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