Auto merge of #87329 - sunfishcode:sunfishcode/io-safety, r=joshtriplett

I/O safety.

Introduce `OwnedFd` and `BorrowedFd`, and the `AsFd` trait, and
implementations of `AsFd`, `From<OwnedFd>` and `From<T> for OwnedFd`
for relevant types, along with Windows counterparts for handles and
sockets.

Tracking issue: <https://github.com/rust-lang/rust/issues/87074>

RFC: <https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md>

Highlights:
 - The doc comments at the top of library/std/src/os/unix/io/mod.rs and library/std/src/os/windows/io/mod.rs
 - The new types and traits in library/std/src/os/unix/io/fd.rs and library/std/src/os/windows/io/handle.rs
 - The removal of the `RawHandle` struct the Windows impl, which had the same name as the `RawHandle` type alias, and its functionality is now folded into `Handle`.

Managing five levels of wrapping (File wraps sys::fs::File wraps sys::fs::FileDesc wraps OwnedFd wraps RawFd, etc.) made for a fair amount of churn and verbose as/into/from sequences in some places. I've managed to simplify some of them, but I'm open to ideas here.

r? `@joshtriplett`
This commit is contained in:
bors 2021-08-20 11:00:55 +00:00
commit 521734787e
57 changed files with 2235 additions and 717 deletions

View File

@ -587,6 +587,12 @@ impl File {
}
}
// In addition to the `impl`s here, `File` also has `impl`s for
// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
// `AsHandle`/`From<OwnedHandle>`/`Into<OwnedHandle>` and
// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows.
impl AsInner<fs_imp::File> for File {
fn as_inner(&self) -> &fs_imp::File {
&self.inner

View File

@ -546,6 +546,12 @@ impl TcpStream {
}
}
// In addition to the `impl`s here, `TcpStream` also has `impl`s for
// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
// `AsSocket`/`From<OwnedSocket>`/`Into<OwnedSocket>` and
// `AsRawSocket`/`IntoRawSocket`/`FromRawSocket` on Windows.
#[stable(feature = "rust1", since = "1.0.0")]
impl Read for TcpStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@ -915,6 +921,12 @@ impl TcpListener {
}
}
// In addition to the `impl`s here, `TcpListener` also has `impl`s for
// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
// `AsSocket`/`From<OwnedSocket>`/`Into<OwnedSocket>` and
// `AsRawSocket`/`IntoRawSocket`/`FromRawSocket` on Windows.
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Iterator for Incoming<'a> {
type Item = io::Result<TcpStream>;

View File

@ -779,6 +779,12 @@ impl UdpSocket {
}
}
// In addition to the `impl`s here, `UdpSocket` also has `impl`s for
// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
// `AsSocket`/`From<OwnedSocket>`/`Into<OwnedSocket>` and
// `AsRawSocket`/`IntoRawSocket`/`FromRawSocket` on Windows.
impl AsInner<net_imp::UdpSocket> for UdpSocket {
fn as_inner(&self) -> &net_imp::UdpSocket {
&self.0

View File

@ -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);
}

View File

@ -0,0 +1,13 @@
//! Owned and borrowed Unix-like file descriptors.
#![unstable(feature = "io_safety", issue = "87074")]
#![deny(unsafe_op_in_unsafe_fn)]
// `RawFd`, `AsRawFd`, etc.
pub mod raw;
// `OwnedFd`, `AsFd`, etc.
pub mod owned;
// Implementations for `AsRawFd` etc. for network types.
mod net;

View File

@ -1,4 +1,5 @@
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::os::fd::owned::OwnedFd;
use crate::os::fd::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
use crate::{net, sys};
@ -8,7 +9,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,8 +22,10 @@ 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);
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
unsafe {
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 +38,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()
}
}
)*};

View File

@ -0,0 +1,289 @@
//! Owned and borrowed Unix-like file descriptors.
#![unstable(feature = "io_safety", issue = "87074")]
#![deny(unsafe_op_in_unsafe_fn)]
use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::fmt;
use crate::fs;
use crate::marker::PhantomData;
use crate::mem::forget;
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> {
fd: 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 {
fd: RawFd,
}
impl BorrowedFd<'_> {
/// Return a `BorrowedFd` holding the given raw file descriptor.
///
/// # Safety
///
/// The resource pointed to by `fd` 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(fd: RawFd) -> Self {
assert_ne!(fd, u32::MAX as RawFd);
// 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 { fd, _phantom: PhantomData } }
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsRawFd for BorrowedFd<'_> {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsRawFd for OwnedFd {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl IntoRawFd for OwnedFd {
#[inline]
fn into_raw_fd(self) -> RawFd {
let fd = self.fd;
forget(self);
fd
}
}
#[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 `fd` must be open and suitable for assuming
/// ownership. The resource must not require any cleanup other than `close`.
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> Self {
assert_ne!(fd, u32::MAX as RawFd);
// 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 { fd } }
}
}
#[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.fd);
}
}
}
#[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.fd).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.fd).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;
/// # #[cfg(target_os = "wasi")]
/// # use std::os::wasi::io::{AsFd, BorrowedFd};
/// # #[cfg(unix)]
/// # use std::os::unix::io::{AsFd, BorrowedFd};
///
/// let mut f = File::open("foo.txt")?;
/// # #[cfg(any(unix, target_os = "wasi"))]
/// 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<'_> {
// Safety: `OwnedFd` and `BorrowedFd` have the same validity
// invariants, and the `BorrowdFd` is bounded by the lifetime
// of `&self`.
unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) }
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsFd for fs::File {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().as_fd()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<fs::File> for OwnedFd {
#[inline]
fn from(file: fs::File) -> OwnedFd {
file.into_inner().into_inner().into_inner()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<OwnedFd> for fs::File {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsFd for crate::net::TcpStream {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().socket().as_fd()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<crate::net::TcpStream> for OwnedFd {
#[inline]
fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<OwnedFd> for crate::net::TcpStream {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
owned_fd,
))))
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsFd for crate::net::TcpListener {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().socket().as_fd()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<crate::net::TcpListener> for OwnedFd {
#[inline]
fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<OwnedFd> for crate::net::TcpListener {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
owned_fd,
))))
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsFd for crate::net::UdpSocket {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().socket().as_fd()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<crate::net::UdpSocket> for OwnedFd {
#[inline]
fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
udp_socket.into_inner().into_socket().into_inner().into_inner().into()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<OwnedFd> for crate::net::UdpSocket {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
owned_fd,
))))
}
}

