From 6ec74e03c8ba7ac26317d842c29d769f46188b0d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 18 Jan 2024 16:18:15 -0800 Subject: [PATCH] Fix handling of negative timestamps in `Stat`. (#999) Deprecate `Stat::st_mtime` etc., because they're unsigned and should be signed, and introduce a `StatExt` extension trait which adds `mtime()` etc. accessor functions which return the values in the appropriate signed type. This `StatExt` trait can go away next time we have a semver breaking change, but for now this preserves compatibility. --- src/backend/libc/fs/syscalls.rs | 50 ++++++++------------------ src/backend/libc/fs/types.rs | 3 ++ src/backend/linux_raw/fs/syscalls.rs | 32 ++++++----------- src/backend/linux_raw/fs/types.rs | 3 ++ src/fs/mod.rs | 35 ++++++++++++++++++ tests/fs/futimens.rs | 4 +-- tests/fs/utimensat.rs | 12 ++++--- tests/fs/y2038.rs | 54 ++++++++++++++-------------- 8 files changed, 102 insertions(+), 91 deletions(-) diff --git a/src/backend/libc/fs/syscalls.rs b/src/backend/libc/fs/syscalls.rs index a098e2b80..cf493e7c5 100644 --- a/src/backend/libc/fs/syscalls.rs +++ b/src/backend/libc/fs/syscalls.rs @@ -1778,6 +1778,7 @@ pub(crate) fn sendfile( /// Convert from a Linux `statx` value to rustix's `Stat`. #[cfg(all(linux_kernel, target_pointer_width = "32"))] +#[allow(deprecated)] // for `st_[amc]time` u64->i64 transition fn statx_to_stat(x: crate::fs::Statx) -> io::Result { Ok(Stat { st_dev: crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor).into(), @@ -1789,23 +1790,11 @@ fn statx_to_stat(x: crate::fs::Statx) -> io::Result { st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, st_blksize: x.stx_blksize.into(), st_blocks: x.stx_blocks.into(), - st_atime: x - .stx_atime - .tv_sec - .try_into() - .map_err(|_| io::Errno::OVERFLOW)?, + st_atime: bitcast!(i64::from(x.stx_atime.tv_sec)), st_atime_nsec: x.stx_atime.tv_nsec as _, - st_mtime: x - .stx_mtime - .tv_sec - .try_into() - .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: bitcast!(i64::from(x.stx_mtime.tv_sec)), st_mtime_nsec: x.stx_mtime.tv_nsec as _, - st_ctime: x - .stx_ctime - .tv_sec - .try_into() - .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: bitcast!(i64::from(x.stx_ctime.tv_sec)), st_ctime_nsec: x.stx_ctime.tv_nsec as _, st_ino: x.stx_ino.into(), }) @@ -1827,23 +1816,11 @@ fn statx_to_stat(x: crate::fs::Statx) -> io::Result { result.st_size = x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?; result.st_blksize = x.stx_blksize.into(); result.st_blocks = x.stx_blocks.try_into().map_err(|_e| io::Errno::OVERFLOW)?; - result.st_atime = x - .stx_atime - .tv_sec - .try_into() - .map_err(|_| io::Errno::OVERFLOW)?; + result.st_atime = bitcast!(i64::from(x.stx_atime.tv_sec)); result.st_atime_nsec = x.stx_atime.tv_nsec as _; - result.st_mtime = x - .stx_mtime - .tv_sec - .try_into() - .map_err(|_| io::Errno::OVERFLOW)?; + result.st_mtime = bitcast!(i64::from(x.stx_mtime.tv_sec)); result.st_mtime_nsec = x.stx_mtime.tv_nsec as _; - result.st_ctime = x - .stx_ctime - .tv_sec - .try_into() - .map_err(|_| io::Errno::OVERFLOW)?; + result.st_ctime = bitcast!(i64::from(x.stx_ctime.tv_sec)); result.st_ctime_nsec = x.stx_ctime.tv_nsec as _; result.st_ino = x.stx_ino.into(); @@ -1852,6 +1829,7 @@ fn statx_to_stat(x: crate::fs::Statx) -> io::Result { /// Convert from a Linux `stat64` value to rustix's `Stat`. #[cfg(all(linux_kernel, target_pointer_width = "32"))] +#[allow(deprecated)] // for `st_[amc]time` u64->i64 transition fn stat64_to_stat(s64: c::stat64) -> io::Result { Ok(Stat { st_dev: s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?, @@ -1863,17 +1841,17 @@ fn stat64_to_stat(s64: c::stat64) -> io::Result { st_size: s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, st_blksize: s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?, st_blocks: s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?, - st_atime: s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime: bitcast!(i64::from(s64.st_atime)), st_atime_nsec: s64 .st_atime_nsec .try_into() .map_err(|_| io::Errno::OVERFLOW)?, - st_mtime: s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: bitcast!(i64::from(s64.st_mtime)), st_mtime_nsec: s64 .st_mtime_nsec .try_into() .map_err(|_| io::Errno::OVERFLOW)?, - st_ctime: s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: bitcast!(i64::from(s64.st_ctime)), st_ctime_nsec: s64 .st_ctime_nsec .try_into() @@ -1899,17 +1877,17 @@ fn stat64_to_stat(s64: c::stat64) -> io::Result { result.st_size = s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?; result.st_blksize = s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?; result.st_blocks = s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?; - result.st_atime = s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_atime = i64::from(s64.st_atime) as _; result.st_atime_nsec = s64 .st_atime_nsec .try_into() .map_err(|_| io::Errno::OVERFLOW)?; - result.st_mtime = s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_mtime = i64::from(s64.st_mtime) as _; result.st_mtime_nsec = s64 .st_mtime_nsec .try_into() .map_err(|_| io::Errno::OVERFLOW)?; - result.st_ctime = s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?; + result.st_ctime = i64::from(s64.st_ctime) as _; result.st_ctime_nsec = s64 .st_ctime_nsec .try_into() diff --git a/src/backend/libc/fs/types.rs b/src/backend/libc/fs/types.rs index 19508c241..f318f1636 100644 --- a/src/backend/libc/fs/types.rs +++ b/src/backend/libc/fs/types.rs @@ -986,10 +986,13 @@ pub struct Stat { pub st_size: i64, pub st_blksize: u32, pub st_blocks: u64, + #[deprecated(note = "Use `rustix::fs::StatExt::atime` instead.")] pub st_atime: u64, pub st_atime_nsec: u32, + #[deprecated(note = "Use `rustix::fs::StatExt::mtime` instead.")] pub st_mtime: u64, pub st_mtime_nsec: u32, + #[deprecated(note = "Use `rustix::fs::StatExt::ctime` instead.")] pub st_ctime: u64, pub st_ctime_nsec: u32, pub st_ino: u64, diff --git a/src/backend/linux_raw/fs/syscalls.rs b/src/backend/linux_raw/fs/syscalls.rs index 47d01df1c..126549386 100644 --- a/src/backend/linux_raw/fs/syscalls.rs +++ b/src/backend/linux_raw/fs/syscalls.rs @@ -711,6 +711,7 @@ fn lstat_old(path: &CStr) -> io::Result { target_arch = "mips64", target_arch = "mips64r6" ))] +#[allow(deprecated)] // for `st_[amc]time` u64->i64 transition fn statx_to_stat(x: crate::fs::Statx) -> io::Result { Ok(Stat { st_dev: crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor), @@ -722,23 +723,11 @@ fn statx_to_stat(x: crate::fs::Statx) -> io::Result { st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, st_blksize: x.stx_blksize.into(), st_blocks: x.stx_blocks.into(), - st_atime: x - .stx_atime - .tv_sec - .try_into() - .map_err(|_| io::Errno::OVERFLOW)?, + st_atime: bitcast!(i64::from(x.stx_atime.tv_sec)), st_atime_nsec: x.stx_atime.tv_nsec.into(), - st_mtime: x - .stx_mtime - .tv_sec - .try_into() - .map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: bitcast!(i64::from(x.stx_mtime.tv_sec)), st_mtime_nsec: x.stx_mtime.tv_nsec.into(), - st_ctime: x - .stx_ctime - .tv_sec - .try_into() - .map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: bitcast!(i64::from(x.stx_ctime.tv_sec)), st_ctime_nsec: x.stx_ctime.tv_nsec.into(), st_ino: x.stx_ino.into(), }) @@ -746,6 +735,7 @@ fn statx_to_stat(x: crate::fs::Statx) -> io::Result { /// Convert from a Linux `stat64` value to rustix's `Stat`. #[cfg(target_pointer_width = "32")] +#[allow(deprecated)] // for `st_[amc]time` u64->i64 transition fn stat_to_stat(s64: linux_raw_sys::general::stat64) -> io::Result { Ok(Stat { st_dev: s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?, @@ -757,17 +747,17 @@ fn stat_to_stat(s64: linux_raw_sys::general::stat64) -> io::Result { st_size: s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, st_blksize: s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?, st_blocks: s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?, - st_atime: s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime: bitcast!(i64::from(s64.st_atime)), st_atime_nsec: s64 .st_atime_nsec .try_into() .map_err(|_| io::Errno::OVERFLOW)?, - st_mtime: s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: bitcast!(i64::from(s64.st_mtime)), st_mtime_nsec: s64 .st_mtime_nsec .try_into() .map_err(|_| io::Errno::OVERFLOW)?, - st_ctime: s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: bitcast!(i64::from(s64.st_ctime)), st_ctime_nsec: s64 .st_ctime_nsec .try_into() @@ -789,17 +779,17 @@ fn stat_to_stat(s: linux_raw_sys::general::stat) -> io::Result { st_size: s.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?, st_blksize: s.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?, st_blocks: s.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?, - st_atime: s.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_atime: bitcast!(i64::from(s.st_atime)), st_atime_nsec: s .st_atime_nsec .try_into() .map_err(|_| io::Errno::OVERFLOW)?, - st_mtime: s.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_mtime: bitcast!(i64::from(s.st_mtime)), st_mtime_nsec: s .st_mtime_nsec .try_into() .map_err(|_| io::Errno::OVERFLOW)?, - st_ctime: s.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?, + st_ctime: bitcast!(i64::from(s.st_ctime)), st_ctime_nsec: s .st_ctime_nsec .try_into() diff --git a/src/backend/linux_raw/fs/types.rs b/src/backend/linux_raw/fs/types.rs index 39823c4e1..c109a6ff9 100644 --- a/src/backend/linux_raw/fs/types.rs +++ b/src/backend/linux_raw/fs/types.rs @@ -653,10 +653,13 @@ pub struct Stat { pub st_size: i64, pub st_blksize: u32, pub st_blocks: u64, + #[deprecated(note = "Use `rustix::fs::StatExt::atime` instead.")] pub st_atime: u64, pub st_atime_nsec: u32, + #[deprecated(note = "Use `rustix::fs::StatExt::mtime` instead.")] pub st_mtime: u64, pub st_mtime_nsec: u32, + #[deprecated(note = "Use `rustix::fs::StatExt::ctime` instead.")] pub st_ctime: u64, pub st_ctime_nsec: u32, pub st_ino: u64, diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 996bb4e57..27d357012 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -141,3 +141,38 @@ pub use std::os::unix::fs::{DirEntryExt, FileExt, FileTypeExt, MetadataExt, Open #[cfg(feature = "std")] #[cfg(all(wasi_ext, target_os = "wasi"))] pub use std::os::wasi::fs::{DirEntryExt, FileExt, FileTypeExt, MetadataExt, OpenOptionsExt}; + +/// Extension trait for accessing timestamp fields of `Stat`. +/// +/// Rustix's `Stat` type on some platforms has unsigned `st_mtime`, +/// `st_atime`, and `st_ctime` fields. This is incorrect, as Unix defines +/// these fields to be signed, with negative values representing dates before +/// the Unix epoch. Until the next semver bump, these unsigned fields are +/// deprecated, and this trait provides accessors which return their values +/// as signed integers. +#[cfg(all(unix, not(any(target_os = "aix", target_os = "nto"))))] +pub trait StatExt { + /// Return the value of the `st_atime` field, casted to the correct type. + fn atime(&self) -> i64; + /// Return the value of the `st_mtime` field, casted to the correct type. + fn mtime(&self) -> i64; + /// Return the value of the `st_ctime` field, casted to the correct type. + fn ctime(&self) -> i64; +} + +#[cfg(all(unix, not(any(target_os = "aix", target_os = "nto"))))] +#[allow(deprecated)] +impl StatExt for Stat { + #[inline] + fn atime(&self) -> i64 { + self.st_atime as i64 + } + #[inline] + fn mtime(&self) -> i64 { + self.st_mtime as i64 + } + #[inline] + fn ctime(&self) -> i64 { + self.st_ctime as i64 + } +} diff --git a/tests/fs/futimens.rs b/tests/fs/futimens.rs index 616638f13..1aa9f72b5 100644 --- a/tests/fs/futimens.rs +++ b/tests/fs/futimens.rs @@ -1,7 +1,7 @@ #[cfg(not(any(target_os = "redox", target_os = "wasi")))] #[test] fn test_futimens() { - use rustix::fs::{fstat, futimens, openat, Mode, OFlags, Timespec, Timestamps, CWD}; + use rustix::fs::{fstat, futimens, openat, Mode, OFlags, StatExt, Timespec, Timestamps, CWD}; let tmp = tempfile::tempdir().unwrap(); let dir = openat(CWD, tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); @@ -28,7 +28,7 @@ fn test_futimens() { let after = fstat(&file).unwrap(); - assert_eq!(times.last_modification.tv_sec as u64, after.st_mtime as u64); + assert_eq!(times.last_modification.tv_sec as u64, after.mtime() as u64); #[cfg(not(target_os = "netbsd"))] assert_eq!( times.last_modification.tv_nsec as u64, diff --git a/tests/fs/utimensat.rs b/tests/fs/utimensat.rs index ec65f466d..14dce7f76 100644 --- a/tests/fs/utimensat.rs +++ b/tests/fs/utimensat.rs @@ -1,7 +1,9 @@ #[cfg(not(any(target_os = "redox", target_os = "wasi")))] #[test] fn test_utimensat() { - use rustix::fs::{openat, statat, utimensat, AtFlags, Mode, OFlags, Timespec, Timestamps, CWD}; + use rustix::fs::{ + openat, statat, utimensat, AtFlags, Mode, OFlags, StatExt, Timespec, Timestamps, CWD, + }; let tmp = tempfile::tempdir().unwrap(); let dir = openat( @@ -34,7 +36,7 @@ fn test_utimensat() { let after = statat(&dir, "file", AtFlags::empty()).unwrap(); - assert_eq!(times.last_modification.tv_sec as u64, after.st_mtime as u64); + assert_eq!(times.last_modification.tv_sec as u64, after.mtime() as u64); #[cfg(not(target_os = "netbsd"))] assert_eq!( times.last_modification.tv_nsec as u64, @@ -45,15 +47,15 @@ fn test_utimensat() { times.last_modification.tv_nsec as u64, after.st_mtimensec as u64 ); - assert!(times.last_access.tv_sec as u64 >= after.st_atime as u64); + assert!(times.last_access.tv_sec as u64 >= after.atime() as u64); #[cfg(not(target_os = "netbsd"))] assert!( - times.last_access.tv_sec as u64 > after.st_atime as u64 + times.last_access.tv_sec as u64 > after.atime() as u64 || times.last_access.tv_nsec as u64 >= after.st_atime_nsec as u64 ); #[cfg(target_os = "netbsd")] assert!( - times.last_access.tv_sec as u64 > after.st_atime as u64 + times.last_access.tv_sec as u64 > after.atime() as u64 || times.last_access.tv_nsec as u64 >= after.st_atimensec as u64 ); } diff --git a/tests/fs/y2038.rs b/tests/fs/y2038.rs index eba3a16d5..615f92636 100644 --- a/tests/fs/y2038.rs +++ b/tests/fs/y2038.rs @@ -9,7 +9,7 @@ #[test] fn test_y2038_with_utimensat() { use rustix::fs::{ - fstat, openat, statat, utimensat, AtFlags, Mode, OFlags, Timespec, Timestamps, CWD, + fstat, openat, statat, utimensat, AtFlags, Mode, OFlags, StatExt, Timespec, Timestamps, CWD, }; let tmp = tempfile::tempdir().unwrap(); @@ -46,23 +46,23 @@ fn test_y2038_with_utimensat() { // Use `statat` to read back the timestamp. let stat = statat(&dir, "file", AtFlags::empty()).unwrap(); - assert_eq!(TryInto::::try_into(stat.st_mtime).unwrap(), m_sec); + assert_eq!(TryInto::::try_into(stat.mtime()).unwrap(), m_sec); #[cfg(not(target_os = "netbsd"))] assert_eq!(stat.st_mtime_nsec as u32, m_nsec); #[cfg(target_os = "netbsd")] assert_eq!(stat.st_mtimensec as u32, m_nsec); - assert!(TryInto::::try_into(stat.st_atime).unwrap() >= a_sec); + assert!(TryInto::::try_into(stat.atime()).unwrap() >= a_sec); #[cfg(not(target_os = "netbsd"))] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atime_nsec as u32 >= a_nsec ); #[cfg(target_os = "netbsd")] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atimensec as u32 >= a_nsec ); @@ -70,23 +70,23 @@ fn test_y2038_with_utimensat() { let file = openat(&dir, "file", OFlags::RDONLY, Mode::empty()).unwrap(); let stat = fstat(&file).unwrap(); - assert_eq!(TryInto::::try_into(stat.st_mtime).unwrap(), m_sec); + assert_eq!(TryInto::::try_into(stat.mtime()).unwrap(), m_sec); #[cfg(not(target_os = "netbsd"))] assert_eq!(stat.st_mtime_nsec as u32, m_nsec); #[cfg(target_os = "netbsd")] assert_eq!(stat.st_mtimensec as u32, m_nsec); - assert!(TryInto::::try_into(stat.st_atime).unwrap() >= a_sec); + assert!(TryInto::::try_into(stat.atime()).unwrap() >= a_sec); #[cfg(not(target_os = "netbsd"))] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atime_nsec as u32 >= a_nsec ); #[cfg(target_os = "netbsd")] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atimensec as u32 >= a_nsec ); } @@ -102,7 +102,7 @@ fn test_y2038_with_utimensat() { #[test] fn test_y2038_with_futimens() { use rustix::fs::{ - fstat, futimens, openat, statat, AtFlags, Mode, OFlags, Timespec, Timestamps, CWD, + fstat, futimens, openat, statat, AtFlags, Mode, OFlags, StatExt, Timespec, Timestamps, CWD, }; let tmp = tempfile::tempdir().unwrap(); @@ -139,23 +139,23 @@ fn test_y2038_with_futimens() { // Use `statat` to read back the timestamp. let stat = statat(&dir, "file", AtFlags::empty()).unwrap(); - assert_eq!(TryInto::::try_into(stat.st_mtime).unwrap(), m_sec); + assert_eq!(TryInto::::try_into(stat.mtime()).unwrap(), m_sec); #[cfg(not(target_os = "netbsd"))] assert_eq!(stat.st_mtime_nsec as u32, m_nsec); #[cfg(target_os = "netbsd")] assert_eq!(stat.st_mtimensec as u32, m_nsec); - assert!(TryInto::::try_into(stat.st_atime).unwrap() >= a_sec); + assert!(TryInto::::try_into(stat.atime()).unwrap() >= a_sec); #[cfg(not(target_os = "netbsd"))] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atime_nsec as u32 >= a_nsec ); #[cfg(target_os = "netbsd")] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atimensec as u32 >= a_nsec ); @@ -163,23 +163,23 @@ fn test_y2038_with_futimens() { let file = openat(&dir, "file", OFlags::RDONLY, Mode::empty()).unwrap(); let stat = fstat(&file).unwrap(); - assert_eq!(TryInto::::try_into(stat.st_mtime).unwrap(), m_sec); + assert_eq!(TryInto::::try_into(stat.mtime()).unwrap(), m_sec); #[cfg(not(target_os = "netbsd"))] assert_eq!(stat.st_mtime_nsec as u32, m_nsec); #[cfg(target_os = "netbsd")] assert_eq!(stat.st_mtimensec as u32, m_nsec); - assert!(TryInto::::try_into(stat.st_atime).unwrap() >= a_sec); + assert!(TryInto::::try_into(stat.atime()).unwrap() >= a_sec); #[cfg(not(target_os = "netbsd"))] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atime_nsec as u32 >= a_nsec ); #[cfg(target_os = "netbsd")] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atimensec as u32 >= a_nsec ); } @@ -193,7 +193,7 @@ fn test_y2038_with_futimens() { #[cfg(not(all(target_os = "emscripten", target_pointer_width = "32")))] #[test] fn test_y2038_with_futimens_and_stat() { - use rustix::fs::{fstat, futimens, open, stat, Mode, OFlags, Timespec, Timestamps}; + use rustix::fs::{fstat, futimens, open, stat, Mode, OFlags, StatExt, Timespec, Timestamps}; let tmp = tempfile::tempdir().unwrap(); @@ -233,23 +233,23 @@ fn test_y2038_with_futimens_and_stat() { // Use `statat` to read back the timestamp. let stat = stat(tmp.path().join("file")).unwrap(); - assert_eq!(TryInto::::try_into(stat.st_mtime).unwrap(), m_sec); + assert_eq!(TryInto::::try_into(stat.mtime()).unwrap(), m_sec); #[cfg(not(target_os = "netbsd"))] assert_eq!(stat.st_mtime_nsec as u32, m_nsec); #[cfg(target_os = "netbsd")] assert_eq!(stat.st_mtimensec as u32, m_nsec); - assert!(TryInto::::try_into(stat.st_atime).unwrap() >= a_sec); + assert!(TryInto::::try_into(stat.atime()).unwrap() >= a_sec); #[cfg(not(target_os = "netbsd"))] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atime_nsec as u32 >= a_nsec ); #[cfg(target_os = "netbsd")] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atimensec as u32 >= a_nsec ); @@ -257,23 +257,23 @@ fn test_y2038_with_futimens_and_stat() { let file = open(tmp.path().join("file"), OFlags::RDONLY, Mode::empty()).unwrap(); let stat = fstat(&file).unwrap(); - assert_eq!(TryInto::::try_into(stat.st_mtime).unwrap(), m_sec); + assert_eq!(TryInto::::try_into(stat.mtime()).unwrap(), m_sec); #[cfg(not(target_os = "netbsd"))] assert_eq!(stat.st_mtime_nsec as u32, m_nsec); #[cfg(target_os = "netbsd")] assert_eq!(stat.st_mtimensec as u32, m_nsec); - assert!(TryInto::::try_into(stat.st_atime).unwrap() >= a_sec); + assert!(TryInto::::try_into(stat.atime()).unwrap() >= a_sec); #[cfg(not(target_os = "netbsd"))] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atime_nsec as u32 >= a_nsec ); #[cfg(target_os = "netbsd")] assert!( - TryInto::::try_into(stat.st_atime).unwrap() > a_sec + TryInto::::try_into(stat.atime()).unwrap() > a_sec || stat.st_atimensec as u32 >= a_nsec ); }