Skip to content

Commit b5301d8

Browse files
authored
Rollup merge of rust-lang#88794 - sunfishcode:sunfishcode/try-clone, r=joshtriplett
Add a `try_clone()` function to `OwnedFd`. As suggested in rust-lang#88564. This adds a `try_clone()` to `OwnedFd` by refactoring the code out of the existing `File`/`Socket` code. r? `@joshtriplett`
2 parents fe0759f + 2d6a4c8 commit b5301d8

File tree

7 files changed

+140
-91
lines changed

7 files changed

+140
-91
lines changed

library/std/src/os/fd/owned.rs

+23
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::fmt;
88
use crate::fs;
99
use crate::marker::PhantomData;
1010
use crate::mem::forget;
11+
use crate::sys::cvt;
1112
use crate::sys_common::{AsInner, FromInner, IntoInner};
1213

1314
/// A borrowed file descriptor.
@@ -67,6 +68,28 @@ impl BorrowedFd<'_> {
6768
}
6869
}
6970

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

library/std/src/os/windows/io/handle.rs

+32
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ use crate::convert::TryFrom;
77
use crate::ffi::c_void;
88
use crate::fmt;
99
use crate::fs;
10+
use crate::io;
1011
use crate::marker::PhantomData;
1112
use crate::mem::forget;
1213
use crate::ptr::NonNull;
1314
use crate::sys::c;
15+
use crate::sys::cvt;
1416
use crate::sys_common::{AsInner, FromInner, IntoInner};
1517

1618
/// A borrowed handle.
@@ -110,6 +112,36 @@ impl BorrowedHandle<'_> {
110112
}
111113
}
112114

115+
impl OwnedHandle {
116+
/// Creates a new `OwnedHandle` instance that shares the same underlying file handle
117+
/// as the existing `OwnedHandle` instance.
118+
pub fn try_clone(&self) -> crate::io::Result<Self> {
119+
self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)
120+
}
121+
122+
pub(crate) fn duplicate(
123+
&self,
124+
access: c::DWORD,
125+
inherit: bool,
126+
options: c::DWORD,
127+
) -> io::Result<Self> {
128+
let mut ret = 0 as c::HANDLE;
129+
cvt(unsafe {
130+
let cur_proc = c::GetCurrentProcess();
131+
c::DuplicateHandle(
132+
cur_proc,
133+
self.as_raw_handle(),
134+
cur_proc,
135+
&mut ret,
136+
access,
137+
inherit as c::BOOL,
138+
options,
139+
)
140+
})?;
141+
unsafe { Ok(Self::from_raw_handle(ret)) }
142+
}
143+
}
144+
113145
impl TryFrom<HandleOrInvalid> for OwnedHandle {
114146
type Error = ();
115147

library/std/src/os/windows/io/socket.rs

+74
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
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;
911
use crate::sys::c;
12+
use crate::sys::cvt;
1013

1114
/// A borrowed socket.
1215
///
@@ -69,6 +72,77 @@ impl BorrowedSocket<'_> {
6972
}
7073
}
7174

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

library/std/src/sys/unix/fd.rs

+2-15
Original file line numberDiff line numberDiff line change
@@ -266,22 +266,9 @@ impl FileDesc {
266266
}
267267
}
268268

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

library/std/src/sys/windows/fs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ impl File {
455455
}
456456

457457
pub fn duplicate(&self) -> io::Result<File> {
458-
Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? })
458+
Ok(Self { handle: self.handle.try_clone()? })
459459
}
460460

461461
fn reparse_point<'a>(

library/std/src/sys/windows/handle.rs

+6-15
Original file line numberDiff line numberDiff line change
@@ -229,26 +229,17 @@ impl Handle {
229229
Ok(written as usize)
230230
}
231231

232+
pub fn try_clone(&self) -> io::Result<Self> {
233+
Ok(Self(self.0.try_clone()?))
234+
}
235+
232236
pub fn duplicate(
233237
&self,
234238
access: c::DWORD,
235239
inherit: bool,
236240
options: c::DWORD,
237-
) -> io::Result<Handle> {
238-
let mut ret = 0 as c::HANDLE;
239-
cvt(unsafe {
240-
let cur_proc = c::GetCurrentProcess();
241-
c::DuplicateHandle(
242-
cur_proc,
243-
self.as_raw_handle(),
244-
cur_proc,
245-
&mut ret,
246-
access,
247-
inherit as c::BOOL,
248-
options,
249-
)
250-
})?;
251-
unsafe { Ok(Handle::from_raw_handle(ret)) }
241+
) -> io::Result<Self> {
242+
Ok(Self(self.0.duplicate(access, inherit, options)?))
252243
}
253244
}
254245

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)