blob: ff73eb29bf3e551f1eb1edd3cb0d523b0b8f222c [file] [log] [blame]
Narayan Kamath7462f022013-11-21 13:05:04 +00001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Narayan Kamath1ef9d2d2017-06-15 13:58:25 +010017#include "zip_archive_private.h"
18
Narayan Kamath00a258c2013-12-13 16:06:19 +000019#include <errno.h>
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -070020#include <fcntl.h>
Narayan Kamath00a258c2013-12-13 16:06:19 +000021#include <getopt.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000022#include <stdio.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080023#include <string.h>
Narayan Kamath00a258c2013-12-13 16:06:19 +000024#include <unistd.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080025
Yabin Cui8e6f7222016-02-08 16:26:33 -080026#include <memory>
Narayan Kamath00a258c2013-12-13 16:06:19 +000027#include <vector>
28
Elliott Hughes4f713192015-12-04 22:00:26 -080029#include <android-base/file.h>
Yabin Cui8e6f7222016-02-08 16:26:33 -080030#include <android-base/test_utils.h>
Tianjie Xu18c25922016-09-29 15:27:41 -070031#include <android-base/unique_fd.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000032#include <gtest/gtest.h>
Tianjie Xu18c25922016-09-29 15:27:41 -070033#include <utils/FileMap.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080034#include <ziparchive/zip_archive.h>
35#include <ziparchive/zip_archive_stream_entry.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000036
Narayan Kamath58aaf462013-12-10 16:47:14 +000037static std::string test_data_dir;
Narayan Kamath7462f022013-11-21 13:05:04 +000038
Neil Fullerb1a113f2014-07-25 14:43:04 +010039static const std::string kMissingZip = "missing.zip";
Narayan Kamath58aaf462013-12-10 16:47:14 +000040static const std::string kValidZip = "valid.zip";
Christopher Ferrise6884ce2015-11-10 14:55:12 -080041static const std::string kLargeZip = "large.zip";
42static const std::string kBadCrcZip = "bad_crc.zip";
Tianjie Xufba1a362016-09-21 14:58:11 -070043static const std::string kCrashApk = "crash.apk";
Tianjie Xu9e020e22016-10-10 12:11:30 -070044static const std::string kBadFilenameZip = "bad_filename.zip";
Tianjie Xu18c25922016-09-29 15:27:41 -070045static const std::string kUpdateZip = "dummy-update.zip";
Narayan Kamath58aaf462013-12-10 16:47:14 +000046
Jiyong Parkcd997e62017-06-30 17:23:33 +090047static const std::vector<uint8_t> kATxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a',
48 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
Narayan Kamath58aaf462013-12-10 16:47:14 +000049
Jiyong Parkcd997e62017-06-30 17:23:33 +090050static const std::vector<uint8_t> kATxtContentsCompressed{'K', 'L', 'J', 'N', 'I', 'M', 'K',
51 207, 'H', 132, 210, '\\', '\0'};
Christopher Ferrise6884ce2015-11-10 14:55:12 -080052
Jiyong Parkcd997e62017-06-30 17:23:33 +090053static const std::vector<uint8_t> kBTxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
Narayan Kamath58aaf462013-12-10 16:47:14 +000054
Christopher Ferrise6884ce2015-11-10 14:55:12 -080055static const std::string kATxtName("a.txt");
56static const std::string kBTxtName("b.txt");
57static const std::string kNonexistentTxtName("nonexistent.txt");
58static const std::string kEmptyTxtName("empty.txt");
59static const std::string kLargeCompressTxtName("compress.txt");
60static const std::string kLargeUncompressTxtName("uncompress.txt");
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +010061
Jiyong Parkcd997e62017-06-30 17:23:33 +090062static int32_t OpenArchiveWrapper(const std::string& name, ZipArchiveHandle* handle) {
Narayan Kamath58aaf462013-12-10 16:47:14 +000063 const std::string abs_path = test_data_dir + "/" + name;
64 return OpenArchive(abs_path.c_str(), handle);
65}
66
Christopher Ferrise6884ce2015-11-10 14:55:12 -080067static void SetZipString(ZipString* zip_str, const std::string& str) {
68 zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
69 zip_str->name_length = str.size();
70}
71
Narayan Kamath58aaf462013-12-10 16:47:14 +000072TEST(ziparchive, Open) {
73 ZipArchiveHandle handle;
74 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
Tianjie Xu9e020e22016-10-10 12:11:30 -070075 CloseArchive(handle);
Narayan Kamath58aaf462013-12-10 16:47:14 +000076
Tianjie Xu9e020e22016-10-10 12:11:30 -070077 ASSERT_EQ(-1, OpenArchiveWrapper(kBadFilenameZip, &handle));
Narayan Kamath58aaf462013-12-10 16:47:14 +000078 CloseArchive(handle);
79}
80
Tianjie Xufba1a362016-09-21 14:58:11 -070081TEST(ziparchive, OutOfBound) {
82 ZipArchiveHandle handle;
83 ASSERT_EQ(-8, OpenArchiveWrapper(kCrashApk, &handle));
84 CloseArchive(handle);
85}
86
Neil Fullerb1a113f2014-07-25 14:43:04 +010087TEST(ziparchive, OpenMissing) {
88 ZipArchiveHandle handle;
89 ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
90
91 // Confirm the file descriptor is not going to be mistaken for a valid one.
92 ASSERT_EQ(-1, GetFileDescriptor(handle));
93}
94
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -070095TEST(ziparchive, OpenAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -080096 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -070097 ASSERT_NE(-1, fd);
98 ZipArchiveHandle handle;
99 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
100 CloseArchive(handle);
101 ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
102 ASSERT_EQ(EBADF, errno);
103}
104
105TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800106 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700107 ASSERT_NE(-1, fd);
108 ZipArchiveHandle handle;
109 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
110 CloseArchive(handle);
111 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
112 close(fd);
113}
114
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000115static void AssertIterationOrder(const ZipString* prefix, const ZipString* suffix,
116 const std::vector<std::string>& expected_names_sorted) {
Narayan Kamath58aaf462013-12-10 16:47:14 +0000117 ZipArchiveHandle handle;
118 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
119
120 void* iteration_cookie;
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000121 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, prefix, suffix));
Narayan Kamath7462f022013-11-21 13:05:04 +0000122
123 ZipEntry data;
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000124 std::vector<std::string> names;
125
Yusuke Sato07447542015-06-25 14:39:19 -0700126 ZipString name;
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000127 for (size_t i = 0; i < expected_names_sorted.size(); ++i) {
128 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
129 names.push_back(std::string(reinterpret_cast<const char*>(name.name), name.name_length));
130 }
Narayan Kamath58aaf462013-12-10 16:47:14 +0000131
132 // End of iteration.
133 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000134 CloseArchive(handle);
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000135
136 // Assert that the names are as expected.
137 std::sort(names.begin(), names.end());
138 ASSERT_EQ(expected_names_sorted, names);
139}
140
141TEST(ziparchive, Iteration) {
142 static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/", "b/c.txt",
143 "b/d.txt"};
144
145 AssertIterationOrder(nullptr, nullptr, kExpectedMatchesSorted);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000146}
147
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700148TEST(ziparchive, IterationWithPrefix) {
Yusuke Sato07447542015-06-25 14:39:19 -0700149 ZipString prefix("b/");
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000150 static const std::vector<std::string> kExpectedMatchesSorted = {"b/", "b/c.txt", "b/d.txt"};
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700151
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000152 AssertIterationOrder(&prefix, nullptr, kExpectedMatchesSorted);
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700153}
154
155TEST(ziparchive, IterationWithSuffix) {
Yusuke Sato07447542015-06-25 14:39:19 -0700156 ZipString suffix(".txt");
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000157 static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/c.txt",
158 "b/d.txt"};
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700159
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000160 AssertIterationOrder(nullptr, &suffix, kExpectedMatchesSorted);
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700161}
162
163TEST(ziparchive, IterationWithPrefixAndSuffix) {
Yusuke Sato07447542015-06-25 14:39:19 -0700164 ZipString prefix("b");
165 ZipString suffix(".txt");
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000166 static const std::vector<std::string> kExpectedMatchesSorted = {"b.txt", "b/c.txt", "b/d.txt"};
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700167
Narayan Kamathf37bb8e2017-12-21 12:54:52 +0000168 AssertIterationOrder(&prefix, &suffix, kExpectedMatchesSorted);
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700169}
170
171TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
172 ZipArchiveHandle handle;
173 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
174
175 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700176 ZipString prefix("x");
177 ZipString suffix("y");
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700178 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
179
180 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700181 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700182
183 // End of iteration.
184 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
185
186 CloseArchive(handle);
187}
188
Narayan Kamath58aaf462013-12-10 16:47:14 +0000189TEST(ziparchive, FindEntry) {
190 ZipArchiveHandle handle;
191 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
192
193 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700194 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800195 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100196 ASSERT_EQ(0, FindEntry(handle, name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000197
198 // Known facts about a.txt, from zipinfo -v.
199 ASSERT_EQ(63, data.offset);
200 ASSERT_EQ(kCompressDeflated, data.method);
201 ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
202 ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
203 ASSERT_EQ(0x950821c5, data.crc32);
beonit0e99a2f2015-07-18 02:08:16 +0900204 ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000205
206 // An entry that doesn't exist. Should be a negative return code.
Yusuke Sato07447542015-06-25 14:39:19 -0700207 ZipString absent_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800208 SetZipString(&absent_name, kNonexistentTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100209 ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000210
211 CloseArchive(handle);
212}
213
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200214TEST(ziparchive, TestInvalidDeclaredLength) {
215 ZipArchiveHandle handle;
216 ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
217
218 void* iteration_cookie;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800219 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200220
Yusuke Sato07447542015-06-25 14:39:19 -0700221 ZipString name;
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200222 ZipEntry data;
223
224 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
225 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
226
227 CloseArchive(handle);
228}
229
Narayan Kamath58aaf462013-12-10 16:47:14 +0000230TEST(ziparchive, ExtractToMemory) {
231 ZipArchiveHandle handle;
232 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
233
234 // An entry that's deflated.
235 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700236 ZipString a_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800237 SetZipString(&a_name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100238 ASSERT_EQ(0, FindEntry(handle, a_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000239 const uint32_t a_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800240 ASSERT_EQ(a_size, kATxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000241 uint8_t* buffer = new uint8_t[a_size];
242 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800243 ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000244 delete[] buffer;
245
246 // An entry that's stored.
Yusuke Sato07447542015-06-25 14:39:19 -0700247 ZipString b_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800248 SetZipString(&b_name, kBTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100249 ASSERT_EQ(0, FindEntry(handle, b_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000250 const uint32_t b_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800251 ASSERT_EQ(b_size, kBTxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000252 buffer = new uint8_t[b_size];
253 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800254 ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000255 delete[] buffer;
256
257 CloseArchive(handle);
258}
259
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100260static const uint32_t kEmptyEntriesZip[] = {
Jiyong Parkcd997e62017-06-30 17:23:33 +0900261 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000, 0x00090000,
262 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13, 0x52e25c24, 0x000b7875,
263 0x42890401, 0x88040000, 0x50000013, 0x1e02014b, 0x00000a03, 0x60000000, 0x00443863,
264 0x00000000, 0x00000000, 0x09000000, 0x00001800, 0x00000000, 0xa0000000, 0x00000081,
265 0x706d6500, 0x742e7974, 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904,
266 0x13880400, 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000};
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100267
Narayan Kamathf899bd52015-04-17 11:53:14 +0100268// This is a zip file containing a single entry (ab.txt) that contains
269// 90072 repetitions of the string "ab\n" and has an uncompressed length
270// of 270216 bytes.
271static const uint16_t kAbZip[] = {
Jiyong Parkcd997e62017-06-30 17:23:33 +0900272 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0, 0x2cda, 0x011b, 0x0000, 0x1f88,
273 0x0004, 0x0006, 0x001c, 0x6261, 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
274 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000, 0xc2ed, 0x0d31, 0x0000, 0x030c,
275 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa, 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
276 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
277 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
278 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
279 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
280 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
281 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
282 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
283 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
284 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
285 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
286 0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02, 0x1403, 0x0000, 0x0800, 0xd200,
287 0x9851, 0xb046, 0xdac4, 0x1b2c, 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
288 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574, 0x0554, 0x0300, 0x097c, 0x553a,
289 0x7875, 0x000b, 0x0401, 0x4289, 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
290 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000};
Narayan Kamathf899bd52015-04-17 11:53:14 +0100291
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800292static const std::string kAbTxtName("ab.txt");
Narayan Kamathf899bd52015-04-17 11:53:14 +0100293static const size_t kAbUncompressedSize = 270216;
294
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100295TEST(ziparchive, EmptyEntries) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800296 TemporaryFile tmp_file;
297 ASSERT_NE(-1, tmp_file.fd);
298 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
Narayan Kamath48953a12014-01-24 12:32:39 +0000299
300 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800301 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath48953a12014-01-24 12:32:39 +0000302
303 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700304 ZipString empty_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800305 SetZipString(&empty_name, kEmptyTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100306 ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
Narayan Kamath48953a12014-01-24 12:32:39 +0000307 ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
308 uint8_t buffer[1];
309 ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
310
Yabin Cui8e6f7222016-02-08 16:26:33 -0800311 TemporaryFile tmp_output_file;
312 ASSERT_NE(-1, tmp_output_file.fd);
313 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamath48953a12014-01-24 12:32:39 +0000314
315 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800316 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamath48953a12014-01-24 12:32:39 +0000317 ASSERT_EQ(0, stat_buf.st_size);
Narayan Kamath48953a12014-01-24 12:32:39 +0000318}
319
Narayan Kamathf899bd52015-04-17 11:53:14 +0100320TEST(ziparchive, EntryLargerThan32K) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800321 TemporaryFile tmp_file;
322 ASSERT_NE(-1, tmp_file.fd);
323 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
Jiyong Parkcd997e62017-06-30 17:23:33 +0900324 sizeof(kAbZip) - 1));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100325 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800326 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100327
328 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700329 ZipString ab_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800330 SetZipString(&ab_name, kAbTxtName);
Narayan Kamathf899bd52015-04-17 11:53:14 +0100331 ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
332 ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
333
334 // Extract the entry to memory.
335 std::vector<uint8_t> buffer(kAbUncompressedSize);
336 ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
337
338 // Extract the entry to a file.
Yabin Cui8e6f7222016-02-08 16:26:33 -0800339 TemporaryFile tmp_output_file;
340 ASSERT_NE(-1, tmp_output_file.fd);
341 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100342
343 // Make sure the extracted file size is as expected.
344 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800345 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100346 ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
347
348 // Read the file back to a buffer and make sure the contents are
349 // the same as the memory buffer we extracted directly to.
350 std::vector<uint8_t> file_contents(kAbUncompressedSize);
Yabin Cui8e6f7222016-02-08 16:26:33 -0800351 ASSERT_EQ(0, lseek64(tmp_output_file.fd, 0, SEEK_SET));
Jiyong Parkcd997e62017-06-30 17:23:33 +0900352 ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0], file_contents.size()));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100353 ASSERT_EQ(file_contents, buffer);
354
355 for (int i = 0; i < 90072; ++i) {
356 const uint8_t* line = &file_contents[0] + (3 * i);
357 ASSERT_EQ('a', line[0]);
358 ASSERT_EQ('b', line[1]);
359 ASSERT_EQ('\n', line[2]);
360 }
Narayan Kamathf899bd52015-04-17 11:53:14 +0100361}
362
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100363TEST(ziparchive, TrailerAfterEOCD) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800364 TemporaryFile tmp_file;
365 ASSERT_NE(-1, tmp_file.fd);
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100366
367 // Create a file with 8 bytes of random garbage.
Jiyong Parkcd997e62017-06-30 17:23:33 +0900368 static const uint8_t trailer[] = {'A', 'n', 'd', 'r', 'o', 'i', 'd', 'z'};
Yabin Cui8e6f7222016-02-08 16:26:33 -0800369 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
370 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100371
372 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800373 ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100374}
375
Narayan Kamath00a258c2013-12-13 16:06:19 +0000376TEST(ziparchive, ExtractToFile) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800377 TemporaryFile tmp_file;
378 ASSERT_NE(-1, tmp_file.fd);
Jiyong Parkcd997e62017-06-30 17:23:33 +0900379 const uint8_t data[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
Yabin Cui8e6f7222016-02-08 16:26:33 -0800380 const size_t data_size = sizeof(data);
Narayan Kamath00a258c2013-12-13 16:06:19 +0000381
Yabin Cui8e6f7222016-02-08 16:26:33 -0800382 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000383
384 ZipArchiveHandle handle;
385 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
386
387 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700388 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800389 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100390 ASSERT_EQ(0, FindEntry(handle, name, &entry));
Yabin Cui8e6f7222016-02-08 16:26:33 -0800391 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000392
Narayan Kamath00a258c2013-12-13 16:06:19 +0000393 // Assert that the first 8 bytes of the file haven't been clobbered.
394 uint8_t read_buffer[data_size];
Yabin Cui8e6f7222016-02-08 16:26:33 -0800395 ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
396 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000397 ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
398
399 // Assert that the remainder of the file contains the incompressed data.
400 std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
Jiyong Parkcd997e62017-06-30 17:23:33 +0900401 ASSERT_TRUE(
402 android::base::ReadFully(tmp_file.fd, uncompressed_data.data(), entry.uncompressed_length));
403 ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(), kATxtContents.size()));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000404
405 // Assert that the total length of the file is sane
Yabin Cui8e6f7222016-02-08 16:26:33 -0800406 ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
407 lseek64(tmp_file.fd, 0, SEEK_END));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000408}
409
Tianjie Xu18c25922016-09-29 15:27:41 -0700410#if !defined(_WIN32)
411TEST(ziparchive, OpenFromMemory) {
412 const std::string zip_path = test_data_dir + "/" + kUpdateZip;
413 android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
414 ASSERT_NE(-1, fd);
415 struct stat sb;
416 ASSERT_EQ(0, fstat(fd, &sb));
417
418 // Memory map the file first and open the archive from the memory region.
419 android::FileMap file_map;
Jiyong Parkcd997e62017-06-30 17:23:33 +0900420 file_map.create(zip_path.c_str(), fd, 0 /*offset*/, sb.st_size, true);
Tianjie Xu18c25922016-09-29 15:27:41 -0700421 ZipArchiveHandle handle;
422 ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
423 zip_path.c_str(), &handle));
424
425 // Assert one entry can be found and extracted correctly.
426 std::string BINARY_PATH("META-INF/com/google/android/update-binary");
427 ZipString binary_path(BINARY_PATH.c_str());
428 ZipEntry binary_entry;
429 ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
430 TemporaryFile tmp_binary;
431 ASSERT_NE(-1, tmp_binary.fd);
432 ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
433}
434#endif
435
Jiyong Parkcd997e62017-06-30 17:23:33 +0900436static void ZipArchiveStreamTest(ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
437 bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800438 ZipString name;
439 SetZipString(&name, entry_name);
440 ASSERT_EQ(0, FindEntry(handle, name, entry));
441 std::unique_ptr<ZipArchiveStreamEntry> stream;
442 if (raw) {
443 stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
444 if (entry->method == kCompressStored) {
445 read_data->resize(entry->uncompressed_length);
446 } else {
447 read_data->resize(entry->compressed_length);
448 }
449 } else {
450 stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
451 read_data->resize(entry->uncompressed_length);
452 }
453 uint8_t* read_data_ptr = read_data->data();
454 ASSERT_TRUE(stream.get() != nullptr);
455 const std::vector<uint8_t>* data;
456 uint64_t total_size = 0;
457 while ((data = stream->Read()) != nullptr) {
458 total_size += data->size();
459 memcpy(read_data_ptr, data->data(), data->size());
460 read_data_ptr += data->size();
461 }
462 ASSERT_EQ(verified, stream->Verify());
463 ASSERT_EQ(total_size, read_data->size());
464}
465
Jiyong Parkcd997e62017-06-30 17:23:33 +0900466static void ZipArchiveStreamTestUsingContents(const std::string& zip_file,
467 const std::string& entry_name,
468 const std::vector<uint8_t>& contents, bool raw) {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800469 ZipArchiveHandle handle;
470 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
471
472 ZipEntry entry;
473 std::vector<uint8_t> read_data;
474 ZipArchiveStreamTest(handle, entry_name, raw, true, &entry, &read_data);
475
476 ASSERT_EQ(contents.size(), read_data.size());
477 ASSERT_TRUE(memcmp(read_data.data(), contents.data(), read_data.size()) == 0);
478
479 CloseArchive(handle);
480}
481
Jiyong Parkcd997e62017-06-30 17:23:33 +0900482static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file,
483 const std::string& entry_name) {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800484 ZipArchiveHandle handle;
485 ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
486
487 ZipEntry entry;
488 std::vector<uint8_t> read_data;
489 ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
490
491 std::vector<uint8_t> cmp_data(entry.uncompressed_length);
492 ASSERT_EQ(entry.uncompressed_length, read_data.size());
493 ASSERT_EQ(0, ExtractToMemory(handle, &entry, cmp_data.data(), cmp_data.size()));
494 ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
495
496 CloseArchive(handle);
497}
498
499TEST(ziparchive, StreamCompressed) {
500 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
501}
502
503TEST(ziparchive, StreamUncompressed) {
504 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
505}
506
507TEST(ziparchive, StreamRawCompressed) {
508 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
509}
510
511TEST(ziparchive, StreamRawUncompressed) {
512 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
513}
514
515TEST(ziparchive, StreamLargeCompressed) {
516 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
517}
518
519TEST(ziparchive, StreamLargeUncompressed) {
520 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
521}
522
523TEST(ziparchive, StreamCompressedBadCrc) {
524 ZipArchiveHandle handle;
525 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
526
527 ZipEntry entry;
528 std::vector<uint8_t> read_data;
529 ZipArchiveStreamTest(handle, kATxtName, false, false, &entry, &read_data);
530
531 CloseArchive(handle);
532}
533
534TEST(ziparchive, StreamUncompressedBadCrc) {
535 ZipArchiveHandle handle;
536 ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
537
538 ZipEntry entry;
539 std::vector<uint8_t> read_data;
540 ZipArchiveStreamTest(handle, kBTxtName, false, false, &entry, &read_data);
541
542 CloseArchive(handle);
543}
544
Narayan Kamath162b7052017-06-05 13:21:12 +0100545// Generated using the following Java program:
546// public static void main(String[] foo) throws Exception {
547// FileOutputStream fos = new
548// FileOutputStream("/tmp/data_descriptor.zip");
549// ZipOutputStream zos = new ZipOutputStream(fos);
550// ZipEntry ze = new ZipEntry("name");
551// ze.setMethod(ZipEntry.DEFLATED);
552// zos.putNextEntry(ze);
553// zos.write("abdcdefghijk".getBytes());
554// zos.closeEntry();
555// zos.close();
556// }
557//
558// cat /tmp/data_descriptor.zip | xxd -i
559//
560static const std::vector<uint8_t> kDataDescriptorZipFile{
561 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a, 0x00, 0x00,
562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6e, 0x61,
563 0x6d, 0x65, 0x4b, 0x4c, 0x4a, 0x49, 0x4e, 0x49, 0x4d, 0x4b, 0xcf, 0xc8, 0xcc, 0xca, 0x06, 0x00,
564 //[sig---------------], [crc32---------------], [csize---------------], [size----------------]
565 0x50, 0x4b, 0x07, 0x08, 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
566 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a,
567 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61,
569 0x6d, 0x65, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x32, 0x00,
570 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
571
572// The offsets of the data descriptor in this file, so we can mess with
573// them later in the test.
574static constexpr uint32_t kDataDescriptorOffset = 48;
575static constexpr uint32_t kCSizeOffset = kDataDescriptorOffset + 8;
576static constexpr uint32_t kSizeOffset = kCSizeOffset + 4;
577
578static void ExtractEntryToMemory(const std::vector<uint8_t>& zip_data,
579 std::vector<uint8_t>* entry_out, int32_t* error_code_out) {
580 TemporaryFile tmp_file;
581 ASSERT_NE(-1, tmp_file.fd);
582 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &zip_data[0], zip_data.size()));
583 ZipArchiveHandle handle;
584 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "ExtractEntryToMemory", &handle));
585
586 // This function expects a variant of kDataDescriptorZipFile, for look for
587 // an entry whose name is "name" and whose size is 12 (contents =
588 // "abdcdefghijk").
589 ZipEntry entry;
Narayan Kamathc36b8092017-12-22 10:42:09 +0000590 ZipString name;
591 std::string name_str = "name";
592 SetZipString(&name, name_str);
Narayan Kamath162b7052017-06-05 13:21:12 +0100593
Narayan Kamathc36b8092017-12-22 10:42:09 +0000594 ASSERT_EQ(0, FindEntry(handle, name, &entry));
Narayan Kamath162b7052017-06-05 13:21:12 +0100595 ASSERT_EQ(static_cast<uint32_t>(12), entry.uncompressed_length);
596
597 entry_out->resize(12);
598 (*error_code_out) = ExtractToMemory(handle, &entry, &((*entry_out)[0]), 12);
599
600 CloseArchive(handle);
601}
602
603TEST(ziparchive, ValidDataDescriptors) {
604 std::vector<uint8_t> entry;
605 int32_t error_code = 0;
606 ExtractEntryToMemory(kDataDescriptorZipFile, &entry, &error_code);
607
608 ASSERT_EQ(0, error_code);
609 ASSERT_EQ(12u, entry.size());
610 ASSERT_EQ('a', entry[0]);
611 ASSERT_EQ('k', entry[11]);
612}
613
Narayan Kamathc36b8092017-12-22 10:42:09 +0000614TEST(ziparchive, InvalidDataDescriptors_csize) {
Narayan Kamath162b7052017-06-05 13:21:12 +0100615 std::vector<uint8_t> invalid_csize = kDataDescriptorZipFile;
616 invalid_csize[kCSizeOffset] = 0xfe;
617
618 std::vector<uint8_t> entry;
619 int32_t error_code = 0;
620 ExtractEntryToMemory(invalid_csize, &entry, &error_code);
621
Narayan Kamath1ef9d2d2017-06-15 13:58:25 +0100622 ASSERT_EQ(kInconsistentInformation, error_code);
Narayan Kamathc36b8092017-12-22 10:42:09 +0000623}
Narayan Kamath162b7052017-06-05 13:21:12 +0100624
Narayan Kamathc36b8092017-12-22 10:42:09 +0000625TEST(ziparchive, InvalidDataDescriptors_size) {
Narayan Kamath162b7052017-06-05 13:21:12 +0100626 std::vector<uint8_t> invalid_size = kDataDescriptorZipFile;
Narayan Kamathc36b8092017-12-22 10:42:09 +0000627 invalid_size[kSizeOffset] = 0xfe;
Narayan Kamath162b7052017-06-05 13:21:12 +0100628
Narayan Kamathc36b8092017-12-22 10:42:09 +0000629 std::vector<uint8_t> entry;
630 int32_t error_code = 0;
631 ExtractEntryToMemory(invalid_size, &entry, &error_code);
Narayan Kamath162b7052017-06-05 13:21:12 +0100632
Narayan Kamath1ef9d2d2017-06-15 13:58:25 +0100633 ASSERT_EQ(kInconsistentInformation, error_code);
634}
635
636TEST(ziparchive, ErrorCodeString) {
637 ASSERT_STREQ("Success", ErrorCodeString(0));
638
639 // Out of bounds.
640 ASSERT_STREQ("Unknown return code", ErrorCodeString(1));
641 ASSERT_STREQ("Unknown return code", ErrorCodeString(-13));
642
643 ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
Narayan Kamath162b7052017-06-05 13:21:12 +0100644}
645
Narayan Kamathc1a56dc2017-08-09 18:32:09 +0100646// A zip file whose local file header at offset zero is corrupted.
647//
648// ---------------
649// cat foo > a.txt
650// zip a.zip a.txt
651// cat a.zip | xxd -i
652//
653// Manual changes :
654// [2] = 0xff // Corrupt the LFH signature of entry 0.
655// [3] = 0xff // Corrupt the LFH signature of entry 0.
656static const std::vector<uint8_t> kZipFileWithBrokenLfhSignature{
657 //[lfh-sig-----------], [lfh contents---------------------------------
658 0x50, 0x4b, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80,
659 //--------------------------------------------------------------------
660 0x09, 0x4b, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
661 //-------------------------------] [file-name-----------------], [---
662 0x00, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55,
663 // entry-contents------------------------------------------------------
664 0x54, 0x09, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x51, 0x24, 0x8b, 0x59,
665 //--------------------------------------------------------------------
666 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88,
667 //-------------------------------------], [cd-record-sig-------], [---
668 0x13, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x0a, 0x50, 0x4b, 0x01, 0x02, 0x1e,
669 // cd-record-----------------------------------------------------------
670 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, 0x09, 0x4b, 0xa8,
671 //--------------------------------------------------------------------
672 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05,
673 //--------------------------------------------------------------------
674 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0,
675 //-] [lfh-file-header-off-], [file-name-----------------], [extra----
676 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54,
677 //--------------------------------------------------------------------
678 0x05, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x75, 0x78, 0x0b, 0x00, 0x01,
679 //-------------------------------------------------------], [eocd-sig-
680 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88, 0x13, 0x00, 0x00, 0x50, 0x4b,
681 //-------], [---------------------------------------------------------
682 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4b, 0x00,
683 //-------------------------------------------]
684 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00};
685
686TEST(ziparchive, BrokenLfhSignature) {
687 TemporaryFile tmp_file;
688 ASSERT_NE(-1, tmp_file.fd);
689 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &kZipFileWithBrokenLfhSignature[0],
690 kZipFileWithBrokenLfhSignature.size()));
691 ZipArchiveHandle handle;
692 ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle));
693}
694
Narayan Kamath2d1e23f2017-10-30 11:17:28 +0000695class VectorReader : public zip_archive::Reader {
696 public:
697 VectorReader(const std::vector<uint8_t>& input) : Reader(), input_(input) {}
698
699 bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
700 if ((offset + len) < input_.size()) {
701 return false;
702 }
703
704 memcpy(buf, &input_[offset], len);
705 return true;
706 }
707
708 private:
709 const std::vector<uint8_t>& input_;
710};
711
712class VectorWriter : public zip_archive::Writer {
713 public:
714 VectorWriter() : Writer() {}
715
716 bool Append(uint8_t* buf, size_t size) {
717 output_.insert(output_.end(), buf, buf + size);
718 return true;
719 }
720
721 std::vector<uint8_t>& GetOutput() { return output_; }
722
723 private:
724 std::vector<uint8_t> output_;
725};
726
727class BadReader : public zip_archive::Reader {
728 public:
729 BadReader() : Reader() {}
730
731 bool ReadAtOffset(uint8_t*, size_t, uint32_t) const { return false; }
732};
733
734class BadWriter : public zip_archive::Writer {
735 public:
736 BadWriter() : Writer() {}
737
738 bool Append(uint8_t*, size_t) { return false; }
739};
740
741TEST(ziparchive, Inflate) {
742 const uint32_t compressed_length = kATxtContentsCompressed.size();
743 const uint32_t uncompressed_length = kATxtContents.size();
744
745 const VectorReader reader(kATxtContentsCompressed);
746 {
747 VectorWriter writer;
748 uint64_t crc_out = 0;
749
750 int32_t ret =
751 zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, &crc_out);
752 ASSERT_EQ(0, ret);
753 ASSERT_EQ(kATxtContents, writer.GetOutput());
754 ASSERT_EQ(0x950821C5u, crc_out);
755 }
756
757 {
758 VectorWriter writer;
759 int32_t ret =
760 zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
761 ASSERT_EQ(0, ret);
762 ASSERT_EQ(kATxtContents, writer.GetOutput());
763 }
764
765 {
766 BadWriter writer;
767 int32_t ret =
768 zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
769 ASSERT_EQ(kIoError, ret);
770 }
771
772 {
773 BadReader reader;
774 VectorWriter writer;
775 int32_t ret =
776 zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
777 ASSERT_EQ(kIoError, ret);
778 ASSERT_EQ(0u, writer.GetOutput().size());
779 }
780}
781
Narayan Kamath58aaf462013-12-10 16:47:14 +0000782int main(int argc, char** argv) {
783 ::testing::InitGoogleTest(&argc, argv);
784
Jiyong Parkcd997e62017-06-30 17:23:33 +0900785 static struct option options[] = {{"test_data_dir", required_argument, nullptr, 't'},
786 {nullptr, 0, nullptr, 0}};
Narayan Kamath58aaf462013-12-10 16:47:14 +0000787
788 while (true) {
789 int option_index;
790 const int c = getopt_long_only(argc, argv, "", options, &option_index);
791 if (c == -1) {
792 break;
793 }
794
795 if (c == 't') {
796 test_data_dir = optarg;
797 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000798 }
799
Narayan Kamath58aaf462013-12-10 16:47:14 +0000800 if (test_data_dir.size() == 0) {
801 printf("Test data flag (--test_data_dir) required\n\n");
802 return -1;
803 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000804
Narayan Kamath58aaf462013-12-10 16:47:14 +0000805 if (test_data_dir[0] != '/') {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800806 std::vector<char> cwd_buffer(1024);
807 const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
808 if (cwd == nullptr) {
809 printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
810 test_data_dir.c_str());
811 return -2;
812 }
813 test_data_dir = '/' + test_data_dir;
814 test_data_dir = cwd + test_data_dir;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000815 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000816
Narayan Kamath58aaf462013-12-10 16:47:14 +0000817 return RUN_ALL_TESTS();
Narayan Kamath7462f022013-11-21 13:05:04 +0000818}