From 729c6ecd0c8194177f2255a0019bc858666f8dc8 Mon Sep 17 00:00:00 2001 From: LI Qing Date: Thu, 4 Jan 2024 17:52:27 +0800 Subject: [PATCH] Add support for chown syscall --- regression/syscall_test/Makefile | 2 +- regression/syscall_test/blocklists/chown_test | 15 +++ services/aster-nix/src/fs/devpts/mod.rs | 74 +++++++---- services/aster-nix/src/fs/devpts/ptmx.rs | 53 +++++--- services/aster-nix/src/fs/devpts/slave.rs | 54 +++++--- .../src/fs/ext2/impl_for_vfs/inode.rs | 30 ++++- services/aster-nix/src/fs/ext2/inode.rs | 14 +++ services/aster-nix/src/fs/file_handle.rs | 27 +++- services/aster-nix/src/fs/fs_resolver.rs | 6 +- .../aster-nix/src/fs/inode_handle/dyn_cap.rs | 45 +++---- services/aster-nix/src/fs/inode_handle/mod.rs | 27 ++-- services/aster-nix/src/fs/pipe.rs | 9 +- .../aster-nix/src/fs/procfs/template/dir.rs | 72 ++++------- .../aster-nix/src/fs/procfs/template/file.rs | 71 ++++------- .../aster-nix/src/fs/procfs/template/mod.rs | 36 ++++-- .../aster-nix/src/fs/procfs/template/sym.rs | 68 ++++------ services/aster-nix/src/fs/ramfs/fs.rs | 28 ++++- services/aster-nix/src/fs/utils/dentry.rs | 84 ++++--------- services/aster-nix/src/fs/utils/inode.rs | 39 +++--- services/aster-nix/src/fs/utils/mount.rs | 2 +- .../src/net/socket/unix/stream/socket.rs | 4 +- .../src/process/program_loader/mod.rs | 6 +- services/aster-nix/src/syscall/chdir.rs | 4 +- services/aster-nix/src/syscall/chmod.rs | 9 +- services/aster-nix/src/syscall/chown.rs | 119 ++++++++++++++++++ services/aster-nix/src/syscall/execve.rs | 24 ++-- services/aster-nix/src/syscall/getdents64.rs | 2 +- services/aster-nix/src/syscall/mod.rs | 10 ++ services/aster-nix/src/syscall/rename.rs | 2 +- services/aster-nix/src/syscall/stat.rs | 6 +- services/aster-nix/src/syscall/truncate.rs | 2 +- 31 files changed, 583 insertions(+), 361 deletions(-) create mode 100644 regression/syscall_test/blocklists/chown_test create mode 100644 services/aster-nix/src/syscall/chown.rs diff --git a/regression/syscall_test/Makefile b/regression/syscall_test/Makefile index 8cea5da4d..e50acf1cd 100644 --- a/regression/syscall_test/Makefile +++ b/regression/syscall_test/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: MPL-2.0 -TESTS ?= chmod_test fsync_test getdents_test link_test lseek_test mkdir_test \ +TESTS ?= chmod_test chown_test fsync_test getdents_test link_test lseek_test mkdir_test \ open_create_test open_test pty_test read_test rename_test stat_test \ statfs_test symlink_test sync_test truncate_test uidgid_test unlink_test \ vdso_clock_gettime_test write_test diff --git a/regression/syscall_test/blocklists/chown_test b/regression/syscall_test/blocklists/chown_test new file mode 100644 index 000000000..1a8c72fa4 --- /dev/null +++ b/regression/syscall_test/blocklists/chown_test @@ -0,0 +1,15 @@ +ChownKinds/ChownParamTest.ChownFileSucceeds/0 +ChownKinds/ChownParamTest.ChownFileSucceeds/1 +ChownKinds/ChownParamTest.ChownFileSucceeds/2 +ChownKinds/ChownParamTest.ChownFileSucceeds/3 +ChownKinds/ChownParamTest.ChownFileSucceeds/4 +ChownKinds/ChownParamTest.ChownFilePermissionDenied/0 +ChownKinds/ChownParamTest.ChownFilePermissionDenied/1 +ChownKinds/ChownParamTest.ChownFilePermissionDenied/2 +ChownKinds/ChownParamTest.ChownFilePermissionDenied/3 +ChownKinds/ChownParamTest.ChownFilePermissionDenied/4 +ChownKinds/ChownParamTest.ChownFileSucceedsAsRoot/0 +ChownKinds/ChownParamTest.ChownFileSucceedsAsRoot/1 +ChownKinds/ChownParamTest.ChownFileSucceedsAsRoot/2 +ChownKinds/ChownParamTest.ChownFileSucceedsAsRoot/3 +ChownKinds/ChownParamTest.ChownFileSucceedsAsRoot/4 \ No newline at end of file diff --git a/services/aster-nix/src/fs/devpts/mod.rs b/services/aster-nix/src/fs/devpts/mod.rs index 89f1e5d09..884928910 100644 --- a/services/aster-nix/src/fs/devpts/mod.rs +++ b/services/aster-nix/src/fs/devpts/mod.rs @@ -7,6 +7,7 @@ use crate::fs::utils::{ SuperBlock, NAME_MAX, }; use crate::prelude::*; +use crate::process::{Gid, Uid}; use aster_util::{id_allocator::IdAlloc, slot_vec::SlotVec}; use core::time::Duration; @@ -100,7 +101,7 @@ impl FileSystem for DevPts { struct RootInode { ptmx: Arc, slaves: RwLock)>>, - metadata: Metadata, + metadata: RwLock, fs: Weak, } @@ -109,7 +110,11 @@ impl RootInode { Arc::new(Self { ptmx: Ptmx::new(sb, fs.clone()), slaves: RwLock::new(SlotVec::new()), - metadata: Metadata::new_dir(ROOT_INO, InodeMode::from_bits_truncate(0o755), sb), + metadata: RwLock::new(Metadata::new_dir( + ROOT_INO, + InodeMode::from_bits_truncate(0o755), + sb, + )), fs, }) } @@ -138,7 +143,7 @@ impl RootInode { impl Inode for RootInode { fn size(&self) -> usize { - self.metadata.size + self.metadata.read().size } fn resize(&self, new_size: usize) -> Result<()> { @@ -146,34 +151,59 @@ impl Inode for RootInode { } fn metadata(&self) -> Metadata { - self.metadata.clone() + *self.metadata.read() } fn ino(&self) -> u64 { - self.metadata.ino as _ + self.metadata.read().ino as _ } fn type_(&self) -> InodeType { - self.metadata.type_ + self.metadata.read().type_ } - fn mode(&self) -> InodeMode { - self.metadata.mode + fn mode(&self) -> Result { + Ok(self.metadata.read().mode) } - fn set_mode(&self, mode: InodeMode) {} + fn set_mode(&self, mode: InodeMode) -> Result<()> { + self.metadata.write().mode = mode; + Ok(()) + } + + fn owner(&self) -> Result { + Ok(self.metadata.read().uid) + } + + fn set_owner(&self, uid: Uid) -> Result<()> { + self.metadata.write().uid = uid; + Ok(()) + } + + fn group(&self) -> Result { + Ok(self.metadata.read().gid) + } + + fn set_group(&self, gid: Gid) -> Result<()> { + self.metadata.write().gid = gid; + Ok(()) + } fn atime(&self) -> Duration { - self.metadata.atime + self.metadata.read().atime } - fn set_atime(&self, time: Duration) {} + fn set_atime(&self, time: Duration) { + self.metadata.write().atime = time; + } fn mtime(&self) -> Duration { - self.metadata.mtime + self.metadata.read().mtime } - fn set_mtime(&self, time: Duration) {} + fn set_mtime(&self, time: Duration) { + self.metadata.write().mtime = time; + } fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result> { Err(Error::new(Errno::EPERM)) @@ -187,20 +217,15 @@ impl Inode for RootInode { let try_readdir = |offset: &mut usize, visitor: &mut dyn DirentVisitor| -> Result<()> { // Read the 3 special entries. if *offset == 0 { - visitor.visit(".", self.metadata.ino as u64, self.metadata.type_, *offset)?; + visitor.visit(".", self.ino(), self.type_(), *offset)?; *offset += 1; } if *offset == 1 { - visitor.visit("..", self.metadata.ino as u64, self.metadata.type_, *offset)?; + visitor.visit("..", self.ino(), self.type_(), *offset)?; *offset += 1; } if *offset == 2 { - visitor.visit( - "ptmx", - self.ptmx.metadata().ino as u64, - self.ptmx.metadata().type_, - *offset, - )?; + visitor.visit("ptmx", self.ptmx.ino(), self.ptmx.type_(), *offset)?; *offset += 1; } @@ -212,12 +237,7 @@ impl Inode for RootInode { .map(|(idx, (name, node))| (idx + 3, (name, node))) .skip_while(|(idx, _)| idx < &start_offset) { - visitor.visit( - name.as_ref(), - node.metadata().ino as u64, - node.metadata().type_, - idx, - )?; + visitor.visit(name.as_ref(), node.ino(), node.type_(), idx)?; *offset = idx + 1; } Ok(()) diff --git a/services/aster-nix/src/fs/devpts/ptmx.rs b/services/aster-nix/src/fs/devpts/ptmx.rs index 6e9adac48..83f72e3a7 100644 --- a/services/aster-nix/src/fs/devpts/ptmx.rs +++ b/services/aster-nix/src/fs/devpts/ptmx.rs @@ -19,7 +19,7 @@ const PTMX_MINOR_NUM: u32 = 2; /// and an corresponding pty slave inode is also created. pub struct Ptmx { inner: Inner, - metadata: Metadata, + metadata: RwLock, } #[derive(Clone)] @@ -29,12 +29,12 @@ impl Ptmx { pub fn new(sb: &SuperBlock, fs: Weak) -> Arc { let inner = Inner(fs); Arc::new(Self { - metadata: Metadata::new_device( + metadata: RwLock::new(Metadata::new_device( PTMX_INO, InodeMode::from_bits_truncate(0o666), sb, &inner, - ), + )), inner, }) } @@ -64,7 +64,7 @@ impl Ptmx { // it returns the pty master. So the ptmx can not be used at upper layer. impl Inode for Ptmx { fn size(&self) -> usize { - self.metadata.size + self.metadata.read().size } fn resize(&self, new_size: usize) -> Result<()> { @@ -72,34 +72,59 @@ impl Inode for Ptmx { } fn metadata(&self) -> Metadata { - self.metadata.clone() + *self.metadata.read() } fn ino(&self) -> u64 { - self.metadata.ino as _ + self.metadata.read().ino as _ } fn type_(&self) -> InodeType { - self.metadata.type_ + self.metadata.read().type_ } - fn mode(&self) -> InodeMode { - self.metadata.mode + fn mode(&self) -> Result { + Ok(self.metadata.read().mode) } - fn set_mode(&self, mode: InodeMode) {} + fn set_mode(&self, mode: InodeMode) -> Result<()> { + self.metadata.write().mode = mode; + Ok(()) + } + + fn owner(&self) -> Result { + Ok(self.metadata.read().uid) + } + + fn set_owner(&self, uid: Uid) -> Result<()> { + self.metadata.write().uid = uid; + Ok(()) + } + + fn group(&self) -> Result { + Ok(self.metadata.read().gid) + } + + fn set_group(&self, gid: Gid) -> Result<()> { + self.metadata.write().gid = gid; + Ok(()) + } fn atime(&self) -> Duration { - self.metadata.atime + self.metadata.read().atime } - fn set_atime(&self, time: Duration) {} + fn set_atime(&self, time: Duration) { + self.metadata.write().atime = time; + } fn mtime(&self) -> Duration { - self.metadata.mtime + self.metadata.read().mtime } - fn set_mtime(&self, time: Duration) {} + fn set_mtime(&self, time: Duration) { + self.metadata.write().mtime = time; + } fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { Ok(0) diff --git a/services/aster-nix/src/fs/devpts/slave.rs b/services/aster-nix/src/fs/devpts/slave.rs index 9b7aeef3b..153e10a62 100644 --- a/services/aster-nix/src/fs/devpts/slave.rs +++ b/services/aster-nix/src/fs/devpts/slave.rs @@ -4,6 +4,7 @@ use crate::events::IoEvents; use crate::fs::inode_handle::FileIo; use crate::prelude::*; use crate::process::signal::Poller; +use crate::process::{Gid, Uid}; use super::*; @@ -15,19 +16,19 @@ const SLAVE_MAJOR_NUM: u32 = 3; /// Pty slave inode for the slave device. pub struct PtySlaveInode { device: Arc, - metadata: Metadata, + metadata: RwLock, fs: Weak, } impl PtySlaveInode { pub fn new(device: Arc, fs: Weak) -> Arc { Arc::new(Self { - metadata: Metadata::new_device( + metadata: RwLock::new(Metadata::new_device( device.index() as usize + FIRST_SLAVE_INO, InodeMode::from_bits_truncate(0o620), &fs.upgrade().unwrap().sb(), device.as_ref(), - ), + )), device, fs, }) @@ -44,7 +45,7 @@ impl Inode for PtySlaveInode { } fn size(&self) -> usize { - self.metadata.size + self.metadata.read().size } fn resize(&self, new_size: usize) -> Result<()> { @@ -52,34 +53,59 @@ impl Inode for PtySlaveInode { } fn metadata(&self) -> Metadata { - self.metadata.clone() + *self.metadata.read() } fn ino(&self) -> u64 { - self.metadata.ino as _ + self.metadata.read().ino as _ } fn type_(&self) -> InodeType { - self.metadata.type_ + self.metadata.read().type_ } - fn mode(&self) -> InodeMode { - self.metadata.mode + fn mode(&self) -> Result { + Ok(self.metadata.read().mode) } - fn set_mode(&self, mode: InodeMode) {} + fn set_mode(&self, mode: InodeMode) -> Result<()> { + self.metadata.write().mode = mode; + Ok(()) + } + + fn owner(&self) -> Result { + Ok(self.metadata.read().uid) + } + + fn set_owner(&self, uid: Uid) -> Result<()> { + self.metadata.write().uid = uid; + Ok(()) + } + + fn group(&self) -> Result { + Ok(self.metadata.read().gid) + } + + fn set_group(&self, gid: Gid) -> Result<()> { + self.metadata.write().gid = gid; + Ok(()) + } fn atime(&self) -> Duration { - self.metadata.atime + self.metadata.read().atime } - fn set_atime(&self, time: Duration) {} + fn set_atime(&self, time: Duration) { + self.metadata.write().atime = time; + } fn mtime(&self) -> Duration { - self.metadata.mtime + self.metadata.read().mtime } - fn set_mtime(&self, time: Duration) {} + fn set_mtime(&self, time: Duration) { + self.metadata.write().mtime = time; + } fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { self.device.read(buf) diff --git a/services/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs b/services/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs index 94fe3a14e..3fd87e13a 100644 --- a/services/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs +++ b/services/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs @@ -6,6 +6,7 @@ use crate::fs::utils::{ DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, }; use crate::prelude::*; +use crate::process::{Gid, Uid}; use crate::vm::vmo::Vmo; use aster_rights::Full; @@ -33,8 +34,8 @@ impl Inode for Ext2Inode { type_: InodeType::from(self.file_type()), mode: InodeMode::from(self.file_perm()), nlinks: self.hard_links() as _, - uid: self.uid() as _, - gid: self.gid() as _, + uid: Uid::new(self.uid()), + gid: Gid::new(self.gid()), rdev: self.device_id(), } } @@ -63,12 +64,31 @@ impl Inode for Ext2Inode { InodeType::from(self.file_type()) } - fn mode(&self) -> InodeMode { - InodeMode::from(self.file_perm()) + fn mode(&self) -> Result { + Ok(InodeMode::from(self.file_perm())) } - fn set_mode(&self, mode: InodeMode) { + fn set_mode(&self, mode: InodeMode) -> Result<()> { self.set_file_perm(mode.into()); + Ok(()) + } + + fn owner(&self) -> Result { + Ok(Uid::new(self.uid())) + } + + fn set_owner(&self, uid: Uid) -> Result<()> { + self.set_uid(uid.as_u32()); + Ok(()) + } + + fn group(&self) -> Result { + Ok(Gid::new(self.gid())) + } + + fn set_group(&self, gid: Gid) -> Result<()> { + self.set_gid(gid.as_u32()); + Ok(()) } fn page_cache(&self) -> Option> { diff --git a/services/aster-nix/src/fs/ext2/inode.rs b/services/aster-nix/src/fs/ext2/inode.rs index 9ce7f1b57..a0996bd85 100644 --- a/services/aster-nix/src/fs/ext2/inode.rs +++ b/services/aster-nix/src/fs/ext2/inode.rs @@ -576,6 +576,8 @@ impl Inode { #[inherit_methods(from = "self.inner.write()")] impl Inode { pub fn set_file_perm(&self, perm: FilePerm); + pub fn set_uid(&self, uid: u32); + pub fn set_gid(&self, gid: u32); pub fn set_atime(&self, time: Duration); pub fn set_mtime(&self, time: Duration); } @@ -601,7 +603,9 @@ impl Inner { pub fn file_perm(&self) -> FilePerm; pub fn set_file_perm(&mut self, perm: FilePerm); pub fn uid(&self) -> u32; + pub fn set_uid(&mut self, uid: u32); pub fn gid(&self) -> u32; + pub fn set_gid(&mut self, gid: u32); pub fn file_flags(&self) -> FileFlags; pub fn hard_links(&self) -> u16; pub fn inc_hard_links(&mut self); @@ -936,10 +940,20 @@ impl InodeImpl { self.0.read().desc.uid } + pub fn set_uid(&self, uid: u32) { + let mut inner = self.0.write(); + inner.desc.uid = uid; + } + pub fn gid(&self) -> u32 { self.0.read().desc.gid } + pub fn set_gid(&self, gid: u32) { + let mut inner = self.0.write(); + inner.desc.gid = gid; + } + pub fn file_flags(&self) -> FileFlags { self.0.read().desc.flags } diff --git a/services/aster-nix/src/fs/file_handle.rs b/services/aster-nix/src/fs/file_handle.rs index 8c92f51a1..481f7becc 100644 --- a/services/aster-nix/src/fs/file_handle.rs +++ b/services/aster-nix/src/fs/file_handle.rs @@ -4,10 +4,11 @@ use crate::events::{IoEvents, Observer}; use crate::fs::device::Device; -use crate::fs::utils::{AccessMode, IoctlCmd, Metadata, SeekFrom, StatusFlags}; +use crate::fs::utils::{AccessMode, InodeMode, IoctlCmd, Metadata, SeekFrom, StatusFlags}; use crate::net::socket::Socket; use crate::prelude::*; use crate::process::signal::Poller; +use crate::process::{Gid, Uid}; use core::any::Any; @@ -41,6 +42,30 @@ pub trait FileLike: Send + Sync + Any { panic!("metadata unsupported"); } + fn mode(&self) -> Result { + return_errno_with_message!(Errno::EINVAL, "mode is not supported"); + } + + fn set_mode(&self, mode: InodeMode) -> Result<()> { + return_errno_with_message!(Errno::EINVAL, "set_mode is not supported"); + } + + fn owner(&self) -> Result { + return_errno_with_message!(Errno::EPERM, "owner is not supported"); + } + + fn set_owner(&self, uid: Uid) -> Result<()> { + return_errno_with_message!(Errno::EPERM, "set_owner is not supported"); + } + + fn group(&self) -> Result { + return_errno_with_message!(Errno::EPERM, "group is not supported"); + } + + fn set_group(&self, gid: Gid) -> Result<()> { + return_errno_with_message!(Errno::EPERM, "set_group is not supported"); + } + fn status_flags(&self) -> StatusFlags { StatusFlags::empty() } diff --git a/services/aster-nix/src/fs/fs_resolver.rs b/services/aster-nix/src/fs/fs_resolver.rs index b98b032ef..4f8a499a6 100644 --- a/services/aster-nix/src/fs/fs_resolver.rs +++ b/services/aster-nix/src/fs/fs_resolver.rs @@ -100,7 +100,7 @@ impl FsResolver { if file_name.ends_with('/') { return_errno_with_message!(Errno::EISDIR, "path refers to a directory"); } - if !dir_dentry.inode_mode().is_writable() { + if !dir_dentry.mode()?.is_writable() { return_errno_with_message!(Errno::EACCES, "file cannot be created"); } dir_dentry.create(&file_name, InodeType::File, inode_mode)? @@ -182,7 +182,7 @@ impl FsResolver { // Iterate next dentry let next_dentry = dentry.lookup(next_name)?; - let next_type = next_dentry.inode_type(); + let next_type = next_dentry.type_(); let next_is_tail = path_remain.is_empty(); // If next inode is a symlink, follow symlinks at most `SYMLINKS_MAX` times. @@ -280,7 +280,7 @@ impl FsResolver { // Dereference the tail symlinks if needed loop { match dir_dentry.lookup(base_name.trim_end_matches('/')) { - Ok(dentry) if dentry.inode_type() == InodeType::SymLink => { + Ok(dentry) if dentry.type_() == InodeType::SymLink => { let link = { let mut link = dentry.inode().read_link()?; if link.is_empty() { diff --git a/services/aster-nix/src/fs/inode_handle/dyn_cap.rs b/services/aster-nix/src/fs/inode_handle/dyn_cap.rs index 487cc1da4..c346135b1 100644 --- a/services/aster-nix/src/fs/inode_handle/dyn_cap.rs +++ b/services/aster-nix/src/fs/inode_handle/dyn_cap.rs @@ -3,7 +3,10 @@ use crate::events::IoEvents; use crate::prelude::*; use crate::process::signal::Poller; +use crate::process::{Gid, Uid}; + use aster_rights::{Rights, TRights}; +use inherit_methods_macro::inherit_methods; use super::*; @@ -14,10 +17,10 @@ impl InodeHandle { status_flags: StatusFlags, ) -> Result { let inode = dentry.inode(); - if access_mode.is_readable() && !inode.mode().is_readable() { + if access_mode.is_readable() && !inode.mode()?.is_readable() { return_errno_with_message!(Errno::EACCES, "File is not readable"); } - if access_mode.is_writable() && !inode.mode().is_writable() { + if access_mode.is_writable() && !inode.mode()?.is_writable() { return_errno_with_message!(Errno::EACCES, "File is not writable"); } if access_mode.is_writable() && inode.type_() == InodeType::Dir { @@ -70,7 +73,21 @@ impl Clone for InodeHandle { } } +#[inherit_methods(from = "self.0")] impl FileLike for InodeHandle { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents; + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result; + fn status_flags(&self) -> StatusFlags; + fn access_mode(&self) -> AccessMode; + fn metadata(&self) -> Metadata; + fn mode(&self) -> Result; + fn set_mode(&self, mode: InodeMode) -> Result<()>; + fn owner(&self) -> Result; + fn set_owner(&self, uid: Uid) -> Result<()>; + fn group(&self) -> Result; + fn set_group(&self, gid: Gid) -> Result<()>; + fn seek(&self, seek_from: SeekFrom) -> Result; + fn read(&self, buf: &mut [u8]) -> Result { if !self.1.contains(Rights::READ) { return_errno_with_message!(Errno::EBADF, "File is not readable"); @@ -85,14 +102,6 @@ impl FileLike for InodeHandle { self.0.write(buf) } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.0.poll(mask, poller) - } - - fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { - self.0.ioctl(cmd, arg) - } - fn resize(&self, new_size: usize) -> Result<()> { if !self.1.contains(Rights::WRITE) { return_errno_with_message!(Errno::EINVAL, "File is not writable"); @@ -100,27 +109,11 @@ impl FileLike for InodeHandle { self.0.resize(new_size) } - fn metadata(&self) -> Metadata { - self.dentry().inode_metadata() - } - - fn status_flags(&self) -> StatusFlags { - self.0.status_flags() - } - fn set_status_flags(&self, new_status_flags: StatusFlags) -> Result<()> { self.0.set_status_flags(new_status_flags); Ok(()) } - fn access_mode(&self) -> AccessMode { - self.0.access_mode() - } - - fn seek(&self, seek_from: SeekFrom) -> Result { - self.0.seek(seek_from) - } - fn clean_for_close(&self) -> Result<()> { // Close does not guarantee that the data has been successfully saved to disk. Ok(()) diff --git a/services/aster-nix/src/fs/inode_handle/mod.rs b/services/aster-nix/src/fs/inode_handle/mod.rs index de3af7a65..dc7e126bc 100644 --- a/services/aster-nix/src/fs/inode_handle/mod.rs +++ b/services/aster-nix/src/fs/inode_handle/mod.rs @@ -6,15 +6,18 @@ mod dyn_cap; mod static_cap; use core::sync::atomic::{AtomicU32, Ordering}; +use inherit_methods_macro::inherit_methods; use crate::events::IoEvents; use crate::fs::device::Device; use crate::fs::file_handle::FileLike; use crate::fs::utils::{ - AccessMode, Dentry, DirentVisitor, InodeType, IoctlCmd, Metadata, SeekFrom, StatusFlags, + AccessMode, Dentry, DirentVisitor, InodeMode, InodeType, IoctlCmd, Metadata, SeekFrom, + StatusFlags, }; use crate::prelude::*; use crate::process::signal::Poller; +use crate::process::{Gid, Uid}; use aster_rights::Rights; #[derive(Debug)] @@ -57,7 +60,7 @@ impl InodeHandle_ { } if self.status_flags().contains(StatusFlags::O_APPEND) { - *offset = self.dentry.inode_size(); + *offset = self.dentry.size(); } let len = if self.status_flags().contains(StatusFlags::O_DIRECT) { self.dentry.inode().write_direct_at(*offset, buf)? @@ -92,7 +95,7 @@ impl InodeHandle_ { off as isize } SeekFrom::End(off /* as isize */) => { - let file_size = self.dentry.inode_size() as isize; + let file_size = self.dentry.size() as isize; assert!(file_size >= 0); file_size .checked_add(off) @@ -116,15 +119,11 @@ impl InodeHandle_ { *offset } - pub fn size(&self) -> usize { - self.dentry.inode_size() - } - pub fn resize(&self, new_size: usize) -> Result<()> { if self.status_flags().contains(StatusFlags::O_APPEND) { return_errno_with_message!(Errno::EPERM, "can not resize append-only file"); } - self.dentry.set_inode_size(new_size) + self.dentry.resize(new_size) } pub fn access_mode(&self) -> AccessMode { @@ -165,6 +164,18 @@ impl InodeHandle_ { } } +#[inherit_methods(from = "self.dentry")] +impl InodeHandle_ { + pub fn size(&self) -> usize; + pub fn metadata(&self) -> Metadata; + pub fn mode(&self) -> Result; + pub fn set_mode(&self, mode: InodeMode) -> Result<()>; + pub fn owner(&self) -> Result; + pub fn set_owner(&self, uid: Uid) -> Result<()>; + pub fn group(&self) -> Result; + pub fn set_group(&self, gid: Gid) -> Result<()>; +} + impl Debug for InodeHandle_ { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct("InodeHandle_") diff --git a/services/aster-nix/src/fs/pipe.rs b/services/aster-nix/src/fs/pipe.rs index 6ccf69c79..1e777e727 100644 --- a/services/aster-nix/src/fs/pipe.rs +++ b/services/aster-nix/src/fs/pipe.rs @@ -3,6 +3,7 @@ use crate::events::{IoEvents, Observer}; use crate::prelude::*; use crate::process::signal::Poller; +use crate::process::{Gid, Uid}; use super::file_handle::FileLike; use super::utils::{AccessMode, Consumer, InodeMode, InodeType, Metadata, Producer, StatusFlags}; @@ -51,8 +52,8 @@ impl FileLike for PipeReader { type_: InodeType::NamedPipe, mode: InodeMode::from_bits_truncate(0o400), nlinks: 1, - uid: 0, - gid: 0, + uid: Uid::new_root(), + gid: Gid::new_root(), rdev: 0, } } @@ -117,8 +118,8 @@ impl FileLike for PipeWriter { type_: InodeType::NamedPipe, mode: InodeMode::from_bits_truncate(0o200), nlinks: 1, - uid: 0, - gid: 0, + uid: Uid::new_root(), + gid: Gid::new_root(), rdev: 0, } } diff --git a/services/aster-nix/src/fs/procfs/template/dir.rs b/services/aster-nix/src/fs/procfs/template/dir.rs index b39a3d130..78a674c46 100644 --- a/services/aster-nix/src/fs/procfs/template/dir.rs +++ b/services/aster-nix/src/fs/procfs/template/dir.rs @@ -2,19 +2,21 @@ use aster_util::slot_vec::SlotVec; use core::time::Duration; +use inherit_methods_macro::inherit_methods; use crate::fs::device::Device; use crate::fs::utils::{DirentVisitor, FileSystem, Inode, InodeMode, InodeType, Metadata}; use crate::prelude::*; +use crate::process::{Gid, Uid}; -use super::{ProcFS, ProcInodeInfo}; +use super::{Common, ProcFS}; pub struct ProcDir { inner: D, this: Weak>, parent: Option>, cached_children: RwLock)>>, - info: ProcInodeInfo, + common: Common, } impl ProcDir { @@ -24,21 +26,21 @@ impl ProcDir { parent: Option>, is_volatile: bool, ) -> Arc { - let info = { + let common = { let procfs = fs.downcast_ref::().unwrap(); let metadata = Metadata::new_dir( procfs.alloc_id(), InodeMode::from_bits_truncate(0o555), &fs.sb(), ); - ProcInodeInfo::new(metadata, Arc::downgrade(&fs), is_volatile) + Common::new(metadata, Arc::downgrade(&fs), is_volatile) }; Arc::new_cyclic(|weak_self| Self { inner: dir, this: weak_self.clone(), parent, cached_children: RwLock::new(SlotVec::new()), - info, + common, }) } @@ -55,51 +57,31 @@ impl ProcDir { } } +#[inherit_methods(from = "self.common")] impl Inode for ProcDir { - fn size(&self) -> usize { - self.info.size() - } + fn size(&self) -> usize; + fn metadata(&self) -> Metadata; + fn ino(&self) -> u64; + fn mode(&self) -> Result; + fn set_mode(&self, mode: InodeMode) -> Result<()>; + fn owner(&self) -> Result; + fn set_owner(&self, uid: Uid) -> Result<()>; + fn group(&self) -> Result; + fn set_group(&self, gid: Gid) -> Result<()>; + fn atime(&self) -> Duration; + fn set_atime(&self, time: Duration); + fn mtime(&self) -> Duration; + fn set_mtime(&self, time: Duration); + fn fs(&self) -> Arc; fn resize(&self, _new_size: usize) -> Result<()> { Err(Error::new(Errno::EISDIR)) } - fn metadata(&self) -> Metadata { - self.info.metadata() - } - - fn ino(&self) -> u64 { - self.info.ino() - } - fn type_(&self) -> InodeType { InodeType::Dir } - fn mode(&self) -> InodeMode { - self.info.mode() - } - - fn set_mode(&self, mode: InodeMode) { - self.info.set_mode(mode) - } - - fn atime(&self) -> Duration { - self.info.atime() - } - - fn set_atime(&self, time: Duration) { - self.info.set_atime(time) - } - - fn mtime(&self) -> Duration { - self.info.mtime() - } - - fn set_mtime(&self, time: Duration) { - self.info.set_mtime(time) - } - fn create(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result> { Err(Error::new(Errno::EPERM)) } @@ -120,8 +102,8 @@ impl Inode for ProcDir { let this_inode = self.this(); visitor.visit( ".", - this_inode.info.metadata().ino as u64, - this_inode.info.metadata().type_, + this_inode.common.metadata().ino as u64, + this_inode.common.metadata().type_, *offset, )?; *offset += 1; @@ -204,12 +186,8 @@ impl Inode for ProcDir { Ok(()) } - fn fs(&self) -> Arc { - self.info.fs().upgrade().unwrap() - } - fn is_dentry_cacheable(&self) -> bool { - !self.info.is_volatile() + !self.common.is_volatile() } } diff --git a/services/aster-nix/src/fs/procfs/template/file.rs b/services/aster-nix/src/fs/procfs/template/file.rs index 4d22376f2..bdb953c9d 100644 --- a/services/aster-nix/src/fs/procfs/template/file.rs +++ b/services/aster-nix/src/fs/procfs/template/file.rs @@ -1,77 +1,62 @@ // SPDX-License-Identifier: MPL-2.0 use core::time::Duration; +use inherit_methods_macro::inherit_methods; use crate::fs::utils::{FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata}; use crate::prelude::*; +use crate::process::{Gid, Uid}; -use super::{ProcFS, ProcInodeInfo}; +use super::{Common, ProcFS}; pub struct ProcFile { inner: F, - info: ProcInodeInfo, + common: Common, } impl ProcFile { pub fn new(file: F, fs: Arc, is_volatile: bool) -> Arc { - let info = { + let common = { let procfs = fs.downcast_ref::().unwrap(); let metadata = Metadata::new_file( procfs.alloc_id(), InodeMode::from_bits_truncate(0o444), &fs.sb(), ); - ProcInodeInfo::new(metadata, Arc::downgrade(&fs), is_volatile) + Common::new(metadata, Arc::downgrade(&fs), is_volatile) }; - Arc::new(Self { inner: file, info }) + Arc::new(Self { + inner: file, + common, + }) } } +#[inherit_methods(from = "self.common")] impl Inode for ProcFile { - fn size(&self) -> usize { - self.info.size() - } + fn size(&self) -> usize; + fn metadata(&self) -> Metadata; + fn ino(&self) -> u64; + fn mode(&self) -> Result; + fn set_mode(&self, mode: InodeMode) -> Result<()>; + fn owner(&self) -> Result; + fn set_owner(&self, uid: Uid) -> Result<()>; + fn group(&self) -> Result; + fn set_group(&self, gid: Gid) -> Result<()>; + fn atime(&self) -> Duration; + fn set_atime(&self, time: Duration); + fn mtime(&self) -> Duration; + fn set_mtime(&self, time: Duration); + fn fs(&self) -> Arc; fn resize(&self, _new_size: usize) -> Result<()> { Err(Error::new(Errno::EPERM)) } - fn metadata(&self) -> Metadata { - self.info.metadata() - } - - fn ino(&self) -> u64 { - self.info.ino() - } - fn type_(&self) -> InodeType { InodeType::File } - fn mode(&self) -> InodeMode { - self.info.mode() - } - - fn set_mode(&self, mode: InodeMode) { - self.info.set_mode(mode) - } - - fn atime(&self) -> Duration { - self.info.atime() - } - - fn set_atime(&self, time: Duration) { - self.info.set_atime(time) - } - - fn mtime(&self) -> Duration { - self.info.mtime() - } - - fn set_mtime(&self, time: Duration) { - self.info.set_mtime(time) - } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { let data = self.inner.data()?; let start = data.len().min(offset); @@ -109,12 +94,8 @@ impl Inode for ProcFile { Ok(()) } - fn fs(&self) -> Arc { - self.info.fs().upgrade().unwrap() - } - fn is_dentry_cacheable(&self) -> bool { - !self.info.is_volatile() + !self.common.is_volatile() } } diff --git a/services/aster-nix/src/fs/procfs/template/mod.rs b/services/aster-nix/src/fs/procfs/template/mod.rs index 3eb4e5163..7e573be4a 100644 --- a/services/aster-nix/src/fs/procfs/template/mod.rs +++ b/services/aster-nix/src/fs/procfs/template/mod.rs @@ -4,6 +4,7 @@ use core::time::Duration; use crate::fs::utils::{FileSystem, InodeMode, Metadata}; use crate::prelude::*; +use crate::process::{Gid, Uid}; use super::ProcFS; @@ -17,13 +18,13 @@ mod dir; mod file; mod sym; -struct ProcInodeInfo { +struct Common { metadata: RwLock, fs: Weak, is_volatile: bool, } -impl ProcInodeInfo { +impl Common { pub fn new(metadata: Metadata, fs: Weak, is_volatile: bool) -> Self { Self { metadata: RwLock::new(metadata), @@ -32,12 +33,12 @@ impl ProcInodeInfo { } } - pub fn fs(&self) -> &Weak { - &self.fs + pub fn fs(&self) -> Arc { + self.fs.upgrade().unwrap() } pub fn metadata(&self) -> Metadata { - self.metadata.read().clone() + *self.metadata.read() } pub fn ino(&self) -> u64 { @@ -64,12 +65,31 @@ impl ProcInodeInfo { self.metadata.write().mtime = time; } - pub fn mode(&self) -> InodeMode { - self.metadata.read().mode + pub fn mode(&self) -> Result { + Ok(self.metadata.read().mode) } - pub fn set_mode(&self, mode: InodeMode) { + pub fn set_mode(&self, mode: InodeMode) -> Result<()> { self.metadata.write().mode = mode; + Ok(()) + } + + pub fn owner(&self) -> Result { + Ok(self.metadata.read().uid) + } + + pub fn set_owner(&self, uid: Uid) -> Result<()> { + self.metadata.write().uid = uid; + Ok(()) + } + + pub fn group(&self) -> Result { + Ok(self.metadata.read().gid) + } + + pub fn set_group(&self, gid: Gid) -> Result<()> { + self.metadata.write().gid = gid; + Ok(()) } pub fn is_volatile(&self) -> bool { diff --git a/services/aster-nix/src/fs/procfs/template/sym.rs b/services/aster-nix/src/fs/procfs/template/sym.rs index c3a8acdaf..2c76d0d6c 100644 --- a/services/aster-nix/src/fs/procfs/template/sym.rs +++ b/services/aster-nix/src/fs/procfs/template/sym.rs @@ -1,77 +1,59 @@ // SPDX-License-Identifier: MPL-2.0 use core::time::Duration; +use inherit_methods_macro::inherit_methods; use crate::fs::utils::{FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata}; use crate::prelude::*; +use crate::process::{Gid, Uid}; -use super::{ProcFS, ProcInodeInfo}; +use super::{Common, ProcFS}; pub struct ProcSym { inner: S, - info: ProcInodeInfo, + common: Common, } impl ProcSym { pub fn new(sym: S, fs: Arc, is_volatile: bool) -> Arc { - let info = { + let common = { let procfs = fs.downcast_ref::().unwrap(); let metadata = Metadata::new_symlink( procfs.alloc_id(), InodeMode::from_bits_truncate(0o777), &fs.sb(), ); - ProcInodeInfo::new(metadata, Arc::downgrade(&fs), is_volatile) + Common::new(metadata, Arc::downgrade(&fs), is_volatile) }; - Arc::new(Self { inner: sym, info }) + Arc::new(Self { inner: sym, common }) } } +#[inherit_methods(from = "self.common")] impl Inode for ProcSym { - fn size(&self) -> usize { - self.info.size() - } + fn size(&self) -> usize; + fn metadata(&self) -> Metadata; + fn ino(&self) -> u64; + fn mode(&self) -> Result; + fn set_mode(&self, mode: InodeMode) -> Result<()>; + fn owner(&self) -> Result; + fn set_owner(&self, uid: Uid) -> Result<()>; + fn group(&self) -> Result; + fn set_group(&self, gid: Gid) -> Result<()>; + fn atime(&self) -> Duration; + fn set_atime(&self, time: Duration); + fn mtime(&self) -> Duration; + fn set_mtime(&self, time: Duration); + fn fs(&self) -> Arc; fn resize(&self, _new_size: usize) -> Result<()> { Err(Error::new(Errno::EPERM)) } - fn metadata(&self) -> Metadata { - self.info.metadata() - } - - fn ino(&self) -> u64 { - self.info.ino() - } - fn type_(&self) -> InodeType { InodeType::SymLink } - fn mode(&self) -> InodeMode { - self.info.mode() - } - - fn set_mode(&self, mode: InodeMode) { - self.info.set_mode(mode) - } - - fn atime(&self) -> Duration { - self.info.atime() - } - - fn set_atime(&self, time: Duration) { - self.info.set_atime(time) - } - - fn mtime(&self) -> Duration { - self.info.mtime() - } - - fn set_mtime(&self, time: Duration) { - self.info.set_mtime(time) - } - fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { Err(Error::new(Errno::EPERM)) } @@ -104,12 +86,8 @@ impl Inode for ProcSym { Ok(()) } - fn fs(&self) -> Arc { - self.info.fs().upgrade().unwrap() - } - fn is_dentry_cacheable(&self) -> bool { - !self.info.is_volatile() + !self.common.is_volatile() } } diff --git a/services/aster-nix/src/fs/ramfs/fs.rs b/services/aster-nix/src/fs/ramfs/fs.rs index f3c2df22a..708c60c51 100644 --- a/services/aster-nix/src/fs/ramfs/fs.rs +++ b/services/aster-nix/src/fs/ramfs/fs.rs @@ -17,6 +17,7 @@ use crate::fs::utils::{ }; use crate::prelude::*; use crate::process::signal::Poller; +use crate::process::{Gid, Uid}; use crate::vm::vmo::Vmo; /// A volatile file system whose data and metadata exists only in memory. @@ -537,12 +538,31 @@ impl Inode for RamInode { self.0.read().metadata.type_ } - fn mode(&self) -> InodeMode { - self.0.read().metadata.mode + fn mode(&self) -> Result { + Ok(self.0.read().metadata.mode) } - fn set_mode(&self, mode: InodeMode) { + fn set_mode(&self, mode: InodeMode) -> Result<()> { self.0.write().metadata.mode = mode; + Ok(()) + } + + fn owner(&self) -> Result { + Ok(self.0.read().metadata.uid) + } + + fn set_owner(&self, uid: Uid) -> Result<()> { + self.0.write().metadata.uid = uid; + Ok(()) + } + + fn group(&self) -> Result { + Ok(self.0.read().metadata.gid) + } + + fn set_group(&self, gid: Gid) -> Result<()> { + self.0.write().metadata.gid = gid; + Ok(()) } fn mknod( @@ -870,7 +890,7 @@ impl Inode for RamInode { } fn metadata(&self) -> Metadata { - self.0.read().metadata.clone() + self.0.read().metadata } fn sync(&self) -> Result<()> { diff --git a/services/aster-nix/src/fs/utils/dentry.rs b/services/aster-nix/src/fs/utils/dentry.rs index b58176ed3..cfa2f5539 100644 --- a/services/aster-nix/src/fs/utils/dentry.rs +++ b/services/aster-nix/src/fs/utils/dentry.rs @@ -2,10 +2,12 @@ use crate::fs::device::Device; use crate::prelude::*; +use crate::process::{Gid, Uid}; use alloc::string::String; use core::sync::atomic::{AtomicU32, Ordering}; use core::time::Duration; +use inherit_methods_macro::inherit_methods; use super::{FileSystem, Inode, InodeMode, InodeType, Metadata, MountNode, NAME_MAX}; @@ -215,7 +217,7 @@ impl Dentry { if self.inode.type_() != InodeType::Dir { return_errno!(Errno::ENOTDIR); } - if !self.inode.mode().is_executable() { + if !self.inode.mode()?.is_executable() { return_errno!(Errno::EACCES); } if name.len() > NAME_MAX { @@ -380,66 +382,6 @@ impl Dentry { Ok(child_mount) } - /// Get the filesystem the inode belongs to - pub fn fs(&self) -> Arc { - self.inode.fs() - } - - /// Flushes all changes made to data and metadata to the device. - pub fn sync(&self) -> Result<()> { - self.inode.sync() - } - - /// Get the inode metadata - pub fn inode_metadata(&self) -> Metadata { - self.inode.metadata() - } - - /// Get the inode type - pub fn inode_type(&self) -> InodeType { - self.inode.type_() - } - - /// Get the inode permission mode - pub fn inode_mode(&self) -> InodeMode { - self.inode.mode() - } - - /// Set the inode permission mode - pub fn set_inode_mode(&self, mode: InodeMode) { - self.inode.set_mode(mode) - } - - /// Gets the size of the inode - pub fn inode_size(&self) -> usize { - self.inode.size() - } - - /// Sets the size of the inode - pub fn set_inode_size(&self, new_size: usize) -> Result<()> { - self.inode.resize(new_size) - } - - /// Get the access timestamp - pub fn atime(&self) -> Duration { - self.inode.atime() - } - - /// Set the access timestamp - pub fn set_atime(&self, time: Duration) { - self.inode.set_atime(time) - } - - /// Get the modified timestamp - pub fn mtime(&self) -> Duration { - self.inode.mtime() - } - - /// Set the modified timestamp - pub fn set_mtime(&self, time: Duration) { - self.inode.set_mtime(time) - } - /// Get the absolute path. /// /// It will resolve the mountpoint automatically. @@ -469,6 +411,26 @@ impl Dentry { } } +#[inherit_methods(from = "self.inode")] +impl Dentry { + pub fn fs(&self) -> Arc; + pub fn sync(&self) -> Result<()>; + pub fn metadata(&self) -> Metadata; + pub fn type_(&self) -> InodeType; + pub fn mode(&self) -> Result; + pub fn set_mode(&self, mode: InodeMode) -> Result<()>; + pub fn size(&self) -> usize; + pub fn resize(&self, size: usize) -> Result<()>; + pub fn owner(&self) -> Result; + pub fn set_owner(&self, uid: Uid) -> Result<()>; + pub fn group(&self) -> Result; + pub fn set_group(&self, gid: Gid) -> Result<()>; + pub fn atime(&self) -> Duration; + pub fn set_atime(&self, time: Duration); + pub fn mtime(&self) -> Duration; + pub fn set_mtime(&self, time: Duration); +} + impl Debug for Dentry { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct("Dentry") diff --git a/services/aster-nix/src/fs/utils/inode.rs b/services/aster-nix/src/fs/utils/inode.rs index be81d2a42..921cfb2c6 100644 --- a/services/aster-nix/src/fs/utils/inode.rs +++ b/services/aster-nix/src/fs/utils/inode.rs @@ -9,6 +9,7 @@ use crate::events::IoEvents; use crate::fs::device::{Device, DeviceType}; use crate::prelude::*; use crate::process::signal::Poller; +use crate::process::{Gid, Uid}; use crate::vm::vmo::Vmo; #[repr(u32)] @@ -112,7 +113,7 @@ impl InodeMode { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct Metadata { pub dev: u64, pub ino: usize, @@ -125,8 +126,8 @@ pub struct Metadata { pub type_: InodeType, pub mode: InodeMode, pub nlinks: usize, - pub uid: usize, - pub gid: usize, + pub uid: Uid, + pub gid: Gid, pub rdev: u64, } @@ -144,8 +145,8 @@ impl Metadata { type_: InodeType::Dir, mode, nlinks: 2, - uid: 0, - gid: 0, + uid: Uid::new_root(), + gid: Gid::new_root(), rdev: 0, } } @@ -163,8 +164,8 @@ impl Metadata { type_: InodeType::File, mode, nlinks: 1, - uid: 0, - gid: 0, + uid: Uid::new_root(), + gid: Gid::new_root(), rdev: 0, } } @@ -182,8 +183,8 @@ impl Metadata { type_: InodeType::SymLink, mode, nlinks: 1, - uid: 0, - gid: 0, + uid: Uid::new_root(), + gid: Gid::new_root(), rdev: 0, } } @@ -200,8 +201,8 @@ impl Metadata { type_: InodeType::from(device.type_()), mode, nlinks: 1, - uid: 0, - gid: 0, + uid: Uid::new_root(), + gid: Gid::new_root(), rdev: device.id().into(), } } @@ -219,8 +220,8 @@ impl Metadata { type_: InodeType::Socket, mode, nlinks: 1, - uid: 0, - gid: 0, + uid: Uid::new_root(), + gid: Gid::new_root(), rdev: 0, } } @@ -237,9 +238,17 @@ pub trait Inode: Any + Sync + Send { fn type_(&self) -> InodeType; - fn mode(&self) -> InodeMode; + fn mode(&self) -> Result; - fn set_mode(&self, mode: InodeMode); + fn set_mode(&self, mode: InodeMode) -> Result<()>; + + fn owner(&self) -> Result; + + fn set_owner(&self, uid: Uid) -> Result<()>; + + fn group(&self) -> Result; + + fn set_group(&self, gid: Gid) -> Result<()>; fn atime(&self) -> Duration; diff --git a/services/aster-nix/src/fs/utils/mount.rs b/services/aster-nix/src/fs/utils/mount.rs index 6cef1b12f..64562b816 100644 --- a/services/aster-nix/src/fs/utils/mount.rs +++ b/services/aster-nix/src/fs/utils/mount.rs @@ -59,7 +59,7 @@ impl MountNode { if !Arc::ptr_eq(&mountpoint.mount_node(), &self.this()) { return_errno_with_message!(Errno::EINVAL, "mountpoint not belongs to this"); } - if mountpoint.inode_type() != InodeType::Dir { + if mountpoint.type_() != InodeType::Dir { return_errno!(Errno::ENOTDIR); } diff --git a/services/aster-nix/src/net/socket/unix/stream/socket.rs b/services/aster-nix/src/net/socket/unix/stream/socket.rs index 1ecc7a950..788bf18d7 100644 --- a/services/aster-nix/src/net/socket/unix/stream/socket.rs +++ b/services/aster-nix/src/net/socket/unix/stream/socket.rs @@ -290,11 +290,11 @@ fn lookup_socket_file(path: &str) -> Result> { fs.lookup(&fs_path)? }; - if dentry.inode_type() != InodeType::Socket { + if dentry.type_() != InodeType::Socket { return_errno_with_message!(Errno::ENOTSOCK, "not a socket file") } - if !dentry.inode_mode().is_readable() || !dentry.inode_mode().is_writable() { + if !dentry.mode()?.is_readable() || !dentry.mode()?.is_writable() { return_errno_with_message!(Errno::EACCES, "the socket cannot be read or written") } Ok(dentry) diff --git a/services/aster-nix/src/process/program_loader/mod.rs b/services/aster-nix/src/process/program_loader/mod.rs index e779e4837..bc8b26b23 100644 --- a/services/aster-nix/src/process/program_loader/mod.rs +++ b/services/aster-nix/src/process/program_loader/mod.rs @@ -96,15 +96,15 @@ pub fn load_program_to_vm( } pub fn check_executable_file(dentry: &Arc) -> Result<()> { - if dentry.inode_type().is_directory() { + if dentry.type_().is_directory() { return_errno_with_message!(Errno::EISDIR, "the file is a directory"); } - if !dentry.inode_type().is_reguler_file() { + if !dentry.type_().is_reguler_file() { return_errno_with_message!(Errno::EACCES, "the dentry is not a regular file"); } - if !dentry.inode_mode().is_executable() { + if !dentry.mode()?.is_executable() { return_errno_with_message!(Errno::EACCES, "the dentry is not executable"); } diff --git a/services/aster-nix/src/syscall/chdir.rs b/services/aster-nix/src/syscall/chdir.rs index 8bf5025e6..9275c75b7 100644 --- a/services/aster-nix/src/syscall/chdir.rs +++ b/services/aster-nix/src/syscall/chdir.rs @@ -26,7 +26,7 @@ pub fn sys_chdir(pathname_addr: Vaddr) -> Result { let fs_path = FsPath::try_from(pathname.as_ref())?; fs.lookup(&fs_path)? }; - if dentry.inode_type() != InodeType::Dir { + if dentry.type_() != InodeType::Dir { return_errno_with_message!(Errno::ENOTDIR, "must be directory"); } fs.set_cwd(dentry); @@ -46,7 +46,7 @@ pub fn sys_fchdir(fd: FileDescripter) -> Result { .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; inode_handle.dentry().clone() }; - if dentry.inode_type() != InodeType::Dir { + if dentry.type_() != InodeType::Dir { return_errno_with_message!(Errno::ENOTDIR, "must be directory"); } current.fs().write().set_cwd(dentry); diff --git a/services/aster-nix/src/syscall/chmod.rs b/services/aster-nix/src/syscall/chmod.rs index e26f39818..9646b17e3 100644 --- a/services/aster-nix/src/syscall/chmod.rs +++ b/services/aster-nix/src/syscall/chmod.rs @@ -3,7 +3,6 @@ use crate::fs::{ file_table::FileDescripter, fs_resolver::{FsPath, AT_FDCWD}, - inode_handle::InodeHandle, utils::{InodeMode, PATH_MAX}, }; use crate::log_syscall_entry; @@ -20,11 +19,7 @@ pub fn sys_fchmod(fd: FileDescripter, mode: u16) -> Result { let current = current!(); let file_table = current.file_table().lock(); let file = file_table.get_file(fd)?; - let inode_handle = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; - let dentry = inode_handle.dentry(); - dentry.set_inode_mode(InodeMode::from_bits_truncate(mode)); + file.set_mode(InodeMode::from_bits_truncate(mode))?; Ok(SyscallReturn::Return(0)) } @@ -52,6 +47,6 @@ pub fn sys_fchmodat( let fs_path = FsPath::new(dirfd, path.as_ref())?; current.fs().read().lookup(&fs_path)? }; - dentry.set_inode_mode(InodeMode::from_bits_truncate(mode)); + dentry.set_mode(InodeMode::from_bits_truncate(mode))?; Ok(SyscallReturn::Return(0)) } diff --git a/services/aster-nix/src/syscall/chown.rs b/services/aster-nix/src/syscall/chown.rs new file mode 100644 index 000000000..1c861094b --- /dev/null +++ b/services/aster-nix/src/syscall/chown.rs @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MPL-2.0 + +use crate::fs::{ + file_table::FileDescripter, + fs_resolver::{FsPath, AT_FDCWD}, + utils::PATH_MAX, +}; +use crate::log_syscall_entry; +use crate::prelude::*; +use crate::process::{Gid, Uid}; +use crate::util::read_cstring_from_user; + +use super::SyscallReturn; +use super::{SYS_FCHOWN, SYS_FCHOWNAT}; + +pub fn sys_fchown(fd: FileDescripter, uid: i32, gid: i32) -> Result { + log_syscall_entry!(SYS_FCHOWN); + debug!("fd = {}, uid = {}, gid = {}", fd, uid, gid); + + let uid = to_optional_id(uid, Uid::new)?; + let gid = to_optional_id(gid, Gid::new)?; + if uid.is_none() && gid.is_none() { + return Ok(SyscallReturn::Return(0)); + } + + let current = current!(); + let file_table = current.file_table().lock(); + let file = file_table.get_file(fd)?; + if let Some(uid) = uid { + file.set_owner(uid)?; + } + if let Some(gid) = gid { + file.set_group(gid)?; + } + Ok(SyscallReturn::Return(0)) +} + +pub fn sys_chown(path_ptr: Vaddr, uid: i32, gid: i32) -> Result { + self::sys_fchownat(AT_FDCWD, path_ptr, uid, gid, 0) +} + +pub fn sys_lchown(path_ptr: Vaddr, uid: i32, gid: i32) -> Result { + self::sys_fchownat( + AT_FDCWD, + path_ptr, + uid, + gid, + ChownFlags::AT_SYMLINK_NOFOLLOW.bits(), + ) +} + +pub fn sys_fchownat( + dirfd: FileDescripter, + path_ptr: Vaddr, + uid: i32, + gid: i32, + flags: u32, +) -> Result { + log_syscall_entry!(SYS_FCHOWNAT); + let path = read_cstring_from_user(path_ptr, PATH_MAX)?; + let flags = ChownFlags::from_bits(flags) + .ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid flags"))?; + debug!( + "dirfd = {}, path = {:?}, uid = {}, gid = {}, flags = {:?}", + dirfd, path, uid, gid, flags + ); + + if path.is_empty() { + if !flags.contains(ChownFlags::AT_EMPTY_PATH) { + return_errno_with_message!(Errno::ENOENT, "path is empty"); + } + return self::sys_fchown(dirfd, uid, gid); + } + + let uid = to_optional_id(uid, Uid::new)?; + let gid = to_optional_id(gid, Gid::new)?; + if uid.is_none() && gid.is_none() { + return Ok(SyscallReturn::Return(0)); + } + + let current = current!(); + let dentry = { + let path = path.to_string_lossy(); + let fs_path = FsPath::new(dirfd, path.as_ref())?; + let fs = current.fs().read(); + if flags.contains(ChownFlags::AT_SYMLINK_NOFOLLOW) { + fs.lookup_no_follow(&fs_path)? + } else { + fs.lookup(&fs_path)? + } + }; + if let Some(uid) = uid { + dentry.set_owner(uid)?; + } + if let Some(gid) = gid { + dentry.set_group(gid)?; + } + Ok(SyscallReturn::Return(0)) +} + +fn to_optional_id(id: i32, f: impl Fn(u32) -> T) -> Result> { + let id = if id >= 0 { + Some(f(id as u32)) + } else if id == -1 { + // If the owner or group is specified as -1, then that ID is not changed. + None + } else { + return_errno!(Errno::EINVAL); + }; + + Ok(id) +} + +bitflags! { + struct ChownFlags: u32 { + const AT_SYMLINK_NOFOLLOW = 1 << 8; + const AT_EMPTY_PATH = 1 << 12; + } +} diff --git a/services/aster-nix/src/syscall/execve.rs b/services/aster-nix/src/syscall/execve.rs index b60968dcb..4ec5159d8 100644 --- a/services/aster-nix/src/syscall/execve.rs +++ b/services/aster-nix/src/syscall/execve.rs @@ -10,9 +10,7 @@ use crate::fs::utils::{Dentry, InodeType}; use crate::log_syscall_entry; use crate::prelude::*; use crate::process::posix_thread::{PosixThreadExt, ThreadName}; -use crate::process::{ - check_executable_file, credentials_mut, load_program_to_vm, Credentials, Gid, Uid, -}; +use crate::process::{check_executable_file, credentials_mut, load_program_to_vm, Credentials}; use crate::syscall::{SYS_EXECVE, SYS_EXECVEAT}; use crate::util::{read_cstring_from_user, read_val_from_user}; @@ -65,7 +63,7 @@ fn lookup_executable_file( let fs_path = FsPath::new(dfd, &filename)?; if flags.contains(OpenFlags::AT_SYMLINK_NOFOLLOW) { let dentry = fs_resolver.lookup_no_follow(&fs_path)?; - if dentry.inode_type() == InodeType::SymLink { + if dentry.type_() == InodeType::SymLink { return_errno_with_message!(Errno::ELOOP, "the executable file is a symlink"); } Ok(dentry) @@ -110,8 +108,8 @@ fn do_execve( debug!("load elf in execve succeeds"); let credentials = credentials_mut(); - set_uid_from_elf(&credentials, &elf_file); - set_gid_from_elf(&credentials, &elf_file); + set_uid_from_elf(&credentials, &elf_file)?; + set_gid_from_elf(&credentials, &elf_file)?; // set executable path current.set_executable_path(new_executable_path); @@ -169,23 +167,25 @@ fn read_cstring_vec( } /// Sets uid for credentials as the same of uid of elf file if elf file has `set_uid` bit. -fn set_uid_from_elf(credentials: &Credentials, elf_file: &Arc) { - if elf_file.inode_mode().has_set_uid() { - let uid = Uid::new(elf_file.inode_metadata().uid as u32); +fn set_uid_from_elf(credentials: &Credentials, elf_file: &Arc) -> Result<()> { + if elf_file.mode()?.has_set_uid() { + let uid = elf_file.owner()?; credentials.set_euid(uid); } // No matter whether the elf_file has `set_uid` bit, suid should be reset. credentials.reset_suid(); + Ok(()) } /// Sets gid for credentials as the same of gid of elf file if elf file has `set_gid` bit. -fn set_gid_from_elf(credentials: &Credentials, elf_file: &Arc) { - if elf_file.inode_mode().has_set_gid() { - let gid = Gid::new(elf_file.inode_metadata().gid as u32); +fn set_gid_from_elf(credentials: &Credentials, elf_file: &Arc) -> Result<()> { + if elf_file.mode()?.has_set_gid() { + let gid = elf_file.group()?; credentials.set_egid(gid); } // No matter whether the the elf file has `set_gid` bit, sgid should be reset. credentials.reset_sgid(); + Ok(()) } diff --git a/services/aster-nix/src/syscall/getdents64.rs b/services/aster-nix/src/syscall/getdents64.rs index e8842b8c9..e9f365b7d 100644 --- a/services/aster-nix/src/syscall/getdents64.rs +++ b/services/aster-nix/src/syscall/getdents64.rs @@ -32,7 +32,7 @@ pub fn sys_getdents64( let inode_handle = file .downcast_ref::() .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; - if inode_handle.dentry().inode_type() != InodeType::Dir { + if inode_handle.dentry().type_() != InodeType::Dir { return_errno!(Errno::ENOTDIR); } let mut buffer = vec![0u8; buf_len]; diff --git a/services/aster-nix/src/syscall/mod.rs b/services/aster-nix/src/syscall/mod.rs index 54e88ef76..b081ab211 100644 --- a/services/aster-nix/src/syscall/mod.rs +++ b/services/aster-nix/src/syscall/mod.rs @@ -8,6 +8,7 @@ use crate::syscall::arch_prctl::sys_arch_prctl; use crate::syscall::brk::sys_brk; use crate::syscall::chdir::{sys_chdir, sys_fchdir}; use crate::syscall::chmod::{sys_chmod, sys_fchmod, sys_fchmodat}; +use crate::syscall::chown::{sys_chown, sys_fchown, sys_fchownat, sys_lchown}; use crate::syscall::clock_gettime::sys_clock_gettime; use crate::syscall::clock_nanosleep::sys_clock_nanosleep; use crate::syscall::clone::sys_clone; @@ -115,6 +116,7 @@ mod bind; mod brk; mod chdir; mod chmod; +mod chown; mod clock_gettime; mod clock_nanosleep; mod clone; @@ -306,6 +308,9 @@ define_syscall_nums!( SYS_READLINK = 89, SYS_CHMOD = 90, SYS_FCHMOD = 91, + SYS_CHOWN = 92, + SYS_FCHOWN = 93, + SYS_LCHOWN = 94, SYS_UMASK = 95, SYS_GETTIMEOFDAY = 96, SYS_GETUID = 102, @@ -350,6 +355,7 @@ define_syscall_nums!( SYS_WAITID = 247, SYS_OPENAT = 257, SYS_MKDIRAT = 258, + SYS_FCHOWNAT = 260, SYS_FSTATAT = 262, SYS_UNLINKAT = 263, SYS_RENAMEAT = 264, @@ -486,6 +492,9 @@ pub fn syscall_dispatch( 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_CHOWN => syscall_handler!(3, sys_chown, args), + SYS_FCHOWN => syscall_handler!(3, sys_fchown, args), + SYS_LCHOWN => syscall_handler!(3, sys_lchown, args), SYS_UMASK => syscall_handler!(1, sys_umask, args), SYS_GETTIMEOFDAY => syscall_handler!(1, sys_gettimeofday, args), SYS_GETUID => syscall_handler!(0, sys_getuid), @@ -530,6 +539,7 @@ pub fn syscall_dispatch( SYS_WAITID => syscall_handler!(5, sys_waitid, args), SYS_OPENAT => syscall_handler!(4, sys_openat, args), SYS_MKDIRAT => syscall_handler!(3, sys_mkdirat, args), + SYS_FCHOWNAT => syscall_handler!(5, sys_fchownat, args), SYS_FSTATAT => syscall_handler!(4, sys_fstatat, args), SYS_UNLINKAT => syscall_handler!(3, sys_unlinkat, args), SYS_RENAMEAT => syscall_handler!(4, sys_renameat, args), diff --git a/services/aster-nix/src/syscall/rename.rs b/services/aster-nix/src/syscall/rename.rs index c3398a3ab..eb8e2d879 100644 --- a/services/aster-nix/src/syscall/rename.rs +++ b/services/aster-nix/src/syscall/rename.rs @@ -45,7 +45,7 @@ pub fn sys_renameat( if new_pathname.is_empty() { return_errno_with_message!(Errno::ENOENT, "newpath is empty"); } - if new_pathname.ends_with('/') && old_dentry.inode_type() != InodeType::Dir { + if new_pathname.ends_with('/') && old_dentry.type_() != InodeType::Dir { return_errno_with_message!(Errno::ENOTDIR, "oldpath is not dir"); } let new_fs_path = FsPath::new(new_dirfd, new_pathname.as_ref().trim_end_matches('/'))?; diff --git a/services/aster-nix/src/syscall/stat.rs b/services/aster-nix/src/syscall/stat.rs index e2fc86fef..4a0d668bd 100644 --- a/services/aster-nix/src/syscall/stat.rs +++ b/services/aster-nix/src/syscall/stat.rs @@ -67,7 +67,7 @@ pub fn sys_fstatat( fs.lookup(&fs_path)? } }; - let stat = Stat::from(dentry.inode_metadata()); + let stat = Stat::from(dentry.metadata()); write_val_to_user(stat_buf_ptr, &stat)?; Ok(SyscallReturn::Return(0)) } @@ -121,8 +121,8 @@ impl From for Stat { st_ino: info.ino, st_nlink: info.nlinks, st_mode: info.type_ as u32 | info.mode.bits() as u32, - st_uid: info.uid as u32, - st_gid: info.gid as u32, + st_uid: info.uid.as_u32(), + st_gid: info.gid.as_u32(), __pad0: 0, st_rdev: info.rdev, st_size: info.size as isize, diff --git a/services/aster-nix/src/syscall/truncate.rs b/services/aster-nix/src/syscall/truncate.rs index 49639099b..ec2c60c02 100644 --- a/services/aster-nix/src/syscall/truncate.rs +++ b/services/aster-nix/src/syscall/truncate.rs @@ -42,7 +42,7 @@ pub fn sys_truncate(path_ptr: Vaddr, len: isize) -> Result { let fs_path = FsPath::new(AT_FDCWD, path.as_ref())?; current.fs().read().lookup(&fs_path)? }; - dentry.set_inode_size(len as usize)?; + dentry.resize(len as usize)?; Ok(SyscallReturn::Return(0)) }