From 40fc7a1fdac23b1799ebce69c2a65236886bc360 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 12 Oct 2019 14:55:02 +0200 Subject: [PATCH] Add support for the statx syscall --- lib/std/os/bits/linux.zig | 78 +++++++++++++++++++++++++++++++++++++++ lib/std/os/linux.zig | 14 +++++++ lib/std/os/linux/test.zig | 32 ++++++++++++++++ 3 files changed, 124 insertions(+) diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 5ed5c0b622..0d70a6bcaa 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -1293,3 +1293,81 @@ pub const utsname = extern struct { domainname: [65]u8, }; pub const HOST_NAME_MAX = 64; + +pub const STATX_TYPE = 0x0001; +pub const STATX_MODE = 0x0002; +pub const STATX_NLINK = 0x0004; +pub const STATX_UID = 0x0008; +pub const STATX_GID = 0x0010; +pub const STATX_ATIME = 0x0020; +pub const STATX_MTIME = 0x0040; +pub const STATX_CTIME = 0x0080; +pub const STATX_INO = 0x0100; +pub const STATX_SIZE = 0x0200; +pub const STATX_BLOCKS = 0x0400; +pub const STATX_BASIC_STATS = 0x07ff; + +pub const STATX_BTIME = 0x0800; + +pub const STATX_ATTR_COMPRESSED = 0x0004; +pub const STATX_ATTR_IMMUTABLE = 0x0010; +pub const STATX_ATTR_APPEND = 0x0020; +pub const STATX_ATTR_NODUMP = 0x0040; +pub const STATX_ATTR_ENCRYPTED = 0x0800; +pub const STATX_ATTR_AUTOMOUNT = 0x1000; + +pub const statx_timestamp = extern struct { + tv_sec: i64, + tv_nsec: u32, + __pad1: u32, +}; + +pub const Statx = extern struct { + // Mask of bits indicating filled fields + stx_mask: u32, + // Block size for filesystem I/O + stx_blksize: u32, + // Extra file attribute indicators + 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 type and mode + stx_mode: u16, + __pad1: u16, + // Inode number + stx_ino: u64, + // Total size in bytes + stx_size: u64, + // Number of 512B blocks allocated + stx_blocks: u64, + // Mask to show what's supported in stx_attributes + stx_attributes_mask: u64, + + // The following fields are file timestamps + // Last access + stx_atime: statx_timestamp, + // Creation + stx_btime: statx_timestamp, + // Last status change + stx_ctime: statx_timestamp, + // Last modification + stx_mtime: statx_timestamp, + + // If this file represents a device, then the next two fields contain the ID of the device + // Major ID + stx_rdev_major: u32, + // Minor ID + stx_rdev_minor: u32, + + // The next two fields contain the ID of the device containing the filesystem where the file resides + // Major ID + stx_dev_major: u32, + // Minor ID + stx_dev_minor: u32, + + __pad2: [14]u64, +}; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 46aeb28f2f..c91b6ad98b 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -860,6 +860,20 @@ pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize } } +pub fn statx(dirfd: i32, path: [*]const u8, flags: u32, mask: u32, statx_buf: *Statx) usize { + if (@hasDecl(@This(), "SYS_statx")) { + return syscall5( + SYS_statx, + @bitCast(usize, isize(dirfd)), + @ptrToInt(path), + flags, + mask, + @ptrToInt(statx_buf), + ); + } + return @bitCast(usize, isize(-ENOSYS)); +} + // TODO https://github.com/ziglang/zig/issues/265 pub fn listxattr(path: [*]const u8, list: [*]u8, size: usize) usize { return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size); diff --git a/lib/std/os/linux/test.zig b/lib/std/os/linux/test.zig index 97bbcc402d..3782bc3301 100644 --- a/lib/std/os/linux/test.zig +++ b/lib/std/os/linux/test.zig @@ -44,3 +44,35 @@ test "timer" { // TODO implicit cast from *[N]T to [*]T err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1); } + +const File = std.fs.File; + +test "statx" { + const tmp_file_name = "just_a_temporary_file.txt"; + var file = try File.openWrite(tmp_file_name); + defer { + file.close(); + std.fs.deleteFile(tmp_file_name) catch {}; + } + + var statx_buf: linux.Statx = undefined; + switch (linux.getErrno(linux.statx(file.handle, c"", linux.AT_EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) { + 0 => {}, + // The statx syscall was only introduced in linux 4.11 + linux.ENOSYS => return error.SkipZigTest, + else => unreachable, + } + + var stat_buf: linux.Stat = undefined; + switch (linux.getErrno(linux.fstatat(file.handle, c"", &stat_buf, linux.AT_EMPTY_PATH))) { + 0 => {}, + else => unreachable, + } + + expect(stat_buf.mode == statx_buf.stx_mode); + expect(@bitCast(u32, stat_buf.uid) == statx_buf.stx_uid); + expect(@bitCast(u32, stat_buf.gid) == statx_buf.stx_gid); + expect(@bitCast(u64, i64(stat_buf.size)) == statx_buf.stx_size); + expect(@bitCast(u64, i64(stat_buf.blksize)) == statx_buf.stx_blksize); + expect(@bitCast(u64, i64(stat_buf.blocks)) == statx_buf.stx_blocks); +}