mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 00:43:24 +00:00
Add syscall getdents
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
4700ab71bc
commit
053f8d416e
@ -98,7 +98,7 @@ provided by Linux on x86-64 architecture.
|
|||||||
| 75 | fdatasync | ❌ |
|
| 75 | fdatasync | ❌ |
|
||||||
| 76 | truncate | ✅ |
|
| 76 | truncate | ✅ |
|
||||||
| 77 | ftruncate | ✅ |
|
| 77 | ftruncate | ✅ |
|
||||||
| 78 | getdents | ❌ |
|
| 78 | getdents | ✅ |
|
||||||
| 79 | getcwd | ✅ |
|
| 79 | getcwd | ✅ |
|
||||||
| 80 | chdir | ✅ |
|
| 80 | chdir | ✅ |
|
||||||
| 81 | fchdir | ✅ |
|
| 81 | fchdir | ✅ |
|
||||||
|
@ -28,7 +28,7 @@ use crate::syscall::{
|
|||||||
fsync::sys_fsync,
|
fsync::sys_fsync,
|
||||||
futex::sys_futex,
|
futex::sys_futex,
|
||||||
getcwd::sys_getcwd,
|
getcwd::sys_getcwd,
|
||||||
getdents64::sys_getdents64,
|
getdents64::{sys_getdents, sys_getdents64},
|
||||||
getegid::sys_getegid,
|
getegid::sys_getegid,
|
||||||
geteuid::sys_geteuid,
|
geteuid::sys_geteuid,
|
||||||
getgid::sys_getgid,
|
getgid::sys_getgid,
|
||||||
@ -184,6 +184,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_FSYNC = 74 => sys_fsync(args[..1]);
|
SYS_FSYNC = 74 => sys_fsync(args[..1]);
|
||||||
SYS_TRUNCATE = 76 => sys_truncate(args[..2]);
|
SYS_TRUNCATE = 76 => sys_truncate(args[..2]);
|
||||||
SYS_FTRUNCATE = 77 => sys_ftruncate(args[..2]);
|
SYS_FTRUNCATE = 77 => sys_ftruncate(args[..2]);
|
||||||
|
SYS_GETDENTS = 78 => sys_getdents(args[..3]);
|
||||||
SYS_GETCWD = 79 => sys_getcwd(args[..2]);
|
SYS_GETCWD = 79 => sys_getcwd(args[..2]);
|
||||||
SYS_CHDIR = 80 => sys_chdir(args[..1]);
|
SYS_CHDIR = 80 => sys_chdir(args[..1]);
|
||||||
SYS_FCHDIR = 81 => sys_fchdir(args[..1]);
|
SYS_FCHDIR = 81 => sys_fchdir(args[..1]);
|
||||||
|
@ -15,6 +15,31 @@ use crate::{
|
|||||||
util::write_bytes_to_user,
|
util::write_bytes_to_user,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn sys_getdents(fd: FileDesc, buf_addr: Vaddr, buf_len: usize) -> Result<SyscallReturn> {
|
||||||
|
debug!(
|
||||||
|
"fd = {}, buf_addr = 0x{:x}, buf_len = 0x{:x}",
|
||||||
|
fd, buf_addr, buf_len
|
||||||
|
);
|
||||||
|
|
||||||
|
let file = {
|
||||||
|
let current = current!();
|
||||||
|
let file_table = current.file_table().lock();
|
||||||
|
file_table.get_file(fd)?.clone()
|
||||||
|
};
|
||||||
|
let inode_handle = file
|
||||||
|
.downcast_ref::<InodeHandle>()
|
||||||
|
.ok_or(Error::with_message(Errno::EBADF, "not inode"))?;
|
||||||
|
if inode_handle.dentry().type_() != InodeType::Dir {
|
||||||
|
return_errno!(Errno::ENOTDIR);
|
||||||
|
}
|
||||||
|
let mut buffer = vec![0u8; buf_len];
|
||||||
|
let mut reader = DirentBufferReader::<Dirent>::new(&mut buffer); // Use the non-64-bit reader
|
||||||
|
let _ = inode_handle.readdir(&mut reader)?;
|
||||||
|
let read_len = reader.read_len();
|
||||||
|
write_bytes_to_user(buf_addr, &buffer[..read_len])?;
|
||||||
|
Ok(SyscallReturn::Return(read_len as _))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sys_getdents64(fd: FileDesc, buf_addr: Vaddr, buf_len: usize) -> Result<SyscallReturn> {
|
pub fn sys_getdents64(fd: FileDesc, buf_addr: Vaddr, buf_len: usize) -> Result<SyscallReturn> {
|
||||||
debug!(
|
debug!(
|
||||||
"fd = {}, buf_addr = 0x{:x}, buf_len = 0x{:x}",
|
"fd = {}, buf_addr = 0x{:x}, buf_len = 0x{:x}",
|
||||||
@ -40,6 +65,16 @@ pub fn sys_getdents64(fd: FileDesc, buf_addr: Vaddr, buf_len: usize) -> Result<S
|
|||||||
Ok(SyscallReturn::Return(read_len as _))
|
Ok(SyscallReturn::Return(read_len as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The DirentSerializer can decide how to serialize the data.
|
||||||
|
trait DirentSerializer {
|
||||||
|
/// Create a DirentSerializer.
|
||||||
|
fn new(ino: u64, offset: u64, type_: InodeType, name: CString) -> Self;
|
||||||
|
/// Get the length of a directory entry.
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
/// Try to serialize a directory entry into buffer.
|
||||||
|
fn serialize(&self, buf: &mut [u8]) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
/// The Buffered DirentReader to visit the dir entry.
|
/// The Buffered DirentReader to visit the dir entry.
|
||||||
/// The DirentSerializer T decides how to serialize the data.
|
/// The DirentSerializer T decides how to serialize the data.
|
||||||
struct DirentBufferReader<'a, T: DirentSerializer> {
|
struct DirentBufferReader<'a, T: DirentSerializer> {
|
||||||
@ -74,14 +109,63 @@ impl<'a, T: DirentSerializer> DirentVisitor for DirentBufferReader<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The DirentSerializer can decide how to serialize the data.
|
#[derive(Debug)]
|
||||||
trait DirentSerializer {
|
struct Dirent {
|
||||||
/// Create a DirentSerializer.
|
inner: DirentInner,
|
||||||
fn new(ino: u64, offset: u64, type_: InodeType, name: CString) -> Self;
|
name: CString,
|
||||||
/// Get the length of a directory entry.
|
}
|
||||||
fn len(&self) -> usize;
|
|
||||||
/// Try to serialize a directory entry into buffer.
|
#[repr(packed)]
|
||||||
fn serialize(&self, buf: &mut [u8]) -> Result<()>;
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct DirentInner {
|
||||||
|
d_ino: u64,
|
||||||
|
d_off: u64,
|
||||||
|
d_reclen: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirentSerializer for Dirent {
|
||||||
|
fn new(ino: u64, offset: u64, _type_: InodeType, name: CString) -> Self {
|
||||||
|
let d_reclen = {
|
||||||
|
let len =
|
||||||
|
core::mem::size_of::<Dirent64Inner>() + name.as_c_str().to_bytes_with_nul().len();
|
||||||
|
align_up(len, 8) as u16
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
inner: DirentInner {
|
||||||
|
d_ino: ino,
|
||||||
|
d_off: offset,
|
||||||
|
d_reclen,
|
||||||
|
},
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.inner.d_reclen as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize(&self, buf: &mut [u8]) -> Result<()> {
|
||||||
|
// Ensure buffer is large enough for the directory entry
|
||||||
|
if self.len() > buf.len() {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "buffer is too small");
|
||||||
|
}
|
||||||
|
|
||||||
|
let d_ino = self.inner.d_ino;
|
||||||
|
let d_off = self.inner.d_off;
|
||||||
|
let d_reclen = self.inner.d_reclen;
|
||||||
|
let items: [&[u8]; 4] = [
|
||||||
|
d_ino.as_bytes(),
|
||||||
|
d_off.as_bytes(),
|
||||||
|
d_reclen.as_bytes(),
|
||||||
|
self.name.as_c_str().to_bytes_with_nul(),
|
||||||
|
];
|
||||||
|
let mut offset = 0;
|
||||||
|
for item in items {
|
||||||
|
buf[offset..offset + item.len()].copy_from_slice(item);
|
||||||
|
offset += item.len();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1,11 +1,2 @@
|
|||||||
GetdentsTest/0.VerifyEntries
|
|
||||||
GetdentsTest/0.VerifyPadding
|
|
||||||
GetdentsTest/0.SmallDir
|
|
||||||
GetdentsTest/0.LargeDir
|
|
||||||
GetdentsTest/0.PartialBuffer
|
GetdentsTest/0.PartialBuffer
|
||||||
GetdentsTest/0.ProcSelfFd
|
|
||||||
GetdentsTest/0.NotDir
|
|
||||||
GetdentsTest/0.SeekResetsCursor
|
|
||||||
GetdentsTest/0.Issue128ProcSeekEnd
|
|
||||||
GetdentsTest/1.PartialBuffer
|
GetdentsTest/1.PartialBuffer
|
||||||
GetdentsTest/1.ProcSelfFd
|
|
Reference in New Issue
Block a user