Vendor things

This commit is contained in:
John Doty 2024-03-08 11:03:01 -08:00
parent 5deceec006
commit 977e3c17e5
19434 changed files with 10682014 additions and 0 deletions

301
third-party/vendor/rustix/src/fs/abs.rs vendored Normal file
View file

@ -0,0 +1,301 @@
//! POSIX-style filesystem functions which operate on bare paths.
use crate::fd::OwnedFd;
#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
use crate::fs::Access;
#[cfg(not(any(
solarish,
target_os = "espidf",
target_os = "haiku",
target_os = "netbsd",
target_os = "nto",
target_os = "redox",
target_os = "vita",
target_os = "wasi",
)))]
use crate::fs::StatFs;
#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
use crate::fs::StatVfs;
use crate::fs::{Mode, OFlags, Stat};
#[cfg(not(target_os = "wasi"))]
use crate::ugid::{Gid, Uid};
use crate::{backend, io, path};
#[cfg(feature = "alloc")]
use {
crate::ffi::{CStr, CString},
crate::path::SMALL_PATH_BUFFER_SIZE,
alloc::vec::Vec,
};
/// `open(path, oflags, mode)`—Opens a file.
///
/// POSIX guarantees that `open` will use the lowest unused file descriptor,
/// however it is not safe in general to rely on this, as file descriptors may
/// be unexpectedly allocated on other threads or in libraries.
///
/// The `Mode` argument is only significant when creating a file.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
/// [Linux]: https://man7.org/linux/man-pages/man2/open.2.html
#[inline]
pub fn open<P: path::Arg>(path: P, flags: OFlags, mode: Mode) -> io::Result<OwnedFd> {
path.into_with_c_str(|path| backend::fs::syscalls::open(path, flags, mode))
}
/// `chmod(path, mode)`—Sets file or directory permissions.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html
/// [Linux]: https://man7.org/linux/man-pages/man2/chmod.2.html
#[cfg(not(target_os = "wasi"))]
#[inline]
pub fn chmod<P: path::Arg>(path: P, mode: Mode) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::chmod(path, mode))
}
/// `stat(path)`—Queries metadata for a file or directory.
///
/// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to
/// interpret the `st_mode` field.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/stat.2.html
/// [`Mode::from_raw_mode`]: crate::fs::Mode::from_raw_mode
/// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode
#[inline]
pub fn stat<P: path::Arg>(path: P) -> io::Result<Stat> {
path.into_with_c_str(backend::fs::syscalls::stat)
}
/// `lstat(path)`—Queries metadata for a file or directory, without following
/// symlinks.
///
/// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to
/// interpret the `st_mode` field.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/lstat.2.html
/// [`Mode::from_raw_mode`]: crate::fs::Mode::from_raw_mode
/// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode
#[inline]
pub fn lstat<P: path::Arg>(path: P) -> io::Result<Stat> {
path.into_with_c_str(backend::fs::syscalls::lstat)
}
/// `readlink(path)`—Reads the contents of a symlink.
///
/// If `reuse` is non-empty, reuse its buffer to store the result if possible.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html
/// [Linux]: https://man7.org/linux/man-pages/man2/readlink.2.html
#[cfg(feature = "alloc")]
#[inline]
pub fn readlink<P: path::Arg, B: Into<Vec<u8>>>(path: P, reuse: B) -> io::Result<CString> {
path.into_with_c_str(|path| _readlink(path, reuse.into()))
}
#[cfg(feature = "alloc")]
fn _readlink(path: &CStr, mut buffer: Vec<u8>) -> io::Result<CString> {
// This code would benefit from having a better way to read into
// uninitialized memory, but that requires `unsafe`.
buffer.clear();
buffer.reserve(SMALL_PATH_BUFFER_SIZE);
buffer.resize(buffer.capacity(), 0_u8);
loop {
let nread = backend::fs::syscalls::readlink(path, &mut buffer)?;
let nread = nread as usize;
assert!(nread <= buffer.len());
if nread < buffer.len() {
buffer.resize(nread, 0_u8);
return Ok(CString::new(buffer).unwrap());
}
// Use `Vec` reallocation strategy to grow capacity exponentially.
buffer.reserve(1);
buffer.resize(buffer.capacity(), 0_u8);
}
}
/// `rename(old_path, new_path)`—Renames a file or directory.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html
/// [Linux]: https://man7.org/linux/man-pages/man2/rename.2.html
#[inline]
pub fn rename<P: path::Arg, Q: path::Arg>(old_path: P, new_path: Q) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| backend::fs::syscalls::rename(old_path, new_path))
})
}
/// `unlink(path)`—Unlinks a file.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html
/// [Linux]: https://man7.org/linux/man-pages/man2/unlink.2.html
#[inline]
pub fn unlink<P: path::Arg>(path: P) -> io::Result<()> {
path.into_with_c_str(backend::fs::syscalls::unlink)
}
/// `rmdir(path)`—Removes a directory.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html
/// [Linux]: https://man7.org/linux/man-pages/man2/rmdir.2.html
#[inline]
pub fn rmdir<P: path::Arg>(path: P) -> io::Result<()> {
path.into_with_c_str(backend::fs::syscalls::rmdir)
}
/// `link(old_path, new_path)`—Creates a hard link.
///
/// POSIX leaves it implementation-defined whether `link` follows a symlink in
/// `old_path`, or creates a new link to the symbolic link itself. On platforms
/// which have it, [`linkat`] avoids this problem since it has an [`AtFlags`]
/// parameter and the [`AtFlags::SYMLINK_FOLLOW`] flag determines whether
/// symlinks should be followed.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html
/// [Linux]: https://man7.org/linux/man-pages/man2/link.2.html
/// [`linkat`]: crate::fs::linkat
/// [`AtFlags`]: crate::fs::AtFlags
/// [`AtFlags::SYMLINK_FOLLOW`]: crate::fs::AtFlags::SYMLINK_FOLLOW
#[inline]
pub fn link<P: path::Arg, Q: path::Arg>(old_path: P, new_path: Q) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| backend::fs::syscalls::link(old_path, new_path))
})
}
/// `symlink(old_path, new_path)`—Creates a symlink.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html
/// [Linux]: https://man7.org/linux/man-pages/man2/symlink.2.html
#[inline]
pub fn symlink<P: path::Arg, Q: path::Arg>(old_path: P, new_path: Q) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| backend::fs::syscalls::symlink(old_path, new_path))
})
}
/// `mkdir(path, mode)`—Creates a directory.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html
/// [Linux]: https://man7.org/linux/man-pages/man2/mkdir.2.html
#[inline]
pub fn mkdir<P: path::Arg>(path: P, mode: Mode) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::mkdir(path, mode))
}
/// `access(path, access)`—Tests permissions for a file or directory.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html
/// [Linux]: https://man7.org/linux/man-pages/man2/access.2.html
#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
#[inline]
pub fn access<P: path::Arg>(path: P, access: Access) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::access(path, access))
}
/// `statfs`—Queries filesystem metadata.
///
/// Compared to [`statvfs`], this function often provides more information,
/// though it's less portable.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/statfs.2.html
#[cfg(not(any(
solarish,
target_os = "espidf",
target_os = "haiku",
target_os = "netbsd",
target_os = "nto",
target_os = "redox",
target_os = "vita",
target_os = "wasi",
)))]
#[inline]
pub fn statfs<P: path::Arg>(path: P) -> io::Result<StatFs> {
path.into_with_c_str(backend::fs::syscalls::statfs)
}
/// `statvfs`—Queries filesystem metadata, POSIX version.
///
/// Compared to [`statfs`], this function often provides less information, but
/// it is more portable. But even so, filesystems are very diverse and not all
/// the fields are meaningful for every filesystem. And `f_fsid` doesn't seem
/// to have a clear meaning anywhere.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/statvfs.html
/// [Linux]: https://man7.org/linux/man-pages/man2/statvfs.2.html
#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
#[inline]
pub fn statvfs<P: path::Arg>(path: P) -> io::Result<StatVfs> {
path.into_with_c_str(backend::fs::syscalls::statvfs)
}
/// `chown(path, owner, group)`—Sets open file or directory ownership.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html
/// [Linux]: https://man7.org/linux/man-pages/man2/chown.2.html
#[cfg(not(target_os = "wasi"))]
#[inline]
pub fn chown<P: path::Arg>(path: P, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::chown(path, owner, group))
}

472
third-party/vendor/rustix/src/fs/at.rs vendored Normal file
View file

