diff --git a/src/fd/mod.rs b/src/fd/mod.rs index f2f4909585..2fc4cffcc9 100644 --- a/src/fd/mod.rs +++ b/src/fd/mod.rs @@ -1,4 +1,5 @@ use alloc::sync::Arc; +use alloc::vec::Vec; use core::sync::atomic::{AtomicI32, Ordering}; use ahash::RandomState; @@ -147,7 +148,7 @@ pub(crate) trait ObjectInterface: Sync + Send + core::fmt::Debug + DynClone { /// 'readdir' returns a pointer to a dirent structure /// representing the next directory entry in the directory stream /// pointed to by the file descriptor - fn readdir(&self) -> Result, IoError> { + fn readdir(&self) -> Result, IoError> { Err(IoError::EINVAL) } diff --git a/src/fs/fuse.rs b/src/fs/fuse.rs index 5b3777a201..802ffb2e6e 100644 --- a/src/fs/fuse.rs +++ b/src/fs/fuse.rs @@ -1387,7 +1387,9 @@ impl VfsNode for FuseDirectory { dirent.d_namelen.try_into().unwrap(), ) }; - entries.push(DirectoryEntry::new(name)); + entries.push(DirectoryEntry::new(unsafe { + core::str::from_utf8_unchecked(name).to_string() + })); } let (cmd, mut rsp) = create_release(fuse_nid, fuse_fh); diff --git a/src/fs/mem.rs b/src/fs/mem.rs index 34de4da98d..92b5565a81 100644 --- a/src/fs/mem.rs +++ b/src/fs/mem.rs @@ -426,7 +426,7 @@ impl VfsNode for MemDirectory { } else { let mut entries: Vec = Vec::new(); for name in self.inner.read().keys() { - entries.push(DirectoryEntry::new(name.as_bytes())); + entries.push(DirectoryEntry::new(name.to_string())); } Ok(entries) diff --git a/src/fs/mod.rs b/src/fs/mod.rs index dfae99306c..635c7fac4d 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -9,7 +9,7 @@ use alloc::sync::Arc; use alloc::vec::Vec; use core::ffi::CStr; use core::fmt; -use core::sync::atomic::{AtomicUsize, Ordering}; +use core::sync::atomic::Ordering; use hermit_sync::OnceCell; use mem::MemDirectory; @@ -22,36 +22,14 @@ use crate::time::{timespec, SystemTime}; pub(crate) static FILESYSTEM: OnceCell = OnceCell::new(); -pub const MAX_NAME_LENGTH: usize = 256; - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct DirectoryEntry { - pub d_name: [u8; MAX_NAME_LENGTH], +#[derive(Debug, Clone)] +pub(crate) struct DirectoryEntry { + pub name: String, } impl DirectoryEntry { - pub fn new(d_name: &[u8]) -> Self { - let len = core::cmp::min(d_name.len(), MAX_NAME_LENGTH); - let mut entry = Self { - d_name: [0; MAX_NAME_LENGTH], - }; - - entry.d_name[..len].copy_from_slice(&d_name[..len]); - - entry - } -} - -impl fmt::Debug for DirectoryEntry { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let d_name = unsafe { CStr::from_ptr(self.d_name.as_ptr() as _) } - .to_str() - .unwrap(); - - f.debug_struct("DirectoryEntry") - .field("d_name", &d_name) - .finish() + pub fn new(name: String) -> Self { + Self { name } } } @@ -147,38 +125,18 @@ pub(crate) trait VfsNode: core::fmt::Debug { } } -#[derive(Debug)] -struct DirectoryReader { - pos: AtomicUsize, - data: Vec, -} +#[derive(Debug, Clone)] +struct DirectoryReader(Vec); impl DirectoryReader { pub fn new(data: Vec) -> Self { - Self { - pos: AtomicUsize::new(0), - data, - } + Self(data) } } impl ObjectInterface for DirectoryReader { - fn readdir(&self) -> Result, IoError> { - let pos = self.pos.fetch_add(1, Ordering::SeqCst); - if pos < self.data.len() { - Ok(Some(self.data[pos])) - } else { - Ok(None) - } - } -} - -impl Clone for DirectoryReader { - fn clone(&self) -> Self { - Self { - pos: AtomicUsize::new(self.pos.load(Ordering::SeqCst)), - data: self.data.clone(), - } + fn readdir(&self) -> Result, IoError> { + Ok(self.0.clone()) } } diff --git a/src/lib.rs b/src/lib.rs index f4944e4f33..799948874e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -252,9 +252,9 @@ pub(crate) extern "C" fn __sys_free(ptr: *mut u8, size: usize, align: usize) { #[cfg(target_os = "none")] extern "C" fn initd(_arg: usize) { extern "C" { - #[cfg(all(not(test), not(feature = "syscall")))] + #[cfg(all(not(test), not(feature = "common-os")))] fn runtime_entry(argc: i32, argv: *const *const u8, env: *const *const u8) -> !; - #[cfg(all(not(test), feature = "syscall"))] + #[cfg(all(not(test), feature = "common-os"))] fn main(argc: i32, argv: *const *const u8, env: *const *const u8); #[cfg(feature = "newlib")] fn init_lwip(); @@ -297,9 +297,9 @@ extern "C" fn initd(_arg: usize) { #[cfg(not(test))] unsafe { // And finally start the application. - #[cfg(all(not(test), not(feature = "syscall")))] + #[cfg(all(not(test), not(feature = "common-os")))] runtime_entry(argc, argv, environ); - #[cfg(all(not(test), feature = "syscall"))] + #[cfg(all(not(test), feature = "common-os"))] main(argc, argv, environ); } #[cfg(test)] diff --git a/src/syscalls/mod.rs b/src/syscalls/mod.rs index b396a33530..03d3e1e8a9 100644 --- a/src/syscalls/mod.rs +++ b/src/syscalls/mod.rs @@ -1,6 +1,7 @@ #![allow(clippy::result_unit_err)] use core::ffi::CStr; +use core::marker::PhantomData; #[cfg(feature = "newlib")] use hermit_sync::InterruptTicketMutex; @@ -335,32 +336,65 @@ pub extern "C" fn sys_lseek(fd: FileDescriptor, offset: isize, whence: i32) -> i kernel_function!(__sys_lseek(fd, offset, whence)) } -extern "C" fn __sys_readdir( - fd: FileDescriptor, - dirent: *mut DirectoryEntry, - dirent_len: *mut usize, -) -> i32 { - if dirent.is_null() || dirent_len.is_null() { - return -crate::errno::EINVAL; +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct Dirent64 { + /// 64-bit inode number + pub d_ino: u64, + /// 64-bit offset to next structure + pub d_off: i64, + /// Size of this dirent + pub d_reclen: u16, + /// File type + pub d_type: u8, + /// Filename (null-terminated) + pub d_name: PhantomData, +} + +extern "C" fn __sys_getdents64(fd: FileDescriptor, dirp: *mut Dirent64, count: usize) -> i64 { + if dirp.is_null() || count == 0 { + return -crate::errno::EINVAL as i64; } - let dirent = unsafe { &mut *dirent }; - let dirent_len = unsafe { &mut *dirent_len }; + let limit = dirp as usize + count; + let mut dirp: *mut Dirent64 = dirp; + let mut offset: i64 = 0; let obj = get_object(fd); obj.map_or_else( - |_| -crate::errno::EINVAL, + |_| -crate::errno::EINVAL as i64, |v| { (*v).readdir().map_or_else( - |e| -num::ToPrimitive::to_i32(&e).unwrap(), + |e| -num::ToPrimitive::to_i64(&e).unwrap(), |v| { - if let Some(v) = v { - *dirent = v; - *dirent_len = core::mem::size_of::(); - } else { - *dirent_len = 0; + for i in v.iter() { + let len = (*i).name.len(); + if dirp as usize + core::mem::size_of::() + len + 1 >= limit { + return -crate::errno::EINVAL as i64; + } + + let dir = unsafe { &mut *dirp }; + + dir.d_ino = 0; + dir.d_type = 0; + dir.d_reclen = (core::mem::size_of::() + len + 1) + .try_into() + .unwrap(); + offset += i64::try_from(dir.d_reclen).unwrap(); + dir.d_off = offset; + + // copy null-terminated filename + let s = &mut dir.d_name as *mut _ as *mut u8; + unsafe { + core::ptr::copy_nonoverlapping((*i).name.as_ptr(), s, len); + s.offset(len as isize).write_bytes(0, 1); + } + + dirp = unsafe { + (dirp as *mut u8).offset(dir.d_reclen as isize) as *mut Dirent64 + }; } - 0 + offset }, ) }, @@ -368,12 +402,8 @@ extern "C" fn __sys_readdir( } #[no_mangle] -pub extern "C" fn sys_readdir( - fd: FileDescriptor, - dirent: *mut DirectoryEntry, - dirent_len: *mut usize, -) -> i32 { - kernel_function!(__sys_readdir(fd, dirent, dirent_len)) +pub extern "C" fn sys_getdents64(fd: FileDescriptor, dirp: *mut Dirent64, count: usize) -> i64 { + kernel_function!(__sys_getdents64(fd, dirp, count)) } extern "C" fn __sys_dup(fd: i32) -> i32 {