1 | //! Owned and borrowed Unix-like file descriptors. |
2 | |
3 | #![stable (feature = "io_safety" , since = "1.63.0" )] |
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::io; |
10 | use crate::marker::PhantomData; |
11 | use crate::mem::forget; |
12 | #[cfg (not(any(target_arch = "wasm32" , target_env = "sgx" , target_os = "hermit" )))] |
13 | use crate::sys::cvt; |
14 | use crate::sys_common::{AsInner, FromInner, IntoInner}; |
15 | |
16 | /// A borrowed file descriptor. |
17 | /// |
18 | /// This has a lifetime parameter to tie it to the lifetime of something that owns the file |
19 | /// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file |
20 | /// descriptor. |
21 | /// |
22 | /// This uses `repr(transparent)` and has the representation of a host file |
23 | /// descriptor, so it can be used in FFI in places where a file descriptor is |
24 | /// passed as an argument, it is not captured or consumed, and it never has the |
25 | /// value `-1`. |
26 | /// |
27 | /// This type's `.to_owned()` implementation returns another `BorrowedFd` |
28 | /// rather than an `OwnedFd`. It just makes a trivial copy of the raw file |
29 | /// descriptor, which is then borrowed under the same lifetime. |
30 | #[derive (Copy, Clone)] |
31 | #[repr (transparent)] |
32 | #[rustc_layout_scalar_valid_range_start (0)] |
33 | // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a |
34 | // 32-bit c_int. Below is -2, in two's complement, but that only works out |
35 | // because c_int is 32 bits. |
36 | #[rustc_layout_scalar_valid_range_end (0xFF_FF_FF_FE)] |
37 | #[rustc_nonnull_optimization_guaranteed ] |
38 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
39 | pub struct BorrowedFd<'fd> { |
40 | fd: RawFd, |
41 | _phantom: PhantomData<&'fd OwnedFd>, |
42 | } |
43 | |
44 | /// An owned file descriptor. |
45 | /// |
46 | /// This closes the file descriptor on drop. It is guaranteed that nobody else will close the file |
47 | /// descriptor. |
48 | /// |
49 | /// This uses `repr(transparent)` and has the representation of a host file |
50 | /// descriptor, so it can be used in FFI in places where a file descriptor is |
51 | /// passed as a consumed argument or returned as an owned value, and it never |
52 | /// has the value `-1`. |
53 | #[repr (transparent)] |
54 | #[rustc_layout_scalar_valid_range_start (0)] |
55 | // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a |
56 | // 32-bit c_int. Below is -2, in two's complement, but that only works out |
57 | // because c_int is 32 bits. |
58 | #[rustc_layout_scalar_valid_range_end (0xFF_FF_FF_FE)] |
59 | #[rustc_nonnull_optimization_guaranteed ] |
60 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
61 | pub struct OwnedFd { |
62 | fd: RawFd, |
63 | } |
64 | |
65 | impl BorrowedFd<'_> { |
66 | /// Return a `BorrowedFd` holding the given raw file descriptor. |
67 | /// |
68 | /// # Safety |
69 | /// |
70 | /// The resource pointed to by `fd` must remain open for the duration of |
71 | /// the returned `BorrowedFd`, and it must not have the value `-1`. |
72 | #[inline ] |
73 | #[rustc_const_stable (feature = "io_safety" , since = "1.63.0" )] |
74 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
75 | pub const unsafe fn borrow_raw(fd: RawFd) -> Self { |
76 | assert!(fd != u32::MAX as RawFd); |
77 | // 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) |
78 | unsafe { Self { fd, _phantom: PhantomData } } |
79 | } |
80 | } |
81 | |
82 | impl OwnedFd { |
83 | /// Creates a new `OwnedFd` instance that shares the same underlying file |
84 | /// description as the existing `OwnedFd` instance. |
85 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
86 | pub fn try_clone(&self) -> crate::io::Result<Self> { |
87 | self.as_fd().try_clone_to_owned() |
88 | } |
89 | } |
90 | |
91 | impl BorrowedFd<'_> { |
92 | /// Creates a new `OwnedFd` instance that shares the same underlying file |
93 | /// description as the existing `BorrowedFd` instance. |
94 | #[cfg (not(any(target_arch = "wasm32" , target_os = "hermit" )))] |
95 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
96 | pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> { |
97 | // We want to atomically duplicate this file descriptor and set the |
98 | // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This |
99 | // is a POSIX flag that was added to Linux in 2.6.24. |
100 | #[cfg (not(any(target_os = "espidf" , target_os = "vita" )))] |
101 | let cmd = libc::F_DUPFD_CLOEXEC; |
102 | |
103 | // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics |
104 | // will never be supported, as this is a bare metal framework with |
105 | // no capabilities for multi-process execution. While F_DUPFD is also |
106 | // not supported yet, it might be (currently it returns ENOSYS). |
107 | #[cfg (any(target_os = "espidf" , target_os = "vita" ))] |
108 | let cmd = libc::F_DUPFD; |
109 | |
110 | // Avoid using file descriptors below 3 as they are used for stdio |
111 | let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?; |
112 | Ok(unsafe { OwnedFd::from_raw_fd(fd) }) |
113 | } |
114 | |
115 | /// Creates a new `OwnedFd` instance that shares the same underlying file |
116 | /// description as the existing `BorrowedFd` instance. |
117 | #[cfg (any(target_arch = "wasm32" , target_os = "hermit" ))] |
118 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
119 | pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> { |
120 | Err(crate::io::const_io_error!( |
121 | crate::io::ErrorKind::Unsupported, |
122 | "operation not supported on this platform" , |
123 | )) |
124 | } |
125 | } |
126 | |
127 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
128 | impl AsRawFd for BorrowedFd<'_> { |
129 | #[inline ] |
130 | fn as_raw_fd(&self) -> RawFd { |
131 | self.fd |
132 | } |
133 | } |
134 | |
135 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
136 | impl AsRawFd for OwnedFd { |
137 | #[inline ] |
138 | fn as_raw_fd(&self) -> RawFd { |
139 | self.fd |
140 | } |
141 | } |
142 | |
143 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
144 | impl IntoRawFd for OwnedFd { |
145 | #[inline ] |
146 | fn into_raw_fd(self) -> RawFd { |
147 | let fd: i32 = self.fd; |
148 | forget(self); |
149 | fd |
150 | } |
151 | } |
152 | |
153 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
154 | impl FromRawFd for OwnedFd { |
155 | /// Constructs a new instance of `Self` from the given raw file descriptor. |
156 | /// |
157 | /// # Safety |
158 | /// |
159 | /// The resource pointed to by `fd` must be open and suitable for assuming |
160 | /// [ownership][io-safety]. The resource must not require any cleanup other than `close`. |
161 | /// |
162 | /// [io-safety]: io#io-safety |
163 | #[inline ] |
164 | unsafe fn from_raw_fd(fd: RawFd) -> Self { |
165 | assert_ne!(fd, u32::MAX as RawFd); |
166 | // 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) |
167 | unsafe { Self { fd } } |
168 | } |
169 | } |
170 | |
171 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
172 | impl Drop for OwnedFd { |
173 | #[inline ] |
174 | fn drop(&mut self) { |
175 | unsafe { |
176 | // Note that errors are ignored when closing a file descriptor. The |
177 | // reason for this is that if an error occurs we don't actually know if |
178 | // the file descriptor was closed or not, and if we retried (for |
179 | // something like EINTR), we might close another valid file descriptor |
180 | // opened after we closed ours. |
181 | #[cfg (not(target_os = "hermit" ))] |
182 | let _ = libc::close(self.fd); |
183 | #[cfg (target_os = "hermit" )] |
184 | let _ = hermit_abi::close(self.fd); |
185 | } |
186 | } |
187 | } |
188 | |
189 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
190 | impl fmt::Debug for BorrowedFd<'_> { |
191 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
192 | f.debug_struct("BorrowedFd" ).field(name:"fd" , &self.fd).finish() |
193 | } |
194 | } |
195 | |
196 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
197 | impl fmt::Debug for OwnedFd { |
198 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
199 | f.debug_struct("OwnedFd" ).field(name:"fd" , &self.fd).finish() |
200 | } |
201 | } |
202 | |
203 | macro_rules! impl_is_terminal { |
204 | ($($t:ty),*$(,)?) => {$( |
205 | #[unstable(feature = "sealed" , issue = "none" )] |
206 | impl crate::sealed::Sealed for $t {} |
207 | |
208 | #[stable(feature = "is_terminal" , since = "1.70.0" )] |
209 | impl crate::io::IsTerminal for $t { |
210 | #[inline] |
211 | fn is_terminal(&self) -> bool { |
212 | crate::sys::io::is_terminal(self) |
213 | } |
214 | } |
215 | )*} |
216 | } |
217 | |
218 | impl_is_terminal!(BorrowedFd<'_>, OwnedFd); |
219 | |
220 | /// A trait to borrow the file descriptor from an underlying object. |
221 | /// |
222 | /// This is only available on unix platforms and must be imported in order to |
223 | /// call the method. Windows platforms have a corresponding `AsHandle` and |
224 | /// `AsSocket` set of traits. |
225 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
226 | pub trait AsFd { |
227 | /// Borrows the file descriptor. |
228 | /// |
229 | /// # Example |
230 | /// |
231 | /// ```rust,no_run |
232 | /// use std::fs::File; |
233 | /// # use std::io; |
234 | /// # #[cfg (any(unix, target_os = "wasi" ))] |
235 | /// # use std::os::fd::{AsFd, BorrowedFd}; |
236 | /// |
237 | /// let mut f = File::open("foo.txt" )?; |
238 | /// # #[cfg (any(unix, target_os = "wasi" ))] |
239 | /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); |
240 | /// # Ok::<(), io::Error>(()) |
241 | /// ``` |
242 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
243 | fn as_fd(&self) -> BorrowedFd<'_>; |
244 | } |
245 | |
246 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
247 | impl<T: AsFd> AsFd for &T { |
248 | #[inline ] |
249 | fn as_fd(&self) -> BorrowedFd<'_> { |
250 | T::as_fd(self) |
251 | } |
252 | } |
253 | |
254 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
255 | impl<T: AsFd> AsFd for &mut T { |
256 | #[inline ] |
257 | fn as_fd(&self) -> BorrowedFd<'_> { |
258 | T::as_fd(self) |
259 | } |
260 | } |
261 | |
262 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
263 | impl AsFd for BorrowedFd<'_> { |
264 | #[inline ] |
265 | fn as_fd(&self) -> BorrowedFd<'_> { |
266 | *self |
267 | } |
268 | } |
269 | |
270 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
271 | impl AsFd for OwnedFd { |
272 | #[inline ] |
273 | fn as_fd(&self) -> BorrowedFd<'_> { |
274 | // Safety: `OwnedFd` and `BorrowedFd` have the same validity |
275 | // invariants, and the `BorrowedFd` is bounded by the lifetime |
276 | // of `&self`. |
277 | unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } |
278 | } |
279 | } |
280 | |
281 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
282 | impl AsFd for fs::File { |
283 | #[inline ] |
284 | fn as_fd(&self) -> BorrowedFd<'_> { |
285 | self.as_inner().as_fd() |
286 | } |
287 | } |
288 | |
289 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
290 | impl From<fs::File> for OwnedFd { |
291 | #[inline ] |
292 | fn from(file: fs::File) -> OwnedFd { |
293 | file.into_inner().into_inner().into_inner() |
294 | } |
295 | } |
296 | |
297 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
298 | impl From<OwnedFd> for fs::File { |
299 | #[inline ] |
300 | fn from(owned_fd: OwnedFd) -> Self { |
301 | Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) |
302 | } |
303 | } |
304 | |
305 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
306 | impl AsFd for crate::net::TcpStream { |
307 | #[inline ] |
308 | fn as_fd(&self) -> BorrowedFd<'_> { |
309 | self.as_inner().socket().as_fd() |
310 | } |
311 | } |
312 | |
313 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
314 | impl From<crate::net::TcpStream> for OwnedFd { |
315 | #[inline ] |
316 | fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { |
317 | tcp_stream.into_inner().into_socket().into_inner().into_inner().into() |
318 | } |
319 | } |
320 | |
321 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
322 | impl From<OwnedFd> for crate::net::TcpStream { |
323 | #[inline ] |
324 | fn from(owned_fd: OwnedFd) -> Self { |
325 | Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( |
326 | owned_fd, |
327 | )))) |
328 | } |
329 | } |
330 | |
331 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
332 | impl AsFd for crate::net::TcpListener { |
333 | #[inline ] |
334 | fn as_fd(&self) -> BorrowedFd<'_> { |
335 | self.as_inner().socket().as_fd() |
336 | } |
337 | } |
338 | |
339 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
340 | impl From<crate::net::TcpListener> for OwnedFd { |
341 | #[inline ] |
342 | fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { |
343 | tcp_listener.into_inner().into_socket().into_inner().into_inner().into() |
344 | } |
345 | } |
346 | |
347 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
348 | impl From<OwnedFd> for crate::net::TcpListener { |
349 | #[inline ] |
350 | fn from(owned_fd: OwnedFd) -> Self { |
351 | Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( |
352 | owned_fd, |
353 | )))) |
354 | } |
355 | } |
356 | |
357 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
358 | impl AsFd for crate::net::UdpSocket { |
359 | #[inline ] |
360 | fn as_fd(&self) -> BorrowedFd<'_> { |
361 | self.as_inner().socket().as_fd() |
362 | } |
363 | } |
364 | |
365 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
366 | impl From<crate::net::UdpSocket> for OwnedFd { |
367 | #[inline ] |
368 | fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { |
369 | udp_socket.into_inner().into_socket().into_inner().into_inner().into() |
370 | } |
371 | } |
372 | |
373 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
374 | impl From<OwnedFd> for crate::net::UdpSocket { |
375 | #[inline ] |
376 | fn from(owned_fd: OwnedFd) -> Self { |
377 | Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( |
378 | owned_fd, |
379 | )))) |
380 | } |
381 | } |
382 | |
383 | #[stable (feature = "asfd_ptrs" , since = "1.64.0" )] |
384 | /// This impl allows implementing traits that require `AsFd` on Arc. |
385 | /// ``` |
386 | /// # #[cfg (any(unix, target_os = "wasi" ))] mod group_cfg { |
387 | /// # #[cfg (target_os = "wasi" )] |
388 | /// # use std::os::wasi::io::AsFd; |
389 | /// # #[cfg (unix)] |
390 | /// # use std::os::unix::io::AsFd; |
391 | /// use std::net::UdpSocket; |
392 | /// use std::sync::Arc; |
393 | /// |
394 | /// trait MyTrait: AsFd {} |
395 | /// impl MyTrait for Arc<UdpSocket> {} |
396 | /// impl MyTrait for Box<UdpSocket> {} |
397 | /// # } |
398 | /// ``` |
399 | impl<T: AsFd> AsFd for crate::sync::Arc<T> { |
400 | #[inline ] |
401 | fn as_fd(&self) -> BorrowedFd<'_> { |
402 | (**self).as_fd() |
403 | } |
404 | } |
405 | |
406 | #[stable (feature = "asfd_rc" , since = "1.69.0" )] |
407 | impl<T: AsFd> AsFd for crate::rc::Rc<T> { |
408 | #[inline ] |
409 | fn as_fd(&self) -> BorrowedFd<'_> { |
410 | (**self).as_fd() |
411 | } |
412 | } |
413 | |
414 | #[stable (feature = "asfd_ptrs" , since = "1.64.0" )] |
415 | impl<T: AsFd> AsFd for Box<T> { |
416 | #[inline ] |
417 | fn as_fd(&self) -> BorrowedFd<'_> { |
418 | (**self).as_fd() |
419 | } |
420 | } |
421 | |
422 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
423 | impl AsFd for io::Stdin { |
424 | #[inline ] |
425 | fn as_fd(&self) -> BorrowedFd<'_> { |
426 | unsafe { BorrowedFd::borrow_raw(fd:0) } |
427 | } |
428 | } |
429 | |
430 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
431 | impl<'a> AsFd for io::StdinLock<'a> { |
432 | #[inline ] |
433 | fn as_fd(&self) -> BorrowedFd<'_> { |
434 | // SAFETY: user code should not close stdin out from under the standard library |
435 | unsafe { BorrowedFd::borrow_raw(fd:0) } |
436 | } |
437 | } |
438 | |
439 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
440 | impl AsFd for io::Stdout { |
441 | #[inline ] |
442 | fn as_fd(&self) -> BorrowedFd<'_> { |
443 | unsafe { BorrowedFd::borrow_raw(fd:1) } |
444 | } |
445 | } |
446 | |
447 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
448 | impl<'a> AsFd for io::StdoutLock<'a> { |
449 | #[inline ] |
450 | fn as_fd(&self) -> BorrowedFd<'_> { |
451 | // SAFETY: user code should not close stdout out from under the standard library |
452 | unsafe { BorrowedFd::borrow_raw(fd:1) } |
453 | } |
454 | } |
455 | |
456 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
457 | impl AsFd for io::Stderr { |
458 | #[inline ] |
459 | fn as_fd(&self) -> BorrowedFd<'_> { |
460 | unsafe { BorrowedFd::borrow_raw(fd:2) } |
461 | } |
462 | } |
463 | |
464 | #[stable (feature = "io_safety" , since = "1.63.0" )] |
465 | impl<'a> AsFd for io::StderrLock<'a> { |
466 | #[inline ] |
467 | fn as_fd(&self) -> BorrowedFd<'_> { |
468 | // SAFETY: user code should not close stderr out from under the standard library |
469 | unsafe { BorrowedFd::borrow_raw(fd:2) } |
470 | } |
471 | } |
472 | |