aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAli Chraghi <alichraghi@pm.me>2022-09-24 19:18:01 +0330
committerAndrew Kelley <andrew@ziglang.org>2022-11-05 15:43:39 -0400
commitaea617c60be848ed372343e08465bb0ac6cb7b85 (patch)
tree4408094ab9c82d28d2b5486308b73ba1226e7649
parent28288dcbbf5258fe7461bbe0f6b2feeba0c2de5d (diff)
downloadzig-aea617c60be848ed372343e08465bb0ac6cb7b85.tar.gz
zig-aea617c60be848ed372343e08465bb0ac6cb7b85.zip
std.os: take advantage of the freebsd's copy_file_range
-rw-r--r--lib/std/c/freebsd.zig2
-rw-r--r--lib/std/os.zig75
-rw-r--r--src/link.zig1
3 files changed, 47 insertions, 31 deletions
diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig
index 9614a14522..06b7b04727 100644
--- a/lib/std/c/freebsd.zig
+++ b/lib/std/c/freebsd.zig
@@ -1440,6 +1440,7 @@ pub const E = enum(u16) {
CAPMODE = 94, // Not permitted in capability mode
NOTRECOVERABLE = 95, // State not recoverable
OWNERDEAD = 96, // Previous owner died
+ INTEGRITY = 97, // Integrity check failed
_,
};
@@ -1875,3 +1876,4 @@ pub const MFD = struct {
};
pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
+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;
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 8590d0f696..edea8f1620 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -6314,6 +6314,7 @@ pub const CopyFileRangeError = error{
Unseekable,
PermissionDenied,
SwapFile,
+ CorruptedData,
} || PReadError || PWriteError || UnexpectedError;
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);
///
/// These systems support in-kernel data copying:
/// * Linux 4.5 (cross-filesystem 5.3)
+/// * FreeBSD 13.0
///
/// Other systems fall back to calling `pread` / `pwrite`.
///
-/// Maximum offsets on Linux are `math.maxInt(i64)`.
+/// Maximum offsets on Linux and FreeBSD are `math.maxInt(i64)`.
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 {
- const call_cfr = comptime if (builtin.os.tag == .wasi)
- // WASI-libc doesn't have copy_file_range.
- false
- else if (builtin.link_libc)
- std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok
- else
- builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true;
-
- if (call_cfr and has_copy_file_range_syscall.load(.Monotonic)) {
+ if ((comptime builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0 }) orelse false) or
+ ((comptime builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse false and
+ std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok) and
+ has_copy_file_range_syscall.load(.Monotonic)))
+ {
var off_in_copy = @bitCast(i64, off_in);
var off_out_copy = @bitCast(i64, off_out);
- const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
- switch (system.getErrno(rc)) {
- .SUCCESS => return @intCast(usize, rc),
- .BADF => return error.FilesOpenedWithWrongFlags,
- .FBIG => return error.FileTooBig,
- .IO => return error.InputOutput,
- .ISDIR => return error.IsDir,
- .NOMEM => return error.OutOfMemory,
- .NOSPC => return error.NoSpaceLeft,
- .OVERFLOW => return error.Unseekable,
- .PERM => return error.PermissionDenied,
- .TXTBSY => return error.SwapFile,
- // these may not be regular files, try fallback
- .INVAL => {},
- // support for cross-filesystem copy added in Linux 5.3, use fallback
- .XDEV => {},
- // syscall added in Linux 4.5, use fallback
- .NOSYS => {
- has_copy_file_range_syscall.store(false, .Monotonic);
- },
- else => |err| return unexpectedErrno(err),
+ while (true) {
+ const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
+ if (builtin.os.tag == .freebsd) {
+ switch (system.getErrno(rc)) {
+ .SUCCESS => return @intCast(usize, rc),
+ .BADF => return error.FilesOpenedWithWrongFlags,
+ .FBIG => return error.FileTooBig,
+ .IO => return error.InputOutput,
+ .ISDIR => return error.IsDir,
+ .NOSPC => return error.NoSpaceLeft,
+ .INVAL => break, // these may not be regular files, try fallback
+ .INTEGRITY => return error.CorruptedData,
+ .INTR => continue,
+ else => |err| return unexpectedErrno(err),
+ }
+ } else { // assume linux
+ switch (system.getErrno(rc)) {
+ .SUCCESS => return @intCast(usize, rc),
+ .BADF => return error.FilesOpenedWithWrongFlags,
+ .FBIG => return error.FileTooBig,
+ .IO => return error.InputOutput,
+ .ISDIR => return error.IsDir,
+ .NOSPC => return error.NoSpaceLeft,
+ .INVAL => break, // these may not be regular files, try fallback
+ .NOMEM => return error.OutOfMemory,
+ .OVERFLOW => return error.Unseekable,
+ .PERM => return error.PermissionDenied,
+ .TXTBSY => return error.SwapFile,
+ .XDEV => break, // support for cross-filesystem copy added in Linux 5.3, use fallback
+ .NOSYS => { // syscall added in Linux 4.5, use fallback
+ has_copy_file_range_syscall.store(false, .Monotonic);
+ break;
+ },
+ else => |err| return unexpectedErrno(err),
+ }
+ }
}
}
diff --git a/src/link.zig b/src/link.zig
index ffa95c9efb..3097e5cf1f 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -457,6 +457,7 @@ pub const File = struct {
Unseekable,
PermissionDenied,
SwapFile,
+ CorruptedData,
SystemResources,
OperationAborted,
BrokenPipe,