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