@@ -4945,6 +4945,9 @@ pub fn sendfile(
4945
4945
pub const CopyFileRangeError = error {
4946
4946
FileTooBig ,
4947
4947
InputOutput ,
4948
+ /// `fd_in` is not open for reading; or `fd_out` is not open for writing;
4949
+ /// or the `O_APPEND` flag is set for `fd_out`.
4950
+ FilesOpenedWithWrongFlags ,
4948
4951
IsDir ,
4949
4952
OutOfMemory ,
4950
4953
NoSpaceLeft ,
@@ -4953,6 +4956,11 @@ pub const CopyFileRangeError = error{
4953
4956
FileBusy ,
4954
4957
} || PReadError || PWriteError || UnexpectedError ;
4955
4958
4959
+ var has_copy_file_range_syscall = init : {
4960
+ const kernel_has_syscall = std .Target .current .os .isAtLeast (.linux , .{ .major = 4 , .minor = 5 }) orelse true ;
4961
+ break :init std .atomic .Int (bool ).init (kernel_has_syscall );
4962
+ };
4963
+
4956
4964
/// Transfer data between file descriptors at specified offsets.
4957
4965
/// Returns the number of bytes written, which can less than requested.
4958
4966
///
@@ -4981,22 +4989,18 @@ pub const CopyFileRangeError = error{
4981
4989
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 {
4982
4990
const use_c = std .c .versionCheck (.{ .major = 2 , .minor = 27 , .patch = 0 }).ok ;
4983
4991
4984
- // TODO support for other systems than linux
4985
- const try_syscall = comptime std .Target .current .os .isAtLeast (.linux , .{ .major = 4 , .minor = 5 }) != false ;
4986
-
4987
- if (use_c or try_syscall ) {
4992
+ if (std .Target .current .os .tag == .linux and
4993
+ (use_c or has_copy_file_range_syscall .get ()))
4994
+ {
4988
4995
const sys = if (use_c ) std .c else linux ;
4989
4996
4990
4997
var off_in_copy = @bitCast (i64 , off_in );
4991
4998
var off_out_copy = @bitCast (i64 , off_out );
4992
4999
4993
5000
const rc = sys .copy_file_range (fd_in , & off_in_copy , fd_out , & off_out_copy , len , flags );
4994
-
4995
- // TODO avoid wasting a syscall every time if kernel is too old and returns ENOSYS https://github.com/ziglang/zig/issues/1018
4996
-
4997
5001
switch (sys .getErrno (rc )) {
4998
5002
0 = > return @intCast (usize , rc ),
4999
- EBADF = > unreachable ,
5003
+ EBADF = > return error . FilesOpenedWithWrongFlags ,
5000
5004
EFBIG = > return error .FileTooBig ,
5001
5005
EIO = > return error .InputOutput ,
5002
5006
EISDIR = > return error .IsDir ,
@@ -5005,9 +5009,14 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len
5005
5009
EOVERFLOW = > return error .Unseekable ,
5006
5010
EPERM = > return error .PermissionDenied ,
5007
5011
ETXTBSY = > return error .FileBusy ,
5008
- EINVAL = > {}, // these may not be regular files, try fallback
5009
- EXDEV = > {}, // support for cross-filesystem copy added in Linux 5.3, use fallback
5010
- ENOSYS = > {}, // syscall added in Linux 4.5, use fallback
5012
+ // these may not be regular files, try fallback
5013
+ EINVAL = > {},
5014
+ // support for cross-filesystem copy added in Linux 5.3, use fallback
5015
+ EXDEV = > {},
5016
+ // syscall added in Linux 4.5, use fallback
5017
+ ENOSYS = > {
5018
+ has_copy_file_range_syscall .set (false );
5019
+ },
5011
5020
else = > | err | return unexpectedErrno (err ),
5012
5021
}
5013
5022
}
0 commit comments