Skip to content

Commit

Permalink
Rollup merge of #88794 - sunfishcode:sunfishcode/try-clone, r=joshtri…
Browse files Browse the repository at this point in the history
…plett

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``
  • Loading branch information
matthiaskrgr committed Jan 25, 2022
2 parents e7825f2 + 83aebf8 commit 687bb58
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 91 deletions.
33 changes: 33 additions & 0 deletions library/std/src/os/fd/owned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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]
Expand Down
32 changes: 32 additions & 0 deletions library/std/src/os/windows/io/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 = ();

Expand Down
75 changes: 75 additions & 0 deletions library/std/src/os/windows/io/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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 {
Expand Down
17 changes: 2 additions & 15 deletions library/std/src/sys/unix/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()?))
}
}

Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
Expand Down
21 changes: 6 additions & 15 deletions library/std/src/sys/windows/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?))
}
}

Expand Down
62 changes: 2 additions & 60 deletions library/std/src/sys/windows/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 687bb58

Please sign in to comment.