From 18bc4a917086888790762385618e9136a025bab1 Mon Sep 17 00:00:00 2001 From: liujingx Date: Wed, 19 Feb 2025 21:28:39 +0800 Subject: [PATCH] fix: incompatible interfaces --- api/ruxos_posix_api/src/imp/fs.rs | 79 ++++--- modules/ruxfdtable/src/lib.rs | 2 - modules/ruxfs/Cargo.toml | 1 - modules/ruxfs/src/api/dir.rs | 3 +- modules/ruxfs/src/api/file.rs | 85 ++----- modules/ruxfs/src/api/mod.rs | 2 +- modules/ruxfs/src/fops.rs | 302 ++++++++++++++----------- modules/ruxfs/src/lib.rs | 5 +- modules/ruxfs/src/root.rs | 233 +------------------ modules/ruxnet/src/unix.rs | 7 +- modules/ruxruntime/src/lib.rs | 2 +- modules/ruxruntime/tests/test_fatfs.rs | 2 +- modules/ruxtask/src/fs.rs | 82 +++---- modules/ruxtask/src/lib.rs | 2 +- modules/ruxtask/src/vma.rs | 2 +- ulib/ruxmusl/src/x86_64/mod.rs | 2 +- 16 files changed, 289 insertions(+), 522 deletions(-) diff --git a/api/ruxos_posix_api/src/imp/fs.rs b/api/ruxos_posix_api/src/imp/fs.rs index 20a95d4e7..7e5749d6c 100644 --- a/api/ruxos_posix_api/src/imp/fs.rs +++ b/api/ruxos_posix_api/src/imp/fs.rs @@ -14,17 +14,14 @@ use core::{ }; use axerrno::{LinuxError, LinuxResult}; -use axio::{Error, PollState, SeekFrom}; -use axsync::Mutex; -use capability::Cap; +use axio::{Error, SeekFrom}; use ruxfdtable::{FileLike, RuxStat}; use ruxfs::{ - fops::{self, DirEntry}, + fops::{self, DirEntry, OpenOptions}, AbsPath, RelPath, }; -use crate::{ctypes, utils::char_ptr_to_str}; -use alloc::vec::Vec; +use crate::ctypes; use ruxtask::fs::{get_file_like, Directory, File}; use super::stdio::{stdin, stdout}; @@ -42,13 +39,34 @@ impl ruxtask::fs::InitFs for InitFsImpl { } } -/// Convert open flags to [`Cap`]. -fn flags_to_cap(flags: u32) -> Cap { +/// Convert open flags to [`OpenOptions`]. +pub fn flags_to_options(flags: c_int, _mode: ctypes::mode_t) -> OpenOptions { + let flags = flags as u32; + let mut options = OpenOptions::new(); match flags & 0b11 { - ctypes::O_RDONLY => Cap::READ, - ctypes::O_WRONLY => Cap::WRITE, - _ => Cap::READ | Cap::WRITE, + ctypes::O_RDONLY => options.read(true), + ctypes::O_WRONLY => options.write(true), + _ => { + options.read(true); + options.write(true); + } + }; + if flags & ctypes::O_APPEND != 0 { + options.append(true); + } + if flags & ctypes::O_TRUNC != 0 { + options.truncate(true); + } + if flags & ctypes::O_CREAT != 0 { + options.create(true); + } + if flags & ctypes::O_EXEC != 0 { + options.create_new(true); + } + if flags & ctypes::O_CLOEXEC != 0 { + options.cloexec(true); } + options } /// Open a file by `filename` and insert it into the file descriptor table. @@ -58,6 +76,7 @@ fn flags_to_cap(flags: u32) -> Cap { pub fn sys_open(filename: *const c_char, flags: c_int, mode: ctypes::mode_t) -> c_int { syscall_body!(sys_open, { let path = parse_path(filename)?; + let opts = flags_to_options(flags, mode); let flags = flags as u32; debug!("sys_open <= {:?} {:#o} {:#o}", path, flags, mode); // Check flag and attr @@ -85,9 +104,8 @@ pub fn sys_open(filename: *const c_char, flags: c_int, mode: ctypes::mode_t) -> node.truncate(0)?; } // Open - let append = flags & ctypes::O_APPEND != 0; - let file = fops::open_file(&path, node, flags_to_cap(flags), append)?; - File::new(file).add_to_fd_table() + let file = fops::open_file(&path, node, &opts)?; + File::new(file).add_to_fd_table(opts) }) } @@ -95,8 +113,8 @@ pub fn sys_open(filename: *const c_char, flags: c_int, mode: ctypes::mode_t) -> pub fn sys_openat(fd: c_int, path: *const c_char, flags: c_int, mode: ctypes::mode_t) -> c_int { syscall_body!(sys_openat, { let path = parse_path_at(fd, path)?; + let opts = flags_to_options(flags, mode); let flags = flags as u32; - let cap = flags_to_cap(flags); debug!( "sys_openat <= {}, {:?}, {:#o}, {:#o}", fd, path, flags, mode @@ -132,13 +150,12 @@ pub fn sys_openat(fd: c_int, path: *const c_char, flags: c_int, mode: ctypes::mo Err(e) => return Err(e.into()), }; // Open file or directory - let append = flags & ctypes::O_APPEND != 0; if node.get_attr()?.is_dir() { - let dir = fops::open_dir(&path, node, cap)?; - Directory::new(dir, flags & ctypes::O_SEARCH != 0).add_to_fd_table() + let dir = fops::open_dir(&path, node, &opts)?; + Directory::new(dir, flags & ctypes::O_SEARCH != 0).add_to_fd_table(opts) } else { - let file = fops::open_file(&path, node, cap, append)?; - File::new(file).add_to_fd_table() + let file = fops::open_file(&path, node, &opts)?; + File::new(file).add_to_fd_table(opts) } }) } @@ -228,11 +245,11 @@ pub unsafe fn sys_stat(path: *const c_char, buf: *mut core::ffi::c_void) -> c_in } let node = fops::lookup(&path)?; let attr = node.get_attr()?; - let st = if attr.is_dir() { - let dir = fops::open_dir(&path, node, Cap::empty())?; + let st: RuxStat = if attr.is_dir() { + let dir = fops::open_dir(&path, node, &OpenOptions::new())?; Directory::new(dir, false).stat()?.into() } else { - let file = fops::open_file(&path, node, Cap::empty(), false)?; + let file = fops::open_file(&path, node, &OpenOptions::new())?; File::new(file).stat()?.into() }; @@ -335,9 +352,9 @@ pub unsafe fn sys_newfstatat( } let node = fops::lookup(&path)?; let st = if node.get_attr()?.is_dir() { - Directory::new(fops::open_dir(&path, node, Cap::empty())?, false).stat()? + Directory::new(fops::open_dir(&path, node, &OpenOptions::new())?, false).stat()? } else { - File::new(fops::open_file(&path, node, Cap::empty(), false)?).stat()? + File::new(fops::open_file(&path, node, &OpenOptions::new())?).stat()? }; unsafe { (*kst).st_dev = st.st_dev; @@ -362,7 +379,7 @@ pub fn sys_getcwd(buf: *mut c_char, size: usize) -> c_int { return Err(LinuxError::EINVAL); } let dst = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, size as _) }; - let cwd = fops::current_dir(); + let cwd = fops::current_dir()?; let cwd = cwd.as_bytes(); if cwd.len() < size { dst[..cwd.len()].copy_from_slice(cwd); @@ -591,8 +608,8 @@ pub unsafe fn sys_getdents64(fd: c_int, dirp: *mut LinuxDirent64, count: ctypes: loop { let mut entry = [DirEntry::default()]; - let offset = dir.inner.lock().entry_idx(); - let n = dir.inner.lock().read_dir(&mut entry)?; + let offset = dir.inner.read().entry_idx(); + let n = dir.inner.write().read_dir(&mut entry)?; debug!( "entry {:?}", str::from_utf8(entry[0].name_as_bytes()).unwrap() @@ -610,7 +627,7 @@ pub unsafe fn sys_getdents64(fd: c_int, dirp: *mut LinuxDirent64, count: ctypes: if written + entry_size > count { debug!("buf not big enough"); // revert the offset - dir.inner.lock().set_entry_idx(offset); + dir.inner.write().set_entry_idx(offset); break; } @@ -709,7 +726,7 @@ pub fn parse_path(path: *const c_char) -> LinuxResult> { if path.starts_with('/') { Ok(AbsPath::new_canonicalized(path)) } else { - Ok(fops::current_dir().join(&RelPath::new_canonicalized(path))) + Ok(fops::current_dir()?.join(&RelPath::new_canonicalized(path))) } } @@ -725,7 +742,7 @@ pub fn parse_path_at(dirfd: c_int, path: *const c_char) -> LinuxResult) -> Result { let node = fops::lookup(&path)?; - let inner = fops::open_dir(&path, node, Cap::EXECUTE)?; + let inner = fops::open_dir(&path, node, &fops::OpenOptions::new())?; Ok(Self { inner }) } diff --git a/modules/ruxfs/src/api/file.rs b/modules/ruxfs/src/api/file.rs index 15b947096..3327d0579 100644 --- a/modules/ruxfs/src/api/file.rs +++ b/modules/ruxfs/src/api/file.rs @@ -10,7 +10,6 @@ use axerrno::ax_err; use axfs_vfs::{AbsPath, VfsError}; use axio::{prelude::*, Result, SeekFrom}; -use capability::Cap; use core::fmt; use crate::fops; @@ -27,109 +26,66 @@ pub type FileAttr = fops::FileAttr; /// Options and flags which can be used to configure how a file is opened. #[derive(Clone)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - _custom_flags: i32, - _mode: u32, -} +pub struct OpenOptions(fops::OpenOptions); impl OpenOptions { /// Creates a blank new set of options ready for configuration. pub const fn new() -> Self { - Self { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - _custom_flags: 0, - _mode: 0o666, - } + Self(fops::OpenOptions::new()) } /// Sets the option for read access. pub fn read(&mut self, read: bool) -> &mut Self { - self.read = read; + self.0.read(read); self } /// Sets the option for write access. pub fn write(&mut self, write: bool) -> &mut Self { - self.write = write; + self.0.write(write); self } /// Sets the option for the append mode. pub fn append(&mut self, append: bool) -> &mut Self { - self.append = append; + self.0.append(append); self } /// Sets the option for truncating a previous file. pub fn truncate(&mut self, truncate: bool) -> &mut Self { - self.truncate = truncate; + self.0.truncate(truncate); self } /// Sets the option to create a new file, or open it if it already exists. pub fn create(&mut self, create: bool) -> &mut Self { - self.create = create; + self.0.create(create); self } /// Sets the option to create a new file, failing if it already exists. pub fn create_new(&mut self, create_new: bool) -> &mut Self { - self.create_new = create_new; + self.0.create_new(create_new); self } - /// Check if the options are valid. - pub const fn is_valid(&self) -> bool { - if !self.read && !self.write && !self.append { - return false; - } - match (self.write, self.append) { - (true, false) => {} - (false, false) => { - if self.truncate || self.create || self.create_new { - return false; - } - } - (_, true) => { - if self.truncate && !self.create_new { - return false; - } - } - } - true - } - /// Opens a file at `path` with the options specified by `self`. pub fn open(&self, path: &AbsPath) -> Result { // Check options - if !self.is_valid() { + if !self.0.is_valid() { return ax_err!(InvalidInput); } // Find node, check flag and attr let node = match fops::lookup(&path) { Ok(node) => { - if self.create_new { + if self.0.create_new { return ax_err!(AlreadyExists); } node } Err(VfsError::NotFound) => { - if !self.create && !self.create_new { + if !self.0.create && !self.0.create_new { return ax_err!(NotFound); } fops::create_file(&path)?; @@ -141,11 +97,11 @@ impl OpenOptions { return ax_err!(IsADirectory); } // Truncate - if self.truncate { + if self.0.truncate { node.truncate(0)?; } // Open - fops::open_file(&path, node, self.into(), self.append).map(|inner| File { inner }) + fops::open_file(&path, node, &self.0).map(|inner| File { inner }) } } @@ -227,26 +183,13 @@ impl Seek for File { } } -impl From<&OpenOptions> for Cap { - fn from(opts: &OpenOptions) -> Cap { - let mut cap = Cap::empty(); - if opts.read { - cap |= Cap::READ; - } - if opts.write | opts.append { - cap |= Cap::WRITE; - } - cap - } -} - impl fmt::Debug for OpenOptions { #[allow(unused_assignments)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut written = false; macro_rules! fmt_opt { ($field: ident, $label: literal) => { - if self.$field { + if self.0.$field { if written { write!(f, " | ")?; } diff --git a/modules/ruxfs/src/api/mod.rs b/modules/ruxfs/src/api/mod.rs index 2a6ad5796..c16f79566 100644 --- a/modules/ruxfs/src/api/mod.rs +++ b/modules/ruxfs/src/api/mod.rs @@ -29,7 +29,7 @@ pub use file::{File, FileAttr, FilePerm, FileType, OpenOptions}; /// Returns the current working directory as a [`AbsPath`]. pub fn current_dir() -> io::Result> { - Ok(fops::current_dir()) + Ok(fops::current_dir().unwrap()) } /// Changes the current working directory to the specified path. diff --git a/modules/ruxfs/src/fops.rs b/modules/ruxfs/src/fops.rs index 9551e4ca4..6f42fe477 100644 --- a/modules/ruxfs/src/fops.rs +++ b/modules/ruxfs/src/fops.rs @@ -14,12 +14,13 @@ //! //! The interface is designed with low coupling to avoid repetitive error handling. +use alloc::{sync::Arc, vec::Vec}; use axerrno::{ax_err, ax_err_type, AxResult}; -use axfs_vfs::{AbsPath, VfsError, VfsNodeOps, VfsNodeRef, VfsNodeType}; +use axfs_vfs::{AbsPath, RelPath, VfsNodeOps, VfsNodeRef, VfsNodeType}; use axio::SeekFrom; use capability::{Cap, WithCap}; -use crate::root::{CURRENT_DIR, ROOT_DIR}; +use crate::root::{MountPoint, RootDirectory}; #[cfg(feature = "myfs")] pub use crate::dev::Disk; @@ -43,90 +44,6 @@ pub struct File { offset: u64, } -/// An opened directory object, with open permissions and a cursor for -/// [`read_dir`](Directory::read_dir). -pub struct Directory { - node: WithCap, - entry_idx: usize, -} - -/// Options and flags which can be used to configure how a file is opened. -#[derive(Clone)] -pub struct OpenOptions { - // generic - pub read: bool, - pub write: bool, - pub append: bool, - pub truncate: bool, - pub create: bool, - pub create_new: bool, - // system-specific - _custom_flags: i32, - _mode: u32, -} - -impl OpenOptions { - /// Creates a blank new set of options ready for configuration. - pub const fn new() -> Self { - Self { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - _custom_flags: 0, - _mode: 0o666, - } - } - /// Sets the option for read access. - pub fn read(&mut self, read: bool) { - self.read = read; - } - /// Sets the option for write access. - pub fn write(&mut self, write: bool) { - self.write = write; - } - /// Sets the option for the append mode. - pub fn append(&mut self, append: bool) { - self.append = append; - } - /// Sets the option for truncating a previous file. - pub fn truncate(&mut self, truncate: bool) { - self.truncate = truncate; - } - /// Sets the option to create a new file, or open it if it already exists. - pub fn create(&mut self, create: bool) { - self.create = create; - } - /// Sets the option to create a new file, failing if it already exists. - pub fn create_new(&mut self, create_new: bool) { - self.create_new = create_new; - } - - pub const fn is_valid(&self) -> bool { - if !self.read && !self.write && !self.append { - return false; - } - match (self.write, self.append) { - (true, false) => {} - (false, false) => { - if self.truncate || self.create || self.create_new { - return false; - } - } - (_, true) => { - if self.truncate && !self.create_new { - return false; - } - } - } - true - } -} - impl File { /// Create an opened file. pub fn new(path: AbsPath<'static>, node: VfsNodeRef, cap: Cap, append: bool) -> Self { @@ -213,6 +130,12 @@ impl File { } } +impl Drop for File { + fn drop(&mut self) { + unsafe { self.node.access_unchecked().release().ok() }; + } +} + /// An opened directory object, with open permissions and a cursor for entry reading. pub struct Directory { path: AbsPath<'static>, @@ -265,11 +188,148 @@ impl Directory { } } +impl Drop for Directory { + fn drop(&mut self) { + unsafe { self.node.access_unchecked().release().ok() }; + } +} + +/// Options and flags which can be used to configure how a file is opened. +#[derive(Clone)] +pub struct OpenOptions { + // generic + pub read: bool, + pub write: bool, + pub append: bool, + pub truncate: bool, + pub create: bool, + pub create_new: bool, + pub cloexec: bool, + // system-specific + _custom_flags: i32, + _mode: u32, +} + +impl OpenOptions { + /// Creates a blank new set of options ready for configuration. + pub const fn new() -> Self { + Self { + // generic + read: false, + write: false, + append: false, + truncate: false, + create: false, + create_new: false, + cloexec: false, + // system-specific + _custom_flags: 0, + _mode: 0o666, + } + } + /// Sets the option for read access. + pub fn read(&mut self, read: bool) { + self.read = read; + } + /// Sets the option for write access. + pub fn write(&mut self, write: bool) { + self.write = write; + } + /// Sets the option for the append mode. + pub fn append(&mut self, append: bool) { + self.append = append; + } + /// Sets the option for truncating a previous file. + pub fn truncate(&mut self, truncate: bool) { + self.truncate = truncate; + } + /// Sets the option to create a new file, or open it if it already exists. + pub fn create(&mut self, create: bool) { + self.create = create; + } + /// Sets the option to create a new file, failing if it already exists. + pub fn create_new(&mut self, create_new: bool) { + self.create_new = create_new; + } + /// Sets the option to close the file after exec. + pub fn cloexec(&mut self, cloexec: bool) { + self.cloexec = cloexec; + } + /// Convert to capability. + pub fn to_cap(&self) -> Cap { + let mut cap = Cap::empty(); + if self.read { + cap |= Cap::READ; + } + if self.write { + cap |= Cap::WRITE; + } + cap + } + + pub const fn is_valid(&self) -> bool { + if !self.read && !self.write && !self.append { + return false; + } + match (self.write, self.append) { + (true, false) => {} + (false, false) => { + if self.truncate || self.create || self.create_new { + return false; + } + } + (_, true) => { + if self.truncate && !self.create_new { + return false; + } + } + } + true + } +} + +#[crate_interface::def_interface] +/// Current working directory operations. +pub trait CurrentWorkingDirectoryOps { + /// Initializes the root filesystem with the specified mount points. + fn init_rootfs(mount_points: Vec); + /// Returns the parent node of the specified path. + fn parent_node_of(dir: Option<&VfsNodeRef>, path: &RelPath) -> VfsNodeRef; + /// Returns the absolute path of the specified path. + fn absolute_path(path: &str) -> AxResult>; + /// Returns the current working directory. + fn current_dir() -> AxResult>; + /// Sets the current working directory. + fn set_current_dir(path: AbsPath<'static>) -> AxResult; + /// get the root directory of the filesystem + fn root_dir() -> Arc; +} + +pub(crate) fn absolute_path(path: &str) -> AxResult> { + crate_interface::call_interface!(CurrentWorkingDirectoryOps::absolute_path, path) +} + +pub fn current_dir() -> AxResult> { + crate_interface::call_interface!(CurrentWorkingDirectoryOps::current_dir) +} + +pub fn set_current_dir(path: AbsPath<'static>) -> AxResult { + crate_interface::call_interface!(CurrentWorkingDirectoryOps::set_current_dir, path) +} + +pub(crate) fn init_rootfs(mount_points: Vec) { + crate_interface::call_interface!(CurrentWorkingDirectoryOps::init_rootfs, mount_points) +} + +pub(crate) fn root_dir() -> Arc { + crate_interface::call_interface!(CurrentWorkingDirectoryOps::root_dir) +} + // File operations with absolute path. /// Look up a file given an absolute path. pub fn lookup(path: &AbsPath) -> AxResult { - ROOT_DIR.clone().lookup(&path.to_rel()) + root_dir().clone().lookup(&path.to_rel()) } /// Get the file attributes given an absolute path. @@ -278,44 +338,53 @@ pub fn get_attr(path: &AbsPath) -> AxResult { } /// Open a node as a file, with permission checked. -pub fn open_file(path: &AbsPath, node: VfsNodeRef, cap: Cap, append: bool) -> AxResult { +pub fn open_file(path: &AbsPath, node: VfsNodeRef, opt: &OpenOptions) -> AxResult { let attr = node.get_attr()?; - if !perm_to_cap(attr.perm()).contains(cap) { + if !perm_to_cap(attr.perm()).contains(opt.to_cap()) { return ax_err!(PermissionDenied); } node.open()?; - Ok(File::new(path.to_owned(), node, cap, append)) + Ok(File::new(path.to_owned(), node, opt.to_cap(), opt.append)) } /// Open a node as a directory, with permission checked. -pub fn open_dir(path: &AbsPath, node: VfsNodeRef, cap: Cap) -> AxResult { +pub fn open_dir(path: &AbsPath, node: VfsNodeRef, opt: &OpenOptions) -> AxResult { let attr = node.get_attr()?; - if !perm_to_cap(attr.perm()).contains(cap) { + if !perm_to_cap(attr.perm()).contains(opt.to_cap()) { return ax_err!(PermissionDenied); } node.open()?; - Ok(Directory::new(path.to_owned(), node, cap | Cap::EXECUTE)) + Ok(Directory::new(path.to_owned(), node, opt.to_cap() | Cap::EXECUTE)) +} + +/// Lookup and open a file at an arbitrary path. +/// +/// If `path` is relative, it will be resolved against the current working directory. +pub fn open(path: &str, opt: &OpenOptions) -> AxResult { + let path = absolute_path(path)?; + let node = lookup(&path)?; + open_file(&path, node, opt) } /// Create a file given an absolute path. /// /// This function will not check if the file exists, check it with [`lookup`] first. pub fn create_file(path: &AbsPath) -> AxResult { - ROOT_DIR.create(&path.to_rel(), VfsNodeType::File) + root_dir().create(&path.to_rel(), VfsNodeType::File) } /// Create a directory given an absolute path. /// /// This function will not check if the directory exists, check it with [`lookup`] first. pub fn create_dir(path: &AbsPath) -> AxResult { - ROOT_DIR.create(&path.to_rel(), VfsNodeType::Dir) + root_dir().create(&path.to_rel(), VfsNodeType::Dir) } /// Create a directory recursively given an absolute path. /// /// This function will not check if the directory exists, check it with [`lookup`] first. pub fn create_dir_all(path: &AbsPath) -> AxResult { - ROOT_DIR.create_recursive(&path.to_rel(), VfsNodeType::Dir) + root_dir().create_recursive(&path.to_rel(), VfsNodeType::Dir) } /// Remove a file given an absolute path. @@ -323,7 +392,7 @@ pub fn create_dir_all(path: &AbsPath) -> AxResult { /// This function will not check if the file exits or removeable, /// check it with [`lookup`] first. pub fn remove_file(path: &AbsPath) -> AxResult { - ROOT_DIR.unlink(&path.to_rel()) + root_dir().unlink(&path.to_rel()) } /// Remove a directory given an absolute path. @@ -331,10 +400,10 @@ pub fn remove_file(path: &AbsPath) -> AxResult { /// This function will not check if the directory exists or is empty, /// check it with [`lookup`] first. pub fn remove_dir(path: &AbsPath) -> AxResult { - if ROOT_DIR.contains(path) { + if root_dir().contains(path) { return ax_err!(PermissionDenied); } - ROOT_DIR.unlink(&path.to_rel()) + root_dir().unlink(&path.to_rel()) } /// Rename a file given an old and a new absolute path. @@ -342,40 +411,7 @@ pub fn remove_dir(path: &AbsPath) -> AxResult { /// This function will not check if the old path or new path exists, check it with /// [`lookup`] first. pub fn rename(old: &AbsPath, new: &AbsPath) -> AxResult { - ROOT_DIR.rename(&old.to_rel(), &new.to_rel()) -} - -/// Get current working directory. -pub fn current_dir<'a>() -> AbsPath<'a> { - CURRENT_DIR.lock().clone() -} - -/// Set current working directory. -/// -/// Returns error if the path does not exist or is not a directory. -pub fn set_current_dir(path: AbsPath<'static>) -> AxResult { - let node = lookup(&path)?; - let attr = node.get_attr()?; - if !attr.is_dir() { - Err(VfsError::NotADirectory) - } else if !attr.perm().owner_executable() { - Err(VfsError::PermissionDenied) - } else { - *CURRENT_DIR.lock() = path; - Ok(()) - } -} - -impl Drop for File { - fn drop(&mut self) { - unsafe { self.node.access_unchecked().release().ok() }; - } -} - -impl Drop for Directory { - fn drop(&mut self) { - unsafe { self.node.access_unchecked().release().ok() }; - } + root_dir().rename(&old.to_rel(), &new.to_rel()) } pub fn perm_to_cap(perm: FilePerm) -> Cap { diff --git a/modules/ruxfs/src/lib.rs b/modules/ruxfs/src/lib.rs index 38b20f73b..6791148d1 100644 --- a/modules/ruxfs/src/lib.rs +++ b/modules/ruxfs/src/lib.rs @@ -51,6 +51,7 @@ pub type RelPath<'a> = axfs_vfs::RelPath<'a>; use alloc::vec::Vec; +#[cfg(feature = "blkfs")] use ruxdriver::{prelude::*, AxDeviceContainer}; cfg_if::cfg_if! { @@ -70,7 +71,7 @@ cfg_if::cfg_if! { } } -pub use root::MountPoint; +use root::MountPoint; /// Initialize an empty filesystems by ramfs. #[cfg(not(any(feature = "blkfs", feature = "virtio-9p", feature = "net-9p")))] @@ -143,5 +144,5 @@ pub fn prepare_commonfs(mount_points: &mut Vec) { /// Initializes root filesystems. pub fn init_filesystems(mount_points: Vec) { - self::root::init_rootfs(mount_points); + self::fops::init_rootfs(mount_points); } diff --git a/modules/ruxfs/src/root.rs b/modules/ruxfs/src/root.rs index a2c3f806d..4635042a4 100644 --- a/modules/ruxfs/src/root.rs +++ b/modules/ruxfs/src/root.rs @@ -17,8 +17,6 @@ use axerrno::{ax_err, AxResult}; use axfs_vfs::{ AbsPath, RelPath, VfsError, VfsNodeAttr, VfsNodeOps, VfsNodeRef, VfsNodeType, VfsOps, VfsResult, }; -use axsync::Mutex; -use lazy_init::LazyInit; /// mount point information pub struct MountPoint { @@ -28,12 +26,6 @@ pub struct MountPoint { pub fs: Arc, } -/// Root directory of the main filesystem -pub(crate) struct RootDirectory { - main_fs: Arc, - mounts: Vec, -} - // pub(crate) static ROOT_DIR: LazyInit> = LazyInit::new(); impl MountPoint { @@ -50,7 +42,7 @@ impl Drop for MountPoint { } /// Root directory of the main filesystem -pub(crate) struct RootDirectory { +pub struct RootDirectory { main_fs: Arc, mounts: Vec, } @@ -189,226 +181,3 @@ impl VfsNodeOps for RootDirectory { ) } } - -/// Current working directory. -pub(crate) static CURRENT_DIR: Mutex = Mutex::new(AbsPath::new("/")); - -/// Root directory of the virtual filesystem. -pub(crate) static ROOT_DIR: LazyInit> = LazyInit::new(); - -/// Initialize virtual filesystem. -pub(crate) fn init_rootfs(mount_points: Vec) { - let main_fs = mount_points - .first() - .expect("No filesystem found") - .fs - .clone(); - let mut root_dir = RootDirectory::new(main_fs); - - for mp in mount_points.iter().skip(1) { - let vfsops = mp.fs.clone(); - let message = format!("failed to mount filesystem at {}", mp.path); - info!("mounting {}", mp.path); - root_dir.mount(mp.path.clone(), vfsops).expect(&message); - } - - ROOT_DIR.init_by(Arc::new(root_dir)); - *CURRENT_DIR.lock() = AbsPath::new("/"); -} - -/// Look up a file given an absolute path. -pub(crate) fn lookup(path: &AbsPath) -> AxResult { - ROOT_DIR.clone().lookup(&path.to_rel()) -} - -/// Open a file given an absolute path. -pub fn open_file(path: &AbsPath, opts: &OpenOptions) -> AxResult { - debug!("open file: {} {:?}", path, opts); - if !opts.is_valid() { - return ax_err!(InvalidInput); - } - let node = match lookup(path) { - Ok(node) => { - if opts.create_new { - return ax_err!(AlreadyExists); - } - node - } - Err(VfsError::NotFound) => { - if !opts.create || !opts.create_new { - return ax_err!(NotFound); - } - create_file(path)?; - lookup(path)? - } - Err(e) => return Err(e), - }; - - let attr = node.get_attr()?; - if attr.is_dir() { - return ax_err!(IsADirectory); - } - let access_cap = opts.into(); - if !perm_to_cap(attr.perm()).contains(access_cap) { - return ax_err!(PermissionDenied); - } - - node.open()?; - if opts.truncate { - node.truncate(0)?; - } - Ok(File::new(node, access_cap, opts.append)) -} - -/// Open a directory given an absolute path. -pub fn open_dir(path: &AbsPath, opts: &OpenOptions) -> AxResult { - debug!("open dir: {}", path); - if !opts.read { - return ax_err!(InvalidInput); - } - if opts.create || opts.create_new || opts.write || opts.append || opts.truncate { - return ax_err!(InvalidInput); - } - let node = lookup(path)?; - let attr = node.get_attr()?; - if !attr.is_dir() { - return ax_err!(NotADirectory); - } - let access_cap = opts.into(); - if !perm_to_cap(attr.perm()).contains(access_cap) { - return ax_err!(PermissionDenied); - } - node.open()?; - Ok(Directory::new(node, access_cap | Cap::EXECUTE)) -} - -/// Get the file attributes given an absolute path. -pub fn get_attr(path: &AbsPath) -> AxResult { - let node = lookup(path)?; - node.get_attr() -} - -/// Create a file given an absolute path. -pub(crate) fn create_file(path: &AbsPath) -> AxResult { - match lookup(path) { - Ok(_) => ax_err!(AlreadyExists), - Err(AxError::NotFound) => { - ROOT_DIR.create(&path.to_rel(), VfsNodeType::File)?; - lookup(path) - } - Err(e) => Err(e), - } -} - -/// Create a directory given an absolute path. -pub(crate) fn create_dir(path: &AbsPath) -> AxResult { - match lookup(path) { - Ok(_) => ax_err!(AlreadyExists), - Err(AxError::NotFound) => ROOT_DIR.create(&path.to_rel(), VfsNodeType::Dir), - Err(e) => Err(e), - } -} - -/// Create a directory recursively given an absolute path. -pub(crate) fn create_dir_all(path: &AbsPath) -> AxResult { - match lookup(path) { - Ok(_) => ax_err!(AlreadyExists), - Err(AxError::NotFound) => ROOT_DIR.create_recursive(&path.to_rel(), VfsNodeType::Dir), - Err(e) => Err(e), - } -} - -/// Rename a file given an absolute path. -pub(crate) fn remove_file(path: &AbsPath) -> AxResult { - let node = lookup(path)?; - let attr = node.get_attr()?; - if attr.is_dir() { - ax_err!(IsADirectory) - } else if !attr.perm().owner_writable() { - ax_err!(PermissionDenied) - } else { - ROOT_DIR.remove(&path.to_rel()) - } -} - -/// Remove a directory given an absolute path. -pub(crate) fn remove_dir(path: &AbsPath) -> AxResult { - if ROOT_DIR.contains(path) { - return ax_err!(PermissionDenied); - } - let node = lookup(path)?; - let attr = node.get_attr()?; - if !attr.is_dir() { - ax_err!(NotADirectory) - } else if !attr.perm().owner_writable() { - ax_err!(PermissionDenied) - } else { - ROOT_DIR.remove(&path.to_rel()) - } -} - -/// Get current working directory. -pub(crate) fn current_dir<'a>() -> AxResult> { - Ok(CURRENT_DIR_PATH.lock().clone()) -} - -/// Set current working directory. -pub(crate) fn set_current_dir(path: AbsPath<'static>) -> AxResult { - let node = lookup(&path)?; - let attr = node.get_attr()?; - if !attr.is_dir() { - ax_err!(NotADirectory) - } else if !attr.perm().owner_executable() { - ax_err!(PermissionDenied) - } else { - *CURRENT_DIR.lock() = node; - *CURRENT_DIR_PATH.lock() = path; - Ok(()) - } -} - -/// Rename a file given an old and a new absolute path. -pub(crate) fn rename(old: &AbsPath, new: &AbsPath) -> AxResult { - if lookup(new).is_ok() { - ax_err!(AlreadyExists) - } else { - ROOT_DIR.rename(&old.to_rel(), &new.to_rel()) - } -} - -#[crate_interface::def_interface] -/// Current working directory operations. -pub trait CurrentWorkingDirectoryOps { - /// Initializes the root filesystem with the specified mount points. - fn init_rootfs(mount_points: Vec); - /// Returns the parent node of the specified path. - fn parent_node_of(dir: Option<&VfsNodeRef>, path: &str) -> VfsNodeRef; - /// Returns the absolute path of the specified path. - fn absolute_path(path: &str) -> AxResult; - /// Returns the current working directory. - fn current_dir() -> AxResult; - /// Sets the current working directory. - fn set_current_dir(path: &str) -> AxResult; - /// get the root directory of the filesystem - fn root_dir() -> Arc; -} - -pub(crate) fn parent_node_of(dir: Option<&VfsNodeRef>, path: &str) -> VfsNodeRef { - crate_interface::call_interface!(CurrentWorkingDirectoryOps::parent_node_of, dir, path) -} - -pub(crate) fn absolute_path(path: &str) -> AxResult { - crate_interface::call_interface!(CurrentWorkingDirectoryOps::absolute_path, path) -} - -pub(crate) fn current_dir() -> AxResult { - crate_interface::call_interface!(CurrentWorkingDirectoryOps::current_dir) -} - -pub(crate) fn set_current_dir(path: &str) -> AxResult { - crate_interface::call_interface!(CurrentWorkingDirectoryOps::set_current_dir, path) -} - -pub(crate) fn init_rootfs(mount_points: Vec) { - crate_interface::call_interface!(CurrentWorkingDirectoryOps::init_rootfs, mount_points) -} diff --git a/modules/ruxnet/src/unix.rs b/modules/ruxnet/src/unix.rs index e3559bcf4..2ad67f6da 100644 --- a/modules/ruxnet/src/unix.rs +++ b/modules/ruxnet/src/unix.rs @@ -11,6 +11,7 @@ use alloc::{format, sync::Arc, vec}; use axerrno::{ax_err, AxError, AxResult, LinuxError, LinuxResult}; use axio::PollState; use axsync::Mutex; +use ruxfs::AbsPath; use core::ffi::c_char; use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use spin::RwLock; @@ -22,7 +23,7 @@ use hashbrown::HashMap; use lazy_init::LazyInit; use smoltcp::socket::tcp::SocketBuffer; -use ruxfs::root::{create_file, lookup}; +use ruxfs::fops::{create_file, lookup}; use ruxtask::yield_now; const SOCK_ADDR_UN_PATH_LEN: usize = 108; @@ -166,7 +167,7 @@ fn get_inode(addr: SocketAddrUnix) -> AxResult { .to_str() .expect("Invalid UTF-8 string") }; - let _vfsnode = match lookup(None, socket_path) { + let _vfsnode = match lookup(&AbsPath::new_canonicalized(socket_path)) { Ok(node) => node, Err(_) => { return Err(AxError::NotFound); @@ -184,7 +185,7 @@ fn create_socket_file(addr: SocketAddrUnix) -> AxResult { .to_str() .expect("Invalid UTF-8 string") }; - let _vfsnode = create_file(None, socket_path)?; + let _vfsnode = create_file(&AbsPath::new_canonicalized(socket_path))?; Err(AxError::Unsupported) } diff --git a/modules/ruxruntime/src/lib.rs b/modules/ruxruntime/src/lib.rs index 59110ab05..0a8c3784c 100644 --- a/modules/ruxruntime/src/lib.rs +++ b/modules/ruxruntime/src/lib.rs @@ -229,7 +229,7 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { extern crate alloc; use alloc::vec::Vec; // By default, mount_points[0] will be rootfs - let mut mount_points: Vec = Vec::new(); + let mut mount_points: Vec = Vec::new(); //setup ramfs as rootfs if no other filesystem can be mounted #[cfg(not(any(feature = "blkfs", feature = "virtio-9p", feature = "net-9p")))] diff --git a/modules/ruxruntime/tests/test_fatfs.rs b/modules/ruxruntime/tests/test_fatfs.rs index 88d844882..59dcc9b9c 100644 --- a/modules/ruxruntime/tests/test_fatfs.rs +++ b/modules/ruxruntime/tests/test_fatfs.rs @@ -31,7 +31,7 @@ fn test_fatfs() { let disk = make_disk().expect("failed to load disk image"); ruxtask::init_scheduler(); // call this to use `axsync::Mutex`. // By default, mount_points[0] will be rootfs - let mut mount_points: Vec = Vec::new(); + let mut mount_points: Vec = Vec::new(); // setup and initialize blkfs as one mountpoint for rootfs mount_points.push(ruxfs::init_blkfs(AxDeviceContainer::from_one(Box::new( disk, diff --git a/modules/ruxtask/src/fs.rs b/modules/ruxtask/src/fs.rs index 555b21078..419104afc 100644 --- a/modules/ruxtask/src/fs.rs +++ b/modules/ruxtask/src/fs.rs @@ -12,16 +12,16 @@ #![cfg(feature = "fs")] use crate::current; -use alloc::{format, string::String, sync::Arc, vec::Vec}; +use alloc::{borrow::ToOwned, format, sync::Arc, vec::Vec}; use axerrno::{ax_err, AxResult}; use axfs_vfs::VfsNodeRef; use bitmaps::Bitmap; use flatten_objects::FlattenObjects; use ruxfdtable::FileLike; use ruxfs::{ - fops, - root::{lookup, CurrentWorkingDirectoryOps, RootDirectory}, - MountPoint, + fops::{lookup, CurrentWorkingDirectoryOps, OpenOptions}, + root::{MountPoint, RootDirectory}, + AbsPath, RelPath, }; use axerrno::{LinuxError, LinuxResult}; @@ -64,7 +64,7 @@ pub fn get_file_like(fd: i32) -> LinuxResult> { /// Adds a file like object to the file descriptor table and returns the file descriptor. /// Actually there only `CLOEXEC` flag in options works. -pub fn add_file_like(f: Arc, options: fops::OpenOptions) -> LinuxResult { +pub fn add_file_like(f: Arc, options: OpenOptions) -> LinuxResult { let binding_task = current(); let mut binding_fs = binding_task.fs.lock(); let fd_table = &mut binding_fs.as_mut().expect("No fd table found").fd_table; @@ -103,7 +103,7 @@ impl File { } /// Adds the file object to the file descriptor table and returns the file descriptor. - pub fn add_to_fd_table(self, options: fops::OpenOptions) -> LinuxResult { + pub fn add_to_fd_table(self, options: OpenOptions) -> LinuxResult { add_file_like(Arc::new(self), options) } @@ -117,6 +117,10 @@ impl File { } impl FileLike for File { + fn path(&self) -> AbsPath { + self.inner.read().path().to_owned() + } + fn read(&self, buf: &mut [u8]) -> LinuxResult { Ok(self.inner.write().read(buf)?) } @@ -176,18 +180,21 @@ impl FileLike for File { pub struct Directory { /// The inner directory object. pub inner: RwLock, + /// Searchable. + pub searchable: bool, } impl Directory { /// Creates a new directory object with the given inner directory object. - pub fn new(inner: ruxfs::fops::Directory) -> Self { + pub fn new(inner: ruxfs::fops::Directory, searchable: bool) -> Self { Self { inner: RwLock::new(inner), + searchable, } } /// Adds the directory object to the file descriptor table and returns the file descriptor. - pub fn add_to_fd_table(self, flags: fops::OpenOptions) -> LinuxResult { + pub fn add_to_fd_table(self, flags: OpenOptions) -> LinuxResult { add_file_like(Arc::new(self), flags) } @@ -201,6 +208,10 @@ impl Directory { } impl FileLike for Directory { + fn path(&self) -> AbsPath { + self.inner.read().path().to_owned() + } + fn read(&self, _buf: &mut [u8]) -> LinuxResult { Err(LinuxError::EACCES) } @@ -257,7 +268,7 @@ pub struct FileSystem { /// The file descriptor table. pub fd_table: FdTable, /// The current working directory. - pub current_path: String, + pub current_path: AbsPath<'static>, /// The current directory. pub current_dir: VfsNodeRef, /// The root directory. @@ -311,10 +322,10 @@ impl FdTable { /// /// Also sets the `FD_CLOEXEC` flag for the file descriptor based on the `flags` argument. /// Returns the assigned file descriptor number (`fd`) if successful, or `None` if the table is full. - pub fn add(&mut self, file: Arc, flags: fops::OpenOptions) -> Option { + pub fn add(&mut self, file: Arc, flags: OpenOptions) -> Option { if let Some(fd) = self.files.add(file) { debug_assert!(!self.cloexec_bitmap.get(fd)); - if flags.is_cloexec() { + if flags.cloexec { self.cloexec_bitmap.set(fd, true); } Some(fd) @@ -424,18 +435,17 @@ pub fn init_rootfs(mount_points: Vec) { let mut root_dir = RootDirectory::new(main_fs); for mp in mount_points.iter().skip(1) { - let path = mp.path; let vfsops = mp.fs.clone(); - let message = format!("failed to mount filesystem at {}", path); - info!("mounting {}", path); - root_dir.mount(path, vfsops).expect(&message); + let message = format!("failed to mount filesystem at {}", mp.path); + info!("mounting {}", mp.path); + root_dir.mount(mp.path.clone(), vfsops).expect(&message); } let root_dir_arc = Arc::new(root_dir); let mut fs = FileSystem { fd_table: FdTable::default(), - current_path: "/".into(), + current_path: AbsPath::new_owned("/".to_owned()), current_dir: root_dir_arc.clone(), root_dir: root_dir_arc.clone(), }; @@ -457,34 +467,28 @@ fn parent_node_of(dir: Option<&VfsNodeRef>, path: &str) -> VfsNodeRef { } /// Returns the absolute path of the given path. -pub fn absolute_path(path: &str) -> AxResult { +pub fn absolute_path(path: &str) -> AxResult> { if path.starts_with('/') { - Ok(axfs_vfs::path::canonicalize(path)) + Ok(AbsPath::new_canonicalized(path)) } else { - let path = current().fs.lock().as_mut().unwrap().current_path.clone() + path; - Ok(axfs_vfs::path::canonicalize(&path)) + Ok(current() + .fs + .lock() + .as_mut() + .unwrap() + .current_path + .join(&RelPath::new_canonicalized(path))) } } /// Returns the current directory. -pub fn current_dir() -> AxResult { +pub fn current_dir() -> AxResult> { Ok(current().fs.lock().as_mut().unwrap().current_path.clone()) } /// Sets the current directory. -pub fn set_current_dir(path: &str) -> AxResult { - let mut abs_path = absolute_path(path)?; - if !abs_path.ends_with('/') { - abs_path += "/"; - } - if abs_path == "/" { - current().fs.lock().as_mut().unwrap().current_dir = - current().fs.lock().as_mut().unwrap().root_dir.clone(); - current().fs.lock().as_mut().unwrap().current_path = "/".into(); - return Ok(()); - } - - let node = lookup(None, &abs_path)?; +pub fn set_current_dir(path: AbsPath<'static>) -> AxResult { + let node = lookup(&path)?; let attr = node.get_attr()?; if !attr.is_dir() { ax_err!(NotADirectory) @@ -492,7 +496,7 @@ pub fn set_current_dir(path: &str) -> AxResult { ax_err!(PermissionDenied) } else { current().fs.lock().as_mut().unwrap().current_dir = node; - current().fs.lock().as_mut().unwrap().current_path = abs_path; + current().fs.lock().as_mut().unwrap().current_path = path; Ok(()) } } @@ -504,16 +508,16 @@ impl CurrentWorkingDirectoryOps for CurrentWorkingDirectoryImpl { fn init_rootfs(mount_points: Vec) { init_rootfs(mount_points) } - fn parent_node_of(dir: Option<&VfsNodeRef>, path: &str) -> VfsNodeRef { + fn parent_node_of(dir: Option<&VfsNodeRef>, path: &RelPath) -> VfsNodeRef { parent_node_of(dir, path) } - fn absolute_path(path: &str) -> AxResult { + fn absolute_path(path: &str) -> AxResult> { absolute_path(path) } - fn current_dir() -> AxResult { + fn current_dir() -> AxResult> { current_dir() } - fn set_current_dir(path: &str) -> AxResult { + fn set_current_dir(path: AbsPath<'static>) -> AxResult { set_current_dir(path) } fn root_dir() -> Arc { diff --git a/modules/ruxtask/src/lib.rs b/modules/ruxtask/src/lib.rs index 038dbfa3a..996b5c589 100644 --- a/modules/ruxtask/src/lib.rs +++ b/modules/ruxtask/src/lib.rs @@ -42,7 +42,7 @@ cfg_if::cfg_if! { if #[cfg(feature = "multitask")] { - #[macro_use] + #[macro_use(info, debug, trace)] extern crate log; extern crate alloc; diff --git a/modules/ruxtask/src/vma.rs b/modules/ruxtask/src/vma.rs index 48e302f97..84623208e 100644 --- a/modules/ruxtask/src/vma.rs +++ b/modules/ruxtask/src/vma.rs @@ -65,7 +65,7 @@ fn open_swap_file(filename: &str) -> Arc { opt.append(true); opt.create(true); - let file = ruxfs::fops::File::open(filename, &opt).expect("create swap file failed"); + let file = ruxfs::fops::open(filename, &opt).expect("create swap file failed"); Arc::new(File::new(file)) } diff --git a/ulib/ruxmusl/src/x86_64/mod.rs b/ulib/ruxmusl/src/x86_64/mod.rs index e2ed777fe..6c504ad78 100644 --- a/ulib/ruxmusl/src/x86_64/mod.rs +++ b/ulib/ruxmusl/src/x86_64/mod.rs @@ -485,7 +485,7 @@ pub fn syscall(syscall_id: SyscallId, args: [usize; 6]) -> isize { #[cfg(feature = "fs")] SyscallId::OPENAT => ruxos_posix_api::sys_openat( - args[0], + args[0] as c_int, args[1] as *const core::ffi::c_char, args[2] as c_int, args[3] as ctypes::mode_t,