Skip to content

Commit fec4818

Browse files
committed
Use statx's 64-bit times on 32-bit linux-gnu
1 parent 97b49a0 commit fec4818

File tree

3 files changed

+97
-41
lines changed

3 files changed

+97
-41
lines changed

library/std/src/os/linux/fs.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -356,19 +356,34 @@ impl MetadataExt for Metadata {
356356
self.as_inner().as_inner().st_size as u64
357357
}
358358
fn st_atime(&self) -> i64 {
359-
self.as_inner().as_inner().st_atime as i64
359+
let file_attr = self.as_inner();
360+
#[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
361+
if let Some(atime) = file_attr.stx_atime() {
362+
return atime.tv_sec;
363+
}
364+
file_attr.as_inner().st_atime as i64
360365
}
361366
fn st_atime_nsec(&self) -> i64 {
362367
self.as_inner().as_inner().st_atime_nsec as i64
363368
}
364369
fn st_mtime(&self) -> i64 {
365-
self.as_inner().as_inner().st_mtime as i64
370+
let file_attr = self.as_inner();
371+
#[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
372+
if let Some(mtime) = file_attr.stx_mtime() {
373+
return mtime.tv_sec;
374+
}
375+
file_attr.as_inner().st_mtime as i64
366376
}
367377
fn st_mtime_nsec(&self) -> i64 {
368378
self.as_inner().as_inner().st_mtime_nsec as i64
369379
}
370380
fn st_ctime(&self) -> i64 {
371-
self.as_inner().as_inner().st_ctime as i64
381+
let file_attr = self.as_inner();
382+
#[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
383+
if let Some(ctime) = file_attr.stx_ctime() {
384+
return ctime.tv_sec;
385+
}
386+
file_attr.as_inner().st_ctime as i64
372387
}
373388
fn st_ctime_nsec(&self) -> i64 {
374389
self.as_inner().as_inner().st_ctime_nsec as i64

library/std/src/sys/unix/fs.rs

+71-38
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,19 @@ cfg_has_statx! {{
113113
// This is needed to check if btime is supported by the filesystem.
114114
stx_mask: u32,
115115
stx_btime: libc::statx_timestamp,
116+
// With statx, we can overcome 32-bit `time_t` too.
117+
#[cfg(target_pointer_width = "32")]
118+
stx_atime: libc::statx_timestamp,
119+
#[cfg(target_pointer_width = "32")]
120+
stx_ctime: libc::statx_timestamp,
121+
#[cfg(target_pointer_width = "32")]
122+
stx_mtime: libc::statx_timestamp,
123+
116124
}
117125

118-
// We prefer `statx` on Linux if available, which contains file creation time.
119-
// Default `stat64` contains no creation time.
126+
// We prefer `statx` on Linux if available, which contains file creation time,
127+
// as well as 64-bit timestamps of all kinds.
128+
// Default `stat64` contains no creation time and may have 32-bit `time_t`.
120129
unsafe fn try_statx(
121130
fd: c_int,
122131
path: *const c_char,
@@ -192,6 +201,13 @@ cfg_has_statx! {{
192201
let extra = StatxExtraFields {
193202
stx_mask: buf.stx_mask,
194203
stx_btime: buf.stx_btime,
204+
// Store full times to avoid 32-bit `time_t` truncation.
205+
#[cfg(target_pointer_width = "32")]
206+
stx_atime: buf.stx_atime,
207+
#[cfg(target_pointer_width = "32")]
208+
stx_ctime: buf.stx_ctime,
209+
#[cfg(target_pointer_width = "32")]
210+
stx_mtime: buf.stx_mtime,
195211
};
196212

197213
Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
@@ -310,6 +326,36 @@ cfg_has_statx! {{
310326
fn from_stat64(stat: stat64) -> Self {
311327
Self { stat, statx_extra_fields: None }
312328
}
329+
330+
#[cfg(target_pointer_width = "32")]
331+
pub fn stx_mtime(&self) -> Option<&libc::statx_timestamp> {
332+
if let Some(ext) = &self.statx_extra_fields {
333+
if (ext.stx_mask & libc::STATX_MTIME) != 0 {
334+
return Some(&ext.stx_mtime);
335+
}
336+
}
337+
None
338+
}
339+
340+
#[cfg(target_pointer_width = "32")]
341+
pub fn stx_atime(&self) -> Option<&libc::statx_timestamp> {
342+
if let Some(ext) = &self.statx_extra_fields {
343+
if (ext.stx_mask & libc::STATX_ATIME) != 0 {
344+
return Some(&ext.stx_atime);
345+
}
346+
}
347+
None
348+
}
349+
350+
#[cfg(target_pointer_width = "32")]
351+
pub fn stx_ctime(&self) -> Option<&libc::statx_timestamp> {
352+
if let Some(ext) = &self.statx_extra_fields {
353+
if (ext.stx_mask & libc::STATX_CTIME) != 0 {
354+
return Some(&ext.stx_ctime);
355+
}
356+
}
357+
None
358+
}
313359
}
314360
} else {
315361
impl FileAttr {
@@ -335,59 +381,52 @@ impl FileAttr {
335381
#[cfg(target_os = "netbsd")]
336382
impl FileAttr {
337383
pub fn modified(&self) -> io::Result<SystemTime> {
338-
Ok(SystemTime::from(libc::timespec {
339-
tv_sec: self.stat.st_mtime as libc::time_t,
340-
tv_nsec: self.stat.st_mtimensec as libc::c_long,
341-
}))
384+
Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtimensec as i64))
342385
}
343386

344387
pub fn accessed(&self) -> io::Result<SystemTime> {
345-
Ok(SystemTime::from(libc::timespec {
346-
tv_sec: self.stat.st_atime as libc::time_t,
347-
tv_nsec: self.stat.st_atimensec as libc::c_long,
348-
}))
388+
Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atimensec as i64))
349389
}
350390

351391
pub fn created(&self) -> io::Result<SystemTime> {
352-
Ok(SystemTime::from(libc::timespec {
353-
tv_sec: self.stat.st_birthtime as libc::time_t,
354-
tv_nsec: self.stat.st_birthtimensec as libc::c_long,
355-
}))
392+
Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtimensec as i64))
356393
}
357394
}
358395

359396
#[cfg(not(target_os = "netbsd"))]
360397
impl FileAttr {
361398
#[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))]
362399
pub fn modified(&self) -> io::Result<SystemTime> {
363-
Ok(SystemTime::from(libc::timespec {
364-
tv_sec: self.stat.st_mtime as libc::time_t,
365-
tv_nsec: self.stat.st_mtime_nsec as _,
366-
}))
400+
#[cfg(target_pointer_width = "32")]
401+
cfg_has_statx! {
402+
if let Some(mtime) = self.stx_mtime() {
403+
return Ok(SystemTime::new(mtime.tv_sec, mtime.tv_nsec as i64));
404+
}
405+
}
406+
407+
Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64))
367408
}
368409

369410
#[cfg(any(target_os = "vxworks", target_os = "espidf"))]
370411
pub fn modified(&self) -> io::Result<SystemTime> {
371-
Ok(SystemTime::from(libc::timespec {
372-
tv_sec: self.stat.st_mtime as libc::time_t,
373-
tv_nsec: 0,
374-
}))
412+
Ok(SystemTime::new(self.stat.st_mtime as i64, 0))
375413
}
376414

377415
#[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))]
378416
pub fn accessed(&self) -> io::Result<SystemTime> {
379-
Ok(SystemTime::from(libc::timespec {
380-
tv_sec: self.stat.st_atime as libc::time_t,
381-
tv_nsec: self.stat.st_atime_nsec as _,
382-
}))
417+
#[cfg(target_pointer_width = "32")]
418+
cfg_has_statx! {
419+
if let Some(atime) = self.stx_atime() {
420+
return Ok(SystemTime::new(atime.tv_sec, atime.tv_nsec as i64));
421+
}
422+
}
423+
424+
Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64))
383425
}
384426

