authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-05 17:41:27-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:07-08:00
log72b76077ab4e5042b13ea311063f2c7e867e00ba
treebda79bf0b7899c4ebdc514ff1c1a2cfd03f81563
parentba999d608c304c37667175b35e4a64f87d90351c

std: fix some surface level compilation errors

And boldly remove preadv, pwritev, readv, writev, pread, pwrite from std.posix.

8 files changed, 64 insertions(+), 407 deletions(-)

lib/std/Io.zig+3-3
...@@ -705,8 +705,8 @@ pub const VTable = struct {...@@ -705,8 +705,8 @@ pub const VTable = struct {
705 fileSetLength: *const fn (?*anyopaque, File, u64) File.SetLengthError!void,705 fileSetLength: *const fn (?*anyopaque, File, u64) File.SetLengthError!void,
706 fileSetOwner: *const fn (?*anyopaque, File, ?File.Uid, ?File.Gid) File.SetOwnerError!void,706 fileSetOwner: *const fn (?*anyopaque, File, ?File.Uid, ?File.Gid) File.SetOwnerError!void,
707 fileSetPermissions: *const fn (?*anyopaque, File, File.Permissions) File.SetPermissionsError!void,707 fileSetPermissions: *const fn (?*anyopaque, File, File.Permissions) File.SetPermissionsError!void,
708 fileSetTimestamps: *const fn (?*anyopaque, File, last_accessed: Timestamp, last_modified: Timestamp, File.SetTimestampsOptions) File.SetTimestampsError!void,708 fileSetTimestamps: *const fn (?*anyopaque, File, last_accessed: Timestamp, last_modified: Timestamp) File.SetTimestampsError!void,
709 fileSetTimestampsNow: *const fn (?*anyopaque, File, File.SetTimestampsOptions) File.SetTimestampsError!void,709 fileSetTimestampsNow: *const fn (?*anyopaque, File) File.SetTimestampsError!void,
710 fileLock: *const fn (?*anyopaque, File, File.Lock) File.LockError!void,710 fileLock: *const fn (?*anyopaque, File, File.Lock) File.LockError!void,
711 fileTryLock: *const fn (?*anyopaque, File, File.Lock) File.LockError!bool,711 fileTryLock: *const fn (?*anyopaque, File, File.Lock) File.LockError!bool,
712 fileUnlock: *const fn (?*anyopaque, File) void,712 fileUnlock: *const fn (?*anyopaque, File) void,
...@@ -726,7 +726,7 @@ pub const VTable = struct {...@@ -726,7 +726,7 @@ pub const VTable = struct {
726 /// Returns 0 on end of stream.726 /// Returns 0 on end of stream.
727 netRead: *const fn (?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize,727 netRead: *const fn (?*anyopaque, src: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize,
728 netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize,728 netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize,
729 netWriteFile: *const fn (?*anyopaque, net.Socket.Handle, header: []const u8, *Io.File.Reader, Io.Limit) net.Stream.WriteFileError!usize,729 netWriteFile: *const fn (?*anyopaque, net.Socket.Handle, header: []const u8, *Io.File.Reader, Io.Limit) net.Stream.Writer.WriteFileError!usize,
730 netClose: *const fn (?*anyopaque, handle: net.Socket.Handle) void,730 netClose: *const fn (?*anyopaque, handle: net.Socket.Handle) void,
731 netInterfaceNameResolve: *const fn (?*anyopaque, *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface,731 netInterfaceNameResolve: *const fn (?*anyopaque, *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface,
732 netInterfaceName: *const fn (?*anyopaque, net.Interface) net.Interface.NameError!net.Interface.Name,732 netInterfaceName: *const fn (?*anyopaque, net.Interface) net.Interface.NameError!net.Interface.Name,
lib/std/Io/File.zig+2-2
...@@ -274,7 +274,7 @@ pub fn sync(file: File, io: Io) SyncError!void {...@@ -274,7 +274,7 @@ pub fn sync(file: File, io: Io) SyncError!void {
274/// Test whether the file refers to a terminal.274/// Test whether the file refers to a terminal.
275///275///
276/// See also:276/// See also:
277/// * `getOrEnableAnsiEscapeSupport`277/// * `enableAnsiEscapeCodes`
278/// * `supportsAnsiEscapeCodes`.278/// * `supportsAnsiEscapeCodes`.
279pub fn isTty(file: File, io: Io) bool {279pub fn isTty(file: File, io: Io) bool {
280 return io.vtable.fileIsTty(io.userdata, file);280 return io.vtable.fileIsTty(io.userdata, file);
...@@ -282,7 +282,7 @@ pub fn isTty(file: File, io: Io) bool {...@@ -282,7 +282,7 @@ pub fn isTty(file: File, io: Io) bool {
282282
283pub const EnableAnsiEscapeCodesError = error{} || Io.Cancelable || Io.UnexpectedError;283pub const EnableAnsiEscapeCodesError = error{} || Io.Cancelable || Io.UnexpectedError;
284284
285pub fn enableAnsiEscapeCodes(file: File, io: Io) EnableAnsiEscapeCodesError {285pub fn enableAnsiEscapeCodes(file: File, io: Io) EnableAnsiEscapeCodesError!void {
286 return io.vtable.fileEnableAnsiEscapeCodes(io.userdata, file);286 return io.vtable.fileEnableAnsiEscapeCodes(io.userdata, file);
287}287}
288288
lib/std/Io/File/Writer.zig+24-1
...@@ -7,7 +7,7 @@ const assert = std.debug.assert;...@@ -7,7 +7,7 @@ const assert = std.debug.assert;
77
8io: Io,8io: Io,
9file: File,9file: File,
10err: ?File.WriteError = null,10err: ?Error = null,
11mode: Mode = .positional,11mode: Mode = .positional,
12/// Tracks the true seek position in the file. To obtain the logical12/// Tracks the true seek position in the file. To obtain the logical
13/// position, add the buffer size to this value.13/// position, add the buffer size to this value.
...@@ -18,6 +18,29 @@ interface: Io.Writer,...@@ -18,6 +18,29 @@ interface: Io.Writer,
1818
19pub const Mode = File.Reader.Mode;19pub const Mode = File.Reader.Mode;
2020
21pub const Error = error{
22 DiskQuota,
23 FileTooBig,
24 InputOutput,
25 NoSpaceLeft,
26 DeviceBusy,
27 InvalidArgument,
28 /// File descriptor does not hold the required rights to write to it.
29 AccessDenied,
30 PermissionDenied,
31 BrokenPipe,
32 SystemResources,
33 NotOpenForWriting,
34 /// The process cannot access the file because another process has locked
35 /// a portion of the file. Windows-only.
36 LockViolation,
37 /// Non-blocking has been enabled and this operation would block.
38 WouldBlock,
39 /// This error occurs when a device gets disconnected before or mid-flush
40 /// while it's being written to - errno(6): No such device or address.
41 NoDevice,
42} || Io.Cancelable || Io.UnexpectedError;
43
21pub const WriteFileError = error{44pub const WriteFileError = error{
22 /// `out_fd` is an unconnected socket, or out_fd closed its read end.45 /// `out_fd` is an unconnected socket, or out_fd closed its read end.
23 BrokenPipe,46 BrokenPipe,
lib/std/Io/Threaded.zig+16
...@@ -6581,6 +6581,22 @@ fn fileWriteFileStreaming(...@@ -6581,6 +6581,22 @@ fn fileWriteFileStreaming(
6581 return error.Unimplemented;6581 return error.Unimplemented;
6582}6582}
65836583
6584fn netWriteFile(
6585 userdata: ?*anyopaque,
6586 socket_handle: net.Socket.Handle,
6587 header: []const u8,
6588 file_reader: *Io.File.Reader,
6589 limit: Io.Limit,
6590) net.Stream.WriteFileError!usize {
6591 const t: *Threaded = @ptrCast(@alignCast(userdata));
6592 _ = t;
6593 _ = socket_handle;
6594 _ = header;
6595 _ = file_reader;
6596 _ = limit;
6597 return error.Unimplemented; // TODO
6598}
6599
6584fn fileWriteFilePositional(6600fn fileWriteFilePositional(
6585 userdata: ?*anyopaque,6601 userdata: ?*anyopaque,
6586 file: Io.File,6602 file: Io.File,
lib/std/Io/net.zig+14-1
...@@ -1256,6 +1256,7 @@ pub const Stream = struct {...@@ -1256,6 +1256,7 @@ pub const Stream = struct {
1256 interface: Io.Writer,1256 interface: Io.Writer,
1257 stream: Stream,1257 stream: Stream,
1258 err: ?Error = null,1258 err: ?Error = null,
1259 write_file_err: ?WriteFileError = null,
12591260
1260 pub const Error = error{1261 pub const Error = error{
1261 /// Another TCP Fast Open is already in progress.1262 /// Another TCP Fast Open is already in progress.
...@@ -1285,12 +1286,17 @@ pub const Stream = struct {...@@ -1285,12 +1286,17 @@ pub const Stream = struct {
1285 SocketNotBound,1286 SocketNotBound,
1286 } || Io.UnexpectedError || Io.Cancelable;1287 } || Io.UnexpectedError || Io.Cancelable;
12871288
1289 pub const WriteFileError = error{} || Io.Cancelable || Io.UnexpectedError;
1290
1288 pub fn init(stream: Stream, io: Io, buffer: []u8) Writer {1291 pub fn init(stream: Stream, io: Io, buffer: []u8) Writer {
1289 return .{1292 return .{
1290 .io = io,1293 .io = io,
1291 .stream = stream,1294 .stream = stream,
1292 .interface = .{1295 .interface = .{
1293 .vtable = &.{ .drain = drain },1296 .vtable = &.{
1297 .drain = drain,
1298 .sendFile = sendFile,
1299 },
1294 .buffer = buffer,1300 .buffer = buffer,
1295 },1301 },
1296 };1302 };
...@@ -1307,6 +1313,13 @@ pub const Stream = struct {...@@ -1307,6 +1313,13 @@ pub const Stream = struct {
1307 };1313 };
1308 return io_w.consume(n);1314 return io_w.consume(n);
1309 }1315 }
1316
1317 fn sendFile(io_w: *Io.Writer, file_reader: *Io.File.Reader, limit: Io.Limit) Io.Writer.FileError!usize {
1318 _ = io_w;
1319 _ = file_reader;
1320 _ = limit;
1321 return error.Unimplemented; // TODO
1322 }
1310 };1323 };
13111324
1312 pub fn reader(stream: Stream, io: Io, buffer: []u8) Reader {1325 pub fn reader(stream: Stream, io: Io, buffer: []u8) Reader {
lib/std/Io/tty.zig+3-1
...@@ -50,7 +50,9 @@ pub const Config = union(enum) {...@@ -50,7 +50,9 @@ pub const Config = union(enum) {
5050
51 if (force_color == false) return .no_color;51 if (force_color == false) return .no_color;
5252
53 if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes;53 if (file.enableAnsiEscapeCodes()) |_| {
54 return .escape_codes;
55 } else |_| {}
5456
55 if (native_os == .windows and file.isTty()) {57 if (native_os == .windows and file.isTty()) {
56 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;58 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
lib/std/Progress.zig+2-2
...@@ -474,9 +474,9 @@ pub fn start(options: Options) Node {...@@ -474,9 +474,9 @@ pub fn start(options: Options) Node {
474 }474 }
475 const stderr: std.fs.File = .stderr();475 const stderr: std.fs.File = .stderr();
476 global_progress.terminal = stderr;476 global_progress.terminal = stderr;
477 if (stderr.getOrEnableAnsiEscapeSupport()) {477 if (stderr.enableAnsiEscapeCodes()) |_| {
478 global_progress.terminal_mode = .ansi_escape_codes;478 global_progress.terminal_mode = .ansi_escape_codes;
479 } else if (is_windows and stderr.isTty()) {479 } else |_| if (is_windows and stderr.isTty()) {
480 global_progress.terminal_mode = TerminalMode{ .windows_api = .{480 global_progress.terminal_mode = TerminalMode{ .windows_api = .{
481 .code_page = windows.kernel32.GetConsoleOutputCP(),481 .code_page = windows.kernel32.GetConsoleOutputCP(),
482 } };482 } };
lib/std/posix.zig-397
...@@ -813,226 +813,6 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -813,226 +813,6 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
813 }813 }
814}814}
815815
816/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
817///
818/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
819/// return error.WouldBlock when EAGAIN is received.
820/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
821/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
822///
823/// This operation is non-atomic on the following systems:
824/// * Windows
825/// On these systems, the read races with concurrent writes to the same file descriptor.
826///
827/// This function assumes that all vectors, including zero-length vectors, have
828/// a pointer within the address space of the application.
829pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
830 if (native_os == .windows) {
831 if (iov.len == 0) return 0;
832 const first = iov[0];
833 return read(fd, first.base[0..first.len]);
834 }
835 if (native_os == .wasi and !builtin.link_libc) {
836 var nread: usize = undefined;
837 switch (wasi.fd_read(fd, iov.ptr, iov.len, &nread)) {
838 .SUCCESS => return nread,
839 .INTR => unreachable,
840 .INVAL => unreachable,
841 .FAULT => unreachable,
842 .AGAIN => unreachable, // currently not support in WASI
843 .BADF => return error.NotOpenForReading, // can be a race condition
844 .IO => return error.InputOutput,
845 .ISDIR => return error.IsDir,
846 .NOBUFS => return error.SystemResources,
847 .NOMEM => return error.SystemResources,
848 .NOTCONN => return error.SocketUnconnected,
849 .CONNRESET => return error.ConnectionResetByPeer,
850 .TIMEDOUT => return error.Timeout,
851 .NOTCAPABLE => return error.AccessDenied,
852 else => |err| return unexpectedErrno(err),
853 }
854 }
855
856 while (true) {
857 const rc = system.readv(fd, iov.ptr, @min(iov.len, IOV_MAX));
858 switch (errno(rc)) {
859 .SUCCESS => return @intCast(rc),
860 .INTR => continue,
861 .INVAL => unreachable,
862 .FAULT => unreachable,
863 .SRCH => return error.ProcessNotFound,
864 .AGAIN => return error.WouldBlock,
865 .BADF => return error.NotOpenForReading, // can be a race condition
866 .IO => return error.InputOutput,
867 .ISDIR => return error.IsDir,
868 .NOBUFS => return error.SystemResources,
869 .NOMEM => return error.SystemResources,
870 .NOTCONN => return error.SocketUnconnected,
871 .CONNRESET => return error.ConnectionResetByPeer,
872 .TIMEDOUT => return error.Timeout,
873 else => |err| return unexpectedErrno(err),
874 }
875 }
876}
877
878pub const PReadError = std.Io.File.ReadPositionalError;
879
880/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
881///
882/// Retries when interrupted by a signal.
883///
884/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
885/// return error.WouldBlock when EAGAIN is received.
886/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
887/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
888///
889/// Linux has a limit on how many bytes may be transferred in one `pread` call, which is `0x7ffff000`
890/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
891/// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page.
892/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
893/// The corresponding POSIX limit is `maxInt(isize)`.
894pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
895 if (buf.len == 0) return 0;
896 if (native_os == .windows) {
897 return windows.ReadFile(fd, buf, offset);
898 }
899 if (native_os == .wasi and !builtin.link_libc) {
900 const iovs = [1]iovec{iovec{
901 .base = buf.ptr,
902 .len = buf.len,
903 }};
904
905 var nread: usize = undefined;
906 switch (wasi.fd_pread(fd, &iovs, iovs.len, offset, &nread)) {
907 .SUCCESS => return nread,
908 .INTR => unreachable,
909 .INVAL => unreachable,
910 .FAULT => unreachable,
911 .AGAIN => unreachable,
912 .BADF => return error.NotOpenForReading, // Can be a race condition.
913 .IO => return error.InputOutput,
914 .ISDIR => return error.IsDir,
915 .NOBUFS => return error.SystemResources,
916 .NOMEM => return error.SystemResources,
917 .NOTCONN => return error.SocketUnconnected,
918 .CONNRESET => return error.ConnectionResetByPeer,
919 .TIMEDOUT => return error.Timeout,
920 .NXIO => return error.Unseekable,
921 .SPIPE => return error.Unseekable,
922 .OVERFLOW => return error.Unseekable,
923 .NOTCAPABLE => return error.AccessDenied,
924 else => |err| return unexpectedErrno(err),
925 }
926 }
927
928 // Prevent EINVAL.
929 const max_count = switch (native_os) {
930 .linux => 0x7ffff000,
931 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => maxInt(i32),
932 else => maxInt(isize),
933 };
934
935 const pread_sym = if (lfs64_abi) system.pread64 else system.pread;
936 while (true) {
937 const rc = pread_sym(fd, buf.ptr, @min(buf.len, max_count), @bitCast(offset));
938 switch (errno(rc)) {
939 .SUCCESS => return @intCast(rc),
940 .INTR => continue,
941 .INVAL => unreachable,
942 .FAULT => unreachable,
943 .SRCH => return error.ProcessNotFound,
944 .AGAIN => return error.WouldBlock,
945 .BADF => return error.NotOpenForReading, // Can be a race condition.
946 .IO => return error.InputOutput,
947 .ISDIR => return error.IsDir,
948 .NOBUFS => return error.SystemResources,
949 .NOMEM => return error.SystemResources,
950 .NOTCONN => return error.SocketUnconnected,
951 .CONNRESET => return error.ConnectionResetByPeer,
952 .TIMEDOUT => return error.Timeout,
953 .NXIO => return error.Unseekable,
954 .SPIPE => return error.Unseekable,
955 .OVERFLOW => return error.Unseekable,
956 else => |err| return unexpectedErrno(err),
957 }
958 }
959}
960
961/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
962///
963/// Retries when interrupted by a signal.
964///
965/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
966/// return error.WouldBlock when EAGAIN is received.
967/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
968/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
969///
970/// This operation is non-atomic on the following systems:
971/// * Darwin
972/// * Windows
973/// On these systems, the read races with concurrent writes to the same file descriptor.
974pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
975 const have_pread_but_not_preadv = switch (native_os) {
976 .windows, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .haiku => true,
977 else => false,
978 };
979 if (have_pread_but_not_preadv) {
980 // We could loop here; but proper usage of `preadv` must handle partial reads anyway.
981 // So we simply read into the first vector only.
982 if (iov.len == 0) return 0;
983 const first = iov[0];
984 return pread(fd, first.base[0..first.len], offset);
985 }
986 if (native_os == .wasi and !builtin.link_libc) {
987 var nread: usize = undefined;
988 switch (wasi.fd_pread(fd, iov.ptr, iov.len, offset, &nread)) {
989 .SUCCESS => return nread,
990 .INTR => unreachable,
991 .INVAL => unreachable,
992 .FAULT => unreachable,
993 .AGAIN => unreachable,
994 .BADF => return error.NotOpenForReading, // can be a race condition
995 .IO => return error.InputOutput,
996 .ISDIR => return error.IsDir,
997 .NOBUFS => return error.SystemResources,
998 .NOMEM => return error.SystemResources,
999 .NOTCONN => return error.SocketUnconnected,
1000 .CONNRESET => return error.ConnectionResetByPeer,
1001 .TIMEDOUT => return error.Timeout,
1002 .NXIO => return error.Unseekable,
1003 .SPIPE => return error.Unseekable,
1004 .OVERFLOW => return error.Unseekable,
1005 .NOTCAPABLE => return error.AccessDenied,
1006 else => |err| return unexpectedErrno(err),
1007 }
1008 }
1009
1010 const preadv_sym = if (lfs64_abi) system.preadv64 else system.preadv;
1011 while (true) {
1012 const rc = preadv_sym(fd, iov.ptr, @min(iov.len, IOV_MAX), @bitCast(offset));
1013 switch (errno(rc)) {
1014 .SUCCESS => return @bitCast(rc),
1015 .INTR => continue,
1016 .INVAL => unreachable,
1017 .FAULT => unreachable,
1018 .SRCH => return error.ProcessNotFound,
1019 .AGAIN => return error.WouldBlock,
1020 .BADF => return error.NotOpenForReading, // can be a race condition
1021 .IO => return error.InputOutput,
1022 .ISDIR => return error.IsDir,
1023 .NOBUFS => return error.SystemResources,
1024 .NOMEM => return error.SystemResources,
1025 .NOTCONN => return error.SocketUnconnected,
1026 .CONNRESET => return error.ConnectionResetByPeer,
1027 .TIMEDOUT => return error.Timeout,
1028 .NXIO => return error.Unseekable,
1029 .SPIPE => return error.Unseekable,
1030 .OVERFLOW => return error.Unseekable,
1031 else => |err| return unexpectedErrno(err),
1032 }
1033 }
1034}
1035
1036pub const WriteError = error{816pub const WriteError = error{
1037 DiskQuota,817 DiskQuota,
1038 FileTooBig,818 FileTooBig,
...@@ -1157,183 +937,6 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {...@@ -1157,183 +937,6 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
1157 }937 }
1158}938}
1159939
1160pub const PWriteError = WriteError || error{Unseekable};
1161
1162/// Write to a file descriptor, with a position offset.
1163/// Retries when interrupted by a signal.
1164/// Returns the number of bytes written. If nonzero bytes were supplied, this will be nonzero.
1165///
1166/// Note that a successful write() may transfer fewer bytes than supplied. Such partial writes can
1167/// occur for various reasons; for example, because there was insufficient space on the disk
1168/// device to write all of the requested bytes, or because a blocked write() to a socket, pipe, or
1169/// similar was interrupted by a signal handler after it had transferred some, but before it had
1170/// transferred all of the requested bytes. In the event of a partial write, the caller can make
1171/// another write() call to transfer the remaining bytes. The subsequent call will either
1172/// transfer further bytes or may result in an error (e.g., if the disk is now full).
1173///
1174/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
1175/// return error.WouldBlock when EAGAIN is received.
1176/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
1177/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
1178///
1179/// Linux has a limit on how many bytes may be transferred in one `pwrite` call, which is `0x7ffff000`
1180/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
1181/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.
1182/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.
1183/// The corresponding POSIX limit is `maxInt(isize)`.
1184pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
1185 if (bytes.len == 0) return 0;
1186 if (native_os == .windows) {
1187 return windows.WriteFile(fd, bytes, offset);
1188 }
1189 if (native_os == .wasi and !builtin.link_libc) {
1190 const ciovs = [1]iovec_const{iovec_const{
1191 .base = bytes.ptr,
1192 .len = bytes.len,
1193 }};
1194
1195 var nwritten: usize = undefined;
1196 switch (wasi.fd_pwrite(fd, &ciovs, ciovs.len, offset, &nwritten)) {
1197 .SUCCESS => return nwritten,
1198 .INTR => unreachable,
1199 .INVAL => unreachable,
1200 .FAULT => unreachable,
1201 .AGAIN => unreachable,
1202 .BADF => return error.NotOpenForWriting, // can be a race condition.
1203 .DESTADDRREQ => unreachable, // `connect` was never called.
1204 .DQUOT => return error.DiskQuota,
1205 .FBIG => return error.FileTooBig,
1206 .IO => return error.InputOutput,
1207 .NOSPC => return error.NoSpaceLeft,
1208 .PERM => return error.PermissionDenied,
1209 .PIPE => return error.BrokenPipe,
1210 .NXIO => return error.Unseekable,
1211 .SPIPE => return error.Unseekable,
1212 .OVERFLOW => return error.Unseekable,
1213 .NOTCAPABLE => return error.AccessDenied,
1214 else => |err| return unexpectedErrno(err),
1215 }
1216 }
1217
1218 // Prevent EINVAL.
1219 const max_count = switch (native_os) {
1220 .linux => 0x7ffff000,
1221 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => maxInt(i32),
1222 else => maxInt(isize),
1223 };
1224
1225 const pwrite_sym = if (lfs64_abi) system.pwrite64 else system.pwrite;
1226 while (true) {
1227 const rc = pwrite_sym(fd, bytes.ptr, @min(bytes.len, max_count), @bitCast(offset));
1228 switch (errno(rc)) {
1229 .SUCCESS => return @intCast(rc),
1230 .INTR => continue,
1231 .INVAL => return error.InvalidArgument,
1232 .FAULT => unreachable,
1233 .SRCH => return error.ProcessNotFound,
1234 .AGAIN => return error.WouldBlock,
1235 .BADF => return error.NotOpenForWriting, // Can be a race condition.
1236 .DESTADDRREQ => unreachable, // `connect` was never called.
1237 .DQUOT => return error.DiskQuota,
1238 .FBIG => return error.FileTooBig,
1239 .IO => return error.InputOutput,
1240 .NOSPC => return error.NoSpaceLeft,
1241 .PERM => return error.PermissionDenied,
1242 .PIPE => return error.BrokenPipe,
1243 .NXIO => return error.Unseekable,
1244 .SPIPE => return error.Unseekable,
1245 .OVERFLOW => return error.Unseekable,
1246 .BUSY => return error.DeviceBusy,
1247 else => |err| return unexpectedErrno(err),
1248 }
1249 }
1250}
1251
1252/// Write multiple buffers to a file descriptor, with a position offset.
1253/// Retries when interrupted by a signal.
1254/// Returns the number of bytes written. If nonzero bytes were supplied, this will be nonzero.
1255///
1256/// Note that a successful write() may transfer fewer than count bytes. Such partial writes can
1257/// occur for various reasons; for example, because there was insufficient space on the disk
1258/// device to write all of the requested bytes, or because a blocked write() to a socket, pipe, or
1259/// similar was interrupted by a signal handler after it had transferred some, but before it had
1260/// transferred all of the requested bytes. In the event of a partial write, the caller can make
1261/// another write() call to transfer the remaining bytes. The subsequent call will either
1262/// transfer further bytes or may result in an error (e.g., if the disk is now full).
1263///
1264/// If `fd` is opened in non blocking mode, the function will
1265/// return error.WouldBlock when EAGAIN is received.
1266///
1267/// The following systems do not have this syscall, and will return partial writes if more than one
1268/// vector is provided:
1269/// * Darwin
1270/// * Windows
1271///
1272/// If `iov.len` is larger than `IOV_MAX`, a partial write will occur.
1273pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usize {
1274 const have_pwrite_but_not_pwritev = switch (native_os) {
1275 .windows, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .haiku => true,
1276 else => false,
1277 };
1278
1279 if (have_pwrite_but_not_pwritev) {
1280 // We could loop here; but proper usage of `pwritev` must handle partial writes anyway.
1281 // So we simply write the first vector only.
1282 if (iov.len == 0) return 0;
1283 const first = iov[0];
1284 return pwrite(fd, first.base[0..first.len], offset);
1285 }
1286 if (native_os == .wasi and !builtin.link_libc) {
1287 var nwritten: usize = undefined;
1288 switch (wasi.fd_pwrite(fd, iov.ptr, iov.len, offset, &nwritten)) {
1289 .SUCCESS => return nwritten,
1290 .INTR => unreachable,
1291 .INVAL => unreachable,
1292 .FAULT => unreachable,
1293 .AGAIN => unreachable,
1294 .BADF => return error.NotOpenForWriting, // Can be a race condition.
1295 .DESTADDRREQ => unreachable, // `connect` was never called.
1296 .DQUOT => return error.DiskQuota,
1297 .FBIG => return error.FileTooBig,
1298 .IO => return error.InputOutput,
1299 .NOSPC => return error.NoSpaceLeft,
1300 .PERM => return error.PermissionDenied,
1301 .PIPE => return error.BrokenPipe,
1302 .NXIO => return error.Unseekable,
1303 .SPIPE => return error.Unseekable,
1304 .OVERFLOW => return error.Unseekable,
1305 .NOTCAPABLE => return error.AccessDenied,
1306 else => |err| return unexpectedErrno(err),
1307 }
1308 }
1309
1310 const pwritev_sym = if (lfs64_abi) system.pwritev64 else system.pwritev;
1311 while (true) {
1312 const rc = pwritev_sym(fd, iov.ptr, @min(iov.len, IOV_MAX), @bitCast(offset));
1313 switch (errno(rc)) {
1314 .SUCCESS => return @intCast(rc),
1315 .INTR => continue,
1316 .INVAL => return error.InvalidArgument,
1317 .FAULT => unreachable,
1318 .SRCH => return error.ProcessNotFound,
1319 .AGAIN => return error.WouldBlock,
1320 .BADF => return error.NotOpenForWriting, // Can be a race condition.
1321 .DESTADDRREQ => unreachable, // `connect` was never called.
1322 .DQUOT => return error.DiskQuota,
1323 .FBIG => return error.FileTooBig,
1324 .IO => return error.InputOutput,
1325 .NOSPC => return error.NoSpaceLeft,
1326 .PERM => return error.PermissionDenied,
1327 .PIPE => return error.BrokenPipe,
1328 .NXIO => return error.Unseekable,
1329 .SPIPE => return error.Unseekable,
1330 .OVERFLOW => return error.Unseekable,
1331 .BUSY => return error.DeviceBusy,
1332 else => |err| return unexpectedErrno(err),
1333 }
1334 }
1335}
1336
1337pub const OpenError = std.Io.File.OpenError || error{WouldBlock};940pub const OpenError = std.Io.File.OpenError || error{WouldBlock};
1338941
1339/// Open and possibly create a file. Keeps trying if it gets interrupted.942/// Open and possibly create a file. Keeps trying if it gets interrupted.