pub struct File(FileDesc); <del> #[derive(Clone)] pub struct FileAttr { stat: stat64, </del> <ins> // FIXME: This should be available on Linux with all `target_arch` and `target_env`. // https://github.com/rust-lang/libc/issues/1545 macro_rules! cfg_has_statx { ({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => { cfg_if::cfg_if! { if #[cfg(all(target_os = "linux", target_env = "gnu", any( target_arch = "x86", target_arch = "arm", // target_arch = "mips", target_arch = "powerpc", target_arch = "x86_64", // target_arch = "aarch64", target_arch = "powerpc64", // target_arch = "mips64", // target_arch = "s390x", target_arch = "sparc64", )))] { $($then_tt)* } else { $($else_tt)* } } }; ($($block_inner:tt)*) => { #[cfg(all(target_os = "linux", target_env = "gnu", any( target_arch = "x86", target_arch = "arm", // target_arch = "mips", target_arch = "powerpc", target_arch = "x86_64", // target_arch = "aarch64", target_arch = "powerpc64", // target_arch = "mips64", // target_arch = "s390x", target_arch = "sparc64", )))] { $($block_inner)* } }; </ins> } <ins> cfg_has_statx! {{ #[derive(Clone)] pub struct FileAttr { stat: stat64, statx_extra_fields: Option<StatxExtraFields>, } #[derive(Clone)] struct StatxExtraFields { // This is needed to check if btime is supported by the filesystem. stx_mask: u32, stx_btime: libc::statx_timestamp, } // We prefer `statx` on Linux if available, which contains file creation time. // Default `stat64` contains no creation time. unsafe fn try_statx( fd: c_int, path: *const libc::c_char, flags: i32, mask: u32, ) -> Option<io::Result<FileAttr>> { use crate::sync::atomic::{AtomicBool, 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); syscall! { fn statx( fd: c_int, pathname: *const libc::c_char, flags: c_int, mask: libc::c_uint, statxbuf: *mut libc::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; } _ => return Some(Err(err)), } 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, }; Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) } } } } else { #[derive(Clone)] pub struct FileAttr { stat: stat64, } }} </ins> // all DirEntry's will have a reference to this struct struct InnerReadDir { dirp: Dir,