compression.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. #include "btrfs.h"
  9. #include <linux/lzo.h>
  10. #include <u-boot/zlib.h>
  11. #include <asm/unaligned.h>
  12. static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
  13. {
  14. u32 tot_len, in_len, res;
  15. size_t out_len;
  16. int ret;
  17. if (clen < 4)
  18. return -1;
  19. tot_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
  20. cbuf += 4;
  21. clen -= 4;
  22. tot_len -= 4;
  23. if (tot_len == 0 && dlen)
  24. return -1;
  25. if (tot_len < 4)
  26. return -1;
  27. res = 0;
  28. while (tot_len > 4) {
  29. in_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
  30. cbuf += 4;
  31. clen -= 4;
  32. if (in_len > clen || tot_len < 4 + in_len)
  33. return -1;
  34. tot_len -= 4 + in_len;
  35. out_len = dlen;
  36. ret = lzo1x_decompress_safe(cbuf, in_len, dbuf, &out_len);
  37. if (ret != LZO_E_OK)
  38. return -1;
  39. cbuf += in_len;
  40. clen -= in_len;
  41. dbuf += out_len;
  42. dlen -= out_len;
  43. res += out_len;
  44. }
  45. return res;
  46. }
  47. /* from zutil.h */
  48. #define PRESET_DICT 0x20
  49. static u32 decompress_zlib(const u8 *_cbuf, u32 clen, u8 *dbuf, u32 dlen)
  50. {
  51. int wbits = MAX_WBITS, ret = -1;
  52. z_stream stream;
  53. u8 *cbuf;
  54. u32 res;
  55. memset(&stream, 0, sizeof(stream));
  56. cbuf = (u8 *) _cbuf;
  57. stream.total_in = 0;
  58. stream.next_out = dbuf;
  59. stream.avail_out = dlen;
  60. stream.total_out = 0;
  61. /* skip adler32 check if deflate and no dictionary */
  62. if (clen > 2 && !(cbuf[1] & PRESET_DICT) &&
  63. ((cbuf[0] & 0x0f) == Z_DEFLATED) &&
  64. !(((cbuf[0] << 8) + cbuf[1]) % 31)) {
  65. wbits = -((cbuf[0] >> 4) + 8);
  66. cbuf += 2;
  67. clen -= 2;
  68. }
  69. if (Z_OK != inflateInit2(&stream, wbits))
  70. return -1;
  71. while (stream.total_in < clen) {
  72. stream.next_in = cbuf + stream.total_in;
  73. stream.avail_in = min((u32) (clen - stream.total_in),
  74. (u32) btrfs_info.sb.sectorsize);
  75. ret = inflate(&stream, Z_NO_FLUSH);
  76. if (ret != Z_OK)
  77. break;
  78. }
  79. res = stream.total_out;
  80. inflateEnd(&stream);
  81. if (ret != Z_STREAM_END)
  82. return -1;
  83. return res;
  84. }
  85. u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen)
  86. {
  87. u32 res;
  88. const u8 *cbuf;
  89. u8 *dbuf;
  90. cbuf = (const u8 *) c;
  91. dbuf = (u8 *) d;
  92. switch (type) {
  93. case BTRFS_COMPRESS_NONE:
  94. res = dlen < clen ? dlen : clen;
  95. memcpy(dbuf, cbuf, res);
  96. return res;
  97. case BTRFS_COMPRESS_ZLIB:
  98. return decompress_zlib(cbuf, clen, dbuf, dlen);
  99. case BTRFS_COMPRESS_LZO:
  100. return decompress_lzo(cbuf, clen, dbuf, dlen);
  101. default:
  102. printf("%s: Unsupported compression in extent: %i\n", __func__,
  103. type);
  104. return -1;
  105. }
  106. }