forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
4.8 KiB
219 lines
4.8 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
#ifdef STATIC |
|
#define PREBOOT |
|
/* Pre-boot environment: included */ |
|
|
|
/* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots |
|
* errors about console_printk etc... on ARM */ |
|
#define _LINUX_KERNEL_H |
|
|
|
#include "zlib_inflate/inftrees.c" |
|
#include "zlib_inflate/inffast.c" |
|
#include "zlib_inflate/inflate.c" |
|
#ifdef CONFIG_ZLIB_DFLTCC |
|
#include "zlib_dfltcc/dfltcc.c" |
|
#include "zlib_dfltcc/dfltcc_inflate.c" |
|
#endif |
|
|
|
#else /* STATIC */ |
|
/* initramfs et al: linked */ |
|
|
|
#include <linux/zutil.h> |
|
|
|
#include "zlib_inflate/inftrees.h" |
|
#include "zlib_inflate/inffast.h" |
|
#include "zlib_inflate/inflate.h" |
|
|
|
#include "zlib_inflate/infutil.h" |
|
#include <linux/decompress/inflate.h> |
|
|
|
#endif /* STATIC */ |
|
|
|
#include <linux/decompress/mm.h> |
|
|
|
#define GZIP_IOBUF_SIZE (16*1024) |
|
|
|
static long INIT nofill(void *buffer, unsigned long len) |
|
{ |
|
return -1; |
|
} |
|
|
|
/* Included from initramfs et al code */ |
|
STATIC int INIT __gunzip(unsigned char *buf, long len, |
|
long (*fill)(void*, unsigned long), |
|
long (*flush)(void*, unsigned long), |
|
unsigned char *out_buf, long out_len, |
|
long *pos, |
|
void(*error)(char *x)) { |
|
u8 *zbuf; |
|
struct z_stream_s *strm; |
|
int rc; |
|
|
|
rc = -1; |
|
if (flush) { |
|
out_len = 0x8000; /* 32 K */ |
|
out_buf = malloc(out_len); |
|
} else { |
|
if (!out_len) |
|
out_len = ((size_t)~0) - (size_t)out_buf; /* no limit */ |
|
} |
|
if (!out_buf) { |
|
error("Out of memory while allocating output buffer"); |
|
goto gunzip_nomem1; |
|
} |
|
|
|
if (buf) |
|
zbuf = buf; |
|
else { |
|
zbuf = malloc(GZIP_IOBUF_SIZE); |
|
len = 0; |
|
} |
|
if (!zbuf) { |
|
error("Out of memory while allocating input buffer"); |
|
goto gunzip_nomem2; |
|
} |
|
|
|
strm = malloc(sizeof(*strm)); |
|
if (strm == NULL) { |
|
error("Out of memory while allocating z_stream"); |
|
goto gunzip_nomem3; |
|
} |
|
|
|
strm->workspace = malloc(flush ? zlib_inflate_workspacesize() : |
|
#ifdef CONFIG_ZLIB_DFLTCC |
|
/* Always allocate the full workspace for DFLTCC */ |
|
zlib_inflate_workspacesize()); |
|
#else |
|
sizeof(struct inflate_state)); |
|
#endif |
|
if (strm->workspace == NULL) { |
|
error("Out of memory while allocating workspace"); |
|
goto gunzip_nomem4; |
|
} |
|
|
|
if (!fill) |
|
fill = nofill; |
|
|
|
if (len == 0) |
|
len = fill(zbuf, GZIP_IOBUF_SIZE); |
|
|
|
/* verify the gzip header */ |
|
if (len < 10 || |
|
zbuf[0] != 0x1f || zbuf[1] != 0x8b || zbuf[2] != 0x08) { |
|
if (pos) |
|
*pos = 0; |
|
error("Not a gzip file"); |
|
goto gunzip_5; |
|
} |
|
|
|
/* skip over gzip header (1f,8b,08... 10 bytes total + |
|
* possible asciz filename) |
|
*/ |
|
strm->next_in = zbuf + 10; |
|
strm->avail_in = len - 10; |
|
/* skip over asciz filename */ |
|
if (zbuf[3] & 0x8) { |
|
do { |
|
/* |
|
* If the filename doesn't fit into the buffer, |
|
* the file is very probably corrupt. Don't try |
|
* to read more data. |
|
*/ |
|
if (strm->avail_in == 0) { |
|
error("header error"); |
|
goto gunzip_5; |
|
} |
|
--strm->avail_in; |
|
} while (*strm->next_in++); |
|
} |
|
|
|
strm->next_out = out_buf; |
|
strm->avail_out = out_len; |
|
|
|
rc = zlib_inflateInit2(strm, -MAX_WBITS); |
|
|
|
#ifdef CONFIG_ZLIB_DFLTCC |
|
/* Always keep the window for DFLTCC */ |
|
#else |
|
if (!flush) { |
|
WS(strm)->inflate_state.wsize = 0; |
|
WS(strm)->inflate_state.window = NULL; |
|
} |
|
#endif |
|
|
|
while (rc == Z_OK) { |
|
if (strm->avail_in == 0) { |
|
/* TODO: handle case where both pos and fill are set */ |
|
len = fill(zbuf, GZIP_IOBUF_SIZE); |
|
if (len < 0) { |
|
rc = -1; |
|
error("read error"); |
|
break; |
|
} |
|
strm->next_in = zbuf; |
|
strm->avail_in = len; |
|
} |
|
rc = zlib_inflate(strm, 0); |
|
|
|
/* Write any data generated */ |
|
if (flush && strm->next_out > out_buf) { |
|
long l = strm->next_out - out_buf; |
|
if (l != flush(out_buf, l)) { |
|
rc = -1; |
|
error("write error"); |
|
break; |
|
} |
|
strm->next_out = out_buf; |
|
strm->avail_out = out_len; |
|
} |
|
|
|
/* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ |
|
if (rc == Z_STREAM_END) { |
|
rc = 0; |
|
break; |
|
} else if (rc != Z_OK) { |
|
error("uncompression error"); |
|
rc = -1; |
|
} |
|
} |
|
|
|
zlib_inflateEnd(strm); |
|
if (pos) |
|
/* add + 8 to skip over trailer */ |
|
*pos = strm->next_in - zbuf+8; |
|
|
|
gunzip_5: |
|
free(strm->workspace); |
|
gunzip_nomem4: |
|
free(strm); |
|
gunzip_nomem3: |
|
if (!buf) |
|
free(zbuf); |
|
gunzip_nomem2: |
|
if (flush) |
|
free(out_buf); |
|
gunzip_nomem1: |
|
return rc; /* returns Z_OK (0) if successful */ |
|
} |
|
|
|
#ifndef PREBOOT |
|
STATIC int INIT gunzip(unsigned char *buf, long len, |
|
long (*fill)(void*, unsigned long), |
|
long (*flush)(void*, unsigned long), |
|
unsigned char *out_buf, |
|
long *pos, |
|
void (*error)(char *x)) |
|
{ |
|
return __gunzip(buf, len, fill, flush, out_buf, 0, pos, error); |
|
} |
|
#else |
|
STATIC int INIT __decompress(unsigned char *buf, long len, |
|
long (*fill)(void*, unsigned long), |
|
long (*flush)(void*, unsigned long), |
|
unsigned char *out_buf, long out_len, |
|
long *pos, |
|
void (*error)(char *x)) |
|
{ |
|
return __gunzip(buf, len, fill, flush, out_buf, out_len, pos, error); |
|
} |
|
#endif
|
|
|