Line data Source code
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 :
36 0 : static long INIT nofill(void *buffer, unsigned long len)
37 : {
38 0 : return -1;
39 : }
40 :
41 : /* Included from initramfs et al code */
42 0 : STATIC 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 0 : u8 *zbuf;
49 0 : struct z_stream_s *strm;
50 0 : int rc;
51 :
52 0 : rc = -1;
53 0 : if (flush) {
54 0 : out_len = 0x8000; /* 32 K */
55 0 : out_buf = malloc(out_len);
56 : } else {
57 0 : if (!out_len)
58 0 : out_len = ((size_t)~0) - (size_t)out_buf; /* no limit */
59 : }
60 0 : if (!out_buf) {
61 0 : error("Out of memory while allocating output buffer");
62 0 : goto gunzip_nomem1;
63 : }
64 :
65 0 : if (buf)
66 : zbuf = buf;
67 : else {
68 0 : zbuf = malloc(GZIP_IOBUF_SIZE);
69 0 : len = 0;
70 : }
71 0 : if (!zbuf) {
72 0 : error("Out of memory while allocating input buffer");
73 0 : goto gunzip_nomem2;
74 : }
75 :
76 0 : strm = malloc(sizeof(*strm));
77 0 : if (strm == NULL) {
78 0 : error("Out of memory while allocating z_stream");
79 0 : goto gunzip_nomem3;
80 : }
81 :
82 0 : 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 0 : if (strm->workspace == NULL) {
90 0 : error("Out of memory while allocating workspace");
91 0 : goto gunzip_nomem4;
92 : }
93 :
94 0 : if (!fill)
95 0 : fill = nofill;
96 :
97 0 : if (len == 0)
98 0 : len = fill(zbuf, GZIP_IOBUF_SIZE);
99 :
100 : /* verify the gzip header */
101 0 : if (len < 10 ||
102 0 : zbuf[0] != 0x1f || zbuf[1] != 0x8b || zbuf[2] != 0x08) {
103 0 : if (pos)
104 0 : *pos = 0;
105 0 : error("Not a gzip file");
106 0 : goto gunzip_5;
107 : }
108 :
109 : /* skip over gzip header (1f,8b,08... 10 bytes total +
110 : * possible asciz filename)
111 : */
112 0 : strm->next_in = zbuf + 10;
113 0 : strm->avail_in = len - 10;
114 : /* skip over asciz filename */
115 0 : if (zbuf[3] & 0x8) {
116 0 : 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 0 : if (strm->avail_in == 0) {
123 0 : error("header error");
124 0 : goto gunzip_5;
125 : }
126 0 : --strm->avail_in;
127 0 : } while (*strm->next_in++);
128 : }
129 :
130 0 : strm->next_out = out_buf;
131 0 : strm->avail_out = out_len;
132 :
133 0 : rc = zlib_inflateInit2(strm, -MAX_WBITS);
134 :
135 : #ifdef CONFIG_ZLIB_DFLTCC
136 : /* Always keep the window for DFLTCC */
137 : #else
138 0 : if (!flush) {
139 0 : WS(strm)->inflate_state.wsize = 0;
140 0 : WS(strm)->inflate_state.window = NULL;
141 : }
142 : #endif
143 :
144 0 : while (rc == Z_OK) {
145 0 : if (strm->avail_in == 0) {
146 : /* TODO: handle case where both pos and fill are set */
147 0 : len = fill(zbuf, GZIP_IOBUF_SIZE);
148 0 : if (len < 0) {
149 0 : rc = -1;
150 0 : error("read error");
151 0 : break;
152 : }
153 0 : strm->next_in = zbuf;
154 0 : strm->avail_in = len;
155 : }
156 0 : rc = zlib_inflate(strm, 0);
157 :
158 : /* Write any data generated */
159 0 : if (flush && strm->next_out > out_buf) {
160 0 : long l = strm->next_out - out_buf;
161 0 : if (l != flush(out_buf, l)) {
162 0 : rc = -1;
163 0 : error("write error");
164 0 : break;
165 : }
166 0 : strm->next_out = out_buf;
167 0 : strm->avail_out = out_len;
168 : }
169 :
170 : /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
171 0 : if (rc == Z_STREAM_END) {
172 : rc = 0;
173 : break;
174 0 : } else if (rc != Z_OK) {
175 0 : error("uncompression error");
176 0 : rc = -1;
177 : }
178 : }
179 :
180 0 : zlib_inflateEnd(strm);
181 0 : if (pos)
182 : /* add + 8 to skip over trailer */
183 0 : *pos = strm->next_in - zbuf+8;
184 :
185 0 : gunzip_5:
186 0 : free(strm->workspace);
187 0 : gunzip_nomem4:
188 0 : free(strm);
189 0 : gunzip_nomem3:
190 0 : if (!buf)
191 0 : free(zbuf);
192 0 : gunzip_nomem2:
193 0 : if (flush)
194 0 : free(out_buf);
195 0 : gunzip_nomem1:
196 0 : return rc; /* returns Z_OK (0) if successful */
197 : }
198 :
199 : #ifndef PREBOOT
200 0 : STATIC 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 0 : return __gunzip(buf, len, fill, flush, out_buf, 0, pos, error);
208 : }
209 : #else
210 : STATIC 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
|