1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2006 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License.
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License.
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Access to Zip archives.
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define LOG_TAG "zip"
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <androidfw/ZipUtils.h>
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Log.h>
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ZipFile.h"
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <zlib.h>
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define DEF_MEM_LEVEL 8                // normally in zutil.h?
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <memory.h>
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <sys/stat.h>
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <errno.h>
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <assert.h>
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiusing namespace android;
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Some environments require the "b", some choke on it.
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define FILE_OPEN_RO        "rb"
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define FILE_OPEN_RW        "r+b"
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define FILE_OPEN_RW_CREATE "w+b"
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* should live somewhere else? */
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic status_t errnoToStatus(int err)
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err == ENOENT)
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NAME_NOT_FOUND;
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else if (err == EACCES)
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return PERMISSION_DENIED;
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open a file and parse its guts.
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::open(const char* zipFileName, int flags)
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool newArchive = false;
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mZipFp == NULL);     // no reopen
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((flags & kOpenTruncate))
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        flags |= kOpenCreate;           // trunc implies create
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return INVALID_OPERATION;       // not both
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return INVALID_OPERATION;       // not neither
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return INVALID_OPERATION;       // create requires write
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (flags & kOpenTruncate) {
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newArchive = true;
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        newArchive = (access(zipFileName, F_OK) != 0);
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!(flags & kOpenCreate) && newArchive) {
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            /* not creating, must already exist */
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("File %s does not exist", zipFileName);
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NAME_NOT_FOUND;
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* open the file */
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* openflags;
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (flags & kOpenReadWrite) {
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (newArchive)
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            openflags = FILE_OPEN_RW_CREATE;
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        else
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            openflags = FILE_OPEN_RW;
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        openflags = FILE_OPEN_RO;
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mZipFp = fopen(zipFileName, openflags);
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mZipFp == NULL) {
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int err = errno;
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("fopen failed: %d\n", err);
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return errnoToStatus(err);
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!newArchive) {
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /*
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * Load the central directory.  If that fails, then this probably
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * isn't a Zip archive.
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         */
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = readCentralDir();
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /*
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * Newly-created.  The EndOfCentralDir constructor actually
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * sets everything to be the way we want it (all zeroes).  We
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * set mNeedCDRewrite so that we create *something* if the
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * caller doesn't add any files.  (We could also just unlink
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * the file if it's brand new and nothing was added, but that's
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * probably doing more than we really should -- the user might
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * have a need for empty zip files.)
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         */
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mNeedCDRewrite = true;
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = NO_ERROR;
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (flags & kOpenReadOnly)
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mReadOnly = true;
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    else
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assert(!mReadOnly);
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return the Nth entry in the archive.
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipEntry* ZipFile::getEntryByIndex(int idx) const
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0 || idx >= (int) mEntries.size())
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return mEntries[idx];
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Find an entry by name.
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipEntry* ZipFile::getEntryByName(const char* fileName) const
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Do a stupid linear string-compare search.
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * There are various ways to speed this up, especially since it's rare
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * to intermingle changes to the archive with "get by name" calls.  We
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * don't want to sort the mEntries vector itself, however, because
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * it's used to recreate the Central Directory.
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * (Hash table works, parallel list of pointers in sorted order is good.)
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int idx;
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (idx = mEntries.size()-1; idx >= 0; idx--) {
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* pEntry = mEntries[idx];
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!pEntry->getDeleted() &&
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strcmp(fileName, pEntry->getFileName()) == 0)
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        {
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return pEntry;
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NULL;
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Empty the mEntries vector.
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid ZipFile::discardEntries(void)
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int count = mEntries.size();
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (--count >= 0)
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete mEntries[count];
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntries.clear();
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Find the central directory and read the contents.
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The fun thing about ZIP archives is that they may or may not be
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * readable from start to end.  In some cases, notably for archives
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * that were written to stdout, the only length information is in the
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * central directory at the end of the file.
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Of course, the central directory can be followed by a variable-length
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * comment field, so we have to scan through it backwards.  The comment
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * itself, plus apparently sometimes people throw random junk on the end
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * just for the fun of it.
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This is all a little wobbly.  If the wrong value ends up in the EOCD
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * area, we're hosed.  This appears to be the way that everbody handles
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * it though, so we're in pretty good company if this fails.
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::readCentralDir(void)
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = NO_ERROR;
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned char* buf = NULL;
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    off_t fileLength, seekStart;
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long readAmount;
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int i;
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fseek(mZipFp, 0, SEEK_END);
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fileLength = ftell(mZipFp);
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    rewind(mZipFp);
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* too small to be a ZIP archive? */
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fileLength < EndOfCentralDir::kEOCDLen) {
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("Length is %ld -- too small\n", (long)fileLength);
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = INVALID_OPERATION;
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (buf == NULL) {
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("Failure allocating %d bytes for EOCD search",
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             EndOfCentralDir::kMaxEOCDSearch);
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = NO_MEMORY;
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        readAmount = EndOfCentralDir::kMaxEOCDSearch;
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        seekStart = 0;
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        readAmount = (long) fileLength;
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("Failure seeking to end of zip at %ld", (long) seekStart);
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* read the last part of the file into the buffer */
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("short file? wanted %ld\n", readAmount);
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* find the end-of-central-dir magic */
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = readAmount - 4; i >= 0; i--) {
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (buf[i] == 0x50 &&
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        {
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGV("+++ Found EOCD at buf+%d\n", i);
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (i < 0) {
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("EOCD not found, not Zip\n");
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = INVALID_OPERATION;
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* extract eocd values */
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = mEOCD.readBuf(buf + i, readAmount - i);
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //mEOCD.dump();
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("Archive spanning not supported\n");
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = INVALID_OPERATION;
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * So far so good.  "mCentralDirSize" is the size in bytes of the
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * central directory, so we can just seek back that far to find it.
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * We can also seek forward mCentralDirOffset bytes from the
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * start of the file.
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * We're not guaranteed to have the rest of the central dir in the
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * buffer, nor are we guaranteed that the central dir will have any
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * sort of convenient size.  We need to skip to the start of it and
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * read the header, then the other goodies.
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * The only thing we really need right now is the file comment, which
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * we're hoping to preserve.
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("Failure seeking to central dir offset %ld\n",
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             mEOCD.mCentralDirOffset);
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Loop through and read the central dir entries.
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ALOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int entry;
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* pEntry = new ZipEntry;
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = pEntry->initFromCDE(mZipFp);
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("initFromCDE failed\n");
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete pEntry;
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mEntries.add(pEntry);
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * If all went well, we should now be back at the EOCD.
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        unsigned char checkBuf[4];
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (fread(checkBuf, 1, 4, mZipFp) != 4) {
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("EOCD check read failed\n");
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = INVALID_OPERATION;
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("EOCD read check failed\n");
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = UNKNOWN_ERROR;
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGV("+++ EOCD read check passed\n");
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete[] buf;
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Add a new file to the archive.
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This requires creating and populating a ZipEntry structure, and copying
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the data into the file at the appropriate position.  The "appropriate
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * position" is the current location of the central directory, which we
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * casually overwrite (we can put it back later).
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If we were concerned about safety, we would want to make all changes
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * in a temp file and then overwrite the original after everything was
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * safely written.  Not really a concern for us.
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* storageName, int sourceType, int compressionMethod,
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry** ppEntry)
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry* pEntry = NULL;
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = NO_ERROR;
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long lfhPosn, startPosn, endPosn, uncompressedLen;
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    FILE* inputFp = NULL;
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned long crc;
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    time_t modWhen;
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mReadOnly)
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return INVALID_OPERATION;
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(compressionMethod == ZipEntry::kCompressDeflated ||
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski           compressionMethod == ZipEntry::kCompressStored);
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* make sure we're in a reasonable state */
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mZipFp != NULL);
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mEntries.size() == mEOCD.mTotalNumEntries);
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* make sure it doesn't already exist */
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (getEntryByName(storageName) != NULL)
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return ALREADY_EXISTS;
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!data) {
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        inputFp = fopen(fileName, FILE_OPEN_RO);
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (inputFp == NULL)
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return errnoToStatus(errno);
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry = new ZipEntry;
395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry->initNew(storageName, NULL);
396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * From here on out, failures are more interesting.
399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mNeedCDRewrite = true;
401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Write the LFH, even though it's still mostly blank.  We need it
404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * as a place-holder.  In theory the LFH isn't necessary, but in
405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * practice some utilities demand it.
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    lfhPosn = ftell(mZipFp);
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry->mLFH.write(mZipFp);
409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    startPosn = ftell(mZipFp);
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Copy the data in, possibly compressing it as we go.
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (sourceType == ZipEntry::kCompressStored) {
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (compressionMethod == ZipEntry::kCompressDeflated) {
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool failed = false;
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (result != NO_ERROR) {
419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ALOGD("compression failed, storing\n");
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                failed = true;
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                /*
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                 * Make sure it has compressed "enough".  This probably ought
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                 * to be set through an API call, but I don't expect our
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                 * criteria to change over time.
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                 */
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                long src = inputFp ? ftell(inputFp) : size;
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                long dst = ftell(mZipFp) - startPosn;
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dst + (dst / 10) > src) {
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    ALOGD("insufficient compression (src=%ld dst=%ld), storing\n",
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        src, dst);
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    failed = true;
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (failed) {
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                compressionMethod = ZipEntry::kCompressStored;
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (inputFp) rewind(inputFp);
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fseek(mZipFp, startPosn, SEEK_SET);
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                /* fall through to kCompressStored case */
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* handle "no compression" request, or failed compression from above */
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (compressionMethod == ZipEntry::kCompressStored) {
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (inputFp) {
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = copyFpToFp(mZipFp, inputFp, &crc);
447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = copyDataToFp(mZipFp, data, size, &crc);
449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (result != NO_ERROR) {
451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // don't need to truncate; happens in CDE rewrite
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ALOGD("failed copying data in\n");
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // currently seeked to end of file
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uncompressedLen = inputFp ? ftell(inputFp) : size;
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (sourceType == ZipEntry::kCompressDeflated) {
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* we should support uncompressed-from-compressed, but it's not
461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * important right now */
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assert(compressionMethod == ZipEntry::kCompressDeflated);
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool scanResult;
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int method;
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        long compressedLen;
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        &compressedLen, &crc);
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!scanResult || method != ZipEntry::kCompressDeflated) {
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("this isn't a deflated gzip file?");
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = UNKNOWN_ERROR;
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("failed copying gzip data in\n");
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assert(false);
483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * We could write the "Data Descriptor", but there doesn't seem to
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * be any point since we're going to go back and write the LFH.
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Update file offsets.
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    endPosn = ftell(mZipFp);            // seeked to end of compressed data
494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Success!  Fill out new values.
497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        compressionMethod);
500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry->setModWhen(modWhen);
502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry->setLFHOffset(lfhPosn);
503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mNumEntries++;
504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mTotalNumEntries++;
505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mCentralDirOffset = endPosn;
507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Go back and write the LFH.
510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry->mLFH.write(mZipFp);
516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Add pEntry to the list.
519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntries.add(pEntry);
521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (ppEntry != NULL)
522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *ppEntry = pEntry;
523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry = NULL;
524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (inputFp != NULL)
527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(inputFp);
528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete pEntry;
529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Add an entry by copying it from another zip file.  If "padding" is
534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * nonzero, the specified number of bytes will be added to the "extra"
535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * field in the header.
536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int padding, ZipEntry** ppEntry)
541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry* pEntry = NULL;
543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long lfhPosn, endPosn;
545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mReadOnly)
547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return INVALID_OPERATION;
548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* make sure we're in a reasonable state */
550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mZipFp != NULL);
551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mEntries.size() == mEOCD.mTotalNumEntries);
552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry = new ZipEntry;
559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (pEntry == NULL) {
560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = NO_MEMORY;
561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR)
566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (padding != 0) {
568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = pEntry->addPadding(padding);
569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR)
570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * From here on out, failures are more interesting.
575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mNeedCDRewrite = true;
577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Write the LFH.  Since we're not recompressing the data, we already
580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * have all of the fields filled out.
581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    lfhPosn = ftell(mZipFp);
583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry->mLFH.write(mZipFp);
584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Copy the data over.
587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * If the "has data descriptor" flag is set, we want to copy the DD
589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * fields as well.  This is a fixed-size area immediately following
590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * the data.
591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {
594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    off_t copyLen;
599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    copyLen = pSourceEntry->getCompressedLen();
600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        copyLen += ZipEntry::kDataDescriptorLen;
602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        != NO_ERROR)
605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {
606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Update file offsets.
613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    endPosn = ftell(mZipFp);
615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Success!  Fill out new values.
618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry->setLFHOffset(lfhPosn);      // sets mCDE.mLocalHeaderRelOffset
620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mNumEntries++;
621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mTotalNumEntries++;
622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mCentralDirOffset = endPosn;
624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Add pEntry to the list.
627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEntries.add(pEntry);
629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (ppEntry != NULL)
630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *ppEntry = pEntry;
631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry = NULL;
632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete pEntry;
637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copy all of the bytes in "src" to "dst".
642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * will be seeked immediately past the data.
645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned char tmpBuf[32768];
649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t count;
650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    *pCRC32 = crc32(0L, Z_NULL, 0);
652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (1) {
654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (ferror(srcFp) || ferror(dstFp))
656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return errnoToStatus(errno);
657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (count == 0)
658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *pCRC32 = crc32(*pCRC32, tmpBuf, count);
661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("fwrite %d bytes failed\n", (int) count);
664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copy all of the bytes in "src" to "dst".
673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * On exit, "dstFp" will be seeked immediately past the data.
675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::copyDataToFp(FILE* dstFp,
677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const void* data, size_t size, unsigned long* pCRC32)
678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t count;
680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    *pCRC32 = crc32(0L, Z_NULL, 0);
682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (size > 0) {
683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (fwrite(data, 1, size, dstFp) != size) {
685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("fwrite %d bytes failed\n", (int) size);
686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copy some of the bytes in "src" to "dst".
695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If "pCRC32" is NULL, the CRC will not be computed.
697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * will be seeked immediately past the data just written.
700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned long* pCRC32)
703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned char tmpBuf[32768];
705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t count;
706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (pCRC32 != NULL)
708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *pCRC32 = crc32(0L, Z_NULL, 0);
709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (length) {
711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        long readSize;
712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        readSize = sizeof(tmpBuf);
714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (readSize > length)
715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            readSize = length;
716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        count = fread(tmpBuf, 1, readSize, srcFp);
718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if ((long) count != readSize) {     // error or unexpected EOF
719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("fread %d bytes failed\n", (int) readSize);
720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (pCRC32 != NULL)
724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *pCRC32 = crc32(*pCRC32, tmpBuf, count);
725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("fwrite %d bytes failed\n", (int) count);
728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        length -= readSize;
732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Compress all of the data in "srcFp" and write it to "dstFp".
739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * will be seeked immediately past the compressed data.
742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const void* data, size_t size, unsigned long* pCRC32)
745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = NO_ERROR;
747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t kBufSize = 32768;
748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned char* inBuf = NULL;
749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned char* outBuf = NULL;
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    z_stream zstream;
751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool atEof = false;     // no feof() aviailable yet
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned long crc;
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int zerr;
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Create an input buffer and an output buffer.
757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    inBuf = new unsigned char[kBufSize];
759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    outBuf = new unsigned char[kBufSize];
760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (inBuf == NULL || outBuf == NULL) {
761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = NO_MEMORY;
762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
765282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
766282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Initialize the zlib stream.
767282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
768282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    memset(&zstream, 0, sizeof(zstream));
769282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zstream.zalloc = Z_NULL;
770282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zstream.zfree = Z_NULL;
771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zstream.opaque = Z_NULL;
772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zstream.next_in = NULL;
773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zstream.avail_in = 0;
774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zstream.next_out = outBuf;
775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zstream.avail_out = kBufSize;
776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zstream.data_type = Z_UNKNOWN;
777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zerr != Z_OK) {
781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = UNKNOWN_ERROR;
782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (zerr == Z_VERSION_ERROR) {
783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ZLIB_VERSION);
785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    crc = crc32(0L, Z_NULL, 0);
792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Loop while we have data.
795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    do {
797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t getSize;
798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int flush;
799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* only read if the input buffer is empty */
801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (zstream.avail_in == 0 && !atEof) {
802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGV("+++ reading %d bytes\n", (int)kBufSize);
803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (data) {
804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                getSize = size > kBufSize ? kBufSize : size;
805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                memcpy(inBuf, data, getSize);
806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                data = ((const char*)data) + getSize;
807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                size -= getSize;
808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                getSize = fread(inBuf, 1, kBufSize, srcFp);
810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (ferror(srcFp)) {
811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    ALOGD("deflate read failed (errno=%d)\n", errno);
812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    goto z_bail;
813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (getSize < kBufSize) {
816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ALOGV("+++  got %d bytes, EOF reached\n",
817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    (int)getSize);
818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                atEof = true;
819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            crc = crc32(crc, inBuf, getSize);
822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zstream.next_in = inBuf;
824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zstream.avail_in = getSize;
825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (atEof)
828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            flush = Z_FINISH;       /* tell zlib that we're done */
829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        else
830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            flush = Z_NO_FLUSH;     /* more to come! */
831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        zerr = deflate(&zstream, flush);
833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (zerr != Z_OK && zerr != Z_STREAM_END) {
834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("zlib deflate call failed (zerr=%d)\n", zerr);
835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = UNKNOWN_ERROR;
836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto z_bail;
837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* write when we're full or when we're done */
840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (zstream.avail_out == 0 ||
841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        {
843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (size_t)(zstream.next_out - outBuf))
846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            {
847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ALOGD("write %d failed in deflate\n",
848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    (int) (zstream.next_out - outBuf));
849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto z_bail;
850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zstream.next_out = outBuf;
853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zstream.avail_out = kBufSize;
854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } while (zerr == Z_OK);
856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    *pCRC32 = crc;
860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiz_bail:
862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    deflateEnd(&zstream);        /* free up any allocated structures */
863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete[] inBuf;
866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete[] outBuf;
867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Mark an entry as deleted.
873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * We will eventually need to crunch the file down, but if several files
875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * are being removed (perhaps as part of an "update" process) we can make
876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * things considerably faster by deferring the removal to "flush" time.
877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::remove(ZipEntry* pEntry)
879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Should verify that pEntry is actually part of this archive, and
882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * not some stray ZipEntry from a different file.
883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* mark entry as deleted, and mark archive as dirty */
886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    pEntry->setDeleted();
887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mNeedCDRewrite = true;
888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
892282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Flush any pending writes.
893282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * In particular, this will crunch out deleted entries, and write the
895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Central Directory and EOCD if we have stomped on them.
896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
897282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::flush(void)
898282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = NO_ERROR;
900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long eocdPosn;
901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int i, count;
902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mReadOnly)
904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return INVALID_OPERATION;
905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!mNeedCDRewrite)
906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NO_ERROR;
907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mZipFp != NULL);
909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = crunchArchive();
911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR)
912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return result;
913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    count = mEntries.size();
918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = 0; i < count; i++) {
919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* pEntry = mEntries[i];
920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        pEntry->mCDE.write(mZipFp);
921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    eocdPosn = ftell(mZipFp);
924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.write(mZipFp);
927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * If we had some stuff bloat up during compression and get replaced
930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * with plain files, or if we deleted some entries, there's a lot
931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * of wasted space at the end of the file.  Remove it now.
932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // not fatal
936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* should we clear the "newly added" flag in all entries now? */
939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mNeedCDRewrite = false;
941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Crunch deleted files out of an archive by shifting the later files down.
946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Because we're not using a temp file, we do the operation inside the
948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * current file.
949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::crunchArchive(void)
951282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = NO_ERROR;
953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int i, count;
954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long delCount, adjust;
955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0
957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("CONTENTS:\n");
958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = 0; i < (int) mEntries.size(); i++) {
959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(" %d: lfhOff=%ld del=%d\n",
960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
961282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("  END is %ld\n", (long) mEOCD.mCentralDirOffset);
963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
965282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Roll through the set of files, shifting them as appropriate.  We
967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * could probably get a slight performance improvement by sliding
968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * multiple files down at once (because we could use larger reads
969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * when operating on batches of small files), but it's not that useful.
970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    count = mEntries.size();
972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delCount = adjust = 0;
973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = 0; i < count; i++) {
974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* pEntry = mEntries[i];
975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        long span;
976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (pEntry->getLFHOffset() != 0) {
978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            long nextOffset;
979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            /* Get the length of this entry by finding the offset
981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * of the next entry.  Directory entries don't have
982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * file offsets, so we need to find the next non-directory
983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * entry.
984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             */
985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            nextOffset = 0;
986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                nextOffset = mEntries[ii]->getLFHOffset();
988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (nextOffset == 0)
989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                nextOffset = mEOCD.mCentralDirOffset;
990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span = nextOffset - pEntry->getLFHOffset();
991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            /* This is a directory entry.  It doesn't have
995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * any actual file contents, so there's no need to
996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * move anything.
997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             */
998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            span = 0;
999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
1002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //    i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
1003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (pEntry->getDeleted()) {
1005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            adjust += span;
1006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delCount++;
1007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete pEntry;
1009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            mEntries.removeAt(i);
1010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            /* adjust loop control */
1012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            count--;
1013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            i--;
1014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (span != 0 && adjust > 0) {
1015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            /* shuffle this entry back */
1016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //printf("+++ Shuffling '%s' back %ld\n",
1017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //    pEntry->getFileName(), adjust);
1018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
1019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        pEntry->getLFHOffset(), span);
1020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (result != NO_ERROR) {
1021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                /* this is why you use a temp file */
1022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ALOGE("error during crunch - archive is toast\n");
1023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return result;
1024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
1027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
1031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Fix EOCD info.  We have to wait until the end to do some of this
1032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * because we use mCentralDirOffset to determine "span" for the
1033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * last entry.
1034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
1035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mCentralDirOffset -= adjust;
1036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mNumEntries -= delCount;
1037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mTotalNumEntries -= delCount;
1038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mEOCD.mCentralDirSize = 0;  // mark invalid; set by flush()
1039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
1041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mEOCD.mNumEntries == count);
1042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
1044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Works like memmove(), but on pieces of a file.
1048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
1050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (dst == src || n <= 0)
1052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NO_ERROR;
1053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned char readBuf[32768];
1055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (dst < src) {
1057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* shift stuff toward start of file; must read from start */
1058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        while (n != 0) {
1059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t getSize = sizeof(readBuf);
1060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (getSize > n)
1061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                getSize = n;
1062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (fseek(fp, (long) src, SEEK_SET) != 0) {
1064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ALOGD("filemove src seek %ld failed\n", (long) src);
1065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return UNKNOWN_ERROR;
1066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (fread(readBuf, 1, getSize, fp) != getSize) {
1069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ALOGD("filemove read %ld off=%ld failed\n",
1070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    (long) getSize, (long) src);
1071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return UNKNOWN_ERROR;
1072282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1074282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (fseek(fp, (long) dst, SEEK_SET) != 0) {
1075282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ALOGD("filemove dst seek %ld failed\n", (long) dst);
1076282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return UNKNOWN_ERROR;
1077282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (fwrite(readBuf, 1, getSize, fp) != getSize) {
1080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ALOGD("filemove write %ld off=%ld failed\n",
1081282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    (long) getSize, (long) dst);
1082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return UNKNOWN_ERROR;
1083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            src += getSize;
1086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dst += getSize;
1087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            n -= getSize;
1088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1089282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
1090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* shift stuff toward end of file; must read from end */
1091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assert(false);      // write this someday, maybe
1092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
1093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
1096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Get the modification time from a file descriptor.
1101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskitime_t ZipFile::getModTime(int fd)
1103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    struct stat sb;
1105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fstat(fd, &sb) < 0) {
1107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("HEY: fstat on fd %d failed\n", fd);
1108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return (time_t) -1;
1109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return sb.st_mtime;
1112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0       /* this is a bad idea */
1116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Get a copy of the Zip file descriptor.
1118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
1119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * We don't allow this if the file was opened read-write because we tend
1120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * to leave the file contents in an uncertain state between calls to
1121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * flush().  The duplicated file descriptor should only be valid for reads.
1122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint ZipFile::getZipFd(void) const
1124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!mReadOnly)
1126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return INVALID_OPERATION;
1127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mZipFp != NULL);
1128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int fd;
1130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fd = dup(fileno(mZipFp));
1131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fd < 0) {
1132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD("didn't work, errno=%d\n", errno);
1133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return fd;
1136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
1138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0
1141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Expand data.
1143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
1145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
1147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
1149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// free the memory when you're done
1151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid* ZipFile::uncompress(const ZipEntry* entry)
1152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t unlen = entry->getUncompressedLen();
1154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t clen = entry->getCompressedLen();
1155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    void* buf = malloc(unlen);
1157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (buf == NULL) {
1158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
1159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fseek(mZipFp, 0, SEEK_SET);
1162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    off_t offset = entry->getFileOffset();
1164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fseek(mZipFp, offset, SEEK_SET) != 0) {
1165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    switch (entry->getCompressionMethod())
1169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {
1170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case ZipEntry::kCompressStored: {
1171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ssize_t amt = fread(buf, 1, unlen, mZipFp);
1172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (amt != (ssize_t)unlen) {
1173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
1174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0
1176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("data...\n");
1177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const unsigned char* p = (unsigned char*)buf;
1178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const unsigned char* end = p+unlen;
1179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (int i=0; i<32 && p < end; i++) {
1180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("0x%08x ", (int)(offset+(i*0x10)));
1181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (int j=0; j<0x10 && p < end; j++) {
1182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf(" %02x", *p);
1183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    p++;
1184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("\n");
1186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
1188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
1191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case ZipEntry::kCompressDeflated: {
1192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
1193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
1194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
1197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        default:
1198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return buf;
1201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
1203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    free(buf);
1204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NULL;
1205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * ===========================================================================
1210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *      ZipFile::EndOfCentralDir
1211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * ===========================================================================
1212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Read the end-of-central-dir fields.
1216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
1217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * "buf" should be positioned at the EOCD signature, and should contain
1218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the entire EOCD area including the comment.
1219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
1221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* don't allow re-use */
1223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assert(mComment == NULL);
1224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (len < kEOCDLen) {
1226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* looks like ZIP file got truncated */
1227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ALOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
1228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            kEOCDLen, len);
1229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return INVALID_OPERATION;
1230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* this should probably be an assert() */
1233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
1234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
1235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
1237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
1238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
1239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
1240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
1241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
1242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
1243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // TODO: validate mCentralDirOffset
1245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mCommentLen > 0) {
1247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (kEOCDLen + mCommentLen > len) {
1248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ALOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
1249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                kEOCDLen, mCommentLen, len);
1250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
1251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mComment = new unsigned char[mCommentLen];
1253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        memcpy(mComment, buf + kEOCDLen, mCommentLen);
1254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
1257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Write an end-of-central-directory section.
1261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ZipFile::EndOfCentralDir::write(FILE* fp)
1263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned char buf[kEOCDLen];
1265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry::putLongLE(&buf[0x00], kSignature);
1267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
1268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
1269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry::putShortLE(&buf[0x08], mNumEntries);
1270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
1271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
1272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
1273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipEntry::putShortLE(&buf[0x14], mCommentLen);
1274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
1276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
1277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mCommentLen > 0) {
1278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assert(mComment != NULL);
1279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
1280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
1281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
1284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Dump the contents of an EndOfCentralDir object.
1288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid ZipFile::EndOfCentralDir::dump(void) const
1290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ALOGD(" EndOfCentralDir contents:\n");
1292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ALOGD("  diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
1293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
1294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ALOGD("  centDirSize=%lu centDirOff=%lu commentLen=%u\n",
1295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mCentralDirSize, mCentralDirOffset, mCommentLen);
1296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1298