@ -0,0 +1,472 @@
//! POSIX-style `*at` functions.
//!
//! The `dirfd` argument to these functions may be a file descriptor for a
//! directory, or the special value [`CWD`].
//!
//! [`cwd`]: crate::fs::CWD
use crate::fd::OwnedFd;
use crate::ffi::CStr;
#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
use crate::fs::Access;
#[cfg(not(target_os = "espidf"))]
use crate::fs::AtFlags;
#[cfg(apple)]
use crate::fs::CloneFlags;
#[cfg(linux_kernel)]
use crate::fs::RenameFlags;
#[cfg(not(target_os = "espidf"))]
use crate::fs::Stat;
#[cfg(not(any(apple, target_os = "espidf", target_os = "vita", target_os = "wasi")))]
use crate::fs::{Dev, FileType};
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
use crate::fs::{Gid, Uid};
use crate::fs::{Mode, OFlags};
use crate::{backend, io, path};
use backend::fd::{AsFd, BorrowedFd};
use core::mem::MaybeUninit;
use core::slice;
#[cfg(feature = "alloc")]
use {crate::ffi::CString, crate::path::SMALL_PATH_BUFFER_SIZE, alloc::vec::Vec};
#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
use {crate::fs::Timestamps, crate::timespec::Nsecs};
/// `UTIME_NOW` for use with [`utimensat`].
///
/// [`utimensat`]: crate::fs::utimensat
#[cfg(not(any(target_os = "espidf", target_os = "redox", target_os = "vita")))]
pub const UTIME_NOW: Nsecs = backend::c::UTIME_NOW as Nsecs;
/// `UTIME_OMIT` for use with [`utimensat`].
///
/// [`utimensat`]: crate::fs::utimensat
#[cfg(not(any(target_os = "espidf", target_os = "redox", target_os = "vita")))]
pub const UTIME_OMIT: Nsecs = backend::c::UTIME_OMIT as Nsecs;
/// `openat(dirfd, path, oflags, mode)`—Opens a file.
///
/// POSIX guarantees that `openat` will use the lowest unused file descriptor,
/// however it is not safe in general to rely on this, as file descriptors may
/// be unexpectedly allocated on other threads or in libraries.
///
/// The `Mode` argument is only significant when creating a file.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/openat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/openat.2.html
#[inline]
pub fn openat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
oflags: OFlags,
create_mode: Mode,
) -> io::Result<OwnedFd> {
path.into_with_c_str(|path| {
backend::fs::syscalls::openat(dirfd.as_fd(), path, oflags, create_mode)
})
}
/// `readlinkat(fd, path)`—Reads the contents of a symlink.
///
/// If `reuse` already has available capacity, reuse it if possible.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlinkat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/readlinkat.2.html
#[cfg(feature = "alloc")]
#[inline]
pub fn readlinkat<P: path::Arg, Fd: AsFd, B: Into<Vec<u8>>>(
dirfd: Fd,
path: P,
reuse: B,
) -> io::Result<CString> {
path.into_with_c_str(|path| _readlinkat(dirfd.as_fd(), path, reuse.into()))
}
#[cfg(feature = "alloc")]
#[allow(unsafe_code)]
fn _readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, mut buffer: Vec<u8>) -> io::Result<CString> {
buffer.clear();
buffer.reserve(SMALL_PATH_BUFFER_SIZE);
loop {
let nread =
backend::fs::syscalls::readlinkat(dirfd.as_fd(), path, buffer.spare_capacity_mut())?;
debug_assert!(nread <= buffer.capacity());
if nread < buffer.capacity() {
// SAFETY: From the [documentation]: “On success, these calls
// return the number of bytes placed in buf.”
//
// [documentation]: https://man7.org/linux/man-pages/man2/readlinkat.2.html
unsafe {
buffer.set_len(nread);
}
// SAFETY:
// - “readlink places the contents of the symbolic link pathname in
// the buffer buf”
// - [POSIX definition 3.271: Pathname]: “A string that is used to
// identify a file.”
// - [POSIX definition 3.375: String]: “A contiguous sequence of
// bytes terminated by and including the first null byte.”
// - “readlink does not append a terminating null byte to buf.”
//
// Thus, there will be no NUL bytes in the string.
//
// [POSIX definition 3.271: Pathname]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_271
// [POSIX definition 3.375: String]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_375
unsafe {
return Ok(CString::from_vec_unchecked(buffer));
}
}
// Use `Vec` reallocation strategy to grow capacity exponentially.
buffer.reserve(buffer.capacity() + 1);
}
}
/// `readlinkat(fd, path)`—Reads the contents of a symlink, without
/// allocating.
///
/// This is the "raw" version which avoids allocating, but which is
/// significantly trickier to use; most users should use plain [`readlinkat`].
///
/// This version writes bytes into the buffer and returns two slices, one
/// containing the written bytes, and one containing the remaining
/// uninitialized space. If the number of written bytes is equal to the length
/// of the buffer, it means the buffer wasn't big enough to hold the full
/// string, and callers should try again with a bigger buffer.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlinkat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/readlinkat.2.html
#[inline]
pub fn readlinkat_raw<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
buf: &mut [MaybeUninit<u8>],
) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>])> {
path.into_with_c_str(|path| _readlinkat_raw(dirfd.as_fd(), path, buf))
}
#[allow(unsafe_code)]
fn _readlinkat_raw<'a>(
dirfd: BorrowedFd<'_>,
path: &CStr,
buf: &'a mut [MaybeUninit<u8>],
) -> io::Result<(&'a mut [u8], &'a mut [MaybeUninit<u8>])> {
let n = backend::fs::syscalls::readlinkat(dirfd.as_fd(), path, buf)?;
unsafe {
Ok((
slice::from_raw_parts_mut(buf.as_mut_ptr().cast::<u8>(), n),
&mut buf[n..],
))
}
}
/// `mkdirat(fd, path, mode)`—Creates a directory.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdirat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/mkdirat.2.html
#[inline]
pub fn mkdirat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, mode: Mode) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::mkdirat(dirfd.as_fd(), path, mode))
}
/// `linkat(old_dirfd, old_path, new_dirfd, new_path, flags)`—Creates a hard
/// link.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/linkat.2.html
#[cfg(not(target_os = "espidf"))]
#[inline]
pub fn linkat<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>(
old_dirfd: PFd,
old_path: P,
new_dirfd: QFd,
new_path: Q,
flags: AtFlags,
) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| {
backend::fs::syscalls::linkat(
old_dirfd.as_fd(),
old_path,
new_dirfd.as_fd(),
new_path,
flags,
)
})
})
}
/// `unlinkat(fd, path, flags)`—Unlinks a file or remove a directory.
///
/// With the [`REMOVEDIR`] flag, this removes a directory. This is in place of
/// a `rmdirat` function.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [`REMOVEDIR`]: AtFlags::REMOVEDIR
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/unlinkat.2.html
#[cfg(not(target_os = "espidf"))]
#[inline]
pub fn unlinkat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, flags: AtFlags) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::unlinkat(dirfd.as_fd(), path, flags))
}
/// `renameat(old_dirfd, old_path, new_dirfd, new_path)`—Renames a file or
/// directory.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/renameat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/renameat.2.html
#[inline]
pub fn renameat<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>(
old_dirfd: PFd,
old_path: P,
new_dirfd: QFd,
new_path: Q,
) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| {
backend::fs::syscalls::renameat(
old_dirfd.as_fd(),
old_path,
new_dirfd.as_fd(),
new_path,
)
})
})
}
/// `renameat2(old_dirfd, old_path, new_dirfd, new_path, flags)`—Renames a
/// file or directory.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/renameat2.2.html
#[cfg(linux_kernel)]
#[inline]
#[doc(alias = "renameat2")]
pub fn renameat_with<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>(
old_dirfd: PFd,
old_path: P,
new_dirfd: QFd,
new_path: Q,
flags: RenameFlags,
) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| {
backend::fs::syscalls::renameat2(
old_dirfd.as_fd(),
old_path,
new_dirfd.as_fd(),
new_path,
flags,
)
})
})
}
/// `symlinkat(old_path, new_dirfd, new_path)`—Creates a symlink.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/symlinkat.2.html
#[inline]
pub fn symlinkat<P: path::Arg, Q: path::Arg, Fd: AsFd>(
old_path: P,
new_dirfd: Fd,
new_path: Q,
) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| {
backend::fs::syscalls::symlinkat(old_path, new_dirfd.as_fd(), new_path)
})
})
}
/// `fstatat(dirfd, path, flags)`—Queries metadata for a file or directory.
///
/// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to
/// interpret the `st_mode` field.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fstatat.2.html
/// [`Mode::from_raw_mode`]: crate::fs::Mode::from_raw_mode
/// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode
#[cfg(not(target_os = "espidf"))]
#[inline]
#[doc(alias = "fstatat")]
pub fn statat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, flags: AtFlags) -> io::Result<Stat> {
path.into_with_c_str(|path| backend::fs::syscalls::statat(dirfd.as_fd(), path, flags))
}
/// `faccessat(dirfd, path, access, flags)`—Tests permissions for a file or
/// directory.
///
/// On Linux before 5.8, this function uses the `faccessat` system call which
/// doesn't support any flags. This function emulates support for the
/// [`AtFlags::EACCESS`] flag by checking whether the uid and gid of the
/// process match the effective uid and gid, in which case the `EACCESS` flag
/// can be ignored. In Linux 5.8 and beyond `faccessat2` is used, which
/// supports flags.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/faccessat.2.html
#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
#[inline]
#[doc(alias = "faccessat")]
pub fn accessat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
access: Access,
flags: AtFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::accessat(dirfd.as_fd(), path, access, flags))
}
/// `utimensat(dirfd, path, times, flags)`—Sets file or directory timestamps.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimensat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/utimensat.2.html
#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
#[inline]
pub fn utimensat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
times: &Timestamps,
flags: AtFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::utimensat(dirfd.as_fd(), path, times, flags))
}
/// `fchmodat(dirfd, path, mode, flags)`—Sets file or directory permissions.
///
/// Platform support for flags varies widely, for example on Linux
/// [`AtFlags::SYMLINK_NOFOLLOW`] is not implemented and therefore
/// [`io::Errno::OPNOTSUPP`] will be returned.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fchmodat.2.html
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
#[inline]
#[doc(alias = "fchmodat")]
pub fn chmodat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
mode: Mode,
flags: AtFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::chmodat(dirfd.as_fd(), path, mode, flags))
}
/// `fclonefileat(src, dst_dir, dst, flags)`—Efficiently copies between files.
///
/// # References
/// - [Apple]
///
/// [Apple]: https://opensource.apple.com/source/xnu/xnu-3789.21.4/bsd/man/man2/clonefile.2.auto.html
#[cfg(apple)]
#[inline]
pub fn fclonefileat<Fd: AsFd, DstFd: AsFd, P: path::Arg>(
src: Fd,
dst_dir: DstFd,
dst: P,
flags: CloneFlags,
) -> io::Result<()> {
dst.into_with_c_str(|dst| {
backend::fs::syscalls::fclonefileat(src.as_fd(), dst_dir.as_fd(), dst, flags)
})
}
/// `mknodat(dirfd, path, mode, dev)`—Creates special or normal files.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknodat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/mknodat.2.html
#[cfg(not(any(apple, target_os = "espidf", target_os = "vita", target_os = "wasi")))]
#[inline]
pub fn mknodat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
file_type: FileType,
mode: Mode,
dev: Dev,
) -> io::Result<()> {
path.into_with_c_str(|path| {
backend::fs::syscalls::mknodat(dirfd.as_fd(), path, file_type, mode, dev)
})
}
/// `fchownat(dirfd, path, owner, group, flags)`—Sets file or directory
/// ownership.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fchownat.2.html
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
#[inline]
#[doc(alias = "fchownat")]
pub fn chownat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
owner: Option<Uid>,
group: Option<Gid>,
flags: AtFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| {
backend::fs::syscalls::chownat(dirfd.as_fd(), path, owner, group, flags)
})
}

