diff --git a/std/src/sys/pal/unix/kernel_copy.rs b/std/src/sys/pal/unix/kernel_copy.rs index 60f4e55755d73..1db86bdb180f9 100644 --- a/std/src/sys/pal/unix/kernel_copy.rs +++ b/std/src/sys/pal/unix/kernel_copy.rs @@ -607,42 +607,44 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> Ok(0) => return CopyResult::Ended(written), // reached EOF Ok(ret) => written += ret as u64, Err(err) => { - let raw_os_error = match err.raw_os_error() { - Some(raw) => raw, - _ => return CopyResult::Error(err, written), - }; - return match raw_os_error { + return match err.raw_os_error() { // when file offset + max_length > u64::MAX - EOVERFLOW => CopyResult::Fallback(written), - ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF if written == 0 => { + Some(EOVERFLOW) => CopyResult::Fallback(written), + Some(raw_os_error @ (ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF)) + if written == 0 => + { if !have_probed { - if raw_os_error == ENOSYS { - HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed); - } else { - // EPERM can indicate seccomp filters or an - // immutable file. To distinguish these cases - // we probe with invalid file descriptors which - // should result in EBADF if the syscall is - // supported and some other error (ENOSYS or - // EPERM) if it's not available. - let result = unsafe { - cvt(copy_file_range( - INVALID_FD, - ptr::null_mut(), - INVALID_FD, - ptr::null_mut(), - 1, - 0, - )) - }; - - if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(EBADF))) - { - HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed); - } else { - HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed); + let available = match raw_os_error { + EPERM => { + // EPERM can indicate seccomp filters or an + // immutable file. To distinguish these + // cases we probe with invalid file + // descriptors which should result in EBADF + // if the syscall is supported and EPERM or + // ENOSYS if it's not available. + match unsafe { + cvt(copy_file_range( + INVALID_FD, + ptr::null_mut(), + INVALID_FD, + ptr::null_mut(), + 1, + 0, + )) + .map_err(|e| e.raw_os_error()) + } { + Err(Some(EPERM | ENOSYS)) => UNAVAILABLE, + Err(Some(EBADF)) => AVAILABLE, + Ok(_) => panic!("unexpected copy_file_range probe success"), + // Treat other errors as the syscall + // being unavailable. + Err(_) => UNAVAILABLE, + } } - } + ENOSYS => UNAVAILABLE, + _ => AVAILABLE, + }; + HAS_COPY_FILE_RANGE.store(available, Ordering::Relaxed); } // Try fallback io::copy if either: