| author | |
| committer | |
| log | 8a1e6c8c394058a25cb21f60ad414f28cd37db22 |
| tree | ef6a86087599855c24d5172eb7b225d515b4dccc |
| parent | 750b1431bf34b238bd991b2ee3b50e81ff20b667 |
14 files changed, 409 insertions(+), 294 deletions(-)
lib/std/Build/Cache.zig+9-9| ... | @@ -1305,7 +1305,7 @@ fn hashFile(file: fs.File, bin_digest: *[Hasher.mac_length]u8) fs.File.PReadErro | ... | @@ -1305,7 +1305,7 @@ fn hashFile(file: fs.File, bin_digest: *[Hasher.mac_length]u8) fs.File.PReadErro |
| 1305 | } | 1305 | } |
| 1306 | 1306 | ||
| 1307 | // Create/Write a file, close it, then grab its stat.mtime timestamp. | 1307 | // Create/Write a file, close it, then grab its stat.mtime timestamp. |
| 1308 | fn testGetCurrentFileTimestamp(dir: fs.Dir) !i128 { | 1308 | fn testGetCurrentFileTimestamp(dir: fs.Dir) !Io.Timestamp { |
| 1309 | const test_out_file = "test-filetimestamp.tmp"; | 1309 | const test_out_file = "test-filetimestamp.tmp"; |
| 1310 | 1310 | ||
| 1311 | var file = try dir.createFile(test_out_file, .{ | 1311 | var file = try dir.createFile(test_out_file, .{ |
| ... | @@ -1333,8 +1333,8 @@ test "cache file and then recall it" { | ... | @@ -1333,8 +1333,8 @@ test "cache file and then recall it" { |
| 1333 | 1333 | ||
| 1334 | // Wait for file timestamps to tick | 1334 | // Wait for file timestamps to tick |
| 1335 | const initial_time = try testGetCurrentFileTimestamp(tmp.dir); | 1335 | const initial_time = try testGetCurrentFileTimestamp(tmp.dir); |
| 1336 | while ((try testGetCurrentFileTimestamp(tmp.dir)) == initial_time) { | 1336 | while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time.nanoseconds) { |
| 1337 | try std.Io.Duration.sleep(.fromNanoseconds(1), io); | 1337 | try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io); |
| 1338 | } | 1338 | } |
| 1339 | 1339 | ||
| 1340 | var digest1: HexDigest = undefined; | 1340 | var digest1: HexDigest = undefined; |
| ... | @@ -1399,8 +1399,8 @@ test "check that changing a file makes cache fail" { | ... | @@ -1399,8 +1399,8 @@ test "check that changing a file makes cache fail" { |
| 1399 | 1399 | ||
| 1400 | // Wait for file timestamps to tick | 1400 | // Wait for file timestamps to tick |
| 1401 | const initial_time = try testGetCurrentFileTimestamp(tmp.dir); | 1401 | const initial_time = try testGetCurrentFileTimestamp(tmp.dir); |
| 1402 | while ((try testGetCurrentFileTimestamp(tmp.dir)) == initial_time) { | 1402 | while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time.nanoseconds) { |
| 1403 | try std.Io.Duration.sleep(.fromNanoseconds(1), io); | 1403 | try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io); |
| 1404 | } | 1404 | } |
| 1405 | 1405 | ||
| 1406 | var digest1: HexDigest = undefined; | 1406 | var digest1: HexDigest = undefined; |
| ... | @@ -1517,8 +1517,8 @@ test "Manifest with files added after initial hash work" { | ... | @@ -1517,8 +1517,8 @@ test "Manifest with files added after initial hash work" { |
| 1517 | 1517 | ||
| 1518 | // Wait for file timestamps to tick | 1518 | // Wait for file timestamps to tick |
| 1519 | const initial_time = try testGetCurrentFileTimestamp(tmp.dir); | 1519 | const initial_time = try testGetCurrentFileTimestamp(tmp.dir); |
| 1520 | while ((try testGetCurrentFileTimestamp(tmp.dir)) == initial_time) { | 1520 | while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time.nanoseconds) { |
| 1521 | try std.Io.Duration.sleep(.fromNanoseconds(1), io); | 1521 | try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io); |
| 1522 | } | 1522 | } |
| 1523 | 1523 | ||
| 1524 | var digest1: HexDigest = undefined; | 1524 | var digest1: HexDigest = undefined; |
| ... | @@ -1568,8 +1568,8 @@ test "Manifest with files added after initial hash work" { | ... | @@ -1568,8 +1568,8 @@ test "Manifest with files added after initial hash work" { |
| 1568 | 1568 | ||
| 1569 | // Wait for file timestamps to tick | 1569 | // Wait for file timestamps to tick |
| 1570 | const initial_time2 = try testGetCurrentFileTimestamp(tmp.dir); | 1570 | const initial_time2 = try testGetCurrentFileTimestamp(tmp.dir); |
| 1571 | while ((try testGetCurrentFileTimestamp(tmp.dir)) == initial_time2) { | 1571 | while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time2.nanoseconds) { |
| 1572 | try std.Io.Duration.sleep(.fromNanoseconds(1), io); | 1572 | try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io); |
| 1573 | } | 1573 | } |
| 1574 | 1574 | ||
| 1575 | { | 1575 | { |
lib/std/Io.zig+23-11| ... | @@ -654,20 +654,20 @@ pub const VTable = struct { | ... | @@ -654,20 +654,20 @@ pub const VTable = struct { |
| 654 | conditionWait: *const fn (?*anyopaque, cond: *Condition, mutex: *Mutex) Cancelable!void, | 654 | conditionWait: *const fn (?*anyopaque, cond: *Condition, mutex: *Mutex) Cancelable!void, |
| 655 | conditionWake: *const fn (?*anyopaque, cond: *Condition, wake: Condition.Wake) void, | 655 | conditionWake: *const fn (?*anyopaque, cond: *Condition, wake: Condition.Wake) void, |
| 656 | 656 | ||
| 657 | dirMake: *const fn (?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void, | 657 | dirMake: *const fn (?*anyopaque, Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void, |
| 658 | dirStat: *const fn (?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat, | 658 | dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat, |
| 659 | dirStatPath: *const fn (?*anyopaque, dir: Dir, sub_path: []const u8) Dir.StatError!File.Stat, | 659 | dirStatPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat, |
| 660 | fileStat: *const fn (?*anyopaque, file: File) File.StatError!File.Stat, | 660 | fileStat: *const fn (?*anyopaque, File) File.StatError!File.Stat, |
| 661 | createFile: *const fn (?*anyopaque, dir: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File, | 661 | createFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.CreateFlags) File.OpenError!File, |
| 662 | fileOpen: *const fn (?*anyopaque, dir: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File, | 662 | fileOpen: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.OpenFlags) File.OpenError!File, |
| 663 | fileClose: *const fn (?*anyopaque, File) void, | 663 | fileClose: *const fn (?*anyopaque, File) void, |
| 664 | pwrite: *const fn (?*anyopaque, file: File, buffer: []const u8, offset: std.posix.off_t) File.PWriteError!usize, | 664 | pwrite: *const fn (?*anyopaque, File, buffer: []const u8, offset: std.posix.off_t) File.PWriteError!usize, |
| 665 | /// Returns 0 on end of stream. | 665 | /// Returns 0 on end of stream. |
| 666 | fileReadStreaming: *const fn (?*anyopaque, file: File, data: [][]u8) File.ReadStreamingError!usize, | 666 | fileReadStreaming: *const fn (?*anyopaque, File, data: [][]u8) File.ReadStreamingError!usize, |
| 667 | /// Returns 0 on end of stream. | 667 | /// Returns 0 on end of stream. |
| 668 | fileReadPositional: *const fn (?*anyopaque, file: File, data: [][]u8, offset: u64) File.ReadPositionalError!usize, | 668 | fileReadPositional: *const fn (?*anyopaque, File, data: [][]u8, offset: u64) File.ReadPositionalError!usize, |
| 669 | fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void, | 669 | fileSeekBy: *const fn (?*anyopaque, File, offset: i64) File.SeekError!void, |
| 670 | fileSeekTo: *const fn (?*anyopaque, file: File, offset: u64) File.SeekError!void, | 670 | fileSeekTo: *const fn (?*anyopaque, File, offset: u64) File.SeekError!void, |
| 671 | 671 | ||
| 672 | now: *const fn (?*anyopaque, Clock) Clock.Error!Timestamp, | 672 | now: *const fn (?*anyopaque, Clock) Clock.Error!Timestamp, |
| 673 | sleep: *const fn (?*anyopaque, Timeout) SleepError!void, | 673 | sleep: *const fn (?*anyopaque, Timeout) SleepError!void, |
| ... | @@ -795,6 +795,14 @@ pub const Clock = enum { | ... | @@ -795,6 +795,14 @@ pub const Clock = enum { |
| 795 | }; | 795 | }; |
| 796 | } | 796 | } |
| 797 | 797 | ||
| 798 | pub fn subDuration(from: Clock.Timestamp, duration: Clock.Duration) Clock.Timestamp { | ||
| 799 | assert(from.clock == duration.clock); | ||
| 800 | return .{ | ||
| 801 | .raw = from.raw.subDuration(duration.raw), | ||
| 802 | .clock = from.clock, | ||
| 803 | }; | ||
| 804 | } | ||
| 805 | |||
| 798 | pub fn fromNow(io: Io, duration: Clock.Duration) Error!Clock.Timestamp { | 806 | pub fn fromNow(io: Io, duration: Clock.Duration) Error!Clock.Timestamp { |
| 799 | return .{ | 807 | return .{ |
| 800 | .clock = duration.clock, | 808 | .clock = duration.clock, |
| ... | @@ -855,6 +863,10 @@ pub const Timestamp = struct { | ... | @@ -855,6 +863,10 @@ pub const Timestamp = struct { |
| 855 | return .{ .nanoseconds = from.nanoseconds + duration.nanoseconds }; | 863 | return .{ .nanoseconds = from.nanoseconds + duration.nanoseconds }; |
| 856 | } | 864 | } |
| 857 | 865 | ||
| 866 | pub fn subDuration(from: Timestamp, duration: Duration) Timestamp { | ||
| 867 | return .{ .nanoseconds = from.nanoseconds - duration.nanoseconds }; | ||
| 868 | } | ||
| 869 | |||
| 858 | pub fn withClock(t: Timestamp, clock: Clock) Clock.Timestamp { | 870 | pub fn withClock(t: Timestamp, clock: Clock) Clock.Timestamp { |
| 859 | return .{ .nanoseconds = t.nanoseconds, .clock = clock }; | 871 | return .{ .nanoseconds = t.nanoseconds, .clock = clock }; |
| 860 | } | 872 | } |
lib/std/Io/Dir.zig+31-11| ... | @@ -15,6 +15,29 @@ pub fn cwd() Dir { | ... | @@ -15,6 +15,29 @@ pub fn cwd() Dir { |
| 15 | 15 | ||
| 16 | pub const Handle = std.posix.fd_t; | 16 | pub const Handle = std.posix.fd_t; |
| 17 | 17 | ||
| 18 | pub const PathNameError = error{ | ||
| 19 | NameTooLong, | ||
| 20 | /// File system cannot encode the requested file name bytes. | ||
| 21 | /// Could be due to invalid WTF-8 on Windows, invalid UTF-8 on WASI, | ||
| 22 | /// invalid characters on Windows, etc. Filesystem and operating specific. | ||
| 23 | BadPathName, | ||
| 24 | }; | ||
| 25 | |||
| 26 | pub const OpenError = error{ | ||
| 27 | FileNotFound, | ||
| 28 | NotDir, | ||
| 29 | AccessDenied, | ||
| 30 | PermissionDenied, | ||
| 31 | SymLinkLoop, | ||
| 32 | ProcessFdQuotaExceeded, | ||
| 33 | SystemFdQuotaExceeded, | ||
| 34 | NoDevice, | ||
| 35 | SystemResources, | ||
| 36 | DeviceBusy, | ||
| 37 | /// On Windows, `\\server` or `\\server\share` was not found. | ||
| 38 | NetworkNotFound, | ||
| 39 | } || PathNameError || Io.Cancelable || Io.UnexpectedError; | ||
| 40 | |||
| 18 | pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | 41 | pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { |
| 19 | return io.vtable.fileOpen(io.userdata, dir, sub_path, flags); | 42 | return io.vtable.fileOpen(io.userdata, dir, sub_path, flags); |
| 20 | } | 43 | } |
| ... | @@ -149,22 +172,15 @@ pub const MakeError = error{ | ... | @@ -149,22 +172,15 @@ pub const MakeError = error{ |
| 149 | PathAlreadyExists, | 172 | PathAlreadyExists, |
| 150 | SymLinkLoop, | 173 | SymLinkLoop, |
| 151 | LinkQuotaExceeded, | 174 | LinkQuotaExceeded, |
| 152 | NameTooLong, | ||
| 153 | FileNotFound, | 175 | FileNotFound, |
| 154 | SystemResources, | 176 | SystemResources, |
| 155 | NoSpaceLeft, | 177 | NoSpaceLeft, |
| 156 | NotDir, | 178 | NotDir, |
| 157 | ReadOnlyFileSystem, | 179 | ReadOnlyFileSystem, |
| 158 | /// Windows-only; file paths provided by the user must be valid WTF-8. | ||
| 159 | /// https://simonsapin.github.io/wtf-8/ | ||
| 160 | InvalidWtf8, | ||
| 161 | BadPathName, | ||
| 162 | NoDevice, | 180 | NoDevice, |
| 163 | /// On Windows, `\\server` or `\\server\share` was not found. | 181 | /// On Windows, `\\server` or `\\server\share` was not found. |
| 164 | NetworkNotFound, | 182 | NetworkNotFound, |
| 165 | /// File system cannot encode the requested file name bytes. | 183 | } || PathNameError || Io.Cancelable || Io.UnexpectedError; |
| 166 | InvalidFileName, | ||
| 167 | } || Io.Cancelable || Io.UnexpectedError; | ||
| 168 | 184 | ||
| 169 | /// Creates a single directory with a relative or absolute path. | 185 | /// Creates a single directory with a relative or absolute path. |
| 170 | /// | 186 | /// |
| ... | @@ -225,7 +241,7 @@ pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8) MakePathError!Make | ... | @@ -225,7 +241,7 @@ pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8) MakePathError!Make |
| 225 | // could cause an infinite loop | 241 | // could cause an infinite loop |
| 226 | check_dir: { | 242 | check_dir: { |
| 227 | // workaround for windows, see https://github.com/ziglang/zig/issues/16738 | 243 | // workaround for windows, see https://github.com/ziglang/zig/issues/16738 |
| 228 | const fstat = statPath(dir, io, component.path) catch |stat_err| switch (stat_err) { | 244 | const fstat = statPath(dir, io, component.path, .{}) catch |stat_err| switch (stat_err) { |
| 229 | error.IsDir => break :check_dir, | 245 | error.IsDir => break :check_dir, |
| 230 | else => |e| return e, | 246 | else => |e| return e, |
| 231 | }; | 247 | }; |
| ... | @@ -251,6 +267,10 @@ pub fn stat(dir: Dir, io: Io) StatError!Stat { | ... | @@ -251,6 +267,10 @@ pub fn stat(dir: Dir, io: Io) StatError!Stat { |
| 251 | 267 | ||
| 252 | pub const StatPathError = File.OpenError || File.StatError; | 268 | pub const StatPathError = File.OpenError || File.StatError; |
| 253 | 269 | ||
| 270 | pub const StatPathOptions = struct { | ||
| 271 | follow_symlinks: bool = true, | ||
| 272 | }; | ||
| 273 | |||
| 254 | /// Returns metadata for a file inside the directory. | 274 | /// Returns metadata for a file inside the directory. |
| 255 | /// | 275 | /// |
| 256 | /// On Windows, this requires three syscalls. On other operating systems, it | 276 | /// On Windows, this requires three syscalls. On other operating systems, it |
| ... | @@ -263,6 +283,6 @@ pub const StatPathError = File.OpenError || File.StatError; | ... | @@ -263,6 +283,6 @@ pub const StatPathError = File.OpenError || File.StatError; |
| 263 | /// * On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | 283 | /// * On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). |
| 264 | /// * On WASI, `sub_path` should be encoded as valid UTF-8. | 284 | /// * On WASI, `sub_path` should be encoded as valid UTF-8. |
| 265 | /// * On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding. | 285 | /// * On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding. |
| 266 | pub fn statPath(dir: Dir, io: Io, sub_path: []const u8) StatPathError!Stat { | 286 | pub fn statPath(dir: Dir, io: Io, sub_path: []const u8, options: StatPathOptions) StatPathError!Stat { |
| 267 | return io.vtable.dirStatPath(io.userdata, dir, sub_path); | 287 | return io.vtable.dirStatPath(io.userdata, dir, sub_path, options); |
| 268 | } | 288 | } |
lib/std/Io/File.zig+57-1| ... | @@ -81,7 +81,63 @@ pub fn stat(file: File, io: Io) StatError!Stat { | ... | @@ -81,7 +81,63 @@ pub fn stat(file: File, io: Io) StatError!Stat { |
| 81 | pub const OpenFlags = std.fs.File.OpenFlags; | 81 | pub const OpenFlags = std.fs.File.OpenFlags; |
| 82 | pub const CreateFlags = std.fs.File.CreateFlags; | 82 | pub const CreateFlags = std.fs.File.CreateFlags; |
| 83 | 83 | ||
| 84 | pub const OpenError = std.fs.File.OpenError || Io.Cancelable; | 84 | pub const OpenError = error{ |
| 85 | SharingViolation, | ||
| 86 | PipeBusy, | ||
| 87 | NoDevice, | ||
| 88 | /// On Windows, `\\server` or `\\server\share` was not found. | ||
| 89 | NetworkNotFound, | ||
| 90 | ProcessNotFound, | ||
| 91 | /// On Windows, antivirus software is enabled by default. It can be | ||
| 92 | /// disabled, but Windows Update sometimes ignores the user's preference | ||
| 93 | /// and re-enables it. When enabled, antivirus software on Windows | ||
| 94 | /// intercepts file system operations and makes them significantly slower | ||
| 95 | /// in addition to possibly failing with this error code. | ||
| 96 | AntivirusInterference, | ||
| 97 | /// In WASI, this error may occur when the file descriptor does | ||
| 98 | /// not hold the required rights to open a new resource relative to it. | ||
| 99 | AccessDenied, | ||
| 100 | PermissionDenied, | ||
| 101 | SymLinkLoop, | ||
| 102 | ProcessFdQuotaExceeded, | ||
| 103 | SystemFdQuotaExceeded, | ||
| 104 | /// Either: | ||
| 105 | /// * One of the path components does not exist. | ||
| 106 | /// * Cwd was used, but cwd has been deleted. | ||
| 107 | /// * The path associated with the open directory handle has been deleted. | ||
| 108 | /// * On macOS, multiple processes or threads raced to create the same file | ||
| 109 | /// with `O.EXCL` set to `false`. | ||
| 110 | FileNotFound, | ||
| 111 | /// The path exceeded `max_path_bytes` bytes. | ||
| 112 | /// Insufficient kernel memory was available, or | ||
| 113 | /// the named file is a FIFO and per-user hard limit on | ||
| 114 | /// memory allocation for pipes has been reached. | ||
| 115 | SystemResources, | ||
| 116 | /// The file is too large to be opened. This error is unreachable | ||
| 117 | /// for 64-bit targets, as well as when opening directories. | ||
| 118 | FileTooBig, | ||
| 119 | /// The path refers to directory but the `DIRECTORY` flag was not provided. | ||
| 120 | IsDir, | ||
| 121 | /// A new path cannot be created because the device has no room for the new file. | ||
| 122 | /// This error is only reachable when the `CREAT` flag is provided. | ||
| 123 | NoSpaceLeft, | ||
| 124 | /// A component used as a directory in the path was not, in fact, a directory, or | ||
| 125 | /// `DIRECTORY` was specified and the path was not a directory. | ||
| 126 | NotDir, | ||
| 127 | /// The path already exists and the `CREAT` and `EXCL` flags were provided. | ||
| 128 | PathAlreadyExists, | ||
| 129 | DeviceBusy, | ||
| 130 | FileLocksNotSupported, | ||
| 131 | /// One of these three things: | ||
| 132 | /// * pathname refers to an executable image which is currently being | ||
| 133 | /// executed and write access was requested. | ||
| 134 | /// * pathname refers to a file that is currently in use as a swap | ||
| 135 | /// file, and the O_TRUNC flag was specified. | ||
| 136 | /// * pathname refers to a file that is currently being read by the | ||
| 137 | /// kernel (e.g., for module/firmware loading), and write access was | ||
| 138 | /// requested. | ||
| 139 | FileBusy, | ||
| 140 | } || Io.Dir.PathNameError || Io.Cancelable || Io.UnexpectedError; | ||
| 85 | 141 | ||
| 86 | pub fn close(file: File, io: Io) void { | 142 | pub fn close(file: File, io: Io) void { |
| 87 | return io.vtable.fileClose(io.userdata, file); | 143 | return io.vtable.fileClose(io.userdata, file); |
lib/std/Io/Threaded.zig+206-16| ... | @@ -166,14 +166,23 @@ pub fn io(pool: *Pool) Io { | ... | @@ -166,14 +166,23 @@ pub fn io(pool: *Pool) Io { |
| 166 | else => dirMakePosix, | 166 | else => dirMakePosix, |
| 167 | }, | 167 | }, |
| 168 | .dirStat = dirStat, | 168 | .dirStat = dirStat, |
| 169 | .dirStatPath = dirStatPath, | 169 | .dirStatPath = switch (builtin.os.tag) { |
| 170 | .linux => dirStatPathLinux, | ||
| 171 | .windows => @panic("TODO"), | ||
| 172 | .wasi => @panic("TODO"), | ||
| 173 | else => dirStatPathPosix, | ||
| 174 | }, | ||
| 170 | .fileStat = switch (builtin.os.tag) { | 175 | .fileStat = switch (builtin.os.tag) { |
| 171 | .linux => fileStatLinux, | 176 | .linux => fileStatLinux, |
| 172 | .windows => fileStatWindows, | 177 | .windows => fileStatWindows, |
| 173 | .wasi => fileStatWasi, | 178 | .wasi => fileStatWasi, |
| 174 | else => fileStatPosix, | 179 | else => fileStatPosix, |
| 175 | }, | 180 | }, |
| 176 | .createFile = createFile, | 181 | .createFile = switch (builtin.os.tag) { |
| 182 | .windows => @panic("TODO"), | ||
| 183 | .wasi => @panic("TODO"), | ||
| 184 | else => createFilePosix, | ||
| 185 | }, | ||
| 177 | .fileOpen = fileOpen, | 186 | .fileOpen = fileOpen, |
| 178 | .fileClose = fileClose, | 187 | .fileClose = fileClose, |
| 179 | .pwrite = pwrite, | 188 | .pwrite = pwrite, |
| ... | @@ -765,8 +774,10 @@ fn conditionWake(userdata: ?*anyopaque, cond: *Io.Condition, wake: Io.Condition. | ... | @@ -765,8 +774,10 @@ fn conditionWake(userdata: ?*anyopaque, cond: *Io.Condition, wake: Io.Condition. |
| 765 | 774 | ||
| 766 | fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void { | 775 | fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void { |
| 767 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 776 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 777 | |||
| 768 | var path_buffer: [posix.PATH_MAX]u8 = undefined; | 778 | var path_buffer: [posix.PATH_MAX]u8 = undefined; |
| 769 | const sub_path_posix = try toPosixPath(sub_path, &path_buffer); | 779 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); |
| 780 | |||
| 770 | while (true) { | 781 | while (true) { |
| 771 | try pool.checkCancel(); | 782 | try pool.checkCancel(); |
| 772 | switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, mode))) { | 783 | switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, mode))) { |
| ... | @@ -788,7 +799,7 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: | ... | @@ -788,7 +799,7 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: |
| 788 | .ROFS => return error.ReadOnlyFileSystem, | 799 | .ROFS => return error.ReadOnlyFileSystem, |
| 789 | // dragonfly: when dir_fd is unlinked from filesystem | 800 | // dragonfly: when dir_fd is unlinked from filesystem |
| 790 | .NOTCONN => return error.FileNotFound, | 801 | .NOTCONN => return error.FileNotFound, |
| 791 | .ILSEQ => return error.InvalidFileName, | 802 | .ILSEQ => return error.BadPathName, |
| 792 | else => |err| return posix.unexpectedErrno(err), | 803 | else => |err| return posix.unexpectedErrno(err), |
| 793 | } | 804 | } |
| 794 | } | 805 | } |
| ... | @@ -802,13 +813,82 @@ fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat { | ... | @@ -802,13 +813,82 @@ fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat { |
| 802 | @panic("TODO"); | 813 | @panic("TODO"); |
| 803 | } | 814 | } |
| 804 | 815 | ||
| 805 | fn dirStatPath(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8) Io.Dir.StatError!Io.File.Stat { | 816 | fn dirStatPathLinux( |
| 817 | userdata: ?*anyopaque, | ||
| 818 | dir: Io.Dir, | ||
| 819 | sub_path: []const u8, | ||
| 820 | options: Io.Dir.StatPathOptions, | ||
| 821 | ) Io.Dir.StatPathError!Io.File.Stat { | ||
| 806 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 822 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 807 | try pool.checkCancel(); | 823 | const linux = std.os.linux; |
| 808 | 824 | ||
| 809 | _ = dir; | 825 | var path_buffer: [posix.PATH_MAX]u8 = undefined; |
| 810 | _ = sub_path; | 826 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); |
| 811 | @panic("TODO"); | 827 | |
| 828 | const flags: u32 = linux.AT.NO_AUTOMOUNT | | ||
| 829 | @as(u32, if (!options.follow_symlinks) linux.AT.SYMLINK_NOFOLLOW else 0); | ||
| 830 | |||
| 831 | while (true) { | ||
| 832 | try pool.checkCancel(); | ||
| 833 | var statx = std.mem.zeroes(linux.Statx); | ||
| 834 | const rc = linux.statx( | ||
| 835 | dir.handle, | ||
| 836 | sub_path_posix, | ||
| 837 | flags, | ||
| 838 | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME, | ||
| 839 | &statx, | ||
| 840 | ); | ||
| 841 | switch (linux.E.init(rc)) { | ||
| 842 | .SUCCESS => return statFromLinux(&statx), | ||
| 843 | .INTR => continue, | ||
| 844 | .ACCES => return error.AccessDenied, | ||
| 845 | .BADF => |err| return errnoBug(err), | ||
| 846 | .FAULT => |err| return errnoBug(err), | ||
| 847 | .INVAL => |err| return errnoBug(err), | ||
| 848 | .LOOP => return error.SymLinkLoop, | ||
| 849 | .NAMETOOLONG => |err| return errnoBug(err), // Handled by pathToPosix() above. | ||
| 850 | .NOENT => return error.FileNotFound, | ||
| 851 | .NOTDIR => return error.NotDir, | ||
| 852 | .NOMEM => return error.SystemResources, | ||
| 853 | else => |err| return posix.unexpectedErrno(err), | ||
| 854 | } | ||
| 855 | } | ||
| 856 | } | ||
| 857 | |||
| 858 | fn dirStatPathPosix( | ||
| 859 | userdata: ?*anyopaque, | ||
| 860 | dir: Io.Dir, | ||
| 861 | sub_path: []const u8, | ||
| 862 | options: Io.Dir.StatPathOptions, | ||
| 863 | ) Io.Dir.StatPathError!Io.File.Stat { | ||
| 864 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | ||
| 865 | |||
| 866 | var path_buffer: [posix.PATH_MAX]u8 = undefined; | ||
| 867 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); | ||
| 868 | |||
| 869 | const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0; | ||
| 870 | const fstatat_sym = if (posix.lfs64_abi) posix.system.fstatat64 else posix.system.fstatat; | ||
| 871 | |||
| 872 | while (true) { | ||
| 873 | try pool.checkCancel(); | ||
| 874 | var stat = std.mem.zeroes(posix.Stat); | ||
| 875 | switch (posix.errno(fstatat_sym(dir.handle, sub_path_posix, &stat, flags))) { | ||
| 876 | .SUCCESS => return statFromPosix(stat), | ||
| 877 | .INTR => continue, | ||
| 878 | .INVAL => |err| return errnoBug(err), | ||
| 879 | .BADF => |err| return errnoBug(err), // Always a race condition. | ||
| 880 | .NOMEM => return error.SystemResources, | ||
| 881 | .ACCES => return error.AccessDenied, | ||
| 882 | .PERM => return error.PermissionDenied, | ||
| 883 | .FAULT => |err| return errnoBug(err), | ||
| 884 | .NAMETOOLONG => return error.NameTooLong, | ||
| 885 | .LOOP => return error.SymLinkLoop, | ||
| 886 | .NOENT => return error.FileNotFound, | ||
| 887 | .NOTDIR => return error.FileNotFound, | ||
| 888 | .ILSEQ => return error.BadPathName, | ||
| 889 | else => |err| return posix.unexpectedErrno(err), | ||
| 890 | } | ||
| 891 | } | ||
| 812 | } | 892 | } |
| 813 | 893 | ||
| 814 | fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat { | 894 | fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat { |
| ... | @@ -885,17 +965,127 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File. | ... | @@ -885,17 +965,127 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File. |
| 885 | } | 965 | } |
| 886 | } | 966 | } |
| 887 | 967 | ||
| 888 | fn createFile( | 968 | const have_flock = @TypeOf(posix.system.flock) != void; |
| 969 | |||
| 970 | fn createFilePosix( | ||
| 889 | userdata: ?*anyopaque, | 971 | userdata: ?*anyopaque, |
| 890 | dir: Io.Dir, | 972 | dir: Io.Dir, |
| 891 | sub_path: []const u8, | 973 | sub_path: []const u8, |
| 892 | flags: Io.File.CreateFlags, | 974 | flags: Io.File.CreateFlags, |
| 893 | ) Io.File.OpenError!Io.File { | 975 | ) Io.File.OpenError!Io.File { |
| 894 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 976 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 895 | try pool.checkCancel(); | 977 | |
| 896 | const fs_dir: std.fs.Dir = .{ .fd = dir.handle }; | 978 | var path_buffer: [posix.PATH_MAX]u8 = undefined; |
| 897 | const fs_file = try fs_dir.createFile(sub_path, flags); | 979 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); |
| 898 | return .{ .handle = fs_file.handle }; | 980 | |
| 981 | var os_flags: posix.O = .{ | ||
| 982 | .ACCMODE = if (flags.read) .RDWR else .WRONLY, | ||
| 983 | .CREAT = true, | ||
| 984 | .TRUNC = flags.truncate, | ||
| 985 | .EXCL = flags.exclusive, | ||
| 986 | }; | ||
| 987 | if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true; | ||
| 988 | if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true; | ||
| 989 | |||
| 990 | // Use the O locking flags if the os supports them to acquire the lock | ||
| 991 | // atomically. Note that the NONBLOCK flag is removed after the openat() | ||
| 992 | // call is successful. | ||
| 993 | const has_flock_open_flags = @hasField(posix.O, "EXLOCK"); | ||
| 994 | if (has_flock_open_flags) switch (flags.lock) { | ||
| 995 | .none => {}, | ||
| 996 | .shared => { | ||
| 997 | os_flags.SHLOCK = true; | ||
| 998 | os_flags.NONBLOCK = flags.lock_nonblocking; | ||
| 999 | }, | ||
| 1000 | .exclusive => { | ||
| 1001 | os_flags.EXLOCK = true; | ||
| 1002 | os_flags.NONBLOCK = flags.lock_nonblocking; | ||
| 1003 | }, | ||
| 1004 | }; | ||
| 1005 | |||
| 1006 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; | ||
| 1007 | |||
| 1008 | const fd: posix.fd_t = while (true) { | ||
| 1009 | try pool.checkCancel(); | ||
| 1010 | const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode); | ||
| 1011 | switch (posix.errno(rc)) { | ||
| 1012 | .SUCCESS => break @intCast(rc), | ||
| 1013 | .INTR => continue, | ||
| 1014 | |||
| 1015 | .FAULT => |err| return errnoBug(err), | ||
| 1016 | .INVAL => return error.BadPathName, | ||
| 1017 | .BADF => |err| return errnoBug(err), | ||
| 1018 | .ACCES => return error.AccessDenied, | ||
| 1019 | .FBIG => return error.FileTooBig, | ||
| 1020 | .OVERFLOW => return error.FileTooBig, | ||
| 1021 | .ISDIR => return error.IsDir, | ||
| 1022 | .LOOP => return error.SymLinkLoop, | ||
| 1023 | .MFILE => return error.ProcessFdQuotaExceeded, | ||
| 1024 | .NAMETOOLONG => return error.NameTooLong, | ||
| 1025 | .NFILE => return error.SystemFdQuotaExceeded, | ||
| 1026 | .NODEV => return error.NoDevice, | ||
| 1027 | .NOENT => return error.FileNotFound, | ||
| 1028 | .SRCH => return error.ProcessNotFound, | ||
| 1029 | .NOMEM => return error.SystemResources, | ||
| 1030 | .NOSPC => return error.NoSpaceLeft, | ||
| 1031 | .NOTDIR => return error.NotDir, | ||
| 1032 | .PERM => return error.PermissionDenied, | ||
| 1033 | .EXIST => return error.PathAlreadyExists, | ||
| 1034 | .BUSY => return error.DeviceBusy, | ||
| 1035 | .OPNOTSUPP => return error.FileLocksNotSupported, | ||
| 1036 | //.AGAIN => return error.WouldBlock, | ||
| 1037 | .TXTBSY => return error.FileBusy, | ||
| 1038 | .NXIO => return error.NoDevice, | ||
| 1039 | .ILSEQ => return error.BadPathName, | ||
| 1040 | else => |err| return posix.unexpectedErrno(err), | ||
| 1041 | } | ||
| 1042 | }; | ||
| 1043 | errdefer posix.close(fd); | ||
| 1044 | |||
| 1045 | if (have_flock and !has_flock_open_flags and flags.lock != .none) { | ||
| 1046 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; | ||
| 1047 | const lock_flags = switch (flags.lock) { | ||
| 1048 | .none => unreachable, | ||
| 1049 | .shared => posix.LOCK.SH | lock_nonblocking, | ||
| 1050 | .exclusive => posix.LOCK.EX | lock_nonblocking, | ||
| 1051 | }; | ||
| 1052 | while (true) { | ||
| 1053 | try pool.checkCancel(); | ||
| 1054 | switch (posix.errno(posix.system.flock(fd, lock_flags))) { | ||
| 1055 | .SUCCESS => break, | ||
| 1056 | .INTR => continue, | ||
| 1057 | |||
| 1058 | .BADF => |err| return errnoBug(err), | ||
| 1059 | .INVAL => |err| return errnoBug(err), // invalid parameters | ||
| 1060 | .NOLCK => return error.SystemResources, | ||
| 1061 | //.AGAIN => return error.WouldBlock, | ||
| 1062 | .OPNOTSUPP => return error.FileLocksNotSupported, | ||
| 1063 | else => |err| return posix.unexpectedErrno(err), | ||
| 1064 | } | ||
| 1065 | } | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | if (has_flock_open_flags and flags.lock_nonblocking) { | ||
| 1069 | var fl_flags: usize = while (true) { | ||
| 1070 | try pool.checkCancel(); | ||
| 1071 | switch (posix.errno(posix.system.fcntl(fd, posix.F.GETFL, 0))) { | ||
| 1072 | .SUCCESS => break, | ||
| 1073 | .INTR => continue, | ||
| 1074 | else => |err| return posix.unexpectedErrno(err), | ||
| 1075 | } | ||
| 1076 | }; | ||
| 1077 | fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK")); | ||
| 1078 | while (true) { | ||
| 1079 | try pool.checkCancel(); | ||
| 1080 | switch (posix.errno(posix.fcntl(fd, posix.F.SETFL, fl_flags))) { | ||
| 1081 | .SUCCESS => break, | ||
| 1082 | .INTR => continue, | ||
| 1083 | else => |err| return posix.unexpectedErrno(err), | ||
| 1084 | } | ||
| 1085 | } | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | return .{ .handle = fd }; | ||
| 899 | } | 1089 | } |
| 900 | 1090 | ||
| 901 | fn fileOpen( | 1091 | fn fileOpen( |
| ... | @@ -2293,8 +2483,8 @@ fn timestampToPosix(nanoseconds: i96) std.posix.timespec { | ... | @@ -2293,8 +2483,8 @@ fn timestampToPosix(nanoseconds: i96) std.posix.timespec { |
| 2293 | }; | 2483 | }; |
| 2294 | } | 2484 | } |
| 2295 | 2485 | ||
| 2296 | fn toPosixPath(file_path: []const u8, buffer: *[posix.PATH_MAX]u8) error{ NameTooLong, InvalidFileName }![:0]u8 { | 2486 | fn pathToPosix(file_path: []const u8, buffer: *[posix.PATH_MAX]u8) Io.Dir.PathNameError![:0]u8 { |
| 2297 | if (std.mem.containsAtLeastScalar2(u8, file_path, 0, 1)) return error.InvalidFileName; | 2487 | if (std.mem.containsAtLeastScalar2(u8, file_path, 0, 1)) return error.BadPathName; |
| 2298 | // >= rather than > to make room for the null byte | 2488 | // >= rather than > to make room for the null byte |
| 2299 | if (file_path.len >= buffer.len) return error.NameTooLong; | 2489 | if (file_path.len >= buffer.len) return error.NameTooLong; |
| 2300 | @memcpy(buffer[0..file_path.len], file_path); | 2490 | @memcpy(buffer[0..file_path.len], file_path); |
lib/std/Io/test.zig+7-5| ... | @@ -11,6 +11,8 @@ const native_endian = @import("builtin").target.cpu.arch.endian(); | ... | @@ -11,6 +11,8 @@ const native_endian = @import("builtin").target.cpu.arch.endian(); |
| 11 | const tmpDir = std.testing.tmpDir; | 11 | const tmpDir = std.testing.tmpDir; |
| 12 | 12 | ||
| 13 | test "write a file, read it, then delete it" { | 13 | test "write a file, read it, then delete it" { |
| 14 | const io = std.testing.io; | ||
| 15 | |||
| 14 | var tmp = tmpDir(.{}); | 16 | var tmp = tmpDir(.{}); |
| 15 | defer tmp.cleanup(); | 17 | defer tmp.cleanup(); |
| 16 | 18 | ||
| ... | @@ -45,7 +47,7 @@ test "write a file, read it, then delete it" { | ... | @@ -45,7 +47,7 @@ test "write a file, read it, then delete it" { |
| 45 | try expectEqual(expected_file_size, file_size); | 47 | try expectEqual(expected_file_size, file_size); |
| 46 | 48 | ||
| 47 | var file_buffer: [1024]u8 = undefined; | 49 | var file_buffer: [1024]u8 = undefined; |
| 48 | var file_reader = file.reader(&file_buffer); | 50 | var file_reader = file.reader(io, &file_buffer); |
| 49 | const contents = try file_reader.interface.allocRemaining(std.testing.allocator, .limited(2 * 1024)); | 51 | const contents = try file_reader.interface.allocRemaining(std.testing.allocator, .limited(2 * 1024)); |
| 50 | defer std.testing.allocator.free(contents); | 52 | defer std.testing.allocator.free(contents); |
| 51 | 53 | ||
| ... | @@ -114,10 +116,10 @@ test "updateTimes" { | ... | @@ -114,10 +116,10 @@ test "updateTimes" { |
| 114 | const stat_old = try file.stat(); | 116 | const stat_old = try file.stat(); |
| 115 | // Set atime and mtime to 5s before | 117 | // Set atime and mtime to 5s before |
| 116 | try file.updateTimes( | 118 | try file.updateTimes( |
| 117 | stat_old.atime - 5 * std.time.ns_per_s, | 119 | stat_old.atime.subDuration(.fromSeconds(5)), |
| 118 | stat_old.mtime - 5 * std.time.ns_per_s, | 120 | stat_old.mtime.subDuration(.fromSeconds(5)), |
| 119 | ); | 121 | ); |
| 120 | const stat_new = try file.stat(); | 122 | const stat_new = try file.stat(); |
| 121 | try expect(stat_new.atime < stat_old.atime); | 123 | try expect(stat_new.atime.nanoseconds < stat_old.atime.nanoseconds); |
| 122 | try expect(stat_new.mtime < stat_old.mtime); | 124 | try expect(stat_new.mtime.nanoseconds < stat_old.mtime.nanoseconds); |
| 123 | } | 125 | } |
lib/std/Thread.zig+4-1| ... | @@ -318,10 +318,13 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co | ... | @@ -318,10 +318,13 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co |
| 318 | var buf: [32]u8 = undefined; | 318 | var buf: [32]u8 = undefined; |
| 319 | const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()}); | 319 | const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()}); |
| 320 | 320 | ||
| 321 | var threaded: std.Io.Threaded = .init_single_threaded; | ||
| 322 | const io = threaded.io(); | ||
| 323 | |||
| 321 | const file = try std.fs.cwd().openFile(path, .{}); | 324 | const file = try std.fs.cwd().openFile(path, .{}); |
| 322 | defer file.close(); | 325 | defer file.close(); |
| 323 | 326 | ||
| 324 | var file_reader = file.readerStreaming(&.{}); | 327 | var file_reader = file.readerStreaming(io, &.{}); |
| 325 | const data_len = file_reader.interface.readSliceShort(buffer_ptr[0 .. max_name_len + 1]) catch |err| switch (err) { | 328 | const data_len = file_reader.interface.readSliceShort(buffer_ptr[0 .. max_name_len + 1]) catch |err| switch (err) { |
| 326 | error.ReadFailed => return file_reader.err.?, | 329 | error.ReadFailed => return file_reader.err.?, |
| 327 | }; | 330 | }; |
lib/std/Thread/Condition.zig+7-8| ... | @@ -123,14 +123,9 @@ const SingleThreadedImpl = struct { | ... | @@ -123,14 +123,9 @@ const SingleThreadedImpl = struct { |
| 123 | fn wait(self: *Impl, mutex: *Mutex, timeout: ?u64) error{Timeout}!void { | 123 | fn wait(self: *Impl, mutex: *Mutex, timeout: ?u64) error{Timeout}!void { |
| 124 | _ = self; | 124 | _ = self; |
| 125 | _ = mutex; | 125 | _ = mutex; |
| 126 | |||
| 127 | // There are no other threads to wake us up. | 126 | // There are no other threads to wake us up. |
| 128 | // So if we wait without a timeout we would never wake up. | 127 | // So if we wait without a timeout we would never wake up. |
| 129 | const timeout_ns = timeout orelse { | 128 | assert(timeout != null); // Deadlock detected. |
| 130 | unreachable; // deadlock detected | ||
| 131 | }; | ||
| 132 | |||
| 133 | std.Thread.sleep(timeout_ns); | ||
| 134 | return error.Timeout; | 129 | return error.Timeout; |
| 135 | } | 130 | } |
| 136 | 131 | ||
| ... | @@ -323,6 +318,8 @@ test "wait and signal" { | ... | @@ -323,6 +318,8 @@ test "wait and signal" { |
| 323 | return error.SkipZigTest; | 318 | return error.SkipZigTest; |
| 324 | } | 319 | } |
| 325 | 320 | ||
| 321 | const io = testing.io; | ||
| 322 | |||
| 326 | const num_threads = 4; | 323 | const num_threads = 4; |
| 327 | 324 | ||
| 328 | const MultiWait = struct { | 325 | const MultiWait = struct { |
| ... | @@ -348,7 +345,7 @@ test "wait and signal" { | ... | @@ -348,7 +345,7 @@ test "wait and signal" { |
| 348 | } | 345 | } |
| 349 | 346 | ||
| 350 | while (true) { | 347 | while (true) { |
| 351 | std.Thread.sleep(100 * std.time.ns_per_ms); | 348 | try std.Io.Clock.Duration.sleep(.{ .clock = .awake, .raw = .fromMilliseconds(100) }, io); |
| 352 | 349 | ||
| 353 | multi_wait.mutex.lock(); | 350 | multi_wait.mutex.lock(); |
| 354 | defer multi_wait.mutex.unlock(); | 351 | defer multi_wait.mutex.unlock(); |
| ... | @@ -368,6 +365,8 @@ test signal { | ... | @@ -368,6 +365,8 @@ test signal { |
| 368 | return error.SkipZigTest; | 365 | return error.SkipZigTest; |
| 369 | } | 366 | } |
| 370 | 367 | ||
| 368 | const io = testing.io; | ||
| 369 | |||
| 371 | const num_threads = 4; | 370 | const num_threads = 4; |
| 372 | 371 | ||
| 373 | const SignalTest = struct { | 372 | const SignalTest = struct { |
| ... | @@ -405,7 +404,7 @@ test signal { | ... | @@ -405,7 +404,7 @@ test signal { |
| 405 | } | 404 | } |
| 406 | 405 | ||
| 407 | while (true) { | 406 | while (true) { |
| 408 | std.Thread.sleep(10 * std.time.ns_per_ms); | 407 | try std.Io.Clock.Duration.sleep(.{ .clock = .awake, .raw = .fromMilliseconds(10) }, io); |
| 409 | 408 | ||
| 410 | signal_test.mutex.lock(); | 409 | signal_test.mutex.lock(); |
| 411 | defer signal_test.mutex.unlock(); | 410 | defer signal_test.mutex.unlock(); |
lib/std/Uri.zig+1-1| ... | @@ -441,7 +441,7 @@ pub fn resolveInPlace(base: Uri, new_len: usize, aux_buf: *[]u8) ResolveInPlaceE | ... | @@ -441,7 +441,7 @@ pub fn resolveInPlace(base: Uri, new_len: usize, aux_buf: *[]u8) ResolveInPlaceE |
| 441 | }; | 441 | }; |
| 442 | } | 442 | } |
| 443 | 443 | ||
| 444 | fn validateHost(bytes: []const u8) []const u8 { | 444 | fn validateHost(bytes: []const u8) HostName.ValidateError![]const u8 { |
| 445 | try HostName.validate(bytes); | 445 | try HostName.validate(bytes); |
| 446 | return bytes; | 446 | return bytes; |
| 447 | } | 447 | } |
lib/std/dynamic_library.zig+1| ... | @@ -137,6 +137,7 @@ const ElfDynLibError = error{ | ... | @@ -137,6 +137,7 @@ const ElfDynLibError = error{ |
| 137 | ElfStringSectionNotFound, | 137 | ElfStringSectionNotFound, |
| 138 | ElfSymSectionNotFound, | 138 | ElfSymSectionNotFound, |
| 139 | ElfHashTableNotFound, | 139 | ElfHashTableNotFound, |
| 140 | Canceled, | ||
| 140 | } || posix.OpenError || posix.MMapError; | 141 | } || posix.OpenError || posix.MMapError; |
| 141 | 142 | ||
| 142 | pub const ElfDynLib = struct { | 143 | pub const ElfDynLib = struct { |
lib/std/fs/Dir.zig+16-74| ... | @@ -36,10 +36,6 @@ const IteratorError = error{ | ... | @@ -36,10 +36,6 @@ const IteratorError = error{ |
| 36 | AccessDenied, | 36 | AccessDenied, |
| 37 | PermissionDenied, | 37 | PermissionDenied, |
| 38 | SystemResources, | 38 | SystemResources, |
| 39 | /// WASI-only. The path of an entry could not be encoded as valid UTF-8. | ||
| 40 | /// WASI is unable to handle paths that cannot be encoded as well-formed UTF-8. | ||
| 41 | /// https://github.com/WebAssembly/wasi-filesystem/issues/17#issuecomment-1430639353 | ||
| 42 | InvalidUtf8, | ||
| 43 | } || posix.UnexpectedError; | 39 | } || posix.UnexpectedError; |
| 44 | 40 | ||
| 45 | pub const Iterator = switch (native_os) { | 41 | pub const Iterator = switch (native_os) { |
| ... | @@ -553,7 +549,6 @@ pub const Iterator = switch (native_os) { | ... | @@ -553,7 +549,6 @@ pub const Iterator = switch (native_os) { |
| 553 | .INVAL => unreachable, | 549 | .INVAL => unreachable, |
| 554 | .NOENT => return error.DirNotFound, // The directory being iterated was deleted during iteration. | 550 | .NOENT => return error.DirNotFound, // The directory being iterated was deleted during iteration. |
| 555 | .NOTCAPABLE => return error.AccessDenied, | 551 | .NOTCAPABLE => return error.AccessDenied, |
| 556 | .ILSEQ => return error.InvalidUtf8, // An entry's name cannot be encoded as UTF-8. | ||
| 557 | else => |err| return posix.unexpectedErrno(err), | 552 | else => |err| return posix.unexpectedErrno(err), |
| 558 | } | 553 | } |
| 559 | if (bufused == 0) return null; | 554 | if (bufused == 0) return null; |
| ... | @@ -844,28 +839,7 @@ pub fn walk(self: Dir, allocator: Allocator) Allocator.Error!Walker { | ... | @@ -844,28 +839,7 @@ pub fn walk(self: Dir, allocator: Allocator) Allocator.Error!Walker { |
| 844 | }; | 839 | }; |
| 845 | } | 840 | } |
| 846 | 841 | ||
| 847 | pub const OpenError = error{ | 842 | pub const OpenError = Io.Dir.OpenError; |
| 848 | FileNotFound, | ||
| 849 | NotDir, | ||
| 850 | AccessDenied, | ||
| 851 | PermissionDenied, | ||
| 852 | SymLinkLoop, | ||
| 853 | ProcessFdQuotaExceeded, | ||
| 854 | NameTooLong, | ||
| 855 | SystemFdQuotaExceeded, | ||
| 856 | NoDevice, | ||
| 857 | SystemResources, | ||
| 858 | /// WASI-only; file paths must be valid UTF-8. | ||
| 859 | InvalidUtf8, | ||
| 860 | /// Windows-only; file paths provided by the user must be valid WTF-8. | ||
| 861 | /// https://wtf-8.codeberg.page/ | ||
| 862 | InvalidWtf8, | ||
| 863 | BadPathName, | ||
| 864 | DeviceBusy, | ||
| 865 | /// On Windows, `\\server` or `\\server\share` was not found. | ||
| 866 | NetworkNotFound, | ||
| 867 | ProcessNotFound, | ||
| 868 | } || posix.UnexpectedError; | ||
| 869 | 843 | ||
| 870 | pub fn close(self: *Dir) void { | 844 | pub fn close(self: *Dir) void { |
| 871 | posix.close(self.fd); | 845 | posix.close(self.fd); |
| ... | @@ -1311,7 +1285,7 @@ pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenOptio | ... | @@ -1311,7 +1285,7 @@ pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenOptio |
| 1311 | }; | 1285 | }; |
| 1312 | } | 1286 | } |
| 1313 | 1287 | ||
| 1314 | pub const RealPathError = posix.RealPathError; | 1288 | pub const RealPathError = posix.RealPathError || error{Canceled}; |
| 1315 | 1289 | ||
| 1316 | /// This function returns the canonicalized absolute pathname of | 1290 | /// This function returns the canonicalized absolute pathname of |
| 1317 | /// `pathname` relative to this `Dir`. If `pathname` is absolute, ignores this | 1291 | /// `pathname` relative to this `Dir`. If `pathname` is absolute, ignores this |
| ... | @@ -1369,7 +1343,6 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathE | ... | @@ -1369,7 +1343,6 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathE |
| 1369 | error.FileLocksNotSupported => return error.Unexpected, | 1343 | error.FileLocksNotSupported => return error.Unexpected, |
| 1370 | error.FileBusy => return error.Unexpected, | 1344 | error.FileBusy => return error.Unexpected, |
| 1371 | error.WouldBlock => return error.Unexpected, | 1345 | error.WouldBlock => return error.Unexpected, |
| 1372 | error.InvalidUtf8 => unreachable, // WASI-only | ||
| 1373 | else => |e| return e, | 1346 | else => |e| return e, |
| 1374 | }; | 1347 | }; |
| 1375 | defer posix.close(fd); | 1348 | defer posix.close(fd); |
| ... | @@ -1639,6 +1612,10 @@ fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: posix.O) OpenError | ... | @@ -1639,6 +1612,10 @@ fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: posix.O) OpenError |
| 1639 | error.FileLocksNotSupported => unreachable, // locking folders is not supported | 1612 | error.FileLocksNotSupported => unreachable, // locking folders is not supported |
| 1640 | error.WouldBlock => unreachable, // can't happen for directories | 1613 | error.WouldBlock => unreachable, // can't happen for directories |
| 1641 | error.FileBusy => unreachable, // can't happen for directories | 1614 | error.FileBusy => unreachable, // can't happen for directories |
| 1615 | error.SharingViolation => unreachable, // can't happen for directories | ||
| 1616 | error.PipeBusy => unreachable, // can't happen for directories | ||
| 1617 | error.AntivirusInterference => unreachable, // can't happen for directories | ||
| 1618 | error.ProcessNotFound => unreachable, // can't happen for directories | ||
| 1642 | else => |e| return e, | 1619 | else => |e| return e, |
| 1643 | }; | 1620 | }; |
| 1644 | return Dir{ .fd = fd }; | 1621 | return Dir{ .fd = fd }; |
| ... | @@ -2095,24 +2072,21 @@ pub const DeleteTreeError = error{ | ... | @@ -2095,24 +2072,21 @@ pub const DeleteTreeError = error{ |
| 2095 | FileBusy, | 2072 | FileBusy, |
| 2096 | DeviceBusy, | 2073 | DeviceBusy, |
| 2097 | ProcessNotFound, | 2074 | ProcessNotFound, |
| 2098 | |||
| 2099 | /// One of the path components was not a directory. | 2075 | /// One of the path components was not a directory. |
| 2100 | /// This error is unreachable if `sub_path` does not contain a path separator. | 2076 | /// This error is unreachable if `sub_path` does not contain a path separator. |
| 2101 | NotDir, | 2077 | NotDir, |
| 2102 | |||
| 2103 | /// WASI-only; file paths must be valid UTF-8. | 2078 | /// WASI-only; file paths must be valid UTF-8. |
| 2104 | InvalidUtf8, | 2079 | InvalidUtf8, |
| 2105 | |||
| 2106 | /// Windows-only; file paths provided by the user must be valid WTF-8. | 2080 | /// Windows-only; file paths provided by the user must be valid WTF-8. |
| 2107 | /// https://wtf-8.codeberg.page/ | 2081 | /// https://wtf-8.codeberg.page/ |
| 2108 | InvalidWtf8, | 2082 | InvalidWtf8, |
| 2109 | |||
| 2110 | /// On Windows, file paths cannot contain these characters: | 2083 | /// On Windows, file paths cannot contain these characters: |
| 2111 | /// '/', '*', '?', '"', '<', '>', '|' | 2084 | /// '/', '*', '?', '"', '<', '>', '|' |
| 2112 | BadPathName, | 2085 | BadPathName, |
| 2113 | |||
| 2114 | /// On Windows, `\\server` or `\\server\share` was not found. | 2086 | /// On Windows, `\\server` or `\\server\share` was not found. |
| 2115 | NetworkNotFound, | 2087 | NetworkNotFound, |
| 2088 | |||
| 2089 | Canceled, | ||
| 2116 | } || posix.UnexpectedError; | 2090 | } || posix.UnexpectedError; |
| 2117 | 2091 | ||
| 2118 | /// Whether `sub_path` describes a symlink, file, or directory, this function | 2092 | /// Whether `sub_path` describes a symlink, file, or directory, this function |
| ... | @@ -2169,17 +2143,15 @@ pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void { | ... | @@ -2169,17 +2143,15 @@ pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void { |
| 2169 | error.PermissionDenied, | 2143 | error.PermissionDenied, |
| 2170 | error.SymLinkLoop, | 2144 | error.SymLinkLoop, |
| 2171 | error.ProcessFdQuotaExceeded, | 2145 | error.ProcessFdQuotaExceeded, |
| 2172 | error.ProcessNotFound, | ||
| 2173 | error.NameTooLong, | 2146 | error.NameTooLong, |
| 2174 | error.SystemFdQuotaExceeded, | 2147 | error.SystemFdQuotaExceeded, |
| 2175 | error.NoDevice, | 2148 | error.NoDevice, |
| 2176 | error.SystemResources, | 2149 | error.SystemResources, |
| 2177 | error.Unexpected, | 2150 | error.Unexpected, |
| 2178 | error.InvalidUtf8, | ||
| 2179 | error.InvalidWtf8, | ||
| 2180 | error.BadPathName, | 2151 | error.BadPathName, |
| 2181 | error.NetworkNotFound, | 2152 | error.NetworkNotFound, |
| 2182 | error.DeviceBusy, | 2153 | error.DeviceBusy, |
| 2154 | error.Canceled, | ||
| 2183 | => |e| return e, | 2155 | => |e| return e, |
| 2184 | }; | 2156 | }; |
| 2185 | stack.appendAssumeCapacity(.{ | 2157 | stack.appendAssumeCapacity(.{ |
| ... | @@ -2266,18 +2238,16 @@ pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void { | ... | @@ -2266,18 +2238,16 @@ pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void { |
| 2266 | error.AccessDenied, | 2238 | error.AccessDenied, |
| 2267 | error.PermissionDenied, | 2239 | error.PermissionDenied, |
| 2268 | error.SymLinkLoop, | 2240 | error.SymLinkLoop, |
| 2269 | error.ProcessNotFound, | ||
| 2270 | error.ProcessFdQuotaExceeded, | 2241 | error.ProcessFdQuotaExceeded, |
| 2271 | error.NameTooLong, | 2242 | error.NameTooLong, |
| 2272 | error.SystemFdQuotaExceeded, | 2243 | error.SystemFdQuotaExceeded, |
| 2273 | error.NoDevice, | 2244 | error.NoDevice, |
| 2274 | error.SystemResources, | 2245 | error.SystemResources, |
| 2275 | error.Unexpected, | 2246 | error.Unexpected, |
| 2276 | error.InvalidUtf8, | ||
| 2277 | error.InvalidWtf8, | ||
| 2278 | error.BadPathName, | 2247 | error.BadPathName, |
| 2279 | error.NetworkNotFound, | 2248 | error.NetworkNotFound, |
| 2280 | error.DeviceBusy, | 2249 | error.DeviceBusy, |
| 2250 | error.Canceled, | ||
| 2281 | => |e| return e, | 2251 | => |e| return e, |
| 2282 | }; | 2252 | }; |
| 2283 | } else { | 2253 | } else { |
| ... | @@ -2374,18 +2344,16 @@ fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint | ... | @@ -2374,18 +2344,16 @@ fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint |
| 2374 | error.AccessDenied, | 2344 | error.AccessDenied, |
| 2375 | error.PermissionDenied, | 2345 | error.PermissionDenied, |
| 2376 | error.SymLinkLoop, | 2346 | error.SymLinkLoop, |
| 2377 | error.ProcessNotFound, | ||
| 2378 | error.ProcessFdQuotaExceeded, | 2347 | error.ProcessFdQuotaExceeded, |
| 2379 | error.NameTooLong, | 2348 | error.NameTooLong, |
| 2380 | error.SystemFdQuotaExceeded, | 2349 | error.SystemFdQuotaExceeded, |
| 2381 | error.NoDevice, | 2350 | error.NoDevice, |
| 2382 | error.SystemResources, | 2351 | error.SystemResources, |
| 2383 | error.Unexpected, | 2352 | error.Unexpected, |
| 2384 | error.InvalidUtf8, | ||
| 2385 | error.InvalidWtf8, | ||
| 2386 | error.BadPathName, | 2353 | error.BadPathName, |
| 2387 | error.NetworkNotFound, | 2354 | error.NetworkNotFound, |
| 2388 | error.DeviceBusy, | 2355 | error.DeviceBusy, |
| 2356 | error.Canceled, | ||
| 2389 | => |e| return e, | 2357 | => |e| return e, |
| 2390 | }; | 2358 | }; |
| 2391 | if (cleanup_dir_parent) |*d| d.close(); | 2359 | if (cleanup_dir_parent) |*d| d.close(); |
| ... | @@ -2476,17 +2444,15 @@ fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File | ... | @@ -2476,17 +2444,15 @@ fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File |
| 2476 | error.PermissionDenied, | 2444 | error.PermissionDenied, |
| 2477 | error.SymLinkLoop, | 2445 | error.SymLinkLoop, |
| 2478 | error.ProcessFdQuotaExceeded, | 2446 | error.ProcessFdQuotaExceeded, |
| 2479 | error.ProcessNotFound, | ||
| 2480 | error.NameTooLong, | 2447 | error.NameTooLong, |
| 2481 | error.SystemFdQuotaExceeded, | 2448 | error.SystemFdQuotaExceeded, |
| 2482 | error.NoDevice, | 2449 | error.NoDevice, |
| 2483 | error.SystemResources, | 2450 | error.SystemResources, |
| 2484 | error.Unexpected, | 2451 | error.Unexpected, |
| 2485 | error.InvalidUtf8, | ||
| 2486 | error.InvalidWtf8, | ||
| 2487 | error.BadPathName, | 2452 | error.BadPathName, |
| 2488 | error.DeviceBusy, | 2453 | error.DeviceBusy, |
| 2489 | error.NetworkNotFound, | 2454 | error.NetworkNotFound, |
| 2455 | error.Canceled, | ||
| 2490 | => |e| return e, | 2456 | => |e| return e, |
| 2491 | }; | 2457 | }; |
| 2492 | } else { | 2458 | } else { |
| ... | @@ -2589,7 +2555,7 @@ pub const CopyFileOptions = struct { | ... | @@ -2589,7 +2555,7 @@ pub const CopyFileOptions = struct { |
| 2589 | 2555 | ||
| 2590 | pub const CopyFileError = File.OpenError || File.StatError || | 2556 | pub const CopyFileError = File.OpenError || File.StatError || |
| 2591 | AtomicFile.InitError || AtomicFile.FinishError || | 2557 | AtomicFile.InitError || AtomicFile.FinishError || |
| 2592 | File.ReadError || File.WriteError; | 2558 | File.ReadError || File.WriteError || error{InvalidFileName}; |
| 2593 | 2559 | ||
| 2594 | /// Atomically creates a new file at `dest_path` within `dest_dir` with the | 2560 | /// Atomically creates a new file at `dest_path` within `dest_dir` with the |
| 2595 | /// same contents as `source_path` within `source_dir`, overwriting any already | 2561 | /// same contents as `source_path` within `source_dir`, overwriting any already |
| ... | @@ -2690,33 +2656,9 @@ pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat { | ... | @@ -2690,33 +2656,9 @@ pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat { |
| 2690 | const st = try std.os.fstatat_wasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true }); | 2656 | const st = try std.os.fstatat_wasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true }); |
| 2691 | return Stat.fromWasi(st); | 2657 | return Stat.fromWasi(st); |
| 2692 | } | 2658 | } |
| 2693 | if (native_os == .linux) { | 2659 | var threaded: Io.Threaded = .init_single_threaded; |
| 2694 | const sub_path_c = try posix.toPosixPath(sub_path); | 2660 | const io = threaded.io(); |
| 2695 | var stx = std.mem.zeroes(linux.Statx); | 2661 | return Io.Dir.statPath(.{ .handle = self.fd }, io, sub_path, .{}); |
| 2696 | |||
| 2697 | const rc = linux.statx( | ||
| 2698 | self.fd, | ||
| 2699 | &sub_path_c, | ||
| 2700 | linux.AT.NO_AUTOMOUNT, | ||
| 2701 | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME, | ||
| 2702 | &stx, | ||
| 2703 | ); | ||
| 2704 | |||
| 2705 | return switch (linux.E.init(rc)) { | ||
| 2706 | .SUCCESS => Stat.fromLinux(stx), | ||
| 2707 | .ACCES => error.AccessDenied, | ||
| 2708 | .BADF => unreachable, | ||
| 2709 | .FAULT => unreachable, | ||
| 2710 | .INVAL => unreachable, | ||
| 2711 | .LOOP => error.SymLinkLoop, | ||
| 2712 | .NAMETOOLONG => unreachable, // Handled by posix.toPosixPath() above. | ||
| 2713 | .NOENT, .NOTDIR => error.FileNotFound, | ||
| 2714 | .NOMEM => error.SystemResources, | ||
| 2715 | else => |err| posix.unexpectedErrno(err), | ||
| 2716 | }; | ||
| 2717 | } | ||
| 2718 | const st = try posix.fstatat(self.fd, sub_path, 0); | ||
| 2719 | return Stat.fromPosix(st); | ||
| 2720 | } | 2662 | } |
| 2721 | 2663 | ||
| 2722 | pub const ChmodError = File.ChmodError; | 2664 | pub const ChmodError = File.ChmodError; |
lib/std/fs/File.zig+2-27| ... | @@ -38,33 +38,8 @@ pub const default_mode = switch (builtin.os.tag) { | ... | @@ -38,33 +38,8 @@ pub const default_mode = switch (builtin.os.tag) { |
| 38 | else => 0o666, | 38 | else => 0o666, |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | pub const OpenError = error{ | 41 | /// Deprecated in favor of `Io.File.OpenError`. |
| 42 | SharingViolation, | 42 | pub const OpenError = Io.File.OpenError || error{WouldBlock}; |
| 43 | PathAlreadyExists, | ||
| 44 | FileNotFound, | ||
| 45 | AccessDenied, | ||
| 46 | PipeBusy, | ||
| 47 | NoDevice, | ||
| 48 | NameTooLong, | ||
| 49 | /// WASI-only; file paths must be valid UTF-8. | ||
| 50 | InvalidUtf8, | ||
| 51 | /// Windows-only; file paths provided by the user must be valid WTF-8. | ||
| 52 | /// https://wtf-8.codeberg.page/ | ||
| 53 | InvalidWtf8, | ||
| 54 | /// On Windows, file paths cannot contain these characters: | ||
| 55 | /// '/', '*', '?', '"', '<', '>', '|' | ||
| 56 | BadPathName, | ||
| 57 | Unexpected, | ||
| 58 | /// On Windows, `\\server` or `\\server\share` was not found. | ||
| 59 | NetworkNotFound, | ||
| 60 | ProcessNotFound, | ||
| 61 | /// On Windows, antivirus software is enabled by default. It can be | ||
| 62 | /// disabled, but Windows Update sometimes ignores the user's preference | ||
| 63 | /// and re-enables it. When enabled, antivirus software on Windows | ||
| 64 | /// intercepts file system operations and makes them significantly slower | ||
| 65 | /// in addition to possibly failing with this error code. | ||
| 66 | AntivirusInterference, | ||
| 67 | } || posix.OpenError || posix.FlockError; | ||
| 68 | 43 | ||
| 69 | pub const OpenMode = enum { | 44 | pub const OpenMode = enum { |
| 70 | read_only, | 45 | read_only, |
lib/std/posix.zig+1-75| ... | @@ -1542,81 +1542,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz | ... | @@ -1542,81 +1542,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz |
| 1542 | } | 1542 | } |
| 1543 | } | 1543 | } |
| 1544 | 1544 | ||
| 1545 | pub const OpenError = error{ | 1545 | pub const OpenError = std.Io.File.OpenError || error{WouldBlock}; |
| 1546 | /// In WASI, this error may occur when the file descriptor does | ||
| 1547 | /// not hold the required rights to open a new resource relative to it. | ||
| 1548 | AccessDenied, | ||
| 1549 | PermissionDenied, | ||
| 1550 | SymLinkLoop, | ||
| 1551 | ProcessFdQuotaExceeded, | ||
| 1552 | SystemFdQuotaExceeded, | ||
| 1553 | NoDevice, | ||
| 1554 | /// Either: | ||
| 1555 | /// * One of the path components does not exist. | ||
| 1556 | /// * Cwd was used, but cwd has been deleted. | ||
| 1557 | /// * The path associated with the open directory handle has been deleted. | ||
| 1558 | /// * On macOS, multiple processes or threads raced to create the same file | ||
| 1559 | /// with `O.EXCL` set to `false`. | ||
| 1560 | FileNotFound, | ||
| 1561 | |||
| 1562 | /// The path exceeded `max_path_bytes` bytes. | ||
| 1563 | NameTooLong, | ||
| 1564 | |||
| 1565 | /// Insufficient kernel memory was available, or | ||
| 1566 | /// the named file is a FIFO and per-user hard limit on | ||
| 1567 | /// memory allocation for pipes has been reached. | ||
| 1568 | SystemResources, | ||
| 1569 | |||
| 1570 | /// The file is too large to be opened. This error is unreachable | ||
| 1571 | /// for 64-bit targets, as well as when opening directories. | ||
| 1572 | FileTooBig, | ||
| 1573 | |||
| 1574 | /// The path refers to directory but the `DIRECTORY` flag was not provided. | ||
| 1575 | IsDir, | ||
| 1576 | |||
| 1577 | /// A new path cannot be created because the device has no room for the new file. | ||
| 1578 | /// This error is only reachable when the `CREAT` flag is provided. | ||
| 1579 | NoSpaceLeft, | ||
| 1580 | |||
| 1581 | /// A component used as a directory in the path was not, in fact, a directory, or | ||
| 1582 | /// `DIRECTORY` was specified and the path was not a directory. | ||
| 1583 | NotDir, | ||
| 1584 | |||
| 1585 | /// The path already exists and the `CREAT` and `EXCL` flags were provided. | ||
| 1586 | PathAlreadyExists, | ||
| 1587 | DeviceBusy, | ||
| 1588 | |||
| 1589 | /// The underlying filesystem does not support file locks | ||
| 1590 | FileLocksNotSupported, | ||
| 1591 | |||
| 1592 | /// Path contains characters that are disallowed by the underlying filesystem. | ||
| 1593 | BadPathName, | ||
| 1594 | |||
| 1595 | /// WASI-only; file paths must be valid UTF-8. | ||
| 1596 | InvalidUtf8, | ||
| 1597 | |||
| 1598 | /// Windows-only; file paths provided by the user must be valid WTF-8. | ||
| 1599 | /// https://wtf-8.codeberg.page/ | ||
| 1600 | InvalidWtf8, | ||
| 1601 | |||
| 1602 | /// On Windows, `\\server` or `\\server\share` was not found. | ||
| 1603 | NetworkNotFound, | ||
| 1604 | |||
| 1605 | /// This error occurs in Linux if the process to be open was not found. | ||
| 1606 | ProcessNotFound, | ||
| 1607 | |||
| 1608 | /// One of these three things: | ||
| 1609 | /// * pathname refers to an executable image which is currently being | ||
| 1610 | /// executed and write access was requested. | ||
| 1611 | /// * pathname refers to a file that is currently in use as a swap | ||
| 1612 | /// file, and the O_TRUNC flag was specified. | ||
| 1613 | /// * pathname refers to a file that is currently being read by the | ||
| 1614 | /// kernel (e.g., for module/firmware loading), and write access was | ||
| 1615 | /// requested. | ||
| 1616 | FileBusy, | ||
| 1617 | |||
| 1618 | WouldBlock, | ||
| 1619 | } || UnexpectedError; | ||
| 1620 | 1546 | ||
| 1621 | /// Open and possibly create a file. Keeps trying if it gets interrupted. | 1547 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 1622 | /// On Windows, `file_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). | 1548 | /// On Windows, `file_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). |
lib/std/zig/system.zig+44-55| ... | @@ -766,27 +766,23 @@ test glibcVerFromLinkName { | ... | @@ -766,27 +766,23 @@ test glibcVerFromLinkName { |
| 766 | 766 | ||
| 767 | fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion { | 767 | fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion { |
| 768 | var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) { | 768 | var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) { |
| 769 | error.NameTooLong => unreachable, | 769 | error.NameTooLong => return error.Unexpected, |
| 770 | error.InvalidUtf8 => unreachable, // WASI only | 770 | error.BadPathName => return error.Unexpected, |
| 771 | error.InvalidWtf8 => unreachable, // Windows-only | 771 | error.DeviceBusy => return error.Unexpected, |
| 772 | error.BadPathName => unreachable, | 772 | error.NetworkNotFound => return error.Unexpected, // Windows-only |
| 773 | error.DeviceBusy => unreachable, | 773 | |
| 774 | error.NetworkNotFound => unreachable, // Windows-only | 774 | error.FileNotFound => return error.GLibCNotFound, |
| 775 | 775 | error.NotDir => return error.GLibCNotFound, | |
| 776 | error.FileNotFound, | 776 | error.AccessDenied => return error.GLibCNotFound, |
| 777 | error.NotDir, | 777 | error.PermissionDenied => return error.GLibCNotFound, |
| 778 | error.AccessDenied, | 778 | error.NoDevice => return error.GLibCNotFound, |
| 779 | error.PermissionDenied, | 779 | |
| 780 | error.NoDevice, | 780 | error.ProcessFdQuotaExceeded => |e| return e, |
| 781 | => return error.GLibCNotFound, | 781 | error.SystemFdQuotaExceeded => |e| return e, |
| 782 | 782 | error.SystemResources => |e| return e, | |
| 783 | error.ProcessNotFound, | 783 | error.SymLinkLoop => |e| return e, |
| 784 | error.ProcessFdQuotaExceeded, | 784 | error.Unexpected => |e| return e, |
| 785 | error.SystemFdQuotaExceeded, | 785 | error.Canceled => |e| return e, |
| 786 | error.SystemResources, | ||
| 787 | error.SymLinkLoop, | ||
| 788 | error.Unexpected, | ||
| 789 | => |e| return e, | ||
| 790 | }; | 786 | }; |
| 791 | defer dir.close(); | 787 | defer dir.close(); |
| 792 | 788 | ||
| ... | @@ -799,38 +795,34 @@ fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion { | ... | @@ -799,38 +795,34 @@ fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion { |
| 799 | // that start with "GLIBC_2.". | 795 | // that start with "GLIBC_2.". |
| 800 | const glibc_so_basename = "libc.so.6"; | 796 | const glibc_so_basename = "libc.so.6"; |
| 801 | var file = dir.openFile(glibc_so_basename, .{}) catch |err| switch (err) { | 797 | var file = dir.openFile(glibc_so_basename, .{}) catch |err| switch (err) { |
| 802 | error.NameTooLong => unreachable, | 798 | error.NameTooLong => return error.Unexpected, |
| 803 | error.InvalidUtf8 => unreachable, // WASI only | 799 | error.BadPathName => return error.Unexpected, |
| 804 | error.InvalidWtf8 => unreachable, // Windows only | 800 | error.PipeBusy => return error.Unexpected, // Windows-only |
| 805 | error.BadPathName => unreachable, // Windows only | 801 | error.SharingViolation => return error.Unexpected, // Windows-only |
| 806 | error.PipeBusy => unreachable, // Windows-only | 802 | error.NetworkNotFound => return error.Unexpected, // Windows-only |
| 807 | error.SharingViolation => unreachable, // Windows-only | 803 | error.AntivirusInterference => return error.Unexpected, // Windows-only |
| 808 | error.NetworkNotFound => unreachable, // Windows-only | 804 | error.FileLocksNotSupported => return error.Unexpected, // No lock requested. |
| 809 | error.AntivirusInterference => unreachable, // Windows-only | 805 | error.NoSpaceLeft => return error.Unexpected, // read-only |
| 810 | error.FileLocksNotSupported => unreachable, // No lock requested. | 806 | error.PathAlreadyExists => return error.Unexpected, // read-only |
| 811 | error.NoSpaceLeft => unreachable, // read-only | 807 | error.DeviceBusy => return error.Unexpected, // read-only |
| 812 | error.PathAlreadyExists => unreachable, // read-only | 808 | error.FileBusy => return error.Unexpected, // read-only |
| 813 | error.DeviceBusy => unreachable, // read-only | 809 | error.NoDevice => return error.Unexpected, // not asking for a special device |
| 814 | error.FileBusy => unreachable, // read-only | ||
| 815 | error.WouldBlock => unreachable, // not using O_NONBLOCK | ||
| 816 | error.NoDevice => unreachable, // not asking for a special device | ||
| 817 | |||
| 818 | error.AccessDenied, | ||
| 819 | error.PermissionDenied, | ||
| 820 | error.FileNotFound, | ||
| 821 | error.NotDir, | ||
| 822 | error.IsDir, | ||
| 823 | => return error.GLibCNotFound, | ||
| 824 | |||
| 825 | error.FileTooBig => return error.Unexpected, | 810 | error.FileTooBig => return error.Unexpected, |
| 826 | 811 | error.WouldBlock => return error.Unexpected, // not opened in non-blocking | |
| 827 | error.ProcessNotFound, | 812 | |
| 828 | error.ProcessFdQuotaExceeded, | 813 | error.AccessDenied => return error.GLibCNotFound, |
| 829 | error.SystemFdQuotaExceeded, | 814 | error.PermissionDenied => return error.GLibCNotFound, |
| 830 | error.SystemResources, | 815 | error.FileNotFound => return error.GLibCNotFound, |
| 831 | error.SymLinkLoop, | 816 | error.NotDir => return error.GLibCNotFound, |
| 832 | error.Unexpected, | 817 | error.IsDir => return error.GLibCNotFound, |
| 833 | => |e| return e, | 818 | |
| 819 | error.ProcessNotFound => |e| return e, | ||
| 820 | error.ProcessFdQuotaExceeded => |e| return e, | ||
| 821 | error.SystemFdQuotaExceeded => |e| return e, | ||
| 822 | error.SystemResources => |e| return e, | ||
| 823 | error.SymLinkLoop => |e| return e, | ||
| 824 | error.Unexpected => |e| return e, | ||
| 825 | error.Canceled => |e| return e, | ||
| 834 | }; | 826 | }; |
| 835 | defer file.close(); | 827 | defer file.close(); |
| 836 | 828 | ||
| ... | @@ -1016,12 +1008,9 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ | ... | @@ -1016,12 +1008,9 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ |
| 1016 | error.NameTooLong => return error.Unexpected, | 1008 | error.NameTooLong => return error.Unexpected, |
| 1017 | error.PathAlreadyExists => return error.Unexpected, | 1009 | error.PathAlreadyExists => return error.Unexpected, |
| 1018 | error.SharingViolation => return error.Unexpected, | 1010 | error.SharingViolation => return error.Unexpected, |
| 1019 | error.InvalidUtf8 => return error.Unexpected, // WASI only | ||
| 1020 | error.InvalidWtf8 => return error.Unexpected, // Windows only | ||
| 1021 | error.BadPathName => return error.Unexpected, | 1011 | error.BadPathName => return error.Unexpected, |
| 1022 | error.PipeBusy => return error.Unexpected, | 1012 | error.PipeBusy => return error.Unexpected, |
| 1023 | error.FileLocksNotSupported => return error.Unexpected, | 1013 | error.FileLocksNotSupported => return error.Unexpected, |
| 1024 | error.WouldBlock => return error.Unexpected, | ||
| 1025 | error.FileBusy => return error.Unexpected, // opened without write permissions | 1014 | error.FileBusy => return error.Unexpected, // opened without write permissions |
| 1026 | error.AntivirusInterference => return error.Unexpected, // Windows-only error | 1015 | error.AntivirusInterference => return error.Unexpected, // Windows-only error |
| 1027 | 1016 |