]> git.sur5r.net Git - u-boot/blob - fs/btrfs/compression.c
SPDX: Convert all of our single license tags to Linux Kernel style
[u-boot] / 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 <linux/lzo.h>
10 #include <u-boot/zlib.h>
11 #include <asm/unaligned.h>
12
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
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
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 }