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 | static long INIT nofill(void *buffer, unsigned long len) |
37 | { |
38 | return -1; |
39 | } |
40 | |
41 | /* Included from initramfs et al code */ |
42 | 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 | 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(size: 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(size: 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(size: 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, windowBits: -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, flush: 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 | |
185 | gunzip_5: |
186 | free(where: strm->workspace); |
187 | gunzip_nomem4: |
188 | free(where: strm); |
189 | gunzip_nomem3: |
190 | if (!buf) |
191 | free(where: zbuf); |
192 | gunzip_nomem2: |
193 | if (flush) |
194 | free(where: out_buf); |
195 | gunzip_nomem1: |
196 | return rc; /* returns Z_OK (0) if successful */ |
197 | } |
198 | |
199 | #ifndef PREBOOT |
200 | 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 | 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 |
220 | |