zip_archive_test.cc revision f1d3d3b2477a813805b71099c60e07d36dbb225a
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
29static std::string test_data_dir;
30
31static const std::string kMissingZip = "missing.zip";
32static const std::string kValidZip = "valid.zip";
33
34static 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
40static const uint8_t kBTxtContents[] = {
41  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
42  '\n'
43};
44
45static const uint16_t kATxtNameLength = 5;
46static const uint16_t kBTxtNameLength = 5;
47static const uint16_t kNonexistentTxtNameLength = 15;
48static const uint16_t kEmptyTxtNameLength = 9;
49
50static const uint8_t kATxtName[kATxtNameLength] = {
51  'a', '.', 't', 'x', 't'
52};
53
54static const uint8_t kBTxtName[kBTxtNameLength] = {
55  'b', '.', 't', 'x', 't'
56};
57
58static const uint8_t kNonexistentTxtName[kNonexistentTxtNameLength] = {
59  'n', 'o', 'n', 'e', 'x', 'i', 's', 't', 'e', 'n', 't', '.', 't', 'x' ,'t'
60};
61
62static const uint8_t kEmptyTxtName[kEmptyTxtNameLength] = {
63  'e', 'm', 'p', 't', 'y', '.', 't', 'x', 't'
64};
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 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
78TEST(ziparchive, Open) {
79  ZipArchiveHandle handle;
80  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
81
82  CloseArchive(handle);
83}
84
85TEST(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
93TEST(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
103TEST(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
113TEST(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
149TEST(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
178TEST(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
211TEST(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
241TEST(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
259TEST(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
285TEST(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
301TEST(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
333static 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.
345static 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
376static const uint8_t kAbTxtName[] = { 'a', 'b', '.', 't', 'x', 't' };
377static const uint16_t kAbTxtNameLength = sizeof(kAbTxtName);
378static const size_t kAbUncompressedSize = 270216;
379
380static 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
395TEST(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
427TEST(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
476TEST(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
492TEST(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
533int 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