From ddca4fb2fc443b538d31ee3e12304c4d8a51117e Mon Sep 17 00:00:00 2001 From: LI Qing Date: Tue, 28 Nov 2023 12:17:42 +0800 Subject: [PATCH] Enable some fs system call test cases --- .github/workflows/integration_test.yml | 8 + Makefile | 2 + regression/syscall_test/Makefile | 7 +- .../syscall_test/blocklists/getdents_test | 11 ++ regression/syscall_test/blocklists/link_test | 1 + regression/syscall_test/blocklists/lseek_test | 6 + regression/syscall_test/blocklists/mkdir_test | 1 + .../syscall_test/blocklists/open_create_test | 9 ++ .../syscall_test/blocklists/rename_test | 7 + regression/syscall_test/blocklists/stat_test | 4 + .../syscall_test/blocklists/symlink_test | 7 + regression/syscall_test/blocklists/sync_test | 3 + .../syscall_test/blocklists/unlink_test | 4 + regression/syscall_test/blocklists/write_test | 3 + regression/syscall_test/run_syscall_test.sh | 4 + services/libs/aster-std/src/fs/fs_resolver.rs | 5 +- services/libs/aster-std/src/fs/ramfs/fs.rs | 142 +++++++++++------- .../src/fs/utils/file_creation_mask.rs | 2 +- .../libs/aster-std/src/syscall/constants.rs | 2 +- services/libs/aster-std/src/syscall/link.rs | 7 +- services/libs/aster-std/src/syscall/mkdir.rs | 6 +- services/libs/aster-std/src/syscall/open.rs | 3 +- services/libs/aster-std/src/syscall/rmdir.rs | 16 +- services/libs/aster-std/src/syscall/unlink.rs | 2 +- services/libs/aster-std/src/syscall/write.rs | 4 + 25 files changed, 197 insertions(+), 69 deletions(-) create mode 100644 regression/syscall_test/blocklists/getdents_test create mode 100644 regression/syscall_test/blocklists/link_test create mode 100644 regression/syscall_test/blocklists/lseek_test create mode 100644 regression/syscall_test/blocklists/mkdir_test create mode 100644 regression/syscall_test/blocklists/open_create_test create mode 100644 regression/syscall_test/blocklists/rename_test create mode 100644 regression/syscall_test/blocklists/stat_test create mode 100644 regression/syscall_test/blocklists/symlink_test create mode 100644 regression/syscall_test/blocklists/sync_test create mode 100644 regression/syscall_test/blocklists/unlink_test create mode 100644 regression/syscall_test/blocklists/write_test diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 962999bf..86fd8820 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -35,3 +35,11 @@ jobs: - name: Syscall Test (MicroVM) id: syscall_test_microvm run: make run AUTO_TEST=syscall ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1 + + - name: Syscall Test at Ext2 (Linux Boot Protocol) + id: syscall_test_at_ext2_linux + run: make run AUTO_TEST=syscall SYSCALL_TEST_DIR=/ext2 ENABLE_KVM=0 BOOT_PROTOCOL=linux RELEASE_MODE=1 + + - name: Syscall Test at Ext2 (MicroVM) + id: syscall_test_at_ext2_microvm + run: make run AUTO_TEST=syscall SYSCALL_TEST_DIR=/ext2 ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1 diff --git a/Makefile b/Makefile index 485b2646..b29c8e92 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ KTEST ?= 0 KTEST_CRATES ?= all KTEST_WHITELIST ?= SKIP_GRUB_MENU ?= 1 +SYSCALL_TEST_DIR ?= /tmp RELEASE_MODE ?= 0 # End of setting up Make varaiables @@ -20,6 +21,7 @@ KERNEL_CMDLINE += ktest.whitelist="$(KTEST_WHITELIST)" INIT_CMDLINE := sh -l ifeq ($(AUTO_TEST), syscall) BUILD_SYSCALL_TEST := 1 +KERNEL_CMDLINE += SYSCALL_TEST_DIR=$(SYSCALL_TEST_DIR) INIT_CMDLINE += /opt/syscall_test/run_syscall_test.sh endif ifeq ($(AUTO_TEST), regression) diff --git a/regression/syscall_test/Makefile b/regression/syscall_test/Makefile index d78412f1..acca28e1 100644 --- a/regression/syscall_test/Makefile +++ b/regression/syscall_test/Makefile @@ -1,4 +1,7 @@ -TESTS ?= open_test read_test statfs_test chmod_test pty_test uidgid_test vdso_clock_gettime_test +TESTS ?= chmod_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 uidgid_test unlink_test \ + vdso_clock_gettime_test write_test MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH))) @@ -46,4 +49,4 @@ $(TARGET_DIR): $(RUN_BASH) $(BLOCK_LIST) @cp -f $(RUN_BASH) $@ clean: - @rm -rf $(TARGET_DIR) \ No newline at end of file + @rm -rf $(TARGET_DIR) diff --git a/regression/syscall_test/blocklists/getdents_test b/regression/syscall_test/blocklists/getdents_test new file mode 100644 index 00000000..cd33c269 --- /dev/null +++ b/regression/syscall_test/blocklists/getdents_test @@ -0,0 +1,11 @@ +GetdentsTest/0.VerifyEntries +GetdentsTest/0.VerifyPadding +GetdentsTest/0.SmallDir +GetdentsTest/0.LargeDir +GetdentsTest/0.PartialBuffer +GetdentsTest/0.ProcSelfFd +GetdentsTest/0.NotDir +GetdentsTest/0.SeekResetsCursor +GetdentsTest/0.Issue128ProcSeekEnd +GetdentsTest/1.PartialBuffer +GetdentsTest/1.ProcSelfFd \ No newline at end of file diff --git a/regression/syscall_test/blocklists/link_test b/regression/syscall_test/blocklists/link_test new file mode 100644 index 00000000..d468f204 --- /dev/null +++ b/regression/syscall_test/blocklists/link_test @@ -0,0 +1 @@ +LinkTest.PermissionDenied \ No newline at end of file diff --git a/regression/syscall_test/blocklists/lseek_test b/regression/syscall_test/blocklists/lseek_test new file mode 100644 index 00000000..73841810 --- /dev/null +++ b/regression/syscall_test/blocklists/lseek_test @@ -0,0 +1,6 @@ +LseekTest.Overflow +LseekTest.ProcFile +LseekTest.SysDir +LseekTest.SeekCurrentDir +LseekTest.ProcStatTwice +LseekTest.EtcPasswdDup \ No newline at end of file diff --git a/regression/syscall_test/blocklists/mkdir_test b/regression/syscall_test/blocklists/mkdir_test new file mode 100644 index 00000000..d17e875f --- /dev/null +++ b/regression/syscall_test/blocklists/mkdir_test @@ -0,0 +1 @@ +MkdirTest.FailsOnDirWithoutWritePerms \ No newline at end of file diff --git a/regression/syscall_test/blocklists/open_create_test b/regression/syscall_test/blocklists/open_create_test new file mode 100644 index 00000000..d2dc2462 --- /dev/null +++ b/regression/syscall_test/blocklists/open_create_test @@ -0,0 +1,9 @@ +CreateTest.HonorsUmask_NoRandomSave +CreateTest.CreatWithOTrunc +CreateTest.CreatDirWithOTruncAndReadOnly +CreateTest.CreateFailsOnUnpermittedDir +CreateTest.CreateFailsOnDirWithoutWritePerms +CreateTest.ChmodReadToWriteBetweenOpens_NoRandomSave +CreateTest.ChmodWriteToReadBetweenOpens_NoRandomSave +CreateTest.CreateWithReadFlagNotAllowedByMode_NoRandomSave +CreateTest.CreateWithWriteFlagNotAllowedByMode_NoRandomSave \ No newline at end of file diff --git a/regression/syscall_test/blocklists/rename_test b/regression/syscall_test/blocklists/rename_test new file mode 100644 index 00000000..62e4f5bc --- /dev/null +++ b/regression/syscall_test/blocklists/rename_test @@ -0,0 +1,7 @@ +RenameTest.RootToAnything +RenameTest.AnythingToRoot +RenameTest.FailsWithDots +RenameTest.FailsWhenOldParentNotWritable +RenameTest.FailsWhenNewParentNotWritable +RenameTest.OverwriteFailsWhenNewParentNotWritable +RenameTest.FileDoesNotExistWhenNewParentNotExecutable \ No newline at end of file diff --git a/regression/syscall_test/blocklists/stat_test b/regression/syscall_test/blocklists/stat_test new file mode 100644 index 00000000..b5f9f070 --- /dev/null +++ b/regression/syscall_test/blocklists/stat_test @@ -0,0 +1,4 @@ +StatTest.FstatatSymlinkDirWithTrailingSlash +StatTest.FstatatSymlinkDirWithTrailingSlashSameInode +StatTest.LstatSymlinkDir +SimpleStatTest.AnonDeviceAllocatesUniqueInodesAcrossSaveRestore \ No newline at end of file diff --git a/regression/syscall_test/blocklists/symlink_test b/regression/syscall_test/blocklists/symlink_test new file mode 100644 index 00000000..daffcf7a --- /dev/null +++ b/regression/syscall_test/blocklists/symlink_test @@ -0,0 +1,7 @@ +SymlinkTest.CannotCreateSymlinkInReadOnlyDir +SymlinkTest.PwriteToSymlink +SymlinkTest.SymlinkAtDegradedPermissions_NoRandomSave +SymlinkTest.ReadlinkAtDegradedPermissions_NoRandomSave +SymlinkTest.FollowUpdatesATime +AbsAndRelTarget/ParamSymlinkTest.CreatLinkCreatesTarget/0 +AbsAndRelTarget/ParamSymlinkTest.CreatLinkCreatesTarget/1 \ No newline at end of file diff --git a/regression/syscall_test/blocklists/sync_test b/regression/syscall_test/blocklists/sync_test new file mode 100644 index 00000000..ec588c30 --- /dev/null +++ b/regression/syscall_test/blocklists/sync_test @@ -0,0 +1,3 @@ +SyncTest.SyncFileSytem +SyncTest.SyncFromPipe +SyncTest.CannotSyncFileSytemAtBadFd \ No newline at end of file diff --git a/regression/syscall_test/blocklists/unlink_test b/regression/syscall_test/blocklists/unlink_test new file mode 100644 index 00000000..04b07ef1 --- /dev/null +++ b/regression/syscall_test/blocklists/unlink_test @@ -0,0 +1,4 @@ +UnlinkTest.AtDirDegradedPermissions_NoRandomSave +UnlinkTest.ParentDegradedPermissions +UnlinkTest.AtBad +UnlinkTest.TooLongName \ No newline at end of file diff --git a/regression/syscall_test/blocklists/write_test b/regression/syscall_test/blocklists/write_test new file mode 100644 index 00000000..0b442486 --- /dev/null +++ b/regression/syscall_test/blocklists/write_test @@ -0,0 +1,3 @@ +WriteTest.WriteNoExceedsRLimit +WriteTest.WriteExceedsRLimit +WriteTest.PwriteNoChangeOffset \ No newline at end of file diff --git a/regression/syscall_test/run_syscall_test.sh b/regression/syscall_test/run_syscall_test.sh index 449fb3cf..d66c8562 100755 --- a/regression/syscall_test/run_syscall_test.sh +++ b/regression/syscall_test/run_syscall_test.sh @@ -1,6 +1,7 @@ #!/bin/sh SCRIPT_DIR=$(dirname "$0") +TEST_TMP_DIR=${SYSCALL_TEST_DIR:-/tmp} TEST_BIN_DIR=$SCRIPT_DIR/tests BLOCKLIST_DIR=$SCRIPT_DIR/blocklists FAIL_CASES=$SCRIPT_DIR/fail_cases @@ -24,8 +25,11 @@ get_blocklist_subtests(){ run_one_test(){ echo -e "Run Test Case: $1" + # The gvisor test framework utilizes the "TEST_TMPDIR" environment variable to dictate the directory's location. + export TEST_TMPDIR=$TEST_TMP_DIR ret=0 if [ -f $TEST_BIN_DIR/$1 ]; then + rm -rf $TEST_TMP_DIR/* get_blocklist_subtests $1 $TEST_BIN_DIR/$1 --gtest_filter=-$BLOCK ret=$? diff --git a/services/libs/aster-std/src/fs/fs_resolver.rs b/services/libs/aster-std/src/fs/fs_resolver.rs index 50aaf556..776eec7d 100644 --- a/services/libs/aster-std/src/fs/fs_resolver.rs +++ b/services/libs/aster-std/src/fs/fs_resolver.rs @@ -59,11 +59,14 @@ impl FsResolver { let access_mode = AccessMode::from_u32(flags)?; let inode_mode = InodeMode::from_bits_truncate(mode); - let follow_tail_link = !creation_flags.contains(CreationFlags::O_NOFOLLOW); + let follow_tail_link = !(creation_flags.contains(CreationFlags::O_NOFOLLOW) + || creation_flags.contains(CreationFlags::O_CREAT) + && creation_flags.contains(CreationFlags::O_EXCL)); let dentry = match self.lookup_inner(path, follow_tail_link) { Ok(dentry) => { let inode = dentry.inode(); if inode.type_() == InodeType::SymLink + && creation_flags.contains(CreationFlags::O_NOFOLLOW) && !status_flags.contains(StatusFlags::O_PATH) { return_errno_with_message!(Errno::ELOOP, "file is a symlink"); diff --git a/services/libs/aster-std/src/fs/ramfs/fs.rs b/services/libs/aster-std/src/fs/ramfs/fs.rs index efdc601c..8a2f17ca 100644 --- a/services/libs/aster-std/src/fs/ramfs/fs.rs +++ b/services/libs/aster-std/src/fs/ramfs/fs.rs @@ -621,15 +621,12 @@ impl Inode for RamInode { return_errno_with_message!(Errno::EPERM, "old is a dir"); } let mut self_inode = self.0.write(); - if self_inode.inner.as_direntry().unwrap().contains_entry(name) { + let self_dir = self_inode.inner.as_direntry_mut().unwrap(); + if self_dir.contains_entry(name) { return_errno_with_message!(Errno::EEXIST, "entry exist"); } - self_inode - .inner - .as_direntry_mut() - .unwrap() - .append_entry(name, old.0.read().this.upgrade().unwrap()); + self_dir.append_entry(name, old.0.read().this.upgrade().unwrap()); self_inode.inc_size(); drop(self_inode); old.0.write().inc_nlinks(); @@ -660,8 +657,11 @@ impl Inode for RamInode { if self.0.read().metadata.type_ != InodeType::Dir { return_errno_with_message!(Errno::ENOTDIR, "self is not dir"); } - if name == "." || name == ".." { - return_errno_with_message!(Errno::EISDIR, "rmdir on . or .."); + if name == "." { + return_errno_with_message!(Errno::EINVAL, "rmdir on ."); + } + if name == ".." { + return_errno_with_message!(Errno::ENOTEMPTY, "rmdir on .."); } let mut self_inode = self.0.write(); let self_dir = self_inode.inner.as_direntry_mut().unwrap(); @@ -724,65 +724,101 @@ impl Inode for RamInode { if new_name == "." || new_name == ".." { return_errno_with_message!(Errno::EISDIR, "new_name is . or .."); } - let src_inode = self.lookup(old_name)?; - if src_inode.metadata().ino == target.metadata().ino { - return_errno_with_message!(Errno::EINVAL, "target is a descendant of old"); - } - if let Ok(dst_inode) = target.lookup(new_name) { - if src_inode.metadata().ino == dst_inode.metadata().ino { - return Ok(()); - } - match (src_inode.metadata().type_, dst_inode.metadata().type_) { - (InodeType::Dir, InodeType::Dir) => { - let dst_inode = dst_inode.downcast_ref::().unwrap(); - if !dst_inode - .0 - .read() - .inner - .as_direntry() - .unwrap() - .is_empty_children() - { - return_errno_with_message!(Errno::ENOTEMPTY, "dir not empty"); + + // Perform necessary checks to ensure that `dst_inode` can be replaced by `src_inode`. + let check_replace_inode = + |src_inode: &Arc, dst_inode: &Arc| -> Result<()> { + if src_inode.metadata().ino == dst_inode.metadata().ino { + return Ok(()); + } + + match (src_inode.metadata().type_, dst_inode.metadata().type_) { + (InodeType::Dir, InodeType::Dir) => { + if !dst_inode + .0 + .read() + .inner + .as_direntry() + .unwrap() + .is_empty_children() + { + return_errno_with_message!(Errno::ENOTEMPTY, "dir not empty"); + } } + (InodeType::Dir, _) => { + return_errno_with_message!(Errno::ENOTDIR, "old is not dir"); + } + (_, InodeType::Dir) => { + return_errno_with_message!(Errno::EISDIR, "new is dir"); + } + _ => {} } - (InodeType::Dir, _) => { - return_errno_with_message!(Errno::ENOTDIR, "old is not dir"); - } - (_, InodeType::Dir) => { - return_errno_with_message!(Errno::EISDIR, "new is dir"); - } - _ => {} - } - } + Ok(()) + }; + + // Rename in the same directory if self.metadata().ino == target.metadata().ino { let mut self_inode = self.0.write(); let self_dir = self_inode.inner.as_direntry_mut().unwrap(); - let (idx, inode) = self_dir + let (src_idx, src_inode) = self_dir .get_entry(old_name) .ok_or(Error::new(Errno::ENOENT))?; - self_dir.substitute_entry(idx, (CStr256::from(new_name), inode)); - } else { + let is_dir = src_inode.0.read().metadata.type_ == InodeType::Dir; + + if let Some((dst_idx, dst_inode)) = self_dir.get_entry(new_name) { + check_replace_inode(&src_inode, &dst_inode)?; + self_dir.remove_entry(dst_idx); + self_dir.substitute_entry(src_idx, (CStr256::from(new_name), src_inode.clone())); + self_inode.dec_size(); + if is_dir { + self_inode.dec_nlinks(); + } + } else { + self_dir.substitute_entry(src_idx, (CStr256::from(new_name), src_inode.clone())); + } + } + // Or rename across different directories + else { let (mut self_inode, mut target_inode) = write_lock_two_inodes(self, target); + let self_inode_arc = self_inode.this.upgrade().unwrap(); + let target_inode_arc = target_inode.this.upgrade().unwrap(); let self_dir = self_inode.inner.as_direntry_mut().unwrap(); - let (idx, src_inode) = self_dir + let (src_idx, src_inode) = self_dir .get_entry(old_name) .ok_or(Error::new(Errno::ENOENT))?; - self_dir.remove_entry(idx); - target_inode - .inner - .as_direntry_mut() - .unwrap() - .append_entry(new_name, src_inode.clone()); - self_inode.dec_size(); - target_inode.inc_size(); - if src_inode.0.read().metadata.type_ == InodeType::Dir { - self_inode.dec_nlinks(); - target_inode.inc_nlinks(); + // Avoid renaming a directory to a subdirectory of itself + if Arc::ptr_eq(&src_inode, &target_inode_arc) { + return_errno!(Errno::EINVAL); + } + let is_dir = src_inode.0.read().metadata.type_ == InodeType::Dir; + + let target_dir = target_inode.inner.as_direntry_mut().unwrap(); + if let Some((dst_idx, dst_inode)) = target_dir.get_entry(new_name) { + // Avoid renaming a subdirectory to a directory. + if Arc::ptr_eq(&self_inode_arc, &dst_inode) { + return_errno!(Errno::ENOTEMPTY); + } + check_replace_inode(&src_inode, &dst_inode)?; + self_dir.remove_entry(src_idx); + target_dir.remove_entry(dst_idx); + target_dir.append_entry(new_name, src_inode.clone()); + self_inode.dec_size(); + if is_dir { + self_inode.dec_nlinks(); + } + } else { + self_dir.remove_entry(src_idx); + target_dir.append_entry(new_name, src_inode.clone()); + self_inode.dec_size(); + target_inode.inc_size(); + if is_dir { + self_inode.dec_nlinks(); + target_inode.inc_nlinks(); + } } drop(self_inode); drop(target_inode); - if src_inode.0.read().metadata.type_ == InodeType::Dir { + if is_dir { src_inode .0 .write() diff --git a/services/libs/aster-std/src/fs/utils/file_creation_mask.rs b/services/libs/aster-std/src/fs/utils/file_creation_mask.rs index 3965e2ec..2a2e9d98 100644 --- a/services/libs/aster-std/src/fs/utils/file_creation_mask.rs +++ b/services/libs/aster-std/src/fs/utils/file_creation_mask.rs @@ -25,6 +25,6 @@ impl FileCreationMask { impl Default for FileCreationMask { fn default() -> Self { - Self(0o777) + Self(0o022) } } diff --git a/services/libs/aster-std/src/syscall/constants.rs b/services/libs/aster-std/src/syscall/constants.rs index 0c9a4f91..e919774e 100644 --- a/services/libs/aster-std/src/syscall/constants.rs +++ b/services/libs/aster-std/src/syscall/constants.rs @@ -1,7 +1,7 @@ //! constants used in syscall /// LONGEST ALLOWED FILENAME -pub const MAX_FILENAME_LEN: usize = 128; +pub const MAX_FILENAME_LEN: usize = 4096; pub const MAX_ARGV_NUMBER: usize = 128; pub const MAX_ENVP_NUMBER: usize = 128; pub const MAX_ARG_LEN: usize = 2048; diff --git a/services/libs/aster-std/src/syscall/link.rs b/services/libs/aster-std/src/syscall/link.rs index a7ad770f..36c1be85 100644 --- a/services/libs/aster-std/src/syscall/link.rs +++ b/services/libs/aster-std/src/syscall/link.rs @@ -37,11 +37,8 @@ pub fn sys_linkat( return_errno_with_message!(Errno::ENOENT, "oldpath is empty"); } let new_pathname = new_pathname.to_string_lossy(); - if new_pathname.ends_with('/') { - return_errno_with_message!(Errno::EPERM, "newpath is dir"); - } - if new_pathname.is_empty() { - return_errno_with_message!(Errno::ENOENT, "newpath is empty"); + if new_pathname.ends_with('/') || new_pathname.is_empty() { + return_errno_with_message!(Errno::ENOENT, "newpath is dir or is empty"); } let old_fs_path = FsPath::new(old_dirfd, old_pathname.as_ref())?; diff --git a/services/libs/aster-std/src/syscall/mkdir.rs b/services/libs/aster-std/src/syscall/mkdir.rs index 12213d20..f8f2193e 100644 --- a/services/libs/aster-std/src/syscall/mkdir.rs +++ b/services/libs/aster-std/src/syscall/mkdir.rs @@ -32,7 +32,11 @@ pub fn sys_mkdirat( let fs_path = FsPath::new(dirfd, pathname.as_ref())?; current.fs().read().lookup_dir_and_base_name(&fs_path)? }; - let inode_mode = InodeMode::from_bits_truncate(mode); + + let inode_mode = { + let mask_mode = mode & !current.umask().read().get(); + InodeMode::from_bits_truncate(mask_mode) + }; let _ = dir_dentry.create(name.trim_end_matches('/'), InodeType::Dir, inode_mode)?; Ok(SyscallReturn::Return(0)) } diff --git a/services/libs/aster-std/src/syscall/open.rs b/services/libs/aster-std/src/syscall/open.rs index bca6c4ab..df3d96f3 100644 --- a/services/libs/aster-std/src/syscall/open.rs +++ b/services/libs/aster-std/src/syscall/open.rs @@ -28,7 +28,8 @@ pub fn sys_openat( let file_handle = { let pathname = pathname.to_string_lossy(); let fs_path = FsPath::new(dirfd, pathname.as_ref())?; - let inode_handle = current.fs().read().open(&fs_path, flags, mode)?; + let mask_mode = mode & !current.umask().read().get(); + let inode_handle = current.fs().read().open(&fs_path, flags, mask_mode)?; Arc::new(inode_handle) }; let mut file_table = current.file_table().lock(); diff --git a/services/libs/aster-std/src/syscall/rmdir.rs b/services/libs/aster-std/src/syscall/rmdir.rs index 5d91f8a1..cda168e7 100644 --- a/services/libs/aster-std/src/syscall/rmdir.rs +++ b/services/libs/aster-std/src/syscall/rmdir.rs @@ -1,4 +1,7 @@ -use crate::fs::fs_resolver::FsPath; +use crate::fs::{ + file_table::FileDescripter, + fs_resolver::{FsPath, AT_FDCWD}, +}; use crate::log_syscall_entry; use crate::prelude::*; use crate::syscall::constants::MAX_FILENAME_LEN; @@ -8,14 +11,21 @@ use super::SyscallReturn; use super::SYS_RMDIR; pub fn sys_rmdir(pathname_addr: Vaddr) -> Result { + self::sys_rmdirat(AT_FDCWD, pathname_addr) +} + +pub(super) fn sys_rmdirat(dirfd: FileDescripter, pathname_addr: Vaddr) -> Result { log_syscall_entry!(SYS_RMDIR); let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?; - debug!("pathname = {:?}", pathname); + debug!("dirfd = {}, pathname = {:?}", dirfd, pathname); let current = current!(); let (dir_dentry, name) = { let pathname = pathname.to_string_lossy(); - let fs_path = FsPath::try_from(pathname.as_ref())?; + if pathname == "/" { + return_errno_with_message!(Errno::EBUSY, "is root directory"); + } + let fs_path = FsPath::new(dirfd, pathname.as_ref())?; current.fs().read().lookup_dir_and_base_name(&fs_path)? }; dir_dentry.rmdir(name.trim_end_matches('/'))?; diff --git a/services/libs/aster-std/src/syscall/unlink.rs b/services/libs/aster-std/src/syscall/unlink.rs index 4823aae7..07cd6b68 100644 --- a/services/libs/aster-std/src/syscall/unlink.rs +++ b/services/libs/aster-std/src/syscall/unlink.rs @@ -18,7 +18,7 @@ pub fn sys_unlinkat( let flags = UnlinkFlags::from_bits(flags).ok_or(Error::with_message(Errno::EINVAL, "invalid flags"))?; if flags.contains(UnlinkFlags::AT_REMOVEDIR) { - return super::rmdir::sys_rmdir(pathname_addr); + return super::rmdir::sys_rmdirat(dirfd, pathname_addr); } log_syscall_entry!(SYS_UNLINKAT); diff --git a/services/libs/aster-std/src/syscall/write.rs b/services/libs/aster-std/src/syscall/write.rs index 589b66ba..60df03be 100644 --- a/services/libs/aster-std/src/syscall/write.rs +++ b/services/libs/aster-std/src/syscall/write.rs @@ -23,6 +23,10 @@ pub fn sys_write( let current = current!(); let file_table = current.file_table().lock(); let file = file_table.get_file(fd)?; + if user_buf_len == 0 { + return Ok(SyscallReturn::Return(0)); + } + let mut buffer = vec![0u8; user_buf_len]; read_bytes_from_user(user_buf_ptr, &mut buffer)?; debug!("write content = {:?}", buffer);