1#![stable(feature = "io_safety", since = "1.63.0")]
4#![deny(unsafe_op_in_unsafe_fn)]
5
6#[cfg(target_os = "motor")]
7use moto_rt::libc;
8
9use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
10#[cfg(not(target_os = "trusty"))]
11use crate::fs;
12use crate::marker::PhantomData;
13use crate::mem::ManuallyDrop;
14#[cfg(not(any(
15 all(target_arch = "wasm32", not(target_os = "emscripten")),
16 target_env = "sgx",
17 target_os = "hermit",
18 target_os = "trusty",
19 target_os = "motor"
20)))]
21use crate::sys::cvt;
22#[cfg(not(target_os = "trusty"))]
23use crate::sys::{AsInner, FromInner, IntoInner};
24use crate::{fmt, io};
25
26type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
27
28#[derive(Copy, Clone)]
48#[repr(transparent)]
49#[rustc_nonnull_optimization_guaranteed]
50#[stable(feature = "io_safety", since = "1.63.0")]
51pub struct BorrowedFd<'fd> {
52 fd: ValidRawFd,
53 _phantom: PhantomData<&'fd OwnedFd>,
54}
55
56#[repr(transparent)]
68#[rustc_nonnull_optimization_guaranteed]
69#[stable(feature = "io_safety", since = "1.63.0")]
70pub struct OwnedFd {
71 fd: ValidRawFd,
72}
73
74impl BorrowedFd<'_> {
75 #[inline]
86 #[track_caller]
87 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
88 #[stable(feature = "io_safety", since = "1.63.0")]
89 pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
90 Self { fd: ValidRawFd::new(fd).expect("fd != -1"), _phantom: PhantomData }
91 }
92}
93
94impl OwnedFd {
95 #[stable(feature = "io_safety", since = "1.63.0")]
98 pub fn try_clone(&self) -> io::Result<Self> {
99 self.as_fd().try_clone_to_owned()
100 }
101}
102
103impl BorrowedFd<'_> {
104 #[cfg(not(any(
107 all(target_arch = "wasm32", not(target_os = "emscripten")),
108 target_os = "hermit",
109 target_os = "trusty",
110 target_os = "motor"
111 )))]
112 #[stable(feature = "io_safety", since = "1.63.0")]
113 pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
114 #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
118 let cmd = libc::F_DUPFD_CLOEXEC;
119
120 #[cfg(any(target_os = "espidf", target_os = "vita"))]
125 let cmd = libc::F_DUPFD;
126
127 let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
129 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
130 }
131
132 #[cfg(any(
135 all(target_arch = "wasm32", not(target_os = "emscripten")),
136 target_os = "hermit",
137 target_os = "trusty"
138 ))]
139 #[stable(feature = "io_safety", since = "1.63.0")]
140 pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
141 Err(io::Error::UNSUPPORTED_PLATFORM)
142 }
143
144 #[cfg(target_os = "motor")]
147 #[stable(feature = "io_safety", since = "1.63.0")]
148 pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
149 let fd = moto_rt::fs::duplicate(self.as_raw_fd()).map_err(crate::sys::map_motor_error)?;
150 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
151 }
152}
153
154#[stable(feature = "io_safety", since = "1.63.0")]
155impl AsRawFd for BorrowedFd<'_> {
156 #[inline]
157 fn as_raw_fd(&self) -> RawFd {
158 self.fd.as_inner()
159 }
160}
161
162#[stable(feature = "io_safety", since = "1.63.0")]
163impl AsRawFd for OwnedFd {
164 #[inline]
165 fn as_raw_fd(&self) -> RawFd {
166 self.fd.as_inner()
167 }
168}
169
170#[stable(feature = "io_safety", since = "1.63.0")]
171impl IntoRawFd for OwnedFd {
172 #[inline]
173 fn into_raw_fd(self) -> RawFd {
174 ManuallyDrop::new(self).fd.as_inner()
175 }
176}
177
178#[stable(feature = "io_safety", since = "1.63.0")]
179impl FromRawFd for OwnedFd {
180 #[inline]
193 #[track_caller]
194 unsafe fn from_raw_fd(fd: RawFd) -> Self {
195 Self { fd: ValidRawFd::new(fd).expect("fd != -1") }
196 }
197}
198
199#[stable(feature = "io_safety", since = "1.63.0")]
200impl Drop for OwnedFd {
201 #[inline]
202 fn drop(&mut self) {
203 unsafe {
204 #[cfg(not(target_os = "hermit"))]
216 {
217 #[cfg(unix)]
218 crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
219
220 let _ = libc::close(self.fd.as_inner());
221 }
222 #[cfg(target_os = "hermit")]
223 let _ = hermit_abi::close(self.fd.as_inner());
224 }
225 }
226}
227
228#[stable(feature = "io_safety", since = "1.63.0")]
229impl fmt::Debug for BorrowedFd<'_> {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
232 }
233}
234
235#[stable(feature = "io_safety", since = "1.63.0")]
236impl fmt::Debug for OwnedFd {
237 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238 f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
239 }
240}
241
242macro_rules! impl_is_terminal {
243 ($($t:ty),*$(,)?) => {$(
244 #[stable(feature = "is_terminal", since = "1.70.0")]
245 impl io::IsTerminal for $t {
246 #[inline]
247 fn is_terminal(&self) -> bool {
248 crate::sys::io::is_terminal(self)
249 }
250 }
251 )*}
252}
253
254impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
255
256#[stable(feature = "io_safety", since = "1.63.0")]
262pub trait AsFd {
263 #[stable(feature = "io_safety", since = "1.63.0")]
279 fn as_fd(&self) -> BorrowedFd<'_>;
280}
281
282#[stable(feature = "io_safety", since = "1.63.0")]
283impl<T: AsFd + ?Sized> AsFd for &T {
284 #[inline]
285 fn as_fd(&self) -> BorrowedFd<'_> {
286 T::as_fd(self)
287 }
288}
289
290#[stable(feature = "io_safety", since = "1.63.0")]
291impl<T: AsFd + ?Sized> AsFd for &mut T {
292 #[inline]
293 fn as_fd(&self) -> BorrowedFd<'_> {
294 T::as_fd(self)
295 }
296}
297
298#[stable(feature = "io_safety", since = "1.63.0")]
299impl AsFd for BorrowedFd<'_> {
300 #[inline]
301 fn as_fd(&self) -> BorrowedFd<'_> {
302 *self
303 }
304}
305
306#[stable(feature = "io_safety", since = "1.63.0")]
307impl AsFd for OwnedFd {
308 #[inline]
309 fn as_fd(&self) -> BorrowedFd<'_> {
310 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
314 }
315}
316
317#[stable(feature = "io_safety", since = "1.63.0")]
318#[cfg(not(target_os = "trusty"))]
319impl AsFd for fs::File {
320 #[inline]
321 fn as_fd(&self) -> BorrowedFd<'_> {
322 self.as_inner().as_fd()
323 }
324}
325
326#[stable(feature = "io_safety", since = "1.63.0")]
327#[cfg(not(target_os = "trusty"))]
328impl From<fs::File> for OwnedFd {
329 #[inline]
331 fn from(file: fs::File) -> OwnedFd {
332 file.into_inner().into_inner().into_inner()
333 }
334}
335
336#[stable(feature = "io_safety", since = "1.63.0")]
337#[cfg(not(target_os = "trusty"))]
338impl From<OwnedFd> for fs::File {
339 #[inline]
342 fn from(owned_fd: OwnedFd) -> Self {
343 Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
344 }
345}
346
347#[stable(feature = "io_safety", since = "1.63.0")]
348#[cfg(not(target_os = "trusty"))]
349impl AsFd for crate::net::TcpStream {
350 #[inline]
351 fn as_fd(&self) -> BorrowedFd<'_> {
352 self.as_inner().socket().as_fd()
353 }
354}
355
356#[stable(feature = "io_safety", since = "1.63.0")]
357#[cfg(not(target_os = "trusty"))]
358impl From<crate::net::TcpStream> for OwnedFd {
359 #[inline]
361 fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
362 tcp_stream.into_inner().into_socket().into_inner().into_inner()
363 }
364}
365
366#[stable(feature = "io_safety", since = "1.63.0")]
367#[cfg(not(target_os = "trusty"))]
368impl From<OwnedFd> for crate::net::TcpStream {
369 #[inline]
370 fn from(owned_fd: OwnedFd) -> Self {
371 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
372 owned_fd,
373 ))))
374 }
375}
376
377#[stable(feature = "io_safety", since = "1.63.0")]
378#[cfg(not(target_os = "trusty"))]
379impl AsFd for crate::net::TcpListener {
380 #[inline]
381 fn as_fd(&self) -> BorrowedFd<'_> {
382 self.as_inner().socket().as_fd()
383 }
384}
385
386#[stable(feature = "io_safety", since = "1.63.0")]
387#[cfg(not(target_os = "trusty"))]
388impl From<crate::net::TcpListener> for OwnedFd {
389 #[inline]
391 fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
392 tcp_listener.into_inner().into_socket().into_inner().into_inner()
393 }
394}
395
396#[stable(feature = "io_safety", since = "1.63.0")]
397#[cfg(not(target_os = "trusty"))]
398impl From<OwnedFd> for crate::net::TcpListener {
399 #[inline]
400 fn from(owned_fd: OwnedFd) -> Self {
401 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
402 owned_fd,
403 ))))
404 }
405}
406
407#[stable(feature = "io_safety", since = "1.63.0")]
408#[cfg(not(target_os = "trusty"))]
409impl AsFd for crate::net::UdpSocket {
410 #[inline]
411 fn as_fd(&self) -> BorrowedFd<'_> {
412 self.as_inner().socket().as_fd()
413 }
414}
415
416#[stable(feature = "io_safety", since = "1.63.0")]
417#[cfg(not(target_os = "trusty"))]
418impl From<crate::net::UdpSocket> for OwnedFd {
419 #[inline]
421 fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
422 udp_socket.into_inner().into_socket().into_inner().into_inner()
423 }
424}
425
426#[stable(feature = "io_safety", since = "1.63.0")]
427#[cfg(not(target_os = "trusty"))]
428impl From<OwnedFd> for crate::net::UdpSocket {
429 #[inline]
430 fn from(owned_fd: OwnedFd) -> Self {
431 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
432 owned_fd,
433 ))))
434 }
435}
436
437#[stable(feature = "asfd_ptrs", since = "1.64.0")]
438impl<T: AsFd + ?Sized> AsFd for crate::sync::Arc<T> {
454 #[inline]
455 fn as_fd(&self) -> BorrowedFd<'_> {
456 (**self).as_fd()
457 }
458}
459
460#[stable(feature = "asfd_rc", since = "1.69.0")]
461impl<T: AsFd + ?Sized> AsFd for crate::rc::Rc<T> {
462 #[inline]
463 fn as_fd(&self) -> BorrowedFd<'_> {
464 (**self).as_fd()
465 }
466}
467
468#[unstable(feature = "unique_rc_arc", issue = "112566")]
469impl<T: AsFd + ?Sized> AsFd for crate::rc::UniqueRc<T> {
470 #[inline]
471 fn as_fd(&self) -> BorrowedFd<'_> {
472 (**self).as_fd()
473 }
474}
475
476#[stable(feature = "asfd_ptrs", since = "1.64.0")]
477impl<T: AsFd + ?Sized> AsFd for Box<T> {
478 #[inline]
479 fn as_fd(&self) -> BorrowedFd<'_> {
480 (**self).as_fd()
481 }
482}
483
484#[stable(feature = "io_safety", since = "1.63.0")]
485impl AsFd for io::Stdin {
486 #[inline]
487 fn as_fd(&self) -> BorrowedFd<'_> {
488 unsafe { BorrowedFd::borrow_raw(0) }
489 }
490}
491
492#[stable(feature = "io_safety", since = "1.63.0")]
493impl<'a> AsFd for io::StdinLock<'a> {
494 #[inline]
495 fn as_fd(&self) -> BorrowedFd<'_> {
496 unsafe { BorrowedFd::borrow_raw(0) }
498 }
499}
500
501#[stable(feature = "io_safety", since = "1.63.0")]
502impl AsFd for io::Stdout {
503 #[inline]
504 fn as_fd(&self) -> BorrowedFd<'_> {
505 unsafe { BorrowedFd::borrow_raw(1) }
506 }
507}
508
509#[stable(feature = "io_safety", since = "1.63.0")]
510impl<'a> AsFd for io::StdoutLock<'a> {
511 #[inline]
512 fn as_fd(&self) -> BorrowedFd<'_> {
513 unsafe { BorrowedFd::borrow_raw(1) }
515 }
516}
517
518#[stable(feature = "io_safety", since = "1.63.0")]
519impl AsFd for io::Stderr {
520 #[inline]
521 fn as_fd(&self) -> BorrowedFd<'_> {
522 unsafe { BorrowedFd::borrow_raw(2) }
523 }
524}
525
526#[stable(feature = "io_safety", since = "1.63.0")]
527impl<'a> AsFd for io::StderrLock<'a> {
528 #[inline]
529 fn as_fd(&self) -> BorrowedFd<'_> {
530 unsafe { BorrowedFd::borrow_raw(2) }
532 }
533}
534
535#[stable(feature = "anonymous_pipe", since = "1.87.0")]
536#[cfg(not(target_os = "trusty"))]
537impl AsFd for io::PipeReader {
538 fn as_fd(&self) -> BorrowedFd<'_> {
539 self.0.as_fd()
540 }
541}
542
543#[stable(feature = "anonymous_pipe", since = "1.87.0")]
544#[cfg(not(target_os = "trusty"))]
545impl From<io::PipeReader> for OwnedFd {
546 fn from(pipe: io::PipeReader) -> Self {
547 pipe.0.into_inner()
548 }
549}
550
551#[stable(feature = "anonymous_pipe", since = "1.87.0")]
552#[cfg(not(target_os = "trusty"))]
553impl AsFd for io::PipeWriter {
554 fn as_fd(&self) -> BorrowedFd<'_> {
555 self.0.as_fd()
556 }
557}
558
559#[stable(feature = "anonymous_pipe", since = "1.87.0")]
560#[cfg(not(target_os = "trusty"))]
561impl From<io::PipeWriter> for OwnedFd {
562 fn from(pipe: io::PipeWriter) -> Self {
563 pipe.0.into_inner()
564 }
565}
566
567#[stable(feature = "anonymous_pipe", since = "1.87.0")]
568#[cfg(not(target_os = "trusty"))]
569impl From<OwnedFd> for io::PipeReader {
570 fn from(owned_fd: OwnedFd) -> Self {
571 Self(FromInner::from_inner(owned_fd))
572 }
573}
574
575#[stable(feature = "anonymous_pipe", since = "1.87.0")]
576#[cfg(not(target_os = "trusty"))]
577impl From<OwnedFd> for io::PipeWriter {
578 fn from(owned_fd: OwnedFd) -> Self {
579 Self(FromInner::from_inner(owned_fd))
580 }
581}