From fc3822b9365328228a3a06cef66da7c281ed6cfd Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sat, 9 Dec 2023 17:20:52 +0800 Subject: [PATCH 1/5] feat: support UTIME_NOW & UTIME_OMIT --- changelog/1879.added.md | 1 + src/sys/stat.rs | 8 ++++- src/sys/time.rs | 9 ++++- test/test_stat.rs | 73 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 changelog/1879.added.md diff --git a/changelog/1879.added.md b/changelog/1879.added.md new file mode 100644 index 0000000000..6f2b9a04d6 --- /dev/null +++ b/changelog/1879.added.md @@ -0,0 +1 @@ +Add associated constants `UTIME_OMIT` `UTIME_NOW` for `TimeSpec` diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 20b5294b31..49a2def89d 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -376,6 +376,9 @@ pub fn lutimes( /// Change the access and modification times of the file specified by a file descriptor. /// +/// If you want to set the timestamp to now, use [`TimeSpec::UTIME_NOW`]. Use +/// [`TimeSpec::UTIME_OMIT`] if you don't want to change it. +/// /// # References /// /// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). @@ -408,6 +411,9 @@ pub enum UtimensatFlags { /// `utimes(path, times)`. The latter is a deprecated API so prefer using the /// former if the platforms you care about support it. /// +/// If you want to set the timestamp to now, use [`TimeSpec::UTIME_NOW`]. Use +/// [`TimeSpec::UTIME_OMIT`] if you don't want to change it. +/// /// # References /// /// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). @@ -448,4 +454,4 @@ pub fn mkdirat( })?; Errno::result(res).map(drop) -} +} \ No newline at end of file diff --git a/src/sys/time.rs b/src/sys/time.rs index ac13de419c..0268bc0aff 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -329,6 +329,13 @@ impl TimeValLike for TimeSpec { } impl TimeSpec { + /// Leave the timestamp unchanged. + #[cfg(not(target_os = "redox"))] + pub const UTIME_OMIT: TimeSpec = TimeSpec::new(0, libc::UTIME_OMIT); + /// Update the timestamp to `Now` + #[cfg(not(target_os = "redox"))] + pub const UTIME_NOW: TimeSpec = TimeSpec::new(0, libc::UTIME_NOW); + /// Construct a new `TimeSpec` from its components #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { @@ -804,4 +811,4 @@ mod test { assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); } -} +} \ No newline at end of file diff --git a/test/test_stat.rs b/test/test_stat.rs index 58238249d9..6ce68e83d1 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -415,3 +415,76 @@ fn test_mknodat() { assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); } + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_futimens_unchanged() { + let tempdir = tempfile::tempdir().unwrap(); + let fullpath = tempdir.path().join("file"); + drop(File::create(&fullpath).unwrap()); + let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + let old_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let old_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + + futimens(fd, &TimeSpec::UTIME_OMIT, &TimeSpec::UTIME_OMIT).unwrap(); + + let new_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let new_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + assert_eq!(old_atime, new_atime); + assert_eq!(old_mtime, new_mtime); +} + + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_utimensat_unchanged() { + let _dr = crate::DirRestore::new(); + let tempdir = tempfile::tempdir().unwrap(); + let filename = "foo.txt"; + let fullpath = tempdir.path().join(filename); + drop(File::create(&fullpath).unwrap()); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); + + let old_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let old_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + utimensat( + Some(dirfd), + filename, + &TimeSpec::UTIME_OMIT, + &TimeSpec::UTIME_OMIT, + UtimensatFlags::NoFollowSymlink, + ) + .unwrap(); + let new_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let new_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + assert_eq!(old_atime, new_atime); + assert_eq!(old_mtime, new_mtime); +} From 62b0b029c845e2245e908021c76828e391a31059 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sat, 9 Dec 2023 17:23:44 +0800 Subject: [PATCH 2/5] fmt --- test/test_stat.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_stat.rs b/test/test_stat.rs index 6ce68e83d1..837c3aaeb9 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -448,7 +448,6 @@ fn test_futimens_unchanged() { assert_eq!(old_mtime, new_mtime); } - #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_utimensat_unchanged() { @@ -476,7 +475,7 @@ fn test_utimensat_unchanged() { &TimeSpec::UTIME_OMIT, UtimensatFlags::NoFollowSymlink, ) - .unwrap(); + .unwrap(); let new_atime = fs::metadata(fullpath.as_path()) .unwrap() .accessed() From 9727ae8d4b5a3202d7d2a6b6cb34a91f31538e25 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sat, 9 Dec 2023 17:25:10 +0800 Subject: [PATCH 3/5] fmt --- src/sys/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/time.rs b/src/sys/time.rs index 0268bc0aff..3068300256 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -811,4 +811,4 @@ mod test { assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); } -} \ No newline at end of file +} From bd89dbf4a24aa5eeee5e9c2773310a8f65f030c7 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sat, 9 Dec 2023 17:37:33 +0800 Subject: [PATCH 4/5] linux x32 type cast --- src/sys/stat.rs | 8 ++++---- src/sys/time.rs | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 49a2def89d..369008a800 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -376,8 +376,8 @@ pub fn lutimes( /// Change the access and modification times of the file specified by a file descriptor. /// -/// If you want to set the timestamp to now, use [`TimeSpec::UTIME_NOW`]. Use -/// [`TimeSpec::UTIME_OMIT`] if you don't want to change it. +/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use +/// `TimeSpec::UTIME_OMIT` if you don't want to change it. /// /// # References /// @@ -411,8 +411,8 @@ pub enum UtimensatFlags { /// `utimes(path, times)`. The latter is a deprecated API so prefer using the /// former if the platforms you care about support it. /// -/// If you want to set the timestamp to now, use [`TimeSpec::UTIME_NOW`]. Use -/// [`TimeSpec::UTIME_OMIT`] if you don't want to change it. +/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use +/// `TimeSpec::UTIME_OMIT` if you don't want to change it. /// /// # References /// diff --git a/src/sys/time.rs b/src/sys/time.rs index 3068300256..5479064899 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -331,10 +331,12 @@ impl TimeValLike for TimeSpec { impl TimeSpec { /// Leave the timestamp unchanged. #[cfg(not(target_os = "redox"))] - pub const UTIME_OMIT: TimeSpec = TimeSpec::new(0, libc::UTIME_OMIT); + // At the time of writing this PR, redox does not support this feature + pub const UTIME_OMIT: TimeSpec = TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t); /// Update the timestamp to `Now` + // At the time of writing this PR, redox does not support this feature #[cfg(not(target_os = "redox"))] - pub const UTIME_NOW: TimeSpec = TimeSpec::new(0, libc::UTIME_NOW); + pub const UTIME_NOW: TimeSpec = TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t); /// Construct a new `TimeSpec` from its components #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 From 45db0af7d03dd194340622bebe4a8a1043309023 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sat, 9 Dec 2023 17:39:23 +0800 Subject: [PATCH 5/5] fmt --- src/sys/time.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sys/time.rs b/src/sys/time.rs index 5479064899..a63a03dc88 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -332,11 +332,13 @@ impl TimeSpec { /// Leave the timestamp unchanged. #[cfg(not(target_os = "redox"))] // At the time of writing this PR, redox does not support this feature - pub const UTIME_OMIT: TimeSpec = TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t); + pub const UTIME_OMIT: TimeSpec = + TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t); /// Update the timestamp to `Now` // At the time of writing this PR, redox does not support this feature #[cfg(not(target_os = "redox"))] - pub const UTIME_NOW: TimeSpec = TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t); + pub const UTIME_NOW: TimeSpec = + TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t); /// Construct a new `TimeSpec` from its components #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848