Skip to content

Commit 4f129d0

Browse files
committed
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.
1 parent a3552a6 commit 4f129d0

File tree

3 files changed

+38
-22
lines changed

3 files changed

+38
-22
lines changed

lib/std/os.zig

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ const Dir = std.fs.Dir;
2222
const ArenaAllocator = std.heap.ArenaAllocator;
2323

2424
test "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

5077
test "open smoke test" {

lib/std/testing.zig

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -379,28 +379,13 @@ pub const TmpIterableDir = struct {
379379
}
380380
};
381381

382-
fn 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-
397382
pub 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();

0 commit comments

Comments
 (0)