-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce `OwnedFd` and `BorrowedFd`, and the `AsFd` trait, and implementations of `AsFd`, `From<OwnedFd>` and `From<T> for OwnedFd` for relevant types, along with Windows counterparts for handles and sockets. Tracking issue: - <#87074> RFC: - <https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md>
- Loading branch information
1 parent
2451f42
commit d154185
Showing
43 changed files
with
2,360 additions
and
556 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,329 @@ | ||
//! Owned and borrowed file descriptors. | ||
|
||
#![unstable(feature = "io_safety", issue = "87074")] | ||
|
||
use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; | ||
use crate::fmt; | ||
use crate::fs; | ||
use crate::marker::PhantomData; | ||
use crate::mem::forget; | ||
use crate::os::raw; | ||
use crate::sys_common::{AsInner, FromInner, IntoInner}; | ||
|
||
/// A borrowed file descriptor. | ||
/// | ||
/// This has a lifetime parameter to tie it to the lifetime of something that | ||
/// owns the file descriptor. | ||
/// | ||
/// This uses `repr(transparent)` and has the representation of a host file | ||
/// descriptor, so it can be used in FFI in places where a file descriptor is | ||
/// passed as an argument, it is not captured or consumed, and it never has the | ||
/// value `-1`. | ||
#[derive(Copy, Clone)] | ||
#[repr(transparent)] | ||
#[rustc_layout_scalar_valid_range_start(0)] | ||
// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a | ||
// 32-bit c_int. Below is -2, in two's complement, but that only works out | ||
// because c_int is 32 bits. | ||
#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] | ||
#[unstable(feature = "io_safety", issue = "87074")] | ||
pub struct BorrowedFd<'fd> { | ||
raw: RawFd, | ||
_phantom: PhantomData<&'fd OwnedFd>, | ||
} | ||
|
||
/// An owned file descriptor. | ||
/// | ||
/// This closes the file descriptor on drop. | ||
/// | ||
/// This uses `repr(transparent)` and has the representation of a host file | ||
/// descriptor, so it can be used in FFI in places where a file descriptor is | ||
/// passed as a consumed argument or returned as an owned value, and it never | ||
/// has the value `-1`. | ||
#[repr(transparent)] | ||
#[rustc_layout_scalar_valid_range_start(0)] | ||
// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a | ||
// 32-bit c_int. Below is -2, in two's complement, but that only works out | ||
// because c_int is 32 bits. | ||
#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] | ||
#[unstable(feature = "io_safety", issue = "87074")] | ||
pub struct OwnedFd { | ||
raw: RawFd, | ||
} | ||
|
||
impl BorrowedFd<'_> { | ||
/// Return a `BorrowedFd` holding the given raw file descriptor. | ||
/// | ||
/// # Safety | ||
/// | ||
/// The resource pointed to by `raw` must remain open for the duration of | ||
/// the returned `BorrowedFd`, and it must not have the value `-1`. | ||
#[inline] | ||
#[unstable(feature = "io_safety", issue = "87074")] | ||
pub unsafe fn borrow_raw_fd(raw: RawFd) -> Self { | ||
assert_ne!(raw, -1_i32 as RawFd); | ||
Self { raw, _phantom: PhantomData } | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsRawFd for BorrowedFd<'_> { | ||
#[inline] | ||
fn as_raw_fd(&self) -> RawFd { | ||
self.raw | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsRawFd for OwnedFd { | ||
#[inline] | ||
fn as_raw_fd(&self) -> RawFd { | ||
self.raw | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl IntoRawFd for OwnedFd { | ||
#[inline] | ||
fn into_raw_fd(self) -> RawFd { | ||
let raw = self.raw; | ||
forget(self); | ||
raw | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl FromRawFd for OwnedFd { | ||
/// Constructs a new instance of `Self` from the given raw file descriptor. | ||
/// | ||
/// # Safety | ||
/// | ||
/// The resource pointed to by `raw` must be open and suitable for assuming | ||
/// ownership. | ||
#[inline] | ||
unsafe fn from_raw_fd(raw: RawFd) -> Self { | ||
assert_ne!(raw, -1i32); | ||
// 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) | ||
Self { raw } | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl Drop for OwnedFd { | ||
#[inline] | ||
fn drop(&mut self) { | ||
unsafe { | ||
// Note that errors are ignored when closing a file descriptor. The | ||
// reason for this is that if an error occurs we don't actually know if | ||
// the file descriptor was closed or not, and if we retried (for | ||
// something like EINTR), we might close another valid file descriptor | ||
// opened after we closed ours. | ||
let _ = libc::close(self.raw as raw::c_int); | ||
} | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl fmt::Debug for BorrowedFd<'_> { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_struct("BorrowedFd").field("fd", &self.raw).finish() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl fmt::Debug for OwnedFd { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_struct("OwnedFd").field("fd", &self.raw).finish() | ||
} | ||
} | ||
|
||
/// A trait to borrow the file descriptor from an underlying object. | ||
/// | ||
/// This is only available on unix platforms and must be imported in order to | ||
/// call the method. Windows platforms have a corresponding `AsHandle` and | ||
/// `AsSocket` set of traits. | ||
#[unstable(feature = "io_safety", issue = "87074")] | ||
pub trait AsFd { | ||
/// Borrows the file descriptor. | ||
/// | ||
/// # Example | ||
/// | ||
/// ```rust,no_run | ||
/// #![feature(io_safety)] | ||
/// use std::fs::File; | ||
/// # use std::io; | ||
/// use std::os::unix::io::{AsFd, BorrowedFd}; | ||
/// | ||
/// let mut f = File::open("foo.txt")?; | ||
/// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); | ||
/// # Ok::<(), io::Error>(()) | ||
/// ``` | ||
#[unstable(feature = "io_safety", issue = "87074")] | ||
fn as_fd(&self) -> BorrowedFd<'_>; | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsFd for BorrowedFd<'_> { | ||
#[inline] | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
*self | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsFd for OwnedFd { | ||
#[inline] | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsFd for fs::File { | ||
#[inline] | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
self.as_inner().as_fd() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<fs::File> for OwnedFd { | ||
#[inline] | ||
fn from(file: fs::File) -> OwnedFd { | ||
file.into_inner().into_inner().into_inner() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<OwnedFd> for fs::File { | ||
#[inline] | ||
fn from(owned_fd: OwnedFd) -> Self { | ||
Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsFd for crate::net::TcpStream { | ||
#[inline] | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
self.as_inner().socket().as_fd() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<crate::net::TcpStream> for OwnedFd { | ||
#[inline] | ||
fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { | ||
tcp_stream.into_inner().into_socket().into_inner().into_inner().into() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<OwnedFd> for crate::net::TcpStream { | ||
#[inline] | ||
fn from(owned_fd: OwnedFd) -> Self { | ||
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( | ||
owned_fd, | ||
)))) | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsFd for crate::net::TcpListener { | ||
#[inline] | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
self.as_inner().socket().as_fd() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<crate::net::TcpListener> for OwnedFd { | ||
#[inline] | ||
fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { | ||
tcp_listener.into_inner().into_socket().into_inner().into_inner().into() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<OwnedFd> for crate::net::TcpListener { | ||
#[inline] | ||
fn from(owned_fd: OwnedFd) -> Self { | ||
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( | ||
owned_fd, | ||
)))) | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsFd for crate::net::UdpSocket { | ||
#[inline] | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
self.as_inner().socket().as_fd() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<crate::net::UdpSocket> for OwnedFd { | ||
#[inline] | ||
fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { | ||
udp_socket.into_inner().into_socket().into_inner().into_inner().into() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<OwnedFd> for crate::net::UdpSocket { | ||
#[inline] | ||
fn from(owned_fd: OwnedFd) -> Self { | ||
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( | ||
owned_fd, | ||
)))) | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsFd for crate::process::ChildStdin { | ||
#[inline] | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
self.as_inner().as_fd() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<crate::process::ChildStdin> for OwnedFd { | ||
#[inline] | ||
fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd { | ||
child_stdin.into_inner().into_inner().into_inner() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsFd for crate::process::ChildStdout { | ||
#[inline] | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
self.as_inner().as_fd() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<crate::process::ChildStdout> for OwnedFd { | ||
#[inline] | ||
fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd { | ||
child_stdout.into_inner().into_inner().into_inner() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl AsFd for crate::process::ChildStderr { | ||
#[inline] | ||
fn as_fd(&self) -> BorrowedFd<'_> { | ||
self.as_inner().as_fd() | ||
} | ||
} | ||
|
||
#[unstable(feature = "io_safety", issue = "87074")] | ||
impl From<crate::process::ChildStderr> for OwnedFd { | ||
#[inline] | ||
fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd { | ||
child_stderr.into_inner().into_inner().into_inner() | ||
} | ||
} |
Oops, something went wrong.