Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 1dbd6d6

Browse files
committed
Factor out Unix and WASI fd code into a common module.
1 parent 71dab73 commit 1dbd6d6

File tree

4 files changed

+298
-560
lines changed

4 files changed

+298
-560
lines changed

library/std/src/os/fd.rs

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

library/std/src/os/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,6 @@ mod imp {
121121
#[cfg(not(doc))]
122122
#[stable(feature = "os", since = "1.0.0")]
123123
pub use imp::*;
124+
125+
#[cfg(any(unix, target_os = "wasi"))]
126+
mod fd;

0 commit comments

Comments
 (0)