summaryrefslogtreecommitdiff
path: root/archival
diff options
context:
space:
mode:
authorPaul Fox <pgf@brightstareng.com>2005-07-20 20:26:49 +0000
committerPaul Fox <pgf@brightstareng.com>2005-07-20 20:26:49 +0000
commit0840b76602900f8236f444b68da16d5c8d57ac3d (patch)
tree9e4bfeefb4a93867bbee1f2a48f77e7a44389397 /archival
parentf2ddc05ee77a2f5ab9a2be318c694d2f3d4e852c (diff)
downloadbusybox-w32-0840b76602900f8236f444b68da16d5c8d57ac3d.tar.gz
busybox-w32-0840b76602900f8236f444b68da16d5c8d57ac3d.tar.bz2
busybox-w32-0840b76602900f8236f444b68da16d5c8d57ac3d.zip
applying fixes from:
0000142: unzip enhancements
Diffstat (limited to 'archival')
-rw-r--r--archival/libunarchive/decompress_unzip.c160
-rw-r--r--archival/unzip.c477
2 files changed, 414 insertions, 223 deletions
diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libunarchive/decompress_unzip.c
index b17065d92..883aaac46 100644
--- a/archival/libunarchive/decompress_unzip.c
+++ b/archival/libunarchive/decompress_unzip.c
@@ -16,6 +16,11 @@
16 * 16 *
17 * read_gz interface + associated hacking by Laurence Anderson 17 * read_gz interface + associated hacking by Laurence Anderson
18 * 18 *
19 * Fixed huft_build() so decoding end-of-block code does not grab more bits
20 * than necessary (this is required by unzip applet), added inflate_cleanup()
21 * to free leaked bytebuffer memory (used in unzip.c), and some minor style
22 * guide cleanups by Ed Clark
23 *
19 * This program is free software; you can redistribute it and/or modify 24 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by 25 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or 26 * the Free Software Foundation; either version 2 of the License, or
@@ -116,26 +121,26 @@ static const unsigned short mask_bits[] = {
116/* Copy lengths for literal codes 257..285 */ 121/* Copy lengths for literal codes 257..285 */
117static const unsigned short cplens[] = { 122static const unsigned short cplens[] = {
118 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 123 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
119 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 124 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
120}; 125};
121 126
122/* note: see note #13 above about the 258 in this list. */ 127/* note: see note #13 above about the 258 in this list. */
123/* Extra bits for literal codes 257..285 */ 128/* Extra bits for literal codes 257..285 */
124static const unsigned char cplext[] = { 129static const unsigned char cplext[] = {
125 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 130 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
126 5, 5, 5, 0, 99, 99 131 5, 5, 5, 0, 99, 99
127}; /* 99==invalid */ 132}; /* 99==invalid */
128 133
129/* Copy offsets for distance codes 0..29 */ 134/* Copy offsets for distance codes 0..29 */
130static const unsigned short cpdist[] = { 135static const unsigned short cpdist[] = {
131 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 136 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
132 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 137 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
133}; 138};
134 139
135/* Extra bits for distance codes */ 140/* Extra bits for distance codes */
136static const unsigned char cpdext[] = { 141static const unsigned char cpdext[] = {
137 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 142 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
138 11, 11, 12, 12, 13, 13 143 11, 11, 12, 12, 13, 13
139}; 144};
140 145
141/* Tables for deflate from PKZIP's appnote.txt. */ 146/* Tables for deflate from PKZIP's appnote.txt. */
@@ -187,8 +192,8 @@ static void make_gunzip_crc_table(void)
187 table_entry = (table_entry >> 1) ^ poly; 192 table_entry = (table_entry >> 1) ^ poly;
188 } else { 193 } else {
189 table_entry >>= 1; 194 table_entry >>= 1;
190 } 195 }
191 } 196 }
192 gunzip_crc_table[i] = table_entry; 197 gunzip_crc_table[i] = table_entry;
193 } 198 }
194} 199}
@@ -228,70 +233,59 @@ static int huft_free(huft_t * t)
228 * t: result: starting table 233 * t: result: starting table
229 * m: maximum lookup bits, returns actual 234 * m: maximum lookup bits, returns actual
230 */ 235 */
231static int huft_build(unsigned int *b, const unsigned int n, 236int huft_build(unsigned int *b, const unsigned int n,
232 const unsigned int s, const unsigned short *d, 237 const unsigned int s, const unsigned short *d,
233 const unsigned char *e, huft_t ** t, int *m) 238 const unsigned char *e, huft_t ** t, int *m)
234{ 239{
235 unsigned a; /* counter for codes of length k */ 240 unsigned a; /* counter for codes of length k */
236 unsigned c[BMAX + 1]; /* bit length count table */ 241 unsigned c[BMAX + 1]; /* bit length count table */
237 unsigned f; /* i repeats in table every f entries */ 242 unsigned eob_len; /* length of end-of-block code (value 256) */
238 int g; /* maximum code length */ 243 unsigned f; /* i repeats in table every f entries */
239 int h; /* table level */ 244 int g; /* maximum code length */
245 int h; /* table level */
240 register unsigned i; /* counter, current code */ 246 register unsigned i; /* counter, current code */
241 register unsigned j; /* counter */ 247 register unsigned j; /* counter */
242 register int k; /* number of bits in current code */ 248 register int k; /* number of bits in current code */
243 int l; /* bits per table (returned in m) */
244 register unsigned *p; /* pointer into c[], b[], or v[] */ 249 register unsigned *p; /* pointer into c[], b[], or v[] */
245 register huft_t *q; /* points to current table */ 250 register huft_t *q; /* points to current table */
246 huft_t r; /* table entry for structure assignment */ 251 huft_t r; /* table entry for structure assignment */
247 huft_t *u[BMAX]; /* table stack */ 252 huft_t *u[BMAX]; /* table stack */
248 unsigned v[N_MAX]; /* values in order of bit length */ 253 unsigned v[N_MAX]; /* values in order of bit length */
249 register int w; /* bits before this table == (l * h) */ 254 int ws[BMAX+1]; /* bits decoded stack */
255 register int w; /* bits decoded */
250 unsigned x[BMAX + 1]; /* bit offsets, then code stack */ 256 unsigned x[BMAX + 1]; /* bit offsets, then code stack */
251 unsigned *xp; /* pointer into x */ 257 unsigned *xp; /* pointer into x */
252 int y; /* number of dummy codes added */ 258 int y; /* number of dummy codes added */
253 unsigned z; /* number of entries in current table */ 259 unsigned z; /* number of entries in current table */
260
261 /* Length of EOB code, if any */
262 eob_len = n > 256 ? b[256] : BMAX;
254 263
255 /* Generate counts for each bit length */ 264 /* Generate counts for each bit length */
256 memset((void *) (c), 0, sizeof(c)); 265 memset((void *)c, 0, sizeof(c));
257 p = b; 266 p = b;
258 i = n; 267 i = n;
259 do { 268 do {
260 c[*p]++; /* assume all entries <= BMAX */ 269 c[*p]++; /* assume all entries <= BMAX */
261 p++; /* Can't combine with above line (Solaris bug) */ 270 p++; /* Can't combine with above line (Solaris bug) */
262 } while (--i); 271 } while (--i);
263 if (c[0] == n) { /* null input--all zero length codes */ 272 if (c[0] == n) { /* null input--all zero length codes */
264 *t = (huft_t *) NULL; 273 *t = (huft_t *) NULL;
265 *m = 0; 274 *m = 0;
266 return 0; 275 return 0;
267 } 276 }
268 277
269 /* Find minimum and maximum length, bound *m by those */ 278 /* Find minimum and maximum length, bound *m by those */
270 l = *m; 279 for (j = 1; (c[j] == 0) && (j <= BMAX); j++);
271 for (j = 1; j <= BMAX; j++) { 280 k = j; /* minimum code length */
272 if (c[j]) { 281 for (i = BMAX; (c[i] == 0) && i; i--);
273 break; 282 g = i; /* maximum code length */
274 } 283 *m = (*m < j) ? j : ((*m > i) ? i : *m);
275 }
276 k = j; /* minimum code length */
277 if ((unsigned) l < j) {
278 l = j;
279 }
280 for (i = BMAX; i; i--) {
281 if (c[i]) {
282 break;
283 }
284 }
285 g = i; /* maximum code length */
286 if ((unsigned) l > i) {
287 l = i;
288 }
289 *m = l;
290 284
291 /* Adjust last length count to fill out codes, if needed */ 285 /* Adjust last length count to fill out codes, if needed */
292 for (y = 1 << j; j < i; j++, y <<= 1) { 286 for (y = 1 << j; j < i; j++, y <<= 1) {
293 if ((y -= c[j]) < 0) { 287 if ((y -= c[j]) < 0) {
294 return 2; /* bad input: more codes than bits */ 288 return 2; /* bad input: more codes than bits */
295 } 289 }
296 } 290 }
297 if ((y -= c[i]) < 0) { 291 if ((y -= c[i]) < 0) {
@@ -303,7 +297,7 @@ static int huft_build(unsigned int *b, const unsigned int n,
303 x[1] = j = 0; 297 x[1] = j = 0;
304 p = c + 1; 298 p = c + 1;
305 xp = x + 2; 299 xp = x + 2;
306 while (--i) { /* note that i == g from above */ 300 while (--i) { /* note that i == g from above */
307 *xp++ = (j += *p++); 301 *xp++ = (j += *p++);
308 } 302 }
309 303
@@ -317,13 +311,13 @@ static int huft_build(unsigned int *b, const unsigned int n,
317 } while (++i < n); 311 } while (++i < n);
318 312
319 /* Generate the Huffman codes and for each, make the table entries */ 313 /* Generate the Huffman codes and for each, make the table entries */
320 x[0] = i = 0; /* first Huffman code is zero */ 314 x[0] = i = 0; /* first Huffman code is zero */
321 p = v; /* grab values in bit order */ 315 p = v; /* grab values in bit order */
322 h = -1; /* no tables yet--level -1 */ 316 h = -1; /* no tables yet--level -1 */
323 w = -l; /* bits decoded == (l * h) */ 317 w = ws[0] = 0; /* bits decoded */
324 u[0] = (huft_t *) NULL; /* just to keep compilers happy */ 318 u[0] = (huft_t *) NULL; /* just to keep compilers happy */
325 q = (huft_t *) NULL; /* ditto */ 319 q = (huft_t *) NULL; /* ditto */
326 z = 0; /* ditto */ 320 z = 0; /* ditto */
327 321
328 /* go through the bit lengths (k already is bits in shortest code) */ 322 /* go through the bit lengths (k already is bits in shortest code) */
329 for (; k <= g; k++) { 323 for (; k <= g; k++) {
@@ -331,52 +325,52 @@ static int huft_build(unsigned int *b, const unsigned int n,
331 while (a--) { 325 while (a--) {
332 /* here i is the Huffman code of length k bits for value *p */ 326 /* here i is the Huffman code of length k bits for value *p */
333 /* make tables up to required level */ 327 /* make tables up to required level */
334 while (k > w + l) { 328 while (k > ws[h + 1]) {
335 h++; 329 w = ws[++h];
336 w += l; /* previous table always l bits */ 330
337 331 /* compute minimum size table less than or equal to *m bits */
338 /* compute minimum size table less than or equal to l bits */ 332 z = (z = g - w) > *m ? *m : z; /* upper limit on table size */
339 z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */ 333 if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table */
340 if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */ 334 /* too few codes for k-w bit table */
341 f -= a + 1; /* deduct codes from patterns left */ 335 f -= a + 1; /* deduct codes from patterns left */
342 xp = c + k; 336 xp = c + k;
343 while (++j < z) { /* try smaller tables up to z bits */ 337 while (++j < z) { /* try smaller tables up to z bits */
344 if ((f <<= 1) <= *++xp) { 338 if ((f <<= 1) <= *++xp) {
345 break; /* enough codes to use up j bits */ 339 break; /* enough codes to use up j bits */
346 } 340 }
347 f -= *xp; /* else deduct codes from patterns */ 341 f -= *xp; /* else deduct codes from patterns */
348 } 342 }
349 } 343 }
344 j = (w + j > eob_len && w < eob_len) ? eob_len - w : j; /* make EOB code end at table */
350 z = 1 << j; /* table entries for j-bit table */ 345 z = 1 << j; /* table entries for j-bit table */
346 ws[h+1] = w + j; /* set bits decoded in stack */
351 347
352 /* allocate and link in new table */ 348 /* allocate and link in new table */
353 q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t)); 349 q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t));
354
355 *t = q + 1; /* link to list for huft_free() */ 350 *t = q + 1; /* link to list for huft_free() */
356 *(t = &(q->v.t)) = NULL; 351 *(t = &(q->v.t)) = NULL;
357 u[h] = ++q; /* table starts after link */ 352 u[h] = ++q; /* table starts after link */
358 353
359 /* connect to last table, if there is one */ 354 /* connect to last table, if there is one */
360 if (h) { 355 if (h) {
361 x[h] = i; /* save pattern for backing up */ 356 x[h] = i; /* save pattern for backing up */
362 r.b = (unsigned char) l; /* bits to dump before this table */ 357 r.b = (unsigned char) (w - ws[h - 1]); /* bits to dump before this table */
363 r.e = (unsigned char) (16 + j); /* bits in this table */ 358 r.e = (unsigned char) (16 + j); /* bits in this table */
364 r.v.t = q; /* pointer to this table */ 359 r.v.t = q; /* pointer to this table */
365 j = i >> (w - l); /* (get around Turbo C bug) */ 360 j = (i & ((1 << w) - 1)) >> ws[h - 1];
366 u[h - 1][j] = r; /* connect to last table */ 361 u[h - 1][j] = r; /* connect to last table */
367 } 362 }
368 } 363 }
369 364
370 /* set up table entry in r */ 365 /* set up table entry in r */
371 r.b = (unsigned char) (k - w); 366 r.b = (unsigned char) (k - w);
372 if (p >= v + n) { 367 if (p >= v + n) {
373 r.e = 99; /* out of values--invalid code */ 368 r.e = 99; /* out of values--invalid code */
374 } else if (*p < s) { 369 } else if (*p < s) {
375 r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ 370 r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */
376 r.v.n = (unsigned short) (*p); /* simple code is just the value */ 371 r.v.n = (unsigned short) (*p++); /* simple code is just the value */
377 p++; /* one compiler does not like *p++ */
378 } else { 372 } else {
379 r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ 373 r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */
380 r.v.n = d[*p++ - s]; 374 r.v.n = d[*p++ - s];
381 } 375 }
382 376
@@ -394,11 +388,14 @@ static int huft_build(unsigned int *b, const unsigned int n,
394 388
395 /* backup over finished tables */ 389 /* backup over finished tables */
396 while ((i & ((1 << w) - 1)) != x[h]) { 390 while ((i & ((1 << w) - 1)) != x[h]) {
397 h--; /* don't need to update q */ 391 w = ws[--h];
398 w -= l;
399 } 392 }
400 } 393 }
401 } 394 }
395
396 /* return actual size of base table */
397 *m = ws[1];
398
402 /* Return true (1) if we were given an incomplete table */ 399 /* Return true (1) if we were given an incomplete table */
403 return y != 0 && g != 1; 400 return y != 0 && g != 1;
404} 401}
@@ -904,6 +901,11 @@ extern void inflate_init(unsigned int bufsize)
904 bytebuffer_size = 0; 901 bytebuffer_size = 0;
905} 902}
906 903
904extern void inflate_cleanup(void)
905{
906 free(bytebuffer);
907}
908
907extern int inflate_unzip(int in, int out) 909extern int inflate_unzip(int in, int out)
908{ 910{
909 ssize_t nwrote; 911 ssize_t nwrote;
diff --git a/archival/unzip.c b/archival/unzip.c
index eea2f5438..05dbc72dd 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -2,7 +2,10 @@
2/* 2/*
3 * Mini unzip implementation for busybox 3 * Mini unzip implementation for busybox
4 * 4 *
5 * Copyright (C) 2001 by Laurence Anderson 5 * Copyright (C) 2004 by Ed Clark
6 *
7 * Loosely based on original busybox unzip applet by Laurence Anderson.
8 * All options and features should work in this version.
6 * 9 *
7 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
@@ -21,227 +24,413 @@
21 */ 24 */
22 25
23/* For reference see 26/* For reference see
24 * http://www.pkware.com/products/enterprise/white_papers/appnote.txt 27 * http://www.pkware.com/company/standards/appnote/
25 * http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip 28 * http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
26 */ 29 */
27 30
28/* TODO Endian issues, exclude, should we accept input from stdin ? */ 31/* TODO
32 * Endian issues
33 * Zip64 + other methods
34 * Improve handling of zip format, ie.
35 * - deferred CRC, comp. & uncomp. lengths (zip header flags bit 3)
36 * - unix file permissions, etc.
37 * - central directory
38 */
29 39
30#include <fcntl.h> 40#include <fcntl.h>
31#include <getopt.h> 41#include <getopt.h>
32#include <stdlib.h> 42#include <stdlib.h>
33#include <string.h> 43#include <string.h>
34#include <unistd.h> 44#include <unistd.h>
45#include <errno.h>
35#include "unarchive.h" 46#include "unarchive.h"
36#include "busybox.h" 47#include "busybox.h"
37 48
38#define ZIP_FILEHEADER_MAGIC 0x04034b50 49#if (BYTE_ORDER == BIG_ENDIAN)
39#define ZIP_CDS_MAGIC 0x02014b50 50static inline unsigned short
40#define ZIP_CDS_END_MAGIC 0x06054b50 51__swap16(unsigned short x) {
41#define ZIP_DD_MAGIC 0x08074b50 52 return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
53}
54
55static inline uint32_t
56__swap32(uint32_t x) {
57 return (((x & 0xFF) << 24) |
58 ((x & 0xFF00) << 8) |
59 ((x & 0xFF0000) >> 8) |
60 ((x & 0xFF000000) >> 24));
61}
62#else
63#define __swap16(x) (x)
64#define __swap32(x) (x)
65#endif
66
67#define ZIP_FILEHEADER_MAGIC __swap32(0x04034b50)
68#define ZIP_CDS_MAGIC __swap32(0x02014b50)
69#define ZIP_CDS_END_MAGIC __swap32(0x06054b50)
70#define ZIP_DD_MAGIC __swap32(0x08074b50)
42 71
43extern unsigned int gunzip_crc; 72extern unsigned int gunzip_crc;
44extern unsigned int gunzip_bytes_out; 73extern unsigned int gunzip_bytes_out;
45 74
46static void header_list_unzip(const file_header_t *file_header) 75typedef union {
76 unsigned char raw[26];
77 struct {
78 unsigned short version; /* 0-1 */
79 unsigned short flags; /* 2-3 */
80 unsigned short method; /* 4-5 */
81 unsigned short modtime; /* 6-7 */
82 unsigned short moddate; /* 8-9 */
83 unsigned int crc32 __attribute__ ((packed)); /* 10-13 */
84 unsigned int cmpsize __attribute__ ((packed)); /* 14-17 */
85 unsigned int ucmpsize __attribute__ ((packed)); /* 18-21 */
86 unsigned short filename_len; /* 22-23 */
87 unsigned short extra_len; /* 24-25 */
88 } formated __attribute__ ((packed));
89} zip_header_t;
90
91static void unzip_skip(int fd, off_t skip)
47{ 92{
48 printf(" inflating: %s\n", file_header->name); 93 if (lseek(fd, skip, SEEK_CUR) == (off_t)-1) {
94 if ((errno != ESPIPE) || (bb_copyfd_size(fd, -1, skip) != skip)) {
95 bb_error_msg_and_die("Seek failure");
96 }
97 }
49} 98}
50 99
51static void header_verbose_list_unzip(const file_header_t *file_header) 100static void unzip_read(int fd, void *buf, size_t count)
52{ 101{
53 unsigned int dostime = (unsigned int) file_header->mtime; 102 if (bb_xread(fd, buf, count) != count) {
103 bb_error_msg_and_die("Read failure");
104 }
105}
54 106
55 /* can printf arguments cut of the decade component ? */ 107static void unzip_create_leading_dirs(char *fn)
56 unsigned short year = 1980 + ((dostime & 0xfe000000) >> 25); 108{
57 while (year >= 100) { 109 /* Create all leading directories */
58 year -= 100; 110 char *name = bb_xstrdup(fn);
111 if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
112 bb_error_msg_and_die("Failed to create directory");
59 } 113 }
114 free(name);
115}
60 116
61 printf("%9u %02u-%02u-%02u %02u:%02u %s\n", 117static void unzip_extract(zip_header_t *zip_header, int src_fd, int dst_fd)
62 (unsigned int) file_header->size, 118{
63 (dostime & 0x01e00000) >> 21, 119 if (zip_header->formated.method == 0) {
64 (dostime & 0x001f0000) >> 16, 120 /* Method 0 - stored (not compressed) */
65 year, 121 int size = zip_header->formated.ucmpsize;
66 (dostime & 0x0000f800) >> 11, 122 if (size && (bb_copyfd_size(src_fd, dst_fd, size) != size)) {
67 (dostime & 0x000007e0) >> 5, 123 bb_error_msg_and_die("Cannot complete extraction");
68 file_header->name); 124 }
125
126 } else {
127 /* Method 8 - inflate */
128 inflate_init(zip_header->formated.cmpsize);
129 inflate_unzip(src_fd, dst_fd);
130 inflate_cleanup();
131 /* Validate decompression - crc */
132 if (zip_header->formated.crc32 != (gunzip_crc ^ 0xffffffffL)) {
133 bb_error_msg("Invalid compressed data--crc error");
134 }
135 /* Validate decompression - size */
136 if (zip_header->formated.ucmpsize != gunzip_bytes_out) {
137 bb_error_msg("Invalid compressed data--length error");
138 }
139 }
69} 140}
70 141
71extern int unzip_main(int argc, char **argv) 142extern int unzip_main(int argc, char **argv)
72{ 143{
73 union { 144 zip_header_t zip_header;
74 unsigned char raw[26]; 145 enum {v_silent, v_normal, v_list} verbosity = v_normal;
75 struct { 146 enum {o_prompt, o_never, o_always} overwrite = o_prompt;
76 unsigned short version; /* 0-1 */
77 unsigned short flags; /* 2-3 */
78 unsigned short method; /* 4-5 */
79 unsigned short modtime; /* 6-7 */
80 unsigned short moddate; /* 8-9 */
81 unsigned int crc32 __attribute__ ((packed)); /* 10-13 */
82 unsigned int cmpsize __attribute__ ((packed));; /* 14-17 */
83 unsigned int ucmpsize __attribute__ ((packed));; /* 18-21 */
84 unsigned short filename_len; /* 22-23 */
85 unsigned short extra_len; /* 24-25 */
86 } formated __attribute__ ((packed));
87 } zip_header;
88
89 archive_handle_t *archive_handle;
90 unsigned int total_size = 0; 147 unsigned int total_size = 0;
91 unsigned int total_entries = 0; 148 unsigned int total_entries = 0;
149 int src_fd = -1, dst_fd = -1;
150 char *src_fn = NULL, *dst_fn = NULL;
151 llist_t *accept = NULL;
152 llist_t *reject = NULL;
92 char *base_dir = NULL; 153 char *base_dir = NULL;
93 int opt = 0; 154 int i, opt, opt_range = 0, list_header_done = 0;
94 155 char key_buf[512];
95 /* Initialise */ 156 struct stat stat_buf;
96 archive_handle = init_handle(); 157
97 archive_handle->action_data = NULL; 158 while((opt = getopt(argc, argv, "-d:lnopqx")) != -1) {
98 archive_handle->action_header = header_list_unzip; 159 switch(opt_range) {
99 160 case 0: /* Options */
100 while ((opt = getopt(argc, argv, "lnopqd:")) != -1) { 161 switch(opt) {
101 switch (opt) { 162 case 'l': /* List */
102 case 'l': /* list */ 163 verbosity = v_list;
103 archive_handle->action_header = header_verbose_list_unzip;
104 archive_handle->action_data = data_skip;
105 break;
106 case 'n': /* never overwright existing files */
107 break; 164 break;
108 case 'o': 165
109 archive_handle->flags = ARCHIVE_EXTRACT_UNCONDITIONAL; 166 case 'n': /* Never overwrite existing files */
110 break; 167 overwrite = o_never;
111 case 'p': /* extract files to stdout */
112 archive_handle->action_data = data_extract_to_stdout;
113 break; 168 break;
114 case 'q': /* Extract files quietly */ 169
115 archive_handle->action_header = header_skip; 170 case 'o': /* Always overwrite existing files */
171 overwrite = o_always;
116 break; 172 break;
117 case 'd': /* Extract files to specified base directory*/ 173
118 base_dir = optarg; 174 case 'p': /* Extract files to stdout and fall through to set verbosity */
175 dst_fd = STDOUT_FILENO;
176
177 case 'q': /* Be quiet */
178 verbosity = (verbosity == v_normal) ? v_silent : verbosity;
119 break; 179 break;
120#if 0 180
121 case 'x': /* Exclude the specified files */ 181 case 1 : /* The zip file */
122 archive_handle->filter = filter_accept_reject_list; 182 src_fn = bb_xstrndup(optarg, strlen(optarg)+4);
183 opt_range++;
123 break; 184 break;
124#endif 185
125 default: 186 default:
126 bb_show_usage(); 187 bb_show_usage();
188
189 }
190 break;
191
192 case 1: /* Include files */
193 if (opt == 1) {
194 accept = llist_add_to(accept, optarg);
195
196 } else if (opt == 'd') {
197 base_dir = optarg;
198 opt_range += 2;
199
200 } else if (opt == 'x') {
201 opt_range++;
202
203 } else {
204 bb_show_usage();
205 }
206 break;
207
208 case 2 : /* Exclude files */
209 if (opt == 1) {
210 reject = llist_add_to(reject, optarg);
211
212 } else if (opt == 'd') { /* Extract to base directory */
213 base_dir = optarg;
214 opt_range++;
215
216 } else {
217 bb_show_usage();
218 }
219 break;
220
221 default:
222 bb_show_usage();
127 } 223 }
128 } 224 }
129 225
130 if (argc == optind) { 226 if (src_fn == NULL) {
131 bb_show_usage(); 227 bb_show_usage();
132 } 228 }
133 229
134 printf("Archive: %s\n", argv[optind]); 230 /* Open input file */
135 if (archive_handle->action_header == header_verbose_list_unzip) { 231 if (strcmp("-", src_fn) == 0) {
136 printf(" Length Date Time Name\n"); 232 src_fd = STDIN_FILENO;
137 printf(" -------- ---- ---- ----\n"); 233 /* Cannot use prompt mode since zip data is arriving on STDIN */
138 } 234 overwrite = (overwrite == o_prompt) ? o_never : overwrite;
139 235
140 if (*argv[optind] == '-') {
141 archive_handle->src_fd = STDIN_FILENO;
142 archive_handle->seek = seek_by_char;
143 } else { 236 } else {
144 archive_handle->src_fd = bb_xopen(argv[optind++], O_RDONLY); 237 char *extn[] = {"", ".zip", ".ZIP"};
238 int orig_src_fn_len = strlen(src_fn);
239 for(i = 0; (i < 3) && (src_fd == -1); i++) {
240 strcpy(src_fn + orig_src_fn_len, extn[i]);
241 src_fd = open(src_fn, O_RDONLY);
242 }
243 if (src_fd == -1) {
244 src_fn[orig_src_fn_len] = 0;
245 bb_error_msg_and_die("Cannot open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);
246 }
145 } 247 }
146 248
147 if ((base_dir) && (chdir(base_dir))) { 249 /* Change dir if necessary */
148 bb_perror_msg_and_die("Couldnt chdir"); 250 if (base_dir && chdir(base_dir)) {
251 bb_perror_msg_and_die("Cannot chdir");
149 } 252 }
150 253
151 while (optind < argc) { 254 if (verbosity != v_silent)
152 archive_handle->filter = filter_accept_list; 255 printf("Archive: %s\n", src_fn);
153 archive_handle->accept = llist_add_to(archive_handle->accept, argv[optind]);
154 optind++;
155 }
156 256
157 while (1) { 257 while (1) {
158 unsigned int magic; 258 unsigned int magic;
159 int dst_fd;
160
161 /* TODO Endian issues */
162 archive_xread_all(archive_handle, &magic, 4);
163 archive_handle->offset += 4;
164 259
260 /* Check magic number */
261 unzip_read(src_fd, &magic, 4);
165 if (magic == ZIP_CDS_MAGIC) { 262 if (magic == ZIP_CDS_MAGIC) {
166 break; 263 break;
167 } 264 } else if (magic != ZIP_FILEHEADER_MAGIC) {
168 else if (magic != ZIP_FILEHEADER_MAGIC) { 265 bb_error_msg_and_die("Invalid zip magic %08X", magic);
169 bb_error_msg_and_die("Invlaide zip magic");
170 } 266 }
171 267
172 /* Read the file header */ 268 /* Read the file header */
173 archive_xread_all(archive_handle, zip_header.raw, 26); 269 unzip_read(src_fd, zip_header.raw, 26);
174 archive_handle->offset += 26; 270#if (BYTE_ORDER == BIG_ENDIAN)
175 archive_handle->file_header->mode = S_IFREG | 0777; 271 zip_header.formated.version = __swap16(zip_header.formated.version);
176 272 zip_header.formated.flags = __swap16(zip_header.formated.flags);
177 if (zip_header.formated.method != 8) { 273 zip_header.formated.method = __swap16(zip_header.formated.method);
178 bb_error_msg_and_die("Unsupported compression method %d\n", zip_header.formated.method); 274 zip_header.formated.modtime = __swap16(zip_header.formated.modtime);
275 zip_header.formated.moddate = __swap16(zip_header.formated.moddate);
276 zip_header.formated.crc32 = __swap32(zip_header.formated.crc32);
277 zip_header.formated.cmpsize = __swap32(zip_header.formated.cmpsize);
278 zip_header.formated.ucmpsize = __swap32(zip_header.formated.ucmpsize);
279 zip_header.formated.filename_len = __swap16(zip_header.formated.filename_len);
280 zip_header.formated.extra_len = __swap16(zip_header.formated.extra_len);
281#endif
282 if ((zip_header.formated.method != 0) && (zip_header.formated.method != 8)) {
283 bb_error_msg_and_die("Unsupported compression method %d", zip_header.formated.method);
179 } 284 }
180 285
181 /* Read filename */ 286 /* Read filename */
182 archive_handle->file_header->name = xmalloc(zip_header.formated.filename_len + 1); 287 free(dst_fn);
183 archive_xread_all(archive_handle, archive_handle->file_header->name, zip_header.formated.filename_len); 288 dst_fn = xmalloc(zip_header.formated.filename_len + 1);
184 archive_handle->offset += zip_header.formated.filename_len; 289 unzip_read(src_fd, dst_fn, zip_header.formated.filename_len);
185 archive_handle->file_header->name[zip_header.formated.filename_len] = '\0'; 290 dst_fn[zip_header.formated.filename_len] = 0;
186 291
187 /* Skip extra header bits */ 292 /* Skip extra header bytes */
188 archive_handle->file_header->size = zip_header.formated.extra_len; 293 unzip_skip(src_fd, zip_header.formated.extra_len);
189 data_skip(archive_handle); 294
190 archive_handle->offset += zip_header.formated.extra_len; 295 if ((verbosity == v_list) && !list_header_done){
191 296 printf(" Length Date Time Name\n");
192 /* Handle directories */ 297 printf(" -------- ---- ---- ----\n");
193 archive_handle->file_header->mode = S_IFREG | 0777; 298 list_header_done = 1;
194 if (last_char_is(archive_handle->file_header->name, '/')) {
195 archive_handle->file_header->mode ^= S_IFREG;
196 archive_handle->file_header->mode |= S_IFDIR;
197 } 299 }
198 300
199 /* Data section */ 301 /* Filter zip entries */
200 archive_handle->file_header->size = zip_header.formated.cmpsize; 302 if (find_list_entry(reject, dst_fn) ||
201 if (archive_handle->action_data) { 303 (accept && !find_list_entry(accept, dst_fn))) { /* Skip entry */
202 archive_handle->action_data(archive_handle); 304 i = 'n';
203 } else { 305
204 dst_fd = bb_xopen(archive_handle->file_header->name, O_WRONLY | O_CREAT); 306 } else { /* Extract entry */
205 inflate_init(zip_header.formated.cmpsize); 307 total_size += zip_header.formated.ucmpsize;
206 inflate_unzip(archive_handle->src_fd, dst_fd); 308
207 close(dst_fd); 309 if (verbosity == v_list) { /* List entry */
208 chmod(archive_handle->file_header->name, archive_handle->file_header->mode); 310 unsigned int dostime = zip_header.formated.modtime | (zip_header.formated.moddate << 16);
209 311 printf("%9u %02u-%02u-%02u %02u:%02u %s\n",
210 /* Validate decompression - crc */ 312 zip_header.formated.ucmpsize,
211 if (zip_header.formated.crc32 != (gunzip_crc ^ 0xffffffffL)) { 313 (dostime & 0x01e00000) >> 21,
212 bb_error_msg("Invalid compressed data--crc error"); 314 (dostime & 0x001f0000) >> 16,
315 (((dostime & 0xfe000000) >> 25) + 1980) % 100,
316 (dostime & 0x0000f800) >> 11,
317 (dostime & 0x000007e0) >> 5,
318 dst_fn);
319 total_entries++;
320 i = 'n';
321
322 } else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */
323 i = -1;
324
325 } else if (last_char_is(dst_fn, '/')) { /* Extract directory */
326 if (stat(dst_fn, &stat_buf) == -1) {
327 if (errno != ENOENT) {
328 bb_perror_msg_and_die("Cannot stat '%s'",dst_fn);
329 }
330 if (verbosity == v_normal) {
331 printf(" creating: %s\n", dst_fn);
332 }
333 unzip_create_leading_dirs(dst_fn);
334 if (bb_make_directory(dst_fn, 0777, 0)) {
335 bb_error_msg_and_die("Failed to create directory");
336 }
337 } else {
338 if (!S_ISDIR(stat_buf.st_mode)) {
339 bb_error_msg_and_die("'%s' exists but is not directory", dst_fn);
340 }
341 }
342 i = 'n';
343
344 } else { /* Extract file */
345 _check_file:
346 if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */
347 if (errno != ENOENT) {
348 bb_perror_msg_and_die("Cannot stat '%s'",dst_fn);
349 }
350 i = 'y';
351
352 } else { /* File already exists */
353 if (overwrite == o_never) {
354 i = 'n';
355
356 } else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */
357 if (overwrite == o_always) {
358 i = 'y';
359 } else {
360 printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
361 if (!fgets(key_buf, 512, stdin)) {
362 bb_perror_msg_and_die("Cannot read input");
363 }
364 i = key_buf[0];
365 }
366
367 } else { /* File is not regular file */
368 bb_error_msg_and_die("'%s' exists but is not regular file",dst_fn);
369 }
370 }
213 } 371 }
372 }
214 373
215 /* Validate decompression - size */ 374 switch (i) {
216 if (gunzip_bytes_out != zip_header.formated.ucmpsize) { 375 case 'A':
217 bb_error_msg("Invalid compressed data--length error"); 376 overwrite = o_always;
377 case 'y': /* Open file and fall into unzip */
378 unzip_create_leading_dirs(dst_fn);
379 dst_fd = bb_xopen(dst_fn, O_WRONLY | O_CREAT);
380 case -1: /* Unzip */
381 if (verbosity == v_normal) {
382 printf(" inflating: %s\n", dst_fn);
218 } 383 }
219 } 384 unzip_extract(&zip_header, src_fd, dst_fd);
385 if (dst_fd != STDOUT_FILENO) {
386 /* closing STDOUT is potentially bad for future business */
387 close(dst_fd);
388 }
389 break;
220 390
221 /* local file descriptor section */ 391 case 'N':
222 archive_handle->offset += zip_header.formated.cmpsize; 392 overwrite = o_never;
223 /* This ISNT unix time */ 393 case 'n':
224 archive_handle->file_header->mtime = zip_header.formated.modtime | (zip_header.formated.moddate << 16); 394 /* Skip entry data */
225 archive_handle->file_header->size = zip_header.formated.ucmpsize; 395 unzip_skip(src_fd, zip_header.formated.cmpsize);
226 total_size += archive_handle->file_header->size; 396 break;
227 total_entries++;
228 397
229 archive_handle->action_header(archive_handle->file_header); 398 case 'r':
399 /* Prompt for new name */
400 printf("new name: ");
401 if (!fgets(key_buf, 512, stdin)) {
402 bb_perror_msg_and_die("Cannot read input");
403 }
404 free(dst_fn);
405 dst_fn = bb_xstrdup(key_buf);
406 chomp(dst_fn);
407 goto _check_file;
408
409 default:
410 printf("error: invalid response [%c]\n",(char)i);
411 goto _check_file;
412 }
230 413
231 /* Data descriptor section */ 414 /* Data descriptor section */
232 if (zip_header.formated.flags & 4) { 415 if (zip_header.formated.flags & 4) {
233 /* skip over duplicate crc, compressed size and uncompressed size */ 416 /* skip over duplicate crc, compressed size and uncompressed size */
234 unsigned char data_description[12]; 417 unzip_skip(src_fd, 12);
235 archive_xread_all(archive_handle, data_description, 12);
236 archive_handle->offset += 12;
237 } 418 }
238 } 419 }
239 /* Central directory section */
240 420
241 if (archive_handle->action_header == header_verbose_list_unzip) { 421 if (verbosity == v_list) {
242 printf(" -------- -------\n"); 422 printf(" -------- -------\n");
243 printf("%9d %d files\n", total_size, total_entries); 423 printf("%9d %d files\n", total_size, total_entries);
244 } 424 }
245 425
246 return(EXIT_SUCCESS); 426 return(EXIT_SUCCESS);
247} 427}
428
429/* END CODE */
430/*
431Local Variables:
432c-file-style: "linux"
433c-basic-offset: 4
434tab-width: 4
435End:
436*/