Home | History | Annotate | Download | only in zipalign
      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 "zopfli/deflate.h"
     32 
     33 #include <memory.h>
     34 #include <sys/stat.h>
     35 #include <errno.h>
     36 #include <assert.h>
     37 #include <inttypes.h>
     38 
     39 using 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? */
     49 static 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  */
     62 status_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  */
    138 ZipEntry* 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  */
    149 ZipEntry* 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  */
    178 void 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  */
    207 status_t ZipFile::readCentralDir(void)
    208 {
    209     status_t result = NO_ERROR;
    210     uint8_t* 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 uint8_t[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 %" PRIu32 "\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 %" PRIu16 " 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.add(pEntry);
    322     }
    323 
    324 
    325     /*
    326      * If all went well, we should now be back at the EOCD.
    327      */
    328     {
    329         uint8_t 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 
    343 bail:
    344     delete[] buf;
    345     return result;
    346 }
    347 
    348 
    349 /*
    350  * Add a new file to the archive.
    351  *
    352  * This requires creating and populating a ZipEntry structure, and copying
    353  * the data into the file at the appropriate position.  The "appropriate
    354  * position" is the current location of the central directory, which we
    355  * casually overwrite (we can put it back later).
    356  *
    357  * If we were concerned about safety, we would want to make all changes
    358  * in a temp file and then overwrite the original after everything was
    359  * safely written.  Not really a concern for us.
    360  */
    361 status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
    362     const char* storageName, int compressionMethod, ZipEntry** ppEntry)
    363 {
    364     ZipEntry* pEntry = NULL;
    365     status_t result = NO_ERROR;
    366     long lfhPosn, startPosn, endPosn, uncompressedLen;
    367     FILE* inputFp = NULL;
    368     uint32_t crc;
    369     time_t modWhen;
    370 
    371     if (mReadOnly)
    372         return INVALID_OPERATION;
    373 
    374     assert(compressionMethod == ZipEntry::kCompressDeflated ||
    375            compressionMethod == ZipEntry::kCompressStored);
    376 
    377     /* make sure we're in a reasonable state */
    378     assert(mZipFp != NULL);
    379     assert(mEntries.size() == mEOCD.mTotalNumEntries);
    380 
    381     /* make sure it doesn't already exist */
    382     if (getEntryByName(storageName) != NULL)
    383         return ALREADY_EXISTS;
    384 
    385     if (!data) {
    386         inputFp = fopen(fileName, FILE_OPEN_RO);
    387         if (inputFp == NULL)
    388             return errnoToStatus(errno);
    389     }
    390 
    391     if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
    392         result = UNKNOWN_ERROR;
    393         goto bail;
    394     }
    395 
    396     pEntry = new ZipEntry;
    397     pEntry->initNew(storageName, NULL);
    398 
    399     /*
    400      * From here on out, failures are more interesting.
    401      */
    402     mNeedCDRewrite = true;
    403 
    404     /*
    405      * Write the LFH, even though it's still mostly blank.  We need it
    406      * as a place-holder.  In theory the LFH isn't necessary, but in
    407      * practice some utilities demand it.
    408      */
    409     lfhPosn = ftell(mZipFp);
    410     pEntry->mLFH.write(mZipFp);
    411     startPosn = ftell(mZipFp);
    412 
    413     /*
    414      * Copy the data in, possibly compressing it as we go.
    415      */
    416     if (compressionMethod == ZipEntry::kCompressDeflated) {
    417         bool failed = false;
    418         result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
    419         if (result != NO_ERROR) {
    420             ALOGD("compression failed, storing\n");
    421             failed = true;
    422         } else {
    423             /*
    424              * Make sure it has compressed "enough".  This probably ought
    425              * to be set through an API call, but I don't expect our
    426              * criteria to change over time.
    427              */
    428             long src = inputFp ? ftell(inputFp) : size;
    429             long dst = ftell(mZipFp) - startPosn;
    430             if (dst + (dst / 10) > src) {
    431                 ALOGD("insufficient compression (src=%ld dst=%ld), storing\n",
    432                     src, dst);
    433                 failed = true;
    434             }
    435         }
    436 
    437         if (failed) {
    438             compressionMethod = ZipEntry::kCompressStored;
    439             if (inputFp) rewind(inputFp);
    440             fseek(mZipFp, startPosn, SEEK_SET);
    441             /* fall through to kCompressStored case */
    442         }
    443     }
    444     /* handle "no compression" request, or failed compression from above */
    445     if (compressionMethod == ZipEntry::kCompressStored) {
    446         if (inputFp) {
    447             result = copyFpToFp(mZipFp, inputFp, &crc);
    448         } else {
    449             result = copyDataToFp(mZipFp, data, size, &crc);
    450         }
    451         if (result != NO_ERROR) {
    452             // don't need to truncate; happens in CDE rewrite
    453             ALOGD("failed copying data in\n");
    454             goto bail;
    455         }
    456     }
    457 
    458     // currently seeked to end of file
    459     uncompressedLen = inputFp ? ftell(inputFp) : size;
    460 
    461     /*
    462      * We could write the "Data Descriptor", but there doesn't seem to
    463      * be any point since we're going to go back and write the LFH.
    464      *
    465      * Update file offsets.
    466      */
    467     endPosn = ftell(mZipFp);            // seeked to end of compressed data
    468 
    469     /*
    470      * Success!  Fill out new values.
    471      */
    472     pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
    473         compressionMethod);
    474     modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
    475     pEntry->setModWhen(modWhen);
    476     pEntry->setLFHOffset(lfhPosn);
    477     mEOCD.mNumEntries++;
    478     mEOCD.mTotalNumEntries++;
    479     mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
    480     mEOCD.mCentralDirOffset = endPosn;
    481 
    482     /*
    483      * Go back and write the LFH.
    484      */
    485     if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
    486         result = UNKNOWN_ERROR;
    487         goto bail;
    488     }
    489     pEntry->mLFH.write(mZipFp);
    490 
    491     /*
    492      * Add pEntry to the list.
    493      */
    494     mEntries.add(pEntry);
    495     if (ppEntry != NULL)
    496         *ppEntry = pEntry;
    497     pEntry = NULL;
    498 
    499 bail:
    500     if (inputFp != NULL)
    501         fclose(inputFp);
    502     delete pEntry;
    503     return result;
    504 }
    505 
    506 /*
    507  * Add an entry by copying it from another zip file.  If "padding" is
    508  * nonzero, the specified number of bytes will be added to the "extra"
    509  * field in the header.
    510  *
    511  * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
    512  */
    513 status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
    514     int padding, ZipEntry** ppEntry)
    515 {
    516     ZipEntry* pEntry = NULL;
    517     status_t result;
    518     long lfhPosn, endPosn;
    519 
    520     if (mReadOnly)
    521         return INVALID_OPERATION;
    522 
    523     /* make sure we're in a reasonable state */
    524     assert(mZipFp != NULL);
    525     assert(mEntries.size() == mEOCD.mTotalNumEntries);
    526 
    527     if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
    528         result = UNKNOWN_ERROR;
    529         goto bail;
    530     }
    531 
    532     pEntry = new ZipEntry;
    533     if (pEntry == NULL) {
    534         result = NO_MEMORY;
    535         goto bail;
    536     }
    537 
    538     result = pEntry->initFromExternal(pSourceEntry);
    539     if (result != NO_ERROR)
    540         goto bail;
    541     if (padding != 0) {
    542         result = pEntry->addPadding(padding);
    543         if (result != NO_ERROR)
    544             goto bail;
    545     }
    546 
    547     /*
    548      * From here on out, failures are more interesting.
    549      */
    550     mNeedCDRewrite = true;
    551 
    552     /*
    553      * Write the LFH.  Since we're not recompressing the data, we already
    554      * have all of the fields filled out.
    555      */
    556     lfhPosn = ftell(mZipFp);
    557     pEntry->mLFH.write(mZipFp);
    558 
    559     /*
    560      * Copy the data over.
    561      *
    562      * If the "has data descriptor" flag is set, we want to copy the DD
    563      * fields as well.  This is a fixed-size area immediately following
    564      * the data.
    565      */
    566     if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
    567     {
    568         result = UNKNOWN_ERROR;
    569         goto bail;
    570     }
    571 
    572     off_t copyLen;
    573     copyLen = pSourceEntry->getCompressedLen();
    574     if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
    575         copyLen += ZipEntry::kDataDescriptorLen;
    576 
    577     if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
    578         != NO_ERROR)
    579     {
    580         ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
    581         result = UNKNOWN_ERROR;
    582         goto bail;
    583     }
    584 
    585     /*
    586      * Update file offsets.
    587      */
    588     endPosn = ftell(mZipFp);
    589 
    590     /*
    591      * Success!  Fill out new values.
    592      */
    593     pEntry->setLFHOffset(lfhPosn);      // sets mCDE.mLocalHeaderRelOffset
    594     mEOCD.mNumEntries++;
    595     mEOCD.mTotalNumEntries++;
    596     mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
    597     mEOCD.mCentralDirOffset = endPosn;
    598 
    599     /*
    600      * Add pEntry to the list.
    601      */
    602     mEntries.add(pEntry);
    603     if (ppEntry != NULL)
    604         *ppEntry = pEntry;
    605     pEntry = NULL;
    606 
    607     result = NO_ERROR;
    608 
    609 bail:
    610     delete pEntry;
    611     return result;
    612 }
    613 
    614 /*
    615  * Add an entry by copying it from another zip file, recompressing with
    616  * Zopfli if already compressed.
    617  *
    618  * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
    619  */
    620 status_t ZipFile::addRecompress(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
    621     ZipEntry** ppEntry)
    622 {
    623     ZipEntry* pEntry = NULL;
    624     status_t result;
    625     long lfhPosn, startPosn, endPosn, uncompressedLen;
    626 
    627     if (mReadOnly)
    628         return INVALID_OPERATION;
    629 
    630     /* make sure we're in a reasonable state */
    631     assert(mZipFp != NULL);
    632     assert(mEntries.size() == mEOCD.mTotalNumEntries);
    633 
    634     if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
    635         result = UNKNOWN_ERROR;
    636         goto bail;
    637     }
    638 
    639     pEntry = new ZipEntry;
    640     if (pEntry == NULL) {
    641         result = NO_MEMORY;
    642         goto bail;
    643     }
    644 
    645     result = pEntry->initFromExternal(pSourceEntry);
    646     if (result != NO_ERROR)
    647         goto bail;
    648 
    649     /*
    650      * From here on out, failures are more interesting.
    651      */
    652     mNeedCDRewrite = true;
    653 
    654     /*
    655      * Write the LFH, even though it's still mostly blank.  We need it
    656      * as a place-holder.  In theory the LFH isn't necessary, but in
    657      * practice some utilities demand it.
    658      */
    659     lfhPosn = ftell(mZipFp);
    660     pEntry->mLFH.write(mZipFp);
    661     startPosn = ftell(mZipFp);
    662 
    663     /*
    664      * Copy the data over.
    665      *
    666      * If the "has data descriptor" flag is set, we want to copy the DD
    667      * fields as well.  This is a fixed-size area immediately following
    668      * the data.
    669      */
    670     if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
    671     {
    672         result = UNKNOWN_ERROR;
    673         goto bail;
    674     }
    675 
    676     uncompressedLen = pSourceEntry->getUncompressedLen();
    677 
    678     if (pSourceEntry->isCompressed()) {
    679         void *buf = pSourceZip->uncompress(pSourceEntry);
    680         if (buf == NULL) {
    681             result = NO_MEMORY;
    682             goto bail;
    683         }
    684         long startPosn = ftell(mZipFp);
    685         uint32_t crc;
    686         if (compressFpToFp(mZipFp, NULL, buf, uncompressedLen, &crc) != NO_ERROR) {
    687             ALOGW("recompress of '%s' failed\n", pEntry->mCDE.mFileName);
    688             result = UNKNOWN_ERROR;
    689             free(buf);
    690             goto bail;
    691         }
    692         long endPosn = ftell(mZipFp);
    693         pEntry->setDataInfo(uncompressedLen, endPosn - startPosn,
    694             pSourceEntry->getCRC32(), ZipEntry::kCompressDeflated);
    695         free(buf);
    696     } else {
    697         off_t copyLen;
    698         copyLen = pSourceEntry->getCompressedLen();
    699         if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
    700             copyLen += ZipEntry::kDataDescriptorLen;
    701 
    702         if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
    703             != NO_ERROR)
    704         {
    705             ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
    706             result = UNKNOWN_ERROR;
    707             goto bail;
    708         }
    709     }
    710 
    711     /*
    712      * Update file offsets.
    713      */
    714     endPosn = ftell(mZipFp);
    715 
    716     /*
    717      * Success!  Fill out new values.
    718      */
    719     pEntry->setLFHOffset(lfhPosn);
    720     mEOCD.mNumEntries++;
    721     mEOCD.mTotalNumEntries++;
    722     mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
    723     mEOCD.mCentralDirOffset = endPosn;
    724 
    725     /*
    726      * Go back and write the LFH.
    727      */
    728     if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
    729         result = UNKNOWN_ERROR;
    730         goto bail;
    731     }
    732     pEntry->mLFH.write(mZipFp);
    733 
    734     /*
    735      * Add pEntry to the list.
    736      */
    737     mEntries.add(pEntry);
    738     if (ppEntry != NULL)
    739         *ppEntry = pEntry;
    740     pEntry = NULL;
    741 
    742     result = NO_ERROR;
    743 
    744 bail:
    745     delete pEntry;
    746     return result;
    747 }
    748 
    749 /*
    750  * Copy all of the bytes in "src" to "dst".
    751  *
    752  * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
    753  * will be seeked immediately past the data.
    754  */
    755 status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, uint32_t* pCRC32)
    756 {
    757     uint8_t tmpBuf[32768];
    758     size_t count;
    759 
    760     *pCRC32 = crc32(0L, Z_NULL, 0);
    761 
    762     while (1) {
    763         count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
    764         if (ferror(srcFp) || ferror(dstFp))
    765             return errnoToStatus(errno);
    766         if (count == 0)
    767             break;
    768 
    769         *pCRC32 = crc32(*pCRC32, tmpBuf, count);
    770 
    771         if (fwrite(tmpBuf, 1, count, dstFp) != count) {
    772             ALOGD("fwrite %d bytes failed\n", (int) count);
    773             return UNKNOWN_ERROR;
    774         }
    775     }
    776 
    777     return NO_ERROR;
    778 }
    779 
    780 /*
    781  * Copy all of the bytes in "src" to "dst".
    782  *
    783  * On exit, "dstFp" will be seeked immediately past the data.
    784  */
    785 status_t ZipFile::copyDataToFp(FILE* dstFp,
    786     const void* data, size_t size, uint32_t* pCRC32)
    787 {
    788     size_t count;
    789 
    790     *pCRC32 = crc32(0L, Z_NULL, 0);
    791     if (size > 0) {
    792         *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
    793         if (fwrite(data, 1, size, dstFp) != size) {
    794             ALOGD("fwrite %d bytes failed\n", (int) size);
    795             return UNKNOWN_ERROR;
    796         }
    797     }
    798 
    799     return NO_ERROR;
    800 }
    801 
    802 /*
    803  * Copy some of the bytes in "src" to "dst".
    804  *
    805  * If "pCRC32" is NULL, the CRC will not be computed.
    806  *
    807  * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
    808  * will be seeked immediately past the data just written.
    809  */
    810 status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
    811     uint32_t* pCRC32)
    812 {
    813     uint8_t tmpBuf[32768];
    814     size_t count;
    815 
    816     if (pCRC32 != NULL)
    817         *pCRC32 = crc32(0L, Z_NULL, 0);
    818 
    819     while (length) {
    820         long readSize;
    821 
    822         readSize = sizeof(tmpBuf);
    823         if (readSize > length)
    824             readSize = length;
    825 
    826         count = fread(tmpBuf, 1, readSize, srcFp);
    827         if ((long) count != readSize) {     // error or unexpected EOF
    828             ALOGD("fread %d bytes failed\n", (int) readSize);
    829             return UNKNOWN_ERROR;
    830         }
    831 
    832         if (pCRC32 != NULL)
    833             *pCRC32 = crc32(*pCRC32, tmpBuf, count);
    834 
    835         if (fwrite(tmpBuf, 1, count, dstFp) != count) {
    836             ALOGD("fwrite %d bytes failed\n", (int) count);
    837             return UNKNOWN_ERROR;
    838         }
    839 
    840         length -= readSize;
    841     }
    842 
    843     return NO_ERROR;
    844 }
    845 
    846 /*
    847  * Compress all of the data in "srcFp" and write it to "dstFp".
    848  *
    849  * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
    850  * will be seeked immediately past the compressed data.
    851  */
    852 status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
    853     const void* data, size_t size, uint32_t* pCRC32)
    854 {
    855     status_t result = NO_ERROR;
    856     const size_t kBufSize = 1024 * 1024;
    857     uint8_t* inBuf = NULL;
    858     uint8_t* outBuf = NULL;
    859     size_t outSize = 0;
    860     bool atEof = false;     // no feof() aviailable yet
    861     uint32_t crc;
    862     ZopfliOptions options;
    863     unsigned char bp = 0;
    864 
    865     ZopfliInitOptions(&options);
    866 
    867     crc = crc32(0L, Z_NULL, 0);
    868 
    869     if (data) {
    870         crc = crc32(crc, (const unsigned char*)data, size);
    871         ZopfliDeflate(&options, 2, true, (const unsigned char*)data, size, &bp,
    872             &outBuf, &outSize);
    873     } else {
    874         /*
    875          * Create an input buffer and an output buffer.
    876          */
    877         inBuf = new uint8_t[kBufSize];
    878         if (inBuf == NULL) {
    879             result = NO_MEMORY;
    880             goto bail;
    881         }
    882 
    883         /*
    884          * Loop while we have data.
    885          */
    886         do {
    887             size_t getSize;
    888             getSize = fread(inBuf, 1, kBufSize, srcFp);
    889             if (ferror(srcFp)) {
    890                 ALOGD("deflate read failed (errno=%d)\n", errno);
    891                 result = UNKNOWN_ERROR;
    892                 delete[] inBuf;
    893                 goto bail;
    894             }
    895             if (getSize < kBufSize) {
    896                 ALOGV("+++  got %d bytes, EOF reached\n",
    897                     (int)getSize);
    898                 atEof = true;
    899             }
    900 
    901             crc = crc32(crc, inBuf, getSize);
    902             ZopfliDeflate(&options, 2, atEof, inBuf, getSize, &bp, &outBuf, &outSize);
    903         } while (!atEof);
    904         delete[] inBuf;
    905     }
    906 
    907     ALOGV("+++ writing %d bytes\n", (int)outSize);
    908     if (fwrite(outBuf, 1, outSize, dstFp) != outSize) {
    909         ALOGD("write %d failed in deflate\n", (int)outSize);
    910         result = UNKNOWN_ERROR;
    911         goto bail;
    912     }
    913 
    914     *pCRC32 = crc;
    915 
    916 bail:
    917     free(outBuf);
    918 
    919     return result;
    920 }
    921 
    922 /*
    923  * Mark an entry as deleted.
    924  *
    925  * We will eventually need to crunch the file down, but if several files
    926  * are being removed (perhaps as part of an "update" process) we can make
    927  * things considerably faster by deferring the removal to "flush" time.
    928  */
    929 status_t ZipFile::remove(ZipEntry* pEntry)
    930 {
    931     /*
    932      * Should verify that pEntry is actually part of this archive, and
    933      * not some stray ZipEntry from a different file.
    934      */
    935 
    936     /* mark entry as deleted, and mark archive as dirty */
    937     pEntry->setDeleted();
    938     mNeedCDRewrite = true;
    939     return NO_ERROR;
    940 }
    941 
    942 /*
    943  * Flush any pending writes.
    944  *
    945  * In particular, this will crunch out deleted entries, and write the
    946  * Central Directory and EOCD if we have stomped on them.
    947  */
    948 status_t ZipFile::flush(void)
    949 {
    950     status_t result = NO_ERROR;
    951     long eocdPosn;
    952     int i, count;
    953 
    954     if (mReadOnly)
    955         return INVALID_OPERATION;
    956     if (!mNeedCDRewrite)
    957         return NO_ERROR;
    958 
    959     assert(mZipFp != NULL);
    960 
    961     result = crunchArchive();
    962     if (result != NO_ERROR)
    963         return result;
    964 
    965     if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
    966         return UNKNOWN_ERROR;
    967 
    968     count = mEntries.size();
    969     for (i = 0; i < count; i++) {
    970         ZipEntry* pEntry = mEntries[i];
    971         pEntry->mCDE.write(mZipFp);
    972     }
    973 
    974     eocdPosn = ftell(mZipFp);
    975     mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
    976 
    977     mEOCD.write(mZipFp);
    978 
    979     /*
    980      * If we had some stuff bloat up during compression and get replaced
    981      * with plain files, or if we deleted some entries, there's a lot
    982      * of wasted space at the end of the file.  Remove it now.
    983      */
    984     if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
    985         ALOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
    986         // not fatal
    987     }
    988 
    989     /* should we clear the "newly added" flag in all entries now? */
    990 
    991     mNeedCDRewrite = false;
    992     return NO_ERROR;
    993 }
    994 
    995 /*
    996  * Crunch deleted files out of an archive by shifting the later files down.
    997  *
    998  * Because we're not using a temp file, we do the operation inside the
    999  * current file.
   1000  */
   1001 status_t ZipFile::crunchArchive(void)
   1002 {
   1003     status_t result = NO_ERROR;
   1004     int i, count;
   1005     long delCount, adjust;
   1006 
   1007 #if 0
   1008     printf("CONTENTS:\n");
   1009     for (i = 0; i < (int) mEntries.size(); i++) {
   1010         printf(" %d: lfhOff=%ld del=%d\n",
   1011             i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
   1012     }
   1013     printf("  END is %ld\n", (long) mEOCD.mCentralDirOffset);
   1014 #endif
   1015 
   1016     /*
   1017      * Roll through the set of files, shifting them as appropriate.  We
   1018      * could probably get a slight performance improvement by sliding
   1019      * multiple files down at once (because we could use larger reads
   1020      * when operating on batches of small files), but it's not that useful.
   1021      */
   1022     count = mEntries.size();
   1023     delCount = adjust = 0;
   1024     for (i = 0; i < count; i++) {
   1025         ZipEntry* pEntry = mEntries[i];
   1026         long span;
   1027 
   1028         if (pEntry->getLFHOffset() != 0) {
   1029             long nextOffset;
   1030 
   1031             /* Get the length of this entry by finding the offset
   1032              * of the next entry.  Directory entries don't have
   1033              * file offsets, so we need to find the next non-directory
   1034              * entry.
   1035              */
   1036             nextOffset = 0;
   1037             for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
   1038                 nextOffset = mEntries[ii]->getLFHOffset();
   1039             if (nextOffset == 0)
   1040                 nextOffset = mEOCD.mCentralDirOffset;
   1041             span = nextOffset - pEntry->getLFHOffset();
   1042 
   1043             assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
   1044         } else {
   1045             /* This is a directory entry.  It doesn't have
   1046              * any actual file contents, so there's no need to
   1047              * move anything.
   1048              */
   1049             span = 0;
   1050         }
   1051 
   1052         //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
   1053         //    i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
   1054 
   1055         if (pEntry->getDeleted()) {
   1056             adjust += span;
   1057             delCount++;
   1058 
   1059             delete pEntry;
   1060             mEntries.removeAt(i);
   1061 
   1062             /* adjust loop control */
   1063             count--;
   1064             i--;
   1065         } else if (span != 0 && adjust > 0) {
   1066             /* shuffle this entry back */
   1067             //printf("+++ Shuffling '%s' back %ld\n",
   1068             //    pEntry->getFileName(), adjust);
   1069             result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
   1070                         pEntry->getLFHOffset(), span);
   1071             if (result != NO_ERROR) {
   1072                 /* this is why you use a temp file */
   1073                 ALOGE("error during crunch - archive is toast\n");
   1074                 return result;
   1075             }
   1076 
   1077             pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
   1078         }
   1079     }
   1080 
   1081     /*
   1082      * Fix EOCD info.  We have to wait until the end to do some of this
   1083      * because we use mCentralDirOffset to determine "span" for the
   1084      * last entry.
   1085      */
   1086     mEOCD.mCentralDirOffset -= adjust;
   1087     mEOCD.mNumEntries -= delCount;
   1088     mEOCD.mTotalNumEntries -= delCount;
   1089     mEOCD.mCentralDirSize = 0;  // mark invalid; set by flush()
   1090 
   1091     assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
   1092     assert(mEOCD.mNumEntries == count);
   1093 
   1094     return result;
   1095 }
   1096 
   1097 /*
   1098  * Works like memmove(), but on pieces of a file.
   1099  */
   1100 status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
   1101 {
   1102     if (dst == src || n <= 0)
   1103         return NO_ERROR;
   1104 
   1105     uint8_t readBuf[32768];
   1106 
   1107     if (dst < src) {
   1108         /* shift stuff toward start of file; must read from start */
   1109         while (n != 0) {
   1110             size_t getSize = sizeof(readBuf);
   1111             if (getSize > n)
   1112                 getSize = n;
   1113 
   1114             if (fseek(fp, (long) src, SEEK_SET) != 0) {
   1115                 ALOGD("filemove src seek %ld failed\n", (long) src);
   1116                 return UNKNOWN_ERROR;
   1117             }
   1118 
   1119             if (fread(readBuf, 1, getSize, fp) != getSize) {
   1120                 ALOGD("filemove read %ld off=%ld failed\n",
   1121                     (long) getSize, (long) src);
   1122                 return UNKNOWN_ERROR;
   1123             }
   1124 
   1125             if (fseek(fp, (long) dst, SEEK_SET) != 0) {
   1126                 ALOGD("filemove dst seek %ld failed\n", (long) dst);
   1127                 return UNKNOWN_ERROR;
   1128             }
   1129 
   1130             if (fwrite(readBuf, 1, getSize, fp) != getSize) {
   1131                 ALOGD("filemove write %ld off=%ld failed\n",
   1132                     (long) getSize, (long) dst);
   1133                 return UNKNOWN_ERROR;
   1134             }
   1135 
   1136             src += getSize;
   1137             dst += getSize;
   1138             n -= getSize;
   1139         }
   1140     } else {
   1141         /* shift stuff toward end of file; must read from end */
   1142         assert(false);      // write this someday, maybe
   1143         return UNKNOWN_ERROR;
   1144     }
   1145 
   1146     return NO_ERROR;
   1147 }
   1148 
   1149 
   1150 /*
   1151  * Get the modification time from a file descriptor.
   1152  */
   1153 time_t ZipFile::getModTime(int fd)
   1154 {
   1155     struct stat sb;
   1156 
   1157     if (fstat(fd, &sb) < 0) {
   1158         ALOGD("HEY: fstat on fd %d failed\n", fd);
   1159         return (time_t) -1;
   1160     }
   1161 
   1162     return sb.st_mtime;
   1163 }
   1164 
   1165 
   1166 #if 0       /* this is a bad idea */
   1167 /*
   1168  * Get a copy of the Zip file descriptor.
   1169  *
   1170  * We don't allow this if the file was opened read-write because we tend
   1171  * to leave the file contents in an uncertain state between calls to
   1172  * flush().  The duplicated file descriptor should only be valid for reads.
   1173  */
   1174 int ZipFile::getZipFd(void) const
   1175 {
   1176     if (!mReadOnly)
   1177         return INVALID_OPERATION;
   1178     assert(mZipFp != NULL);
   1179 
   1180     int fd;
   1181     fd = dup(fileno(mZipFp));
   1182     if (fd < 0) {
   1183         ALOGD("didn't work, errno=%d\n", errno);
   1184     }
   1185 
   1186     return fd;
   1187 }
   1188 #endif
   1189 
   1190 
   1191 #if 0
   1192 /*
   1193  * Expand data.
   1194  */
   1195 bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
   1196 {
   1197     return false;
   1198 }
   1199 #endif
   1200 
   1201 // free the memory when you're done
   1202 void* ZipFile::uncompress(const ZipEntry* entry) const
   1203 {
   1204     size_t unlen = entry->getUncompressedLen();
   1205     size_t clen = entry->getCompressedLen();
   1206 
   1207     void* buf = malloc(unlen);
   1208     if (buf == NULL) {
   1209         return NULL;
   1210     }
   1211 
   1212     fseek(mZipFp, 0, SEEK_SET);
   1213 
   1214     off_t offset = entry->getFileOffset();
   1215     if (fseek(mZipFp, offset, SEEK_SET) != 0) {
   1216         goto bail;
   1217     }
   1218 
   1219     switch (entry->getCompressionMethod())
   1220     {
   1221         case ZipEntry::kCompressStored: {
   1222             ssize_t amt = fread(buf, 1, unlen, mZipFp);
   1223             if (amt != (ssize_t)unlen) {
   1224                 goto bail;
   1225             }
   1226 #if 0
   1227             printf("data...\n");
   1228             const unsigned char* p = (unsigned char*)buf;
   1229             const unsigned char* end = p+unlen;
   1230             for (int i=0; i<32 && p < end; i++) {
   1231                 printf("0x%08x ", (int)(offset+(i*0x10)));
   1232                 for (int j=0; j<0x10 && p < end; j++) {
   1233                     printf(" %02x", *p);
   1234                     p++;
   1235                 }
   1236                 printf("\n");
   1237             }
   1238 #endif
   1239 
   1240             }
   1241             break;
   1242         case ZipEntry::kCompressDeflated: {
   1243             if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
   1244                 goto bail;
   1245             }
   1246             }
   1247             break;
   1248         default:
   1249             goto bail;
   1250     }
   1251     return buf;
   1252 
   1253 bail:
   1254     free(buf);
   1255     return NULL;
   1256 }
   1257 
   1258 
   1259 /*
   1260  * ===========================================================================
   1261  *      ZipFile::EndOfCentralDir
   1262  * ===========================================================================
   1263  */
   1264 
   1265 /*
   1266  * Read the end-of-central-dir fields.
   1267  *
   1268  * "buf" should be positioned at the EOCD signature, and should contain
   1269  * the entire EOCD area including the comment.
   1270  */
   1271 status_t ZipFile::EndOfCentralDir::readBuf(const uint8_t* buf, int len)
   1272 {
   1273     /* don't allow re-use */
   1274     assert(mComment == NULL);
   1275 
   1276     if (len < kEOCDLen) {
   1277         /* looks like ZIP file got truncated */
   1278         ALOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
   1279             kEOCDLen, len);
   1280         return INVALID_OPERATION;
   1281     }
   1282 
   1283     /* this should probably be an assert() */
   1284     if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
   1285         return UNKNOWN_ERROR;
   1286 
   1287     mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
   1288     mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
   1289     mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
   1290     mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
   1291     mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
   1292     mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
   1293     mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
   1294 
   1295     // TODO: validate mCentralDirOffset
   1296 
   1297     if (mCommentLen > 0) {
   1298         if (kEOCDLen + mCommentLen > len) {
   1299             ALOGD("EOCD(%d) + comment(%" PRIu16 ") exceeds len (%d)\n",
   1300                 kEOCDLen, mCommentLen, len);
   1301             return UNKNOWN_ERROR;
   1302         }
   1303         mComment = new uint8_t[mCommentLen];
   1304         memcpy(mComment, buf + kEOCDLen, mCommentLen);
   1305     }
   1306 
   1307     return NO_ERROR;
   1308 }
   1309 
   1310 /*
   1311  * Write an end-of-central-directory section.
   1312  */
   1313 status_t ZipFile::EndOfCentralDir::write(FILE* fp)
   1314 {
   1315     uint8_t buf[kEOCDLen];
   1316 
   1317     ZipEntry::putLongLE(&buf[0x00], kSignature);
   1318     ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
   1319     ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
   1320     ZipEntry::putShortLE(&buf[0x08], mNumEntries);
   1321     ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
   1322     ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
   1323     ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
   1324     ZipEntry::putShortLE(&buf[0x14], mCommentLen);
   1325 
   1326     if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
   1327         return UNKNOWN_ERROR;
   1328     if (mCommentLen > 0) {
   1329         assert(mComment != NULL);
   1330         if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
   1331             return UNKNOWN_ERROR;
   1332     }
   1333 
   1334     return NO_ERROR;
   1335 }
   1336 
   1337 /*
   1338  * Dump the contents of an EndOfCentralDir object.
   1339  */
   1340 void ZipFile::EndOfCentralDir::dump(void) const
   1341 {
   1342     ALOGD(" EndOfCentralDir contents:\n");
   1343     ALOGD("  diskNum=%" PRIu16 " diskWCD=%" PRIu16 " numEnt=%" PRIu16 " totalNumEnt=%" PRIu16 "\n",
   1344         mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
   1345     ALOGD("  centDirSize=%" PRIu32 " centDirOff=%" PRIu32 " commentLen=%" PRIu32 "\n",
   1346         mCentralDirSize, mCentralDirOffset, mCommentLen);
   1347 }
   1348 
   1349