Commit d7ca220121

Jakub Konka <kubkon@jakubkonka.com>
2020-04-30 18:06:15
Start drafting out openZ
1 parent f127dee
Changed files (3)
lib
lib/std/os/bits/wasi.zig
@@ -12,6 +12,8 @@ pub const timespec = extern struct {
     tv_nsec: isize,
 };
 
+pub const PATH_MAX = 4096; // TODO verify this!
+
 // As defined in the wasi_snapshot_preview1 spec file:
 // https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx
 pub const advice_t = u8;
lib/std/os/wasi.zig
@@ -20,6 +20,51 @@ comptime {
 pub const iovec_t = iovec;
 pub const ciovec_t = iovec_const;
 
+fn is_prefix(preopen: []const u8, path: []const u8) bool {
+    if (preopen.len > path.len) {
+        return false;
+    }
+    var i: usize = 0;
+    while (i < preopen.len) {
+        std.debug.warn("{} == {}", .{ preopen[i], path[i] });
+        if (preopen[i] != path[i]) {
+            return false;
+        }
+        i += 1;
+    }
+    return true;
+}
+
+pub fn resolve_preopen(path: []const u8, dirfd: *fd_t, prefix: *usize) errno_t {
+    var fd: fd_t = 3; // start fd has to be beyond stdio fds
+    var preopen_path = [_]u8{0} ** PATH_MAX;
+
+    while (true) {
+        var buf: prestat_t = undefined;
+        switch (fd_prestat_get(fd, &buf)) {
+            ESUCCESS => {},
+            EBADF => {
+                break;
+            },
+            else => |err| return err,
+        }
+        const preopen_len = buf.u.dir.pr_name_len;
+        switch (fd_prestat_dir_name(fd, &preopen_path, preopen_len)) {
+            ESUCCESS => {},
+            else => |err| return err,
+        }
+        if (is_prefix(preopen_path[0..preopen_len], path)) {
+            dirfd.* = fd;
+            prefix.* = preopen_len;
+            return ESUCCESS;
+        }
+        std.mem.set(u8, &preopen_path, 0);
+        fd += 1;
+    }
+
+    return ENOTCAPABLE;
+}
+
 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/os.zig
@@ -879,6 +879,30 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t
         return openW(file_path_w.span(), flags, perm);
     }
     while (true) {
+        if (builtin.os.tag == .wasi and !builtin.link_libc) {
+            var dirfd: fd_t = undefined;
+            var prefix: usize = undefined;
+            const path = mem.span(file_path);
+
+            switch (wasi.resolve_preopen(path, &dirfd, &prefix)) {
+                0 => {},
+                else => |err| return unexpectedErrno(err),
+            }
+
+            const rel_path = path[prefix + 1 ..];
+            // TODO map flags to wasi.oflag_t
+            // TODO call wasi.fd_fdstat_get to verify rights
+            // TODO adjust all flags to path_open
+            var fd: fd_t = undefined;
+
+            switch (wasi.path_open(dirfd, 0x0, rel_path.ptr, rel_path.len, wasi.O_CREAT, 0x0, 0x0, 0x0, &fd)) {
+                0 => {},
+                else => |err| return unexpectedErrno(err),
+            }
+
+            return fd;
+        }
+
         const rc = system.open(file_path, flags, perm);
         switch (errno(rc)) {
             0 => return @intCast(fd_t, rc),