chiark / gitweb /
journalctl: quit on I/O error
[elogind.git] / src / journal / compress.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <lzma.h>
26
27 #include "macro.h"
28 #include "compress.h"
29
30 bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_size) {
31         lzma_stream s = LZMA_STREAM_INIT;
32         lzma_ret ret;
33         bool b = false;
34
35         assert(src);
36         assert(src_size > 0);
37         assert(dst);
38         assert(dst_size);
39
40         /* Returns false if we couldn't compress the data or the
41          * compressed result is longer than the original */
42
43         ret = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_NONE);
44         if (ret != LZMA_OK)
45                 return false;
46
47         s.next_in = src;
48         s.avail_in = src_size;
49         s.next_out = dst;
50         s.avail_out = src_size;
51
52         /* Does it fit? */
53         if (lzma_code(&s, LZMA_FINISH) != LZMA_STREAM_END)
54                 goto fail;
55
56         /* Is it actually shorter? */
57         if (s.avail_out == 0)
58                 goto fail;
59
60         *dst_size = src_size - s.avail_out;
61         b = true;
62
63 fail:
64         lzma_end(&s);
65
66         return b;
67 }
68
69 bool uncompress_blob(const void *src, uint64_t src_size,
70                      void **dst, uint64_t *dst_alloc_size, uint64_t* dst_size, uint64_t dst_max) {
71
72         lzma_stream s = LZMA_STREAM_INIT;
73         lzma_ret ret;
74         uint64_t space;
75         bool b = false;
76
77         assert(src);
78         assert(src_size > 0);
79         assert(dst);
80         assert(dst_alloc_size);
81         assert(dst_size);
82         assert(*dst_alloc_size == 0 || *dst);
83
84         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
85         if (ret != LZMA_OK)
86                 return false;
87
88         if (*dst_alloc_size <= src_size) {
89                 void *p;
90
91                 p = realloc(*dst, src_size*2);
92                 if (!p)
93                         return false;
94
95                 *dst = p;
96                 *dst_alloc_size = src_size*2;
97         }
98
99         s.next_in = src;
100         s.avail_in = src_size;
101
102         s.next_out = *dst;
103         space = dst_max > 0 ? MIN(*dst_alloc_size, dst_max) : *dst_alloc_size;
104         s.avail_out = space;
105
106         for (;;) {
107                 void *p;
108
109                 ret = lzma_code(&s, LZMA_FINISH);
110
111                 if (ret == LZMA_STREAM_END)
112                         break;
113
114                 if (ret != LZMA_OK)
115                         goto fail;
116
117                 if (dst_max > 0 && (space - s.avail_out) >= dst_max)
118                         break;
119
120                 p = realloc(*dst, space*2);
121                 if (!p)
122                         goto fail;
123
124                 s.next_out = (uint8_t*) p + ((uint8_t*) s.next_out - (uint8_t*) *dst);
125                 s.avail_out += space;
126
127                 space *= 2;
128
129                 *dst = p;
130                 *dst_alloc_size = space;
131         }
132
133         *dst_size = space - s.avail_out;
134         b = true;
135
136 fail:
137         lzma_end(&s);
138
139         return b;
140 }
141
142 bool uncompress_startswith(const void *src, uint64_t src_size,
143                            void **buffer, uint64_t *buffer_size,
144                            const void *prefix, uint64_t prefix_len,
145                            uint8_t extra) {
146
147         lzma_stream s = LZMA_STREAM_INIT;
148         lzma_ret ret;
149         bool b = false;
150
151         /* Checks whether the uncompressed blob starts with the
152          * mentioned prefix. The byte extra needs to follow the
153          * prefix */
154
155         assert(src);
156         assert(src_size > 0);
157         assert(buffer);
158         assert(buffer_size);
159         assert(prefix);
160         assert(*buffer_size == 0 || *buffer);
161
162         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
163         if (ret != LZMA_OK)
164                 return false;
165
166         if (*buffer_size <= prefix_len) {
167                 void *p;
168
169                 p = realloc(*buffer, prefix_len*2);
170                 if (!p)
171                         return false;
172
173                 *buffer = p;
174                 *buffer_size = prefix_len*2;
175         }
176
177         s.next_in = src;
178         s.avail_in = src_size;
179
180         s.next_out = *buffer;
181         s.avail_out = *buffer_size;
182
183         for (;;) {
184                 void *p;
185
186                 ret = lzma_code(&s, LZMA_FINISH);
187
188                 if (ret != LZMA_STREAM_END && ret != LZMA_OK)
189                         goto fail;
190
191                 if ((*buffer_size - s.avail_out > prefix_len) &&
192                     memcmp(*buffer, prefix, prefix_len) == 0 &&
193                     ((const uint8_t*) *buffer)[prefix_len] == extra)
194                         break;
195
196                 if (ret == LZMA_STREAM_END)
197                         goto fail;
198
199                 p = realloc(*buffer, *buffer_size*2);
200                 if (!p)
201                         goto fail;
202
203                 s.next_out = (uint8_t*) p + ((uint8_t*) s.next_out - (uint8_t*) *buffer);
204                 s.avail_out += *buffer_size;
205
206                 *buffer = p;
207                 *buffer_size *= 2;
208         }
209
210         b = true;
211
212 fail:
213         lzma_end(&s);
214
215         return b;
216 }