@@ -14,7 +14,27 @@ use std::{
14
14
} ,
15
15
} ;
16
16
#[ 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
+ } ;
18
38
19
39
#[ cfg( all( windows, not( feature = "winapi" ) ) ) ]
20
40
const INVALID_HANDLE_VALUE : * mut core:: ffi:: c_void = !0 as _ ;
@@ -110,6 +130,42 @@ pub struct OwnedFd {
110
130
fd : RawFd ,
111
131
}
112
132
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
+
113
169
/// An owned handle.
114
170
///
115
171
/// This closes the handle on drop.
@@ -133,6 +189,51 @@ pub struct OwnedHandle {
133
189
handle : RawHandle ,
134
190
}
135
191
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
+
136
237
/// An owned socket.
137
238
///
138
239
/// This closes the socket on drop.
@@ -157,6 +258,94 @@ pub struct OwnedSocket {
157
258
socket : RawSocket ,
158
259
}
159
260
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
+
160
349
/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
161
350
/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
162
351
/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
0 commit comments