| ... | ... | @@ -3498,6 +3498,121 @@ pub fn send( |
| 3498 | 3498 | return sendto(sockfd, buf, flags, null, 0); |
| 3499 | 3499 | } |
| 3500 | 3500 | |
| 3501 | pub const SendFileError = error{ |
| 3502 | /// There was an unspecified error while reading from infd. |
| 3503 | InputOutput, |
| 3504 | |
| 3505 | /// There was insufficient resources for processing. |
| 3506 | SystemResources, |
| 3507 | |
| 3508 | /// The value provided for count overflows the maximum size of either |
| 3509 | /// infd or outfd. |
| 3510 | Overflow, |
| 3511 | |
| 3512 | /// Offset was provided, but infd is not seekable. |
| 3513 | Unseekable, |
| 3514 | |
| 3515 | /// The outfd is marked nonblocking and the requested operation would block, and |
| 3516 | /// there is no global event loop configured. |
| 3517 | WouldBlock, |
| 3518 | } || WriteError || UnexpectedError; |
| 3519 | |
| 3520 | pub const sf_hdtr = struct { |
| 3521 | headers: []iovec_const, |
| 3522 | trailers: []iovec_const, |
| 3523 | }; |
| 3524 | |
| 3525 | /// Transfer data between file descriptors. |
| 3526 | /// |
| 3527 | /// The `sendfile` call copies `count` bytes from one file descriptor to another within the kernel. This can |
| 3528 | /// be more performant than transferring data from the kernel to user space and back, such as with |
| 3529 | /// `read` and `write` calls. |
| 3530 | /// |
| 3531 | /// The `infd` should be a file descriptor opened for reading, and `outfd` should be a file descriptor |
| 3532 | /// opened for writing. Copying will begin at `offset`, if not null, which will be updated to reflect |
| 3533 | /// the number of bytes read. If `offset` is null, the copying will begin at the current seek position, |
| 3534 | /// and the file position will be updated. |
| 3535 | pub fn sendfile(infd: fd_t, outfd: fd_t, offset: u64, count: usize, optional_hdtr: ?*const sf_hdtr, flags: u32) SendFileError!usize { |
| 3536 | // XXX: check if offset is > length of file, return 0 bytes written |
| 3537 | // XXX: document systems where headers are sent atomically. |
| 3538 | // XXX: compute new offset on EINTR/EAGAIN |
| 3539 | var rc: usize = undefined; |
| 3540 | var err: usize = undefined; |
| 3541 | if (builtin.os == .linux) { |
| 3542 | while (true) { |
| 3543 | try lseek_SET(infd, offset); |
| 3544 | |
| 3545 | if (optional_hdtr) |hdtr| { |
| 3546 | try writev(outfd, hdtr.headers); |
| 3547 | } |
| 3548 | |
| 3549 | rc = system.sendfile(outfd, infd, null, count); |
| 3550 | err = errno(rc); |
| 3551 | |
| 3552 | if (optional_hdtr) |hdtr| { |
| 3553 | try writev(outfd, hdtr.trailers); |
| 3554 | } |
| 3555 | |
| 3556 | switch (err) { |
| 3557 | 0 => return @intCast(usize, rc), |
| 3558 | else => return unexpectedErrno(err), |
| 3559 | |
| 3560 | EBADF => unreachable, |
| 3561 | EINVAL => unreachable, |
| 3562 | EFAULT => unreachable, |
| 3563 | EAGAIN => if (std.event.Loop.instance) |loop| { |
| 3564 | loop.waitUntilFdWritable(outfd); |
| 3565 | continue; |
| 3566 | } else { |
| 3567 | return error.WouldBlock; |
| 3568 | }, |
| 3569 | EIO => return error.InputOutput, |
| 3570 | ENOMEM => return error.SystemResources, |
| 3571 | EOVERFLOW => return error.Overflow, |
| 3572 | ESPIPE => return error.Unseekable, |
| 3573 | } |
| 3574 | } |
| 3575 | } else if (builtin.os == .freebsd) { |
| 3576 | while (true) { |
| 3577 | var rcount: u64 = 0; |
| 3578 | var hdtr: std.c.sf_hdtr = undefined; |
| 3579 | if (optional_hdtr) |h| { |
| 3580 | hdtr = std.c.sf_hdtr{ |
| 3581 | .headers = h.headers.ptr, |
| 3582 | .hdr_cnt = @intCast(c_int, h.headers.len), |
| 3583 | .trailers = h.trailers.ptr, |
| 3584 | .trl_cnt = @intCast(c_int, h.trailers.len), |
| 3585 | }; |
| 3586 | } |
| 3587 | err = errno(system.sendfile(infd, outfd, offset, count, &hdtr, &rcount, @intCast(c_int, flags))); |
| 3588 | switch (err) { |
| 3589 | 0 => return @intCast(usize, rcount), |
| 3590 | else => return unexpectedErrno(err), |
| 3591 | |
| 3592 | EBADF => unreachable, |
| 3593 | EFAULT => unreachable, |
| 3594 | EINVAL => unreachable, |
| 3595 | ENOTCAPABLE => unreachable, |
| 3596 | ENOTCONN => unreachable, |
| 3597 | ENOTSOCK => unreachable, |
| 3598 | EAGAIN => if (std.event.Loop.instance) |loop| { |
| 3599 | loop.waitUntilFdWritable(outfd); |
| 3600 | continue; |
| 3601 | } else { |
| 3602 | return error.WouldBlock; |
| 3603 | }, |
| 3604 | EBUSY => return error.DeviceBusy, |
| 3605 | EINTR => continue, |
| 3606 | EIO => return error.InputOutput, |
| 3607 | ENOBUFS => return error.SystemResources, |
| 3608 | EPIPE => return error.BrokenPipe, |
| 3609 | } |
| 3610 | } |
| 3611 | } else { |
| 3612 | @compileError("sendfile unimplemented for this target"); |
| 3613 | } |
| 3614 | } |
| 3615 | |
| 3501 | 3616 | pub const PollError = error{ |
| 3502 | 3617 | /// The kernel had no space to allocate file descriptor tables. |
| 3503 | 3618 | SystemResources, |