View file

@ -0,0 +1,7 @@
//! Filesystem API constants, translated into `bitflags` constants.
use crate::backend;
pub use crate::io::FdFlags;
pub use crate::timespec::{Nsecs, Secs, Timespec};
pub use backend::fs::types::*;

View file

@ -0,0 +1,20 @@
use crate::{backend, io};
use backend::fd::AsFd;
/// `copy_file_range(fd_in, off_in, fd_out, off_out, len, 0)`—Copies data
/// from one file to another.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/copy_file_range.2.html
#[inline]
pub fn copy_file_range<InFd: AsFd, OutFd: AsFd>(
fd_in: InFd,
off_in: Option<&mut u64>,
fd_out: OutFd,
off_out: Option<&mut u64>,
len: usize,
) -> io::Result<usize> {
backend::fs::syscalls::copy_file_range(fd_in.as_fd(), off_in, fd_out.as_fd(), off_out, len)
}

39
third-party/vendor/rustix/src/fs/cwd.rs vendored Normal file
View file

@ -0,0 +1,39 @@
//! The `cwd` function, representing the current working directory.
//!
//! # Safety
//!
//! This file uses `AT_FDCWD`, which is a raw file descriptor, but which is
//! always valid.
#![allow(unsafe_code)]
use crate::backend;
use backend::c;
use backend::fd::{BorrowedFd, RawFd};
/// `AT_FDCWD`—A handle representing the current working directory.
///
/// This is a file descriptor which refers to the process current directory
/// which can be used as the directory argument in `*at` functions such as
/// [`openat`].
///
/// # References
/// - [POSIX]
///
/// [`openat`]: crate::fs::openat
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/fcntl.h.html
// SAFETY: `AT_FDCWD` is a reserved value that is never dynamically
// allocated, so it'll remain valid for the duration of `'static`.
#[doc(alias = "AT_FDCWD")]
pub const CWD: BorrowedFd<'static> =
unsafe { BorrowedFd::<'static>::borrow_raw(c::AT_FDCWD as RawFd) };
/// Return the value of [`CWD`].
#[deprecated(note = "Use `CWD` in place of `cwd()`.")]
pub const fn cwd() -> BorrowedFd<'static> {
let at_fdcwd = c::AT_FDCWD as RawFd;
// SAFETY: `AT_FDCWD` is a reserved value that is never dynamically
// allocated, so it'll remain valid for the duration of `'static`.
unsafe { BorrowedFd::<'static>::borrow_raw(at_fdcwd) }
}

View file

@ -0,0 +1,5 @@
//! `Dir` and `DirEntry`.
use crate::backend;
pub use backend::fs::dir::{Dir, DirEntry};

View file

@ -0,0 +1,18 @@
use crate::{backend, io};
use backend::fd::AsFd;
use backend::fs::types::Advice;
/// `posix_fadvise(fd, offset, len, advice)`—Declares an expected access
/// pattern for a file.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html
/// [Linux]: https://man7.org/linux/man-pages/man2/posix_fadvise.2.html
#[inline]
#[doc(alias = "posix_fadvise")]
pub fn fadvise<Fd: AsFd>(fd: Fd, offset: u64, len: u64, advice: Advice) -> io::Result<()> {
backend::fs::syscalls::fadvise(fd.as_fd(), offset, len, advice)
}

View file

@ -0,0 +1,112 @@
//! The Unix `fcntl` function is effectively lots of different functions hidden
//! behind a single dynamic dispatch interface. In order to provide a type-safe
//! API, rustix makes them all separate functions so that they can have
//! dedicated static type signatures.
#[cfg(not(any(
target_os = "emscripten",
target_os = "espidf",
target_os = "fuchsia",
target_os = "redox",
target_os = "vita",
target_os = "wasi"
)))]
use crate::fs::FlockOperation;
use crate::{backend, io};
use backend::fd::AsFd;
use backend::fs::types::OFlags;
// These `fcntl` functions live in the `io` module because they're not specific
// to files, directories, or memfd objects. We re-export them here in the `fs`
// module because the other the `fcntl` functions are here.
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
pub use crate::io::fcntl_dupfd_cloexec;
pub use crate::io::{fcntl_getfd, fcntl_setfd};
/// `fcntl(fd, F_GETFL)`—Returns a file descriptor's access mode and status.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
#[inline]
#[doc(alias = "F_GETFL")]
pub fn fcntl_getfl<Fd: AsFd>(fd: Fd) -> io::Result<OFlags> {
backend::fs::syscalls::fcntl_getfl(fd.as_fd())
}
/// `fcntl(fd, F_SETFL, flags)`—Sets a file descriptor's status.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
#[inline]
#[doc(alias = "F_SETFL")]
pub fn fcntl_setfl<Fd: AsFd>(fd: Fd, flags: OFlags) -> io::Result<()> {
backend::fs::syscalls::fcntl_setfl(fd.as_fd(), flags)
}
/// `fcntl(fd, F_GET_SEALS)`
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))]
#[inline]
#[doc(alias = "F_GET_SEALS")]
pub fn fcntl_get_seals<Fd: AsFd>(fd: Fd) -> io::Result<SealFlags> {
backend::fs::syscalls::fcntl_get_seals(fd.as_fd())
}
#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))]
use backend::fs::types::SealFlags;
/// `fcntl(fd, F_ADD_SEALS)`
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))]
#[inline]
#[doc(alias = "F_ADD_SEALS")]
pub fn fcntl_add_seals<Fd: AsFd>(fd: Fd, seals: SealFlags) -> io::Result<()> {
backend::fs::syscalls::fcntl_add_seals(fd.as_fd(), seals)
}
/// `fcntl(fd, F_SETLK)`—Acquire or release an `fcntl`-style lock.
///
/// This function doesn't currently have an offset or len; it currently always
/// sets the `l_len` field to 0, which is a special case that means the entire
/// file should be locked.
///
/// Unlike `flock`-style locks, `fcntl`-style locks are process-associated,
/// meaning that they don't guard against being acquired by two threads in the
/// same process.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
#[cfg(not(any(
target_os = "emscripten",
target_os = "espidf",
target_os = "fuchsia",
target_os = "redox",
target_os = "vita",
target_os = "wasi"
)))]
#[inline]
#[doc(alias = "F_SETLK")]
#[doc(alias = "F_SETLKW")]
pub fn fcntl_lock<Fd: AsFd>(fd: Fd, operation: FlockOperation) -> io::Result<()> {
backend::fs::syscalls::fcntl_lock(fd.as_fd(), operation)
}

View file

@ -0,0 +1,66 @@
use crate::{backend, io};
use backend::fd::AsFd;
/// `fcntl(fd, F_RDADVISE, radvisory { offset, len })`
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html
#[doc(alias = "F_RDADVISE")]
#[inline]
pub fn fcntl_rdadvise<Fd: AsFd>(fd: Fd, offset: u64, len: u64) -> io::Result<()> {
backend::fs::syscalls::fcntl_rdadvise(fd.as_fd(), offset, len)
}
/// `fcntl(fd, F_FULLFSYNC)`
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html
#[doc(alias = "F_FULLSYNC")]
#[inline]
pub fn fcntl_fullfsync<Fd: AsFd>(fd: Fd) -> io::Result<()> {
backend::fs::syscalls::fcntl_fullfsync(fd.as_fd())
}
/// `fcntl(fd, F_NOCACHE, value)`—Turn data caching off or on for a file
/// descriptor.
///
/// See [this mailing list post] for additional information about the meanings
/// of `F_NOCACHE` and `F_GLOBAL_NOCACHE`.
///
/// [this mailing list post]: https://lists.apple.com/archives/filesystem-dev/2007/Sep/msg00010.html
///
/// See also [`fcntl_global_nocache`].
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html
#[doc(alias = "F_NOCACHE")]
#[inline]
pub fn fcntl_nocache<Fd: AsFd>(fd: Fd, value: bool) -> io::Result<()> {
backend::fs::syscalls::fcntl_nocache(fd.as_fd(), value)
}
/// `fcntl(fd, F_GLOBAL_NOCACHE, value)`—Turn data caching off or on for all
/// file descriptors.
///
/// See [this mailing list post] for additional information about the meanings
/// of `F_NOCACHE` and `F_GLOBAL_NOCACHE`.
///
/// [this mailing list post]: https://lists.apple.com/archives/filesystem-dev/2007/Sep/msg00010.html
///
/// See also [`fcntl_nocache`].
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html
#[doc(alias = "F_GLOBAL_NOCACHE")]
#[inline]
pub fn fcntl_global_nocache<Fd: AsFd>(fd: Fd, value: bool) -> io::Result<()> {
backend::fs::syscalls::fcntl_global_nocache(fd.as_fd(), value)
}

View file

