1 // Copyright 2018 The Chromium OS Authors. All rights reserved. 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, ErrorKind, Result}; 7 use std::os::unix::io::AsRawFd; 8 9 use data_model::VolatileSlice; 10 11 use libc::{c_void, read, write}; 12 13 /// A trait for flushing the contents of a file to disk. 14 /// This is equivalent to File's `sync_all` method, but 15 /// wrapped in a trait so that it can be implemented for 16 /// other types. 17 pub trait FileSync { 18 // Flush buffers related to this file to disk. fsync(&mut self) -> Result<()>19 fn fsync(&mut self) -> Result<()>; 20 } 21 22 impl FileSync for File { fsync(&mut self) -> Result<()>23 fn fsync(&mut self) -> Result<()> { 24 self.sync_all() 25 } 26 } 27 28 /// A trait for setting the size of a file. 29 /// This is equivalent to File's `set_len` method, but 30 /// wrapped in a trait so that it can be implemented for 31 /// other types. 32 pub trait FileSetLen { 33 // Set the size of this file. 34 // This is the moral equivalent of `ftruncate()`. set_len(&self, _len: u64) -> Result<()>35 fn set_len(&self, _len: u64) -> Result<()>; 36 } 37 38 impl FileSetLen for File { set_len(&self, len: u64) -> Result<()>39 fn set_len(&self, len: u64) -> Result<()> { 40 File::set_len(self, len) 41 } 42 } 43 44 /// A trait similar to `Read` and `Write`, but uses volatile memory as buffers. 45 pub trait FileReadWriteVolatile { 46 /// Read bytes from this file into the given slice, returning the number of bytes read on 47 /// success. read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>48 fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>; 49 50 /// Reads bytes from this into the given slice until all bytes in the slice are written, or an 51 /// error is returned. read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()>52 fn read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> { 53 while slice.size() > 0 { 54 let bytes_read = self.read_volatile(slice)?; 55 if bytes_read == 0 { 56 return Err(Error::from(ErrorKind::UnexpectedEof)); 57 } 58 // Will panic if read_volatile read more bytes than we gave it, which would be worthy of 59 // a panic. 60 slice = slice.offset(bytes_read as u64).unwrap(); 61 } 62 Ok(()) 63 } 64 65 /// Write bytes from the slice to the given file, returning the number of bytes written on 66 /// success. write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>67 fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>; 68 69 /// Write bytes from the slice to the given file until all the bytes from the slice have been 70 /// written, or an error is returned. write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()>71 fn write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> { 72 while slice.size() > 0 { 73 let bytes_written = self.write_volatile(slice)?; 74 if bytes_written == 0 { 75 return Err(Error::from(ErrorKind::WriteZero)); 76 } 77 // Will panic if read_volatile read more bytes than we gave it, which would be worthy of 78 // a panic. 79 slice = slice.offset(bytes_written as u64).unwrap(); 80 } 81 Ok(()) 82 } 83 } 84 85 impl FileReadWriteVolatile for File { read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>86 fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> { 87 // Safe because only bytes inside the slice are accessed and the kernel is expected to 88 // handle arbitrary memory for I/O. 89 let ret = unsafe { 90 read( 91 self.as_raw_fd(), 92 slice.as_ptr() as *mut c_void, 93 slice.size() as usize, 94 ) 95 }; 96 if ret >= 0 { 97 Ok(ret as usize) 98 } else { 99 Err(Error::last_os_error()) 100 } 101 } 102 write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>103 fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> { 104 // Safe because only bytes inside the slice are accessed and the kernel is expected to 105 // handle arbitrary memory for I/O. 106 let ret = unsafe { 107 write( 108 self.as_raw_fd(), 109 slice.as_ptr() as *const c_void, 110 slice.size() as usize, 111 ) 112 }; 113 if ret >= 0 { 114 Ok(ret as usize) 115 } else { 116 Err(Error::last_os_error()) 117 } 118 } 119 } 120