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