| ... | ... | @@ -947,6 +947,16 @@ const have_fchmodat2 = native_os == .linux and |
| 947 | 947 | const have_fchmodat_flags = native_os != .linux or |
| 948 | 948 | (!builtin.abi.isAndroid() and std.c.versionCheck(.{ .major = 2, .minor = 32, .patch = 0 })); |
| 949 | 949 | |
| 950 | const have_fchown = switch (native_os) { |
| 951 | .wasi, .windows => false, |
| 952 | else => true, |
| 953 | }; |
| 954 | |
| 955 | const have_fchmod = switch (native_os) { |
| 956 | .wasi, .windows => false, |
| 957 | else => true, |
| 958 | }; |
| 959 | |
| 950 | 960 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; |
| 951 | 961 | const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat; |
| 952 | 962 | const 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) |
| 1480 | 1490 | } |
| 1481 | 1491 | |
| 1482 | 1492 | fn futexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void { |
| 1493 | if (builtin.single_threaded) unreachable; // Nothing to wake up. |
| 1483 | 1494 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1484 | 1495 | _ = t; |
| 1485 | 1496 | switch (native_os) { |
| ... | ... | @@ -4190,7 +4201,6 @@ fn dirDeleteFileWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir. |
| 4190 | 4201 | .NOTDIR => return error.NotDir, |
| 4191 | 4202 | .NOMEM => return error.SystemResources, |
| 4192 | 4203 | .ROFS => return error.ReadOnlyFileSystem, |
| 4193 | | .NOTEMPTY => return error.DirNotEmpty, |
| 4194 | 4204 | .NOTCAPABLE => return error.AccessDenied, |
| 4195 | 4205 | .ILSEQ => return error.BadPathName, |
| 4196 | 4206 | .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 |
| 4464 | 4474 | .BUSY => return error.FileBusy, |
| 4465 | 4475 | .FAULT => |err| return errnoBug(err), |
| 4466 | 4476 | .IO => return error.FileSystem, |
| 4467 | | .ISDIR => return error.IsDir, |
| 4468 | 4477 | .LOOP => return error.SymLinkLoop, |
| 4469 | 4478 | .NAMETOOLONG => return error.NameTooLong, |
| 4470 | 4479 | .NOENT => return error.FileNotFound, |
| ... | ... | @@ -4877,14 +4886,14 @@ fn dirSymLinkWindows( |
| 4877 | 4886 | @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path))); |
| 4878 | 4887 | const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2; |
| 4879 | 4888 | @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 | } |
| 4888 | 4897 | } |
| 4889 | 4898 | |
| 4890 | 4899 | fn dirSymLinkWasi( |
| ... | ... | @@ -4894,7 +4903,7 @@ fn dirSymLinkWasi( |
| 4894 | 4903 | sym_link_path: []const u8, |
| 4895 | 4904 | flags: Dir.SymLinkFlags, |
| 4896 | 4905 | ) 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); |
| 4898 | 4907 | |
| 4899 | 4908 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 4900 | 4909 | const current_thread = Thread.getCurrent(t); |
| ... | ... | @@ -5021,7 +5030,7 @@ fn dirReadLinkWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer |
| 5021 | 5030 | switch (std.os.wasi.path_readlink(dir.handle, sub_path.ptr, sub_path.len, buffer.ptr, buffer.len, &n)) { |
| 5022 | 5031 | .SUCCESS => { |
| 5023 | 5032 | current_thread.endSyscall(); |
| 5024 | | return buffer[0..n]; |
| 5033 | return n; |
| 5025 | 5034 | }, |
| 5026 | 5035 | .CANCELED => return current_thread.endSyscallCanceled(), |
| 5027 | 5036 | .INTR => { |
| ... | ... | @@ -5104,6 +5113,7 @@ fn dirSetPermissionsWindows(userdata: ?*anyopaque, dir: Dir, permissions: Dir.Pe |
| 5104 | 5113 | } |
| 5105 | 5114 | |
| 5106 | 5115 | fn dirSetPermissionsPosix(userdata: ?*anyopaque, dir: Dir, permissions: Dir.Permissions) Dir.SetPermissionsError!void { |
| 5116 | if (@sizeOf(Dir.Permissions) == 0) return; |
| 5107 | 5117 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 5108 | 5118 | const current_thread = Thread.getCurrent(t); |
| 5109 | 5119 | return setPermissionsPosix(current_thread, dir.handle, permissions.toMode()); |
| ... | ... | @@ -5116,7 +5126,7 @@ fn dirSetFilePermissions( |
| 5116 | 5126 | permissions: Dir.Permissions, |
| 5117 | 5127 | options: Dir.SetFilePermissionsOptions, |
| 5118 | 5128 | ) Dir.SetFilePermissionsError!void { |
| 5119 | | if (!Dir.Permissions.has_executable_bit) return error.Unexpected; |
| 5129 | if (@sizeOf(Dir.Permissions) == 0) return; |
| 5120 | 5130 | if (is_windows) @panic("TODO"); |
| 5121 | 5131 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 5122 | 5132 | const current_thread = Thread.getCurrent(t); |
| ... | ... | @@ -5250,14 +5260,16 @@ fn dirSetOwnerUnsupported(userdata: ?*anyopaque, dir: Dir, owner: ?File.Uid, gro |
| 5250 | 5260 | } |
| 5251 | 5261 | |
| 5252 | 5262 | fn 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. |
| 5253 | 5264 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 5254 | 5265 | const current_thread = Thread.getCurrent(t); |
| 5255 | 5266 | const uid = owner orelse ~@as(posix.uid_t, 0); |
| 5256 | 5267 | 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); |
| 5258 | 5269 | } |
| 5259 | 5270 | |
| 5260 | | fn setOwnerPosix(current_thread: *Thread, fd: posix.fd_t, uid: posix.uid_t, gid: posix.gid_t) File.SetOwnerError!void { |
| 5271 | fn posixFchown(current_thread: *Thread, fd: posix.fd_t, uid: posix.uid_t, gid: posix.gid_t) File.SetOwnerError!void { |
| 5272 | comptime assert(have_fchown); |
| 5261 | 5273 | try current_thread.beginSyscall(); |
| 5262 | 5274 | while (true) { |
| 5263 | 5275 | switch (posix.errno(posix.system.fchown(fd, uid, gid))) { |
| ... | ... | @@ -5296,13 +5308,10 @@ fn dirSetFileOwner( |
| 5296 | 5308 | group: ?File.Gid, |
| 5297 | 5309 | options: Dir.SetFileOwnerOptions, |
| 5298 | 5310 | ) Dir.SetFileOwnerError!void { |
| 5311 | if (!have_fchown) return error.Unexpected; // Unsupported OS, don't call this function. |
| 5299 | 5312 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 5300 | 5313 | const current_thread = Thread.getCurrent(t); |
| 5301 | 5314 | |
| 5302 | | if (is_windows) { |
| 5303 | | @panic("TODO"); |
| 5304 | | } |
| 5305 | | |
| 5306 | 5315 | var path_buffer: [posix.PATH_MAX]u8 = undefined; |
| 5307 | 5316 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); |
| 5308 | 5317 | |
| ... | ... | @@ -5317,6 +5326,7 @@ fn dirSetFileOwner( |
| 5317 | 5326 | |
| 5318 | 5327 | const fileSync = switch (native_os) { |
| 5319 | 5328 | .windows => fileSyncWindows, |
| 5329 | .wasi => fileSyncWasi, |
| 5320 | 5330 | else => fileSyncPosix, |
| 5321 | 5331 | }; |
| 5322 | 5332 | |
| ... | ... | @@ -5366,6 +5376,34 @@ fn fileSyncPosix(userdata: ?*anyopaque, file: File) File.SyncError!void { |
| 5366 | 5376 | } |
| 5367 | 5377 | } |
| 5368 | 5378 | |
| 5379 | fn 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 | |
| 5369 | 5407 | fn fileIsTty(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { |
| 5370 | 5408 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 5371 | 5409 | const current_thread = Thread.getCurrent(t); |
| ... | ... | @@ -5659,18 +5697,16 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE |
| 5659 | 5697 | } |
| 5660 | 5698 | |
| 5661 | 5699 | fn 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. |
| 5666 | 5701 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 5667 | 5702 | const current_thread = Thread.getCurrent(t); |
| 5668 | 5703 | const uid = owner orelse ~@as(posix.uid_t, 0); |
| 5669 | 5704 | 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); |
| 5671 | 5706 | } |
| 5672 | 5707 | |
| 5673 | 5708 | fn fileSetPermissions(userdata: ?*anyopaque, file: File, permissions: File.Permissions) File.SetPermissionsError!void { |
| 5709 | if (@sizeOf(File.Permissions) == 0) return; |
| 5674 | 5710 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 5675 | 5711 | const current_thread = Thread.getCurrent(t); |
| 5676 | 5712 | switch (native_os) { |
| ... | ... | @@ -5704,6 +5740,7 @@ fn fileSetPermissions(userdata: ?*anyopaque, file: File, permissions: File.Permi |
| 5704 | 5740 | } |
| 5705 | 5741 | |
| 5706 | 5742 | fn setPermissionsPosix(current_thread: *Thread, fd: posix.fd_t, mode: posix.mode_t) File.SetPermissionsError!void { |
| 5743 | comptime assert(have_fchmod); |
| 5707 | 5744 | try current_thread.beginSyscall(); |
| 5708 | 5745 | while (true) { |
| 5709 | 5746 | switch (posix.errno(posix.system.fchmod(fd, mode))) { |
| ... | ... | @@ -5987,6 +6024,7 @@ const windows_lock_range_off: windows.LARGE_INTEGER = 0; |
| 5987 | 6024 | const windows_lock_range_len: windows.LARGE_INTEGER = 1; |
| 5988 | 6025 | |
| 5989 | 6026 | fn fileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!void { |
| 6027 | if (native_os == .wasi) return error.FileLocksUnsupported; |
| 5990 | 6028 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 5991 | 6029 | const current_thread = Thread.getCurrent(t); |
| 5992 | 6030 | |
| ... | ... | @@ -6066,6 +6104,7 @@ fn fileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!v |
| 6066 | 6104 | } |
| 6067 | 6105 | |
| 6068 | 6106 | fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!bool { |
| 6107 | if (native_os == .wasi) return error.FileLocksUnsupported; |
| 6069 | 6108 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 6070 | 6109 | const current_thread = Thread.getCurrent(t); |
| 6071 | 6110 | |
| ... | ... | @@ -6150,6 +6189,7 @@ fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockErro |
| 6150 | 6189 | } |
| 6151 | 6190 | |
| 6152 | 6191 | fn fileUnlock(userdata: ?*anyopaque, file: File) void { |
| 6192 | if (native_os == .wasi) return; |
| 6153 | 6193 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 6154 | 6194 | _ = t; |
| 6155 | 6195 | |
| ... | ... | @@ -6186,6 +6226,7 @@ fn fileUnlock(userdata: ?*anyopaque, file: File) void { |
| 6186 | 6226 | } |
| 6187 | 6227 | |
| 6188 | 6228 | fn fileDowngradeLock(userdata: ?*anyopaque, file: File) File.DowngradeLockError!void { |
| 6229 | if (native_os == .wasi) return; |
| 6189 | 6230 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 6190 | 6231 | const current_thread = Thread.getCurrent(t); |
| 6191 | 6232 | |
| ... | ... | @@ -7072,7 +7113,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex |
| 7072 | 7113 | const end_index = std.unicode.wtf16LeToWtf8(out_buffer, wide_slice); |
| 7073 | 7114 | return end_index; |
| 7074 | 7115 | }, |
| 7075 | | else => @compileError("unsupported OS"), |
| 7116 | else => return error.OperationUnsupported, |
| 7076 | 7117 | } |
| 7077 | 7118 | } |
| 7078 | 7119 | |
| ... | ... | @@ -10034,7 +10075,10 @@ fn netWriteUnavailable( |
| 10034 | 10075 | |
| 10035 | 10076 | /// This is either usize or u32. Since, either is fine, let's use the same |
| 10036 | 10077 | /// `addBuf` function for both writing to a file and sending network messages. |
| 10037 | | const iovlen_t = @FieldType(posix.msghdr_const, "iovlen"); |
| 10078 | const iovlen_t = switch (native_os) { |
| 10079 | .wasi => u32, |
| 10080 | else => @FieldType(posix.msghdr_const, "iovlen"), |
| 10081 | }; |
| 10038 | 10082 | |
| 10039 | 10083 | fn addBuf(v: []posix.iovec_const, i: *iovlen_t, bytes: []const u8) void { |
| 10040 | 10084 | // 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 { |
| 10775 | 10819 | fn statFromWasi(st: *const std.os.wasi.filestat_t) File.Stat { |
| 10776 | 10820 | return .{ |
| 10777 | 10821 | .inode = st.ino, |
| 10822 | .nlink = st.nlink, |
| 10778 | 10823 | .size = @bitCast(st.size), |
| 10779 | | .mode = 0, |
| 10824 | .permissions = .default_file, |
| 10780 | 10825 | .kind = switch (st.filetype) { |
| 10781 | 10826 | .BLOCK_DEVICE => .block_device, |
| 10782 | 10827 | .CHARACTER_DEVICE => .character_device, |