@@ -5055,33 +5055,52 @@ pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) Acces
5055
5055
return faccessat (dirfd , mem .sliceTo (path , 0 ), mode , flags );
5056
5056
}
5057
5057
5058
- const need_flags = (flags != 0 ); //the older, simpler syscall should stay supported, so we only need to use faccessat2 if we need flags
5059
- const faccessat_result = switch (system ) {
5060
- linux = > if (need_flags )
5061
- linux .faccessat2 (dirfd , path , mode , flags )
5062
- else
5063
- linux .faccessat (dirfd , path , mode ),
5064
- else = > system .faccessat (dirfd , path , mode , flags ),
5058
+ const linux_is_guaranteed_at_least_5_8 = builtin .target .os .isAtLeast (.linux , .{ .major = 5 , .minor = 8 , .patch = 0 });
5059
+ const try_with_flags_first = try_with_flags_first : switch (system ) {
5060
+ linux = > { //regular .faccessat syscall doesn't support flags argument
5061
+ if (builtin .abi .isAndroid ()) break :try_with_flags_first false ; //standard android programs run in a seccomp sandbox that seems to trigger signal 31 (SIGSYS) for faccessat2
5062
+ if (linux_is_guaranteed_at_least_5_8 != true ) break :try_with_flags_first false ; //faccessat2 was introduced in Linux 5.8
5063
+ break :try_with_flags_first (flags != 0 ); //the older, simpler syscall should stay supported, so we only need to use faccessat2 if we need flags
5064
+ },
5065
+ else = > true ,
5065
5066
};
5066
- switch (errno (faccessat_result )) {
5067
- .SUCCESS = > return ,
5068
- .ACCES = > return error .AccessDenied ,
5069
- .PERM = > return error .PermissionDenied ,
5070
- .ROFS = > return error .ReadOnlyFileSystem ,
5071
- .LOOP = > return error .SymLinkLoop ,
5072
- .TXTBSY = > return error .FileBusy ,
5073
- .NOTDIR = > return error .FileNotFound ,
5074
- .NOENT = > return error .FileNotFound ,
5075
- .NAMETOOLONG = > return error .NameTooLong ,
5076
- .INVAL = > unreachable ,
5077
- .FAULT = > unreachable ,
5078
- .IO = > return error .InputOutput ,
5079
- .NOMEM = > return error .SystemResources ,
5080
- .ILSEQ = > | err | if (native_os == .wasi )
5081
- return error .InvalidUtf8
5082
- else
5083
- return unexpectedErrno (err ),
5084
- else = > | err | return unexpectedErrno (err ),
5067
+ try_with_flags_now : switch (try_with_flags_first ) {
5068
+ else = > | try_with_flags_now | {
5069
+ if (! try_with_flags_now ) {
5070
+ if (flags != 0 ) return error .UnsupportedFlags ;
5071
+ }
5072
+ const faccessat_result = switch (system ) {
5073
+ linux = > if (need_flags )
5074
+ linux .faccessat2 (dirfd , path , mode , flags )
5075
+ else
5076
+ linux .faccessat (dirfd , path , mode ),
5077
+ else = > system .faccessat (dirfd , path , mode , flags ),
5078
+ };
5079
+ switch (errno (faccessat_result )) {
5080
+ .SUCCESS = > return ,
5081
+ .ACCES = > return error .AccessDenied ,
5082
+ .PERM = > return error .PermissionDenied ,
5083
+ .ROFS = > return error .ReadOnlyFileSystem ,
5084
+ .LOOP = > return error .SymLinkLoop ,
5085
+ .TXTBSY = > return error .FileBusy ,
5086
+ .NOTDIR = > return error .FileNotFound ,
5087
+ .NOENT = > return error .FileNotFound ,
5088
+ .NAMETOOLONG = > return error .NameTooLong ,
5089
+ .INVAL = > unreachable ,
5090
+ .FAULT = > unreachable ,
5091
+ .IO = > return error .InputOutput ,
5092
+ .NOMEM = > return error .SystemResources ,
5093
+ .ILSEQ = > | err | if (native_os == .wasi )
5094
+ return error .InvalidUtf8
5095
+ else
5096
+ return unexpectedErrno (err ),
5097
+ .NOSYS = > | err | if (system == linux and try_with_flags_now )
5098
+ continue :try_with_flags_now false //retry with older .faccessat (without support for flags)
5099
+ else
5100
+ return unexpectedErrno (err ),
5101
+ else = > | err | return unexpectedErrno (err ),
5102
+ }
5103
+ },
5085
5104
}
5086
5105
}
5087
5106
0 commit comments