authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-19 12:55:00-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:11-08:00
log405db921dc0a053d7bebca6195c5a0031a5b187b
tree1988327af5b062c5988291c0d9667fab36f5c9d0
parent1381f9f612a5e03895615ade253411d86bce31a4

std: fix compilation targeting WASI


5 files changed, 81 insertions(+), 33 deletions(-)

lib/std/Io/File.zig+1-1
......@@ -429,7 +429,7 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum(
429429 executable_file = 0o777,
430430 _,
431431
432 pub const has_executable_bit = true;
432 pub const has_executable_bit = native_os != .wasi;
433433
434434 pub fn toMode(self: @This()) std.posix.mode_t {
435435 return @intFromEnum(self);
lib/std/Io/Threaded.zig+72-27
......@@ -947,6 +947,16 @@ const have_fchmodat2 = native_os == .linux and
947947const have_fchmodat_flags = native_os != .linux or
948948 (!builtin.abi.isAndroid() and std.c.versionCheck(.{ .major = 2, .minor = 32, .patch = 0 }));
949949
950const have_fchown = switch (native_os) {
951 .wasi, .windows => false,
952 else => true,
953};
954
955const have_fchmod = switch (native_os) {
956 .wasi, .windows => false,
957 else => true,
958};
959
950960const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat;
951961const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat;
952962const fstatat_sym = if (posix.lfs64_abi) posix.system.fstatat64 else posix.system.fstatat;
......@@ -1480,6 +1490,7 @@ fn futexWaitUncancelable(userdata: ?*anyopaque, ptr: *const u32, expected: u32)
14801490}
14811491
14821492fn futexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void {
1493 if (builtin.single_threaded) unreachable; // Nothing to wake up.
14831494 const t: *Threaded = @ptrCast(@alignCast(userdata));
14841495 _ = t;
14851496 switch (native_os) {
......@@ -4190,7 +4201,6 @@ fn dirDeleteFileWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.
41904201 .NOTDIR => return error.NotDir,
41914202 .NOMEM => return error.SystemResources,
41924203 .ROFS => return error.ReadOnlyFileSystem,
4193 .NOTEMPTY => return error.DirNotEmpty,
41944204 .NOTCAPABLE => return error.AccessDenied,
41954205 .ILSEQ => return error.BadPathName,
41964206 .INVAL => |err| return errnoBug(err), // invalid flags, or pathname has . as last component
......@@ -4464,7 +4474,6 @@ fn dirDeleteDirWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.D
44644474 .BUSY => return error.FileBusy,
44654475 .FAULT => |err| return errnoBug(err),
44664476 .IO => return error.FileSystem,
4467 .ISDIR => return error.IsDir,
44684477 .LOOP => return error.SymLinkLoop,
44694478 .NAMETOOLONG => return error.NameTooLong,
44704479 .NOENT => return error.FileNotFound,
......@@ -4877,14 +4886,14 @@ fn dirSymLinkWindows(
48774886 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
48784887 const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2;
48794888 @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
4880 _ = w.DeviceIoControl(symlink_handle, w.FSCTL.SET_REPARSE_POINT, .{ .in = buffer[0..buf_len] }) catch |err| switch (err) {
4881 error.PipeClosing => unreachable,
4882 error.PipeAlreadyConnected => unreachable,
4883 error.PipeAlreadyListening => unreachable,
4884 error.Pending => unreachable,
4885 error.UnrecognizedVolume => unreachable,
4886 else => |e| return e,
4887 };
4889 const rc = w.DeviceIoControl(symlink_handle, w.FSCTL.SET_REPARSE_POINT, .{ .in = buffer[0..buf_len] });
4890 switch (rc) {
4891 .SUCCESS => {},
4892 .PRIVILEGE_NOT_HELD => return error.PermissionDenied,
4893 .ACCESS_DENIED => return error.AccessDenied,
4894 .INVALID_DEVICE_REQUEST => return error.FileSystem,
4895 else => return windows.unexpectedStatus(rc),
4896 }
48884897}
48894898
48904899fn dirSymLinkWasi(
......@@ -4894,7 +4903,7 @@ fn dirSymLinkWasi(
48944903 sym_link_path: []const u8,
48954904 flags: Dir.SymLinkFlags,
48964905) Dir.SymLinkError!void {
4897 if (builtin.link_libc) return dirSymLinkPosix(dir, target_path, sym_link_path, flags);
4906 if (builtin.link_libc) return dirSymLinkPosix(userdata, dir, target_path, sym_link_path, flags);
48984907
48994908 const t: *Threaded = @ptrCast(@alignCast(userdata));
49004909 const current_thread = Thread.getCurrent(t);
......@@ -5021,7 +5030,7 @@ fn dirReadLinkWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer
50215030 switch (std.os.wasi.path_readlink(dir.handle, sub_path.ptr, sub_path.len, buffer.ptr, buffer.len, &n)) {
50225031 .SUCCESS => {
50235032 current_thread.endSyscall();
5024 return buffer[0..n];
5033 return n;
50255034 },
50265035 .CANCELED => return current_thread.endSyscallCanceled(),
50275036 .INTR => {
......@@ -5104,6 +5113,7 @@ fn dirSetPermissionsWindows(userdata: ?*anyopaque, dir: Dir, permissions: Dir.Pe
51045113}
51055114
51065115fn dirSetPermissionsPosix(userdata: ?*anyopaque, dir: Dir, permissions: Dir.Permissions) Dir.SetPermissionsError!void {
5116 if (@sizeOf(Dir.Permissions) == 0) return;
51075117 const t: *Threaded = @ptrCast(@alignCast(userdata));
51085118 const current_thread = Thread.getCurrent(t);
51095119 return setPermissionsPosix(current_thread, dir.handle, permissions.toMode());
......@@ -5116,7 +5126,7 @@ fn dirSetFilePermissions(
51165126 permissions: Dir.Permissions,
51175127 options: Dir.SetFilePermissionsOptions,
51185128) Dir.SetFilePermissionsError!void {
5119 if (!Dir.Permissions.has_executable_bit) return error.Unexpected;
5129 if (@sizeOf(Dir.Permissions) == 0) return;
51205130 if (is_windows) @panic("TODO");
51215131 const t: *Threaded = @ptrCast(@alignCast(userdata));
51225132 const current_thread = Thread.getCurrent(t);
......@@ -5250,14 +5260,16 @@ fn dirSetOwnerUnsupported(userdata: ?*anyopaque, dir: Dir, owner: ?File.Uid, gro
52505260}
52515261
52525262fn dirSetOwnerPosix(userdata: ?*anyopaque, dir: Dir, owner: ?File.Uid, group: ?File.Gid) Dir.SetOwnerError!void {
5263 if (!have_fchown) return error.Unexpected; // Unsupported OS, don't call this function.
52535264 const t: *Threaded = @ptrCast(@alignCast(userdata));
52545265 const current_thread = Thread.getCurrent(t);
52555266 const uid = owner orelse ~@as(posix.uid_t, 0);
52565267 const gid = group orelse ~@as(posix.gid_t, 0);
5257 return setOwnerPosix(current_thread, dir.handle, uid, gid);
5268 return posixFchown(current_thread, dir.handle, uid, gid);
52585269}
52595270
5260fn setOwnerPosix(current_thread: *Thread, fd: posix.fd_t, uid: posix.uid_t, gid: posix.gid_t) File.SetOwnerError!void {
5271fn posixFchown(current_thread: *Thread, fd: posix.fd_t, uid: posix.uid_t, gid: posix.gid_t) File.SetOwnerError!void {
5272 comptime assert(have_fchown);
52615273 try current_thread.beginSyscall();
52625274 while (true) {
52635275 switch (posix.errno(posix.system.fchown(fd, uid, gid))) {
......@@ -5296,13 +5308,10 @@ fn dirSetFileOwner(
52965308 group: ?File.Gid,
52975309 options: Dir.SetFileOwnerOptions,
52985310) Dir.SetFileOwnerError!void {
5311 if (!have_fchown) return error.Unexpected; // Unsupported OS, don't call this function.
52995312 const t: *Threaded = @ptrCast(@alignCast(userdata));
53005313 const current_thread = Thread.getCurrent(t);
53015314
5302 if (is_windows) {
5303 @panic("TODO");
5304 }
5305
53065315 var path_buffer: [posix.PATH_MAX]u8 = undefined;
53075316 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
53085317
......@@ -5317,6 +5326,7 @@ fn dirSetFileOwner(
53175326
53185327const fileSync = switch (native_os) {
53195328 .windows => fileSyncWindows,
5329 .wasi => fileSyncWasi,
53205330 else => fileSyncPosix,
53215331};
53225332
......@@ -5366,6 +5376,34 @@ fn fileSyncPosix(userdata: ?*anyopaque, file: File) File.SyncError!void {
53665376 }
53675377}
53685378
5379fn fileSyncWasi(userdata: ?*anyopaque, file: File) File.SyncError!void {
5380 const t: *Threaded = @ptrCast(@alignCast(userdata));
5381 const current_thread = Thread.getCurrent(t);
5382 try current_thread.beginSyscall();
5383 while (true) {
5384 switch (std.os.wasi.fd_sync(file.handle)) {
5385 .SUCCESS => return current_thread.endSyscall(),
5386 .CANCELED => return current_thread.endSyscallCanceled(),
5387 .INTR => {
5388 try current_thread.checkCancel();
5389 continue;
5390 },
5391 else => |e| {
5392 current_thread.endSyscall();
5393 switch (e) {
5394 .BADF => |err| return errnoBug(err),
5395 .INVAL => |err| return errnoBug(err),
5396 .ROFS => |err| return errnoBug(err),
5397 .IO => return error.InputOutput,
5398 .NOSPC => return error.NoSpaceLeft,
5399 .DQUOT => return error.DiskQuota,
5400 else => |err| return posix.unexpectedErrno(err),
5401 }
5402 },
5403 }
5404 }
5405}
5406
53695407fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool {
53705408 const t: *Threaded = @ptrCast(@alignCast(userdata));
53715409 const current_thread = Thread.getCurrent(t);
......@@ -5659,18 +5697,16 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE
56595697}
56605698
56615699fn fileSetOwner(userdata: ?*anyopaque, file: File, owner: ?File.Uid, group: ?File.Gid) File.SetOwnerError!void {
5662 switch (native_os) {
5663 .windows, .wasi => return error.Unexpected,
5664 else => {},
5665 }
5700 if (!have_fchown) return error.Unexpected; // Unsupported OS, don't call this function.
56665701 const t: *Threaded = @ptrCast(@alignCast(userdata));
56675702 const current_thread = Thread.getCurrent(t);
56685703 const uid = owner orelse ~@as(posix.uid_t, 0);
56695704 const gid = group orelse ~@as(posix.gid_t, 0);
5670 return setOwnerPosix(current_thread, file.handle, uid, gid);
5705 return posixFchown(current_thread, file.handle, uid, gid);
56715706}
56725707
56735708fn fileSetPermissions(userdata: ?*anyopaque, file: File, permissions: File.Permissions) File.SetPermissionsError!void {
5709 if (@sizeOf(File.Permissions) == 0) return;
56745710 const t: *Threaded = @ptrCast(@alignCast(userdata));
56755711 const current_thread = Thread.getCurrent(t);
56765712 switch (native_os) {
......@@ -5704,6 +5740,7 @@ fn fileSetPermissions(userdata: ?*anyopaque, file: File, permissions: File.Permi
57045740}
57055741
57065742fn setPermissionsPosix(current_thread: *Thread, fd: posix.fd_t, mode: posix.mode_t) File.SetPermissionsError!void {
5743 comptime assert(have_fchmod);
57075744 try current_thread.beginSyscall();
57085745 while (true) {
57095746 switch (posix.errno(posix.system.fchmod(fd, mode))) {
......@@ -5987,6 +6024,7 @@ const windows_lock_range_off: windows.LARGE_INTEGER = 0;
59876024const windows_lock_range_len: windows.LARGE_INTEGER = 1;
59886025
59896026fn fileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!void {
6027 if (native_os == .wasi) return error.FileLocksUnsupported;
59906028 const t: *Threaded = @ptrCast(@alignCast(userdata));
59916029 const current_thread = Thread.getCurrent(t);
59926030
......@@ -6066,6 +6104,7 @@ fn fileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!v
60666104}
60676105
60686106fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!bool {
6107 if (native_os == .wasi) return error.FileLocksUnsupported;
60696108 const t: *Threaded = @ptrCast(@alignCast(userdata));
60706109 const current_thread = Thread.getCurrent(t);
60716110
......@@ -6150,6 +6189,7 @@ fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockErro
61506189}
61516190
61526191fn fileUnlock(userdata: ?*anyopaque, file: File) void {
6192 if (native_os == .wasi) return;
61536193 const t: *Threaded = @ptrCast(@alignCast(userdata));
61546194 _ = t;
61556195
......@@ -6186,6 +6226,7 @@ fn fileUnlock(userdata: ?*anyopaque, file: File) void {
61866226}
61876227
61886228fn fileDowngradeLock(userdata: ?*anyopaque, file: File) File.DowngradeLockError!void {
6229 if (native_os == .wasi) return;
61896230 const t: *Threaded = @ptrCast(@alignCast(userdata));
61906231 const current_thread = Thread.getCurrent(t);
61916232
......@@ -7072,7 +7113,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex
70727113 const end_index = std.unicode.wtf16LeToWtf8(out_buffer, wide_slice);
70737114 return end_index;
70747115 },
7075 else => @compileError("unsupported OS"),
7116 else => return error.OperationUnsupported,
70767117 }
70777118}
70787119
......@@ -10034,7 +10075,10 @@ fn netWriteUnavailable(
1003410075
1003510076/// This is either usize or u32. Since, either is fine, let's use the same
1003610077/// `addBuf` function for both writing to a file and sending network messages.
10037const iovlen_t = @FieldType(posix.msghdr_const, "iovlen");
10078const iovlen_t = switch (native_os) {
10079 .wasi => u32,
10080 else => @FieldType(posix.msghdr_const, "iovlen"),
10081};
1003810082
1003910083fn addBuf(v: []posix.iovec_const, i: *iovlen_t, bytes: []const u8) void {
1004010084 // OS checks ptr addr before length so zero length vectors must be omitted.
......@@ -10775,8 +10819,9 @@ fn statFromPosix(st: *const posix.Stat) File.Stat {
1077510819fn statFromWasi(st: *const std.os.wasi.filestat_t) File.Stat {
1077610820 return .{
1077710821 .inode = st.ino,
10822 .nlink = st.nlink,
1077810823 .size = @bitCast(st.size),
10779 .mode = 0,
10824 .permissions = .default_file,
1078010825 .kind = switch (st.filetype) {
1078110826 .BLOCK_DEVICE => .block_device,
1078210827 .CHARACTER_DEVICE => .character_device,
lib/std/Progress.zig+2-2
......@@ -498,8 +498,8 @@ pub fn start(io: Io, options: Options) Node {
498498 if (stderr.enableAnsiEscapeCodes(io)) |_| {
499499 global_progress.terminal_mode = .ansi_escape_codes;
500500 } else |_| if (is_windows) {
501 if (stderr.isTty(io)) {
502 global_progress.terminal_mode = TerminalMode{ .windows_api = .{
501 if (stderr.isTty(io)) |is_tty| {
502 if (is_tty) global_progress.terminal_mode = TerminalMode{ .windows_api = .{
503503 .code_page = windows.kernel32.GetConsoleOutputCP(),
504504 } };
505505 } else |err| switch (err) {
lib/std/c.zig+3-2
......@@ -148,9 +148,10 @@ pub const dev_t = switch (native_os) {
148148pub const mode_t = switch (native_os) {
149149 .linux => linux.mode_t,
150150 .emscripten => emscripten.mode_t,
151 .openbsd, .haiku, .netbsd, .illumos, .wasi, .windows => u32,
151 .openbsd, .haiku, .netbsd, .illumos, .windows => u32,
152152 // https://github.com/SerenityOS/serenity/blob/b98f537f117b341788023ab82e0c11ca9ae29a57/Kernel/API/POSIX/sys/types.h#L44
153153 .freebsd, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .dragonfly, .serenity => u16,
154 .wasi => if (builtin.link_libc) u32 else u0, // WASI libc emulates mode.
154155 else => u0,
155156};
156157
......@@ -10608,7 +10609,7 @@ pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_
1060810609pub extern "c" fn mremap(addr: ?*align(page_size) const anyopaque, old_len: usize, new_len: usize, flags: MREMAP, ...) *anyopaque;
1060910610pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;
1061010611pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8) c_int;
10611pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_int) c_int;
10612pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_uint) c_int;
1061210613pub extern "c" fn unlink(path: [*:0]const u8) c_int;
1061310614pub extern "c" fn unlinkat(dirfd: fd_t, path: [*:0]const u8, flags: c_uint) c_int;
1061410615pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
lib/std/process.zig+3-1
......@@ -2121,7 +2121,9 @@ pub fn fatal(comptime format: []const u8, format_arguments: anytype) noreturn {
21212121pub const ExecutablePathBaseError = error{
21222122 FileNotFound,
21232123 AccessDenied,
2124 NotSupported,
2124 /// The operating system does not support an executable learning its own
2125 /// path.
2126 OperationUnsupported,
21252127 NotDir,
21262128 SymLinkLoop,
21272129 InputOutput,