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. */
28DEFINE_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
60finish:
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 */
71DEFINE_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 */
100DEFINE_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 */
149DEFINE_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 */
207DEFINE_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 */
342static void
343compat_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
364DEFINE_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 */
394DEFINE_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 */
429DEFINE_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