mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-23 00:35:13 +00:00
8268613: jar --validate should check inital entries of a JAR file
Reviewed-by: lancea, jvernee
This commit is contained in:
parent
ce1adf63ea
commit
8690d263d9
@ -260,6 +260,19 @@ final class Validator {
|
||||
isValid = false;
|
||||
warn(getMsg("warn.validator.order.mismatch"));
|
||||
}
|
||||
// Check location of an optional manifest entry
|
||||
if ("META-INF/MANIFEST.MF".equals(entryName)) {
|
||||
int index = entryInfo.cen().order();
|
||||
if (index > 1) { // Expect base manifest at index 0 or 1
|
||||
String position = Integer.toString(index);
|
||||
errorAndInvalid(formatMsg("error.validator.manifest.wrong.position", position));
|
||||
} else if (index == 1) { // Ensure "META-INF/" preceeds manifest
|
||||
String firstName = entries.sequencedKeySet().getFirst();
|
||||
if (!"META-INF/".equals(firstName)) {
|
||||
errorAndInvalid(formatMsg("error.validator.metainf.wrong.position", firstName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -134,6 +134,10 @@ error.validator.info.version.notequal=\
|
||||
{0}: module-info.class in a versioned directory contains different "version"
|
||||
error.validator.info.manclass.notequal=\
|
||||
{0}: module-info.class in a versioned directory contains different "main-class"
|
||||
error.validator.metainf.wrong.position=\
|
||||
expected entry META-INF/ to be at position 0, but found: {0}
|
||||
error.validator.manifest.wrong.position=\
|
||||
expected entry META-INF/MANIFEST.MF to be at position 0 or 1, but found it at position: {0}
|
||||
warn.validator.identical.entry=\
|
||||
Warning: entry {0} contains a class that\n\
|
||||
is identical to an entry already in the jar
|
||||
|
||||
@ -38,10 +38,13 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.junit.jupiter.api.TestInstance.Lifecycle;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertLinesMatch;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -50,6 +53,7 @@ import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.spi.ToolProvider;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
@ -306,6 +310,96 @@ class ValidatorTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that base manifest-related entries are at expected LOC positions.
|
||||
* <p>
|
||||
* Copied from <code>JarInputStream.java</code>:
|
||||
* <pre>
|
||||
* This implementation assumes the META-INF/MANIFEST.MF entry
|
||||
* should be either the first or the second entry (when preceded
|
||||
* by the dir META-INF/). It skips the META-INF/ and then
|
||||
* "consumes" the MANIFEST.MF to initialize the Manifest object.
|
||||
* </pre>
|
||||
* This test does not do a similar CEN check in the event that the LOC and CEN
|
||||
* entries do not match. Those mismatch cases are already checked by other tests.
|
||||
*/
|
||||
@Test
|
||||
public void testWrongManifestPositions() throws IOException {
|
||||
testWrongManifestPosition(
|
||||
Path.of("wrong-entry-position-A.jar"),
|
||||
"""
|
||||
expected entry META-INF/ to be at position 0, but found: PLACEHOLDER
|
||||
""",
|
||||
EntryWriter.ofText("PLACEHOLDER", "0"),
|
||||
EntryWriter.ofText(META_INF + "MANIFEST.MF", "Manifest-Version: 1.0"));
|
||||
testWrongManifestPosition(
|
||||
Path.of("wrong-entry-position-B.jar"),
|
||||
"""
|
||||
expected entry META-INF/MANIFEST.MF to be at position 0 or 1, but found it at position: 2
|
||||
""",
|
||||
EntryWriter.ofDirectory(META_INF),
|
||||
EntryWriter.ofText("PLACEHOLDER", "1"),
|
||||
EntryWriter.ofText(META_INF + "MANIFEST.MF", "Manifest-Version: 1.0"));
|
||||
testWrongManifestPosition(
|
||||
Path.of("wrong-entry-position-C.jar"),
|
||||
"""
|
||||
expected entry META-INF/MANIFEST.MF to be at position 0 or 1, but found it at position: 4
|
||||
""",
|
||||
EntryWriter.ofDirectory(META_INF),
|
||||
EntryWriter.ofText("PLACEHOLDER1", "1"),
|
||||
EntryWriter.ofText("PLACEHOLDER2", "2"),
|
||||
EntryWriter.ofText("PLACEHOLDER3", "3"),
|
||||
EntryWriter.ofText(META_INF + "MANIFEST.MF", "Manifest-Version: 1.0"));
|
||||
}
|
||||
|
||||
private void testWrongManifestPosition(
|
||||
Path path, String expectedErrorMessage, EntryWriter... entries) throws IOException {
|
||||
createZipFile(path, entries);
|
||||
// first check JAR file with streaming API
|
||||
try (var jis = new JarInputStream(new FileInputStream(path.toFile()))) {
|
||||
var manifest = jis.getManifest();
|
||||
assertNull(manifest, "Manifest not null?!");
|
||||
}
|
||||
// now validate with tool CLI
|
||||
try {
|
||||
jar("--validate --file " + path);
|
||||
fail("Expecting non-zero exit code validating: " + path);
|
||||
} catch (IOException e) {
|
||||
var err = e.getMessage();
|
||||
System.out.println(err);
|
||||
assertLinesMatch(expectedErrorMessage.lines(), err.lines());
|
||||
}
|
||||
}
|
||||
|
||||
record EntryWriter(ZipEntry entry, Writer writer) {
|
||||
@FunctionalInterface
|
||||
interface Writer {
|
||||
void write(ZipOutputStream stream) throws IOException;
|
||||
}
|
||||
static EntryWriter ofDirectory(String name) {
|
||||
return new EntryWriter(new ZipEntry(name), _ -> {});
|
||||
}
|
||||
static EntryWriter ofText(String name, String text) {
|
||||
return new EntryWriter(new ZipEntry(name),
|
||||
stream -> stream.write(text.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void createZipFile(Path path, EntryWriter... entries) throws IOException {
|
||||
System.out.printf("%n%n*****Creating Zip file with %d entries*****%n".formatted(entries.length));
|
||||
var out = new ByteArrayOutputStream(1024);
|
||||
try (var zos = new ZipOutputStream(out)) {
|
||||
for (var entry : entries) {
|
||||
System.out.printf(" %s%n".formatted(entry.entry().getName()));
|
||||
zos.putNextEntry(entry.entry());
|
||||
entry.writer().write(zos);
|
||||
zos.closeEntry();
|
||||
}
|
||||
zos.flush();
|
||||
}
|
||||
Files.write(path, out.toByteArray());
|
||||
}
|
||||
|
||||
// return stderr output
|
||||
private String jar(String cmdline) throws IOException {
|
||||
System.out.println("jar " + cmdline);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user