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);