blob: 7653872fa9091abb613eafeca4f0adce96fcbbd2 [file] [log] [blame]
Narayan Kamath7462f022013-11-21 13:05:04 +00001/*
2 * Copyright (C) 2013 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
Narayan Kamath1ef9d2d2017-06-15 13:58:25 +010017#include "zip_archive_private.h"
18
Narayan Kamath00a258c2013-12-13 16:06:19 +000019#include <errno.h>
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -070020#include <fcntl.h>
Narayan Kamath00a258c2013-12-13 16:06:19 +000021#include <getopt.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000022#include <stdio.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080023#include <string.h>
Narayan Kamath00a258c2013-12-13 16:06:19 +000024#include <unistd.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080025
Yabin Cui8e6f7222016-02-08 16:26:33 -080026#include <memory>
Narayan Kamath00a258c2013-12-13 16:06:19 +000027#include <vector>
28
Elliott Hughes4f713192015-12-04 22:00:26 -080029#include <android-base/file.h>
Yabin Cui8e6f7222016-02-08 16:26:33 -080030#include <android-base/test_utils.h>
Tianjie Xu18c25922016-09-29 15:27:41 -070031#include <android-base/unique_fd.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000032#include <gtest/gtest.h>
Tianjie Xu18c25922016-09-29 15:27:41 -070033#include <utils/FileMap.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080034#include <ziparchive/zip_archive.h>
35#include <ziparchive/zip_archive_stream_entry.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000036
Narayan Kamath58aaf462013-12-10 16:47:14 +000037static std::string test_data_dir;
Narayan Kamath7462f022013-11-21 13:05:04 +000038
Neil Fullerb1a113f2014-07-25 14:43:04 +010039static const std::string kMissingZip = "missing.zip";
Narayan Kamath58aaf462013-12-10 16:47:14 +000040static const std::string kValidZip = "valid.zip";
Christopher Ferrise6884ce2015-11-10 14:55:12 -080041static const std::string kLargeZip = "large.zip";
42static const std::string kBadCrcZip = "bad_crc.zip";
Tianjie Xufba1a362016-09-21 14:58:11 -070043static const std::string kCrashApk = "crash.apk";
Tianjie Xu18c25922016-09-29 15:27:41 -070044static const std::string kUpdateZip = "dummy-update.zip";
Narayan Kamath58aaf462013-12-10 16:47:14 +000045
Christopher Ferrise6884ce2015-11-10 14:55:12 -080046static const std::vector<uint8_t> kATxtContents {
Narayan Kamath58aaf462013-12-10 16:47:14 +000047 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
48 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
49 '\n'
50};
51
Christopher Ferrise6884ce2015-11-10 14:55:12 -080052static const std::vector<uint8_t> kATxtContentsCompressed {
53 'K', 'L', 'J', 'N', 'I', 'M', 'K', 207, 'H',
54 132, 210, '\\', '\0'
55};
56
57static const std::vector<uint8_t> kBTxtContents {
Narayan Kamath58aaf462013-12-10 16:47:14 +000058 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
59 '\n'
60};
61
Christopher Ferrise6884ce2015-11-10 14:55:12 -080062static const std::string kATxtName("a.txt");
63static const std::string kBTxtName("b.txt");
64static const std::string kNonexistentTxtName("nonexistent.txt");
65static const std::string kEmptyTxtName("empty.txt");
66static const std::string kLargeCompressTxtName("compress.txt");
67static const std::string kLargeUncompressTxtName("uncompress.txt");
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +010068
Narayan Kamath58aaf462013-12-10 16:47:14 +000069static int32_t OpenArchiveWrapper(const std::string& name,
70 ZipArchiveHandle* handle) {
71 const std::string abs_path = test_data_dir + "/" + name;
72 return OpenArchive(abs_path.c_str(), handle);
73}
74
75static void AssertNameEquals(const std::string& name_str,
Yusuke Sato07447542015-06-25 14:39:19 -070076 const ZipString& name) {
Narayan Kamath58aaf462013-12-10 16:47:14 +000077 ASSERT_EQ(name_str.size(), name.name_length);
78 ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
79}
80
Christopher Ferrise6884ce2015-11-10 14:55:12 -080081static void SetZipString(ZipString* zip_str, const std::string& str) {
82 zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
83 zip_str->name_length = str.size();
84}
85
Narayan Kamath58aaf462013-12-10 16:47:14 +000086TEST(ziparchive, Open) {
87 ZipArchiveHandle handle;
88 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
89
90 CloseArchive(handle);
91}
92
Tianjie Xufba1a362016-09-21 14:58:11 -070093TEST(ziparchive, OutOfBound) {
94 ZipArchiveHandle handle;
95 ASSERT_EQ(-8, OpenArchiveWrapper(kCrashApk, &handle));
96 CloseArchive(handle);
97}
98
Neil Fullerb1a113f2014-07-25 14:43:04 +010099TEST(ziparchive, OpenMissing) {
100 ZipArchiveHandle handle;
101 ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
102
103 // Confirm the file descriptor is not going to be mistaken for a valid one.
104 ASSERT_EQ(-1, GetFileDescriptor(handle));
105}
106
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700107TEST(ziparchive, OpenAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800108 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700109 ASSERT_NE(-1, fd);
110 ZipArchiveHandle handle;
111 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
112 CloseArchive(handle);
113 ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
114 ASSERT_EQ(EBADF, errno);
115}
116
117TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800118 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700119 ASSERT_NE(-1, fd);
120 ZipArchiveHandle handle;
121 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
122 CloseArchive(handle);
123 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
124 close(fd);
125}
126
Narayan Kamath58aaf462013-12-10 16:47:14 +0000127TEST(ziparchive, Iteration) {
128 ZipArchiveHandle handle;
129 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
130
131 void* iteration_cookie;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800132 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
Narayan Kamath7462f022013-11-21 13:05:04 +0000133
134 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700135 ZipString name;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000136
137 // b/c.txt
138 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
139 AssertNameEquals("b/c.txt", name);
140
141 // b/d.txt
142 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
143 AssertNameEquals("b/d.txt", name);
144
145 // a.txt
146 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
147 AssertNameEquals("a.txt", name);
148
149 // b.txt
150 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
151 AssertNameEquals("b.txt", name);
152
153 // b/
154 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
155 AssertNameEquals("b/", name);
156
157 // End of iteration.
158 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
159
160 CloseArchive(handle);
161}
162
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700163TEST(ziparchive, IterationWithPrefix) {
164 ZipArchiveHandle handle;
165 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
166
167 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700168 ZipString prefix("b/");
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800169 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, nullptr));
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700170
171 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700172 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700173
174 // b/c.txt
175 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
176 AssertNameEquals("b/c.txt", name);
177
178 // b/d.txt
179 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
180 AssertNameEquals("b/d.txt", name);
181
182 // b/
183 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
184 AssertNameEquals("b/", name);
185
186 // End of iteration.
187 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
188
189 CloseArchive(handle);
190}
191
192TEST(ziparchive, IterationWithSuffix) {
193 ZipArchiveHandle handle;
194 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
195
196 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700197 ZipString suffix(".txt");
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800198 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, &suffix));
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700199
200 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700201 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700202
203 // b/c.txt
204 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
205 AssertNameEquals("b/c.txt", name);
206
207 // b/d.txt
208 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
209 AssertNameEquals("b/d.txt", name);
210
211 // a.txt
212 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
213 AssertNameEquals("a.txt", name);
214
215 // b.txt
216 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
217 AssertNameEquals("b.txt", name);
218
219 // End of iteration.
220 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
221
222 CloseArchive(handle);
223}
224
225TEST(ziparchive, IterationWithPrefixAndSuffix) {
226 ZipArchiveHandle handle;
227 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
228
229 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700230 ZipString prefix("b");
231 ZipString suffix(".txt");
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700232 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
233
234 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700235 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700236
237 // b/c.txt
238 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
239 AssertNameEquals("b/c.txt", name);
240
241 // b/d.txt
242 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
243 AssertNameEquals("b/d.txt", name);
244
245 // b.txt
246 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
247 AssertNameEquals("b.txt", name);
248
249 // End of iteration.
250 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
251
252 CloseArchive(handle);
253}
254
255TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
256 ZipArchiveHandle handle;
257 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
258
259 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700260 ZipString prefix("x");
261 ZipString suffix("y");
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700262 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
263
264 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700265 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700266
267 // End of iteration.
268 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
269
270 CloseArchive(handle);
271}
272
Narayan Kamath58aaf462013-12-10 16:47:14 +0000273TEST(ziparchive, FindEntry) {
274 ZipArchiveHandle handle;
275 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
276
277 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700278 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800279 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100280 ASSERT_EQ(0, FindEntry(handle, name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000281
282 // Known facts about a.txt, from zipinfo -v.
283 ASSERT_EQ(63, data.offset);
284 ASSERT_EQ(kCompressDeflated, data.method);
285 ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
286 ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
287 ASSERT_EQ(0x950821c5, data.crc32);
beonit0e99a2f2015-07-18 02:08:16 +0900288 ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000289
290 // An entry that doesn't exist. Should be a negative return code.
Yusuke Sato07447542015-06-25 14:39:19 -0700291 ZipString absent_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800292 SetZipString(&absent_name, kNonexistentTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100293 ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000294
295 CloseArchive(handle);
296}
297
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200298TEST(ziparchive, TestInvalidDeclaredLength) {
299 ZipArchiveHandle handle;
300 ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
301
302 void* iteration_cookie;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800303 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200304
Yusuke Sato07447542015-06-25 14:39:19 -0700305 ZipString name;
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200306 ZipEntry data;
307
308 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
309 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
310
311 CloseArchive(handle);
312}
313
Narayan Kamath58aaf462013-12-10 16:47:14 +0000314TEST(ziparchive, ExtractToMemory) {
315 ZipArchiveHandle handle;
316 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
317
318 // An entry that's deflated.
319 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700320 ZipString a_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800321 SetZipString(&a_name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100322 ASSERT_EQ(0, FindEntry(handle, a_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000323 const uint32_t a_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800324 ASSERT_EQ(a_size, kATxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000325 uint8_t* buffer = new uint8_t[a_size];
326 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800327 ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000328 delete[] buffer;
329
330 // An entry that's stored.
Yusuke Sato07447542015-06-25 14:39:19 -0700331 ZipString b_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800332 SetZipString(&b_name, kBTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100333 ASSERT_EQ(0, FindEntry(handle, b_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000334 const uint32_t b_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800335 ASSERT_EQ(b_size, kBTxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000336 buffer = new uint8_t[b_size];
337 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800338 ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000339 delete[] buffer;
340
341 CloseArchive(handle);
342}
343
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100344static const uint32_t kEmptyEntriesZip[] = {
Narayan Kamath48953a12014-01-24 12:32:39 +0000345 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
346 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
347 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
348 0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000,
349 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
350 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
351 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100352
Narayan Kamathf899bd52015-04-17 11:53:14 +0100353// This is a zip file containing a single entry (ab.txt) that contains
354// 90072 repetitions of the string "ab\n" and has an uncompressed length
355// of 270216 bytes.
356static const uint16_t kAbZip[] = {
357 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
358 0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
359 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
360 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
361 0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
362 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
363 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
364 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
365 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
366 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
367 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
368 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
369 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
370 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
371 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
372 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
373 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
374 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
375 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
376 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
377 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
378 0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02,
379 0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
380 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
381 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
382 0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
383 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
384 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
385};
386
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800387static const std::string kAbTxtName("ab.txt");
Narayan Kamathf899bd52015-04-17 11:53:14 +0100388static const size_t kAbUncompressedSize = 270216;
389
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100390TEST(ziparchive, EmptyEntries) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800391 TemporaryFile tmp_file;
392 ASSERT_NE(-1, tmp_file.fd);
393 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
Narayan Kamath48953a12014-01-24 12:32:39 +0000394
395 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800396 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath48953a12014-01-24 12:32:39 +0000397
398 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700399 ZipString empty_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800400 SetZipString(&empty_name, kEmptyTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100401 ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
Narayan Kamath48953a12014-01-24 12:32:39 +0000402 ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
403 uint8_t buffer[1];
404 ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
405
Yabin Cui8e6f7222016-02-08 16:26:33 -0800406
407 TemporaryFile tmp_output_file;
408 ASSERT_NE(-1, tmp_output_file.fd);
409 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamath48953a12014-01-24 12:32:39 +0000410
411 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800412 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamath48953a12014-01-24 12:32:39 +0000413 ASSERT_EQ(0, stat_buf.st_size);
Narayan Kamath48953a12014-01-24 12:32:39 +0000414}
415
Narayan Kamathf899bd52015-04-17 11:53:14 +0100416TEST(ziparchive, EntryLargerThan32K) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800417 TemporaryFile tmp_file;
418 ASSERT_NE(-1, tmp_file.fd);
419 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
Narayan Kamathf899bd52015-04-17 11:53:14 +0100420 sizeof(kAbZip) - 1));
421 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800422 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100423
424 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700425 ZipString ab_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800426 SetZipString(&ab_name, kAbTxtName);
Narayan Kamathf899bd52015-04-17 11:53:14 +0100427 ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
428 ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
429
430 // Extract the entry to memory.
431 std::vector<uint8_t> buffer(kAbUncompressedSize);
432 ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
433
434 // Extract the entry to a file.
Yabin Cui8e6f7222016-02-08 16:26:33 -0800435 TemporaryFile tmp_output_file;
436 ASSERT_NE(-1, tmp_output_file.fd);
437 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100438
439 // Make sure the extracted file size is as expected.
440 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800441 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100442 ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
443
444 // Read the file back to a buffer and make sure the contents are
445 // the same as the memory buffer we extracted directly to.
446 std::vector<uint8_t> file_contents(kAbUncompressedSize);
Yabin Cui8e6f7222016-02-08 16:26:33 -0800447 ASSERT_EQ(0, lseek64(tmp_output_file.fd, 0, SEEK_SET));
448 ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0],
449 file_contents.size()));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100450 ASSERT_EQ(file_contents, buffer);
451
452 for (int i = 0; i < 90072; ++i) {
453 const uint8_t* line = &file_contents[0] + (3 * i);
454 ASSERT_EQ('a', line[0]);
455 ASSERT_EQ('b', line[1]);
456 ASSERT_EQ('\n', line[2]);
457 }
Narayan Kamathf899bd52015-04-17 11:53:14 +0100458}
459
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100460TEST(ziparchive, TrailerAfterEOCD) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800461 TemporaryFile tmp_file;
462 ASSERT_NE(-1, tmp_file.fd);
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100463
464 // Create a file with 8 bytes of random garbage.
465 static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
Yabin Cui8e6f7222016-02-08 16:26:33 -0800466 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
467 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100468
469 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800470 ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100471}
472
Narayan Kamath00a258c2013-12-13 16:06:19 +0000473TEST(ziparchive, ExtractToFile) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800474 TemporaryFile tmp_file;
475 ASSERT_NE(-1, tmp_file.fd);
Narayan Kamath00a258c2013-12-13 16:06:19 +0000476 const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
Yabin Cui8e6f7222016-02-08 16:26:33 -0800477 const size_t data_size = sizeof(data);
Narayan Kamath00a258c2013-12-13 16:06:19 +0000478
Yabin Cui8e6f7222016-02-08 16:26:33 -0800479 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000480
481 ZipArchiveHandle handle;
482 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
483
484 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700485 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800486 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100487 ASSERT_EQ(0, FindEntry(handle, name, &entry));
Yabin Cui8e6f7222016-02-08 16:26:33 -0800488 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000489
490
491 // Assert that the first 8 bytes of the file haven't been clobbered.
492 uint8_t read_buffer[data_size];
Yabin Cui8e6f7222016-02-08 16:26:33 -0800493 ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
494 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000495 ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
496
497 // Assert that the remainder of the file contains the incompressed data.
498 std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
Yabin Cui8e6f7222016-02-08 16:26:33 -0800499 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
500 entry.uncompressed_length));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800501 ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(),
502 kATxtContents.size()));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000503
504 // Assert that the total length of the file is sane
Yabin Cui8e6f7222016-02-08 16:26:33 -0800505 ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
506 lseek64(tmp_file.fd, 0, SEEK_END));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000507}
508
Tianjie Xu18c25922016-09-29 15:27:41 -0700509#if !defined(_WIN32)
510TEST(ziparchive, OpenFromMemory) {
511 const std::string zip_path = test_data_dir + "/" + kUpdateZip;
512 android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
513 ASSERT_NE(-1, fd);
514 struct stat sb;
515 ASSERT_EQ(0, fstat(fd, &sb));
516
517 // Memory map the file first and open the archive from the memory region.
518 android::FileMap file_map;
519 file_map.create(zip_path.c_str(), fd, 0/*offset*/, sb.st_size, true);
520 ZipArchiveHandle handle;
521 ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
522 zip_path.c_str(), &handle));
523
524 // Assert one entry can be found and extracted correctly.
525 std::string BINARY_PATH("META-INF/com/google/android/update-binary");
526 ZipString binary_path(BINARY_PATH.c_str());
527 ZipEntry binary_entry;
528 ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
529 TemporaryFile tmp_binary;
530 ASSERT_NE(-1, tmp_binary.fd);
531 ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
532}
533#endif
534
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800535static void ZipArchiveStreamTest(
536 ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
537 bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
538 ZipString name;
539 SetZipString(&name, entry_name);
540 ASSERT_EQ(0, FindEntry(handle, name, entry));
541 std::unique_ptr<ZipArchiveStreamEntry> stream;
542 if (raw) {
543 stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
544 if (entry->method == kCompressStored) {
545 read_data->resize(entry->uncompressed_length);
546 } else {
547 read_data->resize(entry->compressed_length);
548 }
549 } else {
550 stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
551 read_data->resize(entry->uncompressed_length);
552 }
553 uint8_t* read_data_ptr = read_data->data();
554 ASSERT_TRUE(stream.get() != nullptr);
555 const std::vector<uint8_t>* data;
556 uint64_t total_size = 0;
557 while ((data = stream->Read()) != nullptr) {
558 total_size += data->size();
559 memcpy(read_data_ptr, data->data(), data->size());
560 read_data_ptr += data->size();
561 }
562 ASSERT_EQ(verified, stream->Verify());
563 ASSERT_EQ(total_size, read_data->size());
564}
565
566static void ZipArchiveStreamTestUsingContents(
567 const std::string& zip_file, const std::string& entry_name,
568 const std::vector<uint8_t>& contents, bool raw) {
569 ZipArchiveHandle handle;
570 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
571
572 ZipEntry entry;
573 std::vector<uint8_t> read_data;
574 ZipArchiveStreamTest(handle, entry_name, raw, true, &entry, &read_data);
575
576 ASSERT_EQ(contents.size(), read_data.size());
577 ASSERT_TRUE(memcmp(read_data.data(), contents.data(), read_data.size()) == 0);
578
579 CloseArchive(handle);
580}
581
582static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file, const std::string& entry_name) {
583 ZipArchiveHandle handle;
584 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
585
586 ZipEntry entry;
587 std::vector<uint8_t> read_data;
588 ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
589
590 std::vector<uint8_t> cmp_data(entry.uncompressed_length);
591 ASSERT_EQ(entry.uncompressed_length, read_data.size());
592 ASSERT_EQ(0, ExtractToMemory(handle, &entry, cmp_data.data(), cmp_data.size()));
593 ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
594
595 CloseArchive(handle);
596}
597
598TEST(ziparchive, StreamCompressed) {
599 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
600}
601
602TEST(ziparchive, StreamUncompressed) {
603 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
604}
605
606TEST(ziparchive, StreamRawCompressed) {
607 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
608}
609
610TEST(ziparchive, StreamRawUncompressed) {
611 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
612}
613
614TEST(ziparchive, StreamLargeCompressed) {
615 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
616}
617
618TEST(ziparchive, StreamLargeUncompressed) {
619 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
620}
621
622TEST(ziparchive, StreamCompressedBadCrc) {
623 ZipArchiveHandle handle;
624 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
625
626 ZipEntry entry;
627 std::vector<uint8_t> read_data;
628 ZipArchiveStreamTest(handle, kATxtName, false, false, &entry, &read_data);
629
630 CloseArchive(handle);
631}
632
633TEST(ziparchive, StreamUncompressedBadCrc) {
634 ZipArchiveHandle handle;
635 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
636
637 ZipEntry entry;
638 std::vector<uint8_t> read_data;
639 ZipArchiveStreamTest(handle, kBTxtName, false, false, &entry, &read_data);
640
641 CloseArchive(handle);
642}
643
Narayan Kamath162b7052017-06-05 13:21:12 +0100644// Generated using the following Java program:
645// public static void main(String[] foo) throws Exception {
646// FileOutputStream fos = new
647// FileOutputStream("/tmp/data_descriptor.zip");
648// ZipOutputStream zos = new ZipOutputStream(fos);
649// ZipEntry ze = new ZipEntry("name");
650// ze.setMethod(ZipEntry.DEFLATED);
651// zos.putNextEntry(ze);
652// zos.write("abdcdefghijk".getBytes());
653// zos.closeEntry();
654// zos.close();
655// }
656//
657// cat /tmp/data_descriptor.zip | xxd -i
658//
659static const std::vector<uint8_t> kDataDescriptorZipFile{
660 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a, 0x00, 0x00,
661 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6e, 0x61,
662 0x6d, 0x65, 0x4b, 0x4c, 0x4a, 0x49, 0x4e, 0x49, 0x4d, 0x4b, 0xcf, 0xc8, 0xcc, 0xca, 0x06, 0x00,
663 //[sig---------------], [crc32---------------], [csize---------------], [size----------------]
664 0x50, 0x4b, 0x07, 0x08, 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
665 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a,
666 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61,
668 0x6d, 0x65, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x32, 0x00,
669 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
670
671// The offsets of the data descriptor in this file, so we can mess with
672// them later in the test.
673static constexpr uint32_t kDataDescriptorOffset = 48;
674static constexpr uint32_t kCSizeOffset = kDataDescriptorOffset + 8;
675static constexpr uint32_t kSizeOffset = kCSizeOffset + 4;
676
677static void ExtractEntryToMemory(const std::vector<uint8_t>& zip_data,
678 std::vector<uint8_t>* entry_out, int32_t* error_code_out) {
679 TemporaryFile tmp_file;
680 ASSERT_NE(-1, tmp_file.fd);
681 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &zip_data[0], zip_data.size()));
682 ZipArchiveHandle handle;
683 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "ExtractEntryToMemory", &handle));
684
685 // This function expects a variant of kDataDescriptorZipFile, for look for
686 // an entry whose name is "name" and whose size is 12 (contents =
687 // "abdcdefghijk").
688 ZipEntry entry;
689 ZipString empty_name;
690 SetZipString(&empty_name, "name");
691
692 ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
693 ASSERT_EQ(static_cast<uint32_t>(12), entry.uncompressed_length);
694
695 entry_out->resize(12);
696 (*error_code_out) = ExtractToMemory(handle, &entry, &((*entry_out)[0]), 12);
697
698 CloseArchive(handle);
699}
700
701TEST(ziparchive, ValidDataDescriptors) {
702 std::vector<uint8_t> entry;
703 int32_t error_code = 0;
704 ExtractEntryToMemory(kDataDescriptorZipFile, &entry, &error_code);
705
706 ASSERT_EQ(0, error_code);
707 ASSERT_EQ(12u, entry.size());
708 ASSERT_EQ('a', entry[0]);
709 ASSERT_EQ('k', entry[11]);
710}
711
712TEST(ziparchive, InvalidDataDescriptors) {
713 std::vector<uint8_t> invalid_csize = kDataDescriptorZipFile;
714 invalid_csize[kCSizeOffset] = 0xfe;
715
716 std::vector<uint8_t> entry;
717 int32_t error_code = 0;
718 ExtractEntryToMemory(invalid_csize, &entry, &error_code);
719
Narayan Kamath1ef9d2d2017-06-15 13:58:25 +0100720 ASSERT_EQ(kInconsistentInformation, error_code);
Narayan Kamath162b7052017-06-05 13:21:12 +0100721
722 std::vector<uint8_t> invalid_size = kDataDescriptorZipFile;
723 invalid_csize[kSizeOffset] = 0xfe;
724
725 error_code = 0;
726 entry.clear();
727 ExtractEntryToMemory(invalid_csize, &entry, &error_code);
728
Narayan Kamath1ef9d2d2017-06-15 13:58:25 +0100729 ASSERT_EQ(kInconsistentInformation, error_code);
730}
731
732TEST(ziparchive, ErrorCodeString) {
733 ASSERT_STREQ("Success", ErrorCodeString(0));
734
735 // Out of bounds.
736 ASSERT_STREQ("Unknown return code", ErrorCodeString(1));
737 ASSERT_STREQ("Unknown return code", ErrorCodeString(-13));
738
739 ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
Narayan Kamath162b7052017-06-05 13:21:12 +0100740}
741
Narayan Kamath58aaf462013-12-10 16:47:14 +0000742int main(int argc, char** argv) {
743 ::testing::InitGoogleTest(&argc, argv);
744
745 static struct option options[] = {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800746 { "test_data_dir", required_argument, nullptr, 't' },
747 { nullptr, 0, nullptr, 0 }
Narayan Kamath58aaf462013-12-10 16:47:14 +0000748 };
749
750 while (true) {
751 int option_index;
752 const int c = getopt_long_only(argc, argv, "", options, &option_index);
753 if (c == -1) {
754 break;
755 }
756
757 if (c == 't') {
758 test_data_dir = optarg;
759 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000760 }
761
Narayan Kamath58aaf462013-12-10 16:47:14 +0000762 if (test_data_dir.size() == 0) {
763 printf("Test data flag (--test_data_dir) required\n\n");
764 return -1;
765 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000766
Narayan Kamath58aaf462013-12-10 16:47:14 +0000767 if (test_data_dir[0] != '/') {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800768 std::vector<char> cwd_buffer(1024);
769 const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
770 if (cwd == nullptr) {
771 printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
772 test_data_dir.c_str());
773 return -2;
774 }
775 test_data_dir = '/' + test_data_dir;
776 test_data_dir = cwd + test_data_dir;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000777 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000778
Narayan Kamath58aaf462013-12-10 16:47:14 +0000779 return RUN_ALL_TESTS();
Narayan Kamath7462f022013-11-21 13:05:04 +0000780}