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