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