From 33460111eebc29015b5c7cea0f9346256ab75c14 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Fri, 31 May 2019 02:10:49 +0200 Subject: [PATCH] Use statx on Linux, without support for glibc < 2.28 for now --- src/libstd/Cargo.toml | 3 +- src/libstd/os/linux/fs.rs | 64 ++++++++++++++------ src/libstd/sys/unix/fs.rs | 122 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 167 insertions(+), 22 deletions(-) diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index d22dc9a71a40f..5bdb6d8ac6622 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -18,7 +18,8 @@ alloc = { path = "../liballoc" } panic_unwind = { path = "../libpanic_unwind", optional = true } panic_abort = { path = "../libpanic_abort" } core = { path = "../libcore" } -libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] } +# libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] } +libc = { git = "https://github.com/rust-lang/libc", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.15" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs index ec5e98370768d..b184ddb285bef 100644 --- a/src/libstd/os/linux/fs.rs +++ b/src/libstd/os/linux/fs.rs @@ -72,6 +72,10 @@ pub trait MetadataExt { /// Ok(()) /// } /// ``` + #[unstable(feature = "metadata_linux_statx", issue = "59743")] + fn st_dev_major(&self) -> u32; + #[unstable(feature = "metadata_linux_statx", issue = "59743")] + fn st_dev_minor(&self) -> u32; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ino(&self) -> u64; /// Returns the file type and mode. @@ -177,6 +181,10 @@ pub trait MetadataExt { /// Ok(()) /// } /// ``` + #[unstable(feature = "metadata_linux_statx", issue = "59743")] + fn st_rdev_major(&self) -> u32; + #[unstable(feature = "metadata_linux_statx", issue = "59743")] + fn st_rdev_minor(&self) -> u32; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_size(&self) -> u64; /// Returns the last access time of the file, in seconds since Unix Epoch. @@ -230,6 +238,10 @@ pub trait MetadataExt { /// Ok(()) /// } /// ``` + #[unstable(feature = "linux_statx", issue = "59743")] + fn st_btime(&self) -> i64; + #[unstable(feature = "linux_statx", issue= "59743")] + fn st_btime_nsec(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime(&self) -> i64; /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`]. @@ -328,56 +340,74 @@ impl MetadataExt for Metadata { #[allow(deprecated)] fn as_raw_stat(&self) -> &raw::stat { unsafe { - &*(self.as_inner().as_inner() as *const libc::stat64 + &*(self.as_inner().as_inner() as *const libc::statx as *const raw::stat) } } fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 + (unsafe { libc::makedev(self.st_dev_major(), self.st_dev_minor()) }) as u64 + } + fn st_dev_major(&self) -> u32 { + self.as_inner().as_inner().stx_dev_major as u32 + } + fn st_dev_minor(&self) -> u32 { + self.as_inner().as_inner().stx_dev_minor as u32 } fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 + self.as_inner().as_inner().stx_ino as u64 } fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 + self.as_inner().as_inner().stx_mode as u32 } fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 + self.as_inner().as_inner().stx_nlink as u64 } fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 + self.as_inner().as_inner().stx_uid as u32 } fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 + self.as_inner().as_inner().stx_gid as u32 } fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 + (unsafe { libc::makedev(self.st_rdev_major(), self.st_rdev_minor()) }) as u64 + } + fn st_rdev_major(&self) -> u32 { + self.as_inner().as_inner().stx_rdev_major as u32 + } + fn st_rdev_minor(&self) -> u32 { + self.as_inner().as_inner().stx_rdev_minor as u32 } fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 + self.as_inner().as_inner().stx_size as u64 } fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 + self.as_inner().as_inner().stx_atime.tv_sec as i64 } fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 + self.as_inner().as_inner().stx_atime.tv_nsec as i64 + } + fn st_btime(&self) -> i64 { + self.as_inner().as_inner().stx_btime.tv_sec as i64 + } + fn st_btime_nsec(&self) -> i64 { + self.as_inner().as_inner().stx_btime.tv_nsec as i64 } fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 + self.as_inner().as_inner().stx_mtime.tv_sec as i64 } fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 + self.as_inner().as_inner().stx_mtime.tv_nsec as i64 } fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 + self.as_inner().as_inner().stx_ctime.tv_sec as i64 } fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 + self.as_inner().as_inner().stx_ctime.tv_nsec as i64 } fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 + self.as_inner().as_inner().stx_blksize as u64 } fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 + self.as_inner().as_inner().stx_blocks as u64 } } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index cc1f0790d4334..18b8ee63a1d31 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -14,9 +14,13 @@ use crate::sys_common::{AsInner, FromInner}; use libc::{c_int, mode_t}; +#[cfg(target_os = "linux")] +use libc::statx; +#[cfg(any(target_os = "emscripten", target_os = "l4re"))] +use libc::{stat64, fstat64, lstat64}; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] -use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; -#[cfg(any(target_os = "linux", target_os = "emscripten"))] +use libc::{off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; +#[cfg(target_os = "emscripten")] use libc::fstatat64; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] use libc::dirfd; @@ -42,7 +46,10 @@ pub struct File(FileDesc); #[derive(Clone)] pub struct FileAttr { + #[cfg(not(target_os = "linux"))] stat: stat64, + #[cfg(target_os = "linux")] + stat: statx, } // all DirEntry's will have a reference to this struct @@ -96,6 +103,7 @@ pub struct FileType { mode: mode_t } #[derive(Debug)] pub struct DirBuilder { mode: mode_t } +#[cfg(not(target_os = "linux"))] impl FileAttr { pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { @@ -107,6 +115,39 @@ impl FileAttr { } } +#[cfg(target_os = "linux")] +impl FileAttr { + pub fn size(&self) -> u64 { self.stat.stx_size as u64 } + pub fn perm(&self) -> FilePermissions { + FilePermissions { mode: (self.stat.stx_mode as mode_t) } + } + + pub fn file_type(&self) -> FileType { + FileType { mode: self.stat.stx_mode as mode_t } + } + + pub fn modified(&self) -> io::Result { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.stx_mtime.tv_sec as libc::time_t, + tv_nsec: self.stat.stx_mtime.tv_nsec as _, + })) + } + + pub fn accessed(&self) -> io::Result { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.stx_atime.tv_sec as libc::time_t, + tv_nsec: self.stat.stx_atime.tv_nsec as _, + })) + } + + pub fn created(&self) -> io::Result { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.stx_btime.tv_sec as libc::time_t, + tv_nsec: self.stat.stx_btime.tv_nsec as _, + })) + } +} + #[cfg(target_os = "netbsd")] impl FileAttr { pub fn modified(&self) -> io::Result { @@ -131,7 +172,7 @@ impl FileAttr { } } -#[cfg(not(target_os = "netbsd"))] +#[cfg(not(any(target_os = "netbsd", target_os = "linux")))] impl FileAttr { pub fn modified(&self) -> io::Result { Ok(SystemTime::from(libc::timespec { @@ -169,10 +210,16 @@ impl FileAttr { } } +#[cfg(not(target_os = "linux"))] impl AsInner for FileAttr { fn as_inner(&self) -> &stat64 { &self.stat } } +#[cfg(target_os = "linux")] +impl AsInner for FileAttr { + fn as_inner(&self) -> &statx { &self.stat } +} + impl FilePermissions { pub fn readonly(&self) -> bool { // check if any class (owner, group, others) has write permission @@ -303,7 +350,23 @@ impl DirEntry { OsStr::from_bytes(self.name_bytes()).to_os_string() } - #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] + #[cfg(target_os = "linux")] + pub fn metadata(&self) -> io::Result { + let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; + let mut stat: statx = unsafe { mem::zeroed() }; + cvt(unsafe { + statx( + fd, + self.entry.d_name.as_ptr(), + libc::AT_SYMLINK_NOFOLLOW, + libc::STATX_ALL, + &mut stat + ) + })?; + Ok(FileAttr { stat }) + } + + #[cfg(any(target_os = "emscripten", target_os = "android"))] pub fn metadata(&self) -> io::Result { let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; let mut stat: stat64 = unsafe { mem::zeroed() }; @@ -513,6 +576,7 @@ impl File { Ok(File(fd)) } + #[cfg(not(target_os = "linux"))] pub fn file_attr(&self) -> io::Result { let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { @@ -521,6 +585,22 @@ impl File { Ok(FileAttr { stat }) } + #[cfg(target_os = "linux")] + pub fn file_attr(&self) -> io::Result { + let mut stat: statx = unsafe { mem::zeroed() }; + cvt(unsafe { + statx( + self.0.raw(), + // empty_path.as_ptr() as *const libc::c_char, + &0i8 as *const libc::c_char, + libc::AT_SYMLINK_NOFOLLOW, + libc::STATX_ALL, + &mut stat + ) + })?; + Ok(FileAttr { stat }) + } + pub fn fsync(&self) -> io::Result<()> { cvt_r(|| unsafe { os_fsync(self.0.raw()) })?; return Ok(()); @@ -787,6 +867,7 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { Ok(()) } +#[cfg(not(target_os = "linux"))] pub fn stat(p: &Path) -> io::Result { let p = cstr(p)?; let mut stat: stat64 = unsafe { mem::zeroed() }; @@ -796,6 +877,23 @@ pub fn stat(p: &Path) -> io::Result { Ok(FileAttr { stat }) } +#[cfg(target_os = "linux")] +pub fn stat(p: &Path) -> io::Result { + let p = cstr(p)?; + let mut stat: statx = unsafe { mem::zeroed() }; + cvt(unsafe { + statx( + 0, + p.as_ptr(), + 0, + libc::STATX_ALL, + &mut stat + ) + })?; + Ok(FileAttr { stat }) +} + +#[cfg(not(target_os = "linux"))] pub fn lstat(p: &Path) -> io::Result { let p = cstr(p)?; let mut stat: stat64 = unsafe { mem::zeroed() }; @@ -805,6 +903,22 @@ pub fn lstat(p: &Path) -> io::Result { Ok(FileAttr { stat }) } +#[cfg(target_os = "linux")] +pub fn lstat(p: &Path) -> io::Result { + let p = cstr(p)?; + let mut stat: statx = unsafe { mem::zeroed() }; + cvt(unsafe { + statx( + 0, + p.as_ptr(), + libc::AT_SYMLINK_NOFOLLOW, + libc::STATX_ALL, + &mut stat + ) + })?; + Ok(FileAttr { stat }) +} + pub fn canonicalize(p: &Path) -> io::Result { let path = CString::new(p.as_os_str().as_bytes())?; let buf;