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 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
67 assert(dst_alloc_size);
69 assert(*dst_alloc_size == 0 || *dst);
71 ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
75 space = MIN(src_size * 2, dst_max ?: (uint64_t) -1);
76 if (!greedy_realloc(dst, dst_alloc_size, space, 1))
80 s.avail_in = src_size;
88 ret = lzma_code(&s, LZMA_FINISH);
90 if (ret == LZMA_STREAM_END)
96 if (dst_max > 0 && (space - s.avail_out) >= dst_max)
99 if (dst_max > 0 && space == dst_max)
102 used = space - s.avail_out;
103 space = MIN(2 * space, dst_max ?: (uint64_t) -1);
104 if (!greedy_realloc(dst, dst_alloc_size, space, 1))
107 s.avail_out = space - used;
108 s.next_out = *dst + used;
111 *dst_size = space - s.avail_out;
115 bool uncompress_startswith(const void *src, uint64_t src_size,
116 void **buffer, uint64_t *buffer_size,
117 const void *prefix, uint64_t prefix_len,
120 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
123 /* Checks whether the uncompressed blob starts with the
124 * mentioned prefix. The byte extra needs to follow the
128 assert(src_size > 0);
132 assert(*buffer_size == 0 || *buffer);
134 ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
138 if (!(greedy_realloc(buffer, buffer_size, prefix_len + 1, 1)))
142 s.avail_in = src_size;
144 s.next_out = *buffer;
145 s.avail_out = *buffer_size;
148 ret = lzma_code(&s, LZMA_FINISH);
150 if (ret != LZMA_STREAM_END && ret != LZMA_OK)
153 if (*buffer_size - s.avail_out >= prefix_len + 1)
154 return memcmp(*buffer, prefix, prefix_len) == 0 &&
155 ((const uint8_t*) *buffer)[prefix_len] == extra;
157 if (ret == LZMA_STREAM_END)
160 s.avail_out += *buffer_size;
162 if (!(greedy_realloc(buffer, buffer_size, *buffer_size * 2, 1)))
165 s.next_out = *buffer + *buffer_size - s.avail_out;
169 int compress_stream(int fdf, int fdt, uint32_t preset, off_t max_bytes) {
170 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
173 uint8_t buf[BUFSIZ], out[BUFSIZ];
174 lzma_action action = LZMA_RUN;
179 ret = lzma_easy_encoder(&s, preset, LZMA_CHECK_CRC64);
180 if (ret != LZMA_OK) {
181 log_error("Failed to initialize XZ encoder: code %d", ret);
186 if (s.avail_in == 0 && action == LZMA_RUN) {
187 size_t m = sizeof(buf);
190 if (max_bytes != -1 && m > (size_t) max_bytes)
193 n = read(fdf, buf, m);
197 action = LZMA_FINISH;
202 if (max_bytes != -1) {
203 assert(max_bytes >= n);
209 if (s.avail_out == 0) {
211 s.avail_out = sizeof(out);
214 ret = lzma_code(&s, action);
215 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
216 log_error("Compression failed: code %d", ret);
220 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
223 n = sizeof(out) - s.avail_out;
226 k = loop_write(fdt, out, n, false);
230 return errno ? -errno : -EIO;
232 if (ret == LZMA_STREAM_END) {
233 log_debug("Compression finished (%zu -> %zu bytes, %.1f%%)",
234 s.total_in, s.total_out,
235 (double) s.total_out / s.total_in * 100);
243 int decompress_stream(int fdf, int fdt, off_t max_bytes) {
244 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
247 uint8_t buf[BUFSIZ], out[BUFSIZ];
248 lzma_action action = LZMA_RUN;
253 ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
254 if (ret != LZMA_OK) {
255 log_error("Failed to initialize XZ decoder: code %d", ret);
260 if (s.avail_in == 0 && action == LZMA_RUN) {
263 n = read(fdf, buf, sizeof(buf));
267 action = LZMA_FINISH;
274 if (s.avail_out == 0) {
276 s.avail_out = sizeof(out);
279 ret = lzma_code(&s, action);
280 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
281 log_error("Decompression failed: code %d", ret);
285 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
288 n = sizeof(out) - s.avail_out;
290 if (max_bytes != -1) {
298 k = loop_write(fdt, out, n, false);
302 return errno ? -errno : -EIO;
304 if (ret == LZMA_STREAM_END) {
305 log_debug("Decompression finished (%zu -> %zu bytes, %.1f%%)",
306 s.total_in, s.total_out,
307 (double) s.total_out / s.total_in * 100);