1 /*
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 */
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include <memory>
31 #include <vector>
32
33 #include "base/file.h"
34 #include "base/macros.h" // TEMP_FAILURE_RETRY may or may not be in unistd
35 #include "base/memory.h"
36 #include "log/log.h"
37 #include "utils/Compat.h"
38 #include "utils/FileMap.h"
39 #include "zlib.h"
40
41 #include "entry_name_utils-inl.h"
42 #include "ziparchive/zip_archive.h"
43
44 using android::base::get_unaligned;
45
46 // This is for windows. If we don't open a file in binary mode, weird
47 // things will happen.
48 #ifndef O_BINARY
49 #define O_BINARY 0
50 #endif
51
52 // The "end of central directory" (EOCD) record. Each archive
53 // contains exactly once such record which appears at the end of
54 // the archive. It contains archive wide information like the
55 // number of entries in the archive and the offset to the central
56 // directory of the offset.
57 struct EocdRecord {
58 static const uint32_t kSignature = 0x06054b50;
59
60 // End of central directory signature, should always be
61 // |kSignature|.
62 uint32_t eocd_signature;
63 // The number of the current "disk", i.e, the "disk" that this
64 // central directory is on.
65 //
66 // This implementation assumes that each archive spans a single
67 // disk only. i.e, that disk_num == 1.
68 uint16_t disk_num;
69 // The disk where the central directory starts.
70 //
71 // This implementation assumes that each archive spans a single
72 // disk only. i.e, that cd_start_disk == 1.
73 uint16_t cd_start_disk;
74 // The number of central directory records on this disk.
75 //
76 // This implementation assumes that each archive spans a single
77 // disk only. i.e, that num_records_on_disk == num_records.
78 uint16_t num_records_on_disk;
79 // The total number of central directory records.
80 uint16_t num_records;
81 // The size of the central directory (in bytes).
82 uint32_t cd_size;
83 // The offset of the start of the central directory, relative
84 // to the start of the file.
85 uint32_t cd_start_offset;
86 // Length of the central directory comment.
87 uint16_t comment_length;
88 private:
89 EocdRecord() = default;
90 DISALLOW_COPY_AND_ASSIGN(EocdRecord);
91 } __attribute__((packed));
92
93 // 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.
99 struct CentralDirectoryRecord {
100 static const uint32_t kSignature = 0x02014b50;
101
102 // 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 CentralDirectoryRecord() = default;
144 DISALLOW_COPY_AND_ASSIGN(CentralDirectoryRecord);
145 } __attribute__((packed));
146
147 // The local file header for a given entry. This duplicates information
148 // present in the central directory of the archive. It is an error for
149 // the information here to be different from the central directory
150 // information for a given entry.
151 struct LocalFileHeader {
152 static const uint32_t kSignature = 0x04034b50;
153
154 // The local file header signature, must be |kSignature|.
155 uint32_t lfh_signature;
156 // Tool version. Ignored by this implementation.
157 uint16_t version_needed;
158 // The "general purpose bit flags" for this entry. The only
159 // flag value that we currently check for is the "data descriptor"
160 // flag.
161 uint16_t gpb_flags;
162 // The compression method for this entry, one of |kCompressStored|
163 // and |kCompressDeflated|.
164 uint16_t compression_method;
165 // The file modification time and date for this entry.
166 uint16_t last_mod_time;
167 uint16_t last_mod_date;
168 // The CRC-32 checksum for this entry.
169 uint32_t crc32;
170 // The compressed size (in bytes) of this entry.
171 uint32_t compressed_size;
172 // The uncompressed size (in bytes) of this entry.
173 uint32_t uncompressed_size;
174 // The length of the entry file name in bytes. The file name
175 // will appear immediately after this record.
176 uint16_t file_name_length;
177 // The length of the extra field info (in bytes). This data
178 // will appear immediately after the entry file name.
179 uint16_t extra_field_length;
180 private:
181 LocalFileHeader() = default;
182 DISALLOW_COPY_AND_ASSIGN(LocalFileHeader);
183 } __attribute__((packed));
184
185 struct DataDescriptor {
186 // The *optional* data descriptor start signature.
187 static const uint32_t kOptSignature = 0x08074b50;
188
189 // CRC-32 checksum of the entry.
190 uint32_t crc32;
191 // Compressed size of the entry.
192 uint32_t compressed_size;
193 // Uncompressed size of the entry.
194 uint32_t uncompressed_size;
195 private:
196 DataDescriptor() = default;
197 DISALLOW_COPY_AND_ASSIGN(DataDescriptor);
198 } __attribute__((packed));
199
200
201 static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
202
203 // The maximum size of a central directory or a file
204 // comment in bytes.
205 static const uint32_t kMaxCommentLen = 65535;
206
207 // The maximum number of bytes to scan backwards for the EOCD start.
208 static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
209
210 static const char* kErrorMessages[] = {
211 "Unknown return code.",
212 "Iteration ended",
213 "Zlib error",
214 "Invalid file",
215 "Invalid handle",
216 "Duplicate entries in archive",
217 "Empty archive",
218 "Entry not found",
219 "Invalid offset",
220 "Inconsistent information",
221 "Invalid entry name",
222 "I/O Error",
223 "File mapping failed"
224 };
225
226 static const int32_t kErrorMessageUpperBound = 0;
227
228 static const int32_t kIterationEnd = -1;
229
230 // We encountered a Zlib error when inflating a stream from this file.
231 // Usually indicates file corruption.
232 static const int32_t kZlibError = -2;
233
234 // The input file cannot be processed as a zip archive. Usually because
235 // it's too small, too large or does not have a valid signature.
236 static const int32_t kInvalidFile = -3;
237
238 // An invalid iteration / ziparchive handle was passed in as an input
239 // argument.
240 static const int32_t kInvalidHandle = -4;
241
242 // The zip archive contained two (or possibly more) entries with the same
243 // name.
244 static const int32_t kDuplicateEntry = -5;
245
246 // The zip archive contains no entries.
247 static const int32_t kEmptyArchive = -6;
248
249 // The specified entry was not found in the archive.
250 static const int32_t kEntryNotFound = -7;
251
252 // The zip archive contained an invalid local file header pointer.
253 static const int32_t kInvalidOffset = -8;
254
255 // The zip archive contained inconsistent entry information. This could
256 // be because the central directory & local file header did not agree, or
257 // if the actual uncompressed length or crc32 do not match their declared
258 // values.
259 static const int32_t kInconsistentInformation = -9;
260
261 // An invalid entry name was encountered.
262 static const int32_t kInvalidEntryName = -10;
263
264 // An I/O related system call (read, lseek, ftruncate, map) failed.
265 static const int32_t kIoError = -11;
266
267 // We were not able to mmap the central directory or entry contents.
268 static const int32_t kMmapFailed = -12;
269
270 static const int32_t kErrorMessageLowerBound = -13;
271
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 */
291 struct ZipArchive {
292 /* open Zip archive */
293 const int fd;
294 const bool close_file;
295
296 /* mapped central directory area */
297 off64_t directory_offset;
298 android::FileMap directory_map;
299
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;
311
ZipArchiveZipArchive312 ZipArchive(const int fd, bool assume_ownership) :
313 fd(fd),
314 close_file(assume_ownership),
315 directory_offset(0),
316 num_entries(0),
317 hash_table_size(0),
318 hash_table(NULL) {}
319
~ZipArchiveZipArchive320 ~ZipArchive() {
321 if (close_file && fd >= 0) {
322 close(fd);
323 }
324
325 free(hash_table);
326 }
327 };
328
329 /*
330 * Round up to the next highest power of 2.
331 *
332 * Found on http://graphics.stanford.edu/~seander/bithacks.html.
333 */
RoundUpPower2(uint32_t val)334 static uint32_t RoundUpPower2(uint32_t val) {
335 val--;
336 val |= val >> 1;
337 val |= val >> 2;
338 val |= val >> 4;
339 val |= val >> 8;
340 val |= val >> 16;
341 val++;
342
343 return val;
344 }
345
ComputeHash(const ZipEntryName & name)346 static uint32_t ComputeHash(const ZipEntryName& name) {
347 uint32_t hash = 0;
348 uint16_t len = name.name_length;
349 const uint8_t* str = name.name;
350
351 while (len--) {
352 hash = hash * 31 + *str++;
353 }
354
355 return hash;
356 }
357
358 /*
359 * Convert a ZipEntry to a hash table index, verifying that it's in a
360 * valid range.
361 */
EntryToIndex(const ZipEntryName * hash_table,const uint32_t hash_table_size,const ZipEntryName & name)362 static int64_t EntryToIndex(const ZipEntryName* hash_table,
363 const uint32_t hash_table_size,
364 const ZipEntryName& name) {
365 const uint32_t hash = ComputeHash(name);
366
367 // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
368 uint32_t ent = hash & (hash_table_size - 1);
369 while (hash_table[ent].name != NULL) {
370 if (hash_table[ent].name_length == name.name_length &&
371 memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
372 return ent;
373 }
374
375 ent = (ent + 1) & (hash_table_size - 1);
376 }
377
378 ALOGV("Zip: Unable to find entry %.*s", name.name_length, name.name);
379 return kEntryNotFound;
380 }
381
382 /*
383 * Add a new entry to the hash table.
384 */
AddToHash(ZipEntryName * hash_table,const uint64_t hash_table_size,const ZipEntryName & name)385 static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_size,
386 const ZipEntryName& name) {
387 const uint64_t hash = ComputeHash(name);
388 uint32_t ent = hash & (hash_table_size - 1);
389
390 /*
391 * We over-allocated the table, so we're guaranteed to find an empty slot.
392 * Further, we guarantee that the hashtable size is not 0.
393 */
394 while (hash_table[ent].name != NULL) {
395 if (hash_table[ent].name_length == name.name_length &&
396 memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
397 // We've found a duplicate entry. We don't accept it
398 ALOGW("Zip: Found duplicate entry %.*s", name.name_length, name.name);
399 return kDuplicateEntry;
400 }
401 ent = (ent + 1) & (hash_table_size - 1);
402 }
403
404 hash_table[ent].name = name.name;
405 hash_table[ent].name_length = name.name_length;
406 return 0;
407 }
408
MapCentralDirectory0(int fd,const char * debug_file_name,ZipArchive * archive,off64_t file_length,off64_t read_amount,uint8_t * scan_buffer)409 static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
410 ZipArchive* archive, off64_t file_length,
411 off64_t read_amount, uint8_t* scan_buffer) {
412 const off64_t search_start = file_length - read_amount;
413
414 if (lseek64(fd, search_start, SEEK_SET) != search_start) {
415 ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
416 strerror(errno));
417 return kIoError;
418 }
419 ssize_t actual = TEMP_FAILURE_RETRY(
420 read(fd, scan_buffer, static_cast<size_t>(read_amount)));
421 if (actual != static_cast<ssize_t>(read_amount)) {
422 ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
423 strerror(errno));
424 return kIoError;
425 }
426
427 /*
428 * Scan backward for the EOCD magic. In an archive without a trailing
429 * comment, we'll find it on the first try. (We may want to consider
430 * doing an initial minimal read; if we don't find it, retry with a
431 * second read as above.)
432 */
433 int i = read_amount - sizeof(EocdRecord);
434 for (; i >= 0; i--) {
435 if (scan_buffer[i] == 0x50) {
436 uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]);
437 if (get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) {
438 ALOGV("+++ Found EOCD at buf+%d", i);
439 break;
440 }
441 }
442 }
443 if (i < 0) {
444 ALOGD("Zip: EOCD not found, %s is not zip", debug_file_name);
445 return kInvalidFile;
446 }
447
448 const off64_t eocd_offset = search_start + i;
449 const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i);
450 /*
451 * Verify that there's no trailing space at the end of the central directory
452 * and its comment.
453 */
454 const off64_t calculated_length = eocd_offset + sizeof(EocdRecord)
455 + eocd->comment_length;
456 if (calculated_length != file_length) {
457 ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
458 static_cast<int64_t>(file_length - calculated_length));
459 return kInvalidFile;
460 }
461
462 /*
463 * Grab the CD offset and size, and the number of entries in the
464 * archive and verify that they look reasonable.
465 */
466 if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
467 ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
468 eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
469 return kInvalidOffset;
470 }
471 if (eocd->num_records == 0) {
472 ALOGW("Zip: empty archive?");
473 return kEmptyArchive;
474 }
475
476 ALOGV("+++ num_entries=%" PRIu32 "dir_size=%" PRIu32 " dir_offset=%" PRIu32,
477 eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
478
479 /*
480 * It all looks good. Create a mapping for the CD, and set the fields
481 * in archive.
482 */
483 if (!archive->directory_map.create(debug_file_name, fd,
484 static_cast<off64_t>(eocd->cd_start_offset),
485 static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
486 return kMmapFailed;
487 }
488
489 archive->num_entries = eocd->num_records;
490 archive->directory_offset = eocd->cd_start_offset;
491
492 return 0;
493 }
494
495 /*
496 * Find the zip Central Directory and memory-map it.
497 *
498 * On success, returns 0 after populating fields from the EOCD area:
499 * directory_offset
500 * directory_map
501 * num_entries
502 */
MapCentralDirectory(int fd,const char * debug_file_name,ZipArchive * archive)503 static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
504 ZipArchive* archive) {
505
506 // Test file length. We use lseek64 to make sure the file
507 // is small enough to be a zip file (Its size must be less than
508 // 0xffffffff bytes).
509 off64_t file_length = lseek64(fd, 0, SEEK_END);
510 if (file_length == -1) {
511 ALOGV("Zip: lseek on fd %d failed", fd);
512 return kInvalidFile;
513 }
514
515 if (file_length > static_cast<off64_t>(0xffffffff)) {
516 ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
517 return kInvalidFile;
518 }
519
520 if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) {
521 ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length));
522 return kInvalidFile;
523 }
524
525 /*
526 * Perform the traditional EOCD snipe hunt.
527 *
528 * We're searching for the End of Central Directory magic number,
529 * which appears at the start of the EOCD block. It's followed by
530 * 18 bytes of EOCD stuff and up to 64KB of archive comment. We
531 * need to read the last part of the file into a buffer, dig through
532 * it to find the magic number, parse some values out, and use those
533 * to determine the extent of the CD.
534 *
535 * We start by pulling in the last part of the file.
536 */
537 off64_t read_amount = kMaxEOCDSearch;
538 if (file_length < read_amount) {
539 read_amount = file_length;
540 }
541
542 uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
543 int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
544 file_length, read_amount, scan_buffer);
545
546 free(scan_buffer);
547 return result;
548 }
549
550 /*
551 * Parses the Zip archive's Central Directory. Allocates and populates the
552 * hash table.
553 *
554 * Returns 0 on success.
555 */
ParseZipArchive(ZipArchive * archive)556 static int32_t ParseZipArchive(ZipArchive* archive) {
557 const uint8_t* const cd_ptr =
558 reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
559 const size_t cd_length = archive->directory_map.getDataLength();
560 const uint16_t num_entries = archive->num_entries;
561
562 /*
563 * Create hash table. We have a minimum 75% load factor, possibly as
564 * low as 50% after we round off to a power of 2. There must be at
565 * least one unused entry to avoid an infinite loop during creation.
566 */
567 archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
568 archive->hash_table = reinterpret_cast<ZipEntryName*>(calloc(archive->hash_table_size,
569 sizeof(ZipEntryName)));
570
571 /*
572 * Walk through the central directory, adding entries to the hash
573 * table and verifying values.
574 */
575 const uint8_t* const cd_end = cd_ptr + cd_length;
576 const uint8_t* ptr = cd_ptr;
577 for (uint16_t i = 0; i < num_entries; i++) {
578 const CentralDirectoryRecord* cdr =
579 reinterpret_cast<const CentralDirectoryRecord*>(ptr);
580 if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
581 ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
582 return -1;
583 }
584
585 if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
586 ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
587 return -1;
588 }
589
590 const off64_t local_header_offset = cdr->local_file_header_offset;
591 if (local_header_offset >= archive->directory_offset) {
592 ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
593 static_cast<int64_t>(local_header_offset), i);
594 return -1;
595 }
596
597 const uint16_t file_name_length = cdr->file_name_length;
598 const uint16_t extra_length = cdr->extra_field_length;
599 const uint16_t comment_length = cdr->comment_length;
600 const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
601
602 /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
603 if (!IsValidEntryName(file_name, file_name_length)) {
604 return -1;
605 }
606
607 /* add the CDE filename to the hash table */
608 ZipEntryName entry_name;
609 entry_name.name = file_name;
610 entry_name.name_length = file_name_length;
611 const int add_result = AddToHash(archive->hash_table,
612 archive->hash_table_size, entry_name);
613 if (add_result != 0) {
614 ALOGW("Zip: Error adding entry to hash table %d", add_result);
615 return add_result;
616 }
617
618 ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
619 if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
620 ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
621 ptr - cd_ptr, cd_length, i);
622 return -1;
623 }
624 }
625 ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
626
627 return 0;
628 }
629
OpenArchiveInternal(ZipArchive * archive,const char * debug_file_name)630 static int32_t OpenArchiveInternal(ZipArchive* archive,
631 const char* debug_file_name) {
632 int32_t result = -1;
633 if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) {
634 return result;
635 }
636
637 if ((result = ParseZipArchive(archive))) {
638 return result;
639 }
640
641 return 0;
642 }
643
OpenArchiveFd(int fd,const char * debug_file_name,ZipArchiveHandle * handle,bool assume_ownership)644 int32_t OpenArchiveFd(int fd, const char* debug_file_name,
645 ZipArchiveHandle* handle, bool assume_ownership) {
646 ZipArchive* archive = new ZipArchive(fd, assume_ownership);
647 *handle = archive;
648 return OpenArchiveInternal(archive, debug_file_name);
649 }
650
OpenArchive(const char * fileName,ZipArchiveHandle * handle)651 int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
652 const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
653 ZipArchive* archive = new ZipArchive(fd, true);
654 *handle = archive;
655
656 if (fd < 0) {
657 ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
658 return kIoError;
659 }
660
661 return OpenArchiveInternal(archive, fileName);
662 }
663
664 /*
665 * Close a ZipArchive, closing the file and freeing the contents.
666 */
CloseArchive(ZipArchiveHandle handle)667 void CloseArchive(ZipArchiveHandle handle) {
668 ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
669 ALOGV("Closing archive %p", archive);
670 delete archive;
671 }
672
UpdateEntryFromDataDescriptor(int fd,ZipEntry * entry)673 static int32_t UpdateEntryFromDataDescriptor(int fd,
674 ZipEntry *entry) {
675 uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
676 ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf)));
677 if (actual != sizeof(ddBuf)) {
678 return kIoError;
679 }
680
681 const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
682 const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
683 const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
684
685 entry->crc32 = descriptor->crc32;
686 entry->compressed_length = descriptor->compressed_size;
687 entry->uncompressed_length = descriptor->uncompressed_size;
688
689 return 0;
690 }
691
692 // Attempts to read |len| bytes into |buf| at offset |off|.
693 //
694 // This method uses pread64 on platforms that support it and
695 // lseek64 + read on platforms that don't. This implies that
696 // callers should not rely on the |fd| offset being incremented
697 // as a side effect of this call.
ReadAtOffset(int fd,uint8_t * buf,size_t len,off64_t off)698 static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len,
699 off64_t off) {
700 #if !defined(_WIN32)
701 return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
702 #else
703 // The only supported platform that doesn't support pread at the moment
704 // is Windows. Only recent versions of windows support unix like forks,
705 // and even there the semantics are quite different.
706 if (lseek64(fd, off, SEEK_SET) != off) {
707 ALOGW("Zip: failed seek to offset %" PRId64, off);
708 return kIoError;
709 }
710
711 return TEMP_FAILURE_RETRY(read(fd, buf, len));
712 #endif
713 }
714
FindEntry(const ZipArchive * archive,const int ent,ZipEntry * data)715 static int32_t FindEntry(const ZipArchive* archive, const int ent,
716 ZipEntry* data) {
717 const uint16_t nameLen = archive->hash_table[ent].name_length;
718
719 // Recover the start of the central directory entry from the filename
720 // pointer. The filename is the first entry past the fixed-size data,
721 // so we can just subtract back from that.
722 const uint8_t* ptr = archive->hash_table[ent].name;
723 ptr -= sizeof(CentralDirectoryRecord);
724
725 // This is the base of our mmapped region, we have to sanity check that
726 // the name that's in the hash table is a pointer to a location within
727 // this mapped region.
728 const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
729 archive->directory_map.getDataPtr());
730 if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
731 ALOGW("Zip: Invalid entry pointer");
732 return kInvalidOffset;
733 }
734
735 const CentralDirectoryRecord *cdr =
736 reinterpret_cast<const CentralDirectoryRecord*>(ptr);
737
738 // The offset of the start of the central directory in the zipfile.
739 // We keep this lying around so that we can sanity check all our lengths
740 // and our per-file structures.
741 const off64_t cd_offset = archive->directory_offset;
742
743 // Fill out the compression method, modification time, crc32
744 // and other interesting attributes from the central directory. These
745 // will later be compared against values from the local file header.
746 data->method = cdr->compression_method;
747 data->mod_time = cdr->last_mod_time;
748 data->crc32 = cdr->crc32;
749 data->compressed_length = cdr->compressed_size;
750 data->uncompressed_length = cdr->uncompressed_size;
751
752 // Figure out the local header offset from the central directory. The
753 // actual file data will begin after the local header and the name /
754 // extra comments.
755 const off64_t local_header_offset = cdr->local_file_header_offset;
756 if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
757 ALOGW("Zip: bad local hdr offset in zip");
758 return kInvalidOffset;
759 }
760
761 uint8_t lfh_buf[sizeof(LocalFileHeader)];
762 ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
763 local_header_offset);
764 if (actual != sizeof(lfh_buf)) {
765 ALOGW("Zip: failed reading lfh name from offset %" PRId64,
766 static_cast<int64_t>(local_header_offset));
767 return kIoError;
768 }
769
770 const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
771
772 if (lfh->lfh_signature != LocalFileHeader::kSignature) {
773 ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
774 static_cast<int64_t>(local_header_offset));
775 return kInvalidOffset;
776 }
777
778 // Paranoia: Match the values specified in the local file header
779 // to those specified in the central directory.
780 if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
781 data->has_data_descriptor = 0;
782 if (data->compressed_length != lfh->compressed_size
783 || data->uncompressed_length != lfh->uncompressed_size
784 || data->crc32 != lfh->crc32) {
785 ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32
786 ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
787 data->compressed_length, data->uncompressed_length, data->crc32,
788 lfh->compressed_size, lfh->uncompressed_size, lfh->crc32);
789 return kInconsistentInformation;
790 }
791 } else {
792 data->has_data_descriptor = 1;
793 }
794
795 // Check that the local file header name matches the declared
796 // name in the central directory.
797 if (lfh->file_name_length == nameLen) {
798 const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
799 if (name_offset + lfh->file_name_length > cd_offset) {
800 ALOGW("Zip: Invalid declared length");
801 return kInvalidOffset;
802 }
803
804 uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
805 ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
806 name_offset);
807
808 if (actual != nameLen) {
809 ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
810 free(name_buf);
811 return kIoError;
812 }
813
814 if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
815 free(name_buf);
816 return kInconsistentInformation;
817 }
818
819 free(name_buf);
820 } else {
821 ALOGW("Zip: lfh name did not match central directory.");
822 return kInconsistentInformation;
823 }
824
825 const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
826 + lfh->file_name_length + lfh->extra_field_length;
827 if (data_offset > cd_offset) {
828 ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
829 return kInvalidOffset;
830 }
831
832 if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
833 ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
834 static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset));
835 return kInvalidOffset;
836 }
837
838 if (data->method == kCompressStored &&
839 static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
840 ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
841 static_cast<int64_t>(data_offset), data->uncompressed_length,
842 static_cast<int64_t>(cd_offset));
843 return kInvalidOffset;
844 }
845
846 data->offset = data_offset;
847 return 0;
848 }
849
850 struct IterationHandle {
851 uint32_t position;
852 // We're not using vector here because this code is used in the Windows SDK
853 // where the STL is not available.
854 const uint8_t* prefix;
855 const uint16_t prefix_len;
856 const uint8_t* suffix;
857 const uint16_t suffix_len;
858 ZipArchive* archive;
859
IterationHandleIterationHandle860 IterationHandle(const ZipEntryName* prefix_name,
861 const ZipEntryName* suffix_name)
862 : prefix(NULL),
863 prefix_len(prefix_name ? prefix_name->name_length : 0),
864 suffix(NULL),
865 suffix_len(suffix_name ? suffix_name->name_length : 0) {
866 if (prefix_name) {
867 uint8_t* prefix_copy = new uint8_t[prefix_len];
868 memcpy(prefix_copy, prefix_name->name, prefix_len);
869 prefix = prefix_copy;
870 }
871 if (suffix_name) {
872 uint8_t* suffix_copy = new uint8_t[suffix_len];
873 memcpy(suffix_copy, suffix_name->name, suffix_len);
874 suffix = suffix_copy;
875 }
876 }
877
~IterationHandleIterationHandle878 ~IterationHandle() {
879 delete[] prefix;
880 delete[] suffix;
881 }
882 };
883
StartIteration(ZipArchiveHandle handle,void ** cookie_ptr,const ZipEntryName * optional_prefix,const ZipEntryName * optional_suffix)884 int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
885 const ZipEntryName* optional_prefix,
886 const ZipEntryName* optional_suffix) {
887 ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
888
889 if (archive == NULL || archive->hash_table == NULL) {
890 ALOGW("Zip: Invalid ZipArchiveHandle");
891 return kInvalidHandle;
892 }
893
894 IterationHandle* cookie = new IterationHandle(optional_prefix, optional_suffix);
895 cookie->position = 0;
896 cookie->archive = archive;
897
898 *cookie_ptr = cookie ;
899 return 0;
900 }
901
EndIteration(void * cookie)902 void EndIteration(void* cookie) {
903 delete reinterpret_cast<IterationHandle*>(cookie);
904 }
905
FindEntry(const ZipArchiveHandle handle,const ZipEntryName & entryName,ZipEntry * data)906 int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
907 ZipEntry* data) {
908 const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
909 if (entryName.name_length == 0) {
910 ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
911 return kInvalidEntryName;
912 }
913
914 const int64_t ent = EntryToIndex(archive->hash_table,
915 archive->hash_table_size, entryName);
916
917 if (ent < 0) {
918 ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name);
919 return ent;
920 }
921
922 return FindEntry(archive, ent, data);
923 }
924
Next(void * cookie,ZipEntry * data,ZipEntryName * name)925 int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
926 IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
927 if (handle == NULL) {
928 return kInvalidHandle;
929 }
930
931 ZipArchive* archive = handle->archive;
932 if (archive == NULL || archive->hash_table == NULL) {
933 ALOGW("Zip: Invalid ZipArchiveHandle");
934 return kInvalidHandle;
935 }
936
937 const uint32_t currentOffset = handle->position;
938 const uint32_t hash_table_length = archive->hash_table_size;
939 const ZipEntryName *hash_table = archive->hash_table;
940
941 for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
942 if (hash_table[i].name != NULL &&
943 (handle->prefix_len == 0 ||
944 (hash_table[i].name_length >= handle->prefix_len &&
945 memcmp(handle->prefix, hash_table[i].name, handle->prefix_len) == 0)) &&
946 (handle->suffix_len == 0 ||
947 (hash_table[i].name_length >= handle->suffix_len &&
948 memcmp(handle->suffix,
949 hash_table[i].name + hash_table[i].name_length - handle->suffix_len,
950 handle->suffix_len) == 0))) {
951 handle->position = (i + 1);
952 const int error = FindEntry(archive, i, data);
953 if (!error) {
954 name->name = hash_table[i].name;
955 name->name_length = hash_table[i].name_length;
956 }
957
958 return error;
959 }
960 }
961
962 handle->position = 0;
963 return kIterationEnd;
964 }
965
966 class Writer {
967 public:
968 virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
~Writer()969 virtual ~Writer() {}
970 protected:
971 Writer() = default;
972 private:
973 DISALLOW_COPY_AND_ASSIGN(Writer);
974 };
975
976 // A Writer that writes data to a fixed size memory region.
977 // The size of the memory region must be equal to the total size of
978 // the data appended to it.
979 class MemoryWriter : public Writer {
980 public:
MemoryWriter(uint8_t * buf,size_t size)981 MemoryWriter(uint8_t* buf, size_t size) : Writer(),
982 buf_(buf), size_(size), bytes_written_(0) {
983 }
984
Append(uint8_t * buf,size_t buf_size)985 virtual bool Append(uint8_t* buf, size_t buf_size) override {
986 if (bytes_written_ + buf_size > size_) {
987 ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
988 size_, bytes_written_ + buf_size);
989 return false;
990 }
991
992 memcpy(buf_ + bytes_written_, buf, buf_size);
993 bytes_written_ += buf_size;
994 return true;
995 }
996
997 private:
998 uint8_t* const buf_;
999 const size_t size_;
1000 size_t bytes_written_;
1001 };
1002
1003 // A Writer that appends data to a file |fd| at its current position.
1004 // The file will be truncated to the end of the written data.
1005 class FileWriter : public Writer {
1006 public:
1007
1008 // Creates a FileWriter for |fd| and prepare to write |entry| to it,
1009 // guaranteeing that the file descriptor is valid and that there's enough
1010 // space on the volume to write out the entry completely and that the file
1011 // is truncated to the correct length.
1012 //
1013 // Returns a valid FileWriter on success, |nullptr| if an error occurred.
Create(int fd,const ZipEntry * entry)1014 static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
1015 const uint32_t declared_length = entry->uncompressed_length;
1016 const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
1017 if (current_offset == -1) {
1018 ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno));
1019 return nullptr;
1020 }
1021
1022 int result = 0;
1023 #if defined(__linux__)
1024 if (declared_length > 0) {
1025 // Make sure we have enough space on the volume to extract the compressed
1026 // entry. Note that the call to ftruncate below will change the file size but
1027 // will not allocate space on disk and this call to fallocate will not
1028 // change the file size.
1029 // Note: fallocate is only supported by the following filesystems -
1030 // btrfs, ext4, ocfs2, and xfs. Therefore fallocate might fail with
1031 // EOPNOTSUPP error when issued in other filesystems.
1032 // Hence, check for the return error code before concluding that the
1033 // disk does not have enough space.
1034 result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
1035 if (result == -1 && errno == ENOSPC) {
1036 ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
1037 static_cast<int64_t>(declared_length + current_offset), strerror(errno));
1038 return std::unique_ptr<FileWriter>(nullptr);
1039 }
1040 }
1041 #endif // __linux__
1042
1043 result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
1044 if (result == -1) {
1045 ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
1046 static_cast<int64_t>(declared_length + current_offset), strerror(errno));
1047 return std::unique_ptr<FileWriter>(nullptr);
1048 }
1049
1050 return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
1051 }
1052
Append(uint8_t * buf,size_t buf_size)1053 virtual bool Append(uint8_t* buf, size_t buf_size) override {
1054 if (total_bytes_written_ + buf_size > declared_length_) {
1055 ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
1056 declared_length_, total_bytes_written_ + buf_size);
1057 return false;
1058 }
1059
1060 const bool result = android::base::WriteFully(fd_, buf, buf_size);
1061 if (result) {
1062 total_bytes_written_ += buf_size;
1063 } else {
1064 ALOGW("Zip: unable to write " ZD " bytes to file; %s", buf_size, strerror(errno));
1065 }
1066
1067 return result;
1068 }
1069 private:
FileWriter(const int fd,const size_t declared_length)1070 FileWriter(const int fd, const size_t declared_length) :
1071 Writer(),
1072 fd_(fd),
1073 declared_length_(declared_length),
1074 total_bytes_written_(0) {
1075 }
1076
1077 const int fd_;
1078 const size_t declared_length_;
1079 size_t total_bytes_written_;
1080 };
1081
1082 // This method is using libz macros with old-style-casts
1083 #pragma GCC diagnostic push
1084 #pragma GCC diagnostic ignored "-Wold-style-cast"
zlib_inflateInit2(z_stream * stream,int window_bits)1085 static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
1086 return inflateInit2(stream, window_bits);
1087 }
1088 #pragma GCC diagnostic pop
1089
InflateEntryToWriter(int fd,const ZipEntry * entry,Writer * writer,uint64_t * crc_out)1090 static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
1091 Writer* writer, uint64_t* crc_out) {
1092 const size_t kBufSize = 32768;
1093 std::vector<uint8_t> read_buf(kBufSize);
1094 std::vector<uint8_t> write_buf(kBufSize);
1095 z_stream zstream;
1096 int zerr;
1097
1098 /*
1099 * Initialize the zlib stream struct.
1100 */
1101 memset(&zstream, 0, sizeof(zstream));
1102 zstream.zalloc = Z_NULL;
1103 zstream.zfree = Z_NULL;
1104 zstream.opaque = Z_NULL;
1105 zstream.next_in = NULL;
1106 zstream.avail_in = 0;
1107 zstream.next_out = &write_buf[0];
1108 zstream.avail_out = kBufSize;
1109 zstream.data_type = Z_UNKNOWN;
1110
1111 /*
1112 * Use the undocumented "negative window bits" feature to tell zlib
1113 * that there's no zlib header waiting for it.
1114 */
1115 zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
1116 if (zerr != Z_OK) {
1117 if (zerr == Z_VERSION_ERROR) {
1118 ALOGE("Installed zlib is not compatible with linked version (%s)",
1119 ZLIB_VERSION);
1120 } else {
1121 ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr);
1122 }
1123
1124 return kZlibError;
1125 }
1126
1127 auto zstream_deleter = [](z_stream* stream) {
1128 inflateEnd(stream); /* free up any allocated structures */
1129 };
1130
1131 std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
1132
1133 const uint32_t uncompressed_length = entry->uncompressed_length;
1134
1135 uint32_t compressed_length = entry->compressed_length;
1136 do {
1137 /* read as much as we can */
1138 if (zstream.avail_in == 0) {
1139 const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
1140 const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, &read_buf[0], getSize));
1141 if (actual != getSize) {
1142 ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
1143 return kIoError;
1144 }
1145
1146 compressed_length -= getSize;
1147
1148 zstream.next_in = &read_buf[0];
1149 zstream.avail_in = getSize;
1150 }
1151
1152 /* uncompress the data */
1153 zerr = inflate(&zstream, Z_NO_FLUSH);
1154 if (zerr != Z_OK && zerr != Z_STREAM_END) {
1155 ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
1156 zerr, zstream.next_in, zstream.avail_in,
1157 zstream.next_out, zstream.avail_out);
1158 return kZlibError;
1159 }
1160
1161 /* write when we're full or when we're done */
1162 if (zstream.avail_out == 0 ||
1163 (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
1164 const size_t write_size = zstream.next_out - &write_buf[0];
1165 if (!writer->Append(&write_buf[0], write_size)) {
1166 // The file might have declared a bogus length.
1167 return kInconsistentInformation;
1168 }
1169
1170 zstream.next_out = &write_buf[0];
1171 zstream.avail_out = kBufSize;
1172 }
1173 } while (zerr == Z_OK);
1174
1175 assert(zerr == Z_STREAM_END); /* other errors should've been caught */
1176
1177 // stream.adler holds the crc32 value for such streams.
1178 *crc_out = zstream.adler;
1179
1180 if (zstream.total_out != uncompressed_length || compressed_length != 0) {
1181 ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
1182 zstream.total_out, uncompressed_length);
1183 return kInconsistentInformation;
1184 }
1185
1186 return 0;
1187 }
1188
CopyEntryToWriter(int fd,const ZipEntry * entry,Writer * writer,uint64_t * crc_out)1189 static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
1190 uint64_t *crc_out) {
1191 static const uint32_t kBufSize = 32768;
1192 std::vector<uint8_t> buf(kBufSize);
1193
1194 const uint32_t length = entry->uncompressed_length;
1195 uint32_t count = 0;
1196 uint64_t crc = 0;
1197 while (count < length) {
1198 uint32_t remaining = length - count;
1199
1200 // Safe conversion because kBufSize is narrow enough for a 32 bit signed
1201 // value.
1202 const ssize_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
1203 const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, &buf[0], block_size));
1204
1205 if (actual != block_size) {
1206 ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, block_size);
1207 return kIoError;
1208 }
1209
1210 if (!writer->Append(&buf[0], block_size)) {
1211 return kIoError;
1212 }
1213 crc = crc32(crc, &buf[0], block_size);
1214 count += block_size;
1215 }
1216
1217 *crc_out = crc;
1218
1219 return 0;
1220 }
1221
ExtractToWriter(ZipArchiveHandle handle,ZipEntry * entry,Writer * writer)1222 int32_t ExtractToWriter(ZipArchiveHandle handle,
1223 ZipEntry* entry, Writer* writer) {
1224 ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
1225 const uint16_t method = entry->method;
1226 off64_t data_offset = entry->offset;
1227
1228 if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
1229 ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
1230 return kIoError;
1231 }
1232
1233 // this should default to kUnknownCompressionMethod.
1234 int32_t return_value = -1;
1235 uint64_t crc = 0;
1236 if (method == kCompressStored) {
1237 return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
1238 } else if (method == kCompressDeflated) {
1239 return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
1240 }
1241
1242 if (!return_value && entry->has_data_descriptor) {
1243 return_value = UpdateEntryFromDataDescriptor(archive->fd, entry);
1244 if (return_value) {
1245 return return_value;
1246 }
1247 }
1248
1249 // TODO: Fix this check by passing the right flags to inflate2 so that
1250 // it calculates the CRC for us.
1251 if (entry->crc32 != crc && false) {
1252 ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc);
1253 return kInconsistentInformation;
1254 }
1255
1256 return return_value;
1257 }
1258
ExtractToMemory(ZipArchiveHandle handle,ZipEntry * entry,uint8_t * begin,uint32_t size)1259 int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry,
1260 uint8_t* begin, uint32_t size) {
1261 std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
1262 return ExtractToWriter(handle, entry, writer.get());
1263 }
1264
ExtractEntryToFile(ZipArchiveHandle handle,ZipEntry * entry,int fd)1265 int32_t ExtractEntryToFile(ZipArchiveHandle handle,
1266 ZipEntry* entry, int fd) {
1267 std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
1268 if (writer.get() == nullptr) {
1269 return kIoError;
1270 }
1271
1272 return ExtractToWriter(handle, entry, writer.get());
1273 }
1274
ErrorCodeString(int32_t error_code)1275 const char* ErrorCodeString(int32_t error_code) {
1276 if (error_code > kErrorMessageLowerBound && error_code < kErrorMessageUpperBound) {
1277 return kErrorMessages[error_code * -1];
1278 }
1279
1280 return kErrorMessages[0];
1281 }
1282
GetFileDescriptor(const ZipArchiveHandle handle)1283 int GetFileDescriptor(const ZipArchiveHandle handle) {
1284 return reinterpret_cast<ZipArchive*>(handle)->fd;
1285 }
1286