View File

@ -1,23 +1,25 @@
//! Unix-specific extensions to general I/O primitives.
//! Raw Unix-like file descriptors.
#![stable(feature = "rust1", since = "1.0.0")]
use crate::fs;
use crate::io;
use crate::os::raw;
use crate::sys;
use crate::sys_common::{AsInner, FromInner, IntoInner};
#[cfg(unix)]
use crate::os::unix::io::OwnedFd;
#[cfg(target_os = "wasi")]
use crate::os::wasi::io::OwnedFd;
use crate::sys_common::{AsInner, IntoInner};
/// Raw file descriptors.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = raw::c_int;
/// A trait to extract the raw unix file descriptor from an underlying
/// object.
/// A trait to extract the raw 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.
/// This is only available on unix and WASI platforms and must be imported in
/// order to call the method. Windows platforms have a corresponding
/// `AsRawHandle` and `AsRawSocket` set of traits.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawFd {
/// Extracts the raw file descriptor.
@ -31,10 +33,14 @@ pub trait AsRawFd {
/// ```no_run
/// use std::fs::File;
/// # use std::io;
/// #[cfg(unix)]
/// use std::os::unix::io::{AsRawFd, RawFd};
/// #[cfg(target_os = "wasi")]
/// 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.
/// #[cfg(any(unix, target_os = "wasi"))]
/// let raw_fd: RawFd = f.as_raw_fd();
/// # Ok::<(), io::Error>(())
/// ```
@ -64,12 +70,17 @@ pub trait FromRawFd {
/// ```no_run
/// use std::fs::File;
/// # use std::io;
/// #[cfg(unix)]
/// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
/// #[cfg(target_os = "wasi")]
/// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd};
///
/// let f = File::open("foo.txt")?;
/// # #[cfg(any(unix, target_os = "wasi"))]
/// 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.
/// # #[cfg(any(unix, target_os = "wasi"))]
/// let f = unsafe { File::from_raw_fd(raw_fd) };
/// # Ok::<(), io::Error>(())
/// ```
@ -92,9 +103,13 @@ pub trait IntoRawFd {
/// ```no_run
/// use std::fs::File;
/// # use std::io;
/// #[cfg(unix)]
/// use std::os::unix::io::{IntoRawFd, RawFd};
/// #[cfg(target_os = "wasi")]
/// use std::os::wasi::io::{IntoRawFd, RawFd};
///
/// let f = File::open("foo.txt")?;
/// #[cfg(any(unix, target_os = "wasi"))]
/// let raw_fd: RawFd = f.into_raw_fd();
/// # Ok::<(), io::Error>(())
/// ```
@ -128,21 +143,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))
unsafe { 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()
}
}

View File

@ -3,7 +3,7 @@
#![unstable(feature = "linux_pidfd", issue = "82971")]
use crate::io::Result;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::process;
use crate::sealed::Sealed;
#[cfg(not(doc))]
@ -69,19 +69,37 @@ impl IntoInner<FileDesc> for PidFd {
impl AsRawFd for PidFd {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().raw()
self.as_inner().as_raw_fd()
}
}
impl FromRawFd for PidFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self::from_inner(FileDesc::new(fd))
Self::from_inner(FileDesc::from_raw_fd(fd))
}
}
impl IntoRawFd for PidFd {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_raw()
self.into_inner().into_raw_fd()
}
}
impl AsFd for PidFd {
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().as_fd()
}
}
impl From<OwnedFd> for PidFd {
fn from(fd: OwnedFd) -> Self {
Self::from_inner(FileDesc::from_inner(fd))
}
}
impl From<PidFd> for OwnedFd {
fn from(pid_fd: PidFd) -> Self {
pid_fd.into_inner().into_inner()
}
}

View File

