Add support for chmod, fchmod, fchmodat

This commit is contained in:
LI Qing
2023-07-03 16:14:40 +08:00
committed by Tate, Hongliang Tian
parent 743344e3fc
commit 3600a3a439
14 changed files with 160 additions and 26 deletions

View File

@ -4,7 +4,7 @@ use log::Level;
pub const USER_STACK_SIZE: usize = PAGE_SIZE * 4; pub const USER_STACK_SIZE: usize = PAGE_SIZE * 4;
pub const KERNEL_STACK_SIZE: usize = PAGE_SIZE * 64; pub const KERNEL_STACK_SIZE: usize = PAGE_SIZE * 64;
pub const KERNEL_HEAP_SIZE: usize = 0x4_000_000; pub const KERNEL_HEAP_SIZE: usize = 0x5_000_000;
pub const KERNEL_OFFSET: usize = 0xffffffff80000000; pub const KERNEL_OFFSET: usize = 0xffffffff80000000;

View File

@ -1,4 +1,4 @@
TESTS ?= open_test read_test statfs_test TESTS ?= open_test read_test statfs_test chmod_test
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH))) CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))

View File

@ -0,0 +1,3 @@
ChmodTest.FchmodDirSucceeds_NoRandomSave
ChmodTest.FchmodatDirAbsolutePath
ChmodTest.FchmodatDir

View File

@ -109,7 +109,7 @@ impl FsResolver {
return_errno_with_message!(Errno::EISDIR, "path refers to a directory"); return_errno_with_message!(Errno::EISDIR, "path refers to a directory");
} }
if !dir_dentry.vnode().inode_mode().is_writable() { if !dir_dentry.vnode().inode_mode().is_writable() {
return_errno_with_message!(Errno::EPERM, "file cannot be created"); return_errno_with_message!(Errno::EACCES, "file cannot be created");
} }
let new_dentry = dir_dentry.create(&file_name, InodeType::File, inode_mode)?; let new_dentry = dir_dentry.create(&file_name, InodeType::File, inode_mode)?;
new_dentry new_dentry

View File

