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;