diff --git a/deps/sefs b/deps/sefs index c2a1fe48..33143554 160000 --- a/deps/sefs +++ b/deps/sefs @@ -1 +1 @@ -Subproject commit c2a1fe48b06cf9cedbad7a51d9cb846706630403 +Subproject commit 3314355400614c799e237ed1eae5682d27ca1400 diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index 43d7a6f3..d7401a99 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -67,7 +67,7 @@ pub trait File: Debug + Sync + Send + Any { return_op_unsupported_error!("set_len") } - fn iterate_entries(&self, writer: &mut dyn DirentWriter) -> Result { + fn iterate_entries(&self, visitor: &mut dyn DirentVisitor) -> Result { return_op_unsupported_error!("iterate_entries") } diff --git a/src/libos/src/fs/file_ops/getdents.rs b/src/libos/src/fs/file_ops/getdents.rs index 2c60f1bf..f7a2ac17 100644 --- a/src/libos/src/fs/file_ops/getdents.rs +++ b/src/libos/src/fs/file_ops/getdents.rs @@ -9,7 +9,7 @@ pub fn do_getdents(fd: FileDesc, buf: &mut [u8]) -> Result { getdents_common::(fd, buf) } -fn getdents_common(fd: FileDesc, buf: &mut [u8]) -> Result { +fn getdents_common(fd: FileDesc, buf: &mut [u8]) -> Result { debug!( "getdents: fd: {}, buf: {:?}, buf_size: {}", fd, @@ -23,17 +23,17 @@ fn getdents_common(fd: FileDesc, buf: &mut [u8]) -> Result { return_errno!(ENOTDIR, ""); } let mut writer = DirentBufWriter::::new(buf); - let written_len = file_ref.iterate_entries(&mut writer)?; - Ok(written_len) + let _ = file_ref.iterate_entries(&mut writer)?; + Ok(writer.written_len()) } -struct DirentBufWriter<'a, T: Dirent> { +struct DirentBufWriter<'a, T: DirentSerializer> { buf: &'a mut [u8], written_len: usize, phantom: PhantomData, } -impl<'a, T: Dirent> DirentBufWriter<'a, T> { +impl<'a, T: DirentSerializer> DirentBufWriter<'a, T> { fn new(buf: &'a mut [u8]) -> Self { Self { buf, @@ -41,29 +41,38 @@ impl<'a, T: Dirent> DirentBufWriter<'a, T> { phantom: PhantomData, } } -} -impl<'a, T: Dirent> DirentWriter for DirentBufWriter<'a, T> { - fn write_entry(&mut self, name: &str, ino: u64, type_: FileType) -> rcore_fs::vfs::Result<()> { - let dirent: T = Dirent::new(name, ino, type_); - if self.buf.len() - self.written_len < dirent.rec_len() { - return Err(FsError::InvalidParam); - } - dirent - .serialize(&mut self.buf[self.written_len..], name, type_) - .map_err(|_| FsError::InvalidParam)?; - self.written_len += dirent.rec_len(); - Ok(()) - } - - fn written_len(&self) -> usize { + pub fn written_len(&self) -> usize { self.written_len } } -trait Dirent: Sync + Send { - fn new(name: &str, ino: u64, type_: FileType) -> Self; +impl<'a, T: DirentSerializer> DirentVisitor for DirentBufWriter<'a, T> { + fn visit_entry( + &mut self, + name: &str, + ino: u64, + type_: FileType, + offset: usize, + ) -> rcore_fs::vfs::Result<()> { + let dirent_serializer = T::new(name, ino, type_, offset); + if self.written_len >= self.buf.len() { + return Err(FsError::InvalidParam); + } + dirent_serializer + .serialize(&mut self.buf[self.written_len..], name, type_) + .map_err(|_| FsError::InvalidParam)?; + self.written_len += dirent_serializer.rec_len(); + Ok(()) + } +} + +trait DirentSerializer: Sync + Send { + /// Creates a new DirentSerializer. + fn new(name: &str, ino: u64, type_: FileType, offset: usize) -> Self; + /// Returns the length. fn rec_len(&self) -> usize; + /// Tries to serialize a directory entry into buffer. fn serialize(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()>; } @@ -83,13 +92,13 @@ struct LinuxDirent64 { pub name: [u8; 0], } -impl Dirent for LinuxDirent64 { - fn new(name: &str, ino: u64, type_: FileType) -> Self { +impl DirentSerializer for LinuxDirent64 { + fn new(name: &str, ino: u64, type_: FileType, offset: usize) -> Self { let ori_len = core::mem::size_of::() + name.len() + 1; let len = align_up(ori_len, 8); // align up to 8 bytes Self { ino, - offset: 0, + offset: offset as u64, rec_len: len as u16, type_: DirentType::from_file_type(type_), name: [], @@ -101,6 +110,10 @@ impl Dirent for LinuxDirent64 { } fn serialize(&self, buf: &mut [u8], name: &str, _type_: FileType) -> Result<()> { + if self.rec_len() > buf.len() { + return_errno!(EINVAL, "not enough buf"); + } + unsafe { let ptr = buf.as_mut_ptr() as *mut Self; ptr.write(*self); @@ -131,14 +144,14 @@ struct LinuxDirent { */ } -impl Dirent for LinuxDirent { - fn new(name: &str, ino: u64, type_: FileType) -> Self { +impl DirentSerializer for LinuxDirent { + fn new(name: &str, ino: u64, type_: FileType, offset: usize) -> Self { let ori_len = core::mem::size_of::() + name.len() + 1 + core::mem::size_of::(); let len = align_up(ori_len, 8); // align up to 8 bytes Self { ino, - offset: 0, + offset: offset as u64, rec_len: len as u16, name: [], } @@ -149,6 +162,10 @@ impl Dirent for LinuxDirent { } fn serialize(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()> { + if self.rec_len() > buf.len() { + return_errno!(EINVAL, "not enough buf"); + } + unsafe { let ptr = buf.as_mut_ptr() as *mut Self; ptr.write(*self); diff --git a/src/libos/src/fs/hostfs.rs b/src/libos/src/fs/hostfs.rs index 9da7ed97..b1f55cd3 100644 --- a/src/libos/src/fs/hostfs.rs +++ b/src/libos/src/fs/hostfs.rs @@ -250,32 +250,41 @@ impl INode for HNode { } } - fn iterate_entries(&self, ctx: &mut DirentWriterContext) -> Result { + fn iterate_entries(&self, offset: usize, visitor: &mut dyn DirentVisitor) -> Result { if !self.is_dir() { return Err(FsError::NotDir); } - let idx = ctx.pos(); - for entry in try_std!(self.path.read_dir()).skip(idx) { - let entry = try_std!(entry); - if let Err(e) = ctx.write_entry( - &entry - .file_name() - .into_string() - .map_err(|_| FsError::InvalidParam)?, - entry.ino(), - entry - .file_type() - .map_err(|_| FsError::InvalidParam)? - .into_fs_filetype(), - ) { - if ctx.written_len() == 0 { - return Err(e); - } else { - break; - } - }; + + let try_iterate = |offset: &mut usize, visitor: &mut dyn DirentVisitor| -> Result<()> { + let start_offset = *offset; + for (idx, entry) in try_std!(self.path.read_dir()) + .enumerate() + .skip_while(|(idx, _)| idx < &start_offset) + { + let entry = try_std!(entry); + visitor.visit_entry( + &entry + .file_name() + .into_string() + .map_err(|_| FsError::InvalidParam)?, + entry.ino() as u64, + entry + .file_type() + .map_err(|_| FsError::InvalidParam)? + .into_fs_filetype(), + idx, + )?; + *offset = idx + 1; + } + + Ok(()) + }; + + let mut iterate_offset = offset; + match try_iterate(&mut iterate_offset, visitor) { + Err(e) if iterate_offset == offset => Err(e), + _ => Ok(iterate_offset - offset), } - Ok(ctx.written_len()) } fn io_control(&self, cmd: u32, data: usize) -> Result<()> { diff --git a/src/libos/src/fs/inode_file.rs b/src/libos/src/fs/inode_file.rs index 95c8b9a2..13c3256d 100644 --- a/src/libos/src/fs/inode_file.rs +++ b/src/libos/src/fs/inode_file.rs @@ -193,15 +193,14 @@ impl File for INodeFile { Ok(()) } - fn iterate_entries(&self, writer: &mut dyn DirentWriter) -> Result { + fn iterate_entries(&self, visitor: &mut dyn DirentVisitor) -> Result { if !self.access_mode.readable() { return_errno!(EBADF, "File not readable. Can't read entry."); } let mut offset = self.offset.lock().unwrap(); - let mut dir_ctx = DirentWriterContext::new(*offset, writer); - let written_size = self.inode.iterate_entries(&mut dir_ctx)?; - *offset = dir_ctx.pos(); - Ok(written_size) + let visited_len = self.inode.iterate_entries(*offset, visitor)?; + *offset += visited_len; + Ok(visited_len) } fn access_mode(&self) -> Result { diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 8d752b8f..008807f2 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -2,8 +2,7 @@ use super::*; use process; use rcore_fs::vfs::{ - DirentWriter, DirentWriterContext, FileSystem, FileType, FsError, INode, Metadata, Timespec, - PATH_MAX, + DirentVisitor, FileSystem, FileType, FsError, INode, Metadata, Timespec, PATH_MAX, }; use std; use std::any::Any; diff --git a/src/libos/src/fs/procfs/mod.rs b/src/libos/src/fs/procfs/mod.rs index 640669f0..2b496d76 100644 --- a/src/libos/src/fs/procfs/mod.rs +++ b/src/libos/src/fs/procfs/mod.rs @@ -157,44 +157,51 @@ impl DirProcINode for LockedProcRootINode { } } - fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result { + fn iterate_entries( + &self, + offset: usize, + visitor: &mut dyn DirentVisitor, + ) -> vfs::Result { let file = self.0.read().unwrap(); - let idx = ctx.pos(); - // Write first two special entries - if idx == 0 { - let this_inode = file.this.upgrade().unwrap(); - write_inode_entry!(&mut ctx, ".", &this_inode); - } - if idx <= 1 { - let parent_inode = file.this.upgrade().unwrap(); - write_inode_entry!(&mut ctx, "..", &parent_inode); - } + let try_iterate = + |mut offset: &mut usize, mut visitor: &mut dyn DirentVisitor| -> vfs::Result<()> { + // The two special entries + if *offset == 0 { + let this_inode = file.this.upgrade().unwrap(); + rcore_fs::visit_inode_entry!(&mut visitor, ".", &this_inode, &mut offset); + } + if *offset == 1 { + let parent_inode = file.this.upgrade().unwrap(); + rcore_fs::visit_inode_entry!(&mut visitor, "..", &parent_inode, &mut offset); + } - // Write the non volatile entries - let skipped = if idx < 2 { 0 } else { idx - 2 }; - for (name, inode) in file.non_volatile_entries.iter().skip(skipped) { - write_inode_entry!(&mut ctx, name, inode); - } + // The non volatile entries + let start_offset = *offset; + for (name, child) in file.non_volatile_entries.iter().skip(start_offset - 2) { + rcore_fs::visit_inode_entry!(&mut visitor, name, child, &mut offset); + } - // Write the pid entries - let skipped = { - let prior_entries_len = 2 + file.non_volatile_entries.len(); - if idx < prior_entries_len { - 0 - } else { - idx - prior_entries_len - } - }; - for process in get_all_processes().iter().skip(skipped) { - write_entry!( - &mut ctx, - &process.pid().to_string(), - PROC_INO, - vfs::FileType::Dir - ); - } + // The pid entries + let start_offset = *offset; + let skipped_len = 2 + file.non_volatile_entries.len(); + for process in get_all_processes().iter().skip(start_offset - skipped_len) { + rcore_fs::visit_entry!( + &mut visitor, + &process.pid().to_string(), + PROC_INO, + vfs::FileType::Dir, + &mut offset + ); + } - Ok(ctx.written_len()) + Ok(()) + }; + + let mut iterate_offset = offset; + match try_iterate(&mut iterate_offset, visitor) { + Err(e) if iterate_offset == offset => Err(e), + _ => Ok(iterate_offset - offset), + } } } diff --git a/src/libos/src/fs/procfs/pid/fd.rs b/src/libos/src/fs/procfs/pid/fd.rs index 65801a8e..ec26803c 100644 --- a/src/libos/src/fs/procfs/pid/fd.rs +++ b/src/libos/src/fs/procfs/pid/fd.rs @@ -53,26 +53,45 @@ impl DirProcINode for LockedProcFdDirINode { } } - fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result { + fn iterate_entries( + &self, + offset: usize, + visitor: &mut dyn DirentVisitor, + ) -> vfs::Result { let file = self.0.read().unwrap(); - let idx = ctx.pos(); - // Write first two special entries - write_first_two_entries!(idx, &mut ctx, &file); + let try_iterate = + |mut offset: &mut usize, mut visitor: &mut dyn DirentVisitor| -> vfs::Result<()> { + // The two special entries + visit_first_two_entries!(&mut visitor, &file, &mut offset); - // Write the fd entries - let skipped = if idx < 2 { 0 } else { idx - 2 }; - let main_thread = match file.process_ref.main_thread() { - Some(main_thread) => main_thread, - None => { - return Ok(ctx.written_len()); - } - }; - let fds = main_thread.files().lock().unwrap().fds(); - for fd in fds.iter().skip(skipped) { - write_entry!(&mut ctx, &fd.to_string(), PROC_INO, vfs::FileType::SymLink); + // The fd entries + let main_thread = match file.process_ref.main_thread() { + Some(main_thread) => main_thread, + None => { + return Ok(()); + } + }; + let fds = main_thread.files().lock().unwrap().fds(); + let start_offset = *offset; + for fd in fds.iter().skip(start_offset - 2) { + rcore_fs::visit_entry!( + &mut visitor, + &fd.to_string(), + PROC_INO, + vfs::FileType::SymLink, + &mut offset + ); + } + + Ok(()) + }; + + let mut iterate_offset = offset; + match try_iterate(&mut iterate_offset, visitor) { + Err(e) if iterate_offset == offset => Err(e), + _ => Ok(iterate_offset - offset), } - Ok(ctx.written_len()) } } diff --git a/src/libos/src/fs/procfs/pid/mod.rs b/src/libos/src/fs/procfs/pid/mod.rs index 2ff75736..439ab549 100644 --- a/src/libos/src/fs/procfs/pid/mod.rs +++ b/src/libos/src/fs/procfs/pid/mod.rs @@ -113,23 +113,42 @@ impl DirProcINode for LockedPidDirINode { } } - fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result { + fn iterate_entries( + &self, + offset: usize, + visitor: &mut dyn DirentVisitor, + ) -> vfs::Result { let file = self.0.read().unwrap(); - let idx = ctx.pos(); - // Write first two special entries - write_first_two_entries!(idx, &mut ctx, &file); + let try_iterate = + |mut offset: &mut usize, mut visitor: &mut dyn DirentVisitor| -> vfs::Result<()> { + // The two special entries + visit_first_two_entries!(&mut visitor, &file, &mut offset); - // Write the normal entries - let skipped = if idx < 2 { 0 } else { idx - 2 }; - for (name, inode) in file.entries.iter().skip(skipped) { - write_inode_entry!(&mut ctx, name, inode); + // The normal entries + let start_offset = *offset; + for (name, child) in file.entries.iter().skip(start_offset - 2) { + rcore_fs::visit_inode_entry!(&mut visitor, name, child, &mut offset); + } + + // The fd entry + if *offset == 2 + file.entries.len() { + rcore_fs::visit_entry!( + &mut visitor, + "fd", + PROC_INO as u64, + vfs::FileType::Dir, + &mut offset + ); + } + + Ok(()) + }; + + let mut iterate_offset = offset; + match try_iterate(&mut iterate_offset, visitor) { + Err(e) if iterate_offset == offset => Err(e), + _ => Ok(iterate_offset - offset), } - - // Write the fd entry - if idx <= 2 + file.entries.len() { - write_entry!(&mut ctx, "fd", PROC_INO, vfs::FileType::Dir); - } - Ok(ctx.written_len()) } } diff --git a/src/libos/src/fs/procfs/proc_inode/dir.rs b/src/libos/src/fs/procfs/proc_inode/dir.rs index 15913974..8a5a32f8 100644 --- a/src/libos/src/fs/procfs/proc_inode/dir.rs +++ b/src/libos/src/fs/procfs/proc_inode/dir.rs @@ -65,8 +65,12 @@ where self.inner().get_entry(id) } - fn iterate_entries(&self, ctx: &mut DirentWriterContext) -> vfs::Result { - self.inner().iterate_entries(ctx) + fn iterate_entries( + &self, + offset: usize, + visitor: &mut dyn DirentVisitor, + ) -> vfs::Result { + self.inner().iterate_entries(offset, visitor) } fn as_any_ref(&self) -> &dyn Any { diff --git a/src/libos/src/fs/procfs/proc_inode/mod.rs b/src/libos/src/fs/procfs/proc_inode/mod.rs index bd532b95..c01c3220 100644 --- a/src/libos/src/fs/procfs/proc_inode/mod.rs +++ b/src/libos/src/fs/procfs/proc_inode/mod.rs @@ -15,7 +15,8 @@ pub trait ProcINode { pub trait DirProcINode { fn find(&self, name: &str) -> vfs::Result>; fn get_entry(&self, id: usize) -> vfs::Result; - fn iterate_entries(&self, ctx: &mut DirentWriterContext) -> vfs::Result; + fn iterate_entries(&self, offset: usize, visitor: &mut dyn DirentVisitor) + -> vfs::Result; } #[macro_export] @@ -54,7 +55,11 @@ macro_rules! impl_inode_for_file_or_symlink { Err(FsError::NotDir) } - fn iterate_entries(&self, ctx: &mut DirentWriterContext) -> vfs::Result { + fn iterate_entries( + &self, + offset: usize, + visitor: &mut dyn DirentVisitor, + ) -> vfs::Result { Err(FsError::NotDir) } @@ -65,47 +70,19 @@ macro_rules! impl_inode_for_file_or_symlink { } #[macro_export] -macro_rules! write_first_two_entries { - ($idx: expr, $ctx:expr, $file:expr) => { - let idx = $idx; +macro_rules! visit_first_two_entries { + ($visitor:expr, $file:expr, $offset: expr) => { + use rcore_fs::visit_inode_entry; let file = $file; - if idx == 0 { + let offset = **$offset; + if offset == 0 { let this_inode = file.this.upgrade().unwrap(); - write_inode_entry!($ctx, ".", &this_inode); + visit_inode_entry!($visitor, ".", &this_inode, $offset); } - if idx <= 1 { - write_inode_entry!($ctx, "..", &file.parent); - } - }; -} - -#[macro_export] -macro_rules! write_inode_entry { - ($ctx:expr, $name:expr, $inode:expr) => { - let ctx = $ctx; - let name = $name; - let ino = $inode.metadata()?.inode; - let type_ = $inode.metadata()?.type_; - - write_entry!(ctx, name, ino, type_); - }; -} - -#[macro_export] -macro_rules! write_entry { - ($ctx:expr, $name:expr, $ino:expr, $type_:expr) => { - let ctx = $ctx; - let name = $name; - let ino = $ino; - let type_ = $type_; - - if let Err(e) = ctx.write_entry(name, ino as u64, type_) { - if ctx.written_len() == 0 { - return Err(e); - } else { - return Ok(ctx.written_len()); - } + let offset = **$offset; + if offset == 1 { + visit_inode_entry!($visitor, "..", &file.parent, $offset); } }; }