uv_cache_info/
timestamp.rs

1use serde::{Deserialize, Serialize};
2use std::path::Path;
3
4/// A timestamp used to measure changes to a file.
5///
6/// On Unix, this uses `ctime` as a conservative approach. `ctime` should detect all
7/// modifications, including some that we don't care about, like hardlink modifications.
8/// On other platforms, it uses `mtime`.
9///
10/// See: <https://github.com/restic/restic/issues/2179>
11/// See: <https://apenwarr.ca/log/20181113>
12#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
13pub struct Timestamp(std::time::SystemTime);
14
15impl Timestamp {
16    /// Return the [`Timestamp`] for the given path.
17    pub fn from_path(path: impl AsRef<Path>) -> std::io::Result<Self> {
18        let metadata = fs_err::metadata(path.as_ref())?;
19        Ok(Self::from_metadata(&metadata))
20    }
21
22    /// Return the [`Timestamp`] for the given metadata.
23    pub fn from_metadata(metadata: &std::fs::Metadata) -> Self {
24        #[cfg(unix)]
25        {
26            use std::os::unix::fs::MetadataExt;
27
28            let ctime = u64::try_from(metadata.ctime()).expect("ctime to be representable as u64");
29            let ctime_nsec = u32::try_from(metadata.ctime_nsec())
30                .expect("ctime_nsec to be representable as u32");
31            let duration = std::time::Duration::new(ctime, ctime_nsec);
32            Self(std::time::UNIX_EPOCH + duration)
33        }
34
35        #[cfg(not(unix))]
36        {
37            let modified = metadata.modified().expect("modified time to be available");
38            Self(modified)
39        }
40    }
41
42    /// Return the current [`Timestamp`].
43    pub fn now() -> Self {
44        Self(std::time::SystemTime::now())
45    }
46}
47
48impl From<std::time::SystemTime> for Timestamp {
49    fn from(system_time: std::time::SystemTime) -> Self {
50        Self(system_time)
51    }
52}