]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/test-compress.c
meson: check for sys/auxv.h
[thirdparty/systemd.git] / src / journal / test-compress.c
CommitLineData
843fecc0
RC
1/***
2 This file is part of systemd
3
4 Copyright 2014 Ronny Chevalier
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
e3cc7fc4
ZJS
20#ifdef HAVE_LZ4
21#include <lz4.h>
22#endif
23
b5efdb8a 24#include "alloc-util.h"
843fecc0 25#include "compress.h"
3ffd4af2 26#include "fd-util.h"
0d39fa9c 27#include "fileio.h"
843fecc0 28#include "macro.h"
3df3e884 29#include "random-util.h"
3ffd4af2 30#include "util.h"
843fecc0 31
d89c8fdf
ZJS
32#ifdef HAVE_XZ
33# define XZ_OK 0
34#else
35# define XZ_OK -EPROTONOSUPPORT
36#endif
37
92261977 38#ifdef HAVE_LZ4
d89c8fdf
ZJS
39# define LZ4_OK 0
40#else
41# define LZ4_OK -EPROTONOSUPPORT
42#endif
43
44typedef int (compress_blob_t)(const void *src, uint64_t src_size,
5d6f46b6 45 void *dst, size_t dst_alloc_size, size_t *dst_size);
d89c8fdf 46typedef int (decompress_blob_t)(const void *src, uint64_t src_size,
fa1c4b51
ZJS
47 void **dst, size_t *dst_alloc_size,
48 size_t* dst_size, size_t dst_max);
d89c8fdf 49typedef int (decompress_sw_t)(const void *src, uint64_t src_size,
fa1c4b51
ZJS
50 void **buffer, size_t *buffer_size,
51 const void *prefix, size_t prefix_len,
d89c8fdf
ZJS
52 uint8_t extra);
53
59f448cf
LP
54typedef int (compress_stream_t)(int fdf, int fdt, uint64_t max_bytes);
55typedef int (decompress_stream_t)(int fdf, int fdt, uint64_t max_size);
d89c8fdf 56
ccc717fa 57#if defined(HAVE_XZ) || defined(HAVE_LZ4)
d89c8fdf
ZJS
58static void test_compress_decompress(int compression,
59 compress_blob_t compress,
c552d602
ZJS
60 decompress_blob_t decompress,
61 const char *data,
62 size_t data_len,
63 bool may_fail) {
843fecc0 64 char compressed[512];
5d6f46b6 65 size_t csize, usize = 0;
d89c8fdf
ZJS
66 _cleanup_free_ char *decompressed = NULL;
67 int r;
68
c552d602
ZJS
69 log_info("/* testing %s %s blob compression/decompression */",
70 object_compressed_to_string(compression), data);
71
5d6f46b6 72 r = compress(data, data_len, compressed, sizeof(compressed), &csize);
c552d602 73 if (r == -ENOBUFS) {
da927ba9 74 log_info_errno(r, "compression failed: %m");
787784c4 75 assert_se(may_fail);
c552d602 76 } else {
787784c4 77 assert_se(r == 0);
c552d602
ZJS
78 r = decompress(compressed, csize,
79 (void **) &decompressed, &usize, &csize, 0);
787784c4 80 assert_se(r == 0);
c552d602
ZJS
81 assert_se(decompressed);
82 assert_se(memcmp(decompressed, data, data_len) == 0);
83 }
d89c8fdf
ZJS
84
85 r = decompress("garbage", 7,
86 (void **) &decompressed, &usize, &csize, 0);
787784c4 87 assert_se(r < 0);
d89c8fdf
ZJS
88
89 /* make sure to have the minimal lz4 compressed size */
90 r = decompress("00000000\1g", 9,
91 (void **) &decompressed, &usize, &csize, 0);
787784c4 92 assert_se(r < 0);
d89c8fdf
ZJS
93
94 r = decompress("\100000000g", 9,
95 (void **) &decompressed, &usize, &csize, 0);
787784c4 96 assert_se(r < 0);
d89c8fdf
ZJS
97
98 memzero(decompressed, usize);
843fecc0
RC
99}
100
d89c8fdf
ZJS
101static void test_decompress_startswith(int compression,
102 compress_blob_t compress,
c552d602
ZJS
103 decompress_sw_t decompress_sw,
104 const char *data,
105 size_t data_len,
106 bool may_fail) {
d89c8fdf 107
ae5e1b19
ZJS
108 char *compressed;
109 _cleanup_free_ char *compressed1 = NULL, *compressed2 = NULL, *decompressed = NULL;
110 size_t csize, usize = 0, len;
c552d602 111 int r;
d89c8fdf 112
13e785f7 113 log_info("/* testing decompress_startswith with %s on %.20s text */",
c552d602
ZJS
114 object_compressed_to_string(compression), data);
115
ae5e1b19
ZJS
116#define BUFSIZE_1 512
117#define BUFSIZE_2 20000
118
119 compressed = compressed1 = malloc(BUFSIZE_1);
120 assert_se(compressed1);
121 r = compress(data, data_len, compressed, BUFSIZE_1, &csize);
c552d602 122 if (r == -ENOBUFS) {
da927ba9 123 log_info_errno(r, "compression failed: %m");
787784c4 124 assert_se(may_fail);
ae5e1b19
ZJS
125
126 compressed = compressed2 = malloc(BUFSIZE_2);
127 assert_se(compressed2);
128 r = compress(data, data_len, compressed, BUFSIZE_2, &csize);
129 assert(r == 0);
c552d602 130 }
787784c4 131 assert_se(r == 0);
d89c8fdf 132
ae5e1b19
ZJS
133 len = strlen(data);
134
135 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len, '\0');
136 assert_se(r > 0);
137 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len, 'w');
138 assert_se(r == 0);
139 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, "barbarbar", 9, ' ');
140 assert_se(r == 0);
141 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len - 1, data[len-1]);
142 assert_se(r > 0);
143 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len - 1, 'w');
144 assert_se(r == 0);
145 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len, '\0');
146 assert_se(r > 0);
843fecc0
RC
147}
148
d89c8fdf
ZJS
149static void test_compress_stream(int compression,
150 const char* cat,
151 compress_stream_t compress,
152 decompress_stream_t decompress,
153 const char *srcfile) {
154
355b59e2 155 _cleanup_close_ int src = -1, dst = -1, dst2 = -1;
4b5bc539
ZJS
156 char pattern[] = "/tmp/systemd-test.compressed.XXXXXX",
157 pattern2[] = "/tmp/systemd-test.compressed.XXXXXX";
355b59e2 158 int r;
d89c8fdf 159 _cleanup_free_ char *cmd = NULL, *cmd2;
355b59e2
ZJS
160 struct stat st = {};
161
d89c8fdf
ZJS
162 log_debug("/* testing %s compression */",
163 object_compressed_to_string(compression));
164
355b59e2
ZJS
165 log_debug("/* create source from %s */", srcfile);
166
167 assert_se((src = open(srcfile, O_RDONLY|O_CLOEXEC)) >= 0);
168
169 log_debug("/* test compression */");
170
646853bd 171 assert_se((dst = mkostemp_safe(pattern)) >= 0);
355b59e2 172
52754725 173 assert_se(compress(src, dst, -1) == 0);
355b59e2 174
d89c8fdf
ZJS
175 if (cat) {
176 assert_se(asprintf(&cmd, "%s %s | diff %s -", cat, pattern, srcfile) > 0);
52754725 177 assert_se(system(cmd) == 0);
d89c8fdf 178 }
355b59e2
ZJS
179
180 log_debug("/* test decompression */");
181
646853bd 182 assert_se((dst2 = mkostemp_safe(pattern2)) >= 0);
355b59e2
ZJS
183
184 assert_se(stat(srcfile, &st) == 0);
185
186 assert_se(lseek(dst, 0, SEEK_SET) == 0);
d89c8fdf 187 r = decompress(dst, dst2, st.st_size);
0c0cdb06 188 assert_se(r == 0);
355b59e2
ZJS
189
190 assert_se(asprintf(&cmd2, "diff %s %s", srcfile, pattern2) > 0);
191 assert_se(system(cmd2) == 0);
192
193 log_debug("/* test faulty decompression */");
194
195 assert_se(lseek(dst, 1, SEEK_SET) == 1);
d89c8fdf 196 r = decompress(dst, dst2, st.st_size);
4b5bc539 197 assert_se(r == -EBADMSG || r == 0);
355b59e2
ZJS
198
199 assert_se(lseek(dst, 0, SEEK_SET) == 0);
200 assert_se(lseek(dst2, 0, SEEK_SET) == 0);
d89c8fdf 201 r = decompress(dst, dst2, st.st_size - 1);
0c0cdb06 202 assert_se(r == -EFBIG);
355b59e2
ZJS
203
204 assert_se(unlink(pattern) == 0);
205 assert_se(unlink(pattern2) == 0);
206}
ccc717fa 207#endif
355b59e2 208
e3cc7fc4
ZJS
209#ifdef HAVE_LZ4
210static void test_lz4_decompress_partial(void) {
211 char buf[20000];
212 size_t buf_size = sizeof(buf), compressed;
213 int r;
ae5e1b19 214 _cleanup_free_ char *huge = NULL;
e3cc7fc4 215
ae5e1b19
ZJS
216#define HUGE_SIZE (4096*1024)
217 huge = malloc(HUGE_SIZE);
218 memset(huge, 'x', HUGE_SIZE);
e3cc7fc4
ZJS
219 memcpy(huge, "HUGE=", 5);
220
777fe71f
ZJS
221#if LZ4_VERSION_NUMBER >= 10700
222 r = LZ4_compress_default(huge, buf, HUGE_SIZE, buf_size);
223#else
ae5e1b19 224 r = LZ4_compress_limitedOutput(huge, buf, HUGE_SIZE, buf_size);
777fe71f 225#endif
e3cc7fc4
ZJS
226 assert_se(r >= 0);
227 compressed = r;
ae5e1b19 228 log_info("Compressed %i → %zu", HUGE_SIZE, compressed);
e3cc7fc4 229
ae5e1b19 230 r = LZ4_decompress_safe(buf, huge, r, HUGE_SIZE);
e3cc7fc4
ZJS
231 assert_se(r >= 0);
232 log_info("Decompressed → %i", r);
233
234 r = LZ4_decompress_safe_partial(buf, huge,
235 compressed,
ae5e1b19 236 12, HUGE_SIZE);
e3cc7fc4 237 assert_se(r >= 0);
ae5e1b19 238 log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE, r);
e3cc7fc4
ZJS
239
240 /* We expect this to fail, because that's how current lz4 works. If this
241 * call succeeds, then lz4 has been fixed, and we need to change our code.
242 */
243 r = LZ4_decompress_safe_partial(buf, huge,
244 compressed,
ae5e1b19 245 12, HUGE_SIZE-1);
e3cc7fc4 246 assert_se(r < 0);
ae5e1b19 247 log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE-1, r);
e3cc7fc4
ZJS
248}
249#endif
250
843fecc0 251int main(int argc, char *argv[]) {
ccc717fa 252#if defined(HAVE_XZ) || defined(HAVE_LZ4)
c552d602
ZJS
253 const char text[] =
254 "text\0foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"
255 "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF";
256
3e216115
ZJS
257 /* The file to test compression on can be specified as the first argument */
258 const char *srcfile = argc > 1 ? argv[1] : argv[0];
259
c552d602 260 char data[512] = "random\0";
355b59e2 261
ae5e1b19
ZJS
262 char huge[4096*1024];
263 memset(huge, 'x', sizeof(huge));
264 memcpy(huge, "HUGE=", 5);
265 char_array_0(huge);
266
355b59e2
ZJS
267 log_set_max_level(LOG_DEBUG);
268
c552d602
ZJS
269 random_bytes(data + 7, sizeof(data) - 7);
270
d89c8fdf 271#ifdef HAVE_XZ
c552d602
ZJS
272 test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
273 text, sizeof(text), false);
274 test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
275 data, sizeof(data), true);
ae5e1b19 276
c552d602
ZJS
277 test_decompress_startswith(OBJECT_COMPRESSED_XZ,
278 compress_blob_xz, decompress_startswith_xz,
279 text, sizeof(text), false);
280 test_decompress_startswith(OBJECT_COMPRESSED_XZ,
281 compress_blob_xz, decompress_startswith_xz,
282 data, sizeof(data), true);
ae5e1b19
ZJS
283 test_decompress_startswith(OBJECT_COMPRESSED_XZ,
284 compress_blob_xz, decompress_startswith_xz,
285 huge, sizeof(huge), true);
286
d89c8fdf 287 test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat",
3e216115 288 compress_stream_xz, decompress_stream_xz, srcfile);
d89c8fdf
ZJS
289#else
290 log_info("/* XZ test skipped */");
291#endif
c552d602 292
d89c8fdf 293#ifdef HAVE_LZ4
c552d602
ZJS
294 test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
295 text, sizeof(text), false);
296 test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
297 data, sizeof(data), true);
ae5e1b19 298
c552d602
ZJS
299 test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
300 compress_blob_lz4, decompress_startswith_lz4,
301 text, sizeof(text), false);
302 test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
303 compress_blob_lz4, decompress_startswith_lz4,
304 data, sizeof(data), true);
ae5e1b19
ZJS
305 test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
306 compress_blob_lz4, decompress_startswith_lz4,
307 huge, sizeof(huge), true);
d89c8fdf 308
4b5bc539 309 test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat",
3e216115 310 compress_stream_lz4, decompress_stream_lz4, srcfile);
e3cc7fc4
ZJS
311
312 test_lz4_decompress_partial();
d89c8fdf
ZJS
313#else
314 log_info("/* LZ4 test skipped */");
315#endif
843fecc0
RC
316
317 return 0;
ccc717fa
ZJS
318#else
319 return EXIT_TEST_SKIP;
320#endif
843fecc0 321}