@ -0,0 +1,88 @@
use crate::fs::CopyfileFlags;
use crate::{backend, io};
use backend::fd::AsFd;
use backend::fs::types::copyfile_state_t;
/// `fcopyfile(from, to, state, flags)`
///
/// # Safety
///
/// The `state` operand must be allocated with `copyfile_state_alloc` and not
/// yet freed with `copyfile_state_free`.
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html
#[inline]
pub unsafe fn fcopyfile<FromFd: AsFd, ToFd: AsFd>(
from: FromFd,
to: ToFd,
state: copyfile_state_t,
flags: CopyfileFlags,
) -> io::Result<()> {
backend::fs::syscalls::fcopyfile(from.as_fd(), to.as_fd(), state, flags)
}
/// `copyfile_state_alloc()`
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html
#[inline]
pub fn copyfile_state_alloc() -> io::Result<copyfile_state_t> {
backend::fs::syscalls::copyfile_state_alloc()
}
/// `copyfile_state_free(state)`
///
/// # Safety
///
/// The `state` operand must be allocated with `copyfile_state_alloc` and not
/// yet freed with `copyfile_state_free`.
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html
#[inline]
pub unsafe fn copyfile_state_free(state: copyfile_state_t) -> io::Result<()> {
backend::fs::syscalls::copyfile_state_free(state)
}
/// `copyfile_state_get(state, COPYFILE_STATE_COPIED)`
///
/// # Safety
///
/// The `state` operand must be allocated with `copyfile_state_alloc` and not
/// yet freed with `copyfile_state_free`.
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html
#[inline]
pub unsafe fn copyfile_state_get_copied(state: copyfile_state_t) -> io::Result<u64> {
backend::fs::syscalls::copyfile_state_get_copied(state)
}
/// `copyfile_state_get(state, flags, dst)`
///
/// # Safety
///
/// The `state` operand must be allocated with `copyfile_state_alloc` and not
/// yet freed with `copyfile_state_free`.
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/fcopyfile.3.html
#[inline]
pub unsafe fn copyfile_state_get(
state: copyfile_state_t,
flag: u32,
dst: *mut core::ffi::c_void,
) -> io::Result<()> {
backend::fs::syscalls::copyfile_state_get(state, flag, dst)
}

357
third-party/vendor/rustix/src/fs/fd.rs vendored Normal file
View file

@ -0,0 +1,357 @@
//! Functions which operate on file descriptors.
#[cfg(not(target_os = "wasi"))]
use crate::fs::Mode;
#[cfg(not(target_os = "wasi"))]
use crate::fs::{Gid, Uid};
use crate::fs::{OFlags, SeekFrom, Timespec};
use crate::{backend, io};
use backend::fd::{AsFd, BorrowedFd};
#[cfg(not(any(
netbsdlike,
solarish,
target_os = "aix",
target_os = "dragonfly",
target_os = "espidf",
target_os = "nto",
target_os = "redox",
target_os = "vita",
)))]
use backend::fs::types::FallocateFlags;
#[cfg(not(any(
target_os = "espidf",
target_os = "solaris",
target_os = "vita",
target_os = "wasi"
)))]
use backend::fs::types::FlockOperation;
#[cfg(linux_kernel)]
use backend::fs::types::FsWord;
use backend::fs::types::Stat;
#[cfg(not(any(
solarish,
target_os = "espidf",
target_os = "haiku",
target_os = "netbsd",
target_os = "nto",
target_os = "redox",
target_os = "vita",
target_os = "wasi",
)))]
use backend::fs::types::StatFs;
#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
use backend::fs::types::StatVfs;
/// Timestamps used by [`utimensat`] and [`futimens`].
///
/// [`utimensat`]: crate::fs::utimensat
/// [`futimens`]: crate::fs::futimens
// This is `repr(C)` and specifically laid out to match the representation used
// by `utimensat` and `futimens`, which expect 2-element arrays of timestamps.
#[repr(C)]
#[derive(Clone, Debug)]
pub struct Timestamps {
/// The timestamp of the last access to a filesystem object.
pub last_access: Timespec,
/// The timestamp of the last modification of a filesystem object.
pub last_modification: Timespec,
}
/// The filesystem magic number for procfs.
///
/// See [the `fstatfs` manual page] for more information.
///
/// [the `fstatfs` manual page]: https://man7.org/linux/man-pages/man2/fstatfs.2.html#DESCRIPTION
#[cfg(linux_kernel)]
pub const PROC_SUPER_MAGIC: FsWord = backend::c::PROC_SUPER_MAGIC as FsWord;
/// The filesystem magic number for NFS.
///
/// See [the `fstatfs` manual page] for more information.
///
/// [the `fstatfs` manual page]: https://man7.org/linux/man-pages/man2/fstatfs.2.html#DESCRIPTION
#[cfg(linux_kernel)]
pub const NFS_SUPER_MAGIC: FsWord = backend::c::NFS_SUPER_MAGIC as FsWord;
/// `lseek(fd, offset, whence)`—Repositions a file descriptor within a file.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html
/// [Linux]: https://man7.org/linux/man-pages/man2/lseek.2.html
#[inline]
#[doc(alias = "lseek")]
pub fn seek<Fd: AsFd>(fd: Fd, pos: SeekFrom) -> io::Result<u64> {
backend::fs::syscalls::seek(fd.as_fd(), pos)
}
/// `lseek(fd, 0, SEEK_CUR)`—Returns the current position within a file.
///
/// Return the current position of the file descriptor. This is a subset of
/// the functionality of `seek`, but this interface makes it easier for users
/// to declare their intent not to mutate any state.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html
/// [Linux]: https://man7.org/linux/man-pages/man2/lseek.2.html
#[inline]
#[doc(alias = "lseek")]
pub fn tell<Fd: AsFd>(fd: Fd) -> io::Result<u64> {
backend::fs::syscalls::tell(fd.as_fd())
}
/// `fchmod(fd, mode)`—Sets open file or directory permissions.
///
/// This implementation does not support [`OFlags::PATH`] file descriptors,
/// even on platforms where the host libc emulates it.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fchmod.2.html
#[cfg(not(target_os = "wasi"))]
#[inline]
pub fn fchmod<Fd: AsFd>(fd: Fd, mode: Mode) -> io::Result<()> {
backend::fs::syscalls::fchmod(fd.as_fd(), mode)
}
/// `fchown(fd, owner, group)`—Sets open file or directory ownership.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fchown.2.html
#[cfg(not(target_os = "wasi"))]
#[inline]
pub fn fchown<Fd: AsFd>(fd: Fd, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
backend::fs::syscalls::fchown(fd.as_fd(), owner, group)
}
/// `fstat(fd)`—Queries metadata for an open file or directory.
///
/// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to
/// interpret the `st_mode` field.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fstat.2.html
/// [`Mode::from_raw_mode`]: Mode::from_raw_mode
/// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode
#[inline]
pub fn fstat<Fd: AsFd>(fd: Fd) -> io::Result<Stat> {
backend::fs::syscalls::fstat(fd.as_fd())
}
/// `fstatfs(fd)`—Queries filesystem statistics for an open file or directory.
///
/// Compared to [`fstatvfs`], this function often provides more information,
/// though it's less portable.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/fstatfs.2.html
#[cfg(not(any(
solarish,
target_os = "espidf",
target_os = "haiku",
target_os = "netbsd",
target_os = "nto",
target_os = "redox",
target_os = "vita",
target_os = "wasi",
)))]
#[inline]
pub fn fstatfs<Fd: AsFd>(fd: Fd) -> io::Result<StatFs> {
backend::fs::syscalls::fstatfs(fd.as_fd())
}
/// `fstatvfs(fd)`—Queries filesystem statistics for an open file or
/// directory, POSIX version.
///
/// Compared to [`fstatfs`], this function often provides less information,
/// but it is more portable. But even so, filesystems are very diverse and not
/// all the fields are meaningful for every filesystem. And `f_fsid` doesn't
/// seem to have a clear meaning anywhere.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fstatvfs.2.html
#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
#[inline]
pub fn fstatvfs<Fd: AsFd>(fd: Fd) -> io::Result<StatVfs> {
backend::fs::syscalls::fstatvfs(fd.as_fd())
}
/// `futimens(fd, times)`—Sets timestamps for an open file or directory.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
/// [Linux]: https://man7.org/linux/man-pages/man2/utimensat.2.html
#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
#[inline]
pub fn futimens<Fd: AsFd>(fd: Fd, times: &Timestamps) -> io::Result<()> {
backend::fs::syscalls::futimens(fd.as_fd(), times)
}
/// `fallocate(fd, mode, offset, len)`—Adjusts file allocation.
///
/// This is a more general form of `posix_fallocate`, adding a `mode` argument
/// which modifies the behavior. On platforms which only support
/// `posix_fallocate` and not the more general form, no `FallocateFlags` values
/// are defined so it will always be empty.
///
/// # References
/// - [POSIX]
/// - [Linux `fallocate`]
/// - [Linux `posix_fallocate`]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html
/// [Linux `fallocate`]: https://man7.org/linux/man-pages/man2/fallocate.2.html
/// [Linux `posix_fallocate`]: https://man7.org/linux/man-pages/man3/posix_fallocate.3.html
#[cfg(not(any(
netbsdlike,
solarish,
target_os = "aix",
target_os = "dragonfly",
target_os = "espidf",
target_os = "nto",
target_os = "redox",
target_os = "vita",
)))] // not implemented in libc for netbsd yet
#[inline]
#[doc(alias = "posix_fallocate")]
pub fn fallocate<Fd: AsFd>(fd: Fd, mode: FallocateFlags, offset: u64, len: u64) -> io::Result<()> {
backend::fs::syscalls::fallocate(fd.as_fd(), mode, offset, len)
}
/// `fcntl(fd, F_GETFL) & O_ACCMODE`
///
/// Returns a pair of booleans indicating whether the file descriptor is
/// readable and/or writable, respectively. This is only reliable on files; for
/// example, it doesn't reflect whether sockets have been shut down; for
/// general I/O handle support, use [`io::is_read_write`].
#[inline]
pub fn is_file_read_write<Fd: AsFd>(fd: Fd) -> io::Result<(bool, bool)> {
_is_file_read_write(fd.as_fd())
}
pub(crate) fn _is_file_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> {
let mode = backend::fs::syscalls::fcntl_getfl(fd)?;
// Check for `O_PATH`.
#[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))]
if mode.contains(OFlags::PATH) {
return Ok((false, false));
}
// Use `RWMODE` rather than `ACCMODE` as `ACCMODE` may include `O_PATH`.
// We handled `O_PATH` above.
match mode & OFlags::RWMODE {
OFlags::RDONLY => Ok((true, false)),
OFlags::RDWR => Ok((true, true)),
OFlags::WRONLY => Ok((false, true)),
_ => unreachable!(),
}
}
/// `fsync(fd)`—Ensures that file data and metadata is written to the
/// underlying storage device.
///
/// On iOS and macOS this isn't sufficient to ensure that data has reached
/// persistent storage; use [`fcntl_fullfsync`] to ensure that.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fsync.2.html
/// [`fcntl_fullfsync`]: https://docs.rs/rustix/*/x86_64-apple-darwin/rustix/fs/fn.fcntl_fullfsync.html
#[inline]
pub fn fsync<Fd: AsFd>(fd: Fd) -> io::Result<()> {
backend::fs::syscalls::fsync(fd.as_fd())
}
/// `fdatasync(fd)`—Ensures that file data is written to the underlying
/// storage device.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fdatasync.2.html
#[cfg(not(any(
apple,
target_os = "dragonfly",
target_os = "espidf",
target_os = "haiku",
target_os = "redox",
target_os = "vita",
)))]
#[inline]
pub fn fdatasync<Fd: AsFd>(fd: Fd) -> io::Result<()> {
backend::fs::syscalls::fdatasync(fd.as_fd())
}
/// `ftruncate(fd, length)`—Sets the length of a file.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
/// [Linux]: https://man7.org/linux/man-pages/man2/ftruncate.2.html
#[inline]
pub fn ftruncate<Fd: AsFd>(fd: Fd, length: u64) -> io::Result<()> {
backend::fs::syscalls::ftruncate(fd.as_fd(), length)
}
/// `flock(fd, operation)`—Acquire or release an advisory lock on an open file.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/flock.2.html
#[cfg(not(any(
target_os = "espidf",
target_os = "solaris",
target_os = "vita",
target_os = "wasi"
)))]
#[inline]
pub fn flock<Fd: AsFd>(fd: Fd, operation: FlockOperation) -> io::Result<()> {
backend::fs::syscalls::flock(fd.as_fd(), operation)
}
/// `syncfs(fd)`—Flush cached filesystem data.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/syncfs.2.html
#[cfg(linux_kernel)]
#[inline]
pub fn syncfs<Fd: AsFd>(fd: Fd) -> io::Result<()> {
backend::fs::syscalls::syncfs(fd.as_fd())
}

