Home | History | Annotate | Download | only in libziparchive
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *    http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
     18 #define LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
     19 
     20 #include <stdint.h>
     21 #include <stdlib.h>
     22 #include <unistd.h>
     23 
     24 #include <memory>
     25 #include <vector>
     26 
     27 #include <utils/FileMap.h>
     28 #include <ziparchive/zip_archive.h>
     29 #include "android-base/macros.h"
     30 
     31 static const char* kErrorMessages[] = {
     32     "Success",
     33     "Iteration ended",
     34     "Zlib error",
     35     "Invalid file",
     36     "Invalid handle",
     37     "Duplicate entries in archive",
     38     "Empty archive",
     39     "Entry not found",
     40     "Invalid offset",
     41     "Inconsistent information",
     42     "Invalid entry name",
     43     "I/O error",
     44     "File mapping failed",
     45 };
     46 
     47 enum ErrorCodes : int32_t {
     48   kIterationEnd = -1,
     49 
     50   // We encountered a Zlib error when inflating a stream from this file.
     51   // Usually indicates file corruption.
     52   kZlibError = -2,
     53 
     54   // The input file cannot be processed as a zip archive. Usually because
     55   // it's too small, too large or does not have a valid signature.
     56   kInvalidFile = -3,
     57 
     58   // An invalid iteration / ziparchive handle was passed in as an input
     59   // argument.
     60   kInvalidHandle = -4,
     61 
     62   // The zip archive contained two (or possibly more) entries with the same
     63   // name.
     64   kDuplicateEntry = -5,
     65 
     66   // The zip archive contains no entries.
     67   kEmptyArchive = -6,
     68 
     69   // The specified entry was not found in the archive.
     70   kEntryNotFound = -7,
     71 
     72   // The zip archive contained an invalid local file header pointer.
     73   kInvalidOffset = -8,
     74 
     75   // The zip archive contained inconsistent entry information. This could
     76   // be because the central directory & local file header did not agree, or
     77   // if the actual uncompressed length or crc32 do not match their declared
     78   // values.
     79   kInconsistentInformation = -9,
     80 
     81   // An invalid entry name was encountered.
     82   kInvalidEntryName = -10,
     83 
     84   // An I/O related system call (read, lseek, ftruncate, map) failed.
     85   kIoError = -11,
     86 
     87   // We were not able to mmap the central directory or entry contents.
     88   kMmapFailed = -12,
     89 
     90   kLastErrorCode = kMmapFailed,
     91 };
     92 
     93 class MappedZipFile {
     94  public:
     95   explicit MappedZipFile(const int fd)
     96       : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0), read_pos_(0) {}
     97 
     98   explicit MappedZipFile(void* address, size_t length)
     99       : has_fd_(false),
    100         fd_(-1),
    101         base_ptr_(address),
    102         data_length_(static_cast<off64_t>(length)),
    103         read_pos_(0) {}
    104 
    105   bool HasFd() const { return has_fd_; }
    106 
    107   int GetFileDescriptor() const;
    108 
    109   void* GetBasePtr() const;
    110 
    111   off64_t GetFileLength() const;
    112 
    113   bool SeekToOffset(off64_t offset);
    114 
    115   bool ReadData(uint8_t* buffer, size_t read_amount);
    116 
    117   bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
    118 
    119  private:
    120   // If has_fd_ is true, fd is valid and we'll read contents of a zip archive
    121   // from the file. Otherwise, we're opening the archive from a memory mapped
    122   // file. In that case, base_ptr_ points to the start of the memory region and
    123   // data_length_ defines the file length.
    124   const bool has_fd_;
    125 
    126   const int fd_;
    127 
    128   void* const base_ptr_;
    129   const off64_t data_length_;
    130   // read_pos_ is the offset to the base_ptr_ where we read data from.
    131   size_t read_pos_;
    132 };
    133 
    134 class CentralDirectory {
    135  public:
    136   CentralDirectory(void) : base_ptr_(nullptr), length_(0) {}
    137 
    138   const uint8_t* GetBasePtr() const { return base_ptr_; }
    139 
    140   size_t GetMapLength() const { return length_; }
    141 
    142   void Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
    143 
    144  private:
    145   const uint8_t* base_ptr_;
    146   size_t length_;
    147 };
    148 
    149 struct ZipArchive {
    150   // open Zip archive
    151   mutable MappedZipFile mapped_zip;
    152   const bool close_file;
    153 
    154   // mapped central directory area
    155   off64_t directory_offset;
    156   CentralDirectory central_directory;
    157   std::unique_ptr<android::FileMap> directory_map;
    158 
    159   // number of entries in the Zip archive
    160   uint16_t num_entries;
    161 
    162   // We know how many entries are in the Zip archive, so we can have a
    163   // fixed-size hash table. We define a load factor of 0.75 and over
    164   // allocate so the maximum number entries can never be higher than
    165   // ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
    166   uint32_t hash_table_size;
    167   ZipString* hash_table;
    168 
    169   ZipArchive(const int fd, bool assume_ownership)
    170       : mapped_zip(fd),
    171         close_file(assume_ownership),
    172         directory_offset(0),
    173         central_directory(),
    174         directory_map(new android::FileMap()),
    175         num_entries(0),
    176         hash_table_size(0),
    177         hash_table(nullptr) {}
    178 
    179   ZipArchive(void* address, size_t length)
    180       : mapped_zip(address, length),
    181         close_file(false),
    182         directory_offset(0),
    183         central_directory(),
    184         directory_map(new android::FileMap()),
    185         num_entries(0),
    186         hash_table_size(0),
    187         hash_table(nullptr) {}
    188 
    189   ~ZipArchive() {
    190     if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
    191       close(mapped_zip.GetFileDescriptor());
    192     }
    193 
    194     free(hash_table);
    195   }
    196 
    197   bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
    198                                   size_t cd_size);
    199 };
    200 
    201 #endif  // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
    202