@@ -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