From d7ca220121ade4031f09e6a7279fd08b617ee2c0 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 30 Apr 2020 18:06:15 +0200 Subject: 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(+) (limited to 'lib/std') 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; -- cgit v1.2.3 From 8e1cd69717e8d87f53e930bd87edb7ca701b3f0c Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 1 May 2020 12:33:11 +0200 Subject: Implement std.fs.Dir.openFileWasi It seems that `std.os.openZ` is too POSIX-specific, so I think it should not be a point of entry for WASI `open` call. I figure WASI should be treated as a separate "os" that's _not_ POSIX especially given the incoming changes in the ephemeral snapshot. --- lib/std/fs.zig | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- lib/std/os.zig | 54 ++++++++++++++++++++++++++++++------------------------ 2 files changed, 79 insertions(+), 25 deletions(-) (limited to 'lib/std') diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 063b2f3fdc..a175ce4935 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -37,7 +37,7 @@ pub const Watch = @import("fs/watch.zig").Watch; /// fit into a UTF-8 encoded array of this length. /// The byte count includes room for a null sentinel byte. pub const MAX_PATH_BYTES = switch (builtin.os.tag) { - .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX, + .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly, .wasi => os.PATH_MAX, // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. // If it would require 4 UTF-8 bytes, then there would be a surrogate // pair in the UTF-16LE, and we (over)account 3 bytes for it that way. @@ -584,10 +584,33 @@ pub const Dir = struct { const path_w = try os.windows.sliceToPrefixedFileW(sub_path); return self.openFileW(path_w.span(), flags); } + if (builtin.os.tag == .wasi) { + return self.openFileWasi(sub_path, flags); + } const path_c = try os.toPosixPath(sub_path); return self.openFileZ(&path_c, flags); } + pub fn openFileWasi(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { + var fdflags: wasi.fdflag_t = 0x0; + var rights: wasi.rights_t = 0x0; + if (flags.read) { + rights |= wasi.FD_READ | wasi.FD_TELL | wasi.FD_FILESTAT_GET; + } + if (flags.write) { + fdflags |= wasi.FDFLAG_APPEND; + rights |= wasi.FD_WRITE | wasi.FD_DATASYNC | wasi.FD_SEEK | wasi.FD_FDSTAT_SET_FLAGS | wasi.FD_SYNC | wasi.FD_ALLOCATE | wasi.FD_ADVISE | wasi.FD_FILESTAT_SET_TIMES | wasi.FD_FILESTAT_SET_SIZE; + } + + const fd = try os.openatWasi(self.fd, sub_path, 0x0, fdflags, rights); + + return File{ + .handle = fd, + .io_mode = .blocking, + .async_block_allowed = File.async_block_allowed_no, + }; + } + pub const openFileC = @compileError("deprecated: renamed to openFileZ"); /// Same as `openFile` but the path parameter is null-terminated. @@ -671,12 +694,37 @@ pub const Dir = struct { const path_w = try os.windows.sliceToPrefixedFileW(sub_path); return self.createFileW(path_w.span(), flags); } + if (builtin.os.tag == .wasi) { + return self.createFileWasi(sub_path, flags); + } const path_c = try os.toPosixPath(sub_path); return self.createFileZ(&path_c, flags); } pub const createFileC = @compileError("deprecated: renamed to createFileZ"); + pub fn createFileWasi(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { + var oflags: wasi.oflags_t = 0x0; + var rights: wasi.rights_t = wasi.FD_WRITE | wasi.FD_DATASYNC | wasi.FD_SEEK | wasi.FD_FDSTAT_SET_FLAGS | wasi.FD_SYNC | wasi.FD_ALLOCATE | wasi.FD_ADVISE | wasi.FD_FILESTAT_SET_TIMES | wasi.FD_FILESTAT_SET_SIZE; + if (flags.read) { + rights |= wasi.FD_READ | wasi.FD_TELL | wasi.FD_FILESTAT_GET; + } + if (flags.truncate) { + oflags |= wasi.O_TRUNC; + } + if (flags.exclusive) { + oflags |= wasi.O_EXCL; + } + + const fd = try os.openatWasi(self.fd, sub_path, oflags, 0x0, rights); + + return File{ + .handle = fd, + .io_mode = .blocking, + .async_block_allowed = File.async_block_allowed_no, + }; + } + /// Same as `createFile` but the path parameter is null-terminated. pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File { if (builtin.os.tag == .windows) { diff --git a/lib/std/os.zig b/lib/std/os.zig index 4437a4b8da..eab623d93f 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -869,6 +869,26 @@ pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t { return openZ(&file_path_c, flags, perm); } +pub fn openWasi(file_path: []const u8, oflags: wasi.oflags_t, fdflags: wasi.fdflags_t, rights: wasi.rights_t) OpenError!fd_t { + var dirfd: fd_t = undefined; + var prefix: usize = undefined; + + switch (wasi.resolve_preopen(file_path, &dirfd, &prefix)) { + 0 => {}, + else => |err| return unexpectedErrno(err), + } + + const rel_path = file_path[prefix + 1 ..]; + var fd: fd_t = undefined; + switch (wasi.path_open(dirfd, 0x0, rel_path.ptr, rel_path.len, oflags, rights, 0x0, fdflags, &fd)) { + 0 => {}, + // TODO map errors + else => |err| return unexpectedErrno(err), + } + + return fd; +} + pub const openC = @compileError("deprecated: renamed to openZ"); /// Open and possibly create a file. Keeps trying if it gets interrupted. @@ -879,30 +899,6 @@ 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), @@ -947,6 +943,16 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope return openatZ(dir_fd, &file_path_c, flags, mode); } +pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, oflags: wasi.oflag_t, fdflags: wasi.fdflag_t, rights: wasi.rights_t) OpenError!fd_t { + switch (wasi.path_open(dirfd, 0x0, &file_path, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { + 0 => {}, + // TODO map errors + else => |err| return unexpectedErrno(err), + } + + return fd; +} + pub const openatC = @compileError("deprecated: renamed to openatZ"); /// Open and possibly create a file. Keeps trying if it gets interrupted. -- cgit v1.2.3 From 05fb3e79fecc689def1a4186da8783546e17f1ae Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 1 May 2020 22:27:11 +0200 Subject: Make std.fs.cwd() return preopen for "." if exists This commit adds WASI specific impl of `std.fs.cwd()` in which we emulate the `cwd` behaviour by inquiring the runtime for a "." preopen if available. This is OK for simple relative ops, but will not work for any ops which require absolute paths. --- lib/std/fs.zig | 23 ++++++++++++++++++----- lib/std/os.zig | 6 +++--- 2 files changed, 21 insertions(+), 8 deletions(-) (limited to 'lib/std') diff --git a/lib/std/fs.zig b/lib/std/fs.zig index a175ce4935..be729eb295 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -591,7 +591,7 @@ pub const Dir = struct { return self.openFileZ(&path_c, flags); } - pub fn openFileWasi(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { + fn openFileWasi(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { var fdflags: wasi.fdflag_t = 0x0; var rights: wasi.rights_t = 0x0; if (flags.read) { @@ -703,11 +703,12 @@ pub const Dir = struct { pub const createFileC = @compileError("deprecated: renamed to createFileZ"); - pub fn createFileWasi(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { - var oflags: wasi.oflags_t = 0x0; - var rights: wasi.rights_t = wasi.FD_WRITE | wasi.FD_DATASYNC | wasi.FD_SEEK | wasi.FD_FDSTAT_SET_FLAGS | wasi.FD_SYNC | wasi.FD_ALLOCATE | wasi.FD_ADVISE | wasi.FD_FILESTAT_SET_TIMES | wasi.FD_FILESTAT_SET_SIZE; + fn createFileWasi(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { + const wasi = os.wasi; + var oflags: wasi.oflags_t = wasi.O_CREAT; + var rights: wasi.rights_t = wasi.RIGHT_FD_WRITE | wasi.RIGHT_FD_DATASYNC | wasi.RIGHT_FD_SEEK | wasi.RIGHT_FD_FDSTAT_SET_FLAGS | wasi.RIGHT_FD_SYNC | wasi.RIGHT_FD_ALLOCATE | wasi.RIGHT_FD_ADVISE | wasi.RIGHT_FD_FILESTAT_SET_TIMES | wasi.RIGHT_FD_FILESTAT_SET_SIZE; if (flags.read) { - rights |= wasi.FD_READ | wasi.FD_TELL | wasi.FD_FILESTAT_GET; + rights |= wasi.RIGHT_FD_READ | wasi.RIGHT_FD_TELL | wasi.RIGHT_FD_FILESTAT_GET; } if (flags.truncate) { oflags |= wasi.O_TRUNC; @@ -1438,6 +1439,18 @@ pub const Dir = struct { 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 }; } else { return Dir{ .fd = os.AT_FDCWD }; } diff --git a/lib/std/os.zig b/lib/std/os.zig index eab623d93f..c3f5bc55ea 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -943,13 +943,13 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope return openatZ(dir_fd, &file_path_c, flags, mode); } -pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, oflags: wasi.oflag_t, fdflags: wasi.fdflag_t, rights: wasi.rights_t) OpenError!fd_t { - switch (wasi.path_open(dirfd, 0x0, &file_path, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { +pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, oflags: wasi.oflags_t, fdflags: wasi.fdflags_t, rights: wasi.rights_t) OpenError!fd_t { + var fd: fd_t = undefined; + switch (wasi.path_open(dir_fd, 0x0, file_path.ptr, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { 0 => {}, // TODO map errors else => |err| return unexpectedErrno(err), } - return fd; } -- cgit v1.2.3 From 8bce1b6981d5ec71100823dfd135402a32d9609b Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 4 May 2020 13:30:21 +0200 Subject: 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. --- lib/std/fs.zig | 12 +--------- lib/std/os/wasi.zig | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 11 deletions(-) (limited to 'lib/std') 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; -- cgit v1.2.3 From b8112b3d17c678456fa19d600aeaf78c787ca8bc Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 4 May 2020 13:35:02 +0200 Subject: Simplify File constructors --- lib/std/fs.zig | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'lib/std') diff --git a/lib/std/fs.zig b/lib/std/fs.zig index ed2d460cf4..cdaa0091ec 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -604,11 +604,7 @@ pub const Dir = struct { const fd = try os.openatWasi(self.fd, sub_path, 0x0, fdflags, rights); - return File{ - .handle = fd, - .io_mode = .blocking, - .async_block_allowed = File.async_block_allowed_no, - }; + return File{ .handle = fd }; } pub const openFileC = @compileError("deprecated: renamed to openFileZ"); @@ -719,11 +715,7 @@ pub const Dir = struct { const fd = try os.openatWasi(self.fd, sub_path, oflags, 0x0, rights); - return File{ - .handle = fd, - .io_mode = .blocking, - .async_block_allowed = File.async_block_allowed_no, - }; + return File{ .handle = fd }; } /// Same as `createFile` but the path parameter is null-terminated. -- cgit v1.2.3 From fc77e393fdbaf874ab22d528ba2bc3d63836b439 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 4 May 2020 13:40:57 +0200 Subject: Remove obsolete PATH_MAX const --- lib/std/os/bits/wasi.zig | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib/std') diff --git a/lib/std/os/bits/wasi.zig b/lib/std/os/bits/wasi.zig index d64b1f31c9..0da984021d 100644 --- a/lib/std/os/bits/wasi.zig +++ b/lib/std/os/bits/wasi.zig @@ -12,8 +12,6 @@ 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; -- cgit v1.2.3 From dd238352a4d3a9f02ff62d32cd109adabee30b66 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 4 May 2020 21:20:00 +0200 Subject: Encapsulate getPreopens inside PreopenList --- lib/std/os.zig | 20 -------- lib/std/os/wasi.zig | 136 ++++++++++++++++++++-------------------------------- 2 files changed, 52 insertions(+), 104 deletions(-) (limited to 'lib/std') diff --git a/lib/std/os.zig b/lib/std/os.zig index c3f5bc55ea..5335b2ca24 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -869,26 +869,6 @@ pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t { return openZ(&file_path_c, flags, perm); } -pub fn openWasi(file_path: []const u8, oflags: wasi.oflags_t, fdflags: wasi.fdflags_t, rights: wasi.rights_t) OpenError!fd_t { - var dirfd: fd_t = undefined; - var prefix: usize = undefined; - - switch (wasi.resolve_preopen(file_path, &dirfd, &prefix)) { - 0 => {}, - else => |err| return unexpectedErrno(err), - } - - const rel_path = file_path[prefix + 1 ..]; - var fd: fd_t = undefined; - switch (wasi.path_open(dirfd, 0x0, rel_path.ptr, rel_path.len, oflags, rights, 0x0, fdflags, &fd)) { - 0 => {}, - // TODO map errors - else => |err| return unexpectedErrno(err), - } - - return fd; -} - pub const openC = @compileError("deprecated: renamed to openZ"); /// Open and possibly create a file. Keeps trying if it gets interrupted. diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 9acf9001f6..07f6786518 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -4,6 +4,7 @@ const std = @import("std"); const mem = std.mem; const assert = std.debug.assert; +const Allocator = mem.Allocator; pub usingnamespace @import("bits.zig"); @@ -21,51 +22,6 @@ 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 const PreopenType = enum { Dir, }; @@ -86,50 +42,62 @@ pub const Preopen = struct { } }; -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; +pub const PreopenList = struct { + const InnerList = std.ArrayList(Preopen); + + buffer: InnerList, + + const Self = @This(); + pub const Error = std.os.UnexpectedError || Allocator.Error; + + pub fn init(allocator: *Allocator) Self { + return Self{ .buffer = InnerList.init(allocator) }; } - return preopens.toOwnedSlice(); -} + pub fn deinit(pm: Self) void { + for (pm.buffer.items) |preopen| { + switch (preopen.@"type") { + PreopenType.Dir => |path| pm.buffer.allocator.free(path), + } + } + pm.buffer.deinit(); + } -pub fn freePreopens(allocator: *mem.Allocator, preopens: std.ArrayList(Preopen)) void { - for (preopens.items) |preopen| { - switch (preopen.@"type") { - PreopenType.Dir => |path| allocator.free(path), + pub fn populate(self: *Self) Error!void { + errdefer self.deinit(); + 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 self.buffer.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 self.buffer.append(preopen); + fd += 1; } } - preopens.deinit(); -} + + pub fn asSlice(self: *const Self) []const Preopen { + return self.buffer.items; + } +}; 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; -- cgit v1.2.3 From d4c33129cf86441a59079e15fd887711fae8d924 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 4 May 2020 21:47:33 +0200 Subject: Shuffle things around; add PreopenList.findByPath method This commit removes `std.os.openatWasi` function, and renames it to `std.os.wasi.openat`. Additionally, the added `PreopenList.findByPath` method allows querying the list for a matching preopen by path. --- lib/std/fs.zig | 4 ++-- lib/std/os.zig | 10 ---------- lib/std/os/wasi.zig | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 12 deletions(-) (limited to 'lib/std') diff --git a/lib/std/fs.zig b/lib/std/fs.zig index cdaa0091ec..33457c0255 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -602,7 +602,7 @@ pub const Dir = struct { rights |= wasi.FD_WRITE | wasi.FD_DATASYNC | wasi.FD_SEEK | wasi.FD_FDSTAT_SET_FLAGS | wasi.FD_SYNC | wasi.FD_ALLOCATE | wasi.FD_ADVISE | wasi.FD_FILESTAT_SET_TIMES | wasi.FD_FILESTAT_SET_SIZE; } - const fd = try os.openatWasi(self.fd, sub_path, 0x0, fdflags, rights); + const fd = try wasi.openat(self.fd, sub_path, 0x0, fdflags, rights); return File{ .handle = fd }; } @@ -713,7 +713,7 @@ pub const Dir = struct { oflags |= wasi.O_EXCL; } - const fd = try os.openatWasi(self.fd, sub_path, oflags, 0x0, rights); + const fd = try wasi.openat(self.fd, sub_path, oflags, 0x0, rights); return File{ .handle = fd }; } diff --git a/lib/std/os.zig b/lib/std/os.zig index 5335b2ca24..86130ed32c 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -923,16 +923,6 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope return openatZ(dir_fd, &file_path_c, flags, mode); } -pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, oflags: wasi.oflags_t, fdflags: wasi.fdflags_t, rights: wasi.rights_t) OpenError!fd_t { - var fd: fd_t = undefined; - switch (wasi.path_open(dir_fd, 0x0, file_path.ptr, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { - 0 => {}, - // TODO map errors - else => |err| return unexpectedErrno(err), - } - return fd; -} - pub const openatC = @compileError("deprecated: renamed to openatZ"); /// Open and possibly create a file. Keeps trying if it gets interrupted. diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 07f6786518..cb0ad5c3c6 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -94,11 +94,32 @@ pub const PreopenList = struct { } } + pub fn find(self: *const Self, path: []const u8) ?*const Preopen { + for (self.buffer.items) |preopen| { + switch (preopen.@"type") { + PreopenType.Dir => |preopen_path| { + if (mem.eql(u8, path, preopen_path)) return &preopen; + }, + } + } + return null; + } + pub fn asSlice(self: *const Self) []const Preopen { return self.buffer.items; } }; +pub fn openat(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags: fdflags_t, rights: rights_t) std.os.OpenError!fd_t { + var fd: fd_t = undefined; + switch (path_open(dir_fd, 0x0, file_path.ptr, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { + 0 => {}, + // TODO map errors + else => |err| return std.os.unexpectedErrno(err), + } + return fd; +} + 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; -- cgit v1.2.3 From 558bb24601c6de5f05cded4e99b795e85bb3b8e6 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 5 May 2020 15:07:21 +0200 Subject: Move preopen and path wasi helpers to std.fs.wasi module Previously, the path and preopens helpers were prototyped in `std.os.wasi` module, but since they are higher-level abstraction over wasi, they belong in `std.fs.wasi` module. --- lib/std/fs.zig | 6 +-- lib/std/fs/wasi.zig | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/std/os/wasi.zig | 100 -------------------------------------------------- 3 files changed, 106 insertions(+), 104 deletions(-) create mode 100644 lib/std/fs/wasi.zig (limited to 'lib/std') diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 33457c0255..e7d1ce8189 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -12,6 +12,7 @@ const is_darwin = std.Target.current.os.tag.isDarwin(); pub const path = @import("fs/path.zig"); pub const File = @import("fs/file.zig").File; +pub const wasi = @import("fs/wasi.zig"); // TODO audit these APIs with respect to Dir and absolute paths @@ -37,7 +38,7 @@ pub const Watch = @import("fs/watch.zig").Watch; /// fit into a UTF-8 encoded array of this length. /// The byte count includes room for a null sentinel byte. pub const MAX_PATH_BYTES = switch (builtin.os.tag) { - .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly, .wasi => os.PATH_MAX, + .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX, // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. // If it would require 4 UTF-8 bytes, then there would be a surrogate // pair in the UTF-16LE, and we (over)account 3 bytes for it that way. @@ -700,7 +701,6 @@ pub const Dir = struct { pub const createFileC = @compileError("deprecated: renamed to createFileZ"); fn createFileWasi(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { - const wasi = os.wasi; var oflags: wasi.oflags_t = wasi.O_CREAT; var rights: wasi.rights_t = wasi.RIGHT_FD_WRITE | wasi.RIGHT_FD_DATASYNC | wasi.RIGHT_FD_SEEK | wasi.RIGHT_FD_FDSTAT_SET_FLAGS | wasi.RIGHT_FD_SYNC | wasi.RIGHT_FD_ALLOCATE | wasi.RIGHT_FD_ADVISE | wasi.RIGHT_FD_FILESTAT_SET_TIMES | wasi.RIGHT_FD_FILESTAT_SET_SIZE; if (flags.read) { @@ -712,9 +712,7 @@ pub const Dir = struct { if (flags.exclusive) { oflags |= wasi.O_EXCL; } - const fd = try wasi.openat(self.fd, sub_path, oflags, 0x0, rights); - return File{ .handle = fd }; } diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig new file mode 100644 index 0000000000..0c179a3df2 --- /dev/null +++ b/lib/std/fs/wasi.zig @@ -0,0 +1,104 @@ +const std = @import("std"); +const os = std.os; +const mem = std.mem; +const Allocator = mem.Allocator; + +usingnamespace std.os.wasi; + +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 PreopenList = struct { + const InnerList = std.ArrayList(Preopen); + + buffer: InnerList, + + const Self = @This(); + pub const Error = os.UnexpectedError || Allocator.Error; + + pub fn init(allocator: *Allocator) Self { + return Self{ .buffer = InnerList.init(allocator) }; + } + + pub fn deinit(pm: Self) void { + for (pm.buffer.items) |preopen| { + switch (preopen.@"type") { + PreopenType.Dir => |path| pm.buffer.allocator.free(path), + } + } + pm.buffer.deinit(); + } + + pub fn populate(self: *Self) Error!void { + errdefer self.deinit(); + 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 os.unexpectedErrno(err), + } + const preopen_len = buf.u.dir.pr_name_len; + const path_buf = try self.buffer.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 os.unexpectedErrno(err), + } + const preopen = Preopen.newDir(fd, path_buf); + try self.buffer.append(preopen); + fd += 1; + } + } + + pub fn find(self: *const Self, path: []const u8) ?*const Preopen { + for (self.buffer.items) |preopen| { + switch (preopen.@"type") { + PreopenType.Dir => |preopen_path| { + if (mem.eql(u8, path, preopen_path)) return &preopen; + }, + } + } + return null; + } + + pub fn asSlice(self: *const Self) []const Preopen { + return self.buffer.items; + } +}; + +pub fn openat(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags: fdflags_t, rights: rights_t) std.os.OpenError!fd_t { + var fd: fd_t = undefined; + switch (path_open(dir_fd, 0x0, file_path.ptr, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { + 0 => {}, + // TODO map errors + else => |err| return std.os.unexpectedErrno(err), + } + return fd; +} diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index cb0ad5c3c6..23df66f385 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -2,9 +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; -const Allocator = mem.Allocator; pub usingnamespace @import("bits.zig"); @@ -22,104 +20,6 @@ comptime { pub const iovec_t = iovec; pub const ciovec_t = iovec_const; -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 PreopenList = struct { - const InnerList = std.ArrayList(Preopen); - - buffer: InnerList, - - const Self = @This(); - pub const Error = std.os.UnexpectedError || Allocator.Error; - - pub fn init(allocator: *Allocator) Self { - return Self{ .buffer = InnerList.init(allocator) }; - } - - pub fn deinit(pm: Self) void { - for (pm.buffer.items) |preopen| { - switch (preopen.@"type") { - PreopenType.Dir => |path| pm.buffer.allocator.free(path), - } - } - pm.buffer.deinit(); - } - - pub fn populate(self: *Self) Error!void { - errdefer self.deinit(); - 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 self.buffer.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 self.buffer.append(preopen); - fd += 1; - } - } - - pub fn find(self: *const Self, path: []const u8) ?*const Preopen { - for (self.buffer.items) |preopen| { - switch (preopen.@"type") { - PreopenType.Dir => |preopen_path| { - if (mem.eql(u8, path, preopen_path)) return &preopen; - }, - } - } - return null; - } - - pub fn asSlice(self: *const Self) []const Preopen { - return self.buffer.items; - } -}; - -pub fn openat(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags: fdflags_t, rights: rights_t) std.os.OpenError!fd_t { - var fd: fd_t = undefined; - switch (path_open(dir_fd, 0x0, file_path.ptr, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { - 0 => {}, - // TODO map errors - else => |err| return std.os.unexpectedErrno(err), - } - return fd; -} - 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; -- cgit v1.2.3 From 07a968b3444c1db036d605ed8a25bc128110b646 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 5 May 2020 17:05:30 +0200 Subject: Add docs --- lib/std/fs.zig | 46 ++++++++++++++++++++++++++++++++-------------- lib/std/fs/wasi.zig | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 15 deletions(-) (limited to 'lib/std') diff --git a/lib/std/fs.zig b/lib/std/fs.zig index e7d1ce8189..862fc84ef1 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -592,19 +592,27 @@ pub const Dir = struct { return self.openFileZ(&path_c, flags); } - fn openFileWasi(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { - var fdflags: wasi.fdflag_t = 0x0; - var rights: wasi.rights_t = 0x0; + /// Save as `openFile` but WASI only. + pub fn openFileWasi(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { + const w = os.wasi; + var fdflags: w.fdflag_t = 0x0; + var rights: w.rights_t = 0x0; if (flags.read) { - rights |= wasi.FD_READ | wasi.FD_TELL | wasi.FD_FILESTAT_GET; + rights |= w.FD_READ | w.FD_TELL | w.FD_FILESTAT_GET; } if (flags.write) { - fdflags |= wasi.FDFLAG_APPEND; - rights |= wasi.FD_WRITE | wasi.FD_DATASYNC | wasi.FD_SEEK | wasi.FD_FDSTAT_SET_FLAGS | wasi.FD_SYNC | wasi.FD_ALLOCATE | wasi.FD_ADVISE | wasi.FD_FILESTAT_SET_TIMES | wasi.FD_FILESTAT_SET_SIZE; + fdflags |= w.FDFLAG_APPEND; + rights |= w.FD_WRITE | + w.FD_DATASYNC | + w.FD_SEEK | + w.FD_FDSTAT_SET_FLAGS | + w.FD_SYNC | + w.FD_ALLOCATE | + w.FD_ADVISE | + w.FD_FILESTAT_SET_TIMES | + w.FD_FILESTAT_SET_SIZE; } - const fd = try wasi.openat(self.fd, sub_path, 0x0, fdflags, rights); - return File{ .handle = fd }; } @@ -700,17 +708,27 @@ pub const Dir = struct { pub const createFileC = @compileError("deprecated: renamed to createFileZ"); - fn createFileWasi(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { - var oflags: wasi.oflags_t = wasi.O_CREAT; - var rights: wasi.rights_t = wasi.RIGHT_FD_WRITE | wasi.RIGHT_FD_DATASYNC | wasi.RIGHT_FD_SEEK | wasi.RIGHT_FD_FDSTAT_SET_FLAGS | wasi.RIGHT_FD_SYNC | wasi.RIGHT_FD_ALLOCATE | wasi.RIGHT_FD_ADVISE | wasi.RIGHT_FD_FILESTAT_SET_TIMES | wasi.RIGHT_FD_FILESTAT_SET_SIZE; + /// Same as `createFile` but WASI only. + pub fn createFileWasi(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { + const w = os.wasi; + var oflags = w.O_CREAT; + var rights = w.RIGHT_FD_WRITE | + w.RIGHT_FD_DATASYNC | + w.RIGHT_FD_SEEK | + w.RIGHT_FD_FDSTAT_SET_FLAGS | + w.RIGHT_FD_SYNC | + w.RIGHT_FD_ALLOCATE | + w.RIGHT_FD_ADVISE | + w.RIGHT_FD_FILESTAT_SET_TIMES | + w.RIGHT_FD_FILESTAT_SET_SIZE; if (flags.read) { - rights |= wasi.RIGHT_FD_READ | wasi.RIGHT_FD_TELL | wasi.RIGHT_FD_FILESTAT_GET; + rights |= w.RIGHT_FD_READ | w.RIGHT_FD_TELL | w.RIGHT_FD_FILESTAT_GET; } if (flags.truncate) { - oflags |= wasi.O_TRUNC; + oflags |= w.O_TRUNC; } if (flags.exclusive) { - oflags |= wasi.O_EXCL; + oflags |= w.O_EXCL; } const fd = try wasi.openat(self.fd, sub_path, oflags, 0x0, rights); return File{ .handle = fd }; diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig index 0c179a3df2..21107c2094 100644 --- a/lib/std/fs/wasi.zig +++ b/lib/std/fs/wasi.zig @@ -5,18 +5,30 @@ const Allocator = mem.Allocator; usingnamespace std.os.wasi; +/// Type of WASI preopen. +/// +/// WASI currently offers only `Dir` as a valid preopen resource. pub const PreopenType = enum { Dir, }; +/// WASI preopen struct. This struct consists of a WASI file descriptor +/// and type of WASI preopen. It can be obtained directly from the WASI +/// runtime using `PreopenList.populate()` method. pub const Preopen = struct { + /// WASI file descriptor. fd: fd_t, + + /// Type of the preopen. @"type": union(PreopenType) { + /// Path to a preopened directory. Dir: []const u8, }, const Self = @This(); + /// Construct new `Preopen` instance of type `PreopenType.Dir` from + /// WASI file descriptor and WASI path. pub fn newDir(fd: fd_t, path: []const u8) Self { return Self{ .fd = fd, @@ -25,18 +37,29 @@ pub const Preopen = struct { } }; +/// Dynamically-sized array list of WASI preopens. This struct is a +/// convenience wrapper for issuing `std.os.wasi.fd_prestat_get` and +/// `std.os.wasi.fd_prestat_dir_name` syscalls to the WASI runtime, and +/// collecting the returned preopens. +/// +/// This struct is intended to be used in any WASI program which intends +/// to use the capabilities as passed on by the user of the runtime. pub const PreopenList = struct { const InnerList = std.ArrayList(Preopen); + /// Internal dynamically-sized buffer for storing the gathered preopens. buffer: InnerList, const Self = @This(); + pub const Error = os.UnexpectedError || Allocator.Error; + /// Deinitialize with `deinit`. pub fn init(allocator: *Allocator) Self { return Self{ .buffer = InnerList.init(allocator) }; } + /// Release all allocated memory. pub fn deinit(pm: Self) void { for (pm.buffer.items) |preopen| { switch (preopen.@"type") { @@ -46,6 +69,8 @@ pub const PreopenList = struct { pm.buffer.deinit(); } + /// Populate the list with the preopens by issuing `std.os.wasi.fd_prestat_get` + /// and `std.os.wasi.fd_prestat_dir_name` syscalls to the runtime. pub fn populate(self: *Self) Error!void { errdefer self.deinit(); var fd: fd_t = 3; // start fd has to be beyond stdio fds @@ -77,6 +102,12 @@ pub const PreopenList = struct { } } + /// Find preopen by path. If the preopen exists, return it. + /// Otherwise, return `null`. + /// + /// TODO make the function more generic by searching by `PreopenType` union. This will + /// be needed in the future when WASI extends its capabilities to resources + /// other than preopened directories. pub fn find(self: *const Self, path: []const u8) ?*const Preopen { for (self.buffer.items) |preopen| { switch (preopen.@"type") { @@ -88,12 +119,14 @@ pub const PreopenList = struct { return null; } + /// Return the inner buffer as read-only slice. pub fn asSlice(self: *const Self) []const Preopen { return self.buffer.items; } }; -pub fn openat(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags: fdflags_t, rights: rights_t) std.os.OpenError!fd_t { +/// Convenience wrapper for `std.os.wasi.path_open` syscall. +pub fn openat(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags: fdflags_t, rights: rights_t) os.OpenError!fd_t { var fd: fd_t = undefined; switch (path_open(dir_fd, 0x0, file_path.ptr, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { 0 => {}, -- cgit v1.2.3 From 81d824bf80b71fceeb01238824c272d899a364fc Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 5 May 2020 17:23:49 +0200 Subject: Clear PreopenList on every populate call --- lib/std/fs/wasi.zig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'lib/std') diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig index 21107c2094..1cf56e6c7b 100644 --- a/lib/std/fs/wasi.zig +++ b/lib/std/fs/wasi.zig @@ -71,7 +71,16 @@ pub const PreopenList = struct { /// Populate the list with the preopens by issuing `std.os.wasi.fd_prestat_get` /// and `std.os.wasi.fd_prestat_dir_name` syscalls to the runtime. + /// + /// If called more than once, it will clear its contents every time before + /// issuing the syscalls. pub fn populate(self: *Self) Error!void { + // Clear contents if we're being called again + for (self.toOwnedSlice()) |preopen| { + switch (preopen.@"type") { + PreopenType.Dir => |path| self.buffer.allocator.free(path), + } + } errdefer self.deinit(); var fd: fd_t = 3; // start fd has to be beyond stdio fds @@ -123,6 +132,11 @@ pub const PreopenList = struct { pub fn asSlice(self: *const Self) []const Preopen { return self.buffer.items; } + + /// The caller owns the returned memory. ArrayList becomes empty. + pub fn toOwnedSlice(self: *Self) []Preopen { + return self.buffer.toOwnedSlice(); + } }; /// Convenience wrapper for `std.os.wasi.path_open` syscall. -- cgit v1.2.3