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