From fec4818fdb40c82679f57fa7f26fcddc1a874c13 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 9 Mar 2022 17:05:16 -0800 Subject: [PATCH] Use statx's 64-bit times on 32-bit linux-gnu --- library/std/src/os/linux/fs.rs | 21 +++++- library/std/src/sys/unix/fs.rs | 109 ++++++++++++++++++++----------- library/std/src/sys/unix/time.rs | 8 +++ 3 files changed, 97 insertions(+), 41 deletions(-) diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs index 9d18ccbeb2494..23267c44685b0 100644 --- a/library/std/src/os/linux/fs.rs +++ b/library/std/src/os/linux/fs.rs @@ -356,19 +356,34 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_size as u64 } fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 + let file_attr = self.as_inner(); + #[cfg(all(target_env = "gnu", target_pointer_width = "32"))] + if let Some(atime) = file_attr.stx_atime() { + return atime.tv_sec; + } + file_attr.as_inner().st_atime as i64 } fn st_atime_nsec(&self) -> i64 { self.as_inner().as_inner().st_atime_nsec as i64 } fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 + let file_attr = self.as_inner(); + #[cfg(all(target_env = "gnu", target_pointer_width = "32"))] + if let Some(mtime) = file_attr.stx_mtime() { + return mtime.tv_sec; + } + file_attr.as_inner().st_mtime as i64 } fn st_mtime_nsec(&self) -> i64 { self.as_inner().as_inner().st_mtime_nsec as i64 } fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 + let file_attr = self.as_inner(); + #[cfg(all(target_env = "gnu", target_pointer_width = "32"))] + if let Some(ctime) = file_attr.stx_ctime() { + return ctime.tv_sec; + } + file_attr.as_inner().st_ctime as i64 } fn st_ctime_nsec(&self) -> i64 { self.as_inner().as_inner().st_ctime_nsec as i64 diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 27fc7accdaeca..61fb2814018e0 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -113,10 +113,19 @@ cfg_has_statx! {{ // This is needed to check if btime is supported by the filesystem. stx_mask: u32, stx_btime: libc::statx_timestamp, + // With statx, we can overcome 32-bit `time_t` too. + #[cfg(target_pointer_width = "32")] + stx_atime: libc::statx_timestamp, + #[cfg(target_pointer_width = "32")] + stx_ctime: libc::statx_timestamp, + #[cfg(target_pointer_width = "32")] + stx_mtime: libc::statx_timestamp, + } - // We prefer `statx` on Linux if available, which contains file creation time. - // Default `stat64` contains no creation time. + // We prefer `statx` on Linux if available, which contains file creation time, + // as well as 64-bit timestamps of all kinds. + // Default `stat64` contains no creation time and may have 32-bit `time_t`. unsafe fn try_statx( fd: c_int, path: *const c_char, @@ -192,6 +201,13 @@ cfg_has_statx! {{ let extra = StatxExtraFields { stx_mask: buf.stx_mask, stx_btime: buf.stx_btime, + // Store full times to avoid 32-bit `time_t` truncation. + #[cfg(target_pointer_width = "32")] + stx_atime: buf.stx_atime, + #[cfg(target_pointer_width = "32")] + stx_ctime: buf.stx_ctime, + #[cfg(target_pointer_width = "32")] + stx_mtime: buf.stx_mtime, }; Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) @@ -310,6 +326,36 @@ cfg_has_statx! {{ fn from_stat64(stat: stat64) -> Self { Self { stat, statx_extra_fields: None } } + + #[cfg(target_pointer_width = "32")] + pub fn stx_mtime(&self) -> Option<&libc::statx_timestamp> { + if let Some(ext) = &self.statx_extra_fields { + if (ext.stx_mask & libc::STATX_MTIME) != 0 { + return Some(&ext.stx_mtime); + } + } + None + } + + #[cfg(target_pointer_width = "32")] + pub fn stx_atime(&self) -> Option<&libc::statx_timestamp> { + if let Some(ext) = &self.statx_extra_fields { + if (ext.stx_mask & libc::STATX_ATIME) != 0 { + return Some(&ext.stx_atime); + } + } + None + } + + #[cfg(target_pointer_width = "32")] + pub fn stx_ctime(&self) -> Option<&libc::statx_timestamp> { + if let Some(ext) = &self.statx_extra_fields { + if (ext.stx_mask & libc::STATX_CTIME) != 0 { + return Some(&ext.stx_ctime); + } + } + None + } } } else { impl FileAttr { @@ -335,24 +381,15 @@ impl FileAttr { #[cfg(target_os = "netbsd")] impl FileAttr { pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: self.stat.st_mtimensec as libc::c_long, - })) + Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtimensec as i64)) } pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: self.stat.st_atimensec as libc::c_long, - })) + Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atimensec as i64)) } pub fn created(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_birthtime as libc::time_t, - tv_nsec: self.stat.st_birthtimensec as libc::c_long, - })) + Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtimensec as i64)) } } @@ -360,34 +397,36 @@ impl FileAttr { impl FileAttr { #[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))] pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: self.stat.st_mtime_nsec as _, - })) + #[cfg(target_pointer_width = "32")] + cfg_has_statx! { + if let Some(mtime) = self.stx_mtime() { + return Ok(SystemTime::new(mtime.tv_sec, mtime.tv_nsec as i64)); + } + } + + Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64)) } #[cfg(any(target_os = "vxworks", target_os = "espidf"))] pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: 0, - })) + Ok(SystemTime::new(self.stat.st_mtime as i64, 0)) } #[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))] pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: self.stat.st_atime_nsec as _, - })) + #[cfg(target_pointer_width = "32")] + cfg_has_statx! { + if let Some(atime) = self.stx_atime() { + return Ok(SystemTime::new(atime.tv_sec, atime.tv_nsec as i64)); + } + } + + Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64)) } #[cfg(any(target_os = "vxworks", target_os = "espidf"))] pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: 0, - })) + Ok(SystemTime::new(self.stat.st_atime as i64, 0)) } #[cfg(any( @@ -397,10 +436,7 @@ impl FileAttr { target_os = "ios" ))] pub fn created(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_birthtime as libc::time_t, - tv_nsec: self.stat.st_birthtime_nsec as libc::c_long, - })) + Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64)) } #[cfg(not(any( @@ -413,10 +449,7 @@ impl FileAttr { 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 { - tv_sec: ext.stx_btime.tv_sec as libc::time_t, - tv_nsec: ext.stx_btime.tv_nsec as _, - })) + Ok(SystemTime::new(ext.stx_btime.tv_sec, ext.stx_btime.tv_nsec as i64)) } else { Err(io::const_io_error!( io::ErrorKind::Uncategorized, diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 20d061206beb5..5000e7d890b69 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -144,6 +144,10 @@ mod inner { } impl SystemTime { + pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime { + SystemTime { t: Timespec::new(tv_sec, tv_nsec) } + } + pub fn now() -> SystemTime { use crate::ptr; @@ -294,6 +298,10 @@ mod inner { } impl SystemTime { + pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime { + SystemTime { t: Timespec::new(tv_sec, tv_nsec) } + } + pub fn now() -> SystemTime { SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) } }