blob: 59a173430ee03b85c4fb40504a1bfd67b49927d7 [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
Dmitriy Ivanov1f741e52015-03-06 14:26:37 -080021#include <memory>
22
Narayan Kamath7462f022013-11-21 13:05:04 +000023#include <assert.h>
24#include <errno.h>
Mark Salyzyn99ef9912014-03-14 14:26:22 -070025#include <fcntl.h>
26#include <inttypes.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000027#include <limits.h>
28#include <log/log.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000029#include <stdlib.h>
30#include <string.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000031#include <unistd.h>
Mark Salyzyn51d562d2014-05-05 14:38:05 -070032#include <utils/Compat.h>
Narayan Kamatheaf98852013-12-11 14:51:51 +000033#include <utils/FileMap.h>
Mark Salyzyn99ef9912014-03-14 14:26:22 -070034#include <zlib.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000035
36#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd
37
Narayan Kamath044bc8e2014-12-03 18:22:53 +000038#include "entry_name_utils-inl.h"
Mark Salyzyn99ef9912014-03-14 14:26:22 -070039#include "ziparchive/zip_archive.h"
40
Narayan Kamath044bc8e2014-12-03 18:22:53 +000041
Narayan Kamath926973e2014-06-09 14:18:14 +010042// This is for windows. If we don't open a file in binary mode, weird
Narayan Kamath7462f022013-11-21 13:05:04 +000043// things will happen.
44#ifndef O_BINARY
45#define O_BINARY 0
46#endif
47
Narayan Kamath926973e2014-06-09 14:18:14 +010048#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
49 TypeName(); \
50 TypeName(const TypeName&); \
51 void operator=(const TypeName&)
Narayan Kamath7462f022013-11-21 13:05:04 +000052
Narayan Kamath926973e2014-06-09 14:18:14 +010053// The "end of central directory" (EOCD) record. Each archive
54// contains exactly once such record which appears at the end of
55// the archive. It contains archive wide information like the
56// number of entries in the archive and the offset to the central
57// directory of the offset.
58struct EocdRecord {
59 static const uint32_t kSignature = 0x06054b50;
Narayan Kamath7462f022013-11-21 13:05:04 +000060
Narayan Kamath926973e2014-06-09 14:18:14 +010061 // End of central directory signature, should always be
62 // |kSignature|.
63 uint32_t eocd_signature;
64 // The number of the current "disk", i.e, the "disk" that this
65 // central directory is on.
66 //
67 // This implementation assumes that each archive spans a single
68 // disk only. i.e, that disk_num == 1.
69 uint16_t disk_num;
70 // The disk where the central directory starts.
71 //
72 // This implementation assumes that each archive spans a single
73 // disk only. i.e, that cd_start_disk == 1.
74 uint16_t cd_start_disk;
75 // The number of central directory records on this disk.
76 //
77 // This implementation assumes that each archive spans a single
78 // disk only. i.e, that num_records_on_disk == num_records.
79 uint16_t num_records_on_disk;
80 // The total number of central directory records.
81 uint16_t num_records;
82 // The size of the central directory (in bytes).
83 uint32_t cd_size;
84 // The offset of the start of the central directory, relative
85 // to the start of the file.
86 uint32_t cd_start_offset;
87 // Length of the central directory comment.
88 uint16_t comment_length;
89 private:
90 DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
91} __attribute__((packed));
Narayan Kamath7462f022013-11-21 13:05:04 +000092
Narayan Kamath926973e2014-06-09 14:18:14 +010093// A structure representing the fixed length fields for a single
94// record in the central directory of the archive. In addition to
95// the fixed length fields listed here, each central directory
96// record contains a variable length "file_name" and "extra_field"
97// whose lengths are given by |file_name_length| and |extra_field_length|
98// respectively.
99struct CentralDirectoryRecord {
100 static const uint32_t kSignature = 0x02014b50;
Narayan Kamath7462f022013-11-21 13:05:04 +0000101
Narayan Kamath926973e2014-06-09 14:18:14 +0100102 // The start of record signature. Must be |kSignature|.
103 uint32_t record_signature;
104 // Tool version. Ignored by this implementation.
105 uint16_t version_made_by;
106 // Tool version. Ignored by this implementation.
107 uint16_t version_needed;
108 // The "general purpose bit flags" for this entry. The only
109 // flag value that we currently check for is the "data descriptor"
110 // flag.
111 uint16_t gpb_flags;
112 // The compression method for this entry, one of |kCompressStored|
113 // and |kCompressDeflated|.
114 uint16_t compression_method;
115 // The file modification time and date for this entry.
116 uint16_t last_mod_time;
117 uint16_t last_mod_date;
118 // The CRC-32 checksum for this entry.
119 uint32_t crc32;
120 // The compressed size (in bytes) of this entry.
121 uint32_t compressed_size;
122 // The uncompressed size (in bytes) of this entry.
123 uint32_t uncompressed_size;
124 // The length of the entry file name in bytes. The file name
125 // will appear immediately after this record.
126 uint16_t file_name_length;
127 // The length of the extra field info (in bytes). This data
128 // will appear immediately after the entry file name.
129 uint16_t extra_field_length;
130 // The length of the entry comment (in bytes). This data will
131 // appear immediately after the extra field.
132 uint16_t comment_length;
133 // The start disk for this entry. Ignored by this implementation).
134 uint16_t file_start_disk;
135 // File attributes. Ignored by this implementation.
136 uint16_t internal_file_attributes;
137 // File attributes. Ignored by this implementation.
138 uint32_t external_file_attributes;
139 // The offset to the local file header for this entry, from the
140 // beginning of this archive.
141 uint32_t local_file_header_offset;
142 private:
143 DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
144} __attribute__((packed));
Narayan Kamath7462f022013-11-21 13:05:04 +0000145
Narayan Kamath926973e2014-06-09 14:18:14 +0100146// The local file header for a given entry. This duplicates information
147// present in the central directory of the archive. It is an error for
148// the information here to be different from the central directory
149// information for a given entry.
150struct LocalFileHeader {
151 static const uint32_t kSignature = 0x04034b50;
Narayan Kamath7462f022013-11-21 13:05:04 +0000152
Narayan Kamath926973e2014-06-09 14:18:14 +0100153 // The local file header signature, must be |kSignature|.
154 uint32_t lfh_signature;
155 // Tool version. Ignored by this implementation.
156 uint16_t version_needed;
157 // The "general purpose bit flags" for this entry. The only
158 // flag value that we currently check for is the "data descriptor"
159 // flag.
160 uint16_t gpb_flags;
161 // The compression method for this entry, one of |kCompressStored|
162 // and |kCompressDeflated|.
163 uint16_t compression_method;
164 // The file modification time and date for this entry.
165 uint16_t last_mod_time;
166 uint16_t last_mod_date;
167 // The CRC-32 checksum for this entry.
168 uint32_t crc32;
169 // The compressed size (in bytes) of this entry.
170 uint32_t compressed_size;
171 // The uncompressed size (in bytes) of this entry.
172 uint32_t uncompressed_size;
173 // The length of the entry file name in bytes. The file name
174 // will appear immediately after this record.
175 uint16_t file_name_length;
176 // The length of the extra field info (in bytes). This data
177 // will appear immediately after the entry file name.
178 uint16_t extra_field_length;
179 private:
180 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
181} __attribute__((packed));
182
183struct DataDescriptor {
184 // The *optional* data descriptor start signature.
185 static const uint32_t kOptSignature = 0x08074b50;
186
187 // CRC-32 checksum of the entry.
188 uint32_t crc32;
189 // Compressed size of the entry.
190 uint32_t compressed_size;
191 // Uncompressed size of the entry.
192 uint32_t uncompressed_size;
193 private:
194 DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
195} __attribute__((packed));
196
197#undef DISALLOW_IMPLICIT_CONSTRUCTORS
198
Piotr Jastrzebskibd0a7482014-08-13 09:49:25 +0000199static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
Narayan Kamath7462f022013-11-21 13:05:04 +0000200
Narayan Kamath926973e2014-06-09 14:18:14 +0100201// The maximum size of a central directory or a file
202// comment in bytes.
203static const uint32_t kMaxCommentLen = 65535;
204
205// The maximum number of bytes to scan backwards for the EOCD start.
206static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
207
Narayan Kamath7462f022013-11-21 13:05:04 +0000208static const char* kErrorMessages[] = {
209 "Unknown return code.",
Narayan Kamatheb41ad22013-12-09 16:26:36 +0000210 "Iteration ended",
Narayan Kamath7462f022013-11-21 13:05:04 +0000211 "Zlib error",
212 "Invalid file",
213 "Invalid handle",
214 "Duplicate entries in archive",
215 "Empty archive",
216 "Entry not found",
217 "Invalid offset",
218 "Inconsistent information",
219 "Invalid entry name",
Narayan Kamatheb41ad22013-12-09 16:26:36 +0000220 "I/O Error",
Narayan Kamatheaf98852013-12-11 14:51:51 +0000221 "File mapping failed"
Narayan Kamath7462f022013-11-21 13:05:04 +0000222};
223
224static const int32_t kErrorMessageUpperBound = 0;
225
Narayan Kamatheb41ad22013-12-09 16:26:36 +0000226static const int32_t kIterationEnd = -1;
Narayan Kamath7462f022013-11-21 13:05:04 +0000227
228// We encountered a Zlib error when inflating a stream from this file.
229// Usually indicates file corruption.
230static const int32_t kZlibError = -2;
231
232// The input file cannot be processed as a zip archive. Usually because
233// it's too small, too large or does not have a valid signature.
234static const int32_t kInvalidFile = -3;
235
236// An invalid iteration / ziparchive handle was passed in as an input
237// argument.
238static const int32_t kInvalidHandle = -4;
239
240// The zip archive contained two (or possibly more) entries with the same
241// name.
242static const int32_t kDuplicateEntry = -5;
243
244// The zip archive contains no entries.
245static const int32_t kEmptyArchive = -6;
246
247// The specified entry was not found in the archive.
248static const int32_t kEntryNotFound = -7;
249
250// The zip archive contained an invalid local file header pointer.
251static const int32_t kInvalidOffset = -8;
252
253// The zip archive contained inconsistent entry information. This could
254// be because the central directory & local file header did not agree, or
255// if the actual uncompressed length or crc32 do not match their declared
256// values.
257static const int32_t kInconsistentInformation = -9;
258
259// An invalid entry name was encountered.
260static const int32_t kInvalidEntryName = -10;
261
Narayan Kamatheb41ad22013-12-09 16:26:36 +0000262// An I/O related system call (read, lseek, ftruncate, map) failed.
263static const int32_t kIoError = -11;
Narayan Kamath7462f022013-11-21 13:05:04 +0000264
Narayan Kamatheaf98852013-12-11 14:51:51 +0000265// We were not able to mmap the central directory or entry contents.
266static const int32_t kMmapFailed = -12;
Narayan Kamath7462f022013-11-21 13:05:04 +0000267
Narayan Kamatheaf98852013-12-11 14:51:51 +0000268static const int32_t kErrorMessageLowerBound = -13;
Narayan Kamath7462f022013-11-21 13:05:04 +0000269
Narayan Kamatheaf98852013-12-11 14:51:51 +0000270static const char kTempMappingFileName[] = "zip: ExtractFileToFile";
Narayan Kamath7462f022013-11-21 13:05:04 +0000271
272/*
273 * A Read-only Zip archive.
274 *
275 * We want "open" and "find entry by name" to be fast operations, and
276 * we want to use as little memory as possible. We memory-map the zip
277 * central directory, and load a hash table with pointers to the filenames
278 * (which aren't null-terminated). The other fields are at a fixed offset
279 * from the filename, so we don't need to extract those (but we do need
280 * to byte-read and endian-swap them every time we want them).
281 *
282 * It's possible that somebody has handed us a massive (~1GB) zip archive,
283 * so we can't expect to mmap the entire file.
284 *
285 * To speed comparisons when doing a lookup by name, we could make the mapping
286 * "private" (copy-on-write) and null-terminate the filenames after verifying
287 * the record structure. However, this requires a private mapping of
288 * every page that the Central Directory touches. Easier to tuck a copy
289 * of the string length into the hash table entry.
290 */
291struct ZipArchive {
292 /* open Zip archive */
Neil Fullerb1a113f2014-07-25 14:43:04 +0100293 const int fd;
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700294 const bool close_file;
Narayan Kamath7462f022013-11-21 13:05:04 +0000295
296 /* mapped central directory area */
297 off64_t directory_offset;
Dmitriy Ivanov4b67f832015-03-06 10:22:34 -0800298 android::FileMap directory_map;
Narayan Kamath7462f022013-11-21 13:05:04 +0000299
300 /* number of entries in the Zip archive */
301 uint16_t num_entries;
302
303 /*
304 * We know how many entries are in the Zip archive, so we can have a
305 * fixed-size hash table. We define a load factor of 0.75 and overallocat
306 * so the maximum number entries can never be higher than
307 * ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
308 */
309 uint32_t hash_table_size;
310 ZipEntryName* hash_table;
Neil Fullerb1a113f2014-07-25 14:43:04 +0100311
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700312 ZipArchive(const int fd, bool assume_ownership) :
Neil Fullerb1a113f2014-07-25 14:43:04 +0100313 fd(fd),
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700314 close_file(assume_ownership),
Neil Fullerb1a113f2014-07-25 14:43:04 +0100315 directory_offset(0),
Neil Fullerb1a113f2014-07-25 14:43:04 +0100316 num_entries(0),
317 hash_table_size(0),
318 hash_table(NULL) {}
319
320 ~ZipArchive() {
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700321 if (close_file && fd >= 0) {
Neil Fullerb1a113f2014-07-25 14:43:04 +0100322 close(fd);
323 }
324
Neil Fullerb1a113f2014-07-25 14:43:04 +0100325 free(hash_table);
326 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000327};
328
Narayan Kamath7462f022013-11-21 13:05:04 +0000329static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
330 static const uint32_t kBufSize = 32768;
331 uint8_t buf[kBufSize];
332
333 uint32_t count = 0;
334 uint64_t crc = 0;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000335 while (count < length) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000336 uint32_t remaining = length - count;
337
338 // Safe conversion because kBufSize is narrow enough for a 32 bit signed
339 // value.
340 ssize_t get_size = (remaining > kBufSize) ? kBufSize : remaining;
341 ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
342
343 if (actual != get_size) {
Mark Salyzyn51d562d2014-05-05 14:38:05 -0700344 ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, get_size);
Narayan Kamath7462f022013-11-21 13:05:04 +0000345 return kIoError;
346 }
347
348 memcpy(begin + count, buf, get_size);
349 crc = crc32(crc, buf, get_size);
350 count += get_size;
351 }
352
353 *crc_out = crc;
354
355 return 0;
356}
357
358/*
359 * Round up to the next highest power of 2.
360 *
361 * Found on http://graphics.stanford.edu/~seander/bithacks.html.
362 */
363static uint32_t RoundUpPower2(uint32_t val) {
364 val--;
365 val |= val >> 1;
366 val |= val >> 2;
367 val |= val >> 4;
368 val |= val >> 8;
369 val |= val >> 16;
370 val++;
371
372 return val;
373}
374
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100375static uint32_t ComputeHash(const ZipEntryName& name) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000376 uint32_t hash = 0;
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100377 uint16_t len = name.name_length;
378 const uint8_t* str = name.name;
Narayan Kamath7462f022013-11-21 13:05:04 +0000379
380 while (len--) {
381 hash = hash * 31 + *str++;
382 }
383
384 return hash;
385}
386
387/*
388 * Convert a ZipEntry to a hash table index, verifying that it's in a
389 * valid range.
390 */
391static int64_t EntryToIndex(const ZipEntryName* hash_table,
392 const uint32_t hash_table_size,
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100393 const ZipEntryName& name) {
394 const uint32_t hash = ComputeHash(name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000395
396 // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
397 uint32_t ent = hash & (hash_table_size - 1);
398 while (hash_table[ent].name != NULL) {
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100399 if (hash_table[ent].name_length == name.name_length &&
400 memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000401 return ent;
402 }
403
404 ent = (ent + 1) & (hash_table_size - 1);
405 }
406
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100407 ALOGV("Zip: Unable to find entry %.*s", name.name_length, name.name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000408 return kEntryNotFound;
409}
410
411/*
412 * Add a new entry to the hash table.
413 */
414static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_size,
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100415 const ZipEntryName& name) {
416 const uint64_t hash = ComputeHash(name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000417 uint32_t ent = hash & (hash_table_size - 1);
418
419 /*
420 * We over-allocated the table, so we're guaranteed to find an empty slot.
421 * Further, we guarantee that the hashtable size is not 0.
422 */
423 while (hash_table[ent].name != NULL) {
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100424 if (hash_table[ent].name_length == name.name_length &&
425 memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000426 // We've found a duplicate entry. We don't accept it
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100427 ALOGW("Zip: Found duplicate entry %.*s", name.name_length, name.name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000428 return kDuplicateEntry;
429 }
430 ent = (ent + 1) & (hash_table_size - 1);
431 }
432
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100433 hash_table[ent].name = name.name;
434 hash_table[ent].name_length = name.name_length;
Narayan Kamath7462f022013-11-21 13:05:04 +0000435 return 0;
436}
437
Narayan Kamath7462f022013-11-21 13:05:04 +0000438static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
439 ZipArchive* archive, off64_t file_length,
Narayan Kamath926973e2014-06-09 14:18:14 +0100440 off64_t read_amount, uint8_t* scan_buffer) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000441 const off64_t search_start = file_length - read_amount;
442
443 if (lseek64(fd, search_start, SEEK_SET) != search_start) {
Narayan Kamath926973e2014-06-09 14:18:14 +0100444 ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
445 strerror(errno));
Narayan Kamath7462f022013-11-21 13:05:04 +0000446 return kIoError;
447 }
Narayan Kamath926973e2014-06-09 14:18:14 +0100448 ssize_t actual = TEMP_FAILURE_RETRY(
449 read(fd, scan_buffer, static_cast<size_t>(read_amount)));
450 if (actual != static_cast<ssize_t>(read_amount)) {
451 ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
452 strerror(errno));
Narayan Kamath7462f022013-11-21 13:05:04 +0000453 return kIoError;
454 }
455
456 /*
457 * Scan backward for the EOCD magic. In an archive without a trailing
458 * comment, we'll find it on the first try. (We may want to consider
459 * doing an initial minimal read; if we don't find it, retry with a
460 * second read as above.)
461 */
Narayan Kamath926973e2014-06-09 14:18:14 +0100462 int i = read_amount - sizeof(EocdRecord);
463 for (; i >= 0; i--) {
464 if (scan_buffer[i] == 0x50 &&
465 ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000466 ALOGV("+++ Found EOCD at buf+%d", i);
467 break;
468 }
469 }
470 if (i < 0) {
471 ALOGD("Zip: EOCD not found, %s is not zip", debug_file_name);
472 return kInvalidFile;
473 }
474
475 const off64_t eocd_offset = search_start + i;
Narayan Kamath926973e2014-06-09 14:18:14 +0100476 const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i);
Narayan Kamath7462f022013-11-21 13:05:04 +0000477 /*
Narayan Kamath926973e2014-06-09 14:18:14 +0100478 * Verify that there's no trailing space at the end of the central directory
479 * and its comment.
Narayan Kamath7462f022013-11-21 13:05:04 +0000480 */
Narayan Kamath926973e2014-06-09 14:18:14 +0100481 const off64_t calculated_length = eocd_offset + sizeof(EocdRecord)
482 + eocd->comment_length;
483 if (calculated_length != file_length) {
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100484 ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
Narayan Kamath926973e2014-06-09 14:18:14 +0100485 static_cast<int64_t>(file_length - calculated_length));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100486 return kInvalidFile;
487 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000488
Narayan Kamath926973e2014-06-09 14:18:14 +0100489 /*
490 * Grab the CD offset and size, and the number of entries in the
491 * archive and verify that they look reasonable.
492 */
493 if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
494 ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
495 eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +0000496 return kInvalidOffset;
497 }
Narayan Kamath926973e2014-06-09 14:18:14 +0100498 if (eocd->num_records == 0) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000499 ALOGW("Zip: empty archive?");
500 return kEmptyArchive;
501 }
502
Narayan Kamath926973e2014-06-09 14:18:14 +0100503 ALOGV("+++ num_entries=%" PRIu32 "dir_size=%" PRIu32 " dir_offset=%" PRIu32,
504 eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
Narayan Kamath7462f022013-11-21 13:05:04 +0000505
506 /*
507 * It all looks good. Create a mapping for the CD, and set the fields
508 * in archive.
509 */
Dmitriy Ivanov4b67f832015-03-06 10:22:34 -0800510 if (!archive->directory_map.create(debug_file_name, fd,
511 static_cast<off64_t>(eocd->cd_start_offset),
512 static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
Narayan Kamatheaf98852013-12-11 14:51:51 +0000513 return kMmapFailed;
Narayan Kamath7462f022013-11-21 13:05:04 +0000514 }
515
Narayan Kamath926973e2014-06-09 14:18:14 +0100516 archive->num_entries = eocd->num_records;
517 archive->directory_offset = eocd->cd_start_offset;
Narayan Kamath7462f022013-11-21 13:05:04 +0000518
519 return 0;
520}
521
522/*
523 * Find the zip Central Directory and memory-map it.
524 *
525 * On success, returns 0 after populating fields from the EOCD area:
526 * directory_offset
527 * directory_map
528 * num_entries
529 */
530static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
531 ZipArchive* archive) {
532
533 // Test file length. We use lseek64 to make sure the file
534 // is small enough to be a zip file (Its size must be less than
535 // 0xffffffff bytes).
536 off64_t file_length = lseek64(fd, 0, SEEK_END);
537 if (file_length == -1) {
538 ALOGV("Zip: lseek on fd %d failed", fd);
539 return kInvalidFile;
540 }
541
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800542 if (file_length > static_cast<off64_t>(0xffffffff)) {
Narayan Kamath926973e2014-06-09 14:18:14 +0100543 ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
Narayan Kamath7462f022013-11-21 13:05:04 +0000544 return kInvalidFile;
545 }
546
Narayan Kamath926973e2014-06-09 14:18:14 +0100547 if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) {
548 ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length));
Narayan Kamath7462f022013-11-21 13:05:04 +0000549 return kInvalidFile;
550 }
551
552 /*
553 * Perform the traditional EOCD snipe hunt.
554 *
555 * We're searching for the End of Central Directory magic number,
556 * which appears at the start of the EOCD block. It's followed by
557 * 18 bytes of EOCD stuff and up to 64KB of archive comment. We
558 * need to read the last part of the file into a buffer, dig through
559 * it to find the magic number, parse some values out, and use those
560 * to determine the extent of the CD.
561 *
562 * We start by pulling in the last part of the file.
563 */
Narayan Kamath926973e2014-06-09 14:18:14 +0100564 off64_t read_amount = kMaxEOCDSearch;
565 if (file_length < read_amount) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000566 read_amount = file_length;
567 }
568
Narayan Kamath926973e2014-06-09 14:18:14 +0100569 uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
Narayan Kamath7462f022013-11-21 13:05:04 +0000570 int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
571 file_length, read_amount, scan_buffer);
572
573 free(scan_buffer);
574 return result;
575}
576
577/*
578 * Parses the Zip archive's Central Directory. Allocates and populates the
579 * hash table.
580 *
581 * Returns 0 on success.
582 */
583static int32_t ParseZipArchive(ZipArchive* archive) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800584 const uint8_t* const cd_ptr =
585 reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
Dmitriy Ivanov4b67f832015-03-06 10:22:34 -0800586 const size_t cd_length = archive->directory_map.getDataLength();
Narayan Kamath926973e2014-06-09 14:18:14 +0100587 const uint16_t num_entries = archive->num_entries;
Narayan Kamath7462f022013-11-21 13:05:04 +0000588
589 /*
590 * Create hash table. We have a minimum 75% load factor, possibly as
591 * low as 50% after we round off to a power of 2. There must be at
592 * least one unused entry to avoid an infinite loop during creation.
593 */
594 archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800595 archive->hash_table = reinterpret_cast<ZipEntryName*>(calloc(archive->hash_table_size,
596 sizeof(ZipEntryName)));
Narayan Kamath7462f022013-11-21 13:05:04 +0000597
598 /*
599 * Walk through the central directory, adding entries to the hash
600 * table and verifying values.
601 */
Narayan Kamath926973e2014-06-09 14:18:14 +0100602 const uint8_t* const cd_end = cd_ptr + cd_length;
Narayan Kamath7462f022013-11-21 13:05:04 +0000603 const uint8_t* ptr = cd_ptr;
604 for (uint16_t i = 0; i < num_entries; i++) {
Narayan Kamath926973e2014-06-09 14:18:14 +0100605 const CentralDirectoryRecord* cdr =
606 reinterpret_cast<const CentralDirectoryRecord*>(ptr);
607 if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700608 ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
Dmitriy Ivanov3ea93da2015-03-06 11:48:47 -0800609 return -1;
Narayan Kamath7462f022013-11-21 13:05:04 +0000610 }
611
Narayan Kamath926973e2014-06-09 14:18:14 +0100612 if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700613 ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
Dmitriy Ivanov3ea93da2015-03-06 11:48:47 -0800614 return -1;
Narayan Kamath7462f022013-11-21 13:05:04 +0000615 }
616
Narayan Kamath926973e2014-06-09 14:18:14 +0100617 const off64_t local_header_offset = cdr->local_file_header_offset;
Narayan Kamath7462f022013-11-21 13:05:04 +0000618 if (local_header_offset >= archive->directory_offset) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800619 ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
620 static_cast<int64_t>(local_header_offset), i);
Dmitriy Ivanov3ea93da2015-03-06 11:48:47 -0800621 return -1;
Narayan Kamath7462f022013-11-21 13:05:04 +0000622 }
623
Narayan Kamath926973e2014-06-09 14:18:14 +0100624 const uint16_t file_name_length = cdr->file_name_length;
625 const uint16_t extra_length = cdr->extra_field_length;
626 const uint16_t comment_length = cdr->comment_length;
Piotr Jastrzebski78271ba2014-08-15 12:53:00 +0100627 const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
628
Narayan Kamath044bc8e2014-12-03 18:22:53 +0000629 /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
630 if (!IsValidEntryName(file_name, file_name_length)) {
Dmitriy Ivanov3ea93da2015-03-06 11:48:47 -0800631 return -1;
Piotr Jastrzebski78271ba2014-08-15 12:53:00 +0100632 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000633
634 /* add the CDE filename to the hash table */
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100635 ZipEntryName entry_name;
636 entry_name.name = file_name;
637 entry_name.name_length = file_name_length;
Narayan Kamath7462f022013-11-21 13:05:04 +0000638 const int add_result = AddToHash(archive->hash_table,
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100639 archive->hash_table_size, entry_name);
Dmitriy Ivanov3ea93da2015-03-06 11:48:47 -0800640 if (add_result != 0) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000641 ALOGW("Zip: Error adding entry to hash table %d", add_result);
Dmitriy Ivanov3ea93da2015-03-06 11:48:47 -0800642 return add_result;
Narayan Kamath7462f022013-11-21 13:05:04 +0000643 }
644
Narayan Kamath926973e2014-06-09 14:18:14 +0100645 ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
646 if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700647 ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
648 ptr - cd_ptr, cd_length, i);
Dmitriy Ivanov3ea93da2015-03-06 11:48:47 -0800649 return -1;
Narayan Kamath7462f022013-11-21 13:05:04 +0000650 }
651 }
Mark Salyzyn088bf902014-05-08 16:02:20 -0700652 ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
Narayan Kamath7462f022013-11-21 13:05:04 +0000653
Dmitriy Ivanov3ea93da2015-03-06 11:48:47 -0800654 return 0;
Narayan Kamath7462f022013-11-21 13:05:04 +0000655}
656
657static int32_t OpenArchiveInternal(ZipArchive* archive,
658 const char* debug_file_name) {
659 int32_t result = -1;
660 if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) {
661 return result;
662 }
663
664 if ((result = ParseZipArchive(archive))) {
665 return result;
666 }
667
668 return 0;
669}
670
671int32_t OpenArchiveFd(int fd, const char* debug_file_name,
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700672 ZipArchiveHandle* handle, bool assume_ownership) {
673 ZipArchive* archive = new ZipArchive(fd, assume_ownership);
Narayan Kamath7462f022013-11-21 13:05:04 +0000674 *handle = archive;
Narayan Kamath7462f022013-11-21 13:05:04 +0000675 return OpenArchiveInternal(archive, debug_file_name);
676}
677
678int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
Neil Fullerb1a113f2014-07-25 14:43:04 +0100679 const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700680 ZipArchive* archive = new ZipArchive(fd, true);
Narayan Kamath7462f022013-11-21 13:05:04 +0000681 *handle = archive;
682
Narayan Kamath7462f022013-11-21 13:05:04 +0000683 if (fd < 0) {
684 ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
685 return kIoError;
Narayan Kamath7462f022013-11-21 13:05:04 +0000686 }
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700687
Narayan Kamath7462f022013-11-21 13:05:04 +0000688 return OpenArchiveInternal(archive, fileName);
689}
690
691/*
692 * Close a ZipArchive, closing the file and freeing the contents.
693 */
694void CloseArchive(ZipArchiveHandle handle) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800695 ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
Narayan Kamath7462f022013-11-21 13:05:04 +0000696 ALOGV("Closing archive %p", archive);
Neil Fullerb1a113f2014-07-25 14:43:04 +0100697 delete archive;
Narayan Kamath7462f022013-11-21 13:05:04 +0000698}
699
700static int32_t UpdateEntryFromDataDescriptor(int fd,
701 ZipEntry *entry) {
Narayan Kamath926973e2014-06-09 14:18:14 +0100702 uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
Narayan Kamath7462f022013-11-21 13:05:04 +0000703 ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf)));
704 if (actual != sizeof(ddBuf)) {
705 return kIoError;
706 }
707
Narayan Kamath926973e2014-06-09 14:18:14 +0100708 const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
709 const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
710 const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
Narayan Kamath7462f022013-11-21 13:05:04 +0000711
Narayan Kamath926973e2014-06-09 14:18:14 +0100712 entry->crc32 = descriptor->crc32;
713 entry->compressed_length = descriptor->compressed_size;
714 entry->uncompressed_length = descriptor->uncompressed_size;
Narayan Kamath7462f022013-11-21 13:05:04 +0000715
716 return 0;
717}
718
719// Attempts to read |len| bytes into |buf| at offset |off|.
720//
721// This method uses pread64 on platforms that support it and
722// lseek64 + read on platforms that don't. This implies that
723// callers should not rely on the |fd| offset being incremented
724// as a side effect of this call.
725static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len,
726 off64_t off) {
Yabin Cui70160f42014-11-19 20:47:18 -0800727#if !defined(_WIN32)
Narayan Kamath7462f022013-11-21 13:05:04 +0000728 return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
729#else
730 // The only supported platform that doesn't support pread at the moment
731 // is Windows. Only recent versions of windows support unix like forks,
732 // and even there the semantics are quite different.
733 if (lseek64(fd, off, SEEK_SET) != off) {
Mark Salyzyn99ef9912014-03-14 14:26:22 -0700734 ALOGW("Zip: failed seek to offset %" PRId64, off);
Narayan Kamath7462f022013-11-21 13:05:04 +0000735 return kIoError;
736 }
737
738 return TEMP_FAILURE_RETRY(read(fd, buf, len));
Yabin Cui70160f42014-11-19 20:47:18 -0800739#endif
Narayan Kamath7462f022013-11-21 13:05:04 +0000740}
741
742static int32_t FindEntry(const ZipArchive* archive, const int ent,
743 ZipEntry* data) {
744 const uint16_t nameLen = archive->hash_table[ent].name_length;
Narayan Kamath7462f022013-11-21 13:05:04 +0000745
746 // Recover the start of the central directory entry from the filename
747 // pointer. The filename is the first entry past the fixed-size data,
748 // so we can just subtract back from that.
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100749 const uint8_t* ptr = archive->hash_table[ent].name;
Narayan Kamath926973e2014-06-09 14:18:14 +0100750 ptr -= sizeof(CentralDirectoryRecord);
Narayan Kamath7462f022013-11-21 13:05:04 +0000751
752 // This is the base of our mmapped region, we have to sanity check that
753 // the name that's in the hash table is a pointer to a location within
754 // this mapped region.
Narayan Kamath926973e2014-06-09 14:18:14 +0100755 const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
Dmitriy Ivanov4b67f832015-03-06 10:22:34 -0800756 archive->directory_map.getDataPtr());
757 if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000758 ALOGW("Zip: Invalid entry pointer");
759 return kInvalidOffset;
760 }
761
Narayan Kamath926973e2014-06-09 14:18:14 +0100762 const CentralDirectoryRecord *cdr =
763 reinterpret_cast<const CentralDirectoryRecord*>(ptr);
764
Narayan Kamath7462f022013-11-21 13:05:04 +0000765 // The offset of the start of the central directory in the zipfile.
766 // We keep this lying around so that we can sanity check all our lengths
767 // and our per-file structures.
768 const off64_t cd_offset = archive->directory_offset;
769
770 // Fill out the compression method, modification time, crc32
771 // and other interesting attributes from the central directory. These
772 // will later be compared against values from the local file header.
Narayan Kamath926973e2014-06-09 14:18:14 +0100773 data->method = cdr->compression_method;
774 data->mod_time = cdr->last_mod_time;
775 data->crc32 = cdr->crc32;
776 data->compressed_length = cdr->compressed_size;
777 data->uncompressed_length = cdr->uncompressed_size;
Narayan Kamath7462f022013-11-21 13:05:04 +0000778
779 // Figure out the local header offset from the central directory. The
780 // actual file data will begin after the local header and the name /
781 // extra comments.
Narayan Kamath926973e2014-06-09 14:18:14 +0100782 const off64_t local_header_offset = cdr->local_file_header_offset;
783 if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000784 ALOGW("Zip: bad local hdr offset in zip");
785 return kInvalidOffset;
786 }
787
Narayan Kamath926973e2014-06-09 14:18:14 +0100788 uint8_t lfh_buf[sizeof(LocalFileHeader)];
Narayan Kamath7462f022013-11-21 13:05:04 +0000789 ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
790 local_header_offset);
791 if (actual != sizeof(lfh_buf)) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800792 ALOGW("Zip: failed reading lfh name from offset %" PRId64,
793 static_cast<int64_t>(local_header_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +0000794 return kIoError;
795 }
796
Narayan Kamath926973e2014-06-09 14:18:14 +0100797 const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
798
799 if (lfh->lfh_signature != LocalFileHeader::kSignature) {
Mark Salyzyn99ef9912014-03-14 14:26:22 -0700800 ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
Narayan Kamath926973e2014-06-09 14:18:14 +0100801 static_cast<int64_t>(local_header_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +0000802 return kInvalidOffset;
803 }
804
805 // Paranoia: Match the values specified in the local file header
806 // to those specified in the central directory.
Narayan Kamath926973e2014-06-09 14:18:14 +0100807 if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000808 data->has_data_descriptor = 0;
Narayan Kamath926973e2014-06-09 14:18:14 +0100809 if (data->compressed_length != lfh->compressed_size
810 || data->uncompressed_length != lfh->uncompressed_size
811 || data->crc32 != lfh->crc32) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700812 ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32
813 ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
Narayan Kamath7462f022013-11-21 13:05:04 +0000814 data->compressed_length, data->uncompressed_length, data->crc32,
Narayan Kamath926973e2014-06-09 14:18:14 +0100815 lfh->compressed_size, lfh->uncompressed_size, lfh->crc32);
Narayan Kamath7462f022013-11-21 13:05:04 +0000816 return kInconsistentInformation;
817 }
818 } else {
819 data->has_data_descriptor = 1;
820 }
821
822 // Check that the local file header name matches the declared
823 // name in the central directory.
Narayan Kamath926973e2014-06-09 14:18:14 +0100824 if (lfh->file_name_length == nameLen) {
825 const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
826 if (name_offset + lfh->file_name_length >= cd_offset) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000827 ALOGW("Zip: Invalid declared length");
828 return kInvalidOffset;
829 }
830
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800831 uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
Narayan Kamath7462f022013-11-21 13:05:04 +0000832 ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
833 name_offset);
834
835 if (actual != nameLen) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800836 ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +0000837 free(name_buf);
838 return kIoError;
839 }
840
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100841 if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000842 free(name_buf);
843 return kInconsistentInformation;
844 }
845
846 free(name_buf);
847 } else {
848 ALOGW("Zip: lfh name did not match central directory.");
849 return kInconsistentInformation;
850 }
851
Narayan Kamath926973e2014-06-09 14:18:14 +0100852 const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
853 + lfh->file_name_length + lfh->extra_field_length;
Narayan Kamath48953a12014-01-24 12:32:39 +0000854 if (data_offset > cd_offset) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800855 ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +0000856 return kInvalidOffset;
857 }
858
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800859 if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700860 ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800861 static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +0000862 return kInvalidOffset;
863 }
864
865 if (data->method == kCompressStored &&
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800866 static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
Mark Salyzyn088bf902014-05-08 16:02:20 -0700867 ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800868 static_cast<int64_t>(data_offset), data->uncompressed_length,
869 static_cast<int64_t>(cd_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +0000870 return kInvalidOffset;
871 }
872
873 data->offset = data_offset;
874 return 0;
875}
876
877struct IterationHandle {
878 uint32_t position;
Piotr Jastrzebski10aa9a02014-08-19 09:01:20 +0100879 // We're not using vector here because this code is used in the Windows SDK
880 // where the STL is not available.
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100881 const uint8_t* prefix;
882 uint16_t prefix_len;
Narayan Kamath7462f022013-11-21 13:05:04 +0000883 ZipArchive* archive;
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100884
885 IterationHandle() : prefix(NULL), prefix_len(0) {}
886
887 IterationHandle(const ZipEntryName& prefix_name)
888 : prefix_len(prefix_name.name_length) {
889 uint8_t* prefix_copy = new uint8_t[prefix_len];
Piotr Jastrzebski10aa9a02014-08-19 09:01:20 +0100890 memcpy(prefix_copy, prefix_name.name, prefix_len);
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100891 prefix = prefix_copy;
892 }
893
894 ~IterationHandle() {
Piotr Jastrzebski10aa9a02014-08-19 09:01:20 +0100895 delete[] prefix;
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100896 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000897};
898
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100899int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
900 const ZipEntryName* optional_prefix) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800901 ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
Narayan Kamath7462f022013-11-21 13:05:04 +0000902
903 if (archive == NULL || archive->hash_table == NULL) {
904 ALOGW("Zip: Invalid ZipArchiveHandle");
905 return kInvalidHandle;
906 }
907
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100908 IterationHandle* cookie =
909 optional_prefix != NULL ? new IterationHandle(*optional_prefix) : new IterationHandle();
Narayan Kamath7462f022013-11-21 13:05:04 +0000910 cookie->position = 0;
Narayan Kamath7462f022013-11-21 13:05:04 +0000911 cookie->archive = archive;
Narayan Kamath7462f022013-11-21 13:05:04 +0000912
913 *cookie_ptr = cookie ;
914 return 0;
915}
916
Piotr Jastrzebski79c8b342014-08-08 14:02:17 +0100917void EndIteration(void* cookie) {
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100918 delete reinterpret_cast<IterationHandle*>(cookie);
Piotr Jastrzebski79c8b342014-08-08 14:02:17 +0100919}
920
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100921int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
Narayan Kamath7462f022013-11-21 13:05:04 +0000922 ZipEntry* data) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800923 const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100924 if (entryName.name_length == 0) {
925 ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000926 return kInvalidEntryName;
927 }
928
929 const int64_t ent = EntryToIndex(archive->hash_table,
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100930 archive->hash_table_size, entryName);
Narayan Kamath7462f022013-11-21 13:05:04 +0000931
932 if (ent < 0) {
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100933 ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name);
Narayan Kamath7462f022013-11-21 13:05:04 +0000934 return ent;
935 }
936
937 return FindEntry(archive, ent, data);
938}
939
940int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -0800941 IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
Narayan Kamath7462f022013-11-21 13:05:04 +0000942 if (handle == NULL) {
943 return kInvalidHandle;
944 }
945
946 ZipArchive* archive = handle->archive;
947 if (archive == NULL || archive->hash_table == NULL) {
948 ALOGW("Zip: Invalid ZipArchiveHandle");
949 return kInvalidHandle;
950 }
951
952 const uint32_t currentOffset = handle->position;
953 const uint32_t hash_table_length = archive->hash_table_size;
954 const ZipEntryName *hash_table = archive->hash_table;
955
956 for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
957 if (hash_table[i].name != NULL &&
Piotr Jastrzebski8e085362014-08-18 11:37:45 +0100958 (handle->prefix_len == 0 ||
959 (memcmp(handle->prefix, hash_table[i].name, handle->prefix_len) == 0))) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000960 handle->position = (i + 1);
961 const int error = FindEntry(archive, i, data);
962 if (!error) {
963 name->name = hash_table[i].name;
964 name->name_length = hash_table[i].name_length;
965 }
966
967 return error;
968 }
969 }
970
971 handle->position = 0;
972 return kIterationEnd;
973}
974
Dmitriy Ivanovf94e1592015-03-06 13:27:59 -0800975// This method is using libz macros with old-style-casts
976#pragma GCC diagnostic push
977#pragma GCC diagnostic ignored "-Wold-style-cast"
978static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
979 return inflateInit2(stream, window_bits);
980}
981#pragma GCC diagnostic pop
982
Narayan Kamath7462f022013-11-21 13:05:04 +0000983static int32_t InflateToFile(int fd, const ZipEntry* entry,
984 uint8_t* begin, uint32_t length,
985 uint64_t* crc_out) {
Narayan Kamath7462f022013-11-21 13:05:04 +0000986 const uint32_t kBufSize = 32768;
987 uint8_t read_buf[kBufSize];
988 uint8_t write_buf[kBufSize];
989 z_stream zstream;
990 int zerr;
991
992 /*
993 * Initialize the zlib stream struct.
994 */
995 memset(&zstream, 0, sizeof(zstream));
996 zstream.zalloc = Z_NULL;
997 zstream.zfree = Z_NULL;
998 zstream.opaque = Z_NULL;
999 zstream.next_in = NULL;
1000 zstream.avail_in = 0;
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -08001001 zstream.next_out = reinterpret_cast<Bytef*>(write_buf);
Narayan Kamath7462f022013-11-21 13:05:04 +00001002 zstream.avail_out = kBufSize;
1003 zstream.data_type = Z_UNKNOWN;
1004
1005 /*
1006 * Use the undocumented "negative window bits" feature to tell zlib
1007 * that there's no zlib header waiting for it.
1008 */
Dmitriy Ivanovf94e1592015-03-06 13:27:59 -08001009 zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
Narayan Kamath7462f022013-11-21 13:05:04 +00001010 if (zerr != Z_OK) {
1011 if (zerr == Z_VERSION_ERROR) {
1012 ALOGE("Installed zlib is not compatible with linked version (%s)",
1013 ZLIB_VERSION);
1014 } else {
1015 ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr);
1016 }
1017
1018 return kZlibError;
1019 }
1020
Dmitriy Ivanov1f741e52015-03-06 14:26:37 -08001021 auto zstream_deleter = [](z_stream* stream) {
1022 inflateEnd(stream); /* free up any allocated structures */
1023 };
1024
1025 std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
1026
Narayan Kamath7462f022013-11-21 13:05:04 +00001027 const uint32_t uncompressed_length = entry->uncompressed_length;
1028
1029 uint32_t compressed_length = entry->compressed_length;
1030 uint32_t write_count = 0;
1031 do {
1032 /* read as much as we can */
1033 if (zstream.avail_in == 0) {
Mark Salyzyn51d562d2014-05-05 14:38:05 -07001034 const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
1035 const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
Narayan Kamath7462f022013-11-21 13:05:04 +00001036 if (actual != getSize) {
Mark Salyzyn51d562d2014-05-05 14:38:05 -07001037 ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
Dmitriy Ivanov1f741e52015-03-06 14:26:37 -08001038 return kIoError;
Narayan Kamath7462f022013-11-21 13:05:04 +00001039 }
1040
1041 compressed_length -= getSize;
1042
1043 zstream.next_in = read_buf;
1044 zstream.avail_in = getSize;
1045 }
1046
1047 /* uncompress the data */
1048 zerr = inflate(&zstream, Z_NO_FLUSH);
1049 if (zerr != Z_OK && zerr != Z_STREAM_END) {
1050 ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
1051 zerr, zstream.next_in, zstream.avail_in,
1052 zstream.next_out, zstream.avail_out);
Dmitriy Ivanov1f741e52015-03-06 14:26:37 -08001053 return kZlibError;
Narayan Kamath7462f022013-11-21 13:05:04 +00001054 }
1055
1056 /* write when we're full or when we're done */
1057 if (zstream.avail_out == 0 ||
1058 (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
1059 const size_t write_size = zstream.next_out - write_buf;
1060 // The file might have declared a bogus length.
1061 if (write_size + write_count > length) {
Dmitriy Ivanov1f741e52015-03-06 14:26:37 -08001062 return -1;
Narayan Kamath7462f022013-11-21 13:05:04 +00001063 }
1064 memcpy(begin + write_count, write_buf, write_size);
1065 write_count += write_size;
1066
1067 zstream.next_out = write_buf;
1068 zstream.avail_out = kBufSize;
1069 }
1070 } while (zerr == Z_OK);
1071
1072 assert(zerr == Z_STREAM_END); /* other errors should've been caught */
1073
1074 // stream.adler holds the crc32 value for such streams.
1075 *crc_out = zstream.adler;
1076
1077 if (zstream.total_out != uncompressed_length || compressed_length != 0) {
Mark Salyzyn088bf902014-05-08 16:02:20 -07001078 ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
Narayan Kamath7462f022013-11-21 13:05:04 +00001079 zstream.total_out, uncompressed_length);
Dmitriy Ivanov1f741e52015-03-06 14:26:37 -08001080 return kInconsistentInformation;
Narayan Kamath7462f022013-11-21 13:05:04 +00001081 }
1082
Dmitriy Ivanov1f741e52015-03-06 14:26:37 -08001083 return 0;
Narayan Kamath7462f022013-11-21 13:05:04 +00001084}
1085
1086int32_t ExtractToMemory(ZipArchiveHandle handle,
1087 ZipEntry* entry, uint8_t* begin, uint32_t size) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -08001088 ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
Narayan Kamath7462f022013-11-21 13:05:04 +00001089 const uint16_t method = entry->method;
1090 off64_t data_offset = entry->offset;
1091
1092 if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -08001093 ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
Narayan Kamath7462f022013-11-21 13:05:04 +00001094 return kIoError;
1095 }
1096
1097 // this should default to kUnknownCompressionMethod.
1098 int32_t return_value = -1;
1099 uint64_t crc = 0;
1100 if (method == kCompressStored) {
1101 return_value = CopyFileToFile(archive->fd, begin, size, &crc);
1102 } else if (method == kCompressDeflated) {
1103 return_value = InflateToFile(archive->fd, entry, begin, size, &crc);
1104 }
1105
1106 if (!return_value && entry->has_data_descriptor) {
1107 return_value = UpdateEntryFromDataDescriptor(archive->fd, entry);
1108 if (return_value) {
1109 return return_value;
1110 }
1111 }
1112
1113 // TODO: Fix this check by passing the right flags to inflate2 so that
1114 // it calculates the CRC for us.
1115 if (entry->crc32 != crc && false) {
Mark Salyzyn088bf902014-05-08 16:02:20 -07001116 ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc);
Narayan Kamath7462f022013-11-21 13:05:04 +00001117 return kInconsistentInformation;
1118 }
1119
1120 return return_value;
1121}
1122
1123int32_t ExtractEntryToFile(ZipArchiveHandle handle,
1124 ZipEntry* entry, int fd) {
1125 const int32_t declared_length = entry->uncompressed_length;
1126
Narayan Kamath00a258c2013-12-13 16:06:19 +00001127 const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
1128 if (current_offset == -1) {
1129 ALOGW("Zip: unable to seek to current location on fd %d: %s", fd,
1130 strerror(errno));
Narayan Kamath7462f022013-11-21 13:05:04 +00001131 return kIoError;
1132 }
1133
Narayan Kamath00a258c2013-12-13 16:06:19 +00001134 int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
1135 if (result == -1) {
Mark Salyzyn99ef9912014-03-14 14:26:22 -07001136 ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -08001137 static_cast<int64_t>(declared_length + current_offset), strerror(errno));
Narayan Kamath00a258c2013-12-13 16:06:19 +00001138 return kIoError;
1139 }
1140
Narayan Kamath48953a12014-01-24 12:32:39 +00001141 // Don't attempt to map a region of length 0. We still need the
1142 // ftruncate() though, since the API guarantees that we will truncate
1143 // the file to the end of the uncompressed output.
1144 if (declared_length == 0) {
1145 return 0;
1146 }
1147
Dmitriy Ivanov4b67f832015-03-06 10:22:34 -08001148 android::FileMap map;
1149 if (!map.create(kTempMappingFileName, fd, current_offset, declared_length, false)) {
Narayan Kamatheaf98852013-12-11 14:51:51 +00001150 return kMmapFailed;
Narayan Kamath7462f022013-11-21 13:05:04 +00001151 }
1152
Narayan Kamatheaf98852013-12-11 14:51:51 +00001153 const int32_t error = ExtractToMemory(handle, entry,
Dmitriy Ivanov4b67f832015-03-06 10:22:34 -08001154 reinterpret_cast<uint8_t*>(map.getDataPtr()),
1155 map.getDataLength());
Narayan Kamath7462f022013-11-21 13:05:04 +00001156 return error;
1157}
1158
1159const char* ErrorCodeString(int32_t error_code) {
1160 if (error_code > kErrorMessageLowerBound && error_code < kErrorMessageUpperBound) {
1161 return kErrorMessages[error_code * -1];
1162 }
1163
1164 return kErrorMessages[0];
1165}
1166
1167int GetFileDescriptor(const ZipArchiveHandle handle) {
Dmitriy Ivanovf4cb8e22015-03-06 10:50:56 -08001168 return reinterpret_cast<ZipArchive*>(handle)->fd;
Narayan Kamath7462f022013-11-21 13:05:04 +00001169}
1170