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