| ... | @@ -6314,6 +6314,7 @@ pub const CopyFileRangeError = error{ | ... | @@ -6314,6 +6314,7 @@ pub const CopyFileRangeError = error{ |
| 6314 | Unseekable, | 6314 | Unseekable, |
| 6315 | PermissionDenied, | 6315 | PermissionDenied, |
| 6316 | SwapFile, | 6316 | SwapFile, |
| | 6317 | CorruptedData, |
| 6317 | } || PReadError || PWriteError || UnexpectedError; | 6318 | } || PReadError || PWriteError || UnexpectedError; |
| 6318 | | 6319 | |
| 6319 | var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true); | 6320 | 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); | ... | @@ -6339,44 +6340,56 @@ var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true); |
| 6339 | /// | 6340 | /// |
| 6340 | /// These systems support in-kernel data copying: | 6341 | /// These systems support in-kernel data copying: |
| 6341 | /// * Linux 4.5 (cross-filesystem 5.3) | 6342 | /// * Linux 4.5 (cross-filesystem 5.3) |
| | 6343 | /// * FreeBSD 13.0 |
| 6342 | /// | 6344 | /// |
| 6343 | /// Other systems fall back to calling `pread` / `pwrite`. | 6345 | /// Other systems fall back to calling `pread` / `pwrite`. |
| 6344 | /// | 6346 | /// |
| 6345 | /// Maximum offsets on Linux are `math.maxInt(i64)`. | 6347 | /// Maximum offsets on Linux and FreeBSD are `math.maxInt(i64)`. |
| 6346 | 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 { | 6348 | 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) | 6349 | if ((comptime builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0 }) orelse false) or |
| 6348 | // WASI-libc doesn't have copy_file_range. | 6350 | ((comptime builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse false and |
| 6349 | false | 6351 | std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok) and |
| 6350 | else if (builtin.link_libc) | 6352 | has_copy_file_range_syscall.load(.Monotonic))) |
| 6351 | std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok | 6353 | { |
| 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)) { | | |
| 6356 | var off_in_copy = @bitCast(i64, off_in); | 6354 | var off_in_copy = @bitCast(i64, off_in); |
| 6357 | var off_out_copy = @bitCast(i64, off_out); | 6355 | var off_out_copy = @bitCast(i64, off_out); |
| 6358 | | 6356 | |
| 6359 | const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags); | 6357 | while (true) { |
| 6360 | switch (system.getErrno(rc)) { | 6358 | const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags); |
| 6361 | .SUCCESS => return @intCast(usize, rc), | 6359 | if (builtin.os.tag == .freebsd) { |
| 6362 | .BADF => return error.FilesOpenedWithWrongFlags, | 6360 | switch (system.getErrno(rc)) { |
| 6363 | .FBIG => return error.FileTooBig, | 6361 | .SUCCESS => return @intCast(usize, rc), |
| 6364 | .IO => return error.InputOutput, | 6362 | .BADF => return error.FilesOpenedWithWrongFlags, |
| 6365 | .ISDIR => return error.IsDir, | 6363 | .FBIG => return error.FileTooBig, |
| 6366 | .NOMEM => return error.OutOfMemory, | 6364 | .IO => return error.InputOutput, |
| 6367 | .NOSPC => return error.NoSpaceLeft, | 6365 | .ISDIR => return error.IsDir, |
| 6368 | .OVERFLOW => return error.Unseekable, | 6366 | .NOSPC => return error.NoSpaceLeft, |
| 6369 | .PERM => return error.PermissionDenied, | 6367 | .INVAL => break, // these may not be regular files, try fallback |
| 6370 | .TXTBSY => return error.SwapFile, | 6368 | .INTEGRITY => return error.CorruptedData, |
| 6371 | // these may not be regular files, try fallback | 6369 | .INTR => continue, |
| 6372 | .INVAL => {}, | 6370 | else => |err| return unexpectedErrno(err), |
| 6373 | // support for cross-filesystem copy added in Linux 5.3, use fallback | 6371 | } |
| 6374 | .XDEV => {}, | 6372 | } else { // assume linux |
| 6375 | // syscall added in Linux 4.5, use fallback | 6373 | switch (system.getErrno(rc)) { |
| 6376 | .NOSYS => { | 6374 | .SUCCESS => return @intCast(usize, rc), |
| 6377 | has_copy_file_range_syscall.store(false, .Monotonic); | 6375 | .BADF => return error.FilesOpenedWithWrongFlags, |
| 6378 | }, | 6376 | .FBIG => return error.FileTooBig, |
| 6379 | else => |err| return unexpectedErrno(err), | 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 | } |
| 6380 | } | 6393 | } |
| 6381 | } | 6394 | } |
| 6382 | | 6395 | |