diff --git a/lib/std/os.zig b/lib/std/os.zig index edea8f16202c..7ebe41502695 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2999,15 +2999,19 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { if (builtin.os.tag == .wasi and !builtin.link_libc) { var buf: [MAX_PATH_BYTES]u8 = undefined; var alloc = std.heap.FixedBufferAllocator.init(&buf); - const path = try fs.resolve(alloc.allocator(), &.{ wasi_cwd.cwd, dir_path }); + const path = fs.path.resolve(alloc.allocator(), &.{ wasi_cwd.cwd, dir_path }) catch |err| switch (err) { + error.OutOfMemory => return error.NameTooLong, + else => |e| return e, + }; const dirinfo = try fstatat(AT.FDCWD, path, 0); if (dirinfo.filetype != .DIRECTORY) { return error.NotDir; } + // This copy is guaranteed to succeed, since buf and path_buffer are the same size. var cwd_alloc = std.heap.FixedBufferAllocator.init(&wasi_cwd.path_buffer); - wasi_cwd.cwd = try cwd_alloc.allocator().dupe(u8, path); + wasi_cwd.cwd = cwd_alloc.allocator().dupe(u8, path) catch unreachable; return; } else if (builtin.os.tag == .windows) { var utf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index c89026b5de99..86f25fc8c684 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -22,7 +22,8 @@ const Dir = std.fs.Dir; const ArenaAllocator = std.heap.ArenaAllocator; test "chdir smoke test" { - if (native_os == .wasi) return error.SkipZigTest; // WASI doesn't allow navigating outside of a preopen + if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; + if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/preopens/cwd"); // Get current working directory path var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; @@ -35,16 +36,42 @@ test "chdir smoke test" { const new_cwd = try os.getcwd(new_cwd_buf[0..]); try expect(mem.eql(u8, old_cwd, new_cwd)); } - { - // Next, change current working directory to one level above + + // Next, change current working directory to one level above + if (native_os != .wasi) { // WASI does not support navigating outside of Preopens const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute try os.chdir(parent); + // Restore cwd because process may have other tests that do not tolerate chdir. defer os.chdir(old_cwd) catch unreachable; + var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; const new_cwd = try os.getcwd(new_cwd_buf[0..]); try expect(mem.eql(u8, parent, new_cwd)); } + + // Next, change current working directory to a temp directory one level below + { + // Create a tmp directory + var tmp_dir_buf: [fs.MAX_PATH_BYTES]u8 = undefined; + var tmp_dir_path = path: { + var allocator = std.heap.FixedBufferAllocator.init(&tmp_dir_buf); + break :path try fs.path.resolve(allocator.allocator(), &[_][]const u8{ old_cwd, "zig-test-tmp" }); + }; + var tmp_dir = try fs.cwd().makeOpenPath("zig-test-tmp", .{}); + + // Change current working directory to tmp directory + try os.chdir("zig-test-tmp"); + + var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; + const new_cwd = try os.getcwd(new_cwd_buf[0..]); + try expect(mem.eql(u8, tmp_dir_path, new_cwd)); + + // Restore cwd because process may have other tests that do not tolerate chdir. + tmp_dir.close(); + os.chdir(old_cwd) catch unreachable; + try fs.cwd().deleteDir("zig-test-tmp"); + } } test "open smoke test" { diff --git a/lib/std/testing.zig b/lib/std/testing.zig index f1b01b0bd013..00a06dc20f34 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -379,28 +379,13 @@ pub const TmpIterableDir = struct { } }; -fn getCwdOrWasiPreopen() std.fs.Dir { - if (builtin.os.tag == .wasi and !builtin.link_libc) { - var preopens = std.fs.wasi.PreopenList.init(allocator); - defer preopens.deinit(); - preopens.populate(null) catch - @panic("unable to make tmp dir for testing: unable to populate preopens"); - const preopen = preopens.find(std.fs.wasi.PreopenType{ .Dir = "." }) orelse - @panic("unable to make tmp dir for testing: didn't find '.' in the preopens"); - - return std.fs.Dir{ .fd = preopen.fd }; - } else { - return std.fs.cwd(); - } -} - pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir { var random_bytes: [TmpDir.random_bytes_count]u8 = undefined; std.crypto.random.bytes(&random_bytes); var sub_path: [TmpDir.sub_path_len]u8 = undefined; _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes); - var cwd = getCwdOrWasiPreopen(); + var cwd = std.fs.cwd(); var cache_dir = cwd.makeOpenPath("zig-cache", .{}) catch @panic("unable to make tmp dir for testing: unable to make and open zig-cache dir"); defer cache_dir.close(); @@ -422,7 +407,7 @@ pub fn tmpIterableDir(opts: std.fs.Dir.OpenDirOptions) TmpIterableDir { var sub_path: [TmpIterableDir.sub_path_len]u8 = undefined; _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes); - var cwd = getCwdOrWasiPreopen(); + var cwd = std.fs.cwd(); var cache_dir = cwd.makeOpenPath("zig-cache", .{}) catch @panic("unable to make tmp dir for testing: unable to make and open zig-cache dir"); defer cache_dir.close();