1 #![unstable(reason = "not public", issue = "none", feature = "fd")]
7 use crate::io
::{self, Initializer, IoSlice, IoSliceMut, Read}
;
8 use crate::os
::unix
::io
::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}
;
10 use crate::sys_common
::{AsInner, FromInner, IntoInner}
;
12 use libc
::{c_int, c_void}
;
15 pub struct FileDesc(OwnedFd
);
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".
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;
31 target_os
= "dragonfly",
32 target_os
= "freebsd",
36 target_os
= "openbsd",
38 const fn max_iov() -> usize {
39 libc
::IOV_MAX
as usize
42 #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
43 const fn max_iov() -> usize {
44 libc
::UIO_MAXIOV
as usize
48 target_os
= "android",
49 target_os
= "dragonfly",
50 target_os
= "emscripten",
51 target_os
= "freebsd",
56 target_os
= "openbsd",
58 const fn max_iov() -> usize {
59 16 // The minimum value required by POSIX.
63 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
64 let ret
= cvt(unsafe {
67 buf
.as_mut_ptr() as *mut c_void
,
68 cmp
::min(buf
.len(), READ_LIMIT
),
74 #[cfg(not(target_os = "espidf"))]
75 pub fn read_vectored(&self, bufs
: &mut [IoSliceMut
<'_
>]) -> io
::Result
<usize> {
76 let ret
= cvt(unsafe {
79 bufs
.as_ptr() as *const libc
::iovec
,
80 cmp
::min(bufs
.len(), max_iov()) as c_int
,
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
);
92 pub fn is_read_vectored(&self) -> bool
{
93 cfg
!(not(target_os
= "espidf"))
96 pub fn read_to_end(&self, buf
: &mut Vec
<u8>) -> io
::Result
<usize> {
98 (&mut me
).read_to_end(buf
)
101 pub fn read_at(&self, buf
: &mut [u8], offset
: u64) -> io
::Result
<usize> {
102 #[cfg(target_os = "android")]
103 use super::android
::cvt_pread64
;
105 #[cfg(not(target_os = "android"))]
106 unsafe fn cvt_pread64(
111 ) -> io
::Result
<isize> {
112 #[cfg(not(target_os = "linux"))]
113 use libc
::pread
as pread64
;
114 #[cfg(target_os = "linux")]
116 cvt(pread64(fd
, buf
, count
, offset
))
122 buf
.as_mut_ptr() as *mut c_void
,
123 cmp
::min(buf
.len(), READ_LIMIT
),
130 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
131 let ret
= cvt(unsafe {
134 buf
.as_ptr() as *const c_void
,
135 cmp
::min(buf
.len(), READ_LIMIT
),
141 #[cfg(not(target_os = "espidf"))]
142 pub fn write_vectored(&self, bufs
: &[IoSlice
<'_
>]) -> io
::Result
<usize> {
143 let ret
= cvt(unsafe {
146 bufs
.as_ptr() as *const libc
::iovec
,
147 cmp
::min(bufs
.len(), max_iov()) as c_int
,
153 #[cfg(target_os = "espidf")]
154 pub fn write_vectored(&self, bufs
: &[IoSlice
<'_
>]) -> io
::Result
<usize> {
155 return crate::io
::default_write_vectored(|b
| self.write(b
), bufs
);
159 pub fn is_write_vectored(&self) -> bool
{
160 cfg
!(not(target_os
= "espidf"))
163 pub fn write_at(&self, buf
: &[u8], offset
: u64) -> io
::Result
<usize> {
164 #[cfg(target_os = "android")]
165 use super::android
::cvt_pwrite64
;
167 #[cfg(not(target_os = "android"))]
168 unsafe fn cvt_pwrite64(
173 ) -> io
::Result
<isize> {
174 #[cfg(not(target_os = "linux"))]
175 use libc
::pwrite
as pwrite64
;
176 #[cfg(target_os = "linux")]
178 cvt(pwrite64(fd
, buf
, count
, offset
))
184 buf
.as_ptr() as *const c_void
,
185 cmp
::min(buf
.len(), READ_LIMIT
),
192 #[cfg(target_os = "linux")]
193 pub fn get_cloexec(&self) -> io
::Result
<bool
> {
194 unsafe { Ok((cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
198 target_env
= "newlib",
199 target_os
= "solaris",
200 target_os
= "illumos",
201 target_os
= "emscripten",
202 target_os
= "fuchsia",
207 target_os
= "vxworks"
209 pub fn set_cloexec(&self) -> io
::Result
<()> {
211 cvt(libc
::ioctl(self.as_raw_fd(), libc
::FIOCLEX
))?
;
216 all(target_env
= "newlib", not(target_os
= "espidf")),
217 target_os
= "solaris",
218 target_os
= "illumos",
219 target_os
= "emscripten",
220 target_os
= "fuchsia",
225 target_os
= "vxworks"
227 pub fn set_cloexec(&self) -> io
::Result
<()> {
229 let previous
= cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_GETFD
))?
;
230 let new
= previous
| libc
::FD_CLOEXEC
;
232 cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_SETFD
, new
))?
;
237 #[cfg(target_os = "espidf")]
238 pub fn set_cloexec(&self) -> io
::Result
<()> {
239 // FD_CLOEXEC is not supported in ESP-IDF but there's no need to,
240 // because ESP-IDF does not support spawning processes either.
244 #[cfg(target_os = "linux")]
245 pub fn set_nonblocking(&self, nonblocking
: bool
) -> io
::Result
<()> {
247 let v
= nonblocking
as c_int
;
248 cvt(libc
::ioctl(self.as_raw_fd(), libc
::FIONBIO
, &v
))?
;
253 #[cfg(not(target_os = "linux"))]
254 pub fn set_nonblocking(&self, nonblocking
: bool
) -> io
::Result
<()> {
256 let previous
= cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_GETFL
))?
;
257 let new
= if nonblocking
{
258 previous
| libc
::O_NONBLOCK
260 previous
& !libc
::O_NONBLOCK
263 cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_SETFL
, new
))?
;
269 pub fn duplicate(&self) -> io
::Result
<FileDesc
> {
270 // We want to atomically duplicate this file descriptor and set the
271 // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
272 // is a POSIX flag that was added to Linux in 2.6.24.
273 #[cfg(not(target_os = "espidf"))]
274 let cmd
= libc
::F_DUPFD_CLOEXEC
;
276 // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
277 // will never be supported, as this is a bare metal framework with
278 // no capabilities for multi-process execution. While F_DUPFD is also
279 // not supported yet, it might be (currently it returns ENOSYS).
280 #[cfg(target_os = "espidf")]
281 let cmd
= libc
::F_DUPFD
;
283 let fd
= cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) }
)?
;
284 Ok(unsafe { FileDesc::from_raw_fd(fd) }
)
288 impl<'a
> Read
for &'a FileDesc
{
289 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
294 unsafe fn initializer(&self) -> Initializer
{
299 impl AsInner
<OwnedFd
> for FileDesc
{
300 fn as_inner(&self) -> &OwnedFd
{
305 impl IntoInner
<OwnedFd
> for FileDesc
{
306 fn into_inner(self) -> OwnedFd
{
311 impl FromInner
<OwnedFd
> for FileDesc
{
312 fn from_inner(owned_fd
: OwnedFd
) -> Self {
317 impl AsFd
for FileDesc
{
318 fn as_fd(&self) -> BorrowedFd
<'_
> {
323 impl AsRawFd
for FileDesc
{
324 fn as_raw_fd(&self) -> RawFd
{
329 impl IntoRawFd
for FileDesc
{
330 fn into_raw_fd(self) -> RawFd
{
335 impl FromRawFd
for FileDesc
{
336 unsafe fn from_raw_fd(raw_fd
: RawFd
) -> Self {
337 Self(FromRawFd
::from_raw_fd(raw_fd
))