@@ -577,6 +577,23 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
577577 ) -> libc:: ssize_t
578578 }
579579
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+
580597 let mut written = 0u64 ;
581598 while written < max_len {
582599 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) ->
614631 if written == 0 =>
615632 {
616633 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
646648 } ;
647649 HAS_COPY_FILE_RANGE . store ( available, Ordering :: Relaxed ) ;
648650 }
0 commit comments