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
29struct contents {
30	off_t	o;
31	size_t	s;
32	const char *d;
33};
34
35struct contents archive_contents_sparse[] = {
36	{ 1000000, 1, "a" },
37	{ 2000000, 1, "a" },
38	{ 3145728, 0, NULL }
39};
40
41struct contents archive_contents_sparse2[] = {
42	{ 1000000, 1, "a" },
43	{ 2000000, 1, "a" },
44	{ 3000000, 1, "a" },
45	{ 4000000, 1, "a" },
46	{ 5000000, 1, "a" },
47	{ 6000000, 1, "a" },
48	{ 7000000, 1, "a" },
49	{ 8000000, 1, "a" },
50	{ 9000000, 1, "a" },
51	{ 10000000, 1, "a" },
52	{ 11000000, 1, "a" },
53	{ 12000000, 1, "a" },
54	{ 13000000, 1, "a" },
55	{ 14000000, 1, "a" },
56	{ 15000000, 1, "a" },
57	{ 16000000, 1, "a" },
58	{ 17000000, 1, "a" },
59	{ 18000000, 1, "a" },
60	{ 19000000, 1, "a" },
61	{ 20000000, 1, "a" },
62	{ 21000000, 1, "a" },
63	{ 22000000, 1, "a" },
64	{ 23000000, 1, "a" },
65	{ 24000000, 1, "a" },
66	{ 25000000, 1, "a" },
67	{ 26000000, 1, "a" },
68	{ 27000000, 1, "a" },
69	{ 28000000, 1, "a" },
70	{ 29000000, 1, "a" },
71	{ 30000000, 1, "a" },
72	{ 31000000, 1, "a" },
73	{ 32000000, 1, "a" },
74	{ 33000000, 1, "a" },
75	{ 34000000, 1, "a" },
76	{ 35000000, 1, "a" },
77	{ 36000000, 1, "a" },
78	{ 37000000, 1, "a" },
79	{ 38000000, 1, "a" },
80	{ 39000000, 1, "a" },
81	{ 40000000, 1, "a" },
82	{ 41000000, 1, "a" },
83	{ 42000000, 1, "a" },
84	{ 43000000, 1, "a" },
85	{ 44000000, 1, "a" },
86	{ 45000000, 1, "a" },
87	{ 46000000, 1, "a" },
88	{ 47000000, 1, "a" },
89	{ 48000000, 1, "a" },
90	{ 49000000, 1, "a" },
91	{ 50000000, 1, "a" },
92	{ 51000000, 1, "a" },
93	{ 52000000, 1, "a" },
94	{ 53000000, 1, "a" },
95	{ 54000000, 1, "a" },
96	{ 55000000, 1, "a" },
97	{ 56000000, 1, "a" },
98	{ 57000000, 1, "a" },
99	{ 58000000, 1, "a" },
100	{ 59000000, 1, "a" },
101	{ 60000000, 1, "a" },
102	{ 61000000, 1, "a" },
103	{ 62000000, 1, "a" },
104	{ 63000000, 1, "a" },
105	{ 64000000, 1, "a" },
106	{ 65000000, 1, "a" },
107	{ 66000000, 1, "a" },
108	{ 67000000, 1, "a" },
109	{ 68000000, 1, "a" },
110	{ 69000000, 1, "a" },
111	{ 70000000, 1, "a" },
112	{ 71000000, 1, "a" },
113	{ 72000000, 1, "a" },
114	{ 73000000, 1, "a" },
115	{ 74000000, 1, "a" },
116	{ 75000000, 1, "a" },
117	{ 76000000, 1, "a" },
118	{ 77000000, 1, "a" },
119	{ 78000000, 1, "a" },
120	{ 79000000, 1, "a" },
121	{ 80000000, 1, "a" },
122	{ 81000000, 1, "a" },
123	{ 82000000, 1, "a" },
124	{ 83000000, 1, "a" },
125	{ 84000000, 1, "a" },
126	{ 85000000, 1, "a" },
127	{ 86000000, 1, "a" },
128	{ 87000000, 1, "a" },
129	{ 88000000, 1, "a" },
130	{ 89000000, 1, "a" },
131	{ 90000000, 1, "a" },
132	{ 91000000, 1, "a" },
133	{ 92000000, 1, "a" },
134	{ 93000000, 1, "a" },
135	{ 94000000, 1, "a" },
136	{ 95000000, 1, "a" },
137	{ 96000000, 1, "a" },
138	{ 97000000, 1, "a" },
139	{ 98000000, 1, "a" },
140	{ 99000000, 1, "a" },
141	{ 99000001, 0, NULL }
142};
143
144struct contents archive_contents_nonsparse[] = {
145	{ 0, 1, "a" },
146	{ 1, 0, NULL }
147};
148
149/*
150 * Describe an archive with three entries:
151 *
152 * File 1: named "sparse"
153 *   * a length of 3145728 bytes (3MiB)
154 *   * a single 'a' byte at offset 1000000
155 *   * a single 'a' byte at offset 2000000
156 * File 2: named "sparse2"
157 *   * a single 'a' byte at offset 1,000,000, 2,000,000, ..., 99,000,000
158 *   * length of 99,000,001
159 * File 3: named 'non-sparse'
160 *   * length of 1 byte
161 *   * contains a single byte 'a'
162 */
163
164struct archive_contents {
165	const char *filename;
166	struct contents *contents;
167} files[] = {
168	{ "sparse", archive_contents_sparse },
169	{ "sparse2", archive_contents_sparse2 },
170	{ "non-sparse", archive_contents_nonsparse },
171	{ NULL, NULL }
172};
173
174static void
175verify_archive_file(const char *name, struct archive_contents *ac)
176{
177	struct archive_entry *ae;
178	int err;
179	/* data, size, offset of next expected block. */
180	struct contents expect;
181	/* data, size, offset of block read from archive. */
182	struct contents actual;
183	const void *p;
184	struct archive *a;
185
186	extract_reference_file(name);
187
188	assert((a = archive_read_new()) != NULL);
189	assert(0 == archive_read_support_compression_all(a));
190	assert(0 == archive_read_support_format_tar(a));
191	failure("Can't open %s", name);
192	assert(0 == archive_read_open_filename(a, name, 3));
193
194	while (ac->filename != NULL) {
195		struct contents *cts = ac->contents;
196
197		if (!assertEqualIntA(a, 0, archive_read_next_header(a, &ae))) {
198			assert(0 == archive_read_finish(a));
199			return;
200		}
201		failure("Name mismatch in archive %s", name);
202		assertEqualString(ac->filename, archive_entry_pathname(ae));
203
204		expect = *cts++;
205		while (0 == (err = archive_read_data_block(a,
206				 &p, &actual.s, &actual.o))) {
207			actual.d = p;
208			while (actual.s > 0) {
209				char c = *actual.d;
210				if(actual.o < expect.o) {
211					/*
212					 * Any byte before the expected
213					 * data must be NULL.
214					 */
215					failure("%s: pad at offset %d "
216					    "should be zero", name, actual.o);
217					assertEqualInt(c, 0);
218				} else if (actual.o == expect.o) {
219					/*
220					 * Data at matching offsets must match.
221					 */
222					assertEqualInt(c, *expect.d);
223					expect.d++;
224					expect.o++;
225					expect.s--;
226					/* End of expected? step to next expected. */
227					if (expect.s <= 0)
228						expect = *cts++;
229				} else {
230					/*
231					 * We found data beyond that expected.
232					 */
233					failure("%s: Unexpected trailing data",
234					    name);
235					assert(actual.o <= expect.o);
236					archive_read_finish(a);
237					return;
238				}
239				actual.d++;
240				actual.o++;
241				actual.s--;
242			}
243		}
244		failure("%s: should be end of entry", name);
245		assertEqualIntA(a, err, ARCHIVE_EOF);
246		failure("%s: Size returned at EOF must be zero", name);
247		assertEqualInt((int)actual.s, 0);
248#if ARCHIVE_VERSION_NUMBER < 1009000
249		/* libarchive < 1.9 doesn't get this right */
250		skipping("offset of final sparse chunk");
251#else
252		failure("%s: Offset of final empty chunk must be same as file size", name);
253		assertEqualInt(actual.o, expect.o);
254#endif
255		/* Step to next file description. */
256		++ac;
257	}
258
259	err = archive_read_next_header(a, &ae);
260	assertEqualIntA(a, ARCHIVE_EOF, err);
261
262	assert(0 == archive_read_close(a));
263#if ARCHIVE_VERSION_NUMBER < 2000000
264	archive_read_finish(a);
265#else
266	assert(0 == archive_read_finish(a));
267#endif
268}
269
270
271DEFINE_TEST(test_read_format_gtar_sparse)
272{
273	/* Two archives that use the "GNU tar sparse format". */
274	verify_archive_file("test_read_format_gtar_sparse_1_13.tar", files);
275	verify_archive_file("test_read_format_gtar_sparse_1_17.tar", files);
276
277	/*
278	 * libarchive < 1.9 doesn't support the newer --posix sparse formats
279	 * from GNU tar 1.15 and later.
280	 */
281#if ARCHIVE_VERSION_NUMBER < 1009000
282	skipping("read support for GNUtar --posix sparse formats");
283#else
284	/*
285	 * An archive created by GNU tar 1.17 using --posix --sparse-format=0.1
286	 */
287	verify_archive_file(
288		"test_read_format_gtar_sparse_1_17_posix00.tar",
289		files);
290	/*
291	 * An archive created by GNU tar 1.17 using --posix --sparse-format=0.1
292	 */
293	verify_archive_file(
294		"test_read_format_gtar_sparse_1_17_posix01.tar",
295		files);
296	/*
297	 * An archive created by GNU tar 1.17 using --posix --sparse-format=1.0
298	 */
299	verify_archive_file(
300		"test_read_format_gtar_sparse_1_17_posix10.tar",
301		files);
302	/*
303	 * The last test archive here is a little odd.  First, it's
304	 * uncompressed, because that exercises some of the block
305	 * reassembly code a little harder.  Second, it includes some
306	 * leading comments prior to the sparse block description.
307	 * GNU tar doesn't do this, but I think it should, so I want
308	 * to ensure that libarchive correctly ignores such comments.
309	 * Dump the file, looking for "#!gnu-sparse-format" starting
310	 * at byte 0x600.
311	 */
312	verify_archive_file(
313		"test_read_format_gtar_sparse_1_17_posix10_modified.tar",
314		files);
315#endif
316}
317
318
319