]> git.lizzy.rs Git - rust.git/blob - library/std/src/os/fd/owned.rs
Rollup merge of #93613 - crlf0710:rename_to_async_iter, r=yaahc
[rust.git] / library / std / src / os / fd / owned.rs
1 //! Owned and borrowed Unix-like file descriptors.
2
3 #![unstable(feature = "io_safety", issue = "87074")]
4 #![deny(unsafe_op_in_unsafe_fn)]
5
6 use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
7 use crate::fmt;
8 use crate::fs;
9 use crate::marker::PhantomData;
10 use crate::mem::forget;
11 #[cfg(not(target_os = "wasi"))]
12 use crate::sys::cvt;
13 use crate::sys_common::{AsInner, FromInner, IntoInner};
14
15 /// A borrowed file descriptor.
16 ///
17 /// This has a lifetime parameter to tie it to the lifetime of something that
18 /// owns the file descriptor.
19 ///
20 /// This uses `repr(transparent)` and has the representation of a host file
21 /// descriptor, so it can be used in FFI in places where a file descriptor is
22 /// passed as an argument, it is not captured or consumed, and it never has the
23 /// value `-1`.
24 #[derive(Copy, Clone)]
25 #[repr(transparent)]
26 #[rustc_layout_scalar_valid_range_start(0)]
27 // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
28 // 32-bit c_int. Below is -2, in two's complement, but that only works out
29 // because c_int is 32 bits.
30 #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
31 #[unstable(feature = "io_safety", issue = "87074")]
32 pub struct BorrowedFd<'fd> {
33     fd: RawFd,
34     _phantom: PhantomData<&'fd OwnedFd>,
35 }
36
37 /// An owned file descriptor.
38 ///
39 /// This closes the file descriptor on drop.
40 ///
41 /// This uses `repr(transparent)` and has the representation of a host file
42 /// descriptor, so it can be used in FFI in places where a file descriptor is
43 /// passed as a consumed argument or returned as an owned value, and it never
44 /// has the value `-1`.
45 #[repr(transparent)]
46 #[rustc_layout_scalar_valid_range_start(0)]
47 // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
48 // 32-bit c_int. Below is -2, in two's complement, but that only works out
49 // because c_int is 32 bits.
50 #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
51 #[unstable(feature = "io_safety", issue = "87074")]
52 pub struct OwnedFd {
53     fd: RawFd,
54 }
55
56 impl BorrowedFd<'_> {
57     /// Return a `BorrowedFd` holding the given raw file descriptor.
58     ///
59     /// # Safety
60     ///
61     /// The resource pointed to by `fd` must remain open for the duration of
62     /// the returned `BorrowedFd`, and it must not have the value `-1`.
63     #[inline]
64     #[unstable(feature = "io_safety", issue = "87074")]
65     pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self {
66         assert_ne!(fd, u32::MAX as RawFd);
67         // 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)
68         unsafe { Self { fd, _phantom: PhantomData } }
69     }
70 }
71
72 impl OwnedFd {
73     /// Creates a new `OwnedFd` instance that shares the same underlying file handle
74     /// as the existing `OwnedFd` instance.
75     #[cfg(not(target_os = "wasi"))]
76     pub fn try_clone(&self) -> crate::io::Result<Self> {
77         // We want to atomically duplicate this file descriptor and set the
78         // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
79         // is a POSIX flag that was added to Linux in 2.6.24.
80         #[cfg(not(target_os = "espidf"))]
81         let cmd = libc::F_DUPFD_CLOEXEC;
82
83         // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
84         // will never be supported, as this is a bare metal framework with
85         // no capabilities for multi-process execution.  While F_DUPFD is also
86         // not supported yet, it might be (currently it returns ENOSYS).
87         #[cfg(target_os = "espidf")]
88         let cmd = libc::F_DUPFD;
89
90         let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
91         Ok(unsafe { Self::from_raw_fd(fd) })
92     }
93
94     #[cfg(target_os = "wasi")]
95     pub fn try_clone(&self) -> crate::io::Result<Self> {
96         Err(crate::io::const_io_error!(
97             crate::io::ErrorKind::Unsupported,
98             "operation not supported on WASI yet",
99         ))
100     }
101 }
102
103 #[unstable(feature = "io_safety", issue = "87074")]
104 impl AsRawFd for BorrowedFd<'_> {
105     #[inline]
106     fn as_raw_fd(&self) -> RawFd {
107         self.fd
108     }
109 }
110
111 #[unstable(feature = "io_safety", issue = "87074")]
112 impl AsRawFd for OwnedFd {
113     #[inline]
114     fn as_raw_fd(&self) -> RawFd {
115         self.fd
116     }
117 }
118
119 #[unstable(feature = "io_safety", issue = "87074")]
120 impl IntoRawFd for OwnedFd {
121     #[inline]
122     fn into_raw_fd(self) -> RawFd {
123         let fd = self.fd;
124         forget(self);
125         fd
126     }
127 }
128
129 #[unstable(feature = "io_safety", issue = "87074")]
130 impl FromRawFd for OwnedFd {
131     /// Constructs a new instance of `Self` from the given raw file descriptor.
132     ///
133     /// # Safety
134     ///
135     /// The resource pointed to by `fd` must be open and suitable for assuming
136     /// ownership. The resource must not require any cleanup other than `close`.
137     #[inline]
138     unsafe fn from_raw_fd(fd: RawFd) -> Self {
139         assert_ne!(fd, u32::MAX as RawFd);
140         // 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)
141         unsafe { Self { fd } }
142     }
143 }
144
145 #[unstable(feature = "io_safety", issue = "87074")]
146 impl Drop for OwnedFd {
147     #[inline]
148     fn drop(&mut self) {
149         unsafe {
150             // Note that errors are ignored when closing a file descriptor. The
151             // reason for this is that if an error occurs we don't actually know if
152             // the file descriptor was closed or not, and if we retried (for
153             // something like EINTR), we might close another valid file descriptor
154             // opened after we closed ours.
155             let _ = libc::close(self.fd);
156         }
157     }
158 }
159
160 #[unstable(feature = "io_safety", issue = "87074")]
161 impl fmt::Debug for BorrowedFd<'_> {
162     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163         f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
164     }
165 }
166
167 #[unstable(feature = "io_safety", issue = "87074")]
168 impl fmt::Debug for OwnedFd {
169     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170         f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
171     }
172 }
173
174 /// A trait to borrow the file descriptor from an underlying object.
175 ///
176 /// This is only available on unix platforms and must be imported in order to
177 /// call the method. Windows platforms have a corresponding `AsHandle` and
178 /// `AsSocket` set of traits.
179 #[unstable(feature = "io_safety", issue = "87074")]
180 pub trait AsFd {
181     /// Borrows the file descriptor.
182     ///
183     /// # Example
184     ///
185     /// ```rust,no_run
186     /// # #![feature(io_safety)]
187     /// use std::fs::File;
188     /// # use std::io;
189     /// # #[cfg(target_os = "wasi")]
190     /// # use std::os::wasi::io::{AsFd, BorrowedFd};
191     /// # #[cfg(unix)]
192     /// # use std::os::unix::io::{AsFd, BorrowedFd};
193     ///
194     /// let mut f = File::open("foo.txt")?;
195     /// # #[cfg(any(unix, target_os = "wasi"))]
196     /// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
197     /// # Ok::<(), io::Error>(())
198     /// ```
199     #[unstable(feature = "io_safety", issue = "87074")]
200     fn as_fd(&self) -> BorrowedFd<'_>;
201 }
202
203 #[unstable(feature = "io_safety", issue = "87074")]
204 impl<T: AsFd> AsFd for &T {
205     #[inline]
206     fn as_fd(&self) -> BorrowedFd<'_> {
207         T::as_fd(self)
208     }
209 }
210
211 #[unstable(feature = "io_safety", issue = "87074")]
212 impl<T: AsFd> AsFd for &mut T {
213     #[inline]
214     fn as_fd(&self) -> BorrowedFd<'_> {
215         T::as_fd(self)
216     }
217 }
218
219 #[unstable(feature = "io_safety", issue = "87074")]
220 impl AsFd for BorrowedFd<'_> {
221     #[inline]
222     fn as_fd(&self) -> BorrowedFd<'_> {
223         *self
224     }
225 }
226
227 #[unstable(feature = "io_safety", issue = "87074")]
228 impl AsFd for OwnedFd {
229     #[inline]
230     fn as_fd(&self) -> BorrowedFd<'_> {
231         // Safety: `OwnedFd` and `BorrowedFd` have the same validity
232         // invariants, and the `BorrowdFd` is bounded by the lifetime
233         // of `&self`.
234         unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) }
235     }
236 }
237
238 #[unstable(feature = "io_safety", issue = "87074")]
239 impl AsFd for fs::File {
240     #[inline]
241     fn as_fd(&self) -> BorrowedFd<'_> {
242         self.as_inner().as_fd()
243     }
244 }
245
246 #[unstable(feature = "io_safety", issue = "87074")]
247 impl From<fs::File> for OwnedFd {
248     #[inline]
249     fn from(file: fs::File) -> OwnedFd {
250         file.into_inner().into_inner().into_inner()
251     }
252 }
253
254 #[unstable(feature = "io_safety", issue = "87074")]
255 impl From<OwnedFd> for fs::File {
256     #[inline]
257     fn from(owned_fd: OwnedFd) -> Self {
258         Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
259     }
260 }
261
262 #[unstable(feature = "io_safety", issue = "87074")]
263 impl AsFd for crate::net::TcpStream {
264     #[inline]
265     fn as_fd(&self) -> BorrowedFd<'_> {
266         self.as_inner().socket().as_fd()
267     }
268 }
269
270 #[unstable(feature = "io_safety", issue = "87074")]
271 impl From<crate::net::TcpStream> for OwnedFd {
272     #[inline]
273     fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
274         tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
275     }
276 }
277
278 #[unstable(feature = "io_safety", issue = "87074")]
279 impl From<OwnedFd> for crate::net::TcpStream {
280     #[inline]
281     fn from(owned_fd: OwnedFd) -> Self {
282         Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
283             owned_fd,
284         ))))
285     }
286 }
287
288 #[unstable(feature = "io_safety", issue = "87074")]
289 impl AsFd for crate::net::TcpListener {
290     #[inline]
291     fn as_fd(&self) -> BorrowedFd<'_> {
292         self.as_inner().socket().as_fd()
293     }
294 }
295
296 #[unstable(feature = "io_safety", issue = "87074")]
297 impl From<crate::net::TcpListener> for OwnedFd {
298     #[inline]
299     fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
300         tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
301     }
302 }
303
304 #[unstable(feature = "io_safety", issue = "87074")]
305 impl From<OwnedFd> for crate::net::TcpListener {
306     #[inline]
307     fn from(owned_fd: OwnedFd) -> Self {
308         Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
309             owned_fd,
310         ))))
311     }
312 }
313
314 #[unstable(feature = "io_safety", issue = "87074")]
315 impl AsFd for crate::net::UdpSocket {
316     #[inline]
317     fn as_fd(&self) -> BorrowedFd<'_> {
318         self.as_inner().socket().as_fd()
319     }
320 }
321
322 #[unstable(feature = "io_safety", issue = "87074")]
323 impl From<crate::net::UdpSocket> for OwnedFd {
324     #[inline]
325     fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
326         udp_socket.into_inner().into_socket().into_inner().into_inner().into()
327     }
328 }
329
330 #[unstable(feature = "io_safety", issue = "87074")]
331 impl From<OwnedFd> for crate::net::UdpSocket {
332     #[inline]
333     fn from(owned_fd: OwnedFd) -> Self {
334         Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
335             owned_fd,
336         ))))
337     }
338 }