src/java.base/share/classes/java/util/jar/JarFile.java

Print this page

        

*** 24,33 **** --- 24,34 ---- */ package java.util.jar; import jdk.internal.misc.SharedSecrets; + import jdk.internal.misc.JavaUtilZipFileAccess; import sun.security.action.GetPropertyAction; import sun.security.util.ManifestEntryVerifier; import sun.security.util.SignatureFileVerifier; import java.io.ByteArrayInputStream;
*** 43,56 **** --- 44,59 ---- import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Locale; + import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Spliterator; import java.util.Spliterators; + import java.util.stream.Collector; import java.util.stream.Stream; import java.util.stream.StreamSupport; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile;
*** 161,173 **** --- 164,180 ---- // indicates if Class-Path attribute present private boolean hasClassPathAttribute; // true if manifest checked for special attributes private volatile boolean hasCheckedSpecialAttributes; + private static final JavaUtilZipFileAccess JUZFA; + static { // Set up JavaUtilJarAccess in SharedSecrets SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl()); + // Get JavaUtilZipFileAccess from SharedSecrets + JUZFA = jdk.internal.misc.SharedSecrets.getJavaUtilZipFileAccess(); // multi-release jar file versions >= 9 BASE_VERSION = Runtime.Version.parse(Integer.toString(8)); BASE_VERSION_MAJOR = BASE_VERSION.major(); String jarVersion = GetPropertyAction.privilegedGetProperty("jdk.util.jar.version"); int runtimeVersion = Runtime.version().major();
*** 422,433 **** } return man; } private String[] getMetaInfEntryNames() { ! return jdk.internal.misc.SharedSecrets.getJavaUtilZipFileAccess() ! .getMetaInfEntryNames((ZipFile)this); } /** * Returns the {@code JarEntry} for the given base entry name or * {@code null} if not found. --- 429,439 ---- } return man; } private String[] getMetaInfEntryNames() { ! return JUZFA.getMetaInfEntryNames((ZipFile)this); } /** * Returns the {@code JarEntry} for the given base entry name or * {@code null} if not found.
*** 495,556 **** * If a subclass overrides this method, assure that the override method * invokes {@code super.getEntry(name)} to obtain all versioned entries. * </div> */ public ZipEntry getEntry(String name) { ! ZipEntry ze = super.getEntry(name); ! if (ze != null) { ! return new JarFileEntry(ze); ! } ! // no matching base entry, but maybe there is a versioned entry, ! // like a new private class if (isMultiRelease()) { ! ze = new ZipEntry(name); ! ZipEntry vze = getVersionedEntry(ze); ! if (ze != vze) { ! return new JarFileEntry(name, vze); ! } ! } ! return null; ! } ! ! private class JarEntryIterator implements Enumeration<JarEntry>, ! Iterator<JarEntry> ! { ! final Enumeration<? extends ZipEntry> e = JarFile.super.entries(); ! ! public boolean hasNext() { ! return e.hasMoreElements(); ! } ! ! public JarEntry next() { ! ZipEntry ze = e.nextElement(); ! return new JarFileEntry(ze.getName(), ze); ! } ! ! public boolean hasMoreElements() { ! return hasNext(); ! } ! ! public JarEntry nextElement() { ! return next(); ! } ! ! public Iterator<JarEntry> asIterator() { ! return this; } } /** * Returns an enumeration of the jar file entries. * * @return an enumeration of the jar file entries * @throws IllegalStateException * may be thrown if the jar file has been closed */ public Enumeration<JarEntry> entries() { ! return new JarEntryIterator(); } /** * Returns an ordered {@code Stream} over the jar file entries. * Entries appear in the {@code Stream} in the order they appear in --- 501,526 ---- * If a subclass overrides this method, assure that the override method * invokes {@code super.getEntry(name)} to obtain all versioned entries. * </div> */ public ZipEntry getEntry(String name) { ! JarFileEntry je = getEntry0(name); if (isMultiRelease()) { ! return getVersionedEntry(name, je); } + return je; } /** * Returns an enumeration of the jar file entries. * * @return an enumeration of the jar file entries * @throws IllegalStateException * may be thrown if the jar file has been closed */ public Enumeration<JarEntry> entries() { ! return JUZFA.entries(this, JarFileEntry::new); } /** * Returns an ordered {@code Stream} over the jar file entries. * Entries appear in the {@code Stream} in the order they appear in
*** 559,638 **** * @return an ordered {@code Stream} of entries in this jar file * @throws IllegalStateException if the jar file has been closed * @since 1.8 */ public Stream<JarEntry> stream() { ! return StreamSupport.stream(Spliterators.spliterator( ! new JarEntryIterator(), size(), ! Spliterator.ORDERED | Spliterator.DISTINCT | ! Spliterator.IMMUTABLE | Spliterator.NONNULL), false); ! } ! ! private ZipEntry searchForVersionedEntry(final int version, String name) { ! ZipEntry vze = null; ! String sname = "/" + name; ! int i = version; ! while (i > BASE_VERSION_MAJOR) { ! vze = super.getEntry(META_INF_VERSIONS + i + sname); ! if (vze != null) break; ! i--; } ! return vze; } ! private ZipEntry getVersionedEntry(ZipEntry ze) { ! ZipEntry vze = null; if (BASE_VERSION_MAJOR < versionMajor) { - String name = ze.getName(); if (!name.startsWith(META_INF)) { ! vze = searchForVersionedEntry(versionMajor, name); } } ! return vze == null ? ze : vze; } ! /** ! * Returns the real name of a {@code JarEntry}. If this {@code JarFile} is ! * a multi-release jar file and is configured to be processed as such, the ! * name returned by this method is the path name of the versioned entry ! * that the {@code JarEntry} represents, rather than the path name of the ! * base entry that {@link JarEntry#getName()} returns. If the ! * {@code JarEntry} does not represent a versioned entry, or the ! * jar file is not a multi-release jar file or {@code JarFile} is not ! * configured for processing a multi-release jar file, this method returns ! * the same name that {@link JarEntry#getName()} returns. ! * ! * @param entry the JarEntry ! * @return the real name of the JarEntry ! * @since 9 ! */ String getRealName(JarEntry entry) { ! if (entry instanceof JarFileEntry) { ! return ((JarFileEntry)entry).realName(); ! } ! return entry.getName(); } private class JarFileEntry extends JarEntry { ! final private String name; ! JarFileEntry(ZipEntry ze) { ! super(isMultiRelease() ? getVersionedEntry(ze) : ze); ! this.name = ze.getName(); } JarFileEntry(String name, ZipEntry vze) { super(vze); ! this.name = name; } public Attributes getAttributes() throws IOException { Manifest man = JarFile.this.getManifest(); if (man != null) { return man.getAttributes(super.getName()); } else { return null; } } public Certificate[] getCertificates() { try { maybeInstantiateVerifier(); } catch (IOException e) { throw new RuntimeException(e); --- 529,642 ---- * @return an ordered {@code Stream} of entries in this jar file * @throws IllegalStateException if the jar file has been closed * @since 1.8 */ public Stream<JarEntry> stream() { ! return JUZFA.stream(this, JarFileEntry::new); ! } ! ! /** ! * Returns a {@code Stream} of the versioned jar file entries. ! * ! * <p>If this {@code JarFile} is a multi-release jar file and is configured to ! * be processed as such, then an entry in the stream is the latest versioned entry ! * associated with the corresponding base entry name. The maximum version of the ! * latest versioned entry is the version returned by {@link #getVersion()}. ! * The returned stream may include an entry that only exists as a versioned entry. ! * ! * If the jar file is not a multi-release jar file or the {@code JarFile} is not ! * configured for processing a multi-release jar file, this method returns the ! * same stream that {@link #stream()} returns. ! * ! * @return stream of versioned entries ! * @since 10 ! */ ! public Stream<JarEntry> versionedStream() { ! ! if (isMultiRelease()) { ! return JUZFA.entryNameStream(this).map(this::getBasename) ! .filter(Objects::nonNull) ! .distinct() ! .map(this::getJarEntry); } ! return stream(); } ! /* ! * Invokes {@ZipFile}'s getEntry to Return a {@code JarFileEntry} for the ! * given entry name or {@code null} if not found. ! */ ! private JarFileEntry getEntry0(String name) { ! return (JarFileEntry)JUZFA.getEntry(this, name, JarFileEntry::new); ! } ! ! private String getBasename(String name) { ! if (name.startsWith(META_INF_VERSIONS)) { ! int off = META_INF_VERSIONS.length(); ! int index = name.indexOf('/', off); ! try { ! // filter out dir META-INF/versions/ and META-INF/versions/*/ ! // and any entry with version > 'version' ! if (index == -1 || index == (name.length() - 1) || ! Integer.parseInt(name, off, index, 10) > versionMajor) { ! return null; ! } ! } catch (NumberFormatException x) { ! return null; // remove malformed entries silently ! } ! // map to its base name ! return name.substring(index + 1); ! } ! return name; ! } ! ! private JarEntry getVersionedEntry(String name, JarEntry je) { if (BASE_VERSION_MAJOR < versionMajor) { if (!name.startsWith(META_INF)) { ! // search for versioned entry ! int v = versionMajor; ! while (v > BASE_VERSION_MAJOR) { ! JarFileEntry vje = getEntry0(META_INF_VERSIONS + v + "/" + name); ! if (vje != null) { ! return vje.withBasename(name); ! } ! v--; } } ! } ! return je; } ! // placeholder for now String getRealName(JarEntry entry) { ! return entry.getRealName(); } private class JarFileEntry extends JarEntry { ! private String basename; ! JarFileEntry(String name) { ! super(name); ! this.basename = name; } + JarFileEntry(String name, ZipEntry vze) { super(vze); ! this.basename = name; } + + @Override public Attributes getAttributes() throws IOException { Manifest man = JarFile.this.getManifest(); if (man != null) { return man.getAttributes(super.getName()); } else { return null; } } + + @Override public Certificate[] getCertificates() { try { maybeInstantiateVerifier(); } catch (IOException e) { throw new RuntimeException(e);
*** 640,649 **** --- 644,655 ---- if (certs == null && jv != null) { certs = jv.getCerts(JarFile.this, realEntry()); } return certs == null ? null : certs.clone(); } + + @Override public CodeSigner[] getCodeSigners() { try { maybeInstantiateVerifier(); } catch (IOException e) { throw new RuntimeException(e);
*** 651,674 **** if (signers == null && jv != null) { signers = jv.getCodeSigners(JarFile.this, realEntry()); } return signers == null ? null : signers.clone(); } JarFileEntry realEntry() { if (isMultiRelease() && versionMajor != BASE_VERSION_MAJOR) { String entryName = super.getName(); ! return entryName.equals(this.name) ? this : new JarFileEntry(entryName, this); } return this; } - String realName() { - return super.getName(); - } ! @Override ! public String getName() { ! return name; } } /* * Ensures that the JarVerifier has been created if one is --- 657,690 ---- if (signers == null && jv != null) { signers = jv.getCodeSigners(JarFile.this, realEntry()); } return signers == null ? null : signers.clone(); } + + @Override + public String getRealName() { + return super.getName(); + } + + @Override + public String getName() { + return basename; + } + JarFileEntry realEntry() { if (isMultiRelease() && versionMajor != BASE_VERSION_MAJOR) { String entryName = super.getName(); ! return entryName == basename || entryName.equals(basename) ? ! this : new JarFileEntry(entryName, this); } return this; } ! // changes the basename, returns "this" ! JarFileEntry withBasename(String name) { ! basename = name; ! return this; } } /* * Ensures that the JarVerifier has been created if one is
*** 702,712 **** // verifier verify = false; } } - /* * Initializes the verifier object by reading all the manifest * entries and passing them to the verifier. */ private void initializeVerifier() { --- 718,727 ----
*** 902,928 **** } private JarEntry getManEntry() { if (manEntry == null) { // First look up manifest entry using standard name ! ZipEntry manEntry = super.getEntry(MANIFEST_NAME); if (manEntry == null) { // If not found, then iterate through all the "META-INF/" // entries to find a match. String[] names = getMetaInfEntryNames(); if (names != null) { for (String name : names) { if (MANIFEST_NAME.equals(name.toUpperCase(Locale.ENGLISH))) { ! manEntry = super.getEntry(name); break; } } } } ! this.manEntry = (manEntry == null) ! ? null ! : new JarFileEntry(manEntry.getName(), manEntry); } return manEntry; } /** --- 917,941 ---- } private JarEntry getManEntry() { if (manEntry == null) { // First look up manifest entry using standard name ! JarEntry manEntry = getEntry0(MANIFEST_NAME); if (manEntry == null) { // If not found, then iterate through all the "META-INF/" // entries to find a match. String[] names = getMetaInfEntryNames(); if (names != null) { for (String name : names) { if (MANIFEST_NAME.equals(name.toUpperCase(Locale.ENGLISH))) { ! manEntry = getEntry0(name); break; } } } } ! this.manEntry = manEntry; } return manEntry; } /**
*** 1030,1041 **** initializeVerifier(); jvInitialized = true; } } ! JarEntry newEntry(ZipEntry ze) { ! return new JarFileEntry(ze); } Enumeration<String> entryNames(CodeSource[] cs) { ensureInitialization(); if (jv != null) { --- 1043,1078 ---- initializeVerifier(); jvInitialized = true; } } ! /* ! * Returns a versioned {@code JarFileEntry} for the given entry, ! * if there is one. Otherwise returns the original entry. This ! * is invoked by the {@code entries2} for verifier. ! */ ! JarEntry newEntry(JarEntry je) { ! if (isMultiRelease()) { ! return getVersionedEntry(je.getName(), je); ! } ! return je; ! } ! ! /* ! * Returns a versioned {@code JarFileEntry} for the given entry ! * name, if there is one. Otherwise returns a {@code JarFileEntry} ! * with the given name. It is invoked from JarVerifier's entries2 ! * for {@code singers}. ! */ ! JarEntry newEntry(String name) { ! if (isMultiRelease()) { ! JarEntry vje = getVersionedEntry(name, (JarEntry)null); ! if (vje != null) { ! return vje; ! } ! } ! return new JarFileEntry(name); } Enumeration<String> entryNames(CodeSource[] cs) { ensureInitialization(); if (jv != null) {
*** 1075,1113 **** * signed entries missing from the ZIP directory. */ Enumeration<JarEntry> entries2() { ensureInitialization(); if (jv != null) { ! return jv.entries2(this, super.entries()); } // screen out entries which are never signed ! final Enumeration<? extends ZipEntry> enum_ = super.entries(); return new Enumeration<>() { ! ZipEntry entry; public boolean hasMoreElements() { if (entry != null) { return true; } ! while (enum_.hasMoreElements()) { ! ZipEntry ze = enum_.nextElement(); ! if (JarVerifier.isSigningRelated(ze.getName())) { continue; } ! entry = ze; return true; } return false; } ! public JarFileEntry nextElement() { if (hasMoreElements()) { ! ZipEntry ze = entry; entry = null; ! return new JarFileEntry(ze); } throw new NoSuchElementException(); } }; } --- 1112,1152 ---- * signed entries missing from the ZIP directory. */ Enumeration<JarEntry> entries2() { ensureInitialization(); if (jv != null) { ! return jv.entries2(this, JUZFA.entries(JarFile.this, ! JarFileEntry::new)); } // screen out entries which are never signed ! final var unfilteredEntries = JUZFA.entries(JarFile.this, JarFileEntry::new); ! return new Enumeration<>() { ! JarEntry entry; public boolean hasMoreElements() { if (entry != null) { return true; } ! while (unfilteredEntries.hasMoreElements()) { ! JarEntry je = unfilteredEntries.nextElement(); ! if (JarVerifier.isSigningRelated(je.getName())) { continue; } ! entry = je; return true; } return false; } ! public JarEntry nextElement() { if (hasMoreElements()) { ! JarEntry je = entry; entry = null; ! return newEntry(je); } throw new NoSuchElementException(); } }; }