mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 02:44:43 +01:00
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>
This commit is contained in:
commit
2f2b097576
29 changed files with 355 additions and 1080 deletions
|
|
@ -1533,12 +1533,19 @@ fn dirStatPathLinux(
|
|||
dir.handle,
|
||||
sub_path_posix,
|
||||
flags,
|
||||
linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
|
||||
.{ .TYPE = true, .MODE = true, .ATIME = true, .MTIME = true, .CTIME = true, .INO = true, .SIZE = true },
|
||||
&statx,
|
||||
);
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => {
|
||||
current_thread.endSyscall();
|
||||
assert(statx.mask.TYPE);
|
||||
assert(statx.mask.MODE);
|
||||
assert(statx.mask.ATIME);
|
||||
assert(statx.mask.MTIME);
|
||||
assert(statx.mask.CTIME);
|
||||
assert(statx.mask.INO);
|
||||
assert(statx.mask.SIZE);
|
||||
return statFromLinux(&statx);
|
||||
},
|
||||
.INTR => {
|
||||
|
|
@ -1725,12 +1732,19 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
|
|||
file.handle,
|
||||
"",
|
||||
linux.AT.EMPTY_PATH,
|
||||
linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
|
||||
.{ .TYPE = true, .MODE = true, .ATIME = true, .MTIME = true, .CTIME = true, .INO = true, .SIZE = true },
|
||||
&statx,
|
||||
);
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => {
|
||||
current_thread.endSyscall();
|
||||
assert(statx.mask.TYPE);
|
||||
assert(statx.mask.MODE);
|
||||
assert(statx.mask.ATIME);
|
||||
assert(statx.mask.MTIME);
|
||||
assert(statx.mask.CTIME);
|
||||
assert(statx.mask.INO);
|
||||
assert(statx.mask.SIZE);
|
||||
return statFromLinux(&statx);
|
||||
},
|
||||
.INTR => {
|
||||
|
|
|
|||
168
lib/std/c.zig
168
lib/std/c.zig
|
|
@ -7586,166 +7586,6 @@ pub const EAI = if (builtin.abi.isAndroid()) enum(c_int) {
|
|||
pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.c) c_int;
|
||||
|
||||
pub const Stat = switch (native_os) {
|
||||
.linux => switch (native_arch) {
|
||||
.sparc64 => extern struct {
|
||||
dev: u64,
|
||||
__pad1: u16,
|
||||
ino: ino_t,
|
||||
mode: u32,
|
||||
nlink: u32,
|
||||
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
rdev: u64,
|
||||
__pad2: u16,
|
||||
|
||||
size: off_t,
|
||||
blksize: isize,
|
||||
blocks: i64,
|
||||
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
__reserved: [2]usize,
|
||||
|
||||
pub fn atime(self: @This()) timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
},
|
||||
.mips, .mipsel => if (builtin.target.abi.isMusl()) extern struct {
|
||||
dev: dev_t,
|
||||
__pad0: [2]i32,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: uid_t,
|
||||
gid: gid_t,
|
||||
rdev: dev_t,
|
||||
__pad1: [2]i32,
|
||||
size: off_t,
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
blksize: blksize_t,
|
||||
__pad3: i32,
|
||||
blocks: blkcnt_t,
|
||||
__pad4: [14]i32,
|
||||
|
||||
pub fn atime(self: @This()) timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
} else extern struct {
|
||||
dev: u32,
|
||||
__pad0: [3]u32,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: uid_t,
|
||||
gid: gid_t,
|
||||
rdev: u32,
|
||||
__pad1: [3]u32,
|
||||
size: off_t,
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
blksize: blksize_t,
|
||||
__pad3: u32,
|
||||
blocks: blkcnt_t,
|
||||
__pad4: [14]u32,
|
||||
|
||||
pub fn atime(self: @This()) timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
},
|
||||
.mips64, .mips64el => if (builtin.target.abi.isMusl()) extern struct {
|
||||
dev: dev_t,
|
||||
__pad0: [3]i32,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: uid_t,
|
||||
gid: gid_t,
|
||||
rdev: dev_t,
|
||||
__pad1: [2]u32,
|
||||
size: off_t,
|
||||
__pad2: i32,
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
blksize: blksize_t,
|
||||
__pad3: u32,
|
||||
blocks: blkcnt_t,
|
||||
__pad4: [14]i32,
|
||||
|
||||
pub fn atime(self: @This()) timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
} else extern struct {
|
||||
dev: dev_t,
|
||||
__pad0: [3]u32,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: uid_t,
|
||||
gid: gid_t,
|
||||
rdev: dev_t,
|
||||
__pad1: [3]u32,
|
||||
size: off_t,
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
blksize: blksize_t,
|
||||
__pad3: u32,
|
||||
blocks: blkcnt_t,
|
||||
__pad4: [14]i32,
|
||||
|
||||
pub fn atime(self: @This()) timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
},
|
||||
|
||||
else => std.os.linux.Stat, // libc stat is the same as kernel stat.
|
||||
},
|
||||
.emscripten => emscripten.Stat,
|
||||
.wasi => extern struct {
|
||||
// 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) {
|
|||
else => private.fstat,
|
||||
},
|
||||
.netbsd => private.__fstat50,
|
||||
.linux => {},
|
||||
else => private.fstat,
|
||||
};
|
||||
|
||||
|
|
@ -10430,8 +10271,12 @@ pub const fstatat = switch (native_os) {
|
|||
.x86_64 => private.@"fstatat$INODE64",
|
||||
else => private.fstatat,
|
||||
},
|
||||
.linux => {},
|
||||
else => private.fstatat,
|
||||
};
|
||||
|
||||
pub extern "c" fn statx(dirfd: fd_t, path: [*:0]const u8, flags: u32, mask: linux.STATX, buf: *linux.Statx) c_int;
|
||||
|
||||
pub extern "c" fn getpwent() ?*passwd;
|
||||
pub extern "c" fn endpwent() void;
|
||||
pub extern "c" fn setpwent() void;
|
||||
|
|
@ -10505,8 +10350,6 @@ pub extern "c" fn inotify_init1(flags: c_uint) c_int;
|
|||
pub extern "c" fn inotify_add_watch(fd: fd_t, pathname: [*:0]const u8, mask: u32) c_int;
|
||||
pub extern "c" fn inotify_rm_watch(fd: fd_t, wd: c_int) c_int;
|
||||
|
||||
pub extern "c" fn fstat64(fd: fd_t, buf: *Stat) c_int;
|
||||
pub extern "c" fn fstatat64(dirfd: fd_t, noalias path: [*:0]const u8, noalias stat_buf: *Stat, flags: u32) c_int;
|
||||
pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
|
||||
pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE;
|
||||
pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
|
||||
|
|
@ -11552,7 +11395,6 @@ const private = struct {
|
|||
extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
|
||||
extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
|
||||
extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int;
|
||||
extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
|
||||
extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
|
||||
extern "c" fn sysconf(sc: c_int) c_long;
|
||||
extern "c" fn shm_open(name: [*:0]const u8, flag: c_int, mode: mode_t) c_int;
|
||||
|
|
|
|||
|
|
@ -95,15 +95,14 @@ pub fn clone(
|
|||
pub const ARCH = arch_bits.ARCH;
|
||||
pub const HWCAP = arch_bits.HWCAP;
|
||||
pub const SC = arch_bits.SC;
|
||||
pub const Stat = arch_bits.Stat;
|
||||
pub const VDSO = arch_bits.VDSO;
|
||||
pub const blkcnt_t = arch_bits.blkcnt_t;
|
||||
pub const blksize_t = arch_bits.blksize_t;
|
||||
pub const dev_t = arch_bits.dev_t;
|
||||
pub const ino_t = arch_bits.ino_t;
|
||||
pub const mode_t = arch_bits.mode_t;
|
||||
pub const nlink_t = arch_bits.nlink_t;
|
||||
pub const off_t = arch_bits.off_t;
|
||||
pub const blkcnt_t = u64;
|
||||
pub const blksize_t = u32;
|
||||
pub const dev_t = u64;
|
||||
pub const ino_t = u64;
|
||||
pub const mode_t = u32;
|
||||
pub const nlink_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const time_t = arch_bits.time_t;
|
||||
pub const user_desc = arch_bits.user_desc;
|
||||
|
||||
|
|
@ -2199,61 +2198,13 @@ pub fn accept4(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t, flag
|
|||
return syscall4(.accept4, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(addr), @intFromPtr(len), flags);
|
||||
}
|
||||
|
||||
pub fn fstat(fd: i32, stat_buf: *Stat) usize {
|
||||
if (native_arch == .riscv32 or native_arch.isLoongArch()) {
|
||||
// riscv32 and loongarch have made the interesting decision to not implement some of
|
||||
// the older stat syscalls, including this one.
|
||||
@compileError("No fstat syscall on this architecture.");
|
||||
} else if (@hasField(SYS, "fstat64")) {
|
||||
return syscall2(.fstat64, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(stat_buf));
|
||||
} else {
|
||||
return syscall2(.fstat, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(stat_buf));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stat(pathname: [*:0]const u8, statbuf: *Stat) usize {
|
||||
if (native_arch == .riscv32 or native_arch.isLoongArch()) {
|
||||
// riscv32 and loongarch have made the interesting decision to not implement some of
|
||||
// the older stat syscalls, including this one.
|
||||
@compileError("No stat syscall on this architecture.");
|
||||
} else if (@hasField(SYS, "stat64")) {
|
||||
return syscall2(.stat64, @intFromPtr(pathname), @intFromPtr(statbuf));
|
||||
} else {
|
||||
return syscall2(.stat, @intFromPtr(pathname), @intFromPtr(statbuf));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lstat(pathname: [*:0]const u8, statbuf: *Stat) usize {
|
||||
if (native_arch == .riscv32 or native_arch.isLoongArch()) {
|
||||
// riscv32 and loongarch have made the interesting decision to not implement some of
|
||||
// the older stat syscalls, including this one.
|
||||
@compileError("No lstat syscall on this architecture.");
|
||||
} else if (@hasField(SYS, "lstat64")) {
|
||||
return syscall2(.lstat64, @intFromPtr(pathname), @intFromPtr(statbuf));
|
||||
} else {
|
||||
return syscall2(.lstat, @intFromPtr(pathname), @intFromPtr(statbuf));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fstatat(dirfd: i32, path: [*:0]const u8, stat_buf: *Stat, flags: u32) usize {
|
||||
if (native_arch == .riscv32 or native_arch.isLoongArch()) {
|
||||
// riscv32 and loongarch have made the interesting decision to not implement some of
|
||||
// the older stat syscalls, including this one.
|
||||
@compileError("No fstatat syscall on this architecture.");
|
||||
} else if (@hasField(SYS, "fstatat64")) {
|
||||
return syscall4(.fstatat64, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), @intFromPtr(stat_buf), flags);
|
||||
} else {
|
||||
return syscall4(.fstatat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), @intFromPtr(stat_buf), flags);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn statx(dirfd: i32, path: [*:0]const u8, flags: u32, mask: u32, statx_buf: *Statx) usize {
|
||||
pub fn statx(dirfd: i32, path: [*:0]const u8, flags: u32, mask: STATX, statx_buf: *Statx) usize {
|
||||
return syscall5(
|
||||
.statx,
|
||||
@as(usize, @bitCast(@as(isize, dirfd))),
|
||||
@intFromPtr(path),
|
||||
flags,
|
||||
mask,
|
||||
@as(u32, @bitCast(mask)),
|
||||
@intFromPtr(statx_buf),
|
||||
);
|
||||
}
|
||||
|
|
@ -6940,97 +6891,162 @@ pub const utsname = extern struct {
|
|||
};
|
||||
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;
|
||||
/// Flags used to request specific members in `Statx` be filled out.
|
||||
/// The `Statx.mask` member will be updated with what information the kernel
|
||||
/// returned. Callers must check this field since support varies by kernel
|
||||
/// version and filesystem.
|
||||
pub const STATX = packed struct(u32) {
|
||||
/// Want `mode & S.IFMT`.
|
||||
TYPE: bool = false,
|
||||
/// Want `mode & ~S.IFMT`.
|
||||
MODE: bool = false,
|
||||
/// Want the `nlink` member.
|
||||
NLINK: bool = false,
|
||||
/// Want the `uid` member.
|
||||
UID: bool = false,
|
||||
/// Want the `gid` member.
|
||||
GID: bool = false,
|
||||
/// Want the `atime` member.
|
||||
ATIME: bool = false,
|
||||
/// Want the `mtime` member.
|
||||
MTIME: bool = false,
|
||||
/// Want the `ctime` member.
|
||||
CTIME: bool = false,
|
||||
/// Want the `ino` member.
|
||||
INO: bool = false,
|
||||
/// Want the `size` member.
|
||||
SIZE: bool = false,
|
||||
/// Want the `blocks` member.
|
||||
BLOCKS: bool = false,
|
||||
/// Want the `btime` member.
|
||||
BTIME: bool = false,
|
||||
/// Want the `mnt_id` member.
|
||||
MNT_ID: bool = false,
|
||||
/// Want the `dio_mem_align` and `dio_offset_align` members.
|
||||
DIOALIGN: bool = false,
|
||||
/// Want the `stx_mnt_id` member.
|
||||
MNT_ID_UNIQUE: bool = false,
|
||||
/// Want the `sub` member.
|
||||
SUBVOL: bool = false,
|
||||
/// Want the `atomic_write_unit_min`, `atomic_write_unit_max` and
|
||||
/// `atomic_write_segments_max` members.
|
||||
WRITE_ATOMIC: bool = false,
|
||||
/// Want the `dio_read_offset_align` member.
|
||||
DIO_READ_ALIGN: bool = false,
|
||||
__pad: u13 = 0,
|
||||
/// Reserved for future expansion; must not be set.
|
||||
__RESERVED: bool = false,
|
||||
|
||||
pub const STATX_BTIME = 0x0800;
|
||||
pub const BASIC_STATS: STATX = @bitCast(@as(u32, 0x7ff));
|
||||
};
|
||||
|
||||
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;
|
||||
/// Attributes about the state or features of a file as a bitmask.
|
||||
/// Flags marked [I] correspond to the `FS_IOC_SETFLAGS` values semantically.
|
||||
/// See [FS_IOC_SETFLAGS(2const)](https://man7.org/linux/man-pages/man2/FS_IOC_GETFLAGS.2const.html)
|
||||
/// for more.
|
||||
pub const STATX_ATTR = packed struct(u64) {
|
||||
__pad1: u3 = 0,
|
||||
/// [I] File is compressed by the fs.
|
||||
COMPRESSED: bool = false,
|
||||
__pad2: u1 = 0,
|
||||
/// [I] File is marked immutable.
|
||||
IMMUTABLE: bool = false,
|
||||
/// [I] File is append-only.
|
||||
APPEND: bool = false,
|
||||
/// [I] File is not to be dumped.
|
||||
NODUMP: bool = false,
|
||||
/// [I] File requires a key to decrypt in the filesystem.
|
||||
ENCRYPTED: bool = false,
|
||||
/// File names a directory that triggers an automount.
|
||||
AUTOMOUNT: bool = false,
|
||||
/// File names the root of a mount.
|
||||
MOUNT_ROOT: bool = false,
|
||||
/// [I] File is protected by the `dm-verity` device.
|
||||
VERITY: bool = false,
|
||||
/// File is currently in the CPU direct access state.
|
||||
/// Does not correspond to the per-inode DAX flag that some filesystems support.
|
||||
DAX: bool = false,
|
||||
/// File supports atomic write operations.
|
||||
WRITE_ATOMIC: bool = false,
|
||||
__pad3: u50 = 0,
|
||||
};
|
||||
|
||||
pub const statx_timestamp = extern struct {
|
||||
/// Number of seconds before or after `1970-01-01T00:00:00Z`.
|
||||
sec: i64,
|
||||
/// Number of nanoseconds (0..999,999,999) after `sec`.
|
||||
nsec: u32,
|
||||
// Reserved for future increases in resolution.
|
||||
__pad1: u32,
|
||||
};
|
||||
|
||||
/// Renamed to `Statx` to not conflict with the `statx` function.
|
||||
pub const Statx = extern struct {
|
||||
/// Mask of bits indicating filled fields
|
||||
mask: u32,
|
||||
|
||||
/// Block size for filesystem I/O
|
||||
/// Mask of bits indicating filled fields.
|
||||
mask: STATX,
|
||||
/// Block size for filesystem I/O.
|
||||
blksize: u32,
|
||||
|
||||
/// Extra file attribute indicators
|
||||
attributes: u64,
|
||||
|
||||
/// Number of hard links
|
||||
/// Extra file attribute indicators.
|
||||
attributes: STATX_ATTR,
|
||||
/// Number of hard links.
|
||||
nlink: u32,
|
||||
|
||||
/// User ID of owner
|
||||
/// User ID of owner.
|
||||
uid: uid_t,
|
||||
|
||||
/// Group ID of owner
|
||||
/// Group ID of owner.
|
||||
gid: gid_t,
|
||||
|
||||
/// File type and mode
|
||||
/// File type and mode.
|
||||
mode: u16,
|
||||
__pad1: u16,
|
||||
|
||||
/// Inode number
|
||||
__spare0: u16,
|
||||
/// Inode number.
|
||||
ino: u64,
|
||||
|
||||
/// Total size in bytes
|
||||
/// Total size in bytes.
|
||||
size: u64,
|
||||
|
||||
/// Number of 512B blocks allocated
|
||||
/// Number of 512B blocks allocated.
|
||||
blocks: u64,
|
||||
|
||||
/// Mask to show what's supported in `attributes`.
|
||||
attributes_mask: u64,
|
||||
|
||||
/// Last access file timestamp
|
||||
attributes_mask: STATX_ATTR,
|
||||
/// Last access file timestamp.
|
||||
atime: statx_timestamp,
|
||||
|
||||
/// Creation file timestamp
|
||||
/// Creation file timestamp.
|
||||
btime: statx_timestamp,
|
||||
|
||||
/// Last status change file timestamp
|
||||
/// Last status change file timestamp.
|
||||
ctime: statx_timestamp,
|
||||
|
||||
/// Last modification file timestamp
|
||||
/// Last modification file timestamp.
|
||||
mtime: statx_timestamp,
|
||||
|
||||
/// Major ID, if this file represents a device.
|
||||
rdev_major: u32,
|
||||
|
||||
/// Minor ID, if this file represents a device.
|
||||
rdev_minor: u32,
|
||||
|
||||
/// Major ID of the device containing the filesystem where this file resides.
|
||||
dev_major: u32,
|
||||
|
||||
/// Minor ID of the device containing the filesystem where this file resides.
|
||||
dev_minor: u32,
|
||||
|
||||
__pad2: [14]u64,
|
||||
/// Mount ID
|
||||
mnt_id: u64,
|
||||
/// Memory buffer alignment for direct I/O.
|
||||
dio_mem_align: u32,
|
||||
/// File offset alignment for direct I/O.
|
||||
dio_offset_align: u32,
|
||||
/// Subvolume identifier.
|
||||
subvol: u64,
|
||||
/// Min atomic write unit in bytes.
|
||||
atomic_write_unit_min: u32,
|
||||
/// Max atomic write unit in bytes.
|
||||
atomic_write_unit_max: u32,
|
||||
/// Max atomic write segment count.
|
||||
atomic_write_segments_max: u32,
|
||||
/// File offset alignment for direct I/O reads.
|
||||
dio_read_offset_align: u32,
|
||||
/// Optimised max atomic write unit in bytes.
|
||||
atomic_write_unit_max_opt: u32,
|
||||
__spare2: [1]u32,
|
||||
__spare3: [8]u64,
|
||||
};
|
||||
|
||||
comptime {
|
||||
assert(@sizeOf(Statx) == 0x100);
|
||||
}
|
||||
|
||||
pub const addrinfo = extern struct {
|
||||
flags: AI,
|
||||
family: i32,
|
||||
|
|
@ -9970,6 +9986,46 @@ pub const wrapped = struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub const StatxError = std.posix.UnexpectedError || error{
|
||||
/// Search permission is denied for one of the directories in `path`.
|
||||
AccessDenied,
|
||||
/// Too many symbolic links were encountered traversing `path`.
|
||||
SymLinkLoop,
|
||||
/// `path` is too long.
|
||||
NameTooLong,
|
||||
/// One of:
|
||||
/// - A component of `path` does not exist.
|
||||
/// - A component of `path` is not a directory.
|
||||
/// - `path` is a relative and `dirfd` is not a directory file descriptor.
|
||||
FileNotFound,
|
||||
/// Insufficient memory is available.
|
||||
SystemResources,
|
||||
};
|
||||
|
||||
pub fn statx(dirfd: fd_t, path: [*:0]const u8, flags: u32, mask: STATX) StatxError!Statx {
|
||||
const use_c = std.c.versionCheck(if (builtin.abi.isAndroid())
|
||||
.{ .major = 30, .minor = 0, .patch = 0 }
|
||||
else
|
||||
.{ .major = 2, .minor = 28, .patch = 0 });
|
||||
const sys = if (use_c) std.c else std.os.linux;
|
||||
|
||||
var stx = std.mem.zeroes(Statx);
|
||||
const rc = sys.statx(dirfd, path, flags, mask, &stx);
|
||||
return switch (sys.errno(rc)) {
|
||||
.SUCCESS => stx,
|
||||
.ACCES => error.AccessDenied,
|
||||
.BADF => invalidApiUsage(),
|
||||
.FAULT => invalidApiUsage(),
|
||||
.INVAL => invalidApiUsage(),
|
||||
.LOOP => error.SymLinkLoop,
|
||||
.NAMETOOLONG => error.NameTooLong,
|
||||
.NOENT => error.FileNotFound,
|
||||
.NOTDIR => error.FileNotFound,
|
||||
.NOMEM => error.SystemResources,
|
||||
else => |err| unexpectedErrno(err),
|
||||
};
|
||||
}
|
||||
|
||||
const unexpectedErrno = std.posix.unexpectedErrno;
|
||||
|
||||
fn invalidApiUsage() error{Unexpected} {
|
||||
|
|
|
|||
|
|
@ -958,7 +958,7 @@ pub fn statx(
|
|||
fd: linux.fd_t,
|
||||
path: [:0]const u8,
|
||||
flags: u32,
|
||||
mask: u32,
|
||||
mask: linux.STATX,
|
||||
buf: *linux.Statx,
|
||||
) !*linux.io_uring_sqe {
|
||||
const sqe = try self.get_sqe();
|
||||
|
|
@ -2691,7 +2691,7 @@ test "statx" {
|
|||
tmp.dir.fd,
|
||||
path,
|
||||
0,
|
||||
linux.STATX_SIZE,
|
||||
.{ .SIZE = true },
|
||||
&buf,
|
||||
);
|
||||
try testing.expectEqual(linux.IORING_OP.STATX, sqe.opcode);
|
||||
|
|
@ -2718,7 +2718,7 @@ test "statx" {
|
|||
.flags = 0,
|
||||
}, cqe);
|
||||
|
||||
try testing.expect(buf.mask & linux.STATX_SIZE == linux.STATX_SIZE);
|
||||
try testing.expect(buf.mask.SIZE);
|
||||
try testing.expectEqual(@as(u64, 6), buf.size);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -143,43 +143,4 @@ pub const VDSO = struct {
|
|||
pub const CGT_VER = "LINUX_2.6.39";
|
||||
};
|
||||
|
||||
pub const blksize_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i64;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__pad: u64,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
__pad2: i32,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
__unused: [2]u32,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -179,43 +179,4 @@ pub const HWCAP = struct {
|
|||
pub const EVTSTRM = 1 << 21;
|
||||
};
|
||||
|
||||
pub const blksize_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i32;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
__dev_padding: u32,
|
||||
__ino_truncated: u32,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__rdev_padding: u32,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
ino: ino_t,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -119,45 +119,6 @@ pub fn clone() callconv(.naked) u32 {
|
|||
);
|
||||
}
|
||||
|
||||
pub const blksize_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i64;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__pad: u32,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
__pad2: i32,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
__unused: [2]u32,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
pub const VDSO = void;
|
||||
|
|
|
|||
|
|
@ -420,10 +420,10 @@ pub const io_uring_sqe = extern struct {
|
|||
fd: linux.fd_t,
|
||||
path: [*:0]const u8,
|
||||
flags: u32,
|
||||
mask: u32,
|
||||
mask: linux.STATX,
|
||||
buf: *linux.Statx,
|
||||
) void {
|
||||
sqe.prep_rw(.STATX, fd, @intFromPtr(path), mask, @intFromPtr(buf));
|
||||
sqe.prep_rw(.STATX, fd, @intFromPtr(path), @as(u32, @bitCast(mask)), @intFromPtr(buf));
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,46 +125,7 @@ pub fn clone() callconv(.naked) u64 {
|
|||
);
|
||||
}
|
||||
|
||||
pub const blksize_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i64;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u32;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
_pad1: u64,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
_pad2: i32,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
_pad3: [2]u32,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
pub const VDSO = struct {
|
||||
pub const CGT_SYM = "__vdso_clock_gettime";
|
||||
|
|
|
|||
|
|
@ -142,45 +142,7 @@ pub fn restore_rt() callconv(.naked) noreturn {
|
|||
);
|
||||
}
|
||||
|
||||
pub const blksize_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i32;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
__pad: i16,
|
||||
__ino_truncated: i32,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__pad2: i16,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
ino: ino_t,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
// No VDSO used as of glibc 112a0ae18b831bf31f44d81b82666980312511d6.
|
||||
pub const VDSO = void;
|
||||
|
|
|
|||
|
|
@ -230,43 +230,4 @@ pub const VDSO = struct {
|
|||
pub const CGT_VER = "LINUX_2.6";
|
||||
};
|
||||
|
||||
pub const blksize_t = u32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i32;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat64` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
__pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__pad1: [2]u32,
|
||||
size: off_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
blksize: blksize_t,
|
||||
__pad3: u32,
|
||||
blocks: blkcnt_t,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -184,55 +184,4 @@ pub const VDSO = struct {
|
|||
pub const CGT_VER = "LINUX_2.6";
|
||||
};
|
||||
|
||||
pub const blksize_t = u32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i32;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
__pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__pad1: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
|
||||
size: off_t,
|
||||
atim: u32,
|
||||
atim_nsec: u32,
|
||||
mtim: u32,
|
||||
mtim_nsec: u32,
|
||||
ctim: u32,
|
||||
ctim_nsec: u32,
|
||||
blksize: blksize_t,
|
||||
__pad3: u32,
|
||||
blocks: blkcnt_t,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return .{
|
||||
.sec = self.atim,
|
||||
.nsec = self.atim_nsec,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return .{
|
||||
.sec = self.mtim,
|
||||
.nsec = self.mtim_nsec,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return .{
|
||||
.sec = self.ctim,
|
||||
.nsec = self.ctim_nsec,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -184,55 +184,4 @@ pub const VDSO = struct {
|
|||
pub const CGT_VER = "LINUX_2.6";
|
||||
};
|
||||
|
||||
pub const blksize_t = u32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i32;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
__pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__pad1: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
|
||||
size: off_t,
|
||||
atim: u32,
|
||||
atim_nsec: u32,
|
||||
mtim: u32,
|
||||
mtim_nsec: u32,
|
||||
ctim: u32,
|
||||
ctim_nsec: u32,
|
||||
blksize: blksize_t,
|
||||
__pad3: u32,
|
||||
blocks: blkcnt_t,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return .{
|
||||
.sec = self.atim,
|
||||
.nsec = self.atim_nsec,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return .{
|
||||
.sec = self.mtim,
|
||||
.nsec = self.mtim_nsec,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return .{
|
||||
.sec = self.ctim,
|
||||
.nsec = self.ctim_nsec,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -131,43 +131,4 @@ pub fn clone() callconv(.naked) u32 {
|
|||
|
||||
pub const VDSO = void;
|
||||
|
||||
pub const blksize_t = u32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i32;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat64` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
_pad0: [2]u32,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
_pad1: u32,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
_pad2: [2]u32,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -269,42 +269,4 @@ pub const VDSO = struct {
|
|||
pub const CGT_VER = "LINUX_2.6.15";
|
||||
};
|
||||
|
||||
pub const blksize_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i32;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__rdev_padding: i16,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
__unused: [2]u32,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -254,41 +254,4 @@ pub const VDSO = struct {
|
|||
pub const CGT_VER = "LINUX_2.6.15";
|
||||
};
|
||||
|
||||
pub const blksize_t = i64;
|
||||
pub const nlink_t = u64;
|
||||
pub const time_t = i64;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
nlink: nlink_t,
|
||||
mode: mode_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
__unused: [3]u64,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -124,46 +124,7 @@ pub fn clone() callconv(.naked) u32 {
|
|||
);
|
||||
}
|
||||
|
||||
pub const blksize_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i64;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__pad: u32,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
__pad2: i32,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
__unused: [2]u32,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
pub const VDSO = struct {
|
||||
pub const CGT_SYM = "__vdso_clock_gettime";
|
||||
|
|
|
|||
|
|
@ -124,46 +124,7 @@ pub fn clone() callconv(.naked) u64 {
|
|||
);
|
||||
}
|
||||
|
||||
pub const blksize_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i64;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__pad: u64,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
__pad2: i32,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
__unused: [2]u32,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
pub const VDSO = struct {
|
||||
pub const CGT_SYM = "__vdso_clock_gettime";
|
||||
|
|
|
|||
|
|
@ -152,44 +152,7 @@ pub fn restore_rt() callconv(.naked) noreturn {
|
|||
);
|
||||
}
|
||||
|
||||
pub const blksize_t = i64;
|
||||
pub const nlink_t = u64;
|
||||
pub const time_t = i64;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
nlink: nlink_t,
|
||||
mode: mode_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
size: off_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
blksize: blksize_t,
|
||||
blocks: blkcnt_t,
|
||||
__unused: [3]c_ulong,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
pub const VDSO = struct {
|
||||
pub const CGT_SYM = "__kernel_clock_gettime";
|
||||
|
|
|
|||
|
|
@ -228,46 +228,4 @@ pub const VDSO = struct {
|
|||
pub const CGT_VER = "LINUX_2.6";
|
||||
};
|
||||
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const time_t = i64;
|
||||
pub const mode_t = u32;
|
||||
pub const dev_t = u64;
|
||||
pub const nlink_t = u32;
|
||||
pub const blksize_t = i64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat64` definition used by the kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
nlink: nlink_t,
|
||||
_pad: i32,
|
||||
|
||||
mode: mode_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
__pad0: u32,
|
||||
|
||||
rdev: dev_t,
|
||||
size: i64,
|
||||
blksize: blksize_t,
|
||||
blocks: blkcnt_t,
|
||||
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
__unused: [3]u64,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ const expectEqual = std.testing.expectEqual;
|
|||
const fs = std.fs;
|
||||
|
||||
test "fallocate" {
|
||||
if (builtin.cpu.arch.isMIPS64() and (builtin.abi == .gnuabin32 or builtin.abi == .muslabin32)) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23809
|
||||
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
|
|
@ -84,26 +82,22 @@ test "statx" {
|
|||
var file = try tmp.dir.createFile(tmp_file_name, .{});
|
||||
defer file.close();
|
||||
|
||||
var statx_buf: linux.Statx = undefined;
|
||||
switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
|
||||
var buf: linux.Statx = undefined;
|
||||
switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, .BASIC_STATS, &buf))) {
|
||||
.SUCCESS => {},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
if (builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; // No fstatat, so the rest of the test is meaningless.
|
||||
|
||||
var stat_buf: linux.Stat = undefined;
|
||||
switch (linux.errno(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) {
|
||||
.SUCCESS => {},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
try expect(stat_buf.mode == statx_buf.mode);
|
||||
try expect(@as(u32, @bitCast(stat_buf.uid)) == statx_buf.uid);
|
||||
try expect(@as(u32, @bitCast(stat_buf.gid)) == statx_buf.gid);
|
||||
try expect(@as(u64, @bitCast(@as(i64, stat_buf.size))) == statx_buf.size);
|
||||
try expect(@as(u64, @bitCast(@as(i64, stat_buf.blksize))) == statx_buf.blksize);
|
||||
try expect(@as(u64, @bitCast(@as(i64, stat_buf.blocks))) == statx_buf.blocks);
|
||||
const uid = linux.getuid();
|
||||
const gid = linux.getgid();
|
||||
if (buf.mask.MODE)
|
||||
try expectEqual(@as(linux.mode_t, linux.S.IFREG), buf.mode & linux.S.IFMT);
|
||||
if (buf.mask.UID)
|
||||
try expectEqual(uid, buf.uid);
|
||||
if (buf.mask.GID)
|
||||
try expectEqual(gid, buf.gid);
|
||||
if (buf.mask.SIZE)
|
||||
try expectEqual(@as(u64, 0), buf.size);
|
||||
}
|
||||
|
||||
test "user and group ids" {
|
||||
|
|
|
|||
|
|
@ -132,14 +132,7 @@ pub fn restore_rt() callconv(.naked) noreturn {
|
|||
}
|
||||
}
|
||||
|
||||
pub const mode_t = u32;
|
||||
pub const time_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const blksize_t = i32;
|
||||
pub const blkcnt_t = i32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
|
||||
pub const VDSO = struct {
|
||||
pub const CGT_SYM = "__vdso_clock_gettime";
|
||||
|
|
@ -155,36 +148,3 @@ pub const ARCH = struct {
|
|||
pub const GET_FS = 0x1003;
|
||||
pub const GET_GS = 0x1004;
|
||||
};
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
nlink: nlink_t,
|
||||
|
||||
mode: mode_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
__pad0: u32,
|
||||
rdev: dev_t,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
blocks: i64,
|
||||
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
__unused: [3]i32,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -195,46 +195,7 @@ pub const VDSO = struct {
|
|||
pub const CGT_VER = "LINUX_2.6";
|
||||
};
|
||||
|
||||
pub const blksize_t = i32;
|
||||
pub const nlink_t = u32;
|
||||
pub const time_t = i32;
|
||||
pub const mode_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
pub const blkcnt_t = i64;
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
__dev_padding: u32,
|
||||
__ino_truncated: u32,
|
||||
mode: mode_t,
|
||||
nlink: nlink_t,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
rdev: dev_t,
|
||||
__rdev_padding: u32,
|
||||
size: off_t,
|
||||
blksize: blksize_t,
|
||||
blocks: blkcnt_t,
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
ino: ino_t,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
pub const user_desc = extern struct {
|
||||
entry_number: u32,
|
||||
|
|
|
|||
|
|
@ -132,14 +132,7 @@ pub fn restore_rt() callconv(.naked) noreturn {
|
|||
}
|
||||
}
|
||||
|
||||
pub const mode_t = u64;
|
||||
pub const time_t = i64;
|
||||
pub const nlink_t = u64;
|
||||
pub const blksize_t = i64;
|
||||
pub const blkcnt_t = i64;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = u64;
|
||||
pub const dev_t = u64;
|
||||
|
||||
pub const VDSO = struct {
|
||||
pub const CGT_SYM = "__vdso_clock_gettime";
|
||||
|
|
@ -155,36 +148,3 @@ pub const ARCH = struct {
|
|||
pub const GET_FS = 0x1003;
|
||||
pub const GET_GS = 0x1004;
|
||||
};
|
||||
|
||||
// The `stat` definition used by the Linux kernel.
|
||||
pub const Stat = extern struct {
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
nlink: u64,
|
||||
|
||||
mode: u32,
|
||||
uid: std.os.linux.uid_t,
|
||||
gid: std.os.linux.gid_t,
|
||||
__pad0: u32,
|
||||
rdev: dev_t,
|
||||
size: off_t,
|
||||
blksize: i64,
|
||||
blocks: i64,
|
||||
|
||||
atim: std.os.linux.timespec,
|
||||
mtim: std.os.linux.timespec,
|
||||
ctim: std.os.linux.timespec,
|
||||
__unused: [3]i64,
|
||||
|
||||
pub fn atime(self: @This()) std.os.linux.timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: @This()) std.os.linux.timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: @This()) std.os.linux.timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -119,7 +119,18 @@ pub const STDIN_FILENO = system.STDIN_FILENO;
|
|||
pub const STDOUT_FILENO = system.STDOUT_FILENO;
|
||||
pub const SYS = system.SYS;
|
||||
pub const Sigaction = system.Sigaction;
|
||||
pub const Stat = system.Stat;
|
||||
pub const Stat = switch (native_os) {
|
||||
// Has no concept of `stat`.
|
||||
.windows => void,
|
||||
// The `stat` bits/wrappers are removed due to having to maintain the
|
||||
// different varying `struct stat`s per target and libc, leading to runtime
|
||||
// errors.
|
||||
//
|
||||
// Users targeting linux should add a comptime check and use `statx`,
|
||||
// similar to how `std.fs.File.stat` does.
|
||||
.linux => void,
|
||||
else => system.Stat,
|
||||
};
|
||||
pub const T = system.T;
|
||||
pub const TCP = system.TCP;
|
||||
pub const VDSO = system.VDSO;
|
||||
|
|
@ -480,15 +491,21 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr
|
|||
}
|
||||
defer close(pathfd);
|
||||
|
||||
const stat = fstatatZ(pathfd, "", AT.EMPTY_PATH) catch |err| switch (err) {
|
||||
const path_mode = if (linux.wrapped.statx(
|
||||
pathfd,
|
||||
"",
|
||||
AT.EMPTY_PATH,
|
||||
.{ .TYPE = true },
|
||||
)) |stx| blk: {
|
||||
assert(stx.mask.TYPE);
|
||||
break :blk stx.mode;
|
||||
} else |err| switch (err) {
|
||||
error.NameTooLong => unreachable,
|
||||
error.FileNotFound => unreachable,
|
||||
error.Streaming => unreachable,
|
||||
error.BadPathName => return error.Unexpected,
|
||||
error.Canceled => return error.Canceled,
|
||||
else => |e| return e,
|
||||
};
|
||||
if ((stat.mode & S.IFMT) == S.IFLNK)
|
||||
// Even though we only wanted TYPE, the kernel can still fill in the additional bits.
|
||||
if ((path_mode & S.IFMT) == S.IFLNK)
|
||||
return error.OperationNotSupported;
|
||||
|
||||
var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;
|
||||
|
|
@ -3843,13 +3860,9 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
|
|||
if (native_os == .wasi and !builtin.link_libc) {
|
||||
return Stat.fromFilestat(try std.os.fstat_wasi(fd));
|
||||
}
|
||||
if (native_os == .windows) {
|
||||
@compileError("fstat is not yet implemented on Windows");
|
||||
}
|
||||
|
||||
const fstat_sym = if (lfs64_abi) system.fstat64 else system.fstat;
|
||||
var stat = mem.zeroes(Stat);
|
||||
switch (errno(fstat_sym(fd, &stat))) {
|
||||
switch (errno(system.fstat(fd, &stat))) {
|
||||
.SUCCESS => return stat,
|
||||
.INVAL => unreachable,
|
||||
.BADF => unreachable, // Always a race condition.
|
||||
|
|
@ -3889,9 +3902,8 @@ pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!S
|
|||
@compileError("use std.Io instead");
|
||||
}
|
||||
|
||||
const fstatat_sym = if (lfs64_abi) system.fstatat64 else system.fstatat;
|
||||
var stat = mem.zeroes(Stat);
|
||||
switch (errno(fstatat_sym(dirfd, pathname, &stat, flags))) {
|
||||
switch (errno(system.fstatat(dirfd, pathname, &stat, flags))) {
|
||||
.SUCCESS => return stat,
|
||||
.INVAL => unreachable,
|
||||
.BADF => unreachable, // Always a race condition.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ const AtomicRmwOp = std.builtin.AtomicRmwOp;
|
|||
const AtomicOrder = std.builtin.AtomicOrder;
|
||||
const native_os = builtin.target.os.tag;
|
||||
const tmpDir = std.testing.tmpDir;
|
||||
const AT = posix.AT;
|
||||
|
||||
// NOTE: several additional tests are in test/standalone/posix/. Any tests that mutate
|
||||
// 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 {
|
|||
try expect(mem.eql(u8, target_path, given));
|
||||
}
|
||||
|
||||
test "linkat with different directories" {
|
||||
if ((builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) and builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // No `fstatat()`.
|
||||
if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; // `nstat.nlink` assertion is failing with LLVM 20+ for unclear reasons.
|
||||
fn getLinkInfo(fd: posix.fd_t) !struct { posix.ino_t, posix.nlink_t } {
|
||||
if (native_os == .linux) {
|
||||
const stx = try linux.wrapped.statx(
|
||||
fd,
|
||||
"",
|
||||
posix.AT.EMPTY_PATH,
|
||||
.{ .INO = true, .NLINK = true },
|
||||
);
|
||||
std.debug.assert(stx.mask.INO);
|
||||
std.debug.assert(stx.mask.NLINK);
|
||||
return .{ stx.ino, stx.nlink };
|
||||
}
|
||||
|
||||
const st = try posix.fstat(fd);
|
||||
return .{ st.ino, st.nlink };
|
||||
}
|
||||
|
||||
test "linkat with different directories" {
|
||||
switch (native_os) {
|
||||
.wasi, .linux, .illumos => {},
|
||||
else => return error.SkipZigTest,
|
||||
|
|
@ -153,19 +168,49 @@ test "linkat with different directories" {
|
|||
defer nfd.close();
|
||||
|
||||
{
|
||||
const estat = try posix.fstat(efd.handle);
|
||||
const nstat = try posix.fstat(nfd.handle);
|
||||
try testing.expectEqual(estat.ino, nstat.ino);
|
||||
try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
|
||||
const eino, _ = try getLinkInfo(efd.handle);
|
||||
const nino, const nlink = try getLinkInfo(nfd.handle);
|
||||
try testing.expectEqual(eino, nino);
|
||||
try testing.expectEqual(@as(posix.nlink_t, 2), nlink);
|
||||
}
|
||||
|
||||
// Test 2: remove link
|
||||
try posix.unlinkat(subdir.fd, link_name, 0);
|
||||
_, const elink = try getLinkInfo(efd.handle);
|
||||
try testing.expectEqual(@as(posix.nlink_t, 1), elink);
|
||||
}
|
||||
|
||||
{
|
||||
const estat = try posix.fstat(efd.handle);
|
||||
try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
|
||||
}
|
||||
test "fstatat" {
|
||||
if (posix.Stat == void) return error.SkipZigTest;
|
||||
if (native_os == .wasi and !builtin.link_libc) return error.SkipZigTest;
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
// create dummy file
|
||||
const contents = "nonsense";
|
||||
try tmp.dir.writeFile(.{ .sub_path = "file.txt", .data = contents });
|
||||
|
||||
// fetch file's info on the opened fd directly
|
||||
const file = try tmp.dir.openFile("file.txt", .{});
|
||||
const stat = try posix.fstat(file.handle);
|
||||
defer file.close();
|
||||
|
||||
// now repeat but using `fstatat` instead
|
||||
const statat = try posix.fstatat(tmp.dir.fd, "file.txt", posix.AT.SYMLINK_NOFOLLOW);
|
||||
|
||||
try expectEqual(stat.dev, statat.dev);
|
||||
try expectEqual(stat.ino, statat.ino);
|
||||
try expectEqual(stat.nlink, statat.nlink);
|
||||
try expectEqual(stat.mode, statat.mode);
|
||||
try expectEqual(stat.uid, statat.uid);
|
||||
try expectEqual(stat.gid, statat.gid);
|
||||
try expectEqual(stat.rdev, statat.rdev);
|
||||
try expectEqual(stat.size, statat.size);
|
||||
try expectEqual(stat.blksize, statat.blksize);
|
||||
// The stat.blocks/statat.blocks count is managed by the filesystem and may
|
||||
// change if the file is stored in a journal or "inline".
|
||||
// try expectEqual(stat.blocks, statat.blocks);
|
||||
}
|
||||
|
||||
test "readlinkat" {
|
||||
|
|
@ -906,14 +951,31 @@ test "pwrite with empty buffer" {
|
|||
try expectEqual(rc, 0);
|
||||
}
|
||||
|
||||
fn getFileMode(dir: posix.fd_t, path: []const u8) !posix.mode_t {
|
||||
const path_z = try posix.toPosixPath(path);
|
||||
const mode: posix.mode_t = if (native_os == .linux) blk: {
|
||||
const stx = try linux.wrapped.statx(
|
||||
dir,
|
||||
&path_z,
|
||||
posix.AT.SYMLINK_NOFOLLOW,
|
||||
.{ .MODE = true },
|
||||
);
|
||||
std.debug.assert(stx.mask.MODE);
|
||||
break :blk stx.mode;
|
||||
} else blk: {
|
||||
const st = try posix.fstatatZ(dir, &path_z, posix.AT.SYMLINK_NOFOLLOW);
|
||||
break :blk st.mode;
|
||||
};
|
||||
|
||||
return mode & 0b111_111_111;
|
||||
}
|
||||
|
||||
fn expectMode(dir: posix.fd_t, file: []const u8, mode: posix.mode_t) !void {
|
||||
const st = try posix.fstatat(dir, file, posix.AT.SYMLINK_NOFOLLOW);
|
||||
try expectEqual(mode, st.mode & 0b111_111_111);
|
||||
const actual = try getFileMode(dir, file);
|
||||
try expectEqual(mode, actual & 0b111_111_111);
|
||||
}
|
||||
|
||||
test "fchmodat smoke test" {
|
||||
if (builtin.cpu.arch.isMIPS64() and (builtin.abi == .gnuabin32 or builtin.abi == .muslabin32)) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23808
|
||||
|
||||
if (!std.fs.has_executable_bit) return error.SkipZigTest;
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
|
|
@ -928,13 +990,8 @@ test "fchmodat smoke test" {
|
|||
);
|
||||
posix.close(fd);
|
||||
|
||||
if ((builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) and builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // No `fstatat()`.
|
||||
|
||||
try posix.symlinkat("regfile", tmp.dir.fd, "symlink");
|
||||
const sym_mode = blk: {
|
||||
const st = try posix.fstatat(tmp.dir.fd, "symlink", posix.AT.SYMLINK_NOFOLLOW);
|
||||
break :blk st.mode & 0b111_111_111;
|
||||
};
|
||||
const sym_mode = try getFileMode(tmp.dir.fd, "symlink");
|
||||
|
||||
try posix.fchmodat(tmp.dir.fd, "regfile", 0o640, 0);
|
||||
try expectMode(tmp.dir.fd, "regfile", 0o640);
|
||||
|
|
|
|||
|
|
@ -54,6 +54,20 @@ pub fn init(file: std.Io.File, gpa: std.mem.Allocator) !MappedFile {
|
|||
},
|
||||
};
|
||||
}
|
||||
if (is_linux) {
|
||||
const statx = try linux.wrapped.statx(
|
||||
mf.file.handle,
|
||||
"",
|
||||
std.posix.AT.EMPTY_PATH,
|
||||
.{ .TYPE = true, .SIZE = true, .BLOCKS = true },
|
||||
);
|
||||
assert(statx.mask.TYPE);
|
||||
assert(statx.mask.SIZE);
|
||||
assert(statx.mask.BLOCKS);
|
||||
|
||||
if (!std.posix.S.ISREG(statx.mode)) return error.PathAlreadyExists;
|
||||
break :stat .{ statx.size, @max(std.heap.pageSize(), statx.blksize) };
|
||||
}
|
||||
const stat = try std.posix.fstat(mf.file.handle);
|
||||
if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists;
|
||||
break :stat .{ @bitCast(stat.size), @max(std.heap.pageSize(), stat.blksize) };
|
||||
|
|
|
|||
|
|
@ -23,16 +23,19 @@ const c_string = @cImport(
|
|||
// Version of glibc this test is being built to run against
|
||||
const glibc_ver = builtin.os.versionRange().gnuLibCVersion().?;
|
||||
|
||||
extern "c" fn fstatat(dirfd: i32, path: [*:0]const u8, buf: [*]const u8, flag: u32) c_int;
|
||||
extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: [*]const u8) c_int;
|
||||
|
||||
// PR #17034 - fstat moved between libc_nonshared and libc
|
||||
fn checkStat() !void {
|
||||
const cwdFd = std.fs.cwd().fd;
|
||||
|
||||
var stat = std.mem.zeroes(std.c.Stat);
|
||||
var result = std.c.fstatat(cwdFd, "a_file_that_definitely_does_not_exist", &stat, 0);
|
||||
var buf: [256]u8 = @splat(0);
|
||||
var result = fstatat(cwdFd, "a_file_that_definitely_does_not_exist", &buf, 0);
|
||||
assert(result == -1);
|
||||
assert(std.posix.errno(result) == .NOENT);
|
||||
|
||||
result = std.c.stat("a_file_that_definitely_does_not_exist", &stat);
|
||||
result = stat("a_file_that_definitely_does_not_exist", &buf);
|
||||
assert(result == -1);
|
||||
assert(std.posix.errno(result) == .NOENT);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,20 +48,29 @@ fn test_symlink(a: std.mem.Allocator, tmp: std.testing.TmpDir) !void {
|
|||
try std.testing.expectEqualStrings(target_name, given);
|
||||
}
|
||||
|
||||
fn getLinkInfo(fd: std.posix.fd_t) !struct { std.posix.ino_t, std.posix.nlink_t } {
|
||||
if (builtin.target.os.tag == .linux) {
|
||||
const stx = try std.os.linux.wrapped.statx(
|
||||
fd,
|
||||
"",
|
||||
std.posix.AT.EMPTY_PATH,
|
||||
.{ .INO = true, .NLINK = true },
|
||||
);
|
||||
std.debug.assert(stx.mask.INO);
|
||||
std.debug.assert(stx.mask.NLINK);
|
||||
return .{ stx.ino, stx.nlink };
|
||||
}
|
||||
|
||||
const st = try std.posix.fstat(fd);
|
||||
return .{ st.ino, st.nlink };
|
||||
}
|
||||
|
||||
fn test_link(tmp: std.testing.TmpDir) !void {
|
||||
switch (builtin.target.os.tag) {
|
||||
.linux, .illumos => {},
|
||||
else => return,
|
||||
}
|
||||
|
||||
if ((builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) and builtin.target.os.tag == .linux and !builtin.link_libc) {
|
||||
return; // No `fstat()`.
|
||||
}
|
||||
|
||||
if (builtin.cpu.arch.isMIPS64()) {
|
||||
return; // `nstat.nlink` assertion is failing with LLVM 20+ for unclear reasons.
|
||||
}
|
||||
|
||||
const target_name = "link-target";
|
||||
const link_name = "newlink";
|
||||
|
||||
|
|
@ -78,17 +87,16 @@ fn test_link(tmp: std.testing.TmpDir) !void {
|
|||
defer nfd.close();
|
||||
|
||||
{
|
||||
const estat = try std.posix.fstat(efd.handle);
|
||||
const nstat = try std.posix.fstat(nfd.handle);
|
||||
try std.testing.expectEqual(estat.ino, nstat.ino);
|
||||
try std.testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
|
||||
const eino, _ = try getLinkInfo(efd.handle);
|
||||
const nino, const nlink = try getLinkInfo(nfd.handle);
|
||||
try std.testing.expectEqual(eino, nino);
|
||||
try std.testing.expectEqual(@as(std.posix.nlink_t, 2), nlink);
|
||||
}
|
||||
|
||||
// Test 2: Remove the link and see the stats update
|
||||
try std.posix.unlink(link_name);
|
||||
|
||||
{
|
||||
const estat = try std.posix.fstat(efd.handle);
|
||||
try std.testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
|
||||
_, const elink = try getLinkInfo(efd.handle);
|
||||
try std.testing.expectEqual(@as(std.posix.nlink_t, 1), elink);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue