const std = @import("std"); const os = std.os; const math = std.math; const CopyFileError = error{SystemResources} || os.CopyFileRangeError || os.SendFileError; // Transfer all the data between two file descriptors in the most efficient way. // The copy starts at offset 0, the initial offsets are preserved. // No metadata is transferred over. pub fn copy(fd_in: os.fd_t, fd_out: os.fd_t) CopyFileError!void { if (comptime std.Target.current.isDarwin()) { const rc = os.system.fcopyfile(fd_in, fd_out, null, os.system.COPYFILE_DATA); switch (os.errno(rc)) { .SUCCESS => return, .INVAL => unreachable, .NOMEM => return error.SystemResources, // The source file is not a directory, symbolic link, or regular file. // Try with the fallback path before giving up. .OPNOTSUPP => {}, else => |err| return os.unexpectedErrno(err), } } if (comptime std.Target.current.os.tag == .linux) { // Try copy_file_range first as that works at the FS level and is the // most efficient method (if available). var offset: u64 = 0; cfr_loop: while (true) { // The kernel checks the u64 value `offset+count` for overflow, use // a 32 bit value so that the syscall won't return EINVAL except for // impossibly large files (> 2^64-1 - 2^32-1). const amt = try os.copy_file_range(fd_in, offset, fd_out, offset, math.maxInt(u32), 0); // Terminate when no data was copied if (amt == 0) break :cfr_loop; offset += amt; } return; } // Sendfile is a zero-copy mechanism iff the OS supports it, otherwise the // fallback code will copy the contents chunk by chunk. const empty_iovec = [0]os.iovec_const{}; var offset: u64 = 0; sendfile_loop: while (true) { const amt = try os.sendfile(fd_out, fd_in, offset, 0, &empty_iovec, &empty_iovec, 0); // Terminate when no data was copied if (amt == 0) break :sendfile_loop; offset += amt; } }