Skip to content

Commit 4695947

Browse files
authored
实现SYS_LINK和SYS_LINKAT (#611)
* 实现do_linkat及SYS_LINK和SYS_LINKAT * 未在riscv上测试,添加target_arch * 将c字符串检查移动到vfs/syscall.rs,修改do_linkat()逻辑 * 修改部分注释
1 parent 70f159a commit 4695947

File tree

3 files changed

+125
-1
lines changed

3 files changed

+125
-1
lines changed

kernel/src/filesystem/vfs/syscall.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,112 @@ impl Syscall {
737737
return do_mkdir(&path, FileMode::from_bits_truncate(mode as u32)).map(|x| x as usize);
738738
}
739739

740+
/// **创建硬连接的系统调用**
741+
///
742+
/// ## 参数
743+
///
744+
/// - 'oldfd': 用于解析源文件路径的文件描述符
745+
/// - 'old': 源文件路径
746+
/// - 'newfd': 用于解析新文件路径的文件描述符
747+
/// - 'new': 新文件将创建的路径
748+
/// - 'flags': 标志位,仅以位或方式包含AT_EMPTY_PATH和AT_SYMLINK_FOLLOW
749+
///
750+
///
751+
pub fn do_linkat(
752+
oldfd: i32,
753+
old: &str,
754+
newfd: i32,
755+
new: &str,
756+
flags: AtFlags,
757+
) -> Result<usize, SystemError> {
758+
// flag包含其他未规定值时返回EINVAL
759+
if !(AtFlags::AT_EMPTY_PATH | AtFlags::AT_SYMLINK_FOLLOW).contains(flags) {
760+
return Err(SystemError::EINVAL);
761+
}
762+
// TODO AT_EMPTY_PATH标志启用时,进行调用者CAP_DAC_READ_SEARCH或相似的检查
763+
let symlink_times = if flags.contains(AtFlags::AT_SYMLINK_FOLLOW) {
764+
0 as usize
765+
} else {
766+
VFS_MAX_FOLLOW_SYMLINK_TIMES
767+
};
768+
let pcb = ProcessManager::current_pcb();
769+
770+
// 得到源路径的inode
771+
let old_inode: Arc<dyn IndexNode> = if old.is_empty() {
772+
if flags.contains(AtFlags::AT_EMPTY_PATH) {
773+
// 在AT_EMPTY_PATH启用时,old可以为空,old_inode实际为oldfd所指文件,但该文件不能为目录。
774+
let binding = pcb.fd_table();
775+
let fd_table_guard = binding.read();
776+
let file = fd_table_guard
777+
.get_file_by_fd(oldfd)
778+
.ok_or(SystemError::EBADF)?;
779+
let old_inode = file.lock().inode();
780+
old_inode
781+
} else {
782+
return Err(SystemError::ENONET);
783+
}
784+
} else {
785+
let (old_begin_inode, old_remain_path) = user_path_at(&pcb, oldfd, old)?;
786+
old_begin_inode.lookup_follow_symlink(&old_remain_path, symlink_times)?
787+
};
788+
789+
// old_inode为目录时返回EPERM
790+
if old_inode.metadata().unwrap().file_type == FileType::Dir {
791+
return Err(SystemError::EPERM);
792+
}
793+
794+
// 得到新创建节点的父节点
795+
let (new_begin_inode, new_remain_path) = user_path_at(&pcb, newfd, new)?;
796+
let (new_name, new_parent_path) = rsplit_path(&new_remain_path);
797+
let new_parent = new_begin_inode
798+
.lookup_follow_symlink(&new_parent_path.unwrap_or("/"), symlink_times)?;
799+
800+
// 被调用者利用downcast_ref判断两inode是否为同一文件系统
801+
return new_parent.link(&new_name, &old_inode).map(|_| 0);
802+
}
803+
804+
pub fn link(old: *const u8, new: *const u8) -> Result<usize, SystemError> {
805+
let get_path = |cstr: *const u8| -> Result<String, SystemError> {
806+
let res = check_and_clone_cstr(cstr, Some(MAX_PATHLEN))?;
807+
if res.len() >= MAX_PATHLEN {
808+
return Err(SystemError::ENAMETOOLONG);
809+
}
810+
if res.is_empty() {
811+
return Err(SystemError::ENOENT);
812+
}
813+
Ok(res)
814+
};
815+
let old = get_path(old)?;
816+
let new = get_path(new)?;
817+
return Self::do_linkat(
818+
AtFlags::AT_FDCWD.bits() as i32,
819+
&old,
820+
AtFlags::AT_FDCWD.bits() as i32,
821+
&new,
822+
AtFlags::empty(),
823+
);
824+
}
825+
826+
pub fn linkat(
827+
oldfd: i32,
828+
old: *const u8,
829+
newfd: i32,
830+
new: *const u8,
831+
flags: i32,
832+
) -> Result<usize, SystemError> {
833+
let old = check_and_clone_cstr(old, Some(MAX_PATHLEN))?;
834+
let new = check_and_clone_cstr(new, Some(MAX_PATHLEN))?;
835+
if old.len() >= MAX_PATHLEN || new.len() >= MAX_PATHLEN {
836+
return Err(SystemError::ENAMETOOLONG);
837+
}
838+
// old 根据flags & AtFlags::AT_EMPTY_PATH判空
839+
if new.is_empty() {
840+
return Err(SystemError::ENOENT);
841+
}
842+
let flags = AtFlags::from_bits(flags).ok_or(SystemError::EINVAL)?;
843+
Self::do_linkat(oldfd, &old, newfd, &new, flags)
844+
}
845+
740846
/// **删除文件夹、取消文件的链接、删除文件的系统调用**
741847
///
742848
/// ## 参数

kernel/src/syscall/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,21 @@ impl Syscall {
345345
Self::rmdir(path)
346346
}
347347

348+
SYS_LINK => {
349+
let old = args[0] as *const u8;
350+
let new = args[1] as *const u8;
351+
return Self::link(old, new);
352+
}
353+
354+
SYS_LINKAT => {
355+
let oldfd = args[0] as i32;
356+
let old = args[1] as *const u8;
357+
let newfd = args[2] as i32;
358+
let new = args[3] as *const u8;
359+
let flags = args[4] as i32;
360+
return Self::linkat(oldfd, old, newfd, new, flags);
361+
}
362+
348363
#[cfg(target_arch = "x86_64")]
349364
SYS_UNLINK => {
350365
let path = args[0] as *const u8;

kernel/src/syscall/syscall_num.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@
6565
#define SYS_CHDIR 80
6666

6767
#define SYS_MKDIR 83
68-
6968
#define SYS_RMDIR 84
7069

70+
#define SYS_LINK 86
71+
7172
#define SYS_GETTIMEOFDAY 96
7273

7374
#define SYS_ARCH_PRCTL 158
@@ -86,6 +87,8 @@
8687

8788
#define SYS_UNLINK_AT 263
8889

90+
#define SYS_LINKAT 265
91+
8992
#define SYS_PIPE 293
9093

9194
#define SYS_WRITEV 20

0 commit comments

Comments
 (0)