Blame view

lib/gunzip.c 6.59 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
321359f20   Marian Balakowicz   [new uImage] Move...
2
3
4
  /*
   * (C) Copyright 2000-2006
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
321359f20   Marian Balakowicz   [new uImage] Move...
5
6
7
   */
  
  #include <common.h>
321359f20   Marian Balakowicz   [new uImage] Move...
8
  #include <command.h>
24b852a7a   Simon Glass   Move console defi...
9
  #include <console.h>
0c670fc14   Simon Glass   common: Move gzip...
10
11
  #include <div64.h>
  #include <gzip.h>
321359f20   Marian Balakowicz   [new uImage] Move...
12
13
  #include <image.h>
  #include <malloc.h>
d025021e9   Clemens Gruber   gunzip: cache-ali...
14
  #include <memalign.h>
3db711085   Simon Glass   crc32: Use the cr...
15
  #include <u-boot/crc.h>
0c670fc14   Simon Glass   common: Move gzip...
16
  #include <watchdog.h>
a31e091ad   Jean-Christophe PLAGNIOL-VILLARD   rename include/zl...
17
  #include <u-boot/zlib.h>
321359f20   Marian Balakowicz   [new uImage] Move...
18

918e9ebb4   Eric Nelson   gunzip: add gzwri...
19
20
  #define HEADER0			'\x1f'
  #define HEADER1			'\x8b'
321359f20   Marian Balakowicz   [new uImage] Move...
21
22
23
24
25
26
27
  #define	ZALLOC_ALIGNMENT	16
  #define HEAD_CRC		2
  #define EXTRA_FIELD		4
  #define ORIG_NAME		8
  #define COMMENT			0x10
  #define RESERVED		0xe0
  #define DEFLATED		8
