1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2bc22c17eSAlain Knaff #ifdef STATIC
32d3862d2SYinghai Lu #define PREBOOT
4bc22c17eSAlain Knaff /* Pre-boot environment: included */
5bc22c17eSAlain Knaff
6bc22c17eSAlain Knaff /* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots
7bc22c17eSAlain Knaff * errors about console_printk etc... on ARM */
8bc22c17eSAlain Knaff #define _LINUX_KERNEL_H
9bc22c17eSAlain Knaff
10bc22c17eSAlain Knaff #include "zlib_inflate/inftrees.c"
11bc22c17eSAlain Knaff #include "zlib_inflate/inffast.c"
12bc22c17eSAlain Knaff #include "zlib_inflate/inflate.c"
1312619610SMikhail Zaslonko #ifdef CONFIG_ZLIB_DFLTCC
1412619610SMikhail Zaslonko #include "zlib_dfltcc/dfltcc.c"
1512619610SMikhail Zaslonko #include "zlib_dfltcc/dfltcc_inflate.c"
1612619610SMikhail Zaslonko #endif
17bc22c17eSAlain Knaff
18bc22c17eSAlain Knaff #else /* STATIC */
19bc22c17eSAlain Knaff /* initramfs et al: linked */
20bc22c17eSAlain Knaff
21bc22c17eSAlain Knaff #include <linux/zutil.h>
22bc22c17eSAlain Knaff
23bc22c17eSAlain Knaff #include "zlib_inflate/inftrees.h"
24bc22c17eSAlain Knaff #include "zlib_inflate/inffast.h"
25bc22c17eSAlain Knaff #include "zlib_inflate/inflate.h"
26bc22c17eSAlain Knaff
27bc22c17eSAlain Knaff #include "zlib_inflate/infutil.h"
28af661e83SRashika Kheria #include <linux/decompress/inflate.h>
29bc22c17eSAlain Knaff
30bc22c17eSAlain Knaff #endif /* STATIC */
31bc22c17eSAlain Knaff
32bc22c17eSAlain Knaff #include <linux/decompress/mm.h>
33bc22c17eSAlain Knaff
34daeb6b6fSPhillip Lougher #define GZIP_IOBUF_SIZE (16*1024)
35bc22c17eSAlain Knaff
nofill(void * buffer,unsigned long len)36d97b07c5SYinghai Lu static long INIT nofill(void *buffer, unsigned long len)
376a881162SPhillip Lougher {
386a881162SPhillip Lougher return -1;
396a881162SPhillip Lougher }
406a881162SPhillip Lougher
41bc22c17eSAlain Knaff /* Included from initramfs et al code */
__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))42*00444448SArnd Bergmann static int INIT __gunzip(unsigned char *buf, long len,
43d97b07c5SYinghai Lu long (*fill)(void*, unsigned long),
44d97b07c5SYinghai Lu long (*flush)(void*, unsigned long),
452d3862d2SYinghai Lu unsigned char *out_buf, long out_len,
46d97b07c5SYinghai Lu long *pos,
4793685ad2SLasse Collin void(*error)(char *x)) {
48bc22c17eSAlain Knaff u8 *zbuf;
49bc22c17eSAlain Knaff struct z_stream_s *strm;
50bc22c17eSAlain Knaff int rc;
51bc22c17eSAlain Knaff
52bc22c17eSAlain Knaff rc = -1;
53bc22c17eSAlain Knaff if (flush) {
545619448fSH. Peter Anvin out_len = 0x8000; /* 32 K */
55bc22c17eSAlain Knaff out_buf = malloc(out_len);
56bc22c17eSAlain Knaff } else {
572d3862d2SYinghai Lu if (!out_len)
581431574aSAlexandre Courbot out_len = ((size_t)~0) - (size_t)out_buf; /* no limit */
59bc22c17eSAlain Knaff }
60bc22c17eSAlain Knaff if (!out_buf) {
61bc22c17eSAlain Knaff error("Out of memory while allocating output buffer");
62bc22c17eSAlain Knaff goto gunzip_nomem1;
63bc22c17eSAlain Knaff }
64bc22c17eSAlain Knaff
65bc22c17eSAlain Knaff if (buf)
66bc22c17eSAlain Knaff zbuf = buf;
67bc22c17eSAlain Knaff else {
68daeb6b6fSPhillip Lougher zbuf = malloc(GZIP_IOBUF_SIZE);
69bc22c17eSAlain Knaff len = 0;
70bc22c17eSAlain Knaff }
71bc22c17eSAlain Knaff if (!zbuf) {
72bc22c17eSAlain Knaff error("Out of memory while allocating input buffer");
73bc22c17eSAlain Knaff goto gunzip_nomem2;
74bc22c17eSAlain Knaff }
75bc22c17eSAlain Knaff
76bc22c17eSAlain Knaff strm = malloc(sizeof(*strm));
77bc22c17eSAlain Knaff if (strm == NULL) {
78bc22c17eSAlain Knaff error("Out of memory while allocating z_stream");
79bc22c17eSAlain Knaff goto gunzip_nomem3;
80bc22c17eSAlain Knaff }
81bc22c17eSAlain Knaff
82bc22c17eSAlain Knaff strm->workspace = malloc(flush ? zlib_inflate_workspacesize() :
8312619610SMikhail Zaslonko #ifdef CONFIG_ZLIB_DFLTCC
8412619610SMikhail Zaslonko /* Always allocate the full workspace for DFLTCC */
8512619610SMikhail Zaslonko zlib_inflate_workspacesize());
8612619610SMikhail Zaslonko #else
87bc22c17eSAlain Knaff sizeof(struct inflate_state));
8812619610SMikhail Zaslonko #endif
89bc22c17eSAlain Knaff if (strm->workspace == NULL) {
90bc22c17eSAlain Knaff error("Out of memory while allocating workspace");
91bc22c17eSAlain Knaff goto gunzip_nomem4;
92bc22c17eSAlain Knaff }
93bc22c17eSAlain Knaff
946a881162SPhillip Lougher if (!fill)
956a881162SPhillip Lougher fill = nofill;
966a881162SPhillip Lougher
97bc22c17eSAlain Knaff if (len == 0)
98daeb6b6fSPhillip Lougher len = fill(zbuf, GZIP_IOBUF_SIZE);
99bc22c17eSAlain Knaff
100bc22c17eSAlain Knaff /* verify the gzip header */
101bc22c17eSAlain Knaff if (len < 10 ||
102bc22c17eSAlain Knaff zbuf[0] != 0x1f || zbuf[1] != 0x8b || zbuf[2] != 0x08) {
103bc22c17eSAlain Knaff if (pos)
104bc22c17eSAlain Knaff *pos = 0;
105bc22c17eSAlain Knaff error("Not a gzip file");
106bc22c17eSAlain Knaff goto gunzip_5;
107bc22c17eSAlain Knaff }
108bc22c17eSAlain Knaff
109bc22c17eSAlain Knaff /* skip over gzip header (1f,8b,08... 10 bytes total +
110bc22c17eSAlain Knaff * possible asciz filename)
111bc22c17eSAlain Knaff */
112bc22c17eSAlain Knaff strm->next_in = zbuf + 10;
1131da914e0SLasse Collin strm->avail_in = len - 10;
114bc22c17eSAlain Knaff /* skip over asciz filename */
115bc22c17eSAlain Knaff if (zbuf[3] & 0x8) {
1161da914e0SLasse Collin do {
1171da914e0SLasse Collin /*
1181da914e0SLasse Collin * If the filename doesn't fit into the buffer,
1191da914e0SLasse Collin * the file is very probably corrupt. Don't try
1201da914e0SLasse Collin * to read more data.
1211da914e0SLasse Collin */
1221da914e0SLasse Collin if (strm->avail_in == 0) {
1231da914e0SLasse Collin error("header error");
1241da914e0SLasse Collin goto gunzip_5;
125bc22c17eSAlain Knaff }
1261da914e0SLasse Collin --strm->avail_in;
1271da914e0SLasse Collin } while (*strm->next_in++);
1281da914e0SLasse Collin }
129bc22c17eSAlain Knaff
130bc22c17eSAlain Knaff strm->next_out = out_buf;
131bc22c17eSAlain Knaff strm->avail_out = out_len;
132bc22c17eSAlain Knaff
133bc22c17eSAlain Knaff rc = zlib_inflateInit2(strm, -MAX_WBITS);
134bc22c17eSAlain Knaff
13512619610SMikhail Zaslonko #ifdef CONFIG_ZLIB_DFLTCC
13612619610SMikhail Zaslonko /* Always keep the window for DFLTCC */
13712619610SMikhail Zaslonko #else
138bc22c17eSAlain Knaff if (!flush) {
139bc22c17eSAlain Knaff WS(strm)->inflate_state.wsize = 0;
140bc22c17eSAlain Knaff WS(strm)->inflate_state.window = NULL;
141bc22c17eSAlain Knaff }
14212619610SMikhail Zaslonko #endif
143bc22c17eSAlain Knaff
144bc22c17eSAlain Knaff while (rc == Z_OK) {
145bc22c17eSAlain Knaff if (strm->avail_in == 0) {
146bc22c17eSAlain Knaff /* TODO: handle case where both pos and fill are set */
147daeb6b6fSPhillip Lougher len = fill(zbuf, GZIP_IOBUF_SIZE);
148bc22c17eSAlain Knaff if (len < 0) {
149bc22c17eSAlain Knaff rc = -1;
150bc22c17eSAlain Knaff error("read error");
151bc22c17eSAlain Knaff break;
152bc22c17eSAlain Knaff }
153bc22c17eSAlain Knaff strm->next_in = zbuf;
154bc22c17eSAlain Knaff strm->avail_in = len;
155bc22c17eSAlain Knaff }
156bc22c17eSAlain Knaff rc = zlib_inflate(strm, 0);
157bc22c17eSAlain Knaff
158bc22c17eSAlain Knaff /* Write any data generated */
159bc22c17eSAlain Knaff if (flush && strm->next_out > out_buf) {
160d97b07c5SYinghai Lu long l = strm->next_out - out_buf;
161bc22c17eSAlain Knaff if (l != flush(out_buf, l)) {
162bc22c17eSAlain Knaff rc = -1;
163bc22c17eSAlain Knaff error("write error");
164bc22c17eSAlain Knaff break;
165bc22c17eSAlain Knaff }
166bc22c17eSAlain Knaff strm->next_out = out_buf;
167bc22c17eSAlain Knaff strm->avail_out = out_len;
168bc22c17eSAlain Knaff }
169bc22c17eSAlain Knaff
170bc22c17eSAlain Knaff /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
171bc22c17eSAlain Knaff if (rc == Z_STREAM_END) {
172bc22c17eSAlain Knaff rc = 0;
173bc22c17eSAlain Knaff break;
174bc22c17eSAlain Knaff } else if (rc != Z_OK) {
175bc22c17eSAlain Knaff error("uncompression error");
176bc22c17eSAlain Knaff rc = -1;
177bc22c17eSAlain Knaff }
178bc22c17eSAlain Knaff }
179bc22c17eSAlain Knaff
180bc22c17eSAlain Knaff zlib_inflateEnd(strm);
181bc22c17eSAlain Knaff if (pos)
182bc22c17eSAlain Knaff /* add + 8 to skip over trailer */
183bc22c17eSAlain Knaff *pos = strm->next_in - zbuf+8;
184bc22c17eSAlain Knaff
185bc22c17eSAlain Knaff gunzip_5:
186bc22c17eSAlain Knaff free(strm->workspace);
187bc22c17eSAlain Knaff gunzip_nomem4:
188bc22c17eSAlain Knaff free(strm);
189bc22c17eSAlain Knaff gunzip_nomem3:
190bc22c17eSAlain Knaff if (!buf)
191bc22c17eSAlain Knaff free(zbuf);
192bc22c17eSAlain Knaff gunzip_nomem2:
193bc22c17eSAlain Knaff if (flush)
194bc22c17eSAlain Knaff free(out_buf);
195bc22c17eSAlain Knaff gunzip_nomem1:
196bc22c17eSAlain Knaff return rc; /* returns Z_OK (0) if successful */
197bc22c17eSAlain Knaff }
198bc22c17eSAlain Knaff
1992d3862d2SYinghai Lu #ifndef PREBOOT
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))2002d3862d2SYinghai Lu STATIC int INIT gunzip(unsigned char *buf, long len,
2012d3862d2SYinghai Lu long (*fill)(void*, unsigned long),
2022d3862d2SYinghai Lu long (*flush)(void*, unsigned long),
2032d3862d2SYinghai Lu unsigned char *out_buf,
2042d3862d2SYinghai Lu long *pos,
2052d3862d2SYinghai Lu void (*error)(char *x))
2062d3862d2SYinghai Lu {
2072d3862d2SYinghai Lu return __gunzip(buf, len, fill, flush, out_buf, 0, pos, error);
2082d3862d2SYinghai Lu }
2092d3862d2SYinghai Lu #else
__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))2102d3862d2SYinghai Lu STATIC int INIT __decompress(unsigned char *buf, long len,
2112d3862d2SYinghai Lu long (*fill)(void*, unsigned long),
2122d3862d2SYinghai Lu long (*flush)(void*, unsigned long),
2132d3862d2SYinghai Lu unsigned char *out_buf, long out_len,
2142d3862d2SYinghai Lu long *pos,
2152d3862d2SYinghai Lu void (*error)(char *x))
2162d3862d2SYinghai Lu {
2172d3862d2SYinghai Lu return __gunzip(buf, len, fill, flush, out_buf, out_len, pos, error);
2182d3862d2SYinghai Lu }
2192d3862d2SYinghai Lu #endif
220