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.