From d15418586ca78ead4f87ad18fcffa3550c1b169e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 30 Jun 2021 21:44:30 -0700 Subject: [PATCH] I/O safety. Introduce `OwnedFd` and `BorrowedFd`, and the `AsFd` trait, and implementations of `AsFd`, `From` and `From for OwnedFd` for relevant types, along with Windows counterparts for handles and sockets. Tracking issue: - RFC: - --- library/std/src/lib.rs | 1 + library/std/src/net/udp/tests.rs | 3 +- library/std/src/os/unix/io/fd.rs | 329 +++++++++++++++ library/std/src/os/unix/io/mod.rs | 56 +++ library/std/src/os/unix/{io.rs => io/raw.rs} | 10 +- library/std/src/os/unix/net/datagram.rs | 44 +- library/std/src/os/unix/net/listener.rs | 14 +- library/std/src/os/unix/net/raw_fd.rs | 8 +- library/std/src/os/unix/net/stream.rs | 40 +- library/std/src/os/unix/process.rs | 14 +- library/std/src/os/wasi/fs.rs | 30 +- library/std/src/os/wasi/io/fd.rs | 280 +++++++++++++ library/std/src/os/wasi/io/mod.rs | 12 + library/std/src/os/wasi/{io.rs => io/raw.rs} | 124 +++--- library/std/src/os/wasi/mod.rs | 1 + library/std/src/os/wasi/net/mod.rs | 8 + library/std/src/os/wasi/net/raw_fd.rs | 45 ++ library/std/src/os/windows/io/handle.rs | 390 ++++++++++++++++++ library/std/src/os/windows/io/mod.rs | 56 +++ .../std/src/os/windows/{io.rs => io/raw.rs} | 27 +- library/std/src/os/windows/io/socket.rs | 212 ++++++++++ library/std/src/os/windows/process.rs | 18 +- library/std/src/os/windows/thread.rs | 4 +- library/std/src/sys/unix/fd.rs | 115 +++--- library/std/src/sys/unix/fd/tests.rs | 3 +- library/std/src/sys/unix/fs.rs | 77 +++- library/std/src/sys/unix/net.rs | 92 +++-- library/std/src/sys/unix/pipe.rs | 63 ++- .../src/sys/unix/process/process_common.rs | 15 +- library/std/src/sys/unix/stdio.rs | 65 ++- library/std/src/sys/wasi/fd.rs | 138 ++++--- library/std/src/sys/wasi/fs.rs | 49 ++- library/std/src/sys/wasi/net.rs | 125 ++++-- library/std/src/sys/wasi/stdio.rs | 19 +- library/std/src/sys/windows/fs.rs | 73 +++- library/std/src/sys/windows/handle.rs | 122 +++--- library/std/src/sys/windows/net.rs | 106 +++-- library/std/src/sys/windows/os.rs | 2 +- library/std/src/sys/windows/pipe.rs | 17 +- library/std/src/sys/windows/process.rs | 41 +- library/std/src/sys/windows/stdio.rs | 21 +- library/std/src/sys/windows/thread.rs | 5 +- library/std/src/sys_common/net.rs | 42 +- 43 files changed, 2360 insertions(+), 556 deletions(-) create mode 100644 library/std/src/os/unix/io/fd.rs create mode 100644 library/std/src/os/unix/io/mod.rs rename library/std/src/os/unix/{io.rs => io/raw.rs} (96%) create mode 100644 library/std/src/os/wasi/io/fd.rs create mode 100644 library/std/src/os/wasi/io/mod.rs rename library/std/src/os/wasi/{io.rs => io/raw.rs} (65%) create mode 100644 library/std/src/os/wasi/net/mod.rs create mode 100644 library/std/src/os/wasi/net/raw_fd.rs create mode 100644 library/std/src/os/windows/io/handle.rs create mode 100644 library/std/src/os/windows/io/mod.rs rename library/std/src/os/windows/{io.rs => io/raw.rs} (88%) create mode 100644 library/std/src/os/windows/io/socket.rs diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5e91a0cdbd6b5..befb40cd2ed90 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -285,6 +285,7 @@ #![feature(int_log)] #![feature(into_future)] #![feature(intra_doc_pointers)] +#![feature(io_safety)] #![feature(iter_zip)] #![feature(lang_items)] #![feature(linkage)] diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index fbed3d32d451a..a51113dd9e749 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -2,7 +2,6 @@ use crate::io::ErrorKind; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::net::*; use crate::sync::mpsc::channel; -use crate::sys_common::AsInner; use crate::thread; use crate::time::{Duration, Instant}; @@ -173,7 +172,7 @@ fn debug() { let socket_addr = next_test_ip4(); let udpsock = t!(UdpSocket::bind(&socket_addr)); - let udpsock_inner = udpsock.0.socket().as_inner(); + let udpsock_inner = udpsock.0.socket().as_raw(); let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner); assert_eq!(format!("{:?}", udpsock), compare); } diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs new file mode 100644 index 0000000000000..5bf6369122b97 --- /dev/null +++ b/library/std/src/os/unix/io/fd.rs @@ -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 for OwnedFd { + #[inline] + fn from(file: fs::File) -> OwnedFd { + file.into_inner().into_inner().into_inner() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From 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 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 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 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 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 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 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 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 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 for OwnedFd { + #[inline] + fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd { + child_stderr.into_inner().into_inner().into_inner() + } +} diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs new file mode 100644 index 0000000000000..06f47cbb31f01 --- /dev/null +++ b/library/std/src/os/unix/io/mod.rs @@ -0,0 +1,56 @@ +//! Unix-specific extensions to general I/O primitives. +//! +//! Just like raw pointers, raw file descriptors point to resources with +//! dynamic lifetimes, and they can dangle if they outlive their resources +//! or be forged if they're created from invalid values. +//! +//! This module provides three types for representing file descriptors, +//! with different ownership properties: raw, borrowed, and owned, which are +//! analogous to types used for representing pointers: +//! +//! | Type | Analogous to | +//! | ------------------ | ------------ | +//! | [`RawFd`] | `*const _` | +//! | [`BorrowedFd<'a>`] | `&'a _` | +//! | [`OwnedFd`] | `Box<_>` | +//! +//! Like raw pointers, `RawFd` values are primitive values. And in new code, +//! they should be considered unsafe to do I/O on (analogous to dereferencing +//! them). Rust did not always provide this guidance, so existing code in the +//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Libraries are +//! encouraged to migrate, either by adding `unsafe` to APIs that dereference +//! `RawFd` values, or by using to `BorrowedFd` or `OwnedFd` instead. +//! +//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure +//! that they don't outlive the resource they point to. These are safe to +//! use. `BorrowedFd` values may be used in APIs which provide safe access to +//! any system call except for: +//! - `close`, because that would end the dynamic lifetime of the resource +//! without ending the lifetime of the file descriptor. +//! - `dup2`/`dup3`, in the second argument, because this argument is +//! closed and replaced with a new resource, which may break the assumptions +//! other code using that file descriptor. +//! This list doesn't include `mmap`, since `mmap` does do a proper borrow of +//! its file descriptor argument. That said, `mmap` is unsafe for other +//! reasons: it operates on raw pointers, and it has undefined behavior if the +//! underlying storage is mutated. Mutations may come from other processes, or +//! from the same process if the API provides `BorrowedFd` access, since as +//! mentioned earlier, `BorrowedFd` values may be used in APIs which provide +//! safe access to any system call. Consequently, code using `mmap` and +//! presenting a safe API must take full responsibility for ensuring that safe +//! Rust code cannot evoke undefined behavior through it. +//! +//! Like boxes, `OwnedFd` values conceptually own the resource they point to, +//! and free (close) it when they are dropped. +//! +//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd + +#![stable(feature = "rust1", since = "1.0.0")] + +mod fd; +mod raw; + +#[unstable(feature = "io_safety", issue = "87074")] +pub use fd::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::*; diff --git a/library/std/src/os/unix/io.rs b/library/std/src/os/unix/io/raw.rs similarity index 96% rename from library/std/src/os/unix/io.rs rename to library/std/src/os/unix/io/raw.rs index 07c30bfa9ed15..78ee706d41dee 100644 --- a/library/std/src/os/unix/io.rs +++ b/library/std/src/os/unix/io/raw.rs @@ -5,8 +5,8 @@ use crate::fs; use crate::io; use crate::os::raw; -use crate::sys; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::os::unix::io::OwnedFd; +use crate::sys_common::{AsInner, IntoInner}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] @@ -128,21 +128,21 @@ impl FromRawFd for RawFd { impl AsRawFd for fs::File { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() + self.as_inner().as_raw_fd() } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawFd for fs::File { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) + fs::File::from(OwnedFd::from_raw_fd(fd)) } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for fs::File { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 9e39f70f68e69..f11eec18cc521 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -21,7 +21,7 @@ use super::{sockaddr_un, SocketAddr}; ))] use crate::io::{IoSlice, IoSliceMut}; use crate::net::Shutdown; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; @@ -106,7 +106,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::bind(socket.as_raw_fd(), &addr as *const _ as *const _, len as _))?; Ok(socket) } @@ -187,7 +187,7 @@ impl UnixDatagram { unsafe { let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(*self.0.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::connect(self.as_raw_fd(), &addr as *const _ as *const _, len))?; } Ok(()) } @@ -229,7 +229,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) }) } /// Returns the address of this socket's peer. @@ -253,7 +253,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) }) } fn recv_from_flags( @@ -264,7 +264,7 @@ impl UnixDatagram { let mut count = 0; let addr = SocketAddr::new(|addr, len| unsafe { count = libc::recvfrom( - *self.0.as_inner(), + self.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len(), flags, @@ -462,7 +462,7 @@ impl UnixDatagram { let (addr, len) = sockaddr_un(path.as_ref())?; let count = cvt(libc::sendto( - *self.0.as_inner(), + self.as_raw_fd(), buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, @@ -881,7 +881,7 @@ impl UnixDatagram { impl AsRawFd for UnixDatagram { #[inline] fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() + self.0.as_inner().as_raw_fd() } } @@ -889,7 +889,7 @@ impl AsRawFd for UnixDatagram { impl FromRawFd for UnixDatagram { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { - UnixDatagram(Socket::from_inner(fd)) + UnixDatagram(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)))) } } @@ -897,6 +897,30 @@ impl FromRawFd for UnixDatagram { impl IntoRawFd for UnixDatagram { #[inline] fn into_raw_fd(self) -> RawFd { - self.0.into_inner() + self.0.into_inner().into_inner().into_raw_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for UnixDatagram { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(unix_datagram: UnixDatagram) -> OwnedFd { + unsafe { OwnedFd::from_raw_fd(unix_datagram.into_raw_fd()) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for UnixDatagram { + #[inline] + fn from(owned: OwnedFd) -> Self { + unsafe { Self::from_raw_fd(owned.into_raw_fd()) } } } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index bdd08fe8380fa..9066c71794fad 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -1,5 +1,5 @@ use super::{sockaddr_un, SocketAddr, UnixStream}; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; @@ -74,8 +74,8 @@ impl UnixListener { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; + cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(inner.as_inner().as_raw_fd(), 128))?; Ok(UnixListener(inner)) } @@ -150,7 +150,7 @@ impl UnixListener { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) }) } /// Moves the socket into or out of nonblocking mode. @@ -242,7 +242,7 @@ impl UnixListener { impl AsRawFd for UnixListener { #[inline] fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() + self.0.as_inner().as_raw_fd() } } @@ -250,7 +250,7 @@ impl AsRawFd for UnixListener { impl FromRawFd for UnixListener { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) + UnixListener(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)))) } } @@ -258,7 +258,7 @@ impl FromRawFd for UnixListener { impl IntoRawFd for UnixListener { #[inline] fn into_raw_fd(self) -> RawFd { - self.0.into_inner() + self.0.into_inner().into_inner().into_raw_fd() } } diff --git a/library/std/src/os/unix/net/raw_fd.rs b/library/std/src/os/unix/net/raw_fd.rs index b3f1284410124..017caeebf7243 100644 --- a/library/std/src/os/unix/net/raw_fd.rs +++ b/library/std/src/os/unix/net/raw_fd.rs @@ -1,4 +1,4 @@ -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; use crate::{net, sys}; @@ -8,7 +8,7 @@ macro_rules! impl_as_raw_fd { impl AsRawFd for net::$t { #[inline] fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() + self.as_inner().socket().as_raw_fd() } } )*}; @@ -21,7 +21,7 @@ macro_rules! impl_from_raw_fd { impl FromRawFd for net::$t { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> net::$t { - let socket = sys::net::Socket::from_inner(fd); + let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))); net::$t::from_inner(sys_common::net::$t::from_inner(socket)) } } @@ -35,7 +35,7 @@ macro_rules! impl_into_raw_fd { impl IntoRawFd for net::$t { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() + self.into_inner().into_socket().into_inner().into_inner().into_raw_fd() } } )*}; diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index fba084375e5f8..4119de3c03cbe 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -13,7 +13,7 @@ use super::{sockaddr_un, SocketAddr}; use crate::fmt; use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::net::Shutdown; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; #[cfg(any( target_os = "android", target_os = "linux", @@ -28,7 +28,7 @@ use crate::os::unix::ucred; use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner}; use crate::time::Duration; #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] @@ -101,7 +101,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::connect(inner.as_raw_fd(), &addr as *const _ as *const _, len))?; Ok(UnixStream(inner)) } } @@ -167,7 +167,7 @@ impl UnixStream { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) }) } /// Returns the socket address of the remote half of this connection. @@ -185,7 +185,7 @@ impl UnixStream { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) }) } /// Gets the peer credentials for this Unix domain socket. @@ -659,7 +659,7 @@ impl<'a> io::Write for &'a UnixStream { impl AsRawFd for UnixStream { #[inline] fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() + self.0.as_raw_fd() } } @@ -667,7 +667,7 @@ impl AsRawFd for UnixStream { impl FromRawFd for UnixStream { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) + UnixStream(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)))) } } @@ -675,6 +675,30 @@ impl FromRawFd for UnixStream { impl IntoRawFd for UnixStream { #[inline] fn into_raw_fd(self) -> RawFd { - self.0.into_inner() + self.0.into_raw_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for UnixStream { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(unix_stream: UnixStream) -> OwnedFd { + unsafe { OwnedFd::from_raw_fd(unix_stream.into_raw_fd()) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for UnixStream { + #[inline] + fn from(owned: OwnedFd) -> Self { + unsafe { Self::from_raw_fd(owned.into_raw_fd()) } } } diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 615290d270307..1e794842e3c11 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -321,7 +321,7 @@ impl ExitStatusExt for process::ExitStatusError { impl FromRawFd for process::Stdio { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { - let fd = sys::fd::FileDesc::new(fd); + let fd = sys::fd::FileDesc::from_raw_fd(fd); let io = sys::process::Stdio::Fd(fd); process::Stdio::from_inner(io) } @@ -331,7 +331,7 @@ impl FromRawFd for process::Stdio { impl AsRawFd for process::ChildStdin { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() + self.as_inner().as_raw_fd() } } @@ -339,7 +339,7 @@ impl AsRawFd for process::ChildStdin { impl AsRawFd for process::ChildStdout { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() + self.as_inner().as_raw_fd() } } @@ -347,7 +347,7 @@ impl AsRawFd for process::ChildStdout { impl AsRawFd for process::ChildStderr { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() + self.as_inner().as_raw_fd() } } @@ -355,7 +355,7 @@ impl AsRawFd for process::ChildStderr { impl IntoRawFd for process::ChildStdin { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } @@ -363,7 +363,7 @@ impl IntoRawFd for process::ChildStdin { impl IntoRawFd for process::ChildStdout { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } @@ -371,7 +371,7 @@ impl IntoRawFd for process::ChildStdout { impl IntoRawFd for process::ChildStderr { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index bd30d6ae3f333..3df27563e21e9 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -228,35 +228,35 @@ pub trait FileExt { impl FileExt for fs::File { fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - self.as_inner().fd().pread(bufs, offset) + self.as_inner().as_inner().pread(bufs, offset) } fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - self.as_inner().fd().pwrite(bufs, offset) + self.as_inner().as_inner().pwrite(bufs, offset) } fn tell(&self) -> io::Result { - self.as_inner().fd().tell() + self.as_inner().as_inner().tell() } fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> { - self.as_inner().fd().set_flags(flags) + self.as_inner().as_inner().set_flags(flags) } fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> { - self.as_inner().fd().set_rights(rights, inheriting) + self.as_inner().as_inner().set_rights(rights, inheriting) } fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> { - self.as_inner().fd().advise(offset, len, advice) + self.as_inner().as_inner().advise(offset, len, advice) } fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - self.as_inner().fd().allocate(offset, len) + self.as_inner().as_inner().allocate(offset, len) } fn create_directory>(&self, dir: P) -> io::Result<()> { - self.as_inner().fd().create_directory(osstr2str(dir.as_ref().as_ref())?) + self.as_inner().as_inner().create_directory(osstr2str(dir.as_ref().as_ref())?) } fn read_link>(&self, path: P) -> io::Result { @@ -269,11 +269,11 @@ impl FileExt for fs::File { } fn remove_file>(&self, path: P) -> io::Result<()> { - self.as_inner().fd().unlink_file(osstr2str(path.as_ref().as_ref())?) + self.as_inner().as_inner().unlink_file(osstr2str(path.as_ref().as_ref())?) } fn remove_directory>(&self, path: P) -> io::Result<()> { - self.as_inner().fd().remove_directory(osstr2str(path.as_ref().as_ref())?) + self.as_inner().as_inner().remove_directory(osstr2str(path.as_ref().as_ref())?) } } @@ -486,10 +486,10 @@ pub fn link, U: AsRef>( new_fd: &File, new_path: U, ) -> io::Result<()> { - old_fd.as_inner().fd().link( + old_fd.as_inner().as_inner().link( old_flags, osstr2str(old_path.as_ref().as_ref())?, - new_fd.as_inner().fd(), + new_fd.as_inner().as_inner(), osstr2str(new_path.as_ref().as_ref())?, ) } @@ -503,9 +503,9 @@ pub fn rename, U: AsRef>( new_fd: &File, new_path: U, ) -> io::Result<()> { - old_fd.as_inner().fd().rename( + old_fd.as_inner().as_inner().rename( osstr2str(old_path.as_ref().as_ref())?, - new_fd.as_inner().fd(), + new_fd.as_inner().as_inner(), osstr2str(new_path.as_ref().as_ref())?, ) } @@ -519,7 +519,7 @@ pub fn symlink, U: AsRef>( new_path: U, ) -> io::Result<()> { fd.as_inner() - .fd() + .as_inner() .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?) } diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs new file mode 100644 index 0000000000000..494903d941c78 --- /dev/null +++ b/library/std/src/os/wasi/io/fd.rs @@ -0,0 +1,280 @@ +//! Owned and borrowed file descriptors. + +#![unstable(feature = "wasi_ext", issue = "71213")] + +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); + unsafe { 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, RawFd::MAX); + // 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) + unsafe { 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 + /// use std::fs::File; + /// # use std::io; + /// use std::os::wasi::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 for OwnedFd { + #[inline] + fn from(file: fs::File) -> OwnedFd { + file.into_inner().into_inner().into_inner() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From 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 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 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 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 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 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 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, + )))) + } +} diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs new file mode 100644 index 0000000000000..6c884e2eaf471 --- /dev/null +++ b/library/std/src/os/wasi/io/mod.rs @@ -0,0 +1,12 @@ +//! WASI-specific extensions to general I/O primitives. + +#![deny(unsafe_op_in_unsafe_fn)] +#![unstable(feature = "wasi_ext", issue = "71213")] + +mod fd; +mod raw; + +#[unstable(feature = "wasi_ext", issue = "71213")] +pub use fd::*; +#[unstable(feature = "wasi_ext", issue = "71213")] +pub use raw::*; diff --git a/library/std/src/os/wasi/io.rs b/library/std/src/os/wasi/io/raw.rs similarity index 65% rename from library/std/src/os/wasi/io.rs rename to library/std/src/os/wasi/io/raw.rs index b6bc74da8e7b5..3e935e2502e9c 100644 --- a/library/std/src/os/wasi/io.rs +++ b/library/std/src/os/wasi/io/raw.rs @@ -1,6 +1,5 @@ -//! WASI-specific extensions to general I/O primitives +//! Unix-specific extensions to general I/O primitives. -#![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "wasi_ext", issue = "71213")] use crate::fs; @@ -9,6 +8,7 @@ use crate::net; use crate::os::raw; use crate::sys; use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::os::wasi::io::OwnedFd; /// Raw file descriptors. /// @@ -19,14 +19,31 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// assuming that negative file descriptors are invalid. pub type RawFd = raw::c_int; -/// A trait to extract the raw WASI file descriptor from an underlying +/// A trait to extract the raw unix 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 `AsRawHandle` +/// and `AsRawSocket` set of traits. pub trait AsRawFd { /// Extracts the raw file descriptor. /// /// This method does **not** pass ownership of the raw file descriptor /// to the caller. The descriptor is only guaranteed to be valid while /// the original object has not yet been destroyed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::wasi::io::{AsRawFd, RawFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// // Note that `raw_fd` is only valid as long as `f` exists. + /// let raw_fd: RawFd = f.as_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` fn as_raw_fd(&self) -> RawFd; } @@ -45,6 +62,21 @@ pub trait FromRawFd { /// descriptor they are wrapping. Usage of this function could /// accidentally allow violating this contract which can cause memory /// unsafety in code that relies on it being true. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// // SAFETY: no other functions should call `from_raw_fd`, so there + /// // is only one owner for the file descriptor. + /// let f = unsafe { File::from_raw_fd(raw_fd) }; + /// # Ok::<(), io::Error>(()) + /// ``` unsafe fn from_raw_fd(fd: RawFd) -> Self; } @@ -56,24 +88,33 @@ pub trait IntoRawFd { /// This function **transfers ownership** of the underlying file descriptor /// to the caller. Callers are then the unique owners of the file descriptor /// and must close the descriptor once it's no longer needed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::wasi::io::{IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` fn into_raw_fd(self) -> RawFd; } -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl AsRawFd for RawFd { #[inline] fn as_raw_fd(&self) -> RawFd { *self } } -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl IntoRawFd for RawFd { #[inline] fn into_raw_fd(self) -> RawFd { self } } -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl FromRawFd for RawFd { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> RawFd { @@ -81,87 +122,22 @@ impl FromRawFd for RawFd { } } -impl AsRawFd for net::TcpStream { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().as_raw() - } -} - -impl FromRawFd for net::TcpStream { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd)) - } -} - -impl IntoRawFd for net::TcpStream { - #[inline] - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -impl AsRawFd for net::TcpListener { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().as_raw() - } -} - -impl FromRawFd for net::TcpListener { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd)) - } -} - -impl IntoRawFd for net::TcpListener { - #[inline] - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -impl AsRawFd for net::UdpSocket { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().as_raw() - } -} - -impl FromRawFd for net::UdpSocket { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd)) - } -} - -impl IntoRawFd for net::UdpSocket { - #[inline] - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - impl AsRawFd for fs::File { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().as_raw() + self.as_inner().as_raw_fd() } } - impl FromRawFd for fs::File { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) + unsafe { fs::File::from(OwnedFd::from_raw_fd(fd)) } } } - impl IntoRawFd for fs::File { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs index 44b7c32e95617..1338aa271b33f 100644 --- a/library/std/src/os/wasi/mod.rs +++ b/library/std/src/os/wasi/mod.rs @@ -32,6 +32,7 @@ pub mod ffi; pub mod fs; pub mod io; +pub mod net; /// A prelude for conveniently writing platform-specific code. /// diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs new file mode 100644 index 0000000000000..01b2c1033f7e7 --- /dev/null +++ b/library/std/src/os/wasi/net/mod.rs @@ -0,0 +1,8 @@ +//! WASI-specific networking functionality + +#![unstable(feature = "wasi_ext", issue = "71213")] + +mod raw_fd; + +#[unstable(feature = "wasi_ext", issue = "71213")] +pub use self::raw_fd::*; diff --git a/library/std/src/os/wasi/net/raw_fd.rs b/library/std/src/os/wasi/net/raw_fd.rs new file mode 100644 index 0000000000000..201f4fbce390a --- /dev/null +++ b/library/std/src/os/wasi/net/raw_fd.rs @@ -0,0 +1,45 @@ +use crate::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::{net, sys}; + +macro_rules! impl_as_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl AsRawFd for net::$t { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.as_inner().socket().as_raw_fd() + } + } + )*}; +} +impl_as_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_from_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "from_raw_os", since = "1.1.0")] + impl FromRawFd for net::$t { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> net::$t { + unsafe { + let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))); + net::$t::from_inner(sys::net::$t::from_inner(socket)) + } + } + } + )*}; +} +impl_from_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_into_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "into_raw_os", since = "1.4.0")] + impl IntoRawFd for net::$t { + #[inline] + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner().into_inner().into_raw_fd() + } + } + )*}; +} +impl_into_raw_fd! { TcpStream TcpListener UdpSocket } diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs new file mode 100644 index 0000000000000..d881a67709d8f --- /dev/null +++ b/library/std/src/os/windows/io/handle.rs @@ -0,0 +1,390 @@ +//! Owned and borrowed OS handles. + +#![unstable(feature = "io_safety", issue = "87074")] + +use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; +use crate::convert::TryFrom; +use crate::ffi::c_void; +use crate::fmt; +use crate::fs; +use crate::marker::PhantomData; +use crate::mem::forget; +use crate::ptr::NonNull; +use crate::sys::c; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +/// A borrowed handle. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the handle. +/// +/// This uses `repr(transparent)` and has the representation of a host handle, +/// so it can be used in FFI in places where a handle is passed as an argument, +/// it is not captured or consumed, and it is never null. +/// +/// Note that it *may* have the value `INVALID_HANDLE_VALUE`. See [here] for +/// the full story. +/// +/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +#[derive(Copy, Clone)] +#[repr(transparent)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct BorrowedHandle<'handle> { + raw: NonNull, + _phantom: PhantomData<&'handle OwnedHandle>, +} + +/// An owned handle. +/// +/// This closes the handle on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host handle, +/// so it can be used in FFI in places where a handle is passed as a consumed +/// argument or returned as an owned value, and is never null. +/// +/// Note that it *may* have the value `INVALID_HANDLE_VALUE`. See [here] for +/// the full story. For APIs like `CreateFileW` which report errors with +/// `INVALID_HANDLE_VALUE` instead of null, use [`OptionFileHandle`] instead +/// of `Option`. +/// +/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +#[repr(transparent)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct OwnedHandle { + raw: NonNull, +} + +/// Similar to `Option`, but intended for use in FFI interfaces +/// where `INVALID_HANDLE_VALUE` is used as the sentry value, and null values +/// are not used at all, such as in the return value of `CreateFileW`. +/// +/// If this holds an owned handle, it closes the handle on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host handle, +/// so it can be used in FFI in places where a non-null handle is passed as a +/// consumed argument or returned as an owned value, or it is +/// `INVALID_HANDLE_VALUE` indicating an error or an otherwise absent value. +/// +#[repr(transparent)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct OptionFileHandle { + raw: RawHandle, +} + +// The Windows [`HANDLE`] type may be transferred across and shared between +// thread boundaries (despite containing a `*mut void`, which in general isn't +// `Send` or `Sync`). +// +// [`HANDLE`]: std::os::windows::raw::HANDLE +unsafe impl Send for OwnedHandle {} +unsafe impl Send for OptionFileHandle {} +unsafe impl Send for BorrowedHandle<'_> {} +unsafe impl Sync for OwnedHandle {} +unsafe impl Sync for OptionFileHandle {} +unsafe impl Sync for BorrowedHandle<'_> {} + +impl BorrowedHandle<'_> { + /// Return a `BorrowedHandle` holding the given raw handle. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must remain open for the duration of + /// the returned `BorrowedHandle`, and it must not be null. + #[inline] + #[unstable(feature = "io_safety", issue = "87074")] + pub unsafe fn borrow_raw_handle(raw: RawHandle) -> Self { + assert!(!raw.is_null()); + Self { raw: NonNull::new_unchecked(raw), _phantom: PhantomData } + } +} + +impl OptionFileHandle { + /// Return an empty `OptionFileHandle` with no resource. + #[inline] + #[unstable(feature = "io_safety", issue = "87074")] + pub const fn none() -> Self { + Self { raw: c::INVALID_HANDLE_VALUE } + } +} + +impl TryFrom for OwnedHandle { + type Error = (); + + #[inline] + fn try_from(option: OptionFileHandle) -> Result { + let raw = option.raw; + forget(option); + if let Some(non_null) = NonNull::new(raw) { + if non_null.as_ptr() != c::INVALID_HANDLE_VALUE { + Ok(Self { raw: non_null }) + } else { + Err(()) + } + } else { + // In theory, we ought to be able to assume that the pointer here + // is never null, change `option.raw` to `NonNull`, and obviate the + // the panic path here. Unfortunately, Win32 documentation doesn't + // explicitly guarantee this anywhere. + // + // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a + // null handle indicates an absent value, which wouldn't work if + // null were a valid handle value, so it seems very unlikely that + // it could ever return null. But who knows? + // + // [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew + panic!("An `OptionFileHandle` was null!"); + } + } +} + +impl From for OptionFileHandle { + #[inline] + fn from(owned: OwnedHandle) -> Self { + let raw = owned.raw; + forget(owned); + Self { raw: raw.as_ptr() } + } +} + +impl AsRawHandle for BorrowedHandle<'_> { + #[inline] + fn as_raw_handle(&self) -> RawHandle { + self.raw.as_ptr() + } +} + +impl AsRawHandle for OwnedHandle { + #[inline] + fn as_raw_handle(&self) -> RawHandle { + self.raw.as_ptr() + } +} + +impl IntoRawHandle for OwnedHandle { + #[inline] + fn into_raw_handle(self) -> RawHandle { + let raw = self.raw.as_ptr(); + forget(self); + raw + } +} + +impl FromRawHandle for OwnedHandle { + /// Constructs a new instance of `Self` from the given raw handle. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must be open and suitable for assuming + /// ownership. + #[inline] + unsafe fn from_raw_handle(raw: RawHandle) -> Self { + assert!(!raw.is_null()); + Self { raw: NonNull::new_unchecked(raw) } + } +} + +impl FromRawHandle for OptionFileHandle { + /// Constructs a new instance of `Self` from the given raw handle. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must be either open and otherwise + /// unowned, or equal to `INVALID_HANDLE_VALUE``. Note that not all Windows + /// APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for the full + /// story. + /// + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 + #[inline] + unsafe fn from_raw_handle(raw: RawHandle) -> Self { + assert!(!raw.is_null()); + Self { raw } + } +} + +impl Drop for OwnedHandle { + #[inline] + fn drop(&mut self) { + unsafe { + let _ = c::CloseHandle(self.raw.as_ptr()); + } + } +} + +impl Drop for OptionFileHandle { + #[inline] + fn drop(&mut self) { + unsafe { + let _ = c::CloseHandle(self.raw); + } + } +} + +impl fmt::Debug for BorrowedHandle<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedHandle").field("handle", &self.raw).finish() + } +} + +impl fmt::Debug for OwnedHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedHandle").field("handle", &self.raw).finish() + } +} + +impl fmt::Debug for OptionFileHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OptionFileHandle").field("handle", &self.raw).finish() + } +} + +/// A trait to borrow the handle from an underlying object. +#[unstable(feature = "io_safety", issue = "87074")] +pub trait AsHandle { + /// Borrows the handle. + /// + /// # Example + /// + /// ```rust,no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::windows::{AsHandle, BorrowedHandle}; + /// + /// let mut f = File::open("foo.txt")?; + /// let borrowed_handle: BorrowedHandle<'_> = f.as_handle(); + /// # Ok::<(), io::Error>(()) + /// ``` + fn as_handle(&self) -> BorrowedHandle<'_>; +} + +impl AsHandle for BorrowedHandle<'_> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + *self + } +} + +impl AsHandle for OwnedHandle { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandle for fs::File { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().as_handle() + } +} + +impl From for OwnedHandle { + #[inline] + fn from(file: fs::File) -> OwnedHandle { + file.into_inner().into_inner().into_inner().into() + } +} + +impl From for fs::File { + #[inline] + fn from(owned: OwnedHandle) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) + } +} + +impl AsHandle for crate::io::Stdin { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl<'a> AsHandle for crate::io::StdinLock<'a> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandle for crate::io::Stdout { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl<'a> AsHandle for crate::io::StdoutLock<'a> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandle for crate::io::Stderr { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl<'a> AsHandle for crate::io::StderrLock<'a> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandle for crate::process::ChildStdin { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl From for OwnedHandle { + #[inline] + fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle { + unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) } + } +} + +impl AsHandle for crate::process::ChildStdout { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl From for OwnedHandle { + #[inline] + fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle { + unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) } + } +} + +impl AsHandle for crate::process::ChildStderr { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl From for OwnedHandle { + #[inline] + fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle { + unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) } + } +} + +impl AsHandle for crate::thread::JoinHandle { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl From> for OwnedHandle { + #[inline] + fn from(join_handle: crate::thread::JoinHandle) -> OwnedHandle { + join_handle.into_inner().into_handle().into_inner() + } +} diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs new file mode 100644 index 0000000000000..d8e453bc0e040 --- /dev/null +++ b/library/std/src/os/windows/io/mod.rs @@ -0,0 +1,56 @@ +//! Windows-specific extensions to general I/O primitives. +//! +//! Just like raw pointers, raw Windows handles and sockets point to resources +//! with dynamic lifetimes, and they can dangle if they outlive their resources +//! or be forged if they're created from invalid values. +//! +//! This module provides three types for representing raw handles and sockets +//! with different ownership properties: raw, borrowed, and owned, which are +//! analogous to types used for representing pointers: +//! +//! | Type | Analogous to | +//! | ---------------------- | ------------ | +//! | [`RawHandle`] | `*const _` | +//! | [`RawSocket`] | `*const _` | +//! | | | +//! | [`BorrowedHandle<'a>`] | `&'a _` | +//! | [`BorrowedSocket<'a>`] | `&'a _` | +//! | | | +//! | [`OwnedHandle`] | `Box<_>` | +//! | [`OwnedSocket`] | `Box<_>` | +//! +//! Like raw pointers, `RawHandle` and `RawSocket` values are primitive values. +//! And in new code, they should be considered unsafe to do I/O on (analogous +//! to dereferencing them). Rust did not always provide this guidance, so +//! existing code in the Rust ecosystem often doesn't mark `RawHandle` and +//! `RawSocket` usage as unsafe. Libraries are encouraged to migrate, either by +//! adding `unsafe` to APIs that dereference `RawHandle` and `RawSocket` +//! values, or by using to `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, +//! or `OwnedSocket`. +//! +//! Like references, `BorrowedHandle` and `BorrowedSocket` values are tied to a +//! lifetime, to ensure that they don't outlive the resource they point to. +//! These are safe to use. `BorrowedHandle` and `BorrowedSocket` values may be +//! used in APIs which provide safe access to any system call except for +//! `CloseHandle`, `closesocket`, or any other call that would end the +//! dynamic lifetime of the resource without ending the lifetime of the +//! handle or socket. +//! +//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the +//! resource they point to, and free (close) it when they are dropped. +//! +//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle +//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket + +#![stable(feature = "rust1", since = "1.0.0")] + +mod handle; +mod raw; +mod socket; + +#[unstable(feature = "io_safety", issue = "87074")] +pub use handle::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::*; +#[unstable(feature = "io_safety", issue = "87074")] +pub use socket::*; diff --git a/library/std/src/os/windows/io.rs b/library/std/src/os/windows/io/raw.rs similarity index 88% rename from library/std/src/os/windows/io.rs rename to library/std/src/os/windows/io/raw.rs index 31b5d015ed0c3..c7f122048a198 100644 --- a/library/std/src/os/windows/io.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -5,6 +5,7 @@ use crate::fs; use crate::io; use crate::net; +use crate::os::windows::io::{OwnedHandle, OwnedSocket}; use crate::os::windows::raw; use crate::sys; use crate::sys::c; @@ -61,7 +62,7 @@ pub trait IntoRawHandle { impl AsRawHandle for fs::File { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as RawHandle + self.as_inner().as_raw_handle() as RawHandle } } @@ -112,7 +113,9 @@ impl FromRawHandle for fs::File { #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { let handle = handle as c::HANDLE; - fs::File::from_inner(sys::fs::File::from_inner(handle)) + fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( + OwnedHandle::from_raw_handle(handle), + ))) } } @@ -120,7 +123,7 @@ impl FromRawHandle for fs::File { impl IntoRawHandle for fs::File { #[inline] fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_raw_handle() as *mut _ } } @@ -166,21 +169,21 @@ pub trait IntoRawSocket { impl AsRawSocket for net::TcpStream { #[inline] fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() + self.as_inner().socket().as_raw_socket() } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpListener { #[inline] fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() + self.as_inner().socket().as_raw_socket() } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::UdpSocket { #[inline] fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() + self.as_inner().socket().as_raw_socket() } } @@ -188,7 +191,7 @@ impl AsRawSocket for net::UdpSocket { impl FromRawSocket for net::TcpStream { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - let sock = sys::net::Socket::from_inner(sock); + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) } } @@ -196,7 +199,7 @@ impl FromRawSocket for net::TcpStream { impl FromRawSocket for net::TcpListener { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - let sock = sys::net::Socket::from_inner(sock); + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) } } @@ -204,7 +207,7 @@ impl FromRawSocket for net::TcpListener { impl FromRawSocket for net::UdpSocket { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - let sock = sys::net::Socket::from_inner(sock); + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) } } @@ -213,7 +216,7 @@ impl FromRawSocket for net::UdpSocket { impl IntoRawSocket for net::TcpStream { #[inline] fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() + self.into_inner().into_socket().into_inner().into_raw_socket() } } @@ -221,7 +224,7 @@ impl IntoRawSocket for net::TcpStream { impl IntoRawSocket for net::TcpListener { #[inline] fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() + self.into_inner().into_socket().into_inner().into_raw_socket() } } @@ -229,6 +232,6 @@ impl IntoRawSocket for net::TcpListener { impl IntoRawSocket for net::UdpSocket { #[inline] fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() + self.into_inner().into_socket().into_inner().into_raw_socket() } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs new file mode 100644 index 0000000000000..e45b334690e91 --- /dev/null +++ b/library/std/src/os/windows/io/socket.rs @@ -0,0 +1,212 @@ +//! Owned and borrowed OS sockets. + +#![unstable(feature = "io_safety", issue = "87074")] + +use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; +use crate::fmt; +use crate::marker::PhantomData; +use crate::mem::forget; +use crate::sys::c; + +/// A borrowed socket. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the socket. +/// +/// This uses `repr(transparent)` and has the representation of a host socket, +/// so it can be used in FFI in places where a socket is passed as an argument, +/// it is not captured or consumed, and it never has the value +/// `INVALID_SOCKET`. +#[derive(Copy, Clone)] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// This is -2, in two's complement. -1 is `INVALID_SOCKET`. +#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr( + target_pointer_width = "64", + rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) +)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct BorrowedSocket<'socket> { + raw: RawSocket, + _phantom: PhantomData<&'socket OwnedSocket>, +} + +/// An owned socket. +/// +/// This closes the socket on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host socket, +/// so it can be used in FFI in places where a socket is passed as a consumed +/// argument or returned as an owned value, and it never has the value +/// `INVALID_SOCKET`. +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// This is -2, in two's complement. -1 is `INVALID_SOCKET`. +#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr( + target_pointer_width = "64", + rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) +)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct OwnedSocket { + raw: RawSocket, +} + +impl BorrowedSocket<'_> { + /// Return a `BorrowedSocket` holding the given raw socket. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must remain open for the duration of + /// the returned `BorrowedSocket`, and it must not have the value + /// `INVALID_SOCKET`. + #[inline] + #[unstable(feature = "io_safety", issue = "87074")] + pub unsafe fn borrow_raw_socket(raw: RawSocket) -> Self { + debug_assert_ne!(raw, c::INVALID_SOCKET as RawSocket); + Self { raw, _phantom: PhantomData } + } +} + +impl AsRawSocket for BorrowedSocket<'_> { + #[inline] + fn as_raw_socket(&self) -> RawSocket { + self.raw + } +} + +impl AsRawSocket for OwnedSocket { + #[inline] + fn as_raw_socket(&self) -> RawSocket { + self.raw + } +} + +impl IntoRawSocket for OwnedSocket { + #[inline] + fn into_raw_socket(self) -> RawSocket { + let raw = self.raw; + forget(self); + raw + } +} + +impl FromRawSocket for OwnedSocket { + /// Constructs a new instance of `Self` from the given raw socket. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must be open and suitable for assuming + /// ownership. + #[inline] + unsafe fn from_raw_socket(raw: RawSocket) -> Self { + debug_assert_ne!(raw, c::INVALID_SOCKET as RawSocket); + Self { raw } + } +} + +impl Drop for OwnedSocket { + #[inline] + fn drop(&mut self) { + unsafe { + let _ = c::closesocket(self.raw); + } + } +} + +impl fmt::Debug for BorrowedSocket<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedSocket").field("socket", &self.raw).finish() + } +} + +impl fmt::Debug for OwnedSocket { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedSocket").field("socket", &self.raw).finish() + } +} + +/// A trait to borrow the socket from an underlying object. +#[unstable(feature = "io_safety", issue = "87074")] +pub trait AsSocket { + /// Borrows the socket. + fn as_socket(&self) -> BorrowedSocket<'_>; +} + +impl AsSocket for BorrowedSocket<'_> { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + *self + } +} + +impl AsSocket for OwnedSocket { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + } +} + +impl AsSocket for crate::net::TcpStream { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + } +} + +impl From for OwnedSocket { + #[inline] + fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket { + unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) } + } +} + +impl From for crate::net::TcpStream { + #[inline] + fn from(owned: OwnedSocket) -> Self { + unsafe { Self::from_raw_socket(owned.into_raw_socket()) } + } +} + +impl AsSocket for crate::net::TcpListener { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + } +} + +impl From for OwnedSocket { + #[inline] + fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket { + unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) } + } +} + +impl From for crate::net::TcpListener { + #[inline] + fn from(owned: OwnedSocket) -> Self { + unsafe { Self::from_raw_socket(owned.into_raw_socket()) } + } +} + +impl AsSocket for crate::net::UdpSocket { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + } +} + +impl From for OwnedSocket { + #[inline] + fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket { + unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) } + } +} + +impl From for crate::net::UdpSocket { + #[inline] + fn from(owned: OwnedSocket) -> Self { + unsafe { Self::from_raw_socket(owned.into_raw_socket()) } + } +} diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 9e7ccd015b658..56efb62d649a2 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -12,7 +12,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { - let handle = sys::handle::Handle::new(handle as *mut _); + let handle = sys::handle::Handle::from_raw_handle(handle as *mut _); let io = sys::process::Stdio::Handle(handle); process::Stdio::from_inner(io) } @@ -22,14 +22,14 @@ impl FromRawHandle for process::Stdio { impl AsRawHandle for process::Child { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::Child { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } @@ -37,7 +37,7 @@ impl IntoRawHandle for process::Child { impl AsRawHandle for process::ChildStdin { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } @@ -45,7 +45,7 @@ impl AsRawHandle for process::ChildStdin { impl AsRawHandle for process::ChildStdout { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } @@ -53,28 +53,28 @@ impl AsRawHandle for process::ChildStdout { impl AsRawHandle for process::ChildStderr { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdin { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdout { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStderr { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs index 6bd02054f7150..fb1bf66ceed35 100644 --- a/library/std/src/os/windows/thread.rs +++ b/library/std/src/os/windows/thread.rs @@ -10,7 +10,7 @@ use crate::thread; impl AsRawHandle for thread::JoinHandle { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } @@ -18,6 +18,6 @@ impl AsRawHandle for thread::JoinHandle { impl IntoRawHandle for thread::JoinHandle { #[inline] fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 28e32681e15b3..0956726084e02 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -5,21 +5,14 @@ mod tests; use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; -use crate::mem; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys::cvt; -use crate::sys_common::AsInner; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use libc::{c_int, c_void}; #[derive(Debug)] -#[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)] -pub struct FileDesc { - fd: c_int, -} +pub struct FileDesc(OwnedFd); // The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, // with the man page quoting that if the count of bytes to read is @@ -67,26 +60,13 @@ const fn max_iov() -> usize { } impl FileDesc { - pub fn new(fd: c_int) -> FileDesc { - assert_ne!(fd, -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) - unsafe { FileDesc { fd } } - } - - pub fn raw(&self) -> c_int { - self.fd - } - - /// Extracts the actual file descriptor without closing it. - pub fn into_raw(self) -> c_int { - let fd = self.fd; - mem::forget(self); - fd - } - pub fn read(&self, buf: &mut [u8]) -> io::Result { let ret = cvt(unsafe { - libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) + libc::read( + self.as_raw_fd(), + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), READ_LIMIT), + ) })?; Ok(ret as usize) } @@ -95,7 +75,7 @@ impl FileDesc { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let ret = cvt(unsafe { libc::readv( - self.fd, + self.as_raw_fd(), bufs.as_ptr() as *const libc::iovec, cmp::min(bufs.len(), max_iov()) as c_int, ) @@ -138,7 +118,7 @@ impl FileDesc { unsafe { cvt_pread64( - self.fd, + self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT), offset as i64, @@ -149,7 +129,11 @@ impl FileDesc { pub fn write(&self, buf: &[u8]) -> io::Result { let ret = cvt(unsafe { - libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) + libc::write( + self.as_raw_fd(), + buf.as_ptr() as *const c_void, + cmp::min(buf.len(), READ_LIMIT), + ) })?; Ok(ret as usize) } @@ -158,7 +142,7 @@ impl FileDesc { pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { let ret = cvt(unsafe { libc::writev( - self.fd, + self.as_raw_fd(), bufs.as_ptr() as *const libc::iovec, cmp::min(bufs.len(), max_iov()) as c_int, ) @@ -196,7 +180,7 @@ impl FileDesc { unsafe { cvt_pwrite64( - self.fd, + self.as_raw_fd(), buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT), offset as i64, @@ -207,7 +191,7 @@ impl FileDesc { #[cfg(target_os = "linux")] pub fn get_cloexec(&self) -> io::Result { - unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) } + unsafe { Ok((cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) } } #[cfg(not(any( @@ -224,7 +208,7 @@ impl FileDesc { )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { - cvt(libc::ioctl(self.fd, libc::FIOCLEX))?; + cvt(libc::ioctl(self.as_raw_fd(), libc::FIOCLEX))?; Ok(()) } } @@ -242,10 +226,10 @@ impl FileDesc { ))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?; + let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))?; let new = previous | libc::FD_CLOEXEC; if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?; + cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFD, new))?; } Ok(()) } @@ -261,7 +245,7 @@ impl FileDesc { pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { unsafe { let v = nonblocking as c_int; - cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?; + cvt(libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &v))?; Ok(()) } } @@ -269,14 +253,14 @@ impl FileDesc { #[cfg(not(target_os = "linux"))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; + let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFL))?; let new = if nonblocking { previous | libc::O_NONBLOCK } else { previous & !libc::O_NONBLOCK }; if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; + cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFL, new))?; } Ok(()) } @@ -296,8 +280,8 @@ impl FileDesc { #[cfg(target_os = "espidf")] let cmd = libc::F_DUPFD; - let fd = cvt(unsafe { libc::fcntl(self.raw(), cmd, 0) })?; - Ok(FileDesc::new(fd)) + let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; + Ok(unsafe { FileDesc::from_raw_fd(fd) }) } } @@ -312,19 +296,44 @@ impl<'a> Read for &'a FileDesc { } } -impl AsInner for FileDesc { - fn as_inner(&self) -> &c_int { - &self.fd +impl AsInner for FileDesc { + fn as_inner(&self) -> &OwnedFd { + &self.0 + } +} + +impl IntoInner for FileDesc { + fn into_inner(self) -> OwnedFd { + self.0 + } +} + +impl FromInner for FileDesc { + fn from_inner(owned_fd: OwnedFd) -> Self { + Self(owned_fd) + } +} + +impl AsFd for FileDesc { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for FileDesc { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for FileDesc { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() } } -impl Drop for FileDesc { - fn drop(&mut self) { - // 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 _ = unsafe { libc::close(self.fd) }; +impl FromRawFd for FileDesc { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) } } diff --git a/library/std/src/sys/unix/fd/tests.rs b/library/std/src/sys/unix/fd/tests.rs index c9520485c3c7c..5d17e46786c79 100644 --- a/library/std/src/sys/unix/fd/tests.rs +++ b/library/std/src/sys/unix/fd/tests.rs @@ -1,9 +1,10 @@ use super::{FileDesc, IoSlice}; +use crate::os::unix::io::FromRawFd; use core::mem::ManuallyDrop; #[test] fn limit_vector_count() { - let stdout = ManuallyDrop::new(unsafe { FileDesc { fd: 1 } }); + let stdout = ManuallyDrop::new(unsafe { FileDesc::from_raw_fd(1) }); let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); assert!(stdout.write_vectored(&bufs).is_ok()); } diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index fd4defd72eb47..6075eb5c7c58a 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -4,13 +4,14 @@ use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sync::Arc; use crate::sys::fd::FileDesc; use crate::sys::time::SystemTime; use crate::sys::{cvt, cvt_r}; -use crate::sys_common::{AsInner, FromInner}; +use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[cfg(any( all(target_os = "linux", target_env = "gnu"), @@ -764,11 +765,11 @@ impl File { // However, since this is a variadic function, C integer promotion rules mean that on // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms). let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; - Ok(File(FileDesc::new(fd))) + Ok(File(unsafe { FileDesc::from_raw_fd(fd) })) } pub fn file_attr(&self) -> io::Result { - let fd = self.0.raw(); + let fd = self.as_raw_fd(); cfg_has_statx! { if let Some(ret) = unsafe { try_statx( @@ -787,7 +788,7 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - cvt_r(|| unsafe { os_fsync(self.0.raw()) })?; + cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?; return Ok(()); #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -801,7 +802,7 @@ impl File { } pub fn datasync(&self) -> io::Result<()> { - cvt_r(|| unsafe { os_datasync(self.0.raw()) })?; + cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?; return Ok(()); #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -834,14 +835,14 @@ impl File { pub fn truncate(&self, size: u64) -> io::Result<()> { #[cfg(target_os = "android")] - return crate::sys::android::ftruncate64(self.0.raw(), size); + return crate::sys::android::ftruncate64(self.as_raw_fd(), size); #[cfg(not(target_os = "android"))] { use crate::convert::TryInto; let size: off64_t = size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; - cvt_r(|| unsafe { ftruncate64(self.0.raw(), size) }).map(drop) + cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop) } } @@ -891,7 +892,7 @@ impl File { SeekFrom::End(off) => (libc::SEEK_END, off), SeekFrom::Current(off) => (libc::SEEK_CUR, off), }; - let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?; + let n = cvt(unsafe { lseek64(self.as_raw_fd(), pos, whence) })?; Ok(n as u64) } @@ -899,16 +900,8 @@ impl File { self.0.duplicate().map(File) } - pub fn fd(&self) -> &FileDesc { - &self.0 - } - - pub fn into_fd(self) -> FileDesc { - self.0 - } - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?; + cvt_r(|| unsafe { libc::fchmod(self.as_raw_fd(), perm.mode) })?; Ok(()) } } @@ -933,9 +926,51 @@ fn cstr(path: &Path) -> io::Result { Ok(CString::new(path.as_os_str().as_bytes())?) } -impl FromInner for File { - fn from_inner(fd: c_int) -> File { - File(FileDesc::new(fd)) +impl AsInner for File { + fn as_inner(&self) -> &FileDesc { + &self.0 + } +} + +impl AsInnerMut for File { + fn as_inner_mut(&mut self) -> &mut FileDesc { + &mut self.0 + } +} + +impl IntoInner for File { + fn into_inner(self) -> FileDesc { + self.0 + } +} + +impl FromInner for File { + fn from_inner(file_desc: FileDesc) -> Self { + Self(file_desc) + } +} + +impl AsFd for File { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for File { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for File { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for File { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) } } @@ -1009,7 +1044,7 @@ impl fmt::Debug for File { None } - let fd = self.0.raw(); + let fd = self.as_raw_fd(); let mut b = f.debug_struct("File"); b.field("fd", &fd); if let Some(path) = get_path(fd) { diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 3f614fde08aca..c2f5da1dbbb11 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -3,6 +3,7 @@ use crate::ffi::CStr; use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::str; use crate::sys::fd::FileDesc; use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; @@ -74,10 +75,10 @@ impl Socket { // flag to atomically create the socket and set it as // CLOEXEC. On Linux this was added in 2.6.27. let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?; - Ok(Socket(FileDesc::new(fd))) + Ok(Socket(FileDesc::from_raw_fd(fd))) } else { let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::new(fd); + let fd = FileDesc::from_raw_fd(fd); fd.set_cloexec()?; let socket = Socket(fd); @@ -109,11 +110,11 @@ impl Socket { ))] { // Like above, set cloexec atomically cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?; - Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))) + Ok((Socket(FileDesc::from_raw_fd(fds[0])), Socket(FileDesc::from_raw_fd(fds[1])))) } else { cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?; - let a = FileDesc::new(fds[0]); - let b = FileDesc::new(fds[1]); + let a = FileDesc::from_raw_fd(fds[0]); + let b = FileDesc::from_raw_fd(fds[1]); a.set_cloexec()?; b.set_cloexec()?; Ok((Socket(a), Socket(b))) @@ -131,7 +132,7 @@ impl Socket { self.set_nonblocking(true)?; let r = unsafe { let (addrp, len) = addr.into_inner(); - cvt(libc::connect(self.0.raw(), addrp, len)) + cvt(libc::connect(self.as_raw_fd(), addrp, len)) }; self.set_nonblocking(false)?; @@ -142,7 +143,7 @@ impl Socket { Err(e) => return Err(e), } - let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 }; + let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { return Err(io::Error::new_const( @@ -212,15 +213,17 @@ impl Socket { target_os = "netbsd", target_os = "openbsd", ))] { - let fd = cvt_r(|| unsafe { - libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) - })?; - Ok(Socket(FileDesc::new(fd))) + unsafe { + let fd = cvt_r(|| libc::accept4(self.as_raw_fd(), storage, len, libc::SOCK_CLOEXEC))?; + Ok(Socket(FileDesc::from_raw_fd(fd))) + } } else { - let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(Socket(fd)) + unsafe { + let fd = cvt_r(|| libc::accept(self.as_raw_fd(), storage, len))?; + let fd = FileDesc::from_raw_fd(fd); + fd.set_cloexec()?; + Ok(Socket(fd)) + } } } } @@ -231,7 +234,7 @@ impl Socket { fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { let ret = cvt(unsafe { - libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + libc::recv(self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) })?; Ok(ret as usize) } @@ -263,7 +266,7 @@ impl Socket { let n = cvt(unsafe { libc::recvfrom( - self.0.raw(), + self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags, @@ -288,7 +291,7 @@ impl Socket { target_os = "openbsd", ))] pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result { - let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?; + let n = cvt(unsafe { libc::recvmsg(self.as_raw_fd(), msg, libc::MSG_CMSG_CLOEXEC) })?; Ok(n as usize) } @@ -319,7 +322,7 @@ impl Socket { target_os = "openbsd", ))] pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result { - let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?; + let n = cvt(unsafe { libc::sendmsg(self.as_raw_fd(), msg, 0) })?; Ok(n as usize) } @@ -369,7 +372,7 @@ impl Socket { Shutdown::Read => libc::SHUT_RD, Shutdown::Both => libc::SHUT_RDWR, }; - cvt(unsafe { libc::shutdown(self.0.raw(), how) })?; + cvt(unsafe { libc::shutdown(self.as_raw_fd(), how) })?; Ok(()) } @@ -396,7 +399,7 @@ impl Socket { #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as libc::c_int; - cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop) + cvt(unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &mut nonblocking) }).map(drop) } #[cfg(any(target_os = "solaris", target_os = "illumos"))] @@ -410,23 +413,52 @@ impl Socket { let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } + + // This is used by sys_common code to abstract over Windows and Unix. + pub fn as_raw(&self) -> RawFd { + self.as_raw_fd() + } +} + +impl AsInner for Socket { + fn as_inner(&self) -> &FileDesc { + &self.0 + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> FileDesc { + self.0 + } +} + +impl FromInner for Socket { + fn from_inner(file_desc: FileDesc) -> Self { + Self(file_desc) + } +} + +impl AsFd for Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } } -impl AsInner for Socket { - fn as_inner(&self) -> &c_int { - self.0.as_inner() +impl AsRawFd for Socket { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() } } -impl FromInner for Socket { - fn from_inner(fd: c_int) -> Socket { - Socket(FileDesc::new(fd)) +impl IntoRawFd for Socket { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() } } -impl IntoInner for Socket { - fn into_inner(self) -> c_int { - self.0.into_raw() +impl FromRawFd for Socket { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) } } diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index 7ae37bdda70bd..a56c275c94207 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -1,7 +1,9 @@ use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; use crate::sys::{cvt, cvt_r}; +use crate::sys_common::IntoInner; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes @@ -24,16 +26,20 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { target_os = "openbsd", target_os = "redox" ))] { - cvt(unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) })?; - Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1])))) + unsafe { + cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?; + Ok((AnonPipe(FileDesc::from_raw_fd(fds[0])), AnonPipe(FileDesc::from_raw_fd(fds[1])))) + } } else { - cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; - - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - fd0.set_cloexec()?; - fd1.set_cloexec()?; - Ok((AnonPipe(fd0), AnonPipe(fd1))) + unsafe { + cvt(libc::pipe(fds.as_mut_ptr()))?; + + let fd0 = FileDesc::from_raw_fd(fds[0]); + let fd1 = FileDesc::from_raw_fd(fds[1]); + fd0.set_cloexec()?; + fd1.set_cloexec()?; + Ok((AnonPipe(fd0), AnonPipe(fd1))) + } } } } @@ -64,11 +70,10 @@ impl AnonPipe { pub fn is_write_vectored(&self) -> bool { self.0.is_write_vectored() } +} - pub fn fd(&self) -> &FileDesc { - &self.0 - } - pub fn into_fd(self) -> FileDesc { +impl IntoInner for AnonPipe { + fn into_inner(self) -> FileDesc { self.0 } } @@ -76,15 +81,15 @@ impl AnonPipe { pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> io::Result<()> { // Set both pipes into nonblocking mode as we're gonna be reading from both // in the `select` loop below, and we wouldn't want one to block the other! - let p1 = p1.into_fd(); - let p2 = p2.into_fd(); + let p1 = p1.into_inner(); + let p2 = p2.into_inner(); p1.set_nonblocking(true)?; p2.set_nonblocking(true)?; let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; - fds[0].fd = p1.raw(); + fds[0].fd = p1.as_raw_fd(); fds[0].events = libc::POLLIN; - fds[1].fd = p2.raw(); + fds[1].fd = p2.as_raw_fd(); fds[1].events = libc::POLLIN; loop { // wait for either pipe to become readable using `poll` @@ -120,3 +125,27 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> } } } + +impl AsRawFd for AnonPipe { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl AsFd for AnonPipe { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl IntoRawFd for AnonPipe { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for AnonPipe { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) + } +} diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index a1972380a9fdb..7b261a302c33f 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -13,6 +13,7 @@ use crate::sys::fd::FileDesc; use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; use crate::sys_common::process::{CommandEnv, CommandEnvs}; +use crate::sys_common::IntoInner; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; @@ -388,17 +389,17 @@ impl Stdio { // stderr. No matter which we dup first, the second will get // overwritten prematurely. Stdio::Fd(ref fd) => { - if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO { + if fd.as_raw_fd() >= 0 && fd.as_raw_fd() <= libc::STDERR_FILENO { Ok((ChildStdio::Owned(fd.duplicate()?), None)) } else { - Ok((ChildStdio::Explicit(fd.raw()), None)) + Ok((ChildStdio::Explicit(fd.as_raw_fd()), None)) } } Stdio::MakePipe => { let (reader, writer) = pipe::anon_pipe()?; let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) }; - Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) + Ok((ChildStdio::Owned(theirs.into_inner()), Some(ours))) } #[cfg(not(target_os = "fuchsia"))] @@ -408,7 +409,7 @@ impl Stdio { opts.write(!readable); let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) }; let fd = File::open_c(&path, &opts)?; - Ok((ChildStdio::Owned(fd.into_fd()), None)) + Ok((ChildStdio::Owned(fd.into_inner()), None)) } #[cfg(target_os = "fuchsia")] @@ -419,13 +420,13 @@ impl Stdio { impl From for Stdio { fn from(pipe: AnonPipe) -> Stdio { - Stdio::Fd(pipe.into_fd()) + Stdio::Fd(pipe.into_inner()) } } impl From for Stdio { fn from(file: File) -> Stdio { - Stdio::Fd(file.into_fd()) + Stdio::Fd(file.into_inner()) } } @@ -434,7 +435,7 @@ impl ChildStdio { match *self { ChildStdio::Inherit => None, ChildStdio::Explicit(fd) => Some(fd), - ChildStdio::Owned(ref fd) => Some(fd.raw()), + ChildStdio::Owned(ref fd) => Some(fd.as_raw_fd()), #[cfg(target_os = "fuchsia")] ChildStdio::Null => None, diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index a05fe8165cff2..b359987595d30 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -1,5 +1,6 @@ use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; +use crate::os::unix::io::{AsFd, BorrowedFd, FromRawFd}; use crate::sys::fd::FileDesc; pub struct Stdin(()); @@ -14,11 +15,11 @@ impl Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read(buf) + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) } } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read_vectored(bufs) + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) } } #[inline] @@ -35,11 +36,13 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write(buf) + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write(buf) } } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write_vectored(bufs) + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write_vectored(bufs) + } } #[inline] @@ -60,11 +63,13 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write(buf) + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write(buf) } } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write_vectored(bufs) + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write_vectored(bufs) + } } #[inline] @@ -86,3 +91,51 @@ pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn panic_output() -> Option { Some(Stderr::new()) } + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for io::Stdin { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl<'a> AsFd for io::StdinLock<'a> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for io::Stdout { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl<'a> AsFd for io::StdoutLock<'a> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for io::Stderr { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl<'a> AsFd for io::StderrLock<'a> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + } +} diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index 1f6ea8d6e8df3..461afd2316f6f 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -6,10 +6,12 @@ use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::net::Shutdown; use crate::os::raw::c_int; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[derive(Debug)] pub struct WasiFd { - fd: c_int, + fd: OwnedFd, } fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { @@ -27,38 +29,24 @@ fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { } impl WasiFd { - pub unsafe fn from_raw(fd: c_int) -> WasiFd { - WasiFd { fd } - } - - pub fn into_raw(self) -> c_int { - let ret = self.fd; - mem::forget(self); - ret - } - - pub fn as_raw(&self) -> c_int { - self.fd - } - pub fn datasync(&self) -> io::Result<()> { - unsafe { wasi::fd_datasync(self.fd as wasi::Fd).map_err(err2io) } + unsafe { wasi::fd_datasync(self.as_raw_fd()).map_err(err2io) } } pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - unsafe { wasi::fd_pread(self.fd as wasi::Fd, iovec(bufs), offset).map_err(err2io) } + unsafe { wasi::fd_pread(self.as_raw_fd(), iovec(bufs), offset).map_err(err2io) } } pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - unsafe { wasi::fd_pwrite(self.fd as wasi::Fd, ciovec(bufs), offset).map_err(err2io) } + unsafe { wasi::fd_pwrite(self.as_raw_fd(), ciovec(bufs), offset).map_err(err2io) } } pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - unsafe { wasi::fd_read(self.fd as wasi::Fd, iovec(bufs)).map_err(err2io) } + unsafe { wasi::fd_read(self.as_raw_fd(), iovec(bufs)).map_err(err2io) } } pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result { - unsafe { wasi::fd_write(self.fd as wasi::Fd, ciovec(bufs)).map_err(err2io) } + unsafe { wasi::fd_write(self.as_raw_fd(), ciovec(bufs)).map_err(err2io) } } pub fn seek(&self, pos: SeekFrom) -> io::Result { @@ -67,37 +55,37 @@ impl WasiFd { SeekFrom::End(pos) => (wasi::WHENCE_END, pos), SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos), }; - unsafe { wasi::fd_seek(self.fd as wasi::Fd, offset, whence).map_err(err2io) } + unsafe { wasi::fd_seek(self.as_raw_fd(), offset, whence).map_err(err2io) } } pub fn tell(&self) -> io::Result { - unsafe { wasi::fd_tell(self.fd as wasi::Fd).map_err(err2io) } + unsafe { wasi::fd_tell(self.as_raw_fd()).map_err(err2io) } } // FIXME: __wasi_fd_fdstat_get pub fn set_flags(&self, flags: wasi::Fdflags) -> io::Result<()> { - unsafe { wasi::fd_fdstat_set_flags(self.fd as wasi::Fd, flags).map_err(err2io) } + unsafe { wasi::fd_fdstat_set_flags(self.as_raw_fd(), flags).map_err(err2io) } } pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> { - unsafe { wasi::fd_fdstat_set_rights(self.fd as wasi::Fd, base, inheriting).map_err(err2io) } + unsafe { wasi::fd_fdstat_set_rights(self.as_raw_fd(), base, inheriting).map_err(err2io) } } pub fn sync(&self) -> io::Result<()> { - unsafe { wasi::fd_sync(self.fd as wasi::Fd).map_err(err2io) } + unsafe { wasi::fd_sync(self.as_raw_fd()).map_err(err2io) } } pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> { - unsafe { wasi::fd_advise(self.fd as wasi::Fd, offset, len, advice).map_err(err2io) } + unsafe { wasi::fd_advise(self.as_raw_fd(), offset, len, advice).map_err(err2io) } } pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - unsafe { wasi::fd_allocate(self.fd as wasi::Fd, offset, len).map_err(err2io) } + unsafe { wasi::fd_allocate(self.as_raw_fd(), offset, len).map_err(err2io) } } pub fn create_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_create_directory(self.fd as wasi::Fd, path).map_err(err2io) } + unsafe { wasi::path_create_directory(self.as_raw_fd(), path).map_err(err2io) } } pub fn link( @@ -108,14 +96,8 @@ impl WasiFd { new_path: &str, ) -> io::Result<()> { unsafe { - wasi::path_link( - self.fd as wasi::Fd, - old_flags, - old_path, - new_fd.fd as wasi::Fd, - new_path, - ) - .map_err(err2io) + wasi::path_link(self.as_raw_fd(), old_flags, old_path, new_fd.as_raw_fd(), new_path) + .map_err(err2io) } } @@ -130,7 +112,7 @@ impl WasiFd { ) -> io::Result { unsafe { wasi::path_open( - self.fd as wasi::Fd, + self.as_raw_fd(), dirflags, path, oflags, @@ -138,34 +120,32 @@ impl WasiFd { fs_rights_inheriting, fs_flags, ) - .map(|fd| WasiFd::from_raw(fd as c_int)) + .map(|fd| WasiFd::from_raw_fd(fd)) .map_err(err2io) } } pub fn readdir(&self, buf: &mut [u8], cookie: wasi::Dircookie) -> io::Result { unsafe { - wasi::fd_readdir(self.fd as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie) - .map_err(err2io) + wasi::fd_readdir(self.as_raw_fd(), buf.as_mut_ptr(), buf.len(), cookie).map_err(err2io) } } pub fn readlink(&self, path: &str, buf: &mut [u8]) -> io::Result { unsafe { - wasi::path_readlink(self.fd as wasi::Fd, path, buf.as_mut_ptr(), buf.len()) - .map_err(err2io) + wasi::path_readlink(self.as_raw_fd(), path, buf.as_mut_ptr(), buf.len()).map_err(err2io) } } pub fn rename(&self, old_path: &str, new_fd: &WasiFd, new_path: &str) -> io::Result<()> { unsafe { - wasi::path_rename(self.fd as wasi::Fd, old_path, new_fd.fd as wasi::Fd, new_path) + wasi::path_rename(self.as_raw_fd(), old_path, new_fd.as_raw_fd(), new_path) .map_err(err2io) } } pub fn filestat_get(&self) -> io::Result { - unsafe { wasi::fd_filestat_get(self.fd as wasi::Fd).map_err(err2io) } + unsafe { wasi::fd_filestat_get(self.as_raw_fd()).map_err(err2io) } } pub fn filestat_set_times( @@ -175,12 +155,12 @@ impl WasiFd { fstflags: wasi::Fstflags, ) -> io::Result<()> { unsafe { - wasi::fd_filestat_set_times(self.fd as wasi::Fd, atim, mtim, fstflags).map_err(err2io) + wasi::fd_filestat_set_times(self.as_raw_fd(), atim, mtim, fstflags).map_err(err2io) } } pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { - unsafe { wasi::fd_filestat_set_size(self.fd as wasi::Fd, size).map_err(err2io) } + unsafe { wasi::fd_filestat_set_size(self.as_raw_fd(), size).map_err(err2io) } } pub fn path_filestat_get( @@ -188,7 +168,7 @@ impl WasiFd { flags: wasi::Lookupflags, path: &str, ) -> io::Result { - unsafe { wasi::path_filestat_get(self.fd as wasi::Fd, flags, path).map_err(err2io) } + unsafe { wasi::path_filestat_get(self.as_raw_fd(), flags, path).map_err(err2io) } } pub fn path_filestat_set_times( @@ -200,21 +180,21 @@ impl WasiFd { fstflags: wasi::Fstflags, ) -> io::Result<()> { unsafe { - wasi::path_filestat_set_times(self.fd as wasi::Fd, flags, path, atim, mtim, fstflags) + wasi::path_filestat_set_times(self.as_raw_fd(), flags, path, atim, mtim, fstflags) .map_err(err2io) } } pub fn symlink(&self, old_path: &str, new_path: &str) -> io::Result<()> { - unsafe { wasi::path_symlink(old_path, self.fd as wasi::Fd, new_path).map_err(err2io) } + unsafe { wasi::path_symlink(old_path, self.as_raw_fd(), new_path).map_err(err2io) } } pub fn unlink_file(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_unlink_file(self.fd as wasi::Fd, path).map_err(err2io) } + unsafe { wasi::path_unlink_file(self.as_raw_fd(), path).map_err(err2io) } } pub fn remove_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_remove_directory(self.fd as wasi::Fd, path).map_err(err2io) } + unsafe { wasi::path_remove_directory(self.as_raw_fd(), path).map_err(err2io) } } pub fn sock_recv( @@ -222,11 +202,11 @@ impl WasiFd { ri_data: &mut [IoSliceMut<'_>], ri_flags: wasi::Riflags, ) -> io::Result<(usize, wasi::Roflags)> { - unsafe { wasi::sock_recv(self.fd as wasi::Fd, iovec(ri_data), ri_flags).map_err(err2io) } + unsafe { wasi::sock_recv(self.as_raw_fd(), iovec(ri_data), ri_flags).map_err(err2io) } } pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::Siflags) -> io::Result { - unsafe { wasi::sock_send(self.fd as wasi::Fd, ciovec(si_data), si_flags).map_err(err2io) } + unsafe { wasi::sock_send(self.as_raw_fd(), ciovec(si_data), si_flags).map_err(err2io) } } pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { @@ -235,14 +215,54 @@ impl WasiFd { Shutdown::Write => wasi::SDFLAGS_WR, Shutdown::Both => wasi::SDFLAGS_WR | wasi::SDFLAGS_RD, }; - unsafe { wasi::sock_shutdown(self.fd as wasi::Fd, how).map_err(err2io) } + unsafe { wasi::sock_shutdown(self.as_raw_fd(), how).map_err(err2io) } + } +} + +impl AsInner for WasiFd { + fn as_inner(&self) -> &OwnedFd { + &self.fd + } +} + +impl AsInnerMut for WasiFd { + fn as_inner_mut(&mut self) -> &mut OwnedFd { + &mut self.fd + } +} + +impl IntoInner for WasiFd { + fn into_inner(self) -> OwnedFd { + self.fd + } +} + +impl FromInner for WasiFd { + fn from_inner(owned_fd: OwnedFd) -> Self { + Self { fd: owned_fd } + } +} + +impl AsFd for WasiFd { + fn as_fd(&self) -> BorrowedFd<'_> { + self.fd.as_fd() + } +} + +impl AsRawFd for WasiFd { + fn as_raw_fd(&self) -> RawFd { + self.fd.as_raw_fd() + } +} + +impl IntoRawFd for WasiFd { + fn into_raw_fd(self) -> RawFd { + self.fd.into_raw_fd() } } -impl Drop for WasiFd { - fn drop(&mut self) { - // FIXME: can we handle the return code here even though we can't on - // unix? - let _ = unsafe { wasi::fd_close(self.fd as wasi::Fd) }; +impl FromRawFd for WasiFd { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } } } } diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 55c9c652a8bbb..984dda8dc0b4e 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -8,12 +8,13 @@ use crate::iter; use crate::mem::{self, ManuallyDrop}; use crate::os::raw::c_int; use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sync::Arc; use crate::sys::time::SystemTime; use crate::sys::unsupported; -use crate::sys_common::FromInner; +use crate::sys_common::{AsInner, FromInner, IntoInner}; pub use crate::sys_common::fs::{remove_dir_all, try_exists}; @@ -442,22 +443,50 @@ impl File { unsupported() } - pub fn fd(&self) -> &WasiFd { + pub fn read_link(&self, file: &Path) -> io::Result { + read_link(&self.fd, file) + } +} + +impl AsInner for File { + fn as_inner(&self) -> &WasiFd { &self.fd } +} - pub fn into_fd(self) -> WasiFd { +impl IntoInner for File { + fn into_inner(self) -> WasiFd { self.fd } +} - pub fn read_link(&self, file: &Path) -> io::Result { - read_link(&self.fd, file) +impl FromInner for File { + fn from_inner(fd: WasiFd) -> File { + File { fd } + } +} + +impl AsFd for File { + fn as_fd(&self) -> BorrowedFd<'_> { + self.fd.as_fd() + } +} + +impl AsRawFd for File { + fn as_raw_fd(&self) -> RawFd { + self.fd.as_raw_fd() + } +} + +impl IntoRawFd for File { + fn into_raw_fd(self) -> RawFd { + self.fd.into_raw_fd() } } -impl FromInner for File { - fn from_inner(fd: c_int) -> File { - unsafe { File { fd: WasiFd::from_raw(fd) } } +impl FromRawFd for File { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } } } } @@ -474,7 +503,7 @@ impl DirBuilder { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("File").field("fd", &self.fd.as_raw()).finish() + f.debug_struct("File").field("fd", &self.as_raw_fd()).finish() } } @@ -654,7 +683,7 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop, PathBuf)> { let relative = CStr::from_ptr(relative_path).to_bytes().to_vec(); return Ok(( - ManuallyDrop::new(WasiFd::from_raw(fd as c_int)), + ManuallyDrop::new(WasiFd::from_raw_fd(fd as c_int)), PathBuf::from(OsString::from_vec(relative)), )); } diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index 50b7352933e57..1bd33f1e50e32 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -6,12 +6,57 @@ use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::os::raw::c_int; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::unsupported; -use crate::sys_common::FromInner; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; +pub struct Socket(WasiFd); + pub struct TcpStream { - fd: WasiFd, + inner: Socket, +} + +impl AsInner for Socket { + fn as_inner(&self) -> &WasiFd { + &self.0 + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> WasiFd { + self.0 + } +} + +impl FromInner for Socket { + fn from_inner(inner: WasiFd) -> Socket { + Socket(inner) + } +} + +impl AsFd for Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for Socket { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for Socket { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for Socket { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) } + } } impl TcpStream { @@ -107,29 +152,29 @@ impl TcpStream { unsupported() } - pub fn fd(&self) -> &WasiFd { - &self.fd + pub fn socket(&self) -> &Socket { + &self.inner } - pub fn into_fd(self) -> WasiFd { - self.fd + pub fn into_socket(self) -> Socket { + self.inner } } -impl FromInner for TcpStream { - fn from_inner(fd: c_int) -> TcpStream { - unsafe { TcpStream { fd: WasiFd::from_raw(fd) } } +impl FromInner for TcpStream { + fn from_inner(socket: Socket) -> TcpStream { + TcpStream { inner: socket } } } impl fmt::Debug for TcpStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TcpStream").field("fd", &self.fd.as_raw()).finish() + f.debug_struct("TcpStream").field("fd", &self.inner.as_raw_fd()).finish() } } pub struct TcpListener { - fd: WasiFd, + inner: Socket, } impl TcpListener { @@ -173,29 +218,41 @@ impl TcpListener { unsupported() } - pub fn fd(&self) -> &WasiFd { - &self.fd + pub fn socket(&self) -> &Socket { + &self.inner } - pub fn into_fd(self) -> WasiFd { - self.fd + pub fn into_socket(self) -> Socket { + self.inner } } -impl FromInner for TcpListener { - fn from_inner(fd: c_int) -> TcpListener { - unsafe { TcpListener { fd: WasiFd::from_raw(fd) } } +impl AsInner for TcpListener { + fn as_inner(&self) -> &Socket { + &self.inner + } +} + +impl IntoInner for TcpListener { + fn into_inner(self) -> Socket { + self.inner + } +} + +impl FromInner for TcpListener { + fn from_inner(inner: Socket) -> TcpListener { + TcpListener { inner } } } impl fmt::Debug for TcpListener { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TcpListener").field("fd", &self.fd.as_raw()).finish() + f.debug_struct("TcpListener").field("fd", &self.inner.as_raw_fd()).finish() } } pub struct UdpSocket { - fd: WasiFd, + inner: Socket, } impl UdpSocket { @@ -323,24 +380,36 @@ impl UdpSocket { unsupported() } - pub fn fd(&self) -> &WasiFd { - &self.fd + pub fn socket(&self) -> &Socket { + &self.inner + } + + pub fn into_socket(self) -> Socket { + self.inner } +} + +impl AsInner for UdpSocket { + fn as_inner(&self) -> &Socket { + &self.inner + } +} - pub fn into_fd(self) -> WasiFd { - self.fd +impl IntoInner for UdpSocket { + fn into_inner(self) -> Socket { + self.inner } } -impl FromInner for UdpSocket { - fn from_inner(fd: c_int) -> UdpSocket { - unsafe { UdpSocket { fd: WasiFd::from_raw(fd) } } +impl FromInner for UdpSocket { + fn from_inner(inner: Socket) -> UdpSocket { + UdpSocket { inner } } } impl fmt::Debug for UdpSocket { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("UdpSocket").field("fd", &self.fd.as_raw()).finish() + f.debug_struct("UdpSocket").field("fd", &self.inner.as_raw_fd()).finish() } } diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 8782f333a1fa4..2c8f394cd47b0 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -4,6 +4,7 @@ use super::fd::WasiFd; use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::os::raw; +use crate::os::wasi::io::{AsRawFd, FromRawFd}; pub struct Stdin; pub struct Stdout; @@ -13,9 +14,11 @@ impl Stdin { pub const fn new() -> Stdin { Stdin } +} +impl AsRawFd for Stdin { #[inline] - pub fn as_raw_fd(&self) -> raw::c_int { + fn as_raw_fd(&self) -> raw::c_int { 0 } } @@ -26,7 +29,7 @@ impl io::Read for Stdin { } fn read_vectored(&mut self, data: &mut [IoSliceMut<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data) + ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).read(data) } #[inline] @@ -39,9 +42,11 @@ impl Stdout { pub const fn new() -> Stdout { Stdout } +} +impl AsRawFd for Stdout { #[inline] - pub fn as_raw_fd(&self) -> raw::c_int { + fn as_raw_fd(&self) -> raw::c_int { 1 } } @@ -52,7 +57,7 @@ impl io::Write for Stdout { } fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) + ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).write(data) } #[inline] @@ -68,9 +73,11 @@ impl Stderr { pub const fn new() -> Stderr { Stderr } +} +impl AsRawFd for Stderr { #[inline] - pub fn as_raw_fd(&self) -> raw::c_int { + fn as_raw_fd(&self) -> raw::c_int { 2 } } @@ -81,7 +88,7 @@ impl io::Write for Stderr { } fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) + ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).write(data) } #[inline] diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index c677adae6888e..0c1a50e231cd4 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -4,6 +4,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; +use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::slice; @@ -11,7 +12,7 @@ use crate::sync::Arc; use crate::sys::handle::Handle; use crate::sys::time::SystemTime; use crate::sys::{c, cvt}; -use crate::sys_common::FromInner; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use super::to_u16s; @@ -295,12 +296,12 @@ impl File { if handle == c::INVALID_HANDLE_VALUE { Err(Error::last_os_error()) } else { - Ok(File { handle: Handle::new(handle) }) + unsafe { Ok(File { handle: Handle::from_raw_handle(handle) }) } } } pub fn fsync(&self) -> io::Result<()> { - cvt(unsafe { c::FlushFileBuffers(self.handle.raw()) })?; + cvt(unsafe { c::FlushFileBuffers(self.handle.as_raw_handle()) })?; Ok(()) } @@ -313,7 +314,7 @@ impl File { let size = mem::size_of_val(&info); cvt(unsafe { c::SetFileInformationByHandle( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileEndOfFileInfo, &mut info as *mut _ as *mut _, size as c::DWORD, @@ -326,7 +327,7 @@ impl File { pub fn file_attr(&self) -> io::Result { unsafe { let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed(); - cvt(c::GetFileInformationByHandle(self.handle.raw(), &mut info))?; + cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?; let mut reparse_tag = 0; if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; @@ -449,7 +450,7 @@ impl File { }; let pos = pos as c::LARGE_INTEGER; let mut newpos = 0; - cvt(unsafe { c::SetFilePointerEx(self.handle.raw(), pos, &mut newpos, whence) })?; + cvt(unsafe { c::SetFilePointerEx(self.handle.as_raw_handle(), pos, &mut newpos, whence) })?; Ok(newpos as u64) } @@ -457,14 +458,6 @@ impl File { Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? }) } - pub fn handle(&self) -> &Handle { - &self.handle - } - - pub fn into_handle(self) -> Handle { - self.handle - } - fn reparse_point<'a>( &self, space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE], @@ -473,7 +466,7 @@ impl File { let mut bytes = 0; cvt({ c::DeviceIoControl( - self.handle.raw(), + self.handle.as_raw_handle(), c::FSCTL_GET_REPARSE_POINT, ptr::null_mut(), 0, @@ -541,7 +534,7 @@ impl File { let size = mem::size_of_val(&info); cvt(unsafe { c::SetFileInformationByHandle( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileBasicInfo, &mut info as *mut _ as *mut _, size as c::DWORD, @@ -551,9 +544,45 @@ impl File { } } -impl FromInner for File { - fn from_inner(handle: c::HANDLE) -> File { - File { handle: Handle::new(handle) } +impl AsInner for File { + fn as_inner(&self) -> &Handle { + &self.handle + } +} + +impl IntoInner for File { + fn into_inner(self) -> Handle { + self.handle + } +} + +impl FromInner for File { + fn from_inner(handle: Handle) -> File { + File { handle: handle } + } +} + +impl AsHandle for File { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().as_handle() + } +} + +impl AsRawHandle for File { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().as_raw_handle() + } +} + +impl IntoRawHandle for File { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_raw_handle() + } +} + +impl FromRawHandle for File { + unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { + Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } } } @@ -561,7 +590,7 @@ impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME(#24570): add more info here (e.g., mode) let mut b = f.debug_struct("File"); - b.field("handle", &self.handle.raw()); + b.field("handle", &self.handle.as_raw_handle()); if let Ok(path) = get_path(&self) { b.field("path", &path); } @@ -838,7 +867,7 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { fn get_path(f: &File) -> io::Result { super::fill_utf16_buf( |buf, sz| unsafe { - c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, c::VOLUME_NAME_DOS) + c::GetFinalPathNameByHandleW(f.handle.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS) }, |buf| PathBuf::from(OsString::from_wide(buf)), ) @@ -909,7 +938,7 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> { opts.write(true); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); let f = File::open(junction, &opts)?; - let h = f.handle().raw(); + let h = f.as_inner().as_raw_handle(); unsafe { let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 0d4baa3b340df..21d86b002264a 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -3,76 +3,87 @@ use crate::cmp; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read}; use crate::mem; -use crate::ops::Deref; +use crate::os::windows::io::{ + AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, +}; use crate::ptr; use crate::sys::c; use crate::sys::cvt; +use crate::sys_common::{AsInner, FromInner, IntoInner}; /// An owned container for `HANDLE` object, closing them on Drop. /// /// All methods are inherited through a `Deref` impl to `RawHandle` -pub struct Handle(RawHandle); - -/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference -/// as well as Rust-y methods. -/// -/// This does **not** drop the handle when it goes out of scope, use `Handle` -/// instead for that. -#[derive(Copy, Clone)] -pub struct RawHandle(c::HANDLE); - -unsafe impl Send for RawHandle {} -unsafe impl Sync for RawHandle {} +pub struct Handle(OwnedHandle); impl Handle { - pub fn new(handle: c::HANDLE) -> Handle { - Handle(RawHandle::new(handle)) - } - pub fn new_event(manual: bool, init: bool) -> io::Result { unsafe { let event = c::CreateEventW(ptr::null_mut(), manual as c::BOOL, init as c::BOOL, ptr::null()); - if event.is_null() { Err(io::Error::last_os_error()) } else { Ok(Handle::new(event)) } + if event.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(Handle::from_raw_handle(event)) + } } } +} - pub fn into_raw(self) -> c::HANDLE { - let ret = self.raw(); - mem::forget(self); - ret +impl AsInner for Handle { + fn as_inner(&self) -> &OwnedHandle { + &self.0 } } -impl Deref for Handle { - type Target = RawHandle; - fn deref(&self) -> &RawHandle { - &self.0 +impl IntoInner for Handle { + fn into_inner(self) -> OwnedHandle { + self.0 } } -impl Drop for Handle { - fn drop(&mut self) { - unsafe { - let _ = c::CloseHandle(self.raw()); - } +impl FromInner for Handle { + fn from_inner(file_desc: OwnedHandle) -> Self { + Self(file_desc) } } -impl RawHandle { - pub fn new(handle: c::HANDLE) -> RawHandle { - RawHandle(handle) +impl AsHandle for Handle { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.0.as_handle() } +} - pub fn raw(&self) -> c::HANDLE { - self.0 +impl AsRawHandle for Handle { + fn as_raw_handle(&self) -> RawHandle { + self.0.as_raw_handle() } +} +impl IntoRawHandle for Handle { + fn into_raw_handle(self) -> RawHandle { + self.0.into_raw_handle() + } +} + +impl FromRawHandle for Handle { + unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { + Self(FromRawHandle::from_raw_handle(raw_handle)) + } +} + +impl Handle { pub fn read(&self, buf: &mut [u8]) -> io::Result { let mut read = 0; let len = cmp::min(buf.len(), ::MAX as usize) as c::DWORD; let res = cvt(unsafe { - c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, ptr::null_mut()) + c::ReadFile( + self.as_raw_handle(), + buf.as_mut_ptr() as c::LPVOID, + len, + &mut read, + ptr::null_mut(), + ) }); match res { @@ -104,7 +115,13 @@ impl RawHandle { let mut overlapped: c::OVERLAPPED = mem::zeroed(); overlapped.Offset = offset as u32; overlapped.OffsetHigh = (offset >> 32) as u32; - cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, &mut overlapped)) + cvt(c::ReadFile( + self.as_raw_handle(), + buf.as_mut_ptr() as c::LPVOID, + len, + &mut read, + &mut overlapped, + )) }; match res { Ok(_) => Ok(read as usize), @@ -120,7 +137,13 @@ impl RawHandle { ) -> io::Result> { let len = cmp::min(buf.len(), ::MAX as usize) as c::DWORD; let mut amt = 0; - let res = cvt(c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, overlapped)); + let res = cvt(c::ReadFile( + self.as_raw_handle(), + buf.as_ptr() as c::LPVOID, + len, + &mut amt, + overlapped, + )); match res { Ok(_) => Ok(Some(amt as usize)), Err(e) => { @@ -143,7 +166,8 @@ impl RawHandle { unsafe { let mut bytes = 0; let wait = if wait { c::TRUE } else { c::FALSE }; - let res = cvt(c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait)); + let res = + cvt(c::GetOverlappedResult(self.as_raw_handle(), overlapped, &mut bytes, wait)); match res { Ok(_) => Ok(bytes as usize), Err(e) => { @@ -160,14 +184,20 @@ impl RawHandle { } pub fn cancel_io(&self) -> io::Result<()> { - unsafe { cvt(c::CancelIo(self.raw())).map(drop) } + unsafe { cvt(c::CancelIo(self.as_raw_handle())).map(drop) } } pub fn write(&self, buf: &[u8]) -> io::Result { let mut amt = 0; let len = cmp::min(buf.len(), ::MAX as usize) as c::DWORD; cvt(unsafe { - c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, ptr::null_mut()) + c::WriteFile( + self.as_raw_handle(), + buf.as_ptr() as c::LPVOID, + len, + &mut amt, + ptr::null_mut(), + ) })?; Ok(amt as usize) } @@ -189,7 +219,7 @@ impl RawHandle { overlapped.Offset = offset as u32; overlapped.OffsetHigh = (offset >> 32) as u32; cvt(c::WriteFile( - self.0, + self.as_raw_handle(), buf.as_ptr() as c::LPVOID, len, &mut written, @@ -210,7 +240,7 @@ impl RawHandle { let cur_proc = c::GetCurrentProcess(); c::DuplicateHandle( cur_proc, - self.0, + self.as_raw_handle(), cur_proc, &mut ret, access, @@ -218,11 +248,11 @@ impl RawHandle { options, ) })?; - Ok(Handle::new(ret)) + unsafe { Ok(Handle::from_raw_handle(ret)) } } } -impl<'a> Read for &'a RawHandle { +impl<'a> Read for &'a Handle { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 9cea5c5e63a2d..55aacb38c6f78 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -4,6 +4,9 @@ use crate::cmp; use crate::io::{self, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; +use crate::os::windows::io::{ + AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, +}; use crate::ptr; use crate::sync::Once; use crate::sys; @@ -24,7 +27,7 @@ pub mod netc { pub use crate::sys::c::*; } -pub struct Socket(c::SOCKET); +pub struct Socket(OwnedSocket); static INIT: Once = Once::new(); @@ -109,7 +112,7 @@ impl Socket { }; if socket != c::INVALID_SOCKET { - Ok(Self(socket)) + unsafe { Ok(Self::from_raw_socket(socket)) } } else { let error = unsafe { c::WSAGetLastError() }; @@ -124,9 +127,11 @@ impl Socket { return Err(last_error()); } - let socket = Self(socket); - socket.set_no_inherit()?; - Ok(socket) + unsafe { + let socket = Self::from_raw_socket(socket); + socket.set_no_inherit()?; + Ok(socket) + } } } @@ -134,7 +139,7 @@ impl Socket { self.set_nonblocking(true)?; let result = { let (addrp, len) = addr.into_inner(); - let result = unsafe { c::connect(self.0, addrp, len) }; + let result = unsafe { c::connect(self.as_raw_socket(), addrp, len) }; cvt(result).map(drop) }; self.set_nonblocking(false)?; @@ -160,7 +165,7 @@ impl Socket { let fds = { let mut fds = unsafe { mem::zeroed::() }; fds.fd_count = 1; - fds.fd_array[0] = self.0; + fds.fd_array[0] = self.as_raw_socket(); fds }; @@ -194,17 +199,19 @@ impl Socket { } pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result { - let socket = unsafe { c::accept(self.0, storage, len) }; + let socket = unsafe { c::accept(self.as_raw_socket(), storage, len) }; match socket { c::INVALID_SOCKET => Err(last_error()), - _ => Ok(Self(socket)), + _ => unsafe { Ok(Self::from_raw_socket(socket)) }, } } pub fn duplicate(&self) -> io::Result { let mut info = unsafe { mem::zeroed::() }; - let result = unsafe { c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info) }; + let result = unsafe { + c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) + }; cvt(result)?; let socket = unsafe { c::WSASocketW( @@ -218,7 +225,7 @@ impl Socket { }; if socket != c::INVALID_SOCKET { - Ok(Self(socket)) + unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } } else { let error = unsafe { c::WSAGetLastError() }; @@ -241,9 +248,11 @@ impl Socket { return Err(last_error()); } - let socket = Self(socket); - socket.set_no_inherit()?; - Ok(socket) + unsafe { + let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); + socket.set_no_inherit()?; + Ok(socket) + } } } @@ -251,7 +260,8 @@ impl Socket { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. let length = cmp::min(buf.len(), i32::MAX as usize) as i32; - let result = unsafe { c::recv(self.0, buf.as_mut_ptr() as *mut _, length, flags) }; + let result = + unsafe { c::recv(self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags) }; match result { c::SOCKET_ERROR => { @@ -279,7 +289,7 @@ impl Socket { let mut flags = 0; let result = unsafe { c::WSARecv( - self.0, + self.as_raw_socket(), bufs.as_mut_ptr() as *mut c::WSABUF, length, &mut nread, @@ -325,7 +335,7 @@ impl Socket { // do the same on windows to map a shut down socket to returning EOF. let result = unsafe { c::recvfrom( - self.0, + self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags, @@ -361,7 +371,7 @@ impl Socket { let mut nwritten = 0; let result = unsafe { c::WSASend( - self.0, + self.as_raw_socket(), bufs.as_ptr() as *const c::WSABUF as *mut _, length, &mut nwritten, @@ -408,8 +418,10 @@ impl Socket { #[cfg(not(target_vendor = "uwp"))] fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { c::SetHandleInformation(self.0 as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) }) - .map(drop) + sys::cvt(unsafe { + c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) + }) + .map(drop) } #[cfg(target_vendor = "uwp")] @@ -423,13 +435,14 @@ impl Socket { Shutdown::Read => c::SD_RECEIVE, Shutdown::Both => c::SD_BOTH, }; - let result = unsafe { c::shutdown(self.0, how) }; + let result = unsafe { c::shutdown(self.as_raw_socket(), how) }; cvt(result).map(drop) } pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as c_ulong; - let result = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) }; + let result = + unsafe { c::ioctlsocket(self.as_raw_socket(), c::FIONBIO as c_int, &mut nonblocking) }; cvt(result).map(drop) } @@ -446,6 +459,11 @@ impl Socket { let raw: c_int = net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } + + // This is used by sys_common code to abstract over Windows and Unix. + pub fn as_raw(&self) -> RawSocket { + self.as_inner().as_raw_socket() + } } #[unstable(reason = "not public", issue = "none", feature = "fd_read")] @@ -455,28 +473,44 @@ impl<'a> Read for &'a Socket { } } -impl Drop for Socket { - fn drop(&mut self) { - let _ = unsafe { c::closesocket(self.0) }; +impl AsInner for Socket { + fn as_inner(&self) -> &OwnedSocket { + &self.0 } } -impl AsInner for Socket { - fn as_inner(&self) -> &c::SOCKET { - &self.0 +impl FromInner for Socket { + fn from_inner(sock: OwnedSocket) -> Socket { + Socket(sock) } } -impl FromInner for Socket { - fn from_inner(sock: c::SOCKET) -> Socket { - Socket(sock) +impl IntoInner for Socket { + fn into_inner(self) -> OwnedSocket { + self.0 + } +} + +impl AsSocket for Socket { + fn as_socket(&self) -> BorrowedSocket<'_> { + self.0.as_socket() + } +} + +impl AsRawSocket for Socket { + fn as_raw_socket(&self) -> RawSocket { + self.0.as_raw_socket() + } +} + +impl IntoRawSocket for Socket { + fn into_raw_socket(self) -> RawSocket { + self.0.into_raw_socket() } } -impl IntoInner for Socket { - fn into_inner(self) -> c::SOCKET { - let ret = self.0; - mem::forget(self); - ret +impl FromRawSocket for Socket { + unsafe fn from_raw_socket(raw_socket: RawSocket) -> Self { + Self(FromRawSocket::from_raw_socket(raw_socket)) } } diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index 8db97ba50a81f..883690c483167 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -288,7 +288,7 @@ fn home_dir_crt() -> Option { if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 { return None; } - let _handle = Handle::new(token); + let _handle = Handle::from_raw_handle(token); super::fill_utf16_buf( |buf, mut sz| { match c::GetUserProfileDirectoryW(token, buf, &mut sz) { diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs index 104a8db46596e..63d3d6c5ed42f 100644 --- a/library/std/src/sys/windows/pipe.rs +++ b/library/std/src/sys/windows/pipe.rs @@ -12,6 +12,7 @@ use crate::sys::c; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; use crate::sys::hashmap_random_keys; +use crate::sys_common::IntoInner; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes @@ -21,6 +22,12 @@ pub struct AnonPipe { inner: Handle, } +impl IntoInner for AnonPipe { + fn into_inner(self) -> Handle { + self.inner + } +} + pub struct Pipes { pub ours: AnonPipe, pub theirs: AnonPipe, @@ -123,7 +130,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res } return Err(err); } - ours = Handle::new(handle); + ours = Handle::from_raw_handle(handle); break; } @@ -146,11 +153,11 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res }; opts.security_attributes(&mut sa); let theirs = File::open(Path::new(&name), &opts)?; - let theirs = AnonPipe { inner: theirs.into_handle() }; + let theirs = AnonPipe { inner: theirs.into_inner() }; Ok(Pipes { ours: AnonPipe { inner: ours }, - theirs: AnonPipe { inner: theirs.into_handle() }, + theirs: AnonPipe { inner: theirs.into_inner() }, }) } } @@ -207,7 +214,7 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> let mut p1 = AsyncPipe::new(p1, v1)?; let mut p2 = AsyncPipe::new(p2, v2)?; - let objs = [p1.event.raw(), p2.event.raw()]; + let objs = [p1.event.as_raw_handle(), p2.event.as_raw_handle()]; // In a loop we wait for either pipe's scheduled read operation to complete. // If the operation completes with 0 bytes, that means EOF was reached, in @@ -262,7 +269,7 @@ impl<'a> AsyncPipe<'a> { // I/O operation is successfully scheduled (what we want). let event = Handle::new_event(true, true)?; let mut overlapped: Box = unsafe { Box::new(mem::zeroed()) }; - overlapped.hEvent = event.raw(); + overlapped.hEvent = event.as_raw_handle(); Ok(AsyncPipe { pipe, overlapped, event, dst, state: State::NotReading }) } diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index ae193b82e91bb..5cfde16faf0b1 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -15,6 +15,7 @@ use crate::io::{self, Error, ErrorKind}; use crate::mem; use crate::num::NonZeroI32; use crate::os::windows::ffi::OsStrExt; +use crate::os::windows::io::{AsRawHandle, FromRawHandle}; use crate::path::Path; use crate::ptr; use crate::sys::c; @@ -26,7 +27,7 @@ use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; use crate::sys_common::mutex::StaticMutex; use crate::sys_common::process::{CommandEnv, CommandEnvs}; -use crate::sys_common::AsInner; +use crate::sys_common::{AsInner, IntoInner}; use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; @@ -316,9 +317,9 @@ impl Command { let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?; let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?; let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?; - si.hStdInput = stdin.raw(); - si.hStdOutput = stdout.raw(); - si.hStdError = stderr.raw(); + si.hStdInput = stdin.as_raw_handle(); + si.hStdOutput = stdout.as_raw_handle(); + si.hStdError = stderr.as_raw_handle(); unsafe { cvt(c::CreateProcessW( @@ -338,9 +339,11 @@ impl Command { // We close the thread handle because we don't care about keeping // the thread id valid, and we aren't keeping the thread handle // around to be able to close it later. - drop(Handle::new(pi.hThread)); + unsafe { + drop(Handle::from_raw_handle(pi.hThread)); - Ok((Process { handle: Handle::new(pi.hProcess) }, pipes)) + Ok((Process { handle: Handle::from_raw_handle(pi.hProcess) }, pipes)) + } } } @@ -365,13 +368,13 @@ impl Stdio { // should still be unavailable so propagate the // INVALID_HANDLE_VALUE. Stdio::Inherit => match stdio::get_handle(stdio_id) { - Ok(io) => { - let io = Handle::new(io); + Ok(io) => unsafe { + let io = Handle::from_raw_handle(io); let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS); - io.into_raw(); + io.into_inner(); ret - } - Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), + }, + Err(..) => unsafe { Ok(Handle::from_raw_handle(c::INVALID_HANDLE_VALUE)) }, }, Stdio::MakePipe => { @@ -397,7 +400,7 @@ impl Stdio { opts.read(stdio_id == c::STD_INPUT_HANDLE); opts.write(stdio_id != c::STD_INPUT_HANDLE); opts.security_attributes(&mut sa); - File::open(Path::new("NUL"), &opts).map(|file| file.into_handle()) + File::open(Path::new("NUL"), &opts).map(|file| file.into_inner()) } } } @@ -411,7 +414,7 @@ impl From for Stdio { impl From for Stdio { fn from(file: File) -> Stdio { - Stdio::Handle(file.into_handle()) + Stdio::Handle(file.into_inner()) } } @@ -430,29 +433,29 @@ pub struct Process { impl Process { pub fn kill(&mut self) -> io::Result<()> { - cvt(unsafe { c::TerminateProcess(self.handle.raw(), 1) })?; + cvt(unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) })?; Ok(()) } pub fn id(&self) -> u32 { - unsafe { c::GetProcessId(self.handle.raw()) as u32 } + unsafe { c::GetProcessId(self.handle.as_raw_handle()) as u32 } } pub fn wait(&mut self) -> io::Result { unsafe { - let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE); + let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE); if res != c::WAIT_OBJECT_0 { return Err(Error::last_os_error()); } let mut status = 0; - cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; + cvt(c::GetExitCodeProcess(self.handle.as_raw_handle(), &mut status))?; Ok(ExitStatus(status)) } } pub fn try_wait(&mut self) -> io::Result> { unsafe { - match c::WaitForSingleObject(self.handle.raw(), 0) { + match c::WaitForSingleObject(self.handle.as_raw_handle(), 0) { c::WAIT_OBJECT_0 => {} c::WAIT_TIMEOUT => { return Ok(None); @@ -460,7 +463,7 @@ impl Process { _ => return Err(io::Error::last_os_error()), } let mut status = 0; - cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; + cvt(c::GetExitCodeProcess(self.handle.as_raw_handle(), &mut status))?; Ok(Some(ExitStatus(status))) } } diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index 2973951fe9004..1cf0e9f0cf1ea 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -3,6 +3,7 @@ use crate::char::decode_utf16; use crate::cmp; use crate::io; +use crate::os::windows::io::{FromRawHandle, IntoRawHandle}; use crate::ptr; use crate::str; use crate::sys::c; @@ -53,10 +54,12 @@ fn is_console(handle: c::HANDLE) -> bool { fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result { let handle = get_handle(handle_id)?; if !is_console(handle) { - let handle = Handle::new(handle); - let ret = handle.write(data); - handle.into_raw(); // Don't close the handle - return ret; + unsafe { + let handle = Handle::from_raw_handle(handle); + let ret = handle.write(data); + handle.into_raw_handle(); // Don't close the handle + return ret; + } } // As the console is meant for presenting text, we assume bytes of `data` come from a string @@ -140,10 +143,12 @@ impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { let handle = get_handle(c::STD_INPUT_HANDLE)?; if !is_console(handle) { - let handle = Handle::new(handle); - let ret = handle.read(buf); - handle.into_raw(); // Don't close the handle - return ret; + unsafe { + let handle = Handle::from_raw_handle(handle); + let ret = handle.read(buf); + handle.into_raw_handle(); // Don't close the handle + return ret; + } } if buf.len() == 0 { diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs index ef7a9733fd880..a5293133b3ab0 100644 --- a/library/std/src/sys/windows/thread.rs +++ b/library/std/src/sys/windows/thread.rs @@ -1,6 +1,7 @@ use crate::ffi::CStr; use crate::io; use crate::num::NonZeroUsize; +use crate::os::windows::io::{AsRawHandle, FromRawHandle}; use crate::ptr; use crate::sys::c; use crate::sys::handle::Handle; @@ -45,7 +46,7 @@ impl Thread { drop(Box::from_raw(p)); Err(io::Error::last_os_error()) } else { - Ok(Thread { handle: Handle::new(ret) }) + Ok(Thread { handle: Handle::from_raw_handle(ret) }) }; extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { @@ -71,7 +72,7 @@ impl Thread { } pub fn join(self) { - let rc = unsafe { c::WaitForSingleObject(self.handle.raw(), c::INFINITE) }; + let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; if rc == c::WAIT_FAILED { panic!("failed to join on thread: {}", io::Error::last_os_error()); } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index d5f29c4a43970..0ffa5c01dd33b 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -61,13 +61,7 @@ cfg_if::cfg_if! { pub fn setsockopt(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> { unsafe { let payload = &payload as *const T as *const c_void; - cvt(c::setsockopt( - *sock.as_inner(), - opt, - val, - payload, - mem::size_of::() as c::socklen_t, - ))?; + cvt(c::setsockopt(sock.as_raw(), opt, val, payload, mem::size_of::() as c::socklen_t))?; Ok(()) } } @@ -76,7 +70,7 @@ pub fn getsockopt(sock: &Socket, opt: c_int, val: c_int) -> io::Result< unsafe { let mut slot: T = mem::zeroed(); let mut len = mem::size_of::() as c::socklen_t; - cvt(c::getsockopt(*sock.as_inner(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?; + cvt(c::getsockopt(sock.as_raw(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?; assert_eq!(len as usize, mem::size_of::()); Ok(slot) } @@ -217,7 +211,7 @@ impl TcpStream { let sock = Socket::new(addr, c::SOCK_STREAM)?; let (addrp, len) = addr.into_inner(); - cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?; + cvt_r(|| unsafe { c::connect(sock.as_raw(), addrp, len) })?; Ok(TcpStream { inner: sock }) } @@ -273,7 +267,7 @@ impl TcpStream { pub fn write(&self, buf: &[u8]) -> io::Result { let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; let ret = cvt(unsafe { - c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) + c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) })?; Ok(ret as usize) } @@ -288,11 +282,11 @@ impl TcpStream { } pub fn peer_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) } pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { @@ -348,7 +342,7 @@ impl fmt::Debug for TcpStream { } let name = if cfg!(windows) { "socket" } else { "fd" }; - res.field(name, &self.inner.as_inner()).finish() + res.field(name, &self.inner.as_raw()).finish() } } @@ -380,10 +374,10 @@ impl TcpListener { // Bind our new socket let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; + cvt(unsafe { c::bind(sock.as_raw(), addrp, len as _) })?; // Start listening - cvt(unsafe { c::listen(*sock.as_inner(), 128) })?; + cvt(unsafe { c::listen(sock.as_raw(), 128) })?; Ok(TcpListener { inner: sock }) } @@ -396,7 +390,7 @@ impl TcpListener { } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { @@ -453,7 +447,7 @@ impl fmt::Debug for TcpListener { } let name = if cfg!(windows) { "socket" } else { "fd" }; - res.field(name, &self.inner.as_inner()).finish() + res.field(name, &self.inner.as_raw()).finish() } } @@ -473,7 +467,7 @@ impl UdpSocket { let sock = Socket::new(addr, c::SOCK_DGRAM)?; let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; + cvt(unsafe { c::bind(sock.as_raw(), addrp, len as _) })?; Ok(UdpSocket { inner: sock }) } @@ -486,11 +480,11 @@ impl UdpSocket { } pub fn peer_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { @@ -506,7 +500,7 @@ impl UdpSocket { let (dstp, dstlen) = dst.into_inner(); let ret = cvt(unsafe { c::sendto( - *self.inner.as_inner(), + self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL, @@ -643,14 +637,14 @@ impl UdpSocket { pub fn send(&self, buf: &[u8]) -> io::Result { let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; let ret = cvt(unsafe { - c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) + c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) })?; Ok(ret as usize) } pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> { let (addrp, len) = addr?.into_inner(); - cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(drop) + cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addrp, len) }).map(drop) } } @@ -669,6 +663,6 @@ impl fmt::Debug for UdpSocket { } let name = if cfg!(windows) { "socket" } else { "fd" }; - res.field(name, &self.inner.as_inner()).finish() + res.field(name, &self.inner.as_raw()).finish() } }