1//! Owned and borrowed Unix-like file descriptors.
23#![stable(feature = "io_safety", since = "1.63.0")]
4#![deny(unsafe_op_in_unsafe_fn)]
56#[cfg(target_os = "motor")]
7use moto_rt::libc;
89use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
10#[cfg(not(target_os = "trusty"))]
11use crate::fs;
12use crate::marker::PhantomData;
13use crate::mem::ManuallyDrop;
14#[cfg(not(any(
15 all(target_arch = "wasm32", not(target_os = "emscripten")),
16 target_env = "sgx",
17 target_os = "hermit",
18 target_os = "trusty",
19 target_os = "motor"
20)))]
21use crate::sys::cvt;
22#[cfg(not(target_os = "trusty"))]
23use crate::sys::{AsInner, FromInner, IntoInner};
24use crate::{fmt, io};
2526type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
2728/// A borrowed file descriptor.
29///
30/// This has a lifetime parameter to tie it to the lifetime of something that owns the file
31/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file
32/// descriptor.
33///
34/// This uses `repr(transparent)` and has the representation of a host file
35/// descriptor, so it can be used in FFI in places where a file descriptor is
36/// passed as an argument, it is not captured or consumed, and it never has the
37/// value `-1`.
38///
39/// This type does not have a [`ToOwned`][crate::borrow::ToOwned]
40/// implementation. Calling `.to_owned()` on a variable of this type will call
41/// it on `&BorrowedFd` and use `Clone::clone()` like `ToOwned` does for all
42/// types implementing `Clone`. The result will be descriptor borrowed under
43/// the same lifetime.
44///
45/// To obtain an [`OwnedFd`], you can use [`BorrowedFd::try_clone_to_owned`]
46/// instead, but this is not supported on all platforms.
47#[derive(#[automatically_derived]
#[stable(feature = "io_safety", since = "1.63.0")]
impl<'fd> ::core::marker::Copy for BorrowedFd<'fd> { }Copy, #[automatically_derived]
#[stable(feature = "io_safety", since = "1.63.0")]
impl<'fd> ::core::clone::Clone for BorrowedFd<'fd> {
#[inline]
fn clone(&self) -> BorrowedFd<'fd> {
let _: ::core::clone::AssertParamIsClone<ValidRawFd>;
let _: ::core::clone::AssertParamIsClone<PhantomData<&'fd OwnedFd>>;
*self
}
}Clone)]
48#[repr(transparent)]
49#[rustc_nonnull_optimization_guaranteed]
50#[stable(feature = "io_safety", since = "1.63.0")]
51pub struct BorrowedFd<'fd> {
52 fd: ValidRawFd,
53 _phantom: PhantomData<&'fd OwnedFd>,
54}
5556/// An owned file descriptor.
57///
58/// This closes the file descriptor on drop. It is guaranteed that nobody else will close the file
59/// descriptor.
60///
61/// This uses `repr(transparent)` and has the representation of a host file
62/// descriptor, so it can be used in FFI in places where a file descriptor is
63/// passed as a consumed argument or returned as an owned value, and it never
64/// has the value `-1`.
65///
66/// You can use [`AsFd::as_fd`] to obtain a [`BorrowedFd`].
67#[repr(transparent)]
68#[rustc_nonnull_optimization_guaranteed]
69#[stable(feature = "io_safety", since = "1.63.0")]
70pub struct OwnedFd {
71 fd: ValidRawFd,
72}
7374impl BorrowedFd<'_> {
75/// Returns a `BorrowedFd` holding the given raw file descriptor.
76 ///
77 /// # Safety
78 ///
79 /// The resource pointed to by `fd` must remain open for the duration of
80 /// the returned `BorrowedFd`.
81 ///
82 /// # Panics
83 ///
84 /// Panics if the raw file descriptor has the value `-1`.
85#[inline]
86 #[track_caller]
87 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
88 #[stable(feature = "io_safety", since = "1.63.0")]
89pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
90Self { fd: ValidRawFd::new(fd).expect("fd != -1"), _phantom: PhantomData }
91 }
92}
9394impl OwnedFd {
95/// Creates a new `OwnedFd` instance that shares the same underlying file
96 /// description as the existing `OwnedFd` instance.
97#[stable(feature = "io_safety", since = "1.63.0")]
98pub fn try_clone(&self) -> io::Result<Self> {
99self.as_fd().try_clone_to_owned()
100 }
101}
102103impl BorrowedFd<'_> {
104/// Creates a new `OwnedFd` instance that shares the same underlying file
105 /// description as the existing `BorrowedFd` instance.
106#[cfg(not(any(
107 all(target_arch = "wasm32", not(target_os = "emscripten")),
108 target_os = "hermit",
109 target_os = "trusty",
110 target_os = "motor"
111)))]
112 #[stable(feature = "io_safety", since = "1.63.0")]
113pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
114// We want to atomically duplicate this file descriptor and set the
115 // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
116 // is a POSIX flag that was added to Linux in 2.6.24.
117#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
118let cmd = libc::F_DUPFD_CLOEXEC;
119120// For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
121 // will never be supported, as this is a bare metal framework with
122 // no capabilities for multi-process execution. While F_DUPFD is also
123 // not supported yet, it might be (currently it returns ENOSYS).
124#[cfg(any(target_os = "espidf", target_os = "vita"))]
125let cmd = libc::F_DUPFD;
126127// Avoid using file descriptors below 3 as they are used for stdio
128let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
129Ok(unsafe { OwnedFd::from_raw_fd(fd) })
130 }
131132/// Creates a new `OwnedFd` instance that shares the same underlying file
133 /// description as the existing `BorrowedFd` instance.
134#[cfg(any(
135 all(target_arch = "wasm32", not(target_os = "emscripten")),
136 target_os = "hermit",
137 target_os = "trusty"
138))]
139 #[stable(feature = "io_safety", since = "1.63.0")]
140pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
141Err(io::Error::UNSUPPORTED_PLATFORM)
142 }
143144/// Creates a new `OwnedFd` instance that shares the same underlying file
145 /// description as the existing `BorrowedFd` instance.
146#[cfg(target_os = "motor")]
147 #[stable(feature = "io_safety", since = "1.63.0")]
148pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
149let fd = moto_rt::fs::duplicate(self.as_raw_fd()).map_err(crate::sys::map_motor_error)?;
150Ok(unsafe { OwnedFd::from_raw_fd(fd) })
151 }
152}
153154#[stable(feature = "io_safety", since = "1.63.0")]
155impl AsRawFdfor BorrowedFd<'_> {
156#[inline]
157fn as_raw_fd(&self) -> RawFd {
158self.fd.as_inner()
159 }
160}
161162#[stable(feature = "io_safety", since = "1.63.0")]
163impl AsRawFdfor OwnedFd {
164#[inline]
165fn as_raw_fd(&self) -> RawFd {
166self.fd.as_inner()
167 }
168}
169170#[stable(feature = "io_safety", since = "1.63.0")]
171impl IntoRawFdfor OwnedFd {
172#[inline]
173fn into_raw_fd(self) -> RawFd {
174ManuallyDrop::new(self).fd.as_inner()
175 }
176}
177178#[stable(feature = "io_safety", since = "1.63.0")]
179impl FromRawFdfor OwnedFd {
180/// Constructs a new instance of `Self` from the given raw file descriptor.
181 ///
182 /// # Safety
183 ///
184 /// The resource pointed to by `fd` must be open and suitable for assuming
185 /// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
186 ///
187 /// [io-safety]: io#io-safety
188 ///
189 /// # Panics
190 ///
191 /// Panics if the raw file descriptor has the value `-1`.
192#[inline]
193 #[track_caller]
194unsafe fn from_raw_fd(fd: RawFd) -> Self {
195Self { fd: ValidRawFd::new(fd).expect("fd != -1") }
196 }
197}
198199#[stable(feature = "io_safety", since = "1.63.0")]
200impl Dropfor OwnedFd {
201#[inline]
202fn drop(&mut self) {
203unsafe {
204// Note that errors are ignored when closing a file descriptor. According to POSIX 2024,
205 // we can and indeed should retry `close` on `EINTR`
206 // (https://pubs.opengroup.org/onlinepubs/9799919799/functions/close.html),
207 // but it is not clear yet how well widely-used implementations are conforming with this
208 // mandate since older versions of POSIX left the state of the FD after an `EINTR`
209 // unspecified. Ignoring errors is "fine" because some of the major Unices (in
210 // particular, Linux) do make sure to always close the FD, even when `close()` is
211 // interrupted, and the scenario is rare to begin with. If we retried on a
212 // not-POSIX-compliant implementation, the consequences could be really bad since we may
213 // close the wrong FD. Helpful link to an epic discussion by POSIX workgroup that led to
214 // the latest POSIX wording: http://austingroupbugs.net/view.php?id=529
215#[cfg(not(target_os = "hermit"))]
216{
217#[cfg(unix)]
218crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
219220let _ = libc::close(self.fd.as_inner());
221 }
222#[cfg(target_os = "hermit")]
223let _ = hermit_abi::close(self.fd.as_inner());
224 }
225 }
226}
227228#[stable(feature = "io_safety", since = "1.63.0")]
229impl fmt::Debugfor BorrowedFd<'_> {
230fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
232 }
233}
234235#[stable(feature = "io_safety", since = "1.63.0")]
236impl fmt::Debugfor OwnedFd {
237fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
239 }
240}
241242macro_rules!impl_is_terminal {
243 ($($t:ty),*$(,)?) => {$(
244#[stable(feature = "is_terminal", since = "1.70.0")]
245impl io::IsTerminal for $t {
246#[inline]
247fn is_terminal(&self) -> bool {
248crate::sys::io::is_terminal(self)
249 }
250 }
251 )*}
252}
253254#[stable(feature = "is_terminal", since = "1.70.0")]
impl io::IsTerminal for OwnedFd {
#[inline]
fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) }
}impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
255256/// A trait to borrow the file descriptor from an underlying object.
257///
258/// This is only available on unix platforms and must be imported in order to
259/// call the method. Windows platforms have a corresponding `AsHandle` and
260/// `AsSocket` set of traits.
261#[stable(feature = "io_safety", since = "1.63.0")]
262pub trait AsFd {
263/// Borrows the file descriptor.
264 ///
265 /// # Example
266 ///
267 /// ```rust,no_run
268 /// use std::fs::File;
269 /// # use std::io;
270 /// # #[cfg(any(unix, target_os = "wasi"))]
271 /// # use std::os::fd::{AsFd, BorrowedFd};
272 ///
273 /// let mut f = File::open("foo.txt")?;
274 /// # #[cfg(any(unix, target_os = "wasi"))]
275 /// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
276 /// # Ok::<(), io::Error>(())
277 /// ```
278#[stable(feature = "io_safety", since = "1.63.0")]
279fn as_fd(&self) -> BorrowedFd<'_>;
280}
281282#[stable(feature = "io_safety", since = "1.63.0")]
283impl<T: AsFd + ?Sized> AsFdfor &T {
284#[inline]
285fn as_fd(&self) -> BorrowedFd<'_> {
286 T::as_fd(self)
287 }
288}
289290#[stable(feature = "io_safety", since = "1.63.0")]
291impl<T: AsFd + ?Sized> AsFdfor &mut T {
292#[inline]
293fn as_fd(&self) -> BorrowedFd<'_> {
294 T::as_fd(self)
295 }
296}
297298#[stable(feature = "io_safety", since = "1.63.0")]
299impl AsFdfor BorrowedFd<'_> {
300#[inline]
301fn as_fd(&self) -> BorrowedFd<'_> {
302*self303 }
304}
305306#[stable(feature = "io_safety", since = "1.63.0")]
307impl AsFdfor OwnedFd {
308#[inline]
309fn as_fd(&self) -> BorrowedFd<'_> {
310// Safety: `OwnedFd` and `BorrowedFd` have the same validity
311 // invariants, and the `BorrowedFd` is bounded by the lifetime
312 // of `&self`.
313unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
314 }
315}
316317#[stable(feature = "io_safety", since = "1.63.0")]
318#[cfg(not(target_os = "trusty"))]
319impl AsFdfor fs::File {
320#[inline]
321fn as_fd(&self) -> BorrowedFd<'_> {
322self.as_inner().as_fd()
323 }
324}
325326#[stable(feature = "io_safety", since = "1.63.0")]
327#[cfg(not(target_os = "trusty"))]
328impl From<fs::File> for OwnedFd {
329/// Takes ownership of a [`File`](fs::File)'s underlying file descriptor.
330#[inline]
331fn from(file: fs::File) -> OwnedFd {
332file.into_inner().into_inner().into_inner()
333 }
334}
335336#[stable(feature = "io_safety", since = "1.63.0")]
337#[cfg(not(target_os = "trusty"))]
338impl From<OwnedFd> for fs::File {
339/// Returns a [`File`](fs::File) that takes ownership of the given
340 /// file descriptor.
341#[inline]
342fn from(owned_fd: OwnedFd) -> Self {
343Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
344 }
345}
346347#[stable(feature = "io_safety", since = "1.63.0")]
348#[cfg(not(target_os = "trusty"))]
349impl AsFdfor crate::net::TcpStream {
350#[inline]
351fn as_fd(&self) -> BorrowedFd<'_> {
352self.as_inner().socket().as_fd()
353 }
354}
355356#[stable(feature = "io_safety", since = "1.63.0")]
357#[cfg(not(target_os = "trusty"))]
358impl From<crate::net::TcpStream> for OwnedFd {
359/// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor.
360#[inline]
361fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
362tcp_stream.into_inner().into_socket().into_inner().into_inner()
363 }
364}
365366#[stable(feature = "io_safety", since = "1.63.0")]
367#[cfg(not(target_os = "trusty"))]
368impl From<OwnedFd> for crate::net::TcpStream {
369#[inline]
370fn from(owned_fd: OwnedFd) -> Self {
371Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
372owned_fd,
373 ))))
374 }
375}
376377#[stable(feature = "io_safety", since = "1.63.0")]
378#[cfg(not(target_os = "trusty"))]
379impl AsFdfor crate::net::TcpListener {
380#[inline]
381fn as_fd(&self) -> BorrowedFd<'_> {
382self.as_inner().socket().as_fd()
383 }
384}
385386#[stable(feature = "io_safety", since = "1.63.0")]
387#[cfg(not(target_os = "trusty"))]
388impl From<crate::net::TcpListener> for OwnedFd {
389/// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor.
390#[inline]
391fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
392tcp_listener.into_inner().into_socket().into_inner().into_inner()
393 }
394}
395396#[stable(feature = "io_safety", since = "1.63.0")]
397#[cfg(not(target_os = "trusty"))]
398impl From<OwnedFd> for crate::net::TcpListener {
399#[inline]
400fn from(owned_fd: OwnedFd) -> Self {
401Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
402owned_fd,
403 ))))
404 }
405}
406407#[stable(feature = "io_safety", since = "1.63.0")]
408#[cfg(not(target_os = "trusty"))]
409impl AsFdfor crate::net::UdpSocket {
410#[inline]
411fn as_fd(&self) -> BorrowedFd<'_> {
412self.as_inner().socket().as_fd()
413 }
414}
415416#[stable(feature = "io_safety", since = "1.63.0")]
417#[cfg(not(target_os = "trusty"))]
418impl From<crate::net::UdpSocket> for OwnedFd {
419/// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor.
420#[inline]
421fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
422udp_socket.into_inner().into_socket().into_inner().into_inner()
423 }
424}
425426#[stable(feature = "io_safety", since = "1.63.0")]
427#[cfg(not(target_os = "trusty"))]
428impl From<OwnedFd> for crate::net::UdpSocket {
429#[inline]
430fn from(owned_fd: OwnedFd) -> Self {
431Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
432owned_fd,
433 ))))
434 }
435}
436437#[stable(feature = "asfd_ptrs", since = "1.64.0")]
438/// This impl allows implementing traits that require `AsFd` on Arc.
439/// ```
440/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
441/// # #[cfg(target_os = "wasi")]
442/// # use std::os::wasi::io::AsFd;
443/// # #[cfg(unix)]
444/// # use std::os::unix::io::AsFd;
445/// use std::net::UdpSocket;
446/// use std::sync::Arc;
447///
448/// trait MyTrait: AsFd {}
449/// impl MyTrait for Arc<UdpSocket> {}
450/// impl MyTrait for Box<UdpSocket> {}
451/// # }
452/// ```
453impl<T: AsFd + ?Sized> AsFdfor crate::sync::Arc<T> {
454#[inline]
455fn as_fd(&self) -> BorrowedFd<'_> {
456 (**self).as_fd()
457 }
458}
459460#[stable(feature = "asfd_rc", since = "1.69.0")]
461impl<T: AsFd + ?Sized> AsFdfor crate::rc::Rc<T> {
462#[inline]
463fn as_fd(&self) -> BorrowedFd<'_> {
464 (**self).as_fd()
465 }
466}
467468#[unstable(feature = "unique_rc_arc", issue = "112566")]
469impl<T: AsFd + ?Sized> AsFdfor crate::rc::UniqueRc<T> {
470#[inline]
471fn as_fd(&self) -> BorrowedFd<'_> {
472 (**self).as_fd()
473 }
474}
475476#[stable(feature = "asfd_ptrs", since = "1.64.0")]
477impl<T: AsFd + ?Sized> AsFdfor Box<T> {
478#[inline]
479fn as_fd(&self) -> BorrowedFd<'_> {
480 (**self).as_fd()
481 }
482}
483484#[stable(feature = "io_safety", since = "1.63.0")]
485impl AsFdfor io::Stdin {
486#[inline]
487fn as_fd(&self) -> BorrowedFd<'_> {
488unsafe { BorrowedFd::borrow_raw(0) }
489 }
490}
491492#[stable(feature = "io_safety", since = "1.63.0")]
493impl<'a> AsFdfor io::StdinLock<'a> {
494#[inline]
495fn as_fd(&self) -> BorrowedFd<'_> {
496// SAFETY: user code should not close stdin out from under the standard library
497unsafe { BorrowedFd::borrow_raw(0) }
498 }
499}
500501#[stable(feature = "io_safety", since = "1.63.0")]
502impl AsFdfor io::Stdout {
503#[inline]
504fn as_fd(&self) -> BorrowedFd<'_> {
505unsafe { BorrowedFd::borrow_raw(1) }
506 }
507}
508509#[stable(feature = "io_safety", since = "1.63.0")]
510impl<'a> AsFdfor io::StdoutLock<'a> {
511#[inline]
512fn as_fd(&self) -> BorrowedFd<'_> {
513// SAFETY: user code should not close stdout out from under the standard library
514unsafe { BorrowedFd::borrow_raw(1) }
515 }
516}
517518#[stable(feature = "io_safety", since = "1.63.0")]
519impl AsFdfor io::Stderr {
520#[inline]
521fn as_fd(&self) -> BorrowedFd<'_> {
522unsafe { BorrowedFd::borrow_raw(2) }
523 }
524}
525526#[stable(feature = "io_safety", since = "1.63.0")]
527impl<'a> AsFdfor io::StderrLock<'a> {
528#[inline]
529fn as_fd(&self) -> BorrowedFd<'_> {
530// SAFETY: user code should not close stderr out from under the standard library
531unsafe { BorrowedFd::borrow_raw(2) }
532 }
533}
534535#[stable(feature = "anonymous_pipe", since = "1.87.0")]
536#[cfg(not(target_os = "trusty"))]
537impl AsFdfor io::PipeReader {
538fn as_fd(&self) -> BorrowedFd<'_> {
539self.0.as_fd()
540 }
541}
542543#[stable(feature = "anonymous_pipe", since = "1.87.0")]
544#[cfg(not(target_os = "trusty"))]
545impl From<io::PipeReader> for OwnedFd {
546fn from(pipe: io::PipeReader) -> Self {
547pipe.0.into_inner()
548 }
549}
550551#[stable(feature = "anonymous_pipe", since = "1.87.0")]
552#[cfg(not(target_os = "trusty"))]
553impl AsFdfor io::PipeWriter {
554fn as_fd(&self) -> BorrowedFd<'_> {
555self.0.as_fd()
556 }
557}
558559#[stable(feature = "anonymous_pipe", since = "1.87.0")]
560#[cfg(not(target_os = "trusty"))]
561impl From<io::PipeWriter> for OwnedFd {
562fn from(pipe: io::PipeWriter) -> Self {
563pipe.0.into_inner()
564 }
565}
566567#[stable(feature = "anonymous_pipe", since = "1.87.0")]
568#[cfg(not(target_os = "trusty"))]
569impl From<OwnedFd> for io::PipeReader {
570fn from(owned_fd: OwnedFd) -> Self {
571Self(FromInner::from_inner(owned_fd))
572 }
573}
574575#[stable(feature = "anonymous_pipe", since = "1.87.0")]
576#[cfg(not(target_os = "trusty"))]
577impl From<OwnedFd> for io::PipeWriter {
578fn from(owned_fd: OwnedFd) -> Self {
579Self(FromInner::from_inner(owned_fd))
580 }
581}