1 /*-
2 * Copyright (c) 2003-2007 Tim Kientzle
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25 #include "test.h"
26
27 /* Copy this function for each test file and adjust it accordingly. */
DEFINE_TEST(test_compat_zip_1)28 DEFINE_TEST(test_compat_zip_1)
29 {
30 char name[] = "test_compat_zip_1.zip";
31 struct archive_entry *ae;
32 struct archive *a;
33 int r;
34
35 assert((a = archive_read_new()) != NULL);
36 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
37 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
38 extract_reference_file(name);
39 assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));
40
41 /* Read first entry. */
42 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
43 assertEqualString("META-INF/MANIFEST.MF", archive_entry_pathname(ae));
44
45 /* Read second entry. */
46 r = archive_read_next_header(a, &ae);
47 if (r == ARCHIVE_FATAL && archive_zlib_version() == NULL) {
48 skipping("Skipping ZIP compression check: %s",
49 archive_error_string(a));
50 goto finish;
51 }
52 assertEqualIntA(a, ARCHIVE_OK, r);
53 assertEqualString("tmp.class", archive_entry_pathname(ae));
54
55 assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
56
57 assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
58 assertEqualInt(archive_format(a), ARCHIVE_FORMAT_ZIP);
59
60 finish:
61 assertEqualInt(ARCHIVE_OK, archive_read_close(a));
62 assertEqualInt(ARCHIVE_OK, archive_read_free(a));
63 }
64
65 /*
66 * Verify that we skip junk between entries. The compat_zip_2.zip file
67 * has several bytes of junk between 'file1' and 'file2'. Such
68 * junk is routinely introduced by some Zip writers when they manipulate
69 * existing zip archives.
70 */
DEFINE_TEST(test_compat_zip_2)71 DEFINE_TEST(test_compat_zip_2)
72 {
73 char name[] = "test_compat_zip_2.zip";
74 struct archive_entry *ae;
75 struct archive *a;
76
77 assert((a = archive_read_new()) != NULL);
78 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
79 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
80 extract_reference_file(name);
81 assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));
82
83 /* Read first entry. */
84 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
85 assertEqualString("file1", archive_entry_pathname(ae));
86
87 /* Read first entry. */
88 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
89 assertEqualString("file2", archive_entry_pathname(ae));
90
91 assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
92 assertEqualInt(ARCHIVE_OK, archive_read_close(a));
93 assertEqualInt(ARCHIVE_OK, archive_read_free(a));
94 }
95
96 /*
97 * Issue 185: Test a regression that got in between 2.6 and 2.7 that
98 * broke extraction of Zip entries with length-at-end.
99 */
DEFINE_TEST(test_compat_zip_3)100 DEFINE_TEST(test_compat_zip_3)
101 {
102 const char *refname = "test_compat_zip_3.zip";
103 struct archive_entry *ae;
104 struct archive *a;
105
106 extract_reference_file(refname);
107 assert((a = archive_read_new()) != NULL);
108 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
109 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
110 assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
111
112 /* First entry. */
113 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
114 assertEqualString("soapui-4.0.0/", archive_entry_pathname(ae));
115 assertEqualInt(0, archive_entry_size(ae));
116 assert(archive_entry_size_is_set(ae));
117 assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
118
119 /* Second entry. */
120 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
121 assertEqualString("soapui-4.0.0/soapui-settings.xml", archive_entry_pathname(ae));
122 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
123 assertEqualInt(1030, archive_entry_size(ae));
124 assert(archive_entry_size_is_set(ae));
125
126 /* Extract under a different name. */
127 archive_entry_set_pathname(ae, "test_3.txt");
128 if(archive_zlib_version() != NULL) {
129 char *p;
130 size_t s;
131 assertEqualIntA(a, ARCHIVE_OK, archive_read_extract(a, ae, 0));
132 /* Verify the first 12 bytes actually got written to disk correctly. */
133 p = slurpfile(&s, "test_3.txt");
134 assertEqualInt(s, 1030);
135 assertEqualMem(p, "<?xml versio", 12);
136 free(p);
137 } else {
138 skipping("Skipping ZIP compression check, no libz support");
139 }
140 assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
141
142 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
143 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
144 }
145
146 /**
147 * A file with leading garbage (similar to an SFX file).
148 */
DEFINE_TEST(test_compat_zip_4)149 DEFINE_TEST(test_compat_zip_4)
150 {
151 const char *refname = "test_compat_zip_4.zip";
152 struct archive_entry *ae;
153 struct archive *a;
154 void *p;
155 size_t s;
156
157 extract_reference_file(refname);
158 p = slurpfile(&s, "%s", refname);
159
160 /* SFX files require seek support. */
161 assert((a = archive_read_new()) != NULL);
162 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
163 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
164 assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 18));
165
166 /* First entry. */
167 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
168 assertEqualString("foo", archive_entry_pathname(ae));
169 assertEqualInt(4, archive_entry_size(ae));
170 assert(archive_entry_size_is_set(ae));
171 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
172 assertEqualInt(0412, archive_entry_perm(ae));
173
174 /* Second entry. */
175 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
176 assertEqualString("bar", archive_entry_pathname(ae));
177 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
178 assertEqualInt(4, archive_entry_size(ae));
179 assert(archive_entry_size_is_set(ae));
180 assertEqualInt(0567, archive_entry_perm(ae));
181
182 /* Third entry. */
183 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
184 assertEqualString("baz", archive_entry_pathname(ae));
185 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
186 assertEqualInt(4, archive_entry_size(ae));
187 assert(archive_entry_size_is_set(ae));
188 assertEqualInt(0644, archive_entry_perm(ae));
189
190 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
191 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
192
193 /* Try reading without seek support and watch it fail. */
194 assert((a = archive_read_new()) != NULL);
195 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
196 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
197 assertEqualIntA(a, ARCHIVE_FATAL, read_open_memory(a, p, s, 3));
198 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
199 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
200 free(p);
201 }
202 /**
203 * Issue 152: A file generated by a tool that doesn't really
204 * believe in populating local file headers at all. This
205 * is only readable with the seeking reader.
206 */
DEFINE_TEST(test_compat_zip_5)207 DEFINE_TEST(test_compat_zip_5)
208 {
209 const char *refname = "test_compat_zip_5.zip";
210 struct archive_entry *ae;
211 struct archive *a;
212 void *p;
213 size_t s;
214
215 extract_reference_file(refname);
216 p = slurpfile(&s, "%s", refname);
217
218 /* Verify with seek support.
219 * Everything works correctly here. */
220 assert((a = archive_read_new()) != NULL);
221 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
222 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
223 assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 18));
224
225 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
226 assertEqualString("Metadata/Job_PT.xml", archive_entry_pathname(ae));
227 assertEqualInt(3559, archive_entry_size(ae));
228 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
229 assertEqualInt(0664, archive_entry_perm(ae));
230
231 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
232 assertEqualString("Metadata/MXDC_Empty_PT.xml", archive_entry_pathname(ae));
233 assertEqualInt(456, archive_entry_size(ae));
234 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
235 assertEqualInt(0664, archive_entry_perm(ae));
236
237 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
238 assertEqualString("Documents/1/Metadata/Page1_Thumbnail.JPG", archive_entry_pathname(ae));
239 assertEqualInt(1495, archive_entry_size(ae));
240 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
241 assertEqualInt(0664, archive_entry_perm(ae));
242 /* TODO: Read some of the file data and verify it.
243 The code to read uncompressed Zip entries with "file at end" semantics
244 is tricky and should be verified more carefully. */
245
246 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
247 assertEqualString("Documents/1/Pages/_rels/1.fpage.rels", archive_entry_pathname(ae));
248
249 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
250 assertEqualString("Documents/1/Pages/1.fpage", archive_entry_pathname(ae));
251
252 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
253 assertEqualString("Documents/1/Resources/Fonts/3DFDBC8B-4514-41F1-A808-DEA1C79BAC2B.odttf", archive_entry_pathname(ae));
254
255 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
256 assertEqualString("Documents/1/_rels/FixedDocument.fdoc.rels", archive_entry_pathname(ae));
257
258 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
259 assertEqualString("Documents/1/FixedDocument.fdoc", archive_entry_pathname(ae));
260
261 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
262 assertEqualString("_rels/FixedDocumentSequence.fdseq.rels", archive_entry_pathname(ae));
263
264 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
265 assertEqualString("FixedDocumentSequence.fdseq", archive_entry_pathname(ae));
266
267 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
268 assertEqualString("_rels/.rels", archive_entry_pathname(ae));
269
270 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
271 assertEqualString("[Content_Types].xml", archive_entry_pathname(ae));
272
273 assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
274
275 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
276 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
277
278 /* Try reading without seek support. */
279 assert((a = archive_read_new()) != NULL);
280 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
281 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
282 assertEqualIntA(a, ARCHIVE_OK, read_open_memory(a, p, s, 3));
283
284 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
285 assertEqualString("Metadata/Job_PT.xml", archive_entry_pathname(ae));
286 assertEqualInt(0, archive_entry_size(ae));
287 assert(!archive_entry_size_is_set(ae));
288 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
289 assertEqualInt(0664, archive_entry_perm(ae));
290
291 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
292 assertEqualString("Metadata/MXDC_Empty_PT.xml", archive_entry_pathname(ae));
293 assertEqualInt(0, archive_entry_size(ae));
294 assert(!archive_entry_size_is_set(ae));
295 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
296 assertEqualInt(0664, archive_entry_perm(ae));
297
298 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
299 assertEqualString("Documents/1/Metadata/Page1_Thumbnail.JPG", archive_entry_pathname(ae));
300 assertEqualInt(0, archive_entry_size(ae));
301 assert(!archive_entry_size_is_set(ae));
302 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
303 assertEqualInt(0664, archive_entry_perm(ae));
304
305 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
306 assertEqualString("Documents/1/Pages/_rels/1.fpage.rels", archive_entry_pathname(ae));
307
308 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
309 assertEqualString("Documents/1/Pages/1.fpage", archive_entry_pathname(ae));
310
311 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
312 assertEqualString("Documents/1/Resources/Fonts/3DFDBC8B-4514-41F1-A808-DEA1C79BAC2B.odttf", archive_entry_pathname(ae));
313
314 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
315 assertEqualString("Documents/1/_rels/FixedDocument.fdoc.rels", archive_entry_pathname(ae));
316
317 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
318 assertEqualString("Documents/1/FixedDocument.fdoc", archive_entry_pathname(ae));
319
320 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
321 assertEqualString("_rels/FixedDocumentSequence.fdseq.rels", archive_entry_pathname(ae));
322
323 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
324 assertEqualString("FixedDocumentSequence.fdseq", archive_entry_pathname(ae));
325
326 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
327 assertEqualString("_rels/.rels", archive_entry_pathname(ae));
328
329 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
330 assertEqualString("[Content_Types].xml", archive_entry_pathname(ae));
331
332 assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
333
334 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
335 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
336 free(p);
337 }
338
339 /*
340 * Issue 225: Errors extracting MSDOS Zip archives with directories.
341 */
342 static void
compat_zip_6_verify(struct archive * a)343 compat_zip_6_verify(struct archive *a)
344 {
345 struct archive_entry *ae;
346
347 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
348 assertEqualString("New Folder/New Folder/", archive_entry_pathname(ae));
349 assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
350 /* Zip timestamps are local time, so vary by time zone. */
351 /* TODO: A more complex assert would work here; we could
352 verify that it's within +/- 24 hours of a particular value. */
353 /* assertEqualInt(1327314468, archive_entry_mtime(ae)); */
354 assertEqualInt(0, archive_entry_size(ae));
355 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
356 assertEqualString("New Folder/New Folder/New Text Document.txt", archive_entry_pathname(ae));
357 assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
358 /* Zip timestamps are local time, so vary by time zone. */
359 /* assertEqualInt(1327314476, archive_entry_mtime(ae)); */
360 assertEqualInt(11, archive_entry_size(ae));
361 assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
362 }
363
DEFINE_TEST(test_compat_zip_6)364 DEFINE_TEST(test_compat_zip_6)
365 {
366 const char *refname = "test_compat_zip_6.zip";
367 struct archive *a;
368 void *p;
369 size_t s;
370
371 extract_reference_file(refname);
372 p = slurpfile(&s, "%s", refname);
373
374 assert((a = archive_read_new()) != NULL);
375 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
376 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
377 assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 7));
378 compat_zip_6_verify(a);
379 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
380
381 assert((a = archive_read_new()) != NULL);
382 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
383 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
384 assertEqualIntA(a, ARCHIVE_OK, read_open_memory(a, p, s, 7));
385 compat_zip_6_verify(a);
386 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
387 free(p);
388 }
389
390 /*
391 * Issue 226: Try to reproduce hang when reading archives where the
392 * length-at-end marker ends exactly on a block boundary.
393 */
DEFINE_TEST(test_compat_zip_7)394 DEFINE_TEST(test_compat_zip_7)
395 {
396 const char *refname = "test_compat_zip_7.xps";
397 struct archive *a;
398 struct archive_entry *ae;
399 void *p;
400 size_t s;
401 int i;
402
403 extract_reference_file(refname);
404 p = slurpfile(&s, "%s", refname);
405
406 for (i = 1; i < 1000; ++i) {
407 assert((a = archive_read_new()) != NULL);
408 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
409 assertEqualIntA(a, ARCHIVE_OK, read_open_memory_minimal(a, p, s, i));
410
411 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
412 assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));
413 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
414 assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));
415 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
416 assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));
417 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
418 assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));
419
420 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
421 }
422 free(p);
423 }
424
425 /**
426 * A file with backslash path separators instead of slashes.
427 * PowerShell's Compress-Archive cmdlet produces such archives.
428 */
DEFINE_TEST(test_compat_zip_8)429 DEFINE_TEST(test_compat_zip_8)
430 {
431 const char *refname = "test_compat_zip_8.zip";
432 struct archive *a;
433 struct archive_entry *ae;
434 void *p;
435 size_t s;
436
437 extract_reference_file(refname);
438 p = slurpfile(&s, "%s", refname);
439
440 assert((a = archive_read_new()) != NULL);
441 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
442 assertEqualIntA(a, ARCHIVE_OK, read_open_memory_minimal(a, p, s, 7));
443
444 assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
445 /* This file is in the archive as arc\test */
446 assertEqualString("arc/test", archive_entry_pathname(ae));
447 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
448 free(p);
449 }
450