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

View File

@ -3,10 +3,10 @@
mod file; mod file;
mod inode_handle; mod inode_handle;
use crate::fs::utils::Metadata;
use crate::prelude::*; use crate::prelude::*;
use crate::rights::{ReadOp, WriteOp}; use crate::rights::{ReadOp, WriteOp};
use alloc::sync::Arc; use alloc::sync::Arc;
use core::ops::Range;
pub use self::file::File; pub use self::file::File;
pub use self::inode_handle::InodeHandle; 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<()> { pub fn clean_for_close(&self) -> Result<()> {
match &self.inner { match &self.inner {
Inner::Inode(inode_handle) => { Inner::Inode(inode_handle) => {

View File

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

View File

@ -3,7 +3,7 @@ use crate::tty::{get_n_tty, Tty};
use super::file_handle::File; use super::file_handle::File;
use super::file_table::FileDescripter; 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_STDIN: FileDescripter = 0;
pub const FD_STDOUT: FileDescripter = 1; pub const FD_STDOUT: FileDescripter = 1;
@ -45,6 +45,25 @@ impl File for Stdin {
todo!() 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 { impl File for Stdout {
fn ioctl(&self, cmd: super::utils::IoctlCmd, arg: usize) -> Result<i32> { fn ioctl(&self, cmd: super::utils::IoctlCmd, arg: usize) -> Result<i32> {
@ -62,6 +81,25 @@ impl File for Stdout {
todo!() 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 { impl File for Stderr {
@ -80,6 +118,25 @@ impl File for Stderr {
todo!() 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 { impl Stdin {

View File

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

View File

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

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::exit_group::sys_exit_group;
use crate::syscall::fcntl::sys_fcntl; use crate::syscall::fcntl::sys_fcntl;
use crate::syscall::fork::sys_fork; use crate::syscall::fork::sys_fork;
use crate::syscall::fstat::sys_fstat;
use crate::syscall::futex::sys_futex; use crate::syscall::futex::sys_futex;
use crate::syscall::getcwd::sys_getcwd; use crate::syscall::getcwd::sys_getcwd;
use crate::syscall::getegid::sys_getegid; 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::kill::sys_kill;
use crate::syscall::link::{sys_link, sys_linkat}; use crate::syscall::link::{sys_link, sys_linkat};
use crate::syscall::lseek::sys_lseek; use crate::syscall::lseek::sys_lseek;
use crate::syscall::lstat::sys_lstat;
use crate::syscall::madvise::sys_madvise; use crate::syscall::madvise::sys_madvise;
use crate::syscall::mkdir::{sys_mkdir, sys_mkdirat}; use crate::syscall::mkdir::{sys_mkdir, sys_mkdirat};
use crate::syscall::mmap::sys_mmap; 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_robust_list::sys_set_robust_list;
use crate::syscall::set_tid_address::sys_set_tid_address; use crate::syscall::set_tid_address::sys_set_tid_address;
use crate::syscall::setpgid::sys_setpgid; 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::tgkill::sys_tgkill;
use crate::syscall::uname::sys_uname; use crate::syscall::uname::sys_uname;
use crate::syscall::unlink::{sys_unlink, sys_unlinkat}; use crate::syscall::unlink::{sys_unlink, sys_unlinkat};
@ -69,7 +67,6 @@ mod exit;
mod exit_group; mod exit_group;
mod fcntl; mod fcntl;
mod fork; mod fork;
mod fstat;
mod futex; mod futex;
mod getcwd; mod getcwd;
mod getegid; mod getegid;
@ -84,7 +81,6 @@ mod ioctl;
mod kill; mod kill;
mod link; mod link;
mod lseek; mod lseek;
mod lstat;
mod madvise; mod madvise;
mod mkdir; mod mkdir;
mod mmap; mod mmap;
@ -198,6 +194,7 @@ define_syscall_nums!(
SYS_WAITID = 247, SYS_WAITID = 247,
SYS_OPENAT = 257, SYS_OPENAT = 257,
SYS_MKDIRAT = 258, SYS_MKDIRAT = 258,
SYS_FSTATAT = 262,
SYS_UNLINKAT = 263, SYS_UNLINKAT = 263,
SYS_LINKAT = 265, SYS_LINKAT = 265,
SYS_SET_ROBUST_LIST = 273, SYS_SET_ROBUST_LIST = 273,
@ -314,6 +311,7 @@ pub fn syscall_dispatch(
SYS_WAITID => syscall_handler!(5, sys_waitid, args), SYS_WAITID => syscall_handler!(5, sys_waitid, args),
SYS_OPENAT => syscall_handler!(4, sys_openat, args), SYS_OPENAT => syscall_handler!(4, sys_openat, args),
SYS_MKDIRAT => syscall_handler!(3, sys_mkdirat, 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_UNLINKAT => syscall_handler!(3, sys_unlinkat, args),
SYS_LINKAT => syscall_handler!(5, sys_linkat, args), SYS_LINKAT => syscall_handler!(5, sys_linkat, args),
SYS_SET_ROBUST_LIST => syscall_handler!(2, sys_set_robust_list, 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::syscall::constants::MAX_FILENAME_LEN;
use crate::util::read_cstring_from_user; 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::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> { pub fn sys_stat(filename_ptr: Vaddr, stat_buf_ptr: Vaddr) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_STAT); self::sys_fstatat(AT_FDCWD, filename_ptr, stat_buf_ptr, 0)
let filename = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?; }
debug!(
"filename = {:?}, stat_buf_ptr = 0x{:x}", pub fn sys_lstat(filename_ptr: Vaddr, stat_buf_ptr: Vaddr) -> Result<SyscallReturn> {
filename, stat_buf_ptr self::sys_fstatat(
); AT_FDCWD,
return_errno_with_message!(Errno::ENOSYS, "Stat is unimplemented"); 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;
}
} }