authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-11-24 08:10:06-07:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-26 22:06:15+02:00
loga0af3c7a19c8f60f740e9a8c178ce19d85b26256
treef1dca4f8c42e8fbd1a57e8a5bf991a53fcc0b02f
parent304e828088f0b03d47f7b0b3df7b1449c0a1f2d6

std.os: Fix std.os.chdir for WASI

Test coverage was lacking for chdir() on WASI, allowing this to regress. This change makes os.chdir() compile again, and improves the test logic to use our standard CWD support for WASI.

3 files changed, 38 insertions(+), 22 deletions(-)

lib/std/os.zig+6-2
......@@ -2999,15 +2999,19 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
29992999 if (builtin.os.tag == .wasi and !builtin.link_libc) {
30003000 var buf: [MAX_PATH_BYTES]u8 = undefined;
30013001 var alloc = std.heap.FixedBufferAllocator.init(&buf);
3002 const path = try fs.resolve(alloc.allocator(), &.{ wasi_cwd.cwd, dir_path });
3002 const path = fs.path.resolve(alloc.allocator(), &.{ wasi_cwd.cwd, dir_path }) catch |err| switch (err) {
3003 error.OutOfMemory => return error.NameTooLong,
3004 else => |e| return e,
3005 };
30033006
30043007 const dirinfo = try fstatat(AT.FDCWD, path, 0);
30053008 if (dirinfo.filetype != .DIRECTORY) {
30063009 return error.NotDir;
30073010 }
30083011
3012 // This copy is guaranteed to succeed, since buf and path_buffer are the same size.
30093013 var cwd_alloc = std.heap.FixedBufferAllocator.init(&wasi_cwd.path_buffer);
3010 wasi_cwd.cwd = try cwd_alloc.allocator().dupe(u8, path);
3014 wasi_cwd.cwd = cwd_alloc.allocator().dupe(u8, path) catch unreachable;
30113015 return;
30123016 } else if (builtin.os.tag == .windows) {
30133017 var utf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
lib/std/os/test.zig+30-3
......@@ -22,7 +22,8 @@ const Dir = std.fs.Dir;
2222const ArenaAllocator = std.heap.ArenaAllocator;
2323
2424test "chdir smoke test" {
25 if (native_os == .wasi) return error.SkipZigTest; // WASI doesn't allow navigating outside of a preopen
25 if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
26 if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/preopens/cwd");
2627
2728 // Get current working directory path
2829 var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
......@@ -35,16 +36,42 @@ test "chdir smoke test" {
3536 const new_cwd = try os.getcwd(new_cwd_buf[0..]);
3637 try expect(mem.eql(u8, old_cwd, new_cwd));
3738 }
38 {
39 // Next, change current working directory to one level above
39
40 // Next, change current working directory to one level above
41 if (native_os != .wasi) { // WASI does not support navigating outside of Preopens
4042 const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute
4143 try os.chdir(parent);
44
4245 // Restore cwd because process may have other tests that do not tolerate chdir.
4346 defer os.chdir(old_cwd) catch unreachable;
47
4448 var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
4549 const new_cwd = try os.getcwd(new_cwd_buf[0..]);
4650 try expect(mem.eql(u8, parent, new_cwd));
4751 }
52
53 // Next, change current working directory to a temp directory one level below
54 {
55 // Create a tmp directory
56 var tmp_dir_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
57 var tmp_dir_path = path: {
58 var allocator = std.heap.FixedBufferAllocator.init(&tmp_dir_buf);
59 break :path try fs.path.resolve(allocator.allocator(), &[_][]const u8{ old_cwd, "zig-test-tmp" });
60 };
61 var tmp_dir = try fs.cwd().makeOpenPath("zig-test-tmp", .{});
62
63 // Change current working directory to tmp directory
64 try os.chdir("zig-test-tmp");
65
66 var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
67 const new_cwd = try os.getcwd(new_cwd_buf[0..]);
68 try expect(mem.eql(u8, tmp_dir_path, new_cwd));
69
70 // Restore cwd because process may have other tests that do not tolerate chdir.
71 tmp_dir.close();
72 os.chdir(old_cwd) catch unreachable;
73 try fs.cwd().deleteDir("zig-test-tmp");
74 }
4875}
4976
5077test "open smoke test" {
lib/std/testing.zig+2-17
......@@ -379,28 +379,13 @@ pub const TmpIterableDir = struct {
379379 }
380380};
381381
382fn getCwdOrWasiPreopen() std.fs.Dir {
383 if (builtin.os.tag == .wasi and !builtin.link_libc) {
384 var preopens = std.fs.wasi.PreopenList.init(allocator);
385 defer preopens.deinit();
386 preopens.populate(null) catch
387 @panic("unable to make tmp dir for testing: unable to populate preopens");
388 const preopen = preopens.find(std.fs.wasi.PreopenType{ .Dir = "." }) orelse
389 @panic("unable to make tmp dir for testing: didn't find '.' in the preopens");
390
391 return std.fs.Dir{ .fd = preopen.fd };
392 } else {
393 return std.fs.cwd();
394 }
395}
396
397382pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir {
398383 var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
399384 std.crypto.random.bytes(&random_bytes);
400385 var sub_path: [TmpDir.sub_path_len]u8 = undefined;
401386 _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
402387
403 var cwd = getCwdOrWasiPreopen();
388 var cwd = std.fs.cwd();
404389 var cache_dir = cwd.makeOpenPath("zig-cache", .{}) catch
405390 @panic("unable to make tmp dir for testing: unable to make and open zig-cache dir");
406391 defer cache_dir.close();
......@@ -422,7 +407,7 @@ pub fn tmpIterableDir(opts: std.fs.Dir.OpenDirOptions) TmpIterableDir {
422407 var sub_path: [TmpIterableDir.sub_path_len]u8 = undefined;
423408 _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
424409
425 var cwd = getCwdOrWasiPreopen();
410 var cwd = std.fs.cwd();
426411 var cache_dir = cwd.makeOpenPath("zig-cache", .{}) catch
427412 @panic("unable to make tmp dir for testing: unable to make and open zig-cache dir");
428413 defer cache_dir.close();