完善pipe系统调用以及openat系统调用 (#441)

This commit is contained in:
LoGin 2023-11-15 15:39:35 +08:00 committed by GitHub
parent bf4a48994a
commit 0fb515b011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 303 additions and 126 deletions

View File

@ -23,6 +23,7 @@ pub const SYS_FCHMOD: usize = 91;
pub const SYS_UMASK: usize = 95;
pub const SYS_SYSINFO: usize = 99;
pub const SYS_CLOCK_GETTIME: usize = 228;
pub const SYS_OPENAT: usize = 257;
pub const SYS_FCHMODAT: usize = 268;
pub const SYS_FACCESSAT: usize = 269;
pub const SYS_PRLIMIT64: usize = 302;

View File

@ -218,7 +218,7 @@ pub fn do_remove_dir(dirfd: i32, path: &str) -> Result<u64, SystemError> {
}
let pcb = ProcessManager::current_pcb();
let (inode_begin, remain_path) = user_path_at(&pcb, dirfd, path.to_string())?;
let (inode_begin, remain_path) = user_path_at(&pcb, dirfd, path)?;
let inode: Result<Arc<dyn IndexNode>, SystemError> =
inode_begin.lookup_follow_symlink(remain_path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES);
@ -258,7 +258,7 @@ pub fn do_unlink_at(dirfd: i32, path: &str) -> Result<u64, SystemError> {
return Err(SystemError::ENAMETOOLONG);
}
let pcb = ProcessManager::current_pcb();
let (inode_begin, remain_path) = user_path_at(&pcb, dirfd, path.to_string())?;
let (inode_begin, remain_path) = user_path_at(&pcb, dirfd, path)?;
let inode: Result<Arc<dyn IndexNode>, SystemError> =
inode_begin.lookup_follow_symlink(&remain_path, VFS_MAX_FOLLOW_SYMLINK_TIMES);

View File

@ -46,45 +46,49 @@ bitflags! {
/// 与Linux 5.19.10的uapi/asm-generic/fcntl.h相同
/// https://opengrok.ringotek.cn/xref/linux-5.19.10/tools/include/uapi/asm-generic/fcntl.h#19
pub struct FileMode: u32{
/* File access modes for `open' and `fcntl'. */
/// Open Read-only
const O_RDONLY = 0o0;
/// Open Write-only
const O_WRONLY = 0o1;
/// Open read/write
const O_RDWR = 0o2;
/// Mask for file access modes
const O_ACCMODE = 0o00000003;
/* File access modes for `open' and `fcntl'. */
/// Open Read-only
const O_RDONLY = 0o0;
/// Open Write-only
const O_WRONLY = 0o1;
/// Open read/write
const O_RDWR = 0o2;
/// Mask for file access modes
const O_ACCMODE = 0o00000003;
/* Bits OR'd into the second argument to open. */
/// Create file if it does not exist
const O_CREAT = 0o00000100;
/// Fail if file already exists
const O_EXCL = 0o00000200;
/// Do not assign controlling terminal
const O_NOCTTY = 0o00000400;
/// 文件存在且是普通文件并以O_RDWR或O_WRONLY打开则它会被清空
const O_TRUNC = 0o00001000;
/// 文件指针会被移动到文件末尾
const O_APPEND = 0o00002000;
/// 非阻塞式IO模式
const O_NONBLOCK = 0o00004000;
/// 每次write都等待物理I/O完成但是如果写操作不影响读取刚写入的数据则不等待文件属性更新
const O_DSYNC = 0o00010000;
/// fcntl, for BSD compatibility
const FASYNC = 0o00020000;
/* direct disk access hint */
const O_DIRECT = 0o00040000;
const O_LARGEFILE = 0o00100000;
/// 打开的必须是一个目录
const O_DIRECTORY = 0o00200000;
/// Do not follow symbolic links
const O_NOFOLLOW = 0o00400000;
const O_NOATIME = 0o01000000;
/// set close_on_exec
const O_CLOEXEC = 0o02000000;
/// 每次write都等到物理I/O完成包括write引起的文件属性的更新
const O_SYNC = 0o04000000;
/* Bits OR'd into the second argument to open. */
/// Create file if it does not exist
const O_CREAT = 0o00000100;
/// Fail if file already exists
const O_EXCL = 0o00000200;
/// Do not assign controlling terminal
const O_NOCTTY = 0o00000400;
/// 文件存在且是普通文件并以O_RDWR或O_WRONLY打开则它会被清空
const O_TRUNC = 0o00001000;
/// 文件指针会被移动到文件末尾
const O_APPEND = 0o00002000;
/// 非阻塞式IO模式
const O_NONBLOCK = 0o00004000;
/// 每次write都等待物理I/O完成但是如果写操作不影响读取刚写入的数据则不等待文件属性更新
const O_DSYNC = 0o00010000;
/// fcntl, for BSD compatibility
const FASYNC = 0o00020000;
/* direct disk access hint */
const O_DIRECT = 0o00040000;
const O_LARGEFILE = 0o00100000;
/// 打开的必须是一个目录
const O_DIRECTORY = 0o00200000;
/// Do not follow symbolic links
const O_NOFOLLOW = 0o00400000;
const O_NOATIME = 0o01000000;
/// set close_on_exec
const O_CLOEXEC = 0o02000000;
/// 每次write都等到物理I/O完成包括write引起的文件属性的更新
const O_SYNC = 0o04000000;
const O_PATH = 0o10000000;
const O_PATH_FLAGS = Self::O_DIRECTORY.bits|Self::O_NOFOLLOW.bits|Self::O_CLOEXEC.bits|Self::O_PATH.bits;
}
}

View File

@ -1,11 +1,17 @@
use alloc::sync::Arc;
use crate::{
driver::base::block::SeekFrom,
process::ProcessManager,
syscall::{user_access::check_and_clone_cstr, SystemError},
};
use super::{
fcntl::AtFlags, syscall::ModeType, utils::user_path_at, MAX_PATHLEN,
VFS_MAX_FOLLOW_SYMLINK_TIMES,
fcntl::AtFlags,
file::{File, FileMode},
syscall::{ModeType, OpenHow, OpenHowResolve},
utils::{rsplit_path, user_path_at},
FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
};
pub(super) fn do_faccessat(
@ -34,7 +40,7 @@ pub(super) fn do_faccessat(
return Err(SystemError::EINVAL);
}
let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, &path)?;
// 如果找不到文件则返回错误码ENOENT
let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
@ -50,7 +56,7 @@ pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize
return Err(SystemError::EINVAL);
}
let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, &path)?;
// 如果找不到文件则返回错误码ENOENT
let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
@ -60,3 +66,93 @@ pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize
return Ok(0);
}
pub(super) fn do_sys_open(
dfd: i32,
path: &str,
o_flags: FileMode,
mode: ModeType,
follow_symlink: bool,
) -> Result<usize, SystemError> {
let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty());
return do_sys_openat2(dfd, path, how, follow_symlink);
}
fn do_sys_openat2(
dirfd: i32,
path: &str,
how: OpenHow,
follow_symlink: bool,
) -> Result<usize, SystemError> {
// kdebug!("open: path: {}, mode: {:?}", path, mode);
// 文件名过长
if path.len() > MAX_PATHLEN as usize {
return Err(SystemError::ENAMETOOLONG);
}
let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink(
&path,
if follow_symlink {
VFS_MAX_FOLLOW_SYMLINK_TIMES
} else {
0
},
);
let inode: Arc<dyn IndexNode> = if inode.is_err() {
let errno = inode.unwrap_err();
// 文件不存在,且需要创建
if how.o_flags.contains(FileMode::O_CREAT)
&& !how.o_flags.contains(FileMode::O_DIRECTORY)
&& errno == SystemError::ENOENT
{
let (filename, parent_path) = rsplit_path(&path);
// 查找父目录
let parent_inode: Arc<dyn IndexNode> =
ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
// 创建文件
let inode: Arc<dyn IndexNode> = parent_inode.create(
filename,
FileType::File,
ModeType::from_bits_truncate(0o755),
)?;
inode
} else {
// 不需要创建文件,因此返回错误码
return Err(errno);
}
} else {
inode.unwrap()
};
let file_type: FileType = inode.metadata()?.file_type;
// 如果要打开的是文件夹,而目标不是文件夹
if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
return Err(SystemError::ENOTDIR);
}
// 创建文件对象
let mut file: File = File::new(inode, how.o_flags)?;
// 打开模式为“追加”
if how.o_flags.contains(FileMode::O_APPEND) {
file.lseek(SeekFrom::SeekEnd(0))?;
}
// 如果O_TRUNC并且打开模式包含O_RDWR或O_WRONLY清空文件
if how.o_flags.contains(FileMode::O_TRUNC)
&& (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY))
&& file_type == FileType::File
{
file.ftruncate(0)?;
}
// 把文件对象存入pcb
let r = ProcessManager::current_pcb()
.fd_table()
.write()
.alloc_fd(file, None)
.map(|fd| fd as usize);
return r;
}

