chiark / gitweb /
sd-network: rename "index" parameter to "ifindex"
[elogind.git] / src / journal / test-compress.c
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
20 #include "compress.h"
21 #include "util.h"
22 #include "macro.h"
23
24 #ifdef HAVE_XZ
25 # define XZ_OK 0
26 #else
27 # define XZ_OK -EPROTONOSUPPORT
28 #endif
29
30 #ifdef HAVE_LZ4
31 # define LZ4_OK 0
32 #else
33 # define LZ4_OK -EPROTONOSUPPORT
34 #endif
35
36 typedef int (compress_blob_t)(const void *src, uint64_t src_size,
37                               void *dst, uint64_t *dst_size);
38 typedef int (decompress_blob_t)(const void *src, uint64_t src_size,
39                                 void **dst, uint64_t *dst_alloc_size,
40                                 uint64_t* dst_size, uint64_t dst_max);
41
42 typedef int (decompress_sw_t)(const void *src, uint64_t src_size,
43                               void **buffer, uint64_t *buffer_size,
44                               const void *prefix, uint64_t prefix_len,
45                               uint8_t extra);
46
47 typedef int (compress_stream_t)(int fdf, int fdt, off_t max_bytes);
48 typedef int (decompress_stream_t)(int fdf, int fdt, off_t max_size);
49
50 static void test_compress_decompress(int compression,
51                                      compress_blob_t compress,
52                                      decompress_blob_t decompress) {
53         char text[] = "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"
54                       "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF";
55         char compressed[512];
56         uint64_t csize = 512;
57         uint64_t usize = 0;
58         _cleanup_free_ char *decompressed = NULL;
59         int r;
60
61         log_info("/* testing %s blob compression/decompression */",
62                  object_compressed_to_string(compression));
63
64         r = compress(text, sizeof(text), compressed, &csize);
65         assert(r == 0);
66         r = decompress(compressed, csize,
67                        (void **) &decompressed, &usize, &csize, 0);
68         assert(r == 0);
69         assert_se(decompressed);
70         assert_se(streq(decompressed, text));
71
72         r = decompress("garbage", 7,
73                        (void **) &decompressed, &usize, &csize, 0);
74         assert(r < 0);
75
76         /* make sure to have the minimal lz4 compressed size */
77         r = decompress("00000000\1g", 9,
78                        (void **) &decompressed, &usize, &csize, 0);
79         assert(r < 0);
80
81         r = decompress("\100000000g", 9,
82                        (void **) &decompressed, &usize, &csize, 0);
83         assert(r < 0);
84
85         memzero(decompressed, usize);
86 }
87
88 static void test_decompress_startswith(int compression,
89                                        compress_blob_t compress,
90                                        decompress_sw_t decompress_sw) {
91
92         char text[] = "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"
93                       "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF";
94         char compressed[512];
95         uint64_t csize = 512;
96         uint64_t usize = 0;
97         _cleanup_free_ char *decompressed = NULL;
98
99         log_info("/* testing decompress_startswith with %s */",
100                  object_compressed_to_string(compression));
101
102         assert_se(compress(text, sizeof(text), compressed, &csize) == 0);
103         assert_se(decompress_sw(compressed,
104                                 csize,
105                                 (void **) &decompressed,
106                                 &usize,
107                                 "foofoofoofoo", 12, ' ') > 0);
108         assert_se(decompress_sw(compressed,
109                                 csize,
110                                 (void **) &decompressed,
111                                 &usize,
112                                 "foofoofoofoo", 12, 'w') == 0);
113         assert_se(decompress_sw(compressed,
114                                 csize,
115                                 (void **) &decompressed,
116                                 &usize,
117                                 "barbarbar", 9, ' ') == 0);
118         assert_se(decompress_sw(compressed,
119                                 csize,
120                                 (void **) &decompressed,
121                                 &usize,
122                                 "foofoofoofoo", 12, ' ') > 0);
123 }
124
125 static void test_compress_stream(int compression,
126                                  const char* cat,
127                                  compress_stream_t compress,
128                                  decompress_stream_t decompress,
129                                  const char *srcfile) {
130
131         _cleanup_close_ int src = -1, dst = -1, dst2 = -1;
132         char pattern[] = "/tmp/systemd-test.xz.XXXXXX",
133              pattern2[] = "/tmp/systemd-test.xz.XXXXXX";
134         int r;
135         _cleanup_free_ char *cmd = NULL, *cmd2;
136         struct stat st = {};
137
138         log_debug("/* testing %s compression */",
139                   object_compressed_to_string(compression));
140
141         log_debug("/* create source from %s */", srcfile);
142
143         assert_se((src = open(srcfile, O_RDONLY|O_CLOEXEC)) >= 0);
144
145         log_debug("/* test compression */");
146
147         assert_se((dst = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC)) >= 0);
148
149         assert(compress(src, dst, -1) == 0);
150
151         if (cat) {
152                 assert_se(asprintf(&cmd, "%s %s | diff %s -", cat, pattern, srcfile) > 0);
153                 assert(system(cmd) == 0);
154         }
155
156         log_debug("/* test decompression */");
157
158         assert_se((dst2 = mkostemp_safe(pattern2, O_RDWR|O_CLOEXEC)) >= 0);
159
160         assert_se(stat(srcfile, &st) == 0);
161
162         assert_se(lseek(dst, 0, SEEK_SET) == 0);
163         r = decompress(dst, dst2, st.st_size);
164         assert(r == 0);
165
166         assert_se(asprintf(&cmd2, "diff %s %s", srcfile, pattern2) > 0);
167         assert_se(system(cmd2) == 0);
168
169         log_debug("/* test faulty decompression */");
170
171         assert_se(lseek(dst, 1, SEEK_SET) == 1);
172         r = decompress(dst, dst2, st.st_size);
173         assert(r == -EBADMSG);
174
175         assert_se(lseek(dst, 0, SEEK_SET) == 0);
176         assert_se(lseek(dst2, 0, SEEK_SET) == 0);
177         r = decompress(dst, dst2, st.st_size - 1);
178         assert(r == -EFBIG);
179
180         assert_se(unlink(pattern) == 0);
181         assert_se(unlink(pattern2) == 0);
182 }
183
184 int main(int argc, char *argv[]) {
185
186         log_set_max_level(LOG_DEBUG);
187
188 #ifdef HAVE_XZ
189         test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz);
190         test_decompress_startswith(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_startswith_xz);
191         test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat",
192                              compress_stream_xz, decompress_stream_xz, argv[0]);
193 #else
194         log_info("/* XZ test skipped */");
195 #endif
196 #ifdef HAVE_LZ4
197         test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4);
198         test_decompress_startswith(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_startswith_lz4);
199
200         /* Produced stream is not compatible with lz4 binary, skip lz4cat check. */
201         test_compress_stream(OBJECT_COMPRESSED_LZ4, NULL,
202                              compress_stream_lz4, decompress_stream_lz4, argv[0]);
203 #else
204         log_info("/* LZ4 test skipped */");
205 #endif
206
207         return 0;
208 }