Rollup merge of #88794 - sunfishcode:sunfishcode/try-clone, r=joshtriplett
Add a `try_clone()` function to `OwnedFd`. As suggested in #88564. This adds a `try_clone()` to `OwnedFd` by refactoring the code out of the existing `File`/`Socket` code. r? ``@joshtriplett``
This commit is contained in:
commit
687bb583c8
7 changed files with 151 additions and 91 deletions
|
@ -8,6 +8,8 @@ use crate::fmt;
|
|||
use crate::fs;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::forget;
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
use crate::sys::cvt;
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
|
||||
/// A borrowed file descriptor.
|
||||
|
@ -67,6 +69,37 @@ impl BorrowedFd<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl OwnedFd {
|
||||
/// Creates a new `OwnedFd` instance that shares the same underlying file handle
|
||||
/// as the existing `OwnedFd` instance.
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
pub fn try_clone(&self) -> crate::io::Result<Self> {
|
||||
// We want to atomically duplicate this file descriptor and set the
|
||||
// CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
|
||||
// is a POSIX flag that was added to Linux in 2.6.24.
|
||||
#[cfg(not(target_os = "espidf"))]
|
||||
let cmd = libc::F_DUPFD_CLOEXEC;
|
||||
|
||||
// For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
|
||||
// will never be supported, as this is a bare metal framework with
|
||||
// no capabilities for multi-process execution. While F_DUPFD is also
|
||||
// not supported yet, it might be (currently it returns ENOSYS).
|
||||
#[cfg(target_os = "espidf")]
|
||||
let cmd = libc::F_DUPFD;
|
||||
|
||||
let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
|
||||
Ok(unsafe { Self::from_raw_fd(fd) })
|
||||
}
|
||||
|
||||
#[cfg(target_os = "wasi")]
|
||||
pub fn try_clone(&self) -> crate::io::Result<Self> {
|
||||
Err(crate::io::Error::new_const(
|
||||
crate::io::ErrorKind::Unsupported,
|
||||
&"operation not supported on WASI yet",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "io_safety", issue = "87074")]
|
||||
impl AsRawFd for BorrowedFd<'_> {
|
||||
#[inline]
|
||||
|
|
|
@ -6,9 +6,11 @@ use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
|
|||
use crate::convert::TryFrom;
|
||||
use crate::fmt;
|
||||
use crate::fs;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::forget;
|
||||
use crate::sys::c;
|
||||
use crate::sys::cvt;
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
|
||||
/// A borrowed handle.
|
||||
|
@ -144,6 +146,36 @@ impl TryFrom<HandleOrNull> for OwnedHandle {
|
|||
}
|
||||
}
|
||||
|
||||
impl OwnedHandle {
|
||||
/// Creates a new `OwnedHandle` instance that shares the same underlying file handle
|
||||
/// as the existing `OwnedHandle` instance.
|
||||
pub fn try_clone(&self) -> crate::io::Result<Self> {
|
||||
self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)
|
||||
}
|
||||
|
||||
pub(crate) fn duplicate(
|
||||
&self,
|
||||
access: c::DWORD,
|
||||
inherit: bool,
|
||||
options: c::DWORD,
|
||||
) -> io::Result<Self> {
|
||||
let mut ret = 0 as c::HANDLE;
|
||||
cvt(unsafe {
|
||||
let cur_proc = c::GetCurrentProcess();
|
||||
c::DuplicateHandle(
|
||||
cur_proc,
|
||||
self.as_raw_handle(),
|
||||
cur_proc,
|
||||
&mut ret,
|
||||
access,
|
||||
inherit as c::BOOL,
|
||||
options,
|
||||
)
|
||||
})?;
|
||||
unsafe { Ok(Self::from_raw_handle(ret)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<HandleOrInvalid> for OwnedHandle {
|
||||
type Error = ();
|
||||
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
|
||||
use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
|
||||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem;
|
||||
use crate::mem::forget;
|
||||
use crate::sys;
|
||||
use crate::sys::c;
|
||||
use crate::sys::cvt;
|
||||
|
||||
/// A borrowed socket.
|
||||
///
|
||||
|
@ -69,6 +73,77 @@ impl BorrowedSocket<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl OwnedSocket {
|
||||
/// Creates a new `OwnedSocket` instance that shares the same underlying socket
|
||||
/// as the existing `OwnedSocket` instance.
|
||||
pub fn try_clone(&self) -> io::Result<Self> {
|
||||
let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
|
||||
let result = unsafe {
|
||||
c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
|
||||
};
|
||||
sys::net::cvt(result)?;
|
||||
let socket = unsafe {
|
||||
c::WSASocketW(
|
||||
info.iAddressFamily,
|
||||
info.iSocketType,
|
||||
info.iProtocol,
|
||||
&mut info,
|
||||
0,
|
||||
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
|
||||
)
|
||||
};
|
||||
|
||||
if socket != c::INVALID_SOCKET {
|
||||
unsafe { Ok(OwnedSocket::from_raw_socket(socket)) }
|
||||
} else {
|
||||
let error = unsafe { c::WSAGetLastError() };
|
||||
|
||||
if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
|
||||
return Err(io::Error::from_raw_os_error(error));
|
||||
}
|
||||
|
||||
let socket = unsafe {
|
||||
c::WSASocketW(
|
||||
info.iAddressFamily,
|
||||
info.iSocketType,
|
||||
info.iProtocol,
|
||||
&mut info,
|
||||
0,
|
||||
c::WSA_FLAG_OVERLAPPED,
|
||||
)
|
||||
};
|
||||
|
||||
if socket == c::INVALID_SOCKET {
|
||||
return Err(last_error());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let socket = OwnedSocket::from_raw_socket(socket);
|
||||
socket.set_no_inherit()?;
|
||||
Ok(socket)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_vendor = "uwp"))]
|
||||
pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
|
||||
cvt(unsafe {
|
||||
c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
#[cfg(target_vendor = "uwp")]
|
||||
pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
|
||||
Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the last error from the Windows socket interface.
|
||||
fn last_error() -> io::Error {
|
||||
io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
|
||||
}
|
||||
|
||||
impl AsRawSocket for BorrowedSocket<'_> {
|
||||
#[inline]
|
||||
fn as_raw_socket(&self) -> RawSocket {
|
||||
|
|
|
@ -259,22 +259,9 @@ impl FileDesc {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn duplicate(&self) -> io::Result<FileDesc> {
|
||||
// We want to atomically duplicate this file descriptor and set the
|
||||
// CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
|
||||
// is a POSIX flag that was added to Linux in 2.6.24.
|
||||
#[cfg(not(target_os = "espidf"))]
|
||||
let cmd = libc::F_DUPFD_CLOEXEC;
|
||||
|
||||
// For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
|
||||
// will never be supported, as this is a bare metal framework with
|
||||
// no capabilities for multi-process execution. While F_DUPFD is also
|
||||
// not supported yet, it might be (currently it returns ENOSYS).
|
||||
#[cfg(target_os = "espidf")]
|
||||
let cmd = libc::F_DUPFD;
|
||||
|
||||
let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
|
||||
Ok(unsafe { FileDesc::from_raw_fd(fd) })
|
||||
Ok(Self(self.0.try_clone()?))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -460,7 +460,7 @@ impl File {
|
|||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<File> {
|
||||
Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? })
|
||||
Ok(Self { handle: self.handle.try_clone()? })
|
||||
}
|
||||
|
||||
fn reparse_point<'a>(
|
||||
|
|
|
@ -262,26 +262,17 @@ impl Handle {
|
|||
Ok(written as usize)
|
||||
}
|
||||
|
||||
pub fn try_clone(&self) -> io::Result<Self> {
|
||||
Ok(Self(self.0.try_clone()?))
|
||||
}
|
||||
|
||||
pub fn duplicate(
|
||||
&self,
|
||||
access: c::DWORD,
|
||||
inherit: bool,
|
||||
options: c::DWORD,
|
||||
) -> io::Result<Handle> {
|
||||
let mut ret = 0 as c::HANDLE;
|
||||
cvt(unsafe {
|
||||
let cur_proc = c::GetCurrentProcess();
|
||||
c::DuplicateHandle(
|
||||
cur_proc,
|
||||
self.as_raw_handle(),
|
||||
cur_proc,
|
||||
&mut ret,
|
||||
access,
|
||||
inherit as c::BOOL,
|
||||
options,
|
||||
)
|
||||
})?;
|
||||
unsafe { Ok(Handle::from_raw_handle(ret)) }
|
||||
) -> io::Result<Self> {
|
||||
Ok(Self(self.0.duplicate(access, inherit, options)?))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ impl Socket {
|
|||
|
||||
unsafe {
|
||||
let socket = Self::from_raw_socket(socket);
|
||||
socket.set_no_inherit()?;
|
||||
socket.0.set_no_inherit()?;
|
||||
Ok(socket)
|
||||
}
|
||||
}
|
||||
|
@ -213,52 +213,7 @@ impl Socket {
|
|||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<Socket> {
|
||||
let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
|
||||
let result = unsafe {
|
||||
c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
|
||||
};
|
||||
cvt(result)?;
|
||||
let socket = unsafe {
|
||||
c::WSASocketW(
|
||||
info.iAddressFamily,
|
||||
info.iSocketType,
|
||||
info.iProtocol,
|
||||
&mut info,
|
||||
0,
|
||||
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
|
||||
)
|
||||
};
|
||||
|
||||
if socket != c::INVALID_SOCKET {
|
||||
unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) }
|
||||
} else {
|
||||
let error = unsafe { c::WSAGetLastError() };
|
||||
|
||||
if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
|
||||
return Err(io::Error::from_raw_os_error(error));
|
||||
}
|
||||
|
||||
let socket = unsafe {
|
||||
c::WSASocketW(
|
||||
info.iAddressFamily,
|
||||
info.iSocketType,
|
||||
info.iProtocol,
|
||||
&mut info,
|
||||
0,
|
||||
c::WSA_FLAG_OVERLAPPED,
|
||||
)
|
||||
};
|
||||
|
||||
if socket == c::INVALID_SOCKET {
|
||||
return Err(last_error());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket));
|
||||
socket.set_no_inherit()?;
|
||||
Ok(socket)
|
||||
}
|
||||
}
|
||||
Ok(Self(self.0.try_clone()?))
|
||||
}
|
||||
|
||||
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
|
||||
|
@ -421,19 +376,6 @@ impl Socket {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_vendor = "uwp"))]
|
||||
fn set_no_inherit(&self) -> io::Result<()> {
|
||||
sys::cvt(unsafe {
|
||||
c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
#[cfg(target_vendor = "uwp")]
|
||||
fn set_no_inherit(&self) -> io::Result<()> {
|
||||
Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
|
||||
}
|
||||
|
||||
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
|
||||
let how = match how {
|
||||
Shutdown::Write => c::SD_SEND,
|
||||
|
|
Loading…
Add table
Reference in a new issue