use std::fs::File;
use std::io;
use std::io::Error;
use std::io::ErrorKind;
pub trait PunchHole {
fn punch_hole(&self, offset: u64, length: u64) -> io::Result<()>;
}
impl PunchHole for File {
fn punch_hole(&self, offset: u64, length: u64) -> io::Result<()> {
crate::platform::file_punch_hole(self, offset, length)
}
}
pub trait WriteZeroesAt {
fn write_zeroes_at(&self, offset: u64, length: usize) -> io::Result<usize>;
fn write_zeroes_all_at(&self, mut offset: u64, mut length: usize) -> io::Result<()> {
while length > 0 {
match self.write_zeroes_at(offset, length) {
Ok(0) => return Err(Error::from(ErrorKind::WriteZero)),
Ok(bytes_written) => {
length = length
.checked_sub(bytes_written)
.ok_or_else(|| Error::from(ErrorKind::Other))?;
offset = offset
.checked_add(bytes_written as u64)
.ok_or_else(|| Error::from(ErrorKind::Other))?;
}
Err(e) => {
if e.kind() != ErrorKind::Interrupted {
return Err(e);
}
}
}
}
Ok(())
}
}
impl WriteZeroesAt for File {
fn write_zeroes_at(&self, offset: u64, length: usize) -> io::Result<usize> {
crate::platform::file_write_zeroes_at(self, offset, length)
}
}
#[cfg(test)]
mod tests {
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::io::Write;
use tempfile::tempfile;
use super::*;
#[test]
fn simple_test() {
let mut f = tempfile().unwrap();
let init_data = [0x00u8; 16384];
f.write_all(&init_data).unwrap();
let orig_data = [0x55u8; 5678];
f.seek(SeekFrom::Start(1234)).unwrap();
f.write_all(&orig_data).unwrap();
let mut readback = [0u8; 16384];
f.seek(SeekFrom::Start(0)).unwrap();
f.read_exact(&mut readback).unwrap();
for read in &readback[0..1234] {
assert_eq!(*read, 0);
}
for read in &readback[1234..(1234 + 5678)] {
assert_eq!(*read, 0x55);
}
for read in &readback[(1234 + 5678)..] {
assert_eq!(*read, 0);
}
f.write_zeroes_all_at(2345, 4321)
.expect("write_zeroes failed");
f.seek(SeekFrom::Start(0)).unwrap();
f.read_exact(&mut readback).unwrap();
for read in &readback[0..1234] {
assert_eq!(*read, 0);
}
for read in &readback[1234..2345] {
assert_eq!(*read, 0x55);
}
for read in &readback[2345..(2345 + 4321)] {
assert_eq!(*read, 0);
}
for read in &readback[(2345 + 4321)..(1234 + 5678)] {
assert_eq!(*read, 0x55);
}
for read in &readback[(1234 + 5678)..] {
assert_eq!(*read, 0);
}
}
#[test]
fn large_write_zeroes() {
let mut f = tempfile().unwrap();
let init_data = [0x00u8; 16384];
f.write_all(&init_data).unwrap();
let orig_data = [0x55u8; 0x20000];
f.seek(SeekFrom::Start(0)).unwrap();
f.write_all(&orig_data).unwrap();
f.write_zeroes_all_at(0, 0x10001)
.expect("write_zeroes failed");
let mut readback = [0u8; 0x20000];
f.seek(SeekFrom::Start(0)).unwrap();
f.read_exact(&mut readback).unwrap();
for read in &readback[0..0x10001] {
assert_eq!(*read, 0);
}
for read in &readback[0x10001..0x20000] {
assert_eq!(*read, 0x55);
}
}
}