diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java index ba7fe79e8b78..c3c6ab402fa9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import java.net.URLClassLoader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.attribute.FileTime; import java.time.Instant; import java.util.ArrayList; @@ -53,7 +54,6 @@ import org.springframework.boot.loader.TestJarCreator; import org.springframework.boot.loader.data.RandomAccessDataFile; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.FileCopyUtils; import org.springframework.util.StopWatch; import org.springframework.util.StreamUtils; @@ -621,23 +621,45 @@ private byte[] zip64Jar() throws IOException { @Test void jarFileEntryWithEpochTimeOfZeroShouldNotFail() throws Exception { - File file = new File(this.tempDir, "timed.jar"); - FileOutputStream fileOutputStream = new FileOutputStream(file); + File file = createJarFileWithEpochTimeOfZero(); + try (JarFile jar = new JarFile(file)) { + Enumeration entries = jar.entries(); + JarEntry entry = entries.nextElement(); + assertThat(entry.getLastModifiedTime().toInstant()).isEqualTo(Instant.EPOCH); + assertThat(entry.getName()).isEqualTo("1.dat"); + } + } + + private File createJarFileWithEpochTimeOfZero() throws Exception { + File jarFile = new File(this.tempDir, "temp.jar"); + FileOutputStream fileOutputStream = new FileOutputStream(jarFile); + String comment = "outer"; try (JarOutputStream jarOutputStream = new JarOutputStream(fileOutputStream)) { - jarOutputStream.setComment("outer"); + jarOutputStream.setComment(comment); JarEntry entry = new JarEntry("1.dat"); entry.setLastModifiedTime(FileTime.from(Instant.EPOCH)); - ReflectionTestUtils.setField(entry, "xdostime", 0); jarOutputStream.putNextEntry(entry); jarOutputStream.write(new byte[] { (byte) 1 }); jarOutputStream.closeEntry(); } - try (JarFile jar = new JarFile(file)) { - Enumeration entries = jar.entries(); - JarEntry entry = entries.nextElement(); - assertThat(entry.getLastModifiedTime().toInstant()).isEqualTo(Instant.EPOCH); - assertThat(entry.getName()).isEqualTo("1.dat"); - } + + byte[] data = Files.readAllBytes(jarFile.toPath()); + int headerPosition = data.length - ZipFile.ENDHDR - comment.getBytes().length; + int centralHeaderPosition = (int) Bytes.littleEndianValue(data, headerPosition + ZipFile.ENDOFF, 1); + int localHeaderPosition = (int) Bytes.littleEndianValue(data, centralHeaderPosition + ZipFile.CENOFF, 1); + writeTimeBlock(data, centralHeaderPosition + ZipFile.CENTIM, 0); + writeTimeBlock(data, localHeaderPosition + ZipFile.LOCTIM, 0); + + File jar = new File(this.tempDir, "zerotimed.jar"); + Files.write(jar.toPath(), data); + return jar; + } + + private static void writeTimeBlock(byte[] data, int pos, int value) { + data[pos] = (byte) (value & 0xff); + data[pos + 1] = (byte) ((value >> 8) & 0xff); + data[pos + 2] = (byte) ((value >> 16) & 0xff); + data[pos + 3] = (byte) ((value >> 24) & 0xff); } @Test