summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/fs/statx.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/fs/statx.rs')
-rw-r--r--vendor/rustix/src/fs/statx.rs91
1 files changed, 91 insertions, 0 deletions
diff --git a/vendor/rustix/src/fs/statx.rs b/vendor/rustix/src/fs/statx.rs
new file mode 100644
index 000000000..fa1d36779
--- /dev/null
+++ b/vendor/rustix/src/fs/statx.rs
@@ -0,0 +1,91 @@
+//! Linux `statx`.
+
+use crate::fd::{AsFd, BorrowedFd};
+use crate::ffi::CStr;
+use crate::fs::AtFlags;
+use crate::{imp, io, path};
+use core::sync::atomic::{AtomicU8, Ordering};
+
+pub use imp::fs::types::{Statx, StatxFlags, StatxTimestamp};
+
+/// `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]
+///
+/// [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))
+}
+
+// Linux kernel prior to 4.11 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]
+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),
+ _ => imp::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 imp::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 imp::fs::syscalls::is_statx_available() {
+ STATX_STATE.store(2, Ordering::Relaxed);
+ Err(io::Errno::PERM)
+ } else {
+ statx_error_nosys()
+ }
+}