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