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