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};
10use crate::alloc::Allocator;
11#[cfg(not(target_os = "trusty"))]
12use crate::fs;
13use crate::marker::PhantomData;
14use crate::mem::ManuallyDrop;
15#[cfg(not(any(
16 all(target_family = "wasm", not(target_os = "emscripten")),
17 target_env = "sgx",
18 target_os = "hermit",
19 target_os = "trusty",
20 target_os = "motor"
21)))]
22use crate::sys::cvt;
23#[cfg(not(target_os = "trusty"))]
24use crate::sys::{AsInner, FromInner, IntoInner};
25use crate::{fmt, io};
2627type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
2829/// A borrowed file descriptor.
30///
31/// This has a lifetime parameter to tie it to the lifetime of something that owns the file
32/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file
33/// descriptor.
34///
35/// This uses `repr(transparent)` and has the representation of a host file
36/// descriptor, so it can be used in FFI in places where a file descriptor is
37/// passed as an argument, it is not captured or consumed, and it never has the
38/// value `-1`.
39///
40/// This type does not have a [`ToOwned`][crate::borrow::ToOwned]
41/// implementation. Calling `.to_owned()` on a variable of this type will call
42/// it on `&BorrowedFd` and use `Clone::clone()` like `ToOwned` does for all
43/// types implementing `Clone`. The result will be descriptor borrowed under
44/// the same lifetime.
45///
46/// To obtain an [`OwnedFd`], you can use [`BorrowedFd::try_clone_to_owned`]
47/// instead, but this is not supported on all platforms.
48#[derive(#[automatically_derived]
#[stable(feature = "io_safety", since = "1.63.0")]
impl<'fd> ::core::marker::Copy for BorrowedFd<'fd> { }Copy, #[automatically_derived]
#[doc(hidden)]
#[stable(feature = "io_safety", since = "1.63.0")]
unsafe impl<'fd> ::core::clone::TrivialClone for BorrowedFd<'fd> { }
#[automatically_derived]
#[stable(feature = "io_safety", since = "1.63.0")]
impl<'fd> ::core::clone::Clone for BorrowedFd<'fd> {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<ValidRawFd>;
let _: ::core::clone::AssertParamIsClone<PhantomData<&'fd OwnedFd>>;
*self
}
}Clone)]
49#[repr(transparent)]
50#[rustc_nonnull_optimization_guaranteed]
51#[stable(feature = "io_safety", since = "1.63.0")]
52pub struct BorrowedFd<'fd> {
53 fd: ValidRawFd,
54 _phantom: PhantomData<&'fd OwnedFd>,
55}
5657/// An owned file descriptor.
58///
59/// This closes the file descriptor on drop. It is guaranteed that nobody else will close the file
60/// descriptor.
61///
62/// This uses `repr(transparent)` and has the representation of a host file
63/// descriptor, so it can be used in FFI in places where a file descriptor is
64/// passed as a consumed argument or returned as an owned value, and it never
65/// has the value `-1`.
66///
67/// You can use [`AsFd::as_fd`] to obtain a [`BorrowedFd`].
68#[repr(transparent)]
69#[rustc_nonnull_optimization_guaranteed]
70#[stable(feature = "io_safety", since = "1.63.0")]
71pub struct OwnedFd {
72 fd: ValidRawFd,
73}
7475impl BorrowedFd<'_> {
76/// Returns a `BorrowedFd` holding the given raw file descriptor.
77 ///
78 /// # Safety
79 ///
80 /// The resource pointed to by `fd` must remain open for the duration of
81 /// the returned `BorrowedFd`.
82 ///
83 /// # Panics
84 ///
85 /// Panics if the raw file descriptor has the value `-1`.
86#[inline]
87 #[track_caller]
88 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
89 #[stable(feature = "io_safety", since = "1.63.0")]
90pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
91Self { fd: ValidRawFd::new(fd).expect("fd != -1"), _phantom: PhantomData }
92 }
93}
9495impl OwnedFd {
96/// Creates a new `OwnedFd` instance that shares the same underlying file
97 /// description as the existing `OwnedFd` instance.
98#[stable(feature = "io_safety", since = "1.63.0")]
99pub fn try_clone(&self) -> io::Result<Self> {
100self.as_fd().try_clone_to_owned()
101 }
102}
103104impl BorrowedFd<'_> {
105/// Creates a new `OwnedFd` instance that shares the same underlying file
106 /// description as the existing `BorrowedFd` instance.
107#[cfg(not(any(
108 all(target_family = "wasm", not(target_os = "emscripten")),
109 target_os = "hermit",
110 target_os = "trusty",
111 target_os = "motor"
112)))]
113 #[stable(feature = "io_safety", since = "1.63.0")]
114pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
115// We want to atomically duplicate this file descriptor and set the
116 // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
117 // is a POSIX flag that was added to Linux in 2.6.24.
118#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
119let cmd = libc::F_DUPFD_CLOEXEC;
120121// For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
122 // will never be supported, as this is a bare metal framework with
123 // no capabilities for multi-process execution. While F_DUPFD is also
124 // not supported yet, it might be (currently it returns ENOSYS).
125#[cfg(any(target_os = "espidf", target_os = "vita"))]
126let cmd = libc::F_DUPFD;
127128// Avoid using file descriptors below 3 as they are used for stdio
129let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
130Ok(unsafe { OwnedFd::from_raw_fd(fd) })
131 }
132133/// Creates a new `OwnedFd` instance that shares the same underlying file
134 /// description as the existing `BorrowedFd` instance.
135#[cfg(any(
136 all(target_family = "wasm", not(target_os = "emscripten")),
137 target_os = "hermit",
138 target_os = "trusty"
139))]
140 #[stable(feature = "io_safety", since = "1.63.0")]
141pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
142Err(io::Error::UNSUPPORTED_PLATFORM)
143 }
144145/// Creates a new `OwnedFd` instance that shares the same underlying file
146 /// description as the existing `BorrowedFd` instance.
147#[cfg(target_os = "motor")]
148 #[stable(feature = "io_safety", since = "1.63.0")]
149pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
150let fd = moto_rt::fs::duplicate(self.as_raw_fd()).map_err(crate::sys::map_motor_error)?;
151Ok(unsafe { OwnedFd::from_raw_fd(fd) })
152 }
153}
154155#[stable(feature = "io_safety", since = "1.63.0")]
156impl AsRawFdfor BorrowedFd<'_> {
157#[inline]
158fn as_raw_fd(&self) -> RawFd {
159self.fd.as_inner()
160 }
161}
162163#[stable(feature = "io_safety", since = "1.63.0")]
164impl AsRawFdfor OwnedFd {
165#[inline]
166fn as_raw_fd(&self) -> RawFd {
167self.fd.as_inner()
168 }
169}
170171#[stable(feature = "io_safety", since = "1.63.0")]
172impl IntoRawFdfor OwnedFd {
173#[inline]
174fn into_raw_fd(self) -> RawFd {
175ManuallyDrop::new(self).fd.as_inner()
176 }
177}
178179#[stable(feature = "io_safety", since = "1.63.0")]
180impl FromRawFdfor OwnedFd {
181/// Constructs a new instance of `Self` from the given raw file descriptor.
182 ///
183 /// # Safety
184 ///
185 /// The resource pointed to by `fd` must be open and suitable for assuming
186 /// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
187 ///
188 /// [io-safety]: io#io-safety
189 ///
190 /// # Panics
191 ///
192 /// Panics if the raw file descriptor has the value `-1`.
193#[inline]
194 #[track_caller]
195unsafe fn from_raw_fd(fd: RawFd) -> Self {
196Self { fd: ValidRawFd::new(fd).expect("fd != -1") }
197 }
198}
199200#[stable(feature = "io_safety", since = "1.63.0")]
201impl Dropfor OwnedFd {
202#[inline]
203fn drop(&mut self) {
204unsafe {
205// Note that errors are ignored when closing a file descriptor. According to POSIX 2024,
206 // we can and indeed should retry `close` on `EINTR`
207 // (https://pubs.opengroup.org/onlinepubs/9799919799/functions/close.html),
208 // but it is not clear yet how well widely-used implementations are conforming with this
209 // mandate since older versions of POSIX left the state of the FD after an `EINTR`
210 // unspecified. Ignoring errors is "fine" because some of the major Unices (in
211 // particular, Linux) do make sure to always close the FD, even when `close()` is
212 // interrupted, and the scenario is rare to begin with. If we retried on a
213 // not-POSIX-compliant implementation, the consequences could be really bad since we may
214 // close the wrong FD. Helpful link to an epic discussion by POSIX workgroup that led to
215 // the latest POSIX wording: http://austingroupbugs.net/view.php?id=529
216#[cfg(not(target_os = "hermit"))]
217{
218#[cfg(unix)]
219crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
220221let _ = libc::close(self.fd.as_inner());
222 }
223#[cfg(target_os = "hermit")]
224let _ = hermit_abi::close(self.fd.as_inner());
225 }
226 }
227}
228229#[stable(feature = "io_safety", since = "1.63.0")]
230impl fmt::Debugfor BorrowedFd<'_> {
231fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
233 }
234}
235236#[stable(feature = "io_safety", since = "1.63.0")]
237impl fmt::Debugfor OwnedFd {
238fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
240 }
241}
242243macro_rules!impl_is_terminal {
244 ($($t:ty),*$(,)?) => {$(
245#[stable(feature = "is_terminal", since = "1.70.0")]
246impl io::IsTerminal for $t {
247#[inline]
248fn is_terminal(&self) -> bool {
249crate::sys::io::is_terminal(self)
250 }
251 }
252 )*}
253}
254255#[stable(feature = "is_terminal", since = "1.70.0")]
impl io::IsTerminal for BorrowedFd<'_> {
#[inline]
fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) }
}
#[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);
256257/// A trait to borrow the file descriptor from an underlying object.
258///
259/// This is only available on unix platforms and must be imported in order to
260/// call the method. Windows platforms have a corresponding `AsHandle` and
261/// `AsSocket` set of traits.
262#[stable(feature = "io_safety", since = "1.63.0")]
263pub trait AsFd {
264/// Borrows the file descriptor.
265 ///
266 /// # Example
267 ///
268 /// ```rust,no_run
269 /// use std::fs::File;
270 /// # use std::io;
271 /// # #[cfg(any(unix, target_os = "wasi"))]
272 /// # use std::os::fd::{AsFd, BorrowedFd};
273 ///
274 /// let mut f = File::open("foo.txt")?;
275 /// # #[cfg(any(unix, target_os = "wasi"))]
276 /// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
277 /// # Ok::<(), io::Error>(())
278 /// ```
279#[stable(feature = "io_safety", since = "1.63.0")]
280fn as_fd(&self) -> BorrowedFd<'_>;
281}
282283#[stable(feature = "io_safety", since = "1.63.0")]
284impl<T: AsFd + ?Sized> AsFdfor &T {
285#[inline]
286fn as_fd(&self) -> BorrowedFd<'_> {
287 T::as_fd(self)
288 }
289}
290291#[stable(feature = "io_safety", since = "1.63.0")]
292impl<T: AsFd + ?Sized> AsFdfor &mut T {
293#[inline]
294fn as_fd(&self) -> BorrowedFd<'_> {
295 T::as_fd(self)
296 }
297}
298299#[stable(feature = "io_safety", since = "1.63.0")]
300impl AsFdfor BorrowedFd<'_> {
301#[inline]
302fn as_fd(&self) -> BorrowedFd<'_> {
303*self304 }
305}
306307#[stable(feature = "io_safety", since = "1.63.0")]
308impl AsFdfor OwnedFd {
309#[inline]
310fn as_fd(&self) -> BorrowedFd<'_> {
311// Safety: `OwnedFd` and `BorrowedFd` have the same validity
312 // invariants, and the `BorrowedFd` is bounded by the lifetime
313 // of `&self`.
314unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
315 }
316}
317318#[stable(feature = "io_safety", since = "1.63.0")]
319#[cfg(not(target_os = "trusty"))]
320impl AsFdfor fs::File {
321#[inline]
322fn as_fd(&self) -> BorrowedFd<'_> {
323self.as_inner().as_fd()
324 }
325}
326327#[stable(feature = "io_safety", since = "1.63.0")]
328#[cfg(not(target_os = "trusty"))]
329impl From<fs::File> for OwnedFd {
330/// Takes ownership of a [`File`](fs::File)'s underlying file descriptor.
331#[inline]
332fn from(file: fs::File) -> OwnedFd {
333file.into_inner().into_inner().into_inner()
334 }
335}
336337#[stable(feature = "io_safety", since = "1.63.0")]
338#[cfg(not(target_os = "trusty"))]
339impl From<OwnedFd> for fs::File {
340/// Returns a [`File`](fs::File) that takes ownership of the given
341 /// file descriptor.
342#[inline]
343fn from(owned_fd: OwnedFd) -> Self {
344Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
345 }
346}
347348#[stable(feature = "io_safety", since = "1.63.0")]
349#[cfg(not(target_os = "trusty"))]
350impl AsFdfor crate::net::TcpStream {
351#[inline]
352fn as_fd(&self) -> BorrowedFd<'_> {
353self.as_inner().socket().as_fd()
354 }
355}
356357#[stable(feature = "io_safety", since = "1.63.0")]
358#[cfg(not(target_os = "trusty"))]
359impl From<crate::net::TcpStream> for OwnedFd {
360/// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor.
361#[inline]
362fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
363tcp_stream.into_inner().into_socket().into_inner().into_inner()
364 }
365}
366367#[stable(feature = "io_safety", since = "1.63.0")]
368#[cfg(not(target_os = "trusty"))]
369impl From<OwnedFd> for crate::net::TcpStream {
370#[inline]
371fn from(owned_fd: OwnedFd) -> Self {
372Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
373owned_fd,
374 ))))
375 }
376}
377378#[stable(feature = "io_safety", since = "1.63.0")]
379#[cfg(not(target_os = "trusty"))]
380impl AsFdfor crate::net::TcpListener {
381#[inline]
382fn as_fd(&self) -> BorrowedFd<'_> {
383self.as_inner().socket().as_fd()
384 }
385}
386387#[stable(feature = "io_safety", since = "1.63.0")]
388#[cfg(not(target_os = "trusty"))]
389impl From<crate::net::TcpListener> for OwnedFd {
390/// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor.
391#[inline]
392fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
393tcp_listener.into_inner().into_socket().into_inner().into_inner()
394 }
395}
396397#[stable(feature = "io_safety", since = "1.63.0")]
398#[cfg(not(target_os = "trusty"))]
399impl From<OwnedFd> for crate::net::TcpListener {
400#[inline]
401fn from(owned_fd: OwnedFd) -> Self {
402Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
403owned_fd,
404 ))))
405 }
406}
407408#[stable(feature = "io_safety", since = "1.63.0")]
409#[cfg(not(target_os = "trusty"))]
410impl AsFdfor crate::net::UdpSocket {
411#[inline]
412fn as_fd(&self) -> BorrowedFd<'_> {
413self.as_inner().socket().as_fd()
414 }
415}
416417#[stable(feature = "io_safety", since = "1.63.0")]
418#[cfg(not(target_os = "trusty"))]
419impl From<crate::net::UdpSocket> for OwnedFd {
420/// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor.
421#[inline]
422fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
423udp_socket.into_inner().into_socket().into_inner().into_inner()
424 }
425}
426427#[stable(feature = "io_safety", since = "1.63.0")]
428#[cfg(not(target_os = "trusty"))]
429impl From<OwnedFd> for crate::net::UdpSocket {
430#[inline]
431fn from(owned_fd: OwnedFd) -> Self {
432Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
433owned_fd,
434 ))))
435 }
436}
437438#[stable(feature = "asfd_ptrs", since = "1.64.0")]
439/// This impl allows implementing traits that require `AsFd` on Arc.
440/// ```
441/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
442/// # #[cfg(target_os = "wasi")]
443/// # use std::os::wasi::io::AsFd;
444/// # #[cfg(unix)]
445/// # use std::os::unix::io::AsFd;
446/// use std::net::UdpSocket;
447/// use std::sync::Arc;
448///
449/// trait MyTrait: AsFd {}
450/// impl MyTrait for Arc<UdpSocket> {}
451/// impl MyTrait for Box<UdpSocket> {}
452/// # }
453/// ```
454impl<T: AsFd + ?Sized> AsFdfor crate::sync::Arc<T> {
455#[inline]
456fn as_fd(&self) -> BorrowedFd<'_> {
457 (**self).as_fd()
458 }
459}
460461#[stable(feature = "asfd_rc", since = "1.69.0")]
462impl<T: AsFd + ?Sized> AsFdfor crate::rc::Rc<T> {
463#[inline]
464fn as_fd(&self) -> BorrowedFd<'_> {
465 (**self).as_fd()
466 }
467}
468469#[unstable(feature = "unique_rc_arc", issue = "112566")]
470impl<T: AsFd + ?Sized> AsFdfor crate::rc::UniqueRc<T> {
471#[inline]
472fn as_fd(&self) -> BorrowedFd<'_> {
473 (**self).as_fd()
474 }
475}
476477#[stable(feature = "asfd_ptrs", since = "1.64.0")]
478impl<T: AsFd + ?Sized, A: Allocator> AsFdfor Box<T, A> {
479#[inline]
480fn as_fd(&self) -> BorrowedFd<'_> {
481 (**self).as_fd()
482 }
483}
484485#[stable(feature = "io_safety", since = "1.63.0")]
486impl AsFdfor io::Stdin {
487#[inline]
488fn as_fd(&self) -> BorrowedFd<'_> {
489unsafe { BorrowedFd::borrow_raw(0) }
490 }
491}
492493#[stable(feature = "io_safety", since = "1.63.0")]
494impl<'a> AsFdfor io::StdinLock<'a> {
495#[inline]
496fn as_fd(&self) -> BorrowedFd<'_> {
497// SAFETY: user code should not close stdin out from under the standard library
498unsafe { BorrowedFd::borrow_raw(0) }
499 }
500}
501502#[stable(feature = "io_safety", since = "1.63.0")]
503impl AsFdfor io::Stdout {
504#[inline]
505fn as_fd(&self) -> BorrowedFd<'_> {
506unsafe { BorrowedFd::borrow_raw(1) }
507 }
508}
509510#[stable(feature = "io_safety", since = "1.63.0")]
511impl<'a> AsFdfor io::StdoutLock<'a> {
512#[inline]
513fn as_fd(&self) -> BorrowedFd<'_> {
514// SAFETY: user code should not close stdout out from under the standard library
515unsafe { BorrowedFd::borrow_raw(1) }
516 }
517}
518519#[stable(feature = "io_safety", since = "1.63.0")]
520impl AsFdfor io::Stderr {
521#[inline]
522fn as_fd(&self) -> BorrowedFd<'_> {
523unsafe { BorrowedFd::borrow_raw(2) }
524 }
525}
526527#[stable(feature = "io_safety", since = "1.63.0")]
528impl<'a> AsFdfor io::StderrLock<'a> {
529#[inline]
530fn as_fd(&self) -> BorrowedFd<'_> {
531// SAFETY: user code should not close stderr out from under the standard library
532unsafe { BorrowedFd::borrow_raw(2) }
533 }
534}
535536#[stable(feature = "anonymous_pipe", since = "1.87.0")]
537#[cfg(not(target_os = "trusty"))]
538impl AsFdfor io::PipeReader {
539fn as_fd(&self) -> BorrowedFd<'_> {
540self.0.as_fd()
541 }
542}
543544#[stable(feature = "anonymous_pipe", since = "1.87.0")]
545#[cfg(not(target_os = "trusty"))]
546impl From<io::PipeReader> for OwnedFd {
547fn from(pipe: io::PipeReader) -> Self {
548pipe.0.into_inner()
549 }
550}
551552#[stable(feature = "anonymous_pipe", since = "1.87.0")]
553#[cfg(not(target_os = "trusty"))]
554impl AsFdfor io::PipeWriter {
555fn as_fd(&self) -> BorrowedFd<'_> {
556self.0.as_fd()
557 }
558}
559560#[stable(feature = "anonymous_pipe", since = "1.87.0")]
561#[cfg(not(target_os = "trusty"))]
562impl From<io::PipeWriter> for OwnedFd {
563fn from(pipe: io::PipeWriter) -> Self {
564pipe.0.into_inner()
565 }
566}
567568#[stable(feature = "anonymous_pipe", since = "1.87.0")]
569#[cfg(not(target_os = "trusty"))]
570impl From<OwnedFd> for io::PipeReader {
571fn from(owned_fd: OwnedFd) -> Self {
572Self(FromInner::from_inner(owned_fd))
573 }
574}
575576#[stable(feature = "anonymous_pipe", since = "1.87.0")]
577#[cfg(not(target_os = "trusty"))]
578impl From<OwnedFd> for io::PipeWriter {
579fn from(owned_fd: OwnedFd) -> Self {
580Self(FromInner::from_inner(owned_fd))
581 }
582}