1use crate::fd::AsFd;
4use crate::fs::AtFlags;
5use crate::types::Padding;
6use crate::{backend, io, path};
7use backend::c;
8use bitflags::bitflags;
9
10#[cfg(feature = "linux_4_11")]
11use backend::fs::syscalls::statx as _statx;
12#[cfg(not(feature = "linux_4_11"))]
13use compat::statx as _statx;
14
15#[repr(C)]
17#[derive(Debug, Copy, Clone)]
18#[allow(missing_docs)]
19#[non_exhaustive]
20pub struct Statx {
21 pub stx_mask: u32,
22 pub stx_blksize: u32,
23 pub stx_attributes: StatxAttributes,
24 pub stx_nlink: u32,
25 pub stx_uid: u32,
26 pub stx_gid: u32,
27 pub stx_mode: u16,
28 pub(crate) __spare0: Padding<[u16; 1]>,
29 pub stx_ino: u64,
30 pub stx_size: u64,
31 pub stx_blocks: u64,
32 pub stx_attributes_mask: StatxAttributes,
33 pub stx_atime: StatxTimestamp,
34 pub stx_btime: StatxTimestamp,
35 pub stx_ctime: StatxTimestamp,
36 pub stx_mtime: StatxTimestamp,
37 pub stx_rdev_major: u32,
38 pub stx_rdev_minor: u32,
39 pub stx_dev_major: u32,
40 pub stx_dev_minor: u32,
41 pub stx_mnt_id: u64,
42 pub stx_dio_mem_align: u32,
43 pub stx_dio_offset_align: u32,
44 pub stx_subvol: u64,
45 pub stx_atomic_write_unit_min: u32,
46 pub stx_atomic_write_unit_max: u32,
47 pub stx_atomic_write_segments_max: u32,
48 pub stx_dio_read_offset_align: u32,
49 pub stx_atomic_write_unit_max_opt: u32,
50 pub(crate) __spare2: Padding<[u32; 1usize]>,
51 pub(crate) __spare3: Padding<[u64; 8usize]>,
52}
53
54#[repr(C)]
56#[derive(Debug, Copy, Clone)]
57#[non_exhaustive]
58pub struct StatxTimestamp {
59 pub tv_sec: i64,
61
62 pub tv_nsec: u32,
64
65 pub(crate) __reserved: Padding<i32>,
66}
67
68bitflags! {
69 #[repr(transparent)]
73 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
74 pub struct StatxFlags: u32 {
75 const TYPE = c::STATX_TYPE;
77
78 const MODE = c::STATX_MODE;
80
81 const NLINK = c::STATX_NLINK;
83
84 const UID = c::STATX_UID;
86
87 const GID = c::STATX_GID;
89
90 const ATIME = c::STATX_ATIME;
92
93 const MTIME = c::STATX_MTIME;
95
96 const CTIME = c::STATX_CTIME;
98
99 const INO = c::STATX_INO;
101
102 const SIZE = c::STATX_SIZE;
104
105 const BLOCKS = c::STATX_BLOCKS;
107
108 const BASIC_STATS = c::STATX_BASIC_STATS;
110
111 const BTIME = c::STATX_BTIME;
113
114 const MNT_ID = c::STATX_MNT_ID;
116
117 const DIOALIGN = c::STATX_DIOALIGN;
119
120 const ALL = c::STATX_ALL;
122
123 const _ = !0;
125 }
126}
127
128bitflags! {
129 #[repr(transparent)]
131 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
132 pub struct StatxAttributes: u64 {
133 const COMPRESSED = c::STATX_ATTR_COMPRESSED as u64;
135
136 const IMMUTABLE = c::STATX_ATTR_IMMUTABLE as u64;
138
139 const APPEND = c::STATX_ATTR_APPEND as u64;
141
142 const NODUMP = c::STATX_ATTR_NODUMP as u64;
144
145 const ENCRYPTED = c::STATX_ATTR_ENCRYPTED as u64;
147
148 const AUTOMOUNT = c::STATX_ATTR_AUTOMOUNT as u64;
150
151 const MOUNT_ROOT = c::STATX_ATTR_MOUNT_ROOT as u64;
153
154 const VERITY = c::STATX_ATTR_VERITY as u64;
156
157 const DAX = c::STATX_ATTR_DAX as u64;
159
160 const _ = !0;
162 }
163}
164
165#[inline]
206pub fn statx<P: path::Arg, Fd: AsFd>(
207 dirfd: Fd,
208 path: P,
209 flags: AtFlags,
210 mask: StatxFlags,
211) -> io::Result<Statx> {
212 path.into_with_c_str(|path| _statx(dirfd.as_fd(), path, flags, mask))
213}
214
215#[cfg(not(feature = "linux_4_11"))]
216mod compat {
217 use crate::fd::BorrowedFd;
218 use crate::ffi::CStr;
219 use crate::fs::{AtFlags, Statx, StatxFlags};
220 use crate::{backend, io};
221 use core::sync::atomic::{AtomicU8, Ordering};
222
223 static STATX_STATE: AtomicU8 = AtomicU8::new(0);
231
232 #[inline]
233 pub fn statx(
234 dirfd: BorrowedFd<'_>,
235 path: &CStr,
236 flags: AtFlags,
237 mask: StatxFlags,
238 ) -> io::Result<Statx> {
239 match STATX_STATE.load(Ordering::Relaxed) {
240 0 => statx_init(dirfd, path, flags, mask),
241 1 => Err(io::Errno::NOSYS),
242 _ => backend::fs::syscalls::statx(dirfd, path, flags, mask),
243 }
244 }
245
246 fn statx_init(
248 dirfd: BorrowedFd<'_>,
249 path: &CStr,
250 flags: AtFlags,
251 mask: StatxFlags,
252 ) -> io::Result<Statx> {
253 match backend::fs::syscalls::statx(dirfd, path, flags, mask) {
254 Err(err) => statx_error(err),
255 result => {
256 STATX_STATE.store(2, Ordering::Relaxed);
257 result
258 }
259 }
260 }
261
262 #[cold]
266 fn statx_error(err: io::Errno) -> io::Result<Statx> {
267 if backend::fs::syscalls::is_statx_available() {
268 STATX_STATE.store(2, Ordering::Relaxed);
271 Err(err)
272 } else {
273 STATX_STATE.store(1, Ordering::Relaxed);
275 Err(io::Errno::NOSYS)
276 }
277 }
278}