1use std::fs::File;
6use std::io;
7use std::io::Error;
8use std::io::ErrorKind;
9
10pub trait PunchHole {
12 fn punch_hole(&self, offset: u64, length: u64) -> io::Result<()>;
14}
15
16impl PunchHole for File {
17 fn punch_hole(&self, offset: u64, length: u64) -> io::Result<()> {
18 crate::platform::file_punch_hole(self, offset, length)
19 }
20}
21
22pub trait WriteZeroesAt {
24 fn write_zeroes_at(&self, offset: u64, length: usize) -> io::Result<usize>;
27
28 fn write_zeroes_all_at(&self, mut offset: u64, mut length: usize) -> io::Result<()> {
33 while length > 0 {
34 match self.write_zeroes_at(offset, length) {
35 Ok(0) => return Err(Error::from(ErrorKind::WriteZero)),
36 Ok(bytes_written) => {
37 length = length
38 .checked_sub(bytes_written)
39 .ok_or_else(|| Error::from(ErrorKind::Other))?;
40 offset = offset
41 .checked_add(bytes_written as u64)
42 .ok_or_else(|| Error::from(ErrorKind::Other))?;
43 }
44 Err(e) => {
45 if e.kind() != ErrorKind::Interrupted {
46 return Err(e);
47 }
48 }
49 }
50 }
51 Ok(())
52 }
53}
54
55impl WriteZeroesAt for File {
56 fn write_zeroes_at(&self, offset: u64, length: usize) -> io::Result<usize> {
57 crate::platform::file_write_zeroes_at(self, offset, length)
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use std::io::Read;
64 use std::io::Seek;
65 use std::io::SeekFrom;
66 use std::io::Write;
67
68 use tempfile::tempfile;
69
70 use super::*;
71
72 #[test]
73 fn simple_test() {
74 let mut f = tempfile().unwrap();
75
76 let init_data = [0x00u8; 16384];
79 f.write_all(&init_data).unwrap();
80
81 let orig_data = [0x55u8; 5678];
83 f.seek(SeekFrom::Start(1234)).unwrap();
84 f.write_all(&orig_data).unwrap();
85
86 let mut readback = [0u8; 16384];
88 f.seek(SeekFrom::Start(0)).unwrap();
89 f.read_exact(&mut readback).unwrap();
90 for read in &readback[0..1234] {
92 assert_eq!(*read, 0);
93 }
94 for read in &readback[1234..(1234 + 5678)] {
96 assert_eq!(*read, 0x55);
97 }
98 for read in &readback[(1234 + 5678)..] {
100 assert_eq!(*read, 0);
101 }
102
103 f.write_zeroes_all_at(2345, 4321)
105 .expect("write_zeroes failed");
106
107 f.seek(SeekFrom::Start(0)).unwrap();
109 f.read_exact(&mut readback).unwrap();
110 for read in &readback[0..1234] {
112 assert_eq!(*read, 0);
113 }
114 for read in &readback[1234..2345] {
116 assert_eq!(*read, 0x55);
117 }
118 for read in &readback[2345..(2345 + 4321)] {
120 assert_eq!(*read, 0);
121 }
122 for read in &readback[(2345 + 4321)..(1234 + 5678)] {
124 assert_eq!(*read, 0x55);
125 }
126 for read in &readback[(1234 + 5678)..] {
128 assert_eq!(*read, 0);
129 }
130 }
131
132 #[test]
133 fn large_write_zeroes() {
134 let mut f = tempfile().unwrap();
135
136 let init_data = [0x00u8; 16384];
139 f.write_all(&init_data).unwrap();
140
141 let orig_data = [0x55u8; 0x20000];
143 f.seek(SeekFrom::Start(0)).unwrap();
144 f.write_all(&orig_data).unwrap();
145
146 f.write_zeroes_all_at(0, 0x10001)
148 .expect("write_zeroes failed");
149
150 let mut readback = [0u8; 0x20000];
152 f.seek(SeekFrom::Start(0)).unwrap();
153 f.read_exact(&mut readback).unwrap();
154 for read in &readback[0..0x10001] {
156 assert_eq!(*read, 0);
157 }
158 for read in &readback[0x10001..0x20000] {
160 assert_eq!(*read, 0x55);
161 }
162 }
163}