diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index e0e40bb60..51c2fd062 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -407,9 +407,10 @@ impl File { /// @brief 判断当前文件是否可读 #[inline] pub fn readable(&self) -> Result<(), SystemError> { + let mode = *self.mode.read(); // 暂时认为只要不是write only, 就可读 - if *self.mode.read() == FileMode::O_WRONLY { - return Err(SystemError::EPERM); + if mode == FileMode::O_WRONLY || mode.contains(FileMode::O_PATH) { + return Err(SystemError::EBADF); } return Ok(()); diff --git a/kernel/src/filesystem/vfs/syscall/mod.rs b/kernel/src/filesystem/vfs/syscall/mod.rs index 6957be3a8..a5f782385 100644 --- a/kernel/src/filesystem/vfs/syscall/mod.rs +++ b/kernel/src/filesystem/vfs/syscall/mod.rs @@ -31,6 +31,7 @@ mod sys_mkdirat; pub mod sys_mknodat; mod sys_openat; mod sys_pread64; +mod sys_preadv; mod sys_pselect6; mod sys_pwrite64; mod sys_pwritev; diff --git a/kernel/src/filesystem/vfs/syscall/sys_preadv.rs b/kernel/src/filesystem/vfs/syscall/sys_preadv.rs new file mode 100644 index 000000000..b7123db5e --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_preadv.rs @@ -0,0 +1,87 @@ +use alloc::string::ToString; +use alloc::vec::Vec; + +use system_error::SystemError; + +use crate::arch::syscall::nr::SYS_PREADV; +use crate::filesystem::vfs::iov::{IoVec, IoVecs}; +use crate::process::ProcessManager; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; + +pub struct SysPreadVHandle; + +impl Syscall for SysPreadVHandle { + fn num_args(&self) -> usize { + 4 + } + + fn handle( + &self, + args: &[usize], + _frame: &mut crate::arch::interrupt::TrapFrame, + ) -> Result { + let fd = Self::fd(args); + let iov = Self::iov(args); + let iov_count = Self::iov_count(args); + let offset = Self::offset(args); + + // Construct IoVecs from user pointer. + // For preadv, we are writing to user buffers, so we need to verify they are writable. + // IoVecs::from_user internally uses UserBufferWriter::new which verifies the area. + let iovecs = unsafe { IoVecs::from_user(iov, iov_count, true) }?; + + do_preadv(fd, &iovecs, offset) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("fd:", Self::fd(args).to_string()), + FormattedSyscallParam::new("iov:", format!("{:#x}", Self::iov(args) as usize)), + FormattedSyscallParam::new("iov_count:", Self::iov_count(args).to_string()), + FormattedSyscallParam::new("offset:", Self::offset(args).to_string()), + ] + } +} + +impl SysPreadVHandle { + fn fd(args: &[usize]) -> i32 { + args[0] as i32 + } + + fn iov(args: &[usize]) -> *const IoVec { + args[1] as *const IoVec + } + + fn iov_count(args: &[usize]) -> usize { + args[2] + } + + fn offset(args: &[usize]) -> usize { + args[3] + } +} + +pub fn do_preadv(fd: i32, iovecs: &IoVecs, offset: usize) -> Result { + let binding = ProcessManager::current_pcb().fd_table(); + let fd_table_guard = binding.read(); + + let file = fd_table_guard + .get_file_by_fd(fd) + .ok_or(SystemError::EBADF)?; + + drop(fd_table_guard); + + // Create a kernel buffer to read data into. + // TODO: Support scatter-gather I/O directly in FS to avoid this copy. + let mut data = vec![0; iovecs.total_len()]; + + // Read from file at offset into kernel buffer. + let read_len = file.pread(offset, data.len(), &mut data)?; + + // Scatter the read data back to user buffers. + iovecs.scatter(&data[..read_len]); + + Ok(read_len) +} + +syscall_table_macros::declare_syscall!(SYS_PREADV, SysPreadVHandle); diff --git a/user/apps/tests/syscall/gvisor/whitelist.txt b/user/apps/tests/syscall/gvisor/whitelist.txt index 69760d340..96888590e 100644 --- a/user/apps/tests/syscall/gvisor/whitelist.txt +++ b/user/apps/tests/syscall/gvisor/whitelist.txt @@ -25,6 +25,7 @@ chdir_test fchdir_test rename_test getdents_test +preadv_test # 进程相关测试 fork_test