authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-12-14 05:25:29+01:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-12-14 05:25:29+01:00
log2f2b09757682d4c3624d8e6d470852b1d1d6264d
tree127627d7a0c5d5336df3296fe45755609b86e04e
parentc13857e504f5893cabf182dde1e826131f2acf24
parentaec7bfb09219e32389ad666906166f690a158fbe

Merge pull request 'Linux: Nuke Stat bits in favour of Statx' (#30122) from The-King-of-Toasters/zig:statx into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30122 Reviewed-by: Alex Rønne Petersen <alex@alexrp.com>

29 files changed, 358 insertions(+), 1083 deletions(-)

lib/std/Io/Threaded.zig+16-2
......@@ -1533,12 +1533,19 @@ fn dirStatPathLinux(
15331533 dir.handle,
15341534 sub_path_posix,
15351535 flags,
1536 linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
1536 .{ .TYPE = true, .MODE = true, .ATIME = true, .MTIME = true, .CTIME = true, .INO = true, .SIZE = true },
15371537 &statx,
15381538 );
15391539 switch (linux.errno(rc)) {
15401540 .SUCCESS => {
15411541 current_thread.endSyscall();
1542 assert(statx.mask.TYPE);
1543 assert(statx.mask.MODE);
1544 assert(statx.mask.ATIME);
1545 assert(statx.mask.MTIME);
1546 assert(statx.mask.CTIME);
1547 assert(statx.mask.INO);
1548 assert(statx.mask.SIZE);
15421549 return statFromLinux(&statx);
15431550 },
15441551 .INTR => {
......@@ -1725,12 +1732,19 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
17251732 file.handle,
17261733 "",
17271734 linux.AT.EMPTY_PATH,
1728 linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
1735 .{ .TYPE = true, .MODE = true, .ATIME = true, .MTIME = true, .CTIME = true, .INO = true, .SIZE = true },
17291736 &statx,
17301737 );
17311738 switch (linux.errno(rc)) {
17321739 .SUCCESS => {
17331740 current_thread.endSyscall();
1741 assert(statx.mask.TYPE);
1742 assert(statx.mask.MODE);
1743 assert(statx.mask.ATIME);
1744 assert(statx.mask.MTIME);
1745 assert(statx.mask.CTIME);
1746 assert(statx.mask.INO);
1747 assert(statx.mask.SIZE);
17341748 return statFromLinux(&statx);
17351749 },
17361750 .INTR => {
lib/std/c.zig+5-163
......@@ -7586,166 +7586,6 @@ pub const EAI = if (builtin.abi.isAndroid()) enum(c_int) {
75867586pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.c) c_int;
75877587
75887588pub const Stat = switch (native_os) {
7589 .linux => switch (native_arch) {
7590 .sparc64 => extern struct {
7591 dev: u64,
7592 __pad1: u16,
7593 ino: ino_t,
7594 mode: u32,
7595 nlink: u32,
7596
7597 uid: u32,
7598 gid: u32,
7599 rdev: u64,
7600 __pad2: u16,
7601
7602 size: off_t,
7603 blksize: isize,
7604 blocks: i64,
7605
7606 atim: timespec,
7607 mtim: timespec,
7608 ctim: timespec,
7609 __reserved: [2]usize,
7610
7611 pub fn atime(self: @This()) timespec {
7612 return self.atim;
7613 }
7614
7615 pub fn mtime(self: @This()) timespec {
7616 return self.mtim;
7617 }
7618
7619 pub fn ctime(self: @This()) timespec {
7620 return self.ctim;
7621 }
7622 },
7623 .mips, .mipsel => if (builtin.target.abi.isMusl()) extern struct {
7624 dev: dev_t,
7625 __pad0: [2]i32,
7626 ino: ino_t,
7627 mode: mode_t,
7628 nlink: nlink_t,
7629 uid: uid_t,
7630 gid: gid_t,
7631 rdev: dev_t,
7632 __pad1: [2]i32,
7633 size: off_t,
7634 atim: timespec,
7635 mtim: timespec,
7636 ctim: timespec,
7637 blksize: blksize_t,
7638 __pad3: i32,
7639 blocks: blkcnt_t,
7640 __pad4: [14]i32,
7641
7642 pub fn atime(self: @This()) timespec {
7643 return self.atim;
7644 }
7645
7646 pub fn mtime(self: @This()) timespec {
7647 return self.mtim;
7648 }
7649
7650 pub fn ctime(self: @This()) timespec {
7651 return self.ctim;
7652 }
7653 } else extern struct {
7654 dev: u32,
7655 __pad0: [3]u32,
7656 ino: ino_t,
7657 mode: mode_t,
7658 nlink: nlink_t,
7659 uid: uid_t,
7660 gid: gid_t,
7661 rdev: u32,
7662 __pad1: [3]u32,
7663 size: off_t,
7664 atim: timespec,
7665 mtim: timespec,
7666 ctim: timespec,
7667 blksize: blksize_t,
7668 __pad3: u32,
7669 blocks: blkcnt_t,
7670 __pad4: [14]u32,
7671
7672 pub fn atime(self: @This()) timespec {
7673 return self.atim;
7674 }
7675
7676 pub fn mtime(self: @This()) timespec {
7677 return self.mtim;
7678 }
7679
7680 pub fn ctime(self: @This()) timespec {
7681 return self.ctim;
7682 }
7683 },
7684 .mips64, .mips64el => if (builtin.target.abi.isMusl()) extern struct {
7685 dev: dev_t,
7686 __pad0: [3]i32,
7687 ino: ino_t,
7688 mode: mode_t,
7689 nlink: nlink_t,
7690 uid: uid_t,
7691 gid: gid_t,
7692 rdev: dev_t,
7693 __pad1: [2]u32,
7694 size: off_t,
7695 __pad2: i32,
7696 atim: timespec,
7697 mtim: timespec,
7698 ctim: timespec,
7699 blksize: blksize_t,
7700 __pad3: u32,
7701 blocks: blkcnt_t,
7702 __pad4: [14]i32,
7703
7704 pub fn atime(self: @This()) timespec {
7705 return self.atim;
7706 }
7707
7708 pub fn mtime(self: @This()) timespec {
7709 return self.mtim;
7710 }
7711
7712 pub fn ctime(self: @This()) timespec {
7713 return self.ctim;
7714 }
7715 } else extern struct {
7716 dev: dev_t,
7717 __pad0: [3]u32,
7718 ino: ino_t,
7719 mode: mode_t,
7720 nlink: nlink_t,
7721 uid: uid_t,
7722 gid: gid_t,
7723 rdev: dev_t,
7724 __pad1: [3]u32,
7725 size: off_t,
7726 atim: timespec,
7727 mtim: timespec,
7728 ctim: timespec,
7729 blksize: blksize_t,
7730 __pad3: u32,
7731 blocks: blkcnt_t,
7732 __pad4: [14]i32,
7733
7734 pub fn atime(self: @This()) timespec {
7735 return self.atim;
7736 }
7737
7738 pub fn mtime(self: @This()) timespec {
7739 return self.mtim;
7740 }
7741
7742 pub fn ctime(self: @This()) timespec {
7743 return self.ctim;
7744 }
7745 },
7746
7747 else => std.os.linux.Stat, // libc stat is the same as kernel stat.
7748 },
77497589 .emscripten => emscripten.Stat,
77507590 .wasi => extern struct {
77517591 // Match wasi-libc's `struct stat` in lib/libc/include/wasm-wasi-musl/__struct_stat.h
......@@ -10422,6 +10262,7 @@ pub const fstat = switch (native_os) {
1042210262 else => private.fstat,
1042310263 },
1042410264 .netbsd => private.__fstat50,
10265 .linux => {},
1042510266 else => private.fstat,
1042610267};
1042710268
......@@ -10430,8 +10271,12 @@ pub const fstatat = switch (native_os) {
1043010271 .x86_64 => private.@"fstatat$INODE64",
1043110272 else => private.fstatat,
1043210273 },
10274 .linux => {},
1043310275 else => private.fstatat,
1043410276};
10277
10278pub extern "c" fn statx(dirfd: fd_t, path: [*:0]const u8, flags: u32, mask: linux.STATX, buf: *linux.Statx) c_int;
10279
1043510280pub extern "c" fn getpwent() ?*passwd;
1043610281pub extern "c" fn endpwent() void;
1043710282pub extern "c" fn setpwent() void;
......@@ -10505,8 +10350,6 @@ pub extern "c" fn inotify_init1(flags: c_uint) c_int;
1050510350pub extern "c" fn inotify_add_watch(fd: fd_t, pathname: [*:0]const u8, mask: u32) c_int;
1050610351pub extern "c" fn inotify_rm_watch(fd: fd_t, wd: c_int) c_int;
1050710352
10508pub extern "c" fn fstat64(fd: fd_t, buf: *Stat) c_int;
10509pub extern "c" fn fstatat64(dirfd: fd_t, noalias path: [*:0]const u8, noalias stat_buf: *Stat, flags: u32) c_int;
1051010353pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
1051110354pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE;
1051210355pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
......@@ -11552,7 +11395,6 @@ const private = struct {
1155211395 extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
1155311396 extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
1155411397 extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int;
11555 extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
1155611398 extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
1155711399 extern "c" fn sysconf(sc: c_int) c_long;
1155811400 extern "c" fn shm_open(name: [*:0]const u8, flag: c_int, mode: mode_t) c_int;
lib/std/os/linux.zig+174-118
......@@ -95,15 +95,14 @@ pub fn clone(
9595pub const ARCH = arch_bits.ARCH;
9696pub const HWCAP = arch_bits.HWCAP;
9797pub const SC = arch_bits.SC;
98pub const Stat = arch_bits.Stat;
9998pub const VDSO = arch_bits.VDSO;
100pub const blkcnt_t = arch_bits.blkcnt_t;
101pub const blksize_t = arch_bits.blksize_t;
102pub const dev_t = arch_bits.dev_t;
103pub const ino_t = arch_bits.ino_t;
104pub const mode_t = arch_bits.mode_t;
105pub const nlink_t = arch_bits.nlink_t;
106pub const off_t = arch_bits.off_t;
99pub const blkcnt_t = u64;
100pub const blksize_t = u32;
101pub const dev_t = u64;
102pub const ino_t = u64;
103pub const mode_t = u32;
104pub const nlink_t = u32;
105pub const off_t = i64;
107106pub const time_t = arch_bits.time_t;
108107pub const user_desc = arch_bits.user_desc;
109108
......@@ -2199,61 +2198,13 @@ pub fn accept4(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t, flag
21992198 return syscall4(.accept4, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(addr), @intFromPtr(len), flags);
22002199}
22012200
2202pub fn fstat(fd: i32, stat_buf: *Stat) usize {
2203 if (native_arch == .riscv32 or native_arch.isLoongArch()) {
2204 // riscv32 and loongarch have made the interesting decision to not implement some of
2205 // the older stat syscalls, including this one.
2206 @compileError("No fstat syscall on this architecture.");
2207 } else if (@hasField(SYS, "fstat64")) {
2208 return syscall2(.fstat64, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(stat_buf));
2209 } else {
2210 return syscall2(.fstat, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(stat_buf));
2211 }
2212}
2213
2214pub fn stat(pathname: [*:0]const u8, statbuf: *Stat) usize {
2215 if (native_arch == .riscv32 or native_arch.isLoongArch()) {
2216 // riscv32 and loongarch have made the interesting decision to not implement some of
2217 // the older stat syscalls, including this one.
2218 @compileError("No stat syscall on this architecture.");
2219 } else if (@hasField(SYS, "stat64")) {
2220 return syscall2(.stat64, @intFromPtr(pathname), @intFromPtr(statbuf));
2221 } else {
2222 return syscall2(.stat, @intFromPtr(pathname), @intFromPtr(statbuf));
2223 }
2224}
2225
2226pub fn lstat(pathname: [*:0]const u8, statbuf: *Stat) usize {
2227 if (native_arch == .riscv32 or native_arch.isLoongArch()) {
2228 // riscv32 and loongarch have made the interesting decision to not implement some of
2229 // the older stat syscalls, including this one.
2230 @compileError("No lstat syscall on this architecture.");
2231 } else if (@hasField(SYS, "lstat64")) {
2232 return syscall2(.lstat64, @intFromPtr(pathname), @intFromPtr(statbuf));
2233 } else {
2234 return syscall2(.lstat, @intFromPtr(pathname), @intFromPtr(statbuf));
2235 }
2236}
2237
2238pub fn fstatat(dirfd: i32, path: [*:0]const u8, stat_buf: *Stat, flags: u32) usize {
2239 if (native_arch == .riscv32 or native_arch.isLoongArch()) {
2240 // riscv32 and loongarch have made the interesting decision to not implement some of
2241 // the older stat syscalls, including this one.
2242 @compileError("No fstatat syscall on this architecture.");
2243 } else if (@hasField(SYS, "fstatat64")) {
2244 return syscall4(.fstatat64, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), @intFromPtr(stat_buf), flags);
2245 } else {
2246 return syscall4(.fstatat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), @intFromPtr(stat_buf), flags);
2247 }
2248}
2249
2250pub fn statx(dirfd: i32, path: [*:0]const u8, flags: u32, mask: u32, statx_buf: *Statx) usize {
2201pub fn statx(dirfd: i32, path: [*:0]const u8, flags: u32, mask: STATX, statx_buf: *Statx) usize {
22512202 return syscall5(
22522203 .statx,
22532204 @as(usize, @bitCast(@as(isize, dirfd))),
22542205 @intFromPtr(path),
22552206 flags,
2256 mask,
2207 @as(u32, @bitCast(mask)),
22572208 @intFromPtr(statx_buf),
22582209 );
22592210}
......@@ -6940,96 +6891,161 @@ pub const utsname = extern struct {
69406891};
69416892pub const HOST_NAME_MAX = 64;
69426893
6943pub const STATX_TYPE = 0x0001;
6944pub const STATX_MODE = 0x0002;
6945pub const STATX_NLINK = 0x0004;
6946pub const STATX_UID = 0x0008;
6947pub const STATX_GID = 0x0010;
6948pub const STATX_ATIME = 0x0020;
6949pub const STATX_MTIME = 0x0040;
6950pub const STATX_CTIME = 0x0080;
6951pub const STATX_INO = 0x0100;
6952pub const STATX_SIZE = 0x0200;
6953pub const STATX_BLOCKS = 0x0400;
6954pub const STATX_BASIC_STATS = 0x07ff;
6955
6956pub const STATX_BTIME = 0x0800;
6957
6958pub const STATX_ATTR_COMPRESSED = 0x0004;
6959pub const STATX_ATTR_IMMUTABLE = 0x0010;
6960pub const STATX_ATTR_APPEND = 0x0020;
6961pub const STATX_ATTR_NODUMP = 0x0040;
6962pub const STATX_ATTR_ENCRYPTED = 0x0800;
6963pub const STATX_ATTR_AUTOMOUNT = 0x1000;
6894/// Flags used to request specific members in `Statx` be filled out.
6895/// The `Statx.mask` member will be updated with what information the kernel
6896/// returned. Callers must check this field since support varies by kernel
6897/// version and filesystem.
6898pub const STATX = packed struct(u32) {
6899 /// Want `mode & S.IFMT`.
6900 TYPE: bool = false,
6901 /// Want `mode & ~S.IFMT`.
6902 MODE: bool = false,
6903 /// Want the `nlink` member.
6904 NLINK: bool = false,
6905 /// Want the `uid` member.
6906 UID: bool = false,
6907 /// Want the `gid` member.
6908 GID: bool = false,
6909 /// Want the `atime` member.
6910 ATIME: bool = false,
6911 /// Want the `mtime` member.
6912 MTIME: bool = false,
6913 /// Want the `ctime` member.
6914 CTIME: bool = false,
6915 /// Want the `ino` member.
6916 INO: bool = false,
6917 /// Want the `size` member.
6918 SIZE: bool = false,
6919 /// Want the `blocks` member.
6920 BLOCKS: bool = false,
6921 /// Want the `btime` member.
6922 BTIME: bool = false,
6923 /// Want the `mnt_id` member.
6924 MNT_ID: bool = false,
6925 /// Want the `dio_mem_align` and `dio_offset_align` members.
6926 DIOALIGN: bool = false,
6927 /// Want the `stx_mnt_id` member.
6928 MNT_ID_UNIQUE: bool = false,
6929 /// Want the `sub` member.
6930 SUBVOL: bool = false,
6931 /// Want the `atomic_write_unit_min`, `atomic_write_unit_max` and
6932 /// `atomic_write_segments_max` members.
6933 WRITE_ATOMIC: bool = false,
6934 /// Want the `dio_read_offset_align` member.
6935 DIO_READ_ALIGN: bool = false,
6936 __pad: u13 = 0,
6937 /// Reserved for future expansion; must not be set.
6938 __RESERVED: bool = false,
6939
6940 pub const BASIC_STATS: STATX = @bitCast(@as(u32, 0x7ff));
6941};
6942
6943/// Attributes about the state or features of a file as a bitmask.
6944/// Flags marked [I] correspond to the `FS_IOC_SETFLAGS` values semantically.
6945/// See [FS_IOC_SETFLAGS(2const)](https://man7.org/linux/man-pages/man2/FS_IOC_GETFLAGS.2const.html)
6946/// for more.
6947pub const STATX_ATTR = packed struct(u64) {
6948 __pad1: u3 = 0,
6949 /// [I] File is compressed by the fs.
6950 COMPRESSED: bool = false,
6951 __pad2: u1 = 0,
6952 /// [I] File is marked immutable.
6953 IMMUTABLE: bool = false,
6954 /// [I] File is append-only.
6955 APPEND: bool = false,
6956 /// [I] File is not to be dumped.
6957 NODUMP: bool = false,
6958 /// [I] File requires a key to decrypt in the filesystem.
6959 ENCRYPTED: bool = false,
6960 /// File names a directory that triggers an automount.
6961 AUTOMOUNT: bool = false,
6962 /// File names the root of a mount.
6963 MOUNT_ROOT: bool = false,
6964 /// [I] File is protected by the `dm-verity` device.
6965 VERITY: bool = false,
6966 /// File is currently in the CPU direct access state.
6967 /// Does not correspond to the per-inode DAX flag that some filesystems support.
6968 DAX: bool = false,
6969 /// File supports atomic write operations.
6970 WRITE_ATOMIC: bool = false,
6971 __pad3: u50 = 0,
6972};
69646973
69656974pub const statx_timestamp = extern struct {
6975 /// Number of seconds before or after `1970-01-01T00:00:00Z`.
69666976 sec: i64,
6977 /// Number of nanoseconds (0..999,999,999) after `sec`.
69676978 nsec: u32,
6979 // Reserved for future increases in resolution.
69686980 __pad1: u32,
69696981};
69706982
69716983/// Renamed to `Statx` to not conflict with the `statx` function.
69726984pub const Statx = extern struct {
6973 /// Mask of bits indicating filled fields
6974 mask: u32,
6975
6976 /// Block size for filesystem I/O
6985 /// Mask of bits indicating filled fields.
6986 mask: STATX,
6987 /// Block size for filesystem I/O.
69776988 blksize: u32,
6978
6979 /// Extra file attribute indicators
6980 attributes: u64,
6981
6982 /// Number of hard links
6989 /// Extra file attribute indicators.
6990 attributes: STATX_ATTR,
6991 /// Number of hard links.
69836992 nlink: u32,
6984
6985 /// User ID of owner
6993 /// User ID of owner.
69866994 uid: uid_t,
6987
6988 /// Group ID of owner
6995 /// Group ID of owner.
69896996 gid: gid_t,
6990
6991 /// File type and mode
6997 /// File type and mode.
69926998 mode: u16,
6993 __pad1: u16,
6994
6995 /// Inode number
6999 __spare0: u16,
7000 /// Inode number.
69967001 ino: u64,
6997
6998 /// Total size in bytes
7002 /// Total size in bytes.
69997003 size: u64,
7000
7001 /// Number of 512B blocks allocated
7004 /// Number of 512B blocks allocated.
70027005 blocks: u64,
7003
70047006 /// Mask to show what's supported in `attributes`.
7005 attributes_mask: u64,
7006
7007 /// Last access file timestamp
7007 attributes_mask: STATX_ATTR,
7008 /// Last access file timestamp.
70087009 atime: statx_timestamp,
7009
7010 /// Creation file timestamp
7010 /// Creation file timestamp.
70117011 btime: statx_timestamp,
7012
7013 /// Last status change file timestamp
7012 /// Last status change file timestamp.
70147013 ctime: statx_timestamp,
7015
7016 /// Last modification file timestamp
7014 /// Last modification file timestamp.
70177015 mtime: statx_timestamp,
7018
70197016 /// Major ID, if this file represents a device.
70207017 rdev_major: u32,
7021
70227018 /// Minor ID, if this file represents a device.
70237019 rdev_minor: u32,
7024
70257020 /// Major ID of the device containing the filesystem where this file resides.
70267021 dev_major: u32,
7027
70287022 /// Minor ID of the device containing the filesystem where this file resides.
70297023 dev_minor: u32,
7030
7031 __pad2: [14]u64,
7032};
7024 /// Mount ID
7025 mnt_id: u64,
7026 /// Memory buffer alignment for direct I/O.
7027 dio_mem_align: u32,
7028 /// File offset alignment for direct I/O.
7029 dio_offset_align: u32,
7030 /// Subvolume identifier.
7031 subvol: u64,
7032 /// Min atomic write unit in bytes.
7033 atomic_write_unit_min: u32,
7034 /// Max atomic write unit in bytes.
7035 atomic_write_unit_max: u32,
7036 /// Max atomic write segment count.
7037 atomic_write_segments_max: u32,
7038 /// File offset alignment for direct I/O reads.
7039 dio_read_offset_align: u32,
7040 /// Optimised max atomic write unit in bytes.
7041 atomic_write_unit_max_opt: u32,
7042 __spare2: [1]u32,
7043 __spare3: [8]u64,
7044};
7045
7046comptime {
7047 assert(@sizeOf(Statx) == 0x100);
7048}
70337049
70347050pub const addrinfo = extern struct {
70357051 flags: AI,
......@@ -9970,6 +9986,46 @@ pub const wrapped = struct {
99709986 }
99719987 }
99729988
9989 pub const StatxError = std.posix.UnexpectedError || error{
9990 /// Search permission is denied for one of the directories in `path`.
9991 AccessDenied,
9992 /// Too many symbolic links were encountered traversing `path`.
9993 SymLinkLoop,
9994 /// `path` is too long.
9995 NameTooLong,
9996 /// One of:
9997 /// - A component of `path` does not exist.
9998 /// - A component of `path` is not a directory.
9999 /// - `path` is a relative and `dirfd` is not a directory file descriptor.
10000 FileNotFound,
10001 /// Insufficient memory is available.
10002 SystemResources,
10003 };
10004
10005 pub fn statx(dirfd: fd_t, path: [*:0]const u8, flags: u32, mask: STATX) StatxError!Statx {
10006 const use_c = std.c.versionCheck(if (builtin.abi.isAndroid())
10007 .{ .major = 30, .minor = 0, .patch = 0 }
10008 else
10009 .{ .major = 2, .minor = 28, .patch = 0 });
10010 const sys = if (use_c) std.c else std.os.linux;
10011
10012 var stx = std.mem.zeroes(Statx);
10013 const rc = sys.statx(dirfd, path, flags, mask, &stx);
10014 return switch (sys.errno(rc)) {
10015 .SUCCESS => stx,
10016 .ACCES => error.AccessDenied,
10017 .BADF => invalidApiUsage(),
10018 .FAULT => invalidApiUsage(),
10019 .INVAL => invalidApiUsage(),
10020 .LOOP => error.SymLinkLoop,
10021 .NAMETOOLONG => error.NameTooLong,
10022 .NOENT => error.FileNotFound,
10023 .NOTDIR => error.FileNotFound,
10024 .NOMEM => error.SystemResources,
10025 else => |err| unexpectedErrno(err),
10026 };
10027 }
10028
997310029 const unexpectedErrno = std.posix.unexpectedErrno;
997410030
997510031 fn invalidApiUsage() error{Unexpected} {
lib/std/os/linux/IoUring.zig+3-3
......@@ -958,7 +958,7 @@ pub fn statx(
958958 fd: linux.fd_t,
959959 path: [:0]const u8,
960960 flags: u32,
961 mask: u32,
961 mask: linux.STATX,
962962 buf: *linux.Statx,
963963) !*linux.io_uring_sqe {
964964 const sqe = try self.get_sqe();
......@@ -2691,7 +2691,7 @@ test "statx" {
26912691 tmp.dir.fd,
26922692 path,
26932693 0,
2694 linux.STATX_SIZE,
2694 .{ .SIZE = true },
26952695 &buf,
26962696 );
26972697 try testing.expectEqual(linux.IORING_OP.STATX, sqe.opcode);
......@@ -2718,7 +2718,7 @@ test "statx" {
27182718 .flags = 0,
27192719 }, cqe);
27202720
2721 try testing.expect(buf.mask & linux.STATX_SIZE == linux.STATX_SIZE);
2721 try testing.expect(buf.mask.SIZE);
27222722 try testing.expectEqual(@as(u64, 6), buf.size);
27232723}
27242724
lib/std/os/linux/aarch64.zig-39
......@@ -143,43 +143,4 @@ pub const VDSO = struct {
143143 pub const CGT_VER = "LINUX_2.6.39";
144144};
145145
146pub const blksize_t = i32;
147pub const nlink_t = u32;
148146pub const time_t = i64;
149pub const mode_t = u32;
150pub const off_t = i64;
151pub const ino_t = u64;
152pub const dev_t = u64;
153pub const blkcnt_t = i64;
154
155// The `stat` definition used by the Linux kernel.
156pub const Stat = extern struct {
157 dev: dev_t,
158 ino: ino_t,
159 mode: mode_t,
160 nlink: nlink_t,
161 uid: std.os.linux.uid_t,
162 gid: std.os.linux.gid_t,
163 rdev: dev_t,
164 __pad: u64,
165 size: off_t,
166 blksize: blksize_t,
167 __pad2: i32,
168 blocks: blkcnt_t,
169 atim: std.os.linux.timespec,
170 mtim: std.os.linux.timespec,
171 ctim: std.os.linux.timespec,
172 __unused: [2]u32,
173
174 pub fn atime(self: @This()) std.os.linux.timespec {
175 return self.atim;
176 }
177
178 pub fn mtime(self: @This()) std.os.linux.timespec {
179 return self.mtim;
180 }
181
182 pub fn ctime(self: @This()) std.os.linux.timespec {
183 return self.ctim;
184 }
185};
lib/std/os/linux/arm.zig-39
......@@ -179,43 +179,4 @@ pub const HWCAP = struct {
179179 pub const EVTSTRM = 1 << 21;
180180};
181181
182pub const blksize_t = i32;
183pub const nlink_t = u32;
184182pub const time_t = i32;
185pub const mode_t = u32;
186pub const off_t = i64;
187pub const ino_t = u64;
188pub const dev_t = u64;
189pub const blkcnt_t = i64;
190
191// The `stat` definition used by the Linux kernel.
192pub const Stat = extern struct {
193 dev: dev_t,
194 __dev_padding: u32,
195 __ino_truncated: u32,
196 mode: mode_t,
197 nlink: nlink_t,
198 uid: std.os.linux.uid_t,
199 gid: std.os.linux.gid_t,
200 rdev: dev_t,
201 __rdev_padding: u32,
202 size: off_t,
203 blksize: blksize_t,
204 blocks: blkcnt_t,
205 atim: std.os.linux.timespec,
206 mtim: std.os.linux.timespec,
207 ctim: std.os.linux.timespec,
208 ino: ino_t,
209
210 pub fn atime(self: @This()) std.os.linux.timespec {
211 return self.atim;
212 }
213
214 pub fn mtime(self: @This()) std.os.linux.timespec {
215 return self.mtim;
216 }
217
218 pub fn ctime(self: @This()) std.os.linux.timespec {
219 return self.ctim;
220 }
221};
lib/std/os/linux/hexagon.zig-39
......@@ -119,45 +119,6 @@ pub fn clone() callconv(.naked) u32 {
119119 );
120120}
121121
122pub const blksize_t = i32;
123pub const nlink_t = u32;
124122pub const time_t = i64;
125pub const mode_t = u32;
126pub const off_t = i64;
127pub const ino_t = u64;
128pub const dev_t = u64;
129pub const blkcnt_t = i64;
130
131// The `stat` definition used by the Linux kernel.
132pub const Stat = extern struct {
133 dev: dev_t,
134 ino: ino_t,
135 mode: mode_t,
136 nlink: nlink_t,
137 uid: std.os.linux.uid_t,
138 gid: std.os.linux.gid_t,
139 rdev: dev_t,
140 __pad: u32,
141 size: off_t,
142 blksize: blksize_t,
143 __pad2: i32,
144 blocks: blkcnt_t,
145 atim: std.os.linux.timespec,
146 mtim: std.os.linux.timespec,
147 ctim: std.os.linux.timespec,
148 __unused: [2]u32,
149
150 pub fn atime(self: @This()) std.os.linux.timespec {
151 return self.atim;
152 }
153
154 pub fn mtime(self: @This()) std.os.linux.timespec {
155 return self.mtim;
156 }
157
158 pub fn ctime(self: @This()) std.os.linux.timespec {
159 return self.ctim;
160 }
161};
162123
163124pub const VDSO = void;
lib/std/os/linux/io_uring_sqe.zig+2-2
......@@ -420,10 +420,10 @@ pub const io_uring_sqe = extern struct {
420420 fd: linux.fd_t,
421421 path: [*:0]const u8,
422422 flags: u32,
423 mask: u32,
423 mask: linux.STATX,
424424 buf: *linux.Statx,
425425 ) void {
426 sqe.prep_rw(.STATX, fd, @intFromPtr(path), mask, @intFromPtr(buf));
426 sqe.prep_rw(.STATX, fd, @intFromPtr(path), @as(u32, @bitCast(mask)), @intFromPtr(buf));
427427 sqe.rw_flags = flags;
428428 }
429429
lib/std/os/linux/loongarch64.zig-39
......@@ -125,46 +125,7 @@ pub fn clone() callconv(.naked) u64 {
125125 );
126126}
127127
128pub const blksize_t = i32;
129pub const nlink_t = u32;
130128pub const time_t = i64;
131pub const mode_t = u32;
132pub const off_t = i64;
133pub const ino_t = u64;
134pub const dev_t = u32;
135pub const blkcnt_t = i64;
136
137// The `stat` definition used by the Linux kernel.
138pub const Stat = extern struct {
139 dev: dev_t,
140 ino: ino_t,
141 mode: mode_t,
142 nlink: nlink_t,
143 uid: std.os.linux.uid_t,
144 gid: std.os.linux.gid_t,
145 rdev: dev_t,
146 _pad1: u64,
147 size: off_t,
148 blksize: blksize_t,
149 _pad2: i32,
150 blocks: blkcnt_t,
151 atim: std.os.linux.timespec,
152 mtim: std.os.linux.timespec,
153 ctim: std.os.linux.timespec,
154 _pad3: [2]u32,
155
156 pub fn atime(self: @This()) std.os.linux.timespec {
157 return self.atim;
158 }
159
160 pub fn mtime(self: @This()) std.os.linux.timespec {
161 return self.mtim;
162 }
163
164 pub fn ctime(self: @This()) std.os.linux.timespec {
165 return self.ctim;
166 }
167};
168129
169130pub const VDSO = struct {
170131 pub const CGT_SYM = "__vdso_clock_gettime";
lib/std/os/linux/m68k.zig-38
......@@ -142,45 +142,7 @@ pub fn restore_rt() callconv(.naked) noreturn {
142142 );
143143}
144144
145pub const blksize_t = i32;
146pub const nlink_t = u32;
147145pub const time_t = i32;
148pub const mode_t = u32;
149pub const off_t = i64;
150pub const ino_t = u64;
151pub const dev_t = u64;
152pub const blkcnt_t = i64;
153
154pub const Stat = extern struct {
155 dev: dev_t,
156 __pad: i16,
157 __ino_truncated: i32,
158 mode: mode_t,
159 nlink: nlink_t,
160 uid: std.os.linux.uid_t,
161 gid: std.os.linux.gid_t,
162 rdev: dev_t,
163 __pad2: i16,
164 size: off_t,
165 blksize: blksize_t,
166 blocks: blkcnt_t,
167 atim: std.os.linux.timespec,
168 mtim: std.os.linux.timespec,
169 ctim: std.os.linux.timespec,
170 ino: ino_t,
171
172 pub fn atime(self: @This()) std.os.linux.timespec {
173 return self.atim;
174 }
175
176 pub fn mtime(self: @This()) std.os.linux.timespec {
177 return self.mtim;
178 }
179
180 pub fn ctime(self: @This()) std.os.linux.timespec {
181 return self.ctim;
182 }
183};
184146
185147// No VDSO used as of glibc 112a0ae18b831bf31f44d81b82666980312511d6.
186148pub const VDSO = void;
lib/std/os/linux/mips.zig-39
......@@ -230,43 +230,4 @@ pub const VDSO = struct {
230230 pub const CGT_VER = "LINUX_2.6";
231231};
232232
233pub const blksize_t = u32;
234pub const nlink_t = u32;
235233pub const time_t = i32;
236pub const mode_t = u32;
237pub const off_t = i64;
238pub const ino_t = u64;
239pub const dev_t = u64;
240pub const blkcnt_t = i64;
241
242// The `stat64` definition used by the Linux kernel.
243pub const Stat = extern struct {
244 dev: dev_t,
245 __pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
246 ino: ino_t,
247 mode: mode_t,
248 nlink: nlink_t,
249 uid: std.os.linux.uid_t,
250 gid: std.os.linux.gid_t,
251 rdev: dev_t,
252 __pad1: [2]u32,
253 size: off_t,
254 atim: std.os.linux.timespec,
255 mtim: std.os.linux.timespec,
256 ctim: std.os.linux.timespec,
257 blksize: blksize_t,
258 __pad3: u32,
259 blocks: blkcnt_t,
260
261 pub fn atime(self: @This()) std.os.linux.timespec {
262 return self.atim;
263 }
264
265 pub fn mtime(self: @This()) std.os.linux.timespec {
266 return self.mtim;
267 }
268
269 pub fn ctime(self: @This()) std.os.linux.timespec {
270 return self.ctim;
271 }
272};
lib/std/os/linux/mips64.zig-51
......@@ -184,55 +184,4 @@ pub const VDSO = struct {
184184 pub const CGT_VER = "LINUX_2.6";
185185};
186186
187pub const blksize_t = u32;
188pub const nlink_t = u32;
189187pub const time_t = i32;
190pub const mode_t = u32;
191pub const off_t = i64;
192pub const ino_t = u64;
193pub const dev_t = u64;
194pub const blkcnt_t = i64;
195
196// The `stat` definition used by the Linux kernel.
197pub const Stat = extern struct {
198 dev: dev_t,
199 __pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
200 ino: ino_t,
201 mode: mode_t,
202 nlink: nlink_t,
203 uid: std.os.linux.uid_t,
204 gid: std.os.linux.gid_t,
205 rdev: dev_t,
206 __pad1: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
207 size: off_t,
208 atim: u32,
209 atim_nsec: u32,
210 mtim: u32,
211 mtim_nsec: u32,
212 ctim: u32,
213 ctim_nsec: u32,
214 blksize: blksize_t,
215 __pad3: u32,
216 blocks: blkcnt_t,
217
218 pub fn atime(self: @This()) std.os.linux.timespec {
219 return .{
220 .sec = self.atim,
221 .nsec = self.atim_nsec,
222 };
223 }
224
225 pub fn mtime(self: @This()) std.os.linux.timespec {
226 return .{
227 .sec = self.mtim,
228 .nsec = self.mtim_nsec,
229 };
230 }
231
232 pub fn ctime(self: @This()) std.os.linux.timespec {
233 return .{
234 .sec = self.ctim,
235 .nsec = self.ctim_nsec,
236 };
237 }
238};
lib/std/os/linux/mipsn32.zig-51
......@@ -184,55 +184,4 @@ pub const VDSO = struct {
184184 pub const CGT_VER = "LINUX_2.6";
185185};
186186
187pub const blksize_t = u32;
188pub const nlink_t = u32;
189187pub const time_t = i32;
190pub const mode_t = u32;
191pub const off_t = i64;
192pub const ino_t = u64;
193pub const dev_t = u64;
194pub const blkcnt_t = i64;
195
196// The `stat` definition used by the Linux kernel.
197pub const Stat = extern struct {
198 dev: dev_t,
199 __pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
200 ino: ino_t,
201 mode: mode_t,
202 nlink: nlink_t,
203 uid: std.os.linux.uid_t,
204 gid: std.os.linux.gid_t,
205 rdev: dev_t,
206 __pad1: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
207 size: off_t,
208 atim: u32,
209 atim_nsec: u32,
210 mtim: u32,
211 mtim_nsec: u32,
212 ctim: u32,
213 ctim_nsec: u32,
214 blksize: blksize_t,
215 __pad3: u32,
216 blocks: blkcnt_t,
217
218 pub fn atime(self: @This()) std.os.linux.timespec {
219 return .{
220 .sec = self.atim,
221 .nsec = self.atim_nsec,
222 };
223 }
224
225 pub fn mtime(self: @This()) std.os.linux.timespec {
226 return .{
227 .sec = self.mtim,
228 .nsec = self.mtim_nsec,
229 };
230 }
231
232 pub fn ctime(self: @This()) std.os.linux.timespec {
233 return .{
234 .sec = self.ctim,
235 .nsec = self.ctim_nsec,
236 };
237 }
238};
lib/std/os/linux/or1k.zig-39
......@@ -131,43 +131,4 @@ pub fn clone() callconv(.naked) u32 {
131131
132132pub const VDSO = void;
133133
134pub const blksize_t = u32;
135pub const nlink_t = u32;
136134pub const time_t = i32;
137pub const mode_t = u32;
138pub const off_t = i64;
139pub const ino_t = u64;
140pub const dev_t = u64;
141pub const blkcnt_t = i64;
142
143// The `stat64` definition used by the Linux kernel.
144pub const Stat = extern struct {
145 dev: dev_t,
146 ino: ino_t,
147 mode: mode_t,
148 nlink: nlink_t,
149 uid: std.os.linux.uid_t,
150 gid: std.os.linux.gid_t,
151 rdev: dev_t,
152 _pad0: [2]u32,
153 size: off_t,
154 blksize: blksize_t,
155 _pad1: u32,
156 blocks: blkcnt_t,
157 atim: std.os.linux.timespec,
158 mtim: std.os.linux.timespec,
159 ctim: std.os.linux.timespec,
160 _pad2: [2]u32,
161
162 pub fn atime(self: @This()) std.os.linux.timespec {
163 return self.atim;
164 }
165
166 pub fn mtime(self: @This()) std.os.linux.timespec {
167 return self.mtim;
168 }
169
170 pub fn ctime(self: @This()) std.os.linux.timespec {
171 return self.ctim;
172 }
173};
lib/std/os/linux/powerpc.zig-38
......@@ -269,42 +269,4 @@ pub const VDSO = struct {
269269 pub const CGT_VER = "LINUX_2.6.15";
270270};
271271
272pub const blksize_t = i32;
273pub const nlink_t = u32;
274272pub const time_t = i32;
275pub const mode_t = u32;
276pub const off_t = i64;
277pub const ino_t = u64;
278pub const dev_t = u64;
279pub const blkcnt_t = i64;
280
281// The `stat` definition used by the Linux kernel.
282pub const Stat = extern struct {
283 dev: dev_t,
284 ino: ino_t,
285 mode: mode_t,
286 nlink: nlink_t,
287 uid: std.os.linux.uid_t,
288 gid: std.os.linux.gid_t,
289 rdev: dev_t,
290 __rdev_padding: i16,
291 size: off_t,
292 blksize: blksize_t,
293 blocks: blkcnt_t,
294 atim: std.os.linux.timespec,
295 mtim: std.os.linux.timespec,
296 ctim: std.os.linux.timespec,
297 __unused: [2]u32,
298
299 pub fn atime(self: @This()) std.os.linux.timespec {
300 return self.atim;
301 }
302
303 pub fn mtime(self: @This()) std.os.linux.timespec {
304 return self.mtim;
305 }
306
307 pub fn ctime(self: @This()) std.os.linux.timespec {
308 return self.ctim;
309 }
310};
lib/std/os/linux/powerpc64.zig-37
......@@ -254,41 +254,4 @@ pub const VDSO = struct {
254254 pub const CGT_VER = "LINUX_2.6.15";
255255};
256256
257pub const blksize_t = i64;
258pub const nlink_t = u64;
259257pub const time_t = i64;
260pub const mode_t = u32;
261pub const off_t = i64;
262pub const ino_t = u64;
263pub const dev_t = u64;
264pub const blkcnt_t = i64;
265
266// The `stat` definition used by the Linux kernel.
267pub const Stat = extern struct {
268 dev: dev_t,
269 ino: ino_t,
270 nlink: nlink_t,
271 mode: mode_t,
272 uid: std.os.linux.uid_t,
273 gid: std.os.linux.gid_t,
274 rdev: dev_t,
275 size: off_t,
276 blksize: blksize_t,
277 blocks: blkcnt_t,
278 atim: std.os.linux.timespec,
279 mtim: std.os.linux.timespec,
280 ctim: std.os.linux.timespec,
281 __unused: [3]u64,
282
283 pub fn atime(self: @This()) std.os.linux.timespec {
284 return self.atim;
285 }
286
287 pub fn mtime(self: @This()) std.os.linux.timespec {
288 return self.mtim;
289 }
290
291 pub fn ctime(self: @This()) std.os.linux.timespec {
292 return self.ctim;
293 }
294};
lib/std/os/linux/riscv32.zig-39
......@@ -124,46 +124,7 @@ pub fn clone() callconv(.naked) u32 {
124124 );
125125}
126126
127pub const blksize_t = i32;
128pub const nlink_t = u32;
129127pub const time_t = i64;
130pub const mode_t = u32;
131pub const off_t = i64;
132pub const ino_t = u64;
133pub const dev_t = u64;
134pub const blkcnt_t = i64;
135
136// The `stat` definition used by the Linux kernel.
137pub const Stat = extern struct {
138 dev: dev_t,
139 ino: ino_t,
140 mode: mode_t,
141 nlink: nlink_t,
142 uid: std.os.linux.uid_t,
143 gid: std.os.linux.gid_t,
144 rdev: dev_t,
145 __pad: u32,
146 size: off_t,
147 blksize: blksize_t,
148 __pad2: i32,
149 blocks: blkcnt_t,
150 atim: std.os.linux.timespec,
151 mtim: std.os.linux.timespec,
152 ctim: std.os.linux.timespec,
153 __unused: [2]u32,
154
155 pub fn atime(self: @This()) std.os.linux.timespec {
156 return self.atim;
157 }
158
159 pub fn mtime(self: @This()) std.os.linux.timespec {
160 return self.mtim;
161 }
162
163 pub fn ctime(self: @This()) std.os.linux.timespec {
164 return self.ctim;
165 }
166};
167128
168129pub const VDSO = struct {
169130 pub const CGT_SYM = "__vdso_clock_gettime";
lib/std/os/linux/riscv64.zig-39
......@@ -124,46 +124,7 @@ pub fn clone() callconv(.naked) u64 {
124124 );
125125}
126126
127pub const blksize_t = i32;
128pub const nlink_t = u32;
129127pub const time_t = i64;
130pub const mode_t = u32;
131pub const off_t = i64;
132pub const ino_t = u64;
133pub const dev_t = u64;
134pub const blkcnt_t = i64;
135
136// The `stat` definition used by the Linux kernel.
137pub const Stat = extern struct {
138 dev: dev_t,
139 ino: ino_t,
140 mode: mode_t,
141 nlink: nlink_t,
142 uid: std.os.linux.uid_t,
143 gid: std.os.linux.gid_t,
144 rdev: dev_t,
145 __pad: u64,
146 size: off_t,
147 blksize: blksize_t,
148 __pad2: i32,
149 blocks: blkcnt_t,
150 atim: std.os.linux.timespec,
151 mtim: std.os.linux.timespec,
152 ctim: std.os.linux.timespec,
153 __unused: [2]u32,
154
155 pub fn atime(self: @This()) std.os.linux.timespec {
156 return self.atim;
157 }
158
159 pub fn mtime(self: @This()) std.os.linux.timespec {
160 return self.mtim;
161 }
162
163 pub fn ctime(self: @This()) std.os.linux.timespec {
164 return self.ctim;
165 }
166};
167128
168129pub const VDSO = struct {
169130 pub const CGT_SYM = "__vdso_clock_gettime";
lib/std/os/linux/s390x.zig-37
......@@ -152,44 +152,7 @@ pub fn restore_rt() callconv(.naked) noreturn {
152152 );
153153}
154154
155pub const blksize_t = i64;
156pub const nlink_t = u64;
157155pub const time_t = i64;
158pub const mode_t = u32;
159pub const off_t = i64;
160pub const ino_t = u64;
161pub const dev_t = u64;
162pub const blkcnt_t = i64;
163
164// The `stat` definition used by the Linux kernel.
165pub const Stat = extern struct {
166 dev: dev_t,
167 ino: ino_t,
168 nlink: nlink_t,
169 mode: mode_t,
170 uid: std.os.linux.uid_t,
171 gid: std.os.linux.gid_t,
172 rdev: dev_t,
173 size: off_t,
174 atim: std.os.linux.timespec,
175 mtim: std.os.linux.timespec,
176 ctim: std.os.linux.timespec,
177 blksize: blksize_t,
178 blocks: blkcnt_t,
179 __unused: [3]c_ulong,
180
181 pub fn atime(self: @This()) std.os.linux.timespec {
182 return self.atim;
183 }
184
185 pub fn mtime(self: @This()) std.os.linux.timespec {
186 return self.mtim;
187 }
188
189 pub fn ctime(self: @This()) std.os.linux.timespec {
190 return self.ctim;
191 }
192};
193156
194157pub const VDSO = struct {
195158 pub const CGT_SYM = "__kernel_clock_gettime";
lib/std/os/linux/sparc64.zig-42
......@@ -228,46 +228,4 @@ pub const VDSO = struct {
228228 pub const CGT_VER = "LINUX_2.6";
229229};
230230
231pub const off_t = i64;
232pub const ino_t = u64;
233231pub const time_t = i64;
234pub const mode_t = u32;
235pub const dev_t = u64;
236pub const nlink_t = u32;
237pub const blksize_t = i64;
238pub const blkcnt_t = i64;
239
240// The `stat64` definition used by the kernel.
241pub const Stat = extern struct {
242 dev: dev_t,
243 ino: ino_t,
244 nlink: nlink_t,
245 _pad: i32,
246
247 mode: mode_t,
248 uid: std.os.linux.uid_t,
249 gid: std.os.linux.gid_t,
250 __pad0: u32,
251
252 rdev: dev_t,
253 size: i64,
254 blksize: blksize_t,
255 blocks: blkcnt_t,
256
257 atim: std.os.linux.timespec,
258 mtim: std.os.linux.timespec,
259 ctim: std.os.linux.timespec,
260 __unused: [3]u64,
261
262 pub fn atime(self: @This()) std.os.linux.timespec {
263 return self.atim;
264 }
265
266 pub fn mtime(self: @This()) std.os.linux.timespec {
267 return self.mtim;
268 }
269
270 pub fn ctime(self: @This()) std.os.linux.timespec {
271 return self.ctim;
272 }
273};
lib/std/os/linux/test.zig+12-18
......@@ -10,8 +10,6 @@ const expectEqual = std.testing.expectEqual;
1010const fs = std.fs;
1111
1212test "fallocate" {
13 if (builtin.cpu.arch.isMIPS64() and (builtin.abi == .gnuabin32 or builtin.abi == .muslabin32)) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23809
14
1513 var tmp = std.testing.tmpDir(.{});
1614 defer tmp.cleanup();
1715
......@@ -84,26 +82,22 @@ test "statx" {
8482 var file = try tmp.dir.createFile(tmp_file_name, .{});
8583 defer file.close();
8684
87 var statx_buf: linux.Statx = undefined;
88 switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
89 .SUCCESS => {},
90 else => unreachable,
91 }
92
93 if (builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; // No fstatat, so the rest of the test is meaningless.
94
95 var stat_buf: linux.Stat = undefined;
96 switch (linux.errno(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) {
85 var buf: linux.Statx = undefined;
86 switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, .BASIC_STATS, &buf))) {
9787 .SUCCESS => {},
9888 else => unreachable,
9989 }
10090
101 try expect(stat_buf.mode == statx_buf.mode);
102 try expect(@as(u32, @bitCast(stat_buf.uid)) == statx_buf.uid);
103 try expect(@as(u32, @bitCast(stat_buf.gid)) == statx_buf.gid);
104 try expect(@as(u64, @bitCast(@as(i64, stat_buf.size))) == statx_buf.size);
105 try expect(@as(u64, @bitCast(@as(i64, stat_buf.blksize))) == statx_buf.blksize);
106 try expect(@as(u64, @bitCast(@as(i64, stat_buf.blocks))) == statx_buf.blocks);
91 const uid = linux.getuid();
92 const gid = linux.getgid();
93 if (buf.mask.MODE)
94 try expectEqual(@as(linux.mode_t, linux.S.IFREG), buf.mode & linux.S.IFMT);
95 if (buf.mask.UID)
96 try expectEqual(uid, buf.uid);
97 if (buf.mask.GID)
98 try expectEqual(gid, buf.gid);
99 if (buf.mask.SIZE)
100 try expectEqual(@as(u64, 0), buf.size);
107101}
108102
109103test "user and group ids" {
lib/std/os/linux/x32.zig-40
......@@ -132,14 +132,7 @@ pub fn restore_rt() callconv(.naked) noreturn {
132132 }
133133}
134134
135pub const mode_t = u32;
136135pub const time_t = i32;
137pub const nlink_t = u32;
138pub const blksize_t = i32;
139pub const blkcnt_t = i32;
140pub const off_t = i64;
141pub const ino_t = u64;
142pub const dev_t = u64;
143136
144137pub const VDSO = struct {
145138 pub const CGT_SYM = "__vdso_clock_gettime";
......@@ -155,36 +148,3 @@ pub const ARCH = struct {
155148 pub const GET_FS = 0x1003;
156149 pub const GET_GS = 0x1004;
157150};
158
159// The `stat` definition used by the Linux kernel.
160pub const Stat = extern struct {
161 dev: dev_t,
162 ino: ino_t,
163 nlink: nlink_t,
164
165 mode: mode_t,
166 uid: std.os.linux.uid_t,
167 gid: std.os.linux.gid_t,
168 __pad0: u32,
169 rdev: dev_t,
170 size: off_t,
171 blksize: blksize_t,
172 blocks: i64,
173
174 atim: std.os.linux.timespec,
175 mtim: std.os.linux.timespec,
176 ctim: std.os.linux.timespec,
177 __unused: [3]i32,
178
179 pub fn atime(self: @This()) std.os.linux.timespec {
180 return self.atim;
181 }
182
183 pub fn mtime(self: @This()) std.os.linux.timespec {
184 return self.mtim;
185 }
186
187 pub fn ctime(self: @This()) std.os.linux.timespec {
188 return self.ctim;
189 }
190};
lib/std/os/linux/x86.zig-39
......@@ -195,46 +195,7 @@ pub const VDSO = struct {
195195 pub const CGT_VER = "LINUX_2.6";
196196};
197197
198pub const blksize_t = i32;
199pub const nlink_t = u32;
200198pub const time_t = i32;
201pub const mode_t = u32;
202pub const off_t = i64;
203pub const ino_t = u64;
204pub const dev_t = u64;
205pub const blkcnt_t = i64;
206
207// The `stat` definition used by the Linux kernel.
208pub const Stat = extern struct {
209 dev: dev_t,
210 __dev_padding: u32,
211 __ino_truncated: u32,
212 mode: mode_t,
213 nlink: nlink_t,
214 uid: std.os.linux.uid_t,
215 gid: std.os.linux.gid_t,
216 rdev: dev_t,
217 __rdev_padding: u32,
218 size: off_t,
219 blksize: blksize_t,
220 blocks: blkcnt_t,
221 atim: std.os.linux.timespec,
222 mtim: std.os.linux.timespec,
223 ctim: std.os.linux.timespec,
224 ino: ino_t,
225
226 pub fn atime(self: @This()) std.os.linux.timespec {
227 return self.atim;
228 }
229
230 pub fn mtime(self: @This()) std.os.linux.timespec {
231 return self.mtim;
232 }
233
234 pub fn ctime(self: @This()) std.os.linux.timespec {
235 return self.ctim;
236 }
237};
238199
239200pub const user_desc = extern struct {
240201 entry_number: u32,
lib/std/os/linux/x86_64.zig-40
......@@ -132,14 +132,7 @@ pub fn restore_rt() callconv(.naked) noreturn {
132132 }
133133}
134134
135pub const mode_t = u64;
136135pub const time_t = i64;
137pub const nlink_t = u64;
138pub const blksize_t = i64;
139pub const blkcnt_t = i64;
140pub const off_t = i64;
141pub const ino_t = u64;
142pub const dev_t = u64;
143136
144137pub const VDSO = struct {
145138 pub const CGT_SYM = "__vdso_clock_gettime";
......@@ -155,36 +148,3 @@ pub const ARCH = struct {
155148 pub const GET_FS = 0x1003;
156149 pub const GET_GS = 0x1004;
157150};
158
159// The `stat` definition used by the Linux kernel.
160pub const Stat = extern struct {
161 dev: dev_t,
162 ino: ino_t,
163 nlink: u64,
164
165 mode: u32,
166 uid: std.os.linux.uid_t,
167 gid: std.os.linux.gid_t,
168 __pad0: u32,
169 rdev: dev_t,
170 size: off_t,
171 blksize: i64,
172 blocks: i64,
173
174 atim: std.os.linux.timespec,
175 mtim: std.os.linux.timespec,
176 ctim: std.os.linux.timespec,
177 __unused: [3]i64,
178
179 pub fn atime(self: @This()) std.os.linux.timespec {
180 return self.atim;
181 }
182
183 pub fn mtime(self: @This()) std.os.linux.timespec {
184 return self.mtim;
185 }
186
187 pub fn ctime(self: @This()) std.os.linux.timespec {
188 return self.ctim;
189 }
190};
lib/std/posix.zig+25-13
......@@ -119,7 +119,18 @@ pub const STDIN_FILENO = system.STDIN_FILENO;
119119pub const STDOUT_FILENO = system.STDOUT_FILENO;
120120pub const SYS = system.SYS;
121121pub const Sigaction = system.Sigaction;
122pub const Stat = system.Stat;
122pub const Stat = switch (native_os) {
123 // Has no concept of `stat`.
124 .windows => void,
125 // The `stat` bits/wrappers are removed due to having to maintain the
126 // different varying `struct stat`s per target and libc, leading to runtime
127 // errors.
128 //
129 // Users targeting linux should add a comptime check and use `statx`,
130 // similar to how `std.fs.File.stat` does.
131 .linux => void,
132 else => system.Stat,
133};
123134pub const T = system.T;
124135pub const TCP = system.TCP;
125136pub const VDSO = system.VDSO;
......@@ -480,15 +491,21 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr
480491 }
481492 defer close(pathfd);
482493
483 const stat = fstatatZ(pathfd, "", AT.EMPTY_PATH) catch |err| switch (err) {
494 const path_mode = if (linux.wrapped.statx(
495 pathfd,
496 "",
497 AT.EMPTY_PATH,
498 .{ .TYPE = true },
499 )) |stx| blk: {
500 assert(stx.mask.TYPE);
501 break :blk stx.mode;
502 } else |err| switch (err) {
484503 error.NameTooLong => unreachable,
485504 error.FileNotFound => unreachable,
486 error.Streaming => unreachable,
487 error.BadPathName => return error.Unexpected,
488 error.Canceled => return error.Canceled,
489505 else => |e| return e,
490506 };
491 if ((stat.mode & S.IFMT) == S.IFLNK)
507 // Even though we only wanted TYPE, the kernel can still fill in the additional bits.
508 if ((path_mode & S.IFMT) == S.IFLNK)
492509 return error.OperationNotSupported;
493510
494511 var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;
......@@ -3843,13 +3860,9 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
38433860 if (native_os == .wasi and !builtin.link_libc) {
38443861 return Stat.fromFilestat(try std.os.fstat_wasi(fd));
38453862 }
3846 if (native_os == .windows) {
3847 @compileError("fstat is not yet implemented on Windows");
3848 }
38493863
3850 const fstat_sym = if (lfs64_abi) system.fstat64 else system.fstat;
38513864 var stat = mem.zeroes(Stat);
3852 switch (errno(fstat_sym(fd, &stat))) {
3865 switch (errno(system.fstat(fd, &stat))) {
38533866 .SUCCESS => return stat,
38543867 .INVAL => unreachable,
38553868 .BADF => unreachable, // Always a race condition.
......@@ -3889,9 +3902,8 @@ pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!S
38893902 @compileError("use std.Io instead");
38903903 }
38913904
3892 const fstatat_sym = if (lfs64_abi) system.fstatat64 else system.fstatat;
38933905 var stat = mem.zeroes(Stat);
3894 switch (errno(fstatat_sym(dirfd, pathname, &stat, flags))) {
3906 switch (errno(system.fstatat(dirfd, pathname, &stat, flags))) {
38953907 .SUCCESS => return stat,
38963908 .INVAL => unreachable,
38973909 .BADF => unreachable, // Always a race condition.
lib/std/posix/test.zig+78-21
......@@ -16,6 +16,7 @@ const AtomicRmwOp = std.builtin.AtomicRmwOp;
1616const AtomicOrder = std.builtin.AtomicOrder;
1717const native_os = builtin.target.os.tag;
1818const tmpDir = std.testing.tmpDir;
19const AT = posix.AT;
1920
2021// NOTE: several additional tests are in test/standalone/posix/. Any tests that mutate
2122// process-wide POSIX state (cwd, signals, etc) cannot be Zig unit tests and should be over there.
......@@ -123,10 +124,24 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
123124 try expect(mem.eql(u8, target_path, given));
124125}
125126
126test "linkat with different directories" {
127 if ((builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) and builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // No `fstatat()`.
128 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; // `nstat.nlink` assertion is failing with LLVM 20+ for unclear reasons.
127fn getLinkInfo(fd: posix.fd_t) !struct { posix.ino_t, posix.nlink_t } {
128 if (native_os == .linux) {
129 const stx = try linux.wrapped.statx(
130 fd,
131 "",
132 posix.AT.EMPTY_PATH,
133 .{ .INO = true, .NLINK = true },
134 );
135 std.debug.assert(stx.mask.INO);
136 std.debug.assert(stx.mask.NLINK);
137 return .{ stx.ino, stx.nlink };
138 }
129139
140 const st = try posix.fstat(fd);
141 return .{ st.ino, st.nlink };
142}
143
144test "linkat with different directories" {
130145 switch (native_os) {
131146 .wasi, .linux, .illumos => {},
132147 else => return error.SkipZigTest,
......@@ -153,19 +168,49 @@ test "linkat with different directories" {
153168 defer nfd.close();
154169
155170 {
156 const estat = try posix.fstat(efd.handle);
157 const nstat = try posix.fstat(nfd.handle);
158 try testing.expectEqual(estat.ino, nstat.ino);
159 try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
171 const eino, _ = try getLinkInfo(efd.handle);
172 const nino, const nlink = try getLinkInfo(nfd.handle);
173 try testing.expectEqual(eino, nino);
174 try testing.expectEqual(@as(posix.nlink_t, 2), nlink);
160175 }
161176
162177 // Test 2: remove link
163178 try posix.unlinkat(subdir.fd, link_name, 0);
179 _, const elink = try getLinkInfo(efd.handle);
180 try testing.expectEqual(@as(posix.nlink_t, 1), elink);
181}
164182
165 {
166 const estat = try posix.fstat(efd.handle);
167 try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
168 }
183test "fstatat" {
184 if (posix.Stat == void) return error.SkipZigTest;
185 if (native_os == .wasi and !builtin.link_libc) return error.SkipZigTest;
186
187 var tmp = tmpDir(.{});
188 defer tmp.cleanup();
189
190 // create dummy file
191 const contents = "nonsense";
192 try tmp.dir.writeFile(.{ .sub_path = "file.txt", .data = contents });
193
194 // fetch file's info on the opened fd directly
195 const file = try tmp.dir.openFile("file.txt", .{});
196 const stat = try posix.fstat(file.handle);
197 defer file.close();
198
199 // now repeat but using `fstatat` instead
200 const statat = try posix.fstatat(tmp.dir.fd, "file.txt", posix.AT.SYMLINK_NOFOLLOW);
201
202 try expectEqual(stat.dev, statat.dev);
203 try expectEqual(stat.ino, statat.ino);
204 try expectEqual(stat.nlink, statat.nlink);
205 try expectEqual(stat.mode, statat.mode);
206 try expectEqual(stat.uid, statat.uid);
207 try expectEqual(stat.gid, statat.gid);
208 try expectEqual(stat.rdev, statat.rdev);
209 try expectEqual(stat.size, statat.size);
210 try expectEqual(stat.blksize, statat.blksize);
211 // The stat.blocks/statat.blocks count is managed by the filesystem and may
212 // change if the file is stored in a journal or "inline".
213 // try expectEqual(stat.blocks, statat.blocks);
169214}
170215
171216test "readlinkat" {
......@@ -906,14 +951,31 @@ test "pwrite with empty buffer" {
906951 try expectEqual(rc, 0);
907952}
908953
954fn getFileMode(dir: posix.fd_t, path: []const u8) !posix.mode_t {
955 const path_z = try posix.toPosixPath(path);
956 const mode: posix.mode_t = if (native_os == .linux) blk: {
957 const stx = try linux.wrapped.statx(
958 dir,
959 &path_z,
960 posix.AT.SYMLINK_NOFOLLOW,
961 .{ .MODE = true },
962 );
963 std.debug.assert(stx.mask.MODE);
964 break :blk stx.mode;
965 } else blk: {
966 const st = try posix.fstatatZ(dir, &path_z, posix.AT.SYMLINK_NOFOLLOW);
967 break :blk st.mode;
968 };
969
970 return mode & 0b111_111_111;
971}
972
909973fn expectMode(dir: posix.fd_t, file: []const u8, mode: posix.mode_t) !void {
910 const st = try posix.fstatat(dir, file, posix.AT.SYMLINK_NOFOLLOW);
911 try expectEqual(mode, st.mode & 0b111_111_111);
974 const actual = try getFileMode(dir, file);
975 try expectEqual(mode, actual & 0b111_111_111);
912976}
913977
914978test "fchmodat smoke test" {
915 if (builtin.cpu.arch.isMIPS64() and (builtin.abi == .gnuabin32 or builtin.abi == .muslabin32)) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23808
916
917979 if (!std.fs.has_executable_bit) return error.SkipZigTest;
918980
919981 var tmp = tmpDir(.{});
......@@ -928,13 +990,8 @@ test "fchmodat smoke test" {
928990 );
929991 posix.close(fd);
930992
931 if ((builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) and builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // No `fstatat()`.
932
933993 try posix.symlinkat("regfile", tmp.dir.fd, "symlink");
934 const sym_mode = blk: {
935 const st = try posix.fstatat(tmp.dir.fd, "symlink", posix.AT.SYMLINK_NOFOLLOW);
936 break :blk st.mode & 0b111_111_111;
937 };
994 const sym_mode = try getFileMode(tmp.dir.fd, "symlink");
938995
939996 try posix.fchmodat(tmp.dir.fd, "regfile", 0o640, 0);
940997 try expectMode(tmp.dir.fd, "regfile", 0o640);
src/link/MappedFile.zig+14
......@@ -54,6 +54,20 @@ pub fn init(file: std.Io.File, gpa: std.mem.Allocator) !MappedFile {
5454 },
5555 };
5656 }
57 if (is_linux) {
58 const statx = try linux.wrapped.statx(
59 mf.file.handle,
60 "",
61 std.posix.AT.EMPTY_PATH,
62 .{ .TYPE = true, .SIZE = true, .BLOCKS = true },
63 );
64 assert(statx.mask.TYPE);
65 assert(statx.mask.SIZE);
66 assert(statx.mask.BLOCKS);
67
68 if (!std.posix.S.ISREG(statx.mode)) return error.PathAlreadyExists;
69 break :stat .{ statx.size, @max(std.heap.pageSize(), statx.blksize) };
70 }
5771 const stat = try std.posix.fstat(mf.file.handle);
5872 if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists;
5973 break :stat .{ @bitCast(stat.size), @max(std.heap.pageSize(), stat.blksize) };
test/standalone/glibc_compat/glibc_runtime_check.zig+6-3
......@@ -23,16 +23,19 @@ const c_string = @cImport(
2323// Version of glibc this test is being built to run against
2424const glibc_ver = builtin.os.versionRange().gnuLibCVersion().?;
2525
26extern "c" fn fstatat(dirfd: i32, path: [*:0]const u8, buf: [*]const u8, flag: u32) c_int;
27extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: [*]const u8) c_int;
28
2629// PR #17034 - fstat moved between libc_nonshared and libc
2730fn checkStat() !void {
2831 const cwdFd = std.fs.cwd().fd;
2932
30 var stat = std.mem.zeroes(std.c.Stat);
31 var result = std.c.fstatat(cwdFd, "a_file_that_definitely_does_not_exist", &stat, 0);
33 var buf: [256]u8 = @splat(0);
34 var result = fstatat(cwdFd, "a_file_that_definitely_does_not_exist", &buf, 0);
3235 assert(result == -1);
3336 assert(std.posix.errno(result) == .NOENT);
3437
35 result = std.c.stat("a_file_that_definitely_does_not_exist", &stat);
38 result = stat("a_file_that_definitely_does_not_exist", &buf);
3639 assert(result == -1);
3740 assert(std.posix.errno(result) == .NOENT);
3841}
test/standalone/posix/relpaths.zig+23-15
......@@ -48,20 +48,29 @@ fn test_symlink(a: std.mem.Allocator, tmp: std.testing.TmpDir) !void {
4848 try std.testing.expectEqualStrings(target_name, given);
4949}
5050
51fn getLinkInfo(fd: std.posix.fd_t) !struct { std.posix.ino_t, std.posix.nlink_t } {
52 if (builtin.target.os.tag == .linux) {
53 const stx = try std.os.linux.wrapped.statx(
54 fd,
55 "",
56 std.posix.AT.EMPTY_PATH,
57 .{ .INO = true, .NLINK = true },
58 );
59 std.debug.assert(stx.mask.INO);
60 std.debug.assert(stx.mask.NLINK);
61 return .{ stx.ino, stx.nlink };
62 }
63
64 const st = try std.posix.fstat(fd);
65 return .{ st.ino, st.nlink };
66}
67
5168fn test_link(tmp: std.testing.TmpDir) !void {
5269 switch (builtin.target.os.tag) {
5370 .linux, .illumos => {},
5471 else => return,
5572 }
5673
57 if ((builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) and builtin.target.os.tag == .linux and !builtin.link_libc) {
58 return; // No `fstat()`.
59 }
60
61 if (builtin.cpu.arch.isMIPS64()) {
62 return; // `nstat.nlink` assertion is failing with LLVM 20+ for unclear reasons.
63 }
64
6574 const target_name = "link-target";
6675 const link_name = "newlink";
6776
......@@ -78,17 +87,16 @@ fn test_link(tmp: std.testing.TmpDir) !void {
7887 defer nfd.close();
7988
8089 {
81 const estat = try std.posix.fstat(efd.handle);
82 const nstat = try std.posix.fstat(nfd.handle);
83 try std.testing.expectEqual(estat.ino, nstat.ino);
84 try std.testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
90 const eino, _ = try getLinkInfo(efd.handle);
91 const nino, const nlink = try getLinkInfo(nfd.handle);
92 try std.testing.expectEqual(eino, nino);
93 try std.testing.expectEqual(@as(std.posix.nlink_t, 2), nlink);
8594 }
8695
8796 // Test 2: Remove the link and see the stats update
8897 try std.posix.unlink(link_name);
89
9098 {
91 const estat = try std.posix.fstat(efd.handle);
92 try std.testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
99 _, const elink = try getLinkInfo(efd.handle);
100 try std.testing.expectEqual(@as(std.posix.nlink_t, 1), elink);
93101 }
94102}