aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk5
-rw-r--r--applypatch/Android.mk1
-rw-r--r--install.cpp45
-rw-r--r--minzip/Android.mk23
-rw-r--r--minzip/Bits.h357
-rw-r--r--minzip/Hash.cpp378
-rw-r--r--minzip/Hash.h194
-rw-r--r--minzip/Inlines.c25
-rw-r--r--minzip/Zip.cpp1022
-rw-r--r--minzip/Zip.h171
-rw-r--r--minzip/inline_magic.h26
-rw-r--r--otafault/Android.mk2
-rw-r--r--otafault/config.cpp20
-rw-r--r--otafault/config.h4
-rw-r--r--otautil/Android.mk35
-rw-r--r--otautil/DirUtil.cpp (renamed from minzip/DirUtil.cpp)0
-rw-r--r--otautil/DirUtil.h (renamed from minzip/DirUtil.h)0
-rw-r--r--otautil/SysUtil.cpp (renamed from minzip/SysUtil.cpp)0
-rw-r--r--otautil/SysUtil.h (renamed from minzip/SysUtil.h)0
-rw-r--r--otautil/ZipUtil.cpp121
-rw-r--r--otautil/ZipUtil.h57
-rw-r--r--recovery.cpp3
-rw-r--r--tests/Android.mk11
-rw-r--r--tests/component/verifier_test.cpp3
-rw-r--r--tests/testdata/ziptest_dummy-update.zipbin0 -> 1090065 bytes
-rw-r--r--tests/testdata/ziptest_valid.zipbin0 -> 758 bytes
-rw-r--r--tests/unit/zip_test.cpp93
-rw-r--r--updater/Android.mk4
-rw-r--r--updater/blockimg.cpp73
-rw-r--r--updater/include/updater/updater.h4
-rw-r--r--updater/install.cpp38
-rw-r--r--updater/updater.cpp53
-rw-r--r--verifier.cpp2
33 files changed, 448 insertions, 2322 deletions
diff --git a/Android.mk b/Android.mk
index e502d9e6..68f069d6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -77,7 +77,8 @@ LOCAL_STATIC_LIBRARIES := \
77 libbatterymonitor \ 77 libbatterymonitor \
78 libext4_utils_static \ 78 libext4_utils_static \
79 libsparse_static \ 79 libsparse_static \
80 libminzip \ 80 libziparchive \
81 libotautil \
81 libmounts \ 82 libmounts \
82 libz \ 83 libz \
83 libminadbd \ 84 libminadbd \
@@ -150,7 +151,7 @@ LOCAL_CFLAGS := -Werror
150include $(BUILD_STATIC_LIBRARY) 151include $(BUILD_STATIC_LIBRARY)
151 152
152include $(LOCAL_PATH)/minui/Android.mk \ 153include $(LOCAL_PATH)/minui/Android.mk \
153 $(LOCAL_PATH)/minzip/Android.mk \ 154 $(LOCAL_PATH)/otautil/Android.mk \
154 $(LOCAL_PATH)/minadbd/Android.mk \ 155 $(LOCAL_PATH)/minadbd/Android.mk \
155 $(LOCAL_PATH)/tests/Android.mk \ 156 $(LOCAL_PATH)/tests/Android.mk \
156 $(LOCAL_PATH)/tools/Android.mk \ 157 $(LOCAL_PATH)/tools/Android.mk \
diff --git a/applypatch/Android.mk b/applypatch/Android.mk
index 77e499ec..9bbac441 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -80,7 +80,6 @@ LOCAL_STATIC_LIBRARIES += \
80 libbase \ 80 libbase \
81 libedify \ 81 libedify \
82 libotafault \ 82 libotafault \
83 libminzip \
84 libcrypto \ 83 libcrypto \
85 libbz 84 libbz
86LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc 85LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc
diff --git a/install.cpp b/install.cpp
index 72c922d5..c9871523 100644
--- a/install.cpp
+++ b/install.cpp
@@ -32,13 +32,13 @@
32#include <android-base/parseint.h> 32#include <android-base/parseint.h>
33#include <android-base/stringprintf.h> 33#include <android-base/stringprintf.h>
34#include <android-base/strings.h> 34#include <android-base/strings.h>
35#include <ziparchive/zip_archive.h>
35 36
36#include "common.h" 37#include "common.h"
37#include "error_code.h" 38#include "error_code.h"
38#include "install.h" 39#include "install.h"
39#include "minui/minui.h" 40#include "minui/minui.h"
40#include "minzip/SysUtil.h" 41#include "otautil/SysUtil.h"
41#include "minzip/Zip.h"
42#include "roots.h" 42#include "roots.h"
43#include "ui.h" 43#include "ui.h"
44#include "verifier.h" 44#include "verifier.h"
@@ -72,15 +72,17 @@ static int parse_build_number(const std::string& str) {
72} 72}
73 73
74// Read the build.version.incremental of src/tgt from the metadata and log it to last_install. 74// Read the build.version.incremental of src/tgt from the metadata and log it to last_install.
75static void read_source_target_build(ZipArchive* zip, std::vector<std::string>& log_buffer) { 75static void read_source_target_build(ZipArchiveHandle zip, std::vector<std::string>& log_buffer) {
76 const ZipEntry* meta_entry = mzFindZipEntry(zip, METADATA_PATH); 76 ZipString metadata_path(METADATA_PATH);
77 if (meta_entry == nullptr) { 77 ZipEntry meta_entry;
78 if (FindEntry(zip, metadata_path, &meta_entry) != 0) {
78 LOG(ERROR) << "Failed to find " << METADATA_PATH << " in update package"; 79 LOG(ERROR) << "Failed to find " << METADATA_PATH << " in update package";
79 return; 80 return;
80 } 81 }
81 82
82 std::string meta_data(meta_entry->uncompLen, '\0'); 83 std::string meta_data(meta_entry.uncompressed_length, '\0');
83 if (!mzReadZipEntry(zip, meta_entry, &meta_data[0], meta_entry->uncompLen)) { 84 if (ExtractToMemory(zip, &meta_entry, reinterpret_cast<uint8_t*>(&meta_data[0]),
85 meta_entry.uncompressed_length) != 0) {
84 LOG(ERROR) << "Failed to read metadata in update package"; 86 LOG(ERROR) << "Failed to read metadata in update package";
85 return; 87 return;
86 } 88 }
@@ -109,15 +111,14 @@ static void read_source_target_build(ZipArchive* zip, std::vector<std::string>&
109 111
110// If the package contains an update binary, extract it and run it. 112// If the package contains an update binary, extract it and run it.
111static int 113static int
112try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache, 114try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
113 std::vector<std::string>& log_buffer, int retry_count) 115 std::vector<std::string>& log_buffer, int retry_count)
114{ 116{
115 read_source_target_build(zip, log_buffer); 117 read_source_target_build(zip, log_buffer);
116 118
117 const ZipEntry* binary_entry = 119 ZipString binary_name(ASSUMED_UPDATE_BINARY_NAME);
118 mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); 120 ZipEntry binary_entry;
119 if (binary_entry == NULL) { 121 if (FindEntry(zip, binary_name, &binary_entry) != 0) {
120 mzCloseZipArchive(zip);
121 return INSTALL_CORRUPT; 122 return INSTALL_CORRUPT;
122 } 123 }
123 124
@@ -126,15 +127,14 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
126 int fd = creat(binary, 0755); 127 int fd = creat(binary, 0755);
127 if (fd < 0) { 128 if (fd < 0) {
128 PLOG(ERROR) << "Can't make " << binary; 129 PLOG(ERROR) << "Can't make " << binary;
129 mzCloseZipArchive(zip);
130 return INSTALL_ERROR; 130 return INSTALL_ERROR;
131 } 131 }
132 bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); 132 int error = ExtractEntryToFile(zip, &binary_entry, fd);
133 close(fd); 133 close(fd);
134 mzCloseZipArchive(zip);
135 134
136 if (!ok) { 135 if (error != 0) {
137 LOG(ERROR) << "Can't copy " << ASSUMED_UPDATE_BINARY_NAME; 136 LOG(ERROR) << "Can't copy " << ASSUMED_UPDATE_BINARY_NAME
137 << " : " << ErrorCodeString(error);
138 return INSTALL_ERROR; 138 return INSTALL_ERROR;
139 } 139 }
140 140
@@ -326,13 +326,14 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
326 } 326 }
327 327
328 // Try to open the package. 328 // Try to open the package.
329 ZipArchive zip; 329 ZipArchiveHandle zip;
330 err = mzOpenZipArchive(map.addr, map.length, &zip); 330 err = OpenArchiveFromMemory(map.addr, map.length, path, &zip);
331 if (err != 0) { 331 if (err != 0) {
332 LOG(ERROR) << "Can't open " << path; 332 LOG(ERROR) << "Can't open " << path << " : " << ErrorCodeString(err);
333 log_buffer.push_back(android::base::StringPrintf("error: %d", kZipOpenFailure)); 333 log_buffer.push_back(android::base::StringPrintf("error: %d", kZipOpenFailure));
334 334
335 sysReleaseMap(&map); 335 sysReleaseMap(&map);
336 CloseArchive(zip);
336 return INSTALL_CORRUPT; 337 return INSTALL_CORRUPT;
337 } 338 }
338 339
@@ -342,12 +343,12 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
342 ui->Print("Retry attempt: %d\n", retry_count); 343 ui->Print("Retry attempt: %d\n", retry_count);
343 } 344 }
344 ui->SetEnableReboot(false); 345 ui->SetEnableReboot(false);
345 int result = try_update_binary(path, &zip, wipe_cache, log_buffer, retry_count); 346 int result = try_update_binary(path, zip, wipe_cache, log_buffer, retry_count);
346 ui->SetEnableReboot(true); 347 ui->SetEnableReboot(true);
347 ui->Print("\n"); 348 ui->Print("\n");
348 349
349 sysReleaseMap(&map); 350 sysReleaseMap(&map);
350 351 CloseArchive(zip);
351 return result; 352 return result;
352} 353}
353 354
diff --git a/minzip/Android.mk b/minzip/Android.mk
deleted file mode 100644
index 6dbfee99..00000000
--- a/minzip/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
1LOCAL_PATH := $(call my-dir)
2include $(CLEAR_VARS)
3
4LOCAL_SRC_FILES := \
5 Hash.cpp \
6 SysUtil.cpp \
7 DirUtil.cpp \
8 Inlines.c \
9 Zip.cpp
10
11LOCAL_C_INCLUDES := \
12 external/zlib \
13 external/safe-iop/include
14
15LOCAL_STATIC_LIBRARIES := libselinux libbase
16
17LOCAL_MODULE := libminzip
18
19LOCAL_CLANG := true
20
21LOCAL_CFLAGS += -Werror -Wall
22
23include $(BUILD_STATIC_LIBRARY)
diff --git a/minzip/Bits.h b/minzip/Bits.h
deleted file mode 100644
index f96e6c44..00000000
--- a/minzip/Bits.h
+++ /dev/null
@@ -1,357 +0,0 @@
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Some handy functions for manipulating bits and bytes.
5 */
6#ifndef _MINZIP_BITS
7#define _MINZIP_BITS
8
9#include "inline_magic.h"
10
11#include <stdlib.h>
12#include <string.h>
13
14/*
15 * Get 1 byte. (Included to make the code more legible.)
16 */
17INLINE unsigned char get1(unsigned const char* pSrc)
18{
19 return *pSrc;
20}
21
22/*
23 * Get 2 big-endian bytes.
24 */
25INLINE unsigned short get2BE(unsigned char const* pSrc)
26{
27 unsigned short result;
28
29 result = *pSrc++ << 8;
30 result |= *pSrc++;
31
32 return result;
33}
34
35/*
36 * Get 4 big-endian bytes.
37 */
38INLINE unsigned int get4BE(unsigned char const* pSrc)
39{
40 unsigned int result;
41
42 result = *pSrc++ << 24;
43 result |= *pSrc++ << 16;
44 result |= *pSrc++ << 8;
45 result |= *pSrc++;
46
47 return result;
48}
49
50/*
51 * Get 8 big-endian bytes.
52 */
53INLINE unsigned long long get8BE(unsigned char const* pSrc)
54{
55 unsigned long long result;
56
57 result = (unsigned long long) *pSrc++ << 56;
58 result |= (unsigned long long) *pSrc++ << 48;
59 result |= (unsigned long long) *pSrc++ << 40;
60 result |= (unsigned long long) *pSrc++ << 32;
61 result |= (unsigned long long) *pSrc++ << 24;
62 result |= (unsigned long long) *pSrc++ << 16;
63 result |= (unsigned long long) *pSrc++ << 8;
64 result |= (unsigned long long) *pSrc++;
65
66 return result;
67}
68
69/*
70 * Get 2 little-endian bytes.
71 */
72INLINE unsigned short get2LE(unsigned char const* pSrc)
73{
74 unsigned short result;
75
76 result = *pSrc++;
77 result |= *pSrc++ << 8;
78
79 return result;
80}
81
82/*
83 * Get 4 little-endian bytes.
84 */
85INLINE unsigned int get4LE(unsigned char const* pSrc)
86{
87 unsigned int result;
88
89 result = *pSrc++;
90 result |= *pSrc++ << 8;
91 result |= *pSrc++ << 16;
92 result |= *pSrc++ << 24;
93
94 return result;
95}
96
97/*
98 * Get 8 little-endian bytes.
99 */
100INLINE unsigned long long get8LE(unsigned char const* pSrc)
101{
102 unsigned long long result;
103
104 result = (unsigned long long) *pSrc++;
105 result |= (unsigned long long) *pSrc++ << 8;
106 result |= (unsigned long long) *pSrc++ << 16;
107 result |= (unsigned long long) *pSrc++ << 24;
108 result |= (unsigned long long) *pSrc++ << 32;
109 result |= (unsigned long long) *pSrc++ << 40;
110 result |= (unsigned long long) *pSrc++ << 48;
111 result |= (unsigned long long) *pSrc++ << 56;
112
113 return result;
114}
115
116/*
117 * Grab 1 byte and advance the data pointer.
118 */
119INLINE unsigned char read1(unsigned const char** ppSrc)
120{
121 return *(*ppSrc)++;
122}
123
124/*
125 * Grab 2 big-endian bytes and advance the data pointer.
126 */
127INLINE unsigned short read2BE(unsigned char const** ppSrc)
128{
129 unsigned short result;
130
131 result = *(*ppSrc)++ << 8;
132 result |= *(*ppSrc)++;
133
134 return result;
135}
136
137/*
138 * Grab 4 big-endian bytes and advance the data pointer.
139 */
140INLINE unsigned int read4BE(unsigned char const** ppSrc)
141{
142 unsigned int result;
143
144 result = *(*ppSrc)++ << 24;
145 result |= *(*ppSrc)++ << 16;
146 result |= *(*ppSrc)++ << 8;
147 result |= *(*ppSrc)++;
148
149 return result;
150}
151
152/*
153 * Get 8 big-endian bytes.
154 */
155INLINE unsigned long long read8BE(unsigned char const** ppSrc)
156{
157 unsigned long long result;
158
159 result = (unsigned long long) *(*ppSrc)++ << 56;
160 result |= (unsigned long long) *(*ppSrc)++ << 48;
161 result |= (unsigned long long) *(*ppSrc)++ << 40;
162 result |= (unsigned long long) *(*ppSrc)++ << 32;
163 result |= (unsigned long long) *(*ppSrc)++ << 24;
164 result |= (unsigned long long) *(*ppSrc)++ << 16;
165 result |= (unsigned long long) *(*ppSrc)++ << 8;
166 result |= (unsigned long long) *(*ppSrc)++;
167
168 return result;
169}
170
171/*
172 * Grab 2 little-endian bytes and advance the data pointer.
173 */
174INLINE unsigned short read2LE(unsigned char const** ppSrc)
175{
176 unsigned short result;
177
178 result = *(*ppSrc)++;
179 result |= *(*ppSrc)++ << 8;
180
181 return result;
182}
183
184/*
185 * Grab 4 little-endian bytes and advance the data pointer.
186 */
187INLINE unsigned int read4LE(unsigned char const** ppSrc)
188{
189 unsigned int result;
190
191 result = *(*ppSrc)++;
192 result |= *(*ppSrc)++ << 8;
193 result |= *(*ppSrc)++ << 16;
194 result |= *(*ppSrc)++ << 24;
195
196 return result;
197}
198
199/*
200 * Get 8 little-endian bytes.
201 */
202INLINE unsigned long long read8LE(unsigned char const** ppSrc)
203{
204 unsigned long long result;
205
206 result = (unsigned long long) *(*ppSrc)++;
207 result |= (unsigned long long) *(*ppSrc)++ << 8;
208 result |= (unsigned long long) *(*ppSrc)++ << 16;
209 result |= (unsigned long long) *(*ppSrc)++ << 24;
210 result |= (unsigned long long) *(*ppSrc)++ << 32;
211 result |= (unsigned long long) *(*ppSrc)++ << 40;
212 result |= (unsigned long long) *(*ppSrc)++ << 48;
213 result |= (unsigned long long) *(*ppSrc)++ << 56;
214
215 return result;
216}
217
218/*
219 * Skip over a UTF-8 string.
220 */
221INLINE void skipUtf8String(unsigned char const** ppSrc)
222{
223 unsigned int length = read4BE(ppSrc);
224
225 (*ppSrc) += length;
226}
227
228/*
229 * Read a UTF-8 string into a fixed-size buffer, and null-terminate it.
230 *
231 * Returns the length of the original string.
232 */
233INLINE int readUtf8String(unsigned char const** ppSrc, char* buf, size_t bufLen)
234{
235 unsigned int length = read4BE(ppSrc);
236 size_t copyLen = (length < bufLen) ? length : bufLen-1;
237
238 memcpy(buf, *ppSrc, copyLen);
239 buf[copyLen] = '\0';
240
241 (*ppSrc) += length;
242 return length;
243}
244
245/*
246 * Read a UTF-8 string into newly-allocated storage, and null-terminate it.
247 *
248 * Returns the string and its length. (The latter is probably unnecessary
249 * for the way we're using UTF8.)
250 */
251INLINE char* readNewUtf8String(unsigned char const** ppSrc, size_t* pLength)
252{
253 unsigned int length = read4BE(ppSrc);
254 char* buf;
255
256 buf = (char*) malloc(length+1);
257
258 memcpy(buf, *ppSrc, length);
259 buf[length] = '\0';
260
261 (*ppSrc) += length;
262
263 *pLength = length;
264 return buf;
265}
266
267
268/*
269 * Set 1 byte. (Included to make the code more legible.)
270 */
271INLINE void set1(unsigned char* buf, unsigned char val)
272{
273 *buf = (unsigned char)(val);
274}
275
276/*
277 * Set 2 big-endian bytes.
278 */
279INLINE void set2BE(unsigned char* buf, unsigned short val)
280{
281 *buf++ = (unsigned char)(val >> 8);
282 *buf = (unsigned char)(val);
283}
284
285/*
286 * Set 4 big-endian bytes.
287 */
288INLINE void set4BE(unsigned char* buf, unsigned int val)
289{
290 *buf++ = (unsigned char)(val >> 24);
291 *buf++ = (unsigned char)(val >> 16);
292 *buf++ = (unsigned char)(val >> 8);
293 *buf = (unsigned char)(val);
294}
295
296/*
297 * Set 8 big-endian bytes.
298 */
299INLINE void set8BE(unsigned char* buf, unsigned long long val)
300{
301 *buf++ = (unsigned char)(val >> 56);
302 *buf++ = (unsigned char)(val >> 48);
303 *buf++ = (unsigned char)(val >> 40);
304 *buf++ = (unsigned char)(val >> 32);
305 *buf++ = (unsigned char)(val >> 24);
306 *buf++ = (unsigned char)(val >> 16);
307 *buf++ = (unsigned char)(val >> 8);
308 *buf = (unsigned char)(val);
309}
310
311/*
312 * Set 2 little-endian bytes.
313 */
314INLINE void set2LE(unsigned char* buf, unsigned short val)
315{
316 *buf++ = (unsigned char)(val);
317 *buf = (unsigned char)(val >> 8);
318}
319
320/*
321 * Set 4 little-endian bytes.
322 */
323INLINE void set4LE(unsigned char* buf, unsigned int val)
324{
325 *buf++ = (unsigned char)(val);
326 *buf++ = (unsigned char)(val >> 8);
327 *buf++ = (unsigned char)(val >> 16);
328 *buf = (unsigned char)(val >> 24);
329}
330
331/*
332 * Set 8 little-endian bytes.
333 */
334INLINE void set8LE(unsigned char* buf, unsigned long long val)
335{
336 *buf++ = (unsigned char)(val);
337 *buf++ = (unsigned char)(val >> 8);
338 *buf++ = (unsigned char)(val >> 16);
339 *buf++ = (unsigned char)(val >> 24);
340 *buf++ = (unsigned char)(val >> 32);
341 *buf++ = (unsigned char)(val >> 40);
342 *buf++ = (unsigned char)(val >> 48);
343 *buf = (unsigned char)(val >> 56);
344}
345
346/*
347 * Stuff a UTF-8 string into the buffer.
348 */
349INLINE void setUtf8String(unsigned char* buf, const unsigned char* str)
350{
351 unsigned int strLen = strlen((const char*)str);
352
353 set4BE(buf, strLen);
354 memcpy(buf + sizeof(unsigned int), str, strLen);
355}
356
357#endif /*_MINZIP_BITS*/
diff --git a/minzip/Hash.cpp b/minzip/Hash.cpp
deleted file mode 100644
index ac08935d..00000000
--- a/minzip/Hash.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Hash table. The dominant calls are add and lookup, with removals
5 * happening very infrequently. We use probing, and don't worry much
6 * about tombstone removal.
7 */
8#include <stdlib.h>
9#include <assert.h>
10
11#include <android-base/logging.h>
12
13#include "Hash.h"
14
15/* table load factor, i.e. how full can it get before we resize */
16//#define LOAD_NUMER 3 // 75%
17//#define LOAD_DENOM 4
18#define LOAD_NUMER 5 // 62.5%
19#define LOAD_DENOM 8
20//#define LOAD_NUMER 1 // 50%
21//#define LOAD_DENOM 2
22
23/*
24 * Compute the capacity needed for a table to hold "size" elements.
25 */
26size_t mzHashSize(size_t size) {
27 return (size * LOAD_DENOM) / LOAD_NUMER +1;
28}
29
30/*
31 * Round up to the next highest power of 2.
32 *
33 * Found on http://graphics.stanford.edu/~seander/bithacks.html.
34 */
35unsigned int roundUpPower2(unsigned int val)
36{
37 val--;
38 val |= val >> 1;
39 val |= val >> 2;
40 val |= val >> 4;
41 val |= val >> 8;
42 val |= val >> 16;
43 val++;
44
45 return val;
46}
47
48/*
49 * Create and initialize a hash table.
50 */
51HashTable* mzHashTableCreate(size_t initialSize, HashFreeFunc freeFunc)
52{
53 HashTable* pHashTable;
54
55 assert(initialSize > 0);
56
57 pHashTable = (HashTable*) malloc(sizeof(*pHashTable));
58 if (pHashTable == NULL)
59 return NULL;
60
61 pHashTable->tableSize = roundUpPower2(initialSize);
62 pHashTable->numEntries = pHashTable->numDeadEntries = 0;
63 pHashTable->freeFunc = freeFunc;
64 pHashTable->pEntries =
65 (HashEntry*) calloc((size_t)pHashTable->tableSize, sizeof(HashTable));
66 if (pHashTable->pEntries == NULL) {
67 free(pHashTable);
68 return NULL;
69 }
70
71 return pHashTable;
72}
73
74/*
75 * Clear out all entries.
76 */
77void mzHashTableClear(HashTable* pHashTable)
78{
79 HashEntry* pEnt;
80 int i;
81
82 pEnt = pHashTable->pEntries;
83 for (i = 0; i < pHashTable->tableSize; i++, pEnt++) {
84 if (pEnt->data == HASH_TOMBSTONE) {
85 // nuke entry
86 pEnt->data = NULL;
87 } else if (pEnt->data != NULL) {
88 // call free func then nuke entry
89 if (pHashTable->freeFunc != NULL)
90 (*pHashTable->freeFunc)(pEnt->data);
91 pEnt->data = NULL;
92 }
93 }
94
95 pHashTable->numEntries = 0;
96 pHashTable->numDeadEntries = 0;
97}
98
99/*
100 * Free the table.
101 */
102void mzHashTableFree(HashTable* pHashTable)
103{
104 if (pHashTable == NULL)
105 return;
106 mzHashTableClear(pHashTable);
107 free(pHashTable->pEntries);
108 free(pHashTable);
109}
110
111#ifndef NDEBUG
112/*
113 * Count up the number of tombstone entries in the hash table.
114 */
115static int countTombStones(HashTable* pHashTable)
116{
117 int i, count;
118
119 for (count = i = 0; i < pHashTable->tableSize; i++) {
120 if (pHashTable->pEntries[i].data == HASH_TOMBSTONE)
121 count++;
122 }
123 return count;
124}
125#endif
126
127/*
128 * Resize a hash table. We do this when adding an entry increased the
129 * size of the table beyond its comfy limit.
130 *
131 * This essentially requires re-inserting all elements into the new storage.
132 *
133 * If multiple threads can access the hash table, the table's lock should
134 * have been grabbed before issuing the "lookup+add" call that led to the
135 * resize, so we don't have a synchronization problem here.
136 */
137static bool resizeHash(HashTable* pHashTable, int newSize)
138{
139 HashEntry* pNewEntries;
140 int i;
141
142 assert(countTombStones(pHashTable) == pHashTable->numDeadEntries);
143
144 pNewEntries = (HashEntry*) calloc(newSize, sizeof(HashTable));
145 if (pNewEntries == NULL)
146 return false;
147
148 for (i = 0; i < pHashTable->tableSize; i++) {
149 void* data = pHashTable->pEntries[i].data;
150 if (data != NULL && data != HASH_TOMBSTONE) {
151 int hashValue = pHashTable->pEntries[i].hashValue;
152 int newIdx;
153
154 /* probe for new spot, wrapping around */
155 newIdx = hashValue & (newSize-1);
156 while (pNewEntries[newIdx].data != NULL)
157 newIdx = (newIdx + 1) & (newSize-1);
158
159 pNewEntries[newIdx].hashValue = hashValue;
160 pNewEntries[newIdx].data = data;
161 }
162 }
163
164 free(pHashTable->pEntries);
165 pHashTable->pEntries = pNewEntries;
166 pHashTable->tableSize = newSize;
167 pHashTable->numDeadEntries = 0;
168
169 assert(countTombStones(pHashTable) == 0);
170 return true;
171}
172
173/*
174 * Look up an entry.
175 *
176 * We probe on collisions, wrapping around the table.
177 */
178void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item,
179 HashCompareFunc cmpFunc, bool doAdd)
180{
181 HashEntry* pEntry;
182 HashEntry* pEnd;
183 void* result = NULL;
184
185 assert(pHashTable->tableSize > 0);
186 assert(item != HASH_TOMBSTONE);
187 assert(item != NULL);
188
189 /* jump to the first entry and probe for a match */
190 pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
191 pEnd = &pHashTable->pEntries[pHashTable->tableSize];
192 while (pEntry->data != NULL) {
193 if (pEntry->data != HASH_TOMBSTONE &&
194 pEntry->hashValue == itemHash &&
195 (*cmpFunc)(pEntry->data, item) == 0)
196 {
197 /* match */
198 break;
199 }
200
201 pEntry++;
202 if (pEntry == pEnd) { /* wrap around to start */
203 if (pHashTable->tableSize == 1)
204 break; /* edge case - single-entry table */
205 pEntry = pHashTable->pEntries;
206 }
207 }
208
209 if (pEntry->data == NULL) {
210 if (doAdd) {
211 pEntry->hashValue = itemHash;
212 pEntry->data = item;
213 pHashTable->numEntries++;
214
215 /*
216 * We've added an entry. See if this brings us too close to full.
217 */
218 if ((pHashTable->numEntries+pHashTable->numDeadEntries) * LOAD_DENOM
219 > pHashTable->tableSize * LOAD_NUMER)
220 {
221 if (!resizeHash(pHashTable, pHashTable->tableSize * 2)) {
222 /* don't really have a way to indicate failure */
223 LOG(FATAL) << "Hash resize failure";
224 }
225 /* note "pEntry" is now invalid */
226 }
227
228 /* full table is bad -- search for nonexistent never halts */
229 assert(pHashTable->numEntries < pHashTable->tableSize);
230 result = item;
231 } else {
232 assert(result == NULL);
233 }
234 } else {
235 result = pEntry->data;
236 }
237
238 return result;
239}
240
241/*
242 * Remove an entry from the table.
243 *
244 * Does NOT invoke the "free" function on the item.
245 */
246bool mzHashTableRemove(HashTable* pHashTable, unsigned int itemHash, void* item)
247{
248 HashEntry* pEntry;
249 HashEntry* pEnd;
250
251 assert(pHashTable->tableSize > 0);
252
253 /* jump to the first entry and probe for a match */
254 pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
255 pEnd = &pHashTable->pEntries[pHashTable->tableSize];
256 while (pEntry->data != NULL) {
257 if (pEntry->data == item) {
258 pEntry->data = HASH_TOMBSTONE;
259 pHashTable->numEntries--;
260 pHashTable->numDeadEntries++;
261 return true;
262 }
263
264 pEntry++;
265 if (pEntry == pEnd) { /* wrap around to start */
266 if (pHashTable->tableSize == 1)
267 break; /* edge case - single-entry table */
268 pEntry = pHashTable->pEntries;
269 }
270 }
271
272 return false;
273}
274
275/*
276 * Execute a function on every entry in the hash table.
277 *
278 * If "func" returns a nonzero value, terminate early and return the value.
279 */
280int mzHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg)
281{
282 int i, val;
283
284 for (i = 0; i < pHashTable->tableSize; i++) {
285 HashEntry* pEnt = &pHashTable->pEntries[i];
286
287 if (pEnt->data != NULL && pEnt->data != HASH_TOMBSTONE) {
288 val = (*func)(pEnt->data, arg);
289 if (val != 0)
290 return val;
291 }
292 }
293
294 return 0;
295}
296
297
298/*
299 * Look up an entry, counting the number of times we have to probe.
300 *
301 * Returns -1 if the entry wasn't found.
302 */
303int countProbes(HashTable* pHashTable, unsigned int itemHash, const void* item,
304 HashCompareFunc cmpFunc)
305{
306 HashEntry* pEntry;
307 HashEntry* pEnd;
308 int count = 0;
309
310 assert(pHashTable->tableSize > 0);
311 assert(item != HASH_TOMBSTONE);
312 assert(item != NULL);
313
314 /* jump to the first entry and probe for a match */
315 pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
316 pEnd = &pHashTable->pEntries[pHashTable->tableSize];
317 while (pEntry->data != NULL) {
318 if (pEntry->data != HASH_TOMBSTONE &&
319 pEntry->hashValue == itemHash &&
320 (*cmpFunc)(pEntry->data, item) == 0)
321 {
322 /* match */
323 break;
324 }
325
326 pEntry++;
327 if (pEntry == pEnd) { /* wrap around to start */
328 if (pHashTable->tableSize == 1)
329 break; /* edge case - single-entry table */
330 pEntry = pHashTable->pEntries;
331 }
332
333 count++;
334 }
335 if (pEntry->data == NULL)
336 return -1;
337
338 return count;
339}
340
341/*
342 * Evaluate the amount of probing required for the specified hash table.
343 *
344 * We do this by running through all entries in the hash table, computing
345 * the hash value and then doing a lookup.
346 *
347 * The caller should lock the table before calling here.
348 */
349void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
350 HashCompareFunc cmpFunc)
351{
352 int numEntries, minProbe, maxProbe, totalProbe;
353 HashIter iter;
354
355 numEntries = maxProbe = totalProbe = 0;
356 minProbe = 65536*32767;
357
358 for (mzHashIterBegin(pHashTable, &iter); !mzHashIterDone(&iter);
359 mzHashIterNext(&iter))
360 {
361 const void* data = (const void*)mzHashIterData(&iter);
362 int count;
363
364 count = countProbes(pHashTable, (*calcFunc)(data), data, cmpFunc);
365
366 numEntries++;
367
368 if (count < minProbe)
369 minProbe = count;
370 if (count > maxProbe)
371 maxProbe = count;
372 totalProbe += count;
373 }
374
375 LOG(VERBOSE) << "Probe: min=" << minProbe << ", max=" << maxProbe << ", total="
376 << totalProbe <<" in " << numEntries << " (" << pHashTable->tableSize
377 << "), avg=" << (float) totalProbe / (float) numEntries;
378}
diff --git a/minzip/Hash.h b/minzip/Hash.h
deleted file mode 100644
index e83eac41..00000000
--- a/minzip/Hash.h
+++ /dev/null
@@ -1,194 +0,0 @@
1/*
2 * Copyright 2007 The Android Open Source Project
3 *
4 * General purpose hash table, used for finding classes, methods, etc.
5 *
6 * When the number of elements reaches 3/4 of the table's capacity, the
7 * table will be resized.
8 */
9#ifndef _MINZIP_HASH
10#define _MINZIP_HASH
11
12#include "inline_magic.h"
13
14#include <stdlib.h>
15#include <stdbool.h>
16#include <assert.h>
17
18#ifdef __cplusplus
19extern "C" {
20#endif
21
22/* compute the hash of an item with a specific type */
23typedef unsigned int (*HashCompute)(const void* item);
24
25/*
26 * Compare a hash entry with a "loose" item after their hash values match.
27 * Returns { <0, 0, >0 } depending on ordering of items (same semantics
28 * as strcmp()).
29 */
30typedef int (*HashCompareFunc)(const void* tableItem, const void* looseItem);
31
32/*
33 * This function will be used to free entries in the table. This can be
34 * NULL if no free is required, free(), or a custom function.
35 */
36typedef void (*HashFreeFunc)(void* ptr);
37
38/*
39 * Used by mzHashForeach().
40 */
41typedef int (*HashForeachFunc)(void* data, void* arg);
42
43/*
44 * One entry in the hash table. "data" values are expected to be (or have
45 * the same characteristics as) valid pointers. In particular, a NULL
46 * value for "data" indicates an empty slot, and HASH_TOMBSTONE indicates
47 * a no-longer-used slot that must be stepped over during probing.
48 *
49 * Attempting to add a NULL or tombstone value is an error.
50 *
51 * When an entry is released, we will call (HashFreeFunc)(entry->data).
52 */
53typedef struct HashEntry {
54 unsigned int hashValue;
55 void* data;
56} HashEntry;
57
58#define HASH_TOMBSTONE ((void*) 0xcbcacccd) // invalid ptr value
59
60/*
61 * Expandable hash table.
62 *
63 * This structure should be considered opaque.
64 */
65typedef struct HashTable {
66 int tableSize; /* must be power of 2 */
67 int numEntries; /* current #of "live" entries */
68 int numDeadEntries; /* current #of tombstone entries */
69 HashEntry* pEntries; /* array on heap */
70 HashFreeFunc freeFunc;
71} HashTable;
72
73/*
74 * Create and initialize a HashTable structure, using "initialSize" as
75 * a basis for the initial capacity of the table. (The actual initial
76 * table size may be adjusted upward.) If you know exactly how many
77 * elements the table will hold, pass the result from mzHashSize() in.)
78 *
79 * Returns "false" if unable to allocate the table.
80 */
81HashTable* mzHashTableCreate(size_t initialSize, HashFreeFunc freeFunc);
82
83/*
84 * Compute the capacity needed for a table to hold "size" elements. Use
85 * this when you know ahead of time how many elements the table will hold.
86 * Pass this value into mzHashTableCreate() to ensure that you can add
87 * all elements without needing to reallocate the table.
88 */
89size_t mzHashSize(size_t size);
90
91/*
92 * Clear out a hash table, freeing the contents of any used entries.
93 */
94void mzHashTableClear(HashTable* pHashTable);
95
96/*
97 * Free a hash table.
98 */
99void mzHashTableFree(HashTable* pHashTable);
100
101/*
102 * Get #of entries in hash table.
103 */
104INLINE int mzHashTableNumEntries(HashTable* pHashTable) {
105 return pHashTable->numEntries;
106}
107
108/*
109 * Get total size of hash table (for memory usage calculations).
110 */
111INLINE int mzHashTableMemUsage(HashTable* pHashTable) {
112 return sizeof(HashTable) + pHashTable->tableSize * sizeof(HashEntry);
113}
114
115/*
116 * Look up an entry in the table, possibly adding it if it's not there.
117 *
118 * If "item" is not found, and "doAdd" is false, NULL is returned.
119 * Otherwise, a pointer to the found or added item is returned. (You can
120 * tell the difference by seeing if return value == item.)
121 *
122 * An "add" operation may cause the entire table to be reallocated.
123 */
124void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item,
125 HashCompareFunc cmpFunc, bool doAdd);
126
127/*
128 * Remove an item from the hash table, given its "data" pointer. Does not
129 * invoke the "free" function; just detaches it from the table.
130 */
131bool mzHashTableRemove(HashTable* pHashTable, unsigned int hash, void* item);
132
133/*
134 * Execute "func" on every entry in the hash table.
135 *
136 * If "func" returns a nonzero value, terminate early and return the value.
137 */
138int mzHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg);
139
140/*
141 * An alternative to mzHashForeach(), using an iterator.
142 *
143 * Use like this:
144 * HashIter iter;
145 * for (mzHashIterBegin(hashTable, &iter); !mzHashIterDone(&iter);
146 * mzHashIterNext(&iter))
147 * {
148 * MyData* data = (MyData*)mzHashIterData(&iter);
149 * }
150 */
151typedef struct HashIter {
152 void* data;
153 HashTable* pHashTable;
154 int idx;
155} HashIter;
156INLINE void mzHashIterNext(HashIter* pIter) {
157 int i = pIter->idx +1;
158 int lim = pIter->pHashTable->tableSize;
159 for ( ; i < lim; i++) {
160 void* data = pIter->pHashTable->pEntries[i].data;
161 if (data != NULL && data != HASH_TOMBSTONE)
162 break;
163 }
164 pIter->idx = i;
165}
166INLINE void mzHashIterBegin(HashTable* pHashTable, HashIter* pIter) {
167 pIter->pHashTable = pHashTable;
168 pIter->idx = -1;
169 mzHashIterNext(pIter);
170}
171INLINE bool mzHashIterDone(HashIter* pIter) {
172 return (pIter->idx >= pIter->pHashTable->tableSize);
173}
174INLINE void* mzHashIterData(HashIter* pIter) {
175 assert(pIter->idx >= 0 && pIter->idx < pIter->pHashTable->tableSize);
176 return pIter->pHashTable->pEntries[pIter->idx].data;
177}
178
179
180/*
181 * Evaluate hash table performance by examining the number of times we
182 * have to probe for an entry.
183 *
184 * The caller should lock the table beforehand.
185 */
186typedef unsigned int (*HashCalcFunc)(const void* item);
187void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
188 HashCompareFunc cmpFunc);
189
190#ifdef __cplusplus
191}
192#endif
193
194#endif /*_MINZIP_HASH*/
diff --git a/minzip/Inlines.c b/minzip/Inlines.c
deleted file mode 100644
index 91f87751..00000000
--- a/minzip/Inlines.c
+++ /dev/null
@@ -1,25 +0,0 @@
1/*
2 * Copyright (C) 2007 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/* Make sure that non-inlined versions of INLINED-marked functions
18 * exist so that debug builds (which don't generally do inlining)
19 * don't break.
20 */
21#define MINZIP_GENERATE_INLINES 1
22#include "Bits.h"
23#include "Hash.h"
24#include "SysUtil.h"
25#include "Zip.h"
diff --git a/minzip/Zip.cpp b/minzip/Zip.cpp
deleted file mode 100644
index b887b846..00000000
--- a/minzip/Zip.cpp
+++ /dev/null
@@ -1,1022 +0,0 @@
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Simple Zip file support.
5 */
6#include "safe_iop.h"
7#include "zlib.h"
8
9#include <errno.h>
10#include <fcntl.h>
11#include <limits.h>
12#include <stdint.h> // for uintptr_t
13#include <stdlib.h>
14#include <sys/stat.h> // for S_ISLNK()
15#include <unistd.h>
16
17#include <string>
18
19#include <android-base/logging.h>
20#include <android-base/stringprintf.h>
21#include <assert.h>
22#include <selinux/label.h>
23#include <selinux/selinux.h>
24
25#include "Zip.h"
26#include "Bits.h"
27#include "DirUtil.h"
28
29#define SORT_ENTRIES 1
30
31/*
32 * Offset and length constants (java.util.zip naming convention).
33 */
34enum {
35 CENSIG = 0x02014b50, // PK12
36 CENHDR = 46,
37
38 CENVEM = 4,
39 CENVER = 6,
40 CENFLG = 8,
41 CENHOW = 10,
42 CENTIM = 12,
43 CENCRC = 16,
44 CENSIZ = 20,
45 CENLEN = 24,
46 CENNAM = 28,
47 CENEXT = 30,
48 CENCOM = 32,
49 CENDSK = 34,
50 CENATT = 36,
51 CENATX = 38,
52 CENOFF = 42,
53
54 ENDSIG = 0x06054b50, // PK56
55 ENDHDR = 22,
56
57 ENDSUB = 8,
58 ENDTOT = 10,
59 ENDSIZ = 12,
60 ENDOFF = 16,
61 ENDCOM = 20,
62
63 EXTSIG = 0x08074b50, // PK78
64 EXTHDR = 16,
65
66 EXTCRC = 4,
67 EXTSIZ = 8,
68 EXTLEN = 12,
69
70 LOCSIG = 0x04034b50, // PK34
71 LOCHDR = 30,
72
73 LOCVER = 4,
74 LOCFLG = 6,
75 LOCHOW = 8,
76 LOCTIM = 10,
77 LOCCRC = 14,
78 LOCSIZ = 18,
79 LOCLEN = 22,
80 LOCNAM = 26,
81 LOCEXT = 28,
82
83 STORED = 0,
84 DEFLATED = 8,
85
86 CENVEM_UNIX = 3 << 8, // the high byte of CENVEM
87};
88
89
90/*
91 * For debugging, dump the contents of a ZipEntry.
92 */
93#if 0
94static void dumpEntry(const ZipEntry* pEntry)
95{
96 LOGI(" %p '%.*s'\n", pEntry->fileName,pEntry->fileNameLen,pEntry->fileName);
97 LOGI(" off=%u comp=%u uncomp=%u how=%d\n", pEntry->offset,
98 pEntry->compLen, pEntry->uncompLen, pEntry->compression);
99}
100#endif
101
102/*
103 * (This is a mzHashTableLookup callback.)
104 *
105 * Compare two ZipEntry structs, by name.
106 */
107static int hashcmpZipEntry(const void* ventry1, const void* ventry2)
108{
109 const ZipEntry* entry1 = (const ZipEntry*) ventry1;
110 const ZipEntry* entry2 = (const ZipEntry*) ventry2;
111
112 if (entry1->fileNameLen != entry2->fileNameLen)
113 return entry1->fileNameLen - entry2->fileNameLen;
114 return memcmp(entry1->fileName, entry2->fileName, entry1->fileNameLen);
115}
116
117/*
118 * (This is a mzHashTableLookup callback.)
119 *
120 * find a ZipEntry struct by name.
121 */
122static int hashcmpZipName(const void* ventry, const void* vname)
123{
124 const ZipEntry* entry = (const ZipEntry*) ventry;
125 const char* name = (const char*) vname;
126 unsigned int nameLen = strlen(name);
127
128 if (entry->fileNameLen != nameLen)
129 return entry->fileNameLen - nameLen;
130 return memcmp(entry->fileName, name, nameLen);
131}
132
133/*
134 * Compute the hash code for a ZipEntry filename.
135 *
136 * Not expected to be compatible with any other hash function, so we init
137 * to 2 to ensure it doesn't happen to match.
138 */
139static unsigned int computeHash(const char* name, int nameLen)
140{
141 unsigned int hash = 2;
142
143 while (nameLen--)
144 hash = hash * 31 + *name++;
145
146 return hash;
147}
148
149static void addEntryToHashTable(HashTable* pHash, ZipEntry* pEntry)
150{
151 unsigned int itemHash = computeHash(pEntry->fileName, pEntry->fileNameLen);
152 const ZipEntry* found;
153
154 found = (const ZipEntry*)mzHashTableLookup(pHash,
155 itemHash, pEntry, hashcmpZipEntry, true);
156 if (found != pEntry) {
157 LOG(WARNING) << "WARNING: duplicate entry '" << std::string(found->fileName,
158 found->fileNameLen) << "' in Zip";
159
160 /* keep going */
161 }
162}
163
164static int validFilename(const char *fileName, unsigned int fileNameLen)
165{
166 // Forbid super long filenames.
167 if (fileNameLen >= PATH_MAX) {
168 LOG(WARNING) << "Filename too long (" << fileNameLen << " chatacters)";
169 return 0;
170 }
171
172 // Require all characters to be printable ASCII (no NUL, no UTF-8, etc).
173 unsigned int i;
174 for (i = 0; i < fileNameLen; ++i) {
175 if (fileName[i] < 32 || fileName[i] >= 127) {
176 LOG(WARNING) << android::base::StringPrintf(
177 "Filename contains invalid character '\%02x'\n", fileName[i]);
178 return 0;
179 }
180 }
181
182 return 1;
183}
184
185/*
186 * Parse the contents of a Zip archive. After confirming that the file
187 * is in fact a Zip, we scan out the contents of the central directory and
188 * store it in a hash table.
189 *
190 * Returns "true" on success.
191 */
192static bool parseZipArchive(ZipArchive* pArchive)
193{
194 bool result = false;
195 const unsigned char* ptr;
196 unsigned int i, numEntries, cdOffset;
197 unsigned int val;
198
199 /*
200 * The first 4 bytes of the file will either be the local header
201 * signature for the first file (LOCSIG) or, if the archive doesn't
202 * have any files in it, the end-of-central-directory signature (ENDSIG).
203 */
204 val = get4LE(pArchive->addr);
205 if (val == ENDSIG) {
206 LOG(WARNING) << "Found Zip archive, but it looks empty";
207 goto bail;
208 } else if (val != LOCSIG) {
209 LOG(WARNING) << android::base::StringPrintf("Not a Zip archive (found 0x%08x)\n", val);
210 goto bail;
211 }
212
213 /*
214 * Find the EOCD. We'll find it immediately unless they have a file
215 * comment.
216 */
217 ptr = pArchive->addr + pArchive->length - ENDHDR;
218
219 while (ptr >= (const unsigned char*) pArchive->addr) {
220 if (*ptr == (ENDSIG & 0xff) && get4LE(ptr) == ENDSIG)
221 break;
222 ptr--;
223 }
224 if (ptr < (const unsigned char*) pArchive->addr) {
225 LOG(WARNING) << "Could not find end-of-central-directory in Zip";
226 goto bail;
227 }
228
229 /*
230 * There are two interesting items in the EOCD block: the number of
231 * entries in the file, and the file offset of the start of the
232 * central directory.
233 */
234 numEntries = get2LE(ptr + ENDSUB);
235 cdOffset = get4LE(ptr + ENDOFF);
236
237 LOG(VERBOSE) << "numEntries=" << numEntries << " cdOffset=" << cdOffset;
238 if (numEntries == 0 || cdOffset >= pArchive->length) {
239 LOG(WARNING) << "Invalid entries=" << numEntries << " offset=" << cdOffset
240 << " (len=" << pArchive->length << ")";
241 goto bail;
242 }
243
244 /*
245 * Create data structures to hold entries.
246 */
247 pArchive->numEntries = numEntries;
248 pArchive->pEntries = (ZipEntry*) calloc(numEntries, sizeof(ZipEntry));
249 pArchive->pHash = mzHashTableCreate(mzHashSize(numEntries), NULL);
250 if (pArchive->pEntries == NULL || pArchive->pHash == NULL)
251 goto bail;
252
253 ptr = pArchive->addr + cdOffset;
254 for (i = 0; i < numEntries; i++) {
255 ZipEntry* pEntry;
256 unsigned int fileNameLen, extraLen, commentLen, localHdrOffset;
257 const unsigned char* localHdr;
258 const char *fileName;
259
260 if (ptr + CENHDR > (const unsigned char*)pArchive->addr + pArchive->length) {
261 LOG(WARNING) << "Ran off the end (at " << i << ")";
262 goto bail;
263 }
264 if (get4LE(ptr) != CENSIG) {
265 LOG(WARNING) << "Missed a central dir sig (at " << i << ")";
266 goto bail;
267 }
268
269 localHdrOffset = get4LE(ptr + CENOFF);
270 fileNameLen = get2LE(ptr + CENNAM);
271 extraLen = get2LE(ptr + CENEXT);
272 commentLen = get2LE(ptr + CENCOM);
273 fileName = (const char*)ptr + CENHDR;
274 if (fileName + fileNameLen > (const char*)pArchive->addr + pArchive->length) {
275 LOG(WARNING) << "Filename ran off the end (at " << i << ")";
276 goto bail;
277 }
278 if (!validFilename(fileName, fileNameLen)) {
279 LOG(WARNING) << "Invalid filename (at " << i << ")";
280 goto bail;
281 }
282
283#if SORT_ENTRIES
284 /* Figure out where this entry should go (binary search).
285 */
286 if (i > 0) {
287 int low, high;
288
289 low = 0;
290 high = i - 1;
291 while (low <= high) {
292 int mid;
293 int diff;
294 int diffLen;
295
296 mid = low + ((high - low) / 2); // avoid overflow
297
298 if (pArchive->pEntries[mid].fileNameLen < fileNameLen) {
299 diffLen = pArchive->pEntries[mid].fileNameLen;
300 } else {
301 diffLen = fileNameLen;
302 }
303 diff = strncmp(pArchive->pEntries[mid].fileName, fileName,
304 diffLen);
305 if (diff == 0) {
306 diff = pArchive->pEntries[mid].fileNameLen - fileNameLen;
307 }
308 if (diff < 0) {
309 low = mid + 1;
310 } else if (diff > 0) {
311 high = mid - 1;
312 } else {
313 high = mid;
314 break;
315 }
316 }
317
318 unsigned int target = high + 1;
319 assert(target <= i);
320 if (target != i) {
321 /* It belongs somewhere other than at the end of
322 * the list. Make some room at [target].
323 */
324 memmove(pArchive->pEntries + target + 1,
325 pArchive->pEntries + target,
326 (i - target) * sizeof(ZipEntry));
327 }
328 pEntry = &pArchive->pEntries[target];
329 } else {
330 pEntry = &pArchive->pEntries[0];
331 }
332#else
333 pEntry = &pArchive->pEntries[i];
334#endif
335 pEntry->fileNameLen = fileNameLen;
336 pEntry->fileName = fileName;
337
338 pEntry->compLen = get4LE(ptr + CENSIZ);
339 pEntry->uncompLen = get4LE(ptr + CENLEN);
340 pEntry->compression = get2LE(ptr + CENHOW);
341 pEntry->modTime = get4LE(ptr + CENTIM);
342 pEntry->crc32 = get4LE(ptr + CENCRC);
343
344 /* These two are necessary for finding the mode of the file.
345 */
346 pEntry->versionMadeBy = get2LE(ptr + CENVEM);
347 if ((pEntry->versionMadeBy & 0xff00) != 0 &&
348 (pEntry->versionMadeBy & 0xff00) != CENVEM_UNIX)
349 {
350 LOG(WARNING) << android::base::StringPrintf(
351 "Incompatible \"version made by\": 0x%02x (at %d)\n",
352 pEntry->versionMadeBy >> 8, i);
353 goto bail;
354 }
355 pEntry->externalFileAttributes = get4LE(ptr + CENATX);
356
357 // Perform pArchive->addr + localHdrOffset, ensuring that it won't
358 // overflow. This is needed because localHdrOffset is untrusted.
359 if (!safe_add((uintptr_t *)&localHdr, (uintptr_t)pArchive->addr,
360 (uintptr_t)localHdrOffset)) {
361 LOG(WARNING) << "Integer overflow adding in parseZipArchive";
362 goto bail;
363 }
364 if ((uintptr_t)localHdr + LOCHDR >
365 (uintptr_t)pArchive->addr + pArchive->length) {
366 LOG(WARNING) << "Bad offset to local header: " << localHdrOffset
367 << " (at " << i << ")";
368 goto bail;
369 }
370 if (get4LE(localHdr) != LOCSIG) {
371 LOG(WARNING) << "Missed a local header sig (at " << i << ")";
372 goto bail;
373 }
374 pEntry->offset = localHdrOffset + LOCHDR
375 + get2LE(localHdr + LOCNAM) + get2LE(localHdr + LOCEXT);
376 if (!safe_add(NULL, pEntry->offset, pEntry->compLen)) {
377 LOG(WARNING) << "Integer overflow adding in parseZipArchive";
378 goto bail;
379 }
380 if ((size_t)pEntry->offset + pEntry->compLen > pArchive->length) {
381 LOG(WARNING) << "Data ran off the end (at " << i << ")";
382 goto bail;
383 }
384
385#if !SORT_ENTRIES
386 /* Add to hash table; no need to lock here.
387 * Can't do this now if we're sorting, because entries
388 * will move around.
389 */
390 addEntryToHashTable(pArchive->pHash, pEntry);
391#endif
392
393 //dumpEntry(pEntry);
394 ptr += CENHDR + fileNameLen + extraLen + commentLen;
395 }
396
397#if SORT_ENTRIES
398 /* If we're sorting, we have to wait until all entries
399 * are in their final places, otherwise the pointers will
400 * probably point to the wrong things.
401 */
402 for (i = 0; i < numEntries; i++) {
403 /* Add to hash table; no need to lock here.
404 */
405 addEntryToHashTable(pArchive->pHash, &pArchive->pEntries[i]);
406 }
407#endif
408
409 result = true;
410
411bail:
412 if (!result) {
413 mzHashTableFree(pArchive->pHash);
414 pArchive->pHash = NULL;
415 }
416 return result;
417}
418
419/*
420 * Open a Zip archive and scan out the contents.
421 *
422 * The easiest way to do this is to mmap() the whole thing and do the
423 * traditional backward scan for central directory. Since the EOCD is
424 * a relatively small bit at the end, we should end up only touching a
425 * small set of pages.
426 *
427 * This will be called on non-Zip files, especially during startup, so
428 * we don't want to be too noisy about failures. (Do we want a "quiet"
429 * flag?)
430 *
431 * On success, we fill out the contents of "pArchive".
432 */
433int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive)
434{
435 int err;
436
437 if (length < ENDHDR) {
438 err = -1;
439 LOG(WARNING) << "Archive " << pArchive << " is too small to be zip ("
440 << length << ")";
441 goto bail;
442 }
443
444 pArchive->addr = addr;
445 pArchive->length = length;
446
447 if (!parseZipArchive(pArchive)) {
448 err = -1;
449 LOG(WARNING) << "Parsing archive " << pArchive << " failed";
450 goto bail;
451 }
452
453 err = 0;
454
455bail:
456 if (err != 0)
457 mzCloseZipArchive(pArchive);
458 return err;
459}
460
461/*
462 * Close a ZipArchive, closing the file and freeing the contents.
463 *
464 * NOTE: the ZipArchive may not have been fully created.
465 */
466void mzCloseZipArchive(ZipArchive* pArchive)
467{
468 LOG(VERBOSE) << "Closing archive " << pArchive;
469
470 free(pArchive->pEntries);
471
472 mzHashTableFree(pArchive->pHash);
473
474 pArchive->pHash = NULL;
475 pArchive->pEntries = NULL;
476}
477
478/*
479 * Find a matching entry.
480 *
481 * Returns NULL if no matching entry found.
482 */
483const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive,
484 const char* entryName)
485{
486 unsigned int itemHash = computeHash(entryName, strlen(entryName));
487
488 return (const ZipEntry*)mzHashTableLookup(pArchive->pHash,
489 itemHash, (char*) entryName, hashcmpZipName, false);
490}
491
492/*
493 * Return true if the entry is a symbolic link.
494 */
495static bool mzIsZipEntrySymlink(const ZipEntry* pEntry)
496{
497 if ((pEntry->versionMadeBy & 0xff00) == CENVEM_UNIX) {
498 return S_ISLNK(pEntry->externalFileAttributes >> 16);
499 }
500 return false;
501}
502
503/* Call processFunction on the uncompressed data of a STORED entry.
504 */
505static bool processStoredEntry(const ZipArchive *pArchive,
506 const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
507 void *cookie)
508{
509 return processFunction(pArchive->addr + pEntry->offset, pEntry->uncompLen, cookie);
510}
511
512static bool processDeflatedEntry(const ZipArchive *pArchive,
513 const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
514 void *cookie)
515{
516 bool success = false;
517 unsigned long totalOut = 0;
518 unsigned char procBuf[32 * 1024];
519 z_stream zstream;
520 int zerr;
521
522 /*
523 * Initialize the zlib stream.
524 */
525 memset(&zstream, 0, sizeof(zstream));
526 zstream.zalloc = Z_NULL;
527 zstream.zfree = Z_NULL;
528 zstream.opaque = Z_NULL;
529 zstream.next_in = pArchive->addr + pEntry->offset;
530 zstream.avail_in = pEntry->compLen;
531 zstream.next_out = (Bytef*) procBuf;
532 zstream.avail_out = sizeof(procBuf);
533 zstream.data_type = Z_UNKNOWN;
534
535 /*
536 * Use the undocumented "negative window bits" feature to tell zlib
537 * that there's no zlib header waiting for it.
538 */
539 zerr = inflateInit2(&zstream, -MAX_WBITS);
540 if (zerr != Z_OK) {
541 if (zerr == Z_VERSION_ERROR) {
542 LOG(ERROR) << "Installed zlib is not compatible with linked version ("
543 << ZLIB_VERSION << ")";
544 } else {
545 LOG(ERROR) << "Call to inflateInit2 failed (zerr=" << zerr << ")";
546 }
547 goto bail;
548 }
549
550 /*
551 * Loop while we have data.
552 */
553 do {
554 /* uncompress the data */
555 zerr = inflate(&zstream, Z_NO_FLUSH);
556 if (zerr != Z_OK && zerr != Z_STREAM_END) {
557 LOG(WARNING) << "zlib inflate call failed (zerr=" << zerr << ")";
558 goto z_bail;
559 }
560
561 /* write when we're full or when we're done */
562 if (zstream.avail_out == 0 ||
563 (zerr == Z_STREAM_END && zstream.avail_out != sizeof(procBuf)))
564 {
565 long procSize = zstream.next_out - procBuf;
566 LOG(VERBOSE) << "+++ processing " << procSize << " bytes";
567 bool ret = processFunction(procBuf, procSize, cookie);
568 if (!ret) {
569 LOG(WARNING) << "Process function elected to fail (in inflate)";
570 goto z_bail;
571 }
572
573 zstream.next_out = procBuf;
574 zstream.avail_out = sizeof(procBuf);
575 }
576 } while (zerr == Z_OK);
577
578 assert(zerr == Z_STREAM_END); /* other errors should've been caught */
579
580 // success!
581 totalOut = zstream.total_out;
582 success = true;
583
584z_bail:
585 inflateEnd(&zstream); /* free up any allocated structures */
586
587bail:
588 if (totalOut != pEntry->uncompLen) {
589 if (success) { // error already shown?
590 LOG(WARNING) << "Size mismatch on inflated file (" << totalOut << " vs "
591 << pEntry->uncompLen << ")";
592 }
593 return false;
594 }
595 return true;
596}
597
598/*
599 * Stream the uncompressed data through the supplied function,
600 * passing cookie to it each time it gets called. processFunction
601 * may be called more than once.
602 *
603 * If processFunction returns false, the operation is abandoned and
604 * mzProcessZipEntryContents() immediately returns false.
605 *
606 * This is useful for calculating the hash of an entry's uncompressed contents.
607 */
608bool mzProcessZipEntryContents(const ZipArchive *pArchive,
609 const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
610 void *cookie)
611{
612 bool ret = false;
613
614 switch (pEntry->compression) {
615 case STORED:
616 ret = processStoredEntry(pArchive, pEntry, processFunction, cookie);
617 break;
618 case DEFLATED:
619 ret = processDeflatedEntry(pArchive, pEntry, processFunction, cookie);
620 break;
621 default:
622 LOG(ERROR) << "Unsupported compression type " << pEntry->compression
623 << " for entry '" << pEntry->fileName << "'";
624 break;
625 }
626
627 return ret;
628}
629
630typedef struct {
631 char *buf;
632 int bufLen;
633} CopyProcessArgs;
634
635static bool copyProcessFunction(const unsigned char *data, int dataLen,
636 void *cookie)
637{
638 CopyProcessArgs *args = (CopyProcessArgs *)cookie;
639 if (dataLen <= args->bufLen) {
640 memcpy(args->buf, data, dataLen);
641 args->buf += dataLen;
642 args->bufLen -= dataLen;
643 return true;
644 }
645 return false;
646}
647
648/*
649 * Read an entry into a buffer allocated by the caller.
650 */
651bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry,
652 char *buf, int bufLen)
653{
654 CopyProcessArgs args;
655 bool ret;
656
657 args.buf = buf;
658 args.bufLen = bufLen;
659 ret = mzProcessZipEntryContents(pArchive, pEntry, copyProcessFunction,
660 (void *)&args);
661 if (!ret) {
662 LOG(ERROR) << "Can't extract entry to buffer";
663 return false;
664 }
665 return true;
666}
667
668static bool writeProcessFunction(const unsigned char *data, int dataLen,
669 void *cookie)
670{
671 int fd = (int)(intptr_t)cookie;
672 if (dataLen == 0) {
673 return true;
674 }
675 ssize_t soFar = 0;
676 while (true) {
677 ssize_t n = TEMP_FAILURE_RETRY(write(fd, data+soFar, dataLen-soFar));
678 if (n <= 0) {
679 PLOG(ERROR) << "Error writing " << dataLen-soFar << " bytes from zip file from "
680 << data+soFar;
681 return false;
682 } else if (n > 0) {
683 soFar += n;
684 if (soFar == dataLen) return true;
685 if (soFar > dataLen) {
686 LOG(ERROR) << "write overrun? (" << soFar << " bytes instead of "
687 << dataLen << ")";
688 return false;
689 }
690 }
691 }
692}
693
694/*
695 * Uncompress "pEntry" in "pArchive" to "fd" at the current offset.
696 */
697bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
698 const ZipEntry *pEntry, int fd)
699{
700 bool ret = mzProcessZipEntryContents(pArchive, pEntry, writeProcessFunction,
701 (void*)(intptr_t)fd);
702 if (!ret) {
703 LOG(ERROR) << "Can't extract entry to file.";
704 return false;
705 }
706 return true;
707}
708
709typedef struct {
710 unsigned char* buffer;
711 long len;
712} BufferExtractCookie;
713
714static bool bufferProcessFunction(const unsigned char *data, int dataLen,
715 void *cookie) {
716 BufferExtractCookie *bec = (BufferExtractCookie*)cookie;
717
718 memmove(bec->buffer, data, dataLen);
719 bec->buffer += dataLen;
720 bec->len -= dataLen;
721
722 return true;
723}
724
725/*
726 * Uncompress "pEntry" in "pArchive" to buffer, which must be large
727 * enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
728 */
729bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
730 const ZipEntry *pEntry, unsigned char *buffer)
731{
732 BufferExtractCookie bec;
733 bec.buffer = buffer;
734 bec.len = mzGetZipEntryUncompLen(pEntry);
735
736 bool ret = mzProcessZipEntryContents(pArchive, pEntry,
737 bufferProcessFunction, (void*)&bec);
738 if (!ret || bec.len != 0) {
739 LOG(ERROR) << "Can't extract entry to memory buffer.";
740 return false;
741 }
742 return true;
743}
744
745
746/* Helper state to make path translation easier and less malloc-happy.
747 */
748typedef struct {
749 const char *targetDir;
750 const char *zipDir;
751 char *buf;
752 int targetDirLen;
753 int zipDirLen;
754 int bufLen;
755} MzPathHelper;
756
757/* Given the values of targetDir and zipDir in the helper,
758 * return the target filename of the provided entry.
759 * The helper must be initialized first.
760 */
761static const char *targetEntryPath(MzPathHelper *helper, ZipEntry *pEntry)
762{
763 int needLen;
764 bool firstTime = (helper->buf == NULL);
765
766 /* target file <-- targetDir + / + entry[zipDirLen:]
767 */
768 needLen = helper->targetDirLen + 1 +
769 pEntry->fileNameLen - helper->zipDirLen + 1;
770 if (firstTime || needLen > helper->bufLen) {
771 char *newBuf;
772
773 needLen *= 2;
774 newBuf = (char *)realloc(helper->buf, needLen);
775 if (newBuf == NULL) {
776 return NULL;
777 }
778 helper->buf = newBuf;
779 helper->bufLen = needLen;
780 }
781
782 /* Every path will start with the target path and a slash.
783 */
784 if (firstTime) {
785 char *p = helper->buf;
786 memcpy(p, helper->targetDir, helper->targetDirLen);
787 p += helper->targetDirLen;
788 if (p == helper->buf || p[-1] != '/') {
789 helper->targetDirLen += 1;
790 *p++ = '/';
791 }
792 }
793
794 /* Replace the custom part of the path with the appropriate
795 * part of the entry's path.
796 */
797 char *epath = helper->buf + helper->targetDirLen;
798 memcpy(epath, pEntry->fileName + helper->zipDirLen,
799 pEntry->fileNameLen - helper->zipDirLen);
800 epath += pEntry->fileNameLen - helper->zipDirLen;
801 *epath = '\0';
802
803 return helper->buf;
804}
805
806/*
807 * Inflate all entries under zipDir to the directory specified by
808 * targetDir, which must exist and be a writable directory.
809 *
810 * The immediate children of zipDir will become the immediate
811 * children of targetDir; e.g., if the archive contains the entries
812 *
813 * a/b/c/one
814 * a/b/c/two
815 * a/b/c/d/three
816 *
817 * and mzExtractRecursive(a, "a/b/c", "/tmp") is called, the resulting
818 * files will be
819 *
820 * /tmp/one
821 * /tmp/two
822 * /tmp/d/three
823 *
824 * Returns true on success, false on failure.
825 */
826bool mzExtractRecursive(const ZipArchive *pArchive,
827 const char *zipDir, const char *targetDir,
828 const struct utimbuf *timestamp,
829 void (*callback)(const char *fn, void *), void *cookie,
830 struct selabel_handle *sehnd)
831{
832 if (zipDir[0] == '/') {
833 LOG(ERROR) << "mzExtractRecursive(): zipDir must be a relative path.";
834 return false;
835 }
836 if (targetDir[0] != '/') {
837 LOG(ERROR) << "mzExtractRecursive(): targetDir must be an absolute path.\n";
838 return false;
839 }
840
841 unsigned int zipDirLen;
842 char *zpath;
843
844 zipDirLen = strlen(zipDir);
845 zpath = (char *)malloc(zipDirLen + 2);
846 if (zpath == NULL) {
847 LOG(ERROR) << "Can't allocate " << (zipDirLen + 2) << " bytes for zip path";
848 return false;
849 }
850 /* If zipDir is empty, we'll extract the entire zip file.
851 * Otherwise, canonicalize the path.
852 */
853 if (zipDirLen > 0) {
854 /* Make sure there's (hopefully, exactly one) slash at the
855 * end of the path. This way we don't need to worry about
856 * accidentally extracting "one/twothree" when a path like
857 * "one/two" is specified.
858 */
859 memcpy(zpath, zipDir, zipDirLen);
860 if (zpath[zipDirLen-1] != '/') {
861 zpath[zipDirLen++] = '/';
862 }
863 }
864 zpath[zipDirLen] = '\0';
865
866 /* Set up the helper structure that we'll use to assemble paths.
867 */
868 MzPathHelper helper;
869 helper.targetDir = targetDir;
870 helper.targetDirLen = strlen(helper.targetDir);
871 helper.zipDir = zpath;
872 helper.zipDirLen = strlen(helper.zipDir);
873 helper.buf = NULL;
874 helper.bufLen = 0;
875
876 /* Walk through the entries and extract anything whose path begins
877 * with zpath.
878 //TODO: since the entries are sorted, binary search for the first match
879 // and stop after the first non-match.
880 */
881 unsigned int i;
882 bool seenMatch = false;
883 int ok = true;
884 int extractCount = 0;
885 for (i = 0; i < pArchive->numEntries; i++) {
886 ZipEntry *pEntry = pArchive->pEntries + i;
887 if (pEntry->fileNameLen < zipDirLen) {
888 //TODO: look out for a single empty directory entry that matches zpath, but
889 // missing the trailing slash. Most zip files seem to include
890 // the trailing slash, but I think it's legal to leave it off.
891 // e.g., zpath "a/b/", entry "a/b", with no children of the entry.
892 /* No chance of matching.
893 */
894#if SORT_ENTRIES
895 if (seenMatch) {
896 /* Since the entries are sorted, we can give up
897 * on the first mismatch after the first match.
898 */
899 break;
900 }
901#endif
902 continue;
903 }
904 /* If zpath is empty, this strncmp() will match everything,
905 * which is what we want.
906 */
907 if (strncmp(pEntry->fileName, zpath, zipDirLen) != 0) {
908#if SORT_ENTRIES
909 if (seenMatch) {
910 /* Since the entries are sorted, we can give up
911 * on the first mismatch after the first match.
912 */
913 break;
914 }
915#endif
916 continue;
917 }
918 /* This entry begins with zipDir, so we'll extract it.
919 */
920 seenMatch = true;
921
922 /* Find the target location of the entry.
923 */
924 const char *targetFile = targetEntryPath(&helper, pEntry);
925 if (targetFile == NULL) {
926 LOG(ERROR) << "Can't assemble target path for \"" << std::string(pEntry->fileName,
927 pEntry->fileNameLen) << "\"";
928 ok = false;
929 break;
930 }
931
932#define UNZIP_DIRMODE 0755
933#define UNZIP_FILEMODE 0644
934 /*
935 * Create the file or directory. We ignore directory entries
936 * because we recursively create paths to each file entry we encounter
937 * in the zip archive anyway.
938 *
939 * NOTE: A "directory entry" in a zip archive is just a zero length
940 * entry that ends in a "/". They're not mandatory and many tools get
941 * rid of them. We need to process them only if we want to preserve
942 * empty directories from the archive.
943 */
944 if (pEntry->fileName[pEntry->fileNameLen-1] != '/') {
945 /* This is not a directory. First, make sure that
946 * the containing directory exists.
947 */
948 int ret = dirCreateHierarchy(
949 targetFile, UNZIP_DIRMODE, timestamp, true, sehnd);
950 if (ret != 0) {
951 PLOG(ERROR) << "Can't create containing directory for \"" << targetFile << "\"";
952 ok = false;
953 break;
954 }
955
956 /*
957 * The entry is a regular file or a symlink. Open the target for writing.
958 *
959 * TODO: This behavior for symlinks seems rather bizarre. For a
960 * symlink foo/bar/baz -> foo/tar/taz, we will create a file called
961 * "foo/bar/baz" whose contents are the literal "foo/tar/taz". We
962 * warn about this for now and preserve older behavior.
963 */
964 if (mzIsZipEntrySymlink(pEntry)) {
965 LOG(ERROR) << "Symlink entry \"" << std::string(pEntry->fileName,
966 pEntry->fileNameLen) << "\" will be output as a regular file.";
967 }
968
969 char *secontext = NULL;
970
971 if (sehnd) {
972 selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE);
973 setfscreatecon(secontext);
974 }
975
976 int fd = open(targetFile, O_CREAT|O_WRONLY|O_TRUNC,
977 UNZIP_FILEMODE);
978
979 if (secontext) {
980 freecon(secontext);
981 setfscreatecon(NULL);
982 }
983
984 if (fd < 0) {
985 PLOG(ERROR) << "Can't create target file \"" << targetFile << "\"";
986 ok = false;
987 break;
988 }
989
990 bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd);
991 if (ok) {
992 ok = (fsync(fd) == 0);
993 }
994 if (close(fd) != 0) {
995 ok = false;
996 }
997 if (!ok) {
998 LOG(ERROR) << "Error extracting \"" << targetFile << "\"";
999 ok = false;
1000 break;
1001 }
1002
1003 if (timestamp != NULL && utime(targetFile, timestamp)) {
1004 LOG(ERROR) << "Error touching \"" << targetFile << "\"";
1005 ok = false;
1006 break;
1007 }
1008
1009 LOG(VERBOSE) <<"Extracted file \"" << targetFile << "\"";
1010 ++extractCount;
1011 }
1012
1013 if (callback != NULL) callback(targetFile, cookie);
1014 }
1015
1016 LOG(VERBOSE) << "Extracted " << extractCount << " file(s)";
1017
1018 free(helper.buf);
1019 free(zpath);
1020
1021 return ok;
1022}
diff --git a/minzip/Zip.h b/minzip/Zip.h
deleted file mode 100644
index c932c117..00000000
--- a/minzip/Zip.h
+++ /dev/null
@@ -1,171 +0,0 @@
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Simple Zip archive support.
5 */
6#ifndef _MINZIP_ZIP
7#define _MINZIP_ZIP
8
9#include "inline_magic.h"
10
11#include <stdlib.h>
12#include <utime.h>
13
14#include "Hash.h"
15#include "SysUtil.h"
16
17#ifdef __cplusplus
18extern "C" {
19#endif
20
21struct selabel_handle;
22
23/*
24 * One entry in the Zip archive. Treat this as opaque -- use accessors below.
25 *
26 * TODO: we're now keeping the pages mapped so we don't have to copy the
27 * filename. We can change the accessors to retrieve the various pieces
28 * directly from the source file instead of copying them out, for a very
29 * slight speed hit and a modest reduction in memory usage.
30 */
31typedef struct ZipEntry {
32 unsigned int fileNameLen;
33 const char* fileName; // not null-terminated
34 uint32_t offset;
35 uint32_t compLen;
36 uint32_t uncompLen;
37 int compression;
38 long modTime;
39 long crc32;
40 int versionMadeBy;
41 long externalFileAttributes;
42} ZipEntry;
43
44/*
45 * One Zip archive. Treat as opaque.
46 */
47typedef struct ZipArchive {
48 unsigned int numEntries;
49 ZipEntry* pEntries;
50 HashTable* pHash; // maps file name to ZipEntry
51 unsigned char* addr;
52 size_t length;
53} ZipArchive;
54
55/*
56 * Represents a non-NUL-terminated string,
57 * which is how entry names are stored.
58 */
59typedef struct {
60 const char *str;
61 size_t len;
62} UnterminatedString;
63
64/*
65 * Open a Zip archive.
66 *
67 * On success, returns 0 and populates "pArchive". Returns nonzero errno
68 * value on failure.
69 */
70int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive);
71
72/*
73 * Close archive, releasing resources associated with it.
74 *
75 * Depending on the implementation this could unmap pages used by classes
76 * stored in a Jar. This should only be done after unloading classes.
77 */
78void mzCloseZipArchive(ZipArchive* pArchive);
79
80
81/*
82 * Find an entry in the Zip archive, by name.
83 */
84const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive,
85 const char* entryName);
86
87INLINE uint32_t mzGetZipEntryOffset(const ZipEntry* pEntry) {
88 return pEntry->offset;
89}
90INLINE uint32_t mzGetZipEntryUncompLen(const ZipEntry* pEntry) {
91 return pEntry->uncompLen;
92}
93
94/*
95 * Type definition for the callback function used by
96 * mzProcessZipEntryContents().
97 */
98typedef bool (*ProcessZipEntryContentsFunction)(const unsigned char *data,
99 int dataLen, void *cookie);
100
101/*
102 * Stream the uncompressed data through the supplied function,
103 * passing cookie to it each time it gets called. processFunction
104 * may be called more than once.
105 *
106 * If processFunction returns false, the operation is abandoned and
107 * mzProcessZipEntryContents() immediately returns false.
108 *
109 * This is useful for calculating the hash of an entry's uncompressed contents.
110 */
111bool mzProcessZipEntryContents(const ZipArchive *pArchive,
112 const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
113 void *cookie);
114
115/*
116 * Read an entry into a buffer allocated by the caller.
117 */
118bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry,
119 char* buf, int bufLen);
120
121/*
122 * Inflate and write an entry to a file.
123 */
124bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
125 const ZipEntry *pEntry, int fd);
126
127/*
128 * Inflate and write an entry to a memory buffer, which must be long
129 * enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
130 */
131bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
132 const ZipEntry *pEntry, unsigned char* buffer);
133
134/*
135 * Inflate all files under zipDir to the directory specified by
136 * targetDir, which must exist and be a writable directory.
137 *
138 * Directory entries and symlinks are not extracted.
139 *
140 *
141 * The immediate children of zipDir will become the immediate
142 * children of targetDir; e.g., if the archive contains the entries
143 *
144 * a/b/c/one
145 * a/b/c/two
146 * a/b/c/d/three
147 *
148 * and mzExtractRecursive(a, "a/b/c", "/tmp", ...) is called, the resulting
149 * files will be
150 *
151 * /tmp/one
152 * /tmp/two
153 * /tmp/d/three
154 *
155 * If timestamp is non-NULL, file timestamps will be set accordingly.
156 *
157 * If callback is non-NULL, it will be invoked with each unpacked file.
158 *
159 * Returns true on success, false on failure.
160 */
161bool mzExtractRecursive(const ZipArchive *pArchive,
162 const char *zipDir, const char *targetDir,
163 const struct utimbuf *timestamp,
164 void (*callback)(const char *fn, void*), void *cookie,
165 struct selabel_handle *sehnd);
166
167#ifdef __cplusplus
168}
169#endif
170
171#endif /*_MINZIP_ZIP*/
diff --git a/minzip/inline_magic.h b/minzip/inline_magic.h
deleted file mode 100644
index 59c659f7..00000000
--- a/minzip/inline_magic.h
+++ /dev/null
@@ -1,26 +0,0 @@
1/*
2 * Copyright (C) 2007 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 MINZIP_INLINE_MAGIC_H_
18#define MINZIP_INLINE_MAGIC_H_
19
20#ifndef MINZIP_GENERATE_INLINES
21#define INLINE extern inline __attribute((__gnu_inline__))
22#else
23#define INLINE
24#endif
25
26#endif // MINZIP_INLINE_MAGIC_H_
diff --git a/otafault/Android.mk b/otafault/Android.mk
index 82c26710..71c2c62f 100644
--- a/otafault/Android.mk
+++ b/otafault/Android.mk
@@ -17,7 +17,7 @@ LOCAL_PATH := $(call my-dir)
17include $(CLEAR_VARS) 17include $(CLEAR_VARS)
18 18
19otafault_static_libs := \ 19otafault_static_libs := \
20 libminzip \ 20 libziparchive \
21 libz \ 21 libz \
22 libselinux \ 22 libselinux \
23 libbase \ 23 libbase \
diff --git a/otafault/config.cpp b/otafault/config.cpp
index b4567392..ee4ef891 100644
--- a/otafault/config.cpp
+++ b/otafault/config.cpp
@@ -21,21 +21,21 @@
21#include <unistd.h> 21#include <unistd.h>
22 22
23#include <android-base/stringprintf.h> 23#include <android-base/stringprintf.h>
24#include <ziparchive/zip_archive.h>
24 25
25#include "minzip/Zip.h"
26#include "config.h" 26#include "config.h"
27#include "ota_io.h" 27#include "ota_io.h"
28 28
29#define OTAIO_MAX_FNAME_SIZE 128 29#define OTAIO_MAX_FNAME_SIZE 128
30 30
31static ZipArchive* archive; 31static ZipArchiveHandle archive;
32static std::map<std::string, bool> should_inject_cache; 32static std::map<std::string, bool> should_inject_cache;
33 33
34static std::string get_type_path(const char* io_type) { 34static std::string get_type_path(const char* io_type) {
35 return android::base::StringPrintf("%s/%s", OTAIO_BASE_DIR, io_type); 35 return android::base::StringPrintf("%s/%s", OTAIO_BASE_DIR, io_type);
36} 36}
37 37
38void ota_io_init(ZipArchive* za) { 38void ota_io_init(ZipArchiveHandle za) {
39 archive = za; 39 archive = za;
40 ota_set_fault_files(); 40 ota_set_fault_files();
41} 41}
@@ -50,9 +50,11 @@ bool should_fault_inject(const char* io_type) {
50 if (should_inject_cache.find(type_path) != should_inject_cache.end()) { 50 if (should_inject_cache.find(type_path) != should_inject_cache.end()) {
51 return should_inject_cache[type_path]; 51 return should_inject_cache[type_path];
52 } 52 }
53 const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str()); 53 ZipString zip_type_path(type_path.c_str());
54 should_inject_cache[type_path] = entry != nullptr; 54 ZipEntry entry;
55 return entry != NULL; 55 int status = FindEntry(archive, zip_type_path, &entry);
56 should_inject_cache[type_path] = (status == 0);
57 return (status == 0);
56} 58}
57 59
58bool should_hit_cache() { 60bool should_hit_cache() {
@@ -63,7 +65,9 @@ std::string fault_fname(const char* io_type) {
63 std::string type_path = get_type_path(io_type); 65 std::string type_path = get_type_path(io_type);
64 std::string fname; 66 std::string fname;
65 fname.resize(OTAIO_MAX_FNAME_SIZE); 67 fname.resize(OTAIO_MAX_FNAME_SIZE);
66 const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str()); 68 ZipString zip_type_path(type_path.c_str());
67 mzReadZipEntry(archive, entry, &fname[0], OTAIO_MAX_FNAME_SIZE); 69 ZipEntry entry;
70 int status = FindEntry(archive, zip_type_path, &entry);
71 ExtractToMemory(archive, &entry, reinterpret_cast<uint8_t*>(&fname[0]), OTAIO_MAX_FNAME_SIZE);
68 return fname; 72 return fname;
69} 73}
diff --git a/otafault/config.h b/otafault/config.h
index 4430be3f..c048617c 100644
--- a/otafault/config.h
+++ b/otafault/config.h
@@ -41,7 +41,7 @@
41 41
42#include <stdbool.h> 42#include <stdbool.h>
43 43
44#include "minzip/Zip.h" 44#include <ziparchive/zip_archive.h>
45 45
46#define OTAIO_BASE_DIR ".libotafault" 46#define OTAIO_BASE_DIR ".libotafault"
47#define OTAIO_READ "READ" 47#define OTAIO_READ "READ"
@@ -52,7 +52,7 @@
52/* 52/*
53 * Initialize libotafault by providing a reference to the OTA package. 53 * Initialize libotafault by providing a reference to the OTA package.
54 */ 54 */
55void ota_io_init(ZipArchive* za); 55void ota_io_init(ZipArchiveHandle zip);
56 56
57/* 57/*
58 * Return true if a config file is present for the given IO type. 58 * Return true if a config file is present for the given IO type.
diff --git a/otautil/Android.mk b/otautil/Android.mk
new file mode 100644
index 00000000..3acfa533
--- /dev/null
+++ b/otautil/Android.mk
@@ -0,0 +1,35 @@
1# Copyright (C) 2016 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15LOCAL_PATH := $(call my-dir)
16include $(CLEAR_VARS)
17
18LOCAL_SRC_FILES := \
19 SysUtil.cpp \
20 DirUtil.cpp \
21 ZipUtil.cpp
22
23LOCAL_C_INCLUDES := \
24 external/zlib \
25 external/safe-iop/include
26
27LOCAL_STATIC_LIBRARIES := libselinux libbase
28
29LOCAL_MODULE := libotautil
30
31LOCAL_CLANG := true
32
33LOCAL_CFLAGS += -Werror -Wall
34
35include $(BUILD_STATIC_LIBRARY)
diff --git a/minzip/DirUtil.cpp b/otautil/DirUtil.cpp
index e08e360c..e08e360c 100644
--- a/minzip/DirUtil.cpp
+++ b/otautil/DirUtil.cpp
diff --git a/minzip/DirUtil.h b/otautil/DirUtil.h
index 85b83c38..85b83c38 100644
--- a/minzip/DirUtil.h
+++ b/otautil/DirUtil.h
diff --git a/minzip/SysUtil.cpp b/otautil/SysUtil.cpp
index 2936c5ca..2936c5ca 100644
--- a/minzip/SysUtil.cpp
+++ b/otautil/SysUtil.cpp
diff --git a/minzip/SysUtil.h b/otautil/SysUtil.h
index 7adff1e5..7adff1e5 100644
--- a/minzip/SysUtil.h
+++ b/otautil/SysUtil.h
diff --git a/otautil/ZipUtil.cpp b/otautil/ZipUtil.cpp
new file mode 100644
index 00000000..714c956e
--- /dev/null
+++ b/otautil/ZipUtil.cpp
@@ -0,0 +1,121 @@
1/*
2 * Copyright (C) 2016 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#include "ZipUtil.h"
18
19#include <errno.h>
20#include <fcntl.h>
21#include <utime.h>
22
23#include <string>
24
25#include <android-base/logging.h>
26#include <android-base/unique_fd.h>
27#include <selinux/label.h>
28#include <selinux/selinux.h>
29#include <ziparchive/zip_archive.h>
30
31#include "DirUtil.h"
32
33static constexpr mode_t UNZIP_DIRMODE = 0755;
34static constexpr mode_t UNZIP_FILEMODE = 0644;
35
36bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path,
37 const std::string& dest_path, const struct utimbuf* timestamp,
38 struct selabel_handle* sehnd) {
39 if (!zip_path.empty() && zip_path[0] == '/') {
40 LOG(ERROR) << "ExtractPackageRecursive(): zip_path must be a relative path " << zip_path;
41 return false;
42 }
43 if (dest_path.empty() || dest_path[0] != '/') {
44 LOG(ERROR) << "ExtractPackageRecursive(): dest_path must be an absolute path " << dest_path;
45 return false;
46 }
47
48 void* cookie;
49 std::string target_dir(dest_path);
50 if (dest_path.back() != '/') {
51 target_dir += '/';
52 }
53 std::string prefix_path(zip_path);
54 if (!zip_path.empty() && zip_path.back() != '/') {
55 prefix_path += '/';
56 }
57 const ZipString zip_prefix(prefix_path.c_str());
58
59 int ret = StartIteration(zip, &cookie, &zip_prefix, nullptr);
60 if (ret != 0) {
61 LOG(ERROR) << "failed to start iterating zip entries.";
62 return false;
63 }
64
65 std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
66 ZipEntry entry;
67 ZipString name;
68 int extractCount = 0;
69 while (Next(cookie, &entry, &name) == 0) {
70 std::string entry_name(name.name, name.name + name.name_length);
71 CHECK_LE(prefix_path.size(), entry_name.size());
72 std::string path = target_dir + entry_name.substr(prefix_path.size());
73 // Skip dir.
74 if (path.back() == '/') {
75 continue;
76 }
77 //TODO(b/31917448) handle the symlink.
78
79 if (dirCreateHierarchy(path.c_str(), UNZIP_DIRMODE, timestamp, true, sehnd) != 0) {
80 LOG(ERROR) << "failed to create dir for " << path;
81 return false;
82 }
83
84 char *secontext = NULL;
85 if (sehnd) {
86 selabel_lookup(sehnd, &secontext, path.c_str(), UNZIP_FILEMODE);
87 setfscreatecon(secontext);
88 }
89 android::base::unique_fd fd(open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC, UNZIP_FILEMODE));
90 if (fd == -1) {
91 PLOG(ERROR) << "Can't create target file \"" << path << "\"";
92 return false;
93 }
94 if (secontext) {
95 freecon(secontext);
96 setfscreatecon(NULL);
97 }
98
99 int err = ExtractEntryToFile(zip, &entry, fd);
100 if (err != 0) {
101 LOG(ERROR) << "Error extracting \"" << path << "\" : " << ErrorCodeString(err);
102 return false;
103 }
104
105 if (fsync(fd) != 0) {
106 PLOG(ERROR) << "Error syncing file descriptor when extracting \"" << path << "\"";
107 return false;
108 }
109
110 if (timestamp != nullptr && utime(path.c_str(), timestamp)) {
111 PLOG(ERROR) << "Error touching \"" << path << "\"";
112 return false;
113 }
114
115 LOG(INFO) << "Extracted file \"" << path << "\"";
116 ++extractCount;
117 }
118
119 LOG(INFO) << "Extracted " << extractCount << " file(s)";
120 return true;
121}
diff --git a/otautil/ZipUtil.h b/otautil/ZipUtil.h
new file mode 100644
index 00000000..cda405c2
--- /dev/null
+++ b/otautil/ZipUtil.h
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2016 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 _OTAUTIL_ZIPUTIL_H
18#define _OTAUTIL_ZIPUTIL_H
19
20#include <utime.h>
21
22#include <string>
23
24#include <selinux/label.h>
25#include <ziparchive/zip_archive.h>
26
27/*
28 * Inflate all files under zip_path to the directory specified by
29 * dest_path, which must exist and be a writable directory. The zip_path
30 * is allowed to be an empty string, in which case the whole package
31 * will be extracted.
32 *
33 * Directory entries are not extracted.
34 *
35 * The immediate children of zip_path will become the immediate
36 * children of dest_path; e.g., if the archive contains the entries
37 *
38 * a/b/c/one
39 * a/b/c/two
40 * a/b/c/d/three
41 *
42 * and ExtractPackageRecursive(a, "a/b/c", "/tmp", ...) is called, the resulting
43 * files will be
44 *
45 * /tmp/one
46 * /tmp/two
47 * /tmp/d/three
48 *
49 * If timestamp is non-NULL, file timestamps will be set accordingly.
50 *
51 * Returns true on success, false on failure.
52 */
53bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path,
54 const std::string& dest_path, const struct utimbuf* timestamp,
55 struct selabel_handle* sehnd);
56
57#endif // _OTAUTIL_ZIPUTIL_H
diff --git a/recovery.cpp b/recovery.cpp
index 9cf63c42..668ef3ca 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -52,6 +52,7 @@
52#include <private/android_logger.h> /* private pmsg functions */ 52#include <private/android_logger.h> /* private pmsg functions */
53#include <selinux/label.h> 53#include <selinux/label.h>
54#include <selinux/selinux.h> 54#include <selinux/selinux.h>
55#include <ziparchive/zip_archive.h>
55 56
56#include "adb_install.h" 57#include "adb_install.h"
57#include "bootloader.h" 58#include "bootloader.h"
@@ -63,7 +64,7 @@
63#include "install.h" 64#include "install.h"
64#include "minadbd/minadbd.h" 65#include "minadbd/minadbd.h"
65#include "minui/minui.h" 66#include "minui/minui.h"
66#include "minzip/DirUtil.h" 67#include "otautil/DirUtil.h"
67#include "roots.h" 68#include "roots.h"
68#include "ui.h" 69#include "ui.h"
69#include "screen_ui.h" 70#include "screen_ui.h"
diff --git a/tests/Android.mk b/tests/Android.mk
index ef822d1d..abe6b6d6 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -24,11 +24,18 @@ LOCAL_MODULE := recovery_unit_test
24LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk 24LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
25LOCAL_STATIC_LIBRARIES := \ 25LOCAL_STATIC_LIBRARIES := \
26 libverifier \ 26 libverifier \
27 libminui 27 libminui \
28 libotautil \
29 libziparchive \
30 libutils \
31 libz \
32 libselinux \
33 libbase
28 34
29LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp 35LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp
30LOCAL_SRC_FILES += unit/recovery_test.cpp 36LOCAL_SRC_FILES += unit/recovery_test.cpp
31LOCAL_SRC_FILES += unit/locale_test.cpp 37LOCAL_SRC_FILES += unit/locale_test.cpp
38LOCAL_SRC_FILES += unit/zip_test.cpp
32LOCAL_C_INCLUDES := bootable/recovery 39LOCAL_C_INCLUDES := bootable/recovery
33LOCAL_SHARED_LIBRARIES := liblog 40LOCAL_SHARED_LIBRARIES := liblog
34include $(BUILD_NATIVE_TEST) 41include $(BUILD_NATIVE_TEST)
@@ -62,7 +69,7 @@ LOCAL_STATIC_LIBRARIES := \
62 libupdater \ 69 libupdater \
63 libverifier \ 70 libverifier \
64 libminui \ 71 libminui \
65 libminzip \ 72 libotautil \
66 libmounts \ 73 libmounts \
67 liblog \ 74 liblog \
68 libselinux \ 75 libselinux \
diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp
index 6a3eebf2..7f9a7140 100644
--- a/tests/component/verifier_test.cpp
+++ b/tests/component/verifier_test.cpp
@@ -29,10 +29,11 @@
29#include <openssl/sha.h> 29#include <openssl/sha.h>
30 30
31#include <android-base/stringprintf.h> 31#include <android-base/stringprintf.h>
32#include <ziparchive/zip_archive.h>
32 33
33#include "common.h" 34#include "common.h"
34#include "common/test_constants.h" 35#include "common/test_constants.h"
35#include "minzip/SysUtil.h" 36#include "otautil/SysUtil.h"
36#include "ui.h" 37#include "ui.h"
37#include "verifier.h" 38#include "verifier.h"
38 39
diff --git a/tests/testdata/ziptest_dummy-update.zip b/tests/testdata/ziptest_dummy-update.zip
new file mode 100644
index 00000000..6976bf15
--- /dev/null
+++ b/tests/testdata/ziptest_dummy-update.zip
Binary files differ
diff --git a/tests/testdata/ziptest_valid.zip b/tests/testdata/ziptest_valid.zip
new file mode 100644
index 00000000..9e7cb780
--- /dev/null
+++ b/tests/testdata/ziptest_valid.zip
Binary files differ
diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp
new file mode 100644
index 00000000..b617446b
--- /dev/null
+++ b/tests/unit/zip_test.cpp
@@ -0,0 +1,93 @@
1/*
2 * Copyright (C) 2016 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#include <errno.h>
18#include <fcntl.h>
19#include <pthread.h>
20#include <unistd.h>
21
22#include <memory>
23#include <vector>
24
25#include <android-base/file.h>
26#include <android-base/stringprintf.h>
27#include <android-base/unique_fd.h>
28#include <android-base/test_utils.h>
29#include <gtest/gtest.h>
30#include <otautil/SysUtil.h>
31#include <otautil/ZipUtil.h>
32#include <ziparchive/zip_archive.h>
33
34static const std::string DATA_PATH(getenv("ANDROID_DATA"));
35static const std::string TESTDATA_PATH("/recovery/testdata/");
36
37static const std::vector<uint8_t> kATxtContents {
38 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
39 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
40 '\n'
41};
42
43static const std::vector<uint8_t> kBTxtContents {
44 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
45 '\n'
46};
47
48TEST(otazip, ExtractPackageRecursive) {
49 TemporaryDir td;
50 ASSERT_NE(td.path, nullptr);
51 ZipArchiveHandle handle;
52 std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_valid.zip";
53 ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
54 // Extract the whole package into a temp directory.
55 ExtractPackageRecursive(handle, "", td.path, nullptr, nullptr);
56 // Make sure all the files are extracted correctly.
57 std::string path(td.path);
58 android::base::unique_fd fd(open((path + "/a.txt").c_str(), O_RDONLY));
59 ASSERT_NE(fd, -1);
60 std::vector<uint8_t> read_data;
61 read_data.resize(kATxtContents.size());
62 // The content of the file is the same as expected.
63 ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size()));
64 ASSERT_EQ(0, memcmp(read_data.data(), kATxtContents.data(), kATxtContents.size()));
65
66 fd.reset(open((path + "/b.txt").c_str(), O_RDONLY));
67 ASSERT_NE(fd, -1);
68 fd.reset(open((path + "/b/c.txt").c_str(), O_RDONLY));
69 ASSERT_NE(fd, -1);
70 fd.reset(open((path + "/b/d.txt").c_str(), O_RDONLY));
71 ASSERT_NE(fd, -1);
72 read_data.resize(kBTxtContents.size());
73 ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size()));
74 ASSERT_EQ(0, memcmp(read_data.data(), kBTxtContents.data(), kBTxtContents.size()));
75}
76
77TEST(otazip, OpenFromMemory) {
78 MemMapping map;
79 std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_dummy-update.zip";
80 ASSERT_EQ(0, sysMapFile(zip_path.c_str(), &map));
81 // Map an update package into memory and open the archive from there.
82 ZipArchiveHandle handle;
83 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_path.c_str(), &handle));
84 static constexpr const char* BINARY_PATH = "META-INF/com/google/android/update-binary";
85 ZipString binary_path(BINARY_PATH);
86 ZipEntry binary_entry;
87 // Make sure the package opens correctly and its entry can be read.
88 ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
89 TemporaryFile tmp_binary;
90 ASSERT_NE(-1, tmp_binary.fd);
91 ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
92}
93
diff --git a/updater/Android.mk b/updater/Android.mk
index 33e97385..3c1d0d41 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -25,7 +25,9 @@ tune2fs_static_libraries := \
25updater_common_static_libraries := \ 25updater_common_static_libraries := \
26 libapplypatch \ 26 libapplypatch \
27 libedify \ 27 libedify \
28 libminzip \ 28 libziparchive \
29 libotautil \
30 libutils \
29 libmounts \ 31 libmounts \
30 libotafault \ 32 libotafault \
31 libext4_utils_static \ 33 libext4_utils_static \
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index 5f9b437f..f08ca5b0 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -33,21 +33,21 @@
33#include <unistd.h> 33#include <unistd.h>
34#include <fec/io.h> 34#include <fec/io.h>
35 35
36#include <map>
37#include <memory> 36#include <memory>
38#include <string> 37#include <string>
38#include <unordered_map>
39#include <vector> 39#include <vector>
40 40
41#include <android-base/parseint.h> 41#include <android-base/parseint.h>
42#include <android-base/strings.h> 42#include <android-base/strings.h>
43#include <android-base/unique_fd.h> 43#include <android-base/unique_fd.h>
44#include <ziparchive/zip_archive.h>
44 45
45#include "applypatch/applypatch.h" 46#include "applypatch/applypatch.h"
46#include "edify/expr.h" 47#include "edify/expr.h"
47#include "error_code.h" 48#include "error_code.h"
48#include "updater/install.h" 49#include "updater/install.h"
49#include "openssl/sha.h" 50#include "openssl/sha.h"
50#include "minzip/Hash.h"
51#include "ota_io.h" 51#include "ota_io.h"
52#include "print_sha1.h" 52#include "print_sha1.h"
53#include "updater/updater.h" 53#include "updater/updater.h"
@@ -71,7 +71,7 @@ struct RangeSet {
71 71
72static CauseCode failure_type = kNoCause; 72static CauseCode failure_type = kNoCause;
73static bool is_retry = false; 73static bool is_retry = false;
74static std::map<std::string, RangeSet> stash_map; 74static std::unordered_map<std::string, RangeSet> stash_map;
75 75
76static void parse_range(const std::string& range_text, RangeSet& rs) { 76static void parse_range(const std::string& range_text, RangeSet& rs) {
77 77
@@ -300,8 +300,8 @@ static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
300// rss and signals the condition again. 300// rss and signals the condition again.
301 301
302struct NewThreadInfo { 302struct NewThreadInfo {
303 ZipArchive* za; 303 ZipArchiveHandle za;
304 const ZipEntry* entry; 304 ZipEntry entry;
305 305
306 RangeSinkState* rss; 306 RangeSinkState* rss;
307 307
@@ -309,7 +309,7 @@ struct NewThreadInfo {
309 pthread_cond_t cv; 309 pthread_cond_t cv;
310}; 310};
311 311
312static bool receive_new_data(const unsigned char* data, int size, void* cookie) { 312static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) {
313 NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie); 313 NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie);
314 314
315 while (size > 0) { 315 while (size > 0) {
@@ -342,7 +342,7 @@ static bool receive_new_data(const unsigned char* data, int size, void* cookie)
342 342
343static void* unzip_new_data(void* cookie) { 343static void* unzip_new_data(void* cookie) {
344 NewThreadInfo* nti = (NewThreadInfo*) cookie; 344 NewThreadInfo* nti = (NewThreadInfo*) cookie;
345 mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti); 345 ProcessZipEntryContents(nti->za, &nti->entry, receive_new_data, nti);
346 return nullptr; 346 return nullptr;
347} 347}
348 348
@@ -1351,28 +1351,6 @@ struct Command {
1351 CommandFunction f; 1351 CommandFunction f;
1352}; 1352};
1353 1353
1354// CompareCommands and CompareCommandNames are for the hash table
1355
1356static int CompareCommands(const void* c1, const void* c2) {
1357 return strcmp(((const Command*) c1)->name, ((const Command*) c2)->name);
1358}
1359
1360static int CompareCommandNames(const void* c1, const void* c2) {
1361 return strcmp(((const Command*) c1)->name, (const char*) c2);
1362}
1363
1364// HashString is used to hash command names for the hash table
1365
1366static unsigned int HashString(const char *s) {
1367 unsigned int hash = 0;
1368 if (s) {
1369 while (*s) {
1370 hash = hash * 33 + *s++;
1371 }
1372 }
1373 return hash;
1374}
1375
1376// args: 1354// args:
1377// - block device (or file) to modify in-place 1355// - block device (or file) to modify in-place
1378// - transfer list (blob) 1356// - transfer list (blob)
@@ -1429,21 +1407,23 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
1429 } 1407 }
1430 1408
1431 FILE* cmd_pipe = ui->cmd_pipe; 1409 FILE* cmd_pipe = ui->cmd_pipe;
1432 ZipArchive* za = ui->package_zip; 1410 ZipArchiveHandle za = ui->package_zip;
1433 1411
1434 if (cmd_pipe == nullptr || za == nullptr) { 1412 if (cmd_pipe == nullptr || za == nullptr) {
1435 return StringValue(""); 1413 return StringValue("");
1436 } 1414 }
1437 1415
1438 const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data.c_str()); 1416 ZipString path_data(patch_data_fn->data.c_str());
1439 if (patch_entry == nullptr) { 1417 ZipEntry patch_entry;
1418 if (FindEntry(za, path_data, &patch_entry) != 0) {
1440 fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data.c_str()); 1419 fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data.c_str());
1441 return StringValue(""); 1420 return StringValue("");
1442 } 1421 }
1443 1422
1444 params.patch_start = ui->package_zip_addr + mzGetZipEntryOffset(patch_entry); 1423 params.patch_start = ui->package_zip_addr + patch_entry.offset;
1445 const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data.c_str()); 1424 ZipString new_data(new_data_fn->data.c_str());
1446 if (new_entry == nullptr) { 1425 ZipEntry new_entry;
1426 if (FindEntry(za, new_data, &new_entry) != 0) {
1447 fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data.c_str()); 1427 fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data.c_str());
1448 return StringValue(""); 1428 return StringValue("");
1449 } 1429 }
@@ -1526,13 +1506,15 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
1526 start += 2; 1506 start += 2;
1527 } 1507 }
1528 1508
1529 // Build a hash table of the available commands 1509 // Build a map of the available commands
1530 HashTable* cmdht = mzHashTableCreate(cmdcount, nullptr); 1510 std::unordered_map<std::string, const Command*> cmd_map;
1531 std::unique_ptr<HashTable, decltype(&mzHashTableFree)> cmdht_holder(cmdht, mzHashTableFree);
1532
1533 for (size_t i = 0; i < cmdcount; ++i) { 1511 for (size_t i = 0; i < cmdcount; ++i) {
1534 unsigned int cmdhash = HashString(commands[i].name); 1512 if (cmd_map.find(commands[i].name) != cmd_map.end()) {
1535 mzHashTableLookup(cmdht, cmdhash, (void*) &commands[i], CompareCommands, true); 1513 fprintf(stderr, "Error: command [%s] already exists in the cmd map.\n",
1514 commands[i].name);
1515 return StringValue(strdup(""));
1516 }
1517 cmd_map[commands[i].name] = &commands[i];
1536 } 1518 }
1537 1519
1538 int rc = -1; 1520 int rc = -1;
@@ -1549,16 +1531,13 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
1549 params.cmdname = params.tokens[params.cpos++].c_str(); 1531 params.cmdname = params.tokens[params.cpos++].c_str();
1550 params.cmdline = line_str.c_str(); 1532 params.cmdline = line_str.c_str();
1551 1533
1552 unsigned int cmdhash = HashString(params.cmdname); 1534 if (cmd_map.find(params.cmdname) == cmd_map.end()) {
1553 const Command* cmd = reinterpret_cast<const Command*>(mzHashTableLookup(cmdht, cmdhash,
1554 const_cast<char*>(params.cmdname), CompareCommandNames,
1555 false));
1556
1557 if (cmd == nullptr) {
1558 fprintf(stderr, "unexpected command [%s]\n", params.cmdname); 1535 fprintf(stderr, "unexpected command [%s]\n", params.cmdname);
1559 goto pbiudone; 1536 goto pbiudone;
1560 } 1537 }
1561 1538
1539 const Command* cmd = cmd_map[params.cmdname];
1540
1562 if (cmd->f != nullptr && cmd->f(params) == -1) { 1541 if (cmd->f != nullptr && cmd->f(params) == -1) {
1563 fprintf(stderr, "failed to execute command [%s]\n", line_str.c_str()); 1542 fprintf(stderr, "failed to execute command [%s]\n", line_str.c_str());
1564 goto pbiudone; 1543 goto pbiudone;
diff --git a/updater/include/updater/updater.h b/updater/include/updater/updater.h
index d3a09b93..f4a2fe87 100644
--- a/updater/include/updater/updater.h
+++ b/updater/include/updater/updater.h
@@ -18,11 +18,11 @@
18#define _UPDATER_UPDATER_H_ 18#define _UPDATER_UPDATER_H_
19 19
20#include <stdio.h> 20#include <stdio.h>
21#include "minzip/Zip.h" 21#include <ziparchive/zip_archive.h>
22 22
23typedef struct { 23typedef struct {
24 FILE* cmd_pipe; 24 FILE* cmd_pipe;
25 ZipArchive* package_zip; 25 ZipArchiveHandle package_zip;
26 int version; 26 int version;
27 27
28 uint8_t* package_zip_addr; 28 uint8_t* package_zip_addr;
diff --git a/updater/install.cpp b/updater/install.cpp
index d723b388..a41c5db3 100644
--- a/updater/install.cpp
+++ b/updater/install.cpp
@@ -33,6 +33,7 @@
33#include <sys/xattr.h> 33#include <sys/xattr.h>
34#include <time.h> 34#include <time.h>
35#include <unistd.h> 35#include <unistd.h>
36#include <utime.h>
36 37
37#include <memory> 38#include <memory>
38#include <string> 39#include <string>
@@ -48,14 +49,16 @@
48#include <openssl/sha.h> 49#include <openssl/sha.h>
49#include <selinux/label.h> 50#include <selinux/label.h>
50#include <selinux/selinux.h> 51#include <selinux/selinux.h>
52#include <ziparchive/zip_archive.h>
51 53
52#include "applypatch/applypatch.h" 54#include "applypatch/applypatch.h"
53#include "bootloader.h" 55#include "bootloader.h"
54#include "edify/expr.h" 56#include "edify/expr.h"
55#include "error_code.h" 57#include "error_code.h"
56#include "minzip/DirUtil.h"
57#include "mounts.h" 58#include "mounts.h"
58#include "ota_io.h" 59#include "ota_io.h"
60#include "otautil/DirUtil.h"
61#include "otautil/ZipUtil.h"
59#include "print_sha1.h" 62#include "print_sha1.h"
60#include "tune2fs.h" 63#include "tune2fs.h"
61#include "updater/updater.h" 64#include "updater/updater.h"
@@ -465,14 +468,13 @@ Value* PackageExtractDirFn(const char* name, State* state,
465 char* dest_path; 468 char* dest_path;
466 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL; 469 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
467 470
468 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; 471 ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
469 472
470 // To create a consistent system image, never use the clock for timestamps. 473 // To create a consistent system image, never use the clock for timestamps.
471 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default 474 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
472 475
473 bool success = mzExtractRecursive(za, zip_path, dest_path, 476 bool success = ExtractPackageRecursive(za, zip_path, dest_path, &timestamp, sehandle);
474 &timestamp, 477
475 NULL, NULL, sehandle);
476 free(zip_path); 478 free(zip_path);
477 free(dest_path); 479 free(dest_path);
478 return StringValue(success ? "t" : ""); 480 return StringValue(success ? "t" : "");
@@ -495,14 +497,15 @@ Value* PackageExtractFileFn(const char* name, State* state,
495 if (argc == 2) { 497 if (argc == 2) {
496 // The two-argument version extracts to a file. 498 // The two-argument version extracts to a file.
497 499
498 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; 500 ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
499 501
500 char* zip_path; 502 char* zip_path;
501 char* dest_path; 503 char* dest_path;
502 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL; 504 if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
503 505
504 const ZipEntry* entry = mzFindZipEntry(za, zip_path); 506 ZipString zip_string_path(zip_path);
505 if (entry == NULL) { 507 ZipEntry entry;
508 if (FindEntry(za, zip_string_path, &entry) != 0) {
506 printf("%s: no %s in package\n", name, zip_path); 509 printf("%s: no %s in package\n", name, zip_path);
507 goto done2; 510 goto done2;
508 } 511 }
@@ -514,7 +517,7 @@ Value* PackageExtractFileFn(const char* name, State* state,
514 printf("%s: can't open %s for write: %s\n", name, dest_path, strerror(errno)); 517 printf("%s: can't open %s for write: %s\n", name, dest_path, strerror(errno));
515 goto done2; 518 goto done2;
516 } 519 }
517 success = mzExtractZipEntryToFile(za, entry, fd); 520 success = ExtractEntryToFile(za, &entry, fd);
518 if (ota_fsync(fd) == -1) { 521 if (ota_fsync(fd) == -1) {
519 printf("fsync of \"%s\" failed: %s\n", dest_path, strerror(errno)); 522 printf("fsync of \"%s\" failed: %s\n", dest_path, strerror(errno));
520 success = false; 523 success = false;
@@ -538,16 +541,21 @@ Value* PackageExtractFileFn(const char* name, State* state,
538 541
539 Value* v = new Value(VAL_INVALID, ""); 542 Value* v = new Value(VAL_INVALID, "");
540 543
541 ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; 544 ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
542 const ZipEntry* entry = mzFindZipEntry(za, zip_path); 545 ZipString zip_string_path(zip_path);
543 if (entry == NULL) { 546 ZipEntry entry;
547 if (FindEntry(za, zip_string_path, &entry) != 0) {
544 printf("%s: no %s in package\n", name, zip_path); 548 printf("%s: no %s in package\n", name, zip_path);
545 goto done1; 549 goto done1;
546 } 550 }
547 551
548 v->data.resize(mzGetZipEntryUncompLen(entry)); 552 v->data.resize(entry.uncompressed_length);
549 success = mzExtractZipEntryToBuffer(za, entry, 553 if (ExtractToMemory(za, &entry, reinterpret_cast<uint8_t*>(&v->data[0]),
550 reinterpret_cast<unsigned char *>(&v->data[0])); 554 v->data.size()) != 0) {
555 printf("%s: faled to extract %zu bytes to memory\n", name, v->data.size());
556 } else {
557 success = true;
558 }
551 559
552 done1: 560 done1:
553 free(zip_path); 561 free(zip_path);
diff --git a/updater/updater.cpp b/updater/updater.cpp
index 47696b80..7327c52e 100644
--- a/updater/updater.cpp
+++ b/updater/updater.cpp
@@ -21,14 +21,17 @@
21#include <stdlib.h> 21#include <stdlib.h>
22#include <string.h> 22#include <string.h>
23 23
24#include <string>
25
24#include <android-base/strings.h> 26#include <android-base/strings.h>
25#include <selinux/label.h> 27#include <selinux/label.h>
26#include <selinux/selinux.h> 28#include <selinux/selinux.h>
29#include <ziparchive/zip_archive.h>
27 30
28#include "config.h" 31#include "config.h"
29#include "edify/expr.h" 32#include "edify/expr.h"
30#include "minzip/SysUtil.h" 33#include "otautil/DirUtil.h"
31#include "minzip/Zip.h" 34#include "otautil/SysUtil.h"
32#include "updater/blockimg.h" 35#include "updater/blockimg.h"
33#include "updater/install.h" 36#include "updater/install.h"
34 37
@@ -82,28 +85,35 @@ int main(int argc, char** argv) {
82 printf("failed to map package %s\n", argv[3]); 85 printf("failed to map package %s\n", argv[3]);
83 return 3; 86 return 3;
84 } 87 }
85 ZipArchive za; 88 ZipArchiveHandle za;
86 int err; 89 int open_err = OpenArchiveFromMemory(map.addr, map.length, argv[3], &za);
87 err = mzOpenZipArchive(map.addr, map.length, &za); 90 if (open_err != 0) {
88 if (err != 0) {
89 printf("failed to open package %s: %s\n", 91 printf("failed to open package %s: %s\n",
90 argv[3], strerror(err)); 92 argv[3], ErrorCodeString(open_err));
93 CloseArchive(za);
91 return 3; 94 return 3;
92 } 95 }
93 ota_io_init(&za); 96 ota_io_init(za);
94 97
95 const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); 98 ZipString script_name(SCRIPT_NAME);
96 if (script_entry == NULL) { 99 ZipEntry script_entry;
97 printf("failed to find %s in %s\n", SCRIPT_NAME, package_filename); 100 int find_err = FindEntry(za, script_name, &script_entry);
101 if (find_err != 0) {
102 printf("failed to find %s in %s: %s\n", SCRIPT_NAME, package_filename,
103 ErrorCodeString(find_err));
104 CloseArchive(za);
98 return 4; 105 return 4;
99 } 106 }
100 107
101 char* script = reinterpret_cast<char*>(malloc(script_entry->uncompLen+1)); 108 std::string script;
102 if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) { 109 script.resize(script_entry.uncompressed_length);
103 printf("failed to read script from package\n"); 110 int extract_err = ExtractToMemory(za, &script_entry, reinterpret_cast<uint8_t*>(&script[0]),
111 script_entry.uncompressed_length);
112 if (extract_err != 0) {
113 printf("failed to read script from package: %s\n", ErrorCodeString(extract_err));
114 CloseArchive(za);
104 return 5; 115 return 5;
105 } 116 }
106 script[script_entry->uncompLen] = '\0';
107 117
108 // Configure edify's functions. 118 // Configure edify's functions.
109 119
@@ -116,9 +126,10 @@ int main(int argc, char** argv) {
116 126
117 Expr* root; 127 Expr* root;
118 int error_count = 0; 128 int error_count = 0;
119 int error = parse_string(script, &root, &error_count); 129 int error = parse_string(script.c_str(), &root, &error_count);
120 if (error != 0 || error_count > 0) { 130 if (error != 0 || error_count > 0) {
121 printf("%d parse errors\n", error_count); 131 printf("%d parse errors\n", error_count);
132 CloseArchive(za);
122 return 6; 133 return 6;
123 } 134 }
124 135
@@ -136,7 +147,7 @@ int main(int argc, char** argv) {
136 147
137 UpdaterInfo updater_info; 148 UpdaterInfo updater_info;
138 updater_info.cmd_pipe = cmd_pipe; 149 updater_info.cmd_pipe = cmd_pipe;
139 updater_info.package_zip = &za; 150 updater_info.package_zip = za;
140 updater_info.version = atoi(version); 151 updater_info.version = atoi(version);
141 updater_info.package_zip_addr = map.addr; 152 updater_info.package_zip_addr = map.addr;
142 updater_info.package_zip_len = map.length; 153 updater_info.package_zip_len = map.length;
@@ -187,16 +198,18 @@ int main(int argc, char** argv) {
187 } 198 }
188 } 199 }
189 200
201 if (updater_info.package_zip) {
202 CloseArchive(updater_info.package_zip);
203 }
190 return 7; 204 return 7;
191 } else { 205 } else {
192 fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result.c_str()); 206 fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result.c_str());
193 } 207 }
194 208
195 if (updater_info.package_zip) { 209 if (updater_info.package_zip) {
196 mzCloseZipArchive(updater_info.package_zip); 210 CloseArchive(updater_info.package_zip);
197 } 211 }
198 sysReleaseMap(&map); 212 sysReleaseMap(&map);
199 free(script);
200 213
201 return 0; 214 return 0;
202} 215}
diff --git a/verifier.cpp b/verifier.cpp
index 401bd7e3..82cdd3bc 100644
--- a/verifier.cpp
+++ b/verifier.cpp
@@ -184,7 +184,7 @@ int verify_file(unsigned char* addr, size_t length,
184 if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b && 184 if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b &&
185 eocd[i+2] == 0x05 && eocd[i+3] == 0x06) { 185 eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
186 // if the sequence $50 $4b $05 $06 appears anywhere after 186 // if the sequence $50 $4b $05 $06 appears anywhere after
187 // the real one, minzip will find the later (wrong) one, 187 // the real one, libziparchive will find the later (wrong) one,
188 // which could be exploitable. Fail verification if 188 // which could be exploitable. Fail verification if
189 // this sequence occurs anywhere after the real one. 189 // this sequence occurs anywhere after the real one.
190 LOG(ERROR) << "EOCD marker occurs after start of EOCD"; 190 LOG(ERROR) << "EOCD marker occurs after start of EOCD";