diff --git a/Cargo.toml b/Cargo.toml index e1f76408e..256a4772a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -284,7 +284,7 @@ radium = "1.1.1" rand = "0.10" rapidhash = "4.4.1" result-like = "0.5.0" -rustix = { version = "1.1", features = ["event", "param", "system"] } +rustix = { version = "1.1", features = ["event", "fs", "param", "system"] } rustls = { version = "0.23.39", default-features = false } rustls-graviola = "0.3" rustls-native-certs = "0.8" diff --git a/crates/host_env/src/os.rs b/crates/host_env/src/os.rs index 8afa07aea..b1d398faa 100644 --- a/crates/host_env/src/os.rs +++ b/crates/host_env/src/os.rs @@ -256,30 +256,14 @@ pub fn system(command: &CStr) -> libc::c_int { #[cfg(target_os = "linux")] pub fn copy_file_range( src: crt_fd::Borrowed<'_>, - offset_src: Option<&mut crt_fd::Offset>, + offset_src: Option<&mut u64>, dst: crt_fd::Borrowed<'_>, - offset_dst: Option<&mut crt_fd::Offset>, + offset_dst: Option<&mut u64>, count: usize, -) -> io::Result { - #[allow(clippy::unnecessary_option_map_or_else)] - let p_offset_src = offset_src.map_or_else(core::ptr::null_mut, |x| x as *mut _); - #[allow(clippy::unnecessary_option_map_or_else)] - let p_offset_dst = offset_dst.map_or_else(core::ptr::null_mut, |x| x as *mut _); - - // Why not use `libc::copy_file_range`: On musl, the libc wrapper may be missing. - let ret = unsafe { - libc::syscall( - libc::SYS_copy_file_range, - src.as_raw(), - p_offset_src, - dst.as_raw(), - p_offset_dst, - count, - 0u32, - ) - }; - - usize::try_from(ret).map_err(|_| io::Error::last_os_error()) +) -> rustix::io::Result { + // `copy_file_range` isn't wrapped in every libc (i.e. musl). + // However, Rustix is a safe wrapper around the syscall that bypasses libc. + rustix::fs::copy_file_range(src, offset_src, dst, offset_dst, count) } pub fn rename( @@ -369,6 +353,13 @@ impl ErrorExt for io::Error { } } +#[cfg(all(not(windows), not(target_arch = "wasm32")))] +impl ErrorExt for rustix::io::Errno { + fn posix_errno(&self) -> i32 { + self.raw_os_error() + } +} + /// Get the last error from C runtime library functions (like _dup, _dup2, _fstat, etc.) /// CRT functions set errno, not GetLastError(), so we need to read errno directly. #[cfg(windows)] diff --git a/crates/vm/src/stdlib/os.rs b/crates/vm/src/stdlib/os.rs index 986a45fb4..d6f6a181a 100644 --- a/crates/vm/src/stdlib/os.rs +++ b/crates/vm/src/stdlib/os.rs @@ -1709,20 +1709,30 @@ pub(super) mod _os { #[cfg(target_os = "linux")] #[pyfunction] - fn copy_file_range(mut args: CopyFileRangeArgs<'_>, vm: &VirtualMachine) -> PyResult { + fn copy_file_range(args: CopyFileRangeArgs<'_>, vm: &VirtualMachine) -> PyResult { let count: usize = args .count .try_into() .map_err(|_| vm.new_value_error("count should >= 0"))?; + let mut offset_src = args + .offset_src + .map(TryInto::try_into) + .transpose() + .map_err(|_| vm.new_value_error("offset_src should be >= 0"))?; + let mut offset_dst = args + .offset_dst + .map(TryInto::try_into) + .transpose() + .map_err(|_| vm.new_value_error("offset_dst should be >= 0"))?; crate::host_env::os::copy_file_range( args.src, - args.offset_src.as_mut(), + offset_src.as_mut(), args.dst, - args.offset_dst.as_mut(), + offset_dst.as_mut(), count, ) - .map_err(|_| vm.new_last_errno_error()) + .map_err(|e| vm.new_errno_error(e.raw_os_error(), e.to_string()).upcast()) } #[pyfunction]