diff --git a/lib/std/fs.zig b/lib/std/fs.zig index be729eb295..ed2d460cf4 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1440,17 +1440,7 @@ pub fn cwd() Dir { if (builtin.os.tag == .windows) { return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; } else if (builtin.os.tag == .wasi) { - const wasi = os.wasi; - // On WASI we indeed don't have a concept of cwd; however, we can approximate it with - // trying to obtain a preopen for ".". - // TODO `cwd()` should be a fallible operation if we're going to support WASI this way. - var fd: wasi.fd_t = undefined; - var prefix: usize = undefined; - switch (wasi.resolve_preopen(".", &fd, &prefix)) { - 0 => {}, - else => {}, - } - return Dir{ .fd = fd }; + @compileError("WASI doesn't have a concept of cwd; use TODO instead"); } else { return Dir{ .fd = os.AT_FDCWD }; } diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 07a354e67c..9acf9001f6 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -2,6 +2,7 @@ // * 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 std = @import("std"); +const mem = std.mem; const assert = std.debug.assert; pub usingnamespace @import("bits.zig"); @@ -65,6 +66,71 @@ pub fn resolve_preopen(path: []const u8, dirfd: *fd_t, prefix: *usize) errno_t { return ENOTCAPABLE; } +pub const PreopenType = enum { + Dir, +}; + +pub const Preopen = struct { + fd: fd_t, + @"type": union(PreopenType) { + Dir: []const u8, + }, + + const Self = @This(); + + pub fn newDir(fd: fd_t, path: []const u8) Self { + return Self{ + .fd = fd, + .@"type" = .{ .Dir = path }, + }; + } +}; + +pub const GetPreopenError = std.os.UnexpectedError || mem.Allocator.Error; + +pub fn getPreopens(allocator: *mem.Allocator) GetPreopenError![]Preopen { + var preopens = std.ArrayList(Preopen).init(allocator); + errdefer freePreopens(allocator, preopens); + var fd: fd_t = 3; // start fd has to be beyond stdio fds + + while (true) { + var buf: prestat_t = undefined; + switch (fd_prestat_get(fd, &buf)) { + ESUCCESS => {}, + ENOTSUP => { + // not a preopen, so keep going + continue; + }, + EBADF => { + // OK, no more fds available + break; + }, + else => |err| return std.os.unexpectedErrno(err), + } + const preopen_len = buf.u.dir.pr_name_len; + const path_buf = try allocator.alloc(u8, preopen_len); + mem.set(u8, path_buf, 0); + switch (fd_prestat_dir_name(fd, path_buf.ptr, preopen_len)) { + ESUCCESS => {}, + else => |err| return std.os.unexpectedErrno(err), + } + const preopen = Preopen.newDir(fd, path_buf); + try preopens.append(preopen); + fd += 1; + } + + return preopens.toOwnedSlice(); +} + +pub fn freePreopens(allocator: *mem.Allocator, preopens: std.ArrayList(Preopen)) void { + for (preopens.items) |preopen| { + switch (preopen.@"type") { + PreopenType.Dir => |path| allocator.free(path), + } + } + preopens.deinit(); +} + pub extern "wasi_snapshot_preview1" fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t; pub extern "wasi_snapshot_preview1" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;