Commit 8bce1b6981

Jakub Konka <kubkon@jakubkonka.com>
2020-05-04 13:30:21
Refactor resolve_preopen into getPreopens function
This commit refactors `std.os.wasi.resolve_preopen` into a (higher-level) `std.os.wasi.getPreopens` funtion which returns a slice with _all_ preopens at any given time. This fn allows the WASI module to inquire at any given time for all preopens provided by the runtime. This commit also makes `cwd()` a compile error on WASI.
1 parent 05fb3e7
Changed files (2)
lib
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;
 
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 };
     }