17462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath/* 27462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Copyright (C) 2008 The Android Open Source Project 37462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 47462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 57462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * you may not use this file except in compliance with the License. 67462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * You may obtain a copy of the License at 77462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 87462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 97462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 107462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Unless required by applicable law or agreed to in writing, software 117462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 127462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * See the License for the specific language governing permissions and 147462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * limitations under the License. 157462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 167462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 177462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath/* 187462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Read-only access to Zip archives, with minimal heap allocation. 197462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 207462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 21cfd5b080af8de527d768f0ff7902c26af8d49307Mark Salyzyn#define LOG_TAG "ziparchive" 22cfd5b080af8de527d768f0ff7902c26af8d49307Mark Salyzyn 237462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath#include <assert.h> 247462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath#include <errno.h> 2599ef9914be1e39276e2e077670368927a1221921Mark Salyzyn#include <fcntl.h> 2699ef9914be1e39276e2e077670368927a1221921Mark Salyzyn#include <inttypes.h> 277462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath#include <limits.h> 287462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath#include <stdlib.h> 297462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath#include <string.h> 307462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath#include <unistd.h> 317462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 321ae0764e01ac0ad15cc16395fc36809343755823Dan Albert#include <memory> 331ae0764e01ac0ad15cc16395fc36809343755823Dan Albert#include <vector> 341ae0764e01ac0ad15cc16395fc36809343755823Dan Albert 35ff2dcd9af994a23ed483939a416b48bdc10eefd5Mark Salyzyn#include <android-base/file.h> 36ff2dcd9af994a23ed483939a416b48bdc10eefd5Mark Salyzyn#include <android-base/logging.h> 37ff2dcd9af994a23ed483939a416b48bdc10eefd5Mark Salyzyn#include <android-base/macros.h> // TEMP_FAILURE_RETRY may or may not be in unistd 38ff2dcd9af994a23ed483939a416b48bdc10eefd5Mark Salyzyn#include <android-base/memory.h> 39cfd5b080af8de527d768f0ff7902c26af8d49307Mark Salyzyn#include <log/log.h> 40ff2dcd9af994a23ed483939a416b48bdc10eefd5Mark Salyzyn#include <utils/Compat.h> 41ff2dcd9af994a23ed483939a416b48bdc10eefd5Mark Salyzyn#include <utils/FileMap.h> 42e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include "ziparchive/zip_archive.h" 431ae0764e01ac0ad15cc16395fc36809343755823Dan Albert#include "zlib.h" 447462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 45044bc8ee89462206dbf5f33c0573834ee507c955Narayan Kamath#include "entry_name_utils-inl.h" 46ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski#include "zip_archive_common.h" 47e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include "zip_archive_private.h" 4899ef9914be1e39276e2e077670368927a1221921Mark Salyzyn 491ae0764e01ac0ad15cc16395fc36809343755823Dan Albertusing android::base::get_unaligned; 50044bc8ee89462206dbf5f33c0573834ee507c955Narayan Kamath 51926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath// This is for windows. If we don't open a file in binary mode, weird 527462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// things will happen. 537462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath#ifndef O_BINARY 547462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath#define O_BINARY 0 557462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath#endif 567462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 57926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath// The maximum number of bytes to scan backwards for the EOCD start. 58926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamathstatic const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord); 59926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath 607462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const char* kErrorMessages[] = { 617462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Unknown return code.", 62eb41ad212e125aa81f09df850e0c41e11ba96043Narayan Kamath "Iteration ended", 637462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Zlib error", 647462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Invalid file", 657462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Invalid handle", 667462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Duplicate entries in archive", 677462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Empty archive", 687462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Entry not found", 697462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Invalid offset", 707462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Inconsistent information", 717462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath "Invalid entry name", 72eb41ad212e125aa81f09df850e0c41e11ba96043Narayan Kamath "I/O Error", 73eaf988532b9e603b1599b7750bfa923fbb39d297Narayan Kamath "File mapping failed" 747462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath}; 757462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 767462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kErrorMessageUpperBound = 0; 777462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 78eb41ad212e125aa81f09df850e0c41e11ba96043Narayan Kamathstatic const int32_t kIterationEnd = -1; 797462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 807462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// We encountered a Zlib error when inflating a stream from this file. 817462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// Usually indicates file corruption. 827462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kZlibError = -2; 837462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 847462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// The input file cannot be processed as a zip archive. Usually because 857462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// it's too small, too large or does not have a valid signature. 867462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kInvalidFile = -3; 877462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 887462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// An invalid iteration / ziparchive handle was passed in as an input 897462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// argument. 907462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kInvalidHandle = -4; 917462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 927462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// The zip archive contained two (or possibly more) entries with the same 937462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// name. 947462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kDuplicateEntry = -5; 957462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 967462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// The zip archive contains no entries. 977462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kEmptyArchive = -6; 987462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 997462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// The specified entry was not found in the archive. 1007462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kEntryNotFound = -7; 1017462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1027462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// The zip archive contained an invalid local file header pointer. 1037462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kInvalidOffset = -8; 1047462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1057462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// The zip archive contained inconsistent entry information. This could 1067462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// be because the central directory & local file header did not agree, or 1077462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// if the actual uncompressed length or crc32 do not match their declared 1087462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// values. 1097462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kInconsistentInformation = -9; 1107462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1117462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath// An invalid entry name was encountered. 1127462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic const int32_t kInvalidEntryName = -10; 1137462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 114eb41ad212e125aa81f09df850e0c41e11ba96043Narayan Kamath// An I/O related system call (read, lseek, ftruncate, map) failed. 115eb41ad212e125aa81f09df850e0c41e11ba96043Narayan Kamathstatic const int32_t kIoError = -11; 1167462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 117eaf988532b9e603b1599b7750bfa923fbb39d297Narayan Kamath// We were not able to mmap the central directory or entry contents. 118eaf988532b9e603b1599b7750bfa923fbb39d297Narayan Kamathstatic const int32_t kMmapFailed = -12; 1197462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 120eaf988532b9e603b1599b7750bfa923fbb39d297Narayan Kamathstatic const int32_t kErrorMessageLowerBound = -13; 1217462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1227462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath/* 1237462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * A Read-only Zip archive. 1247462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 1257462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * We want "open" and "find entry by name" to be fast operations, and 1267462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * we want to use as little memory as possible. We memory-map the zip 1277462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * central directory, and load a hash table with pointers to the filenames 1287462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * (which aren't null-terminated). The other fields are at a fixed offset 1297462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * from the filename, so we don't need to extract those (but we do need 1307462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * to byte-read and endian-swap them every time we want them). 1317462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 1327462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * It's possible that somebody has handed us a massive (~1GB) zip archive, 1337462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * so we can't expect to mmap the entire file. 1347462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 1357462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * To speed comparisons when doing a lookup by name, we could make the mapping 1367462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * "private" (copy-on-write) and null-terminate the filenames after verifying 1377462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * the record structure. However, this requires a private mapping of 1387462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * every page that the Central Directory touches. Easier to tuck a copy 1397462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * of the string length into the hash table entry. 1407462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 1417462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1427462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath/* 1437462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Round up to the next highest power of 2. 1447462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 1457462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Found on http://graphics.stanford.edu/~seander/bithacks.html. 1467462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 1477462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic uint32_t RoundUpPower2(uint32_t val) { 1487462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath val--; 1497462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath val |= val >> 1; 1507462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath val |= val >> 2; 1517462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath val |= val >> 4; 1527462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath val |= val >> 8; 1537462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath val |= val >> 16; 1547462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath val++; 1557462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1567462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return val; 1577462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 1587462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 15907447544adbde8f688806b43f47c182eaeda4bb3Yusuke Satostatic uint32_t ComputeHash(const ZipString& name) { 1607462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath uint32_t hash = 0; 161ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski uint16_t len = name.name_length; 162ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski const uint8_t* str = name.name; 1637462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1647462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath while (len--) { 1657462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath hash = hash * 31 + *str++; 1667462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 1677462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1687462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return hash; 1697462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 1707462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1717462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath/* 1727462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Convert a ZipEntry to a hash table index, verifying that it's in a 1737462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * valid range. 1747462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 17507447544adbde8f688806b43f47c182eaeda4bb3Yusuke Satostatic int64_t EntryToIndex(const ZipString* hash_table, 1767462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const uint32_t hash_table_size, 17707447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato const ZipString& name) { 178ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski const uint32_t hash = ComputeHash(name); 1797462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1807462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // NOTE: (hash_table_size - 1) is guaranteed to be non-negative. 1817462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath uint32_t ent = hash & (hash_table_size - 1); 1827462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath while (hash_table[ent].name != NULL) { 18307447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato if (hash_table[ent] == name) { 1847462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return ent; 1857462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 1867462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1877462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ent = (ent + 1) & (hash_table_size - 1); 1887462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 1897462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 190ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski ALOGV("Zip: Unable to find entry %.*s", name.name_length, name.name); 1917462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kEntryNotFound; 1927462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 1937462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1947462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath/* 1957462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Add a new entry to the hash table. 1967462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 19707447544adbde8f688806b43f47c182eaeda4bb3Yusuke Satostatic int32_t AddToHash(ZipString *hash_table, const uint64_t hash_table_size, 19807447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato const ZipString& name) { 199ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski const uint64_t hash = ComputeHash(name); 2007462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath uint32_t ent = hash & (hash_table_size - 1); 2017462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 2027462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* 2037462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * We over-allocated the table, so we're guaranteed to find an empty slot. 2047462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Further, we guarantee that the hashtable size is not 0. 2057462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 2067462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath while (hash_table[ent].name != NULL) { 20707447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato if (hash_table[ent] == name) { 2087462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // We've found a duplicate entry. We don't accept it 209ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski ALOGW("Zip: Found duplicate entry %.*s", name.name_length, name.name); 2107462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kDuplicateEntry; 2117462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 2127462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ent = (ent + 1) & (hash_table_size - 1); 2137462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 2147462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 215ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski hash_table[ent].name = name.name; 216ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski hash_table[ent].name_length = name.name_length; 2177462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return 0; 2187462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 2197462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 22018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xustatic int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive, 22118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu off64_t file_length, off64_t read_amount, 22218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu uint8_t* scan_buffer) { 2237462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const off64_t search_start = file_length - read_amount; 2247462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 22518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if(!archive->mapped_zip.ReadAtOffset(scan_buffer, read_amount, search_start)) { 22618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: read %" PRId64 " from offset %" PRId64 " failed", 22718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu static_cast<int64_t>(read_amount), static_cast<int64_t>(search_start)); 2287462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kIoError; 2297462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 2307462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 2317462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* 2327462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Scan backward for the EOCD magic. In an archive without a trailing 2337462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * comment, we'll find it on the first try. (We may want to consider 2347462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * doing an initial minimal read; if we don't find it, retry with a 2357462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * second read as above.) 2367462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 237926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath int i = read_amount - sizeof(EocdRecord); 238926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath for (; i >= 0; i--) { 2391ae0764e01ac0ad15cc16395fc36809343755823Dan Albert if (scan_buffer[i] == 0x50) { 2401ae0764e01ac0ad15cc16395fc36809343755823Dan Albert uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]); 2411ae0764e01ac0ad15cc16395fc36809343755823Dan Albert if (get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) { 2421ae0764e01ac0ad15cc16395fc36809343755823Dan Albert ALOGV("+++ Found EOCD at buf+%d", i); 2431ae0764e01ac0ad15cc16395fc36809343755823Dan Albert break; 2441ae0764e01ac0ad15cc16395fc36809343755823Dan Albert } 2457462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 2467462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 2477462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (i < 0) { 2487462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGD("Zip: EOCD not found, %s is not zip", debug_file_name); 2497462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidFile; 2507462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 2517462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 2527462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const off64_t eocd_offset = search_start + i; 253926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i); 2547462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* 255926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath * Verify that there's no trailing space at the end of the central directory 256926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath * and its comment. 2577462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 258926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const off64_t calculated_length = eocd_offset + sizeof(EocdRecord) 259926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath + eocd->comment_length; 260926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if (calculated_length != file_length) { 2614f6b499ead3de87888d37a74adceaec92c584c0aNarayan Kamath ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory", 262926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath static_cast<int64_t>(file_length - calculated_length)); 2634f6b499ead3de87888d37a74adceaec92c584c0aNarayan Kamath return kInvalidFile; 2644f6b499ead3de87888d37a74adceaec92c584c0aNarayan Kamath } 2657462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 266926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath /* 267926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath * Grab the CD offset and size, and the number of entries in the 268926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath * archive and verify that they look reasonable. 269926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath */ 270ae8180c06dee228cd1378c56afa6020ae98d8a24Tianjie Xu if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) { 271926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")", 272926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset)); 273ae8180c06dee228cd1378c56afa6020ae98d8a24Tianjie Xu#if defined(__ANDROID__) 274ae8180c06dee228cd1378c56afa6020ae98d8a24Tianjie Xu if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) { 275ae8180c06dee228cd1378c56afa6020ae98d8a24Tianjie Xu android_errorWriteLog(0x534e4554, "31251826"); 276ae8180c06dee228cd1378c56afa6020ae98d8a24Tianjie Xu } 277ae8180c06dee228cd1378c56afa6020ae98d8a24Tianjie Xu#endif 2787462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidOffset; 2797462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 280926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if (eocd->num_records == 0) { 2817462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Zip: empty archive?"); 2827462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kEmptyArchive; 2837462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 2847462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 285e49236b3dae364532c07265d62abc9abd7ea6935Elliott Hughes ALOGV("+++ num_entries=%" PRIu32 " dir_size=%" PRIu32 " dir_offset=%" PRIu32, 286926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath eocd->num_records, eocd->cd_size, eocd->cd_start_offset); 2877462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 2887462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* 2897462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * It all looks good. Create a mapping for the CD, and set the fields 2907462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * in archive. 2917462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 29218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 29318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!archive->InitializeCentralDirectory(debug_file_name, 29418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu static_cast<off64_t>(eocd->cd_start_offset), 29518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu static_cast<size_t>(eocd->cd_size))) { 29618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: failed to intialize central directory.\n"); 297eaf988532b9e603b1599b7750bfa923fbb39d297Narayan Kamath return kMmapFailed; 2987462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 2997462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 300926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath archive->num_entries = eocd->num_records; 301926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath archive->directory_offset = eocd->cd_start_offset; 3027462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 3037462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return 0; 3047462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 3057462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 3067462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath/* 3077462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Find the zip Central Directory and memory-map it. 3087462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 3097462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * On success, returns 0 after populating fields from the EOCD area: 3107462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * directory_offset 31118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu * directory_ptr 3127462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * num_entries 3137462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 31418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xustatic int32_t MapCentralDirectory(const char* debug_file_name, ZipArchive* archive) { 3157462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 3167462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // Test file length. We use lseek64 to make sure the file 3177462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // is small enough to be a zip file (Its size must be less than 3187462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // 0xffffffff bytes). 31918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu off64_t file_length = archive->mapped_zip.GetFileLength(); 3207462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (file_length == -1) { 3217462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidFile; 3227462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 3237462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 324f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov if (file_length > static_cast<off64_t>(0xffffffff)) { 325926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length)); 3267462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidFile; 3277462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 3287462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 329926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) { 330926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length)); 3317462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidFile; 3327462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 3337462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 3347462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* 3357462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Perform the traditional EOCD snipe hunt. 3367462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 3377462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * We're searching for the End of Central Directory magic number, 3387462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * which appears at the start of the EOCD block. It's followed by 3397462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 18 bytes of EOCD stuff and up to 64KB of archive comment. We 3407462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * need to read the last part of the file into a buffer, dig through 3417462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * it to find the magic number, parse some values out, and use those 3427462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * to determine the extent of the CD. 3437462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 3447462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * We start by pulling in the last part of the file. 3457462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 346926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath off64_t read_amount = kMaxEOCDSearch; 347926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if (file_length < read_amount) { 3487462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath read_amount = file_length; 3497462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 3507462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 35118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu std::vector<uint8_t> scan_buffer(read_amount); 35218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu int32_t result = MapCentralDirectory0(debug_file_name, archive, file_length, read_amount, 35318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu scan_buffer.data()); 3547462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return result; 3557462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 3567462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 3577462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath/* 3587462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Parses the Zip archive's Central Directory. Allocates and populates the 3597462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * hash table. 3607462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * 3617462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Returns 0 on success. 3627462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 3637462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic int32_t ParseZipArchive(ZipArchive* archive) { 36418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu const uint8_t* const cd_ptr = archive->central_directory.GetBasePtr(); 36518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu const size_t cd_length = archive->central_directory.GetMapLength(); 366926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const uint16_t num_entries = archive->num_entries; 3677462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 3687462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* 3697462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Create hash table. We have a minimum 75% load factor, possibly as 3707462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * low as 50% after we round off to a power of 2. There must be at 3717462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * least one unused entry to avoid an infinite loop during creation. 3727462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 3737462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3); 37407447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato archive->hash_table = reinterpret_cast<ZipString*>(calloc(archive->hash_table_size, 37507447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato sizeof(ZipString))); 376bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu if (archive->hash_table == nullptr) { 377bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu ALOGW("Zip: unable to allocate the %u-entry hash_table, entry size: %zu", 378bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu archive->hash_table_size, sizeof(ZipString)); 379bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu return -1; 380bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu } 3817462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 3827462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* 3837462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Walk through the central directory, adding entries to the hash 3847462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * table and verifying values. 3857462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 386926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const uint8_t* const cd_end = cd_ptr + cd_length; 3877462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const uint8_t* ptr = cd_ptr; 3887462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath for (uint16_t i = 0; i < num_entries; i++) { 389d9fd1863f46d5185eaaebc0803ee9c5da3ef110bTianjie Xu if (ptr > cd_end - sizeof(CentralDirectoryRecord)) { 390d9fd1863f46d5185eaaebc0803ee9c5da3ef110bTianjie Xu ALOGW("Zip: ran off the end (at %" PRIu16 ")", i); 391d9fd1863f46d5185eaaebc0803ee9c5da3ef110bTianjie Xu#if defined(__ANDROID__) 392d9fd1863f46d5185eaaebc0803ee9c5da3ef110bTianjie Xu android_errorWriteLog(0x534e4554, "36392138"); 393d9fd1863f46d5185eaaebc0803ee9c5da3ef110bTianjie Xu#endif 394d9fd1863f46d5185eaaebc0803ee9c5da3ef110bTianjie Xu return -1; 395d9fd1863f46d5185eaaebc0803ee9c5da3ef110bTianjie Xu } 396d9fd1863f46d5185eaaebc0803ee9c5da3ef110bTianjie Xu 397926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const CentralDirectoryRecord* cdr = 398926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath reinterpret_cast<const CentralDirectoryRecord*>(ptr); 399926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if (cdr->record_signature != CentralDirectoryRecord::kSignature) { 400088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i); 4013ea93da3c21c9f35d658f4760064a404fce3b43bDmitriy Ivanov return -1; 4027462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 4037462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 404926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const off64_t local_header_offset = cdr->local_file_header_offset; 4057462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (local_header_offset >= archive->directory_offset) { 406f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, 407f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov static_cast<int64_t>(local_header_offset), i); 4083ea93da3c21c9f35d658f4760064a404fce3b43bDmitriy Ivanov return -1; 4097462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 4107462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 411926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const uint16_t file_name_length = cdr->file_name_length; 412926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const uint16_t extra_length = cdr->extra_field_length; 413926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const uint16_t comment_length = cdr->comment_length; 41478271ba97b5d867e3597b7fc2257dd1bbd513b05Piotr Jastrzebski const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord); 41578271ba97b5d867e3597b7fc2257dd1bbd513b05Piotr Jastrzebski 416bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu if (file_name + file_name_length > cd_end) { 417bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu ALOGW("Zip: file name boundary exceeds the central directory range, file_name_length: " 418bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu "%" PRIx16 ", cd_length: %zu", file_name_length, cd_length); 419bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu return -1; 420bcc4431f240d1ee5bc89c6ab41542e096e07c48cTianjie Xu } 421044bc8ee89462206dbf5f33c0573834ee507c955Narayan Kamath /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */ 422044bc8ee89462206dbf5f33c0573834ee507c955Narayan Kamath if (!IsValidEntryName(file_name, file_name_length)) { 4233ea93da3c21c9f35d658f4760064a404fce3b43bDmitriy Ivanov return -1; 42478271ba97b5d867e3597b7fc2257dd1bbd513b05Piotr Jastrzebski } 4257462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 4267462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* add the CDE filename to the hash table */ 42707447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato ZipString entry_name; 428ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski entry_name.name = file_name; 429ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski entry_name.name_length = file_name_length; 4307462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const int add_result = AddToHash(archive->hash_table, 431ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski archive->hash_table_size, entry_name); 4323ea93da3c21c9f35d658f4760064a404fce3b43bDmitriy Ivanov if (add_result != 0) { 4337462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Zip: Error adding entry to hash table %d", add_result); 4343ea93da3c21c9f35d658f4760064a404fce3b43bDmitriy Ivanov return add_result; 4357462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 4367462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 437926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length; 438926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) { 439088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16, 440088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ptr - cd_ptr, cd_length, i); 4413ea93da3c21c9f35d658f4760064a404fce3b43bDmitriy Ivanov return -1; 4427462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 4437462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 444088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries); 4457462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 4463ea93da3c21c9f35d658f4760064a404fce3b43bDmitriy Ivanov return 0; 4477462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 4487462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 4497462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic int32_t OpenArchiveInternal(ZipArchive* archive, 4507462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const char* debug_file_name) { 4517462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath int32_t result = -1; 45218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if ((result = MapCentralDirectory(debug_file_name, archive)) != 0) { 4537462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return result; 4547462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 4557462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 4567462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if ((result = ParseZipArchive(archive))) { 4577462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return result; 4587462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 4597462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 4607462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return 0; 4617462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 4627462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 4637462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathint32_t OpenArchiveFd(int fd, const char* debug_file_name, 46440b52b2c884e2a0abf9c4af8b785433286b7e84bDmitriy Ivanov ZipArchiveHandle* handle, bool assume_ownership) { 46540b52b2c884e2a0abf9c4af8b785433286b7e84bDmitriy Ivanov ZipArchive* archive = new ZipArchive(fd, assume_ownership); 4667462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath *handle = archive; 4677462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return OpenArchiveInternal(archive, debug_file_name); 4687462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 4697462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 4707462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathint32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) { 471b1a113f618561b274ab793e6401416d449c60449Neil Fuller const int fd = open(fileName, O_RDONLY | O_BINARY, 0); 47240b52b2c884e2a0abf9c4af8b785433286b7e84bDmitriy Ivanov ZipArchive* archive = new ZipArchive(fd, true); 4737462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath *handle = archive; 4747462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 4757462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (fd < 0) { 4767462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Unable to open '%s': %s", fileName, strerror(errno)); 4777462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kIoError; 4787462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 47940b52b2c884e2a0abf9c4af8b785433286b7e84bDmitriy Ivanov 4807462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return OpenArchiveInternal(archive, fileName); 4817462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 4827462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 48318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xuint32_t OpenArchiveFromMemory(void* address, size_t length, const char* debug_file_name, 48418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ZipArchiveHandle *handle) { 48518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ZipArchive* archive = new ZipArchive(address, length); 48618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu *handle = archive; 48718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return OpenArchiveInternal(archive, debug_file_name); 48818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 48918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 4907462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath/* 4917462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Close a ZipArchive, closing the file and freeing the contents. 4927462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 4937462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathvoid CloseArchive(ZipArchiveHandle handle) { 494f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); 4957462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGV("Closing archive %p", archive); 496b1a113f618561b274ab793e6401416d449c60449Neil Fuller delete archive; 4977462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 4987462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 49918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xustatic int32_t UpdateEntryFromDataDescriptor(MappedZipFile& mapped_zip, 5007462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ZipEntry *entry) { 501926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)]; 50218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) { 5037462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kIoError; 5047462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 5057462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 506926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf)); 507926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0; 508926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset); 5097462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 510926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath entry->crc32 = descriptor->crc32; 511926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath entry->compressed_length = descriptor->compressed_size; 512926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath entry->uncompressed_length = descriptor->uncompressed_size; 5137462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 5147462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return 0; 5157462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 5167462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 5177462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstatic int32_t FindEntry(const ZipArchive* archive, const int ent, 5187462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ZipEntry* data) { 5197462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const uint16_t nameLen = archive->hash_table[ent].name_length; 5207462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 5217462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // Recover the start of the central directory entry from the filename 5227462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // pointer. The filename is the first entry past the fixed-size data, 5237462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // so we can just subtract back from that. 524ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski const uint8_t* ptr = archive->hash_table[ent].name; 525926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath ptr -= sizeof(CentralDirectoryRecord); 5267462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 5277462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // This is the base of our mmapped region, we have to sanity check that 5287462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // the name that's in the hash table is a pointer to a location within 5297462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // this mapped region. 53018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu const uint8_t* base_ptr = archive->central_directory.GetBasePtr(); 53118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (ptr < base_ptr || ptr > base_ptr + archive->central_directory.GetMapLength()) { 5327462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Zip: Invalid entry pointer"); 5337462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidOffset; 5347462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 5357462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 536926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const CentralDirectoryRecord *cdr = 537926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath reinterpret_cast<const CentralDirectoryRecord*>(ptr); 538926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath 5397462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // The offset of the start of the central directory in the zipfile. 5407462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // We keep this lying around so that we can sanity check all our lengths 5417462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // and our per-file structures. 5427462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const off64_t cd_offset = archive->directory_offset; 5437462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 5447462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // Fill out the compression method, modification time, crc32 5457462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // and other interesting attributes from the central directory. These 5467462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // will later be compared against values from the local file header. 547926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath data->method = cdr->compression_method; 5480e99a2f79ae3831d8bb749e470b3d3217083b015beonit data->mod_time = cdr->last_mod_date << 16 | cdr->last_mod_time; 549926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath data->crc32 = cdr->crc32; 550926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath data->compressed_length = cdr->compressed_size; 551926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath data->uncompressed_length = cdr->uncompressed_size; 5527462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 5537462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // Figure out the local header offset from the central directory. The 5547462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // actual file data will begin after the local header and the name / 5557462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // extra comments. 556926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const off64_t local_header_offset = cdr->local_file_header_offset; 557926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) { 5587462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Zip: bad local hdr offset in zip"); 5597462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidOffset; 5607462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 5617462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 562926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath uint8_t lfh_buf[sizeof(LocalFileHeader)]; 56318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!archive->mapped_zip.ReadAtOffset(lfh_buf, sizeof(lfh_buf), local_header_offset)) { 564f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov ALOGW("Zip: failed reading lfh name from offset %" PRId64, 565f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov static_cast<int64_t>(local_header_offset)); 5667462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kIoError; 5677462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 5687462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 569926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf); 570926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath 571926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if (lfh->lfh_signature != LocalFileHeader::kSignature) { 57299ef9914be1e39276e2e077670368927a1221921Mark Salyzyn ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64, 573926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath static_cast<int64_t>(local_header_offset)); 5747462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidOffset; 5757462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 5767462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 5777462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // Paranoia: Match the values specified in the local file header 5787462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // to those specified in the central directory. 579e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1Adam Lesinski 58073b3aa541f1ad3fff961c9423dbaaf048452ca4bAdam Lesinski // Verify that the central directory and local file header have the same general purpose bit 58173b3aa541f1ad3fff961c9423dbaaf048452ca4bAdam Lesinski // flags set. 58273b3aa541f1ad3fff961c9423dbaaf048452ca4bAdam Lesinski if (lfh->gpb_flags != cdr->gpb_flags) { 583e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1Adam Lesinski ALOGW("Zip: gpb flag mismatch. expected {%04" PRIx16 "}, was {%04" PRIx16 "}", 584e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1Adam Lesinski cdr->gpb_flags, lfh->gpb_flags); 585e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1Adam Lesinski return kInconsistentInformation; 586e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1Adam Lesinski } 587e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1Adam Lesinski 588e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1Adam Lesinski // If there is no trailing data descriptor, verify that the central directory and local file 589e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1Adam Lesinski // header agree on the crc, compressed, and uncompressed sizes of the entry. 590926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) { 5917462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath data->has_data_descriptor = 0; 592926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if (data->compressed_length != lfh->compressed_size 593926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath || data->uncompressed_length != lfh->uncompressed_size 594926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath || data->crc32 != lfh->crc32) { 595088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32 596088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}", 5977462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath data->compressed_length, data->uncompressed_length, data->crc32, 598926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath lfh->compressed_size, lfh->uncompressed_size, lfh->crc32); 5997462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInconsistentInformation; 6007462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6017462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } else { 6027462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath data->has_data_descriptor = 1; 6037462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6047462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 6057462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // Check that the local file header name matches the declared 6067462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // name in the central directory. 607926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath if (lfh->file_name_length == nameLen) { 608926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader); 60950afc159b3bba06cd02648b1e287ba06d4fac059Mykola Kondratenko if (name_offset + lfh->file_name_length > cd_offset) { 6107462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Zip: Invalid declared length"); 6117462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidOffset; 6127462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6137462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 61418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu std::vector<uint8_t> name_buf(nameLen); 61518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!archive->mapped_zip.ReadAtOffset(name_buf.data(), nameLen, name_offset)) { 616f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset)); 6177462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kIoError; 6187462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6197462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 62018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (memcmp(archive->hash_table[ent].name, name_buf.data(), nameLen)) { 6217462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInconsistentInformation; 6227462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6237462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 6247462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } else { 6257462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Zip: lfh name did not match central directory."); 6267462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInconsistentInformation; 6277462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6287462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 629926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader) 630926973ec1486dc7cd4692c7e339d744ea442699cNarayan Kamath + lfh->file_name_length + lfh->extra_field_length; 63148953a1b8fdcf1d6fa1aeeb40c57821d33fc87d2Narayan Kamath if (data_offset > cd_offset) { 632f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset)); 6337462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidOffset; 6347462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6357462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 636f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) { 637088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")", 638f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset)); 6397462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidOffset; 6407462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6417462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 6427462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (data->method == kCompressStored && 643f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) { 644088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")", 645f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov static_cast<int64_t>(data_offset), data->uncompressed_length, 646f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov static_cast<int64_t>(cd_offset)); 6477462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidOffset; 6487462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6497462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 6507462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath data->offset = data_offset; 6517462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return 0; 6527462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 6537462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 6547462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathstruct IterationHandle { 6557462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath uint32_t position; 65610aa9a0e2446092ccb1a0b53438fd775427160ccPiotr Jastrzebski // We're not using vector here because this code is used in the Windows SDK 65710aa9a0e2446092ccb1a0b53438fd775427160ccPiotr Jastrzebski // where the STL is not available. 65807447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato ZipString prefix; 65907447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato ZipString suffix; 6607462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ZipArchive* archive; 6618e08536108d2b5a7f4f9a4b008987b54602fda18Piotr Jastrzebski 66207447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato IterationHandle(const ZipString* in_prefix, 66307447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato const ZipString* in_suffix) { 66407447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato if (in_prefix) { 66507447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato uint8_t* name_copy = new uint8_t[in_prefix->name_length]; 66607447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato memcpy(name_copy, in_prefix->name, in_prefix->name_length); 66707447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato prefix.name = name_copy; 66807447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato prefix.name_length = in_prefix->name_length; 66907447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato } else { 67007447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato prefix.name = NULL; 67107447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato prefix.name_length = 0; 672f1d3d3b2477a813805b71099c60e07d36dbb225aYusuke Sato } 67307447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato if (in_suffix) { 67407447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato uint8_t* name_copy = new uint8_t[in_suffix->name_length]; 67507447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato memcpy(name_copy, in_suffix->name, in_suffix->name_length); 67607447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato suffix.name = name_copy; 67707447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato suffix.name_length = in_suffix->name_length; 67807447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato } else { 67907447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato suffix.name = NULL; 68007447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato suffix.name_length = 0; 681f1d3d3b2477a813805b71099c60e07d36dbb225aYusuke Sato } 6828e08536108d2b5a7f4f9a4b008987b54602fda18Piotr Jastrzebski } 6838e08536108d2b5a7f4f9a4b008987b54602fda18Piotr Jastrzebski 6848e08536108d2b5a7f4f9a4b008987b54602fda18Piotr Jastrzebski ~IterationHandle() { 68507447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato delete[] prefix.name; 68607447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato delete[] suffix.name; 6878e08536108d2b5a7f4f9a4b008987b54602fda18Piotr Jastrzebski } 6887462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath}; 6897462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 690ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebskiint32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, 69107447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato const ZipString* optional_prefix, 69207447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato const ZipString* optional_suffix) { 693f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); 6947462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 6957462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (archive == NULL || archive->hash_table == NULL) { 6967462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Zip: Invalid ZipArchiveHandle"); 6977462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidHandle; 6987462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 6997462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 700f1d3d3b2477a813805b71099c60e07d36dbb225aYusuke Sato IterationHandle* cookie = new IterationHandle(optional_prefix, optional_suffix); 7017462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath cookie->position = 0; 7027462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath cookie->archive = archive; 7037462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 7047462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath *cookie_ptr = cookie ; 7057462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return 0; 7067462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 7077462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 70879c8b34f36ef29d481e76ebd8af97992c894d58cPiotr Jastrzebskivoid EndIteration(void* cookie) { 709ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski delete reinterpret_cast<IterationHandle*>(cookie); 71079c8b34f36ef29d481e76ebd8af97992c894d58cPiotr Jastrzebski} 71179c8b34f36ef29d481e76ebd8af97992c894d58cPiotr Jastrzebski 71207447544adbde8f688806b43f47c182eaeda4bb3Yusuke Satoint32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, 7137462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ZipEntry* data) { 714f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); 715ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski if (entryName.name_length == 0) { 716ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name); 7177462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidEntryName; 7187462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 7197462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 7207462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const int64_t ent = EntryToIndex(archive->hash_table, 721ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski archive->hash_table_size, entryName); 7227462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 7237462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (ent < 0) { 724ecccc5ad9397264d3d05018647b4a2e39d7c774cPiotr Jastrzebski ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name); 7257462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return ent; 7267462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 7277462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 7287462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return FindEntry(archive, ent, data); 7297462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 7307462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 73107447544adbde8f688806b43f47c182eaeda4bb3Yusuke Satoint32_t Next(void* cookie, ZipEntry* data, ZipString* name) { 732f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie); 7337462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (handle == NULL) { 7347462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidHandle; 7357462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 7367462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 7377462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ZipArchive* archive = handle->archive; 7387462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (archive == NULL || archive->hash_table == NULL) { 7397462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Zip: Invalid ZipArchiveHandle"); 7407462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInvalidHandle; 7417462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 7427462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 7437462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const uint32_t currentOffset = handle->position; 7447462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const uint32_t hash_table_length = archive->hash_table_size; 74507447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato const ZipString* hash_table = archive->hash_table; 7467462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 7477462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath for (uint32_t i = currentOffset; i < hash_table_length; ++i) { 7487462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (hash_table[i].name != NULL && 74907447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato (handle->prefix.name_length == 0 || 75007447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato hash_table[i].StartsWith(handle->prefix)) && 75107447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato (handle->suffix.name_length == 0 || 75207447544adbde8f688806b43f47c182eaeda4bb3Yusuke Sato hash_table[i].EndsWith(handle->suffix))) { 7537462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath handle->position = (i + 1); 7547462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const int error = FindEntry(archive, i, data); 7557462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (!error) { 7567462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath name->name = hash_table[i].name; 7577462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath name->name_length = hash_table[i].name_length; 7587462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 7597462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 7607462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return error; 7617462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 7627462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 7637462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 7647462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath handle->position = 0; 7657462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kIterationEnd; 7667462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 7677462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 768f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamathclass Writer { 769f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath public: 770f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath virtual bool Append(uint8_t* buf, size_t buf_size) = 0; 771f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath virtual ~Writer() {} 772f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath protected: 773f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath Writer() = default; 774f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath private: 775f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath DISALLOW_COPY_AND_ASSIGN(Writer); 776f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath}; 777f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 778f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath// A Writer that writes data to a fixed size memory region. 779f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath// The size of the memory region must be equal to the total size of 780f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath// the data appended to it. 781f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamathclass MemoryWriter : public Writer { 782f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath public: 783f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath MemoryWriter(uint8_t* buf, size_t size) : Writer(), 784f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath buf_(buf), size_(size), bytes_written_(0) { 785f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 786f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 787f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath virtual bool Append(uint8_t* buf, size_t buf_size) override { 788f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath if (bytes_written_ + buf_size > size_) { 789f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)", 790f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath size_, bytes_written_ + buf_size); 791f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return false; 792f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 793f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 794f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath memcpy(buf_ + bytes_written_, buf, buf_size); 795f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath bytes_written_ += buf_size; 796f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return true; 797f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 798f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 799f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath private: 800f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath uint8_t* const buf_; 801f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath const size_t size_; 802f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath size_t bytes_written_; 803f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath}; 804f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 805f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath// A Writer that appends data to a file |fd| at its current position. 806f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath// The file will be truncated to the end of the written data. 807f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamathclass FileWriter : public Writer { 808f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath public: 809f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 810f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // Creates a FileWriter for |fd| and prepare to write |entry| to it, 811f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // guaranteeing that the file descriptor is valid and that there's enough 812f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // space on the volume to write out the entry completely and that the file 813a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao // is truncated to the correct length (no truncation if |fd| references a 814a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao // block device). 815f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // 816f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // Returns a valid FileWriter on success, |nullptr| if an error occurred. 817f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) { 818f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath const uint32_t declared_length = entry->uncompressed_length; 819f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath const off64_t current_offset = lseek64(fd, 0, SEEK_CUR); 820f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath if (current_offset == -1) { 821f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno)); 822f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return nullptr; 823f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 824f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 825f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath int result = 0; 826f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath#if defined(__linux__) 827f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath if (declared_length > 0) { 828f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // Make sure we have enough space on the volume to extract the compressed 829f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // entry. Note that the call to ftruncate below will change the file size but 830f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // will not allocate space on disk and this call to fallocate will not 831f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // change the file size. 832a68d0d1fe48afc7a7a7fd0ee42df1607f21fa996Badhri Jagan Sridharan // Note: fallocate is only supported by the following filesystems - 833a68d0d1fe48afc7a7a7fd0ee42df1607f21fa996Badhri Jagan Sridharan // btrfs, ext4, ocfs2, and xfs. Therefore fallocate might fail with 834a68d0d1fe48afc7a7a7fd0ee42df1607f21fa996Badhri Jagan Sridharan // EOPNOTSUPP error when issued in other filesystems. 835a68d0d1fe48afc7a7a7fd0ee42df1607f21fa996Badhri Jagan Sridharan // Hence, check for the return error code before concluding that the 836a68d0d1fe48afc7a7a7fd0ee42df1607f21fa996Badhri Jagan Sridharan // disk does not have enough space. 837f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length)); 838a68d0d1fe48afc7a7a7fd0ee42df1607f21fa996Badhri Jagan Sridharan if (result == -1 && errno == ENOSPC) { 839d5d7abe3d1969ff1848c316c54d3f560947b3626Narayan Kamath ALOGW("Zip: unable to allocate %" PRId64 " bytes at offset %" PRId64 " : %s", 840d5d7abe3d1969ff1848c316c54d3f560947b3626Narayan Kamath static_cast<int64_t>(declared_length), static_cast<int64_t>(current_offset), 841d5d7abe3d1969ff1848c316c54d3f560947b3626Narayan Kamath strerror(errno)); 842f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return std::unique_ptr<FileWriter>(nullptr); 843f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 844f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 845f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath#endif // __linux__ 846f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 847a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao struct stat sb; 848a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao if (fstat(fd, &sb) == -1) { 849a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao ALOGW("Zip: unable to fstat file: %s", strerror(errno)); 850f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return std::unique_ptr<FileWriter>(nullptr); 851f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 852f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 853a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao // Block device doesn't support ftruncate(2). 854a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao if (!S_ISBLK(sb.st_mode)) { 855a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); 856a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao if (result == -1) { 857a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao ALOGW("Zip: unable to truncate file to %" PRId64 ": %s", 858a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao static_cast<int64_t>(declared_length + current_offset), strerror(errno)); 859a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao return std::unique_ptr<FileWriter>(nullptr); 860a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao } 861a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao } 862a456c2134882c7cede4d0f617a20ce0f8f8f3358Tao Bao 863f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length)); 864f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 865f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 866f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath virtual bool Append(uint8_t* buf, size_t buf_size) override { 867f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath if (total_bytes_written_ + buf_size > declared_length_) { 868f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)", 869f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath declared_length_, total_bytes_written_ + buf_size); 870f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return false; 871f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 872f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 873e97e66ea7c624190afa4639d6ddc60e7d013f46cNarayan Kamath const bool result = android::base::WriteFully(fd_, buf, buf_size); 874e97e66ea7c624190afa4639d6ddc60e7d013f46cNarayan Kamath if (result) { 875e97e66ea7c624190afa4639d6ddc60e7d013f46cNarayan Kamath total_bytes_written_ += buf_size; 876e97e66ea7c624190afa4639d6ddc60e7d013f46cNarayan Kamath } else { 877e97e66ea7c624190afa4639d6ddc60e7d013f46cNarayan Kamath ALOGW("Zip: unable to write " ZD " bytes to file; %s", buf_size, strerror(errno)); 878f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 879f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 880e97e66ea7c624190afa4639d6ddc60e7d013f46cNarayan Kamath return result; 881f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 882f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath private: 883f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath FileWriter(const int fd, const size_t declared_length) : 884f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath Writer(), 885f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath fd_(fd), 886f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath declared_length_(declared_length), 887f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath total_bytes_written_(0) { 888f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 889f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 890f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath const int fd_; 891f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath const size_t declared_length_; 892f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath size_t total_bytes_written_; 893f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath}; 894f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 895f94e15900779904c1ac934e9c0679044c4974441Dmitriy Ivanov// This method is using libz macros with old-style-casts 896f94e15900779904c1ac934e9c0679044c4974441Dmitriy Ivanov#pragma GCC diagnostic push 897f94e15900779904c1ac934e9c0679044c4974441Dmitriy Ivanov#pragma GCC diagnostic ignored "-Wold-style-cast" 898f94e15900779904c1ac934e9c0679044c4974441Dmitriy Ivanovstatic inline int zlib_inflateInit2(z_stream* stream, int window_bits) { 899f94e15900779904c1ac934e9c0679044c4974441Dmitriy Ivanov return inflateInit2(stream, window_bits); 900f94e15900779904c1ac934e9c0679044c4974441Dmitriy Ivanov} 901f94e15900779904c1ac934e9c0679044c4974441Dmitriy Ivanov#pragma GCC diagnostic pop 902f94e15900779904c1ac934e9c0679044c4974441Dmitriy Ivanov 90318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xustatic int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, 904f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath Writer* writer, uint64_t* crc_out) { 905edbabfe9fe3c5939c3d9ae06b50c079f5e248ea3Dmitriy Ivanov const size_t kBufSize = 32768; 906edbabfe9fe3c5939c3d9ae06b50c079f5e248ea3Dmitriy Ivanov std::vector<uint8_t> read_buf(kBufSize); 907edbabfe9fe3c5939c3d9ae06b50c079f5e248ea3Dmitriy Ivanov std::vector<uint8_t> write_buf(kBufSize); 9087462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath z_stream zstream; 9097462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath int zerr; 9107462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9117462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* 9127462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Initialize the zlib stream struct. 9137462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 9147462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath memset(&zstream, 0, sizeof(zstream)); 9157462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.zalloc = Z_NULL; 9167462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.zfree = Z_NULL; 9177462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.opaque = Z_NULL; 9187462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.next_in = NULL; 9197462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.avail_in = 0; 920edbabfe9fe3c5939c3d9ae06b50c079f5e248ea3Dmitriy Ivanov zstream.next_out = &write_buf[0]; 9217462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.avail_out = kBufSize; 9227462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.data_type = Z_UNKNOWN; 9237462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9247462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* 9257462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * Use the undocumented "negative window bits" feature to tell zlib 9267462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath * that there's no zlib header waiting for it. 9277462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath */ 928f94e15900779904c1ac934e9c0679044c4974441Dmitriy Ivanov zerr = zlib_inflateInit2(&zstream, -MAX_WBITS); 9297462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (zerr != Z_OK) { 9307462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (zerr == Z_VERSION_ERROR) { 9317462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGE("Installed zlib is not compatible with linked version (%s)", 9327462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ZLIB_VERSION); 9337462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } else { 9347462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr); 9357462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 9367462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9377462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kZlibError; 9387462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 9397462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9401f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov auto zstream_deleter = [](z_stream* stream) { 9411f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov inflateEnd(stream); /* free up any allocated structures */ 9421f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov }; 9431f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov 9441f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter); 9451f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov 9467462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const uint32_t uncompressed_length = entry->uncompressed_length; 9477462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9487462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath uint32_t compressed_length = entry->compressed_length; 9497462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath do { 9507462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* read as much as we can */ 9517462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (zstream.avail_in == 0) { 952b2a770042ebfd44989c2853689e5f45eee4a3ad9Yabin Cui const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length; 95318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!mapped_zip.ReadData(read_buf.data(), getSize)) { 954b2a770042ebfd44989c2853689e5f45eee4a3ad9Yabin Cui ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno)); 9551f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov return kIoError; 9567462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 9577462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9587462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath compressed_length -= getSize; 9597462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 960edbabfe9fe3c5939c3d9ae06b50c079f5e248ea3Dmitriy Ivanov zstream.next_in = &read_buf[0]; 9617462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.avail_in = getSize; 9627462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 9637462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9647462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* uncompress the data */ 9657462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zerr = inflate(&zstream, Z_NO_FLUSH); 9667462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (zerr != Z_OK && zerr != Z_STREAM_END) { 9677462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)", 9687462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zerr, zstream.next_in, zstream.avail_in, 9697462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.next_out, zstream.avail_out); 9701f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov return kZlibError; 9717462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 9727462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9737462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath /* write when we're full or when we're done */ 9747462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (zstream.avail_out == 0 || 9757462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) { 976edbabfe9fe3c5939c3d9ae06b50c079f5e248ea3Dmitriy Ivanov const size_t write_size = zstream.next_out - &write_buf[0]; 977f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath if (!writer->Append(&write_buf[0], write_size)) { 978f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // The file might have declared a bogus length. 979f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return kInconsistentInformation; 9807462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 9817462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 982edbabfe9fe3c5939c3d9ae06b50c079f5e248ea3Dmitriy Ivanov zstream.next_out = &write_buf[0]; 9837462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.avail_out = kBufSize; 9847462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 9857462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } while (zerr == Z_OK); 9867462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9877462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath assert(zerr == Z_STREAM_END); /* other errors should've been caught */ 9887462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9897462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // stream.adler holds the crc32 value for such streams. 9907462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath *crc_out = zstream.adler; 9917462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9927462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (zstream.total_out != uncompressed_length || compressed_length != 0) { 993088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", 9947462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath zstream.total_out, uncompressed_length); 9951f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov return kInconsistentInformation; 9967462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 9977462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 9981f741e51bc125e776e049c358bcde75069938980Dmitriy Ivanov return 0; 9997462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 10007462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 100118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xustatic int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer, 1002f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath uint64_t *crc_out) { 1003f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath static const uint32_t kBufSize = 32768; 1004f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath std::vector<uint8_t> buf(kBufSize); 1005f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 1006f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath const uint32_t length = entry->uncompressed_length; 1007f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath uint32_t count = 0; 1008f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath uint64_t crc = 0; 1009f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath while (count < length) { 1010f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath uint32_t remaining = length - count; 1011f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 1012f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // Safe conversion because kBufSize is narrow enough for a 32 bit signed 1013f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath // value. 1014b2a770042ebfd44989c2853689e5f45eee4a3ad9Yabin Cui const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining; 101518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!mapped_zip.ReadData(buf.data(), block_size)) { 1016b2a770042ebfd44989c2853689e5f45eee4a3ad9Yabin Cui ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno)); 1017f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return kIoError; 1018f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 1019f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 1020f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath if (!writer->Append(&buf[0], block_size)) { 1021f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return kIoError; 1022f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 1023f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath crc = crc32(crc, &buf[0], block_size); 1024f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath count += block_size; 1025f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath } 1026f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 1027f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath *crc_out = crc; 1028f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 1029f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return 0; 1030f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath} 1031f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 1032f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamathint32_t ExtractToWriter(ZipArchiveHandle handle, 1033f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath ZipEntry* entry, Writer* writer) { 1034f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); 10357462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath const uint16_t method = entry->method; 10367462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath off64_t data_offset = entry->offset; 10377462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 103818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!archive->mapped_zip.SeekToOffset(data_offset)) { 1039f4cb8e2ac2020af33579988e7af53be23460a998Dmitriy Ivanov ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset)); 10407462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kIoError; 10417462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 10427462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 10437462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // this should default to kUnknownCompressionMethod. 10447462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath int32_t return_value = -1; 10457462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath uint64_t crc = 0; 10467462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (method == kCompressStored) { 104718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return_value = CopyEntryToWriter(archive->mapped_zip, entry, writer, &crc); 10487462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } else if (method == kCompressDeflated) { 104918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return_value = InflateEntryToWriter(archive->mapped_zip, entry, writer, &crc); 10507462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 10517462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 10527462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (!return_value && entry->has_data_descriptor) { 105318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return_value = UpdateEntryFromDataDescriptor(archive->mapped_zip, entry); 10547462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (return_value) { 10557462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return return_value; 10567462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 10577462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 10587462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 10597462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // TODO: Fix this check by passing the right flags to inflate2 so that 10607462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath // it calculates the CRC for us. 10617462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (entry->crc32 != crc && false) { 1062088bf90e5de251f4b2f2419187d8ee5d7b2bd831Mark Salyzyn ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc); 10637462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kInconsistentInformation; 10647462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 10657462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 10667462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return return_value; 10677462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 10687462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 1069f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamathint32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, 1070f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath uint8_t* begin, uint32_t size) { 1071f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath std::unique_ptr<Writer> writer(new MemoryWriter(begin, size)); 1072f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return ExtractToWriter(handle, entry, writer.get()); 1073f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath} 1074f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath 10757462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathint32_t ExtractEntryToFile(ZipArchiveHandle handle, 10767462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath ZipEntry* entry, int fd) { 1077f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry)); 1078f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath if (writer.get() == nullptr) { 107900a258cec7bbecf10e04fef7ed4781cd750ba1d8Narayan Kamath return kIoError; 108000a258cec7bbecf10e04fef7ed4781cd750ba1d8Narayan Kamath } 108100a258cec7bbecf10e04fef7ed4781cd750ba1d8Narayan Kamath 1082f899bd534b2dc51b9db8d27c76394b192fe51155Narayan Kamath return ExtractToWriter(handle, entry, writer.get()); 10837462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 10847462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 10857462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathconst char* ErrorCodeString(int32_t error_code) { 10867462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath if (error_code > kErrorMessageLowerBound && error_code < kErrorMessageUpperBound) { 10877462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kErrorMessages[error_code * -1]; 10887462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath } 10897462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 10907462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath return kErrorMessages[0]; 10917462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 10927462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath 10937462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamathint GetFileDescriptor(const ZipArchiveHandle handle) { 109418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return reinterpret_cast<ZipArchive*>(handle)->mapped_zip.GetFileDescriptor(); 10957462f02f82cce1dd196069e6d84c5c3ea7bf10ffNarayan Kamath} 10967c6c7f0b9f96650ab12056965e223a735ea92adaColin Cross 10977c6c7f0b9f96650ab12056965e223a735ea92adaColin CrossZipString::ZipString(const char* entry_name) 10987c6c7f0b9f96650ab12056965e223a735ea92adaColin Cross : name(reinterpret_cast<const uint8_t*>(entry_name)) { 10997c6c7f0b9f96650ab12056965e223a735ea92adaColin Cross size_t len = strlen(entry_name); 11007c6c7f0b9f96650ab12056965e223a735ea92adaColin Cross CHECK_LE(len, static_cast<size_t>(UINT16_MAX)); 11017c6c7f0b9f96650ab12056965e223a735ea92adaColin Cross name_length = static_cast<uint16_t>(len); 11027c6c7f0b9f96650ab12056965e223a735ea92adaColin Cross} 110318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 110418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu#if !defined(_WIN32) 110518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xuclass ProcessWriter : public Writer { 110618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu public: 110718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ProcessWriter(ProcessZipEntryFunction func, void* cookie) : Writer(), 110818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu proc_function_(func), 110918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu cookie_(cookie) { 111018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 111118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 111218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu virtual bool Append(uint8_t* buf, size_t buf_size) override { 111318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return proc_function_(buf, buf_size, cookie_); 111418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 111518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 111618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu private: 111718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ProcessZipEntryFunction proc_function_; 111818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu void* cookie_; 111918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu}; 112018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 112118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xuint32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry, 112218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ProcessZipEntryFunction func, void* cookie) { 112318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ProcessWriter writer(func, cookie); 112418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return ExtractToWriter(handle, entry, &writer); 112518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 112618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 112718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu#endif //!defined(_WIN32) 112818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 112918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xuint MappedZipFile::GetFileDescriptor() const { 113018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!has_fd_) { 113118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGW("Zip: MappedZipFile doesn't have a file descriptor."); 113218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return -1; 113318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 113418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return fd_; 113518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 113618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 113718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xuvoid* MappedZipFile::GetBasePtr() const { 113818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (has_fd_) { 113918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGW("Zip: MappedZipFile doesn't have a base pointer."); 114018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return nullptr; 114118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 114218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return base_ptr_; 114318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 114418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 114518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xuoff64_t MappedZipFile::GetFileLength() const { 114618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (has_fd_) { 114718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu off64_t result = lseek64(fd_, 0, SEEK_END); 114818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (result == -1) { 114918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: lseek on fd %d failed: %s", fd_, strerror(errno)); 115018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 115118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return result; 115218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } else { 115318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (base_ptr_ == nullptr) { 115418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: invalid file map\n"); 115518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return -1; 115618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 115718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return static_cast<off64_t>(data_length_); 115818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 115918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 116018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 116118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xubool MappedZipFile::SeekToOffset(off64_t offset) { 116218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (has_fd_) { 116318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (lseek64(fd_, offset, SEEK_SET) != offset) { 116418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno)); 116518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return false; 116618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 116718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return true; 116818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } else { 116918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (offset < 0 || offset > static_cast<off64_t>(data_length_)) { 117018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n" , offset, 117118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu data_length_); 117218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return false; 117318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 117418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 117518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu read_pos_ = offset; 117618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return true; 117718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 117818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 117918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 118018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xubool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) { 118118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (has_fd_) { 118218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if(!android::base::ReadFully(fd_, buffer, read_amount)) { 118318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: read from %d failed\n", fd_); 118418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return false; 118518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 118618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } else { 118718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount); 118818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu read_pos_ += read_amount; 118918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 119018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return true; 119118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 119218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 119318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu// Attempts to read |len| bytes into |buf| at offset |off|. 119418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xubool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) { 119518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu#if !defined(_WIN32) 119618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (has_fd_) { 119718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) { 119818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: failed to read at offset %" PRId64 "\n", off); 119918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return false; 120018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 120118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return true; 120218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 120318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu#endif 120418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!SeekToOffset(off)) { 120518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return false; 120618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 120718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return ReadData(buf, len); 120818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 120918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 121018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 121118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xuvoid CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) { 121218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu base_ptr_ = static_cast<uint8_t*>(map_base_ptr) + cd_start_offset; 121318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu length_ = cd_size; 121418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 121518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 121618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xubool ZipArchive::InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset, 121718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu size_t cd_size) { 121818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (mapped_zip.HasFd()) { 121918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (!directory_map->create(debug_file_name, mapped_zip.GetFileDescriptor(), 122018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu cd_start_offset, cd_size, true /* read only */)) { 122118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return false; 122218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 122318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 122418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu CHECK_EQ(directory_map->getDataLength(), cd_size); 122518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu central_directory.Initialize(directory_map->getDataPtr(), 0/*offset*/, cd_size); 122618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } else { 122718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (mapped_zip.GetBasePtr() == nullptr) { 122818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer\n"); 122918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return false; 123018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 123118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu if (static_cast<off64_t>(cd_start_offset) + static_cast<off64_t>(cd_size) > 123218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu mapped_zip.GetFileLength()) { 123318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu ALOGE("Zip: Failed to map central directory, offset exceeds mapped memory region (" 123418c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu "start_offset %" PRId64 ", cd_size %zu, mapped_region_size %" PRId64 ")", 123518c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu static_cast<int64_t>(cd_start_offset), cd_size, mapped_zip.GetFileLength()); 123618c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return false; 123718c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 123818c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu 123918c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu central_directory.Initialize(mapped_zip.GetBasePtr(), cd_start_offset, cd_size); 124018c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu } 124118c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu return true; 124218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu} 1243