1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
32 bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_size) {
41 /* Returns false if we couldn't compress the data or the
42 * compressed result is longer than the original */
44 ret = lzma_easy_buffer_encode(LZMA_PRESET_DEFAULT, LZMA_CHECK_NONE, NULL,
45 src, src_size, dst, &out_pos, src_size);
49 /* Is it actually shorter? */
50 if (out_pos == src_size)
57 bool uncompress_blob(const void *src, uint64_t src_size,
58 void **dst, uint64_t *dst_alloc_size, uint64_t* dst_size, uint64_t dst_max) {
60 lzma_stream s = LZMA_STREAM_INIT;
68 assert(dst_alloc_size);
70 assert(*dst_alloc_size == 0 || *dst);
72 ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
76 if (*dst_alloc_size <= src_size) {
79 p = realloc(*dst, src_size*2);
84 *dst_alloc_size = src_size*2;
88 s.avail_in = src_size;
91 space = dst_max > 0 ? MIN(*dst_alloc_size, dst_max) : *dst_alloc_size;
97 ret = lzma_code(&s, LZMA_FINISH);
99 if (ret == LZMA_STREAM_END)
105 if (dst_max > 0 && (space - s.avail_out) >= dst_max)
108 p = realloc(*dst, space*2);
112 s.next_out = (uint8_t*) p + ((uint8_t*) s.next_out - (uint8_t*) *dst);
113 s.avail_out += space;
118 *dst_alloc_size = space;
121 *dst_size = space - s.avail_out;
130 bool uncompress_startswith(const void *src, uint64_t src_size,
131 void **buffer, uint64_t *buffer_size,
132 const void *prefix, uint64_t prefix_len,
135 lzma_stream s = LZMA_STREAM_INIT;
139 /* Checks whether the uncompressed blob starts with the
140 * mentioned prefix. The byte extra needs to follow the
144 assert(src_size > 0);
148 assert(*buffer_size == 0 || *buffer);
150 ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
154 if (*buffer_size <= prefix_len) {
157 p = realloc(*buffer, prefix_len*2);
162 *buffer_size = prefix_len*2;
166 s.avail_in = src_size;
168 s.next_out = *buffer;
169 s.avail_out = *buffer_size;
174 ret = lzma_code(&s, LZMA_FINISH);
176 if (ret != LZMA_STREAM_END && ret != LZMA_OK)
179 if ((*buffer_size - s.avail_out > prefix_len) &&
180 memcmp(*buffer, prefix, prefix_len) == 0 &&
181 ((const uint8_t*) *buffer)[prefix_len] == extra)
184 if (ret == LZMA_STREAM_END)
187 p = realloc(*buffer, *buffer_size*2);
191 s.next_out = (uint8_t*) p + ((uint8_t*) s.next_out - (uint8_t*) *buffer);
192 s.avail_out += *buffer_size;
206 int compress_stream(int fdf, int fdt, uint32_t preset, off_t max_bytes) {
207 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
210 uint8_t buf[BUFSIZ], out[BUFSIZ];
211 lzma_action action = LZMA_RUN;
216 ret = lzma_easy_encoder(&s, preset, LZMA_CHECK_CRC64);
217 if (ret != LZMA_OK) {
218 log_error("Failed to initialize XZ encoder: code %d", ret);
223 if (s.avail_in == 0 && action == LZMA_RUN) {
224 size_t m = sizeof(buf);
227 if (max_bytes != -1 && m > (size_t) max_bytes)
230 n = read(fdf, buf, m);
234 action = LZMA_FINISH;
239 if (max_bytes != -1) {
240 assert(max_bytes >= n);
246 if (s.avail_out == 0) {
248 s.avail_out = sizeof(out);
251 ret = lzma_code(&s, action);
252 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
253 log_error("Compression failed: code %d", ret);
257 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
260 n = sizeof(out) - s.avail_out;
263 k = loop_write(fdt, out, n, false);
267 return errno ? -errno : -EIO;
269 if (ret == LZMA_STREAM_END) {
270 log_debug("Compression finished (%zu -> %zu bytes, %.1f%%)",
271 s.total_in, s.total_out,
272 (double) s.total_out / s.total_in * 100);
280 int decompress_stream(int fdf, int fdt, off_t max_bytes) {
281 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
284 uint8_t buf[BUFSIZ], out[BUFSIZ];
285 lzma_action action = LZMA_RUN;
290 ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
291 if (ret != LZMA_OK) {
292 log_error("Failed to initialize XZ decoder: code %d", ret);
297 if (s.avail_in == 0 && action == LZMA_RUN) {
300 n = read(fdf, buf, sizeof(buf));
304 action = LZMA_FINISH;
311 if (s.avail_out == 0) {
313 s.avail_out = sizeof(out);
316 ret = lzma_code(&s, action);
317 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
318 log_error("Decompression failed: code %d", ret);
322 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
325 n = sizeof(out) - s.avail_out;
327 if (max_bytes != -1) {
335 k = loop_write(fdt, out, n, false);
339 return errno ? -errno : -EIO;
341 if (ret == LZMA_STREAM_END) {
342 log_debug("Decompression finished (%zu -> %zu bytes, %.1f%%)",
343 s.total_in, s.total_out,
344 (double) s.total_out / s.total_in * 100);