Skip to content

Commit 7df959e

Browse files
authored
Merge pull request #36 from lucab/ups/file-update-timestamps
file: add helper for updating timestamps
2 parents 9b9d84d + 1df874d commit 7df959e

File tree

1 file changed

+40
-10
lines changed

1 file changed

+40
-10
lines changed

src/lib.rs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,9 @@ pub trait FileExt {
696696
/// Copy the entire contents of `self` to `to`. This uses operating system
697697
/// specific fast paths if available.
698698
fn copy_to(&self, to: &File) -> io::Result<u64>;
699+
700+
/// Update timestamps (both access and modification) to the current time.
701+
fn update_timestamps(&self) -> io::Result<()>;
699702
}
700703

701704
impl FileExt for File {
@@ -764,6 +767,16 @@ impl FileExt for File {
764767
}
765768
Ok(written)
766769
}
770+
771+
fn update_timestamps(&self) -> io::Result<()> {
772+
use nix::sys::{stat::futimens, time::TimeSpec};
773+
774+
let now = TimeSpec::from(libc::timespec {
775+
tv_nsec: libc::UTIME_NOW,
776+
tv_sec: 0,
777+
});
778+
retry_eintr!(futimens(self.as_raw_fd(), &now, &now,).map_err(map_nix_error))
779+
}
767780
}
768781

769782
fn to_cstr<P: openat::AsPath>(path: P) -> io::Result<P::Buffer> {
@@ -775,7 +788,8 @@ fn to_cstr<P: openat::AsPath>(path: P) -> io::Result<P::Buffer> {
775788
mod tests {
776789
use super::*;
777790
use std::path::{Path, PathBuf};
778-
use std::{error, result};
791+
use std::time::Duration;
792+
use std::{error, result, thread};
779793
use tempfile;
780794

781795
type Result<T> = result::Result<T, Box<dyn error::Error>>;
@@ -905,18 +919,34 @@ mod tests {
905919

906920
#[test]
907921
fn test_update_timestamps() {
922+
// File timestamps can not be updated faster than kernel ticking granularity,
923+
// so this test has to artificially sleep through several timer interrupts.
924+
const TICKING_PAUSE: Duration = Duration::from_millis(100);
925+
908926
let td = tempfile::tempdir().unwrap();
909927
let d = openat::Dir::open(td.path()).unwrap();
910-
d.ensure_dir("foo", 0o755).unwrap();
911-
let before = d.metadata("foo").unwrap();
912-
// File timestamps can not be updated faster than kernel ticking granularity,
913-
// so this artificially sleeps through several timer interrupts.
914-
std::thread::sleep(std::time::Duration::from_millis(100));
915928

916-
d.update_timestamps("foo").unwrap();
917-
let after = d.metadata("foo").unwrap();
918-
if before.stat().st_mtime == after.stat().st_mtime {
919-
assert_ne!(before.stat().st_mtime_nsec, after.stat().st_mtime_nsec);
929+
{
930+
d.ensure_dir("foo", 0o755).unwrap();
931+
let before = d.metadata("foo").unwrap();
932+
thread::sleep(TICKING_PAUSE);
933+
d.update_timestamps("foo").unwrap();
934+
let after = d.metadata("foo").unwrap();
935+
if before.stat().st_mtime == after.stat().st_mtime {
936+
assert_ne!(before.stat().st_mtime_nsec, after.stat().st_mtime_nsec);
937+
}
938+
}
939+
{
940+
use nix::sys::stat::fstat;
941+
942+
let bar = d.update_file("bar", 0o644).unwrap();
943+
let before = fstat(bar.as_raw_fd()).unwrap();
944+
thread::sleep(TICKING_PAUSE);
945+
bar.update_timestamps().unwrap();
946+
let after = fstat(bar.as_raw_fd()).unwrap();
947+
if before.st_mtime == after.st_mtime {
948+
assert_ne!(before.st_mtime_nsec, after.st_mtime_nsec);
949+
}
920950
}
921951
}
922952

0 commit comments

Comments
 (0)