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