• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, RawFd};
8 
9 use data_model::VolatileSlice;
10 
11 use crate::{fallocate, FallocateMode};
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 for getting the size of a file.
45 /// This is equivalent to File's metadata().len() method,
46 /// but wrapped in a trait so that it can be implemented for
47 /// other types.
48 pub trait FileGetLen {
49     /// Get the current length of the file in bytes.
get_len(&self) -> Result<u64>50     fn get_len(&self) -> Result<u64>;
51 }
52 
53 impl FileGetLen for File {
get_len(&self) -> Result<u64>54     fn get_len(&self) -> Result<u64> {
55         Ok(self.metadata()?.len())
56     }
57 }
58 
59 /// A trait for allocating disk space in a sparse file.
60 /// This is equivalent to fallocate() with no special flags.
61 pub trait FileAllocate {
62     /// Allocate storage for the region of the file starting at `offset` and extending `len` bytes.
allocate(&mut self, offset: u64, len: u64) -> Result<()>63     fn allocate(&mut self, offset: u64, len: u64) -> Result<()>;
64 }
65 
66 impl FileAllocate for File {
allocate(&mut self, offset: u64, len: u64) -> Result<()>67     fn allocate(&mut self, offset: u64, len: u64) -> Result<()> {
68         fallocate(self, FallocateMode::Allocate, true, offset, len)
69             .map_err(|e| Error::from_raw_os_error(e.errno()))
70     }
71 }
72 
73 /// A trait similar to `Read` and `Write`, but uses volatile memory as buffers.
74 pub trait FileReadWriteVolatile {
75     /// Read bytes from this file into the given slice, returning the number of bytes read on
76     /// success.
read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>77     fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
78 
79     /// Like `read_volatile`, except it reads to a slice of buffers. Data is copied to fill each
80     /// buffer in order, with the final buffer written to possibly being only partially filled. This
81     /// method must behave as a single call to `read_volatile` with the buffers concatenated would.
82     /// The default implementation calls `read_volatile` with either the first nonempty buffer
83     /// provided, or returns `Ok(0)` if none exists.
read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>84     fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
85         bufs.iter()
86             .find(|b| b.size() > 0)
87             .map(|&b| self.read_volatile(b))
88             .unwrap_or(Ok(0))
89     }
90 
91     /// Reads bytes from this into the given slice until all bytes in the slice are written, or an
92     /// error is returned.
read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()>93     fn read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
94         while slice.size() > 0 {
95             let bytes_read = self.read_volatile(slice)?;
96             if bytes_read == 0 {
97                 return Err(Error::from(ErrorKind::UnexpectedEof));
98             }
99             // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
100             // a panic.
101             slice = slice.offset(bytes_read).unwrap();
102         }
103         Ok(())
104     }
105 
106     /// Write bytes from the slice to the given file, returning the number of bytes written on
107     /// success.
write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>108     fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
109 
110     /// Like `write_volatile`, except that it writes from a slice of buffers. Data is copied from
111     /// each buffer in order, with the final buffer read from possibly being only partially
112     /// consumed. This method must behave as a call to `write_volatile` with the buffers
113     /// concatenated would. The default implementation calls `write_volatile` with either the first
114     /// nonempty buffer provided, or returns `Ok(0)` if none exists.
write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>115     fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
116         bufs.iter()
117             .find(|b| b.size() > 0)
118             .map(|&b| self.write_volatile(b))
119             .unwrap_or(Ok(0))
120     }
121 
122     /// Write bytes from the slice to the given file until all the bytes from the slice have been
123     /// written, or an error is returned.
write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()>124     fn write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
125         while slice.size() > 0 {
126             let bytes_written = self.write_volatile(slice)?;
127             if bytes_written == 0 {
128                 return Err(Error::from(ErrorKind::WriteZero));
129             }
130             // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
131             // a panic.
132             slice = slice.offset(bytes_written).unwrap();
133         }
134         Ok(())
135     }
136 }
137 
138 impl<'a, T: FileReadWriteVolatile + ?Sized> FileReadWriteVolatile for &'a mut T {
read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>139     fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
140         (**self).read_volatile(slice)
141     }
142 
read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>143     fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
144         (**self).read_vectored_volatile(bufs)
145     }
146 
read_exact_volatile(&mut self, slice: VolatileSlice) -> Result<()>147     fn read_exact_volatile(&mut self, slice: VolatileSlice) -> Result<()> {
148         (**self).read_exact_volatile(slice)
149     }
150 
write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>151     fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
152         (**self).write_volatile(slice)
153     }
154 
write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>155     fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
156         (**self).write_vectored_volatile(bufs)
157     }
158 
write_all_volatile(&mut self, slice: VolatileSlice) -> Result<()>159     fn write_all_volatile(&mut self, slice: VolatileSlice) -> Result<()> {
160         (**self).write_all_volatile(slice)
161     }
162 }
163 
164 /// A trait similar to the unix `ReadExt` and `WriteExt` traits, but for volatile memory.
165 pub trait FileReadWriteAtVolatile {
166     /// Reads bytes from this file at `offset` into the given slice, returning the number of bytes
167     /// read on success.
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.
read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>175     fn read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
176         if let Some(&slice) = bufs.first() {
177             self.read_at_volatile(slice, offset)
178         } else {
179             Ok(0)
180         }
181     }
182 
183     /// Reads bytes from this file at `offset` into the given slice until all bytes in the slice are
184     /// read, or an error is returned.
read_exact_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>185     fn read_exact_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> {
186         while slice.size() > 0 {
187             match self.read_at_volatile(slice, offset) {
188                 Ok(0) => return Err(Error::from(ErrorKind::UnexpectedEof)),
189                 Ok(n) => {
190                     slice = slice.offset(n).unwrap();
191                     offset = offset.checked_add(n as u64).unwrap();
192                 }
193                 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
194                 Err(e) => return Err(e),
195             }
196         }
197         Ok(())
198     }
199 
200     /// Writes bytes from this file at `offset` into the given slice, returning the number of bytes
201     /// written on success.
write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>202     fn write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>;
203 
204     /// Like `write_at_at_volatile`, except that it writes from a slice of buffers. Data is copied
205     /// from each buffer in order, with the final buffer read from possibly being only partially
206     /// consumed. This method must behave as a call to `write_at_volatile` with the buffers
207     /// concatenated would. The default implementation calls `write_at_volatile` with either the
208     /// first nonempty buffer provided, or returns `Ok(0)` if none exists.
write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>209     fn write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
210         if let Some(&slice) = bufs.first() {
211             self.write_at_volatile(slice, offset)
212         } else {
213             Ok(0)
214         }
215     }
216 
217     /// Writes bytes from this file at `offset` into the given slice until all bytes in the slice
218     /// are written, or an error is returned.
write_all_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>219     fn write_all_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> {
220         while slice.size() > 0 {
221             match self.write_at_volatile(slice, offset) {
222                 Ok(0) => return Err(Error::from(ErrorKind::WriteZero)),
223                 Ok(n) => {
224                     slice = slice.offset(n).unwrap();
225                     offset = offset.checked_add(n as u64).unwrap();
226                 }
227                 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
228                 Err(e) => return Err(e),
229             }
230         }
231         Ok(())
232     }
233 }
234 
235 impl<'a, T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &'a mut T {
read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>236     fn read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize> {
237         (**self).read_at_volatile(slice, offset)
238     }
239 
read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>240     fn read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
241         (**self).read_vectored_at_volatile(bufs, offset)
242     }
243 
read_exact_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()>244     fn read_exact_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()> {
245         (**self).read_exact_at_volatile(slice, offset)
246     }
247 
write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>248     fn write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize> {
249         (**self).write_at_volatile(slice, offset)
250     }
251 
write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>252     fn write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
253         (**self).write_vectored_at_volatile(bufs, offset)
254     }
255 
write_all_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()>256     fn write_all_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()> {
257         (**self).write_all_at_volatile(slice, offset)
258     }
259 }
260 
261 // This module allows the below macros to refer to $crate::file_traits::lib::X and ensures other
262 // crates don't need to add additional crates to their Cargo.toml.
263 pub mod lib {
264     pub use libc::{
265         c_int, c_void, iovec, off64_t, pread64, preadv64, pwrite64, pwritev64, read, readv, size_t,
266         write, writev,
267     };
268 
269     pub use data_model::VolatileSlice;
270 }
271 
272 #[macro_export]
273 macro_rules! volatile_impl {
274     ($ty:ty) => {
275         impl FileReadWriteVolatile for $ty {
276             fn read_volatile(
277                 &mut self,
278                 slice: $crate::file_traits::lib::VolatileSlice,
279             ) -> std::io::Result<usize> {
280                 // Safe because only bytes inside the slice are accessed and the kernel is expected
281                 // to handle arbitrary memory for I/O.
282                 let ret = unsafe {
283                     $crate::file_traits::lib::read(
284                         self.as_raw_fd(),
285                         slice.as_mut_ptr() as *mut std::ffi::c_void,
286                         slice.size() as usize,
287                     )
288                 };
289                 if ret >= 0 {
290                     Ok(ret as usize)
291                 } else {
292                     Err(std::io::Error::last_os_error())
293                 }
294             }
295 
296             fn read_vectored_volatile(
297                 &mut self,
298                 bufs: &[$crate::file_traits::lib::VolatileSlice],
299             ) -> std::io::Result<usize> {
300                 let iovecs = $crate::file_traits::lib::VolatileSlice::as_iobufs(bufs);
301 
302                 if iovecs.is_empty() {
303                     return Ok(0);
304                 }
305 
306                 // Safe because only bytes inside the buffers are accessed and the kernel is
307                 // expected to handle arbitrary memory for I/O.
308                 let ret = unsafe {
309                     $crate::file_traits::lib::readv(
310                         self.as_raw_fd(),
311                         iovecs.as_ptr(),
312                         iovecs.len() as std::os::raw::c_int,
313                     )
314                 };
315                 if ret >= 0 {
316                     Ok(ret as usize)
317                 } else {
318                     Err(std::io::Error::last_os_error())
319                 }
320             }
321 
322             fn write_volatile(
323                 &mut self,
324                 slice: $crate::file_traits::lib::VolatileSlice,
325             ) -> std::io::Result<usize> {
326                 // Safe because only bytes inside the slice are accessed and the kernel is expected
327                 // to handle arbitrary memory for I/O.
328                 let ret = unsafe {
329                     $crate::file_traits::lib::write(
330                         self.as_raw_fd(),
331                         slice.as_ptr() as *const std::ffi::c_void,
332                         slice.size() as usize,
333                     )
334                 };
335                 if ret >= 0 {
336                     Ok(ret as usize)
337                 } else {
338                     Err(std::io::Error::last_os_error())
339                 }
340             }
341 
342             fn write_vectored_volatile(
343                 &mut self,
344                 bufs: &[$crate::file_traits::lib::VolatileSlice],
345             ) -> std::io::Result<usize> {
346                 let iovecs = $crate::file_traits::lib::VolatileSlice::as_iobufs(bufs);
347 
348                 if iovecs.is_empty() {
349                     return Ok(0);
350                 }
351 
352                 // Safe because only bytes inside the buffers are accessed and the kernel is
353                 // expected to handle arbitrary memory for I/O.
354                 let ret = unsafe {
355                     $crate::file_traits::lib::writev(
356                         self.as_raw_fd(),
357                         iovecs.as_ptr(),
358                         iovecs.len() as std::os::raw::c_int,
359                     )
360                 };
361                 if ret >= 0 {
362                     Ok(ret as usize)
363                 } else {
364                     Err(std::io::Error::last_os_error())
365                 }
366             }
367         }
368     };
369 }
370 
371 #[macro_export]
372 macro_rules! volatile_at_impl {
373     ($ty:ty) => {
374         impl FileReadWriteAtVolatile for $ty {
375             fn read_at_volatile(
376                 &mut self,
377                 slice: $crate::file_traits::lib::VolatileSlice,
378                 offset: u64,
379             ) -> std::io::Result<usize> {
380                 // Safe because only bytes inside the slice are accessed and the kernel is expected
381                 // to handle arbitrary memory for I/O.
382                 let ret = unsafe {
383                     $crate::file_traits::lib::pread64(
384                         self.as_raw_fd(),
385                         slice.as_mut_ptr() as *mut std::ffi::c_void,
386                         slice.size() as usize,
387                         offset as $crate::file_traits::lib::off64_t,
388                     )
389                 };
390 
391                 if ret >= 0 {
392                     Ok(ret as usize)
393                 } else {
394                     Err(std::io::Error::last_os_error())
395                 }
396             }
397 
398             fn read_vectored_at_volatile(
399                 &mut self,
400                 bufs: &[$crate::file_traits::lib::VolatileSlice],
401                 offset: u64,
402             ) -> std::io::Result<usize> {
403                 let iovecs = $crate::file_traits::lib::VolatileSlice::as_iobufs(bufs);
404 
405                 if iovecs.is_empty() {
406                     return Ok(0);
407                 }
408 
409                 // Safe because only bytes inside the buffers are accessed and the kernel is
410                 // expected to handle arbitrary memory for I/O.
411                 let ret = unsafe {
412                     $crate::file_traits::lib::preadv64(
413                         self.as_raw_fd(),
414                         iovecs.as_ptr(),
415                         iovecs.len() as std::os::raw::c_int,
416                         offset as $crate::file_traits::lib::off64_t,
417                     )
418                 };
419                 if ret >= 0 {
420                     Ok(ret as usize)
421                 } else {
422                     Err(std::io::Error::last_os_error())
423                 }
424             }
425 
426             fn write_at_volatile(
427                 &mut self,
428                 slice: $crate::file_traits::lib::VolatileSlice,
429                 offset: u64,
430             ) -> std::io::Result<usize> {
431                 // Safe because only bytes inside the slice are accessed and the kernel is expected
432                 // to handle arbitrary memory for I/O.
433                 let ret = unsafe {
434                     $crate::file_traits::lib::pwrite64(
435                         self.as_raw_fd(),
436                         slice.as_ptr() as *const std::ffi::c_void,
437                         slice.size() as usize,
438                         offset as $crate::file_traits::lib::off64_t,
439                     )
440                 };
441 
442                 if ret >= 0 {
443                     Ok(ret as usize)
444                 } else {
445                     Err(std::io::Error::last_os_error())
446                 }
447             }
448 
449             fn write_vectored_at_volatile(
450                 &mut self,
451                 bufs: &[$crate::file_traits::lib::VolatileSlice],
452                 offset: u64,
453             ) -> std::io::Result<usize> {
454                 let iovecs = $crate::file_traits::lib::VolatileSlice::as_iobufs(bufs);
455 
456                 if iovecs.is_empty() {
457                     return Ok(0);
458                 }
459 
460                 // Safe because only bytes inside the buffers are accessed and the kernel is
461                 // expected to handle arbitrary memory for I/O.
462                 let ret = unsafe {
463                     $crate::file_traits::lib::pwritev64(
464                         self.as_raw_fd(),
465                         iovecs.as_ptr(),
466                         iovecs.len() as std::os::raw::c_int,
467                         offset as $crate::file_traits::lib::off64_t,
468                     )
469                 };
470                 if ret >= 0 {
471                     Ok(ret as usize)
472                 } else {
473                     Err(std::io::Error::last_os_error())
474                 }
475             }
476         }
477     };
478 }
479 
480 volatile_impl!(File);
481 volatile_at_impl!(File);
482 
483 /// A trait similar to `AsRawFd` but supports an arbitrary number of file descriptors.
484 pub trait AsRawFds {
as_raw_fds(&self) -> Vec<RawFd>485     fn as_raw_fds(&self) -> Vec<RawFd>;
486 }
487 
488 impl<T> AsRawFds for T
489 where
490     T: AsRawFd,
491 {
as_raw_fds(&self) -> Vec<RawFd>492     fn as_raw_fds(&self) -> Vec<RawFd> {
493         vec![self.as_raw_fd()]
494     }
495 }
496