@@ -105,11 +105,14 @@ cfg_has_statx! {{
105
105
flags: i32 ,
106
106
mask: u32 ,
107
107
) -> Option <io:: Result <FileAttr >> {
108
- use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
108
+ use crate :: sync:: atomic:: { AtomicU8 , Ordering } ;
109
109
110
110
// 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 ) ;
113
116
syscall! {
114
117
fn statx(
115
118
fd: c_int,
@@ -120,21 +123,36 @@ cfg_has_statx! {{
120
123
) -> c_int
121
124
}
122
125
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 ) ;
134
146
}
135
- _ => return Some ( Err ( err ) ) ,
147
+ try_statx ( fd , path , flags , mask )
136
148
}
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
+
138
156
// We cannot fill `stat64` exhaustively because of private padding fields.
139
157
let mut stat: stat64 = mem:: zeroed( ) ;
140
158
// `c_ulong` on gnu-mips, `dev_t` otherwise
0 commit comments