diff options
| author | bors <bors@rust-lang.org> | 2019-10-25 11:13:30 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-10-25 11:13:30 +0000 |
| commit | 23f890f10202a71168c6424da0cdf94135d3c40c (patch) | |
| tree | 8d77ecdc401e9ae082a217c707d933ecd197708b /src/libstd/sys | |
| parent | 85943fd7c88ddf870b03afdd6cd6782721c348e1 (diff) | |
| parent | c0bbb4bcdce880711c13b535fc4d9cd369741782 (diff) | |
| download | rust-23f890f10202a71168c6424da0cdf94135d3c40c.tar.gz rust-23f890f10202a71168c6424da0cdf94135d3c40c.zip | |
Auto merge of #65804 - Centril:rollup-arlxgch, r=Centril
Rollup of 9 pull requests Successful merges: - #64639 (Stabilize `#[non_exhaustive]` (RFC 2008)) - #65074 (Fix the start/end byte positions in the compiler JSON output) - #65315 (Intern place projection) - #65685 (Fix check of `statx` and handle EPERM) - #65731 (Prevent unnecessary allocation in PathBuf::set_extension.) - #65740 (Fix default "disable-shortcuts" feature value) - #65787 (move panictry! to where it is used.) - #65789 (move Attribute::with_desugared_doc to librustdoc) - #65790 (move report_invalid_macro_expansion_item to item.rs) Failed merges: r? @ghost
Diffstat (limited to 'src/libstd/sys')
| -rw-r--r-- | src/libstd/sys/unix/fs.rs | 97 |
1 files changed, 55 insertions, 42 deletions
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 39cc120594a..5e1f10c03ce 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -105,11 +105,14 @@ cfg_has_statx! {{ flags: i32, mask: u32, ) -> Option<io::Result<FileAttr>> { - 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,50 +123,60 @@ cfg_has_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); + match STATX_STATE.load(Ordering::Relaxed) { + 0 => { + // It is a trick to call `statx` with NULL pointers to check if the syscall + // is available. According to the manual, it is expected to fail with EFAULT. + // We do this mainly for performance, since it is nearly hundreds times + // faster than a normal successfull call. + let err = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut())) + .err() + .and_then(|e| e.raw_os_error()); + // We don't check `err == Some(libc::ENOSYS)` because the syscall may be limited + // and returns `EPERM`. Listing all possible errors seems not a good idea. + // See: https://github.com/rust-lang/rust/issues/65662 + if err != Some(libc::EFAULT) { + STATX_STATE.store(1, Ordering::Relaxed); return None; } - _ => return Some(Err(err)), + STATX_STATE.store(2, Ordering::Relaxed); } - Ok(_) => { - // We cannot fill `stat64` exhaustively because of private padding fields. - let mut stat: stat64 = mem::zeroed(); - // `c_ulong` on gnu-mips, `dev_t` otherwise - stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; - stat.st_ino = buf.stx_ino as libc::ino64_t; - stat.st_nlink = buf.stx_nlink as libc::nlink_t; - stat.st_mode = buf.stx_mode as libc::mode_t; - stat.st_uid = buf.stx_uid as libc::uid_t; - stat.st_gid = buf.stx_gid as libc::gid_t; - stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; - stat.st_size = buf.stx_size as off64_t; - stat.st_blksize = buf.stx_blksize as libc::blksize_t; - stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; - stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; - // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. - stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; - stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; - stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; - stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; - stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; - - let extra = StatxExtraFields { - stx_mask: buf.stx_mask, - stx_btime: buf.stx_btime, - }; + 1 => return None, + _ => {} + } - Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) - } + 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 + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; + stat.st_ino = buf.stx_ino as libc::ino64_t; + stat.st_nlink = buf.stx_nlink as libc::nlink_t; + stat.st_mode = buf.stx_mode as libc::mode_t; + stat.st_uid = buf.stx_uid as libc::uid_t; + stat.st_gid = buf.stx_gid as libc::gid_t; + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; + stat.st_size = buf.stx_size as off64_t; + stat.st_blksize = buf.stx_blksize as libc::blksize_t; + stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; + stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; + // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. + stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; + stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; + stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; + + let extra = StatxExtraFields { + stx_mask: buf.stx_mask, + stx_btime: buf.stx_btime, + }; + + Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) } } else { |
