| ... | ... | @@ -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, |
| ... | ... | @@ -1920,7 +1934,7 @@ fn dirStatFileLinux( |
| 1920 | 1934 | try current_thread.beginSyscall(); |
| 1921 | 1935 | while (true) { |
| 1922 | 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 | 1938 | .SUCCESS => { |
| 1925 | 1939 | current_thread.endSyscall(); |
| 1926 | 1940 | return statFromLinux(&statx); |
| ... | ... | @@ -2155,7 +2169,7 @@ fn fileStatLinux(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 2155 | 2169 | try current_thread.beginSyscall(); |
| 2156 | 2170 | while (true) { |
| 2157 | 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 | 2173 | .SUCCESS => { |
| 2160 | 2174 | current_thread.endSyscall(); |
| 2161 | 2175 | return statFromLinux(&statx); |
| ... | ... | @@ -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,11 +6046,34 @@ 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 | var access_time_buffer: windows.FILETIME = undefined; |
| 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 | 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 | 6077 | if (rc == 0) { |
| 6093 | 6078 | switch (windows.GetLastError()) { |
| 6094 | 6079 | else => |err| return windows.unexpectedError(err), |
| ... | ... | @@ -6097,123 +6082,70 @@ fn fileSetTimestamps( |
| 6097 | 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 | 6085 | if (native_os == .wasi and !builtin.link_libc) { |
| 6106 | | const atim = times[0].toTimestamp(); |
| 6107 | | const mtim = times[1].toTimestamp(); |
| 6108 | | 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 | | } |
| 6086 | var atime: std.os.wasi.timestamp_t = 0; |
| 6087 | var mtime: std.os.wasi.timestamp_t = 0; |
| 6088 | var flags: std.os.wasi.fstflags_t = .{}; |
| 6134 | 6089 | |
| 6135 | | try current_thread.beginSyscall(); |
| 6136 | | while (true) { |
| 6137 | | switch (posix.errno(posix.system.futimens(file.handle, &times))) { |
| 6138 | | .SUCCESS => return current_thread.endSyscall(), |
| 6139 | | .INTR => { |
| 6140 | | try current_thread.checkCancel(); |
| 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 | | } |
| 6090 | switch (options.access_timestamp) { |
| 6091 | .unchanged => {}, |
| 6092 | .now => flags.ATIM_NOW = true, |
| 6093 | .new => |ts| { |
| 6094 | atime = timestampToPosix(ts.nanoseconds).toTimestamp(); |
| 6095 | flags.ATIM = true; |
| 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) { |
| 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 | | } |
| 6099 | switch (options.modify_timestamp) { |
| 6100 | .unchanged => {}, |
| 6101 | .now => flags.MTIM_NOW = true, |
| 6102 | .new => |ts| { |
| 6103 | mtime = timestampToPosix(ts.nanoseconds).toTimestamp(); |
| 6104 | flags.MTIM = true; |
| 6105 | }, |
| 6192 | 6106 | } |
| 6193 | | } |
| 6194 | 6107 | |
| 6195 | | try current_thread.beginSyscall(); |
| 6196 | | while (true) { |
| 6197 | | switch (posix.errno(posix.system.futimens(file.handle, null))) { |
| 6108 | try current_thread.beginSyscall(); |
| 6109 | while (true) switch (std.os.wasi.fd_filestat_set_times(file.handle, atime, mtime, flags)) { |
| 6198 | 6110 | .SUCCESS => return current_thread.endSyscall(), |
| 6199 | 6111 | .INTR => { |
| 6200 | 6112 | try current_thread.checkCancel(); |
| 6201 | 6113 | continue; |
| 6202 | 6114 | }, |
| 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 | | } |
| 6115 | .BADF => |err| return current_thread.endSyscallErrnoBug(err), // File descriptor use-after-free. |
| 6116 | .FAULT => |err| return current_thread.endSyscallErrnoBug(err), |
| 6117 | .INVAL => |err| return current_thread.endSyscallErrnoBug(err), |
| 6118 | .ACCES => return current_thread.endSyscallError(error.AccessDenied), |
| 6119 | .PERM => return current_thread.endSyscallError(error.PermissionDenied), |
| 6120 | .ROFS => return current_thread.endSyscallError(error.ReadOnlyFileSystem), |
| 6121 | else => |err| return current_thread.endSyscallUnexpectedErrno(err), |
| 6122 | }; |
| 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 | 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 | 11101 | }; |
| 11170 | 11102 | } |
| 11171 | 11103 | |
| 11172 | | const linux_statx_mask: std.os.linux.STATX = .{ |
| 11104 | const linux_statx_request: std.os.linux.STATX = .{ |
| 11173 | 11105 | .TYPE = true, |
| 11174 | 11106 | .MODE = true, |
| 11175 | 11107 | .ATIME = true, |
| ... | ... | @@ -11180,14 +11112,22 @@ const linux_statx_mask: std.os.linux.STATX = .{ |
| 11180 | 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 | 11126 | fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat { |
| 11184 | 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 | 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 | 11131 | return .{ |
| 11192 | 11132 | .inode = stx.ino, |
| 11193 | 11133 | .nlink = stx.nlink, |
| ... | ... | @@ -11203,9 +11143,11 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat { |
| 11203 | 11143 | std.os.linux.S.IFSOCK => .unix_domain_socket, |
| 11204 | 11144 | else => .unknown, |
| 11205 | 11145 | }, |
| 11206 | | .atime = .{ .nanoseconds = @intCast(@as(i128, atime.sec) * std.time.ns_per_s + atime.nsec) }, |
| 11207 | | .mtime = .{ .nanoseconds = @intCast(@as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec) }, |
| 11208 | | .ctime = .{ .nanoseconds = @intCast(@as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec) }, |
| 11146 | .atime = if (!stx.mask.ATIME) null else .{ |
| 11147 | .nanoseconds = @intCast(@as(i128, stx.atime.sec) * std.time.ns_per_s + stx.atime.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 | 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 | 11236 | fn pathToPosix(file_path: []const u8, buffer: *[posix.PATH_MAX]u8) Dir.PathNameError![:0]u8 { |
| 11287 | 11237 | if (std.mem.containsAtLeastScalar2(u8, file_path, 0, 1)) return error.BadPathName; |
| 11288 | 11238 | // >= rather than > to make room for the null byte |