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 "ziparchive/zip_archive.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <vector>
25
26 #include <base/file.h>
27 #include <gtest/gtest.h>
28
29 static std::string test_data_dir;
30
31 static const std::string kMissingZip = "missing.zip";
32 static const std::string kValidZip = "valid.zip";
33
34 static const uint8_t kATxtContents[] = {
35 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
36 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
37 '\n'
38 };
39
40 static const uint8_t kBTxtContents[] = {
41 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
42 '\n'
43 };
44
45 static const uint16_t kATxtNameLength = 5;
46 static const uint16_t kBTxtNameLength = 5;
47 static const uint16_t kNonexistentTxtNameLength = 15;
48 static const uint16_t kEmptyTxtNameLength = 9;
49
50 static const uint8_t kATxtName[kATxtNameLength] = {
51 'a', '.', 't', 'x', 't'
52 };
53
54 static const uint8_t kBTxtName[kBTxtNameLength] = {
55 'b', '.', 't', 'x', 't'
56 };
57
58 static const uint8_t kNonexistentTxtName[kNonexistentTxtNameLength] = {
59 'n', 'o', 'n', 'e', 'x', 'i', 's', 't', 'e', 'n', 't', '.', 't', 'x' ,'t'
60 };
61
62 static const uint8_t kEmptyTxtName[kEmptyTxtNameLength] = {
63 'e', 'm', 'p', 't', 'y', '.', 't', 'x', 't'
64 };
65
OpenArchiveWrapper(const std::string & name,ZipArchiveHandle * handle)66 static 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
AssertNameEquals(const std::string & name_str,const ZipEntryName & name)72 static void AssertNameEquals(const std::string& name_str,
73 const ZipEntryName& 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
TEST(ziparchive,Open)78 TEST(ziparchive, Open) {
79 ZipArchiveHandle handle;
80 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
81
82 CloseArchive(handle);
83 }
84
TEST(ziparchive,OpenMissing)85 TEST(ziparchive, OpenMissing) {
86 ZipArchiveHandle handle;
87 ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
88
89 // Confirm the file descriptor is not going to be mistaken for a valid one.
90 ASSERT_EQ(-1, GetFileDescriptor(handle));
91 }
92
TEST(ziparchive,OpenAssumeFdOwnership)93 TEST(ziparchive, OpenAssumeFdOwnership) {
94 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY);
95 ASSERT_NE(-1, fd);
96 ZipArchiveHandle handle;
97 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
98 CloseArchive(handle);
99 ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
100 ASSERT_EQ(EBADF, errno);
101 }
102
TEST(ziparchive,OpenDoNotAssumeFdOwnership)103 TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
104 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY);
105 ASSERT_NE(-1, fd);
106 ZipArchiveHandle handle;
107 ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
108 CloseArchive(handle);
109 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
110 close(fd);
111 }
112
TEST(ziparchive,Iteration)113 TEST(ziparchive, Iteration) {
114 ZipArchiveHandle handle;
115 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
116
117 void* iteration_cookie;
118 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, NULL));
119
120 ZipEntry data;
121 ZipEntryName name;
122
123 // b/c.txt
124 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
125 AssertNameEquals("b/c.txt", name);
126
127 // b/d.txt
128 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
129 AssertNameEquals("b/d.txt", name);
130
131 // a.txt
132 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
133 AssertNameEquals("a.txt", name);
134
135 // b.txt
136 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
137 AssertNameEquals("b.txt", name);
138
139 // b/
140 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
141 AssertNameEquals("b/", name);
142
143 // End of iteration.
144 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
145
146 CloseArchive(handle);
147 }
148
TEST(ziparchive,IterationWithPrefix)149 TEST(ziparchive, IterationWithPrefix) {
150 ZipArchiveHandle handle;
151 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
152
153 void* iteration_cookie;
154 ZipEntryName prefix("b/");
155 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, NULL));
156
157 ZipEntry data;
158 ZipEntryName name;
159
160 // b/c.txt
161 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
162 AssertNameEquals("b/c.txt", name);
163
164 // b/d.txt
165 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
166 AssertNameEquals("b/d.txt", name);
167
168 // b/
169 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
170 AssertNameEquals("b/", name);
171
172 // End of iteration.
173 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
174
175 CloseArchive(handle);
176 }
177
TEST(ziparchive,IterationWithSuffix)178 TEST(ziparchive, IterationWithSuffix) {
179 ZipArchiveHandle handle;
180 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
181
182 void* iteration_cookie;
183 ZipEntryName suffix(".txt");
184 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, &suffix));
185
186 ZipEntry data;
187 ZipEntryName name;
188
189 // b/c.txt
190 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
191 AssertNameEquals("b/c.txt", name);
192
193 // b/d.txt
194 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
195 AssertNameEquals("b/d.txt", name);
196
197 // a.txt
198 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
199 AssertNameEquals("a.txt", name);
200
201 // b.txt
202 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
203 AssertNameEquals("b.txt", name);
204
205 // End of iteration.
206 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
207
208 CloseArchive(handle);
209 }
210
TEST(ziparchive,IterationWithPrefixAndSuffix)211 TEST(ziparchive, IterationWithPrefixAndSuffix) {
212 ZipArchiveHandle handle;
213 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
214
215 void* iteration_cookie;
216 ZipEntryName prefix("b");
217 ZipEntryName suffix(".txt");
218 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
219
220 ZipEntry data;
221 ZipEntryName name;
222
223 // b/c.txt
224 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
225 AssertNameEquals("b/c.txt", name);
226
227 // b/d.txt
228 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
229 AssertNameEquals("b/d.txt", name);
230
231 // b.txt
232 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
233 AssertNameEquals("b.txt", name);
234
235 // End of iteration.
236 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
237
238 CloseArchive(handle);
239 }
240
TEST(ziparchive,IterationWithBadPrefixAndSuffix)241 TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
242 ZipArchiveHandle handle;
243 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
244
245 void* iteration_cookie;
246 ZipEntryName prefix("x");
247 ZipEntryName suffix("y");
248 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
249
250 ZipEntry data;
251 ZipEntryName name;
252
253 // End of iteration.
254 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
255
256 CloseArchive(handle);
257 }
258
TEST(ziparchive,FindEntry)259 TEST(ziparchive, FindEntry) {
260 ZipArchiveHandle handle;
261 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
262
263 ZipEntry data;
264 ZipEntryName name;
265 name.name = kATxtName;
266 name.name_length = kATxtNameLength;
267 ASSERT_EQ(0, FindEntry(handle, name, &data));
268
269 // Known facts about a.txt, from zipinfo -v.
270 ASSERT_EQ(63, data.offset);
271 ASSERT_EQ(kCompressDeflated, data.method);
272 ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
273 ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
274 ASSERT_EQ(0x950821c5, data.crc32);
275
276 // An entry that doesn't exist. Should be a negative return code.
277 ZipEntryName absent_name;
278 absent_name.name = kNonexistentTxtName;
279 absent_name.name_length = kNonexistentTxtNameLength;
280 ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
281
282 CloseArchive(handle);
283 }
284
TEST(ziparchive,TestInvalidDeclaredLength)285 TEST(ziparchive, TestInvalidDeclaredLength) {
286 ZipArchiveHandle handle;
287 ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
288
289 void* iteration_cookie;
290 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL));
291
292 ZipEntryName name;
293 ZipEntry data;
294
295 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
296 ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
297
298 CloseArchive(handle);
299 }
300
TEST(ziparchive,ExtractToMemory)301 TEST(ziparchive, ExtractToMemory) {
302 ZipArchiveHandle handle;
303 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
304
305 // An entry that's deflated.
306 ZipEntry data;
307 ZipEntryName a_name;
308 a_name.name = kATxtName;
309 a_name.name_length = kATxtNameLength;
310 ASSERT_EQ(0, FindEntry(handle, a_name, &data));
311 const uint32_t a_size = data.uncompressed_length;
312 ASSERT_EQ(a_size, sizeof(kATxtContents));
313 uint8_t* buffer = new uint8_t[a_size];
314 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
315 ASSERT_EQ(0, memcmp(buffer, kATxtContents, a_size));
316 delete[] buffer;
317
318 // An entry that's stored.
319 ZipEntryName b_name;
320 b_name.name = kBTxtName;
321 b_name.name_length = kBTxtNameLength;
322 ASSERT_EQ(0, FindEntry(handle, b_name, &data));
323 const uint32_t b_size = data.uncompressed_length;
324 ASSERT_EQ(b_size, sizeof(kBTxtContents));
325 buffer = new uint8_t[b_size];
326 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
327 ASSERT_EQ(0, memcmp(buffer, kBTxtContents, b_size));
328 delete[] buffer;
329
330 CloseArchive(handle);
331 }
332
333 static const uint32_t kEmptyEntriesZip[] = {
334 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
335 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
336 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
337 0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000,
338 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
339 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
340 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
341
342 // This is a zip file containing a single entry (ab.txt) that contains
343 // 90072 repetitions of the string "ab\n" and has an uncompressed length
344 // of 270216 bytes.
345 static const uint16_t kAbZip[] = {
346 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
347 0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
348 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
349 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
350 0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
351 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
352 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
353 0x5555, 0x5555, 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, 0xdd55, 0x502c, 0x014b, 0x1e02,
368 0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
369 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
370 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
371 0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
372 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
373 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
374 };
375
376 static const uint8_t kAbTxtName[] = { 'a', 'b', '.', 't', 'x', 't' };
377 static const uint16_t kAbTxtNameLength = sizeof(kAbTxtName);
378 static const size_t kAbUncompressedSize = 270216;
379
make_temporary_file(const char * file_name_pattern)380 static int make_temporary_file(const char* file_name_pattern) {
381 char full_path[1024];
382 // Account for differences between the host and the target.
383 //
384 // TODO: Maybe reuse bionic/tests/TemporaryFile.h.
385 snprintf(full_path, sizeof(full_path), "/data/local/tmp/%s", file_name_pattern);
386 int fd = mkstemp(full_path);
387 if (fd == -1) {
388 snprintf(full_path, sizeof(full_path), "/tmp/%s", file_name_pattern);
389 fd = mkstemp(full_path);
390 }
391
392 return fd;
393 }
394
TEST(ziparchive,EmptyEntries)395 TEST(ziparchive, EmptyEntries) {
396 char temp_file_pattern[] = "empty_entries_test_XXXXXX";
397 int fd = make_temporary_file(temp_file_pattern);
398 ASSERT_NE(-1, fd);
399 const ssize_t file_size = sizeof(kEmptyEntriesZip);
400 ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
401
402 ZipArchiveHandle handle;
403 ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
404
405 ZipEntry entry;
406 ZipEntryName empty_name;
407 empty_name.name = kEmptyTxtName;
408 empty_name.name_length = kEmptyTxtNameLength;
409 ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
410 ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
411 uint8_t buffer[1];
412 ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
413
414 char output_file_pattern[] = "empty_entries_output_XXXXXX";
415 int output_fd = make_temporary_file(output_file_pattern);
416 ASSERT_NE(-1, output_fd);
417 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
418
419 struct stat stat_buf;
420 ASSERT_EQ(0, fstat(output_fd, &stat_buf));
421 ASSERT_EQ(0, stat_buf.st_size);
422
423 close(fd);
424 close(output_fd);
425 }
426
TEST(ziparchive,EntryLargerThan32K)427 TEST(ziparchive, EntryLargerThan32K) {
428 char temp_file_pattern[] = "entry_larger_than_32k_test_XXXXXX";
429 int fd = make_temporary_file(temp_file_pattern);
430 ASSERT_NE(-1, fd);
431 ASSERT_TRUE(android::base::WriteFully(fd, reinterpret_cast<const uint8_t*>(kAbZip),
432 sizeof(kAbZip) - 1));
433 ZipArchiveHandle handle;
434 ASSERT_EQ(0, OpenArchiveFd(fd, "EntryLargerThan32KTest", &handle));
435
436 ZipEntry entry;
437 ZipEntryName ab_name;
438 ab_name.name = kAbTxtName;
439 ab_name.name_length = kAbTxtNameLength;
440 ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
441 ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
442
443 // Extract the entry to memory.
444 std::vector<uint8_t> buffer(kAbUncompressedSize);
445 ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
446
447 // Extract the entry to a file.
448 char output_file_pattern[] = "entry_larger_than_32k_test_output_XXXXXX";
449 int output_fd = make_temporary_file(output_file_pattern);
450 ASSERT_NE(-1, output_fd);
451 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
452
453 // Make sure the extracted file size is as expected.
454 struct stat stat_buf;
455 ASSERT_EQ(0, fstat(output_fd, &stat_buf));
456 ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
457
458 // Read the file back to a buffer and make sure the contents are
459 // the same as the memory buffer we extracted directly to.
460 std::vector<uint8_t> file_contents(kAbUncompressedSize);
461 ASSERT_EQ(0, lseek64(output_fd, 0, SEEK_SET));
462 ASSERT_TRUE(android::base::ReadFully(output_fd, &file_contents[0], file_contents.size()));
463 ASSERT_EQ(file_contents, buffer);
464
465 for (int i = 0; i < 90072; ++i) {
466 const uint8_t* line = &file_contents[0] + (3 * i);
467 ASSERT_EQ('a', line[0]);
468 ASSERT_EQ('b', line[1]);
469 ASSERT_EQ('\n', line[2]);
470 }
471
472 close(fd);
473 close(output_fd);
474 }
475
TEST(ziparchive,TrailerAfterEOCD)476 TEST(ziparchive, TrailerAfterEOCD) {
477 char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
478 int fd = make_temporary_file(temp_file_pattern);
479 ASSERT_NE(-1, fd);
480
481 // Create a file with 8 bytes of random garbage.
482 static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
483 const ssize_t file_size = sizeof(kEmptyEntriesZip);
484 const ssize_t trailer_size = sizeof(trailer);
485 ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
486 ASSERT_EQ(trailer_size, TEMP_FAILURE_RETRY(write(fd, trailer, trailer_size)));
487
488 ZipArchiveHandle handle;
489 ASSERT_GT(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
490 }
491
TEST(ziparchive,ExtractToFile)492 TEST(ziparchive, ExtractToFile) {
493 char kTempFilePattern[] = "zip_archive_input_XXXXXX";
494 int fd = make_temporary_file(kTempFilePattern);
495 ASSERT_NE(-1, fd);
496 const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
497 const ssize_t data_size = sizeof(data);
498
499 ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(write(fd, data, data_size)));
500
501 ZipArchiveHandle handle;
502 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
503
504 ZipEntry entry;
505 ZipEntryName name;
506 name.name = kATxtName;
507 name.name_length = kATxtNameLength;
508 ASSERT_EQ(0, FindEntry(handle, name, &entry));
509 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, fd));
510
511
512 // Assert that the first 8 bytes of the file haven't been clobbered.
513 uint8_t read_buffer[data_size];
514 ASSERT_EQ(0, lseek64(fd, 0, SEEK_SET));
515 ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(read(fd, read_buffer, data_size)));
516 ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
517
518 // Assert that the remainder of the file contains the incompressed data.
519 std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
520 ASSERT_EQ(static_cast<ssize_t>(entry.uncompressed_length),
521 TEMP_FAILURE_RETRY(
522 read(fd, &uncompressed_data[0], entry.uncompressed_length)));
523 ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents,
524 sizeof(kATxtContents)));
525
526 // Assert that the total length of the file is sane
527 ASSERT_EQ(data_size + static_cast<ssize_t>(sizeof(kATxtContents)),
528 lseek64(fd, 0, SEEK_END));
529
530 close(fd);
531 }
532
main(int argc,char ** argv)533 int main(int argc, char** argv) {
534 ::testing::InitGoogleTest(&argc, argv);
535
536 static struct option options[] = {
537 { "test_data_dir", required_argument, NULL, 't' },
538 { NULL, 0, NULL, 0 }
539 };
540
541 while (true) {
542 int option_index;
543 const int c = getopt_long_only(argc, argv, "", options, &option_index);
544 if (c == -1) {
545 break;
546 }
547
548 if (c == 't') {
549 test_data_dir = optarg;
550 }
551 }
552
553 if (test_data_dir.size() == 0) {
554 printf("Test data flag (--test_data_dir) required\n\n");
555 return -1;
556 }
557
558 if (test_data_dir[0] != '/') {
559 printf("Test data must be an absolute path, was %s\n\n",
560 test_data_dir.c_str());
561 return -2;
562 }
563
564 return RUN_ALL_TESTS();
565 }
566