Clarify how `Path` inherits methods

This commit is contained in:
Ruihan Li 2025-10-07 18:58:11 +08:00 committed by Chengjun Chen
parent 9c8a8f8df9
commit 0636e1048e
5 changed files with 71 additions and 111 deletions

View File

@ -204,7 +204,7 @@ impl FileLike for InodeHandle {
}
fn inode(&self) -> &Arc<dyn Inode> {
self.0.inode()
self.0.path.inode()
}
}

View File

@ -7,7 +7,6 @@ mod dyn_cap;
use core::sync::atomic::{AtomicU32, Ordering};
pub use dyn_cap::InodeHandle;
use inherit_methods_macro::inherit_methods;
use crate::{
events::IoEvents,
@ -252,12 +251,6 @@ impl HandleInner {
}
}
#[inherit_methods(from = "self.path")]
impl HandleInner {
pub(self) fn size(&self) -> usize;
pub(self) fn inode(&self) -> &Arc<dyn Inode>;
}
impl Debug for HandleInner {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("HandleInner")

View File

@ -1,24 +1,14 @@
// SPDX-License-Identifier: MPL-2.0
#![expect(dead_code)]
use core::{
sync::atomic::{AtomicU32, Ordering},
time::Duration,
};
use core::sync::atomic::{AtomicU32, Ordering};
use hashbrown::HashMap;
use inherit_methods_macro::inherit_methods;
use ostd::sync::RwMutexWriteGuard;
use super::is_dot_or_dotdot;
use crate::{
fs::utils::{
FileSystem, Inode, InodeMode, InodeType, Metadata, MknodType, XattrName, XattrNamespace,
XattrSetFlags,
},
fs::utils::{Inode, InodeMode, InodeType, MknodType},
prelude::*,
process::{Gid, Uid},
};
/// A `Dentry` represents a cached filesystem node in the VFS tree.
@ -100,6 +90,12 @@ impl Dentry {
&self.inode
}
/// Returns whether the dentry can be cached.
fn is_dentry_cacheable(&self) -> bool {
// Should we store it as a dentry flag?
self.inode.is_dentry_cacheable()
}
fn flags(&self) -> DentryFlags {
let flags = self.flags.load(Ordering::Relaxed);
DentryFlags::from_bits(flags).unwrap()
@ -355,48 +351,14 @@ impl Dentry {
}
}
#[inherit_methods(from = "self.inode")]
impl Dentry {
pub(super) fn fs(&self) -> Arc<dyn FileSystem>;
pub(super) fn sync_all(&self) -> Result<()>;
pub(super) fn sync_data(&self) -> Result<()>;
pub(super) fn metadata(&self) -> Metadata;
pub(super) fn mode(&self) -> Result<InodeMode>;
pub(super) fn set_mode(&self, mode: InodeMode) -> Result<()>;
pub(super) fn size(&self) -> usize;
pub(super) fn resize(&self, size: usize) -> Result<()>;
pub(super) fn owner(&self) -> Result<Uid>;
pub(super) fn set_owner(&self, uid: Uid) -> Result<()>;
pub(super) fn group(&self) -> Result<Gid>;
pub(super) fn set_group(&self, gid: Gid) -> Result<()>;
pub(super) fn atime(&self) -> Duration;
pub(super) fn set_atime(&self, time: Duration);
pub(super) fn mtime(&self) -> Duration;
pub(super) fn set_mtime(&self, time: Duration);
pub(super) fn ctime(&self) -> Duration;
pub(super) fn set_ctime(&self, time: Duration);
pub(super) fn is_dentry_cacheable(&self) -> bool;
pub(super) fn set_xattr(
&self,
name: XattrName,
value_reader: &mut VmReader,
flags: XattrSetFlags,
) -> Result<()>;
pub(super) fn get_xattr(&self, name: XattrName, value_writer: &mut VmWriter) -> Result<usize>;
pub(super) fn list_xattr(
&self,
namespace: XattrNamespace,
list_writer: &mut VmWriter,
) -> Result<usize>;
pub(super) fn remove_xattr(&self, name: XattrName) -> Result<()>;
}
impl Debug for Dentry {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("Dentry")
.field("inode", &self.inode)
.field("flags", &self.flags())
.finish()
.field("type_", &self.type_)
.field("flags", &self.flags)
.field("mount_count", &self.mount_count)
.finish_non_exhaustive()
}
}
@ -459,6 +421,7 @@ impl DentryChildren {
}
/// Checks if a negative dentry with the given name exists.
#[expect(dead_code)]
fn contains_negative(&self, name: &str) -> bool {
self.dentries.get(name).is_some_and(|child| child.is_none())
}

View File

