1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Read-only access to Zip archives, with minimal heap allocation. 19 */ 20 #include "ZipArchive.h" 21 22 #include <zlib.h> 23 24 #include <stdlib.h> 25 #include <unistd.h> 26 #include <string.h> 27 #include <fcntl.h> 28 #include <errno.h> 29 30 #include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd 31 #include <utils/Compat.h> // For off64_t and lseek64 on Mac 32 33 #ifndef O_BINARY 34 #define O_BINARY 0 35 #endif 36 37 /* 38 * Zip file constants. 39 */ 40 #define kEOCDSignature 0x06054b50 41 #define kEOCDLen 22 42 #define kEOCDDiskNumber 4 // number of the current disk 43 #define kEOCDDiskNumberForCD 6 // disk number with the Central Directory 44 #define kEOCDNumEntries 8 // offset to #of entries in file 45 #define kEOCDTotalNumEntries 10 // offset to total #of entries in spanned archives 46 #define kEOCDSize 12 // size of the central directory 47 #define kEOCDFileOffset 16 // offset to central directory 48 #define kEOCDCommentSize 20 // offset to the length of the file comment 49 50 #define kMaxCommentLen 65535 // longest possible in ushort 51 #define kMaxEOCDSearch (kMaxCommentLen + kEOCDLen) 52 53 #define kLFHSignature 0x04034b50 54 #define kLFHLen 30 // excluding variable-len fields 55 #define kLFHGPBFlags 6 // offset to GPB flags 56 #define kLFHNameLen 26 // offset to filename length 57 #define kLFHExtraLen 28 // offset to extra length 58 59 #define kCDESignature 0x02014b50 60 #define kCDELen 46 // excluding variable-len fields 61 #define kCDEGPBFlags 8 // offset to GPB flags 62 #define kCDEMethod 10 // offset to compression method 63 #define kCDEModWhen 12 // offset to modification timestamp 64 #define kCDECRC 16 // offset to entry CRC 65 #define kCDECompLen 20 // offset to compressed length 66 #define kCDEUncompLen 24 // offset to uncompressed length 67 #define kCDENameLen 28 // offset to filename length 68 #define kCDEExtraLen 30 // offset to extra length 69 #define kCDECommentLen 32 // offset to comment length 70 #define kCDELocalOffset 42 // offset to local hdr 71 72 /* General Purpose Bit Flag */ 73 #define kGPFEncryptedFlag (1 << 0) 74 #define kGPFUnsupportedMask (kGPFEncryptedFlag) 75 76 /* 77 * The values we return for ZipEntryRO use 0 as an invalid value, so we 78 * want to adjust the hash table index by a fixed amount. Using a large 79 * value helps insure that people don't mix & match arguments, e.g. to 80 * findEntryByIndex(). 81 */ 82 #define kZipEntryAdj 10000 83 84 /* 85 * Convert a ZipEntry to a hash table index, verifying that it's in a 86 * valid range. 87 */ 88 static int entryToIndex(const ZipArchive* pArchive, const ZipEntry entry) 89 { 90 long ent = ((long) entry) - kZipEntryAdj; 91 if (ent < 0 || ent >= pArchive->mHashTableSize || 92 pArchive->mHashTable[ent].name == NULL) 93 { 94 ALOGW("Zip: invalid ZipEntry %p (%ld)", entry, ent); 95 return -1; 96 } 97 return ent; 98 } 99 100 /* 101 * Simple string hash function for non-null-terminated strings. 102 */ 103 static unsigned int computeHash(const char* str, int len) 104 { 105 unsigned int hash = 0; 106 107 while (len--) 108 hash = hash * 31 + *str++; 109 110 return hash; 111 } 112 113 /* 114 * Add a new entry to the hash table. 115 */ 116 static void addToHash(ZipArchive* pArchive, const char* str, int strLen, 117 unsigned int hash) 118 { 119 const int hashTableSize = pArchive->mHashTableSize; 120 int ent = hash & (hashTableSize - 1); 121 122 /* 123 * We over-allocated the table, so we're guaranteed to find an empty slot. 124 */ 125 while (pArchive->mHashTable[ent].name != NULL) 126 ent = (ent + 1) & (hashTableSize-1); 127 128 pArchive->mHashTable[ent].name = str; 129 pArchive->mHashTable[ent].nameLen = strLen; 130 } 131 132 /* 133 * Get 2 little-endian bytes. 134 */ 135 static u2 get2LE(unsigned char const* pSrc) 136 { 137 return pSrc[0] | (pSrc[1] << 8); 138 } 139 140 /* 141 * Get 4 little-endian bytes. 142 */ 143 static u4 get4LE(unsigned char const* pSrc) 144 { 145 u4 result; 146 147 result = pSrc[0]; 148 result |= pSrc[1] << 8; 149 result |= pSrc[2] << 16; 150 result |= pSrc[3] << 24; 151 152 return result; 153 } 154 155 static int mapCentralDirectory0(int fd, const char* debugFileName, 156 ZipArchive* pArchive, off64_t fileLength, size_t readAmount, u1* scanBuf) 157 { 158 /* 159 * Make sure this is a Zip archive. 160 */ 161 if (lseek64(pArchive->mFd, 0, SEEK_SET) != 0) { 162 ALOGW("seek to start failed: %s", strerror(errno)); 163 return false; 164 } 165 166 ssize_t actual = TEMP_FAILURE_RETRY(read(pArchive->mFd, scanBuf, sizeof(int32_t))); 167 if (actual != (ssize_t) sizeof(int32_t)) { 168 ALOGI("couldn't read first signature from zip archive: %s", strerror(errno)); 169 return false; 170 } 171 172 unsigned int header = get4LE(scanBuf); 173 if (header != kLFHSignature) { 174 ALOGV("Not a Zip archive (found 0x%08x)\n", header); 175 return false; 176 } 177 178 /* 179 * Perform the traditional EOCD snipe hunt. 180 * 181 * We're searching for the End of Central Directory magic number, 182 * which appears at the start of the EOCD block. It's followed by 183 * 18 bytes of EOCD stuff and up to 64KB of archive comment. We 184 * need to read the last part of the file into a buffer, dig through 185 * it to find the magic number, parse some values out, and use those 186 * to determine the extent of the CD. 187 * 188 * We start by pulling in the last part of the file. 189 */ 190 off64_t searchStart = fileLength - readAmount; 191 192 if (lseek64(pArchive->mFd, searchStart, SEEK_SET) != searchStart) { 193 ALOGW("seek %ld failed: %s\n", (long) searchStart, strerror(errno)); 194 return false; 195 } 196 actual = TEMP_FAILURE_RETRY(read(pArchive->mFd, scanBuf, readAmount)); 197 if (actual != (ssize_t) readAmount) { 198 ALOGW("Zip: read %zd, expected %zd. Failed: %s\n", 199 actual, readAmount, strerror(errno)); 200 return false; 201 } 202 203 204 /* 205 * Scan backward for the EOCD magic. In an archive without a trailing 206 * comment, we'll find it on the first try. (We may want to consider 207 * doing an initial minimal read; if we don't find it, retry with a 208 * second read as above.) 209 */ 210 int i; 211 for (i = readAmount - kEOCDLen; i >= 0; i--) { 212 if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) { 213 ALOGV("+++ Found EOCD at buf+%d", i); 214 break; 215 } 216 } 217 if (i < 0) { 218 ALOGD("Zip: EOCD not found, %s is not zip", debugFileName); 219 return -1; 220 } 221 222 off64_t eocdOffset = searchStart + i; 223 const u1* eocdPtr = scanBuf + i; 224 225 assert(eocdOffset < fileLength); 226 227 /* 228 * Grab the CD offset and size, and the number of entries in the 229 * archive. Verify that they look reasonable. 230 */ 231 u4 diskNumber = get2LE(eocdPtr + kEOCDDiskNumber); 232 u4 diskWithCentralDir = get2LE(eocdPtr + kEOCDDiskNumberForCD); 233 u4 numEntries = get2LE(eocdPtr + kEOCDNumEntries); 234 u4 totalNumEntries = get2LE(eocdPtr + kEOCDTotalNumEntries); 235 u4 centralDirSize = get4LE(eocdPtr + kEOCDSize); 236 u4 centralDirOffset = get4LE(eocdPtr + kEOCDFileOffset); 237 u4 commentSize = get2LE(eocdPtr + kEOCDCommentSize); 238 239 // Verify that they look reasonable. 240 if ((long long) centralDirOffset + (long long) centralDirSize > (long long) eocdOffset) { 241 ALOGW("bad offsets (dir %ld, size %u, eocd %ld)\n", 242 (long) centralDirOffset, centralDirSize, (long) eocdOffset); 243 return false; 244 } 245 if (numEntries == 0) { 246 ALOGW("empty archive?\n"); 247 return false; 248 } else if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) { 249 ALOGW("spanned archives not supported"); 250 return false; 251 } 252 253 // Check to see if comment is a sane size 254 if (((size_t) commentSize > (fileLength - kEOCDLen)) 255 || (eocdOffset > (fileLength - kEOCDLen) - commentSize)) { 256 ALOGW("comment size runs off end of file"); 257 return false; 258 } 259 260 ALOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n", 261 numEntries, centralDirSize, centralDirOffset); 262 263 /* 264 * It all looks good. Create a mapping for the CD, and set the fields 265 * in pArchive. 266 */ 267 if (sysMapFileSegmentInShmem(fd, centralDirOffset, centralDirSize, 268 &pArchive->mDirectoryMap) != 0) 269 { 270 ALOGW("Zip: cd map failed"); 271 return -1; 272 } 273 274 pArchive->mNumEntries = numEntries; 275 pArchive->mDirectoryOffset = centralDirOffset; 276 277 return 0; 278 } 279 280 /* 281 * Find the zip Central Directory and memory-map it. 282 * 283 * On success, returns 0 after populating fields from the EOCD area: 284 * mDirectoryOffset 285 * mDirectoryMap 286 * mNumEntries 287 */ 288 static int mapCentralDirectory(int fd, const char* debugFileName, 289 ZipArchive* pArchive) 290 { 291 /* 292 * Get and test file length. 293 */ 294 off64_t fileLength = lseek64(fd, 0, SEEK_END); 295 if (fileLength < kEOCDLen) { 296 ALOGV("Zip: length %ld is too small to be zip", (long) fileLength); 297 return -1; 298 } 299 300 /* 301 * Perform the traditional EOCD snipe hunt. 302 * 303 * We're searching for the End of Central Directory magic number, 304 * which appears at the start of the EOCD block. It's followed by 305 * 18 bytes of EOCD stuff and up to 64KB of archive comment. We 306 * need to read the last part of the file into a buffer, dig through 307 * it to find the magic number, parse some values out, and use those 308 * to determine the extent of the CD. 309 * 310 * We start by pulling in the last part of the file. 311 */ 312 size_t readAmount = kMaxEOCDSearch; 313 if (fileLength < off_t(readAmount)) 314 readAmount = fileLength; 315 316 u1* scanBuf = (u1*) malloc(readAmount); 317 if (scanBuf == NULL) { 318 return -1; 319 } 320 321 int result = mapCentralDirectory0(fd, debugFileName, pArchive, 322 fileLength, readAmount, scanBuf); 323 324 free(scanBuf); 325 return result; 326 } 327 328 /* 329 * Parses the Zip archive's Central Directory. Allocates and populates the 330 * hash table. 331 * 332 * Returns 0 on success. 333 */ 334 static int parseZipArchive(ZipArchive* pArchive) 335 { 336 int result = -1; 337 const u1* cdPtr = (const u1*)pArchive->mDirectoryMap.addr; 338 size_t cdLength = pArchive->mDirectoryMap.length; 339 int numEntries = pArchive->mNumEntries; 340 341 /* 342 * Create hash table. We have a minimum 75% load factor, possibly as 343 * low as 50% after we round off to a power of 2. There must be at 344 * least one unused entry to avoid an infinite loop during creation. 345 */ 346 pArchive->mHashTableSize = dexRoundUpPower2(1 + (numEntries * 4) / 3); 347 pArchive->mHashTable = (ZipHashEntry*) 348 calloc(pArchive->mHashTableSize, sizeof(ZipHashEntry)); 349 350 /* 351 * Walk through the central directory, adding entries to the hash 352 * table and verifying values. 353 */ 354 const u1* ptr = cdPtr; 355 int i; 356 for (i = 0; i < numEntries; i++) { 357 if (get4LE(ptr) != kCDESignature) { 358 ALOGW("Zip: missed a central dir sig (at %d)", i); 359 goto bail; 360 } 361 if (ptr + kCDELen > cdPtr + cdLength) { 362 ALOGW("Zip: ran off the end (at %d)", i); 363 goto bail; 364 } 365 366 long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset); 367 if (localHdrOffset >= pArchive->mDirectoryOffset) { 368 ALOGW("Zip: bad LFH offset %ld at entry %d", localHdrOffset, i); 369 goto bail; 370 } 371 372 unsigned int gpbf = get2LE(ptr + kCDEGPBFlags); 373 if ((gpbf & kGPFUnsupportedMask) != 0) { 374 ALOGW("Invalid General Purpose Bit Flag: %d", gpbf); 375 goto bail; 376 } 377 378 unsigned int nameLen, extraLen, commentLen, hash; 379 nameLen = get2LE(ptr + kCDENameLen); 380 extraLen = get2LE(ptr + kCDEExtraLen); 381 commentLen = get2LE(ptr + kCDECommentLen); 382 383 const char *name = (const char *) ptr + kCDELen; 384 385 /* Check name for NULL characters */ 386 if (memchr(name, 0, nameLen) != NULL) { 387 ALOGW("Filename contains NUL byte"); 388 goto bail; 389 } 390 391 /* add the CDE filename to the hash table */ 392 hash = computeHash(name, nameLen); 393 addToHash(pArchive, name, nameLen, hash); 394 395 /* We don't care about the comment or extra data. */ 396 ptr += kCDELen + nameLen + extraLen + commentLen; 397 if ((size_t)(ptr - cdPtr) > cdLength) { 398 ALOGW("Zip: bad CD advance (%d vs %zd) at entry %d", 399 (int) (ptr - cdPtr), cdLength, i); 400 goto bail; 401 } 402 } 403 ALOGV("+++ zip good scan %d entries", numEntries); 404 405 result = 0; 406 407 bail: 408 return result; 409 } 410 411 /* 412 * Open the specified file read-only. We examine the contents and verify 413 * that it appears to be a valid zip file. 414 * 415 * This will be called on non-Zip files, especially during VM startup, so 416 * we don't want to be too noisy about certain types of failure. (Do 417 * we want a "quiet" flag?) 418 * 419 * On success, we fill out the contents of "pArchive" and return 0. On 420 * failure we return the errno value. 421 */ 422 int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive) 423 { 424 int fd, err; 425 426 ALOGV("Opening as zip '%s' %p", fileName, pArchive); 427 428 memset(pArchive, 0, sizeof(ZipArchive)); 429 430 fd = open(fileName, O_RDONLY | O_BINARY, 0); 431 if (fd < 0) { 432 err = errno ? errno : -1; 433 ALOGV("Unable to open '%s': %s", fileName, strerror(err)); 434 return err; 435 } 436 437 return dexZipPrepArchive(fd, fileName, pArchive); 438 } 439 440 /* 441 * Prepare to access a ZipArchive through an open file descriptor. 442 * 443 * On success, we fill out the contents of "pArchive" and return 0. 444 */ 445 int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive) 446 { 447 int result = -1; 448 449 memset(pArchive, 0, sizeof(*pArchive)); 450 pArchive->mFd = fd; 451 452 if (mapCentralDirectory(fd, debugFileName, pArchive) != 0) 453 goto bail; 454 455 if (parseZipArchive(pArchive) != 0) { 456 ALOGV("Zip: parsing '%s' failed", debugFileName); 457 goto bail; 458 } 459 460 /* success */ 461 result = 0; 462 463 bail: 464 if (result != 0) 465 dexZipCloseArchive(pArchive); 466 return result; 467 } 468 469 470 /* 471 * Close a ZipArchive, closing the file and freeing the contents. 472 * 473 * NOTE: the ZipArchive may not have been fully created. 474 */ 475 void dexZipCloseArchive(ZipArchive* pArchive) 476 { 477 ALOGV("Closing archive %p", pArchive); 478 479 if (pArchive->mFd >= 0) 480 close(pArchive->mFd); 481 482 sysReleaseShmem(&pArchive->mDirectoryMap); 483 484 free(pArchive->mHashTable); 485 486 /* ensure nobody tries to use the ZipArchive after it's closed */ 487 pArchive->mDirectoryOffset = -1; 488 pArchive->mFd = -1; 489 pArchive->mNumEntries = -1; 490 pArchive->mHashTableSize = -1; 491 pArchive->mHashTable = NULL; 492 } 493 494 495 /* 496 * Find a matching entry. 497 * 498 * Returns 0 if not found. 499 */ 500 ZipEntry dexZipFindEntry(const ZipArchive* pArchive, const char* entryName) 501 { 502 int nameLen = strlen(entryName); 503 unsigned int hash = computeHash(entryName, nameLen); 504 const int hashTableSize = pArchive->mHashTableSize; 505 int ent = hash & (hashTableSize-1); 506 507 while (pArchive->mHashTable[ent].name != NULL) { 508 if (pArchive->mHashTable[ent].nameLen == nameLen && 509 memcmp(pArchive->mHashTable[ent].name, entryName, nameLen) == 0) 510 { 511 /* match */ 512 return (ZipEntry)(long)(ent + kZipEntryAdj); 513 } 514 515 ent = (ent + 1) & (hashTableSize-1); 516 } 517 518 return NULL; 519 } 520 521 #if 0 522 /* 523 * Find the Nth entry. 524 * 525 * This currently involves walking through the sparse hash table, counting 526 * non-empty entries. If we need to speed this up we can either allocate 527 * a parallel lookup table or (perhaps better) provide an iterator interface. 528 */ 529 ZipEntry findEntryByIndex(ZipArchive* pArchive, int idx) 530 { 531 if (idx < 0 || idx >= pArchive->mNumEntries) { 532 ALOGW("Invalid index %d", idx); 533 return NULL; 534 } 535 536 int ent; 537 for (ent = 0; ent < pArchive->mHashTableSize; ent++) { 538 if (pArchive->mHashTable[ent].name != NULL) { 539 if (idx-- == 0) 540 return (ZipEntry) (ent + kZipEntryAdj); 541 } 542 } 543 544 return NULL; 545 } 546 #endif 547 548 /* 549 * Get the useful fields from the zip entry. 550 * 551 * Returns non-zero if the contents of the fields (particularly the data 552 * offset) appear to be bogus. 553 */ 554 int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry, 555 int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset, 556 long* pModWhen, long* pCrc32) 557 { 558 int ent = entryToIndex(pArchive, entry); 559 if (ent < 0) 560 return -1; 561 562 /* 563 * Recover the start of the central directory entry from the filename 564 * pointer. The filename is the first entry past the fixed-size data, 565 * so we can just subtract back from that. 566 */ 567 const unsigned char* basePtr = (const unsigned char*) 568 pArchive->mDirectoryMap.addr; 569 const unsigned char* ptr = (const unsigned char*) 570 pArchive->mHashTable[ent].name; 571 off_t cdOffset = pArchive->mDirectoryOffset; 572 573 ptr -= kCDELen; 574 575 int method = get2LE(ptr + kCDEMethod); 576 if (pMethod != NULL) 577 *pMethod = method; 578 579 if (pModWhen != NULL) 580 *pModWhen = get4LE(ptr + kCDEModWhen); 581 if (pCrc32 != NULL) 582 *pCrc32 = get4LE(ptr + kCDECRC); 583 584 size_t compLen = get4LE(ptr + kCDECompLen); 585 if (pCompLen != NULL) 586 *pCompLen = compLen; 587 size_t uncompLen = get4LE(ptr + kCDEUncompLen); 588 if (pUncompLen != NULL) 589 *pUncompLen = uncompLen; 590 591 /* 592 * If requested, determine the offset of the start of the data. All we 593 * have is the offset to the Local File Header, which is variable size, 594 * so we have to read the contents of the struct to figure out where 595 * the actual data starts. 596 * 597 * We also need to make sure that the lengths are not so large that 598 * somebody trying to map the compressed or uncompressed data runs 599 * off the end of the mapped region. 600 * 601 * Note we don't verify compLen/uncompLen if they don't request the 602 * dataOffset, because dataOffset is expensive to determine. However, 603 * if they don't have the file offset, they're not likely to be doing 604 * anything with the contents. 605 */ 606 if (pOffset != NULL) { 607 long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset); 608 if (localHdrOffset + kLFHLen >= cdOffset) { 609 ALOGW("Zip: bad local hdr offset in zip"); 610 return -1; 611 } 612 613 u1 lfhBuf[kLFHLen]; 614 if (lseek(pArchive->mFd, localHdrOffset, SEEK_SET) != localHdrOffset) { 615 ALOGW("Zip: failed seeking to lfh at offset %ld", localHdrOffset); 616 return -1; 617 } 618 ssize_t actual = 619 TEMP_FAILURE_RETRY(read(pArchive->mFd, lfhBuf, sizeof(lfhBuf))); 620 if (actual != sizeof(lfhBuf)) { 621 ALOGW("Zip: failed reading lfh from offset %ld", localHdrOffset); 622 return -1; 623 } 624 625 if (get4LE(lfhBuf) != kLFHSignature) { 626 ALOGW("Zip: didn't find signature at start of lfh, offset=%ld", 627 localHdrOffset); 628 return -1; 629 } 630 631 u4 gpbf = get2LE(lfhBuf + kLFHGPBFlags); 632 if ((gpbf & kGPFUnsupportedMask) != 0) { 633 ALOGW("Invalid General Purpose Bit Flag: %d", gpbf); 634 return -1; 635 } 636 637 off64_t dataOffset = localHdrOffset + kLFHLen 638 + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen); 639 if (dataOffset >= cdOffset) { 640 ALOGW("Zip: bad data offset %ld in zip", (long) dataOffset); 641 return -1; 642 } 643 644 /* check lengths */ 645 if ((off_t)(dataOffset + compLen) > cdOffset) { 646 ALOGW("Zip: bad compressed length in zip (%ld + %zd > %ld)", 647 (long) dataOffset, compLen, (long) cdOffset); 648 return -1; 649 } 650 651 if (method == kCompressStored && 652 (off_t)(dataOffset + uncompLen) > cdOffset) 653 { 654 ALOGW("Zip: bad uncompressed length in zip (%ld + %zd > %ld)", 655 (long) dataOffset, uncompLen, (long) cdOffset); 656 return -1; 657 } 658 659 *pOffset = dataOffset; 660 } 661 return 0; 662 } 663 664 /* 665 * Uncompress "deflate" data from the archive's file to an open file 666 * descriptor. 667 */ 668 static int inflateToFile(int outFd, int inFd, size_t uncompLen, size_t compLen) 669 { 670 int result = -1; 671 const size_t kBufSize = 32768; 672 unsigned char* readBuf = (unsigned char*) malloc(kBufSize); 673 unsigned char* writeBuf = (unsigned char*) malloc(kBufSize); 674 z_stream zstream; 675 int zerr; 676 677 if (readBuf == NULL || writeBuf == NULL) 678 goto bail; 679 680 /* 681 * Initialize the zlib stream struct. 682 */ 683 memset(&zstream, 0, sizeof(zstream)); 684 zstream.zalloc = Z_NULL; 685 zstream.zfree = Z_NULL; 686 zstream.opaque = Z_NULL; 687 zstream.next_in = NULL; 688 zstream.avail_in = 0; 689 zstream.next_out = (Bytef*) writeBuf; 690 zstream.avail_out = kBufSize; 691 zstream.data_type = Z_UNKNOWN; 692 693 /* 694 * Use the undocumented "negative window bits" feature to tell zlib 695 * that there's no zlib header waiting for it. 696 */ 697 zerr = inflateInit2(&zstream, -MAX_WBITS); 698 if (zerr != Z_OK) { 699 if (zerr == Z_VERSION_ERROR) { 700 ALOGE("Installed zlib is not compatible with linked version (%s)", 701 ZLIB_VERSION); 702 } else { 703 ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr); 704 } 705 goto bail; 706 } 707 708 /* 709 * Loop while we have more to do. 710 */ 711 do { 712 /* read as much as we can */ 713 if (zstream.avail_in == 0) { 714 size_t getSize = (compLen > kBufSize) ? kBufSize : compLen; 715 716 ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, readBuf, getSize)); 717 if (actual != (ssize_t) getSize) { 718 ALOGW("Zip: inflate read failed (%d vs %zd)", 719 (int)actual, getSize); 720 goto z_bail; 721 } 722 723 compLen -= getSize; 724 725 zstream.next_in = readBuf; 726 zstream.avail_in = getSize; 727 } 728 729 /* uncompress the data */ 730 zerr = inflate(&zstream, Z_NO_FLUSH); 731 if (zerr != Z_OK && zerr != Z_STREAM_END) { 732 ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)", 733 zerr, zstream.next_in, zstream.avail_in, 734 zstream.next_out, zstream.avail_out); 735 goto z_bail; 736 } 737 738 /* write when we're full or when we're done */ 739 if (zstream.avail_out == 0 || 740 (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) 741 { 742 size_t writeSize = zstream.next_out - writeBuf; 743 if (sysWriteFully(outFd, writeBuf, writeSize, "Zip inflate") != 0) 744 goto z_bail; 745 746 zstream.next_out = writeBuf; 747 zstream.avail_out = kBufSize; 748 } 749 } while (zerr == Z_OK); 750 751 assert(zerr == Z_STREAM_END); /* other errors should've been caught */ 752 753 /* paranoia */ 754 if (zstream.total_out != uncompLen) { 755 ALOGW("Zip: size mismatch on inflated file (%ld vs %zd)", 756 zstream.total_out, uncompLen); 757 goto z_bail; 758 } 759 760 result = 0; 761 762 z_bail: 763 inflateEnd(&zstream); /* free up any allocated structures */ 764 765 bail: 766 free(readBuf); 767 free(writeBuf); 768 return result; 769 } 770 771 /* 772 * Uncompress an entry, in its entirety, to an open file descriptor. 773 * 774 * TODO: this doesn't verify the data's CRC, but probably should (especially 775 * for uncompressed data). 776 */ 777 int dexZipExtractEntryToFile(const ZipArchive* pArchive, 778 const ZipEntry entry, int fd) 779 { 780 int result = -1; 781 int ent = entryToIndex(pArchive, entry); 782 if (ent < 0) { 783 ALOGW("Zip: extract can't find entry %p", entry); 784 goto bail; 785 } 786 787 int method; 788 size_t uncompLen, compLen; 789 off_t dataOffset; 790 791 if (dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen, 792 &dataOffset, NULL, NULL) != 0) 793 { 794 goto bail; 795 } 796 if (lseek(pArchive->mFd, dataOffset, SEEK_SET) != dataOffset) { 797 ALOGW("Zip: lseek to data at %ld failed", (long) dataOffset); 798 goto bail; 799 } 800 801 if (method == kCompressStored) { 802 if (sysCopyFileToFile(fd, pArchive->mFd, uncompLen) != 0) 803 goto bail; 804 } else { 805 if (inflateToFile(fd, pArchive->mFd, uncompLen, compLen) != 0) 806 goto bail; 807 } 808 809 result = 0; 810 811 bail: 812 return result; 813 } 814