1 #![unstable(reason = "not public", issue = "none", feature = "fd")]
7 use crate::io
::{self, IoSlice, IoSliceMut, Read, ReadBuf}
;
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",
51 const fn max_iov() -> usize {
52 libc
::IOV_MAX
as usize
55 #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
56 const fn max_iov() -> usize {
57 libc
::UIO_MAXIOV
as usize
61 target_os
= "android",
62 target_os
= "dragonfly",
63 target_os
= "emscripten",
64 target_os
= "freebsd",
69 target_os
= "openbsd",
72 const fn max_iov() -> usize {
73 16 // The minimum value required by POSIX.
77 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
78 let ret
= cvt(unsafe {
81 buf
.as_mut_ptr() as *mut libc
::c_void
,
82 cmp
::min(buf
.len(), READ_LIMIT
),
88 #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
89 pub fn read_vectored(&self, bufs
: &mut [IoSliceMut
<'_
>]) -> io
::Result
<usize> {
90 let ret
= cvt(unsafe {
93 bufs
.as_ptr() as *const libc
::iovec
,
94 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
100 #[cfg(any(target_os = "espidf", target_os = "horizon"))]
101 pub fn read_vectored(&self, bufs
: &mut [IoSliceMut
<'_
>]) -> io
::Result
<usize> {
102 return crate::io
::default_read_vectored(|b
| self.read(b
), bufs
);
106 pub fn is_read_vectored(&self) -> bool
{
107 cfg
!(not(any(target_os
= "espidf", target_os
= "horizon")))
110 pub fn read_to_end(&self, buf
: &mut Vec
<u8>) -> io
::Result
<usize> {
112 (&mut me
).read_to_end(buf
)
115 pub fn read_at(&self, buf
: &mut [u8], offset
: u64) -> io
::Result
<usize> {
116 #[cfg(not(any(target_os = "linux", target_os = "android")))]
117 use libc
::pread
as pread64
;
118 #[cfg(any(target_os = "linux", target_os = "android"))]
124 buf
.as_mut_ptr() as *mut libc
::c_void
,
125 cmp
::min(buf
.len(), READ_LIMIT
),
132 pub fn read_buf(&self, buf
: &mut ReadBuf
<'_
>) -> io
::Result
<()> {
133 let ret
= cvt(unsafe {
136 buf
.unfilled_mut().as_mut_ptr() as *mut libc
::c_void
,
137 cmp
::min(buf
.remaining(), READ_LIMIT
),
141 // Safety: `ret` bytes were written to the initialized portion of the buffer
143 buf
.assume_init(ret
as usize);
145 buf
.add_filled(ret
as usize);
149 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
150 let ret
= cvt(unsafe {
153 buf
.as_ptr() as *const libc
::c_void
,
154 cmp
::min(buf
.len(), READ_LIMIT
),
160 #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
161 pub fn write_vectored(&self, bufs
: &[IoSlice
<'_
>]) -> io
::Result
<usize> {
162 let ret
= cvt(unsafe {
165 bufs
.as_ptr() as *const libc
::iovec
,
166 cmp
::min(bufs
.len(), max_iov()) as libc
::c_int
,
172 #[cfg(any(target_os = "espidf", target_os = "horizon"))]
173 pub fn write_vectored(&self, bufs
: &[IoSlice
<'_
>]) -> io
::Result
<usize> {
174 return crate::io
::default_write_vectored(|b
| self.write(b
), bufs
);
178 pub fn is_write_vectored(&self) -> bool
{
179 cfg
!(not(any(target_os
= "espidf", target_os
= "horizon")))
182 pub fn write_at(&self, buf
: &[u8], offset
: u64) -> io
::Result
<usize> {
183 #[cfg(not(any(target_os = "linux", target_os = "android")))]
184 use libc
::pwrite
as pwrite64
;
185 #[cfg(any(target_os = "linux", target_os = "android"))]
191 buf
.as_ptr() as *const libc
::c_void
,
192 cmp
::min(buf
.len(), READ_LIMIT
),
199 #[cfg(target_os = "linux")]
200 pub fn get_cloexec(&self) -> io
::Result
<bool
> {
201 unsafe { Ok((cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
205 target_env
= "newlib",
206 target_os
= "solaris",
207 target_os
= "illumos",
208 target_os
= "emscripten",
209 target_os
= "fuchsia",
214 target_os
= "vxworks"
216 pub fn set_cloexec(&self) -> io
::Result
<()> {
218 cvt(libc
::ioctl(self.as_raw_fd(), libc
::FIOCLEX
))?
;
223 all(target_env
= "newlib", not(any(target_os
= "espidf", target_os
= "horizon"))),
224 target_os
= "solaris",
225 target_os
= "illumos",
226 target_os
= "emscripten",
227 target_os
= "fuchsia",
232 target_os
= "vxworks"
234 pub fn set_cloexec(&self) -> io
::Result
<()> {
236 let previous
= cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_GETFD
))?
;
237 let new
= previous
| libc
::FD_CLOEXEC
;
239 cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_SETFD
, new
))?
;
244 #[cfg(any(target_os = "espidf", target_os = "horizon"))]
245 pub fn set_cloexec(&self) -> io
::Result
<()> {
246 // FD_CLOEXEC is not supported in ESP-IDF and Horizon OS but there's no need to,
247 // because neither supports spawning processes.
251 #[cfg(target_os = "linux")]
252 pub fn set_nonblocking(&self, nonblocking
: bool
) -> io
::Result
<()> {
254 let v
= nonblocking
as libc
::c_int
;
255 cvt(libc
::ioctl(self.as_raw_fd(), libc
::FIONBIO
, &v
))?
;
260 #[cfg(not(target_os = "linux"))]
261 pub fn set_nonblocking(&self, nonblocking
: bool
) -> io
::Result
<()> {
263 let previous
= cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_GETFL
))?
;
264 let new
= if nonblocking
{
265 previous
| libc
::O_NONBLOCK
267 previous
& !libc
::O_NONBLOCK
270 cvt(libc
::fcntl(self.as_raw_fd(), libc
::F_SETFL
, new
))?
;
277 pub fn duplicate(&self) -> io
::Result
<FileDesc
> {
278 Ok(Self(self.0.try_clone()?
))
282 impl<'a
> Read
for &'a FileDesc
{
283 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
288 impl AsInner
<OwnedFd
> for FileDesc
{
289 fn as_inner(&self) -> &OwnedFd
{
294 impl IntoInner
<OwnedFd
> for FileDesc
{
295 fn into_inner(self) -> OwnedFd
{
300 impl FromInner
<OwnedFd
> for FileDesc
{
301 fn from_inner(owned_fd
: OwnedFd
) -> Self {
306 impl AsFd
for FileDesc
{
307 fn as_fd(&self) -> BorrowedFd
<'_
> {
312 impl AsRawFd
for FileDesc
{
313 fn as_raw_fd(&self) -> RawFd
{
318 impl IntoRawFd
for FileDesc
{
319 fn into_raw_fd(self) -> RawFd
{
324 impl FromRawFd
for FileDesc
{
325 unsafe fn from_raw_fd(raw_fd
: RawFd
) -> Self {
326 Self(FromRawFd
::from_raw_fd(raw_fd
))