blob: 18e02291d42e23ef5c26d25fe9ae30cb2292a176 [file] [log] [blame]
Christopher Ferrise6884ce2015-11-10 14:55:12 -08001/*
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
Tianjie Xu18c25922016-09-29 15:27:41 -070024#include <memory>
25#include <vector>
26
Christopher Ferrise6884ce2015-11-10 14:55:12 -080027#include <utils/FileMap.h>
28#include <ziparchive/zip_archive.h>
Narayan Kamath1ef9d2d2017-06-15 13:58:25 +010029#include "android-base/macros.h"
30
31static 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
47enum 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};
Christopher Ferrise6884ce2015-11-10 14:55:12 -080092
Tianjie Xu18c25922016-09-29 15:27:41 -070093class MappedZipFile {
94 public:
Jiyong Parkcd997e62017-06-30 17:23:33 +090095 explicit MappedZipFile(const int fd)
Adam Lesinskide117e42017-06-19 10:27:38 -070096 : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0) {}
Tianjie Xu18c25922016-09-29 15:27:41 -070097
Jiyong Parkcd997e62017-06-30 17:23:33 +090098 explicit MappedZipFile(void* address, size_t length)
Adam Lesinskide117e42017-06-19 10:27:38 -070099 : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)) {}
Tianjie Xu18c25922016-09-29 15:27:41 -0700100
Jiyong Parkcd997e62017-06-30 17:23:33 +0900101 bool HasFd() const { return has_fd_; }
Tianjie Xu18c25922016-09-29 15:27:41 -0700102
103 int GetFileDescriptor() const;
104
105 void* GetBasePtr() const;
106
107 off64_t GetFileLength() const;
108
Narayan Kamath8b8faed2017-10-26 14:08:38 +0100109 bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const;
Tianjie Xu18c25922016-09-29 15:27:41 -0700110
111 private:
112 // If has_fd_ is true, fd is valid and we'll read contents of a zip archive
113 // from the file. Otherwise, we're opening the archive from a memory mapped
114 // file. In that case, base_ptr_ points to the start of the memory region and
115 // data_length_ defines the file length.
116 const bool has_fd_;
117
118 const int fd_;
119
120 void* const base_ptr_;
121 const off64_t data_length_;
Tianjie Xu18c25922016-09-29 15:27:41 -0700122};
123
124class CentralDirectory {
125 public:
Jiyong Parkcd997e62017-06-30 17:23:33 +0900126 CentralDirectory(void) : base_ptr_(nullptr), length_(0) {}
Tianjie Xu18c25922016-09-29 15:27:41 -0700127
Jiyong Parkcd997e62017-06-30 17:23:33 +0900128 const uint8_t* GetBasePtr() const { return base_ptr_; }
Tianjie Xu18c25922016-09-29 15:27:41 -0700129
Jiyong Parkcd997e62017-06-30 17:23:33 +0900130 size_t GetMapLength() const { return length_; }
Tianjie Xu18c25922016-09-29 15:27:41 -0700131
132 void Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
133
134 private:
135 const uint8_t* base_ptr_;
136 size_t length_;
137};
138
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800139struct ZipArchive {
140 // open Zip archive
Tianjie Xu18c25922016-09-29 15:27:41 -0700141 mutable MappedZipFile mapped_zip;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800142 const bool close_file;
143
144 // mapped central directory area
145 off64_t directory_offset;
Tianjie Xu18c25922016-09-29 15:27:41 -0700146 CentralDirectory central_directory;
147 std::unique_ptr<android::FileMap> directory_map;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800148
149 // number of entries in the Zip archive
150 uint16_t num_entries;
151
152 // We know how many entries are in the Zip archive, so we can have a
153 // fixed-size hash table. We define a load factor of 0.75 and over
154 // allocate so the maximum number entries can never be higher than
155 // ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
156 uint32_t hash_table_size;
157 ZipString* hash_table;
158
Jiyong Parkcd997e62017-06-30 17:23:33 +0900159 ZipArchive(const int fd, bool assume_ownership)
160 : mapped_zip(fd),
161 close_file(assume_ownership),
162 directory_offset(0),
163 central_directory(),
164 directory_map(new android::FileMap()),
165 num_entries(0),
166 hash_table_size(0),
167 hash_table(nullptr) {}
Tianjie Xu18c25922016-09-29 15:27:41 -0700168
Jiyong Parkcd997e62017-06-30 17:23:33 +0900169 ZipArchive(void* address, size_t length)
170 : mapped_zip(address, length),
171 close_file(false),
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) {}
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800178
179 ~ZipArchive() {
Tianjie Xu18c25922016-09-29 15:27:41 -0700180 if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
181 close(mapped_zip.GetFileDescriptor());
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800182 }
183
184 free(hash_table);
185 }
Tianjie Xu18c25922016-09-29 15:27:41 -0700186
187 bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
188 size_t cd_size);
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800189};
190
191#endif // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_