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