about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTobias Bucher <tobiasbucher5991@gmail.com>2024-03-06 14:37:25 +0100
committerTobias Bucher <tobiasbucher5991@gmail.com>2024-03-06 14:37:25 +0100
commit5073475b0e5477c3d02c219a4c2e7075891240a7 (patch)
tree248089fae4561bfe635e8d2bdff040a74710506f
parent214c49837a56c402ab28f7dd5eff08c7ae709c09 (diff)
downloadrust-5073475b0e5477c3d02c219a4c2e7075891240a7.tar.gz
rust-5073475b0e5477c3d02c219a4c2e7075891240a7.zip
Be stricter with `copy_file_range` probe results
-rw-r--r--library/std/src/sys/pal/unix/kernel_copy.rs68
1 files changed, 35 insertions, 33 deletions
diff --git a/library/std/src/sys/pal/unix/kernel_copy.rs b/library/std/src/sys/pal/unix/kernel_copy.rs
index 60f4e55755d..1db86bdb180 100644
--- a/library/std/src/sys/pal/unix/kernel_copy.rs
+++ b/library/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: