Skip to content

Commit aea617c

Browse files
alichraghiandrewrk
authored andcommitted
std.os: take advantage of the freebsd's copy_file_range
1 parent 28288dc commit aea617c

File tree

3 files changed

+47
-31
lines changed

3 files changed

+47
-31
lines changed

lib/std/c/freebsd.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,7 @@ pub const E = enum(u16) {
14401440
CAPMODE = 94, // Not permitted in capability mode
14411441
NOTRECOVERABLE = 95, // State not recoverable
14421442
OWNERDEAD = 96, // Previous owner died
1443+
INTEGRITY = 97, // Integrity check failed
14431444
_,
14441445
};
14451446

@@ -1875,3 +1876,4 @@ pub const MFD = struct {
18751876
};
18761877

18771878
pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
1879+
pub extern "c" fn copy_file_range(fd_in: fd_t, off_in: ?*off_t, fd_out: fd_t, off_out: ?*off_t, len: usize, flags: u32) usize;

lib/std/os.zig

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6314,6 +6314,7 @@ pub const CopyFileRangeError = error{
63146314
Unseekable,
63156315
PermissionDenied,
63166316
SwapFile,
6317+
CorruptedData,
63176318
} || PReadError || PWriteError || UnexpectedError;
63186319

63196320
var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true);
@@ -6339,44 +6340,56 @@ var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true);
63396340
///
63406341
/// These systems support in-kernel data copying:
63416342
/// * Linux 4.5 (cross-filesystem 5.3)
6343+
/// * FreeBSD 13.0
63426344
///
63436345
/// Other systems fall back to calling `pread` / `pwrite`.
63446346
///
6345-
/// Maximum offsets on Linux are `math.maxInt(i64)`.
6347+
/// Maximum offsets on Linux and FreeBSD are `math.maxInt(i64)`.
63466348
pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len: usize, flags: u32) CopyFileRangeError!usize {
6347-
const call_cfr = comptime if (builtin.os.tag == .wasi)
6348-
// WASI-libc doesn't have copy_file_range.
6349-
false
6350-
else if (builtin.link_libc)
6351-
std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok
6352-
else
6353-
builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true;
6354-
6355-
if (call_cfr and has_copy_file_range_syscall.load(.Monotonic)) {
6349+
if ((comptime builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0 }) orelse false) or
6350+
((comptime builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse false and
6351+
std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok) and
6352+
has_copy_file_range_syscall.load(.Monotonic)))
6353+
{
63566354
var off_in_copy = @bitCast(i64, off_in);
63576355
var off_out_copy = @bitCast(i64, off_out);
63586356

6359-
const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
6360-
switch (system.getErrno(rc)) {
6361-
.SUCCESS => return @intCast(usize, rc),
6362-
.BADF => return error.FilesOpenedWithWrongFlags,
6363-
.FBIG => return error.FileTooBig,
6364-
.IO => return error.InputOutput,
6365-
.ISDIR => return error.IsDir,
6366-
.NOMEM => return error.OutOfMemory,
6367-
.NOSPC => return error.NoSpaceLeft,
6368-
.OVERFLOW => return error.Unseekable,
6369-
.PERM => return error.PermissionDenied,
6370-
.TXTBSY => return error.SwapFile,
6371-
// these may not be regular files, try fallback
6372-
.INVAL => {},
6373-
// support for cross-filesystem copy added in Linux 5.3, use fallback
6374-
.XDEV => {},
6375-
// syscall added in Linux 4.5, use fallback
6376-
.NOSYS => {
6377-
has_copy_file_range_syscall.store(false, .Monotonic);
6378-
},
6379-
else => |err| return unexpectedErrno(err),
6357+
while (true) {
6358+
const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
6359+
if (builtin.os.tag == .freebsd) {
6360+
switch (system.getErrno(rc)) {
6361+
.SUCCESS => return @intCast(usize, rc),
6362+
.BADF => return error.FilesOpenedWithWrongFlags,
6363+
.FBIG => return error.FileTooBig,
6364+
.IO => return error.InputOutput,
6365+
.ISDIR => return error.IsDir,
6366+
.NOSPC => return error.NoSpaceLeft,
6367+
.INVAL => break, // these may not be regular files, try fallback
6368+
.INTEGRITY => return error.CorruptedData,
6369+
.INTR => continue,
6370+
else => |err| return unexpectedErrno(err),
6371+
}
6372+
} else { // assume linux
6373+
switch (system.getErrno(rc)) {
6374+
.SUCCESS => return @intCast(usize, rc),
6375+
.BADF => return error.FilesOpenedWithWrongFlags,
6376+
.FBIG => return error.FileTooBig,
6377+
.IO => return error.InputOutput,
6378+
.ISDIR => return error.IsDir,
6379+
.NOSPC => return error.NoSpaceLeft,
6380+
.INVAL => break, // these may not be regular files, try fallback
6381+
.NOMEM => return error.OutOfMemory,
6382+
.OVERFLOW => return error.Unseekable,
6383+
.PERM => return error.PermissionDenied,
6384+
.TXTBSY => return error.SwapFile,
6385+
.XDEV => break, // support for cross-filesystem copy added in Linux 5.3, use fallback
6386+
.NOSYS => { // syscall added in Linux 4.5, use fallback
6387+
has_copy_file_range_syscall.store(false, .Monotonic);
6388+
break;
6389+
},
6390+
else => |err| return unexpectedErrno(err),
6391+
}
6392+
}
63806393
}
63816394
}
63826395

src/link.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ pub const File = struct {
457457
Unseekable,
458458
PermissionDenied,
459459
SwapFile,
460+
CorruptedData,
460461
SystemResources,
461462
OperationAborted,
462463
BrokenPipe,

0 commit comments

Comments
 (0)