gzboot.c revision 1.5.2.3 1 1.5.2.3 nathanw /* $NetBSD: gzboot.c,v 1.5.2.3 2002/06/20 03:38:35 nathanw Exp $ */
2 1.5.2.2 nathanw
3 1.5.2.2 nathanw /*
4 1.5.2.2 nathanw * Copyright (c) 2002 Wasabi Systems, Inc.
5 1.5.2.2 nathanw * All rights reserved.
6 1.5.2.2 nathanw *
7 1.5.2.2 nathanw * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 1.5.2.2 nathanw *
9 1.5.2.2 nathanw * Redistribution and use in source and binary forms, with or without
10 1.5.2.2 nathanw * modification, are permitted provided that the following conditions
11 1.5.2.2 nathanw * are met:
12 1.5.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
13 1.5.2.2 nathanw * notice, this list of conditions and the following disclaimer.
14 1.5.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
15 1.5.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
16 1.5.2.2 nathanw * documentation and/or other materials provided with the distribution.
17 1.5.2.2 nathanw * 3. All advertising materials mentioning features or use of this software
18 1.5.2.2 nathanw * must display the following acknowledgement:
19 1.5.2.2 nathanw * This product includes software developed for the NetBSD Project by
20 1.5.2.2 nathanw * Wasabi Systems, Inc.
21 1.5.2.2 nathanw * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 1.5.2.2 nathanw * or promote products derived from this software without specific prior
23 1.5.2.2 nathanw * written permission.
24 1.5.2.2 nathanw *
25 1.5.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 1.5.2.2 nathanw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.5.2.2 nathanw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.5.2.2 nathanw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 1.5.2.2 nathanw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.5.2.2 nathanw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.5.2.2 nathanw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.5.2.2 nathanw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.5.2.2 nathanw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.5.2.2 nathanw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.5.2.2 nathanw * POSSIBILITY OF SUCH DAMAGE.
36 1.5.2.2 nathanw */
37 1.5.2.2 nathanw
38 1.5.2.2 nathanw /*
39 1.5.2.2 nathanw * The Gzip header parser and libz interface glue are derived from
40 1.5.2.2 nathanw * sys/lib/libsa/cread.c, which carries the following notice:
41 1.5.2.2 nathanw *
42 1.5.2.2 nathanw * Copyright (c) 1996
43 1.5.2.2 nathanw * Matthias Drochner. All rights reserved.
44 1.5.2.2 nathanw *
45 1.5.2.2 nathanw * Redistribution and use in source and binary forms, with or without
46 1.5.2.2 nathanw * modification, are permitted provided that the following conditions
47 1.5.2.2 nathanw * are met:
48 1.5.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
49 1.5.2.2 nathanw * notice, this list of conditions and the following disclaimer.
50 1.5.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
51 1.5.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
52 1.5.2.2 nathanw * documentation and/or other materials provided with the distribution.
53 1.5.2.2 nathanw * 3. All advertising materials mentioning features or use of this software
54 1.5.2.2 nathanw * must display the following acknowledgement:
55 1.5.2.2 nathanw * This product includes software developed for the NetBSD Project
56 1.5.2.2 nathanw * by Matthias Drochner.
57 1.5.2.2 nathanw * 4. The name of the author may not be used to endorse or promote products
58 1.5.2.2 nathanw * derived from this software without specific prior written permission.
59 1.5.2.2 nathanw *
60 1.5.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
61 1.5.2.2 nathanw * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
62 1.5.2.2 nathanw * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
63 1.5.2.2 nathanw * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
64 1.5.2.2 nathanw * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
65 1.5.2.2 nathanw * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
66 1.5.2.2 nathanw * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
67 1.5.2.2 nathanw * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68 1.5.2.2 nathanw * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
69 1.5.2.2 nathanw * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70 1.5.2.2 nathanw */
71 1.5.2.2 nathanw
72 1.5.2.2 nathanw #include <sys/param.h>
73 1.5.2.2 nathanw #include <lib/libsa/stand.h>
74 1.5.2.2 nathanw #include <lib/libkern/libkern.h>
75 1.5.2.2 nathanw #include <lib/libz/zlib.h>
76 1.5.2.2 nathanw
77 1.5.2.2 nathanw #include "board.h"
78 1.5.2.2 nathanw #include "gzboot.h"
79 1.5.2.2 nathanw
80 1.5.2.2 nathanw /* zlib glue defns */
81 1.5.2.2 nathanw
82 1.5.2.2 nathanw #define EOF (-1) /* needed by compression code */
83 1.5.2.2 nathanw
84 1.5.2.2 nathanw #define Z_BUFSIZE 1024
85 1.5.2.2 nathanw
86 1.5.2.2 nathanw static const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
87 1.5.2.2 nathanw
88 1.5.2.2 nathanw /* gzip flag byte */
89 1.5.2.2 nathanw #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
90 1.5.2.2 nathanw #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
91 1.5.2.2 nathanw #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
92 1.5.2.2 nathanw #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
93 1.5.2.2 nathanw #define COMMENT 0x10 /* bit 4 set: file comment present */
94 1.5.2.2 nathanw #define RESERVED 0xe0 /* bits 5..7: reserved */
95 1.5.2.2 nathanw
96 1.5.2.2 nathanw struct state {
97 1.5.2.2 nathanw z_stream stream;
98 1.5.2.2 nathanw int z_err; /* error code for last stream operation */
99 1.5.2.2 nathanw int z_eof; /* set of end of input file */
100 1.5.2.2 nathanw const unsigned char *srcbuf;/* source buffer */
101 1.5.2.2 nathanw size_t srcoff; /* source buffer offset */
102 1.5.2.2 nathanw size_t srcsize;/* size of source buffer */
103 1.5.2.2 nathanw unsigned char *inbuf; /* input buffer */
104 1.5.2.2 nathanw uint32_t crc; /* crc32 of uncompressed data */
105 1.5.2.2 nathanw int spinny; /* twiddle every N reads */
106 1.5.2.2 nathanw };
107 1.5.2.2 nathanw
108 1.5.2.2 nathanw static uint32_t get_u8(struct state *);
109 1.5.2.2 nathanw static uint32_t get_u32(struct state *);
110 1.5.2.2 nathanw static int check_header(struct state *);
111 1.5.2.2 nathanw
112 1.5.2.2 nathanw /* XXX - find a suitable header for these: */
113 1.5.2.2 nathanw void zmemcpy(unsigned char *, unsigned char *, unsigned int);
114 1.5.2.2 nathanw
115 1.5.2.2 nathanw /* end zlib glue defns */
116 1.5.2.2 nathanw
117 1.5.2.2 nathanw void main(void);
118 1.5.2.2 nathanw void gzcopy(void *, const void *, size_t);
119 1.5.2.2 nathanw
120 1.5.2.2 nathanw void
121 1.5.2.2 nathanw main(void)
122 1.5.2.2 nathanw {
123 1.5.2.2 nathanw extern char bootprog_name[], bootprog_rev[],
124 1.5.2.2 nathanw bootprog_maker[], bootprog_date[];
125 1.5.2.2 nathanw void (*loadaddr)(void) = (void *) md_root_loadaddr;
126 1.5.2.2 nathanw
127 1.5.2.2 nathanw cons_init();
128 1.5.2.2 nathanw
129 1.5.2.2 nathanw printf("\n");
130 1.5.2.2 nathanw printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
131 1.5.2.2 nathanw printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
132 1.5.2.2 nathanw
133 1.5.2.3 nathanw board_init();
134 1.5.2.2 nathanw
135 1.5.2.2 nathanw printf(">> Load address: 0x%x\n", md_root_loadaddr);
136 1.5.2.2 nathanw printf(">> Image size: %u\n", md_root_size);
137 1.5.2.2 nathanw
138 1.5.2.2 nathanw printf("Uncompressing image...");
139 1.5.2.2 nathanw gzcopy((void *) loadaddr, md_root_image, md_root_size);
140 1.5.2.2 nathanw printf("done.\n");
141 1.5.2.2 nathanw
142 1.5.2.2 nathanw printf("Jumping to image @ 0x%x...\n", md_root_loadaddr);
143 1.5.2.3 nathanw
144 1.5.2.3 nathanw board_fini();
145 1.5.2.3 nathanw
146 1.5.2.2 nathanw (*loadaddr)();
147 1.5.2.2 nathanw
148 1.5.2.2 nathanw _rtt();
149 1.5.2.2 nathanw }
150 1.5.2.2 nathanw
151 1.5.2.2 nathanw void abort(void);
152 1.5.2.2 nathanw void
153 1.5.2.2 nathanw abort(void)
154 1.5.2.2 nathanw {
155 1.5.2.2 nathanw
156 1.5.2.2 nathanw for (;;) ;
157 1.5.2.2 nathanw }
158 1.5.2.2 nathanw
159 1.5.2.2 nathanw __dead void
160 1.5.2.2 nathanw _rtt(void)
161 1.5.2.2 nathanw {
162 1.5.2.2 nathanw
163 1.5.2.2 nathanw for (;;) ;
164 1.5.2.2 nathanw }
165 1.5.2.2 nathanw
166 1.5.2.2 nathanw /* internal utility routines */
167 1.5.2.2 nathanw
168 1.5.2.2 nathanw static ssize_t
169 1.5.2.2 nathanw readbuf(struct state *s, void *buf, size_t len)
170 1.5.2.2 nathanw {
171 1.5.2.2 nathanw
172 1.5.2.2 nathanw if (len > (s->srcsize - s->srcoff))
173 1.5.2.2 nathanw len = s->srcsize - s->srcoff;
174 1.5.2.2 nathanw
175 1.5.2.2 nathanw if ((s->spinny++ & 7) == 0)
176 1.5.2.2 nathanw twiddle();
177 1.5.2.2 nathanw bcopy(s->srcbuf + s->srcoff, buf, len);
178 1.5.2.2 nathanw s->srcoff += len;
179 1.5.2.2 nathanw
180 1.5.2.2 nathanw return (len);
181 1.5.2.2 nathanw }
182 1.5.2.2 nathanw
183 1.5.2.2 nathanw static ssize_t
184 1.5.2.2 nathanw readgz(struct state *s, void *buf, size_t len)
185 1.5.2.2 nathanw {
186 1.5.2.2 nathanw unsigned char *start = buf; /* start for CRC computation */
187 1.5.2.2 nathanw
188 1.5.2.2 nathanw if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
189 1.5.2.2 nathanw return (-1);
190 1.5.2.2 nathanw if (s->z_err == Z_STREAM_END)
191 1.5.2.2 nathanw return (0); /* EOF */
192 1.5.2.2 nathanw
193 1.5.2.2 nathanw s->stream.next_out = buf;
194 1.5.2.2 nathanw s->stream.avail_out = len;
195 1.5.2.2 nathanw
196 1.5.2.2 nathanw while (s->stream.avail_out != 0) {
197 1.5.2.2 nathanw if (s->stream.avail_in == 0 && s->z_eof == 0) {
198 1.5.2.2 nathanw ssize_t got;
199 1.5.2.2 nathanw got = readbuf(s, s->inbuf, Z_BUFSIZE);
200 1.5.2.2 nathanw if (got <= 0)
201 1.5.2.2 nathanw s->z_eof = 1;
202 1.5.2.2 nathanw s->stream.avail_in = got;
203 1.5.2.2 nathanw s->stream.next_in = s->inbuf;
204 1.5.2.2 nathanw }
205 1.5.2.2 nathanw
206 1.5.2.2 nathanw s->z_err = inflate(&s->stream, Z_NO_FLUSH);
207 1.5.2.2 nathanw
208 1.5.2.2 nathanw if (s->z_err == Z_STREAM_END) {
209 1.5.2.2 nathanw /* Check CRC and original size */
210 1.5.2.2 nathanw s->crc = crc32(s->crc, start, (unsigned int)
211 1.5.2.2 nathanw (s->stream.next_out - start));
212 1.5.2.2 nathanw start = s->stream.next_out;
213 1.5.2.2 nathanw
214 1.5.2.2 nathanw if (get_u32(s) != s->crc) {
215 1.5.2.2 nathanw printf("FATAL: CRC checksum mismatch\n");
216 1.5.2.2 nathanw s->z_err = Z_DATA_ERROR;
217 1.5.2.2 nathanw }
218 1.5.2.2 nathanw if (get_u32(s) != s->stream.total_out) {
219 1.5.2.2 nathanw printf("FATAL: total output mismatch\n");
220 1.5.2.2 nathanw s->z_err = Z_DATA_ERROR;
221 1.5.2.2 nathanw }
222 1.5.2.2 nathanw s->z_eof = 1;
223 1.5.2.2 nathanw }
224 1.5.2.2 nathanw if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) {
225 1.5.2.2 nathanw printf("FATAL: error %d from zlib\n",
226 1.5.2.2 nathanw s->z_err);
227 1.5.2.2 nathanw return (-1);
228 1.5.2.2 nathanw }
229 1.5.2.2 nathanw if (s->z_err != Z_OK || s->z_eof)
230 1.5.2.2 nathanw break;
231 1.5.2.2 nathanw }
232 1.5.2.2 nathanw
233 1.5.2.2 nathanw s->crc = crc32(s->crc, start,
234 1.5.2.2 nathanw (unsigned int)(s->stream.next_out - start));
235 1.5.2.2 nathanw
236 1.5.2.2 nathanw return ((ssize_t) (len - s->stream.avail_out));
237 1.5.2.2 nathanw }
238 1.5.2.2 nathanw
239 1.5.2.2 nathanw /* util routines for zlib */
240 1.5.2.2 nathanw
241 1.5.2.2 nathanw void
242 1.5.2.2 nathanw zmemcpy(unsigned char *dst, unsigned char *src, unsigned int len)
243 1.5.2.2 nathanw {
244 1.5.2.2 nathanw
245 1.5.2.2 nathanw bcopy(src, dst, len);
246 1.5.2.2 nathanw }
247 1.5.2.2 nathanw
248 1.5.2.2 nathanw /* gzip utility routines */
249 1.5.2.2 nathanw
250 1.5.2.2 nathanw static uint32_t
251 1.5.2.2 nathanw get_u8(struct state *s)
252 1.5.2.2 nathanw {
253 1.5.2.2 nathanw
254 1.5.2.2 nathanw if (s->z_eof)
255 1.5.2.2 nathanw return (EOF);
256 1.5.2.2 nathanw
257 1.5.2.2 nathanw if (s->stream.avail_in == 0) {
258 1.5.2.2 nathanw ssize_t got;
259 1.5.2.2 nathanw
260 1.5.2.2 nathanw got = readbuf(s, s->inbuf, Z_BUFSIZE);
261 1.5.2.2 nathanw if (got <= 0) {
262 1.5.2.2 nathanw s->z_eof = 1;
263 1.5.2.2 nathanw return (EOF);
264 1.5.2.2 nathanw }
265 1.5.2.2 nathanw s->stream.avail_in = got;
266 1.5.2.2 nathanw s->stream.next_in = s->inbuf;
267 1.5.2.2 nathanw }
268 1.5.2.2 nathanw s->stream.avail_in--;
269 1.5.2.2 nathanw return (*(s->stream.next_in)++);
270 1.5.2.2 nathanw }
271 1.5.2.2 nathanw
272 1.5.2.2 nathanw static uint32_t
273 1.5.2.2 nathanw get_u32(struct state *s)
274 1.5.2.2 nathanw {
275 1.5.2.2 nathanw uint32_t x, c;
276 1.5.2.2 nathanw
277 1.5.2.2 nathanw x = get_u8(s);
278 1.5.2.2 nathanw x |= get_u8(s) << 8;
279 1.5.2.2 nathanw x |= get_u8(s) << 16;
280 1.5.2.2 nathanw c = get_u8(s);
281 1.5.2.2 nathanw if (c == EOF)
282 1.5.2.2 nathanw s->z_err = Z_DATA_ERROR;
283 1.5.2.2 nathanw x |= c << 24;
284 1.5.2.2 nathanw return (x);
285 1.5.2.2 nathanw }
286 1.5.2.2 nathanw
287 1.5.2.2 nathanw static int
288 1.5.2.2 nathanw check_header(struct state *s)
289 1.5.2.2 nathanw {
290 1.5.2.2 nathanw int method; /* method byte */
291 1.5.2.2 nathanw int flags; /* flags byte */
292 1.5.2.2 nathanw unsigned int len;
293 1.5.2.2 nathanw int c;
294 1.5.2.2 nathanw
295 1.5.2.2 nathanw /* Check the gzip magic header */
296 1.5.2.2 nathanw for (len = 0; len < 2; len++) {
297 1.5.2.2 nathanw c = get_u8(s);
298 1.5.2.2 nathanw if (c == gz_magic[len])
299 1.5.2.2 nathanw continue;
300 1.5.2.2 nathanw printf("FATAL: not a Gzip'd image\n");
301 1.5.2.2 nathanw return (1);
302 1.5.2.2 nathanw }
303 1.5.2.2 nathanw
304 1.5.2.2 nathanw method = get_u8(s);
305 1.5.2.2 nathanw flags = get_u8(s);
306 1.5.2.2 nathanw if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
307 1.5.2.2 nathanw printf("FATAL: invalid Gzip header\n");
308 1.5.2.2 nathanw return (1);
309 1.5.2.2 nathanw }
310 1.5.2.2 nathanw
311 1.5.2.2 nathanw /* Discard time, xflags, and OS code: */
312 1.5.2.2 nathanw for (len = 0; len < 6; len++)
313 1.5.2.2 nathanw (void) get_u8(s);
314 1.5.2.2 nathanw
315 1.5.2.2 nathanw if (flags & EXTRA_FIELD) {
316 1.5.2.2 nathanw /* skip the extra field */
317 1.5.2.2 nathanw len = get_u8(s);
318 1.5.2.2 nathanw len |= get_u8(s) << 8;
319 1.5.2.2 nathanw /* len is garbage if EOF, but the loop below will quit anyway */
320 1.5.2.2 nathanw while (len-- && get_u8(s) != EOF)
321 1.5.2.2 nathanw /* loop */;
322 1.5.2.2 nathanw }
323 1.5.2.2 nathanw if (flags & ORIG_NAME) {
324 1.5.2.2 nathanw /* skip the original file name */
325 1.5.2.2 nathanw while ((c = get_u8(s)) != 0 && c != EOF)
326 1.5.2.2 nathanw /* loop */;
327 1.5.2.2 nathanw }
328 1.5.2.2 nathanw if (flags & COMMENT) {
329 1.5.2.2 nathanw /* skip the file comment */
330 1.5.2.2 nathanw while ((c = get_u8(s)) != 0 && c != EOF)
331 1.5.2.2 nathanw /* loop */;
332 1.5.2.2 nathanw }
333 1.5.2.2 nathanw if (flags & HEAD_CRC) {
334 1.5.2.2 nathanw /* skip header CRC */
335 1.5.2.2 nathanw for (len = 0; len < 2; len++)
336 1.5.2.2 nathanw (void) get_u8(s);
337 1.5.2.2 nathanw }
338 1.5.2.2 nathanw
339 1.5.2.2 nathanw if (s->z_eof) {
340 1.5.2.2 nathanw printf("FATAL: end of image encountered parsing Gzip header\n");
341 1.5.2.2 nathanw return (1);
342 1.5.2.2 nathanw }
343 1.5.2.2 nathanw
344 1.5.2.2 nathanw /* OK! */
345 1.5.2.2 nathanw return (0);
346 1.5.2.2 nathanw }
347 1.5.2.2 nathanw
348 1.5.2.2 nathanw /* the actual gzcopy routine */
349 1.5.2.2 nathanw
350 1.5.2.2 nathanw void
351 1.5.2.2 nathanw gzcopy(void *dst, const void *src, size_t srclen)
352 1.5.2.2 nathanw {
353 1.5.2.2 nathanw struct state state;
354 1.5.2.2 nathanw unsigned char *cp = dst;
355 1.5.2.2 nathanw ssize_t len;
356 1.5.2.2 nathanw
357 1.5.2.2 nathanw bzero(&state, sizeof(state));
358 1.5.2.2 nathanw
359 1.5.2.2 nathanw state.z_err = Z_OK;
360 1.5.2.2 nathanw state.srcbuf = src;
361 1.5.2.2 nathanw state.srcsize = srclen;
362 1.5.2.2 nathanw
363 1.5.2.2 nathanw if (inflateInit2(&state.stream, -15) != Z_OK) {
364 1.5.2.2 nathanw printf("FATAL: inflateInit2 failed\n");
365 1.5.2.2 nathanw _rtt();
366 1.5.2.2 nathanw }
367 1.5.2.2 nathanw
368 1.5.2.2 nathanw state.stream.next_in = state.inbuf = alloc(Z_BUFSIZE);
369 1.5.2.2 nathanw if (state.inbuf == NULL) {
370 1.5.2.2 nathanw inflateEnd(&state.stream);
371 1.5.2.2 nathanw printf("FATAL: unable to allocate Z buffer\n");
372 1.5.2.2 nathanw _rtt();
373 1.5.2.2 nathanw }
374 1.5.2.2 nathanw
375 1.5.2.2 nathanw /* Skip the Gzip header. */
376 1.5.2.2 nathanw if (check_header(&state)) {
377 1.5.2.2 nathanw inflateEnd(&state.stream);
378 1.5.2.2 nathanw free(state.inbuf, Z_BUFSIZE);
379 1.5.2.2 nathanw _rtt();
380 1.5.2.2 nathanw }
381 1.5.2.2 nathanw
382 1.5.2.2 nathanw /* Uncompress the image! */
383 1.5.2.2 nathanw while ((len = readgz(&state, cp, Z_BUFSIZE)) > 0)
384 1.5.2.2 nathanw cp += len;
385 1.5.2.2 nathanw if (len == -1)
386 1.5.2.2 nathanw _rtt();
387 1.5.2.2 nathanw
388 1.5.2.2 nathanw /* All done! */
389 1.5.2.2 nathanw inflateEnd(&state.stream);
390 1.5.2.2 nathanw free(state.inbuf, Z_BUFSIZE);
391 1.5.2.2 nathanw }
392