/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustix-1.1.2/src/fs/statx.rs
Line | Count | Source |
1 | | //! Linux `statx`. |
2 | | |
3 | | use crate::fd::AsFd; |
4 | | use crate::fs::AtFlags; |
5 | | use crate::{backend, io, path}; |
6 | | use backend::c; |
7 | | use bitflags::bitflags; |
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 | | /// `struct statx` for use with [`statx`]. |
15 | | #[repr(C)] |
16 | | #[derive(Debug, Copy, Clone)] |
17 | | #[allow(missing_docs)] |
18 | | #[non_exhaustive] |
19 | | pub struct Statx { |
20 | | pub stx_mask: u32, |
21 | | pub stx_blksize: u32, |
22 | | pub stx_attributes: StatxAttributes, |
23 | | pub stx_nlink: u32, |
24 | | pub stx_uid: u32, |
25 | | pub stx_gid: u32, |
26 | | pub stx_mode: u16, |
27 | | pub(crate) __spare0: [u16; 1], |
28 | | pub stx_ino: u64, |
29 | | pub stx_size: u64, |
30 | | pub stx_blocks: u64, |
31 | | pub stx_attributes_mask: StatxAttributes, |
32 | | pub stx_atime: StatxTimestamp, |
33 | | pub stx_btime: StatxTimestamp, |
34 | | pub stx_ctime: StatxTimestamp, |
35 | | pub stx_mtime: StatxTimestamp, |
36 | | pub stx_rdev_major: u32, |
37 | | pub stx_rdev_minor: u32, |
38 | | pub stx_dev_major: u32, |
39 | | pub stx_dev_minor: u32, |
40 | | pub stx_mnt_id: u64, |
41 | | pub stx_dio_mem_align: u32, |
42 | | pub stx_dio_offset_align: u32, |
43 | | pub stx_subvol: u64, |
44 | | pub stx_atomic_write_unit_min: u32, |
45 | | pub stx_atomic_write_unit_max: u32, |
46 | | pub stx_atomic_write_segments_max: u32, |
47 | | pub stx_dio_read_offset_align: u32, |
48 | | pub stx_atomic_write_unit_max_opt: u32, |
49 | | pub __spare2: [u32; 1usize], |
50 | | pub __spare3: [u64; 8usize], |
51 | | } |
52 | | |
53 | | /// `struct statx_timestamp` for use with [`Statx`]. |
54 | | #[repr(C)] |
55 | | #[derive(Debug, Copy, Clone)] |
56 | | #[non_exhaustive] |
57 | | pub struct StatxTimestamp { |
58 | | /// Seconds. |
59 | | pub tv_sec: i64, |
60 | | |
61 | | /// Nanoseconds. Must be less than 1_000_000_000. |
62 | | pub tv_nsec: u32, |
63 | | |
64 | | pub(crate) __reserved: i32, |
65 | | } |
66 | | |
67 | | bitflags! { |
68 | | /// `STATX_*` constants for use with [`statx`]. |
69 | | /// |
70 | | /// [`statx`]: crate::fs::statx |
71 | | #[repr(transparent)] |
72 | | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] |
73 | | pub struct StatxFlags: u32 { |
74 | | /// `STATX_TYPE` |
75 | | const TYPE = c::STATX_TYPE; |
76 | | |
77 | | /// `STATX_MODE` |
78 | | const MODE = c::STATX_MODE; |
79 | | |
80 | | /// `STATX_NLINK` |
81 | | const NLINK = c::STATX_NLINK; |
82 | | |
83 | | /// `STATX_UID` |
84 | | const UID = c::STATX_UID; |
85 | | |
86 | | /// `STATX_GID` |
87 | | const GID = c::STATX_GID; |
88 | | |
89 | | /// `STATX_ATIME` |
90 | | const ATIME = c::STATX_ATIME; |
91 | | |
92 | | /// `STATX_MTIME` |
93 | | const MTIME = c::STATX_MTIME; |
94 | | |
95 | | /// `STATX_CTIME` |
96 | | const CTIME = c::STATX_CTIME; |
97 | | |
98 | | /// `STATX_INO` |
99 | | const INO = c::STATX_INO; |
100 | | |
101 | | /// `STATX_SIZE` |
102 | | const SIZE = c::STATX_SIZE; |
103 | | |
104 | | /// `STATX_BLOCKS` |
105 | | const BLOCKS = c::STATX_BLOCKS; |
106 | | |
107 | | /// `STATX_BASIC_STATS` |
108 | | const BASIC_STATS = c::STATX_BASIC_STATS; |
109 | | |
110 | | /// `STATX_BTIME` |
111 | | const BTIME = c::STATX_BTIME; |
112 | | |
113 | | /// `STATX_MNT_ID` (since Linux 5.8) |
114 | | const MNT_ID = c::STATX_MNT_ID; |
115 | | |
116 | | /// `STATX_DIOALIGN` (since Linux 6.1) |
117 | | const DIOALIGN = c::STATX_DIOALIGN; |
118 | | |
119 | | /// `STATX_ALL` |
120 | | const ALL = c::STATX_ALL; |
121 | | |
122 | | /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> |
123 | | const _ = !0; |
124 | | } |
125 | | } |
126 | | |
127 | | bitflags! { |
128 | | /// `STATX_ATTR_*` flags for use with [`Statx`]. |
129 | | #[repr(transparent)] |
130 | | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] |
131 | | pub struct StatxAttributes: u64 { |
132 | | /// `STATX_ATTR_COMPRESSED` |
133 | | const COMPRESSED = c::STATX_ATTR_COMPRESSED as u64; |
134 | | |
135 | | /// `STATX_ATTR_IMMUTABLE` |
136 | | const IMMUTABLE = c::STATX_ATTR_IMMUTABLE as u64; |
137 | | |
138 | | /// `STATX_ATTR_APPEND` |
139 | | const APPEND = c::STATX_ATTR_APPEND as u64; |
140 | | |
141 | | /// `STATX_ATTR_NODUMP` |
142 | | const NODUMP = c::STATX_ATTR_NODUMP as u64; |
143 | | |
144 | | /// `STATX_ATTR_ENCRYPTED` |
145 | | const ENCRYPTED = c::STATX_ATTR_ENCRYPTED as u64; |
146 | | |
147 | | /// `STATX_ATTR_AUTOMOUNT` |
148 | | const AUTOMOUNT = c::STATX_ATTR_AUTOMOUNT as u64; |
149 | | |
150 | | /// `STATX_ATTR_MOUNT_ROOT` |
151 | | const MOUNT_ROOT = c::STATX_ATTR_MOUNT_ROOT as u64; |
152 | | |
153 | | /// `STATX_ATTR_VERITY` |
154 | | const VERITY = c::STATX_ATTR_VERITY as u64; |
155 | | |
156 | | /// `STATX_ATTR_DAX` |
157 | | const DAX = c::STATX_ATTR_DAX as u64; |
158 | | |
159 | | /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> |
160 | | const _ = !0; |
161 | | } |
162 | | } |
163 | | |
164 | | /// `statx(dirfd, path, flags, mask, statxbuf)`—Extended `stat`. |
165 | | /// |
166 | | /// This function returns [`io::Errno::NOSYS`] if `statx` is not available on |
167 | | /// the platform, such as Linux before 4.11. This also includes older Docker |
168 | | /// versions where the actual syscall fails with different error codes; rustix |
169 | | /// handles this and translates them into `NOSYS`. |
170 | | /// |
171 | | /// # References |
172 | | /// - [Linux] |
173 | | /// |
174 | | /// # Examples |
175 | | /// |
176 | | /// ``` |
177 | | /// # use std::path::Path; |
178 | | /// # use std::io; |
179 | | /// # use rustix::fs::{AtFlags, StatxFlags}; |
180 | | /// # use rustix::fd::BorrowedFd; |
181 | | /// /// Try to determine if the provided path is a mount root. Will return |
182 | | /// /// `Ok(None)` if the kernel is not new enough to support `statx` or |
183 | | /// /// [`StatxAttributes::MOUNT_ROOT`]. |
184 | | /// fn is_mountpoint(root: BorrowedFd<'_>, path: &Path) -> io::Result<Option<bool>> { |
185 | | /// use rustix::fs::{AtFlags, StatxAttributes, StatxFlags}; |
186 | | /// |
187 | | /// match rustix::fs::statx( |
188 | | /// root, |
189 | | /// path, |
190 | | /// AtFlags::NO_AUTOMOUNT | AtFlags::SYMLINK_NOFOLLOW, |
191 | | /// StatxFlags::empty(), |
192 | | /// ) { |
193 | | /// Ok(r) => { |
194 | | /// let present = r.stx_attributes_mask.contains(StatxAttributes::MOUNT_ROOT); |
195 | | /// Ok(present.then(|| r.stx_attributes.contains(StatxAttributes::MOUNT_ROOT))) |
196 | | /// } |
197 | | /// Err(rustix::io::Errno::NOSYS) => Ok(None), |
198 | | /// Err(e) => Err(e.into()), |
199 | | /// } |
200 | | /// } |
201 | | /// ``` |
202 | | /// |
203 | | /// [Linux]: https://man7.org/linux/man-pages/man2/statx.2.html |
204 | | #[inline] |
205 | 0 | pub fn statx<P: path::Arg, Fd: AsFd>( |
206 | 0 | dirfd: Fd, |
207 | 0 | path: P, |
208 | 0 | flags: AtFlags, |
209 | 0 | mask: StatxFlags, |
210 | 0 | ) -> io::Result<Statx> { |
211 | 0 | path.into_with_c_str(|path| _statx(dirfd.as_fd(), path, flags, mask)) Unexecuted instantiation: rustix::fs::statx::statx::<&std::path::Path, &std::fs::File>::{closure#0} Unexecuted instantiation: rustix::fs::statx::statx::<&str, std::os::fd::owned::BorrowedFd>::{closure#0} Unexecuted instantiation: rustix::fs::statx::statx::<_, _>::{closure#0} |
212 | 0 | } Unexecuted instantiation: rustix::fs::statx::statx::<&std::path::Path, &std::fs::File> Unexecuted instantiation: rustix::fs::statx::statx::<&str, std::os::fd::owned::BorrowedFd> Unexecuted instantiation: rustix::fs::statx::statx::<_, _> |
213 | | |
214 | | #[cfg(not(feature = "linux_4_11"))] |
215 | | mod compat { |
216 | | use crate::fd::BorrowedFd; |
217 | | use crate::ffi::CStr; |
218 | | use crate::fs::{AtFlags, Statx, StatxFlags}; |
219 | | use crate::{backend, io}; |
220 | | use core::sync::atomic::{AtomicU8, Ordering}; |
221 | | |
222 | | // Linux kernel prior to 4.11 and old versions of Docker don't support |
223 | | // `statx`. We store the availability in a global to avoid unnecessary |
224 | | // syscalls. |
225 | | // |
226 | | // 0: Unknown |
227 | | // 1: Not available |
228 | | // 2: Available |
229 | | static STATX_STATE: AtomicU8 = AtomicU8::new(0); |
230 | | |
231 | | #[inline] |
232 | 0 | pub fn statx( |
233 | 0 | dirfd: BorrowedFd<'_>, |
234 | 0 | path: &CStr, |
235 | 0 | flags: AtFlags, |
236 | 0 | mask: StatxFlags, |
237 | 0 | ) -> io::Result<Statx> { |
238 | 0 | match STATX_STATE.load(Ordering::Relaxed) { |
239 | 0 | 0 => statx_init(dirfd, path, flags, mask), |
240 | 0 | 1 => Err(io::Errno::NOSYS), |
241 | 0 | _ => backend::fs::syscalls::statx(dirfd, path, flags, mask), |
242 | | } |
243 | 0 | } Unexecuted instantiation: rustix::fs::statx::compat::statx Unexecuted instantiation: rustix::fs::statx::compat::statx |
244 | | |
245 | | /// The first `statx` call. We don't know if `statx` is available yet. |
246 | 0 | fn statx_init( |
247 | 0 | dirfd: BorrowedFd<'_>, |
248 | 0 | path: &CStr, |
249 | 0 | flags: AtFlags, |
250 | 0 | mask: StatxFlags, |
251 | 0 | ) -> io::Result<Statx> { |
252 | 0 | match backend::fs::syscalls::statx(dirfd, path, flags, mask) { |
253 | 0 | Err(err) => statx_error(err), |
254 | 0 | result => { |
255 | 0 | STATX_STATE.store(2, Ordering::Relaxed); |
256 | 0 | result |
257 | | } |
258 | | } |
259 | 0 | } |
260 | | |
261 | | /// The first `statx` call failed. We can get a variety of error codes |
262 | | /// from seccomp configs or faulty FUSE drivers, so we don't trust |
263 | | /// `ENOSYS` or `EPERM` to tell us whether statx is available. |
264 | | #[cold] |
265 | 0 | fn statx_error(err: io::Errno) -> io::Result<Statx> { |
266 | 0 | if backend::fs::syscalls::is_statx_available() { |
267 | | // Statx is available. Record this, and fail with the error |
268 | | // code of the initial `statx` call. |
269 | 0 | STATX_STATE.store(2, Ordering::Relaxed); |
270 | 0 | Err(err) |
271 | | } else { |
272 | | // Statx is not available. Record this, and fail with `NOSYS`. |
273 | 0 | STATX_STATE.store(1, Ordering::Relaxed); |
274 | 0 | Err(io::Errno::NOSYS) |
275 | | } |
276 | 0 | } |
277 | | } |