mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
cp: fix possible OOM and partial write with large files
This commit is contained in:
parent
6935a0d67e
commit
1781c3e07d
1 changed files with 14 additions and 18 deletions
|
@ -141,6 +141,10 @@ where
|
||||||
}
|
}
|
||||||
let src_fd = src_file.as_raw_fd();
|
let src_fd = src_file.as_raw_fd();
|
||||||
let mut current_offset: isize = 0;
|
let mut current_offset: isize = 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 {
|
loop {
|
||||||
let result = unsafe { libc::lseek(src_fd, current_offset.try_into().unwrap(), SEEK_DATA) }
|
let result = unsafe { libc::lseek(src_fd, current_offset.try_into().unwrap(), SEEK_DATA) }
|
||||||
.try_into()
|
.try_into()
|
||||||
|
@ -158,16 +162,14 @@ where
|
||||||
return Err(std::io::Error::last_os_error());
|
return Err(std::io::Error::last_os_error());
|
||||||
}
|
}
|
||||||
let len: isize = hole - current_offset;
|
let len: isize = hole - current_offset;
|
||||||
let mut buf: Vec<u8> = vec![0x0; len as usize];
|
// Read and write data in chunks of `step` while reusing the same buffer
|
||||||
src_file.read_exact_at(&mut buf, current_offset as u64)?;
|
for i in (0..len).step_by(step) {
|
||||||
unsafe {
|
// Ensure we don't read past the end of the file or the start of the next hole
|
||||||
libc::pwrite(
|
let read_len = std::cmp::min((len - i) as usize, step);
|
||||||
dst_fd,
|
let buf = &mut buf[..read_len];
|
||||||
buf.as_ptr() as *const libc::c_void,
|
src_file.read_exact_at(buf, (current_offset + i) as u64)?;
|
||||||
len as usize,
|
dst_file.write_all_at(buf, (current_offset + i) as u64)?;
|
||||||
current_offset.try_into().unwrap(),
|
}
|
||||||
)
|
|
||||||
};
|
|
||||||
current_offset = hole;
|
current_offset = hole;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -197,15 +199,9 @@ where
|
||||||
// https://www.kernel.org/doc/html/latest/filesystems/fiemap.html
|
// https://www.kernel.org/doc/html/latest/filesystems/fiemap.html
|
||||||
while current_offset < size {
|
while current_offset < size {
|
||||||
let this_read = src_file.read(&mut buf)?;
|
let this_read = src_file.read(&mut buf)?;
|
||||||
|
let buf = &buf[..this_read];
|
||||||
if buf.iter().any(|&x| x != 0) {
|
if buf.iter().any(|&x| x != 0) {
|
||||||
unsafe {
|
dst_file.write_all_at(buf, current_offset.try_into().unwrap())?;
|
||||||
libc::pwrite(
|
|
||||||
dst_fd,
|
|
||||||
buf.as_ptr() as *const libc::c_void,
|
|
||||||
this_read,
|
|
||||||
current_offset.try_into().unwrap(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
current_offset += this_read;
|
current_offset += this_read;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue