| ... | @@ -5,18 +5,30 @@ const Allocator = mem.Allocator; | ... | @@ -5,18 +5,30 @@ const Allocator = mem.Allocator; |
| 5 | | 5 | |
| 6 | usingnamespace std.os.wasi; | 6 | usingnamespace std.os.wasi; |
| 7 | | 7 | |
| | 8 | /// Type of WASI preopen. |
| | 9 | /// |
| | 10 | /// WASI currently offers only `Dir` as a valid preopen resource. |
| 8 | pub const PreopenType = enum { | 11 | pub const PreopenType = enum { |
| 9 | Dir, | 12 | Dir, |
| 10 | }; | 13 | }; |
| 11 | | 14 | |
| | 15 | /// WASI preopen struct. This struct consists of a WASI file descriptor |
| | 16 | /// and type of WASI preopen. It can be obtained directly from the WASI |
| | 17 | /// runtime using `PreopenList.populate()` method. |
| 12 | pub const Preopen = struct { | 18 | pub const Preopen = struct { |
| | 19 | /// WASI file descriptor. |
| 13 | fd: fd_t, | 20 | fd: fd_t, |
| | 21 | |
| | 22 | /// Type of the preopen. |
| 14 | @"type": union(PreopenType) { | 23 | @"type": union(PreopenType) { |
| | 24 | /// Path to a preopened directory. |
| 15 | Dir: []const u8, | 25 | Dir: []const u8, |
| 16 | }, | 26 | }, |
| 17 | | 27 | |
| 18 | const Self = @This(); | 28 | const Self = @This(); |
| 19 | | 29 | |
| | 30 | /// Construct new `Preopen` instance of type `PreopenType.Dir` from |
| | 31 | /// WASI file descriptor and WASI path. |
| 20 | pub fn newDir(fd: fd_t, path: []const u8) Self { | 32 | pub fn newDir(fd: fd_t, path: []const u8) Self { |
| 21 | return Self{ | 33 | return Self{ |
| 22 | .fd = fd, | 34 | .fd = fd, |
| ... | @@ -25,18 +37,29 @@ pub const Preopen = struct { | ... | @@ -25,18 +37,29 @@ pub const Preopen = struct { |
| 25 | } | 37 | } |
| 26 | }; | 38 | }; |
| 27 | | 39 | |
| | 40 | /// Dynamically-sized array list of WASI preopens. This struct is a |
| | 41 | /// convenience wrapper for issuing `std.os.wasi.fd_prestat_get` and |
| | 42 | /// `std.os.wasi.fd_prestat_dir_name` syscalls to the WASI runtime, and |
| | 43 | /// collecting the returned preopens. |
| | 44 | /// |
| | 45 | /// This struct is intended to be used in any WASI program which intends |
| | 46 | /// to use the capabilities as passed on by the user of the runtime. |
| 28 | pub const PreopenList = struct { | 47 | pub const PreopenList = struct { |
| 29 | const InnerList = std.ArrayList(Preopen); | 48 | const InnerList = std.ArrayList(Preopen); |
| 30 | | 49 | |
| | 50 | /// Internal dynamically-sized buffer for storing the gathered preopens. |
| 31 | buffer: InnerList, | 51 | buffer: InnerList, |
| 32 | | 52 | |
| 33 | const Self = @This(); | 53 | const Self = @This(); |
| | 54 | |
| 34 | pub const Error = os.UnexpectedError || Allocator.Error; | 55 | pub const Error = os.UnexpectedError || Allocator.Error; |
| 35 | | 56 | |
| | 57 | /// Deinitialize with `deinit`. |
| 36 | pub fn init(allocator: *Allocator) Self { | 58 | pub fn init(allocator: *Allocator) Self { |
| 37 | return Self{ .buffer = InnerList.init(allocator) }; | 59 | return Self{ .buffer = InnerList.init(allocator) }; |
| 38 | } | 60 | } |
| 39 | | 61 | |
| | 62 | /// Release all allocated memory. |
| 40 | pub fn deinit(pm: Self) void { | 63 | pub fn deinit(pm: Self) void { |
| 41 | for (pm.buffer.items) |preopen| { | 64 | for (pm.buffer.items) |preopen| { |
| 42 | switch (preopen.@"type") { | 65 | switch (preopen.@"type") { |
| ... | @@ -46,6 +69,8 @@ pub const PreopenList = struct { | ... | @@ -46,6 +69,8 @@ pub const PreopenList = struct { |
| 46 | pm.buffer.deinit(); | 69 | pm.buffer.deinit(); |
| 47 | } | 70 | } |
| 48 | | 71 | |
| | 72 | /// Populate the list with the preopens by issuing `std.os.wasi.fd_prestat_get` |
| | 73 | /// and `std.os.wasi.fd_prestat_dir_name` syscalls to the runtime. |
| 49 | pub fn populate(self: *Self) Error!void { | 74 | pub fn populate(self: *Self) Error!void { |
| 50 | errdefer self.deinit(); | 75 | errdefer self.deinit(); |
| 51 | var fd: fd_t = 3; // start fd has to be beyond stdio fds | 76 | var fd: fd_t = 3; // start fd has to be beyond stdio fds |
| ... | @@ -77,6 +102,12 @@ pub const PreopenList = struct { | ... | @@ -77,6 +102,12 @@ pub const PreopenList = struct { |
| 77 | } | 102 | } |
| 78 | } | 103 | } |
| 79 | | 104 | |
| | 105 | /// Find preopen by path. If the preopen exists, return it. |
| | 106 | /// Otherwise, return `null`. |
| | 107 | /// |
| | 108 | /// TODO make the function more generic by searching by `PreopenType` union. This will |
| | 109 | /// be needed in the future when WASI extends its capabilities to resources |
| | 110 | /// other than preopened directories. |
| 80 | pub fn find(self: *const Self, path: []const u8) ?*const Preopen { | 111 | pub fn find(self: *const Self, path: []const u8) ?*const Preopen { |
| 81 | for (self.buffer.items) |preopen| { | 112 | for (self.buffer.items) |preopen| { |
| 82 | switch (preopen.@"type") { | 113 | switch (preopen.@"type") { |
| ... | @@ -88,12 +119,14 @@ pub const PreopenList = struct { | ... | @@ -88,12 +119,14 @@ pub const PreopenList = struct { |
| 88 | return null; | 119 | return null; |
| 89 | } | 120 | } |
| 90 | | 121 | |
| | 122 | /// Return the inner buffer as read-only slice. |
| 91 | pub fn asSlice(self: *const Self) []const Preopen { | 123 | pub fn asSlice(self: *const Self) []const Preopen { |
| 92 | return self.buffer.items; | 124 | return self.buffer.items; |
| 93 | } | 125 | } |
| 94 | }; | 126 | }; |
| 95 | | 127 | |
| 96 | 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 { | 128 | /// Convenience wrapper for `std.os.wasi.path_open` syscall. |
| | 129 | pub fn openat(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags: fdflags_t, rights: rights_t) os.OpenError!fd_t { |
| 97 | var fd: fd_t = undefined; | 130 | var fd: fd_t = undefined; |
| 98 | switch (path_open(dir_fd, 0x0, file_path.ptr, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { | 131 | switch (path_open(dir_fd, 0x0, file_path.ptr, file_path.len, oflags, rights, 0x0, fdflags, &fd)) { |
| 99 | 0 => {}, | 132 | 0 => {}, |