| ... | ... | @@ -235,6 +235,24 @@ const Thread = struct { |
| 235 | 235 | ) orelse return; |
| 236 | 236 | } |
| 237 | 237 | |
| 238 | fn endSyscallErrnoBug(thread: *Thread, err: posix.E) Io.UnexpectedError { |
| 239 | @branchHint(.cold); |
| 240 | thread.endSyscall(); |
| 241 | return errnoBug(err); |
| 242 | } |
| 243 | |
| 244 | fn endSyscallUnexpectedErrno(thread: *Thread, err: posix.E) Io.UnexpectedError { |
| 245 | @branchHint(.cold); |
| 246 | thread.endSyscall(); |
| 247 | return posix.unexpectedErrno(err); |
| 248 | } |
| 249 | |
| 250 | /// inline to make error return traces slightly shallower. |
| 251 | inline fn endSyscallError(thread: *Thread, err: anytype) @TypeOf(err) { |
| 252 | thread.endSyscall(); |
| 253 | return err; |
| 254 | } |
| 255 | |
| 238 | 256 | fn currentSignalId() SignaleeId { |
| 239 | 257 | return if (std.Thread.use_pthreads) std.c.pthread_self() else std.Thread.getCurrentId(); |
| 240 | 258 | } |
| ... | ... | @@ -811,7 +829,6 @@ pub fn io(t: *Threaded) Io { |
| 811 | 829 | .dirSetPermissions = dirSetPermissions, |
| 812 | 830 | .dirSetFilePermissions = dirSetFilePermissions, |
| 813 | 831 | .dirSetTimestamps = dirSetTimestamps, |
| 814 | | .dirSetTimestampsNow = dirSetTimestampsNow, |
| 815 | 832 | .dirHardLink = dirHardLink, |
| 816 | 833 | |
| 817 | 834 | .fileStat = fileStat, |
| ... | ... | @@ -833,7 +850,6 @@ pub fn io(t: *Threaded) Io { |
| 833 | 850 | .fileSetOwner = fileSetOwner, |
| 834 | 851 | .fileSetPermissions = fileSetPermissions, |
| 835 | 852 | .fileSetTimestamps = fileSetTimestamps, |
| 836 | | .fileSetTimestampsNow = fileSetTimestampsNow, |
| 837 | 853 | .fileLock = fileLock, |
| 838 | 854 | .fileTryLock = fileTryLock, |
| 839 | 855 | .fileUnlock = fileUnlock, |
| ... | ... | @@ -947,7 +963,6 @@ pub fn ioBasic(t: *Threaded) Io { |
| 947 | 963 | .dirSetPermissions = dirSetPermissions, |
| 948 | 964 | .dirSetFilePermissions = dirSetFilePermissions, |
| 949 | 965 | .dirSetTimestamps = dirSetTimestamps, |
| 950 | | .dirSetTimestampsNow = dirSetTimestampsNow, |
| 951 | 966 | .dirHardLink = dirHardLink, |
| 952 | 967 | |
| 953 | 968 | .fileStat = fileStat, |
| ... | ... | @@ -969,7 +984,6 @@ pub fn ioBasic(t: *Threaded) Io { |
| 969 | 984 | .fileSetOwner = fileSetOwner, |
| 970 | 985 | .fileSetPermissions = fileSetPermissions, |
| 971 | 986 | .fileSetTimestamps = fileSetTimestamps, |
| 972 | | .fileSetTimestampsNow = fileSetTimestampsNow, |
| 973 | 987 | .fileLock = fileLock, |
| 974 | 988 | .fileTryLock = fileTryLock, |
| 975 | 989 | .fileUnlock = fileUnlock, |
| ... | ... | @@ -5977,8 +5991,6 @@ fn dirSetTimestamps( |
| 5977 | 5991 | userdata: ?*anyopaque, |
| 5978 | 5992 | dir: Dir, |
| 5979 | 5993 | sub_path: []const u8, |
| 5980 | | last_accessed: Io.Timestamp, |
| 5981 | | last_modified: Io.Timestamp, |
| 5982 | 5994 | options: Dir.SetTimestampsOptions, |
| 5983 | 5995 | ) Dir.SetTimestampsError!void { |
| 5984 | 5996 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| ... | ... | @@ -5992,9 +6004,13 @@ fn dirSetTimestamps( |
| 5992 | 6004 | @panic("TODO implement dirSetTimestamps wasi"); |
| 5993 | 6005 | } |
| 5994 | 6006 | |
| 5995 | | const times: [2]posix.timespec = .{ |
| 5996 | | timestampToPosix(last_accessed.nanoseconds), |
| 5997 | | timestampToPosix(last_modified.nanoseconds), |
| 6007 | var times_buffer: [2]posix.timespec = undefined; |
| 6008 | const times = if (options.modify_timestamp == .now and options.access_timestamp == .now) null else p: { |
| 6009 | times_buffer = .{ |
| 6010 | setTimestampToPosix(options.access_timestamp), |
| 6011 | setTimestampToPosix(options.modify_timestamp), |
| 6012 | }; |
| 6013 | break :p &times_buffer; |
| 5998 | 6014 | }; |
| 5999 | 6015 | |
| 6000 | 6016 | const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0; |
| ... | ... | @@ -6003,80 +6019,26 @@ fn dirSetTimestamps( |
| 6003 | 6019 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); |
| 6004 | 6020 | |
| 6005 | 6021 | try current_thread.beginSyscall(); |
| 6006 | | while (true) { |
| 6007 | | switch (posix.errno(posix.system.utimensat(dir.handle, sub_path_posix, &times, flags))) { |
| 6008 | | .SUCCESS => return current_thread.endSyscall(), |
| 6009 | | .INTR => { |
| 6010 | | try current_thread.checkCancel(); |
| 6011 | | continue; |
| 6012 | | }, |
| 6013 | | else => |e| { |
| 6014 | | current_thread.endSyscall(); |
| 6015 | | switch (e) { |
| 6016 | | .ACCES => return error.AccessDenied, |
| 6017 | | .PERM => return error.PermissionDenied, |
| 6018 | | .BADF => |err| return errnoBug(err), // always a race condition |
| 6019 | | .FAULT => |err| return errnoBug(err), |
| 6020 | | .INVAL => |err| return errnoBug(err), |
| 6021 | | .ROFS => return error.ReadOnlyFileSystem, |
| 6022 | | else => |err| return posix.unexpectedErrno(err), |
| 6023 | | } |
| 6024 | | }, |
| 6025 | | } |
| 6026 | | } |
| 6027 | | } |
| 6028 | | |
| 6029 | | fn dirSetTimestampsNow( |
| 6030 | | userdata: ?*anyopaque, |
| 6031 | | dir: Dir, |
| 6032 | | sub_path: []const u8, |
| 6033 | | options: Dir.SetTimestampsOptions, |
| 6034 | | ) Dir.SetTimestampsError!void { |
| 6035 | | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 6036 | | const current_thread = Thread.getCurrent(t); |
| 6037 | | |
| 6038 | | if (is_windows) { |
| 6039 | | @panic("TODO implement dirSetTimestampsNow windows"); |
| 6040 | | } |
| 6041 | | |
| 6042 | | if (native_os == .wasi and !builtin.link_libc) { |
| 6043 | | @panic("TODO implement dirSetTimestampsNow wasi"); |
| 6044 | | } |
| 6045 | | |
| 6046 | | const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0; |
| 6047 | | |
| 6048 | | var path_buffer: [posix.PATH_MAX]u8 = undefined; |
| 6049 | | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); |
| 6050 | | |
| 6051 | | try current_thread.beginSyscall(); |
| 6052 | | while (true) { |
| 6053 | | switch (posix.errno(posix.system.utimensat(dir.handle, sub_path_posix, null, flags))) { |
| 6054 | | .SUCCESS => return current_thread.endSyscall(), |
| 6055 | | .INTR => { |
| 6056 | | try current_thread.checkCancel(); |
| 6057 | | continue; |
| 6058 | | }, |
| 6059 | | else => |e| { |
| 6060 | | current_thread.endSyscall(); |
| 6061 | | switch (e) { |
| 6062 | | .ACCES => return error.AccessDenied, |
| 6063 | | .PERM => return error.PermissionDenied, |
| 6064 | | .BADF => |err| return errnoBug(err), // always a race condition |
| 6065 | | .FAULT => |err| return errnoBug(err), |
| 6066 | | .INVAL => |err| return errnoBug(err), |
| 6067 | | .ROFS => return error.ReadOnlyFileSystem, |
| 6068 | | else => |err| return posix.unexpectedErrno(err), |
| 6069 | | } |
| 6070 | | }, |
| 6071 | | } |
| 6072 | | } |
| 6022 | while (true) switch (posix.errno(posix.system.utimensat(dir.handle, sub_path_posix, times, flags))) { |
| 6023 | .SUCCESS => return current_thread.endSyscall(), |
| 6024 | .INTR => { |
| 6025 | try current_thread.checkCancel(); |
| 6026 | continue; |
| 6027 | }, |
| 6028 | .BADF => |err| return current_thread.endSyscallErrnoBug(err), // always a race condition |
| 6029 | .FAULT => |err| return current_thread.endSyscallErrnoBug(err), |
| 6030 | .INVAL => |err| return current_thread.endSyscallErrnoBug(err), |
| 6031 | .ACCES => return current_thread.endSyscallError(error.AccessDenied), |
| 6032 | .PERM => return current_thread.endSyscallError(error.PermissionDenied), |
| 6033 | .ROFS => return current_thread.endSyscallError(error.ReadOnlyFileSystem), |
| 6034 | else => |err| return current_thread.endSyscallUnexpectedErrno(err), |
| 6035 | }; |
| 6073 | 6036 | } |
| 6074 | 6037 | |
| 6075 | 6038 | fn fileSetTimestamps( |
| 6076 | 6039 | userdata: ?*anyopaque, |
| 6077 | 6040 | file: File, |
| 6078 | | last_accessed: Io.Timestamp, |
| 6079 | | last_modified: Io.Timestamp, |
| 6041 | options: File.SetTimestampsOptions, |
| 6080 | 6042 | ) File.SetTimestampsError!void { |
| 6081 | 6043 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 6082 | 6044 | const current_thread = Thread.getCurrent(t); |
| ... | ... | @@ -6084,8 +6046,8 @@ fn fileSetTimestamps( |
| 6084 | 6046 | if (is_windows) { |
| 6085 | 6047 | try current_thread.checkCancel(); |
| 6086 | 6048 | |
| 6087 | | const atime_ft = windows.nanoSecondsToFileTime(last_accessed); |
| 6088 | | const mtime_ft = windows.nanoSecondsToFileTime(last_modified); |
| 6049 | const atime_ft = windows.nanoSecondsToFileTime(options.access_time); |
| 6050 | const mtime_ft = windows.nanoSecondsToFileTime(options.modify_time); |
| 6089 | 6051 | |
| 6090 | 6052 | // https://github.com/ziglang/zig/issues/1840 |
| 6091 | 6053 | const rc = windows.kernel32.SetFileTime(file.handle, null, &atime_ft, &mtime_ft); |
| ... | ... | @@ -6097,123 +6059,53 @@ fn fileSetTimestamps( |
| 6097 | 6059 | return; |
| 6098 | 6060 | } |
| 6099 | 6061 | |
| 6100 | | const times: [2]posix.timespec = .{ |
| 6101 | | timestampToPosix(last_accessed.nanoseconds), |
| 6102 | | timestampToPosix(last_modified.nanoseconds), |
| 6103 | | }; |
| 6104 | | |
| 6105 | 6062 | if (native_os == .wasi and !builtin.link_libc) { |
| 6106 | | const atim = times[0].toTimestamp(); |
| 6107 | | const mtim = times[1].toTimestamp(); |
| 6063 | const atim = timestampToPosix(options.access_time.nanoseconds).toTimestamp(); |
| 6064 | const mtim = timestampToPosix(options.modify_time.nanoseconds).toTimestamp(); |
| 6108 | 6065 | try current_thread.beginSyscall(); |
| 6109 | | while (true) { |
| 6110 | | switch (std.os.wasi.fd_filestat_set_times(file.handle, atim, mtim, .{ |
| 6111 | | .ATIM = true, |
| 6112 | | .MTIM = true, |
| 6113 | | })) { |
| 6114 | | .SUCCESS => return current_thread.endSyscall(), |
| 6115 | | .INTR => { |
| 6116 | | try current_thread.checkCancel(); |
| 6117 | | continue; |
| 6118 | | }, |
| 6119 | | else => |e| { |
| 6120 | | current_thread.endSyscall(); |
| 6121 | | switch (e) { |
| 6122 | | .ACCES => return error.AccessDenied, |
| 6123 | | .PERM => return error.PermissionDenied, |
| 6124 | | .BADF => |err| return errnoBug(err), // File descriptor use-after-free. |
| 6125 | | .FAULT => |err| return errnoBug(err), |
| 6126 | | .INVAL => |err| return errnoBug(err), |
| 6127 | | .ROFS => return error.ReadOnlyFileSystem, |
| 6128 | | else => |err| return posix.unexpectedErrno(err), |
| 6129 | | } |
| 6130 | | }, |
| 6131 | | } |
| 6132 | | } |
| 6133 | | } |
| 6134 | | |
| 6135 | | try current_thread.beginSyscall(); |
| 6136 | | while (true) { |
| 6137 | | switch (posix.errno(posix.system.futimens(file.handle, &times))) { |
| 6066 | while (true) switch (std.os.wasi.fd_filestat_set_times(file.handle, atim, mtim, .{ |
| 6067 | .ATIM = true, |
| 6068 | .MTIM = true, |
| 6069 | })) { |
| 6138 | 6070 | .SUCCESS => return current_thread.endSyscall(), |
| 6139 | 6071 | .INTR => { |
| 6140 | 6072 | try current_thread.checkCancel(); |
| 6141 | 6073 | continue; |
| 6142 | 6074 | }, |
| 6143 | | else => |e| { |
| 6144 | | current_thread.endSyscall(); |
| 6145 | | switch (e) { |
| 6146 | | .ACCES => return error.AccessDenied, |
| 6147 | | .PERM => return error.PermissionDenied, |
| 6148 | | .BADF => |err| return errnoBug(err), // always a race condition |
| 6149 | | .FAULT => |err| return errnoBug(err), |
| 6150 | | .INVAL => |err| return errnoBug(err), |
| 6151 | | .ROFS => return error.ReadOnlyFileSystem, |
| 6152 | | else => |err| return posix.unexpectedErrno(err), |
| 6153 | | } |
| 6154 | | }, |
| 6155 | | } |
| 6156 | | } |
| 6157 | | } |
| 6158 | | |
| 6159 | | fn fileSetTimestampsNow(userdata: ?*anyopaque, file: File) File.SetTimestampsError!void { |
| 6160 | | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 6161 | | const current_thread = Thread.getCurrent(t); |
| 6162 | | |
| 6163 | | if (is_windows) { |
| 6164 | | @panic("TODO implement fileSetTimestampsNow windows"); |
| 6075 | .BADF => |err| return current_thread.endSyscallErrnoBug(err), // File descriptor use-after-free. |
| 6076 | .FAULT => |err| return current_thread.endSyscallErrnoBug(err), |
| 6077 | .INVAL => |err| return current_thread.endSyscallErrnoBug(err), |
| 6078 | .ACCES => return current_thread.endSyscallErrnoBug(error.AccessDenied), |
| 6079 | .PERM => return current_thread.endSyscallErrnoBug(error.PermissionDenied), |
| 6080 | .ROFS => return current_thread.endSyscallErrnoBug(error.ReadOnlyFileSystem), |
| 6081 | else => |err| return current_thread.endSyscallUnexpectedErrno(err), |
| 6082 | }; |
| 6165 | 6083 | } |
| 6166 | 6084 | |
| 6167 | | if (native_os == .wasi and !builtin.link_libc) { |
| 6168 | | try current_thread.beginSyscall(); |
| 6169 | | while (true) { |
| 6170 | | switch (std.os.wasi.fd_filestat_set_times(file.handle, 0, 0, .{ |
| 6171 | | .ATIM_NOW = true, |
| 6172 | | .MTIM_NOW = true, |
| 6173 | | })) { |
| 6174 | | .SUCCESS => return current_thread.endSyscall(), |
| 6175 | | .INTR => { |
| 6176 | | try current_thread.checkCancel(); |
| 6177 | | continue; |
| 6178 | | }, |
| 6179 | | else => |e| { |
| 6180 | | current_thread.endSyscall(); |
| 6181 | | switch (e) { |
| 6182 | | .ACCES => return error.AccessDenied, |
| 6183 | | .PERM => return error.PermissionDenied, |
| 6184 | | .BADF => |err| return errnoBug(err), // always a race condition |
| 6185 | | .FAULT => |err| return errnoBug(err), |
| 6186 | | .INVAL => |err| return errnoBug(err), |
| 6187 | | .ROFS => return error.ReadOnlyFileSystem, |
| 6188 | | else => |err| return posix.unexpectedErrno(err), |
| 6189 | | } |
| 6190 | | }, |
| 6191 | | } |
| 6192 | | } |
| 6193 | | } |
| 6085 | var times_buffer: [2]posix.timespec = undefined; |
| 6086 | const times = if (options.modify_timestamp == .now and options.access_timestamp == .now) null else p: { |
| 6087 | times_buffer = .{ |
| 6088 | setTimestampToPosix(options.access_timestamp), |
| 6089 | setTimestampToPosix(options.modify_timestamp), |
| 6090 | }; |
| 6091 | break :p &times_buffer; |
| 6092 | }; |
| 6194 | 6093 | |
| 6195 | 6094 | try current_thread.beginSyscall(); |
| 6196 | | while (true) { |
| 6197 | | switch (posix.errno(posix.system.futimens(file.handle, null))) { |
| 6198 | | .SUCCESS => return current_thread.endSyscall(), |
| 6199 | | .INTR => { |
| 6200 | | try current_thread.checkCancel(); |
| 6201 | | continue; |
| 6202 | | }, |
| 6203 | | else => |e| { |
| 6204 | | current_thread.endSyscall(); |
| 6205 | | switch (e) { |
| 6206 | | .ACCES => return error.AccessDenied, |
| 6207 | | .PERM => return error.PermissionDenied, |
| 6208 | | .BADF => |err| return errnoBug(err), // always a race condition |
| 6209 | | .FAULT => |err| return errnoBug(err), |
| 6210 | | .INVAL => |err| return errnoBug(err), |
| 6211 | | .ROFS => return error.ReadOnlyFileSystem, |
| 6212 | | else => |err| return posix.unexpectedErrno(err), |
| 6213 | | } |
| 6214 | | }, |
| 6215 | | } |
| 6216 | | } |
| 6095 | while (true) switch (posix.errno(posix.system.futimens(file.handle, times))) { |
| 6096 | .SUCCESS => return current_thread.endSyscall(), |
| 6097 | .INTR => { |
| 6098 | try current_thread.checkCancel(); |
| 6099 | continue; |
| 6100 | }, |
| 6101 | .BADF => |err| return current_thread.endSyscallErrnoBug(err), // always a race condition |
| 6102 | .FAULT => |err| return current_thread.endSyscallErrnoBug(err), |
| 6103 | .INVAL => |err| return current_thread.endSyscallErrnoBug(err), |
| 6104 | .ACCES => return current_thread.endSyscallError(error.AccessDenied), |
| 6105 | .PERM => return current_thread.endSyscallError(error.PermissionDenied), |
| 6106 | .ROFS => return current_thread.endSyscallError(error.ReadOnlyFileSystem), |
| 6107 | else => |err| return current_thread.endSyscallUnexpectedErrno(err), |
| 6108 | }; |
| 6217 | 6109 | } |
| 6218 | 6110 | |
| 6219 | 6111 | const windows_lock_range_off: windows.LARGE_INTEGER = 0; |
| ... | ... | @@ -11283,6 +11175,14 @@ fn timestampToPosix(nanoseconds: i96) posix.timespec { |
| 11283 | 11175 | }; |
| 11284 | 11176 | } |
| 11285 | 11177 | |
| 11178 | fn setTimestampToPosix(set_ts: File.SetTimestamp) posix.timespec { |
| 11179 | return switch (set_ts) { |
| 11180 | .unchanged => .OMIT, |
| 11181 | .now => .NOW, |
| 11182 | .new => |t| timestampToPosix(t.nanoseconds), |
| 11183 | }; |
| 11184 | } |
| 11185 | |
| 11286 | 11186 | fn pathToPosix(file_path: []const u8, buffer: *[posix.PATH_MAX]u8) Dir.PathNameError![:0]u8 { |
| 11287 | 11187 | if (std.mem.containsAtLeastScalar2(u8, file_path, 0, 1)) return error.BadPathName; |
| 11288 | 11188 | // >= rather than > to make room for the null byte |