| ... | ... | @@ -446,103 +446,6 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 446 | 446 | } |
| 447 | 447 | } |
| 448 | 448 | |
| 449 | | pub const WriteError = error{ |
| 450 | | DiskQuota, |
| 451 | | FileTooBig, |
| 452 | | InputOutput, |
| 453 | | NoSpaceLeft, |
| 454 | | DeviceBusy, |
| 455 | | InvalidArgument, |
| 456 | | |
| 457 | | /// File descriptor does not hold the required rights to write to it. |
| 458 | | AccessDenied, |
| 459 | | PermissionDenied, |
| 460 | | BrokenPipe, |
| 461 | | SystemResources, |
| 462 | | Canceled, |
| 463 | | NotOpenForWriting, |
| 464 | | |
| 465 | | /// The process cannot access the file because another process has locked |
| 466 | | /// a portion of the file. Windows-only. |
| 467 | | LockViolation, |
| 468 | | |
| 469 | | /// This error occurs when no global event loop is configured, |
| 470 | | /// and reading from the file descriptor would block. |
| 471 | | WouldBlock, |
| 472 | | |
| 473 | | /// Connection reset by peer. |
| 474 | | ConnectionResetByPeer, |
| 475 | | |
| 476 | | /// This error occurs in Linux if the process being written to |
| 477 | | /// no longer exists. |
| 478 | | ProcessNotFound, |
| 479 | | /// This error occurs when a device gets disconnected before or mid-flush |
| 480 | | /// while it's being written to - errno(6): No such device or address. |
| 481 | | NoDevice, |
| 482 | | |
| 483 | | /// The socket type requires that message be sent atomically, and the size of the message |
| 484 | | /// to be sent made this impossible. The message is not transmitted. |
| 485 | | MessageOversize, |
| 486 | | } || UnexpectedError; |
| 487 | | |
| 488 | | /// Write to a file descriptor. |
| 489 | | /// Retries when interrupted by a signal. |
| 490 | | /// Returns the number of bytes written. If nonzero bytes were supplied, this will be nonzero. |
| 491 | | /// |
| 492 | | /// Note that a successful write() may transfer fewer than count bytes. Such partial writes can |
| 493 | | /// occur for various reasons; for example, because there was insufficient space on the disk |
| 494 | | /// device to write all of the requested bytes, or because a blocked write() to a socket, pipe, or |
| 495 | | /// similar was interrupted by a signal handler after it had transferred some, but before it had |
| 496 | | /// transferred all of the requested bytes. In the event of a partial write, the caller can make |
| 497 | | /// another write() call to transfer the remaining bytes. The subsequent call will either |
| 498 | | /// transfer further bytes or may result in an error (e.g., if the disk is now full). |
| 499 | | /// |
| 500 | | /// For POSIX systems, if `fd` is opened in non blocking mode, the function will |
| 501 | | /// return error.WouldBlock when EAGAIN is received. |
| 502 | | /// On Windows, if the application has a global event loop enabled, I/O Completion Ports are |
| 503 | | /// used to perform the I/O. `error.WouldBlock` is not possible on Windows. |
| 504 | | /// |
| 505 | | /// Linux has a limit on how many bytes may be transferred in one `write` call, which is `0x7ffff000` |
| 506 | | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as |
| 507 | | /// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page. |
| 508 | | /// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. |
| 509 | | /// The corresponding POSIX limit is `maxInt(isize)`. |
| 510 | | pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { |
| 511 | | if (bytes.len == 0) return 0; |
| 512 | | if (native_os == .windows) @compileError("unsupported OS"); |
| 513 | | if (native_os == .wasi) @compileError("unsupported OS"); |
| 514 | | |
| 515 | | const max_count = switch (native_os) { |
| 516 | | .linux => 0x7ffff000, |
| 517 | | .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => maxInt(i32), |
| 518 | | else => maxInt(isize), |
| 519 | | }; |
| 520 | | while (true) { |
| 521 | | const rc = system.write(fd, bytes.ptr, @min(bytes.len, max_count)); |
| 522 | | switch (errno(rc)) { |
| 523 | | .SUCCESS => return @intCast(rc), |
| 524 | | .INTR => continue, |
| 525 | | .INVAL => return error.InvalidArgument, |
| 526 | | .FAULT => unreachable, |
| 527 | | .AGAIN => return error.WouldBlock, |
| 528 | | .BADF => return error.NotOpenForWriting, // can be a race condition. |
| 529 | | .DESTADDRREQ => unreachable, // `connect` was never called. |
| 530 | | .DQUOT => return error.DiskQuota, |
| 531 | | .FBIG => return error.FileTooBig, |
| 532 | | .IO => return error.InputOutput, |
| 533 | | .NOSPC => return error.NoSpaceLeft, |
| 534 | | .ACCES => return error.AccessDenied, |
| 535 | | .PERM => return error.PermissionDenied, |
| 536 | | .PIPE => return error.BrokenPipe, |
| 537 | | .CONNRESET => return error.ConnectionResetByPeer, |
| 538 | | .BUSY => return error.DeviceBusy, |
| 539 | | .NXIO => return error.NoDevice, |
| 540 | | .MSGSIZE => return error.MessageOversize, |
| 541 | | else => |err| return unexpectedErrno(err), |
| 542 | | } |
| 543 | | } |
| 544 | | } |
| 545 | | |
| 546 | 449 | pub const OpenError = std.Io.File.OpenError || error{WouldBlock}; |
| 547 | 450 | |
| 548 | 451 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |