18a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak/* 28a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * Copyright (C) 2013 The Android Open Source Project 38a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * 48a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * Licensed under the Apache License, Version 2.0 (the "License"); 58a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * you may not use this file except in compliance with the License. 68a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * You may obtain a copy of the License at 78a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * 88a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * http://www.apache.org/licenses/LICENSE-2.0 98a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * 108a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * Unless required by applicable law or agreed to in writing, software 118a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * distributed under the License is distributed on an "AS IS" BASIS, 128a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * See the License for the specific language governing permissions and 148a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * limitations under the License. 158a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak */ 168a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 178a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 188a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakpackage android.util.jar; 198a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 206c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewskiimport android.system.ErrnoException; 216c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewskiimport android.system.Os; 226c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewskiimport android.system.OsConstants; 236c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski 248a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport dalvik.system.CloseGuard; 256c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewskiimport java.io.FileDescriptor; 268a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.io.FilterInputStream; 278a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.io.IOException; 288a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.io.InputStream; 298a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.security.cert.Certificate; 308a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.HashMap; 318a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.Iterator; 328a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.Set; 336c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewskiimport java.util.jar.JarFile; 348a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.zip.Inflater; 358a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.zip.InflaterInputStream; 368a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.zip.ZipEntry; 376c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewskiimport libcore.io.IoBridge; 388a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport libcore.io.IoUtils; 398a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport libcore.io.Streams; 408a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 418a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak/** 428a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * A subset of the JarFile API implemented as a thin wrapper over 438a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * system/core/libziparchive. 448a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * 458a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * @hide for internal use only. Not API compatible (or as forgiving) as 468a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * {@link java.util.jar.JarFile} 478a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak */ 488a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakpublic final class StrictJarFile { 498a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 508a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private final long nativeHandle; 518a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 528a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // NOTE: It's possible to share a file descriptor with the native 538a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // code, at the cost of some additional complexity. 546c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski private final FileDescriptor fd; 558a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 568a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private final StrictJarManifest manifest; 578a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private final StrictJarVerifier verifier; 588a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 598a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private final boolean isSigned; 608a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 618a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private final CloseGuard guard = CloseGuard.get(); 628a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private boolean closed; 638a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 64e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin public StrictJarFile(String fileName) 65e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin throws IOException, SecurityException { 669b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin this(fileName, true, true); 67e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin } 68e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin 696c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski public StrictJarFile(FileDescriptor fd) 706c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski throws IOException, SecurityException { 716c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski this(fd, true, true); 726c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski } 736c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski 746c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski public StrictJarFile(FileDescriptor fd, 756c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski boolean verify, 766c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski boolean signatureSchemeRollbackProtectionsEnforced) 776c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski throws IOException, SecurityException { 786c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski this("[fd:" + fd.getInt$() + "]", fd, verify, 796c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski signatureSchemeRollbackProtectionsEnforced); 806c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski } 816c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski 826c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski public StrictJarFile(String fileName, 836c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski boolean verify, 846c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski boolean signatureSchemeRollbackProtectionsEnforced) 856c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski throws IOException, SecurityException { 866c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski this(fileName, IoBridge.open(fileName, OsConstants.O_RDONLY), 876c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski verify, signatureSchemeRollbackProtectionsEnforced); 886c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski } 896c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski 909b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin /** 916c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski * @param name of the archive (not necessarily a path). 926c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski * @param fd seekable file descriptor for the JAR file. 939b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin * @param verify whether to verify the file's JAR signatures and collect the corresponding 949b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin * signer certificates. 959b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin * @param signatureSchemeRollbackProtectionsEnforced {@code true} to enforce protections against 969b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin * stripping newer signature schemes (e.g., APK Signature Scheme v2) from the file, or 979b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin * {@code false} to ignore any such protections. This parameter is ignored when 989b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin * {@code verify} is {@code false}. 999b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin */ 1006c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski private StrictJarFile(String name, 1016c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski FileDescriptor fd, 1029b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin boolean verify, 1039b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin boolean signatureSchemeRollbackProtectionsEnforced) 1049b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin throws IOException, SecurityException { 1056c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski this.nativeHandle = nativeOpenJarFile(name, fd.getInt$()); 1066c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski this.fd = fd; 1078a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1088a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak try { 1098a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // Read the MANIFEST and signature files up front and try to 1108a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // parse them. We never want to accept a JAR File with broken signatures 1118a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // or manifests, so it's best to throw as early as possible. 112e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin if (verify) { 113e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin HashMap<String, byte[]> metaEntries = getMetaEntries(); 114e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin this.manifest = new StrictJarManifest(metaEntries.get(JarFile.MANIFEST_NAME), true); 1159b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin this.verifier = 1169b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin new StrictJarVerifier( 1176c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski name, 1189b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin manifest, 1199b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin metaEntries, 1209b59bc459b4cb5415909641bd1e981100bfafb2bAlex Klyubin signatureSchemeRollbackProtectionsEnforced); 121e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin Set<String> files = manifest.getEntries().keySet(); 122e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin for (String file : files) { 123e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin if (findEntry(file) == null) { 1246c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski throw new SecurityException("File " + file + " in manifest does not exist"); 125e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin } 1268a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 1278a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 128e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin isSigned = verifier.readCertificates() && verifier.isSignedJar(); 129e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin } else { 130e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin isSigned = false; 131e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin this.manifest = null; 132e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin this.verifier = null; 133e415718502897a4e5385af47d3bbe8c8257c2e5dAlex Klyubin } 1348a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } catch (IOException | SecurityException e) { 1358a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak nativeClose(this.nativeHandle); 1366c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski IoUtils.closeQuietly(fd); 137b061fc2bb5b6e8397c7f3a40be521badad91e9afTomasz Mikolajewski closed = true; 1388a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak throw e; 1398a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 1408a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1418a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak guard.open("close"); 1428a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 1438a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1448a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public StrictJarManifest getManifest() { 1458a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return manifest; 1468a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 1478a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1488a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public Iterator<ZipEntry> iterator() throws IOException { 1498a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return new EntryIterator(nativeHandle, ""); 1508a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 1518a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1528a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public ZipEntry findEntry(String name) { 1538a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return nativeFindEntry(nativeHandle, name); 1548a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 1558a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1568a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak /** 1578a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * Return all certificate chains for a given {@link ZipEntry} belonging to this jar. 1588a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * This method MUST be called only after fully exhausting the InputStream belonging 1598a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * to this entry. 1608a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * 1618a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * Returns {@code null} if this jar file isn't signed or if this method is 1628a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * called before the stream is processed. 1638a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak */ 1648a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public Certificate[][] getCertificateChains(ZipEntry ze) { 1658a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (isSigned) { 1668a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return verifier.getCertificateChains(ze.getName()); 1678a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 1688a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1698a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return null; 1708a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 1718a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1728a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak /** 1738a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * Return all certificates for a given {@link ZipEntry} belonging to this jar. 1748a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * This method MUST be called only after fully exhausting the InputStream belonging 1758a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * to this entry. 1768a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * 1778a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * Returns {@code null} if this jar file isn't signed or if this method is 1788a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * called before the stream is processed. 1798a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * 1808a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * @deprecated Switch callers to use getCertificateChains instead 1818a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak */ 1828a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Deprecated 1838a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public Certificate[] getCertificates(ZipEntry ze) { 1848a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (isSigned) { 1858a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak Certificate[][] certChains = verifier.getCertificateChains(ze.getName()); 1868a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1878a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // Measure number of certs. 1888a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak int count = 0; 1898a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak for (Certificate[] chain : certChains) { 1908a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak count += chain.length; 1918a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 1928a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 1938a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // Create new array and copy all the certs into it. 1948a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak Certificate[] certs = new Certificate[count]; 1958a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak int i = 0; 1968a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak for (Certificate[] chain : certChains) { 1978a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak System.arraycopy(chain, 0, certs, i, chain.length); 1988a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak i += chain.length; 1998a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2008a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2018a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return certs; 2028a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2038a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2048a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return null; 2058a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2068a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2078a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public InputStream getInputStream(ZipEntry ze) { 2088a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak final InputStream is = getZipInputStream(ze); 2098a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2108a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (isSigned) { 2118a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak StrictJarVerifier.VerifierEntry entry = verifier.initEntry(ze.getName()); 2128a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (entry == null) { 2138a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return is; 2148a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2158a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2168a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return new JarFileInputStream(is, ze.getSize(), entry); 2178a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2188a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2198a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return is; 2208a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2218a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2228a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public void close() throws IOException { 2238a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (!closed) { 2246c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski if (guard != null) { 2256c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski guard.close(); 2266c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski } 2278a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2288a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak nativeClose(nativeHandle); 2296c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski IoUtils.closeQuietly(fd); 2308a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak closed = true; 2318a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2328a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2338a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 234b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller @Override 235b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller protected void finalize() throws Throwable { 236b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller try { 237b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller if (guard != null) { 238b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller guard.warnIfOpen(); 239b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller } 240b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller close(); 241b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller } finally { 242b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller super.finalize(); 243b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller } 244b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller } 245b69f61472a25cff07cb9cc139e26e50c5af20394Neil Fuller 2468a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private InputStream getZipInputStream(ZipEntry ze) { 2478a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (ze.getMethod() == ZipEntry.STORED) { 2486c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski return new FDStream(fd, ze.getDataOffset(), 2498a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak ze.getDataOffset() + ze.getSize()); 2508a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } else { 2516c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski final FDStream wrapped = new FDStream( 2526c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski fd, ze.getDataOffset(), ze.getDataOffset() + ze.getCompressedSize()); 2538a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2548a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak int bufSize = Math.max(1024, (int) Math.min(ze.getSize(), 65535L)); 2558a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return new ZipInflaterInputStream(wrapped, new Inflater(true), bufSize, ze); 2568a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2578a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2588a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2598a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak static final class EntryIterator implements Iterator<ZipEntry> { 2608a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private final long iterationHandle; 2618a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private ZipEntry nextEntry; 2628a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2638a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak EntryIterator(long nativeHandle, String prefix) throws IOException { 2648a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak iterationHandle = nativeStartIteration(nativeHandle, prefix); 2658a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2668a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2678a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public ZipEntry next() { 2688a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (nextEntry != null) { 2698a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak final ZipEntry ze = nextEntry; 2708a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak nextEntry = null; 2718a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return ze; 2728a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2738a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2748a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return nativeNextEntry(iterationHandle); 2758a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2768a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2778a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public boolean hasNext() { 2788a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (nextEntry != null) { 2798a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return true; 2808a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2818a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2828a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak final ZipEntry ze = nativeNextEntry(iterationHandle); 2838a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (ze == null) { 2848a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return false; 2858a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2868a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2878a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak nextEntry = ze; 2888a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return true; 2898a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2908a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2918a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public void remove() { 2928a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak throw new UnsupportedOperationException(); 2938a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2948a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 2958a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2968a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private HashMap<String, byte[]> getMetaEntries() throws IOException { 2978a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak HashMap<String, byte[]> metaEntries = new HashMap<String, byte[]>(); 2988a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 2998a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak Iterator<ZipEntry> entryIterator = new EntryIterator(nativeHandle, "META-INF/"); 3008a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak while (entryIterator.hasNext()) { 3018a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak final ZipEntry entry = entryIterator.next(); 3028a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak metaEntries.put(entry.getName(), Streams.readFully(getInputStream(entry))); 3038a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3048a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3058a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return metaEntries; 3068a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3078a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3088a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak static final class JarFileInputStream extends FilterInputStream { 3098a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private final StrictJarVerifier.VerifierEntry entry; 3108a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3118a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private long count; 3128a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private boolean done = false; 3138a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3148a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak JarFileInputStream(InputStream is, long size, StrictJarVerifier.VerifierEntry e) { 3158a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak super(is); 3168a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak entry = e; 3178a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3188a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak count = size; 3198a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3208a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3218a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override 3228a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public int read() throws IOException { 3238a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (done) { 3248a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return -1; 3258a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3268a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (count > 0) { 3278a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak int r = super.read(); 3288a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (r != -1) { 3298a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak entry.write(r); 3308a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak count--; 3318a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } else { 3328a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak count = 0; 3338a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3348a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (count == 0) { 3358a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak done = true; 3368a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak entry.verify(); 3378a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3388a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return r; 3398a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } else { 3408a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak done = true; 3418a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak entry.verify(); 3428a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return -1; 3438a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3448a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3458a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3468a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override 3478a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 3488a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (done) { 3498a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return -1; 3508a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3518a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (count > 0) { 3528a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak int r = super.read(buffer, byteOffset, byteCount); 3538a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (r != -1) { 3548a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak int size = r; 3558a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (count < size) { 3568a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak size = (int) count; 3578a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3588a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak entry.write(buffer, byteOffset, size); 3598a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak count -= size; 3608a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } else { 3618a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak count = 0; 3628a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3638a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (count == 0) { 3648a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak done = true; 3658a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak entry.verify(); 3668a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3678a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return r; 3688a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } else { 3698a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak done = true; 3708a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak entry.verify(); 3718a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return -1; 3728a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3738a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3748a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3758a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override 3768a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public int available() throws IOException { 3778a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (done) { 3788a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return 0; 3798a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3808a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return super.available(); 3818a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3828a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3838a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override 3848a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public long skip(long byteCount) throws IOException { 3858a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return Streams.skipByReading(this, byteCount); 3868a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3878a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3888a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3898a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak /** @hide */ 3908a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public static class ZipInflaterInputStream extends InflaterInputStream { 3918a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private final ZipEntry entry; 3928a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private long bytesRead = 0; 3938a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3948a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak public ZipInflaterInputStream(InputStream is, Inflater inf, int bsize, ZipEntry entry) { 3958a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak super(is, inf, bsize); 3968a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak this.entry = entry; 3978a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 3988a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 3998a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 4008a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak final int i; 4018a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak try { 4028a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak i = super.read(buffer, byteOffset, byteCount); 4038a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } catch (IOException e) { 4048a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak throw new IOException("Error reading data for " + entry.getName() + " near offset " 4058a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak + bytesRead, e); 4068a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4078a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (i == -1) { 4088a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (entry.getSize() != bytesRead) { 4098a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak throw new IOException("Size mismatch on inflated file: " + bytesRead + " vs " 4108a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak + entry.getSize()); 4118a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4128a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } else { 4138a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak bytesRead += i; 4148a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4158a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return i; 4168a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4178a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 4188a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override public int available() throws IOException { 4198a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (closed) { 4208a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // Our superclass will throw an exception, but there's a jtreg test that 4218a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // explicitly checks that the InputStream returned from ZipFile.getInputStream 4228a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak // returns 0 even when closed. 4238a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return 0; 4248a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4258a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return super.available() == 0 ? 0 : (int) (entry.getSize() - bytesRead); 4268a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4278a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4288a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 4298a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak /** 4306c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski * Wrap a stream around a FileDescriptor. The file descriptor is shared 4318a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * among all streams returned by getInputStream(), so we have to synchronize 4328a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * access to it. (We can optimize this by adding buffering here to reduce 4338a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * collisions.) 4348a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * 4358a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * <p>We could support mark/reset, but we don't currently need them. 4368a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * 4378a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * @hide 4388a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak */ 4396c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski public static class FDStream extends InputStream { 4406c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski private final FileDescriptor fd; 4418a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private long endOffset; 4428a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private long offset; 4438a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 4446c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski public FDStream(FileDescriptor fd, long initialOffset, long endOffset) { 4456c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski this.fd = fd; 4468a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak offset = initialOffset; 4478a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak this.endOffset = endOffset; 4488a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4498a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 4508a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override public int available() throws IOException { 4518a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return (offset < endOffset ? 1 : 0); 4528a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4538a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 4548a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override public int read() throws IOException { 4558a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return Streams.readSingleByte(this); 4568a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4578a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 4588a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 4596c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski synchronized (this.fd) { 4608a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak final long length = endOffset - offset; 4618a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (byteCount > length) { 4628a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak byteCount = (int) length; 4638a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4646c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski try { 4656c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski Os.lseek(fd, offset, OsConstants.SEEK_SET); 4666c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski } catch (ErrnoException e) { 4676c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski throw new IOException(e); 4686c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski } 4696c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski int count = IoBridge.read(fd, buffer, byteOffset, byteCount); 4708a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (count > 0) { 4718a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak offset += count; 4728a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return count; 4738a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } else { 4748a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return -1; 4758a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4768a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4778a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4788a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 4798a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak @Override public long skip(long byteCount) throws IOException { 4808a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak if (byteCount > endOffset - offset) { 4818a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak byteCount = endOffset - offset; 4828a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4838a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak offset += byteCount; 4848a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak return byteCount; 4858a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4868a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak } 4878a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak 4886c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski private static native long nativeOpenJarFile(String name, int fd) 4896c3df1543cb85d5ff7ebb2b026d7a34184465c7bTomasz Mikolajewski throws IOException; 4908a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private static native long nativeStartIteration(long nativeHandle, String prefix); 4918a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private static native ZipEntry nativeNextEntry(long iterationHandle); 4928a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private static native ZipEntry nativeFindEntry(long nativeHandle, String entryName); 4938a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak private static native void nativeClose(long nativeHandle); 4948a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak} 495