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