summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/backend/libc/fs/syscalls.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/backend/libc/fs/syscalls.rs')
-rw-r--r--vendor/rustix/src/backend/libc/fs/syscalls.rs874
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)) }
+}