| #![unstable(reason = "not public", issue = "none", feature = "fd")] | |
| #[cfg(test)] | |
| mod tests; | |
| #[cfg(not(any( | |
| target_os = "linux", | |
| target_os = "l4re", | |
| target_os = "android", | |
| target_os = "hurd", | |
| )))] | |
| use libc::off_t as off64_t; | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "linux", | |
| target_os = "l4re", | |
| target_os = "hurd", | |
| ))] | |
| use libc::off64_t; | |
| cfg_select! { | |
| any( | |
| all(target_os = "linux", not(target_env = "musl")), | |
| target_os = "android", | |
| target_os = "hurd", | |
| ) => { | |
| // Prefer explicit pread64 for 64-bit offset independently of libc | |
| // #[cfg(gnu_file_offset_bits64)]. | |
| use libc::pread64; | |
| } | |
| _ => { | |
| use libc::pread as pread64; | |
| } | |
| } | |
| use crate::cmp; | |
| use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; | |
| use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; | |
| #[cfg(all(target_os = "android", target_pointer_width = "64"))] | |
| use crate::sys::pal::weak::syscall; | |
| #[cfg(any(all(target_os = "android", target_pointer_width = "32"), target_vendor = "apple"))] | |
| use crate::sys::pal::weak::weak; | |
| use crate::sys::{AsInner, FromInner, IntoInner, cvt}; | |
| #[derive(Debug)] | |
| pub struct FileDesc(OwnedFd); | |
| // The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, | |
| // with the man page quoting that if the count of bytes to read is | |
| // greater than `SSIZE_MAX` the result is "unspecified". | |
| // | |
| // On Apple targets however, apparently the 64-bit libc is either buggy or | |
| // intentionally showing odd behavior by rejecting any read with a size | |
| // larger than INT_MAX. To handle both of these the read size is capped on | |
| // both platforms. | |
| const READ_LIMIT: usize = if cfg!(target_vendor = "apple") { | |
| libc::c_int::MAX as usize | |
| } else { | |
| libc::ssize_t::MAX as usize | |
| }; | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "netbsd", | |
| target_os = "openbsd", | |
| target_vendor = "apple", | |
| target_os = "cygwin", | |
| ))] | |
| const fn max_iov() -> usize { | |
| libc::IOV_MAX as usize | |
| } | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "emscripten", | |
| target_os = "linux", | |
| target_os = "nto", | |
| ))] | |
| const fn max_iov() -> usize { | |
| libc::UIO_MAXIOV as usize | |
| } | |
| #[cfg(not(any( | |
| target_os = "android", | |
| target_os = "dragonfly", | |
| target_os = "emscripten", | |
| target_os = "espidf", | |
| target_os = "freebsd", | |
| target_os = "linux", | |
| target_os = "netbsd", | |
| target_os = "nuttx", | |
| target_os = "nto", | |
| target_os = "openbsd", | |
| target_os = "horizon", | |
| target_os = "vita", | |
| target_vendor = "apple", | |
| target_os = "cygwin", | |
| )))] | |
| const fn max_iov() -> usize { | |
| 16 // The minimum value required by POSIX. | |
| } | |
| impl FileDesc { | |
| #[inline] | |
| pub fn try_clone(&self) -> io::Result<Self> { | |
| self.duplicate() | |
| } | |
| pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { | |
| let ret = cvt(unsafe { | |
| libc::read( | |
| self.as_raw_fd(), | |
| buf.as_mut_ptr() as *mut libc::c_void, | |
| cmp::min(buf.len(), READ_LIMIT), | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| #[cfg(not(any( | |
| target_os = "espidf", | |
| target_os = "horizon", | |
| target_os = "vita", | |
| target_os = "nuttx" | |
| )))] | |
| pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { | |
| let ret = cvt(unsafe { | |
| libc::readv( | |
| self.as_raw_fd(), | |
| bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| #[cfg(any( | |
| target_os = "espidf", | |
| target_os = "horizon", | |
| target_os = "vita", | |
| target_os = "nuttx" | |
| ))] | |
| pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { | |
| io::default_read_vectored(|b| self.read(b), bufs) | |
| } | |
| #[inline] | |
| pub fn is_read_vectored(&self) -> bool { | |
| cfg!(not(any( | |
| target_os = "espidf", | |
| target_os = "horizon", | |
| target_os = "vita", | |
| target_os = "nuttx", | |
| target_os = "wasi", | |
| ))) | |
| } | |
| pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { | |
| let mut me = self; | |
| (&mut me).read_to_end(buf) | |
| } | |
| pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { | |
| cvt(unsafe { | |
| pread64( | |
| self.as_raw_fd(), | |
| buf.as_mut_ptr() as *mut libc::c_void, | |
| cmp::min(buf.len(), READ_LIMIT), | |
| offset as off64_t, // EINVAL if offset + count overflows | |
| ) | |
| }) | |
| .map(|n| n as usize) | |
| } | |
| pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { | |
| // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes | |
| let ret = cvt(unsafe { | |
| libc::read( | |
| self.as_raw_fd(), | |
| cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(), | |
| cmp::min(cursor.capacity(), READ_LIMIT), | |
| ) | |
| })?; | |
| // SAFETY: `ret` bytes were written to the initialized portion of the buffer | |
| unsafe { | |
| cursor.advance_unchecked(ret as usize); | |
| } | |
| Ok(()) | |
| } | |
| pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { | |
| // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes | |
| let ret = cvt(unsafe { | |
| pread64( | |
| self.as_raw_fd(), | |
| cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(), | |
| cmp::min(cursor.capacity(), READ_LIMIT), | |
| offset as off64_t, // EINVAL if offset + count overflows | |
| ) | |
| })?; | |
| // SAFETY: `ret` bytes were written to the initialized portion of the buffer | |
| unsafe { | |
| cursor.advance_unchecked(ret as usize); | |
| } | |
| Ok(()) | |
| } | |
| #[cfg(any( | |
| target_os = "aix", | |
| target_os = "dragonfly", // DragonFly 1.5 | |
| target_os = "emscripten", | |
| target_os = "freebsd", | |
| target_os = "fuchsia", | |
| target_os = "hurd", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "netbsd", | |
| target_os = "openbsd", // OpenBSD 2.7 | |
| ))] | |
| pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { | |
| let ret = cvt(unsafe { | |
| libc::preadv( | |
| self.as_raw_fd(), | |
| bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| offset as _, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| #[cfg(not(any( | |
| target_os = "aix", | |
| target_os = "android", | |
| target_os = "dragonfly", | |
| target_os = "emscripten", | |
| target_os = "freebsd", | |
| target_os = "fuchsia", | |
| target_os = "hurd", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "netbsd", | |
| target_os = "openbsd", | |
| target_vendor = "apple", | |
| )))] | |
| pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { | |
| io::default_read_vectored(|b| self.read_at(b, offset), bufs) | |
| } | |
| // We support some old Android versions that do not have `preadv` in libc, | |
| // so we use weak linkage and fallback to a direct syscall if not available. | |
| // | |
| // On 32-bit targets, we don't want to deal with weird ABI issues around | |
| // passing 64-bits parameters to syscalls, so we fallback to the default | |
| // implementation if `preadv` is not available. | |
| #[cfg(all(target_os = "android", target_pointer_width = "64"))] | |
| pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { | |
| syscall!( | |
| fn preadv( | |
| fd: libc::c_int, | |
| iovec: *const libc::iovec, | |
| n_iovec: libc::c_int, | |
| offset: off64_t, | |
| ) -> isize; | |
| ); | |
| let ret = cvt(unsafe { | |
| preadv( | |
| self.as_raw_fd(), | |
| bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| offset as _, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| #[cfg(all(target_os = "android", target_pointer_width = "32"))] | |
| pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { | |
| weak!( | |
| fn preadv64( | |
| fd: libc::c_int, | |
| iovec: *const libc::iovec, | |
| n_iovec: libc::c_int, | |
| offset: off64_t, | |
| ) -> isize; | |
| ); | |
| match preadv64.get() { | |
| Some(preadv) => { | |
| let ret = cvt(unsafe { | |
| preadv( | |
| self.as_raw_fd(), | |
| bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| offset as _, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| None => io::default_read_vectored(|b| self.read_at(b, offset), bufs), | |
| } | |
| } | |
| // We support old MacOS, iOS, watchOS, tvOS and visionOS. `preadv` was added in the following | |
| // Apple OS versions: | |
| // ios 14.0 | |
| // tvos 14.0 | |
| // macos 11.0 | |
| // watchos 7.0 | |
| // | |
| // These versions may be newer than the minimum supported versions of OS's we support so we must | |
| // use "weak" linking. | |
| #[cfg(target_vendor = "apple")] | |
| pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { | |
| weak!( | |
| fn preadv( | |
| fd: libc::c_int, | |
| iovec: *const libc::iovec, | |
| n_iovec: libc::c_int, | |
| offset: off64_t, | |
| ) -> isize; | |
| ); | |
| match preadv.get() { | |
| Some(preadv) => { | |
| let ret = cvt(unsafe { | |
| preadv( | |
| self.as_raw_fd(), | |
| bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| offset as _, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| None => io::default_read_vectored(|b| self.read_at(b, offset), bufs), | |
| } | |
| } | |
| pub fn write(&self, buf: &[u8]) -> io::Result<usize> { | |
| let ret = cvt(unsafe { | |
| libc::write( | |
| self.as_raw_fd(), | |
| buf.as_ptr() as *const libc::c_void, | |
| cmp::min(buf.len(), READ_LIMIT), | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| #[cfg(not(any( | |
| target_os = "espidf", | |
| target_os = "horizon", | |
| target_os = "vita", | |
| target_os = "nuttx" | |
| )))] | |
| pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| let ret = cvt(unsafe { | |
| libc::writev( | |
| self.as_raw_fd(), | |
| bufs.as_ptr() as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| #[cfg(any( | |
| target_os = "espidf", | |
| target_os = "horizon", | |
| target_os = "vita", | |
| target_os = "nuttx" | |
| ))] | |
| pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
| io::default_write_vectored(|b| self.write(b), bufs) | |
| } | |
| #[inline] | |
| pub fn is_write_vectored(&self) -> bool { | |
| cfg!(not(any( | |
| target_os = "espidf", | |
| target_os = "horizon", | |
| target_os = "vita", | |
| target_os = "nuttx", | |
| target_os = "wasi", | |
| ))) | |
| } | |
| pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { | |
| #[cfg(not(any( | |
| all(target_os = "linux", not(target_env = "musl")), | |
| target_os = "android", | |
| target_os = "hurd" | |
| )))] | |
| use libc::pwrite as pwrite64; | |
| #[cfg(any( | |
| all(target_os = "linux", not(target_env = "musl")), | |
| target_os = "android", | |
| target_os = "hurd" | |
| ))] | |
| use libc::pwrite64; | |
| unsafe { | |
| cvt(pwrite64( | |
| self.as_raw_fd(), | |
| buf.as_ptr() as *const libc::c_void, | |
| cmp::min(buf.len(), READ_LIMIT), | |
| offset as off64_t, | |
| )) | |
| .map(|n| n as usize) | |
| } | |
| } | |
| #[cfg(any( | |
| target_os = "aix", | |
| target_os = "dragonfly", // DragonFly 1.5 | |
| target_os = "emscripten", | |
| target_os = "freebsd", | |
| target_os = "fuchsia", | |
| target_os = "hurd", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "netbsd", | |
| target_os = "openbsd", // OpenBSD 2.7 | |
| ))] | |
| pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { | |
| let ret = cvt(unsafe { | |
| libc::pwritev( | |
| self.as_raw_fd(), | |
| bufs.as_ptr() as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| offset as _, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| #[cfg(not(any( | |
| target_os = "aix", | |
| target_os = "android", | |
| target_os = "dragonfly", | |
| target_os = "emscripten", | |
| target_os = "freebsd", | |
| target_os = "fuchsia", | |
| target_os = "hurd", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "netbsd", | |
| target_os = "openbsd", | |
| target_vendor = "apple", | |
| )))] | |
| pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { | |
| io::default_write_vectored(|b| self.write_at(b, offset), bufs) | |
| } | |
| // We support some old Android versions that do not have `pwritev` in libc, | |
| // so we use weak linkage and fallback to a direct syscall if not available. | |
| // | |
| // On 32-bit targets, we don't want to deal with weird ABI issues around | |
| // passing 64-bits parameters to syscalls, so we fallback to the default | |
| // implementation if `pwritev` is not available. | |
| #[cfg(all(target_os = "android", target_pointer_width = "64"))] | |
| pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { | |
| syscall!( | |
| fn pwritev( | |
| fd: libc::c_int, | |
| iovec: *const libc::iovec, | |
| n_iovec: libc::c_int, | |
| offset: off64_t, | |
| ) -> isize; | |
| ); | |
| let ret = cvt(unsafe { | |
| pwritev( | |
| self.as_raw_fd(), | |
| bufs.as_ptr() as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| offset as _, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| #[cfg(all(target_os = "android", target_pointer_width = "32"))] | |
| pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { | |
| weak!( | |
| fn pwritev64( | |
| fd: libc::c_int, | |
| iovec: *const libc::iovec, | |
| n_iovec: libc::c_int, | |
| offset: off64_t, | |
| ) -> isize; | |
| ); | |
| match pwritev64.get() { | |
| Some(pwritev) => { | |
| let ret = cvt(unsafe { | |
| pwritev( | |
| self.as_raw_fd(), | |
| bufs.as_ptr() as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| offset as _, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| None => io::default_write_vectored(|b| self.write_at(b, offset), bufs), | |
| } | |
| } | |
| // We support old MacOS, iOS, watchOS, tvOS and visionOS. `pwritev` was added in the following | |
| // Apple OS versions: | |
| // ios 14.0 | |
| // tvos 14.0 | |
| // macos 11.0 | |
| // watchos 7.0 | |
| // | |
| // These versions may be newer than the minimum supported versions of OS's we support so we must | |
| // use "weak" linking. | |
| #[cfg(target_vendor = "apple")] | |
| pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { | |
| weak!( | |
| fn pwritev( | |
| fd: libc::c_int, | |
| iovec: *const libc::iovec, | |
| n_iovec: libc::c_int, | |
| offset: off64_t, | |
| ) -> isize; | |
| ); | |
| match pwritev.get() { | |
| Some(pwritev) => { | |
| let ret = cvt(unsafe { | |
| pwritev( | |
| self.as_raw_fd(), | |
| bufs.as_ptr() as *const libc::iovec, | |
| cmp::min(bufs.len(), max_iov()) as libc::c_int, | |
| offset as _, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| None => io::default_write_vectored(|b| self.write_at(b, offset), bufs), | |
| } | |
| } | |
| #[cfg(not(any( | |
| target_env = "newlib", | |
| target_os = "solaris", | |
| target_os = "illumos", | |
| target_os = "emscripten", | |
| target_os = "fuchsia", | |
| target_os = "l4re", | |
| target_os = "linux", | |
| target_os = "cygwin", | |
| target_os = "haiku", | |
| target_os = "redox", | |
| target_os = "vxworks", | |
| target_os = "nto", | |
| target_os = "wasi", | |
| )))] | |
| pub fn set_cloexec(&self) -> io::Result<()> { | |
| unsafe { | |
| cvt(libc::ioctl(self.as_raw_fd(), libc::FIOCLEX))?; | |
| Ok(()) | |
| } | |
| } | |
| #[cfg(any( | |
| all( | |
| target_env = "newlib", | |
| not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")) | |
| ), | |
| target_os = "solaris", | |
| target_os = "illumos", | |
| target_os = "emscripten", | |
| target_os = "fuchsia", | |
| target_os = "l4re", | |
| target_os = "linux", | |
| target_os = "cygwin", | |
| target_os = "haiku", | |
| target_os = "redox", | |
| target_os = "vxworks", | |
| target_os = "nto", | |
| target_os = "wasi", | |
| ))] | |
| pub fn set_cloexec(&self) -> io::Result<()> { | |
| unsafe { | |
| let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))?; | |
| let new = previous | libc::FD_CLOEXEC; | |
| if new != previous { | |
| cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFD, new))?; | |
| } | |
| Ok(()) | |
| } | |
| } | |
| #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] | |
| pub fn set_cloexec(&self) -> io::Result<()> { | |
| // FD_CLOEXEC is not supported in ESP-IDF, Horizon OS and Vita but there's no need to, | |
| // because none of them supports spawning processes. | |
| Ok(()) | |
| } | |
| #[cfg(target_os = "linux")] | |
| pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
| unsafe { | |
| let v = nonblocking as libc::c_int; | |
| cvt(libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &v))?; | |
| Ok(()) | |
| } | |
| } | |
| #[cfg(not(target_os = "linux"))] | |
| pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
| unsafe { | |
| let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFL))?; | |
| let new = if nonblocking { | |
| previous | libc::O_NONBLOCK | |
| } else { | |
| previous & !libc::O_NONBLOCK | |
| }; | |
| if new != previous { | |
| cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFL, new))?; | |
| } | |
| Ok(()) | |
| } | |
| } | |
| #[inline] | |
| pub fn duplicate(&self) -> io::Result<FileDesc> { | |
| Ok(Self(self.0.try_clone()?)) | |
| } | |
| } | |
| impl<'a> Read for &'a FileDesc { | |
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
| (**self).read(buf) | |
| } | |
| fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { | |
| (**self).read_buf(cursor) | |
| } | |
| fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { | |
| (**self).read_vectored(bufs) | |
| } | |
| #[inline] | |
| fn is_read_vectored(&self) -> bool { | |
| (**self).is_read_vectored() | |
| } | |
| } | |
| impl AsInner<OwnedFd> for FileDesc { | |
| #[inline] | |
| fn as_inner(&self) -> &OwnedFd { | |
| &self.0 | |
| } | |
| } | |
| impl IntoInner<OwnedFd> for FileDesc { | |
| fn into_inner(self) -> OwnedFd { | |
| self.0 | |
| } | |
| } | |
| impl FromInner<OwnedFd> for FileDesc { | |
| fn from_inner(owned_fd: OwnedFd) -> Self { | |
| Self(owned_fd) | |
| } | |
| } | |
| impl AsFd for FileDesc { | |
| fn as_fd(&self) -> BorrowedFd<'_> { | |
| self.0.as_fd() | |
| } | |
| } | |
| impl AsRawFd for FileDesc { | |
| #[inline] | |
| fn as_raw_fd(&self) -> RawFd { | |
| self.0.as_raw_fd() | |
| } | |
| } | |
| impl IntoRawFd for FileDesc { | |
| fn into_raw_fd(self) -> RawFd { | |
| self.0.into_raw_fd() | |
| } | |
| } | |
| impl FromRawFd for FileDesc { | |
| unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { | |
| Self(unsafe { FromRawFd::from_raw_fd(raw_fd) }) | |
| } | |
| } |