From f4b2bf9ed83d69c6b9fa836c3e45d57f9f6244b0 Mon Sep 17 00:00:00 2001 From: Yuekai Jia Date: Fri, 7 Apr 2023 00:18:54 +0800 Subject: [PATCH] fs: implement directory relative ops (openat) --- modules/axfs/src/api/dir.rs | 2 +- modules/axfs/src/api/mod.rs | 4 +-- modules/axfs/src/fops.rs | 50 +++++++++++++++++++++++++++++++++---- modules/axfs/src/root.rs | 32 ++++++++++++------------ 4 files changed, 64 insertions(+), 24 deletions(-) diff --git a/modules/axfs/src/api/dir.rs b/modules/axfs/src/api/dir.rs index c4c241546a..55ad5ab32a 100644 --- a/modules/axfs/src/api/dir.rs +++ b/modules/axfs/src/api/dir.rs @@ -137,7 +137,7 @@ impl DirBuilder { if self.recursive { self.create_dir_all(path) } else { - crate::root::create_dir(path) + crate::root::create_dir(None, path) } } diff --git a/modules/axfs/src/api/mod.rs b/modules/axfs/src/api/mod.rs index 83dca95f46..d574682f45 100644 --- a/modules/axfs/src/api/mod.rs +++ b/modules/axfs/src/api/mod.rs @@ -72,10 +72,10 @@ pub fn create_dir_all(path: &str) -> io::Result<()> { /// Removes an empty directory. pub fn remove_dir(path: &str) -> io::Result<()> { - crate::root::remove_dir(path) + crate::root::remove_dir(None, path) } /// Removes a file from the filesystem. pub fn remove_file(path: &str) -> io::Result<()> { - crate::root::remove_file(path) + crate::root::remove_file(None, path) } diff --git a/modules/axfs/src/fops.rs b/modules/axfs/src/fops.rs index de1ac6fe0d..6b5064ecf5 100644 --- a/modules/axfs/src/fops.rs +++ b/modules/axfs/src/fops.rs @@ -91,13 +91,13 @@ impl OpenOptions { } impl File { - pub fn open(path: &str, opts: &OpenOptions) -> AxResult { + fn _open_at(dir: Option<&VfsNodeRef>, path: &str, opts: &OpenOptions) -> AxResult { debug!("open file: {} {:?}", path, opts); if !opts.is_valid() { return ax_err!(InvalidInput); } - let node_option = crate::root::lookup(path); + let node_option = crate::root::lookup(dir, path); let node = if opts.create || opts.create_new { match node_option { Ok(node) => { @@ -108,7 +108,7 @@ impl File { node } // not exists, create new - Err(VfsError::NotFound) => crate::root::create_file(path)?, + Err(VfsError::NotFound) => crate::root::create_file(dir, path)?, Err(e) => return Err(e), } } else { @@ -138,6 +138,10 @@ impl File { }) } + pub fn open(path: &str, opts: &OpenOptions) -> AxResult { + Self::_open_at(None, path, opts) + } + pub fn truncate(&self, size: u64) -> AxResult { self.node.access(Cap::WRITE)?.truncate(size)?; Ok(()) @@ -171,7 +175,7 @@ impl File { } impl Directory { - pub fn open_dir(path: &str, opts: &OpenOptions) -> AxResult { + fn _open_dir_at(dir: Option<&VfsNodeRef>, path: &str, opts: &OpenOptions) -> AxResult { debug!("open dir: {}", path); if !opts.read { return ax_err!(InvalidInput); @@ -180,7 +184,7 @@ impl Directory { return ax_err!(InvalidInput); } - let node = crate::root::lookup(path)?; + let node = crate::root::lookup(dir, path)?; let attr = node.get_attr()?; if !attr.is_dir() { return ax_err!(NotADirectory); @@ -197,6 +201,42 @@ impl Directory { }) } + fn access_at(&self, path: &str) -> AxResult> { + if path.starts_with('/') { + Ok(None) + } else { + Ok(Some(self.node.access(Cap::EXECUTE)?)) + } + } + + pub fn open_dir(path: &str, opts: &OpenOptions) -> AxResult { + Self::_open_dir_at(None, path, opts) + } + + pub fn open_dir_at(&self, path: &str, opts: &OpenOptions) -> AxResult { + Self::_open_dir_at(self.access_at(path)?, path, opts) + } + + pub fn open_file_at(&self, path: &str, opts: &OpenOptions) -> AxResult { + File::_open_at(self.access_at(path)?, path, opts) + } + + pub fn create_file(&self, path: &str) -> AxResult { + crate::root::create_file(self.access_at(path)?, path) + } + + pub fn create_dir(&self, path: &str) -> AxResult { + crate::root::create_dir(self.access_at(path)?, path) + } + + pub fn remove_file(&self, path: &str) -> AxResult { + crate::root::remove_file(self.access_at(path)?, path) + } + + pub fn remove_dir(&self, path: &str) -> AxResult { + crate::root::remove_dir(self.access_at(path)?, path) + } + pub fn read_dir(&mut self, dirents: &mut [DirEntry]) -> AxResult { let n = self .node diff --git a/modules/axfs/src/root.rs b/modules/axfs/src/root.rs index 497a547cc7..5d52ebc263 100644 --- a/modules/axfs/src/root.rs +++ b/modules/axfs/src/root.rs @@ -164,19 +164,19 @@ pub(crate) fn init_rootfs(disk: crate::dev::Disk) { *CURRENT_DIR_PATH.lock() = "/".into(); } -fn parent_node_of(path: &str) -> VfsNodeRef { +fn parent_node_of(dir: Option<&VfsNodeRef>, path: &str) -> VfsNodeRef { if path.starts_with('/') { ROOT_DIR.clone() } else { - CURRENT_DIR.lock().clone() + dir.cloned().unwrap_or_else(|| CURRENT_DIR.lock().clone()) } } -pub(crate) fn lookup(path: &str) -> AxResult { +pub(crate) fn lookup(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { if path.is_empty() { return ax_err!(NotFound); } - let node = parent_node_of(path).lookup(path)?; + let node = parent_node_of(dir, path).lookup(path)?; if path.ends_with('/') && !node.get_attr()?.is_dir() { ax_err!(NotADirectory) } else { @@ -184,38 +184,38 @@ pub(crate) fn lookup(path: &str) -> AxResult { } } -pub(crate) fn create_file(path: &str) -> AxResult { +pub(crate) fn create_file(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { if path.is_empty() { return ax_err!(NotFound); } else if path.ends_with('/') { return ax_err!(NotADirectory); } - let parent = parent_node_of(path); + let parent = parent_node_of(dir, path); parent.create(path, VfsNodeType::File)?; parent.lookup(path) } -pub(crate) fn create_dir(path: &str) -> AxResult { - match lookup(path) { +pub(crate) fn create_dir(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { + match lookup(dir, path) { Ok(_) => ax_err!(AlreadyExists), - Err(AxError::NotFound) => parent_node_of(path).create(path, VfsNodeType::Dir), + Err(AxError::NotFound) => parent_node_of(dir, path).create(path, VfsNodeType::Dir), Err(e) => Err(e), } } -pub(crate) fn remove_file(path: &str) -> AxResult { - let node = lookup(path)?; +pub(crate) fn remove_file(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { + let node = lookup(dir, path)?; let attr = node.get_attr()?; if attr.is_dir() { ax_err!(IsADirectory) } else if !attr.perm().owner_writable() { ax_err!(PermissionDenied) } else { - parent_node_of(path).remove(path) + parent_node_of(dir, path).remove(path) } } -pub(crate) fn remove_dir(path: &str) -> AxResult { +pub(crate) fn remove_dir(dir: Option<&VfsNodeRef>, path: &str) -> AxResult { // TODO: canonicalize path to avoid bypassing checks for removeing mount points if path.is_empty() { return ax_err!(NotFound); @@ -231,14 +231,14 @@ pub(crate) fn remove_dir(path: &str) -> AxResult { return ax_err!(InvalidInput); } - let node = lookup(path)?; + let node = lookup(dir, path)?; let attr = node.get_attr()?; if !attr.is_dir() { ax_err!(NotADirectory) } else if !attr.perm().owner_writable() { ax_err!(PermissionDenied) } else { - parent_node_of(path).remove(path) + parent_node_of(dir, path).remove(path) } } @@ -247,7 +247,7 @@ pub(crate) fn current_dir() -> AxResult { } pub(crate) fn set_current_dir(path: &str) -> AxResult { - let node = lookup(path)?; + let node = lookup(None, path)?; let attr = node.get_attr()?; if !attr.is_dir() { ax_err!(NotADirectory)