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