From e7ba8f306fcfc8566f09cc8f64b6f318aeae96a1 Mon Sep 17 00:00:00 2001 From: Theodore Dubois Date: Sun, 20 Oct 2024 18:24:04 -0700 Subject: [PATCH] Add real implementation of statx Fixes #2418 --- fs/stat.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/stat.h | 35 +++++++++++++++++++++++++++++++++ kernel/calls.c | 2 +- kernel/calls.h | 1 + kernel/fs.h | 1 + 5 files changed, 90 insertions(+), 1 deletion(-) diff --git a/fs/stat.c b/fs/stat.c index d277bae4f5..c509b41d1b 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -93,3 +93,55 @@ dword_t sys_fstat64(fd_t fd_no, addr_t statbuf_addr) { return _EFAULT; return 0; } + +dword_t sys_statx(fd_t at_f, addr_t path_addr, int_t flags, uint_t mask, addr_t statx_addr) { + int err; + char path[MAX_PATH]; + if (user_read_string(path_addr, path, sizeof(path))) + return _EFAULT; + struct fd *at = at_fd(at_f); + if (at == NULL) + return _EBADF; + + STRACE("statx(at=%d, path=\"%s\", flags=%d, mask=%d, statx=0x%x)", at_f, path, flags, mask, statx_addr); + + struct statbuf stat = {}; + + if ((flags & AT_EMPTY_PATH_) && strcmp(path, "") == 0) { + struct fd *fd = at; + int err = fd->mount->fs->fstat(fd, &stat); + if (err < 0) + return err; + } else { + bool follow_links = !(flags & AT_SYMLINK_NOFOLLOW_); + int err = generic_statat(at, path, &stat, follow_links); + if (err < 0) + return err; + } + + // for now, ignore the requested mask and just fill in the same fields as stat returns + struct statx_ statx = {}; + statx.mask = STATX_BASIC_STATS_; + statx.blksize = stat.blksize; + statx.nlink = stat.nlink; + statx.uid = stat.uid; + statx.gid = stat.gid; + statx.mode = stat.mode; + statx.ino = stat.inode; + statx.size = stat.size; + statx.blocks = stat.blocks; + statx.atime.sec = stat.atime; + statx.atime.nsec = stat.atime_nsec; + statx.mtime.sec = stat.mtime; + statx.mtime.nsec = stat.mtime_nsec; + statx.ctime.sec = stat.ctime; + statx.ctime.nsec = stat.ctime_nsec; + statx.rdev_major = dev_major(stat.rdev); + statx.rdev_minor = dev_minor(stat.rdev); + statx.dev_major = dev_major(stat.dev); + statx.dev_minor = dev_minor(stat.dev); + + if (user_put(statx_addr, statx)) + return _EFAULT; + return 0; +} diff --git a/fs/stat.h b/fs/stat.h index 632c172bdb..51557c4681 100644 --- a/fs/stat.h +++ b/fs/stat.h @@ -123,4 +123,39 @@ struct statfs64_ { uint_t pad[4]; } __attribute__((packed)); +struct statx_timestamp_ { + int64_t sec; + uint32_t nsec; + uint32_t _pad; +}; + +struct statx_ { + uint32_t mask; + uint32_t blksize; + uint64_t attributes; + uint32_t nlink; + uint32_t uid; + uint32_t gid; + uint16_t mode; + uint16_t _pad1; + uint64_t ino; + uint64_t size; + uint64_t blocks; + uint64_t attributes_mask; + struct statx_timestamp_ atime; + struct statx_timestamp_ btime; + struct statx_timestamp_ ctime; + struct statx_timestamp_ mtime; + uint32_t rdev_major; + uint32_t rdev_minor; + uint32_t dev_major; + uint32_t dev_minor; + uint64_t mnt_id; + uint32_t dio_mem_align; + uint32_t dio_offset_align; + uint32_t _pad2[24]; +} __attribute__((packed)); + +#define STATX_BASIC_STATS_ 0x7ff + #endif diff --git a/kernel/calls.c b/kernel/calls.c index 88d214b1c6..10f06e6b96 100644 --- a/kernel/calls.c +++ b/kernel/calls.c @@ -246,7 +246,7 @@ syscall_t syscall_table[] = { [373] = (syscall_t) sys_shutdown, [375] = (syscall_t) syscall_silent_stub, // membarrier [377] = (syscall_t) sys_copy_file_range, - [383] = (syscall_t) syscall_silent_stub, // statx + [383] = (syscall_t) sys_statx, [384] = (syscall_t) sys_arch_prctl, [422] = (syscall_t) syscall_silent_stub, // futex_time64 [439] = (syscall_t) syscall_silent_stub, // faccessat2 diff --git a/kernel/calls.h b/kernel/calls.h index 9fd7c4d962..5a661102d3 100644 --- a/kernel/calls.h +++ b/kernel/calls.h @@ -158,6 +158,7 @@ dword_t sys_statfs(addr_t path_addr, addr_t buf_addr); dword_t sys_statfs64(addr_t path_addr, dword_t buf_size, addr_t buf_addr); dword_t sys_fstatfs(fd_t f, addr_t buf_addr); dword_t sys_fstatfs64(fd_t f, addr_t buf_addr); +dword_t sys_statx(fd_t at_f, addr_t path_addr, int_t flags, uint_t mask, addr_t statx_addr); #define MS_READONLY_ (1 << 0) #define MS_NOSUID_ (1 << 1) diff --git a/kernel/fs.h b/kernel/fs.h index 5a8154ccb4..5a0becc7f0 100644 --- a/kernel/fs.h +++ b/kernel/fs.h @@ -45,6 +45,7 @@ struct attr { ((struct attr) {.type = attr_##_type, ._type = thing}) #define AT_SYMLINK_NOFOLLOW_ 0x100 +#define AT_EMPTY_PATH_ 0x1000 struct fd *generic_open(const char *path, int flags, int mode); struct fd *generic_openat(struct fd *at, const char *path, int flags, int mode);