View file

@ -0,0 +1,14 @@
use crate::ffi::CString;
use crate::{backend, io};
use backend::fd::AsFd;
/// `fcntl(fd, F_GETPATH)`
///
/// # References
/// - [Apple]
///
/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html
#[inline]
pub fn getpath<Fd: AsFd>(fd: Fd) -> io::Result<CString> {
backend::fs::syscalls::getpath(fd.as_fd())
}

View file

@ -0,0 +1 @@
pub use crate::ugid::{Gid, Uid};

View file

@ -0,0 +1,165 @@
//! Filesystem-oriented `ioctl` functions.
#![allow(unsafe_code)]
#[cfg(linux_kernel)]
use {
crate::fd::AsFd,
crate::{backend, io, ioctl},
backend::c,
};
use bitflags::bitflags;
#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
use crate::fd::{AsRawFd, BorrowedFd};
/// `ioctl(fd, BLKSSZGET)`—Returns the logical block size of a block device.
///
/// This is mentioned in the [Linux `openat` manual page].
///
/// [Linux `openat` manual page]: https://man7.org/linux/man-pages/man2/openat.2.html
#[cfg(linux_kernel)]
#[inline]
#[doc(alias = "BLKSSZGET")]
pub fn ioctl_blksszget<Fd: AsFd>(fd: Fd) -> io::Result<u32> {
// SAFETY: BLZSSZGET is a getter opcode that gets a u32.
unsafe {
let ctl = ioctl::Getter::<ioctl::BadOpcode<{ c::BLKSSZGET }>, c::c_uint>::new();
ioctl::ioctl(fd, ctl)
}
}
/// `ioctl(fd, BLKPBSZGET)`—Returns the physical block size of a block device.
#[cfg(linux_kernel)]
#[inline]
#[doc(alias = "BLKPBSZGET")]
pub fn ioctl_blkpbszget<Fd: AsFd>(fd: Fd) -> io::Result<u32> {
// SAFETY: BLKPBSZGET is a getter opcode that gets a u32.
unsafe {
let ctl = ioctl::Getter::<ioctl::BadOpcode<{ c::BLKPBSZGET }>, c::c_uint>::new();
ioctl::ioctl(fd, ctl)
}
}
/// `ioctl(fd, FICLONE, src_fd)`—Share data between open files.
///
/// This ioctl is not available on Sparc platforms
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl_ficlone.2.html
#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
#[inline]
#[doc(alias = "FICLONE")]
pub fn ioctl_ficlone<Fd: AsFd, SrcFd: AsFd>(fd: Fd, src_fd: SrcFd) -> io::Result<()> {
unsafe { ioctl::ioctl(fd, Ficlone(src_fd.as_fd())) }
}
/// `ioctl(fd, EXT4_IOC_RESIZE_FS, blocks)`—Resize ext4 filesystem on fd.
#[cfg(linux_kernel)]
#[inline]
#[doc(alias = "EXT4_IOC_RESIZE_FS")]
pub fn ext4_ioc_resize_fs<Fd: AsFd>(fd: Fd, blocks: u64) -> io::Result<()> {
// SAFETY: EXT4_IOC_RESIZE_FS is a pointer setter opcode.
unsafe {
let ctl = ioctl::Setter::<ioctl::BadOpcode<{ backend::fs::EXT4_IOC_RESIZE_FS }>, u64>::new(
blocks,
);
ioctl::ioctl(fd, ctl)
}
}
#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
struct Ficlone<'a>(BorrowedFd<'a>);
#[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))]
unsafe impl ioctl::Ioctl for Ficlone<'_> {
type Output = ();
const IS_MUTATING: bool = false;
const OPCODE: ioctl::Opcode = ioctl::Opcode::old(c::FICLONE as ioctl::RawOpcode);
fn as_ptr(&mut self) -> *mut c::c_void {
self.0.as_raw_fd() as *mut c::c_void
}
unsafe fn output_from_ptr(
_: ioctl::IoctlOutput,
_: *mut c::c_void,
) -> io::Result<Self::Output> {
Ok(())
}
}
#[cfg(linux_kernel)]
bitflags! {
/// `FS_*` constants for use with [`ioctl_getflags`][crate::io::ioctl::ioctl_getflags].
pub struct IFlags: c::c_uint {
/// `FS_APPEND_FL`
const APPEND = linux_raw_sys::general::FS_APPEND_FL;
/// `FS_COMPR_FL`
const COMPRESSED = linux_raw_sys::general::FS_COMPR_FL;
/// `FS_DIRSYNC_FL`
const DIRSYNC = linux_raw_sys::general::FS_DIRSYNC_FL;
/// `FS_IMMUTABLE_FL`
const IMMUTABLE = linux_raw_sys::general::FS_IMMUTABLE_FL;
/// `FS_JOURNAL_DATA_FL`
const JOURNALING = linux_raw_sys::general::FS_JOURNAL_DATA_FL;
/// `FS_NOATIME_FL`
const NOATIME = linux_raw_sys::general::FS_NOATIME_FL;
/// `FS_NOCOW_FL`
const NOCOW = linux_raw_sys::general::FS_NOCOW_FL;
/// `FS_NODUMP_FL`
const NODUMP = linux_raw_sys::general::FS_NODUMP_FL;
/// `FS_NOTAIL_FL`
const NOTAIL = linux_raw_sys::general::FS_NOTAIL_FL;
/// `FS_PROJINHERIT_FL`
const PROJECT_INHERIT = linux_raw_sys::general::FS_PROJINHERIT_FL;
/// `FS_SECRM_FL`
const SECURE_REMOVAL = linux_raw_sys::general::FS_SECRM_FL;
/// `FS_SYNC_FL`
const SYNC = linux_raw_sys::general::FS_SYNC_FL;
/// `FS_TOPDIR_FL`
const TOPDIR = linux_raw_sys::general::FS_TOPDIR_FL;
/// `FS_UNRM_FL`
const UNRM = linux_raw_sys::general::FS_UNRM_FL;
}
}
/// `ioctl(fd, FS_IOC_GETFLAGS)`—Returns the [inode flags] attributes
///
/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html
#[cfg(linux_kernel)]
#[inline]
#[doc(alias = "FS_IOC_GETFLAGS")]
pub fn ioctl_getflags<Fd: AsFd>(fd: Fd) -> io::Result<IFlags> {
unsafe {
#[cfg(target_pointer_width = "32")]
let ctl = ioctl::Getter::<ioctl::BadOpcode<{ c::FS_IOC32_GETFLAGS }>, u32>::new();
#[cfg(target_pointer_width = "64")]
let ctl = ioctl::Getter::<ioctl::BadOpcode<{ c::FS_IOC_GETFLAGS }>, u32>::new();
ioctl::ioctl(fd, ctl).map(IFlags::from_bits_retain)
}
}
/// `ioctl(fd, FS_IOC_SETFLAGS)`—Modify the [inode flags] attributes
///
/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html
#[cfg(linux_kernel)]
#[inline]
#[doc(alias = "FS_IOC_SETFLAGS")]
pub fn ioctl_setflags<Fd: AsFd>(fd: Fd, flags: IFlags) -> io::Result<()> {
unsafe {
#[cfg(target_pointer_width = "32")]
let ctl =
ioctl::Setter::<ioctl::BadOpcode<{ c::FS_IOC32_SETFLAGS }>, u32>::new(flags.bits());
#[cfg(target_pointer_width = "64")]
let ctl = ioctl::Setter::<ioctl::BadOpcode<{ c::FS_IOC_SETFLAGS }>, u32>::new(flags.bits());
ioctl::ioctl(fd, ctl)
}
}

