@@ -14,7 +14,27 @@ use std::{
1414 } ,
1515} ;
1616#[ cfg( all( windows, feature = "close" ) ) ]
17- use winapi:: { um:: handleapi:: INVALID_HANDLE_VALUE , um:: winsock2:: INVALID_SOCKET } ;
17+ use winapi:: {
18+ shared:: minwindef:: { BOOL , DWORD } ,
19+ shared:: ntdef:: HANDLE ,
20+ um:: handleapi:: DuplicateHandle ,
21+ um:: handleapi:: SetHandleInformation ,
22+ um:: handleapi:: INVALID_HANDLE_VALUE ,
23+ um:: processthreadsapi:: GetCurrentProcess ,
24+ um:: processthreadsapi:: GetCurrentProcessId ,
25+ um:: winbase:: HANDLE_FLAG_INHERIT ,
26+ um:: winnt:: DUPLICATE_SAME_ACCESS ,
27+ um:: winsock2:: WSADuplicateSocketW ,
28+ um:: winsock2:: WSAGetLastError ,
29+ um:: winsock2:: WSASocketW ,
30+ um:: winsock2:: INVALID_SOCKET ,
31+ um:: winsock2:: SOCKET_ERROR ,
32+ um:: winsock2:: WSAEINVAL ,
33+ um:: winsock2:: WSAEPROTOTYPE ,
34+ um:: winsock2:: WSAPROTOCOL_INFOW ,
35+ um:: winsock2:: WSA_FLAG_NO_HANDLE_INHERIT ,
36+ um:: winsock2:: WSA_FLAG_OVERLAPPED ,
37+ } ;
1838
1939#[ cfg( all( windows, not( feature = "winapi" ) ) ) ]
2040const INVALID_HANDLE_VALUE : * mut core:: ffi:: c_void = !0 as _ ;
@@ -110,6 +130,42 @@ pub struct OwnedFd {
110130 fd : RawFd ,
111131}
112132
133+ #[ cfg( any( unix, target_os = "wasi" ) ) ]
134+ impl OwnedFd {
135+ /// Creates a new `OwnedFd` instance that shares the same underlying file handle
136+ /// as the existing `OwnedFd` instance.
137+ pub fn try_clone ( & self ) -> std:: io:: Result < Self > {
138+ #[ cfg( feature = "close" ) ]
139+ {
140+ // We want to atomically duplicate this file descriptor and set the
141+ // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
142+ // is a POSIX flag that was added to Linux in 2.6.24.
143+ #[ cfg( not( target_os = "espidf" ) ) ]
144+ let cmd = libc:: F_DUPFD_CLOEXEC ;
145+
146+ // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
147+ // will never be supported, as this is a bare metal framework with
148+ // no capabilities for multi-process execution. While F_DUPFD is also
149+ // not supported yet, it might be (currently it returns ENOSYS).
150+ #[ cfg( target_os = "espidf" ) ]
151+ let cmd = libc:: F_DUPFD ;
152+
153+ let fd = match unsafe { libc:: fcntl ( self . as_raw_fd ( ) , cmd, 0 ) } {
154+ -1 => return Err ( std:: io:: Error :: last_os_error ( ) ) ,
155+ fd => fd,
156+ } ;
157+ Ok ( unsafe { Self :: from_raw_fd ( fd) } )
158+ }
159+
160+ // If the `close` feature is disabled, we expect users to avoid cloning
161+ // `OwnedFd` instances, so that we don't have to call `fcntl`.
162+ #[ cfg( not( feature = "close" ) ) ]
163+ {
164+ unreachable ! ( "try_clone called without the \" close\" feature in io-lifetimes" ) ;
165+ }
166+ }
167+ }
168+
113169/// An owned handle.
114170///
115171/// This closes the handle on drop.
@@ -133,6 +189,51 @@ pub struct OwnedHandle {
133189 handle : RawHandle ,
134190}
135191
192+ #[ cfg( windows) ]
193+ impl OwnedHandle {
194+ /// Creates a new `OwnedHandle` instance that shares the same underlying file handle
195+ /// as the existing `OwnedHandle` instance.
196+ pub fn try_clone ( & self ) -> std:: io:: Result < OwnedHandle > {
197+ #[ cfg( feature = "close" ) ]
198+ {
199+ self . duplicate ( 0 , false , DUPLICATE_SAME_ACCESS )
200+ }
201+
202+ // If the `close` feature is disabled, we expect users to avoid cloning
203+ // `OwnedHandle` instances, so that we don't have to call `fcntl`.
204+ #[ cfg( not( feature = "close" ) ) ]
205+ {
206+ unreachable ! ( "try_clone called without the \" close\" feature in io-lifetimes" ) ;
207+ }
208+ }
209+
210+ #[ cfg( feature = "close" ) ]
211+ pub ( crate ) fn duplicate (
212+ & self ,
213+ access : DWORD ,
214+ inherit : bool ,
215+ options : DWORD ,
216+ ) -> std:: io:: Result < Self > {
217+ let mut ret = 0 as HANDLE ;
218+ match unsafe {
219+ let cur_proc = GetCurrentProcess ( ) ;
220+ DuplicateHandle (
221+ cur_proc,
222+ self . as_raw_handle ( ) ,
223+ cur_proc,
224+ & mut ret,
225+ access,
226+ inherit as BOOL ,
227+ options,
228+ )
229+ } {
230+ 0 => return Err ( std:: io:: Error :: last_os_error ( ) ) ,
231+ _ => ( ) ,
232+ }
233+ unsafe { Ok ( Self :: from_raw_handle ( ret) ) }
234+ }
235+ }
236+
136237/// An owned socket.
137238///
138239/// This closes the socket on drop.
@@ -157,6 +258,94 @@ pub struct OwnedSocket {
157258 socket : RawSocket ,
158259}
159260
261+ #[ cfg( windows) ]
262+ impl OwnedSocket {
263+ /// Creates a new `OwnedSocket` instance that shares the same underlying socket
264+ /// as the existing `OwnedSocket` instance.
265+ pub fn try_clone ( & self ) -> std:: io:: Result < Self > {
266+ #[ cfg( feature = "close" ) ]
267+ {
268+ let mut info = unsafe { std:: mem:: zeroed :: < WSAPROTOCOL_INFOW > ( ) } ;
269+ let result = unsafe {
270+ WSADuplicateSocketW ( self . as_raw_socket ( ) as _ , GetCurrentProcessId ( ) , & mut info)
271+ } ;
272+ match result {
273+ SOCKET_ERROR => return Err ( std:: io:: Error :: last_os_error ( ) ) ,
274+ 0 => ( ) ,
275+ _ => panic ! ( ) ,
276+ }
277+ let socket = unsafe {
278+ WSASocketW (
279+ info. iAddressFamily ,
280+ info. iSocketType ,
281+ info. iProtocol ,
282+ & mut info,
283+ 0 ,
284+ WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT ,
285+ )
286+ } ;
287+
288+ if socket != INVALID_SOCKET {
289+ unsafe { Ok ( OwnedSocket :: from_raw_socket ( socket as _ ) ) }
290+ } else {
291+ let error = unsafe { WSAGetLastError ( ) } ;
292+
293+ if error != WSAEPROTOTYPE && error != WSAEINVAL {
294+ return Err ( std:: io:: Error :: from_raw_os_error ( error) ) ;
295+ }
296+
297+ let socket = unsafe {
298+ WSASocketW (
299+ info. iAddressFamily ,
300+ info. iSocketType ,
301+ info. iProtocol ,
302+ & mut info,
303+ 0 ,
304+ WSA_FLAG_OVERLAPPED ,
305+ )
306+ } ;
307+
308+ if socket == INVALID_SOCKET {
309+ return Err ( std:: io:: Error :: last_os_error ( ) ) ;
310+ }
311+
312+ unsafe {
313+ let socket = OwnedSocket :: from_raw_socket ( socket as _ ) ;
314+ socket. set_no_inherit ( ) ?;
315+ Ok ( socket)
316+ }
317+ }
318+ }
319+
320+ // If the `close` feature is disabled, we expect users to avoid cloning
321+ // `OwnedSocket` instances, so that we don't have to call `fcntl`.
322+ #[ cfg( not( feature = "close" ) ) ]
323+ {
324+ unreachable ! ( "try_clone called without the \" close\" feature in io-lifetimes" ) ;
325+ }
326+ }
327+
328+ #[ cfg( feature = "close" ) ]
329+ #[ cfg( not( target_vendor = "uwp" ) ) ]
330+ fn set_no_inherit ( & self ) -> std:: io:: Result < ( ) > {
331+ match unsafe {
332+ SetHandleInformation ( self . as_raw_socket ( ) as HANDLE , HANDLE_FLAG_INHERIT , 0 )
333+ } {
334+ 0 => return Err ( std:: io:: Error :: last_os_error ( ) ) ,
335+ _ => Ok ( ( ) ) ,
336+ }
337+ }
338+
339+ #[ cfg( feature = "close" ) ]
340+ #[ cfg( target_vendor = "uwp" ) ]
341+ fn set_no_inherit ( & self ) -> std:: io:: Result < ( ) > {
342+ Err ( io:: Error :: new_const (
343+ std:: io:: ErrorKind :: Unsupported ,
344+ & "Unavailable on UWP" ,
345+ ) )
346+ }
347+ }
348+
160349/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
161350/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
162351/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
0 commit comments