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