Skip to content

Commit 0eedc9d

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 4b674fa + 53e072f commit 0eedc9d

File tree

7 files changed

+150
-91
lines changed

7 files changed

+150
-91
lines changed

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]

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

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
@@ -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

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>(

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

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)