-
-
Notifications
You must be signed in to change notification settings - Fork 161
实现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 all 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 |
---|---|---|
|
@@ -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 { | ||
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); | ||
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. 同理,因为check_and_clone_str会自动截断。 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. 我个人认为这个只检查是否等于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) | ||
} | ||
|
||
/// **删除文件夹、取消文件的链接、删除文件的系统调用** | ||
/// | ||
/// ## 参数 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 => { | ||
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 = 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; | ||
|
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.
这两个if是不必要的。