| ... | @@ -235,6 +235,24 @@ const Thread = struct { | ... | @@ -235,6 +235,24 @@ const Thread = struct { |
| 235 | ) orelse return; | 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 | fn currentSignalId() SignaleeId { | 256 | fn currentSignalId() SignaleeId { |
| 239 | return if (std.Thread.use_pthreads) std.c.pthread_self() else std.Thread.getCurrentId(); | 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,7 +829,6 @@ pub fn io(t: *Threaded) Io { |
| 811 | .dirSetPermissions = dirSetPermissions, | 829 | .dirSetPermissions = dirSetPermissions, |
| 812 | .dirSetFilePermissions = dirSetFilePermissions, | 830 | .dirSetFilePermissions = dirSetFilePermissions, |
| 813 | .dirSetTimestamps = dirSetTimestamps, | 831 | .dirSetTimestamps = dirSetTimestamps, |
| 814 | .dirSetTimestampsNow = dirSetTimestampsNow, | | |
| 815 | .dirHardLink = dirHardLink, | 832 | .dirHardLink = dirHardLink, |
| 816 | | 833 | |
| 817 | .fileStat = fileStat, | 834 | .fileStat = fileStat, |
| ... | @@ -833,7 +850,6 @@ pub fn io(t: *Threaded) Io { | ... | @@ -833,7 +850,6 @@ pub fn io(t: *Threaded) Io { |
| 833 | .fileSetOwner = fileSetOwner, | 850 | .fileSetOwner = fileSetOwner, |
| 834 | .fileSetPermissions = fileSetPermissions, | 851 | .fileSetPermissions = fileSetPermissions, |
| 835 | .fileSetTimestamps = fileSetTimestamps, | 852 | .fileSetTimestamps = fileSetTimestamps, |
| 836 | .fileSetTimestampsNow = fileSetTimestampsNow, | | |
| 837 | .fileLock = fileLock, | 853 | .fileLock = fileLock, |
| 838 | .fileTryLock = fileTryLock, | 854 | .fileTryLock = fileTryLock, |
| 839 | .fileUnlock = fileUnlock, | 855 | .fileUnlock = fileUnlock, |
| ... | @@ -947,7 +963,6 @@ pub fn ioBasic(t: *Threaded) Io { | ... | @@ -947,7 +963,6 @@ pub fn ioBasic(t: *Threaded) Io { |
| 947 | .dirSetPermissions = dirSetPermissions, | 963 | .dirSetPermissions = dirSetPermissions, |
| 948 | .dirSetFilePermissions = dirSetFilePermissions, | 964 | .dirSetFilePermissions = dirSetFilePermissions, |
| 949 | .dirSetTimestamps = dirSetTimestamps, | 965 | .dirSetTimestamps = dirSetTimestamps, |
| 950 | .dirSetTimestampsNow = dirSetTimestampsNow, | | |
| 951 | .dirHardLink = dirHardLink, | 966 | .dirHardLink = dirHardLink, |
| 952 | | 967 | |
| 953 | .fileStat = fileStat, | 968 | .fileStat = fileStat, |
| ... | @@ -969,7 +984,6 @@ pub fn ioBasic(t: *Threaded) Io { | ... | @@ -969,7 +984,6 @@ pub fn ioBasic(t: *Threaded) Io { |
| 969 | .fileSetOwner = fileSetOwner, | 984 | .fileSetOwner = fileSetOwner, |
| 970 | .fileSetPermissions = fileSetPermissions, | 985 | .fileSetPermissions = fileSetPermissions, |
| 971 | .fileSetTimestamps = fileSetTimestamps, | 986 | .fileSetTimestamps = fileSetTimestamps, |
| 972 | .fileSetTimestampsNow = fileSetTimestampsNow, | | |
| 973 | .fileLock = fileLock, | 987 | .fileLock = fileLock, |
| 974 | .fileTryLock = fileTryLock, | 988 | .fileTryLock = fileTryLock, |
| 975 | .fileUnlock = fileUnlock, | 989 | .fileUnlock = fileUnlock, |
| ... | @@ -1920,7 +1934,7 @@ fn dirStatFileLinux( | ... | @@ -1920,7 +1934,7 @@ fn dirStatFileLinux( |
| 1920 | try current_thread.beginSyscall(); | 1934 | try current_thread.beginSyscall(); |
| 1921 | while (true) { | 1935 | while (true) { |
| 1922 | var statx = std.mem.zeroes(linux.Statx); | 1936 | var statx = std.mem.zeroes(linux.Statx); |
| 1923 | switch (sys.errno(sys.statx(dir.handle, sub_path_posix, flags, linux_statx_mask, &statx))) { | 1937 | switch (sys.errno(sys.statx(dir.handle, sub_path_posix, flags, linux_statx_request, &statx))) { |
| 1924 | .SUCCESS => { | 1938 | .SUCCESS => { |
| 1925 | current_thread.endSyscall(); | 1939 | current_thread.endSyscall(); |
| 1926 | return statFromLinux(&statx); | 1940 | return statFromLinux(&statx); |
| ... | @@ -2155,7 +2169,7 @@ fn fileStatLinux(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { | ... | @@ -2155,7 +2169,7 @@ fn fileStatLinux(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 2155 | try current_thread.beginSyscall(); | 2169 | try current_thread.beginSyscall(); |
| 2156 | while (true) { | 2170 | while (true) { |
| 2157 | var statx = std.mem.zeroes(linux.Statx); | 2171 | var statx = std.mem.zeroes(linux.Statx); |
| 2158 | switch (sys.errno(sys.statx(file.handle, "", linux.AT.EMPTY_PATH, linux_statx_mask, &statx))) { | 2172 | switch (sys.errno(sys.statx(file.handle, "", linux.AT.EMPTY_PATH, linux_statx_request, &statx))) { |
| 2159 | .SUCCESS => { | 2173 | .SUCCESS => { |
| 2160 | current_thread.endSyscall(); | 2174 | current_thread.endSyscall(); |
| 2161 | return statFromLinux(&statx); | 2175 | return statFromLinux(&statx); |
| ... | @@ -5977,8 +5991,6 @@ fn dirSetTimestamps( | ... | @@ -5977,8 +5991,6 @@ fn dirSetTimestamps( |
| 5977 | userdata: ?*anyopaque, | 5991 | userdata: ?*anyopaque, |
| 5978 | dir: Dir, | 5992 | dir: Dir, |
| 5979 | sub_path: []const u8, | 5993 | sub_path: []const u8, |
| 5980 | last_accessed: Io.Timestamp, | | |
| 5981 | last_modified: Io.Timestamp, | | |
| 5982 | options: Dir.SetTimestampsOptions, | 5994 | options: Dir.SetTimestampsOptions, |
| 5983 | ) Dir.SetTimestampsError!void { | 5995 | ) Dir.SetTimestampsError!void { |
| 5984 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 5996 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| ... | @@ -5992,9 +6004,13 @@ fn dirSetTimestamps( | ... | @@ -5992,9 +6004,13 @@ fn dirSetTimestamps( |
| 5992 | @panic("TODO implement dirSetTimestamps wasi"); | 6004 | @panic("TODO implement dirSetTimestamps wasi"); |
| 5993 | } | 6005 | } |
| 5994 | | 6006 | |
| 5995 | const times: [2]posix.timespec = .{ | 6007 | var times_buffer: [2]posix.timespec = undefined; |
| 5996 | timestampToPosix(last_accessed.nanoseconds), | 6008 | const times = if (options.modify_timestamp == .now and options.access_timestamp == .now) null else p: { |
| 5997 | timestampToPosix(last_modified.nanoseconds), | 6009 | times_buffer = .{ |
| | 6010 | setTimestampToPosix(options.access_timestamp), |
| | 6011 | setTimestampToPosix(options.modify_timestamp), |
| | 6012 | }; |
| | 6013 | break :p &times_buffer; |
| 5998 | }; | 6014 | }; |
| 5999 | | 6015 | |
| 6000 | const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0; | 6016 | const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0; |
| ... | @@ -6003,80 +6019,26 @@ fn dirSetTimestamps( | ... | @@ -6003,80 +6019,26 @@ fn dirSetTimestamps( |
| 6003 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); | 6019 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); |
| 6004 | | 6020 | |
| 6005 | try current_thread.beginSyscall(); | 6021 | try current_thread.beginSyscall(); |
| 6006 | while (true) { | 6022 | while (true) switch (posix.errno(posix.system.utimensat(dir.handle, sub_path_posix, times, flags))) { |
| 6007 | switch (posix.errno(posix.system.utimensat(dir.handle, sub_path_posix, &times, flags))) { | 6023 | .SUCCESS => return current_thread.endSyscall(), |
| 6008 | .SUCCESS => return current_thread.endSyscall(), | 6024 | .INTR => { |
| 6009 | .INTR => { | 6025 | try current_thread.checkCancel(); |
| 6010 | try current_thread.checkCancel(); | 6026 | continue; |
| 6011 | continue; | 6027 | }, |
| 6012 | }, | 6028 | .BADF => |err| return current_thread.endSyscallErrnoBug(err), // always a race condition |
| 6013 | else => |e| { | 6029 | .FAULT => |err| return current_thread.endSyscallErrnoBug(err), |
| 6014 | current_thread.endSyscall(); | 6030 | .INVAL => |err| return current_thread.endSyscallErrnoBug(err), |
| 6015 | switch (e) { | 6031 | .ACCES => return current_thread.endSyscallError(error.AccessDenied), |
| 6016 | .ACCES => return error.AccessDenied, | 6032 | .PERM => return current_thread.endSyscallError(error.PermissionDenied), |
| 6017 | .PERM => return error.PermissionDenied, | 6033 | .ROFS => return current_thread.endSyscallError(error.ReadOnlyFileSystem), |
| 6018 | .BADF => |err| return errnoBug(err), // always a race condition | 6034 | else => |err| return current_thread.endSyscallUnexpectedErrno(err), |
| 6019 | .FAULT => |err| return errnoBug(err), | 6035 | }; |
| 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 | } | | |
| 6073 | } | 6036 | } |
| 6074 | | 6037 | |
| 6075 | fn fileSetTimestamps( | 6038 | fn fileSetTimestamps( |
| 6076 | userdata: ?*anyopaque, | 6039 | userdata: ?*anyopaque, |
| 6077 | file: File, | 6040 | file: File, |
| 6078 | last_accessed: Io.Timestamp, | 6041 | options: File.SetTimestampsOptions, |
| 6079 | last_modified: Io.Timestamp, | | |
| 6080 | ) File.SetTimestampsError!void { | 6042 | ) File.SetTimestampsError!void { |
| 6081 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 6043 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 6082 | const current_thread = Thread.getCurrent(t); | 6044 | const current_thread = Thread.getCurrent(t); |
| ... | @@ -6084,11 +6046,34 @@ fn fileSetTimestamps( | ... | @@ -6084,11 +6046,34 @@ fn fileSetTimestamps( |
| 6084 | if (is_windows) { | 6046 | if (is_windows) { |
| 6085 | try current_thread.checkCancel(); | 6047 | try current_thread.checkCancel(); |
| 6086 | | 6048 | |
| 6087 | const atime_ft = windows.nanoSecondsToFileTime(last_accessed); | 6049 | var access_time_buffer: windows.FILETIME = undefined; |
| 6088 | const mtime_ft = windows.nanoSecondsToFileTime(last_modified); | 6050 | var modify_time_buffer: windows.FILETIME = undefined; |
| | 6051 | var system_time_buffer: windows.LARGE_INTEGER = undefined; |
| | 6052 | |
| | 6053 | if (options.access_timestamp == .now or options.modify_timestamp == .now) { |
| | 6054 | system_time_buffer = windows.ntdll.RtlGetSystemTimePrecise(); |
| | 6055 | } |
| | 6056 | |
| | 6057 | const access_ptr = switch (options.access_timestamp) { |
| | 6058 | .unchanged => null, |
| | 6059 | .now => @panic("TODO do SystemTimeToFileTime logic here"), |
| | 6060 | .new => |ts| p: { |
| | 6061 | access_time_buffer = windows.nanoSecondsToFileTime(ts); |
| | 6062 | break :p &access_time_buffer; |
| | 6063 | }, |
| | 6064 | }; |
| | 6065 | |
| | 6066 | const modify_ptr = switch (options.modify_timestamp) { |
| | 6067 | .unchanged => null, |
| | 6068 | .now => @panic("TODO do SystemTimeToFileTime logic here"), |
| | 6069 | .new => |ts| p: { |
| | 6070 | modify_time_buffer = windows.nanoSecondsToFileTime(ts); |
| | 6071 | break :p &modify_time_buffer; |
| | 6072 | }, |
| | 6073 | }; |
| 6089 | | 6074 | |
| 6090 | // https://github.com/ziglang/zig/issues/1840 | 6075 | // https://github.com/ziglang/zig/issues/1840 |
| 6091 | const rc = windows.kernel32.SetFileTime(file.handle, null, &atime_ft, &mtime_ft); | 6076 | const rc = windows.kernel32.SetFileTime(file.handle, null, access_ptr, modify_ptr); |
| 6092 | if (rc == 0) { | 6077 | if (rc == 0) { |
| 6093 | switch (windows.GetLastError()) { | 6078 | switch (windows.GetLastError()) { |
| 6094 | else => |err| return windows.unexpectedError(err), | 6079 | else => |err| return windows.unexpectedError(err), |
| ... | @@ -6097,123 +6082,70 @@ fn fileSetTimestamps( | ... | @@ -6097,123 +6082,70 @@ fn fileSetTimestamps( |
| 6097 | return; | 6082 | return; |
| 6098 | } | 6083 | } |
| 6099 | | 6084 | |
| 6100 | const times: [2]posix.timespec = .{ | | |
| 6101 | timestampToPosix(last_accessed.nanoseconds), | | |
| 6102 | timestampToPosix(last_modified.nanoseconds), | | |
| 6103 | }; | | |
| 6104 | | | |
| 6105 | if (native_os == .wasi and !builtin.link_libc) { | 6085 | if (native_os == .wasi and !builtin.link_libc) { |
| 6106 | const atim = times[0].toTimestamp(); | 6086 | var atime: std.os.wasi.timestamp_t = 0; |
| 6107 | const mtim = times[1].toTimestamp(); | 6087 | var mtime: std.os.wasi.timestamp_t = 0; |
| 6108 | try current_thread.beginSyscall(); | 6088 | var flags: std.os.wasi.fstflags_t = .{}; |
| 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 | | 6089 | |
| 6135 | try current_thread.beginSyscall(); | 6090 | switch (options.access_timestamp) { |
| 6136 | while (true) { | 6091 | .unchanged => {}, |
| 6137 | switch (posix.errno(posix.system.futimens(file.handle, &times))) { | 6092 | .now => flags.ATIM_NOW = true, |
| 6138 | .SUCCESS => return current_thread.endSyscall(), | 6093 | .new => |ts| { |
| 6139 | .INTR => { | 6094 | atime = timestampToPosix(ts.nanoseconds).toTimestamp(); |
| 6140 | try current_thread.checkCancel(); | 6095 | flags.ATIM = true; |
| 6141 | continue; | | |
| 6142 | }, | | |
| 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 | }, | 6096 | }, |
| 6155 | } | 6097 | } |
| 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"); | | |
| 6165 | } | | |
| 6166 | | 6098 | |
| 6167 | if (native_os == .wasi and !builtin.link_libc) { | 6099 | switch (options.modify_timestamp) { |
| 6168 | try current_thread.beginSyscall(); | 6100 | .unchanged => {}, |
| 6169 | while (true) { | 6101 | .now => flags.MTIM_NOW = true, |
| 6170 | switch (std.os.wasi.fd_filestat_set_times(file.handle, 0, 0, .{ | 6102 | .new => |ts| { |
| 6171 | .ATIM_NOW = true, | 6103 | mtime = timestampToPosix(ts.nanoseconds).toTimestamp(); |
| 6172 | .MTIM_NOW = true, | 6104 | flags.MTIM = true; |
| 6173 | })) { | 6105 | }, |
| 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 | } | 6106 | } |
| 6193 | } | | |
| 6194 | | 6107 | |
| 6195 | try current_thread.beginSyscall(); | 6108 | try current_thread.beginSyscall(); |
| 6196 | while (true) { | 6109 | while (true) switch (std.os.wasi.fd_filestat_set_times(file.handle, atime, mtime, flags)) { |
| 6197 | switch (posix.errno(posix.system.futimens(file.handle, null))) { | | |
| 6198 | .SUCCESS => return current_thread.endSyscall(), | 6110 | .SUCCESS => return current_thread.endSyscall(), |
| 6199 | .INTR => { | 6111 | .INTR => { |
| 6200 | try current_thread.checkCancel(); | 6112 | try current_thread.checkCancel(); |
| 6201 | continue; | 6113 | continue; |
| 6202 | }, | 6114 | }, |
| 6203 | else => |e| { | 6115 | .BADF => |err| return current_thread.endSyscallErrnoBug(err), // File descriptor use-after-free. |
| 6204 | current_thread.endSyscall(); | 6116 | .FAULT => |err| return current_thread.endSyscallErrnoBug(err), |
| 6205 | switch (e) { | 6117 | .INVAL => |err| return current_thread.endSyscallErrnoBug(err), |
| 6206 | .ACCES => return error.AccessDenied, | 6118 | .ACCES => return current_thread.endSyscallError(error.AccessDenied), |
| 6207 | .PERM => return error.PermissionDenied, | 6119 | .PERM => return current_thread.endSyscallError(error.PermissionDenied), |
| 6208 | .BADF => |err| return errnoBug(err), // always a race condition | 6120 | .ROFS => return current_thread.endSyscallError(error.ReadOnlyFileSystem), |
| 6209 | .FAULT => |err| return errnoBug(err), | 6121 | else => |err| return current_thread.endSyscallUnexpectedErrno(err), |
| 6210 | .INVAL => |err| return errnoBug(err), | 6122 | }; |
| 6211 | .ROFS => return error.ReadOnlyFileSystem, | | |
| 6212 | else => |err| return posix.unexpectedErrno(err), | | |
| 6213 | } | | |
| 6214 | }, | | |
| 6215 | } | | |
| 6216 | } | 6123 | } |
| | 6124 | |
| | 6125 | var times_buffer: [2]posix.timespec = undefined; |
| | 6126 | const times = if (options.modify_timestamp == .now and options.access_timestamp == .now) null else p: { |
| | 6127 | times_buffer = .{ |
| | 6128 | setTimestampToPosix(options.access_timestamp), |
| | 6129 | setTimestampToPosix(options.modify_timestamp), |
| | 6130 | }; |
| | 6131 | break :p &times_buffer; |
| | 6132 | }; |
| | 6133 | |
| | 6134 | try current_thread.beginSyscall(); |
| | 6135 | while (true) switch (posix.errno(posix.system.futimens(file.handle, times))) { |
| | 6136 | .SUCCESS => return current_thread.endSyscall(), |
| | 6137 | .INTR => { |
| | 6138 | try current_thread.checkCancel(); |
| | 6139 | continue; |
| | 6140 | }, |
| | 6141 | .BADF => |err| return current_thread.endSyscallErrnoBug(err), // always a race condition |
| | 6142 | .FAULT => |err| return current_thread.endSyscallErrnoBug(err), |
| | 6143 | .INVAL => |err| return current_thread.endSyscallErrnoBug(err), |
| | 6144 | .ACCES => return current_thread.endSyscallError(error.AccessDenied), |
| | 6145 | .PERM => return current_thread.endSyscallError(error.PermissionDenied), |
| | 6146 | .ROFS => return current_thread.endSyscallError(error.ReadOnlyFileSystem), |
| | 6147 | else => |err| return current_thread.endSyscallUnexpectedErrno(err), |
| | 6148 | }; |
| 6217 | } | 6149 | } |
| 6218 | | 6150 | |
| 6219 | const windows_lock_range_off: windows.LARGE_INTEGER = 0; | 6151 | const windows_lock_range_off: windows.LARGE_INTEGER = 0; |
| ... | @@ -11169,7 +11101,7 @@ fn clockToWasi(clock: Io.Clock) std.os.wasi.clockid_t { | ... | @@ -11169,7 +11101,7 @@ fn clockToWasi(clock: Io.Clock) std.os.wasi.clockid_t { |
| 11169 | }; | 11101 | }; |
| 11170 | } | 11102 | } |
| 11171 | | 11103 | |
| 11172 | const linux_statx_mask: std.os.linux.STATX = .{ | 11104 | const linux_statx_request: std.os.linux.STATX = .{ |
| 11173 | .TYPE = true, | 11105 | .TYPE = true, |
| 11174 | .MODE = true, | 11106 | .MODE = true, |
| 11175 | .ATIME = true, | 11107 | .ATIME = true, |
| ... | @@ -11180,14 +11112,22 @@ const linux_statx_mask: std.os.linux.STATX = .{ | ... | @@ -11180,14 +11112,22 @@ const linux_statx_mask: std.os.linux.STATX = .{ |
| 11180 | .NLINK = true, | 11112 | .NLINK = true, |
| 11181 | }; | 11113 | }; |
| 11182 | | 11114 | |
| | 11115 | const linux_statx_check: std.os.linux.STATX = .{ |
| | 11116 | .TYPE = true, |
| | 11117 | .MODE = true, |
| | 11118 | .ATIME = false, |
| | 11119 | .MTIME = true, |
| | 11120 | .CTIME = true, |
| | 11121 | .INO = true, |
| | 11122 | .SIZE = true, |
| | 11123 | .NLINK = true, |
| | 11124 | }; |
| | 11125 | |
| 11183 | fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat { | 11126 | fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat { |
| 11184 | const actual_mask_int: u32 = @bitCast(stx.mask); | 11127 | const actual_mask_int: u32 = @bitCast(stx.mask); |
| 11185 | const wanted_mask_int: u32 = @bitCast(linux_statx_mask); | 11128 | const wanted_mask_int: u32 = @bitCast(linux_statx_check); |
| 11186 | if ((actual_mask_int | wanted_mask_int) != actual_mask_int) return error.Unexpected; | 11129 | if ((actual_mask_int | wanted_mask_int) != actual_mask_int) return error.Unexpected; |
| 11187 | | 11130 | |
| 11188 | const atime = stx.atime; | | |
| 11189 | const mtime = stx.mtime; | | |
| 11190 | const ctime = stx.ctime; | | |
| 11191 | return .{ | 11131 | return .{ |
| 11192 | .inode = stx.ino, | 11132 | .inode = stx.ino, |
| 11193 | .nlink = stx.nlink, | 11133 | .nlink = stx.nlink, |
| ... | @@ -11203,9 +11143,11 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat { | ... | @@ -11203,9 +11143,11 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat { |
| 11203 | std.os.linux.S.IFSOCK => .unix_domain_socket, | 11143 | std.os.linux.S.IFSOCK => .unix_domain_socket, |
| 11204 | else => .unknown, | 11144 | else => .unknown, |
| 11205 | }, | 11145 | }, |
| 11206 | .atime = .{ .nanoseconds = @intCast(@as(i128, atime.sec) * std.time.ns_per_s + atime.nsec) }, | 11146 | .atime = if (!stx.mask.ATIME) null else .{ |
| 11207 | .mtime = .{ .nanoseconds = @intCast(@as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec) }, | 11147 | .nanoseconds = @intCast(@as(i128, stx.atime.sec) * std.time.ns_per_s + stx.atime.nsec), |
| 11208 | .ctime = .{ .nanoseconds = @intCast(@as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec) }, | 11148 | }, |
| | 11149 | .mtime = .{ .nanoseconds = @intCast(@as(i128, stx.mtime.sec) * std.time.ns_per_s + stx.mtime.nsec) }, |
| | 11150 | .ctime = .{ .nanoseconds = @intCast(@as(i128, stx.ctime.sec) * std.time.ns_per_s + stx.ctime.nsec) }, |
| 11209 | }; | 11151 | }; |
| 11210 | } | 11152 | } |
| 11211 | | 11153 | |
| ... | @@ -11283,6 +11225,14 @@ fn timestampToPosix(nanoseconds: i96) posix.timespec { | ... | @@ -11283,6 +11225,14 @@ fn timestampToPosix(nanoseconds: i96) posix.timespec { |
| 11283 | }; | 11225 | }; |
| 11284 | } | 11226 | } |
| 11285 | | 11227 | |
| | 11228 | fn setTimestampToPosix(set_ts: File.SetTimestamp) posix.timespec { |
| | 11229 | return switch (set_ts) { |
| | 11230 | .unchanged => .OMIT, |
| | 11231 | .now => .NOW, |
| | 11232 | .new => |t| timestampToPosix(t.nanoseconds), |
| | 11233 | }; |
| | 11234 | } |
| | 11235 | |
| 11286 | fn pathToPosix(file_path: []const u8, buffer: *[posix.PATH_MAX]u8) Dir.PathNameError![:0]u8 { | 11236 | fn pathToPosix(file_path: []const u8, buffer: *[posix.PATH_MAX]u8) Dir.PathNameError![:0]u8 { |
| 11287 | if (std.mem.containsAtLeastScalar2(u8, file_path, 0, 1)) return error.BadPathName; | 11237 | if (std.mem.containsAtLeastScalar2(u8, file_path, 0, 1)) return error.BadPathName; |
| 11288 | // >= rather than > to make room for the null byte | 11238 | // >= rather than > to make room for the null byte |