Remove open-related APIs from FsResolver

This commit is contained in:
Chen Chengjun 2025-10-16 09:50:28 +00:00 committed by Ruihan Li
parent c2ab393d57
commit 782301c239
5 changed files with 180 additions and 24 deletions

View File

@ -13,6 +13,7 @@ use crate::{
file_table::FdFlags,
fs_resolver::FsPath,
inode_handle::FileIo,
open_args::OpenArgs,
utils::{mkmod, AccessMode, Inode, IoctlCmd},
},
prelude::*,
@ -127,13 +128,13 @@ impl FileIo for PtyMaster {
let fs_path = FsPath::try_from(slave_name.as_str())?;
let inode_handle = {
let flags = AccessMode::O_RDWR as u32;
let mode = mkmod!(u+rw).bits();
let open_args = OpenArgs::from_modes(AccessMode::O_RDWR, mkmod!(u+rw));
thread_local
.borrow_fs()
.resolver()
.read()
.open(&fs_path, flags, mode)?
.lookup(&fs_path)?
.open(open_args)?
};
Arc::new(inode_handle)
};

View File

@ -12,6 +12,7 @@ pub mod file_table;
pub mod fs_resolver;
pub mod inode_handle;
pub mod named_pipe;
pub mod open_args;
pub mod overlayfs;
pub mod path;
pub mod pipe;
@ -33,6 +34,7 @@ use crate::{
ext2::Ext2,
file_table::FdFlags,
fs_resolver::{FsPath, FsResolver},
open_args::OpenArgs,
utils::{mkmod, AccessMode},
},
prelude::*,
@ -104,19 +106,28 @@ pub fn init_in_first_process(ctx: &Context) {
// Initialize the file table for the first process.
let tty_path = FsPath::new(fs_resolver::AT_FDCWD, "/dev/console").expect("cannot find tty");
let stdin = {
let flags = AccessMode::O_RDONLY as u32;
let mode = mkmod!(u+r);
fs_resolver.open(&tty_path, flags, mode.bits()).unwrap()
let open_args = OpenArgs::from_modes(AccessMode::O_RDONLY, mkmod!(u+r));
fs_resolver
.lookup(&tty_path)
.unwrap()
.open(open_args)
.unwrap()
};
let stdout = {
let flags = AccessMode::O_WRONLY as u32;
let mode = mkmod!(u+w);
fs_resolver.open(&tty_path, flags, mode.bits()).unwrap()
let open_args = OpenArgs::from_modes(AccessMode::O_WRONLY, mkmod!(u+w));
fs_resolver
.lookup(&tty_path)
.unwrap()
.open(open_args)
.unwrap()
};
let stderr = {
let flags = AccessMode::O_WRONLY as u32;
let mode = mkmod!(u+w);
fs_resolver.open(&tty_path, flags, mode.bits()).unwrap()
let open_args = OpenArgs::from_modes(AccessMode::O_WRONLY, mkmod!(u+w));
fs_resolver
.lookup(&tty_path)
.unwrap()
.open(open_args)
.unwrap()
};
let mut file_table_ref = ctx.thread_local.borrow_file_table_mut();

View File

@ -0,0 +1,47 @@
// SPDX-License-Identifier: MPL-2.0
use crate::{
fs::utils::{AccessMode, CreationFlags, InodeMode, StatusFlags},
prelude::*,
};
/// Arguments for an open request.
#[derive(Debug)]
pub struct OpenArgs {
pub creation_flags: CreationFlags,
pub status_flags: StatusFlags,
pub access_mode: AccessMode,
pub inode_mode: InodeMode,
}
impl OpenArgs {
/// Create `OpenArgs` from the given flags and mode.
pub fn from_flags_and_mode(flags: u32, inode_mode: InodeMode) -> Result<Self> {
let creation_flags = CreationFlags::from_bits_truncate(flags);
let status_flags = StatusFlags::from_bits_truncate(flags);
let access_mode = AccessMode::from_u32(flags)?;
Ok(Self {
creation_flags,
status_flags,
access_mode,
inode_mode,
})
}
/// Create `OpenArgs` from the given access mode and inode mode.
pub fn from_modes(access_mode: AccessMode, inode_mode: InodeMode) -> Self {
Self {
creation_flags: CreationFlags::empty(),
status_flags: StatusFlags::empty(),
access_mode,
inode_mode,
}
}
/// Returns whether to follow the tail link when resolving the path.
pub fn follow_tail_link(&self) -> bool {
!(self.creation_flags.contains(CreationFlags::O_NOFOLLOW)
|| self.creation_flags.contains(CreationFlags::O_CREAT)
&& self.creation_flags.contains(CreationFlags::O_EXCL))
}
}

View File

@ -10,10 +10,12 @@ pub use mount_namespace::MountNamespace;
use crate::{
fs::{
inode_handle::InodeHandle,
open_args::OpenArgs,
path::dentry::{Dentry, DentryKey},
utils::{
FileSystem, Inode, InodeMode, InodeType, Metadata, MknodType, Permission, XattrName,
XattrNamespace, XattrSetFlags, NAME_MAX,
CreationFlags, FileSystem, Inode, InodeMode, InodeType, Metadata, MknodType,
Permission, StatusFlags, XattrName, XattrNamespace, XattrSetFlags, NAME_MAX,
},
},
prelude::*,
@ -366,6 +368,47 @@ 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();
let inode_type = inode.type_();
let creation_flags = &open_args.creation_flags;
match inode_type {
InodeType::NamedPipe => {
warn!("NamedPipe doesn't support additional operation when opening.");
debug!("Open NamedPipe with args: {open_args:?}.");
}
InodeType::SymLink => {
if creation_flags.contains(CreationFlags::O_NOFOLLOW)
&& !open_args.status_flags.contains(StatusFlags::O_PATH)
{
return_errno_with_message!(Errno::ELOOP, "file is a symlink");
}
}
_ => {}
}
if creation_flags.contains(CreationFlags::O_CREAT)
&& creation_flags.contains(CreationFlags::O_EXCL)
{
return_errno_with_message!(Errno::EEXIST, "file exists");
}
if creation_flags.contains(CreationFlags::O_DIRECTORY) && inode_type != InodeType::Dir {
return_errno_with_message!(
Errno::ENOTDIR,
"O_DIRECTORY is specified but file is not a directory"
);
}
if inode_type.is_regular_file() && creation_flags.contains(CreationFlags::O_TRUNC) {
self.resize(0)?;
}
InodeHandle::new(self.clone(), open_args.access_mode, open_args.status_flags)
}
}
#[inherit_methods(from = "self.dentry")]