@ -55,26 +55,34 @@ impl<D: DirOps> ProcDir<D> {
impl<D: DirOps + 'static> Inode for ProcDir<D> { impl<D: DirOps + 'static> Inode for ProcDir<D> {
fn len(&self) -> usize { fn len(&self) -> usize {
self.info.metadata().size self.info.size()
} }
fn resize(&self, _new_size: usize) {} fn resize(&self, _new_size: usize) {}
fn metadata(&self) -> Metadata { fn metadata(&self) -> Metadata {
self.info.metadata().clone() self.info.metadata()
} }
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.info.metadata().atime self.info.atime()
} }
fn set_atime(&self, _time: Duration) {} fn set_atime(&self, time: Duration) {
self.info.set_atime(time)
}
fn mtime(&self) -> Duration { fn mtime(&self) -> Duration {
self.info.metadata().mtime self.info.mtime()
} }
fn set_mtime(&self, _time: Duration) {} fn set_mtime(&self, time: Duration) {
self.info.set_mtime(time)
}
fn set_mode(&self, mode: InodeMode) {
self.info.set_mode(mode)
}
fn create(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result<Arc<dyn Inode>> { fn create(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result<Arc<dyn Inode>> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))

View File

@ -28,26 +28,34 @@ impl<F: FileOps> ProcFile<F> {
impl<F: FileOps + 'static> Inode for ProcFile<F> { impl<F: FileOps + 'static> Inode for ProcFile<F> {
fn len(&self) -> usize { fn len(&self) -> usize {
self.info.metadata().size self.info.size()
} }
fn resize(&self, _new_size: usize) {} fn resize(&self, _new_size: usize) {}
fn metadata(&self) -> Metadata { fn metadata(&self) -> Metadata {
self.info.metadata().clone() self.info.metadata()
} }
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.info.metadata().atime self.info.atime()
} }
fn set_atime(&self, _time: Duration) {} fn set_atime(&self, time: Duration) {
self.info.set_atime(time)
}
fn mtime(&self) -> Duration { fn mtime(&self) -> Duration {
self.info.metadata().mtime self.info.mtime()
} }
fn set_mtime(&self, _time: Duration) {} fn set_mtime(&self, time: Duration) {
self.info.set_mtime(time)
}
fn set_mode(&self, mode: InodeMode) {
self.info.set_mode(mode)
}
fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> { fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> {
unreachable!() unreachable!()

View File

@ -1,4 +1,6 @@
use crate::fs::utils::{FileSystem, Metadata}; use core::time::Duration;
use crate::fs::utils::{FileSystem, InodeMode, Metadata};
use crate::prelude::*; use crate::prelude::*;
use super::ProcFS; use super::ProcFS;
@ -14,7 +16,7 @@ mod file;
mod sym; mod sym;
struct ProcInodeInfo { struct ProcInodeInfo {
metadata: Metadata, metadata: RwLock<Metadata>,
fs: Weak<dyn FileSystem>, fs: Weak<dyn FileSystem>,
is_volatile: bool, is_volatile: bool,
} }
@ -22,7 +24,7 @@ struct ProcInodeInfo {
impl ProcInodeInfo { impl ProcInodeInfo {
pub fn new(metadata: Metadata, fs: Weak<dyn FileSystem>, is_volatile: bool) -> Self { pub fn new(metadata: Metadata, fs: Weak<dyn FileSystem>, is_volatile: bool) -> Self {
Self { Self {
metadata, metadata: RwLock::new(metadata),
fs, fs,
is_volatile, is_volatile,
} }
@ -32,8 +34,32 @@ impl ProcInodeInfo {
&self.fs &self.fs
} }
pub fn metadata(&self) -> &Metadata { pub fn metadata(&self) -> Metadata {
&self.metadata self.metadata.read().clone()
}
pub fn size(&self) -> usize {
self.metadata.read().size
}
pub fn atime(&self) -> Duration {
self.metadata.read().atime
}
pub fn set_atime(&self, time: Duration) {
self.metadata.write().atime = time;
}
pub fn mtime(&self) -> Duration {
self.metadata.read().mtime
}
pub fn set_mtime(&self, time: Duration) {
self.metadata.write().mtime = time;
}
pub fn set_mode(&self, mode: InodeMode) {
self.metadata.write().mode = mode;
} }
pub fn is_volatile(&self) -> bool { pub fn is_volatile(&self) -> bool {

View File

@ -28,26 +28,34 @@ impl<S: SymOps> ProcSym<S> {
impl<S: SymOps + 'static> Inode for ProcSym<S> { impl<S: SymOps + 'static> Inode for ProcSym<S> {
fn len(&self) -> usize { fn len(&self) -> usize {
self.info.metadata().size self.info.size()
} }
fn resize(&self, _new_size: usize) {} fn resize(&self, _new_size: usize) {}
fn metadata(&self) -> Metadata { fn metadata(&self) -> Metadata {
self.info.metadata().clone() self.info.metadata()
} }
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.info.metadata().atime self.info.atime()
} }
fn set_atime(&self, _time: Duration) {} fn set_atime(&self, time: Duration) {
self.info.set_atime(time)
}
fn mtime(&self) -> Duration { fn mtime(&self) -> Duration {
self.info.metadata().mtime self.info.mtime()
} }
fn set_mtime(&self, _time: Duration) {} fn set_mtime(&self, time: Duration) {
self.info.set_mtime(time)
}
fn set_mode(&self, mode: InodeMode) {
self.info.set_mode(mode)
}
fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> { fn read_page(&self, _idx: usize, _frame: &VmFrame) -> Result<()> {
Err(Error::new(Errno::EPERM)) Err(Error::new(Errno::EPERM))

View File

@ -394,6 +394,10 @@ impl Inode for RamInode {
self.0.write().metadata.mtime = time; self.0.write().metadata.mtime = time;
} }
fn set_mode(&self, mode: InodeMode) {
self.0.write().metadata.mode = mode;
}
fn mknod( fn mknod(
&self, &self,
name: &str, name: &str,

View File

@ -110,6 +110,9 @@ impl Dentry {
if self.vnode.inode_type() != InodeType::Dir { if self.vnode.inode_type() != InodeType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
if !self.vnode.inode_mode().is_executable() {
return_errno!(Errno::EACCES);
}
if name.len() > NAME_MAX { if name.len() > NAME_MAX {
return_errno!(Errno::ENAMETOOLONG); return_errno!(Errno::ENAMETOOLONG);
} }
@ -253,6 +256,11 @@ impl Dentry {
self.vnode.inode_mode() self.vnode.inode_mode()
} }
/// Set the inode permission mode
pub fn set_inode_mode(&self, mode: InodeMode) {
self.vnode.set_inode_mode(mode)
}
/// Get the inode length /// Get the inode length
pub fn inode_len(&self) -> usize { pub fn inode_len(&self) -> usize {
self.vnode.len() self.vnode.len()

View File

@ -223,6 +223,8 @@ pub trait Inode: Any + Sync + Send {
fn set_mtime(&self, time: Duration); fn set_mtime(&self, time: Duration);
fn set_mode(&self, mode: InodeMode);
fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> { fn read_page(&self, idx: usize, frame: &VmFrame) -> Result<()> {
Err(Error::new(Errno::EISDIR)) Err(Error::new(Errno::EISDIR))
} }

View File

@ -218,6 +218,10 @@ impl Vnode {
self.inner.read().inode.metadata().mode self.inner.read().inode.metadata().mode
} }
pub fn set_inode_mode(&self, mode: InodeMode) {
self.inner.read().inode.set_mode(mode)
}
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.inner.read().inode.len() self.inner.read().inode.len()
} }

View File

@ -0,0 +1,55 @@
use crate::fs::{
file_table::FileDescripter,
fs_resolver::{FsPath, AT_FDCWD},
inode_handle::InodeHandle,
utils::{InodeMode, PATH_MAX},
};
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::util::read_cstring_from_user;
use super::SyscallReturn;
use super::{SYS_FCHMOD, SYS_FCHMODAT};
pub fn sys_fchmod(fd: FileDescripter, mode: u16) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_FCHMOD);
debug!("fd = {}, mode = 0o{:o}", fd, mode);
let current = current!();
let file_table = current.file_table().lock();
let file = file_table.get_file(fd)?;
let inode_handle = file
.downcast_ref::<InodeHandle>()
.ok_or(Error::with_message(Errno::EBADF, "not inode"))?;
let dentry = inode_handle.dentry();
dentry.set_inode_mode(InodeMode::from_bits_truncate(mode));
Ok(SyscallReturn::Return(0))
}
pub fn sys_chmod(path_ptr: Vaddr, mode: u16) -> Result<SyscallReturn> {
self::sys_fchmodat(AT_FDCWD, path_ptr, mode)
}
// Glibc handles the `flags` argument, so we just ignore it.
pub fn sys_fchmodat(
dirfd: FileDescripter,
path_ptr: Vaddr,
mode: u16,
/* flags: u32, */
) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_FCHMODAT);
let path = read_cstring_from_user(path_ptr, PATH_MAX)?;
debug!("dirfd = {}, path = {:?}, mode = 0o{:o}", dirfd, path, mode,);
let current = current!();
let dentry = {
let path = path.to_string_lossy();
if path.is_empty() {
return_errno_with_message!(Errno::ENOENT, "path is empty");
}
let fs_path = FsPath::new(dirfd, path.as_ref())?;
current.fs().read().lookup(&fs_path)?
};
dentry.set_inode_mode(InodeMode::from_bits_truncate(mode));
Ok(SyscallReturn::Return(0))
}

View File

@ -5,6 +5,7 @@ use crate::syscall::access::sys_access;
use crate::syscall::arch_prctl::sys_arch_prctl; use crate::syscall::arch_prctl::sys_arch_prctl;
use crate::syscall::brk::sys_brk; use crate::syscall::brk::sys_brk;
use crate::syscall::chdir::{sys_chdir, sys_fchdir}; use crate::syscall::chdir::{sys_chdir, sys_fchdir};
use crate::syscall::chmod::{sys_chmod, sys_fchmod, sys_fchmodat};
use crate::syscall::clock_gettime::sys_clock_gettime; use crate::syscall::clock_gettime::sys_clock_gettime;
use crate::syscall::clock_nanosleep::sys_clock_nanosleep; use crate::syscall::clock_nanosleep::sys_clock_nanosleep;
use crate::syscall::clone::sys_clone; use crate::syscall::clone::sys_clone;
@ -89,6 +90,7 @@ mod arch_prctl;
mod bind; mod bind;
mod brk; mod brk;
mod chdir; mod chdir;
mod chmod;
mod clock_gettime; mod clock_gettime;
mod clock_nanosleep; mod clock_nanosleep;
mod clone; mod clone;
@ -252,6 +254,8 @@ define_syscall_nums!(
SYS_UNLINK = 87, SYS_UNLINK = 87,
SYS_SYMLINK = 88, SYS_SYMLINK = 88,
SYS_READLINK = 89, SYS_READLINK = 89,
SYS_CHMOD = 90,
SYS_FCHMOD = 91,
SYS_UMASK = 95, SYS_UMASK = 95,
SYS_GETTIMEOFDAY = 96, SYS_GETTIMEOFDAY = 96,
SYS_GETUID = 102, SYS_GETUID = 102,
@ -286,6 +290,7 @@ define_syscall_nums!(
SYS_LINKAT = 265, SYS_LINKAT = 265,
SYS_SYMLINKAT = 266, SYS_SYMLINKAT = 266,
SYS_READLINKAT = 267, SYS_READLINKAT = 267,
SYS_FCHMODAT = 268,
SYS_SET_ROBUST_LIST = 273, SYS_SET_ROBUST_LIST = 273,
SYS_UTIMENSAT = 280, SYS_UTIMENSAT = 280,
SYS_EPOLL_CREATE1 = 291, SYS_EPOLL_CREATE1 = 291,
@ -406,6 +411,8 @@ pub fn syscall_dispatch(
SYS_UNLINK => syscall_handler!(1, sys_unlink, args), SYS_UNLINK => syscall_handler!(1, sys_unlink, args),
SYS_SYMLINK => syscall_handler!(2, sys_symlink, args), SYS_SYMLINK => syscall_handler!(2, sys_symlink, args),
SYS_READLINK => syscall_handler!(3, sys_readlink, args), SYS_READLINK => syscall_handler!(3, sys_readlink, args),
SYS_CHMOD => syscall_handler!(2, sys_chmod, args),
SYS_FCHMOD => syscall_handler!(2, sys_fchmod, args),
SYS_UMASK => syscall_handler!(1, sys_umask, args), SYS_UMASK => syscall_handler!(1, sys_umask, args),
SYS_GETTIMEOFDAY => syscall_handler!(1, sys_gettimeofday, args), SYS_GETTIMEOFDAY => syscall_handler!(1, sys_gettimeofday, args),
SYS_GETUID => syscall_handler!(0, sys_getuid), SYS_GETUID => syscall_handler!(0, sys_getuid),
@ -440,6 +447,7 @@ pub fn syscall_dispatch(
SYS_LINKAT => syscall_handler!(5, sys_linkat, args), SYS_LINKAT => syscall_handler!(5, sys_linkat, args),
SYS_SYMLINKAT => syscall_handler!(3, sys_symlinkat, args), SYS_SYMLINKAT => syscall_handler!(3, sys_symlinkat, args),
SYS_READLINKAT => syscall_handler!(4, sys_readlinkat, args), SYS_READLINKAT => syscall_handler!(4, sys_readlinkat, args),
SYS_FCHMODAT => syscall_handler!(3, sys_fchmodat, args),
SYS_SET_ROBUST_LIST => syscall_handler!(2, sys_set_robust_list, args), SYS_SET_ROBUST_LIST => syscall_handler!(2, sys_set_robust_list, args),
SYS_UTIMENSAT => syscall_handler!(4, sys_utimensat, args), SYS_UTIMENSAT => syscall_handler!(4, sys_utimensat, args),
SYS_EPOLL_CREATE1 => syscall_handler!(1, sys_epoll_create1, args), SYS_EPOLL_CREATE1 => syscall_handler!(1, sys_epoll_create1, args),