diff --git a/rust/hg-core/src/dirstate/entry.rs b/rust/hg-core/src/dirstate/entry.rs --- a/rust/hg-core/src/dirstate/entry.rs +++ b/rust/hg-core/src/dirstate/entry.rs @@ -87,6 +87,10 @@ } } + /// Returns a `TruncatedTimestamp` for the modification time of `metadata`. + /// + /// Propagates errors from `std` on platforms where modification time + /// is not available at all. pub fn for_mtime_of(metadata: &fs::Metadata) -> io::Result { #[cfg(unix)] { @@ -102,13 +106,18 @@ } } - /// Returns whether this timestamp is reliable as the "mtime" of a file. + /// Like `for_mtime_of`, but may return `None` or a value with + /// `second_ambiguous` set if the mtime is not "reliable". /// /// A modification time is reliable if it is older than `boundary` (or /// sufficiently in the future). /// /// Otherwise a concurrent modification might happens with the same mtime. - pub fn is_reliable_mtime(&self, boundary: &Self) -> bool { + pub fn for_reliable_mtime_of( + metadata: &fs::Metadata, + boundary: &Self, + ) -> io::Result> { + let mut mtime = Self::for_mtime_of(metadata)?; // If the mtime of the ambiguous file is younger (or equal) to the // starting point of the `status` walk, we cannot garantee that // another, racy, write will not happen right after with the same mtime @@ -118,16 +127,23 @@ // mismatch between the current clock and previous file system // operation. So mtime more than one days in the future are considered // fine. - if self.truncated_seconds == boundary.truncated_seconds { - self.nanoseconds != 0 + let reliable = if mtime.truncated_seconds == boundary.truncated_seconds + { + mtime.second_ambiguous = true; + mtime.nanoseconds != 0 && boundary.nanoseconds != 0 - && self.nanoseconds < boundary.nanoseconds + && mtime.nanoseconds < boundary.nanoseconds } else { // `truncated_seconds` is less than 2**31, // so this does not overflow `u32`: let one_day_later = boundary.truncated_seconds + 24 * 3600; - self.truncated_seconds < boundary.truncated_seconds - || self.truncated_seconds > one_day_later + mtime.truncated_seconds < boundary.truncated_seconds + || mtime.truncated_seconds > one_day_later + }; + if reliable { + Ok(Some(mtime)) + } else { + Ok(None) } } diff --git a/rust/rhg/src/commands/status.rs b/rust/rhg/src/commands/status.rs --- a/rust/rhg/src/commands/status.rs +++ b/rust/rhg/src/commands/status.rs @@ -352,9 +352,13 @@ let fs_metadata = repo .working_directory_vfs() .symlink_metadata(&fs_path)?; - let mtime = TruncatedTimestamp::for_mtime_of(&fs_metadata) - .when_reading_file(&fs_path)?; - if mtime.is_reliable_mtime(&mtime_boundary) { + if let Some(mtime) = + TruncatedTimestamp::for_reliable_mtime_of( + &fs_metadata, + &mtime_boundary, + ) + .when_reading_file(&fs_path)? + { let mode = fs_metadata.mode(); let size = fs_metadata.len() as u32 & RANGE_MASK_31BIT; let mut entry = dmap