1 /*-
2  * Copyright (c) 2014 Michihiro NAKAJIMA
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  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "test.h"
28 
29 /*
30  * A basic exercise of lz4 reading and writing.
31  */
32 
33 DEFINE_TEST(test_write_filter_lz4)
34 {
35 	struct archive_entry *ae;
36 	struct archive* a;
37 	char *buff, *data;
38 	size_t buffsize, datasize;
39 	char path[16];
40 	size_t used1, used2;
41 	int i, r, use_prog = 0, filecount;
42 
43 	assert((a = archive_write_new()) != NULL);
44 	r = archive_write_add_filter_lz4(a);
45 	if (archive_liblz4_version() == NULL) {
46 		if (!canLz4()) {
47 			skipping("lz4 writing not supported on this platform");
48 			assertEqualInt(ARCHIVE_WARN, r);
49 			assertEqualInt(ARCHIVE_OK, archive_write_free(a));
50 			return;
51 		} else {
52 			assertEqualInt(ARCHIVE_WARN, r);
53 			use_prog = 1;
54 		}
55 	} else {
56 		assertEqualInt(ARCHIVE_OK, r);
57 	}
58 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
59 
60 	buffsize = 2000000;
61 	assert(NULL != (buff = (char *)malloc(buffsize)));
62 
63 	datasize = 10000;
64 	assert(NULL != (data = (char *)calloc(datasize, 1)));
65 	filecount = 10;
66 
67 	/*
68 	 * Write a filecount files and read them all back.
69 	 */
70 	assert((a = archive_write_new()) != NULL);
71 	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
72 	assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
73 	    archive_write_add_filter_lz4(a));
74 	assertEqualIntA(a, ARCHIVE_OK,
75 	    archive_write_set_bytes_per_block(a, 1024));
76 	assertEqualIntA(a, ARCHIVE_OK,
77 	    archive_write_set_bytes_in_last_block(a, 1024));
78 	assertEqualInt(ARCHIVE_FILTER_LZ4, archive_filter_code(a, 0));
79 	assertEqualString("lz4", archive_filter_name(a, 0));
80 	assertEqualIntA(a, ARCHIVE_OK,
81 	    archive_write_open_memory(a, buff, buffsize, &used1));
82 	assert((ae = archive_entry_new()) != NULL);
83 	archive_entry_set_filetype(ae, AE_IFREG);
84 	archive_entry_set_size(ae, datasize);
85 	for (i = 0; i < filecount; i++) {
86 		snprintf(path, sizeof(path), "file%03d", i);
87 		archive_entry_copy_pathname(ae, path);
88 		assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
89 		assertA(datasize
90 		    == (size_t)archive_write_data(a, data, datasize));
91 	}
92 	archive_entry_free(ae);
93 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
94 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
95 
96 	assert((a = archive_read_new()) != NULL);
97 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
98 	r = archive_read_support_filter_lz4(a);
99 	if (r == ARCHIVE_WARN) {
100 		skipping("Can't verify lz4 writing by reading back;"
101 		    " lz4 reading not fully supported on this platform");
102 		assertEqualInt(ARCHIVE_OK, archive_read_free(a));
103 		return;
104 	}
105 
106 	assertEqualIntA(a, ARCHIVE_OK,
107 	    archive_read_open_memory(a, buff, used1));
108 	for (i = 0; i < filecount; i++) {
109 		snprintf(path, sizeof(path), "file%03d", i);
110 		if (!assertEqualInt(ARCHIVE_OK,
111 			archive_read_next_header(a, &ae)))
112 			break;
113 		assertEqualString(path, archive_entry_pathname(ae));
114 		assertEqualInt((int)datasize, archive_entry_size(ae));
115 	}
116 	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
117 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
118 
119 	/*
120 	 * Repeat the cycle again, this time setting some compression
121 	 * options.
122 	 */
123 	assert((a = archive_write_new()) != NULL);
124 	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
125 	assertEqualIntA(a, ARCHIVE_OK,
126 	    archive_write_set_bytes_per_block(a, 10));
127 	assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
128 	    archive_write_add_filter_lz4(a));
129 	assertEqualIntA(a, ARCHIVE_FAILED,
130 	    archive_write_set_options(a, "lz4:nonexistent-option=0"));
131 	assertEqualIntA(a, ARCHIVE_OK,
132 	    archive_write_set_options(a, "lz4:compression-level=1"));
133 	assertEqualIntA(a, ARCHIVE_OK,
134 	    archive_write_set_filter_option(a, NULL, "compression-level", "9"));
135 	assertEqualIntA(a, ARCHIVE_FAILED,
136 	    archive_write_set_filter_option(a, NULL, "compression-level", "abc"));
137 	assertEqualIntA(a, ARCHIVE_FAILED,
138 	    archive_write_set_filter_option(a, NULL, "compression-level", "99"));
139 	assertEqualIntA(a, ARCHIVE_OK,
140 	    archive_write_set_options(a, "lz4:compression-level=9"));
141 	assertEqualIntA(a, ARCHIVE_OK,
142 	    archive_write_open_memory(a, buff, buffsize, &used2));
143 	for (i = 0; i < filecount; i++) {
144 		snprintf(path, sizeof(path), "file%03d", i);
145 		assert((ae = archive_entry_new()) != NULL);
146 		archive_entry_copy_pathname(ae, path);
147 		archive_entry_set_size(ae, datasize);
148 		archive_entry_set_filetype(ae, AE_IFREG);
149 		assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
150 		assertA(datasize == (size_t)archive_write_data(
151 		    a, data, datasize));
152 		archive_entry_free(ae);
153 	}
154 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
155 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
156 
157 	failure("compression-level=9 wrote %d bytes, default wrote %d bytes",
158 	    (int)used2, (int)used1);
159 	assert(used2 < used1);
160 
161 	assert((a = archive_read_new()) != NULL);
162 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
163 	r = archive_read_support_filter_lz4(a);
164 	if (r != ARCHIVE_OK && !use_prog) {
165 		skipping("lz4 reading not fully supported on this platform");
166 	} else {
167 		assertEqualIntA(a, ARCHIVE_OK,
168 		    archive_read_support_filter_all(a));
169 		assertEqualIntA(a, ARCHIVE_OK,
170 		    archive_read_open_memory(a, buff, used2));
171 		for (i = 0; i < filecount; i++) {
172 			snprintf(path, sizeof(path), "file%03d", i);
173 			if (!assertEqualInt(ARCHIVE_OK,
174 				archive_read_next_header(a, &ae)))
175 				break;
176 			assertEqualString(path, archive_entry_pathname(ae));
177 			assertEqualInt((int)datasize, archive_entry_size(ae));
178 		}
179 		assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
180 	}
181 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
182 
183 	/*
184 	 * Repeat again, with much lower compression.
185 	 */
186 	assert((a = archive_write_new()) != NULL);
187 	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
188 	assertEqualIntA(a, ARCHIVE_OK,
189 	    archive_write_set_bytes_per_block(a, 10));
190 	assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
191 	    archive_write_add_filter_lz4(a));
192 	assertEqualIntA(a, ARCHIVE_OK,
193 	    archive_write_set_filter_option(a, NULL, "compression-level", "1"));
194 	assertEqualIntA(a, ARCHIVE_OK,
195 	    archive_write_open_memory(a, buff, buffsize, &used2));
196 	for (i = 0; i < filecount; i++) {
197 		snprintf(path, sizeof(path), "file%03d", i);
198 		assert((ae = archive_entry_new()) != NULL);
199 		archive_entry_copy_pathname(ae, path);
200 		archive_entry_set_size(ae, datasize);
201 		archive_entry_set_filetype(ae, AE_IFREG);
202 		assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
203 		failure("Writing file %s", path);
204 		assertEqualIntA(a, datasize,
205 		    (size_t)archive_write_data(a, data, datasize));
206 		archive_entry_free(ae);
207 	}
208 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
209 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
210 
211 #if 0
212 	failure("Compression-level=1 wrote %d bytes; default wrote %d bytes",
213 	    (int)used2, (int)used1);
214 	assert(used2 > used1);
215 #endif
216 
217 	assert((a = archive_read_new()) != NULL);
218 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
219 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
220 	r = archive_read_support_filter_lz4(a);
221 	if (r == ARCHIVE_WARN) {
222 		skipping("lz4 reading not fully supported on this platform");
223 	} else {
224 		assertEqualIntA(a, ARCHIVE_OK,
225 		    archive_read_open_memory(a, buff, used2));
226 		for (i = 0; i < filecount; i++) {
227 			snprintf(path, sizeof(path), "file%03d", i);
228 			if (!assertEqualInt(ARCHIVE_OK,
229 				archive_read_next_header(a, &ae)))
230 				break;
231 			assertEqualString(path, archive_entry_pathname(ae));
232 			assertEqualInt((int)datasize, archive_entry_size(ae));
233 		}
234 		assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
235 	}
236 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
237 
238 	/*
239 	 * Test various premature shutdown scenarios to make sure we
240 	 * don't crash or leak memory.
241 	 */
242 	assert((a = archive_write_new()) != NULL);
243 	assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
244 	    archive_write_add_filter_lz4(a));
245 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
246 
247 	assert((a = archive_write_new()) != NULL);
248 	assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
249 	    archive_write_add_filter_lz4(a));
250 	assertEqualInt(ARCHIVE_OK, archive_write_close(a));
251 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
252 
253 	assert((a = archive_write_new()) != NULL);
254 	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
255 	assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
256 	    archive_write_add_filter_lz4(a));
257 	assertEqualInt(ARCHIVE_OK, archive_write_close(a));
258 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
259 
260 	assert((a = archive_write_new()) != NULL);
261 	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
262 	assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
263 	    archive_write_add_filter_lz4(a));
264 	assertEqualIntA(a, ARCHIVE_OK,
265 	    archive_write_open_memory(a, buff, buffsize, &used2));
266 	assertEqualInt(ARCHIVE_OK, archive_write_close(a));
267 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
268 
269 	/*
270 	 * Clean up.
271 	 */
272 	free(data);
273 	free(buff);
274 }
275 
276 static void
277 test_options(const char *options)
278 {
279 	struct archive_entry *ae;
280 	struct archive* a;
281 	char *buff, *data;
282 	size_t buffsize, datasize;
283 	char path[16];
284 	size_t used1;
285 	int i, r, use_prog = 0, filecount;
286 
287 	assert((a = archive_write_new()) != NULL);
288 	r = archive_write_add_filter_lz4(a);
289 	if (archive_liblz4_version() == NULL) {
290 		if (!canLz4()) {
291 			skipping("lz4 writing not supported on this platform");
292 			assertEqualInt(ARCHIVE_WARN, r);
293 			assertEqualInt(ARCHIVE_OK, archive_write_free(a));
294 			return;
295 		} else {
296 			assertEqualInt(ARCHIVE_WARN, r);
297 			use_prog = 1;
298 		}
299 	} else {
300 		assertEqualInt(ARCHIVE_OK, r);
301 	}
302 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
303 
304 	buffsize = 2000000;
305 	assert(NULL != (buff = (char *)malloc(buffsize)));
306 
307 	datasize = 10000;
308 	assert(NULL != (data = (char *)calloc(datasize, 1)));
309 	filecount = 10;
310 
311 	/*
312 	 * Write a filecount files and read them all back.
313 	 */
314 	assert((a = archive_write_new()) != NULL);
315 	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
316 	assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
317 	    archive_write_add_filter_lz4(a));
318 	assertEqualIntA(a, ARCHIVE_OK,
319 	    archive_write_set_options(a, options));
320 	assertEqualIntA(a, ARCHIVE_OK,
321 	    archive_write_set_bytes_per_block(a, 1024));
322 	assertEqualIntA(a, ARCHIVE_OK,
323 	    archive_write_set_bytes_in_last_block(a, 1024));
324 	assertEqualInt(ARCHIVE_FILTER_LZ4, archive_filter_code(a, 0));
325 	assertEqualString("lz4", archive_filter_name(a, 0));
326 	assertEqualIntA(a, ARCHIVE_OK,
327 	    archive_write_open_memory(a, buff, buffsize, &used1));
328 	assert((ae = archive_entry_new()) != NULL);
329 	archive_entry_set_filetype(ae, AE_IFREG);
330 	archive_entry_set_size(ae, datasize);
331 	for (i = 0; i < filecount; i++) {
332 		snprintf(path, sizeof(path), "file%03d", i);
333 		archive_entry_copy_pathname(ae, path);
334 		assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
335 		assertA(datasize
336 		    == (size_t)archive_write_data(a, data, datasize));
337 	}
338 	archive_entry_free(ae);
339 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
340 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
341 
342 	assert((a = archive_read_new()) != NULL);
343 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
344 	r = archive_read_support_filter_lz4(a);
345 	if (r == ARCHIVE_WARN) {
346 		skipping("Can't verify lz4 writing by reading back;"
347 		    " lz4 reading not fully supported on this platform");
348 	} else {
349 		assertEqualIntA(a, ARCHIVE_OK,
350 		    archive_read_open_memory(a, buff, used1));
351 		for (i = 0; i < filecount; i++) {
352 			snprintf(path, sizeof(path), "file%03d", i);
353 			if (!assertEqualInt(ARCHIVE_OK,
354 				archive_read_next_header(a, &ae)))
355 				break;
356 			assertEqualString(path, archive_entry_pathname(ae));
357 			assertEqualInt((int)datasize, archive_entry_size(ae));
358 		}
359 		assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
360 	}
361 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
362 
363 	/*
364 	 * Clean up.
365 	 */
366 	free(data);
367 	free(buff);
368 }
369 
370 DEFINE_TEST(test_write_filter_lz4_disable_stream_checksum)
371 {
372 	test_options("lz4:!stream-checksum");
373 }
374 
375 DEFINE_TEST(test_write_filter_lz4_enable_block_checksum)
376 {
377 	test_options("lz4:block-checksum");
378 }
379 
380 DEFINE_TEST(test_write_filter_lz4_block_size_4)
381 {
382 	test_options("lz4:block-size=4");
383 }
384 
385 DEFINE_TEST(test_write_filter_lz4_block_size_5)
386 {
387 	test_options("lz4:block-size=5");
388 }
389 
390 DEFINE_TEST(test_write_filter_lz4_block_size_6)
391 {
392 	test_options("lz4:block-size=6");
393 }
394 
395 DEFINE_TEST(test_write_filter_lz4_block_dependence)
396 {
397 	test_options("lz4:block-dependence");
398 }
399 
400 /*
401  * TODO: Figure out how to correctly handle this.
402  *
403  * This option simply fails on some versions of the LZ4 libraries.
404  */
405 /*
406 XXXDEFINE_TEST(test_write_filter_lz4_block_dependence_hc)
407 {
408 	test_options("lz4:block-dependence,lz4:compression-level=9");
409 }
410 */
411