@@ -6256,6 +6256,8 @@ pub const CopyFileRangeError = error{
6256
6256
Unseekable ,
6257
6257
PermissionDenied ,
6258
6258
SwapFile ,
6259
+ CorruptedData ,
6260
+ RangeOverlap ,
6259
6261
} || PReadError || PWriteError || UnexpectedError ;
6260
6262
6261
6263
var has_copy_file_range_syscall = std .atomic .Atomic (bool ).init (true );
@@ -6281,44 +6283,68 @@ var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true);
6281
6283
///
6282
6284
/// These systems support in-kernel data copying:
6283
6285
/// * Linux 4.5 (cross-filesystem 5.3)
6286
+ /// * FreeBSD 13.0
6284
6287
///
6285
6288
/// Other systems fall back to calling `pread` / `pwrite`.
6286
6289
///
6287
- /// Maximum offsets on Linux are `math.maxInt(i64)`.
6290
+ /// Maximum offsets on Linux and FreeBSD are `math.maxInt(i64)`.
6288
6291
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 {
6289
- const call_cfr = comptime if (builtin .os .tag == .wasi )
6290
- // WASI-libc doesn't have copy_file_range.
6291
- false
6292
- else if (builtin .link_libc )
6293
- std .c .versionCheck (.{ .major = 2 , .minor = 27 , .patch = 0 }).ok
6294
- else
6295
- builtin .os .isAtLeast (.linux , .{ .major = 4 , .minor = 5 }) orelse true ;
6296
-
6297
- if (call_cfr and has_copy_file_range_syscall .load (.Monotonic )) {
6298
- var off_in_copy = @bitCast (i64 , off_in );
6299
- var off_out_copy = @bitCast (i64 , off_out );
6300
-
6301
- const rc = system .copy_file_range (fd_in , & off_in_copy , fd_out , & off_out_copy , len , flags );
6302
- switch (system .getErrno (rc )) {
6303
- .SUCCESS = > return @intCast (usize , rc ),
6304
- .BADF = > return error .FilesOpenedWithWrongFlags ,
6305
- .FBIG = > return error .FileTooBig ,
6306
- .IO = > return error .InputOutput ,
6307
- .ISDIR = > return error .IsDir ,
6308
- .NOMEM = > return error .OutOfMemory ,
6309
- .NOSPC = > return error .NoSpaceLeft ,
6310
- .OVERFLOW = > return error .Unseekable ,
6311
- .PERM = > return error .PermissionDenied ,
6312
- .TXTBSY = > return error .SwapFile ,
6313
- // these may not be regular files, try fallback
6314
- .INVAL = > {},
6315
- // support for cross-filesystem copy added in Linux 5.3, use fallback
6316
- .XDEV = > {},
6317
- // syscall added in Linux 4.5, use fallback
6318
- .NOSYS = > {
6319
- has_copy_file_range_syscall .store (false , .Monotonic );
6292
+ // WASI-libc doesn't have copy_file_range.
6293
+ if (builtin .os .tag != .wasi ) {
6294
+ switch (builtin .os .tag ) {
6295
+ .linux = > {
6296
+ if (std .c .versionCheck (.{ .major = 2 , .minor = 27 , .patch = 0 }).ok and
6297
+ builtin .os .isAtLeast (.linux , .{ .major = 4 , .minor = 5 }) orelse true and
6298
+ has_copy_file_range_syscall .load (.Monotonic ))
6299
+ {
6300
+ var off_in_copy = @bitCast (i64 , off_in );
6301
+ var off_out_copy = @bitCast (i64 , off_out );
6302
+
6303
+ const rc = system .copy_file_range (fd_in , & off_in_copy , fd_out , & off_out_copy , len , flags );
6304
+ switch (system .getErrno (rc )) {
6305
+ .SUCCESS = > return @intCast (usize , rc ),
6306
+ .BADF = > return error .FilesOpenedWithWrongFlags ,
6307
+ .FBIG = > return error .FileTooBig ,
6308
+ .IO = > return error .InputOutput ,
6309
+ .ISDIR = > return error .IsDir ,
6310
+ .NOMEM = > return error .OutOfMemory ,
6311
+ .NOSPC = > return error .NoSpaceLeft ,
6312
+ .OVERFLOW = > return error .Unseekable ,
6313
+ .PERM = > return error .PermissionDenied ,
6314
+ .TXTBSY = > return error .SwapFile ,
6315
+ // these may not be regular files, try fallback
6316
+ .INVAL = > {},
6317
+ // support for cross-filesystem copy added in Linux 5.3, use fallback
6318
+ .XDEV = > {},
6319
+ // syscall added in Linux 4.5, use fallback
6320
+ .NOSYS = > {
6321
+ has_copy_file_range_syscall .store (false , .Monotonic );
6322
+ },
6323
+ else = > | err | return unexpectedErrno (err ),
6324
+ }
6325
+ }
6320
6326
},
6321
- else = > | err | return unexpectedErrno (err ),
6327
+ .freebsd = > {
6328
+ if (builtin .os .isAtLeast (.freebsd , .{ .major = 13 , .minor = 0 }) orelse true ) {
6329
+ var off_in_copy = @bitCast (i64 , off_in );
6330
+ var off_out_copy = @bitCast (i64 , off_out );
6331
+ const rc = freebsd .copy_file_range (fd_in , & off_in_copy , fd_out , & off_out_copy , len , flags );
6332
+ switch (system .getErrno (rc )) {
6333
+ .SUCCESS = > return @intCast (usize , rc ),
6334
+ .BADF = > return error .FilesOpenedWithWrongFlags ,
6335
+ .FBIG = > return error .FileTooBig ,
6336
+ .INVAL = > return error .RangeOverlap ,
6337
+ .IO = > return error .InputOutput ,
6338
+ .INTEGRITY = > return error .CorruptedData ,
6339
+ .ISDIR = > return error .IsDir ,
6340
+ .NOSPC = > return error .NoSpaceLeft ,
6341
+ .INTR = > unreachable ,
6342
+ else = > | err | return unexpectedErrno (err ),
6343
+ }
6344
+ }
6345
+ },
6346
+ // unsupported OS, use fallback
6347
+ else = > {},
6322
6348
}
6323
6349
}
6324
6350
0 commit comments