@ -121,3 +121,6 @@ mod imp {
#[cfg(not(doc))]
#[stable(feature = "os", since = "1.0.0")]
pub use imp::*;
#[cfg(any(unix, target_os = "wasi", doc))]
mod fd;

View File

@ -0,0 +1,9 @@
//! Owned and borrowed file descriptors.
#![unstable(feature = "io_safety", issue = "87074")]
// Tests for this module
#[cfg(test)]
mod tests;
pub use crate::os::fd::owned::*;

View File

@ -0,0 +1,11 @@
use crate::mem::size_of;
use crate::os::unix::io::RawFd;
#[test]
fn test_raw_fd_layout() {
// `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
// and `rustc_layout_scalar_valid_range_end`, with values that depend on
// the bit width of `RawFd`. If this ever changes, those values will need
// to be updated.
assert_eq!(size_of::<RawFd>(), 4);
}

View File

@ -0,0 +1,57 @@
//! 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. Once the
//! `io_safety` feature is stable, libraries will be 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 assigned 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 can have 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::*;

View File

@ -0,0 +1,5 @@
//! Unix-specific extensions to general I/O primitives.
#![stable(feature = "rust1", since = "1.0.0")]
pub use crate::os::fd::raw::*;

View File

@ -108,7 +108,7 @@ pub mod prelude {
pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt};
#[doc(no_inline)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
#[doc(no_inline)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::process::{CommandExt, ExitStatusExt};

View File

@ -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> {
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> {
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<UnixDatagram> 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<OwnedFd> for UnixDatagram {
#[inline]
fn from(owned: OwnedFd) -> Self {
unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
}
}

View File

@ -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> {
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()
}
}

View File

@ -25,7 +25,6 @@ mod addr;
mod ancillary;
mod datagram;
mod listener;
mod raw_fd;
mod stream;
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
@ -48,7 +47,5 @@ pub use self::ancillary::*;
pub use self::datagram::*;
#[stable(feature = "unix_socket", since = "1.10.0")]
pub use self::listener::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::raw_fd::*;
#[stable(feature = "unix_socket", since = "1.10.0")]
pub use self::stream::*;

View File

@ -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> {
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> {
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<UnixStream> 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<OwnedFd> for UnixStream {
#[inline]
fn from(owned: OwnedFd) -> Self {
unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
}
}

View File

@ -4,7 +4,7 @@
use crate::ffi::OsStr;
use crate::io;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::process;
use crate::sealed::Sealed;
use crate::sys;
@ -321,7 +321,17 @@ 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)
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<OwnedFd> for process::Stdio {
#[inline]
fn from(fd: OwnedFd) -> process::Stdio {
let fd = sys::fd::FileDesc::from_inner(fd);
let io = sys::process::Stdio::Fd(fd);
process::Stdio::from_inner(io)
}
@ -331,7 +341,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 +349,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 +357,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 +365,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 +373,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 +381,55 @@ 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()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsFd for crate::process::ChildStdin {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().as_fd()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<crate::process::ChildStdin> for OwnedFd {
#[inline]
fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
child_stdin.into_inner().into_inner().into_inner()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsFd for crate::process::ChildStdout {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().as_fd()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<crate::process::ChildStdout> for OwnedFd {
#[inline]
fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
child_stdout.into_inner().into_inner().into_inner()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsFd for crate::process::ChildStderr {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().as_fd()
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<crate::process::ChildStderr> for OwnedFd {
#[inline]
fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
child_stderr.into_inner().into_inner().into_inner()
}
}

View File

@ -228,35 +228,35 @@ pub trait FileExt {
impl FileExt for fs::File {
fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
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<usize> {
self.as_inner().fd().pwrite(bufs, offset)
self.as_inner().as_inner().pwrite(bufs, offset)
}
fn tell(&self) -> io::Result<u64> {
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<P: AsRef<Path>>(&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<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
@ -269,11 +269,11 @@ impl FileExt for fs::File {
}
fn remove_file<P: AsRef<Path>>(&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<P: AsRef<Path>>(&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<P: AsRef<Path>, U: AsRef<Path>>(
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<P: AsRef<Path>, U: AsRef<Path>>(
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<P: AsRef<Path>, U: AsRef<Path>>(
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())?)
}

View File

@ -1,208 +0,0 @@
//! WASI-specific extensions to general I/O primitives
#![deny(unsafe_op_in_unsafe_fn)]
#![unstable(feature = "wasi_ext", issue = "71213")]
use crate::fs;
use crate::io;
use crate::net;
use crate::os::raw;
use crate::sys;
use crate::sys_common::{AsInner, FromInner, IntoInner};
/// Raw file descriptors.
///
/// This has type `c_int` to ease compatibility with code that also compiles on
/// Unix configurations, however unlike Unix and POSIX, in WASI negative file
/// descriptors are valid. Only `-1` is reserved for indicating errors. Code
/// intending to be portable across Unix platforms and WASI should avoid
/// 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
/// object.
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.
fn as_raw_fd(&self) -> RawFd;
}
/// A trait to express the ability to construct an object from a raw file
/// descriptor.
pub trait FromRawFd {
/// Constructs a new instance of `Self` from the given raw file
/// descriptor.
///
/// This function **consumes ownership** of the specified file
/// descriptor. The returned object will take responsibility for closing
/// it when the object goes out of scope.
///
/// This function is also unsafe as the primitives currently returned
/// have the contract that they are the sole owner of the file
/// 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.
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
/// A trait to express the ability to consume an object and acquire ownership of
/// its raw file descriptor.
pub trait IntoRawFd {
/// Consumes this object, returning the raw underlying file descriptor.
///
/// 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.
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 {
fd
}
}
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()
}
}
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))
}
}
impl IntoRawFd for fs::File {
#[inline]
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
impl AsRawFd for io::Stdin {
#[inline]
fn as_raw_fd(&self) -> RawFd {
libc::STDIN_FILENO
}
}
impl AsRawFd for io::Stdout {
#[inline]
fn as_raw_fd(&self) -> RawFd {
libc::STDOUT_FILENO
}
}
impl AsRawFd for io::Stderr {
#[inline]
fn as_raw_fd(&self) -> RawFd {
libc::STDERR_FILENO
}
}
impl<'a> AsRawFd for io::StdinLock<'a> {
#[inline]
fn as_raw_fd(&self) -> RawFd {
libc::STDIN_FILENO
}
}
impl<'a> AsRawFd for io::StdoutLock<'a> {
#[inline]
fn as_raw_fd(&self) -> RawFd {
libc::STDOUT_FILENO
}
}
impl<'a> AsRawFd for io::StderrLock<'a> {
#[inline]
fn as_raw_fd(&self) -> RawFd {
libc::STDERR_FILENO
}
}

View File

@ -0,0 +1,9 @@
//! Owned and borrowed file descriptors.
#![unstable(feature = "wasi_ext", issue = "71213")]
// Tests for this module
#[cfg(test)]
mod tests;
pub use crate::os::fd::owned::*;

View File

@ -0,0 +1,11 @@
use crate::mem::size_of;
use crate::os::wasi::io::RawFd;
#[test]
fn test_raw_fd_layout() {
// `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
// and `rustc_layout_scalar_valid_range_end`, with values that depend on
// the bit width of `RawFd`. If this ever changes, those values will need
// to be updated.
assert_eq!(size_of::<RawFd>(), 4);
}

View File

@ -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::*;

View File

@ -0,0 +1,5 @@
//! WASI-specific extensions to general I/O primitives.
#![unstable(feature = "wasi_ext", issue = "71213")]
pub use crate::os::fd::raw::*;

View File

@ -32,6 +32,7 @@
pub mod ffi;
pub mod fs;
pub mod io;
pub mod net;
/// A prelude for conveniently writing platform-specific code.
///
@ -49,5 +50,5 @@ pub mod prelude {
pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
#[doc(no_inline)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
}

View File

@ -0,0 +1,3 @@
//! WASI-specific networking functionality
#![unstable(feature = "wasi_ext", issue = "71213")]

View File

@ -0,0 +1,386 @@
//! 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` (-1), which is
/// sometimes a valid 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> {
handle: NonNull<c_void>,
_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` (-1), which is
/// sometimes a valid handle value. See [here] for the full story. For APIs
/// like `CreateFileW` which report errors with `INVALID_HANDLE_VALUE` instead
/// of null, use [`HandleOrInvalid`] instead of `Option<OwnedHandle>`.
///
/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
/// it must not be used with handles to open registry keys which need to be
/// closed with [`RegCloseKey`] instead.
///
/// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
///
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
#[repr(transparent)]
#[unstable(feature = "io_safety", issue = "87074")]
pub struct OwnedHandle {
handle: NonNull<c_void>,
}
/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
/// FFI declarations.
///
/// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an
/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
/// checking for `INVALID_HANDLE_VALUE` first.
///
/// If this holds a valid handle, it will close the handle on drop.
#[repr(transparent)]
#[unstable(feature = "io_safety", issue = "87074")]
#[derive(Debug)]
pub struct HandleOrInvalid(Option<OwnedHandle>);
// 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 HandleOrInvalid {}
unsafe impl Send for BorrowedHandle<'_> {}
unsafe impl Sync for OwnedHandle {}
unsafe impl Sync for HandleOrInvalid {}
unsafe impl Sync for BorrowedHandle<'_> {}
impl BorrowedHandle<'_> {
/// Return a `BorrowedHandle` holding the given raw handle.
///
/// # Safety
///
/// The resource pointed to by `handle` must be a valid open handle, it
/// must remain open for the duration of the returned `BorrowedHandle`, and
/// it must not be null.
///
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
/// sometimes a valid handle value. See [here] for the full story.
///
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
#[inline]
#[unstable(feature = "io_safety", issue = "87074")]
pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self {
assert!(!handle.is_null());
Self { handle: NonNull::new_unchecked(handle), _phantom: PhantomData }
}
}
impl TryFrom<HandleOrInvalid> for OwnedHandle {
type Error = ();
#[inline]
fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, ()> {
// In theory, we ought to be able to assume that the pointer here is
// never null, use `OwnedHandle` rather than `Option<OwnedHandle>`, 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
let owned_handle = handle_or_invalid.0.expect("A `HandleOrInvalid` was null!");
if owned_handle.handle.as_ptr() == c::INVALID_HANDLE_VALUE {
Err(())
} else {
Ok(owned_handle)
}
}
}
impl AsRawHandle for BorrowedHandle<'_> {
#[inline]
fn as_raw_handle(&self) -> RawHandle {
self.handle.as_ptr()
}
}
impl AsRawHandle for OwnedHandle {
#[inline]
fn as_raw_handle(&self) -> RawHandle {
self.handle.as_ptr()
}
}
impl IntoRawHandle for OwnedHandle {
#[inline]
fn into_raw_handle(self) -> RawHandle {
let handle = self.handle.as_ptr();
forget(self);
handle
}
}
impl FromRawHandle for OwnedHandle {
/// Constructs a new instance of `Self` from the given raw handle.
///
/// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` for APIs that
/// use `INVALID_HANDLE_VALUE` to indicate failure.
///
/// # Safety
///
/// The resource pointed to by `handle` must be open and suitable for
/// assuming ownership. The resource must not require any cleanup other
/// than `CloseHandle`.
///
/// In particular, it must not be used with handles to open registry
/// keys which need to be closed with [`RegCloseKey`] instead.
///
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
/// sometimes a valid handle value. See [here] for the full story.
///
/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
#[inline]
unsafe fn from_raw_handle(handle: RawHandle) -> Self {
assert!(!handle.is_null());
Self { handle: NonNull::new_unchecked(handle) }
}
}
impl FromRawHandle for HandleOrInvalid {
/// Constructs a new instance of `Self` from the given `RawHandle` returned
/// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
/// failure, such as `CreateFileW`.
///
/// Use `Option<OwnedHandle>` instead of `HandleOrInvalid` for APIs that
/// use null to indicate failure.
///
/// # Safety
///
/// The resource pointed to by `handle` must be either open and otherwise
/// unowned, or equal to `INVALID_HANDLE_VALUE` (-1). It must not be null.
/// 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(handle: RawHandle) -> Self {
// We require non-null here to catch errors earlier.
Self(Some(OwnedHandle::from_raw_handle(handle)))
}
}
impl Drop for OwnedHandle {
#[inline]
fn drop(&mut self) {
unsafe {
let _ = c::CloseHandle(self.handle.as_ptr());
}
}
}
impl fmt::Debug for BorrowedHandle<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish()
}
}
impl fmt::Debug for OwnedHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedHandle").field("handle", &self.handle).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
/// # #![feature(io_safety)]
/// use std::fs::File;
/// # use std::io;
/// use std::os::windows::io::{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<'_> {
// Safety: `OwnedHandle` and `BorrowedHandle` have the same validity
// invariants, and the `BorrowdHandle` is bounded by the lifetime
// of `&self`.
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<fs::File> for OwnedHandle {
#[inline]
fn from(file: fs::File) -> OwnedHandle {
file.into_inner().into_inner().into_inner().into()
}
}
impl From<OwnedHandle> 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<crate::process::ChildStdin> 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<crate::process::ChildStdout> 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<crate::process::ChildStderr> for OwnedHandle {
#[inline]
fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle {
unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) }
}
}
impl<T> AsHandle for crate::thread::JoinHandle<T> {
#[inline]
fn as_handle(&self) -> BorrowedHandle<'_> {
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
}
}
impl<T> From<crate::thread::JoinHandle<T>> for OwnedHandle {
#[inline]
fn from(join_handle: crate::thread::JoinHandle<T>) -> OwnedHandle {
join_handle.into_inner().into_handle().into_inner()
}
}

View File

@ -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. Once the `io_safety` feature is stable,
//! libraries will be 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::*;

View File

@ -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()
}
}

