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