View File

@ -25,7 +25,7 @@ use super::{
core::{do_mkdir, do_remove_dir, do_unlink_at},
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
file::{File, FileMode},
open::{do_faccessat, do_fchmodat},
open::{do_faccessat, do_fchmodat, do_sys_open},
utils::{rsplit_path, user_path_at},
Dirent, FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
};
@ -146,6 +146,100 @@ impl PosixKstat {
}
}
}
///
/// Arguments for how openat2(2) should open the target path. If only @flags and
/// @mode are non-zero, then openat2(2) operates very similarly to openat(2).
///
/// However, unlike openat(2), unknown or invalid bits in @flags result in
/// -EINVAL rather than being silently ignored. @mode must be zero unless one of
/// {O_CREAT, O_TMPFILE} are set.
///
/// ## 成员变量
///
/// - flags: O_* flags.
/// - mode: O_CREAT/O_TMPFILE file mode.
/// - resolve: RESOLVE_* flags.
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct PosixOpenHow {
pub flags: u64,
pub mode: u64,
pub resolve: u64,
}
impl PosixOpenHow {
#[allow(dead_code)]
pub fn new(flags: u64, mode: u64, resolve: u64) -> Self {
Self {
flags,
mode,
resolve,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct OpenHow {
pub o_flags: FileMode,
pub mode: ModeType,
pub resolve: OpenHowResolve,
}
impl OpenHow {
pub fn new(mut o_flags: FileMode, mut mode: ModeType, resolve: OpenHowResolve) -> Self {
if !o_flags.contains(FileMode::O_CREAT) {
mode = ModeType::empty();
}
if o_flags.contains(FileMode::O_PATH) {
o_flags = o_flags.intersection(FileMode::O_PATH_FLAGS);
}
Self {
o_flags,
mode,
resolve,
}
}
}
impl From<PosixOpenHow> for OpenHow {
fn from(posix_open_how: PosixOpenHow) -> Self {
let o_flags = FileMode::from_bits_truncate(posix_open_how.flags as u32);
let mode = ModeType::from_bits_truncate(posix_open_how.mode as u32);
let resolve = OpenHowResolve::from_bits_truncate(posix_open_how.resolve as u64);
return Self::new(o_flags, mode, resolve);
}
}
bitflags! {
pub struct OpenHowResolve: u64{
/// Block mount-point crossings
/// (including bind-mounts).
const RESOLVE_NO_XDEV = 0x01;
/// Block traversal through procfs-style
/// "magic-links"
const RESOLVE_NO_MAGICLINKS = 0x02;
/// Block traversal through all symlinks
/// (implies OEXT_NO_MAGICLINKS)
const RESOLVE_NO_SYMLINKS = 0x04;
/// Block "lexical" trickery like
/// "..", symlinks, and absolute
const RESOLVE_BENEATH = 0x08;
/// Make all jumps to "/" and ".."
/// be scoped inside the dirfd
/// (similar to chroot(2)).
const RESOLVE_IN_ROOT = 0x10;
// Only complete if resolution can be
// completed through cached lookup. May
// return -EAGAIN if that's not
// possible.
const RESOLVE_CACHED = 0x20;
}
}
impl Syscall {
/// @brief 为当前进程打开一个文件
///
@ -153,78 +247,23 @@ impl Syscall {
/// @param o_flags 打开文件的标志位
///
/// @return 文件描述符编号,或者是错误码
pub fn open(path: &str, mode: FileMode, follow_symlink: bool) -> Result<usize, SystemError> {
// kdebug!("open: path: {}, mode: {:?}", path, mode);
// 文件名过长
if path.len() > MAX_PATHLEN as usize {
return Err(SystemError::ENAMETOOLONG);
}
pub fn open(
path: &str,
flags: FileMode,
mode: ModeType,
follow_symlink: bool,
) -> Result<usize, SystemError> {
return do_sys_open(AtFlags::AT_FDCWD.bits(), path, flags, mode, follow_symlink);
}
let inode: Result<Arc<dyn IndexNode>, SystemError> = ROOT_INODE().lookup_follow_symlink(
path,
if follow_symlink {
VFS_MAX_FOLLOW_SYMLINK_TIMES
} else {
0
},
);
let inode: Arc<dyn IndexNode> = if inode.is_err() {
let errno = inode.unwrap_err();
// 文件不存在,且需要创建
if mode.contains(FileMode::O_CREAT)
&& !mode.contains(FileMode::O_DIRECTORY)
&& errno == SystemError::ENOENT
{
let (filename, parent_path) = rsplit_path(path);
// 查找父目录
let parent_inode: Arc<dyn IndexNode> =
ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
// 创建文件
let inode: Arc<dyn IndexNode> = parent_inode.create(
filename,
FileType::File,
ModeType::from_bits_truncate(0o755),
)?;
inode
} else {
// 不需要创建文件,因此返回错误码
return Err(errno);
}
} else {
inode.unwrap()
};
let file_type: FileType = inode.metadata()?.file_type;
// 如果要打开的是文件夹,而目标不是文件夹
if mode.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
return Err(SystemError::ENOTDIR);
}
// 创建文件对象
let mut file: File = File::new(inode, mode)?;
// 打开模式为“追加”
if mode.contains(FileMode::O_APPEND) {
file.lseek(SeekFrom::SeekEnd(0))?;
}
// 如果O_TRUNC并且打开模式包含O_RDWR或O_WRONLY清空文件
if mode.contains(FileMode::O_TRUNC)
&& (mode.contains(FileMode::O_RDWR) || mode.contains(FileMode::O_WRONLY))
&& file_type == FileType::File
{
file.ftruncate(0)?;
}
// 把文件对象存入pcb
let r = ProcessManager::current_pcb()
.fd_table()
.write()
.alloc_fd(file, None)
.map(|fd| fd as usize);
return r;
pub fn openat(
dirfd: i32,
path: &str,
o_flags: FileMode,
mode: ModeType,
follow_symlink: bool,
) -> Result<usize, SystemError> {
return do_sys_open(dirfd, path, o_flags, mode, follow_symlink);
}
/// @brief 关闭文件
@ -764,14 +803,14 @@ impl Syscall {
}
pub fn stat(path: &str, user_kstat: *mut PosixKstat) -> Result<usize, SystemError> {
let fd = Self::open(path, FileMode::O_RDONLY, true)?;
let fd = Self::open(path, FileMode::O_RDONLY, ModeType::empty(), true)?;
let r = Self::fstat(fd as i32, user_kstat);
Self::close(fd).ok();
return r;
}
pub fn lstat(path: &str, user_kstat: *mut PosixKstat) -> Result<usize, SystemError> {
let fd = Self::open(path, FileMode::O_RDONLY, false)?;
let fd = Self::open(path, FileMode::O_RDONLY, ModeType::empty(), false)?;
let r = Self::fstat(fd as i32, user_kstat);
Self::close(fd).ok();
return r;
@ -847,7 +886,7 @@ impl Syscall {
return Err(SystemError::EINVAL);
}
let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, &path)?;
let inode = inode.lookup(path.as_str())?;
if inode.metadata()?.file_type != FileType::SymLink {

View File

@ -35,9 +35,10 @@ pub fn rsplit_path(path: &str) -> (&str, Option<&str>) {
pub fn user_path_at(
pcb: &Arc<ProcessControlBlock>,
dirfd: i32,
mut path: String,
path: &str,
) -> Result<(Arc<dyn IndexNode>, String), SystemError> {
let mut inode = ROOT_INODE();
let ret_path;
// 如果path不是绝对路径则需要拼接
if path.as_bytes()[0] != b'/' {
// 如果dirfd不是AT_FDCWD则需要检查dirfd是否是目录
@ -58,13 +59,16 @@ pub fn user_path_at(
}
inode = file_guard.inode();
ret_path = String::from(path);
} else {
let mut cwd = pcb.basic().cwd();
cwd.push('/');
cwd.push_str(path.as_str());
path = cwd;
cwd.push_str(path);
ret_path = cwd;
}
} else {
ret_path = String::from(path);
}
return Ok((inode, path));
return Ok((inode, ret_path));
}

View File

@ -6,7 +6,8 @@ use core::{
use crate::{
arch::syscall::{
SYS_ACCESS, SYS_CHMOD, SYS_CLOCK_GETTIME, SYS_FACCESSAT, SYS_FACCESSAT2, SYS_FCHMOD,
SYS_FCHMODAT, SYS_LSTAT, SYS_PRLIMIT64, SYS_READV, SYS_SYSINFO, SYS_UMASK, SYS_UNLINK,
SYS_FCHMODAT, SYS_LSTAT, SYS_OPENAT, SYS_PRLIMIT64, SYS_READV, SYS_SYSINFO, SYS_UMASK,
SYS_UNLINK,
},
libs::{futex::constant::FutexFlag, rand::GRandFlags},
process::{
@ -367,6 +368,7 @@ pub const SYS_RT_SIGRETURN: usize = 15;
pub const SYS_IOCTL: usize = 16;
pub const SYS_WRITEV: usize = 20;
pub const SYS_PIPE: usize = 22;
pub const SYS_MADVISE: usize = 28;
@ -456,7 +458,7 @@ pub const SYS_READLINK_AT: usize = 267;
pub const SYS_ACCEPT4: usize = 288;
pub const SYS_PIPE: usize = 293;
pub const SYS_PIPE2: usize = 293;
#[allow(dead_code)]
pub const SYS_GET_RANDOM: usize = 318;
@ -515,8 +517,31 @@ impl Syscall {
let path: &str = path.unwrap();
let flags = args[1];
let mode = args[2];
let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32);
Self::open(path, open_flags, true)
let mode = ModeType::from_bits(mode as u32).ok_or(SystemError::EINVAL)?;
Self::open(path, open_flags, mode, true)
};
res
}
SYS_OPENAT => {
let dirfd = args[0] as i32;
let path: &CStr = unsafe { CStr::from_ptr(args[1] as *const c_char) };
let flags = args[2];
let mode = args[3];
let path: Result<&str, core::str::Utf8Error> = path.to_str();
let res = if path.is_err() {
Err(SystemError::EINVAL)
} else {
let path: &str = path.unwrap();
let open_flags: FileMode =
FileMode::from_bits(flags as u32).ok_or(SystemError::EINVAL)?;
let mode = ModeType::from_bits(mode as u32).ok_or(SystemError::EINVAL)?;
Self::openat(dirfd, path, open_flags, mode, true)
};
res
}
@ -725,6 +750,14 @@ impl Syscall {
SYS_CLOCK => Self::clock(),
SYS_PIPE => {
let pipefd: *mut i32 = args[0] as *mut c_int;
if pipefd.is_null() {
Err(SystemError::EFAULT)
} else {
Self::pipe2(pipefd, FileMode::empty())
}
}
SYS_PIPE2 => {
let pipefd: *mut i32 = args[0] as *mut c_int;
let arg1 = args[1];
if pipefd.is_null() {