]> git.proxmox.com Git - rustc.git/blame - vendor/rustix/src/io/fd/owned.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / vendor / rustix / src / io / fd / owned.rs
CommitLineData
064997fb
FG
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
11use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
12use crate::io::close;
13use core::fmt;
14use core::marker::PhantomData;
15use 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)]
39pub 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)]
60pub struct OwnedFd {
61 fd: RawFd,
62}
63
64impl 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"))]
73 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
86impl 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"))]
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"))]
487cf647 95 let fd = crate::io::fcntl_dupfd_cloexec(self, 0)?;
064997fb
FG
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")]
487cf647 102 let fd = crate::io::fcntl_dupfd(self)?;
064997fb
FG
103
104 Ok(fd.into())
105 }
106
107 #[cfg(target_arch = "wasm32")]
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"))]
117impl AsRawFd for BorrowedFd<'_> {
118 #[inline]
119 fn as_raw_fd(&self) -> RawFd {
120 self.fd
121 }
122}
123
124#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
125impl AsRawFd for OwnedFd {
126 #[inline]
127 fn as_raw_fd(&self) -> RawFd {
128 self.fd
129 }
130}
131
132#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
133impl IntoRawFd for OwnedFd {
134 #[inline]
135 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"))]
143impl 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]
151 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"))]
162impl Drop for OwnedFd {
163 #[inline]
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.
353b0b11 171 close(self.fd as _);
064997fb
FG
172 }
173 }
174}
175
176#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
177impl fmt::Debug for BorrowedFd<'_> {
178 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"))]
184impl fmt::Debug for OwnedFd {
185 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"))]
196pub trait AsFd {
197 /// Borrows the file descriptor.
198 ///
199 /// # Example
200 ///
353b0b11 201 /// ```no_run
064997fb
FG
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"))]
216 fn as_fd(&self) -> BorrowedFd<'_>;
217}
218
219#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
220impl<T: AsFd> AsFd for &T {
221 #[inline]
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"))]
228impl<T: AsFd> AsFd for &mut T {
229 #[inline]
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"))]
236impl AsFd for BorrowedFd<'_> {
237 #[inline]
238 fn as_fd(&self) -> BorrowedFd<'_> {
239 *self
240 }
241}
242
243#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))]
244impl AsFd for OwnedFd {
245 #[inline]
246 fn as_fd(&self) -> BorrowedFd<'_> {
353b0b11 247 // SAFETY: `OwnedFd` and `BorrowedFd` have the same validity
064997fb
FG
248 // invariants, and the `BorrowedFd` is bounded by the lifetime
249 // of `&self`.
250 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
251 }
252}