host_env: Use Rustix for copy_file_range (#8099)

Rustix bypasses `libc` to make direct syscalls on Linux. Rustix is also
semantically cleaner than `libc` itself. For `copy_file_range`, the
offsets can't be negative but `libc`'s `off_t` type is an `i64` because
it's used elsewhere, including for functions that CAN take a negative
offset. Rustix is cleaner because the offsets are `u64`.
This commit is contained in:
Joshua Megnauth authored and GitHub committed 2026-06-15 11:18:31 +09:00
1 parent 370fc76f6c
commit a0fcafd3f5
3 files changed
+28 -27

No files matched your search

+1 -1
View File
@@ -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"
+13 -22
View File
@@ -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<usize> {
#[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<usize> {
// `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)]
+14 -4
View File
@@ -1709,20 +1709,30 @@ pub(super) mod _os {
#[cfg(target_os = "linux")]
#[pyfunction]
fn copy_file_range(mut args: CopyFileRangeArgs<'_>, vm: &VirtualMachine) -> PyResult<usize> {
fn copy_file_range(args: CopyFileRangeArgs<'_>, vm: &VirtualMachine) -> PyResult<usize> {
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]