decompress_inflate.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // SPDX-License-Identifier: GPL-2.0
  2. #ifdef STATIC
  3. #define PREBOOT
  4. /* Pre-boot environment: included */
  5. /* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots
  6. * errors about console_printk etc... on ARM */
  7. #define _LINUX_KERNEL_H
  8. #include "zlib_inflate/inftrees.c"
  9. #include "zlib_inflate/inffast.c"
  10. #include "zlib_inflate/inflate.c"
  11. #else /* STATIC */
  12. /* initramfs et al: linked */
  13. #include <linux/zutil.h>
  14. #include "zlib_inflate/inftrees.h"
  15. #include "zlib_inflate/inffast.h"
  16. #include "zlib_inflate/inflate.h"
  17. #include "zlib_inflate/infutil.h"
  18. #include <linux/decompress/inflate.h>
  19. #endif /* STATIC */
  20. #include <linux/decompress/mm.h>
  21. #define GZIP_IOBUF_SIZE (16*1024)
  22. static long INIT nofill(void *buffer, unsigned long len)
  23. {
  24. return -1;
  25. }
  26. /* Included from initramfs et al code */
  27. STATIC int INIT __gunzip(unsigned char *buf, long len,
  28. long (*fill)(void*, unsigned long),
  29. long (*flush)(void*, unsigned long),
  30. unsigned char *out_buf, long out_len,
  31. long *pos,
  32. void(*error)(char *x)) {
  33. u8 *zbuf;
  34. struct z_stream_s *strm;
  35. int rc;
  36. rc = -1;
  37. if (flush) {
  38. out_len = 0x8000; /* 32 K */
  39. out_buf = malloc(out_len);
  40. } else {
  41. if (!out_len)
  42. out_len = ((size_t)~0) - (size_t)out_buf; /* no limit */
  43. }
  44. if (!out_buf) {
  45. error("Out of memory while allocating output buffer");
  46. goto gunzip_nomem1;
  47. }
  48. if (buf)
  49. zbuf = buf;
  50. else {
  51. zbuf = malloc(GZIP_IOBUF_SIZE);
  52. len = 0;
  53. }
  54. if (!zbuf) {
  55. error("Out of memory while allocating input buffer");
  56. goto gunzip_nomem2;
  57. }
  58. strm = malloc(sizeof(*strm));
  59. if (strm == NULL) {
  60. error("Out of memory while allocating z_stream");
  61. goto gunzip_nomem3;
  62. }
  63. strm->workspace = malloc(flush ? zlib_inflate_workspacesize() :
  64. sizeof(struct inflate_state));
  65. if (strm->workspace == NULL) {
  66. error("Out of memory while allocating workspace");
  67. goto gunzip_nomem4;
  68. }
  69. if (!fill)
  70. fill = nofill;
  71. if (len == 0)
  72. len = fill(zbuf, GZIP_IOBUF_SIZE);
  73. /* verify the gzip header */
  74. if (len < 10 ||
  75. zbuf[0] != 0x1f || zbuf[1] != 0x8b || zbuf[2] != 0x08) {
  76. if (pos)
  77. *pos = 0;
  78. error("Not a gzip file");
  79. goto gunzip_5;
  80. }
  81. /* skip over gzip header (1f,8b,08... 10 bytes total +
  82. * possible asciz filename)
  83. */
  84. strm->next_in = zbuf + 10;
  85. strm->avail_in = len - 10;
  86. /* skip over asciz filename */
  87. if (zbuf[3] & 0x8) {
  88. do {
  89. /*
  90. * If the filename doesn't fit into the buffer,
  91. * the file is very probably corrupt. Don't try
  92. * to read more data.
  93. */
  94. if (strm->avail_in == 0) {
  95. error("header error");
  96. goto gunzip_5;
  97. }
  98. --strm->avail_in;
  99. } while (*strm->next_in++);
  100. }
  101. strm->next_out = out_buf;
  102. strm->avail_out = out_len;
  103. rc = zlib_inflateInit2(strm, -MAX_WBITS);
  104. if (!flush) {
  105. WS(strm)->inflate_state.wsize = 0;
  106. WS(strm)->inflate_state.window = NULL;
  107. }
  108. while (rc == Z_OK) {
  109. if (strm->avail_in == 0) {
  110. /* TODO: handle case where both pos and fill are set */
  111. len = fill(zbuf, GZIP_IOBUF_SIZE);
  112. if (len < 0) {
  113. rc = -1;
  114. error("read error");
  115. break;
  116. }
  117. strm->next_in = zbuf;
  118. strm->avail_in = len;
  119. }
  120. rc = zlib_inflate(strm, 0);
  121. /* Write any data generated */
  122. if (flush && strm->next_out > out_buf) {
  123. long l = strm->next_out - out_buf;
  124. if (l != flush(out_buf, l)) {
  125. rc = -1;
  126. error("write error");
  127. break;
  128. }
  129. strm->next_out = out_buf;
  130. strm->avail_out = out_len;
  131. }
  132. /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
  133. if (rc == Z_STREAM_END) {
  134. rc = 0;
  135. break;
  136. } else if (rc != Z_OK) {
  137. error("uncompression error");
  138. rc = -1;
  139. }
  140. }
  141. zlib_inflateEnd(strm);
  142. if (pos)
  143. /* add + 8 to skip over trailer */
  144. *pos = strm->next_in - zbuf+8;
  145. gunzip_5:
  146. free(strm->workspace);
  147. gunzip_nomem4:
  148. free(strm);
  149. gunzip_nomem3:
  150. if (!buf)
  151. free(zbuf);
  152. gunzip_nomem2:
  153. if (flush)
  154. free(out_buf);
  155. gunzip_nomem1:
  156. return rc; /* returns Z_OK (0) if successful */
  157. }
  158. #ifndef PREBOOT
  159. STATIC int INIT gunzip(unsigned char *buf, long len,
  160. long (*fill)(void*, unsigned long),
  161. long (*flush)(void*, unsigned long),
  162. unsigned char *out_buf,
  163. long *pos,
  164. void (*error)(char *x))
  165. {
  166. return __gunzip(buf, len, fill, flush, out_buf, 0, pos, error);
  167. }
  168. #else
  169. STATIC int INIT __decompress(unsigned char *buf, long len,
  170. long (*fill)(void*, unsigned long),
  171. long (*flush)(void*, unsigned long),
  172. unsigned char *out_buf, long out_len,
  173. long *pos,
  174. void (*error)(char *x))
  175. {
  176. return __gunzip(buf, len, fill, flush, out_buf, out_len, pos, error);
  177. }
  178. #endif