View File

@ -0,0 +1,216 @@
//! 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> {
socket: 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 {
socket: 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(socket: RawSocket) -> Self {
debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket);
Self { socket, _phantom: PhantomData }
}
}
impl AsRawSocket for BorrowedSocket<'_> {
#[inline]
fn as_raw_socket(&self) -> RawSocket {
self.socket
}
}
impl AsRawSocket for OwnedSocket {
#[inline]
fn as_raw_socket(&self) -> RawSocket {
self.socket
}
}
impl IntoRawSocket for OwnedSocket {
#[inline]
fn into_raw_socket(self) -> RawSocket {
let socket = self.socket;
forget(self);
socket
}
}
impl FromRawSocket for OwnedSocket {
/// Constructs a new instance of `Self` from the given raw socket.
///
/// # Safety
///
/// The resource pointed to by `socket` must be open and suitable for
/// assuming ownership. The resource must not require cleanup other than
/// `closesocket`.
#[inline]
unsafe fn from_raw_socket(socket: RawSocket) -> Self {
debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket);
Self { socket }
}
}
impl Drop for OwnedSocket {
#[inline]
fn drop(&mut self) {
unsafe {
let _ = c::closesocket(self.socket);
}
}
}
impl fmt::Debug for BorrowedSocket<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BorrowedSocket").field("socket", &self.socket).finish()
}
}
impl fmt::Debug for OwnedSocket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedSocket").field("socket", &self.socket).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<'_> {
// Safety: `OwnedSocket` and `BorrowedSocket` have the same validity
// invariants, and the `BorrowdSocket` is bounded by the lifetime
// of `&self`.
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<crate::net::TcpStream> for OwnedSocket {
#[inline]
fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket {
unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) }
}
}
impl From<OwnedSocket> 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<crate::net::TcpListener> for OwnedSocket {
#[inline]
fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket {
unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) }
}
}
impl From<OwnedSocket> 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<crate::net::UdpSocket> for OwnedSocket {
#[inline]
fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket {
unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) }
}
}
impl From<OwnedSocket> for crate::net::UdpSocket {
#[inline]
fn from(owned: OwnedSocket) -> Self {
unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
}
}

