authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-07 14:12:34-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-07 17:33:06-08:00
log213ef953462341b44c52adc0696ab3fbc60e82b4
tree2a2580d329b06c672beb8e0491e165c8e710c34d
parent2f372b3dc00c60a625e1cc3518fa1bda3429de59

goodbye posix.open

see #6600

4 files changed, 51 insertions(+), 109 deletions(-)

lib/std/dynamic_library.zig+15-23
...@@ -148,7 +148,7 @@ const ElfDynLibError = error{...@@ -148,7 +148,7 @@ const ElfDynLibError = error{
148 ElfHashTableNotFound,148 ElfHashTableNotFound,
149 Canceled,149 Canceled,
150 Streaming,150 Streaming,
151} || posix.OpenError || posix.MMapError;151} || Io.File.OpenError || posix.MMapError;
152152
153pub const ElfDynLib = struct {153pub const ElfDynLib = struct {
154 strings: [*:0]u8,154 strings: [*:0]u8,
...@@ -177,27 +177,20 @@ pub const ElfDynLib = struct {...@@ -177,27 +177,20 @@ pub const ElfDynLib = struct {
177 return parent;177 return parent;
178 }178 }
179179
180 fn resolveFromSearchPath(io: Io, search_path: []const u8, file_name: []const u8, delim: u8) ?posix.fd_t {180 fn resolveFromSearchPath(io: Io, search_path: []const u8, file_name: []const u8, delim: u8) ?Io.File {
181 var paths = std.mem.tokenizeScalar(u8, search_path, delim);181 var paths = std.mem.tokenizeScalar(u8, search_path, delim);
182 while (paths.next()) |p| {182 while (paths.next()) |p| {
183 var dir = openPath(io, p) catch continue;183 var dir = openPath(io, p) catch continue;
184 defer dir.close(io);184 defer dir.close(io);
185 const fd = posix.openat(dir.handle, file_name, .{185 return dir.openFile(io, file_name, .{}) catch continue;
186 .ACCMODE = .RDONLY,
187 .CLOEXEC = true,
188 }, 0) catch continue;
189 return fd;
190 }186 }
191 return null;187 return null;
192 }188 }
193189
194 fn resolveFromParent(io: Io, dir_path: []const u8, file_name: []const u8) ?posix.fd_t {190 fn resolveFromParent(io: Io, dir_path: []const u8, file_name: []const u8) ?Io.File {
195 var dir = Io.Dir.cwd().openDir(io, dir_path, .{}) catch return null;191 var dir = Io.Dir.cwd().openDir(io, dir_path, .{}) catch return null;
196 defer dir.close(io);192 defer dir.close(io);
197 return posix.openat(dir.handle, file_name, .{193 return dir.openFile(io, file_name, .{}) catch null;
198 .ACCMODE = .RDONLY,
199 .CLOEXEC = true,
200 }, 0) catch null;
201 }194 }
202195
203 // This implements enough to be able to load system libraries in general196 // This implements enough to be able to load system libraries in general
...@@ -205,10 +198,10 @@ pub const ElfDynLib = struct {...@@ -205,10 +198,10 @@ pub const ElfDynLib = struct {
205 // - DT_RPATH of the calling binary is not used as a search path198 // - DT_RPATH of the calling binary is not used as a search path
206 // - DT_RUNPATH of the calling binary is not used as a search path199 // - DT_RUNPATH of the calling binary is not used as a search path
207 // - /etc/ld.so.cache is not read200 // - /etc/ld.so.cache is not read
208 fn resolveFromName(io: Io, path_or_name: []const u8, LD_LIBRARY_PATH: ?[]const u8) !posix.fd_t {201 fn resolveFromName(io: Io, path_or_name: []const u8, LD_LIBRARY_PATH: ?[]const u8) !Io.File {
209 // If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) pathname202 // If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) pathname
210 if (std.mem.findScalarPos(u8, path_or_name, 0, '/')) |_| {203 if (std.mem.findScalarPos(u8, path_or_name, 0, '/')) |_| {
211 return posix.open(path_or_name, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);204 return Io.Dir.cwd().openFile(io, path_or_name, .{});
212 }205 }
213206
214 // Only read LD_LIBRARY_PATH if the binary is not setuid/setgid207 // Only read LD_LIBRARY_PATH if the binary is not setuid/setgid
...@@ -216,15 +209,15 @@ pub const ElfDynLib = struct {...@@ -216,15 +209,15 @@ pub const ElfDynLib = struct {
216 std.os.linux.getegid() == std.os.linux.getgid())209 std.os.linux.getegid() == std.os.linux.getgid())
217 {210 {
218 if (LD_LIBRARY_PATH) |ld_library_path| {211 if (LD_LIBRARY_PATH) |ld_library_path| {
219 if (resolveFromSearchPath(io, ld_library_path, path_or_name, ':')) |fd| {212 if (resolveFromSearchPath(io, ld_library_path, path_or_name, ':')) |file| {
220 return fd;213 return file;
221 }214 }
222 }215 }
223 }216 }
224217
225 // Lastly the directories /lib and /usr/lib are searched (in this exact order)218 // Lastly the directories /lib and /usr/lib are searched (in this exact order)
226 if (resolveFromParent(io, "/lib", path_or_name)) |fd| return fd;219 if (resolveFromParent(io, "/lib", path_or_name)) |file| return file;
227 if (resolveFromParent(io, "/usr/lib", path_or_name)) |fd| return fd;220 if (resolveFromParent(io, "/usr/lib", path_or_name)) |file| return file;
228 return error.FileNotFound;221 return error.FileNotFound;
229 }222 }
230223
...@@ -232,10 +225,9 @@ pub const ElfDynLib = struct {...@@ -232,10 +225,9 @@ pub const ElfDynLib = struct {
232 pub fn open(path: []const u8, LD_LIBRARY_PATH: ?[]const u8) Error!ElfDynLib {225 pub fn open(path: []const u8, LD_LIBRARY_PATH: ?[]const u8) Error!ElfDynLib {
233 const io = std.Options.debug_io;226 const io = std.Options.debug_io;
234227
235 const fd = try resolveFromName(io, path, LD_LIBRARY_PATH);228 const file = try resolveFromName(io, path, LD_LIBRARY_PATH);
236 defer posix.close(fd);229 defer file.close(io);
237230
238 const file: Io.File = .{ .handle = fd };
239 const stat = try file.stat(io);231 const stat = try file.stat(io);
240 const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig;232 const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig;
241233
...@@ -248,7 +240,7 @@ pub const ElfDynLib = struct {...@@ -248,7 +240,7 @@ pub const ElfDynLib = struct {
248 mem.alignForward(usize, size, page_size),240 mem.alignForward(usize, size, page_size),
249 posix.PROT.READ,241 posix.PROT.READ,
250 .{ .TYPE = .PRIVATE },242 .{ .TYPE = .PRIVATE },
251 fd,243 file.handle,
252 0,244 0,
253 );245 );
254 defer posix.munmap(file_bytes);246 defer posix.munmap(file_bytes);
...@@ -318,7 +310,7 @@ pub const ElfDynLib = struct {...@@ -318,7 +310,7 @@ pub const ElfDynLib = struct {
318 extended_memsz,310 extended_memsz,
319 prot,311 prot,
320 .{ .TYPE = .PRIVATE, .FIXED = true },312 .{ .TYPE = .PRIVATE, .FIXED = true },
321 fd,313 file.handle,
322 ph.p_offset - extra_bytes,314 ph.p_offset - extra_bytes,
323 );315 );
324 } else {316 } else {
lib/std/os/linux/IoUring/test.zig+24-18
...@@ -932,6 +932,8 @@ test "accept/connect/recv/cancel" {...@@ -932,6 +932,8 @@ test "accept/connect/recv/cancel" {
932}932}
933933
934test "register_files_update" {934test "register_files_update" {
935 const io = testing.io;
936
935 var ring = IoUring.init(1, 0) catch |err| switch (err) {937 var ring = IoUring.init(1, 0) catch |err| switch (err) {
936 error.SystemOutdated => return error.SkipZigTest,938 error.SystemOutdated => return error.SkipZigTest,
937 error.PermissionDenied => return error.SkipZigTest,939 error.PermissionDenied => return error.SkipZigTest,
...@@ -939,13 +941,13 @@ test "register_files_update" {...@@ -939,13 +941,13 @@ test "register_files_update" {
939 };941 };
940 defer ring.deinit();942 defer ring.deinit();
941943
942 const fd = try posix.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);944 const file = try Io.Dir.openFileAbsolute(io, "/dev/zero", .{});
943 defer posix.close(fd);945 defer file.close(io);
944946
945 var registered_fds = [_]linux.fd_t{0} ** 2;947 var registered_fds = [_]linux.fd_t{0} ** 2;
946 const fd_index = 0;948 const fd_index = 0;
947 const fd_index2 = 1;949 const fd_index2 = 1;
948 registered_fds[fd_index] = fd;950 registered_fds[fd_index] = file.handle;
949 registered_fds[fd_index2] = -1;951 registered_fds[fd_index2] = -1;
950952
951 ring.register_files(registered_fds[0..]) catch |err| switch (err) {953 ring.register_files(registered_fds[0..]) catch |err| switch (err) {
...@@ -957,10 +959,10 @@ test "register_files_update" {...@@ -957,10 +959,10 @@ test "register_files_update" {
957 // Test IORING_REGISTER_FILES_UPDATE959 // Test IORING_REGISTER_FILES_UPDATE
958 // Only available since Linux 5.5960 // Only available since Linux 5.5
959961
960 const fd2 = try posix.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);962 const file2 = try Io.Dir.openFileAbsolute(io, "/dev/zero", .{});
961 defer posix.close(fd2);963 defer file2.close(io);
962964
963 registered_fds[fd_index] = fd2;965 registered_fds[fd_index] = file2.handle;
964 registered_fds[fd_index2] = -1;966 registered_fds[fd_index2] = -1;
965 try ring.register_files_update(0, registered_fds[0..]);967 try ring.register_files_update(0, registered_fds[0..]);
966968
...@@ -1339,6 +1341,8 @@ test "linkat" {...@@ -1339,6 +1341,8 @@ test "linkat" {
1339}1341}
13401342
1341test "provide_buffers: read" {1343test "provide_buffers: read" {
1344 const io = testing.io;
1345
1342 var ring = IoUring.init(1, 0) catch |err| switch (err) {1346 var ring = IoUring.init(1, 0) catch |err| switch (err) {
1343 error.SystemOutdated => return error.SkipZigTest,1347 error.SystemOutdated => return error.SkipZigTest,
1344 error.PermissionDenied => return error.SkipZigTest,1348 error.PermissionDenied => return error.SkipZigTest,
...@@ -1346,8 +1350,8 @@ test "provide_buffers: read" {...@@ -1346,8 +1350,8 @@ test "provide_buffers: read" {
1346 };1350 };
1347 defer ring.deinit();1351 defer ring.deinit();
13481352
1349 const fd = try posix.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);1353 const file = try Io.Dir.openFileAbsolute(io, "/dev/zero", .{});
1350 defer posix.close(fd);1354 defer file.close(io);
13511355
1352 const group_id = 1337;1356 const group_id = 1337;
1353 const buffer_id = 0;1357 const buffer_id = 0;
...@@ -1380,9 +1384,9 @@ test "provide_buffers: read" {...@@ -1380,9 +1384,9 @@ test "provide_buffers: read" {
13801384
1381 var i: usize = 0;1385 var i: usize = 0;
1382 while (i < buffers.len) : (i += 1) {1386 while (i < buffers.len) : (i += 1) {
1383 const sqe = try ring.read(0xdededede, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);1387 const sqe = try ring.read(0xdededede, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
1384 try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);1388 try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);
1385 try testing.expectEqual(@as(i32, fd), sqe.fd);1389 try testing.expectEqual(@as(i32, file.handle), sqe.fd);
1386 try testing.expectEqual(@as(u64, 0), sqe.addr);1390 try testing.expectEqual(@as(u64, 0), sqe.addr);
1387 try testing.expectEqual(@as(u32, buffer_len), sqe.len);1391 try testing.expectEqual(@as(u32, buffer_len), sqe.len);
1388 try testing.expectEqual(@as(u16, group_id), sqe.buf_index);1392 try testing.expectEqual(@as(u16, group_id), sqe.buf_index);
...@@ -1406,9 +1410,9 @@ test "provide_buffers: read" {...@@ -1406,9 +1410,9 @@ test "provide_buffers: read" {
1406 // This read should fail1410 // This read should fail
14071411
1408 {1412 {
1409 const sqe = try ring.read(0xdfdfdfdf, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);1413 const sqe = try ring.read(0xdfdfdfdf, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
1410 try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);1414 try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);
1411 try testing.expectEqual(@as(i32, fd), sqe.fd);1415 try testing.expectEqual(@as(i32, file.handle), sqe.fd);
1412 try testing.expectEqual(@as(u64, 0), sqe.addr);1416 try testing.expectEqual(@as(u64, 0), sqe.addr);
1413 try testing.expectEqual(@as(u32, buffer_len), sqe.len);1417 try testing.expectEqual(@as(u32, buffer_len), sqe.len);
1414 try testing.expectEqual(@as(u16, group_id), sqe.buf_index);1418 try testing.expectEqual(@as(u16, group_id), sqe.buf_index);
...@@ -1445,9 +1449,9 @@ test "provide_buffers: read" {...@@ -1445,9 +1449,9 @@ test "provide_buffers: read" {
1445 // Final read which should work1449 // Final read which should work
14461450
1447 {1451 {
1448 const sqe = try ring.read(0xdfdfdfdf, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);1452 const sqe = try ring.read(0xdfdfdfdf, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
1449 try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);1453 try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);
1450 try testing.expectEqual(@as(i32, fd), sqe.fd);1454 try testing.expectEqual(@as(i32, file.handle), sqe.fd);
1451 try testing.expectEqual(@as(u64, 0), sqe.addr);1455 try testing.expectEqual(@as(u64, 0), sqe.addr);
1452 try testing.expectEqual(@as(u32, buffer_len), sqe.len);1456 try testing.expectEqual(@as(u32, buffer_len), sqe.len);
1453 try testing.expectEqual(@as(u16, group_id), sqe.buf_index);1457 try testing.expectEqual(@as(u16, group_id), sqe.buf_index);
...@@ -1469,6 +1473,8 @@ test "provide_buffers: read" {...@@ -1469,6 +1473,8 @@ test "provide_buffers: read" {
1469}1473}
14701474
1471test "remove_buffers" {1475test "remove_buffers" {
1476 const io = testing.io;
1477
1472 var ring = IoUring.init(1, 0) catch |err| switch (err) {1478 var ring = IoUring.init(1, 0) catch |err| switch (err) {
1473 error.SystemOutdated => return error.SkipZigTest,1479 error.SystemOutdated => return error.SkipZigTest,
1474 error.PermissionDenied => return error.SkipZigTest,1480 error.PermissionDenied => return error.SkipZigTest,
...@@ -1476,8 +1482,8 @@ test "remove_buffers" {...@@ -1476,8 +1482,8 @@ test "remove_buffers" {
1476 };1482 };
1477 defer ring.deinit();1483 defer ring.deinit();
14781484
1479 const fd = try posix.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);1485 const file = try Io.Dir.openFileAbsolute(io, "/dev/zero", .{});
1480 defer posix.close(fd);1486 defer file.close(io);
14811487
1482 const group_id = 1337;1488 const group_id = 1337;
1483 const buffer_id = 0;1489 const buffer_id = 0;
...@@ -1522,7 +1528,7 @@ test "remove_buffers" {...@@ -1522,7 +1528,7 @@ test "remove_buffers" {
1522 // This read should work1528 // This read should work
15231529
1524 {1530 {
1525 _ = try ring.read(0xdfdfdfdf, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);1531 _ = try ring.read(0xdfdfdfdf, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
1526 try testing.expectEqual(@as(u32, 1), try ring.submit());1532 try testing.expectEqual(@as(u32, 1), try ring.submit());
15271533
1528 const cqe = try ring.copy_cqe();1534 const cqe = try ring.copy_cqe();
...@@ -1542,7 +1548,7 @@ test "remove_buffers" {...@@ -1542,7 +1548,7 @@ test "remove_buffers" {
1542 // Final read should _not_ work1548 // Final read should _not_ work
15431549
1544 {1550 {
1545 _ = try ring.read(0xdfdfdfdf, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);1551 _ = try ring.read(0xdfdfdfdf, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
1546 try testing.expectEqual(@as(u32, 1), try ring.submit());1552 try testing.expectEqual(@as(u32, 1), try ring.submit());
15471553
1548 const cqe = try ring.copy_cqe();1554 const cqe = try ring.copy_cqe();
lib/std/posix.zig-60
...@@ -448,66 +448,6 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -448,66 +448,6 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
448448
449pub const OpenError = std.Io.File.OpenError || error{WouldBlock};449pub const OpenError = std.Io.File.OpenError || error{WouldBlock};
450450
451/// Open and possibly create a file. Keeps trying if it gets interrupted.
452/// On Windows, `file_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
453/// On WASI, `file_path` should be encoded as valid UTF-8.
454/// On other platforms, `file_path` is an opaque sequence of bytes with no particular encoding.
455/// See also `openZ`.
456pub fn open(file_path: []const u8, flags: O, perm: mode_t) OpenError!fd_t {
457 if (native_os == .windows) {
458 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
459 } else if (native_os == .wasi and !builtin.link_libc) {
460 return openat(AT.FDCWD, file_path, flags, perm);
461 }
462 const file_path_c = try toPosixPath(file_path);
463 return openZ(&file_path_c, flags, perm);
464}
465
466/// Open and possibly create a file. Keeps trying if it gets interrupted.
467/// On Windows, `file_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
468/// On WASI, `file_path` should be encoded as valid UTF-8.
469/// On other platforms, `file_path` is an opaque sequence of bytes with no particular encoding.
470/// See also `open`.
471pub fn openZ(file_path: [*:0]const u8, flags: O, perm: mode_t) OpenError!fd_t {
472 if (native_os == .windows) {
473 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
474 } else if (native_os == .wasi and !builtin.link_libc) {
475 return open(mem.sliceTo(file_path, 0), flags, perm);
476 }
477
478 const open_sym = if (lfs64_abi) system.open64 else system.open;
479 while (true) {
480 const rc = open_sym(file_path, flags, perm);
481 switch (errno(rc)) {
482 .SUCCESS => return @intCast(rc),
483 .INTR => continue,
484
485 .FAULT => unreachable,
486 .INVAL => return error.BadPathName,
487 .ACCES => return error.AccessDenied,
488 .FBIG => return error.FileTooBig,
489 .OVERFLOW => return error.FileTooBig,
490 .ISDIR => return error.IsDir,
491 .LOOP => return error.SymLinkLoop,
492 .MFILE => return error.ProcessFdQuotaExceeded,
493 .NAMETOOLONG => return error.NameTooLong,
494 .NFILE => return error.SystemFdQuotaExceeded,
495 .NODEV => return error.NoDevice,
496 .NOENT => return error.FileNotFound,
497 // Can happen on Linux when opening procfs files.
498 .SRCH => return error.FileNotFound,
499 .NOMEM => return error.SystemResources,
500 .NOSPC => return error.NoSpaceLeft,
501 .NOTDIR => return error.NotDir,
502 .PERM => return error.PermissionDenied,
503 .EXIST => return error.PathAlreadyExists,
504 .BUSY => return error.DeviceBusy,
505 .ILSEQ => return error.BadPathName,
506 else => |err| return unexpectedErrno(err),
507 }
508 }
509}
510
511/// Open and possibly create a file. Keeps trying if it gets interrupted.451/// Open and possibly create a file. Keeps trying if it gets interrupted.
512/// `file_path` is relative to the open directory handle `dir_fd`.452/// `file_path` is relative to the open directory handle `dir_fd`.
513/// On Windows, `file_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).453/// On Windows, `file_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
lib/std/posix/test.zig+12-8
...@@ -463,8 +463,12 @@ test "rename smoke test" {...@@ -463,8 +463,12 @@ test "rename smoke test" {
463 // Create some file using `open`.463 // Create some file using `open`.
464 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });464 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });
465 defer gpa.free(file_path);465 defer gpa.free(file_path);
466 const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);466 const file = try Io.Dir.cwd().createFile(io, file_path, .{
467 posix.close(fd);467 .read = true,
468 .exclusive = true,
469 .permissions = .fromMode(mode),
470 });
471 file.close(io);
468472
469 // Rename the file473 // Rename the file
470 const new_file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_file" });474 const new_file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_file" });
...@@ -476,15 +480,15 @@ test "rename smoke test" {...@@ -476,15 +480,15 @@ test "rename smoke test" {
476 // Try opening renamed file480 // Try opening renamed file
477 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_file" });481 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_file" });
478 defer gpa.free(file_path);482 defer gpa.free(file_path);
479 const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR }, mode);483 const file = try Io.Dir.cwd().openFile(io, file_path, .{ .mode = .read_write });
480 posix.close(fd);484 file.close(io);
481 }485 }
482486
483 {487 {
484 // Try opening original file - should fail with error.FileNotFound488 // Try opening original file - should fail with error.FileNotFound
485 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });489 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });
486 defer gpa.free(file_path);490 defer gpa.free(file_path);
487 try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));491 try expectError(error.FileNotFound, Io.Dir.cwd().openFile(io, file_path, .{ .mode = .read_write }));
488 }492 }
489493
490 {494 {
...@@ -503,15 +507,15 @@ test "rename smoke test" {...@@ -503,15 +507,15 @@ test "rename smoke test" {
503 // Try opening renamed directory507 // Try opening renamed directory
504 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_dir" });508 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_dir" });
505 defer gpa.free(file_path);509 defer gpa.free(file_path);
506 const fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);510 const dir = try Io.Dir.cwd().openDir(io, file_path, .{});
507 posix.close(fd);511 dir.close(io);
508 }512 }
509513
510 {514 {
511 // Try opening original directory - should fail with error.FileNotFound515 // Try opening original directory - should fail with error.FileNotFound
512 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_dir" });516 const file_path = try Dir.path.join(gpa, &.{ base_path, "some_dir" });
513 defer gpa.free(file_path);517 defer gpa.free(file_path);
514 try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode));518 try expectError(error.FileNotFound, Io.Dir.cwd().openDir(io, file_path, .{}));
515 }519 }
516}520}
517521