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 } 135