@@ -781,6 +781,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
781
781
#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
782
782
pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
783
783
use fs:: { File , set_permissions} ;
784
+ use sync:: atomic:: { AtomicBool , Ordering } ;
785
+
786
+ // Kernel prior to 4.5 don't have copy_file_range
787
+ // We store the availability in a global to avoid unneccessary syscalls
788
+ static HAS_COPY_FILE_RANGE : AtomicBool = AtomicBool :: new ( true ) ;
784
789
785
790
unsafe fn copy_file_range (
786
791
fd_in : libc:: c_int ,
@@ -820,16 +825,26 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
820
825
} else {
821
826
( len - written) as usize
822
827
} ;
823
- let copy_result = unsafe {
824
- // We actually don't have to adjust the offsets,
825
- // because copy_file_range adjusts the file offset automatically
826
- cvt ( copy_file_range ( reader. as_raw_fd ( ) ,
827
- ptr:: null_mut ( ) ,
828
- writer. as_raw_fd ( ) ,
829
- ptr:: null_mut ( ) ,
830
- bytes_to_copy,
831
- 0 )
832
- )
828
+ let copy_result = if HAS_COPY_FILE_RANGE . load ( Ordering :: Relaxed ) {
829
+ let copy_result = unsafe {
830
+ // We actually don't have to adjust the offsets,
831
+ // because copy_file_range adjusts the file offset automatically
832
+ cvt ( copy_file_range ( reader. as_raw_fd ( ) ,
833
+ ptr:: null_mut ( ) ,
834
+ writer. as_raw_fd ( ) ,
835
+ ptr:: null_mut ( ) ,
836
+ bytes_to_copy,
837
+ 0 )
838
+ )
839
+ } ;
840
+ if let Err ( ref copy_err) = copy_result {
841
+ if let Some ( libc:: ENOSYS ) = copy_err. raw_os_error ( ) {
842
+ HAS_COPY_FILE_RANGE . store ( false , Ordering :: Relaxed ) ;
843
+ }
844
+ }
845
+ copy_result
846
+ } else {
847
+ Err ( io:: Error :: from_raw_os_error ( libc:: ENOSYS ) )
833
848
} ;
834
849
match copy_result {
835
850
Ok ( ret) => written += ret as u64 ,
0 commit comments