]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/test-compress.c
man: fix typos (#4527)
[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
ZJS
56
57static void test_compress_decompress(int compression,
58 compress_blob_t compress,
c552d602
ZJS
59 decompress_blob_t decompress,
60 const char *data,
61 size_t data_len,
62 bool may_fail) {
843fecc0 63 char compressed[512];
5d6f46b6 64 size_t csize, usize = 0;
d89c8fdf
ZJS
65 _cleanup_free_ char *decompressed = NULL;
66 int r;
67
c552d602
ZJS
68 log_info("/* testing %s %s blob compression/decompression */",
69 object_compressed_to_string(compression), data);
70
5d6f46b6 71 r = compress(data, data_len, compressed, sizeof(compressed), &csize);
c552d602 72 if (r == -ENOBUFS) {
da927ba9 73 log_info_errno(r, "compression failed: %m");
787784c4 74 assert_se(may_fail);
c552d602 75 } else {
787784c4 76 assert_se(r == 0);
c552d602
ZJS
77 r = decompress(compressed, csize,
78 (void **) &decompressed, &usize, &csize, 0);
787784c4 79 assert_se(r == 0);
c552d602
ZJS
80 assert_se(decompressed);
81 assert_se(memcmp(decompressed, data, data_len) == 0);
82 }
d89c8fdf
ZJS
83
84 r = decompress("garbage", 7,
85 (void **) &decompressed, &usize, &csize, 0);
787784c4 86 assert_se(r < 0);
d89c8fdf
ZJS
87
88 /* make sure to have the minimal lz4 compressed size */
89 r = decompress("00000000\1g", 9,
90 (void **) &decompressed, &usize, &csize, 0);
787784c4 91 assert_se(r < 0);
d89c8fdf
ZJS
92
93 r = decompress("\100000000g", 9,
94 (void **) &decompressed, &usize, &csize, 0);
787784c4 95 assert_se(r < 0);
d89c8fdf
ZJS
96
97 memzero(decompressed, usize);
843fecc0
RC
98}
99
d89c8fdf
ZJS
100static void test_decompress_startswith(int compression,
101 compress_blob_t compress,
c552d602
ZJS
102 decompress_sw_t decompress_sw,
103 const char *data,
104 size_t data_len,
105 bool may_fail) {
d89c8fdf 106
ae5e1b19
ZJS
107 char *compressed;
108 _cleanup_free_ char *compressed1 = NULL, *compressed2 = NULL, *decompressed = NULL;
109 size_t csize, usize = 0, len;
c552d602 110 int r;
d89c8fdf 111
ae5e1b19 112 log_info("/* testing decompress_startswith with %s on %.20s text*/",
c552d602
ZJS
113 object_compressed_to_string(compression), data);
114
ae5e1b19
ZJS
115#define BUFSIZE_1 512
116#define BUFSIZE_2 20000
117
118 compressed = compressed1 = malloc(BUFSIZE_1);
119 assert_se(compressed1);
120 r = compress(data, data_len, compressed, BUFSIZE_1, &csize);
c552d602 121 if (r == -ENOBUFS) {
da927ba9 122 log_info_errno(r, "compression failed: %m");
787784c4 123 assert_se(may_fail);
ae5e1b19
ZJS
124
125 compressed = compressed2 = malloc(BUFSIZE_2);
126 assert_se(compressed2);
127 r = compress(data, data_len, compressed, BUFSIZE_2, &csize);
128 assert(r == 0);
c552d602 129 }
787784c4 130 assert_se(r == 0);
d89c8fdf 131
ae5e1b19
ZJS
132 len = strlen(data);
133
134 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len, '\0');
135 assert_se(r > 0);
136 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len, 'w');
137 assert_se(r == 0);
138 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, "barbarbar", 9, ' ');
139 assert_se(r == 0);
140 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len - 1, data[len-1]);
141 assert_se(r > 0);
142 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len - 1, 'w');
143 assert_se(r == 0);
144 r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len, '\0');
145 assert_se(r > 0);
843fecc0
RC
146}
147
d89c8fdf
ZJS
148static void test_compress_stream(int compression,
149 const char* cat,
150 compress_stream_t compress,
151 decompress_stream_t decompress,
152 const char *srcfile) {
153
355b59e2 154 _cleanup_close_ int src = -1, dst = -1, dst2 = -1;
4b5bc539
ZJS
155 char pattern[] = "/tmp/systemd-test.compressed.XXXXXX",
156 pattern2[] = "/tmp/systemd-test.compressed.XXXXXX";
355b59e2 157 int r;
d89c8fdf 158 _cleanup_free_ char *cmd = NULL, *cmd2;
355b59e2
ZJS
159 struct stat st = {};
160
d89c8fdf
ZJS
161 log_debug("/* testing %s compression */",
162 object_compressed_to_string(compression));
163
355b59e2
ZJS
164 log_debug("/* create source from %s */", srcfile);
165
166 assert_se((src = open(srcfile, O_RDONLY|O_CLOEXEC)) >= 0);
167
168 log_debug("/* test compression */");
169
646853bd 170 assert_se((dst = mkostemp_safe(pattern)) >= 0);
355b59e2 171
52754725 172 assert_se(compress(src, dst, -1) == 0);
355b59e2 173
d89c8fdf
ZJS
174 if (cat) {
175 assert_se(asprintf(&cmd, "%s %s | diff %s -", cat, pattern, srcfile) > 0);
52754725 176 assert_se(system(cmd) == 0);
d89c8fdf 177 }
355b59e2
ZJS
178
179 log_debug("/* test decompression */");
180
646853bd 181 assert_se((dst2 = mkostemp_safe(pattern2)) >= 0);
355b59e2
ZJS
182
183 assert_se(stat(srcfile, &st) == 0);
184
185 assert_se(lseek(dst, 0, SEEK_SET) == 0);
d89c8fdf 186 r = decompress(dst, dst2, st.st_size);
0c0cdb06 187 assert_se(r == 0);
355b59e2
ZJS
188
189 assert_se(asprintf(&cmd2, "diff %s %s", srcfile, pattern2) > 0);
190 assert_se(system(cmd2) == 0);
191
192 log_debug("/* test faulty decompression */");
193
194 assert_se(lseek(dst, 1, SEEK_SET) == 1);
d89c8fdf 195 r = decompress(dst, dst2, st.st_size);
4b5bc539 196 assert_se(r == -EBADMSG || r == 0);
355b59e2
ZJS
197
198 assert_se(lseek(dst, 0, SEEK_SET) == 0);
199 assert_se(lseek(dst2, 0, SEEK_SET) == 0);
d89c8fdf 200 r = decompress(dst, dst2, st.st_size - 1);
0c0cdb06 201 assert_se(r == -EFBIG);
355b59e2
ZJS
202
203 assert_se(unlink(pattern) == 0);
204 assert_se(unlink(pattern2) == 0);
205}
206
e3cc7fc4
ZJS
207#ifdef HAVE_LZ4
208static void test_lz4_decompress_partial(void) {
209 char buf[20000];
210 size_t buf_size = sizeof(buf), compressed;
211 int r;
ae5e1b19 212 _cleanup_free_ char *huge = NULL;
e3cc7fc4 213
ae5e1b19
ZJS
214#define HUGE_SIZE (4096*1024)
215 huge = malloc(HUGE_SIZE);
216 memset(huge, 'x', HUGE_SIZE);
e3cc7fc4
ZJS
217 memcpy(huge, "HUGE=", 5);
218
ae5e1b19 219 r = LZ4_compress_limitedOutput(huge, buf, HUGE_SIZE, buf_size);
e3cc7fc4
ZJS
220 assert_se(r >= 0);
221 compressed = r;
ae5e1b19 222 log_info("Compressed %i → %zu", HUGE_SIZE, compressed);
e3cc7fc4 223
ae5e1b19 224 r = LZ4_decompress_safe(buf, huge, r, HUGE_SIZE);
e3cc7fc4
ZJS
225 assert_se(r >= 0);
226 log_info("Decompressed → %i", r);
227
228 r = LZ4_decompress_safe_partial(buf, huge,
229 compressed,
ae5e1b19 230 12, HUGE_SIZE);
e3cc7fc4 231 assert_se(r >= 0);
ae5e1b19 232 log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE, r);
e3cc7fc4
ZJS
233
234 /* We expect this to fail, because that's how current lz4 works. If this
235 * call succeeds, then lz4 has been fixed, and we need to change our code.
236 */
237 r = LZ4_decompress_safe_partial(buf, huge,
238 compressed,
ae5e1b19 239 12, HUGE_SIZE-1);
e3cc7fc4 240 assert_se(r < 0);
ae5e1b19 241 log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE-1, r);
e3cc7fc4
ZJS
242}
243#endif
244
843fecc0 245int main(int argc, char *argv[]) {
c552d602
ZJS
246 const char text[] =
247 "text\0foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"
248 "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF";
249
250 char data[512] = "random\0";
355b59e2 251
ae5e1b19
ZJS
252 char huge[4096*1024];
253 memset(huge, 'x', sizeof(huge));
254 memcpy(huge, "HUGE=", 5);
255 char_array_0(huge);
256
355b59e2
ZJS
257 log_set_max_level(LOG_DEBUG);
258
c552d602
ZJS
259 random_bytes(data + 7, sizeof(data) - 7);
260
d89c8fdf 261#ifdef HAVE_XZ
c552d602
ZJS
262 test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
263 text, sizeof(text), false);
264 test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
265 data, sizeof(data), true);
ae5e1b19 266
c552d602
ZJS
267 test_decompress_startswith(OBJECT_COMPRESSED_XZ,
268 compress_blob_xz, decompress_startswith_xz,
269 text, sizeof(text), false);
270 test_decompress_startswith(OBJECT_COMPRESSED_XZ,
271 compress_blob_xz, decompress_startswith_xz,
272 data, sizeof(data), true);
ae5e1b19
ZJS
273 test_decompress_startswith(OBJECT_COMPRESSED_XZ,
274 compress_blob_xz, decompress_startswith_xz,
275 huge, sizeof(huge), true);
276
d89c8fdf
ZJS
277 test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat",
278 compress_stream_xz, decompress_stream_xz, argv[0]);
279#else
280 log_info("/* XZ test skipped */");
281#endif
c552d602 282
d89c8fdf 283#ifdef HAVE_LZ4
c552d602
ZJS
284 test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
285 text, sizeof(text), false);
286 test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
287 data, sizeof(data), true);
ae5e1b19 288
c552d602
ZJS
289 test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
290 compress_blob_lz4, decompress_startswith_lz4,
291 text, sizeof(text), false);
292 test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
293 compress_blob_lz4, decompress_startswith_lz4,
294 data, sizeof(data), true);
ae5e1b19
ZJS
295 test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
296 compress_blob_lz4, decompress_startswith_lz4,
297 huge, sizeof(huge), true);
d89c8fdf 298
4b5bc539 299 test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat",
d89c8fdf 300 compress_stream_lz4, decompress_stream_lz4, argv[0]);
e3cc7fc4
ZJS
301
302 test_lz4_decompress_partial();
d89c8fdf
ZJS
303#else
304 log_info("/* LZ4 test skipped */");
305#endif
843fecc0
RC
306
307 return 0;
308}