123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- use system_error::SystemError;
- use crate::{
- arch::filesystem::stat::PosixStat,
- driver::base::device::device_number::DeviceNumber,
- filesystem::vfs::{mount::is_mountpoint_root, vcore::do_file_lookup_at},
- process::ProcessManager,
- syscall::user_access::UserBufferWriter,
- time::PosixTimeSpec,
- };
- use alloc::sync::Arc;
- use super::{
- fcntl::AtFlags,
- syscall::{ModeType, PosixStatx, PosixStatxMask, StxAttributes},
- IndexNode,
- };
- #[derive(Clone)]
- pub struct KStat {
- pub result_mask: PosixStatxMask, // What fields the user got
- pub mode: ModeType, // umode_t
- pub nlink: u32,
- pub blksize: u32, // Preferred I/O size
- pub attributes: StxAttributes,
- pub attributes_mask: StxAttributes,
- pub ino: u64,
- pub dev: DeviceNumber, // dev_t
- pub rdev: DeviceNumber, // dev_t
- pub uid: u32, // kuid_t
- pub gid: u32, // kgid_t
- pub size: usize, // loff_t
- pub atime: PosixTimeSpec, // struct timespec64
- pub mtime: PosixTimeSpec, // struct timespec64
- pub ctime: PosixTimeSpec, // struct timespec64
- pub btime: PosixTimeSpec, // File creation time
- pub blocks: u64,
- pub mnt_id: u64,
- pub dio_mem_align: u32,
- pub dio_offset_align: u32,
- }
- impl Default for KStat {
- fn default() -> Self {
- Self {
- result_mask: PosixStatxMask::empty(),
- mode: ModeType::empty(),
- nlink: Default::default(),
- blksize: Default::default(),
- attributes: StxAttributes::empty(),
- attributes_mask: StxAttributes::empty(),
- ino: Default::default(),
- dev: Default::default(),
- rdev: Default::default(),
- uid: Default::default(),
- gid: Default::default(),
- size: Default::default(),
- atime: Default::default(),
- mtime: Default::default(),
- ctime: Default::default(),
- btime: Default::default(),
- blocks: Default::default(),
- mnt_id: Default::default(),
- dio_mem_align: Default::default(),
- dio_offset_align: Default::default(),
- }
- }
- }
- bitflags! {
- /// https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/namei.h?fi=LOOKUP_FOLLOW#21
- pub struct LookUpFlags: u32 {
- /// follow links at the end
- const FOLLOW = 0x0001;
- /// require a directory
- const DIRECTORY = 0x0002;
- /// force terminal automount
- const AUTOMOUNT = 0x0004;
- /// accept empty path [user_... only]
- const EMPTY = 0x4000;
- /// follow mounts in the starting point
- const DOWN = 0x8000;
- /// follow mounts in the end
- const MOUNTPOINT = 0x0080;
- /// tell ->d_revalidate() to trust no cache
- const REVAL = 0x0020;
- /// RCU pathwalk mode; semi-internal
- const RCU = 0x0040;
- /// ... in open
- const OPEN = 0x0100;
- /// ... in object creation
- const CREATE = 0x0200;
- /// ... in exclusive creation
- const EXCL = 0x0400;
- /// ... in destination of rename()
- const RENAME_TARGET = 0x0800;
- /// internal use only
- const PARENT = 0x0010;
- /// No symlink crossing
- const NO_SYMLINKS = 0x010000;
- /// No nd_jump_link() crossing
- const NO_MAGICLINKS = 0x020000;
- /// No mountpoint crossing
- const NO_XDEV = 0x040000;
- /// No escaping from starting point
- const BENEATH = 0x080000;
- /// Treat dirfd as fs root
- const IN_ROOT = 0x100000;
- /// Only do cached lookup
- const CACHED = 0x200000;
- /// LOOKUP_* flags which do scope-related checks based on the dirfd.
- const IS_SCOPED = LookUpFlags::BENEATH.bits | LookUpFlags::IN_ROOT.bits;
- }
- }
- impl From<AtFlags> for LookUpFlags {
- fn from(value: AtFlags) -> Self {
- let mut lookup_flags = LookUpFlags::empty();
- if !value.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
- lookup_flags |= LookUpFlags::FOLLOW;
- }
- if !value.contains(AtFlags::AT_NO_AUTOMOUNT) {
- lookup_flags |= LookUpFlags::AUTOMOUNT;
- }
- if value.contains(AtFlags::AT_EMPTY_PATH) {
- lookup_flags |= LookUpFlags::EMPTY;
- }
- lookup_flags
- }
- }
- /// https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#232
- #[inline(never)]
- pub fn vfs_statx(
- dfd: i32,
- filename: &str,
- flags: AtFlags,
- request_mask: PosixStatxMask,
- ) -> Result<KStat, SystemError> {
- let lookup_flags: LookUpFlags = flags.into();
- // Validate flags - only allowed flags are AT_SYMLINK_NOFOLLOW, AT_NO_AUTOMOUNT, AT_EMPTY_PATH, AT_STATX_SYNC_TYPE
- if flags.intersects(
- !(AtFlags::AT_SYMLINK_NOFOLLOW
- | AtFlags::AT_NO_AUTOMOUNT
- | AtFlags::AT_EMPTY_PATH
- | AtFlags::AT_STATX_SYNC_TYPE),
- ) {
- return Err(SystemError::EINVAL);
- }
- let inode = do_file_lookup_at(dfd, filename, lookup_flags)?;
- let mut kstat = vfs_getattr(&inode, request_mask, flags)?;
- if is_mountpoint_root(&inode) {
- kstat
- .attributes
- .insert(StxAttributes::STATX_ATTR_MOUNT_ROOT);
- }
- kstat
- .attributes_mask
- .insert(StxAttributes::STATX_ATTR_MOUNT_ROOT);
- // todo: 添加 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#266 这里的逻辑
- Ok(kstat)
- }
- /// 获取文件的增强基本属性
- ///
- /// # 参数
- /// - `path`: 目标文件路径
- /// - `stat`: 用于返回统计信息的结构体
- /// - `request_mask`: PosixStatxMask标志位,指示调用者需要哪些属性
- /// - `query_flags`: 查询模式(AT_STATX_SYNC_TYPE)
- ///
- /// # 描述
- /// 向文件系统请求文件的属性。调用者必须通过request_mask和query_flags指定需要的信息。
- ///
- /// 如果文件是远程的:
- /// - 可以通过传递AT_STATX_FORCE_SYNC强制文件系统从后端存储更新属性
- /// - 可以通过传递AT_STATX_DONT_SYNC禁止更新
- ///
- /// request_mask中必须设置相应的位来指示调用者需要检索哪些属性。
- /// 未请求的属性也可能被返回,但其值可能是近似的,如果是远程文件,
- /// 可能没有与服务器同步。
- ///
- /// # 返回值
- /// 成功时返回0,失败时返回负的错误码
- ///
- /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#165
- #[inline(never)]
- pub fn vfs_getattr(
- inode: &Arc<dyn IndexNode>,
- request_mask: PosixStatxMask,
- mut at_flags: AtFlags,
- ) -> Result<KStat, SystemError> {
- if at_flags.contains(AtFlags::AT_GETATTR_NOSEC) {
- return Err(SystemError::EPERM);
- }
- let mut kstat = KStat::default();
- kstat.result_mask |= PosixStatxMask::STATX_BASIC_STATS;
- at_flags &= AtFlags::AT_STATX_SYNC_TYPE;
- let metadata = inode.metadata()?;
- if metadata.atime.is_empty() {
- kstat.result_mask.remove(PosixStatxMask::STATX_ATIME);
- }
- // todo: 添加automount和dax属性
- kstat.blksize = metadata.blk_size as u32;
- if request_mask.contains(PosixStatxMask::STATX_MODE)
- || request_mask.contains(PosixStatxMask::STATX_TYPE)
- {
- kstat.mode = metadata.mode;
- }
- if request_mask.contains(PosixStatxMask::STATX_NLINK) {
- kstat.nlink = metadata.nlinks as u32;
- }
- if request_mask.contains(PosixStatxMask::STATX_UID) {
- kstat.uid = metadata.uid as u32;
- }
- if request_mask.contains(PosixStatxMask::STATX_GID) {
- kstat.gid = metadata.gid as u32;
- }
- if request_mask.contains(PosixStatxMask::STATX_ATIME) {
- kstat.atime.tv_sec = metadata.atime.tv_sec;
- kstat.atime.tv_nsec = metadata.atime.tv_nsec;
- }
- if request_mask.contains(PosixStatxMask::STATX_MTIME) {
- kstat.mtime.tv_sec = metadata.mtime.tv_sec;
- kstat.mtime.tv_nsec = metadata.mtime.tv_nsec;
- }
- if request_mask.contains(PosixStatxMask::STATX_CTIME) {
- // ctime是文件上次修改状态的时间
- kstat.ctime.tv_sec = metadata.ctime.tv_sec;
- kstat.ctime.tv_nsec = metadata.ctime.tv_nsec;
- }
- if request_mask.contains(PosixStatxMask::STATX_INO) {
- kstat.ino = metadata.inode_id.into() as u64;
- }
- if request_mask.contains(PosixStatxMask::STATX_SIZE) {
- kstat.size = metadata.size as usize;
- }
- if request_mask.contains(PosixStatxMask::STATX_BLOCKS) {
- kstat.blocks = metadata.blocks as u64;
- }
- if request_mask.contains(PosixStatxMask::STATX_BTIME) {
- // btime是文件创建时间
- kstat.btime.tv_sec = metadata.btime.tv_sec;
- kstat.btime.tv_nsec = metadata.btime.tv_nsec;
- }
- if request_mask.contains(PosixStatxMask::STATX_ALL) {
- kstat.attributes = StxAttributes::STATX_ATTR_APPEND;
- kstat.attributes_mask |=
- StxAttributes::STATX_ATTR_AUTOMOUNT | StxAttributes::STATX_ATTR_DAX;
- kstat.dev = DeviceNumber::from(metadata.dev_id as u32);
- kstat.rdev = metadata.raw_dev;
- }
- // 把文件类型加入mode里面 (todo: 在具体的文件系统里面去实现这个操作。这里只是权宜之计)
- kstat.mode |= metadata.file_type.into();
- return Ok(kstat);
- }
- /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#274
- #[inline(never)]
- pub fn vfs_fstatat(dfd: i32, filename: &str, flags: AtFlags) -> Result<KStat, SystemError> {
- let statx_flags = flags | AtFlags::AT_NO_AUTOMOUNT;
- if dfd >= 0 && flags == AtFlags::AT_EMPTY_PATH {
- return vfs_fstat(dfd);
- }
- return vfs_statx(
- dfd,
- filename,
- statx_flags,
- PosixStatxMask::STATX_BASIC_STATS,
- );
- }
- /// vfs_fstat - Get the basic attributes by file descriptor
- ///
- /// # Arguments
- /// - fd: The file descriptor referring to the file of interest
- ///
- /// This function is a wrapper around vfs_getattr(). The main difference is
- /// that it uses a file descriptor to determine the file location.
- ///
- /// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#190
- pub fn vfs_fstat(dfd: i32) -> Result<KStat, SystemError> {
- // Get the file from the file descriptor
- let pcb = ProcessManager::current_pcb();
- let fd_table = pcb.fd_table();
- let file = fd_table
- .read()
- .get_file_by_fd(dfd)
- .ok_or(SystemError::EBADF)?;
- let inode = file.inode();
- // Get attributes using vfs_getattr with basic stats mask
- vfs_getattr(&inode, PosixStatxMask::STATX_BASIC_STATS, AtFlags::empty())
- }
- pub(super) fn do_newfstatat(
- dfd: i32,
- filename: &str,
- user_stat_buf_ptr: usize,
- flags: u32,
- ) -> Result<(), SystemError> {
- let kstat = vfs_fstatat(dfd, filename, AtFlags::from_bits_truncate(flags as i32))?;
- cp_new_stat(kstat, user_stat_buf_ptr)
- }
- /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#393
- #[inline(never)]
- fn cp_new_stat(kstat: KStat, user_buf_ptr: usize) -> Result<(), SystemError> {
- let posix_stat = PosixStat::try_from(kstat)?;
- let mut ubuf_writer =
- UserBufferWriter::new(user_buf_ptr as *mut PosixStat, size_of::<PosixStat>(), true)?;
- ubuf_writer
- .copy_one_to_user(&posix_stat, 0)
- .map_err(|_| SystemError::EFAULT)
- }
- /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#660
- pub(super) fn do_statx(
- dfd: i32,
- filename: &str,
- flags: u32,
- mask: u32,
- user_kstat_ptr: usize,
- ) -> Result<(), SystemError> {
- let mask = PosixStatxMask::from_bits_truncate(mask);
- if mask.contains(PosixStatxMask::STATX_RESERVED) {
- return Err(SystemError::EINVAL);
- }
- let flags = AtFlags::from_bits_truncate(flags as i32);
- if flags.contains(AtFlags::AT_STATX_SYNC_TYPE) {
- return Err(SystemError::EINVAL);
- }
- let kstat = vfs_statx(dfd, filename, flags, mask)?;
- cp_statx(kstat, user_kstat_ptr)
- }
- /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#622
- #[inline(never)]
- fn cp_statx(kstat: KStat, user_buf_ptr: usize) -> Result<(), SystemError> {
- let mut userbuf = UserBufferWriter::new(
- user_buf_ptr as *mut PosixStatx,
- size_of::<PosixStatx>(),
- true,
- )?;
- let mut statx: PosixStatx = PosixStatx::new();
- // Copy fields from KStat to PosixStatx
- statx.stx_mask = kstat.result_mask & !PosixStatxMask::STATX_CHANGE_COOKIE;
- statx.stx_blksize = kstat.blksize;
- statx.stx_attributes = kstat.attributes & !StxAttributes::STATX_ATTR_CHANGE_MONOTONIC;
- statx.stx_nlink = kstat.nlink;
- statx.stx_uid = kstat.uid;
- statx.stx_gid = kstat.gid;
- statx.stx_mode = kstat.mode;
- statx.stx_inode = kstat.ino;
- statx.stx_size = kstat.size as i64;
- statx.stx_blocks = kstat.blocks;
- statx.stx_attributes_mask = kstat.attributes_mask;
- // Copy time fields
- statx.stx_atime = kstat.atime;
- statx.stx_btime = kstat.btime;
- statx.stx_ctime = kstat.ctime;
- statx.stx_mtime = kstat.mtime;
- // Convert device numbers
- statx.stx_rdev_major = kstat.rdev.major().data();
- statx.stx_rdev_minor = kstat.rdev.minor();
- statx.stx_dev_major = kstat.dev.major().data();
- statx.stx_dev_minor = kstat.dev.minor();
- statx.stx_mnt_id = kstat.mnt_id;
- statx.stx_dio_mem_align = kstat.dio_mem_align;
- statx.stx_dio_offset_align = kstat.dio_offset_align;
- // Write to user space
- userbuf.copy_one_to_user(&statx, 0)?;
- Ok(())
- }
- // 注意!这个结构体定义的貌似不太对,需要修改!
- #[repr(C)]
- #[derive(Clone, Copy)]
- /// # 文件信息结构体
- pub struct PosixKstat {
- /// 硬件设备ID
- pub dev_id: u64,
- /// inode号
- pub inode: u64,
- /// 硬链接数
- pub nlink: u64,
- /// 文件权限
- pub mode: ModeType,
- /// 所有者用户ID
- pub uid: i32,
- /// 所有者组ID
- pub gid: i32,
- /// 设备ID
- pub rdev: i64,
- /// 文件大小
- pub size: i64,
- /// 文件系统块大小
- pub blcok_size: i64,
- /// 分配的512B块数
- pub blocks: u64,
- /// 最后访问时间
- pub atime: PosixTimeSpec,
- /// 最后修改时间
- pub mtime: PosixTimeSpec,
- /// 最后状态变化时间
- pub ctime: PosixTimeSpec,
- /// 用于填充结构体大小的空白数据
- pub _pad: [i8; 24],
- }
- impl PosixKstat {
- pub(super) fn new() -> Self {
- Self {
- inode: 0,
- dev_id: 0,
- mode: ModeType::empty(),
- nlink: 0,
- uid: 0,
- gid: 0,
- rdev: 0,
- size: 0,
- atime: PosixTimeSpec {
- tv_sec: 0,
- tv_nsec: 0,
- },
- mtime: PosixTimeSpec {
- tv_sec: 0,
- tv_nsec: 0,
- },
- ctime: PosixTimeSpec {
- tv_sec: 0,
- tv_nsec: 0,
- },
- blcok_size: 0,
- blocks: 0,
- _pad: Default::default(),
- }
- }
- }
|