Skip to content

Commit 687bb58

Browse files
authoredJan 25, 2022
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``
2 parents e7825f2 + 83aebf8 commit 687bb58

File tree

7 files changed

+151
-91
lines changed

7 files changed

+151
-91
lines changed
 

Diff for: ‎library/std/src/os/fd/owned.rs

+33
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use crate::fmt;
88
use crate::fs;
99
use crate::marker::PhantomData;
1010
use crate::mem::forget;
11+
#[cfg(not(target_os = "wasi"))]
12+
use crate::sys::cvt;
1113
use crate::sys_common::{AsInner, FromInner, IntoInner};
1214

1315
/// A borrowed file descriptor.
@@ -67,6 +69,37 @@ impl BorrowedFd<'_> {
6769
}
6870
}
6971

72+
impl OwnedFd {
73+
/// Creates a new `OwnedFd` instance that shares the same underlying file handle
74+
/// as the existing `OwnedFd` instance.
75+
#[cfg(not(target_os = "wasi"))]
76+
pub fn try_clone(&self) -> crate::io::Result<Self> {
77+
// We want to atomically duplicate this file descriptor and set the
78+
// CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
79+
// is a POSIX flag that was added to Linux in 2.6.24.
80+
#[cfg(not(target_os = "espidf"))]
81+
let cmd = libc::F_DUPFD_CLOEXEC;
82+
83+
// For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
84+
// will never be supported, as this is a bare metal framework with
85+
// no capabilities for multi-process execution. While F_DUPFD is also
86+
// not supported yet, it might be (currently it returns ENOSYS).
87+
#[cfg(target_os = "espidf")]
88+
let cmd = libc::F_DUPFD;
89+
90+
let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
91+
Ok(unsafe { Self::from_raw_fd(fd) })
92+
}
93+
94+
#[cfg(target_os = "wasi")]
95+
pub fn try_clone(&self) -> crate::io::Result<Self> {
96+
Err(crate::io::Error::new_const(
97+
crate::io::ErrorKind::Unsupported,
98+
&"operation not supported on WASI yet",
99+
))
100+
}
101+
}
102+
70103
#[unstable(feature = "io_safety", issue = "87074")]
71104
impl AsRawFd for BorrowedFd<'_> {
72105
#[inline]

Diff for: ‎library/std/src/os/windows/io/handle.rs

+32
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
66
use crate::convert::TryFrom;
77
use crate::fmt;
88
use crate::fs;
9+
use crate::io;
910
use crate::marker::PhantomData;
1011
use crate::mem::forget;
1112
use crate::sys::c;
13+
use crate::sys::cvt;
1214
use crate::sys_common::{AsInner, FromInner, IntoInner};
1315

1416
/// A borrowed handle.
@@ -144,6 +146,36 @@ impl TryFrom<HandleOrNull> for OwnedHandle {
144146
}
145147
}
146148

149+
impl OwnedHandle {
150+
/// Creates a new `OwnedHandle` instance that shares the same underlying file handle
151+
/// as the existing `OwnedHandle` instance.
152+
pub fn try_clone(&self) -> crate::io::Result<Self> {
153+
self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)
154+
}
155+
156+
pub(crate) fn duplicate(
157+
&self,
158+
access: c::DWORD,
159+
inherit: bool,
160+
options: c::DWORD,
161+
) -> io::Result<Self> {
162+
let mut ret = 0 as c::HANDLE;
163+
cvt(unsafe {
164+
let cur_proc = c::GetCurrentProcess();
165+
c::DuplicateHandle(
166+
cur_proc,
167+
self.as_raw_handle(),
168+
cur_proc,
169+
&mut ret,
170+
access,
171+
inherit as c::BOOL,
172+
options,
173+
)
174+
})?;
175+
unsafe { Ok(Self::from_raw_handle(ret)) }
176+
}
177+
}
178+
147179
impl TryFrom<HandleOrInvalid> for OwnedHandle {
148180
type Error = ();
149181

Diff for: ‎library/std/src/os/windows/io/socket.rs

+75
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
66
use crate::fmt;
7+
use crate::io;
78
use crate::marker::PhantomData;
9+
use crate::mem;
810
use crate::mem::forget;
11+
use crate::sys;
912
use crate::sys::c;
13+
use crate::sys::cvt;
1014

1115
/// A borrowed socket.
1216
///
@@ -69,6 +73,77 @@ impl BorrowedSocket<'_> {
6973
}
7074
}
7175

76+
impl OwnedSocket {
77+
/// Creates a new `OwnedSocket` instance that shares the same underlying socket
78+
/// as the existing `OwnedSocket` instance.
79+
pub fn try_clone(&self) -> io::Result<Self> {
80+
let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
81+
let result = unsafe {
82+
c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
83+
};
84+
sys::net::cvt(result)?;
85+
let socket = unsafe {
86+
c::WSASocketW(
87+
info.iAddressFamily,
88+
info.iSocketType,
89+
info.iProtocol,
90+
&mut info,
91+
0,
92+
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
93+
)
94+
};
95+
96+
if socket != c::INVALID_SOCKET {
97+
unsafe { Ok(OwnedSocket::from_raw_socket(socket)) }
98+
} else {
99+
let error = unsafe { c::WSAGetLastError() };
100+
101+
if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
102+
return Err(io::Error::from_raw_os_error(error));
103+
}
104+
105+
let socket = unsafe {
106+
c::WSASocketW(
107+
info.iAddressFamily,
108+
info.iSocketType,
109+
info.iProtocol,
110+
&mut info,
111+
0,
112+
c::WSA_FLAG_OVERLAPPED,
113+
)
114+
};
115+
116+
if socket == c::INVALID_SOCKET {
117+
return Err(last_error());
118+
}
119+
120+
unsafe {
121+
let socket = OwnedSocket::from_raw_socket(socket);
122+
socket.set_no_inherit()?;
123+
Ok(socket)
124+
}
125+
}
126+
}
127+
128+
#[cfg(not(target_vendor = "uwp"))]
129+
pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
130+
cvt(unsafe {
131+
c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
132+
})
133+
.map(drop)
134+
}
135+
136+
#[cfg(target_vendor = "uwp")]
137+
pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
138+
Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
139+
}
140+
}
141+
142+
/// Returns the last error from the Windows socket interface.
143+
fn last_error() -> io::Error {
144+
io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
145+
}
146+
72147
impl AsRawSocket for BorrowedSocket<'_> {
73148
#[inline]
74149
fn as_raw_socket(&self) -> RawSocket {

Diff for: ‎library/std/src/sys/unix/fd.rs

+2-15
Original file line numberDiff line numberDiff line change
@@ -259,22 +259,9 @@ impl FileDesc {
259259
}
260260
}
261261

