xref: /aosp_15_r20/external/crosvm/base/src/sys/unix/file_traits.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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