e3ed0575a   Mike Frysinger   gunzip: rename z{...
28
  void *gzalloc(void *x, unsigned items, unsigned size)
321359f20   Marian Balakowicz   [new uImage] Move...
29
30
31
32
33
34
35
36
37
38
  {
  	void *p;
  
  	size *= items;
  	size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
  
  	p = malloc (size);
  
  	return (p);
  }
e3ed0575a   Mike Frysinger   gunzip: rename z{...
39
  void gzfree(void *x, void *addr, unsigned nb)
321359f20   Marian Balakowicz   [new uImage] Move...
40
41
42
  {
  	free (addr);
  }
376ddf9d4   Jean-Jacques Hiblot   gzip: add a funct...
43
  int gzip_parse_header(const unsigned char *src, unsigned long len)
321359f20   Marian Balakowicz   [new uImage] Move...
44
  {
35f6a943f   Ricardo Ribalda Delgado   lib_generic: gunz...
45
  	int i, flags;
321359f20   Marian Balakowicz   [new uImage] Move...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  
  	/* skip header */
  	i = 10;
  	flags = src[3];
  	if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
  		puts ("Error: Bad gzipped data
  ");
  		return (-1);
  	}
  	if ((flags & EXTRA_FIELD) != 0)
  		i = 12 + src[10] + (src[11] << 8);
  	if ((flags & ORIG_NAME) != 0)
  		while (src[i++] != 0)
  			;
  	if ((flags & COMMENT) != 0)
  		while (src[i++] != 0)
  			;
  	if ((flags & HEAD_CRC) != 0)
  		i += 2;
376ddf9d4   Jean-Jacques Hiblot   gzip: add a funct...
65
  	if (i >= len) {
321359f20   Marian Balakowicz   [new uImage] Move...
66
67
68
69
  		puts ("Error: gunzip out of data in header
  ");
  		return (-1);
  	}
376ddf9d4   Jean-Jacques Hiblot   gzip: add a funct...
70
71
72
73
74
75
76
77
78
  	return i;
  }
  
  int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp)
  {
  	int offset = gzip_parse_header(src, *lenp);
  
  	if (offset < 0)
  		return offset;
321359f20   Marian Balakowicz   [new uImage] Move...
79

376ddf9d4   Jean-Jacques Hiblot   gzip: add a funct...
80
  	return zunzip(dst, dstlen, src, lenp, 1, offset);
35f6a943f   Ricardo Ribalda Delgado   lib_generic: gunz...
81
  }
1811b7d38   Tom Rini   gunzip.c: Only in...
82
  #ifdef CONFIG_CMD_UNZIP
918e9ebb4   Eric Nelson   gunzip: add gzwri...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  __weak
  void gzwrite_progress_init(u64 expectedsize)
  {
  	putc('
  ');
  }
  
  __weak
  void gzwrite_progress(int iteration,
  		     u64 bytes_written,
  		     u64 total_bytes)
  {
  	if (0 == (iteration & 3))
  		printf("%llu/%llu\r", bytes_written, total_bytes);
  }
  
  __weak
  void gzwrite_progress_finish(int returnval,
  			     u64 bytes_written,
  			     u64 total_bytes,
  			     u32 expected_crc,
  			     u32 calculated_crc)
  {
  	if (0 == returnval) {
  		printf("
  \t%llu bytes, crc 0x%08x
  ",
  		       total_bytes, calculated_crc);
  	} else {
  		printf("
  \tuncompressed %llu of %llu
  "
  		       "\tcrcs == 0x%08x/0x%08x
  ",
  		       bytes_written, total_bytes,
  		       expected_crc, calculated_crc);
  	}
  }
  
  int gzwrite(unsigned char *src, int len,
4101f6879   Simon Glass   dm: Drop the bloc...
123
  	    struct blk_desc *dev,
918e9ebb4   Eric Nelson   gunzip: add gzwri...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  	    unsigned long szwritebuf,
  	    u64 startoffs,
  	    u64 szexpected)
  {
  	int i, flags;
  	z_stream s;
  	int r = 0;
  	unsigned char *writebuf;
  	unsigned crc = 0;
  	u64 totalfilled = 0;
  	lbaint_t blksperbuf, outblock;
  	u32 expected_crc;
  	u32 payload_size;
  	int iteration = 0;
  
  	if (!szwritebuf ||
  	    (szwritebuf % dev->blksz) ||
  	    (szwritebuf < dev->blksz)) {
  		printf("%s: size %lu not a multiple of %lu
  ",
  		       __func__, szwritebuf, dev->blksz);
  		return -1;
  	}
  
  	if (startoffs & (dev->blksz-1)) {
  		printf("%s: start offset %llu not a multiple of %lu
  ",
  		       __func__, startoffs, dev->blksz);
  		return -1;
  	}
  
  	blksperbuf = szwritebuf / dev->blksz;
  	outblock = lldiv(startoffs, dev->blksz);
  
  	/* skip header */
  	i = 10;
  	flags = src[3];
  	if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
  		puts("Error: Bad gzipped data
  ");
  		return -1;
  	}
  	if ((flags & EXTRA_FIELD) != 0)
  		i = 12 + src[10] + (src[11] << 8);
  	if ((flags & ORIG_NAME) != 0)
  		while (src[i++] != 0)
  			;
  	if ((flags & COMMENT) != 0)
  		while (src[i++] != 0)
  			;
  	if ((flags & HEAD_CRC) != 0)
  		i += 2;
  
  	if (i >= len-8) {
  		puts("Error: gunzip out of data in header");
  		return -1;
  	}
  
  	payload_size = len - i - 8;
  
  	memcpy(&expected_crc, src + len - 8, sizeof(expected_crc));
  	expected_crc = le32_to_cpu(expected_crc);
  	u32 szuncompressed;
  	memcpy(&szuncompressed, src + len - 4, sizeof(szuncompressed));
  	if (szexpected == 0) {
  		szexpected = le32_to_cpu(szuncompressed);
  	} else if (szuncompressed != (u32)szexpected) {
  		printf("size of %llx doesn't match trailer low bits %x
  ",
  		       szexpected, szuncompressed);
  		return -1;
  	}
  	if (lldiv(szexpected, dev->blksz) > (dev->lba - outblock)) {
  		printf("%s: uncompressed size %llu exceeds device size
  ",
  		       __func__, szexpected);
  		return -1;
  	}
  
  	gzwrite_progress_init(szexpected);
  
  	s.zalloc = gzalloc;
  	s.zfree = gzfree;
  
  	r = inflateInit2(&s, -MAX_WBITS);
  	if (r != Z_OK) {
  		printf("Error: inflateInit2() returned %d
  ", r);
  		return -1;
  	}
  
  	s.next_in = src + i;
  	s.avail_in = payload_size+8;
d025021e9   Clemens Gruber   gunzip: cache-ali...
217
  	writebuf = (unsigned char *)malloc_cache_aligned(szwritebuf);
918e9ebb4   Eric Nelson   gunzip: add gzwri...
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  
  	/* decompress until deflate stream ends or end of file */
  	do {
  		if (s.avail_in == 0) {
  			printf("%s: weird termination with result %d
  ",
  			       __func__, r);
  			break;
  		}
  
  		/* run inflate() on input until output buffer not full */
  		do {
  			unsigned long blocks_written;
  			int numfilled;
  			lbaint_t writeblocks;
  
  			s.avail_out = szwritebuf;
  			s.next_out = writebuf;
  			r = inflate(&s, Z_SYNC_FLUSH);
  			if ((r != Z_OK) &&
  			    (r != Z_STREAM_END)) {
  				printf("Error: inflate() returned %d
  ", r);
  				goto out;
  			}
  			numfilled = szwritebuf - s.avail_out;
  			crc = crc32(crc, writebuf, numfilled);
  			totalfilled += numfilled;
  			if (numfilled < szwritebuf) {
  				writeblocks = (numfilled+dev->blksz-1)
  						/ dev->blksz;
  				memset(writebuf+numfilled, 0,
  				       dev->blksz-(numfilled%dev->blksz));
  			} else {
  				writeblocks = blksperbuf;
  			}
  
  			gzwrite_progress(iteration++,
  					 totalfilled,
  					 szexpected);
6a3bf3e57   Eric Nelson   gunzip.c: use blo...
258
259
  			blocks_written = blk_dwrite(dev, outblock,
  						    writeblocks, writebuf);
918e9ebb4   Eric Nelson   gunzip: add gzwri...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  			outblock += blocks_written;
  			if (ctrlc()) {
  				puts("abort
  ");
  				goto out;
  			}
  			WATCHDOG_RESET();
  		} while (s.avail_out == 0);
  		/* done when inflate() says it's done */
  	} while (r != Z_STREAM_END);
  
  	if ((szexpected != totalfilled) ||
  	    (crc != expected_crc))
  		r = -1;
  	else
  		r = 0;
  
  out:
  	gzwrite_progress_finish(r, totalfilled, szexpected,
  				expected_crc, crc);
  	free(writebuf);
  	inflateEnd(&s);
  
  	return r;
  }
1811b7d38   Tom Rini   gunzip.c: Only in...
285
  #endif
918e9ebb4   Eric Nelson   gunzip: add gzwri...
286

35f6a943f   Ricardo Ribalda Delgado   lib_generic: gunz...
287
288
289
290
291
292
293
  /*
   * Uncompress blocks compressed with zlib without headers
   */
  int zunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp,
  						int stoponerr, int offset)
  {
  	z_stream s;
9c55c54fb   Simon Glass   gunzip: Update le...
294
  	int err = 0;
35f6a943f   Ricardo Ribalda Delgado   lib_generic: gunz...
295
  	int r;
e3ed0575a   Mike Frysinger   gunzip: rename z{...
296
297
  	s.zalloc = gzalloc;
  	s.zfree = gzfree;
321359f20   Marian Balakowicz   [new uImage] Move...
298
299
300
  
  	r = inflateInit2(&s, -MAX_WBITS);
  	if (r != Z_OK) {
918e9ebb4   Eric Nelson   gunzip: add gzwri...
301
302
  		printf("Error: inflateInit2() returned %d
  ", r);
35f6a943f   Ricardo Ribalda Delgado   lib_generic: gunz...
303
  		return -1;
321359f20   Marian Balakowicz   [new uImage] Move...
304
  	}
35f6a943f   Ricardo Ribalda Delgado   lib_generic: gunz...
305
306
  	s.next_in = src + offset;
  	s.avail_in = *lenp - offset;
321359f20   Marian Balakowicz   [new uImage] Move...
307
308
  	s.next_out = dst;
  	s.avail_out = dstlen;
f039ada5c   Catalin Radu   Fix gunzip to wor...
309
310
  	do {
  		r = inflate(&s, Z_FINISH);
b75650d84   Kees Cook   gzip: correctly b...
311
  		if (stoponerr == 1 && r != Z_STREAM_END &&
193466574   Stephen Warren   gunzip: remove av...
312
  		    (s.avail_in == 0 || s.avail_out == 0 || r != Z_BUF_ERROR)) {
f039ada5c   Catalin Radu   Fix gunzip to wor...
313
314
  			printf("Error: inflate() returned %d
  ", r);
9c55c54fb   Simon Glass   gunzip: Update le...
315
316
  			err = -1;
  			break;
f039ada5c   Catalin Radu   Fix gunzip to wor...
317
  		}
f039ada5c   Catalin Radu   Fix gunzip to wor...
318
  	} while (r == Z_BUF_ERROR);
321359f20   Marian Balakowicz   [new uImage] Move...
319
320
  	*lenp = s.next_out - (unsigned char *) dst;
  	inflateEnd(&s);
9c55c54fb   Simon Glass   gunzip: Update le...
321
  	return err;
321359f20   Marian Balakowicz   [new uImage] Move...
322
  }