diff --git a/library/std/src/sys/yggdrasil/fs/dir.rs b/library/std/src/sys/yggdrasil/fs/dir.rs index 22daa8475d9..0541981c21f 100644 --- a/library/std/src/sys/yggdrasil/fs/dir.rs +++ b/library/std/src/sys/yggdrasil/fs/dir.rs @@ -1,4 +1,4 @@ -use yggdrasil_rt::io::DirectoryEntry as OsDirectoryEntry; +use yggdrasil_rt::io::{DirectoryEntry as OsDirectoryEntry, FileMode as OsFileMode}; use crate::ffi::OsString; use crate::fmt; @@ -8,8 +8,8 @@ use crate::os::yggdrasil::io::{AsRawFd, FromRawFd}; use crate::path::{Path, PathBuf}; use crate::str::FromStr; use crate::sys::fd::FileDesc; -use crate::sys::yggdrasil::cvt_io; -use crate::sys::yggdrasil::fs::{FileAttr, FileType}; +use crate::sys::yggdrasil::fs::{get_metadata_inner, FileAttr, FileType}; +use crate::sys::yggdrasil::{cvt_io, run_with_path_str}; pub struct DirEntry { filename: OsString, @@ -20,18 +20,27 @@ pub struct DirEntry { pub struct ReadDir { fd: FileDesc, path: PathBuf, + // TODO fetch more entries at a time buffer: Option, + eof: bool, } #[derive(Debug)] -pub struct DirBuilder {} +pub struct DirBuilder { + mode: OsFileMode, +} impl ReadDir { fn open(path: &Path) -> io::Result { let path_buf = PathBuf::from(path); let path_str = path.to_str().unwrap(); let fd = cvt_io(unsafe { yggdrasil_rt::sys::open_directory(None, path_str) })?; - Ok(ReadDir { fd: unsafe { FileDesc::from_raw_fd(fd) }, buffer: None, path: path_buf }) + Ok(ReadDir { + fd: unsafe { FileDesc::from_raw_fd(fd) }, + buffer: None, + path: path_buf, + eof: false, + }) } fn fill_buffer(&mut self) -> io::Result<()> { @@ -47,6 +56,8 @@ impl ReadDir { assert!(count <= 1); if count == 1 { self.buffer.replace(unsafe { readbuf[0].assume_init() }); + } else { + self.eof = true; } Ok(()) @@ -57,20 +68,34 @@ impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { - if let Err(e) = self.fill_buffer() { - return Some(Err(e)); + if self.eof { + return None; } - // buffer should have an entry by now - let entry = self.buffer.take(); + loop { + if let Err(e) = self.fill_buffer() { + break Some(Err(e)); + } - entry.map(|e| Ok(DirEntry::from_raw(self.path.clone(), &e))) + // buffer should have an entry by now + let entry = self.buffer.take(); + + break if let Some(entry) = entry { + if &entry.name[..2] == b".\0" || &entry.name[..3] == b"..\0" { + continue; + } + + Some(Ok(DirEntry::from_raw(self.path.clone(), &entry))) + } else { + None + }; + } } } impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&*self.path, f) } } @@ -93,7 +118,7 @@ impl DirEntry { } pub fn metadata(&self) -> io::Result { - todo!() + run_with_path_str(self.path.as_ref(), |path_str| get_metadata_inner(None, path_str, false)) } pub fn file_type(&self) -> io::Result { @@ -102,12 +127,14 @@ impl DirEntry { } impl DirBuilder { - pub fn new() -> DirBuilder { - todo!() + pub fn new() -> Self { + Self { mode: OsFileMode::default_dir() } } - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - todo!() + pub fn mkdir(&self, path: &Path) -> io::Result<()> { + run_with_path_str(path, |path_str| { + cvt_io(unsafe { yggdrasil_rt::sys::create_directory(None, path_str, self.mode) }) + }) } } @@ -115,10 +142,14 @@ pub fn readdir(path: &Path) -> io::Result { ReadDir::open(path) } -pub fn rmdir(_p: &Path) -> io::Result<()> { - todo!() +pub fn rmdir(path: &Path) -> io::Result<()> { + run_with_path_str(path, |path_str| { + cvt_io(unsafe { yggdrasil_rt::sys::remove(None, path_str, false) }) + }) } -pub fn remove_dir_all(_p: &Path) -> io::Result<()> { - todo!() +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + run_with_path_str(path, |path_str| { + cvt_io(unsafe { yggdrasil_rt::sys::remove(None, path_str, true) }) + }) } diff --git a/library/std/src/sys/yggdrasil/fs/mod.rs b/library/std/src/sys/yggdrasil/fs/mod.rs index 5f09c8a3dfa..bbeb1348e36 100644 --- a/library/std/src/sys/yggdrasil/fs/mod.rs +++ b/library/std/src/sys/yggdrasil/fs/mod.rs @@ -3,8 +3,11 @@ use crate::hash::Hash; use crate::io; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; +use crate::sys::{cvt_io, run_with_path_str}; -use yggdrasil_rt::io::FileType as OsFileType; +use yggdrasil_rt::io::{ + FileAttr as OsFileAttr, FileMode as OsFileMode, FileType as OsFileType, RawFd as OsRawFd, +}; mod dir; mod file; @@ -12,10 +15,13 @@ mod file; pub use dir::{readdir, remove_dir_all, rmdir, DirBuilder, DirEntry, ReadDir}; pub use file::{File, OpenOptions}; -pub struct FileAttr(!); -pub struct FilePermissions(!); +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct FileAttr(OsFileAttr); -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct FilePermissions(OsFileMode); + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct FileType(OsFileType); #[derive(Copy, Clone, Debug, Default)] @@ -23,33 +29,36 @@ pub struct FileTimes {} impl FileAttr { pub fn size(&self) -> u64 { - todo!() + self.0.size } pub fn perm(&self) -> FilePermissions { - todo!() + FilePermissions(self.0.mode) } pub fn file_type(&self) -> FileType { - todo!() + FileType(self.0.ty) } pub fn modified(&self) -> io::Result { - todo!() + Err(crate::io::const_io_error!( + crate::io::ErrorKind::Unsupported, + "feature not implemented" + )) } pub fn accessed(&self) -> io::Result { - todo!() + Err(crate::io::const_io_error!( + crate::io::ErrorKind::Unsupported, + "feature not implemented" + )) } pub fn created(&self) -> io::Result { - todo!() - } -} - -impl Clone for FileAttr { - fn clone(&self) -> Self { - todo!() + Err(crate::io::const_io_error!( + crate::io::ErrorKind::Unsupported, + "feature not implemented" + )) } } @@ -63,23 +72,9 @@ impl FilePermissions { } } -impl Clone for FilePermissions { - fn clone(&self) -> Self { - todo!() - } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &Self) -> bool { - todo!() - } -} - -impl Eq for FilePermissions {} - impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0.bits(), f) } } @@ -97,6 +92,12 @@ impl FileType { } } +impl fmt::Debug for FileType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + impl FileTimes { pub fn set_accessed(&mut self, _t: SystemTime) { todo!() @@ -107,8 +108,20 @@ impl FileTimes { } } -pub fn unlink(_p: &Path) -> io::Result<()> { - todo!() +pub(self) fn get_metadata_inner( + at: Option, + path: &str, + follow: bool, +) -> io::Result { + let mut metadata = crate::mem::MaybeUninit::uninit(); + cvt_io(unsafe { yggdrasil_rt::sys::get_metadata(at, path, &mut metadata, follow) })?; + Ok(unsafe { FileAttr(metadata.assume_init()) }) +} + +pub fn unlink(path: &Path) -> io::Result<()> { + run_with_path_str(path, |path_str| { + cvt_io(unsafe { yggdrasil_rt::sys::remove(None, path_str, false) }) + }) } pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { @@ -131,12 +144,12 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { todo!() } -pub fn stat(_p: &Path) -> io::Result { - todo!() +pub fn stat(path: &Path) -> io::Result { + run_with_path_str(path, |path_str| get_metadata_inner(None, path_str, true)) } -pub fn lstat(_p: &Path) -> io::Result { - todo!() +pub fn lstat(path: &Path) -> io::Result { + run_with_path_str(path, |path_str| get_metadata_inner(None, path_str, false)) } pub fn canonicalize(_p: &Path) -> io::Result { diff --git a/library/std/src/sys/yggdrasil/mod.rs b/library/std/src/sys/yggdrasil/mod.rs index 8e7b54d62bc..a1d876138af 100644 --- a/library/std/src/sys/yggdrasil/mod.rs +++ b/library/std/src/sys/yggdrasil/mod.rs @@ -32,6 +32,8 @@ pub(self) use yggdrasil_rt; use yggdrasil_rt::Error as OsError; +use crate::path::Path; + #[doc(hidden)] pub trait IsNegative { fn is_negative(&self) -> bool; @@ -94,9 +96,18 @@ fn cvt_io_err(e: OsError) -> crate::io::Error { OsError::NotADirectory => { crate::io::const_io_error!(ErrorKind::NotADirectory, "not a directory") } + OsError::DirectoryNotEmpty => { + crate::io::const_io_error!(ErrorKind::DirectoryNotEmpty, "directory is not empty") + } } } +#[inline] +pub fn run_with_path_str T>(path: &Path, f: F) -> T { + let path_str = path.to_str().unwrap(); + f(path_str) +} + pub fn cvt_io(t: Result) -> crate::io::Result { match t { Ok(t) => Ok(t),