commit 2f372b3dc00c60a625e1cc3518fa1bda3429de59 (tree)
parent 520397b48fac7fd0c107257c57f2cca4f0a40a98
Author: Andrew Kelley <andrew@ziglang.org>
Date: Wed, 7 Jan 2026 13:54:02 -0800
goodbye posix.write
see #6600
Diffstat:
3 files changed, 10 insertions(+), 102 deletions(-)
diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig
@@ -175,7 +175,7 @@ pub const SetNameError = error{
Unsupported,
Unexpected,
InvalidWtf8,
-} || posix.PrctlError || posix.WriteError || Io.File.OpenError || std.fmt.BufPrintError;
+} || posix.PrctlError || Io.File.Writer.Error || Io.File.OpenError || std.fmt.BufPrintError;
pub fn setName(self: Thread, io: Io, name: []const u8) SetNameError!void {
if (name.len > max_name_len) return error.NameTooLong;
diff --git a/lib/std/posix.zig b/lib/std/posix.zig
@@ -446,103 +446,6 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
}
}
-pub const WriteError = error{
- DiskQuota,
- FileTooBig,
- InputOutput,
- NoSpaceLeft,
- DeviceBusy,
- InvalidArgument,
-
- /// File descriptor does not hold the required rights to write to it.
- AccessDenied,
- PermissionDenied,
- BrokenPipe,
- SystemResources,
- Canceled,
- NotOpenForWriting,
-
- /// The process cannot access the file because another process has locked
- /// a portion of the file. Windows-only.
- LockViolation,
-
- /// This error occurs when no global event loop is configured,
- /// and reading from the file descriptor would block.
- WouldBlock,
-
- /// Connection reset by peer.
- ConnectionResetByPeer,
-
- /// This error occurs in Linux if the process being written to
- /// no longer exists.
- ProcessNotFound,
- /// This error occurs when a device gets disconnected before or mid-flush
- /// while it's being written to - errno(6): No such device or address.
- NoDevice,
-
- /// The socket type requires that message be sent atomically, and the size of the message
- /// to be sent made this impossible. The message is not transmitted.
- MessageOversize,
-} || UnexpectedError;
-
-/// Write to a file descriptor.
-/// Retries when interrupted by a signal.
-/// Returns the number of bytes written. If nonzero bytes were supplied, this will be nonzero.
-///
-/// Note that a successful write() may transfer fewer than count bytes. Such partial writes can
-/// occur for various reasons; for example, because there was insufficient space on the disk
-/// device to write all of the requested bytes, or because a blocked write() to a socket, pipe, or
-/// similar was interrupted by a signal handler after it had transferred some, but before it had
-/// transferred all of the requested bytes. In the event of a partial write, the caller can make
-/// another write() call to transfer the remaining bytes. The subsequent call will either
-/// transfer further bytes or may result in an error (e.g., if the disk is now full).
-///
-/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
-/// return error.WouldBlock when EAGAIN is received.
-/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
-/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
-///
-/// Linux has a limit on how many bytes may be transferred in one `write` call, which is `0x7ffff000`
-/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
-/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.
-/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
-/// The corresponding POSIX limit is `maxInt(isize)`.
-pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
- if (bytes.len == 0) return 0;
- if (native_os == .windows) @compileError("unsupported OS");
- if (native_os == .wasi) @compileError("unsupported OS");
-
- const max_count = switch (native_os) {
- .linux => 0x7ffff000,
- .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => maxInt(i32),
- else => maxInt(isize),
- };
- while (true) {
- const rc = system.write(fd, bytes.ptr, @min(bytes.len, max_count));
- switch (errno(rc)) {
- .SUCCESS => return @intCast(rc),
- .INTR => continue,
- .INVAL => return error.InvalidArgument,
- .FAULT => unreachable,
- .AGAIN => return error.WouldBlock,
- .BADF => return error.NotOpenForWriting, // can be a race condition.
- .DESTADDRREQ => unreachable, // `connect` was never called.
- .DQUOT => return error.DiskQuota,
- .FBIG => return error.FileTooBig,
- .IO => return error.InputOutput,
- .NOSPC => return error.NoSpaceLeft,
- .ACCES => return error.AccessDenied,
- .PERM => return error.PermissionDenied,
- .PIPE => return error.BrokenPipe,
- .CONNRESET => return error.ConnectionResetByPeer,
- .BUSY => return error.DeviceBusy,
- .NXIO => return error.NoDevice,
- .MSGSIZE => return error.MessageOversize,
- else => |err| return unexpectedErrno(err),
- }
- }
-}
-
pub const OpenError = std.Io.File.OpenError || error{WouldBlock};
/// Open and possibly create a file. Keeps trying if it gets interrupted.
diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig
@@ -121,13 +121,18 @@ test "pipe" {
if (native_os == .windows or native_os == .wasi)
return error.SkipZigTest;
+ const io = testing.io;
+
const fds = try std.Io.Threaded.pipe2(.{});
- try expect((try posix.write(fds[1], "hello")) == 5);
+ const out: Io.File = .{ .handle = fds[0] };
+ const in: Io.File = .{ .handle = fds[1] };
+ try in.writeStreamingAll(io, "hello");
var buf: [16]u8 = undefined;
- try expect((try posix.read(fds[0], buf[0..])) == 5);
+ try expect((try out.readStreaming(io, &.{&buf})) == 5);
+
try expectEqualSlices(u8, buf[0..5], "hello");
- posix.close(fds[1]);
- posix.close(fds[0]);
+ out.close(io);
+ in.close(io);
}
test "memfd_create" {