]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | #![unstable(reason = "not public", issue = "none", feature = "fd")] |
54a0048b | 2 | |
1b1a35ee XL |
3 | #[cfg(test)] |
4 | mod tests; | |
5 | ||
532ac7d7 | 6 | use crate::cmp; |
a2a8927a | 7 | use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf}; |
94222f64 | 8 | use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; |
532ac7d7 | 9 | use crate::sys::cvt; |
94222f64 | 10 | use crate::sys_common::{AsInner, FromInner, IntoInner}; |
532ac7d7 | 11 | |
3dfed10e | 12 | use libc::{c_int, c_void}; |
85aaf69f | 13 | |
32a655c1 | 14 | #[derive(Debug)] |
94222f64 | 15 | pub struct FileDesc(OwnedFd); |
85aaf69f | 16 | |
3dfed10e XL |
17 | // The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, |
18 | // with the man page quoting that if the count of bytes to read is | |
19 | // greater than `SSIZE_MAX` the result is "unspecified". | |
20 | // | |
21 | // On macOS, however, apparently the 64-bit libc is either buggy or | |
22 | // intentionally showing odd behavior by rejecting any read with a size | |
23 | // larger than or equal to INT_MAX. To handle both of these the read | |
24 | // size is capped on both platforms. | |
25 | #[cfg(target_os = "macos")] | |
26 | const READ_LIMIT: usize = c_int::MAX as usize - 1; | |
27 | #[cfg(not(target_os = "macos"))] | |
28 | const READ_LIMIT: usize = libc::ssize_t::MAX as usize; | |
29 | ||
1b1a35ee XL |
30 | #[cfg(any( |
31 | target_os = "dragonfly", | |
32 | target_os = "freebsd", | |
33 | target_os = "ios", | |
34 | target_os = "macos", | |
35 | target_os = "netbsd", | |
36 | target_os = "openbsd", | |
37 | ))] | |
38 | const fn max_iov() -> usize { | |
39 | libc::IOV_MAX as usize | |
40 | } | |
3dfed10e | 41 | |
1b1a35ee XL |
42 | #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] |
43 | const fn max_iov() -> usize { | |
44 | libc::UIO_MAXIOV as usize | |
3dfed10e XL |
45 | } |
46 | ||
1b1a35ee XL |
47 | #[cfg(not(any( |
48 | target_os = "android", | |
49 | target_os = "dragonfly", | |
50 | target_os = "emscripten", | |
51 | target_os = "freebsd", | |
52 | target_os = "ios", | |
53 | target_os = "linux", | |
54 | target_os = "macos", | |
55 | target_os = "netbsd", | |
56 | target_os = "openbsd", | |
57 | )))] | |
58 | const fn max_iov() -> usize { | |
3dfed10e | 59 | 16 // The minimum value required by POSIX. |
32a655c1 SL |
60 | } |
61 | ||
85aaf69f | 62 | impl FileDesc { |
85aaf69f | 63 | pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
54a0048b | 64 | let ret = cvt(unsafe { |
94222f64 XL |
65 | libc::read( |
66 | self.as_raw_fd(), | |
67 | buf.as_mut_ptr() as *mut c_void, | |
68 | cmp::min(buf.len(), READ_LIMIT), | |
69 | ) | |
54a0048b | 70 | })?; |
85aaf69f SL |
71 | Ok(ret as usize) |
72 | } | |
73 | ||
94222f64 | 74 | #[cfg(not(target_os = "espidf"))] |
48663c56 | 75 | pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
9fa01778 | 76 | let ret = cvt(unsafe { |
60c5eb7d | 77 | libc::readv( |
94222f64 | 78 | self.as_raw_fd(), |
60c5eb7d | 79 | bufs.as_ptr() as *const libc::iovec, |
3dfed10e | 80 | cmp::min(bufs.len(), max_iov()) as c_int, |
60c5eb7d | 81 | ) |
9fa01778 XL |
82 | })?; |
83 | Ok(ret as usize) | |
84 | } | |
85 | ||
94222f64 XL |
86 | #[cfg(target_os = "espidf")] |
87 | pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { | |
88 | return crate::io::default_read_vectored(|b| self.read(b), bufs); | |
89 | } | |
90 | ||
f9f354fc XL |
91 | #[inline] |
92 | pub fn is_read_vectored(&self) -> bool { | |
94222f64 | 93 | cfg!(not(target_os = "espidf")) |
f9f354fc XL |
94 | } |
95 | ||
54a0048b SL |
96 | pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { |
97 | let mut me = self; | |
98 | (&mut me).read_to_end(buf) | |
99 | } | |
100 | ||
c30ab7b3 | 101 | pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { |
a2a8927a XL |
102 | #[cfg(not(any(target_os = "linux", target_os = "android")))] |
103 | use libc::pread as pread64; | |
104 | #[cfg(any(target_os = "linux", target_os = "android"))] | |
105 | use libc::pread64; | |
c30ab7b3 SL |
106 | |
107 | unsafe { | |
a2a8927a | 108 | cvt(pread64( |
94222f64 | 109 | self.as_raw_fd(), |
60c5eb7d | 110 | buf.as_mut_ptr() as *mut c_void, |
3dfed10e | 111 | cmp::min(buf.len(), READ_LIMIT), |
60c5eb7d | 112 | offset as i64, |
a2a8927a | 113 | )) |
60c5eb7d | 114 | .map(|n| n as usize) |
c30ab7b3 SL |
115 | } |
116 | } | |
117 | ||
a2a8927a XL |
118 | pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { |
119 | let ret = cvt(unsafe { | |
120 | libc::read( | |
121 | self.as_raw_fd(), | |
122 | buf.unfilled_mut().as_mut_ptr() as *mut c_void, | |
123 | cmp::min(buf.remaining(), READ_LIMIT), | |
124 | ) | |
125 | })?; | |
126 | ||
127 | // Safety: `ret` bytes were written to the initialized portion of the buffer | |
128 | unsafe { | |
129 | buf.assume_init(ret as usize); | |
130 | } | |
131 | buf.add_filled(ret as usize); | |
132 | Ok(()) | |
133 | } | |
134 | ||
85aaf69f | 135 | pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
54a0048b | 136 | let ret = cvt(unsafe { |
94222f64 XL |
137 | libc::write( |
138 | self.as_raw_fd(), | |
139 | buf.as_ptr() as *const c_void, | |
140 | cmp::min(buf.len(), READ_LIMIT), | |
141 | ) | |
54a0048b | 142 | })?; |
85aaf69f SL |
143 | Ok(ret as usize) |
144 | } | |
9346a6ac | 145 | |
94222f64 | 146 | #[cfg(not(target_os = "espidf"))] |
48663c56 | 147 | pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
9fa01778 | 148 | let ret = cvt(unsafe { |
60c5eb7d | 149 | libc::writev( |
94222f64 | 150 | self.as_raw_fd(), |
60c5eb7d | 151 | bufs.as_ptr() as *const libc::iovec, |
3dfed10e | 152 | cmp::min(bufs.len(), max_iov()) as c_int, |
60c5eb7d | 153 | ) |
9fa01778 XL |
154 | })?; |
155 | Ok(ret as usize) | |
156 | } | |
157 | ||
94222f64 XL |
158 | #[cfg(target_os = "espidf")] |
159 | pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
160 | return crate::io::default_write_vectored(|b| self.write(b), bufs); | |
161 | } | |
162 | ||
f9f354fc XL |
163 | #[inline] |
164 | pub fn is_write_vectored(&self) -> bool { | |
94222f64 | 165 | cfg!(not(target_os = "espidf")) |
f9f354fc XL |
166 | } |
167 | ||
c30ab7b3 | 168 | pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { |
a2a8927a XL |
169 | #[cfg(not(any(target_os = "linux", target_os = "android")))] |
170 | use libc::pwrite as pwrite64; | |
171 | #[cfg(any(target_os = "linux", target_os = "android"))] | |
172 | use libc::pwrite64; | |
c30ab7b3 SL |
173 | |
174 | unsafe { | |
a2a8927a | 175 | cvt(pwrite64( |
94222f64 | 176 | self.as_raw_fd(), |
60c5eb7d | 177 | buf.as_ptr() as *const c_void, |
3dfed10e | 178 | cmp::min(buf.len(), READ_LIMIT), |
60c5eb7d | 179 | offset as i64, |
a2a8927a | 180 | )) |
60c5eb7d | 181 | .map(|n| n as usize) |
c30ab7b3 SL |
182 | } |
183 | } | |
184 | ||
94b46f34 XL |
185 | #[cfg(target_os = "linux")] |
186 | pub fn get_cloexec(&self) -> io::Result<bool> { | |
94222f64 | 187 | unsafe { Ok((cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) } |
94b46f34 XL |
188 | } |
189 | ||
60c5eb7d XL |
190 | #[cfg(not(any( |
191 | target_env = "newlib", | |
192 | target_os = "solaris", | |
ba9703b0 | 193 | target_os = "illumos", |
60c5eb7d XL |
194 | target_os = "emscripten", |
195 | target_os = "fuchsia", | |
196 | target_os = "l4re", | |
197 | target_os = "linux", | |
198 | target_os = "haiku", | |
29967ef6 XL |
199 | target_os = "redox", |
200 | target_os = "vxworks" | |
60c5eb7d | 201 | )))] |
3157f602 | 202 | pub fn set_cloexec(&self) -> io::Result<()> { |
9346a6ac | 203 | unsafe { |
94222f64 | 204 | cvt(libc::ioctl(self.as_raw_fd(), libc::FIOCLEX))?; |
3157f602 | 205 | Ok(()) |
92a42be0 SL |
206 | } |
207 | } | |
60c5eb7d | 208 | #[cfg(any( |
94222f64 | 209 | all(target_env = "newlib", not(target_os = "espidf")), |
60c5eb7d | 210 | target_os = "solaris", |
ba9703b0 | 211 | target_os = "illumos", |
60c5eb7d XL |
212 | target_os = "emscripten", |
213 | target_os = "fuchsia", | |
214 | target_os = "l4re", | |
215 | target_os = "linux", | |
216 | target_os = "haiku", | |
29967ef6 XL |
217 | target_os = "redox", |
218 | target_os = "vxworks" | |
60c5eb7d | 219 | ))] |
3157f602 | 220 | pub fn set_cloexec(&self) -> io::Result<()> { |
92a42be0 | 221 | unsafe { |
94222f64 | 222 | let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))?; |
8bb4bdeb XL |
223 | let new = previous | libc::FD_CLOEXEC; |
224 | if new != previous { | |
94222f64 | 225 | cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFD, new))?; |
8bb4bdeb | 226 | } |
3157f602 | 227 | Ok(()) |
9346a6ac AL |
228 | } |
229 | } | |
94222f64 XL |
230 | #[cfg(target_os = "espidf")] |
231 | pub fn set_cloexec(&self) -> io::Result<()> { | |
232 | // FD_CLOEXEC is not supported in ESP-IDF but there's no need to, | |
233 | // because ESP-IDF does not support spawning processes either. | |
234 | Ok(()) | |
235 | } | |
7453a54e | 236 | |
8bb4bdeb XL |
237 | #[cfg(target_os = "linux")] |
238 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
239 | unsafe { | |
240 | let v = nonblocking as c_int; | |
94222f64 | 241 | cvt(libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &v))?; |
8bb4bdeb XL |
242 | Ok(()) |
243 | } | |
244 | } | |
245 | ||
246 | #[cfg(not(target_os = "linux"))] | |
3157f602 | 247 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
54a0048b | 248 | unsafe { |
94222f64 | 249 | let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFL))?; |
54a0048b SL |
250 | let new = if nonblocking { |
251 | previous | libc::O_NONBLOCK | |
252 | } else { | |
253 | previous & !libc::O_NONBLOCK | |
254 | }; | |
8bb4bdeb | 255 | if new != previous { |
94222f64 | 256 | cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFL, new))?; |
8bb4bdeb | 257 | } |
3157f602 | 258 | Ok(()) |
54a0048b SL |
259 | } |
260 | } | |
261 | ||
5099ac24 | 262 | #[inline] |
7453a54e | 263 | pub fn duplicate(&self) -> io::Result<FileDesc> { |
5099ac24 | 264 | Ok(Self(self.0.try_clone()?)) |
7453a54e | 265 | } |
85aaf69f SL |
266 | } |
267 | ||
54a0048b SL |
268 | impl<'a> Read for &'a FileDesc { |
269 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
270 | (**self).read(buf) | |
271 | } | |
54a0048b SL |
272 | } |
273 | ||
94222f64 XL |
274 | impl AsInner<OwnedFd> for FileDesc { |
275 | fn as_inner(&self) -> &OwnedFd { | |
276 | &self.0 | |
277 | } | |
278 | } | |
279 | ||
280 | impl IntoInner<OwnedFd> for FileDesc { | |
281 | fn into_inner(self) -> OwnedFd { | |
282 | self.0 | |
283 | } | |
284 | } | |
285 | ||
286 | impl FromInner<OwnedFd> for FileDesc { | |
287 | fn from_inner(owned_fd: OwnedFd) -> Self { | |
288 | Self(owned_fd) | |
289 | } | |
290 | } | |
291 | ||
292 | impl AsFd for FileDesc { | |
293 | fn as_fd(&self) -> BorrowedFd<'_> { | |
294 | self.0.as_fd() | |
295 | } | |
296 | } | |
297 | ||
298 | impl AsRawFd for FileDesc { | |
299 | fn as_raw_fd(&self) -> RawFd { | |
300 | self.0.as_raw_fd() | |
301 | } | |
302 | } | |
303 | ||
304 | impl IntoRawFd for FileDesc { | |
305 | fn into_raw_fd(self) -> RawFd { | |
306 | self.0.into_raw_fd() | |
60c5eb7d | 307 | } |
85aaf69f SL |
308 | } |
309 | ||
94222f64 XL |
310 | impl FromRawFd for FileDesc { |
311 | unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { | |
312 | Self(FromRawFd::from_raw_fd(raw_fd)) | |
85aaf69f SL |
313 | } |
314 | } |