From 4547b622d8d29df964fa2914213088b148c498fc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:32 +0200 Subject: Merging upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/rustix/src/backend/libc/io/epoll.rs | 573 ++++++++++ vendor/rustix/src/backend/libc/io/errno.rs | 1106 ++++++++++++++++++++ vendor/rustix/src/backend/libc/io/io_slice.rs | 87 ++ vendor/rustix/src/backend/libc/io/mod.rs | 13 + vendor/rustix/src/backend/libc/io/poll_fd.rs | 136 +++ vendor/rustix/src/backend/libc/io/syscalls.rs | 533 ++++++++++ vendor/rustix/src/backend/libc/io/types.rs | 164 +++ .../rustix/src/backend/libc/io/windows_syscalls.rs | 39 + 8 files changed, 2651 insertions(+) create mode 100644 vendor/rustix/src/backend/libc/io/epoll.rs create mode 100644 vendor/rustix/src/backend/libc/io/errno.rs create mode 100644 vendor/rustix/src/backend/libc/io/io_slice.rs create mode 100644 vendor/rustix/src/backend/libc/io/mod.rs create mode 100644 vendor/rustix/src/backend/libc/io/poll_fd.rs create mode 100644 vendor/rustix/src/backend/libc/io/syscalls.rs create mode 100644 vendor/rustix/src/backend/libc/io/types.rs create mode 100644 vendor/rustix/src/backend/libc/io/windows_syscalls.rs (limited to 'vendor/rustix/src/backend/libc/io') diff --git a/vendor/rustix/src/backend/libc/io/epoll.rs b/vendor/rustix/src/backend/libc/io/epoll.rs new file mode 100644 index 000000000..3205a613f --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/epoll.rs @@ -0,0 +1,573 @@ +//! epoll support. +//! +//! This is an experiment, and it isn't yet clear whether epoll is the right +//! level of abstraction at which to introduce safety. But it works fairly well +//! in simple examples 🙂. +//! +//! # Examples +//! +//! ```rust,no_run +//! # #![cfg_attr(io_lifetimes_use_std, feature(io_safety))] +//! # #[cfg(feature = "net")] +//! # fn main() -> std::io::Result<()> { +//! use io_lifetimes::AsFd; +//! use rustix::io::epoll::{self, Epoll}; +//! use rustix::io::{ioctl_fionbio, read, write}; +//! use rustix::net::{ +//! accept, bind_v4, listen, socket, AddressFamily, Ipv4Addr, Protocol, SocketAddrV4, +//! SocketType, +//! }; +//! use std::os::unix::io::AsRawFd; +//! +//! // Create a socket and listen on it. +//! let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; +//! bind_v4(&listen_sock, &SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?; +//! listen(&listen_sock, 1)?; +//! +//! // Create an epoll object. Using `Owning` here means the epoll object will +//! // take ownership of the file descriptors registered with it. +//! let epoll = Epoll::new(epoll::CreateFlags::CLOEXEC, epoll::Owning::new())?; +//! +//! // Remember the socket raw fd, which we use for comparisons only. +//! let raw_listen_sock = listen_sock.as_fd().as_raw_fd(); +//! +//! // Register the socket with the epoll object. +//! epoll.add(listen_sock, epoll::EventFlags::IN)?; +//! +//! // Process events. +//! let mut event_list = epoll::EventVec::with_capacity(4); +//! loop { +//! epoll.wait(&mut event_list, -1)?; +//! for (_event_flags, target) in &event_list { +//! if target.as_raw_fd() == raw_listen_sock { +//! // Accept a new connection, set it to non-blocking, and +//! // register to be notified when it's ready to write to. +//! let conn_sock = accept(&*target)?; +//! ioctl_fionbio(&conn_sock, true)?; +//! epoll.add(conn_sock, epoll::EventFlags::OUT | epoll::EventFlags::ET)?; +//! } else { +//! // Write a message to the stream and then unregister it. +//! write(&*target, b"hello\n")?; +//! let _ = epoll.del(target)?; +//! } +//! } +//! } +//! # } +//! # #[cfg(not(feature = "net"))] +//! # fn main() {} +//! ``` + +use super::super::c; +use super::super::conv::{ret, ret_owned_fd, ret_u32}; +use crate::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}; +#[cfg(not(feature = "rustc-dep-of-std"))] +use crate::fd::{FromRawFd, IntoRawFd}; +use crate::io; +use alloc::vec::Vec; +use bitflags::bitflags; +use core::convert::TryInto; +use core::fmt; +use core::marker::PhantomData; +use core::ops::Deref; +use core::ptr::{null, null_mut}; + +bitflags! { + /// `EPOLL_*` for use with [`Epoll::new`]. + pub struct CreateFlags: c::c_int { + /// `EPOLL_CLOEXEC` + const CLOEXEC = c::EPOLL_CLOEXEC; + } +} + +bitflags! { + /// `EPOLL*` for use with [`Epoll::add`]. + #[derive(Default)] + pub struct EventFlags: u32 { + /// `EPOLLIN` + const IN = c::EPOLLIN as u32; + + /// `EPOLLOUT` + const OUT = c::EPOLLOUT as u32; + + /// `EPOLLPRI` + const PRI = c::EPOLLPRI as u32; + + /// `EPOLLERR` + const ERR = c::EPOLLERR as u32; + + /// `EPOLLHUP` + const HUP = c::EPOLLHUP as u32; + + /// `EPOLLET` + const ET = c::EPOLLET as u32; + + /// `EPOLLONESHOT` + const ONESHOT = c::EPOLLONESHOT as u32; + + /// `EPOLLWAKEUP` + const WAKEUP = c::EPOLLWAKEUP as u32; + + /// `EPOLLEXCLUSIVE` + #[cfg(not(target_os = "android"))] + const EXCLUSIVE = c::EPOLLEXCLUSIVE as u32; + } +} + +/// A reference to a `T`. +pub struct Ref<'a, T> { + t: T, + _phantom: PhantomData<&'a T>, +} + +impl<'a, T> Ref<'a, T> { + #[inline] + fn new(t: T) -> Self { + Self { + t, + _phantom: PhantomData, + } + } + + #[inline] + fn consume(self) -> T { + self.t + } +} + +impl<'a, T> Deref for Ref<'a, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.t + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for Ref<'a, T> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.t.fmt(fmt) + } +} + +/// A trait for data stored within an [`Epoll`] instance. +pub trait Context { + /// The type of an element owned by this context. + type Data; + + /// The type of a value used to refer to an element owned by this context. + type Target: AsFd; + + /// Assume ownership of `data`, and returning a `Target`. + fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target>; + + /// Encode `target` as a `u64`. The only requirement on this value is that + /// it be decodable by `decode`. + fn encode(&self, target: Ref<'_, Self::Target>) -> u64; + + /// Decode `raw`, which is a value encoded by `encode`, into a `Target`. + /// + /// # Safety + /// + /// `raw` must be a `u64` value returned from `encode`, from the same + /// context, and within the context's lifetime. + unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target>; + + /// Release ownership of the value referred to by `target` and return it. + fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data; +} + +/// A type implementing [`Context`] where the `Data` type is `BorrowedFd<'a>`. +pub struct Borrowing<'a> { + _phantom: PhantomData>, +} + +impl<'a> Context for Borrowing<'a> { + type Data = BorrowedFd<'a>; + type Target = BorrowedFd<'a>; + + #[inline] + fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> { + Ref::new(data) + } + + #[inline] + fn encode(&self, target: Ref<'_, Self::Target>) -> u64 { + target.as_raw_fd() as u64 + } + + #[inline] + unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> { + Ref::new(BorrowedFd::<'a>::borrow_raw(raw as RawFd)) + } + + #[inline] + fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data { + target.consume() + } +} + +/// A type implementing [`Context`] where the `Data` type is `T`, a type +/// implementing `From` and `From for OwnedFd`. +/// +/// This may be used with [`OwnedFd`], or higher-level types like +/// [`std::fs::File`] or [`std::net::TcpStream`]. +#[cfg(not(feature = "rustc-dep-of-std"))] +pub struct Owning<'context, T: Into + From> { + _phantom: PhantomData<&'context T>, +} + +#[cfg(not(feature = "rustc-dep-of-std"))] +impl<'context, T: Into + From> Owning<'context, T> { + /// Creates a new empty `Owning`. + #[allow(clippy::new_without_default)] // This is a specialized type that doesn't need to be generically constructible. + #[inline] + pub fn new() -> Self { + Self { + _phantom: PhantomData, + } + } +} + +#[cfg(not(feature = "rustc-dep-of-std"))] +impl<'context, T: AsFd + Into + From> Context for Owning<'context, T> { + type Data = T; + type Target = BorrowedFd<'context>; + + #[inline] + fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> { + let fd: OwnedFd = data.into(); + let raw_fd = fd.into_raw_fd(); + // Safety: `epoll` will assign ownership of the file descriptor to the + // kernel epoll object. We use `Into`+`IntoRawFd` to consume + // the `Data` and extract the raw file descriptor and then "borrow" it + // with `borrow_raw` knowing that the borrow won't outlive the + // kernel epoll object. + unsafe { Ref::new(BorrowedFd::<'context>::borrow_raw(raw_fd)) } + } + + #[inline] + fn encode(&self, target: Ref<'_, Self::Target>) -> u64 { + target.as_fd().as_raw_fd() as u64 + } + + #[inline] + unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> { + Ref::new(BorrowedFd::<'context>::borrow_raw(raw as RawFd)) + } + + #[inline] + fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data { + // The file descriptor was held by the kernel epoll object and is now + // being released, so we can create a new `OwnedFd` that assumes + // ownership. + let raw_fd = target.consume().as_raw_fd(); + unsafe { T::from(OwnedFd::from_raw_fd(raw_fd).into()) } + } +} + +/// An "epoll", an interface to an OS object allowing one to repeatedly wait +/// for events from a set of file descriptors efficiently. +pub struct Epoll { + epoll_fd: OwnedFd, + context: Context, +} + +impl Epoll { + /// `epoll_create1(flags)`—Creates a new `Epoll`. + /// + /// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file + /// descriptor from being implicitly passed across `exec` boundaries. + #[inline] + #[doc(alias = "epoll_create1")] + pub fn new(flags: CreateFlags, context: Context) -> io::Result { + // Safety: We're calling `epoll_create1` via FFI and we know how it + // behaves. + unsafe { + Ok(Self { + epoll_fd: ret_owned_fd(c::epoll_create1(flags.bits()))?, + context, + }) + } + } + + /// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an + /// `Epoll`. + /// + /// This registers interest in any of the events set in `events` occurring + /// on the file descriptor associated with `data`. + #[doc(alias = "epoll_ctl")] + pub fn add( + &self, + data: Context::Data, + event_flags: EventFlags, + ) -> io::Result> { + // Safety: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + let target = self.context.acquire(data); + let raw_fd = target.as_fd().as_raw_fd(); + let encoded = self.context.encode(target); + ret(c::epoll_ctl( + self.epoll_fd.as_fd().as_raw_fd(), + c::EPOLL_CTL_ADD, + raw_fd, + &mut c::epoll_event { + events: event_flags.bits(), + r#u64: encoded, + }, + ))?; + Ok(self.context.decode(encoded)) + } + } + + /// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in + /// this `Epoll`. + /// + /// This sets the events of interest with `target` to `events`. + #[doc(alias = "epoll_ctl")] + pub fn mod_( + &self, + target: Ref<'_, Context::Target>, + event_flags: EventFlags, + ) -> io::Result<()> { + let raw_fd = target.as_fd().as_raw_fd(); + let encoded = self.context.encode(target); + // Safety: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + ret(c::epoll_ctl( + self.epoll_fd.as_fd().as_raw_fd(), + c::EPOLL_CTL_MOD, + raw_fd, + &mut c::epoll_event { + events: event_flags.bits(), + r#u64: encoded, + }, + )) + } + } + + /// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in + /// this `Epoll`. + /// + /// This also returns the owning `Data`. + #[doc(alias = "epoll_ctl")] + pub fn del(&self, target: Ref<'_, Context::Target>) -> io::Result { + // Safety: We're calling `epoll_ctl` via FFI and we know how it + // behaves. + unsafe { + let raw_fd = target.as_fd().as_raw_fd(); + ret(c::epoll_ctl( + self.epoll_fd.as_fd().as_raw_fd(), + c::EPOLL_CTL_DEL, + raw_fd, + null_mut(), + ))?; + } + Ok(self.context.release(target)) + } + + /// `epoll_wait(self, events, timeout)`—Waits for registered events of + /// interest. + /// + /// For each event of interest, an element is written to `events`. On + /// success, this returns the number of written elements. + #[doc(alias = "epoll_wait")] + pub fn wait<'context>( + &'context self, + event_list: &mut EventVec<'context, Context>, + timeout: c::c_int, + ) -> io::Result<()> { + // Safety: We're calling `epoll_wait` via FFI and we know how it + // behaves. + unsafe { + event_list.events.set_len(0); + let nfds = ret_u32(c::epoll_wait( + self.epoll_fd.as_fd().as_raw_fd(), + event_list.events.as_mut_ptr().cast::(), + event_list.events.capacity().try_into().unwrap_or(i32::MAX), + timeout, + ))?; + event_list.events.set_len(nfds as usize); + event_list.context = &self.context; + } + + Ok(()) + } +} + +#[cfg(not(feature = "rustc-dep-of-std"))] +impl<'context, T: AsFd + Into + From> AsRawFd for Epoll> { + fn as_raw_fd(&self) -> RawFd { + self.epoll_fd.as_raw_fd() + } +} + +#[cfg(not(feature = "rustc-dep-of-std"))] +impl<'context, T: AsFd + Into + From> IntoRawFd for Epoll> { + fn into_raw_fd(self) -> RawFd { + self.epoll_fd.into_raw_fd() + } +} + +#[cfg(not(feature = "rustc-dep-of-std"))] +impl<'context, T: AsFd + Into + From> FromRawFd for Epoll> { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self { + epoll_fd: OwnedFd::from_raw_fd(fd), + context: Owning::new(), + } + } +} + +#[cfg(not(feature = "rustc-dep-of-std"))] +impl<'context, T: AsFd + Into + From> AsFd for Epoll> { + fn as_fd(&self) -> BorrowedFd<'_> { + self.epoll_fd.as_fd() + } +} + +#[cfg(not(feature = "rustc-dep-of-std"))] +impl<'context, T: AsFd + Into + From> From>> + for OwnedFd +{ + fn from(epoll: Epoll>) -> Self { + epoll.epoll_fd + } +} + +#[cfg(not(feature = "rustc-dep-of-std"))] +impl<'context, T: AsFd + Into + From> From + for Epoll> +{ + fn from(fd: OwnedFd) -> Self { + Self { + epoll_fd: fd, + context: Owning::new(), + } + } +} + +/// An iterator over the `Event`s in an `EventVec`. +pub struct Iter<'context, Context: self::Context> { + iter: core::slice::Iter<'context, Event>, + context: *const Context, + _phantom: PhantomData<&'context Context>, +} + +impl<'context, Context: self::Context> Iterator for Iter<'context, Context> { + type Item = (EventFlags, Ref<'context, Context::Target>); + + fn next(&mut self) -> Option { + // Safety: `self.context` is guaranteed to be valid because we hold + // `'context` for it. And we know this event is associated with this + // context because `wait` sets both. + self.iter.next().map(|event| { + (event.event_flags, unsafe { + (*self.context).decode(event.encoded) + }) + }) + } +} + +/// A record of an event that occurred. +#[repr(C)] +#[cfg_attr( + any( + all( + target_arch = "x86", + not(target_env = "musl"), + not(target_os = "android"), + ), + target_arch = "x86_64", + ), + repr(packed) +)] +struct Event { + // Match the layout of `c::epoll_event`. We just use a `u64` instead of + // the full union; `Context` implementations will simply need to deal with + // casting the value into and out of the `u64` themselves. + event_flags: EventFlags, + encoded: u64, +} + +/// A vector of `Event`s, plus context for interpreting them. +pub struct EventVec<'context, Context: self::Context> { + events: Vec, + context: *const Context, + _phantom: PhantomData<&'context Context>, +} + +impl<'context, Context: self::Context> EventVec<'context, Context> { + /// Constructs an `EventVec` with memory for `capacity` `Event`s. + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + Self { + events: Vec::with_capacity(capacity), + context: null(), + _phantom: PhantomData, + } + } + + /// Returns the current `Event` capacity of this `EventVec`. + #[inline] + pub fn capacity(&self) -> usize { + self.events.capacity() + } + + /// Reserves enough memory for at least `additional` more `Event`s. + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.events.reserve(additional); + } + + /// Reserves enough memory for exactly `additional` more `Event`s. + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.events.reserve_exact(additional); + } + + /// Clears all the `Events` out of this `EventVec`. + #[inline] + pub fn clear(&mut self) { + self.events.clear(); + } + + /// Shrinks the capacity of this `EventVec` as much as possible. + #[inline] + pub fn shrink_to_fit(&mut self) { + self.events.shrink_to_fit(); + } + + /// Returns an iterator over the `Event`s in this `EventVec`. + #[inline] + pub fn iter(&self) -> Iter<'_, Context> { + Iter { + iter: self.events.iter(), + context: self.context, + _phantom: PhantomData, + } + } + + /// Returns the number of `Event`s logically contained in this `EventVec`. + #[inline] + pub fn len(&mut self) -> usize { + self.events.len() + } + + /// Tests whether this `EventVec` is logically empty. + #[inline] + pub fn is_empty(&mut self) -> bool { + self.events.is_empty() + } +} + +impl<'context, Context: self::Context> IntoIterator for &'context EventVec<'context, Context> { + type IntoIter = Iter<'context, Context>; + type Item = (EventFlags, Ref<'context, Context::Target>); + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} diff --git a/vendor/rustix/src/backend/libc/io/errno.rs b/vendor/rustix/src/backend/libc/io/errno.rs new file mode 100644 index 000000000..131709e0c --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/errno.rs @@ -0,0 +1,1106 @@ +//! The `rustix` `Errno` type. +//! +//! This type holds an OS error code, which conceptually corresponds to an +//! `errno` value. + +use super::super::c; +use libc_errno::errno; + +/// The error type for `rustix` APIs. +/// +/// This is similar to `std::io::Error`, but only holds an OS error code, +/// and no extra error value. +#[repr(transparent)] +#[doc(alias = "errno")] +#[derive(Eq, PartialEq, Hash, Copy, Clone)] +pub struct Errno(pub(crate) c::c_int); + +impl Errno { + /// `EACCES` + #[doc(alias = "ACCES")] + pub const ACCESS: Self = Self(c::EACCES); + /// `EADDRINUSE` + pub const ADDRINUSE: Self = Self(c::EADDRINUSE); + /// `EADDRNOTAVAIL` + pub const ADDRNOTAVAIL: Self = Self(c::EADDRNOTAVAIL); + /// `EADV` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const ADV: Self = Self(c::EADV); + /// `EAFNOSUPPORT` + pub const AFNOSUPPORT: Self = Self(c::EAFNOSUPPORT); + /// `EAGAIN` + pub const AGAIN: Self = Self(c::EAGAIN); + /// `EALREADY` + pub const ALREADY: Self = Self(c::EALREADY); + /// `EAUTH` + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const AUTH: Self = Self(c::EAUTH); + /// `EBADE` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const BADE: Self = Self(c::EBADE); + /// `EBADF` + pub const BADF: Self = Self(c::EBADF); + /// `EBADFD` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const BADFD: Self = Self(c::EBADFD); + /// `EBADMSG` + #[cfg(not(windows))] + pub const BADMSG: Self = Self(c::EBADMSG); + /// `EBADR` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const BADR: Self = Self(c::EBADR); + /// `EBADRPC` + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const BADRPC: Self = Self(c::EBADRPC); + /// `EBADRQC` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const BADRQC: Self = Self(c::EBADRQC); + /// `EBADSLT` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const BADSLT: Self = Self(c::EBADSLT); + /// `EBFONT` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const BFONT: Self = Self(c::EBFONT); + /// `EBUSY` + #[cfg(not(windows))] + pub const BUSY: Self = Self(c::EBUSY); + /// `ECANCELED` + pub const CANCELED: Self = Self(c::ECANCELED); + /// `ECAPMODE` + #[cfg(any(target_os = "freebsd"))] + pub const CAPMODE: Self = Self(c::ECAPMODE); + /// `ECHILD` + #[cfg(not(windows))] + pub const CHILD: Self = Self(c::ECHILD); + /// `ECHRNG` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const CHRNG: Self = Self(c::ECHRNG); + /// `ECOMM` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const COMM: Self = Self(c::ECOMM); + /// `ECONNABORTED` + pub const CONNABORTED: Self = Self(c::ECONNABORTED); + /// `ECONNREFUSED` + pub const CONNREFUSED: Self = Self(c::ECONNREFUSED); + /// `ECONNRESET` + pub const CONNRESET: Self = Self(c::ECONNRESET); + /// `EDEADLK` + #[cfg(not(windows))] + pub const DEADLK: Self = Self(c::EDEADLK); + /// `EDEADLOCK` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const DEADLOCK: Self = Self(c::EDEADLOCK); + /// `EDESTADDRREQ` + pub const DESTADDRREQ: Self = Self(c::EDESTADDRREQ); + /// `EDISCON` + #[cfg(windows)] + pub const DISCON: Self = Self(c::EDISCON); + /// `EDOM` + #[cfg(not(windows))] + pub const DOM: Self = Self(c::EDOM); + /// `EDOOFUS` + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + pub const DOOFUS: Self = Self(c::EDOOFUS); + /// `EDOTDOT` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const DOTDOT: Self = Self(c::EDOTDOT); + /// `EDQUOT` + pub const DQUOT: Self = Self(c::EDQUOT); + /// `EEXIST` + #[cfg(not(windows))] + pub const EXIST: Self = Self(c::EEXIST); + /// `EFAULT` + pub const FAULT: Self = Self(c::EFAULT); + /// `EFBIG` + #[cfg(not(windows))] + pub const FBIG: Self = Self(c::EFBIG); + /// `EFTYPE` + #[cfg(any( + target_env = "newlib", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const FTYPE: Self = Self(c::EFTYPE); + /// `EHOSTDOWN` + #[cfg(not(target_os = "wasi"))] + pub const HOSTDOWN: Self = Self(c::EHOSTDOWN); + /// `EHOSTUNREACH` + pub const HOSTUNREACH: Self = Self(c::EHOSTUNREACH); + /// `EHWPOISON` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "wasi", + )))] + pub const HWPOISON: Self = Self(c::EHWPOISON); + /// `EIDRM` + #[cfg(not(windows))] + pub const IDRM: Self = Self(c::EIDRM); + /// `EILSEQ` + #[cfg(not(windows))] + pub const ILSEQ: Self = Self(c::EILSEQ); + /// `EINPROGRESS` + pub const INPROGRESS: Self = Self(c::EINPROGRESS); + /// `EINTR` + /// + /// For a convenient way to retry system calls that exit with `INTR`, use + /// [`retry_on_intr`]. + /// + /// [`retry_on_intr`]: crate::io::retry_on_intr + pub const INTR: Self = Self(c::EINTR); + /// `EINVAL` + pub const INVAL: Self = Self(c::EINVAL); + /// `EINVALIDPROCTABLE` + #[cfg(windows)] + pub const INVALIDPROCTABLE: Self = Self(c::EINVALIDPROCTABLE); + /// `EINVALIDPROVIDER` + #[cfg(windows)] + pub const INVALIDPROVIDER: Self = Self(c::EINVALIDPROVIDER); + /// `EIO` + #[cfg(not(windows))] + pub const IO: Self = Self(c::EIO); + /// `EISCONN` + pub const ISCONN: Self = Self(c::EISCONN); + /// `EISDIR` + #[cfg(not(windows))] + pub const ISDIR: Self = Self(c::EISDIR); + /// `EISNAM` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const ISNAM: Self = Self(c::EISNAM); + /// `EKEYEXPIRED` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const KEYEXPIRED: Self = Self(c::EKEYEXPIRED); + /// `EKEYREJECTED` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const KEYREJECTED: Self = Self(c::EKEYREJECTED); + /// `EKEYREVOKED` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const KEYREVOKED: Self = Self(c::EKEYREVOKED); + /// `EL2HLT` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const L2HLT: Self = Self(c::EL2HLT); + /// `EL2NSYNC` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const L2NSYNC: Self = Self(c::EL2NSYNC); + /// `EL3HLT` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const L3HLT: Self = Self(c::EL3HLT); + /// `EL3RST` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const L3RST: Self = Self(c::EL3RST); + /// `ELIBACC` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const LIBACC: Self = Self(c::ELIBACC); + /// `ELIBBAD` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const LIBBAD: Self = Self(c::ELIBBAD); + /// `ELIBEXEC` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const LIBEXEC: Self = Self(c::ELIBEXEC); + /// `ELIBMAX` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const LIBMAX: Self = Self(c::ELIBMAX); + /// `ELIBSCN` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const LIBSCN: Self = Self(c::ELIBSCN); + /// `ELNRNG` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const LNRNG: Self = Self(c::ELNRNG); + /// `ELOOP` + pub const LOOP: Self = Self(c::ELOOP); + /// `EMEDIUMTYPE` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const MEDIUMTYPE: Self = Self(c::EMEDIUMTYPE); + /// `EMFILE` + pub const MFILE: Self = Self(c::EMFILE); + /// `EMLINK` + #[cfg(not(windows))] + pub const MLINK: Self = Self(c::EMLINK); + /// `EMSGSIZE` + pub const MSGSIZE: Self = Self(c::EMSGSIZE); + /// `EMULTIHOP` + #[cfg(not(any(windows, target_os = "openbsd")))] + pub const MULTIHOP: Self = Self(c::EMULTIHOP); + /// `ENAMETOOLONG` + pub const NAMETOOLONG: Self = Self(c::ENAMETOOLONG); + /// `ENAVAIL` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const NAVAIL: Self = Self(c::ENAVAIL); + /// `ENEEDAUTH` + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const NEEDAUTH: Self = Self(c::ENEEDAUTH); + /// `ENETDOWN` + pub const NETDOWN: Self = Self(c::ENETDOWN); + /// `ENETRESET` + pub const NETRESET: Self = Self(c::ENETRESET); + /// `ENETUNREACH` + pub const NETUNREACH: Self = Self(c::ENETUNREACH); + /// `ENFILE` + #[cfg(not(windows))] + pub const NFILE: Self = Self(c::ENFILE); + /// `ENOANO` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NOANO: Self = Self(c::ENOANO); + /// `ENOATTR` + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const NOATTR: Self = Self(c::ENOATTR); + /// `ENOBUFS` + pub const NOBUFS: Self = Self(c::ENOBUFS); + /// `ENOCSI` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NOCSI: Self = Self(c::ENOCSI); + /// `ENODATA` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NODATA: Self = Self(c::ENODATA); + /// `ENODEV` + #[cfg(not(windows))] + pub const NODEV: Self = Self(c::ENODEV); + /// `ENOENT` + #[cfg(not(windows))] + pub const NOENT: Self = Self(c::ENOENT); + /// `ENOEXEC` + #[cfg(not(windows))] + pub const NOEXEC: Self = Self(c::ENOEXEC); + /// `ENOKEY` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const NOKEY: Self = Self(c::ENOKEY); + /// `ENOLCK` + #[cfg(not(windows))] + pub const NOLCK: Self = Self(c::ENOLCK); + /// `ENOLINK` + #[cfg(not(any(windows, target_os = "openbsd")))] + pub const NOLINK: Self = Self(c::ENOLINK); + /// `ENOMEDIUM` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const NOMEDIUM: Self = Self(c::ENOMEDIUM); + /// `ENOMEM` + #[cfg(not(windows))] + pub const NOMEM: Self = Self(c::ENOMEM); + /// `ENOMORE` + #[cfg(windows)] + pub const NOMORE: Self = Self(c::ENOMORE); + /// `ENOMSG` + #[cfg(not(windows))] + pub const NOMSG: Self = Self(c::ENOMSG); + /// `ENONET` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NONET: Self = Self(c::ENONET); + /// `ENOPKG` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NOPKG: Self = Self(c::ENOPKG); + /// `ENOPROTOOPT` + pub const NOPROTOOPT: Self = Self(c::ENOPROTOOPT); + /// `ENOSPC` + #[cfg(not(windows))] + pub const NOSPC: Self = Self(c::ENOSPC); + /// `ENOSR` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NOSR: Self = Self(c::ENOSR); + /// `ENOSTR` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NOSTR: Self = Self(c::ENOSTR); + /// `ENOSYS` + #[cfg(not(windows))] + pub const NOSYS: Self = Self(c::ENOSYS); + /// `ENOTBLK` + #[cfg(not(any(windows, target_os = "haiku", target_os = "wasi")))] + pub const NOTBLK: Self = Self(c::ENOTBLK); + /// `ENOTCAPABLE` + #[cfg(any(target_os = "freebsd", target_os = "wasi"))] + pub const NOTCAPABLE: Self = Self(c::ENOTCAPABLE); + /// `ENOTCONN` + pub const NOTCONN: Self = Self(c::ENOTCONN); + /// `ENOTDIR` + #[cfg(not(windows))] + pub const NOTDIR: Self = Self(c::ENOTDIR); + /// `ENOTEMPTY` + pub const NOTEMPTY: Self = Self(c::ENOTEMPTY); + /// `ENOTNAM` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const NOTNAM: Self = Self(c::ENOTNAM); + /// `ENOTRECOVERABLE` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "haiku", + target_os = "netbsd" + )))] + pub const NOTRECOVERABLE: Self = Self(c::ENOTRECOVERABLE); + /// `ENOTSOCK` + pub const NOTSOCK: Self = Self(c::ENOTSOCK); + /// `ENOTSUP` + #[cfg(not(any(windows, target_os = "haiku", target_os = "redox")))] + pub const NOTSUP: Self = Self(c::ENOTSUP); + /// `ENOTTY` + #[cfg(not(windows))] + pub const NOTTY: Self = Self(c::ENOTTY); + /// `ENOTUNIQ` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const NOTUNIQ: Self = Self(c::ENOTUNIQ); + /// `ENXIO` + #[cfg(not(windows))] + pub const NXIO: Self = Self(c::ENXIO); + /// `EOPNOTSUPP` + pub const OPNOTSUPP: Self = Self(c::EOPNOTSUPP); + /// `EOVERFLOW` + #[cfg(not(windows))] + pub const OVERFLOW: Self = Self(c::EOVERFLOW); + /// `EOWNERDEAD` + #[cfg(not(any( + windows, + target_os = "haiku", + target_os = "dragonfly", + target_os = "netbsd" + )))] + pub const OWNERDEAD: Self = Self(c::EOWNERDEAD); + /// `EPERM` + #[cfg(not(windows))] + pub const PERM: Self = Self(c::EPERM); + /// `EPFNOSUPPORT` + #[cfg(not(target_os = "wasi"))] + pub const PFNOSUPPORT: Self = Self(c::EPFNOSUPPORT); + /// `EPIPE` + #[cfg(not(windows))] + pub const PIPE: Self = Self(c::EPIPE); + /// `EPROCLIM` + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const PROCLIM: Self = Self(c::EPROCLIM); + /// `EPROCUNAVAIL` + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const PROCUNAVAIL: Self = Self(c::EPROCUNAVAIL); + /// `EPROGMISMATCH` + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const PROGMISMATCH: Self = Self(c::EPROGMISMATCH); + /// `EPROGUNAVAIL` + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const PROGUNAVAIL: Self = Self(c::EPROGUNAVAIL); + /// `EPROTO` + #[cfg(not(windows))] + pub const PROTO: Self = Self(c::EPROTO); + /// `EPROTONOSUPPORT` + pub const PROTONOSUPPORT: Self = Self(c::EPROTONOSUPPORT); + /// `EPROTOTYPE` + pub const PROTOTYPE: Self = Self(c::EPROTOTYPE); + /// `EPROVIDERFAILEDINIT` + #[cfg(windows)] + pub const PROVIDERFAILEDINIT: Self = Self(c::EPROVIDERFAILEDINIT); + /// `ERANGE` + #[cfg(not(windows))] + pub const RANGE: Self = Self(c::ERANGE); + /// `EREFUSED` + #[cfg(windows)] + pub const REFUSED: Self = Self(c::EREFUSED); + /// `EREMCHG` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const REMCHG: Self = Self(c::EREMCHG); + /// `EREMOTE` + #[cfg(not(any(target_os = "haiku", target_os = "wasi")))] + pub const REMOTE: Self = Self(c::EREMOTE); + /// `EREMOTEIO` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const REMOTEIO: Self = Self(c::EREMOTEIO); + /// `ERESTART` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const RESTART: Self = Self(c::ERESTART); + /// `ERFKILL` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "wasi", + )))] + pub const RFKILL: Self = Self(c::ERFKILL); + /// `EROFS` + #[cfg(not(windows))] + pub const ROFS: Self = Self(c::EROFS); + /// `ERPCMISMATCH` + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub const RPCMISMATCH: Self = Self(c::ERPCMISMATCH); + /// `ESHUTDOWN` + #[cfg(not(target_os = "wasi"))] + pub const SHUTDOWN: Self = Self(c::ESHUTDOWN); + /// `ESOCKTNOSUPPORT` + #[cfg(not(any(target_os = "haiku", target_os = "wasi")))] + pub const SOCKTNOSUPPORT: Self = Self(c::ESOCKTNOSUPPORT); + /// `ESPIPE` + #[cfg(not(windows))] + pub const SPIPE: Self = Self(c::ESPIPE); + /// `ESRCH` + #[cfg(not(windows))] + pub const SRCH: Self = Self(c::ESRCH); + /// `ESRMNT` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const SRMNT: Self = Self(c::ESRMNT); + /// `ESTALE` + pub const STALE: Self = Self(c::ESTALE); + /// `ESTRPIPE` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const STRPIPE: Self = Self(c::ESTRPIPE); + /// `ETIME` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const TIME: Self = Self(c::ETIME); + /// `ETIMEDOUT` + pub const TIMEDOUT: Self = Self(c::ETIMEDOUT); + /// `E2BIG` + #[cfg(not(windows))] + #[doc(alias = "2BIG")] + pub const TOOBIG: Self = Self(c::E2BIG); + /// `ETOOMANYREFS` + #[cfg(not(any(target_os = "haiku", target_os = "wasi")))] + pub const TOOMANYREFS: Self = Self(c::ETOOMANYREFS); + /// `ETXTBSY` + #[cfg(not(windows))] + pub const TXTBSY: Self = Self(c::ETXTBSY); + /// `EUCLEAN` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "wasi", + )))] + pub const UCLEAN: Self = Self(c::EUCLEAN); + /// `EUNATCH` + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const UNATCH: Self = Self(c::EUNATCH); + /// `EUSERS` + #[cfg(not(any(target_os = "haiku", target_os = "wasi")))] + pub const USERS: Self = Self(c::EUSERS); + /// `EWOULDBLOCK` + pub const WOULDBLOCK: Self = Self(c::EWOULDBLOCK); + /// `EXDEV` + #[cfg(not(windows))] + pub const XDEV: Self = Self(c::EXDEV); + /// `EXFULL` + #[cfg(not(any( + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "wasi", + )))] + pub const XFULL: Self = Self(c::EXFULL); +} + +impl Errno { + /// Extract an `Errno` value from a `std::io::Error`. + /// + /// This isn't a `From` conversion because it's expected to be relatively + /// uncommon. + #[cfg(feature = "std")] + #[inline] + pub fn from_io_error(io_err: &std::io::Error) -> Option { + io_err + .raw_os_error() + .and_then(|raw| if raw != 0 { Some(Self(raw)) } else { None }) + } + + /// Extract the raw OS error number from this error. + #[inline] + pub const fn raw_os_error(self) -> i32 { + self.0 + } + + /// Construct an `Errno` from a raw OS error number. + #[inline] + pub const fn from_raw_os_error(raw: i32) -> Self { + Self(raw) + } + + pub(crate) fn last_os_error() -> Self { + Self(errno().0) + } +} diff --git a/vendor/rustix/src/backend/libc/io/io_slice.rs b/vendor/rustix/src/backend/libc/io/io_slice.rs new file mode 100644 index 000000000..de1ef434c --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/io_slice.rs @@ -0,0 +1,87 @@ +//! The following is derived from Rust's +//! library/std/src/sys/unix/io.rs +//! dca3f1b786efd27be3b325ed1e01e247aa589c3b. + +#![allow(missing_docs)] + +use super::super::c; +use core::marker::PhantomData; +use core::slice; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct IoSlice<'a> { + vec: c::iovec, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { + vec: c::iovec { + iov_base: buf.as_ptr() as *mut u8 as *mut c::c_void, + iov_len: buf.len(), + }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSlice beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} + +#[repr(transparent)] +pub struct IoSliceMut<'a> { + vec: c::iovec, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { + vec: c::iovec { + iov_base: buf.as_mut_ptr() as *mut c::c_void, + iov_len: buf.len(), + }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSliceMut beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} diff --git a/vendor/rustix/src/backend/libc/io/mod.rs b/vendor/rustix/src/backend/libc/io/mod.rs new file mode 100644 index 000000000..1378adf3d --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/mod.rs @@ -0,0 +1,13 @@ +pub(crate) mod errno; +#[cfg(not(windows))] +#[cfg(not(feature = "std"))] +pub(crate) mod io_slice; +pub(crate) mod poll_fd; +#[cfg(not(windows))] +pub(crate) mod types; + +#[cfg_attr(windows, path = "windows_syscalls.rs")] +pub(crate) mod syscalls; + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub mod epoll; diff --git a/vendor/rustix/src/backend/libc/io/poll_fd.rs b/vendor/rustix/src/backend/libc/io/poll_fd.rs new file mode 100644 index 000000000..c516a9309 --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/poll_fd.rs @@ -0,0 +1,136 @@ +use super::super::c; +use super::super::conv::borrowed_fd; +#[cfg(windows)] +use super::super::fd::RawFd; +use super::super::fd::{AsFd, AsRawFd, BorrowedFd, LibcFd}; +use bitflags::bitflags; +use core::marker::PhantomData; +#[cfg(windows)] +use std::fmt; + +bitflags! { + /// `POLL*` flags for use with [`poll`]. + /// + /// [`poll`]: crate::io::poll + pub struct PollFlags: c::c_short { + /// `POLLIN` + const IN = c::POLLIN; + /// `POLLPRI` + #[cfg(not(target_os = "wasi"))] + const PRI = c::POLLPRI; + /// `POLLOUT` + const OUT = c::POLLOUT; + /// `POLLRDNORM` + #[cfg(not(target_os = "redox"))] + const RDNORM = c::POLLRDNORM; + /// `POLLWRNORM` + #[cfg(not(target_os = "redox"))] + const WRNORM = c::POLLWRNORM; + /// `POLLRDBAND` + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] + const RDBAND = c::POLLRDBAND; + /// `POLLWRBAND` + #[cfg(not(any(target_os = "redox", target_os = "wasi")))] + const WRBAND = c::POLLWRBAND; + /// `POLLERR` + const ERR = c::POLLERR; + /// `POLLHUP` + const HUP = c::POLLHUP; + /// `POLLNVAL` + const NVAL = c::POLLNVAL; + /// `POLLRDHUP` + #[cfg(all( + any(target_os = "android", target_os = "linux"), + not(any(target_arch = "sparc", target_arch = "sparc64"))), + )] + const RDHUP = c::POLLRDHUP; + } +} + +/// `struct pollfd`—File descriptor and flags for use with [`poll`]. +/// +/// [`poll`]: crate::io::poll +#[doc(alias = "pollfd")] +#[derive(Clone)] +#[cfg_attr(not(windows), derive(Debug))] +#[repr(transparent)] +pub struct PollFd<'fd> { + pollfd: c::pollfd, + _phantom: PhantomData>, +} + +#[cfg(windows)] +impl<'fd> fmt::Debug for PollFd<'fd> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("pollfd") + .field("fd", &self.pollfd.fd) + .field("events", &self.pollfd.events) + .field("revents", &self.pollfd.revents) + .finish() + } +} + +impl<'fd> PollFd<'fd> { + /// Constructs a new `PollFd` holding `fd` and `events`. + #[inline] + pub fn new(fd: &'fd Fd, events: PollFlags) -> Self { + Self::from_borrowed_fd(fd.as_fd(), events) + } + + /// Sets the contained file descriptor to `fd`. + #[inline] + pub fn set_fd(&mut self, fd: &'fd Fd) { + self.pollfd.fd = fd.as_fd().as_raw_fd() as LibcFd; + } + + /// Clears the ready events. + #[inline] + pub fn clear_revents(&mut self) { + self.pollfd.revents = 0; + } + + /// Constructs a new `PollFd` holding `fd` and `events`. + /// + /// This is the same as `new`, but can be used to avoid borrowing the + /// `BorrowedFd`, which can be tricky in situations where the `BorrowedFd` + /// is a temporary. + #[inline] + pub fn from_borrowed_fd(fd: BorrowedFd<'fd>, events: PollFlags) -> Self { + Self { + pollfd: c::pollfd { + fd: borrowed_fd(fd), + events: events.bits(), + revents: 0, + }, + _phantom: PhantomData, + } + } + + /// Returns the ready events. + #[inline] + pub fn revents(&self) -> PollFlags { + // Use `unwrap()` here because in theory we know we know all the bits + // the OS might set here, but OS's have added extensions in the past. + PollFlags::from_bits(self.pollfd.revents).unwrap() + } +} + +#[cfg(not(windows))] +impl<'fd> AsFd for PollFd<'fd> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + // Safety: Our constructors and `set_fd` require `pollfd.fd` to be + // valid for the `fd lifetime. + unsafe { BorrowedFd::borrow_raw(self.pollfd.fd) } + } +} + +#[cfg(windows)] +impl<'fd> io_lifetimes::AsSocket for PollFd<'fd> { + #[inline] + fn as_socket(&self) -> BorrowedFd<'_> { + // Safety: Our constructors and `set_fd` require `pollfd.fd` to be + // valid for the `fd lifetime. + unsafe { BorrowedFd::borrow_raw(self.pollfd.fd as RawFd) } + } +} diff --git a/vendor/rustix/src/backend/libc/io/syscalls.rs b/vendor/rustix/src/backend/libc/io/syscalls.rs new file mode 100644 index 000000000..3774e700a --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/syscalls.rs @@ -0,0 +1,533 @@ +//! libc syscalls supporting `rustix::io`. + +use super::super::c; +#[cfg(any(target_os = "android", target_os = "linux"))] +use super::super::conv::syscall_ret_owned_fd; +use super::super::conv::{ + borrowed_fd, ret, ret_c_int, ret_discarded_fd, ret_owned_fd, ret_ssize_t, +}; +use super::super::offset::{libc_pread, libc_pwrite}; +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] +use super::super::offset::{libc_preadv, libc_pwritev}; +#[cfg(all(target_os = "linux", target_env = "gnu"))] +use super::super::offset::{libc_preadv2, libc_pwritev2}; +use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; +#[cfg(not(any(target_os = "aix", target_os = "wasi")))] +use crate::io::DupFlags; +#[cfg(not(any( + target_os = "aix", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "wasi" +)))] +use crate::io::PipeFlags; +use crate::io::{self, FdFlags, IoSlice, IoSliceMut, PollFd}; +#[cfg(any(target_os = "android", target_os = "linux"))] +use crate::io::{EventfdFlags, IoSliceRaw, ReadWriteFlags, SpliceFlags}; +use core::cmp::min; +use core::convert::TryInto; +use core::mem::MaybeUninit; +#[cfg(any(target_os = "android", target_os = "linux"))] +use core::ptr; +#[cfg(all(feature = "fs", feature = "net"))] +use libc_errno::errno; + +pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result { + let nread = unsafe { + ret_ssize_t(c::read( + borrowed_fd(fd), + buf.as_mut_ptr().cast(), + min(buf.len(), READ_LIMIT), + ))? + }; + Ok(nread as usize) +} + +pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result { + let nwritten = unsafe { + ret_ssize_t(c::write( + borrowed_fd(fd), + buf.as_ptr().cast(), + min(buf.len(), READ_LIMIT), + ))? + }; + Ok(nwritten as usize) +} + +pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], offset: u64) -> io::Result { + let len = min(buf.len(), READ_LIMIT); + + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + + let nread = unsafe { + ret_ssize_t(libc_pread( + borrowed_fd(fd), + buf.as_mut_ptr().cast(), + len, + offset, + ))? + }; + Ok(nread as usize) +} + +pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result { + let len = min(buf.len(), READ_LIMIT); + + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + + let nwritten = unsafe { + ret_ssize_t(libc_pwrite( + borrowed_fd(fd), + buf.as_ptr().cast(), + len, + offset, + ))? + }; + Ok(nwritten as usize) +} + +pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut]) -> io::Result { + let nread = unsafe { + ret_ssize_t(c::readv( + borrowed_fd(fd), + bufs.as_ptr().cast::(), + min(bufs.len(), max_iov()) as c::c_int, + ))? + }; + Ok(nread as usize) +} + +pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice]) -> io::Result { + let nwritten = unsafe { + ret_ssize_t(c::writev( + borrowed_fd(fd), + bufs.as_ptr().cast::(), + min(bufs.len(), max_iov()) as c::c_int, + ))? + }; + Ok(nwritten as usize) +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] +pub(crate) fn preadv( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut], + offset: u64, +) -> io::Result { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + let nread = unsafe { + ret_ssize_t(libc_preadv( + borrowed_fd(fd), + bufs.as_ptr().cast::(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + ))? + }; + Ok(nread as usize) +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] +pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice], offset: u64) -> io::Result { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + let nwritten = unsafe { + ret_ssize_t(libc_pwritev( + borrowed_fd(fd), + bufs.as_ptr().cast::(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + ))? + }; + Ok(nwritten as usize) +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(crate) fn preadv2( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + let nread = unsafe { + ret_ssize_t(libc_preadv2( + borrowed_fd(fd), + bufs.as_ptr().cast::(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + flags.bits(), + ))? + }; + Ok(nread as usize) +} + +/// At present, `libc` only has `preadv2` defined for glibc. On other +/// ABIs, `ReadWriteFlags` has no flags defined, and we use plain `preadv`. +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "gnu")), +))] +#[inline] +pub(crate) fn preadv2( + fd: BorrowedFd<'_>, + bufs: &mut [IoSliceMut], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result { + assert!(flags.is_empty()); + preadv(fd, bufs, offset) +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(crate) fn pwritev2( + fd: BorrowedFd<'_>, + bufs: &[IoSlice], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result { + // Silently cast; we'll get `EINVAL` if the value is negative. + let offset = offset as i64; + let nwritten = unsafe { + ret_ssize_t(libc_pwritev2( + borrowed_fd(fd), + bufs.as_ptr().cast::(), + min(bufs.len(), max_iov()) as c::c_int, + offset, + flags.bits(), + ))? + }; + Ok(nwritten as usize) +} + +/// At present, `libc` only has `pwritev2` defined for glibc. On other +/// ABIs, `ReadWriteFlags` has no flags defined, and we use plain `pwritev`. +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "gnu")), +))] +#[inline] +pub(crate) fn pwritev2( + fd: BorrowedFd<'_>, + bufs: &[IoSlice], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result { + assert!(flags.is_empty()); + pwritev(fd, bufs, offset) +} + +// These functions are derived from Rust's library/std/src/sys/unix/fd.rs at +// revision a77da2d454e6caa227a85b16410b95f93495e7e0. + +// 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 greater than +// `SSIZE_MAX` the result is "unspecified". +// +// On macOS, however, apparently the 64-bit libc is either buggy or +// intentionally showing odd behavior by rejecting any read with a size larger +// than or equal to `INT_MAX`. To handle both of these the read size is capped +// on both platforms. +#[cfg(target_os = "macos")] +const READ_LIMIT: usize = c::c_int::MAX as usize - 1; +#[cfg(not(target_os = "macos"))] +const READ_LIMIT: usize = c::ssize_t::MAX as usize; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +const fn max_iov() -> usize { + c::IOV_MAX as usize +} + +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] +const fn max_iov() -> usize { + c::UIO_MAXIOV as usize +} + +#[cfg(not(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +)))] +const fn max_iov() -> usize { + 16 // The minimum value required by POSIX. +} + +pub(crate) unsafe fn close(raw_fd: RawFd) { + let _ = c::close(raw_fd as c::c_int); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result { + unsafe { syscall_ret_owned_fd(c::syscall(c::SYS_eventfd2, initval, flags.bits())) } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub(crate) fn ioctl_blksszget(fd: BorrowedFd) -> io::Result { + let mut result = MaybeUninit::::uninit(); + unsafe { + ret(c::ioctl(borrowed_fd(fd), c::BLKSSZGET, result.as_mut_ptr()))?; + Ok(result.assume_init() as u32) + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result { + let mut result = MaybeUninit::::uninit(); + unsafe { + ret(c::ioctl( + borrowed_fd(fd), + c::BLKPBSZGET, + result.as_mut_ptr(), + ))?; + Ok(result.assume_init() as u32) + } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn ioctl_fionread(fd: BorrowedFd<'_>) -> io::Result { + let mut nread = MaybeUninit::::uninit(); + unsafe { + ret(c::ioctl(borrowed_fd(fd), c::FIONREAD, nread.as_mut_ptr()))?; + // `FIONREAD` returns the number of bytes silently casted to a `c_int`, + // even when this is lossy. The best we can do is convert it back to a + // `u64` without sign-extending it back first. + Ok(u64::from(nread.assume_init() as c::c_uint)) + } +} + +pub(crate) fn ioctl_fionbio(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + unsafe { + let data = value as c::c_int; + ret(c::ioctl(borrowed_fd(fd), c::FIONBIO, &data)) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[cfg(all(feature = "fs", feature = "net"))] +pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { + let (mut read, mut write) = crate::fs::fd::_is_file_read_write(fd)?; + let mut not_socket = false; + if read { + // Do a `recv` with `PEEK` and `DONTWAIT` for 1 byte. A 0 indicates + // the read side is shut down; an `EWOULDBLOCK` indicates the read + // side is still open. + match unsafe { + c::recv( + borrowed_fd(fd), + MaybeUninit::<[u8; 1]>::uninit() + .as_mut_ptr() + .cast::(), + 1, + c::MSG_PEEK | c::MSG_DONTWAIT, + ) + } { + 0 => read = false, + -1 => { + #[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK` + match errno().0 { + c::EAGAIN | c::EWOULDBLOCK => (), + c::ENOTSOCK => not_socket = true, + err => return Err(io::Errno(err)), + } + } + _ => (), + } + } + if write && !not_socket { + // Do a `send` with `DONTWAIT` for 0 bytes. An `EPIPE` indicates + // the write side is shut down. + if unsafe { c::send(borrowed_fd(fd), [].as_ptr(), 0, c::MSG_DONTWAIT) } == -1 { + #[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK` + match errno().0 { + c::EAGAIN | c::EWOULDBLOCK => (), + c::ENOTSOCK => (), + c::EPIPE => write = false, + err => return Err(io::Errno(err)), + } + } + } + Ok((read, write)) +} + +#[cfg(target_os = "wasi")] +#[cfg(all(feature = "fs", feature = "net"))] +pub(crate) fn is_read_write(_fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { + todo!("Implement is_read_write for WASI in terms of fd_fdstat_get"); +} + +pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result { + unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFD)).map(FdFlags::from_bits_truncate) } +} + +pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> { + unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETFD, flags.bits())) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result { + unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD_CLOEXEC, min)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result { + unsafe { ret_owned_fd(c::dup(borrowed_fd(fd))) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> { + unsafe { ret_discarded_fd(c::dup2(borrowed_fd(fd), borrowed_fd(new.as_fd()))) } +} + +#[cfg(not(any( + target_os = "aix", + target_os = "android", + target_os = "dragonfly", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "wasi", +)))] +pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> { + unsafe { + ret_discarded_fd(c::dup3( + borrowed_fd(fd), + borrowed_fd(new.as_fd()), + flags.bits(), + )) + } +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "redox", +))] +pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, _flags: DupFlags) -> io::Result<()> { + // Android 5.0 has `dup3`, but libc doesn't have bindings. Emulate it + // using `dup2`. We don't need to worry about the difference between + // `dup2` and `dup3` when the file descriptors are equal because we + // have an `&mut OwnedFd` which means `fd` doesn't alias it. + dup2(fd, new) +} + +#[cfg(any(target_os = "ios", target_os = "macos"))] +pub(crate) fn ioctl_fioclex(fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { ret(c::ioctl(borrowed_fd(fd), c::FIOCLEX)) } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub(crate) fn ioctl_tiocexcl(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCEXCL as _)) } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub(crate) fn ioctl_tiocnxcl(fd: BorrowedFd) -> io::Result<()> { + unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCNXCL as _)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn pipe() -> io::Result<(OwnedFd, OwnedFd)> { + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(c::pipe(result.as_mut_ptr().cast::()))?; + let [p0, p1] = result.assume_init(); + Ok((p0, p1)) + } +} + +#[cfg(not(any( + target_os = "aix", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "wasi" +)))] +pub(crate) fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> { + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(c::pipe2(result.as_mut_ptr().cast::(), flags.bits()))?; + let [p0, p1] = result.assume_init(); + Ok((p0, p1)) + } +} + +#[inline] +pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result { + let nfds = fds + .len() + .try_into() + .map_err(|_convert_err| io::Errno::INVAL)?; + + ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) }) + .map(|nready| nready as usize) +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub fn splice( + fd_in: BorrowedFd, + off_in: Option<&mut u64>, + fd_out: BorrowedFd, + off_out: Option<&mut u64>, + len: usize, + flags: SpliceFlags, +) -> io::Result { + let off_in = off_in + .map(|off| (off as *mut u64).cast()) + .unwrap_or(ptr::null_mut()); + + let off_out = off_out + .map(|off| (off as *mut u64).cast()) + .unwrap_or(ptr::null_mut()); + + ret_ssize_t(unsafe { + c::splice( + borrowed_fd(fd_in), + off_in, + borrowed_fd(fd_out), + off_out, + len, + flags.bits(), + ) + }) + .map(|spliced| spliced as usize) +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub unsafe fn vmsplice( + fd: BorrowedFd, + bufs: &[IoSliceRaw], + flags: SpliceFlags, +) -> io::Result { + ret_ssize_t(c::vmsplice( + borrowed_fd(fd), + bufs.as_ptr().cast::(), + min(bufs.len(), max_iov()), + flags.bits(), + )) + .map(|spliced| spliced as usize) +} diff --git a/vendor/rustix/src/backend/libc/io/types.rs b/vendor/rustix/src/backend/libc/io/types.rs new file mode 100644 index 000000000..46d5f6332 --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/types.rs @@ -0,0 +1,164 @@ +use super::super::c; +use bitflags::bitflags; +#[cfg(any(target_os = "android", target_os = "linux"))] +use core::marker::PhantomData; + +bitflags! { + /// `FD_*` constants for use with [`fcntl_getfd`] and [`fcntl_setfd`]. + /// + /// [`fcntl_getfd`]: crate::io::fcntl_getfd + /// [`fcntl_setfd`]: crate::io::fcntl_setfd + pub struct FdFlags: c::c_int { + /// `FD_CLOEXEC` + const CLOEXEC = c::FD_CLOEXEC; + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +bitflags! { + /// `RWF_*` constants for use with [`preadv2`] and [`pwritev2`]. + /// + /// [`preadv2`]: crate::io::preadv2 + /// [`pwritev2`]: crate::io::pwritev + pub struct ReadWriteFlags: c::c_int { + /// `RWF_DSYNC` (since Linux 4.7) + #[cfg(all(target_os = "linux", target_env = "gnu"))] + const DSYNC = c::RWF_DSYNC; + /// `RWF_HIPRI` (since Linux 4.6) + #[cfg(all(target_os = "linux", target_env = "gnu"))] + const HIPRI = c::RWF_HIPRI; + /// `RWF_SYNC` (since Linux 4.7) + #[cfg(all(target_os = "linux", target_env = "gnu"))] + const SYNC = c::RWF_SYNC; + /// `RWF_NOWAIT` (since Linux 4.14) + #[cfg(all(target_os = "linux", target_env = "gnu"))] + const NOWAIT = c::RWF_NOWAIT; + /// `RWF_APPEND` (since Linux 4.16) + #[cfg(all(target_os = "linux", target_env = "gnu"))] + const APPEND = c::RWF_APPEND; + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +bitflags! { + /// `SPLICE_F_*` constants for use with [`splice`] and [`vmsplice`]. + pub struct SpliceFlags: c::c_uint { + /// `SPLICE_F_MOVE` + const MOVE = c::SPLICE_F_MOVE; + /// `SPLICE_F_NONBLOCK` + const NONBLOCK = c::SPLICE_F_NONBLOCK; + /// `SPLICE_F_MORE` + const MORE = c::SPLICE_F_MORE; + /// `SPLICE_F_GIFT` + const GIFT = c::SPLICE_F_GIFT; + } +} + +#[cfg(not(target_os = "wasi"))] +bitflags! { + /// `O_*` constants for use with [`dup2`]. + /// + /// [`dup2`]: crate::io::dup2 + pub struct DupFlags: c::c_int { + /// `O_CLOEXEC` + #[cfg(not(any( + target_os = "android", + target_os = "ios", + target_os = "macos", + target_os = "redox", + )))] // Android 5.0 has dup3, but libc doesn't have bindings + const CLOEXEC = c::O_CLOEXEC; + } +} + +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "wasi")))] +bitflags! { + /// `O_*` constants for use with [`pipe_with`]. + /// + /// [`pipe_with`]: crate::io::pipe_with + pub struct PipeFlags: c::c_int { + /// `O_CLOEXEC` + const CLOEXEC = c::O_CLOEXEC; + /// `O_DIRECT` + #[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + )))] + const DIRECT = c::O_DIRECT; + /// `O_NONBLOCK` + const NONBLOCK = c::O_NONBLOCK; + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +bitflags! { + /// `EFD_*` flags for use with [`eventfd`]. + /// + /// [`eventfd`]: crate::io::eventfd + pub struct EventfdFlags: c::c_int { + /// `EFD_CLOEXEC` + const CLOEXEC = c::EFD_CLOEXEC; + /// `EFD_NONBLOCK` + const NONBLOCK = c::EFD_NONBLOCK; + /// `EFD_SEMAPHORE` + const SEMAPHORE = c::EFD_SEMAPHORE; + } +} + +/// `PIPE_BUF`—The maximum size of a write to a pipe guaranteed to be atomic. +#[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "redox", + target_os = "solaris", + target_os = "wasi", +)))] +pub const PIPE_BUF: usize = c::PIPE_BUF; + +#[cfg(not(any(windows, target_os = "redox")))] +pub(crate) const AT_FDCWD: c::c_int = c::AT_FDCWD; +#[cfg(not(windows))] +pub(crate) const STDIN_FILENO: c::c_int = c::STDIN_FILENO; +#[cfg(not(windows))] +pub(crate) const STDOUT_FILENO: c::c_int = c::STDOUT_FILENO; +#[cfg(not(windows))] +pub(crate) const STDERR_FILENO: c::c_int = c::STDERR_FILENO; + +/// A buffer type used with `vmsplice`. +/// It is guaranteed to be ABI compatible with the iovec type on Unix platforms and WSABUF on Windows. +/// Unlike `IoSlice` and `IoSliceMut` it is semantically like a raw pointer, +/// and therefore can be shared or mutated as needed. +#[cfg(any(target_os = "android", target_os = "linux"))] +#[repr(transparent)] +pub struct IoSliceRaw<'a> { + _buf: c::iovec, + _lifetime: PhantomData<&'a ()>, +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +impl<'a> IoSliceRaw<'a> { + /// Creates a new IoSlice wrapping a byte slice. + pub fn from_slice(buf: &'a [u8]) -> Self { + IoSliceRaw { + _buf: c::iovec { + iov_base: buf.as_ptr() as *mut u8 as *mut c::c_void, + iov_len: buf.len() as _, + }, + _lifetime: PhantomData, + } + } + + /// Creates a new IoSlice wrapping a mutable byte slice. + pub fn from_slice_mut(buf: &'a mut [u8]) -> Self { + IoSliceRaw { + _buf: c::iovec { + iov_base: buf.as_mut_ptr() as *mut c::c_void, + iov_len: buf.len() as _, + }, + _lifetime: PhantomData, + } + } +} diff --git a/vendor/rustix/src/backend/libc/io/windows_syscalls.rs b/vendor/rustix/src/backend/libc/io/windows_syscalls.rs new file mode 100644 index 000000000..4c6e86f94 --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/windows_syscalls.rs @@ -0,0 +1,39 @@ +//! Windows system calls in the `io` module. + +use super::super::c; +use super::super::conv::{borrowed_fd, ret, ret_c_int}; +use super::super::fd::LibcFd; +use crate::fd::{BorrowedFd, RawFd}; +use crate::io; +use crate::io::PollFd; +use core::convert::TryInto; +use core::mem::MaybeUninit; + +pub(crate) unsafe fn close(raw_fd: RawFd) { + let _ = c::close(raw_fd as LibcFd); +} + +pub(crate) fn ioctl_fionread(fd: BorrowedFd<'_>) -> io::Result { + let mut nread = MaybeUninit::::uninit(); + unsafe { + ret(c::ioctl(borrowed_fd(fd), c::FIONREAD, nread.as_mut_ptr()))?; + Ok(u64::from(nread.assume_init())) + } +} + +pub(crate) fn ioctl_fionbio(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + unsafe { + let mut data = value as c::c_uint; + ret(c::ioctl(borrowed_fd(fd), c::FIONBIO, &mut data)) + } +} + +pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result { + let nfds = fds + .len() + .try_into() + .map_err(|_convert_err| io::Errno::INVAL)?; + + ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) }) + .map(|nready| nready as usize) +} -- cgit v1.2.3