test/py: Add usb gadget binding test
[platform/kernel/u-boot.git] / fs / btrfs / compression.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * BTRFS filesystem implementation for U-Boot
4  *
5  * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
6  */
7
8 #include "btrfs.h"
9 #include <log.h>
10 #include <malloc.h>
11 #include <linux/lzo.h>
12 #include <linux/zstd.h>
13 #include <linux/compat.h>
14 #include <u-boot/zlib.h>
15 #include <asm/unaligned.h>
16
17 /* Header for each segment, LE32, recording the compressed size */
18 #define LZO_LEN         4
19 static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
20 {
21         u32 tot_len, tot_in, in_len, res;
22         size_t out_len;
23         int ret;
24
25         if (clen < LZO_LEN)
26                 return -1;
27
28         tot_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
29         tot_in = 0;
30         cbuf += LZO_LEN;
31         clen -= LZO_LEN;
32         tot_len -= LZO_LEN;
33         tot_in += LZO_LEN;
34
35         if (tot_len == 0 && dlen)
36                 return -1;
37         if (tot_len < LZO_LEN)
38                 return -1;
39
40         res = 0;
41
42         while (tot_len > LZO_LEN) {
43                 u32 rem_page;
44
45                 in_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
46                 cbuf += LZO_LEN;
47                 clen -= LZO_LEN;
48
49                 if (in_len > clen || tot_len < LZO_LEN + in_len)
50                         return -1;
51
52                 tot_len -= (LZO_LEN + in_len);
53                 tot_in += (LZO_LEN + in_len);
54
55                 out_len = dlen;
56                 ret = lzo1x_decompress_safe(cbuf, in_len, dbuf, &out_len);
57                 if (ret != LZO_E_OK)
58                         return -1;
59
60                 cbuf += in_len;
61                 clen -= in_len;
62                 dbuf += out_len;
63                 dlen -= out_len;
64
65                 res += out_len;
66
67                 /*
68                  * If the 4 bytes header does not fit to the rest of the page we
69                  * have to move to next one, or we read some garbage.
70                  */
71                 rem_page = PAGE_SIZE - (tot_in % PAGE_SIZE);
72                 if (rem_page < LZO_LEN) {
73                         cbuf += rem_page;
74                         tot_in += rem_page;
75                         clen -= rem_page;
76                         tot_len -= rem_page;
77                 }
78         }
79
80         return res;
81 }
82
83 /* from zutil.h */
84 #define PRESET_DICT 0x20
85
86 static u32 decompress_zlib(const u8 *_cbuf, u32 clen, u8 *dbuf, u32 dlen)
87 {
88         int wbits = MAX_WBITS, ret = -1;
89         z_stream stream;
90         u8 *cbuf;
91         u32 res;
92
93         memset(&stream, 0, sizeof(stream));
94
95         cbuf = (u8 *) _cbuf;
96
97         stream.total_in = 0;
98
99         stream.next_out = dbuf;
100         stream.avail_out = dlen;
101         stream.total_out = 0;
102
103         /* skip adler32 check if deflate and no dictionary */
104         if (clen > 2 && !(cbuf[1] & PRESET_DICT) &&
105             ((cbuf[0] & 0x0f) == Z_DEFLATED) &&
106             !(((cbuf[0] << 8) + cbuf[1]) % 31)) {
107                 wbits = -((cbuf[0] >> 4) + 8);
108                 cbuf += 2;
109                 clen -= 2;
110         }
111
112         if (Z_OK != inflateInit2(&stream, wbits))
113                 return -1;
114
115         while (stream.total_in < clen) {
116                 stream.next_in = cbuf + stream.total_in;
117                 stream.avail_in = min((u32) (clen - stream.total_in),
118                                         current_fs_info->sectorsize);
119
120                 ret = inflate(&stream, Z_NO_FLUSH);
121                 if (ret != Z_OK)
122                         break;
123         }
124
125         res = stream.total_out;
126         inflateEnd(&stream);
127
128         if (ret != Z_STREAM_END)
129                 return -1;
130
131         return res;
132 }
133
134 #define ZSTD_BTRFS_MAX_WINDOWLOG 17
135 #define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
136
137 static u32 decompress_zstd(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
138 {
139         ZSTD_DStream *dstream;
140         ZSTD_inBuffer in_buf;
141         ZSTD_outBuffer out_buf;
142         void *workspace;
143         size_t wsize;
144         u32 res = -1;
145
146         wsize = ZSTD_DStreamWorkspaceBound(ZSTD_BTRFS_MAX_INPUT);
147         workspace = malloc(wsize);
148         if (!workspace) {
149                 debug("%s: cannot allocate workspace of size %zu\n", __func__,
150                       wsize);
151                 return -1;
152         }
153
154         dstream = ZSTD_initDStream(ZSTD_BTRFS_MAX_INPUT, workspace, wsize);
155         if (!dstream) {
156                 printf("%s: ZSTD_initDStream failed\n", __func__);
157                 goto err_free;
158         }
159
160         in_buf.src = cbuf;
161         in_buf.pos = 0;
162         in_buf.size = clen;
163
164         out_buf.dst = dbuf;
165         out_buf.pos = 0;
166         out_buf.size = dlen;
167
168         while (1) {
169                 size_t ret;
170
171                 ret = ZSTD_decompressStream(dstream, &out_buf, &in_buf);
172                 if (ZSTD_isError(ret)) {
173                         printf("%s: ZSTD_decompressStream error %d\n", __func__,
174                                ZSTD_getErrorCode(ret));
175                         goto err_free;
176                 }
177
178                 if (in_buf.pos >= clen || !ret)
179                         break;
180         }
181
182         res = out_buf.pos;
183
184 err_free:
185         free(workspace);
186         return res;
187 }
188
189 u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen)
190 {
191         u32 res;
192         const u8 *cbuf;
193         u8 *dbuf;
194
195         cbuf = (const u8 *) c;
196         dbuf = (u8 *) d;
197
198         switch (type) {
199         case BTRFS_COMPRESS_NONE:
200                 res = dlen < clen ? dlen : clen;
201                 memcpy(dbuf, cbuf, res);
202                 return res;
203         case BTRFS_COMPRESS_ZLIB:
204                 return decompress_zlib(cbuf, clen, dbuf, dlen);
205         case BTRFS_COMPRESS_LZO:
206                 return decompress_lzo(cbuf, clen, dbuf, dlen);
207         case BTRFS_COMPRESS_ZSTD:
208                 return decompress_zstd(cbuf, clen, dbuf, dlen);
209         default:
210                 printf("%s: Unsupported compression in extent: %i\n", __func__,
211                        type);
212                 return -1;
213         }
214 }