diff options
Diffstat (limited to 'vendor/rustix/src/backend/libc')
73 files changed, 15050 insertions, 0 deletions
diff --git a/vendor/rustix/src/backend/libc/c.rs b/vendor/rustix/src/backend/libc/c.rs new file mode 100644 index 0000000..d3a1e5f --- /dev/null +++ b/vendor/rustix/src/backend/libc/c.rs @@ -0,0 +1,468 @@ +//! Libc and supplemental types and constants. + +#![allow(unused_imports)] + +// Import everything from libc, but we'll add some stuff and override some +// things below. +pub(crate) use libc::*; + +/// `PROC_SUPER_MAGIC`—The magic number for the procfs filesystem. +#[cfg(all(linux_kernel, target_env = "musl"))] +pub(crate) const PROC_SUPER_MAGIC: u32 = 0x0000_9fa0; + +/// `NFS_SUPER_MAGIC`—The magic number for the NFS filesystem. +#[cfg(all(linux_kernel, target_env = "musl"))] +pub(crate) const NFS_SUPER_MAGIC: u32 = 0x0000_6969; + +#[cfg(feature = "process")] +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) const EXIT_SIGNALED_SIGABRT: c_int = 128 + SIGABRT as c_int; + +// TODO: Upstream these. +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_TSN: c_int = linux_raw_sys::if_ether::ETH_P_TSN as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_ERSPAN2: c_int = linux_raw_sys::if_ether::ETH_P_ERSPAN2 as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_ERSPAN: c_int = linux_raw_sys::if_ether::ETH_P_ERSPAN as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_PROFINET: c_int = linux_raw_sys::if_ether::ETH_P_PROFINET as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_REALTEK: c_int = linux_raw_sys::if_ether::ETH_P_REALTEK as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_ETHERCAT: c_int = linux_raw_sys::if_ether::ETH_P_ETHERCAT as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_PREAUTH: c_int = linux_raw_sys::if_ether::ETH_P_PREAUTH as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_LLDP: c_int = linux_raw_sys::if_ether::ETH_P_LLDP as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_MRP: c_int = linux_raw_sys::if_ether::ETH_P_MRP as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_NCSI: c_int = linux_raw_sys::if_ether::ETH_P_NCSI as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_CFM: c_int = linux_raw_sys::if_ether::ETH_P_CFM as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_IBOE: c_int = linux_raw_sys::if_ether::ETH_P_IBOE as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_HSR: c_int = linux_raw_sys::if_ether::ETH_P_HSR as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_NSH: c_int = linux_raw_sys::if_ether::ETH_P_NSH as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_DSA_8021Q: c_int = linux_raw_sys::if_ether::ETH_P_DSA_8021Q as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_DSA_A5PSW: c_int = linux_raw_sys::if_ether::ETH_P_DSA_A5PSW as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_IFE: c_int = linux_raw_sys::if_ether::ETH_P_IFE as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_CAN: c_int = linux_raw_sys::if_ether::ETH_P_CAN as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_CANXL: c_int = linux_raw_sys::if_ether::ETH_P_CANXL as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_XDSA: c_int = linux_raw_sys::if_ether::ETH_P_XDSA as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_MAP: c_int = linux_raw_sys::if_ether::ETH_P_MAP as _; +#[cfg(all(linux_kernel, feature = "net"))] +pub(crate) const ETH_P_MCTP: c_int = linux_raw_sys::if_ether::ETH_P_MCTP as _; + +#[cfg(all( +    linux_kernel, +    any( +        target_arch = "mips", +        target_arch = "mips32r6", +        target_arch = "mips64", +        target_arch = "mips64r6", +        target_arch = "sparc", +        target_arch = "sparc64" +    ) +))] +pub(crate) const SIGEMT: c_int = linux_raw_sys::general::SIGEMT as _; + +// TODO: Upstream these. +#[cfg(all(linux_kernel, feature = "termios"))] +pub(crate) const IUCLC: tcflag_t = linux_raw_sys::general::IUCLC as _; +#[cfg(all(linux_kernel, feature = "termios"))] +pub(crate) const XCASE: tcflag_t = linux_raw_sys::general::XCASE as _; + +#[cfg(target_os = "aix")] +pub(crate) const MSG_DONTWAIT: c_int = libc::MSG_NONBLOCK; + +// TODO: Remove once https://github.com/rust-lang/libc/pull/3377 is merged and released. +#[cfg(target_os = "netbsd")] +#[cfg(feature = "net")] +pub(crate) const SO_NOSIGPIPE: c_int = 0x0800; + +// On PowerPC, the regular `termios` has the `termios2` fields and there is no +// `termios2`. linux-raw-sys has aliases `termios2` to `termios` to cover this +// difference, but we still need to manually import it since `libc` doesn't +// have this. +#[cfg(all( +    linux_kernel, +    feature = "termios", +    any(target_arch = "powerpc", target_arch = "powerpc64") +))] +pub(crate) use { +    linux_raw_sys::general::{termios2, CIBAUD}, +    linux_raw_sys::ioctl::{TCGETS2, TCSETS2, TCSETSF2, TCSETSW2}, +}; + +// Automatically enable “large file” support (LFS) features. + +#[cfg(target_os = "vxworks")] +pub(super) use libc::_Vx_ticks64_t as _Vx_ticks_t; +#[cfg(linux_kernel)] +pub(super) use libc::fallocate64 as fallocate; +#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] +#[cfg(any(linux_like, target_os = "aix"))] +pub(super) use libc::open64 as open; +#[cfg(any( +    linux_kernel, +    target_os = "aix", +    target_os = "hurd", +    target_os = "l4re" +))] +pub(super) use libc::posix_fallocate64 as posix_fallocate; +#[cfg(any(all(linux_like, not(target_os = "android")), target_os = "aix"))] +pub(super) use libc::{blkcnt64_t as blkcnt_t, rlim64_t as rlim_t}; +// TODO: AIX has `stat64x`, `fstat64x`, `lstat64x`, and `stat64xat`; add them +// to the upstream libc crate and implement rustix's `statat` etc. with them. +#[cfg(target_os = "aix")] +pub(super) use libc::{ +    blksize64_t as blksize_t, fstat64 as fstat, fstatfs64 as fstatfs, fstatvfs64 as fstatvfs, +    ftruncate64 as ftruncate, getrlimit64 as getrlimit, ino_t, lseek64 as lseek, mmap, +    off64_t as off_t, openat, posix_fadvise64 as posix_fadvise, preadv, pwritev, +    rlimit64 as rlimit, setrlimit64 as setrlimit, stat64at as fstatat, statfs64 as statfs, +    statvfs64 as statvfs, RLIM_INFINITY, +}; +#[cfg(any(linux_like, target_os = "hurd"))] +pub(super) use libc::{ +    fstat64 as fstat, fstatat64 as fstatat, fstatfs64 as fstatfs, fstatvfs64 as fstatvfs, +    ftruncate64 as ftruncate, getrlimit64 as getrlimit, ino64_t as ino_t, lseek64 as lseek, +    mmap64 as mmap, off64_t as off_t, openat64 as openat, posix_fadvise64 as posix_fadvise, +    rlimit64 as rlimit, setrlimit64 as setrlimit, statfs64 as statfs, statvfs64 as statvfs, +    RLIM64_INFINITY as RLIM_INFINITY, +}; +#[cfg(apple)] +pub(super) use libc::{ +    host_info64_t as host_info_t, host_statistics64 as host_statistics, +    vm_statistics64_t as vm_statistics_t, +}; +#[cfg(not(all( +    linux_kernel, +    any( +        target_pointer_width = "32", +        target_arch = "mips64", +        target_arch = "mips64r6" +    ) +)))] +#[cfg(any(linux_like, target_os = "aix", target_os = "hurd"))] +pub(super) use libc::{lstat64 as lstat, stat64 as stat}; +#[cfg(any( +    linux_kernel, +    target_os = "aix", +    target_os = "hurd", +    target_os = "emscripten" +))] +pub(super) use libc::{pread64 as pread, pwrite64 as pwrite}; +#[cfg(any(target_os = "linux", target_os = "hurd", target_os = "emscripten"))] +pub(super) use libc::{preadv64 as preadv, pwritev64 as pwritev}; + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(super) unsafe fn prlimit( +    pid: libc::pid_t, +    resource: libc::__rlimit_resource_t, +    new_limit: *const libc::rlimit64, +    old_limit: *mut libc::rlimit64, +) -> libc::c_int { +    // `prlimit64` wasn't supported in glibc until 2.13. +    weak_or_syscall! { +        fn prlimit64( +            pid: libc::pid_t, +            resource: libc::__rlimit_resource_t, +            new_limit: *const libc::rlimit64, +            old_limit: *mut libc::rlimit64 +        ) via SYS_prlimit64 -> libc::c_int +    } + +    prlimit64(pid, resource, new_limit, old_limit) +} + +#[cfg(all(target_os = "linux", target_env = "musl"))] +pub(super) unsafe fn prlimit( +    pid: libc::pid_t, +    resource: libc::c_int, +    new_limit: *const libc::rlimit64, +    old_limit: *mut libc::rlimit64, +) -> libc::c_int { +    weak_or_syscall! { +        fn prlimit64( +            pid: libc::pid_t, +            resource: libc::c_int, +            new_limit: *const libc::rlimit64, +            old_limit: *mut libc::rlimit64 +        ) via SYS_prlimit64 -> libc::c_int +    } + +    prlimit64(pid, resource, new_limit, old_limit) +} + +#[cfg(target_os = "android")] +pub(super) unsafe fn prlimit( +    pid: libc::pid_t, +    resource: libc::c_int, +    new_limit: *const libc::rlimit64, +    old_limit: *mut libc::rlimit64, +) -> libc::c_int { +    weak_or_syscall! { +        fn prlimit64( +            pid: libc::pid_t, +            resource: libc::c_int, +            new_limit: *const libc::rlimit64, +            old_limit: *mut libc::rlimit64 +        ) via SYS_prlimit64 -> libc::c_int +    } + +    prlimit64(pid, resource, new_limit, old_limit) +} + +#[cfg(target_os = "android")] +mod readwrite_pv64 { +    use super::*; + +    pub(in super::super) unsafe fn preadv64( +        fd: libc::c_int, +        iov: *const libc::iovec, +        iovcnt: libc::c_int, +        offset: libc::off64_t, +    ) -> libc::ssize_t { +        // Older Android libc lacks `preadv64`, so use the `weak!` mechanism to +        // test for it, and call back to `libc::syscall`. We don't use +        // `weak_or_syscall` here because we need to pass the 64-bit offset +        // specially. +        weak! { +            fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, libc::off64_t) -> libc::ssize_t +        } +        if let Some(fun) = preadv64.get() { +            fun(fd, iov, iovcnt, offset) +        } else { +            // Unlike the plain "p" functions, the "pv" functions pass their +            // offset in an endian-independent way, and always in two registers. +            syscall! { +                fn preadv( +                    fd: libc::c_int, +                    iov: *const libc::iovec, +                    iovcnt: libc::c_int, +                    offset_lo: usize, +                    offset_hi: usize +                ) via SYS_preadv -> libc::ssize_t +            } +            preadv(fd, iov, iovcnt, offset as usize, (offset >> 32) as usize) +        } +    } +    pub(in super::super) unsafe fn pwritev64( +        fd: libc::c_int, +        iov: *const libc::iovec, +        iovcnt: libc::c_int, +        offset: libc::off64_t, +    ) -> libc::ssize_t { +        // See the comments in `preadv64`. +        weak! { +            fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, libc::off64_t) -> libc::ssize_t +        } +        if let Some(fun) = pwritev64.get() { +            fun(fd, iov, iovcnt, offset) +        } else { +            // Unlike the plain "p" functions, the "pv" functions pass their +            // offset in an endian-independent way, and always in two registers. +            syscall! { +                fn pwritev( +                    fd: libc::c_int, +                    iov: *const libc::iovec, +                    iovcnt: libc::c_int, +                    offset_lo: usize, +                    offset_hi: usize +                ) via SYS_pwritev -> libc::ssize_t +            } +            pwritev(fd, iov, iovcnt, offset as usize, (offset >> 32) as usize) +        } +    } +} +#[cfg(target_os = "android")] +pub(super) use readwrite_pv64::{preadv64 as preadv, pwritev64 as pwritev}; + +// macOS added `preadv` and `pwritev` in version 11.0. +#[cfg(apple)] +mod readwrite_pv { +    weakcall! { +        pub(in super::super) fn preadv( +            fd: libc::c_int, +            iov: *const libc::iovec, +            iovcnt: libc::c_int, +            offset: libc::off_t +        ) -> libc::ssize_t +    } +    weakcall! { +        pub(in super::super) fn pwritev( +            fd: libc::c_int, +            iov: *const libc::iovec, +            iovcnt: libc::c_int, offset: libc::off_t +        ) -> libc::ssize_t +    } +} +#[cfg(apple)] +pub(super) use readwrite_pv::{preadv, pwritev}; + +// glibc added `preadv64v2` and `pwritev64v2` in version 2.26. +#[cfg(all(target_os = "linux", target_env = "gnu"))] +mod readwrite_pv64v2 { +    use super::*; + +    pub(in super::super) unsafe fn preadv64v2( +        fd: libc::c_int, +        iov: *const libc::iovec, +        iovcnt: libc::c_int, +        offset: libc::off64_t, +        flags: libc::c_int, +    ) -> libc::ssize_t { +        // Older glibc lacks `preadv64v2`, so use the `weak!` mechanism to +        // test for it, and call back to `libc::syscall`. We don't use +        // `weak_or_syscall` here because we need to pass the 64-bit offset +        // specially. +        weak! { +            fn preadv64v2(libc::c_int, *const libc::iovec, libc::c_int, libc::off64_t, libc::c_int) -> libc::ssize_t +        } +        if let Some(fun) = preadv64v2.get() { +            fun(fd, iov, iovcnt, offset, flags) +        } else { +            // Unlike the plain "p" functions, the "pv" functions pass their +            // offset in an endian-independent way, and always in two registers. +            syscall! { +                fn preadv2( +                    fd: libc::c_int, +                    iov: *const libc::iovec, +                    iovcnt: libc::c_int, +                    offset_lo: usize, +                    offset_hi: usize, +                    flags: libc::c_int +                ) via SYS_preadv2 -> libc::ssize_t +            } +            preadv2( +                fd, +                iov, +                iovcnt, +                offset as usize, +                (offset >> 32) as usize, +                flags, +            ) +        } +    } +    pub(in super::super) unsafe fn pwritev64v2( +        fd: libc::c_int, +        iov: *const libc::iovec, +        iovcnt: libc::c_int, +        offset: libc::off64_t, +        flags: libc::c_int, +    ) -> libc::ssize_t { +        // See the comments in `preadv64v2`. +        weak! { +            fn pwritev64v2(libc::c_int, *const libc::iovec, libc::c_int, libc::off64_t, libc::c_int) -> libc::ssize_t +        } +        if let Some(fun) = pwritev64v2.get() { +            fun(fd, iov, iovcnt, offset, flags) +        } else { +            // Unlike the plain "p" functions, the "pv" functions pass their +            // offset in an endian-independent way, and always in two registers. +            syscall! { +                fn pwritev2( +                    fd: libc::c_int, +                    iov: *const libc::iovec, +                    iovec: libc::c_int, +                    offset_lo: usize, +                    offset_hi: usize, +                    flags: libc::c_int +                ) via SYS_pwritev2 -> libc::ssize_t +            } +            pwritev2( +                fd, +                iov, +                iovcnt, +                offset as usize, +                (offset >> 32) as usize, +                flags, +            ) +        } +    } +} +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(super) use readwrite_pv64v2::{preadv64v2 as preadv2, pwritev64v2 as pwritev2}; + +// On non-glibc, assume we don't have `pwritev2`/`preadv2` in libc and use +// `c::syscall` instead. +#[cfg(any( +    target_os = "android", +    all(target_os = "linux", not(target_env = "gnu")), +))] +mod readwrite_pv64v2 { +    use super::*; + +    pub(in super::super) unsafe fn preadv64v2( +        fd: libc::c_int, +        iov: *const libc::iovec, +        iovcnt: libc::c_int, +        offset: libc::off64_t, +        flags: libc::c_int, +    ) -> libc::ssize_t { +        // Unlike the plain "p" functions, the "pv" functions pass their offset +        // in an endian-independent way, and always in two registers. +        syscall! { +            fn preadv2( +                fd: libc::c_int, +                iov: *const libc::iovec, +                iovcnt: libc::c_int, +                offset_lo: usize, +                offset_hi: usize, +                flags: libc::c_int +            ) via SYS_preadv2 -> libc::ssize_t +        } +        preadv2( +            fd, +            iov, +            iovcnt, +            offset as usize, +            (offset >> 32) as usize, +            flags, +        ) +    } +    pub(in super::super) unsafe fn pwritev64v2( +        fd: libc::c_int, +        iov: *const libc::iovec, +        iovcnt: libc::c_int, +        offset: libc::off64_t, +        flags: libc::c_int, +    ) -> libc::ssize_t { +        // Unlike the plain "p" functions, the "pv" functions pass their offset +        // in an endian-independent way, and always in two registers. +        syscall! { +            fn pwritev2( +                fd: libc::c_int, +                iov: *const libc::iovec, +                iovcnt: libc::c_int, +                offset_lo: usize, +                offset_hi: usize, +                flags: libc::c_int +            ) via SYS_pwritev2 -> libc::ssize_t +        } +        pwritev2( +            fd, +            iov, +            iovcnt, +            offset as usize, +            (offset >> 32) as usize, +            flags, +        ) +    } +} +#[cfg(any( +    target_os = "android", +    all(target_os = "linux", not(target_env = "gnu")), +))] +pub(super) use readwrite_pv64v2::{preadv64v2 as preadv2, pwritev64v2 as pwritev2}; diff --git a/vendor/rustix/src/backend/libc/conv.rs b/vendor/rustix/src/backend/libc/conv.rs new file mode 100644 index 0000000..2539510 --- /dev/null +++ b/vendor/rustix/src/backend/libc/conv.rs @@ -0,0 +1,247 @@ +//! Libc call arguments and return values are often things like `c_int`, +//! `c_uint`, or libc-specific pointer types. This module provides functions +//! for converting between rustix's types and libc types. + +use super::c; +#[cfg(all(feature = "alloc", not(any(windows, target_os = "espidf"))))] +use super::fd::IntoRawFd; +use super::fd::{AsRawFd, BorrowedFd, FromRawFd, LibcFd, OwnedFd, RawFd}; +#[cfg(not(windows))] +use crate::ffi::CStr; +use crate::io; + +#[cfg(not(windows))] +#[inline] +pub(super) fn c_str(c: &CStr) -> *const c::c_char { +    c.as_ptr() +} + +#[cfg(not(any(windows, target_os = "espidf", target_os = "vita", target_os = "wasi")))] +#[inline] +pub(super) fn no_fd() -> LibcFd { +    -1 +} + +#[inline] +pub(super) fn borrowed_fd(fd: BorrowedFd<'_>) -> LibcFd { +    fd.as_raw_fd() as LibcFd +} + +#[cfg(all( +    feature = "alloc", +    not(any(windows, target_os = "espidf", target_os = "redox")) +))] +#[inline] +pub(super) fn owned_fd(fd: OwnedFd) -> LibcFd { +    fd.into_raw_fd() as LibcFd +} + +#[inline] +pub(super) fn ret(raw: c::c_int) -> io::Result<()> { +    if raw == 0 { +        Ok(()) +    } else { +        Err(io::Errno::last_os_error()) +    } +} + +#[cfg(apple)] +#[inline] +pub(super) fn nonnegative_ret(raw: c::c_int) -> io::Result<()> { +    if raw >= 0 { +        Ok(()) +    } else { +        Err(io::Errno::last_os_error()) +    } +} + +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +pub(super) unsafe fn ret_infallible(raw: c::c_int) { +    debug_assert_eq!(raw, 0, "unexpected error: {:?}", io::Errno::last_os_error()); +} + +#[inline] +pub(super) fn ret_c_int(raw: c::c_int) -> io::Result<c::c_int> { +    if raw == -1 { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(raw) +    } +} + +#[cfg(linux_kernel)] +#[inline] +pub(super) fn ret_u32(raw: c::c_int) -> io::Result<u32> { +    if raw == -1 { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(raw as u32) +    } +} + +#[inline] +pub(super) fn ret_usize(raw: c::ssize_t) -> io::Result<usize> { +    if raw == -1 { +        Err(io::Errno::last_os_error()) +    } else { +        debug_assert!(raw >= 0); +        Ok(raw as usize) +    } +} + +#[cfg(not(windows))] +#[cfg(feature = "fs")] +#[inline] +pub(super) fn ret_off_t(raw: c::off_t) -> io::Result<c::off_t> { +    if raw == -1 { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(raw) +    } +} + +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +pub(super) fn ret_pid_t(raw: c::pid_t) -> io::Result<c::pid_t> { +    if raw == -1 { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(raw) +    } +} + +/// Convert a `c_int` returned from a libc function to an `OwnedFd`, if valid. +/// +/// # Safety +/// +/// The caller must ensure that this is the return value of a libc function +/// which returns an owned file descriptor. +#[inline] +pub(super) unsafe fn ret_owned_fd(raw: LibcFd) -> io::Result<OwnedFd> { +    if raw == !0 { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(OwnedFd::from_raw_fd(raw as RawFd)) +    } +} + +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +pub(super) fn ret_discarded_fd(raw: LibcFd) -> io::Result<()> { +    if raw == !0 { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(()) +    } +} + +#[cfg(all(feature = "alloc", not(any(windows, target_os = "wasi"))))] +#[inline] +pub(super) fn ret_discarded_char_ptr(raw: *mut c::c_char) -> io::Result<()> { +    if raw.is_null() { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(()) +    } +} + +/// Convert the buffer-length argument value of a `send` or `recv` call. +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +#[inline] +pub(super) fn send_recv_len(len: usize) -> usize { +    len +} + +/// Convert the buffer-length argument value of a `send` or `recv` call. +#[cfg(windows)] +#[inline] +pub(super) fn send_recv_len(len: usize) -> i32 { +    // On Windows, the length argument has type `i32`; saturate the length, +    // since `send` and `recv` are allowed to send and recv less data than +    // requested. +    len.try_into().unwrap_or(i32::MAX) +} + +/// Convert the return value of a `send` or `recv` call. +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +#[inline] +pub(super) fn ret_send_recv(len: isize) -> io::Result<usize> { +    ret_usize(len) +} + +/// Convert the return value of a `send` or `recv` call. +#[cfg(windows)] +#[inline] +pub(super) fn ret_send_recv(len: i32) -> io::Result<usize> { +    ret_usize(len as isize) +} + +/// Convert the value to the `msg_iovlen` field of a `msghdr` struct. +#[cfg(all( +    not(any(windows, target_os = "espidf", target_os = "redox", target_os = "wasi")), +    any( +        target_os = "android", +        all(target_os = "linux", not(target_env = "musl")) +    ) +))] +#[inline] +pub(super) fn msg_iov_len(len: usize) -> c::size_t { +    len +} + +/// Convert the value to the `msg_iovlen` field of a `msghdr` struct. +#[cfg(all( +    not(any( +        windows, +        target_os = "espidf", +        target_os = "redox", +        target_os = "vita", +        target_os = "wasi" +    )), +    not(any( +        target_os = "android", +        all(target_os = "linux", not(target_env = "musl")) +    )) +))] +#[inline] +pub(crate) fn msg_iov_len(len: usize) -> c::c_int { +    len.try_into().unwrap_or(c::c_int::MAX) +} + +/// Convert the value to a `socklen_t`. +#[cfg(any( +    bsd, +    solarish, +    target_env = "musl", +    target_os = "aix", +    target_os = "emscripten", +    target_os = "fuchsia", +    target_os = "haiku", +    target_os = "nto", +))] +#[inline] +pub(crate) fn msg_control_len(len: usize) -> c::socklen_t { +    len.try_into().unwrap_or(c::socklen_t::MAX) +} + +/// Convert the value to a `size_t`. +#[cfg(not(any( +    bsd, +    solarish, +    windows, +    target_env = "musl", +    target_os = "aix", +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "haiku", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +#[inline] +pub(crate) fn msg_control_len(len: usize) -> c::size_t { +    len +} diff --git a/vendor/rustix/src/backend/libc/event/epoll.rs b/vendor/rustix/src/backend/libc/event/epoll.rs new file mode 100644 index 0000000..ced3be1 --- /dev/null +++ b/vendor/rustix/src/backend/libc/event/epoll.rs @@ -0,0 +1,496 @@ +//! Linux `epoll` support. +//! +//! # Examples +//! +//! ```no_run +//! # #[cfg(feature = "net")] +//! # fn main() -> std::io::Result<()> { +//! use rustix::event::epoll; +//! use rustix::fd::AsFd; +//! use rustix::io::{ioctl_fionbio, read, write}; +//! use rustix::net::{ +//!     accept, bind_v4, listen, socket, AddressFamily, Ipv4Addr, SocketAddrV4, SocketType, +//! }; +//! use std::collections::HashMap; +//! use std::os::unix::io::AsRawFd; +//! +//! // Create a socket and listen on it. +//! let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, None)?; +//! 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::create(epoll::CreateFlags::CLOEXEC)?; +//! +//! // Register the socket with the epoll object. +//! epoll::add( +//!     &epoll, +//!     &listen_sock, +//!     epoll::EventData::new_u64(1), +//!     epoll::EventFlags::IN, +//! )?; +//! +//! // Keep track of the sockets we've opened. +//! let mut next_id = epoll::EventData::new_u64(2); +//! let mut sockets = HashMap::new(); +//! +//! // Process events. +//! let mut event_list = epoll::EventVec::with_capacity(4); +//! loop { +//!     epoll::wait(&epoll, &mut event_list, -1)?; +//!     for event in &event_list { +//!         let target = event.data; +//!         if target.u64() == 1 { +//!             // 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(&listen_sock)?; +//!             ioctl_fionbio(&conn_sock, true)?; +//!             epoll::add( +//!                 &epoll, +//!                 &conn_sock, +//!                 next_id, +//!                 epoll::EventFlags::OUT | epoll::EventFlags::ET, +//!             )?; +//! +//!             // Keep track of the socket. +//!             sockets.insert(next_id, conn_sock); +//!             next_id = epoll::EventData::new_u64(next_id.u64() + 1); +//!         } else { +//!             // Write a message to the stream and then unregister it. +//!             let target = sockets.remove(&target).unwrap(); +//!             write(&target, b"hello\n")?; +//!             let _ = epoll::delete(&epoll, &target)?; +//!         } +//!     } +//! } +//! # } +//! # #[cfg(not(feature = "net"))] +//! # fn main() {} +//! ``` + +use crate::backend::c; +#[cfg(feature = "alloc")] +use crate::backend::conv::ret_u32; +use crate::backend::conv::{ret, ret_owned_fd}; +use crate::fd::{AsFd, AsRawFd, OwnedFd}; +use crate::io; +use crate::utils::as_mut_ptr; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +use bitflags::bitflags; +use core::ffi::c_void; +use core::hash::{Hash, Hasher}; +use core::ptr::null_mut; +use core::slice; + +bitflags! { +    /// `EPOLL_*` for use with [`new`]. +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct CreateFlags: u32 { +        /// `EPOLL_CLOEXEC` +        const CLOEXEC = bitcast!(c::EPOLL_CLOEXEC); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +bitflags! { +    /// `EPOLL*` for use with [`add`]. +    #[repr(transparent)] +    #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct EventFlags: u32 { +        /// `EPOLLIN` +        const IN = bitcast!(c::EPOLLIN); + +        /// `EPOLLOUT` +        const OUT = bitcast!(c::EPOLLOUT); + +        /// `EPOLLPRI` +        const PRI = bitcast!(c::EPOLLPRI); + +        /// `EPOLLERR` +        const ERR = bitcast!(c::EPOLLERR); + +        /// `EPOLLHUP` +        const HUP = bitcast!(c::EPOLLHUP); + +        /// `EPOLLRDNORM` +        const RDNORM = bitcast!(c::EPOLLRDNORM); + +        /// `EPOLLRDBAND` +        const RDBAND = bitcast!(c::EPOLLRDBAND); + +        /// `EPOLLWRNORM` +        const WRNORM = bitcast!(c::EPOLLWRNORM); + +        /// `EPOLLWRBAND` +        const WRBAND = bitcast!(c::EPOLLWRBAND); + +        /// `EPOLLMSG` +        const MSG = bitcast!(c::EPOLLMSG); + +        /// `EPOLLRDHUP` +        const RDHUP = bitcast!(c::EPOLLRDHUP); + +        /// `EPOLLET` +        const ET = bitcast!(c::EPOLLET); + +        /// `EPOLLONESHOT` +        const ONESHOT = bitcast!(c::EPOLLONESHOT); + +        /// `EPOLLWAKEUP` +        const WAKEUP = bitcast!(c::EPOLLWAKEUP); + +        /// `EPOLLEXCLUSIVE` +        #[cfg(not(target_os = "android"))] +        const EXCLUSIVE = bitcast!(c::EPOLLEXCLUSIVE); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// `epoll_create1(flags)`—Creates a new epoll object. +/// +/// 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 create(flags: CreateFlags) -> io::Result<OwnedFd> { +    // SAFETY: We're calling `epoll_create1` via FFI and we know how it +    // behaves. +    unsafe { ret_owned_fd(c::epoll_create1(bitflags_bits!(flags))) } +} + +/// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an epoll +/// object. +/// +/// This registers interest in any of the events set in `events` occurring on +/// the file descriptor associated with `data`. +/// +/// If [`delete`] is not called on the I/O source passed into this function +/// before the I/O source is `close`d, then the `epoll` will act as if the I/O +/// source is still registered with it. This can lead to spurious events being +/// returned from [`wait`]. If a file descriptor is an +/// `Arc<dyn SystemResource>`, then `epoll` can be thought to maintain a +/// `Weak<dyn SystemResource>` to the file descriptor. +#[doc(alias = "epoll_ctl")] +pub fn add( +    epoll: impl AsFd, +    source: impl AsFd, +    data: EventData, +    event_flags: EventFlags, +) -> io::Result<()> { +    // SAFETY: We're calling `epoll_ctl` via FFI and we know how it +    // behaves. We use our own `Event` struct instead of libc's because +    // ours preserves pointer provenance instead of just using a `u64`, +    // and we have tests elsehwere for layout equivalence. +    unsafe { +        let raw_fd = source.as_fd().as_raw_fd(); +        ret(c::epoll_ctl( +            epoll.as_fd().as_raw_fd(), +            c::EPOLL_CTL_ADD, +            raw_fd, +            as_mut_ptr(&mut Event { +                flags: event_flags, +                data, +            }) +            .cast(), +        )) +    } +} + +/// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in a +/// given epoll object. +/// +/// This sets the events of interest with `target` to `events`. +#[doc(alias = "epoll_ctl")] +pub fn modify( +    epoll: impl AsFd, +    source: impl AsFd, +    data: EventData, +    event_flags: EventFlags, +) -> io::Result<()> { +    let raw_fd = source.as_fd().as_raw_fd(); + +    // SAFETY: We're calling `epoll_ctl` via FFI and we know how it +    // behaves. We use our own `Event` struct instead of libc's because +    // ours preserves pointer provenance instead of just using a `u64`, +    // and we have tests elsehwere for layout equivalence. +    unsafe { +        ret(c::epoll_ctl( +            epoll.as_fd().as_raw_fd(), +            c::EPOLL_CTL_MOD, +            raw_fd, +            as_mut_ptr(&mut Event { +                flags: event_flags, +                data, +            }) +            .cast(), +        )) +    } +} + +/// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in a +/// given epoll object. +#[doc(alias = "epoll_ctl")] +pub fn delete(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> { +    // SAFETY: We're calling `epoll_ctl` via FFI and we know how it +    // behaves. +    unsafe { +        let raw_fd = source.as_fd().as_raw_fd(); +        ret(c::epoll_ctl( +            epoll.as_fd().as_raw_fd(), +            c::EPOLL_CTL_DEL, +            raw_fd, +            null_mut(), +        )) +    } +} + +/// `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. +#[cfg(feature = "alloc")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] +pub fn wait(epoll: impl AsFd, event_list: &mut EventVec, 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( +            epoll.as_fd().as_raw_fd(), +            event_list.events.as_mut_ptr().cast::<c::epoll_event>(), +            event_list.events.capacity().try_into().unwrap_or(i32::MAX), +            timeout, +        ))?; +        event_list.events.set_len(nfds as usize); +    } + +    Ok(()) +} + +/// An iterator over the `Event`s in an `EventVec`. +pub struct Iter<'a> { +    /// Use `Copied` to copy the struct, since `Event` is `packed` on some +    /// platforms, and it's common for users to directly destructure it, which +    /// would lead to errors about forming references to packed fields. +    iter: core::iter::Copied<slice::Iter<'a, Event>>, +} + +impl<'a> Iterator for Iter<'a> { +    type Item = Event; + +    #[inline] +    fn next(&mut self) -> Option<Self::Item> { +        self.iter.next() +    } +} + +/// 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) +)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct Event { +    /// Which specific event(s) occurred. +    pub flags: EventFlags, +    /// User data. +    pub data: EventData, +} + +/// Data associated with an [`Event`]. This can either be a 64-bit integer +/// value or a pointer which preserves pointer provenance. +#[repr(C)] +#[derive(Copy, Clone)] +pub union EventData { +    /// A 64-bit integer value. +    as_u64: u64, + +    /// A `*mut c_void` which preserves pointer provenance, extended to be +    /// 64-bit so that if we read the value as a `u64` union field, we don't +    /// get uninitialized memory. +    sixty_four_bit_pointer: SixtyFourBitPointer, +} + +impl EventData { +    /// Construct a new value containing a `u64`. +    #[inline] +    pub const fn new_u64(value: u64) -> Self { +        Self { as_u64: value } +    } + +    /// Construct a new value containing a `*mut c_void`. +    #[inline] +    pub const fn new_ptr(value: *mut c_void) -> Self { +        Self { +            sixty_four_bit_pointer: SixtyFourBitPointer { +                pointer: value, +                #[cfg(target_pointer_width = "32")] +                _padding: 0, +            }, +        } +    } + +    /// Return the value as a `u64`. +    /// +    /// If the stored value was a pointer, the pointer is zero-extended to a +    /// `u64`. +    #[inline] +    pub fn u64(self) -> u64 { +        unsafe { self.as_u64 } +    } + +    /// Return the value as a `*mut c_void`. +    /// +    /// If the stored value was a `u64`, the least-significant bits of the +    /// `u64` are returned as a pointer value. +    #[inline] +    pub fn ptr(self) -> *mut c_void { +        unsafe { self.sixty_four_bit_pointer.pointer } +    } +} + +impl PartialEq for EventData { +    #[inline] +    fn eq(&self, other: &Self) -> bool { +        self.u64() == other.u64() +    } +} + +impl Eq for EventData {} + +impl Hash for EventData { +    #[inline] +    fn hash<H: Hasher>(&self, state: &mut H) { +        self.u64().hash(state) +    } +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct SixtyFourBitPointer { +    #[cfg(target_endian = "big")] +    #[cfg(target_pointer_width = "32")] +    _padding: u32, + +    pointer: *mut c_void, + +    #[cfg(target_endian = "little")] +    #[cfg(target_pointer_width = "32")] +    _padding: u32, +} + +/// A vector of `Event`s, plus context for interpreting them. +#[cfg(feature = "alloc")] +pub struct EventVec { +    events: Vec<Event>, +} + +#[cfg(feature = "alloc")] +impl EventVec { +    /// Constructs an `EventVec` from raw pointer, length, and capacity. +    /// +    /// # Safety +    /// +    /// This function calls [`Vec::from_raw_parts`] with its arguments. +    /// +    /// [`Vec::from_raw_parts`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.from_raw_parts +    #[inline] +    pub unsafe fn from_raw_parts(ptr: *mut Event, len: usize, capacity: usize) -> Self { +        Self { +            events: Vec::from_raw_parts(ptr, len, capacity), +        } +    } + +    /// Constructs an `EventVec` with memory for `capacity` `Event`s. +    #[inline] +    pub fn with_capacity(capacity: usize) -> Self { +        Self { +            events: Vec::with_capacity(capacity), +        } +    } + +    /// 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<'_> { +        Iter { +            iter: self.events.iter().copied(), +        } +    } + +    /// 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() +    } +} + +#[cfg(feature = "alloc")] +impl<'a> IntoIterator for &'a EventVec { +    type IntoIter = Iter<'a>; +    type Item = Event; + +    #[inline] +    fn into_iter(self) -> Self::IntoIter { +        self.iter() +    } +} + +#[test] +fn test_epoll_layouts() { +    check_renamed_type!(Event, epoll_event); +    check_renamed_type!(Event, epoll_event); +    check_renamed_struct_renamed_field!(Event, epoll_event, flags, events); +    check_renamed_struct_renamed_field!(Event, epoll_event, data, u64); +} diff --git a/vendor/rustix/src/backend/libc/event/mod.rs b/vendor/rustix/src/backend/libc/event/mod.rs new file mode 100644 index 0000000..6aed461 --- /dev/null +++ b/vendor/rustix/src/backend/libc/event/mod.rs @@ -0,0 +1,9 @@ +pub(crate) mod poll_fd; +#[cfg(not(windows))] +pub(crate) mod types; + +#[cfg_attr(windows, path = "windows_syscalls.rs")] +pub(crate) mod syscalls; + +#[cfg(linux_kernel)] +pub mod epoll; diff --git a/vendor/rustix/src/backend/libc/event/poll_fd.rs b/vendor/rustix/src/backend/libc/event/poll_fd.rs new file mode 100644 index 0000000..32fd83d --- /dev/null +++ b/vendor/rustix/src/backend/libc/event/poll_fd.rs @@ -0,0 +1,142 @@ +use crate::backend::c; +use crate::backend::conv::borrowed_fd; +use crate::backend::fd::{AsFd, AsRawFd, BorrowedFd, LibcFd}; +use bitflags::bitflags; +use core::marker::PhantomData; +#[cfg(windows)] +use { +    crate::backend::fd::{AsSocket, RawFd}, +    core::fmt, +}; + +bitflags! { +    /// `POLL*` flags for use with [`poll`]. +    /// +    /// [`poll`]: crate::event::poll +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    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` +        const RDNORM = c::POLLRDNORM; +        /// `POLLWRNORM` +        #[cfg(not(target_os = "l4re"))] +        const WRNORM = c::POLLWRNORM; +        /// `POLLRDBAND` +        #[cfg(not(any(target_os = "l4re", target_os = "wasi")))] +        const RDBAND = c::POLLRDBAND; +        /// `POLLWRBAND` +        #[cfg(not(any(target_os = "l4re", target_os = "wasi")))] +        const WRBAND = c::POLLWRBAND; +        /// `POLLERR` +        const ERR = c::POLLERR; +        /// `POLLHUP` +        const HUP = c::POLLHUP; +        /// `POLLNVAL` +        #[cfg(not(target_os = "espidf"))] +        const NVAL = c::POLLNVAL; +        /// `POLLRDHUP` +        #[cfg(all( +            linux_kernel, +            not(any(target_arch = "sparc", target_arch = "sparc64"))), +        )] +        const RDHUP = c::POLLRDHUP; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// `struct pollfd`—File descriptor and flags for use with [`poll`]. +/// +/// [`poll`]: crate::event::poll +#[doc(alias = "pollfd")] +#[derive(Clone)] +#[cfg_attr(not(windows), derive(Debug))] +#[repr(transparent)] +pub struct PollFd<'fd> { +    pollfd: c::pollfd, +    _phantom: PhantomData<BorrowedFd<'fd>>, +} + +#[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: AsFd>(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<Fd: AsFd>(&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> 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/event/syscalls.rs b/vendor/rustix/src/backend/libc/event/syscalls.rs new file mode 100644 index 0000000..725ec82 --- /dev/null +++ b/vendor/rustix/src/backend/libc/event/syscalls.rs @@ -0,0 +1,191 @@ +//! libc syscalls supporting `rustix::event`. + +use crate::backend::c; +use crate::backend::conv::ret_c_int; +#[cfg(any(apple, netbsdlike, target_os = "dragonfly", target_os = "solaris"))] +use crate::backend::conv::ret_owned_fd; +use crate::event::PollFd; +#[cfg(any(linux_kernel, bsd, solarish, target_os = "espidf"))] +use crate::fd::OwnedFd; +use crate::io; +#[cfg(any(bsd, solarish))] +use {crate::backend::conv::borrowed_fd, crate::fd::BorrowedFd, core::mem::MaybeUninit}; +#[cfg(solarish)] +use { +    crate::backend::conv::ret, crate::event::port::Event, crate::utils::as_mut_ptr, +    core::ptr::null_mut, +}; +#[cfg(any( +    linux_kernel, +    target_os = "freebsd", +    target_os = "illumos", +    target_os = "espidf" +))] +use {crate::backend::conv::ret_owned_fd, crate::event::EventfdFlags}; +#[cfg(all(feature = "alloc", bsd))] +use {crate::event::kqueue::Event, crate::utils::as_ptr, core::ptr::null}; + +#[cfg(any( +    linux_kernel, +    target_os = "freebsd", +    target_os = "illumos", +    target_os = "espidf" +))] +pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { +    #[cfg(linux_kernel)] +    unsafe { +        syscall! { +            fn eventfd2( +                initval: c::c_uint, +                flags: c::c_int +            ) via SYS_eventfd2 -> c::c_int +        } +        ret_owned_fd(eventfd2(initval, bitflags_bits!(flags))) +    } + +    // `eventfd` was added in FreeBSD 13, so it isn't available on FreeBSD 12. +    #[cfg(target_os = "freebsd")] +    unsafe { +        weakcall! { +            fn eventfd( +                initval: c::c_uint, +                flags: c::c_int +            ) -> c::c_int +        } +        ret_owned_fd(eventfd(initval, bitflags_bits!(flags))) +    } + +    #[cfg(any(target_os = "illumos", target_os = "espidf"))] +    unsafe { +        ret_owned_fd(c::eventfd(initval, bitflags_bits!(flags))) +    } +} + +#[cfg(all(feature = "alloc", bsd))] +pub(crate) fn kqueue() -> io::Result<OwnedFd> { +    unsafe { ret_owned_fd(c::kqueue()) } +} + +#[cfg(all(feature = "alloc", bsd))] +pub(crate) unsafe fn kevent( +    kq: BorrowedFd<'_>, +    changelist: &[Event], +    eventlist: &mut [MaybeUninit<Event>], +    timeout: Option<&c::timespec>, +) -> io::Result<c::c_int> { +    ret_c_int(c::kevent( +        borrowed_fd(kq), +        changelist.as_ptr().cast(), +        changelist +            .len() +            .try_into() +            .map_err(|_| io::Errno::OVERFLOW)?, +        eventlist.as_mut_ptr().cast(), +        eventlist +            .len() +            .try_into() +            .map_err(|_| io::Errno::OVERFLOW)?, +        timeout.map_or(null(), as_ptr), +    )) +} + +#[inline] +pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> { +    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(solarish)] +pub(crate) fn port_create() -> io::Result<OwnedFd> { +    unsafe { ret_owned_fd(c::port_create()) } +} + +#[cfg(solarish)] +pub(crate) unsafe fn port_associate( +    port: BorrowedFd<'_>, +    source: c::c_int, +    object: c::uintptr_t, +    events: c::c_int, +    user: *mut c::c_void, +) -> io::Result<()> { +    ret(c::port_associate( +        borrowed_fd(port), +        source, +        object, +        events, +        user, +    )) +} + +#[cfg(solarish)] +pub(crate) unsafe fn port_dissociate( +    port: BorrowedFd<'_>, +    source: c::c_int, +    object: c::uintptr_t, +) -> io::Result<()> { +    ret(c::port_dissociate(borrowed_fd(port), source, object)) +} + +#[cfg(solarish)] +pub(crate) fn port_get( +    port: BorrowedFd<'_>, +    timeout: Option<&mut c::timespec>, +) -> io::Result<Event> { +    let mut event = MaybeUninit::<c::port_event>::uninit(); +    let timeout = timeout.map_or(null_mut(), as_mut_ptr); + +    unsafe { +        ret(c::port_get(borrowed_fd(port), event.as_mut_ptr(), timeout))?; +    } + +    // If we're done, initialize the event and return it. +    Ok(Event(unsafe { event.assume_init() })) +} + +#[cfg(all(feature = "alloc", solarish))] +pub(crate) fn port_getn( +    port: BorrowedFd<'_>, +    timeout: Option<&mut c::timespec>, +    events: &mut Vec<Event>, +    mut nget: u32, +) -> io::Result<()> { +    let timeout = timeout.map_or(null_mut(), as_mut_ptr); +    unsafe { +        ret(c::port_getn( +            borrowed_fd(port), +            events.as_mut_ptr().cast(), +            events.len().try_into().unwrap(), +            &mut nget, +            timeout, +        ))?; +    } + +    // Update the vector length. +    unsafe { +        events.set_len(nget.try_into().unwrap()); +    } + +    Ok(()) +} + +#[cfg(solarish)] +pub(crate) fn port_send( +    port: BorrowedFd<'_>, +    events: c::c_int, +    userdata: *mut c::c_void, +) -> io::Result<()> { +    unsafe { ret(c::port_send(borrowed_fd(port), events, userdata)) } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn pause() { +    let r = unsafe { libc::pause() }; +    let errno = libc_errno::errno().0; +    debug_assert_eq!(r, -1); +    debug_assert_eq!(errno, libc::EINTR); +} diff --git a/vendor/rustix/src/backend/libc/event/types.rs b/vendor/rustix/src/backend/libc/event/types.rs new file mode 100644 index 0000000..a04d7e6 --- /dev/null +++ b/vendor/rustix/src/backend/libc/event/types.rs @@ -0,0 +1,37 @@ +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))] +use crate::backend::c; +#[cfg(any( +    linux_kernel, +    target_os = "freebsd", +    target_os = "illumos", +    target_os = "espidf" +))] +use bitflags::bitflags; + +#[cfg(any( +    linux_kernel, +    target_os = "freebsd", +    target_os = "illumos", +    target_os = "espidf" +))] +bitflags! { +    /// `EFD_*` flags for use with [`eventfd`]. +    /// +    /// [`eventfd`]: crate::event::eventfd +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct EventfdFlags: u32 { +        /// `EFD_CLOEXEC` +        #[cfg(not(target_os = "espidf"))] +        const CLOEXEC = bitcast!(c::EFD_CLOEXEC); +        /// `EFD_NONBLOCK` +        #[cfg(not(target_os = "espidf"))] +        const NONBLOCK = bitcast!(c::EFD_NONBLOCK); +        /// `EFD_SEMAPHORE` +        #[cfg(not(target_os = "espidf"))] +        const SEMAPHORE = bitcast!(c::EFD_SEMAPHORE); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} diff --git a/vendor/rustix/src/backend/libc/event/windows_syscalls.rs b/vendor/rustix/src/backend/libc/event/windows_syscalls.rs new file mode 100644 index 0000000..8ccad47 --- /dev/null +++ b/vendor/rustix/src/backend/libc/event/windows_syscalls.rs @@ -0,0 +1,16 @@ +//! Windows system calls in the `event` module. + +use crate::backend::c; +use crate::backend::conv::ret_c_int; +use crate::event::PollFd; +use crate::io; + +pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> { +    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) +} diff --git a/vendor/rustix/src/backend/libc/fs/dir.rs b/vendor/rustix/src/backend/libc/fs/dir.rs new file mode 100644 index 0000000..82a0a90 --- /dev/null +++ b/vendor/rustix/src/backend/libc/fs/dir.rs @@ -0,0 +1,423 @@ +#[cfg(not(any(solarish, target_os = "haiku", target_os = "nto", target_os = "vita")))] +use super::types::FileType; +use crate::backend::c; +use crate::backend::conv::owned_fd; +use crate::fd::{AsFd, BorrowedFd, OwnedFd}; +use crate::ffi::{CStr, CString}; +use crate::fs::{fcntl_getfl, openat, Mode, OFlags}; +#[cfg(not(target_os = "vita"))] +use crate::fs::{fstat, Stat}; +#[cfg(not(any( +    solarish, +    target_os = "haiku", +    target_os = "netbsd", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +use crate::fs::{fstatfs, StatFs}; +#[cfg(not(any( +    solarish, +    target_os = "haiku", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +use crate::fs::{fstatvfs, StatVfs}; +use crate::io; +#[cfg(not(any(target_os = "fuchsia", target_os = "vita", target_os = "wasi")))] +#[cfg(feature = "process")] +use crate::process::fchdir; +use alloc::borrow::ToOwned; +#[cfg(not(any(linux_like, target_os = "hurd")))] +use c::readdir as libc_readdir; +#[cfg(any(linux_like, target_os = "hurd"))] +use c::readdir64 as libc_readdir; +use core::fmt; +use core::ptr::NonNull; +use libc_errno::{errno, set_errno, Errno}; + +/// `DIR*` +pub struct Dir { +    /// The `libc` `DIR` pointer. +    libc_dir: NonNull<c::DIR>, + +    /// Have we seen any errors in this iteration? +    any_errors: bool, +} + +impl Dir { +    /// Take ownership of `fd` and construct a `Dir` that reads entries from +    /// the given directory file descriptor. +    #[inline] +    pub fn new<Fd: Into<OwnedFd>>(fd: Fd) -> io::Result<Self> { +        Self::_new(fd.into()) +    } + +    #[inline] +    fn _new(fd: OwnedFd) -> io::Result<Self> { +        let raw = owned_fd(fd); +        unsafe { +            let libc_dir = c::fdopendir(raw); + +            if let Some(libc_dir) = NonNull::new(libc_dir) { +                Ok(Self { +                    libc_dir, +                    any_errors: false, +                }) +            } else { +                let err = io::Errno::last_os_error(); +                let _ = c::close(raw); +                Err(err) +            } +        } +    } + +    /// Borrow `fd` and construct a `Dir` that reads entries from the given +    /// directory file descriptor. +    #[inline] +    pub fn read_from<Fd: AsFd>(fd: Fd) -> io::Result<Self> { +        Self::_read_from(fd.as_fd()) +    } + +    #[inline] +    #[allow(unused_mut)] +    fn _read_from(fd: BorrowedFd<'_>) -> io::Result<Self> { +        let mut any_errors = false; + +        // Given an arbitrary `OwnedFd`, it's impossible to know whether the +        // user holds a `dup`'d copy which could continue to modify the +        // file description state, which would cause Undefined Behavior after +        // our call to `fdopendir`. To prevent this, we obtain an independent +        // `OwnedFd`. +        let flags = fcntl_getfl(fd)?; +        let fd_for_dir = match openat(fd, cstr!("."), flags | OFlags::CLOEXEC, Mode::empty()) { +            Ok(fd) => fd, +            #[cfg(not(target_os = "wasi"))] +            Err(io::Errno::NOENT) => { +                // If "." doesn't exist, it means the directory was removed. +                // We treat that as iterating through a directory with no +                // entries. +                any_errors = true; +                crate::io::dup(fd)? +            } +            Err(err) => return Err(err), +        }; + +        let raw = owned_fd(fd_for_dir); +        unsafe { +            let libc_dir = c::fdopendir(raw); + +            if let Some(libc_dir) = NonNull::new(libc_dir) { +                Ok(Self { +                    libc_dir, +                    any_errors, +                }) +            } else { +                let err = io::Errno::last_os_error(); +                let _ = c::close(raw); +                Err(err) +            } +        } +    } + +    /// `rewinddir(self)` +    #[inline] +    pub fn rewind(&mut self) { +        self.any_errors = false; +        unsafe { c::rewinddir(self.libc_dir.as_ptr()) } +    } + +    /// `readdir(self)`, where `None` means the end of the directory. +    pub fn read(&mut self) -> Option<io::Result<DirEntry>> { +        // If we've seen errors, don't continue to try to read anyting further. +        if self.any_errors { +            return None; +        } + +        set_errno(Errno(0)); +        let dirent_ptr = unsafe { libc_readdir(self.libc_dir.as_ptr()) }; +        if dirent_ptr.is_null() { +            let curr_errno = errno().0; +            if curr_errno == 0 { +                // We successfully reached the end of the stream. +                None +            } else { +                // `errno` is unknown or non-zero, so an error occurred. +                self.any_errors = true; +                Some(Err(io::Errno(curr_errno))) +            } +        } else { +            // We successfully read an entry. +            unsafe { +                let dirent = &*dirent_ptr; + +                // We have our own copy of OpenBSD's dirent; check that the +                // layout minimally matches libc's. +                #[cfg(target_os = "openbsd")] +                check_dirent_layout(dirent); + +                let result = DirEntry { +                    #[cfg(not(any( +                        solarish, +                        target_os = "aix", +                        target_os = "haiku", +                        target_os = "nto", +                        target_os = "vita" +                    )))] +                    d_type: dirent.d_type, + +                    #[cfg(not(any(freebsdlike, netbsdlike, target_os = "vita")))] +                    d_ino: dirent.d_ino, + +                    #[cfg(any(freebsdlike, netbsdlike))] +                    d_fileno: dirent.d_fileno, + +                    name: CStr::from_ptr(dirent.d_name.as_ptr()).to_owned(), +                }; + +                Some(Ok(result)) +            } +        } +    } + +    /// `fstat(self)` +    #[cfg(not(target_os = "vita"))] +    #[inline] +    pub fn stat(&self) -> io::Result<Stat> { +        fstat(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.libc_dir.as_ptr())) }) +    } + +    /// `fstatfs(self)` +    #[cfg(not(any( +        solarish, +        target_os = "haiku", +        target_os = "netbsd", +        target_os = "nto", +        target_os = "redox", +        target_os = "vita", +        target_os = "wasi", +    )))] +    #[inline] +    pub fn statfs(&self) -> io::Result<StatFs> { +        fstatfs(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.libc_dir.as_ptr())) }) +    } + +    /// `fstatvfs(self)` +    #[cfg(not(any( +        solarish, +        target_os = "haiku", +        target_os = "redox", +        target_os = "vita", +        target_os = "wasi" +    )))] +    #[inline] +    pub fn statvfs(&self) -> io::Result<StatVfs> { +        fstatvfs(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.libc_dir.as_ptr())) }) +    } + +    /// `fchdir(self)` +    #[cfg(feature = "process")] +    #[cfg(not(any(target_os = "fuchsia", target_os = "vita", target_os = "wasi")))] +    #[cfg_attr(doc_cfg, doc(cfg(feature = "process")))] +    #[inline] +    pub fn chdir(&self) -> io::Result<()> { +        fchdir(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.libc_dir.as_ptr())) }) +    } +} + +/// `Dir` implements `Send` but not `Sync`, because we use `readdir` which is +/// not guaranteed to be thread-safe. Users can wrap this in a `Mutex` if they +/// need `Sync`, which is effectively what'd need to do to implement `Sync` +/// ourselves. +unsafe impl Send for Dir {} + +impl Drop for Dir { +    #[inline] +    fn drop(&mut self) { +        unsafe { c::closedir(self.libc_dir.as_ptr()) }; +    } +} + +impl Iterator for Dir { +    type Item = io::Result<DirEntry>; + +    #[inline] +    fn next(&mut self) -> Option<Self::Item> { +        Self::read(self) +    } +} + +impl fmt::Debug for Dir { +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +        let mut s = f.debug_struct("Dir"); +        #[cfg(not(target_os = "vita"))] +        s.field("fd", unsafe { &c::dirfd(self.libc_dir.as_ptr()) }); +        s.finish() +    } +} + +/// `struct dirent` +#[derive(Debug)] +pub struct DirEntry { +    #[cfg(not(any( +        solarish, +        target_os = "aix", +        target_os = "haiku", +        target_os = "nto", +        target_os = "vita" +    )))] +    d_type: u8, + +    #[cfg(not(any(freebsdlike, netbsdlike, target_os = "vita")))] +    d_ino: c::ino_t, + +    #[cfg(any(freebsdlike, netbsdlike))] +    d_fileno: c::ino_t, + +    name: CString, +} + +impl DirEntry { +    /// Returns the file name of this directory entry. +    #[inline] +    pub fn file_name(&self) -> &CStr { +        &self.name +    } + +    /// Returns the type of this directory entry. +    #[cfg(not(any( +        solarish, +        target_os = "aix", +        target_os = "haiku", +        target_os = "nto", +        target_os = "vita" +    )))] +    #[inline] +    pub fn file_type(&self) -> FileType { +        FileType::from_dirent_d_type(self.d_type) +    } + +    /// Return the inode number of this directory entry. +    #[cfg(not(any(freebsdlike, netbsdlike, target_os = "vita")))] +    #[inline] +    pub fn ino(&self) -> u64 { +        self.d_ino as u64 +    } + +    /// Return the inode number of this directory entry. +    #[cfg(any(freebsdlike, netbsdlike))] +    #[inline] +    pub fn ino(&self) -> u64 { +        #[allow(clippy::useless_conversion)] +        self.d_fileno.into() +    } +} + +/// libc's OpenBSD `dirent` has a private field so we can't construct it +/// directly, so we declare it ourselves to make all fields accessible. +#[cfg(target_os = "openbsd")] +#[repr(C)] +#[derive(Debug)] +struct libc_dirent { +    d_fileno: c::ino_t, +    d_off: c::off_t, +    d_reclen: u16, +    d_type: u8, +    d_namlen: u8, +    __d_padding: [u8; 4], +    d_name: [c::c_char; 256], +} + +/// We have our own copy of OpenBSD's dirent; check that the layout +/// minimally matches libc's. +#[cfg(target_os = "openbsd")] +fn check_dirent_layout(dirent: &c::dirent) { +    use crate::utils::as_ptr; + +    // Check that the basic layouts match. +    #[cfg(test)] +    { +        assert_eq_size!(libc_dirent, c::dirent); +        assert_eq_size!(libc_dirent, c::dirent); +    } + +    // Check that the field offsets match. +    assert_eq!( +        { +            let z = libc_dirent { +                d_fileno: 0_u64, +                d_off: 0_i64, +                d_reclen: 0_u16, +                d_type: 0_u8, +                d_namlen: 0_u8, +                __d_padding: [0_u8; 4], +                d_name: [0 as c::c_char; 256], +            }; +            let base = as_ptr(&z) as usize; +            ( +                (as_ptr(&z.d_fileno) as usize) - base, +                (as_ptr(&z.d_off) as usize) - base, +                (as_ptr(&z.d_reclen) as usize) - base, +                (as_ptr(&z.d_type) as usize) - base, +                (as_ptr(&z.d_namlen) as usize) - base, +                (as_ptr(&z.d_name) as usize) - base, +            ) +        }, +        { +            let z = dirent; +            let base = as_ptr(z) as usize; +            ( +                (as_ptr(&z.d_fileno) as usize) - base, +                (as_ptr(&z.d_off) as usize) - base, +                (as_ptr(&z.d_reclen) as usize) - base, +                (as_ptr(&z.d_type) as usize) - base, +                (as_ptr(&z.d_namlen) as usize) - base, +                (as_ptr(&z.d_name) as usize) - base, +            ) +        } +    ); +} + +#[test] +fn dir_iterator_handles_io_errors() { +    // create a dir, keep the FD, then delete the dir +    let tmp = tempfile::tempdir().unwrap(); +    let fd = crate::fs::openat( +        crate::fs::CWD, +        tmp.path(), +        crate::fs::OFlags::RDONLY | crate::fs::OFlags::CLOEXEC, +        crate::fs::Mode::empty(), +    ) +    .unwrap(); + +    let file_fd = crate::fs::openat( +        &fd, +        tmp.path().join("test.txt"), +        crate::fs::OFlags::WRONLY | crate::fs::OFlags::CREATE, +        crate::fs::Mode::RWXU, +    ) +    .unwrap(); + +    let mut dir = Dir::read_from(&fd).unwrap(); + +    // Reach inside the `Dir` and replace its directory with a file, which +    // will cause the subsequent `readdir` to fail. +    unsafe { +        let raw_fd = c::dirfd(dir.libc_dir.as_ptr()); +        let mut owned_fd: crate::fd::OwnedFd = crate::fd::FromRawFd::from_raw_fd(raw_fd); +        crate::io::dup2(&file_fd, &mut owned_fd).unwrap(); +        core::mem::forget(owned_fd); +    } + +    // FreeBSD and macOS seem to read some directory entries before we call +    // `.next()`. +    #[cfg(any(apple, freebsdlike))] +    { +        dir.rewind(); +    } + +    assert!(matches!(dir.next(), Some(Err(_)))); +    assert!(dir.next().is_none()); +} diff --git a/vendor/rustix/src/backend/libc/fs/inotify.rs b/vendor/rustix/src/backend/libc/fs/inotify.rs new file mode 100644 index 0000000..2044bd9 --- /dev/null +++ b/vendor/rustix/src/backend/libc/fs/inotify.rs @@ -0,0 +1,131 @@ +//! inotify support for working with inotifies + +use crate::backend::c; +use crate::backend::conv::{borrowed_fd, c_str, ret, ret_c_int, ret_owned_fd}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use bitflags::bitflags; + +bitflags! { +    /// `IN_*` for use with [`inotify_init`]. +    /// +    /// [`inotify_init`]: crate::fs::inotify::inotify_init +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct CreateFlags: u32 { +        /// `IN_CLOEXEC` +        const CLOEXEC = bitcast!(c::IN_CLOEXEC); +        /// `IN_NONBLOCK` +        const NONBLOCK = bitcast!(c::IN_NONBLOCK); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +bitflags! { +    /// `IN*` for use with [`inotify_add_watch`]. +    /// +    /// [`inotify_add_watch`]: crate::fs::inotify::inotify_add_watch +    #[repr(transparent)] +    #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct WatchFlags: u32 { +        /// `IN_ACCESS` +        const ACCESS = c::IN_ACCESS; +        /// `IN_ATTRIB` +        const ATTRIB = c::IN_ATTRIB; +        /// `IN_CLOSE_NOWRITE` +        const CLOSE_NOWRITE = c::IN_CLOSE_NOWRITE; +        /// `IN_CLOSE_WRITE` +        const CLOSE_WRITE = c::IN_CLOSE_WRITE; +        /// `IN_CREATE` +        const CREATE = c::IN_CREATE; +        /// `IN_DELETE` +        const DELETE = c::IN_DELETE; +        /// `IN_DELETE_SELF` +        const DELETE_SELF = c::IN_DELETE_SELF; +        /// `IN_MODIFY` +        const MODIFY = c::IN_MODIFY; +        /// `IN_MOVE_SELF` +        const MOVE_SELF = c::IN_MOVE_SELF; +        /// `IN_MOVED_FROM` +        const MOVED_FROM = c::IN_MOVED_FROM; +        /// `IN_MOVED_TO` +        const MOVED_TO = c::IN_MOVED_TO; +        /// `IN_OPEN` +        const OPEN = c::IN_OPEN; + +        /// `IN_CLOSE` +        const CLOSE = c::IN_CLOSE; +        /// `IN_MOVE` +        const MOVE = c::IN_MOVE; +        /// `IN_ALL_EVENTS` +        const ALL_EVENTS = c::IN_ALL_EVENTS; + +        /// `IN_DONT_FOLLOW` +        const DONT_FOLLOW = c::IN_DONT_FOLLOW; +        /// `IN_EXCL_UNLINK` +        const EXCL_UNLINK = 1; +        /// `IN_MASK_ADD` +        const MASK_ADD = 1; +        /// `IN_MASK_CREATE` +        const MASK_CREATE = 1; +        /// `IN_ONESHOT` +        const ONESHOT = c::IN_ONESHOT; +        /// `IN_ONLYDIR` +        const ONLYDIR = c::IN_ONLYDIR; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// `inotify_init1(flags)`—Creates a new inotify object. +/// +/// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file +/// descriptor from being implicitly passed across `exec` boundaries. +#[doc(alias = "inotify_init1")] +pub fn inotify_init(flags: CreateFlags) -> io::Result<OwnedFd> { +    // SAFETY: `inotify_init1` has no safety preconditions. +    unsafe { ret_owned_fd(c::inotify_init1(bitflags_bits!(flags))) } +} + +/// `inotify_add_watch(self, path, flags)`—Adds a watch to inotify. +/// +/// This registers or updates a watch for the filesystem path `path` and +/// returns a watch descriptor corresponding to this watch. +/// +/// Note: Due to the existence of hardlinks, providing two different paths to +/// this method may result in it returning the same watch descriptor. An +/// application should keep track of this externally to avoid logic errors. +pub fn inotify_add_watch<P: crate::path::Arg>( +    inot: BorrowedFd<'_>, +    path: P, +    flags: WatchFlags, +) -> io::Result<i32> { +    path.into_with_c_str(|path| { +        // SAFETY: The fd and path we are passing is guaranteed valid by the +        // type system. +        unsafe { +            ret_c_int(c::inotify_add_watch( +                borrowed_fd(inot), +                c_str(path), +                flags.bits(), +            )) +        } +    }) +} + +/// `inotify_rm_watch(self, wd)`—Removes a watch from this inotify. +/// +/// The watch descriptor provided should have previously been returned by +/// [`inotify_add_watch`] and not previously have been removed. +#[doc(alias = "inotify_rm_watch")] +pub fn inotify_remove_watch(inot: BorrowedFd<'_>, wd: i32) -> io::Result<()> { +    // Android's `inotify_rm_watch` takes `u32` despite that +    // `inotify_add_watch` expects a `i32`. +    #[cfg(target_os = "android")] +    let wd = wd as u32; +    // SAFETY: The fd is valid and closing an arbitrary wd is valid. +    unsafe { ret(c::inotify_rm_watch(borrowed_fd(inot), wd)) } +} diff --git a/vendor/rustix/src/backend/libc/fs/makedev.rs b/vendor/rustix/src/backend/libc/fs/makedev.rs new file mode 100644 index 0000000..aa12102 --- /dev/null +++ b/vendor/rustix/src/backend/libc/fs/makedev.rs @@ -0,0 +1,138 @@ +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +use crate::backend::c; +use crate::fs::Dev; + +#[cfg(not(any( +    apple, +    solarish, +    target_os = "aix", +    target_os = "android", +    target_os = "emscripten", +)))] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { +    c::makedev(maj, min) +} + +#[cfg(solarish)] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { +    // SAFETY: Solarish's `makedev` is marked unsafe but it isn't doing +    // anything unsafe. +    unsafe { c::makedev(maj, min) } +} + +#[cfg(all(target_os = "android", not(target_pointer_width = "32")))] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { +    c::makedev(maj, min) +} + +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { +    // 32-bit Android's `dev_t` is 32-bit, but its `st_dev` is 64-bit, so we do +    // it ourselves. +    ((u64::from(maj) & 0xffff_f000_u64) << 32) +        | ((u64::from(maj) & 0x0000_0fff_u64) << 8) +        | ((u64::from(min) & 0xffff_ff00_u64) << 12) +        | (u64::from(min) & 0x0000_00ff_u64) +} + +#[cfg(target_os = "emscripten")] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { +    // Emscripten's `makedev` has a 32-bit return value. +    Dev::from(c::makedev(maj, min)) +} + +#[cfg(apple)] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { +    // Apple's `makedev` oddly has signed argument types and is `unsafe`. +    unsafe { c::makedev(maj as i32, min as i32) } +} + +#[cfg(target_os = "aix")] +#[inline] +pub(crate) fn makedev(maj: u32, min: u32) -> Dev { +    // AIX's `makedev` oddly is `unsafe`. +    unsafe { c::makedev(maj, min) } +} + +#[cfg(not(any( +    apple, +    freebsdlike, +    target_os = "android", +    target_os = "emscripten", +    target_os = "netbsd" +)))] +#[inline] +pub(crate) fn major(dev: Dev) -> u32 { +    unsafe { c::major(dev) } +} + +#[cfg(any( +    apple, +    freebsdlike, +    target_os = "netbsd", +    all(target_os = "android", not(target_pointer_width = "32")), +))] +#[inline] +pub(crate) fn major(dev: Dev) -> u32 { +    // On some platforms `major` oddly has signed return types. +    (unsafe { c::major(dev) }) as u32 +} + +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +#[inline] +pub(crate) fn major(dev: Dev) -> u32 { +    // 32-bit Android's `dev_t` is 32-bit, but its `st_dev` is 64-bit, so we do +    // it ourselves. +    (((dev >> 31 >> 1) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)) as u32 +} + +#[cfg(target_os = "emscripten")] +#[inline] +pub(crate) fn major(dev: Dev) -> u32 { +    // Emscripten's `major` has a 32-bit argument value. +    unsafe { c::major(dev as u32) } +} + +#[cfg(not(any( +    apple, +    freebsdlike, +    target_os = "android", +    target_os = "emscripten", +    target_os = "netbsd" +)))] +#[inline] +pub(crate) fn minor(dev: Dev) -> u32 { +    unsafe { c::minor(dev) } +} + +#[cfg(any( +    apple, +    freebsdlike, +    target_os = "netbsd", +    all(target_os = "android", not(target_pointer_width = "32")) +))] +#[inline] +pub(crate) fn minor(dev: Dev) -> u32 { +    // On some platforms, `minor` oddly has signed return types. +    (unsafe { c::minor(dev) }) as u32 +} + +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +#[inline] +pub(crate) fn minor(dev: Dev) -> u32 { +    // 32-bit Android's `dev_t` is 32-bit, but its `st_dev` is 64-bit, so we do +    // it ourselves. +    (((dev >> 12) & 0xffff_ff00) | (dev & 0x0000_00ff)) as u32 +} + +#[cfg(target_os = "emscripten")] +#[inline] +pub(crate) fn minor(dev: Dev) -> u32 { +    // Emscripten's `minor` has a 32-bit argument value. +    unsafe { c::minor(dev as u32) } +} diff --git a/vendor/rustix/src/backend/libc/fs/mod.rs b/vendor/rustix/src/backend/libc/fs/mod.rs new file mode 100644 index 0000000..c17e863 --- /dev/null +++ b/vendor/rustix/src/backend/libc/fs/mod.rs @@ -0,0 +1,23 @@ +#[cfg(all(feature = "alloc", not(any(target_os = "espidf", target_os = "redox"))))] +pub(crate) mod dir; +#[cfg(linux_kernel)] +pub mod inotify; +#[cfg(not(any( +    target_os = "espidf", +    target_os = "haiku", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) mod makedev; +#[cfg(not(windows))] +pub(crate) mod syscalls; +pub(crate) mod types; + +// TODO: Fix linux-raw-sys to define ioctl codes for sparc. +#[cfg(all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64")))] +pub(crate) const EXT4_IOC_RESIZE_FS: crate::ioctl::RawOpcode = 0x8008_6610; + +#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))] +pub(crate) const EXT4_IOC_RESIZE_FS: crate::ioctl::RawOpcode = +    linux_raw_sys::ioctl::EXT4_IOC_RESIZE_FS as crate::ioctl::RawOpcode; diff --git a/vendor/rustix/src/backend/libc/fs/syscalls.rs b/vendor/rustix/src/backend/libc/fs/syscalls.rs new file mode 100644 index 0000000..70e86cf --- /dev/null +++ b/vendor/rustix/src/backend/libc/fs/syscalls.rs @@ -0,0 +1,2514 @@ +//! libc syscalls supporting `rustix::fs`. + +use crate::backend::c; +#[cfg(any( +    not(target_os = "redox"), +    feature = "alloc", +    all(linux_kernel, feature = "procfs") +))] +use crate::backend::conv::ret_usize; +use crate::backend::conv::{borrowed_fd, c_str, ret, ret_c_int, ret_off_t, ret_owned_fd}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::ffi::CStr; +#[cfg(all(apple, feature = "alloc"))] +use crate::ffi::CString; +#[cfg(not(any(target_os = "espidf", target_os = "vita")))] +use crate::fs::Access; +#[cfg(not(any( +    apple, +    netbsdlike, +    solarish, +    target_os = "dragonfly", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "redox", +    target_os = "vita", +)))] +use crate::fs::Advice; +#[cfg(not(any(target_os = "espidf", target_os = "redox")))] +use crate::fs::AtFlags; +#[cfg(not(any( +    netbsdlike, +    solarish, +    target_os = "aix", +    target_os = "dragonfly", +    target_os = "espidf", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +)))] +use crate::fs::FallocateFlags; +#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))] +use crate::fs::FlockOperation; +#[cfg(any(linux_kernel, target_os = "freebsd"))] +use crate::fs::MemfdFlags; +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +use crate::fs::SealFlags; +#[cfg(not(any( +    solarish, +    target_os = "espidf", +    target_os = "haiku", +    target_os = "netbsd", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +use crate::fs::StatFs; +#[cfg(not(any(target_os = "espidf", target_os = "vita")))] +use crate::fs::Timestamps; +#[cfg(not(any( +    apple, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +use crate::fs::{Dev, FileType}; +use crate::fs::{Mode, OFlags, SeekFrom, Stat}; +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +use crate::fs::{StatVfs, StatVfsMountFlags}; +use crate::io; +#[cfg(all(target_env = "gnu", fix_y2038))] +use crate::timespec::LibcTimespec; +#[cfg(not(target_os = "wasi"))] +use crate::ugid::{Gid, Uid}; +#[cfg(all(apple, feature = "alloc"))] +use alloc::vec; +use core::mem::MaybeUninit; +#[cfg(apple)] +use { +    crate::backend::conv::nonnegative_ret, +    crate::fs::{copyfile_state_t, CloneFlags, CopyfileFlags}, +}; +#[cfg(any(apple, linux_kernel))] +use {crate::fs::XattrFlags, core::mem::size_of, core::ptr::null_mut}; +#[cfg(linux_kernel)] +use { +    crate::fs::{RenameFlags, ResolveFlags, Statx, StatxFlags, CWD}, +    core::ptr::null, +}; + +#[cfg(all(target_env = "gnu", fix_y2038))] +weak!(fn __utimensat64(c::c_int, *const c::c_char, *const LibcTimespec, c::c_int) -> c::c_int); +#[cfg(all(target_env = "gnu", fix_y2038))] +weak!(fn __futimens64(c::c_int, *const LibcTimespec) -> c::c_int); + +/// Use a direct syscall (via libc) for `open`. +/// +/// This is only currently necessary as a workaround for old glibc; see below. +#[cfg(all(unix, target_env = "gnu"))] +fn open_via_syscall(path: &CStr, oflags: OFlags, mode: Mode) -> io::Result<OwnedFd> { +    // Linux on aarch64, loongarch64 and riscv64 has no `open` syscall so use +    // `openat`. +    #[cfg(any( +        target_arch = "aarch64", +        target_arch = "riscv32", +        target_arch = "riscv64", +        target_arch = "csky", +        target_arch = "loongarch64" +    ))] +    { +        openat_via_syscall(CWD, path, oflags, mode) +    } + +    // Use the `open` syscall. +    #[cfg(not(any( +        target_arch = "aarch64", +        target_arch = "riscv32", +        target_arch = "riscv64", +        target_arch = "csky", +        target_arch = "loongarch64" +    )))] +    unsafe { +        syscall! { +            fn open( +                pathname: *const c::c_char, +                oflags: c::c_int, +                mode: c::mode_t +            ) via SYS_open -> c::c_int +        } + +        ret_owned_fd(open( +            c_str(path), +            bitflags_bits!(oflags), +            bitflags_bits!(mode), +        )) +    } +} + +pub(crate) fn open(path: &CStr, oflags: OFlags, mode: Mode) -> io::Result<OwnedFd> { +    // Work around <https://sourceware.org/bugzilla/show_bug.cgi?id=17523>. +    // glibc versions before 2.25 don't handle `O_TMPFILE` correctly. +    #[cfg(all(unix, target_env = "gnu", not(target_os = "hurd")))] +    if oflags.contains(OFlags::TMPFILE) && crate::backend::if_glibc_is_less_than_2_25() { +        return open_via_syscall(path, oflags, mode); +    } + +    // On these platforms, `mode_t` is `u16` and can't be passed directly to a +    // variadic function. +    #[cfg(any( +        apple, +        freebsdlike, +        all(target_os = "android", target_pointer_width = "32") +    ))] +    let mode: c::c_uint = mode.bits().into(); + +    // Otherwise, cast to `mode_t` as that's what `open` is documented to take. +    #[cfg(not(any( +        apple, +        freebsdlike, +        all(target_os = "android", target_pointer_width = "32") +    )))] +    let mode: c::mode_t = mode.bits() as _; + +    unsafe { ret_owned_fd(c::open(c_str(path), bitflags_bits!(oflags), mode)) } +} + +/// Use a direct syscall (via libc) for `openat`. +/// +/// This is only currently necessary as a workaround for old glibc; see below. +#[cfg(all(unix, target_env = "gnu", not(target_os = "hurd")))] +fn openat_via_syscall( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    oflags: OFlags, +    mode: Mode, +) -> io::Result<OwnedFd> { +    syscall! { +        fn openat( +            base_dirfd: c::c_int, +            pathname: *const c::c_char, +            oflags: c::c_int, +            mode: c::mode_t +        ) via SYS_openat -> c::c_int +    } + +    unsafe { +        ret_owned_fd(openat( +            borrowed_fd(dirfd), +            c_str(path), +            bitflags_bits!(oflags), +            bitflags_bits!(mode), +        )) +    } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn openat( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    oflags: OFlags, +    mode: Mode, +) -> io::Result<OwnedFd> { +    // Work around <https://sourceware.org/bugzilla/show_bug.cgi?id=17523>. +    // glibc versions before 2.25 don't handle `O_TMPFILE` correctly. +    #[cfg(all(unix, target_env = "gnu", not(target_os = "hurd")))] +    if oflags.contains(OFlags::TMPFILE) && crate::backend::if_glibc_is_less_than_2_25() { +        return openat_via_syscall(dirfd, path, oflags, mode); +    } + +    // On these platforms, `mode_t` is `u16` and can't be passed directly to a +    // variadic function. +    #[cfg(any( +        apple, +        freebsdlike, +        all(target_os = "android", target_pointer_width = "32") +    ))] +    let mode: c::c_uint = mode.bits().into(); + +    // Otherwise, cast to `mode_t` as that's what `open` is documented to take. +    #[cfg(not(any( +        apple, +        freebsdlike, +        all(target_os = "android", target_pointer_width = "32") +    )))] +    let mode: c::mode_t = mode.bits() as _; + +    unsafe { +        ret_owned_fd(c::openat( +            borrowed_fd(dirfd), +            c_str(path), +            bitflags_bits!(oflags), +            mode, +        )) +    } +} + +#[cfg(not(any( +    solarish, +    target_os = "espidf", +    target_os = "haiku", +    target_os = "netbsd", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +#[inline] +pub(crate) fn statfs(filename: &CStr) -> io::Result<StatFs> { +    unsafe { +        let mut result = MaybeUninit::<StatFs>::uninit(); +        ret(c::statfs(c_str(filename), result.as_mut_ptr()))?; +        Ok(result.assume_init()) +    } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +#[inline] +pub(crate) fn statvfs(filename: &CStr) -> io::Result<StatVfs> { +    unsafe { +        let mut result = MaybeUninit::<c::statvfs>::uninit(); +        ret(c::statvfs(c_str(filename), result.as_mut_ptr()))?; +        Ok(libc_statvfs_to_statvfs(result.assume_init())) +    } +} + +#[cfg(feature = "alloc")] +#[inline] +pub(crate) fn readlink(path: &CStr, buf: &mut [u8]) -> io::Result<usize> { +    unsafe { +        ret_usize( +            c::readlink(c_str(path), buf.as_mut_ptr().cast::<c::c_char>(), buf.len()) as isize, +        ) +    } +} + +#[cfg(not(target_os = "redox"))] +#[inline] +pub(crate) fn readlinkat( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    buf: &mut [MaybeUninit<u8>], +) -> io::Result<usize> { +    unsafe { +        ret_usize(c::readlinkat( +            borrowed_fd(dirfd), +            c_str(path), +            buf.as_mut_ptr().cast::<c::c_char>(), +            buf.len(), +        ) as isize) +    } +} + +pub(crate) fn mkdir(path: &CStr, mode: Mode) -> io::Result<()> { +    unsafe { ret(c::mkdir(c_str(path), mode.bits() as c::mode_t)) } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn mkdirat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Result<()> { +    unsafe { +        ret(c::mkdirat( +            borrowed_fd(dirfd), +            c_str(path), +            mode.bits() as c::mode_t, +        )) +    } +} + +#[cfg(linux_kernel)] +pub(crate) fn getdents_uninit( +    fd: BorrowedFd<'_>, +    buf: &mut [MaybeUninit<u8>], +) -> io::Result<usize> { +    syscall! { +        fn getdents64( +            fd: c::c_int, +            dirp: *mut c::c_void, +            count: usize +        ) via SYS_getdents64 -> c::ssize_t +    } +    unsafe { +        ret_usize(getdents64( +            borrowed_fd(fd), +            buf.as_mut_ptr().cast::<c::c_void>(), +            buf.len(), +        )) +    } +} + +pub(crate) fn link(old_path: &CStr, new_path: &CStr) -> io::Result<()> { +    unsafe { ret(c::link(c_str(old_path), c_str(new_path))) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "redox")))] +pub(crate) fn linkat( +    old_dirfd: BorrowedFd<'_>, +    old_path: &CStr, +    new_dirfd: BorrowedFd<'_>, +    new_path: &CStr, +    flags: AtFlags, +) -> io::Result<()> { +    // macOS <= 10.9 lacks `linkat`. +    #[cfg(target_os = "macos")] +    unsafe { +        weak! { +            fn linkat( +                c::c_int, +                *const c::c_char, +                c::c_int, +                *const c::c_char, +                c::c_int +            ) -> c::c_int +        } +        // If we have `linkat`, use it. +        if let Some(libc_linkat) = linkat.get() { +            return ret(libc_linkat( +                borrowed_fd(old_dirfd), +                c_str(old_path), +                borrowed_fd(new_dirfd), +                c_str(new_path), +                bitflags_bits!(flags), +            )); +        } +        // Otherwise, see if we can emulate the `AT_FDCWD` case. +        if borrowed_fd(old_dirfd) != c::AT_FDCWD || borrowed_fd(new_dirfd) != c::AT_FDCWD { +            return Err(io::Errno::NOSYS); +        } +        if flags.intersects(!AtFlags::SYMLINK_FOLLOW) { +            return Err(io::Errno::INVAL); +        } +        if !flags.is_empty() { +            return Err(io::Errno::OPNOTSUPP); +        } +        ret(c::link(c_str(old_path), c_str(new_path))) +    } + +    #[cfg(not(target_os = "macos"))] +    unsafe { +        ret(c::linkat( +            borrowed_fd(old_dirfd), +            c_str(old_path), +            borrowed_fd(new_dirfd), +            c_str(new_path), +            bitflags_bits!(flags), +        )) +    } +} + +pub(crate) fn rmdir(path: &CStr) -> io::Result<()> { +    unsafe { ret(c::rmdir(c_str(path))) } +} + +pub(crate) fn unlink(path: &CStr) -> io::Result<()> { +    unsafe { ret(c::unlink(c_str(path))) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "redox")))] +pub(crate) fn unlinkat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<()> { +    // macOS <= 10.9 lacks `unlinkat`. +    #[cfg(target_os = "macos")] +    unsafe { +        weak! { +            fn unlinkat( +                c::c_int, +                *const c::c_char, +                c::c_int +            ) -> c::c_int +        } +        // If we have `unlinkat`, use it. +        if let Some(libc_unlinkat) = unlinkat.get() { +            return ret(libc_unlinkat( +                borrowed_fd(dirfd), +                c_str(path), +                bitflags_bits!(flags), +            )); +        } +        // Otherwise, see if we can emulate the `AT_FDCWD` case. +        if borrowed_fd(dirfd) != c::AT_FDCWD { +            return Err(io::Errno::NOSYS); +        } +        if flags.intersects(!AtFlags::REMOVEDIR) { +            return Err(io::Errno::INVAL); +        } +        if flags.contains(AtFlags::REMOVEDIR) { +            ret(c::rmdir(c_str(path))) +        } else { +            ret(c::unlink(c_str(path))) +        } +    } + +    #[cfg(not(target_os = "macos"))] +    unsafe { +        ret(c::unlinkat( +            borrowed_fd(dirfd), +            c_str(path), +            bitflags_bits!(flags), +        )) +    } +} + +pub(crate) fn rename(old_path: &CStr, new_path: &CStr) -> io::Result<()> { +    unsafe { ret(c::rename(c_str(old_path), c_str(new_path))) } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn renameat( +    old_dirfd: BorrowedFd<'_>, +    old_path: &CStr, +    new_dirfd: BorrowedFd<'_>, +    new_path: &CStr, +) -> io::Result<()> { +    // macOS <= 10.9 lacks `renameat`. +    #[cfg(target_os = "macos")] +    unsafe { +        weak! { +            fn renameat( +                c::c_int, +                *const c::c_char, +                c::c_int, +                *const c::c_char +            ) -> c::c_int +        } +        // If we have `renameat`, use it. +        if let Some(libc_renameat) = renameat.get() { +            return ret(libc_renameat( +                borrowed_fd(old_dirfd), +                c_str(old_path), +                borrowed_fd(new_dirfd), +                c_str(new_path), +            )); +        } +        // Otherwise, see if we can emulate the `AT_FDCWD` case. +        if borrowed_fd(old_dirfd) != c::AT_FDCWD || borrowed_fd(new_dirfd) != c::AT_FDCWD { +            return Err(io::Errno::NOSYS); +        } +        ret(c::rename(c_str(old_path), c_str(new_path))) +    } + +    #[cfg(not(target_os = "macos"))] +    unsafe { +        ret(c::renameat( +            borrowed_fd(old_dirfd), +            c_str(old_path), +            borrowed_fd(new_dirfd), +            c_str(new_path), +        )) +    } +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub(crate) fn renameat2( +    old_dirfd: BorrowedFd<'_>, +    old_path: &CStr, +    new_dirfd: BorrowedFd<'_>, +    new_path: &CStr, +    flags: RenameFlags, +) -> io::Result<()> { +    // `renameat2` wasn't supported in glibc until 2.28. +    weak_or_syscall! { +        fn renameat2( +            olddirfd: c::c_int, +            oldpath: *const c::c_char, +            newdirfd: c::c_int, +            newpath: *const c::c_char, +            flags: c::c_uint +        ) via SYS_renameat2 -> c::c_int +    } + +    unsafe { +        ret(renameat2( +            borrowed_fd(old_dirfd), +            c_str(old_path), +            borrowed_fd(new_dirfd), +            c_str(new_path), +            flags.bits(), +        )) +    } +} + +#[cfg(any( +    target_os = "android", +    all(target_os = "linux", not(target_env = "gnu")), +))] +#[inline] +pub(crate) fn renameat2( +    old_dirfd: BorrowedFd<'_>, +    old_path: &CStr, +    new_dirfd: BorrowedFd<'_>, +    new_path: &CStr, +    flags: RenameFlags, +) -> io::Result<()> { +    // At present, `libc` only has `renameat2` defined for glibc. If we have +    // no flags, we can use plain `renameat`, but otherwise we use `syscall!`. +    // to call `renameat2` ourselves. +    if flags.is_empty() { +        renameat(old_dirfd, old_path, new_dirfd, new_path) +    } else { +        syscall! { +            fn renameat2( +                olddirfd: c::c_int, +                oldpath: *const c::c_char, +                newdirfd: c::c_int, +                newpath: *const c::c_char, +                flags: c::c_uint +            ) via SYS_renameat2 -> c::c_int +        } + +        unsafe { +            ret(renameat2( +                borrowed_fd(old_dirfd), +                c_str(old_path), +                borrowed_fd(new_dirfd), +                c_str(new_path), +                flags.bits(), +            )) +        } +    } +} + +pub(crate) fn symlink(old_path: &CStr, new_path: &CStr) -> io::Result<()> { +    unsafe { ret(c::symlink(c_str(old_path), c_str(new_path))) } +} + +#[cfg(not(target_os = "redox"))] +pub(crate) fn symlinkat( +    old_path: &CStr, +    new_dirfd: BorrowedFd<'_>, +    new_path: &CStr, +) -> io::Result<()> { +    unsafe { +        ret(c::symlinkat( +            c_str(old_path), +            borrowed_fd(new_dirfd), +            c_str(new_path), +        )) +    } +} + +pub(crate) fn stat(path: &CStr) -> io::Result<Stat> { +    // See the comments in `fstat` about using `crate::fs::statx` here. +    #[cfg(all( +        linux_kernel, +        any( +            target_pointer_width = "32", +            target_arch = "mips64", +            target_arch = "mips64r6" +        ) +    ))] +    { +        match crate::fs::statx( +            crate::fs::CWD, +            path, +            AtFlags::empty(), +            StatxFlags::BASIC_STATS, +        ) { +            Ok(x) => statx_to_stat(x), +            Err(io::Errno::NOSYS) => statat_old(crate::fs::CWD, path, AtFlags::empty()), +            Err(err) => Err(err), +        } +    } + +    // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and +    // there's nothing practical we can do. +    #[cfg(not(all( +        linux_kernel, +        any( +            target_pointer_width = "32", +            target_arch = "mips64", +            target_arch = "mips64r6" +        ) +    )))] +    unsafe { +        let mut stat = MaybeUninit::<Stat>::uninit(); +        ret(c::stat(c_str(path), stat.as_mut_ptr()))?; +        Ok(stat.assume_init()) +    } +} + +pub(crate) fn lstat(path: &CStr) -> io::Result<Stat> { +    // See the comments in `fstat` about using `crate::fs::statx` here. +    #[cfg(all( +        linux_kernel, +        any( +            target_pointer_width = "32", +            target_arch = "mips64", +            target_arch = "mips64r6" +        ) +    ))] +    { +        match crate::fs::statx( +            crate::fs::CWD, +            path, +            AtFlags::SYMLINK_NOFOLLOW, +            StatxFlags::BASIC_STATS, +        ) { +            Ok(x) => statx_to_stat(x), +            Err(io::Errno::NOSYS) => statat_old(crate::fs::CWD, path, AtFlags::SYMLINK_NOFOLLOW), +            Err(err) => Err(err), +        } +    } + +    // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and +    // there's nothing practical we can do. +    #[cfg(not(all( +        linux_kernel, +        any( +            target_pointer_width = "32", +            target_arch = "mips64", +            target_arch = "mips64r6" +        ) +    )))] +    unsafe { +        let mut stat = MaybeUninit::<Stat>::uninit(); +        ret(c::lstat(c_str(path), stat.as_mut_ptr()))?; +        Ok(stat.assume_init()) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "redox")))] +pub(crate) fn statat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> { +    // See the comments in `fstat` about using `crate::fs::statx` here. +    #[cfg(all( +        linux_kernel, +        any( +            target_pointer_width = "32", +            target_arch = "mips64", +            target_arch = "mips64r6" +        ) +    ))] +    { +        match crate::fs::statx(dirfd, path, flags, StatxFlags::BASIC_STATS) { +            Ok(x) => statx_to_stat(x), +            Err(io::Errno::NOSYS) => statat_old(dirfd, path, flags), +            Err(err) => Err(err), +        } +    } + +    // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and +    // there's nothing practical we can do. +    #[cfg(not(all( +        linux_kernel, +        any( +            target_pointer_width = "32", +            target_arch = "mips64", +            target_arch = "mips64r6" +        ) +    )))] +    unsafe { +        let mut stat = MaybeUninit::<Stat>::uninit(); +        ret(c::fstatat( +            borrowed_fd(dirfd), +            c_str(path), +            stat.as_mut_ptr(), +            bitflags_bits!(flags), +        ))?; +        Ok(stat.assume_init()) +    } +} + +#[cfg(all( +    linux_kernel, +    any( +        target_pointer_width = "32", +        target_arch = "mips64", +        target_arch = "mips64r6" +    ) +))] +fn statat_old(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> { +    unsafe { +        let mut result = MaybeUninit::<c::stat64>::uninit(); +        ret(c::fstatat( +            borrowed_fd(dirfd), +            c_str(path), +            result.as_mut_ptr(), +            bitflags_bits!(flags), +        ))?; +        stat64_to_stat(result.assume_init()) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "emscripten", target_os = "vita")))] +pub(crate) fn access(path: &CStr, access: Access) -> io::Result<()> { +    unsafe { ret(c::access(c_str(path), access.bits())) } +} + +#[cfg(not(any( +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita" +)))] +pub(crate) fn accessat( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    access: Access, +    flags: AtFlags, +) -> io::Result<()> { +    // macOS <= 10.9 lacks `faccessat`. +    #[cfg(target_os = "macos")] +    unsafe { +        weak! { +            fn faccessat( +                c::c_int, +                *const c::c_char, +                c::c_int, +                c::c_int +            ) -> c::c_int +        } +        // If we have `faccessat`, use it. +        if let Some(libc_faccessat) = faccessat.get() { +            return ret(libc_faccessat( +                borrowed_fd(dirfd), +                c_str(path), +                bitflags_bits!(access), +                bitflags_bits!(flags), +            )); +        } +        // Otherwise, see if we can emulate the `AT_FDCWD` case. +        if borrowed_fd(dirfd) != c::AT_FDCWD { +            return Err(io::Errno::NOSYS); +        } +        if flags.intersects(!(AtFlags::EACCESS | AtFlags::SYMLINK_NOFOLLOW)) { +            return Err(io::Errno::INVAL); +        } +        if !flags.is_empty() { +            return Err(io::Errno::OPNOTSUPP); +        } +        ret(c::access(c_str(path), bitflags_bits!(access))) +    } + +    #[cfg(not(target_os = "macos"))] +    unsafe { +        ret(c::faccessat( +            borrowed_fd(dirfd), +            c_str(path), +            bitflags_bits!(access), +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(target_os = "emscripten")] +pub(crate) fn access(_path: &CStr, _access: Access) -> io::Result<()> { +    Ok(()) +} + +#[cfg(target_os = "emscripten")] +pub(crate) fn accessat( +    _dirfd: BorrowedFd<'_>, +    _path: &CStr, +    _access: Access, +    _flags: AtFlags, +) -> io::Result<()> { +    Ok(()) +} + +#[cfg(not(any(target_os = "espidf", target_os = "redox", target_os = "vita")))] +pub(crate) fn utimensat( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    times: &Timestamps, +    flags: AtFlags, +) -> io::Result<()> { +    // Old 32-bit version: libc has `utimensat` but it is not y2038 safe by +    // default. But there may be a `__utimensat16` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_utimensat) = __utimensat64.get() { +            let libc_times: [LibcTimespec; 2] = [ +                times.last_access.clone().into(), +                times.last_modification.clone().into(), +            ]; + +            unsafe { +                return ret(libc_utimensat( +                    borrowed_fd(dirfd), +                    c_str(path), +                    libc_times.as_ptr(), +                    bitflags_bits!(flags), +                )); +            } +        } + +        utimensat_old(dirfd, path, times, flags) +    } + +    // Main version: libc is y2038 safe and has `utimensat`. Or, the platform +    // is not y2038 safe and there's nothing practical we can do. +    #[cfg(not(any(apple, fix_y2038)))] +    unsafe { +        use crate::utils::as_ptr; + +        ret(c::utimensat( +            borrowed_fd(dirfd), +            c_str(path), +            as_ptr(times).cast(), +            bitflags_bits!(flags), +        )) +    } + +    // Apple version: `utimensat` was introduced in macOS 10.13. +    #[cfg(apple)] +    unsafe { +        use crate::utils::as_ptr; + +        // ABI details +        weak! { +            fn utimensat( +                c::c_int, +                *const c::c_char, +                *const c::timespec, +                c::c_int +            ) -> c::c_int +        } +        extern "C" { +            fn setattrlist( +                path: *const c::c_char, +                attr_list: *const Attrlist, +                attr_buf: *const c::c_void, +                attr_buf_size: c::size_t, +                options: c::c_ulong, +            ) -> c::c_int; +        } +        const FSOPT_NOFOLLOW: c::c_ulong = 0x0000_0001; + +        // If we have `utimensat`, use it. +        if let Some(have_utimensat) = utimensat.get() { +            return ret(have_utimensat( +                borrowed_fd(dirfd), +                c_str(path), +                as_ptr(times).cast(), +                bitflags_bits!(flags), +            )); +        } + +        // `setattrlistat` was introduced in 10.13 along with `utimensat`, so +        // if we don't have `utimensat`, we don't have `setattrlistat` either. +        // Emulate it using `fork`, and `fchdir` and [`setattrlist`]. +        // +        // [`setattrlist`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setattrlist.2.html +        match c::fork() { +            -1 => Err(io::Errno::IO), +            0 => { +                if c::fchdir(borrowed_fd(dirfd)) != 0 { +                    let code = match libc_errno::errno().0 { +                        c::EACCES => 2, +                        c::ENOTDIR => 3, +                        _ => 1, +                    }; +                    c::_exit(code); +                } + +                let mut flags_arg = 0; +                if flags.contains(AtFlags::SYMLINK_NOFOLLOW) { +                    flags_arg |= FSOPT_NOFOLLOW; +                } + +                let (attrbuf_size, times, attrs) = times_to_attrlist(times); + +                if setattrlist( +                    c_str(path), +                    &attrs, +                    as_ptr(×).cast(), +                    attrbuf_size, +                    flags_arg, +                ) != 0 +                { +                    // Translate expected `errno` codes into ad-hoc integer +                    // values suitable for exit statuses. +                    let code = match libc_errno::errno().0 { +                        c::EACCES => 2, +                        c::ENOTDIR => 3, +                        c::EPERM => 4, +                        c::EROFS => 5, +                        c::ELOOP => 6, +                        c::ENOENT => 7, +                        c::ENAMETOOLONG => 8, +                        c::EINVAL => 9, +                        c::ESRCH => 10, +                        c::ENOTSUP => 11, +                        _ => 1, +                    }; +                    c::_exit(code); +                } + +                c::_exit(0); +            } +            child_pid => { +                let mut wstatus = 0; +                let _ = ret_c_int(c::waitpid(child_pid, &mut wstatus, 0))?; +                if c::WIFEXITED(wstatus) { +                    // Translate our ad-hoc exit statuses back to `errno` +                    // codes. +                    match c::WEXITSTATUS(wstatus) { +                        0 => Ok(()), +                        2 => Err(io::Errno::ACCESS), +                        3 => Err(io::Errno::NOTDIR), +                        4 => Err(io::Errno::PERM), +                        5 => Err(io::Errno::ROFS), +                        6 => Err(io::Errno::LOOP), +                        7 => Err(io::Errno::NOENT), +                        8 => Err(io::Errno::NAMETOOLONG), +                        9 => Err(io::Errno::INVAL), +                        10 => Err(io::Errno::SRCH), +                        11 => Err(io::Errno::NOTSUP), +                        _ => Err(io::Errno::IO), +                    } +                } else { +                    Err(io::Errno::IO) +                } +            } +        } +    } +} + +#[cfg(fix_y2038)] +fn utimensat_old( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    times: &Timestamps, +    flags: AtFlags, +) -> io::Result<()> { +    let old_times = [ +        c::timespec { +            tv_sec: times +                .last_access +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: times +                .last_access +                .tv_nsec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +        }, +        c::timespec { +            tv_sec: times +                .last_modification +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: times +                .last_modification +                .tv_nsec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +        }, +    ]; +    unsafe { +        ret(c::utimensat( +            borrowed_fd(dirfd), +            c_str(path), +            old_times.as_ptr(), +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn chmod(path: &CStr, mode: Mode) -> io::Result<()> { +    unsafe { ret(c::chmod(c_str(path), mode.bits() as c::mode_t)) } +} + +#[cfg(not(any( +    linux_kernel, +    target_os = "espidf", +    target_os = "redox", +    target_os = "wasi" +)))] +pub(crate) fn chmodat( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    mode: Mode, +    flags: AtFlags, +) -> io::Result<()> { +    unsafe { +        ret(c::fchmodat( +            borrowed_fd(dirfd), +            c_str(path), +            mode.bits() as c::mode_t, +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(linux_kernel)] +pub(crate) fn chmodat( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    mode: Mode, +    flags: AtFlags, +) -> io::Result<()> { +    // Linux's `fchmodat` does not have a flags argument. +    // +    // Use `c::syscall` rather than `c::fchmodat` because some libc +    // implementations, such as musl, add extra logic to `fchmod` to emulate +    // support for `AT_SYMLINK_NOFOLLOW`, which uses `/proc` outside our +    // control. +    syscall! { +        fn fchmodat( +            base_dirfd: c::c_int, +            pathname: *const c::c_char, +            mode: c::mode_t +        ) via SYS_fchmodat -> c::c_int +    } +    if flags == AtFlags::SYMLINK_NOFOLLOW { +        return Err(io::Errno::OPNOTSUPP); +    } +    if !flags.is_empty() { +        return Err(io::Errno::INVAL); +    } +    unsafe { +        ret(fchmodat( +            borrowed_fd(dirfd), +            c_str(path), +            mode.bits() as c::mode_t, +        )) +    } +} + +#[cfg(apple)] +pub(crate) fn fclonefileat( +    srcfd: BorrowedFd<'_>, +    dst_dirfd: BorrowedFd<'_>, +    dst: &CStr, +    flags: CloneFlags, +) -> io::Result<()> { +    syscall! { +        fn fclonefileat( +            srcfd: BorrowedFd<'_>, +            dst_dirfd: BorrowedFd<'_>, +            dst: *const c::c_char, +            flags: c::c_int +        ) via SYS_fclonefileat -> c::c_int +    } + +    unsafe { +        ret(fclonefileat( +            srcfd, +            dst_dirfd, +            c_str(dst), +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "redox", target_os = "wasi")))] +pub(crate) fn chownat( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    owner: Option<Uid>, +    group: Option<Gid>, +    flags: AtFlags, +) -> io::Result<()> { +    unsafe { +        let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); +        ret(c::fchownat( +            borrowed_fd(dirfd), +            c_str(path), +            ow, +            gr, +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(not(any( +    apple, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) fn mknodat( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    file_type: FileType, +    mode: Mode, +    dev: Dev, +) -> io::Result<()> { +    unsafe { +        ret(c::mknodat( +            borrowed_fd(dirfd), +            c_str(path), +            (mode.bits() | file_type.as_raw_mode()) as c::mode_t, +            dev.try_into().map_err(|_e| io::Errno::PERM)?, +        )) +    } +} + +#[cfg(linux_kernel)] +pub(crate) fn copy_file_range( +    fd_in: BorrowedFd<'_>, +    off_in: Option<&mut u64>, +    fd_out: BorrowedFd<'_>, +    off_out: Option<&mut u64>, +    len: usize, +) -> io::Result<usize> { +    syscall! { +        fn copy_file_range( +            fd_in: c::c_int, +            off_in: *mut c::loff_t, +            fd_out: c::c_int, +            off_out: *mut c::loff_t, +            len: usize, +            flags: c::c_uint +        ) via SYS_copy_file_range -> c::ssize_t +    } + +    let mut off_in_val: c::loff_t = 0; +    let mut off_out_val: c::loff_t = 0; +    // Silently cast; we'll get `EINVAL` if the value is negative. +    let off_in_ptr = if let Some(off_in) = &off_in { +        off_in_val = **off_in as i64; +        &mut off_in_val +    } else { +        null_mut() +    }; +    let off_out_ptr = if let Some(off_out) = &off_out { +        off_out_val = **off_out as i64; +        &mut off_out_val +    } else { +        null_mut() +    }; +    let copied = unsafe { +        ret_usize(copy_file_range( +            borrowed_fd(fd_in), +            off_in_ptr, +            borrowed_fd(fd_out), +            off_out_ptr, +            len, +            0, // no flags are defined yet +        ))? +    }; +    if let Some(off_in) = off_in { +        *off_in = off_in_val as u64; +    } +    if let Some(off_out) = off_out { +        *off_out = off_out_val as u64; +    } +    Ok(copied) +} + +#[cfg(not(any( +    apple, +    netbsdlike, +    solarish, +    target_os = "dragonfly", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "redox", +    target_os = "vita", +)))] +pub(crate) fn fadvise(fd: BorrowedFd<'_>, offset: u64, len: u64, advice: Advice) -> io::Result<()> { +    let offset = offset as i64; +    let len = len as i64; + +    // FreeBSD returns `EINVAL` on invalid offsets; emulate the POSIX behavior. +    #[cfg(target_os = "freebsd")] +    let offset = if (offset as i64) < 0 { +        i64::MAX +    } else { +        offset +    }; + +    // FreeBSD returns `EINVAL` on overflow; emulate the POSIX behavior. +    #[cfg(target_os = "freebsd")] +    let len = if len > 0 && offset.checked_add(len).is_none() { +        i64::MAX - offset +    } else { +        len +    }; + +    let err = unsafe { c::posix_fadvise(borrowed_fd(fd), offset, len, advice as c::c_int) }; + +    // `posix_fadvise` returns its error status rather than using `errno`. +    if err == 0 { +        Ok(()) +    } else { +        Err(io::Errno(err)) +    } +} + +pub(crate) fn fcntl_getfl(fd: BorrowedFd<'_>) -> io::Result<OFlags> { +    let flags = unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFL))? }; +    Ok(OFlags::from_bits_retain(bitcast!(flags))) +} + +pub(crate) fn fcntl_setfl(fd: BorrowedFd<'_>, flags: OFlags) -> io::Result<()> { +    unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETFL, flags.bits())) } +} + +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +pub(crate) fn fcntl_get_seals(fd: BorrowedFd<'_>) -> io::Result<SealFlags> { +    let flags = unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GET_SEALS))? }; +    Ok(SealFlags::from_bits_retain(bitcast!(flags))) +} + +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +pub(crate) fn fcntl_add_seals(fd: BorrowedFd<'_>, seals: SealFlags) -> io::Result<()> { +    unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_ADD_SEALS, seals.bits())) } +} + +#[cfg(not(any( +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn fcntl_lock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> { +    use c::{flock, F_RDLCK, F_SETLK, F_SETLKW, F_UNLCK, F_WRLCK, SEEK_SET}; + +    let (cmd, l_type) = match operation { +        FlockOperation::LockShared => (F_SETLKW, F_RDLCK), +        FlockOperation::LockExclusive => (F_SETLKW, F_WRLCK), +        FlockOperation::Unlock => (F_SETLKW, F_UNLCK), +        FlockOperation::NonBlockingLockShared => (F_SETLK, F_RDLCK), +        FlockOperation::NonBlockingLockExclusive => (F_SETLK, F_WRLCK), +        FlockOperation::NonBlockingUnlock => (F_SETLK, F_UNLCK), +    }; + +    unsafe { +        let mut lock: flock = core::mem::zeroed(); +        lock.l_type = l_type as _; + +        // When `l_len` is zero, this locks all the bytes from +        // `l_whence`/`l_start` to the end of the file, even as the +        // file grows dynamically. +        lock.l_whence = SEEK_SET as _; +        lock.l_start = 0; +        lock.l_len = 0; + +        ret(c::fcntl(borrowed_fd(fd), cmd, &lock)) +    } +} + +pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> { +    let (whence, offset) = match pos { +        SeekFrom::Start(pos) => { +            let pos: u64 = pos; +            // Silently cast; we'll get `EINVAL` if the value is negative. +            (c::SEEK_SET, pos as i64) +        } +        SeekFrom::End(offset) => (c::SEEK_END, offset), +        SeekFrom::Current(offset) => (c::SEEK_CUR, offset), +        #[cfg(any(apple, freebsdlike, linux_kernel, solarish))] +        SeekFrom::Data(offset) => (c::SEEK_DATA, offset), +        #[cfg(any(apple, freebsdlike, linux_kernel, solarish))] +        SeekFrom::Hole(offset) => (c::SEEK_HOLE, offset), +    }; + +    // ESP-IDF and Vita don't support 64-bit offsets. +    #[cfg(any(target_os = "espidf", target_os = "vita"))] +    let offset: i32 = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?; + +    let offset = unsafe { ret_off_t(c::lseek(borrowed_fd(fd), offset, whence))? }; +    Ok(offset as u64) +} + +pub(crate) fn tell(fd: BorrowedFd<'_>) -> io::Result<u64> { +    let offset = unsafe { ret_off_t(c::lseek(borrowed_fd(fd), 0, c::SEEK_CUR))? }; +    Ok(offset as u64) +} + +#[cfg(not(any(linux_kernel, target_os = "wasi")))] +pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> { +    unsafe { ret(c::fchmod(borrowed_fd(fd), bitflags_bits!(mode))) } +} + +#[cfg(linux_kernel)] +pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> { +    // Use `c::syscall` rather than `c::fchmod` because some libc +    // implementations, such as musl, add extra logic to `fchmod` to emulate +    // support for `O_PATH`, which uses `/proc` outside our control and +    // interferes with our own use of `O_PATH`. +    syscall! { +        fn fchmod( +            fd: c::c_int, +            mode: c::mode_t +        ) via SYS_fchmod -> c::c_int +    } +    unsafe { ret(fchmod(borrowed_fd(fd), mode.bits() as c::mode_t)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn chown(path: &CStr, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> { +    unsafe { +        let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); +        ret(c::chown(c_str(path), ow, gr)) +    } +} + +#[cfg(linux_kernel)] +pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> { +    // Use `c::syscall` rather than `c::fchown` because some libc +    // implementations, such as musl, add extra logic to `fchown` to emulate +    // support for `O_PATH`, which uses `/proc` outside our control and +    // interferes with our own use of `O_PATH`. +    syscall! { +        fn fchown( +            fd: c::c_int, +            owner: c::uid_t, +            group: c::gid_t +        ) via SYS_fchown -> c::c_int +    } +    unsafe { +        let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); +        ret(fchown(borrowed_fd(fd), ow, gr)) +    } +} + +#[cfg(not(any(linux_kernel, target_os = "wasi")))] +pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> { +    unsafe { +        let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); +        ret(c::fchown(borrowed_fd(fd), ow, gr)) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "solaris", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> { +    unsafe { ret(c::flock(borrowed_fd(fd), operation as c::c_int)) } +} + +#[cfg(linux_kernel)] +pub(crate) fn syncfs(fd: BorrowedFd<'_>) -> io::Result<()> { +    // Some versions of Android libc lack a `syncfs` function. +    #[cfg(target_os = "android")] +    syscall! { +        fn syncfs(fd: c::c_int) via SYS_syncfs -> c::c_int +    } + +    // `syncfs` was added to glibc in 2.20. +    #[cfg(not(target_os = "android"))] +    weak_or_syscall! { +        fn syncfs(fd: c::c_int) via SYS_syncfs -> c::c_int +    } + +    unsafe { ret(syncfs(borrowed_fd(fd))) } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) fn sync() { +    unsafe { c::sync() } +} + +pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> { +    // 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use +    // `statx`. +    // +    // And, some old platforms don't support `statx`, and some fail with a +    // confusing error code, so we call `crate::fs::statx` to handle that. If +    // `statx` isn't available, fall back to the buggy system call. +    #[cfg(all( +        linux_kernel, +        any( +            target_pointer_width = "32", +            target_arch = "mips64", +            target_arch = "mips64r6" +        ) +    ))] +    { +        match crate::fs::statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) { +            Ok(x) => statx_to_stat(x), +            Err(io::Errno::NOSYS) => fstat_old(fd), +            Err(err) => Err(err), +        } +    } + +    // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and +    // there's nothing practical we can do. +    #[cfg(not(all( +        linux_kernel, +        any( +            target_pointer_width = "32", +            target_arch = "mips64", +            target_arch = "mips64r6" +        ) +    )))] +    unsafe { +        let mut stat = MaybeUninit::<Stat>::uninit(); +        ret(c::fstat(borrowed_fd(fd), stat.as_mut_ptr()))?; +        Ok(stat.assume_init()) +    } +} + +#[cfg(all( +    linux_kernel, +    any( +        target_pointer_width = "32", +        target_arch = "mips64", +        target_arch = "mips64r6" +    ) +))] +fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> { +    unsafe { +        let mut result = MaybeUninit::<c::stat64>::uninit(); +        ret(c::fstat(borrowed_fd(fd), result.as_mut_ptr()))?; +        stat64_to_stat(result.assume_init()) +    } +} + +#[cfg(not(any( +    solarish, +    target_os = "espidf", +    target_os = "haiku", +    target_os = "netbsd", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +pub(crate) fn fstatfs(fd: BorrowedFd<'_>) -> io::Result<StatFs> { +    let mut statfs = MaybeUninit::<StatFs>::uninit(); +    unsafe { +        ret(c::fstatfs(borrowed_fd(fd), statfs.as_mut_ptr()))?; +        Ok(statfs.assume_init()) +    } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +pub(crate) fn fstatvfs(fd: BorrowedFd<'_>) -> io::Result<StatVfs> { +    let mut statvfs = MaybeUninit::<c::statvfs>::uninit(); +    unsafe { +        ret(c::fstatvfs(borrowed_fd(fd), statvfs.as_mut_ptr()))?; +        Ok(libc_statvfs_to_statvfs(statvfs.assume_init())) +    } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +fn libc_statvfs_to_statvfs(from: c::statvfs) -> StatVfs { +    StatVfs { +        f_bsize: from.f_bsize as u64, +        f_frsize: from.f_frsize as u64, +        f_blocks: from.f_blocks as u64, +        f_bfree: from.f_bfree as u64, +        f_bavail: from.f_bavail as u64, +        f_files: from.f_files as u64, +        f_ffree: from.f_ffree as u64, +        f_favail: from.f_ffree as u64, +        #[cfg(not(target_os = "aix"))] +        f_fsid: from.f_fsid as u64, +        #[cfg(target_os = "aix")] +        f_fsid: ((from.f_fsid.val[0] as u64) << 32) | from.f_fsid.val[1], +        f_flag: StatVfsMountFlags::from_bits_retain(from.f_flag as u64), +        f_namemax: from.f_namemax as u64, +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "vita")))] +pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> { +    // Old 32-bit version: libc has `futimens` but it is not y2038 safe by +    // default. But there may be a `__futimens64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_futimens) = __futimens64.get() { +            let libc_times: [LibcTimespec; 2] = [ +                times.last_access.clone().into(), +                times.last_modification.clone().into(), +            ]; + +            unsafe { +                return ret(libc_futimens(borrowed_fd(fd), libc_times.as_ptr())); +            } +        } + +        futimens_old(fd, times) +    } + +    // Main version: libc is y2038 safe and has `futimens`. Or, the platform +    // is not y2038 safe and there's nothing practical we can do. +    #[cfg(not(any(apple, fix_y2038)))] +    unsafe { +        use crate::utils::as_ptr; + +        ret(c::futimens(borrowed_fd(fd), as_ptr(times).cast())) +    } + +    // Apple version: `futimens` was introduced in macOS 10.13. +    #[cfg(apple)] +    unsafe { +        use crate::utils::as_ptr; + +        // ABI details. +        weak! { +            fn futimens(c::c_int, *const c::timespec) -> c::c_int +        } +        extern "C" { +            fn fsetattrlist( +                fd: c::c_int, +                attr_list: *const Attrlist, +                attr_buf: *const c::c_void, +                attr_buf_size: c::size_t, +                options: c::c_ulong, +            ) -> c::c_int; +        } + +        // If we have `futimens`, use it. +        if let Some(have_futimens) = futimens.get() { +            return ret(have_futimens(borrowed_fd(fd), as_ptr(times).cast())); +        } + +        // Otherwise use `fsetattrlist`. +        let (attrbuf_size, times, attrs) = times_to_attrlist(times); + +        ret(fsetattrlist( +            borrowed_fd(fd), +            &attrs, +            as_ptr(×).cast(), +            attrbuf_size, +            0, +        )) +    } +} + +#[cfg(fix_y2038)] +fn futimens_old(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> { +    let old_times = [ +        c::timespec { +            tv_sec: times +                .last_access +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: times +                .last_access +                .tv_nsec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +        }, +        c::timespec { +            tv_sec: times +                .last_modification +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: times +                .last_modification +                .tv_nsec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +        }, +    ]; + +    unsafe { ret(c::futimens(borrowed_fd(fd), old_times.as_ptr())) } +} + +#[cfg(not(any( +    apple, +    netbsdlike, +    solarish, +    target_os = "aix", +    target_os = "dragonfly", +    target_os = "espidf", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +)))] +pub(crate) fn fallocate( +    fd: BorrowedFd<'_>, +    mode: FallocateFlags, +    offset: u64, +    len: u64, +) -> io::Result<()> { +    // Silently cast; we'll get `EINVAL` if the value is negative. +    let offset = offset as i64; +    let len = len as i64; + +    #[cfg(any(linux_kernel, target_os = "fuchsia"))] +    unsafe { +        ret(c::fallocate( +            borrowed_fd(fd), +            bitflags_bits!(mode), +            offset, +            len, +        )) +    } + +    #[cfg(not(any(linux_kernel, target_os = "fuchsia")))] +    { +        assert!(mode.is_empty()); +        let err = unsafe { c::posix_fallocate(borrowed_fd(fd), offset, len) }; + +        // `posix_fallocate` returns its error status rather than using +        // `errno`. +        if err == 0 { +            Ok(()) +        } else { +            Err(io::Errno(err)) +        } +    } +} + +#[cfg(apple)] +pub(crate) fn fallocate( +    fd: BorrowedFd<'_>, +    mode: FallocateFlags, +    offset: u64, +    len: u64, +) -> io::Result<()> { +    let offset: i64 = offset.try_into().map_err(|_e| io::Errno::INVAL)?; +    let len = len as i64; + +    assert!(mode.is_empty()); + +    let new_len = offset.checked_add(len).ok_or(io::Errno::FBIG)?; +    let mut store = c::fstore_t { +        fst_flags: c::F_ALLOCATECONTIG, +        fst_posmode: c::F_PEOFPOSMODE, +        fst_offset: 0, +        fst_length: new_len, +        fst_bytesalloc: 0, +    }; +    unsafe { +        if c::fcntl(borrowed_fd(fd), c::F_PREALLOCATE, &store) == -1 { +            // Unable to allocate contiguous disk space; attempt to allocate +            // non-contiguously. +            store.fst_flags = c::F_ALLOCATEALL; +            let _ = ret_c_int(c::fcntl(borrowed_fd(fd), c::F_PREALLOCATE, &store))?; +        } +        ret(c::ftruncate(borrowed_fd(fd), new_len)) +    } +} + +pub(crate) fn fsync(fd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { ret(c::fsync(borrowed_fd(fd))) } +} + +#[cfg(not(any( +    apple, +    target_os = "dragonfly", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "redox", +    target_os = "vita", +)))] +pub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { ret(c::fdatasync(borrowed_fd(fd))) } +} + +pub(crate) fn ftruncate(fd: BorrowedFd<'_>, length: u64) -> io::Result<()> { +    let length = length.try_into().map_err(|_overflow_err| io::Errno::FBIG)?; +    unsafe { ret(c::ftruncate(borrowed_fd(fd), length)) } +} + +#[cfg(any(linux_kernel, target_os = "freebsd"))] +pub(crate) fn memfd_create(name: &CStr, flags: MemfdFlags) -> io::Result<OwnedFd> { +    #[cfg(target_os = "freebsd")] +    weakcall! { +        fn memfd_create( +            name: *const c::c_char, +            flags: c::c_uint +        ) -> c::c_int +    } + +    #[cfg(linux_kernel)] +    weak_or_syscall! { +        fn memfd_create( +            name: *const c::c_char, +            flags: c::c_uint +        ) via SYS_memfd_create -> c::c_int +    } + +    unsafe { ret_owned_fd(memfd_create(c_str(name), bitflags_bits!(flags))) } +} + +#[cfg(linux_kernel)] +pub(crate) fn openat2( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    oflags: OFlags, +    mode: Mode, +    resolve: ResolveFlags, +) -> io::Result<OwnedFd> { +    use linux_raw_sys::general::open_how; + +    syscall! { +        fn openat2( +            base_dirfd: c::c_int, +            pathname: *const c::c_char, +            how: *mut open_how, +            size: usize +        ) via SYS_OPENAT2 -> c::c_int +    } + +    let oflags = oflags.bits(); +    let mut open_how = open_how { +        flags: u64::from(oflags), +        mode: u64::from(mode.bits()), +        resolve: resolve.bits(), +    }; + +    unsafe { +        ret_owned_fd(openat2( +            borrowed_fd(dirfd), +            c_str(path), +            &mut open_how, +            size_of::<open_how>(), +        )) +    } +} +#[cfg(all(linux_kernel, target_pointer_width = "32"))] +const SYS_OPENAT2: i32 = 437; +#[cfg(all(linux_kernel, target_pointer_width = "64"))] +const SYS_OPENAT2: i64 = 437; + +#[cfg(target_os = "linux")] +pub(crate) fn sendfile( +    out_fd: BorrowedFd<'_>, +    in_fd: BorrowedFd<'_>, +    offset: Option<&mut u64>, +    count: usize, +) -> io::Result<usize> { +    unsafe { +        ret_usize(c::sendfile64( +            borrowed_fd(out_fd), +            borrowed_fd(in_fd), +            offset.map_or(null_mut(), crate::utils::as_mut_ptr).cast(), +            count, +        )) +    } +} + +/// Convert from a Linux `statx` value to rustix's `Stat`. +#[cfg(all(linux_kernel, target_pointer_width = "32"))] +fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> { +    Ok(Stat { +        st_dev: crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor).into(), +        st_mode: x.stx_mode.into(), +        st_nlink: x.stx_nlink.into(), +        st_uid: x.stx_uid.into(), +        st_gid: x.stx_gid.into(), +        st_rdev: crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor).into(), +        st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_blksize: x.stx_blksize.into(), +        st_blocks: x.stx_blocks.into(), +        st_atime: x +            .stx_atime +            .tv_sec +            .try_into() +            .map_err(|_| io::Errno::OVERFLOW)?, +        st_atime_nsec: x.stx_atime.tv_nsec as _, +        st_mtime: x +            .stx_mtime +            .tv_sec +            .try_into() +            .map_err(|_| io::Errno::OVERFLOW)?, +        st_mtime_nsec: x.stx_mtime.tv_nsec as _, +        st_ctime: x +            .stx_ctime +            .tv_sec +            .try_into() +            .map_err(|_| io::Errno::OVERFLOW)?, +        st_ctime_nsec: x.stx_ctime.tv_nsec as _, +        st_ino: x.stx_ino.into(), +    }) +} + +/// Convert from a Linux `statx` value to rustix's `Stat`. +/// +/// mips64' `struct stat64` in libc has private fields, and `stx_blocks` +#[cfg(all(linux_kernel, any(target_arch = "mips64", target_arch = "mips64r6")))] +fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> { +    let mut result: Stat = unsafe { core::mem::zeroed() }; + +    result.st_dev = crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor); +    result.st_mode = x.stx_mode.into(); +    result.st_nlink = x.stx_nlink.into(); +    result.st_uid = x.stx_uid.into(); +    result.st_gid = x.stx_gid.into(); +    result.st_rdev = crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor); +    result.st_size = x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_blksize = x.stx_blksize.into(); +    result.st_blocks = x.stx_blocks.try_into().map_err(|_e| io::Errno::OVERFLOW)?; +    result.st_atime = x +        .stx_atime +        .tv_sec +        .try_into() +        .map_err(|_| io::Errno::OVERFLOW)?; +    result.st_atime_nsec = x.stx_atime.tv_nsec as _; +    result.st_mtime = x +        .stx_mtime +        .tv_sec +        .try_into() +        .map_err(|_| io::Errno::OVERFLOW)?; +    result.st_mtime_nsec = x.stx_mtime.tv_nsec as _; +    result.st_ctime = x +        .stx_ctime +        .tv_sec +        .try_into() +        .map_err(|_| io::Errno::OVERFLOW)?; +    result.st_ctime_nsec = x.stx_ctime.tv_nsec as _; +    result.st_ino = x.stx_ino.into(); + +    Ok(result) +} + +/// Convert from a Linux `stat64` value to rustix's `Stat`. +#[cfg(all(linux_kernel, target_pointer_width = "32"))] +fn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> { +    Ok(Stat { +        st_dev: s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_mode: s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_nlink: s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_uid: s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_gid: s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_rdev: s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_size: s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_blksize: s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_blocks: s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_atime: s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_atime_nsec: s64 +            .st_atime_nsec +            .try_into() +            .map_err(|_| io::Errno::OVERFLOW)?, +        st_mtime: s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_mtime_nsec: s64 +            .st_mtime_nsec +            .try_into() +            .map_err(|_| io::Errno::OVERFLOW)?, +        st_ctime: s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        st_ctime_nsec: s64 +            .st_ctime_nsec +            .try_into() +            .map_err(|_| io::Errno::OVERFLOW)?, +        st_ino: s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?, +    }) +} + +/// Convert from a Linux `stat64` value to rustix's `Stat`. +/// +/// mips64' `struct stat64` in libc has private fields, and `st_blocks` has +/// type `i64`. +#[cfg(all(linux_kernel, any(target_arch = "mips64", target_arch = "mips64r6")))] +fn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> { +    let mut result: Stat = unsafe { core::mem::zeroed() }; + +    result.st_dev = s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_mode = s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_nlink = s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_uid = s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_gid = s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_rdev = s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_size = s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_blksize = s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_blocks = s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_atime = s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_atime_nsec = s64 +        .st_atime_nsec +        .try_into() +        .map_err(|_| io::Errno::OVERFLOW)?; +    result.st_mtime = s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_mtime_nsec = s64 +        .st_mtime_nsec +        .try_into() +        .map_err(|_| io::Errno::OVERFLOW)?; +    result.st_ctime = s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?; +    result.st_ctime_nsec = s64 +        .st_ctime_nsec +        .try_into() +        .map_err(|_| io::Errno::OVERFLOW)?; +    result.st_ino = s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?; + +    Ok(result) +} + +#[cfg(linux_kernel)] +#[allow(non_upper_case_globals)] +mod sys { +    use super::{c, BorrowedFd, Statx}; + +    weak_or_syscall! { +        pub(super) fn statx( +            dirfd_: BorrowedFd<'_>, +            path: *const c::c_char, +            flags: c::c_int, +            mask: c::c_uint, +            buf: *mut Statx +        ) via SYS_statx -> c::c_int +    } +} + +#[cfg(linux_kernel)] +#[allow(non_upper_case_globals)] +pub(crate) fn statx( +    dirfd: BorrowedFd<'_>, +    path: &CStr, +    flags: AtFlags, +    mask: StatxFlags, +) -> io::Result<Statx> { +    // If a future Linux kernel adds more fields to `struct statx` and users +    // passing flags unknown to rustix in `StatxFlags`, we could end up +    // writing outside of the buffer. To prevent this possibility, we mask off +    // any flags that we don't know about. +    // +    // This includes `STATX__RESERVED`, which has a value that we know, but +    // which could take on arbitrary new meaning in the future. Linux currently +    // rejects this flag with `EINVAL`, so we do the same. +    // +    // This doesn't rely on `STATX_ALL` because [it's deprecated] and already +    // doesn't represent all the known flags. +    // +    // [it's deprecated]: https://patchwork.kernel.org/project/linux-fsdevel/patch/20200505095915.11275-7-mszeredi@redhat.com/ +    #[cfg(not(any(target_os = "android", target_env = "musl")))] +    const STATX__RESERVED: u32 = c::STATX__RESERVED as u32; +    #[cfg(any(target_os = "android", target_env = "musl"))] +    const STATX__RESERVED: u32 = linux_raw_sys::general::STATX__RESERVED; +    if (mask.bits() & STATX__RESERVED) == STATX__RESERVED { +        return Err(io::Errno::INVAL); +    } +    let mask = mask & StatxFlags::all(); + +    let mut statx_buf = MaybeUninit::<Statx>::uninit(); +    unsafe { +        ret(sys::statx( +            dirfd, +            c_str(path), +            bitflags_bits!(flags), +            mask.bits(), +            statx_buf.as_mut_ptr(), +        ))?; +        Ok(statx_buf.assume_init()) +    } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn is_statx_available() -> bool { +    unsafe { +        // Call `statx` with null pointers so that if it fails for any reason +        // other than `EFAULT`, we know it's not supported. +        matches!( +            ret(sys::statx(CWD, null(), 0, 0, null_mut())), +            Err(io::Errno::FAULT) +        ) +    } +} + +#[cfg(apple)] +pub(crate) unsafe fn fcopyfile( +    from: BorrowedFd<'_>, +    to: BorrowedFd<'_>, +    state: copyfile_state_t, +    flags: CopyfileFlags, +) -> io::Result<()> { +    extern "C" { +        fn fcopyfile( +            from: c::c_int, +            to: c::c_int, +            state: copyfile_state_t, +            flags: c::c_uint, +        ) -> c::c_int; +    } + +    nonnegative_ret(fcopyfile( +        borrowed_fd(from), +        borrowed_fd(to), +        state, +        bitflags_bits!(flags), +    )) +} + +#[cfg(apple)] +pub(crate) fn copyfile_state_alloc() -> io::Result<copyfile_state_t> { +    extern "C" { +        fn copyfile_state_alloc() -> copyfile_state_t; +    } + +    let result = unsafe { copyfile_state_alloc() }; +    if result.0.is_null() { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(result) +    } +} + +#[cfg(apple)] +pub(crate) unsafe fn copyfile_state_free(state: copyfile_state_t) -> io::Result<()> { +    extern "C" { +        fn copyfile_state_free(state: copyfile_state_t) -> c::c_int; +    } + +    nonnegative_ret(copyfile_state_free(state)) +} + +#[cfg(apple)] +const COPYFILE_STATE_COPIED: u32 = 8; + +#[cfg(apple)] +pub(crate) unsafe fn copyfile_state_get_copied(state: copyfile_state_t) -> io::Result<u64> { +    let mut copied = MaybeUninit::<u64>::uninit(); +    copyfile_state_get(state, COPYFILE_STATE_COPIED, copied.as_mut_ptr().cast())?; +    Ok(copied.assume_init()) +} + +#[cfg(apple)] +pub(crate) unsafe fn copyfile_state_get( +    state: copyfile_state_t, +    flag: u32, +    dst: *mut c::c_void, +) -> io::Result<()> { +    extern "C" { +        fn copyfile_state_get(state: copyfile_state_t, flag: u32, dst: *mut c::c_void) -> c::c_int; +    } + +    nonnegative_ret(copyfile_state_get(state, flag, dst)) +} + +#[cfg(all(apple, feature = "alloc"))] +pub(crate) fn getpath(fd: BorrowedFd<'_>) -> io::Result<CString> { +    // The use of `PATH_MAX` is generally not encouraged, but it +    // is inevitable in this case because macOS defines `fcntl` with +    // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no +    // alternatives. If a better method is invented, it should be used +    // instead. +    let mut buf = vec![0; c::PATH_MAX as usize]; + +    // From the [macOS `fcntl` manual page]: +    // `F_GETPATH` - Get the path of the file descriptor `Fildes`. The argument +    //               must be a buffer of size `MAXPATHLEN` or greater. +    // +    // [macOS `fcntl` manual page]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html +    unsafe { +        ret(c::fcntl(borrowed_fd(fd), c::F_GETPATH, buf.as_mut_ptr()))?; +    } + +    let l = buf.iter().position(|&c| c == 0).unwrap(); +    buf.truncate(l); +    buf.shrink_to_fit(); + +    Ok(CString::new(buf).unwrap()) +} + +#[cfg(apple)] +pub(crate) fn fcntl_rdadvise(fd: BorrowedFd<'_>, offset: u64, len: u64) -> io::Result<()> { +    // From the [macOS `fcntl` manual page]: +    // `F_RDADVISE` - Issue an advisory read async with no copy to user. +    // +    // The `F_RDADVISE` command operates on the following structure which holds +    // information passed from the user to the system: +    // +    // ```c +    // struct radvisory { +    //      off_t   ra_offset;  /* offset into the file */ +    //      int     ra_count;   /* size of the read     */ +    // }; +    // ``` +    // +    // [macOS `fcntl` manual page]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html +    let ra_offset = match offset.try_into() { +        Ok(len) => len, +        // If this conversion fails, the user is providing an offset outside +        // any possible file extent, so just ignore it. +        Err(_) => return Ok(()), +    }; +    let ra_count = match len.try_into() { +        Ok(len) => len, +        // If this conversion fails, the user is providing a dubiously large +        // hint which is unlikely to improve performance. +        Err(_) => return Ok(()), +    }; +    unsafe { +        let radvisory = c::radvisory { +            ra_offset, +            ra_count, +        }; +        ret(c::fcntl(borrowed_fd(fd), c::F_RDADVISE, &radvisory)) +    } +} + +#[cfg(apple)] +pub(crate) fn fcntl_fullfsync(fd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_FULLFSYNC)) } +} + +#[cfg(apple)] +pub(crate) fn fcntl_nocache(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_NOCACHE, value as c::c_int)) } +} + +#[cfg(apple)] +pub(crate) fn fcntl_global_nocache(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    unsafe { +        ret(c::fcntl( +            borrowed_fd(fd), +            c::F_GLOBAL_NOCACHE, +            value as c::c_int, +        )) +    } +} + +/// Convert `times` from a `futimens`/`utimensat` argument into `setattrlist` +/// arguments. +#[cfg(apple)] +fn times_to_attrlist(times: &Timestamps) -> (c::size_t, [c::timespec; 2], Attrlist) { +    // ABI details. +    const ATTR_CMN_MODTIME: u32 = 0x0000_0400; +    const ATTR_CMN_ACCTIME: u32 = 0x0000_1000; +    const ATTR_BIT_MAP_COUNT: u16 = 5; + +    let mut times = times.clone(); + +    // If we have any `UTIME_NOW` elements, replace them with the current time. +    if times.last_access.tv_nsec == c::UTIME_NOW || times.last_modification.tv_nsec == c::UTIME_NOW +    { +        let now = { +            let mut tv = c::timeval { +                tv_sec: 0, +                tv_usec: 0, +            }; +            unsafe { +                let r = c::gettimeofday(&mut tv, null_mut()); +                assert_eq!(r, 0); +            } +            c::timespec { +                tv_sec: tv.tv_sec, +                tv_nsec: (tv.tv_usec * 1000) as _, +            } +        }; +        if times.last_access.tv_nsec == c::UTIME_NOW { +            times.last_access = now; +        } +        if times.last_modification.tv_nsec == c::UTIME_NOW { +            times.last_modification = now; +        } +    } + +    // Pack the return values following the rules for [`getattrlist`]. +    // +    // [`getattrlist`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getattrlist.2.html +    let mut times_size = 0; +    let mut attrs = Attrlist { +        bitmapcount: ATTR_BIT_MAP_COUNT, +        reserved: 0, +        commonattr: 0, +        volattr: 0, +        dirattr: 0, +        fileattr: 0, +        forkattr: 0, +    }; +    let mut return_times = [c::timespec { +        tv_sec: 0, +        tv_nsec: 0, +    }; 2]; +    let mut times_index = 0; +    if times.last_modification.tv_nsec != c::UTIME_OMIT { +        attrs.commonattr |= ATTR_CMN_MODTIME; +        return_times[times_index] = times.last_modification; +        times_index += 1; +        times_size += size_of::<c::timespec>(); +    } +    if times.last_access.tv_nsec != c::UTIME_OMIT { +        attrs.commonattr |= ATTR_CMN_ACCTIME; +        return_times[times_index] = times.last_access; +        times_size += size_of::<c::timespec>(); +    } + +    (times_size, return_times, attrs) +} + +/// Support type for `Attrlist`. +#[cfg(apple)] +type Attrgroup = u32; + +/// Attribute list for use with `setattrlist`. +#[cfg(apple)] +#[repr(C)] +struct Attrlist { +    bitmapcount: u16, +    reserved: u16, +    commonattr: Attrgroup, +    volattr: Attrgroup, +    dirattr: Attrgroup, +    fileattr: Attrgroup, +    forkattr: Attrgroup, +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn getxattr(path: &CStr, name: &CStr, value: &mut [u8]) -> io::Result<usize> { +    let value_ptr = value.as_mut_ptr(); + +    #[cfg(not(apple))] +    unsafe { +        ret_usize(c::getxattr( +            path.as_ptr(), +            name.as_ptr(), +            value_ptr.cast::<c::c_void>(), +            value.len(), +        )) +    } + +    #[cfg(apple)] +    unsafe { +        ret_usize(c::getxattr( +            path.as_ptr(), +            name.as_ptr(), +            value_ptr.cast::<c::c_void>(), +            value.len(), +            0, +            0, +        )) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn lgetxattr(path: &CStr, name: &CStr, value: &mut [u8]) -> io::Result<usize> { +    let value_ptr = value.as_mut_ptr(); + +    #[cfg(not(apple))] +    unsafe { +        ret_usize(c::lgetxattr( +            path.as_ptr(), +            name.as_ptr(), +            value_ptr.cast::<c::c_void>(), +            value.len(), +        )) +    } + +    #[cfg(apple)] +    unsafe { +        ret_usize(c::getxattr( +            path.as_ptr(), +            name.as_ptr(), +            value_ptr.cast::<c::c_void>(), +            value.len(), +            0, +            c::XATTR_NOFOLLOW, +        )) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn fgetxattr(fd: BorrowedFd<'_>, name: &CStr, value: &mut [u8]) -> io::Result<usize> { +    let value_ptr = value.as_mut_ptr(); + +    #[cfg(not(apple))] +    unsafe { +        ret_usize(c::fgetxattr( +            borrowed_fd(fd), +            name.as_ptr(), +            value_ptr.cast::<c::c_void>(), +            value.len(), +        )) +    } + +    #[cfg(apple)] +    unsafe { +        ret_usize(c::fgetxattr( +            borrowed_fd(fd), +            name.as_ptr(), +            value_ptr.cast::<c::c_void>(), +            value.len(), +            0, +            0, +        )) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn setxattr( +    path: &CStr, +    name: &CStr, +    value: &[u8], +    flags: XattrFlags, +) -> io::Result<()> { +    #[cfg(not(apple))] +    unsafe { +        ret(c::setxattr( +            path.as_ptr(), +            name.as_ptr(), +            value.as_ptr().cast::<c::c_void>(), +            value.len(), +            flags.bits() as i32, +        )) +    } + +    #[cfg(apple)] +    unsafe { +        ret(c::setxattr( +            path.as_ptr(), +            name.as_ptr(), +            value.as_ptr().cast::<c::c_void>(), +            value.len(), +            0, +            flags.bits() as i32, +        )) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn lsetxattr( +    path: &CStr, +    name: &CStr, +    value: &[u8], +    flags: XattrFlags, +) -> io::Result<()> { +    #[cfg(not(apple))] +    unsafe { +        ret(c::lsetxattr( +            path.as_ptr(), +            name.as_ptr(), +            value.as_ptr().cast::<c::c_void>(), +            value.len(), +            flags.bits() as i32, +        )) +    } + +    #[cfg(apple)] +    unsafe { +        ret(c::setxattr( +            path.as_ptr(), +            name.as_ptr(), +            value.as_ptr().cast::<c::c_void>(), +            value.len(), +            0, +            flags.bits() as i32 | c::XATTR_NOFOLLOW, +        )) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn fsetxattr( +    fd: BorrowedFd<'_>, +    name: &CStr, +    value: &[u8], +    flags: XattrFlags, +) -> io::Result<()> { +    #[cfg(not(apple))] +    unsafe { +        ret(c::fsetxattr( +            borrowed_fd(fd), +            name.as_ptr(), +            value.as_ptr().cast::<c::c_void>(), +            value.len(), +            flags.bits() as i32, +        )) +    } + +    #[cfg(apple)] +    unsafe { +        ret(c::fsetxattr( +            borrowed_fd(fd), +            name.as_ptr(), +            value.as_ptr().cast::<c::c_void>(), +            value.len(), +            0, +            flags.bits() as i32, +        )) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn listxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usize> { +    #[cfg(not(apple))] +    unsafe { +        ret_usize(c::listxattr(path.as_ptr(), list.as_mut_ptr(), list.len())) +    } + +    #[cfg(apple)] +    unsafe { +        ret_usize(c::listxattr( +            path.as_ptr(), +            list.as_mut_ptr(), +            list.len(), +            0, +        )) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn llistxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usize> { +    #[cfg(not(apple))] +    unsafe { +        ret_usize(c::llistxattr(path.as_ptr(), list.as_mut_ptr(), list.len())) +    } + +    #[cfg(apple)] +    unsafe { +        ret_usize(c::listxattr( +            path.as_ptr(), +            list.as_mut_ptr(), +            list.len(), +            c::XATTR_NOFOLLOW, +        )) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn flistxattr(fd: BorrowedFd<'_>, list: &mut [c::c_char]) -> io::Result<usize> { +    let fd = borrowed_fd(fd); + +    #[cfg(not(apple))] +    unsafe { +        ret_usize(c::flistxattr(fd, list.as_mut_ptr(), list.len())) +    } + +    #[cfg(apple)] +    unsafe { +        ret_usize(c::flistxattr(fd, list.as_mut_ptr(), list.len(), 0)) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn removexattr(path: &CStr, name: &CStr) -> io::Result<()> { +    #[cfg(not(apple))] +    unsafe { +        ret(c::removexattr(path.as_ptr(), name.as_ptr())) +    } + +    #[cfg(apple)] +    unsafe { +        ret(c::removexattr(path.as_ptr(), name.as_ptr(), 0)) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn lremovexattr(path: &CStr, name: &CStr) -> io::Result<()> { +    #[cfg(not(apple))] +    unsafe { +        ret(c::lremovexattr(path.as_ptr(), name.as_ptr())) +    } + +    #[cfg(apple)] +    unsafe { +        ret(c::removexattr( +            path.as_ptr(), +            name.as_ptr(), +            c::XATTR_NOFOLLOW, +        )) +    } +} + +#[cfg(any(apple, linux_kernel))] +pub(crate) fn fremovexattr(fd: BorrowedFd<'_>, name: &CStr) -> io::Result<()> { +    let fd = borrowed_fd(fd); + +    #[cfg(not(apple))] +    unsafe { +        ret(c::fremovexattr(fd, name.as_ptr())) +    } + +    #[cfg(apple)] +    unsafe { +        ret(c::fremovexattr(fd, name.as_ptr(), 0)) +    } +} + +#[test] +fn test_sizes() { +    #[cfg(linux_kernel)] +    assert_eq_size!(c::loff_t, u64); + +    // Assert that `Timestamps` has the expected layout. If we're not fixing +    // y2038, libc's type should match ours. If we are, it's smaller. +    #[cfg(not(fix_y2038))] +    assert_eq_size!([c::timespec; 2], Timestamps); +    #[cfg(fix_y2038)] +    assert!(core::mem::size_of::<[c::timespec; 2]>() < core::mem::size_of::<Timestamps>()); +} diff --git a/vendor/rustix/src/backend/libc/fs/types.rs b/vendor/rustix/src/backend/libc/fs/types.rs new file mode 100644 index 0000000..19508c2 --- /dev/null +++ b/vendor/rustix/src/backend/libc/fs/types.rs @@ -0,0 +1,1164 @@ +use crate::backend::c; +use bitflags::bitflags; + +#[cfg(not(any(target_os = "espidf", target_os = "vita")))] +bitflags! { +    /// `*_OK` constants for use with [`accessat`]. +    /// +    /// [`accessat`]: fn.accessat.html +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct Access: c::c_int { +        /// `R_OK` +        const READ_OK = c::R_OK; + +        /// `W_OK` +        const WRITE_OK = c::W_OK; + +        /// `X_OK` +        const EXEC_OK = c::X_OK; + +        /// `F_OK` +        const EXISTS = c::F_OK; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "redox")))] +bitflags! { +    /// `AT_*` constants for use with [`openat`], [`statat`], and other `*at` +    /// functions. +    /// +    /// [`openat`]: crate::fs::openat +    /// [`statat`]: crate::fs::statat +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct AtFlags: u32 { +        /// `AT_SYMLINK_NOFOLLOW` +        const SYMLINK_NOFOLLOW = bitcast!(c::AT_SYMLINK_NOFOLLOW); + +        /// `AT_EACCESS` +        #[cfg(not(any(target_os = "emscripten", target_os = "android")))] +        const EACCESS = bitcast!(c::AT_EACCESS); + +        /// `AT_REMOVEDIR` +        const REMOVEDIR = bitcast!(c::AT_REMOVEDIR); + +        /// `AT_SYMLINK_FOLLOW` +        const SYMLINK_FOLLOW = bitcast!(c::AT_SYMLINK_FOLLOW); + +        /// `AT_NO_AUTOMOUNT` +        #[cfg(any(linux_like, target_os = "fuchsia"))] +        const NO_AUTOMOUNT = bitcast!(c::AT_NO_AUTOMOUNT); + +        /// `AT_EMPTY_PATH` +        #[cfg(any( +            linux_kernel, +            target_os = "freebsd", +            target_os = "fuchsia", +        ))] +        const EMPTY_PATH = bitcast!(c::AT_EMPTY_PATH); + +        /// `AT_RESOLVE_BENEATH` +        #[cfg(target_os = "freebsd")] +        const RESOLVE_BENEATH = bitcast!(c::AT_RESOLVE_BENEATH); + +        /// `AT_STATX_SYNC_AS_STAT` +        #[cfg(all(target_os = "linux", target_env = "gnu"))] +        const STATX_SYNC_AS_STAT = bitcast!(c::AT_STATX_SYNC_AS_STAT); + +        /// `AT_STATX_FORCE_SYNC` +        #[cfg(all(target_os = "linux", target_env = "gnu"))] +        const STATX_FORCE_SYNC = bitcast!(c::AT_STATX_FORCE_SYNC); + +        /// `AT_STATX_DONT_SYNC` +        #[cfg(all(target_os = "linux", target_env = "gnu"))] +        const STATX_DONT_SYNC = bitcast!(c::AT_STATX_DONT_SYNC); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +bitflags! { +    /// `S_I*` constants for use with [`openat`], [`chmodat`], and [`fchmod`]. +    /// +    /// [`openat`]: crate::fs::openat +    /// [`chmodat`]: crate::fs::chmodat +    /// [`fchmod`]: crate::fs::fchmod +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct Mode: RawMode { +        /// `S_IRWXU` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const RWXU = c::S_IRWXU as RawMode; + +        /// `S_IRUSR` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const RUSR = c::S_IRUSR as RawMode; + +        /// `S_IWUSR` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const WUSR = c::S_IWUSR as RawMode; + +        /// `S_IXUSR` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const XUSR = c::S_IXUSR as RawMode; + +        /// `S_IRWXG` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const RWXG = c::S_IRWXG as RawMode; + +        /// `S_IRGRP` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const RGRP = c::S_IRGRP as RawMode; + +        /// `S_IWGRP` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const WGRP = c::S_IWGRP as RawMode; + +        /// `S_IXGRP` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const XGRP = c::S_IXGRP as RawMode; + +        /// `S_IRWXO` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const RWXO = c::S_IRWXO as RawMode; + +        /// `S_IROTH` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const ROTH = c::S_IROTH as RawMode; + +        /// `S_IWOTH` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const WOTH = c::S_IWOTH as RawMode; + +        /// `S_IXOTH` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const XOTH = c::S_IXOTH as RawMode; + +        /// `S_ISUID` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const SUID = c::S_ISUID as RawMode; + +        /// `S_ISGID` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const SGID = c::S_ISGID as RawMode; + +        /// `S_ISVTX` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const SVTX = c::S_ISVTX as RawMode; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(not(target_os = "espidf"))] +impl Mode { +    /// Construct a `Mode` from the mode bits of the `st_mode` field of a +    /// `Mode`. +    #[inline] +    pub const fn from_raw_mode(st_mode: RawMode) -> Self { +        Self::from_bits_truncate(st_mode) +    } + +    /// Construct an `st_mode` value from a `Mode`. +    #[inline] +    pub const fn as_raw_mode(self) -> RawMode { +        self.bits() +    } +} + +#[cfg(not(target_os = "espidf"))] +impl From<RawMode> for Mode { +    /// Support conversions from raw mode values to `Mode`. +    /// +    /// ``` +    /// use rustix::fs::{Mode, RawMode}; +    /// assert_eq!(Mode::from(0o700), Mode::RWXU); +    /// ``` +    #[inline] +    fn from(st_mode: RawMode) -> Self { +        Self::from_raw_mode(st_mode) +    } +} + +#[cfg(not(target_os = "espidf"))] +impl From<Mode> for RawMode { +    /// Support conversions from `Mode` to raw mode values. +    /// +    /// ``` +    /// use rustix::fs::{Mode, RawMode}; +    /// assert_eq!(RawMode::from(Mode::RWXU), 0o700); +    /// ``` +    #[inline] +    fn from(mode: Mode) -> Self { +        mode.as_raw_mode() +    } +} + +bitflags! { +    /// `O_*` constants for use with [`openat`]. +    /// +    /// [`openat`]: crate::fs::openat +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct OFlags: u32 { +        /// `O_ACCMODE` +        const ACCMODE = bitcast!(c::O_ACCMODE); + +        /// Similar to `ACCMODE`, but just includes the read/write flags, and +        /// no other flags. +        /// +        /// On some platforms, `PATH` may be included in `ACCMODE`, when +        /// sometimes we really just want the read/write bits. Caution is +        /// indicated, as the presence of `PATH` may mean that the read/write +        /// bits don't have their usual meaning. +        const RWMODE = bitcast!(c::O_RDONLY | c::O_WRONLY | c::O_RDWR); + +        /// `O_APPEND` +        const APPEND = bitcast!(c::O_APPEND); + +        /// `O_CREAT` +        #[doc(alias = "CREAT")] +        const CREATE = bitcast!(c::O_CREAT); + +        /// `O_DIRECTORY` +        #[cfg(not(target_os = "espidf"))] +        const DIRECTORY = bitcast!(c::O_DIRECTORY); + +        /// `O_DSYNC` +        #[cfg(not(any(target_os = "dragonfly", target_os = "espidf", target_os = "l4re", target_os = "redox", target_os = "vita")))] +        const DSYNC = bitcast!(c::O_DSYNC); + +        /// `O_EXCL` +        const EXCL = bitcast!(c::O_EXCL); + +        /// `O_FSYNC` +        #[cfg(any( +            bsd, +            all(target_os = "linux", not(target_env = "musl")), +        ))] +        const FSYNC = bitcast!(c::O_FSYNC); + +        /// `O_NOFOLLOW` +        #[cfg(not(target_os = "espidf"))] +        const NOFOLLOW = bitcast!(c::O_NOFOLLOW); + +        /// `O_NONBLOCK` +        const NONBLOCK = bitcast!(c::O_NONBLOCK); + +        /// `O_RDONLY` +        const RDONLY = bitcast!(c::O_RDONLY); + +        /// `O_WRONLY` +        const WRONLY = bitcast!(c::O_WRONLY); + +        /// `O_RDWR` +        /// +        /// This is not equal to `RDONLY | WRONLY`. It's a distinct flag. +        const RDWR = bitcast!(c::O_RDWR); + +        /// `O_NOCTTY` +        #[cfg(not(any(target_os = "espidf", target_os = "l4re", target_os = "redox", target_os = "vita")))] +        const NOCTTY = bitcast!(c::O_NOCTTY); + +        /// `O_RSYNC` +        #[cfg(any( +            linux_kernel, +            netbsdlike, +            target_os = "emscripten", +            target_os = "wasi", +        ))] +        const RSYNC = bitcast!(c::O_RSYNC); + +        /// `O_SYNC` +        #[cfg(not(any(target_os = "l4re", target_os = "redox")))] +        const SYNC = bitcast!(c::O_SYNC); + +        /// `O_TRUNC` +        const TRUNC = bitcast!(c::O_TRUNC); + +        /// `O_PATH` +        #[cfg(any( +            linux_kernel, +            target_os = "emscripten", +            target_os = "freebsd", +            target_os = "fuchsia", +            target_os = "redox", +        ))] +        const PATH = bitcast!(c::O_PATH); + +        /// `O_CLOEXEC` +        const CLOEXEC = bitcast!(c::O_CLOEXEC); + +        /// `O_TMPFILE` +        #[cfg(any( +            linux_kernel, +            target_os = "emscripten", +            target_os = "fuchsia", +        ))] +        const TMPFILE = bitcast!(c::O_TMPFILE); + +        /// `O_NOATIME` +        #[cfg(any( +            linux_kernel, +            target_os = "fuchsia", +        ))] +        const NOATIME = bitcast!(c::O_NOATIME); + +        /// `O_DIRECT` +        #[cfg(any( +            linux_kernel, +            target_os = "emscripten", +            target_os = "freebsd", +            target_os = "fuchsia", +            target_os = "netbsd", +        ))] +        const DIRECT = bitcast!(c::O_DIRECT); + +        /// `O_RESOLVE_BENEATH` +        #[cfg(target_os = "freebsd")] +        const RESOLVE_BENEATH = bitcast!(c::O_RESOLVE_BENEATH); + +        /// `O_EMPTY_PATH` +        #[cfg(target_os = "freebsd")] +        const EMPTY_PATH = bitcast!(c::O_EMPTY_PATH); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(apple)] +bitflags! { +    /// `CLONE_*` constants for use with [`fclonefileat`]. +    /// +    /// [`fclonefileat`]: crate::fs::fclonefileat +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct CloneFlags: u32 { +        /// `CLONE_NOFOLLOW` +        const NOFOLLOW = 1; + +        /// `CLONE_NOOWNERCOPY` +        const NOOWNERCOPY = 2; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(apple)] +mod copyfile { +    pub(super) const ACL: u32 = 1 << 0; +    pub(super) const STAT: u32 = 1 << 1; +    pub(super) const XATTR: u32 = 1 << 2; +    pub(super) const DATA: u32 = 1 << 3; +    pub(super) const SECURITY: u32 = STAT | ACL; +    pub(super) const METADATA: u32 = SECURITY | XATTR; +    pub(super) const ALL: u32 = METADATA | DATA; +} + +#[cfg(apple)] +bitflags! { +    /// `COPYFILE_*` constants for use with [`fcopyfile`]. +    /// +    /// [`fcopyfile`]: crate::fs::fcopyfile +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct CopyfileFlags: c::c_uint { +        /// `COPYFILE_ACL` +        const ACL = copyfile::ACL; + +        /// `COPYFILE_STAT` +        const STAT = copyfile::STAT; + +        /// `COPYFILE_XATTR` +        const XATTR = copyfile::XATTR; + +        /// `COPYFILE_DATA` +        const DATA = copyfile::DATA; + +        /// `COPYFILE_SECURITY` +        const SECURITY = copyfile::SECURITY; + +        /// `COPYFILE_METADATA` +        const METADATA = copyfile::METADATA; + +        /// `COPYFILE_ALL` +        const ALL = copyfile::ALL; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(linux_kernel)] +bitflags! { +    /// `RESOLVE_*` constants for use with [`openat2`]. +    /// +    /// [`openat2`]: crate::fs::openat2 +    #[repr(transparent)] +    #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct ResolveFlags: u64 { +        /// `RESOLVE_NO_XDEV` +        const NO_XDEV = 0x01; + +        /// `RESOLVE_NO_MAGICLINKS` +        const NO_MAGICLINKS = 0x02; + +        /// `RESOLVE_NO_SYMLINKS` +        const NO_SYMLINKS = 0x04; + +        /// `RESOLVE_BENEATH` +        const BENEATH = 0x08; + +        /// `RESOLVE_IN_ROOT` +        const IN_ROOT = 0x10; + +        /// `RESOLVE_CACHED` (since Linux 5.12) +        const CACHED = 0x20; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(linux_kernel)] +bitflags! { +    /// `RENAME_*` constants for use with [`renameat_with`]. +    /// +    /// [`renameat_with`]: crate::fs::renameat_with +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct RenameFlags: c::c_uint { +        /// `RENAME_EXCHANGE` +        const EXCHANGE = bitcast!(c::RENAME_EXCHANGE); + +        /// `RENAME_NOREPLACE` +        const NOREPLACE = bitcast!(c::RENAME_NOREPLACE); + +        /// `RENAME_WHITEOUT` +        const WHITEOUT = bitcast!(c::RENAME_WHITEOUT); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// `S_IF*` constants for use with [`mknodat`] and [`Stat`]'s `st_mode` field. +/// +/// [`mknodat`]: crate::fs::mknodat +/// [`Stat`]: crate::fs::Stat +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FileType { +    /// `S_IFREG` +    RegularFile = c::S_IFREG as isize, + +    /// `S_IFDIR` +    Directory = c::S_IFDIR as isize, + +    /// `S_IFLNK` +    Symlink = c::S_IFLNK as isize, + +    /// `S_IFIFO` +    #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFIFO`. +    #[doc(alias = "IFO")] +    Fifo = c::S_IFIFO as isize, + +    /// `S_IFSOCK` +    #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFSOCK`. +    Socket = c::S_IFSOCK as isize, + +    /// `S_IFCHR` +    CharacterDevice = c::S_IFCHR as isize, + +    /// `S_IFBLK` +    BlockDevice = c::S_IFBLK as isize, + +    /// An unknown filesystem object. +    Unknown, +} + +impl FileType { +    /// Construct a `FileType` from the `S_IFMT` bits of the `st_mode` field of +    /// a `Stat`. +    #[inline] +    pub const fn from_raw_mode(st_mode: RawMode) -> Self { +        match (st_mode as c::mode_t) & c::S_IFMT { +            c::S_IFREG => Self::RegularFile, +            c::S_IFDIR => Self::Directory, +            c::S_IFLNK => Self::Symlink, +            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFIFO`. +            c::S_IFIFO => Self::Fifo, +            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFSOCK`. +            c::S_IFSOCK => Self::Socket, +            c::S_IFCHR => Self::CharacterDevice, +            c::S_IFBLK => Self::BlockDevice, +            _ => Self::Unknown, +        } +    } + +    /// Construct an `st_mode` value from a `FileType`. +    #[inline] +    pub const fn as_raw_mode(self) -> RawMode { +        match self { +            Self::RegularFile => c::S_IFREG as RawMode, +            Self::Directory => c::S_IFDIR as RawMode, +            Self::Symlink => c::S_IFLNK as RawMode, +            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFIFO`. +            Self::Fifo => c::S_IFIFO as RawMode, +            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFSOCK`. +            Self::Socket => c::S_IFSOCK as RawMode, +            Self::CharacterDevice => c::S_IFCHR as RawMode, +            Self::BlockDevice => c::S_IFBLK as RawMode, +            Self::Unknown => c::S_IFMT as RawMode, +        } +    } + +    /// Construct a `FileType` from the `d_type` field of a `c::dirent`. +    #[cfg(not(any( +        solarish, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "nto", +        target_os = "redox", +        target_os = "vita" +    )))] +    #[inline] +    pub(crate) const fn from_dirent_d_type(d_type: u8) -> Self { +        match d_type { +            c::DT_REG => Self::RegularFile, +            c::DT_DIR => Self::Directory, +            c::DT_LNK => Self::Symlink, +            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `DT_SOCK`. +            c::DT_SOCK => Self::Socket, +            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `DT_FIFO`. +            c::DT_FIFO => Self::Fifo, +            c::DT_CHR => Self::CharacterDevice, +            c::DT_BLK => Self::BlockDevice, +            // c::DT_UNKNOWN | +            _ => Self::Unknown, +        } +    } +} + +/// `POSIX_FADV_*` constants for use with [`fadvise`]. +/// +/// [`fadvise`]: crate::fs::fadvise +#[cfg(not(any( +    apple, +    netbsdlike, +    solarish, +    target_os = "dragonfly", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "redox", +    target_os = "vita", +)))] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +pub enum Advice { +    /// `POSIX_FADV_NORMAL` +    Normal = c::POSIX_FADV_NORMAL as c::c_uint, + +    /// `POSIX_FADV_SEQUENTIAL` +    Sequential = c::POSIX_FADV_SEQUENTIAL as c::c_uint, + +    /// `POSIX_FADV_RANDOM` +    Random = c::POSIX_FADV_RANDOM as c::c_uint, + +    /// `POSIX_FADV_NOREUSE` +    NoReuse = c::POSIX_FADV_NOREUSE as c::c_uint, + +    /// `POSIX_FADV_WILLNEED` +    WillNeed = c::POSIX_FADV_WILLNEED as c::c_uint, + +    /// `POSIX_FADV_DONTNEED` +    DontNeed = c::POSIX_FADV_DONTNEED as c::c_uint, +} + +#[cfg(any(linux_kernel, target_os = "freebsd"))] +bitflags! { +    /// `MFD_*` constants for use with [`memfd_create`]. +    /// +    /// [`memfd_create`]: crate::fs::memfd_create +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MemfdFlags: c::c_uint { +        /// `MFD_CLOEXEC` +        const CLOEXEC = c::MFD_CLOEXEC; + +        /// `MFD_ALLOW_SEALING` +        const ALLOW_SEALING = c::MFD_ALLOW_SEALING; + +        /// `MFD_HUGETLB` (since Linux 4.14) +        const HUGETLB = c::MFD_HUGETLB; + +        /// `MFD_HUGE_64KB` +        const HUGE_64KB = c::MFD_HUGE_64KB; +        /// `MFD_HUGE_512JB` +        const HUGE_512KB = c::MFD_HUGE_512KB; +        /// `MFD_HUGE_1MB` +        const HUGE_1MB = c::MFD_HUGE_1MB; +        /// `MFD_HUGE_2MB` +        const HUGE_2MB = c::MFD_HUGE_2MB; +        /// `MFD_HUGE_8MB` +        const HUGE_8MB = c::MFD_HUGE_8MB; +        /// `MFD_HUGE_16MB` +        const HUGE_16MB = c::MFD_HUGE_16MB; +        /// `MFD_HUGE_32MB` +        const HUGE_32MB = c::MFD_HUGE_32MB; +        /// `MFD_HUGE_256MB` +        const HUGE_256MB = c::MFD_HUGE_256MB; +        /// `MFD_HUGE_512MB` +        const HUGE_512MB = c::MFD_HUGE_512MB; +        /// `MFD_HUGE_1GB` +        const HUGE_1GB = c::MFD_HUGE_1GB; +        /// `MFD_HUGE_2GB` +        const HUGE_2GB = c::MFD_HUGE_2GB; +        /// `MFD_HUGE_16GB` +        const HUGE_16GB = c::MFD_HUGE_16GB; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] +bitflags! { +    /// `F_SEAL_*` constants for use with [`fcntl_add_seals`] and +    /// [`fcntl_get_seals`]. +    /// +    /// [`fcntl_add_seals`]: crate::fs::fcntl_add_seals +    /// [`fcntl_get_seals`]: crate::fs::fcntl_get_seals +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct SealFlags: u32 { +        /// `F_SEAL_SEAL` +        const SEAL = bitcast!(c::F_SEAL_SEAL); +        /// `F_SEAL_SHRINK` +        const SHRINK = bitcast!(c::F_SEAL_SHRINK); +        /// `F_SEAL_GROW` +        const GROW = bitcast!(c::F_SEAL_GROW); +        /// `F_SEAL_WRITE` +        const WRITE = bitcast!(c::F_SEAL_WRITE); +        /// `F_SEAL_FUTURE_WRITE` (since Linux 5.1) +        #[cfg(linux_kernel)] +        const FUTURE_WRITE = bitcast!(c::F_SEAL_FUTURE_WRITE); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +bitflags! { +    /// `STATX_*` constants for use with [`statx`]. +    /// +    /// [`statx`]: crate::fs::statx +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct StatxFlags: u32 { +        /// `STATX_TYPE` +        const TYPE = c::STATX_TYPE; + +        /// `STATX_MODE` +        const MODE = c::STATX_MODE; + +        /// `STATX_NLINK` +        const NLINK = c::STATX_NLINK; + +        /// `STATX_UID` +        const UID = c::STATX_UID; + +        /// `STATX_GID` +        const GID = c::STATX_GID; + +        /// `STATX_ATIME` +        const ATIME = c::STATX_ATIME; + +        /// `STATX_MTIME` +        const MTIME = c::STATX_MTIME; + +        /// `STATX_CTIME` +        const CTIME = c::STATX_CTIME; + +        /// `STATX_INO` +        const INO = c::STATX_INO; + +        /// `STATX_SIZE` +        const SIZE = c::STATX_SIZE; + +        /// `STATX_BLOCKS` +        const BLOCKS = c::STATX_BLOCKS; + +        /// `STATX_BASIC_STATS` +        const BASIC_STATS = c::STATX_BASIC_STATS; + +        /// `STATX_BTIME` +        const BTIME = c::STATX_BTIME; + +        /// `STATX_MNT_ID` (since Linux 5.8) +        const MNT_ID = c::STATX_MNT_ID; + +        /// `STATX_DIOALIGN` (since Linux 6.1) +        const DIOALIGN = c::STATX_DIOALIGN; + +        /// `STATX_ALL` +        const ALL = c::STATX_ALL; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(any( +    target_os = "android", +    all(target_os = "linux", not(target_env = "gnu")), +))] +bitflags! { +    /// `STATX_*` constants for use with [`statx`]. +    /// +    /// [`statx`]: crate::fs::statx +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct StatxFlags: u32 { +        /// `STATX_TYPE` +        const TYPE = 0x0001; + +        /// `STATX_MODE` +        const MODE = 0x0002; + +        /// `STATX_NLINK` +        const NLINK = 0x0004; + +        /// `STATX_UID` +        const UID = 0x0008; + +        /// `STATX_GID` +        const GID = 0x0010; + +        /// `STATX_ATIME` +        const ATIME = 0x0020; + +        /// `STATX_MTIME` +        const MTIME = 0x0040; + +        /// `STATX_CTIME` +        const CTIME = 0x0080; + +        /// `STATX_INO` +        const INO = 0x0100; + +        /// `STATX_SIZE` +        const SIZE = 0x0200; + +        /// `STATX_BLOCKS` +        const BLOCKS = 0x0400; + +        /// `STATX_BASIC_STATS` +        const BASIC_STATS = 0x07ff; + +        /// `STATX_BTIME` +        const BTIME = 0x800; + +        /// `STATX_MNT_ID` (since Linux 5.8) +        const MNT_ID = 0x1000; + +        /// `STATX_ALL` +        const ALL = 0xfff; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(not(any( +    netbsdlike, +    solarish, +    target_os = "aix", +    target_os = "espidf", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita" +)))] +bitflags! { +    /// `FALLOC_FL_*` constants for use with [`fallocate`]. +    /// +    /// [`fallocate`]: crate::fs::fallocate +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct FallocateFlags: u32 { +        /// `FALLOC_FL_KEEP_SIZE` +        #[cfg(not(any( +            bsd, +            target_os = "aix", +            target_os = "haiku", +            target_os = "hurd", +            target_os = "wasi", +        )))] +        const KEEP_SIZE = bitcast!(c::FALLOC_FL_KEEP_SIZE); +        /// `FALLOC_FL_PUNCH_HOLE` +        #[cfg(not(any( +            bsd, +            target_os = "aix", +            target_os = "haiku", +            target_os = "hurd", +            target_os = "wasi", +        )))] +        const PUNCH_HOLE = bitcast!(c::FALLOC_FL_PUNCH_HOLE); +        /// `FALLOC_FL_NO_HIDE_STALE` +        #[cfg(not(any( +            bsd, +            target_os = "aix", +            target_os = "emscripten", +            target_os = "fuchsia", +            target_os = "haiku", +            target_os = "hurd", +            target_os = "l4re", +            target_os = "linux", +            target_os = "wasi", +        )))] +        const NO_HIDE_STALE = bitcast!(c::FALLOC_FL_NO_HIDE_STALE); +        /// `FALLOC_FL_COLLAPSE_RANGE` +        #[cfg(not(any( +            bsd, +            target_os = "aix", +            target_os = "haiku", +            target_os = "hurd", +            target_os = "emscripten", +            target_os = "wasi", +        )))] +        const COLLAPSE_RANGE = bitcast!(c::FALLOC_FL_COLLAPSE_RANGE); +        /// `FALLOC_FL_ZERO_RANGE` +        #[cfg(not(any( +            bsd, +            target_os = "aix", +            target_os = "haiku", +            target_os = "hurd", +            target_os = "emscripten", +            target_os = "wasi", +        )))] +        const ZERO_RANGE = bitcast!(c::FALLOC_FL_ZERO_RANGE); +        /// `FALLOC_FL_INSERT_RANGE` +        #[cfg(not(any( +            bsd, +            target_os = "aix", +            target_os = "haiku", +            target_os = "hurd", +            target_os = "emscripten", +            target_os = "wasi", +        )))] +        const INSERT_RANGE = bitcast!(c::FALLOC_FL_INSERT_RANGE); +        /// `FALLOC_FL_UNSHARE_RANGE` +        #[cfg(not(any( +            bsd, +            target_os = "aix", +            target_os = "haiku", +            target_os = "hurd", +            target_os = "emscripten", +            target_os = "wasi", +        )))] +        const UNSHARE_RANGE = bitcast!(c::FALLOC_FL_UNSHARE_RANGE); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +bitflags! { +    /// `ST_*` constants for use with [`StatVfs`]. +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct StatVfsMountFlags: u64 { +        /// `ST_MANDLOCK` +        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))] +        const MANDLOCK = c::ST_MANDLOCK as u64; + +        /// `ST_NOATIME` +        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))] +        const NOATIME = c::ST_NOATIME as u64; + +        /// `ST_NODEV` +        #[cfg(any( +            linux_kernel, +            target_os = "aix", +            target_os = "emscripten", +            target_os = "fuchsia" +        ))] +        const NODEV = c::ST_NODEV as u64; + +        /// `ST_NODIRATIME` +        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))] +        const NODIRATIME = c::ST_NODIRATIME as u64; + +        /// `ST_NOEXEC` +        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))] +        const NOEXEC = c::ST_NOEXEC as u64; + +        /// `ST_NOSUID` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const NOSUID = c::ST_NOSUID as u64; + +        /// `ST_RDONLY` +        #[cfg(not(any(target_os = "espidf", target_os = "vita")))] +        const RDONLY = c::ST_RDONLY as u64; + +        /// `ST_RELATIME` +        #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] +        const RELATIME = c::ST_RELATIME as u64; + +        /// `ST_SYNCHRONOUS` +        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))] +        const SYNCHRONOUS = c::ST_SYNCHRONOUS as u64; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// `LOCK_*` constants for use with [`flock`] and [`fcntl_lock`]. +/// +/// [`flock`]: crate::fs::flock +/// [`fcntl_lock`]: crate::fs::fcntl_lock +#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u32)] +pub enum FlockOperation { +    /// `LOCK_SH` +    LockShared = bitcast!(c::LOCK_SH), +    /// `LOCK_EX` +    LockExclusive = bitcast!(c::LOCK_EX), +    /// `LOCK_UN` +    Unlock = bitcast!(c::LOCK_UN), +    /// `LOCK_SH | LOCK_NB` +    NonBlockingLockShared = bitcast!(c::LOCK_SH | c::LOCK_NB), +    /// `LOCK_EX | LOCK_NB` +    NonBlockingLockExclusive = bitcast!(c::LOCK_EX | c::LOCK_NB), +    /// `LOCK_UN | LOCK_NB` +    NonBlockingUnlock = bitcast!(c::LOCK_UN | c::LOCK_NB), +} + +/// `struct stat` for use with [`statat`] and [`fstat`]. +/// +/// [`statat`]: crate::fs::statat +/// [`fstat`]: crate::fs::fstat +#[cfg(not(any(linux_like, target_os = "hurd")))] +pub type Stat = c::stat; + +/// `struct stat` for use with [`statat`] and [`fstat`]. +/// +/// [`statat`]: crate::fs::statat +/// [`fstat`]: crate::fs::fstat +#[cfg(any( +    all(linux_kernel, target_pointer_width = "64"), +    target_os = "hurd", +    target_os = "emscripten", +    target_os = "l4re", +))] +pub type Stat = c::stat64; + +/// `struct stat` for use with [`statat`] and [`fstat`]. +/// +/// [`statat`]: crate::fs::statat +/// [`fstat`]: crate::fs::fstat +// On 32-bit, Linux's `struct stat64` has a 32-bit `st_mtime` and friends, so +// we use our own struct, populated from `statx` where possible, to avoid the +// y2038 bug. +#[cfg(all(linux_kernel, target_pointer_width = "32"))] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[allow(missing_docs)] +pub struct Stat { +    pub st_dev: u64, +    pub st_mode: u32, +    pub st_nlink: u32, +    pub st_uid: u32, +    pub st_gid: u32, +    pub st_rdev: u64, +    pub st_size: i64, +    pub st_blksize: u32, +    pub st_blocks: u64, +    pub st_atime: u64, +    pub st_atime_nsec: u32, +    pub st_mtime: u64, +    pub st_mtime_nsec: u32, +    pub st_ctime: u64, +    pub st_ctime_nsec: u32, +    pub st_ino: u64, +} + +/// `struct statfs` for use with [`statfs`] and [`fstatfs`]. +/// +/// [`statfs`]: crate::fs::statfs +/// [`fstatfs`]: crate::fs::fstatfs +#[cfg(not(any( +    linux_like, +    solarish, +    target_os = "espidf", +    target_os = "haiku", +    target_os = "netbsd", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +#[allow(clippy::module_name_repetitions)] +pub type StatFs = c::statfs; + +/// `struct statfs` for use with [`statfs`] and [`fstatfs`]. +/// +/// [`statfs`]: crate::fs::statfs +/// [`fstatfs`]: crate::fs::fstatfs +#[cfg(linux_like)] +pub type StatFs = c::statfs64; + +/// `struct statvfs` for use with [`statvfs`] and [`fstatvfs`]. +/// +/// [`statvfs`]: crate::fs::statvfs +/// [`fstatvfs`]: crate::fs::fstatvfs +#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] +#[allow(missing_docs)] +pub struct StatVfs { +    pub f_bsize: u64, +    pub f_frsize: u64, +    pub f_blocks: u64, +    pub f_bfree: u64, +    pub f_bavail: u64, +    pub f_files: u64, +    pub f_ffree: u64, +    pub f_favail: u64, +    pub f_fsid: u64, +    pub f_flag: StatVfsMountFlags, +    pub f_namemax: u64, +} + +/// `struct statx` for use with [`statx`]. +/// +/// [`statx`]: crate::fs::statx +#[cfg(all(target_os = "linux", target_env = "gnu"))] +// Use the glibc `struct statx`. +pub type Statx = c::statx; + +/// `struct statx_timestamp` for use with [`Statx`]. +#[cfg(all(target_os = "linux", target_env = "gnu"))] +// Use the glibc `struct statx_timestamp`. +pub type StatxTimestamp = c::statx; + +/// `struct statx` for use with [`statx`]. +/// +/// [`statx`]: crate::fs::statx +// Non-glibc ABIs don't currently declare a `struct statx`, so we declare it +// ourselves. +#[cfg(any( +    target_os = "android", +    all(target_os = "linux", not(target_env = "gnu")), +))] +#[repr(C)] +#[allow(missing_docs)] +pub struct Statx { +    pub stx_mask: u32, +    pub stx_blksize: u32, +    pub stx_attributes: u64, +    pub stx_nlink: u32, +    pub stx_uid: u32, +    pub stx_gid: u32, +    pub stx_mode: u16, +    __statx_pad1: [u16; 1], +    pub stx_ino: u64, +    pub stx_size: u64, +    pub stx_blocks: u64, +    pub stx_attributes_mask: u64, +    pub stx_atime: StatxTimestamp, +    pub stx_btime: StatxTimestamp, +    pub stx_ctime: StatxTimestamp, +    pub stx_mtime: StatxTimestamp, +    pub stx_rdev_major: u32, +    pub stx_rdev_minor: u32, +    pub stx_dev_major: u32, +    pub stx_dev_minor: u32, +    pub stx_mnt_id: u64, +    __statx_pad2: u64, +    __statx_pad3: [u64; 12], +} + +/// `struct statx_timestamp` for use with [`Statx`]. +// Non-glibc ABIs don't currently declare a `struct statx_timestamp`, so we +// declare it ourselves. +#[cfg(any( +    target_os = "android", +    all(target_os = "linux", not(target_env = "gnu")), +))] +#[repr(C)] +#[allow(missing_docs)] +pub struct StatxTimestamp { +    pub tv_sec: i64, +    pub tv_nsec: u32, +    pub __statx_timestamp_pad1: [i32; 1], +} + +/// `mode_t` +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +pub type RawMode = c::mode_t; + +/// `mode_t` +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +pub type RawMode = c::c_uint; + +/// `dev_t` +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +pub type Dev = c::dev_t; + +/// `dev_t` +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +pub type Dev = c::c_ulonglong; + +/// `__fsword_t` +#[cfg(all( +    target_os = "linux", +    not(target_env = "musl"), +    not(target_arch = "s390x"), +))] +pub type FsWord = c::__fsword_t; + +/// `__fsword_t` +#[cfg(all( +    any(target_os = "android", all(target_os = "linux", target_env = "musl")), +    target_pointer_width = "32", +))] +pub type FsWord = u32; + +/// `__fsword_t` +#[cfg(all( +    any(target_os = "android", all(target_os = "linux", target_env = "musl")), +    not(target_arch = "s390x"), +    target_pointer_width = "64", +))] +pub type FsWord = u64; + +/// `__fsword_t` +// s390x uses `u32` for `statfs` entries on glibc, even though `__fsword_t` is +// `u64`. +#[cfg(all(target_os = "linux", target_arch = "s390x", target_env = "gnu"))] +pub type FsWord = u32; + +/// `__fsword_t` +// s390x uses `u64` for `statfs` entries on musl. +#[cfg(all(target_os = "linux", target_arch = "s390x", target_env = "musl"))] +pub type FsWord = u64; + +/// `copyfile_state_t`—State for use with [`fcopyfile`]. +/// +/// [`fcopyfile`]: crate::fs::fcopyfile +#[cfg(apple)] +#[allow(non_camel_case_types)] +#[repr(transparent)] +#[derive(Copy, Clone)] +pub struct copyfile_state_t(pub(crate) *mut c::c_void); 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 0000000..805ea67 --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/errno.rs @@ -0,0 +1,1052 @@ +//! The `rustix` `Errno` type. +//! +//! This type holds an OS error code, which conceptually corresponds to an +//! `errno` value. + +use crate::backend::c; +use libc_errno::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] +///  - [Winsock] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +///  - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/errno.html +/// [Linux]: https://man7.org/linux/man-pages/man3/errno.3.html +/// [Winsock]: https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2 +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?errno +/// [NetBSD]: https://man.netbsd.org/errno.2 +/// [OpenBSD]: https://man.openbsd.org/errno.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=errno§ion=2 +/// [illumos]: https://illumos.org/man/3C/errno +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Error-Codes.html +/// [`std::io::Error`]: Result +#[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( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const ADV: Self = Self(c::EADV); +    /// `EAFNOSUPPORT` +    #[cfg(not(target_os = "l4re"))] +    pub const AFNOSUPPORT: Self = Self(c::EAFNOSUPPORT); +    /// `EAGAIN` +    pub const AGAIN: Self = Self(c::EAGAIN); +    /// `EALREADY` +    #[cfg(not(target_os = "l4re"))] +    pub const ALREADY: Self = Self(c::EALREADY); +    /// `EAUTH` +    #[cfg(bsd)] +    pub const AUTH: Self = Self(c::EAUTH); +    /// `EBADE` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const BADE: Self = Self(c::EBADE); +    /// `EBADF` +    pub const BADF: Self = Self(c::EBADF); +    /// `EBADFD` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const BADFD: Self = Self(c::EBADFD); +    /// `EBADMSG` +    #[cfg(not(any(windows, target_os = "l4re")))] +    pub const BADMSG: Self = Self(c::EBADMSG); +    /// `EBADR` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const BADR: Self = Self(c::EBADR); +    /// `EBADRPC` +    #[cfg(bsd)] +    pub const BADRPC: Self = Self(c::EBADRPC); +    /// `EBADRQC` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const BADRQC: Self = Self(c::EBADRQC); +    /// `EBADSLT` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const BADSLT: Self = Self(c::EBADSLT); +    /// `EBFONT` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const BFONT: Self = Self(c::EBFONT); +    /// `EBUSY` +    #[cfg(not(windows))] +    pub const BUSY: Self = Self(c::EBUSY); +    /// `ECANCELED` +    #[cfg(not(target_os = "l4re"))] +    pub const CANCELED: Self = Self(c::ECANCELED); +    /// `ECAPMODE` +    #[cfg(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( +        bsd, +        windows, +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const CHRNG: Self = Self(c::ECHRNG); +    /// `ECOMM` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        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( +        bsd, +        windows, +        target_os = "aix", +        target_os = "android", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const DEADLOCK: Self = Self(c::EDEADLOCK); +    /// `EDESTADDRREQ` +    #[cfg(not(target_os = "l4re"))] +    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(freebsdlike)] +    pub const DOOFUS: Self = Self(c::EDOOFUS); +    /// `EDOTDOT` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        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(bsd, target_env = "newlib"))] +    pub const FTYPE: Self = Self(c::EFTYPE); +    /// `EHOSTDOWN` +    #[cfg(not(any(target_os = "l4re", target_os = "wasi")))] +    pub const HOSTDOWN: Self = Self(c::EHOSTDOWN); +    /// `EHOSTUNREACH` +    pub const HOSTUNREACH: Self = Self(c::EHOSTUNREACH); +    /// `EHWPOISON` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "android", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "redox", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const HWPOISON: Self = Self(c::EHWPOISON); +    /// `EIDRM` +    #[cfg(not(any(windows, target_os = "l4re")))] +    pub const IDRM: Self = Self(c::EIDRM); +    /// `EILSEQ` +    #[cfg(not(any(windows, target_os = "l4re")))] +    pub const ILSEQ: Self = Self(c::EILSEQ); +    /// `EINPROGRESS` +    #[cfg(not(target_os = "l4re"))] +    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` +    #[cfg(not(target_os = "l4re"))] +    pub const ISCONN: Self = Self(c::EISCONN); +    /// `EISDIR` +    #[cfg(not(windows))] +    pub const ISDIR: Self = Self(c::EISDIR); +    /// `EISNAM` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const ISNAM: Self = Self(c::EISNAM); +    /// `EKEYEXPIRED` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const KEYEXPIRED: Self = Self(c::EKEYEXPIRED); +    /// `EKEYREJECTED` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const KEYREJECTED: Self = Self(c::EKEYREJECTED); +    /// `EKEYREVOKED` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const KEYREVOKED: Self = Self(c::EKEYREVOKED); +    /// `EL2HLT` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const L2HLT: Self = Self(c::EL2HLT); +    /// `EL2NSYNC` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const L2NSYNC: Self = Self(c::EL2NSYNC); +    /// `EL3HLT` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const L3HLT: Self = Self(c::EL3HLT); +    /// `EL3RST` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const L3RST: Self = Self(c::EL3RST); +    /// `ELIBACC` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const LIBACC: Self = Self(c::ELIBACC); +    /// `ELIBBAD` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const LIBBAD: Self = Self(c::ELIBBAD); +    /// `ELIBEXEC` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const LIBEXEC: Self = Self(c::ELIBEXEC); +    /// `ELIBMAX` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const LIBMAX: Self = Self(c::ELIBMAX); +    /// `ELIBSCN` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const LIBSCN: Self = Self(c::ELIBSCN); +    /// `ELNRNG` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const LNRNG: Self = Self(c::ELNRNG); +    /// `ELOOP` +    pub const LOOP: Self = Self(c::ELOOP); +    /// `EMEDIUMTYPE` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        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` +    #[cfg(not(target_os = "l4re"))] +    pub const MSGSIZE: Self = Self(c::EMSGSIZE); +    /// `EMULTIHOP` +    #[cfg(not(any(windows, target_os = "l4re", target_os = "openbsd")))] +    pub const MULTIHOP: Self = Self(c::EMULTIHOP); +    /// `ENAMETOOLONG` +    pub const NAMETOOLONG: Self = Self(c::ENAMETOOLONG); +    /// `ENAVAIL` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const NAVAIL: Self = Self(c::ENAVAIL); +    /// `ENEEDAUTH` +    #[cfg(bsd)] +    pub const NEEDAUTH: Self = Self(c::ENEEDAUTH); +    /// `ENETDOWN` +    pub const NETDOWN: Self = Self(c::ENETDOWN); +    /// `ENETRESET` +    #[cfg(not(target_os = "l4re"))] +    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( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const NOANO: Self = Self(c::ENOANO); +    /// `ENOATTR` +    #[cfg(any(bsd, target_os = "haiku"))] +    pub const NOATTR: Self = Self(c::ENOATTR); +    /// `ENOBUFS` +    #[cfg(not(target_os = "l4re"))] +    pub const NOBUFS: Self = Self(c::ENOBUFS); +    /// `ENOCSI` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const NOCSI: Self = Self(c::ENOCSI); +    /// `ENODATA` +    #[cfg(not(any( +        freebsdlike, +        windows, +        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( +        solarish, +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const NOKEY: Self = Self(c::ENOKEY); +    /// `ENOLCK` +    #[cfg(not(any(windows, target_os = "l4re")))] +    pub const NOLCK: Self = Self(c::ENOLCK); +    /// `ENOLINK` +    #[cfg(not(any(windows, target_os = "l4re", target_os = "openbsd")))] +    pub const NOLINK: Self = Self(c::ENOLINK); +    /// `ENOMEDIUM` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        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(any(windows, target_os = "l4re")))] +    pub const NOMSG: Self = Self(c::ENOMSG); +    /// `ENONET` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const NONET: Self = Self(c::ENONET); +    /// `ENOPKG` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const NOPKG: Self = Self(c::ENOPKG); +    /// `ENOPROTOOPT` +    #[cfg(not(target_os = "l4re"))] +    pub const NOPROTOOPT: Self = Self(c::ENOPROTOOPT); +    /// `ENOSPC` +    #[cfg(not(windows))] +    pub const NOSPC: Self = Self(c::ENOSPC); +    /// `ENOSR` +    #[cfg(not(any( +        freebsdlike, +        windows, +        target_os = "haiku", +        target_os = "l4re", +        target_os = "openbsd", +        target_os = "wasi", +    )))] +    pub const NOSR: Self = Self(c::ENOSR); +    /// `ENOSTR` +    #[cfg(not(any( +        freebsdlike, +        windows, +        target_os = "haiku", +        target_os = "l4re", +        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 = "espidf", +        target_os = "haiku", +        target_os = "vita", +        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( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const NOTNAM: Self = Self(c::ENOTNAM); +    /// `ENOTRECOVERABLE` +    #[cfg(not(any( +        freebsdlike, +        netbsdlike, +        windows, +        target_os = "haiku", +        target_os = "l4re" +    )))] +    pub const NOTRECOVERABLE: Self = Self(c::ENOTRECOVERABLE); +    /// `ENOTSOCK` +    #[cfg(not(target_os = "l4re"))] +    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( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        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(any(windows, target_os = "l4re")))] +    pub const OVERFLOW: Self = Self(c::EOVERFLOW); +    /// `EOWNERDEAD` +    #[cfg(not(any( +        freebsdlike, +        netbsdlike, +        windows, +        target_os = "haiku", +        target_os = "l4re" +    )))] +    pub const OWNERDEAD: Self = Self(c::EOWNERDEAD); +    /// `EPERM` +    #[cfg(not(windows))] +    pub const PERM: Self = Self(c::EPERM); +    /// `EPFNOSUPPORT` +    #[cfg(not(any(target_os = "l4re", target_os = "wasi")))] +    pub const PFNOSUPPORT: Self = Self(c::EPFNOSUPPORT); +    /// `EPIPE` +    #[cfg(not(windows))] +    pub const PIPE: Self = Self(c::EPIPE); +    /// `EPROCLIM` +    #[cfg(bsd)] +    pub const PROCLIM: Self = Self(c::EPROCLIM); +    /// `EPROCUNAVAIL` +    #[cfg(bsd)] +    pub const PROCUNAVAIL: Self = Self(c::EPROCUNAVAIL); +    /// `EPROGMISMATCH` +    #[cfg(bsd)] +    pub const PROGMISMATCH: Self = Self(c::EPROGMISMATCH); +    /// `EPROGUNAVAIL` +    #[cfg(bsd)] +    pub const PROGUNAVAIL: Self = Self(c::EPROGUNAVAIL); +    /// `EPROTO` +    #[cfg(not(any(windows, target_os = "l4re")))] +    pub const PROTO: Self = Self(c::EPROTO); +    /// `EPROTONOSUPPORT` +    #[cfg(not(target_os = "l4re"))] +    pub const PROTONOSUPPORT: Self = Self(c::EPROTONOSUPPORT); +    /// `EPROTOTYPE` +    #[cfg(not(target_os = "l4re"))] +    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( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const REMCHG: Self = Self(c::EREMCHG); +    /// `EREMOTE` +    #[cfg(not(any( +        target_os = "espidf", +        target_os = "haiku", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const REMOTE: Self = Self(c::EREMOTE); +    /// `EREMOTEIO` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const REMOTEIO: Self = Self(c::EREMOTEIO); +    /// `ERESTART` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const RESTART: Self = Self(c::ERESTART); +    /// `ERFKILL` +    #[cfg(not(any( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "android", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "redox", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const RFKILL: Self = Self(c::ERFKILL); +    /// `EROFS` +    #[cfg(not(windows))] +    pub const ROFS: Self = Self(c::EROFS); +    /// `ERPCMISMATCH` +    #[cfg(bsd)] +    pub const RPCMISMATCH: Self = Self(c::ERPCMISMATCH); +    /// `ESHUTDOWN` +    #[cfg(not(any( +        target_os = "espidf", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const SHUTDOWN: Self = Self(c::ESHUTDOWN); +    /// `ESOCKTNOSUPPORT` +    #[cfg(not(any( +        target_os = "espidf", +        target_os = "haiku", +        target_os = "l4re", +        target_os = "vita", +        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( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const SRMNT: Self = Self(c::ESRMNT); +    /// `ESTALE` +    pub const STALE: Self = Self(c::ESTALE); +    /// `ESTRPIPE` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const STRPIPE: Self = Self(c::ESTRPIPE); +    /// `ETIME` +    #[cfg(not(any( +        freebsdlike, +        windows, +        target_os = "l4re", +        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 = "l4re", 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( +        bsd, +        solarish, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "nto", +        target_os = "vita", +        target_os = "wasi", +    )))] +    pub const UCLEAN: Self = Self(c::EUCLEAN); +    /// `EUNATCH` +    #[cfg(not(any( +        bsd, +        windows, +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        target_os = "wasi" +    )))] +    pub const UNATCH: Self = Self(c::EUNATCH); +    /// `EUSERS` +    #[cfg(not(any( +        target_os = "espidf", +        target_os = "haiku", +        target_os = "l4re", +        target_os = "vita", +        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( +        bsd, +        windows, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "l4re", +        target_os = "vita", +        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<Self> { +        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/mod.rs b/vendor/rustix/src/backend/libc/io/mod.rs new file mode 100644 index 0000000..4873885 --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/mod.rs @@ -0,0 +1,6 @@ +pub(crate) mod errno; +#[cfg(not(windows))] +pub(crate) mod types; + +#[cfg_attr(windows, path = "windows_syscalls.rs")] +pub(crate) mod syscalls; 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 0000000..e28e6be --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/syscalls.rs @@ -0,0 +1,340 @@ +//! libc syscalls supporting `rustix::io`. + +use crate::backend::c; +#[cfg(not(target_os = "wasi"))] +use crate::backend::conv::ret_discarded_fd; +use crate::backend::conv::{borrowed_fd, ret, ret_c_int, ret_owned_fd, ret_usize}; +use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; +#[cfg(not(any( +    target_os = "aix", +    target_os = "espidf", +    target_os = "nto", +    target_os = "vita", +    target_os = "wasi" +)))] +use crate::io::DupFlags; +#[cfg(linux_kernel)] +use crate::io::ReadWriteFlags; +use crate::io::{self, FdFlags}; +use crate::ioctl::{IoctlOutput, RawOpcode}; +use core::cmp::min; +#[cfg(all(feature = "fs", feature = "net"))] +use libc_errno::errno; +#[cfg(not(target_os = "espidf"))] +use { +    crate::backend::MAX_IOV, +    crate::io::{IoSlice, IoSliceMut}, +}; + +pub(crate) unsafe fn read(fd: BorrowedFd<'_>, buf: *mut u8, len: usize) -> io::Result<usize> { +    ret_usize(c::read(borrowed_fd(fd), buf.cast(), min(len, READ_LIMIT))) +} + +pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> { +    unsafe { +        ret_usize(c::write( +            borrowed_fd(fd), +            buf.as_ptr().cast(), +            min(buf.len(), READ_LIMIT), +        )) +    } +} + +pub(crate) unsafe fn pread( +    fd: BorrowedFd<'_>, +    buf: *mut u8, +    len: usize, +    offset: u64, +) -> io::Result<usize> { +    let len = min(len, READ_LIMIT); + +    // Silently cast; we'll get `EINVAL` if the value is negative. +    let offset = offset as i64; + +    // ESP-IDF and Vita don't support 64-bit offsets. +    #[cfg(any(target_os = "espidf", target_os = "vita"))] +    let offset: i32 = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?; + +    ret_usize(c::pread(borrowed_fd(fd), buf.cast(), len, offset)) +} + +pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result<usize> { +    let len = min(buf.len(), READ_LIMIT); + +    // Silently cast; we'll get `EINVAL` if the value is negative. +    let offset = offset as i64; + +    // ESP-IDF and Vita don't support 64-bit offsets. +    #[cfg(any(target_os = "espidf", target_os = "vita"))] +    let offset: i32 = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?; + +    unsafe { ret_usize(c::pwrite(borrowed_fd(fd), buf.as_ptr().cast(), len, offset)) } +} + +#[cfg(not(target_os = "espidf"))] +pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { +    unsafe { +        ret_usize(c::readv( +            borrowed_fd(fd), +            bufs.as_ptr().cast::<c::iovec>(), +            min(bufs.len(), MAX_IOV) as c::c_int, +        )) +    } +} + +#[cfg(not(target_os = "espidf"))] +pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>]) -> io::Result<usize> { +    unsafe { +        ret_usize(c::writev( +            borrowed_fd(fd), +            bufs.as_ptr().cast::<c::iovec>(), +            min(bufs.len(), MAX_IOV) as c::c_int, +        )) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "haiku", +    target_os = "nto", +    target_os = "redox", +    target_os = "solaris", +    target_os = "vita" +)))] +pub(crate) fn preadv( +    fd: BorrowedFd<'_>, +    bufs: &mut [IoSliceMut<'_>], +    offset: u64, +) -> io::Result<usize> { +    // Silently cast; we'll get `EINVAL` if the value is negative. +    let offset = offset as i64; +    unsafe { +        ret_usize(c::preadv( +            borrowed_fd(fd), +            bufs.as_ptr().cast::<c::iovec>(), +            min(bufs.len(), MAX_IOV) as c::c_int, +            offset, +        )) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "haiku", +    target_os = "nto", +    target_os = "redox", +    target_os = "solaris", +    target_os = "vita" +)))] +pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { +    // Silently cast; we'll get `EINVAL` if the value is negative. +    let offset = offset as i64; +    unsafe { +        ret_usize(c::pwritev( +            borrowed_fd(fd), +            bufs.as_ptr().cast::<c::iovec>(), +            min(bufs.len(), MAX_IOV) as c::c_int, +            offset, +        )) +    } +} + +#[cfg(linux_kernel)] +pub(crate) fn preadv2( +    fd: BorrowedFd<'_>, +    bufs: &mut [IoSliceMut<'_>], +    offset: u64, +    flags: ReadWriteFlags, +) -> io::Result<usize> { +    // Silently cast; we'll get `EINVAL` if the value is negative. +    let offset = offset as i64; +    unsafe { +        ret_usize(c::preadv2( +            borrowed_fd(fd), +            bufs.as_ptr().cast::<c::iovec>(), +            min(bufs.len(), MAX_IOV) as c::c_int, +            offset, +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(linux_kernel)] +pub(crate) fn pwritev2( +    fd: BorrowedFd<'_>, +    bufs: &[IoSlice<'_>], +    offset: u64, +    flags: ReadWriteFlags, +) -> io::Result<usize> { +    // Silently cast; we'll get `EINVAL` if the value is negative. +    let offset = offset as i64; +    unsafe { +        ret_usize(c::pwritev2( +            borrowed_fd(fd), +            bufs.as_ptr().cast::<c::iovec>(), +            min(bufs.len(), MAX_IOV) as c::c_int, +            offset, +            bitflags_bits!(flags), +        )) +    } +} + +// These functions are derived from Rust's library/std/src/sys/unix/fd.rs at +// revision 326ef470a8b379a180d6dc4bbef08990698a737a. + +// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, with the +// manual 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; + +pub(crate) unsafe fn close(raw_fd: RawFd) { +    let _ = c::close(raw_fd as c::c_int); +} + +#[inline] +pub(crate) unsafe fn ioctl( +    fd: BorrowedFd<'_>, +    request: RawOpcode, +    arg: *mut c::c_void, +) -> io::Result<IoctlOutput> { +    ret_c_int(c::ioctl(borrowed_fd(fd), request, arg)) +} + +#[inline] +pub(crate) unsafe fn ioctl_readonly( +    fd: BorrowedFd<'_>, +    request: RawOpcode, +    arg: *mut c::c_void, +) -> io::Result<IoctlOutput> { +    ioctl(fd, request, arg) +} + +#[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)> { +    use core::mem::MaybeUninit; + +    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::<c::c_void>(), +                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<FdFlags> { +    let flags = unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFD))? }; +    Ok(FdFlags::from_bits_retain(bitcast!(flags))) +} + +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(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { +    unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD_CLOEXEC, min)) } +} + +#[cfg(target_os = "espidf")] +pub(crate) fn fcntl_dupfd(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { +    unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD, min)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { +    unsafe { ret_owned_fd(c::dup(borrowed_fd(fd))) } +} + +#[allow(clippy::needless_pass_by_ref_mut)] +#[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()))) } +} + +#[allow(clippy::needless_pass_by_ref_mut)] +#[cfg(not(any( +    apple, +    target_os = "aix", +    target_os = "android", +    target_os = "dragonfly", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +    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()), +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(any( +    apple, +    target_os = "android", +    target_os = "dragonfly", +    target_os = "haiku", +    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) +} 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 0000000..510206f --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/types.rs @@ -0,0 +1,65 @@ +use crate::backend::c; +use bitflags::bitflags; + +bitflags! { +    /// `FD_*` constants for use with [`fcntl_getfd`] and [`fcntl_setfd`]. +    /// +    /// [`fcntl_getfd`]: crate::io::fcntl_getfd +    /// [`fcntl_setfd`]: crate::io::fcntl_setfd +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct FdFlags: u32 { +        /// `FD_CLOEXEC` +        const CLOEXEC = bitcast!(c::FD_CLOEXEC); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(linux_kernel)] +bitflags! { +    /// `RWF_*` constants for use with [`preadv2`] and [`pwritev2`]. +    /// +    /// [`preadv2`]: crate::io::preadv2 +    /// [`pwritev2`]: crate::io::pwritev +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct ReadWriteFlags: u32 { +        /// `RWF_DSYNC` (since Linux 4.7) +        const DSYNC = linux_raw_sys::general::RWF_DSYNC; +        /// `RWF_HIPRI` (since Linux 4.6) +        const HIPRI = linux_raw_sys::general::RWF_HIPRI; +        /// `RWF_SYNC` (since Linux 4.7) +        const SYNC = linux_raw_sys::general::RWF_SYNC; +        /// `RWF_NOWAIT` (since Linux 4.14) +        const NOWAIT = linux_raw_sys::general::RWF_NOWAIT; +        /// `RWF_APPEND` (since Linux 4.16) +        const APPEND = linux_raw_sys::general::RWF_APPEND; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(not(target_os = "wasi"))] +bitflags! { +    /// `O_*` constants for use with [`dup2`]. +    /// +    /// [`dup2`]: crate::io::dup2 +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct DupFlags: u32 { +        /// `O_CLOEXEC` +        #[cfg(not(any( +            apple, +            target_os = "aix", +            target_os = "android", +            target_os = "redox", +        )))] // Android 5.0 has dup3, but libc doesn't have bindings +        const CLOEXEC = bitcast!(c::O_CLOEXEC); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} 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 0000000..049221d --- /dev/null +++ b/vendor/rustix/src/backend/libc/io/windows_syscalls.rs @@ -0,0 +1,30 @@ +//! Windows system calls in the `io` module. + +use crate::backend::c; +use crate::backend::conv::{borrowed_fd, ret_c_int}; +use crate::backend::fd::LibcFd; +use crate::fd::{BorrowedFd, RawFd}; +use crate::io; +use crate::ioctl::{IoctlOutput, RawOpcode}; + +pub(crate) unsafe fn close(raw_fd: RawFd) { +    let _ = c::close(raw_fd as LibcFd); +} + +#[inline] +pub(crate) unsafe fn ioctl( +    fd: BorrowedFd<'_>, +    request: RawOpcode, +    arg: *mut c::c_void, +) -> io::Result<IoctlOutput> { +    ret_c_int(c::ioctl(borrowed_fd(fd), request, arg.cast())) +} + +#[inline] +pub(crate) unsafe fn ioctl_readonly( +    fd: BorrowedFd<'_>, +    request: RawOpcode, +    arg: *mut c::c_void, +) -> io::Result<IoctlOutput> { +    ioctl(fd, request, arg) +} diff --git a/vendor/rustix/src/backend/libc/io_uring/mod.rs b/vendor/rustix/src/backend/libc/io_uring/mod.rs new file mode 100644 index 0000000..ef944f0 --- /dev/null +++ b/vendor/rustix/src/backend/libc/io_uring/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix/src/backend/libc/io_uring/syscalls.rs b/vendor/rustix/src/backend/libc/io_uring/syscalls.rs new file mode 100644 index 0000000..8e81824 --- /dev/null +++ b/vendor/rustix/src/backend/libc/io_uring/syscalls.rs @@ -0,0 +1,70 @@ +//! libc syscalls supporting `rustix::io_uring`. + +use crate::backend::c; +use crate::backend::conv::{borrowed_fd, ret_owned_fd, ret_u32}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use crate::io_uring::{io_uring_params, IoringEnterFlags, IoringRegisterOp}; + +#[inline] +pub(crate) fn io_uring_setup(entries: u32, params: &mut io_uring_params) -> io::Result<OwnedFd> { +    syscall! { +        fn io_uring_setup( +            entries: u32, +            params: *mut io_uring_params +        ) via SYS_io_uring_setup -> c::c_int +    } +    unsafe { ret_owned_fd(io_uring_setup(entries, params)) } +} + +#[inline] +pub(crate) unsafe fn io_uring_register( +    fd: BorrowedFd<'_>, +    opcode: IoringRegisterOp, +    arg: *const c::c_void, +    nr_args: u32, +) -> io::Result<u32> { +    syscall! { +        fn io_uring_register( +            fd: c::c_uint, +            opcode: c::c_uint, +            arg: *const c::c_void, +            nr_args: c::c_uint +        ) via SYS_io_uring_register -> c::c_int +    } +    ret_u32(io_uring_register( +        borrowed_fd(fd) as _, +        opcode as u32, +        arg, +        nr_args, +    )) +} + +#[inline] +pub(crate) unsafe fn io_uring_enter( +    fd: BorrowedFd<'_>, +    to_submit: u32, +    min_complete: u32, +    flags: IoringEnterFlags, +    arg: *const c::c_void, +    size: usize, +) -> io::Result<u32> { +    syscall! { +        fn io_uring_enter2( +            fd: c::c_uint, +            to_submit: c::c_uint, +            min_complete: c::c_uint, +            flags: c::c_uint, +            arg: *const c::c_void, +            size: usize +        ) via SYS_io_uring_enter -> c::c_int +    } +    ret_u32(io_uring_enter2( +        borrowed_fd(fd) as _, +        to_submit, +        min_complete, +        bitflags_bits!(flags), +        arg, +        size, +    )) +} diff --git a/vendor/rustix/src/backend/libc/mm/mod.rs b/vendor/rustix/src/backend/libc/mm/mod.rs new file mode 100644 index 0000000..1e0181a --- /dev/null +++ b/vendor/rustix/src/backend/libc/mm/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix/src/backend/libc/mm/syscalls.rs b/vendor/rustix/src/backend/libc/mm/syscalls.rs new file mode 100644 index 0000000..33bc9ca --- /dev/null +++ b/vendor/rustix/src/backend/libc/mm/syscalls.rs @@ -0,0 +1,244 @@ +//! libc syscalls supporting `rustix::mm`. + +#[cfg(not(target_os = "redox"))] +use super::types::Advice; +#[cfg(any(linux_kernel, freebsdlike, netbsdlike))] +use super::types::MlockAllFlags; +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +use super::types::MremapFlags; +use super::types::{MapFlags, MprotectFlags, MsyncFlags, ProtFlags}; +#[cfg(linux_kernel)] +use super::types::{MlockFlags, UserfaultfdFlags}; +use crate::backend::c; +#[cfg(linux_kernel)] +use crate::backend::conv::ret_owned_fd; +use crate::backend::conv::{borrowed_fd, no_fd, ret}; +use crate::fd::BorrowedFd; +#[cfg(linux_kernel)] +use crate::fd::OwnedFd; +use crate::io; + +#[cfg(not(target_os = "redox"))] +pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> { +    // On Linux platforms, `MADV_DONTNEED` has the same value as +    // `POSIX_MADV_DONTNEED` but different behavior. We remap it to a different +    // value, and check for it here. +    #[cfg(target_os = "linux")] +    if let Advice::LinuxDontNeed = advice { +        return unsafe { ret(c::madvise(addr, len, c::MADV_DONTNEED)) }; +    } + +    #[cfg(not(target_os = "android"))] +    { +        let err = unsafe { c::posix_madvise(addr, len, advice as c::c_int) }; + +        // `posix_madvise` returns its error status rather than using `errno`. +        if err == 0 { +            Ok(()) +        } else { +            Err(io::Errno(err)) +        } +    } + +    #[cfg(target_os = "android")] +    { +        if let Advice::DontNeed = advice { +            // Do nothing. Linux's `MADV_DONTNEED` isn't the same as +            // `POSIX_MADV_DONTNEED`, so just discard `MADV_DONTNEED`. +            Ok(()) +        } else { +            unsafe { ret(c::madvise(addr, len, advice as c::c_int)) } +        } +    } +} + +pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> { +    let err = c::msync(addr, len, bitflags_bits!(flags)); + +    // `msync` returns its error status rather than using `errno`. +    if err == 0 { +        Ok(()) +    } else { +        Err(io::Errno(err)) +    } +} + +/// # Safety +/// +/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working +/// with memory pointed to by raw pointers is unsafe. +pub(crate) unsafe fn mmap( +    ptr: *mut c::c_void, +    len: usize, +    prot: ProtFlags, +    flags: MapFlags, +    fd: BorrowedFd<'_>, +    offset: u64, +) -> io::Result<*mut c::c_void> { +    let res = c::mmap( +        ptr, +        len, +        bitflags_bits!(prot), +        bitflags_bits!(flags), +        borrowed_fd(fd), +        offset as i64, +    ); +    if res == c::MAP_FAILED { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(res) +    } +} + +/// # Safety +/// +/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working +/// with memory pointed to by raw pointers is unsafe. +pub(crate) unsafe fn mmap_anonymous( +    ptr: *mut c::c_void, +    len: usize, +    prot: ProtFlags, +    flags: MapFlags, +) -> io::Result<*mut c::c_void> { +    let res = c::mmap( +        ptr, +        len, +        bitflags_bits!(prot), +        bitflags_bits!(flags | MapFlags::from_bits_retain(bitcast!(c::MAP_ANONYMOUS))), +        no_fd(), +        0, +    ); +    if res == c::MAP_FAILED { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(res) +    } +} + +pub(crate) unsafe fn mprotect( +    ptr: *mut c::c_void, +    len: usize, +    flags: MprotectFlags, +) -> io::Result<()> { +    ret(c::mprotect(ptr, len, bitflags_bits!(flags))) +} + +pub(crate) unsafe fn munmap(ptr: *mut c::c_void, len: usize) -> io::Result<()> { +    ret(c::munmap(ptr, len)) +} + +/// # Safety +/// +/// `mremap` is primarily unsafe due to the `old_address` parameter, as +/// anything working with memory pointed to by raw pointers is unsafe. +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +pub(crate) unsafe fn mremap( +    old_address: *mut c::c_void, +    old_size: usize, +    new_size: usize, +    flags: MremapFlags, +) -> io::Result<*mut c::c_void> { +    let res = c::mremap(old_address, old_size, new_size, bitflags_bits!(flags)); +    if res == c::MAP_FAILED { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(res) +    } +} + +/// # Safety +/// +/// `mremap_fixed` is primarily unsafe due to the `old_address` and +/// `new_address` parameters, as anything working with memory pointed to by raw +/// pointers is unsafe. +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +pub(crate) unsafe fn mremap_fixed( +    old_address: *mut c::c_void, +    old_size: usize, +    new_size: usize, +    flags: MremapFlags, +    new_address: *mut c::c_void, +) -> io::Result<*mut c::c_void> { +    let res = c::mremap( +        old_address, +        old_size, +        new_size, +        bitflags_bits!(flags | MremapFlags::from_bits_retain(bitcast!(c::MAP_FIXED))), +        new_address, +    ); +    if res == c::MAP_FAILED { +        Err(io::Errno::last_os_error()) +    } else { +        Ok(res) +    } +} + +/// # Safety +/// +/// `mlock` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { +    ret(c::mlock(addr, length)) +} + +/// # Safety +/// +/// `mlock_with` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[cfg(linux_kernel)] +#[inline] +pub(crate) unsafe fn mlock_with( +    addr: *mut c::c_void, +    length: usize, +    flags: MlockFlags, +) -> io::Result<()> { +    weak_or_syscall! { +        fn mlock2( +            addr: *const c::c_void, +            len: c::size_t, +            flags: c::c_int +        ) via SYS_mlock2 -> c::c_int +    } + +    ret(mlock2(addr, length, bitflags_bits!(flags))) +} + +/// # Safety +/// +/// `munlock` operates on raw pointers and may round out to the nearest page +/// boundaries. +#[inline] +pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { +    ret(c::munlock(addr, length)) +} + +#[cfg(linux_kernel)] +pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> { +    syscall! { +        fn userfaultfd( +            flags: c::c_int +        ) via SYS_userfaultfd -> c::c_int +    } +    ret_owned_fd(userfaultfd(bitflags_bits!(flags))) +} + +/// Locks all pages mapped into the address space of the calling process. +/// +/// This includes the pages of the code, data, and stack segment, as well as +/// shared libraries, user space kernel data, shared memory, and memory-mapped +/// files. All mapped pages are guaranteed to be resident in RAM when the call +/// returns successfully; the pages are guaranteed to stay in RAM until later +/// unlocked. +#[inline] +#[cfg(any(linux_kernel, freebsdlike, netbsdlike))] +pub(crate) fn mlockall(flags: MlockAllFlags) -> io::Result<()> { +    unsafe { ret(c::mlockall(bitflags_bits!(flags))) } +} + +/// Unlocks all pages mapped into the address space of the calling process. +#[inline] +#[cfg(any(linux_kernel, freebsdlike, netbsdlike))] +pub(crate) fn munlockall() -> io::Result<()> { +    unsafe { ret(c::munlockall()) } +} diff --git a/vendor/rustix/src/backend/libc/mm/types.rs b/vendor/rustix/src/backend/libc/mm/types.rs new file mode 100644 index 0000000..a4aa3e2 --- /dev/null +++ b/vendor/rustix/src/backend/libc/mm/types.rs @@ -0,0 +1,477 @@ +use crate::backend::c; +use bitflags::bitflags; + +bitflags! { +    /// `PROT_*` flags for use with [`mmap`]. +    /// +    /// For `PROT_NONE`, use `ProtFlags::empty()`. +    /// +    /// [`mmap`]: crate::mm::mmap +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct ProtFlags: u32 { +        /// `PROT_READ` +        const READ = bitcast!(c::PROT_READ); +        /// `PROT_WRITE` +        const WRITE = bitcast!(c::PROT_WRITE); +        /// `PROT_EXEC` +        const EXEC = bitcast!(c::PROT_EXEC); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +bitflags! { +    /// `PROT_*` flags for use with [`mprotect`]. +    /// +    /// For `PROT_NONE`, use `MprotectFlags::empty()`. +    /// +    /// [`mprotect`]: crate::mm::mprotect +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MprotectFlags: u32 { +        /// `PROT_READ` +        const READ = bitcast!(c::PROT_READ); +        /// `PROT_WRITE` +        const WRITE = bitcast!(c::PROT_WRITE); +        /// `PROT_EXEC` +        const EXEC = bitcast!(c::PROT_EXEC); +        /// `PROT_GROWSUP` +        #[cfg(linux_kernel)] +        const GROWSUP = bitcast!(c::PROT_GROWSUP); +        /// `PROT_GROWSDOWN` +        #[cfg(linux_kernel)] +        const GROWSDOWN = bitcast!(c::PROT_GROWSDOWN); +        /// `PROT_SEM` +        #[cfg(linux_kernel)] +        const SEM = linux_raw_sys::general::PROT_SEM; +        /// `PROT_BTI` +        #[cfg(all(linux_kernel, target_arch = "aarch64"))] +        const BTI = linux_raw_sys::general::PROT_BTI; +        /// `PROT_MTE` +        #[cfg(all(linux_kernel, target_arch = "aarch64"))] +        const MTE = linux_raw_sys::general::PROT_MTE; +        /// `PROT_SAO` +        #[cfg(all(linux_kernel, any(target_arch = "powerpc", target_arch = "powerpc64")))] +        const SAO = linux_raw_sys::general::PROT_SAO; +        /// `PROT_ADI` +        #[cfg(all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64")))] +        const ADI = linux_raw_sys::general::PROT_ADI; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +bitflags! { +    /// `MAP_*` flags for use with [`mmap`]. +    /// +    /// For `MAP_ANONYMOUS` (aka `MAP_ANON`), see [`mmap_anonymous`]. +    /// +    /// [`mmap`]: crate::mm::mmap +    /// [`mmap_anonymous`]: crates::mm::mmap_anonymous +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MapFlags: u32 { +        /// `MAP_SHARED` +        const SHARED = bitcast!(c::MAP_SHARED); +        /// `MAP_SHARED_VALIDATE` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "android", +            target_os = "emscripten", +            target_os = "fuchsia", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +        )))] +        const SHARED_VALIDATE = bitcast!(c::MAP_SHARED_VALIDATE); +        /// `MAP_PRIVATE` +        const PRIVATE = bitcast!(c::MAP_PRIVATE); +        /// `MAP_DENYWRITE` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +        )))] +        const DENYWRITE = bitcast!(c::MAP_DENYWRITE); +        /// `MAP_FIXED` +        const FIXED = bitcast!(c::MAP_FIXED); +        /// `MAP_FIXED_NOREPLACE` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "android", +            target_os = "emscripten", +            target_os = "fuchsia", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +        )))] +        const FIXED_NOREPLACE = bitcast!(c::MAP_FIXED_NOREPLACE); +        /// `MAP_GROWSDOWN` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +        )))] +        const GROWSDOWN = bitcast!(c::MAP_GROWSDOWN); +        /// `MAP_HUGETLB` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +        )))] +        const HUGETLB = bitcast!(c::MAP_HUGETLB); +        /// `MAP_HUGE_2MB` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "android", +            target_os = "emscripten", +            target_os = "fuchsia", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +        )))] +        const HUGE_2MB = bitcast!(c::MAP_HUGE_2MB); +        /// `MAP_HUGE_1GB` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "android", +            target_os = "emscripten", +            target_os = "fuchsia", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +        )))] +        const HUGE_1GB = bitcast!(c::MAP_HUGE_1GB); +        /// `MAP_LOCKED` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +        )))] +        const LOCKED = bitcast!(c::MAP_LOCKED); +        /// `MAP_NOCORE` +        #[cfg(freebsdlike)] +        const NOCORE = bitcast!(c::MAP_NOCORE); +        /// `MAP_NORESERVE` +        #[cfg(not(any( +            freebsdlike, +            target_os = "aix", +            target_os = "nto", +            target_os = "redox", +        )))] +        const NORESERVE = bitcast!(c::MAP_NORESERVE); +        /// `MAP_NOSYNC` +        #[cfg(freebsdlike)] +        const NOSYNC = bitcast!(c::MAP_NOSYNC); +        /// `MAP_POPULATE` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +        )))] +        const POPULATE = bitcast!(c::MAP_POPULATE); +        /// `MAP_STACK` +        #[cfg(not(any( +            apple, +            solarish, +            target_os = "aix", +            target_os = "dragonfly", +            target_os = "haiku", +            target_os = "netbsd", +            target_os = "redox", +        )))] +        const STACK = bitcast!(c::MAP_STACK); +        /// `MAP_PREFAULT_READ` +        #[cfg(target_os = "freebsd")] +        const PREFAULT_READ = bitcast!(c::MAP_PREFAULT_READ); +        /// `MAP_SYNC` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "android", +            target_os = "emscripten", +            target_os = "fuchsia", +            target_os = "haiku", +            target_os = "nto", +            target_os = "redox", +            all( +                linux_kernel, +                any(target_arch = "mips", target_arch = "mips32r6", target_arch = "mips64", target_arch = "mips64r6"), +            ) +        )))] +        const SYNC = bitcast!(c::MAP_SYNC); +        /// `MAP_UNINITIALIZED` +        #[cfg(any())] +        const UNINITIALIZED = bitcast!(c::MAP_UNINITIALIZED); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(any(target_os = "emscripten", target_os = "linux"))] +bitflags! { +    /// `MREMAP_*` flags for use with [`mremap`]. +    /// +    /// For `MREMAP_FIXED`, see [`mremap_fixed`]. +    /// +    /// [`mremap`]: crate::mm::mremap +    /// [`mremap_fixed`]: crate::mm::mremap_fixed +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MremapFlags: u32 { +        /// `MREMAP_MAYMOVE` +        const MAYMOVE = bitcast!(c::MREMAP_MAYMOVE); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +bitflags! { +    /// `MS_*` flags for use with [`msync`]. +    /// +    /// [`msync`]: crate::mm::msync +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MsyncFlags: u32 { +        /// `MS_SYNC`—Requests an update and waits for it to complete. +        const SYNC = bitcast!(c::MS_SYNC); +        /// `MS_ASYNC`—Specifies that an update be scheduled, but the call +        /// returns immediately. +        const ASYNC = bitcast!(c::MS_ASYNC); +        /// `MS_INVALIDATE`—Asks to invalidate other mappings of the same +        /// file (so that they can be updated with the fresh values just +        /// written). +        const INVALIDATE = bitcast!(c::MS_INVALIDATE); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(linux_kernel)] +bitflags! { +    /// `MLOCK_*` flags for use with [`mlock_with`]. +    /// +    /// [`mlock_with`]: crate::mm::mlock_with +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MlockFlags: u32 { +        /// `MLOCK_ONFAULT` +        const ONFAULT = bitcast!(c::MLOCK_ONFAULT); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// `POSIX_MADV_*` constants for use with [`madvise`]. +/// +/// [`madvise`]: crate::mm::madvise +#[cfg(not(target_os = "redox"))] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +#[non_exhaustive] +pub enum Advice { +    /// `POSIX_MADV_NORMAL` +    #[cfg(not(any(target_os = "android", target_os = "haiku")))] +    Normal = bitcast!(c::POSIX_MADV_NORMAL), + +    /// `POSIX_MADV_NORMAL` +    #[cfg(any(target_os = "android", target_os = "haiku"))] +    Normal = bitcast!(c::MADV_NORMAL), + +    /// `POSIX_MADV_SEQUENTIAL` +    #[cfg(not(any(target_os = "android", target_os = "haiku")))] +    Sequential = bitcast!(c::POSIX_MADV_SEQUENTIAL), + +    /// `POSIX_MADV_SEQUENTIAL` +    #[cfg(any(target_os = "android", target_os = "haiku"))] +    Sequential = bitcast!(c::MADV_SEQUENTIAL), + +    /// `POSIX_MADV_RANDOM` +    #[cfg(not(any(target_os = "android", target_os = "haiku")))] +    Random = bitcast!(c::POSIX_MADV_RANDOM), + +    /// `POSIX_MADV_RANDOM` +    #[cfg(any(target_os = "android", target_os = "haiku"))] +    Random = bitcast!(c::MADV_RANDOM), + +    /// `POSIX_MADV_WILLNEED` +    #[cfg(not(any(target_os = "android", target_os = "haiku")))] +    WillNeed = bitcast!(c::POSIX_MADV_WILLNEED), + +    /// `POSIX_MADV_WILLNEED` +    #[cfg(any(target_os = "android", target_os = "haiku"))] +    WillNeed = bitcast!(c::MADV_WILLNEED), + +    /// `POSIX_MADV_DONTNEED` +    #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "haiku")))] +    DontNeed = bitcast!(c::POSIX_MADV_DONTNEED), + +    /// `POSIX_MADV_DONTNEED` +    #[cfg(any(target_os = "android", target_os = "haiku"))] +    DontNeed = bitcast!(i32::MAX - 1), + +    /// `MADV_DONTNEED` +    // `MADV_DONTNEED` has the same value as `POSIX_MADV_DONTNEED`. We don't +    // have a separate `posix_madvise` from `madvise`, so we expose a special +    // value which we special-case. +    #[cfg(target_os = "linux")] +    LinuxDontNeed = bitcast!(i32::MAX), + +    /// `MADV_DONTNEED` +    #[cfg(target_os = "android")] +    LinuxDontNeed = bitcast!(c::MADV_DONTNEED), +    /// `MADV_FREE` +    #[cfg(linux_kernel)] +    LinuxFree = bitcast!(c::MADV_FREE), +    /// `MADV_REMOVE` +    #[cfg(linux_kernel)] +    LinuxRemove = bitcast!(c::MADV_REMOVE), +    /// `MADV_DONTFORK` +    #[cfg(linux_kernel)] +    LinuxDontFork = bitcast!(c::MADV_DONTFORK), +    /// `MADV_DOFORK` +    #[cfg(linux_kernel)] +    LinuxDoFork = bitcast!(c::MADV_DOFORK), +    /// `MADV_HWPOISON` +    #[cfg(linux_kernel)] +    LinuxHwPoison = bitcast!(c::MADV_HWPOISON), +    /// `MADV_SOFT_OFFLINE` +    #[cfg(all( +        linux_kernel, +        not(any( +            target_arch = "mips", +            target_arch = "mips32r6", +            target_arch = "mips64", +            target_arch = "mips64r6" +        )) +    ))] +    LinuxSoftOffline = bitcast!(c::MADV_SOFT_OFFLINE), +    /// `MADV_MERGEABLE` +    #[cfg(linux_kernel)] +    LinuxMergeable = bitcast!(c::MADV_MERGEABLE), +    /// `MADV_UNMERGEABLE` +    #[cfg(linux_kernel)] +    LinuxUnmergeable = bitcast!(c::MADV_UNMERGEABLE), +    /// `MADV_HUGEPAGE` +    #[cfg(linux_kernel)] +    LinuxHugepage = bitcast!(c::MADV_HUGEPAGE), +    /// `MADV_NOHUGEPAGE` +    #[cfg(linux_kernel)] +    LinuxNoHugepage = bitcast!(c::MADV_NOHUGEPAGE), +    /// `MADV_DONTDUMP` (since Linux 3.4) +    #[cfg(linux_kernel)] +    LinuxDontDump = bitcast!(c::MADV_DONTDUMP), +    /// `MADV_DODUMP` (since Linux 3.4) +    #[cfg(linux_kernel)] +    LinuxDoDump = bitcast!(c::MADV_DODUMP), +    /// `MADV_WIPEONFORK` (since Linux 4.14) +    #[cfg(linux_kernel)] +    LinuxWipeOnFork = bitcast!(c::MADV_WIPEONFORK), +    /// `MADV_KEEPONFORK` (since Linux 4.14) +    #[cfg(linux_kernel)] +    LinuxKeepOnFork = bitcast!(c::MADV_KEEPONFORK), +    /// `MADV_COLD` (since Linux 5.4) +    #[cfg(linux_kernel)] +    LinuxCold = bitcast!(c::MADV_COLD), +    /// `MADV_PAGEOUT` (since Linux 5.4) +    #[cfg(linux_kernel)] +    LinuxPageOut = bitcast!(c::MADV_PAGEOUT), +    /// `MADV_POPULATE_READ` (since Linux 5.14) +    #[cfg(linux_kernel)] +    LinuxPopulateRead = bitcast!(c::MADV_POPULATE_READ), +    /// `MADV_POPULATE_WRITE` (since Linux 5.14) +    #[cfg(linux_kernel)] +    LinuxPopulateWrite = bitcast!(c::MADV_POPULATE_WRITE), +    /// `MADV_DONTNEED_LOCKED` (since Linux 5.18) +    #[cfg(linux_kernel)] +    LinuxDontneedLocked = bitcast!(c::MADV_DONTNEED_LOCKED), +} + +#[cfg(target_os = "emscripten")] +#[allow(non_upper_case_globals)] +impl Advice { +    /// `POSIX_MADV_DONTNEED` +    pub const DontNeed: Self = Self::Normal; +} + +#[cfg(linux_kernel)] +bitflags! { +    /// `O_*` flags for use with [`userfaultfd`]. +    /// +    /// [`userfaultfd`]: crate::mm::userfaultfd +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct UserfaultfdFlags: u32 { +        /// `O_CLOEXEC` +        const CLOEXEC = bitcast!(c::O_CLOEXEC); +        /// `O_NONBLOCK` +        const NONBLOCK = bitcast!(c::O_NONBLOCK); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(any(linux_kernel, freebsdlike, netbsdlike))] +bitflags! { +    /// `MCL_*` flags for use with [`mlockall`]. +    /// +    /// [`mlockall`]: crate::mm::mlockall +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MlockAllFlags: u32 { +        /// Used together with `MCL_CURRENT`, `MCL_FUTURE`, or both. Mark all +        /// current (with `MCL_CURRENT`) or future (with `MCL_FUTURE`) mappings +        /// to lock pages when they are faulted in. When used with +        /// `MCL_CURRENT`, all present pages are locked, but `mlockall` will +        /// not fault in non-present pages. When used with `MCL_FUTURE`, all +        /// future mappings will be marked to lock pages when they are faulted +        /// in, but they will not be populated by the lock when the mapping is +        /// created. `MCL_ONFAULT` must be used with either `MCL_CURRENT` or +        /// `MCL_FUTURE` or both. +        #[cfg(linux_kernel)] +        const ONFAULT = bitcast!(libc::MCL_ONFAULT); +        /// Lock all pages which will become mapped into the address space of +        /// the process in the future. These could be, for instance, new pages +        /// required by a growing heap and stack as well as new memory-mapped +        /// files or shared memory regions. +        const FUTURE = bitcast!(libc::MCL_FUTURE); +        /// Lock all pages which are currently mapped into the address space of +        /// the process. +        const CURRENT = bitcast!(libc::MCL_CURRENT); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} diff --git a/vendor/rustix/src/backend/libc/mod.rs b/vendor/rustix/src/backend/libc/mod.rs new file mode 100644 index 0000000..9ecb09f --- /dev/null +++ b/vendor/rustix/src/backend/libc/mod.rs @@ -0,0 +1,215 @@ +//! The libc backend. +//! +//! On most platforms, this uses the `libc` crate to make system calls. On +//! Windows, this uses the Winsock API in `windows-sys`, which can be adapted +//! to have a very `libc`-like interface. + +// Every FFI call requires an unsafe block, and there are a lot of FFI +// calls. For now, set this to allow for the libc backend. +#![allow(clippy::undocumented_unsafe_blocks)] +// Lots of libc types vary between platforms, so we often need a `.into()` on +// one platform where it's redundant on another. +#![allow(clippy::useless_conversion)] + +mod conv; + +#[cfg(windows)] +pub(crate) mod fd { +    pub use crate::maybe_polyfill::os::windows::io::{ +        AsRawSocket, AsSocket, BorrowedSocket as BorrowedFd, FromRawSocket, IntoRawSocket, +        OwnedSocket as OwnedFd, RawSocket as RawFd, +    }; +    pub(crate) use windows_sys::Win32::Networking::WinSock::SOCKET as LibcFd; + +    /// A version of [`AsRawFd`] for use with Winsock API. +    /// +    /// [`AsRawFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.AsRawFd.html +    pub trait AsRawFd { +        /// A version of [`as_raw_fd`] for use with Winsock API. +        /// +        /// [`as_raw_fd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#tymethod.as_raw_fd +        fn as_raw_fd(&self) -> RawFd; +    } +    impl<T: AsRawSocket> AsRawFd for T { +        #[inline] +        fn as_raw_fd(&self) -> RawFd { +            self.as_raw_socket() +        } +    } + +    /// A version of [`IntoRawFd`] for use with Winsock API. +    /// +    /// [`IntoRawFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.IntoRawFd.html +    pub trait IntoRawFd { +        /// A version of [`into_raw_fd`] for use with Winsock API. +        /// +        /// [`into_raw_fd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#tymethod.into_raw_fd +        fn into_raw_fd(self) -> RawFd; +    } +    impl<T: IntoRawSocket> IntoRawFd for T { +        #[inline] +        fn into_raw_fd(self) -> RawFd { +            self.into_raw_socket() +        } +    } + +    /// A version of [`FromRawFd`] for use with Winsock API. +    /// +    /// [`FromRawFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html +    pub trait FromRawFd { +        /// A version of [`from_raw_fd`] for use with Winsock API. +        /// +        /// # Safety +        /// +        /// See the [safety requirements] for [`from_raw_fd`]. +        /// +        /// [`from_raw_fd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#tymethod.from_raw_fd +        /// [safety requirements]: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.html#safety +        unsafe fn from_raw_fd(raw_fd: RawFd) -> Self; +    } +    impl<T: FromRawSocket> FromRawFd for T { +        #[inline] +        unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { +            Self::from_raw_socket(raw_fd) +        } +    } + +    /// A version of [`AsFd`] for use with Winsock API. +    /// +    /// [`AsFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.AsFd.html +    pub trait AsFd { +        /// An `as_fd` function for Winsock, where a `Fd` is a `Socket`. +        fn as_fd(&self) -> BorrowedFd; +    } +    impl<T: AsSocket> AsFd for T { +        #[inline] +        fn as_fd(&self) -> BorrowedFd { +            self.as_socket() +        } +    } +} +#[cfg(not(windows))] +pub(crate) mod fd { +    pub use crate::maybe_polyfill::os::fd::{ +        AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd, +    }; +    #[allow(unused_imports)] +    pub(crate) use RawFd as LibcFd; +} + +// On Windows we emulate selected libc-compatible interfaces. On non-Windows, +// we just use libc here, since this is the libc backend. +#[cfg_attr(windows, path = "winsock_c.rs")] +pub(crate) mod c; + +#[cfg(feature = "event")] +pub(crate) mod event; +#[cfg(not(windows))] +#[cfg(feature = "fs")] +pub(crate) mod fs; +pub(crate) mod io; +#[cfg(linux_kernel)] +#[cfg(feature = "io_uring")] +pub(crate) mod io_uring; +#[cfg(not(any(windows, target_os = "espidf", target_os = "vita", target_os = "wasi")))] +#[cfg(feature = "mm")] +pub(crate) mod mm; +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) mod mount; +#[cfg(linux_kernel)] +#[cfg(all(feature = "fs", not(feature = "mount")))] +pub(crate) mod mount; // for deprecated mount functions in "fs" +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[cfg(feature = "net")] +pub(crate) mod net; +#[cfg(not(any(windows, target_os = "espidf")))] +#[cfg(any( +    feature = "param", +    feature = "runtime", +    feature = "time", +    target_arch = "x86", +))] +pub(crate) mod param; +#[cfg(not(windows))] +#[cfg(feature = "pipe")] +pub(crate) mod pipe; +#[cfg(not(windows))] +#[cfg(feature = "process")] +pub(crate) mod process; +#[cfg(not(windows))] +#[cfg(not(target_os = "wasi"))] +#[cfg(feature = "pty")] +pub(crate) mod pty; +#[cfg(not(windows))] +#[cfg(feature = "rand")] +pub(crate) mod rand; +#[cfg(not(windows))] +#[cfg(not(target_os = "wasi"))] +#[cfg(feature = "system")] +pub(crate) mod system; +#[cfg(not(any(windows, target_os = "vita")))] +#[cfg(feature = "termios")] +pub(crate) mod termios; +#[cfg(not(windows))] +#[cfg(feature = "thread")] +pub(crate) mod thread; +#[cfg(not(any(windows, target_os = "espidf")))] +#[cfg(feature = "time")] +pub(crate) mod time; + +/// If the host libc is glibc, return `true` if it is less than version 2.25. +/// +/// To restate and clarify, this function returning true does not mean the libc +/// is glibc just that if it is glibc, it is less than version 2.25. +/// +/// For now, this function is only available on Linux, but if it ends up being +/// used beyond that, this could be changed to e.g. `#[cfg(unix)]`. +#[cfg(all(unix, target_env = "gnu"))] +pub(crate) fn if_glibc_is_less_than_2_25() -> bool { +    // This is also defined inside `weak_or_syscall!` in +    // backend/libc/rand/syscalls.rs, but it's not convenient to re-export the +    // weak symbol from that macro, so we duplicate it at a small cost here. +    weak! { fn getrandom(*mut c::c_void, c::size_t, c::c_uint) -> c::ssize_t } + +    // glibc 2.25 has `getrandom`, which is how we satisfy the API contract of +    // this function. But, there are likely other libc versions which have it. +    getrandom.get().is_none() +} + +// Private modules used by multiple public modules. +#[cfg(any(feature = "procfs", feature = "process", feature = "runtime"))] +#[cfg(not(any(windows, target_os = "wasi")))] +pub(crate) mod pid; +#[cfg(any(feature = "process", feature = "thread"))] +#[cfg(linux_kernel)] +pub(crate) mod prctl; +#[cfg(not(any( +    windows, +    target_os = "android", +    target_os = "espidf", +    target_os = "vita", +    target_os = "wasi" +)))] +#[cfg(feature = "shm")] +pub(crate) mod shm; +#[cfg(any(feature = "fs", feature = "thread", feature = "process"))] +#[cfg(not(any(windows, target_os = "wasi")))] +pub(crate) mod ugid; + +#[cfg(bsd)] +const MAX_IOV: usize = c::IOV_MAX as usize; + +#[cfg(any(linux_kernel, target_os = "emscripten", target_os = "nto"))] +const MAX_IOV: usize = c::UIO_MAXIOV as usize; + +#[cfg(not(any( +    bsd, +    linux_kernel, +    windows, +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "nto", +    target_os = "horizon", +)))] +const MAX_IOV: usize = 16; // The minimum value required by POSIX. diff --git a/vendor/rustix/src/backend/libc/mount/mod.rs b/vendor/rustix/src/backend/libc/mount/mod.rs new file mode 100644 index 0000000..1e0181a --- /dev/null +++ b/vendor/rustix/src/backend/libc/mount/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix/src/backend/libc/mount/syscalls.rs b/vendor/rustix/src/backend/libc/mount/syscalls.rs new file mode 100644 index 0000000..7245114 --- /dev/null +++ b/vendor/rustix/src/backend/libc/mount/syscalls.rs @@ -0,0 +1,272 @@ +use crate::backend::c; +use crate::backend::conv::ret; +#[cfg(feature = "mount")] +use crate::backend::conv::{borrowed_fd, c_str, ret_owned_fd}; +#[cfg(feature = "mount")] +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::ffi::CStr; +use crate::io; +use core::ptr::null; + +#[cfg(linux_kernel)] +pub(crate) fn mount( +    source: Option<&CStr>, +    target: &CStr, +    file_system_type: Option<&CStr>, +    flags: super::types::MountFlagsArg, +    data: Option<&CStr>, +) -> io::Result<()> { +    unsafe { +        ret(c::mount( +            source.map_or_else(null, CStr::as_ptr), +            target.as_ptr(), +            file_system_type.map_or_else(null, CStr::as_ptr), +            flags.0, +            data.map_or_else(null, CStr::as_ptr).cast(), +        )) +    } +} + +#[cfg(linux_kernel)] +pub(crate) fn unmount(target: &CStr, flags: super::types::UnmountFlags) -> io::Result<()> { +    unsafe { ret(c::umount2(target.as_ptr(), bitflags_bits!(flags))) } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsopen(fs_name: &CStr, flags: super::types::FsOpenFlags) -> io::Result<OwnedFd> { +    syscall! { +        fn fsopen( +            fs_name: *const c::c_char, +            flags: c::c_uint +        ) via SYS_fsopen -> c::c_int +    } +    unsafe { ret_owned_fd(fsopen(c_str(fs_name), flags.bits())) } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsmount( +    fs_fd: BorrowedFd<'_>, +    flags: super::types::FsMountFlags, +    attr_flags: super::types::MountAttrFlags, +) -> io::Result<OwnedFd> { +    syscall! { +        fn fsmount( +            fs_fd: c::c_int, +            flags: c::c_uint, +            attr_flags: c::c_uint +        ) via SYS_fsmount -> c::c_int +    } +    unsafe { ret_owned_fd(fsmount(borrowed_fd(fs_fd), flags.bits(), attr_flags.bits())) } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn move_mount( +    from_dfd: BorrowedFd<'_>, +    from_pathname: &CStr, +    to_dfd: BorrowedFd<'_>, +    to_pathname: &CStr, +    flags: super::types::MoveMountFlags, +) -> io::Result<()> { +    syscall! { +        fn move_mount( +            from_dfd: c::c_int, +            from_pathname: *const c::c_char, +            to_dfd: c::c_int, +            to_pathname: *const c::c_char, +            flags: c::c_uint +        ) via SYS_move_mount -> c::c_int +    } +    unsafe { +        ret(move_mount( +            borrowed_fd(from_dfd), +            c_str(from_pathname), +            borrowed_fd(to_dfd), +            c_str(to_pathname), +            flags.bits(), +        )) +    } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn open_tree( +    dfd: BorrowedFd<'_>, +    filename: &CStr, +    flags: super::types::OpenTreeFlags, +) -> io::Result<OwnedFd> { +    syscall! { +        fn open_tree( +            dfd: c::c_int, +            filename: *const c::c_char, +            flags: c::c_uint +        ) via SYS_open_tree -> c::c_int +    } + +    unsafe { ret_owned_fd(open_tree(borrowed_fd(dfd), c_str(filename), flags.bits())) } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fspick( +    dfd: BorrowedFd<'_>, +    path: &CStr, +    flags: super::types::FsPickFlags, +) -> io::Result<OwnedFd> { +    syscall! { +        fn fspick( +            dfd: c::c_int, +            path: *const c::c_char, +            flags: c::c_uint +        ) via SYS_fspick -> c::c_int +    } + +    unsafe { ret_owned_fd(fspick(borrowed_fd(dfd), c_str(path), flags.bits())) } +} + +#[cfg(feature = "mount")] +#[cfg(linux_kernel)] +syscall! { +    fn fsconfig( +        fs_fd: c::c_int, +        cmd: c::c_uint, +        key: *const c::c_char, +        val: *const c::c_char, +        aux: c::c_int +    ) via SYS_fsconfig -> c::c_int +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsconfig_set_flag(fs_fd: BorrowedFd<'_>, key: &CStr) -> io::Result<()> { +    unsafe { +        ret(fsconfig( +            borrowed_fd(fs_fd), +            super::types::FsConfigCmd::SetFlag as _, +            c_str(key), +            null(), +            0, +        )) +    } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsconfig_set_string( +    fs_fd: BorrowedFd<'_>, +    key: &CStr, +    value: &CStr, +) -> io::Result<()> { +    unsafe { +        ret(fsconfig( +            borrowed_fd(fs_fd), +            super::types::FsConfigCmd::SetString as _, +            c_str(key), +            c_str(value), +            0, +        )) +    } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsconfig_set_binary( +    fs_fd: BorrowedFd<'_>, +    key: &CStr, +    value: &[u8], +) -> io::Result<()> { +    unsafe { +        ret(fsconfig( +            borrowed_fd(fs_fd), +            super::types::FsConfigCmd::SetBinary as _, +            c_str(key), +            value.as_ptr().cast(), +            value.len().try_into().map_err(|_| io::Errno::OVERFLOW)?, +        )) +    } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsconfig_set_fd( +    fs_fd: BorrowedFd<'_>, +    key: &CStr, +    fd: BorrowedFd<'_>, +) -> io::Result<()> { +    unsafe { +        ret(fsconfig( +            borrowed_fd(fs_fd), +            super::types::FsConfigCmd::SetFd as _, +            c_str(key), +            null(), +            borrowed_fd(fd), +        )) +    } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsconfig_set_path( +    fs_fd: BorrowedFd<'_>, +    key: &CStr, +    path: &CStr, +    fd: BorrowedFd<'_>, +) -> io::Result<()> { +    unsafe { +        ret(fsconfig( +            borrowed_fd(fs_fd), +            super::types::FsConfigCmd::SetPath as _, +            c_str(key), +            c_str(path), +            borrowed_fd(fd), +        )) +    } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsconfig_set_path_empty( +    fs_fd: BorrowedFd<'_>, +    key: &CStr, +    fd: BorrowedFd<'_>, +) -> io::Result<()> { +    unsafe { +        ret(fsconfig( +            borrowed_fd(fs_fd), +            super::types::FsConfigCmd::SetPathEmpty as _, +            c_str(key), +            c_str(cstr!("")), +            borrowed_fd(fd), +        )) +    } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsconfig_create(fs_fd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { +        ret(fsconfig( +            borrowed_fd(fs_fd), +            super::types::FsConfigCmd::Create as _, +            null(), +            null(), +            0, +        )) +    } +} + +#[cfg(linux_kernel)] +#[cfg(feature = "mount")] +pub(crate) fn fsconfig_reconfigure(fs_fd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { +        ret(fsconfig( +            borrowed_fd(fs_fd), +            super::types::FsConfigCmd::Reconfigure as _, +            null(), +            null(), +            0, +        )) +    } +} diff --git a/vendor/rustix/src/backend/libc/mount/types.rs b/vendor/rustix/src/backend/libc/mount/types.rs new file mode 100644 index 0000000..1023686 --- /dev/null +++ b/vendor/rustix/src/backend/libc/mount/types.rs @@ -0,0 +1,340 @@ +use crate::backend::c; +use bitflags::bitflags; + +#[cfg(linux_kernel)] +bitflags! { +    /// `MS_*` constants for use with [`mount`]. +    /// +    /// [`mount`]: crate::mount::mount +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MountFlags: c::c_ulong { +        /// `MS_BIND` +        const BIND = c::MS_BIND; + +        /// `MS_DIRSYNC` +        const DIRSYNC = c::MS_DIRSYNC; + +        /// `MS_LAZYTIME` +        const LAZYTIME = c::MS_LAZYTIME; + +        /// `MS_MANDLOCK` +        #[doc(alias = "MANDLOCK")] +        const PERMIT_MANDATORY_FILE_LOCKING = c::MS_MANDLOCK; + +        /// `MS_NOATIME` +        const NOATIME = c::MS_NOATIME; + +        /// `MS_NODEV` +        const NODEV = c::MS_NODEV; + +        /// `MS_NODIRATIME` +        const NODIRATIME = c::MS_NODIRATIME; + +        /// `MS_NOEXEC` +        const NOEXEC = c::MS_NOEXEC; + +        /// `MS_NOSUID` +        const NOSUID = c::MS_NOSUID; + +        /// `MS_RDONLY` +        const RDONLY = c::MS_RDONLY; + +        /// `MS_REC` +        const REC = c::MS_REC; + +        /// `MS_RELATIME` +        const RELATIME = c::MS_RELATIME; + +        /// `MS_SILENT` +        const SILENT = c::MS_SILENT; + +        /// `MS_STRICTATIME` +        const STRICTATIME = c::MS_STRICTATIME; + +        /// `MS_SYNCHRONOUS` +        const SYNCHRONOUS = c::MS_SYNCHRONOUS; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(linux_kernel)] +bitflags! { +    /// `MNT_*` constants for use with [`unmount`]. +    /// +    /// [`unmount`]: crate::mount::unmount +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct UnmountFlags: u32 { +        /// `MNT_FORCE` +        const FORCE = bitcast!(c::MNT_FORCE); +        /// `MNT_DETACH` +        const DETACH = bitcast!(c::MNT_DETACH); +        /// `MNT_EXPIRE` +        const EXPIRE = bitcast!(c::MNT_EXPIRE); +        /// `UMOUNT_NOFOLLOW` +        const NOFOLLOW = bitcast!(c::UMOUNT_NOFOLLOW); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(feature = "mount")] +#[cfg(linux_kernel)] +bitflags! { +    /// `FSOPEN_*` constants for use with [`fsopen`]. +    /// +    /// [`fsopen`]: crate::mount::fsopen +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct FsOpenFlags: c::c_uint { +        /// `FSOPEN_CLOEXEC` +        const FSOPEN_CLOEXEC = 0x0000_0001; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(feature = "mount")] +#[cfg(linux_kernel)] +bitflags! { +    /// `FSMOUNT_*` constants for use with [`fsmount`]. +    /// +    /// [`fsmount`]: crate::mount::fsmount +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct FsMountFlags: c::c_uint { +        /// `FSMOUNT_CLOEXEC` +        const FSMOUNT_CLOEXEC = 0x0000_0001; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// `FSCONFIG_*` constants for use with the `fsconfig` syscall. +#[cfg(feature = "mount")] +#[cfg(linux_kernel)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +pub(crate) enum FsConfigCmd { +    /// `FSCONFIG_SET_FLAG` +    SetFlag = 0, + +    /// `FSCONFIG_SET_STRING` +    SetString = 1, + +    /// `FSCONFIG_SET_BINARY` +    SetBinary = 2, + +    /// `FSCONFIG_SET_PATH` +    SetPath = 3, + +    /// `FSCONFIG_SET_PATH_EMPTY` +    SetPathEmpty = 4, + +    /// `FSCONFIG_SET_FD` +    SetFd = 5, + +    /// `FSCONFIG_CMD_CREATE` +    Create = 6, + +    /// `FSCONFIG_CMD_RECONFIGURE` +    Reconfigure = 7, +} + +#[cfg(feature = "mount")] +#[cfg(linux_kernel)] +bitflags! { +    /// `MOUNT_ATTR_*` constants for use with [`fsmount`]. +    /// +    /// [`fsmount`]: crate::mount::fsmount +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MountAttrFlags: c::c_uint { +        /// `MOUNT_ATTR_RDONLY` +        const MOUNT_ATTR_RDONLY = 0x0000_0001; + +        /// `MOUNT_ATTR_NOSUID` +        const MOUNT_ATTR_NOSUID = 0x0000_0002; + +        /// `MOUNT_ATTR_NODEV` +        const MOUNT_ATTR_NODEV = 0x0000_0004; + +        /// `MOUNT_ATTR_NOEXEC` +        const MOUNT_ATTR_NOEXEC = 0x0000_0008; + +        /// `MOUNT_ATTR__ATIME` +        const MOUNT_ATTR__ATIME = 0x0000_0070; + +        /// `MOUNT_ATTR_RELATIME` +        const MOUNT_ATTR_RELATIME = 0x0000_0000; + +        /// `MOUNT_ATTR_NOATIME` +        const MOUNT_ATTR_NOATIME = 0x0000_0010; + +        /// `MOUNT_ATTR_STRICTATIME` +        const MOUNT_ATTR_STRICTATIME = 0x0000_0020; + +        /// `MOUNT_ATTR_NODIRATIME` +        const MOUNT_ATTR_NODIRATIME = 0x0000_0080; + +        /// `MOUNT_ATTR_NOUSER` +        const MOUNT_ATTR_IDMAP = 0x0010_0000; + +        /// `MOUNT_ATTR__ATIME_FLAGS` +        const MOUNT_ATTR_NOSYMFOLLOW = 0x0020_0000; + +        /// `MOUNT_ATTR__ATIME_FLAGS` +        const MOUNT_ATTR_SIZE_VER0 = 32; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(feature = "mount")] +#[cfg(linux_kernel)] +bitflags! { +    /// `MOVE_MOUNT_*` constants for use with [`move_mount`]. +    /// +    /// [`move_mount`]: crate::mount::move_mount +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MoveMountFlags: c::c_uint { +        /// `MOVE_MOUNT_F_EMPTY_PATH` +        const MOVE_MOUNT_F_SYMLINKS = 0x0000_0001; + +        /// `MOVE_MOUNT_F_AUTOMOUNTS` +        const MOVE_MOUNT_F_AUTOMOUNTS = 0x0000_0002; + +        /// `MOVE_MOUNT_F_EMPTY_PATH` +        const MOVE_MOUNT_F_EMPTY_PATH = 0x0000_0004; + +        /// `MOVE_MOUNT_T_SYMLINKS` +        const MOVE_MOUNT_T_SYMLINKS = 0x0000_0010; + +        /// `MOVE_MOUNT_T_AUTOMOUNTS` +        const MOVE_MOUNT_T_AUTOMOUNTS = 0x0000_0020; + +        /// `MOVE_MOUNT_T_EMPTY_PATH` +        const MOVE_MOUNT_T_EMPTY_PATH = 0x0000_0040; + +        /// `MOVE_MOUNT__MASK` +        const MOVE_MOUNT_SET_GROUP = 0x0000_0100; + +        // TODO: add when Linux 6.5 is released +        // /// `MOVE_MOUNT_BENEATH` +        // const MOVE_MOUNT_BENEATH = 0x0000_0200; + +        /// `MOVE_MOUNT__MASK` +        const MOVE_MOUNT__MASK = 0x0000_0377; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(feature = "mount")] +#[cfg(linux_kernel)] +bitflags! { +    /// `OPENTREE_*` constants for use with [`open_tree`]. +    /// +    /// [`open_tree`]: crate::mount::open_tree +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct OpenTreeFlags: c::c_uint { +        /// `OPENTREE_CLONE` +        const OPEN_TREE_CLONE = 1; + +        /// `OPENTREE_CLOEXEC` +        const OPEN_TREE_CLOEXEC = c::O_CLOEXEC as c::c_uint; + +        /// `AT_EMPTY_PATH` +        const AT_EMPTY_PATH = c::AT_EMPTY_PATH as c::c_uint; + +        /// `AT_NO_AUTOMOUNT` +        const AT_NO_AUTOMOUNT = c::AT_NO_AUTOMOUNT as c::c_uint; + +        /// `AT_RECURSIVE` +        const AT_RECURSIVE = c::AT_RECURSIVE as c::c_uint; + +        /// `AT_SYMLINK_NOFOLLOW` +        const AT_SYMLINK_NOFOLLOW = c::AT_SYMLINK_NOFOLLOW as c::c_uint; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(feature = "mount")] +#[cfg(linux_kernel)] +bitflags! { +    /// `FSPICK_*` constants for use with [`fspick`]. +    /// +    /// [`fspick`]: crate::mount::fspick +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct FsPickFlags: c::c_uint { +        /// `FSPICK_CLOEXEC` +        const FSPICK_CLOEXEC = 0x0000_0001; + +        /// `FSPICK_SYMLINK_NOFOLLOW` +        const FSPICK_SYMLINK_NOFOLLOW = 0x0000_0002; + +        /// `FSPICK_NO_AUTOMOUNT` +        const FSPICK_NO_AUTOMOUNT = 0x0000_0004; + +        /// `FSPICK_EMPTY_PATH` +        const FSPICK_EMPTY_PATH = 0x0000_0008; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(linux_kernel)] +bitflags! { +    /// `MS_*` constants for use with [`mount_change`]. +    /// +    /// [`mount_change`]: crate::mount::mount_change +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct MountPropagationFlags: c::c_ulong { +        /// `MS_SILENT` +        const SILENT = c::MS_SILENT; +        /// `MS_SHARED` +        const SHARED = c::MS_SHARED; +        /// `MS_PRIVATE` +        const PRIVATE = c::MS_PRIVATE; +        /// `MS_SLAVE` +        const SLAVE = c::MS_SLAVE; +        /// `MS_UNBINDABLE` +        const UNBINDABLE = c::MS_UNBINDABLE; +        /// `MS_REC` +        const REC = c::MS_REC; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(linux_kernel)] +bitflags! { +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub(crate) struct InternalMountFlags: c::c_ulong { +        const REMOUNT = c::MS_REMOUNT; +        const MOVE = c::MS_MOVE; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(linux_kernel)] +pub(crate) struct MountFlagsArg(pub(crate) c::c_ulong); diff --git a/vendor/rustix/src/backend/libc/net/addr.rs b/vendor/rustix/src/backend/libc/net/addr.rs new file mode 100644 index 0000000..719a549 --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/addr.rs @@ -0,0 +1,245 @@ +//! Socket address utilities. + +use crate::backend::c; +#[cfg(unix)] +use { +    crate::ffi::CStr, +    crate::io, +    crate::path, +    core::cmp::Ordering, +    core::fmt, +    core::hash::{Hash, Hasher}, +    core::slice, +}; + +/// `struct sockaddr_un` +#[cfg(unix)] +#[derive(Clone)] +#[doc(alias = "sockaddr_un")] +pub struct SocketAddrUnix { +    pub(crate) unix: c::sockaddr_un, +    #[cfg(not(any(bsd, target_os = "haiku")))] +    len: c::socklen_t, +} + +#[cfg(unix)] +impl SocketAddrUnix { +    /// Construct a new Unix-domain address from a filesystem path. +    #[inline] +    pub fn new<P: path::Arg>(path: P) -> io::Result<Self> { +        path.into_with_c_str(Self::_new) +    } + +    #[inline] +    fn _new(path: &CStr) -> io::Result<Self> { +        let mut unix = Self::init(); +        let bytes = path.to_bytes_with_nul(); +        if bytes.len() > unix.sun_path.len() { +            return Err(io::Errno::NAMETOOLONG); +        } +        for (i, b) in bytes.iter().enumerate() { +            unix.sun_path[i] = *b as c::c_char; +        } + +        #[cfg(any(bsd, target_os = "haiku"))] +        { +            unix.sun_len = (offsetof_sun_path() + bytes.len()).try_into().unwrap(); +        } + +        Ok(Self { +            unix, +            #[cfg(not(any(bsd, target_os = "haiku")))] +            len: (offsetof_sun_path() + bytes.len()).try_into().unwrap(), +        }) +    } + +    /// Construct a new abstract Unix-domain address from a byte slice. +    #[cfg(linux_kernel)] +    #[inline] +    pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> { +        let mut unix = Self::init(); +        if 1 + name.len() > unix.sun_path.len() { +            return Err(io::Errno::NAMETOOLONG); +        } +        unix.sun_path[0] = 0; +        for (i, b) in name.iter().enumerate() { +            unix.sun_path[1 + i] = *b as c::c_char; +        } +        let len = offsetof_sun_path() + 1 + name.len(); +        let len = len.try_into().unwrap(); +        Ok(Self { +            unix, +            #[cfg(not(any(bsd, target_os = "haiku")))] +            len, +        }) +    } + +    fn init() -> c::sockaddr_un { +        c::sockaddr_un { +            #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))] +            sun_len: 0, +            #[cfg(target_os = "vita")] +            ss_len: 0, +            sun_family: c::AF_UNIX as _, +            #[cfg(any(bsd, target_os = "nto"))] +            sun_path: [0; 104], +            #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto")))] +            sun_path: [0; 108], +            #[cfg(target_os = "haiku")] +            sun_path: [0; 126], +            #[cfg(target_os = "aix")] +            sun_path: [0; 1023], +        } +    } + +    /// For a filesystem path address, return the path. +    #[inline] +    pub fn path(&self) -> Option<&CStr> { +        let len = self.len(); +        if len != 0 && self.unix.sun_path[0] != 0 { +            let end = len as usize - offsetof_sun_path(); +            let bytes = &self.unix.sun_path[..end]; +            // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. +            // And `from_bytes_with_nul_unchecked` since the string is +            // NUL-terminated. +            unsafe { +                Some(CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( +                    bytes.as_ptr().cast(), +                    bytes.len(), +                ))) +            } +        } else { +            None +        } +    } + +    /// For an abstract address, return the identifier. +    #[cfg(linux_kernel)] +    #[inline] +    pub fn abstract_name(&self) -> Option<&[u8]> { +        let len = self.len(); +        if len != 0 && self.unix.sun_path[0] == 0 { +            let end = len as usize - offsetof_sun_path(); +            let bytes = &self.unix.sun_path[1..end]; +            // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. +            unsafe { Some(slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len())) } +        } else { +            None +        } +    } + +    #[inline] +    pub(crate) fn addr_len(&self) -> c::socklen_t { +        #[cfg(not(any(bsd, target_os = "haiku")))] +        { +            self.len +        } +        #[cfg(any(bsd, target_os = "haiku"))] +        { +            c::socklen_t::from(self.unix.sun_len) +        } +    } + +    #[inline] +    pub(crate) fn len(&self) -> usize { +        self.addr_len() as usize +    } +} + +#[cfg(unix)] +impl PartialEq for SocketAddrUnix { +    #[inline] +    fn eq(&self, other: &Self) -> bool { +        let self_len = self.len() - offsetof_sun_path(); +        let other_len = other.len() - offsetof_sun_path(); +        self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len]) +    } +} + +#[cfg(unix)] +impl Eq for SocketAddrUnix {} + +#[cfg(unix)] +impl PartialOrd for SocketAddrUnix { +    #[inline] +    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { +        Some(self.cmp(other)) +    } +} + +#[cfg(unix)] +impl Ord for SocketAddrUnix { +    #[inline] +    fn cmp(&self, other: &Self) -> Ordering { +        let self_len = self.len() - offsetof_sun_path(); +        let other_len = other.len() - offsetof_sun_path(); +        self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len]) +    } +} + +#[cfg(unix)] +impl Hash for SocketAddrUnix { +    #[inline] +    fn hash<H: Hasher>(&self, state: &mut H) { +        let self_len = self.len() - offsetof_sun_path(); +        self.unix.sun_path[..self_len].hash(state) +    } +} + +#[cfg(unix)] +impl fmt::Debug for SocketAddrUnix { +    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { +        if let Some(path) = self.path() { +            path.fmt(fmt) +        } else { +            #[cfg(linux_kernel)] +            if let Some(name) = self.abstract_name() { +                return name.fmt(fmt); +            } + +            "(unnamed)".fmt(fmt) +        } +    } +} + +/// `struct sockaddr_storage` as a raw struct. +pub type SocketAddrStorage = c::sockaddr_storage; + +/// Return the offset of the `sun_path` field of `sockaddr_un`. +#[cfg(not(windows))] +#[inline] +pub(crate) fn offsetof_sun_path() -> usize { +    let z = c::sockaddr_un { +        #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))] +        sun_len: 0_u8, +        #[cfg(target_os = "vita")] +        ss_len: 0, +        #[cfg(any( +            bsd, +            target_os = "aix", +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita" +        ))] +        sun_family: 0_u8, +        #[cfg(not(any( +            bsd, +            target_os = "aix", +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita" +        )))] +        sun_family: 0_u16, +        #[cfg(any(bsd, target_os = "nto"))] +        sun_path: [0; 104], +        #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto")))] +        sun_path: [0; 108], +        #[cfg(target_os = "haiku")] +        sun_path: [0; 126], +        #[cfg(target_os = "aix")] +        sun_path: [0; 1023], +    }; +    (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize) +} diff --git a/vendor/rustix/src/backend/libc/net/ext.rs b/vendor/rustix/src/backend/libc/net/ext.rs new file mode 100644 index 0000000..2e11c05 --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/ext.rs @@ -0,0 +1,135 @@ +use crate::backend::c; + +/// The windows `sockaddr_in6` type is a union with accessor functions which +/// are not `const fn`. Define our own layout-compatible version so that we +/// can transmute in and out of it. +#[cfg(windows)] +#[repr(C)] +struct sockaddr_in6 { +    sin6_family: u16, +    sin6_port: u16, +    sin6_flowinfo: u32, +    sin6_addr: c::in6_addr, +    sin6_scope_id: u32, +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn in_addr_s_addr(addr: c::in_addr) -> u32 { +    addr.s_addr +} + +#[cfg(windows)] +#[inline] +pub(crate) const fn in_addr_s_addr(addr: c::in_addr) -> u32 { +    // This should be `*addr.S_un.S_addr()`, except that isn't a `const fn`. +    unsafe { core::mem::transmute(addr) } +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn in_addr_new(s_addr: u32) -> c::in_addr { +    c::in_addr { s_addr } +} + +#[cfg(windows)] +#[inline] +pub(crate) const fn in_addr_new(s_addr: u32) -> c::in_addr { +    unsafe { core::mem::transmute(s_addr) } +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn in6_addr_s6_addr(addr: c::in6_addr) -> [u8; 16] { +    addr.s6_addr +} + +#[cfg(windows)] +#[inline] +pub(crate) const fn in6_addr_s6_addr(addr: c::in6_addr) -> [u8; 16] { +    unsafe { core::mem::transmute(addr) } +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn in6_addr_new(s6_addr: [u8; 16]) -> c::in6_addr { +    c::in6_addr { s6_addr } +} + +#[cfg(windows)] +#[inline] +pub(crate) const fn in6_addr_new(s6_addr: [u8; 16]) -> c::in6_addr { +    unsafe { core::mem::transmute(s6_addr) } +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn sockaddr_in6_sin6_scope_id(addr: &c::sockaddr_in6) -> u32 { +    addr.sin6_scope_id +} + +#[cfg(windows)] +#[inline] +pub(crate) const fn sockaddr_in6_sin6_scope_id(addr: &c::sockaddr_in6) -> u32 { +    let addr: &sockaddr_in6 = unsafe { core::mem::transmute(addr) }; +    addr.sin6_scope_id +} + +#[cfg(not(windows))] +#[inline] +pub(crate) const fn sockaddr_in6_new( +    #[cfg(any( +        bsd, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "nto", +        target_os = "vita" +    ))] +    sin6_len: u8, +    sin6_family: c::sa_family_t, +    sin6_port: u16, +    sin6_flowinfo: u32, +    sin6_addr: c::in6_addr, +    sin6_scope_id: u32, +) -> c::sockaddr_in6 { +    c::sockaddr_in6 { +        #[cfg(any( +            bsd, +            target_os = "aix", +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita" +        ))] +        sin6_len, +        sin6_family, +        sin6_port, +        sin6_flowinfo, +        sin6_addr, +        sin6_scope_id, +        #[cfg(solarish)] +        __sin6_src_id: 0, +        #[cfg(target_os = "vita")] +        sin6_vport: 0, +    } +} + +#[cfg(windows)] +#[inline] +pub(crate) const fn sockaddr_in6_new( +    sin6_family: u16, +    sin6_port: u16, +    sin6_flowinfo: u32, +    sin6_addr: c::in6_addr, +    sin6_scope_id: u32, +) -> c::sockaddr_in6 { +    let addr = sockaddr_in6 { +        sin6_family, +        sin6_port, +        sin6_flowinfo, +        sin6_addr, +        sin6_scope_id, +    }; +    unsafe { core::mem::transmute(addr) } +} diff --git a/vendor/rustix/src/backend/libc/net/mod.rs b/vendor/rustix/src/backend/libc/net/mod.rs new file mode 100644 index 0000000..d7ab68d --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/mod.rs @@ -0,0 +1,16 @@ +pub(crate) mod addr; +pub(crate) mod ext; +#[cfg(not(any( +    windows, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) mod msghdr; +pub(crate) mod read_sockaddr; +pub(crate) mod send_recv; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) mod sockopt; +pub(crate) mod syscalls; +pub(crate) mod write_sockaddr; diff --git a/vendor/rustix/src/backend/libc/net/msghdr.rs b/vendor/rustix/src/backend/libc/net/msghdr.rs new file mode 100644 index 0000000..dd9b156 --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/msghdr.rs @@ -0,0 +1,134 @@ +//! Utilities for dealing with message headers. +//! +//! These take closures rather than returning a `c::msghdr` directly because +//! the message headers may reference stack-local data. + +use crate::backend::c; +use crate::backend::conv::{msg_control_len, msg_iov_len}; +use crate::backend::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; + +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrV4, SocketAddrV6}; +use crate::utils::as_ptr; + +use core::mem::{size_of, zeroed, MaybeUninit}; + +/// Create a message header intended to receive a datagram. +pub(crate) fn with_recv_msghdr<R>( +    name: &mut MaybeUninit<c::sockaddr_storage>, +    iov: &mut [IoSliceMut<'_>], +    control: &mut RecvAncillaryBuffer<'_>, +    f: impl FnOnce(&mut c::msghdr) -> io::Result<R>, +) -> io::Result<R> { +    control.clear(); + +    let namelen = size_of::<c::sockaddr_storage>() as c::socklen_t; +    let mut msghdr = { +        let mut h = zero_msghdr(); +        h.msg_name = name.as_mut_ptr().cast(); +        h.msg_namelen = namelen; +        h.msg_iov = iov.as_mut_ptr().cast(); +        h.msg_iovlen = msg_iov_len(iov.len()); +        h.msg_control = control.as_control_ptr().cast(); +        h.msg_controllen = msg_control_len(control.control_len()); +        h +    }; + +    let res = f(&mut msghdr); + +    // Reset the control length. +    if res.is_ok() { +        unsafe { +            control.set_control_len(msghdr.msg_controllen.try_into().unwrap_or(usize::MAX)); +        } +    } + +    res +} + +/// Create a message header intended to send without an address. +pub(crate) fn with_noaddr_msghdr<R>( +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    f: impl FnOnce(c::msghdr) -> R, +) -> R { +    f({ +        let mut h = zero_msghdr(); +        h.msg_iov = iov.as_ptr() as _; +        h.msg_iovlen = msg_iov_len(iov.len()); +        h.msg_control = control.as_control_ptr().cast(); +        h.msg_controllen = msg_control_len(control.control_len()); +        h +    }) +} + +/// Create a message header intended to send with an IPv4 address. +pub(crate) fn with_v4_msghdr<R>( +    addr: &SocketAddrV4, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    f: impl FnOnce(c::msghdr) -> R, +) -> R { +    let encoded = encode_sockaddr_v4(addr); + +    f({ +        let mut h = zero_msghdr(); +        h.msg_name = as_ptr(&encoded) as _; +        h.msg_namelen = size_of::<SocketAddrV4>() as _; +        h.msg_iov = iov.as_ptr() as _; +        h.msg_iovlen = msg_iov_len(iov.len()); +        h.msg_control = control.as_control_ptr().cast(); +        h.msg_controllen = msg_control_len(control.control_len()); +        h +    }) +} + +/// Create a message header intended to send with an IPv6 address. +pub(crate) fn with_v6_msghdr<R>( +    addr: &SocketAddrV6, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    f: impl FnOnce(c::msghdr) -> R, +) -> R { +    let encoded = encode_sockaddr_v6(addr); + +    f({ +        let mut h = zero_msghdr(); +        h.msg_name = as_ptr(&encoded) as _; +        h.msg_namelen = size_of::<SocketAddrV6>() as _; +        h.msg_iov = iov.as_ptr() as _; +        h.msg_iovlen = msg_iov_len(iov.len()); +        h.msg_control = control.as_control_ptr().cast(); +        h.msg_controllen = msg_control_len(control.control_len()); +        h +    }) +} + +/// Create a message header intended to send with a Unix address. +#[cfg(all(unix, not(target_os = "redox")))] +pub(crate) fn with_unix_msghdr<R>( +    addr: &crate::net::SocketAddrUnix, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    f: impl FnOnce(c::msghdr) -> R, +) -> R { +    f({ +        let mut h = zero_msghdr(); +        h.msg_name = as_ptr(&addr.unix) as _; +        h.msg_namelen = addr.addr_len(); +        h.msg_iov = iov.as_ptr() as _; +        h.msg_iovlen = msg_iov_len(iov.len()); +        h.msg_control = control.as_control_ptr().cast(); +        h.msg_controllen = msg_control_len(control.control_len()); +        h +    }) +} + +/// Create a zero-initialized message header struct value. +#[cfg(all(unix, not(target_os = "redox")))] +pub(crate) fn zero_msghdr() -> c::msghdr { +    // SAFETY: We can't initialize all the fields by value because on some +    // platforms the `msghdr` struct in the libc crate contains private padding +    // fields. But it is still a C type that's meant to be zero-initializable. +    unsafe { zeroed() } +} diff --git a/vendor/rustix/src/backend/libc/net/read_sockaddr.rs b/vendor/rustix/src/backend/libc/net/read_sockaddr.rs new file mode 100644 index 0000000..6da7a50 --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/read_sockaddr.rs @@ -0,0 +1,306 @@ +//! The BSD sockets API requires us to read the `ss_family` field before we can +//! interpret the rest of a `sockaddr` produced by the kernel. + +#[cfg(unix)] +use super::addr::SocketAddrUnix; +use super::ext::{in6_addr_s6_addr, in_addr_s_addr, sockaddr_in6_sin6_scope_id}; +use crate::backend::c; +#[cfg(not(windows))] +use crate::ffi::CStr; +use crate::io; +use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use core::mem::size_of; + +// This must match the header of `sockaddr`. +#[repr(C)] +struct sockaddr_header { +    #[cfg(any( +        bsd, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "nto", +        target_os = "vita" +    ))] +    sa_len: u8, +    #[cfg(any( +        bsd, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "nto", +        target_os = "vita" +    ))] +    ss_family: u8, +    #[cfg(not(any( +        bsd, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "nto", +        target_os = "vita" +    )))] +    ss_family: u16, +} + +/// Read the `ss_family` field from a socket address returned from the OS. +/// +/// # Safety +/// +/// `storage` must point to a valid socket address returned from the OS. +#[inline] +unsafe fn read_ss_family(storage: *const c::sockaddr_storage) -> u16 { +    // Assert that we know the layout of `sockaddr`. +    let _ = c::sockaddr { +        #[cfg(any( +            bsd, +            target_os = "aix", +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita" +        ))] +        sa_len: 0_u8, +        #[cfg(any( +            bsd, +            target_os = "aix", +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita" +        ))] +        sa_family: 0_u8, +        #[cfg(not(any( +            bsd, +            target_os = "aix", +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita" +        )))] +        sa_family: 0_u16, +        #[cfg(not(target_os = "haiku"))] +        sa_data: [0; 14], +        #[cfg(target_os = "haiku")] +        sa_data: [0; 30], +    }; + +    (*storage.cast::<sockaddr_header>()).ss_family.into() +} + +/// Set the `ss_family` field of a socket address to `AF_UNSPEC`, so that we +/// can test for `AF_UNSPEC` to test whether it was stored to. +pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr_storage) { +    (*storage.cast::<sockaddr_header>()).ss_family = c::AF_UNSPEC as _; +} + +/// Read a socket address encoded in a platform-specific format. +/// +/// # Safety +/// +/// `storage` must point to valid socket address storage. +pub(crate) unsafe fn read_sockaddr( +    storage: *const c::sockaddr_storage, +    len: usize, +) -> io::Result<SocketAddrAny> { +    #[cfg(unix)] +    let offsetof_sun_path = super::addr::offsetof_sun_path(); + +    if len < size_of::<c::sa_family_t>() { +        return Err(io::Errno::INVAL); +    } +    match read_ss_family(storage).into() { +        c::AF_INET => { +            if len < size_of::<c::sockaddr_in>() { +                return Err(io::Errno::INVAL); +            } +            let decode = &*storage.cast::<c::sockaddr_in>(); +            Ok(SocketAddrAny::V4(SocketAddrV4::new( +                Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))), +                u16::from_be(decode.sin_port), +            ))) +        } +        c::AF_INET6 => { +            if len < size_of::<c::sockaddr_in6>() { +                return Err(io::Errno::INVAL); +            } +            let decode = &*storage.cast::<c::sockaddr_in6>(); +            #[cfg(not(windows))] +            let s6_addr = decode.sin6_addr.s6_addr; +            #[cfg(windows)] +            let s6_addr = decode.sin6_addr.u.Byte; +            #[cfg(not(windows))] +            let sin6_scope_id = decode.sin6_scope_id; +            #[cfg(windows)] +            let sin6_scope_id = decode.Anonymous.sin6_scope_id; +            Ok(SocketAddrAny::V6(SocketAddrV6::new( +                Ipv6Addr::from(s6_addr), +                u16::from_be(decode.sin6_port), +                u32::from_be(decode.sin6_flowinfo), +                sin6_scope_id, +            ))) +        } +        #[cfg(unix)] +        c::AF_UNIX => { +            if len < offsetof_sun_path { +                return Err(io::Errno::INVAL); +            } +            if len == offsetof_sun_path { +                SocketAddrUnix::new(&[][..]).map(SocketAddrAny::Unix) +            } else { +                let decode = &*storage.cast::<c::sockaddr_un>(); + +                // On Linux check for Linux's [abstract namespace]. +                // +                // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html +                #[cfg(linux_kernel)] +                if decode.sun_path[0] == 0 { +                    return SocketAddrUnix::new_abstract_name(core::mem::transmute::< +                        &[c::c_char], +                        &[u8], +                    >( +                        &decode.sun_path[1..len - offsetof_sun_path], +                    )) +                    .map(SocketAddrAny::Unix); +                } + +                // Otherwise we expect a NUL-terminated filesystem path. + +                // Trim off unused bytes from the end of `path_bytes`. +                let path_bytes = if cfg!(any(solarish, target_os = "freebsd")) { +                    // FreeBSD and illumos sometimes set the length to longer +                    // than the length of the NUL-terminated string. Find the +                    // NUL and truncate the string accordingly. +                    &decode.sun_path[..decode +                        .sun_path +                        .iter() +                        .position(|b| *b == 0) +                        .ok_or(io::Errno::INVAL)?] +                } else { +                    // Otherwise, use the provided length. +                    let provided_len = len - 1 - offsetof_sun_path; +                    if decode.sun_path[provided_len] != 0 { +                        return Err(io::Errno::INVAL); +                    } +                    debug_assert_eq!( +                        CStr::from_ptr(decode.sun_path.as_ptr()).to_bytes().len(), +                        provided_len +                    ); +                    &decode.sun_path[..provided_len] +                }; + +                SocketAddrUnix::new(core::mem::transmute::<&[c::c_char], &[u8]>(path_bytes)) +                    .map(SocketAddrAny::Unix) +            } +        } +        _ => Err(io::Errno::INVAL), +    } +} + +/// Read an optional socket address returned from the OS. +/// +/// # Safety +/// +/// `storage` must point to a valid socket address returned from the OS. +pub(crate) unsafe fn maybe_read_sockaddr_os( +    storage: *const c::sockaddr_storage, +    len: usize, +) -> Option<SocketAddrAny> { +    if len == 0 { +        return None; +    } + +    assert!(len >= size_of::<c::sa_family_t>()); +    let family = read_ss_family(storage).into(); +    if family == c::AF_UNSPEC { +        None +    } else { +        Some(inner_read_sockaddr_os(family, storage, len)) +    } +} + +/// Read a socket address returned from the OS. +/// +/// # Safety +/// +/// `storage` must point to a valid socket address returned from the OS. +pub(crate) unsafe fn read_sockaddr_os( +    storage: *const c::sockaddr_storage, +    len: usize, +) -> SocketAddrAny { +    assert!(len >= size_of::<c::sa_family_t>()); +    let family = read_ss_family(storage).into(); +    inner_read_sockaddr_os(family, storage, len) +} + +unsafe fn inner_read_sockaddr_os( +    family: c::c_int, +    storage: *const c::sockaddr_storage, +    len: usize, +) -> SocketAddrAny { +    #[cfg(unix)] +    let offsetof_sun_path = super::addr::offsetof_sun_path(); + +    assert!(len >= size_of::<c::sa_family_t>()); +    match family { +        c::AF_INET => { +            assert!(len >= size_of::<c::sockaddr_in>()); +            let decode = &*storage.cast::<c::sockaddr_in>(); +            SocketAddrAny::V4(SocketAddrV4::new( +                Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))), +                u16::from_be(decode.sin_port), +            )) +        } +        c::AF_INET6 => { +            assert!(len >= size_of::<c::sockaddr_in6>()); +            let decode = &*storage.cast::<c::sockaddr_in6>(); +            SocketAddrAny::V6(SocketAddrV6::new( +                Ipv6Addr::from(in6_addr_s6_addr(decode.sin6_addr)), +                u16::from_be(decode.sin6_port), +                u32::from_be(decode.sin6_flowinfo), +                sockaddr_in6_sin6_scope_id(decode), +            )) +        } +        #[cfg(unix)] +        c::AF_UNIX => { +            assert!(len >= offsetof_sun_path); +            if len == offsetof_sun_path { +                SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap()) +            } else { +                let decode = &*storage.cast::<c::sockaddr_un>(); + +                // On Linux check for Linux's [abstract namespace]. +                // +                // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html +                #[cfg(linux_kernel)] +                if decode.sun_path[0] == 0 { +                    return SocketAddrAny::Unix( +                        SocketAddrUnix::new_abstract_name(core::mem::transmute::< +                            &[c::c_char], +                            &[u8], +                        >( +                            &decode.sun_path[1..len - offsetof_sun_path], +                        )) +                        .unwrap(), +                    ); +                } + +                // Otherwise we expect a NUL-terminated filesystem path. +                assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0); +                let path_bytes = &decode.sun_path[..len - 1 - offsetof_sun_path]; + +                // FreeBSD and illumos sometimes set the length to longer than +                // the length of the NUL-terminated string. Find the NUL and +                // truncate the string accordingly. +                #[cfg(any(solarish, target_os = "freebsd"))] +                let path_bytes = &path_bytes[..path_bytes.iter().position(|b| *b == 0).unwrap()]; + +                SocketAddrAny::Unix( +                    SocketAddrUnix::new(core::mem::transmute::<&[c::c_char], &[u8]>(path_bytes)) +                        .unwrap(), +                ) +            } +        } +        other => unimplemented!("{:?}", other), +    } +} diff --git a/vendor/rustix/src/backend/libc/net/send_recv.rs b/vendor/rustix/src/backend/libc/net/send_recv.rs new file mode 100644 index 0000000..5dc60dd --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/send_recv.rs @@ -0,0 +1,103 @@ +use crate::backend::c; +use bitflags::bitflags; + +bitflags! { +    /// `MSG_*` flags for use with [`send`], [`send_to`], and related +    /// functions. +    /// +    /// [`send`]: crate::net::send +    /// [`sendto`]: crate::net::sendto +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct SendFlags: u32 { +        /// `MSG_CONFIRM` +        #[cfg(not(any( +            bsd, +            solarish, +            windows, +            target_os = "aix", +            target_os = "espidf", +            target_os = "nto", +            target_os = "haiku", +            target_os = "vita", +        )))] +        const CONFIRM = bitcast!(c::MSG_CONFIRM); +        /// `MSG_DONTROUTE` +        const DONTROUTE = bitcast!(c::MSG_DONTROUTE); +        /// `MSG_DONTWAIT` +        #[cfg(not(windows))] +        const DONTWAIT = bitcast!(c::MSG_DONTWAIT); +        /// `MSG_EOR` +        #[cfg(not(windows))] +        const EOT = bitcast!(c::MSG_EOR); +        /// `MSG_MORE` +        #[cfg(not(any( +            bsd, +            solarish, +            windows, +            target_os = "aix", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita", +        )))] +        const MORE = bitcast!(c::MSG_MORE); +        #[cfg(not(any(apple, windows, target_os = "vita")))] +        /// `MSG_NOSIGNAL` +        const NOSIGNAL = bitcast!(c::MSG_NOSIGNAL); +        /// `MSG_OOB` +        const OOB = bitcast!(c::MSG_OOB); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +bitflags! { +    /// `MSG_*` flags for use with [`recv`], [`recvfrom`], and related +    /// functions. +    /// +    /// [`recv`]: crate::net::recv +    /// [`recvfrom`]: crate::net::recvfrom +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct RecvFlags: u32 { +        #[cfg(not(any( +            apple, +            solarish, +            windows, +            target_os = "aix", +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita", +        )))] +        /// `MSG_CMSG_CLOEXEC` +        const CMSG_CLOEXEC = bitcast!(c::MSG_CMSG_CLOEXEC); +        /// `MSG_DONTWAIT` +        #[cfg(not(windows))] +        const DONTWAIT = bitcast!(c::MSG_DONTWAIT); +        /// `MSG_ERRQUEUE` +        #[cfg(not(any( +            bsd, +            solarish, +            windows, +            target_os = "aix", +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita", +        )))] +        const ERRQUEUE = bitcast!(c::MSG_ERRQUEUE); +        /// `MSG_OOB` +        const OOB = bitcast!(c::MSG_OOB); +        /// `MSG_PEEK` +        const PEEK = bitcast!(c::MSG_PEEK); +        /// `MSG_TRUNC` +        const TRUNC = bitcast!(c::MSG_TRUNC); +        /// `MSG_WAITALL` +        const WAITALL = bitcast!(c::MSG_WAITALL); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} diff --git a/vendor/rustix/src/backend/libc/net/sockopt.rs b/vendor/rustix/src/backend/libc/net/sockopt.rs new file mode 100644 index 0000000..cff2ca2 --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/sockopt.rs @@ -0,0 +1,1065 @@ +//! libc syscalls supporting `rustix::net::sockopt`. + +use super::ext::{in6_addr_new, in_addr_new}; +use crate::backend::c; +use crate::backend::conv::{borrowed_fd, ret}; +use crate::fd::BorrowedFd; +#[cfg(feature = "alloc")] +#[cfg(any( +    linux_like, +    target_os = "freebsd", +    target_os = "fuchsia", +    target_os = "illumos" +))] +use crate::ffi::CStr; +use crate::io; +use crate::net::sockopt::Timeout; +#[cfg(not(any( +    apple, +    windows, +    target_os = "aix", +    target_os = "dragonfly", +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "netbsd", +    target_os = "nto", +    target_os = "vita", +)))] +use crate::net::AddressFamily; +#[cfg(any( +    linux_kernel, +    target_os = "freebsd", +    target_os = "fuchsia", +    target_os = "openbsd", +    target_os = "redox", +    target_env = "newlib" +))] +use crate::net::Protocol; +#[cfg(any( +    linux_kernel, +    target_os = "freebsd", +    target_os = "fuchsia", +    target_os = "openbsd", +    target_os = "redox", +    target_env = "newlib" +))] +use crate::net::RawProtocol; +use crate::net::{Ipv4Addr, Ipv6Addr, SocketType}; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +use crate::net::{SocketAddrAny, SocketAddrStorage, SocketAddrV4}; +#[cfg(linux_kernel)] +use crate::net::{SocketAddrV6, UCred}; +use crate::utils::as_mut_ptr; +#[cfg(feature = "alloc")] +#[cfg(any( +    linux_like, +    target_os = "freebsd", +    target_os = "fuchsia", +    target_os = "illumos" +))] +use alloc::borrow::ToOwned; +#[cfg(feature = "alloc")] +#[cfg(any( +    linux_like, +    target_os = "freebsd", +    target_os = "fuchsia", +    target_os = "illumos" +))] +use alloc::string::String; +#[cfg(apple)] +use c::TCP_KEEPALIVE as TCP_KEEPIDLE; +#[cfg(not(any(apple, target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +use c::TCP_KEEPIDLE; +use core::mem::{size_of, MaybeUninit}; +use core::time::Duration; +#[cfg(windows)] +use windows_sys::Win32::Foundation::BOOL; + +#[inline] +fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: i32, optname: i32) -> io::Result<T> { +    let mut optlen = core::mem::size_of::<T>().try_into().unwrap(); +    debug_assert!( +        optlen as usize >= core::mem::size_of::<c::c_int>(), +        "Socket APIs don't ever use `bool` directly" +    ); + +    let mut value = MaybeUninit::<T>::zeroed(); +    getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?; + +    // On Windows at least, `getsockopt` has been observed writing 1 +    // byte on at least (`IPPROTO_TCP`, `TCP_NODELAY`), even though +    // Windows' documentation says that should write a 4-byte `BOOL`. +    // So, we initialize the memory to zeros above, and just assert +    // that `getsockopt` doesn't write too many bytes here. +    assert!( +        optlen as usize <= size_of::<T>(), +        "unexpected getsockopt size" +    ); + +    unsafe { Ok(value.assume_init()) } +} + +#[inline] +fn getsockopt_raw<T>( +    fd: BorrowedFd<'_>, +    level: i32, +    optname: i32, +    value: &mut MaybeUninit<T>, +    optlen: &mut c::socklen_t, +) -> io::Result<()> { +    unsafe { +        ret(c::getsockopt( +            borrowed_fd(fd), +            level, +            optname, +            as_mut_ptr(value).cast(), +            optlen, +        )) +    } +} + +#[inline] +fn setsockopt<T: Copy>(fd: BorrowedFd<'_>, level: i32, optname: i32, value: T) -> io::Result<()> { +    let optlen = core::mem::size_of::<T>().try_into().unwrap(); +    debug_assert!( +        optlen as usize >= core::mem::size_of::<c::c_int>(), +        "Socket APIs don't ever use `bool` directly" +    ); +    setsockopt_raw(fd, level, optname, &value, optlen) +} + +#[inline] +fn setsockopt_raw<T>( +    fd: BorrowedFd<'_>, +    level: i32, +    optname: i32, +    ptr: *const T, +    optlen: c::socklen_t, +) -> io::Result<()> { +    unsafe { +        ret(c::setsockopt( +            borrowed_fd(fd), +            level, +            optname, +            ptr.cast(), +            optlen, +        )) +    } +} + +#[inline] +pub(crate) fn get_socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_TYPE) +} + +#[inline] +pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> { +    setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR, from_bool(reuseaddr)) +} + +#[inline] +pub(crate) fn get_socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> { +    setsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST, from_bool(broadcast)) +} + +#[inline] +pub(crate) fn get_socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_linger(fd: BorrowedFd<'_>, linger: Option<Duration>) -> io::Result<()> { +    // Convert `linger` to seconds, rounding up. +    let l_linger = if let Some(linger) = linger { +        duration_to_secs(linger)? +    } else { +        0 +    }; +    let linger = c::linger { +        l_onoff: linger.is_some().into(), +        l_linger, +    }; +    setsockopt(fd, c::SOL_SOCKET, c::SO_LINGER, linger) +} + +#[inline] +pub(crate) fn get_socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> { +    let linger: c::linger = getsockopt(fd, c::SOL_SOCKET, c::SO_LINGER)?; +    Ok((linger.l_onoff != 0).then(|| Duration::from_secs(linger.l_linger as u64))) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> { +    setsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED, from_bool(passcred)) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn get_socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_timeout( +    fd: BorrowedFd<'_>, +    id: Timeout, +    timeout: Option<Duration>, +) -> io::Result<()> { +    let optname = match id { +        Timeout::Recv => c::SO_RCVTIMEO, +        Timeout::Send => c::SO_SNDTIMEO, +    }; + +    #[cfg(not(windows))] +    let timeout = match timeout { +        Some(timeout) => { +            if timeout == Duration::ZERO { +                return Err(io::Errno::INVAL); +            } + +            // Rust's musl libc bindings deprecated `time_t` while they +            // transition to 64-bit `time_t`. What we want here is just +            // “whatever type `timeval`'s `tv_sec` is”, so we're ok using +            // the deprecated type. +            #[allow(deprecated)] +            let tv_sec = timeout.as_secs().try_into().unwrap_or(c::time_t::MAX); + +            // `subsec_micros` rounds down, so we use `subsec_nanos` and +            // manually round up. +            let mut timeout = c::timeval { +                tv_sec, +                tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _, +            }; +            if timeout.tv_sec == 0 && timeout.tv_usec == 0 { +                timeout.tv_usec = 1; +            } +            timeout +        } +        None => c::timeval { +            tv_sec: 0, +            tv_usec: 0, +        }, +    }; + +    #[cfg(windows)] +    let timeout: u32 = match timeout { +        Some(timeout) => { +            if timeout == Duration::ZERO { +                return Err(io::Errno::INVAL); +            } + +            // `as_millis` rounds down, so we use `as_nanos` and +            // manually round up. +            let mut timeout: u32 = ((timeout.as_nanos() + 999_999) / 1_000_000) +                .try_into() +                .map_err(|_convert_err| io::Errno::INVAL)?; +            if timeout == 0 { +                timeout = 1; +            } +            timeout +        } +        None => 0, +    }; + +    setsockopt(fd, c::SOL_SOCKET, optname, timeout) +} + +#[inline] +pub(crate) fn get_socket_timeout(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> { +    let optname = match id { +        Timeout::Recv => c::SO_RCVTIMEO, +        Timeout::Send => c::SO_SNDTIMEO, +    }; + +    #[cfg(not(windows))] +    { +        let timeout: c::timeval = getsockopt(fd, c::SOL_SOCKET, optname)?; +        if timeout.tv_sec == 0 && timeout.tv_usec == 0 { +            Ok(None) +        } else { +            Ok(Some( +                Duration::from_secs(timeout.tv_sec as u64) +                    + Duration::from_micros(timeout.tv_usec as u64), +            )) +        } +    } + +    #[cfg(windows)] +    { +        let timeout: u32 = getsockopt(fd, c::SOL_SOCKET, optname)?; +        if timeout == 0 { +            Ok(None) +        } else { +            Ok(Some(Duration::from_millis(timeout as u64))) +        } +    } +} + +#[cfg(any(apple, freebsdlike, target_os = "netbsd"))] +#[inline] +pub(crate) fn get_socket_nosigpipe(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_NOSIGPIPE).map(to_bool) +} + +#[cfg(any(apple, freebsdlike, target_os = "netbsd"))] +#[inline] +pub(crate) fn set_socket_nosigpipe(fd: BorrowedFd<'_>, val: bool) -> io::Result<()> { +    setsockopt(fd, c::SOL_SOCKET, c::SO_NOSIGPIPE, from_bool(val)) +} + +#[inline] +pub(crate) fn get_socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> { +    let err: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_ERROR)?; +    Ok(if err == 0 { +        Ok(()) +    } else { +        Err(io::Errno::from_raw_os_error(err)) +    }) +} + +#[inline] +pub(crate) fn set_socket_keepalive(fd: BorrowedFd<'_>, keepalive: bool) -> io::Result<()> { +    setsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE, from_bool(keepalive)) +} + +#[inline] +pub(crate) fn get_socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_recv_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> { +    let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?; +    setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF, size) +} + +#[inline] +pub(crate) fn get_socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF).map(|size: u32| size as usize) +} + +#[inline] +pub(crate) fn set_socket_send_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> { +    let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?; +    setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF, size) +} + +#[inline] +pub(crate) fn get_socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF).map(|size: u32| size as usize) +} + +#[inline] +#[cfg(not(any( +    apple, +    windows, +    target_os = "aix", +    target_os = "dragonfly", +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "netbsd", +    target_os = "nto", +    target_os = "vita", +)))] +pub(crate) fn get_socket_domain(fd: BorrowedFd<'_>) -> io::Result<AddressFamily> { +    let domain: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_DOMAIN)?; +    Ok(AddressFamily( +        domain.try_into().map_err(|_| io::Errno::OPNOTSUPP)?, +    )) +} + +#[inline] +#[cfg(not(apple))] // Apple platforms declare the constant, but do not actually implement it. +pub(crate) fn get_socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_ACCEPTCONN).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_oobinline(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE, from_bool(value)) +} + +#[inline] +pub(crate) fn get_socket_oobinline(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE).map(to_bool) +} + +#[cfg(not(any(solarish, windows)))] +#[inline] +pub(crate) fn set_socket_reuseport(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT, from_bool(value)) +} + +#[cfg(not(any(solarish, windows)))] +#[inline] +pub(crate) fn get_socket_reuseport(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT).map(to_bool) +} + +#[cfg(target_os = "freebsd")] +#[inline] +pub(crate) fn set_socket_reuseport_lb(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT_LB, from_bool(value)) +} + +#[cfg(target_os = "freebsd")] +#[inline] +pub(crate) fn get_socket_reuseport_lb(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT_LB).map(to_bool) +} + +#[cfg(any( +    linux_kernel, +    target_os = "freebsd", +    target_os = "fuchsia", +    target_os = "openbsd", +    target_os = "redox", +    target_env = "newlib" +))] +#[inline] +pub(crate) fn get_socket_protocol(fd: BorrowedFd<'_>) -> io::Result<Option<Protocol>> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_PROTOCOL) +        .map(|raw| RawProtocol::new(raw).map(Protocol::from_raw)) +} + +#[cfg(target_os = "linux")] +#[inline] +pub(crate) fn get_socket_cookie(fd: BorrowedFd<'_>) -> io::Result<u64> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_COOKIE) +} + +#[cfg(target_os = "linux")] +#[inline] +pub(crate) fn get_socket_incoming_cpu(fd: BorrowedFd<'_>) -> io::Result<u32> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU) +} + +#[cfg(target_os = "linux")] +#[inline] +pub(crate) fn set_socket_incoming_cpu(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { +    setsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU, value) +} + +#[inline] +pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IP, c::IP_TTL, ttl) +} + +#[inline] +pub(crate) fn get_ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { +    getsockopt(fd, c::IPPROTO_IP, c::IP_TTL) +} + +#[inline] +pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY, from_bool(only_v6)) +} + +#[inline] +pub(crate) fn get_ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY).map(to_bool) +} + +#[inline] +pub(crate) fn set_ip_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> { +    setsockopt( +        fd, +        c::IPPROTO_IP, +        c::IP_MULTICAST_LOOP, +        from_bool(multicast_loop), +    ) +} + +#[inline] +pub(crate) fn get_ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_LOOP).map(to_bool) +} + +#[inline] +pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl) +} + +#[inline] +pub(crate) fn get_ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { +    getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL) +} + +#[inline] +pub(crate) fn set_ipv6_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> { +    setsockopt( +        fd, +        c::IPPROTO_IPV6, +        c::IPV6_MULTICAST_LOOP, +        from_bool(multicast_loop), +    ) +} + +#[inline] +pub(crate) fn get_ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP).map(to_bool) +} + +#[inline] +pub(crate) fn set_ipv6_multicast_hops(fd: BorrowedFd<'_>, multicast_hops: u32) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS, multicast_hops) +} + +#[inline] +pub(crate) fn get_ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> { +    getsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS) +} + +#[inline] +pub(crate) fn set_ip_add_membership( +    fd: BorrowedFd<'_>, +    multiaddr: &Ipv4Addr, +    interface: &Ipv4Addr, +) -> io::Result<()> { +    let mreq = to_ip_mreq(multiaddr, interface); +    setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) +} + +#[cfg(any( +    apple, +    freebsdlike, +    linux_like, +    target_os = "fuchsia", +    target_os = "openbsd" +))] +#[inline] +pub(crate) fn set_ip_add_membership_with_ifindex( +    fd: BorrowedFd<'_>, +    multiaddr: &Ipv4Addr, +    address: &Ipv4Addr, +    ifindex: i32, +) -> io::Result<()> { +    let mreqn = to_ip_mreqn(multiaddr, address, ifindex); +    setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreqn) +} + +#[cfg(any(apple, freebsdlike, linux_like, solarish, target_os = "aix"))] +#[inline] +pub(crate) fn set_ip_add_source_membership( +    fd: BorrowedFd<'_>, +    multiaddr: &Ipv4Addr, +    interface: &Ipv4Addr, +    sourceaddr: &Ipv4Addr, +) -> io::Result<()> { +    let mreq_source = to_imr_source(multiaddr, interface, sourceaddr); +    setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_SOURCE_MEMBERSHIP, mreq_source) +} + +#[cfg(any(apple, freebsdlike, linux_like, solarish, target_os = "aix"))] +#[inline] +pub(crate) fn set_ip_drop_source_membership( +    fd: BorrowedFd<'_>, +    multiaddr: &Ipv4Addr, +    interface: &Ipv4Addr, +    sourceaddr: &Ipv4Addr, +) -> io::Result<()> { +    let mreq_source = to_imr_source(multiaddr, interface, sourceaddr); +    setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_SOURCE_MEMBERSHIP, mreq_source) +} + +#[inline] +pub(crate) fn set_ipv6_add_membership( +    fd: BorrowedFd<'_>, +    multiaddr: &Ipv6Addr, +    interface: u32, +) -> io::Result<()> { +    #[cfg(not(any( +        bsd, +        solarish, +        target_os = "haiku", +        target_os = "l4re", +        target_os = "nto" +    )))] +    use c::IPV6_ADD_MEMBERSHIP; +    #[cfg(any( +        bsd, +        solarish, +        target_os = "haiku", +        target_os = "l4re", +        target_os = "nto" +    ))] +    use c::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; + +    let mreq = to_ipv6mr(multiaddr, interface); +    setsockopt(fd, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) +} + +#[inline] +pub(crate) fn set_ip_drop_membership( +    fd: BorrowedFd<'_>, +    multiaddr: &Ipv4Addr, +    interface: &Ipv4Addr, +) -> io::Result<()> { +    let mreq = to_ip_mreq(multiaddr, interface); +    setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) +} + +#[cfg(any( +    apple, +    freebsdlike, +    linux_like, +    target_os = "fuchsia", +    target_os = "openbsd" +))] +#[inline] +pub(crate) fn set_ip_drop_membership_with_ifindex( +    fd: BorrowedFd<'_>, +    multiaddr: &Ipv4Addr, +    address: &Ipv4Addr, +    ifindex: i32, +) -> io::Result<()> { +    let mreqn = to_ip_mreqn(multiaddr, address, ifindex); +    setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreqn) +} + +#[inline] +pub(crate) fn set_ipv6_drop_membership( +    fd: BorrowedFd<'_>, +    multiaddr: &Ipv6Addr, +    interface: u32, +) -> io::Result<()> { +    #[cfg(not(any( +        bsd, +        solarish, +        target_os = "haiku", +        target_os = "l4re", +        target_os = "nto" +    )))] +    use c::IPV6_DROP_MEMBERSHIP; +    #[cfg(any( +        bsd, +        solarish, +        target_os = "haiku", +        target_os = "l4re", +        target_os = "nto" +    ))] +    use c::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; + +    let mreq = to_ipv6mr(multiaddr, interface); +    setsockopt(fd, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) +} + +#[inline] +pub(crate) fn get_ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> { +    getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS).map(|hops: c::c_int| hops as u8) +} + +#[inline] +pub(crate) fn set_ipv6_unicast_hops(fd: BorrowedFd<'_>, hops: Option<u8>) -> io::Result<()> { +    let hops = match hops { +        Some(hops) => hops as c::c_int, +        None => -1, +    }; +    setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, hops) +} + +#[cfg(any( +    bsd, +    linux_like, +    target_os = "aix", +    target_os = "fuchsia", +    target_os = "haiku", +    target_os = "nto", +    target_env = "newlib" +))] +#[inline] +pub(crate) fn set_ip_tos(fd: BorrowedFd<'_>, value: u8) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IP, c::IP_TOS, i32::from(value)) +} + +#[cfg(any( +    bsd, +    linux_like, +    target_os = "aix", +    target_os = "fuchsia", +    target_os = "haiku", +    target_os = "nto", +    target_env = "newlib" +))] +#[inline] +pub(crate) fn get_ip_tos(fd: BorrowedFd<'_>) -> io::Result<u8> { +    let value: i32 = getsockopt(fd, c::IPPROTO_IP, c::IP_TOS)?; +    Ok(value as u8) +} + +#[cfg(any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_ip_recvtos(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS, from_bool(value)) +} + +#[cfg(any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_ip_recvtos(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS).map(to_bool) +} + +#[cfg(any( +    bsd, +    linux_like, +    target_os = "aix", +    target_os = "fuchsia", +    target_os = "nto" +))] +#[inline] +pub(crate) fn set_ipv6_recvtclass(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS, from_bool(value)) +} + +#[cfg(any( +    bsd, +    linux_like, +    target_os = "aix", +    target_os = "fuchsia", +    target_os = "nto" +))] +#[inline] +pub(crate) fn get_ipv6_recvtclass(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS).map(to_bool) +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_ip_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND, from_bool(value)) +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_ip_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND).map(to_bool) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn set_ipv6_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND, from_bool(value)) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn get_ipv6_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND).map(to_bool) +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_ip_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV4> { +    let level = c::IPPROTO_IP; +    let optname = c::SO_ORIGINAL_DST; +    let mut value = MaybeUninit::<SocketAddrStorage>::uninit(); +    let mut optlen = core::mem::size_of_val(&value).try_into().unwrap(); + +    getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?; + +    let any = unsafe { SocketAddrAny::read(value.as_ptr(), optlen as usize)? }; +    match any { +        SocketAddrAny::V4(v4) => Ok(v4), +        _ => unreachable!(), +    } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn get_ipv6_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV6> { +    let level = c::IPPROTO_IPV6; +    let optname = c::IP6T_SO_ORIGINAL_DST; +    let mut value = MaybeUninit::<SocketAddrStorage>::uninit(); +    let mut optlen = core::mem::size_of_val(&value).try_into().unwrap(); + +    getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?; + +    let any = unsafe { SocketAddrAny::read(value.as_ptr(), optlen as usize)? }; +    match any { +        SocketAddrAny::V6(v6) => Ok(v6), +        _ => unreachable!(), +    } +} + +#[cfg(not(any( +    solarish, +    windows, +    target_os = "espidf", +    target_os = "haiku", +    target_os = "vita" +)))] +#[inline] +pub(crate) fn set_ipv6_tclass(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS, value) +} + +#[cfg(not(any( +    solarish, +    windows, +    target_os = "espidf", +    target_os = "haiku", +    target_os = "vita" +)))] +#[inline] +pub(crate) fn get_ipv6_tclass(fd: BorrowedFd<'_>) -> io::Result<u32> { +    getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS) +} + +#[inline] +pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY, from_bool(nodelay)) +} + +#[inline] +pub(crate) fn get_tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY).map(to_bool) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT, count) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn get_tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> { +    getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> { +    let secs: c::c_uint = duration_to_secs(duration)?; +    setsockopt(fd, c::IPPROTO_TCP, TCP_KEEPIDLE, secs) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn get_tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> { +    let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, TCP_KEEPIDLE)?; +    Ok(Duration::from_secs(secs as u64)) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> { +    let secs: c::c_uint = duration_to_secs(duration)?; +    setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL, secs) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn get_tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> { +    let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL)?; +    Ok(Duration::from_secs(secs as u64)) +} + +#[inline] +#[cfg(any(linux_like, target_os = "fuchsia"))] +pub(crate) fn set_tcp_user_timeout(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT, value) +} + +#[inline] +#[cfg(any(linux_like, target_os = "fuchsia"))] +pub(crate) fn get_tcp_user_timeout(fd: BorrowedFd<'_>) -> io::Result<u32> { +    getsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT) +} + +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_tcp_quickack(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK, from_bool(value)) +} + +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_tcp_quickack(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK).map(to_bool) +} + +#[cfg(any( +    linux_like, +    target_os = "freebsd", +    target_os = "fuchsia", +    target_os = "illumos" +))] +#[inline] +pub(crate) fn set_tcp_congestion(fd: BorrowedFd<'_>, value: &str) -> io::Result<()> { +    let level = c::IPPROTO_TCP; +    let optname = c::TCP_CONGESTION; +    let optlen = value.len().try_into().unwrap(); +    setsockopt_raw(fd, level, optname, value.as_ptr(), optlen) +} + +#[cfg(feature = "alloc")] +#[cfg(any( +    linux_like, +    target_os = "freebsd", +    target_os = "fuchsia", +    target_os = "illumos" +))] +#[inline] +pub(crate) fn get_tcp_congestion(fd: BorrowedFd<'_>) -> io::Result<String> { +    let level = c::IPPROTO_TCP; +    let optname = c::TCP_CONGESTION; +    const OPTLEN: c::socklen_t = 16; +    let mut value = MaybeUninit::<[MaybeUninit<u8>; OPTLEN as usize]>::uninit(); +    let mut optlen = OPTLEN; +    getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?; +    unsafe { +        let value = value.assume_init(); +        let slice: &[u8] = core::mem::transmute(&value[..optlen as usize]); +        assert!(slice.iter().any(|b| *b == b'\0')); +        Ok( +            core::str::from_utf8(CStr::from_ptr(slice.as_ptr().cast()).to_bytes()) +                .unwrap() +                .to_owned(), +        ) +    } +} + +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_tcp_thin_linear_timeouts(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt( +        fd, +        c::IPPROTO_TCP, +        c::TCP_THIN_LINEAR_TIMEOUTS, +        from_bool(value), +    ) +} + +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_tcp_thin_linear_timeouts(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_TCP, c::TCP_THIN_LINEAR_TIMEOUTS).map(to_bool) +} + +#[cfg(any(linux_like, solarish, target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_tcp_cork(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { +    setsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK, from_bool(value)) +} + +#[cfg(any(linux_like, solarish, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_tcp_cork(fd: BorrowedFd<'_>) -> io::Result<bool> { +    getsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK).map(to_bool) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn get_socket_peercred(fd: BorrowedFd<'_>) -> io::Result<UCred> { +    getsockopt(fd, c::SOL_SOCKET, c::SO_PEERCRED) +} + +#[inline] +fn to_ip_mreq(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq { +    c::ip_mreq { +        imr_multiaddr: to_imr_addr(multiaddr), +        imr_interface: to_imr_addr(interface), +    } +} + +#[cfg(any( +    apple, +    freebsdlike, +    linux_like, +    target_os = "fuchsia", +    target_os = "openbsd" +))] +#[inline] +fn to_ip_mreqn(multiaddr: &Ipv4Addr, address: &Ipv4Addr, ifindex: i32) -> c::ip_mreqn { +    c::ip_mreqn { +        imr_multiaddr: to_imr_addr(multiaddr), +        imr_address: to_imr_addr(address), +        imr_ifindex: ifindex, +    } +} + +#[cfg(any(apple, freebsdlike, linux_like, solarish, target_os = "aix"))] +#[inline] +fn to_imr_source( +    multiaddr: &Ipv4Addr, +    interface: &Ipv4Addr, +    sourceaddr: &Ipv4Addr, +) -> c::ip_mreq_source { +    c::ip_mreq_source { +        imr_multiaddr: to_imr_addr(multiaddr), +        imr_interface: to_imr_addr(interface), +        imr_sourceaddr: to_imr_addr(sourceaddr), +    } +} + +#[inline] +fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr { +    in_addr_new(u32::from_ne_bytes(addr.octets())) +} + +#[inline] +fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq { +    c::ipv6_mreq { +        ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr), +        ipv6mr_interface: to_ipv6mr_interface(interface), +    } +} + +#[inline] +fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr { +    in6_addr_new(multiaddr.octets()) +} + +#[cfg(target_os = "android")] +#[inline] +fn to_ipv6mr_interface(interface: u32) -> c::c_int { +    interface as c::c_int +} + +#[cfg(not(target_os = "android"))] +#[inline] +fn to_ipv6mr_interface(interface: u32) -> c::c_uint { +    interface as c::c_uint +} + +// `getsockopt` and `setsockopt` represent boolean values as integers. +#[cfg(not(windows))] +type RawSocketBool = c::c_int; +#[cfg(windows)] +type RawSocketBool = BOOL; + +// Wrap `RawSocketBool` in a newtype to discourage misuse. +#[repr(transparent)] +#[derive(Copy, Clone)] +struct SocketBool(RawSocketBool); + +// Convert from a `bool` to a `SocketBool`. +#[inline] +fn from_bool(value: bool) -> SocketBool { +    SocketBool(value.into()) +} + +// Convert from a `SocketBool` to a `bool`. +#[inline] +fn to_bool(value: SocketBool) -> bool { +    value.0 != 0 +} + +/// Convert to seconds, rounding up if necessary. +#[inline] +fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> { +    let mut secs = duration.as_secs(); +    if duration.subsec_nanos() != 0 { +        secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?; +    } +    T::try_from(secs).map_err(|_e| io::Errno::INVAL) +} diff --git a/vendor/rustix/src/backend/libc/net/syscalls.rs b/vendor/rustix/src/backend/libc/net/syscalls.rs new file mode 100644 index 0000000..48dbf1f --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/syscalls.rs @@ -0,0 +1,568 @@ +//! libc syscalls supporting `rustix::net`. + +#[cfg(unix)] +use super::addr::SocketAddrUnix; +use crate::backend::c; +use crate::backend::conv::{borrowed_fd, ret, ret_owned_fd, ret_send_recv, send_recv_len}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use crate::utils::as_ptr; +use core::mem::{size_of, MaybeUninit}; +#[cfg(not(any( +    windows, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +use { +    super::msghdr::{with_noaddr_msghdr, with_recv_msghdr, with_v4_msghdr, with_v6_msghdr}, +    crate::io::{IoSlice, IoSliceMut}, +    crate::net::{RecvAncillaryBuffer, RecvMsgReturn, SendAncillaryBuffer}, +}; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +use { +    super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os}, +    super::send_recv::{RecvFlags, SendFlags}, +    super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}, +    crate::net::{AddressFamily, Protocol, Shutdown, SocketFlags, SocketType}, +    core::ptr::null_mut, +}; + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) unsafe fn recv( +    fd: BorrowedFd<'_>, +    buf: *mut u8, +    len: usize, +    flags: RecvFlags, +) -> io::Result<usize> { +    ret_send_recv(c::recv( +        borrowed_fd(fd), +        buf.cast(), +        send_recv_len(len), +        bitflags_bits!(flags), +    )) +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn send(fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags) -> io::Result<usize> { +    unsafe { +        ret_send_recv(c::send( +            borrowed_fd(fd), +            buf.as_ptr().cast(), +            send_recv_len(buf.len()), +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) unsafe fn recvfrom( +    fd: BorrowedFd<'_>, +    buf: *mut u8, +    buf_len: usize, +    flags: RecvFlags, +) -> io::Result<(usize, Option<SocketAddrAny>)> { +    let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); +    let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; + +    // `recvfrom` does not write to the storage if the socket is +    // connection-oriented sockets, so we initialize the family field to +    // `AF_UNSPEC` so that we can detect this case. +    initialize_family_to_unspec(storage.as_mut_ptr()); + +    ret_send_recv(c::recvfrom( +        borrowed_fd(fd), +        buf.cast(), +        send_recv_len(buf_len), +        bitflags_bits!(flags), +        storage.as_mut_ptr().cast(), +        &mut len, +    )) +    .map(|nread| { +        ( +            nread, +            maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()), +        ) +    }) +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn sendto_v4( +    fd: BorrowedFd<'_>, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddrV4, +) -> io::Result<usize> { +    unsafe { +        ret_send_recv(c::sendto( +            borrowed_fd(fd), +            buf.as_ptr().cast(), +            send_recv_len(buf.len()), +            bitflags_bits!(flags), +            as_ptr(&encode_sockaddr_v4(addr)).cast::<c::sockaddr>(), +            size_of::<c::sockaddr_in>() as c::socklen_t, +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn sendto_v6( +    fd: BorrowedFd<'_>, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddrV6, +) -> io::Result<usize> { +    unsafe { +        ret_send_recv(c::sendto( +            borrowed_fd(fd), +            buf.as_ptr().cast(), +            send_recv_len(buf.len()), +            bitflags_bits!(flags), +            as_ptr(&encode_sockaddr_v6(addr)).cast::<c::sockaddr>(), +            size_of::<c::sockaddr_in6>() as c::socklen_t, +        )) +    } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn sendto_unix( +    fd: BorrowedFd<'_>, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddrUnix, +) -> io::Result<usize> { +    unsafe { +        ret_send_recv(c::sendto( +            borrowed_fd(fd), +            buf.as_ptr().cast(), +            send_recv_len(buf.len()), +            bitflags_bits!(flags), +            as_ptr(&addr.unix).cast(), +            addr.addr_len(), +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn socket( +    domain: AddressFamily, +    type_: SocketType, +    protocol: Option<Protocol>, +) -> io::Result<OwnedFd> { +    let raw_protocol = match protocol { +        Some(p) => p.0.get(), +        None => 0, +    }; +    unsafe { +        ret_owned_fd(c::socket( +            domain.0 as c::c_int, +            type_.0 as c::c_int, +            raw_protocol as c::c_int, +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn socket_with( +    domain: AddressFamily, +    type_: SocketType, +    flags: SocketFlags, +    protocol: Option<Protocol>, +) -> io::Result<OwnedFd> { +    let raw_protocol = match protocol { +        Some(p) => p.0.get(), +        None => 0, +    }; +    unsafe { +        ret_owned_fd(c::socket( +            domain.0 as c::c_int, +            (type_.0 | flags.bits()) as c::c_int, +            raw_protocol as c::c_int, +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn bind_v4(sockfd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { +    unsafe { +        ret(c::bind( +            borrowed_fd(sockfd), +            as_ptr(&encode_sockaddr_v4(addr)).cast(), +            size_of::<c::sockaddr_in>() as c::socklen_t, +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn bind_v6(sockfd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { +    unsafe { +        ret(c::bind( +            borrowed_fd(sockfd), +            as_ptr(&encode_sockaddr_v6(addr)).cast(), +            size_of::<c::sockaddr_in6>() as c::socklen_t, +        )) +    } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn bind_unix(sockfd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { +    unsafe { +        ret(c::bind( +            borrowed_fd(sockfd), +            as_ptr(&addr.unix).cast(), +            addr.addr_len(), +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn connect_v4(sockfd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { +    unsafe { +        ret(c::connect( +            borrowed_fd(sockfd), +            as_ptr(&encode_sockaddr_v4(addr)).cast(), +            size_of::<c::sockaddr_in>() as c::socklen_t, +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn connect_v6(sockfd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { +    unsafe { +        ret(c::connect( +            borrowed_fd(sockfd), +            as_ptr(&encode_sockaddr_v6(addr)).cast(), +            size_of::<c::sockaddr_in6>() as c::socklen_t, +        )) +    } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn connect_unix(sockfd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { +    unsafe { +        ret(c::connect( +            borrowed_fd(sockfd), +            as_ptr(&addr.unix).cast(), +            addr.addr_len(), +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn connect_unspec(sockfd: BorrowedFd<'_>) -> io::Result<()> { +    debug_assert_eq!(c::AF_UNSPEC, 0); +    let addr = MaybeUninit::<c::sockaddr_storage>::zeroed(); +    unsafe { +        ret(c::connect( +            borrowed_fd(sockfd), +            as_ptr(&addr).cast(), +            size_of::<c::sockaddr_storage>() as c::socklen_t, +        )) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn listen(sockfd: BorrowedFd<'_>, backlog: c::c_int) -> io::Result<()> { +    unsafe { ret(c::listen(borrowed_fd(sockfd), backlog)) } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn accept(sockfd: BorrowedFd<'_>) -> io::Result<OwnedFd> { +    unsafe { +        let owned_fd = ret_owned_fd(c::accept(borrowed_fd(sockfd), null_mut(), null_mut()))?; +        Ok(owned_fd) +    } +} + +#[cfg(not(any( +    windows, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) fn recvmsg( +    sockfd: BorrowedFd<'_>, +    iov: &mut [IoSliceMut<'_>], +    control: &mut RecvAncillaryBuffer<'_>, +    msg_flags: RecvFlags, +) -> io::Result<RecvMsgReturn> { +    let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); + +    with_recv_msghdr(&mut storage, iov, control, |msghdr| { +        let result = unsafe { +            ret_send_recv(c::recvmsg( +                borrowed_fd(sockfd), +                msghdr, +                bitflags_bits!(msg_flags), +            )) +        }; + +        result.map(|bytes| { +            // Get the address of the sender, if any. +            let addr = +                unsafe { maybe_read_sockaddr_os(msghdr.msg_name as _, msghdr.msg_namelen as _) }; + +            RecvMsgReturn { +                bytes, +                address: addr, +                flags: RecvFlags::from_bits_retain(bitcast!(msghdr.msg_flags)), +            } +        }) +    }) +} + +#[cfg(not(any( +    windows, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) fn sendmsg( +    sockfd: BorrowedFd<'_>, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    msg_flags: SendFlags, +) -> io::Result<usize> { +    with_noaddr_msghdr(iov, control, |msghdr| unsafe { +        ret_send_recv(c::sendmsg( +            borrowed_fd(sockfd), +            &msghdr, +            bitflags_bits!(msg_flags), +        )) +    }) +} + +#[cfg(not(any( +    windows, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) fn sendmsg_v4( +    sockfd: BorrowedFd<'_>, +    addr: &SocketAddrV4, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    msg_flags: SendFlags, +) -> io::Result<usize> { +    with_v4_msghdr(addr, iov, control, |msghdr| unsafe { +        ret_send_recv(c::sendmsg( +            borrowed_fd(sockfd), +            &msghdr, +            bitflags_bits!(msg_flags), +        )) +    }) +} + +#[cfg(not(any( +    windows, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) fn sendmsg_v6( +    sockfd: BorrowedFd<'_>, +    addr: &SocketAddrV6, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    msg_flags: SendFlags, +) -> io::Result<usize> { +    with_v6_msghdr(addr, iov, control, |msghdr| unsafe { +        ret_send_recv(c::sendmsg( +            borrowed_fd(sockfd), +            &msghdr, +            bitflags_bits!(msg_flags), +        )) +    }) +} + +#[cfg(all( +    unix, +    not(any(target_os = "espidf", target_os = "redox", target_os = "vita")) +))] +pub(crate) fn sendmsg_unix( +    sockfd: BorrowedFd<'_>, +    addr: &SocketAddrUnix, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    msg_flags: SendFlags, +) -> io::Result<usize> { +    super::msghdr::with_unix_msghdr(addr, iov, control, |msghdr| unsafe { +        ret_send_recv(c::sendmsg( +            borrowed_fd(sockfd), +            &msghdr, +            bitflags_bits!(msg_flags), +        )) +    }) +} + +#[cfg(not(any( +    apple, +    windows, +    target_os = "aix", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "redox", +    target_os = "nto", +    target_os = "vita", +    target_os = "wasi", +)))] +pub(crate) fn accept_with(sockfd: BorrowedFd<'_>, flags: SocketFlags) -> io::Result<OwnedFd> { +    unsafe { +        let owned_fd = ret_owned_fd(c::accept4( +            borrowed_fd(sockfd), +            null_mut(), +            null_mut(), +            flags.bits() as c::c_int, +        ))?; +        Ok(owned_fd) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn acceptfrom(sockfd: BorrowedFd<'_>) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { +    unsafe { +        let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); +        let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; +        let owned_fd = ret_owned_fd(c::accept( +            borrowed_fd(sockfd), +            storage.as_mut_ptr().cast(), +            &mut len, +        ))?; +        Ok(( +            owned_fd, +            maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()), +        )) +    } +} + +#[cfg(not(any( +    apple, +    windows, +    target_os = "aix", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "nto", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +pub(crate) fn acceptfrom_with( +    sockfd: BorrowedFd<'_>, +    flags: SocketFlags, +) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { +    unsafe { +        let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); +        let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; +        let owned_fd = ret_owned_fd(c::accept4( +            borrowed_fd(sockfd), +            storage.as_mut_ptr().cast(), +            &mut len, +            flags.bits() as c::c_int, +        ))?; +        Ok(( +            owned_fd, +            maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()), +        )) +    } +} + +/// Darwin lacks `accept4`, but does have `accept`. We define +/// `SocketFlags` to have no flags, so we can discard it here. +#[cfg(any( +    apple, +    windows, +    target_os = "aix", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "nto", +    target_os = "vita", +))] +pub(crate) fn accept_with(sockfd: BorrowedFd<'_>, _flags: SocketFlags) -> io::Result<OwnedFd> { +    accept(sockfd) +} + +/// Darwin lacks `accept4`, but does have `accept`. We define +/// `SocketFlags` to have no flags, so we can discard it here. +#[cfg(any( +    apple, +    windows, +    target_os = "aix", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "nto", +    target_os = "vita", +))] +pub(crate) fn acceptfrom_with( +    sockfd: BorrowedFd<'_>, +    _flags: SocketFlags, +) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { +    acceptfrom(sockfd) +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn shutdown(sockfd: BorrowedFd<'_>, how: Shutdown) -> io::Result<()> { +    unsafe { ret(c::shutdown(borrowed_fd(sockfd), how as c::c_int)) } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn getsockname(sockfd: BorrowedFd<'_>) -> io::Result<SocketAddrAny> { +    unsafe { +        let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); +        let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; +        ret(c::getsockname( +            borrowed_fd(sockfd), +            storage.as_mut_ptr().cast(), +            &mut len, +        ))?; +        Ok(read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap())) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn getpeername(sockfd: BorrowedFd<'_>) -> io::Result<Option<SocketAddrAny>> { +    unsafe { +        let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit(); +        let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t; +        ret(c::getpeername( +            borrowed_fd(sockfd), +            storage.as_mut_ptr().cast(), +            &mut len, +        ))?; +        Ok(maybe_read_sockaddr_os( +            storage.as_ptr(), +            len.try_into().unwrap(), +        )) +    } +} + +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +pub(crate) fn socketpair( +    domain: AddressFamily, +    type_: SocketType, +    flags: SocketFlags, +    protocol: Option<Protocol>, +) -> io::Result<(OwnedFd, OwnedFd)> { +    let raw_protocol = match protocol { +        Some(p) => p.0.get(), +        None => 0, +    }; +    unsafe { +        let mut fds = MaybeUninit::<[OwnedFd; 2]>::uninit(); +        ret(c::socketpair( +            c::c_int::from(domain.0), +            (type_.0 | flags.bits()) as c::c_int, +            raw_protocol as c::c_int, +            fds.as_mut_ptr().cast::<c::c_int>(), +        ))?; + +        let [fd0, fd1] = fds.assume_init(); +        Ok((fd0, fd1)) +    } +} diff --git a/vendor/rustix/src/backend/libc/net/write_sockaddr.rs b/vendor/rustix/src/backend/libc/net/write_sockaddr.rs new file mode 100644 index 0000000..2eee98c --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/write_sockaddr.rs @@ -0,0 +1,103 @@ +//! The BSD sockets API requires us to read the `ss_family` field before we can +//! interpret the rest of a `sockaddr` produced by the kernel. + +use super::addr::SocketAddrStorage; +#[cfg(unix)] +use super::addr::SocketAddrUnix; +use super::ext::{in6_addr_new, in_addr_new, sockaddr_in6_new}; +use crate::backend::c; +use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use core::mem::size_of; + +pub(crate) unsafe fn write_sockaddr( +    addr: &SocketAddrAny, +    storage: *mut SocketAddrStorage, +) -> usize { +    match addr { +        SocketAddrAny::V4(v4) => write_sockaddr_v4(v4, storage), +        SocketAddrAny::V6(v6) => write_sockaddr_v6(v6, storage), +        #[cfg(unix)] +        SocketAddrAny::Unix(unix) => write_sockaddr_unix(unix, storage), +    } +} + +pub(crate) fn encode_sockaddr_v4(v4: &SocketAddrV4) -> c::sockaddr_in { +    c::sockaddr_in { +        #[cfg(any( +            bsd, +            target_os = "aix", +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "vita", +        ))] +        sin_len: size_of::<c::sockaddr_in>() as _, +        sin_family: c::AF_INET as _, +        sin_port: u16::to_be(v4.port()), +        sin_addr: in_addr_new(u32::from_ne_bytes(v4.ip().octets())), +        #[cfg(not(any(target_os = "haiku", target_os = "vita")))] +        sin_zero: [0; 8_usize], +        #[cfg(target_os = "haiku")] +        sin_zero: [0; 24_usize], +        #[cfg(target_os = "vita")] +        sin_zero: [0; 6_usize], +        #[cfg(target_os = "vita")] +        sin_vport: 0, +    } +} + +unsafe fn write_sockaddr_v4(v4: &SocketAddrV4, storage: *mut SocketAddrStorage) -> usize { +    let encoded = encode_sockaddr_v4(v4); +    core::ptr::write(storage.cast(), encoded); +    size_of::<c::sockaddr_in>() +} + +pub(crate) fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 { +    #[cfg(any( +        bsd, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "nto", +        target_os = "vita" +    ))] +    { +        sockaddr_in6_new( +            size_of::<c::sockaddr_in6>() as _, +            c::AF_INET6 as _, +            u16::to_be(v6.port()), +            u32::to_be(v6.flowinfo()), +            in6_addr_new(v6.ip().octets()), +            v6.scope_id(), +        ) +    } +    #[cfg(not(any( +        bsd, +        target_os = "aix", +        target_os = "espidf", +        target_os = "haiku", +        target_os = "nto", +        target_os = "vita" +    )))] +    { +        sockaddr_in6_new( +            c::AF_INET6 as _, +            u16::to_be(v6.port()), +            u32::to_be(v6.flowinfo()), +            in6_addr_new(v6.ip().octets()), +            v6.scope_id(), +        ) +    } +} + +unsafe fn write_sockaddr_v6(v6: &SocketAddrV6, storage: *mut SocketAddrStorage) -> usize { +    let encoded = encode_sockaddr_v6(v6); +    core::ptr::write(storage.cast(), encoded); +    size_of::<c::sockaddr_in6>() +} + +#[cfg(unix)] +unsafe fn write_sockaddr_unix(unix: &SocketAddrUnix, storage: *mut SocketAddrStorage) -> usize { +    core::ptr::write(storage.cast(), unix.unix); +    unix.len() +} diff --git a/vendor/rustix/src/backend/libc/param/auxv.rs b/vendor/rustix/src/backend/libc/param/auxv.rs new file mode 100644 index 0000000..880a1d4 --- /dev/null +++ b/vendor/rustix/src/backend/libc/param/auxv.rs @@ -0,0 +1,54 @@ +use crate::backend::c; +#[cfg(any( +    all(target_os = "android", target_pointer_width = "64"), +    target_os = "linux", +))] +use crate::ffi::CStr; + +// `getauxval` wasn't supported in glibc until 2.16. +#[cfg(any( +    all(target_os = "android", target_pointer_width = "64"), +    target_os = "linux", +))] +weak!(fn getauxval(c::c_ulong) -> *mut c::c_void); + +#[inline] +pub(crate) fn page_size() -> usize { +    unsafe { c::sysconf(c::_SC_PAGESIZE) as usize } +} + +#[cfg(not(any(target_os = "vita", target_os = "wasi")))] +#[inline] +pub(crate) fn clock_ticks_per_second() -> u64 { +    unsafe { c::sysconf(c::_SC_CLK_TCK) as u64 } +} + +#[cfg(any( +    all(target_os = "android", target_pointer_width = "64"), +    target_os = "linux", +))] +#[inline] +pub(crate) fn linux_hwcap() -> (usize, usize) { +    if let Some(libc_getauxval) = getauxval.get() { +        unsafe { +            let hwcap = libc_getauxval(c::AT_HWCAP) as usize; +            let hwcap2 = libc_getauxval(c::AT_HWCAP2) as usize; +            (hwcap, hwcap2) +        } +    } else { +        (0, 0) +    } +} + +#[cfg(any( +    all(target_os = "android", target_pointer_width = "64"), +    target_os = "linux", +))] +#[inline] +pub(crate) fn linux_execfn() -> &'static CStr { +    if let Some(libc_getauxval) = getauxval.get() { +        unsafe { CStr::from_ptr(libc_getauxval(c::AT_EXECFN).cast()) } +    } else { +        cstr!("") +    } +} diff --git a/vendor/rustix/src/backend/libc/param/mod.rs b/vendor/rustix/src/backend/libc/param/mod.rs new file mode 100644 index 0000000..2cb2fe7 --- /dev/null +++ b/vendor/rustix/src/backend/libc/param/mod.rs @@ -0,0 +1 @@ +pub(crate) mod auxv; diff --git a/vendor/rustix/src/backend/libc/pid/mod.rs b/vendor/rustix/src/backend/libc/pid/mod.rs new file mode 100644 index 0000000..ef944f0 --- /dev/null +++ b/vendor/rustix/src/backend/libc/pid/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix/src/backend/libc/pid/syscalls.rs b/vendor/rustix/src/backend/libc/pid/syscalls.rs new file mode 100644 index 0000000..d0ed4bc --- /dev/null +++ b/vendor/rustix/src/backend/libc/pid/syscalls.rs @@ -0,0 +1,14 @@ +//! libc syscalls for PIDs + +use crate::backend::c; +use crate::pid::Pid; + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getpid() -> Pid { +    unsafe { +        let pid = c::getpid(); +        Pid::from_raw_unchecked(pid) +    } +} diff --git a/vendor/rustix/src/backend/libc/pipe/mod.rs b/vendor/rustix/src/backend/libc/pipe/mod.rs new file mode 100644 index 0000000..1e0181a --- /dev/null +++ b/vendor/rustix/src/backend/libc/pipe/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix/src/backend/libc/pipe/syscalls.rs b/vendor/rustix/src/backend/libc/pipe/syscalls.rs new file mode 100644 index 0000000..cff932d --- /dev/null +++ b/vendor/rustix/src/backend/libc/pipe/syscalls.rs @@ -0,0 +1,125 @@ +use crate::backend::c; +use crate::backend::conv::ret; +use crate::fd::OwnedFd; +use crate::io; +#[cfg(not(any( +    apple, +    target_os = "aix", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "nto", +    target_os = "wasi" +)))] +use crate::pipe::PipeFlags; +use core::mem::MaybeUninit; +#[cfg(linux_kernel)] +use { +    crate::backend::conv::{borrowed_fd, ret_c_int, ret_usize}, +    crate::backend::MAX_IOV, +    crate::fd::BorrowedFd, +    crate::pipe::{IoSliceRaw, SpliceFlags}, +    crate::utils::option_as_mut_ptr, +    core::cmp::min, +}; + +#[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::<i32>()))?; +        let [p0, p1] = result.assume_init(); +        Ok((p0, p1)) +    } +} + +#[cfg(not(any( +    apple, +    target_os = "aix", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "nto", +    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::<i32>(), +            bitflags_bits!(flags), +        ))?; +        let [p0, p1] = result.assume_init(); +        Ok((p0, p1)) +    } +} + +#[cfg(linux_kernel)] +#[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<usize> { +    let off_in = option_as_mut_ptr(off_in).cast(); +    let off_out = option_as_mut_ptr(off_out).cast(); + +    unsafe { +        ret_usize(c::splice( +            borrowed_fd(fd_in), +            off_in, +            borrowed_fd(fd_out), +            off_out, +            len, +            flags.bits(), +        )) +    } +} + +#[cfg(linux_kernel)] +#[inline] +pub unsafe fn vmsplice( +    fd: BorrowedFd<'_>, +    bufs: &[IoSliceRaw<'_>], +    flags: SpliceFlags, +) -> io::Result<usize> { +    ret_usize(c::vmsplice( +        borrowed_fd(fd), +        bufs.as_ptr().cast::<c::iovec>(), +        min(bufs.len(), MAX_IOV), +        flags.bits(), +    )) +} + +#[cfg(linux_kernel)] +#[inline] +pub fn tee( +    fd_in: BorrowedFd<'_>, +    fd_out: BorrowedFd<'_>, +    len: usize, +    flags: SpliceFlags, +) -> io::Result<usize> { +    unsafe { +        ret_usize(c::tee( +            borrowed_fd(fd_in), +            borrowed_fd(fd_out), +            len, +            flags.bits(), +        )) +    } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn fcntl_getpipe_sz(fd: BorrowedFd<'_>) -> io::Result<usize> { +    unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETPIPE_SZ)).map(|size| size as usize) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn fcntl_setpipe_sz(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> { +    let size: c::c_int = size.try_into().map_err(|_| io::Errno::PERM)?; + +    unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETPIPE_SZ, size)) } +} diff --git a/vendor/rustix/src/backend/libc/pipe/types.rs b/vendor/rustix/src/backend/libc/pipe/types.rs new file mode 100644 index 0000000..78fc2fc --- /dev/null +++ b/vendor/rustix/src/backend/libc/pipe/types.rs @@ -0,0 +1,103 @@ +#[cfg(linux_kernel)] +use core::marker::PhantomData; +#[cfg(not(any(apple, target_os = "wasi")))] +use {crate::backend::c, bitflags::bitflags}; + +#[cfg(not(any(apple, target_os = "wasi")))] +bitflags! { +    /// `O_*` constants for use with [`pipe_with`]. +    /// +    /// [`pipe_with`]: crate::pipe::pipe_with +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct PipeFlags: u32 { +        /// `O_CLOEXEC` +        const CLOEXEC = bitcast!(c::O_CLOEXEC); +        /// `O_DIRECT` +        #[cfg(not(any( +            solarish, +            target_os = "espidf", +            target_os = "haiku", +            target_os = "nto", +            target_os = "openbsd", +            target_os = "redox", +            target_os = "vita", +        )))] +        const DIRECT = bitcast!(c::O_DIRECT); +        /// `O_NONBLOCK` +        const NONBLOCK = bitcast!(c::O_NONBLOCK); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(linux_kernel)] +bitflags! { +    /// `SPLICE_F_*` constants for use with [`splice`], [`vmsplice`], and +    /// [`tee`]. +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    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; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// A buffer type for use 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. +/// +/// [`vmsplice`]: crate::pipe::vmsplice +#[cfg(linux_kernel)] +#[repr(transparent)] +pub struct IoSliceRaw<'a> { +    _buf: c::iovec, +    _lifetime: PhantomData<&'a ()>, +} + +#[cfg(linux_kernel)] +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, +        } +    } +} + +#[cfg(not(any(apple, target_os = "wasi")))] +#[test] +fn test_types() { +    assert_eq_size!(PipeFlags, c::c_int); + +    #[cfg(linux_kernel)] +    assert_eq_size!(SpliceFlags, c::c_int); +} diff --git a/vendor/rustix/src/backend/libc/prctl/mod.rs b/vendor/rustix/src/backend/libc/prctl/mod.rs new file mode 100644 index 0000000..ef944f0 --- /dev/null +++ b/vendor/rustix/src/backend/libc/prctl/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix/src/backend/libc/prctl/syscalls.rs b/vendor/rustix/src/backend/libc/prctl/syscalls.rs new file mode 100644 index 0000000..451cecc --- /dev/null +++ b/vendor/rustix/src/backend/libc/prctl/syscalls.rs @@ -0,0 +1,14 @@ +use crate::backend::c; +use crate::backend::conv::ret_c_int; +use crate::io; + +#[inline] +pub(crate) unsafe fn prctl( +    option: c::c_int, +    arg2: *mut c::c_void, +    arg3: *mut c::c_void, +    arg4: *mut c::c_void, +    arg5: *mut c::c_void, +) -> io::Result<c::c_int> { +    ret_c_int(c::prctl(option, arg2, arg3, arg4, arg5)) +} diff --git a/vendor/rustix/src/backend/libc/process/cpu_set.rs b/vendor/rustix/src/backend/libc/process/cpu_set.rs new file mode 100644 index 0000000..4cf06b9 --- /dev/null +++ b/vendor/rustix/src/backend/libc/process/cpu_set.rs @@ -0,0 +1,50 @@ +//! Rust implementation of the `CPU_*` macro API. + +#![allow(non_snake_case)] + +use super::types::{RawCpuSet, CPU_SETSIZE}; +use crate::backend::c; + +#[inline] +pub(crate) fn CPU_SET(cpu: usize, cpuset: &mut RawCpuSet) { +    assert!( +        cpu < CPU_SETSIZE, +        "cpu out of bounds: the cpu max is {} but the cpu is {}", +        CPU_SETSIZE, +        cpu +    ); +    unsafe { c::CPU_SET(cpu, cpuset) } +} + +#[inline] +pub(crate) fn CPU_ZERO(cpuset: &mut RawCpuSet) { +    unsafe { c::CPU_ZERO(cpuset) } +} + +#[inline] +pub(crate) fn CPU_CLR(cpu: usize, cpuset: &mut RawCpuSet) { +    assert!( +        cpu < CPU_SETSIZE, +        "cpu out of bounds: the cpu max is {} but the cpu is {}", +        CPU_SETSIZE, +        cpu +    ); +    unsafe { c::CPU_CLR(cpu, cpuset) } +} + +#[inline] +pub(crate) fn CPU_ISSET(cpu: usize, cpuset: &RawCpuSet) -> bool { +    assert!( +        cpu < CPU_SETSIZE, +        "cpu out of bounds: the cpu max is {} but the cpu is {}", +        CPU_SETSIZE, +        cpu +    ); +    unsafe { c::CPU_ISSET(cpu, cpuset) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn CPU_COUNT(cpuset: &RawCpuSet) -> u32 { +    unsafe { c::CPU_COUNT(cpuset).try_into().unwrap() } +} diff --git a/vendor/rustix/src/backend/libc/process/mod.rs b/vendor/rustix/src/backend/libc/process/mod.rs new file mode 100644 index 0000000..39803b5 --- /dev/null +++ b/vendor/rustix/src/backend/libc/process/mod.rs @@ -0,0 +1,7 @@ +#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))] +pub(crate) mod cpu_set; +#[cfg(not(windows))] +pub(crate) mod syscalls; +pub(crate) mod types; +#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))] +pub(crate) mod wait; diff --git a/vendor/rustix/src/backend/libc/process/syscalls.rs b/vendor/rustix/src/backend/libc/process/syscalls.rs new file mode 100644 index 0000000..46fd182 --- /dev/null +++ b/vendor/rustix/src/backend/libc/process/syscalls.rs @@ -0,0 +1,713 @@ +//! libc syscalls supporting `rustix::process`. + +#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))] +use super::types::RawCpuSet; +use crate::backend::c; +#[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))] +use crate::backend::conv::borrowed_fd; +#[cfg(feature = "fs")] +use crate::backend::conv::c_str; +#[cfg(all(feature = "alloc", feature = "fs", not(target_os = "wasi")))] +use crate::backend::conv::ret_discarded_char_ptr; +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +use crate::backend::conv::ret_infallible; +#[cfg(not(target_os = "wasi"))] +use crate::backend::conv::ret_pid_t; +#[cfg(linux_kernel)] +use crate::backend::conv::ret_u32; +#[cfg(all(feature = "alloc", not(target_os = "wasi")))] +use crate::backend::conv::ret_usize; +use crate::backend::conv::{ret, ret_c_int}; +#[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))] +use crate::fd::BorrowedFd; +#[cfg(target_os = "linux")] +use crate::fd::{AsRawFd, OwnedFd, RawFd}; +#[cfg(feature = "fs")] +use crate::ffi::CStr; +#[cfg(feature = "fs")] +use crate::fs::Mode; +use crate::io; +#[cfg(all(feature = "alloc", not(target_os = "wasi")))] +use crate::process::Gid; +#[cfg(not(target_os = "wasi"))] +use crate::process::Pid; +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +use crate::process::Signal; +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "vita", +    target_os = "wasi" +)))] +use crate::process::Uid; +#[cfg(linux_kernel)] +use crate::process::{Cpuid, MembarrierCommand, MembarrierQuery}; +#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))] +use crate::process::{RawPid, WaitOptions, WaitStatus}; +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +use crate::process::{Resource, Rlimit}; +#[cfg(not(any( +    target_os = "espidf", +    target_os = "redox", +    target_os = "openbsd", +    target_os = "vita", +    target_os = "wasi" +)))] +use crate::process::{WaitId, WaitidOptions, WaitidStatus}; +use core::mem::MaybeUninit; +#[cfg(target_os = "linux")] +use { +    super::super::conv::ret_owned_fd, crate::process::PidfdFlags, crate::process::PidfdGetfdFlags, +}; + +#[cfg(any(linux_kernel, target_os = "dragonfly"))] +#[inline] +pub(crate) fn sched_getcpu() -> usize { +    let r = unsafe { libc::sched_getcpu() }; +    debug_assert!(r >= 0); +    r as usize +} + +#[cfg(feature = "fs")] +#[cfg(not(target_os = "wasi"))] +pub(crate) fn chdir(path: &CStr) -> io::Result<()> { +    unsafe { ret(c::chdir(c_str(path))) } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +pub(crate) fn fchdir(dirfd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { ret(c::fchdir(borrowed_fd(dirfd))) } +} + +#[cfg(feature = "fs")] +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +pub(crate) fn chroot(path: &CStr) -> io::Result<()> { +    unsafe { ret(c::chroot(c_str(path))) } +} + +#[cfg(all(feature = "alloc", feature = "fs"))] +#[cfg(not(target_os = "wasi"))] +pub(crate) fn getcwd(buf: &mut [MaybeUninit<u8>]) -> io::Result<()> { +    unsafe { ret_discarded_char_ptr(c::getcwd(buf.as_mut_ptr().cast(), buf.len())) } +} + +// The `membarrier` syscall has a third argument, but it's only used when +// the `flags` argument is `MEMBARRIER_CMD_FLAG_CPU`. +#[cfg(linux_kernel)] +syscall! { +    fn membarrier_all( +        cmd: c::c_int, +        flags: c::c_uint +    ) via SYS_membarrier -> c::c_int +} + +#[cfg(linux_kernel)] +pub(crate) fn membarrier_query() -> MembarrierQuery { +    // glibc does not have a wrapper for `membarrier`; [the documentation] +    // says to use `syscall`. +    // +    // [the documentation]: https://man7.org/linux/man-pages/man2/membarrier.2.html#NOTES +    const MEMBARRIER_CMD_QUERY: u32 = 0; +    unsafe { +        match ret_u32(membarrier_all(MEMBARRIER_CMD_QUERY as i32, 0)) { +            Ok(query) => MembarrierQuery::from_bits_retain(query), +            Err(_) => MembarrierQuery::empty(), +        } +    } +} + +#[cfg(linux_kernel)] +pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> { +    unsafe { ret(membarrier_all(cmd as i32, 0)) } +} + +#[cfg(linux_kernel)] +pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> { +    const MEMBARRIER_CMD_FLAG_CPU: u32 = 1; + +    syscall! { +        fn membarrier_cpu( +            cmd: c::c_int, +            flags: c::c_uint, +            cpu_id: c::c_int +        ) via SYS_membarrier -> c::c_int +    } + +    unsafe { +        ret(membarrier_cpu( +            cmd as i32, +            MEMBARRIER_CMD_FLAG_CPU, +            bitcast!(cpu.as_raw()), +        )) +    } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getppid() -> Option<Pid> { +    unsafe { +        let pid: i32 = c::getppid(); +        Pid::from_raw(pid) +    } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> { +    unsafe { +        let pgid = ret_pid_t(c::getpgid(Pid::as_raw(pid) as _))?; +        Ok(Pid::from_raw_unchecked(pgid)) +    } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> { +    unsafe { ret(c::setpgid(Pid::as_raw(pid) as _, Pid::as_raw(pgid) as _)) } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getpgrp() -> Pid { +    unsafe { +        let pgid = c::getpgrp(); +        Pid::from_raw_unchecked(pgid) +    } +} + +#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))] +#[inline] +pub(crate) fn sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()> { +    unsafe { +        ret(c::sched_getaffinity( +            Pid::as_raw(pid) as _, +            core::mem::size_of::<RawCpuSet>(), +            cpuset, +        )) +    } +} + +#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))] +#[inline] +pub(crate) fn sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()> { +    unsafe { +        ret(c::sched_setaffinity( +            Pid::as_raw(pid) as _, +            core::mem::size_of::<RawCpuSet>(), +            cpuset, +        )) +    } +} + +#[inline] +pub(crate) fn sched_yield() { +    unsafe { +        let _ = c::sched_yield(); +    } +} + +#[cfg(not(target_os = "wasi"))] +#[cfg(feature = "fs")] +#[inline] +pub(crate) fn umask(mask: Mode) -> Mode { +    unsafe { Mode::from_bits_retain(c::umask(mask.bits() as c::mode_t).into()) } +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "vita", target_os = "wasi")))] +#[inline] +pub(crate) fn nice(inc: i32) -> io::Result<i32> { +    libc_errno::set_errno(libc_errno::Errno(0)); +    let r = unsafe { c::nice(inc) }; +    if libc_errno::errno().0 != 0 { +        ret_c_int(r) +    } else { +        Ok(r) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn getpriority_user(uid: Uid) -> io::Result<i32> { +    libc_errno::set_errno(libc_errno::Errno(0)); +    let r = unsafe { c::getpriority(c::PRIO_USER, uid.as_raw() as _) }; +    if libc_errno::errno().0 != 0 { +        ret_c_int(r) +    } else { +        Ok(r) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> { +    libc_errno::set_errno(libc_errno::Errno(0)); +    let r = unsafe { c::getpriority(c::PRIO_PGRP, Pid::as_raw(pgid) as _) }; +    if libc_errno::errno().0 != 0 { +        ret_c_int(r) +    } else { +        Ok(r) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> { +    libc_errno::set_errno(libc_errno::Errno(0)); +    let r = unsafe { c::getpriority(c::PRIO_PROCESS, Pid::as_raw(pid) as _) }; +    if libc_errno::errno().0 != 0 { +        ret_c_int(r) +    } else { +        Ok(r) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> { +    unsafe { ret(c::setpriority(c::PRIO_USER, uid.as_raw() as _, priority)) } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> { +    unsafe { +        ret(c::setpriority( +            c::PRIO_PGRP, +            Pid::as_raw(pgid) as _, +            priority, +        )) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> { +    unsafe { +        ret(c::setpriority( +            c::PRIO_PROCESS, +            Pid::as_raw(pid) as _, +            priority, +        )) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn getrlimit(limit: Resource) -> Rlimit { +    let mut result = MaybeUninit::<c::rlimit>::uninit(); +    unsafe { +        ret_infallible(c::getrlimit(limit as _, result.as_mut_ptr())); +        rlimit_from_libc(result.assume_init()) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> { +    let lim = rlimit_to_libc(new)?; +    unsafe { ret(c::setrlimit(limit as _, &lim)) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit> { +    let lim = rlimit_to_libc(new)?; +    let mut result = MaybeUninit::<c::rlimit>::uninit(); +    unsafe { +        ret(c::prlimit( +            Pid::as_raw(pid), +            limit as _, +            &lim, +            result.as_mut_ptr(), +        ))?; +        Ok(rlimit_from_libc(result.assume_init())) +    } +} + +/// Convert a Rust [`Rlimit`] to a C `c::rlimit`. +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +fn rlimit_from_libc(lim: c::rlimit) -> Rlimit { +    let current = if lim.rlim_cur == c::RLIM_INFINITY { +        None +    } else { +        Some(lim.rlim_cur.try_into().unwrap()) +    }; +    let maximum = if lim.rlim_max == c::RLIM_INFINITY { +        None +    } else { +        Some(lim.rlim_max.try_into().unwrap()) +    }; +    Rlimit { current, maximum } +} + +/// Convert a C `c::rlimit` to a Rust `Rlimit`. +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +fn rlimit_to_libc(lim: Rlimit) -> io::Result<c::rlimit> { +    let Rlimit { current, maximum } = lim; +    let rlim_cur = match current { +        Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?, +        None => c::RLIM_INFINITY as _, +    }; +    let rlim_max = match maximum { +        Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?, +        None => c::RLIM_INFINITY as _, +    }; +    Ok(c::rlimit { rlim_cur, rlim_max }) +} + +#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))] +#[inline] +pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { +    _waitpid(!0, waitopts) +} + +#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))] +#[inline] +pub(crate) fn waitpid( +    pid: Option<Pid>, +    waitopts: WaitOptions, +) -> io::Result<Option<(Pid, WaitStatus)>> { +    _waitpid(Pid::as_raw(pid), waitopts) +} + +#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))] +#[inline] +pub(crate) fn waitpgid(pgid: Pid, waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { +    _waitpid(-pgid.as_raw_nonzero().get(), waitopts) +} + +#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))] +#[inline] +pub(crate) fn _waitpid( +    pid: RawPid, +    waitopts: WaitOptions, +) -> io::Result<Option<(Pid, WaitStatus)>> { +    unsafe { +        let mut status: c::c_int = 0; +        let pid = ret_c_int(c::waitpid(pid as _, &mut status, waitopts.bits() as _))?; +        Ok(Pid::from_raw(pid).map(|pid| (pid, WaitStatus::new(status as _)))) +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "redox", +    target_os = "openbsd", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +pub(crate) fn waitid(id: WaitId<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { +    // Get the id to wait on. +    match id { +        WaitId::All => _waitid_all(options), +        WaitId::Pid(pid) => _waitid_pid(pid, options), +        WaitId::Pgid(pgid) => _waitid_pgid(pgid, options), +        #[cfg(target_os = "linux")] +        WaitId::PidFd(fd) => _waitid_pidfd(fd, options), +        #[cfg(not(target_os = "linux"))] +        WaitId::__EatLifetime(_) => unreachable!(), +    } +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "redox", +    target_os = "openbsd", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +fn _waitid_all(options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { +    // `waitid` can return successfully without initializing the struct (no +    // children found when using `WNOHANG`) +    let mut status = MaybeUninit::<c::siginfo_t>::zeroed(); +    unsafe { +        ret(c::waitid( +            c::P_ALL, +            0, +            status.as_mut_ptr(), +            options.bits() as _, +        ))? +    }; + +    Ok(unsafe { cvt_waitid_status(status) }) +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "redox", +    target_os = "openbsd", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +fn _waitid_pid(pid: Pid, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { +    // `waitid` can return successfully without initializing the struct (no +    // children found when using `WNOHANG`) +    let mut status = MaybeUninit::<c::siginfo_t>::zeroed(); +    unsafe { +        ret(c::waitid( +            c::P_PID, +            Pid::as_raw(Some(pid)) as _, +            status.as_mut_ptr(), +            options.bits() as _, +        ))? +    }; + +    Ok(unsafe { cvt_waitid_status(status) }) +} + +#[cfg(not(any( +    target_os = "espidf", +    target_os = "redox", +    target_os = "openbsd", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +fn _waitid_pgid(pgid: Option<Pid>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { +    // `waitid` can return successfully without initializing the struct (no +    // children found when using `WNOHANG`) +    let mut status = MaybeUninit::<c::siginfo_t>::zeroed(); +    unsafe { +        ret(c::waitid( +            c::P_PGID, +            Pid::as_raw(pgid) as _, +            status.as_mut_ptr(), +            options.bits() as _, +        ))? +    }; + +    Ok(unsafe { cvt_waitid_status(status) }) +} + +#[cfg(target_os = "linux")] +#[inline] +fn _waitid_pidfd(fd: BorrowedFd<'_>, options: WaitidOptions) -> io::Result<Option<WaitidStatus>> { +    // `waitid` can return successfully without initializing the struct (no +    // children found when using `WNOHANG`) +    let mut status = MaybeUninit::<c::siginfo_t>::zeroed(); +    unsafe { +        ret(c::waitid( +            c::P_PIDFD, +            fd.as_raw_fd() as _, +            status.as_mut_ptr(), +            options.bits() as _, +        ))? +    }; + +    Ok(unsafe { cvt_waitid_status(status) }) +} + +/// Convert a `siginfo_t` to a `WaitidStatus`. +/// +/// # Safety +/// +/// The caller must ensure that `status` is initialized and that `waitid` +/// returned successfully. +#[cfg(not(any( +    target_os = "espidf", +    target_os = "openbsd", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +#[inline] +unsafe fn cvt_waitid_status(status: MaybeUninit<c::siginfo_t>) -> Option<WaitidStatus> { +    let status = status.assume_init(); +    // `si_pid` is supposedly the better way to check that the struct has been +    // filled, e.g. the Linux manpage says about the `WNOHANG` case “zero out +    // the si_pid field before the call and check for a nonzero value”. +    // But e.g. NetBSD/OpenBSD don't have it exposed in the libc crate for now, +    // and some platforms don't have it at all. For simplicity, always check +    // `si_signo`. We have zero-initialized the whole struct, and all kernels +    // should set `SIGCHLD` here. +    if status.si_signo == 0 { +        None +    } else { +        Some(WaitidStatus(status)) +    } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[inline] +pub(crate) fn getsid(pid: Option<Pid>) -> io::Result<Pid> { +    unsafe { +        let pid = ret_pid_t(c::getsid(Pid::as_raw(pid) as _))?; +        Ok(Pid::from_raw_unchecked(pid)) +    } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn setsid() -> io::Result<Pid> { +    unsafe { +        let pid = ret_c_int(c::setsid())?; +        Ok(Pid::from_raw_unchecked(pid)) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[inline] +pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> { +    unsafe { ret(c::kill(pid.as_raw_nonzero().get(), sig as i32)) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[inline] +pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> { +    unsafe { +        ret(c::kill( +            pid.as_raw_nonzero().get().wrapping_neg(), +            sig as i32, +        )) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[inline] +pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> { +    unsafe { ret(c::kill(0, sig as i32)) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) fn test_kill_process(pid: Pid) -> io::Result<()> { +    unsafe { ret(c::kill(pid.as_raw_nonzero().get(), 0)) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[inline] +pub(crate) fn test_kill_process_group(pid: Pid) -> io::Result<()> { +    unsafe { ret(c::kill(pid.as_raw_nonzero().get().wrapping_neg(), 0)) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[inline] +pub(crate) fn test_kill_current_process_group() -> io::Result<()> { +    unsafe { ret(c::kill(0, 0)) } +} + +#[cfg(freebsdlike)] +#[inline] +pub(crate) unsafe fn procctl( +    idtype: c::idtype_t, +    id: c::id_t, +    option: c::c_int, +    data: *mut c::c_void, +) -> io::Result<()> { +    ret(c::procctl(idtype, id, option, data)) +} + +#[cfg(target_os = "linux")] +pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> { +    syscall! { +        fn pidfd_open( +            pid: c::pid_t, +            flags: c::c_uint +        ) via SYS_pidfd_open -> c::c_int +    } +    unsafe { +        ret_owned_fd(pidfd_open( +            pid.as_raw_nonzero().get(), +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(target_os = "linux")] +pub(crate) fn pidfd_getfd( +    pidfd: BorrowedFd<'_>, +    targetfd: RawFd, +    flags: PidfdGetfdFlags, +) -> io::Result<OwnedFd> { +    syscall! { +        fn pidfd_getfd( +            pidfd: c::c_int, +            targetfd: c::c_int, +            flags: c::c_uint +        ) via SYS_pidfd_getfd -> c::c_int +    } +    unsafe { +        ret_owned_fd(pidfd_getfd( +            borrowed_fd(pidfd), +            targetfd, +            bitflags_bits!(flags), +        )) +    } +} + +#[cfg(all(feature = "alloc", not(target_os = "wasi")))] +pub(crate) fn getgroups(buf: &mut [Gid]) -> io::Result<usize> { +    let len = buf.len().try_into().map_err(|_| io::Errno::NOMEM)?; + +    unsafe { ret_usize(c::getgroups(len, buf.as_mut_ptr().cast()) as isize) } +} diff --git a/vendor/rustix/src/backend/libc/process/types.rs b/vendor/rustix/src/backend/libc/process/types.rs new file mode 100644 index 0000000..f914128 --- /dev/null +++ b/vendor/rustix/src/backend/libc/process/types.rs @@ -0,0 +1,172 @@ +#[cfg(not(any(target_os = "espidf", target_os = "vita")))] +use crate::backend::c; + +/// A command for use with [`membarrier`] and [`membarrier_cpu`]. +/// +/// For `MEMBARRIER_CMD_QUERY`, see [`membarrier_query`]. +/// +/// [`membarrier`]: crate::process::membarrier +/// [`membarrier_cpu`]: crate::process::membarrier_cpu +/// [`membarrier_query`]: crate::process::membarrier_query +#[cfg(linux_kernel)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[repr(u32)] +pub enum MembarrierCommand { +    /// `MEMBARRIER_CMD_GLOBAL` +    #[doc(alias = "Shared")] +    #[doc(alias = "MEMBARRIER_CMD_SHARED")] +    Global = c::MEMBARRIER_CMD_GLOBAL as u32, +    /// `MEMBARRIER_CMD_GLOBAL_EXPEDITED` +    GlobalExpedited = c::MEMBARRIER_CMD_GLOBAL_EXPEDITED as u32, +    /// `MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED` +    RegisterGlobalExpedited = c::MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED as u32, +    /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED` +    PrivateExpedited = c::MEMBARRIER_CMD_PRIVATE_EXPEDITED as u32, +    /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED` +    RegisterPrivateExpedited = c::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED as u32, +    /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE` +    PrivateExpeditedSyncCore = c::MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE as u32, +    /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE` +    RegisterPrivateExpeditedSyncCore = +        c::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE as u32, +    /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10) +    PrivateExpeditedRseq = c::MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ as u32, +    /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10) +    RegisterPrivateExpeditedRseq = c::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ as u32, +} + +/// A resource value for use with [`getrlimit`], [`setrlimit`], and +/// [`prlimit`]. +/// +/// [`getrlimit`]: crate::process::getrlimit +/// [`setrlimit`]: crate::process::setrlimit +/// [`prlimit`]: crate::process::prlimit +#[cfg(not(any( +    target_os = "espidf", +    target_os = "fuchsia", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(not(target_os = "l4re"), repr(u32))] +#[cfg_attr(target_os = "l4re", repr(u64))] +pub enum Resource { +    /// `RLIMIT_CPU` +    Cpu = bitcast!(c::RLIMIT_CPU), +    /// `RLIMIT_FSIZE` +    Fsize = bitcast!(c::RLIMIT_FSIZE), +    /// `RLIMIT_DATA` +    Data = bitcast!(c::RLIMIT_DATA), +    /// `RLIMIT_STACK` +    Stack = bitcast!(c::RLIMIT_STACK), +    /// `RLIMIT_CORE` +    #[cfg(not(target_os = "haiku"))] +    Core = bitcast!(c::RLIMIT_CORE), +    /// `RLIMIT_RSS` +    // "nto" has `RLIMIT_RSS`, but it has the same value as `RLIMIT_AS`. +    #[cfg(not(any(apple, solarish, target_os = "nto", target_os = "haiku")))] +    Rss = bitcast!(c::RLIMIT_RSS), +    /// `RLIMIT_NPROC` +    #[cfg(not(any(solarish, target_os = "haiku")))] +    Nproc = bitcast!(c::RLIMIT_NPROC), +    /// `RLIMIT_NOFILE` +    Nofile = bitcast!(c::RLIMIT_NOFILE), +    /// `RLIMIT_MEMLOCK` +    #[cfg(not(any(solarish, target_os = "aix", target_os = "haiku")))] +    Memlock = bitcast!(c::RLIMIT_MEMLOCK), +    /// `RLIMIT_AS` +    #[cfg(not(target_os = "openbsd"))] +    As = bitcast!(c::RLIMIT_AS), +    /// `RLIMIT_LOCKS` +    #[cfg(not(any( +        bsd, +        solarish, +        target_os = "aix", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "nto" +    )))] +    Locks = bitcast!(c::RLIMIT_LOCKS), +    /// `RLIMIT_SIGPENDING` +    #[cfg(not(any( +        bsd, +        solarish, +        target_os = "aix", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "nto" +    )))] +    Sigpending = bitcast!(c::RLIMIT_SIGPENDING), +    /// `RLIMIT_MSGQUEUE` +    #[cfg(not(any( +        bsd, +        solarish, +        target_os = "aix", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "nto" +    )))] +    Msgqueue = bitcast!(c::RLIMIT_MSGQUEUE), +    /// `RLIMIT_NICE` +    #[cfg(not(any( +        bsd, +        solarish, +        target_os = "aix", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "nto" +    )))] +    Nice = bitcast!(c::RLIMIT_NICE), +    /// `RLIMIT_RTPRIO` +    #[cfg(not(any( +        bsd, +        solarish, +        target_os = "aix", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "nto" +    )))] +    Rtprio = bitcast!(c::RLIMIT_RTPRIO), +    /// `RLIMIT_RTTIME` +    #[cfg(not(any( +        bsd, +        solarish, +        target_os = "aix", +        target_os = "android", +        target_os = "emscripten", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "nto", +    )))] +    Rttime = bitcast!(c::RLIMIT_RTTIME), +} + +#[cfg(apple)] +#[allow(non_upper_case_globals)] +impl Resource { +    /// `RLIMIT_RSS` +    pub const Rss: Self = Self::As; +} + +/// A CPU identifier as a raw integer. +#[cfg(linux_kernel)] +pub type RawCpuid = u32; +#[cfg(freebsdlike)] +pub type RawId = c::id_t; + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +pub(crate) type RawCpuSet = c::cpu_set_t; +#[cfg(freebsdlike)] +pub(crate) type RawCpuSet = c::cpuset_t; + +#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))] +#[inline] +pub(crate) fn raw_cpu_set_new() -> RawCpuSet { +    let mut set = unsafe { core::mem::zeroed() }; +    super::cpu_set::CPU_ZERO(&mut set); +    set +} + +#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))] +pub(crate) const CPU_SETSIZE: usize = c::CPU_SETSIZE as usize; diff --git a/vendor/rustix/src/backend/libc/process/wait.rs b/vendor/rustix/src/backend/libc/process/wait.rs new file mode 100644 index 0000000..9a932cf --- /dev/null +++ b/vendor/rustix/src/backend/libc/process/wait.rs @@ -0,0 +1,9 @@ +use crate::backend::c; + +pub(crate) use c::{ +    WCONTINUED, WEXITSTATUS, WIFCONTINUED, WIFEXITED, WIFSIGNALED, WIFSTOPPED, WNOHANG, WSTOPSIG, +    WTERMSIG, WUNTRACED, +}; + +#[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "wasi")))] +pub(crate) use c::{WEXITED, WNOWAIT, WSTOPPED}; diff --git a/vendor/rustix/src/backend/libc/pty/mod.rs b/vendor/rustix/src/backend/libc/pty/mod.rs new file mode 100644 index 0000000..ef944f0 --- /dev/null +++ b/vendor/rustix/src/backend/libc/pty/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix/src/backend/libc/pty/syscalls.rs b/vendor/rustix/src/backend/libc/pty/syscalls.rs new file mode 100644 index 0000000..2395efd --- /dev/null +++ b/vendor/rustix/src/backend/libc/pty/syscalls.rs @@ -0,0 +1,106 @@ +//! libc syscalls supporting `rustix::pty`. + +use crate::backend::c; +use crate::backend::conv::{borrowed_fd, ret}; +use crate::fd::BorrowedFd; +use crate::io; +#[cfg(all( +    feature = "alloc", +    any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia") +))] +use { +    crate::ffi::{CStr, CString}, +    crate::path::SMALL_PATH_BUFFER_SIZE, +    alloc::borrow::ToOwned, +    alloc::vec::Vec, +}; + +#[cfg(not(linux_kernel))] +use crate::{backend::conv::ret_owned_fd, fd::OwnedFd, pty::OpenptFlags}; + +#[cfg(not(linux_kernel))] +#[inline] +pub(crate) fn openpt(flags: OpenptFlags) -> io::Result<OwnedFd> { +    unsafe { ret_owned_fd(c::posix_openpt(flags.bits() as _)) } +} + +#[cfg(all( +    feature = "alloc", +    any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia") +))] +#[inline] +pub(crate) fn ptsname(fd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<CString> { +    // This code would benefit from having a better way to read into +    // uninitialized memory, but that requires `unsafe`. +    buffer.clear(); +    buffer.reserve(SMALL_PATH_BUFFER_SIZE); +    buffer.resize(buffer.capacity(), 0_u8); + +    loop { +        // On platforms with `ptsname_r`, use it. +        #[cfg(any(linux_like, target_os = "fuchsia"))] +        let r = unsafe { c::ptsname_r(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) }; + +        // FreeBSD 12 doesn't have `ptsname_r`. +        #[cfg(target_os = "freebsd")] +        let r = unsafe { +            weak! { +                fn ptsname_r( +                     c::c_int, +                     *mut c::c_char, +                     c::size_t +                ) -> c::c_int +            } +            if let Some(func) = ptsname_r.get() { +                func(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) +            } else { +                libc::ENOSYS +            } +        }; + +        // macOS 10.13.4 has `ptsname_r`; use it if we have it, otherwise fall +        // back to calling the underlying ioctl directly. +        #[cfg(apple)] +        let r = unsafe { +            weak! { fn ptsname_r(c::c_int, *mut c::c_char, c::size_t) -> c::c_int } + +            if let Some(libc_ptsname_r) = ptsname_r.get() { +                libc_ptsname_r(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) +            } else { +                // The size declared in the `TIOCPTYGNAME` macro in +                // sys/ttycom.h is 128. +                let mut name: [u8; 128] = [0_u8; 128]; +                match c::ioctl(borrowed_fd(fd), c::TIOCPTYGNAME as _, &mut name) { +                    0 => { +                        let len = CStr::from_ptr(name.as_ptr().cast()).to_bytes().len(); +                        std::ptr::copy_nonoverlapping(name.as_ptr(), buffer.as_mut_ptr(), len + 1); +                        0 +                    } +                    _ => libc_errno::errno().0, +                } +            } +        }; + +        if r == 0 { +            return Ok(unsafe { CStr::from_ptr(buffer.as_ptr().cast()).to_owned() }); +        } +        if r != c::ERANGE { +            return Err(io::Errno::from_raw_os_error(r)); +        } + +        // Use `Vec` reallocation strategy to grow capacity exponentially. +        buffer.reserve(1); +        buffer.resize(buffer.capacity(), 0_u8); +    } +} + +#[inline] +pub(crate) fn unlockpt(fd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { ret(c::unlockpt(borrowed_fd(fd))) } +} + +#[cfg(not(linux_kernel))] +#[inline] +pub(crate) fn grantpt(fd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { ret(c::grantpt(borrowed_fd(fd))) } +} diff --git a/vendor/rustix/src/backend/libc/rand/mod.rs b/vendor/rustix/src/backend/libc/rand/mod.rs new file mode 100644 index 0000000..1e0181a --- /dev/null +++ b/vendor/rustix/src/backend/libc/rand/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix/src/backend/libc/rand/syscalls.rs b/vendor/rustix/src/backend/libc/rand/syscalls.rs new file mode 100644 index 0000000..3a3929e --- /dev/null +++ b/vendor/rustix/src/backend/libc/rand/syscalls.rs @@ -0,0 +1,18 @@ +//! libc syscalls supporting `rustix::rand`. + +#[cfg(linux_kernel)] +use {crate::backend::c, crate::backend::conv::ret_usize, crate::io, crate::rand::GetRandomFlags}; + +#[cfg(linux_kernel)] +pub(crate) unsafe fn getrandom( +    buf: *mut u8, +    cap: usize, +    flags: GetRandomFlags, +) -> io::Result<usize> { +    // `getrandom` wasn't supported in glibc until 2.25. +    weak_or_syscall! { +        fn getrandom(buf: *mut c::c_void, buflen: c::size_t, flags: c::c_uint) via SYS_getrandom -> c::ssize_t +    } + +    ret_usize(getrandom(buf.cast(), cap, flags.bits())) +} diff --git a/vendor/rustix/src/backend/libc/rand/types.rs b/vendor/rustix/src/backend/libc/rand/types.rs new file mode 100644 index 0000000..46690b5 --- /dev/null +++ b/vendor/rustix/src/backend/libc/rand/types.rs @@ -0,0 +1,24 @@ +#[cfg(linux_kernel)] +use crate::backend::c; +#[cfg(linux_kernel)] +use bitflags::bitflags; + +#[cfg(linux_kernel)] +bitflags! { +    /// `GRND_*` flags for use with [`getrandom`]. +    /// +    /// [`getrandom`]: crate::rand::getrandom +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct GetRandomFlags: u32 { +        /// `GRND_RANDOM` +        const RANDOM = c::GRND_RANDOM; +        /// `GRND_NONBLOCK` +        const NONBLOCK = c::GRND_NONBLOCK; +        /// `GRND_INSECURE` +        const INSECURE = c::GRND_INSECURE; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} diff --git a/vendor/rustix/src/backend/libc/shm/mod.rs b/vendor/rustix/src/backend/libc/shm/mod.rs new file mode 100644 index 0000000..1e0181a --- /dev/null +++ b/vendor/rustix/src/backend/libc/shm/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix/src/backend/libc/shm/syscalls.rs b/vendor/rustix/src/backend/libc/shm/syscalls.rs new file mode 100644 index 0000000..b0d907f --- /dev/null +++ b/vendor/rustix/src/backend/libc/shm/syscalls.rs @@ -0,0 +1,25 @@ +use crate::ffi::CStr; + +use crate::backend::c; +use crate::backend::conv::{c_str, ret, ret_owned_fd}; +use crate::fd::OwnedFd; +use crate::fs::Mode; +use crate::io; +use crate::shm::ShmOFlags; + +pub(crate) fn shm_open(name: &CStr, oflags: ShmOFlags, mode: Mode) -> io::Result<OwnedFd> { +    // On this platforms, `mode_t` is `u16` and can't be passed directly to a +    // variadic function. +    #[cfg(apple)] +    let mode: c::c_uint = mode.bits().into(); + +    // Otherwise, cast to `mode_t` as that's what `open` is documented to take. +    #[cfg(not(apple))] +    let mode: c::mode_t = mode.bits() as _; + +    unsafe { ret_owned_fd(c::shm_open(c_str(name), bitflags_bits!(oflags), mode)) } +} + +pub(crate) fn shm_unlink(name: &CStr) -> io::Result<()> { +    unsafe { ret(c::shm_unlink(c_str(name))) } +} diff --git a/vendor/rustix/src/backend/libc/shm/types.rs b/vendor/rustix/src/backend/libc/shm/types.rs new file mode 100644 index 0000000..6575ef5 --- /dev/null +++ b/vendor/rustix/src/backend/libc/shm/types.rs @@ -0,0 +1,30 @@ +use crate::backend::c; +use bitflags::bitflags; + +bitflags! { +    /// `O_*` constants for use with [`shm_open`]. +    /// +    /// [`shm_open`]: crate:shm::shm_open +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct ShmOFlags: u32 { +        /// `O_CREAT` +        #[doc(alias = "CREAT")] +        const CREATE = bitcast!(c::O_CREAT); + +        /// `O_EXCL` +        const EXCL = bitcast!(c::O_EXCL); + +        /// `O_RDONLY` +        const RDONLY = bitcast!(c::O_RDONLY); + +        /// `O_RDWR` +        const RDWR = bitcast!(c::O_RDWR); + +        /// `O_TRUNC` +        const TRUNC = bitcast!(c::O_TRUNC); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} diff --git a/vendor/rustix/src/backend/libc/system/mod.rs b/vendor/rustix/src/backend/libc/system/mod.rs new file mode 100644 index 0000000..bff7fd5 --- /dev/null +++ b/vendor/rustix/src/backend/libc/system/mod.rs @@ -0,0 +1,3 @@ +#[cfg(not(windows))] +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix/src/backend/libc/system/syscalls.rs b/vendor/rustix/src/backend/libc/system/syscalls.rs new file mode 100644 index 0000000..05d674b --- /dev/null +++ b/vendor/rustix/src/backend/libc/system/syscalls.rs @@ -0,0 +1,67 @@ +//! libc syscalls supporting `rustix::process`. + +use super::types::RawUname; +use crate::backend::c; +#[cfg(not(target_os = "wasi"))] +use crate::backend::conv::ret_infallible; +#[cfg(target_os = "linux")] +use crate::system::RebootCommand; +#[cfg(linux_kernel)] +use crate::system::Sysinfo; +use core::mem::MaybeUninit; +#[cfg(not(any( +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +use {crate::backend::conv::ret, crate::io}; + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn uname() -> RawUname { +    let mut uname = MaybeUninit::<RawUname>::uninit(); +    unsafe { +        let r = c::uname(uname.as_mut_ptr()); + +        // On POSIX, `uname` is documented to return non-negative on success +        // instead of the usual 0, though some specific systems do document +        // that they always use zero allowing us to skip this check. +        #[cfg(not(any(apple, freebsdlike, linux_like, target_os = "netbsd")))] +        let r = core::cmp::min(r, 0); + +        ret_infallible(r); +        uname.assume_init() +    } +} + +#[cfg(linux_kernel)] +pub(crate) fn sysinfo() -> Sysinfo { +    let mut info = MaybeUninit::<Sysinfo>::uninit(); +    unsafe { +        ret_infallible(c::sysinfo(info.as_mut_ptr())); +        info.assume_init() +    } +} + +#[cfg(not(any( +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub(crate) fn sethostname(name: &[u8]) -> io::Result<()> { +    unsafe { +        ret(c::sethostname( +            name.as_ptr().cast(), +            name.len().try_into().map_err(|_| io::Errno::INVAL)?, +        )) +    } +} + +#[cfg(target_os = "linux")] +pub(crate) fn reboot(cmd: RebootCommand) -> io::Result<()> { +    unsafe { ret(c::reboot(cmd as i32)) } +} diff --git a/vendor/rustix/src/backend/libc/system/types.rs b/vendor/rustix/src/backend/libc/system/types.rs new file mode 100644 index 0000000..731e89b --- /dev/null +++ b/vendor/rustix/src/backend/libc/system/types.rs @@ -0,0 +1,8 @@ +use crate::backend::c; + +/// `sysinfo` +#[cfg(linux_kernel)] +pub type Sysinfo = c::sysinfo; + +#[cfg(not(target_os = "wasi"))] +pub(crate) type RawUname = c::utsname; diff --git a/vendor/rustix/src/backend/libc/termios/mod.rs b/vendor/rustix/src/backend/libc/termios/mod.rs new file mode 100644 index 0000000..ef944f0 --- /dev/null +++ b/vendor/rustix/src/backend/libc/termios/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix/src/backend/libc/termios/syscalls.rs b/vendor/rustix/src/backend/libc/termios/syscalls.rs new file mode 100644 index 0000000..a833aea --- /dev/null +++ b/vendor/rustix/src/backend/libc/termios/syscalls.rs @@ -0,0 +1,403 @@ +//! libc syscalls supporting `rustix::termios`. +//! +//! # Safety +//! +//! See the `rustix::backend::syscalls` module documentation for details. + +use crate::backend::c; +#[cfg(not(target_os = "wasi"))] +use crate::backend::conv::ret_pid_t; +use crate::backend::conv::{borrowed_fd, ret}; +use crate::fd::BorrowedFd; +#[cfg(all(feature = "alloc", feature = "procfs"))] +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +use crate::ffi::CStr; +#[cfg(any( +    not(target_os = "espidf"), +    all( +        feature = "procfs", +        not(any(target_os = "fuchsia", target_os = "wasi")) +    ) +))] +use core::mem::MaybeUninit; +#[cfg(not(target_os = "wasi"))] +use {crate::io, crate::pid::Pid}; +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +use { +    crate::termios::{Action, OptionalActions, QueueSelector, Termios, Winsize}, +    crate::utils::as_mut_ptr, +}; + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) fn tcgetattr(fd: BorrowedFd<'_>) -> io::Result<Termios> { +    // If we have `TCGETS2`, use it, so that we fill in the `c_ispeed` and +    // `c_ospeed` fields. +    #[cfg(linux_kernel)] +    { +        use crate::termios::{ControlModes, InputModes, LocalModes, OutputModes, SpecialCodes}; +        use crate::utils::default_array; + +        let termios2 = unsafe { +            let mut termios2 = MaybeUninit::<c::termios2>::uninit(); + +            // QEMU's `TCGETS2` doesn't currently set `input_speed` or +            // `output_speed` on PowerPC, so zero out the fields ourselves. +            #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +            { +                termios2.write(core::mem::zeroed()); +            } + +            ret(c::ioctl( +                borrowed_fd(fd), +                c::TCGETS2 as _, +                termios2.as_mut_ptr(), +            ))?; + +            termios2.assume_init() +        }; + +        // Convert from the Linux `termios2` to our `Termios`. +        let mut result = Termios { +            input_modes: InputModes::from_bits_retain(termios2.c_iflag), +            output_modes: OutputModes::from_bits_retain(termios2.c_oflag), +            control_modes: ControlModes::from_bits_retain(termios2.c_cflag), +            local_modes: LocalModes::from_bits_retain(termios2.c_lflag), +            line_discipline: termios2.c_line, +            special_codes: SpecialCodes(default_array()), +            input_speed: termios2.c_ispeed, +            output_speed: termios2.c_ospeed, +        }; + +        // QEMU's `TCGETS2` doesn't currently set `input_speed` or +        // `output_speed` on PowerPC, so set them manually if we can. +        #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +        { +            use crate::termios::speed; + +            if result.output_speed == 0 && (termios2.c_cflag & c::CBAUD) != c::BOTHER { +                if let Some(output_speed) = speed::decode(termios2.c_cflag & c::CBAUD) { +                    result.output_speed = output_speed; +                } +            } +            if result.input_speed == 0 +                && ((termios2.c_cflag & c::CIBAUD) >> c::IBSHIFT) != c::BOTHER +            { +                // For input speeds, `B0` is special-cased to mean the input +                // speed is the same as the output speed. +                if ((termios2.c_cflag & c::CIBAUD) >> c::IBSHIFT) == c::B0 { +                    result.input_speed = result.output_speed; +                } else if let Some(input_speed) = +                    speed::decode((termios2.c_cflag & c::CIBAUD) >> c::IBSHIFT) +                { +                    result.input_speed = input_speed; +                } +            } +        } + +        result.special_codes.0[..termios2.c_cc.len()].copy_from_slice(&termios2.c_cc); + +        Ok(result) +    } + +    #[cfg(not(linux_kernel))] +    unsafe { +        let mut result = MaybeUninit::<Termios>::uninit(); + +        // `result` is a `Termios` which starts with the same layout as +        // `libc::termios`, so we can cast the pointer. +        ret(c::tcgetattr(borrowed_fd(fd), result.as_mut_ptr().cast()))?; + +        Ok(result.assume_init()) +    } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcgetpgrp(fd: BorrowedFd<'_>) -> io::Result<Pid> { +    unsafe { +        let pid = ret_pid_t(c::tcgetpgrp(borrowed_fd(fd)))?; + +        // This doesn't appear to be documented, but on Linux, it appears +        // `tcsetpgrp` can succceed and set the pid to 0 if we pass it a +        // pseudo-terminal device fd. For now, translate it into `OPNOTSUPP`. +        #[cfg(linux_kernel)] +        if pid == 0 { +            return Err(io::Errno::OPNOTSUPP); +        } + +        Ok(Pid::from_raw_unchecked(pid)) +    } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcsetpgrp(fd: BorrowedFd<'_>, pid: Pid) -> io::Result<()> { +    unsafe { ret(c::tcsetpgrp(borrowed_fd(fd), pid.as_raw_nonzero().get())) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) fn tcsetattr( +    fd: BorrowedFd<'_>, +    optional_actions: OptionalActions, +    termios: &Termios, +) -> io::Result<()> { +    // If we have `TCSETS2`, use it, so that we use the `c_ispeed` and +    // `c_ospeed` fields. +    #[cfg(linux_kernel)] +    { +        use crate::termios::speed; +        use crate::utils::default_array; +        use linux_raw_sys::general::{termios2, BOTHER, CBAUD, IBSHIFT}; + +        #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] +        use linux_raw_sys::ioctl::{TCSETS, TCSETS2}; + +        // linux-raw-sys' ioctl-generation script for sparc isn't working yet, +        // so as a temporary workaround, declare these manually. +        #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] +        const TCSETS: u32 = 0x8024_5409; +        #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] +        const TCSETS2: u32 = 0x802c_540d; + +        // Translate from `optional_actions` into an ioctl request code. On +        // MIPS, `optional_actions` already has `TCGETS` added to it. +        let request = TCSETS2 +            + if cfg!(any( +                target_arch = "mips", +                target_arch = "mips32r6", +                target_arch = "mips64", +                target_arch = "mips64r6" +            )) { +                optional_actions as u32 - TCSETS +            } else { +                optional_actions as u32 +            }; + +        let input_speed = termios.input_speed(); +        let output_speed = termios.output_speed(); +        let mut termios2 = termios2 { +            c_iflag: termios.input_modes.bits(), +            c_oflag: termios.output_modes.bits(), +            c_cflag: termios.control_modes.bits(), +            c_lflag: termios.local_modes.bits(), +            c_line: termios.line_discipline, +            c_cc: default_array(), +            c_ispeed: input_speed, +            c_ospeed: output_speed, +        }; +        // Ensure that our input and output speeds are set, as `libc` +        // routines don't always support setting these separately. +        termios2.c_cflag &= !CBAUD; +        termios2.c_cflag |= speed::encode(output_speed).unwrap_or(BOTHER); +        termios2.c_cflag &= !(CBAUD << IBSHIFT); +        termios2.c_cflag |= speed::encode(input_speed).unwrap_or(BOTHER) << IBSHIFT; +        let nccs = termios2.c_cc.len(); +        termios2 +            .c_cc +            .copy_from_slice(&termios.special_codes.0[..nccs]); + +        unsafe { ret(c::ioctl(borrowed_fd(fd), request as _, &termios2)) } +    } + +    #[cfg(not(linux_kernel))] +    unsafe { +        ret(c::tcsetattr( +            borrowed_fd(fd), +            optional_actions as _, +            crate::utils::as_ptr(termios).cast(), +        )) +    } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcsendbreak(fd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { ret(c::tcsendbreak(borrowed_fd(fd), 0)) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) fn tcdrain(fd: BorrowedFd<'_>) -> io::Result<()> { +    unsafe { ret(c::tcdrain(borrowed_fd(fd))) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) fn tcflush(fd: BorrowedFd<'_>, queue_selector: QueueSelector) -> io::Result<()> { +    unsafe { ret(c::tcflush(borrowed_fd(fd), queue_selector as _)) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) fn tcflow(fd: BorrowedFd<'_>, action: Action) -> io::Result<()> { +    unsafe { ret(c::tcflow(borrowed_fd(fd), action as _)) } +} + +#[cfg(not(target_os = "wasi"))] +pub(crate) fn tcgetsid(fd: BorrowedFd<'_>) -> io::Result<Pid> { +    unsafe { +        let pid = ret_pid_t(c::tcgetsid(borrowed_fd(fd)))?; +        Ok(Pid::from_raw_unchecked(pid)) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) fn tcsetwinsize(fd: BorrowedFd<'_>, winsize: Winsize) -> io::Result<()> { +    unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCSWINSZ, &winsize)) } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub(crate) fn tcgetwinsize(fd: BorrowedFd<'_>) -> io::Result<Winsize> { +    unsafe { +        let mut buf = MaybeUninit::<Winsize>::uninit(); +        ret(c::ioctl( +            borrowed_fd(fd), +            c::TIOCGWINSZ.into(), +            buf.as_mut_ptr(), +        ))?; +        Ok(buf.assume_init()) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "nto", target_os = "wasi")))] +#[inline] +pub(crate) fn set_speed(termios: &mut Termios, arbitrary_speed: u32) -> io::Result<()> { +    #[cfg(bsd)] +    let encoded_speed = arbitrary_speed; + +    #[cfg(not(bsd))] +    let encoded_speed = match crate::termios::speed::encode(arbitrary_speed) { +        Some(encoded_speed) => encoded_speed, +        #[cfg(linux_kernel)] +        None => c::BOTHER, +        #[cfg(not(linux_kernel))] +        None => return Err(io::Errno::INVAL), +    }; + +    #[cfg(not(linux_kernel))] +    unsafe { +        ret(c::cfsetspeed( +            as_mut_ptr(termios).cast(), +            encoded_speed.into(), +        )) +    } + +    // Linux libc implementations don't support arbitrary speeds, so we encode +    // the speed manually. +    #[cfg(linux_kernel)] +    { +        use crate::termios::ControlModes; + +        debug_assert_eq!(encoded_speed & !c::CBAUD, 0); + +        termios.control_modes -= ControlModes::from_bits_retain(c::CBAUD | c::CIBAUD); +        termios.control_modes |= +            ControlModes::from_bits_retain(encoded_speed | (encoded_speed << c::IBSHIFT)); + +        termios.input_speed = arbitrary_speed; +        termios.output_speed = arbitrary_speed; + +        Ok(()) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[inline] +pub(crate) fn set_output_speed(termios: &mut Termios, arbitrary_speed: u32) -> io::Result<()> { +    #[cfg(bsd)] +    let encoded_speed = arbitrary_speed; + +    #[cfg(not(bsd))] +    let encoded_speed = match crate::termios::speed::encode(arbitrary_speed) { +        Some(encoded_speed) => encoded_speed, +        #[cfg(linux_kernel)] +        None => c::BOTHER, +        #[cfg(not(linux_kernel))] +        None => return Err(io::Errno::INVAL), +    }; + +    #[cfg(not(linux_kernel))] +    unsafe { +        ret(c::cfsetospeed( +            as_mut_ptr(termios).cast(), +            encoded_speed.into(), +        )) +    } + +    // Linux libc implementations don't support arbitrary speeds or setting the +    // input and output speeds separately, so we encode the speed manually. +    #[cfg(linux_kernel)] +    { +        use crate::termios::ControlModes; + +        debug_assert_eq!(encoded_speed & !c::CBAUD, 0); + +        termios.control_modes -= ControlModes::from_bits_retain(c::CBAUD); +        termios.control_modes |= ControlModes::from_bits_retain(encoded_speed); + +        termios.output_speed = arbitrary_speed; + +        Ok(()) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[inline] +pub(crate) fn set_input_speed(termios: &mut Termios, arbitrary_speed: u32) -> io::Result<()> { +    #[cfg(bsd)] +    let encoded_speed = arbitrary_speed; + +    #[cfg(not(bsd))] +    let encoded_speed = match crate::termios::speed::encode(arbitrary_speed) { +        Some(encoded_speed) => encoded_speed, +        #[cfg(linux_kernel)] +        None => c::BOTHER, +        #[cfg(not(linux_kernel))] +        None => return Err(io::Errno::INVAL), +    }; + +    #[cfg(not(linux_kernel))] +    unsafe { +        ret(c::cfsetispeed( +            as_mut_ptr(termios).cast(), +            encoded_speed.into(), +        )) +    } + +    // Linux libc implementations don't support arbitrary speeds or setting the +    // input and output speeds separately, so we encode the speed manually. +    #[cfg(linux_kernel)] +    { +        use crate::termios::ControlModes; + +        debug_assert_eq!(encoded_speed & !c::CBAUD, 0); + +        termios.control_modes -= ControlModes::from_bits_retain(c::CIBAUD); +        termios.control_modes |= ControlModes::from_bits_retain(encoded_speed << c::IBSHIFT); + +        termios.input_speed = arbitrary_speed; + +        Ok(()) +    } +} + +#[cfg(not(any(target_os = "espidf", target_os = "nto", target_os = "wasi")))] +#[inline] +pub(crate) fn cfmakeraw(termios: &mut Termios) { +    unsafe { c::cfmakeraw(as_mut_ptr(termios).cast()) } +} + +pub(crate) fn isatty(fd: BorrowedFd<'_>) -> bool { +    // Use the return value of `isatty` alone. We don't check `errno` because +    // we return `bool` rather than `io::Result<bool>`, because we assume +    // `BorrowedFd` protects us from `EBADF`, and any other reasonably +    // anticipated `errno` value would end up interpreted as “assume it's not a +    // terminal” anyway. +    unsafe { c::isatty(borrowed_fd(fd)) != 0 } +} + +#[cfg(all(feature = "alloc", feature = "procfs"))] +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +pub(crate) fn ttyname(dirfd: BorrowedFd<'_>, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> { +    unsafe { +        // `ttyname_r` returns its error status rather than using `errno`. +        match c::ttyname_r(borrowed_fd(dirfd), buf.as_mut_ptr().cast(), buf.len()) { +            0 => Ok(CStr::from_ptr(buf.as_ptr().cast()).to_bytes().len()), +            err => Err(io::Errno::from_raw_os_error(err)), +        } +    } +} diff --git a/vendor/rustix/src/backend/libc/thread/futex.rs b/vendor/rustix/src/backend/libc/thread/futex.rs new file mode 100644 index 0000000..44d96f0 --- /dev/null +++ b/vendor/rustix/src/backend/libc/thread/futex.rs @@ -0,0 +1,43 @@ +use crate::backend::c; + +bitflags::bitflags! { +    /// `FUTEX_*` flags for use with [`futex`]. +    /// +    /// [`futex`]: crate::thread::futex +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct FutexFlags: u32 { +        /// `FUTEX_PRIVATE_FLAG` +        const PRIVATE = bitcast!(c::FUTEX_PRIVATE_FLAG); +        /// `FUTEX_CLOCK_REALTIME` +        const CLOCK_REALTIME = bitcast!(c::FUTEX_CLOCK_REALTIME); +    } +} + +/// `FUTEX_*` operations for use with [`futex`]. +/// +/// [`futex`]: crate::thread::futex +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +pub enum FutexOperation { +    /// `FUTEX_WAIT` +    Wait = bitcast!(c::FUTEX_WAIT), +    /// `FUTEX_WAKE` +    Wake = bitcast!(c::FUTEX_WAKE), +    /// `FUTEX_FD` +    Fd = bitcast!(c::FUTEX_FD), +    /// `FUTEX_REQUEUE` +    Requeue = bitcast!(c::FUTEX_REQUEUE), +    /// `FUTEX_CMP_REQUEUE` +    CmpRequeue = bitcast!(c::FUTEX_CMP_REQUEUE), +    /// `FUTEX_WAKE_OP` +    WakeOp = bitcast!(c::FUTEX_WAKE_OP), +    /// `FUTEX_LOCK_PI` +    LockPi = bitcast!(c::FUTEX_LOCK_PI), +    /// `FUTEX_UNLOCK_PI` +    UnlockPi = bitcast!(c::FUTEX_UNLOCK_PI), +    /// `FUTEX_TRYLOCK_PI` +    TrylockPi = bitcast!(c::FUTEX_TRYLOCK_PI), +    /// `FUTEX_WAIT_BITSET` +    WaitBitset = bitcast!(c::FUTEX_WAIT_BITSET), +} diff --git a/vendor/rustix/src/backend/libc/thread/mod.rs b/vendor/rustix/src/backend/libc/thread/mod.rs new file mode 100644 index 0000000..4f8c87c --- /dev/null +++ b/vendor/rustix/src/backend/libc/thread/mod.rs @@ -0,0 +1,4 @@ +#[cfg(linux_kernel)] +pub(crate) mod futex; +#[cfg(not(windows))] +pub(crate) mod syscalls; diff --git a/vendor/rustix/src/backend/libc/thread/syscalls.rs b/vendor/rustix/src/backend/libc/thread/syscalls.rs new file mode 100644 index 0000000..33750f4 --- /dev/null +++ b/vendor/rustix/src/backend/libc/thread/syscalls.rs @@ -0,0 +1,523 @@ +//! libc syscalls supporting `rustix::thread`. + +use crate::backend::c; +use crate::backend::conv::ret; +use crate::io; +#[cfg(not(target_os = "redox"))] +use crate::thread::{NanosleepRelativeResult, Timespec}; +#[cfg(all(target_env = "gnu", fix_y2038))] +use crate::timespec::LibcTimespec; +use core::mem::MaybeUninit; +#[cfg(linux_kernel)] +use { +    crate::backend::conv::{borrowed_fd, ret_c_int, ret_usize}, +    crate::fd::BorrowedFd, +    crate::pid::Pid, +    crate::thread::{FutexFlags, FutexOperation}, +    crate::utils::as_mut_ptr, +}; +#[cfg(not(any( +    apple, +    freebsdlike, +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "haiku", +    target_os = "openbsd", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +use {crate::thread::ClockId, core::ptr::null_mut}; + +#[cfg(all(target_env = "gnu", fix_y2038))] +weak!(fn __clock_nanosleep_time64(c::clockid_t, c::c_int, *const LibcTimespec, *mut LibcTimespec) -> c::c_int); +#[cfg(all(target_env = "gnu", fix_y2038))] +weak!(fn __nanosleep64(*const LibcTimespec, *mut LibcTimespec) -> c::c_int); + +#[cfg(not(any( +    apple, +    target_os = "dragonfly", +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11. +    target_os = "haiku", +    target_os = "openbsd", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +#[inline] +pub(crate) fn clock_nanosleep_relative(id: ClockId, request: &Timespec) -> NanosleepRelativeResult { +    // Old 32-bit version: libc has `clock_nanosleep` but it is not y2038 safe +    // by default. But there may be a `__clock_nanosleep_time64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_clock_nanosleep) = __clock_nanosleep_time64.get() { +            let flags = 0; +            let mut remain = MaybeUninit::<LibcTimespec>::uninit(); + +            unsafe { +                return match libc_clock_nanosleep( +                    id as c::clockid_t, +                    flags, +                    &request.clone().into(), +                    remain.as_mut_ptr(), +                ) { +                    0 => NanosleepRelativeResult::Ok, +                    err if err == io::Errno::INTR.0 => { +                        NanosleepRelativeResult::Interrupted(remain.assume_init().into()) +                    } +                    err => NanosleepRelativeResult::Err(io::Errno(err)), +                }; +            } +        } + +        clock_nanosleep_relative_old(id, request) +    } + +    // Main version: libc is y2038 safe and has `clock_nanosleep`. +    #[cfg(not(fix_y2038))] +    unsafe { +        let flags = 0; +        let mut remain = MaybeUninit::<Timespec>::uninit(); + +        match c::clock_nanosleep(id as c::clockid_t, flags, request, remain.as_mut_ptr()) { +            0 => NanosleepRelativeResult::Ok, +            err if err == io::Errno::INTR.0 => { +                NanosleepRelativeResult::Interrupted(remain.assume_init()) +            } +            err => NanosleepRelativeResult::Err(io::Errno(err)), +        } +    } +} + +#[cfg(all( +    fix_y2038, +    not(any( +        apple, +        target_os = "emscripten", +        target_os = "haiku", +        target_os = "vita" +    )) +))] +fn clock_nanosleep_relative_old(id: ClockId, request: &Timespec) -> NanosleepRelativeResult { +    let tv_sec = match request.tv_sec.try_into() { +        Ok(tv_sec) => tv_sec, +        Err(_) => return NanosleepRelativeResult::Err(io::Errno::OVERFLOW), +    }; +    let tv_nsec = match request.tv_nsec.try_into() { +        Ok(tv_nsec) => tv_nsec, +        Err(_) => return NanosleepRelativeResult::Err(io::Errno::INVAL), +    }; +    let old_request = c::timespec { tv_sec, tv_nsec }; +    let mut old_remain = MaybeUninit::<c::timespec>::uninit(); +    let flags = 0; + +    unsafe { +        match c::clock_nanosleep( +            id as c::clockid_t, +            flags, +            &old_request, +            old_remain.as_mut_ptr(), +        ) { +            0 => NanosleepRelativeResult::Ok, +            err if err == io::Errno::INTR.0 => { +                let old_remain = old_remain.assume_init(); +                let remain = Timespec { +                    tv_sec: old_remain.tv_sec.into(), +                    tv_nsec: old_remain.tv_nsec.into(), +                }; +                NanosleepRelativeResult::Interrupted(remain) +            } +            err => NanosleepRelativeResult::Err(io::Errno(err)), +        } +    } +} + +#[cfg(not(any( +    apple, +    target_os = "dragonfly", +    target_os = "emscripten", +    target_os = "espidf", +    target_os = "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11. +    target_os = "haiku", +    target_os = "openbsd", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi", +)))] +#[inline] +pub(crate) fn clock_nanosleep_absolute(id: ClockId, request: &Timespec) -> io::Result<()> { +    // Old 32-bit version: libc has `clock_nanosleep` but it is not y2038 safe +    // by default. But there may be a `__clock_nanosleep_time64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_clock_nanosleep) = __clock_nanosleep_time64.get() { +            let flags = c::TIMER_ABSTIME; +            unsafe { +                return match { +                    libc_clock_nanosleep( +                        id as c::clockid_t, +                        flags, +                        &request.clone().into(), +                        null_mut(), +                    ) +                } { +                    0 => Ok(()), +                    err => Err(io::Errno(err)), +                }; +            } +        } + +        clock_nanosleep_absolute_old(id, request) +    } + +    // Main version: libc is y2038 safe and has `clock_nanosleep`. +    #[cfg(not(fix_y2038))] +    { +        let flags = c::TIMER_ABSTIME; + +        match unsafe { c::clock_nanosleep(id as c::clockid_t, flags as _, request, null_mut()) } { +            0 => Ok(()), +            err => Err(io::Errno(err)), +        } +    } +} + +#[cfg(all( +    fix_y2038, +    not(any( +        apple, +        target_os = "emscripten", +        target_os = "haiku", +        target_os = "vita" +    )) +))] +fn clock_nanosleep_absolute_old(id: ClockId, request: &Timespec) -> io::Result<()> { +    let flags = c::TIMER_ABSTIME; + +    let old_request = c::timespec { +        tv_sec: request.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?, +        tv_nsec: request.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, +    }; +    match unsafe { c::clock_nanosleep(id as c::clockid_t, flags, &old_request, null_mut()) } { +        0 => Ok(()), +        err => Err(io::Errno(err)), +    } +} + +#[cfg(not(target_os = "redox"))] +#[inline] +pub(crate) fn nanosleep(request: &Timespec) -> NanosleepRelativeResult { +    // Old 32-bit version: libc has `nanosleep` but it is not y2038 safe by +    // default. But there may be a `__nanosleep64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_nanosleep) = __nanosleep64.get() { +            let mut remain = MaybeUninit::<LibcTimespec>::uninit(); +            unsafe { +                return match ret(libc_nanosleep(&request.clone().into(), remain.as_mut_ptr())) { +                    Ok(()) => NanosleepRelativeResult::Ok, +                    Err(io::Errno::INTR) => { +                        NanosleepRelativeResult::Interrupted(remain.assume_init().into()) +                    } +                    Err(err) => NanosleepRelativeResult::Err(err), +                }; +            } +        } + +        nanosleep_old(request) +    } + +    // Main version: libc is y2038 safe and has `nanosleep`. +    #[cfg(not(fix_y2038))] +    unsafe { +        let mut remain = MaybeUninit::<Timespec>::uninit(); + +        match ret(c::nanosleep(request, remain.as_mut_ptr())) { +            Ok(()) => NanosleepRelativeResult::Ok, +            Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(remain.assume_init()), +            Err(err) => NanosleepRelativeResult::Err(err), +        } +    } +} + +#[cfg(fix_y2038)] +fn nanosleep_old(request: &Timespec) -> NanosleepRelativeResult { +    let tv_sec = match request.tv_sec.try_into() { +        Ok(tv_sec) => tv_sec, +        Err(_) => return NanosleepRelativeResult::Err(io::Errno::OVERFLOW), +    }; +    let tv_nsec = match request.tv_nsec.try_into() { +        Ok(tv_nsec) => tv_nsec, +        Err(_) => return NanosleepRelativeResult::Err(io::Errno::INVAL), +    }; +    let old_request = c::timespec { tv_sec, tv_nsec }; +    let mut old_remain = MaybeUninit::<c::timespec>::uninit(); + +    unsafe { +        match ret(c::nanosleep(&old_request, old_remain.as_mut_ptr())) { +            Ok(()) => NanosleepRelativeResult::Ok, +            Err(io::Errno::INTR) => { +                let old_remain = old_remain.assume_init(); +                let remain = Timespec { +                    tv_sec: old_remain.tv_sec.into(), +                    tv_nsec: old_remain.tv_nsec.into(), +                }; +                NanosleepRelativeResult::Interrupted(remain) +            } +            Err(err) => NanosleepRelativeResult::Err(err), +        } +    } +} + +#[cfg(linux_kernel)] +#[inline] +#[must_use] +pub(crate) fn gettid() -> Pid { +    // `gettid` wasn't supported in glibc until 2.30, and musl until 1.2.2, +    // so use `syscall`. +    // <https://sourceware.org/bugzilla/show_bug.cgi?id=6399#c62> +    weak_or_syscall! { +        fn gettid() via SYS_gettid -> c::pid_t +    } + +    unsafe { +        let tid = gettid(); +        Pid::from_raw_unchecked(tid) +    } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn setns(fd: BorrowedFd<'_>, nstype: c::c_int) -> io::Result<c::c_int> { +    // `setns` wasn't supported in glibc until 2.14, and musl until 0.9.5, +    // so use `syscall`. +    weak_or_syscall! { +        fn setns(fd: c::c_int, nstype: c::c_int) via SYS_setns -> c::c_int +    } + +    unsafe { ret_c_int(setns(borrowed_fd(fd), nstype)) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> { +    unsafe { ret(c::unshare(flags.bits() as i32)) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn capget( +    header: &mut linux_raw_sys::general::__user_cap_header_struct, +    data: &mut [MaybeUninit<linux_raw_sys::general::__user_cap_data_struct>], +) -> io::Result<()> { +    syscall! { +        fn capget( +            hdrp: *mut linux_raw_sys::general::__user_cap_header_struct, +            data: *mut linux_raw_sys::general::__user_cap_data_struct +        ) via SYS_capget -> c::c_int +    } + +    unsafe { +        ret(capget( +            as_mut_ptr(header), +            data.as_mut_ptr() +                .cast::<linux_raw_sys::general::__user_cap_data_struct>(), +        )) +    } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn capset( +    header: &mut linux_raw_sys::general::__user_cap_header_struct, +    data: &[linux_raw_sys::general::__user_cap_data_struct], +) -> io::Result<()> { +    syscall! { +        fn capset( +            hdrp: *mut linux_raw_sys::general::__user_cap_header_struct, +            data: *const linux_raw_sys::general::__user_cap_data_struct +        ) via SYS_capset -> c::c_int +    } + +    unsafe { ret(capset(as_mut_ptr(header), data.as_ptr())) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn setuid_thread(uid: crate::ugid::Uid) -> io::Result<()> { +    syscall! { +        fn setuid(uid: c::uid_t) via SYS_setuid -> c::c_int +    } + +    unsafe { ret(setuid(uid.as_raw())) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn setresuid_thread( +    ruid: crate::ugid::Uid, +    euid: crate::ugid::Uid, +    suid: crate::ugid::Uid, +) -> io::Result<()> { +    #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))] +    const SYS: c::c_long = c::SYS_setresuid32 as c::c_long; +    #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))] +    const SYS: c::c_long = c::SYS_setresuid as c::c_long; + +    syscall! { +        fn setresuid(ruid: c::uid_t, euid: c::uid_t, suid: c::uid_t) via SYS -> c::c_int +    } + +    unsafe { ret(setresuid(ruid.as_raw(), euid.as_raw(), suid.as_raw())) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn setgid_thread(gid: crate::ugid::Gid) -> io::Result<()> { +    syscall! { +        fn setgid(gid: c::gid_t) via SYS_setgid -> c::c_int +    } + +    unsafe { ret(setgid(gid.as_raw())) } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn setresgid_thread( +    rgid: crate::ugid::Gid, +    egid: crate::ugid::Gid, +    sgid: crate::ugid::Gid, +) -> io::Result<()> { +    #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))] +    const SYS: c::c_long = c::SYS_setresgid32 as c::c_long; +    #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))] +    const SYS: c::c_long = c::SYS_setresgid as c::c_long; + +    syscall! { +        fn setresgid(rgid: c::gid_t, egid: c::gid_t, sgid: c::gid_t) via SYS -> c::c_int +    } + +    unsafe { ret(setresgid(rgid.as_raw(), egid.as_raw(), sgid.as_raw())) } +} + +// TODO: This could be de-multiplexed. +#[cfg(linux_kernel)] +pub(crate) unsafe fn futex( +    uaddr: *mut u32, +    op: FutexOperation, +    flags: FutexFlags, +    val: u32, +    utime: *const Timespec, +    uaddr2: *mut u32, +    val3: u32, +) -> io::Result<usize> { +    #[cfg(all( +        target_pointer_width = "32", +        not(any(target_arch = "aarch64", target_arch = "x86_64")) +    ))] +    { +        // TODO: Upstream this to the libc crate. +        #[allow(non_upper_case_globals)] +        const SYS_futex_time64: i32 = linux_raw_sys::general::__NR_futex_time64 as i32; + +        syscall! { +            fn futex_time64( +                uaddr: *mut u32, +                futex_op: c::c_int, +                val: u32, +                timeout: *const Timespec, +                uaddr2: *mut u32, +                val3: u32 +            ) via SYS_futex_time64 -> c::ssize_t +        } + +        ret_usize(futex_time64( +            uaddr, +            op as i32 | flags.bits() as i32, +            val, +            utime, +            uaddr2, +            val3, +        )) +        .or_else(|err| { +            // See the comments in `rustix_clock_gettime_via_syscall` about +            // emulation. +            if err == io::Errno::NOSYS { +                futex_old(uaddr, op, flags, val, utime, uaddr2, val3) +            } else { +                Err(err) +            } +        }) +    } + +    #[cfg(any( +        target_pointer_width = "64", +        target_arch = "aarch64", +        target_arch = "x86_64" +    ))] +    { +        syscall! { +            fn futex( +                uaddr: *mut u32, +                futex_op: c::c_int, +                val: u32, +                timeout: *const linux_raw_sys::general::__kernel_timespec, +                uaddr2: *mut u32, +                val3: u32 +            ) via SYS_futex -> c::c_long +        } + +        ret_usize(futex( +            uaddr, +            op as i32 | flags.bits() as i32, +            val, +            utime.cast(), +            uaddr2, +            val3, +        ) as isize) +    } +} + +#[cfg(linux_kernel)] +#[cfg(all( +    target_pointer_width = "32", +    not(any(target_arch = "aarch64", target_arch = "x86_64")) +))] +unsafe fn futex_old( +    uaddr: *mut u32, +    op: FutexOperation, +    flags: FutexFlags, +    val: u32, +    utime: *const Timespec, +    uaddr2: *mut u32, +    val3: u32, +) -> io::Result<usize> { +    syscall! { +        fn futex( +            uaddr: *mut u32, +            futex_op: c::c_int, +            val: u32, +            timeout: *const linux_raw_sys::general::__kernel_old_timespec, +            uaddr2: *mut u32, +            val3: u32 +        ) via SYS_futex -> c::c_long +    } + +    let old_utime = linux_raw_sys::general::__kernel_old_timespec { +        tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?, +        tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?, +    }; +    ret_usize(futex( +        uaddr, +        op as i32 | flags.bits() as i32, +        val, +        &old_utime, +        uaddr2, +        val3, +    ) as isize) +} diff --git a/vendor/rustix/src/backend/libc/time/mod.rs b/vendor/rustix/src/backend/libc/time/mod.rs new file mode 100644 index 0000000..bff7fd5 --- /dev/null +++ b/vendor/rustix/src/backend/libc/time/mod.rs @@ -0,0 +1,3 @@ +#[cfg(not(windows))] +pub(crate) mod syscalls; +pub(crate) mod types; diff --git a/vendor/rustix/src/backend/libc/time/syscalls.rs b/vendor/rustix/src/backend/libc/time/syscalls.rs new file mode 100644 index 0000000..6b1c9fd --- /dev/null +++ b/vendor/rustix/src/backend/libc/time/syscalls.rs @@ -0,0 +1,452 @@ +//! libc syscalls supporting `rustix::time`. + +use crate::backend::c; +use crate::backend::conv::ret; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(feature = "time")] +#[cfg(any(all(target_env = "gnu", fix_y2038), not(fix_y2038)))] +use crate::backend::time::types::LibcItimerspec; +#[cfg(not(target_os = "wasi"))] +use crate::clockid::{ClockId, DynamicClockId}; +use crate::io; +#[cfg(all(target_env = "gnu", fix_y2038))] +use crate::timespec::LibcTimespec; +use crate::timespec::Timespec; +use core::mem::MaybeUninit; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(feature = "time")] +use { +    crate::backend::conv::{borrowed_fd, ret_owned_fd}, +    crate::fd::{BorrowedFd, OwnedFd}, +    crate::time::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags}, +}; + +#[cfg(all(target_env = "gnu", fix_y2038))] +weak!(fn __clock_gettime64(c::clockid_t, *mut LibcTimespec) -> c::c_int); +#[cfg(all(target_env = "gnu", fix_y2038))] +weak!(fn __clock_settime64(c::clockid_t, *const LibcTimespec) -> c::c_int); +#[cfg(all(target_env = "gnu", fix_y2038))] +weak!(fn __clock_getres64(c::clockid_t, *mut LibcTimespec) -> c::c_int); +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(all(target_env = "gnu", fix_y2038))] +#[cfg(feature = "time")] +weak!(fn __timerfd_gettime64(c::c_int, *mut LibcItimerspec) -> c::c_int); +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(all(target_env = "gnu", fix_y2038))] +#[cfg(feature = "time")] +weak!(fn __timerfd_settime64(c::c_int, c::c_int, *const LibcItimerspec, *mut LibcItimerspec) -> c::c_int); + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[inline] +#[must_use] +pub(crate) fn clock_getres(id: ClockId) -> Timespec { +    // Old 32-bit version: libc has `clock_getres` but it is not y2038 safe by +    // default. But there may be a `__clock_getres64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_clock_getres) = __clock_getres64.get() { +            let mut timespec = MaybeUninit::<LibcTimespec>::uninit(); +            unsafe { +                ret(libc_clock_getres(id as c::clockid_t, timespec.as_mut_ptr())).unwrap(); +                return timespec.assume_init().into(); +            } +        } + +        clock_getres_old(id) +    } + +    // Main version: libc is y2038 safe and has `clock_getres`. +    #[cfg(not(fix_y2038))] +    unsafe { +        let mut timespec = MaybeUninit::<Timespec>::uninit(); +        let _ = c::clock_getres(id as c::clockid_t, timespec.as_mut_ptr()); +        timespec.assume_init() +    } +} + +#[cfg(fix_y2038)] +#[must_use] +fn clock_getres_old(id: ClockId) -> Timespec { +    let mut old_timespec = MaybeUninit::<c::timespec>::uninit(); + +    let old_timespec = unsafe { +        ret(c::clock_getres( +            id as c::clockid_t, +            old_timespec.as_mut_ptr(), +        )) +        .unwrap(); +        old_timespec.assume_init() +    }; + +    Timespec { +        tv_sec: old_timespec.tv_sec.into(), +        tv_nsec: old_timespec.tv_nsec.into(), +    } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn clock_gettime(id: ClockId) -> Timespec { +    // Old 32-bit version: libc has `clock_gettime` but it is not y2038 safe by +    // default. But there may be a `__clock_gettime64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_clock_gettime) = __clock_gettime64.get() { +            let mut timespec = MaybeUninit::<LibcTimespec>::uninit(); +            unsafe { +                ret(libc_clock_gettime( +                    id as c::clockid_t, +                    timespec.as_mut_ptr(), +                )) +                .unwrap(); +                return timespec.assume_init().into(); +            } +        } + +        clock_gettime_old(id) +    } + +    // Use `.unwrap()` here because `clock_getres` can fail if the clock itself +    // overflows a number of seconds, but if that happens, the monotonic clocks +    // can't maintain their invariants, or the realtime clocks aren't properly +    // configured. +    #[cfg(not(fix_y2038))] +    unsafe { +        let mut timespec = MaybeUninit::<Timespec>::uninit(); +        ret(c::clock_gettime(id as c::clockid_t, timespec.as_mut_ptr())).unwrap(); +        timespec.assume_init() +    } +} + +#[cfg(fix_y2038)] +#[must_use] +fn clock_gettime_old(id: ClockId) -> Timespec { +    let mut old_timespec = MaybeUninit::<c::timespec>::uninit(); + +    let old_timespec = unsafe { +        ret(c::clock_gettime( +            id as c::clockid_t, +            old_timespec.as_mut_ptr(), +        )) +        .unwrap(); +        old_timespec.assume_init() +    }; + +    Timespec { +        tv_sec: old_timespec.tv_sec.into(), +        tv_nsec: old_timespec.tv_nsec.into(), +    } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +pub(crate) fn clock_gettime_dynamic(id: DynamicClockId<'_>) -> io::Result<Timespec> { +    let id: c::clockid_t = match id { +        DynamicClockId::Known(id) => id as c::clockid_t, + +        #[cfg(linux_kernel)] +        DynamicClockId::Dynamic(fd) => { +            use crate::fd::AsRawFd; +            const CLOCKFD: i32 = 3; +            (!fd.as_raw_fd() << 3) | CLOCKFD +        } + +        #[cfg(not(linux_kernel))] +        DynamicClockId::Dynamic(_fd) => { +            // Dynamic clocks are not supported on this platform. +            return Err(io::Errno::INVAL); +        } + +        #[cfg(linux_kernel)] +        DynamicClockId::RealtimeAlarm => c::CLOCK_REALTIME_ALARM, + +        #[cfg(linux_kernel)] +        DynamicClockId::Tai => c::CLOCK_TAI, + +        #[cfg(any( +            freebsdlike, +            linux_kernel, +            target_os = "fuchsia", +            target_os = "openbsd" +        ))] +        DynamicClockId::Boottime => c::CLOCK_BOOTTIME, + +        #[cfg(any(linux_kernel, target_os = "fuchsia"))] +        DynamicClockId::BoottimeAlarm => c::CLOCK_BOOTTIME_ALARM, +    }; + +    // Old 32-bit version: libc has `clock_gettime` but it is not y2038 +    // safe by default. But there may be a `__clock_gettime64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_clock_gettime) = __clock_gettime64.get() { +            let mut timespec = MaybeUninit::<LibcTimespec>::uninit(); +            unsafe { +                ret(libc_clock_gettime( +                    id as c::clockid_t, +                    timespec.as_mut_ptr(), +                ))?; + +                return Ok(timespec.assume_init().into()); +            } +        } + +        clock_gettime_dynamic_old(id) +    } + +    // Main version: libc is y2038 safe and has `clock_gettime`. +    #[cfg(not(fix_y2038))] +    unsafe { +        let mut timespec = MaybeUninit::<Timespec>::uninit(); + +        ret(c::clock_gettime(id as c::clockid_t, timespec.as_mut_ptr()))?; + +        Ok(timespec.assume_init()) +    } +} + +#[cfg(fix_y2038)] +#[inline] +fn clock_gettime_dynamic_old(id: c::clockid_t) -> io::Result<Timespec> { +    let mut old_timespec = MaybeUninit::<c::timespec>::uninit(); + +    let old_timespec = unsafe { +        ret(c::clock_gettime( +            id as c::clockid_t, +            old_timespec.as_mut_ptr(), +        ))?; + +        old_timespec.assume_init() +    }; + +    Ok(Timespec { +        tv_sec: old_timespec.tv_sec.into(), +        tv_nsec: old_timespec.tv_nsec.into(), +    }) +} + +#[cfg(not(any( +    target_os = "redox", +    target_os = "wasi", +    all(apple, not(target_os = "macos")) +)))] +#[inline] +pub(crate) fn clock_settime(id: ClockId, timespec: Timespec) -> io::Result<()> { +    // Old 32-bit version: libc has `clock_gettime` but it is not y2038 safe by +    // default. But there may be a `__clock_settime64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_clock_settime) = __clock_settime64.get() { +            unsafe { +                let mut new_timespec = core::mem::zeroed::<LibcTimespec>(); +                new_timespec.tv_sec = timespec.tv_sec; +                new_timespec.tv_nsec = timespec.tv_nsec as _; +                return ret(libc_clock_settime(id as c::clockid_t, &new_timespec)); +            } +        } + +        clock_settime_old(id, timespec) +    } + +    // Main version: libc is y2038 safe and has `clock_settime`. +    #[cfg(not(fix_y2038))] +    unsafe { +        ret(c::clock_settime(id as c::clockid_t, ×pec)) +    } +} + +#[cfg(not(any( +    target_os = "redox", +    target_os = "wasi", +    all(apple, not(target_os = "macos")) +)))] +#[cfg(fix_y2038)] +fn clock_settime_old(id: ClockId, timespec: Timespec) -> io::Result<()> { +    let old_timespec = c::timespec { +        tv_sec: timespec +            .tv_sec +            .try_into() +            .map_err(|_| io::Errno::OVERFLOW)?, +        tv_nsec: timespec.tv_nsec as _, +    }; + +    unsafe { ret(c::clock_settime(id as c::clockid_t, &old_timespec)) } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(feature = "time")] +pub(crate) fn timerfd_create(id: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> { +    unsafe { ret_owned_fd(c::timerfd_create(id as c::clockid_t, bitflags_bits!(flags))) } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(feature = "time")] +pub(crate) fn timerfd_settime( +    fd: BorrowedFd<'_>, +    flags: TimerfdTimerFlags, +    new_value: &Itimerspec, +) -> io::Result<Itimerspec> { +    // Old 32-bit version: libc has `timerfd_settime` but it is not y2038 safe +    // by default. But there may be a `__timerfd_settime64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_timerfd_settime) = __timerfd_settime64.get() { +            let mut result = MaybeUninit::<LibcItimerspec>::uninit(); +            unsafe { +                ret(libc_timerfd_settime( +                    borrowed_fd(fd), +                    bitflags_bits!(flags), +                    &new_value.clone().into(), +                    result.as_mut_ptr(), +                ))?; +                return Ok(result.assume_init().into()); +            } +        } + +        timerfd_settime_old(fd, flags, new_value) +    } + +    #[cfg(not(fix_y2038))] +    unsafe { +        let mut result = MaybeUninit::<LibcItimerspec>::uninit(); +        ret(c::timerfd_settime( +            borrowed_fd(fd), +            bitflags_bits!(flags), +            new_value, +            result.as_mut_ptr(), +        ))?; +        Ok(result.assume_init()) +    } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(fix_y2038)] +#[cfg(feature = "time")] +fn timerfd_settime_old( +    fd: BorrowedFd<'_>, +    flags: TimerfdTimerFlags, +    new_value: &Itimerspec, +) -> io::Result<Itimerspec> { +    let mut old_result = MaybeUninit::<c::itimerspec>::uninit(); + +    // Convert `new_value` to the old `itimerspec` format. +    let old_new_value = c::itimerspec { +        it_interval: c::timespec { +            tv_sec: new_value +                .it_interval +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: new_value +                .it_interval +                .tv_nsec +                .try_into() +                .map_err(|_| io::Errno::INVAL)?, +        }, +        it_value: c::timespec { +            tv_sec: new_value +                .it_value +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: new_value +                .it_value +                .tv_nsec +                .try_into() +                .map_err(|_| io::Errno::INVAL)?, +        }, +    }; + +    let old_result = unsafe { +        ret(c::timerfd_settime( +            borrowed_fd(fd), +            bitflags_bits!(flags), +            &old_new_value, +            old_result.as_mut_ptr(), +        ))?; +        old_result.assume_init() +    }; + +    Ok(Itimerspec { +        it_interval: Timespec { +            tv_sec: old_result +                .it_interval +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: old_result.it_interval.tv_nsec as _, +        }, +        it_value: Timespec { +            tv_sec: old_result +                .it_interval +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: old_result.it_interval.tv_nsec as _, +        }, +    }) +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(feature = "time")] +pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> { +    // Old 32-bit version: libc has `timerfd_gettime` but it is not y2038 safe +    // by default. But there may be a `__timerfd_gettime64` we can use. +    #[cfg(fix_y2038)] +    { +        #[cfg(target_env = "gnu")] +        if let Some(libc_timerfd_gettime) = __timerfd_gettime64.get() { +            let mut result = MaybeUninit::<LibcItimerspec>::uninit(); +            unsafe { +                ret(libc_timerfd_gettime(borrowed_fd(fd), result.as_mut_ptr()))?; +                return Ok(result.assume_init().into()); +            } +        } + +        timerfd_gettime_old(fd) +    } + +    #[cfg(not(fix_y2038))] +    unsafe { +        let mut result = MaybeUninit::<LibcItimerspec>::uninit(); +        ret(c::timerfd_gettime(borrowed_fd(fd), result.as_mut_ptr()))?; +        Ok(result.assume_init()) +    } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(fix_y2038)] +#[cfg(feature = "time")] +fn timerfd_gettime_old(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> { +    let mut old_result = MaybeUninit::<c::itimerspec>::uninit(); + +    let old_result = unsafe { +        ret(c::timerfd_gettime(borrowed_fd(fd), old_result.as_mut_ptr()))?; +        old_result.assume_init() +    }; + +    Ok(Itimerspec { +        it_interval: Timespec { +            tv_sec: old_result +                .it_interval +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: old_result.it_interval.tv_nsec as _, +        }, +        it_value: Timespec { +            tv_sec: old_result +                .it_interval +                .tv_sec +                .try_into() +                .map_err(|_| io::Errno::OVERFLOW)?, +            tv_nsec: old_result.it_interval.tv_nsec as _, +        }, +    }) +} diff --git a/vendor/rustix/src/backend/libc/time/types.rs b/vendor/rustix/src/backend/libc/time/types.rs new file mode 100644 index 0000000..5254c6b --- /dev/null +++ b/vendor/rustix/src/backend/libc/time/types.rs @@ -0,0 +1,177 @@ +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +use crate::backend::c; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(fix_y2038)] +use crate::timespec::LibcTimespec; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(fix_y2038)] +use crate::timespec::Timespec; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +use bitflags::bitflags; + +/// `struct itimerspec` for use with [`timerfd_gettime`] and +/// [`timerfd_settime`]. +/// +/// [`timerfd_gettime`]: crate::time::timerfd_gettime +/// [`timerfd_settime`]: crate::time::timerfd_settime +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(not(fix_y2038))] +pub type Itimerspec = c::itimerspec; + +/// `struct itimerspec` for use with [`timerfd_gettime`] and +/// [`timerfd_settime`]. +/// +/// [`timerfd_gettime`]: crate::time::timerfd_gettime +/// [`timerfd_settime`]: crate::time::timerfd_settime +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(fix_y2038)] +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Itimerspec { +    /// The interval of an interval timer. +    pub it_interval: Timespec, +    /// Time remaining in the current interval. +    pub it_value: Timespec, +} + +/// On most platforms, `LibcItimerspec` is just `Itimerspec`. +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(not(fix_y2038))] +pub(crate) type LibcItimerspec = Itimerspec; + +/// On 32-bit glibc platforms, `LibcTimespec` differs from `Timespec`, so we +/// define our own struct, with bidirectional `From` impls. +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(fix_y2038)] +#[repr(C)] +#[derive(Debug, Clone)] +pub(crate) struct LibcItimerspec { +    pub it_interval: LibcTimespec, +    pub it_value: LibcTimespec, +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(fix_y2038)] +impl From<LibcItimerspec> for Itimerspec { +    #[inline] +    fn from(t: LibcItimerspec) -> Self { +        Self { +            it_interval: t.it_interval.into(), +            it_value: t.it_value.into(), +        } +    } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[cfg(fix_y2038)] +impl From<Itimerspec> for LibcItimerspec { +    #[inline] +    fn from(t: Itimerspec) -> Self { +        Self { +            it_interval: t.it_interval.into(), +            it_value: t.it_value.into(), +        } +    } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +bitflags! { +    /// `TFD_*` flags for use with [`timerfd_create`]. +    /// +    /// [`timerfd_create`]: crate::time::timerfd_create +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct TimerfdFlags: u32 { +        /// `TFD_NONBLOCK` +        #[doc(alias = "TFD_NONBLOCK")] +        const NONBLOCK = bitcast!(c::TFD_NONBLOCK); + +        /// `TFD_CLOEXEC` +        #[doc(alias = "TFD_CLOEXEC")] +        const CLOEXEC = bitcast!(c::TFD_CLOEXEC); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +bitflags! { +    /// `TFD_TIMER_*` flags for use with [`timerfd_settime`]. +    /// +    /// [`timerfd_settime`]: crate::time::timerfd_settime +    #[repr(transparent)] +    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +    pub struct TimerfdTimerFlags: u32 { +        /// `TFD_TIMER_ABSTIME` +        #[doc(alias = "TFD_TIMER_ABSTIME")] +        const ABSTIME = bitcast!(c::TFD_TIMER_ABSTIME); + +        /// `TFD_TIMER_CANCEL_ON_SET` +        #[cfg(linux_kernel)] +        #[doc(alias = "TFD_TIMER_CANCEL_ON_SET")] +        const CANCEL_ON_SET = bitcast!(c::TFD_TIMER_CANCEL_ON_SET); + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// `CLOCK_*` constants for use with [`timerfd_create`]. +/// +/// [`timerfd_create`]: crate::time::timerfd_create +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[repr(u32)] +#[non_exhaustive] +pub enum TimerfdClockId { +    /// `CLOCK_REALTIME`—A clock that tells the “real” time. +    /// +    /// This is a clock that tells the amount of time elapsed since the Unix +    /// epoch, 1970-01-01T00:00:00Z. The clock is externally settable, so it is +    /// not monotonic. Successive reads may see decreasing times, so it isn't +    /// reliable for measuring durations. +    #[doc(alias = "CLOCK_REALTIME")] +    Realtime = bitcast!(c::CLOCK_REALTIME), + +    /// `CLOCK_MONOTONIC`—A clock that tells an abstract time. +    /// +    /// Unlike `Realtime`, this clock is not based on a fixed known epoch, so +    /// individual times aren't meaningful. However, since it isn't settable, +    /// it is reliable for measuring durations. +    /// +    /// This clock does not advance while the system is suspended; see +    /// `Boottime` for a clock that does. +    #[doc(alias = "CLOCK_MONOTONIC")] +    Monotonic = bitcast!(c::CLOCK_MONOTONIC), + +    /// `CLOCK_BOOTTIME`—Like `Monotonic`, but advances while suspended. +    /// +    /// This clock is similar to `Monotonic`, but does advance while the system +    /// is suspended. +    #[doc(alias = "CLOCK_BOOTTIME")] +    Boottime = bitcast!(c::CLOCK_BOOTTIME), + +    /// `CLOCK_REALTIME_ALARM`—Like `Realtime`, but wakes a suspended system. +    /// +    /// This clock is like `Realtime`, but can wake up a suspended system. +    /// +    /// Use of this clock requires the `CAP_WAKE_ALARM` Linux capability. +    #[doc(alias = "CLOCK_REALTIME_ALARM")] +    RealtimeAlarm = bitcast!(c::CLOCK_REALTIME_ALARM), + +    /// `CLOCK_BOOTTIME_ALARM`—Like `Boottime`, but wakes a suspended system. +    /// +    /// This clock is like `Boottime`, but can wake up a suspended system. +    /// +    /// Use of this clock requires the `CAP_WAKE_ALARM` Linux capability. +    #[doc(alias = "CLOCK_BOOTTIME_ALARM")] +    BoottimeAlarm = bitcast!(c::CLOCK_BOOTTIME_ALARM), +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[test] +fn test_types() { +    assert_eq_size!(TimerfdFlags, c::c_int); +    assert_eq_size!(TimerfdTimerFlags, c::c_int); +} diff --git a/vendor/rustix/src/backend/libc/ugid/mod.rs b/vendor/rustix/src/backend/libc/ugid/mod.rs new file mode 100644 index 0000000..ef944f0 --- /dev/null +++ b/vendor/rustix/src/backend/libc/ugid/mod.rs @@ -0,0 +1 @@ +pub(crate) mod syscalls; diff --git a/vendor/rustix/src/backend/libc/ugid/syscalls.rs b/vendor/rustix/src/backend/libc/ugid/syscalls.rs new file mode 100644 index 0000000..0d3f622 --- /dev/null +++ b/vendor/rustix/src/backend/libc/ugid/syscalls.rs @@ -0,0 +1,42 @@ +use crate::backend::c; +use crate::ugid::{Gid, Uid}; + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getuid() -> Uid { +    unsafe { +        let uid = c::getuid(); +        Uid::from_raw(uid) +    } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn geteuid() -> Uid { +    unsafe { +        let uid = c::geteuid(); +        Uid::from_raw(uid) +    } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getgid() -> Gid { +    unsafe { +        let gid = c::getgid(); +        Gid::from_raw(gid) +    } +} + +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getegid() -> Gid { +    unsafe { +        let gid = c::getegid(); +        Gid::from_raw(gid) +    } +} diff --git a/vendor/rustix/src/backend/libc/winsock_c.rs b/vendor/rustix/src/backend/libc/winsock_c.rs new file mode 100644 index 0000000..ee2704a --- /dev/null +++ b/vendor/rustix/src/backend/libc/winsock_c.rs @@ -0,0 +1,59 @@ +//! Adapt the Winsock API to resemble a POSIX-style libc API. + +#![allow(unused_imports)] +#![allow(non_camel_case_types)] +#![allow(dead_code)] + +use windows_sys::Win32::Networking::WinSock; + +// Define the basic C types. With Rust 1.64, we can use these from `core::ffi`. +pub(crate) type c_schar = i8; +pub(crate) type c_uchar = u8; +pub(crate) type c_short = i16; +pub(crate) type c_ushort = u16; +pub(crate) type c_int = i32; +pub(crate) type c_uint = u32; +pub(crate) type c_longlong = i64; +pub(crate) type c_ulonglong = u64; +pub(crate) type ssize_t = isize; +pub(crate) type c_char = i8; +pub(crate) type c_long = i32; +pub(crate) type c_ulong = u32; +pub(crate) use core::ffi::c_void; + +// windows-sys declares these constants as u16. For better compatibility +// with Unix-family APIs, redeclare them as u32. +pub(crate) const AF_INET: i32 = WinSock::AF_INET as _; +pub(crate) const AF_INET6: i32 = WinSock::AF_INET6 as _; +pub(crate) const AF_UNSPEC: i32 = WinSock::AF_UNSPEC as _; + +// Include the contents of `WinSock`, renaming as needed to match POSIX. +// +// Use `WSA_E_CANCELLED` for `ECANCELED` instead of `WSAECANCELLED`, because +// `WSAECANCELLED` will be removed in the future. +// <https://docs.microsoft.com/en-us/windows/win32/api/ws2spi/nc-ws2spi-lpnsplookupserviceend#remarks> +pub(crate) use WinSock::{ +    closesocket as close, ioctlsocket as ioctl, WSAPoll as poll, ADDRESS_FAMILY as sa_family_t, +    ADDRINFOA as addrinfo, IN6_ADDR as in6_addr, IN_ADDR as in_addr, IPV6_MREQ as ipv6_mreq, +    IP_MREQ as ip_mreq, LINGER as linger, SD_BOTH as SHUT_RDWR, SD_RECEIVE as SHUT_RD, +    SD_SEND as SHUT_WR, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, +    SOCKADDR_IN6 as sockaddr_in6, SOCKADDR_STORAGE as sockaddr_storage, WSAEACCES as EACCES, +    WSAEADDRINUSE as EADDRINUSE, WSAEADDRNOTAVAIL as EADDRNOTAVAIL, +    WSAEAFNOSUPPORT as EAFNOSUPPORT, WSAEALREADY as EALREADY, WSAEBADF as EBADF, +    WSAECONNABORTED as ECONNABORTED, WSAECONNREFUSED as ECONNREFUSED, WSAECONNRESET as ECONNRESET, +    WSAEDESTADDRREQ as EDESTADDRREQ, WSAEDISCON as EDISCON, WSAEDQUOT as EDQUOT, +    WSAEFAULT as EFAULT, WSAEHOSTDOWN as EHOSTDOWN, WSAEHOSTUNREACH as EHOSTUNREACH, +    WSAEINPROGRESS as EINPROGRESS, WSAEINTR as EINTR, WSAEINVAL as EINVAL, +    WSAEINVALIDPROCTABLE as EINVALIDPROCTABLE, WSAEINVALIDPROVIDER as EINVALIDPROVIDER, +    WSAEISCONN as EISCONN, WSAELOOP as ELOOP, WSAEMFILE as EMFILE, WSAEMSGSIZE as EMSGSIZE, +    WSAENAMETOOLONG as ENAMETOOLONG, WSAENETDOWN as ENETDOWN, WSAENETRESET as ENETRESET, +    WSAENETUNREACH as ENETUNREACH, WSAENOBUFS as ENOBUFS, WSAENOMORE as ENOMORE, +    WSAENOPROTOOPT as ENOPROTOOPT, WSAENOTCONN as ENOTCONN, WSAENOTEMPTY as ENOTEMPTY, +    WSAENOTSOCK as ENOTSOCK, WSAEOPNOTSUPP as EOPNOTSUPP, WSAEPFNOSUPPORT as EPFNOSUPPORT, +    WSAEPROCLIM as EPROCLIM, WSAEPROTONOSUPPORT as EPROTONOSUPPORT, WSAEPROTOTYPE as EPROTOTYPE, +    WSAEPROVIDERFAILEDINIT as EPROVIDERFAILEDINIT, WSAEREFUSED as EREFUSED, WSAEREMOTE as EREMOTE, +    WSAESHUTDOWN as ESHUTDOWN, WSAESOCKTNOSUPPORT as ESOCKTNOSUPPORT, WSAESTALE as ESTALE, +    WSAETIMEDOUT as ETIMEDOUT, WSAETOOMANYREFS as ETOOMANYREFS, WSAEUSERS as EUSERS, +    WSAEWOULDBLOCK as EWOULDBLOCK, WSAEWOULDBLOCK as EAGAIN, WSAPOLLFD as pollfd, +    WSA_E_CANCELLED as ECANCELED, *, +};  | 
