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