• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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