1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License. 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License. 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 168911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Read-only access to Zip archives, with minimal heap allocation. 19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "ZipArchive.h" 21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <zlib.h> 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdlib.h> 258911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden#include <unistd.h> 26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <string.h> 27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <fcntl.h> 28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <errno.h> 29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 308911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd 318911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 32bf0cce6d471ffcd65161eca6e027e1b66f02f054Raphael#ifndef O_BINARY 33bf0cce6d471ffcd65161eca6e027e1b66f02f054Raphael#define O_BINARY 0 34bf0cce6d471ffcd65161eca6e027e1b66f02f054Raphael#endif 35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Zip file constants. 38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kEOCDSignature 0x06054b50 40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kEOCDLen 22 41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kEOCDNumEntries 8 // offset to #of entries in file 428911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden#define kEOCDSize 12 // size of the central directory 43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kEOCDFileOffset 16 // offset to central directory 44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kMaxCommentLen 65535 // longest possible in ushort 46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kMaxEOCDSearch (kMaxCommentLen + kEOCDLen) 47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kLFHSignature 0x04034b50 49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kLFHLen 30 // excluding variable-len fields 50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kLFHNameLen 26 // offset to filename length 51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kLFHExtraLen 28 // offset to extra length 52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDESignature 0x02014b50 54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDELen 46 // excluding variable-len fields 55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDEMethod 10 // offset to compression method 56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDEModWhen 12 // offset to modification timestamp 57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDECRC 16 // offset to entry CRC 58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDECompLen 20 // offset to compressed length 59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDEUncompLen 24 // offset to uncompressed length 60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDENameLen 28 // offset to filename length 61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDEExtraLen 30 // offset to extra length 62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDECommentLen 32 // offset to comment length 63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kCDELocalOffset 42 // offset to local hdr 64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The values we return for ZipEntry use 0 as an invalid value, so we 67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * want to adjust the hash table index by a fixed amount. Using a large 68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * value helps insure that people don't mix & match arguments, e.g. with 69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * entry indices. 70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kZipEntryAdj 10000 72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Convert a ZipEntry to a hash table index, verifying that it's in a 75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * valid range. 76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int entryToIndex(const ZipArchive* pArchive, const ZipEntry entry) 78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project long ent = ((long) entry) - kZipEntryAdj; 80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (ent < 0 || ent >= pArchive->mHashTableSize || 81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mHashTable[ent].name == NULL) 82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 83e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: invalid ZipEntry %p (%ld)", entry, ent); 84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return ent; 87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Simple string hash function for non-null-terminated strings. 91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic unsigned int computeHash(const char* str, int len) 93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unsigned int hash = 0; 95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (len--) 97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project hash = hash * 31 + *str++; 98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return hash; 100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Add a new entry to the hash table. 104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void addToHash(ZipArchive* pArchive, const char* str, int strLen, 106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unsigned int hash) 107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const int hashTableSize = pArchive->mHashTableSize; 109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int ent = hash & (hashTableSize - 1); 110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We over-allocated the table, so we're guaranteed to find an empty slot. 113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (pArchive->mHashTable[ent].name != NULL) 115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ent = (ent + 1) & (hashTableSize-1); 116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mHashTable[ent].name = str; 118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mHashTable[ent].nameLen = strLen; 119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get 2 little-endian bytes. 123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic u2 get2LE(unsigned char const* pSrc) 125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 126de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro return pSrc[0] | (pSrc[1] << 8); 127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get 4 little-endian bytes. 131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic u4 get4LE(unsigned char const* pSrc) 133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project u4 result; 135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project result = pSrc[0]; 137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project result |= pSrc[1] << 8; 138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project result |= pSrc[2] << 16; 139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project result |= pSrc[3] << 24; 140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return result; 142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 144a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornsteinstatic int mapCentralDirectory0(int fd, const char* debugFileName, 145d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown ZipArchive* pArchive, off_t fileLength, size_t readAmount, u1* scanBuf) 146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 1478911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden off_t searchStart = fileLength - readAmount; 1488911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 1498911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (lseek(fd, searchStart, SEEK_SET) != searchStart) { 150e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: seek %ld failed: %s", (long) searchStart, strerror(errno)); 151a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein return -1; 1528911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 1538911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, readAmount)); 1548911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (actual != (ssize_t) readAmount) { 155e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: read %zd failed: %s", readAmount, strerror(errno)); 156a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein return -1; 157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1608911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Scan backward for the EOCD magic. In an archive without a trailing 1618911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * comment, we'll find it on the first try. (We may want to consider 1628911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * doing an initial minimal read; if we don't find it, retry with a 1638911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * second read as above.) 164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1658911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden int i; 1668911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden for (i = readAmount - kEOCDLen; i >= 0; i--) { 1678911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) { 16892c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("+++ Found EOCD at buf+%d", i); 169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project break; 1708911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 1728911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (i < 0) { 173062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("Zip: EOCD not found, %s is not zip", debugFileName); 174a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein return -1; 175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 1778911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden off_t eocdOffset = searchStart + i; 1788911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden const u1* eocdPtr = scanBuf + i; 1798911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 1808911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden assert(eocdOffset < fileLength); 1818911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 1838911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Grab the CD offset and size, and the number of entries in the 1848911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * archive. Verify that they look reasonable. 185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1868911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden u4 numEntries = get2LE(eocdPtr + kEOCDNumEntries); 1878911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden u4 dirSize = get4LE(eocdPtr + kEOCDSize); 1888911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden u4 dirOffset = get4LE(eocdPtr + kEOCDFileOffset); 1898911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 1908911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) { 191e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: bad offsets (dir %ld, size %u, eocd %ld)", 1928911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden (long) dirOffset, dirSize, (long) eocdOffset); 193a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein return -1; 1948911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 1958911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (numEntries == 0) { 196e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: empty archive?"); 197a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein return -1; 1988911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 20092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("+++ numEntries=%d dirSize=%d dirOffset=%d", 2018911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden numEntries, dirSize, dirOffset); 202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2038911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden /* 2048911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * It all looks good. Create a mapping for the CD, and set the fields 2058911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * in pArchive. 2068911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden */ 2078911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (sysMapFileSegmentInShmem(fd, dirOffset, dirSize, 2088911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden &pArchive->mDirectoryMap) != 0) 2098911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden { 210e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: cd map failed"); 211a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein return -1; 212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 2148911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden pArchive->mNumEntries = numEntries; 2158911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden pArchive->mDirectoryOffset = dirOffset; 2168911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 217a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein return 0; 218a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein} 219a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein 220a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein/* 221a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein * Find the zip Central Directory and memory-map it. 222a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein * 223a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein * On success, returns 0 after populating fields from the EOCD area: 224a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein * mDirectoryOffset 225a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein * mDirectoryMap 226a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein * mNumEntries 227a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein */ 228a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornsteinstatic int mapCentralDirectory(int fd, const char* debugFileName, 229a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein ZipArchive* pArchive) 230a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein{ 231d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown /* 232d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * Get and test file length. 233d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown */ 234d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown off_t fileLength = lseek(fd, 0, SEEK_END); 235d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown if (fileLength < kEOCDLen) { 23692c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("Zip: length %ld is too small to be zip", (long) fileLength); 237d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown return -1; 238d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown } 239d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown 240d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown /* 241d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * Perform the traditional EOCD snipe hunt. 242d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * 243d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * We're searching for the End of Central Directory magic number, 244d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * which appears at the start of the EOCD block. It's followed by 245d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * 18 bytes of EOCD stuff and up to 64KB of archive comment. We 246d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * need to read the last part of the file into a buffer, dig through 247d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * it to find the magic number, parse some values out, and use those 248d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * to determine the extent of the CD. 249d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * 250d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown * We start by pulling in the last part of the file. 251d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown */ 252d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown size_t readAmount = kMaxEOCDSearch; 253d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown if (fileLength < off_t(readAmount)) 254d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown readAmount = fileLength; 255a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein 256d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown u1* scanBuf = (u1*) malloc(readAmount); 257a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein if (scanBuf == NULL) { 258a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein return -1; 259a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein } 260a70a3d8faa8f7332549fa0c9ae2008d428e28606Dan Bornstein 261d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown int result = mapCentralDirectory0(fd, debugFileName, pArchive, 262d48cf5c57a850dd4b712efeeb35a09e3d5390f5eJeff Brown fileLength, readAmount, scanBuf); 2638911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 2648911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden free(scanBuf); 2658911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return result; 2668911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden} 2678911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 2688911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden/* 2698911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Parses the Zip archive's Central Directory. Allocates and populates the 2708911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * hash table. 2718911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * 2728911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Returns 0 on success. 2738911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden */ 2748911f7a2222124ba724a4a9281555b74d0e098e2Andy McFaddenstatic int parseZipArchive(ZipArchive* pArchive) 2758911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden{ 2768911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden int result = -1; 2778911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden const u1* cdPtr = (const u1*)pArchive->mDirectoryMap.addr; 2788911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden size_t cdLength = pArchive->mDirectoryMap.length; 2798911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden int numEntries = pArchive->mNumEntries; 2808911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create hash table. We have a minimum 75% load factor, possibly as 283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * low as 50% after we round off to a power of 2. There must be at 284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * least one unused entry to avoid an infinite loop during creation. 285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mHashTableSize = dexRoundUpPower2(1 + (numEntries * 4) / 3); 287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mHashTable = (ZipHashEntry*) 288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project calloc(pArchive->mHashTableSize, sizeof(ZipHashEntry)); 289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Walk through the central directory, adding entries to the hash 2928911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * table and verifying values. 293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 2948911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden const u1* ptr = cdPtr; 2958911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden int i; 296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (i = 0; i < numEntries; i++) { 297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (get4LE(ptr) != kCDESignature) { 298e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: missed a central dir sig (at %d)", i); 2998911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden goto bail; 3008911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 3018911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (ptr + kCDELen > cdPtr + cdLength) { 302e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: ran off the end (at %d)", i); 303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 3058911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 3068911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset); 3078911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (localHdrOffset >= pArchive->mDirectoryOffset) { 308e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: bad LFH offset %ld at entry %d", localHdrOffset, i); 309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3128911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden unsigned int fileNameLen, extraLen, commentLen, hash; 313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project fileNameLen = get2LE(ptr + kCDENameLen); 314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project extraLen = get2LE(ptr + kCDEExtraLen); 315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project commentLen = get2LE(ptr + kCDECommentLen); 316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* add the CDE filename to the hash table */ 318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project hash = computeHash((const char*)ptr + kCDELen, fileNameLen); 319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project addToHash(pArchive, (const char*)ptr + kCDELen, fileNameLen, hash); 320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3218911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden ptr += kCDELen + fileNameLen + extraLen + commentLen; 3228911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if ((size_t)(ptr - cdPtr) > cdLength) { 323e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: bad CD advance (%d vs %zd) at entry %d", 3248911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden (int) (ptr - cdPtr), cdLength, i); 325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 32892c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("+++ zip good scan %d entries", numEntries); 329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3308911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden result = 0; 331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail: 333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return result; 334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3378911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Open the specified file read-only. We examine the contents and verify 3388911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * that it appears to be a valid zip file. 339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This will be called on non-Zip files, especially during VM startup, so 341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we don't want to be too noisy about certain types of failure. (Do 342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we want a "quiet" flag?) 343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3448911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * On success, we fill out the contents of "pArchive" and return 0. On 3458911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * failure we return the errno value. 346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint dexZipOpenArchive(const char* fileName, ZipArchive* pArchive) 348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int fd, err; 350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 35192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("Opening as zip '%s' %p", fileName, pArchive); 352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3530198b1443707d575d30c2b20f1bc3766a9221e96Andy McFadden memset(pArchive, 0, sizeof(ZipArchive)); 3540198b1443707d575d30c2b20f1bc3766a9221e96Andy McFadden 355b4719eda048c4dc4a4b6e5280c7a2b8299051078Raphael Moll fd = open(fileName, O_RDONLY | O_BINARY, 0); 356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (fd < 0) { 357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project err = errno ? errno : -1; 35892c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("Unable to open '%s': %s", fileName, strerror(err)); 359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return err; 360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return dexZipPrepArchive(fd, fileName, pArchive); 363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 3668911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Prepare to access a ZipArchive through an open file descriptor. 3678911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * 3688911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * On success, we fill out the contents of "pArchive" and return 0. 369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive) 371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 3728911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden int result = -1; 373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project memset(pArchive, 0, sizeof(*pArchive)); 375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mFd = fd; 376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3778911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (mapCentralDirectory(fd, debugFileName, pArchive) != 0) 378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3808911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (parseZipArchive(pArchive) != 0) { 38192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("Zip: parsing '%s' failed", debugFileName); 382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* success */ 3868911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden result = 0; 387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail: 3898911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (result != 0) 390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project dexZipCloseArchive(pArchive); 3918911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return result; 392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Close a ZipArchive, closing the file and freeing the contents. 397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * NOTE: the ZipArchive may not have been fully created. 399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dexZipCloseArchive(ZipArchive* pArchive) 401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 40292c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("Closing archive %p", pArchive); 403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pArchive->mFd >= 0) 405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project close(pArchive->mFd); 406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4078911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden sysReleaseShmem(&pArchive->mDirectoryMap); 408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(pArchive->mHashTable); 410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4118911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden /* ensure nobody tries to use the ZipArchive after it's closed */ 4128911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden pArchive->mDirectoryOffset = -1; 413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mFd = -1; 414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mNumEntries = -1; 415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mHashTableSize = -1; 416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mHashTable = NULL; 417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Find a matching entry. 422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns 0 if not found. 424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectZipEntry dexZipFindEntry(const ZipArchive* pArchive, const char* entryName) 426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int nameLen = strlen(entryName); 428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project unsigned int hash = computeHash(entryName, nameLen); 429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const int hashTableSize = pArchive->mHashTableSize; 430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int ent = hash & (hashTableSize-1); 431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (pArchive->mHashTable[ent].name != NULL) { 433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pArchive->mHashTable[ent].nameLen == nameLen && 434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project memcmp(pArchive->mHashTable[ent].name, entryName, nameLen) == 0) 435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* match */ 4378911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return (ZipEntry)(long)(ent + kZipEntryAdj); 438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ent = (ent + 1) & (hashTableSize-1); 441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if 0 447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Find the Nth entry. 449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This currently involves walking through the sparse hash table, counting 451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * non-empty entries. If we need to speed this up we can either allocate 452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * a parallel lookup table or (perhaps better) provide an iterator interface. 453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectZipEntry findEntryByIndex(ZipArchive* pArchive, int idx) 455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (idx < 0 || idx >= pArchive->mNumEntries) { 457e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Invalid index %d", idx); 458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int ent; 462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (ent = 0; ent < pArchive->mHashTableSize; ent++) { 463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pArchive->mHashTable[ent].name != NULL) { 464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (idx-- == 0) 465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return (ZipEntry) (ent + kZipEntryAdj); 466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get the useful fields from the zip entry. 475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 4768911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Returns non-zero if the contents of the fields (particularly the data 4778911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * offset) appear to be bogus. 478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 4798911f7a2222124ba724a4a9281555b74d0e098e2Andy McFaddenint dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry, 4808911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset, 481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project long* pModWhen, long* pCrc32) 482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int ent = entryToIndex(pArchive, entry); 484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (ent < 0) 4858911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return -1; 486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Recover the start of the central directory entry from the filename 4898911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * pointer. The filename is the first entry past the fixed-size data, 4908911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * so we can just subtract back from that. 491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const unsigned char* basePtr = (const unsigned char*) 4938911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden pArchive->mDirectoryMap.addr; 494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const unsigned char* ptr = (const unsigned char*) 495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pArchive->mHashTable[ent].name; 4968911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden off_t cdOffset = pArchive->mDirectoryOffset; 497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ptr -= kCDELen; 499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int method = get2LE(ptr + kCDEMethod); 501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pMethod != NULL) 502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *pMethod = method; 503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pModWhen != NULL) 505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *pModWhen = get4LE(ptr + kCDEModWhen); 506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pCrc32 != NULL) 507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *pCrc32 = get4LE(ptr + kCDECRC); 508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 5098911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden size_t compLen = get4LE(ptr + kCDECompLen); 5108911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (pCompLen != NULL) 5118911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden *pCompLen = compLen; 5128911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden size_t uncompLen = get4LE(ptr + kCDEUncompLen); 5138911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (pUncompLen != NULL) 5148911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden *pUncompLen = uncompLen; 5158911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 5178911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * If requested, determine the offset of the start of the data. All we 5188911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * have is the offset to the Local File Header, which is variable size, 5198911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * so we have to read the contents of the struct to figure out where 5208911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * the actual data starts. 5218911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * 5228911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * We also need to make sure that the lengths are not so large that 5238911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * somebody trying to map the compressed or uncompressed data runs 5248911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * off the end of the mapped region. 5258911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * 5268911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Note we don't verify compLen/uncompLen if they don't request the 5278911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * dataOffset, because dataOffset is expensive to determine. However, 5288911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * if they don't have the file offset, they're not likely to be doing 5298911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * anything with the contents. 530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 5318911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (pOffset != NULL) { 5328911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset); 5338911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (localHdrOffset + kLFHLen >= cdOffset) { 534e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: bad local hdr offset in zip"); 5358911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return -1; 5368911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 5388911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden u1 lfhBuf[kLFHLen]; 5398911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (lseek(pArchive->mFd, localHdrOffset, SEEK_SET) != localHdrOffset) { 540e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: failed seeking to lfh at offset %ld", localHdrOffset); 5418911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return -1; 542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 5438911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden ssize_t actual = 5448911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden TEMP_FAILURE_RETRY(read(pArchive->mFd, lfhBuf, sizeof(lfhBuf))); 5458911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (actual != sizeof(lfhBuf)) { 546e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: failed reading lfh from offset %ld", localHdrOffset); 5478911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return -1; 5488911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 5498911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 5508911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (get4LE(lfhBuf) != kLFHSignature) { 551e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: didn't find signature at start of lfh, offset=%ld", 5528911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden localHdrOffset); 5538911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return -1; 5548911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 5558911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 5568911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden off_t dataOffset = localHdrOffset + kLFHLen 5578911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen); 5588911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (dataOffset >= cdOffset) { 559e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: bad data offset %ld in zip", (long) dataOffset); 5608911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return -1; 5618911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 5628911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 5638911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden /* check lengths */ 5648911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if ((off_t)(dataOffset + compLen) > cdOffset) { 565e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: bad compressed length in zip (%ld + %zd > %ld)", 5668911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden (long) dataOffset, compLen, (long) cdOffset); 5678911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return -1; 568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 5698911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (method == kCompressStored && 5718911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden (off_t)(dataOffset + uncompLen) > cdOffset) 572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 573e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: bad uncompressed length in zip (%ld + %zd > %ld)", 5748911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden (long) dataOffset, uncompLen, (long) cdOffset); 5758911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return -1; 576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *pOffset = dataOffset; 579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 5808911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden return 0; 581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 5848911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Uncompress "deflate" data from the archive's file to an open file 5858911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * descriptor. 586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 587650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornsteinstatic int inflateToFile(int outFd, int inFd, size_t uncompLen, size_t compLen) 588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 5898911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden int result = -1; 5908911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden const size_t kBufSize = 32768; 5918911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden unsigned char* readBuf = (unsigned char*) malloc(kBufSize); 5928911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden unsigned char* writeBuf = (unsigned char*) malloc(kBufSize); 593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project z_stream zstream; 594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int zerr; 595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 5968911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (readBuf == NULL || writeBuf == NULL) 5978911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden goto bail; 5988911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initialize the zlib stream struct. 601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 6028911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden memset(&zstream, 0, sizeof(zstream)); 603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zstream.zalloc = Z_NULL; 604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zstream.zfree = Z_NULL; 605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zstream.opaque = Z_NULL; 6068911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden zstream.next_in = NULL; 6078911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden zstream.avail_in = 0; 608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zstream.next_out = (Bytef*) writeBuf; 6098911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden zstream.avail_out = kBufSize; 610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zstream.data_type = Z_UNKNOWN; 611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 6128911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden /* 6138911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Use the undocumented "negative window bits" feature to tell zlib 6148911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * that there's no zlib header waiting for it. 6158911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden */ 616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zerr = inflateInit2(&zstream, -MAX_WBITS); 617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (zerr != Z_OK) { 618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (zerr == Z_VERSION_ERROR) { 619c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block ALOGE("Installed zlib is not compatible with linked version (%s)", 620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ZLIB_VERSION); 621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 622e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr); 623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Loop while we have more to do. 629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project do { 6318911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden /* read as much as we can */ 6328911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (zstream.avail_in == 0) { 6338911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden size_t getSize = (compLen > kBufSize) ? kBufSize : compLen; 6348911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 6358911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, readBuf, getSize)); 6368911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (actual != (ssize_t) getSize) { 637e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: inflate read failed (%d vs %zd)", 6388911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden (int)actual, getSize); 6398911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden goto z_bail; 6408911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 6418911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 6428911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden compLen -= getSize; 6438911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 6448911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden zstream.next_in = readBuf; 6458911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden zstream.avail_in = getSize; 6468911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 6478911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden 6488911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden /* uncompress the data */ 649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zerr = inflate(&zstream, Z_NO_FLUSH); 650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (zerr != Z_OK && zerr != Z_STREAM_END) { 651e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)", 652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zerr, zstream.next_in, zstream.avail_in, 653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zstream.next_out, zstream.avail_out); 654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto z_bail; 655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* write when we're full or when we're done */ 658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (zstream.avail_out == 0 || 6598911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) 660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 6618911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden size_t writeSize = zstream.next_out - writeBuf; 66264896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden if (sysWriteFully(outFd, writeBuf, writeSize, "Zip inflate") != 0) 663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto z_bail; 664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zstream.next_out = writeBuf; 6668911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden zstream.avail_out = kBufSize; 667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } while (zerr == Z_OK); 669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(zerr == Z_STREAM_END); /* other errors should've been caught */ 671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* paranoia */ 6738911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (zstream.total_out != uncompLen) { 674e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: size mismatch on inflated file (%ld vs %zd)", 675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zstream.total_out, uncompLen); 676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto z_bail; 677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 6798911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden result = 0; 680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectz_bail: 682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project inflateEnd(&zstream); /* free up any allocated structures */ 683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail: 6858911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden free(readBuf); 6868911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden free(writeBuf); 687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return result; 688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Uncompress an entry, in its entirety, to an open file descriptor. 692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * TODO: this doesn't verify the data's CRC, but probably should (especially 694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * for uncompressed data). 695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 6968911f7a2222124ba724a4a9281555b74d0e098e2Andy McFaddenint dexZipExtractEntryToFile(const ZipArchive* pArchive, 697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project const ZipEntry entry, int fd) 698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 6998911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden int result = -1; 700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int ent = entryToIndex(pArchive, entry); 7018911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (ent < 0) { 702e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: extract can't find entry %p", entry); 7038911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden goto bail; 7048911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int method; 7078911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden size_t uncompLen, compLen; 7088911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden off_t dataOffset; 709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 7108911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen, 7118911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden &dataOffset, NULL, NULL) != 0) 712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 7158911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden if (lseek(pArchive->mFd, dataOffset, SEEK_SET) != dataOffset) { 716e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Zip: lseek to data at %ld failed", (long) dataOffset); 7178911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden goto bail; 7188911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden } 719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (method == kCompressStored) { 721650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein if (sysCopyFileToFile(fd, pArchive->mFd, uncompLen) != 0) 722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 724650177ee24fbe07cdd9ad9d8913fbf44cf44be13Dan Bornstein if (inflateToFile(fd, pArchive->mFd, uncompLen, compLen) != 0) 725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project goto bail; 726f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 7288911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden result = 0; 729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail: 731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return result; 732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 733