1 /* 2 * Copyright (C) 2006 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 // Access to Zip archives. 19 // 20 21 #define LOG_TAG "zip" 22 23 #include <androidfw/ZipUtils.h> 24 #include <utils/Log.h> 25 26 #include "ZipFile.h" 27 28 #include <zlib.h> 29 #define DEF_MEM_LEVEL 8 // normally in zutil.h? 30 31 #include <memory.h> 32 #include <sys/stat.h> 33 #include <errno.h> 34 #include <assert.h> 35 36 using namespace android; 37 38 /* 39 * Some environments require the "b", some choke on it. 40 */ 41 #define FILE_OPEN_RO "rb" 42 #define FILE_OPEN_RW "r+b" 43 #define FILE_OPEN_RW_CREATE "w+b" 44 45 /* should live somewhere else? */ 46 static status_t errnoToStatus(int err) 47 { 48 if (err == ENOENT) 49 return NAME_NOT_FOUND; 50 else if (err == EACCES) 51 return PERMISSION_DENIED; 52 else 53 return UNKNOWN_ERROR; 54 } 55 56 /* 57 * Open a file and parse its guts. 58 */ 59 status_t ZipFile::open(const char* zipFileName, int flags) 60 { 61 bool newArchive = false; 62 63 assert(mZipFp == NULL); // no reopen 64 65 if ((flags & kOpenTruncate)) 66 flags |= kOpenCreate; // trunc implies create 67 68 if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite)) 69 return INVALID_OPERATION; // not both 70 if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite))) 71 return INVALID_OPERATION; // not neither 72 if ((flags & kOpenCreate) && !(flags & kOpenReadWrite)) 73 return INVALID_OPERATION; // create requires write 74 75 if (flags & kOpenTruncate) { 76 newArchive = true; 77 } else { 78 newArchive = (access(zipFileName, F_OK) != 0); 79 if (!(flags & kOpenCreate) && newArchive) { 80 /* not creating, must already exist */ 81 ALOGD("File %s does not exist", zipFileName); 82 return NAME_NOT_FOUND; 83 } 84 } 85 86 /* open the file */ 87 const char* openflags; 88 if (flags & kOpenReadWrite) { 89 if (newArchive) 90 openflags = FILE_OPEN_RW_CREATE; 91 else 92 openflags = FILE_OPEN_RW; 93 } else { 94 openflags = FILE_OPEN_RO; 95 } 96 mZipFp = fopen(zipFileName, openflags); 97 if (mZipFp == NULL) { 98 int err = errno; 99 ALOGD("fopen failed: %d\n", err); 100 return errnoToStatus(err); 101 } 102 103 status_t result; 104 if (!newArchive) { 105 /* 106 * Load the central directory. If that fails, then this probably 107 * isn't a Zip archive. 108 */ 109 result = readCentralDir(); 110 } else { 111 /* 112 * Newly-created. The EndOfCentralDir constructor actually 113 * sets everything to be the way we want it (all zeroes). We 114 * set mNeedCDRewrite so that we create *something* if the 115 * caller doesn't add any files. (We could also just unlink 116 * the file if it's brand new and nothing was added, but that's 117 * probably doing more than we really should -- the user might 118 * have a need for empty zip files.) 119 */ 120 mNeedCDRewrite = true; 121 result = NO_ERROR; 122 } 123 124 if (flags & kOpenReadOnly) 125 mReadOnly = true; 126 else 127 assert(!mReadOnly); 128 129 return result; 130 } 131 132 /* 133 * Return the Nth entry in the archive. 134 */ 135 ZipEntry* ZipFile::getEntryByIndex(int idx) const 136 { 137 if (idx < 0 || idx >= (int) mEntries.size()) 138 return NULL; 139 140 return mEntries[idx]; 141 } 142 143 /* 144 * Find an entry by name. 145 */ 146 ZipEntry* ZipFile::getEntryByName(const char* fileName) const 147 { 148 /* 149 * Do a stupid linear string-compare search. 150 * 151 * There are various ways to speed this up, especially since it's rare 152 * to intermingle changes to the archive with "get by name" calls. We 153 * don't want to sort the mEntries vector itself, however, because 154 * it's used to recreate the Central Directory. 155 * 156 * (Hash table works, parallel list of pointers in sorted order is good.) 157 */ 158 int idx; 159 160 for (idx = mEntries.size()-1; idx >= 0; idx--) { 161 ZipEntry* pEntry = mEntries[idx]; 162 if (!pEntry->getDeleted() && 163 strcmp(fileName, pEntry->getFileName()) == 0) 164 { 165 return pEntry; 166 } 167 } 168 169 return NULL; 170 } 171 172 /* 173 * Empty the mEntries vector. 174 */ 175 void ZipFile::discardEntries(void) 176 { 177 int count = mEntries.size(); 178 179 while (--count >= 0) 180 delete mEntries[count]; 181 182 mEntries.clear(); 183 } 184 185 186 /* 187 * Find the central directory and read the contents. 188 * 189 * The fun thing about ZIP archives is that they may or may not be 190 * readable from start to end. In some cases, notably for archives 191 * that were written to stdout, the only length information is in the 192 * central directory at the end of the file. 193 * 194 * Of course, the central directory can be followed by a variable-length 195 * comment field, so we have to scan through it backwards. The comment 196 * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff 197 * itself, plus apparently sometimes people throw random junk on the end 198 * just for the fun of it. 199 * 200 * This is all a little wobbly. If the wrong value ends up in the EOCD 201 * area, we're hosed. This appears to be the way that everbody handles 202 * it though, so we're in pretty good company if this fails. 203 */ 204 status_t ZipFile::readCentralDir(void) 205 { 206 status_t result = NO_ERROR; 207 unsigned char* buf = NULL; 208 off_t fileLength, seekStart; 209 long readAmount; 210 int i; 211 212 fseek(mZipFp, 0, SEEK_END); 213 fileLength = ftell(mZipFp); 214 rewind(mZipFp); 215 216 /* too small to be a ZIP archive? */ 217 if (fileLength < EndOfCentralDir::kEOCDLen) { 218 ALOGD("Length is %ld -- too small\n", (long)fileLength); 219 result = INVALID_OPERATION; 220 goto bail; 221 } 222 223 buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch]; 224 if (buf == NULL) { 225 ALOGD("Failure allocating %d bytes for EOCD search", 226 EndOfCentralDir::kMaxEOCDSearch); 227 result = NO_MEMORY; 228 goto bail; 229 } 230 231 if (fileLength > EndOfCentralDir::kMaxEOCDSearch) { 232 seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch; 233 readAmount = EndOfCentralDir::kMaxEOCDSearch; 234 } else { 235 seekStart = 0; 236 readAmount = (long) fileLength; 237 } 238 if (fseek(mZipFp, seekStart, SEEK_SET) != 0) { 239 ALOGD("Failure seeking to end of zip at %ld", (long) seekStart); 240 result = UNKNOWN_ERROR; 241 goto bail; 242 } 243 244 /* read the last part of the file into the buffer */ 245 if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) { 246 ALOGD("short file? wanted %ld\n", readAmount); 247 result = UNKNOWN_ERROR; 248 goto bail; 249 } 250 251 /* find the end-of-central-dir magic */ 252 for (i = readAmount - 4; i >= 0; i--) { 253 if (buf[i] == 0x50 && 254 ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature) 255 { 256 ALOGV("+++ Found EOCD at buf+%d\n", i); 257 break; 258 } 259 } 260 if (i < 0) { 261 ALOGD("EOCD not found, not Zip\n"); 262 result = INVALID_OPERATION; 263 goto bail; 264 } 265 266 /* extract eocd values */ 267 result = mEOCD.readBuf(buf + i, readAmount - i); 268 if (result != NO_ERROR) { 269 ALOGD("Failure reading %ld bytes of EOCD values", readAmount - i); 270 goto bail; 271 } 272 //mEOCD.dump(); 273 274 if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 || 275 mEOCD.mNumEntries != mEOCD.mTotalNumEntries) 276 { 277 ALOGD("Archive spanning not supported\n"); 278 result = INVALID_OPERATION; 279 goto bail; 280 } 281 282 /* 283 * So far so good. "mCentralDirSize" is the size in bytes of the 284 * central directory, so we can just seek back that far to find it. 285 * We can also seek forward mCentralDirOffset bytes from the 286 * start of the file. 287 * 288 * We're not guaranteed to have the rest of the central dir in the 289 * buffer, nor are we guaranteed that the central dir will have any 290 * sort of convenient size. We need to skip to the start of it and 291 * read the header, then the other goodies. 292 * 293 * The only thing we really need right now is the file comment, which 294 * we're hoping to preserve. 295 */ 296 if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { 297 ALOGD("Failure seeking to central dir offset %ld\n", 298 mEOCD.mCentralDirOffset); 299 result = UNKNOWN_ERROR; 300 goto bail; 301 } 302 303 /* 304 * Loop through and read the central dir entries. 305 */ 306 ALOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries); 307 int entry; 308 for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) { 309 ZipEntry* pEntry = new ZipEntry; 310 311 result = pEntry->initFromCDE(mZipFp); 312 if (result != NO_ERROR) { 313 ALOGD("initFromCDE failed\n"); 314 delete pEntry; 315 goto bail; 316 } 317 318 mEntries.add(pEntry); 319 } 320 321 322 /* 323 * If all went well, we should now be back at the EOCD. 324 */ 325 { 326 unsigned char checkBuf[4]; 327 if (fread(checkBuf, 1, 4, mZipFp) != 4) { 328 ALOGD("EOCD check read failed\n"); 329 result = INVALID_OPERATION; 330 goto bail; 331 } 332 if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) { 333 ALOGD("EOCD read check failed\n"); 334 result = UNKNOWN_ERROR; 335 goto bail; 336 } 337 ALOGV("+++ EOCD read check passed\n"); 338 } 339 340 bail: 341 delete[] buf; 342 return result; 343 } 344 345 346 /* 347 * Add a new file to the archive. 348 * 349 * This requires creating and populating a ZipEntry structure, and copying 350 * the data into the file at the appropriate position. The "appropriate 351 * position" is the current location of the central directory, which we 352 * casually overwrite (we can put it back later). 353 * 354 * If we were concerned about safety, we would want to make all changes 355 * in a temp file and then overwrite the original after everything was 356 * safely written. Not really a concern for us. 357 */ 358 status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size, 359 const char* storageName, int sourceType, int compressionMethod, 360 ZipEntry** ppEntry) 361 { 362 ZipEntry* pEntry = NULL; 363 status_t result = NO_ERROR; 364 long lfhPosn, startPosn, endPosn, uncompressedLen; 365 FILE* inputFp = NULL; 366 unsigned long crc; 367 time_t modWhen = 0; 368 369 if (mReadOnly) 370 return INVALID_OPERATION; 371 372 assert(compressionMethod == ZipEntry::kCompressDeflated || 373 compressionMethod == ZipEntry::kCompressStored); 374 375 /* make sure we're in a reasonable state */ 376 assert(mZipFp != NULL); 377 assert(mEntries.size() == mEOCD.mTotalNumEntries); 378 379 /* make sure it doesn't already exist */ 380 if (getEntryByName(storageName) != NULL) 381 return ALREADY_EXISTS; 382 383 if (!data) { 384 inputFp = fopen(fileName, FILE_OPEN_RO); 385 if (inputFp == NULL) 386 return errnoToStatus(errno); 387 } 388 389 if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { 390 result = UNKNOWN_ERROR; 391 goto bail; 392 } 393 394 pEntry = new ZipEntry; 395 pEntry->initNew(storageName, NULL); 396 397 /* 398 * From here on out, failures are more interesting. 399 */ 400 mNeedCDRewrite = true; 401 402 /* 403 * Write the LFH, even though it's still mostly blank. We need it 404 * as a place-holder. In theory the LFH isn't necessary, but in 405 * practice some utilities demand it. 406 */ 407 lfhPosn = ftell(mZipFp); 408 pEntry->mLFH.write(mZipFp); 409 startPosn = ftell(mZipFp); 410 411 /* 412 * Copy the data in, possibly compressing it as we go. 413 */ 414 if (sourceType == ZipEntry::kCompressStored) { 415 if (compressionMethod == ZipEntry::kCompressDeflated) { 416 bool failed = false; 417 result = compressFpToFp(mZipFp, inputFp, data, size, &crc); 418 if (result != NO_ERROR) { 419 ALOGD("compression failed, storing\n"); 420 failed = true; 421 } else { 422 /* 423 * Make sure it has compressed "enough". This probably ought 424 * to be set through an API call, but I don't expect our 425 * criteria to change over time. 426 */ 427 long src = inputFp ? ftell(inputFp) : size; 428 long dst = ftell(mZipFp) - startPosn; 429 if (dst + (dst / 10) > src) { 430 ALOGD("insufficient compression (src=%ld dst=%ld), storing\n", 431 src, dst); 432 failed = true; 433 } 434 } 435 436 if (failed) { 437 compressionMethod = ZipEntry::kCompressStored; 438 if (inputFp) rewind(inputFp); 439 fseek(mZipFp, startPosn, SEEK_SET); 440 /* fall through to kCompressStored case */ 441 } 442 } 443 /* handle "no compression" request, or failed compression from above */ 444 if (compressionMethod == ZipEntry::kCompressStored) { 445 if (inputFp) { 446 result = copyFpToFp(mZipFp, inputFp, &crc); 447 } else { 448 result = copyDataToFp(mZipFp, data, size, &crc); 449 } 450 if (result != NO_ERROR) { 451 // don't need to truncate; happens in CDE rewrite 452 ALOGD("failed copying data in\n"); 453 goto bail; 454 } 455 } 456 457 // currently seeked to end of file 458 uncompressedLen = inputFp ? ftell(inputFp) : size; 459 } else if (sourceType == ZipEntry::kCompressDeflated) { 460 /* we should support uncompressed-from-compressed, but it's not 461 * important right now */ 462 assert(compressionMethod == ZipEntry::kCompressDeflated); 463 464 bool scanResult; 465 int method; 466 long compressedLen; 467 468 scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen, 469 &compressedLen, &crc); 470 if (!scanResult || method != ZipEntry::kCompressDeflated) { 471 ALOGD("this isn't a deflated gzip file?"); 472 result = UNKNOWN_ERROR; 473 goto bail; 474 } 475 476 result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL); 477 if (result != NO_ERROR) { 478 ALOGD("failed copying gzip data in\n"); 479 goto bail; 480 } 481 } else { 482 assert(false); 483 result = UNKNOWN_ERROR; 484 goto bail; 485 } 486 487 /* 488 * We could write the "Data Descriptor", but there doesn't seem to 489 * be any point since we're going to go back and write the LFH. 490 * 491 * Update file offsets. 492 */ 493 endPosn = ftell(mZipFp); // seeked to end of compressed data 494 495 /* 496 * Success! Fill out new values. 497 */ 498 pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc, 499 compressionMethod); 500 pEntry->setModWhen(modWhen); 501 pEntry->setLFHOffset(lfhPosn); 502 mEOCD.mNumEntries++; 503 mEOCD.mTotalNumEntries++; 504 mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() 505 mEOCD.mCentralDirOffset = endPosn; 506 507 /* 508 * Go back and write the LFH. 509 */ 510 if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) { 511 result = UNKNOWN_ERROR; 512 goto bail; 513 } 514 pEntry->mLFH.write(mZipFp); 515 516 /* 517 * Add pEntry to the list. 518 */ 519 mEntries.add(pEntry); 520 if (ppEntry != NULL) 521 *ppEntry = pEntry; 522 pEntry = NULL; 523 524 bail: 525 if (inputFp != NULL) 526 fclose(inputFp); 527 delete pEntry; 528 return result; 529 } 530 531 /* 532 * Add an entry by copying it from another zip file. If "padding" is 533 * nonzero, the specified number of bytes will be added to the "extra" 534 * field in the header. 535 * 536 * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. 537 */ 538 status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, 539 int padding, ZipEntry** ppEntry) 540 { 541 ZipEntry* pEntry = NULL; 542 status_t result; 543 long lfhPosn, endPosn; 544 545 if (mReadOnly) 546 return INVALID_OPERATION; 547 548 /* make sure we're in a reasonable state */ 549 assert(mZipFp != NULL); 550 assert(mEntries.size() == mEOCD.mTotalNumEntries); 551 552 if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { 553 result = UNKNOWN_ERROR; 554 goto bail; 555 } 556 557 pEntry = new ZipEntry; 558 if (pEntry == NULL) { 559 result = NO_MEMORY; 560 goto bail; 561 } 562 563 result = pEntry->initFromExternal(pSourceZip, pSourceEntry); 564 if (result != NO_ERROR) 565 goto bail; 566 if (padding != 0) { 567 result = pEntry->addPadding(padding); 568 if (result != NO_ERROR) 569 goto bail; 570 } 571 572 /* 573 * From here on out, failures are more interesting. 574 */ 575 mNeedCDRewrite = true; 576 577 /* 578 * Write the LFH. Since we're not recompressing the data, we already 579 * have all of the fields filled out. 580 */ 581 lfhPosn = ftell(mZipFp); 582 pEntry->mLFH.write(mZipFp); 583 584 /* 585 * Copy the data over. 586 * 587 * If the "has data descriptor" flag is set, we want to copy the DD 588 * fields as well. This is a fixed-size area immediately following 589 * the data. 590 */ 591 if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0) 592 { 593 result = UNKNOWN_ERROR; 594 goto bail; 595 } 596 597 off_t copyLen; 598 copyLen = pSourceEntry->getCompressedLen(); 599 if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0) 600 copyLen += ZipEntry::kDataDescriptorLen; 601 602 if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL) 603 != NO_ERROR) 604 { 605 ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName); 606 result = UNKNOWN_ERROR; 607 goto bail; 608 } 609 610 /* 611 * Update file offsets. 612 */ 613 endPosn = ftell(mZipFp); 614 615 /* 616 * Success! Fill out new values. 617 */ 618 pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset 619 mEOCD.mNumEntries++; 620 mEOCD.mTotalNumEntries++; 621 mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() 622 mEOCD.mCentralDirOffset = endPosn; 623 624 /* 625 * Add pEntry to the list. 626 */ 627 mEntries.add(pEntry); 628 if (ppEntry != NULL) 629 *ppEntry = pEntry; 630 pEntry = NULL; 631 632 result = NO_ERROR; 633 634 bail: 635 delete pEntry; 636 return result; 637 } 638 639 /* 640 * Copy all of the bytes in "src" to "dst". 641 * 642 * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" 643 * will be seeked immediately past the data. 644 */ 645 status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32) 646 { 647 unsigned char tmpBuf[32768]; 648 size_t count; 649 650 *pCRC32 = crc32(0L, Z_NULL, 0); 651 652 while (1) { 653 count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp); 654 if (ferror(srcFp) || ferror(dstFp)) 655 return errnoToStatus(errno); 656 if (count == 0) 657 break; 658 659 *pCRC32 = crc32(*pCRC32, tmpBuf, count); 660 661 if (fwrite(tmpBuf, 1, count, dstFp) != count) { 662 ALOGD("fwrite %d bytes failed\n", (int) count); 663 return UNKNOWN_ERROR; 664 } 665 } 666 667 return NO_ERROR; 668 } 669 670 /* 671 * Copy all of the bytes in "src" to "dst". 672 * 673 * On exit, "dstFp" will be seeked immediately past the data. 674 */ 675 status_t ZipFile::copyDataToFp(FILE* dstFp, 676 const void* data, size_t size, unsigned long* pCRC32) 677 { 678 *pCRC32 = crc32(0L, Z_NULL, 0); 679 if (size > 0) { 680 *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size); 681 if (fwrite(data, 1, size, dstFp) != size) { 682 ALOGD("fwrite %d bytes failed\n", (int) size); 683 return UNKNOWN_ERROR; 684 } 685 } 686 687 return NO_ERROR; 688 } 689 690 /* 691 * Copy some of the bytes in "src" to "dst". 692 * 693 * If "pCRC32" is NULL, the CRC will not be computed. 694 * 695 * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" 696 * will be seeked immediately past the data just written. 697 */ 698 status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length, 699 unsigned long* pCRC32) 700 { 701 unsigned char tmpBuf[32768]; 702 size_t count; 703 704 if (pCRC32 != NULL) 705 *pCRC32 = crc32(0L, Z_NULL, 0); 706 707 while (length) { 708 long readSize; 709 710 readSize = sizeof(tmpBuf); 711 if (readSize > length) 712 readSize = length; 713 714 count = fread(tmpBuf, 1, readSize, srcFp); 715 if ((long) count != readSize) { // error or unexpected EOF 716 ALOGD("fread %d bytes failed\n", (int) readSize); 717 return UNKNOWN_ERROR; 718 } 719 720 if (pCRC32 != NULL) 721 *pCRC32 = crc32(*pCRC32, tmpBuf, count); 722 723 if (fwrite(tmpBuf, 1, count, dstFp) != count) { 724 ALOGD("fwrite %d bytes failed\n", (int) count); 725 return UNKNOWN_ERROR; 726 } 727 728 length -= readSize; 729 } 730 731 return NO_ERROR; 732 } 733 734 /* 735 * Compress all of the data in "srcFp" and write it to "dstFp". 736 * 737 * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" 738 * will be seeked immediately past the compressed data. 739 */ 740 status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp, 741 const void* data, size_t size, unsigned long* pCRC32) 742 { 743 status_t result = NO_ERROR; 744 const size_t kBufSize = 32768; 745 unsigned char* inBuf = NULL; 746 unsigned char* outBuf = NULL; 747 z_stream zstream; 748 bool atEof = false; // no feof() aviailable yet 749 unsigned long crc; 750 int zerr; 751 752 /* 753 * Create an input buffer and an output buffer. 754 */ 755 inBuf = new unsigned char[kBufSize]; 756 outBuf = new unsigned char[kBufSize]; 757 if (inBuf == NULL || outBuf == NULL) { 758 result = NO_MEMORY; 759 goto bail; 760 } 761 762 /* 763 * Initialize the zlib stream. 764 */ 765 memset(&zstream, 0, sizeof(zstream)); 766 zstream.zalloc = Z_NULL; 767 zstream.zfree = Z_NULL; 768 zstream.opaque = Z_NULL; 769 zstream.next_in = NULL; 770 zstream.avail_in = 0; 771 zstream.next_out = outBuf; 772 zstream.avail_out = kBufSize; 773 zstream.data_type = Z_UNKNOWN; 774 775 zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION, 776 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); 777 if (zerr != Z_OK) { 778 result = UNKNOWN_ERROR; 779 if (zerr == Z_VERSION_ERROR) { 780 ALOGE("Installed zlib is not compatible with linked version (%s)\n", 781 ZLIB_VERSION); 782 } else { 783 ALOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr); 784 } 785 goto bail; 786 } 787 788 crc = crc32(0L, Z_NULL, 0); 789 790 /* 791 * Loop while we have data. 792 */ 793 do { 794 size_t getSize; 795 int flush; 796 797 /* only read if the input buffer is empty */ 798 if (zstream.avail_in == 0 && !atEof) { 799 ALOGV("+++ reading %d bytes\n", (int)kBufSize); 800 if (data) { 801 getSize = size > kBufSize ? kBufSize : size; 802 memcpy(inBuf, data, getSize); 803 data = ((const char*)data) + getSize; 804 size -= getSize; 805 } else { 806 getSize = fread(inBuf, 1, kBufSize, srcFp); 807 if (ferror(srcFp)) { 808 ALOGD("deflate read failed (errno=%d)\n", errno); 809 goto z_bail; 810 } 811 } 812 if (getSize < kBufSize) { 813 ALOGV("+++ got %d bytes, EOF reached\n", 814 (int)getSize); 815 atEof = true; 816 } 817 818 crc = crc32(crc, inBuf, getSize); 819 820 zstream.next_in = inBuf; 821 zstream.avail_in = getSize; 822 } 823 824 if (atEof) 825 flush = Z_FINISH; /* tell zlib that we're done */ 826 else 827 flush = Z_NO_FLUSH; /* more to come! */ 828 829 zerr = deflate(&zstream, flush); 830 if (zerr != Z_OK && zerr != Z_STREAM_END) { 831 ALOGD("zlib deflate call failed (zerr=%d)\n", zerr); 832 result = UNKNOWN_ERROR; 833 goto z_bail; 834 } 835 836 /* write when we're full or when we're done */ 837 if (zstream.avail_out == 0 || 838 (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize)) 839 { 840 ALOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf)); 841 if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) != 842 (size_t)(zstream.next_out - outBuf)) 843 { 844 ALOGD("write %d failed in deflate\n", 845 (int) (zstream.next_out - outBuf)); 846 goto z_bail; 847 } 848 849 zstream.next_out = outBuf; 850 zstream.avail_out = kBufSize; 851 } 852 } while (zerr == Z_OK); 853 854 assert(zerr == Z_STREAM_END); /* other errors should've been caught */ 855 856 *pCRC32 = crc; 857 858 z_bail: 859 deflateEnd(&zstream); /* free up any allocated structures */ 860 861 bail: 862 delete[] inBuf; 863 delete[] outBuf; 864 865 return result; 866 } 867 868 /* 869 * Mark an entry as deleted. 870 * 871 * We will eventually need to crunch the file down, but if several files 872 * are being removed (perhaps as part of an "update" process) we can make 873 * things considerably faster by deferring the removal to "flush" time. 874 */ 875 status_t ZipFile::remove(ZipEntry* pEntry) 876 { 877 /* 878 * Should verify that pEntry is actually part of this archive, and 879 * not some stray ZipEntry from a different file. 880 */ 881 882 /* mark entry as deleted, and mark archive as dirty */ 883 pEntry->setDeleted(); 884 mNeedCDRewrite = true; 885 return NO_ERROR; 886 } 887 888 /* 889 * Flush any pending writes. 890 * 891 * In particular, this will crunch out deleted entries, and write the 892 * Central Directory and EOCD if we have stomped on them. 893 */ 894 status_t ZipFile::flush(void) 895 { 896 status_t result = NO_ERROR; 897 long eocdPosn; 898 int i, count; 899 900 if (mReadOnly) 901 return INVALID_OPERATION; 902 if (!mNeedCDRewrite) 903 return NO_ERROR; 904 905 assert(mZipFp != NULL); 906 907 result = crunchArchive(); 908 if (result != NO_ERROR) 909 return result; 910 911 if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) 912 return UNKNOWN_ERROR; 913 914 count = mEntries.size(); 915 for (i = 0; i < count; i++) { 916 ZipEntry* pEntry = mEntries[i]; 917 pEntry->mCDE.write(mZipFp); 918 } 919 920 eocdPosn = ftell(mZipFp); 921 mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset; 922 923 mEOCD.write(mZipFp); 924 925 /* 926 * If we had some stuff bloat up during compression and get replaced 927 * with plain files, or if we deleted some entries, there's a lot 928 * of wasted space at the end of the file. Remove it now. 929 */ 930 if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) { 931 ALOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno)); 932 // not fatal 933 } 934 935 /* should we clear the "newly added" flag in all entries now? */ 936 937 mNeedCDRewrite = false; 938 return NO_ERROR; 939 } 940 941 /* 942 * Crunch deleted files out of an archive by shifting the later files down. 943 * 944 * Because we're not using a temp file, we do the operation inside the 945 * current file. 946 */ 947 status_t ZipFile::crunchArchive(void) 948 { 949 status_t result = NO_ERROR; 950 int i, count; 951 long delCount, adjust; 952 953 #if 0 954 printf("CONTENTS:\n"); 955 for (i = 0; i < (int) mEntries.size(); i++) { 956 printf(" %d: lfhOff=%ld del=%d\n", 957 i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted()); 958 } 959 printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset); 960 #endif 961 962 /* 963 * Roll through the set of files, shifting them as appropriate. We 964 * could probably get a slight performance improvement by sliding 965 * multiple files down at once (because we could use larger reads 966 * when operating on batches of small files), but it's not that useful. 967 */ 968 count = mEntries.size(); 969 delCount = adjust = 0; 970 for (i = 0; i < count; i++) { 971 ZipEntry* pEntry = mEntries[i]; 972 long span; 973 974 if (pEntry->getLFHOffset() != 0) { 975 long nextOffset; 976 977 /* Get the length of this entry by finding the offset 978 * of the next entry. Directory entries don't have 979 * file offsets, so we need to find the next non-directory 980 * entry. 981 */ 982 nextOffset = 0; 983 for (int ii = i+1; nextOffset == 0 && ii < count; ii++) 984 nextOffset = mEntries[ii]->getLFHOffset(); 985 if (nextOffset == 0) 986 nextOffset = mEOCD.mCentralDirOffset; 987 span = nextOffset - pEntry->getLFHOffset(); 988 989 assert(span >= ZipEntry::LocalFileHeader::kLFHLen); 990 } else { 991 /* This is a directory entry. It doesn't have 992 * any actual file contents, so there's no need to 993 * move anything. 994 */ 995 span = 0; 996 } 997 998 //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n", 999 // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count); 1000 1001 if (pEntry->getDeleted()) { 1002 adjust += span; 1003 delCount++; 1004 1005 delete pEntry; 1006 mEntries.removeAt(i); 1007 1008 /* adjust loop control */ 1009 count--; 1010 i--; 1011 } else if (span != 0 && adjust > 0) { 1012 /* shuffle this entry back */ 1013 //printf("+++ Shuffling '%s' back %ld\n", 1014 // pEntry->getFileName(), adjust); 1015 result = filemove(mZipFp, pEntry->getLFHOffset() - adjust, 1016 pEntry->getLFHOffset(), span); 1017 if (result != NO_ERROR) { 1018 /* this is why you use a temp file */ 1019 ALOGE("error during crunch - archive is toast\n"); 1020 return result; 1021 } 1022 1023 pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust); 1024 } 1025 } 1026 1027 /* 1028 * Fix EOCD info. We have to wait until the end to do some of this 1029 * because we use mCentralDirOffset to determine "span" for the 1030 * last entry. 1031 */ 1032 mEOCD.mCentralDirOffset -= adjust; 1033 mEOCD.mNumEntries -= delCount; 1034 mEOCD.mTotalNumEntries -= delCount; 1035 mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() 1036 1037 assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries); 1038 assert(mEOCD.mNumEntries == count); 1039 1040 return result; 1041 } 1042 1043 /* 1044 * Works like memmove(), but on pieces of a file. 1045 */ 1046 status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n) 1047 { 1048 if (dst == src || n <= 0) 1049 return NO_ERROR; 1050 1051 unsigned char readBuf[32768]; 1052 1053 if (dst < src) { 1054 /* shift stuff toward start of file; must read from start */ 1055 while (n != 0) { 1056 size_t getSize = sizeof(readBuf); 1057 if (getSize > n) 1058 getSize = n; 1059 1060 if (fseek(fp, (long) src, SEEK_SET) != 0) { 1061 ALOGD("filemove src seek %ld failed\n", (long) src); 1062 return UNKNOWN_ERROR; 1063 } 1064 1065 if (fread(readBuf, 1, getSize, fp) != getSize) { 1066 ALOGD("filemove read %ld off=%ld failed\n", 1067 (long) getSize, (long) src); 1068 return UNKNOWN_ERROR; 1069 } 1070 1071 if (fseek(fp, (long) dst, SEEK_SET) != 0) { 1072 ALOGD("filemove dst seek %ld failed\n", (long) dst); 1073 return UNKNOWN_ERROR; 1074 } 1075 1076 if (fwrite(readBuf, 1, getSize, fp) != getSize) { 1077 ALOGD("filemove write %ld off=%ld failed\n", 1078 (long) getSize, (long) dst); 1079 return UNKNOWN_ERROR; 1080 } 1081 1082 src += getSize; 1083 dst += getSize; 1084 n -= getSize; 1085 } 1086 } else { 1087 /* shift stuff toward end of file; must read from end */ 1088 assert(false); // write this someday, maybe 1089 return UNKNOWN_ERROR; 1090 } 1091 1092 return NO_ERROR; 1093 } 1094 1095 1096 /* 1097 * Get the modification time from a file descriptor. 1098 */ 1099 time_t ZipFile::getModTime(int fd) 1100 { 1101 struct stat sb; 1102 1103 if (fstat(fd, &sb) < 0) { 1104 ALOGD("HEY: fstat on fd %d failed\n", fd); 1105 return (time_t) -1; 1106 } 1107 1108 return sb.st_mtime; 1109 } 1110 1111 1112 #if 0 /* this is a bad idea */ 1113 /* 1114 * Get a copy of the Zip file descriptor. 1115 * 1116 * We don't allow this if the file was opened read-write because we tend 1117 * to leave the file contents in an uncertain state between calls to 1118 * flush(). The duplicated file descriptor should only be valid for reads. 1119 */ 1120 int ZipFile::getZipFd(void) const 1121 { 1122 if (!mReadOnly) 1123 return INVALID_OPERATION; 1124 assert(mZipFp != NULL); 1125 1126 int fd; 1127 fd = dup(fileno(mZipFp)); 1128 if (fd < 0) { 1129 ALOGD("didn't work, errno=%d\n", errno); 1130 } 1131 1132 return fd; 1133 } 1134 #endif 1135 1136 1137 #if 0 1138 /* 1139 * Expand data. 1140 */ 1141 bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const 1142 { 1143 return false; 1144 } 1145 #endif 1146 1147 // free the memory when you're done 1148 void* ZipFile::uncompress(const ZipEntry* entry) 1149 { 1150 size_t unlen = entry->getUncompressedLen(); 1151 size_t clen = entry->getCompressedLen(); 1152 1153 void* buf = malloc(unlen); 1154 if (buf == NULL) { 1155 return NULL; 1156 } 1157 1158 fseek(mZipFp, 0, SEEK_SET); 1159 1160 off_t offset = entry->getFileOffset(); 1161 if (fseek(mZipFp, offset, SEEK_SET) != 0) { 1162 goto bail; 1163 } 1164 1165 switch (entry->getCompressionMethod()) 1166 { 1167 case ZipEntry::kCompressStored: { 1168 ssize_t amt = fread(buf, 1, unlen, mZipFp); 1169 if (amt != (ssize_t)unlen) { 1170 goto bail; 1171 } 1172 #if 0 1173 printf("data...\n"); 1174 const unsigned char* p = (unsigned char*)buf; 1175 const unsigned char* end = p+unlen; 1176 for (int i=0; i<32 && p < end; i++) { 1177 printf("0x%08x ", (int)(offset+(i*0x10))); 1178 for (int j=0; j<0x10 && p < end; j++) { 1179 printf(" %02x", *p); 1180 p++; 1181 } 1182 printf("\n"); 1183 } 1184 #endif 1185 1186 } 1187 break; 1188 case ZipEntry::kCompressDeflated: { 1189 if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) { 1190 goto bail; 1191 } 1192 } 1193 break; 1194 default: 1195 goto bail; 1196 } 1197 return buf; 1198 1199 bail: 1200 free(buf); 1201 return NULL; 1202 } 1203 1204 1205 /* 1206 * =========================================================================== 1207 * ZipFile::EndOfCentralDir 1208 * =========================================================================== 1209 */ 1210 1211 /* 1212 * Read the end-of-central-dir fields. 1213 * 1214 * "buf" should be positioned at the EOCD signature, and should contain 1215 * the entire EOCD area including the comment. 1216 */ 1217 status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len) 1218 { 1219 /* don't allow re-use */ 1220 assert(mComment == NULL); 1221 1222 if (len < kEOCDLen) { 1223 /* looks like ZIP file got truncated */ 1224 ALOGD(" Zip EOCD: expected >= %d bytes, found %d\n", 1225 kEOCDLen, len); 1226 return INVALID_OPERATION; 1227 } 1228 1229 /* this should probably be an assert() */ 1230 if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) 1231 return UNKNOWN_ERROR; 1232 1233 mDiskNumber = ZipEntry::getShortLE(&buf[0x04]); 1234 mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]); 1235 mNumEntries = ZipEntry::getShortLE(&buf[0x08]); 1236 mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]); 1237 mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]); 1238 mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]); 1239 mCommentLen = ZipEntry::getShortLE(&buf[0x14]); 1240 1241 // TODO: validate mCentralDirOffset 1242 1243 if (mCommentLen > 0) { 1244 if (kEOCDLen + mCommentLen > len) { 1245 ALOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n", 1246 kEOCDLen, mCommentLen, len); 1247 return UNKNOWN_ERROR; 1248 } 1249 mComment = new unsigned char[mCommentLen]; 1250 memcpy(mComment, buf + kEOCDLen, mCommentLen); 1251 } 1252 1253 return NO_ERROR; 1254 } 1255 1256 /* 1257 * Write an end-of-central-directory section. 1258 */ 1259 status_t ZipFile::EndOfCentralDir::write(FILE* fp) 1260 { 1261 unsigned char buf[kEOCDLen]; 1262 1263 ZipEntry::putLongLE(&buf[0x00], kSignature); 1264 ZipEntry::putShortLE(&buf[0x04], mDiskNumber); 1265 ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir); 1266 ZipEntry::putShortLE(&buf[0x08], mNumEntries); 1267 ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries); 1268 ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize); 1269 ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset); 1270 ZipEntry::putShortLE(&buf[0x14], mCommentLen); 1271 1272 if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen) 1273 return UNKNOWN_ERROR; 1274 if (mCommentLen > 0) { 1275 assert(mComment != NULL); 1276 if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen) 1277 return UNKNOWN_ERROR; 1278 } 1279 1280 return NO_ERROR; 1281 } 1282 1283 /* 1284 * Dump the contents of an EndOfCentralDir object. 1285 */ 1286 void ZipFile::EndOfCentralDir::dump(void) const 1287 { 1288 ALOGD(" EndOfCentralDir contents:\n"); 1289 ALOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n", 1290 mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries); 1291 ALOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n", 1292 mCentralDirSize, mCentralDirOffset, mCommentLen); 1293 } 1294 1295