View file

@ -0,0 +1,35 @@
use crate::backend;
use crate::fs::Dev;
/// `makedev(maj, min)`
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man3/makedev.3.html
#[inline]
pub fn makedev(maj: u32, min: u32) -> Dev {
backend::fs::makedev::makedev(maj, min)
}
/// `minor(dev)`
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man3/minor.3.html
#[inline]
pub fn minor(dev: Dev) -> u32 {
backend::fs::makedev::minor(dev)
}
/// `major(dev)`
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man3/major.3.html
#[inline]
pub fn major(dev: Dev) -> u32 {
backend::fs::makedev::major(dev)
}

View file

@ -0,0 +1,18 @@
use crate::fd::OwnedFd;
use crate::{backend, io, path};
use backend::fs::types::MemfdFlags;
/// `memfd_create(name, flags)`
///
/// # References
/// - [Linux]
/// - [glibc]
/// - [FreeBSD]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-memfd_005fcreate
/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?memfd_create
#[inline]
pub fn memfd_create<P: path::Arg>(name: P, flags: MemfdFlags) -> io::Result<OwnedFd> {
name.into_with_c_str(|name| backend::fs::syscalls::memfd_create(name, flags))
}

178
third-party/vendor/rustix/src/fs/mod.rs vendored Normal file
View file

@ -0,0 +1,178 @@
//! Filesystem operations.
mod abs;
#[cfg(not(target_os = "redox"))]
mod at;
mod constants;
#[cfg(linux_kernel)]
mod copy_file_range;
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
#[cfg(not(target_os = "haiku"))] // Haiku needs <https://github.com/rust-lang/rust/pull/112371>
mod cwd;
#[cfg(all(feature = "alloc", not(any(target_os = "espidf", target_os = "redox"))))]
mod dir;
#[cfg(not(any(
apple,
netbsdlike,
solarish,
target_os = "dragonfly",
target_os = "espidf",
target_os = "haiku",
target_os = "redox",
target_os = "vita",
)))]
mod fadvise;
pub(crate) mod fcntl;
#[cfg(apple)]
mod fcntl_apple;
#[cfg(apple)]
mod fcopyfile;
pub(crate) mod fd;
#[cfg(all(apple, feature = "alloc"))]
mod getpath;
#[cfg(not(target_os = "wasi"))] // WASI doesn't have get[gpu]id.
mod id;
#[cfg(linux_kernel)]
mod ioctl;
#[cfg(not(any(
target_os = "espidf",
target_os = "haiku",
target_os = "redox",
target_os = "vita",
target_os = "wasi"
)))]
mod makedev;
#[cfg(any(linux_kernel, target_os = "freebsd"))]
mod memfd_create;
#[cfg(linux_kernel)]
#[cfg(feature = "fs")]
mod mount;
#[cfg(linux_kernel)]
mod openat2;
#[cfg(linux_kernel)]
mod raw_dir;
mod seek_from;
#[cfg(target_os = "linux")]
mod sendfile;
#[cfg(linux_kernel)]
mod statx;
#[cfg(not(any(
target_os = "espidf",
target_os = "redox",
target_os = "vita",
target_os = "wasi"
)))]
mod sync;
#[cfg(any(apple, linux_kernel))]
mod xattr;
#[cfg(linux_kernel)]
pub use crate::backend::fs::inotify;
pub use abs::*;
#[cfg(not(target_os = "redox"))]
pub use at::*;
pub use constants::*;
#[cfg(linux_kernel)]
pub use copy_file_range::copy_file_range;
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
#[cfg(not(target_os = "haiku"))] // Haiku needs <https://github.com/rust-lang/rust/pull/112371>
pub use cwd::*;
#[cfg(all(feature = "alloc", not(any(target_os = "espidf", target_os = "redox"))))]
pub use dir::{Dir, DirEntry};
#[cfg(not(any(
apple,
netbsdlike,
solarish,
target_os = "dragonfly",
target_os = "espidf",
target_os = "haiku",
target_os = "redox",
target_os = "vita",
)))]
pub use fadvise::fadvise;
pub use fcntl::*;
#[cfg(apple)]
pub use fcntl_apple::*;
#[cfg(apple)]
pub use fcopyfile::*;
pub use fd::*;
#[cfg(all(apple, feature = "alloc"))]
pub use getpath::getpath;
#[cfg(not(target_os = "wasi"))]
pub use id::*;
#[cfg(linux_kernel)]
pub use ioctl::*;
#[cfg(not(any(
target_os = "espidf",
target_os = "haiku",
target_os = "redox",
target_os = "vita",
target_os = "wasi"
)))]
pub use makedev::*;
#[cfg(any(linux_kernel, target_os = "freebsd"))]
pub use memfd_create::memfd_create;
#[cfg(linux_kernel)]
#[cfg(feature = "fs")]
pub use mount::*;
#[cfg(linux_kernel)]
pub use openat2::openat2;
#[cfg(linux_kernel)]
pub use raw_dir::{RawDir, RawDirEntry};
pub use seek_from::SeekFrom;
#[cfg(target_os = "linux")]
pub use sendfile::sendfile;
#[cfg(linux_kernel)]
pub use statx::statx;
#[cfg(not(any(
target_os = "espidf",
target_os = "redox",
target_os = "vita",
target_os = "wasi"
)))]
pub use sync::sync;
#[cfg(any(apple, linux_kernel))]
pub use xattr::*;
/// Re-export types common to POSIX-ish platforms.
#[cfg(feature = "std")]
#[cfg(unix)]
pub use std::os::unix::fs::{DirEntryExt, FileExt, FileTypeExt, MetadataExt, OpenOptionsExt};
#[cfg(feature = "std")]
#[cfg(all(wasi_ext, target_os = "wasi"))]
pub use std::os::wasi::fs::{DirEntryExt, FileExt, FileTypeExt, MetadataExt, OpenOptionsExt};
/// Extension trait for accessing timestamp fields of `Stat`.
///
/// Rustix's `Stat` type on some platforms has unsigned `st_mtime`,
/// `st_atime`, and `st_ctime` fields. This is incorrect, as Unix defines
/// these fields to be signed, with negative values representing dates before
/// the Unix epoch. Until the next semver bump, these unsigned fields are
/// deprecated, and this trait provides accessors which return their values
/// as signed integers.
#[cfg(all(unix, not(any(target_os = "aix", target_os = "nto"))))]
pub trait StatExt {
/// Return the value of the `st_atime` field, casted to the correct type.
fn atime(&self) -> i64;
/// Return the value of the `st_mtime` field, casted to the correct type.
fn mtime(&self) -> i64;
/// Return the value of the `st_ctime` field, casted to the correct type.
fn ctime(&self) -> i64;
}
#[cfg(all(unix, not(any(target_os = "aix", target_os = "nto"))))]
#[allow(deprecated)]
impl StatExt for Stat {
#[inline]
fn atime(&self) -> i64 {
self.st_atime as i64
}
#[inline]
fn mtime(&self) -> i64 {
self.st_mtime as i64
}
#[inline]
fn ctime(&self) -> i64 {
self.st_ctime as i64
}
}

View file

@ -0,0 +1,55 @@
//! Linux `mount`.
//!
//! These have been moved to a new `rustix::mount` module.
#[deprecated(note = "`rustix::fs::UnmountFlags` moved to `rustix::mount::UnmountFlags`.")]
#[doc(hidden)]
pub use crate::mount::UnmountFlags;
#[deprecated(note = "`rustix::fs::MountFlags` moved to `rustix::mount::MountFlags`.")]
#[doc(hidden)]
pub use crate::mount::MountFlags;
#[deprecated(
note = "`rustix::fs::MountPropagationFlags` moved to `rustix::mount::MountPropagationFlags`."
)]
#[doc(hidden)]
pub use crate::mount::MountPropagationFlags;
#[deprecated(note = "`rustix::fs::mount` moved to `rustix::mount::mount`.")]
#[doc(hidden)]
pub use crate::mount::mount;
#[deprecated(note = "`rustix::fs::unmount` moved to `rustix::mount::unmount`.")]
#[doc(hidden)]
pub use crate::mount::unmount;
#[deprecated(
note = "`rustix::fs::remount` is renamed and moved to `rustix::mount::mount_remount`."
)]
#[doc(hidden)]
pub use crate::mount::mount_remount as remount;
#[deprecated(
note = "`rustix::fs::bind_mount` is renamed and moved to `rustix::mount::mount_bind`."
)]
#[doc(hidden)]
pub use crate::mount::mount_bind as bind_mount;
#[deprecated(
note = "`rustix::fs::recursive_bind_mount` is renamed and moved to `rustix::mount::mount_recursive_bind`."
)]
#[doc(hidden)]
pub use crate::mount::mount_recursive_bind as recursive_bind_mount;
#[deprecated(
note = "`rustix::fs::change_mount` is renamed and moved to `rustix::mount::mount_change`."
)]
#[doc(hidden)]
pub use crate::mount::mount_change as change_mount;
#[deprecated(
note = "`rustix::fs::move_mount` is renamed and moved to `rustix::mount::mount_move`."
)]
#[doc(hidden)]
pub use crate::mount::mount_move as move_mount;

View file

