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 => {},