Zhenchen Wang 9e729593e8 Add syscall faccessat2
Signed-off-by: Zhenchen Wang <m202372036@hust.edu.cn>
2025-04-23 20:39:54 +08:00

120 lines
3.0 KiB
Rust

// SPDX-License-Identifier: MPL-2.0
use super::SyscallReturn;
use crate::{
fs::{
file_table::FileDesc,
fs_resolver::{FsPath, AT_FDCWD},
utils::{Permission, PATH_MAX},
},
prelude::*,
};
pub fn sys_faccessat(
dirfd: FileDesc,
path_ptr: Vaddr,
mode: u16,
ctx: &Context,
) -> Result<SyscallReturn> {
debug!(
"faccessat: dirfd = {}, path_ptr = {:#x}, mode = {:o}",
dirfd, path_ptr, mode
);
do_faccessat(dirfd, path_ptr, mode, 0, ctx)
}
pub fn sys_access(path_ptr: Vaddr, mode: u16, ctx: &Context) -> Result<SyscallReturn> {
debug!("access: path_ptr = {:#x}, mode = {:o}", path_ptr, mode);
do_faccessat(AT_FDCWD, path_ptr, mode, 0, ctx)
}
pub fn sys_faccessat2(
dirfd: FileDesc,
path_ptr: Vaddr,
mode: u16,
flags: u32,
ctx: &Context,
) -> Result<SyscallReturn> {
debug!(
"faccessat2: dirfd = {}, path_ptr = {:#x}, mode = {:o}, flags = {}",
dirfd, path_ptr, mode, flags
);
do_faccessat(dirfd, path_ptr, mode, flags, ctx)
}
bitflags! {
struct FaccessatFlags: u32 {
const AT_EACCESS = 0x200;
const AT_SYMLINK_NOFOLLOW = 0x100;
const AT_EMPTY_PATH = 0x1000;
}
}
bitflags! {
struct AccessMode: u16 {
const R_OK = 0x4;
const W_OK = 0x2;
const X_OK = 0x1;
// We could ignore F_OK in bitflags.
// const F_OK = 0x0;
}
}
pub fn do_faccessat(
dirfd: FileDesc,
path_ptr: Vaddr,
mode: u16,
flags: u32,
ctx: &Context,
) -> Result<SyscallReturn> {
let mode = AccessMode::from_bits(mode)
.ok_or_else(|| Error::with_message(Errno::EINVAL, "Invalid mode"))?;
let flags = FaccessatFlags::from_bits(flags)
.ok_or_else(|| Error::with_message(Errno::EINVAL, "Invalid flags"))?;
let path = ctx.user_space().read_cstring(path_ptr, PATH_MAX)?;
debug!(
"dirfd = {}, path = {:?}, mode = {:o}, flags = {:?}",
dirfd, path, mode, flags
);
if path.is_empty() && !flags.contains(FaccessatFlags::AT_EMPTY_PATH) {
return_errno_with_message!(Errno::ENOENT, "path is empty");
}
let dentry = {
let path = path.to_string_lossy();
let fs_path = FsPath::new(dirfd, path.as_ref())?;
let fs = ctx.posix_thread.fs().resolver().read();
if flags.contains(FaccessatFlags::AT_SYMLINK_NOFOLLOW) {
fs.lookup_no_follow(&fs_path)?
} else {
fs.lookup(&fs_path)?
}
};
// AccessMode::empty() means F_OK and no more permission check needed.
if mode.is_empty() {
return Ok(SyscallReturn::Return(0));
}
let inode = dentry.inode();
// FIXME: The current implementation is dummy
if mode.contains(AccessMode::R_OK) {
inode.check_permission(Permission::MAY_READ)?;
}
if mode.contains(AccessMode::W_OK) {
inode.check_permission(Permission::MAY_WRITE)?;
}
if mode.contains(AccessMode::X_OK) {
inode.check_permission(Permission::MAY_EXEC)?;
}
Ok(SyscallReturn::Return(0))
}