@@ -577,6 +577,23 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
577
577
) -> libc:: ssize_t
578
578
}
579
579
580
+ fn probe_copy_file_range_support ( ) -> u8 {
581
+ // In some cases, we cannot determine availability from the first
582
+ // `copy_file_range` call. In this case, we probe with an invalid file
583
+ // descriptor so that the results are easily interpretable.
584
+ match unsafe {
585
+ cvt ( copy_file_range ( INVALID_FD , ptr:: null_mut ( ) , INVALID_FD , ptr:: null_mut ( ) , 1 , 0 ) )
586
+ . map_err ( |e| e. raw_os_error ( ) )
587
+ } {
588
+ Err ( Some ( EPERM | ENOSYS ) ) => UNAVAILABLE ,
589
+ Err ( Some ( EBADF ) ) => AVAILABLE ,
590
+ Ok ( _) => panic ! ( "unexpected copy_file_range probe success" ) ,
591
+ // Treat other errors as the syscall
592
+ // being unavailable.
593
+ Err ( _) => UNAVAILABLE ,
594
+ }
595
+ }
596
+
580
597
let mut written = 0u64 ;
581
598
while written < max_len {
582
599
let bytes_to_copy = cmp:: min ( max_len - written, usize:: MAX as u64 ) ;
@@ -614,35 +631,20 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
614
631
if written == 0 =>
615
632
{
616
633
if !have_probed {
617
- let available = match raw_os_error {
618
- EPERM => {
619
- // EPERM can indicate seccomp filters or an
620
- // immutable file. To distinguish these
621
- // cases we probe with invalid file
622
- // descriptors which should result in EBADF
623
- // if the syscall is supported and EPERM or
624
- // ENOSYS if it's not available.
625
- match unsafe {
626
- cvt ( copy_file_range (
627
- INVALID_FD ,
628
- ptr:: null_mut ( ) ,
629
- INVALID_FD ,
630
- ptr:: null_mut ( ) ,
631
- 1 ,
632
- 0 ,
633
- ) )
634
- . map_err ( |e| e. raw_os_error ( ) )
635
- } {
636
- Err ( Some ( EPERM | ENOSYS ) ) => UNAVAILABLE ,
637
- Err ( Some ( EBADF ) ) => AVAILABLE ,
638
- Ok ( _) => panic ! ( "unexpected copy_file_range probe success" ) ,
639
- // Treat other errors as the syscall
640
- // being unavailable.
641
- Err ( _) => UNAVAILABLE ,
642
- }
643
- }
644
- ENOSYS => UNAVAILABLE ,
645
- _ => AVAILABLE ,
634
+ let available = if matches ! ( raw_os_error, ENOSYS | EOPNOTSUPP | EPERM ) {
635
+ // EPERM can indicate seccomp filters or an
636
+ // immutable file. To distinguish these
637
+ // cases we probe with invalid file
638
+ // descriptors which should result in EBADF
639
+ // if the syscall is supported and EPERM or
640
+ // ENOSYS if it's not available.
641
+ //
642
+ // For EOPNOTSUPP, see below. In the case of
643
+ // ENOSYS, we try to cover for faulty FUSE
644
+ // drivers.
645
+ probe_copy_file_range_support ( )
646
+ } else {
647
+ AVAILABLE
646
648
} ;
647
649
HAS_COPY_FILE_RANGE . store ( available, Ordering :: Relaxed ) ;
648
650
}
0 commit comments