[libos] Refine the getdents syscall.
This commit is contained in:
parent
bc9e78b360
commit
27a3c75209
2
deps/sefs
vendored
2
deps/sefs
vendored
@ -1 +1 @@
|
||||
Subproject commit 98196fb62f64f0edeacc20d60c30aaaf4a290f70
|
||||
Subproject commit a771d5d37f2a21b02ee579bab85dc8e551d924e0
|
@ -23,13 +23,13 @@ fn getdents_common<T: Dirent>(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
||||
return_errno!(ENOTDIR, "");
|
||||
}
|
||||
let mut writer = DirentBufWriter::<T>::new(buf);
|
||||
let written_size = file_ref.iterate_entries(&mut writer)?;
|
||||
Ok(written_size)
|
||||
let written_len = file_ref.iterate_entries(&mut writer)?;
|
||||
Ok(written_len)
|
||||
}
|
||||
|
||||
struct DirentBufWriter<'a, T: Dirent> {
|
||||
buf: &'a mut [u8],
|
||||
written_size: usize,
|
||||
written_len: usize,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
@ -37,40 +37,34 @@ impl<'a, T: Dirent> DirentBufWriter<'a, T> {
|
||||
fn new(buf: &'a mut [u8]) -> Self {
|
||||
Self {
|
||||
buf,
|
||||
written_size: 0,
|
||||
written_len: 0,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_write(&mut self, name: &str, ino: u64, type_: FileType) -> Result<usize> {
|
||||
let dirent: T = Dirent::new(name, ino, type_);
|
||||
if self.buf.len() - self.written_size < dirent.rec_len() {
|
||||
return_errno!(EINVAL, "the given buffer is too small");
|
||||
}
|
||||
dirent.dump(&mut self.buf[self.written_size..], name, type_)?;
|
||||
self.written_size += dirent.rec_len();
|
||||
Ok(dirent.rec_len())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Dirent> DirentWriter for DirentBufWriter<'a, T> {
|
||||
fn write_entry(
|
||||
&mut self,
|
||||
name: &str,
|
||||
ino: u64,
|
||||
type_: FileType,
|
||||
) -> rcore_fs::vfs::Result<usize> {
|
||||
let written_len = self
|
||||
.try_write(&name, ino, type_)
|
||||
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)?;
|
||||
Ok(written_len)
|
||||
self.written_len += dirent.rec_len();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn written_len(&self) -> usize {
|
||||
self.written_len
|
||||
}
|
||||
}
|
||||
|
||||
trait Dirent: Sync + Send {
|
||||
fn new(name: &str, ino: u64, type_: FileType) -> Self;
|
||||
fn rec_len(&self) -> usize;
|
||||
fn dump(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()>;
|
||||
fn serialize(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()>;
|
||||
}
|
||||
|
||||
/// Same with struct linux_dirent64
|
||||
@ -106,7 +100,7 @@ impl Dirent for LinuxDirent64 {
|
||||
self.rec_len as usize
|
||||
}
|
||||
|
||||
fn dump(&self, buf: &mut [u8], name: &str, _type_: FileType) -> Result<()> {
|
||||
fn serialize(&self, buf: &mut [u8], name: &str, _type_: FileType) -> Result<()> {
|
||||
unsafe {
|
||||
let ptr = buf.as_mut_ptr() as *mut Self;
|
||||
ptr.write(*self);
|
||||
@ -154,7 +148,7 @@ impl Dirent for LinuxDirent {
|
||||
self.rec_len as usize
|
||||
}
|
||||
|
||||
fn dump(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()> {
|
||||
fn serialize(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()> {
|
||||
unsafe {
|
||||
let ptr = buf.as_mut_ptr() as *mut Self;
|
||||
ptr.write(*self);
|
||||
|
@ -269,10 +269,9 @@ impl INode for HNode {
|
||||
return Err(FsError::NotDir);
|
||||
}
|
||||
let idx = ctx.pos();
|
||||
let mut total_written_len = 0;
|
||||
for entry in try_std!(self.path.read_dir()).skip(idx) {
|
||||
let entry = try_std!(entry);
|
||||
let written_len = match ctx.write_entry(
|
||||
if let Err(e) = ctx.write_entry(
|
||||
&entry
|
||||
.file_name()
|
||||
.into_string()
|
||||
@ -283,18 +282,14 @@ impl INode for HNode {
|
||||
.map_err(|_| FsError::InvalidParam)?
|
||||
.into_fs_filetype(),
|
||||
) {
|
||||
Ok(written_len) => written_len,
|
||||
Err(e) => {
|
||||
if total_written_len == 0 {
|
||||
return Err(e);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if ctx.written_len() == 0 {
|
||||
return Err(e);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
total_written_len += written_len;
|
||||
}
|
||||
Ok(total_written_len)
|
||||
Ok(ctx.written_len())
|
||||
}
|
||||
|
||||
fn io_control(&self, cmd: u32, data: usize) -> Result<()> {
|
||||
|
@ -159,23 +159,22 @@ impl DirProcINode for LockedProcRootINode {
|
||||
|
||||
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
|
||||
let file = self.0.read().unwrap();
|
||||
let mut total_written_len = 0;
|
||||
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, &mut total_written_len);
|
||||
write_inode_entry!(&mut ctx, ".", &this_inode);
|
||||
}
|
||||
if idx <= 1 {
|
||||
let parent_inode = file.this.upgrade().unwrap();
|
||||
write_inode_entry!(&mut ctx, "..", &parent_inode, &mut total_written_len);
|
||||
write_inode_entry!(&mut ctx, "..", &parent_inode);
|
||||
}
|
||||
|
||||
// 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, &mut total_written_len);
|
||||
write_inode_entry!(&mut ctx, name, inode);
|
||||
}
|
||||
|
||||
// Write the pid entries
|
||||
@ -192,11 +191,10 @@ impl DirProcINode for LockedProcRootINode {
|
||||
&mut ctx,
|
||||
&process.pid().to_string(),
|
||||
PROC_INO,
|
||||
vfs::FileType::Dir,
|
||||
&mut total_written_len
|
||||
vfs::FileType::Dir
|
||||
);
|
||||
}
|
||||
|
||||
Ok(total_written_len)
|
||||
Ok(ctx.written_len())
|
||||
}
|
||||
}
|
||||
|
@ -55,32 +55,24 @@ impl DirProcINode for LockedProcFdDirINode {
|
||||
|
||||
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
|
||||
let file = self.0.read().unwrap();
|
||||
let mut total_written_len = 0;
|
||||
let idx = ctx.pos();
|
||||
|
||||
// Write first two special entries
|
||||
write_first_two_entries!(idx, &mut ctx, &file, &mut total_written_len);
|
||||
write_first_two_entries!(idx, &mut ctx, &file);
|
||||
|
||||
// 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(total_written_len);
|
||||
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,
|
||||
&mut total_written_len
|
||||
);
|
||||
write_entry!(&mut ctx, &fd.to_string(), PROC_INO, vfs::FileType::SymLink);
|
||||
}
|
||||
|
||||
Ok(total_written_len)
|
||||
Ok(ctx.written_len())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,29 +115,21 @@ impl DirProcINode for LockedPidDirINode {
|
||||
|
||||
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
|
||||
let file = self.0.read().unwrap();
|
||||
let mut total_written_len = 0;
|
||||
let idx = ctx.pos();
|
||||
|
||||
// Write first two special entries
|
||||
write_first_two_entries!(idx, &mut ctx, &file, &mut total_written_len);
|
||||
write_first_two_entries!(idx, &mut ctx, &file);
|
||||
|
||||
// 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, &mut total_written_len);
|
||||
write_inode_entry!(&mut ctx, name, inode);
|
||||
}
|
||||
|
||||
// Write the fd entry
|
||||
if idx <= 2 + file.entries.len() {
|
||||
write_entry!(
|
||||
&mut ctx,
|
||||
"fd",
|
||||
PROC_INO,
|
||||
vfs::FileType::Dir,
|
||||
&mut total_written_len
|
||||
);
|
||||
write_entry!(&mut ctx, "fd", PROC_INO, vfs::FileType::Dir);
|
||||
}
|
||||
|
||||
Ok(total_written_len)
|
||||
Ok(ctx.written_len())
|
||||
}
|
||||
}
|
||||
|
@ -66,52 +66,45 @@ macro_rules! impl_inode_for_file_or_symlink {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! write_first_two_entries {
|
||||
($idx: expr, $ctx:expr, $file:expr, $total_written:expr) => {
|
||||
($idx: expr, $ctx:expr, $file:expr) => {
|
||||
let idx = $idx;
|
||||
let file = $file;
|
||||
|
||||
if idx == 0 {
|
||||
let this_inode = file.this.upgrade().unwrap();
|
||||
write_inode_entry!($ctx, ".", &this_inode, $total_written);
|
||||
write_inode_entry!($ctx, ".", &this_inode);
|
||||
}
|
||||
if idx <= 1 {
|
||||
write_inode_entry!($ctx, "..", &file.parent, $total_written);
|
||||
write_inode_entry!($ctx, "..", &file.parent);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! write_inode_entry {
|
||||
($ctx:expr, $name:expr, $inode:expr, $total_written:expr) => {
|
||||
($ctx:expr, $name:expr, $inode:expr) => {
|
||||
let ctx = $ctx;
|
||||
let name = $name;
|
||||
let ino = $inode.metadata()?.inode;
|
||||
let type_ = $inode.metadata()?.type_;
|
||||
let total_written = $total_written;
|
||||
|
||||
write_entry!(ctx, name, ino, type_, total_written);
|
||||
write_entry!(ctx, name, ino, type_);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! write_entry {
|
||||
($ctx:expr, $name:expr, $ino:expr, $type_:expr, $total_written:expr) => {
|
||||
($ctx:expr, $name:expr, $ino:expr, $type_:expr) => {
|
||||
let ctx = $ctx;
|
||||
let name = $name;
|
||||
let ino = $ino;
|
||||
let type_ = $type_;
|
||||
let total_written = $total_written;
|
||||
|
||||
match ctx.write_entry(name, ino as u64, type_) {
|
||||
Ok(written_len) => {
|
||||
*total_written += written_len;
|
||||
}
|
||||
Err(e) => {
|
||||
if *total_written == 0 {
|
||||
return Err(e);
|
||||
} else {
|
||||
return Ok(*total_written);
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user