[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, "");
|
return_errno!(ENOTDIR, "");
|
||||||
}
|
}
|
||||||
let mut writer = DirentBufWriter::<T>::new(buf);
|
let mut writer = DirentBufWriter::<T>::new(buf);
|
||||||
let written_size = file_ref.iterate_entries(&mut writer)?;
|
let written_len = file_ref.iterate_entries(&mut writer)?;
|
||||||
Ok(written_size)
|
Ok(written_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DirentBufWriter<'a, T: Dirent> {
|
struct DirentBufWriter<'a, T: Dirent> {
|
||||||
buf: &'a mut [u8],
|
buf: &'a mut [u8],
|
||||||
written_size: usize,
|
written_len: usize,
|
||||||
phantom: PhantomData<T>,
|
phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,40 +37,34 @@ impl<'a, T: Dirent> DirentBufWriter<'a, T> {
|
|||||||
fn new(buf: &'a mut [u8]) -> Self {
|
fn new(buf: &'a mut [u8]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buf,
|
buf,
|
||||||
written_size: 0,
|
written_len: 0,
|
||||||
phantom: PhantomData,
|
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> {
|
impl<'a, T: Dirent> DirentWriter for DirentBufWriter<'a, T> {
|
||||||
fn write_entry(
|
fn write_entry(&mut self, name: &str, ino: u64, type_: FileType) -> rcore_fs::vfs::Result<()> {
|
||||||
&mut self,
|
let dirent: T = Dirent::new(name, ino, type_);
|
||||||
name: &str,
|
if self.buf.len() - self.written_len < dirent.rec_len() {
|
||||||
ino: u64,
|
return Err(FsError::InvalidParam);
|
||||||
type_: FileType,
|
}
|
||||||
) -> rcore_fs::vfs::Result<usize> {
|
dirent
|
||||||
let written_len = self
|
.serialize(&mut self.buf[self.written_len..], name, type_)
|
||||||
.try_write(&name, ino, type_)
|
|
||||||
.map_err(|_| FsError::InvalidParam)?;
|
.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 {
|
trait Dirent: Sync + Send {
|
||||||
fn new(name: &str, ino: u64, type_: FileType) -> Self;
|
fn new(name: &str, ino: u64, type_: FileType) -> Self;
|
||||||
fn rec_len(&self) -> usize;
|
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
|
/// Same with struct linux_dirent64
|
||||||
@ -106,7 +100,7 @@ impl Dirent for LinuxDirent64 {
|
|||||||
self.rec_len as usize
|
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 {
|
unsafe {
|
||||||
let ptr = buf.as_mut_ptr() as *mut Self;
|
let ptr = buf.as_mut_ptr() as *mut Self;
|
||||||
ptr.write(*self);
|
ptr.write(*self);
|
||||||
@ -154,7 +148,7 @@ impl Dirent for LinuxDirent {
|
|||||||
self.rec_len as usize
|
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 {
|
unsafe {
|
||||||
let ptr = buf.as_mut_ptr() as *mut Self;
|
let ptr = buf.as_mut_ptr() as *mut Self;
|
||||||
ptr.write(*self);
|
ptr.write(*self);
|
||||||
|
@ -269,10 +269,9 @@ impl INode for HNode {
|
|||||||
return Err(FsError::NotDir);
|
return Err(FsError::NotDir);
|
||||||
}
|
}
|
||||||
let idx = ctx.pos();
|
let idx = ctx.pos();
|
||||||
let mut total_written_len = 0;
|
|
||||||
for entry in try_std!(self.path.read_dir()).skip(idx) {
|
for entry in try_std!(self.path.read_dir()).skip(idx) {
|
||||||
let entry = try_std!(entry);
|
let entry = try_std!(entry);
|
||||||
let written_len = match ctx.write_entry(
|
if let Err(e) = ctx.write_entry(
|
||||||
&entry
|
&entry
|
||||||
.file_name()
|
.file_name()
|
||||||
.into_string()
|
.into_string()
|
||||||
@ -283,18 +282,14 @@ impl INode for HNode {
|
|||||||
.map_err(|_| FsError::InvalidParam)?
|
.map_err(|_| FsError::InvalidParam)?
|
||||||
.into_fs_filetype(),
|
.into_fs_filetype(),
|
||||||
) {
|
) {
|
||||||
Ok(written_len) => written_len,
|
if ctx.written_len() == 0 {
|
||||||
Err(e) => {
|
|
||||||
if total_written_len == 0 {
|
|
||||||
return Err(e);
|
return Err(e);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
total_written_len += written_len;
|
|
||||||
}
|
}
|
||||||
Ok(total_written_len)
|
Ok(ctx.written_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn io_control(&self, cmd: u32, data: usize) -> Result<()> {
|
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> {
|
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
|
||||||
let file = self.0.read().unwrap();
|
let file = self.0.read().unwrap();
|
||||||
let mut total_written_len = 0;
|
|
||||||
let idx = ctx.pos();
|
let idx = ctx.pos();
|
||||||
|
|
||||||
// Write first two special entries
|
// Write first two special entries
|
||||||
if idx == 0 {
|
if idx == 0 {
|
||||||
let this_inode = file.this.upgrade().unwrap();
|
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 {
|
if idx <= 1 {
|
||||||
let parent_inode = file.this.upgrade().unwrap();
|
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
|
// Write the non volatile entries
|
||||||
let skipped = if idx < 2 { 0 } else { idx - 2 };
|
let skipped = if idx < 2 { 0 } else { idx - 2 };
|
||||||
for (name, inode) in file.non_volatile_entries.iter().skip(skipped) {
|
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
|
// Write the pid entries
|
||||||
@ -192,11 +191,10 @@ impl DirProcINode for LockedProcRootINode {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
&process.pid().to_string(),
|
&process.pid().to_string(),
|
||||||
PROC_INO,
|
PROC_INO,
|
||||||
vfs::FileType::Dir,
|
vfs::FileType::Dir
|
||||||
&mut total_written_len
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
|
||||||
let file = self.0.read().unwrap();
|
let file = self.0.read().unwrap();
|
||||||
let mut total_written_len = 0;
|
|
||||||
let idx = ctx.pos();
|
let idx = ctx.pos();
|
||||||
|
|
||||||
// Write first two special entries
|
// 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
|
// Write the fd entries
|
||||||
let skipped = if idx < 2 { 0 } else { idx - 2 };
|
let skipped = if idx < 2 { 0 } else { idx - 2 };
|
||||||
let main_thread = match file.process_ref.main_thread() {
|
let main_thread = match file.process_ref.main_thread() {
|
||||||
Some(main_thread) => main_thread,
|
Some(main_thread) => main_thread,
|
||||||
None => {
|
None => {
|
||||||
return Ok(total_written_len);
|
return Ok(ctx.written_len());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let fds = main_thread.files().lock().unwrap().fds();
|
let fds = main_thread.files().lock().unwrap().fds();
|
||||||
for fd in fds.iter().skip(skipped) {
|
for fd in fds.iter().skip(skipped) {
|
||||||
write_entry!(
|
write_entry!(&mut ctx, &fd.to_string(), PROC_INO, vfs::FileType::SymLink);
|
||||||
&mut ctx,
|
|
||||||
&fd.to_string(),
|
|
||||||
PROC_INO,
|
|
||||||
vfs::FileType::SymLink,
|
|
||||||
&mut total_written_len
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
Ok(ctx.written_len())
|
||||||
Ok(total_written_len)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,29 +115,21 @@ impl DirProcINode for LockedPidDirINode {
|
|||||||
|
|
||||||
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
|
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
|
||||||
let file = self.0.read().unwrap();
|
let file = self.0.read().unwrap();
|
||||||
let mut total_written_len = 0;
|
|
||||||
let idx = ctx.pos();
|
let idx = ctx.pos();
|
||||||
|
|
||||||
// Write first two special entries
|
// 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
|
// Write the normal entries
|
||||||
let skipped = if idx < 2 { 0 } else { idx - 2 };
|
let skipped = if idx < 2 { 0 } else { idx - 2 };
|
||||||
for (name, inode) in file.entries.iter().skip(skipped) {
|
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
|
// Write the fd entry
|
||||||
if idx <= 2 + file.entries.len() {
|
if idx <= 2 + file.entries.len() {
|
||||||
write_entry!(
|
write_entry!(&mut ctx, "fd", PROC_INO, vfs::FileType::Dir);
|
||||||
&mut ctx,
|
|
||||||
"fd",
|
|
||||||
PROC_INO,
|
|
||||||
vfs::FileType::Dir,
|
|
||||||
&mut total_written_len
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
Ok(ctx.written_len())
|
||||||
Ok(total_written_len)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,52 +66,45 @@ macro_rules! impl_inode_for_file_or_symlink {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! write_first_two_entries {
|
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 idx = $idx;
|
||||||
let file = $file;
|
let file = $file;
|
||||||
|
|
||||||
if idx == 0 {
|
if idx == 0 {
|
||||||
let this_inode = file.this.upgrade().unwrap();
|
let this_inode = file.this.upgrade().unwrap();
|
||||||
write_inode_entry!($ctx, ".", &this_inode, $total_written);
|
write_inode_entry!($ctx, ".", &this_inode);
|
||||||
}
|
}
|
||||||
if idx <= 1 {
|
if idx <= 1 {
|
||||||
write_inode_entry!($ctx, "..", &file.parent, $total_written);
|
write_inode_entry!($ctx, "..", &file.parent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! write_inode_entry {
|
macro_rules! write_inode_entry {
|
||||||
($ctx:expr, $name:expr, $inode:expr, $total_written:expr) => {
|
($ctx:expr, $name:expr, $inode:expr) => {
|
||||||
let ctx = $ctx;
|
let ctx = $ctx;
|
||||||
let name = $name;
|
let name = $name;
|
||||||
let ino = $inode.metadata()?.inode;
|
let ino = $inode.metadata()?.inode;
|
||||||
let type_ = $inode.metadata()?.type_;
|
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_export]
|
||||||
macro_rules! write_entry {
|
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 ctx = $ctx;
|
||||||
let name = $name;
|
let name = $name;
|
||||||
let ino = $ino;
|
let ino = $ino;
|
||||||
let type_ = $type_;
|
let type_ = $type_;
|
||||||
let total_written = $total_written;
|
|
||||||
|
|
||||||
match ctx.write_entry(name, ino as u64, type_) {
|
if let Err(e) = ctx.write_entry(name, ino as u64, type_) {
|
||||||
Ok(written_len) => {
|
if ctx.written_len() == 0 {
|
||||||
*total_written += written_len;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
if *total_written == 0 {
|
|
||||||
return Err(e);
|
return Err(e);
|
||||||
} else {
|
} else {
|
||||||
return Ok(*total_written);
|
return Ok(ctx.written_len());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user