xref: /aosp_15_r20/external/crosvm/base/src/file_traits.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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(&self) -> Result<()>17     fn fsync(&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(&self) -> Result<()>21     fn fdatasync(&self) -> Result<()>;
22 }
23 
24 impl FileSync for File {
fsync(&self) -> Result<()>25     fn fsync(&self) -> Result<()> {
26         self.sync_all()
27     }
28 
fdatasync(&self) -> Result<()>29     fn fdatasync(&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(&self, offset: u64, len: u64) -> Result<()>54     fn allocate(&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(&self, slice: VolatileSlice, offset: u64) -> Result<usize>168     fn read_at_volatile(&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(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>177     fn read_vectored_at_volatile(&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(&self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>188     fn read_exact_at_volatile(&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(&self, slice: VolatileSlice, offset: u64) -> Result<usize>206     fn write_at_volatile(&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(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>215     fn write_vectored_at_volatile(&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(&self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>226     fn write_all_at_volatile(&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(&self, slice: VolatileSlice, offset: u64) -> Result<usize>243     fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
244         (**self).read_at_volatile(slice, offset)
245     }
246 
read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>247     fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
248         (**self).read_vectored_at_volatile(bufs, offset)
249     }
250 
read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()>251     fn read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
252         (**self).read_exact_at_volatile(slice, offset)
253     }
254 
write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize>255     fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
256         (**self).write_at_volatile(slice, offset)
257     }
258 
write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>259     fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
260         (**self).write_vectored_at_volatile(bufs, offset)
261     }
262 
write_all_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()>263     fn write_all_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
264         (**self).write_all_at_volatile(slice, offset)
265     }
266 }
267 
268 impl<'a, T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &'a T {
read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize>269     fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
270         (**self).read_at_volatile(slice, offset)
271     }
272 
read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>273     fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
274         (**self).read_vectored_at_volatile(bufs, offset)
275     }
276 
read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()>277     fn read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
278         (**self).read_exact_at_volatile(slice, offset)
279     }
280 
write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize>281     fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
282         (**self).write_at_volatile(slice, offset)
283     }
284 
write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>285     fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
286         (**self).write_vectored_at_volatile(bufs, offset)
287     }
288 
write_all_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()>289     fn write_all_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
290         (**self).write_all_at_volatile(slice, offset)
291     }
292 }
293 
294 #[cfg(test)]
295 mod tests {
296     use std::io::Read;
297     use std::io::Seek;
298     use std::io::SeekFrom;
299     use std::io::Write;
300 
301     use tempfile::tempfile;
302 
303     use super::*;
304 
305     #[test]
read_file() -> Result<()>306     fn read_file() -> Result<()> {
307         let mut f = tempfile()?;
308         f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA")
309             .expect("Failed to write bytes");
310         f.seek(SeekFrom::Start(0))?;
311 
312         let mut omem = [0u8; 30];
313         let om = &mut omem[..];
314         let buf = VolatileSlice::new(om);
315         f.read_volatile(buf).expect("read_volatile failed.");
316 
317         f.seek(SeekFrom::Start(0))?;
318 
319         let mut mem = [0u8; 30];
320         let (m1, rest) = mem.split_at_mut(10);
321         let (m2, m3) = rest.split_at_mut(10);
322         let buf1 = VolatileSlice::new(m1);
323         let buf2 = VolatileSlice::new(m2);
324         let buf3 = VolatileSlice::new(m3);
325         let bufs = [buf1, buf2, buf3];
326 
327         f.read_vectored_volatile(&bufs)
328             .expect("read_vectored_volatile failed.");
329 
330         assert_eq!(&mem[..], b"AAAAAAAAAAbbbbbbbbbbAAAAA\0\0\0\0\0");
331         Ok(())
332     }
333 
334     #[test]
write_file() -> Result<()>335     fn write_file() -> Result<()> {
336         let mut f = tempfile()?;
337 
338         let mut omem = [0u8; 25];
339         let om = &mut omem[..];
340         let buf = VolatileSlice::new(om);
341         buf.write_bytes(65);
342         f.write_volatile(buf).expect("write_volatile failed.");
343 
344         f.seek(SeekFrom::Start(0))?;
345 
346         let mut filebuf = [0u8; 25];
347         f.read_exact(&mut filebuf).expect("Failed to read filebuf");
348         assert_eq!(&filebuf, b"AAAAAAAAAAAAAAAAAAAAAAAAA");
349         Ok(())
350     }
351 
352     #[test]
write_vectored_file() -> Result<()>353     fn write_vectored_file() -> Result<()> {
354         let mut f = tempfile()?;
355 
356         let mut mem = [0u8; 30];
357         let (m1, rest) = mem.split_at_mut(10);
358         let (m2, m3) = rest.split_at_mut(10);
359         let buf1 = VolatileSlice::new(m1);
360         let buf2 = VolatileSlice::new(m2);
361         let buf3 = VolatileSlice::new(m3);
362         buf1.write_bytes(65);
363         buf2.write_bytes(98);
364         buf3.write_bytes(65);
365         let bufs = [buf1, buf2, buf3];
366         f.write_vectored_volatile(&bufs)
367             .expect("write_vectored_volatile failed.");
368 
369         f.seek(SeekFrom::Start(0))?;
370 
371         let mut filebuf = [0u8; 30];
372         f.read_exact(&mut filebuf).expect("Failed to read filebuf.");
373         assert_eq!(&filebuf, b"AAAAAAAAAAbbbbbbbbbbAAAAAAAAAA");
374         Ok(())
375     }
376 
377     #[test]
read_at_file() -> Result<()>378     fn read_at_file() -> Result<()> {
379         let mut f = tempfile()?;
380         f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA")
381             .expect("Failed to write bytes.");
382 
383         let mut omem = [0u8; 20];
384         let om = &mut omem[..];
385         let buf = VolatileSlice::new(om);
386         f.read_at_volatile(buf, 10)
387             .expect("read_at_volatile failed.");
388 
389         assert_eq!(om, b"bbbbbbbbbbAAAAA\0\0\0\0\0");
390 
391         let mut mem = [0u8; 20];
392         let (m1, m2) = mem.split_at_mut(10);
393         let buf1 = VolatileSlice::new(m1);
394         let buf2 = VolatileSlice::new(m2);
395         let bufs = [buf1, buf2];
396 
397         f.read_vectored_at_volatile(&bufs, 10)
398             .expect("read_vectored_at_volatile failed.");
399 
400         assert_eq!(&mem[..], b"bbbbbbbbbbAAAAA\0\0\0\0\0");
401         Ok(())
402     }
403 
404     #[test]
write_at_file() -> Result<()>405     fn write_at_file() -> Result<()> {
406         let mut f = tempfile()?;
407         f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ")
408             .expect("Failed to write bytes");
409 
410         let mut omem = [0u8; 15];
411         let om = &mut omem[..];
412         let buf = VolatileSlice::new(om);
413         buf.write_bytes(65);
414         f.write_at_volatile(buf, 10)
415             .expect("write_at_volatile failed.");
416 
417         f.seek(SeekFrom::Start(0))?;
418 
419         let mut filebuf = [0u8; 30];
420         f.read_exact(&mut filebuf).expect("Failed to read filebuf.");
421         assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAAAAAAZZZZZ");
422         Ok(())
423     }
424 
425     #[test]
write_vectored_at_file() -> Result<()>426     fn write_vectored_at_file() -> Result<()> {
427         let mut f = tempfile()?;
428         f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ")
429             .expect("Failed to write bytes");
430 
431         let mut mem = [0u8; 30];
432         let (m1, m2) = mem.split_at_mut(10);
433         let buf1 = VolatileSlice::new(m1);
434         let buf2 = VolatileSlice::new(m2);
435         buf1.write_bytes(65);
436         buf2.write_bytes(98);
437         let bufs = [buf1, buf2];
438         f.write_vectored_at_volatile(&bufs, 10)
439             .expect("write_vectored_at_volatile failed.");
440 
441         f.seek(SeekFrom::Start(0))?;
442 
443         let mut filebuf = [0u8; 30];
444         f.read_exact(&mut filebuf).expect("Failed to read filebuf.");
445         assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAbbbbbbbbbb");
446         Ok(())
447     }
448 }
449