1//! Owned and borrowed Unix-like file descriptors.
23#![stable(feature = "io_safety", since = "1.63.0")]
4#![deny(unsafe_op_in_unsafe_fn)]
56use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
7#[cfg(not(target_os = "trusty"))]
8use crate::fs;
9use crate::marker::PhantomData;
10use crate::mem::ManuallyDrop;
11#[cfg(not(any(
12 target_arch = "wasm32",
13 target_env = "sgx",
14 target_os = "hermit",
15 target_os = "trusty"
16)))]
17use crate::sys::cvt;
18#[cfg(not(target_os = "trusty"))]
19use crate::sys_common::{AsInner, FromInner, IntoInner};
20use crate::{fmt, io};
2122type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
2324/// A borrowed file descriptor.
25///
26/// This has a lifetime parameter to tie it to the lifetime of something that owns the file
27/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file
28/// descriptor.
29///
30/// This uses `repr(transparent)` and has the representation of a host file
31/// descriptor, so it can be used in FFI in places where a file descriptor is
32/// passed as an argument, it is not captured or consumed, and it never has the
33/// value `-1`.
34///
35/// This type does not have a [`ToOwned`][crate::borrow::ToOwned]
36/// implementation. Calling `.to_owned()` on a variable of this type will call
37/// it on `&BorrowedFd` and use `Clone::clone()` like `ToOwned` does for all
38/// types implementing `Clone`. The result will be descriptor borrowed under
39/// the same lifetime.
40///
41/// To obtain an [`OwnedFd`], you can use [`BorrowedFd::try_clone_to_owned`]
42/// instead, but this is not supported on all platforms.
43#[derive(Copy, Clone)]
44#[repr(transparent)]
45#[rustc_nonnull_optimization_guaranteed]
46#[stable(feature = "io_safety", since = "1.63.0")]
47pub struct BorrowedFd<'fd> {
48 fd: ValidRawFd,
49 _phantom: PhantomData<&'fd OwnedFd>,
50}
5152/// An owned file descriptor.
53///
54/// This closes the file descriptor on drop. It is guaranteed that nobody else will close the file
55/// descriptor.
56///
57/// This uses `repr(transparent)` and has the representation of a host file
58/// descriptor, so it can be used in FFI in places where a file descriptor is
59/// passed as a consumed argument or returned as an owned value, and it never
60/// has the value `-1`.
61///
62/// You can use [`AsFd::as_fd`] to obtain a [`BorrowedFd`].
63#[repr(transparent)]
64#[rustc_nonnull_optimization_guaranteed]
65#[stable(feature = "io_safety", since = "1.63.0")]
66pub struct OwnedFd {
67 fd: ValidRawFd,
68}
6970impl BorrowedFd<'_> {
71/// Returns a `BorrowedFd` holding the given raw file descriptor.
72 ///
73 /// # Safety
74 ///
75 /// The resource pointed to by `fd` must remain open for the duration of
76 /// the returned `BorrowedFd`, and it must not have the value `-1`.
77#[inline]
78 #[track_caller]
79 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
80 #[stable(feature = "io_safety", since = "1.63.0")]
81pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
82Self { fd: ValidRawFd::new(fd).expect("fd != -1"), _phantom: PhantomData }
83 }
84}
8586impl OwnedFd {
87/// Creates a new `OwnedFd` instance that shares the same underlying file
88 /// description as the existing `OwnedFd` instance.
89#[stable(feature = "io_safety", since = "1.63.0")]
90pub fn try_clone(&self) -> crate::io::Result<Self> {
91self.as_fd().try_clone_to_owned()
92 }
93}
9495impl BorrowedFd<'_> {
96/// Creates a new `OwnedFd` instance that shares the same underlying file
97 /// description as the existing `BorrowedFd` instance.
98#[cfg(not(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty")))]
99 #[stable(feature = "io_safety", since = "1.63.0")]
100pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
101// We want to atomically duplicate this file descriptor and set the
102 // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
103 // is a POSIX flag that was added to Linux in 2.6.24.
104#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
105let cmd = libc::F_DUPFD_CLOEXEC;
106107// For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
108 // will never be supported, as this is a bare metal framework with
109 // no capabilities for multi-process execution. While F_DUPFD is also
110 // not supported yet, it might be (currently it returns ENOSYS).
111#[cfg(any(target_os = "espidf", target_os = "vita"))]
112let cmd = libc::F_DUPFD;
113114// Avoid using file descriptors below 3 as they are used for stdio
115let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
116Ok(unsafe { OwnedFd::from_raw_fd(fd) })
117 }
118119/// Creates a new `OwnedFd` instance that shares the same underlying file
120 /// description as the existing `BorrowedFd` instance.
121#[cfg(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty"))]
122 #[stable(feature = "io_safety", since = "1.63.0")]
123pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
124Err(crate::io::Error::UNSUPPORTED_PLATFORM)
125 }
126}
127128#[stable(feature = "io_safety", since = "1.63.0")]
129impl AsRawFd for BorrowedFd<'_> {
130#[inline]
131fn as_raw_fd(&self) -> RawFd {
132self.fd.as_inner()
133 }
134}
135136#[stable(feature = "io_safety", since = "1.63.0")]
137impl AsRawFd for OwnedFd {
138#[inline]
139fn as_raw_fd(&self) -> RawFd {
140self.fd.as_inner()
141 }
142}
143144#[stable(feature = "io_safety", since = "1.63.0")]
145impl IntoRawFd for OwnedFd {
146#[inline]
147fn into_raw_fd(self) -> RawFd {
148 ManuallyDrop::new(self).fd.as_inner()
149 }
150}
151152#[stable(feature = "io_safety", since = "1.63.0")]
153impl FromRawFd for OwnedFd {
154/// Constructs a new instance of `Self` from the given raw file descriptor.
155 ///
156 /// # Safety
157 ///
158 /// The resource pointed to by `fd` must be open and suitable for assuming
159 /// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
160 ///
161 /// [io-safety]: io#io-safety
162#[inline]
163 #[track_caller]
164unsafe fn from_raw_fd(fd: RawFd) -> Self {
165Self { fd: ValidRawFd::new(fd).expect("fd != -1") }
166 }
167}
168169#[stable(feature = "io_safety", since = "1.63.0")]
170impl Drop for OwnedFd {
171#[inline]
172fn drop(&mut self) {
173unsafe {
174// Note that errors are ignored when closing a file descriptor. According to POSIX 2024,
175 // we can and indeed should retry `close` on `EINTR`
176 // (https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/close.html),
177 // but it is not clear yet how well widely-used implementations are conforming with this
178 // mandate since older versions of POSIX left the state of the FD after an `EINTR`
179 // unspecified. Ignoring errors is "fine" because some of the major Unices (in
180 // particular, Linux) do make sure to always close the FD, even when `close()` is
181 // interrupted, and the scenario is rare to begin with. If we retried on a
182 // not-POSIX-compliant implementation, the consequences could be really bad since we may
183 // close the wrong FD. Helpful link to an epic discussion by POSIX workgroup that led to
184 // the latest POSIX wording: http://austingroupbugs.net/view.php?id=529
185#[cfg(not(target_os = "hermit"))]
186{
187#[cfg(unix)]
188crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
189190let _ = libc::close(self.fd.as_inner());
191 }
192#[cfg(target_os = "hermit")]
193let _ = hermit_abi::close(self.fd.as_inner());
194 }
195 }
196}
197198#[stable(feature = "io_safety", since = "1.63.0")]
199impl fmt::Debug for BorrowedFd<'_> {
200fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
202 }
203}
204205#[stable(feature = "io_safety", since = "1.63.0")]
206impl fmt::Debug for OwnedFd {
207fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
209 }
210}
211212macro_rules! impl_is_terminal {
213 ($($t:ty),*$(,)?) => {$(
214#[unstable(feature = "sealed", issue = "none")]
215impl crate::sealed::Sealed for $t {}
216217#[stable(feature = "is_terminal", since = "1.70.0")]
218impl crate::io::IsTerminal for $t {
219#[inline]
220fn is_terminal(&self) -> bool {
221crate::sys::io::is_terminal(self)
222 }
223 }
224 )*}
225}
226227impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
228229/// A trait to borrow the file descriptor from an underlying object.
230///
231/// This is only available on unix platforms and must be imported in order to
232/// call the method. Windows platforms have a corresponding `AsHandle` and
233/// `AsSocket` set of traits.
234#[stable(feature = "io_safety", since = "1.63.0")]
235pub trait AsFd {
236/// Borrows the file descriptor.
237 ///
238 /// # Example
239 ///
240 /// ```rust,no_run
241 /// use std::fs::File;
242 /// # use std::io;
243 /// # #[cfg(any(unix, target_os = "wasi"))]
244 /// # use std::os::fd::{AsFd, BorrowedFd};
245 ///
246 /// let mut f = File::open("foo.txt")?;
247 /// # #[cfg(any(unix, target_os = "wasi"))]
248 /// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
249 /// # Ok::<(), io::Error>(())
250 /// ```
251#[stable(feature = "io_safety", since = "1.63.0")]
252fn as_fd(&self) -> BorrowedFd<'_>;
253}
254255#[stable(feature = "io_safety", since = "1.63.0")]
256impl<T: AsFd + ?Sized> AsFd for &T {
257#[inline]
258fn as_fd(&self) -> BorrowedFd<'_> {
259 T::as_fd(self)
260 }
261}
262263#[stable(feature = "io_safety", since = "1.63.0")]
264impl<T: AsFd + ?Sized> AsFd for &mut T {
265#[inline]
266fn as_fd(&self) -> BorrowedFd<'_> {
267 T::as_fd(self)
268 }
269}
270271#[stable(feature = "io_safety", since = "1.63.0")]
272impl AsFd for BorrowedFd<'_> {
273#[inline]
274fn as_fd(&self) -> BorrowedFd<'_> {
275*self
276}
277}
278279#[stable(feature = "io_safety", since = "1.63.0")]
280impl AsFd for OwnedFd {
281#[inline]
282fn as_fd(&self) -> BorrowedFd<'_> {
283// Safety: `OwnedFd` and `BorrowedFd` have the same validity
284 // invariants, and the `BorrowedFd` is bounded by the lifetime
285 // of `&self`.
286unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
287 }
288}
289290#[stable(feature = "io_safety", since = "1.63.0")]
291#[cfg(not(target_os = "trusty"))]
292impl AsFd for fs::File {
293#[inline]
294fn as_fd(&self) -> BorrowedFd<'_> {
295self.as_inner().as_fd()
296 }
297}
298299#[stable(feature = "io_safety", since = "1.63.0")]
300#[cfg(not(target_os = "trusty"))]
301impl From<fs::File> for OwnedFd {
302/// Takes ownership of a [`File`](fs::File)'s underlying file descriptor.
303#[inline]
304fn from(file: fs::File) -> OwnedFd {
305 file.into_inner().into_inner().into_inner()
306 }
307}
308309#[stable(feature = "io_safety", since = "1.63.0")]
310#[cfg(not(target_os = "trusty"))]
311impl From<OwnedFd> for fs::File {
312/// Returns a [`File`](fs::File) that takes ownership of the given
313 /// file descriptor.
314#[inline]
315fn from(owned_fd: OwnedFd) -> Self {
316Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
317 }
318}
319320#[stable(feature = "io_safety", since = "1.63.0")]
321#[cfg(not(target_os = "trusty"))]
322impl AsFd for crate::net::TcpStream {
323#[inline]
324fn as_fd(&self) -> BorrowedFd<'_> {
325self.as_inner().socket().as_fd()
326 }
327}
328329#[stable(feature = "io_safety", since = "1.63.0")]
330#[cfg(not(target_os = "trusty"))]
331impl From<crate::net::TcpStream> for OwnedFd {
332/// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor.
333#[inline]
334fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
335 tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
336 }
337}
338339#[stable(feature = "io_safety", since = "1.63.0")]
340#[cfg(not(target_os = "trusty"))]
341impl From<OwnedFd> for crate::net::TcpStream {
342#[inline]
343fn from(owned_fd: OwnedFd) -> Self {
344Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
345 owned_fd,
346 ))))
347 }
348}
349350#[stable(feature = "io_safety", since = "1.63.0")]
351#[cfg(not(target_os = "trusty"))]
352impl AsFd for crate::net::TcpListener {
353#[inline]
354fn as_fd(&self) -> BorrowedFd<'_> {
355self.as_inner().socket().as_fd()
356 }
357}
358359#[stable(feature = "io_safety", since = "1.63.0")]
360#[cfg(not(target_os = "trusty"))]
361impl From<crate::net::TcpListener> for OwnedFd {
362/// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor.
363#[inline]
364fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
365 tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
366 }
367}
368369#[stable(feature = "io_safety", since = "1.63.0")]
370#[cfg(not(target_os = "trusty"))]
371impl From<OwnedFd> for crate::net::TcpListener {
372#[inline]
373fn from(owned_fd: OwnedFd) -> Self {
374Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
375 owned_fd,
376 ))))
377 }
378}
379380#[stable(feature = "io_safety", since = "1.63.0")]
381#[cfg(not(target_os = "trusty"))]
382impl AsFd for crate::net::UdpSocket {
383#[inline]
384fn as_fd(&self) -> BorrowedFd<'_> {
385self.as_inner().socket().as_fd()
386 }
387}
388389#[stable(feature = "io_safety", since = "1.63.0")]
390#[cfg(not(target_os = "trusty"))]
391impl From<crate::net::UdpSocket> for OwnedFd {
392/// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor.
393#[inline]
394fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
395 udp_socket.into_inner().into_socket().into_inner().into_inner().into()
396 }
397}
398399#[stable(feature = "io_safety", since = "1.63.0")]
400#[cfg(not(target_os = "trusty"))]
401impl From<OwnedFd> for crate::net::UdpSocket {
402#[inline]
403fn from(owned_fd: OwnedFd) -> Self {
404Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
405 owned_fd,
406 ))))
407 }
408}
409410#[stable(feature = "asfd_ptrs", since = "1.64.0")]
411/// This impl allows implementing traits that require `AsFd` on Arc.
412/// ```
413/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
414/// # #[cfg(target_os = "wasi")]
415/// # use std::os::wasi::io::AsFd;
416/// # #[cfg(unix)]
417/// # use std::os::unix::io::AsFd;
418/// use std::net::UdpSocket;
419/// use std::sync::Arc;
420///
421/// trait MyTrait: AsFd {}
422/// impl MyTrait for Arc<UdpSocket> {}
423/// impl MyTrait for Box<UdpSocket> {}
424/// # }
425/// ```
426impl<T: AsFd + ?Sized> AsFd for crate::sync::Arc<T> {
427#[inline]
428fn as_fd(&self) -> BorrowedFd<'_> {
429 (**self).as_fd()
430 }
431}
432433#[stable(feature = "asfd_rc", since = "1.69.0")]
434impl<T: AsFd + ?Sized> AsFd for crate::rc::Rc<T> {
435#[inline]
436fn as_fd(&self) -> BorrowedFd<'_> {
437 (**self).as_fd()
438 }
439}
440441#[unstable(feature = "unique_rc_arc", issue = "112566")]
442impl<T: AsFd + ?Sized> AsFd for crate::rc::UniqueRc<T> {
443#[inline]
444fn as_fd(&self) -> BorrowedFd<'_> {
445 (**self).as_fd()
446 }
447}
448449#[stable(feature = "asfd_ptrs", since = "1.64.0")]
450impl<T: AsFd + ?Sized> AsFd for Box<T> {
451#[inline]
452fn as_fd(&self) -> BorrowedFd<'_> {
453 (**self).as_fd()
454 }
455}
456457#[stable(feature = "io_safety", since = "1.63.0")]
458impl AsFd for io::Stdin {
459#[inline]
460fn as_fd(&self) -> BorrowedFd<'_> {
461unsafe { BorrowedFd::borrow_raw(0) }
462 }
463}
464465#[stable(feature = "io_safety", since = "1.63.0")]
466impl<'a> AsFd for io::StdinLock<'a> {
467#[inline]
468fn as_fd(&self) -> BorrowedFd<'_> {
469// SAFETY: user code should not close stdin out from under the standard library
470unsafe { BorrowedFd::borrow_raw(0) }
471 }
472}
473474#[stable(feature = "io_safety", since = "1.63.0")]
475impl AsFd for io::Stdout {
476#[inline]
477fn as_fd(&self) -> BorrowedFd<'_> {
478unsafe { BorrowedFd::borrow_raw(1) }
479 }
480}
481482#[stable(feature = "io_safety", since = "1.63.0")]
483impl<'a> AsFd for io::StdoutLock<'a> {
484#[inline]
485fn as_fd(&self) -> BorrowedFd<'_> {
486// SAFETY: user code should not close stdout out from under the standard library
487unsafe { BorrowedFd::borrow_raw(1) }
488 }
489}
490491#[stable(feature = "io_safety", since = "1.63.0")]
492impl AsFd for io::Stderr {
493#[inline]
494fn as_fd(&self) -> BorrowedFd<'_> {
495unsafe { BorrowedFd::borrow_raw(2) }
496 }
497}
498499#[stable(feature = "io_safety", since = "1.63.0")]
500impl<'a> AsFd for io::StderrLock<'a> {
501#[inline]
502fn as_fd(&self) -> BorrowedFd<'_> {
503// SAFETY: user code should not close stderr out from under the standard library
504unsafe { BorrowedFd::borrow_raw(2) }
505 }
506}
507508#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
509#[cfg(not(target_os = "trusty"))]
510impl AsFd for io::PipeReader {
511fn as_fd(&self) -> BorrowedFd<'_> {
512self.0.as_fd()
513 }
514}
515516#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
517#[cfg(not(target_os = "trusty"))]
518impl From<io::PipeReader> for OwnedFd {
519fn from(pipe: io::PipeReader) -> Self {
520 pipe.0.into_inner()
521 }
522}
523524#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
525#[cfg(not(target_os = "trusty"))]
526impl AsFd for io::PipeWriter {
527fn as_fd(&self) -> BorrowedFd<'_> {
528self.0.as_fd()
529 }
530}
531532#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
533#[cfg(not(target_os = "trusty"))]
534impl From<io::PipeWriter> for OwnedFd {
535fn from(pipe: io::PipeWriter) -> Self {
536 pipe.0.into_inner()
537 }
538}
539540#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
541#[cfg(not(target_os = "trusty"))]
542impl From<OwnedFd> for io::PipeReader {
543fn from(owned_fd: OwnedFd) -> Self {
544Self(FromInner::from_inner(owned_fd))
545 }
546}
547548#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
549#[cfg(not(target_os = "trusty"))]
550impl From<OwnedFd> for io::PipeWriter {
551fn from(owned_fd: OwnedFd) -> Self {
552Self(FromInner::from_inner(owned_fd))
553 }
554}