@ -11,7 +11,7 @@ pub use mount_namespace::MountNamespace;
use crate::{
fs::{
inode_handle::InodeHandle,
path::dentry::{Dentry, DentryKey},
path::dentry::Dentry,
utils::{
CreationFlags, FileSystem, FsFlags, Inode, InodeMode, InodeType, Metadata, MknodType,
OpenArgs, Permission, StatusFlags, XattrName, XattrNamespace, XattrSetFlags, NAME_MAX,
@ -99,6 +99,23 @@ impl Path {
Ok(target_path.get_top_path())
}
/// Opens the `Path` with the given `OpenArgs`.
///
/// Returns an `InodeHandle` on success.
pub fn open(&self, open_args: OpenArgs) -> Result<InodeHandle> {
let inode = self.inode();
check_open_util(inode.as_ref(), &open_args)?;
if inode.type_().is_regular_file()
&& open_args.creation_flags.contains(CreationFlags::O_TRUNC)
&& !open_args.status_flags.contains(StatusFlags::O_PATH)
{
self.resize(0)?;
}
InodeHandle::new(self.clone(), open_args.access_mode, open_args.status_flags)
}
/// Gets the absolute path.
///
/// It will resolve the mountpoint automatically.
@ -195,6 +212,33 @@ impl Path {
}
}
/// Checks if the given `Inode` can be opened with the given `OpenArgs`.
pub(super) fn check_open_util(inode: &dyn Inode, open_args: &OpenArgs) -> Result<()> {
let inode_type = inode.type_();
let creation_flags = &open_args.creation_flags;
if inode_type == InodeType::SymLink
&& creation_flags.contains(CreationFlags::O_NOFOLLOW)
&& !open_args.status_flags.contains(StatusFlags::O_PATH)
{
return_errno_with_message!(Errno::ELOOP, "the file is a symlink");
}
if creation_flags.contains(CreationFlags::O_CREAT)
&& creation_flags.contains(CreationFlags::O_EXCL)
{
return_errno_with_message!(Errno::EEXIST, "the file already exists");
}
if creation_flags.contains(CreationFlags::O_DIRECTORY) && inode_type != InodeType::Dir {
return_errno_with_message!(
Errno::ENOTDIR,
"O_DIRECTORY is specified but the file is not a directory"
);
}
Ok(())
}
impl Path {
/// Mounts a filesystem at the current path.
///
@ -394,6 +438,15 @@ impl Path {
Ok(())
}
}
// Methods inherited from `Dentry`.
#[inherit_methods(from = "self.dentry")]
impl Path {
pub fn inode(&self) -> &Arc<dyn Inode>;
pub fn type_(&self) -> InodeType;
pub fn unlink(&self, name: &str) -> Result<()>;
pub fn rmdir(&self, name: &str) -> Result<()>;
/// Creates a `Path` by making an inode of the `type_` with the `mode`.
pub fn mknod(&self, name: &str, mode: InodeMode, type_: MknodType) -> Result<Self> {
@ -418,61 +471,15 @@ impl Path {
self.dentry.rename(old_name, &new_dir.dentry, new_name)
}
/// Opens the `Path` with the given `OpenArgs`.
///
/// Returns an `InodeHandle` on success.
pub fn open(&self, open_args: OpenArgs) -> Result<InodeHandle> {
let inode = self.inode();
check_open_util(inode.as_ref(), &open_args)?;
if inode.type_().is_regular_file()
&& open_args.creation_flags.contains(CreationFlags::O_TRUNC)
&& !open_args.status_flags.contains(StatusFlags::O_PATH)
{
self.resize(0)?;
}
InodeHandle::new(self.clone(), open_args.access_mode, open_args.status_flags)
}
}
/// Checks if the given `Inode` can be opened with the given `OpenArgs`.
pub fn check_open_util(inode: &dyn Inode, open_args: &OpenArgs) -> Result<()> {
let inode_type = inode.type_();
let creation_flags = &open_args.creation_flags;
if inode_type == InodeType::SymLink
&& creation_flags.contains(CreationFlags::O_NOFOLLOW)
&& !open_args.status_flags.contains(StatusFlags::O_PATH)
{
return_errno_with_message!(Errno::ELOOP, "the file is a symlink");
}
if creation_flags.contains(CreationFlags::O_CREAT)
&& creation_flags.contains(CreationFlags::O_EXCL)
{
return_errno_with_message!(Errno::EEXIST, "the file already exists");
}
if creation_flags.contains(CreationFlags::O_DIRECTORY) && inode_type != InodeType::Dir {
return_errno_with_message!(
Errno::ENOTDIR,
"O_DIRECTORY is specified but the file is not a directory"
);
}
Ok(())
}
#[inherit_methods(from = "self.dentry")]
// Methods inherited from `Inode`.
#[inherit_methods(from = "self.inode()")]
impl Path {
pub fn unlink(&self, name: &str) -> Result<()>;
pub fn rmdir(&self, name: &str) -> Result<()>;
pub fn fs(&self) -> Arc<dyn FileSystem>;
pub fn sync_all(&self) -> Result<()>;
pub fn sync_data(&self) -> Result<()>;
pub fn metadata(&self) -> Metadata;
pub fn type_(&self) -> InodeType;
pub fn mode(&self) -> Result<InodeMode>;
pub fn set_mode(&self, mode: InodeMode) -> Result<()>;
pub fn size(&self) -> usize;
@ -487,9 +494,6 @@ impl Path {
pub fn set_mtime(&self, time: Duration);
pub fn ctime(&self) -> Duration;
pub fn set_ctime(&self, time: Duration);
pub fn key(&self) -> DentryKey;
pub fn inode(&self) -> &Arc<dyn Inode>;
pub fn is_mountpoint(&self) -> bool;
pub fn set_xattr(
&self,
name: XattrName,

View File

@ -371,7 +371,7 @@ impl Mount {
/// Attaches the mount node to the mountpoint.
fn attach_to_path(&self, target_path: &Path) {
let key = target_path.key();
let key = target_path.dentry.key();
target_path
.mount_node()
.children