mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-10 03:56:49 +00:00
feat: sys_readlink && sys_readlinkat (#436)
This commit is contained in:
parent
be8cdf4b8e
commit
709498cac1
@ -58,5 +58,57 @@ pub enum FcntlCommand {
|
|||||||
SetFileRwHint = F_LINUX_SPECIFIC_BASE + 14,
|
SetFileRwHint = F_LINUX_SPECIFIC_BASE + 14,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is
|
||||||
|
/// meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
|
||||||
|
/// unlinkat. The two functions do completely different things and therefore,
|
||||||
|
/// the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to
|
||||||
|
/// faccessat would be undefined behavior and thus treating it equivalent to
|
||||||
|
/// AT_EACCESS is valid undefined behavior.
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum AtFlags {
|
||||||
|
/// 特殊值,用于指示openat应使用当前工作目录。
|
||||||
|
AtFdCwd = -100,
|
||||||
|
/// 不要跟随符号链接。
|
||||||
|
/// AT_SYMLINK_NOFOLLOW: 0x100
|
||||||
|
AtSymlinkNoFollow = 0x100,
|
||||||
|
/// AtEAccess: 使用有效ID进行访问测试,而不是实际ID。
|
||||||
|
/// AtRemoveDir: 删除目录而不是取消链接文件。
|
||||||
|
/// AT_EACCESS: 0x200
|
||||||
|
/// AT_REMOVEDIR: 0x200
|
||||||
|
AtEAccess_OR_AtRemoveDir = 0x200,
|
||||||
|
|
||||||
|
/// 跟随符号链接。
|
||||||
|
/// AT_SYMLINK_FOLLOW: 0x400
|
||||||
|
AtSymlinkFollow = 0x400,
|
||||||
|
/// 禁止终端自动挂载遍历。
|
||||||
|
/// AT_NO_AUTOMOUNT: 0x800
|
||||||
|
AtNoAutomount = 0x800,
|
||||||
|
/// 允许空的相对路径名。
|
||||||
|
/// AT_EMPTY_PATH: 0x1000
|
||||||
|
AtEmptyPath = 0x1000,
|
||||||
|
/// statx()所需的同步类型。
|
||||||
|
/// AT_STATX_SYNC_TYPE: 0x6000
|
||||||
|
AtStatxSyncType = 0x6000,
|
||||||
|
/// 执行与stat()相同的操作。
|
||||||
|
/// AT_STATX_SYNC_AS_STAT: 0x0000
|
||||||
|
AtStatxSyncAsStat = 0x0000,
|
||||||
|
/// 强制将属性与服务器同步。
|
||||||
|
/// AT_STATX_FORCE_SYNC: 0x2000
|
||||||
|
AtStatxForceSync = 0x2000,
|
||||||
|
/// 不要将属性与服务器同步。
|
||||||
|
/// AT_STATX_DONT_SYNC: 0x4000
|
||||||
|
AtStatxDontSync = 0x4000,
|
||||||
|
/// 应用于整个子树。
|
||||||
|
/// AT_RECURSIVE: 0x8000
|
||||||
|
AtRecursive = 0x8000,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<i32> for AtFlags {
|
||||||
|
fn into(self) -> i32 {
|
||||||
|
self as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// for F_[GET|SET]FL
|
/// for F_[GET|SET]FL
|
||||||
pub const FD_CLOEXEC: u32 = 1;
|
pub const FD_CLOEXEC: u32 = 1;
|
||||||
|
@ -14,13 +14,16 @@ use crate::{
|
|||||||
libs::rwlock::RwLockWriteGuard,
|
libs::rwlock::RwLockWriteGuard,
|
||||||
mm::VirtAddr,
|
mm::VirtAddr,
|
||||||
process::ProcessManager,
|
process::ProcessManager,
|
||||||
syscall::{user_access::UserBufferReader, Syscall, SystemError},
|
syscall::{
|
||||||
|
user_access::{check_and_clone_cstr, UserBufferReader, UserBufferWriter},
|
||||||
|
Syscall, SystemError,
|
||||||
|
},
|
||||||
time::TimeSpec,
|
time::TimeSpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
core::{do_mkdir, do_remove_dir, do_unlink_at},
|
core::{do_mkdir, do_remove_dir, do_unlink_at},
|
||||||
fcntl::{FcntlCommand, FD_CLOEXEC},
|
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
|
||||||
file::{File, FileMode},
|
file::{File, FileMode},
|
||||||
utils::rsplit_path,
|
utils::rsplit_path,
|
||||||
Dirent, FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
Dirent, FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||||
@ -794,7 +797,72 @@ impl Syscall {
|
|||||||
|
|
||||||
Self::write(fd, &data)
|
Self::write(fd, &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn readlink_at(
|
||||||
|
dirfd: i32,
|
||||||
|
path: *const u8,
|
||||||
|
user_buf: *mut u8,
|
||||||
|
buf_size: usize,
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
let mut path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
|
||||||
|
let mut user_buf = UserBufferWriter::new(user_buf, buf_size, true)?;
|
||||||
|
|
||||||
|
if path.len() == 0 {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut inode = ROOT_INODE();
|
||||||
|
// 如果path不是绝对路径,则需要拼接
|
||||||
|
if path.as_bytes()[0] != b'/' {
|
||||||
|
// 如果dirfd不是AT_FDCWD,则需要检查dirfd是否是目录
|
||||||
|
if dirfd != AtFlags::AtFdCwd.into() {
|
||||||
|
let binding = ProcessManager::current_pcb().fd_table();
|
||||||
|
let fd_table_guard = binding.read();
|
||||||
|
let file = fd_table_guard
|
||||||
|
.get_file_by_fd(dirfd)
|
||||||
|
.ok_or(SystemError::EBADF)?;
|
||||||
|
|
||||||
|
// drop guard 以避免无法调度的问题
|
||||||
|
drop(fd_table_guard);
|
||||||
|
|
||||||
|
let file_guard = file.lock();
|
||||||
|
// 如果dirfd不是目录,则返回错误码ENOTDIR
|
||||||
|
if file_guard.file_type() != FileType::Dir {
|
||||||
|
return Err(SystemError::ENOTDIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
inode = file_guard.inode();
|
||||||
|
} else {
|
||||||
|
let mut cwd = ProcessManager::current_pcb().basic().cwd();
|
||||||
|
cwd.push('/');
|
||||||
|
cwd.push_str(path.as_str());
|
||||||
|
path = cwd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let inode = inode.lookup(path.as_str())?;
|
||||||
|
if inode.metadata()?.file_type != FileType::SymLink {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ubuf = user_buf.buffer::<u8>(0).unwrap();
|
||||||
|
|
||||||
|
let mut file = File::new(inode, FileMode::O_RDONLY)?;
|
||||||
|
|
||||||
|
let len = file.read(buf_size, ubuf)?;
|
||||||
|
|
||||||
|
return Ok(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn readlink(
|
||||||
|
path: *const u8,
|
||||||
|
user_buf: *mut u8,
|
||||||
|
buf_size: usize,
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
return Self::readlink_at(AtFlags::AtFdCwd.into(), path, user_buf, buf_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct IoVec {
|
pub struct IoVec {
|
||||||
|
@ -399,6 +399,8 @@ pub const SYS_CHDIR: usize = 80;
|
|||||||
|
|
||||||
pub const SYS_MKDIR: usize = 83;
|
pub const SYS_MKDIR: usize = 83;
|
||||||
|
|
||||||
|
pub const SYS_READLINK: usize = 89;
|
||||||
|
|
||||||
pub const SYS_GETTIMEOFDAY: usize = 96;
|
pub const SYS_GETTIMEOFDAY: usize = 96;
|
||||||
pub const SYS_GETRUSAGE: usize = 98;
|
pub const SYS_GETRUSAGE: usize = 98;
|
||||||
|
|
||||||
@ -437,6 +439,8 @@ pub const SYS_EXIT_GROUP: usize = 231;
|
|||||||
|
|
||||||
pub const SYS_UNLINK_AT: usize = 263;
|
pub const SYS_UNLINK_AT: usize = 263;
|
||||||
|
|
||||||
|
pub const SYS_READLINK_AT: usize = 267;
|
||||||
|
|
||||||
pub const SYS_ACCEPT4: usize = 288;
|
pub const SYS_ACCEPT4: usize = 288;
|
||||||
|
|
||||||
pub const SYS_PIPE: usize = 293;
|
pub const SYS_PIPE: usize = 293;
|
||||||
@ -1171,6 +1175,22 @@ impl Syscall {
|
|||||||
Self::get_rusage(who, rusage)
|
Self::get_rusage(who, rusage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SYS_READLINK =>{
|
||||||
|
let path = args[0] as *const u8;
|
||||||
|
let buf = args[1] as *mut u8;
|
||||||
|
let bufsiz = args[2] as usize;
|
||||||
|
Self::readlink(path, buf, bufsiz)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_READLINK_AT =>{
|
||||||
|
let dirfd = args[0] as i32;
|
||||||
|
let pathname = args[1] as *const u8;
|
||||||
|
let buf = args[2] as *mut u8;
|
||||||
|
let bufsiz = args[3] as usize;
|
||||||
|
Self::readlink_at(dirfd, pathname, buf, bufsiz)
|
||||||
|
}
|
||||||
|
|
||||||
_ => panic!("Unsupported syscall ID: {}", syscall_num),
|
_ => panic!("Unsupported syscall ID: {}", syscall_num),
|
||||||
};
|
};
|
||||||
return r;
|
return r;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user