Skip to content

Commit c787fe3

Browse files
committed
Fix check of statx
1 parent 10f12fe commit c787fe3

File tree

1 file changed

+34
-16
lines changed

1 file changed

+34
-16
lines changed

src/libstd/sys/unix/fs.rs

+34-16
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,14 @@ cfg_has_statx! {{
105105
flags: i32,
106106
mask: u32,
107107
) -> Option<io::Result<FileAttr>> {
108-
use crate::sync::atomic::{AtomicBool, Ordering};
108+
use crate::sync::atomic::{AtomicU8, Ordering};
109109

110110
// Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`
111-
// We store the availability in a global to avoid unnecessary syscalls
112-
static HAS_STATX: AtomicBool = AtomicBool::new(true);
111+
// We store the availability in global to avoid unnecessary syscalls.
112+
// 0: Unknown
113+
// 1: Not available
114+
// 2: Available
115+
static STATX_STATE: AtomicU8 = AtomicU8::new(0);
113116
syscall! {
114117
fn statx(
115118
fd: c_int,
@@ -120,21 +123,36 @@ cfg_has_statx! {{
120123
) -> c_int
121124
}
122125

123-
if !HAS_STATX.load(Ordering::Relaxed) {
124-
return None;
125-
}
126-
127-
let mut buf: libc::statx = mem::zeroed();
128-
let ret = cvt(statx(fd, path, flags, mask, &mut buf));
129-
match ret {
130-
Err(err) => match err.raw_os_error() {
131-
Some(libc::ENOSYS) => {
132-
HAS_STATX.store(false, Ordering::Relaxed);
133-
return None;
126+
match STATX_STATE.load(Ordering::Relaxed) {
127+
// For the first time, we try to call on current working directory
128+
// to check if it is available.
129+
0 => {
130+
let mut buf: libc::statx = mem::zeroed();
131+
let err = cvt(statx(
132+
libc::AT_FDCWD,
133+
b".\0".as_ptr().cast(),
134+
0,
135+
libc::STATX_ALL,
136+
&mut buf,
137+
))
138+
.err()
139+
.and_then(|e| e.raw_os_error());
140+
// `seccomp` will emit `EPERM` on denied syscall.
141+
// See: https://github.com/rust-lang/rust/issues/65662
142+
if err == Some(libc::ENOSYS) || err == Some(libc::EPERM) {
143+
STATX_STATE.store(1, Ordering::Relaxed);
144+
} else {
145+
STATX_STATE.store(2, Ordering::Relaxed);
134146
}
135-
_ => return Some(Err(err)),
147+
try_statx(fd, path, flags, mask)
136148
}
137-
Ok(_) => {
149+
1 => None,
150+
_ => {
151+
let mut buf: libc::statx = mem::zeroed();
152+
if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) {
153+
return Some(Err(err));
154+
}
155+
138156
// We cannot fill `stat64` exhaustively because of private padding fields.
139157
let mut stat: stat64 = mem::zeroed();
140158
// `c_ulong` on gnu-mips, `dev_t` otherwise

0 commit comments

Comments
 (0)