mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-13 23:36:48 +00:00
Add syscall statx
Signed-off-by: Zhenchen Wang <m202372036@hust.edu.cn>
This commit is contained in:
parent
1130933546
commit
7ac4fa9519
@ -340,6 +340,7 @@ provided by Linux on x86-64 architecture.
|
|||||||
| 322 | execveat | ✅ |
|
| 322 | execveat | ✅ |
|
||||||
| 327 | preadv2 | ✅ |
|
| 327 | preadv2 | ✅ |
|
||||||
| 328 | pwritev2 | ✅ |
|
| 328 | pwritev2 | ✅ |
|
||||||
|
| 332 | statx | ✅ |
|
||||||
| 435 | clone3 | ✅ |
|
| 435 | clone3 | ✅ |
|
||||||
|
|
||||||
## File Systems
|
## File Systems
|
||||||
|
@ -120,6 +120,7 @@ use crate::syscall::{
|
|||||||
socketpair::sys_socketpair,
|
socketpair::sys_socketpair,
|
||||||
stat::{sys_fstat, sys_fstatat},
|
stat::{sys_fstat, sys_fstatat},
|
||||||
statfs::{sys_fstatfs, sys_statfs},
|
statfs::{sys_fstatfs, sys_statfs},
|
||||||
|
statx::sys_statx,
|
||||||
symlink::sys_symlinkat,
|
symlink::sys_symlinkat,
|
||||||
sync::sys_sync,
|
sync::sys_sync,
|
||||||
tgkill::sys_tgkill,
|
tgkill::sys_tgkill,
|
||||||
@ -287,6 +288,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_EXECVEAT = 281 => sys_execveat(args[..5], &mut user_ctx);
|
SYS_EXECVEAT = 281 => sys_execveat(args[..5], &mut user_ctx);
|
||||||
SYS_PREADV2 = 286 => sys_preadv2(args[..5]);
|
SYS_PREADV2 = 286 => sys_preadv2(args[..5]);
|
||||||
SYS_PWRITEV2 = 287 => sys_pwritev2(args[..5]);
|
SYS_PWRITEV2 = 287 => sys_pwritev2(args[..5]);
|
||||||
|
SYS_STATX = 291 => sys_statx(args[..5]);
|
||||||
SYS_PRLIMIT64 = 302 => sys_prlimit64(args[..4]);
|
SYS_PRLIMIT64 = 302 => sys_prlimit64(args[..4]);
|
||||||
SYS_CLOCK_GETTIME = 403 => sys_clock_gettime(args[..2]);
|
SYS_CLOCK_GETTIME = 403 => sys_clock_gettime(args[..2]);
|
||||||
SYS_CLOCK_NANOSLEEP = 407 => sys_clock_nanosleep(args[..4]);
|
SYS_CLOCK_NANOSLEEP = 407 => sys_clock_nanosleep(args[..4]);
|
||||||
|
@ -133,6 +133,7 @@ use crate::syscall::{
|
|||||||
socketpair::sys_socketpair,
|
socketpair::sys_socketpair,
|
||||||
stat::{sys_fstat, sys_fstatat, sys_lstat, sys_stat},
|
stat::{sys_fstat, sys_fstatat, sys_lstat, sys_stat},
|
||||||
statfs::{sys_fstatfs, sys_statfs},
|
statfs::{sys_fstatfs, sys_statfs},
|
||||||
|
statx::sys_statx,
|
||||||
symlink::{sys_symlink, sys_symlinkat},
|
symlink::{sys_symlink, sys_symlinkat},
|
||||||
sync::sys_sync,
|
sync::sys_sync,
|
||||||
sysinfo::sys_sysinfo,
|
sysinfo::sys_sysinfo,
|
||||||
@ -357,5 +358,6 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_EXECVEAT = 322 => sys_execveat(args[..5], &mut user_ctx);
|
SYS_EXECVEAT = 322 => sys_execveat(args[..5], &mut user_ctx);
|
||||||
SYS_PREADV2 = 327 => sys_preadv2(args[..5]);
|
SYS_PREADV2 = 327 => sys_preadv2(args[..5]);
|
||||||
SYS_PWRITEV2 = 328 => sys_pwritev2(args[..5]);
|
SYS_PWRITEV2 = 328 => sys_pwritev2(args[..5]);
|
||||||
|
SYS_STATX = 332 => sys_statx(args[..5]);
|
||||||
SYS_CLONE3 = 435 => sys_clone3(args[..2], &user_ctx);
|
SYS_CLONE3 = 435 => sys_clone3(args[..2], &user_ctx);
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,7 @@ mod socket;
|
|||||||
mod socketpair;
|
mod socketpair;
|
||||||
mod stat;
|
mod stat;
|
||||||
mod statfs;
|
mod statfs;
|
||||||
|
mod statx;
|
||||||
mod symlink;
|
mod symlink;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod sysinfo;
|
mod sysinfo;
|
||||||
|
212
kernel/src/syscall/statx.rs
Normal file
212
kernel/src/syscall/statx.rs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use ::core::time::Duration;
|
||||||
|
|
||||||
|
use super::SyscallReturn;
|
||||||
|
use crate::{
|
||||||
|
fs::{device::DeviceId, file_table::FileDesc, fs_resolver::FsPath, utils::Metadata},
|
||||||
|
prelude::*,
|
||||||
|
syscall::constants::MAX_FILENAME_LEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn sys_statx(
|
||||||
|
dirfd: FileDesc,
|
||||||
|
filename_ptr: Vaddr,
|
||||||
|
flags: u32,
|
||||||
|
mask: u32,
|
||||||
|
statx_buf_ptr: Vaddr,
|
||||||
|
ctx: &Context,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
let user_space = ctx.user_space();
|
||||||
|
let filename = user_space.read_cstring(filename_ptr, MAX_FILENAME_LEN)?;
|
||||||
|
let flags = StatxFlags::from_bits(flags)
|
||||||
|
.ok_or(Error::with_message(Errno::EINVAL, "invalid statx flags"))?;
|
||||||
|
let mask = StatxMask::from_bits_truncate(mask);
|
||||||
|
debug!(
|
||||||
|
"dirfd = {}, filename = {:?}, flags = {:?}, mask = {:?}, statx_buf_ptr = 0x{:x}",
|
||||||
|
dirfd, filename, flags, mask, statx_buf_ptr,
|
||||||
|
);
|
||||||
|
|
||||||
|
if filename.is_empty() && !flags.contains(StatxFlags::AT_EMPTY_PATH) {
|
||||||
|
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if flags.contains(StatxFlags::AT_STATX_FORCE_SYNC)
|
||||||
|
&& flags.contains(StatxFlags::AT_STATX_DONT_SYNC)
|
||||||
|
{
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid statx flags");
|
||||||
|
}
|
||||||
|
|
||||||
|
if mask.contains(StatxMask::STATX_RESERVED) {
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EINVAL,
|
||||||
|
"mask reserved for future struct statx expansion"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dentry = {
|
||||||
|
let filename = filename.to_string_lossy();
|
||||||
|
let fs_path = FsPath::new(dirfd, filename.as_ref())?;
|
||||||
|
let fs = ctx.posix_thread.fs().resolver().read();
|
||||||
|
if flags.contains(StatxFlags::AT_SYMLINK_NOFOLLOW) {
|
||||||
|
fs.lookup_no_follow(&fs_path)?
|
||||||
|
} else {
|
||||||
|
fs.lookup(&fs_path)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let statx = Statx::from(dentry.metadata());
|
||||||
|
|
||||||
|
user_space.write_val(statx_buf_ptr, &statx)?;
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Structures for the extended file attribute retrieval system call statx.
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Statx {
|
||||||
|
/// Indicates which fields in the `statx` structure were successfully filled,
|
||||||
|
/// reflecting the state information supported by the filesystem.
|
||||||
|
stx_mask: u32,
|
||||||
|
/// Preferred general I/O size
|
||||||
|
stx_blksize: u32,
|
||||||
|
/// Flags conveying information about the file
|
||||||
|
stx_attributes: u64,
|
||||||
|
/// Number of hard links
|
||||||
|
stx_nlink: u32,
|
||||||
|
/// User ID of owner
|
||||||
|
stx_uid: u32,
|
||||||
|
/// Group ID of owner
|
||||||
|
stx_gid: u32,
|
||||||
|
/// File mode
|
||||||
|
stx_mode: u16,
|
||||||
|
/// Padding
|
||||||
|
__spare0: [u16; 1],
|
||||||
|
/// Inode number
|
||||||
|
stx_ino: u64,
|
||||||
|
/// File size
|
||||||
|
stx_size: u64,
|
||||||
|
/// Number of 512-byte blocks allocated
|
||||||
|
stx_blocks: u64,
|
||||||
|
/// Mask to show what's supported in stx_attributes
|
||||||
|
stx_attributes_mask: u64,
|
||||||
|
/// Last access time
|
||||||
|
stx_atime: StatxTimestamp,
|
||||||
|
/// File creation time
|
||||||
|
stx_btime: StatxTimestamp,
|
||||||
|
/// Last attribute change time
|
||||||
|
stx_ctime: StatxTimestamp,
|
||||||
|
/// Last data modification time
|
||||||
|
stx_mtime: StatxTimestamp,
|
||||||
|
/// Device ID of special file (if bdev/cdev)
|
||||||
|
stx_rdev_major: u32,
|
||||||
|
stx_rdev_minor: u32,
|
||||||
|
/// ID of device containing file
|
||||||
|
stx_dev_major: u32,
|
||||||
|
stx_dev_minor: u32,
|
||||||
|
/// Mount ID
|
||||||
|
stx_mnt_id: u64,
|
||||||
|
/// Memory buffer alignment for direct I/O
|
||||||
|
stx_dio_mem_align: u32,
|
||||||
|
/// File offset alignment for direct I/O
|
||||||
|
stx_dio_offset_align: u32,
|
||||||
|
/// Spare space for future expansion
|
||||||
|
__spare3: [u64; 12],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Metadata> for Statx {
|
||||||
|
fn from(info: Metadata) -> Self {
|
||||||
|
let devid = DeviceId::from(info.dev);
|
||||||
|
let rdevid = DeviceId::from(info.rdev);
|
||||||
|
Self {
|
||||||
|
// FIXME: All zero fields below are dummy implementations that need to be improved in the future.
|
||||||
|
stx_mask: 0,
|
||||||
|
stx_blksize: info.blk_size as u32,
|
||||||
|
stx_attributes: 0,
|
||||||
|
stx_nlink: info.nlinks as u32,
|
||||||
|
stx_uid: info.uid.into(),
|
||||||
|
stx_gid: info.gid.into(),
|
||||||
|
stx_mode: info.type_ as u16 | info.mode.bits(),
|
||||||
|
__spare0: [0; 1],
|
||||||
|
stx_ino: info.ino,
|
||||||
|
stx_size: info.size as u64,
|
||||||
|
stx_blocks: (info.blocks * (info.blk_size / 512)) as u64,
|
||||||
|
stx_attributes_mask: 0,
|
||||||
|
stx_atime: StatxTimestamp::from(info.atime),
|
||||||
|
stx_btime: StatxTimestamp::from(info.atime),
|
||||||
|
stx_ctime: StatxTimestamp::from(info.ctime),
|
||||||
|
stx_mtime: StatxTimestamp::from(info.ctime),
|
||||||
|
stx_rdev_major: rdevid.major(),
|
||||||
|
stx_rdev_minor: rdevid.minor(),
|
||||||
|
stx_dev_major: devid.major(),
|
||||||
|
stx_dev_minor: devid.minor(),
|
||||||
|
stx_mnt_id: 0,
|
||||||
|
stx_dio_mem_align: 0,
|
||||||
|
stx_dio_offset_align: 0,
|
||||||
|
__spare3: [0; 12],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Statx Timestamp (seconds and nanoseconds)
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct StatxTimestamp {
|
||||||
|
/// Seconds
|
||||||
|
tv_sec: i64,
|
||||||
|
/// Nanoseconds
|
||||||
|
tv_nsec: u32,
|
||||||
|
__reserved: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Duration> for StatxTimestamp {
|
||||||
|
fn from(duration: Duration) -> Self {
|
||||||
|
Self {
|
||||||
|
tv_sec: duration.as_secs() as i64,
|
||||||
|
tv_nsec: duration.subsec_nanos() as u32,
|
||||||
|
__reserved: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Flags can be used to influence a pathname-based lookup.
|
||||||
|
/// Flags can also be used to control what sort of synchronization the
|
||||||
|
/// kernel will do when querying a file on a remote filesystem.
|
||||||
|
struct StatxFlags: u32 {
|
||||||
|
const AT_EMPTY_PATH = 1 << 12; // Allow empty relative pathname to operate on dirfd directly.
|
||||||
|
const AT_NO_AUTOMOUNT = 1 << 11; // Suppress terminal automount traversal.
|
||||||
|
const AT_SYMLINK_NOFOLLOW = 1 << 8; // Do not follow symbolic links.
|
||||||
|
const AT_STATX_SYNC_AS_STAT = 0; // Do whatever stat() does.
|
||||||
|
const AT_STATX_FORCE_SYNC = 1 << 13; // Force the attributes to be sync'd with the server.
|
||||||
|
const AT_STATX_DONT_SYNC = 1 << 14; // Don't sync attributes with the server.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Flags to be stx_mask.
|
||||||
|
/// Query request/result mask for statx() and struct statx::stx_mask.
|
||||||
|
/// These bits should be set in the mask argument of statx() to request
|
||||||
|
/// particular items when calling statx().
|
||||||
|
pub struct StatxMask: u32 {
|
||||||
|
const STATX_TYPE = 0x00000001; // Want stx_mode & S_IFMT
|
||||||
|
const STATX_MODE = 0x00000002; // Want stx_mode & ~S_IFMT
|
||||||
|
const STATX_NLINK = 0x00000004; // Want stx_nlink
|
||||||
|
const STATX_UID = 0x00000008; // Want stx_uid
|
||||||
|
const STATX_GID = 0x00000010; // Want stx_gid
|
||||||
|
const STATX_ATIME = 0x00000020; // Want stx_atime
|
||||||
|
const STATX_MTIME = 0x00000040; // Want stx_mtime
|
||||||
|
const STATX_CTIME = 0x00000080; // Want stx_ctime
|
||||||
|
const STATX_INO = 0x00000100; // Want stx_ino
|
||||||
|
const STATX_SIZE = 0x00000200; // Want stx_size
|
||||||
|
const STATX_BLOCKS = 0x00000400; // Want stx_blocks
|
||||||
|
const STATX_BASIC_STATS = 0x000007ff; // All of the above (stx_mode, stx_nlink, etc.)
|
||||||
|
const STATX_BTIME = 0x00000800; // Want stx_btime
|
||||||
|
const STATX_ALL = 0x00000fff; // Deprecated: The same as STATX_BASIC_STATS | STATX_BTIME
|
||||||
|
const STATX_MNT_ID = 0x00001000; // Want stx_mnt_id
|
||||||
|
const STATX_DIOALIGN = 0x00002000; // Want stx_dio_mem_align and stx_dio_offset_align
|
||||||
|
const STATX_MNT_ID_UNIQUE = 0x00004000; // Want unique stx_mnt_id
|
||||||
|
const STATX_RESERVED = 0x80000000; // Reserved for future struct statx expansion
|
||||||
|
const STATX_CHANGE_COOKIE = 0x40000000; // Want/got stx_change_attr
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user