diff --git a/src/services/libs/jinux-std/src/fs/file_handle/file.rs b/src/services/libs/jinux-std/src/fs/file_handle/file.rs index 5e59233fb..69e1a33de 100644 --- a/src/services/libs/jinux-std/src/fs/file_handle/file.rs +++ b/src/services/libs/jinux-std/src/fs/file_handle/file.rs @@ -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"); + } } diff --git a/src/services/libs/jinux-std/src/fs/file_handle/mod.rs b/src/services/libs/jinux-std/src/fs/file_handle/mod.rs index 08e386882..8ef1625e2 100644 --- a/src/services/libs/jinux-std/src/fs/file_handle/mod.rs +++ b/src/services/libs/jinux-std/src/fs/file_handle/mod.rs @@ -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) => { diff --git a/src/services/libs/jinux-std/src/fs/ramfs/fs.rs b/src/services/libs/jinux-std/src/fs/ramfs/fs.rs index 3471840d3..a72c6b03c 100644 --- a/src/services/libs/jinux-std/src/fs/ramfs/fs.rs +++ b/src/services/libs/jinux-std/src/fs/ramfs/fs.rs @@ -19,12 +19,14 @@ pub struct RamFS { impl RamFS { pub fn new() -> Arc { + 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 diff --git a/src/services/libs/jinux-std/src/fs/stdio.rs b/src/services/libs/jinux-std/src/fs/stdio.rs index 3bcfa7396..4d6b2b452 100644 --- a/src/services/libs/jinux-std/src/fs/stdio.rs +++ b/src/services/libs/jinux-std/src/fs/stdio.rs @@ -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 { @@ -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 { diff --git a/src/services/libs/jinux-std/src/fs/utils/inode.rs b/src/services/libs/jinux-std/src/fs/utils/inode.rs index d1f355c78..95e3032c4 100644 --- a/src/services/libs/jinux-std/src/fs/utils/inode.rs +++ b/src/services/libs/jinux-std/src/fs/utils/inode.rs @@ -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, diff --git a/src/services/libs/jinux-std/src/fs/utils/stat.rs b/src/services/libs/jinux-std/src/fs/utils/stat.rs index 4a15cafd4..605ec06ba 100644 --- a/src/services/libs/jinux-std/src/fs/utils/stat.rs +++ b/src/services/libs/jinux-std/src/fs/utils/stat.rs @@ -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 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], + } } } diff --git a/src/services/libs/jinux-std/src/syscall/fstat.rs b/src/services/libs/jinux-std/src/syscall/fstat.rs deleted file mode 100644 index f61bf1441..000000000 --- a/src/services/libs/jinux-std/src/syscall/fstat.rs +++ /dev/null @@ -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 { - 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)) -} diff --git a/src/services/libs/jinux-std/src/syscall/lstat.rs b/src/services/libs/jinux-std/src/syscall/lstat.rs deleted file mode 100644 index c8bdf9ef9..000000000 --- a/src/services/libs/jinux-std/src/syscall/lstat.rs +++ /dev/null @@ -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 { - 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!() -} diff --git a/src/services/libs/jinux-std/src/syscall/mod.rs b/src/services/libs/jinux-std/src/syscall/mod.rs index e5f1429c2..8e7bf0287 100644 --- a/src/services/libs/jinux-std/src/syscall/mod.rs +++ b/src/services/libs/jinux-std/src/syscall/mod.rs @@ -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), diff --git a/src/services/libs/jinux-std/src/syscall/stat.rs b/src/services/libs/jinux-std/src/syscall/stat.rs index a72da3325..f4a88c804 100644 --- a/src/services/libs/jinux-std/src/syscall/stat.rs +++ b/src/services/libs/jinux-std/src/syscall/stat.rs @@ -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 { + 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 { - 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 { + 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 { + 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; + } }