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 = (char *)malloc(buffsize)));
41 if (buff == NULL)
42 return;
43
44 datasize = 10000;
45 assert(NULL != (data = (char *)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 if ((int)(sizeof(size_t) == 4))
234 assertEqualIntA(a, ARCHIVE_OK,
235 archive_write_set_filter_option(a, NULL, "long", "26"));
236 else
237 assertEqualIntA(a, ARCHIVE_OK,
238 archive_write_set_filter_option(a, NULL, "long", "27"));
239 assertEqualIntA(a, ARCHIVE_FAILED,
240 archive_write_set_filter_option(a, NULL, "long", "-1")); /* negative */
241 #endif
242 assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
243 for (i = 0; i < 100; i++) {
244 snprintf(path, sizeof(path), "file%03d", i);
245 assert((ae = archive_entry_new()) != NULL);
246 archive_entry_copy_pathname(ae, path);
247 archive_entry_set_size(ae, datasize);
248 archive_entry_set_filetype(ae, AE_IFREG);
249 assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
250 assertA(datasize == (size_t)archive_write_data(a, data, datasize));
251 archive_entry_free(ae);
252 }
253 assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
254 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
255
256 assert((a = archive_read_new()) != NULL);
257 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
258 r = archive_read_support_filter_zstd(a);
259 if (r == ARCHIVE_WARN) {
260 skipping("zstd reading not fully supported on this platform");
261 } else {
262 assertEqualIntA(a, ARCHIVE_OK,
263 archive_read_support_filter_all(a));
264 assertEqualIntA(a, ARCHIVE_OK,
265 archive_read_open_memory(a, buff, used2));
266 for (i = 0; i < 100; i++) {
267 snprintf(path, sizeof(path), "file%03d", i);
268 failure("Trying to read %s", path);
269 if (!assertEqualIntA(a, ARCHIVE_OK,
270 archive_read_next_header(a, &ae)))
271 break;
272 assertEqualString(path, archive_entry_pathname(ae));
273 assertEqualInt((int)datasize, archive_entry_size(ae));
274 }
275 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
276 }
277 assertEqualInt(ARCHIVE_OK, archive_read_free(a));
278
279 /*
280 * One more time at level 1
281 */
282 assert((a = archive_write_new()) != NULL);
283 assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
284 assertEqualIntA(a, ARCHIVE_OK,
285 archive_write_set_bytes_per_block(a, 10));
286 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
287 assertEqualIntA(a, ARCHIVE_OK,
288 archive_write_set_filter_option(a, NULL, "compression-level", "1"));
289 assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used3));
290 assert((ae = archive_entry_new()) != NULL);
291 archive_entry_set_filetype(ae, AE_IFREG);
292 archive_entry_set_size(ae, datasize);
293 for (i = 0; i < 100; i++) {
294 snprintf(path, sizeof(path), "file%03d", i);
295 archive_entry_copy_pathname(ae, path);
296 assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
297 assertA(datasize == (size_t)archive_write_data(a, data, datasize));
298 }
299 archive_entry_free(ae);
300 assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
301 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
302
303 assert((a = archive_read_new()) != NULL);
304 assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
305 r = archive_read_support_filter_zstd(a);
306 if (r == ARCHIVE_WARN) {
307 skipping("zstd reading not fully supported on this platform");
308 } else {
309 assertEqualIntA(a, ARCHIVE_OK,
310 archive_read_support_filter_all(a));
311 assertEqualIntA(a, ARCHIVE_OK,
312 archive_read_open_memory(a, buff, used3));
313 for (i = 0; i < 100; i++) {
314 snprintf(path, sizeof(path), "file%03d", i);
315 failure("Trying to read %s", path);
316 if (!assertEqualIntA(a, ARCHIVE_OK,
317 archive_read_next_header(a, &ae)))
318 break;
319 assertEqualString(path, archive_entry_pathname(ae));
320 assertEqualInt((int)datasize, archive_entry_size(ae));
321 }
322 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
323 }
324 assertEqualInt(ARCHIVE_OK, archive_read_free(a));
325
326 /*
327 * Check output sizes for various compression levels, expectation
328 * is that archive size for level=7 < default < level=1
329 */
330 failure("compression-level=7 wrote %d bytes, default wrote %d bytes",
331 (int)used2, (int)used1);
332 assert(used2 < used1);
333 failure("compression-level=1 wrote %d bytes, default wrote %d bytes",
334 (int)used3, (int)used1);
335 assert(used1 < used3);
336
337 /*
338 * Test various premature shutdown scenarios to make sure we
339 * don't crash or leak memory.
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_free(a));
344
345 assert((a = archive_write_new()) != NULL);
346 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
347 assertEqualInt(ARCHIVE_OK, archive_write_close(a));
348 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
349
350 assert((a = archive_write_new()) != NULL);
351 assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
352 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
353 assertEqualInt(ARCHIVE_OK, archive_write_close(a));
354 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
355
356 assert((a = archive_write_new()) != NULL);
357 assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
358 assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_zstd(a));
359 assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
360 assertEqualInt(ARCHIVE_OK, archive_write_close(a));
361 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
362
363 /*
364 * Clean up.
365 */
366 free(data);
367 free(buff);
368 }
369