385427
#[cfg(any(target_os = "vxworks", target_os = "espidf"))]
386428
pub fn accessed(&self) -> io::Result<SystemTime> {
387-
Ok(SystemTime::from(libc::timespec {
388-
tv_sec: self.stat.st_atime as libc::time_t,
389-
tv_nsec: 0,
390-
}))
429+
Ok(SystemTime::new(self.stat.st_atime as i64, 0))
391430
}
392431

393432
#[cfg(any(
@@ -397,10 +436,7 @@ impl FileAttr {
397436
target_os = "ios"
398437
))]
399438
pub fn created(&self) -> io::Result<SystemTime> {
400-
Ok(SystemTime::from(libc::timespec {
401-
tv_sec: self.stat.st_birthtime as libc::time_t,
402-
tv_nsec: self.stat.st_birthtime_nsec as libc::c_long,
403-
}))
439+
Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64))
404440
}
405441

406442
#[cfg(not(any(
@@ -413,10 +449,7 @@ impl FileAttr {
413449
cfg_has_statx! {
414450
if let Some(ext) = &self.statx_extra_fields {
415451
return if (ext.stx_mask & libc::STATX_BTIME) != 0 {
416-
Ok(SystemTime::from(libc::timespec {
417-
tv_sec: ext.stx_btime.tv_sec as libc::time_t,
418-
tv_nsec: ext.stx_btime.tv_nsec as _,
419-
}))
452+
Ok(SystemTime::new(ext.stx_btime.tv_sec, ext.stx_btime.tv_nsec as i64))
420453
} else {
421454
Err(io::const_io_error!(
422455
io::ErrorKind::Uncategorized,

library/std/src/sys/unix/time.rs

+8
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ mod inner {
144144
}
145145

146146
impl SystemTime {
147+
pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
148+
SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
149+
}
150+
147151
pub fn now() -> SystemTime {
148152
use crate::ptr;
149153

@@ -294,6 +298,10 @@ mod inner {
294298
}
295299

296300
impl SystemTime {
301+
pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
302+
SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
303+
}
304+
297305
pub fn now() -> SystemTime {
298306
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
299307
}

0 commit comments

Comments
 (0)