View File

@ -32,8 +32,11 @@ pub mod prelude {
pub use super::fs::{MetadataExt, OpenOptionsExt};
#[doc(no_inline)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket};
pub use super::io::{
AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, FromRawHandle, FromRawSocket,
HandleOrInvalid, IntoRawHandle, IntoRawSocket, OwnedHandle, OwnedSocket,
};
#[doc(no_inline)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::io::{FromRawHandle, FromRawSocket, IntoRawHandle, IntoRawSocket};
pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket};
}

View File

@ -3,7 +3,9 @@
#![stable(feature = "process_extensions", since = "1.2.0")]
use crate::ffi::OsStr;
use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
use crate::os::windows::io::{
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
};
use crate::process;
use crate::sealed::Sealed;
use crate::sys;
@ -12,7 +14,16 @@ 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)
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<OwnedHandle> for process::Stdio {
fn from(handle: OwnedHandle) -> process::Stdio {
let handle = sys::handle::Handle::from_inner(handle);
let io = sys::process::Stdio::Handle(handle);
process::Stdio::from_inner(io)
}
@ -22,14 +33,29 @@ 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 _
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl AsHandle for process::Child {
#[inline]
fn as_handle(&self) -> BorrowedHandle<'_> {
self.as_inner().handle().as_handle()
}
}
#[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 _
}
}
#[unstable(feature = "io_safety", issue = "87074")]
impl From<process::Child> for OwnedHandle {
fn from(child: process::Child) -> OwnedHandle {
child.into_inner().into_handle().into_inner()
}
}
@ -37,7 +63,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 +71,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 +79,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 _
}
}

View File

@ -10,7 +10,7 @@ use crate::thread;
impl<T> AsRawHandle for thread::JoinHandle<T> {
#[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<T> AsRawHandle for thread::JoinHandle<T> {
impl<T> IntoRawHandle for thread::JoinHandle<T> {
#[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 _
}
}

View File

