• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! The following is derived from Rust's
2 //! library/std/src/os/fd/owned.rs at revision
3 //! fa68e73e9947be8ffc5b3b46d899e4953a44e7e9.
4 //!
5 //! Owned and borrowed Unix-like file descriptors.
6 
7 #![cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
8 #![deny(unsafe_op_in_unsafe_fn)]
9 #![allow(unsafe_code)]
10 
11 use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
12 use crate::io::close;
13 use core::fmt;
14 use core::marker::PhantomData;
15 use core::mem::forget;
16 
17 /// A borrowed file descriptor.
18 ///
19 /// This has a lifetime parameter to tie it to the lifetime of something that
20 /// owns the file 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 #[cfg_attr(rustc_attrs, 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 #[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
37 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
38 #[cfg_attr(rustc_attrs, rustc_nonnull_optimization_guaranteed)]
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.
47 ///
48 /// This uses `repr(transparent)` and has the representation of a host file
49 /// descriptor, so it can be used in FFI in places where a file descriptor is
50 /// passed as a consumed argument or returned as an owned value, and it never
51 /// has the value `-1`.
52 #[repr(transparent)]
53 #[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_start(0))]
54 // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
55 // 32-bit c_int. Below is -2, in two's complement, but that only works out
56 // because c_int is 32 bits.
57 #[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
58 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
59 #[cfg_attr(rustc_attrs, rustc_nonnull_optimization_guaranteed)]
60 pub struct OwnedFd {
61     fd: RawFd,
62 }
63 
64 impl BorrowedFd<'_> {
65     /// Return a `BorrowedFd` holding the given raw file descriptor.
66     ///
67     /// # Safety
68     ///
69     /// The resource pointed to by `fd` must remain open for the duration of
70     /// the returned `BorrowedFd`, and it must not have the value `-1`.
71     #[inline]
72     #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
borrow_raw(fd: RawFd) -> Self73     pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
74         assert!(fd != u32::MAX as RawFd);
75         // 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)
76         #[allow(unused_unsafe)]
77         unsafe {
78             Self {
79                 fd,
80                 _phantom: PhantomData,
81             }
82         }
83     }
84 }
85 
86 impl OwnedFd {
87     /// Creates a new `OwnedFd` instance that shares the same underlying file handle
88     /// as the existing `OwnedFd` instance.
89     #[cfg(not(target_arch = "wasm32"))]
try_clone(&self) -> crate::io::Result<Self>90     pub fn try_clone(&self) -> crate::io::Result<Self> {
91         // We want to atomically duplicate this file descriptor and set the
92         // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
93         // is a POSIX flag that was added to Linux in 2.6.24.
94         #[cfg(not(target_os = "espidf"))]
95         let fd = crate::io::fcntl_dupfd_cloexec(self, 0)?;
96 
97         // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
98         // will never be supported, as this is a bare metal framework with
99         // no capabilities for multi-process execution. While F_DUPFD is also
100         // not supported yet, it might be (currently it returns ENOSYS).
101         #[cfg(target_os = "espidf")]
102         let fd = crate::io::fcntl_dupfd(self)?;
103 
104         Ok(fd.into())
105     }
106 
107     #[cfg(target_arch = "wasm32")]
try_clone(&self) -> crate::io::Result<Self>108     pub fn try_clone(&self) -> crate::io::Result<Self> {
109         Err(crate::io::const_io_error!(
110             crate::io::ErrorKind::Unsupported,
111             "operation not supported on WASI yet",
112         ))
113     }
114 }
115 
116 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
117 impl AsRawFd for BorrowedFd<'_> {
118     #[inline]
as_raw_fd(&self) -> RawFd119     fn as_raw_fd(&self) -> RawFd {
120         self.fd
121     }
122 }
123 
124 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
125 impl AsRawFd for OwnedFd {
126     #[inline]
as_raw_fd(&self) -> RawFd127     fn as_raw_fd(&self) -> RawFd {
128         self.fd
129     }
130 }
131 
132 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
133 impl IntoRawFd for OwnedFd {
134     #[inline]
into_raw_fd(self) -> RawFd135     fn into_raw_fd(self) -> RawFd {
136         let fd = self.fd;
137         forget(self);
138         fd
139     }
140 }
141 
142 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
143 impl FromRawFd for OwnedFd {
144     /// Constructs a new instance of `Self` from the given raw file descriptor.
145     ///
146     /// # Safety
147     ///
148     /// The resource pointed to by `fd` must be open and suitable for assuming
149     /// ownership. The resource must not require any cleanup other than `close`.
150     #[inline]
from_raw_fd(fd: RawFd) -> Self151     unsafe fn from_raw_fd(fd: RawFd) -> Self {
152         assert_ne!(fd, u32::MAX as RawFd);
153         // 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)
154         #[allow(unused_unsafe)]
155         unsafe {
156             Self { fd }
157         }
158     }
159 }
160 
161 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
162 impl Drop for OwnedFd {
163     #[inline]
drop(&mut self)164     fn drop(&mut self) {
165         unsafe {
166             // Errors are ignored when closing a file descriptor. The reason
167             // for this is that if an error occurs we don't actually know if
168             // the file descriptor was closed or not, and if we retried (for
169             // something like EINTR), we might close another valid file
170             // descriptor opened after we closed ours.
171             let _ = close(self.fd as _);
172         }
173     }
174 }
175 
176 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
177 impl fmt::Debug for BorrowedFd<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result178     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179         f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
180     }
181 }
182 
183 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
184 impl fmt::Debug for OwnedFd {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result185     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186         f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
187     }
188 }
189 
190 /// A trait to borrow the file descriptor from an underlying object.
191 ///
192 /// This is only available on unix platforms and must be imported in order to
193 /// call the method. Windows platforms have a corresponding `AsHandle` and
194 /// `AsSocket` set of traits.
195 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
196 pub trait AsFd {
197     /// Borrows the file descriptor.
198     ///
199     /// # Example
200     ///
201     /// ```rust,no_run
202     /// # #![feature(io_safety)]
203     /// use std::fs::File;
204     /// # use std::io;
205     /// # #[cfg(target_os = "wasi")]
206     /// # use std::os::wasi::io::{AsFd, BorrowedFd};
207     /// # #[cfg(unix)]
208     /// # use std::os::unix::io::{AsFd, BorrowedFd};
209     ///
210     /// let mut f = File::open("foo.txt")?;
211     /// # #[cfg(any(unix, target_os = "wasi"))]
212     /// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
213     /// # Ok::<(), io::Error>(())
214     /// ```
215     #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
as_fd(&self) -> BorrowedFd<'_>216     fn as_fd(&self) -> BorrowedFd<'_>;
217 }
218 
219 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
220 impl<T: AsFd> AsFd for &T {
221     #[inline]
as_fd(&self) -> BorrowedFd<'_>222     fn as_fd(&self) -> BorrowedFd<'_> {
223         T::as_fd(self)
224     }
225 }
226 
227 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
228 impl<T: AsFd> AsFd for &mut T {
229     #[inline]
as_fd(&self) -> BorrowedFd<'_>230     fn as_fd(&self) -> BorrowedFd<'_> {
231         T::as_fd(self)
232     }
233 }
234 
235 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
236 impl AsFd for BorrowedFd<'_> {
237     #[inline]
as_fd(&self) -> BorrowedFd<'_>238     fn as_fd(&self) -> BorrowedFd<'_> {
239         *self
240     }
241 }
242 
243 #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
244 impl AsFd for OwnedFd {
245     #[inline]
as_fd(&self) -> BorrowedFd<'_>246     fn as_fd(&self) -> BorrowedFd<'_> {
247         // Safety: `OwnedFd` and `BorrowedFd` have the same validity
248         // invariants, and the `BorrowedFd` is bounded by the lifetime
249         // of `&self`.
250         unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
251     }
252 }
253