]>
Commit | Line | Data |
---|---|---|
94222f64 XL |
1 | //! Owned and borrowed Unix-like file descriptors. |
2 | ||
923072b8 | 3 | #![stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
4 | #![deny(unsafe_op_in_unsafe_fn)] |
5 | ||
6 | use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; | |
7 | use crate::fmt; | |
8 | use crate::fs; | |
9 | use crate::marker::PhantomData; | |
10 | use crate::mem::forget; | |
04454e1e | 11 | #[cfg(not(any(target_arch = "wasm32", target_env = "sgx")))] |
5099ac24 | 12 | use crate::sys::cvt; |
94222f64 XL |
13 | use crate::sys_common::{AsInner, FromInner, IntoInner}; |
14 | ||
15 | /// A borrowed file descriptor. | |
16 | /// | |
17 | /// This has a lifetime parameter to tie it to the lifetime of something that | |
18 | /// owns the file descriptor. | |
19 | /// | |
20 | /// This uses `repr(transparent)` and has the representation of a host file | |
21 | /// descriptor, so it can be used in FFI in places where a file descriptor is | |
22 | /// passed as an argument, it is not captured or consumed, and it never has the | |
23 | /// value `-1`. | |
5e7ed085 FG |
24 | /// |
25 | /// This type's `.to_owned()` implementation returns another `BorrowedFd` | |
26 | /// rather than an `OwnedFd`. It just makes a trivial copy of the raw file | |
27 | /// descriptor, which is then borrowed under the same lifetime. | |
94222f64 XL |
28 | #[derive(Copy, Clone)] |
29 | #[repr(transparent)] | |
30 | #[rustc_layout_scalar_valid_range_start(0)] | |
31 | // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a | |
32 | // 32-bit c_int. Below is -2, in two's complement, but that only works out | |
33 | // because c_int is 32 bits. | |
34 | #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] | |
923072b8 FG |
35 | #[rustc_nonnull_optimization_guaranteed] |
36 | #[stable(feature = "io_safety", since = "1.63.0")] | |
94222f64 XL |
37 | pub struct BorrowedFd<'fd> { |
38 | fd: RawFd, | |
39 | _phantom: PhantomData<&'fd OwnedFd>, | |
40 | } | |
41 | ||
42 | /// An owned file descriptor. | |
43 | /// | |
44 | /// This closes the file descriptor on drop. | |
45 | /// | |
46 | /// This uses `repr(transparent)` and has the representation of a host file | |
47 | /// descriptor, so it can be used in FFI in places where a file descriptor is | |
48 | /// passed as a consumed argument or returned as an owned value, and it never | |
49 | /// has the value `-1`. | |
50 | #[repr(transparent)] | |
51 | #[rustc_layout_scalar_valid_range_start(0)] | |
52 | // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a | |
53 | // 32-bit c_int. Below is -2, in two's complement, but that only works out | |
54 | // because c_int is 32 bits. | |
55 | #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] | |
923072b8 FG |
56 | #[rustc_nonnull_optimization_guaranteed] |
57 | #[stable(feature = "io_safety", since = "1.63.0")] | |
94222f64 XL |
58 | pub struct OwnedFd { |
59 | fd: RawFd, | |
60 | } | |
61 | ||
62 | impl BorrowedFd<'_> { | |
63 | /// Return a `BorrowedFd` holding the given raw file descriptor. | |
64 | /// | |
65 | /// # Safety | |
66 | /// | |
67 | /// The resource pointed to by `fd` must remain open for the duration of | |
68 | /// the returned `BorrowedFd`, and it must not have the value `-1`. | |
69 | #[inline] | |
923072b8 FG |
70 | #[rustc_const_stable(feature = "io_safety", since = "1.63.0")] |
71 | #[stable(feature = "io_safety", since = "1.63.0")] | |
04454e1e FG |
72 | pub const unsafe fn borrow_raw(fd: RawFd) -> Self { |
73 | assert!(fd != u32::MAX as RawFd); | |
94222f64 XL |
74 | // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) |
75 | unsafe { Self { fd, _phantom: PhantomData } } | |
76 | } | |
77 | } | |
78 | ||
5099ac24 | 79 | impl OwnedFd { |
923072b8 FG |
80 | /// Creates a new `OwnedFd` instance that shares the same underlying file |
81 | /// description as the existing `OwnedFd` instance. | |
82 | #[stable(feature = "io_safety", since = "1.63.0")] | |
5099ac24 | 83 | pub fn try_clone(&self) -> crate::io::Result<Self> { |
923072b8 FG |
84 | self.as_fd().try_clone_to_owned() |
85 | } | |
86 | } | |
87 | ||
88 | impl BorrowedFd<'_> { | |
89 | /// Creates a new `OwnedFd` instance that shares the same underlying file | |
90 | /// description as the existing `BorrowedFd` instance. | |
91 | #[cfg(not(target_arch = "wasm32"))] | |
92 | #[stable(feature = "io_safety", since = "1.63.0")] | |
93 | pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> { | |
5099ac24 FG |
94 | // We want to atomically duplicate this file descriptor and set the |
95 | // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This | |
96 | // is a POSIX flag that was added to Linux in 2.6.24. | |
97 | #[cfg(not(target_os = "espidf"))] | |
98 | let cmd = libc::F_DUPFD_CLOEXEC; | |
99 | ||
100 | // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics | |
101 | // will never be supported, as this is a bare metal framework with | |
102 | // no capabilities for multi-process execution. While F_DUPFD is also | |
103 | // not supported yet, it might be (currently it returns ENOSYS). | |
104 | #[cfg(target_os = "espidf")] | |
105 | let cmd = libc::F_DUPFD; | |
106 | ||
107 | let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; | |
923072b8 | 108 | Ok(unsafe { OwnedFd::from_raw_fd(fd) }) |
5099ac24 FG |
109 | } |
110 | ||
923072b8 FG |
111 | /// Creates a new `OwnedFd` instance that shares the same underlying file |
112 | /// description as the existing `BorrowedFd` instance. | |
04454e1e | 113 | #[cfg(target_arch = "wasm32")] |
923072b8 FG |
114 | #[stable(feature = "io_safety", since = "1.63.0")] |
115 | pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> { | |
5099ac24 FG |
116 | Err(crate::io::const_io_error!( |
117 | crate::io::ErrorKind::Unsupported, | |
118 | "operation not supported on WASI yet", | |
119 | )) | |
120 | } | |
121 | } | |
122 | ||
923072b8 | 123 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
124 | impl AsRawFd for BorrowedFd<'_> { |
125 | #[inline] | |
126 | fn as_raw_fd(&self) -> RawFd { | |
127 | self.fd | |
128 | } | |
129 | } | |
130 | ||
923072b8 | 131 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
132 | impl AsRawFd for OwnedFd { |
133 | #[inline] | |
134 | fn as_raw_fd(&self) -> RawFd { | |
135 | self.fd | |
136 | } | |
137 | } | |
138 | ||
923072b8 | 139 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
140 | impl IntoRawFd for OwnedFd { |
141 | #[inline] | |
142 | fn into_raw_fd(self) -> RawFd { | |
143 | let fd = self.fd; | |
144 | forget(self); | |
145 | fd | |
146 | } | |
147 | } | |
148 | ||
923072b8 | 149 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
150 | impl FromRawFd for OwnedFd { |
151 | /// Constructs a new instance of `Self` from the given raw file descriptor. | |
152 | /// | |
153 | /// # Safety | |
154 | /// | |
155 | /// The resource pointed to by `fd` must be open and suitable for assuming | |
156 | /// ownership. The resource must not require any cleanup other than `close`. | |
157 | #[inline] | |
158 | unsafe fn from_raw_fd(fd: RawFd) -> Self { | |
159 | assert_ne!(fd, u32::MAX as RawFd); | |
160 | // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) | |
161 | unsafe { Self { fd } } | |
162 | } | |
163 | } | |
164 | ||
923072b8 | 165 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
166 | impl Drop for OwnedFd { |
167 | #[inline] | |
168 | fn drop(&mut self) { | |
169 | unsafe { | |
170 | // Note that errors are ignored when closing a file descriptor. The | |
171 | // reason for this is that if an error occurs we don't actually know if | |
172 | // the file descriptor was closed or not, and if we retried (for | |
173 | // something like EINTR), we might close another valid file descriptor | |
174 | // opened after we closed ours. | |
175 | let _ = libc::close(self.fd); | |
176 | } | |
177 | } | |
178 | } | |
179 | ||
923072b8 | 180 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
181 | impl fmt::Debug for BorrowedFd<'_> { |
182 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
183 | f.debug_struct("BorrowedFd").field("fd", &self.fd).finish() | |
184 | } | |
185 | } | |
186 | ||
923072b8 | 187 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
188 | impl fmt::Debug for OwnedFd { |
189 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
190 | f.debug_struct("OwnedFd").field("fd", &self.fd).finish() | |
191 | } | |
192 | } | |
193 | ||
194 | /// A trait to borrow the file descriptor from an underlying object. | |
195 | /// | |
196 | /// This is only available on unix platforms and must be imported in order to | |
197 | /// call the method. Windows platforms have a corresponding `AsHandle` and | |
198 | /// `AsSocket` set of traits. | |
923072b8 | 199 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
200 | pub trait AsFd { |
201 | /// Borrows the file descriptor. | |
202 | /// | |
203 | /// # Example | |
204 | /// | |
205 | /// ```rust,no_run | |
94222f64 XL |
206 | /// use std::fs::File; |
207 | /// # use std::io; | |
208 | /// # #[cfg(target_os = "wasi")] | |
209 | /// # use std::os::wasi::io::{AsFd, BorrowedFd}; | |
210 | /// # #[cfg(unix)] | |
211 | /// # use std::os::unix::io::{AsFd, BorrowedFd}; | |
212 | /// | |
213 | /// let mut f = File::open("foo.txt")?; | |
214 | /// # #[cfg(any(unix, target_os = "wasi"))] | |
215 | /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); | |
216 | /// # Ok::<(), io::Error>(()) | |
217 | /// ``` | |
923072b8 | 218 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
219 | fn as_fd(&self) -> BorrowedFd<'_>; |
220 | } | |
221 | ||
923072b8 | 222 | #[stable(feature = "io_safety", since = "1.63.0")] |
5099ac24 FG |
223 | impl<T: AsFd> AsFd for &T { |
224 | #[inline] | |
225 | fn as_fd(&self) -> BorrowedFd<'_> { | |
226 | T::as_fd(self) | |
227 | } | |
228 | } | |
229 | ||
923072b8 | 230 | #[stable(feature = "io_safety", since = "1.63.0")] |
5099ac24 FG |
231 | impl<T: AsFd> AsFd for &mut T { |
232 | #[inline] | |
233 | fn as_fd(&self) -> BorrowedFd<'_> { | |
234 | T::as_fd(self) | |
235 | } | |
236 | } | |
237 | ||
923072b8 | 238 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
239 | impl AsFd for BorrowedFd<'_> { |
240 | #[inline] | |
241 | fn as_fd(&self) -> BorrowedFd<'_> { | |
242 | *self | |
243 | } | |
244 | } | |
245 | ||
923072b8 | 246 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
247 | impl AsFd for OwnedFd { |
248 | #[inline] | |
249 | fn as_fd(&self) -> BorrowedFd<'_> { | |
250 | // Safety: `OwnedFd` and `BorrowedFd` have the same validity | |
251 | // invariants, and the `BorrowdFd` is bounded by the lifetime | |
252 | // of `&self`. | |
5e7ed085 | 253 | unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } |
94222f64 XL |
254 | } |
255 | } | |
256 | ||
923072b8 | 257 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
258 | impl AsFd for fs::File { |
259 | #[inline] | |
260 | fn as_fd(&self) -> BorrowedFd<'_> { | |
261 | self.as_inner().as_fd() | |
262 | } | |
263 | } | |
264 | ||
923072b8 | 265 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
266 | impl From<fs::File> for OwnedFd { |
267 | #[inline] | |
268 | fn from(file: fs::File) -> OwnedFd { | |
269 | file.into_inner().into_inner().into_inner() | |
270 | } | |
271 | } | |
272 | ||
923072b8 | 273 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
274 | impl From<OwnedFd> for fs::File { |
275 | #[inline] | |
276 | fn from(owned_fd: OwnedFd) -> Self { | |
277 | Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) | |
278 | } | |
279 | } | |
280 | ||
923072b8 | 281 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
282 | impl AsFd for crate::net::TcpStream { |
283 | #[inline] | |
284 | fn as_fd(&self) -> BorrowedFd<'_> { | |
285 | self.as_inner().socket().as_fd() | |
286 | } | |
287 | } | |
288 | ||
923072b8 | 289 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
290 | impl From<crate::net::TcpStream> for OwnedFd { |
291 | #[inline] | |
292 | fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { | |
293 | tcp_stream.into_inner().into_socket().into_inner().into_inner().into() | |
294 | } | |
295 | } | |
296 | ||
923072b8 | 297 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
298 | impl From<OwnedFd> for crate::net::TcpStream { |
299 | #[inline] | |
300 | fn from(owned_fd: OwnedFd) -> Self { | |
301 | Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( | |
302 | owned_fd, | |
303 | )))) | |
304 | } | |
305 | } | |
306 | ||
923072b8 | 307 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
308 | impl AsFd for crate::net::TcpListener { |
309 | #[inline] | |
310 | fn as_fd(&self) -> BorrowedFd<'_> { | |
311 | self.as_inner().socket().as_fd() | |
312 | } | |
313 | } | |
314 | ||
923072b8 | 315 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
316 | impl From<crate::net::TcpListener> for OwnedFd { |
317 | #[inline] | |
318 | fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { | |
319 | tcp_listener.into_inner().into_socket().into_inner().into_inner().into() | |
320 | } | |
321 | } | |
322 | ||
923072b8 | 323 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
324 | impl From<OwnedFd> for crate::net::TcpListener { |
325 | #[inline] | |
326 | fn from(owned_fd: OwnedFd) -> Self { | |
327 | Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( | |
328 | owned_fd, | |
329 | )))) | |
330 | } | |
331 | } | |
332 | ||
923072b8 | 333 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
334 | impl AsFd for crate::net::UdpSocket { |
335 | #[inline] | |
336 | fn as_fd(&self) -> BorrowedFd<'_> { | |
337 | self.as_inner().socket().as_fd() | |
338 | } | |
339 | } | |
340 | ||
923072b8 | 341 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
342 | impl From<crate::net::UdpSocket> for OwnedFd { |
343 | #[inline] | |
344 | fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { | |
345 | udp_socket.into_inner().into_socket().into_inner().into_inner().into() | |
346 | } | |
347 | } | |
348 | ||
923072b8 | 349 | #[stable(feature = "io_safety", since = "1.63.0")] |
94222f64 XL |
350 | impl From<OwnedFd> for crate::net::UdpSocket { |
351 | #[inline] | |
352 | fn from(owned_fd: OwnedFd) -> Self { | |
353 | Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( | |
354 | owned_fd, | |
355 | )))) | |
356 | } | |
357 | } |