1 #![unstable(reason = "not public", issue = "none", feature = "fd")]
7 use crate::io
::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}
;
8 use crate::os
::unix
::io
::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}
;
10 use crate::sys_common
::{AsInner, FromInner, IntoInner}
;
13 target_os
= "android",
15 target_os
= "emscripten",
21 target_os
= "emscripten",
25 use libc
::off_t
as off64_t
;
28 pub struct FileDesc(OwnedFd
);
30 // The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
31 // with the man page quoting that if the count of bytes to read is
32 // greater than `SSIZE_MAX` the result is "unspecified".
34 // On macOS, however, apparently the 64-bit libc is either buggy or
35 // intentionally showing odd behavior by rejecting any read with a size
36 // larger than or equal to INT_MAX. To handle both of these the read
37 // size is capped on both platforms.
38 #[cfg(target_os = "macos")]
39 const READ_LIMIT
: usize = libc
::c_int
::MAX
as usize - 1;
40 #[cfg(not(target_os = "macos"))]
41 const READ_LIMIT
: usize = libc
::ssize_t
::MAX
as usize;
44 target_os
= "dragonfly",
45 target_os
= "freebsd",
49 target_os
= "openbsd",
50 target_os
= "watchos",
52 const fn max_iov() -> usize {
53 libc
::IOV_MAX
as usize
57 target_os
= "android",
58 target_os
= "emscripten",
62 const fn max_iov() -> usize {
63 libc
::UIO_MAXIOV
as usize
67 target_os
= "android",
68 target_os
= "dragonfly",
69 target_os
= "emscripten",
70 target_os
= "freebsd",
76 target_os
= "openbsd",
77 target_os
= "horizon",
78 target_os
= "watchos",
80 const fn max_iov() -> usize {
81 16 // The minimum value required by POSIX.
85 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
86 let ret
= cvt(unsafe {
89 buf
.as_mut_ptr() as *mut libc
::c_void
,
90 cmp
::min(buf
.len(), READ_LIMIT
),
96 #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
97 pub fn read_vectored(&self, bufs
: &mut [IoSliceMut
<'_
>]) -> io
::Result
<usize> {
98 let ret
= cvt(unsafe {
101 bufs
.as_mut_ptr() as *mut libc
::iovec
as *const libc
::iovec
,
102 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
108 #[cfg(any(target_os = "espidf", target_os = "horizon"))]
109 pub fn read_vectored(&self, bufs
: &mut [IoSliceMut
<'_
>]) -> io
::Result
<usize> {
110 io
::default_read_vectored(|b
| self.read(b
), bufs
)
114 pub fn is_read_vectored(&self) -> bool
{
115 cfg
!(not(any(target_os
= "espidf", target_os
= "horizon")))
118 pub fn read_to_end(&self, buf
: &mut Vec
<u8>) -> io
::Result
<usize> {
120 (&mut me
).read_to_end(buf
)
123 pub fn read_at(&self, buf
: &mut [u8], offset
: u64) -> io
::Result
<usize> {
124 #[cfg(not(any(target_os = "linux", target_os = "android")))]
125 use libc
::pread
as pread64
;
126 #[cfg(any(target_os = "linux", target_os = "android"))]
132 buf
.as_mut_ptr() as *mut libc
::c_void
,
133 cmp
::min(buf
.len(), READ_LIMIT
),
140 pub fn read_buf(&self, mut cursor
: BorrowedCursor
<'_
>) -> io
::Result
<()> {
141 let ret
= cvt(unsafe {
144 cursor
.as_mut().as_mut_ptr() as *mut libc
::c_void
,
145 cmp
::min(cursor
.capacity(), READ_LIMIT
),
149 // Safety: `ret` bytes were written to the initialized portion of the buffer
151 cursor
.advance(ret
as usize);
157 target_os
= "emscripten",
158 target_os
= "freebsd",
159 target_os
= "fuchsia",
160 target_os
= "illumos",
162 target_os
= "netbsd",
164 pub fn read_vectored_at(&self, bufs
: &mut [IoSliceMut
<'_
>], offset
: u64) -> io
::Result
<usize> {
165 let ret
= cvt(unsafe {
168 bufs
.as_mut_ptr() as *mut libc
::iovec
as *const libc
::iovec
,
169 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
177 target_os
= "android",
178 target_os
= "emscripten",
179 target_os
= "freebsd",
180 target_os
= "fuchsia",
181 target_os
= "illumos",
185 target_os
= "netbsd",
187 pub fn read_vectored_at(&self, bufs
: &mut [IoSliceMut
<'_
>], offset
: u64) -> io
::Result
<usize> {
188 io
::default_read_vectored(|b
| self.read_at(b
, offset
), bufs
)
191 // We support some old Android versions that do not have `preadv` in libc,
192 // so we use weak linkage and fallback to a direct syscall if not available.
194 // On 32-bit targets, we don't want to deal with weird ABI issues around
195 // passing 64-bits parameters to syscalls, so we fallback to the default
196 // implementation if `preadv` is not available.
197 #[cfg(all(target_os = "android", target_pointer_width = "64"))]
198 pub fn read_vectored_at(&self, bufs
: &mut [IoSliceMut
<'_
>], offset
: u64) -> io
::Result
<usize> {
199 super::weak
::syscall
! {
202 iovec
: *const libc
::iovec
,
203 n_iovec
: libc
::c_int
,
208 let ret
= cvt(unsafe {
211 bufs
.as_mut_ptr() as *mut libc
::iovec
as *const libc
::iovec
,
212 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
219 // We support old MacOS and iOS versions that do not have `preadv`. There is
220 // no `syscall` possible in these platform.
222 all(target_os
= "android", target_pointer_width
= "32"),
226 pub fn read_vectored_at(&self, bufs
: &mut [IoSliceMut
<'_
>], offset
: u64) -> io
::Result
<usize> {
227 super::weak
::weak
!(fn preadv64(libc
::c_int
, *const libc
::iovec
, libc
::c_int
, off64_t
) -> isize);
229 match preadv64
.get() {
231 let ret
= cvt(unsafe {
234 bufs
.as_mut_ptr() as *mut libc
::iovec
as *const libc
::iovec
,
235 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
241 None
=> io
::default_read_vectored(|b
| self.read_at(b
, offset
), bufs
),
245 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
246 let ret
= cvt(unsafe {
249 buf
.as_ptr() as *const libc
::c_void
,
250 cmp
::min(buf
.len(), READ_LIMIT
),
256 #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
257 pub fn write_vectored(&self, bufs
: &[IoSlice
<'_
>]) -> io
::Result
<usize> {
258 let ret
= cvt(unsafe {
261 bufs
.as_ptr() as *const libc
::iovec
,
262 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
268 #[cfg(any(target_os = "espidf", target_os = "horizon"))]
269 pub fn write_vectored(&self, bufs
: &[IoSlice
<'_
>]) -> io
::Result
<usize> {
270 io
::default_write_vectored(|b
| self.write(b
), bufs
)
274 pub fn is_write_vectored(&self) -> bool
{
275 cfg
!(not(any(target_os
= "espidf", target_os
= "horizon")))
278 pub fn write_at(&self, buf
: &[u8], offset
: u64) -> io
::Result
<usize> {
279 #[cfg(not(any(target_os = "linux", target_os = "android")))]
280 use libc
::pwrite
as pwrite64
;
281 #[cfg(any(target_os = "linux", target_os = "android"))]
287 buf
.as_ptr() as *const libc
::c_void
,
288 cmp
::min(buf
.len(), READ_LIMIT
),
296 target_os
= "emscripten",
297 target_os
= "freebsd",
298 target_os
= "fuchsia",
299 target_os
= "illumos",
301 target_os
= "netbsd",
303 pub fn write_vectored_at(&self, bufs
: &[IoSlice
<'_
>], offset
: u64) -> io
::Result
<usize> {
304 let ret
= cvt(unsafe {
307 bufs
.as_ptr() as *const libc
::iovec
,
308 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
316 target_os
= "android",
317 target_os
= "emscripten",
318 target_os
= "freebsd",
319 target_os
= "fuchsia",
320 target_os
= "illumos",
324 target_os
= "netbsd",
326 pub fn write_vectored_at(&self, bufs
: &[IoSlice
<'_
>], offset
: u64) -> io
::Result
<usize> {
327 io
::default_write_vectored(|b
| self.write_at(b
, offset
), bufs
)
330 // We support some old Android versions that do not have `pwritev` in libc,
331 // so we use weak linkage and fallback to a direct syscall if not available.
333 // On 32-bit targets, we don't want to deal with weird ABI issues around
334 // passing 64-bits parameters to syscalls, so we fallback to the default
335 // implementation if `pwritev` is not available.
336 #[cfg(all(target_os = "android", target_pointer_width = "64"))]
337 pub fn write_vectored_at(&self, bufs
: &[IoSlice
<'_
>], offset
: u64) -> io
::Result
<usize> {
338 super::weak
::syscall
! {
341 iovec
: *const libc
::iovec
,
342 n_iovec
: libc
::c_int
,
347 let ret
= cvt(unsafe {
350 bufs
.as_ptr() as *const libc
::iovec
,
351 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
358 // We support old MacOS and iOS versions that do not have `pwritev`. There is
359 // no `syscall` possible in these platform.
361 all(target_os
= "android", target_pointer_width
= "32"),
365 pub fn write_vectored_at(&self, bufs
: &[IoSlice
<'_
>], offset
: u64) -> io
::Result
<usize> {
366 super::weak
::weak
!(fn pwritev64(libc
::c_int
, *const libc
::iovec
, libc
::c_int
, off64_t
) -> isize);
368 match pwritev64
.get() {
370 let ret
= cvt(unsafe {
373 bufs
.as_ptr() as *const libc
::iovec
,
374 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
380 None
=> io
::default_write_vectored(|b
| self.write_at(b
, offset
), bufs
),
385 target_env
= "newlib",
386 target_os
= "solaris",
387 target_os
= "illumos",
388 target_os
= "emscripten",
389 target_os
= "fuchsia",
394 target_os
= "vxworks",
397 pub fn set_cloexec(&self) -> io
::Result
<()> {
399 cvt(libc
::ioctl(self.as_raw_fd(), libc
::FIOCLEX
))?
;
404 all(target_env
= "newlib", not(any(target_os
= "espidf", target_os
= "horizon"))),
405 target_os
= "solaris",
406 target_os
= "illumos",
407 target_os
= "emscripten",
408 target_os
= "fuchsia",
413 target_os
= "vxworks",
416 pub fn set_cloexec(&self) -> io
::Result
<()> {
418 let previous
= cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_GETFD
))?
;
419 let new
= previous
| libc
::FD_CLOEXEC
;
421 cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_SETFD
, new
))?
;
426 #[cfg(any(target_os = "espidf", target_os = "horizon"))]
427 pub fn set_cloexec(&self) -> io
::Result
<()> {
428 // FD_CLOEXEC is not supported in ESP-IDF and Horizon OS but there's no need to,
429 // because neither supports spawning processes.
433 #[cfg(target_os = "linux")]
434 pub fn set_nonblocking(&self, nonblocking
: bool
) -> io
::Result
<()> {
436 let v
= nonblocking
as libc
::c_int
;
437 cvt(libc
::ioctl(self.as_raw_fd(), libc
::FIONBIO
, &v
))?
;
442 #[cfg(not(target_os = "linux"))]
443 pub fn set_nonblocking(&self, nonblocking
: bool
) -> io
::Result
<()> {
445 let previous
= cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_GETFL
))?
;
446 let new
= if nonblocking
{
447 previous
| libc
::O_NONBLOCK
449 previous
& !libc
::O_NONBLOCK
452 cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_SETFL
, new
))?
;
459 pub fn duplicate(&self) -> io
::Result
<FileDesc
> {
460 Ok(Self(self.0.try_clone()?
))
464 impl<'a
> Read
for &'a FileDesc
{
465 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
469 fn read_buf(&mut self, cursor
: BorrowedCursor
<'_
>) -> io
::Result
<()> {
470 (**self).read_buf(cursor
)
474 impl AsInner
<OwnedFd
> for FileDesc
{
475 fn as_inner(&self) -> &OwnedFd
{
480 impl IntoInner
<OwnedFd
> for FileDesc
{
481 fn into_inner(self) -> OwnedFd
{
486 impl FromInner
<OwnedFd
> for FileDesc
{
487 fn from_inner(owned_fd
: OwnedFd
) -> Self {
492 impl AsFd
for FileDesc
{
493 fn as_fd(&self) -> BorrowedFd
<'_
> {
498 impl AsRawFd
for FileDesc
{
499 fn as_raw_fd(&self) -> RawFd
{
504 impl IntoRawFd
for FileDesc
{
505 fn into_raw_fd(self) -> RawFd
{
510 impl FromRawFd
for FileDesc
{
511 unsafe fn from_raw_fd(raw_fd
: RawFd
) -> Self {
512 Self(FromRawFd
::from_raw_fd(raw_fd
))