262+
#[inline]
262263
pub fn duplicate(&self) -> io::Result<FileDesc> {
263-
// We want to atomically duplicate this file descriptor and set the
264-
// CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
265-
// is a POSIX flag that was added to Linux in 2.6.24.
266-
#[cfg(not(target_os = "espidf"))]
267-
let cmd = libc::F_DUPFD_CLOEXEC;
268-
269-
// For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
270-
// will never be supported, as this is a bare metal framework with
271-
// no capabilities for multi-process execution. While F_DUPFD is also
272-
// not supported yet, it might be (currently it returns ENOSYS).
273-
#[cfg(target_os = "espidf")]
274-
let cmd = libc::F_DUPFD;
275-
276-
let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
277-
Ok(unsafe { FileDesc::from_raw_fd(fd) })
264+
Ok(Self(self.0.try_clone()?))
278265
}
279266
}
280267

Diff for: ‎library/std/src/sys/windows/fs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ impl File {
460460
}
461461

462462
pub fn duplicate(&self) -> io::Result<File> {
463-
Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? })
463+
Ok(Self { handle: self.handle.try_clone()? })
464464
}
465465

466466
fn reparse_point<'a>(

Diff for: ‎library/std/src/sys/windows/handle.rs

+6-15
Original file line numberDiff line numberDiff line change
@@ -262,26 +262,17 @@ impl Handle {
262262
Ok(written as usize)
263263
}
264264

265+
pub fn try_clone(&self) -> io::Result<Self> {
266+
Ok(Self(self.0.try_clone()?))
267+
}
268+
265269
pub fn duplicate(
266270
&self,
267271
access: c::DWORD,
268272
inherit: bool,
269273
options: c::DWORD,
270-
) -> io::Result<Handle> {
271-
let mut ret = 0 as c::HANDLE;
272-
cvt(unsafe {
273-
let cur_proc = c::GetCurrentProcess();
274-
c::DuplicateHandle(
275-
cur_proc,
276-
self.as_raw_handle(),
277-
cur_proc,
278-
&mut ret,
279-
access,
280-
inherit as c::BOOL,
281-
options,
282-
)
283-
})?;
284-
unsafe { Ok(Handle::from_raw_handle(ret)) }
274+
) -> io::Result<Self> {
275+
Ok(Self(self.0.duplicate(access, inherit, options)?))
285276
}
286277
}
287278

Diff for: ‎library/std/src/sys/windows/net.rs

+2-60
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl Socket {
134134

135135
unsafe {
136136
let socket = Self::from_raw_socket(socket);
137-
socket.set_no_inherit()?;
137+
socket.0.set_no_inherit()?;
138138
Ok(socket)
139139
}
140140
}
@@ -213,52 +213,7 @@ impl Socket {
213213
}
214214

215215
pub fn duplicate(&self) -> io::Result<Socket> {
216-
let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
217-
let result = unsafe {
218-
c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
219-
};
220-
cvt(result)?;
221-
let socket = unsafe {
222-
c::WSASocketW(
223-
info.iAddressFamily,
224-
info.iSocketType,
225-
info.iProtocol,
226-
&mut info,
227-
0,
228-
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
229-
)
230-
};
231-
232-
if socket != c::INVALID_SOCKET {
233-
unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) }
234-
} else {
235-
let error = unsafe { c::WSAGetLastError() };
236-
237-
if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
238-
return Err(io::Error::from_raw_os_error(error));
239-
}
240-
241-
let socket = unsafe {
242-
c::WSASocketW(
243-
info.iAddressFamily,
244-
info.iSocketType,
245-
info.iProtocol,
246-
&mut info,
247-
0,
248-
c::WSA_FLAG_OVERLAPPED,
249-
)
250-
};
251-
252-
if socket == c::INVALID_SOCKET {
253-
return Err(last_error());
254-
}
255-
256-
unsafe {
257-
let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket));
258-
socket.set_no_inherit()?;
259-
Ok(socket)
260-
}
261-
}
216+
Ok(Self(self.0.try_clone()?))
262217
}
263218

264219
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
@@ -421,19 +376,6 @@ impl Socket {
421376
}
422377
}
423378

424-
#[cfg(not(target_vendor = "uwp"))]
425-
fn set_no_inherit(&self) -> io::Result<()> {
426-
sys::cvt(unsafe {
427-
c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
428-
})
429-
.map(drop)
430-
}
431-
432-
#[cfg(target_vendor = "uwp")]
433-
fn set_no_inherit(&self) -> io::Result<()> {
434-
Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
435-
}
436-
437379
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
438380
let how = match how {
439381
Shutdown::Write => c::SD_SEND,

0 commit comments

Comments
 (0)
Please sign in to comment.