/
githubmirror
/
riscv-port
Обзор
Документация
Войти
/
githubmirror
/
riscv-port
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.base/share/classes/java/util/jar/JarInputStream.java
296 строк
12 KB
Sergey Bylokhov
8374327: Update copyright year to 2025 for files in java.base added/updated by commits in 2025
31 дек 2025, 12:13
31 дек 2025, 12:13
36d2c27
Код
Авторство
О чём код?
/* * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util.jar; import java.util.zip.*; import java.io.*; import sun.security.util.ManifestEntryVerifier; /** * The {@code JarInputStream} class, which extends {@link ZipInputStream}, * is used to read the contents of a JAR file from an input stream. * It provides support for reading an optional * <a href="{@docRoot}/../specs/jar/jar.html#jar-manifest">Manifest</a> * entry. The {@code Manifest} can be used to store * meta-information about the JAR file and its entries. * <p> * Unless otherwise noted, passing a {@code null} argument to a constructor * or method in this class will cause a {@link NullPointerException} to be * thrown. * </p> * <h2>Accessing the Manifest</h2> * <p> * The {@link #getManifest() getManifest} method is used to return the * <a href="{@docRoot}/../specs/jar/jar.html#jar-manifest">Manifest</a> * from the entry {@code META-INF/MANIFEST.MF} when it is the first entry * in the stream (or the second entry if the first entry in the stream is * {@code META-INF/} and the second entry is {@code META-INF/MANIFEST.MF}). * </p> * <p> The {@link #getNextJarEntry()} and {@link #getNextEntry()} methods are * used to read JAR file entries from the stream. These methods skip over the * Manifest ({@code META-INF/MANIFEST.MF}) when it is at the beginning of the * stream. In other words, these methods do not return an entry for the Manifest * when the Manifest is the first entry in the stream. If the first entry is * {@code META-INF/} and the second entry is the Manifest then both are skipped * over by these methods. Whether these methods skip over the Manifest when it * appears later in the stream is not specified. * </p> * <h2>Signed JAR Files</h2> * * A {@code JarInputStream} verifies the signatures of entries in a * <a href="{@docRoot}/../specs/jar/jar.html#signed-jar-file">Signed JAR file</a> * when: * <ul> * <li> * The {@code Manifest} is the first entry in the stream (or the second * entry if the first entry in the stream is {@code META-INF/} and the * second entry is {@code META-INF/MANIFEST.MF}). * </li> * <li> * All signature-related entries immediately follow the {@code Manifest} * </li> * </ul> * <p> * Once the {@code JarEntry} has been completely verified, which is done by * reading until the end of the entry's input stream, * {@link JarEntry#getCertificates()} may be called to obtain the certificates * for this entry and {@link JarEntry#getCodeSigners()} may be called to obtain * the signers. * </p> * <p> * It is important to note that the verification process does not include validating * the signer's certificate. A caller should inspect the return value of * {@link JarEntry#getCodeSigners()} to further determine if the signature * can be trusted. * </p> * @apiNote * If a {@code JarEntry} is modified after the JAR file is signed, * a {@link SecurityException} will be thrown when the entry is read. * * @author David Connelly * @see Manifest * @see java.util.zip.ZipInputStream * @since 1.2 */ public class JarInputStream extends ZipInputStream { private Manifest man; private JarEntry first; private JarVerifier jv; private ManifestEntryVerifier mev; private final boolean doVerify; private boolean tryManifest; /** * Creates a new {@code JarInputStream} and reads the optional * manifest. If a manifest is present, also attempts to verify * the signatures if the JarInputStream is signed. * @param in the actual input stream * @throws IOException if an I/O error has occurred */ public JarInputStream(InputStream in) throws IOException { this(in, true); } /** * Creates a new {@code JarInputStream} and reads the optional * manifest. If a manifest is present and verify is true, also attempts * to verify the signatures if the JarInputStream is signed. * * @param in the actual input stream * @param verify whether or not to verify the JarInputStream if * it is signed. * @throws IOException if an I/O error has occurred */ @SuppressWarnings("this-escape") public JarInputStream(InputStream in, boolean verify) throws IOException { super(in); this.doVerify = verify; // 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. JarEntry e = (JarEntry)super.getNextEntry(); if (e != null && e.getName().equalsIgnoreCase("META-INF/")) e = (JarEntry)super.getNextEntry(); first = checkManifest(e); } private JarEntry checkManifest(JarEntry e) throws IOException { if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) { man = new Manifest(); byte[] bytes = readAllBytes(); man.read(new ByteArrayInputStream(bytes)); closeEntry(); if (doVerify) { jv = new JarVerifier(e.getName(), bytes); mev = new ManifestEntryVerifier(man, jv.manifestName); } JarEntry nextEntry = (JarEntry)super.getNextEntry(); if (nextEntry != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(nextEntry.getName())) { if (JarVerifier.debug != null) { JarVerifier.debug.println(JarVerifier.MULTIPLE_MANIFEST_WARNING); } jv = null; mev = null; } return nextEntry; } return e; } /** * Returns the {@code Manifest} for this JAR file when it is the first entry * in the stream (or the second entry if the first entry in the stream is * {@code META-INF/} and the second entry is {@code META-INF/MANIFEST.MF}), or * {@code null} otherwise. * * @return the {@code Manifest} for this JAR file, or * {@code null} otherwise. */ public Manifest getManifest() { return man; } /** * Reads the next ZIP file entry and positions the stream at the * beginning of the entry data. If verification has been enabled, * any invalid signature detected while positioning the stream for * the next entry will result in an exception. * @throws ZipException if a ZIP file error has occurred * @throws IOException if an I/O error has occurred * @throws SecurityException if any of the jar file entries * are incorrectly signed. */ public ZipEntry getNextEntry() throws IOException { JarEntry e; if (first == null) { e = (JarEntry)super.getNextEntry(); if (tryManifest) { e = checkManifest(e); tryManifest = false; } } else { e = first; if (first.getName().equalsIgnoreCase(JarFile.INDEX_NAME)) tryManifest = true; first = null; } if (jv != null && e != null) { // At this point, we might have parsed all the meta-inf // entries and have nothing to verify. If we have // nothing to verify, get rid of the JarVerifier object. if (jv.nothingToVerify() == true) { jv = null; mev = null; } else { jv.beginEntry(e, mev); } } return e; } /** * Reads the next JAR file entry and positions the stream at the * beginning of the entry data. If verification has been enabled, * any invalid signature detected while positioning the stream for * the next entry will result in an exception. * @return the next JAR file entry, or null if there are no more entries * @throws ZipException if a ZIP file error has occurred * @throws IOException if an I/O error has occurred * @throws SecurityException if any of the jar file entries * are incorrectly signed. */ public JarEntry getNextJarEntry() throws IOException { return (JarEntry)getNextEntry(); } /** * Reads from the current JAR entry into an array of bytes, returning the number of * inflated bytes. If {@code len} is not zero, the method blocks until some input is * available; otherwise, no bytes are read and {@code 0} is returned. * <p> * If the current entry is compressed and this method returns a nonzero * integer <i>n</i> then {@code buf[off]} * through {@code buf[off+}<i>n</i>{@code -1]} contain the uncompressed * data. The content of elements {@code buf[off+}<i>n</i>{@code ]} through * {@code buf[off+}<i>len</i>{@code -1]} is undefined, contrary to the * specification of the {@link java.io.InputStream InputStream} superclass, * so an implementation is free to modify these elements during the inflate * operation. If this method returns {@code -1} or throws an exception then * the content of {@code buf[off]} through {@code buf[off+}<i>len</i>{@code * -1]} is undefined. * <p> * If verification has been enabled, any invalid signature * on the current entry will be reported at some point before the * end of the entry is reached. * @param b the buffer into which the data is read * @param off the start offset in the destination array {@code b} * @param len the maximum number of bytes to read * @return the actual number of bytes read, or -1 if the end of the * entry is reached * @throws IndexOutOfBoundsException If {@code off} is negative, * {@code len} is negative, or {@code len} is greater than * {@code b.length - off} * @throws ZipException if a ZIP file error has occurred * @throws IOException if an I/O error has occurred * @throws SecurityException if any of the jar file entries * are incorrectly signed. */ public int read(byte[] b, int off, int len) throws IOException { int n; if (first == null) { n = super.read(b, off, len); } else { n = -1; } if (jv != null) { jv.update(n, b, off, len, mev); } return n; } /** * Creates a new {@code JarEntry} ({@code ZipEntry}) for the * specified JAR file entry name. The manifest attributes of * the specified JAR file entry name will be copied to the new * <CODE>JarEntry</CODE>. * * @param name the name of the JAR/ZIP file entry * @return the {@code JarEntry} object just created */ protected ZipEntry createZipEntry(String name) { JarEntry e = new JarEntry(name); if (man != null) { e.attr = man.getAttributes(name); } return e; } }