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