@ -0,0 +1,23 @@
use crate::fd::OwnedFd;
use crate::{backend, io, path};
use backend::fd::AsFd;
use backend::fs::types::{Mode, OFlags, ResolveFlags};
/// `openat2(dirfd, path, OpenHow { oflags, mode, resolve }, sizeof(OpenHow))`
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/openat2.2.html
#[inline]
pub fn openat2<Fd: AsFd, P: path::Arg>(
dirfd: Fd,
path: P,
oflags: OFlags,
mode: Mode,
resolve: ResolveFlags,
) -> io::Result<OwnedFd> {
path.into_with_c_str(|path| {
backend::fs::syscalls::openat2(dirfd.as_fd(), path, oflags, mode, resolve)
})
}

View file

@ -0,0 +1,237 @@
//! `RawDir` and `RawDirEntry`.
use core::fmt;
use core::mem::{align_of, MaybeUninit};
use linux_raw_sys::general::linux_dirent64;
use crate::backend::fs::syscalls::getdents_uninit;
use crate::fd::AsFd;
use crate::ffi::CStr;
use crate::fs::FileType;
use crate::io;
/// A directory iterator implemented with getdents.
///
/// Note: This implementation does not handle growing the buffer. If this
/// functionality is necessary, you'll need to drop the current iterator,
/// resize the buffer, and then re-create the iterator. The iterator is
/// guaranteed to continue where it left off provided the file descriptor isn't
/// changed. See the example in [`RawDir::new`].
pub struct RawDir<'buf, Fd: AsFd> {
fd: Fd,
buf: &'buf mut [MaybeUninit<u8>],
initialized: usize,
offset: usize,
}
impl<'buf, Fd: AsFd> RawDir<'buf, Fd> {
/// Create a new iterator from the given file descriptor and buffer.
///
/// Note: the buffer size may be trimmed to accommodate alignment
/// requirements.
///
/// # Examples
///
/// ## Simple but non-portable
///
/// These examples are non-portable, because file systems may not have a
/// maximum file name length. If you can make assumptions that bound
/// this length, then these examples may suffice.
///
/// Using the heap:
///
/// ```
/// # use std::mem::MaybeUninit;
/// # use rustix::fs::{CWD, Mode, OFlags, openat, RawDir};
/// # use rustix::cstr;
///
/// let fd = openat(
/// CWD,
/// cstr!("."),
/// OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC,
/// Mode::empty(),
/// )
/// .unwrap();
///
/// let mut buf = Vec::with_capacity(8192);
/// let mut iter = RawDir::new(fd, buf.spare_capacity_mut());
/// while let Some(entry) = iter.next() {
/// let entry = entry.unwrap();
/// dbg!(&entry);
/// }
/// ```
///
/// Using the stack:
///
/// ```
/// # use std::mem::MaybeUninit;
/// # use rustix::fs::{CWD, Mode, OFlags, openat, RawDir};
/// # use rustix::cstr;
///
/// let fd = openat(
/// CWD,
/// cstr!("."),
/// OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC,
/// Mode::empty(),
/// )
/// .unwrap();
///
/// let mut buf = [MaybeUninit::uninit(); 2048];
/// let mut iter = RawDir::new(fd, &mut buf);
/// while let Some(entry) = iter.next() {
/// let entry = entry.unwrap();
/// dbg!(&entry);
/// }
/// ```
///
/// ## Portable
///
/// Heap allocated growing buffer for supporting directory entries with
/// arbitrarily large file names:
///
/// ```notrust
/// # // The `notrust` above can be removed when we can depend on Rust 1.65.
/// # use std::mem::MaybeUninit;
/// # use rustix::fs::{CWD, Mode, OFlags, openat, RawDir};
/// # use rustix::io::Errno;
/// # use rustix::cstr;
///
/// let fd = openat(
/// CWD,
/// cstr!("."),
/// OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC,
/// Mode::empty(),
/// )
/// .unwrap();
///
/// let mut buf = Vec::with_capacity(8192);
/// 'read: loop {
/// 'resize: {
/// let mut iter = RawDir::new(&fd, buf.spare_capacity_mut());
/// while let Some(entry) = iter.next() {
/// let entry = match entry {
/// Err(Errno::INVAL) => break 'resize,
/// r => r.unwrap(),
/// };
/// dbg!(&entry);
/// }
/// break 'read;
/// }
///
/// let new_capacity = buf.capacity() * 2;
/// buf.reserve(new_capacity);
/// }
/// ```
pub fn new(fd: Fd, buf: &'buf mut [MaybeUninit<u8>]) -> Self {
Self {
fd,
buf: {
let offset = buf.as_ptr().align_offset(align_of::<linux_dirent64>());
if offset < buf.len() {
&mut buf[offset..]
} else {
&mut []
}
},
initialized: 0,
offset: 0,
}
}
}
/// A raw directory entry, similar to [`std::fs::DirEntry`].
///
/// Unlike the std version, this may represent the `.` or `..` entries.
pub struct RawDirEntry<'a> {
file_name: &'a CStr,
file_type: u8,
inode_number: u64,
next_entry_cookie: i64,
}
impl<'a> fmt::Debug for RawDirEntry<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = f.debug_struct("RawDirEntry");
f.field("file_name", &self.file_name());
f.field("file_type", &self.file_type());
f.field("ino", &self.ino());
f.field("next_entry_cookie", &self.next_entry_cookie());
f.finish()
}
}
impl<'a> RawDirEntry<'a> {
/// Returns the file name of this directory entry.
#[inline]
pub fn file_name(&self) -> &CStr {
self.file_name
}
/// Returns the type of this directory entry.
#[inline]
pub fn file_type(&self) -> FileType {
FileType::from_dirent_d_type(self.file_type)
}
/// Returns the inode number of this directory entry.
#[inline]
#[doc(alias = "inode_number")]
pub fn ino(&self) -> u64 {
self.inode_number
}
/// Returns the seek cookie to the next directory entry.
#[inline]
#[doc(alias = "off")]
pub fn next_entry_cookie(&self) -> u64 {
self.next_entry_cookie as u64
}
}
impl<'buf, Fd: AsFd> RawDir<'buf, Fd> {
/// Identical to [`Iterator::next`] except that [`Iterator::Item`] borrows
/// from self.
///
/// Note: this interface will be broken to implement a stdlib iterator API
/// with GAT support once one becomes available.
#[allow(unsafe_code)]
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Option<io::Result<RawDirEntry<'_>>> {
if self.is_buffer_empty() {
match getdents_uninit(self.fd.as_fd(), self.buf) {
Ok(0) => return None,
Ok(bytes_read) => {
self.initialized = bytes_read;
self.offset = 0;
}
Err(e) => return Some(Err(e)),
}
}
let dirent_ptr = self.buf[self.offset..].as_ptr();
// SAFETY:
// - This data is initialized by the check above.
// - Assumption: the kernel will not give us partial structs.
// - Assumption: the kernel uses proper alignment between structs.
// - The starting pointer is aligned (performed in RawDir::new)
let dirent = unsafe { &*dirent_ptr.cast::<linux_dirent64>() };
self.offset += usize::from(dirent.d_reclen);
Some(Ok(RawDirEntry {
file_type: dirent.d_type,
inode_number: dirent.d_ino.into(),
next_entry_cookie: dirent.d_off.into(),
// SAFETY: The kernel guarantees a NUL-terminated string.
file_name: unsafe { CStr::from_ptr(dirent.d_name.as_ptr().cast()) },
}))
}
/// Returns true if the internal buffer is empty and will be refilled when
/// calling [`next`].
///
/// [`next`]: Self::next
pub fn is_buffer_empty(&self) -> bool {
self.offset >= self.initialized
}
}

View file

@ -0,0 +1,53 @@
//! The following is derived from Rust's
//! library/std/src/io/mod.rs at revision
//! dca3f1b786efd27be3b325ed1e01e247aa589c3b.
/// Enumeration of possible methods to seek within an I/O object.
///
/// It is used by the [`seek`] function.
///
/// This is similar to [`std::io::SeekFrom`], however it adds platform-specific
/// seek options.
///
/// [`seek`]: crate::fs::seek
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub enum SeekFrom {
/// Sets the offset to the provided number of bytes.
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
Start(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] u64),
/// Sets the offset to the size of this object plus the specified number of
/// bytes.
///
/// It is possible to seek beyond the end of an object, but it's an error
/// to seek before byte 0.
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
End(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] i64),
/// Sets the offset to the current position plus the specified number of
/// bytes.
///
/// It is possible to seek beyond the end of an object, but it's an error
/// to seek before byte 0.
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
Current(#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] i64),
/// Sets the offset to the current position plus the specified number of
/// bytes, plus the distance to the next byte which is not in a hole.
///
/// If the offset is in a hole at the end of the file, the seek will fail
/// with [`Errno::NXIO`].
///
/// [`Errno::NXIO`]: crate::io::Errno::NXIO
#[cfg(any(apple, freebsdlike, linux_kernel, solarish))]
Data(i64),
/// Sets the offset to the current position plus the specified number of
/// bytes, plus the distance to the next byte which is in a hole.
///
/// If there is no hole past the offset, it will be set to the end of the
/// file i.e. there is an implicit hole at the end of any file.
#[cfg(any(apple, freebsdlike, linux_kernel, solarish))]
Hole(i64),
}

View file

@ -0,0 +1,19 @@
use crate::{backend, io};
use backend::fd::AsFd;
/// `sendfile(out_fd, in_fd, offset, count)`
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/sendfile.2.html
#[cfg(linux_kernel)]
#[inline]
pub fn sendfile<OutFd: AsFd, InFd: AsFd>(
out_fd: OutFd,
in_fd: InFd,
offset: Option<&mut u64>,
count: usize,
) -> io::Result<usize> {
backend::fs::syscalls::sendfile(out_fd.as_fd(), in_fd.as_fd(), offset, count)
}

View file

