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};
10use crate::alloc::Allocator;
11#[cfg(not(target_os = "trusty"))]
12use crate::fs;
13use crate::marker::PhantomData;
14use crate::mem::ManuallyDrop;
15#[cfg(not(any(
16 all(target_family = "wasm", not(target_os = "emscripten")),
17 target_env = "sgx",
18 target_os = "hermit",
19 target_os = "trusty",
20 target_os = "motor"
21)))]
22use crate::sys::cvt;
23#[cfg(not(target_os = "trusty"))]
24use crate::sys::{AsInner, FromInner, IntoInner};
25use crate::{fmt, io};
26
27type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
28
29#[derive(Copy, Clone)]
49#[repr(transparent)]
50#[rustc_nonnull_optimization_guaranteed]
51#[stable(feature = "io_safety", since = "1.63.0")]
52pub struct BorrowedFd<'fd> {
53 fd: ValidRawFd,
54 _phantom: PhantomData<&'fd OwnedFd>,
55}
56
57#[repr(transparent)]
69#[rustc_nonnull_optimization_guaranteed]
70#[stable(feature = "io_safety", since = "1.63.0")]
71pub struct OwnedFd {
72 fd: ValidRawFd,
73}
74
75impl BorrowedFd<'_> {
76 #[inline]
87 #[track_caller]
88 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
89 #[stable(feature = "io_safety", since = "1.63.0")]
90 pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
91 Self { fd: ValidRawFd::new(fd).expect("fd != -1"), _phantom: PhantomData }
92 }
93
94 #[cfg_attr(all(unix, not(miri)), doc = "```")]
97 #[cfg_attr(
98 any(not(unix), miri),
100 doc = "```ignore (needs unix; miri doesn't support metadata on stdio)"
101 )]
102 #[unstable(feature = "fd_view", issue = "160402")]
112 pub fn to_view<T>(&self) -> &T
113 where
114 Self: AsRef<T>,
115 {
116 self.as_ref()
117 }
118}
119
120impl OwnedFd {
121 #[stable(feature = "io_safety", since = "1.63.0")]
124 pub fn try_clone(&self) -> io::Result<Self> {
125 self.as_fd().try_clone_to_owned()
126 }
127}
128
129impl BorrowedFd<'_> {
130 #[cfg(not(any(
133 all(target_family = "wasm", not(target_os = "emscripten")),
134 target_os = "hermit",
135 target_os = "trusty",
136 target_os = "motor"
137 )))]
138 #[stable(feature = "io_safety", since = "1.63.0")]
139 pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
140 #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
144 let cmd = libc::F_DUPFD_CLOEXEC;
145
146 #[cfg(any(target_os = "espidf", target_os = "vita"))]
151 let cmd = libc::F_DUPFD;
152
153 let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
155 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
156 }
157
158 #[cfg(any(
161 all(target_family = "wasm", not(target_os = "emscripten")),
162 target_os = "hermit",
163 target_os = "trusty"
164 ))]
165 #[stable(feature = "io_safety", since = "1.63.0")]
166 pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
167 Err(io::Error::UNSUPPORTED_PLATFORM)
168 }
169
170 #[cfg(target_os = "motor")]
173 #[stable(feature = "io_safety", since = "1.63.0")]
174 pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
175 let fd = moto_rt::fs::duplicate(self.as_raw_fd()).map_err(crate::sys::map_motor_error)?;
176 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
177 }
178}
179
180#[stable(feature = "io_safety", since = "1.63.0")]
181impl AsRawFd for BorrowedFd<'_> {
182 #[inline]
183 fn as_raw_fd(&self) -> RawFd {
184 self.fd.as_inner()
185 }
186}
187
188#[stable(feature = "io_safety", since = "1.63.0")]
189impl AsRawFd for OwnedFd {
190 #[inline]
191 fn as_raw_fd(&self) -> RawFd {
192 self.fd.as_inner()
193 }
194}
195
196#[stable(feature = "io_safety", since = "1.63.0")]
197impl IntoRawFd for OwnedFd {
198 #[inline]
199 fn into_raw_fd(self) -> RawFd {
200 ManuallyDrop::new(self).fd.as_inner()
201 }
202}
203
204#[stable(feature = "io_safety", since = "1.63.0")]
205impl FromRawFd for OwnedFd {
206 #[inline]
219 #[track_caller]
220 unsafe fn from_raw_fd(fd: RawFd) -> Self {
221 Self { fd: ValidRawFd::new(fd).expect("fd != -1") }
222 }
223}
224
225#[stable(feature = "io_safety", since = "1.63.0")]
226impl Drop for OwnedFd {
227 #[inline]
228 fn drop(&mut self) {
229 unsafe {
230 #[cfg(not(target_os = "hermit"))]
242 {
243 #[cfg(unix)]
244 crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
245
246 let _ = libc::close(self.fd.as_inner());
247 }
248 #[cfg(target_os = "hermit")]
249 let _ = hermit_abi::close(self.fd.as_inner());
250 }
251 }
252}
253
254#[stable(feature = "io_safety", since = "1.63.0")]
255impl fmt::Debug for BorrowedFd<'_> {
256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
258 }
259}
260
261#[stable(feature = "io_safety", since = "1.63.0")]
262impl fmt::Debug for OwnedFd {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
265 }
266}
267
268macro_rules! impl_is_terminal {
269 ($($t:ty),*$(,)?) => {$(
270 #[stable(feature = "is_terminal", since = "1.70.0")]
271 impl io::IsTerminal for $t {
272 #[inline]
273 fn is_terminal(&self) -> bool {
274 crate::sys::io::is_terminal(self)
275 }
276 }
277 )*}
278}
279
280impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
281
282#[stable(feature = "io_safety", since = "1.63.0")]
288pub trait AsFd {
289 #[stable(feature = "io_safety", since = "1.63.0")]
305 fn as_fd(&self) -> BorrowedFd<'_>;
306}
307
308#[stable(feature = "io_safety", since = "1.63.0")]
309impl<T: AsFd + ?Sized> AsFd for &T {
310 #[inline]
311 fn as_fd(&self) -> BorrowedFd<'_> {
312 T::as_fd(self)
313 }
314}
315
316#[stable(feature = "io_safety", since = "1.63.0")]
317impl<T: AsFd + ?Sized> AsFd for &mut T {
318 #[inline]
319 fn as_fd(&self) -> BorrowedFd<'_> {
320 T::as_fd(self)
321 }
322}
323
324#[stable(feature = "io_safety", since = "1.63.0")]
325impl AsFd for BorrowedFd<'_> {
326 #[inline]
327 fn as_fd(&self) -> BorrowedFd<'_> {
328 *self
329 }
330}
331
332#[stable(feature = "io_safety", since = "1.63.0")]
333impl AsFd for OwnedFd {
334 #[inline]
335 fn as_fd(&self) -> BorrowedFd<'_> {
336 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
340 }
341}
342
343#[stable(feature = "io_safety", since = "1.63.0")]
344#[cfg(not(target_os = "trusty"))]
345impl AsFd for fs::File {
346 #[inline]
347 fn as_fd(&self) -> BorrowedFd<'_> {
348 self.as_inner().as_fd()
349 }
350}
351
352#[stable(feature = "io_safety", since = "1.63.0")]
353#[cfg(not(target_os = "trusty"))]
354impl From<fs::File> for OwnedFd {
355 #[inline]
357 fn from(file: fs::File) -> OwnedFd {
358 file.into_inner().into_inner().into_inner()
359 }
360}
361
362#[stable(feature = "io_safety", since = "1.63.0")]
363#[cfg(not(target_os = "trusty"))]
364impl From<OwnedFd> for fs::File {
365 #[inline]
368 fn from(owned_fd: OwnedFd) -> Self {
369 Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
370 }
371}
372
373#[stable(feature = "io_safety", since = "1.63.0")]
374#[cfg(not(target_os = "trusty"))]
375impl AsFd for crate::net::TcpStream {
376 #[inline]
377 fn as_fd(&self) -> BorrowedFd<'_> {
378 self.as_inner().socket().as_fd()
379 }
380}
381
382#[stable(feature = "io_safety", since = "1.63.0")]
383#[cfg(not(target_os = "trusty"))]
384impl From<crate::net::TcpStream> for OwnedFd {
385 #[inline]
387 fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
388 tcp_stream.into_inner().into_socket().into_inner().into_inner()
389 }
390}
391
392#[stable(feature = "io_safety", since = "1.63.0")]
393#[cfg(not(target_os = "trusty"))]
394impl From<OwnedFd> for crate::net::TcpStream {
395 #[inline]
396 fn from(owned_fd: OwnedFd) -> Self {
397 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
398 owned_fd,
399 ))))
400 }
401}
402
403#[stable(feature = "io_safety", since = "1.63.0")]
404#[cfg(not(target_os = "trusty"))]
405impl AsFd for crate::net::TcpListener {
406 #[inline]
407 fn as_fd(&self) -> BorrowedFd<'_> {
408 self.as_inner().socket().as_fd()
409 }
410}
411
412#[stable(feature = "io_safety", since = "1.63.0")]
413#[cfg(not(target_os = "trusty"))]
414impl From<crate::net::TcpListener> for OwnedFd {
415 #[inline]
417 fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
418 tcp_listener.into_inner().into_socket().into_inner().into_inner()
419 }
420}
421
422#[stable(feature = "io_safety", since = "1.63.0")]
423#[cfg(not(target_os = "trusty"))]
424impl From<OwnedFd> for crate::net::TcpListener {
425 #[inline]
426 fn from(owned_fd: OwnedFd) -> Self {
427 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
428 owned_fd,
429 ))))
430 }
431}
432
433#[stable(feature = "io_safety", since = "1.63.0")]
434#[cfg(not(target_os = "trusty"))]
435impl AsFd for crate::net::UdpSocket {
436 #[inline]
437 fn as_fd(&self) -> BorrowedFd<'_> {
438 self.as_inner().socket().as_fd()
439 }
440}
441
442#[stable(feature = "io_safety", since = "1.63.0")]
443#[cfg(not(target_os = "trusty"))]
444impl From<crate::net::UdpSocket> for OwnedFd {
445 #[inline]
447 fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
448 udp_socket.into_inner().into_socket().into_inner().into_inner()
449 }
450}
451
452#[stable(feature = "io_safety", since = "1.63.0")]
453#[cfg(not(target_os = "trusty"))]
454impl From<OwnedFd> for crate::net::UdpSocket {
455 #[inline]
456 fn from(owned_fd: OwnedFd) -> Self {
457 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
458 owned_fd,
459 ))))
460 }
461}
462
463pub(crate) macro unsafe_impl_fd_asrefs {
479 ($($t:ty),*$(,)?) => {$(
480 #[unstable(feature = "fd_view", issue = "160402")]
481 #[unstable_feature_bound(fd_view)]
482 impl AsRef<$t> for BorrowedFd<'_> {
483 #[inline]
484 fn as_ref(&self) -> &$t {
485 use core::mem;
486
487 fn type_check<T: From<OwnedFd> + Into<OwnedFd> + AsFd>() {}
490
491 const {
493 assert!(mem::size_of::<RawFd>() == mem::size_of::<$t>());
494 assert!(mem::size_of::<RawFd>() == mem::size_of::<BorrowedFd<'_>>());
495 }
496 type_check::<$t>();
497 unsafe { mem::transmute::<&BorrowedFd<'_>, &$t>(self) }
499 }
500 }
501 )*}
502}
503
504#[cfg(not(target_os = "trusty"))]
505unsafe_impl_fd_asrefs!(
506 crate::fs::File,
507 crate::net::TcpStream,
508 crate::net::TcpListener,
509 crate::net::UdpSocket,
510);
511
512#[cfg(unix)]
513unsafe_impl_fd_asrefs!(io::PipeWriter, io::PipeReader);
514
515#[stable(feature = "asfd_ptrs", since = "1.64.0")]
516impl<T: AsFd + ?Sized> AsFd for crate::sync::Arc<T> {
532 #[inline]
533 fn as_fd(&self) -> BorrowedFd<'_> {
534 (**self).as_fd()
535 }
536}
537
538#[stable(feature = "asfd_rc", since = "1.69.0")]
539impl<T: AsFd + ?Sized> AsFd for crate::rc::Rc<T> {
540 #[inline]
541 fn as_fd(&self) -> BorrowedFd<'_> {
542 (**self).as_fd()
543 }
544}
545
546#[unstable(feature = "unique_rc_arc", issue = "112566")]
547impl<T: AsFd + ?Sized> AsFd for crate::rc::UniqueRc<T> {
548 #[inline]
549 fn as_fd(&self) -> BorrowedFd<'_> {
550 (**self).as_fd()
551 }
552}
553
554#[stable(feature = "asfd_ptrs", since = "1.64.0")]
555impl<T: AsFd + ?Sized, A: Allocator> AsFd for Box<T, A> {
556 #[inline]
557 fn as_fd(&self) -> BorrowedFd<'_> {
558 (**self).as_fd()
559 }
560}
561
562#[stable(feature = "io_safety", since = "1.63.0")]
563impl AsFd for io::Stdin {
564 #[inline]
565 fn as_fd(&self) -> BorrowedFd<'_> {
566 unsafe { BorrowedFd::borrow_raw(0) }
567 }
568}
569
570#[stable(feature = "io_safety", since = "1.63.0")]
571impl<'a> AsFd for io::StdinLock<'a> {
572 #[inline]
573 fn as_fd(&self) -> BorrowedFd<'_> {
574 unsafe { BorrowedFd::borrow_raw(0) }
576 }
577}
578
579#[stable(feature = "io_safety", since = "1.63.0")]
580impl AsFd for io::Stdout {
581 #[inline]
582 fn as_fd(&self) -> BorrowedFd<'_> {
583 unsafe { BorrowedFd::borrow_raw(1) }
584 }
585}
586
587#[stable(feature = "io_safety", since = "1.63.0")]
588impl<'a> AsFd for io::StdoutLock<'a> {
589 #[inline]
590 fn as_fd(&self) -> BorrowedFd<'_> {
591 unsafe { BorrowedFd::borrow_raw(1) }
593 }
594}
595
596#[stable(feature = "io_safety", since = "1.63.0")]
597impl AsFd for io::Stderr {
598 #[inline]
599 fn as_fd(&self) -> BorrowedFd<'_> {
600 unsafe { BorrowedFd::borrow_raw(2) }
601 }
602}
603
604#[stable(feature = "io_safety", since = "1.63.0")]
605impl<'a> AsFd for io::StderrLock<'a> {
606 #[inline]
607 fn as_fd(&self) -> BorrowedFd<'_> {
608 unsafe { BorrowedFd::borrow_raw(2) }
610 }
611}
612
613#[stable(feature = "anonymous_pipe", since = "1.87.0")]
614#[cfg(not(target_os = "trusty"))]
615impl AsFd for io::PipeReader {
616 fn as_fd(&self) -> BorrowedFd<'_> {
617 self.0.as_fd()
618 }
619}
620
621#[stable(feature = "anonymous_pipe", since = "1.87.0")]
622#[cfg(not(target_os = "trusty"))]
623impl From<io::PipeReader> for OwnedFd {
624 fn from(pipe: io::PipeReader) -> Self {
625 pipe.0.into_inner()
626 }
627}
628
629#[stable(feature = "anonymous_pipe", since = "1.87.0")]
630#[cfg(not(target_os = "trusty"))]
631impl AsFd for io::PipeWriter {
632 fn as_fd(&self) -> BorrowedFd<'_> {
633 self.0.as_fd()
634 }
635}
636
637#[stable(feature = "anonymous_pipe", since = "1.87.0")]
638#[cfg(not(target_os = "trusty"))]
639impl From<io::PipeWriter> for OwnedFd {
640 fn from(pipe: io::PipeWriter) -> Self {
641 pipe.0.into_inner()
642 }
643}
644
645#[stable(feature = "anonymous_pipe", since = "1.87.0")]
646#[cfg(not(target_os = "trusty"))]
647impl From<OwnedFd> for io::PipeReader {
648 fn from(owned_fd: OwnedFd) -> Self {
649 Self(FromInner::from_inner(owned_fd))
650 }
651}
652
653#[stable(feature = "anonymous_pipe", since = "1.87.0")]
654#[cfg(not(target_os = "trusty"))]
655impl From<OwnedFd> for io::PipeWriter {
656 fn from(owned_fd: OwnedFd) -> Self {
657 Self(FromInner::from_inner(owned_fd))
658 }
659}