diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 2640abff1e..e253aaff9e 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1488,19 +1488,7 @@ pub const Dir = struct { /// See also `Dir.realpathZ`, `Dir.realpathW`, and `Dir.realpathAlloc`. pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) ![]u8 { if (builtin.os.tag == .wasi) { - if (self.fd == os.wasi.AT.FDCWD or path.isAbsolute(pathname)) { - var buffer: [MAX_PATH_BYTES]u8 = undefined; - const out_path = try os.realpath(pathname, &buffer); - if (out_path.len > out_buffer.len) { - return error.NameTooLong; - } - mem.copy(u8, out_buffer, out_path); - return out_buffer[0..out_path.len]; - } else { - // Unfortunately, we have no ability to look up the path for an fd_t - // on WASI, so we have to give up here. - return error.InvalidHandle; - } + @compileError("realpath is not available on WASI"); } if (builtin.os.tag == .windows) { const pathname_w = try os.windows.sliceToPrefixedFileW(pathname); @@ -2652,8 +2640,13 @@ pub const Dir = struct { pub fn cwd() Dir { if (builtin.os.tag == .windows) { return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; - } else if (builtin.os.tag == .wasi and @hasDecl(root, "wasi_cwd")) { - return root.wasi_cwd(); + } else if (builtin.os.tag == .wasi) { + if (@hasDecl(root, "wasi_cwd")) { + return root.wasi_cwd(); + } else { + // Expect the first preopen to be current working directory. + return .{ .fd = 3 }; + } } else { return Dir{ .fd = os.AT.FDCWD }; } diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 556f3b8459..c497e213bf 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -48,8 +48,7 @@ fn testReadLink(dir: Dir, target_path: []const u8, symlink_path: []const u8) !vo } test "accessAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -67,8 +66,7 @@ test "accessAbsolute" { } test "openDirAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -104,8 +102,7 @@ test "openDir cwd parent .." { } test "readLinkAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -187,8 +184,6 @@ test "Dir.Iterator" { } test "Dir.Iterator many entries" { - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); - var tmp_dir = tmpIterableDir(.{}); defer tmp_dir.cleanup(); @@ -638,8 +633,7 @@ test "rename" { } test "renameAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp_dir = tmpDir(.{}); defer tmp_dir.cleanup(); @@ -1149,7 +1143,6 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" { test "walker" { if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); var tmp = tmpIterableDir(.{}); defer tmp.cleanup(); @@ -1203,7 +1196,6 @@ test "walker" { test "walker without fully iterating" { if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); var tmp = tmpIterableDir(.{}); defer tmp.cleanup(); @@ -1227,7 +1219,6 @@ test "walker without fully iterating" { test ". and .. in fs.Dir functions" { if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -1255,8 +1246,7 @@ test ". and .. in fs.Dir functions" { } test ". and .. in absolute functions" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); diff --git a/lib/std/os.zig b/lib/std/os.zig index ab43b3a0a1..fc021be954 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2032,7 +2032,7 @@ pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLin if (builtin.os.tag == .windows) { @compileError("symlink is not supported on Windows; use std.os.windows.CreateSymbolicLink instead"); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - return symlink(mem.sliceTo(target_path, 0), mem.sliceTo(sym_link_path, 0)); + return symlinkatZ(target_path, fs.cwd().fd, sym_link_path); } switch (errno(system.symlink(target_path, sym_link_path))) { .SUCCESS => return, @@ -2078,6 +2078,7 @@ pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []c .SUCCESS => {}, .FAULT => unreachable, .INVAL => unreachable, + .BADF => unreachable, .ACCES => return error.AccessDenied, .PERM => return error.AccessDenied, .DQUOT => return error.DiskQuota, diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index ed86024dcd..44d0e0c808 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -22,8 +22,7 @@ const Dir = std.fs.Dir; const ArenaAllocator = std.heap.ArenaAllocator; test "chdir smoke test" { - 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"); + if (native_os == .wasi) return error.SkipZigTest; // Get current working directory path var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; @@ -75,8 +74,7 @@ test "chdir smoke test" { } test "open smoke test" { - 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, "/"); + if (native_os == .wasi) return error.SkipZigTest; // TODO verify file attributes using `fstat` @@ -131,7 +129,6 @@ test "open smoke test" { test "openat smoke test" { 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, "/"); // TODO verify file attributes using `fstatat` @@ -168,7 +165,6 @@ test "openat smoke test" { test "symlink with relative paths" { 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, "/"); const cwd = fs.cwd(); cwd.deleteFile("file.txt") catch {}; @@ -219,15 +215,10 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void { } test "link with relative paths" { + if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; + switch (native_os) { - .wasi => { - if (builtin.link_libc) { - return error.SkipZigTest; - } else { - try os.initPreopensWasi(std.heap.page_allocator, "/"); - } - }, - .linux, .solaris => {}, + .wasi, .linux, .solaris => {}, else => return error.SkipZigTest, } var cwd = fs.cwd(); @@ -263,9 +254,10 @@ test "link with relative paths" { } test "linkat with different directories" { + if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; + switch (native_os) { - .wasi => if (!builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"), - .linux, .solaris => {}, + .wasi, .linux, .solaris => {}, else => return error.SkipZigTest, } var cwd = fs.cwd(); @@ -950,8 +942,7 @@ test "POSIX file locking with fcntl" { } test "rename smoke test" { - 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, "/"); + if (native_os == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -1007,8 +998,7 @@ test "rename smoke test" { } test "access smoke test" { - 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, "/"); + if (native_os == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 308b6cc23d..711352e2fe 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -1,6 +1,7 @@ // wasi_snapshot_preview1 spec available (in witx format) here: // * typenames -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx // * module -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/wasi_snapshot_preview1.witx +const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; @@ -157,7 +158,12 @@ pub const IOV_MAX = 1024; pub const AT = struct { pub const REMOVEDIR: u32 = 0x4; - pub const FDCWD: fd_t = -2; + /// When linking libc, we follow their convention and use -2 for current working directory. + /// However, without libc, Zig does a different convention: it assumes the + /// current working directory is the first preopen. This behavior can be + /// overridden with a public function called `wasi_cwd` in the root source + /// file. + pub const FDCWD: fd_t = if (builtin.link_libc) -2 else 3; }; // As defined in the wasi_snapshot_preview1 spec file: