From d7ca220121ade4031f09e6a7279fd08b617ee2c0 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 30 Apr 2020 18:06:15 +0200 Subject: [PATCH] Start drafting out openZ --- lib/std/os.zig | 24 +++++++++++++++++++++ lib/std/os/bits/wasi.zig | 2 ++ lib/std/os/wasi.zig | 45 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/lib/std/os.zig b/lib/std/os.zig index 86130ed32c..4437a4b8da 100644 --- a/lib/std/os.zig +++ b/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), diff --git a/lib/std/os/bits/wasi.zig b/lib/std/os/bits/wasi.zig index 0da984021d..d64b1f31c9 100644 --- a/lib/std/os/bits/wasi.zig +++ b/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; diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 23df66f385..07a354e67c 100644 --- a/lib/std/os/wasi.zig +++ b/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;