| ... | ... | @@ -2091,7 +2091,7 @@ fn fileStatLinux(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 2091 | 2091 | try current_thread.beginSyscall(); |
| 2092 | 2092 | while (true) { |
| 2093 | 2093 | var statx = std.mem.zeroes(linux.Statx); |
| 2094 | | const rc = sys.statx( |
| 2094 | switch (sys.errno(sys.statx( |
| 2095 | 2095 | file.handle, |
| 2096 | 2096 | "", |
| 2097 | 2097 | linux.AT.EMPTY_PATH, |
| ... | ... | @@ -2106,8 +2106,7 @@ fn fileStatLinux(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 2106 | 2106 | .NLINK = true, |
| 2107 | 2107 | }, |
| 2108 | 2108 | &statx, |
| 2109 | | ); |
| 2110 | | switch (sys.errno(rc)) { |
| 2109 | ))) { |
| 2111 | 2110 | .SUCCESS => { |
| 2112 | 2111 | current_thread.endSyscall(); |
| 2113 | 2112 | return statFromLinux(&statx); |
| ... | ... | @@ -5120,7 +5119,7 @@ fn posixFchmodat( |
| 5120 | 5119 | } |
| 5121 | 5120 | |
| 5122 | 5121 | if (@atomicLoad(UseFchmodat2, &t.use_fchmodat2, .monotonic) == .disabled) |
| 5123 | | return fchmodatFallback(current_thread, dir_fd, path, mode, flags); |
| 5122 | return fchmodatFallback(current_thread, dir_fd, path, mode); |
| 5124 | 5123 | |
| 5125 | 5124 | comptime assert(native_os == .linux); |
| 5126 | 5125 | |
| ... | ... | @@ -5149,7 +5148,7 @@ fn posixFchmodat( |
| 5149 | 5148 | .ROFS => return error.ReadOnlyFileSystem, |
| 5150 | 5149 | .NOSYS => { |
| 5151 | 5150 | @atomicStore(UseFchmodat2, &t.use_fchmodat2, .disabled, .monotonic); |
| 5152 | | return fchmodatFallback(current_thread, dir_fd, path, mode, flags); |
| 5151 | return fchmodatFallback(current_thread, dir_fd, path, mode); |
| 5153 | 5152 | }, |
| 5154 | 5153 | else => |err| return posix.unexpectedErrno(err), |
| 5155 | 5154 | } |
| ... | ... | @@ -5163,16 +5162,114 @@ fn fchmodatFallback( |
| 5163 | 5162 | dir_fd: posix.fd_t, |
| 5164 | 5163 | path: [*:0]const u8, |
| 5165 | 5164 | mode: posix.mode_t, |
| 5166 | | flags: u32, |
| 5167 | 5165 | ) Dir.SetFilePermissionsError!void { |
| 5168 | | _ = current_thread; |
| 5169 | | _ = dir_fd; |
| 5170 | | _ = path; |
| 5171 | | _ = mode; |
| 5172 | | _ = flags; |
| 5173 | | // I deleted the previous fallback implementation because it looked wrong to me. Please cross-reference |
| 5174 | | // fhmodat.c in musl libc before blindly restoring the implementation. |
| 5175 | | @panic("TODO"); |
| 5166 | comptime assert(native_os == .linux); |
| 5167 | const use_c = std.c.versionCheck(if (builtin.abi.isAndroid()) |
| 5168 | .{ .major = 30, .minor = 0, .patch = 0 } |
| 5169 | else |
| 5170 | .{ .major = 2, .minor = 28, .patch = 0 }); |
| 5171 | const sys = if (use_c) std.c else std.os.linux; |
| 5172 | |
| 5173 | // Fallback to changing permissions using procfs: |
| 5174 | // |
| 5175 | // 1. Open `path` as a `PATH` descriptor. |
| 5176 | // 2. Stat the fd and check if it isn't a symbolic link. |
| 5177 | // 3. Generate the procfs reference to the fd via `/proc/self/fd/{fd}`. |
| 5178 | // 4. Pass the procfs path to `chmod` with the `mode`. |
| 5179 | try current_thread.beginSyscall(); |
| 5180 | const path_fd: posix.fd_t = while (true) { |
| 5181 | const rc = posix.system.openat(dir_fd, path, .{ |
| 5182 | .PATH = true, |
| 5183 | .NOFOLLOW = true, |
| 5184 | .CLOEXEC = true, |
| 5185 | }, @as(posix.mode_t, 0)); |
| 5186 | switch (posix.errno(rc)) { |
| 5187 | .SUCCESS => { |
| 5188 | current_thread.endSyscall(); |
| 5189 | break @intCast(rc); |
| 5190 | }, |
| 5191 | .INTR => { |
| 5192 | try current_thread.checkCancel(); |
| 5193 | continue; |
| 5194 | }, |
| 5195 | else => |e| { |
| 5196 | current_thread.endSyscall(); |
| 5197 | switch (e) { |
| 5198 | .FAULT => |err| return errnoBug(err), |
| 5199 | .INVAL => |err| return errnoBug(err), |
| 5200 | .ACCES => return error.AccessDenied, |
| 5201 | .PERM => return error.PermissionDenied, |
| 5202 | .LOOP => return error.SymLinkLoop, |
| 5203 | .MFILE => return error.ProcessFdQuotaExceeded, |
| 5204 | .NAMETOOLONG => return error.NameTooLong, |
| 5205 | .NFILE => return error.SystemFdQuotaExceeded, |
| 5206 | .NOENT => return error.FileNotFound, |
| 5207 | .NOMEM => return error.SystemResources, |
| 5208 | else => |err| return posix.unexpectedErrno(err), |
| 5209 | } |
| 5210 | }, |
| 5211 | } |
| 5212 | }; |
| 5213 | defer posix.close(path_fd); |
| 5214 | |
| 5215 | try current_thread.beginSyscall(); |
| 5216 | const path_mode = while (true) { |
| 5217 | var statx = std.mem.zeroes(std.os.linux.Statx); |
| 5218 | switch (sys.errno(sys.statx(path_fd, "", posix.AT.EMPTY_PATH, .{ .TYPE = true }, &statx))) { |
| 5219 | .SUCCESS => { |
| 5220 | current_thread.endSyscall(); |
| 5221 | assert(statx.mask.TYPE); |
| 5222 | break statx.mode; |
| 5223 | }, |
| 5224 | .INTR => { |
| 5225 | try current_thread.checkCancel(); |
| 5226 | continue; |
| 5227 | }, |
| 5228 | else => |e| { |
| 5229 | current_thread.endSyscall(); |
| 5230 | switch (e) { |
| 5231 | .ACCES => return error.AccessDenied, |
| 5232 | .LOOP => return error.SymLinkLoop, |
| 5233 | .NOMEM => return error.SystemResources, |
| 5234 | else => |err| return posix.unexpectedErrno(err), |
| 5235 | } |
| 5236 | }, |
| 5237 | } |
| 5238 | }; |
| 5239 | |
| 5240 | // Even though we only wanted TYPE, the kernel can still fill in the additional bits. |
| 5241 | if ((path_mode & posix.S.IFMT) == posix.S.IFLNK) |
| 5242 | return error.OperationUnsupported; |
| 5243 | |
| 5244 | var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; |
| 5245 | const proc_path = std.fmt.bufPrintSentinel(&procfs_buf, "/proc/self/fd/{d}", .{path_fd}, 0) catch unreachable; |
| 5246 | try current_thread.beginSyscall(); |
| 5247 | while (true) { |
| 5248 | switch (posix.errno(posix.system.chmod(proc_path, mode))) { |
| 5249 | .SUCCESS => return current_thread.endSyscall(), |
| 5250 | .INTR => { |
| 5251 | try current_thread.checkCancel(); |
| 5252 | continue; |
| 5253 | }, |
| 5254 | else => |e| { |
| 5255 | current_thread.endSyscall(); |
| 5256 | switch (e) { |
| 5257 | .NOENT => return error.OperationUnsupported, // procfs not mounted. |
| 5258 | .BADF => |err| return errnoBug(err), |
| 5259 | .FAULT => |err| return errnoBug(err), |
| 5260 | .INVAL => |err| return errnoBug(err), |
| 5261 | .ACCES => return error.AccessDenied, |
| 5262 | .IO => return error.InputOutput, |
| 5263 | .LOOP => return error.SymLinkLoop, |
| 5264 | .NOMEM => return error.SystemResources, |
| 5265 | .NOTDIR => return error.FileNotFound, |
| 5266 | .PERM => return error.PermissionDenied, |
| 5267 | .ROFS => return error.ReadOnlyFileSystem, |
| 5268 | else => |err| return posix.unexpectedErrno(err), |
| 5269 | } |
| 5270 | }, |
| 5271 | } |
| 5272 | } |
| 5176 | 5273 | } |
| 5177 | 5274 | |
| 5178 | 5275 | const dirSetOwner = switch (native_os) { |