View File

@ -4,8 +4,10 @@ use super::SyscallReturn;
use crate::{
fs::{
file_table::{FdFlags, FileDesc},
fs_resolver::{FsPath, AT_FDCWD},
utils::{AccessMode, CreationFlags},
fs_resolver::{FsPath, FsResolver, LookupResult, AT_FDCWD},
inode_handle::InodeHandle,
open_args::OpenArgs,
utils::{AccessMode, CreationFlags, InodeMode, InodeType},
},
prelude::*,
syscall::constants::MAX_FILENAME_LEN,
@ -31,16 +33,22 @@ pub fn sys_openat(
let file_handle = {
let path = path.to_string_lossy();
let fs_path = FsPath::new(dirfd, path.as_ref())?;
let fs_ref = ctx.thread_local.borrow_fs();
let mask_mode = mode & !fs_ref.umask().get();
let inode_handle = fs_ref
.resolver()
.read()
.open(&fs_path, flags, mask_mode)
let fs_resolver = fs_ref.resolver().read();
let inode_handle = do_open(
&fs_resolver,
&fs_path,
flags,
InodeMode::from_bits_truncate(mask_mode),
)
.map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
Arc::new(inode_handle)
};
@ -68,3 +76,49 @@ pub fn sys_creat(path_addr: Vaddr, mode: u16, ctx: &Context) -> Result<SyscallRe
AccessMode::O_WRONLY as u32 | CreationFlags::O_CREAT.bits() | CreationFlags::O_TRUNC.bits();
self::sys_openat(AT_FDCWD, path_addr, flags, mode, ctx)
}
fn do_open(
fs_resolver: &FsResolver,
path: &FsPath,
flags: u32,
mode: InodeMode,
) -> Result<InodeHandle> {
let open_args = OpenArgs::from_flags_and_mode(flags, mode)?;
let lookup_res = if open_args.follow_tail_link() {
fs_resolver.lookup_unresolved(path)?
} else {
fs_resolver.lookup_unresolved_no_follow(path)?
};
let inode_handle = match lookup_res {
LookupResult::Resolved(target_path) => target_path.open(open_args)?,
LookupResult::AtParent(result) => {
if !open_args.creation_flags.contains(CreationFlags::O_CREAT) {
return_errno_with_message!(Errno::ENOENT, "file does not exist");
}
if open_args
.creation_flags
.contains(CreationFlags::O_DIRECTORY)
{
return_errno_with_message!(Errno::ENOTDIR, "cannot create directory");
}
if result.target_is_dir() {
return_errno_with_message!(Errno::EISDIR, "cannot create directory");
}
let (parent, tail_name) = result.into_parent_and_tail_name();
let new_path =
parent.new_fs_child(&tail_name, InodeType::File, open_args.inode_mode)?;
// Don't check access mode for newly created file.
InodeHandle::new_unchecked_access(
new_path,
open_args.access_mode,
open_args.status_flags,
)?
}
};
Ok(inode_handle)
}