Skip to content

Commit 18c14ad

Browse files
committed
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.
1 parent 497ee32 commit 18c14ad

File tree

7 files changed

+115
-76
lines changed

7 files changed

+115
-76
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

+33
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::marker::PhantomData;
1111
use crate::mem::forget;
1212
use crate::ptr::NonNull;
1313
use crate::sys::c;
14+
use crate::sys::cvt;
1415
use crate::sys_common::{AsInner, FromInner, IntoInner};
1516

1617
/// A borrowed handle.
@@ -110,6 +111,38 @@ impl BorrowedHandle<'_> {
110111
}
111112
}
112113

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

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

+54
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::fmt;
77
use crate::marker::PhantomData;
88
use crate::mem::forget;
99
use crate::sys::c;
10+
use crate::sys::cvt;
1011

1112
/// A borrowed socket.
1213
///
@@ -69,6 +70,59 @@ impl BorrowedSocket<'_> {
6970
}
7071
}
7172

73+
impl OwnedSocket {
74+
/// Creates a new `OwnedSocket` instance that shares the same underlying socket
75+
/// as the existing `OwnedSocket` instance.
76+
pub fn try_clone(&self) -> io::Result<Self> {
77+
let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
78+
let result = unsafe {
79+
c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
80+
};
81+
cvt(result)?;
82+
let socket = unsafe {
83+
c::WSASocketW(
84+
info.iAddressFamily,
85+
info.iSocketType,
86+
info.iProtocol,
87+
&mut info,
88+
0,
89+
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
90+
)
91+
};
92+
93+
if socket != c::INVALID_SOCKET {
94+
unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) }
95+
} else {
96+
let error = unsafe { c::WSAGetLastError() };
97+
98+
if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
99+
return Err(io::Error::from_raw_os_error(error));
100+
}
101+
102+
let socket = unsafe {
103+
c::WSASocketW(
104+
info.iAddressFamily,
105+
info.iSocketType,
106+
info.iProtocol,
107+
&mut info,
108+
0,
109+
c::WSA_FLAG_OVERLAPPED,
110+
)
111+
};
112+
113+
if socket == c::INVALID_SOCKET {
114+
return Err(last_error());
115+
}
116+
117+
unsafe {
118+
let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket));
119+
socket.set_no_inherit()?;
120+
Ok(socket)
121+
}
122+
}
123+
}
124+
}
125+
72126
impl AsRawSocket for BorrowedSocket<'_> {
73127
#[inline]
74128
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(self.0.try_clone()?))
459459
}
460460

461461
fn reparse_point<'a>(

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

+1-14
Original file line numberDiff line numberDiff line change
@@ -235,20 +235,7 @@ impl Handle {
235235
inherit: bool,
236236
options: c::DWORD,
237237
) -> 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)) }
238+
Ok(Self(self.0.duplicate(access, inherit, options)?))
252239
}
253240
}
254241

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

+1-46
Original file line numberDiff line numberDiff line change
@@ -208,52 +208,7 @@ impl Socket {
208208
}
209209

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

259214
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {

0 commit comments

Comments
 (0)