Add correct stat syscall support

This commit is contained in:
LI Qing 2023-02-20 13:51:25 +08:00 committed by Tate, Hongliang Tian
parent 036f75505d
commit 116b687cae
10 changed files with 217 additions and 138 deletions

View File

@ -2,7 +2,7 @@ use crate::prelude::*;
use crate::tty::get_n_tty;
use core::any::Any;
use crate::fs::utils::{IoEvents, IoctlCmd};
use crate::fs::utils::{IoEvents, IoctlCmd, Metadata};
/// The basic operations defined on a file
pub trait File: Send + Sync + Any {
@ -32,4 +32,8 @@ pub trait File: Send + Sync + Any {
fn flush(&self) -> Result<()> {
Ok(())
}
fn metadata(&self) -> Metadata {
panic!("metadata unsupported");
}
}

View File

@ -3,10 +3,10 @@
mod file;
mod inode_handle;
use crate::fs::utils::Metadata;
use crate::prelude::*;
use crate::rights::{ReadOp, WriteOp};
use alloc::sync::Arc;
use core::ops::Range;
pub use self::file::File;
pub use self::inode_handle::InodeHandle;
@ -67,6 +67,13 @@ impl FileHandle {
}
}
pub fn metadata(&self) -> Metadata {
match &self.inner {
Inner::File(file) => file.metadata(),
Inner::Inode(inode_handle) => inode_handle.dentry().vnode().inode().metadata(),
}
}
pub fn clean_for_close(&self) -> Result<()> {
match &self.inner {
Inner::Inode(inode_handle) => {

View File

@ -19,12 +19,14 @@ pub struct RamFS {
impl RamFS {
pub fn new() -> Arc<Self> {
let sb = SuperBlock::new(RAMFS_MAGIC, BLOCK_SIZE, NAME_MAX);
let root = Arc::new(RamInode(RwLock::new(Inode_::new_dir(
ROOT_INO,
InodeMode::from_bits_truncate(0o755),
&sb,
))));
let ramfs = Arc::new(Self {
metadata: RwLock::new(SuperBlock::new(RAMFS_MAGIC, BLOCK_SIZE, NAME_MAX)),
metadata: RwLock::new(sb),
root,
inode_allocator: AtomicUsize::new(ROOT_INO + 1),
});
@ -71,28 +73,28 @@ struct Inode_ {
}
impl Inode_ {
pub fn new_dir(ino: usize, mode: InodeMode) -> Self {
pub fn new_dir(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self {
Self {
inner: Inner::Dir(DirEntry::new()),
metadata: Metadata::new_dir(ino, mode),
metadata: Metadata::new_dir(ino, mode, sb),
this: Weak::default(),
fs: Weak::default(),
}
}
pub fn new_file(ino: usize, mode: InodeMode) -> Self {
pub fn new_file(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self {
Self {
inner: Inner::File,
metadata: Metadata::new_file(ino, mode),
metadata: Metadata::new_file(ino, mode, sb),
this: Weak::default(),
fs: Weak::default(),
}
}
pub fn new_symlink(ino: usize, mode: InodeMode) -> Self {
pub fn new_symlink(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self {
Self {
inner: Inner::SymLink(Str256::from("")),
metadata: Metadata::new_synlink(ino, mode),
metadata: Metadata::new_symlink(ino, mode, sb),
this: Weak::default(),
fs: Weak::default(),
}
@ -315,19 +317,22 @@ impl Inode for RamInode {
if self_inode.inner.as_direntry().unwrap().contains_entry(name) {
return_errno_with_message!(Errno::EEXIST, "entry exists");
}
let fs = self_inode.fs.upgrade().unwrap();
let new_inode = match type_ {
InodeType::File => {
let file_inode = Arc::new(RamInode(RwLock::new(Inode_::new_file(
self_inode.fs.upgrade().unwrap().alloc_id(),
fs.alloc_id(),
mode,
&fs.sb(),
))));
file_inode.0.write().fs = self_inode.fs.clone();
file_inode
}
InodeType::Dir => {
let dir_inode = Arc::new(RamInode(RwLock::new(Inode_::new_dir(
self_inode.fs.upgrade().unwrap().alloc_id(),
fs.alloc_id(),
mode,
&fs.sb(),
))));
dir_inode.0.write().fs = self_inode.fs.clone();
dir_inode.0.write().inner.as_direntry_mut().unwrap().init(
@ -338,8 +343,9 @@ impl Inode for RamInode {
}
InodeType::SymLink => {
let sym_inode = Arc::new(RamInode(RwLock::new(Inode_::new_symlink(
self_inode.fs.upgrade().unwrap().alloc_id(),
fs.alloc_id(),
mode,
&fs.sb(),
))));
sym_inode.0.write().fs = self_inode.fs.clone();
sym_inode

View File

@ -3,7 +3,7 @@ use crate::tty::{get_n_tty, Tty};
use super::file_handle::File;
use super::file_table::FileDescripter;
use super::utils::IoEvents;
use super::utils::{InodeMode, InodeType, IoEvents, Metadata};
pub const FD_STDIN: FileDescripter = 0;
pub const FD_STDOUT: FileDescripter = 1;
@ -45,6 +45,25 @@ impl File for Stdin {
todo!()
}
}
fn metadata(&self) -> Metadata {
Metadata {
dev: 0,
ino: 0,
size: 0,
blk_size: 1024,
blocks: 0,
atime: Default::default(),
mtime: Default::default(),
ctime: Default::default(),
type_: InodeType::CharDevice,
mode: InodeMode::from_bits_truncate(0o620),
nlinks: 1,
uid: 0,
gid: 0,
rdev: 0,
}
}
}
impl File for Stdout {
fn ioctl(&self, cmd: super::utils::IoctlCmd, arg: usize) -> Result<i32> {
@ -62,6 +81,25 @@ impl File for Stdout {
todo!()
}
}
fn metadata(&self) -> Metadata {
Metadata {
dev: 0,
ino: 0,
size: 0,
blk_size: 1024,
blocks: 0,
atime: Default::default(),
mtime: Default::default(),
ctime: Default::default(),
type_: InodeType::CharDevice,
mode: InodeMode::from_bits_truncate(0o620),
nlinks: 1,
uid: 0,
gid: 0,
rdev: 0,
}
}
}
impl File for Stderr {
@ -80,6 +118,25 @@ impl File for Stderr {
todo!()
}
}
fn metadata(&self) -> Metadata {
Metadata {
dev: 0,
ino: 0,
size: 0,
blk_size: 1024,
blocks: 0,
atime: Default::default(),
mtime: Default::default(),
ctime: Default::default(),
type_: InodeType::CharDevice,
mode: InodeMode::from_bits_truncate(0o620),
nlinks: 1,
uid: 0,
gid: 0,
rdev: 0,
}
}
}
impl Stdin {

View File

@ -4,17 +4,19 @@ use bitflags::bitflags;
use core::any::Any;
use jinux_frame::vm::VmFrame;
use super::{DirentWriterContext, FileSystem, IoctlCmd};
use super::{DirentWriterContext, FileSystem, IoctlCmd, SuperBlock};
use crate::prelude::*;
#[repr(u32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum InodeType {
File = 1,
Dir = 2,
SymLink = 3,
CharDevice = 4,
BlockDevice = 5,
NamedPipe = 0o010000,
CharDevice = 0o020000,
Dir = 0o040000,
BlockDevice = 0o060000,
File = 0o100000,
SymLink = 0o120000,
Socket = 0o140000,
}
bitflags! {
@ -91,12 +93,12 @@ pub struct Metadata {
}
impl Metadata {
pub fn new_dir(ino: usize, mode: InodeMode) -> Self {
pub fn new_dir(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self {
Self {
dev: 0,
ino,
size: 2,
blk_size: 0,
blk_size: sb.bsize,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
@ -110,12 +112,12 @@ impl Metadata {
}
}
pub fn new_file(ino: usize, mode: InodeMode) -> Self {
pub fn new_file(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self {
Self {
dev: 0,
ino,
size: 0,
blk_size: 0,
blk_size: sb.bsize,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
@ -129,12 +131,12 @@ impl Metadata {
}
}
pub fn new_synlink(ino: usize, mode: InodeMode) -> Self {
pub fn new_symlink(ino: usize, mode: InodeMode, sb: &SuperBlock) -> Self {
Self {
dev: 0,
ino,
size: 0,
blk_size: 0,
blk_size: sb.bsize,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
@ -149,7 +151,8 @@ impl Metadata {
}
}
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
#[derive(Default, Copy, Clone, Pod, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
#[repr(C)]
pub struct Timespec {
pub sec: i64,
pub nsec: i64,

View File

@ -1,15 +1,6 @@
#![allow(non_camel_case_types)]
type dev_t = usize;
type ino_t = usize;
type mode_t = u32;
type nlink_t = usize;
type uid_t = u32;
type gid_t = u32;
type off_t = u32;
type blksize_t = isize;
type blkcnt_t = isize;
type timespec = isize;
use super::{Metadata, Timespec};
pub const S_IFMT: u32 = 0o170000;
pub const S_IFCHR: u32 = 0o020000;
@ -22,59 +13,55 @@ pub const S_IFLNK: u32 = 0o120000;
#[repr(C)]
pub struct Stat {
/// ID of device containing file
st_dev: dev_t,
st_dev: usize,
/// Inode number
st_ino: ino_t,
/// File type and mode
st_mode: mode_t,
st_ino: usize,
/// Number of hard links
st_nlink: nlink_t,
st_nlink: usize,
/// File type and mode
st_mode: u32,
/// User ID of owner
st_uid: uid_t,
st_uid: u32,
/// Group ID of owner
st_gid: gid_t,
st_gid: u32,
/// Padding bytes
__pad0: u32,
/// Device ID (if special file)
st_rdev: dev_t,
st_rdev: usize,
/// Total size, in bytes
st_size: off_t,
st_size: isize,
/// Block size for filesystem I/O
st_blksize: blksize_t,
/// Number of 512B blocks allocated
st_blocks: blkcnt_t,
st_blksize: isize,
/// Number of 512-byte blocks allocated
st_blocks: isize,
/// Time of last access
st_atime: timespec,
st_atime: Timespec,
/// Time of last modification
st_mtime: timespec,
st_mtime: Timespec,
/// Time of last status change
st_ctime: timespec,
st_ctime: Timespec,
/// Unused field
__unused: [i64; 3],
}
impl Stat {
/// We use the same stat as linux
pub fn stdout_stat() -> Self {
let mut stat = Stat::default();
stat.st_mode = S_IFCHR | 0o620;
stat.st_nlink = 1;
stat.st_blksize = 1024;
stat
}
/// Fake stat for a dir
pub fn fake_dir_stat() -> Self {
let mut stat = Stat::default();
stat.st_mode = S_IFDIR | 0o755;
stat.st_nlink = 20;
stat.st_blksize = 4096;
stat
}
// Fake stat for /bin/stty
pub fn fake_stty_stat() -> Self {
let mut stat = Stat::default();
stat.st_mode = S_IFREG | 0o755;
stat.st_nlink = 1;
stat.st_blksize = 4096;
stat.st_size = 84344;
stat
impl From<Metadata> for Stat {
fn from(info: Metadata) -> Self {
Self {
st_dev: info.dev,
st_ino: info.ino,
st_nlink: info.nlinks,
st_mode: info.type_ as u32 | info.mode.bits() as u32,
st_uid: info.uid as u32,
st_gid: info.gid as u32,
__pad0: 0,
st_rdev: 0,
st_size: info.size as isize,
st_blksize: info.blk_size as isize,
st_blocks: info.blocks as isize,
st_atime: info.atime,
st_mtime: info.mtime,
st_ctime: info.ctime,
__unused: [0; 3],
}
}
}

View File

@ -1,21 +0,0 @@
use jinux_frame::vm::VmIo;
use crate::fs::utils::Stat;
use crate::{log_syscall_entry, prelude::*};
use crate::syscall::{SyscallReturn, SYS_FSTAT};
pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_FSTAT);
debug!("fd = {}, stat_buf_addr = 0x{:x}", fd, stat_buf_ptr);
let current = current!();
let root_vmar = current.root_vmar();
if fd == 1 {
let stat = Stat::stdout_stat();
root_vmar.write_val(stat_buf_ptr, &stat)?;
return Ok(SyscallReturn::Return(0));
}
// TODO: fstat only returns fake result now
Ok(SyscallReturn::Return(0))
}

View File

@ -1,25 +0,0 @@
use crate::fs::utils::Stat;
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::syscall::constants::MAX_FILENAME_LEN;
use crate::util::read_cstring_from_user;
use crate::util::write_val_to_user;
use super::SyscallReturn;
use super::SYS_LSTAT;
pub fn sys_lstat(filename_ptr: Vaddr, stat_buf_ptr: Vaddr) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_LSTAT);
let filename = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?;
debug!(
"filename = {:?}, stat_buf_ptr = 0x{:x}",
filename, stat_buf_ptr
);
// TODO: only return a fake result here
if filename == CString::new(".")? || filename == CString::new("/")? {
let stat = Stat::fake_dir_stat();
write_val_to_user(stat_buf_ptr, &stat)?;
return Ok(SyscallReturn::Return(0));
}
todo!()
}

View File

@ -12,7 +12,6 @@ use crate::syscall::exit::sys_exit;
use crate::syscall::exit_group::sys_exit_group;
use crate::syscall::fcntl::sys_fcntl;
use crate::syscall::fork::sys_fork;
use crate::syscall::fstat::sys_fstat;
use crate::syscall::futex::sys_futex;
use crate::syscall::getcwd::sys_getcwd;
use crate::syscall::getegid::sys_getegid;
@ -27,7 +26,6 @@ use crate::syscall::ioctl::sys_ioctl;
use crate::syscall::kill::sys_kill;
use crate::syscall::link::{sys_link, sys_linkat};
use crate::syscall::lseek::sys_lseek;
use crate::syscall::lstat::sys_lstat;
use crate::syscall::madvise::sys_madvise;
use crate::syscall::mkdir::{sys_mkdir, sys_mkdirat};
use crate::syscall::mmap::sys_mmap;
@ -47,7 +45,7 @@ use crate::syscall::sched_yield::sys_sched_yield;
use crate::syscall::set_robust_list::sys_set_robust_list;
use crate::syscall::set_tid_address::sys_set_tid_address;
use crate::syscall::setpgid::sys_setpgid;
use crate::syscall::stat::sys_stat;
use crate::syscall::stat::{sys_fstat, sys_fstatat, sys_lstat, sys_stat};
use crate::syscall::tgkill::sys_tgkill;
use crate::syscall::uname::sys_uname;
use crate::syscall::unlink::{sys_unlink, sys_unlinkat};
@ -69,7 +67,6 @@ mod exit;
mod exit_group;
mod fcntl;
mod fork;
mod fstat;
mod futex;
mod getcwd;
mod getegid;
@ -84,7 +81,6 @@ mod ioctl;
mod kill;
mod link;
mod lseek;
mod lstat;
mod madvise;
mod mkdir;
mod mmap;
@ -198,6 +194,7 @@ define_syscall_nums!(
SYS_WAITID = 247,
SYS_OPENAT = 257,
SYS_MKDIRAT = 258,
SYS_FSTATAT = 262,
SYS_UNLINKAT = 263,
SYS_LINKAT = 265,
SYS_SET_ROBUST_LIST = 273,
@ -314,6 +311,7 @@ pub fn syscall_dispatch(
SYS_WAITID => syscall_handler!(5, sys_waitid, args),
SYS_OPENAT => syscall_handler!(4, sys_openat, args),
SYS_MKDIRAT => syscall_handler!(3, sys_mkdirat, args),
SYS_FSTATAT => syscall_handler!(4, sys_fstatat, args),
SYS_UNLINKAT => syscall_handler!(3, sys_unlinkat, args),
SYS_LINKAT => syscall_handler!(5, sys_linkat, args),
SYS_SET_ROBUST_LIST => syscall_handler!(2, sys_set_robust_list, args),

View File

@ -1,16 +1,79 @@
use super::SYS_STAT;
use crate::fs::{
file_table::FileDescripter,
fs_resolver::{FsPath, AT_FDCWD},
utils::Stat,
};
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::syscall::constants::MAX_FILENAME_LEN;
use crate::util::read_cstring_from_user;
use crate::{log_syscall_entry, prelude::*};
use crate::util::write_val_to_user;
use super::SyscallReturn;
use super::{SYS_FSTAT, SYS_FSTATAT};
pub fn sys_fstat(fd: FileDescripter, stat_buf_ptr: Vaddr) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_FSTAT);
debug!("fd = {}, stat_buf_addr = 0x{:x}", fd, stat_buf_ptr);
let current = current!();
let file_table = current.file_table().lock();
let file = file_table.get_file(fd)?;
let stat = Stat::from(file.metadata());
write_val_to_user(stat_buf_ptr, &stat)?;
Ok(SyscallReturn::Return(0))
}
pub fn sys_stat(filename_ptr: Vaddr, stat_buf_ptr: Vaddr) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_STAT);
let filename = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?;
debug!(
"filename = {:?}, stat_buf_ptr = 0x{:x}",
filename, stat_buf_ptr
);
return_errno_with_message!(Errno::ENOSYS, "Stat is unimplemented");
self::sys_fstatat(AT_FDCWD, filename_ptr, stat_buf_ptr, 0)
}
pub fn sys_lstat(filename_ptr: Vaddr, stat_buf_ptr: Vaddr) -> Result<SyscallReturn> {
self::sys_fstatat(
AT_FDCWD,
filename_ptr,
stat_buf_ptr,
StatFlags::AT_SYMLINK_NOFOLLOW.bits(),
)
}
pub fn sys_fstatat(
dirfd: FileDescripter,
filename_ptr: Vaddr,
stat_buf_ptr: Vaddr,
flags: u32,
) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_FSTATAT);
let filename = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?;
let flags =
StatFlags::from_bits(flags).ok_or(Error::with_message(Errno::EINVAL, "invalid flags"))?;
debug!(
"dirfd = {}, filename = {:?}, stat_buf_ptr = 0x{:x}, flags = {:?}",
dirfd, filename, stat_buf_ptr, flags
);
let current = current!();
let dentry = {
let filename = filename.to_string_lossy();
if filename.is_empty() && !flags.contains(StatFlags::AT_EMPTY_PATH) {
return_errno_with_message!(Errno::ENOENT, "path is empty");
}
let fs_path = FsPath::new(dirfd, filename.as_ref())?;
let fs = current.fs().read();
if flags.contains(StatFlags::AT_SYMLINK_NOFOLLOW) {
fs.lookup_no_follow(&fs_path)?
} else {
fs.lookup(&fs_path)?
}
};
let stat = Stat::from(dentry.vnode().inode().metadata());
write_val_to_user(stat_buf_ptr, &stat)?;
Ok(SyscallReturn::Return(0))
}
bitflags::bitflags! {
struct StatFlags: u32 {
const AT_EMPTY_PATH = 1 << 12;
const AT_NO_AUTOMOUNT = 1 << 11;
const AT_SYMLINK_NOFOLLOW = 1 << 8;
}
}