From 6fc6df0643693cd1d31c0d34d554a05a02a6d719 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Thu, 4 Jan 2024 20:09:49 +0000 Subject: [PATCH] add basic support of file attributes --- src/fd/mod.rs | 12 +++-- src/fs/fuse.rs | 38 +++++++------- src/fs/mem.rs | 117 ++++++++++++++++++++++++++++++++++++++------ src/fs/mod.rs | 20 +++++--- src/fs/uhyve.rs | 4 +- src/syscalls/mod.rs | 8 +-- 6 files changed, 148 insertions(+), 51 deletions(-) diff --git a/src/fd/mod.rs b/src/fd/mod.rs index 018cf206f9..8db34177b8 100644 --- a/src/fd/mod.rs +++ b/src/fd/mod.rs @@ -81,8 +81,8 @@ bitflags! { } bitflags! { - #[derive(Debug, Copy, Clone, Default)] - pub(crate) struct AccessPermission: i32 { + #[derive(Debug, Copy, Clone)] + pub struct AccessPermission: u32 { const S_IRUSR = 0o400; const S_IWUSR = 0o200; const S_IXUSR = 0o100; @@ -98,6 +98,12 @@ bitflags! { } } +impl Default for AccessPermission { + fn default() -> Self { + AccessPermission::from_bits(0o666).unwrap() + } +} + #[repr(C)] #[derive(Debug, Copy, Clone, Default)] pub struct Dirent { @@ -242,7 +248,7 @@ pub(crate) trait ObjectInterface: Sync + Send + core::fmt::Debug + DynClone { fn close(&self) {} } -pub(crate) fn open(name: &str, flags: i32, mode: i32) -> Result { +pub(crate) fn open(name: &str, flags: i32, mode: u32) -> Result { // mode is 0x777 (0b0111_0111_0111), when flags | O_CREAT, else 0 // flags is bitmask of O_DEC_* defined above. // (taken from rust stdlib/sys hermit target ) diff --git a/src/fs/fuse.rs b/src/fs/fuse.rs index 6ed885302d..d8d11a1cd6 100644 --- a/src/fs/fuse.rs +++ b/src/fs/fuse.rs @@ -204,24 +204,24 @@ struct fuse_attr { pub padding: u32, } -impl fuse_attr { - fn to_stat(&self) -> FileAttr { +impl From for FileAttr { + fn from(attr: fuse_attr) -> FileAttr { FileAttr { - st_ino: self.ino, - st_nlink: self.nlink as u64, - st_mode: self.mode, - st_uid: self.uid, - st_gid: self.gid, - st_rdev: self.rdev as u64, - st_size: self.size.try_into().unwrap(), - st_blksize: self.blksize as i64, - st_blocks: self.blocks.try_into().unwrap(), - st_atime: self.atime.try_into().unwrap(), - st_atime_nsec: self.atimensec as i64, - st_mtime: self.mtime.try_into().unwrap(), - st_mtime_nsec: self.atimensec as i64, - st_ctime: self.ctime.try_into().unwrap(), - st_ctime_nsec: self.ctimensec as i64, + st_ino: attr.ino, + st_nlink: attr.nlink as u64, + st_mode: AccessPermission::from_bits(attr.mode).unwrap(), + st_uid: attr.uid, + st_gid: attr.gid, + st_rdev: attr.rdev as u64, + st_size: attr.size.try_into().unwrap(), + st_blksize: attr.blksize as i64, + st_blocks: attr.blocks.try_into().unwrap(), + st_atime: attr.atime.try_into().unwrap(), + st_atime_nsec: attr.atimensec as i64, + st_mtime: attr.mtime.try_into().unwrap(), + st_mtime_nsec: attr.atimensec as i64, + st_ctime: attr.ctime.try_into().unwrap(), + st_ctime_nsec: attr.ctimensec as i64, ..Default::default() } } @@ -1498,7 +1498,7 @@ impl VfsNode for FuseDirectory { let attr = rsp.attr; if attr.mode & S_IFMT != S_IFLNK { - Ok(attr.to_stat()) + Ok(FileAttr::from(attr)) } else { let path = readlink(rsp.nodeid)?; let mut components: Vec<&str> = path.split('/').collect(); @@ -1522,7 +1522,7 @@ impl VfsNode for FuseDirectory { .send_command(cmd.as_ref(), rsp.as_mut()); let attr = unsafe { rsp.rsp.assume_init().attr }; - Ok(attr.to_stat()) + Ok(FileAttr::from(attr)) } fn traverse_open( diff --git a/src/fs/mem.rs b/src/fs/mem.rs index 06ca4b3a12..5beeaad9b6 100644 --- a/src/fs/mem.rs +++ b/src/fs/mem.rs @@ -151,7 +151,10 @@ impl Clone for RamFileInterface { } #[derive(Debug, Clone)] -pub(crate) struct RomFile(Arc>); +pub(crate) struct RomFile { + data: Arc>, + attr: FileAttr, +} impl VfsNode for RomFile { fn get_kind(&self) -> NodeKind { @@ -159,20 +162,49 @@ impl VfsNode for RomFile { } fn get_object(&self) -> Result, IoError> { - Ok(Arc::new(RomFileInterface::new(self.0.clone()))) + Ok(Arc::new(RomFileInterface::new(self.data.clone()))) + } + + fn get_file_attributes(&self) -> Result { + Ok(self.attr) + } + + fn traverse_lstat(&self, components: &mut Vec<&str>) -> Result { + if components.is_empty() { + Ok(self.attr) + } else { + Err(IoError::EBADF) + } + } + + fn traverse_stat(&self, components: &mut Vec<&str>) -> Result { + if components.is_empty() { + Ok(self.attr) + } else { + Err(IoError::EBADF) + } } } impl RomFile { - pub unsafe fn new(ptr: *const u8, length: usize) -> Self { - Self(Arc::new(RwSpinLock::new(unsafe { - slice::from_raw_parts(ptr, length) - }))) + pub unsafe fn new(ptr: *const u8, length: usize, mode: AccessPermission) -> Self { + Self { + data: Arc::new(RwSpinLock::new(unsafe { + slice::from_raw_parts(ptr, length) + })), + attr: FileAttr { + st_mode: mode, + ..Default::default() + }, + } } } #[derive(Debug, Clone)] -pub(crate) struct RamFile(Arc>>); +pub(crate) struct RamFile { + data: Arc>>, + attr: FileAttr, +} impl VfsNode for RamFile { fn get_kind(&self) -> NodeKind { @@ -180,13 +212,39 @@ impl VfsNode for RamFile { } fn get_object(&self) -> Result, IoError> { - Ok(Arc::new(RamFileInterface::new(self.0.clone()))) + Ok(Arc::new(RamFileInterface::new(self.data.clone()))) + } + + fn get_file_attributes(&self) -> Result { + Ok(self.attr) + } + + fn traverse_lstat(&self, components: &mut Vec<&str>) -> Result { + if components.is_empty() { + Ok(self.attr) + } else { + Err(IoError::EBADF) + } + } + + fn traverse_stat(&self, components: &mut Vec<&str>) -> Result { + if components.is_empty() { + Ok(self.attr) + } else { + Err(IoError::EBADF) + } } } impl RamFile { - pub fn new() -> Self { - Self(Arc::new(RwSpinLock::new(Vec::new()))) + pub fn new(mode: AccessPermission) -> Self { + Self { + data: Arc::new(RwSpinLock::new(Vec::new())), + attr: FileAttr { + st_mode: mode, + ..Default::default() + }, + } } } @@ -308,19 +366,30 @@ pub(crate) struct MemDirectory { inner: Arc< RwSpinLock>>, >, + attr: FileAttr, } impl MemDirectory { - pub fn new() -> Self { + pub fn new(mode: AccessPermission) -> Self { Self { inner: Arc::new(RwSpinLock::new(BTreeMap::new())), + attr: FileAttr { + st_mode: mode, + ..Default::default() + }, } } - pub fn create_file(&self, name: &str, ptr: *const u8, length: usize) -> Result<(), IoError> { + pub fn create_file( + &self, + name: &str, + ptr: *const u8, + length: usize, + mode: AccessPermission, + ) -> Result<(), IoError> { let name = name.trim(); if name.find('/').is_none() { - let file = unsafe { RomFile::new(ptr, length) }; + let file = unsafe { RomFile::new(ptr, length, mode) }; self.inner.write().insert(name.to_string(), Box::new(file)); Ok(()) } else { @@ -334,6 +403,10 @@ impl VfsNode for MemDirectory { NodeKind::Directory } + fn get_file_attributes(&self) -> Result { + Ok(self.attr) + } + fn traverse_mkdir( &self, components: &mut Vec<&str>, @@ -349,7 +422,7 @@ impl VfsNode for MemDirectory { if components.is_empty() { self.inner .write() - .insert(node_name, Box::new(MemDirectory::new())); + .insert(node_name, Box::new(MemDirectory::new(mode))); return Ok(()); } } @@ -426,6 +499,12 @@ impl VfsNode for MemDirectory { if let Some(component) = components.pop() { let node_name = String::from(component); + if components.is_empty() { + if let Some(node) = self.inner.read().get(&node_name) { + node.get_file_attributes()?; + } + } + if let Some(directory) = self.inner.read().get(&node_name) { directory.traverse_lstat(components) } else { @@ -440,6 +519,12 @@ impl VfsNode for MemDirectory { if let Some(component) = components.pop() { let node_name = String::from(component); + if components.is_empty() { + if let Some(node) = self.inner.read().get(&node_name) { + node.get_file_attributes()?; + } + } + if let Some(directory) = self.inner.read().get(&node_name) { directory.traverse_stat(components) } else { @@ -486,9 +571,9 @@ impl VfsNode for MemDirectory { if guard.get(&node_name).is_some() { return Err(IoError::EEXIST); } else { - let file = Box::new(RamFile::new()); + let file = Box::new(RamFile::new(mode)); guard.insert(node_name, file.clone()); - return Ok(Arc::new(RamFileInterface::new(file.0.clone()))); + return Ok(Arc::new(RamFileInterface::new(file.data.clone()))); } } else if let Some(file) = guard.get(&node_name) { if file.get_kind() == NodeKind::File { diff --git a/src/fs/mod.rs b/src/fs/mod.rs index f850cae487..242c8e6ef2 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -28,6 +28,11 @@ pub(crate) trait VfsNode: core::fmt::Debug { /// Determines the current node type fn get_kind(&self) -> NodeKind; + /// determines the current file attribute + fn get_file_attributes(&self) -> Result { + Err(IoError::ENOSYS) + } + /// Determine the syscall interface fn get_object(&self) -> Result, IoError> { Err(IoError::ENOSYS) @@ -98,7 +103,7 @@ pub(crate) struct Filesystem { impl Filesystem { pub fn new() -> Self { Self { - root: MemDirectory::new(), + root: MemDirectory::new(AccessPermission::from_bits(0o777).unwrap()), } } @@ -210,8 +215,9 @@ impl Filesystem { name: &str, ptr: *const u8, length: usize, + mode: AccessPermission, ) -> Result<(), IoError> { - self.root.create_file(name, ptr, length) + self.root.create_file(name, ptr, length, mode) } } @@ -221,7 +227,7 @@ pub struct FileAttr { pub st_dev: u64, pub st_ino: u64, pub st_nlink: u64, - pub st_mode: u32, + pub st_mode: AccessPermission, pub st_uid: u32, pub st_gid: u32, pub st_rdev: u64, @@ -275,7 +281,7 @@ pub(crate) fn init() { if let Ok(fd) = FILESYSTEM.get().unwrap().open( "/etc/hostname", OpenOption::O_CREAT | OpenOption::O_RDWR, - AccessPermission::from_bits(0o666).unwrap(), + AccessPermission::from_bits(0o644).unwrap(), ) { let _ret = fd.write(b"Hermit"); fd.close(); @@ -283,7 +289,7 @@ pub(crate) fn init() { if let Ok(fd) = FILESYSTEM.get().unwrap().open( "/etc/version", OpenOption::O_CREAT | OpenOption::O_RDWR, - AccessPermission::from_bits(0o666).unwrap(), + AccessPermission::from_bits(0o644).unwrap(), ) { let _ret = fd.write(VERSION.as_bytes()); fd.close(); @@ -294,12 +300,12 @@ pub(crate) fn init() { uhyve::init(); } -pub unsafe fn create_file(name: &str, ptr: *const u8, length: usize) { +pub unsafe fn create_file(name: &str, ptr: *const u8, length: usize, mode: AccessPermission) { unsafe { FILESYSTEM .get() .unwrap() - .create_file(name, ptr, length) + .create_file(name, ptr, length, mode) .expect("Unable to create file from ROM") } } diff --git a/src/fs/uhyve.rs b/src/fs/uhyve.rs index c9caa4ca92..136cbb7d05 100644 --- a/src/fs/uhyve.rs +++ b/src/fs/uhyve.rs @@ -66,12 +66,12 @@ const UHYVE_PORT_UNLINK: u16 = 0x840; struct SysOpen { name: PhysAddr, flags: i32, - mode: i32, + mode: u32, ret: i32, } impl SysOpen { - fn new(name: VirtAddr, flags: i32, mode: i32) -> SysOpen { + fn new(name: VirtAddr, flags: i32, mode: u32) -> SysOpen { SysOpen { name: paging::virtual_to_physical(name).unwrap(), flags, diff --git a/src/syscalls/mod.rs b/src/syscalls/mod.rs index c845e42a9b..c161ee3b04 100644 --- a/src/syscalls/mod.rs +++ b/src/syscalls/mod.rs @@ -117,7 +117,7 @@ pub extern "C" fn sys_unlink(name: *const u8) -> i32 { kernel_function!(__sys_unlink(name)) } -extern "C" fn __sys_mkdir(name: *const u8, mode: i32) -> i32 { +extern "C" fn __sys_mkdir(name: *const u8, mode: u32) -> i32 { let name = unsafe { CStr::from_ptr(name as _) }.to_str().unwrap(); let mode = if let Some(mode) = AccessPermission::from_bits(mode) { mode @@ -133,7 +133,7 @@ extern "C" fn __sys_mkdir(name: *const u8, mode: i32) -> i32 { } #[no_mangle] -pub extern "C" fn sys_mkdir(name: *const u8, mode: i32) -> i32 { +pub extern "C" fn sys_mkdir(name: *const u8, mode: u32) -> i32 { kernel_function!(__sys_mkdir(name, mode)) } @@ -216,7 +216,7 @@ pub extern "C" fn sys_opendir(name: *const u8) -> FileDescriptor { kernel_function!(__sys_opendir(name)) } -extern "C" fn __sys_open(name: *const u8, flags: i32, mode: i32) -> FileDescriptor { +extern "C" fn __sys_open(name: *const u8, flags: i32, mode: u32) -> FileDescriptor { if let Ok(name) = unsafe { CStr::from_ptr(name as _) }.to_str() { crate::fd::open(name, flags, mode) .map_or_else(|e| -num::ToPrimitive::to_i32(&e).unwrap(), |v| v) @@ -226,7 +226,7 @@ extern "C" fn __sys_open(name: *const u8, flags: i32, mode: i32) -> FileDescript } #[no_mangle] -pub extern "C" fn sys_open(name: *const u8, flags: i32, mode: i32) -> FileDescriptor { +pub extern "C" fn sys_open(name: *const u8, flags: i32, mode: u32) -> FileDescriptor { kernel_function!(__sys_open(name, flags, mode)) }