Browse Source

添加access、faccessat、faccessat2 (#439)

LoGin 1 year ago
parent
commit
9b0abe6da7

+ 3 - 0
kernel/src/arch/x86_64/syscall.rs

@@ -13,7 +13,10 @@ use alloc::string::String;
 
 use super::{interrupt::TrapFrame, mm::barrier::mfence};
 
+pub const SYS_ACCESS: usize = 21;
 pub const SYS_PRLIMIT64: usize = 302;
+pub const SYS_FACCESSAT: usize = 269;
+pub const SYS_FACCESSAT2: usize = 439;
 
 /// ### 存储PCB系统调用栈以及在syscall过程中暂存用户态rsp的结构体
 ///

+ 40 - 47
kernel/src/filesystem/vfs/fcntl.rs

@@ -58,55 +58,48 @@ pub enum FcntlCommand {
     SetFileRwHint = F_LINUX_SPECIFIC_BASE + 14,
 }
 
-///  The constants AT_REMOVEDIR and AT_EACCESS have the same value.  AT_EACCESS is
-///  meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
-///  unlinkat.  The two functions do completely different things and therefore,
-///  the flags can be allowed to overlap.  For example, passing AT_REMOVEDIR to
-///  faccessat would be undefined behavior and thus treating it equivalent to
-///  AT_EACCESS is valid undefined behavior.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
-#[allow(non_camel_case_types)]
-pub enum AtFlags {
-    /// 特殊值,用于指示openat应使用当前工作目录。
-    AtFdCwd = -100,
-    /// 不要跟随符号链接。
-    /// AT_SYMLINK_NOFOLLOW: 0x100
-    AtSymlinkNoFollow = 0x100,
-    /// AtEAccess: 使用有效ID进行访问测试,而不是实际ID。
-    /// AtRemoveDir: 删除目录而不是取消链接文件。
-    /// AT_EACCESS: 0x200
-    /// AT_REMOVEDIR: 0x200
-    AtEAccess_OR_AtRemoveDir = 0x200,
+bitflags! {
 
-    /// 跟随符号链接。
-    /// AT_SYMLINK_FOLLOW: 0x400
-    AtSymlinkFollow = 0x400,
-    /// 禁止终端自动挂载遍历。
-    /// AT_NO_AUTOMOUNT: 0x800
-    AtNoAutomount = 0x800,
-    /// 允许空的相对路径名。
-    /// AT_EMPTY_PATH: 0x1000
-    AtEmptyPath = 0x1000,
-    /// statx()所需的同步类型。
-    /// AT_STATX_SYNC_TYPE: 0x6000
-    AtStatxSyncType = 0x6000,
-    /// 执行与stat()相同的操作。
-    /// AT_STATX_SYNC_AS_STAT: 0x0000
-    AtStatxSyncAsStat = 0x0000,
-    /// 强制将属性与服务器同步。
-    /// AT_STATX_FORCE_SYNC: 0x2000
-    AtStatxForceSync = 0x2000,
-    /// 不要将属性与服务器同步。
-    /// AT_STATX_DONT_SYNC: 0x4000
-    AtStatxDontSync = 0x4000,
-    /// 应用于整个子树。
-    /// AT_RECURSIVE: 0x8000
-    AtRecursive = 0x8000,
-}
+    ///  The constants AT_REMOVEDIR and AT_EACCESS have the same value.  AT_EACCESS is
+    ///  meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
+    ///  unlinkat.  The two functions do completely different things and therefore,
+    ///  the flags can be allowed to overlap.  For example, passing AT_REMOVEDIR to
+    ///  faccessat would be undefined behavior and thus treating it equivalent to
+    ///  AT_EACCESS is valid undefined behavior.
+    pub struct AtFlags: i32 {
+        /// 特殊值,用于指示openat应使用当前工作目录。
+        const AT_FDCWD = -100;
+        /// 不要跟随符号链接。
+        const AT_SYMLINK_NOFOLLOW = 0x100;
+        /// AtEAccess: 使用有效ID进行访问测试,而不是实际ID。
+        const AT_EACCESS = 0x200;
+        /// AtRemoveDir: 删除目录而不是取消链接文件。
+        const AT_REMOVEDIR = 0x200;
 
-impl Into<i32> for AtFlags {
-    fn into(self) -> i32 {
-        self as i32
+        /// 跟随符号链接。
+        /// AT_SYMLINK_FOLLOW: 0x400
+        const AT_SYMLINK_FOLLOW = 0x400;
+        /// 禁止终端自动挂载遍历。
+        /// AT_NO_AUTOMOUNT: 0x800
+        const AT_NO_AUTOMOUNT = 0x800;
+        /// 允许空的相对路径名。
+        /// AT_EMPTY_PATH: 0x1000
+        const AT_EMPTY_PATH = 0x1000;
+        /// statx()所需的同步类型。
+        /// AT_STATX_SYNC_TYPE: 0x6000
+        const AT_STATX_SYNC_TYPE = 0x6000;
+        /// 执行与stat()相同的操作。
+        /// AT_STATX_SYNC_AS_STAT: 0x0000
+        const AT_STATX_SYNC_AS_STAT = 0x0000;
+        /// 强制将属性与服务器同步。
+        /// AT_STATX_FORCE_SYNC: 0x2000
+        const AT_STATX_FORCE_SYNC = 0x2000;
+        /// 不要将属性与服务器同步。
+        /// AT_STATX_DONT_SYNC: 0x4000
+        const AT_STATX_DONT_SYNC = 0x4000;
+        /// 应用于整个子树。
+        /// AT_RECURSIVE: 0x8000
+        const AT_RECURSIVE = 0x8000;
     }
 }
 

+ 1 - 0
kernel/src/filesystem/vfs/mod.rs

@@ -4,6 +4,7 @@ pub mod core;
 pub mod fcntl;
 pub mod file;
 pub mod mount;
+pub mod open;
 pub mod syscall;
 mod utils;
 

+ 27 - 0
kernel/src/filesystem/vfs/open.rs

@@ -0,0 +1,27 @@
+use crate::syscall::SystemError;
+
+use super::{fcntl::AtFlags, syscall::ModeType};
+
+pub(super) fn do_faccessat(
+    _dirfd: i32,
+    _pathname: *const u8,
+    mode: ModeType,
+    flags: u32,
+) -> Result<usize, SystemError> {
+    if (mode.bits() & (!ModeType::S_IXUGO.bits())) != 0 {
+        return Err(SystemError::EINVAL);
+    }
+
+    if (flags
+        & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits()
+            as u32)))
+        != 0
+    {
+        return Err(SystemError::EINVAL);
+    }
+
+    // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0;
+
+    // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat)
+    return Ok(0);
+}

+ 23 - 31
kernel/src/filesystem/vfs/syscall.rs

@@ -25,7 +25,8 @@ use super::{
     core::{do_mkdir, do_remove_dir, do_unlink_at},
     fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
     file::{File, FileMode},
-    utils::rsplit_path,
+    open::do_faccessat,
+    utils::{rsplit_path, user_path_at},
     Dirent, FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
 };
 // use crate::kdebug;
@@ -804,41 +805,14 @@ impl Syscall {
         user_buf: *mut u8,
         buf_size: usize,
     ) -> Result<usize, SystemError> {
-        let mut path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
+        let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
         let mut user_buf = UserBufferWriter::new(user_buf, buf_size, true)?;
 
         if path.len() == 0 {
             return Err(SystemError::EINVAL);
         }
 
-        let mut inode = ROOT_INODE();
-        // 如果path不是绝对路径,则需要拼接
-        if path.as_bytes()[0] != b'/' {
-            // 如果dirfd不是AT_FDCWD,则需要检查dirfd是否是目录
-            if dirfd != AtFlags::AtFdCwd.into() {
-                let binding = ProcessManager::current_pcb().fd_table();
-                let fd_table_guard = binding.read();
-                let file = fd_table_guard
-                    .get_file_by_fd(dirfd)
-                    .ok_or(SystemError::EBADF)?;
-
-                // drop guard 以避免无法调度的问题
-                drop(fd_table_guard);
-
-                let file_guard = file.lock();
-                // 如果dirfd不是目录,则返回错误码ENOTDIR
-                if file_guard.file_type() != FileType::Dir {
-                    return Err(SystemError::ENOTDIR);
-                }
-
-                inode = file_guard.inode();
-            } else {
-                let mut cwd = ProcessManager::current_pcb().basic().cwd();
-                cwd.push('/');
-                cwd.push_str(path.as_str());
-                path = cwd;
-            }
-        }
+        let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
 
         let inode = inode.lookup(path.as_str())?;
         if inode.metadata()?.file_type != FileType::SymLink {
@@ -859,7 +833,25 @@ impl Syscall {
         user_buf: *mut u8,
         buf_size: usize,
     ) -> Result<usize, SystemError> {
-        return Self::readlink_at(AtFlags::AtFdCwd.into(), path, user_buf, buf_size);
+        return Self::readlink_at(AtFlags::AT_FDCWD.bits(), path, user_buf, buf_size);
+    }
+
+    pub fn access(pathname: *const u8, mode: u32) -> Result<usize, SystemError> {
+        return do_faccessat(
+            AtFlags::AT_FDCWD.bits(),
+            pathname,
+            ModeType::from_bits_truncate(mode),
+            0,
+        );
+    }
+
+    pub fn faccessat2(
+        dirfd: i32,
+        pathname: *const u8,
+        mode: u32,
+        flags: u32,
+    ) -> Result<usize, SystemError> {
+        return do_faccessat(dirfd, pathname, ModeType::from_bits_truncate(mode), flags);
     }
 }
 

+ 48 - 0
kernel/src/filesystem/vfs/utils.rs

@@ -1,3 +1,9 @@
+use alloc::{string::String, sync::Arc};
+
+use crate::{process::ProcessControlBlock, syscall::SystemError};
+
+use super::{fcntl::AtFlags, FileType, IndexNode, ROOT_INODE};
+
 /// @brief 切分路径字符串,返回最左侧那一级的目录名和剩余的部分。
 ///
 /// 举例:对于 /123/456/789/   本函数返回的第一个值为123, 第二个值为456/789
@@ -19,3 +25,45 @@ pub fn rsplit_path(path: &str) -> (&str, Option<&str>) {
 
     return (comp, rest_opt);
 }
+
+/// 根据dirfd和path,计算接下来开始lookup的inode和剩余的path
+///
+/// ## 返回值
+///
+/// 返回值为(需要lookup的inode, 剩余的path)
+pub fn user_path_at(
+    pcb: &Arc<ProcessControlBlock>,
+    dirfd: i32,
+    mut path: String,
+) -> Result<(Arc<dyn IndexNode>, String), SystemError> {
+    let mut inode = ROOT_INODE();
+    // 如果path不是绝对路径,则需要拼接
+    if path.as_bytes()[0] != b'/' {
+        // 如果dirfd不是AT_FDCWD,则需要检查dirfd是否是目录
+        if dirfd != AtFlags::AT_FDCWD.bits() {
+            let binding = pcb.fd_table();
+            let fd_table_guard = binding.read();
+            let file = fd_table_guard
+                .get_file_by_fd(dirfd)
+                .ok_or(SystemError::EBADF)?;
+
+            // drop guard 以避免无法调度的问题
+            drop(fd_table_guard);
+
+            let file_guard = file.lock();
+            // 如果dirfd不是目录,则返回错误码ENOTDIR
+            if file_guard.file_type() != FileType::Dir {
+                return Err(SystemError::ENOTDIR);
+            }
+
+            inode = file_guard.inode();
+        } else {
+            let mut cwd = pcb.basic().cwd();
+            cwd.push('/');
+            cwd.push_str(path.as_str());
+            path = cwd;
+        }
+    }
+
+    return Ok((inode, path));
+}

+ 22 - 1
kernel/src/syscall/mod.rs

@@ -4,7 +4,7 @@ use core::{
 };
 
 use crate::{
-    arch::syscall::SYS_PRLIMIT64,
+    arch::syscall::{SYS_ACCESS, SYS_FACCESSAT, SYS_FACCESSAT2, SYS_PRLIMIT64},
     libs::{futex::constant::FutexFlag, rand::GRandFlags},
     process::{
         fork::KernelCloneArgs,
@@ -1204,6 +1204,27 @@ impl Syscall {
                 Self::prlimit64(pid, resource, new_limit, old_limit)
             }
 
+            SYS_ACCESS => {
+                let pathname = args[0] as *const u8;
+                let mode = args[1] as u32;
+                Self::access(pathname, mode)
+            }
+
+            SYS_FACCESSAT => {
+                let dirfd = args[0] as i32;
+                let pathname = args[1] as *const u8;
+                let mode = args[2] as u32;
+                Self::faccessat2(dirfd, pathname, mode, 0)
+            }
+
+            SYS_FACCESSAT2 => {
+                let dirfd = args[0] as i32;
+                let pathname = args[1] as *const u8;
+                let mode = args[2] as u32;
+                let flags = args[3] as u32;
+                Self::faccessat2(dirfd, pathname, mode, flags)
+            }
+
             _ => panic!("Unsupported syscall ID: {}", syscall_num),
         };
         return r;