1 //! Owned and borrowed Unix-like file descriptors. 2 3 #![unstable(feature = "io_safety", issue = "87074")] 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::marker::PhantomData; 10 use crate::mem::forget; 11 use crate::sys_common::{AsInner, FromInner, IntoInner}; 12 13 /// A borrowed file descriptor. 14 /// 15 /// This has a lifetime parameter to tie it to the lifetime of something that 16 /// owns the file descriptor. 17 /// 18 /// This uses `repr(transparent)` and has the representation of a host file 19 /// descriptor, so it can be used in FFI in places where a file descriptor is 20 /// passed as an argument, it is not captured or consumed, and it never has the 21 /// value `-1`. 22 #[derive(Copy, Clone)] 23 #[repr(transparent)] 24 #[rustc_layout_scalar_valid_range_start(0)] 25 // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a 26 // 32-bit c_int. Below is -2, in two's complement, but that only works out 27 // because c_int is 32 bits. 28 #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] 29 #[unstable(feature = "io_safety", issue = "87074")] 30 pub struct BorrowedFd<'fd> { 31 fd: RawFd, 32 _phantom: PhantomData<&'fd OwnedFd>, 33 } 34 35 /// An owned file descriptor. 36 /// 37 /// This closes the file descriptor on drop. 38 /// 39 /// This uses `repr(transparent)` and has the representation of a host file 40 /// descriptor, so it can be used in FFI in places where a file descriptor is 41 /// passed as a consumed argument or returned as an owned value, and it never 42 /// has the value `-1`. 43 #[repr(transparent)] 44 #[rustc_layout_scalar_valid_range_start(0)] 45 // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a 46 // 32-bit c_int. Below is -2, in two's complement, but that only works out 47 // because c_int is 32 bits. 48 #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] 49 #[unstable(feature = "io_safety", issue = "87074")] 50 pub struct OwnedFd { 51 fd: RawFd, 52 } 53 54 impl BorrowedFd<'_> { 55 /// Return a `BorrowedFd` holding the given raw file descriptor. 56 /// 57 /// # Safety 58 /// 59 /// The resource pointed to by `fd` must remain open for the duration of 60 /// the returned `BorrowedFd`, and it must not have the value `-1`. 61 #[inline] 62 #[unstable(feature = "io_safety", issue = "87074")] borrow_raw_fd(fd: RawFd) -> Self63 pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { 64 assert_ne!(fd, u32::MAX as RawFd); 65 // 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) 66 unsafe { Self { fd, _phantom: PhantomData } } 67 } 68 } 69 70 #[unstable(feature = "io_safety", issue = "87074")] 71 impl AsRawFd for BorrowedFd<'_> { 72 #[inline] as_raw_fd(&self) -> RawFd73 fn as_raw_fd(&self) -> RawFd { 74 self.fd 75 } 76 } 77 78 #[unstable(feature = "io_safety", issue = "87074")] 79 impl AsRawFd for OwnedFd { 80 #[inline] as_raw_fd(&self) -> RawFd81 fn as_raw_fd(&self) -> RawFd { 82 self.fd 83 } 84 } 85 86 #[unstable(feature = "io_safety", issue = "87074")] 87 impl IntoRawFd for OwnedFd { 88 #[inline] into_raw_fd(self) -> RawFd89 fn into_raw_fd(self) -> RawFd { 90 let fd = self.fd; 91 forget(self); 92 fd 93 } 94 } 95 96 #[unstable(feature = "io_safety", issue = "87074")] 97 impl FromRawFd for OwnedFd { 98 /// Constructs a new instance of `Self` from the given raw file descriptor. 99 /// 100 /// # Safety 101 /// 102 /// The resource pointed to by `fd` must be open and suitable for assuming 103 /// ownership. The resource must not require any cleanup other than `close`. 104 #[inline] from_raw_fd(fd: RawFd) -> Self105 unsafe fn from_raw_fd(fd: RawFd) -> Self { 106 assert_ne!(fd, u32::MAX as RawFd); 107 // 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) 108 unsafe { Self { fd } } 109 } 110 } 111 112 #[unstable(feature = "io_safety", issue = "87074")] 113 impl Drop for OwnedFd { 114 #[inline] drop(&mut self)115 fn drop(&mut self) { 116 unsafe { 117 // Note that errors are ignored when closing a file descriptor. The 118 // reason for this is that if an error occurs we don't actually know if 119 // the file descriptor was closed or not, and if we retried (for 120 // something like EINTR), we might close another valid file descriptor 121 // opened after we closed ours. 122 let _ = libc::close(self.fd); 123 } 124 } 125 } 126 127 #[unstable(feature = "io_safety", issue = "87074")] 128 impl fmt::Debug for BorrowedFd<'_> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 130 f.debug_struct("BorrowedFd").field("fd", &self.fd).finish() 131 } 132 } 133 134 #[unstable(feature = "io_safety", issue = "87074")] 135 impl fmt::Debug for OwnedFd { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 137 f.debug_struct("OwnedFd").field("fd", &self.fd).finish() 138 } 139 } 140 141 /// A trait to borrow the file descriptor from an underlying object. 142 /// 143 /// This is only available on unix platforms and must be imported in order to 144 /// call the method. Windows platforms have a corresponding `AsHandle` and 145 /// `AsSocket` set of traits. 146 #[unstable(feature = "io_safety", issue = "87074")] 147 pub trait AsFd { 148 /// Borrows the file descriptor. 149 /// 150 /// # Example 151 /// 152 /// ```rust,no_run 153 /// # #![feature(io_safety)] 154 /// use std::fs::File; 155 /// # use std::io; 156 /// # #[cfg(target_os = "wasi")] 157 /// # use std::os::wasi::io::{AsFd, BorrowedFd}; 158 /// # #[cfg(unix)] 159 /// # use std::os::unix::io::{AsFd, BorrowedFd}; 160 /// 161 /// let mut f = File::open("foo.txt")?; 162 /// # #[cfg(any(unix, target_os = "wasi"))] 163 /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); 164 /// # Ok::<(), io::Error>(()) 165 /// ``` 166 #[unstable(feature = "io_safety", issue = "87074")] as_fd(&self) -> BorrowedFd<'_>167 fn as_fd(&self) -> BorrowedFd<'_>; 168 } 169 170 #[unstable(feature = "io_safety", issue = "87074")] 171 impl AsFd for BorrowedFd<'_> { 172 #[inline] as_fd(&self) -> BorrowedFd<'_>173 fn as_fd(&self) -> BorrowedFd<'_> { 174 *self 175 } 176 } 177 178 #[unstable(feature = "io_safety", issue = "87074")] 179 impl AsFd for OwnedFd { 180 #[inline] as_fd(&self) -> BorrowedFd<'_>181 fn as_fd(&self) -> BorrowedFd<'_> { 182 // Safety: `OwnedFd` and `BorrowedFd` have the same validity 183 // invariants, and the `BorrowdFd` is bounded by the lifetime 184 // of `&self`. 185 unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } 186 } 187 } 188 189 #[unstable(feature = "io_safety", issue = "87074")] 190 impl AsFd for fs::File { 191 #[inline] as_fd(&self) -> BorrowedFd<'_>192 fn as_fd(&self) -> BorrowedFd<'_> { 193 self.as_inner().as_fd() 194 } 195 } 196 197 #[unstable(feature = "io_safety", issue = "87074")] 198 impl From<fs::File> for OwnedFd { 199 #[inline] from(file: fs::File) -> OwnedFd200 fn from(file: fs::File) -> OwnedFd { 201 file.into_inner().into_inner().into_inner() 202 } 203 } 204 205 #[unstable(feature = "io_safety", issue = "87074")] 206 impl From<OwnedFd> for fs::File { 207 #[inline] from(owned_fd: OwnedFd) -> Self208 fn from(owned_fd: OwnedFd) -> Self { 209 Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) 210 } 211 } 212 213 #[unstable(feature = "io_safety", issue = "87074")] 214 impl AsFd for crate::net::TcpStream { 215 #[inline] as_fd(&self) -> BorrowedFd<'_>216 fn as_fd(&self) -> BorrowedFd<'_> { 217 self.as_inner().socket().as_fd() 218 } 219 } 220 221 #[unstable(feature = "io_safety", issue = "87074")] 222 impl From<crate::net::TcpStream> for OwnedFd { 223 #[inline] from(tcp_stream: crate::net::TcpStream) -> OwnedFd224 fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { 225 tcp_stream.into_inner().into_socket().into_inner().into_inner().into() 226 } 227 } 228 229 #[unstable(feature = "io_safety", issue = "87074")] 230 impl From<OwnedFd> for crate::net::TcpStream { 231 #[inline] from(owned_fd: OwnedFd) -> Self232 fn from(owned_fd: OwnedFd) -> Self { 233 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( 234 owned_fd, 235 )))) 236 } 237 } 238 239 #[unstable(feature = "io_safety", issue = "87074")] 240 impl AsFd for crate::net::TcpListener { 241 #[inline] as_fd(&self) -> BorrowedFd<'_>242 fn as_fd(&self) -> BorrowedFd<'_> { 243 self.as_inner().socket().as_fd() 244 } 245 } 246 247 #[unstable(feature = "io_safety", issue = "87074")] 248 impl From<crate::net::TcpListener> for OwnedFd { 249 #[inline] from(tcp_listener: crate::net::TcpListener) -> OwnedFd250 fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { 251 tcp_listener.into_inner().into_socket().into_inner().into_inner().into() 252 } 253 } 254 255 #[unstable(feature = "io_safety", issue = "87074")] 256 impl From<OwnedFd> for crate::net::TcpListener { 257 #[inline] from(owned_fd: OwnedFd) -> Self258 fn from(owned_fd: OwnedFd) -> Self { 259 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( 260 owned_fd, 261 )))) 262 } 263 } 264 265 #[unstable(feature = "io_safety", issue = "87074")] 266 impl AsFd for crate::net::UdpSocket { 267 #[inline] as_fd(&self) -> BorrowedFd<'_>268 fn as_fd(&self) -> BorrowedFd<'_> { 269 self.as_inner().socket().as_fd() 270 } 271 } 272 273 #[unstable(feature = "io_safety", issue = "87074")] 274 impl From<crate::net::UdpSocket> for OwnedFd { 275 #[inline] from(udp_socket: crate::net::UdpSocket) -> OwnedFd276 fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { 277 udp_socket.into_inner().into_socket().into_inner().into_inner().into() 278 } 279 } 280 281 #[unstable(feature = "io_safety", issue = "87074")] 282 impl From<OwnedFd> for crate::net::UdpSocket { 283 #[inline] from(owned_fd: OwnedFd) -> Self284 fn from(owned_fd: OwnedFd) -> Self { 285 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( 286 owned_fd, 287 )))) 288 } 289 } 290