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