base/
file_traits.rs

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
5use std::fs::File;
6use std::io::Error;
7use std::io::ErrorKind;
8use std::io::Result;
9
10use 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.
15pub trait FileSync {
16    // Flush buffers related to this file to disk.
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.
21    fn fdatasync(&self) -> Result<()>;
22}
23
24impl FileSync for File {
25    fn fsync(&self) -> Result<()> {
26        self.sync_all()
27    }
28
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.
38pub trait FileSetLen {
39    // Set the size of this file.
40    // This is the moral equivalent of `ftruncate()`.
41    fn set_len(&self, _len: u64) -> Result<()>;
42}
43
44impl FileSetLen for File {
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.
52pub trait FileAllocate {
53    /// Allocate storage for the region of the file starting at `offset` and extending `len` bytes.
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.
61pub trait FileGetLen {
62    /// Get the current length of the file in bytes.
63    fn get_len(&self) -> Result<u64>;
64}
65
66impl FileGetLen for File {
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.
73pub trait FileReadWriteVolatile {
74    /// Read bytes from this file into the given slice, returning the number of bytes read on
75    /// success.
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.
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.
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.
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.
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.
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
137impl<T: FileReadWriteVolatile + ?Sized> FileReadWriteVolatile for &mut T {
138    fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
139        (**self).read_volatile(slice)
140    }
141
142    fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
143        (**self).read_vectored_volatile(bufs)
144    }
145
146    fn read_exact_volatile(&mut self, slice: VolatileSlice) -> Result<()> {
147        (**self).read_exact_volatile(slice)
148    }
149
150    fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
151        (**self).write_volatile(slice)
152    }
153
154    fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
155        (**self).write_vectored_volatile(bufs)
156    }
157
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.
164pub 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.
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.
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.
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.
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.
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.
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
242impl<T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &mut T {
243    fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
244        (**self).read_at_volatile(slice, offset)
245    }
246
247    fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
248        (**self).read_vectored_at_volatile(bufs, offset)
249    }
250
251    fn read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
252        (**self).read_exact_at_volatile(slice, offset)
253    }
254
255    fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
256        (**self).write_at_volatile(slice, offset)
257    }
258
259    fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
260        (**self).write_vectored_at_volatile(bufs, offset)
261    }
262
263    fn write_all_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
264        (**self).write_all_at_volatile(slice, offset)
265    }
266}
267
268impl<T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &T {
269    fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
270        (**self).read_at_volatile(slice, offset)
271    }
272
273    fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
274        (**self).read_vectored_at_volatile(bufs, offset)
275    }
276
277    fn read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
278        (**self).read_exact_at_volatile(slice, offset)
279    }
280
281    fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
282        (**self).write_at_volatile(slice, offset)
283    }
284
285    fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
286        (**self).write_vectored_at_volatile(bufs, offset)
287    }
288
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)]
295mod 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]
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]
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]
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]
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]
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]
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}