Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions kernel/src/filesystem/vfs/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,112 @@ 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: AtFlags,
) -> Result<usize, SystemError> {
// 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 = if flags.contains(AtFlags::AT_SYMLINK_FOLLOW) {
0 as usize
} else {
VFS_MAX_FOLLOW_SYMLINK_TIMES
};
let pcb = ProcessManager::current_pcb();

// 得到源路径的inode
let old_inode: Arc<dyn IndexNode> = 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);
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);
}

pub fn link(old: *const u8, new: *const u8) -> Result<usize, SystemError> {
let get_path = |cstr: *const u8| -> Result<String, SystemError> {
let res = check_and_clone_cstr(cstr, Some(MAX_PATHLEN))?;
if res.len() >= MAX_PATHLEN {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这两个if是不必要的。

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,
AtFlags::AT_FDCWD.bits() as i32,
&new,
AtFlags::empty(),
);
}

pub fn linkat(
oldfd: i32,
old: *const u8,
newfd: i32,
new: *const u8,
flags: i32,
) -> Result<usize, SystemError> {
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同理,因为check_and_clone_str会自动截断。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我个人认为这个只检查是否等于MAX_PATHLEN,写成>=的形式是参考了unlink的写法。

}
// 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)
}

/// **删除文件夹、取消文件的链接、删除文件的系统调用**
///
/// ## 参数
Expand Down
15 changes: 15 additions & 0 deletions kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,21 @@ impl Syscall {
Self::rmdir(path)
}

SYS_LINK => {
let old = args[0] as *const u8;
let new = args[1] as *const u8;
return Self::link(old, new);
}

SYS_LINKAT => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个系统调用riscv也有,因此不需要加条件编译。

let oldfd = args[0] as i32;
let old = args[1] as *const u8;
let newfd = args[2] as i32;
let new = args[3] as *const u8;
let flags = args[4] as i32;
return Self::linkat(oldfd, old, newfd, new, flags);
}

#[cfg(target_arch = "x86_64")]
SYS_UNLINK => {
let path = args[0] as *const u8;
Expand Down
5 changes: 4 additions & 1 deletion kernel/src/syscall/syscall_num.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,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
Expand All @@ -85,6 +86,8 @@

#define SYS_UNLINK_AT 263

#define SYS_LINKAT 265

#define SYS_PIPE 293

#define SYS_WRITEV 20
Expand Down