use anyhow::Result; use std::fs::OpenOptions; use std::path::Path; use std::io::{Seek, SeekFrom, Write, Read}; //use std::os::unix::fs::OpenOptionsExt; pub type Sector = u64; #[derive(Debug)] pub struct Region { pub src: Sector, pub dest: Sector, pub len: Sector, } fn copy_step(file: &mut W, src_byte: u64, dest_byte: u64, len: usize) -> Result<()> where W: Write + Seek + Read, { let mut buf = vec![0; len]; file.seek(SeekFrom::Start(src_byte))?; file.read_exact(&mut buf)?; file.seek(SeekFrom::Start(dest_byte))?; file.write_all(&buf)?; Ok(()) } fn copy_region(file: &mut W, r: &Region) -> Result<()> where W: Write + Seek + Read, { const MAX_BYTES: Sector = 1024 * 1024 * 64; let src_bytes = r.src * 512; let dest_bytes = r.dest * 512; let len_bytes = r.len * 512; let mut written = 0; while written != len_bytes { let step = u64::min(len_bytes - written, MAX_BYTES); copy_step(file, src_bytes + written, dest_bytes + written, step as usize)?; written += step; } Ok(()) } pub fn copy(path: &Path, regions: &[Region]) -> Result<()> { let mut input = OpenOptions::new() .read(true) .write(true) //.custom_flags(libc::O_DIRECT) .open(path)?; for r in regions { eprintln!("copying {:?}", r); copy_region(&mut input, r)?; } input.flush()?; Ok(()) }