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