• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::fs::File;
6 use std::io::Error;
7 use std::io::ErrorKind;
8 use std::io::Result;
9 
10 use data_model::VolatileSlice;
11 
12 /// A trait for flushing the contents of a file to disk.
13 /// This is equivalent to File's `sync_all` method, but
14 /// wrapped in a trait so that it can be implemented for
15 /// other types.
16 pub trait FileSync {
17     // Flush buffers related to this file to disk.
fsync(&mut self) -> Result<()>18     fn fsync(&mut self) -> Result<()>;
19 }
20 
21 impl FileSync for File {
fsync(&mut self) -> Result<()>22     fn fsync(&mut self) -> Result<()> {
23         self.sync_all()
24     }
25 }
26 
27 /// A trait for setting the size of a file.
28 /// This is equivalent to File's `set_len` method, but
29 /// wrapped in a trait so that it can be implemented for
30 /// other types.
31 pub trait FileSetLen {
32     // Set the size of this file.
33     // This is the moral equivalent of `ftruncate()`.
set_len(&self, _len: u64) -> Result<()>34     fn set_len(&self, _len: u64) -> Result<()>;
35 }
36 
37 impl FileSetLen for File {
set_len(&self, len: u64) -> Result<()>38     fn set_len(&self, len: u64) -> Result<()> {
39         File::set_len(self, len)
40     }
41 }
42 
43 /// A trait for allocating disk space in a sparse file.
44 /// This is equivalent to fallocate() with no special flags.
45 pub trait FileAllocate {
46     /// Allocate storage for the region of the file starting at `offset` and extending `len` bytes.
allocate(&mut self, offset: u64, len: u64) -> Result<()>47     fn allocate(&mut self, offset: u64, len: u64) -> Result<()>;
48 }
49 
50 /// A trait for getting the size of a file.
51 /// This is equivalent to File's metadata().len() method,
52 /// but wrapped in a trait so that it can be implemented for
53 /// other types.
54 pub trait FileGetLen {
55     /// Get the current length of the file in bytes.
get_len(&self) -> Result<u64>56     fn get_len(&self) -> Result<u64>;
57 }
58 
59 impl FileGetLen for File {
get_len(&self) -> Result<u64>60     fn get_len(&self) -> Result<u64> {
61         Ok(self.metadata()?.len())
62     }
63 }
64 
65 /// A trait similar to `Read` and `Write`, but uses volatile memory as buffers.
66 pub trait FileReadWriteVolatile {
67     /// Read bytes from this file into the given slice, returning the number of bytes read on
68     /// success.
read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>69     fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
70 
71     /// Like `read_volatile`, except it reads to a slice of buffers. Data is copied to fill each
72     /// buffer in order, with the final buffer written to possibly being only partially filled. This
73     /// method must behave as a single call to `read_volatile` with the buffers concatenated would.
74     /// The default implementation calls `read_volatile` with either the first nonempty buffer
75     /// provided, or returns `Ok(0)` if none exists.
read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>76     fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
77         bufs.iter()
78             .find(|b| b.size() > 0)
79             .map(|&b| self.read_volatile(b))
80             .unwrap_or(Ok(0))
81     }
82 
83     /// Reads bytes from this into the given slice until all bytes in the slice are written, or an
84     /// error is returned.
read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()>85     fn read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
86         while slice.size() > 0 {
87             let bytes_read = self.read_volatile(slice)?;
88             if bytes_read == 0 {
89                 return Err(Error::from(ErrorKind::UnexpectedEof));
90             }
91             // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
92             // a panic.
93             slice = slice.offset(bytes_read).unwrap();
94         }
95         Ok(())
96     }
97 
98     /// Write bytes from the slice to the given file, returning the number of bytes written on
99     /// success.
write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>100     fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
101 
102     /// Like `write_volatile`, except that it writes from a slice of buffers. Data is copied from
103     /// each buffer in order, with the final buffer read from possibly being only partially
104     /// consumed. This method must behave as a call to `write_volatile` with the buffers
105     /// concatenated would. The default implementation calls `write_volatile` with either the first
106     /// nonempty buffer provided, or returns `Ok(0)` if none exists.
write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>107     fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
108         bufs.iter()
109             .find(|b| b.size() > 0)
110             .map(|&b| self.write_volatile(b))
111             .unwrap_or(Ok(0))
112     }
113 
114     /// Write bytes from the slice to the given file until all the bytes from the slice have been
115     /// written, or an error is returned.
write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()>116     fn write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
117         while slice.size() > 0 {
118             let bytes_written = self.write_volatile(slice)?;
119             if bytes_written == 0 {
120                 return Err(Error::from(ErrorKind::WriteZero));
121             }
122             // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
123             // a panic.
124             slice = slice.offset(bytes_written).unwrap();
125         }
126         Ok(())
127     }
128 }
129 
130 impl<'a, T: FileReadWriteVolatile + ?Sized> FileReadWriteVolatile for &'a mut T {
read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>131     fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
132         (**self).read_volatile(slice)
133     }
134 
read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>135     fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
136         (**self).read_vectored_volatile(bufs)
137     }
138 
read_exact_volatile(&mut self, slice: VolatileSlice) -> Result<()>139     fn read_exact_volatile(&mut self, slice: VolatileSlice) -> Result<()> {
140         (**self).read_exact_volatile(slice)
141     }
142 
write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>143     fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
144         (**self).write_volatile(slice)
145     }
146 
write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>147     fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
148         (**self).write_vectored_volatile(bufs)
149     }
150 
write_all_volatile(&mut self, slice: VolatileSlice) -> Result<()>151     fn write_all_volatile(&mut self, slice: VolatileSlice) -> Result<()> {
152         (**self).write_all_volatile(slice)
153     }
154 }
155 
156 /// A trait similar to the unix `ReadExt` and `WriteExt` traits, but for volatile memory.
157 pub trait FileReadWriteAtVolatile {
158     /// Reads bytes from this file at `offset` into the given slice, returning the number of bytes
159     /// read on success. On Windows file pointer will update with the read, but on Linux the
160     /// file pointer will not change.
read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>161     fn read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>;
162 
163     /// Like `read_at_volatile`, except it reads to a slice of buffers. Data is copied to fill each
164     /// buffer in order, with the final buffer written to possibly being only partially filled. This
165     /// method must behave as a single call to `read_at_volatile` with the buffers concatenated
166     /// would. The default implementation calls `read_at_volatile` with either the first nonempty
167     /// buffer provided, or returns `Ok(0)` if none exists.
168     /// On Windows file pointer will update with the read, but on Linux the file pointer will not change.
read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>169     fn read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
170         if let Some(&slice) = bufs.first() {
171             self.read_at_volatile(slice, offset)
172         } else {
173             Ok(0)
174         }
175     }
176 
177     /// Reads bytes from this file at `offset` into the given slice until all bytes in the slice are
178     /// read, or an error is returned. On Windows file pointer will update with the read, but on Linux the
179     /// file pointer will not change.
read_exact_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>180     fn read_exact_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> {
181         while slice.size() > 0 {
182             match self.read_at_volatile(slice, offset) {
183                 Ok(0) => return Err(Error::from(ErrorKind::UnexpectedEof)),
184                 Ok(n) => {
185                     slice = slice.offset(n).unwrap();
186                     offset = offset.checked_add(n as u64).unwrap();
187                 }
188                 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
189                 Err(e) => return Err(e),
190             }
191         }
192         Ok(())
193     }
194 
195     /// Writes bytes to this file at `offset` from the given slice, returning the number of bytes
196     /// written on success. On Windows file pointer will update with the write, but on Linux the
197     /// file pointer will not change.
write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>198     fn write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>;
199 
200     /// Like `write_at_volatile`, except that it writes from a slice of buffers. Data is copied
201     /// from each buffer in order, with the final buffer read from possibly being only partially
202     /// consumed. This method must behave as a call to `write_at_volatile` with the buffers
203     /// concatenated would. The default implementation calls `write_at_volatile` with either the
204     /// first nonempty buffer provided, or returns `Ok(0)` if none exists.
205     /// On Windows file pointer will update with the write, but on Linux the file pointer will not change.
write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>206     fn write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
207         if let Some(&slice) = bufs.first() {
208             self.write_at_volatile(slice, offset)
209         } else {
210             Ok(0)
211         }
212     }
213 
214     /// Writes bytes to this file at `offset` from the given slice until all bytes in the slice
215     /// are written, or an error is returned. On Windows file pointer will update with the write,
216     /// but on Linux the file pointer will not change.
write_all_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>217     fn write_all_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> {
218         while slice.size() > 0 {
219             match self.write_at_volatile(slice, offset) {
220                 Ok(0) => return Err(Error::from(ErrorKind::WriteZero)),
221                 Ok(n) => {
222                     slice = slice.offset(n).unwrap();
223                     offset = offset.checked_add(n as u64).unwrap();
224                 }
225                 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
226                 Err(e) => return Err(e),
227             }
228         }
229         Ok(())
230     }
231 }
232 
233 impl<'a, T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &'a mut T {
read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>234     fn read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize> {
235         (**self).read_at_volatile(slice, offset)
236     }
237 
read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>238     fn read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
239         (**self).read_vectored_at_volatile(bufs, offset)
240     }
241 
read_exact_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()>242     fn read_exact_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()> {
243         (**self).read_exact_at_volatile(slice, offset)
244     }
245 
write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>246     fn write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize> {
247         (**self).write_at_volatile(slice, offset)
248     }
249 
write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>250     fn write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
251         (**self).write_vectored_at_volatile(bufs, offset)
252     }
253 
write_all_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()>254     fn write_all_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()> {
255         (**self).write_all_at_volatile(slice, offset)
256     }
257 }
258 
259 #[cfg(test)]
260 mod tests {
261     use std::io::Read;
262     use std::io::Seek;
263     use std::io::SeekFrom;
264     use std::io::Write;
265 
266     use tempfile::tempfile;
267 
268     use super::*;
269 
270     #[test]
read_file() -> Result<()>271     fn read_file() -> Result<()> {
272         let mut f = tempfile()?;
273         f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA")
274             .expect("Failed to write bytes");
275         f.seek(SeekFrom::Start(0))?;
276 
277         let mut omem = [0u8; 30];
278         let om = &mut omem[..];
279         let buf = VolatileSlice::new(om);
280         f.read_volatile(buf).expect("read_volatile failed.");
281 
282         f.seek(SeekFrom::Start(0))?;
283 
284         let mut mem = [0u8; 30];
285         let (m1, rest) = mem.split_at_mut(10);
286         let (m2, m3) = rest.split_at_mut(10);
287         let buf1 = VolatileSlice::new(m1);
288         let buf2 = VolatileSlice::new(m2);
289         let buf3 = VolatileSlice::new(m3);
290         let bufs = [buf1, buf2, buf3];
291 
292         f.read_vectored_volatile(&bufs)
293             .expect("read_vectored_volatile failed.");
294 
295         assert_eq!(&mem[..], b"AAAAAAAAAAbbbbbbbbbbAAAAA\0\0\0\0\0");
296         Ok(())
297     }
298 
299     #[test]
write_file() -> Result<()>300     fn write_file() -> Result<()> {
301         let mut f = tempfile()?;
302 
303         let mut omem = [0u8; 25];
304         let om = &mut omem[..];
305         let buf = VolatileSlice::new(om);
306         buf.write_bytes(65);
307         f.write_volatile(buf).expect("write_volatile failed.");
308 
309         f.seek(SeekFrom::Start(0))?;
310 
311         let mut filebuf = [0u8; 25];
312         f.read_exact(&mut filebuf).expect("Failed to read filebuf");
313         assert_eq!(&filebuf, b"AAAAAAAAAAAAAAAAAAAAAAAAA");
314         Ok(())
315     }
316 
317     #[test]
write_vectored_file() -> Result<()>318     fn write_vectored_file() -> Result<()> {
319         let mut f = tempfile()?;
320 
321         let mut mem = [0u8; 30];
322         let (m1, rest) = mem.split_at_mut(10);
323         let (m2, m3) = rest.split_at_mut(10);
324         let buf1 = VolatileSlice::new(m1);
325         let buf2 = VolatileSlice::new(m2);
326         let buf3 = VolatileSlice::new(m3);
327         buf1.write_bytes(65);
328         buf2.write_bytes(98);
329         buf3.write_bytes(65);
330         let bufs = [buf1, buf2, buf3];
331         f.write_vectored_volatile(&bufs)
332             .expect("write_vectored_volatile failed.");
333 
334         f.seek(SeekFrom::Start(0))?;
335 
336         let mut filebuf = [0u8; 30];
337         f.read_exact(&mut filebuf).expect("Failed to read filebuf.");
338         assert_eq!(&filebuf, b"AAAAAAAAAAbbbbbbbbbbAAAAAAAAAA");
339         Ok(())
340     }
341 
342     #[test]
read_at_file() -> Result<()>343     fn read_at_file() -> Result<()> {
344         let mut f = tempfile()?;
345         f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA")
346             .expect("Failed to write bytes.");
347 
348         let mut omem = [0u8; 20];
349         let om = &mut omem[..];
350         let buf = VolatileSlice::new(om);
351         f.read_at_volatile(buf, 10)
352             .expect("read_at_volatile failed.");
353 
354         assert_eq!(om, b"bbbbbbbbbbAAAAA\0\0\0\0\0");
355 
356         let mut mem = [0u8; 20];
357         let (m1, m2) = mem.split_at_mut(10);
358         let buf1 = VolatileSlice::new(m1);
359         let buf2 = VolatileSlice::new(m2);
360         let bufs = [buf1, buf2];
361 
362         f.read_vectored_at_volatile(&bufs, 10)
363             .expect("read_vectored_at_volatile failed.");
364 
365         assert_eq!(&mem[..], b"bbbbbbbbbbAAAAA\0\0\0\0\0");
366         Ok(())
367     }
368 
369     #[test]
write_at_file() -> Result<()>370     fn write_at_file() -> Result<()> {
371         let mut f = tempfile()?;
372         f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ")
373             .expect("Failed to write bytes");
374 
375         let mut omem = [0u8; 15];
376         let om = &mut omem[..];
377         let buf = VolatileSlice::new(om);
378         buf.write_bytes(65);
379         f.write_at_volatile(buf, 10)
380             .expect("write_at_volatile failed.");
381 
382         f.seek(SeekFrom::Start(0))?;
383 
384         let mut filebuf = [0u8; 30];
385         f.read_exact(&mut filebuf).expect("Failed to read filebuf.");
386         assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAAAAAAZZZZZ");
387         Ok(())
388     }
389 
390     #[test]
write_vectored_at_file() -> Result<()>391     fn write_vectored_at_file() -> Result<()> {
392         let mut f = tempfile()?;
393         f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ")
394             .expect("Failed to write bytes");
395 
396         let mut mem = [0u8; 30];
397         let (m1, m2) = mem.split_at_mut(10);
398         let buf1 = VolatileSlice::new(m1);
399         let buf2 = VolatileSlice::new(m2);
400         buf1.write_bytes(65);
401         buf2.write_bytes(98);
402         let bufs = [buf1, buf2];
403         f.write_vectored_at_volatile(&bufs, 10)
404             .expect("write_vectored_at_volatile failed.");
405 
406         f.seek(SeekFrom::Start(0))?;
407 
408         let mut filebuf = [0u8; 30];
409         f.read_exact(&mut filebuf).expect("Failed to read filebuf.");
410         assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAbbbbbbbbbb");
411         Ok(())
412     }
413 }
414