compression.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * BTRFS filesystem implementation for U-Boot
  4. *
  5. * 2017 Marek Behún, CZ.NIC, kabel@kernel.org
  6. */
  7. #include "btrfs.h"
  8. #include <abuf.h>
  9. #include <log.h>
  10. #include <malloc.h>
  11. #include <linux/lzo.h>
  12. #include <linux/zstd.h>
  13. #include <linux/compat.h>
  14. #include <u-boot/zlib.h>
  15. #include <asm/unaligned.h>
  16. /* Header for each segment, LE32, recording the compressed size */
  17. #define LZO_LEN 4
  18. static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
  19. {
  20. u32 tot_len, tot_in, in_len, res;
  21. size_t out_len;
  22. int ret;
  23. if (clen < LZO_LEN)
  24. return -1;
  25. tot_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
  26. tot_in = 0;
  27. cbuf += LZO_LEN;
  28. clen -= LZO_LEN;
  29. tot_len -= LZO_LEN;
  30. tot_in += LZO_LEN;
  31. if (tot_len == 0 && dlen)
  32. return -1;
  33. if (tot_len < LZO_LEN)
  34. return -1;
  35. res = 0;
  36. while (tot_len > LZO_LEN) {
  37. u32 rem_page;
  38. in_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
  39. cbuf += LZO_LEN;
  40. clen -= LZO_LEN;
  41. if (in_len > clen || tot_len < LZO_LEN + in_len)
  42. return -1;
  43. tot_len -= (LZO_LEN + in_len);
  44. tot_in += (LZO_LEN + in_len);
  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. cbuf += in_len;
  50. clen -= in_len;
  51. dbuf += out_len;
  52. dlen -= out_len;
  53. res += out_len;
  54. /*
  55. * If the 4 bytes header does not fit to the rest of the page we
  56. * have to move to next one, or we read some garbage.
  57. */
  58. rem_page = PAGE_SIZE - (tot_in % PAGE_SIZE);
  59. if (rem_page < LZO_LEN) {
  60. cbuf += rem_page;
  61. tot_in += rem_page;
  62. clen -= rem_page;
  63. tot_len -= rem_page;
  64. }
  65. }
  66. return res;
  67. }
  68. /* from zutil.h */
  69. #define PRESET_DICT 0x20
  70. static u32 decompress_zlib(const u8 *_cbuf, u32 clen, u8 *dbuf, u32 dlen)
  71. {
  72. int wbits = MAX_WBITS, ret = -1;
  73. z_stream stream;
  74. u8 *cbuf;
  75. u32 res;
  76. memset(&stream, 0, sizeof(stream));
  77. cbuf = (u8 *) _cbuf;
  78. stream.total_in = 0;
  79. stream.next_out = dbuf;
  80. stream.avail_out = dlen;
  81. stream.total_out = 0;
  82. /* skip adler32 check if deflate and no dictionary */
  83. if (clen > 2 && !(cbuf[1] & PRESET_DICT) &&
  84. ((cbuf[0] & 0x0f) == Z_DEFLATED) &&
  85. !(((cbuf[0] << 8) + cbuf[1]) % 31)) {
  86. wbits = -((cbuf[0] >> 4) + 8);
  87. cbuf += 2;
  88. clen -= 2;
  89. }
  90. if (Z_OK != inflateInit2(&stream, wbits))
  91. return -1;
  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. current_fs_info->sectorsize);
  96. ret = inflate(&stream, Z_NO_FLUSH);
  97. if (ret != Z_OK)
  98. break;
  99. }
  100. res = stream.total_out;
  101. inflateEnd(&stream);
  102. if (ret != Z_STREAM_END)
  103. return -1;
  104. return res;
  105. }
  106. #define ZSTD_BTRFS_MAX_WINDOWLOG 17
  107. #define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
  108. static u32 decompress_zstd(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
  109. {
  110. struct abuf in, out;
  111. abuf_init_set(&in, (u8 *)cbuf, clen);
  112. abuf_init_set(&out, dbuf, dlen);
  113. return zstd_decompress(&in, &out);
  114. }
  115. u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen)
  116. {
  117. u32 res;
  118. const u8 *cbuf;
  119. u8 *dbuf;
  120. cbuf = (const u8 *) c;
  121. dbuf = (u8 *) d;
  122. switch (type) {
  123. case BTRFS_COMPRESS_NONE:
  124. res = dlen < clen ? dlen : clen;
  125. memcpy(dbuf, cbuf, res);
  126. return res;
  127. case BTRFS_COMPRESS_ZLIB:
  128. return decompress_zlib(cbuf, clen, dbuf, dlen);
  129. case BTRFS_COMPRESS_LZO:
  130. return decompress_lzo(cbuf, clen, dbuf, dlen);
  131. case BTRFS_COMPRESS_ZSTD:
  132. return decompress_zstd(cbuf, clen, dbuf, dlen);
  133. default:
  134. printf("%s: Unsupported compression in extent: %i\n", __func__,
  135. type);
  136. return -1;
  137. }
  138. }