@ -258,6 +258,12 @@ pub struct ChildStdin {
inner: AnonPipe,
}
// In addition to the `impl`s here, `ChildStdin` also has `impl`s for
// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
// `AsHandle`/`From<OwnedHandle>`/`Into<OwnedHandle>` and
// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows.
#[stable(feature = "process", since = "1.0.0")]
impl Write for ChildStdin {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
@ -335,6 +341,12 @@ pub struct ChildStdout {
inner: AnonPipe,
}
// In addition to the `impl`s here, `ChildStdout` also has `impl`s for
// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
// `AsHandle`/`From<OwnedHandle>`/`Into<OwnedHandle>` and
// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows.
#[stable(feature = "process", since = "1.0.0")]
impl Read for ChildStdout {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@ -396,6 +408,12 @@ pub struct ChildStderr {
inner: AnonPipe,
}
// In addition to the `impl`s here, `ChildStderr` also has `impl`s for
// `AsFd`/`From<OwnedFd>`/`Into<OwnedFd>` and
// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and
// `AsHandle`/`From<OwnedHandle>`/`Into<OwnedHandle>` and
// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows.
#[stable(feature = "process", since = "1.0.0")]
impl Read for ChildStderr {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {

View File

@ -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<usize> {
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<usize> {
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<usize> {
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<usize> {
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<bool> {
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<c_int> for FileDesc {
fn as_inner(&self) -> &c_int {
&self.fd
impl AsInner<OwnedFd> for FileDesc {
fn as_inner(&self) -> &OwnedFd {
&self.0
}
}
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 IntoInner<OwnedFd> for FileDesc {
fn into_inner(self) -> OwnedFd {
self.0
}
}
impl FromInner<OwnedFd> 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 FromRawFd for FileDesc {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
Self(FromRawFd::from_raw_fd(raw_fd))
}
}

View File

@ -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::<Vec<_>>();
assert!(stdout.write_vectored(&bufs).is_ok());
}

View File

@ -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<FileAttr> {
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<CString> {
Ok(CString::new(path.as_os_str().as_bytes())?)
}
impl FromInner<c_int> for File {
fn from_inner(fd: c_int) -> File {
File(FileDesc::new(fd))
impl AsInner<FileDesc> for File {
fn as_inner(&self) -> &FileDesc {
&self.0
}
}
impl AsInnerMut<FileDesc> for File {
fn as_inner_mut(&mut self) -> &mut FileDesc {
&mut self.0
}
}
impl IntoInner<FileDesc> for File {
fn into_inner(self) -> FileDesc {
self.0
}
}
impl FromInner<FileDesc> 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) {

View File

@ -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<usize> {
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<usize> {
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<usize> {
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))) }
}
}
impl AsInner<c_int> for Socket {
fn as_inner(&self) -> &c_int {
self.0.as_inner()
// This is used by sys_common code to abstract over Windows and Unix.
pub fn as_raw(&self) -> RawFd {
self.as_raw_fd()
}
}
impl FromInner<c_int> for Socket {
fn from_inner(fd: c_int) -> Socket {
Socket(FileDesc::new(fd))
impl AsInner<FileDesc> for Socket {
fn as_inner(&self) -> &FileDesc {
&self.0
}
}
impl IntoInner<c_int> for Socket {
fn into_inner(self) -> c_int {
self.0.into_raw()
impl IntoInner<FileDesc> for Socket {
fn into_inner(self) -> FileDesc {
self.0
}
}
impl FromInner<FileDesc> 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 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 {
Self(FromRawFd::from_raw_fd(raw_fd))
}
}

View File

@ -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()) })?;
unsafe {
cvt(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)))
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<FileDesc> for AnonPipe {
fn into_inner(self) -> FileDesc {
self.0
}
}
@ -76,15 +81,15 @@ impl AnonPipe {
pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> 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<u8>, p2: AnonPipe, v2: &mut Vec<u8>) ->
}
}
}
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))
}
}

View File

@ -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<AnonPipe> for Stdio {
fn from(pipe: AnonPipe) -> Stdio {
Stdio::Fd(pipe.into_fd())
Stdio::Fd(pipe.into_inner())
}
}
impl From<File> 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,

View File

@ -97,7 +97,9 @@ impl Command {
drop(env_lock);
drop(output);
let mut p = Process::new(pid, pidfd);
// Safety: We obtained the pidfd from calling `clone3` with
// `CLONE_PIDFD` so it's valid an otherwise unowned.
let mut p = unsafe { Process::new(pid, pidfd) };
let mut bytes = [0; 8];
// loop to handle EINTR
@ -446,7 +448,8 @@ impl Command {
None => None,
};
let mut p = Process::new(0, -1);
// Safety: -1 indicates we don't have a pidfd.
let mut p = unsafe { Process::new(0, -1) };
struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>);
@ -545,14 +548,17 @@ pub struct Process {
impl Process {
#[cfg(target_os = "linux")]
fn new(pid: pid_t, pidfd: pid_t) -> Self {
unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self {
use crate::os::unix::io::FromRawFd;
use crate::sys_common::FromInner;
let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::new(pidfd)));
// Safety: If `pidfd` is nonnegative, we assume it's valid and otherwise unowned.
let pidfd = (pidfd >= 0)
.then(|| PidFd::from_inner(unsafe { sys::fd::FileDesc::from_raw_fd(pidfd) }));
Process { pid, status: None, pidfd }
}
#[cfg(not(target_os = "linux"))]
fn new(pid: pid_t, _pidfd: pid_t) -> Self {
unsafe fn new(pid: pid_t, _pidfd: pid_t) -> Self {
Process { pid, status: None }
}

View File

@ -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<usize> {
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<usize> {
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<usize> {
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<usize> {
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<usize> {
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<usize> {
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<impl io::Write> {
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) }
}
}

View File

@ -5,11 +5,12 @@ use super::err2io;
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 +28,26 @@ 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() as wasi::Fd).map_err(err2io) }
}
pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
unsafe { wasi::fd_pread(self.fd as wasi::Fd, iovec(bufs), offset).map_err(err2io) }
unsafe { wasi::fd_pread(self.as_raw_fd() as wasi::Fd, iovec(bufs), offset).map_err(err2io) }
}
pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
unsafe { wasi::fd_pwrite(self.fd as wasi::Fd, ciovec(bufs), offset).map_err(err2io) }
unsafe {
wasi::fd_pwrite(self.as_raw_fd() as wasi::Fd, ciovec(bufs), offset).map_err(err2io)
}
}
pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
unsafe { wasi::fd_read(self.fd as wasi::Fd, iovec(bufs)).map_err(err2io) }
unsafe { wasi::fd_read(self.as_raw_fd() as wasi::Fd, iovec(bufs)).map_err(err2io) }
}
pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
unsafe { wasi::fd_write(self.fd as wasi::Fd, ciovec(bufs)).map_err(err2io) }
unsafe { wasi::fd_write(self.as_raw_fd() as wasi::Fd, ciovec(bufs)).map_err(err2io) }
}
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
@ -67,37 +56,42 @@ 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() as wasi::Fd, offset, whence).map_err(err2io) }
}
pub fn tell(&self) -> io::Result<u64> {
unsafe { wasi::fd_tell(self.fd as wasi::Fd).map_err(err2io) }
unsafe { wasi::fd_tell(self.as_raw_fd() as wasi::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() as wasi::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() as wasi::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() as wasi::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() as wasi::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() as wasi::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() as wasi::Fd, path).map_err(err2io) }
}
pub fn link(
@ -109,10 +103,10 @@ impl WasiFd {
) -> io::Result<()> {
unsafe {
wasi::path_link(
self.fd as wasi::Fd,
self.as_raw_fd() as wasi::Fd,
old_flags,
old_path,
new_fd.fd as wasi::Fd,
new_fd.as_raw_fd() as wasi::Fd,
new_path,
)
.map_err(err2io)
@ -130,7 +124,7 @@ impl WasiFd {
) -> io::Result<WasiFd> {
unsafe {
wasi::path_open(
self.fd as wasi::Fd,
self.as_raw_fd() as wasi::Fd,
dirflags,
path,
oflags,
@ -138,34 +132,39 @@ impl WasiFd {
fs_rights_inheriting,
fs_flags,
)
.map(|fd| WasiFd::from_raw(fd as c_int))
.map(|fd| WasiFd::from_raw_fd(fd as RawFd))
.map_err(err2io)
}
}
pub fn readdir(&self, buf: &mut [u8], cookie: wasi::Dircookie) -> io::Result<usize> {
unsafe {
wasi::fd_readdir(self.fd as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie)
wasi::fd_readdir(self.as_raw_fd() as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie)
.map_err(err2io)
}
}
pub fn readlink(&self, path: &str, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
wasi::path_readlink(self.fd as wasi::Fd, path, buf.as_mut_ptr(), buf.len())
wasi::path_readlink(self.as_raw_fd() as wasi::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)
.map_err(err2io)
wasi::path_rename(
self.as_raw_fd() as wasi::Fd,
old_path,
new_fd.as_raw_fd() as wasi::Fd,
new_path,
)
.map_err(err2io)
}
}
pub fn filestat_get(&self) -> io::Result<wasi::Filestat> {
unsafe { wasi::fd_filestat_get(self.fd as wasi::Fd).map_err(err2io) }
unsafe { wasi::fd_filestat_get(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
}
pub fn filestat_set_times(
@ -175,12 +174,13 @@ 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() as wasi::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() as wasi::Fd, size).map_err(err2io) }
}
pub fn path_filestat_get(
@ -188,7 +188,9 @@ impl WasiFd {
flags: wasi::Lookupflags,
path: &str,
) -> io::Result<wasi::Filestat> {
unsafe { wasi::path_filestat_get(self.fd as wasi::Fd, flags, path).map_err(err2io) }
unsafe {
wasi::path_filestat_get(self.as_raw_fd() as wasi::Fd, flags, path).map_err(err2io)
}
}
pub fn path_filestat_set_times(
@ -200,21 +202,30 @@ impl WasiFd {
fstflags: wasi::Fstflags,
) -> io::Result<()> {
unsafe {
wasi::path_filestat_set_times(self.fd as wasi::Fd, flags, path, atim, mtim, fstflags)
.map_err(err2io)
wasi::path_filestat_set_times(
self.as_raw_fd() as wasi::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() as wasi::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() as wasi::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() as wasi::Fd, path).map_err(err2io) }
}
pub fn sock_recv(
@ -222,11 +233,15 @@ 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() as wasi::Fd, iovec(ri_data), ri_flags).map_err(err2io)
}
}
pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::Siflags) -> io::Result<usize> {
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() as wasi::Fd, ciovec(si_data), si_flags).map_err(err2io)
}
}
pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> {
@ -235,14 +250,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() as wasi::Fd, how).map_err(err2io) }
}
}
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 AsInner<OwnedFd> for WasiFd {
fn as_inner(&self) -> &OwnedFd {
&self.fd
}
}
impl AsInnerMut<OwnedFd> for WasiFd {
fn as_inner_mut(&mut self) -> &mut OwnedFd {
&mut self.fd
}
}
impl IntoInner<OwnedFd> for WasiFd {
fn into_inner(self) -> OwnedFd {
self.fd
}
}
impl FromInner<OwnedFd> 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 FromRawFd for WasiFd {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
}
}

