Commit d7ca220121
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),