1 // Copyright 2018 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 5 //! FileReadWriteAtVolatile is implemented in terms of `pread` and `pwrite`. These are provided by 6 //! platform-specific imports. On Linux they resolve to the 64-bit versions, while on MacOS the 7 //! base versions are already 64-bit. 8 9 use std::fs::File; 10 use std::os::unix::io::AsRawFd; 11 use std::os::unix::net::UnixStream; 12 13 use crate::FileReadWriteAtVolatile; 14 use crate::FileReadWriteVolatile; 15 16 // This module allows the below macros to refer to $crate::unix::file_traits::lib::X and ensures 17 // other crates don't need to add additional crates to their Cargo.toml. 18 pub mod lib { 19 pub use libc::c_int; 20 pub use libc::c_void; 21 pub use libc::iovec; 22 pub use libc::read; 23 pub use libc::readv; 24 pub use libc::size_t; 25 pub use libc::write; 26 pub use libc::writev; 27 } 28 29 #[macro_export] 30 macro_rules! volatile_impl { 31 ($ty:ty) => { 32 impl FileReadWriteVolatile for $ty { 33 fn read_volatile(&mut self, slice: $crate::VolatileSlice) -> std::io::Result<usize> { 34 // SAFETY: 35 // Safe because only bytes inside the slice are accessed and the kernel is expected 36 // to handle arbitrary memory for I/O. 37 let ret = unsafe { 38 $crate::unix::file_traits::lib::read( 39 self.as_raw_fd(), 40 slice.as_mut_ptr() as *mut std::ffi::c_void, 41 slice.size() as usize, 42 ) 43 }; 44 if ret >= 0 { 45 Ok(ret as usize) 46 } else { 47 Err(std::io::Error::last_os_error()) 48 } 49 } 50 51 fn read_vectored_volatile( 52 &mut self, 53 bufs: &[$crate::VolatileSlice], 54 ) -> std::io::Result<usize> { 55 let iobufs = $crate::VolatileSlice::as_iobufs(bufs); 56 let iovecs = $crate::IoBufMut::as_iobufs(iobufs); 57 58 if iovecs.is_empty() { 59 return Ok(0); 60 } 61 62 // SAFETY: 63 // Safe because only bytes inside the buffers are accessed and the kernel is 64 // expected to handle arbitrary memory for I/O. 65 let ret = unsafe { 66 $crate::unix::file_traits::lib::readv( 67 self.as_raw_fd(), 68 iovecs.as_ptr(), 69 iovecs.len() as std::os::raw::c_int, 70 ) 71 }; 72 if ret >= 0 { 73 Ok(ret as usize) 74 } else { 75 Err(std::io::Error::last_os_error()) 76 } 77 } 78 79 fn write_volatile(&mut self, slice: $crate::VolatileSlice) -> std::io::Result<usize> { 80 // SAFETY: 81 // Safe because only bytes inside the slice are accessed and the kernel is expected 82 // to handle arbitrary memory for I/O. 83 let ret = unsafe { 84 $crate::unix::file_traits::lib::write( 85 self.as_raw_fd(), 86 slice.as_ptr() as *const std::ffi::c_void, 87 slice.size() as usize, 88 ) 89 }; 90 if ret >= 0 { 91 Ok(ret as usize) 92 } else { 93 Err(std::io::Error::last_os_error()) 94 } 95 } 96 97 fn write_vectored_volatile( 98 &mut self, 99 bufs: &[$crate::VolatileSlice], 100 ) -> std::io::Result<usize> { 101 let iobufs = $crate::VolatileSlice::as_iobufs(bufs); 102 let iovecs = $crate::IoBufMut::as_iobufs(iobufs); 103 104 if iovecs.is_empty() { 105 return Ok(0); 106 } 107 108 // SAFETY: 109 // Safe because only bytes inside the buffers are accessed and the kernel is 110 // expected to handle arbitrary memory for I/O. 111 let ret = unsafe { 112 $crate::unix::file_traits::lib::writev( 113 self.as_raw_fd(), 114 iovecs.as_ptr(), 115 iovecs.len() as std::os::raw::c_int, 116 ) 117 }; 118 if ret >= 0 { 119 Ok(ret as usize) 120 } else { 121 Err(std::io::Error::last_os_error()) 122 } 123 } 124 } 125 }; 126 } 127 128 #[macro_export] 129 macro_rules! volatile_at_impl { 130 ($ty:ty) => { 131 impl FileReadWriteAtVolatile for $ty { 132 fn read_at_volatile( 133 &self, 134 slice: $crate::VolatileSlice, 135 offset: u64, 136 ) -> std::io::Result<usize> { 137 // SAFETY: 138 // Safe because only bytes inside the slice are accessed and the kernel is expected 139 // to handle arbitrary memory for I/O. 140 let ret = unsafe { 141 $crate::platform::pread( 142 self.as_raw_fd(), 143 slice.as_mut_ptr() as *mut std::ffi::c_void, 144 slice.size() as usize, 145 offset as $crate::platform::off_t, 146 ) 147 }; 148 149 if ret >= 0 { 150 Ok(ret as usize) 151 } else { 152 Err(std::io::Error::last_os_error()) 153 } 154 } 155 156 fn read_vectored_at_volatile( 157 &self, 158 bufs: &[$crate::VolatileSlice], 159 offset: u64, 160 ) -> std::io::Result<usize> { 161 let iobufs = $crate::VolatileSlice::as_iobufs(bufs); 162 let iovecs = $crate::IoBufMut::as_iobufs(iobufs); 163 164 if iovecs.is_empty() { 165 return Ok(0); 166 } 167 168 // SAFETY: 169 // Safe because only bytes inside the buffers are accessed and the kernel is 170 // expected to handle arbitrary memory for I/O. 171 let ret = unsafe { 172 $crate::platform::preadv( 173 self.as_raw_fd(), 174 iovecs.as_ptr(), 175 iovecs.len() as std::os::raw::c_int, 176 offset as $crate::platform::off_t, 177 ) 178 }; 179 if ret >= 0 { 180 Ok(ret as usize) 181 } else { 182 Err(std::io::Error::last_os_error()) 183 } 184 } 185 186 fn write_at_volatile( 187 &self, 188 slice: $crate::VolatileSlice, 189 offset: u64, 190 ) -> std::io::Result<usize> { 191 // SAFETY: 192 // Safe because only bytes inside the slice are accessed and the kernel is expected 193 // to handle arbitrary memory for I/O. 194 let ret = unsafe { 195 $crate::platform::pwrite( 196 self.as_raw_fd(), 197 slice.as_ptr() as *const std::ffi::c_void, 198 slice.size() as usize, 199 offset as $crate::platform::off_t, 200 ) 201 }; 202 203 if ret >= 0 { 204 Ok(ret as usize) 205 } else { 206 Err(std::io::Error::last_os_error()) 207 } 208 } 209 210 fn write_vectored_at_volatile( 211 &self, 212 bufs: &[$crate::VolatileSlice], 213 offset: u64, 214 ) -> std::io::Result<usize> { 215 let iobufs = $crate::VolatileSlice::as_iobufs(bufs); 216 let iovecs = $crate::IoBufMut::as_iobufs(iobufs); 217 218 if iovecs.is_empty() { 219 return Ok(0); 220 } 221 222 // SAFETY: 223 // Safe because only bytes inside the buffers are accessed and the kernel is 224 // expected to handle arbitrary memory for I/O. 225 let ret = unsafe { 226 $crate::platform::pwritev( 227 self.as_raw_fd(), 228 iovecs.as_ptr(), 229 iovecs.len() as std::os::raw::c_int, 230 offset as $crate::platform::off_t, 231 ) 232 }; 233 if ret >= 0 { 234 Ok(ret as usize) 235 } else { 236 Err(std::io::Error::last_os_error()) 237 } 238 } 239 } 240 }; 241 } 242 243 volatile_impl!(File); 244 volatile_at_impl!(File); 245 volatile_impl!(UnixStream); 246