Skip to content

Commit 1c189d9

Browse files
authored
feat: Add associated constants UTIME_OMIT UTIME_NOW to TimeSpec (#1879)
* feat: support UTIME_NOW & UTIME_OMIT * fmt * fmt * linux x32 type cast * fmt
1 parent d518abd commit 1c189d9

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

changelog/1879.added.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add associated constants `UTIME_OMIT` `UTIME_NOW` for `TimeSpec`

src/sys/stat.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@ pub fn lutimes<P: ?Sized + NixPath>(
376376

377377
/// Change the access and modification times of the file specified by a file descriptor.
378378
///
379+
/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use
380+
/// `TimeSpec::UTIME_OMIT` if you don't want to change it.
381+
///
379382
/// # References
380383
///
381384
/// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html).
@@ -408,6 +411,9 @@ pub enum UtimensatFlags {
408411
/// `utimes(path, times)`. The latter is a deprecated API so prefer using the
409412
/// former if the platforms you care about support it.
410413
///
414+
/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use
415+
/// `TimeSpec::UTIME_OMIT` if you don't want to change it.
416+
///
411417
/// # References
412418
///
413419
/// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
@@ -448,4 +454,4 @@ pub fn mkdirat<P: ?Sized + NixPath>(
448454
})?;
449455

450456
Errno::result(res).map(drop)
451-
}
457+
}

src/sys/time.rs

+11
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,17 @@ impl TimeValLike for TimeSpec {
329329
}
330330

331331
impl TimeSpec {
332+
/// Leave the timestamp unchanged.
333+
#[cfg(not(target_os = "redox"))]
334+
// At the time of writing this PR, redox does not support this feature
335+
pub const UTIME_OMIT: TimeSpec =
336+
TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t);
337+
/// Update the timestamp to `Now`
338+
// At the time of writing this PR, redox does not support this feature
339+
#[cfg(not(target_os = "redox"))]
340+
pub const UTIME_NOW: TimeSpec =
341+
TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t);
342+
332343
/// Construct a new `TimeSpec` from its components
333344
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
334345
pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self {

test/test_stat.rs

+72
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,75 @@ fn test_mknodat() {
413413
assert_eq!(mode & libc::S_IFREG, libc::S_IFREG);
414414
assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU);
415415
}
416+
417+
#[test]
418+
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
419+
fn test_futimens_unchanged() {
420+
let tempdir = tempfile::tempdir().unwrap();
421+
let fullpath = tempdir.path().join("file");
422+
drop(File::create(&fullpath).unwrap());
423+
let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty())
424+
.unwrap();
425+
426+
let old_atime = fs::metadata(fullpath.as_path())
427+
.unwrap()
428+
.accessed()
429+
.unwrap();
430+
let old_mtime = fs::metadata(fullpath.as_path())
431+
.unwrap()
432+
.modified()
433+
.unwrap();
434+
435+
futimens(fd, &TimeSpec::UTIME_OMIT, &TimeSpec::UTIME_OMIT).unwrap();
436+
437+
let new_atime = fs::metadata(fullpath.as_path())
438+
.unwrap()
439+
.accessed()
440+
.unwrap();
441+
let new_mtime = fs::metadata(fullpath.as_path())
442+
.unwrap()
443+
.modified()
444+
.unwrap();
445+
assert_eq!(old_atime, new_atime);
446+
assert_eq!(old_mtime, new_mtime);
447+
}
448+
449+
#[test]
450+
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
451+
fn test_utimensat_unchanged() {
452+
let _dr = crate::DirRestore::new();
453+
let tempdir = tempfile::tempdir().unwrap();
454+
let filename = "foo.txt";
455+
let fullpath = tempdir.path().join(filename);
456+
drop(File::create(&fullpath).unwrap());
457+
let dirfd =
458+
fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
459+
.unwrap();
460+
461+
let old_atime = fs::metadata(fullpath.as_path())
462+
.unwrap()
463+
.accessed()
464+
.unwrap();
465+
let old_mtime = fs::metadata(fullpath.as_path())
466+
.unwrap()
467+
.modified()
468+
.unwrap();
469+
utimensat(
470+
Some(dirfd),
471+
filename,
472+
&TimeSpec::UTIME_OMIT,
473+
&TimeSpec::UTIME_OMIT,
474+
UtimensatFlags::NoFollowSymlink,
475+
)
476+
.unwrap();
477+
let new_atime = fs::metadata(fullpath.as_path())
478+
.unwrap()
479+
.accessed()
480+
.unwrap();
481+
let new_mtime = fs::metadata(fullpath.as_path())
482+
.unwrap()
483+
.modified()
484+
.unwrap();
485+
assert_eq!(old_atime, new_atime);
486+
assert_eq!(old_mtime, new_mtime);
487+
}

0 commit comments

Comments
 (0)