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};
7use crate::marker::PhantomData;
8use crate::mem::ManuallyDrop;
9#[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))]
10use crate::sys::cvt;
11use crate::sys_common::{AsInner, FromInner, IntoInner};
12use crate::{fmt, fs, io};
1314type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
1516/// 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 does not have a [`ToOwned`][crate::borrow::ToOwned]
28/// implementation. Calling `.to_owned()` on a variable of this type will call
29/// it on `&BorrowedFd` and use `Clone::clone()` like `ToOwned` does for all
30/// types implementing `Clone`. The result will be descriptor borrowed under
31/// the same lifetime.
32///
33/// To obtain an [`OwnedFd`], you can use [`BorrowedFd::try_clone_to_owned`]
34/// instead, but this is not supported on all platforms.
35#[derive(Copy, Clone)]
36#[repr(transparent)]
37#[rustc_nonnull_optimization_guaranteed]
38#[stable(feature = "io_safety", since = "1.63.0")]
39pub struct BorrowedFd<'fd> {
40 fd: ValidRawFd,
41 _phantom: PhantomData<&'fd OwnedFd>,
42}
4344/// 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///
54/// You can use [`AsFd::as_fd`] to obtain a [`BorrowedFd`].
55#[repr(transparent)]
56#[rustc_nonnull_optimization_guaranteed]
57#[stable(feature = "io_safety", since = "1.63.0")]
58pub struct OwnedFd {
59 fd: ValidRawFd,
60}
6162impl BorrowedFd<'_> {
63/// Returns 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]
70 #[track_caller]
71 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
72 #[stable(feature = "io_safety", since = "1.63.0")]
73pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
74Self { fd: ValidRawFd::new(fd).expect("fd != -1"), _phantom: PhantomData }
75 }
76}
7778impl OwnedFd {
79/// Creates a new `OwnedFd` instance that shares the same underlying file
80 /// description as the existing `OwnedFd` instance.
81#[stable(feature = "io_safety", since = "1.63.0")]
82pub fn try_clone(&self) -> crate::io::Result<Self> {
83self.as_fd().try_clone_to_owned()
84 }
85}
8687impl BorrowedFd<'_> {
88/// Creates a new `OwnedFd` instance that shares the same underlying file
89 /// description as the existing `BorrowedFd` instance.
90#[cfg(not(any(target_arch = "wasm32", target_os = "hermit")))]
91 #[stable(feature = "io_safety", since = "1.63.0")]
92pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
93// We want to atomically duplicate this file descriptor and set the
94 // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
95 // is a POSIX flag that was added to Linux in 2.6.24.
96#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
97let cmd = libc::F_DUPFD_CLOEXEC;
9899// For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
100 // will never be supported, as this is a bare metal framework with
101 // no capabilities for multi-process execution. While F_DUPFD is also
102 // not supported yet, it might be (currently it returns ENOSYS).
103#[cfg(any(target_os = "espidf", target_os = "vita"))]
104let cmd = libc::F_DUPFD;
105106// Avoid using file descriptors below 3 as they are used for stdio
107let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
108Ok(unsafe { OwnedFd::from_raw_fd(fd) })
109 }
110111/// Creates a new `OwnedFd` instance that shares the same underlying file
112 /// description as the existing `BorrowedFd` instance.
113#[cfg(any(target_arch = "wasm32", target_os = "hermit"))]
114 #[stable(feature = "io_safety", since = "1.63.0")]
115pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
116Err(crate::io::Error::UNSUPPORTED_PLATFORM)
117 }
118}
119120#[stable(feature = "io_safety", since = "1.63.0")]
121impl AsRawFd for BorrowedFd<'_> {
122#[inline]
123fn as_raw_fd(&self) -> RawFd {
124self.fd.as_inner()
125 }
126}
127128#[stable(feature = "io_safety", since = "1.63.0")]
129impl AsRawFd for OwnedFd {
130#[inline]
131fn as_raw_fd(&self) -> RawFd {
132self.fd.as_inner()
133 }
134}
135136#[stable(feature = "io_safety", since = "1.63.0")]
137impl IntoRawFd for OwnedFd {
138#[inline]
139fn into_raw_fd(self) -> RawFd {
140 ManuallyDrop::new(self).fd.as_inner()
141 }
142}
143144#[stable(feature = "io_safety", since = "1.63.0")]
145impl FromRawFd for OwnedFd {
146/// Constructs a new instance of `Self` from the given raw file descriptor.
147 ///
148 /// # Safety
149 ///
150 /// The resource pointed to by `fd` must be open and suitable for assuming
151 /// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
152 ///
153 /// [io-safety]: io#io-safety
154#[inline]
155 #[track_caller]
156unsafe fn from_raw_fd(fd: RawFd) -> Self {
157Self { fd: ValidRawFd::new(fd).expect("fd != -1") }
158 }
159}
160161#[stable(feature = "io_safety", since = "1.63.0")]
162impl Drop for OwnedFd {
163#[inline]
164fn drop(&mut self) {
165unsafe {
166// Note that errors are ignored when closing a file descriptor. According to POSIX 2024,
167 // we can and indeed should retry `close` on `EINTR`
168 // (https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/close.html),
169 // but it is not clear yet how well widely-used implementations are conforming with this
170 // mandate since older versions of POSIX left the state of the FD after an `EINTR`
171 // unspecified. Ignoring errors is "fine" because some of the major Unices (in
172 // particular, Linux) do make sure to always close the FD, even when `close()` is
173 // interrupted, and the scenario is rare to begin with. If we retried on a
174 // not-POSIX-compliant implementation, the consequences could be really bad since we may
175 // close the wrong FD. Helpful link to an epic discussion by POSIX workgroup that led to
176 // the latest POSIX wording: http://austingroupbugs.net/view.php?id=529
177#[cfg(not(target_os = "hermit"))]
178{
179#[cfg(unix)]
180crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
181182let _ = libc::close(self.fd.as_inner());
183 }
184#[cfg(target_os = "hermit")]
185let _ = hermit_abi::close(self.fd.as_inner());
186 }
187 }
188}
189190#[stable(feature = "io_safety", since = "1.63.0")]
191impl fmt::Debug for BorrowedFd<'_> {
192fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
194 }
195}
196197#[stable(feature = "io_safety", since = "1.63.0")]
198impl fmt::Debug for OwnedFd {
199fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200 f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
201 }
202}
203204macro_rules! impl_is_terminal {
205 ($($t:ty),*$(,)?) => {$(
206#[unstable(feature = "sealed", issue = "none")]
207impl crate::sealed::Sealed for $t {}
208209#[stable(feature = "is_terminal", since = "1.70.0")]
210impl crate::io::IsTerminal for $t {
211#[inline]
212fn is_terminal(&self) -> bool {
213crate::sys::io::is_terminal(self)
214 }
215 }
216 )*}
217}
218219impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
220221/// A trait to borrow the file descriptor from an underlying object.
222///
223/// This is only available on unix platforms and must be imported in order to
224/// call the method. Windows platforms have a corresponding `AsHandle` and
225/// `AsSocket` set of traits.
226#[stable(feature = "io_safety", since = "1.63.0")]
227pub trait AsFd {
228/// Borrows the file descriptor.
229 ///
230 /// # Example
231 ///
232 /// ```rust,no_run
233 /// use std::fs::File;
234 /// # use std::io;
235 /// # #[cfg(any(unix, target_os = "wasi"))]
236 /// # use std::os::fd::{AsFd, BorrowedFd};
237 ///
238 /// let mut f = File::open("foo.txt")?;
239 /// # #[cfg(any(unix, target_os = "wasi"))]
240 /// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
241 /// # Ok::<(), io::Error>(())
242 /// ```
243#[stable(feature = "io_safety", since = "1.63.0")]
244fn as_fd(&self) -> BorrowedFd<'_>;
245}
246247#[stable(feature = "io_safety", since = "1.63.0")]
248impl<T: AsFd + ?Sized> AsFd for &T {
249#[inline]
250fn as_fd(&self) -> BorrowedFd<'_> {
251 T::as_fd(self)
252 }
253}
254255#[stable(feature = "io_safety", since = "1.63.0")]
256impl<T: AsFd + ?Sized> AsFd for &mut 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 AsFd for BorrowedFd<'_> {
265#[inline]
266fn as_fd(&self) -> BorrowedFd<'_> {
267*self
268}
269}
270271#[stable(feature = "io_safety", since = "1.63.0")]
272impl AsFd for OwnedFd {
273#[inline]
274fn as_fd(&self) -> BorrowedFd<'_> {
275// Safety: `OwnedFd` and `BorrowedFd` have the same validity
276 // invariants, and the `BorrowedFd` is bounded by the lifetime
277 // of `&self`.
278unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
279 }
280}
281282#[stable(feature = "io_safety", since = "1.63.0")]
283impl AsFd for fs::File {
284#[inline]
285fn as_fd(&self) -> BorrowedFd<'_> {
286self.as_inner().as_fd()
287 }
288}
289290#[stable(feature = "io_safety", since = "1.63.0")]
291impl From<fs::File> for OwnedFd {
292/// Takes ownership of a [`File`](fs::File)'s underlying file descriptor.
293#[inline]
294fn from(file: fs::File) -> OwnedFd {
295 file.into_inner().into_inner().into_inner()
296 }
297}
298299#[stable(feature = "io_safety", since = "1.63.0")]
300impl From<OwnedFd> for fs::File {
301/// Returns a [`File`](fs::File) that takes ownership of the given
302 /// file descriptor.
303#[inline]
304fn from(owned_fd: OwnedFd) -> Self {
305Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
306 }
307}
308309#[stable(feature = "io_safety", since = "1.63.0")]
310impl AsFd for crate::net::TcpStream {
311#[inline]
312fn as_fd(&self) -> BorrowedFd<'_> {
313self.as_inner().socket().as_fd()
314 }
315}
316317#[stable(feature = "io_safety", since = "1.63.0")]
318impl From<crate::net::TcpStream> for OwnedFd {
319/// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor.
320#[inline]
321fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
322 tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
323 }
324}
325326#[stable(feature = "io_safety", since = "1.63.0")]
327impl From<OwnedFd> for crate::net::TcpStream {
328#[inline]
329fn from(owned_fd: OwnedFd) -> Self {
330Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
331 owned_fd,
332 ))))
333 }
334}
335336#[stable(feature = "io_safety", since = "1.63.0")]
337impl AsFd for crate::net::TcpListener {
338#[inline]
339fn as_fd(&self) -> BorrowedFd<'_> {
340self.as_inner().socket().as_fd()
341 }
342}
343344#[stable(feature = "io_safety", since = "1.63.0")]
345impl From<crate::net::TcpListener> for OwnedFd {
346/// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor.
347#[inline]
348fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
349 tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
350 }
351}
352353#[stable(feature = "io_safety", since = "1.63.0")]
354impl From<OwnedFd> for crate::net::TcpListener {
355#[inline]
356fn from(owned_fd: OwnedFd) -> Self {
357Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
358 owned_fd,
359 ))))
360 }
361}
362363#[stable(feature = "io_safety", since = "1.63.0")]
364impl AsFd for crate::net::UdpSocket {
365#[inline]
366fn as_fd(&self) -> BorrowedFd<'_> {
367self.as_inner().socket().as_fd()
368 }
369}
370371#[stable(feature = "io_safety", since = "1.63.0")]
372impl From<crate::net::UdpSocket> for OwnedFd {
373/// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor.
374#[inline]
375fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
376 udp_socket.into_inner().into_socket().into_inner().into_inner().into()
377 }
378}
379380#[stable(feature = "io_safety", since = "1.63.0")]
381impl From<OwnedFd> for crate::net::UdpSocket {
382#[inline]
383fn from(owned_fd: OwnedFd) -> Self {
384Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
385 owned_fd,
386 ))))
387 }
388}
389390#[stable(feature = "asfd_ptrs", since = "1.64.0")]
391/// This impl allows implementing traits that require `AsFd` on Arc.
392/// ```
393/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
394/// # #[cfg(target_os = "wasi")]
395/// # use std::os::wasi::io::AsFd;
396/// # #[cfg(unix)]
397/// # use std::os::unix::io::AsFd;
398/// use std::net::UdpSocket;
399/// use std::sync::Arc;
400///
401/// trait MyTrait: AsFd {}
402/// impl MyTrait for Arc<UdpSocket> {}
403/// impl MyTrait for Box<UdpSocket> {}
404/// # }
405/// ```
406impl<T: AsFd + ?Sized> AsFd for crate::sync::Arc<T> {
407#[inline]
408fn as_fd(&self) -> BorrowedFd<'_> {
409 (**self).as_fd()
410 }
411}
412413#[stable(feature = "asfd_rc", since = "1.69.0")]
414impl<T: AsFd + ?Sized> AsFd for crate::rc::Rc<T> {
415#[inline]
416fn as_fd(&self) -> BorrowedFd<'_> {
417 (**self).as_fd()
418 }
419}
420421#[unstable(feature = "unique_rc_arc", issue = "112566")]
422impl<T: AsFd + ?Sized> AsFd for crate::rc::UniqueRc<T> {
423#[inline]
424fn as_fd(&self) -> BorrowedFd<'_> {
425 (**self).as_fd()
426 }
427}
428429#[stable(feature = "asfd_ptrs", since = "1.64.0")]
430impl<T: AsFd + ?Sized> AsFd for Box<T> {
431#[inline]
432fn as_fd(&self) -> BorrowedFd<'_> {
433 (**self).as_fd()
434 }
435}
436437#[stable(feature = "io_safety", since = "1.63.0")]
438impl AsFd for io::Stdin {
439#[inline]
440fn as_fd(&self) -> BorrowedFd<'_> {
441unsafe { BorrowedFd::borrow_raw(0) }
442 }
443}
444445#[stable(feature = "io_safety", since = "1.63.0")]
446impl<'a> AsFd for io::StdinLock<'a> {
447#[inline]
448fn as_fd(&self) -> BorrowedFd<'_> {
449// SAFETY: user code should not close stdin out from under the standard library
450unsafe { BorrowedFd::borrow_raw(0) }
451 }
452}
453454#[stable(feature = "io_safety", since = "1.63.0")]
455impl AsFd for io::Stdout {
456#[inline]
457fn as_fd(&self) -> BorrowedFd<'_> {
458unsafe { BorrowedFd::borrow_raw(1) }
459 }
460}
461462#[stable(feature = "io_safety", since = "1.63.0")]
463impl<'a> AsFd for io::StdoutLock<'a> {
464#[inline]
465fn as_fd(&self) -> BorrowedFd<'_> {
466// SAFETY: user code should not close stdout out from under the standard library
467unsafe { BorrowedFd::borrow_raw(1) }
468 }
469}
470471#[stable(feature = "io_safety", since = "1.63.0")]
472impl AsFd for io::Stderr {
473#[inline]
474fn as_fd(&self) -> BorrowedFd<'_> {
475unsafe { BorrowedFd::borrow_raw(2) }
476 }
477}
478479#[stable(feature = "io_safety", since = "1.63.0")]
480impl<'a> AsFd for io::StderrLock<'a> {
481#[inline]
482fn as_fd(&self) -> BorrowedFd<'_> {
483// SAFETY: user code should not close stderr out from under the standard library
484unsafe { BorrowedFd::borrow_raw(2) }
485 }
486}