Skip to content

Commit 30c876c

Browse files
committed
Be stricter with copy_file_range probe results
1 parent fe05246 commit 30c876c

File tree

1 file changed

+35
-33
lines changed

1 file changed

+35
-33
lines changed

std/src/sys/pal/unix/kernel_copy.rs

+35-33
Original file line numberDiff line numberDiff line change
@@ -607,42 +607,44 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
607607
Ok(0) => return CopyResult::Ended(written), // reached EOF
608608
Ok(ret) => written += ret as u64,
609609
Err(err) => {
610-
let raw_os_error = match err.raw_os_error() {
611-
Some(raw) => raw,
612-
_ => return CopyResult::Error(err, written),
613-
};
614-
return match raw_os_error {
610+
return match err.raw_os_error() {
615611
// when file offset + max_length > u64::MAX
616-
EOVERFLOW => CopyResult::Fallback(written),
617-
ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF if written == 0 => {
612+
Some(EOVERFLOW) => CopyResult::Fallback(written),
613+
Some(raw_os_error @ (ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF))
614+
if written == 0 =>
615+
{
618616
if !have_probed {
619-
if raw_os_error == ENOSYS {
620-
HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed);
621-
} else {
622-
// EPERM can indicate seccomp filters or an
623-
// immutable file. To distinguish these cases
624-
// we probe with invalid file descriptors which
625-
// should result in EBADF if the syscall is
626-
// supported and some other error (ENOSYS or
627-
// EPERM) if it's not available.
628-
let result = unsafe {
629-
cvt(copy_file_range(
630-
INVALID_FD,
631-
ptr::null_mut(),
632-
INVALID_FD,
633-
ptr::null_mut(),
634-
1,
635-
0,
636-
))
637-
};
638-
639-
if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(EBADF)))
640-
{
641-
HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed);
642-
} else {
643-
HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed);
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+
}
644643
}
645-
}
644+
ENOSYS => UNAVAILABLE,
645+
_ => AVAILABLE,
646+
};
647+
HAS_COPY_FILE_RANGE.store(available, Ordering::Relaxed);
646648
}
647649

648650
// Try fallback io::copy if either:

0 commit comments

Comments
 (0)