authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-09 00:47:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:49-07:00
logb1733b7bcec44ddd73a210ede09c3c9eeb411d27
tree2d60aeac5fd30893103c1f6e852ce4a46314318e
parent8a1e6c8c394058a25cb21f60ad414f28cd37db22

std.Io: implement dirOpenFile


5 files changed, 140 insertions(+), 229 deletions(-)

lib/std/Io.zig+2-2
......@@ -657,9 +657,9 @@ pub const VTable = struct {
657657 dirMake: *const fn (?*anyopaque, Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void,
658658 dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat,
659659 dirStatPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat,
660 dirCreateFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.CreateFlags) File.OpenError!File,
661 dirOpenFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.OpenFlags) File.OpenError!File,
660662 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,
664664 pwrite: *const fn (?*anyopaque, File, buffer: []const u8, offset: std.posix.off_t) File.PWriteError!usize,
665665 /// Returns 0 on end of stream.
lib/std/Io/Dir.zig+2-2
......@@ -39,11 +39,11 @@ pub const OpenError = error{
3939} || PathNameError || Io.Cancelable || Io.UnexpectedError;
4040
4141pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
42 return io.vtable.fileOpen(io.userdata, dir, sub_path, flags);
42 return io.vtable.dirOpenFile(io.userdata, dir, sub_path, flags);
4343}
4444
4545pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
46 return io.vtable.createFile(io.userdata, dir, sub_path, flags);
46 return io.vtable.dirCreateFile(io.userdata, dir, sub_path, flags);
4747}
4848
4949pub const WriteFileOptions = struct {
lib/std/Io/Threaded.zig+127-13
......@@ -178,12 +178,12 @@ pub fn io(pool: *Pool) Io {
178178 .wasi => fileStatWasi,
179179 else => fileStatPosix,
180180 },
181 .createFile = switch (builtin.os.tag) {
181 .dirCreateFile = switch (builtin.os.tag) {
182182 .windows => @panic("TODO"),
183183 .wasi => @panic("TODO"),
184 else => createFilePosix,
184 else => dirCreateFilePosix,
185185 },
186 .fileOpen = fileOpen,
186 .dirOpenFile = dirOpenFile,
187187 .fileClose = fileClose,
188188 .pwrite = pwrite,
189189 .fileReadStreaming = fileReadStreaming,
......@@ -966,8 +966,9 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.
966966}
967967
968968const have_flock = @TypeOf(posix.system.flock) != void;
969const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat;
969970
970fn createFilePosix(
971fn dirCreateFilePosix(
971972 userdata: ?*anyopaque,
972973 dir: Io.Dir,
973974 sub_path: []const u8,
......@@ -1003,8 +1004,6 @@ fn createFilePosix(
10031004 },
10041005 };
10051006
1006 const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat;
1007
10081007 const fd: posix.fd_t = while (true) {
10091008 try pool.checkCancel();
10101009 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);
......@@ -1088,24 +1087,139 @@ fn createFilePosix(
10881087 return .{ .handle = fd };
10891088}
10901089
1091fn fileOpen(
1090fn dirOpenFile(
10921091 userdata: ?*anyopaque,
10931092 dir: Io.Dir,
10941093 sub_path: []const u8,
10951094 flags: Io.File.OpenFlags,
10961095) Io.File.OpenError!Io.File {
10971096 const pool: *Pool = @ptrCast(@alignCast(userdata));
1098 try pool.checkCancel();
1099 const fs_dir: std.fs.Dir = .{ .fd = dir.handle };
1100 const fs_file = try fs_dir.openFile(sub_path, flags);
1101 return .{ .handle = fs_file.handle };
1097
1098 var path_buffer: [posix.PATH_MAX]u8 = undefined;
1099 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
1100
1101 var os_flags: posix.O = switch (native_os) {
1102 .wasi => .{
1103 .read = flags.mode != .write_only,
1104 .write = flags.mode != .read_only,
1105 },
1106 else => .{
1107 .ACCMODE = switch (flags.mode) {
1108 .read_only => .RDONLY,
1109 .write_only => .WRONLY,
1110 .read_write => .RDWR,
1111 },
1112 },
1113 };
1114 if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
1115 if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
1116 if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty;
1117
1118 // Use the O locking flags if the os supports them to acquire the lock
1119 // atomically.
1120 const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
1121 if (has_flock_open_flags) {
1122 // Note that the NONBLOCK flag is removed after the openat() call
1123 // is successful.
1124 switch (flags.lock) {
1125 .none => {},
1126 .shared => {
1127 os_flags.SHLOCK = true;
1128 os_flags.NONBLOCK = flags.lock_nonblocking;
1129 },
1130 .exclusive => {
1131 os_flags.EXLOCK = true;
1132 os_flags.NONBLOCK = flags.lock_nonblocking;
1133 },
1134 }
1135 }
1136 const fd: posix.fd_t = while (true) {
1137 try pool.checkCancel();
1138 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, 0);
1139 switch (posix.errno(rc)) {
1140 .SUCCESS => break @intCast(rc),
1141 .INTR => continue,
1142
1143 .FAULT => |err| return errnoBug(err),
1144 .INVAL => return error.BadPathName,
1145 .BADF => |err| return errnoBug(err),
1146 .ACCES => return error.AccessDenied,
1147 .FBIG => return error.FileTooBig,
1148 .OVERFLOW => return error.FileTooBig,
1149 .ISDIR => return error.IsDir,
1150 .LOOP => return error.SymLinkLoop,
1151 .MFILE => return error.ProcessFdQuotaExceeded,
1152 .NAMETOOLONG => return error.NameTooLong,
1153 .NFILE => return error.SystemFdQuotaExceeded,
1154 .NODEV => return error.NoDevice,
1155 .NOENT => return error.FileNotFound,
1156 .SRCH => return error.ProcessNotFound,
1157 .NOMEM => return error.SystemResources,
1158 .NOSPC => return error.NoSpaceLeft,
1159 .NOTDIR => return error.NotDir,
1160 .PERM => return error.PermissionDenied,
1161 .EXIST => return error.PathAlreadyExists,
1162 .BUSY => return error.DeviceBusy,
1163 .OPNOTSUPP => return error.FileLocksNotSupported,
1164 //.AGAIN => return error.WouldBlock,
1165 .TXTBSY => return error.FileBusy,
1166 .NXIO => return error.NoDevice,
1167 .ILSEQ => return error.BadPathName,
1168 else => |err| return posix.unexpectedErrno(err),
1169 }
1170 };
1171 errdefer posix.close(fd);
1172
1173 if (have_flock and !has_flock_open_flags and flags.lock != .none) {
1174 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
1175 const lock_flags = switch (flags.lock) {
1176 .none => unreachable,
1177 .shared => posix.LOCK.SH | lock_nonblocking,
1178 .exclusive => posix.LOCK.EX | lock_nonblocking,
1179 };
1180 while (true) {
1181 try pool.checkCancel();
1182 switch (posix.errno(posix.system.flock(fd, lock_flags))) {
1183 .SUCCESS => break,
1184 .INTR => continue,
1185
1186 .BADF => |err| return errnoBug(err),
1187 .INVAL => |err| return errnoBug(err), // invalid parameters
1188 .NOLCK => return error.SystemResources,
1189 //.AGAIN => return error.WouldBlock,
1190 .OPNOTSUPP => return error.FileLocksNotSupported,
1191 else => |err| return posix.unexpectedErrno(err),
1192 }
1193 }
1194 }
1195
1196 if (has_flock_open_flags and flags.lock_nonblocking) {
1197 var fl_flags: usize = while (true) {
1198 try pool.checkCancel();
1199 switch (posix.errno(posix.system.fcntl(fd, posix.F.GETFL, 0))) {
1200 .SUCCESS => break,
1201 .INTR => continue,
1202 else => |err| return posix.unexpectedErrno(err),
1203 }
1204 };
1205 fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
1206 while (true) {
1207 try pool.checkCancel();
1208 switch (posix.errno(posix.fcntl(fd, posix.F.SETFL, fl_flags))) {
1209 .SUCCESS => break,
1210 .INTR => continue,
1211 else => |err| return posix.unexpectedErrno(err),
1212 }
1213 }
1214 }
1215
1216 return .{ .handle = fd };
11021217}
11031218
11041219fn fileClose(userdata: ?*anyopaque, file: Io.File) void {
11051220 const pool: *Pool = @ptrCast(@alignCast(userdata));
11061221 _ = pool;
1107 const fs_file: std.fs.File = .{ .handle = file.handle };
1108 return fs_file.close();
1222 posix.close(file.handle);
11091223}
11101224
11111225fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.ReadStreamingError!usize {
lib/std/fs.zig+2-48
......@@ -260,12 +260,6 @@ pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.O
260260 return cwd().openFile(absolute_path, flags);
261261}
262262
263/// Same as `openFileAbsolute` but the path parameter is null-terminated.
264pub fn openFileAbsoluteZ(absolute_path_c: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
265 assert(path.isAbsoluteZ(absolute_path_c));
266 return cwd().openFileZ(absolute_path_c, flags);
267}
268
269263/// Same as `openFileAbsolute` but the path parameter is WTF-16-encoded.
270264pub fn openFileAbsoluteW(absolute_path_w: []const u16, flags: File.OpenFlags) File.OpenError!File {
271265 assert(path.isAbsoluteWindowsWTF16(absolute_path_w));
......@@ -284,11 +278,6 @@ pub fn accessAbsolute(absolute_path: []const u8, flags: File.OpenFlags) Dir.Acce
284278 assert(path.isAbsolute(absolute_path));
285279 try cwd().access(absolute_path, flags);
286280}
287/// Same as `accessAbsolute` but the path parameter is null-terminated.
288pub fn accessAbsoluteZ(absolute_path: [*:0]const u8, flags: File.OpenFlags) Dir.AccessError!void {
289 assert(path.isAbsoluteZ(absolute_path));
290 try cwd().accessZ(absolute_path, flags);
291}
292281/// Same as `accessAbsolute` but the path parameter is WTF-16 encoded.
293282pub fn accessAbsoluteW(absolute_path: [*:0]const u16, flags: File.OpenFlags) Dir.AccessError!void {
294283 assert(path.isAbsoluteWindowsW(absolute_path));
......@@ -309,12 +298,6 @@ pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) Fi
309298 return cwd().createFile(absolute_path, flags);
310299}
311300
312/// Same as `createFileAbsolute` but the path parameter is null-terminated.
313pub fn createFileAbsoluteZ(absolute_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
314 assert(path.isAbsoluteZ(absolute_path_c));
315 return cwd().createFileZ(absolute_path_c, flags);
316}
317
318301/// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded.
319302pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File {
320303 assert(path.isAbsoluteWindowsW(absolute_path_w));
......@@ -333,12 +316,6 @@ pub fn deleteFileAbsolute(absolute_path: []const u8) Dir.DeleteFileError!void {
333316 return cwd().deleteFile(absolute_path);
334317}
335318
336/// Same as `deleteFileAbsolute` except the parameter is null-terminated.
337pub fn deleteFileAbsoluteZ(absolute_path_c: [*:0]const u8) Dir.DeleteFileError!void {
338 assert(path.isAbsoluteZ(absolute_path_c));
339 return cwd().deleteFileZ(absolute_path_c);
340}
341
342319/// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded.
343320pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) Dir.DeleteFileError!void {
344321 assert(path.isAbsoluteWindowsW(absolute_path_w));
......@@ -383,12 +360,6 @@ pub fn readlinkAbsoluteW(pathname_w: [*:0]const u16, buffer: *[max_path_bytes]u8
383360 return posix.readlinkW(mem.span(pathname_w), buffer);
384361}
385362
386/// Same as `readLink`, except the path parameter is null-terminated.
387pub fn readLinkAbsoluteZ(pathname_c: [*:0]const u8, buffer: *[max_path_bytes]u8) ![]u8 {
388 assert(path.isAbsoluteZ(pathname_c));
389 return posix.readlinkZ(pathname_c, buffer);
390}
391
392363/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
393364/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
394365/// one; the latter case is known as a dangling link.
......@@ -426,28 +397,11 @@ pub fn symLinkAbsoluteW(
426397 return windows.CreateSymbolicLink(null, mem.span(sym_link_path_w), mem.span(target_path_w), flags.is_directory);
427398}
428399
429/// Same as `symLinkAbsolute` except the parameters are null-terminated pointers.
430/// See also `symLinkAbsolute`.
431pub fn symLinkAbsoluteZ(
432 target_path_c: [*:0]const u8,
433 sym_link_path_c: [*:0]const u8,
434 flags: Dir.SymLinkFlags,
435) !void {
436 assert(path.isAbsoluteZ(target_path_c));
437 assert(path.isAbsoluteZ(sym_link_path_c));
438 if (native_os == .windows) {
439 const target_path_w = try windows.cStrToPrefixedFileW(null, target_path_c);
440 const sym_link_path_w = try windows.cStrToPrefixedFileW(null, sym_link_path_c);
441 return windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
442 }
443 return posix.symlinkZ(target_path_c, sym_link_path_c);
444}
445
446400pub const OpenSelfExeError = posix.OpenError || SelfExePathError || posix.FlockError;
447401
448402pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
449403 if (native_os == .linux or native_os == .serenity) {
450 return openFileAbsoluteZ("/proc/self/exe", flags);
404 return openFileAbsolute("/proc/self/exe", flags);
451405 }
452406 if (native_os == .windows) {
453407 // If ImagePathName is a symlink, then it will contain the path of the symlink,
......@@ -463,7 +417,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
463417 var buf: [max_path_bytes]u8 = undefined;
464418 const self_exe_path = try selfExePath(&buf);
465419 buf[self_exe_path.len] = 0;
466 return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags);
420 return openFileAbsolute(buf[0..self_exe_path.len :0], flags);
467421}
468422
469423// This is `posix.ReadLinkError || posix.RealPathError` with impossible errors excluded
lib/std/fs/Dir.zig+7-164
......@@ -885,94 +885,9 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope
885885 const fd = try posix.openatWasi(self.fd, sub_path, .{}, .{}, .{}, base, .{});
886886 return .{ .handle = fd };
887887 }
888 const path_c = try posix.toPosixPath(sub_path);
889 return self.openFileZ(&path_c, flags);
890}
891
892/// Same as `openFile` but the path parameter is null-terminated.
893pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
894 switch (native_os) {
895 .windows => {
896 const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path);
897 return self.openFileW(path_w.span(), flags);
898 },
899 // Use the libc API when libc is linked because it implements things
900 // such as opening absolute file paths.
901 .wasi => if (!builtin.link_libc) {
902 return openFile(self, mem.sliceTo(sub_path, 0), flags);
903 },
904 else => {},
905 }
906
907 var os_flags: posix.O = switch (native_os) {
908 .wasi => .{
909 .read = flags.mode != .write_only,
910 .write = flags.mode != .read_only,
911 },
912 else => .{
913 .ACCMODE = switch (flags.mode) {
914 .read_only => .RDONLY,
915 .write_only => .WRONLY,
916 .read_write => .RDWR,
917 },
918 },
919 };
920 if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
921 if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
922 if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty;
923
924 // Use the O locking flags if the os supports them to acquire the lock
925 // atomically.
926 const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
927 if (has_flock_open_flags) {
928 // Note that the NONBLOCK flag is removed after the openat() call
929 // is successful.
930 switch (flags.lock) {
931 .none => {},
932 .shared => {
933 os_flags.SHLOCK = true;
934 os_flags.NONBLOCK = flags.lock_nonblocking;
935 },
936 .exclusive => {
937 os_flags.EXLOCK = true;
938 os_flags.NONBLOCK = flags.lock_nonblocking;
939 },
940 }
941 }
942 const fd = try posix.openatZ(self.fd, sub_path, os_flags, 0);
943 errdefer posix.close(fd);
944
945 if (have_flock and !has_flock_open_flags and flags.lock != .none) {
946 // TODO: integrate async I/O
947 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
948 try posix.flock(fd, switch (flags.lock) {
949 .none => unreachable,
950 .shared => posix.LOCK.SH | lock_nonblocking,
951 .exclusive => posix.LOCK.EX | lock_nonblocking,
952 });
953 }
954
955 if (has_flock_open_flags and flags.lock_nonblocking) {
956 var fl_flags = posix.fcntl(fd, posix.F.GETFL, 0) catch |err| switch (err) {
957 error.FileBusy => unreachable,
958 error.Locked => unreachable,
959 error.PermissionDenied => unreachable,
960 error.DeadLock => unreachable,
961 error.LockedRegionLimitExceeded => unreachable,
962 else => |e| return e,
963 };
964 fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
965 _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
966 error.FileBusy => unreachable,
967 error.Locked => unreachable,
968 error.PermissionDenied => unreachable,
969 error.DeadLock => unreachable,
970 error.LockedRegionLimitExceeded => unreachable,
971 else => |e| return e,
972 };
973 }
974
975 return .{ .handle = fd };
888 var threaded: Io.Threaded = .init_single_threaded;
889 const io = threaded.io();
890 return .adaptFromNewApi(try Io.Dir.openFile(self.adaptToNewApi(), io, sub_path, flags));
976891}
977892
978893/// Same as `openFile` but Windows-only and the path parameter is
......@@ -1048,82 +963,10 @@ pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File
1048963 }, .{}),
1049964 };
1050965 }
1051 const path_c = try posix.toPosixPath(sub_path);
1052 return self.createFileZ(&path_c, flags);
1053}
1054
1055/// Same as `createFile` but the path parameter is null-terminated.
1056pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
1057 switch (native_os) {
1058 .windows => {
1059 const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path_c);
1060 return self.createFileW(path_w.span(), flags);
1061 },
1062 .wasi => {
1063 return createFile(self, mem.sliceTo(sub_path_c, 0), flags);
1064 },
1065 else => {},
1066 }
1067
1068 var os_flags: posix.O = .{
1069 .ACCMODE = if (flags.read) .RDWR else .WRONLY,
1070 .CREAT = true,
1071 .TRUNC = flags.truncate,
1072 .EXCL = flags.exclusive,
1073 };
1074 if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
1075 if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
1076
1077 // Use the O locking flags if the os supports them to acquire the lock
1078 // atomically. Note that the NONBLOCK flag is removed after the openat()
1079 // call is successful.
1080 const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
1081 if (has_flock_open_flags) switch (flags.lock) {
1082 .none => {},
1083 .shared => {
1084 os_flags.SHLOCK = true;
1085 os_flags.NONBLOCK = flags.lock_nonblocking;
1086 },
1087 .exclusive => {
1088 os_flags.EXLOCK = true;
1089 os_flags.NONBLOCK = flags.lock_nonblocking;
1090 },
1091 };
1092
1093 const fd = try posix.openatZ(self.fd, sub_path_c, os_flags, flags.mode);
1094 errdefer posix.close(fd);
1095
1096 if (have_flock and !has_flock_open_flags and flags.lock != .none) {
1097 // TODO: integrate async I/O
1098 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
1099 try posix.flock(fd, switch (flags.lock) {
1100 .none => unreachable,
1101 .shared => posix.LOCK.SH | lock_nonblocking,
1102 .exclusive => posix.LOCK.EX | lock_nonblocking,
1103 });
1104 }
1105
1106 if (has_flock_open_flags and flags.lock_nonblocking) {
1107 var fl_flags = posix.fcntl(fd, posix.F.GETFL, 0) catch |err| switch (err) {
1108 error.FileBusy => unreachable,
1109 error.Locked => unreachable,
1110 error.PermissionDenied => unreachable,
1111 error.DeadLock => unreachable,
1112 error.LockedRegionLimitExceeded => unreachable,
1113 else => |e| return e,
1114 };
1115 fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
1116 _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
1117 error.FileBusy => unreachable,
1118 error.Locked => unreachable,
1119 error.PermissionDenied => unreachable,
1120 error.DeadLock => unreachable,
1121 error.LockedRegionLimitExceeded => unreachable,
1122 else => |e| return e,
1123 };
1124 }
1125
1126 return .{ .handle = fd };
966 var threaded: Io.Threaded = .init_single_threaded;
967 const io = threaded.io();
968 const new_file = try Io.Dir.createFile(self.adaptToNewApi(), io, sub_path, flags);
969 return .adaptFromNewApi(new_file);
1127970}
1128971
1129972/// Same as `createFile` but Windows-only and the path parameter is