From 3755a516a3b2dd8979fae3da9faa6e456c2778bc Mon Sep 17 00:00:00 2001 From: schulice Date: Sat, 16 Mar 2024 16:38:27 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=AE=9E=E7=8E=B0do=5Flinkat=E5=8F=8ASYS?= =?UTF-8?q?=5FLINK=E5=92=8CSYS=5FLINKAT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/filesystem/vfs/syscall.rs | 90 ++++++++++++++++++++++++++++ kernel/src/syscall/mod.rs | 36 +++++++++++ kernel/src/syscall/syscall_num.h | 5 +- 3 files changed, 130 insertions(+), 1 deletion(-) diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index 67986e6a1..727b1f882 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -538,6 +538,93 @@ impl Syscall { return do_mkdir(path, FileMode::from_bits_truncate(mode as u32)).map(|x| x as usize); } + /// **创建硬连接的系统调用** + /// + /// ## 参数 + /// + /// - 'oldfd': 用于解析源文件路径的文件描述符 + /// - 'old': 源文件路径 + /// - 'newfd': 用于解析新文件路径的文件描述符 + /// - 'new': 新文件将创建的路径 + /// - 'flags': 标志位,仅以位或方式包含AT_EMPTY_PATH和AT_SYMLINK_FOLLOW + /// + /// + pub fn do_linkat( + oldfd: i32, + old: &str, + newfd: i32, + new: &str, + flags: i32, + ) -> Result { + // flag错误时返回EINVAL + if flags & ((!(AtFlags::AT_EMPTY_PATH | AtFlags::AT_SYMLINK_FOLLOW)).bits()) != 0 { + return Err(SystemError::EINVAL); + } + // TODO AT_EMPTY_PATH标志启用时,进行调用者CAP_DAC_READ_SEARCH或相似的检查 + let symlink_times = match flags & AtFlags::AT_SYMLINK_FOLLOW.bits() { + 0 => 0, + _ => VFS_MAX_FOLLOW_SYMLINK_TIMES, + }; + let pcb = ProcessManager::current_pcb(); + + // AT_EMPTY_PATH标志不启用时得到源路径的inode的闭包 + let get_old_inode_without_empty_flag = || { + let (old_begin_inode, old_remain_path) = user_path_at(&pcb, oldfd, old)?; + old_begin_inode.lookup_follow_symlink(&old_remain_path, symlink_times) + }; + + // 得到源路径的inode + let old_inode: Arc = match flags & AtFlags::AT_EMPTY_PATH.bits() { + 0 => get_old_inode_without_empty_flag()?, + _ => { + if old.len() == 0 { + // 在AT_EMPTY_PATH启用时,old可以为空,old_inode实际为oldfd所指文件,但该文件不能为目录。 + let binding = pcb.fd_table(); + let fd_table_guard = binding.read(); + let file = fd_table_guard + .get_file_by_fd(oldfd) + .ok_or(SystemError::EBADF)?; + let old_inode = file.lock().inode(); + if old_inode.metadata().unwrap().file_type == FileType::Dir { + return Err(SystemError::EPERM); + } + old_inode + } else { + get_old_inode_without_empty_flag()? + } + } + }; + + // 得到新创建节点的父节点 + let (new_begin_inode, new_remain_path) = user_path_at(&pcb, newfd, new)?; + let (new_name, new_parent_path) = rsplit_path(&new_remain_path); + let new_parent = new_begin_inode + .lookup_follow_symlink(&new_parent_path.unwrap_or("/"), symlink_times)?; + + // 在下层检查是否处于同一文件系统 + return new_parent.link(&new_name, &old_inode).map(|_| 0); + } + + pub fn link(old: &str, new: &str) -> Result { + Self::do_linkat( + AtFlags::AT_FDCWD.bits() as i32, + old, + AtFlags::AT_FDCWD.bits() as i32, + new, + 0, + ) + } + + pub fn linkat( + oldfd: i32, + old: &str, + newfd: i32, + new: &str, + flags: i32, + ) -> Result { + Self::do_linkat(oldfd, old, newfd, new, flags) + } + /// **删除文件夹、取消文件的链接、删除文件的系统调用** /// /// ## 参数 @@ -579,6 +666,9 @@ impl Syscall { if pathname.len() >= MAX_PATHLEN { return Err(SystemError::ENAMETOOLONG); } + if pathname.len() <= 0 { + return Err(SystemError::ENOENT); + } let pathname = pathname.as_str().trim(); return do_remove_dir(AtFlags::AT_FDCWD.bits(), pathname).map(|v| v as usize); } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index fb9480dbf..c6c445e84 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -6,6 +6,7 @@ use core::{ use crate::{ arch::{ipc::signal::SigSet, syscall::nr::*}, driver::base::device::device_number::DeviceNumber, + filesystem::vfs::fcntl::AtFlags, libs::{futex::constant::FutexFlag, rand::GRandFlags}, mm::syscall::MremapFlags, net::syscall::MsgHdr, @@ -411,6 +412,41 @@ impl Syscall { Self::rmdir(pathname) } + SYS_LINK => { + let old_cstr = args[0] as *const u8; + let new_cstr = args[1] as *const u8; + + let old = check_and_clone_cstr(old_cstr, Some(MAX_PATHLEN))?; + let new = check_and_clone_cstr(new_cstr, Some(MAX_PATHLEN))?; + if old.len() >= MAX_PATHLEN || new.len() >= MAX_PATHLEN { + return Err(SystemError::ENAMETOOLONG); + } + if old.len() <= 0 || new.len() <= 0 { + return Err(SystemError::ENOENT); + } + return Self::link(&old, &new); + } + + SYS_LINKAT => { + let oldfd = args[0] as i32; + let old_cstr = args[1] as *const u8; + let newfd = args[2] as i32; + let new_cstr = args[3] as *const u8; + let flags = args[4] as i32; + + let old = check_and_clone_cstr(old_cstr, Some(MAX_PATHLEN))?; + let new = check_and_clone_cstr(new_cstr, Some(MAX_PATHLEN))?; + if old.len() >= MAX_PATHLEN || new.len() >= MAX_PATHLEN { + return Err(SystemError::ENAMETOOLONG); + } + // old.len() 根据flags & AtFlags::AT_EMPTY_PATH判空 + if new.len() <= 0 || (old.len() <= 0 && flags & AtFlags::AT_EMPTY_PATH.bits() == 0) + { + return Err(SystemError::ENOENT); + } + return Self::linkat(oldfd, &old, newfd, &new, flags); + } + #[cfg(target_arch = "x86_64")] SYS_UNLINK => { let pathname = args[0] as *const u8; diff --git a/kernel/src/syscall/syscall_num.h b/kernel/src/syscall/syscall_num.h index 9b5462430..bdbb7e4ac 100644 --- a/kernel/src/syscall/syscall_num.h +++ b/kernel/src/syscall/syscall_num.h @@ -64,9 +64,10 @@ #define SYS_CHDIR 80 #define SYS_MKDIR 83 - #define SYS_RMDIR 84 +#define SYS_LINK 86 + #define SYS_GETTIMEOFDAY 96 #define SYS_ARCH_PRCTL 158 @@ -84,6 +85,8 @@ #define SYS_UNLINK_AT 263 +#define SYS_LINKAT 265 + #define SYS_PIPE 293 #define SYS_WRITEV 20 From 04a8ab0cdc36e2d942636f3b7c08aa49dc8b92af Mon Sep 17 00:00:00 2001 From: schulice Date: Sat, 16 Mar 2024 16:51:45 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=9C=AA=E5=9C=A8riscv=E4=B8=8A=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=EF=BC=8C=E6=B7=BB=E5=8A=A0target=5Farch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/syscall/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c6c445e84..3fd4aaf75 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -412,6 +412,7 @@ impl Syscall { Self::rmdir(pathname) } + #[cfg(target_arch = "x86_64")] SYS_LINK => { let old_cstr = args[0] as *const u8; let new_cstr = args[1] as *const u8; @@ -427,6 +428,7 @@ impl Syscall { return Self::link(&old, &new); } + #[cfg(target_arch = "x86_64")] SYS_LINKAT => { let oldfd = args[0] as i32; let old_cstr = args[1] as *const u8; From e61ceaf92ff553eda132b5b348f6d0cffcb7132b Mon Sep 17 00:00:00 2001 From: schulice Date: Sun, 17 Mar 2024 14:30:37 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=B0=86c=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E7=A7=BB=E5=8A=A8=E5=88=B0vfs/syscall.rs?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9do=5Flinkat()=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/filesystem/vfs/syscall.rs | 97 +++++++++++++++++----------- kernel/src/syscall/mod.rs | 35 ++-------- 2 files changed, 64 insertions(+), 68 deletions(-) diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index 727b1f882..1542b33c7 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -554,47 +554,44 @@ impl Syscall { old: &str, newfd: i32, new: &str, - flags: i32, + flags: AtFlags, ) -> Result { - // flag错误时返回EINVAL - if flags & ((!(AtFlags::AT_EMPTY_PATH | AtFlags::AT_SYMLINK_FOLLOW)).bits()) != 0 { + // flag包含其他未规定值时返回EINVAL + if !(AtFlags::AT_EMPTY_PATH | AtFlags::AT_SYMLINK_FOLLOW).contains(flags) { return Err(SystemError::EINVAL); } // TODO AT_EMPTY_PATH标志启用时,进行调用者CAP_DAC_READ_SEARCH或相似的检查 - let symlink_times = match flags & AtFlags::AT_SYMLINK_FOLLOW.bits() { - 0 => 0, - _ => VFS_MAX_FOLLOW_SYMLINK_TIMES, + let symlink_times = if flags.contains(AtFlags::AT_SYMLINK_FOLLOW) { + 0 as usize + } else { + VFS_MAX_FOLLOW_SYMLINK_TIMES }; let pcb = ProcessManager::current_pcb(); - // AT_EMPTY_PATH标志不启用时得到源路径的inode的闭包 - let get_old_inode_without_empty_flag = || { - let (old_begin_inode, old_remain_path) = user_path_at(&pcb, oldfd, old)?; - old_begin_inode.lookup_follow_symlink(&old_remain_path, symlink_times) - }; - // 得到源路径的inode - let old_inode: Arc = match flags & AtFlags::AT_EMPTY_PATH.bits() { - 0 => get_old_inode_without_empty_flag()?, - _ => { - if old.len() == 0 { - // 在AT_EMPTY_PATH启用时,old可以为空,old_inode实际为oldfd所指文件,但该文件不能为目录。 - let binding = pcb.fd_table(); - let fd_table_guard = binding.read(); - let file = fd_table_guard - .get_file_by_fd(oldfd) - .ok_or(SystemError::EBADF)?; - let old_inode = file.lock().inode(); - if old_inode.metadata().unwrap().file_type == FileType::Dir { - return Err(SystemError::EPERM); - } - old_inode - } else { - get_old_inode_without_empty_flag()? - } + let old_inode: Arc = if old.is_empty() { + if flags.contains(AtFlags::AT_EMPTY_PATH) { + // 在AT_EMPTY_PATH启用时,old可以为空,old_inode实际为oldfd所指文件,但该文件不能为目录。 + let binding = pcb.fd_table(); + let fd_table_guard = binding.read(); + let file = fd_table_guard + .get_file_by_fd(oldfd) + .ok_or(SystemError::EBADF)?; + let old_inode = file.lock().inode(); + old_inode + } else { + return Err(SystemError::ENONET); } + } else { + let (old_begin_inode, old_remain_path) = user_path_at(&pcb, oldfd, old)?; + old_begin_inode.lookup_follow_symlink(&old_remain_path, symlink_times)? }; + // old_inode为目录时返回EPERM + if old_inode.metadata().unwrap().file_type == FileType::Dir { + return Err(SystemError::EPERM); + } + // 得到新创建节点的父节点 let (new_begin_inode, new_remain_path) = user_path_at(&pcb, newfd, new)?; let (new_name, new_parent_path) = rsplit_path(&new_remain_path); @@ -605,24 +602,46 @@ impl Syscall { return new_parent.link(&new_name, &old_inode).map(|_| 0); } - pub fn link(old: &str, new: &str) -> Result { - Self::do_linkat( + pub fn link(old: *const u8, new: *const u8) -> Result { + let get_path = |cstr: *const u8| -> Result { + let res = check_and_clone_cstr(cstr, Some(MAX_PATHLEN))?; + if res.len() >= MAX_PATHLEN { + return Err(SystemError::ENAMETOOLONG); + } + if res.is_empty() { + return Err(SystemError::ENOENT); + } + Ok(res) + }; + let old = get_path(old)?; + let new = get_path(new)?; + return Self::do_linkat( AtFlags::AT_FDCWD.bits() as i32, - old, + &old, AtFlags::AT_FDCWD.bits() as i32, - new, - 0, - ) + &new, + AtFlags::empty(), + ); } pub fn linkat( oldfd: i32, - old: &str, + old: *const u8, newfd: i32, - new: &str, + new: *const u8, flags: i32, ) -> Result { - Self::do_linkat(oldfd, old, newfd, new, flags) + let old = check_and_clone_cstr(old, Some(MAX_PATHLEN))?; + let new = check_and_clone_cstr(new, Some(MAX_PATHLEN))?; + if old.len() >= MAX_PATHLEN || new.len() >= MAX_PATHLEN { + return Err(SystemError::ENAMETOOLONG); + } + // old 根据flags & AtFlags::AT_EMPTY_PATH判空 + if new.is_empty() { + return Err(SystemError::ENOENT); + } + let flags = AtFlags::from_bits(flags).ok_or(SystemError::EINVAL)?; + Self::do_linkat(oldfd, &old, newfd, &new, flags) } /// **删除文件夹、取消文件的链接、删除文件的系统调用** diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 3fd4aaf75..c1b7af44c 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -6,7 +6,6 @@ use core::{ use crate::{ arch::{ipc::signal::SigSet, syscall::nr::*}, driver::base::device::device_number::DeviceNumber, - filesystem::vfs::fcntl::AtFlags, libs::{futex::constant::FutexFlag, rand::GRandFlags}, mm::syscall::MremapFlags, net::syscall::MsgHdr, @@ -412,41 +411,19 @@ impl Syscall { Self::rmdir(pathname) } - #[cfg(target_arch = "x86_64")] SYS_LINK => { - let old_cstr = args[0] as *const u8; - let new_cstr = args[1] as *const u8; - - let old = check_and_clone_cstr(old_cstr, Some(MAX_PATHLEN))?; - let new = check_and_clone_cstr(new_cstr, Some(MAX_PATHLEN))?; - if old.len() >= MAX_PATHLEN || new.len() >= MAX_PATHLEN { - return Err(SystemError::ENAMETOOLONG); - } - if old.len() <= 0 || new.len() <= 0 { - return Err(SystemError::ENOENT); - } - return Self::link(&old, &new); + let old = args[0] as *const u8; + let new = args[1] as *const u8; + return Self::link(old, new); } - #[cfg(target_arch = "x86_64")] SYS_LINKAT => { let oldfd = args[0] as i32; - let old_cstr = args[1] as *const u8; + let old = args[1] as *const u8; let newfd = args[2] as i32; - let new_cstr = args[3] as *const u8; + let new = args[3] as *const u8; let flags = args[4] as i32; - - let old = check_and_clone_cstr(old_cstr, Some(MAX_PATHLEN))?; - let new = check_and_clone_cstr(new_cstr, Some(MAX_PATHLEN))?; - if old.len() >= MAX_PATHLEN || new.len() >= MAX_PATHLEN { - return Err(SystemError::ENAMETOOLONG); - } - // old.len() 根据flags & AtFlags::AT_EMPTY_PATH判空 - if new.len() <= 0 || (old.len() <= 0 && flags & AtFlags::AT_EMPTY_PATH.bits() == 0) - { - return Err(SystemError::ENOENT); - } - return Self::linkat(oldfd, &old, newfd, &new, flags); + return Self::linkat(oldfd, old, newfd, new, flags); } #[cfg(target_arch = "x86_64")] From 8da6f358c04f4870914a3448c8c9dd3ac1dda041 Mon Sep 17 00:00:00 2001 From: schulice Date: Wed, 20 Mar 2024 20:35:49 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/filesystem/vfs/syscall.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index d194778a5..057674ffc 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -618,7 +618,7 @@ impl Syscall { let new_parent = new_begin_inode .lookup_follow_symlink(&new_parent_path.unwrap_or("/"), symlink_times)?; - // 在下层检查是否处于同一文件系统 + // 被调用者利用downcast_ref判断两inode是否为同一文件系统 return new_parent.link(&new_name, &old_inode).map(|_| 0); }