Line data Source code
1 : /*
2 : * Copyright (C) 2008 Nokia Corporation.
3 : * Copyright (C) 2008 University of Szeged, Hungary
4 : *
5 : * This program is free software; you can redistribute it and/or modify it
6 : * under the terms of the GNU General Public License version 2 as published by
7 : * the Free Software Foundation.
8 : *
9 : * This program is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 : * more details.
13 : *
14 : * You should have received a copy of the GNU General Public License along with
15 : * this program; if not, write to the Free Software Foundation, Inc., 51
16 : * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 : *
18 : * Authors: Artem Bityutskiy
19 : * Adrian Hunter
20 : * Zoltan Sogor
21 : */
22 :
23 : #include <stdlib.h>
24 : #include <stdio.h>
25 : #include <stdint.h>
26 : #include <string.h>
27 : #ifdef WITH_LZO
28 : #include <lzo/lzo1x.h>
29 : #endif
30 : #include <linux/types.h>
31 : #ifdef WITH_ZSTD
32 : #include <zstd.h>
33 : #endif
34 :
35 : #ifdef WITH_ZLIB
36 : #define crc32 __zlib_crc32
37 : #include <zlib.h>
38 : #undef crc32
39 : #endif
40 :
41 : #include "compr.h"
42 : #include "ubifs.h"
43 :
44 : static void *lzo_mem;
45 : static unsigned long long errcnt = 0;
46 : #ifdef WITH_LZO
47 : extern struct ubifs_info info_;
48 : static struct ubifs_info *c = &info_;
49 : #endif
50 :
51 : #ifdef WITH_ZLIB
52 : #define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION
53 : #define DEFLATE_DEF_WINBITS 11
54 : #define DEFLATE_DEF_MEMLEVEL 8
55 :
56 0 : static int zlib_deflate(void *in_buf, size_t in_len, void *out_buf,
57 : size_t *out_len)
58 : {
59 : z_stream strm;
60 :
61 0 : strm.zalloc = NULL;
62 0 : strm.zfree = NULL;
63 :
64 : /*
65 : * Match exactly the zlib parameters used by the Linux kernel crypto
66 : * API.
67 : */
68 0 : if (deflateInit2(&strm, DEFLATE_DEF_LEVEL, Z_DEFLATED,
69 : -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
70 : Z_DEFAULT_STRATEGY)) {
71 0 : errcnt += 1;
72 0 : return -1;
73 : }
74 :
75 0 : strm.next_in = in_buf;
76 0 : strm.avail_in = in_len;
77 0 : strm.total_in = 0;
78 :
79 0 : strm.next_out = out_buf;
80 0 : strm.avail_out = *out_len;
81 0 : strm.total_out = 0;
82 :
83 0 : if (deflate(&strm, Z_FINISH) != Z_STREAM_END) {
84 0 : deflateEnd(&strm);
85 0 : errcnt += 1;
86 0 : return -1;
87 : }
88 :
89 0 : if (deflateEnd(&strm) != Z_OK) {
90 0 : errcnt += 1;
91 0 : return -1;
92 : }
93 :
94 0 : *out_len = strm.total_out;
95 :
96 0 : return 0;
97 : }
98 : #endif
99 :
100 : #ifdef WITH_LZO
101 592320 : static int lzo_compress(void *in_buf, size_t in_len, void *out_buf,
102 : size_t *out_len)
103 : {
104 : lzo_uint len;
105 : int ret;
106 :
107 592320 : len = *out_len;
108 592320 : ret = lzo1x_999_compress(in_buf, in_len, out_buf, &len, lzo_mem);
109 592320 : *out_len = len;
110 :
111 592320 : if (ret != LZO_E_OK) {
112 0 : errcnt += 1;
113 0 : return -1;
114 : }
115 :
116 : return 0;
117 : }
118 : #endif
119 :
120 : #ifdef WITH_ZSTD
121 : static ZSTD_CCtx *zctx;
122 :
123 0 : static int zstd_compress(void *in_buf, size_t in_len, void *out_buf,
124 : size_t *out_len)
125 : {
126 : size_t ret;
127 :
128 0 : ret = ZSTD_compressCCtx(zctx, out_buf, *out_len, in_buf, in_len, 0);
129 0 : if (ZSTD_isError(ret)) {
130 0 : errcnt += 1;
131 0 : return -1;
132 : }
133 0 : *out_len = ret;
134 0 : return 0;
135 : }
136 : #endif
137 :
138 : static int no_compress(void *in_buf, size_t in_len, void *out_buf,
139 : size_t *out_len)
140 : {
141 592960 : memcpy(out_buf, in_buf, in_len);
142 592960 : *out_len = in_len;
143 : return 0;
144 : }
145 :
146 : static char *zlib_buf;
147 :
148 : #if defined(WITH_LZO) && defined(WITH_ZLIB)
149 0 : static int favor_lzo_compress(void *in_buf, size_t in_len, void *out_buf,
150 : size_t *out_len, int *type)
151 : {
152 : int lzo_ret, zlib_ret;
153 : size_t lzo_len, zlib_len;
154 :
155 0 : lzo_len = zlib_len = *out_len;
156 0 : lzo_ret = lzo_compress(in_buf, in_len, out_buf, &lzo_len);
157 0 : zlib_ret = zlib_deflate(in_buf, in_len, zlib_buf, &zlib_len);
158 :
159 0 : if (lzo_ret && zlib_ret)
160 : /* Both compressors failed */
161 : return -1;
162 :
163 0 : if (!lzo_ret && !zlib_ret) {
164 : double percent;
165 :
166 : /* Both compressors succeeded */
167 0 : if (lzo_len <= zlib_len )
168 : goto select_lzo;
169 :
170 0 : percent = (double)zlib_len / (double)lzo_len;
171 0 : percent *= 100;
172 0 : if (percent > 100 - c->favor_percent)
173 : goto select_lzo;
174 : goto select_zlib;
175 : }
176 :
177 0 : if (lzo_ret)
178 : /* Only zlib compressor succeeded */
179 : goto select_zlib;
180 :
181 : /* Only LZO compressor succeeded */
182 :
183 0 : select_lzo:
184 0 : *out_len = lzo_len;
185 0 : *type = UBIFS_COMPR_LZO;
186 0 : return 0;
187 :
188 0 : select_zlib:
189 0 : *out_len = zlib_len;
190 0 : *type = UBIFS_COMPR_ZLIB;
191 0 : memcpy(out_buf, zlib_buf, zlib_len);
192 0 : return 0;
193 : }
194 : #endif
195 :
196 1185280 : int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len,
197 : int type)
198 : {
199 : int ret;
200 :
201 1185280 : if (in_len < UBIFS_MIN_COMPR_LEN) {
202 640 : no_compress(in_buf, in_len, out_buf, out_len);
203 640 : return UBIFS_COMPR_NONE;
204 : }
205 :
206 : #if defined(WITH_LZO) && defined(WITH_ZLIB)
207 1184640 : if (c->favor_lzo)
208 0 : ret = favor_lzo_compress(in_buf, in_len, out_buf, out_len, &type);
209 : else {
210 : #else
211 : {
212 : #endif
213 1184640 : switch (type) {
214 : #ifdef WITH_LZO
215 592320 : case UBIFS_COMPR_LZO:
216 592320 : ret = lzo_compress(in_buf, in_len, out_buf, out_len);
217 592320 : break;
218 : #endif
219 : #ifdef WITH_ZLIB
220 0 : case UBIFS_COMPR_ZLIB:
221 0 : ret = zlib_deflate(in_buf, in_len, out_buf, out_len);
222 0 : break;
223 : #endif
224 : #ifdef WITH_ZSTD
225 0 : case UBIFS_COMPR_ZSTD:
226 0 : ret = zstd_compress(in_buf, in_len, out_buf, out_len);
227 0 : break;
228 : #endif
229 : case UBIFS_COMPR_NONE:
230 : ret = 1;
231 : break;
232 0 : default:
233 0 : errcnt += 1;
234 0 : ret = 1;
235 : break;
236 : }
237 : }
238 592320 : if (ret || *out_len >= in_len) {
239 592320 : no_compress(in_buf, in_len, out_buf, out_len);
240 592320 : return UBIFS_COMPR_NONE;
241 : }
242 592320 : return type;
243 : }
244 :
245 640 : int init_compression(void)
246 : {
247 : #ifndef WITH_LZO
248 : lzo_mem = NULL;
249 : #else
250 640 : lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
251 640 : if (!lzo_mem)
252 : return -1;
253 : #endif
254 :
255 : #ifndef WITH_ZLIB
256 : zlib_buf = NULL;
257 : #else
258 640 : zlib_buf = malloc(UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR);
259 640 : if (!zlib_buf)
260 : goto err;
261 : #endif
262 :
263 : #ifdef WITH_ZSTD
264 640 : zctx = ZSTD_createCCtx();
265 640 : if (!zctx)
266 : goto err;
267 : #endif
268 :
269 : return 0;
270 0 : err:
271 0 : free(zlib_buf);
272 0 : free(lzo_mem);
273 0 : return -1;
274 : }
275 :
276 640 : void destroy_compression(void)
277 : {
278 640 : free(zlib_buf);
279 640 : free(lzo_mem);
280 : #ifdef WITH_ZSTD
281 640 : ZSTD_freeCCtx(zctx);
282 : #endif
283 640 : if (errcnt)
284 0 : fprintf(stderr, "%llu compression errors occurred\n", errcnt);
285 640 : }
|