From: oxalica Date: Tue, 22 Oct 2019 04:02:32 +0000 (+0800) Subject: Fix check of `statx` X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=c787fe3c70bdb84d0c82d6c592080ca2f1d7902f;p=rust.git Fix check of `statx` --- diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 39cc120594a..54b2aee9400 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -105,11 +105,14 @@ unsafe fn try_statx( flags: i32, mask: u32, ) -> Option> { - use crate::sync::atomic::{AtomicBool, Ordering}; + use crate::sync::atomic::{AtomicU8, Ordering}; // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` - // We store the availability in a global to avoid unnecessary syscalls - static HAS_STATX: AtomicBool = AtomicBool::new(true); + // We store the availability in global to avoid unnecessary syscalls. + // 0: Unknown + // 1: Not available + // 2: Available + static STATX_STATE: AtomicU8 = AtomicU8::new(0); syscall! { fn statx( fd: c_int, @@ -120,21 +123,36 @@ fn statx( ) -> c_int } - if !HAS_STATX.load(Ordering::Relaxed) { - return None; - } - - let mut buf: libc::statx = mem::zeroed(); - let ret = cvt(statx(fd, path, flags, mask, &mut buf)); - match ret { - Err(err) => match err.raw_os_error() { - Some(libc::ENOSYS) => { - HAS_STATX.store(false, Ordering::Relaxed); - return None; + match STATX_STATE.load(Ordering::Relaxed) { + // For the first time, we try to call on current working directory + // to check if it is available. + 0 => { + let mut buf: libc::statx = mem::zeroed(); + let err = cvt(statx( + libc::AT_FDCWD, + b".\0".as_ptr().cast(), + 0, + libc::STATX_ALL, + &mut buf, + )) + .err() + .and_then(|e| e.raw_os_error()); + // `seccomp` will emit `EPERM` on denied syscall. + // See: https://github.com/rust-lang/rust/issues/65662 + if err == Some(libc::ENOSYS) || err == Some(libc::EPERM) { + STATX_STATE.store(1, Ordering::Relaxed); + } else { + STATX_STATE.store(2, Ordering::Relaxed); } - _ => return Some(Err(err)), + try_statx(fd, path, flags, mask) } - Ok(_) => { + 1 => None, + _ => { + let mut buf: libc::statx = mem::zeroed(); + if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) { + return Some(Err(err)); + } + // We cannot fill `stat64` exhaustively because of private padding fields. let mut stat: stat64 = mem::zeroed(); // `c_ulong` on gnu-mips, `dev_t` otherwise