Skip to content

Commit a1321b5

Browse files
committed
Set all file timestamps consistently to prevent backwards time
When restoring files from cache, set creation time, last modified time, and last access time to the same value from the ZIP entry. This prevents the scenario where creation time is newer than last modified time, which can occur when only setting last modified time while creation time defaults to the extraction time. Uses BasicFileAttributeView.setTimes() instead of Files.setLastModifiedTime() to set all three timestamps atomically. This ensures consistent timestamp state across all supported platforms (Windows, macOS, Linux).
1 parent 6eee251 commit a1321b5

File tree

1 file changed

+24
-13
lines changed

1 file changed

+24
-13
lines changed

src/main/java/org/apache/maven/buildcache/CacheUtils.java

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.nio.file.PathMatcher;
2828
import java.nio.file.SimpleFileVisitor;
2929
import java.nio.file.StandardCopyOption;
30+
import java.nio.file.attribute.BasicFileAttributeView;
3031
import java.nio.file.attribute.BasicFileAttributes;
3132
import java.nio.file.attribute.FileTime;
3233
import java.util.Arrays;
@@ -266,13 +267,7 @@ public static void unzip(Path zip, Path out, boolean preserveTimestamps) throws
266267
Files.copy(zis, file, StandardCopyOption.REPLACE_EXISTING);
267268

268269
if (preserveTimestamps) {
269-
// Set file timestamp with error handling
270-
try {
271-
Files.setLastModifiedTime(file, FileTime.fromMillis(entry.getTime()));
272-
} catch (IOException e) {
273-
// Timestamp setting is best-effort; log but don't fail extraction
274-
// This can happen on filesystems that don't support modification times
275-
}
270+
setAllTimestamps(file, entry.getTime());
276271
}
277272
}
278273
entry = zis.getNextEntry();
@@ -283,13 +278,29 @@ public static void unzip(Path zip, Path out, boolean preserveTimestamps) throws
283278
// Set directory timestamps after all files have been extracted to avoid them being
284279
// updated by file creation operations
285280
for (Map.Entry<Path, Long> dirEntry : directoryTimestamps.entrySet()) {
286-
try {
287-
Files.setLastModifiedTime(dirEntry.getKey(), FileTime.fromMillis(dirEntry.getValue()));
288-
} catch (IOException e) {
289-
// Timestamp setting is best-effort; log but don't fail extraction
290-
// This can happen on filesystems that don't support modification times
291-
}
281+
setAllTimestamps(dirEntry.getKey(), dirEntry.getValue());
282+
}
283+
}
284+
}
285+
286+
/**
287+
* Sets all timestamps (lastModifiedTime, lastAccessTime, and creationTime) for a path
288+
* to the same value to ensure consistency. This is a best-effort operation that silently
289+
* ignores errors on filesystems that don't support timestamp modification.
290+
*
291+
* @param path the path to update
292+
* @param timestampMillis the timestamp in milliseconds since epoch
293+
*/
294+
private static void setAllTimestamps(Path path, long timestampMillis) {
295+
try {
296+
BasicFileAttributeView attributes = Files.getFileAttributeView(path, BasicFileAttributeView.class);
297+
if (attributes != null) {
298+
FileTime time = FileTime.fromMillis(timestampMillis);
299+
attributes.setTimes(time, time, time);
292300
}
301+
} catch (IOException e) {
302+
// Timestamp setting is best-effort; log but don't fail extraction
303+
// This can happen on filesystems that don't support modification times
293304
}
294305
}
295306

0 commit comments

Comments
 (0)