diff options
Diffstat (limited to 'vendor/rustix/src/backend/libc/fs/syscalls.rs')
-rw-r--r-- | vendor/rustix/src/backend/libc/fs/syscalls.rs | 874 |
1 files changed, 595 insertions, 279 deletions
diff --git a/vendor/rustix/src/backend/libc/fs/syscalls.rs b/vendor/rustix/src/backend/libc/fs/syscalls.rs index 40c160182..bdba777e9 100644 --- a/vendor/rustix/src/backend/libc/fs/syscalls.rs +++ b/vendor/rustix/src/backend/libc/fs/syscalls.rs @@ -1,48 +1,9 @@ //! libc syscalls supporting `rustix::fs`. -use super::super::c; -use super::super::conv::{borrowed_fd, c_str, ret, ret_c_int, ret_off_t, ret_owned_fd, ret_usize}; -#[cfg(any(target_os = "android", target_os = "linux"))] -use super::super::conv::{syscall_ret, syscall_ret_owned_fd, syscall_ret_usize}; -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -use super::super::offset::libc_fallocate; -#[cfg(not(any( - apple, - netbsdlike, - solarish, - target_os = "dragonfly", - target_os = "haiku", - target_os = "redox", -)))] -use super::super::offset::libc_posix_fadvise; -#[cfg(not(any( - apple, - netbsdlike, - solarish, - target_os = "aix", - target_os = "android", - target_os = "dragonfly", - target_os = "fuchsia", - target_os = "linux", - target_os = "redox", -)))] -use super::super::offset::libc_posix_fallocate; -use super::super::offset::{libc_fstat, libc_fstatat, libc_ftruncate, libc_lseek, libc_off_t}; -#[cfg(not(any( - solarish, - target_os = "haiku", - target_os = "netbsd", - target_os = "redox", - target_os = "wasi", -)))] -use super::super::offset::{libc_fstatfs, libc_statfs}; -#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] -use super::super::offset::{libc_fstatvfs, libc_statvfs}; -#[cfg(all( - any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), - target_env = "gnu", -))] -use super::super::time::types::LibcTimespec; +use crate::backend::c; +use crate::backend::conv::{ + borrowed_fd, c_str, ret, ret_c_int, ret_off_t, ret_owned_fd, ret_usize, +}; use crate::fd::{BorrowedFd, OwnedFd}; use crate::ffi::CStr; #[cfg(apple)] @@ -56,6 +17,8 @@ use crate::ffi::CString; target_os = "redox", )))] use crate::fs::Advice; +#[cfg(not(target_os = "redox"))] +use crate::fs::AtFlags; #[cfg(not(any( netbsdlike, solarish, @@ -66,14 +29,9 @@ use crate::fs::Advice; use crate::fs::FallocateFlags; #[cfg(not(target_os = "wasi"))] use crate::fs::FlockOperation; -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_kernel, target_os = "freebsd"))] use crate::fs::MemfdFlags; -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "linux", -))] +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] use crate::fs::SealFlags; #[cfg(not(any( solarish, @@ -83,38 +41,39 @@ use crate::fs::SealFlags; target_os = "wasi", )))] use crate::fs::StatFs; -#[cfg(any(apple, target_os = "android", target_os = "linux"))] -use crate::fs::XattrFlags; -#[cfg(any(target_os = "android", target_os = "linux"))] -use crate::fs::{cwd, RenameFlags, ResolveFlags, Statx, StatxFlags}; -use crate::fs::{Access, Mode, OFlags, Stat, Timestamps}; +use crate::fs::{Access, Mode, OFlags, SeekFrom, Stat, Timestamps}; #[cfg(not(any(apple, target_os = "redox", target_os = "wasi")))] use crate::fs::{Dev, FileType}; #[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] use crate::fs::{StatVfs, StatVfsMountFlags}; -use crate::io::{self, SeekFrom}; +use crate::io; +#[cfg(all( + any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), + target_env = "gnu", +))] +use crate::timespec::LibcTimespec; #[cfg(not(target_os = "wasi"))] -use crate::process::{Gid, Uid}; +use crate::ugid::{Gid, Uid}; #[cfg(not(all( any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), target_env = "gnu", )))] use crate::utils::as_ptr; -use core::convert::TryInto; -#[cfg(any(apple, target_os = "android", target_os = "linux"))] -use core::mem::size_of; +#[cfg(apple)] +use alloc::vec; use core::mem::MaybeUninit; -#[cfg(any(target_os = "android", target_os = "linux"))] -use core::ptr::null; -#[cfg(any(apple, target_os = "android", target_os = "linux"))] -use core::ptr::null_mut; #[cfg(apple)] use { - super::super::conv::nonnegative_ret, + crate::backend::conv::nonnegative_ret, crate::fs::{copyfile_state_t, CloneFlags, CopyfileFlags}, }; -#[cfg(not(target_os = "redox"))] -use {super::super::offset::libc_openat, crate::fs::AtFlags}; +#[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( any(target_arch = "arm", target_arch = "mips", target_arch = "x86"), @@ -127,6 +86,64 @@ weak!(fn __utimensat64(c::c_int, *const c::c_char, *const LibcTimespec, c::c_int ))] 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 and riscv64 has no `open` syscall so use `openat`. + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + { + openat_via_syscall(CWD, path, oflags, mode) + } + + // Use the `open` syscall. + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + 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"))] + 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. @@ -137,18 +154,22 @@ fn openat_via_syscall( 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 { - let dirfd = borrowed_fd(dirfd); - let path = c_str(path); - let oflags = oflags.bits(); - let mode = c::c_uint::from(mode.bits()); - ret_owned_fd(c::syscall( - c::SYS_openat, - c::c_long::from(dirfd), - path, - c::c_long::from(oflags), - mode as c::c_long, - ) as c::c_int) + ret_owned_fd(openat( + borrowed_fd(dirfd), + c_str(path), + bitflags_bits!(oflags), + bitflags_bits!(mode), + )) } } @@ -165,15 +186,30 @@ pub(crate) fn openat( 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 { - // Pass `mode` as a `c_uint` even if `mode_t` is narrower, since - // `libc_openat` is declared as a variadic function and narrower - // arguments are promoted. - ret_owned_fd(libc_openat( + ret_owned_fd(c::openat( borrowed_fd(dirfd), c_str(path), - oflags.bits(), - c::c_uint::from(mode.bits()), + bitflags_bits!(oflags), + mode, )) } } @@ -189,7 +225,7 @@ pub(crate) fn openat( pub(crate) fn statfs(filename: &CStr) -> io::Result<StatFs> { unsafe { let mut result = MaybeUninit::<StatFs>::uninit(); - ret(libc_statfs(c_str(filename), result.as_mut_ptr()))?; + ret(c::statfs(c_str(filename), result.as_mut_ptr()))?; Ok(result.assume_init()) } } @@ -198,15 +234,30 @@ pub(crate) fn statfs(filename: &CStr) -> io::Result<StatFs> { #[inline] pub(crate) fn statvfs(filename: &CStr) -> io::Result<StatVfs> { unsafe { - let mut result = MaybeUninit::<libc_statvfs>::uninit(); - ret(libc_statvfs(c_str(filename), result.as_mut_ptr()))?; + 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())) } } +#[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(), + )) + } +} + #[cfg(not(target_os = "redox"))] #[inline] -pub(crate) fn readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, buf: &mut [u8]) -> io::Result<usize> { +pub(crate) fn readlinkat( + dirfd: BorrowedFd<'_>, + path: &CStr, + buf: &mut [MaybeUninit<u8>], +) -> io::Result<usize> { unsafe { ret_usize(c::readlinkat( borrowed_fd(dirfd), @@ -217,6 +268,10 @@ pub(crate) fn readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, buf: &mut [u8]) -> } } +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 { @@ -228,21 +283,31 @@ pub(crate) fn mkdirat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Res } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[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 { - syscall_ret_usize(c::syscall( - c::SYS_getdents64, - fd, - buf.as_mut_ptr().cast::<c::c_char>(), + 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(target_os = "redox"))] pub(crate) fn linkat( old_dirfd: BorrowedFd<'_>, @@ -251,20 +316,107 @@ pub(crate) fn linkat( 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), - flags.bits(), + 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(target_os = "redox"))] pub(crate) fn unlinkat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<()> { - unsafe { ret(c::unlinkat(borrowed_fd(dirfd), c_str(path), flags.bits())) } + // 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"))] @@ -274,6 +426,34 @@ pub(crate) fn renameat( 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), @@ -292,7 +472,7 @@ pub(crate) fn renameat2( new_path: &CStr, flags: RenameFlags, ) -> io::Result<()> { - // `getrandom` wasn't supported in glibc until 2.28. + // `renameat2` wasn't supported in glibc until 2.28. weak_or_syscall! { fn renameat2( olddirfd: c::c_int, @@ -332,6 +512,10 @@ pub(crate) fn renameat2( renameat(old_dirfd, old_path, new_dirfd, new_path) } +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, @@ -347,16 +531,64 @@ pub(crate) fn symlinkat( } } +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")))] + { + 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"))))] + 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")))] + { + 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::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"))))] + unsafe { + let mut stat = MaybeUninit::<Stat>::uninit(); + ret(c::lstat(c_str(path), stat.as_mut_ptr()))?; + Ok(stat.assume_init()) + } +} + #[cfg(not(target_os = "redox"))] pub(crate) fn statat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> { - // 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use - // `statx`. - #[cfg(all( - any(target_os = "android", target_os = "linux"), - any(target_pointer_width = "32", target_arch = "mips64"), - ))] + // See the comments in `fstat` about using `crate::fs::statx` here. + #[cfg(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64")))] { - match statx(dirfd, path, flags, StatxFlags::BASIC_STATS) { + 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), @@ -365,39 +597,38 @@ pub(crate) fn statat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io:: // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and // there's nothing practical we can do. - #[cfg(not(all( - any(target_os = "android", target_os = "linux"), - any(target_pointer_width = "32", target_arch = "mips64"), - )))] + #[cfg(not(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64"))))] unsafe { let mut stat = MaybeUninit::<Stat>::uninit(); - ret(libc_fstatat( + ret(c::fstatat( borrowed_fd(dirfd), c_str(path), stat.as_mut_ptr(), - flags.bits(), + bitflags_bits!(flags), ))?; Ok(stat.assume_init()) } } -#[cfg(all( - any(target_os = "android", target_os = "linux"), - any(target_pointer_width = "32", target_arch = "mips64"), -))] +#[cfg(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64")))] fn statat_old(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> { unsafe { let mut result = MaybeUninit::<c::stat64>::uninit(); - ret(libc_fstatat( + ret(c::fstatat( borrowed_fd(dirfd), c_str(path), result.as_mut_ptr(), - flags.bits(), + bitflags_bits!(flags), ))?; stat64_to_stat(result.assume_init()) } } +#[cfg(not(target_os = "emscripten"))] +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 = "redox")))] pub(crate) fn accessat( dirfd: BorrowedFd<'_>, @@ -405,17 +636,56 @@ pub(crate) fn accessat( 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), - access.bits(), - flags.bits(), + 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, @@ -449,7 +719,7 @@ pub(crate) fn utimensat( borrowed_fd(dirfd), c_str(path), libc_times.as_ptr(), - flags.bits(), + bitflags_bits!(flags), )) } else { utimensat_old(dirfd, path, times, flags) @@ -473,7 +743,7 @@ pub(crate) fn utimensat( borrowed_fd(dirfd), c_str(path), as_ptr(times).cast(), - flags.bits(), + bitflags_bits!(flags), )) } @@ -509,7 +779,7 @@ pub(crate) fn utimensat( borrowed_fd(dirfd), c_str(path), as_ptr(times).cast(), - flags.bits(), + bitflags_bits!(flags), )); } @@ -625,16 +895,16 @@ unsafe fn utimensat_old( borrowed_fd(dirfd), c_str(path), old_times.as_ptr(), - flags.bits(), + bitflags_bits!(flags), )) } -#[cfg(not(any( - target_os = "android", - target_os = "linux", - target_os = "redox", - target_os = "wasi", -)))] +#[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 = "redox", target_os = "wasi")))] pub(crate) fn chmodat( dirfd: BorrowedFd<'_>, path: &CStr, @@ -646,12 +916,12 @@ pub(crate) fn chmodat( borrowed_fd(dirfd), c_str(path), mode.bits() as c::mode_t, - flags.bits(), + bitflags_bits!(flags), )) } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_kernel)] pub(crate) fn chmodat( dirfd: BorrowedFd<'_>, path: &CStr, @@ -664,6 +934,13 @@ pub(crate) fn chmodat( // 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); } @@ -671,14 +948,10 @@ pub(crate) fn chmodat( return Err(io::Errno::INVAL); } unsafe { - // Pass `mode` as a `c_uint` even if `mode_t` is narrower, since - // `libc_openat` is declared as a variadic function and narrower - // arguments are promoted. - syscall_ret(c::syscall( - c::SYS_fchmodat, + ret(fchmodat( borrowed_fd(dirfd), c_str(path), - c::c_uint::from(mode.bits()), + mode.bits() as c::mode_t, )) } } @@ -699,7 +972,14 @@ pub(crate) fn fclonefileat( ) via SYS_fclonefileat -> c::c_int } - unsafe { ret(fclonefileat(srcfd, dst_dirfd, c_str(dst), flags.bits())) } + unsafe { + ret(fclonefileat( + srcfd, + dst_dirfd, + c_str(dst), + bitflags_bits!(flags), + )) + } } #[cfg(not(any(target_os = "redox", target_os = "wasi")))] @@ -711,13 +991,13 @@ pub(crate) fn chownat( flags: AtFlags, ) -> io::Result<()> { unsafe { - let (ow, gr) = crate::process::translate_fchown_args(owner, group); + let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); ret(c::fchownat( borrowed_fd(dirfd), c_str(path), ow, gr, - flags.bits(), + bitflags_bits!(flags), )) } } @@ -740,7 +1020,7 @@ pub(crate) fn mknodat( } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_kernel)] pub(crate) fn copy_file_range( fd_in: BorrowedFd<'_>, off_in: Option<&mut u64>, @@ -748,26 +1028,36 @@ pub(crate) fn copy_file_range( 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 + } + assert_eq!(size_of::<c::loff_t>(), size_of::<u64>()); 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; + 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; + off_out_val = **off_out as i64; &mut off_out_val } else { null_mut() }; let copied = unsafe { - syscall_ret_usize(c::syscall( - c::SYS_copy_file_range, + ret_usize(copy_file_range( borrowed_fd(fd_in), off_in_ptr, borrowed_fd(fd_out), @@ -813,7 +1103,7 @@ pub(crate) fn fadvise(fd: BorrowedFd<'_>, offset: u64, len: u64, advice: Advice) len }; - let err = unsafe { libc_posix_fadvise(borrowed_fd(fd), offset, len, advice as c::c_int) }; + 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 { @@ -824,32 +1114,21 @@ pub(crate) fn fadvise(fd: BorrowedFd<'_>, offset: u64, len: u64, advice: Advice) } pub(crate) fn fcntl_getfl(fd: BorrowedFd<'_>) -> io::Result<OFlags> { - unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFL)).map(OFlags::from_bits_truncate) } + 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( - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "linux", -))] +#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))] pub(crate) fn fcntl_get_seals(fd: BorrowedFd<'_>) -> io::Result<SealFlags> { - unsafe { - ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GET_SEALS)) - .map(|flags| SealFlags::from_bits_unchecked(flags)) - } + let flags = unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GET_SEALS))? }; + Ok(SealFlags::from_bits_retain(bitcast!(flags))) } -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "linux", -))] +#[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())) } } @@ -889,7 +1168,7 @@ pub(crate) fn fcntl_lock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::R } pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> { - let (whence, offset): (c::c_int, libc_off_t) = match pos { + let (whence, offset): (c::c_int, c::off_t) = match pos { SeekFrom::Start(pos) => { let pos: u64 = pos; // Silently cast; we'll get `EINVAL` if the value is negative. @@ -902,51 +1181,58 @@ pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> { #[cfg(any(freebsdlike, target_os = "linux", target_os = "solaris"))] SeekFrom::Hole(offset) => (c::SEEK_HOLE, offset), }; - let offset = unsafe { ret_off_t(libc_lseek(borrowed_fd(fd), offset, whence))? }; + 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(libc_lseek(borrowed_fd(fd), 0, c::SEEK_CUR))? }; + let offset = unsafe { ret_off_t(c::lseek(borrowed_fd(fd), 0, c::SEEK_CUR))? }; Ok(offset as u64) } -#[cfg(not(any(target_os = "android", target_os = "linux", target_os = "wasi")))] +#[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), mode.bits())) } + unsafe { ret(c::fchmod(borrowed_fd(fd), bitflags_bits!(mode))) } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[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`. - unsafe { - syscall_ret(c::syscall( - c::SYS_fchmod, - borrowed_fd(fd), - c::c_uint::from(mode.bits()), - )) + 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(any(target_os = "android", target_os = "linux"))] +#[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::process::translate_fchown_args(owner, group); - syscall_ret(c::syscall(c::SYS_fchown, borrowed_fd(fd), ow, gr)) + let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); + ret(fchown(borrowed_fd(fd), ow, gr)) } } -#[cfg(not(any(target_os = "android", target_os = "linux", target_os = "wasi")))] +#[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::process::translate_fchown_args(owner, group); + let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); ret(c::fchown(borrowed_fd(fd), ow, gr)) } } @@ -956,18 +1242,21 @@ pub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result unsafe { ret(c::flock(borrowed_fd(fd), operation as c::c_int)) } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_kernel)] pub(crate) fn syncfs(fd: BorrowedFd<'_>) -> io::Result<()> { // Some versions of Android libc lack a `syncfs` function. #[cfg(target_os = "android")] - unsafe { - syscall_ret(c::syscall(c::SYS_syncfs, borrowed_fd(fd))) + 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"))] - unsafe { - ret(c::syncfs(borrowed_fd(fd))) + 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 = "redox", target_os = "wasi")))] @@ -978,12 +1267,13 @@ pub(crate) fn sync() { pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> { // 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use // `statx`. - #[cfg(all( - any(target_os = "android", target_os = "linux"), - any(target_pointer_width = "32", target_arch = "mips64"), - ))] + // + // 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")))] { - match statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) { + 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), @@ -992,25 +1282,19 @@ pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> { // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and // there's nothing practical we can do. - #[cfg(not(all( - any(target_os = "android", target_os = "linux"), - any(target_pointer_width = "32", target_arch = "mips64"), - )))] + #[cfg(not(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64"))))] unsafe { let mut stat = MaybeUninit::<Stat>::uninit(); - ret(libc_fstat(borrowed_fd(fd), stat.as_mut_ptr()))?; + ret(c::fstat(borrowed_fd(fd), stat.as_mut_ptr()))?; Ok(stat.assume_init()) } } -#[cfg(all( - any(target_os = "android", target_os = "linux"), - any(target_pointer_width = "32", target_arch = "mips64"), -))] +#[cfg(all(linux_kernel, any(target_pointer_width = "32", target_arch = "mips64")))] fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> { unsafe { let mut result = MaybeUninit::<c::stat64>::uninit(); - ret(libc_fstat(borrowed_fd(fd), result.as_mut_ptr()))?; + ret(c::fstat(borrowed_fd(fd), result.as_mut_ptr()))?; stat64_to_stat(result.assume_init()) } } @@ -1025,22 +1309,22 @@ fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> { pub(crate) fn fstatfs(fd: BorrowedFd<'_>) -> io::Result<StatFs> { let mut statfs = MaybeUninit::<StatFs>::uninit(); unsafe { - ret(libc_fstatfs(borrowed_fd(fd), statfs.as_mut_ptr()))?; + 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::<libc_statvfs>::uninit(); + let mut statvfs = MaybeUninit::<c::statvfs>::uninit(); unsafe { - ret(libc_fstatvfs(borrowed_fd(fd), statvfs.as_mut_ptr()))?; + 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: libc_statvfs) -> StatVfs { +fn libc_statvfs_to_statvfs(from: c::statvfs) -> StatVfs { StatVfs { f_bsize: from.f_bsize as u64, f_frsize: from.f_frsize as u64, @@ -1051,7 +1335,7 @@ fn libc_statvfs_to_statvfs(from: libc_statvfs) -> StatVfs { f_ffree: from.f_ffree as u64, f_favail: from.f_ffree as u64, f_fsid: from.f_fsid as u64, - f_flag: unsafe { StatVfsMountFlags::from_bits_unchecked(from.f_flag as u64) }, + f_flag: StatVfsMountFlags::from_bits_retain(from.f_flag as u64), f_namemax: from.f_namemax as u64, } } @@ -1174,15 +1458,20 @@ pub(crate) fn fallocate( let offset = offset as i64; let len = len as i64; - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_kernel, target_os = "fuchsia"))] unsafe { - ret(libc_fallocate(borrowed_fd(fd), mode.bits(), offset, len)) + ret(c::fallocate( + borrowed_fd(fd), + bitflags_bits!(mode), + offset, + len, + )) } - #[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))] + #[cfg(not(any(linux_kernel, target_os = "fuchsia")))] { assert!(mode.is_empty()); - let err = unsafe { libc_posix_fallocate(borrowed_fd(fd), offset, len) }; + let err = unsafe { c::posix_fallocate(borrowed_fd(fd), offset, len) }; // `posix_fallocate` returns its error status rather than using `errno`. if err == 0 { @@ -1240,10 +1529,10 @@ pub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> { pub(crate) fn ftruncate(fd: BorrowedFd<'_>, length: u64) -> io::Result<()> { let length = length.try_into().map_err(|_overflow_err| io::Errno::FBIG)?; - unsafe { ret(libc_ftruncate(borrowed_fd(fd), length)) } + unsafe { ret(c::ftruncate(borrowed_fd(fd), length)) } } -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_kernel, target_os = "freebsd"))] pub(crate) fn memfd_create(path: &CStr, flags: MemfdFlags) -> io::Result<OwnedFd> { #[cfg(target_os = "freebsd")] weakcall! { @@ -1253,7 +1542,7 @@ pub(crate) fn memfd_create(path: &CStr, flags: MemfdFlags) -> io::Result<OwnedFd ) -> c::c_int } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_kernel)] weak_or_syscall! { fn memfd_create( name: *const c::c_char, @@ -1261,10 +1550,10 @@ pub(crate) fn memfd_create(path: &CStr, flags: MemfdFlags) -> io::Result<OwnedFd ) via SYS_memfd_create -> c::c_int } - unsafe { ret_owned_fd(memfd_create(c_str(path), flags.bits())) } + unsafe { ret_owned_fd(memfd_create(c_str(path), bitflags_bits!(flags))) } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_kernel)] pub(crate) fn openat2( dirfd: BorrowedFd<'_>, path: &CStr, @@ -1272,45 +1561,38 @@ pub(crate) fn openat2( mode: Mode, resolve: ResolveFlags, ) -> io::Result<OwnedFd> { - let oflags: i32 = oflags.bits(); - let open_how = OpenHow { - oflag: u64::from(oflags as u32), + 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 { - syscall_ret_owned_fd(c::syscall( - SYS_OPENAT2, + ret_owned_fd(openat2( borrowed_fd(dirfd), c_str(path), - &open_how, - SIZEOF_OPEN_HOW, + &mut open_how, + size_of::<open_how>(), )) } } -#[cfg(all( - target_pointer_width = "32", - any(target_os = "android", target_os = "linux"), -))] +#[cfg(all(linux_kernel, target_pointer_width = "32"))] const SYS_OPENAT2: i32 = 437; -#[cfg(all( - target_pointer_width = "64", - any(target_os = "android", target_os = "linux"), -))] +#[cfg(all(linux_kernel, target_pointer_width = "64"))] const SYS_OPENAT2: i64 = 437; -#[cfg(any(target_os = "android", target_os = "linux"))] -#[repr(C)] -#[derive(Debug)] -struct OpenHow { - oflag: u64, - mode: u64, - resolve: u64, -} -#[cfg(any(target_os = "android", target_os = "linux"))] -const SIZEOF_OPEN_HOW: usize = size_of::<OpenHow>(); - #[cfg(target_os = "linux")] pub(crate) fn sendfile( out_fd: BorrowedFd<'_>, @@ -1329,10 +1611,7 @@ pub(crate) fn sendfile( } /// Convert from a Linux `statx` value to rustix's `Stat`. -#[cfg(all( - any(target_os = "android", target_os = "linux"), - target_pointer_width = "32", -))] +#[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(), @@ -1369,10 +1648,7 @@ fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> { /// Convert from a Linux `statx` value to rustix's `Stat`. /// /// mips64' `struct stat64` in libc has private fields, and `stx_blocks` -#[cfg(all( - any(target_os = "android", target_os = "linux"), - target_arch = "mips64", -))] +#[cfg(all(linux_kernel, target_arch = "mips64"))] fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> { let mut result: Stat = unsafe { core::mem::zeroed() }; @@ -1409,10 +1685,7 @@ fn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> { } /// Convert from a Linux `stat64` value to rustix's `Stat`. -#[cfg(all( - any(target_os = "android", target_os = "linux"), - target_pointer_width = "32", -))] +#[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)?, @@ -1447,10 +1720,7 @@ fn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> { /// /// mips64' `struct stat64` in libc has private fields, and `st_blocks` has /// type `i64`. -#[cfg(all( - any(target_os = "android", target_os = "linux"), - target_arch = "mips64", -))] +#[cfg(all(linux_kernel, target_arch = "mips64"))] fn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> { let mut result: Stat = unsafe { core::mem::zeroed() }; @@ -1483,7 +1753,7 @@ fn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> { Ok(result) } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_kernel)] #[allow(non_upper_case_globals)] mod sys { use super::{c, BorrowedFd, Statx}; @@ -1499,7 +1769,7 @@ mod sys { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_kernel)] #[allow(non_upper_case_globals)] pub(crate) fn statx( dirfd: BorrowedFd<'_>, @@ -1534,7 +1804,7 @@ pub(crate) fn statx( ret(sys::statx( dirfd, c_str(path), - flags.bits(), + bitflags_bits!(flags), mask.bits(), statx_buf.as_mut_ptr(), ))?; @@ -1542,14 +1812,14 @@ pub(crate) fn statx( } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[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())), + ret(sys::statx(CWD, null(), 0, 0, null_mut())), Err(io::Errno::FAULT) ) } @@ -1575,7 +1845,7 @@ pub(crate) unsafe fn fcopyfile( borrowed_fd(from), borrowed_fd(to), state, - flags.bits(), + bitflags_bits!(flags), )) } @@ -1632,7 +1902,7 @@ pub(crate) fn getpath(fd: BorrowedFd<'_>) -> io::Result<CString> { // `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 = alloc::vec![0; c::PATH_MAX as usize]; + 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 @@ -1645,9 +1915,6 @@ pub(crate) fn getpath(fd: BorrowedFd<'_>) -> io::Result<CString> { let l = buf.iter().position(|&c| c == 0).unwrap(); buf.truncate(l); - - // TODO: On Rust 1.56, we can use `shrink_to` here. - //buf.shrink_to(l + 1); buf.shrink_to_fit(); Ok(CString::new(buf).unwrap()) @@ -1781,7 +2048,7 @@ struct Attrlist { forkattr: Attrgroup, } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_kernel)] pub(crate) fn mount( source: Option<&CStr>, target: &CStr, @@ -1800,12 +2067,12 @@ pub(crate) fn mount( } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_kernel)] pub(crate) fn unmount(target: &CStr, flags: super::types::UnmountFlags) -> io::Result<()> { - unsafe { ret(c::umount2(target.as_ptr(), flags.bits())) } + unsafe { ret(c::umount2(target.as_ptr(), bitflags_bits!(flags))) } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[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(); @@ -1832,7 +2099,7 @@ pub(crate) fn getxattr(path: &CStr, name: &CStr, value: &mut [u8]) -> io::Result } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[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(); @@ -1859,7 +2126,7 @@ pub(crate) fn lgetxattr(path: &CStr, name: &CStr, value: &mut [u8]) -> io::Resul } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[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(); @@ -1886,7 +2153,7 @@ pub(crate) fn fgetxattr(fd: BorrowedFd<'_>, name: &CStr, value: &mut [u8]) -> io } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[cfg(any(apple, linux_kernel))] pub(crate) fn setxattr( path: &CStr, name: &CStr, @@ -1917,7 +2184,7 @@ pub(crate) fn setxattr( } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[cfg(any(apple, linux_kernel))] pub(crate) fn lsetxattr( path: &CStr, name: &CStr, @@ -1948,7 +2215,7 @@ pub(crate) fn lsetxattr( } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[cfg(any(apple, linux_kernel))] pub(crate) fn fsetxattr( fd: BorrowedFd<'_>, name: &CStr, @@ -1979,7 +2246,7 @@ pub(crate) fn fsetxattr( } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[cfg(any(apple, linux_kernel))] pub(crate) fn listxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usize> { #[cfg(not(apple))] unsafe { @@ -1997,7 +2264,7 @@ pub(crate) fn listxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usize } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[cfg(any(apple, linux_kernel))] pub(crate) fn llistxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usize> { #[cfg(not(apple))] unsafe { @@ -2015,7 +2282,7 @@ pub(crate) fn llistxattr(path: &CStr, list: &mut [c::c_char]) -> io::Result<usiz } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[cfg(any(apple, linux_kernel))] pub(crate) fn flistxattr(fd: BorrowedFd<'_>, list: &mut [c::c_char]) -> io::Result<usize> { let fd = borrowed_fd(fd); @@ -2030,7 +2297,7 @@ pub(crate) fn flistxattr(fd: BorrowedFd<'_>, list: &mut [c::c_char]) -> io::Resu } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[cfg(any(apple, linux_kernel))] pub(crate) fn removexattr(path: &CStr, name: &CStr) -> io::Result<()> { #[cfg(not(apple))] unsafe { @@ -2043,7 +2310,7 @@ pub(crate) fn removexattr(path: &CStr, name: &CStr) -> io::Result<()> { } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[cfg(any(apple, linux_kernel))] pub(crate) fn lremovexattr(path: &CStr, name: &CStr) -> io::Result<()> { #[cfg(not(apple))] unsafe { @@ -2060,7 +2327,7 @@ pub(crate) fn lremovexattr(path: &CStr, name: &CStr) -> io::Result<()> { } } -#[cfg(any(apple, target_os = "android", target_os = "linux"))] +#[cfg(any(apple, linux_kernel))] pub(crate) fn fremovexattr(fd: BorrowedFd<'_>, name: &CStr) -> io::Result<()> { let fd = borrowed_fd(fd); @@ -2074,3 +2341,52 @@ pub(crate) fn fremovexattr(fd: BorrowedFd<'_>, name: &CStr) -> io::Result<()> { ret(c::fremovexattr(fd, name.as_ptr(), 0)) } } + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn ioctl_blksszget(fd: BorrowedFd) -> io::Result<u32> { + let mut result = MaybeUninit::<c::c_uint>::uninit(); + unsafe { + ret(c::ioctl(borrowed_fd(fd), c::BLKSSZGET, result.as_mut_ptr()))?; + Ok(result.assume_init() as u32) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result<u32> { + let mut result = MaybeUninit::<c::c_uint>::uninit(); + unsafe { + ret(c::ioctl( + borrowed_fd(fd), + c::BLKPBSZGET, + result.as_mut_ptr(), + ))?; + Ok(result.assume_init() as u32) + } +} + +// Sparc lacks `FICLONE`. +#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))] +pub(crate) fn ioctl_ficlone(fd: BorrowedFd<'_>, src_fd: BorrowedFd<'_>) -> io::Result<()> { + unsafe { + ret(c::ioctl( + borrowed_fd(fd), + c::FICLONE as _, + borrowed_fd(src_fd), + )) + } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn ext4_ioc_resize_fs(fd: BorrowedFd<'_>, blocks: u64) -> io::Result<()> { + // TODO: Fix linux-raw-sys to define ioctl codes for sparc. + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] + const EXT4_IOC_RESIZE_FS: u32 = 0x8008_6610; + + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] + use linux_raw_sys::ioctl::EXT4_IOC_RESIZE_FS; + + unsafe { ret(c::ioctl(borrowed_fd(fd), EXT4_IOC_RESIZE_FS as _, &blocks)) } +} |