authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-06-29 17:10:01+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-06-29 17:10:01+02:00
logbf8bf528c6c131f61de4af24c3599486a59c5868
tree5350bc08ee690d446c219a4df7076390dde7dbad
parent374e3e42e0de10d21406c077599cfc4a6a813497

Handle ENOTCAPABLE in WASI

This commit adds `error.NotCapable` enum value and makes sure that every applicable WASI syscall that can return `ENOTCAPABLE` errno remaps it to `error.NotCapable.

2 files changed, 132 insertions(+), 43 deletions(-)

lib/std/fs.zig+24-10
......@@ -264,7 +264,13 @@ pub const Dir = struct {
264264 pub const Kind = File.Kind;
265265 };
266266
267 const IteratorError = error{AccessDenied} || os.UnexpectedError;
267 const IteratorError = error{
268 AccessDenied,
269
270 /// WASI-only. This error occurs when the underlying `Dir` file descriptor does
271 /// not hold the required rights to call `fd_readdir` on it.
272 NotCapable,
273 } || os.UnexpectedError;
268274
269275 pub const Iterator = switch (builtin.os.tag) {
270276 .macosx, .ios, .freebsd, .netbsd, .dragonfly => struct {
......@@ -535,14 +541,15 @@ pub const Dir = struct {
535541 w.EFAULT => unreachable,
536542 w.ENOTDIR => unreachable,
537543 w.EINVAL => unreachable,
544 w.ENOTCAPABLE => return error.NotCapable,
538545 else => |err| return os.unexpectedErrno(err),
539546 }
540547 if (bufused == 0) return null;
541548 self.index = 0;
542549 self.end_index = bufused;
543550 }
544 const entry = @ptrCast(*align(1) os.wasi.dirent_t, &self.buf[self.index]);
545 const entry_size = @sizeOf(os.wasi.dirent_t);
551 const entry = @ptrCast(*align(1) w.dirent_t, &self.buf[self.index]);
552 const entry_size = @sizeOf(w.dirent_t);
546553 const name_index = self.index + entry_size;
547554 const name = mem.span(self.buf[name_index .. name_index + entry.d_namlen]);
548555
......@@ -556,12 +563,12 @@ pub const Dir = struct {
556563 }
557564
558565 const entry_kind = switch (entry.d_type) {
559 wasi.FILETYPE_BLOCK_DEVICE => Entry.Kind.BlockDevice,
560 wasi.FILETYPE_CHARACTER_DEVICE => Entry.Kind.CharacterDevice,
561 wasi.FILETYPE_DIRECTORY => Entry.Kind.Directory,
562 wasi.FILETYPE_SYMBOLIC_LINK => Entry.Kind.SymLink,
563 wasi.FILETYPE_REGULAR_FILE => Entry.Kind.File,
564 wasi.FILETYPE_SOCKET_STREAM, wasi.FILETYPE_SOCKET_DGRAM => Entry.Kind.UnixDomainSocket,
566 w.FILETYPE_BLOCK_DEVICE => Entry.Kind.BlockDevice,
567 w.FILETYPE_CHARACTER_DEVICE => Entry.Kind.CharacterDevice,
568 w.FILETYPE_DIRECTORY => Entry.Kind.Directory,
569 w.FILETYPE_SYMBOLIC_LINK => Entry.Kind.SymLink,
570 w.FILETYPE_REGULAR_FILE => Entry.Kind.File,
571 w.FILETYPE_SOCKET_STREAM, wasi.FILETYPE_SOCKET_DGRAM => Entry.Kind.UnixDomainSocket,
565572 else => Entry.Kind.Unknown,
566573 };
567574 return Entry{
......@@ -621,6 +628,7 @@ pub const Dir = struct {
621628 InvalidUtf8,
622629 BadPathName,
623630 DeviceBusy,
631 NotCapable,
624632 } || os.UnexpectedError;
625633
626634 pub fn close(self: *Dir) void {
......@@ -1105,7 +1113,7 @@ pub const Dir = struct {
11051113 }
11061114 }
11071115
1108 pub const DeleteFileError = os.UnlinkError;
1116 pub const DeleteFileError = os.UnlinkatError;
11091117
11101118 /// Delete a file name and possibly the file it refers to, based on an open directory handle.
11111119 /// Asserts that the path parameter has no null bytes.
......@@ -1147,6 +1155,7 @@ pub const Dir = struct {
11471155 ReadOnlyFileSystem,
11481156 InvalidUtf8,
11491157 BadPathName,
1158 NotCapable,
11501159 Unexpected,
11511160 };
11521161
......@@ -1249,6 +1258,7 @@ pub const Dir = struct {
12491258 /// On Windows, file paths cannot contain these characters:
12501259 /// '/', '*', '?', '"', '<', '>', '|'
12511260 BadPathName,
1261 NotCapable,
12521262 } || os.UnexpectedError;
12531263
12541264 /// Whether `full_path` describes a symlink, file, or directory, this function
......@@ -1276,6 +1286,7 @@ pub const Dir = struct {
12761286 error.FileBusy,
12771287 error.BadPathName,
12781288 error.Unexpected,
1289 error.NotCapable,
12791290 => |e| return e,
12801291 }
12811292 var dir = self.openDir(sub_path, .{ .iterate = true }) catch |err| switch (err) {
......@@ -1301,6 +1312,7 @@ pub const Dir = struct {
13011312 error.InvalidUtf8,
13021313 error.BadPathName,
13031314 error.DeviceBusy,
1315 error.NotCapable,
13041316 => |e| return e,
13051317 };
13061318 var cleanup_dir_parent: ?Dir = null;
......@@ -1342,6 +1354,7 @@ pub const Dir = struct {
13421354 error.FileBusy,
13431355 error.BadPathName,
13441356 error.Unexpected,
1357 error.NotCapable,
13451358 => |e| return e,
13461359 }
13471360
......@@ -1368,6 +1381,7 @@ pub const Dir = struct {
13681381 error.InvalidUtf8,
13691382 error.BadPathName,
13701383 error.DeviceBusy,
1384 error.NotCapable,
13711385 => |e| return e,
13721386 };
13731387 if (cleanup_dir_parent) |*d| d.close();
lib/std/os.zig+108-33
......@@ -300,6 +300,10 @@ pub const ReadError = error{
300300 /// This error occurs when no global event loop is configured,
301301 /// and reading from the file descriptor would block.
302302 WouldBlock,
303
304 /// WASI-only. This error occurs when the file descriptor does
305 /// not hold the required rights to read from it.
306 NotCapable,
303307} || UnexpectedError;
304308
305309/// Returns the number of bytes that were read, which can be less than
......@@ -335,6 +339,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
335339 wasi.ENOMEM => return error.SystemResources,
336340 wasi.ECONNRESET => return error.ConnectionResetByPeer,
337341 wasi.ETIMEDOUT => return error.ConnectionTimedOut,
342 wasi.ENOTCAPABLE => return error.NotCapable,
338343 else => |err| return unexpectedErrno(err),
339344 }
340345 }
......@@ -402,6 +407,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
402407 wasi.EISDIR => return error.IsDir,
403408 wasi.ENOBUFS => return error.SystemResources,
404409 wasi.ENOMEM => return error.SystemResources,
410 wasi.ENOTCAPABLE => return error.NotCapable,
405411 else => |err| return unexpectedErrno(err),
406412 }
407413 }
......@@ -466,6 +472,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
466472 wasi.ENXIO => return error.Unseekable,
467473 wasi.ESPIPE => return error.Unseekable,
468474 wasi.EOVERFLOW => return error.Unseekable,
475 wasi.ENOTCAPABLE => return error.NotCapable,
469476 else => |err| return unexpectedErrno(err),
470477 }
471478 }
......@@ -502,6 +509,10 @@ pub const TruncateError = error{
502509 InputOutput,
503510 CannotTruncate,
504511 FileBusy,
512
513 /// WASI-only. This error occurs when the file descriptor does
514 /// not hold the required rights to call `ftruncate` on it.
515 NotCapable,
505516} || UnexpectedError;
506517
507518pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
......@@ -536,6 +547,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
536547 wasi.ETXTBSY => return error.FileBusy,
537548 wasi.EBADF => unreachable, // Handle not open for writing
538549 wasi.EINVAL => unreachable, // Handle not open for writing
550 wasi.ENOTCAPABLE => return error.NotCapable,
539551 else => |err| return unexpectedErrno(err),
540552 }
541553 }
......@@ -604,6 +616,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
604616 wasi.ENXIO => return error.Unseekable,
605617 wasi.ESPIPE => return error.Unseekable,
606618 wasi.EOVERFLOW => return error.Unseekable,
619 wasi.ENOTCAPABLE => return error.NotCapable,
607620 else => |err| return unexpectedErrno(err),
608621 }
609622 }
......@@ -649,6 +662,10 @@ pub const WriteError = error{
649662 /// This error occurs when no global event loop is configured,
650663 /// and reading from the file descriptor would block.
651664 WouldBlock,
665
666 /// WASI-only. This error occurs when the file descriptor does
667 /// not hold the required rights to write to it.
668 NotCapable,
652669} || UnexpectedError;
653670
654671/// Write to a file descriptor.
......@@ -697,6 +714,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
697714 wasi.ENOSPC => return error.NoSpaceLeft,
698715 wasi.EPERM => return error.AccessDenied,
699716 wasi.EPIPE => return error.BrokenPipe,
717 wasi.ENOTCAPABLE => return error.NotCapable,
700718 else => |err| return unexpectedErrno(err),
701719 }
702720 }
......@@ -774,6 +792,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
774792 wasi.ENOSPC => return error.NoSpaceLeft,
775793 wasi.EPERM => return error.AccessDenied,
776794 wasi.EPIPE => return error.BrokenPipe,
795 wasi.ENOTCAPABLE => return error.NotCapable,
777796 else => |err| return unexpectedErrno(err),
778797 }
779798 }
......@@ -856,6 +875,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
856875 wasi.ENXIO => return error.Unseekable,
857876 wasi.ESPIPE => return error.Unseekable,
858877 wasi.EOVERFLOW => return error.Unseekable,
878 wasi.ENOTCAPABLE => return error.NotCapable,
859879 else => |err| return unexpectedErrno(err),
860880 }
861881 }
......@@ -949,6 +969,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
949969 wasi.ENXIO => return error.Unseekable,
950970 wasi.ESPIPE => return error.Unseekable,
951971 wasi.EOVERFLOW => return error.Unseekable,
972 wasi.ENOTCAPABLE => return error.NotCapable,
952973 else => |err| return unexpectedErrno(err),
953974 }
954975 }
......@@ -1020,6 +1041,10 @@ pub const OpenError = error{
10201041
10211042 /// The underlying filesystem does not support file locks
10221043 FileLocksNotSupported,
1044
1045 /// WASI-only. This error occurs when the file descriptor does
1046 /// not hold the required rights to open a new resource relative to it.
1047 NotCapable,
10231048} || UnexpectedError;
10241049
10251050/// Open and possibly create a file. Keeps trying if it gets interrupted.
......@@ -1113,6 +1138,7 @@ pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, oflags: oflags_t, fdflags
11131138 wasi.EPERM => return error.AccessDenied,
11141139 wasi.EEXIST => return error.PathAlreadyExists,
11151140 wasi.EBUSY => return error.DeviceBusy,
1141 wasi.ENOTCAPABLE => return error.NotCapable,
11161142 else => |err| return unexpectedErrno(err),
11171143 }
11181144 }
......@@ -1563,13 +1589,19 @@ pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLin
15631589 }
15641590}
15651591
1592pub const SymlinkatError = error{
1593 /// WASI-only. This error occurs when the file descriptor does
1594 /// not hold the required rights to create a new symbolic link relative to it.
1595 NotCapable,
1596} || SymlinkError;
1597
15661598/// Similar to `symlink`, however, creates a symbolic link named `sym_link_path` which contains the string
15671599/// `target_path` **relative** to `newdirfd` directory handle.
15681600/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
15691601/// one; the latter case is known as a dangling link.
15701602/// If `sym_link_path` exists, it will not be overwritten.
15711603/// See also `symlinkatWasi`, `symlinkatZ` and `symlinkatW`.
1572pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void {
1604pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkatError!void {
15731605 if (builtin.os.tag == .wasi) {
15741606 return symlinkatWasi(target_path, newdirfd, sym_link_path);
15751607 }
......@@ -1587,7 +1619,7 @@ pub const symlinkatC = @compileError("deprecated: renamed to symlinkatZ");
15871619
15881620/// WASI-only. The same as `symlinkat` but targeting WASI.
15891621/// See also `symlinkat`.
1590pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void {
1622pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkatError!void {
15911623 switch (wasi.path_symlink(target_path.ptr, target_path.len, newdirfd, sym_link_path.ptr, sym_link_path.len)) {
15921624 wasi.ESUCCESS => {},
15931625 wasi.EFAULT => unreachable,
......@@ -1604,19 +1636,20 @@ pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []c
16041636 wasi.ENOMEM => return error.SystemResources,
16051637 wasi.ENOSPC => return error.NoSpaceLeft,
16061638 wasi.EROFS => return error.ReadOnlyFileSystem,
1639 wasi.ENOTCAPABLE => return error.NotCapable,
16071640 else => |err| return unexpectedErrno(err),
16081641 }
16091642}
16101643
16111644/// Windows-only. The same as `symlinkat` except the paths are null-terminated, WTF-16 encoded.
16121645/// See also `symlinkat`.
1613pub fn symlinkatW(target_path: [*:0]const u16, newdirfd: fd_t, sym_link_path: [*:0]const u16) SymlinkError!void {
1646pub fn symlinkatW(target_path: [*:0]const u16, newdirfd: fd_t, sym_link_path: [*:0]const u16) SymlinkatError!void {
16141647 @compileError("TODO implement on Windows");
16151648}
16161649
16171650/// The same as `symlinkat` except the parameters are null-terminated pointers.
16181651/// See also `symlinkat`.
1619pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:0]const u8) SymLinkError!void {
1652pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:0]const u8) SymLinkatError!void {
16201653 if (builtin.os.tag == .windows) {
16211654 const target_path_w = try windows.cStrToPrefixedFileW(target_path);
16221655 const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
......@@ -1706,6 +1739,10 @@ pub fn unlinkZ(file_path: [*:0]const u8) UnlinkError!void {
17061739pub const UnlinkatError = UnlinkError || error{
17071740 /// When passing `AT_REMOVEDIR`, this error occurs when the named directory is not empty.
17081741 DirNotEmpty,
1742
1743 /// WASI-only. This error occurs when the file descriptor does
1744 /// not hold the required rights to unlink a resource by path relative to it.
1745 NotCapable,
17091746};
17101747
17111748/// Delete a file name and possibly the file it refers to, based on an open directory handle.
......@@ -1747,6 +1784,7 @@ pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatErro
17471784 wasi.ENOMEM => return error.SystemResources,
17481785 wasi.EROFS => return error.ReadOnlyFileSystem,
17491786 wasi.ENOTEMPTY => return error.DirNotEmpty,
1787 wasi.ENOTCAPABLE => return error.NotCapable,
17501788
17511789 wasi.EINVAL => unreachable, // invalid flags, or pathname has . as last component
17521790 wasi.EBADF => unreachable, // always a race condition
......@@ -1925,13 +1963,19 @@ pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!v
19251963 return windows.MoveFileExW(old_path, new_path, flags);
19261964}
19271965
1966pub const RenameatError = error{
1967 /// WASI-only. This error occurs when the file descriptor does
1968 /// not hold the required rights to rename a resource by path relative to it.
1969 NotCapable,
1970} || RenameError;
1971
19281972/// Change the name or location of a file based on an open directory handle.
19291973pub fn renameat(
19301974 old_dir_fd: fd_t,
19311975 old_path: []const u8,
19321976 new_dir_fd: fd_t,
19331977 new_path: []const u8,
1934) RenameError!void {
1978) RenameatError!void {
19351979 if (builtin.os.tag == .windows) {
19361980 const old_path_w = try windows.sliceToPrefixedFileW(old_path);
19371981 const new_path_w = try windows.sliceToPrefixedFileW(new_path);
......@@ -1947,7 +1991,7 @@ pub fn renameat(
19471991
19481992/// WASI-only. Same as `renameat` expect targeting WASI.
19491993/// See also `renameat`.
1950pub fn renameatWasi(old_dir_fd: fd_t, old_path: []const u8, new_dir_fd: fd_t, new_path: []const u8) RenameError!void {
1994pub fn renameatWasi(old_dir_fd: fd_t, old_path: []const u8, new_dir_fd: fd_t, new_path: []const u8) RenameatError!void {
19511995 switch (wasi.path_rename(old_dir_fd, old_path.ptr, old_path.len, new_dir_fd, new_path.ptr, new_path.len)) {
19521996 wasi.ESUCCESS => return,
19531997 wasi.EACCES => return error.AccessDenied,
......@@ -1968,6 +2012,7 @@ pub fn renameatWasi(old_dir_fd: fd_t, old_path: []const u8, new_dir_fd: fd_t, ne
19682012 wasi.ENOTEMPTY => return error.PathAlreadyExists,
19692013 wasi.EROFS => return error.ReadOnlyFileSystem,
19702014 wasi.EXDEV => return error.RenameAcrossMountPoints,
2015 wasi.ENOTCAPABLE => return error.NotCapable,
19712016 else => |err| return unexpectedErrno(err),
19722017 }
19732018}
......@@ -1978,7 +2023,7 @@ pub fn renameatZ(
19782023 old_path: [*:0]const u8,
19792024 new_dir_fd: fd_t,
19802025 new_path: [*:0]const u8,
1981) RenameError!void {
2026) RenameatError!void {
19822027 if (builtin.os.tag == .windows) {
19832028 const old_path_w = try windows.cStrToPrefixedFileW(old_path);
19842029 const new_path_w = try windows.cStrToPrefixedFileW(new_path);
......@@ -2017,7 +2062,7 @@ pub fn renameatW(
20172062 new_dir_fd: fd_t,
20182063 new_path_w: []const u16,
20192064 ReplaceIfExists: windows.BOOLEAN,
2020) RenameError!void {
2065) RenameatError!void {
20212066 const src_fd = windows.OpenFile(old_path_w, .{
20222067 .dir = old_dir_fd,
20232068 .access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE | windows.DELETE,
......@@ -2066,24 +2111,13 @@ pub fn renameatW(
20662111 }
20672112}
20682113
2069pub const MakeDirError = error{
2070 AccessDenied,
2071 DiskQuota,
2072 PathAlreadyExists,
2073 SymLinkLoop,
2074 LinkQuotaExceeded,
2075 NameTooLong,
2076 FileNotFound,
2077 SystemResources,
2078 NoSpaceLeft,
2079 NotDir,
2080 ReadOnlyFileSystem,
2081 InvalidUtf8,
2082 BadPathName,
2083 NoDevice,
2084} || UnexpectedError;
2114pub const MakeDirAtError = error{
2115 /// WASI-only. This error occurs when the file descriptor does
2116 /// not hold the required rights to create a new directory relative to it.
2117 NotCapable,
2118} || MakeDirError;
20852119
2086pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {
2120pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirAtError!void {
20872121 if (builtin.os.tag == .windows) {
20882122 const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path);
20892123 return mkdiratW(dir_fd, sub_dir_path_w.span().ptr, mode);
......@@ -2097,7 +2131,7 @@ pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!v
20972131
20982132pub const mkdiratC = @compileError("deprecated: renamed to mkdiratZ");
20992133
2100pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void {
2134pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirAtError!void {
21012135 switch (wasi.path_create_directory(dir_fd, sub_dir_path.ptr, sub_dir_path.len)) {
21022136 wasi.ESUCCESS => return,
21032137 wasi.EACCES => return error.AccessDenied,
......@@ -2114,11 +2148,12 @@ pub fn mkdiratWasi(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirErr
21142148 wasi.ENOSPC => return error.NoSpaceLeft,
21152149 wasi.ENOTDIR => return error.NotDir,
21162150 wasi.EROFS => return error.ReadOnlyFileSystem,
2151 wasi.ENOTCAPABLE => return error.NotCapable,
21172152 else => |err| return unexpectedErrno(err),
21182153 }
21192154}
21202155
2121pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
2156pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirAtError!void {
21222157 if (builtin.os.tag == .windows) {
21232158 const sub_dir_path_w = try windows.cStrToPrefixedFileW(sub_dir_path);
21242159 return mkdiratW(dir_fd, sub_dir_path_w.span().ptr, mode);
......@@ -2143,11 +2178,28 @@ pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirErr
21432178 }
21442179}
21452180
2146pub fn mkdiratW(dir_fd: fd_t, sub_path_w: [*:0]const u16, mode: u32) MakeDirError!void {
2181pub fn mkdiratW(dir_fd: fd_t, sub_path_w: [*:0]const u16, mode: u32) MakeDirAtError!void {
21472182 const sub_dir_handle = try windows.CreateDirectoryW(dir_fd, sub_path_w, null);
21482183 windows.CloseHandle(sub_dir_handle);
21492184}
21502185
2186pub const MakeDirError = error{
2187 AccessDenied,
2188 DiskQuota,
2189 PathAlreadyExists,
2190 SymLinkLoop,
2191 LinkQuotaExceeded,
2192 NameTooLong,
2193 FileNotFound,
2194 SystemResources,
2195 NoSpaceLeft,
2196 NotDir,
2197 ReadOnlyFileSystem,
2198 InvalidUtf8,
2199 BadPathName,
2200 NoDevice,
2201} || UnexpectedError;
2202
21512203/// Create a directory.
21522204/// `mode` is ignored on Windows.
21532205pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
......@@ -2364,10 +2416,16 @@ pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8
23642416 }
23652417}
23662418
2419pub const ReadLinkAtError = error{
2420 /// WASI-only. This error occurs when the file descriptor does
2421 /// not hold the required rights to read value of a symbolic link relative to it.
2422 NotCapable,
2423} || ReadLinkError;
2424
23672425/// Similar to `readlink` except reads value of a symbolink link **relative** to `dirfd` directory handle.
23682426/// The return value is a slice of `out_buffer` from index 0.
23692427/// See also `readlinkatWasi`, `realinkatZ` and `realinkatW`.
2370pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
2428pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkAtError![]u8 {
23712429 if (builtin.os.tag == .wasi) {
23722430 return readlinkatWasi(dirfd, file_path, out_buffer);
23732431 }
......@@ -2383,7 +2441,7 @@ pub const readlinkatC = @compileError("deprecated: renamed to readlinkatZ");
23832441
23842442/// WASI-only. Same as `readlinkat` but targets WASI.
23852443/// See also `readlinkat`.
2386pub fn readlinkatWasi(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
2444pub fn readlinkatWasi(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkAtError![]u8 {
23872445 var bufused: usize = undefined;
23882446 switch (wasi.path_readlink(dirfd, file_path.ptr, file_path.len, out_buffer.ptr, out_buffer.len, &bufused)) {
23892447 wasi.ESUCCESS => return out_buffer[0..bufused],
......@@ -2396,19 +2454,20 @@ pub fn readlinkatWasi(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) Read
23962454 wasi.ENOENT => return error.FileNotFound,
23972455 wasi.ENOMEM => return error.SystemResources,
23982456 wasi.ENOTDIR => return error.NotDir,
2457 wasi.ENOTCAPABLE => return error.NotCapable,
23992458 else => |err| return unexpectedErrno(err),
24002459 }
24012460}
24022461
24032462/// Windows-only. Same as `readlinkat` except `file_path` is null-terminated, WTF16 encoded.
24042463/// See also `readlinkat`.
2405pub fn readlinkatW(dirfd: fd_t, file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 {
2464pub fn readlinkatW(dirfd: fd_t, file_path: [*:0]const u16, out_buffer: []u8) ReadLinkAtError![]u8 {
24062465 @compileError("TODO implement on Windows");
24072466}
24082467
24092468/// Same as `readlinkat` except `file_path` is null-terminated.
24102469/// See also `readlinkat`.
2411pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
2470pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkAtError![]u8 {
24122471 if (builtin.os.tag == .windows) {
24132472 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
24142473 return readlinkatW(dirfd, file_path_w.span().ptr, out_buffer);
......@@ -3074,6 +3133,10 @@ pub fn waitpid(pid: i32, flags: u32) u32 {
30743133pub const FStatError = error{
30753134 SystemResources,
30763135 AccessDenied,
3136
3137 /// WASI-only. This error occurs when the file descriptor does
3138 /// not hold the required rights to get its filestat information.
3139 NotCapable,
30773140} || UnexpectedError;
30783141
30793142/// Return information about a file descriptor.
......@@ -3086,6 +3149,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
30863149 wasi.EBADF => unreachable, // Always a race condition.
30873150 wasi.ENOMEM => return error.SystemResources,
30883151 wasi.EACCES => return error.AccessDenied,
3152 wasi.ENOTCAPABLE => return error.NotCapable,
30893153 else => |err| return unexpectedErrno(err),
30903154 }
30913155 }
......@@ -3136,6 +3200,7 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S
31363200 wasi.ENAMETOOLONG => return error.NameTooLong,
31373201 wasi.ENOENT => return error.FileNotFound,
31383202 wasi.ENOTDIR => return error.FileNotFound,
3203 wasi.ENOTCAPABLE => return error.NotCapable,
31393204 else => |err| return unexpectedErrno(err),
31403205 }
31413206}
......@@ -3641,7 +3706,13 @@ pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void {
36413706 }
36423707}
36433708
3644pub const SeekError = error{Unseekable} || UnexpectedError;
3709pub const SeekError = error{
3710 Unseekable,
3711
3712 /// WASI-only. This error occurs when the file descriptor does
3713 /// not hold the required rights to seek on it.
3714 NotCapable,
3715} || UnexpectedError;
36453716
36463717/// Repositions read/write file offset relative to the beginning.
36473718pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
......@@ -3669,6 +3740,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
36693740 wasi.EOVERFLOW => return error.Unseekable,
36703741 wasi.ESPIPE => return error.Unseekable,
36713742 wasi.ENXIO => return error.Unseekable,
3743 wasi.ENOTCAPABLE => return error.NotCapable,
36723744 else => |err| return unexpectedErrno(err),
36733745 }
36743746 }
......@@ -3710,6 +3782,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
37103782 wasi.EOVERFLOW => return error.Unseekable,
37113783 wasi.ESPIPE => return error.Unseekable,
37123784 wasi.ENXIO => return error.Unseekable,
3785 wasi.ENOTCAPABLE => return error.NotCapable,
37133786 else => |err| return unexpectedErrno(err),
37143787 }
37153788 }
......@@ -3750,6 +3823,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
37503823 wasi.EOVERFLOW => return error.Unseekable,
37513824 wasi.ESPIPE => return error.Unseekable,
37523825 wasi.ENXIO => return error.Unseekable,
3826 wasi.ENOTCAPABLE => return error.NotCapable,
37533827 else => |err| return unexpectedErrno(err),
37543828 }
37553829 }
......@@ -3790,6 +3864,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
37903864 wasi.EOVERFLOW => return error.Unseekable,
37913865 wasi.ESPIPE => return error.Unseekable,
37923866 wasi.ENXIO => return error.Unseekable,
3867 wasi.ENOTCAPABLE => return error.NotCapable,
37933868 else => |err| return unexpectedErrno(err),
37943869 }
37953870 }