mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 13:06:33 +00:00
Enable some fs system call test cases
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
5bc1312a91
commit
ddca4fb2fc
8
.github/workflows/integration_test.yml
vendored
8
.github/workflows/integration_test.yml
vendored
@ -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
|
||||
|
2
Makefile
2
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)
|
||||
|
@ -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)))
|
||||
|
11
regression/syscall_test/blocklists/getdents_test
Normal file
11
regression/syscall_test/blocklists/getdents_test
Normal file
@ -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
|
1
regression/syscall_test/blocklists/link_test
Normal file
1
regression/syscall_test/blocklists/link_test
Normal file
@ -0,0 +1 @@
|
||||
LinkTest.PermissionDenied
|
6
regression/syscall_test/blocklists/lseek_test
Normal file
6
regression/syscall_test/blocklists/lseek_test
Normal file
@ -0,0 +1,6 @@
|
||||
LseekTest.Overflow
|
||||
LseekTest.ProcFile
|
||||
LseekTest.SysDir
|
||||
LseekTest.SeekCurrentDir
|
||||
LseekTest.ProcStatTwice
|
||||
LseekTest.EtcPasswdDup
|
1
regression/syscall_test/blocklists/mkdir_test
Normal file
1
regression/syscall_test/blocklists/mkdir_test
Normal file
@ -0,0 +1 @@
|
||||
MkdirTest.FailsOnDirWithoutWritePerms
|
9
regression/syscall_test/blocklists/open_create_test
Normal file
9
regression/syscall_test/blocklists/open_create_test
Normal file
@ -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
|
7
regression/syscall_test/blocklists/rename_test
Normal file
7
regression/syscall_test/blocklists/rename_test
Normal file
@ -0,0 +1,7 @@
|
||||
RenameTest.RootToAnything
|
||||
RenameTest.AnythingToRoot
|
||||
RenameTest.FailsWithDots
|
||||
RenameTest.FailsWhenOldParentNotWritable
|
||||
RenameTest.FailsWhenNewParentNotWritable
|
||||
RenameTest.OverwriteFailsWhenNewParentNotWritable
|
||||
RenameTest.FileDoesNotExistWhenNewParentNotExecutable
|
4
regression/syscall_test/blocklists/stat_test
Normal file
4
regression/syscall_test/blocklists/stat_test
Normal file
@ -0,0 +1,4 @@
|
||||
StatTest.FstatatSymlinkDirWithTrailingSlash
|
||||
StatTest.FstatatSymlinkDirWithTrailingSlashSameInode
|
||||
StatTest.LstatSymlinkDir
|
||||
SimpleStatTest.AnonDeviceAllocatesUniqueInodesAcrossSaveRestore
|
7
regression/syscall_test/blocklists/symlink_test
Normal file
7
regression/syscall_test/blocklists/symlink_test
Normal file
@ -0,0 +1,7 @@
|
||||
SymlinkTest.CannotCreateSymlinkInReadOnlyDir
|
||||
SymlinkTest.PwriteToSymlink
|
||||
SymlinkTest.SymlinkAtDegradedPermissions_NoRandomSave
|
||||
SymlinkTest.ReadlinkAtDegradedPermissions_NoRandomSave
|
||||
SymlinkTest.FollowUpdatesATime
|
||||
AbsAndRelTarget/ParamSymlinkTest.CreatLinkCreatesTarget/0
|
||||
AbsAndRelTarget/ParamSymlinkTest.CreatLinkCreatesTarget/1
|
3
regression/syscall_test/blocklists/sync_test
Normal file
3
regression/syscall_test/blocklists/sync_test
Normal file
@ -0,0 +1,3 @@
|
||||
SyncTest.SyncFileSytem
|
||||
SyncTest.SyncFromPipe
|
||||
SyncTest.CannotSyncFileSytemAtBadFd
|
4
regression/syscall_test/blocklists/unlink_test
Normal file
4
regression/syscall_test/blocklists/unlink_test
Normal file
@ -0,0 +1,4 @@
|
||||
UnlinkTest.AtDirDegradedPermissions_NoRandomSave
|
||||
UnlinkTest.ParentDegradedPermissions
|
||||
UnlinkTest.AtBad
|
||||
UnlinkTest.TooLongName
|
3
regression/syscall_test/blocklists/write_test
Normal file
3
regression/syscall_test/blocklists/write_test
Normal file
@ -0,0 +1,3 @@
|
||||
WriteTest.WriteNoExceedsRLimit
|
||||
WriteTest.WriteExceedsRLimit
|
||||
WriteTest.PwriteNoChangeOffset
|
@ -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=$?
|
||||
|
@ -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");
|
||||
|
@ -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::<RamInode>().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<RamInode>, dst_inode: &Arc<RamInode>| -> 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()
|
||||
|
@ -25,6 +25,6 @@ impl FileCreationMask {
|
||||
|
||||
impl Default for FileCreationMask {
|
||||
fn default() -> Self {
|
||||
Self(0o777)
|
||||
Self(0o022)
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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())?;
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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<SyscallReturn> {
|
||||
self::sys_rmdirat(AT_FDCWD, pathname_addr)
|
||||
}
|
||||
|
||||
pub(super) fn sys_rmdirat(dirfd: FileDescripter, pathname_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
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('/'))?;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user