@@ -124,64 +124,59 @@ cfg_has_statx! {{
124
124
}
125
125
126
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
127
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
- ) )
128
+ // It is a trick to call `statx` with NULL pointers to check if the syscall
129
+ // is available. According to the manual, it is expected to fail with EFAULT.
130
+ // We do this mainly for performance, since it is nearly hundreds times
131
+ // faster than a normal successfull call.
132
+ let err = cvt( statx( 0 , ptr:: null( ) , 0 , libc:: STATX_ALL , ptr:: null_mut( ) ) )
138
133
. err( )
139
134
. and_then( |e| e. raw_os_error( ) ) ;
140
- // `seccomp` will emit `EPERM` on denied syscall.
135
+ // We don't check `err == Some(libc::ENOSYS)` because the syscall may be limited
136
+ // and returns `EPERM`. Listing all possible errors seems not a good idea.
141
137
// See: https://github.com/rust-lang/rust/issues/65662
142
- if err == Some ( libc:: ENOSYS ) || err == Some ( libc :: EPERM ) {
138
+ if err != Some ( libc:: EFAULT ) {
143
139
STATX_STATE . store( 1 , Ordering :: Relaxed ) ;
144
- } else {
145
- STATX_STATE . store( 2 , Ordering :: Relaxed ) ;
140
+ return None ;
146
141
}
147
- try_statx ( fd , path , flags , mask )
142
+ STATX_STATE . store ( 2 , Ordering :: Relaxed ) ;
148
143
}
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
-
156
- // We cannot fill `stat64` exhaustively because of private padding fields.
157
- let mut stat: stat64 = mem:: zeroed( ) ;
158
- // `c_ulong` on gnu-mips, `dev_t` otherwise
159
- stat. st_dev = libc:: makedev( buf. stx_dev_major, buf. stx_dev_minor) as _;
160
- stat. st_ino = buf. stx_ino as libc:: ino64_t;
161
- stat. st_nlink = buf. stx_nlink as libc:: nlink_t;
162
- stat. st_mode = buf. stx_mode as libc:: mode_t;
163
- stat. st_uid = buf. stx_uid as libc:: uid_t;
164
- stat. st_gid = buf. stx_gid as libc:: gid_t;
165
- stat. st_rdev = libc:: makedev( buf. stx_rdev_major, buf. stx_rdev_minor) as _;
166
- stat. st_size = buf. stx_size as off64_t;
167
- stat. st_blksize = buf. stx_blksize as libc:: blksize_t;
168
- stat. st_blocks = buf. stx_blocks as libc:: blkcnt64_t;
169
- stat. st_atime = buf. stx_atime. tv_sec as libc:: time_t;
170
- // `i64` on gnu-x86_64-x32, `c_ulong` otherwise.
171
- stat. st_atime_nsec = buf. stx_atime. tv_nsec as _;
172
- stat. st_mtime = buf. stx_mtime. tv_sec as libc:: time_t;
173
- stat. st_mtime_nsec = buf. stx_mtime. tv_nsec as _;
174
- stat. st_ctime = buf. stx_ctime. tv_sec as libc:: time_t;
175
- stat. st_ctime_nsec = buf. stx_ctime. tv_nsec as _;
176
-
177
- let extra = StatxExtraFields {
178
- stx_mask: buf. stx_mask,
179
- stx_btime: buf. stx_btime,
180
- } ;
144
+ 1 => return None ,
145
+ _ => { }
146
+ }
181
147
182
- Some ( Ok ( FileAttr { stat, statx_extra_fields: Some ( extra) } ) )
183
- }
148
+ let mut buf: libc:: statx = mem:: zeroed( ) ;
149
+ if let Err ( err) = cvt( statx( fd, path, flags, mask, & mut buf) ) {
150
+ return Some ( Err ( err) ) ;
184
151
}
152
+
153
+ // We cannot fill `stat64` exhaustively because of private padding fields.
154
+ let mut stat: stat64 = mem:: zeroed( ) ;
155
+ // `c_ulong` on gnu-mips, `dev_t` otherwise
156
+ stat. st_dev = libc:: makedev( buf. stx_dev_major, buf. stx_dev_minor) as _;
157
+ stat. st_ino = buf. stx_ino as libc:: ino64_t;
158
+ stat. st_nlink = buf. stx_nlink as libc:: nlink_t;
159
+ stat. st_mode = buf. stx_mode as libc:: mode_t;
160
+ stat. st_uid = buf. stx_uid as libc:: uid_t;
161
+ stat. st_gid = buf. stx_gid as libc:: gid_t;
162
+ stat. st_rdev = libc:: makedev( buf. stx_rdev_major, buf. stx_rdev_minor) as _;
163
+ stat. st_size = buf. stx_size as off64_t;
164
+ stat. st_blksize = buf. stx_blksize as libc:: blksize_t;
165
+ stat. st_blocks = buf. stx_blocks as libc:: blkcnt64_t;
166
+ stat. st_atime = buf. stx_atime. tv_sec as libc:: time_t;
167
+ // `i64` on gnu-x86_64-x32, `c_ulong` otherwise.
168
+ stat. st_atime_nsec = buf. stx_atime. tv_nsec as _;
169
+ stat. st_mtime = buf. stx_mtime. tv_sec as libc:: time_t;
170
+ stat. st_mtime_nsec = buf. stx_mtime. tv_nsec as _;
171
+ stat. st_ctime = buf. stx_ctime. tv_sec as libc:: time_t;
172
+ stat. st_ctime_nsec = buf. stx_ctime. tv_nsec as _;
173
+
174
+ let extra = StatxExtraFields {
175
+ stx_mask: buf. stx_mask,
176
+ stx_btime: buf. stx_btime,
177
+ } ;
178
+
179
+ Some ( Ok ( FileAttr { stat, statx_extra_fields: Some ( extra) } ) )
185
180
}
186
181
187
182
} else {
0 commit comments