blob: 92150c39b9d329a63d75134cf0b6c51fffe329ca [file] [log] [blame]
Narayan Kamath7462f022013-11-21 13:05:04 +00001/*
2 * Copyright (C) 2008 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 */
Narayan Kamath7462f022013-11-21 13:05:04 +000020
21#include <assert.h>
22#include <errno.h>
Mark Salyzyn99ef9912014-03-14 14:26:22 -070023#include <fcntl.h>
24#include <inttypes.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000025#include <limits.h>
26#include <log/log.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000027#include <stdlib.h>
28#include <string.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000029#include <unistd.h>
Mark Salyzyn51d562d2014-05-05 14:38:05 -070030#include <utils/Compat.h>
Narayan Kamatheaf98852013-12-11 14:51:51 +000031#include <utils/FileMap.h>
Mark Salyzyn99ef9912014-03-14 14:26:22 -070032#include <zlib.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000033
34#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd
35
Mark Salyzyn99ef9912014-03-14 14:26:22 -070036#include "ziparchive/zip_archive.h"
37
Narayan Kamath926973e2014-06-09 14:18:14 +010038// This is for windows. If we don't open a file in binary mode, weird
Narayan Kamath7462f022013-11-21 13:05:04 +000039// things will happen.
40#ifndef O_BINARY
41#define O_BINARY 0
42#endif
43
Narayan Kamath926973e2014-06-09 14:18:14 +010044#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
45 TypeName(); \
46 TypeName(const TypeName&); \
47 void operator=(const TypeName&)
Narayan Kamath7462f022013-11-21 13:05:04 +000048
Narayan Kamath926973e2014-06-09 14:18:14 +010049// The "end of central directory" (EOCD) record. Each archive
50// contains exactly once such record which appears at the end of
51// the archive. It contains archive wide information like the
52// number of entries in the archive and the offset to the central
53// directory of the offset.
54struct EocdRecord {
55 static const uint32_t kSignature = 0x06054b50;
Narayan Kamath7462f022013-11-21 13:05:04 +000056
Narayan Kamath926973e2014-06-09 14:18:14 +010057 // End of central directory signature, should always be
58 // |kSignature|.
59 uint32_t eocd_signature;
60 // The number of the current "disk", i.e, the "disk" that this
61 // central directory is on.
62 //
63 // This implementation assumes that each archive spans a single
64 // disk only. i.e, that disk_num == 1.
65 uint16_t disk_num;
66 // The disk where the central directory starts.
67 //
68 // This implementation assumes that each archive spans a single
69 // disk only. i.e, that cd_start_disk == 1.
70 uint16_t cd_start_disk;
71 // The number of central directory records on this disk.
72 //
73 // This implementation assumes that each archive spans a single
74 // disk only. i.e, that num_records_on_disk == num_records.
75 uint16_t num_records_on_disk;
76 // The total number of central directory records.
77 uint16_t num_records;
78 // The size of the central directory (in bytes).
79 uint32_t cd_size;
80 // The offset of the start of the central directory, relative
81 // to the start of the file.
82 uint32_t cd_start_offset;
83 // Length of the central directory comment.
84 uint16_t comment_length;
85 private:
86 DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
87} __attribute__((packed));
Narayan Kamath7462f022013-11-21 13:05:04 +000088
Narayan Kamath926973e2014-06-09 14:18:14 +010089// A structure representing the fixed length fields for a single
90// record in the central directory of the archive. In addition to
91// the fixed length fields listed here, each central directory
92// record contains a variable length "file_name" and "extra_field"
93// whose lengths are given by |file_name_length| and |extra_field_length|
94// respectively.
95struct CentralDirectoryRecord {
96 static const uint32_t kSignature = 0x02014b50;
Narayan Kamath7462f022013-11-21 13:05:04 +000097
Narayan Kamath926973e2014-06-09 14:18:14 +010098 // The start of record signature. Must be |kSignature|.
99 uint32_t record_signature;
100 // Tool version. Ignored by this implementation.
101 uint16_t version_made_by;
102 // Tool version. Ignored by this implementation.
103 uint16_t version_needed;
104 // The "general purpose bit flags" for this entry. The only
105 // flag value that we currently check for is the "data descriptor"
106 // flag.
107 uint16_t gpb_flags;
108 // The compression method for this entry, one of |kCompressStored|
109 // and |kCompressDeflated|.
110 uint16_t compression_method;
111 // The file modification time and date for this entry.
112 uint16_t last_mod_time;
113 uint16_t last_mod_date;
114 // The CRC-32 checksum for this entry.
115 uint32_t crc32;
116 // The compressed size (in bytes) of this entry.
117 uint32_t compressed_size;
118 // The uncompressed size (in bytes) of this entry.
119 uint32_t uncompressed_size;
120 // The length of the entry file name in bytes. The file name
121 // will appear immediately after this record.
122 uint16_t file_name_length;
123 // The length of the extra field info (in bytes). This data
124 // will appear immediately after the entry file name.
125 uint16_t extra_field_length;
126 // The length of the entry comment (in bytes). This data will
127 // appear immediately after the extra field.
128 uint16_t comment_length;
129 // The start disk for this entry. Ignored by this implementation).
130 uint16_t file_start_disk;
131 // File attributes. Ignored by this implementation.
132 uint16_t internal_file_attributes;
133 // File attributes. Ignored by this implementation.
134 uint32_t external_file_attributes;
135 // The offset to the local file header for this entry, from the
136 // beginning of this archive.
137 uint32_t local_file_header_offset;
138 private:
139 DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
140} __attribute__((packed));
Narayan Kamath7462f022013-11-21 13:05:04 +0000141
Narayan Kamath926973e2014-06-09 14:18:14 +0100142// The local file header for a given entry. This duplicates information
143// present in the central directory of the archive. It is an error for
144// the information here to be different from the central directory
145// information for a given entry.
146struct LocalFileHeader {
147 static const uint32_t kSignature = 0x04034b50;
Narayan Kamath7462f022013-11-21 13:05:04 +0000148
Narayan Kamath926973e2014-06-09 14:18:14 +0100149 // The local file header signature, must be |kSignature|.
150 uint32_t lfh_signature;
151 // Tool version. Ignored by this implementation.
152 uint16_t version_needed;
153 // The "general purpose bit flags" for this entry. The only
154 // flag value that we currently check for is the "data descriptor"
155 // flag.
156 uint16_t gpb_flags;
157 // The compression method for this entry, one of |kCompressStored|
158 // and |kCompressDeflated|.
159 uint16_t compression_method;
160 // The file modification time and date for this entry.
161 uint16_t last_mod_time;
162 uint16_t last_mod_date;
163 // The CRC-32 checksum for this entry.
164 uint32_t crc32;
165 // The compressed size (in bytes) of this entry.
166 uint32_t compressed_size;
167 // The uncompressed size (in bytes) of this entry.
168 uint32_t uncompressed_size;
169 // The length of the entry file name in bytes. The file name
170 // will appear immediately after this record.
171 uint16_t file_name_length;
172 // The length of the extra field info (in bytes). This data
173 // will appear immediately after the entry file name.
174 uint16_t extra_field_length;
175 private:
176 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
177} __attribute__((packed));
178
179struct DataDescriptor {
180 // The *optional* data descriptor start signature.
181 static const uint32_t kOptSignature = 0x08074b50;
182
183 // CRC-32 checksum of the entry.
184 uint32_t crc32;
185 // Compressed size of the entry.
186 uint32_t compressed_size;
187 // Uncompressed size of the entry.
188 uint32_t uncompressed_size;
189 private:
190 DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
191} __attribute__((packed));
192
193#undef DISALLOW_IMPLICIT_CONSTRUCTORS
194
Piotr Jastrzebskibd0a7482014-08-13 09:49:25 +0000195static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
Narayan Kamath7462f022013-11-21 13:05:04 +0000196
Narayan Kamath926973e2014-06-09 14:18:14 +0100197// The maximum size of a central directory or a file
198// comment in bytes.
199static const uint32_t kMaxCommentLen = 65535;
200
201// The maximum number of bytes to scan backwards for the EOCD start.
202static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
203
Narayan Kamath7462f022013-11-21 13:05:04 +0000204static const char* kErrorMessages[] = {
205 "Unknown return code.",
Narayan Kamatheb41ad22013-12-09 16:26:36 +0000206 "Iteration ended",
Narayan Kamath7462f022013-11-21 13:05:04 +0000207 "Zlib error",
208 "Invalid file",
209 "Invalid handle",
210 "Duplicate entries in archive",
211 "Empty archive",
212 "Entry not found",
213 "Invalid offset",
214 "Inconsistent information",
215 "Invalid entry name",
Narayan Kamatheb41ad22013-12-09 16:26:36 +0000216 "I/O Error",
Narayan Kamatheaf98852013-12-11 14:51:51 +0000217 "File mapping failed"
Narayan Kamath7462f022013-11-21 13:05:04 +0000218};
219
220static const int32_t kErrorMessageUpperBound = 0;
221
Narayan Kamatheb41ad22013-12-09 16:26:36 +0000222static const int32_t kIterationEnd = -1;
Narayan Kamath7462f022013-11-21 13:05:04 +0000223
224// We encountered a Zlib error when inflating a stream from this file.
225// Usually indicates file corruption.
226static const int32_t kZlibError = -2;
227
228// The input file cannot be processed as a zip archive. Usually because
229// it's too small, too large or does not have a valid signature.
230static const int32_t kInvalidFile = -3;
231
232// An invalid iteration / ziparchive handle was passed in as an input
233// argument.
234static const int32_t kInvalidHandle = -4;
235
236// The zip archive contained two (or possibly more) entries with the same
237// name.
238static const int32_t kDuplicateEntry = -5;
239
240// The zip archive contains no entries.
241static const int32_t kEmptyArchive = -6;
242
243// The specified entry was not found in the archive.
244static const int32_t kEntryNotFound = -7;
245
246// The zip archive contained an invalid local file header pointer.
247static const int32_t kInvalidOffset = -8;
248
249// The zip archive contained inconsistent entry information. This could
250// be because the central directory & local file header did not agree, or
251// if the actual uncompressed length or crc32 do not match their declared
252// values.
253static const int32_t kInconsistentInformation = -9;
254
255// An invalid entry name was encountered.
256static const int32_t kInvalidEntryName = -10;
257
Narayan Kamatheb41ad22013-12-09 16:26:36 +0000258// An I/O related system call (read, lseek, ftruncate, map) failed.
259static const int32_t kIoError = -11;
Narayan Kamath7462f022013-11-21 13:05:04 +0000260
Narayan Kamatheaf98852013-12-11 14:51:51 +0000261// We were not able to mmap the central directory or entry contents.
262static const int32_t kMmapFailed = -12;
Narayan Kamath7462f022013-11-21 13:05:04 +0000263
Narayan Kamatheaf98852013-12-11 14:51:51 +0000264static const int32_t kErrorMessageLowerBound = -13;
Narayan Kamath7462f022013-11-21 13:05:04 +0000265
Narayan Kamatheaf98852013-12-11 14:51:51 +0000266static const char kTempMappingFileName[] = "zip: ExtractFileToFile";
Narayan Kamath7462f022013-11-21 13:05:04 +0000267
268/*
269 * A Read-only Zip archive.
270 *
271 * We want "open" and "find entry by name" to be fast operations, and
272 * we want to use as little memory as possible. We memory-map the zip
273 * central directory, and load a hash table with pointers to the filenames
274 * (which aren't null-terminated). The other fields are at a fixed offset
275 * from the filename, so we don't need to extract those (but we do need
276 * to byte-read and endian-swap them every time we want them).
277 *
278 * It's possible that somebody has handed us a massive (~1GB) zip archive,
279 * so we can't expect to mmap the entire file.
280 *
281 * To speed comparisons when doing a lookup by name, we could make the mapping
282 * "private" (copy-on-write) and null-terminate the filenames after verifying
283 * the record structure. However, this requires a private mapping of
284 * every page that the Central Directory touches. Easier to tuck a copy
285 * of the string length into the hash table entry.
286 */
287struct ZipArchive {
288 /* open Zip archive */
Neil Fullerb1a113f2014-07-25 14:43:04 +0100289 const int fd;
Narayan Kamath7462f022013-11-21 13:05:04 +0000290
291 /* mapped central directory area */
292 off64_t directory_offset;
Narayan Kamatheaf98852013-12-11 14:51:51 +0000293 android::FileMap* directory_map;
Narayan Kamath7462f022013-11-21 13:05:04 +0000294
295 /* number of entries in the Zip archive */
296 uint16_t num_entries;
297
298 /*
299 * We know how many entries are in the Zip archive, so we can have a
300 * fixed-size hash table. We define a load factor of 0.75 and overallocat
301 * so the maximum number entries can never be higher than
302 * ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
303 */
304 uint32_t hash_table_size;
305 ZipEntryName* hash_table;
Neil Fullerb1a113f2014-07-25 14:43:04 +0100306
307 ZipArchive(const int fd) :
308 fd(fd),
309 directory_offset(0),
310 directory_map(NULL),
311 num_entries(0),
312 hash_table_size(0),
313 hash_table(NULL) {}
314
315 ~ZipArchive() {
316 if (fd >= 0) {
317 close(fd);
318 }
319
320 if (directory_map != NULL) {
321 directory_map->release();
322 }
323 free(hash_table);
324 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000325};
326
327// Returns 0 on success and negative values on failure.
Narayan Kamatheaf98852013-12-11 14:51:51 +0000328static android::FileMap* MapFileSegment(const int fd, const off64_t start,
329 const size_t length, const bool read_only,
330 const char* debug_file_name) {
331 android::FileMap* file_map = new android::FileMap;
332 const bool success = file_map->create(debug_file_name, fd, start, length, read_only);
333 if (!success) {
334 file_map->release();
335 return NULL;
Narayan Kamath7462f022013-11-21 13:05:04 +0000336 }
337
Narayan Kamatheaf98852013-12-11 14:51:51 +0000338 return file_map;
Narayan Kamath7462f022013-11-21 13:05:04 +0000339}
340
341static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
342 static const uint32_t kBufSize = 32768;
343 uint8_t buf[kBufSize];
344
345 uint32_t count = 0;
346 uint64_t crc = 0;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000347 while (count < length) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000348 uint32_t remaining = length - count;
349
350 // Safe conversion because kBufSize is narrow enough for a 32 bit signed
351 // value.
352 ssize_t get_size = (remaining > kBufSize) ? kBufSize : remaining;
353 ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
354
355 if (actual != get_size) {
Mark Salyzyn51d562d2014-05-05 14:38:05 -0700356 ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, get_size);
Narayan Kamath7462f022013-11-21 13:05:04 +0000357 return kIoError;
358 }
359
360 memcpy(begin + count, buf, get_size);
361 crc = crc32(crc, buf, get_size);
362 count += get_size;
363 }
364
365 *crc_out = crc;
366
367 return 0;
368}
369
370/*
371 * Round up to the next highest power of 2.
372 *
373 * Found on http://graphics.stanford.edu/~seander/bithacks.html.
374 */
375static uint32_t RoundUpPower2(uint32_t val) {
376 val--;
377 val |= val >> 1;
378 val |= val >> 2;
379 val |= val >> 4;
380 val |= val >> 8;
381 val |= val >> 16;
382 val++;
383
384 return val;
385}
386
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100387static uint32_t ComputeHash(const ZipEntryName& name) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000388 uint32_t hash = 0;
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100389 uint16_t len = name.name_length;
390 const uint8_t* str = name.name;
Narayan Kamath7462f022013-11-21 13:05:04 +0000391
392 while (len--) {
393 hash = hash * 31 + *str++;
394 }
395
396 return hash;
397}
398
399/*
400 * Convert a ZipEntry to a hash table index, verifying that it's in a
401 * valid range.
402 */
403static int64_t EntryToIndex(const ZipEntryName* hash_table,
404 const uint32_t hash_table_size,
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100405 const ZipEntryName& name) {
406 const uint32_t hash = ComputeHash(name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000407
408 // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
409 uint32_t ent = hash & (hash_table_size - 1);
410 while (hash_table[ent].name != NULL) {
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100411 if (hash_table[ent].name_length == name.name_length &&
412 memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000413 return ent;
414 }
415
416 ent = (ent + 1) & (hash_table_size - 1);
417 }
418
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100419 ALOGV("Zip: Unable to find entry %.*s", name.name_length, name.name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000420 return kEntryNotFound;
421}
422
423/*
424 * Add a new entry to the hash table.
425 */
426static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_size,
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100427 const ZipEntryName& name) {
428 const uint64_t hash = ComputeHash(name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000429 uint32_t ent = hash & (hash_table_size - 1);
430
431 /*
432 * We over-allocated the table, so we're guaranteed to find an empty slot.
433 * Further, we guarantee that the hashtable size is not 0.
434 */
435 while (hash_table[ent].name != NULL) {
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100436 if (hash_table[ent].name_length == name.name_length &&
437 memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000438 // We've found a duplicate entry. We don't accept it
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100439 ALOGW("Zip: Found duplicate entry %.*s", name.name_length, name.name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000440 return kDuplicateEntry;
441 }
442 ent = (ent + 1) & (hash_table_size - 1);
443 }
444
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100445 hash_table[ent].name = name.name;
446 hash_table[ent].name_length = name.name_length;
Narayan Kamath7462f022013-11-21 13:05:04 +0000447 return 0;
448}
449
Narayan Kamath7462f022013-11-21 13:05:04 +0000450static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
451 ZipArchive* archive, off64_t file_length,
Narayan Kamath926973e2014-06-09 14:18:14 +0100452 off64_t read_amount, uint8_t* scan_buffer) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000453 const off64_t search_start = file_length - read_amount;
454
455 if (lseek64(fd, search_start, SEEK_SET) != search_start) {
Narayan Kamath926973e2014-06-09 14:18:14 +0100456 ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
457 strerror(errno));
Narayan Kamath7462f022013-11-21 13:05:04 +0000458 return kIoError;
459 }
Narayan Kamath926973e2014-06-09 14:18:14 +0100460 ssize_t actual = TEMP_FAILURE_RETRY(
461 read(fd, scan_buffer, static_cast<size_t>(read_amount)));
462 if (actual != static_cast<ssize_t>(read_amount)) {
463 ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
464 strerror(errno));
Narayan Kamath7462f022013-11-21 13:05:04 +0000465 return kIoError;
466 }
467
468 /*
469 * Scan backward for the EOCD magic. In an archive without a trailing
470 * comment, we'll find it on the first try. (We may want to consider
471 * doing an initial minimal read; if we don't find it, retry with a
472 * second read as above.)
473 */
Narayan Kamath926973e2014-06-09 14:18:14 +0100474 int i = read_amount - sizeof(EocdRecord);
475 for (; i >= 0; i--) {
476 if (scan_buffer[i] == 0x50 &&
477 ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000478 ALOGV("+++ Found EOCD at buf+%d", i);
479 break;
480 }
481 }
482 if (i < 0) {
483 ALOGD("Zip: EOCD not found, %s is not zip", debug_file_name);
484 return kInvalidFile;
485 }
486
487 const off64_t eocd_offset = search_start + i;
Narayan Kamath926973e2014-06-09 14:18:14 +0100488 const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i);
Narayan Kamath7462f022013-11-21 13:05:04 +0000489 /*
Narayan Kamath926973e2014-06-09 14:18:14 +0100490 * Verify that there's no trailing space at the end of the central directory
491 * and its comment.
Narayan Kamath7462f022013-11-21 13:05:04 +0000492 */
Narayan Kamath926973e2014-06-09 14:18:14 +0100493 const off64_t calculated_length = eocd_offset + sizeof(EocdRecord)
494 + eocd->comment_length;
495 if (calculated_length != file_length) {
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100496 ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
Narayan Kamath926973e2014-06-09 14:18:14 +0100497 static_cast<int64_t>(file_length - calculated_length));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100498 return kInvalidFile;
499 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000500
Narayan Kamath926973e2014-06-09 14:18:14 +0100501 /*
502 * Grab the CD offset and size, and the number of entries in the
503 * archive and verify that they look reasonable.
504 */
505 if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
506 ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
507 eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +0000508 return kInvalidOffset;
509 }
Narayan Kamath926973e2014-06-09 14:18:14 +0100510 if (eocd->num_records == 0) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000511 ALOGW("Zip: empty archive?");
512 return kEmptyArchive;
513 }
514
Narayan Kamath926973e2014-06-09 14:18:14 +0100515 ALOGV("+++ num_entries=%" PRIu32 "dir_size=%" PRIu32 " dir_offset=%" PRIu32,
516 eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
Narayan Kamath7462f022013-11-21 13:05:04 +0000517
518 /*
519 * It all looks good. Create a mapping for the CD, and set the fields
520 * in archive.
521 */
Narayan Kamath926973e2014-06-09 14:18:14 +0100522 android::FileMap* map = MapFileSegment(fd,
523 static_cast<off64_t>(eocd->cd_start_offset),
524 static_cast<size_t>(eocd->cd_size),
525 true /* read only */, debug_file_name);
Narayan Kamatheaf98852013-12-11 14:51:51 +0000526 if (map == NULL) {
527 archive->directory_map = NULL;
528 return kMmapFailed;
Narayan Kamath7462f022013-11-21 13:05:04 +0000529 }
530
Narayan Kamatheaf98852013-12-11 14:51:51 +0000531 archive->directory_map = map;
Narayan Kamath926973e2014-06-09 14:18:14 +0100532 archive->num_entries = eocd->num_records;
533 archive->directory_offset = eocd->cd_start_offset;
Narayan Kamath7462f022013-11-21 13:05:04 +0000534
535 return 0;
536}
537
538/*
539 * Find the zip Central Directory and memory-map it.
540 *
541 * On success, returns 0 after populating fields from the EOCD area:
542 * directory_offset
543 * directory_map
544 * num_entries
545 */
546static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
547 ZipArchive* archive) {
548
549 // Test file length. We use lseek64 to make sure the file
550 // is small enough to be a zip file (Its size must be less than
551 // 0xffffffff bytes).
552 off64_t file_length = lseek64(fd, 0, SEEK_END);
553 if (file_length == -1) {
554 ALOGV("Zip: lseek on fd %d failed", fd);
555 return kInvalidFile;
556 }
557
558 if (file_length > (off64_t) 0xffffffff) {
Narayan Kamath926973e2014-06-09 14:18:14 +0100559 ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
Narayan Kamath7462f022013-11-21 13:05:04 +0000560 return kInvalidFile;
561 }
562
Narayan Kamath926973e2014-06-09 14:18:14 +0100563 if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) {
564 ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length));
Narayan Kamath7462f022013-11-21 13:05:04 +0000565 return kInvalidFile;
566 }
567
568 /*
569 * Perform the traditional EOCD snipe hunt.
570 *
571 * We're searching for the End of Central Directory magic number,
572 * which appears at the start of the EOCD block. It's followed by
573 * 18 bytes of EOCD stuff and up to 64KB of archive comment. We
574 * need to read the last part of the file into a buffer, dig through
575 * it to find the magic number, parse some values out, and use those
576 * to determine the extent of the CD.
577 *
578 * We start by pulling in the last part of the file.
579 */
Narayan Kamath926973e2014-06-09 14:18:14 +0100580 off64_t read_amount = kMaxEOCDSearch;
581 if (file_length < read_amount) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000582 read_amount = file_length;
583 }
584
Narayan Kamath926973e2014-06-09 14:18:14 +0100585 uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
Narayan Kamath7462f022013-11-21 13:05:04 +0000586 int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
587 file_length, read_amount, scan_buffer);
588
589 free(scan_buffer);
590 return result;
591}
592
593/*
594 * Parses the Zip archive's Central Directory. Allocates and populates the
595 * hash table.
596 *
597 * Returns 0 on success.
598 */
599static int32_t ParseZipArchive(ZipArchive* archive) {
600 int32_t result = -1;
Narayan Kamath926973e2014-06-09 14:18:14 +0100601 const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
602 const size_t cd_length = archive->directory_map->getDataLength();
603 const uint16_t num_entries = archive->num_entries;
Narayan Kamath7462f022013-11-21 13:05:04 +0000604
605 /*
606 * Create hash table. We have a minimum 75% load factor, possibly as
607 * low as 50% after we round off to a power of 2. There must be at
608 * least one unused entry to avoid an infinite loop during creation.
609 */
610 archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
611 archive->hash_table = (ZipEntryName*) calloc(archive->hash_table_size,
612 sizeof(ZipEntryName));
613
614 /*
615 * Walk through the central directory, adding entries to the hash
616 * table and verifying values.
617 */
Narayan Kamath926973e2014-06-09 14:18:14 +0100618 const uint8_t* const cd_end = cd_ptr + cd_length;
Narayan Kamath7462f022013-11-21 13:05:04 +0000619 const uint8_t* ptr = cd_ptr;
620 for (uint16_t i = 0; i < num_entries; i++) {
Narayan Kamath926973e2014-06-09 14:18:14 +0100621 const CentralDirectoryRecord* cdr =
622 reinterpret_cast<const CentralDirectoryRecord*>(ptr);
623 if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700624 ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
Narayan Kamath7462f022013-11-21 13:05:04 +0000625 goto bail;
626 }
627
Narayan Kamath926973e2014-06-09 14:18:14 +0100628 if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700629 ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
Narayan Kamath7462f022013-11-21 13:05:04 +0000630 goto bail;
631 }
632
Narayan Kamath926973e2014-06-09 14:18:14 +0100633 const off64_t local_header_offset = cdr->local_file_header_offset;
Narayan Kamath7462f022013-11-21 13:05:04 +0000634 if (local_header_offset >= archive->directory_offset) {
Mark Salyzyn56a90a02014-05-08 17:20:55 -0700635 ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i);
Narayan Kamath7462f022013-11-21 13:05:04 +0000636 goto bail;
637 }
638
Narayan Kamath926973e2014-06-09 14:18:14 +0100639 const uint16_t file_name_length = cdr->file_name_length;
640 const uint16_t extra_length = cdr->extra_field_length;
641 const uint16_t comment_length = cdr->comment_length;
Piotr Jastrzebski78271ba2014-08-15 12:53:00 +0100642 const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
643
644 /* check that file name doesn't contain \0 character */
645 if (memchr(file_name, 0, file_name_length) != NULL) {
646 ALOGW("Zip: entry name can't contain \\0 character");
647 goto bail;
648 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000649
650 /* add the CDE filename to the hash table */
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100651 ZipEntryName entry_name;
652 entry_name.name = file_name;
653 entry_name.name_length = file_name_length;
Narayan Kamath7462f022013-11-21 13:05:04 +0000654 const int add_result = AddToHash(archive->hash_table,
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100655 archive->hash_table_size, entry_name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000656 if (add_result) {
657 ALOGW("Zip: Error adding entry to hash table %d", add_result);
658 result = add_result;
659 goto bail;
660 }
661
Narayan Kamath926973e2014-06-09 14:18:14 +0100662 ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
663 if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700664 ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
665 ptr - cd_ptr, cd_length, i);
Narayan Kamath7462f022013-11-21 13:05:04 +0000666 goto bail;
667 }
668 }
Mark Salyzyn088bf902014-05-08 16:02:20 -0700669 ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
Narayan Kamath7462f022013-11-21 13:05:04 +0000670
671 result = 0;
672
673bail:
674 return result;
675}
676
677static int32_t OpenArchiveInternal(ZipArchive* archive,
678 const char* debug_file_name) {
679 int32_t result = -1;
680 if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) {
681 return result;
682 }
683
684 if ((result = ParseZipArchive(archive))) {
685 return result;
686 }
687
688 return 0;
689}
690
691int32_t OpenArchiveFd(int fd, const char* debug_file_name,
692 ZipArchiveHandle* handle) {
Neil Fullerb1a113f2014-07-25 14:43:04 +0100693 ZipArchive* archive = new ZipArchive(fd);
Narayan Kamath7462f022013-11-21 13:05:04 +0000694 *handle = archive;
Narayan Kamath7462f022013-11-21 13:05:04 +0000695 return OpenArchiveInternal(archive, debug_file_name);
696}
697
698int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
Neil Fullerb1a113f2014-07-25 14:43:04 +0100699 const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
700 ZipArchive* archive = new ZipArchive(fd);
Narayan Kamath7462f022013-11-21 13:05:04 +0000701 *handle = archive;
702
Narayan Kamath7462f022013-11-21 13:05:04 +0000703 if (fd < 0) {
704 ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
705 return kIoError;
Narayan Kamath7462f022013-11-21 13:05:04 +0000706 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000707 return OpenArchiveInternal(archive, fileName);
708}
709
710/*
711 * Close a ZipArchive, closing the file and freeing the contents.
712 */
713void CloseArchive(ZipArchiveHandle handle) {
714 ZipArchive* archive = (ZipArchive*) handle;
715 ALOGV("Closing archive %p", archive);
Neil Fullerb1a113f2014-07-25 14:43:04 +0100716 delete archive;
Narayan Kamath7462f022013-11-21 13:05:04 +0000717}
718
719static int32_t UpdateEntryFromDataDescriptor(int fd,
720 ZipEntry *entry) {
Narayan Kamath926973e2014-06-09 14:18:14 +0100721 uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
Narayan Kamath7462f022013-11-21 13:05:04 +0000722 ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf)));
723 if (actual != sizeof(ddBuf)) {
724 return kIoError;
725 }
726
Narayan Kamath926973e2014-06-09 14:18:14 +0100727 const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
728 const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
729 const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
Narayan Kamath7462f022013-11-21 13:05:04 +0000730
Narayan Kamath926973e2014-06-09 14:18:14 +0100731 entry->crc32 = descriptor->crc32;
732 entry->compressed_length = descriptor->compressed_size;
733 entry->uncompressed_length = descriptor->uncompressed_size;
Narayan Kamath7462f022013-11-21 13:05:04 +0000734
735 return 0;
736}
737
738// Attempts to read |len| bytes into |buf| at offset |off|.
739//
740// This method uses pread64 on platforms that support it and
741// lseek64 + read on platforms that don't. This implies that
742// callers should not rely on the |fd| offset being incremented
743// as a side effect of this call.
744static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len,
745 off64_t off) {
Yabin Cui70160f42014-11-19 20:47:18 -0800746#if !defined(_WIN32)
Narayan Kamath7462f022013-11-21 13:05:04 +0000747 return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
748#else
749 // The only supported platform that doesn't support pread at the moment
750 // is Windows. Only recent versions of windows support unix like forks,
751 // and even there the semantics are quite different.
752 if (lseek64(fd, off, SEEK_SET) != off) {
Mark Salyzyn99ef9912014-03-14 14:26:22 -0700753 ALOGW("Zip: failed seek to offset %" PRId64, off);
Narayan Kamath7462f022013-11-21 13:05:04 +0000754 return kIoError;
755 }
756
757 return TEMP_FAILURE_RETRY(read(fd, buf, len));
Yabin Cui70160f42014-11-19 20:47:18 -0800758#endif
Narayan Kamath7462f022013-11-21 13:05:04 +0000759}
760
761static int32_t FindEntry(const ZipArchive* archive, const int ent,
762 ZipEntry* data) {
763 const uint16_t nameLen = archive->hash_table[ent].name_length;
Narayan Kamath7462f022013-11-21 13:05:04 +0000764
765 // Recover the start of the central directory entry from the filename
766 // pointer. The filename is the first entry past the fixed-size data,
767 // so we can just subtract back from that.
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100768 const uint8_t* ptr = archive->hash_table[ent].name;
Narayan Kamath926973e2014-06-09 14:18:14 +0100769 ptr -= sizeof(CentralDirectoryRecord);
Narayan Kamath7462f022013-11-21 13:05:04 +0000770
771 // This is the base of our mmapped region, we have to sanity check that
772 // the name that's in the hash table is a pointer to a location within
773 // this mapped region.
Narayan Kamath926973e2014-06-09 14:18:14 +0100774 const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
775 archive->directory_map->getDataPtr());
Narayan Kamatheaf98852013-12-11 14:51:51 +0000776 if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000777 ALOGW("Zip: Invalid entry pointer");
778 return kInvalidOffset;
779 }
780
Narayan Kamath926973e2014-06-09 14:18:14 +0100781 const CentralDirectoryRecord *cdr =
782 reinterpret_cast<const CentralDirectoryRecord*>(ptr);
783
Narayan Kamath7462f022013-11-21 13:05:04 +0000784 // The offset of the start of the central directory in the zipfile.
785 // We keep this lying around so that we can sanity check all our lengths
786 // and our per-file structures.
787 const off64_t cd_offset = archive->directory_offset;
788
789 // Fill out the compression method, modification time, crc32
790 // and other interesting attributes from the central directory. These
791 // will later be compared against values from the local file header.
Narayan Kamath926973e2014-06-09 14:18:14 +0100792 data->method = cdr->compression_method;
793 data->mod_time = cdr->last_mod_time;
794 data->crc32 = cdr->crc32;
795 data->compressed_length = cdr->compressed_size;
796 data->uncompressed_length = cdr->uncompressed_size;
Narayan Kamath7462f022013-11-21 13:05:04 +0000797
798 // Figure out the local header offset from the central directory. The
799 // actual file data will begin after the local header and the name /
800 // extra comments.
Narayan Kamath926973e2014-06-09 14:18:14 +0100801 const off64_t local_header_offset = cdr->local_file_header_offset;
802 if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000803 ALOGW("Zip: bad local hdr offset in zip");
804 return kInvalidOffset;
805 }
806
Narayan Kamath926973e2014-06-09 14:18:14 +0100807 uint8_t lfh_buf[sizeof(LocalFileHeader)];
Narayan Kamath7462f022013-11-21 13:05:04 +0000808 ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
809 local_header_offset);
810 if (actual != sizeof(lfh_buf)) {
Mark Salyzyn56a90a02014-05-08 17:20:55 -0700811 ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)local_header_offset);
Narayan Kamath7462f022013-11-21 13:05:04 +0000812 return kIoError;
813 }
814
Narayan Kamath926973e2014-06-09 14:18:14 +0100815 const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
816
817 if (lfh->lfh_signature != LocalFileHeader::kSignature) {
Mark Salyzyn99ef9912014-03-14 14:26:22 -0700818 ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
Narayan Kamath926973e2014-06-09 14:18:14 +0100819 static_cast<int64_t>(local_header_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +0000820 return kInvalidOffset;
821 }
822
823 // Paranoia: Match the values specified in the local file header
824 // to those specified in the central directory.
Narayan Kamath926973e2014-06-09 14:18:14 +0100825 if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000826 data->has_data_descriptor = 0;
Narayan Kamath926973e2014-06-09 14:18:14 +0100827 if (data->compressed_length != lfh->compressed_size
828 || data->uncompressed_length != lfh->uncompressed_size
829 || data->crc32 != lfh->crc32) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700830 ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32
831 ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
Narayan Kamath7462f022013-11-21 13:05:04 +0000832 data->compressed_length, data->uncompressed_length, data->crc32,
Narayan Kamath926973e2014-06-09 14:18:14 +0100833 lfh->compressed_size, lfh->uncompressed_size, lfh->crc32);
Narayan Kamath7462f022013-11-21 13:05:04 +0000834 return kInconsistentInformation;
835 }
836 } else {
837 data->has_data_descriptor = 1;
838 }
839
840 // Check that the local file header name matches the declared
841 // name in the central directory.
Narayan Kamath926973e2014-06-09 14:18:14 +0100842 if (lfh->file_name_length == nameLen) {
843 const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
844 if (name_offset + lfh->file_name_length >= cd_offset) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000845 ALOGW("Zip: Invalid declared length");
846 return kInvalidOffset;
847 }
848
849 uint8_t* name_buf = (uint8_t*) malloc(nameLen);
850 ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
851 name_offset);
852
853 if (actual != nameLen) {
Mark Salyzyn56a90a02014-05-08 17:20:55 -0700854 ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)name_offset);
Narayan Kamath7462f022013-11-21 13:05:04 +0000855 free(name_buf);
856 return kIoError;
857 }
858
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100859 if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000860 free(name_buf);
861 return kInconsistentInformation;
862 }
863
864 free(name_buf);
865 } else {
866 ALOGW("Zip: lfh name did not match central directory.");
867 return kInconsistentInformation;
868 }
869
Narayan Kamath926973e2014-06-09 14:18:14 +0100870 const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
871 + lfh->file_name_length + lfh->extra_field_length;
Narayan Kamath48953a12014-01-24 12:32:39 +0000872 if (data_offset > cd_offset) {
Mark Salyzyn56a90a02014-05-08 17:20:55 -0700873 ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset);
Narayan Kamath7462f022013-11-21 13:05:04 +0000874 return kInvalidOffset;
875 }
876
877 if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700878 ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
Mark Salyzyn56a90a02014-05-08 17:20:55 -0700879 (int64_t)data_offset, data->compressed_length, (int64_t)cd_offset);
Narayan Kamath7462f022013-11-21 13:05:04 +0000880 return kInvalidOffset;
881 }
882
883 if (data->method == kCompressStored &&
884 (off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700885 ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
Mark Salyzyn96c5c992014-05-08 19:16:40 -0700886 (int64_t)data_offset, data->uncompressed_length, (int64_t)cd_offset);
Narayan Kamath7462f022013-11-21 13:05:04 +0000887 return kInvalidOffset;
888 }
889
890 data->offset = data_offset;
891 return 0;
892}
893
894struct IterationHandle {
895 uint32_t position;
Piotr Jastrzebski10aa9a02014-08-19 09:01:20 +0100896 // We're not using vector here because this code is used in the Windows SDK
897 // where the STL is not available.
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100898 const uint8_t* prefix;
899 uint16_t prefix_len;
Narayan Kamath7462f022013-11-21 13:05:04 +0000900 ZipArchive* archive;
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100901
902 IterationHandle() : prefix(NULL), prefix_len(0) {}
903
904 IterationHandle(const ZipEntryName& prefix_name)
905 : prefix_len(prefix_name.name_length) {
906 uint8_t* prefix_copy = new uint8_t[prefix_len];
Piotr Jastrzebski10aa9a02014-08-19 09:01:20 +0100907 memcpy(prefix_copy, prefix_name.name, prefix_len);
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100908 prefix = prefix_copy;
909 }
910
911 ~IterationHandle() {
Piotr Jastrzebski10aa9a02014-08-19 09:01:20 +0100912 delete[] prefix;
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100913 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000914};
915
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100916int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
917 const ZipEntryName* optional_prefix) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000918 ZipArchive* archive = (ZipArchive *) handle;
919
920 if (archive == NULL || archive->hash_table == NULL) {
921 ALOGW("Zip: Invalid ZipArchiveHandle");
922 return kInvalidHandle;
923 }
924
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100925 IterationHandle* cookie =
926 optional_prefix != NULL ? new IterationHandle(*optional_prefix) : new IterationHandle();
Narayan Kamath7462f022013-11-21 13:05:04 +0000927 cookie->position = 0;
Narayan Kamath7462f022013-11-21 13:05:04 +0000928 cookie->archive = archive;
Narayan Kamath7462f022013-11-21 13:05:04 +0000929
930 *cookie_ptr = cookie ;
931 return 0;
932}
933
Piotr Jastrzebski79c8b342014-08-08 14:02:17 +0100934void EndIteration(void* cookie) {
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100935 delete reinterpret_cast<IterationHandle*>(cookie);
Piotr Jastrzebski79c8b342014-08-08 14:02:17 +0100936}
937
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100938int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
Narayan Kamath7462f022013-11-21 13:05:04 +0000939 ZipEntry* data) {
940 const ZipArchive* archive = (ZipArchive*) handle;
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100941 if (entryName.name_length == 0) {
942 ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000943 return kInvalidEntryName;
944 }
945
946 const int64_t ent = EntryToIndex(archive->hash_table,
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100947 archive->hash_table_size, entryName);
Narayan Kamath7462f022013-11-21 13:05:04 +0000948
949 if (ent < 0) {
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100950 ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000951 return ent;
952 }
953
954 return FindEntry(archive, ent, data);
955}
956
957int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
958 IterationHandle* handle = (IterationHandle *) cookie;
959 if (handle == NULL) {
960 return kInvalidHandle;
961 }
962
963 ZipArchive* archive = handle->archive;
964 if (archive == NULL || archive->hash_table == NULL) {
965 ALOGW("Zip: Invalid ZipArchiveHandle");
966 return kInvalidHandle;
967 }
968
969 const uint32_t currentOffset = handle->position;
970 const uint32_t hash_table_length = archive->hash_table_size;
971 const ZipEntryName *hash_table = archive->hash_table;
972
973 for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
974 if (hash_table[i].name != NULL &&
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100975 (handle->prefix_len == 0 ||
976 (memcmp(handle->prefix, hash_table[i].name, handle->prefix_len) == 0))) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000977 handle->position = (i + 1);
978 const int error = FindEntry(archive, i, data);
979 if (!error) {
980 name->name = hash_table[i].name;
981 name->name_length = hash_table[i].name_length;
982 }
983
984 return error;
985 }
986 }
987
988 handle->position = 0;
989 return kIterationEnd;
990}
991
992static int32_t InflateToFile(int fd, const ZipEntry* entry,
993 uint8_t* begin, uint32_t length,
994 uint64_t* crc_out) {
995 int32_t result = -1;
996 const uint32_t kBufSize = 32768;
997 uint8_t read_buf[kBufSize];
998 uint8_t write_buf[kBufSize];
999 z_stream zstream;
1000 int zerr;
1001
1002 /*
1003 * Initialize the zlib stream struct.
1004 */
1005 memset(&zstream, 0, sizeof(zstream));
1006 zstream.zalloc = Z_NULL;
1007 zstream.zfree = Z_NULL;
1008 zstream.opaque = Z_NULL;
1009 zstream.next_in = NULL;
1010 zstream.avail_in = 0;
1011 zstream.next_out = (Bytef*) write_buf;
1012 zstream.avail_out = kBufSize;
1013 zstream.data_type = Z_UNKNOWN;
1014
1015 /*
1016 * Use the undocumented "negative window bits" feature to tell zlib
1017 * that there's no zlib header waiting for it.
1018 */
1019 zerr = inflateInit2(&zstream, -MAX_WBITS);
1020 if (zerr != Z_OK) {
1021 if (zerr == Z_VERSION_ERROR) {
1022 ALOGE("Installed zlib is not compatible with linked version (%s)",
1023 ZLIB_VERSION);
1024 } else {
1025 ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr);
1026 }
1027
1028 return kZlibError;
1029 }
1030
1031 const uint32_t uncompressed_length = entry->uncompressed_length;
1032
1033 uint32_t compressed_length = entry->compressed_length;
1034 uint32_t write_count = 0;
1035 do {
1036 /* read as much as we can */
1037 if (zstream.avail_in == 0) {
Mark Salyzyn51d562d2014-05-05 14:38:05 -07001038 const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
1039 const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
Narayan Kamath7462f022013-11-21 13:05:04 +00001040 if (actual != getSize) {
Mark Salyzyn51d562d2014-05-05 14:38:05 -07001041 ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
Narayan Kamath7462f022013-11-21 13:05:04 +00001042 result = kIoError;
1043 goto z_bail;
1044 }
1045
1046 compressed_length -= getSize;
1047
1048 zstream.next_in = read_buf;
1049 zstream.avail_in = getSize;
1050 }
1051
1052 /* uncompress the data */
1053 zerr = inflate(&zstream, Z_NO_FLUSH);
1054 if (zerr != Z_OK && zerr != Z_STREAM_END) {
1055 ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
1056 zerr, zstream.next_in, zstream.avail_in,
1057 zstream.next_out, zstream.avail_out);
1058 result = kZlibError;
1059 goto z_bail;
1060 }
1061
1062 /* write when we're full or when we're done */
1063 if (zstream.avail_out == 0 ||
1064 (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
1065 const size_t write_size = zstream.next_out - write_buf;
1066 // The file might have declared a bogus length.
1067 if (write_size + write_count > length) {
1068 goto z_bail;
1069 }
1070 memcpy(begin + write_count, write_buf, write_size);
1071 write_count += write_size;
1072
1073 zstream.next_out = write_buf;
1074 zstream.avail_out = kBufSize;
1075 }
1076 } while (zerr == Z_OK);
1077
1078 assert(zerr == Z_STREAM_END); /* other errors should've been caught */
1079
1080 // stream.adler holds the crc32 value for such streams.
1081 *crc_out = zstream.adler;
1082
1083 if (zstream.total_out != uncompressed_length || compressed_length != 0) {
Mark Salyzyn088bf902014-05-08 16:02:20 -07001084 ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
Narayan Kamath7462f022013-11-21 13:05:04 +00001085 zstream.total_out, uncompressed_length);
1086 result = kInconsistentInformation;
1087 goto z_bail;
1088 }
1089
1090 result = 0;
1091
1092z_bail:
1093 inflateEnd(&zstream); /* free up any allocated structures */
1094
1095 return result;
1096}
1097
1098int32_t ExtractToMemory(ZipArchiveHandle handle,
1099 ZipEntry* entry, uint8_t* begin, uint32_t size) {
1100 ZipArchive* archive = (ZipArchive*) handle;
1101 const uint16_t method = entry->method;
1102 off64_t data_offset = entry->offset;
1103
1104 if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
Mark Salyzyn56a90a02014-05-08 17:20:55 -07001105 ALOGW("Zip: lseek to data at %" PRId64 " failed", (int64_t)data_offset);
Narayan Kamath7462f022013-11-21 13:05:04 +00001106 return kIoError;
1107 }
1108
1109 // this should default to kUnknownCompressionMethod.
1110 int32_t return_value = -1;
1111 uint64_t crc = 0;
1112 if (method == kCompressStored) {
1113 return_value = CopyFileToFile(archive->fd, begin, size, &crc);
1114 } else if (method == kCompressDeflated) {
1115 return_value = InflateToFile(archive->fd, entry, begin, size, &crc);
1116 }
1117
1118 if (!return_value && entry->has_data_descriptor) {
1119 return_value = UpdateEntryFromDataDescriptor(archive->fd, entry);
1120 if (return_value) {
1121 return return_value;
1122 }
1123 }
1124
1125 // TODO: Fix this check by passing the right flags to inflate2 so that
1126 // it calculates the CRC for us.
1127 if (entry->crc32 != crc && false) {
Mark Salyzyn088bf902014-05-08 16:02:20 -07001128 ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc);
Narayan Kamath7462f022013-11-21 13:05:04 +00001129 return kInconsistentInformation;
1130 }
1131
1132 return return_value;
1133}
1134
1135int32_t ExtractEntryToFile(ZipArchiveHandle handle,
1136 ZipEntry* entry, int fd) {
1137 const int32_t declared_length = entry->uncompressed_length;
1138
Narayan Kamath00a258c2013-12-13 16:06:19 +00001139 const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
1140 if (current_offset == -1) {
1141 ALOGW("Zip: unable to seek to current location on fd %d: %s", fd,
1142 strerror(errno));
Narayan Kamath7462f022013-11-21 13:05:04 +00001143 return kIoError;
1144 }
1145
Narayan Kamath00a258c2013-12-13 16:06:19 +00001146 int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
1147 if (result == -1) {
Mark Salyzyn99ef9912014-03-14 14:26:22 -07001148 ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
Mark Salyzyn56a90a02014-05-08 17:20:55 -07001149 (int64_t)(declared_length + current_offset), strerror(errno));
Narayan Kamath00a258c2013-12-13 16:06:19 +00001150 return kIoError;
1151 }
1152
Narayan Kamath48953a12014-01-24 12:32:39 +00001153 // Don't attempt to map a region of length 0. We still need the
1154 // ftruncate() though, since the API guarantees that we will truncate
1155 // the file to the end of the uncompressed output.
1156 if (declared_length == 0) {
1157 return 0;
1158 }
1159
Narayan Kamath00a258c2013-12-13 16:06:19 +00001160 android::FileMap* map = MapFileSegment(fd, current_offset, declared_length,
Narayan Kamatheaf98852013-12-11 14:51:51 +00001161 false, kTempMappingFileName);
1162 if (map == NULL) {
1163 return kMmapFailed;
Narayan Kamath7462f022013-11-21 13:05:04 +00001164 }
1165
Narayan Kamatheaf98852013-12-11 14:51:51 +00001166 const int32_t error = ExtractToMemory(handle, entry,
1167 reinterpret_cast<uint8_t*>(map->getDataPtr()),
1168 map->getDataLength());
1169 map->release();
Narayan Kamath7462f022013-11-21 13:05:04 +00001170 return error;
1171}
1172
1173const char* ErrorCodeString(int32_t error_code) {
1174 if (error_code > kErrorMessageLowerBound && error_code < kErrorMessageUpperBound) {
1175 return kErrorMessages[error_code * -1];
1176 }
1177
1178 return kErrorMessages[0];
1179}
1180
1181int GetFileDescriptor(const ZipArchiveHandle handle) {
1182 return ((ZipArchive*) handle)->fd;
1183}
1184