1 /*-
2 * Copyright (c) 2017 Sean Purcell
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
DEFINE_TEST(test_write_filter_zstd)29 DEFINE_TEST(test_write_filter_zstd)
30 {
31 struct archive_entry *ae;
32 struct archive *a;
33 char *buff, *data;
34 size_t buffsize, datasize;
35 char path[16];
36 size_t used1, used2, used3;
37 int i, r;
38
39 buffsize = 2000000;
40 assert(NULL != (buff = malloc(buffsize)));
41 if (buff == NULL)
42 return;
43
44 datasize = 10000;
45 assert(NULL != (data = malloc(datasize)));
46 if (data == NULL) {
47 free(buff);
48 return;
49 }
50 memset(data, 0, datasize);
51
52 /*
53 * Write a 100 files and read them all back.
54 */
55 assert((a = archive_write_new()) != NULL);
56 assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
57 r = archive_write_add_filter_zstd(a);
58 if (r != ARCHIVE_OK) {
59 skipping("zstd writing not supported on this platform");
60 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
61 free(buff);
62 free(data);
63 return;
64 }
65 assertEqualIntA(a, ARCHIVE_OK,
66 archive_write_set_bytes_per_block(a, 10));
67 assertEqualInt(ARCHIVE_FILTER_ZSTD, archive_filter_code(a, 0));
68 assertEqualString("zstd", archive_filter_name(a, 0));
69 assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used1));
70 assertEqualInt(ARCHIVE_FILTER_ZSTD, archive_filter_code(a, 0));
71 assertEqualString("zstd", archive_filter_name(a, 0));
72 assert((ae = archive_entry_new()) != NULL);
73 archive_entry_set_filetype(ae, AE_IFREG);
74 archive_entry_set_size(ae, datasize);
75 for (i = 0; i < 100; i++) {
76 snprintf(path, sizeof(path), "file%03d", i);
77 archive_entry_copy_pathname(ae, path);
78 assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
79 assertA(datasize
80 == (size_t)archive_write_data(a, data, datasize));
81 }
82 archive_entry_free(ae);
83 assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
84 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
85
86 assert((a = archive_read_new()) != NULL);
87 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
88 r = archive_read_support_filter_zstd(a);
89 if (r == ARCHIVE_WARN) {
90 skipping("Can't verify zstd writing by reading back;"
91 " zstd reading not fully supported on this platform");
92 } else {
93 assertEqualIntA(a, ARCHIVE_OK,
94 archive_read_support_filter_all(a));
95 assertEqualIntA(a, ARCHIVE_OK,
96 archive_read_open_memory(a, buff, used1));
97 for (i = 0; i < 100; i++) {
98 snprintf(path, sizeof(path), "file%03d", i);
99 if (!assertEqualInt(ARCHIVE_OK,
100 archive_read_next_header(a, &ae)))
101 break;
102 assertEqualString(path, archive_entry_pathname(ae));
103 assertEqualInt((int)datasize, archive_entry_size(ae));
104 }
105 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
106 }
107 assertEqualInt(ARCHIVE_OK, archive_read_free(a));
108
109 /*
110 * Repeat the cycle again, this time setting some compression
111 * options.
112 */
113 assert((a = archive_write_new()) != NULL);
114 assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
115 assertEqualIntA(a, ARCHIVE_OK,
116 archive_write_set_bytes_per_block(a, 10));
117 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
118 assertEqualIntA(a, ARCHIVE_FAILED,
119 archive_write_set_filter_option(a, NULL, "nonexistent-option", "0"));
120 assertEqualIntA(a, ARCHIVE_FAILED,
121 archive_write_set_filter_option(a, NULL, "compression-level", "abc"));
122 assertEqualIntA(a, ARCHIVE_FAILED,
123 archive_write_set_filter_option(a, NULL, "compression-level", "25")); /* too big */
124 assertEqualIntA(a, ARCHIVE_OK,
125 archive_write_set_filter_option(a, NULL, "compression-level", "9"));
126 /* Following is disabled as it will fail on library versions < 1.3.4 */
127 /* assertEqualIntA(a, ARCHIVE_OK,
128 archive_write_set_filter_option(a, NULL, "compression-level", "-1")); */
129 assertEqualIntA(a, ARCHIVE_OK,
130 archive_write_set_filter_option(a, NULL, "compression-level", "7"));
131 assertEqualIntA(a, ARCHIVE_FAILED,
132 archive_write_set_filter_option(a, NULL, "threads", "-1")); /* negative */
133 assertEqualIntA(a, ARCHIVE_OK,
134 archive_write_set_filter_option(a, NULL, "threads", "4"));
135 #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
136 /* frame-per-file: boolean */
137 assertEqualIntA(a, ARCHIVE_OK,
138 archive_write_set_filter_option(a, NULL, "frame-per-file", ""));
139 /* min-frame-in: >= 0 */
140 assertEqualIntA(a, ARCHIVE_FAILED,
141 archive_write_set_filter_option(a, NULL, "min-frame-out", ""));
142 assertEqualIntA(a, ARCHIVE_FAILED,
143 archive_write_set_filter_option(a, NULL, "min-frame-out", "-1"));
144 assertEqualIntA(a, ARCHIVE_OK,
145 archive_write_set_filter_option(a, NULL, "min-frame-out", "0"));
146 assertEqualIntA(a, ARCHIVE_OK,
147 archive_write_set_filter_option(a, NULL, "min-frame-out", "1048576"));
148 assertEqualIntA(a, ARCHIVE_OK,
149 archive_write_set_filter_option(a, NULL, "min-frame-out", "1k"));
150 assertEqualIntA(a, ARCHIVE_OK,
151 archive_write_set_filter_option(a, NULL, "min-frame-out", "1kB"));
152 assertEqualIntA(a, ARCHIVE_OK,
153 archive_write_set_filter_option(a, NULL, "min-frame-out", "1M"));
154 assertEqualIntA(a, ARCHIVE_OK,
155 archive_write_set_filter_option(a, NULL, "min-frame-out", "1MB"));
156 assertEqualIntA(a, ARCHIVE_OK,
157 archive_write_set_filter_option(a, NULL, "min-frame-out", "1G"));
158 assertEqualIntA(a, ARCHIVE_OK,
159 archive_write_set_filter_option(a, NULL, "min-frame-out", "1GB"));
160 /* min-frame-out: >= 0 */
161 assertEqualIntA(a, ARCHIVE_FAILED,
162 archive_write_set_filter_option(a, NULL, "min-frame-in", ""));
163 assertEqualIntA(a, ARCHIVE_FAILED,
164 archive_write_set_filter_option(a, NULL, "min-frame-in", "-1"));
165 assertEqualIntA(a, ARCHIVE_OK,
166 archive_write_set_filter_option(a, NULL, "min-frame-in", "0"));
167 assertEqualIntA(a, ARCHIVE_OK,
168 archive_write_set_filter_option(a, NULL, "min-frame-in", "1048576"));
169 assertEqualIntA(a, ARCHIVE_OK,
170 archive_write_set_filter_option(a, NULL, "min-frame-in", "1k"));
171 assertEqualIntA(a, ARCHIVE_OK,
172 archive_write_set_filter_option(a, NULL, "min-frame-in", "1kB"));
173 assertEqualIntA(a, ARCHIVE_OK,
174 archive_write_set_filter_option(a, NULL, "min-frame-in", "1M"));
175 assertEqualIntA(a, ARCHIVE_OK,
176 archive_write_set_filter_option(a, NULL, "min-frame-in", "1MB"));
177 assertEqualIntA(a, ARCHIVE_OK,
178 archive_write_set_filter_option(a, NULL, "min-frame-in", "1G"));
179 assertEqualIntA(a, ARCHIVE_OK,
180 archive_write_set_filter_option(a, NULL, "min-frame-in", "1GB"));
181 /* max-frame-in: >= 1024 */
182 assertEqualIntA(a, ARCHIVE_FAILED,
183 archive_write_set_filter_option(a, NULL, "max-frame-in", ""));
184 assertEqualIntA(a, ARCHIVE_FAILED,
185 archive_write_set_filter_option(a, NULL, "max-frame-in", "-1"));
186 assertEqualIntA(a, ARCHIVE_FAILED,
187 archive_write_set_filter_option(a, NULL, "max-frame-in", "0"));
188 assertEqualIntA(a, ARCHIVE_FAILED,
189 archive_write_set_filter_option(a, NULL, "max-frame-in", "1023"));
190 assertEqualIntA(a, ARCHIVE_OK,
191 archive_write_set_filter_option(a, NULL, "max-frame-in", "1024"));
192 assertEqualIntA(a, ARCHIVE_OK,
193 archive_write_set_filter_option(a, NULL, "max-frame-in", "1048576"));
194 assertEqualIntA(a, ARCHIVE_OK,
195 archive_write_set_filter_option(a, NULL, "max-frame-in", "1k"));
196 assertEqualIntA(a, ARCHIVE_OK,
197 archive_write_set_filter_option(a, NULL, "max-frame-in", "1kB"));
198 assertEqualIntA(a, ARCHIVE_OK,
199 archive_write_set_filter_option(a, NULL, "max-frame-in", "1M"));
200 assertEqualIntA(a, ARCHIVE_OK,
201 archive_write_set_filter_option(a, NULL, "max-frame-in", "1MB"));
202 assertEqualIntA(a, ARCHIVE_OK,
203 archive_write_set_filter_option(a, NULL, "max-frame-in", "1G"));
204 assertEqualIntA(a, ARCHIVE_OK,
205 archive_write_set_filter_option(a, NULL, "max-frame-in", "1GB"));
206 /* max-frame-out: >= 1024 */
207 assertEqualIntA(a, ARCHIVE_FAILED,
208 archive_write_set_filter_option(a, NULL, "max-frame-out", ""));
209 assertEqualIntA(a, ARCHIVE_FAILED,
210 archive_write_set_filter_option(a, NULL, "max-frame-out", "-1"));
211 assertEqualIntA(a, ARCHIVE_FAILED,
212 archive_write_set_filter_option(a, NULL, "max-frame-out", "0"));
213 assertEqualIntA(a, ARCHIVE_FAILED,
214 archive_write_set_filter_option(a, NULL, "max-frame-out", "1023"));
215 assertEqualIntA(a, ARCHIVE_OK,
216 archive_write_set_filter_option(a, NULL, "max-frame-out", "1024"));
217 assertEqualIntA(a, ARCHIVE_OK,
218 archive_write_set_filter_option(a, NULL, "max-frame-out", "1048576"));
219 assertEqualIntA(a, ARCHIVE_OK,
220 archive_write_set_filter_option(a, NULL, "max-frame-out", "1k"));
221 assertEqualIntA(a, ARCHIVE_OK,
222 archive_write_set_filter_option(a, NULL, "max-frame-out", "1kB"));
223 assertEqualIntA(a, ARCHIVE_OK,
224 archive_write_set_filter_option(a, NULL, "max-frame-out", "1M"));
225 assertEqualIntA(a, ARCHIVE_OK,
226 archive_write_set_filter_option(a, NULL, "max-frame-out", "1MB"));
227 assertEqualIntA(a, ARCHIVE_OK,
228 archive_write_set_filter_option(a, NULL, "max-frame-out", "1G"));
229 assertEqualIntA(a, ARCHIVE_OK,
230 archive_write_set_filter_option(a, NULL, "max-frame-out", "1GB"));
231 #endif
232 #if ZSTD_VERSION_NUMBER >= MINVER_LONG
233 assertEqualIntA(a, ARCHIVE_OK,
234 archive_write_set_filter_option(a, NULL, "long", "23"));
235 assertEqualIntA(a, ARCHIVE_FAILED,
236 archive_write_set_filter_option(a, NULL, "long", "-1")); /* negative */
237 #endif
238 assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
239 for (i = 0; i < 100; i++) {
240 snprintf(path, sizeof(path), "file%03d", i);
241 assert((ae = archive_entry_new()) != NULL);
242 archive_entry_copy_pathname(ae, path);
243 archive_entry_set_size(ae, datasize);
244 archive_entry_set_filetype(ae, AE_IFREG);
245 assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
246 assertA(datasize == (size_t)archive_write_data(a, data, datasize));
247 archive_entry_free(ae);
248 }
249 assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
250 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
251
252 assert((a = archive_read_new()) != NULL);
253 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
254 r = archive_read_support_filter_zstd(a);
255 if (r == ARCHIVE_WARN) {
256 skipping("zstd reading not fully supported on this platform");
257 } else {
258 assertEqualIntA(a, ARCHIVE_OK,
259 archive_read_support_filter_all(a));
260 assertEqualIntA(a, ARCHIVE_OK,
261 archive_read_open_memory(a, buff, used2));
262 for (i = 0; i < 100; i++) {
263 snprintf(path, sizeof(path), "file%03d", i);
264 failure("Trying to read %s", path);
265 if (!assertEqualIntA(a, ARCHIVE_OK,
266 archive_read_next_header(a, &ae)))
267 break;
268 assertEqualString(path, archive_entry_pathname(ae));
269 assertEqualInt((int)datasize, archive_entry_size(ae));
270 }
271 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
272 }
273 assertEqualInt(ARCHIVE_OK, archive_read_free(a));
274
275 /*
276 * One more time at level 1
277 */
278 assert((a = archive_write_new()) != NULL);
279 assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
280 assertEqualIntA(a, ARCHIVE_OK,
281 archive_write_set_bytes_per_block(a, 10));
282 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
283 assertEqualIntA(a, ARCHIVE_OK,
284 archive_write_set_filter_option(a, NULL, "compression-level", "1"));
285 assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used3));
286 assert((ae = archive_entry_new()) != NULL);
287 archive_entry_set_filetype(ae, AE_IFREG);
288 archive_entry_set_size(ae, datasize);
289 for (i = 0; i < 100; i++) {
290 snprintf(path, sizeof(path), "file%03d", i);
291 archive_entry_copy_pathname(ae, path);
292 assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
293 assertA(datasize == (size_t)archive_write_data(a, data, datasize));
294 }
295 archive_entry_free(ae);
296 assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
297 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
298
299 assert((a = archive_read_new()) != NULL);
300 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
301 r = archive_read_support_filter_zstd(a);
302 if (r == ARCHIVE_WARN) {
303 skipping("zstd reading not fully supported on this platform");
304 } else {
305 assertEqualIntA(a, ARCHIVE_OK,
306 archive_read_support_filter_all(a));
307 assertEqualIntA(a, ARCHIVE_OK,
308 archive_read_open_memory(a, buff, used3));
309 for (i = 0; i < 100; i++) {
310 snprintf(path, sizeof(path), "file%03d", i);
311 failure("Trying to read %s", path);
312 if (!assertEqualIntA(a, ARCHIVE_OK,
313 archive_read_next_header(a, &ae)))
314 break;
315 assertEqualString(path, archive_entry_pathname(ae));
316 assertEqualInt((int)datasize, archive_entry_size(ae));
317 }
318 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
319 }
320 assertEqualInt(ARCHIVE_OK, archive_read_free(a));
321
322 /*
323 * Check output sizes for various compression levels, expectation
324 * is that archive size for level=7 < default < level=1
325 */
326 failure("compression-level=7 wrote %d bytes, default wrote %d bytes",
327 (int)used2, (int)used1);
328 assert(used2 < used1);
329 failure("compression-level=1 wrote %d bytes, default wrote %d bytes",
330 (int)used3, (int)used1);
331 assert(used1 < used3);
332
333 /*
334 * Test various premature shutdown scenarios to make sure we
335 * don't crash or leak memory.
336 */
337 assert((a = archive_write_new()) != NULL);
338 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
339 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
340
341 assert((a = archive_write_new()) != NULL);
342 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
343 assertEqualInt(ARCHIVE_OK, archive_write_close(a));
344 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
345
346 assert((a = archive_write_new()) != NULL);
347 assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
348 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
349 assertEqualInt(ARCHIVE_OK, archive_write_close(a));
350 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
351
352 assert((a = archive_write_new()) != NULL);
353 assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
354 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
355 assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
356 assertEqualInt(ARCHIVE_OK, archive_write_close(a));
357 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
358
359 /*
360 * Clean up.
361 */
362 free(data);
363 free(buff);
364 }
365