blob: 52099c3b551820dc0ec4a449dddc8d8f49fbf7af [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 Xu18c25922016-09-29 15:27:41 -070043static const std::string kUpdateZip = "dummy-update.zip";
Narayan Kamath58aaf462013-12-10 16:47:14 +000044
Christopher Ferrise6884ce2015-11-10 14:55:12 -080045static const std::vector<uint8_t> kATxtContents {
Narayan Kamath58aaf462013-12-10 16:47:14 +000046 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
47 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
48 '\n'
49};
50
Christopher Ferrise6884ce2015-11-10 14:55:12 -080051static const std::vector<uint8_t> kATxtContentsCompressed {
52 'K', 'L', 'J', 'N', 'I', 'M', 'K', 207, 'H',
53 132, 210, '\\', '\0'
54};
55
56static const std::vector<uint8_t> kBTxtContents {
Narayan Kamath58aaf462013-12-10 16:47:14 +000057 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
58 '\n'
59};
60
Christopher Ferrise6884ce2015-11-10 14:55:12 -080061static const std::string kATxtName("a.txt");
62static const std::string kBTxtName("b.txt");
63static const std::string kNonexistentTxtName("nonexistent.txt");
64static const std::string kEmptyTxtName("empty.txt");
65static const std::string kLargeCompressTxtName("compress.txt");
66static const std::string kLargeUncompressTxtName("uncompress.txt");
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +010067
Narayan Kamath58aaf462013-12-10 16:47:14 +000068static int32_t OpenArchiveWrapper(const std::string& name,
69 ZipArchiveHandle* handle) {
70 const std::string abs_path = test_data_dir + "/" + name;
71 return OpenArchive(abs_path.c_str(), handle);
72}
73
74static void AssertNameEquals(const std::string& name_str,
Yusuke Sato07447542015-06-25 14:39:19 -070075 const ZipString& name) {
Narayan Kamath58aaf462013-12-10 16:47:14 +000076 ASSERT_EQ(name_str.size(), name.name_length);
77 ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
78}
79
Christopher Ferrise6884ce2015-11-10 14:55:12 -080080static void SetZipString(ZipString* zip_str, const std::string& str) {
81 zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
82 zip_str->name_length = str.size();
83}
84
Narayan Kamath58aaf462013-12-10 16:47:14 +000085TEST(ziparchive, Open) {
86 ZipArchiveHandle handle;
87 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
88
89 CloseArchive(handle);
90}
91
Neil Fullerb1a113f2014-07-25 14:43:04 +010092TEST(ziparchive, OpenMissing) {
93 ZipArchiveHandle handle;
94 ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
95
96 // Confirm the file descriptor is not going to be mistaken for a valid one.
97 ASSERT_EQ(-1, GetFileDescriptor(handle));
98}
99
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700100TEST(ziparchive, OpenAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800101 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700102 ASSERT_NE(-1, fd);
103 ZipArchiveHandle handle;
104 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
105 CloseArchive(handle);
106 ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
107 ASSERT_EQ(EBADF, errno);
108}
109
110TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800111 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700112 ASSERT_NE(-1, fd);
113 ZipArchiveHandle handle;
114 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
115 CloseArchive(handle);
116 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
117 close(fd);
118}
119
Narayan Kamath58aaf462013-12-10 16:47:14 +0000120TEST(ziparchive, Iteration) {
121 ZipArchiveHandle handle;
122 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
123
124 void* iteration_cookie;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800125 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
Narayan Kamath7462f022013-11-21 13:05:04 +0000126
127 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700128 ZipString name;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000129
130 // b/c.txt
131 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
132 AssertNameEquals("b/c.txt", name);
133
134 // b/d.txt
135 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
136 AssertNameEquals("b/d.txt", name);
137
138 // a.txt
139 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
140 AssertNameEquals("a.txt", name);
141
142 // b.txt
143 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
144 AssertNameEquals("b.txt", name);
145
146 // b/
147 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
148 AssertNameEquals("b/", name);
149
150 // End of iteration.
151 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
152
153 CloseArchive(handle);
154}
155
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700156TEST(ziparchive, IterationWithPrefix) {
157 ZipArchiveHandle handle;
158 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
159
160 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700161 ZipString prefix("b/");
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800162 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, nullptr));
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700163
164 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700165 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700166
167 // b/c.txt
168 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
169 AssertNameEquals("b/c.txt", name);
170
171 // b/d.txt
172 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
173 AssertNameEquals("b/d.txt", name);
174
175 // b/
176 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
177 AssertNameEquals("b/", name);
178
179 // End of iteration.
180 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
181
182 CloseArchive(handle);
183}
184
185TEST(ziparchive, IterationWithSuffix) {
186 ZipArchiveHandle handle;
187 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
188
189 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700190 ZipString suffix(".txt");
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800191 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, &suffix));
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700192
193 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700194 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700195
196 // b/c.txt
197 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
198 AssertNameEquals("b/c.txt", name);
199
200 // b/d.txt
201 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
202 AssertNameEquals("b/d.txt", name);
203
204 // a.txt
205 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
206 AssertNameEquals("a.txt", name);
207
208 // b.txt
209 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
210 AssertNameEquals("b.txt", name);
211
212 // End of iteration.
213 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
214
215 CloseArchive(handle);
216}
217
218TEST(ziparchive, IterationWithPrefixAndSuffix) {
219 ZipArchiveHandle handle;
220 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
221
222 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700223 ZipString prefix("b");
224 ZipString suffix(".txt");
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700225 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
226
227 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700228 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700229
230 // b/c.txt
231 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
232 AssertNameEquals("b/c.txt", name);
233
234 // b/d.txt
235 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
236 AssertNameEquals("b/d.txt", name);
237
238 // b.txt
239 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
240 AssertNameEquals("b.txt", name);
241
242 // End of iteration.
243 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
244
245 CloseArchive(handle);
246}
247
248TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
249 ZipArchiveHandle handle;
250 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
251
252 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700253 ZipString prefix("x");
254 ZipString suffix("y");
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700255 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
256
257 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700258 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700259
260 // End of iteration.
261 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
262
263 CloseArchive(handle);
264}
265
Narayan Kamath58aaf462013-12-10 16:47:14 +0000266TEST(ziparchive, FindEntry) {
267 ZipArchiveHandle handle;
268 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
269
270 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700271 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800272 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100273 ASSERT_EQ(0, FindEntry(handle, name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000274
275 // Known facts about a.txt, from zipinfo -v.
276 ASSERT_EQ(63, data.offset);
277 ASSERT_EQ(kCompressDeflated, data.method);
278 ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
279 ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
280 ASSERT_EQ(0x950821c5, data.crc32);
beonit0e99a2f2015-07-18 02:08:16 +0900281 ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000282
283 // An entry that doesn't exist. Should be a negative return code.
Yusuke Sato07447542015-06-25 14:39:19 -0700284 ZipString absent_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800285 SetZipString(&absent_name, kNonexistentTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100286 ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000287
288 CloseArchive(handle);
289}
290
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200291TEST(ziparchive, TestInvalidDeclaredLength) {
292 ZipArchiveHandle handle;
293 ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
294
295 void* iteration_cookie;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800296 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200297
Yusuke Sato07447542015-06-25 14:39:19 -0700298 ZipString name;
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200299 ZipEntry data;
300
301 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
302 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
303
304 CloseArchive(handle);
305}
306
Narayan Kamath58aaf462013-12-10 16:47:14 +0000307TEST(ziparchive, ExtractToMemory) {
308 ZipArchiveHandle handle;
309 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
310
311 // An entry that's deflated.
312 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700313 ZipString a_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800314 SetZipString(&a_name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100315 ASSERT_EQ(0, FindEntry(handle, a_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000316 const uint32_t a_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800317 ASSERT_EQ(a_size, kATxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000318 uint8_t* buffer = new uint8_t[a_size];
319 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800320 ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000321 delete[] buffer;
322
323 // An entry that's stored.
Yusuke Sato07447542015-06-25 14:39:19 -0700324 ZipString b_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800325 SetZipString(&b_name, kBTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100326 ASSERT_EQ(0, FindEntry(handle, b_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000327 const uint32_t b_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800328 ASSERT_EQ(b_size, kBTxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000329 buffer = new uint8_t[b_size];
330 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800331 ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000332 delete[] buffer;
333
334 CloseArchive(handle);
335}
336
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100337static const uint32_t kEmptyEntriesZip[] = {
Narayan Kamath48953a12014-01-24 12:32:39 +0000338 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
339 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
340 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
341 0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000,
342 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
343 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
344 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100345
Narayan Kamathf899bd52015-04-17 11:53:14 +0100346// This is a zip file containing a single entry (ab.txt) that contains
347// 90072 repetitions of the string "ab\n" and has an uncompressed length
348// of 270216 bytes.
349static const uint16_t kAbZip[] = {
350 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
351 0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
352 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
353 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
354 0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
355 0x841f, 0x45fc, 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, 0x5555, 0x5555, 0x5555, 0x5555,
370 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
371 0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02,
372 0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
373 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
374 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
375 0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
376 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
377 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
378};
379
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800380static const std::string kAbTxtName("ab.txt");
Narayan Kamathf899bd52015-04-17 11:53:14 +0100381static const size_t kAbUncompressedSize = 270216;
382
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100383TEST(ziparchive, EmptyEntries) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800384 TemporaryFile tmp_file;
385 ASSERT_NE(-1, tmp_file.fd);
386 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
Narayan Kamath48953a12014-01-24 12:32:39 +0000387
388 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800389 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath48953a12014-01-24 12:32:39 +0000390
391 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700392 ZipString empty_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800393 SetZipString(&empty_name, kEmptyTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100394 ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
Narayan Kamath48953a12014-01-24 12:32:39 +0000395 ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
396 uint8_t buffer[1];
397 ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
398
Yabin Cui8e6f7222016-02-08 16:26:33 -0800399
400 TemporaryFile tmp_output_file;
401 ASSERT_NE(-1, tmp_output_file.fd);
402 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamath48953a12014-01-24 12:32:39 +0000403
404 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800405 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamath48953a12014-01-24 12:32:39 +0000406 ASSERT_EQ(0, stat_buf.st_size);
Narayan Kamath48953a12014-01-24 12:32:39 +0000407}
408
Narayan Kamathf899bd52015-04-17 11:53:14 +0100409TEST(ziparchive, EntryLargerThan32K) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800410 TemporaryFile tmp_file;
411 ASSERT_NE(-1, tmp_file.fd);
412 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
Narayan Kamathf899bd52015-04-17 11:53:14 +0100413 sizeof(kAbZip) - 1));
414 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800415 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100416
417 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700418 ZipString ab_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800419 SetZipString(&ab_name, kAbTxtName);
Narayan Kamathf899bd52015-04-17 11:53:14 +0100420 ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
421 ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
422
423 // Extract the entry to memory.
424 std::vector<uint8_t> buffer(kAbUncompressedSize);
425 ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
426
427 // Extract the entry to a file.
Yabin Cui8e6f7222016-02-08 16:26:33 -0800428 TemporaryFile tmp_output_file;
429 ASSERT_NE(-1, tmp_output_file.fd);
430 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100431
432 // Make sure the extracted file size is as expected.
433 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800434 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100435 ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
436
437 // Read the file back to a buffer and make sure the contents are
438 // the same as the memory buffer we extracted directly to.
439 std::vector<uint8_t> file_contents(kAbUncompressedSize);
Yabin Cui8e6f7222016-02-08 16:26:33 -0800440 ASSERT_EQ(0, lseek64(tmp_output_file.fd, 0, SEEK_SET));
441 ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0],
442 file_contents.size()));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100443 ASSERT_EQ(file_contents, buffer);
444
445 for (int i = 0; i < 90072; ++i) {
446 const uint8_t* line = &file_contents[0] + (3 * i);
447 ASSERT_EQ('a', line[0]);
448 ASSERT_EQ('b', line[1]);
449 ASSERT_EQ('\n', line[2]);
450 }
Narayan Kamathf899bd52015-04-17 11:53:14 +0100451}
452
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100453TEST(ziparchive, TrailerAfterEOCD) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800454 TemporaryFile tmp_file;
455 ASSERT_NE(-1, tmp_file.fd);
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100456
457 // Create a file with 8 bytes of random garbage.
458 static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
Yabin Cui8e6f7222016-02-08 16:26:33 -0800459 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
460 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100461
462 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800463 ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100464}
465
Narayan Kamath00a258c2013-12-13 16:06:19 +0000466TEST(ziparchive, ExtractToFile) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800467 TemporaryFile tmp_file;
468 ASSERT_NE(-1, tmp_file.fd);
Narayan Kamath00a258c2013-12-13 16:06:19 +0000469 const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
Yabin Cui8e6f7222016-02-08 16:26:33 -0800470 const size_t data_size = sizeof(data);
Narayan Kamath00a258c2013-12-13 16:06:19 +0000471
Yabin Cui8e6f7222016-02-08 16:26:33 -0800472 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000473
474 ZipArchiveHandle handle;
475 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
476
477 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700478 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800479 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100480 ASSERT_EQ(0, FindEntry(handle, name, &entry));
Yabin Cui8e6f7222016-02-08 16:26:33 -0800481 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000482
483
484 // Assert that the first 8 bytes of the file haven't been clobbered.
485 uint8_t read_buffer[data_size];
Yabin Cui8e6f7222016-02-08 16:26:33 -0800486 ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
487 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000488 ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
489
490 // Assert that the remainder of the file contains the incompressed data.
491 std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
Yabin Cui8e6f7222016-02-08 16:26:33 -0800492 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
493 entry.uncompressed_length));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800494 ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(),
495 kATxtContents.size()));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000496
497 // Assert that the total length of the file is sane
Yabin Cui8e6f7222016-02-08 16:26:33 -0800498 ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
499 lseek64(tmp_file.fd, 0, SEEK_END));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000500}
501
Tianjie Xu18c25922016-09-29 15:27:41 -0700502#if !defined(_WIN32)
503TEST(ziparchive, OpenFromMemory) {
504 const std::string zip_path = test_data_dir + "/" + kUpdateZip;
505 android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
506 ASSERT_NE(-1, fd);
507 struct stat sb;
508 ASSERT_EQ(0, fstat(fd, &sb));
509
510 // Memory map the file first and open the archive from the memory region.
511 android::FileMap file_map;
512 file_map.create(zip_path.c_str(), fd, 0/*offset*/, sb.st_size, true);
513 ZipArchiveHandle handle;
514 ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
515 zip_path.c_str(), &handle));
516
517 // Assert one entry can be found and extracted correctly.
518 std::string BINARY_PATH("META-INF/com/google/android/update-binary");
519 ZipString binary_path(BINARY_PATH.c_str());
520 ZipEntry binary_entry;
521 ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
522 TemporaryFile tmp_binary;
523 ASSERT_NE(-1, tmp_binary.fd);
524 ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
525}
526#endif
527
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800528static void ZipArchiveStreamTest(
529 ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
530 bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
531 ZipString name;
532 SetZipString(&name, entry_name);
533 ASSERT_EQ(0, FindEntry(handle, name, entry));
534 std::unique_ptr<ZipArchiveStreamEntry> stream;
535 if (raw) {
536 stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
537 if (entry->method == kCompressStored) {
538 read_data->resize(entry->uncompressed_length);
539 } else {
540 read_data->resize(entry->compressed_length);
541 }
542 } else {
543 stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
544 read_data->resize(entry->uncompressed_length);
545 }
546 uint8_t* read_data_ptr = read_data->data();
547 ASSERT_TRUE(stream.get() != nullptr);
548 const std::vector<uint8_t>* data;
549 uint64_t total_size = 0;
550 while ((data = stream->Read()) != nullptr) {
551 total_size += data->size();
552 memcpy(read_data_ptr, data->data(), data->size());
553 read_data_ptr += data->size();
554 }
555 ASSERT_EQ(verified, stream->Verify());
556 ASSERT_EQ(total_size, read_data->size());
557}
558
559static void ZipArchiveStreamTestUsingContents(
560 const std::string& zip_file, const std::string& entry_name,
561 const std::vector<uint8_t>& contents, bool raw) {
562 ZipArchiveHandle handle;
563 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
564
565 ZipEntry entry;
566 std::vector<uint8_t> read_data;
567 ZipArchiveStreamTest(handle, entry_name, raw, true, &entry, &read_data);
568
569 ASSERT_EQ(contents.size(), read_data.size());
570 ASSERT_TRUE(memcmp(read_data.data(), contents.data(), read_data.size()) == 0);
571
572 CloseArchive(handle);
573}
574
575static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file, const std::string& entry_name) {
576 ZipArchiveHandle handle;
577 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
578
579 ZipEntry entry;
580 std::vector<uint8_t> read_data;
581 ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
582
583 std::vector<uint8_t> cmp_data(entry.uncompressed_length);
584 ASSERT_EQ(entry.uncompressed_length, read_data.size());
585 ASSERT_EQ(0, ExtractToMemory(handle, &entry, cmp_data.data(), cmp_data.size()));
586 ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
587
588 CloseArchive(handle);
589}
590
591TEST(ziparchive, StreamCompressed) {
592 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
593}
594
595TEST(ziparchive, StreamUncompressed) {
596 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
597}
598
599TEST(ziparchive, StreamRawCompressed) {
600 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
601}
602
603TEST(ziparchive, StreamRawUncompressed) {
604 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
605}
606
607TEST(ziparchive, StreamLargeCompressed) {
608 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
609}
610
611TEST(ziparchive, StreamLargeUncompressed) {
612 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
613}
614
615TEST(ziparchive, StreamCompressedBadCrc) {
616 ZipArchiveHandle handle;
617 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
618
619 ZipEntry entry;
620 std::vector<uint8_t> read_data;
621 ZipArchiveStreamTest(handle, kATxtName, false, false, &entry, &read_data);
622
623 CloseArchive(handle);
624}
625
626TEST(ziparchive, StreamUncompressedBadCrc) {
627 ZipArchiveHandle handle;
628 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
629
630 ZipEntry entry;
631 std::vector<uint8_t> read_data;
632 ZipArchiveStreamTest(handle, kBTxtName, false, false, &entry, &read_data);
633
634 CloseArchive(handle);
635}
636
Narayan Kamath162b7052017-06-05 13:21:12 +0100637// Generated using the following Java program:
638// public static void main(String[] foo) throws Exception {
639// FileOutputStream fos = new
640// FileOutputStream("/tmp/data_descriptor.zip");
641// ZipOutputStream zos = new ZipOutputStream(fos);
642// ZipEntry ze = new ZipEntry("name");
643// ze.setMethod(ZipEntry.DEFLATED);
644// zos.putNextEntry(ze);
645// zos.write("abdcdefghijk".getBytes());
646// zos.closeEntry();
647// zos.close();
648// }
649//
650// cat /tmp/data_descriptor.zip | xxd -i
651//
652static const std::vector<uint8_t> kDataDescriptorZipFile{
653 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a, 0x00, 0x00,
654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6e, 0x61,
655 0x6d, 0x65, 0x4b, 0x4c, 0x4a, 0x49, 0x4e, 0x49, 0x4d, 0x4b, 0xcf, 0xc8, 0xcc, 0xca, 0x06, 0x00,
656 //[sig---------------], [crc32---------------], [csize---------------], [size----------------]
657 0x50, 0x4b, 0x07, 0x08, 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
658 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a,
659 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61,
661 0x6d, 0x65, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x32, 0x00,
662 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
663
664// The offsets of the data descriptor in this file, so we can mess with
665// them later in the test.
666static constexpr uint32_t kDataDescriptorOffset = 48;
667static constexpr uint32_t kCSizeOffset = kDataDescriptorOffset + 8;
668static constexpr uint32_t kSizeOffset = kCSizeOffset + 4;
669
670static void ExtractEntryToMemory(const std::vector<uint8_t>& zip_data,
671 std::vector<uint8_t>* entry_out, int32_t* error_code_out) {
672 TemporaryFile tmp_file;
673 ASSERT_NE(-1, tmp_file.fd);
674 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &zip_data[0], zip_data.size()));
675 ZipArchiveHandle handle;
676 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "ExtractEntryToMemory", &handle));
677
678 // This function expects a variant of kDataDescriptorZipFile, for look for
679 // an entry whose name is "name" and whose size is 12 (contents =
680 // "abdcdefghijk").
681 ZipEntry entry;
682 ZipString empty_name;
683 SetZipString(&empty_name, "name");
684
685 ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
686 ASSERT_EQ(static_cast<uint32_t>(12), entry.uncompressed_length);
687
688 entry_out->resize(12);
689 (*error_code_out) = ExtractToMemory(handle, &entry, &((*entry_out)[0]), 12);
690
691 CloseArchive(handle);
692}
693
694TEST(ziparchive, ValidDataDescriptors) {
695 std::vector<uint8_t> entry;
696 int32_t error_code = 0;
697 ExtractEntryToMemory(kDataDescriptorZipFile, &entry, &error_code);
698
699 ASSERT_EQ(0, error_code);
700 ASSERT_EQ(12u, entry.size());
701 ASSERT_EQ('a', entry[0]);
702 ASSERT_EQ('k', entry[11]);
703}
704
705TEST(ziparchive, InvalidDataDescriptors) {
706 std::vector<uint8_t> invalid_csize = kDataDescriptorZipFile;
707 invalid_csize[kCSizeOffset] = 0xfe;
708
709 std::vector<uint8_t> entry;
710 int32_t error_code = 0;
711 ExtractEntryToMemory(invalid_csize, &entry, &error_code);
712
Narayan Kamath1ef9d2d2017-06-15 13:58:25 +0100713 ASSERT_EQ(kInconsistentInformation, error_code);
Narayan Kamath162b7052017-06-05 13:21:12 +0100714
715 std::vector<uint8_t> invalid_size = kDataDescriptorZipFile;
716 invalid_csize[kSizeOffset] = 0xfe;
717
718 error_code = 0;
719 entry.clear();
720 ExtractEntryToMemory(invalid_csize, &entry, &error_code);
721
Narayan Kamath1ef9d2d2017-06-15 13:58:25 +0100722 ASSERT_EQ(kInconsistentInformation, error_code);
723}
724
725TEST(ziparchive, ErrorCodeString) {
726 ASSERT_STREQ("Success", ErrorCodeString(0));
727
728 // Out of bounds.
729 ASSERT_STREQ("Unknown return code", ErrorCodeString(1));
730 ASSERT_STREQ("Unknown return code", ErrorCodeString(-13));
731
732 ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
Narayan Kamath162b7052017-06-05 13:21:12 +0100733}
734
Narayan Kamath58aaf462013-12-10 16:47:14 +0000735int main(int argc, char** argv) {
736 ::testing::InitGoogleTest(&argc, argv);
737
738 static struct option options[] = {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800739 { "test_data_dir", required_argument, nullptr, 't' },
740 { nullptr, 0, nullptr, 0 }
Narayan Kamath58aaf462013-12-10 16:47:14 +0000741 };
742
743 while (true) {
744 int option_index;
745 const int c = getopt_long_only(argc, argv, "", options, &option_index);
746 if (c == -1) {
747 break;
748 }
749
750 if (c == 't') {
751 test_data_dir = optarg;
752 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000753 }
754
Narayan Kamath58aaf462013-12-10 16:47:14 +0000755 if (test_data_dir.size() == 0) {
756 printf("Test data flag (--test_data_dir) required\n\n");
757 return -1;
758 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000759
Narayan Kamath58aaf462013-12-10 16:47:14 +0000760 if (test_data_dir[0] != '/') {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800761 std::vector<char> cwd_buffer(1024);
762 const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
763 if (cwd == nullptr) {
764 printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
765 test_data_dir.c_str());
766 return -2;
767 }
768 test_data_dir = '/' + test_data_dir;
769 test_data_dir = cwd + test_data_dir;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000770 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000771
Narayan Kamath58aaf462013-12-10 16:47:14 +0000772 return RUN_ALL_TESTS();
Narayan Kamath7462f022013-11-21 13:05:04 +0000773}