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