Skip to content

Commit 0e09f13

Browse files
committed
chore(cp): move raw libc calls to rustix
1 parent 061f4cb commit 0e09f13

1 file changed

Lines changed: 21 additions & 50 deletions

File tree

src/uu/cp/src/platform/linux.rs

Lines changed: 21 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44
// file that was distributed with this source code.
55
// spell-checker:ignore ficlone reflink ftruncate pwrite fiemap lseek
66

7-
use libc::{SEEK_DATA, SEEK_HOLE};
7+
use rustix::fs::{SeekFrom, ftruncate, ioctl_ficlone, seek};
88
use std::fs::{File, OpenOptions};
99
use std::io::Read;
1010
use std::os::unix::fs::FileExt;
1111
use std::os::unix::fs::MetadataExt;
1212
use std::os::unix::fs::{FileTypeExt, OpenOptionsExt};
13-
use std::os::unix::io::AsRawFd;
1413
use std::path::Path;
1514
use uucore::buf_copy;
1615
use uucore::mode::get_umask;
@@ -60,18 +59,15 @@ where
6059
{
6160
let src_file = File::open(&source)?;
6261
let dst_file = File::create(&dest)?;
63-
let src_fd = src_file.as_raw_fd();
64-
let dst_fd = dst_file.as_raw_fd();
65-
let result = unsafe { libc::ioctl(dst_fd, libc::FICLONE, src_fd) };
66-
if result == 0 {
67-
return Ok(());
68-
}
69-
match fallback {
70-
CloneFallback::Error => Err(std::io::Error::last_os_error()),
71-
CloneFallback::FSCopy => std::fs::copy(source, dest).map(|_| ()),
72-
CloneFallback::SparseCopy => sparse_copy(source, dest),
73-
CloneFallback::SparseCopyWithoutHole => sparse_copy_without_hole(source, dest),
62+
if ioctl_ficlone(dst_file, src_file).is_err() {
63+
return match fallback {
64+
CloneFallback::Error => Err(std::io::Error::last_os_error()),
65+
CloneFallback::FSCopy => std::fs::copy(source, dest).map(|_| ()),
66+
CloneFallback::SparseCopy => sparse_copy(source, dest),
67+
CloneFallback::SparseCopyWithoutHole => sparse_copy_without_hole(source, dest),
68+
};
7469
}
70+
Ok(())
7571
}
7672

7773
/// 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> {
9086
let _ = src_file.read(&mut buf)?;
9187
return Ok((buf.iter().any(|&x| x != 0x0), size, 0));
9288
}
89+
let has_data = seek(src_file, SeekFrom::Data(0)).is_ok();
9390

94-
let src_fd = src_file.as_raw_fd();
95-
96-
let result = unsafe { libc::lseek(src_fd, 0, SEEK_DATA) };
97-
98-
match result {
99-
-1 => Ok((false, size, blocks)), // No data found or end of file
100-
_ if result >= 0 => Ok((true, size, blocks)), // Data found
101-
_ => Err(std::io::Error::last_os_error()),
102-
}
91+
Ok((has_data, size, blocks))
10392
}
10493

10594
#[cfg(any(target_os = "linux", target_os = "android"))]
@@ -126,42 +115,27 @@ where
126115
{
127116
let src_file = File::open(source)?;
128117
let dst_file = File::create(dest)?;
129-
let dst_fd = dst_file.as_raw_fd();
130118

131119
let size = src_file.metadata()?.size();
132-
if unsafe { libc::ftruncate(dst_fd, size.try_into().unwrap()) } < 0 {
133-
return Err(std::io::Error::last_os_error());
134-
}
135-
let src_fd = src_file.as_raw_fd();
136-
let mut current_offset: isize = 0;
120+
ftruncate(&dst_file, size)?;
121+
let mut current_offset = 0;
137122
// Maximize the data read at once to 16 MiB to avoid memory hogging with large files
138123
// 16 MiB chunks should saturate an SSD
139124
let step = std::cmp::min(size, 16 * 1024 * 1024) as usize;
140125
let mut buf: Vec<u8> = vec![0x0; step];
141-
loop {
142-
let result = unsafe { libc::lseek(src_fd, current_offset.try_into().unwrap(), SEEK_DATA) }
143-
.try_into()
144-
.unwrap();
145-
146-
current_offset = result;
147-
let hole: isize =
148-
unsafe { libc::lseek(src_fd, current_offset.try_into().unwrap(), SEEK_HOLE) }
149-
.try_into()
150-
.unwrap();
151-
if result == -1 || hole == -1 {
126+
while let Ok(data) = seek(&src_file, SeekFrom::Data(current_offset)) {
127+
current_offset = data;
128+
let Ok(hole) = seek(&src_file, SeekFrom::Hole(current_offset)) else {
152129
break;
153-
}
154-
if result <= -2 || hole <= -2 {
155-
return Err(std::io::Error::last_os_error());
156-
}
157-
let len: isize = hole - current_offset;
130+
};
131+
let len = hole - current_offset;
158132
// Read and write data in chunks of `step` while reusing the same buffer
159133
for i in (0..len).step_by(step) {
160134
// Ensure we don't read past the end of the file or the start of the next hole
161135
let read_len = std::cmp::min((len - i) as usize, step);
162136
let buf = &mut buf[..read_len];
163-
src_file.read_exact_at(buf, (current_offset + i) as u64)?;
164-
dst_file.write_all_at(buf, (current_offset + i) as u64)?;
137+
src_file.read_exact_at(buf, current_offset + i)?;
138+
dst_file.write_all_at(buf, current_offset + i)?;
165139
}
166140
current_offset = hole;
167141
}
@@ -176,12 +150,9 @@ where
176150
{
177151
let mut src_file = File::open(source)?;
178152
let dst_file = File::create(dest)?;
179-
let dst_fd = dst_file.as_raw_fd();
180153

181154
let size: usize = src_file.metadata()?.size().try_into().unwrap();
182-
if unsafe { libc::ftruncate(dst_fd, size.try_into().unwrap()) } < 0 {
183-
return Err(std::io::Error::last_os_error());
184-
}
155+
ftruncate(&dst_file, size.try_into().unwrap())?;
185156

186157
let blksize = dst_file.metadata()?.blksize();
187158
let mut buf: Vec<u8> = vec![0; blksize.try_into().unwrap()];

0 commit comments

Comments
 (0)