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