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
6use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
7use crate::fmt;
8use crate::fs;
9use crate::io;
10use crate::marker::PhantomData;
11use crate::mem::forget;
12#[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))]
13use crate::sys::cvt;
14use crate::sys_common::{AsInner, FromInner, IntoInner};
15
16/// A borrowed file descriptor.
17///
18/// This has a lifetime parameter to tie it to the lifetime of something that owns the file
19/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file
20/// 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#[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#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
37#[rustc_nonnull_optimization_guaranteed]
38#[stable(feature = "io_safety", since = "1.63.0")]
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. It is guaranteed that nobody else will close the file
47/// descriptor.
48///
49/// This uses `repr(transparent)` and has the representation of a host file
50/// descriptor, so it can be used in FFI in places where a file descriptor is
51/// passed as a consumed argument or returned as an owned value, and it never
52/// has the value `-1`.
53#[repr(transparent)]
54#[rustc_layout_scalar_valid_range_start(0)]
55// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
56// 32-bit c_int. Below is -2, in two's complement, but that only works out
57// because c_int is 32 bits.
58#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
59#[rustc_nonnull_optimization_guaranteed]
60#[stable(feature = "io_safety", since = "1.63.0")]
61pub struct OwnedFd {
62 fd: RawFd,
63}
64
65impl BorrowedFd<'_> {
66 /// Return a `BorrowedFd` holding the given raw file descriptor.
67 ///
68 /// # Safety
69 ///
70 /// The resource pointed to by `fd` must remain open for the duration of
71 /// the returned `BorrowedFd`, and it must not have the value `-1`.
72 #[inline]
73 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
74 #[stable(feature = "io_safety", since = "1.63.0")]
75 pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
76 assert!(fd != u32::MAX as RawFd);
77 // 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)
78 unsafe { Self { fd, _phantom: PhantomData } }
79 }
80}
81
82impl OwnedFd {
83 /// Creates a new `OwnedFd` instance that shares the same underlying file
84 /// description as the existing `OwnedFd` instance.
85 #[stable(feature = "io_safety", since = "1.63.0")]
86 pub fn try_clone(&self) -> crate::io::Result<Self> {
87 self.as_fd().try_clone_to_owned()
88 }
89}
90
91impl BorrowedFd<'_> {
92 /// Creates a new `OwnedFd` instance that shares the same underlying file
93 /// description as the existing `BorrowedFd` instance.
94 #[cfg(not(any(target_arch = "wasm32", target_os = "hermit")))]
95 #[stable(feature = "io_safety", since = "1.63.0")]
96 pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
97 // We want to atomically duplicate this file descriptor and set the
98 // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
99 // is a POSIX flag that was added to Linux in 2.6.24.
100 #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
101 let cmd = libc::F_DUPFD_CLOEXEC;
102
103 // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
104 // will never be supported, as this is a bare metal framework with
105 // no capabilities for multi-process execution. While F_DUPFD is also
106 // not supported yet, it might be (currently it returns ENOSYS).
107 #[cfg(any(target_os = "espidf", target_os = "vita"))]
108 let cmd = libc::F_DUPFD;
109
110 // Avoid using file descriptors below 3 as they are used for stdio
111 let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
112 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
113 }
114
115 /// Creates a new `OwnedFd` instance that shares the same underlying file
116 /// description as the existing `BorrowedFd` instance.
117 #[cfg(any(target_arch = "wasm32", target_os = "hermit"))]
118 #[stable(feature = "io_safety", since = "1.63.0")]
119 pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
120 Err(crate::io::const_io_error!(
121 crate::io::ErrorKind::Unsupported,
122 "operation not supported on this platform",
123 ))
124 }
125}
126
127#[stable(feature = "io_safety", since = "1.63.0")]
128impl AsRawFd for BorrowedFd<'_> {
129 #[inline]
130 fn as_raw_fd(&self) -> RawFd {
131 self.fd
132 }
133}
134
135#[stable(feature = "io_safety", since = "1.63.0")]
136impl AsRawFd for OwnedFd {
137 #[inline]
138 fn as_raw_fd(&self) -> RawFd {
139 self.fd
140 }
141}
142
143#[stable(feature = "io_safety", since = "1.63.0")]
144impl IntoRawFd for OwnedFd {
145 #[inline]
146 fn into_raw_fd(self) -> RawFd {
147 let fd: i32 = self.fd;
148 forget(self);
149 fd
150 }
151}
152
153#[stable(feature = "io_safety", since = "1.63.0")]
154impl FromRawFd for OwnedFd {
155 /// Constructs a new instance of `Self` from the given raw file descriptor.
156 ///
157 /// # Safety
158 ///
159 /// The resource pointed to by `fd` must be open and suitable for assuming
160 /// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
161 ///
162 /// [io-safety]: io#io-safety
163 #[inline]
164 unsafe fn from_raw_fd(fd: RawFd) -> Self {
165 assert_ne!(fd, u32::MAX as RawFd);
166 // 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)
167 unsafe { Self { fd } }
168 }
169}
170
171#[stable(feature = "io_safety", since = "1.63.0")]
172impl Drop for OwnedFd {
173 #[inline]
174 fn drop(&mut self) {
175 unsafe {
176 // Note that errors are ignored when closing a file descriptor. The
177 // reason for this is that if an error occurs we don't actually know if
178 // the file descriptor was closed or not, and if we retried (for
179 // something like EINTR), we might close another valid file descriptor
180 // opened after we closed ours.
181 #[cfg(not(target_os = "hermit"))]
182 let _ = libc::close(self.fd);
183 #[cfg(target_os = "hermit")]
184 let _ = hermit_abi::close(self.fd);
185 }
186 }
187}
188
189#[stable(feature = "io_safety", since = "1.63.0")]
190impl fmt::Debug for BorrowedFd<'_> {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 f.debug_struct("BorrowedFd").field(name:"fd", &self.fd).finish()
193 }
194}
195
196#[stable(feature = "io_safety", since = "1.63.0")]
197impl fmt::Debug for OwnedFd {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 f.debug_struct("OwnedFd").field(name:"fd", &self.fd).finish()
200 }
201}
202
203macro_rules! impl_is_terminal {
204 ($($t:ty),*$(,)?) => {$(
205 #[unstable(feature = "sealed", issue = "none")]
206 impl crate::sealed::Sealed for $t {}
207
208 #[stable(feature = "is_terminal", since = "1.70.0")]
209 impl crate::io::IsTerminal for $t {
210 #[inline]
211 fn is_terminal(&self) -> bool {
212 crate::sys::io::is_terminal(self)
213 }
214 }
215 )*}
216}
217
218impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
219
220/// A trait to borrow the file descriptor from an underlying object.
221///
222/// This is only available on unix platforms and must be imported in order to
223/// call the method. Windows platforms have a corresponding `AsHandle` and
224/// `AsSocket` set of traits.
225#[stable(feature = "io_safety", since = "1.63.0")]
226pub trait AsFd {
227 /// Borrows the file descriptor.
228 ///
229 /// # Example
230 ///
231 /// ```rust,no_run
232 /// use std::fs::File;
233 /// # use std::io;
234 /// # #[cfg(any(unix, target_os = "wasi"))]
235 /// # use std::os::fd::{AsFd, BorrowedFd};
236 ///
237 /// let mut f = File::open("foo.txt")?;
238 /// # #[cfg(any(unix, target_os = "wasi"))]
239 /// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
240 /// # Ok::<(), io::Error>(())
241 /// ```
242 #[stable(feature = "io_safety", since = "1.63.0")]
243 fn as_fd(&self) -> BorrowedFd<'_>;
244}
245
246#[stable(feature = "io_safety", since = "1.63.0")]
247impl<T: AsFd> AsFd for &T {
248 #[inline]
249 fn as_fd(&self) -> BorrowedFd<'_> {
250 T::as_fd(self)
251 }
252}
253
254#[stable(feature = "io_safety", since = "1.63.0")]
255impl<T: AsFd> AsFd for &mut T {
256 #[inline]
257 fn as_fd(&self) -> BorrowedFd<'_> {
258 T::as_fd(self)
259 }
260}
261
262#[stable(feature = "io_safety", since = "1.63.0")]
263impl AsFd for BorrowedFd<'_> {
264 #[inline]
265 fn as_fd(&self) -> BorrowedFd<'_> {
266 *self
267 }
268}
269
270#[stable(feature = "io_safety", since = "1.63.0")]
271impl AsFd for OwnedFd {
272 #[inline]
273 fn as_fd(&self) -> BorrowedFd<'_> {
274 // Safety: `OwnedFd` and `BorrowedFd` have the same validity
275 // invariants, and the `BorrowedFd` is bounded by the lifetime
276 // of `&self`.
277 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
278 }
279}
280
281#[stable(feature = "io_safety", since = "1.63.0")]
282impl AsFd for fs::File {
283 #[inline]
284 fn as_fd(&self) -> BorrowedFd<'_> {
285 self.as_inner().as_fd()
286 }
287}
288
289#[stable(feature = "io_safety", since = "1.63.0")]
290impl From<fs::File> for OwnedFd {
291 #[inline]
292 fn from(file: fs::File) -> OwnedFd {
293 file.into_inner().into_inner().into_inner()
294 }
295}
296
297#[stable(feature = "io_safety", since = "1.63.0")]
298impl From<OwnedFd> for fs::File {
299 #[inline]
300 fn from(owned_fd: OwnedFd) -> Self {
301 Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
302 }
303}
304
305#[stable(feature = "io_safety", since = "1.63.0")]
306impl AsFd for crate::net::TcpStream {
307 #[inline]
308 fn as_fd(&self) -> BorrowedFd<'_> {
309 self.as_inner().socket().as_fd()
310 }
311}
312
313#[stable(feature = "io_safety", since = "1.63.0")]
314impl From<crate::net::TcpStream> for OwnedFd {
315 #[inline]
316 fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
317 tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
318 }
319}
320
321#[stable(feature = "io_safety", since = "1.63.0")]
322impl From<OwnedFd> for crate::net::TcpStream {
323 #[inline]
324 fn from(owned_fd: OwnedFd) -> Self {
325 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
326 owned_fd,
327 ))))
328 }
329}
330
331#[stable(feature = "io_safety", since = "1.63.0")]
332impl AsFd for crate::net::TcpListener {
333 #[inline]
334 fn as_fd(&self) -> BorrowedFd<'_> {
335 self.as_inner().socket().as_fd()
336 }
337}
338
339#[stable(feature = "io_safety", since = "1.63.0")]
340impl From<crate::net::TcpListener> for OwnedFd {
341 #[inline]
342 fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
343 tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
344 }
345}
346
347#[stable(feature = "io_safety", since = "1.63.0")]
348impl From<OwnedFd> for crate::net::TcpListener {
349 #[inline]
350 fn from(owned_fd: OwnedFd) -> Self {
351 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
352 owned_fd,
353 ))))
354 }
355}
356
357#[stable(feature = "io_safety", since = "1.63.0")]
358impl AsFd for crate::net::UdpSocket {
359 #[inline]
360 fn as_fd(&self) -> BorrowedFd<'_> {
361 self.as_inner().socket().as_fd()
362 }
363}
364
365#[stable(feature = "io_safety", since = "1.63.0")]
366impl From<crate::net::UdpSocket> for OwnedFd {
367 #[inline]
368 fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
369 udp_socket.into_inner().into_socket().into_inner().into_inner().into()
370 }
371}
372
373#[stable(feature = "io_safety", since = "1.63.0")]
374impl From<OwnedFd> for crate::net::UdpSocket {
375 #[inline]
376 fn from(owned_fd: OwnedFd) -> Self {
377 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
378 owned_fd,
379 ))))
380 }
381}
382
383#[stable(feature = "asfd_ptrs", since = "1.64.0")]
384/// This impl allows implementing traits that require `AsFd` on Arc.
385/// ```
386/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
387/// # #[cfg(target_os = "wasi")]
388/// # use std::os::wasi::io::AsFd;
389/// # #[cfg(unix)]
390/// # use std::os::unix::io::AsFd;
391/// use std::net::UdpSocket;
392/// use std::sync::Arc;
393///
394/// trait MyTrait: AsFd {}
395/// impl MyTrait for Arc<UdpSocket> {}
396/// impl MyTrait for Box<UdpSocket> {}
397/// # }
398/// ```
399impl<T: AsFd> AsFd for crate::sync::Arc<T> {
400 #[inline]
401 fn as_fd(&self) -> BorrowedFd<'_> {
402 (**self).as_fd()
403 }
404}
405
406#[stable(feature = "asfd_rc", since = "1.69.0")]
407impl<T: AsFd> AsFd for crate::rc::Rc<T> {
408 #[inline]
409 fn as_fd(&self) -> BorrowedFd<'_> {
410 (**self).as_fd()
411 }
412}
413
414#[stable(feature = "asfd_ptrs", since = "1.64.0")]
415impl<T: AsFd> AsFd for Box<T> {
416 #[inline]
417 fn as_fd(&self) -> BorrowedFd<'_> {
418 (**self).as_fd()
419 }
420}
421
422#[stable(feature = "io_safety", since = "1.63.0")]
423impl AsFd for io::Stdin {
424 #[inline]
425 fn as_fd(&self) -> BorrowedFd<'_> {
426 unsafe { BorrowedFd::borrow_raw(fd:0) }
427 }
428}
429
430#[stable(feature = "io_safety", since = "1.63.0")]
431impl<'a> AsFd for io::StdinLock<'a> {
432 #[inline]
433 fn as_fd(&self) -> BorrowedFd<'_> {
434 // SAFETY: user code should not close stdin out from under the standard library
435 unsafe { BorrowedFd::borrow_raw(fd:0) }
436 }
437}
438
439#[stable(feature = "io_safety", since = "1.63.0")]
440impl AsFd for io::Stdout {
441 #[inline]
442 fn as_fd(&self) -> BorrowedFd<'_> {
443 unsafe { BorrowedFd::borrow_raw(fd:1) }
444 }
445}
446
447#[stable(feature = "io_safety", since = "1.63.0")]
448impl<'a> AsFd for io::StdoutLock<'a> {
449 #[inline]
450 fn as_fd(&self) -> BorrowedFd<'_> {
451 // SAFETY: user code should not close stdout out from under the standard library
452 unsafe { BorrowedFd::borrow_raw(fd:1) }
453 }
454}
455
456#[stable(feature = "io_safety", since = "1.63.0")]
457impl AsFd for io::Stderr {
458 #[inline]
459 fn as_fd(&self) -> BorrowedFd<'_> {
460 unsafe { BorrowedFd::borrow_raw(fd:2) }
461 }
462}
463
464#[stable(feature = "io_safety", since = "1.63.0")]
465impl<'a> AsFd for io::StderrLock<'a> {
466 #[inline]
467 fn as_fd(&self) -> BorrowedFd<'_> {
468 // SAFETY: user code should not close stderr out from under the standard library
469 unsafe { BorrowedFd::borrow_raw(fd:2) }
470 }
471}
472