chore(cp): move raw libc calls to rustix

This commit is contained in:
Guillem L. Jara
2026-05-01 15:53:44 +02:00
committed by Dorian Péron
parent b5ba95b030
commit bf89c8bf22
+21 -50
View File
@@ -4,13 +4,12 @@
// file that was distributed with this source code.
// spell-checker:ignore ficlone reflink ftruncate pwrite fiemap lseek
use libc::{SEEK_DATA, SEEK_HOLE};
use rustix::fs::{SeekFrom, ftruncate, ioctl_ficlone, seek};
use std::fs::{File, OpenOptions};
use std::io::Read;
use std::os::unix::fs::FileExt;
use std::os::unix::fs::MetadataExt;
use std::os::unix::fs::{FileTypeExt, OpenOptionsExt};
use std::os::unix::io::AsRawFd;
use std::path::Path;
use uucore::buf_copy;
use uucore::mode::get_umask;
@@ -60,18 +59,15 @@ where
{
let src_file = File::open(&source)?;
let dst_file = File::create(&dest)?;
let src_fd = src_file.as_raw_fd();
let dst_fd = dst_file.as_raw_fd();
let result = unsafe { libc::ioctl(dst_fd, libc::FICLONE, src_fd) };
if result == 0 {
return Ok(());
}
match fallback {
CloneFallback::Error => Err(std::io::Error::last_os_error()),
CloneFallback::FSCopy => std::fs::copy(source, dest).map(|_| ()),
CloneFallback::SparseCopy => sparse_copy(source, dest),
CloneFallback::SparseCopyWithoutHole => sparse_copy_without_hole(source, dest),
if ioctl_ficlone(dst_file, src_file).is_err() {
return match fallback {
CloneFallback::Error => Err(std::io::Error::last_os_error()),
CloneFallback::FSCopy => std::fs::copy(source, dest).map(|_| ()),
CloneFallback::SparseCopy => sparse_copy(source, dest),
CloneFallback::SparseCopyWithoutHole => sparse_copy_without_hole(source, dest),
};
}
Ok(())
}
/// Checks whether a file contains any non null bytes i.e. any byte != 0x0
@@ -90,16 +86,9 @@ fn check_for_data(source: &Path) -> Result<(bool, u64, u64), std::io::Error> {
let _ = src_file.read(&mut buf)?;
return Ok((buf.iter().any(|&x| x != 0x0), size, 0));
}
let has_data = seek(src_file, SeekFrom::Data(0)).is_ok();
let src_fd = src_file.as_raw_fd();
let result = unsafe { libc::lseek(src_fd, 0, SEEK_DATA) };
match result {
-1 => Ok((false, size, blocks)), // No data found or end of file
_ if result >= 0 => Ok((true, size, blocks)), // Data found
_ => Err(std::io::Error::last_os_error()),
}
Ok((has_data, size, blocks))
}
#[cfg(any(target_os = "linux", target_os = "android"))]
@@ -126,42 +115,27 @@ where
{
let src_file = File::open(source)?;
let dst_file = File::create(dest)?;
let dst_fd = dst_file.as_raw_fd();
let size = src_file.metadata()?.size();
if unsafe { libc::ftruncate(dst_fd, size.try_into().unwrap()) } < 0 {
return Err(std::io::Error::last_os_error());
}
let src_fd = src_file.as_raw_fd();
let mut current_offset: isize = 0;
ftruncate(&dst_file, size)?;
let mut current_offset = 0;
// Maximize the data read at once to 16 MiB to avoid memory hogging with large files
// 16 MiB chunks should saturate an SSD
let step = std::cmp::min(size, 16 * 1024 * 1024) as usize;
let mut buf: Vec<u8> = vec![0x0; step];
loop {
let result = unsafe { libc::lseek(src_fd, current_offset.try_into().unwrap(), SEEK_DATA) }
.try_into()
.unwrap();
current_offset = result;
let hole: isize =
unsafe { libc::lseek(src_fd, current_offset.try_into().unwrap(), SEEK_HOLE) }
.try_into()
.unwrap();
if result == -1 || hole == -1 {
while let Ok(data) = seek(&src_file, SeekFrom::Data(current_offset)) {
current_offset = data;
let Ok(hole) = seek(&src_file, SeekFrom::Hole(current_offset)) else {
break;
}
if result <= -2 || hole <= -2 {
return Err(std::io::Error::last_os_error());
}
let len: isize = hole - current_offset;
};
let len = hole - current_offset;
// Read and write data in chunks of `step` while reusing the same buffer
for i in (0..len).step_by(step) {
// Ensure we don't read past the end of the file or the start of the next hole
let read_len = std::cmp::min((len - i) as usize, step);
let buf = &mut buf[..read_len];
src_file.read_exact_at(buf, (current_offset + i) as u64)?;
dst_file.write_all_at(buf, (current_offset + i) as u64)?;
src_file.read_exact_at(buf, current_offset + i)?;
dst_file.write_all_at(buf, current_offset + i)?;
}
current_offset = hole;
}
@@ -176,12 +150,9 @@ where
{
let mut src_file = File::open(source)?;
let dst_file = File::create(dest)?;
let dst_fd = dst_file.as_raw_fd();
let size: usize = src_file.metadata()?.size().try_into().unwrap();
if unsafe { libc::ftruncate(dst_fd, size.try_into().unwrap()) } < 0 {
return Err(std::io::Error::last_os_error());
}
ftruncate(&dst_file, size.try_into().unwrap())?;
let blksize = dst_file.metadata()?.blksize();
let mut buf: Vec<u8> = vec![0; blksize.try_into().unwrap()];