Be stricter with copy_file_range
probe results · model-checking/verify-rust-std@30c876c (original) (raw)
`@@ -607,42 +607,44 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
`
607
607
`Ok(0) => return CopyResult::Ended(written), // reached EOF
`
608
608
`Ok(ret) => written += ret as u64,
`
609
609
`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() {
`
615
611
`// 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
`+
{
`
618
616
`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
`+
}
`
644
643
`}
`
645
``
`-
}
`
``
644
`+
ENOSYS => UNAVAILABLE,
`
``
645
`+
_ => AVAILABLE,
`
``
646
`+
};
`
``
647
`+
HAS_COPY_FILE_RANGE.store(available, Ordering::Relaxed);
`
646
648
`}
`
647
649
``
648
650
`// Try fallback io::copy if either:
`