< prev index next >
src/java.base/share/classes/java/util/zip/ZipFile.java
Print this page
rev 59204 : imported patch jarf_signature
@@ -43,10 +43,12 @@
import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
import java.util.Objects;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
@@ -1008,33 +1010,53 @@
}
}
/**
- * Returns the names of all non-directory entries that begin with
- * "META-INF/" (case ignored). This method is used in JarFile, via
- * SharedSecrets, as an optimization when looking up manifest and
- * signature file entries. Returns null if no entries were found.
+ * Returns the names of the META-INF/MANIFEST.MF entry - if exists -
+ * and any signature-related files under META-INF. This method is used in
+ * JarFile, via SharedSecrets, as an optimization.
*/
- private String[] getMetaInfEntryNames() {
+ private List<String> getManifestAndSignatureRelatedFiles() {
synchronized (this) {
ensureOpen();
Source zsrc = res.zsrc;
- if (zsrc.metanames == null) {
- return null;
+ int[] metanames = zsrc.signatureMetaNames;
+ List<String> files = null;
+ if (zsrc.manifestPos >= 0) {
+ files = new ArrayList<>();
+ files.add(getEntryName(zsrc.manifestPos));
+ }
+ if (metanames != null) {
+ if (files == null) {
+ files = new ArrayList<>();
+ }
+ for (int i = 0; i < metanames.length; i++) {
+ files.add(getEntryName(metanames[i]));
+ }
+ }
+ return files == null ? List.of() : files;
}
- String[] names = new String[zsrc.metanames.length];
- byte[] cen = zsrc.cen;
- for (int i = 0; i < names.length; i++) {
- int pos = zsrc.metanames[i];
- // This will only be invoked on JarFile, which is guaranteed
- // to use (or be compatible with) UTF-8 encoding.
- names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos),
- UTF_8.INSTANCE);
}
- return names;
+
+ /**
+ * Returns the name of the META-INF/MANIFEST.MF entry, ignoring
+ * case. If {@code onlyIfSignatureRelatedFiles} is true, we only return the
+ * manifest if there is also at least one signature-related file.
+ * This method is used in JarFile, via SharedSecrets, as an optimization
+ * when looking up the manifest file.
+ */
+ private String getManifestName(boolean onlyIfSignatureRelatedFiles) {
+ synchronized (this) {
+ ensureOpen();
+ Source zsrc = res.zsrc;
+ int pos = zsrc.manifestPos;
+ if (pos >= 0 && (!onlyIfSignatureRelatedFiles || zsrc.signatureMetaNames != null)) {
+ return getEntryName(pos);
+ }
}
+ return null;
}
/**
* Returns the versions for which there exists a non-directory
* entry that begin with "META-INF/versions/" (case ignored).
@@ -1057,12 +1079,16 @@
@Override
public boolean startsWithLocHeader(ZipFile zip) {
return zip.res.zsrc.startsWithLoc;
}
@Override
- public String[] getMetaInfEntryNames(JarFile jar) {
- return ((ZipFile)jar).getMetaInfEntryNames();
+ public List<String> getManifestAndSignatureRelatedFiles(JarFile jar) {
+ return ((ZipFile)jar).getManifestAndSignatureRelatedFiles();
+ }
+ @Override
+ public String getManifestName(JarFile jar, boolean onlyIfHasSignatureRelatedFiles) {
+ return ((ZipFile)jar).getManifestName(onlyIfHasSignatureRelatedFiles);
}
@Override
public int[] getMetaInfVersions(JarFile jar) {
return ((ZipFile)jar).getMetaInfVersions();
}
@@ -1103,11 +1129,12 @@
private RandomAccessFile zfile; // zfile of the underlying zip file
private byte[] cen; // CEN & ENDHDR
private long locpos; // position of first LOC header (usually 0)
private byte[] comment; // zip file comment
// list of meta entries in META-INF dir
- private int[] metanames;
+ private int manifestPos = -1; // position of the META-INF/MANIFEST.MF, if exists
+ private int[] signatureMetaNames; // positions of signature related entries, if such exist
private int[] metaVersions; // list of unique versions found in META-INF/versions/
private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
// A Hashmap for all entries.
//
@@ -1252,11 +1279,12 @@
zfile.close();
zfile = null;
cen = null;
entries = null;
table = null;
- metanames = null;
+ manifestPos = -1;
+ signatureMetaNames = null;
metaVersions = EMPTY_META_VERSIONS;
}
private static final int BUF_SIZE = 8192;
private final int readFullyAt(byte[] buf, int off, int len, long pos)
@@ -1436,11 +1464,11 @@
int idx = 0;
int hash;
int next;
// list for all meta entries
- ArrayList<Integer> metanamesList = null;
+ ArrayList<Integer> signatureNames = null;
// Set of all version numbers seen in META-INF/versions/
Set<Integer> metaVersionsSet = null;
// Iterate through the entries in the central directory
int i = 0;
@@ -1474,13 +1502,19 @@
next = table[hsh];
table[hsh] = idx;
idx = addEntry(idx, hash, next, pos);
// Adds name to metanames.
if (isMetaName(cen, entryPos, nlen)) {
- if (metanamesList == null)
- metanamesList = new ArrayList<>(4);
- metanamesList.add(pos);
+ if (isManifestName(cen, entryPos + META_INF_LENGTH,
+ nlen - META_INF_LENGTH)) {
+ manifestPos = entryPos;
+ } else {
+ if (isSignatureRelated(cen, entryPos, nlen)) {
+ if (signatureNames == null)
+ signatureNames = new ArrayList<>(4);
+ signatureNames.add(pos);
+ }
// If this is a versioned entry, parse the version
// and store it for later. This optimizes lookup
// performance in multi-release jar files
int version = getMetaVersion(cen,
@@ -1489,20 +1523,22 @@
if (metaVersionsSet == null)
metaVersionsSet = new TreeSet<>();
metaVersionsSet.add(version);
}
}
+ }
// skip ext and comment
pos = entryPos + nlen + elen + clen;
entryPos = pos + CENHDR;
i++;
}
total = i;
- if (metanamesList != null) {
- metanames = new int[metanamesList.size()];
- for (int j = 0, len = metanames.length; j < len; j++) {
- metanames[j] = metanamesList.get(j);
+ if (signatureNames != null) {
+ int len = signatureNames.size();
+ signatureMetaNames = new int[len];
+ for (int j = 0; j < len; j++) {
+ signatureMetaNames[j] = signatureNames.get(j);
}
}
if (metaVersionsSet != null) {
metaVersions = new int[metaVersionsSet.size()];
int c = 0;
@@ -1593,10 +1629,49 @@
&& (name[off++] | 0x20) == 'f'
&& (name[off] ) == '/';
}
/*
+ * Check if the bytes represents a name equals to MANIFEST.MF
+ */
+ private static boolean isManifestName(byte[] name, int off, int len) {
+ return (len == 11 // "MANIFEST.MF".length()
+ && (name[off++] | 0x20) == 'm'
+ && (name[off++] | 0x20) == 'a'
+ && (name[off++] | 0x20) == 'n'
+ && (name[off++] | 0x20) == 'i'
+ && (name[off++] | 0x20) == 'f'
+ && (name[off++] | 0x20) == 'e'
+ && (name[off++] | 0x20) == 's'
+ && (name[off++] | 0x20) == 't'
+ && (name[off++] | 0x20) == '.'
+ && (name[off++] | 0x20) == 'm'
+ && (name[off++] | 0x20) == 'f');
+ }
+
+ private boolean isSignatureRelated(byte[] cen, int start, int len) {
+ // Check if entry ends with .EC and .SF
+ if (cen[start + len - 3] == '.') {
+ int b1 = cen[start + len - 2] | 0x20;
+ int b2 = cen[start + len - 1] | 0x20;
+ if ((b1 == 'e' && b2 == 'c') || (b1 == 's' && b2 == 'f')) {
+ return true;
+ }
+ }
+ // Check if entry ends with .DSA and .RSA
+ if (cen[start + len - 4] == '.') {
+ int b1 = cen[start + len - 3] | 0x20;
+ int b2 = cen[start + len - 2] | 0x20;
+ int b3 = cen[start + len - 1] | 0x20;
+ if ((b1 == 'r' || b1 == 'd') && b2 == 's' && b3 == 'a') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
* If the bytes represents a non-directory name beginning
* with "versions/", continuing with a positive integer,
* followed by a '/', then return that integer value.
* Otherwise, return 0
*/
< prev index next >