#![allow(unsafe_code)]
use crate::imp::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
#[cfg(all(not(io_lifetimes_use_std), feature = "std"))]
use crate::imp::fd::{FromFd, IntoFd};
use crate::io::close;
use core::fmt;
use core::mem::{forget, ManuallyDrop};
#[repr(transparent)]
pub struct OwnedFd {
inner: ManuallyDrop<crate::imp::fd::OwnedFd>,
}
impl OwnedFd {
#[cfg(all(unix, not(target_os = "wasi")))]
pub fn try_clone(&self) -> crate::io::Result<Self> {
#[cfg(not(target_os = "espidf"))]
let fd = crate::fs::fcntl_dupfd_cloexec(self, 0)?;
#[cfg(target_os = "espidf")]
let fd = crate::fs::fcntl_dupfd(self)?;
Ok(fd)
}
#[cfg(target_os = "wasi")]
pub fn try_clone(&self) -> std::io::Result<Self> {
Err(std::io::Error::new(
std::io::ErrorKind::Unsupported,
"operation not supported on WASI yet",
))
}
#[cfg(target_os = "windows")]
pub fn try_clone(&self) -> std::io::Result<Self> {
use winapi::um::processthreadsapi::GetCurrentProcessId;
use winapi::um::winsock2::{
WSADuplicateSocketW, WSAGetLastError, WSASocketW, INVALID_SOCKET, SOCKET_ERROR,
WSAEINVAL, WSAEPROTOTYPE, WSAPROTOCOL_INFOW, WSA_FLAG_NO_HANDLE_INHERIT,
WSA_FLAG_OVERLAPPED,
};
let mut info = unsafe { std::mem::zeroed::<WSAPROTOCOL_INFOW>() };
let result =
unsafe { WSADuplicateSocketW(self.as_raw_fd() as _, GetCurrentProcessId(), &mut info) };
match result {
SOCKET_ERROR => return Err(std::io::Error::last_os_error()),
0 => (),
_ => panic!(),
}
let socket = unsafe {
WSASocketW(
info.iAddressFamily,
info.iSocketType,
info.iProtocol,
&mut info,
0,
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT,
)
};
if socket != INVALID_SOCKET {
unsafe { Ok(Self::from_raw_fd(socket as _)) }
} else {
let error = unsafe { WSAGetLastError() };
if error != WSAEPROTOTYPE && error != WSAEINVAL {
return Err(std::io::Error::from_raw_os_error(error));
}
let socket = unsafe {
WSASocketW(
info.iAddressFamily,
info.iSocketType,
info.iProtocol,
&mut info,
0,
WSA_FLAG_OVERLAPPED,
)
};
if socket == INVALID_SOCKET {
return Err(std::io::Error::last_os_error());
}
unsafe {
let socket = Self::from_raw_fd(socket as _);
socket.set_no_inherit()?;
Ok(socket)
}
}
}
#[cfg(windows)]
#[cfg(not(target_vendor = "uwp"))]
fn set_no_inherit(&self) -> std::io::Result<()> {
use winapi::um::handleapi::SetHandleInformation;
use winapi::um::winbase::HANDLE_FLAG_INHERIT;
use winapi::um::winnt::HANDLE;
match unsafe { SetHandleInformation(self.as_raw_fd() as HANDLE, HANDLE_FLAG_INHERIT, 0) } {
0 => return Err(std::io::Error::last_os_error()),
_ => Ok(()),
}
}
#[cfg(windows)]
#[cfg(target_vendor = "uwp")]
fn set_no_inherit(&self) -> std::io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Unsupported,
"Unavailable on UWP",
))
}
}
#[cfg(not(windows))]
impl AsFd for OwnedFd {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.inner.as_fd()
}
}
#[cfg(windows)]
impl io_lifetimes::AsSocket for OwnedFd {
#[inline]
fn as_socket(&self) -> BorrowedFd<'_> {
self.inner.as_socket()
}
}
#[cfg(io_lifetimes_use_std)]
impl From<OwnedFd> for crate::imp::fd::OwnedFd {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
let raw_fd = owned_fd.inner.as_fd().as_raw_fd();
forget(owned_fd);
unsafe { crate::imp::fd::OwnedFd::from_raw_fd(raw_fd) }
}
}
#[cfg(not(any(io_lifetimes_use_std, not(feature = "std"))))]
impl IntoFd for OwnedFd {
#[inline]
fn into_fd(self) -> crate::imp::fd::OwnedFd {
let raw_fd = self.inner.as_fd().as_raw_fd();
forget(self);
unsafe { crate::imp::fd::OwnedFd::from_raw_fd(raw_fd) }
}
}
#[cfg(any(io_lifetimes_use_std, not(feature = "std")))]
impl From<crate::imp::fd::OwnedFd> for OwnedFd {
#[inline]
fn from(owned_fd: crate::imp::fd::OwnedFd) -> Self {
Self {
inner: ManuallyDrop::new(owned_fd),
}
}
}
#[cfg(all(not(io_lifetimes_use_std), feature = "std"))]
impl FromFd for OwnedFd {
#[inline]
fn from_fd(owned_fd: crate::imp::fd::OwnedFd) -> Self {
Self {
inner: ManuallyDrop::new(owned_fd),
}
}
}
#[cfg(not(any(io_lifetimes_use_std, not(feature = "std"))))]
impl From<crate::imp::fd::OwnedFd> for OwnedFd {
#[inline]
fn from(fd: crate::imp::fd::OwnedFd) -> Self {
Self {
inner: ManuallyDrop::new(fd),
}
}
}
#[cfg(not(any(io_lifetimes_use_std, not(feature = "std"))))]
impl From<OwnedFd> for crate::imp::fd::OwnedFd {
#[inline]
fn from(fd: OwnedFd) -> Self {
let raw_fd = fd.inner.as_fd().as_raw_fd();
forget(fd);
unsafe { crate::imp::fd::OwnedFd::from_raw_fd(raw_fd) }
}
}
impl AsRawFd for OwnedFd {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}
impl IntoRawFd for OwnedFd {
#[inline]
fn into_raw_fd(self) -> RawFd {
let raw_fd = self.inner.as_fd().as_raw_fd();
forget(self);
raw_fd
}
}
impl FromRawFd for OwnedFd {
#[inline]
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
Self {
inner: ManuallyDrop::new(crate::imp::fd::OwnedFd::from_raw_fd(raw_fd)),
}
}
}
impl Drop for OwnedFd {
#[inline]
fn drop(&mut self) {
unsafe {
close(self.as_fd().as_raw_fd());
}
}
}
impl fmt::Debug for OwnedFd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}