Merge "DirCacheEntry: Fix mightBeRacilyClean() time difference calculation"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
index 01d1e02..158d9de 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
@@ -22,6 +22,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.security.MessageDigest;
+import java.time.Duration;
 import java.time.Instant;
 import java.util.concurrent.TimeUnit;
 
@@ -339,4 +340,29 @@ private static void copyMetaDataHelper(boolean keepStage) {
 		assertTrue(e.isUpdateNeeded());
 		assertEquals("some/path", e.getPathString());
 	}
+
+	@Test
+	public void testMightBeRacilyCleanNanoOverflow() {
+		DirCacheEntry entry = new DirCacheEntry("some/path");
+		final Instant instant = Instant.ofEpochSecond(1, 999_999_999);
+		entry.setLastModified(instant.plus(Duration.ofNanos(1)));
+		assertTrue(entry.mightBeRacilyClean(instant));
+	}
+
+	@Test
+	public void testMightBeRacilyCleanOneSecondAfter() {
+		DirCacheEntry entry = new DirCacheEntry("some/path");
+		final Instant instant = Instant.ofEpochSecond(1, 0);
+		entry.setLastModified(instant.plus(Duration.ofSeconds(1)));
+		assertTrue(entry.mightBeRacilyClean(instant));
+	}
+
+	@Test
+	public void testNotRacilyCleanWhenSmudgeIsAfter() {
+		DirCacheEntry entry = new DirCacheEntry("some/path");
+		final Instant entryTime = Instant.ofEpochSecond(1, 0);
+		entry.setLastModified(entryTime);
+		final Instant smudge = entryTime.plus(Duration.ofNanos(1));
+		assertFalse(entry.mightBeRacilyClean(smudge));
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
index 5a22938..aebea7a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -411,9 +411,14 @@ public final boolean mightBeRacilyClean(Instant smudge) {
 		// it is clean or not based on the modification time alone.
 		//
 		final int base = infoOffset + P_MTIME;
-		final int mtime = NB.decodeInt32(info, base);
-		if ((int) smudge.getEpochSecond() == mtime) {
-			return smudge.getNano() <= NB.decodeInt32(info, base + 4);
+		final int entryMtimeSec = NB.decodeInt32(info, base);
+		final int smudgeSec = (int) smudge.getEpochSecond();
+		if (smudgeSec != 0) {
+			if (smudgeSec < entryMtimeSec) {
+				return true;
+			} else if (smudgeSec == entryMtimeSec) {
+				return smudge.getNano() <= NB.decodeInt32(info, base + 4);
+			}
 		}
 		return false;
 	}