1
Fork 0

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:
Matthias Krüger 2022-01-25 05:51:09 +01:00 committed by GitHub
commit 687bb583c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 151 additions and 91 deletions

View file

@ -8,6 +8,8 @@ use crate::fmt;
use crate::fs; use crate::fs;
use crate::marker::PhantomData; use crate::marker::PhantomData;
use crate::mem::forget; use crate::mem::forget;
#[cfg(not(target_os = "wasi"))]
use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{AsInner, FromInner, IntoInner};
/// A borrowed file descriptor. /// 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")] #[unstable(feature = "io_safety", issue = "87074")]
impl AsRawFd for BorrowedFd<'_> { impl AsRawFd for BorrowedFd<'_> {
#[inline] #[inline]

View file

@ -6,9 +6,11 @@ use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
use crate::convert::TryFrom; use crate::convert::TryFrom;
use crate::fmt; use crate::fmt;
use crate::fs; use crate::fs;
use crate::io;
use crate::marker::PhantomData; use crate::marker::PhantomData;
use crate::mem::forget; use crate::mem::forget;
use crate::sys::c; use crate::sys::c;
use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{AsInner, FromInner, IntoInner};
/// A borrowed handle. /// 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 { impl TryFrom<HandleOrInvalid> for OwnedHandle {
type Error = (); type Error = ();

View file

@ -4,9 +4,13 @@
use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
use crate::fmt; use crate::fmt;
use crate::io;
use crate::marker::PhantomData; use crate::marker::PhantomData;
use crate::mem;
use crate::mem::forget; use crate::mem::forget;
use crate::sys;
use crate::sys::c; use crate::sys::c;
use crate::sys::cvt;
/// A borrowed socket. /// 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<'_> { impl AsRawSocket for BorrowedSocket<'_> {
#[inline] #[inline]
fn as_raw_socket(&self) -> RawSocket { fn as_raw_socket(&self) -> RawSocket {

View file

@ -259,22 +259,9 @@ impl FileDesc {
} }
} }
#[inline]
pub fn duplicate(&self) -> io::Result<FileDesc> { pub fn duplicate(&self) -> io::Result<FileDesc> {
// We want to atomically duplicate this file descriptor and set the Ok(Self(self.0.try_clone()?))
// 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) })
} }
} }

View file

@ -460,7 +460,7 @@ impl File {
} }
pub fn duplicate(&self) -> io::Result<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>( fn reparse_point<'a>(

View file

@ -262,26 +262,17 @@ impl Handle {
Ok(written as usize) Ok(written as usize)
} }
pub fn try_clone(&self) -> io::Result<Self> {
Ok(Self(self.0.try_clone()?))
}
pub fn duplicate( pub fn duplicate(
&self, &self,
access: c::DWORD, access: c::DWORD,
inherit: bool, inherit: bool,
options: c::DWORD, options: c::DWORD,
) -> io::Result<Handle> { ) -> io::Result<Self> {
let mut ret = 0 as c::HANDLE; Ok(Self(self.0.duplicate(access, inherit, options)?))
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)) }
} }
} }

View file

@ -134,7 +134,7 @@ impl Socket {
unsafe { unsafe {
let socket = Self::from_raw_socket(socket); let socket = Self::from_raw_socket(socket);
socket.set_no_inherit()?; socket.0.set_no_inherit()?;
Ok(socket) Ok(socket)
} }
} }
@ -213,52 +213,7 @@ impl Socket {
} }
pub fn duplicate(&self) -> io::Result<Socket> { pub fn duplicate(&self) -> io::Result<Socket> {
let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() }; Ok(Self(self.0.try_clone()?))
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)
}
}
} }
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { 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<()> { pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
let how = match how { let how = match how {
Shutdown::Write => c::SD_SEND, Shutdown::Write => c::SD_SEND,