Home | History | Annotate | Download | only in libziparchive
      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 "zip_archive_private.h"
     18 
     19 #include <errno.h>
     20 #include <fcntl.h>
     21 #include <getopt.h>
     22 #include <stdio.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 
     26 #include <memory>
     27 #include <vector>
     28 
     29 #include <android-base/file.h>
     30 #include <android-base/test_utils.h>
     31 #include <android-base/unique_fd.h>
     32 #include <gtest/gtest.h>
     33 #include <utils/FileMap.h>
     34 #include <ziparchive/zip_archive.h>
     35 #include <ziparchive/zip_archive_stream_entry.h>
     36 
     37 static std::string test_data_dir;
     38 
     39 static const std::string kMissingZip = "missing.zip";
     40 static const std::string kValidZip = "valid.zip";
     41 static const std::string kLargeZip = "large.zip";
     42 static const std::string kBadCrcZip = "bad_crc.zip";
     43 static const std::string kCrashApk = "crash.apk";
     44 static const std::string kBadFilenameZip = "bad_filename.zip";
     45 static const std::string kUpdateZip = "dummy-update.zip";
     46 
     47 static const std::vector<uint8_t> kATxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a',
     48                                                 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
     49 
     50 static const std::vector<uint8_t> kATxtContentsCompressed{'K', 'L', 'J', 'N', 'I',  'M', 'K',
     51                                                           207, 'H', 132, 210, '\\', '\0'};
     52 
     53 static const std::vector<uint8_t> kBTxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
     54 
     55 static const std::string kATxtName("a.txt");
     56 static const std::string kBTxtName("b.txt");
     57 static const std::string kNonexistentTxtName("nonexistent.txt");
     58 static const std::string kEmptyTxtName("empty.txt");
     59 static const std::string kLargeCompressTxtName("compress.txt");
     60 static const std::string kLargeUncompressTxtName("uncompress.txt");
     61 
     62 static int32_t OpenArchiveWrapper(const std::string& name, ZipArchiveHandle* handle) {
     63   const std::string abs_path = test_data_dir + "/" + name;
     64   return OpenArchive(abs_path.c_str(), handle);
     65 }
     66 
     67 static void AssertNameEquals(const std::string& name_str, const ZipString& name) {
     68   ASSERT_EQ(name_str.size(), name.name_length);
     69   ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
     70 }
     71 
     72 static void SetZipString(ZipString* zip_str, const std::string& str) {
     73   zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
     74   zip_str->name_length = str.size();
     75 }
     76 
     77 TEST(ziparchive, Open) {
     78   ZipArchiveHandle handle;
     79   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
     80   CloseArchive(handle);
     81 
     82   ASSERT_EQ(-1, OpenArchiveWrapper(kBadFilenameZip, &handle));
     83   CloseArchive(handle);
     84 }
     85 
     86 TEST(ziparchive, OutOfBound) {
     87   ZipArchiveHandle handle;
     88   ASSERT_EQ(-8, OpenArchiveWrapper(kCrashApk, &handle));
     89   CloseArchive(handle);
     90 }
     91 
     92 TEST(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 
    100 TEST(ziparchive, OpenAssumeFdOwnership) {
    101   int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
    102   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 
    110 TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
    111   int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
    112   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 
    120 TEST(ziparchive, Iteration) {
    121   ZipArchiveHandle handle;
    122   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    123 
    124   void* iteration_cookie;
    125   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
    126 
    127   ZipEntry data;
    128   ZipString name;
    129 
    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 
    156 TEST(ziparchive, IterationWithPrefix) {
    157   ZipArchiveHandle handle;
    158   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    159 
    160   void* iteration_cookie;
    161   ZipString prefix("b/");
    162   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, nullptr));
    163 
    164   ZipEntry data;
    165   ZipString name;
    166 
    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 
    185 TEST(ziparchive, IterationWithSuffix) {
    186   ZipArchiveHandle handle;
    187   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    188 
    189   void* iteration_cookie;
    190   ZipString suffix(".txt");
    191   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, &suffix));
    192 
    193   ZipEntry data;
    194   ZipString name;
    195 
    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 
    218 TEST(ziparchive, IterationWithPrefixAndSuffix) {
    219   ZipArchiveHandle handle;
    220   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    221 
    222   void* iteration_cookie;
    223   ZipString prefix("b");
    224   ZipString suffix(".txt");
    225   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
    226 
    227   ZipEntry data;
    228   ZipString name;
    229 
    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 
    248 TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
    249   ZipArchiveHandle handle;
    250   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    251 
    252   void* iteration_cookie;
    253   ZipString prefix("x");
    254   ZipString suffix("y");
    255   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
    256 
    257   ZipEntry data;
    258   ZipString name;
    259 
    260   // End of iteration.
    261   ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
    262 
    263   CloseArchive(handle);
    264 }
    265 
    266 TEST(ziparchive, FindEntry) {
    267   ZipArchiveHandle handle;
    268   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    269 
    270   ZipEntry data;
    271   ZipString name;
    272   SetZipString(&name, kATxtName);
    273   ASSERT_EQ(0, FindEntry(handle, name, &data));
    274 
    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);
    281   ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
    282 
    283   // An entry that doesn't exist. Should be a negative return code.
    284   ZipString absent_name;
    285   SetZipString(&absent_name, kNonexistentTxtName);
    286   ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
    287 
    288   CloseArchive(handle);
    289 }
    290 
    291 TEST(ziparchive, TestInvalidDeclaredLength) {
    292   ZipArchiveHandle handle;
    293   ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
    294 
    295   void* iteration_cookie;
    296   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
    297 
    298   ZipString name;
    299   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 
    307 TEST(ziparchive, ExtractToMemory) {
    308   ZipArchiveHandle handle;
    309   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    310 
    311   // An entry that's deflated.
    312   ZipEntry data;
    313   ZipString a_name;
    314   SetZipString(&a_name, kATxtName);
    315   ASSERT_EQ(0, FindEntry(handle, a_name, &data));
    316   const uint32_t a_size = data.uncompressed_length;
    317   ASSERT_EQ(a_size, kATxtContents.size());
    318   uint8_t* buffer = new uint8_t[a_size];
    319   ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
    320   ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
    321   delete[] buffer;
    322 
    323   // An entry that's stored.
    324   ZipString b_name;
    325   SetZipString(&b_name, kBTxtName);
    326   ASSERT_EQ(0, FindEntry(handle, b_name, &data));
    327   const uint32_t b_size = data.uncompressed_length;
    328   ASSERT_EQ(b_size, kBTxtContents.size());
    329   buffer = new uint8_t[b_size];
    330   ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
    331   ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
    332   delete[] buffer;
    333 
    334   CloseArchive(handle);
    335 }
    336 
    337 static const uint32_t kEmptyEntriesZip[] = {
    338     0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000, 0x00090000,
    339     0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13, 0x52e25c24, 0x000b7875,
    340     0x42890401, 0x88040000, 0x50000013, 0x1e02014b, 0x00000a03, 0x60000000, 0x00443863,
    341     0x00000000, 0x00000000, 0x09000000, 0x00001800, 0x00000000, 0xa0000000, 0x00000081,
    342     0x706d6500, 0x742e7974, 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904,
    343     0x13880400, 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000};
    344 
    345 // This is a zip file containing a single entry (ab.txt) that contains
    346 // 90072 repetitions of the string "ab\n" and has an uncompressed length
    347 // of 270216 bytes.
    348 static const uint16_t kAbZip[] = {
    349     0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0, 0x2cda, 0x011b, 0x0000, 0x1f88,
    350     0x0004, 0x0006, 0x001c, 0x6261, 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
    351     0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000, 0xc2ed, 0x0d31, 0x0000, 0x030c,
    352     0x7fa0, 0x3b2e, 0x22ff, 0xa2aa, 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    353     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    354     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    355     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    356     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    357     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    358     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    359     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    360     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    361     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    362     0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    363     0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02, 0x1403, 0x0000, 0x0800, 0xd200,
    364     0x9851, 0xb046, 0xdac4, 0x1b2c, 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
    365     0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574, 0x0554, 0x0300, 0x097c, 0x553a,
    366     0x7875, 0x000b, 0x0401, 0x4289, 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
    367     0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000};
    368 
    369 static const std::string kAbTxtName("ab.txt");
    370 static const size_t kAbUncompressedSize = 270216;
    371 
    372 TEST(ziparchive, EmptyEntries) {
    373   TemporaryFile tmp_file;
    374   ASSERT_NE(-1, tmp_file.fd);
    375   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
    376 
    377   ZipArchiveHandle handle;
    378   ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
    379 
    380   ZipEntry entry;
    381   ZipString empty_name;
    382   SetZipString(&empty_name, kEmptyTxtName);
    383   ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
    384   ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
    385   uint8_t buffer[1];
    386   ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
    387 
    388   TemporaryFile tmp_output_file;
    389   ASSERT_NE(-1, tmp_output_file.fd);
    390   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
    391 
    392   struct stat stat_buf;
    393   ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
    394   ASSERT_EQ(0, stat_buf.st_size);
    395 }
    396 
    397 TEST(ziparchive, EntryLargerThan32K) {
    398   TemporaryFile tmp_file;
    399   ASSERT_NE(-1, tmp_file.fd);
    400   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
    401                                         sizeof(kAbZip) - 1));
    402   ZipArchiveHandle handle;
    403   ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
    404 
    405   ZipEntry entry;
    406   ZipString ab_name;
    407   SetZipString(&ab_name, kAbTxtName);
    408   ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
    409   ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
    410 
    411   // Extract the entry to memory.
    412   std::vector<uint8_t> buffer(kAbUncompressedSize);
    413   ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
    414 
    415   // Extract the entry to a file.
    416   TemporaryFile tmp_output_file;
    417   ASSERT_NE(-1, tmp_output_file.fd);
    418   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
    419 
    420   // Make sure the extracted file size is as expected.
    421   struct stat stat_buf;
    422   ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
    423   ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
    424 
    425   // Read the file back to a buffer and make sure the contents are
    426   // the same as the memory buffer we extracted directly to.
    427   std::vector<uint8_t> file_contents(kAbUncompressedSize);
    428   ASSERT_EQ(0, lseek64(tmp_output_file.fd, 0, SEEK_SET));
    429   ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0], file_contents.size()));
    430   ASSERT_EQ(file_contents, buffer);
    431 
    432   for (int i = 0; i < 90072; ++i) {
    433     const uint8_t* line = &file_contents[0] + (3 * i);
    434     ASSERT_EQ('a', line[0]);
    435     ASSERT_EQ('b', line[1]);
    436     ASSERT_EQ('\n', line[2]);
    437   }
    438 }
    439 
    440 TEST(ziparchive, TrailerAfterEOCD) {
    441   TemporaryFile tmp_file;
    442   ASSERT_NE(-1, tmp_file.fd);
    443 
    444   // Create a file with 8 bytes of random garbage.
    445   static const uint8_t trailer[] = {'A', 'n', 'd', 'r', 'o', 'i', 'd', 'z'};
    446   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
    447   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
    448 
    449   ZipArchiveHandle handle;
    450   ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
    451 }
    452 
    453 TEST(ziparchive, ExtractToFile) {
    454   TemporaryFile tmp_file;
    455   ASSERT_NE(-1, tmp_file.fd);
    456   const uint8_t data[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
    457   const size_t data_size = sizeof(data);
    458 
    459   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
    460 
    461   ZipArchiveHandle handle;
    462   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    463 
    464   ZipEntry entry;
    465   ZipString name;
    466   SetZipString(&name, kATxtName);
    467   ASSERT_EQ(0, FindEntry(handle, name, &entry));
    468   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
    469 
    470   // Assert that the first 8 bytes of the file haven't been clobbered.
    471   uint8_t read_buffer[data_size];
    472   ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
    473   ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
    474   ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
    475 
    476   // Assert that the remainder of the file contains the incompressed data.
    477   std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
    478   ASSERT_TRUE(
    479       android::base::ReadFully(tmp_file.fd, uncompressed_data.data(), entry.uncompressed_length));
    480   ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(), kATxtContents.size()));
    481 
    482   // Assert that the total length of the file is sane
    483   ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
    484             lseek64(tmp_file.fd, 0, SEEK_END));
    485 }
    486 
    487 #if !defined(_WIN32)
    488 TEST(ziparchive, OpenFromMemory) {
    489   const std::string zip_path = test_data_dir + "/" + kUpdateZip;
    490   android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
    491   ASSERT_NE(-1, fd);
    492   struct stat sb;
    493   ASSERT_EQ(0, fstat(fd, &sb));
    494 
    495   // Memory map the file first and open the archive from the memory region.
    496   android::FileMap file_map;
    497   file_map.create(zip_path.c_str(), fd, 0 /*offset*/, sb.st_size, true);
    498   ZipArchiveHandle handle;
    499   ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
    500                                      zip_path.c_str(), &handle));
    501 
    502   // Assert one entry can be found and extracted correctly.
    503   std::string BINARY_PATH("META-INF/com/google/android/update-binary");
    504   ZipString binary_path(BINARY_PATH.c_str());
    505   ZipEntry binary_entry;
    506   ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
    507   TemporaryFile tmp_binary;
    508   ASSERT_NE(-1, tmp_binary.fd);
    509   ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
    510 }
    511 #endif
    512 
    513 static void ZipArchiveStreamTest(ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
    514                                  bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
    515   ZipString name;
    516   SetZipString(&name, entry_name);
    517   ASSERT_EQ(0, FindEntry(handle, name, entry));
    518   std::unique_ptr<ZipArchiveStreamEntry> stream;
    519   if (raw) {
    520     stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
    521     if (entry->method == kCompressStored) {
    522       read_data->resize(entry->uncompressed_length);
    523     } else {
    524       read_data->resize(entry->compressed_length);
    525     }
    526   } else {
    527     stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
    528     read_data->resize(entry->uncompressed_length);
    529   }
    530   uint8_t* read_data_ptr = read_data->data();
    531   ASSERT_TRUE(stream.get() != nullptr);
    532   const std::vector<uint8_t>* data;
    533   uint64_t total_size = 0;
    534   while ((data = stream->Read()) != nullptr) {
    535     total_size += data->size();
    536     memcpy(read_data_ptr, data->data(), data->size());
    537     read_data_ptr += data->size();
    538   }
    539   ASSERT_EQ(verified, stream->Verify());
    540   ASSERT_EQ(total_size, read_data->size());
    541 }
    542 
    543 static void ZipArchiveStreamTestUsingContents(const std::string& zip_file,
    544                                               const std::string& entry_name,
    545                                               const std::vector<uint8_t>& contents, bool raw) {
    546   ZipArchiveHandle handle;
    547   ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
    548 
    549   ZipEntry entry;
    550   std::vector<uint8_t> read_data;
    551   ZipArchiveStreamTest(handle, entry_name, raw, true, &entry, &read_data);
    552 
    553   ASSERT_EQ(contents.size(), read_data.size());
    554   ASSERT_TRUE(memcmp(read_data.data(), contents.data(), read_data.size()) == 0);
    555 
    556   CloseArchive(handle);
    557 }
    558 
    559 static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file,
    560                                             const std::string& entry_name) {
    561   ZipArchiveHandle handle;
    562   ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
    563 
    564   ZipEntry entry;
    565   std::vector<uint8_t> read_data;
    566   ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
    567 
    568   std::vector<uint8_t> cmp_data(entry.uncompressed_length);
    569   ASSERT_EQ(entry.uncompressed_length, read_data.size());
    570   ASSERT_EQ(0, ExtractToMemory(handle, &entry, cmp_data.data(), cmp_data.size()));
    571   ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
    572 
    573   CloseArchive(handle);
    574 }
    575 
    576 TEST(ziparchive, StreamCompressed) {
    577   ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
    578 }
    579 
    580 TEST(ziparchive, StreamUncompressed) {
    581   ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
    582 }
    583 
    584 TEST(ziparchive, StreamRawCompressed) {
    585   ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
    586 }
    587 
    588 TEST(ziparchive, StreamRawUncompressed) {
    589   ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
    590 }
    591 
    592 TEST(ziparchive, StreamLargeCompressed) {
    593   ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
    594 }
    595 
    596 TEST(ziparchive, StreamLargeUncompressed) {
    597   ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
    598 }
    599 
    600 TEST(ziparchive, StreamCompressedBadCrc) {
    601   ZipArchiveHandle handle;
    602   ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
    603 
    604   ZipEntry entry;
    605   std::vector<uint8_t> read_data;
    606   ZipArchiveStreamTest(handle, kATxtName, false, false, &entry, &read_data);
    607 
    608   CloseArchive(handle);
    609 }
    610 
    611 TEST(ziparchive, StreamUncompressedBadCrc) {
    612   ZipArchiveHandle handle;
    613   ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
    614 
    615   ZipEntry entry;
    616   std::vector<uint8_t> read_data;
    617   ZipArchiveStreamTest(handle, kBTxtName, false, false, &entry, &read_data);
    618 
    619   CloseArchive(handle);
    620 }
    621 
    622 // Generated using the following Java program:
    623 //     public static void main(String[] foo) throws Exception {
    624 //       FileOutputStream fos = new
    625 //       FileOutputStream("/tmp/data_descriptor.zip");
    626 //       ZipOutputStream zos = new ZipOutputStream(fos);
    627 //       ZipEntry ze = new ZipEntry("name");
    628 //       ze.setMethod(ZipEntry.DEFLATED);
    629 //       zos.putNextEntry(ze);
    630 //       zos.write("abdcdefghijk".getBytes());
    631 //       zos.closeEntry();
    632 //       zos.close();
    633 //     }
    634 //
    635 // cat /tmp/data_descriptor.zip | xxd -i
    636 //
    637 static const std::vector<uint8_t> kDataDescriptorZipFile{
    638     0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a, 0x00, 0x00,
    639     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6e, 0x61,
    640     0x6d, 0x65, 0x4b, 0x4c, 0x4a, 0x49, 0x4e, 0x49, 0x4d, 0x4b, 0xcf, 0xc8, 0xcc, 0xca, 0x06, 0x00,
    641     //[sig---------------], [crc32---------------], [csize---------------], [size----------------]
    642     0x50, 0x4b, 0x07, 0x08, 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
    643     0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a,
    644     0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
    645     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61,
    646     0x6d, 0x65, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x32, 0x00,
    647     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
    648 
    649 // The offsets of the data descriptor in this file, so we can mess with
    650 // them later in the test.
    651 static constexpr uint32_t kDataDescriptorOffset = 48;
    652 static constexpr uint32_t kCSizeOffset = kDataDescriptorOffset + 8;
    653 static constexpr uint32_t kSizeOffset = kCSizeOffset + 4;
    654 
    655 static void ExtractEntryToMemory(const std::vector<uint8_t>& zip_data,
    656                                  std::vector<uint8_t>* entry_out, int32_t* error_code_out) {
    657   TemporaryFile tmp_file;
    658   ASSERT_NE(-1, tmp_file.fd);
    659   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &zip_data[0], zip_data.size()));
    660   ZipArchiveHandle handle;
    661   ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "ExtractEntryToMemory", &handle));
    662 
    663   // This function expects a variant of kDataDescriptorZipFile, for look for
    664   // an entry whose name is "name" and whose size is 12 (contents =
    665   // "abdcdefghijk").
    666   ZipEntry entry;
    667   ZipString empty_name;
    668   SetZipString(&empty_name, "name");
    669 
    670   ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
    671   ASSERT_EQ(static_cast<uint32_t>(12), entry.uncompressed_length);
    672 
    673   entry_out->resize(12);
    674   (*error_code_out) = ExtractToMemory(handle, &entry, &((*entry_out)[0]), 12);
    675 
    676   CloseArchive(handle);
    677 }
    678 
    679 TEST(ziparchive, ValidDataDescriptors) {
    680   std::vector<uint8_t> entry;
    681   int32_t error_code = 0;
    682   ExtractEntryToMemory(kDataDescriptorZipFile, &entry, &error_code);
    683 
    684   ASSERT_EQ(0, error_code);
    685   ASSERT_EQ(12u, entry.size());
    686   ASSERT_EQ('a', entry[0]);
    687   ASSERT_EQ('k', entry[11]);
    688 }
    689 
    690 TEST(ziparchive, InvalidDataDescriptors) {
    691   std::vector<uint8_t> invalid_csize = kDataDescriptorZipFile;
    692   invalid_csize[kCSizeOffset] = 0xfe;
    693 
    694   std::vector<uint8_t> entry;
    695   int32_t error_code = 0;
    696   ExtractEntryToMemory(invalid_csize, &entry, &error_code);
    697 
    698   ASSERT_EQ(kInconsistentInformation, error_code);
    699 
    700   std::vector<uint8_t> invalid_size = kDataDescriptorZipFile;
    701   invalid_csize[kSizeOffset] = 0xfe;
    702 
    703   error_code = 0;
    704   entry.clear();
    705   ExtractEntryToMemory(invalid_csize, &entry, &error_code);
    706 
    707   ASSERT_EQ(kInconsistentInformation, error_code);
    708 }
    709 
    710 TEST(ziparchive, ErrorCodeString) {
    711   ASSERT_STREQ("Success", ErrorCodeString(0));
    712 
    713   // Out of bounds.
    714   ASSERT_STREQ("Unknown return code", ErrorCodeString(1));
    715   ASSERT_STREQ("Unknown return code", ErrorCodeString(-13));
    716 
    717   ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
    718 }
    719 
    720 // A zip file whose local file header at offset zero is corrupted.
    721 //
    722 // ---------------
    723 // cat foo > a.txt
    724 // zip a.zip a.txt
    725 // cat a.zip | xxd -i
    726 //
    727 // Manual changes :
    728 // [2] = 0xff  // Corrupt the LFH signature of entry 0.
    729 // [3] = 0xff  // Corrupt the LFH signature of entry 0.
    730 static const std::vector<uint8_t> kZipFileWithBrokenLfhSignature{
    731     //[lfh-sig-----------], [lfh contents---------------------------------
    732     0x50, 0x4b, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80,
    733     //--------------------------------------------------------------------
    734     0x09, 0x4b, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
    735     //-------------------------------]  [file-name-----------------], [---
    736     0x00, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55,
    737     // entry-contents------------------------------------------------------
    738     0x54, 0x09, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x51, 0x24, 0x8b, 0x59,
    739     //--------------------------------------------------------------------
    740     0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88,
    741     //-------------------------------------], [cd-record-sig-------], [---
    742     0x13, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x0a, 0x50, 0x4b, 0x01, 0x02, 0x1e,
    743     // cd-record-----------------------------------------------------------
    744     0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, 0x09, 0x4b, 0xa8,
    745     //--------------------------------------------------------------------
    746     0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05,
    747     //--------------------------------------------------------------------
    748     0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0,
    749     //-]  [lfh-file-header-off-], [file-name-----------------], [extra----
    750     0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54,
    751     //--------------------------------------------------------------------
    752     0x05, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x75, 0x78, 0x0b, 0x00, 0x01,
    753     //-------------------------------------------------------], [eocd-sig-
    754     0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88, 0x13, 0x00, 0x00, 0x50, 0x4b,
    755     //-------], [---------------------------------------------------------
    756     0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4b, 0x00,
    757     //-------------------------------------------]
    758     0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00};
    759 
    760 TEST(ziparchive, BrokenLfhSignature) {
    761   TemporaryFile tmp_file;
    762   ASSERT_NE(-1, tmp_file.fd);
    763   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &kZipFileWithBrokenLfhSignature[0],
    764                                         kZipFileWithBrokenLfhSignature.size()));
    765   ZipArchiveHandle handle;
    766   ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle));
    767 }
    768 
    769 int main(int argc, char** argv) {
    770   ::testing::InitGoogleTest(&argc, argv);
    771 
    772   static struct option options[] = {{"test_data_dir", required_argument, nullptr, 't'},
    773                                     {nullptr, 0, nullptr, 0}};
    774 
    775   while (true) {
    776     int option_index;
    777     const int c = getopt_long_only(argc, argv, "", options, &option_index);
    778     if (c == -1) {
    779       break;
    780     }
    781 
    782     if (c == 't') {
    783       test_data_dir = optarg;
    784     }
    785   }
    786 
    787   if (test_data_dir.size() == 0) {
    788     printf("Test data flag (--test_data_dir) required\n\n");
    789     return -1;
    790   }
    791 
    792   if (test_data_dir[0] != '/') {
    793     std::vector<char> cwd_buffer(1024);
    794     const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
    795     if (cwd == nullptr) {
    796       printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
    797              test_data_dir.c_str());
    798       return -2;
    799     }
    800     test_data_dir = '/' + test_data_dir;
    801     test_data_dir = cwd + test_data_dir;
    802   }
    803 
    804   return RUN_ALL_TESTS();
    805 }
    806