未验证 提交 15cb3e08 编写于 作者: O oxalica

Fix cfgs for current libc

上级 43f398be
......@@ -41,88 +41,137 @@
pub struct File(FileDesc);
#[derive(Clone)]
pub struct FileAttr {
stat: stat64,
#[cfg(target_os = "linux")]
statx_extra_fields: Option<StatxExtraFields>,
}
#[cfg(target_os = "linux")]
#[derive(Clone)]
struct StatxExtraFields {
// This is needed to check if btime is supported by the filesystem.
stx_mask: u32,
stx_btime: libc::statx_timestamp,
// 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)*
}
};
}
// We prefer `statx` on Linux if available, which contains file creation time.
// Default `stat64` contains no creation time.
#[cfg(target_os = "linux")]
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};
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
}
// 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;
}
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,
};
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;
Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
}
_ => return Some(Err(err)),
}
Ok(_) => {
// We cannot fill `stat64` exhaustively because of private padding fields.
let mut stat: stat64 = mem::zeroed();
stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor);
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);
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;
stat.st_atime_nsec = buf.stx_atime.tv_nsec as libc::c_long;
stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t;
stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as libc::c_long;
stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t;
stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as libc::c_long;
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,
}
}
}}
// all DirEntry's will have a reference to this struct
struct InnerReadDir {
......@@ -175,15 +224,21 @@ pub struct FileType { mode: mode_t }
#[derive(Debug)]
pub struct DirBuilder { mode: mode_t }
impl FileAttr {
fn from_stat64(stat: stat64) -> Self {
Self {
stat,
#[cfg(target_os = "linux")]
statx_extra_fields: None,
cfg_has_statx! {{
impl FileAttr {
fn from_stat64(stat: stat64) -> Self {
Self { stat, statx_extra_fields: None }
}
}
} else {
impl FileAttr {
fn from_stat64(stat: stat64) -> Self {
Self { stat }
}
}
}}
impl FileAttr {
pub fn size(&self) -> u64 { self.stat.st_size as u64 }
pub fn perm(&self) -> FilePermissions {
FilePermissions { mode: (self.stat.st_mode as mode_t) }
......@@ -250,8 +305,7 @@ pub fn created(&self) -> io::Result<SystemTime> {
target_os = "macos",
target_os = "ios")))]
pub fn created(&self) -> io::Result<SystemTime> {
#[cfg(target_os = "linux")]
{
cfg_has_statx! {
if let Some(ext) = &self.statx_extra_fields {
return if (ext.stx_mask & libc::STATX_BTIME) != 0 {
Ok(SystemTime::from(libc::timespec {
......@@ -412,8 +466,7 @@ pub fn metadata(&self) -> io::Result<FileAttr> {
let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?;
let name = self.entry.d_name.as_ptr();
#[cfg(target_os = "linux")]
{
cfg_has_statx! {
if let Some(ret) = unsafe { try_statx(
fd,
name,
......@@ -636,8 +689,7 @@ fn ensure_cloexec(_: &FileDesc) -> io::Result<()> {
pub fn file_attr(&self) -> io::Result<FileAttr> {
let fd = self.0.raw();
#[cfg(target_os = "linux")]
{
cfg_has_statx! {
if let Some(ret) = unsafe { try_statx(
fd,
b"\0" as *const _ as *const libc::c_char,
......@@ -930,8 +982,7 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
pub fn stat(p: &Path) -> io::Result<FileAttr> {
let p = cstr(p)?;
#[cfg(target_os = "linux")]
{
cfg_has_statx! {
if let Some(ret) = unsafe { try_statx(
libc::AT_FDCWD,
p.as_ptr(),
......@@ -952,8 +1003,7 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> {
pub fn lstat(p: &Path) -> io::Result<FileAttr> {
let p = cstr(p)?;
#[cfg(target_os = "linux")]
{
cfg_has_statx! {
if let Some(ret) = unsafe { try_statx(
libc::AT_FDCWD,
p.as_ptr(),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册