authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-09 00:19:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:49-07:00
log8a1e6c8c394058a25cb21f60ad414f28cd37db22
treeef6a86087599855c24d5172eb7b225d515b4dccc
parent750b1431bf34b238bd991b2ee3b50e81ff20b667

std.Io: implement dirStatPath


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
13051305}
13061306
13071307// Create/Write a file, close it, then grab its stat.mtime timestamp.
1308fn testGetCurrentFileTimestamp(dir: fs.Dir) !i128 {
1308fn testGetCurrentFileTimestamp(dir: fs.Dir) !Io.Timestamp {
13091309 const test_out_file = "test-filetimestamp.tmp";
13101310
13111311 var file = try dir.createFile(test_out_file, .{
......@@ -1333,8 +1333,8 @@ test "cache file and then recall it" {
13331333
13341334 // Wait for file timestamps to tick
13351335 const initial_time = try testGetCurrentFileTimestamp(tmp.dir);
1336 while ((try testGetCurrentFileTimestamp(tmp.dir)) == initial_time) {
1337 try std.Io.Duration.sleep(.fromNanoseconds(1), io);
1336 while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time.nanoseconds) {
1337 try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io);
13381338 }
13391339
13401340 var digest1: HexDigest = undefined;
......@@ -1399,8 +1399,8 @@ test "check that changing a file makes cache fail" {
13991399
14001400 // Wait for file timestamps to tick
14011401 const initial_time = try testGetCurrentFileTimestamp(tmp.dir);
1402 while ((try testGetCurrentFileTimestamp(tmp.dir)) == initial_time) {
1403 try std.Io.Duration.sleep(.fromNanoseconds(1), io);
1402 while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time.nanoseconds) {
1403 try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io);
14041404 }
14051405
14061406 var digest1: HexDigest = undefined;
......@@ -1517,8 +1517,8 @@ test "Manifest with files added after initial hash work" {
15171517
15181518 // Wait for file timestamps to tick
15191519 const initial_time = try testGetCurrentFileTimestamp(tmp.dir);
1520 while ((try testGetCurrentFileTimestamp(tmp.dir)) == initial_time) {
1521 try std.Io.Duration.sleep(.fromNanoseconds(1), io);
1520 while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time.nanoseconds) {
1521 try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io);
15221522 }
15231523
15241524 var digest1: HexDigest = undefined;
......@@ -1568,8 +1568,8 @@ test "Manifest with files added after initial hash work" {
15681568
15691569 // Wait for file timestamps to tick
15701570 const initial_time2 = try testGetCurrentFileTimestamp(tmp.dir);
1571 while ((try testGetCurrentFileTimestamp(tmp.dir)) == initial_time2) {
1572 try std.Io.Duration.sleep(.fromNanoseconds(1), io);
1571 while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time2.nanoseconds) {
1572 try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io);
15731573 }
15741574
15751575 {
lib/std/Io.zig+23-11
......@@ -654,20 +654,20 @@ pub const VTable = struct {
654654 conditionWait: *const fn (?*anyopaque, cond: *Condition, mutex: *Mutex) Cancelable!void,
655655 conditionWake: *const fn (?*anyopaque, cond: *Condition, wake: Condition.Wake) void,
656656
657 dirMake: *const fn (?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void,
658 dirStat: *const fn (?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat,
659 dirStatPath: *const fn (?*anyopaque, dir: Dir, sub_path: []const u8) Dir.StatError!File.Stat,
660 fileStat: *const fn (?*anyopaque, file: File) File.StatError!File.Stat,
661 createFile: *const fn (?*anyopaque, dir: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File,
662 fileOpen: *const fn (?*anyopaque, dir: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File,
657 dirMake: *const fn (?*anyopaque, Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void,
658 dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat,
659 dirStatPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat,
660 fileStat: *const fn (?*anyopaque, File) File.StatError!File.Stat,
661 createFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.CreateFlags) File.OpenError!File,
662 fileOpen: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.OpenFlags) File.OpenError!File,
663663 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,
665665 /// 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,
667667 /// Returns 0 on end of stream.
668 fileReadPositional: *const fn (?*anyopaque, file: File, data: [][]u8, offset: u64) File.ReadPositionalError!usize,
669 fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void,
670 fileSeekTo: *const fn (?*anyopaque, file: File, offset: u64) File.SeekError!void,
668 fileReadPositional: *const fn (?*anyopaque, File, data: [][]u8, offset: u64) File.ReadPositionalError!usize,
669 fileSeekBy: *const fn (?*anyopaque, File, offset: i64) File.SeekError!void,
670 fileSeekTo: *const fn (?*anyopaque, File, offset: u64) File.SeekError!void,
671671
672672 now: *const fn (?*anyopaque, Clock) Clock.Error!Timestamp,
673673 sleep: *const fn (?*anyopaque, Timeout) SleepError!void,
......@@ -795,6 +795,14 @@ pub const Clock = enum {
795795 };
796796 }
797797
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
798806 pub fn fromNow(io: Io, duration: Clock.Duration) Error!Clock.Timestamp {
799807 return .{
800808 .clock = duration.clock,
......@@ -855,6 +863,10 @@ pub const Timestamp = struct {
855863 return .{ .nanoseconds = from.nanoseconds + duration.nanoseconds };
856864 }
857865
866 pub fn subDuration(from: Timestamp, duration: Duration) Timestamp {
867 return .{ .nanoseconds = from.nanoseconds - duration.nanoseconds };
868 }
869
858870 pub fn withClock(t: Timestamp, clock: Clock) Clock.Timestamp {
859871 return .{ .nanoseconds = t.nanoseconds, .clock = clock };
860872 }
lib/std/Io/Dir.zig+31-11
......@@ -15,6 +15,29 @@ pub fn cwd() Dir {
1515
1616pub const Handle = std.posix.fd_t;
1717
18pub 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
26pub 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
1841pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
1942 return io.vtable.fileOpen(io.userdata, dir, sub_path, flags);
2043}
......@@ -149,22 +172,15 @@ pub const MakeError = error{
149172 PathAlreadyExists,
150173 SymLinkLoop,
151174 LinkQuotaExceeded,
152 NameTooLong,
153175 FileNotFound,
154176 SystemResources,
155177 NoSpaceLeft,
156178 NotDir,
157179 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,
162180 NoDevice,
163181 /// On Windows, `\\server` or `\\server\share` was not found.
164182 NetworkNotFound,
165 /// File system cannot encode the requested file name bytes.
166 InvalidFileName,
167} || Io.Cancelable || Io.UnexpectedError;
183} || PathNameError || Io.Cancelable || Io.UnexpectedError;
168184
169185/// Creates a single directory with a relative or absolute path.
170186///
......@@ -225,7 +241,7 @@ pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8) MakePathError!Make
225241 // could cause an infinite loop
226242 check_dir: {
227243 // 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) {
229245 error.IsDir => break :check_dir,
230246 else => |e| return e,
231247 };
......@@ -251,6 +267,10 @@ pub fn stat(dir: Dir, io: Io) StatError!Stat {
251267
252268pub const StatPathError = File.OpenError || File.StatError;
253269
270pub const StatPathOptions = struct {
271 follow_symlinks: bool = true,
272};
273
254274/// Returns metadata for a file inside the directory.
255275///
256276/// On Windows, this requires three syscalls. On other operating systems, it
......@@ -263,6 +283,6 @@ pub const StatPathError = File.OpenError || File.StatError;
263283/// * On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
264284/// * On WASI, `sub_path` should be encoded as valid UTF-8.
265285/// * On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
266pub fn statPath(dir: Dir, io: Io, sub_path: []const u8) StatPathError!Stat {
267 return io.vtable.dirStatPath(io.userdata, dir, sub_path);
286pub fn statPath(dir: Dir, io: Io, sub_path: []const u8, options: StatPathOptions) StatPathError!Stat {
287 return io.vtable.dirStatPath(io.userdata, dir, sub_path, options);
268288}
lib/std/Io/File.zig+57-1
......@@ -81,7 +81,63 @@ pub fn stat(file: File, io: Io) StatError!Stat {
8181pub const OpenFlags = std.fs.File.OpenFlags;
8282pub const CreateFlags = std.fs.File.CreateFlags;
8383
84pub const OpenError = std.fs.File.OpenError || Io.Cancelable;
84pub 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;
85141
86142pub fn close(file: File, io: Io) void {
87143 return io.vtable.fileClose(io.userdata, file);
lib/std/Io/Threaded.zig+206-16
......@@ -166,14 +166,23 @@ pub fn io(pool: *Pool) Io {
166166 else => dirMakePosix,
167167 },
168168 .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 },
170175 .fileStat = switch (builtin.os.tag) {
171176 .linux => fileStatLinux,
172177 .windows => fileStatWindows,
173178 .wasi => fileStatWasi,
174179 else => fileStatPosix,
175180 },
176 .createFile = createFile,
181 .createFile = switch (builtin.os.tag) {
182 .windows => @panic("TODO"),
183 .wasi => @panic("TODO"),
184 else => createFilePosix,
185 },
177186 .fileOpen = fileOpen,
178187 .fileClose = fileClose,
179188 .pwrite = pwrite,
......@@ -765,8 +774,10 @@ fn conditionWake(userdata: ?*anyopaque, cond: *Io.Condition, wake: Io.Condition.
765774
766775fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
767776 const pool: *Pool = @ptrCast(@alignCast(userdata));
777
768778 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
770781 while (true) {
771782 try pool.checkCancel();
772783 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:
788799 .ROFS => return error.ReadOnlyFileSystem,
789800 // dragonfly: when dir_fd is unlinked from filesystem
790801 .NOTCONN => return error.FileNotFound,
791 .ILSEQ => return error.InvalidFileName,
802 .ILSEQ => return error.BadPathName,
792803 else => |err| return posix.unexpectedErrno(err),
793804 }
794805 }
......@@ -802,13 +813,82 @@ fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {
802813 @panic("TODO");
803814}
804815
805fn dirStatPath(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8) Io.Dir.StatError!Io.File.Stat {
816fn 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 {
806822 const pool: *Pool = @ptrCast(@alignCast(userdata));
807 try pool.checkCancel();
823 const linux = std.os.linux;
808824
809 _ = dir;
810 _ = sub_path;
811 @panic("TODO");
825 var path_buffer: [posix.PATH_MAX]u8 = undefined;
826 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
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
858fn 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 }
812892}
813893
814894fn 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.
885965 }
886966}
887967
888fn createFile(
968const have_flock = @TypeOf(posix.system.flock) != void;
969
970fn createFilePosix(
889971 userdata: ?*anyopaque,
890972 dir: Io.Dir,
891973 sub_path: []const u8,
892974 flags: Io.File.CreateFlags,
893975) Io.File.OpenError!Io.File {
894976 const pool: *Pool = @ptrCast(@alignCast(userdata));
895 try pool.checkCancel();
896 const fs_dir: std.fs.Dir = .{ .fd = dir.handle };
897 const fs_file = try fs_dir.createFile(sub_path, flags);
898 return .{ .handle = fs_file.handle };
977
978 var path_buffer: [posix.PATH_MAX]u8 = undefined;
979 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
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 };
8991089}
9001090
9011091fn fileOpen(
......@@ -2293,8 +2483,8 @@ fn timestampToPosix(nanoseconds: i96) std.posix.timespec {
22932483 };
22942484}
22952485
2296fn toPosixPath(file_path: []const u8, buffer: *[posix.PATH_MAX]u8) error{ NameTooLong, InvalidFileName }![:0]u8 {
2297 if (std.mem.containsAtLeastScalar2(u8, file_path, 0, 1)) return error.InvalidFileName;
2486fn pathToPosix(file_path: []const u8, buffer: *[posix.PATH_MAX]u8) Io.Dir.PathNameError![:0]u8 {
2487 if (std.mem.containsAtLeastScalar2(u8, file_path, 0, 1)) return error.BadPathName;
22982488 // >= rather than > to make room for the null byte
22992489 if (file_path.len >= buffer.len) return error.NameTooLong;
23002490 @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();
1111const tmpDir = std.testing.tmpDir;
1212
1313test "write a file, read it, then delete it" {
14 const io = std.testing.io;
15
1416 var tmp = tmpDir(.{});
1517 defer tmp.cleanup();
1618
......@@ -45,7 +47,7 @@ test "write a file, read it, then delete it" {
4547 try expectEqual(expected_file_size, file_size);
4648
4749 var file_buffer: [1024]u8 = undefined;
48 var file_reader = file.reader(&file_buffer);
50 var file_reader = file.reader(io, &file_buffer);
4951 const contents = try file_reader.interface.allocRemaining(std.testing.allocator, .limited(2 * 1024));
5052 defer std.testing.allocator.free(contents);
5153
......@@ -114,10 +116,10 @@ test "updateTimes" {
114116 const stat_old = try file.stat();
115117 // Set atime and mtime to 5s before
116118 try file.updateTimes(
117 stat_old.atime - 5 * std.time.ns_per_s,
118 stat_old.mtime - 5 * std.time.ns_per_s,
119 stat_old.atime.subDuration(.fromSeconds(5)),
120 stat_old.mtime.subDuration(.fromSeconds(5)),
119121 );
120122 const stat_new = try file.stat();
121 try expect(stat_new.atime < stat_old.atime);
122 try expect(stat_new.mtime < stat_old.mtime);
123 try expect(stat_new.atime.nanoseconds < stat_old.atime.nanoseconds);
124 try expect(stat_new.mtime.nanoseconds < stat_old.mtime.nanoseconds);
123125}
lib/std/Thread.zig+4-1
......@@ -318,10 +318,13 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
318318 var buf: [32]u8 = undefined;
319319 const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()});
320320
321 var threaded: std.Io.Threaded = .init_single_threaded;
322 const io = threaded.io();
323
321324 const file = try std.fs.cwd().openFile(path, .{});
322325 defer file.close();
323326
324 var file_reader = file.readerStreaming(&.{});
327 var file_reader = file.readerStreaming(io, &.{});
325328 const data_len = file_reader.interface.readSliceShort(buffer_ptr[0 .. max_name_len + 1]) catch |err| switch (err) {
326329 error.ReadFailed => return file_reader.err.?,
327330 };
lib/std/Thread/Condition.zig+7-8
......@@ -123,14 +123,9 @@ const SingleThreadedImpl = struct {
123123 fn wait(self: *Impl, mutex: *Mutex, timeout: ?u64) error{Timeout}!void {
124124 _ = self;
125125 _ = mutex;
126
127126 // There are no other threads to wake us up.
128127 // So if we wait without a timeout we would never wake up.
129 const timeout_ns = timeout orelse {
130 unreachable; // deadlock detected
131 };
132
133 std.Thread.sleep(timeout_ns);
128 assert(timeout != null); // Deadlock detected.
134129 return error.Timeout;
135130 }
136131
......@@ -323,6 +318,8 @@ test "wait and signal" {
323318 return error.SkipZigTest;
324319 }
325320
321 const io = testing.io;
322
326323 const num_threads = 4;
327324
328325 const MultiWait = struct {
......@@ -348,7 +345,7 @@ test "wait and signal" {
348345 }
349346
350347 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);
352349
353350 multi_wait.mutex.lock();
354351 defer multi_wait.mutex.unlock();
......@@ -368,6 +365,8 @@ test signal {
368365 return error.SkipZigTest;
369366 }
370367
368 const io = testing.io;
369
371370 const num_threads = 4;
372371
373372 const SignalTest = struct {
......@@ -405,7 +404,7 @@ test signal {
405404 }
406405
407406 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);
409408
410409 signal_test.mutex.lock();
411410 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
441441 };
442442}
443443
444fn validateHost(bytes: []const u8) []const u8 {
444fn validateHost(bytes: []const u8) HostName.ValidateError![]const u8 {
445445 try HostName.validate(bytes);
446446 return bytes;
447447}
lib/std/dynamic_library.zig+1
......@@ -137,6 +137,7 @@ const ElfDynLibError = error{
137137 ElfStringSectionNotFound,
138138 ElfSymSectionNotFound,
139139 ElfHashTableNotFound,
140 Canceled,
140141} || posix.OpenError || posix.MMapError;
141142
142143pub const ElfDynLib = struct {
lib/std/fs/Dir.zig+16-74
......@@ -36,10 +36,6 @@ const IteratorError = error{
3636 AccessDenied,
3737 PermissionDenied,
3838 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,
4339} || posix.UnexpectedError;
4440
4541pub const Iterator = switch (native_os) {
......@@ -553,7 +549,6 @@ pub const Iterator = switch (native_os) {
553549 .INVAL => unreachable,
554550 .NOENT => return error.DirNotFound, // The directory being iterated was deleted during iteration.
555551 .NOTCAPABLE => return error.AccessDenied,
556 .ILSEQ => return error.InvalidUtf8, // An entry's name cannot be encoded as UTF-8.
557552 else => |err| return posix.unexpectedErrno(err),
558553 }
559554 if (bufused == 0) return null;
......@@ -844,28 +839,7 @@ pub fn walk(self: Dir, allocator: Allocator) Allocator.Error!Walker {
844839 };
845840}
846841
847pub const OpenError = error{
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;
842pub const OpenError = Io.Dir.OpenError;
869843
870844pub fn close(self: *Dir) void {
871845 posix.close(self.fd);
......@@ -1311,7 +1285,7 @@ pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenOptio
13111285 };
13121286}
13131287
1314pub const RealPathError = posix.RealPathError;
1288pub const RealPathError = posix.RealPathError || error{Canceled};
13151289
13161290/// This function returns the canonicalized absolute pathname of
13171291/// `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
13691343 error.FileLocksNotSupported => return error.Unexpected,
13701344 error.FileBusy => return error.Unexpected,
13711345 error.WouldBlock => return error.Unexpected,
1372 error.InvalidUtf8 => unreachable, // WASI-only
13731346 else => |e| return e,
13741347 };
13751348 defer posix.close(fd);
......@@ -1639,6 +1612,10 @@ fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: posix.O) OpenError
16391612 error.FileLocksNotSupported => unreachable, // locking folders is not supported
16401613 error.WouldBlock => unreachable, // can't happen for directories
16411614 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
16421619 else => |e| return e,
16431620 };
16441621 return Dir{ .fd = fd };
......@@ -2095,24 +2072,21 @@ pub const DeleteTreeError = error{
20952072 FileBusy,
20962073 DeviceBusy,
20972074 ProcessNotFound,
2098
20992075 /// One of the path components was not a directory.
21002076 /// This error is unreachable if `sub_path` does not contain a path separator.
21012077 NotDir,
2102
21032078 /// WASI-only; file paths must be valid UTF-8.
21042079 InvalidUtf8,
2105
21062080 /// Windows-only; file paths provided by the user must be valid WTF-8.
21072081 /// https://wtf-8.codeberg.page/
21082082 InvalidWtf8,
2109
21102083 /// On Windows, file paths cannot contain these characters:
21112084 /// '/', '*', '?', '"', '<', '>', '|'
21122085 BadPathName,
2113
21142086 /// On Windows, `\\server` or `\\server\share` was not found.
21152087 NetworkNotFound,
2088
2089 Canceled,
21162090} || posix.UnexpectedError;
21172091
21182092/// 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 {
21692143 error.PermissionDenied,
21702144 error.SymLinkLoop,
21712145 error.ProcessFdQuotaExceeded,
2172 error.ProcessNotFound,
21732146 error.NameTooLong,
21742147 error.SystemFdQuotaExceeded,
21752148 error.NoDevice,
21762149 error.SystemResources,
21772150 error.Unexpected,
2178 error.InvalidUtf8,
2179 error.InvalidWtf8,
21802151 error.BadPathName,
21812152 error.NetworkNotFound,
21822153 error.DeviceBusy,
2154 error.Canceled,
21832155 => |e| return e,
21842156 };
21852157 stack.appendAssumeCapacity(.{
......@@ -2266,18 +2238,16 @@ pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void {
22662238 error.AccessDenied,
22672239 error.PermissionDenied,
22682240 error.SymLinkLoop,
2269 error.ProcessNotFound,
22702241 error.ProcessFdQuotaExceeded,
22712242 error.NameTooLong,
22722243 error.SystemFdQuotaExceeded,
22732244 error.NoDevice,
22742245 error.SystemResources,
22752246 error.Unexpected,
2276 error.InvalidUtf8,
2277 error.InvalidWtf8,
22782247 error.BadPathName,
22792248 error.NetworkNotFound,
22802249 error.DeviceBusy,
2250 error.Canceled,
22812251 => |e| return e,
22822252 };
22832253 } else {
......@@ -2374,18 +2344,16 @@ fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint
23742344 error.AccessDenied,
23752345 error.PermissionDenied,
23762346 error.SymLinkLoop,
2377 error.ProcessNotFound,
23782347 error.ProcessFdQuotaExceeded,
23792348 error.NameTooLong,
23802349 error.SystemFdQuotaExceeded,
23812350 error.NoDevice,
23822351 error.SystemResources,
23832352 error.Unexpected,
2384 error.InvalidUtf8,
2385 error.InvalidWtf8,
23862353 error.BadPathName,
23872354 error.NetworkNotFound,
23882355 error.DeviceBusy,
2356 error.Canceled,
23892357 => |e| return e,
23902358 };
23912359 if (cleanup_dir_parent) |*d| d.close();
......@@ -2476,17 +2444,15 @@ fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File
24762444 error.PermissionDenied,
24772445 error.SymLinkLoop,
24782446 error.ProcessFdQuotaExceeded,
2479 error.ProcessNotFound,
24802447 error.NameTooLong,
24812448 error.SystemFdQuotaExceeded,
24822449 error.NoDevice,
24832450 error.SystemResources,
24842451 error.Unexpected,
2485 error.InvalidUtf8,
2486 error.InvalidWtf8,
24872452 error.BadPathName,
24882453 error.DeviceBusy,
24892454 error.NetworkNotFound,
2455 error.Canceled,
24902456 => |e| return e,
24912457 };
24922458 } else {
......@@ -2589,7 +2555,7 @@ pub const CopyFileOptions = struct {
25892555
25902556pub const CopyFileError = File.OpenError || File.StatError ||
25912557 AtomicFile.InitError || AtomicFile.FinishError ||
2592 File.ReadError || File.WriteError;
2558 File.ReadError || File.WriteError || error{InvalidFileName};
25932559
25942560/// Atomically creates a new file at `dest_path` within `dest_dir` with the
25952561/// 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 {
26902656 const st = try std.os.fstatat_wasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true });
26912657 return Stat.fromWasi(st);
26922658 }
2693 if (native_os == .linux) {
2694 const sub_path_c = try posix.toPosixPath(sub_path);
2695 var stx = std.mem.zeroes(linux.Statx);
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);
2659 var threaded: Io.Threaded = .init_single_threaded;
2660 const io = threaded.io();
2661 return Io.Dir.statPath(.{ .handle = self.fd }, io, sub_path, .{});
27202662}
27212663
27222664pub const ChmodError = File.ChmodError;
lib/std/fs/File.zig+2-27
......@@ -38,33 +38,8 @@ pub const default_mode = switch (builtin.os.tag) {
3838 else => 0o666,
3939};
4040
41pub const OpenError = error{
42 SharingViolation,
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;
41/// Deprecated in favor of `Io.File.OpenError`.
42pub const OpenError = Io.File.OpenError || error{WouldBlock};
6843
6944pub const OpenMode = enum {
7045 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
15421542 }
15431543}
15441544
1545pub const OpenError = error{
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;
1545pub const OpenError = std.Io.File.OpenError || error{WouldBlock};
16201546
16211547/// Open and possibly create a file. Keeps trying if it gets interrupted.
16221548/// 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 {
766766
767767fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion {
768768 var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) {
769 error.NameTooLong => unreachable,
770 error.InvalidUtf8 => unreachable, // WASI only
771 error.InvalidWtf8 => unreachable, // Windows-only
772 error.BadPathName => unreachable,
773 error.DeviceBusy => unreachable,
774 error.NetworkNotFound => unreachable, // Windows-only
775
776 error.FileNotFound,
777 error.NotDir,
778 error.AccessDenied,
779 error.PermissionDenied,
780 error.NoDevice,
781 => return error.GLibCNotFound,
782
783 error.ProcessNotFound,
784 error.ProcessFdQuotaExceeded,
785 error.SystemFdQuotaExceeded,
786 error.SystemResources,
787 error.SymLinkLoop,
788 error.Unexpected,
789 => |e| return e,
769 error.NameTooLong => return error.Unexpected,
770 error.BadPathName => return error.Unexpected,
771 error.DeviceBusy => return error.Unexpected,
772 error.NetworkNotFound => return error.Unexpected, // Windows-only
773
774 error.FileNotFound => return error.GLibCNotFound,
775 error.NotDir => return error.GLibCNotFound,
776 error.AccessDenied => return error.GLibCNotFound,
777 error.PermissionDenied => return error.GLibCNotFound,
778 error.NoDevice => return error.GLibCNotFound,
779
780 error.ProcessFdQuotaExceeded => |e| return e,
781 error.SystemFdQuotaExceeded => |e| return e,
782 error.SystemResources => |e| return e,
783 error.SymLinkLoop => |e| return e,
784 error.Unexpected => |e| return e,
785 error.Canceled => |e| return e,
790786 };
791787 defer dir.close();
792788
......@@ -799,38 +795,34 @@ fn glibcVerFromRPath(io: Io, rpath: []const u8) !std.SemanticVersion {
799795 // that start with "GLIBC_2.".
800796 const glibc_so_basename = "libc.so.6";
801797 var file = dir.openFile(glibc_so_basename, .{}) catch |err| switch (err) {
802 error.NameTooLong => unreachable,
803 error.InvalidUtf8 => unreachable, // WASI only
804 error.InvalidWtf8 => unreachable, // Windows only
805 error.BadPathName => unreachable, // Windows only
806 error.PipeBusy => unreachable, // Windows-only
807 error.SharingViolation => unreachable, // Windows-only
808 error.NetworkNotFound => unreachable, // Windows-only
809 error.AntivirusInterference => unreachable, // Windows-only
810 error.FileLocksNotSupported => unreachable, // No lock requested.
811 error.NoSpaceLeft => unreachable, // read-only
812 error.PathAlreadyExists => unreachable, // read-only
813 error.DeviceBusy => unreachable, // read-only
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
798 error.NameTooLong => return error.Unexpected,
799 error.BadPathName => return error.Unexpected,
800 error.PipeBusy => return error.Unexpected, // Windows-only
801 error.SharingViolation => return error.Unexpected, // Windows-only
802 error.NetworkNotFound => return error.Unexpected, // Windows-only
803 error.AntivirusInterference => return error.Unexpected, // Windows-only
804 error.FileLocksNotSupported => return error.Unexpected, // No lock requested.
805 error.NoSpaceLeft => return error.Unexpected, // read-only
806 error.PathAlreadyExists => return error.Unexpected, // read-only
807 error.DeviceBusy => return error.Unexpected, // read-only
808 error.FileBusy => return error.Unexpected, // read-only
809 error.NoDevice => return error.Unexpected, // not asking for a special device
825810 error.FileTooBig => return error.Unexpected,
826
827 error.ProcessNotFound,
828 error.ProcessFdQuotaExceeded,
829 error.SystemFdQuotaExceeded,
830 error.SystemResources,
831 error.SymLinkLoop,
832 error.Unexpected,
833 => |e| return e,
811 error.WouldBlock => return error.Unexpected, // not opened in non-blocking
812
813 error.AccessDenied => return error.GLibCNotFound,
814 error.PermissionDenied => return error.GLibCNotFound,
815 error.FileNotFound => return error.GLibCNotFound,
816 error.NotDir => return error.GLibCNotFound,
817 error.IsDir => return error.GLibCNotFound,
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,
834826 };
835827 defer file.close();
836828
......@@ -1016,12 +1008,9 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
10161008 error.NameTooLong => return error.Unexpected,
10171009 error.PathAlreadyExists => return error.Unexpected,
10181010 error.SharingViolation => return error.Unexpected,
1019 error.InvalidUtf8 => return error.Unexpected, // WASI only
1020 error.InvalidWtf8 => return error.Unexpected, // Windows only
10211011 error.BadPathName => return error.Unexpected,
10221012 error.PipeBusy => return error.Unexpected,
10231013 error.FileLocksNotSupported => return error.Unexpected,
1024 error.WouldBlock => return error.Unexpected,
10251014 error.FileBusy => return error.Unexpected, // opened without write permissions
10261015 error.AntivirusInterference => return error.Unexpected, // Windows-only error
10271016