Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
90 changes: 90 additions & 0 deletions kernel/src/filesystem/vfs/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Member

Choose a reason for hiding this comment

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

这个作为内部的函数,flags应当是Atflags类型,而不是i32

) -> Result<usize, SystemError> {
// 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,
Copy link
Member

Choose a reason for hiding this comment

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

这里应当使用flags.contains或者if 来判断它是否等于0,而不是match。下面那个代码也一样。

_ => 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<dyn IndexNode> = 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);
Copy link
Member

Choose a reason for hiding this comment

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

返回值是eperm吗?有无linux man7的文档。看看这种情况应当返回什么内容。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

是参考的man page
image

}
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)?;

// 在下层检查是否处于同一文件系统
Copy link
Member

Choose a reason for hiding this comment

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

这个注释貌似不太对。

return new_parent.link(&new_name, &old_inode).map(|_| 0);
}

pub fn link(old: &str, new: &str) -> Result<usize, SystemError> {
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<usize, SystemError> {
Self::do_linkat(oldfd, old, newfd, new, flags)
}

/// **删除文件夹、取消文件的链接、删除文件的系统调用**
///
/// ## 参数
Expand Down Expand Up @@ -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);
}
Expand Down
38 changes: 38 additions & 0 deletions kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -411,6 +412,43 @@ 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))?;
Copy link
Member

Choose a reason for hiding this comment

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

把这些校验的操作放到vfs的syscall里面去。不要写在这里。

let new = check_and_clone_cstr(new_cstr, Some(MAX_PATHLEN))?;
if old.len() >= MAX_PATHLEN || new.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.

这两个系统调用在校验这块的逻辑类似,应当封装成函数。

return Err(SystemError::ENAMETOOLONG);
}
if old.len() <= 0 || new.len() <= 0 {
return Err(SystemError::ENOENT);
}
return Self::link(&old, &new);
}

#[cfg(target_arch = "x86_64")]
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_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)
Copy link
Member

Choose a reason for hiding this comment

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

这些逻辑不应该放在这里。应到放在do_link_at

{
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;
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 @@ -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
Expand All @@ -84,6 +85,8 @@

#define SYS_UNLINK_AT 263

#define SYS_LINKAT 265

#define SYS_PIPE 293

#define SYS_WRITEV 20
Expand Down