• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2 /*
3  * Copyright (C), 2008-2020, OPPO Mobile Comm Corp., Ltd.
4  * Created by Huang Jianan <huangjianan@oppo.com>
5  */
6 #include <stdlib.h>
7 
8 #include "erofs/decompress.h"
9 #include "erofs/err.h"
10 #include "erofs/print.h"
11 
12 #ifdef HAVE_LIBDEFLATE
13 /* if libdeflate is available, use libdeflate instead. */
14 #include <libdeflate.h>
15 
z_erofs_decompress_deflate(struct z_erofs_decompress_req * rq)16 static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq)
17 {
18 	struct erofs_sb_info *sbi = rq->sbi;
19 	u8 *dest = (u8 *)rq->out;
20 	u8 *src = (u8 *)rq->in;
21 	u8 *buff = NULL;
22 	size_t actual_out;
23 	unsigned int inputmargin = 0;
24 	struct libdeflate_decompressor *inf;
25 	enum libdeflate_result ret;
26 
27 	while (!src[inputmargin & (erofs_blksiz(sbi) - 1)])
28 		if (!(++inputmargin & (erofs_blksiz(sbi) - 1)))
29 			break;
30 
31 	if (inputmargin >= rq->inputsize)
32 		return -EFSCORRUPTED;
33 
34 	if (rq->decodedskip) {
35 		buff = malloc(rq->decodedlength);
36 		if (!buff)
37 			return -ENOMEM;
38 		dest = buff;
39 	}
40 
41 	inf = libdeflate_alloc_decompressor();
42 	if (!inf)
43 		return -ENOMEM;
44 
45 	if (rq->partial_decoding) {
46 		ret = libdeflate_deflate_decompress(inf, src + inputmargin,
47 				rq->inputsize - inputmargin, dest,
48 				rq->decodedlength, &actual_out);
49 		if (ret && ret != LIBDEFLATE_INSUFFICIENT_SPACE) {
50 			ret = -EIO;
51 			goto out_inflate_end;
52 		}
53 
54 		if (actual_out != rq->decodedlength) {
55 			ret = -EIO;
56 			goto out_inflate_end;
57 		}
58 	} else {
59 		ret = libdeflate_deflate_decompress(inf, src + inputmargin,
60 				rq->inputsize - inputmargin, dest,
61 				rq->decodedlength, NULL);
62 		if (ret) {
63 			ret = -EIO;
64 			goto out_inflate_end;
65 		}
66 	}
67 
68 	if (rq->decodedskip)
69 		memcpy(rq->out, dest + rq->decodedskip,
70 		       rq->decodedlength - rq->decodedskip);
71 
72 out_inflate_end:
73 	libdeflate_free_decompressor(inf);
74 	if (buff)
75 		free(buff);
76 	return ret;
77 }
78 #elif defined(HAVE_ZLIB)
79 #include <zlib.h>
80 
81 /* report a zlib or i/o error */
zerr(int ret)82 static int zerr(int ret)
83 {
84 	switch (ret) {
85 	case Z_STREAM_ERROR:
86 		return -EINVAL;
87 	case Z_DATA_ERROR:
88 		return -EIO;
89 	case Z_MEM_ERROR:
90 		return -ENOMEM;
91 	case Z_ERRNO:
92 	case Z_VERSION_ERROR:
93 	default:
94 		return -EFAULT;
95 	}
96 }
97 
z_erofs_decompress_deflate(struct z_erofs_decompress_req * rq)98 static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq)
99 {
100 	struct erofs_sb_info *sbi = rq->sbi;
101 	u8 *dest = (u8 *)rq->out;
102 	u8 *src = (u8 *)rq->in;
103 	u8 *buff = NULL;
104 	unsigned int inputmargin = 0;
105 	z_stream strm;
106 	int ret;
107 
108 	while (!src[inputmargin & (erofs_blksiz(sbi) - 1)])
109 		if (!(++inputmargin & (erofs_blksiz(sbi) - 1)))
110 			break;
111 
112 	if (inputmargin >= rq->inputsize)
113 		return -EFSCORRUPTED;
114 
115 	if (rq->decodedskip) {
116 		buff = malloc(rq->decodedlength);
117 		if (!buff)
118 			return -ENOMEM;
119 		dest = buff;
120 	}
121 
122 	/* allocate inflate state */
123 	strm.zalloc = Z_NULL;
124 	strm.zfree = Z_NULL;
125 	strm.opaque = Z_NULL;
126 	strm.avail_in = 0;
127 	strm.next_in = Z_NULL;
128 	ret = inflateInit2(&strm, -15);
129 	if (ret != Z_OK) {
130 		free(buff);
131 		return zerr(ret);
132 	}
133 
134 	strm.next_in = src + inputmargin;
135 	strm.avail_in = rq->inputsize - inputmargin;
136 	strm.next_out = dest;
137 	strm.avail_out = rq->decodedlength;
138 
139 	ret = inflate(&strm, rq->partial_decoding ? Z_SYNC_FLUSH : Z_FINISH);
140 	if (ret != Z_STREAM_END || strm.total_out != rq->decodedlength) {
141 		if (ret != Z_OK || !rq->partial_decoding) {
142 			ret = zerr(ret);
143 			goto out_inflate_end;
144 		}
145 	}
146 
147 	if (rq->decodedskip)
148 		memcpy(rq->out, dest + rq->decodedskip,
149 		       rq->decodedlength - rq->decodedskip);
150 
151 out_inflate_end:
152 	inflateEnd(&strm);
153 	if (buff)
154 		free(buff);
155 	return ret;
156 }
157 #endif
158 
159 #ifdef HAVE_LIBLZMA
160 #include <lzma.h>
161 
z_erofs_decompress_lzma(struct z_erofs_decompress_req * rq)162 static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq)
163 {
164 	int ret = 0;
165 	struct erofs_sb_info *sbi = rq->sbi;
166 	u8 *dest = (u8 *)rq->out;
167 	u8 *src = (u8 *)rq->in;
168 	u8 *buff = NULL;
169 	unsigned int inputmargin = 0;
170 	lzma_stream strm;
171 	lzma_ret ret2;
172 
173 	while (!src[inputmargin & (erofs_blksiz(sbi) - 1)])
174 		if (!(++inputmargin & (erofs_blksiz(sbi) - 1)))
175 			break;
176 
177 	if (inputmargin >= rq->inputsize)
178 		return -EFSCORRUPTED;
179 
180 	if (rq->decodedskip) {
181 		buff = malloc(rq->decodedlength);
182 		if (!buff)
183 			return -ENOMEM;
184 		dest = buff;
185 	}
186 
187 	strm = (lzma_stream)LZMA_STREAM_INIT;
188 	strm.next_in = src + inputmargin;
189 	strm.avail_in = rq->inputsize - inputmargin;
190 	strm.next_out = dest;
191 	strm.avail_out = rq->decodedlength;
192 
193 	ret2 = lzma_microlzma_decoder(&strm, strm.avail_in, rq->decodedlength,
194 				      !rq->partial_decoding,
195 				      Z_EROFS_LZMA_MAX_DICT_SIZE);
196 	if (ret2 != LZMA_OK) {
197 		erofs_err("fail to initialize lzma decoder %u", ret2 | 0U);
198 		ret = -EFAULT;
199 		goto out;
200 	}
201 
202 	ret2 = lzma_code(&strm, LZMA_FINISH);
203 	if (ret2 != LZMA_STREAM_END) {
204 		ret = -EFSCORRUPTED;
205 		goto out_lzma_end;
206 	}
207 
208 	if (rq->decodedskip)
209 		memcpy(rq->out, dest + rq->decodedskip,
210 		       rq->decodedlength - rq->decodedskip);
211 
212 out_lzma_end:
213 	lzma_end(&strm);
214 out:
215 	if (buff)
216 		free(buff);
217 	return ret;
218 }
219 #endif
220 
221 #ifdef LZ4_ENABLED
222 #include <lz4.h>
223 
z_erofs_decompress_lz4(struct z_erofs_decompress_req * rq)224 static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
225 {
226 	int ret = 0;
227 	char *dest = rq->out;
228 	char *src = rq->in;
229 	char *buff = NULL;
230 	bool support_0padding = false;
231 	unsigned int inputmargin = 0;
232 	struct erofs_sb_info *sbi = rq->sbi;
233 
234 	if (erofs_sb_has_lz4_0padding(sbi)) {
235 		support_0padding = true;
236 
237 		while (!src[inputmargin & (erofs_blksiz(sbi) - 1)])
238 			if (!(++inputmargin & (erofs_blksiz(sbi) - 1)))
239 				break;
240 
241 		if (inputmargin >= rq->inputsize)
242 			return -EIO;
243 	}
244 
245 	if (rq->decodedskip) {
246 		buff = malloc(rq->decodedlength);
247 		if (!buff)
248 			return -ENOMEM;
249 		dest = buff;
250 	}
251 
252 	if (rq->partial_decoding || !support_0padding)
253 		ret = LZ4_decompress_safe_partial(src + inputmargin, dest,
254 				rq->inputsize - inputmargin,
255 				rq->decodedlength, rq->decodedlength);
256 	else
257 		ret = LZ4_decompress_safe(src + inputmargin, dest,
258 					  rq->inputsize - inputmargin,
259 					  rq->decodedlength);
260 
261 	if (ret != (int)rq->decodedlength) {
262 		erofs_err("failed to %s decompress %d in[%u, %u] out[%u]",
263 			  rq->partial_decoding ? "partial" : "full",
264 			  ret, rq->inputsize, inputmargin, rq->decodedlength);
265 		ret = -EIO;
266 		goto out;
267 	}
268 
269 	if (rq->decodedskip)
270 		memcpy(rq->out, dest + rq->decodedskip,
271 		       rq->decodedlength - rq->decodedskip);
272 
273 out:
274 	if (buff)
275 		free(buff);
276 
277 	return ret;
278 }
279 #endif
280 
z_erofs_decompress(struct z_erofs_decompress_req * rq)281 int z_erofs_decompress(struct z_erofs_decompress_req *rq)
282 {
283 	struct erofs_sb_info *sbi = rq->sbi;
284 
285 	if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
286 		unsigned int count, rightpart, skip;
287 
288 		/* XXX: should support inputsize >= erofs_blksiz(sbi) later */
289 		if (rq->inputsize > erofs_blksiz(sbi))
290 			return -EFSCORRUPTED;
291 
292 		if (rq->decodedlength > erofs_blksiz(sbi))
293 			return -EFSCORRUPTED;
294 
295 		if (rq->decodedlength < rq->decodedskip)
296 			return -EFSCORRUPTED;
297 
298 		count = rq->decodedlength - rq->decodedskip;
299 		skip = erofs_blkoff(sbi, rq->interlaced_offset + rq->decodedskip);
300 		rightpart = min(erofs_blksiz(sbi) - skip, count);
301 		memcpy(rq->out, rq->in + skip, rightpart);
302 		memcpy(rq->out + rightpart, rq->in, count - rightpart);
303 		return 0;
304 	} else if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
305 		if (rq->decodedlength > rq->inputsize)
306 			return -EFSCORRUPTED;
307 
308 		DBG_BUGON(rq->decodedlength < rq->decodedskip);
309 		memcpy(rq->out, rq->in + rq->decodedskip,
310 		       rq->decodedlength - rq->decodedskip);
311 		return 0;
312 	}
313 
314 #ifdef LZ4_ENABLED
315 	if (rq->alg == Z_EROFS_COMPRESSION_LZ4)
316 		return z_erofs_decompress_lz4(rq);
317 #endif
318 #ifdef HAVE_LIBLZMA
319 	if (rq->alg == Z_EROFS_COMPRESSION_LZMA)
320 		return z_erofs_decompress_lzma(rq);
321 #endif
322 #if defined(HAVE_ZLIB) || defined(HAVE_LIBDEFLATE)
323 	if (rq->alg == Z_EROFS_COMPRESSION_DEFLATE)
324 		return z_erofs_decompress_deflate(rq);
325 #endif
326 	return -EOPNOTSUPP;
327 }
328