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 <linux/lzo.h>
10 #include <u-boot/zlib.h>
11 #include <asm/unaligned.h>
12
decompress_lzo(const u8 * cbuf,u32 clen,u8 * dbuf,u32 dlen)13 static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
14 {
15 u32 tot_len, in_len, res;
16 size_t out_len;
17 int ret;
18
19 if (clen < 4)
20 return -1;
21
22 tot_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
23 cbuf += 4;
24 clen -= 4;
25 tot_len -= 4;
26
27 if (tot_len == 0 && dlen)
28 return -1;
29 if (tot_len < 4)
30 return -1;
31
32 res = 0;
33
34 while (tot_len > 4) {
35 in_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
36 cbuf += 4;
37 clen -= 4;
38
39 if (in_len > clen || tot_len < 4 + in_len)
40 return -1;
41
42 tot_len -= 4 + in_len;
43
44 out_len = dlen;
45 ret = lzo1x_decompress_safe(cbuf, in_len, dbuf, &out_len);
46 if (ret != LZO_E_OK)
47 return -1;
48
49 cbuf += in_len;
50 clen -= in_len;
51 dbuf += out_len;
52 dlen -= out_len;
53
54 res += out_len;
55 }
56
57 return res;
58 }
59
60 /* from zutil.h */
61 #define PRESET_DICT 0x20
62
decompress_zlib(const u8 * _cbuf,u32 clen,u8 * dbuf,u32 dlen)63 static u32 decompress_zlib(const u8 *_cbuf, u32 clen, u8 *dbuf, u32 dlen)
64 {
65 int wbits = MAX_WBITS, ret = -1;
66 z_stream stream;
67 u8 *cbuf;
68 u32 res;
69
70 memset(&stream, 0, sizeof(stream));
71
72 cbuf = (u8 *) _cbuf;
73
74 stream.total_in = 0;
75
76 stream.next_out = dbuf;
77 stream.avail_out = dlen;
78 stream.total_out = 0;
79
80 /* skip adler32 check if deflate and no dictionary */
81 if (clen > 2 && !(cbuf[1] & PRESET_DICT) &&
82 ((cbuf[0] & 0x0f) == Z_DEFLATED) &&
83 !(((cbuf[0] << 8) + cbuf[1]) % 31)) {
84 wbits = -((cbuf[0] >> 4) + 8);
85 cbuf += 2;
86 clen -= 2;
87 }
88
89 if (Z_OK != inflateInit2(&stream, wbits))
90 return -1;
91
92 while (stream.total_in < clen) {
93 stream.next_in = cbuf + stream.total_in;
94 stream.avail_in = min((u32) (clen - stream.total_in),
95 (u32) btrfs_info.sb.sectorsize);
96
97 ret = inflate(&stream, Z_NO_FLUSH);
98 if (ret != Z_OK)
99 break;
100 }
101
102 res = stream.total_out;
103 inflateEnd(&stream);
104
105 if (ret != Z_STREAM_END)
106 return -1;
107
108 return res;
109 }
110
btrfs_decompress(u8 type,const char * c,u32 clen,char * d,u32 dlen)111 u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen)
112 {
113 u32 res;
114 const u8 *cbuf;
115 u8 *dbuf;
116
117 cbuf = (const u8 *) c;
118 dbuf = (u8 *) d;
119
120 switch (type) {
121 case BTRFS_COMPRESS_NONE:
122 res = dlen < clen ? dlen : clen;
123 memcpy(dbuf, cbuf, res);
124 return res;
125 case BTRFS_COMPRESS_ZLIB:
126 return decompress_zlib(cbuf, clen, dbuf, dlen);
127 case BTRFS_COMPRESS_LZO:
128 return decompress_lzo(cbuf, clen, dbuf, dlen);
129 default:
130 printf("%s: Unsupported compression in extent: %i\n", __func__,
131 type);
132 return -1;
133 }
134 }
135