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