-
-
Notifications
You must be signed in to change notification settings - Fork 158
实现SYS_LINK和SYS_LINKAT #611
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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<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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 返回值是eperm吗?有无linux man7的文档。看看这种情况应当返回什么内容。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
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)?; | ||
|
||
// 在下层检查是否处于同一文件系统 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
} | ||
|
||
/// **删除文件夹、取消文件的链接、删除文件的系统调用** | ||
/// | ||
/// ## 参数 | ||
|
@@ -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); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,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))?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个作为内部的函数,flags应当是Atflags类型,而不是i32