Zig Version
0.11.0-dev.4296+7e25fb4a4
Steps to Reproduce and Observed Behavior
faccessatZ on linux ignores flags because it is using the wrong syscall, faccessat instead of faccessat2 (see here). In the man page
Because the Linux kernel's faccessat() system call does not support a
flags argument, the glibc faccessat() wrapper function provided in
glibc 2.32 and earlier emulates the required functionality using a com‐
bination of the faccessat() system call and fstatat(2). However, this
emulation does not take ACLs into account. Starting with glibc 2.33,
the wrapper function avoids this bug by making use of the faccessat2()
system call where it is provided by the underlying kernel.
This can be seen in the code below. Created a simple ln --symbolic main.zing src/main2.zig
conststd=@import("std");
pubfnmain() !void {
// stdout is for the actual output of your application, for example if you// are implementing gzip, then only the compressed bytes should be sent to// stdout, not any debugging messages.conststdout_file=std.io.getStdOut().writer();
varbw=std.io.bufferedWriter(stdout_file);
conststdout=bw.writer();
constx=faccessat2Z(std.os.AT.FDCWD, "./src/main2.zig", std.os.X_OK, 0);
trystdout.print("faccessat2 (follow symlink): {!}\n", .{x});
consty=faccessat2Z(std.os.AT.FDCWD, "./src/main2.zig", std.os.X_OK, std.os.AT.SYMLINK_NOFOLLOW);
trystdout.print("faccessat2 (SYMLINK_NOFOLLOW): {!}\n", .{y});
consta=std.os.faccessatZ(std.os.AT.FDCWD, "./src/main2.zig", std.os.X_OK, 0);
trystdout.print("std.os.faccessat (follow symlink): {!}\n", .{a});
constb=std.os.faccessatZ(std.os.AT.FDCWD, "./src/main2.zig", std.os.X_OK, std.os.AT.SYMLINK_NOFOLLOW);
trystdout.print("std.os.faccessat (SYMLINK_NOFOLLOW): {!}\n", .{b});
trybw.flush(); // don't forget to flush!
}
pubfnfaccessat2(dirfd: i32, path: [*:0]constu8, mode: u32, flags: u32) usize {
returnstd.os.linux.syscall4(.faccessat2, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), mode, flags);
}
pubfnfaccessat2Z(dirfd: std.os.fd_t, path: [*:0]constu8, mode: u32, flags: u32) std.os.AccessError!void {
switch (std.os.errno(faccessat2(dirfd, path, mode, flags))) {
.SUCCESS=>return,
.ACCES=>returnerror.PermissionDenied,
.ROFS=>returnerror.ReadOnlyFileSystem,
.LOOP=>returnerror.SymLinkLoop,
.TXTBSY=>returnerror.FileBusy,
.NOTDIR=>returnerror.FileNotFound,
.NOENT=>returnerror.FileNotFound,
.NAMETOOLONG=>returnerror.NameTooLong,
.INVAL=>unreachable,
.FAULT=>unreachable,
.IO=>returnerror.InputOutput,
.NOMEM=>returnerror.SystemResources,
else=>|err|returnstd.os.unexpectedErrno(err),
}
}Output: (notice only faccessat2 did not follow the symlink and returned success)
faccessat2 (followsymlink): error.PermissionDeniedfaccessat2 (SYMLINK_NOFOLLOW): voidstd.os.faccessat (followsymlink): error.PermissionDeniedstd.os.faccessat (SYMLINK_NOFOLLOW): error.PermissionDenied
Expected Behavior
The std library should use the faccessat2. If it does not exist can choose to either fallback to faccessat and ignore flags, or also use the emulated fstatat behavior found in glibc.
Zig Version
0.11.0-dev.4296+7e25fb4a4
Steps to Reproduce and Observed Behavior
faccessatZon linux ignores flags because it is using the wrong syscall,faccessatinstead offaccessat2(see here). In the man pageThis can be seen in the code below. Created a simple
ln --symbolic main.zing src/main2.zigOutput: (notice only faccessat2 did not follow the symlink and returned success)
Expected Behavior
The std library should use the
faccessat2. If it does not exist can choose to either fallback tofaccessatand ignore flags, or also use the emulatedfstatatbehavior found in glibc.