@@ -27,6 +27,120 @@ pub struct OwnedFd {
2727 inner : ManuallyDrop < crate :: imp:: fd:: OwnedFd > ,
2828}
2929
30+ impl OwnedFd {
31+ /// Creates a new `OwnedFd` instance that shares the same underlying file handle
32+ /// as the existing `OwnedFd` instance.
33+ #[ cfg( all( unix, not( target_os = "wasi" ) ) ) ]
34+ pub fn try_clone ( & self ) -> crate :: io:: Result < Self > {
35+ // We want to atomically duplicate this file descriptor and set the
36+ // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
37+ // is a POSIX flag that was added to Linux in 2.6.24.
38+ #[ cfg( not( target_os = "espidf" ) ) ]
39+ let fd = crate :: fs:: fcntl_dupfd_cloexec ( self , 0 ) ?;
40+
41+ // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
42+ // will never be supported, as this is a bare metal framework with
43+ // no capabilities for multi-process execution. While F_DUPFD is also
44+ // not supported yet, it might be (currently it returns ENOSYS).
45+ #[ cfg( target_os = "espidf" ) ]
46+ let fd = crate :: fs:: fcntl_dupfd ( self ) ?;
47+
48+ Ok ( fd)
49+ }
50+
51+ /// Creates a new `OwnedFd` instance that shares the same underlying file handle
52+ /// as the existing `OwnedFd` instance.
53+ #[ cfg( target_os = "wasi" ) ]
54+ pub fn try_clone ( & self ) -> std:: io:: Result < Self > {
55+ Err ( std:: io:: Error :: new (
56+ std:: io:: ErrorKind :: Unsupported ,
57+ "operation not supported on WASI yet" ,
58+ ) )
59+ }
60+
61+ /// Creates a new `OwnedFd` instance that shares the same underlying file
62+ /// handle as the existing `OwnedFd` instance.
63+ #[ cfg( target_os = "windows" ) ]
64+ pub fn try_clone ( & self ) -> std:: io:: Result < Self > {
65+ use winapi:: um:: processthreadsapi:: GetCurrentProcessId ;
66+ use winapi:: um:: winsock2:: {
67+ WSADuplicateSocketW , WSAGetLastError , WSASocketW , INVALID_SOCKET , WSAEINVAL ,
68+ WSAEPROTOTYPE , WSAPROTOCOL_INFOW , WSA_FLAG_NO_HANDLE_INHERIT , WSA_FLAG_OVERLAPPED ,
69+ } ;
70+
71+ let mut info = unsafe { std:: mem:: zeroed :: < WSAPROTOCOL_INFOW > ( ) } ;
72+ let result =
73+ unsafe { WSADuplicateSocketW ( self . as_raw_fd ( ) as _ , GetCurrentProcessId ( ) , & mut info) } ;
74+ match result {
75+ SOCKET_ERROR => return Err ( std:: io:: Error :: last_os_error ( ) ) ,
76+ 0 => ( ) ,
77+ _ => panic ! ( ) ,
78+ }
79+ let socket = unsafe {
80+ WSASocketW (
81+ info. iAddressFamily ,
82+ info. iSocketType ,
83+ info. iProtocol ,
84+ & mut info,
85+ 0 ,
86+ WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT ,
87+ )
88+ } ;
89+
90+ if socket != INVALID_SOCKET {
91+ unsafe { Ok ( Self :: from_raw_fd ( socket as _ ) ) }
92+ } else {
93+ let error = unsafe { WSAGetLastError ( ) } ;
94+
95+ if error != WSAEPROTOTYPE && error != WSAEINVAL {
96+ return Err ( std:: io:: Error :: from_raw_os_error ( error) ) ;
97+ }
98+
99+ let socket = unsafe {
100+ WSASocketW (
101+ info. iAddressFamily ,
102+ info. iSocketType ,
103+ info. iProtocol ,
104+ & mut info,
105+ 0 ,
106+ WSA_FLAG_OVERLAPPED ,
107+ )
108+ } ;
109+
110+ if socket == INVALID_SOCKET {
111+ return Err ( std:: io:: Error :: last_os_error ( ) ) ;
112+ }
113+
114+ unsafe {
115+ let socket = Self :: from_raw_fd ( socket as _ ) ;
116+ socket. set_no_inherit ( ) ?;
117+ Ok ( socket)
118+ }
119+ }
120+ }
121+
122+ #[ cfg( windows) ]
123+ #[ cfg( not( target_vendor = "uwp" ) ) ]
124+ fn set_no_inherit ( & self ) -> std:: io:: Result < ( ) > {
125+ use winapi:: um:: handleapi:: SetHandleInformation ;
126+ use winapi:: um:: winbase:: HANDLE_FLAG_INHERIT ;
127+ use winapi:: um:: winnt:: HANDLE ;
128+ match unsafe { SetHandleInformation ( self . as_raw_fd ( ) as HANDLE , HANDLE_FLAG_INHERIT , 0 ) } {
129+ 0 => return Err ( std:: io:: Error :: last_os_error ( ) ) ,
130+ _ => Ok ( ( ) ) ,
131+ }
132+ }
133+
134+ #[ cfg( windows) ]
135+ #[ cfg( target_vendor = "uwp" ) ]
136+ fn set_no_inherit ( & self ) -> std:: io:: Result < ( ) > {
137+ Err ( io:: Error :: new_const (
138+ std:: io:: ErrorKind :: Unsupported ,
139+ & "Unavailable on UWP" ,
140+ ) )
141+ }
142+ }
143+
30144#[ cfg( not( windows) ) ]
31145impl AsFd for OwnedFd {
32146 #[ inline]
0 commit comments