diff options
Diffstat (limited to 'vendor/rustix/src/io')
-rw-r--r-- | vendor/rustix/src/io/close.rs | 41 | ||||
-rw-r--r-- | vendor/rustix/src/io/dup.rs | 80 | ||||
-rw-r--r-- | vendor/rustix/src/io/errno.rs | 85 | ||||
-rw-r--r-- | vendor/rustix/src/io/eventfd.rs | 16 | ||||
-rw-r--r-- | vendor/rustix/src/io/fd/mod.rs | 17 | ||||
-rw-r--r-- | vendor/rustix/src/io/fd/owned.rs | 252 | ||||
-rw-r--r-- | vendor/rustix/src/io/fd/raw.rs | 159 | ||||
-rw-r--r-- | vendor/rustix/src/io/ioctl.rs | 99 | ||||
-rw-r--r-- | vendor/rustix/src/io/is_read_write.rs | 16 | ||||
-rw-r--r-- | vendor/rustix/src/io/mod.rs | 74 | ||||
-rw-r--r-- | vendor/rustix/src/io/owned_fd.rs | 272 | ||||
-rw-r--r-- | vendor/rustix/src/io/pipe.rs | 53 | ||||
-rw-r--r-- | vendor/rustix/src/io/poll.rs | 20 | ||||
-rw-r--r-- | vendor/rustix/src/io/procfs.rs | 482 | ||||
-rw-r--r-- | vendor/rustix/src/io/read_write.rs | 170 | ||||
-rw-r--r-- | vendor/rustix/src/io/seek_from.rs | 30 | ||||
-rw-r--r-- | vendor/rustix/src/io/stdio.rs | 194 |
17 files changed, 2060 insertions, 0 deletions
diff --git a/vendor/rustix/src/io/close.rs b/vendor/rustix/src/io/close.rs new file mode 100644 index 000000000..2116f53bd --- /dev/null +++ b/vendor/rustix/src/io/close.rs @@ -0,0 +1,41 @@ +//! The unsafe `close` for raw file descriptors. +//! +//! # Safety +//! +//! Operating on raw file descriptors is unsafe. +#![allow(unsafe_code)] + +use crate::imp; +use imp::fd::RawFd; + +/// `close(raw_fd)`—Closes a `RawFd` directly. +/// +/// Most users won't need to use this, as `OwnedFd` automatically closes its +/// file descriptor on `Drop`. +/// +/// This function does not return a `Result`, as it is the [responsibility] of +/// filesystem designers to not return errors from `close`. Users who chose to +/// use NFS or similar filesystems should take care to monitor for problems +/// externally. +/// +/// [responsibility]: https://lwn.net/Articles/576518/ +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html +/// [Linux]: https://man7.org/linux/man-pages/man2/close.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/close.2.html#//apple_ref/doc/man/2/close +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket +/// +/// # Safety +/// +/// This function takes a `RawFd`, which must be valid before the call, and is +/// not valid after the call. +#[inline] +pub unsafe fn close(raw_fd: RawFd) { + imp::io::syscalls::close(raw_fd) +} diff --git a/vendor/rustix/src/io/dup.rs b/vendor/rustix/src/io/dup.rs new file mode 100644 index 000000000..ffa0401f2 --- /dev/null +++ b/vendor/rustix/src/io/dup.rs @@ -0,0 +1,80 @@ +//! Functions which duplicate file descriptors. + +use crate::imp; +use crate::io::{self, OwnedFd}; +use imp::fd::AsFd; + +#[cfg(not(target_os = "wasi"))] +pub use imp::io::types::DupFlags; + +/// `dup(fd)`—Creates a new `OwnedFd` instance that shares the same +/// underlying [file description] as `fd`. +/// +/// This function does not set the `O_CLOEXEC` flag. To do a `dup` that does +/// set `O_CLOEXEC`, use [`fcntl_dupfd_cloexec`]. +/// +/// POSIX guarantees that `dup` will use the lowest unused file descriptor, +/// however it is not safe in general to rely on this, as file descriptors may +/// be unexpectedly allocated on other threads or in libraries. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [file description]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_258 +/// [`fcntl_dupfd_cloexec`]: crate::fs::fcntl_dupfd_cloexec +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html +/// [Linux]: https://man7.org/linux/man-pages/man2/dup.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/dup.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn dup<Fd: AsFd>(fd: Fd) -> io::Result<OwnedFd> { + imp::io::syscalls::dup(fd.as_fd()) +} + +/// `dup2(fd, new)`—Changes the [file description] of a file descriptor. +/// +/// `dup2` conceptually closes `new` and then sets the file description for +/// `new` to be the same as the one for `fd`. This is a very unusual operation, +/// and should only be used on file descriptors where you know how `new` will +/// be subsequently used. +/// +/// This function does not set the `O_CLOEXEC` flag. To do a `dup2` that does +/// set `O_CLOEXEC`, use [`dup3`] with [`DupFlags::CLOEXEC`] on platforms which +/// support it, or [`fcntl_dupfd_cloexec`] +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [file description]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_258 +/// [`fcntl_dupfd_cloexec`]: crate::fs::fcntl_dupfd_cloexec +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup2.html +/// [Linux]: https://man7.org/linux/man-pages/man2/dup2.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/dup2.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn dup2<Fd: AsFd>(fd: Fd, new: &mut OwnedFd) -> io::Result<()> { + imp::io::syscalls::dup2(fd.as_fd(), new) +} + +/// `dup3(fd, new, flags)`—Changes the [file description] of a file +/// descriptor, with flags. +/// +/// `dup3` is the same as [`dup2`] but adds an additional flags operand, and it +/// fails in the case that `fd` and `new` have the same file descriptor value. +/// This additional difference is the reason this function isn't named +/// `dup2_with`. +/// +/// # References +/// - [Linux] +/// +/// [file description]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_258 +/// [Linux]: https://man7.org/linux/man-pages/man2/dup3.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn dup3<Fd: AsFd>(fd: Fd, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> { + imp::io::syscalls::dup3(fd.as_fd(), new, flags) +} diff --git a/vendor/rustix/src/io/errno.rs b/vendor/rustix/src/io/errno.rs new file mode 100644 index 000000000..84ced6a37 --- /dev/null +++ b/vendor/rustix/src/io/errno.rs @@ -0,0 +1,85 @@ +//! The `Errno` type, which is a minimal wrapper around an error code. +//! +//! We define the error constants as individual `const`s instead of an +//! enum because we may not know about all of the host's error values +//! and we don't want unrecognized values to create UB. + +use crate::imp; +use core::{fmt, result}; +#[cfg(feature = "std")] +use std::error; + +/// A specialized [`Result`] type for `rustix` APIs. +/// +/// [`Result`]: core::result::Result +pub type Result<T> = result::Result<T, Errno>; + +/// `errno`—An error code. +/// +/// 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. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/errno.html +/// [Linux]: https://man7.org/linux/man-pages/man3/errno.3.html +pub use imp::io::errno::Errno; + +impl Errno { + /// Shorthand for `std::io::Error::from(self).kind()`. + #[cfg(feature = "std")] + #[inline] + pub fn kind(self) -> std::io::ErrorKind { + std::io::Error::from(self).kind() + } +} + +impl fmt::Display for Errno { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + #[cfg(feature = "std")] + { + std::io::Error::from(*self).fmt(fmt) + } + #[cfg(not(feature = "std"))] + { + write!(fmt, "os error {}", self.raw_os_error()) + } + } +} + +impl fmt::Debug for Errno { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + #[cfg(feature = "std")] + { + std::io::Error::from(*self).fmt(fmt) + } + #[cfg(not(feature = "std"))] + { + write!(fmt, "os error {}", self.raw_os_error()) + } + } +} + +#[cfg(feature = "std")] +impl error::Error for Errno {} + +#[cfg(feature = "std")] +impl From<Errno> for std::io::Error { + #[inline] + fn from(err: Errno) -> Self { + Self::from_raw_os_error(err.raw_os_error() as _) + } +} + +/// Call `f` until it either succeeds or fails other than [`Errno::INTR`]. +#[inline] +pub fn retry_on_intr<T, F: FnMut() -> Result<T>>(mut f: F) -> Result<T> { + loop { + match f() { + Err(Errno::INTR) => (), + result => return result, + } + } +} diff --git a/vendor/rustix/src/io/eventfd.rs b/vendor/rustix/src/io/eventfd.rs new file mode 100644 index 000000000..53e9d11f0 --- /dev/null +++ b/vendor/rustix/src/io/eventfd.rs @@ -0,0 +1,16 @@ +use crate::imp; +use crate::io::{self, OwnedFd}; + +pub use imp::io::types::EventfdFlags; + +/// `eventfd(initval, flags)`—Creates a file descriptor for event +/// notification. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/eventfd.2.html +#[inline] +pub fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { + imp::io::syscalls::eventfd(initval, flags) +} diff --git a/vendor/rustix/src/io/fd/mod.rs b/vendor/rustix/src/io/fd/mod.rs new file mode 100644 index 000000000..0978b5421 --- /dev/null +++ b/vendor/rustix/src/io/fd/mod.rs @@ -0,0 +1,17 @@ +//! The following is derived from Rust's +//! library/std/src/os/fd/mod.rs at revision +//! fa68e73e9947be8ffc5b3b46d899e4953a44e7e9. +//! +//! Owned and borrowed Unix-like file descriptors. + +#![cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +#![deny(unsafe_op_in_unsafe_fn)] + +// `RawFd`, `AsRawFd`, etc. +mod raw; + +// `OwnedFd`, `AsFd`, etc. +mod owned; + +pub use owned::*; +pub use raw::*; diff --git a/vendor/rustix/src/io/fd/owned.rs b/vendor/rustix/src/io/fd/owned.rs new file mode 100644 index 000000000..d99b6a0f9 --- /dev/null +++ b/vendor/rustix/src/io/fd/owned.rs @@ -0,0 +1,252 @@ +//! The following is derived from Rust's +//! library/std/src/os/fd/owned.rs at revision +//! fa68e73e9947be8ffc5b3b46d899e4953a44e7e9. +//! +//! Owned and borrowed Unix-like file descriptors. + +#![cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +#![deny(unsafe_op_in_unsafe_fn)] +#![allow(unsafe_code)] + +use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::io::close; +use core::fmt; +use core::marker::PhantomData; +use core::mem::forget; + +/// 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`. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedFd` +/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file +/// descriptor, which is then borrowed under the same lifetime. +#[derive(Copy, Clone)] +#[repr(transparent)] +#[cfg_attr(rustc_attrs, 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. +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +#[cfg_attr(rustc_attrs, rustc_nonnull_optimization_guaranteed)] +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)] +#[cfg_attr(rustc_attrs, 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. +#[cfg_attr(rustc_attrs, rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +#[cfg_attr(rustc_attrs, rustc_nonnull_optimization_guaranteed)] +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] + #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] + pub const unsafe fn borrow_raw(fd: RawFd) -> Self { + assert!(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) + #[allow(unused_unsafe)] + unsafe { + Self { + fd, + _phantom: PhantomData, + } + } + } +} + +impl OwnedFd { + /// Creates a new `OwnedFd` instance that shares the same underlying file handle + /// as the existing `OwnedFd` instance. + #[cfg(not(target_arch = "wasm32"))] + pub fn try_clone(&self) -> crate::io::Result<Self> { + // We want to atomically duplicate this file descriptor and set the + // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This + // is a POSIX flag that was added to Linux in 2.6.24. + #[cfg(not(target_os = "espidf"))] + let fd = crate::fs::fcntl_dupfd_cloexec(self, 0)?; + + // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics + // will never be supported, as this is a bare metal framework with + // no capabilities for multi-process execution. While F_DUPFD is also + // not supported yet, it might be (currently it returns ENOSYS). + #[cfg(target_os = "espidf")] + let fd = crate::fs::fcntl_dupfd(self)?; + + Ok(fd.into()) + } + + #[cfg(target_arch = "wasm32")] + pub fn try_clone(&self) -> crate::io::Result<Self> { + Err(crate::io::const_io_error!( + crate::io::ErrorKind::Unsupported, + "operation not supported on WASI yet", + )) + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl AsRawFd for BorrowedFd<'_> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl AsRawFd for OwnedFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl IntoRawFd for OwnedFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + let fd = self.fd; + forget(self); + fd + } +} + +#[cfg_attr(staged_api, 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) + #[allow(unused_unsafe)] + unsafe { + Self { fd } + } + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl Drop for OwnedFd { + #[inline] + fn drop(&mut self) { + unsafe { + // 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 _ = close(self.fd as _); + } + } +} + +#[cfg_attr(staged_api, 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() + } +} + +#[cfg_attr(staged_api, 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. +#[cfg_attr(staged_api, 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>(()) + /// ``` + #[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] + fn as_fd(&self) -> BorrowedFd<'_>; +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl<T: AsFd> AsFd for &T { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + T::as_fd(self) + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl<T: AsFd> AsFd for &mut T { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + T::as_fd(self) + } +} + +#[cfg_attr(staged_api, unstable(feature = "io_safety", issue = "87074"))] +impl AsFd for BorrowedFd<'_> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + *self + } +} + +#[cfg_attr(staged_api, 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 `BorrowedFd` is bounded by the lifetime + // of `&self`. + unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } + } +} diff --git a/vendor/rustix/src/io/fd/raw.rs b/vendor/rustix/src/io/fd/raw.rs new file mode 100644 index 000000000..44322d9fe --- /dev/null +++ b/vendor/rustix/src/io/fd/raw.rs @@ -0,0 +1,159 @@ +//! The following is derived from Rust's +//! library/std/src/os/fd/raw.rs at revision +//! fa68e73e9947be8ffc5b3b46d899e4953a44e7e9. +//! +//! Raw Unix-like file descriptors. + +#![cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +#![allow(unsafe_code)] + +use crate::imp::c; + +/// Raw file descriptors. +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub type RawFd = c::c_int; + +/// A trait to extract the raw file descriptor from an underlying object. +/// +/// 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. +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub trait AsRawFd { + /// Extracts the raw file descriptor. + /// + /// This function is typically used to **borrow** an owned file descriptor. + /// When used in this way, this method does **not** pass ownership of the + /// raw file descriptor to the caller, and the file descriptor is only + /// guaranteed to be valid while the original object has not yet been + /// destroyed. + /// + /// However, borrowing is not strictly required. See [`AsFd::as_fd`] + /// for an API which strictly borrows a file descriptor. + /// + /// # Example + /// + /// ```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")?; + /// // `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>(()) + /// ``` + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + fn as_raw_fd(&self) -> RawFd; +} + +/// A trait to express the ability to construct an object from a raw file +/// descriptor. +#[cfg_attr(staged_api, stable(feature = "from_raw_os", since = "1.1.0"))] +pub trait FromRawFd { + /// Constructs a new instance of `Self` from the given raw file + /// descriptor. + /// + /// This function is typically used to **consume ownership** of the + /// specified file descriptor. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. + /// + /// However, consuming ownership is not strictly required. Use a + /// [`From<OwnedFd>::from`] implementation for an API which strictly + /// consumes ownership. + /// + /// # Safety + /// + /// The `fd` passed in must be a valid an open file descriptor. + /// + /// # Example + /// + /// ```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>(()) + /// ``` + #[cfg_attr(staged_api, stable(feature = "from_raw_os", since = "1.1.0"))] + 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. +#[cfg_attr(staged_api, stable(feature = "into_raw_os", since = "1.4.0"))] +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function is typically used to **transfer ownership** of the underlying + /// file descriptor to the caller. When used in this way, callers are then the unique + /// owners of the file descriptor and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// [`Into<OwnedFd>::into`] implementation for an API which strictly + /// transfers ownership. + /// + /// # Example + /// + /// ```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>(()) + /// ``` + #[cfg_attr(staged_api, stable(feature = "into_raw_os", since = "1.4.0"))] + fn into_raw_fd(self) -> RawFd; +} + +#[cfg_attr( + staged_api, + stable(feature = "raw_fd_reflexive_traits", since = "1.48.0") +)] +impl AsRawFd for RawFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[cfg_attr( + staged_api, + stable(feature = "raw_fd_reflexive_traits", since = "1.48.0") +)] +impl IntoRawFd for RawFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + self + } +} +#[cfg_attr( + staged_api, + stable(feature = "raw_fd_reflexive_traits", since = "1.48.0") +)] +impl FromRawFd for RawFd { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} diff --git a/vendor/rustix/src/io/ioctl.rs b/vendor/rustix/src/io/ioctl.rs new file mode 100644 index 000000000..be47e7958 --- /dev/null +++ b/vendor/rustix/src/io/ioctl.rs @@ -0,0 +1,99 @@ +//! The Unix `ioctl` function is effectively lots of different functions +//! hidden behind a single dynamic dispatch interface. In order to provide +//! a type-safe API, rustix makes them all separate functions so that they +//! can have dedicated static type signatures. + +use crate::{imp, io}; +use imp::fd::AsFd; + +/// `ioctl(fd, TIOCEXCL)`—Enables exclusive mode on a terminal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCEXCL")] +pub fn ioctl_tiocexcl<Fd: AsFd>(fd: Fd) -> io::Result<()> { + imp::io::syscalls::ioctl_tiocexcl(fd.as_fd()) +} + +/// `ioctl(fd, TIOCNXCL)`—Disables exclusive mode on a terminal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCNXCL")] +pub fn ioctl_tiocnxcl<Fd: AsFd>(fd: Fd) -> io::Result<()> { + imp::io::syscalls::ioctl_tiocnxcl(fd.as_fd()) +} + +/// `ioctl(fd, FIOCLEX)`—Set the close-on-exec flag. +/// +/// Also known as `fcntl(fd, F_SETFD, FD_CLOEXEC)`. +/// +/// # References +/// - [Linux] +/// - [Winsock2] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ioctlsocket +#[cfg(any(target_os = "ios", target_os = "macos"))] +#[inline] +#[doc(alias = "FIOCLEX")] +#[doc(alias = "FD_CLOEXEC")] +pub fn ioctl_fioclex<Fd: AsFd>(fd: Fd) -> io::Result<()> { + imp::io::syscalls::ioctl_fioclex(fd.as_fd()) +} + +/// `ioctl(fd, FIONBIO, &value)`—Enables or disables non-blocking mode. +/// +/// # References +/// - [Linux] +/// - [Winsock2] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls#unix-ioctl-codes +#[inline] +#[doc(alias = "FIONBIO")] +pub fn ioctl_fionbio<Fd: AsFd>(fd: Fd, value: bool) -> io::Result<()> { + imp::io::syscalls::ioctl_fionbio(fd.as_fd(), value) +} + +/// `ioctl(fd, FIONREAD)`—Returns the number of bytes ready to be read. +/// +/// The result of this function gets silently coerced into a C `int` +/// by the OS, so it may contain a wrapped value. +/// +/// # References +/// - [Linux] +/// - [Winsock2] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl_tty.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls#unix-ioctl-codes +#[cfg(not(target_os = "redox"))] +#[inline] +#[doc(alias = "FIONREAD")] +pub fn ioctl_fionread<Fd: AsFd>(fd: Fd) -> io::Result<u64> { + imp::io::syscalls::ioctl_fionread(fd.as_fd()) +} + +/// `ioctl(fd, BLKSSZGET)`—Returns the logical block size of a block device. +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +#[doc(alias = "BLKSSZGET")] +pub fn ioctl_blksszget<Fd: AsFd>(fd: Fd) -> io::Result<u32> { + imp::io::syscalls::ioctl_blksszget(fd.as_fd()) +} + +/// `ioctl(fd, BLKPBSZGET)`—Returns the physical block size of a block device. +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +#[doc(alias = "BLKPBSZGET")] +pub fn ioctl_blkpbszget<Fd: AsFd>(fd: Fd) -> io::Result<u32> { + imp::io::syscalls::ioctl_blkpbszget(fd.as_fd()) +} diff --git a/vendor/rustix/src/io/is_read_write.rs b/vendor/rustix/src/io/is_read_write.rs new file mode 100644 index 000000000..c6f189090 --- /dev/null +++ b/vendor/rustix/src/io/is_read_write.rs @@ -0,0 +1,16 @@ +//! The [`is_read_write`] function. + +use crate::{imp, io}; +use imp::fd::AsFd; + +/// Returns a pair of booleans indicating whether the file descriptor is +/// readable and/or writable, respectively. +/// +/// Unlike [`is_file_read_write`], this correctly detects whether sockets +/// have been shutdown, partially or completely. +/// +/// [`is_file_read_write`]: crate::fs::is_file_read_write +#[inline] +pub fn is_read_write<Fd: AsFd>(fd: Fd) -> io::Result<(bool, bool)> { + imp::io::syscalls::is_read_write(fd.as_fd()) +} diff --git a/vendor/rustix/src/io/mod.rs b/vendor/rustix/src/io/mod.rs new file mode 100644 index 000000000..5cd5e2ec9 --- /dev/null +++ b/vendor/rustix/src/io/mod.rs @@ -0,0 +1,74 @@ +//! I/O operations. + +mod close; +#[cfg(not(windows))] +mod dup; +mod errno; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod eventfd; +#[cfg(not(feature = "std"))] +pub(crate) mod fd; +mod ioctl; +#[cfg(not(any(windows, target_os = "redox")))] +#[cfg(feature = "net")] +mod is_read_write; +mod owned_fd; +#[cfg(not(any(windows, target_os = "wasi")))] +mod pipe; +mod poll; +#[cfg(all(feature = "procfs", any(target_os = "android", target_os = "linux")))] +mod procfs; +#[cfg(not(windows))] +mod read_write; +#[cfg(not(feature = "std"))] +mod seek_from; +#[cfg(not(windows))] +mod stdio; + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use crate::imp::io::epoll; +pub use close::close; +#[cfg(not(any(windows, target_os = "wasi")))] +pub use dup::{dup, dup2, dup3, DupFlags}; +pub use errno::{retry_on_intr, Errno, Result}; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use eventfd::{eventfd, EventfdFlags}; +#[cfg(any(target_os = "ios", target_os = "macos"))] +pub use ioctl::ioctl_fioclex; +pub use ioctl::ioctl_fionbio; +#[cfg(not(target_os = "redox"))] +pub use ioctl::ioctl_fionread; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use ioctl::{ioctl_blkpbszget, ioctl_blksszget}; +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub use ioctl::{ioctl_tiocexcl, ioctl_tiocnxcl}; +#[cfg(not(any(windows, target_os = "redox")))] +#[cfg(feature = "net")] +pub use is_read_write::is_read_write; +pub use owned_fd::OwnedFd; +#[cfg(not(any(windows, target_os = "wasi")))] +pub use pipe::pipe; +#[cfg(not(any( + windows, + target_os = "illumos", + target_os = "redox", + target_os = "wasi", +)))] +pub use pipe::PIPE_BUF; +#[cfg(not(any(windows, target_os = "ios", target_os = "macos", target_os = "wasi")))] +pub use pipe::{pipe_with, PipeFlags}; +pub use poll::{poll, PollFd, PollFlags}; +#[cfg(all(feature = "procfs", any(target_os = "android", target_os = "linux")))] +pub use procfs::{proc_self_fd, proc_self_fdinfo_fd, proc_self_maps, proc_self_pagemap}; +#[cfg(not(windows))] +pub use read_write::{pread, pwrite, read, readv, write, writev, IoSlice, IoSliceMut}; +#[cfg(not(any(windows, target_os = "redox")))] +pub use read_write::{preadv, pwritev}; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use read_write::{preadv2, pwritev2, ReadWriteFlags}; +#[cfg(not(feature = "std"))] +pub use seek_from::SeekFrom; +#[cfg(feature = "std")] +pub use std::io::SeekFrom; +#[cfg(not(windows))] +pub use stdio::{stderr, stdin, stdout, take_stderr, take_stdin, take_stdout}; diff --git a/vendor/rustix/src/io/owned_fd.rs b/vendor/rustix/src/io/owned_fd.rs new file mode 100644 index 000000000..63c6145b0 --- /dev/null +++ b/vendor/rustix/src/io/owned_fd.rs @@ -0,0 +1,272 @@ +//! A wrapper around [`io_lifetimes::OwnedFd`]. +//! +//! rustix needs to wrap io-lifetimes' `OwnedFd` type so that it can call its +//! own [`close`] function when the `OwnedFd` is dropped. +//! +//! [`close`]: crate::io::close +//! +//! # Safety +//! +//! We wrap an `OwnedFd` in a `ManuallyDrop` so that we can extract the +//! file descriptor and close it ourselves. +#![allow(unsafe_code)] + +use crate::imp::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; +#[cfg(all(not(io_lifetimes_use_std), feature = "std"))] +use crate::imp::fd::{FromFd, IntoFd}; +use crate::io::close; +use core::fmt; +use core::mem::{forget, ManuallyDrop}; + +/// A wrapper around [`io_lifetimes::OwnedFd`] which closes the file descriptor +/// using rustix's own [`close`] rather than libc's `close`. +/// +/// [`close`]: crate::io::close +#[repr(transparent)] +pub struct OwnedFd { + inner: ManuallyDrop<crate::imp::fd::OwnedFd>, +} + +impl OwnedFd { + /// Creates a new `OwnedFd` instance that shares the same underlying file + /// handle as the existing `OwnedFd` instance. + #[cfg(all(unix, not(target_os = "wasi")))] + pub fn try_clone(&self) -> crate::io::Result<Self> { + // We want to atomically duplicate this file descriptor and set the + // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This + // is a POSIX flag that was added to Linux in 2.6.24. + #[cfg(not(target_os = "espidf"))] + let fd = crate::fs::fcntl_dupfd_cloexec(self, 0)?; + + // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics + // will never be supported, as this is a bare metal framework with + // no capabilities for multi-process execution. While F_DUPFD is also + // not supported yet, it might be (currently it returns ENOSYS). + #[cfg(target_os = "espidf")] + let fd = crate::fs::fcntl_dupfd(self)?; + + Ok(fd) + } + + /// Creates a new `OwnedFd` instance that shares the same underlying file + /// handle as the existing `OwnedFd` instance. + #[cfg(target_os = "wasi")] + pub fn try_clone(&self) -> std::io::Result<Self> { + Err(std::io::Error::new( + std::io::ErrorKind::Unsupported, + "operation not supported on WASI yet", + )) + } + + /// Creates a new `OwnedFd` instance that shares the same underlying file + /// handle as the existing `OwnedFd` instance. + #[cfg(target_os = "windows")] + pub fn try_clone(&self) -> std::io::Result<Self> { + use windows_sys::Win32::Networking::WinSock::{ + WSADuplicateSocketW, WSAGetLastError, WSASocketW, INVALID_SOCKET, SOCKET_ERROR, + WSAEINVAL, WSAEPROTOTYPE, WSAPROTOCOL_INFOW, WSA_FLAG_NO_HANDLE_INHERIT, + WSA_FLAG_OVERLAPPED, + }; + use windows_sys::Win32::System::Threading::GetCurrentProcessId; + + let mut info = unsafe { std::mem::zeroed::<WSAPROTOCOL_INFOW>() }; + let result = + unsafe { WSADuplicateSocketW(self.as_raw_fd() as _, GetCurrentProcessId(), &mut info) }; + match result { + SOCKET_ERROR => return Err(std::io::Error::last_os_error()), + 0 => (), + _ => panic!(), + } + let socket = unsafe { + WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT, + ) + }; + + if socket != INVALID_SOCKET { + unsafe { Ok(Self::from_raw_fd(socket as _)) } + } else { + let error = unsafe { WSAGetLastError() }; + + if error != WSAEPROTOTYPE && error != WSAEINVAL { + return Err(std::io::Error::from_raw_os_error(error)); + } + + let socket = unsafe { + WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + WSA_FLAG_OVERLAPPED, + ) + }; + + if socket == INVALID_SOCKET { + return Err(std::io::Error::last_os_error()); + } + + unsafe { + let socket = Self::from_raw_fd(socket as _); + socket.set_no_inherit()?; + Ok(socket) + } + } + } + + #[cfg(windows)] + #[cfg(not(target_vendor = "uwp"))] + fn set_no_inherit(&self) -> std::io::Result<()> { + use windows_sys::Win32::Foundation::{SetHandleInformation, HANDLE, HANDLE_FLAG_INHERIT}; + match unsafe { SetHandleInformation(self.as_raw_fd() as HANDLE, HANDLE_FLAG_INHERIT, 0) } { + 0 => return Err(std::io::Error::last_os_error()), + _ => Ok(()), + } + } + + #[cfg(windows)] + #[cfg(target_vendor = "uwp")] + fn set_no_inherit(&self) -> std::io::Result<()> { + Err(std::io::Error::new( + std::io::ErrorKind::Unsupported, + "Unavailable on UWP", + )) + } +} + +#[cfg(not(windows))] +impl AsFd for OwnedFd { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.inner.as_fd() + } +} + +#[cfg(windows)] +impl io_lifetimes::AsSocket for OwnedFd { + #[inline] + fn as_socket(&self) -> BorrowedFd<'_> { + self.inner.as_socket() + } +} + +#[cfg(any(io_lifetimes_use_std, not(feature = "std")))] +impl From<OwnedFd> for crate::imp::fd::OwnedFd { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + let raw_fd = owned_fd.inner.as_fd().as_raw_fd(); + forget(owned_fd); + + // Safety: We use `as_fd().as_raw_fd()` to extract the raw file + // descriptor from `self.inner`, and then `forget` `self` so + // that they remain valid until the new `OwnedFd` acquires them. + unsafe { crate::imp::fd::OwnedFd::from_raw_fd(raw_fd) } + } +} + +#[cfg(not(any(io_lifetimes_use_std, not(feature = "std"))))] +impl IntoFd for OwnedFd { + #[inline] + fn into_fd(self) -> crate::imp::fd::OwnedFd { + let raw_fd = self.inner.as_fd().as_raw_fd(); + forget(self); + + // Safety: We use `as_fd().as_raw_fd()` to extract the raw file + // descriptor from `self.inner`, and then `forget` `self` so + // that they remain valid until the new `OwnedFd` acquires them. + unsafe { crate::imp::fd::OwnedFd::from_raw_fd(raw_fd) } + } +} + +#[cfg(any(io_lifetimes_use_std, not(feature = "std")))] +impl From<crate::imp::fd::OwnedFd> for OwnedFd { + #[inline] + fn from(owned_fd: crate::imp::fd::OwnedFd) -> Self { + Self { + inner: ManuallyDrop::new(owned_fd), + } + } +} + +#[cfg(all(not(io_lifetimes_use_std), feature = "std"))] +impl FromFd for OwnedFd { + #[inline] + fn from_fd(owned_fd: crate::imp::fd::OwnedFd) -> Self { + Self { + inner: ManuallyDrop::new(owned_fd), + } + } +} + +#[cfg(not(any(io_lifetimes_use_std, not(feature = "std"))))] +impl From<crate::imp::fd::OwnedFd> for OwnedFd { + #[inline] + fn from(fd: crate::imp::fd::OwnedFd) -> Self { + Self { + inner: ManuallyDrop::new(fd), + } + } +} + +#[cfg(not(any(io_lifetimes_use_std, not(feature = "std"))))] +impl From<OwnedFd> for crate::imp::fd::OwnedFd { + #[inline] + fn from(fd: OwnedFd) -> Self { + let raw_fd = fd.inner.as_fd().as_raw_fd(); + forget(fd); + + // Safety: We use `as_fd().as_raw_fd()` to extract the raw file + // descriptor from `self.inner`, and then `forget` `self` so + // that they remain valid until the new `OwnedFd` acquires them. + unsafe { Self::from_raw_fd(raw_fd) } + } +} + +impl AsRawFd for OwnedFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.inner.as_raw_fd() + } +} + +impl IntoRawFd for OwnedFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + let raw_fd = self.inner.as_fd().as_raw_fd(); + forget(self); + raw_fd + } +} + +impl FromRawFd for OwnedFd { + #[inline] + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self { + inner: ManuallyDrop::new(crate::imp::fd::OwnedFd::from_raw_fd(raw_fd)), + } + } +} + +impl Drop for OwnedFd { + #[inline] + fn drop(&mut self) { + // Safety: We use `as_fd().as_raw_fd()` to extract the raw file + // descriptor from `self.inner`. `self.inner` is wrapped with + // `ManuallyDrop` so dropping it doesn't invalid them. + unsafe { + close(self.as_fd().as_raw_fd()); + } + } +} + +impl fmt::Debug for OwnedFd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.inner.fmt(f) + } +} diff --git a/vendor/rustix/src/io/pipe.rs b/vendor/rustix/src/io/pipe.rs new file mode 100644 index 000000000..2878d10b1 --- /dev/null +++ b/vendor/rustix/src/io/pipe.rs @@ -0,0 +1,53 @@ +use crate::imp; +use crate::io::{self, OwnedFd}; + +#[cfg(not(any(target_os = "ios", target_os = "macos")))] +pub use imp::io::types::PipeFlags; + +/// `PIPE_BUF`—The maximum length at which writes to a pipe are atomic. +/// +/// # References +/// - [Linux] +/// - [POSIX] +/// +/// [Linux]: https://man7.org/linux/man-pages/man7/pipe.7.html +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html +#[cfg(not(any( + windows, + target_os = "illumos", + target_os = "redox", + target_os = "wasi", +)))] +pub const PIPE_BUF: usize = imp::io::types::PIPE_BUF; + +/// `pipe()`—Creates a pipe. +/// +/// This function creates a pipe and returns two file descriptors, for the +/// reading and writing ends of the pipe, respectively. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html +/// [Linux]: https://man7.org/linux/man-pages/man2/pipe.2.html +#[inline] +pub fn pipe() -> io::Result<(OwnedFd, OwnedFd)> { + imp::io::syscalls::pipe() +} + +/// `pipe2(flags)`—Creates a pipe, with flags. +/// +/// This function creates a pipe and returns two file descriptors, for the +/// reading and writing ends of the pipe, respectively. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/pipe2.2.html +#[cfg(not(any(target_os = "ios", target_os = "macos")))] +#[inline] +#[doc(alias = "pipe2")] +pub fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> { + imp::io::syscalls::pipe_with(flags) +} diff --git a/vendor/rustix/src/io/poll.rs b/vendor/rustix/src/io/poll.rs new file mode 100644 index 000000000..efa25045c --- /dev/null +++ b/vendor/rustix/src/io/poll.rs @@ -0,0 +1,20 @@ +use crate::{imp, io}; + +pub use imp::io::poll_fd::{PollFd, PollFlags}; + +/// `poll(self.fds, timeout)` +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock2] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html +/// [Linux]: https://man7.org/linux/man-pages/man2/poll.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/poll.2.html +/// [Winsock2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll +#[inline] +pub fn poll(fds: &mut [PollFd<'_>], timeout: i32) -> io::Result<usize> { + imp::io::syscalls::poll(fds, timeout) +} diff --git a/vendor/rustix/src/io/procfs.rs b/vendor/rustix/src/io/procfs.rs new file mode 100644 index 000000000..a947a4e06 --- /dev/null +++ b/vendor/rustix/src/io/procfs.rs @@ -0,0 +1,482 @@ +//! Utilities for working with `/proc`, where Linux's `procfs` is typically +//! mounted. `/proc` serves as an adjunct to Linux's main syscall surface area, +//! providing additional features with an awkward interface. +//! +//! This module does a considerable amount of work to determine whether `/proc` +//! is mounted, with actual `procfs`, and without any additional mount points +//! on top of the paths we open. +//! +//! Why all the effort to detect bind mount points? People are doing all kinds +//! of things with Linux containers these days, with many different privilege +//! schemes, and we want to avoid making any unnecessary assumptions. Rustix +//! and its users will sometimes use procfs *implicitly* (when Linux gives them +//! no better options), in ways that aren't obvious from their public APIs. +//! These filesystem accesses might not be visible to someone auditing the main +//! code of an application for places which may be influenced by the filesystem +//! namespace. So with the checking here, they may fail, but they won't be able +//! to succeed with bogus results. + +use crate::fd::{AsFd, BorrowedFd}; +use crate::ffi::CStr; +use crate::fs::{ + cwd, fstat, fstatfs, major, openat, renameat, Dir, FileType, Mode, OFlags, Stat, + PROC_SUPER_MAGIC, +}; +use crate::io::{self, OwnedFd}; +use crate::path::DecInt; +use crate::process::{getgid, getpid, getuid, Gid, RawGid, RawUid, Uid}; +#[cfg(feature = "rustc-dep-of-std")] +use core::lazy::OnceCell; +#[cfg(not(feature = "rustc-dep-of-std"))] +use once_cell::sync::OnceCell; + +/// Linux's procfs always uses inode 1 for its root directory. +const PROC_ROOT_INO: u64 = 1; + +// Identify an entry within "/proc", to determine which anomalies to check for. +#[derive(Copy, Clone, Debug)] +enum Kind { + Proc, + Pid, + Fd, + File, +} + +/// Check a subdirectory of "/proc" for anomalies. +fn check_proc_entry( + kind: Kind, + entry: BorrowedFd<'_>, + proc_stat: Option<&Stat>, + uid: RawUid, + gid: RawGid, +) -> io::Result<Stat> { + let entry_stat = fstat(entry)?; + check_proc_entry_with_stat(kind, entry, entry_stat, proc_stat, uid, gid) +} + +/// Check a subdirectory of "/proc" for anomalies, using the provided `Stat`. +fn check_proc_entry_with_stat( + kind: Kind, + entry: BorrowedFd<'_>, + entry_stat: Stat, + proc_stat: Option<&Stat>, + uid: RawUid, + gid: RawGid, +) -> io::Result<Stat> { + // Check the filesystem magic. + check_procfs(entry)?; + + match kind { + Kind::Proc => check_proc_root(entry, &entry_stat)?, + Kind::Pid | Kind::Fd => check_proc_subdir(entry, &entry_stat, proc_stat)?, + Kind::File => check_proc_file(&entry_stat, proc_stat)?, + } + + // Check the ownership of the directory. We can't do that for the toplevel + // "/proc" though, because in e.g. a user namespace scenario, root outside + // the container may be mapped to another uid like `nobody`. + if !matches!(kind, Kind::Proc) && (entry_stat.st_uid, entry_stat.st_gid) != (uid, gid) { + return Err(io::Errno::NOTSUP); + } + + // "/proc" directories are typically mounted r-xr-xr-x. + // "/proc/self/fd" is r-x------. Allow them to have fewer permissions, but + // not more. + let expected_mode = if let Kind::Fd = kind { 0o500 } else { 0o555 }; + if entry_stat.st_mode & 0o777 & !expected_mode != 0 { + return Err(io::Errno::NOTSUP); + } + + match kind { + Kind::Fd => { + // Check that the "/proc/self/fd" directory doesn't have any extraneous + // links into it (which might include unexpected subdirectories). + if entry_stat.st_nlink != 2 { + return Err(io::Errno::NOTSUP); + } + } + Kind::Pid | Kind::Proc => { + // Check that the "/proc" and "/proc/self" directories aren't empty. + if entry_stat.st_nlink <= 2 { + return Err(io::Errno::NOTSUP); + } + } + Kind::File => { + // Check that files in procfs don't have extraneous hard links to + // them (which might indicate hard links to other things). + if entry_stat.st_nlink != 1 { + return Err(io::Errno::NOTSUP); + } + } + } + + Ok(entry_stat) +} + +fn check_proc_root(entry: BorrowedFd<'_>, stat: &Stat) -> io::Result<()> { + // We use `O_DIRECTORY` for proc directories, so open should fail if we + // don't get a directory when we expect one. + assert_eq!(FileType::from_raw_mode(stat.st_mode), FileType::Directory); + + // Check the root inode number. + if stat.st_ino != PROC_ROOT_INO { + return Err(io::Errno::NOTSUP); + } + + // Proc is a non-device filesystem, so check for major number 0. + // <https://www.kernel.org/doc/Documentation/admin-guide/devices.txt> + if major(stat.st_dev) != 0 { + return Err(io::Errno::NOTSUP); + } + + // Check that "/proc" is a mountpoint. + if !is_mountpoint(entry) { + return Err(io::Errno::NOTSUP); + } + + Ok(()) +} + +fn check_proc_subdir( + entry: BorrowedFd<'_>, + stat: &Stat, + proc_stat: Option<&Stat>, +) -> io::Result<()> { + // We use `O_DIRECTORY` for proc directories, so open should fail if we + // don't get a directory when we expect one. + assert_eq!(FileType::from_raw_mode(stat.st_mode), FileType::Directory); + + check_proc_nonroot(stat, proc_stat)?; + + // Check that subdirectories of "/proc" are not mount points. + if is_mountpoint(entry) { + return Err(io::Errno::NOTSUP); + } + + Ok(()) +} + +fn check_proc_file(stat: &Stat, proc_stat: Option<&Stat>) -> io::Result<()> { + // Check that we have a regular file. + if FileType::from_raw_mode(stat.st_mode) != FileType::RegularFile { + return Err(io::Errno::NOTSUP); + } + + check_proc_nonroot(stat, proc_stat)?; + + Ok(()) +} + +fn check_proc_nonroot(stat: &Stat, proc_stat: Option<&Stat>) -> io::Result<()> { + // Check that we haven't been linked back to the root of "/proc". + if stat.st_ino == PROC_ROOT_INO { + return Err(io::Errno::NOTSUP); + } + + // Check that we're still in procfs. + if stat.st_dev != proc_stat.unwrap().st_dev { + return Err(io::Errno::NOTSUP); + } + + Ok(()) +} + +/// Check that `file` is opened on a `procfs` filesystem. +fn check_procfs(file: BorrowedFd<'_>) -> io::Result<()> { + let statfs = fstatfs(file)?; + let f_type = statfs.f_type; + if f_type != PROC_SUPER_MAGIC { + return Err(io::Errno::NOTSUP); + } + + Ok(()) +} + +/// Check whether the given directory handle is a mount point. We use a +/// `renameat` call that would otherwise fail, but which fails with `EXDEV` +/// first if it would cross a mount point. +fn is_mountpoint(file: BorrowedFd<'_>) -> bool { + let err = renameat(file, cstr!("../."), file, cstr!(".")).unwrap_err(); + match err { + io::Errno::XDEV => true, // the rename failed due to crossing a mount point + io::Errno::BUSY => false, // the rename failed normally + _ => panic!("Unexpected error from `renameat`: {:?}", err), + } +} + +/// Open a directory in `/proc`, mapping all errors to `io::Errno::NOTSUP`. +fn proc_opendirat<P: crate::path::Arg, Fd: AsFd>(dirfd: Fd, path: P) -> io::Result<OwnedFd> { + // We could add `PATH`|`NOATIME` here but Linux 2.6.32 doesn't support it. + let oflags = OFlags::NOFOLLOW | OFlags::DIRECTORY | OFlags::CLOEXEC | OFlags::NOCTTY; + openat(dirfd, path, oflags, Mode::empty()).map_err(|_err| io::Errno::NOTSUP) +} + +/// Returns a handle to Linux's `/proc` directory. +/// +/// This ensures that `/proc` is procfs, that nothing is mounted on top of it, +/// and that it looks normal. It also returns the `Stat` of `/proc`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +fn proc() -> io::Result<(BorrowedFd<'static>, &'static Stat)> { + static PROC: StaticFd = StaticFd::new(); + + // `OnceBox` is "racey" in that the initialization function may run + // multiple times. We're ok with that, since the initialization function + // has no side effects. + PROC.get_or_try_init(|| { + // Open "/proc". + let proc = proc_opendirat(cwd(), cstr!("/proc"))?; + let proc_stat = check_proc_entry( + Kind::Proc, + proc.as_fd(), + None, + Uid::ROOT.as_raw(), + Gid::ROOT.as_raw(), + ) + .map_err(|_err| io::Errno::NOTSUP)?; + + Ok(new_static_fd(proc, proc_stat)) + }) + .map(|(fd, stat)| (fd.as_fd(), stat)) +} + +/// Returns a handle to Linux's `/proc/self` directory. +/// +/// This ensures that `/proc/self` is procfs, that nothing is mounted on top of +/// it, and that it looks normal. It also returns the `Stat` of `/proc/self`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +fn proc_self() -> io::Result<(BorrowedFd<'static>, &'static Stat)> { + static PROC_SELF: StaticFd = StaticFd::new(); + + // The init function here may run multiple times; see above. + PROC_SELF + .get_or_try_init(|| { + let (proc, proc_stat) = proc()?; + + let (uid, gid, pid) = (getuid(), getgid(), getpid()); + + // Open "/proc/self". Use our pid to compute the name rather than literally + // using "self", as "self" is a symlink. + let proc_self = proc_opendirat(proc, DecInt::new(pid.as_raw_nonzero().get()))?; + let proc_self_stat = check_proc_entry( + Kind::Pid, + proc_self.as_fd(), + Some(proc_stat), + uid.as_raw(), + gid.as_raw(), + ) + .map_err(|_err| io::Errno::NOTSUP)?; + + Ok(new_static_fd(proc_self, proc_self_stat)) + }) + .map(|(owned, stat)| (owned.as_fd(), stat)) +} + +/// Returns a handle to Linux's `/proc/self/fd` directory. +/// +/// This ensures that `/proc/self/fd` is `procfs`, that nothing is mounted on +/// top of it, and that it looks normal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +pub fn proc_self_fd() -> io::Result<BorrowedFd<'static>> { + static PROC_SELF_FD: StaticFd = StaticFd::new(); + + // The init function here may run multiple times; see above. + PROC_SELF_FD + .get_or_try_init(|| { + let (_, proc_stat) = proc()?; + + let (proc_self, proc_self_stat) = proc_self()?; + + // Open "/proc/self/fd". + let proc_self_fd = proc_opendirat(proc_self, cstr!("fd"))?; + let proc_self_fd_stat = check_proc_entry( + Kind::Fd, + proc_self_fd.as_fd(), + Some(proc_stat), + proc_self_stat.st_uid, + proc_self_stat.st_gid, + ) + .map_err(|_err| io::Errno::NOTSUP)?; + + Ok(new_static_fd(proc_self_fd, proc_self_fd_stat)) + }) + .map(|(owned, _stat)| owned.as_fd()) +} + +type StaticFd = OnceCell<(OwnedFd, Stat)>; + +#[inline] +fn new_static_fd(fd: OwnedFd, stat: Stat) -> (OwnedFd, Stat) { + (fd, stat) +} + +/// Returns a handle to Linux's `/proc/self/fdinfo` directory. +/// +/// This ensures that `/proc/self/fdinfo` is `procfs`, that nothing is mounted +/// on top of it, and that it looks normal. It also returns the `Stat` of +/// `/proc/self/fd`. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +fn proc_self_fdinfo() -> io::Result<(BorrowedFd<'static>, &'static Stat)> { + static PROC_SELF_FDINFO: OnceCell<(OwnedFd, Stat)> = OnceCell::new(); + + PROC_SELF_FDINFO + .get_or_try_init(|| { + let (_, proc_stat) = proc()?; + + let (proc_self, proc_self_stat) = proc_self()?; + + // Open "/proc/self/fdinfo". + let proc_self_fdinfo = proc_opendirat(proc_self, cstr!("fdinfo"))?; + let proc_self_fdinfo_stat = check_proc_entry( + Kind::Fd, + proc_self_fdinfo.as_fd(), + Some(proc_stat), + proc_self_stat.st_uid, + proc_self_stat.st_gid, + ) + .map_err(|_err| io::Errno::NOTSUP)?; + + Ok((proc_self_fdinfo, proc_self_fdinfo_stat)) + }) + .map(|(owned, stat)| (owned.as_fd(), stat)) +} + +/// Returns a handle to a Linux `/proc/self/fdinfo/<fd>` file. +/// +/// This ensures that `/proc/self/fdinfo/<fd>` is `procfs`, that nothing is +/// mounted on top of it, and that it looks normal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +#[inline] +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +pub fn proc_self_fdinfo_fd<Fd: AsFd>(fd: Fd) -> io::Result<OwnedFd> { + _proc_self_fdinfo(fd.as_fd()) +} + +fn _proc_self_fdinfo(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { + let (proc_self_fdinfo, proc_self_fdinfo_stat) = proc_self_fdinfo()?; + let fd_str = DecInt::from_fd(fd); + open_and_check_file(proc_self_fdinfo, proc_self_fdinfo_stat, fd_str.as_c_str()) +} + +/// Returns a handle to a Linux `/proc/self/pagemap` file. +/// +/// This ensures that `/proc/self/pagemap` is `procfs`, that nothing is +/// mounted on top of it, and that it looks normal. +/// +/// # References +/// - [Linux] +/// - [Linux pagemap] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +/// [Linux pagemap]: https://www.kernel.org/doc/Documentation/vm/pagemap.txt +#[inline] +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +pub fn proc_self_pagemap() -> io::Result<OwnedFd> { + proc_self_file(cstr!("pagemap")) +} + +/// Returns a handle to a Linux `/proc/self/maps` file. +/// +/// This ensures that `/proc/self/maps` is `procfs`, that nothing is +/// mounted on top of it, and that it looks normal. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man5/proc.5.html +#[inline] +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +pub fn proc_self_maps() -> io::Result<OwnedFd> { + proc_self_file(cstr!("maps")) +} + +/// Open a file under `/proc/self`. +fn proc_self_file(name: &CStr) -> io::Result<OwnedFd> { + let (proc_self, proc_self_stat) = proc_self()?; + open_and_check_file(proc_self, proc_self_stat, name) +} + +/// Open a procfs file within in `dir` and check it for bind mounts. +fn open_and_check_file(dir: BorrowedFd, dir_stat: &Stat, name: &CStr) -> io::Result<OwnedFd> { + let (_, proc_stat) = proc()?; + + let oflags = + OFlags::RDONLY | OFlags::CLOEXEC | OFlags::NOFOLLOW | OFlags::NOCTTY | OFlags::NOATIME; + let file = openat(&dir, name, oflags, Mode::empty()).map_err(|_err| io::Errno::NOTSUP)?; + let file_stat = fstat(&file)?; + + // `is_mountpoint` only works on directory mount points, not file mount + // points. To detect file mount points, scan the parent directory to see + // if we can find a regular file with an inode and name that matches the + // file we just opened. If we can't find it, there could be a file bind + // mount on top of the file we want. + // + // As we scan, we also check for ".", to make sure it's the same directory + // as our original directory, to detect mount points, since + // `Dir::read_from` reopens ".". + // + // TODO: With Linux 5.8 we might be able to use `statx` and + // `STATX_ATTR_MOUNT_ROOT` to detect mountpoints directly instead of doing + // this scanning. + let dir = Dir::read_from(dir).map_err(|_err| io::Errno::NOTSUP)?; + + // Confirm that we got the same inode. + let dot_stat = dir.stat().map_err(|_err| io::Errno::NOTSUP)?; + if (dot_stat.st_dev, dot_stat.st_ino) != (dir_stat.st_dev, dir_stat.st_ino) { + return Err(io::Errno::NOTSUP); + } + + let mut found_file = false; + let mut found_dot = false; + for entry in dir { + let entry = entry.map_err(|_err| io::Errno::NOTSUP)?; + if entry.ino() == file_stat.st_ino + && entry.file_type() == FileType::RegularFile + && entry.file_name() == name + { + // We found the file. Proceed to check the file handle. + let _ = check_proc_entry_with_stat( + Kind::File, + file.as_fd(), + file_stat, + Some(proc_stat), + dir_stat.st_uid, + dir_stat.st_gid, + )?; + + found_file = true; + } else if entry.ino() == dir_stat.st_ino + && entry.file_type() == FileType::Directory + && entry.file_name() == cstr!(".") + { + // We found ".", and it's the right ".". + found_dot = true; + } + } + + if found_file && found_dot { + Ok(file) + } else { + Err(io::Errno::NOTSUP) + } +} diff --git a/vendor/rustix/src/io/read_write.rs b/vendor/rustix/src/io/read_write.rs new file mode 100644 index 000000000..abb96e9c1 --- /dev/null +++ b/vendor/rustix/src/io/read_write.rs @@ -0,0 +1,170 @@ +//! `read` and `write`, optionally positioned, optionally vectored + +use crate::{imp, io}; +use imp::fd::AsFd; + +// Declare `IoSlice` and `IoSliceMut`. +#[cfg(not(windows))] +#[cfg(not(feature = "std"))] +pub use imp::io::io_slice::{IoSlice, IoSliceMut}; +#[cfg(not(windows))] +#[cfg(feature = "std")] +pub use std::io::{IoSlice, IoSliceMut}; + +/// `RWF_*` constants for use with [`preadv2`] and [`pwritev2`]. +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use imp::io::types::ReadWriteFlags; + +/// `read(fd, buf)`—Reads from a stream. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html +/// [Linux]: https://man7.org/linux/man-pages/man2/read.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/read.2.html +#[inline] +pub fn read<Fd: AsFd>(fd: Fd, buf: &mut [u8]) -> io::Result<usize> { + imp::io::syscalls::read(fd.as_fd(), buf) +} + +/// `write(fd, buf)`—Writes to a stream. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html +/// [Linux]: https://man7.org/linux/man-pages/man2/write.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/write.2.html +#[inline] +pub fn write<Fd: AsFd>(fd: Fd, buf: &[u8]) -> io::Result<usize> { + imp::io::syscalls::write(fd.as_fd(), buf) +} + +/// `pread(fd, buf, offset)`—Reads from a file at a given position. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html +/// [Linux]: https://man7.org/linux/man-pages/man2/pread.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pread.2.html +#[inline] +pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: u64) -> io::Result<usize> { + imp::io::syscalls::pread(fd.as_fd(), buf, offset) +} + +/// `pwrite(fd, bufs)`—Writes to a file at a given position. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html +/// [Linux]: https://man7.org/linux/man-pages/man2/pwrite.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pwrite.2.html +#[inline] +pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: u64) -> io::Result<usize> { + imp::io::syscalls::pwrite(fd.as_fd(), buf, offset) +} + +/// `readv(fd, bufs)`—Reads from a stream into multiple buffers. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html +/// [Linux]: https://man7.org/linux/man-pages/man2/readv.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/readv.2.html +#[inline] +pub fn readv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + imp::io::syscalls::readv(fd.as_fd(), bufs) +} + +/// `writev(fd, bufs)`—Writes to a stream from multiple buffers. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html +/// [Linux]: https://man7.org/linux/man-pages/man2/writev.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/writev.2.html +#[inline] +pub fn writev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + imp::io::syscalls::writev(fd.as_fd(), bufs) +} + +/// `preadv(fd, bufs, offset)`—Reads from a file at a given position into +/// multiple buffers. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/preadv.2.html +#[cfg(not(target_os = "redox"))] +#[inline] +pub fn preadv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + imp::io::syscalls::preadv(fd.as_fd(), bufs, offset) +} + +/// `pwritev(fd, bufs, offset)`—Writes to a file at a given position from +/// multiple buffers. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/pwritev.2.html +#[cfg(not(target_os = "redox"))] +#[inline] +pub fn pwritev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { + imp::io::syscalls::pwritev(fd.as_fd(), bufs, offset) +} + +/// `preadv2(fd, bufs, offset, flags)`—Reads data, with several options. +/// +/// An `offset` of `u64::MAX` means to use and update the current file offset. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/preadv2.2.html +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub fn preadv2<Fd: AsFd>( + fd: Fd, + bufs: &mut [IoSliceMut<'_>], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + imp::io::syscalls::preadv2(fd.as_fd(), bufs, offset, flags) +} + +/// `pwritev2(fd, bufs, offset, flags)`—Writes data, with several options. +/// +/// An `offset` of `u64::MAX` means to use and update the current file offset. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/pwritev2.2.html +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub fn pwritev2<Fd: AsFd>( + fd: Fd, + bufs: &[IoSlice<'_>], + offset: u64, + flags: ReadWriteFlags, +) -> io::Result<usize> { + imp::io::syscalls::pwritev2(fd.as_fd(), bufs, offset, flags) +} diff --git a/vendor/rustix/src/io/seek_from.rs b/vendor/rustix/src/io/seek_from.rs new file mode 100644 index 000000000..265369b6b --- /dev/null +++ b/vendor/rustix/src/io/seek_from.rs @@ -0,0 +1,30 @@ +//! The following is derived from Rust's +//! library/std/src/io/mod.rs at revision +//! dca3f1b786efd27be3b325ed1e01e247aa589c3b. + +/// Enumeration of possible methods to seek within an I/O object. +/// +/// It is used by the [`Seek`] trait. +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] +pub enum SeekFrom { + /// Sets the offset to the provided number of bytes. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + Start(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] u64), + + /// Sets the offset to the size of this object plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but it's an error + /// to seek before byte 0. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + End(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] i64), + + /// Sets the offset to the current position plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but it's an error + /// to seek before byte 0. + #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] + Current(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] i64), +} diff --git a/vendor/rustix/src/io/stdio.rs b/vendor/rustix/src/io/stdio.rs new file mode 100644 index 000000000..f9d03a701 --- /dev/null +++ b/vendor/rustix/src/io/stdio.rs @@ -0,0 +1,194 @@ +//! Functions returning the stdio file descriptors. +//! +//! # Safety +//! +//! These access the file descriptors by absolute index value, and nothing +//! prevents them from being closed and reused. They should only be used in +//! `main` or other situations where one is in control of the process' +//! stdio streams. +#![allow(unsafe_code)] + +use crate::imp; +use crate::io::OwnedFd; +use imp::fd::{BorrowedFd, FromRawFd, RawFd}; + +/// `STDIN_FILENO`—Standard input, borrowed. +/// +/// # Safety +/// +/// This function must be called from code which knows how the process' +/// standard input is being used. Often, this will be the `main` function or +/// code that knows its relationship with the `main` function. +/// +/// The stdin file descriptor can be closed, potentially on other threads, in +/// which case the file descriptor index value could be dynamically reused for +/// other purposes, potentially on different threads. +/// +/// # Other hazards +/// +/// Stdin could be redirected from arbitrary input sources, and unless one +/// knows how the process' standard input is being used, one could consume +/// bytes that are expected to be consumed by other parts of the process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdin.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html +#[inline] +pub unsafe fn stdin() -> BorrowedFd<'static> { + BorrowedFd::borrow_raw(imp::io::types::STDIN_FILENO as RawFd) +} + +/// `STDIN_FILENO`—Standard input, owned. +/// +/// This is similar to [`stdin`], however it returns an `OwnedFd` which closes +/// standard input when it is dropped. +/// +/// # Safety +/// +/// This is unsafe for the same reasons as [`stdin`]. +/// +/// # Other hazards +/// +/// This has the same hazards as [`stdin`]. +/// +/// And, when the `OwnedFd` is dropped, subsequent newly created file +/// descriptors may unknowingly reuse the stdin file descriptor number, which +/// may break common assumptions, so it should typically only be dropped at the +/// end of a program when no more file descriptors will be created. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdin.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html +#[inline] +pub unsafe fn take_stdin() -> OwnedFd { + OwnedFd::from(imp::fd::OwnedFd::from_raw_fd( + imp::io::types::STDIN_FILENO as RawFd, + )) +} + +/// `STDOUT_FILENO`—Standard output, borrowed. +/// +/// # Safety +/// +/// This function must be called from code which knows how the process' +/// standard output is being used. Often, this will be the `main` function or +/// code that knows its relationship with the `main` function. +/// +/// The stdout file descriptor can be closed, potentially on other threads, in +/// which case the file descriptor index value could be dynamically reused for +/// other purposes, potentially on different threads. +/// +/// # Other hazards +/// +/// Stdout could be redirected to arbitrary output sinks, and unless one +/// knows how the process' standard output is being used, one could +/// unexpectedly inject bytes into a stream being written by another part of +/// the process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdout.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html +#[inline] +pub unsafe fn stdout() -> BorrowedFd<'static> { + BorrowedFd::borrow_raw(imp::io::types::STDOUT_FILENO as RawFd) +} + +/// `STDOUT_FILENO`—Standard output, owned. +/// +/// This is similar to [`stdout`], however it returns an `OwnedFd` which closes +/// standard output when it is dropped. +/// +/// # Safety +/// +/// This is unsafe for the same reasons as [`stdout`]. +/// +/// # Other hazards +/// +/// This has the same hazards as [`stdout`]. +/// +/// And, when the `OwnedFd` is dropped, subsequent newly created file +/// descriptors may unknowingly reuse the stdout file descriptor number, which +/// may break common assumptions, so it should typically only be dropped at the +/// end of a program when no more file descriptors will be created. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stdout.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html +#[inline] +pub unsafe fn take_stdout() -> OwnedFd { + OwnedFd::from(imp::fd::OwnedFd::from_raw_fd( + imp::io::types::STDOUT_FILENO as RawFd, + )) +} + +/// `STDERR_FILENO`—Standard error, borrowed. +/// +/// # Safety +/// +/// This function must be called from code which knows how the process' +/// standard error is being used. Often, this will be the `main` function or +/// code that knows its relationship with the `main` function. +/// +/// The stderr file descriptor can be closed, potentially on other threads, in +/// which case the file descriptor index value could be dynamically reused for +/// other purposes, potentially on different threads. +/// +/// # Other hazards +/// +/// Stderr could be redirected to arbitrary output sinks, and unless one +/// knows how the process' standard error is being used, one could unexpectedly +/// inject bytes into a stream being written by another part of the process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stderr.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html +#[inline] +pub unsafe fn stderr() -> BorrowedFd<'static> { + BorrowedFd::borrow_raw(imp::io::types::STDERR_FILENO as RawFd) +} + +/// `STDERR_FILENO`—Standard error, owned. +/// +/// This is similar to [`stdout`], however it returns an `OwnedFd` which closes +/// standard output when it is dropped. +/// +/// # Safety +/// +/// This is unsafe for the same reasons as [`stderr`]. +/// +/// # Other hazards +/// +/// This has the same hazards as [`stderr`]. +/// +/// And, when the `OwnedFd` is dropped, subsequent newly created file +/// descriptors may unknowingly reuse the stderr file descriptor number, which +/// may break common assumptions, so it should typically only be dropped at the +/// end of a program when no more file descriptors will be created. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stderr.html +/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html +#[inline] +pub unsafe fn take_stderr() -> OwnedFd { + OwnedFd::from(imp::fd::OwnedFd::from_raw_fd( + imp::io::types::STDERR_FILENO as RawFd, + )) +} |