mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
120 lines
3.0 KiB
Rust
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))
|
|
}
|