1b8a62b91Sopenharmony_ci//! Linux `statx`. 2b8a62b91Sopenharmony_ci 3b8a62b91Sopenharmony_ciuse crate::fd::{AsFd, BorrowedFd}; 4b8a62b91Sopenharmony_ciuse crate::ffi::CStr; 5b8a62b91Sopenharmony_ciuse crate::fs::AtFlags; 6b8a62b91Sopenharmony_ciuse crate::{backend, io, path}; 7b8a62b91Sopenharmony_ciuse core::sync::atomic::{AtomicU8, Ordering}; 8b8a62b91Sopenharmony_ci 9b8a62b91Sopenharmony_cipub use backend::fs::types::{Statx, StatxFlags, StatxTimestamp}; 10b8a62b91Sopenharmony_ci 11b8a62b91Sopenharmony_ci/// `statx(dirfd, path, flags, mask, statxbuf)` 12b8a62b91Sopenharmony_ci/// 13b8a62b91Sopenharmony_ci/// This function returns [`io::Errno::NOSYS`] if `statx` is not available on 14b8a62b91Sopenharmony_ci/// the platform, such as Linux before 4.11. This also includes older Docker 15b8a62b91Sopenharmony_ci/// versions where the actual syscall fails with different error codes; Rustix 16b8a62b91Sopenharmony_ci/// handles this and translates them into `NOSYS`. 17b8a62b91Sopenharmony_ci/// 18b8a62b91Sopenharmony_ci/// # References 19b8a62b91Sopenharmony_ci/// - [Linux] 20b8a62b91Sopenharmony_ci/// 21b8a62b91Sopenharmony_ci/// [Linux]: https://man7.org/linux/man-pages/man2/statx.2.html 22b8a62b91Sopenharmony_ci#[inline] 23b8a62b91Sopenharmony_cipub fn statx<P: path::Arg, Fd: AsFd>( 24b8a62b91Sopenharmony_ci dirfd: Fd, 25b8a62b91Sopenharmony_ci path: P, 26b8a62b91Sopenharmony_ci flags: AtFlags, 27b8a62b91Sopenharmony_ci mask: StatxFlags, 28b8a62b91Sopenharmony_ci) -> io::Result<Statx> { 29b8a62b91Sopenharmony_ci path.into_with_c_str(|path| _statx(dirfd.as_fd(), path, flags, mask)) 30b8a62b91Sopenharmony_ci} 31b8a62b91Sopenharmony_ci 32b8a62b91Sopenharmony_ci// Linux kernel prior to 4.11 old versions of Docker don't support `statx`. We 33b8a62b91Sopenharmony_ci// store the availability in a global to avoid unnecessary syscalls. 34b8a62b91Sopenharmony_ci// 35b8a62b91Sopenharmony_ci// 0: Unknown 36b8a62b91Sopenharmony_ci// 1: Not available 37b8a62b91Sopenharmony_ci// 2: Available 38b8a62b91Sopenharmony_cistatic STATX_STATE: AtomicU8 = AtomicU8::new(0); 39b8a62b91Sopenharmony_ci 40b8a62b91Sopenharmony_ci#[inline] 41b8a62b91Sopenharmony_cifn _statx( 42b8a62b91Sopenharmony_ci dirfd: BorrowedFd<'_>, 43b8a62b91Sopenharmony_ci path: &CStr, 44b8a62b91Sopenharmony_ci flags: AtFlags, 45b8a62b91Sopenharmony_ci mask: StatxFlags, 46b8a62b91Sopenharmony_ci) -> io::Result<Statx> { 47b8a62b91Sopenharmony_ci match STATX_STATE.load(Ordering::Relaxed) { 48b8a62b91Sopenharmony_ci 0 => statx_init(dirfd, path, flags, mask), 49b8a62b91Sopenharmony_ci 1 => Err(io::Errno::NOSYS), 50b8a62b91Sopenharmony_ci _ => backend::fs::syscalls::statx(dirfd, path, flags, mask), 51b8a62b91Sopenharmony_ci } 52b8a62b91Sopenharmony_ci} 53b8a62b91Sopenharmony_ci 54b8a62b91Sopenharmony_ci/// The first `statx` call. We don't know if `statx` is available yet. 55b8a62b91Sopenharmony_cifn statx_init( 56b8a62b91Sopenharmony_ci dirfd: BorrowedFd<'_>, 57b8a62b91Sopenharmony_ci path: &CStr, 58b8a62b91Sopenharmony_ci flags: AtFlags, 59b8a62b91Sopenharmony_ci mask: StatxFlags, 60b8a62b91Sopenharmony_ci) -> io::Result<Statx> { 61b8a62b91Sopenharmony_ci match backend::fs::syscalls::statx(dirfd, path, flags, mask) { 62b8a62b91Sopenharmony_ci Err(io::Errno::NOSYS) => statx_error_nosys(), 63b8a62b91Sopenharmony_ci Err(io::Errno::PERM) => statx_error_perm(), 64b8a62b91Sopenharmony_ci result => { 65b8a62b91Sopenharmony_ci STATX_STATE.store(2, Ordering::Relaxed); 66b8a62b91Sopenharmony_ci result 67b8a62b91Sopenharmony_ci } 68b8a62b91Sopenharmony_ci } 69b8a62b91Sopenharmony_ci} 70b8a62b91Sopenharmony_ci 71b8a62b91Sopenharmony_ci/// The first `statx` call failed with `NOSYS` (or something we're treating 72b8a62b91Sopenharmony_ci/// like `NOSYS`). 73b8a62b91Sopenharmony_ci#[cold] 74b8a62b91Sopenharmony_cifn statx_error_nosys() -> io::Result<Statx> { 75b8a62b91Sopenharmony_ci STATX_STATE.store(1, Ordering::Relaxed); 76b8a62b91Sopenharmony_ci Err(io::Errno::NOSYS) 77b8a62b91Sopenharmony_ci} 78b8a62b91Sopenharmony_ci 79b8a62b91Sopenharmony_ci/// The first `statx` call failed with `PERM`. 80b8a62b91Sopenharmony_ci#[cold] 81b8a62b91Sopenharmony_cifn statx_error_perm() -> io::Result<Statx> { 82b8a62b91Sopenharmony_ci // Some old versions of Docker have `statx` fail with `PERM` when it isn't 83b8a62b91Sopenharmony_ci // recognized. Check whether `statx` really is available, and if so, fail 84b8a62b91Sopenharmony_ci // with `PERM`, and if not, treat it like `NOSYS`. 85b8a62b91Sopenharmony_ci if backend::fs::syscalls::is_statx_available() { 86b8a62b91Sopenharmony_ci STATX_STATE.store(2, Ordering::Relaxed); 87b8a62b91Sopenharmony_ci Err(io::Errno::PERM) 88b8a62b91Sopenharmony_ci } else { 89b8a62b91Sopenharmony_ci statx_error_nosys() 90b8a62b91Sopenharmony_ci } 91b8a62b91Sopenharmony_ci} 92