1 /*
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
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <getopt.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include <memory>
25 #include <vector>
26
27 #include <android-base/file.h>
28 #include <android-base/test_utils.h>
29 #include <android-base/unique_fd.h>
30 #include <gtest/gtest.h>
31 #include <utils/FileMap.h>
32 #include <ziparchive/zip_archive.h>
33 #include <ziparchive/zip_archive_stream_entry.h>
34
35 static std::string test_data_dir;
36
37 static const std::string kMissingZip = "missing.zip";
38 static const std::string kValidZip = "valid.zip";
39 static const std::string kLargeZip = "large.zip";
40 static const std::string kBadCrcZip = "bad_crc.zip";
41 static const std::string kCrashApk = "crash.apk";
42 static const std::string kBadFilenameZip = "bad_filename.zip";
43 static const std::string kUpdateZip = "dummy-update.zip";
44
45 static const std::vector<uint8_t> kATxtContents {
46 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
47 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
48 '\n'
49 };
50
51 static const std::vector<uint8_t> kATxtContentsCompressed {
52 'K', 'L', 'J', 'N', 'I', 'M', 'K', 207, 'H',
53 132, 210, '\\', '\0'
54 };
55
56 static const std::vector<uint8_t> kBTxtContents {
57 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
58 '\n'
59 };
60
61 static const std::string kATxtName("a.txt");
62 static const std::string kBTxtName("b.txt");
63 static const std::string kNonexistentTxtName("nonexistent.txt");
64 static const std::string kEmptyTxtName("empty.txt");
65 static const std::string kLargeCompressTxtName("compress.txt");
66 static const std::string kLargeUncompressTxtName("uncompress.txt");
67
OpenArchiveWrapper(const std::string & name,ZipArchiveHandle * handle)68 static 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
AssertNameEquals(const std::string & name_str,const ZipString & name)74 static void AssertNameEquals(const std::string& name_str,
75 const ZipString& name) {
76 ASSERT_EQ(name_str.size(), name.name_length);
77 ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
78 }
79
SetZipString(ZipString * zip_str,const std::string & str)80 static 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
TEST(ziparchive,Open)85 TEST(ziparchive, Open) {
86 ZipArchiveHandle handle;
87 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
88 CloseArchive(handle);
89
90 ASSERT_EQ(-1, OpenArchiveWrapper(kBadFilenameZip, &handle));
91 CloseArchive(handle);
92 }
93
TEST(ziparchive,OutOfBound)94 TEST(ziparchive, OutOfBound) {
95 ZipArchiveHandle handle;
96 ASSERT_EQ(-8, OpenArchiveWrapper(kCrashApk, &handle));
97 CloseArchive(handle);
98 }
99
TEST(ziparchive,OpenMissing)100 TEST(ziparchive, OpenMissing) {
101 ZipArchiveHandle handle;
102 ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
103
104 // Confirm the file descriptor is not going to be mistaken for a valid one.
105 ASSERT_EQ(-1, GetFileDescriptor(handle));
106 }
107
TEST(ziparchive,OpenAssumeFdOwnership)108 TEST(ziparchive, OpenAssumeFdOwnership) {
109 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
110 ASSERT_NE(-1, fd);
111 ZipArchiveHandle handle;
112 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
113 CloseArchive(handle);
114 ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
115 ASSERT_EQ(EBADF, errno);
116 }
117
TEST(ziparchive,OpenDoNotAssumeFdOwnership)118 TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
119 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
120 ASSERT_NE(-1, fd);
121 ZipArchiveHandle handle;
122 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
123 CloseArchive(handle);
124 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
125 close(fd);
126 }
127
TEST(ziparchive,Iteration)128 TEST(ziparchive, Iteration) {
129 ZipArchiveHandle handle;
130 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
131
132 void* iteration_cookie;
133 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
134
135 ZipEntry data;
136 ZipString name;
137
138 // b/c.txt
139 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
140 AssertNameEquals("b/c.txt", name);
141
142 // b/d.txt
143 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
144 AssertNameEquals("b/d.txt", name);
145
146 // a.txt
147 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
148 AssertNameEquals("a.txt", name);
149
150 // b.txt
151 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
152 AssertNameEquals("b.txt", name);
153
154 // b/
155 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
156 AssertNameEquals("b/", name);
157
158 // End of iteration.
159 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
160
161 CloseArchive(handle);
162 }
163
TEST(ziparchive,IterationWithPrefix)164 TEST(ziparchive, IterationWithPrefix) {
165 ZipArchiveHandle handle;
166 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
167
168 void* iteration_cookie;
169 ZipString prefix("b/");
170 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, nullptr));
171
172 ZipEntry data;
173 ZipString name;
174
175 // b/c.txt
176 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
177 AssertNameEquals("b/c.txt", name);
178
179 // b/d.txt
180 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
181 AssertNameEquals("b/d.txt", name);
182
183 // b/
184 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
185 AssertNameEquals("b/", name);
186
187 // End of iteration.
188 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
189
190 CloseArchive(handle);
191 }
192
TEST(ziparchive,IterationWithSuffix)193 TEST(ziparchive, IterationWithSuffix) {
194 ZipArchiveHandle handle;
195 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
196
197 void* iteration_cookie;
198 ZipString suffix(".txt");
199 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, &suffix));
200
201 ZipEntry data;
202 ZipString name;
203
204 // b/c.txt
205 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
206 AssertNameEquals("b/c.txt", name);
207
208 // b/d.txt
209 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
210 AssertNameEquals("b/d.txt", name);
211
212 // a.txt
213 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
214 AssertNameEquals("a.txt", name);
215
216 // b.txt
217 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
218 AssertNameEquals("b.txt", name);
219
220 // End of iteration.
221 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
222
223 CloseArchive(handle);
224 }
225
TEST(ziparchive,IterationWithPrefixAndSuffix)226 TEST(ziparchive, IterationWithPrefixAndSuffix) {
227 ZipArchiveHandle handle;
228 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
229
230 void* iteration_cookie;
231 ZipString prefix("b");
232 ZipString suffix(".txt");
233 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
234
235 ZipEntry data;
236 ZipString name;
237
238 // b/c.txt
239 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
240 AssertNameEquals("b/c.txt", name);
241
242 // b/d.txt
243 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
244 AssertNameEquals("b/d.txt", name);
245
246 // b.txt
247 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
248 AssertNameEquals("b.txt", name);
249
250 // End of iteration.
251 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
252
253 CloseArchive(handle);
254 }
255
TEST(ziparchive,IterationWithBadPrefixAndSuffix)256 TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
257 ZipArchiveHandle handle;
258 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
259
260 void* iteration_cookie;
261 ZipString prefix("x");
262 ZipString suffix("y");
263 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
264
265 ZipEntry data;
266 ZipString name;
267
268 // End of iteration.
269 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
270
271 CloseArchive(handle);
272 }
273
TEST(ziparchive,FindEntry)274 TEST(ziparchive, FindEntry) {
275 ZipArchiveHandle handle;
276 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
277
278 ZipEntry data;
279 ZipString name;
280 SetZipString(&name, kATxtName);
281 ASSERT_EQ(0, FindEntry(handle, name, &data));
282
283 // Known facts about a.txt, from zipinfo -v.
284 ASSERT_EQ(63, data.offset);
285 ASSERT_EQ(kCompressDeflated, data.method);
286 ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
287 ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
288 ASSERT_EQ(0x950821c5, data.crc32);
289 ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
290
291 // An entry that doesn't exist. Should be a negative return code.
292 ZipString absent_name;
293 SetZipString(&absent_name, kNonexistentTxtName);
294 ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
295
296 CloseArchive(handle);
297 }
298
TEST(ziparchive,TestInvalidDeclaredLength)299 TEST(ziparchive, TestInvalidDeclaredLength) {
300 ZipArchiveHandle handle;
301 ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
302
303 void* iteration_cookie;
304 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
305
306 ZipString name;
307 ZipEntry data;
308
309 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
310 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
311
312 CloseArchive(handle);
313 }
314
TEST(ziparchive,ExtractToMemory)315 TEST(ziparchive, ExtractToMemory) {
316 ZipArchiveHandle handle;
317 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
318
319 // An entry that's deflated.
320 ZipEntry data;
321 ZipString a_name;
322 SetZipString(&a_name, kATxtName);
323 ASSERT_EQ(0, FindEntry(handle, a_name, &data));
324 const uint32_t a_size = data.uncompressed_length;
325 ASSERT_EQ(a_size, kATxtContents.size());
326 uint8_t* buffer = new uint8_t[a_size];
327 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
328 ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
329 delete[] buffer;
330
331 // An entry that's stored.
332 ZipString b_name;
333 SetZipString(&b_name, kBTxtName);
334 ASSERT_EQ(0, FindEntry(handle, b_name, &data));
335 const uint32_t b_size = data.uncompressed_length;
336 ASSERT_EQ(b_size, kBTxtContents.size());
337 buffer = new uint8_t[b_size];
338 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
339 ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
340 delete[] buffer;
341
342 CloseArchive(handle);
343 }
344
345 static const uint32_t kEmptyEntriesZip[] = {
346 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
347 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
348 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
349 0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000,
350 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
351 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
352 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
353
354 // This is a zip file containing a single entry (ab.txt) that contains
355 // 90072 repetitions of the string "ab\n" and has an uncompressed length
356 // of 270216 bytes.
357 static const uint16_t kAbZip[] = {
358 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
359 0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
360 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
361 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
362 0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
363 0x841f, 0x45fc, 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, 0x5555, 0x5555, 0x5555, 0x5555,
379 0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02,
380 0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
381 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
382 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
383 0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
384 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
385 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
386 };
387
388 static const std::string kAbTxtName("ab.txt");
389 static const size_t kAbUncompressedSize = 270216;
390
TEST(ziparchive,EmptyEntries)391 TEST(ziparchive, EmptyEntries) {
392 TemporaryFile tmp_file;
393 ASSERT_NE(-1, tmp_file.fd);
394 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
395
396 ZipArchiveHandle handle;
397 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
398
399 ZipEntry entry;
400 ZipString empty_name;
401 SetZipString(&empty_name, kEmptyTxtName);
402 ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
403 ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
404 uint8_t buffer[1];
405 ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
406
407
408 TemporaryFile tmp_output_file;
409 ASSERT_NE(-1, tmp_output_file.fd);
410 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
411
412 struct stat stat_buf;
413 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
414 ASSERT_EQ(0, stat_buf.st_size);
415 }
416
TEST(ziparchive,EntryLargerThan32K)417 TEST(ziparchive, EntryLargerThan32K) {
418 TemporaryFile tmp_file;
419 ASSERT_NE(-1, tmp_file.fd);
420 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
421 sizeof(kAbZip) - 1));
422 ZipArchiveHandle handle;
423 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
424
425 ZipEntry entry;
426 ZipString ab_name;
427 SetZipString(&ab_name, kAbTxtName);
428 ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
429 ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
430
431 // Extract the entry to memory.
432 std::vector<uint8_t> buffer(kAbUncompressedSize);
433 ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
434
435 // Extract the entry to a file.
436 TemporaryFile tmp_output_file;
437 ASSERT_NE(-1, tmp_output_file.fd);
438 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
439
440 // Make sure the extracted file size is as expected.
441 struct stat stat_buf;
442 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
443 ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
444
445 // Read the file back to a buffer and make sure the contents are
446 // the same as the memory buffer we extracted directly to.
447 std::vector<uint8_t> file_contents(kAbUncompressedSize);
448 ASSERT_EQ(0, lseek64(tmp_output_file.fd, 0, SEEK_SET));
449 ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0],
450 file_contents.size()));
451 ASSERT_EQ(file_contents, buffer);
452
453 for (int i = 0; i < 90072; ++i) {
454 const uint8_t* line = &file_contents[0] + (3 * i);
455 ASSERT_EQ('a', line[0]);
456 ASSERT_EQ('b', line[1]);
457 ASSERT_EQ('\n', line[2]);
458 }
459 }
460
TEST(ziparchive,TrailerAfterEOCD)461 TEST(ziparchive, TrailerAfterEOCD) {
462 TemporaryFile tmp_file;
463 ASSERT_NE(-1, tmp_file.fd);
464
465 // Create a file with 8 bytes of random garbage.
466 static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
467 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
468 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
469
470 ZipArchiveHandle handle;
471 ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
472 }
473
TEST(ziparchive,ExtractToFile)474 TEST(ziparchive, ExtractToFile) {
475 TemporaryFile tmp_file;
476 ASSERT_NE(-1, tmp_file.fd);
477 const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
478 const size_t data_size = sizeof(data);
479
480 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
481
482 ZipArchiveHandle handle;
483 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
484
485 ZipEntry entry;
486 ZipString name;
487 SetZipString(&name, kATxtName);
488 ASSERT_EQ(0, FindEntry(handle, name, &entry));
489 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
490
491
492 // Assert that the first 8 bytes of the file haven't been clobbered.
493 uint8_t read_buffer[data_size];
494 ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
495 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
496 ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
497
498 // Assert that the remainder of the file contains the incompressed data.
499 std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
500 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
501 entry.uncompressed_length));
502 ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(),
503 kATxtContents.size()));
504
505 // Assert that the total length of the file is sane
506 ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
507 lseek64(tmp_file.fd, 0, SEEK_END));
508 }
509
510 #if !defined(_WIN32)
TEST(ziparchive,OpenFromMemory)511 TEST(ziparchive, OpenFromMemory) {
512 const std::string zip_path = test_data_dir + "/" + kUpdateZip;
513 android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
514 ASSERT_NE(-1, fd);
515 struct stat sb;
516 ASSERT_EQ(0, fstat(fd, &sb));
517
518 // Memory map the file first and open the archive from the memory region.
519 android::FileMap file_map;
520 file_map.create(zip_path.c_str(), fd, 0/*offset*/, sb.st_size, true);
521 ZipArchiveHandle handle;
522 ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
523 zip_path.c_str(), &handle));
524
525 // Assert one entry can be found and extracted correctly.
526 std::string BINARY_PATH("META-INF/com/google/android/update-binary");
527 ZipString binary_path(BINARY_PATH.c_str());
528 ZipEntry binary_entry;
529 ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
530 TemporaryFile tmp_binary;
531 ASSERT_NE(-1, tmp_binary.fd);
532 ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
533 }
534 #endif
535
ZipArchiveStreamTest(ZipArchiveHandle & handle,const std::string & entry_name,bool raw,bool verified,ZipEntry * entry,std::vector<uint8_t> * read_data)536 static void ZipArchiveStreamTest(
537 ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
538 bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
539 ZipString name;
540 SetZipString(&name, entry_name);
541 ASSERT_EQ(0, FindEntry(handle, name, entry));
542 std::unique_ptr<ZipArchiveStreamEntry> stream;
543 if (raw) {
544 stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
545 if (entry->method == kCompressStored) {
546 read_data->resize(entry->uncompressed_length);
547 } else {
548 read_data->resize(entry->compressed_length);
549 }
550 } else {
551 stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
552 read_data->resize(entry->uncompressed_length);
553 }
554 uint8_t* read_data_ptr = read_data->data();
555 ASSERT_TRUE(stream.get() != nullptr);
556 const std::vector<uint8_t>* data;
557 uint64_t total_size = 0;
558 while ((data = stream->Read()) != nullptr) {
559 total_size += data->size();
560 memcpy(read_data_ptr, data->data(), data->size());
561 read_data_ptr += data->size();
562 }
563 ASSERT_EQ(verified, stream->Verify());
564 ASSERT_EQ(total_size, read_data->size());
565 }
566
ZipArchiveStreamTestUsingContents(const std::string & zip_file,const std::string & entry_name,const std::vector<uint8_t> & contents,bool raw)567 static void ZipArchiveStreamTestUsingContents(
568 const std::string& zip_file, const std::string& entry_name,
569 const std::vector<uint8_t>& contents, bool raw) {
570 ZipArchiveHandle handle;
571 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
572
573 ZipEntry entry;
574 std::vector<uint8_t> read_data;
575 ZipArchiveStreamTest(handle, entry_name, raw, true, &entry, &read_data);
576
577 ASSERT_EQ(contents.size(), read_data.size());
578 ASSERT_TRUE(memcmp(read_data.data(), contents.data(), read_data.size()) == 0);
579
580 CloseArchive(handle);
581 }
582
ZipArchiveStreamTestUsingMemory(const std::string & zip_file,const std::string & entry_name)583 static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file, const std::string& entry_name) {
584 ZipArchiveHandle handle;
585 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
586
587 ZipEntry entry;
588 std::vector<uint8_t> read_data;
589 ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
590
591 std::vector<uint8_t> cmp_data(entry.uncompressed_length);
592 ASSERT_EQ(entry.uncompressed_length, read_data.size());
593 ASSERT_EQ(0, ExtractToMemory(handle, &entry, cmp_data.data(), cmp_data.size()));
594 ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
595
596 CloseArchive(handle);
597 }
598
TEST(ziparchive,StreamCompressed)599 TEST(ziparchive, StreamCompressed) {
600 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
601 }
602
TEST(ziparchive,StreamUncompressed)603 TEST(ziparchive, StreamUncompressed) {
604 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
605 }
606
TEST(ziparchive,StreamRawCompressed)607 TEST(ziparchive, StreamRawCompressed) {
608 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
609 }
610
TEST(ziparchive,StreamRawUncompressed)611 TEST(ziparchive, StreamRawUncompressed) {
612 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
613 }
614
TEST(ziparchive,StreamLargeCompressed)615 TEST(ziparchive, StreamLargeCompressed) {
616 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
617 }
618
TEST(ziparchive,StreamLargeUncompressed)619 TEST(ziparchive, StreamLargeUncompressed) {
620 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
621 }
622
TEST(ziparchive,StreamCompressedBadCrc)623 TEST(ziparchive, StreamCompressedBadCrc) {
624 ZipArchiveHandle handle;
625 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
626
627 ZipEntry entry;
628 std::vector<uint8_t> read_data;
629 ZipArchiveStreamTest(handle, kATxtName, false, false, &entry, &read_data);
630
631 CloseArchive(handle);
632 }
633
TEST(ziparchive,StreamUncompressedBadCrc)634 TEST(ziparchive, StreamUncompressedBadCrc) {
635 ZipArchiveHandle handle;
636 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
637
638 ZipEntry entry;
639 std::vector<uint8_t> read_data;
640 ZipArchiveStreamTest(handle, kBTxtName, false, false, &entry, &read_data);
641
642 CloseArchive(handle);
643 }
644
main(int argc,char ** argv)645 int main(int argc, char** argv) {
646 ::testing::InitGoogleTest(&argc, argv);
647
648 static struct option options[] = {
649 { "test_data_dir", required_argument, nullptr, 't' },
650 { nullptr, 0, nullptr, 0 }
651 };
652
653 while (true) {
654 int option_index;
655 const int c = getopt_long_only(argc, argv, "", options, &option_index);
656 if (c == -1) {
657 break;
658 }
659
660 if (c == 't') {
661 test_data_dir = optarg;
662 }
663 }
664
665 if (test_data_dir.size() == 0) {
666 printf("Test data flag (--test_data_dir) required\n\n");
667 return -1;
668 }
669
670 if (test_data_dir[0] != '/') {
671 std::vector<char> cwd_buffer(1024);
672 const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
673 if (cwd == nullptr) {
674 printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
675 test_data_dir.c_str());
676 return -2;
677 }
678 test_data_dir = '/' + test_data_dir;
679 test_data_dir = cwd + test_data_dir;
680 }
681
682 return RUN_ALL_TESTS();
683 }
684