compression.c 3.7 KB

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