• 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_LIBLZMA
13 #include <lzma.h>
14 
z_erofs_decompress_lzma(struct z_erofs_decompress_req * rq)15 static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq)
16 {
17 	int ret = 0;
18 	u8 *dest = (u8 *)rq->out;
19 	u8 *src = (u8 *)rq->in;
20 	u8 *buff = NULL;
21 	unsigned int inputmargin = 0;
22 	lzma_stream strm;
23 	lzma_ret ret2;
24 
25 	while (!src[inputmargin & ~PAGE_MASK])
26 		if (!(++inputmargin & ~PAGE_MASK))
27 			break;
28 
29 	if (inputmargin >= rq->inputsize)
30 		return -EFSCORRUPTED;
31 
32 	if (rq->decodedskip) {
33 		buff = malloc(rq->decodedlength);
34 		if (!buff)
35 			return -ENOMEM;
36 		dest = buff;
37 	}
38 
39 	strm = (lzma_stream)LZMA_STREAM_INIT;
40 	strm.next_in = src + inputmargin;
41 	strm.avail_in = rq->inputsize - inputmargin;
42 	strm.next_out = dest;
43 	strm.avail_out = rq->decodedlength;
44 
45 	ret2 = lzma_microlzma_decoder(&strm, strm.avail_in, rq->decodedlength,
46 				      !rq->partial_decoding,
47 				      Z_EROFS_LZMA_MAX_DICT_SIZE);
48 	if (ret2 != LZMA_OK) {
49 		erofs_err("fail to initialize lzma decoder %u", ret2 | 0U);
50 		ret = -EFAULT;
51 		goto out;
52 	}
53 
54 	ret2 = lzma_code(&strm, LZMA_FINISH);
55 	if (ret2 != LZMA_STREAM_END) {
56 		ret = -EFSCORRUPTED;
57 		goto out_lzma_end;
58 	}
59 
60 	if (rq->decodedskip)
61 		memcpy(rq->out, dest + rq->decodedskip,
62 		       rq->decodedlength - rq->decodedskip);
63 
64 out_lzma_end:
65 	lzma_end(&strm);
66 out:
67 	if (buff)
68 		free(buff);
69 	return ret;
70 }
71 #endif
72 
73 #ifdef LZ4_ENABLED
74 #include <lz4.h>
75 
z_erofs_decompress_lz4(struct z_erofs_decompress_req * rq)76 static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
77 {
78 	int ret = 0;
79 	char *dest = rq->out;
80 	char *src = rq->in;
81 	char *buff = NULL;
82 	bool support_0padding = false;
83 	unsigned int inputmargin = 0;
84 
85 	if (erofs_sb_has_lz4_0padding()) {
86 		support_0padding = true;
87 
88 		while (!src[inputmargin & ~PAGE_MASK])
89 			if (!(++inputmargin & ~PAGE_MASK))
90 				break;
91 
92 		if (inputmargin >= rq->inputsize)
93 			return -EIO;
94 	}
95 
96 	if (rq->decodedskip) {
97 		buff = malloc(rq->decodedlength);
98 		if (!buff)
99 			return -ENOMEM;
100 		dest = buff;
101 	}
102 
103 	if (rq->partial_decoding || !support_0padding)
104 		ret = LZ4_decompress_safe_partial(src + inputmargin, dest,
105 				rq->inputsize - inputmargin,
106 				rq->decodedlength, rq->decodedlength);
107 	else
108 		ret = LZ4_decompress_safe(src + inputmargin, dest,
109 					  rq->inputsize - inputmargin,
110 					  rq->decodedlength);
111 
112 	if (ret != (int)rq->decodedlength) {
113 		erofs_err("failed to %s decompress %d in[%u, %u] out[%u]",
114 			  rq->partial_decoding ? "partial" : "full",
115 			  ret, rq->inputsize, inputmargin, rq->decodedlength);
116 		ret = -EIO;
117 		goto out;
118 	}
119 
120 	if (rq->decodedskip)
121 		memcpy(rq->out, dest + rq->decodedskip,
122 		       rq->decodedlength - rq->decodedskip);
123 
124 out:
125 	if (buff)
126 		free(buff);
127 
128 	return ret;
129 }
130 #endif
131 
z_erofs_decompress(struct z_erofs_decompress_req * rq)132 int z_erofs_decompress(struct z_erofs_decompress_req *rq)
133 {
134 	if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
135 		if (rq->inputsize > EROFS_BLKSIZ)
136 			return -EFSCORRUPTED;
137 
138 		DBG_BUGON(rq->decodedlength > EROFS_BLKSIZ);
139 		DBG_BUGON(rq->decodedlength < rq->decodedskip);
140 
141 		memcpy(rq->out, rq->in + rq->decodedskip,
142 		       rq->decodedlength - rq->decodedskip);
143 		return 0;
144 	}
145 
146 #ifdef LZ4_ENABLED
147 	if (rq->alg == Z_EROFS_COMPRESSION_LZ4)
148 		return z_erofs_decompress_lz4(rq);
149 #endif
150 #ifdef HAVE_LIBLZMA
151 	if (rq->alg == Z_EROFS_COMPRESSION_LZMA)
152 		return z_erofs_decompress_lzma(rq);
153 #endif
154 	return -EOPNOTSUPP;
155 }
156