base/sys/unix/file_traits.rs
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
9use std::fs::File;
10use std::os::unix::io::AsRawFd;
11use std::os::unix::net::UnixStream;
12
13use crate::FileReadWriteAtVolatile;
14use 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.
18pub 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]
30macro_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]
129macro_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
243volatile_impl!(File);
244volatile_at_impl!(File);
245volatile_impl!(UnixStream);