Skip to content

Commit

Permalink
cp: fix possible OOM and partial write with large files
Browse files Browse the repository at this point in the history
  • Loading branch information
neyo8826 committed Sep 13, 2024
1 parent 7430856 commit 75485ae
Showing 1 changed file with 9 additions and 18 deletions.
27 changes: 9 additions & 18 deletions src/uu/cp/src/platform/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ where
}
let src_fd = src_file.as_raw_fd();
let mut current_offset: isize = 0;
let step = std::cmp::min(size, 16 * 1024 * 1024) as usize; // 16 MiB
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()
Expand All @@ -158,16 +160,12 @@ where
return Err(std::io::Error::last_os_error());
}
let len: isize = hole - current_offset;
let mut buf: Vec<u8> = vec![0x0; len as usize];
src_file.read_exact_at(&mut buf, current_offset as u64)?;
unsafe {
libc::pwrite(
dst_fd,
buf.as_ptr() as *const libc::c_void,
len as usize,
current_offset.try_into().unwrap(),
)
};
for i in (0..len).step_by(step) {
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)?;
}
current_offset = hole;
}
Ok(())
Expand Down Expand Up @@ -198,14 +196,7 @@ where
while current_offset < size {
let this_read = src_file.read(&mut buf)?;
if buf.iter().any(|&x| x != 0) {
unsafe {
libc::pwrite(
dst_fd,
buf.as_ptr() as *const libc::c_void,
this_read,
current_offset.try_into().unwrap(),
)
};
dst_file.write_all_at(&buf, current_offset.try_into().unwrap())?;
}
current_offset += this_read;
}
Expand Down

0 comments on commit 75485ae

Please sign in to comment.