mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
51 lines
2.1 KiB
Zig
51 lines
2.1 KiB
Zig
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;
|
|
}
|
|
}
|