mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2026-09-08 23:57:59 +08:00
add dropbear support (#1304)
https://github.com/DragonOS-Community/DragonOS/pull/1304 * fix rename error in fat32 add a fake link implementation for fat32(it will be removed in the future). Signed-off-by: Godones <chenlinfeng25@outlook.com> * feat: add new syscall and fix the fnctl error add sendfile syscall. add rt_sigsuspend syscall. add sendfile test. add setown/getown command for fcntl. Signed-off-by: Godones <chenlinfeng25@outlook.com> --------- Signed-off-by: Godones <chenlinfeng25@outlook.com>
This commit is contained in:
@@ -42,53 +42,6 @@ pub(super) fn pts_driver() -> Arc<TtyDriver> {
|
||||
PTS_DRIVER.get().clone()
|
||||
}
|
||||
|
||||
// lazy_static! {
|
||||
// pub static ref PTM_DRIVER: Arc<TtyDriver> = {
|
||||
// let mut ptm_driver = TtyDriver::new(
|
||||
// NR_UNIX98_PTY_MAX,
|
||||
// "ptm",
|
||||
// 0,
|
||||
// Major::UNIX98_PTY_MASTER_MAJOR,
|
||||
// 0,
|
||||
// TtyDriverType::Pty,
|
||||
// *TTY_STD_TERMIOS,
|
||||
// Arc::new(Unix98PtyDriverInner::new()),
|
||||
// );
|
||||
|
||||
// ptm_driver.set_subtype(TtyDriverSubType::PtyMaster);
|
||||
// let term = ptm_driver.init_termios_mut();
|
||||
// term.input_mode = InputMode::empty();
|
||||
// term.output_mode = OutputMode::empty();
|
||||
// term.control_mode = ControlMode::B38400 | ControlMode::CS8 | ControlMode::CREAD;
|
||||
// term.local_mode = LocalMode::empty();
|
||||
// term.input_speed = 38400;
|
||||
// term.output_speed = 38400;
|
||||
// TtyDriverManager::tty_register_driver(ptm_driver).unwrap()
|
||||
// };
|
||||
// pub static ref PTS_DRIVER: Arc<TtyDriver> = {
|
||||
// let mut pts_driver = TtyDriver::new(
|
||||
// NR_UNIX98_PTY_MAX,
|
||||
// "pts",
|
||||
// 0,
|
||||
// Major::UNIX98_PTY_SLAVE_MAJOR,
|
||||
// 0,
|
||||
// TtyDriverType::Pty,
|
||||
// *TTY_STD_TERMIOS,
|
||||
// Arc::new(Unix98PtyDriverInner::new()),
|
||||
// );
|
||||
|
||||
// pts_driver.set_subtype(TtyDriverSubType::PtySlave);
|
||||
// let term = pts_driver.init_termios_mut();
|
||||
// term.input_mode = InputMode::empty();
|
||||
// term.output_mode = OutputMode::empty();
|
||||
// term.control_mode = ControlMode::B38400 | ControlMode::CS8 | ControlMode::CREAD;
|
||||
// term.local_mode = LocalMode::empty();
|
||||
// term.input_speed = 38400;
|
||||
// term.output_speed = 38400;
|
||||
// TtyDriverManager::tty_register_driver(pts_driver).unwrap()
|
||||
// };
|
||||
// }
|
||||
|
||||
pub struct PtyCommon;
|
||||
|
||||
impl PtyCommon {
|
||||
|
||||
@@ -854,7 +854,7 @@ impl FATDir {
|
||||
new_name: &str,
|
||||
) -> Result<FATDirEntry, SystemError> {
|
||||
// 判断源目录项是否存在
|
||||
let old_dentry: FATDirEntry = if let FATDirEntryOrShortName::DirEntry(dentry) =
|
||||
let old_dentry = if let FATDirEntryOrShortName::DirEntry(dentry) =
|
||||
self.check_existence(old_name, None, fs.clone())?
|
||||
{
|
||||
dentry
|
||||
@@ -863,22 +863,26 @@ impl FATDir {
|
||||
return Err(SystemError::ENOENT);
|
||||
};
|
||||
|
||||
let short_name = if let FATDirEntryOrShortName::ShortName(s) =
|
||||
self.check_existence(new_name, None, fs.clone())?
|
||||
{
|
||||
s
|
||||
} else {
|
||||
// 如果目标目录项存在,那么就返回错误
|
||||
return Err(SystemError::EEXIST);
|
||||
let short_name = match self.check_existence(new_name, None, fs.clone())? {
|
||||
FATDirEntryOrShortName::ShortName(s) => s,
|
||||
// If newpath already exists, it will be atomically replaced, so that
|
||||
// there is no point at which another process attempting to access
|
||||
// newpath will find it missing.
|
||||
// TODO: support other flags like RENAME_EXCHANGE
|
||||
FATDirEntryOrShortName::DirEntry(e) => {
|
||||
// remove the existing entry
|
||||
self.remove(fs.clone(), new_name, true)?;
|
||||
e.short_name_raw()
|
||||
}
|
||||
};
|
||||
|
||||
let old_short_dentry: Option<ShortDirEntry> = old_dentry.short_dir_entry();
|
||||
let old_short_dentry = old_dentry.short_dir_entry();
|
||||
if let Some(se) = old_short_dentry {
|
||||
// 删除原来的目录项
|
||||
self.remove(fs.clone(), old_dentry.name().as_str(), false)?;
|
||||
|
||||
// 创建新的目录项
|
||||
let new_dentry: FATDirEntry = self.create_dir_entries(
|
||||
let new_dentry = self.create_dir_entries(
|
||||
new_name,
|
||||
&short_name,
|
||||
Some(se),
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::filesystem::page_cache::PageCache;
|
||||
use crate::filesystem::vfs::utils::DName;
|
||||
use crate::filesystem::vfs::{Magic, SpecialNodeData, SuperBlock};
|
||||
use crate::ipc::pipe::LockedPipeInode;
|
||||
use crate::libs::casting::DowncastArc;
|
||||
use crate::mm::fault::{PageFaultHandler, PageFaultMessage};
|
||||
use crate::mm::VmFaultReason;
|
||||
use crate::{
|
||||
@@ -266,11 +267,11 @@ impl LockedFATInode {
|
||||
new_name: &str,
|
||||
) -> Result<(), SystemError> {
|
||||
let mut guard = self.0.lock();
|
||||
let old_inode: Arc<LockedFATInode> = guard.find(old_name)?;
|
||||
let old_inode = guard.find(old_name)?;
|
||||
// 对目标inode上锁,以防更改
|
||||
let old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
|
||||
let old_inode_guard = old_inode.0.lock();
|
||||
let fs = old_inode_guard.fs.upgrade().unwrap();
|
||||
// 从缓存删除
|
||||
|
||||
let old_dir = match &guard.inode_type {
|
||||
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
|
||||
return Err(SystemError::ENOTDIR);
|
||||
@@ -281,11 +282,14 @@ impl LockedFATInode {
|
||||
return Err(SystemError::EROFS);
|
||||
}
|
||||
};
|
||||
// 检查文件是否存在
|
||||
// old_dir.check_existence(old_name, Some(false), guard.fs.upgrade().unwrap())?;
|
||||
|
||||
// remove entries
|
||||
old_dir.rename(fs, old_name, new_name)?;
|
||||
let _nod = guard.children.remove(&to_search_name(old_name));
|
||||
|
||||
let old_inode = guard.children.remove(&to_search_name(old_name)).unwrap();
|
||||
// the new_name should refer to old_inode
|
||||
guard.children.insert(to_search_name(new_name), old_inode);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1486,6 +1490,31 @@ impl FATFsInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl LockedFATInode {
|
||||
fn try_read_pagecache(&self, offset: usize, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let page_cache = self.0.lock().page_cache.clone();
|
||||
if let Some(page_cache) = page_cache {
|
||||
let r = page_cache.lock_irqsave().read(offset, buf);
|
||||
return r;
|
||||
} else {
|
||||
return self.read_sync(offset, buf);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_write_pagecache(&self, offset: usize, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
let page_cache = self.0.lock().page_cache.clone();
|
||||
if let Some(page_cache) = page_cache {
|
||||
let write_len = page_cache.lock_irqsave().write(offset, buf)?;
|
||||
let mut guard = self.0.lock();
|
||||
let old_size = guard.metadata.size;
|
||||
guard.update_metadata(Some(core::cmp::max(old_size, (offset + write_len) as i64)));
|
||||
return Ok(write_len);
|
||||
} else {
|
||||
return self.write_sync(offset, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexNode for LockedFATInode {
|
||||
fn read_sync(&self, offset: usize, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||
@@ -1531,18 +1560,11 @@ impl IndexNode for LockedFATInode {
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
data: SpinLockGuard<FilePrivateData>,
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
let len = core::cmp::min(len, buf.len());
|
||||
let buf = &mut buf[0..len];
|
||||
|
||||
let page_cache = self.0.lock().page_cache.clone();
|
||||
if let Some(page_cache) = page_cache {
|
||||
let r = page_cache.lock_irqsave().read(offset, &mut buf[0..len]);
|
||||
return r;
|
||||
} else {
|
||||
return self.read_direct(offset, len, buf, data);
|
||||
}
|
||||
self.try_read_pagecache(offset, buf)
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
@@ -1550,21 +1572,11 @@ impl IndexNode for LockedFATInode {
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &[u8],
|
||||
data: SpinLockGuard<FilePrivateData>,
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
let len = core::cmp::min(len, buf.len());
|
||||
let buf = &buf[0..len];
|
||||
|
||||
let page_cache = self.0.lock().page_cache.clone();
|
||||
if let Some(page_cache) = page_cache {
|
||||
let write_len = page_cache.lock_irqsave().write(offset, buf)?;
|
||||
let mut guard = self.0.lock();
|
||||
let old_size = guard.metadata.size;
|
||||
guard.update_metadata(Some(core::cmp::max(old_size, (offset + write_len) as i64)));
|
||||
return Ok(write_len);
|
||||
} else {
|
||||
return self.write_direct(offset, len, buf, data);
|
||||
}
|
||||
self.try_write_pagecache(offset, buf)
|
||||
}
|
||||
|
||||
fn read_direct(
|
||||
@@ -1633,6 +1645,41 @@ impl IndexNode for LockedFATInode {
|
||||
}
|
||||
}
|
||||
|
||||
// fat32 does not support hard link
|
||||
// TODO: remove this function
|
||||
fn link(&self, name: &str, other: &Arc<dyn IndexNode>) -> Result<(), SystemError> {
|
||||
let ty = other.metadata()?.file_type;
|
||||
let mode = other.metadata()?.mode;
|
||||
let other = other
|
||||
.downcast_ref::<LockedFATInode>()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
|
||||
let new_inode = self
|
||||
.create(name, ty, mode)?
|
||||
.downcast_arc::<LockedFATInode>()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
|
||||
let mut offset = 0;
|
||||
let mut buf = [0u8; 512];
|
||||
loop {
|
||||
let read_len = other.try_read_pagecache(offset, &mut buf)?;
|
||||
if read_len == 0 {
|
||||
break;
|
||||
}
|
||||
log::error!("Fake FATFS(link): read_len={read_len}, offset={offset}");
|
||||
let write_len = new_inode.try_write_pagecache(offset, &buf[0..read_len])?;
|
||||
if write_len < read_len {
|
||||
log::error!(
|
||||
"Fake FATFS(link): write link file failed, read_len={read_len}, write_len={write_len}"
|
||||
);
|
||||
return Err(SystemError::EIO);
|
||||
}
|
||||
offset += write_len;
|
||||
}
|
||||
log::error!("Fake FATFS(link): link file {name} success, size={offset}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
return self.0.lock().fs.upgrade().unwrap();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ pub enum FcntlCommand {
|
||||
SetLock = 6,
|
||||
/// set record locking info (blocking)
|
||||
SetLockWait = 7,
|
||||
/// set owner
|
||||
SetOwn = 8,
|
||||
/// get owner
|
||||
GetOwn = 9,
|
||||
|
||||
SetLease = F_LINUX_SPECIFIC_BASE,
|
||||
GetLease = F_LINUX_SPECIFIC_BASE + 1,
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::{
|
||||
},
|
||||
ipc::{kill::kill_process, pipe::PipeFsPrivateData},
|
||||
libs::{rwlock::RwLock, spinlock::SpinLock},
|
||||
process::{cred::Cred, resource::RLimitID, ProcessManager},
|
||||
process::{cred::Cred, resource::RLimitID, ProcessControlBlock, ProcessManager, RawPid},
|
||||
};
|
||||
|
||||
/// 文件私有信息的枚举类型
|
||||
@@ -131,6 +131,8 @@ pub struct File {
|
||||
cred: Arc<Cred>,
|
||||
/// 文件描述符标志:是否在execve时关闭
|
||||
close_on_exec: AtomicBool,
|
||||
/// owner
|
||||
pid: SpinLock<Option<Arc<ProcessControlBlock>>>,
|
||||
}
|
||||
|
||||
impl File {
|
||||
@@ -161,6 +163,7 @@ impl File {
|
||||
private_data,
|
||||
cred: ProcessManager::current_pcb().cred(),
|
||||
close_on_exec: AtomicBool::new(close_on_exec),
|
||||
pid: SpinLock::new(None),
|
||||
};
|
||||
|
||||
return Ok(f);
|
||||
@@ -230,7 +233,7 @@ impl File {
|
||||
self.do_write(offset, len, buf, false)
|
||||
}
|
||||
|
||||
fn do_read(
|
||||
pub fn do_read(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
@@ -259,7 +262,7 @@ impl File {
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
fn do_write(
|
||||
pub fn do_write(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
@@ -452,6 +455,7 @@ impl File {
|
||||
private_data: SpinLock::new(self.private_data.lock().clone()),
|
||||
cred: self.cred.clone(),
|
||||
close_on_exec: AtomicBool::new(self.close_on_exec.load(Ordering::SeqCst)),
|
||||
pid: SpinLock::new(None),
|
||||
};
|
||||
// 调用inode的open方法,让inode知道有新的文件打开了这个inode
|
||||
// TODO: reopen is not a good idea for some inodes, need a better design
|
||||
@@ -544,6 +548,27 @@ impl File {
|
||||
let private_data = self.private_data.lock();
|
||||
self.inode.as_pollable_inode()?.poll(&private_data)
|
||||
}
|
||||
|
||||
pub fn owner(&self) -> Option<RawPid> {
|
||||
self.pid.lock().as_ref().map(|pcb| pcb.raw_pid())
|
||||
}
|
||||
|
||||
/// Set a process (group) as owner of the file descriptor.
|
||||
///
|
||||
/// Such that this process (group) will receive `SIGIO` and `SIGURG` signals
|
||||
/// for I/O events on the file descriptor, if `O_ASYNC` status flag is set
|
||||
/// on this file.
|
||||
pub fn set_owner(&self, pid: Option<Arc<ProcessControlBlock>>) -> Result<(), SystemError> {
|
||||
let Some(pcb) = pid else {
|
||||
*self.pid.lock() = None;
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
self.pid.lock().replace(pcb);
|
||||
// todo: update inode owner
|
||||
log::error!("set_owner has not been implemented yet");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for File {
|
||||
|
||||
@@ -53,13 +53,13 @@ mod sys_epoll_ctl;
|
||||
mod sys_epoll_pwait;
|
||||
|
||||
pub mod symlink_utils;
|
||||
mod sys_fsync;
|
||||
pub mod sys_mount;
|
||||
mod sys_sync;
|
||||
pub mod sys_umount2;
|
||||
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
|
||||
mod sys_fstat;
|
||||
mod sys_fsync;
|
||||
pub mod sys_mount;
|
||||
mod sys_sendfile;
|
||||
mod sys_sync;
|
||||
pub mod sys_umount2;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod sys_access;
|
||||
|
||||
@@ -26,7 +26,7 @@ pub fn do_renameat2(
|
||||
filename_from: *const u8,
|
||||
newfd: i32,
|
||||
filename_to: *const u8,
|
||||
_flags: u32,
|
||||
flags: u32,
|
||||
) -> Result<usize, SystemError> {
|
||||
let filename_from = check_and_clone_cstr(filename_from, Some(MAX_PATHLEN))
|
||||
.unwrap()
|
||||
@@ -41,6 +41,12 @@ pub fn do_renameat2(
|
||||
return Err(SystemError::ENAMETOOLONG);
|
||||
}
|
||||
|
||||
let flags = Flags::from_bits_truncate(flags);
|
||||
if !flags.is_empty() {
|
||||
log::warn!("renameat2 flags {flags:?} not supported yet");
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
//获取pcb,文件节点
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let (_old_inode_begin, old_remain_path) = user_path_at(&pcb, oldfd, &filename_from)?;
|
||||
@@ -56,3 +62,16 @@ pub fn do_renameat2(
|
||||
old_parent_inode.move_to(old_filename, &new_parent_inode, new_filename)?;
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags used in the `renameat2` system call.
|
||||
///
|
||||
/// Reference: <https://elixir.bootlin.com/linux/v6.16.3/source/include/uapi/linux/fcntl.h#L140-L143>.
|
||||
///
|
||||
/// Reference: <https://man7.org/linux/man-pages/man2/renameat.2.html>.
|
||||
struct Flags: u32 {
|
||||
const NOREPLACE = 1 << 0;
|
||||
const EXCHANGE = 1 << 1;
|
||||
const WHITEOUT = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::arch::syscall::nr::SYS_FCNTL;
|
||||
use crate::process::RawPid;
|
||||
use crate::{
|
||||
arch::interrupt::TrapFrame,
|
||||
filesystem::vfs::{
|
||||
@@ -158,6 +159,37 @@ impl SysFcntlHandle {
|
||||
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
FcntlCommand::SetOwn => {
|
||||
let pid = arg.unsigned_abs();
|
||||
if pid > i32::MAX as u32 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let pb = if pid == 0 {
|
||||
None
|
||||
} else {
|
||||
let pb =
|
||||
ProcessManager::find(RawPid::from(pid as _)).ok_or(SystemError::ESRCH)?;
|
||||
Some(pb)
|
||||
};
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let file = binding
|
||||
.read()
|
||||
.get_file_by_fd(fd)
|
||||
.ok_or(SystemError::EBADF)?;
|
||||
file.set_owner(pb)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
FcntlCommand::GetOwn => {
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let file = binding
|
||||
.read()
|
||||
.get_file_by_fd(fd)
|
||||
.ok_or(SystemError::EBADF)?;
|
||||
let owner = file.owner().unwrap_or(RawPid::from(0));
|
||||
|
||||
return Ok(owner.data());
|
||||
}
|
||||
_ => {
|
||||
// TODO: unimplemented
|
||||
// 未实现的命令,返回0,不报错。
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
use crate::arch::syscall::nr::SYS_SENDFILE;
|
||||
use crate::process::ProcessManager;
|
||||
use crate::syscall::table::Syscall;
|
||||
use crate::syscall::user_access::UserBufferReader;
|
||||
use alloc::vec::Vec;
|
||||
use system_error::SystemError;
|
||||
|
||||
/// See <https://man7.org/linux/man-pages/man2/sendfile64.2.html>
|
||||
pub struct SysSendfileHandle;
|
||||
|
||||
impl Syscall for SysSendfileHandle {
|
||||
fn num_args(&self) -> usize {
|
||||
4
|
||||
}
|
||||
|
||||
fn handle(
|
||||
&self,
|
||||
args: &[usize],
|
||||
_frame: &mut crate::arch::interrupt::TrapFrame,
|
||||
) -> Result<usize, SystemError> {
|
||||
let offset_ptr = args[2] as *const isize;
|
||||
let out_fd = args[0] as i32;
|
||||
let in_fd = args[1] as i32;
|
||||
let count = args[3] as isize;
|
||||
|
||||
let offset = if offset_ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
let offset = *UserBufferReader::new(offset_ptr, size_of::<isize>(), true)?
|
||||
.read_one_from_user::<isize>(0)?;
|
||||
if offset < 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
Some(offset)
|
||||
};
|
||||
|
||||
log::trace!(
|
||||
"out_fd = {}, in_fd = {}, offset = {:x?}, count = 0x{:x}",
|
||||
out_fd,
|
||||
in_fd,
|
||||
offset,
|
||||
count
|
||||
);
|
||||
|
||||
let count = if count < 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
} else {
|
||||
count as usize
|
||||
};
|
||||
|
||||
let (out_file, in_file) = {
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let fd_table_guard = binding.write();
|
||||
|
||||
let out_file = fd_table_guard
|
||||
.get_file_by_fd(out_fd)
|
||||
.ok_or(SystemError::EBADF)?;
|
||||
let in_file = fd_table_guard
|
||||
.get_file_by_fd(in_fd)
|
||||
.ok_or(SystemError::EBADF)?;
|
||||
(out_file, in_file)
|
||||
};
|
||||
|
||||
let mut buffer = vec![0u8; 4096].into_boxed_slice();
|
||||
let mut total_len = 0;
|
||||
let mut offset = offset.map(|offset| offset as usize);
|
||||
|
||||
while total_len < count {
|
||||
// The offset decides how to read from `in_file`.
|
||||
// If offset is `Some(_)`, the data will be read from the given offset,
|
||||
// and after reading, the file offset of `in_file` will remain unchanged.
|
||||
// If offset is `None`, the data will be read from the file offset,
|
||||
// and the file offset of `in_file` is adjusted
|
||||
// to reflect the number of bytes read from `in_file`.
|
||||
let max_readlen = buffer.len().min(count - total_len);
|
||||
// Read from `in_file`
|
||||
let read_res = if let Some(offset) = offset.as_mut() {
|
||||
let res = in_file.do_read(*offset, max_readlen, &mut buffer[..max_readlen], false);
|
||||
if let Ok(len) = res.as_ref() {
|
||||
*offset += *len;
|
||||
}
|
||||
res
|
||||
} else {
|
||||
in_file.read(max_readlen, &mut buffer[..max_readlen])
|
||||
};
|
||||
|
||||
let read_len = match read_res {
|
||||
Ok(len) => len,
|
||||
Err(e) => {
|
||||
if total_len > 0 {
|
||||
log::warn!("error occurs when trying to read file: {:?}", e);
|
||||
break;
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
if read_len == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
// Note: `sendfile` allows sending partial data,
|
||||
// so short reads and short writes are all acceptable
|
||||
let write_res = out_file.write(read_len, &buffer[..read_len]);
|
||||
|
||||
match write_res {
|
||||
Ok(len) => {
|
||||
total_len += len;
|
||||
if len < 4096 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if total_len > 0 {
|
||||
log::warn!("error occurs when trying to write file: {:?}", e);
|
||||
break;
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(total_len)
|
||||
}
|
||||
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<crate::syscall::table::FormattedSyscallParam> {
|
||||
vec![
|
||||
crate::syscall::table::FormattedSyscallParam::new("out_fd", format!("{:#x}", args[0])),
|
||||
crate::syscall::table::FormattedSyscallParam::new("in_fd", format!("{:#x}", args[1])),
|
||||
crate::syscall::table::FormattedSyscallParam::new("offset", format!("{:#x}", args[2])),
|
||||
crate::syscall::table::FormattedSyscallParam::new("count", format!("{:#x}", args[3])),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
syscall_table_macros::declare_syscall!(SYS_SENDFILE, SysSendfileHandle);
|
||||
@@ -1,7 +1,10 @@
|
||||
pub mod sys_kill;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod sys_pipe;
|
||||
pub mod sys_pipe2;
|
||||
mod sys_restart;
|
||||
mod sys_rt_sigprocmask;
|
||||
mod sys_rt_sigsuspend;
|
||||
pub mod sys_rt_sigtimedwait;
|
||||
mod sys_shmat;
|
||||
mod sys_shmctl;
|
||||
@@ -11,6 +14,3 @@ mod sys_sigaction;
|
||||
mod sys_sigpending;
|
||||
pub mod sys_tgkill;
|
||||
pub mod sys_tkill;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod sys_pipe;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
use syscall_table_macros::declare_syscall;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::arch::ipc::signal::SigSet;
|
||||
use crate::arch::syscall::nr::SYS_RT_SIGSUSPEND;
|
||||
use crate::ipc::signal::{set_sigprocmask, SigHow};
|
||||
use crate::process::ProcessManager;
|
||||
use crate::sched::{schedule, SchedMode};
|
||||
use crate::{
|
||||
mm::VirtAddr,
|
||||
syscall::{
|
||||
table::{FormattedSyscallParam, Syscall},
|
||||
user_access::UserBufferReader,
|
||||
},
|
||||
};
|
||||
|
||||
/// See <https://man7.org/linux/man-pages/man2/rt_sigsuspend.2.html>
|
||||
pub struct SysRtSigSuspend;
|
||||
impl Syscall for SysRtSigSuspend {
|
||||
fn num_args(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn handle(
|
||||
&self,
|
||||
args: &[usize],
|
||||
_frame: &mut crate::arch::interrupt::TrapFrame,
|
||||
) -> Result<usize, system_error::SystemError> {
|
||||
let sigsetsize = args[1];
|
||||
if sigsetsize != size_of::<SigSet>() {
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
|
||||
let reader = UserBufferReader::new(
|
||||
VirtAddr::new(args[0]).as_ptr::<u64>(),
|
||||
core::mem::size_of::<u64>(),
|
||||
true,
|
||||
)?;
|
||||
let mask = reader.read_one_from_user::<u64>(0)?;
|
||||
let mut mask = SigSet::from_bits_truncate(*mask);
|
||||
// It is not possible to block SIGKILL or SIGSTOP; specifying these
|
||||
// signals in mask, has no effect on the thread's signal mask.
|
||||
mask -= SigSet::SIGKILL;
|
||||
mask -= SigSet::SIGSTOP;
|
||||
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let old_mask = *pcb.sig_info_irqsave().sig_blocked();
|
||||
|
||||
set_sigprocmask(SigHow::SetMask, mask).unwrap();
|
||||
log::trace!("Process enter rt_sigsuspend, new mask: {mask:?}, old mask: {old_mask:?}");
|
||||
loop {
|
||||
if pcb.has_pending_signal_fast() && pcb.has_pending_not_masked_signal() {
|
||||
set_sigprocmask(SigHow::SetMask, old_mask).unwrap();
|
||||
return Err(SystemError::EINTR);
|
||||
}
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
// unreachable!("rt_sigsuspend always return EINTR");
|
||||
}
|
||||
|
||||
fn entry_format(
|
||||
&self,
|
||||
args: &[usize],
|
||||
) -> alloc::vec::Vec<crate::syscall::table::FormattedSyscallParam> {
|
||||
vec![FormattedSyscallParam::new(
|
||||
"mask",
|
||||
format!("{:#x}", args[0]),
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
declare_syscall!(SYS_RT_SIGSUSPEND, SysRtSigSuspend);
|
||||
@@ -68,6 +68,17 @@ impl<T: Socket + 'static> IndexNode for T {
|
||||
ModeType::from_bits_truncate(0o755),
|
||||
))
|
||||
}
|
||||
|
||||
// TODO: implement ioctl for socket
|
||||
fn ioctl(
|
||||
&self,
|
||||
_cmd: u32,
|
||||
_data: usize,
|
||||
_private_data: &FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
log::warn!("Socket not support ioctl");
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Socket + 'static> PollableInode for T {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "用法: %s <源文件> <目标文件>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *src_path = argv[1];
|
||||
const char *dst_path = argv[2];
|
||||
|
||||
int src_fd = open(src_path, O_RDONLY);
|
||||
if (src_fd < 0) {
|
||||
perror("打开源文件失败");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dst_fd = open(dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (dst_fd < 0) {
|
||||
perror("打开目标文件失败");
|
||||
close(src_fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct stat stat_buf;
|
||||
if (fstat(src_fd, &stat_buf) < 0) {
|
||||
perror("fstat失败");
|
||||
close(src_fd);
|
||||
close(dst_fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
off_t offset = 0;
|
||||
ssize_t sent = sendfile(dst_fd, src_fd, &offset, stat_buf.st_size);
|
||||
if (sent < 0) {
|
||||
perror("sendfile失败");
|
||||
close(src_fd);
|
||||
close(dst_fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("成功复制 %zd 字节,从 %s 到 %s\n", sent, src_path, dst_path);
|
||||
|
||||
close(src_fd);
|
||||
close(dst_fd);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user