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
use crate::fs::{FollowSymlinks, Metadata, MetadataExt};
use rustix::fs::{statat, AtFlags};
use std::path::Path;
use std::{fs, io};
#[cfg(any(target_os = "android", target_os = "linux"))]
use rustix::fs::{statx, StatxFlags};
#[cfg(any(target_os = "android", target_os = "linux"))]
use std::sync::atomic::{AtomicU8, Ordering};
pub(crate) fn stat_unchecked(
start: &fs::File,
path: &Path,
follow: FollowSymlinks,
) -> io::Result<Metadata> {
let atflags = match follow {
FollowSymlinks::Yes => AtFlags::empty(),
FollowSymlinks::No => AtFlags::SYMLINK_NOFOLLOW,
};
#[cfg(any(target_os = "android", target_os = "linux"))]
{
static STATX_STATE: AtomicU8 = AtomicU8::new(0);
let state = STATX_STATE.load(Ordering::Relaxed);
if state != 1 {
let statx_result = statx(
start,
path,
atflags,
StatxFlags::BASIC_STATS | StatxFlags::BTIME,
);
match statx_result {
Ok(statx) => {
if state == 0 {
STATX_STATE.store(2, Ordering::Relaxed);
}
return Ok(MetadataExt::from_rustix_statx(statx));
}
Err(rustix::io::Errno::NOSYS) => STATX_STATE.store(1, Ordering::Relaxed),
Err(rustix::io::Errno::PERM) if state == 0 => {
if let Err(rustix::io::Errno::PERM) = statx(
rustix::fs::cwd(),
"",
AtFlags::EMPTY_PATH,
StatxFlags::empty(),
) {
STATX_STATE.store(1, Ordering::Relaxed);
} else {
return Err(rustix::io::Errno::PERM.into());
}
}
Err(e) => return Err(e.into()),
}
}
}
Ok(statat(start, path, atflags).map(MetadataExt::from_rustix)?)
}