Lift the probe code of `copy_file_range` into a function · model-checking/verify-rust-std@7a6ddb3
@@ -577,6 +577,23 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
577577) -> libc::ssize_t
578578}
579579580+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+580597let mut written = 0u64;
581598while written < max_len {
582599let 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) ->
614631if written == 0 =>
615632{
616633if !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};
647649HAS_COPY_FILE_RANGE.store(available, Ordering::Relaxed);
648650}