1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // 18 // Read-only access to Zip archives, with minimal heap allocation. 19 // 20 #define LOG_TAG "zipro" 21 //#define LOG_NDEBUG 0 22 #include <androidfw/ZipFileRO.h> 23 #include <utils/Log.h> 24 #include <utils/Compat.h> 25 #include <utils/misc.h> 26 #include <utils/threads.h> 27 #include <ziparchive/zip_archive.h> 28 29 #include <zlib.h> 30 31 #include <string.h> 32 #include <fcntl.h> 33 #include <errno.h> 34 #include <assert.h> 35 #include <unistd.h> 36 37 using namespace android; 38 39 class _ZipEntryRO { 40 public: 41 ZipEntry entry; 42 ZipString name; 43 void *cookie; 44 45 _ZipEntryRO() : cookie(NULL) {} 46 47 ~_ZipEntryRO() { 48 EndIteration(cookie); 49 } 50 51 private: 52 _ZipEntryRO(const _ZipEntryRO& other); 53 _ZipEntryRO& operator=(const _ZipEntryRO& other); 54 }; 55 56 ZipFileRO::~ZipFileRO() { 57 CloseArchive(mHandle); 58 if (mFileName != NULL) { 59 free(mFileName); 60 } 61 } 62 63 /* 64 * Open the specified file read-only. We memory-map the entire thing and 65 * close the file before returning. 66 */ 67 /* static */ ZipFileRO* ZipFileRO::open(const char* zipFileName) 68 { 69 ZipArchiveHandle handle; 70 const int32_t error = OpenArchive(zipFileName, &handle); 71 if (error) { 72 ALOGW("Error opening archive %s: %s", zipFileName, ErrorCodeString(error)); 73 CloseArchive(handle); 74 return NULL; 75 } 76 77 return new ZipFileRO(handle, strdup(zipFileName)); 78 } 79 80 81 /* static */ ZipFileRO* ZipFileRO::openFd(int fd, const char* debugFileName, 82 bool assume_ownership) 83 { 84 ZipArchiveHandle handle; 85 const int32_t error = OpenArchiveFd(fd, debugFileName, &handle, assume_ownership); 86 if (error) { 87 ALOGW("Error opening archive fd %d %s: %s", fd, debugFileName, ErrorCodeString(error)); 88 CloseArchive(handle); 89 return NULL; 90 } 91 92 return new ZipFileRO(handle, strdup(debugFileName)); 93 } 94 95 ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const 96 { 97 _ZipEntryRO* data = new _ZipEntryRO; 98 99 data->name = ZipString(entryName); 100 101 const int32_t error = FindEntry(mHandle, data->name, &(data->entry)); 102 if (error) { 103 delete data; 104 return NULL; 105 } 106 107 return (ZipEntryRO) data; 108 } 109 110 /* 111 * Get the useful fields from the zip entry. 112 * 113 * Returns "false" if the offsets to the fields or the contents of the fields 114 * appear to be bogus. 115 */ 116 bool ZipFileRO::getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, 117 uint32_t* pUncompLen, uint32_t* pCompLen, off64_t* pOffset, 118 uint32_t* pModWhen, uint32_t* pCrc32) const 119 { 120 const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 121 const ZipEntry& ze = zipEntry->entry; 122 123 if (pMethod != NULL) { 124 *pMethod = ze.method; 125 } 126 if (pUncompLen != NULL) { 127 *pUncompLen = ze.uncompressed_length; 128 } 129 if (pCompLen != NULL) { 130 *pCompLen = ze.compressed_length; 131 } 132 if (pOffset != NULL) { 133 *pOffset = ze.offset; 134 } 135 if (pModWhen != NULL) { 136 *pModWhen = ze.mod_time; 137 } 138 if (pCrc32 != NULL) { 139 *pCrc32 = ze.crc32; 140 } 141 142 return true; 143 } 144 145 bool ZipFileRO::startIteration(void** cookie) { 146 return startIteration(cookie, NULL, NULL); 147 } 148 149 bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* suffix) 150 { 151 _ZipEntryRO* ze = new _ZipEntryRO; 152 ZipString pe(prefix ? prefix : ""); 153 ZipString se(suffix ? suffix : ""); 154 int32_t error = StartIteration(mHandle, &(ze->cookie), 155 prefix ? &pe : NULL, 156 suffix ? &se : NULL); 157 if (error) { 158 ALOGW("Could not start iteration over %s: %s", mFileName != NULL ? mFileName : "<null>", 159 ErrorCodeString(error)); 160 delete ze; 161 return false; 162 } 163 164 *cookie = ze; 165 return true; 166 } 167 168 ZipEntryRO ZipFileRO::nextEntry(void* cookie) 169 { 170 _ZipEntryRO* ze = reinterpret_cast<_ZipEntryRO*>(cookie); 171 int32_t error = Next(ze->cookie, &(ze->entry), &(ze->name)); 172 if (error) { 173 if (error != -1) { 174 ALOGW("Error iteration over %s: %s", mFileName != NULL ? mFileName : "<null>", 175 ErrorCodeString(error)); 176 } 177 return NULL; 178 } 179 180 return &(ze->entry); 181 } 182 183 void ZipFileRO::endIteration(void* cookie) 184 { 185 delete reinterpret_cast<_ZipEntryRO*>(cookie); 186 } 187 188 void ZipFileRO::releaseEntry(ZipEntryRO entry) const 189 { 190 delete reinterpret_cast<_ZipEntryRO*>(entry); 191 } 192 193 /* 194 * Copy the entry's filename to the buffer. 195 */ 196 int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, size_t bufLen) 197 const 198 { 199 const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 200 const uint16_t requiredSize = zipEntry->name.name_length + 1; 201 202 if (bufLen < requiredSize) { 203 ALOGW("Buffer too short, requires %d bytes for entry name", requiredSize); 204 return requiredSize; 205 } 206 207 memcpy(buffer, zipEntry->name.name, requiredSize - 1); 208 buffer[requiredSize - 1] = '\0'; 209 210 return 0; 211 } 212 213 /* 214 * Create a new FileMap object that spans the data in "entry". 215 */ 216 FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const 217 { 218 const _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 219 const ZipEntry& ze = zipEntry->entry; 220 int fd = GetFileDescriptor(mHandle); 221 size_t actualLen = 0; 222 223 if (ze.method == kCompressStored) { 224 actualLen = ze.uncompressed_length; 225 } else { 226 actualLen = ze.compressed_length; 227 } 228 229 FileMap* newMap = new FileMap(); 230 if (!newMap->create(mFileName, fd, ze.offset, actualLen, true)) { 231 delete newMap; 232 return NULL; 233 } 234 235 return newMap; 236 } 237 238 /* 239 * Uncompress an entry, in its entirety, into the provided output buffer. 240 * 241 * This doesn't verify the data's CRC, which might be useful for 242 * uncompressed data. The caller should be able to manage it. 243 */ 244 bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer, size_t size) const 245 { 246 _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 247 const int32_t error = ExtractToMemory(mHandle, &(zipEntry->entry), 248 (uint8_t*) buffer, size); 249 if (error) { 250 ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error)); 251 return false; 252 } 253 254 return true; 255 } 256 257 /* 258 * Uncompress an entry, in its entirety, to an open file descriptor. 259 * 260 * This doesn't verify the data's CRC, but probably should. 261 */ 262 bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const 263 { 264 _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 265 const int32_t error = ExtractEntryToFile(mHandle, &(zipEntry->entry), fd); 266 if (error) { 267 ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error)); 268 return false; 269 } 270 271 return true; 272 } 273