@ -0,0 +1,135 @@
//! Linux `statx`.
use crate::fd::AsFd;
use crate::fs::AtFlags;
use crate::{backend, io, path};
use backend::fs::types::{Statx, StatxFlags};
#[cfg(feature = "linux_4_11")]
use backend::fs::syscalls::statx as _statx;
#[cfg(not(feature = "linux_4_11"))]
use compat::statx as _statx;
/// `statx(dirfd, path, flags, mask, statxbuf)`
///
/// This function returns [`io::Errno::NOSYS`] if `statx` is not available on
/// the platform, such as Linux before 4.11. This also includes older Docker
/// versions where the actual syscall fails with different error codes; rustix
/// handles this and translates them into `NOSYS`.
///
/// # References
/// - [Linux]
///
/// # Examples
///
/// ```
/// # use std::path::Path;
/// # use std::io;
/// # use rustix::fs::{AtFlags, StatxFlags};
/// # use rustix::fd::BorrowedFd;
/// /// Try to determine if the provided path is a mount root. Will return
/// /// `Ok(None)` if the kernel is not new enough to support `statx` or
/// /// [`libc::STATX_ATTR_MOUNT_ROOT`].
/// fn is_mountpoint(root: BorrowedFd<'_>, path: &Path) -> io::Result<Option<bool>> {
/// use rustix::fs::{AtFlags, StatxFlags};
///
/// let mountroot_flag = libc::STATX_ATTR_MOUNT_ROOT as u64;
/// match rustix::fs::statx(
/// root,
/// path,
/// AtFlags::NO_AUTOMOUNT | AtFlags::SYMLINK_NOFOLLOW,
/// StatxFlags::empty(),
/// ) {
/// Ok(r) => {
/// let present = (r.stx_attributes_mask & mountroot_flag) > 0;
/// Ok(present.then(|| r.stx_attributes & mountroot_flag > 0))
/// }
/// Err(e) if e == rustix::io::Errno::NOSYS => Ok(None),
/// Err(e) => Err(e.into()),
/// }
/// }
/// ```
///
/// [Linux]: https://man7.org/linux/man-pages/man2/statx.2.html
#[inline]
pub fn statx<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
flags: AtFlags,
mask: StatxFlags,
) -> io::Result<Statx> {
path.into_with_c_str(|path| _statx(dirfd.as_fd(), path, flags, mask))
}
#[cfg(not(feature = "linux_4_11"))]
mod compat {
use crate::fd::BorrowedFd;
use crate::ffi::CStr;
use crate::fs::AtFlags;
use crate::{backend, io};
use core::sync::atomic::{AtomicU8, Ordering};
use backend::fs::types::{Statx, StatxFlags};
// Linux kernel prior to 4.11 and old versions of Docker don't support
// `statx`. We store the availability in a global to avoid unnecessary
// syscalls.
//
// 0: Unknown
// 1: Not available
// 2: Available
static STATX_STATE: AtomicU8 = AtomicU8::new(0);
#[inline]
pub fn statx(
dirfd: BorrowedFd<'_>,
path: &CStr,
flags: AtFlags,
mask: StatxFlags,
) -> io::Result<Statx> {
match STATX_STATE.load(Ordering::Relaxed) {
0 => statx_init(dirfd, path, flags, mask),
1 => Err(io::Errno::NOSYS),
_ => backend::fs::syscalls::statx(dirfd, path, flags, mask),
}
}
/// The first `statx` call. We don't know if `statx` is available yet.
fn statx_init(
dirfd: BorrowedFd<'_>,
path: &CStr,
flags: AtFlags,
mask: StatxFlags,
) -> io::Result<Statx> {
match backend::fs::syscalls::statx(dirfd, path, flags, mask) {
Err(io::Errno::NOSYS) => statx_error_nosys(),
Err(io::Errno::PERM) => statx_error_perm(),
result => {
STATX_STATE.store(2, Ordering::Relaxed);
result
}
}
}
/// The first `statx` call failed with `NOSYS` (or something we're treating
/// like `NOSYS`).
#[cold]
fn statx_error_nosys() -> io::Result<Statx> {
STATX_STATE.store(1, Ordering::Relaxed);
Err(io::Errno::NOSYS)
}
/// The first `statx` call failed with `PERM`.
#[cold]
fn statx_error_perm() -> io::Result<Statx> {
// Some old versions of Docker have `statx` fail with `PERM` when it
// isn't recognized. Check whether `statx` really is available, and if
// so, fail with `PERM`, and if not, treat it like `NOSYS`.
if backend::fs::syscalls::is_statx_available() {
STATX_STATE.store(2, Ordering::Relaxed);
Err(io::Errno::PERM)
} else {
statx_error_nosys()
}
}
}

View file

@ -0,0 +1,14 @@
use crate::backend;
/// `sync`—Flush cached filesystem data for all filesystems.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html
/// [Linux]: https://man7.org/linux/man-pages/man2/sync.2.html
#[inline]
pub fn sync() {
backend::fs::syscalls::sync();
}

View file

@ -0,0 +1,202 @@
use crate::{backend, io, path};
use backend::c;
use backend::fd::AsFd;
use bitflags::bitflags;
bitflags! {
/// `XATTR_*` constants for use with [`setxattr`], and other `*setxattr`
/// functions.
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct XattrFlags: c::c_uint {
/// `XATTR_CREATE`
const CREATE = c::XATTR_CREATE as c::c_uint;
/// `XATTR_REPLACE`
const REPLACE = c::XATTR_REPLACE as c::c_uint;
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
const _ = !0;
}
}
/// `getxattr(path, name, value.as_ptr(), value.len())`—Get extended
/// filesystem attributes.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/getxattr.2.html
#[inline]
pub fn getxattr<P: path::Arg, Name: path::Arg>(
path: P,
name: Name,
value: &mut [u8],
) -> io::Result<usize> {
path.into_with_c_str(|path| {
name.into_with_c_str(|name| backend::fs::syscalls::getxattr(path, name, value))
})
}
/// `lgetxattr(path, name, value.as_ptr(), value.len())`—Get extended
/// filesystem attributes, without following symlinks in the last path
/// component.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/lgetxattr.2.html
#[inline]
pub fn lgetxattr<P: path::Arg, Name: path::Arg>(
path: P,
name: Name,
value: &mut [u8],
) -> io::Result<usize> {
path.into_with_c_str(|path| {
name.into_with_c_str(|name| backend::fs::syscalls::lgetxattr(path, name, value))
})
}
/// `fgetxattr(fd, name, value.as_ptr(), value.len())`—Get extended
/// filesystem attributes on an open file descriptor.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/fgetxattr.2.html
#[inline]
pub fn fgetxattr<Fd: AsFd, Name: path::Arg>(
fd: Fd,
name: Name,
value: &mut [u8],
) -> io::Result<usize> {
name.into_with_c_str(|name| backend::fs::syscalls::fgetxattr(fd.as_fd(), name, value))
}
/// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended
/// filesystem attributes.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/setxattr.2.html
#[inline]
pub fn setxattr<P: path::Arg, Name: path::Arg>(
path: P,
name: Name,
value: &[u8],
flags: XattrFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| {
name.into_with_c_str(|name| backend::fs::syscalls::setxattr(path, name, value, flags))
})
}
/// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended
/// filesystem attributes, without following symlinks in the last path
/// component.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/lsetxattr.2.html
#[inline]
pub fn lsetxattr<P: path::Arg, Name: path::Arg>(
path: P,
name: Name,
value: &[u8],
flags: XattrFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| {
name.into_with_c_str(|name| backend::fs::syscalls::lsetxattr(path, name, value, flags))
})
}
/// `fsetxattr(fd, name, value.as_ptr(), value.len(), flags)`—Set extended
/// filesystem attributes on an open file descriptor.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/fsetxattr.2.html
#[inline]
pub fn fsetxattr<Fd: AsFd, Name: path::Arg>(
fd: Fd,
name: Name,
value: &[u8],
flags: XattrFlags,
) -> io::Result<()> {
name.into_with_c_str(|name| backend::fs::syscalls::fsetxattr(fd.as_fd(), name, value, flags))
}
/// `listxattr(path, list.as_ptr(), list.len())`—List extended filesystem
/// attributes.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/listxattr.2.html
#[inline]
pub fn listxattr<P: path::Arg>(path: P, list: &mut [c::c_char]) -> io::Result<usize> {
path.into_with_c_str(|path| backend::fs::syscalls::listxattr(path, list))
}
/// `llistxattr(path, list.as_ptr(), list.len())`—List extended filesystem
/// attributes, without following symlinks in the last path component.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/llistxattr.2.html
#[inline]
pub fn llistxattr<P: path::Arg>(path: P, list: &mut [c::c_char]) -> io::Result<usize> {
path.into_with_c_str(|path| backend::fs::syscalls::llistxattr(path, list))
}
/// `flistxattr(fd, list.as_ptr(), list.len())`—List extended filesystem
/// attributes on an open file descriptor.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/flistxattr.2.html
#[inline]
pub fn flistxattr<Fd: AsFd>(fd: Fd, list: &mut [c::c_char]) -> io::Result<usize> {
backend::fs::syscalls::flistxattr(fd.as_fd(), list)
}
/// `removexattr(path, name)`—Remove an extended filesystem attribute.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/removexattr.2.html
pub fn removexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> {
path.into_with_c_str(|path| {
name.into_with_c_str(|name| backend::fs::syscalls::removexattr(path, name))
})
}
/// `lremovexattr(path, name)`—Remove an extended filesystem attribute,
/// without following symlinks in the last path component.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/lremovexattr.2.html
pub fn lremovexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> {
path.into_with_c_str(|path| {
name.into_with_c_str(|name| backend::fs::syscalls::lremovexattr(path, name))
})
}
/// `fremovexattr(fd, name)`—Remove an extended filesystem attribute on an
/// open file descriptor.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://man7.org/linux/man-pages/man2/fremovexattr.2.html
pub fn fremovexattr<Fd: AsFd, Name: path::Arg>(fd: Fd, name: Name) -> io::Result<()> {
name.into_with_c_str(|name| backend::fs::syscalls::fremovexattr(fd.as_fd(), name))
}