blob: 9dd6cc0dfedda25ecdd2d2cc55d1a55af4ee8941 [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 Kamath00a258c2013-12-13 16:06:19 +000017#include <errno.h>
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -070018#include <fcntl.h>
Narayan Kamath00a258c2013-12-13 16:06:19 +000019#include <getopt.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000020#include <stdio.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080021#include <string.h>
Narayan Kamath00a258c2013-12-13 16:06:19 +000022#include <unistd.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080023
Yabin Cui8e6f7222016-02-08 16:26:33 -080024#include <memory>
Narayan Kamath00a258c2013-12-13 16:06:19 +000025#include <vector>
26
Elliott Hughes4f713192015-12-04 22:00:26 -080027#include <android-base/file.h>
Yabin Cui8e6f7222016-02-08 16:26:33 -080028#include <android-base/test_utils.h>
Tianjie Xu18c25922016-09-29 15:27:41 -070029#include <android-base/unique_fd.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000030#include <gtest/gtest.h>
Tianjie Xu18c25922016-09-29 15:27:41 -070031#include <utils/FileMap.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080032#include <ziparchive/zip_archive.h>
33#include <ziparchive/zip_archive_stream_entry.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000034
Narayan Kamath58aaf462013-12-10 16:47:14 +000035static std::string test_data_dir;
Narayan Kamath7462f022013-11-21 13:05:04 +000036
Neil Fullerb1a113f2014-07-25 14:43:04 +010037static const std::string kMissingZip = "missing.zip";
Narayan Kamath58aaf462013-12-10 16:47:14 +000038static const std::string kValidZip = "valid.zip";
Christopher Ferrise6884ce2015-11-10 14:55:12 -080039static const std::string kLargeZip = "large.zip";
40static const std::string kBadCrcZip = "bad_crc.zip";
Tianjie Xu18c25922016-09-29 15:27:41 -070041static const std::string kUpdateZip = "dummy-update.zip";
Narayan Kamath58aaf462013-12-10 16:47:14 +000042
Christopher Ferrise6884ce2015-11-10 14:55:12 -080043static const std::vector<uint8_t> kATxtContents {
Narayan Kamath58aaf462013-12-10 16:47:14 +000044 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
45 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
46 '\n'
47};
48
Christopher Ferrise6884ce2015-11-10 14:55:12 -080049static const std::vector<uint8_t> kATxtContentsCompressed {
50 'K', 'L', 'J', 'N', 'I', 'M', 'K', 207, 'H',
51 132, 210, '\\', '\0'
52};
53
54static const std::vector<uint8_t> kBTxtContents {
Narayan Kamath58aaf462013-12-10 16:47:14 +000055 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
56 '\n'
57};
58
Christopher Ferrise6884ce2015-11-10 14:55:12 -080059static const std::string kATxtName("a.txt");
60static const std::string kBTxtName("b.txt");
61static const std::string kNonexistentTxtName("nonexistent.txt");
62static const std::string kEmptyTxtName("empty.txt");
63static const std::string kLargeCompressTxtName("compress.txt");
64static const std::string kLargeUncompressTxtName("uncompress.txt");
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +010065
Narayan Kamath58aaf462013-12-10 16:47:14 +000066static int32_t OpenArchiveWrapper(const std::string& name,
67 ZipArchiveHandle* handle) {
68 const std::string abs_path = test_data_dir + "/" + name;
69 return OpenArchive(abs_path.c_str(), handle);
70}
71
72static void AssertNameEquals(const std::string& name_str,
Yusuke Sato07447542015-06-25 14:39:19 -070073 const ZipString& name) {
Narayan Kamath58aaf462013-12-10 16:47:14 +000074 ASSERT_EQ(name_str.size(), name.name_length);
75 ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
76}
77
Christopher Ferrise6884ce2015-11-10 14:55:12 -080078static void SetZipString(ZipString* zip_str, const std::string& str) {
79 zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
80 zip_str->name_length = str.size();
81}
82
Narayan Kamath58aaf462013-12-10 16:47:14 +000083TEST(ziparchive, Open) {
84 ZipArchiveHandle handle;
85 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
86
87 CloseArchive(handle);
88}
89
Neil Fullerb1a113f2014-07-25 14:43:04 +010090TEST(ziparchive, OpenMissing) {
91 ZipArchiveHandle handle;
92 ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
93
94 // Confirm the file descriptor is not going to be mistaken for a valid one.
95 ASSERT_EQ(-1, GetFileDescriptor(handle));
96}
97
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -070098TEST(ziparchive, OpenAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -080099 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700100 ASSERT_NE(-1, fd);
101 ZipArchiveHandle handle;
102 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
103 CloseArchive(handle);
104 ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
105 ASSERT_EQ(EBADF, errno);
106}
107
108TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800109 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700110 ASSERT_NE(-1, fd);
111 ZipArchiveHandle handle;
112 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
113 CloseArchive(handle);
114 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
115 close(fd);
116}
117
Narayan Kamath58aaf462013-12-10 16:47:14 +0000118TEST(ziparchive, Iteration) {
119 ZipArchiveHandle handle;
120 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
121
122 void* iteration_cookie;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800123 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
Narayan Kamath7462f022013-11-21 13:05:04 +0000124
125 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700126 ZipString name;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000127
128 // b/c.txt
129 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
130 AssertNameEquals("b/c.txt", name);
131
132 // b/d.txt
133 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
134 AssertNameEquals("b/d.txt", name);
135
136 // a.txt
137 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
138 AssertNameEquals("a.txt", name);
139
140 // b.txt
141 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
142 AssertNameEquals("b.txt", name);
143
144 // b/
145 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
146 AssertNameEquals("b/", name);
147
148 // End of iteration.
149 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
150
151 CloseArchive(handle);
152}
153
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700154TEST(ziparchive, IterationWithPrefix) {
155 ZipArchiveHandle handle;
156 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
157
158 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700159 ZipString prefix("b/");
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800160 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, nullptr));
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700161
162 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700163 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700164
165 // b/c.txt
166 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
167 AssertNameEquals("b/c.txt", name);
168
169 // b/d.txt
170 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
171 AssertNameEquals("b/d.txt", name);
172
173 // b/
174 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
175 AssertNameEquals("b/", name);
176
177 // End of iteration.
178 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
179
180 CloseArchive(handle);
181}
182
183TEST(ziparchive, IterationWithSuffix) {
184 ZipArchiveHandle handle;
185 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
186
187 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700188 ZipString suffix(".txt");
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800189 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, &suffix));
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700190
191 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700192 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700193
194 // b/c.txt
195 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
196 AssertNameEquals("b/c.txt", name);
197
198 // b/d.txt
199 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
200 AssertNameEquals("b/d.txt", name);
201
202 // a.txt
203 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
204 AssertNameEquals("a.txt", name);
205
206 // b.txt
207 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
208 AssertNameEquals("b.txt", name);
209
210 // End of iteration.
211 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
212
213 CloseArchive(handle);
214}
215
216TEST(ziparchive, IterationWithPrefixAndSuffix) {
217 ZipArchiveHandle handle;
218 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
219
220 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700221 ZipString prefix("b");
222 ZipString suffix(".txt");
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700223 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
224
225 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700226 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700227
228 // b/c.txt
229 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
230 AssertNameEquals("b/c.txt", name);
231
232 // b/d.txt
233 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
234 AssertNameEquals("b/d.txt", name);
235
236 // b.txt
237 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
238 AssertNameEquals("b.txt", name);
239
240 // End of iteration.
241 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
242
243 CloseArchive(handle);
244}
245
246TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
247 ZipArchiveHandle handle;
248 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
249
250 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700251 ZipString prefix("x");
252 ZipString suffix("y");
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700253 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
254
255 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700256 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700257
258 // End of iteration.
259 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
260
261 CloseArchive(handle);
262}
263
Narayan Kamath58aaf462013-12-10 16:47:14 +0000264TEST(ziparchive, FindEntry) {
265 ZipArchiveHandle handle;
266 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
267
268 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700269 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800270 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100271 ASSERT_EQ(0, FindEntry(handle, name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000272
273 // Known facts about a.txt, from zipinfo -v.
274 ASSERT_EQ(63, data.offset);
275 ASSERT_EQ(kCompressDeflated, data.method);
276 ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
277 ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
278 ASSERT_EQ(0x950821c5, data.crc32);
beonit0e99a2f2015-07-18 02:08:16 +0900279 ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000280
281 // An entry that doesn't exist. Should be a negative return code.
Yusuke Sato07447542015-06-25 14:39:19 -0700282 ZipString absent_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800283 SetZipString(&absent_name, kNonexistentTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100284 ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000285
286 CloseArchive(handle);
287}
288
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200289TEST(ziparchive, TestInvalidDeclaredLength) {
290 ZipArchiveHandle handle;
291 ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
292
293 void* iteration_cookie;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800294 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200295
Yusuke Sato07447542015-06-25 14:39:19 -0700296 ZipString name;
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200297 ZipEntry data;
298
299 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
300 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
301
302 CloseArchive(handle);
303}
304
Narayan Kamath58aaf462013-12-10 16:47:14 +0000305TEST(ziparchive, ExtractToMemory) {
306 ZipArchiveHandle handle;
307 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
308
309 // An entry that's deflated.
310 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700311 ZipString a_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800312 SetZipString(&a_name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100313 ASSERT_EQ(0, FindEntry(handle, a_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000314 const uint32_t a_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800315 ASSERT_EQ(a_size, kATxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000316 uint8_t* buffer = new uint8_t[a_size];
317 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800318 ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000319 delete[] buffer;
320
321 // An entry that's stored.
Yusuke Sato07447542015-06-25 14:39:19 -0700322 ZipString b_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800323 SetZipString(&b_name, kBTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100324 ASSERT_EQ(0, FindEntry(handle, b_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000325 const uint32_t b_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800326 ASSERT_EQ(b_size, kBTxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000327 buffer = new uint8_t[b_size];
328 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800329 ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000330 delete[] buffer;
331
332 CloseArchive(handle);
333}
334
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100335static const uint32_t kEmptyEntriesZip[] = {
Narayan Kamath48953a12014-01-24 12:32:39 +0000336 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
337 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
338 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
339 0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000,
340 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
341 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
342 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100343
Narayan Kamathf899bd52015-04-17 11:53:14 +0100344// This is a zip file containing a single entry (ab.txt) that contains
345// 90072 repetitions of the string "ab\n" and has an uncompressed length
346// of 270216 bytes.
347static const uint16_t kAbZip[] = {
348 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
349 0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
350 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
351 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
352 0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
353 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
354 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
355 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
356 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
357 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
358 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
359 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
360 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
361 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
362 0x5555, 0x5555, 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, 0xdd55, 0x502c, 0x014b, 0x1e02,
370 0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
371 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
372 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
373 0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
374 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
375 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
376};
377
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800378static const std::string kAbTxtName("ab.txt");
Narayan Kamathf899bd52015-04-17 11:53:14 +0100379static const size_t kAbUncompressedSize = 270216;
380
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100381TEST(ziparchive, EmptyEntries) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800382 TemporaryFile tmp_file;
383 ASSERT_NE(-1, tmp_file.fd);
384 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
Narayan Kamath48953a12014-01-24 12:32:39 +0000385
386 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800387 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath48953a12014-01-24 12:32:39 +0000388
389 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700390 ZipString empty_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800391 SetZipString(&empty_name, kEmptyTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100392 ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
Narayan Kamath48953a12014-01-24 12:32:39 +0000393 ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
394 uint8_t buffer[1];
395 ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
396
Yabin Cui8e6f7222016-02-08 16:26:33 -0800397
398 TemporaryFile tmp_output_file;
399 ASSERT_NE(-1, tmp_output_file.fd);
400 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamath48953a12014-01-24 12:32:39 +0000401
402 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800403 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamath48953a12014-01-24 12:32:39 +0000404 ASSERT_EQ(0, stat_buf.st_size);
Narayan Kamath48953a12014-01-24 12:32:39 +0000405}
406
Narayan Kamathf899bd52015-04-17 11:53:14 +0100407TEST(ziparchive, EntryLargerThan32K) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800408 TemporaryFile tmp_file;
409 ASSERT_NE(-1, tmp_file.fd);
410 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
Narayan Kamathf899bd52015-04-17 11:53:14 +0100411 sizeof(kAbZip) - 1));
412 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800413 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100414
415 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700416 ZipString ab_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800417 SetZipString(&ab_name, kAbTxtName);
Narayan Kamathf899bd52015-04-17 11:53:14 +0100418 ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
419 ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
420
421 // Extract the entry to memory.
422 std::vector<uint8_t> buffer(kAbUncompressedSize);
423 ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
424
425 // Extract the entry to a file.
Yabin Cui8e6f7222016-02-08 16:26:33 -0800426 TemporaryFile tmp_output_file;
427 ASSERT_NE(-1, tmp_output_file.fd);
428 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100429
430 // Make sure the extracted file size is as expected.
431 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800432 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100433 ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
434
435 // Read the file back to a buffer and make sure the contents are
436 // the same as the memory buffer we extracted directly to.
437 std::vector<uint8_t> file_contents(kAbUncompressedSize);
Yabin Cui8e6f7222016-02-08 16:26:33 -0800438 ASSERT_EQ(0, lseek64(tmp_output_file.fd, 0, SEEK_SET));
439 ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0],
440 file_contents.size()));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100441 ASSERT_EQ(file_contents, buffer);
442
443 for (int i = 0; i < 90072; ++i) {
444 const uint8_t* line = &file_contents[0] + (3 * i);
445 ASSERT_EQ('a', line[0]);
446 ASSERT_EQ('b', line[1]);
447 ASSERT_EQ('\n', line[2]);
448 }
Narayan Kamathf899bd52015-04-17 11:53:14 +0100449}
450
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100451TEST(ziparchive, TrailerAfterEOCD) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800452 TemporaryFile tmp_file;
453 ASSERT_NE(-1, tmp_file.fd);
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100454
455 // Create a file with 8 bytes of random garbage.
456 static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
Yabin Cui8e6f7222016-02-08 16:26:33 -0800457 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
458 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100459
460 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800461 ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100462}
463
Narayan Kamath00a258c2013-12-13 16:06:19 +0000464TEST(ziparchive, ExtractToFile) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800465 TemporaryFile tmp_file;
466 ASSERT_NE(-1, tmp_file.fd);
Narayan Kamath00a258c2013-12-13 16:06:19 +0000467 const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
Yabin Cui8e6f7222016-02-08 16:26:33 -0800468 const size_t data_size = sizeof(data);
Narayan Kamath00a258c2013-12-13 16:06:19 +0000469
Yabin Cui8e6f7222016-02-08 16:26:33 -0800470 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000471
472 ZipArchiveHandle handle;
473 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
474
475 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700476 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800477 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100478 ASSERT_EQ(0, FindEntry(handle, name, &entry));
Yabin Cui8e6f7222016-02-08 16:26:33 -0800479 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000480
481
482 // Assert that the first 8 bytes of the file haven't been clobbered.
483 uint8_t read_buffer[data_size];
Yabin Cui8e6f7222016-02-08 16:26:33 -0800484 ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
485 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000486 ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
487
488 // Assert that the remainder of the file contains the incompressed data.
489 std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
Yabin Cui8e6f7222016-02-08 16:26:33 -0800490 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
491 entry.uncompressed_length));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800492 ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(),
493 kATxtContents.size()));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000494
495 // Assert that the total length of the file is sane
Yabin Cui8e6f7222016-02-08 16:26:33 -0800496 ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
497 lseek64(tmp_file.fd, 0, SEEK_END));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000498}
499
Tianjie Xu18c25922016-09-29 15:27:41 -0700500#if !defined(_WIN32)
501TEST(ziparchive, OpenFromMemory) {
502 const std::string zip_path = test_data_dir + "/" + kUpdateZip;
503 android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
504 ASSERT_NE(-1, fd);
505 struct stat sb;
506 ASSERT_EQ(0, fstat(fd, &sb));
507
508 // Memory map the file first and open the archive from the memory region.
509 android::FileMap file_map;
510 file_map.create(zip_path.c_str(), fd, 0/*offset*/, sb.st_size, true);
511 ZipArchiveHandle handle;
512 ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
513 zip_path.c_str(), &handle));
514
515 // Assert one entry can be found and extracted correctly.
516 std::string BINARY_PATH("META-INF/com/google/android/update-binary");
517 ZipString binary_path(BINARY_PATH.c_str());
518 ZipEntry binary_entry;
519 ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
520 TemporaryFile tmp_binary;
521 ASSERT_NE(-1, tmp_binary.fd);
522 ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
523}
524#endif
525
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800526static void ZipArchiveStreamTest(
527 ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
528 bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
529 ZipString name;
530 SetZipString(&name, entry_name);
531 ASSERT_EQ(0, FindEntry(handle, name, entry));
532 std::unique_ptr<ZipArchiveStreamEntry> stream;
533 if (raw) {
534 stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
535 if (entry->method == kCompressStored) {
536 read_data->resize(entry->uncompressed_length);
537 } else {
538 read_data->resize(entry->compressed_length);
539 }
540 } else {
541 stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
542 read_data->resize(entry->uncompressed_length);
543 }
544 uint8_t* read_data_ptr = read_data->data();
545 ASSERT_TRUE(stream.get() != nullptr);
546 const std::vector<uint8_t>* data;
547 uint64_t total_size = 0;
548 while ((data = stream->Read()) != nullptr) {
549 total_size += data->size();
550 memcpy(read_data_ptr, data->data(), data->size());
551 read_data_ptr += data->size();
552 }
553 ASSERT_EQ(verified, stream->Verify());
554 ASSERT_EQ(total_size, read_data->size());
555}
556
557static void ZipArchiveStreamTestUsingContents(
558 const std::string& zip_file, const std::string& entry_name,
559 const std::vector<uint8_t>& contents, bool raw) {
560 ZipArchiveHandle handle;
561 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
562
563 ZipEntry entry;
564 std::vector<uint8_t> read_data;
565 ZipArchiveStreamTest(handle, entry_name, raw, true, &entry, &read_data);
566
567 ASSERT_EQ(contents.size(), read_data.size());
568 ASSERT_TRUE(memcmp(read_data.data(), contents.data(), read_data.size()) == 0);
569
570 CloseArchive(handle);
571}
572
573static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file, const std::string& entry_name) {
574 ZipArchiveHandle handle;
575 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
576
577 ZipEntry entry;
578 std::vector<uint8_t> read_data;
579 ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
580
581 std::vector<uint8_t> cmp_data(entry.uncompressed_length);
582 ASSERT_EQ(entry.uncompressed_length, read_data.size());
583 ASSERT_EQ(0, ExtractToMemory(handle, &entry, cmp_data.data(), cmp_data.size()));
584 ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
585
586 CloseArchive(handle);
587}
588
589TEST(ziparchive, StreamCompressed) {
590 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
591}
592
593TEST(ziparchive, StreamUncompressed) {
594 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
595}
596
597TEST(ziparchive, StreamRawCompressed) {
598 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
599}
600
601TEST(ziparchive, StreamRawUncompressed) {
602 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
603}
604
605TEST(ziparchive, StreamLargeCompressed) {
606 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
607}
608
609TEST(ziparchive, StreamLargeUncompressed) {
610 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
611}
612
613TEST(ziparchive, StreamCompressedBadCrc) {
614 ZipArchiveHandle handle;
615 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
616
617 ZipEntry entry;
618 std::vector<uint8_t> read_data;
619 ZipArchiveStreamTest(handle, kATxtName, false, false, &entry, &read_data);
620
621 CloseArchive(handle);
622}
623
624TEST(ziparchive, StreamUncompressedBadCrc) {
625 ZipArchiveHandle handle;
626 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
627
628 ZipEntry entry;
629 std::vector<uint8_t> read_data;
630 ZipArchiveStreamTest(handle, kBTxtName, false, false, &entry, &read_data);
631
632 CloseArchive(handle);
633}
634
Narayan Kamath58aaf462013-12-10 16:47:14 +0000635int main(int argc, char** argv) {
636 ::testing::InitGoogleTest(&argc, argv);
637
638 static struct option options[] = {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800639 { "test_data_dir", required_argument, nullptr, 't' },
640 { nullptr, 0, nullptr, 0 }
Narayan Kamath58aaf462013-12-10 16:47:14 +0000641 };
642
643 while (true) {
644 int option_index;
645 const int c = getopt_long_only(argc, argv, "", options, &option_index);
646 if (c == -1) {
647 break;
648 }
649
650 if (c == 't') {
651 test_data_dir = optarg;
652 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000653 }
654
Narayan Kamath58aaf462013-12-10 16:47:14 +0000655 if (test_data_dir.size() == 0) {
656 printf("Test data flag (--test_data_dir) required\n\n");
657 return -1;
658 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000659
Narayan Kamath58aaf462013-12-10 16:47:14 +0000660 if (test_data_dir[0] != '/') {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800661 std::vector<char> cwd_buffer(1024);
662 const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
663 if (cwd == nullptr) {
664 printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
665 test_data_dir.c_str());
666 return -2;
667 }
668 test_data_dir = '/' + test_data_dir;
669 test_data_dir = cwd + test_data_dir;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000670 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000671
Narayan Kamath58aaf462013-12-10 16:47:14 +0000672 return RUN_ALL_TESTS();
Narayan Kamath7462f022013-11-21 13:05:04 +0000673}