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