-
Notifications
You must be signed in to change notification settings - Fork 645
/
statx.rs
346 lines (308 loc) · 11.6 KB
/
statx.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
use std::{mem, os::unix::prelude::RawFd};
use libc::{self, c_int, c_uint, mode_t};
use crate::{errno::Errno, NixPath, Result, sys::stat::{SFlag, Mode}, unistd::{Uid, Gid}, sys::time::TimeSpec};
libc_bitflags!(
/// Configuration options for statx.
pub struct Flags: c_int {
/// Allow empty `pathname`, to receive status of the specified file descriptor
/// itself (not a directory entry) instead.
AT_EMPTY_PATH;
/// Do not automount the last component of the path being queried.
AT_NO_AUTOMOUNT;
/// Do not follow symlink in the last component of the path being queried.
AT_SYMLINK_NOFOLLOW;
/// Do whatever usual, non-`x` stat does. The default.
AT_STATX_SYNC_AS_STAT;
/// Force returned attributes to be up to date (synchonized).
/// May trigger data writeback.
/// May involve additional roudtrips for networked filesystems.
AT_STATX_FORCE_SYNC;
/// Don't synchronize, use cached data if possible. This may lead to the
/// returned data to be approximate.
AT_STATX_DONT_SYNC;
}
);
libc_bitflags!(
/// Configuration options for statx.
pub struct Mask: c_uint {
/// Want stx_mode & S_IFMT
STATX_TYPE;
/// Want stx_mode & ~S_IFMT
STATX_MODE;
/// Want stx_nlink
STATX_NLINK;
/// Want stx_uid
STATX_UID;
/// Want stx_gid
STATX_GID;
/// Want stx_atime
STATX_ATIME;
/// Want stx_mtime
STATX_MTIME;
/// Want stx_ctime
STATX_CTIME;
/// Want stx_ino
STATX_INO;
/// Want stx_size
STATX_SIZE;
/// Want stx_blocks
STATX_BLOCKS;
/// [All of the above]
STATX_BASIC_STATS;
/// Want stx_btime
STATX_BTIME;
/// Want stx_mnt_id (since Linux 5.8);
STATX_MNT_ID;
/// [All currently available fields]
STATX_ALL;
}
);
/// Attempt to retrieve stats of `pathname`. If `pathname` is relative, `dirfd`
/// is used as starting directory for lookups. If `dirfd` is None, current
/// directory is used.
/// `pathname` may be empty string. But instead of specifying empty string
/// literal, you are adviced to use zero-terminated `CStr` to avoid extra allocation
/// `mask` determines what stats entries should be filled in, but kernel
/// can actually fill more or less than requested.
/// `statx` is not atomic: if attributes are being changed at the time of
/// `statx` is called, the returned attributes set may have items from
/// different moments of time.
pub fn statx<P: ?Sized + NixPath>(
dirfd: Option<RawFd>,
pathname: &P,
flags: Flags,
mask: Mask,
) -> Result<Statx> {
let dirfd = dirfd.unwrap_or(libc::AT_FDCWD);
let mut dst = mem::MaybeUninit::uninit();
let res = pathname.with_nix_path(|cstr| unsafe {
libc::statx(
dirfd,
cstr.as_ptr(),
flags.bits() as libc::c_int,
mask.bits() as libc::c_uint,
dst.as_mut_ptr(),
)
})?;
Errno::result(res)?;
Ok(Statx ( unsafe { dst.assume_init() } ))
}
#[derive(Debug,Copy,Clone)]
pub struct Statx (pub libc::statx);
impl From<libc::statx_timestamp> for TimeSpec {
fn from(x: libc::statx_timestamp) -> Self {
TimeSpec::from_timespec(libc::timespec {
tv_sec: x.tv_sec,
tv_nsec: x.tv_nsec.into(),
})
}
}
impl Statx {
/// Retrieve file type, if it has been returned by kernel
pub fn filetype(&self) -> Option<SFlag> {
if Mask::STATX_TYPE.bits() & self.0.stx_mask > 0 {
Some(SFlag::from_bits_truncate(self.0.stx_mode as mode_t & SFlag::S_IFMT.bits()))
} else {
None
}
}
/// Retrieve file mode, if it has been returned by kernel.
pub fn mode(&self) -> Option<Mode> {
if Mask::STATX_MODE.bits() & self.0.stx_mask > 0 {
Some(Mode::from_bits_truncate(self.0.stx_mode as mode_t))
} else {
None
}
}
/// Retrieve number of hard links, if it has been returned by kernel.
pub fn nlinks(&self) -> Option<u32> {
if Mask::STATX_NLINK.bits() & self.0.stx_mask > 0 {
Some(self.0.stx_nlink)
} else {
None
}
}
/// Retrieve uid (owner, user ID), if it has been returned by kernel.
pub fn uid(&self) -> Option<Uid> {
if Mask::STATX_UID.bits() & self.0.stx_mask > 0 {
Some(Uid::from_raw(self.0.stx_uid))
} else {
None
}
}
/// Retrieve gid (group ID), if it has been returned by kernel.
pub fn gid(&self) -> Option<Gid> {
if Mask::STATX_GID.bits() & self.0.stx_mask > 0 {
Some(Gid::from_raw(self.0.stx_uid))
} else {
None
}
}
/// Retrieve file access time, if it has been returned by kernel
pub fn atime(&self) -> Option<TimeSpec> {
if Mask::STATX_ATIME.bits() & self.0.stx_mask > 0 {
Some(self.0.stx_atime.into())
} else {
None
}
}
/// Retrieve file modification time, if it has been returned by kernel
pub fn mtime(&self) -> Option<TimeSpec> {
if Mask::STATX_MTIME.bits() & self.0.stx_mask > 0 {
Some(self.0.stx_mtime.into())
} else {
None
}
}
/// Retrieve file attribute change time, if it has been returned by kernel
pub fn ctime(&self) -> Option<TimeSpec> {
if Mask::STATX_CTIME.bits() & self.0.stx_mask > 0 {
Some(self.0.stx_ctime.into())
} else {
None
}
}
/// Retrieve file birth (creation) time, if it has been returned by kernel
pub fn btime(&self) -> Option<TimeSpec> {
if Mask::STATX_BTIME.bits() & self.0.stx_mask > 0 {
Some(self.0.stx_btime.into())
} else {
None
}
}
/// Retrieve inode number, if it has been returned by kernel
pub fn ino(&self) -> Option<u64> {
if Mask::STATX_INO.bits() & self.0.stx_mask > 0 {
Some(self.0.stx_ino)
} else {
None
}
}
/// Retrieve file size, in bytes, if it has been returned by kernel
pub fn size(&self) -> Option<u64> {
if Mask::STATX_SIZE.bits() & self.0.stx_mask > 0 {
Some(self.0.stx_size)
} else {
None
}
}
/// Retrieve file size as a number of blocks, if it has been returned by kernel
pub fn blocks(&self) -> Option<u64> {
if Mask::STATX_BLOCKS.bits() & self.0.stx_mask > 0 {
Some(self.0.stx_blocks)
} else {
None
}
}
/// Retrieve size of the block (used in `blocks` function) in bytes
pub fn blksize(&self) -> Option<u32> {
// I'm not sure what exact mask bit should be used to check presence of block size.
// Actual Linux kernel seems return most of STATX_BASIC_STATS
// in one go, regarless of which things were asked for.
if Mask::STATX_BASIC_STATS.bits() & self.0.stx_mask == Mask::STATX_BASIC_STATS.bits() {
Some(self.0.stx_blksize)
} else {
None
}
}
/// Retrieve mount ID, if it has been returned by kernel
pub fn mnt_id(&self) -> Option<u64> {
if Mask::STATX_MNT_ID.bits() & self.0.stx_mask > 0 {
Some(self.0.stx_mnt_id)
} else {
None
}
}
/// Retrieve device major and minor numbers (first and second elements of the
/// tuple respectively) of the filesystem where the file resides at, if it has been returned by kernel.
pub fn dev_major_minor(&self) -> Option<(u32, u32)> {
// I'm not sure what exact mask bit should be used to check presence of this information.
// Actual Linux kernel seems return most of STATX_BASIC_STATS in one go,
// regarless of which things were asked for.
if Mask::STATX_BASIC_STATS.bits() & self.0.stx_mask == Mask::STATX_BASIC_STATS.bits() {
Some((self.0.stx_dev_major, self.0.stx_dev_minor))
} else {
None
}
}
/// Retrieve pointed-to device major and minor numbers (first and second
/// elements of the tuple respectively) of this character or block device
/// file, if it has been returned by kernel.
/// Note that this function does not check for the file type.
/// It would return `Some` even for regular files.
pub fn rdev_major_minor(&self) -> Option<(u32, u32)> {
// I'm not sure what exact mask bit should be used to check presence of this information.
// Actual Linux kernel seems return most of STATX_BASIC_STATS
// in one go, regarless of which things were asked for.
if Mask::STATX_BASIC_STATS.bits() & self.0.stx_mask == Mask::STATX_BASIC_STATS.bits() {
Some((self.0.stx_rdev_major, self.0.stx_rdev_minor))
} else {
None
}
}
/// Determine if the file is compressed. None means kernel does not
/// indicate this attrbiute is supported by the filesystem
pub fn compressed(&self) -> Option<bool> {
if self.0.stx_attributes_mask & libc::STATX_ATTR_COMPRESSED as u64 > 0 {
Some(self.0.stx_attributes & libc::STATX_ATTR_COMPRESSED as u64 > 0)
} else {
None
}
}
/// Determine if the file is immutable. None means kernel does not indicate this
/// attrbiute is supported by the filesystem
pub fn immutable(&self) -> Option<bool> {
if self.0.stx_attributes_mask & libc::STATX_ATTR_IMMUTABLE as u64 > 0 {
Some(self.0.stx_attributes & libc::STATX_ATTR_IMMUTABLE as u64 > 0)
} else {
None
}
}
/// Determine if the file is append-only. None means kernel does not indicate
/// this attrbiute is supported by the filesystem
pub fn append_only(&self) -> Option<bool> {
if self.0.stx_attributes_mask & libc::STATX_ATTR_APPEND as u64 > 0 {
Some(self.0.stx_attributes & libc::STATX_ATTR_APPEND as u64 > 0)
} else {
None
}
}
/// Determine if the file is not a candidate for a backup. None means kernel
/// does not indicate this attrbiute is supported by the filesystem
pub fn nodump(&self) -> Option<bool> {
if self.0.stx_attributes_mask & libc::STATX_ATTR_NODUMP as u64 > 0 {
Some(self.0.stx_attributes & libc::STATX_ATTR_NODUMP as u64 > 0)
} else {
None
}
}
/// Determine if the file requires a key to be encrypted(?).
/// None means kernel does not indicate this attrbiute is supported by the filesystem
pub fn encrypted(&self) -> Option<bool> {
if self.0.stx_attributes_mask & libc::STATX_ATTR_ENCRYPTED as u64 > 0 {
Some(self.0.stx_attributes & libc::STATX_ATTR_ENCRYPTED as u64 > 0)
} else {
None
}
}
/*
/// Determine if the file has fs-verify enabled. None means kernel does not
/// indicate this attrbiute is supported by the filesystem
pub fn verify_enabled(&self) -> Option<bool> {
if self.0.stx_attributes_mask & libc::STATX_ATTR_VERITY as u64 > 0 {
Some(self.0.stx_attributes & libc::STATX_ATTR_VERITY as u64 > 0)
} else {
None
}
}
/// Determine if the file is in CPU direct access state. None means kernel
/// does not indicate this attrbiute is supported by the filesystem.
pub fn dax(&self) -> Option<bool> {
if self.0.stx_attributes_mask & libc::STATX_ATTR_DAX as u64 > 0 {
Some(self.0.stx_attributes & libc::STATX_ATTR_DAX as u64 > 0)
} else {
None
}
}
*/
}