Skip to content

Commit

Permalink
replace sys_read by sys_getdents64
Browse files Browse the repository at this point in the history
sys_getdents64 is compatible to Linux' system call getdents64.
Consequently, it offers the reusing of an existing ABI.
  • Loading branch information
stlankes committed Jan 9, 2024
1 parent d1d5b75 commit d994f47
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 83 deletions.
3 changes: 2 additions & 1 deletion src/fd/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::sync::atomic::{AtomicI32, Ordering};

use ahash::RandomState;
Expand Down Expand Up @@ -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<Option<DirectoryEntry>, IoError> {
fn readdir(&self) -> Result<Vec<DirectoryEntry>, IoError> {
Err(IoError::EINVAL)
}

Expand Down
4 changes: 3 additions & 1 deletion src/fs/fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/fs/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ impl VfsNode for MemDirectory {
} else {
let mut entries: Vec<DirectoryEntry> = 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)
Expand Down
64 changes: 11 additions & 53 deletions src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,36 +22,14 @@ use crate::time::{timespec, SystemTime};

pub(crate) static FILESYSTEM: OnceCell<Filesystem> = 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 }
}
}

Expand Down Expand Up @@ -147,38 +125,18 @@ pub(crate) trait VfsNode: core::fmt::Debug {
}
}

#[derive(Debug)]
struct DirectoryReader {
pos: AtomicUsize,
data: Vec<DirectoryEntry>,
}
#[derive(Debug, Clone)]
struct DirectoryReader(Vec<DirectoryEntry>);

impl DirectoryReader {
pub fn new(data: Vec<DirectoryEntry>) -> Self {
Self {
pos: AtomicUsize::new(0),
data,
}
Self(data)
}
}

impl ObjectInterface for DirectoryReader {
fn readdir(&self) -> Result<Option<DirectoryEntry>, 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<Vec<DirectoryEntry>, IoError> {
Ok(self.0.clone())
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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)]
Expand Down
76 changes: 53 additions & 23 deletions src/syscalls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(clippy::result_unit_err)]

use core::ffi::CStr;
use core::marker::PhantomData;

#[cfg(feature = "newlib")]
use hermit_sync::InterruptTicketMutex;
Expand Down Expand Up @@ -335,45 +336,74 @@ 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<u8>,
}

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::<DirectoryEntry>();
} else {
*dirent_len = 0;
for i in v.iter() {
let len = (*i).name.len();
if dirp as usize + core::mem::size_of::<Dirent64>() + 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::<Dirent64>() + 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
},
)
},
)
}

#[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 {
Expand Down

0 comments on commit d994f47

Please sign in to comment.