Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use statx on Linux #61386

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/libstd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
64 changes: 47 additions & 17 deletions src/libstd/os/linux/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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`].
Expand Down Expand Up @@ -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
}
}
122 changes: 118 additions & 4 deletions src/libstd/sys/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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<SystemTime> {
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<SystemTime> {
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<SystemTime> {
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<SystemTime> {
Expand All @@ -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<SystemTime> {
Ok(SystemTime::from(libc::timespec {
Expand Down Expand Up @@ -169,10 +210,16 @@ impl FileAttr {
}
}

#[cfg(not(target_os = "linux"))]
impl AsInner<stat64> for FileAttr {
fn as_inner(&self) -> &stat64 { &self.stat }
}

#[cfg(target_os = "linux")]
impl AsInner<statx> 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
Expand Down Expand Up @@ -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<FileAttr> {
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<FileAttr> {
let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?;
let mut stat: stat64 = unsafe { mem::zeroed() };
Expand Down Expand Up @@ -513,6 +576,7 @@ impl File {
Ok(File(fd))
}

#[cfg(not(target_os = "linux"))]
pub fn file_attr(&self) -> io::Result<FileAttr> {
let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
Expand All @@ -521,6 +585,22 @@ impl File {
Ok(FileAttr { stat })
}

#[cfg(target_os = "linux")]
pub fn file_attr(&self) -> io::Result<FileAttr> {
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(());
Expand Down Expand Up @@ -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<FileAttr> {
let p = cstr(p)?;
let mut stat: stat64 = unsafe { mem::zeroed() };
Expand All @@ -796,6 +877,23 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> {
Ok(FileAttr { stat })
}

#[cfg(target_os = "linux")]
pub fn stat(p: &Path) -> io::Result<FileAttr> {
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<FileAttr> {
let p = cstr(p)?;
let mut stat: stat64 = unsafe { mem::zeroed() };
Expand All @@ -805,6 +903,22 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
Ok(FileAttr { stat })
}

#[cfg(target_os = "linux")]
pub fn lstat(p: &Path) -> io::Result<FileAttr> {
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<PathBuf> {
let path = CString::new(p.as_os_str().as_bytes())?;
let buf;
Expand Down