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