View File

@ -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 {
&self.fd
}
pub fn into_fd(self) -> WasiFd {
self.fd
}
pub fn read_link(&self, file: &Path) -> io::Result<PathBuf> {
read_link(&self.fd, file)
}
}
impl FromInner<c_int> for File {
fn from_inner(fd: c_int) -> File {
unsafe { File { fd: WasiFd::from_raw(fd) } }
impl AsInner<WasiFd> for File {
fn as_inner(&self) -> &WasiFd {
&self.fd
}
}
impl IntoInner<WasiFd> for File {
fn into_inner(self) -> WasiFd {
self.fd
}
}
impl FromInner<WasiFd> 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 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<WasiFd>, 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)),
));
}

View File

@ -5,13 +5,57 @@ use crate::convert::TryFrom;
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<WasiFd> for Socket {
fn as_inner(&self) -> &WasiFd {
&self.0
}
}
impl IntoInner<WasiFd> for Socket {
fn into_inner(self) -> WasiFd {
self.0
}
}
impl FromInner<WasiFd> 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 +151,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<c_int> for TcpStream {
fn from_inner(fd: c_int) -> TcpStream {
unsafe { TcpStream { fd: WasiFd::from_raw(fd) } }
impl FromInner<Socket> 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 +217,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<c_int> for TcpListener {
fn from_inner(fd: c_int) -> TcpListener {
unsafe { TcpListener { fd: WasiFd::from_raw(fd) } }
impl AsInner<Socket> for TcpListener {
fn as_inner(&self) -> &Socket {
&self.inner
}
}
impl IntoInner<Socket> for TcpListener {
fn into_inner(self) -> Socket {
self.inner
}
}
impl FromInner<Socket> 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 +379,36 @@ impl UdpSocket {
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<c_int> for UdpSocket {
fn from_inner(fd: c_int) -> UdpSocket {
unsafe { UdpSocket { fd: WasiFd::from_raw(fd) } }
impl AsInner<Socket> for UdpSocket {
fn as_inner(&self) -> &Socket {
&self.inner
}
}
impl IntoInner<Socket> for UdpSocket {
fn into_inner(self) -> Socket {
self.inner
}
}
impl FromInner<Socket> 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()
}
}

View File

@ -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<usize> {
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<usize> {
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<usize> {
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]

View File

@ -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<FileAttr> {
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<c::HANDLE> for File {
fn from_inner(handle: c::HANDLE) -> File {
File { handle: Handle::new(handle) }
impl AsInner<Handle> for File {
fn as_inner(&self) -> &Handle {
&self.handle
}
}
impl IntoInner<Handle> for File {
fn into_inner(self) -> Handle {
self.handle
}
}
impl FromInner<Handle> 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<PathBuf> {
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];

View File

@ -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<Handle> {
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 Deref for Handle {
type Target = RawHandle;
fn deref(&self) -> &RawHandle {
impl AsInner<OwnedHandle> for Handle {
fn as_inner(&self) -> &OwnedHandle {
&self.0
}
}
impl Drop for Handle {
fn drop(&mut self) {
unsafe {
let _ = c::CloseHandle(self.raw());
}
impl IntoInner<OwnedHandle> for Handle {
fn into_inner(self) -> OwnedHandle {
self.0
}
}
impl RawHandle {
pub fn new(handle: c::HANDLE) -> RawHandle {
RawHandle(handle)
impl FromInner<OwnedHandle> for Handle {
fn from_inner(file_desc: OwnedHandle) -> Self {
Self(file_desc)
}
}
pub fn raw(&self) -> c::HANDLE {
self.0
impl AsHandle for Handle {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
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<usize> {
let mut read = 0;
let len = cmp::min(buf.len(), <c::DWORD>::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<Option<usize>> {
let len = cmp::min(buf.len(), <c::DWORD>::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<usize> {
let mut amt = 0;
let len = cmp::min(buf.len(), <c::DWORD>::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<usize> {
(**self).read(buf)
}

View File

@ -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::<c::fd_set>() };
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<Socket> {
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<Socket> {
let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
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<c::SOCKET> for Socket {
fn as_inner(&self) -> &c::SOCKET {
impl AsInner<OwnedSocket> for Socket {
fn as_inner(&self) -> &OwnedSocket {
&self.0
}
}
impl FromInner<c::SOCKET> for Socket {
fn from_inner(sock: c::SOCKET) -> Socket {
impl FromInner<OwnedSocket> for Socket {
fn from_inner(sock: OwnedSocket) -> Socket {
Socket(sock)
}
}
impl IntoInner<c::SOCKET> for Socket {
fn into_inner(self) -> c::SOCKET {
let ret = self.0;
mem::forget(self);
ret
impl IntoInner<OwnedSocket> 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 FromRawSocket for Socket {
unsafe fn from_raw_socket(raw_socket: RawSocket) -> Self {
Self(FromRawSocket::from_raw_socket(raw_socket))
}
}

View File

@ -288,7 +288,7 @@ fn home_dir_crt() -> Option<PathBuf> {
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) {

View File

@ -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<Handle> 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<u8>, p2: AnonPipe, v2: &mut Vec<u8>) ->
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<c::OVERLAPPED> = unsafe { Box::new(mem::zeroed()) };
overlapped.hEvent = event.raw();
overlapped.hEvent = event.as_raw_handle();
Ok(AsyncPipe { pipe, overlapped, event, dst, state: State::NotReading })
}

View File

@ -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, IntoRawHandle};
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_raw_handle();
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<AnonPipe> for Stdio {
impl From<File> 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<ExitStatus> {
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<Option<ExitStatus>> {
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)))
}
}

View File

@ -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<usize> {
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<usize> {
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 {

View File

@ -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());
}

View File

@ -61,13 +61,7 @@ cfg_if::cfg_if! {
pub fn setsockopt<T>(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::<T>() as c::socklen_t,
))?;
cvt(c::setsockopt(sock.as_raw(), opt, val, payload, mem::size_of::<T>() as c::socklen_t))?;
Ok(())
}
}
@ -76,7 +70,7 @@ pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, val: c_int) -> io::Result<
unsafe {
let mut slot: T = mem::zeroed();
let mut len = mem::size_of::<T>() 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::<T>());
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<usize> {
let len = cmp::min(buf.len(), <wrlen_t>::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<SocketAddr> {
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<SocketAddr> {
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<SocketAddr> {
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<SocketAddr> {
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<SocketAddr> {
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<usize> {
let len = cmp::min(buf.len(), <wrlen_t>::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()
}
}