summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/imp/linux_raw/fs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/imp/linux_raw/fs')
-rw-r--r--vendor/rustix/src/imp/linux_raw/fs/dir.rs213
-rw-r--r--vendor/rustix/src/imp/linux_raw/fs/makedev.rs19
-rw-r--r--vendor/rustix/src/imp/linux_raw/fs/mod.rs5
-rw-r--r--vendor/rustix/src/imp/linux_raw/fs/syscalls.rs1391
-rw-r--r--vendor/rustix/src/imp/linux_raw/fs/types.rs613
5 files changed, 2241 insertions, 0 deletions
diff --git a/vendor/rustix/src/imp/linux_raw/fs/dir.rs b/vendor/rustix/src/imp/linux_raw/fs/dir.rs
new file mode 100644
index 000000000..64f5aa652
--- /dev/null
+++ b/vendor/rustix/src/imp/linux_raw/fs/dir.rs
@@ -0,0 +1,213 @@
+use crate::fd::{AsFd, BorrowedFd};
+use crate::ffi::{CStr, CString};
+use crate::fs::{fcntl_getfl, fstat, fstatfs, openat, FileType, Mode, OFlags, Stat, StatFs};
+use crate::io::{self, OwnedFd};
+use crate::process::fchdir;
+use crate::utils::as_ptr;
+use alloc::borrow::ToOwned;
+use alloc::vec::Vec;
+use core::fmt;
+use core::mem::size_of;
+use linux_raw_sys::general::{linux_dirent64, SEEK_SET};
+
+/// `DIR*`
+pub struct Dir {
+ /// The `OwnedFd` that we read directory entries from.
+ fd: OwnedFd,
+
+ buf: Vec<u8>,
+ pos: usize,
+ next: Option<u64>,
+}
+
+impl Dir {
+ /// Construct a `Dir` that reads entries from the given directory
+ /// file descriptor.
+ #[inline]
+ pub fn read_from<Fd: AsFd>(fd: Fd) -> io::Result<Self> {
+ Self::_read_from(fd.as_fd())
+ }
+
+ #[inline]
+ fn _read_from(fd: BorrowedFd<'_>) -> io::Result<Self> {
+ let flags = fcntl_getfl(fd)?;
+ let fd_for_dir = openat(fd, cstr!("."), flags | OFlags::CLOEXEC, Mode::empty())?;
+
+ Ok(Self {
+ fd: fd_for_dir,
+ buf: Vec::new(),
+ pos: 0,
+ next: None,
+ })
+ }
+
+ /// `rewinddir(self)`
+ #[inline]
+ pub fn rewind(&mut self) {
+ self.pos = self.buf.len();
+ self.next = Some(0);
+ }
+
+ /// `readdir(self)`, where `None` means the end of the directory.
+ pub fn read(&mut self) -> Option<io::Result<DirEntry>> {
+ if let Some(next) = self.next.take() {
+ match crate::imp::fs::syscalls::_seek(self.fd.as_fd(), next as i64, SEEK_SET) {
+ Ok(_) => (),
+ Err(err) => return Some(Err(err)),
+ }
+ }
+
+ // Compute linux_dirent64 field offsets.
+ let z = linux_dirent64 {
+ d_ino: 0_u64,
+ d_off: 0_i64,
+ d_type: 0_u8,
+ d_reclen: 0_u16,
+ d_name: Default::default(),
+ };
+ let base = as_ptr(&z) as usize;
+ let offsetof_d_reclen = (as_ptr(&z.d_reclen) as usize) - base;
+ let offsetof_d_name = (as_ptr(&z.d_name) as usize) - base;
+ let offsetof_d_ino = (as_ptr(&z.d_ino) as usize) - base;
+ let offsetof_d_type = (as_ptr(&z.d_type) as usize) - base;
+
+ // Test if we need more entries, and if so, read more.
+ if self.buf.len() - self.pos < size_of::<linux_dirent64>() {
+ match self.read_more()? {
+ Ok(()) => (),
+ Err(e) => return Some(Err(e)),
+ }
+ }
+
+ // We successfully read an entry. Extract the fields.
+ let pos = self.pos;
+
+ // Do an unaligned u16 load.
+ let d_reclen = u16::from_ne_bytes([
+ self.buf[pos + offsetof_d_reclen],
+ self.buf[pos + offsetof_d_reclen + 1],
+ ]);
+ assert!(self.buf.len() - pos >= d_reclen as usize);
+ self.pos += d_reclen as usize;
+
+ // Read the NUL-terminated name from the `d_name` field. Without
+ // `unsafe`, we need to scan for the NUL twice: once to obtain a size
+ // for the slice, and then once within `CStr::from_bytes_with_nul`.
+ let name_start = pos + offsetof_d_name;
+ let name_len = self.buf[name_start..]
+ .iter()
+ .position(|x| *x == b'\0')
+ .unwrap();
+ let name =
+ CStr::from_bytes_with_nul(&self.buf[name_start..name_start + name_len + 1]).unwrap();
+ let name = name.to_owned();
+ assert!(name.as_bytes().len() <= self.buf.len() - name_start);
+
+ // Do an unaligned u64 load.
+ let d_ino = u64::from_ne_bytes([
+ self.buf[pos + offsetof_d_ino],
+ self.buf[pos + offsetof_d_ino + 1],
+ self.buf[pos + offsetof_d_ino + 2],
+ self.buf[pos + offsetof_d_ino + 3],
+ self.buf[pos + offsetof_d_ino + 4],
+ self.buf[pos + offsetof_d_ino + 5],
+ self.buf[pos + offsetof_d_ino + 6],
+ self.buf[pos + offsetof_d_ino + 7],
+ ]);
+
+ let d_type = self.buf[pos + offsetof_d_type];
+
+ // Check that our types correspond to the `linux_dirent64` types.
+ let _ = linux_dirent64 {
+ d_ino,
+ d_off: 0,
+ d_type,
+ d_reclen,
+ d_name: Default::default(),
+ };
+
+ Some(Ok(DirEntry {
+ d_ino,
+ d_type,
+ name,
+ }))
+ }
+
+ fn read_more(&mut self) -> Option<io::Result<()>> {
+ // Capacity increment currently chosen by wild guess.
+ self.buf
+ .resize(self.buf.capacity() + 32 * size_of::<linux_dirent64>(), 0);
+ self.pos = 0;
+ let nread = match crate::imp::fs::syscalls::getdents(self.fd.as_fd(), &mut self.buf) {
+ Ok(nread) => nread,
+ Err(err) => return Some(Err(err)),
+ };
+ self.buf.resize(nread, 0);
+ if nread == 0 {
+ None
+ } else {
+ Some(Ok(()))
+ }
+ }
+
+ /// `fstat(self)`
+ #[inline]
+ pub fn stat(&self) -> io::Result<Stat> {
+ fstat(&self.fd)
+ }
+
+ /// `fstatfs(self)`
+ #[inline]
+ pub fn statfs(&self) -> io::Result<StatFs> {
+ fstatfs(&self.fd)
+ }
+
+ /// `fchdir(self)`
+ #[inline]
+ pub fn chdir(&self) -> io::Result<()> {
+ fchdir(&self.fd)
+ }
+}
+
+impl Iterator for Dir {
+ type Item = io::Result<DirEntry>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ Self::read(self)
+ }
+}
+
+impl fmt::Debug for Dir {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Dir").field("fd", &self.fd).finish()
+ }
+}
+
+/// `struct dirent`
+#[derive(Debug)]
+pub struct DirEntry {
+ d_ino: u64,
+ d_type: u8,
+ name: CString,
+}
+
+impl DirEntry {
+ /// Returns the file name of this directory entry.
+ #[inline]
+ pub fn file_name(&self) -> &CStr {
+ &self.name
+ }
+
+ /// Returns the type of this directory entry.
+ #[inline]
+ pub fn file_type(&self) -> FileType {
+ FileType::from_dirent_d_type(self.d_type)
+ }
+
+ /// Return the inode number of this directory entry.
+ #[inline]
+ pub fn ino(&self) -> u64 {
+ self.d_ino
+ }
+}
diff --git a/vendor/rustix/src/imp/linux_raw/fs/makedev.rs b/vendor/rustix/src/imp/linux_raw/fs/makedev.rs
new file mode 100644
index 000000000..284ba2f10
--- /dev/null
+++ b/vendor/rustix/src/imp/linux_raw/fs/makedev.rs
@@ -0,0 +1,19 @@
+use crate::fs::Dev;
+
+#[inline]
+pub(crate) fn makedev(maj: u32, min: u32) -> Dev {
+ ((u64::from(maj) & 0xffff_f000_u64) << 32)
+ | ((u64::from(maj) & 0x0000_0fff_u64) << 8)
+ | ((u64::from(min) & 0xffff_ff00_u64) << 12)
+ | (u64::from(min) & 0x0000_00ff_u64)
+}
+
+#[inline]
+pub(crate) fn major(dev: Dev) -> u32 {
+ (((dev >> 31 >> 1) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)) as u32
+}
+
+#[inline]
+pub(crate) fn minor(dev: Dev) -> u32 {
+ (((dev >> 12) & 0xffff_ff00) | (dev & 0x0000_00ff)) as u32
+}
diff --git a/vendor/rustix/src/imp/linux_raw/fs/mod.rs b/vendor/rustix/src/imp/linux_raw/fs/mod.rs
new file mode 100644
index 000000000..641e65744
--- /dev/null
+++ b/vendor/rustix/src/imp/linux_raw/fs/mod.rs
@@ -0,0 +1,5 @@
+#[cfg(any(feature = "fs", feature = "procfs"))]
+pub(crate) mod dir;
+pub(crate) mod makedev;
+pub(crate) mod syscalls;
+pub(crate) mod types;
diff --git a/vendor/rustix/src/imp/linux_raw/fs/syscalls.rs b/vendor/rustix/src/imp/linux_raw/fs/syscalls.rs
new file mode 100644
index 000000000..db1ecaaf6
--- /dev/null
+++ b/vendor/rustix/src/imp/linux_raw/fs/syscalls.rs
@@ -0,0 +1,1391 @@
+//! linux_raw syscalls supporting `rustix::fs`.
+//!
+//! # Safety
+//!
+//! See the `rustix::imp` module documentation for details.
+#![allow(unsafe_code)]
+#![allow(dead_code)]
+#![allow(clippy::undocumented_unsafe_blocks)]
+
+use super::super::c;
+use super::super::conv::{
+ by_ref, c_int, c_uint, dev_t, oflags_for_open_how, opt_mut, pass_usize, raw_fd, ret, ret_c_int,
+ ret_c_uint, ret_owned_fd, ret_usize, size_of, slice_mut, zero,
+};
+#[cfg(target_pointer_width = "64")]
+use super::super::conv::{loff_t, loff_t_from_u64, ret_u64};
+#[cfg(any(
+ target_arch = "aarch64",
+ target_arch = "riscv64",
+ target_arch = "mips64",
+ target_pointer_width = "32",
+))]
+use crate::fd::AsFd;
+use crate::fd::{BorrowedFd, RawFd};
+use crate::ffi::CStr;
+use crate::fs::{
+ Access, Advice, AtFlags, FallocateFlags, FdFlags, FileType, FlockOperation, MemfdFlags, Mode,
+ OFlags, RenameFlags, ResolveFlags, SealFlags, Stat, StatFs, StatxFlags, Timestamps,
+};
+use crate::io::{self, OwnedFd, SeekFrom};
+use crate::process::{Gid, Uid};
+use core::convert::TryInto;
+use core::mem::MaybeUninit;
+#[cfg(target_arch = "mips64")]
+use linux_raw_sys::general::stat as linux_stat64;
+use linux_raw_sys::general::{
+ __kernel_timespec, open_how, statx, AT_EACCESS, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW,
+ F_ADD_SEALS, F_DUPFD, F_DUPFD_CLOEXEC, F_GETFD, F_GETFL, F_GETLEASE, F_GETOWN, F_GETPIPE_SZ,
+ F_GETSIG, F_GET_SEALS, F_SETFD, F_SETFL, F_SETPIPE_SZ, SEEK_CUR, SEEK_END, SEEK_SET,
+};
+#[cfg(target_pointer_width = "32")]
+use {
+ super::super::conv::{hi, lo, slice_just_addr},
+ linux_raw_sys::general::stat64 as linux_stat64,
+ linux_raw_sys::general::timespec as __kernel_old_timespec,
+};
+
+#[inline]
+pub(crate) fn open(filename: &CStr, flags: OFlags, mode: Mode) -> io::Result<OwnedFd> {
+ #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
+ {
+ openat(crate::fs::cwd().as_fd(), filename, flags, mode)
+ }
+ #[cfg(all(
+ target_pointer_width = "32",
+ not(any(target_arch = "aarch64", target_arch = "riscv64")),
+ ))]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(__NR_open, filename, flags, mode))
+ }
+ #[cfg(all(
+ target_pointer_width = "64",
+ not(any(target_arch = "aarch64", target_arch = "riscv64")),
+ ))]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(__NR_open, filename, flags, mode))
+ }
+}
+
+#[inline]
+pub(crate) fn openat(
+ dirfd: BorrowedFd<'_>,
+ filename: &CStr,
+ flags: OFlags,
+ mode: Mode,
+) -> io::Result<OwnedFd> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(__NR_openat, dirfd, filename, flags, mode))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(__NR_openat, dirfd, filename, flags, mode))
+ }
+}
+
+#[inline]
+pub(crate) fn openat2(
+ dirfd: BorrowedFd<'_>,
+ pathname: &CStr,
+ flags: OFlags,
+ mode: Mode,
+ resolve: ResolveFlags,
+) -> io::Result<OwnedFd> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_openat2,
+ dirfd,
+ pathname,
+ by_ref(&open_how {
+ flags: oflags_for_open_how(flags),
+ mode: u64::from(mode.bits()),
+ resolve: resolve.bits(),
+ }),
+ size_of::<open_how, _>()
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_openat2,
+ dirfd,
+ pathname,
+ by_ref(&open_how {
+ flags: oflags_for_open_how(flags),
+ mode: u64::from(mode.bits()),
+ resolve: resolve.bits(),
+ }),
+ size_of::<open_how, _>()
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn chmod(filename: &CStr, mode: Mode) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fchmodat,
+ raw_fd(AT_FDCWD),
+ filename,
+ mode
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn chmodat(dirfd: BorrowedFd<'_>, filename: &CStr, mode: Mode) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_fchmodat, dirfd, filename, mode)) }
+}
+
+#[inline]
+pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_fchmod, fd, mode)) }
+}
+
+#[inline]
+pub(crate) fn chownat(
+ dirfd: BorrowedFd<'_>,
+ filename: &CStr,
+ owner: Option<Uid>,
+ group: Option<Gid>,
+ flags: AtFlags,
+) -> io::Result<()> {
+ unsafe {
+ let (ow, gr) = crate::process::translate_fchown_args(owner, group);
+ ret(syscall_readonly!(
+ __NR_fchownat,
+ dirfd,
+ filename,
+ c_uint(ow),
+ c_uint(gr),
+ flags
+ ))
+ }
+}
+
+#[inline]
+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);
+ ret(syscall_readonly!(__NR_fchown, fd, c_uint(ow), c_uint(gr)))
+ }
+}
+
+#[inline]
+pub(crate) fn mknodat(
+ dirfd: BorrowedFd<'_>,
+ filename: &CStr,
+ file_type: FileType,
+ mode: Mode,
+ dev: u64,
+) -> io::Result<()> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_mknodat,
+ dirfd,
+ filename,
+ (mode, file_type),
+ dev_t(dev)?
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_mknodat,
+ dirfd,
+ filename,
+ (mode, file_type),
+ dev_t(dev)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> {
+ let (whence, offset) = match pos {
+ SeekFrom::Start(pos) => {
+ let pos: u64 = pos;
+ // Silently cast; we'll get `EINVAL` if the value is negative.
+ (SEEK_SET, pos as i64)
+ }
+ SeekFrom::End(offset) => (SEEK_END, offset),
+ SeekFrom::Current(offset) => (SEEK_CUR, offset),
+ };
+ _seek(fd, offset, whence)
+}
+
+#[inline]
+pub(crate) fn _seek(fd: BorrowedFd<'_>, offset: i64, whence: c::c_uint) -> io::Result<u64> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ let mut result = MaybeUninit::<u64>::uninit();
+ ret(syscall!(
+ __NR__llseek,
+ fd,
+ // Don't use the hi/lo functions here because Linux's llseek
+ // takes its 64-bit argument differently from everything else.
+ pass_usize((offset >> 32) as usize),
+ pass_usize(offset as usize),
+ &mut result,
+ c_uint(whence)
+ ))
+ .map(|()| result.assume_init())
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_u64(syscall_readonly!(
+ __NR_lseek,
+ fd,
+ loff_t(offset),
+ c_uint(whence)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn tell(fd: BorrowedFd<'_>) -> io::Result<u64> {
+ _seek(fd, 0, SEEK_CUR).map(|x| x as u64)
+}
+
+#[inline]
+pub(crate) fn ftruncate(fd: BorrowedFd<'_>, length: u64) -> io::Result<()> {
+ // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L81-L83>
+ #[cfg(all(
+ target_pointer_width = "32",
+ any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc"),
+ ))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_ftruncate64,
+ fd,
+ zero(),
+ hi(length),
+ lo(length)
+ ))
+ }
+ #[cfg(all(
+ target_pointer_width = "32",
+ not(any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc")),
+ ))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_ftruncate64,
+ fd,
+ hi(length),
+ lo(length)
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_ftruncate,
+ fd,
+ loff_t_from_u64(length)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fallocate(
+ fd: BorrowedFd<'_>,
+ mode: FallocateFlags,
+ offset: u64,
+ len: u64,
+) -> io::Result<()> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fallocate,
+ fd,
+ mode,
+ hi(offset),
+ lo(offset),
+ hi(len),
+ lo(len)
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fallocate,
+ fd,
+ mode,
+ loff_t_from_u64(offset),
+ loff_t_from_u64(len)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fadvise(fd: BorrowedFd<'_>, pos: u64, len: u64, advice: Advice) -> io::Result<()> {
+ // On ARM, the arguments are reordered so that the len and pos argument
+ // pairs are aligned. And ARM has a custom syscall code for this.
+ #[cfg(target_arch = "arm")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_arm_fadvise64_64,
+ fd,
+ advice,
+ hi(pos),
+ lo(pos),
+ hi(len),
+ lo(len)
+ ))
+ }
+
+ // On powerpc, the arguments are reordered as on ARM.
+ #[cfg(target_arch = "powerpc")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fadvise64_64,
+ fd,
+ advice,
+ hi(pos),
+ lo(pos),
+ hi(len),
+ lo(len)
+ ))
+ }
+ // On mips, the arguments are not reordered, and padding is inserted
+ // instead to ensure alignment.
+ #[cfg(target_arch = "mips")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fadvise64,
+ fd,
+ zero(),
+ hi(pos),
+ lo(pos),
+ hi(len),
+ lo(len),
+ advice
+ ))
+ }
+ #[cfg(all(
+ target_pointer_width = "32",
+ not(any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc")),
+ ))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fadvise64_64,
+ fd,
+ hi(pos),
+ lo(pos),
+ hi(len),
+ lo(len),
+ advice
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fadvise64,
+ fd,
+ loff_t_from_u64(pos),
+ loff_t_from_u64(len),
+ advice
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fsync(fd: BorrowedFd<'_>) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_fsync, fd)) }
+}
+
+#[inline]
+pub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_fdatasync, fd)) }
+}
+
+#[inline]
+pub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> {
+ unsafe { ret(syscall!(__NR_flock, fd, c_uint(operation as c::c_uint))) }
+}
+
+#[inline]
+pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> {
+ #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+ {
+ match statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
+ Ok(x) => statx_to_stat(x),
+ Err(io::Errno::NOSYS) => fstat_old(fd),
+ Err(e) => Err(e),
+ }
+ }
+
+ #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
+ unsafe {
+ let mut result = MaybeUninit::<Stat>::uninit();
+ ret(syscall!(__NR_fstat, fd, &mut result)).map(|()| result.assume_init())
+ }
+}
+
+#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> {
+ let mut result = MaybeUninit::<linux_stat64>::uninit();
+
+ #[cfg(target_arch = "mips64")]
+ unsafe {
+ ret(syscall!(__NR_fstat, fd, &mut result))?;
+ stat_to_stat(result.assume_init())
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall!(__NR_fstat64, fd, &mut result))?;
+ stat_to_stat(result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn stat(filename: &CStr) -> io::Result<Stat> {
+ #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+ {
+ match statx(
+ crate::fs::cwd().as_fd(),
+ filename,
+ AtFlags::empty(),
+ StatxFlags::BASIC_STATS,
+ ) {
+ Ok(x) => return statx_to_stat(x),
+ Err(io::Errno::NOSYS) => stat_old(filename),
+ Err(e) => return Err(e),
+ }
+ }
+
+ #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
+ unsafe {
+ let mut result = MaybeUninit::<Stat>::uninit();
+ ret(syscall!(
+ __NR_newfstatat,
+ raw_fd(AT_FDCWD),
+ filename,
+ &mut result,
+ c_uint(0)
+ ))
+ .map(|()| result.assume_init())
+ }
+}
+
+#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+fn stat_old(filename: &CStr) -> io::Result<Stat> {
+ let mut result = MaybeUninit::<linux_stat64>::uninit();
+
+ #[cfg(target_arch = "mips64")]
+ unsafe {
+ ret(syscall!(
+ __NR_newfstatat,
+ raw_fd(AT_FDCWD),
+ filename,
+ &mut result,
+ c_uint(0)
+ ))?;
+ stat_to_stat(result.assume_init())
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall!(
+ __NR_fstatat64,
+ raw_fd(AT_FDCWD),
+ filename,
+ &mut result,
+ c_uint(0)
+ ))?;
+ stat_to_stat(result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn statat(dirfd: BorrowedFd<'_>, filename: &CStr, flags: AtFlags) -> io::Result<Stat> {
+ #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+ {
+ match statx(dirfd, filename, flags, StatxFlags::BASIC_STATS) {
+ Ok(x) => return statx_to_stat(x),
+ Err(io::Errno::NOSYS) => statat_old(dirfd, filename, flags),
+ Err(e) => return Err(e),
+ }
+ }
+
+ #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
+ unsafe {
+ let mut result = MaybeUninit::<Stat>::uninit();
+ ret(syscall!(
+ __NR_newfstatat,
+ dirfd,
+ filename,
+ &mut result,
+ flags
+ ))
+ .map(|()| result.assume_init())
+ }
+}
+
+#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+fn statat_old(dirfd: BorrowedFd<'_>, filename: &CStr, flags: AtFlags) -> io::Result<Stat> {
+ let mut result = MaybeUninit::<linux_stat64>::uninit();
+
+ #[cfg(target_arch = "mips64")]
+ unsafe {
+ ret(syscall!(
+ __NR_newfstatat,
+ dirfd,
+ filename,
+ &mut result,
+ flags
+ ))?;
+ stat_to_stat(result.assume_init())
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall!(
+ __NR_fstatat64,
+ dirfd,
+ filename,
+ &mut result,
+ flags
+ ))?;
+ stat_to_stat(result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn lstat(filename: &CStr) -> io::Result<Stat> {
+ #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+ {
+ match statx(
+ crate::fs::cwd().as_fd(),
+ filename,
+ AtFlags::SYMLINK_NOFOLLOW,
+ StatxFlags::BASIC_STATS,
+ ) {
+ Ok(x) => return statx_to_stat(x),
+ Err(io::Errno::NOSYS) => lstat_old(filename),
+ Err(e) => return Err(e),
+ }
+ }
+
+ #[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
+ unsafe {
+ let mut result = MaybeUninit::<Stat>::uninit();
+ ret(syscall!(
+ __NR_newfstatat,
+ raw_fd(AT_FDCWD),
+ filename,
+ &mut result,
+ c_uint(AT_SYMLINK_NOFOLLOW)
+ ))
+ .map(|()| result.assume_init())
+ }
+}
+
+#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+fn lstat_old(filename: &CStr) -> io::Result<Stat> {
+ let mut result = MaybeUninit::<linux_stat64>::uninit();
+
+ #[cfg(target_arch = "mips64")]
+ unsafe {
+ ret(syscall!(
+ __NR_newfstatat,
+ raw_fd(AT_FDCWD),
+ filename,
+ &mut result,
+ c_uint(AT_SYMLINK_NOFOLLOW)
+ ))?;
+ stat_to_stat(result.assume_init())
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall!(
+ __NR_fstatat64,
+ raw_fd(AT_FDCWD),
+ filename,
+ &mut result,
+ c_uint(AT_SYMLINK_NOFOLLOW)
+ ))?;
+ stat_to_stat(result.assume_init())
+ }
+}
+
+/// Convert from a Linux `statx` value to rustix's `Stat`.
+#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+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),
+ st_mode: x.stx_mode.into(),
+ st_nlink: x.stx_nlink.into(),
+ st_uid: x.stx_uid.into(),
+ st_gid: x.stx_gid.into(),
+ st_rdev: crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor),
+ st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_blksize: x.stx_blksize.into(),
+ st_blocks: x.stx_blocks.into(),
+ st_atime: x
+ .stx_atime
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_atime_nsec: x.stx_atime.tv_nsec.into(),
+ st_mtime: x
+ .stx_mtime
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_mtime_nsec: x.stx_mtime.tv_nsec.into(),
+ st_ctime: x
+ .stx_ctime
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_ctime_nsec: x.stx_ctime.tv_nsec.into(),
+ st_ino: x.stx_ino.into(),
+ })
+}
+
+/// Convert from a Linux `stat64` value to rustix's `Stat`.
+#[cfg(target_pointer_width = "32")]
+fn stat_to_stat(s64: linux_raw_sys::general::stat64) -> io::Result<Stat> {
+ Ok(Stat {
+ st_dev: s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_mode: s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_nlink: s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_uid: s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_gid: s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_rdev: s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_size: s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_blksize: s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_blocks: s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_atime: s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_atime_nsec: s64
+ .st_atime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_mtime: s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_mtime_nsec: s64
+ .st_mtime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_ctime: s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_ctime_nsec: s64
+ .st_ctime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_ino: s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ })
+}
+
+/// Convert from a Linux `stat` value to rustix's `Stat`.
+#[cfg(target_arch = "mips64")]
+fn stat_to_stat(s: linux_raw_sys::general::stat) -> io::Result<Stat> {
+ Ok(Stat {
+ st_dev: s.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_mode: s.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_nlink: s.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_uid: s.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_gid: s.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_rdev: s.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_size: s.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_blksize: s.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_blocks: s.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_atime: s.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_atime_nsec: s
+ .st_atime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_mtime: s.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_mtime_nsec: s
+ .st_mtime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_ctime: s.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ st_ctime_nsec: s
+ .st_ctime_nsec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ st_ino: s.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?,
+ })
+}
+
+#[inline]
+pub(crate) fn statx(
+ dirfd: BorrowedFd<'_>,
+ pathname: &CStr,
+ flags: AtFlags,
+ mask: StatxFlags,
+) -> io::Result<statx> {
+ unsafe {
+ let mut statx_buf = MaybeUninit::<statx>::uninit();
+ ret(syscall!(
+ __NR_statx,
+ dirfd,
+ pathname,
+ flags,
+ mask,
+ &mut statx_buf
+ ))
+ .map(|()| statx_buf.assume_init())
+ }
+}
+
+#[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(syscall!(
+ __NR_statx,
+ raw_fd(AT_FDCWD),
+ zero(),
+ zero(),
+ zero(),
+ zero()
+ )),
+ Err(io::Errno::FAULT)
+ )
+ }
+}
+
+#[inline]
+pub(crate) fn fstatfs(fd: BorrowedFd<'_>) -> io::Result<StatFs> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ let mut result = MaybeUninit::<StatFs>::uninit();
+ ret(syscall!(
+ __NR_fstatfs64,
+ fd,
+ size_of::<StatFs, _>(),
+ &mut result
+ ))
+ .map(|()| result.assume_init())
+ }
+
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ let mut result = MaybeUninit::<StatFs>::uninit();
+ ret(syscall!(__NR_fstatfs, fd, &mut result)).map(|()| result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn statfs(filename: &CStr) -> io::Result<StatFs> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ let mut result = MaybeUninit::<StatFs>::uninit();
+ ret(syscall!(
+ __NR_statfs64,
+ filename,
+ size_of::<StatFs, _>(),
+ &mut result
+ ))
+ .map(|()| result.assume_init())
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ let mut result = MaybeUninit::<StatFs>::uninit();
+ ret(syscall!(__NR_statfs, filename, &mut result)).map(|()| result.assume_init())
+ }
+}
+
+#[inline]
+pub(crate) fn readlink(path: &CStr, buf: &mut [u8]) -> io::Result<usize> {
+ let (buf_addr_mut, buf_len) = slice_mut(buf);
+ unsafe {
+ ret_usize(syscall!(
+ __NR_readlinkat,
+ raw_fd(AT_FDCWD),
+ path,
+ buf_addr_mut,
+ buf_len
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, buf: &mut [u8]) -> io::Result<usize> {
+ let (buf_addr_mut, buf_len) = slice_mut(buf);
+ unsafe {
+ ret_usize(syscall!(
+ __NR_readlinkat,
+ dirfd,
+ path,
+ buf_addr_mut,
+ buf_len
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_dupfd(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_fcntl64,
+ fd,
+ c_uint(F_DUPFD),
+ raw_fd(min)
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_fcntl,
+ fd,
+ c_uint(F_DUPFD),
+ raw_fd(min)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_fcntl64,
+ fd,
+ c_uint(F_DUPFD_CLOEXEC),
+ raw_fd(min)
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_fcntl,
+ fd,
+ c_uint(F_DUPFD_CLOEXEC),
+ raw_fd(min)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result<FdFlags> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_c_uint(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETFD)))
+ .map(FdFlags::from_bits_truncate)
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFD)))
+ .map(FdFlags::from_bits_truncate)
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_SETFD), flags))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(__NR_fcntl, fd, c_uint(F_SETFD), flags))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_getfl(fd: BorrowedFd<'_>) -> io::Result<OFlags> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_c_uint(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETFL)))
+ .map(OFlags::from_bits_truncate)
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFL)))
+ .map(OFlags::from_bits_truncate)
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_setfl(fd: BorrowedFd<'_>, flags: OFlags) -> io::Result<()> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_SETFL), flags))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(__NR_fcntl, fd, c_uint(F_SETFL), flags))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_getlease(fd: BorrowedFd<'_>) -> io::Result<c::c_int> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETLEASE)))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETLEASE)))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_getown(fd: BorrowedFd<'_>) -> io::Result<c::c_int> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETOWN)))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETOWN)))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_getsig(fd: BorrowedFd<'_>) -> io::Result<c::c_int> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETSIG)))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETSIG)))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_getpipe_sz(fd: BorrowedFd<'_>) -> io::Result<usize> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_usize(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETPIPE_SZ)))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_usize(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETPIPE_SZ)))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_setpipe_sz(fd: BorrowedFd<'_>, size: c::c_int) -> io::Result<usize> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_usize(syscall_readonly!(
+ __NR_fcntl64,
+ fd,
+ c_uint(F_SETPIPE_SZ),
+ c_int(size)
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_usize(syscall_readonly!(
+ __NR_fcntl,
+ fd,
+ c_uint(F_SETPIPE_SZ),
+ c_int(size)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_get_seals(fd: BorrowedFd<'_>) -> io::Result<SealFlags> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_c_int(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GET_SEALS)))
+ .map(|seals| SealFlags::from_bits_unchecked(seals as u32))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_c_int(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GET_SEALS)))
+ .map(|seals| SealFlags::from_bits_unchecked(seals as u32))
+ }
+}
+
+#[inline]
+pub(crate) fn fcntl_add_seals(fd: BorrowedFd<'_>, seals: SealFlags) -> io::Result<()> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fcntl64,
+ fd,
+ c_uint(F_ADD_SEALS),
+ seals
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_fcntl,
+ fd,
+ c_uint(F_ADD_SEALS),
+ seals
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn rename(oldname: &CStr, newname: &CStr) -> io::Result<()> {
+ #[cfg(target_arch = "riscv64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat2,
+ raw_fd(AT_FDCWD),
+ oldname,
+ raw_fd(AT_FDCWD),
+ newname,
+ c_uint(0)
+ ))
+ }
+ #[cfg(not(target_arch = "riscv64"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat,
+ raw_fd(AT_FDCWD),
+ oldname,
+ raw_fd(AT_FDCWD),
+ newname
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn renameat(
+ old_dirfd: BorrowedFd<'_>,
+ oldname: &CStr,
+ new_dirfd: BorrowedFd<'_>,
+ newname: &CStr,
+) -> io::Result<()> {
+ #[cfg(target_arch = "riscv64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat2,
+ old_dirfd,
+ oldname,
+ new_dirfd,
+ newname,
+ c_uint(0)
+ ))
+ }
+ #[cfg(not(target_arch = "riscv64"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat,
+ old_dirfd,
+ oldname,
+ new_dirfd,
+ newname
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn renameat2(
+ old_dirfd: BorrowedFd<'_>,
+ oldname: &CStr,
+ new_dirfd: BorrowedFd<'_>,
+ newname: &CStr,
+ flags: RenameFlags,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_renameat2,
+ old_dirfd,
+ oldname,
+ new_dirfd,
+ newname,
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn unlink(pathname: &CStr) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_unlinkat,
+ raw_fd(AT_FDCWD),
+ pathname,
+ c_uint(0)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn unlinkat(dirfd: BorrowedFd<'_>, pathname: &CStr, flags: AtFlags) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_unlinkat, dirfd, pathname, flags)) }
+}
+
+#[inline]
+pub(crate) fn rmdir(pathname: &CStr) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_unlinkat,
+ raw_fd(AT_FDCWD),
+ pathname,
+ c_uint(AT_REMOVEDIR)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn link(oldname: &CStr, newname: &CStr) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_linkat,
+ raw_fd(AT_FDCWD),
+ oldname,
+ raw_fd(AT_FDCWD),
+ newname,
+ c_uint(0)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn linkat(
+ old_dirfd: BorrowedFd<'_>,
+ oldname: &CStr,
+ new_dirfd: BorrowedFd<'_>,
+ newname: &CStr,
+ flags: AtFlags,
+) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_linkat,
+ old_dirfd,
+ oldname,
+ new_dirfd,
+ newname,
+ flags
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn symlink(oldname: &CStr, newname: &CStr) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_symlinkat,
+ oldname,
+ raw_fd(AT_FDCWD),
+ newname
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn symlinkat(oldname: &CStr, dirfd: BorrowedFd<'_>, newname: &CStr) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_symlinkat, oldname, dirfd, newname)) }
+}
+
+#[inline]
+pub(crate) fn mkdir(pathname: &CStr, mode: Mode) -> io::Result<()> {
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_mkdirat,
+ raw_fd(AT_FDCWD),
+ pathname,
+ mode
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn mkdirat(dirfd: BorrowedFd<'_>, pathname: &CStr, mode: Mode) -> io::Result<()> {
+ unsafe { ret(syscall_readonly!(__NR_mkdirat, dirfd, pathname, mode)) }
+}
+
+#[inline]
+pub(crate) fn getdents(fd: BorrowedFd<'_>, dirent: &mut [u8]) -> io::Result<usize> {
+ let (dirent_addr_mut, dirent_len) = slice_mut(dirent);
+
+ unsafe { ret_usize(syscall!(__NR_getdents64, fd, dirent_addr_mut, dirent_len)) }
+}
+
+#[inline]
+pub(crate) fn utimensat(
+ dirfd: BorrowedFd<'_>,
+ pathname: &CStr,
+ times: &Timestamps,
+ flags: AtFlags,
+) -> io::Result<()> {
+ _utimensat(dirfd, Some(pathname), times, flags)
+}
+
+#[inline]
+fn _utimensat(
+ dirfd: BorrowedFd<'_>,
+ pathname: Option<&CStr>,
+ times: &Timestamps,
+ flags: AtFlags,
+) -> io::Result<()> {
+ // Assert that `Timestamps` has the expected layout.
+ let _ = unsafe { core::mem::transmute::<Timestamps, [__kernel_timespec; 2]>(times.clone()) };
+
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ match ret(syscall_readonly!(
+ __NR_utimensat_time64,
+ dirfd,
+ pathname,
+ by_ref(times),
+ flags
+ )) {
+ Err(io::Errno::NOSYS) => _utimensat_old(dirfd, pathname, times, flags),
+ otherwise => otherwise,
+ }
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_utimensat,
+ dirfd,
+ pathname,
+ by_ref(times),
+ flags
+ ))
+ }
+}
+
+#[cfg(target_pointer_width = "32")]
+unsafe fn _utimensat_old(
+ dirfd: BorrowedFd<'_>,
+ pathname: Option<&CStr>,
+ times: &Timestamps,
+ flags: AtFlags,
+) -> io::Result<()> {
+ // See the comments in `rustix_clock_gettime_via_syscall` about
+ // emulation.
+ let old_times = [
+ __kernel_old_timespec {
+ tv_sec: times
+ .last_access
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ tv_nsec: times
+ .last_access
+ .tv_nsec
+ .try_into()
+ .map_err(|_| io::Errno::INVAL)?,
+ },
+ __kernel_old_timespec {
+ tv_sec: times
+ .last_modification
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ tv_nsec: times
+ .last_modification
+ .tv_nsec
+ .try_into()
+ .map_err(|_| io::Errno::INVAL)?,
+ },
+ ];
+ // The length of the array is fixed and not passed into the syscall.
+ let old_times_addr = slice_just_addr(&old_times);
+ ret(syscall_readonly!(
+ __NR_utimensat,
+ dirfd,
+ pathname,
+ old_times_addr,
+ flags
+ ))
+}
+
+#[inline]
+pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> {
+ _utimensat(fd, None, times, AtFlags::empty())
+}
+
+pub(crate) fn accessat(
+ dirfd: BorrowedFd<'_>,
+ path: &CStr,
+ access: Access,
+ flags: AtFlags,
+) -> io::Result<()> {
+ // Linux's `faccessat` doesn't have a flags parameter. If we have
+ // `AT_EACCESS` and we're not setuid or setgid, we can emulate it.
+ if flags.is_empty()
+ || (flags.bits() == AT_EACCESS
+ && crate::process::getuid() == crate::process::geteuid()
+ && crate::process::getgid() == crate::process::getegid())
+ {
+ return unsafe { ret(syscall_readonly!(__NR_faccessat, dirfd, path, access)) };
+ }
+
+ if flags.bits() != AT_EACCESS {
+ return Err(io::Errno::INVAL);
+ }
+
+ // TODO: Use faccessat2 in newer Linux versions.
+ Err(io::Errno::NOSYS)
+}
+
+#[inline]
+pub(crate) fn copy_file_range(
+ fd_in: BorrowedFd<'_>,
+ off_in: Option<&mut u64>,
+ fd_out: BorrowedFd<'_>,
+ off_out: Option<&mut u64>,
+ len: u64,
+) -> io::Result<u64> {
+ let len: usize = len.try_into().unwrap_or(usize::MAX);
+ _copy_file_range(fd_in, off_in, fd_out, off_out, len, 0).map(|result| result as u64)
+}
+
+#[inline]
+fn _copy_file_range(
+ fd_in: BorrowedFd<'_>,
+ off_in: Option<&mut u64>,
+ fd_out: BorrowedFd<'_>,
+ off_out: Option<&mut u64>,
+ len: usize,
+ flags: c::c_uint,
+) -> io::Result<usize> {
+ unsafe {
+ ret_usize(syscall!(
+ __NR_copy_file_range,
+ fd_in,
+ opt_mut(off_in),
+ fd_out,
+ opt_mut(off_out),
+ pass_usize(len),
+ c_uint(flags)
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn memfd_create(name: &CStr, flags: MemfdFlags) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(syscall_readonly!(__NR_memfd_create, name, flags)) }
+}
+
+#[inline]
+pub(crate) fn sendfile(
+ out_fd: BorrowedFd<'_>,
+ in_fd: BorrowedFd<'_>,
+ offset: Option<&mut u64>,
+ count: usize,
+) -> io::Result<usize> {
+ #[cfg(target_pointer_width = "32")]
+ unsafe {
+ ret_usize(syscall!(
+ __NR_sendfile64,
+ out_fd,
+ in_fd,
+ opt_mut(offset),
+ pass_usize(count)
+ ))
+ }
+ #[cfg(target_pointer_width = "64")]
+ unsafe {
+ ret_usize(syscall!(
+ __NR_sendfile,
+ out_fd,
+ in_fd,
+ opt_mut(offset),
+ pass_usize(count)
+ ))
+ }
+}
diff --git a/vendor/rustix/src/imp/linux_raw/fs/types.rs b/vendor/rustix/src/imp/linux_raw/fs/types.rs
new file mode 100644
index 000000000..959a5ee27
--- /dev/null
+++ b/vendor/rustix/src/imp/linux_raw/fs/types.rs
@@ -0,0 +1,613 @@
+use super::super::c;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `FD_*` constants for use with [`fcntl_getfd`] and [`fcntl_setfd`].
+ ///
+ /// [`fcntl_getfd`]: crate::fs::fcntl_getfd
+ /// [`fcntl_setfd`]: crate::fs::fcntl_setfd
+ pub struct FdFlags: c::c_uint {
+ /// `FD_CLOEXEC`
+ const CLOEXEC = linux_raw_sys::general::FD_CLOEXEC;
+ }
+}
+
+bitflags! {
+ /// `*_OK` constants for use with [`accessat`].
+ ///
+ /// [`accessat`]: fn.accessat.html
+ pub struct Access: c::c_uint {
+ /// `R_OK`
+ const READ_OK = linux_raw_sys::general::R_OK;
+
+ /// `W_OK`
+ const WRITE_OK = linux_raw_sys::general::W_OK;
+
+ /// `X_OK`
+ const EXEC_OK = linux_raw_sys::general::X_OK;
+
+ /// `F_OK`
+ const EXISTS = linux_raw_sys::general::F_OK;
+ }
+}
+
+bitflags! {
+ /// `AT_*` constants for use with [`openat`], [`statat`], and other `*at`
+ /// functions.
+ ///
+ /// [`openat`]: crate::fs::openat
+ /// [`statat`]: crate::fs::statat
+ pub struct AtFlags: c::c_uint {
+ /// `AT_REMOVEDIR`
+ const REMOVEDIR = linux_raw_sys::general::AT_REMOVEDIR;
+
+ /// `AT_SYMLINK_FOLLOW`
+ const SYMLINK_FOLLOW = linux_raw_sys::general::AT_SYMLINK_FOLLOW;
+
+ /// `AT_SYMLINK_NOFOLLOW`
+ const SYMLINK_NOFOLLOW = linux_raw_sys::general::AT_SYMLINK_NOFOLLOW;
+
+ /// `AT_EMPTY_PATH`
+ const EMPTY_PATH = linux_raw_sys::general::AT_EMPTY_PATH;
+
+ /// `AT_EACCESS`
+ const EACCESS = linux_raw_sys::general::AT_EACCESS;
+
+ /// `AT_STATX_SYNC_AS_STAT`
+ const STATX_SYNC_AS_STAT = linux_raw_sys::general::AT_STATX_SYNC_AS_STAT;
+
+ /// `AT_STATX_FORCE_SYNC`
+ const STATX_FORCE_SYNC = linux_raw_sys::general::AT_STATX_FORCE_SYNC;
+
+ /// `AT_STATX_DONT_SYNC`
+ const STATX_DONT_SYNC = linux_raw_sys::general::AT_STATX_DONT_SYNC;
+ }
+}
+
+bitflags! {
+ /// `S_I*` constants for use with [`openat`], [`chmodat`], and [`fchmod`].
+ ///
+ /// [`openat`]: crate::fs::openat
+ /// [`chmodat`]: crate::fs::chmodat
+ /// [`fchmod`]: crate::fs::fchmod
+ pub struct Mode: RawMode {
+ /// `S_IRWXU`
+ const RWXU = linux_raw_sys::general::S_IRWXU;
+
+ /// `S_IRUSR`
+ const RUSR = linux_raw_sys::general::S_IRUSR;
+
+ /// `S_IWUSR`
+ const WUSR = linux_raw_sys::general::S_IWUSR;
+
+ /// `S_IXUSR`
+ const XUSR = linux_raw_sys::general::S_IXUSR;
+
+ /// `S_IRWXG`
+ const RWXG = linux_raw_sys::general::S_IRWXG;
+
+ /// `S_IRGRP`
+ const RGRP = linux_raw_sys::general::S_IRGRP;
+
+ /// `S_IWGRP`
+ const WGRP = linux_raw_sys::general::S_IWGRP;
+
+ /// `S_IXGRP`
+ const XGRP = linux_raw_sys::general::S_IXGRP;
+
+ /// `S_IRWXO`
+ const RWXO = linux_raw_sys::general::S_IRWXO;
+
+ /// `S_IROTH`
+ const ROTH = linux_raw_sys::general::S_IROTH;
+
+ /// `S_IWOTH`
+ const WOTH = linux_raw_sys::general::S_IWOTH;
+
+ /// `S_IXOTH`
+ const XOTH = linux_raw_sys::general::S_IXOTH;
+
+ /// `S_ISUID`
+ const SUID = linux_raw_sys::general::S_ISUID;
+
+ /// `S_ISGID`
+ const SGID = linux_raw_sys::general::S_ISGID;
+
+ /// `S_ISVTX`
+ const SVTX = linux_raw_sys::general::S_ISVTX;
+ }
+}
+
+impl Mode {
+ /// Construct a `Mode` from the mode bits of the `st_mode` field of a
+ /// `Stat`.
+ #[inline]
+ pub const fn from_raw_mode(st_mode: RawMode) -> Self {
+ Self::from_bits_truncate(st_mode)
+ }
+
+ /// Construct an `st_mode` value from `Stat`.
+ #[inline]
+ pub const fn as_raw_mode(self) -> RawMode {
+ self.bits()
+ }
+}
+
+bitflags! {
+ /// `O_*` constants for use with [`openat`].
+ ///
+ /// [`openat`]: crate::fs::openat
+ pub struct OFlags: c::c_uint {
+ /// `O_ACCMODE`
+ const ACCMODE = linux_raw_sys::general::O_ACCMODE;
+
+ /// Similar to `ACCMODE`, but just includes the read/write flags, and
+ /// no other flags.
+ ///
+ /// Some implementations include `O_PATH` in `O_ACCMODE`, when
+ /// sometimes we really just want the read/write bits. Caution is
+ /// indicated, as the presence of `O_PATH` may mean that the read/write
+ /// bits don't have their usual meaning.
+ const RWMODE = linux_raw_sys::general::O_RDONLY |
+ linux_raw_sys::general::O_WRONLY |
+ linux_raw_sys::general::O_RDWR;
+
+ /// `O_APPEND`
+ const APPEND = linux_raw_sys::general::O_APPEND;
+
+ /// `O_CREAT`
+ #[doc(alias = "CREAT")]
+ const CREATE = linux_raw_sys::general::O_CREAT;
+
+ /// `O_DIRECTORY`
+ const DIRECTORY = linux_raw_sys::general::O_DIRECTORY;
+
+ /// `O_DSYNC`. Linux 2.6.32 only supports `O_SYNC`.
+ const DSYNC = linux_raw_sys::general::O_SYNC;
+
+ /// `O_EXCL`
+ const EXCL = linux_raw_sys::general::O_EXCL;
+
+ /// `O_FSYNC`. Linux 2.6.32 only supports `O_SYNC`.
+ const FSYNC = linux_raw_sys::general::O_SYNC;
+
+ /// `O_NOFOLLOW`
+ const NOFOLLOW = linux_raw_sys::general::O_NOFOLLOW;
+
+ /// `O_NONBLOCK`
+ const NONBLOCK = linux_raw_sys::general::O_NONBLOCK;
+
+ /// `O_RDONLY`
+ const RDONLY = linux_raw_sys::general::O_RDONLY;
+
+ /// `O_WRONLY`
+ const WRONLY = linux_raw_sys::general::O_WRONLY;
+
+ /// `O_RDWR`
+ const RDWR = linux_raw_sys::general::O_RDWR;
+
+ /// `O_NOCTTY`
+ const NOCTTY = linux_raw_sys::general::O_NOCTTY;
+
+ /// `O_RSYNC`. Linux 2.6.32 only supports `O_SYNC`.
+ const RSYNC = linux_raw_sys::general::O_SYNC;
+
+ /// `O_SYNC`
+ const SYNC = linux_raw_sys::general::O_SYNC;
+
+ /// `O_TRUNC`
+ const TRUNC = linux_raw_sys::general::O_TRUNC;
+
+ /// `O_PATH`
+ const PATH = linux_raw_sys::general::O_PATH;
+
+ /// `O_CLOEXEC`
+ const CLOEXEC = linux_raw_sys::general::O_CLOEXEC;
+
+ /// `O_TMPFILE`
+ const TMPFILE = linux_raw_sys::general::O_TMPFILE;
+
+ /// `O_NOATIME`
+ const NOATIME = linux_raw_sys::general::O_NOATIME;
+ }
+}
+
+bitflags! {
+ /// `RESOLVE_*` constants for use with [`openat2`].
+ ///
+ /// [`openat2`]: crate::fs::openat2
+ #[derive(Default)]
+ pub struct ResolveFlags: u64 {
+ /// `RESOLVE_NO_XDEV`
+ const NO_XDEV = linux_raw_sys::general::RESOLVE_NO_XDEV as u64;
+
+ /// `RESOLVE_NO_MAGICLINKS`
+ const NO_MAGICLINKS = linux_raw_sys::general::RESOLVE_NO_MAGICLINKS as u64;
+
+ /// `RESOLVE_NO_SYMLINKS`
+ const NO_SYMLINKS = linux_raw_sys::general::RESOLVE_NO_SYMLINKS as u64;
+
+ /// `RESOLVE_BENEATH`
+ const BENEATH = linux_raw_sys::general::RESOLVE_BENEATH as u64;
+
+ /// `RESOLVE_IN_ROOT`
+ const IN_ROOT = linux_raw_sys::general::RESOLVE_IN_ROOT as u64;
+
+ /// `RESOLVE_CACHED` (since Linux 5.12)
+ const CACHED = linux_raw_sys::general::RESOLVE_CACHED as u64;
+ }
+}
+
+bitflags! {
+ /// `RENAME_*` constants for use with [`renameat_with`].
+ ///
+ /// [`renameat_with`]: crate::fs::renameat_with
+ pub struct RenameFlags: c::c_uint {
+ /// `RENAME_EXCHANGE`
+ const EXCHANGE = linux_raw_sys::general::RENAME_EXCHANGE;
+
+ /// `RENAME_NOREPLACE`
+ const NOREPLACE = linux_raw_sys::general::RENAME_NOREPLACE;
+
+ /// `RENAME_WHITEOUT`
+ const WHITEOUT = linux_raw_sys::general::RENAME_WHITEOUT;
+ }
+}
+
+/// `S_IF*` constants for use with [`mknodat`] and [`Stat`]'s `st_mode` field.
+///
+/// [`mknodat`]: crate::fs::mknodat
+/// [`Stat`]: crate::fs::Stat
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum FileType {
+ /// `S_IFREG`
+ RegularFile = linux_raw_sys::general::S_IFREG as isize,
+
+ /// `S_IFDIR`
+ Directory = linux_raw_sys::general::S_IFDIR as isize,
+
+ /// `S_IFLNK`
+ Symlink = linux_raw_sys::general::S_IFLNK as isize,
+
+ /// `S_IFIFO`
+ Fifo = linux_raw_sys::general::S_IFIFO as isize,
+
+ /// `S_IFSOCK`
+ Socket = linux_raw_sys::general::S_IFSOCK as isize,
+
+ /// `S_IFCHR`
+ CharacterDevice = linux_raw_sys::general::S_IFCHR as isize,
+
+ /// `S_IFBLK`
+ BlockDevice = linux_raw_sys::general::S_IFBLK as isize,
+
+ /// An unknown filesystem object.
+ Unknown,
+}
+
+impl FileType {
+ /// Construct a `FileType` from the `S_IFMT` bits of the `st_mode` field of
+ /// a `Stat`.
+ #[inline]
+ pub const fn from_raw_mode(st_mode: RawMode) -> Self {
+ match st_mode & linux_raw_sys::general::S_IFMT {
+ linux_raw_sys::general::S_IFREG => Self::RegularFile,
+ linux_raw_sys::general::S_IFDIR => Self::Directory,
+ linux_raw_sys::general::S_IFLNK => Self::Symlink,
+ linux_raw_sys::general::S_IFIFO => Self::Fifo,
+ linux_raw_sys::general::S_IFSOCK => Self::Socket,
+ linux_raw_sys::general::S_IFCHR => Self::CharacterDevice,
+ linux_raw_sys::general::S_IFBLK => Self::BlockDevice,
+ _ => Self::Unknown,
+ }
+ }
+
+ /// Construct an `st_mode` value from `Stat`.
+ #[inline]
+ pub const fn as_raw_mode(self) -> RawMode {
+ match self {
+ Self::RegularFile => linux_raw_sys::general::S_IFREG,
+ Self::Directory => linux_raw_sys::general::S_IFDIR,
+ Self::Symlink => linux_raw_sys::general::S_IFLNK,
+ Self::Fifo => linux_raw_sys::general::S_IFIFO,
+ Self::Socket => linux_raw_sys::general::S_IFSOCK,
+ Self::CharacterDevice => linux_raw_sys::general::S_IFCHR,
+ Self::BlockDevice => linux_raw_sys::general::S_IFBLK,
+ Self::Unknown => linux_raw_sys::general::S_IFMT,
+ }
+ }
+
+ /// Construct a `FileType` from the `d_type` field of a `dirent`.
+ #[inline]
+ pub(crate) const fn from_dirent_d_type(d_type: u8) -> Self {
+ match d_type as u32 {
+ linux_raw_sys::general::DT_REG => Self::RegularFile,
+ linux_raw_sys::general::DT_DIR => Self::Directory,
+ linux_raw_sys::general::DT_LNK => Self::Symlink,
+ linux_raw_sys::general::DT_SOCK => Self::Socket,
+ linux_raw_sys::general::DT_FIFO => Self::Fifo,
+ linux_raw_sys::general::DT_CHR => Self::CharacterDevice,
+ linux_raw_sys::general::DT_BLK => Self::BlockDevice,
+ // linux_raw_sys::general::DT_UNKNOWN |
+ _ => Self::Unknown,
+ }
+ }
+}
+
+/// `POSIX_FADV_*` constants for use with [`fadvise`].
+///
+/// [`fadvise`]: crate::fs::fadvise
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[repr(u32)]
+pub enum Advice {
+ /// `POSIX_FADV_NORMAL`
+ Normal = linux_raw_sys::general::POSIX_FADV_NORMAL,
+
+ /// `POSIX_FADV_SEQUENTIAL`
+ Sequential = linux_raw_sys::general::POSIX_FADV_SEQUENTIAL,
+
+ /// `POSIX_FADV_RANDOM`
+ Random = linux_raw_sys::general::POSIX_FADV_RANDOM,
+
+ /// `POSIX_FADV_NOREUSE`
+ NoReuse = linux_raw_sys::general::POSIX_FADV_NOREUSE,
+
+ /// `POSIX_FADV_WILLNEED`
+ WillNeed = linux_raw_sys::general::POSIX_FADV_WILLNEED,
+
+ /// `POSIX_FADV_DONTNEED`
+ DontNeed = linux_raw_sys::general::POSIX_FADV_DONTNEED,
+}
+
+bitflags! {
+ /// `MFD_*` constants for use with [`memfd_create`].
+ ///
+ /// [`memfd_create`]: crate::fs::memfd_create
+ pub struct MemfdFlags: c::c_uint {
+ /// `MFD_CLOEXEC`
+ const CLOEXEC = linux_raw_sys::general::MFD_CLOEXEC;
+
+ /// `MFD_ALLOW_SEALING`
+ const ALLOW_SEALING = linux_raw_sys::general::MFD_ALLOW_SEALING;
+
+ /// `MFD_HUGETLB` (since Linux 4.14)
+ const HUGETLB = linux_raw_sys::general::MFD_HUGETLB;
+
+ /// `MFD_HUGE_64KB`
+ const HUGE_64KB = linux_raw_sys::general::MFD_HUGE_64KB;
+ /// `MFD_HUGE_512JB`
+ const HUGE_512KB = linux_raw_sys::general::MFD_HUGE_512KB;
+ /// `MFD_HUGE_1MB`
+ const HUGE_1MB = linux_raw_sys::general::MFD_HUGE_1MB;
+ /// `MFD_HUGE_2MB`
+ const HUGE_2MB = linux_raw_sys::general::MFD_HUGE_2MB;
+ /// `MFD_HUGE_8MB`
+ const HUGE_8MB = linux_raw_sys::general::MFD_HUGE_8MB;
+ /// `MFD_HUGE_16MB`
+ const HUGE_16MB = linux_raw_sys::general::MFD_HUGE_16MB;
+ /// `MFD_HUGE_32MB`
+ const HUGE_32MB = linux_raw_sys::general::MFD_HUGE_32MB;
+ /// `MFD_HUGE_256MB`
+ const HUGE_256MB = linux_raw_sys::general::MFD_HUGE_256MB;
+ /// `MFD_HUGE_512MB`
+ const HUGE_512MB = linux_raw_sys::general::MFD_HUGE_512MB;
+ /// `MFD_HUGE_1GB`
+ const HUGE_1GB = linux_raw_sys::general::MFD_HUGE_1GB;
+ /// `MFD_HUGE_2GB`
+ const HUGE_2GB = linux_raw_sys::general::MFD_HUGE_2GB;
+ /// `MFD_HUGE_16GB`
+ const HUGE_16GB = linux_raw_sys::general::MFD_HUGE_16GB;
+ }
+}
+
+bitflags! {
+ /// `F_SEAL_*` constants for use with [`fcntl_add_seals`] and
+ /// [`fcntl_get_seals`].
+ ///
+ /// [`fcntl_add_seals`]: crate::fs::fcntl_add_seals
+ /// [`fcntl_get_seals`]: crate::fs::fcntl_get_seals
+ pub struct SealFlags: u32 {
+ /// `F_SEAL_SEAL`.
+ const SEAL = linux_raw_sys::general::F_SEAL_SEAL;
+ /// `F_SEAL_SHRINK`.
+ const SHRINK = linux_raw_sys::general::F_SEAL_SHRINK;
+ /// `F_SEAL_GROW`.
+ const GROW = linux_raw_sys::general::F_SEAL_GROW;
+ /// `F_SEAL_WRITE`.
+ const WRITE = linux_raw_sys::general::F_SEAL_WRITE;
+ /// `F_SEAL_FUTURE_WRITE` (since Linux 5.1)
+ const FUTURE_WRITE = linux_raw_sys::general::F_SEAL_FUTURE_WRITE;
+ }
+}
+
+bitflags! {
+ /// `STATX_*` constants for use with [`statx`].
+ ///
+ /// [`statx`]: crate::fs::statx
+ pub struct StatxFlags: u32 {
+ /// `STATX_TYPE`
+ const TYPE = linux_raw_sys::general::STATX_TYPE;
+
+ /// `STATX_MODE`
+ const MODE = linux_raw_sys::general::STATX_MODE;
+
+ /// `STATX_NLINK`
+ const NLINK = linux_raw_sys::general::STATX_NLINK;
+
+ /// `STATX_UID`
+ const UID = linux_raw_sys::general::STATX_UID;
+
+ /// `STATX_GID`
+ const GID = linux_raw_sys::general::STATX_GID;
+
+ /// `STATX_ATIME`
+ const ATIME = linux_raw_sys::general::STATX_ATIME;
+
+ /// `STATX_MTIME`
+ const MTIME = linux_raw_sys::general::STATX_MTIME;
+
+ /// `STATX_CTIME`
+ const CTIME = linux_raw_sys::general::STATX_CTIME;
+
+ /// `STATX_INO`
+ const INO = linux_raw_sys::general::STATX_INO;
+
+ /// `STATX_SIZE`
+ const SIZE = linux_raw_sys::general::STATX_SIZE;
+
+ /// `STATX_BLOCKS`
+ const BLOCKS = linux_raw_sys::general::STATX_BLOCKS;
+
+ /// `STATX_BASIC_STATS`
+ const BASIC_STATS = linux_raw_sys::general::STATX_BASIC_STATS;
+
+ /// `STATX_BTIME`
+ const BTIME = linux_raw_sys::general::STATX_BTIME;
+
+ /// `STATX_MNT_ID` (since Linux 5.8)
+ const MNT_ID = linux_raw_sys::general::STATX_MNT_ID;
+
+ /// `STATX_ALL`
+ const ALL = linux_raw_sys::general::STATX_ALL;
+ }
+}
+
+bitflags! {
+ /// `FALLOC_FL_*` constants for use with [`fallocate`].
+ ///
+ /// [`fallocate`]: crate::fs::fallocate
+ pub struct FallocateFlags: u32 {
+ /// `FALLOC_FL_KEEP_SIZE`
+ const KEEP_SIZE = linux_raw_sys::general::FALLOC_FL_KEEP_SIZE;
+ /// `FALLOC_FL_PUNCH_HOLE`
+ const PUNCH_HOLE = linux_raw_sys::general::FALLOC_FL_PUNCH_HOLE;
+ /// `FALLOC_FL_NO_HIDE_STALE`
+ const NO_HIDE_STALE = linux_raw_sys::general::FALLOC_FL_NO_HIDE_STALE;
+ /// `FALLOC_FL_COLLAPSE_RANGE`
+ const COLLAPSE_RANGE = linux_raw_sys::general::FALLOC_FL_COLLAPSE_RANGE;
+ /// `FALLOC_FL_ZERO_RANGE`
+ const ZERO_RANGE = linux_raw_sys::general::FALLOC_FL_ZERO_RANGE;
+ /// `FALLOC_FL_INSERT_RANGE`
+ const INSERT_RANGE = linux_raw_sys::general::FALLOC_FL_INSERT_RANGE;
+ /// `FALLOC_FL_UNSHARE_RANGE`
+ const UNSHARE_RANGE = linux_raw_sys::general::FALLOC_FL_UNSHARE_RANGE;
+ }
+}
+
+/// `LOCK_*` constants for use with [`flock`]
+///
+/// [`flock`]: crate::fs::flock
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[repr(u32)]
+pub enum FlockOperation {
+ /// `LOCK_SH`
+ LockShared = linux_raw_sys::general::LOCK_SH,
+ /// `LOCK_EX`
+ LockExclusive = linux_raw_sys::general::LOCK_EX,
+ /// `LOCK_UN`
+ Unlock = linux_raw_sys::general::LOCK_UN,
+ /// `LOCK_SH | LOCK_NB`
+ NonBlockingLockShared = linux_raw_sys::general::LOCK_SH | linux_raw_sys::general::LOCK_NB,
+ /// `LOCK_EX | LOCK_NB`
+ NonBlockingLockExclusive = linux_raw_sys::general::LOCK_EX | linux_raw_sys::general::LOCK_NB,
+ /// `LOCK_UN | LOCK_NB`
+ NonBlockingUnlock = linux_raw_sys::general::LOCK_UN | linux_raw_sys::general::LOCK_NB,
+}
+
+/// `struct stat` for use with [`statat`] and [`fstat`].
+///
+/// [`statat`]: crate::fs::statat
+/// [`fstat`]: crate::fs::fstat
+// On 32-bit, and mips64, Linux's `struct stat64` has a 32-bit `st_mtime` and
+// friends, so we use our own struct, populated from `statx` where possible, to
+// avoid the y2038 bug.
+#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+#[allow(missing_docs)]
+pub struct Stat {
+ pub st_dev: u64,
+ pub st_mode: u32,
+ pub st_nlink: u32,
+ pub st_uid: u32,
+ pub st_gid: u32,
+ pub st_rdev: u64,
+ pub st_size: i64,
+ pub st_blksize: u32,
+ pub st_blocks: u64,
+ pub st_atime: u64,
+ pub st_atime_nsec: u32,
+ pub st_mtime: u64,
+ pub st_mtime_nsec: u32,
+ pub st_ctime: u64,
+ pub st_ctime_nsec: u32,
+ pub st_ino: u64,
+}
+
+/// `struct stat` for use with [`statat`] and [`fstat`].
+///
+/// [`statat`]: crate::fs::statat
+/// [`fstat`]: crate::fs::fstat
+#[cfg(all(target_pointer_width = "64", not(target_arch = "mips64")))]
+pub type Stat = linux_raw_sys::general::stat;
+
+/// `struct statfs` for use with [`fstatfs`].
+///
+/// [`fstatfs`]: crate::fs::fstatfs
+#[cfg(target_pointer_width = "32")]
+#[allow(clippy::module_name_repetitions)]
+pub type StatFs = linux_raw_sys::general::statfs64;
+
+/// `struct statfs` for use with [`fstatfs`].
+///
+/// [`fstatfs`]: crate::fs::fstatfs
+#[cfg(target_pointer_width = "64")]
+#[allow(clippy::module_name_repetitions)]
+pub type StatFs = linux_raw_sys::general::statfs64;
+
+/// `struct statx` for use with [`statx`].
+///
+/// [`statx`]: crate::fs::statx
+pub type Statx = linux_raw_sys::general::statx;
+
+/// `struct statx_timestamp` for use with [`Statx`].
+pub type StatxTimestamp = linux_raw_sys::general::statx_timestamp;
+
+/// `mode_t`
+#[cfg(not(any(
+ target_arch = "x86",
+ target_arch = "sparc",
+ target_arch = "avr",
+ target_arch = "arm",
+)))]
+pub type RawMode = linux_raw_sys::general::__kernel_mode_t;
+
+/// `mode_t
+#[cfg(any(
+ target_arch = "x86",
+ target_arch = "sparc",
+ target_arch = "avr",
+ target_arch = "arm",
+))]
+// Don't use `__kernel_mode_t` since it's `u16` which differs from `st_size`.
+pub type RawMode = c::c_uint;
+
+/// `dev_t`
+// Within the kernel the dev_t is 32-bit, but userspace uses a 64-bit field.
+pub type Dev = u64;
+
+/// `__fsword_t`
+#[cfg(not(target_arch = "mips64"))]
+pub type FsWord = linux_raw_sys::general::__fsword_t;
+
+/// `__fsword_t`
+#[cfg(target_arch = "mips64")]
+pub type FsWord = i64;
+
+pub use linux_raw_sys::general::{UTIME_NOW, UTIME_OMIT};
+
+/// `PROC_SUPER_MAGIC`—The magic number for the procfs filesystem.
+pub const PROC_SUPER_MAGIC: FsWord = linux_raw_sys::general::PROC_SUPER_MAGIC as FsWord;
+
+/// `NFS_SUPER_MAGIC`—The magic number for the NFS filesystem.
+pub const NFS_SUPER_MAGIC: FsWord = linux_raw_sys::general::NFS_SUPER_MAGIC as FsWord;