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