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