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