Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/archival/unzip.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 815 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 16  Line 16 
16   */   */
17    
18  /* TODO  /* TODO
  * Endian issues  
19   * Zip64 + other methods   * Zip64 + other methods
  * Improve handling of zip format, ie.  
  * - deferred CRC, comp. & uncomp. lengths (zip header flags bit 3)  
  * - unix file permissions, etc.  
  * - central directory  
20   */   */
21    
22  #include "busybox.h"  #include "libbb.h"
23  #include "unarchive.h"  #include "unarchive.h"
24    
25  #define ZIP_FILEHEADER_MAGIC SWAP_LE32(0x04034b50)  enum {
26  #define ZIP_CDS_MAGIC SWAP_LE32(0x02014b50)  #if BB_BIG_ENDIAN
27  #define ZIP_CDS_END_MAGIC SWAP_LE32(0x06054b50)   ZIP_FILEHEADER_MAGIC = 0x504b0304,
28  #define ZIP_DD_MAGIC SWAP_LE32(0x08074b50)   ZIP_CDS_MAGIC        = 0x504b0102,
29     ZIP_CDE_MAGIC        = 0x504b0506,
30     ZIP_DD_MAGIC         = 0x504b0708,
31    #else
32     ZIP_FILEHEADER_MAGIC = 0x04034b50,
33     ZIP_CDS_MAGIC        = 0x02014b50,
34     ZIP_CDE_MAGIC        = 0x06054b50,
35     ZIP_DD_MAGIC         = 0x08074b50,
36    #endif
37    };
38    
39    #define ZIP_HEADER_LEN 26
40    
41    typedef union {
42     uint8_t raw[ZIP_HEADER_LEN];
43     struct {
44     uint16_t version;               /* 0-1 */
45     uint16_t flags;                 /* 2-3 */
46     uint16_t method;                /* 4-5 */
47     uint16_t modtime;               /* 6-7 */
48     uint16_t moddate;               /* 8-9 */
49     uint32_t crc32 PACKED;          /* 10-13 */
50     uint32_t cmpsize PACKED;        /* 14-17 */
51     uint32_t ucmpsize PACKED;       /* 18-21 */
52     uint16_t filename_len;          /* 22-23 */
53     uint16_t extra_len;             /* 24-25 */
54     } formatted PACKED;
55    } zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */
56    
57    /* Check the offset of the last element, not the length.  This leniency
58     * allows for poor packing, whereby the overall struct may be too long,
59     * even though the elements are all in the right place.
60     */
61    struct BUG_zip_header_must_be_26_bytes {
62     char BUG_zip_header_must_be_26_bytes[
63     offsetof(zip_header_t, formatted.extra_len) + 2
64     == ZIP_HEADER_LEN ? 1 : -1];
65    };
66    
67    #define FIX_ENDIANNESS_ZIP(zip_header) do { \
68     (zip_header).formatted.version      = SWAP_LE16((zip_header).formatted.version     ); \
69     (zip_header).formatted.flags        = SWAP_LE16((zip_header).formatted.flags       ); \
70     (zip_header).formatted.method       = SWAP_LE16((zip_header).formatted.method      ); \
71     (zip_header).formatted.modtime      = SWAP_LE16((zip_header).formatted.modtime     ); \
72     (zip_header).formatted.moddate      = SWAP_LE16((zip_header).formatted.moddate     ); \
73     (zip_header).formatted.crc32        = SWAP_LE32((zip_header).formatted.crc32       ); \
74     (zip_header).formatted.cmpsize      = SWAP_LE32((zip_header).formatted.cmpsize     ); \
75     (zip_header).formatted.ucmpsize     = SWAP_LE32((zip_header).formatted.ucmpsize    ); \
76     (zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \
77     (zip_header).formatted.extra_len    = SWAP_LE16((zip_header).formatted.extra_len   ); \
78    } while (0)
79    
80    #define CDS_HEADER_LEN 42
81    
82    typedef union {
83     uint8_t raw[CDS_HEADER_LEN];
84     struct {
85     /* uint32_t signature; 50 4b 01 02 */
86     uint16_t version_made_by;       /* 0-1 */
87     uint16_t version_needed;        /* 2-3 */
88     uint16_t cds_flags;             /* 4-5 */
89     uint16_t method;                /* 6-7 */
90     uint16_t mtime;                 /* 8-9 */
91     uint16_t mdate;                 /* 10-11 */
92     uint32_t crc32;                 /* 12-15 */
93     uint32_t cmpsize;               /* 16-19 */
94     uint32_t ucmpsize;              /* 20-23 */
95     uint16_t file_name_length;      /* 24-25 */
96     uint16_t extra_field_length;    /* 26-27 */
97     uint16_t file_comment_length;   /* 28-29 */
98     uint16_t disk_number_start;     /* 30-31 */
99     uint16_t internal_file_attributes; /* 32-33 */
100     uint32_t external_file_attributes PACKED; /* 34-37 */
101     uint32_t relative_offset_of_local_header PACKED; /* 38-41 */
102     } formatted PACKED;
103    } cds_header_t;
104    
105    struct BUG_cds_header_must_be_42_bytes {
106     char BUG_cds_header_must_be_42_bytes[
107     offsetof(cds_header_t, formatted.relative_offset_of_local_header) + 4
108     == CDS_HEADER_LEN ? 1 : -1];
109    };
110    
111    #define FIX_ENDIANNESS_CDS(cds_header) do { \
112     (cds_header).formatted.crc32        = SWAP_LE32((cds_header).formatted.crc32       ); \
113     (cds_header).formatted.cmpsize      = SWAP_LE32((cds_header).formatted.cmpsize     ); \
114     (cds_header).formatted.ucmpsize     = SWAP_LE32((cds_header).formatted.ucmpsize    ); \
115     (cds_header).formatted.file_name_length = SWAP_LE16((cds_header).formatted.file_name_length); \
116     (cds_header).formatted.extra_field_length = SWAP_LE16((cds_header).formatted.extra_field_length); \
117     (cds_header).formatted.file_comment_length = SWAP_LE16((cds_header).formatted.file_comment_length); \
118    } while (0)
119    
120    #define CDE_HEADER_LEN 16
121    
122  typedef union {  typedef union {
123   unsigned char raw[26];   uint8_t raw[CDE_HEADER_LEN];
124   struct {   struct {
125   unsigned short version; /* 0-1 */   /* uint32_t signature; 50 4b 05 06 */
126   unsigned short flags; /* 2-3 */   uint16_t this_disk_no;
127   unsigned short method; /* 4-5 */   uint16_t disk_with_cds_no;
128   unsigned short modtime; /* 6-7 */   uint16_t cds_entries_on_this_disk;
129   unsigned short moddate; /* 8-9 */   uint16_t cds_entries_total;
130   unsigned int crc32 ATTRIBUTE_PACKED; /* 10-13 */   uint32_t cds_size;
131   unsigned int cmpsize ATTRIBUTE_PACKED; /* 14-17 */   uint32_t cds_offset;
132   unsigned int ucmpsize ATTRIBUTE_PACKED; /* 18-21 */   /* uint16_t file_comment_length; */
133   unsigned short filename_len; /* 22-23 */   /* .ZIP file comment (variable size) */
134   unsigned short extra_len; /* 24-25 */   } formatted PACKED;
135   } formatted ATTRIBUTE_PACKED;  } cde_header_t;
136  } zip_header_t;  
137    struct BUG_cde_header_must_be_16_bytes {
138     char BUG_cde_header_must_be_16_bytes[
139     sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1];
140    };
141    
142    #define FIX_ENDIANNESS_CDE(cde_header) do { \
143     (cde_header).formatted.cds_offset = SWAP_LE32((cde_header).formatted.cds_offset); \
144    } while (0)
145    
146    enum { zip_fd = 3 };
147    
148    
149    #if ENABLE_DESKTOP
150    /* NB: does not preserve file position! */
151    static uint32_t find_cds_offset(void)
152    {
153     unsigned char buf[1024];
154     cde_header_t cde_header;
155     unsigned char *p;
156     off_t end;
157    
158     end = xlseek(zip_fd, 0, SEEK_END);
159     if (end < 1024)
160     end = 1024;
161     end -= 1024;
162     xlseek(zip_fd, end, SEEK_SET);
163     full_read(zip_fd, buf, 1024);
164    
165     p = buf;
166     while (p <= buf + 1024 - CDE_HEADER_LEN - 4) {
167     if (*p != 'P') {
168     p++;
169     continue;
170     }
171     if (*++p != 'K')
172     continue;
173     if (*++p != 5)
174     continue;
175     if (*++p != 6)
176     continue;
177     /* we found CDE! */
178     memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);
179     FIX_ENDIANNESS_CDE(cde_header);
180     return cde_header.formatted.cds_offset;
181     }
182     bb_error_msg_and_die("can't find file table");
183    };
184    
185  static void unzip_skip(int fd, off_t skip)  static uint32_t read_next_cds(int count_m1, uint32_t cds_offset, cds_header_t *cds_ptr)
186  {  {
187   if (lseek(fd, skip, SEEK_CUR) == (off_t)-1) {   off_t org;
188   if (errno != ESPIPE)  
189   bb_error_msg_and_die("seek failure");   org = xlseek(zip_fd, 0, SEEK_CUR);
190   bb_copyfd_exact_size(fd, -1, skip);  
191     if (!cds_offset)
192     cds_offset = find_cds_offset();
193    
194     while (count_m1-- >= 0) {
195     xlseek(zip_fd, cds_offset + 4, SEEK_SET);
196     xread(zip_fd, cds_ptr->raw, CDS_HEADER_LEN);
197     FIX_ENDIANNESS_CDS(*cds_ptr);
198     cds_offset += 4 + CDS_HEADER_LEN
199     + cds_ptr->formatted.file_name_length
200     + cds_ptr->formatted.extra_field_length
201     + cds_ptr->formatted.file_comment_length;
202   }   }
203    
204     xlseek(zip_fd, org, SEEK_SET);
205     return cds_offset;
206    };
207    #endif
208    
209    static void unzip_skip(off_t skip)
210    {
211     bb_copyfd_exact_size(zip_fd, -1, skip);
212  }  }
213    
214  static void unzip_create_leading_dirs(char *fn)  static void unzip_create_leading_dirs(const char *fn)
215  {  {
216   /* Create all leading directories */   /* Create all leading directories */
217   char *name = xstrdup(fn);   char *name = xstrdup(fn);
# Line 67  static void unzip_create_leading_dirs(ch Line 221  static void unzip_create_leading_dirs(ch
221   free(name);   free(name);
222  }  }
223    
224  static int unzip_extract(zip_header_t *zip_header, int src_fd, int dst_fd)  static void unzip_extract(zip_header_t *zip_header, int dst_fd)
225  {  {
226   if (zip_header->formatted.method == 0) {   if (zip_header->formatted.method == 0) {
227   /* Method 0 - stored (not compressed) */   /* Method 0 - stored (not compressed) */
228   off_t size = zip_header->formatted.ucmpsize;   off_t size = zip_header->formatted.ucmpsize;
229   if (size)   if (size)
230   bb_copyfd_exact_size(src_fd, dst_fd, size);   bb_copyfd_exact_size(zip_fd, dst_fd, size);
231   } else {   } else {
232   /* Method 8 - inflate */   /* Method 8 - inflate */
233   inflate_unzip_result res;   inflate_unzip_result res;
234   /* err = */ inflate_unzip(&res, zip_header->formatted.cmpsize, src_fd, dst_fd);   if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0)
235  // we should check for -1 error return   bb_error_msg_and_die("inflate error");
236   /* Validate decompression - crc */   /* Validate decompression - crc */
237   if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) {   if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) {
238   bb_error_msg("invalid compressed data--%s error", "crc");   bb_error_msg_and_die("crc error");
  return 1;  
239   }   }
240   /* Validate decompression - size */   /* Validate decompression - size */
241   if (zip_header->formatted.ucmpsize != res.bytes_out) {   if (zip_header->formatted.ucmpsize != res.bytes_out) {
242   bb_error_msg("invalid compressed data--%s error", "length");   /* Don't die. Who knows, maybe len calculation
243   return 1;   * was botched somewhere. After all, crc matched! */
244     bb_error_msg("bad length");
245   }   }
246   }   }
  return 0;  
247  }  }
248    
249    int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
250  int unzip_main(int argc, char **argv)  int unzip_main(int argc, char **argv)
251  {  {
252     enum { O_PROMPT, O_NEVER, O_ALWAYS };
253    
254   zip_header_t zip_header;   zip_header_t zip_header;
255   enum {v_silent, v_normal, v_list} verbosity = v_normal;   smallint verbose = 1;
256   enum {o_prompt, o_never, o_always} overwrite = o_prompt;   smallint listing = 0;
257   unsigned int total_size = 0;   smallint overwrite = O_PROMPT;
258   unsigned int total_entries = 0;  #if ENABLE_DESKTOP
259   int src_fd = -1, dst_fd = -1;   uint32_t cds_offset;
260   char *src_fn = NULL, *dst_fn = NULL;   unsigned cds_entries;
261    #endif
262     unsigned total_size;
263     unsigned total_entries;
264     int dst_fd = -1;
265     char *src_fn = NULL;
266     char *dst_fn = NULL;
267   llist_t *zaccept = NULL;   llist_t *zaccept = NULL;
268   llist_t *zreject = NULL;   llist_t *zreject = NULL;
269   char *base_dir = NULL;   char *base_dir = NULL;
270   int failed, i, opt, opt_range = 0, list_header_done = 0;   int i, opt;
271   char key_buf[512];   int opt_range = 0;
272     char key_buf[80];
273   struct stat stat_buf;   struct stat stat_buf;
274    
275     /* '-' makes getopt return 1 for non-options */
276   while ((opt = getopt(argc, argv, "-d:lnopqx")) != -1) {   while ((opt = getopt(argc, argv, "-d:lnopqx")) != -1) {
277   switch (opt_range) {   switch (opt_range) {
278   case 0: /* Options */   case 0: /* Options */
279   switch (opt) {   switch (opt) {
280   case 'l': /* List */   case 'l': /* List */
281   verbosity = v_list;   listing = 1;
282   break;   break;
283    
284   case 'n': /* Never overwrite existing files */   case 'n': /* Never overwrite existing files */
285   overwrite = o_never;   overwrite = O_NEVER;
286   break;   break;
287    
288   case 'o': /* Always overwrite existing files */   case 'o': /* Always overwrite existing files */
289   overwrite = o_always;   overwrite = O_ALWAYS;
290   break;   break;
291    
292   case 'p': /* Extract files to stdout and fall through to set verbosity */   case 'p': /* Extract files to stdout and fall through to set verbosity */
293   dst_fd = STDOUT_FILENO;   dst_fd = STDOUT_FILENO;
294    
295   case 'q': /* Be quiet */   case 'q': /* Be quiet */
296   verbosity = (verbosity == v_normal) ? v_silent : verbosity;   verbose = 0;
297   break;   break;
298    
299   case 1 : /* The zip file */   case 1: /* The zip file */
300   src_fn = xstrndup(optarg, strlen(optarg)+4);   /* +5: space for ".zip" and NUL */
301     src_fn = xmalloc(strlen(optarg) + 5);
302     strcpy(src_fn, optarg);
303   opt_range++;   opt_range++;
304   break;   break;
305    
# Line 146  int unzip_main(int argc, char **argv) Line 312  int unzip_main(int argc, char **argv)
312   case 1: /* Include files */   case 1: /* Include files */
313   if (opt == 1) {   if (opt == 1) {
314   llist_add_to(&zaccept, optarg);   llist_add_to(&zaccept, optarg);
315     break;
316   } else if (opt == 'd') {   }
317     if (opt == 'd') {
318   base_dir = optarg;   base_dir = optarg;
319   opt_range += 2;   opt_range += 2;
320     break;
321   } else if (opt == 'x') {   }
322     if (opt == 'x') {
323   opt_range++;   opt_range++;
324     break;
  } else {  
  bb_show_usage();  
325   }   }
326   break;   bb_show_usage();
327    
328   case 2 : /* Exclude files */   case 2 : /* Exclude files */
329   if (opt == 1) {   if (opt == 1) {
330   llist_add_to(&zreject, optarg);   llist_add_to(&zreject, optarg);
331     break;
332   } else if (opt == 'd') { /* Extract to base directory */   }
333     if (opt == 'd') { /* Extract to base directory */
334   base_dir = optarg;   base_dir = optarg;
335   opt_range++;   opt_range++;
336     break;
  } else {  
  bb_show_usage();  
337   }   }
338   break;   /* fall through */
339    
340   default:   default:
341   bb_show_usage();   bb_show_usage();
# Line 183  int unzip_main(int argc, char **argv) Line 348  int unzip_main(int argc, char **argv)
348    
349   /* Open input file */   /* Open input file */
350   if (LONE_DASH(src_fn)) {   if (LONE_DASH(src_fn)) {
351   src_fd = STDIN_FILENO;   xdup2(STDIN_FILENO, zip_fd);
352   /* Cannot use prompt mode since zip data is arriving on STDIN */   /* Cannot use prompt mode since zip data is arriving on STDIN */
353   overwrite = (overwrite == o_prompt) ? o_never : overwrite;   if (overwrite == O_PROMPT)
354     overwrite = O_NEVER;
355   } else {   } else {
356   static const char *const extn[] = {"", ".zip", ".ZIP"};   static const char extn[][5] = {"", ".zip", ".ZIP"};
357   int orig_src_fn_len = strlen(src_fn);   int orig_src_fn_len = strlen(src_fn);
358     int src_fd = -1;
359    
360   for (i = 0; (i < 3) && (src_fd == -1); i++) {   for (i = 0; (i < 3) && (src_fd == -1); i++) {
361   strcpy(src_fn + orig_src_fn_len, extn[i]);   strcpy(src_fn + orig_src_fn_len, extn[i]);
362   src_fd = open(src_fn, O_RDONLY);   src_fd = open(src_fn, O_RDONLY);
363   }   }
364   if (src_fd == -1) {   if (src_fd == -1) {
365   src_fn[orig_src_fn_len] = 0;   src_fn[orig_src_fn_len] = '\0';
366   bb_error_msg_and_die("cannot open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);   bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);
367   }   }
368     xmove_fd(src_fd, zip_fd);
369   }   }
370    
371   /* Change dir if necessary */   /* Change dir if necessary */
372   if (base_dir)   if (base_dir)
373   xchdir(base_dir);   xchdir(base_dir);
374    
375   if (verbosity != v_silent)   if (verbose) {
376   printf("Archive:  %s\n", src_fn);   printf("Archive:  %s\n", src_fn);
377     if (listing){
378     puts("  Length     Date   Time    Name\n"
379         " --------    ----   ----    ----");
380     }
381     }
382    
383   failed = 0;   total_size = 0;
384     total_entries = 0;
385    #if ENABLE_DESKTOP
386     cds_entries = 0;
387     cds_offset = 0;
388    #endif
389   while (1) {   while (1) {
390   unsigned int magic;   uint32_t magic;
391    
392   /* Check magic number */   /* Check magic number */
393   xread(src_fd, &magic, 4);   xread(zip_fd, &magic, 4);
394   if (magic == ZIP_CDS_MAGIC) {   /* Central directory? It's at the end, so exit */
395     if (magic == ZIP_CDS_MAGIC)
396   break;   break;
397   } else if (magic != ZIP_FILEHEADER_MAGIC) {  #if ENABLE_DESKTOP
398   bb_error_msg_and_die("invalid zip magic %08X", magic);   /* Data descriptor? It was a streaming file, go on */
399   }   if (magic == ZIP_DD_MAGIC) {
400     /* skip over duplicate crc32, cmpsize and ucmpsize */
401     unzip_skip(3 * 4);
402     continue;
403     }
404    #endif
405     if (magic != ZIP_FILEHEADER_MAGIC)
406     bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
407    
408   /* Read the file header */   /* Read the file header */
409   xread(src_fd, zip_header.raw, 26);   xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN);
410   zip_header.formatted.version = SWAP_LE32(zip_header.formatted.version);   FIX_ENDIANNESS_ZIP(zip_header);
  zip_header.formatted.flags = SWAP_LE32(zip_header.formatted.flags);  
  zip_header.formatted.method = SWAP_LE32(zip_header.formatted.method);  
  zip_header.formatted.modtime = SWAP_LE32(zip_header.formatted.modtime);  
  zip_header.formatted.moddate = SWAP_LE32(zip_header.formatted.moddate);  
  zip_header.formatted.crc32 = SWAP_LE32(zip_header.formatted.crc32);  
  zip_header.formatted.cmpsize = SWAP_LE32(zip_header.formatted.cmpsize);  
  zip_header.formatted.ucmpsize = SWAP_LE32(zip_header.formatted.ucmpsize);  
  zip_header.formatted.filename_len = SWAP_LE32(zip_header.formatted.filename_len);  
  zip_header.formatted.extra_len = SWAP_LE32(zip_header.formatted.extra_len);  
411   if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {   if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {
412   bb_error_msg_and_die("unsupported compression method %d", zip_header.formatted.method);   bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
413     }
414    #if !ENABLE_DESKTOP
415     if (zip_header.formatted.flags & 0x0009) {
416     bb_error_msg_and_die("zip flags 1 and 8 are not supported");
417     }
418    #else
419     if (zip_header.formatted.flags & 0x0001) {
420     /* 0x0001 - encrypted */
421     bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
422     }
423     if (zip_header.formatted.flags & 0x0008) {
424     cds_header_t cds_header;
425     /* 0x0008 - streaming. [u]cmpsize can be reliably gotten
426     * only from Central Directory. See unzip_doc.txt */
427     cds_offset = read_next_cds(total_entries - cds_entries, cds_offset, &cds_header);
428     cds_entries = total_entries + 1;
429     zip_header.formatted.crc32    = cds_header.formatted.crc32;
430     zip_header.formatted.cmpsize  = cds_header.formatted.cmpsize;
431     zip_header.formatted.ucmpsize = cds_header.formatted.ucmpsize;
432   }   }
433    #endif
434    
435   /* Read filename */   /* Read filename */
436   free(dst_fn);   free(dst_fn);
437   dst_fn = xzalloc(zip_header.formatted.filename_len + 1);   dst_fn = xzalloc(zip_header.formatted.filename_len + 1);
438   xread(src_fd, dst_fn, zip_header.formatted.filename_len);   xread(zip_fd, dst_fn, zip_header.formatted.filename_len);
439    
440   /* Skip extra header bytes */   /* Skip extra header bytes */
441   unzip_skip(src_fd, zip_header.formatted.extra_len);   unzip_skip(zip_header.formatted.extra_len);
   
  if ((verbosity == v_list) && !list_header_done){  
  puts("  Length     Date   Time    Name\n"  
      " --------    ----   ----    ----");  
  list_header_done = 1;  
  }  
442    
443   /* Filter zip entries */   /* Filter zip entries */
444   if (find_list_entry(zreject, dst_fn) ||   if (find_list_entry(zreject, dst_fn)
445   (zaccept && !find_list_entry(zaccept, dst_fn))) { /* Skip entry */   || (zaccept && !find_list_entry(zaccept, dst_fn))
446     ) { /* Skip entry */
447   i = 'n';   i = 'n';
448    
449   } else { /* Extract entry */   } else { /* Extract entry */
450   total_size += zip_header.formatted.ucmpsize;   if (listing) { /* List entry */
451     if (verbose) {
452   if (verbosity == v_list) { /* List entry */   unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
453   unsigned int dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);   printf("%9u  %02u-%02u-%02u %02u:%02u   %s\n",
  printf("%9u  %02u-%02u-%02u %02u:%02u   %s\n",  
454     zip_header.formatted.ucmpsize,     zip_header.formatted.ucmpsize,
455     (dostime & 0x01e00000) >> 21,     (dostime & 0x01e00000) >> 21,
456     (dostime & 0x001f0000) >> 16,     (dostime & 0x001f0000) >> 16,
# Line 267  int unzip_main(int argc, char **argv) Line 458  int unzip_main(int argc, char **argv)
458     (dostime & 0x0000f800) >> 11,     (dostime & 0x0000f800) >> 11,
459     (dostime & 0x000007e0) >> 5,     (dostime & 0x000007e0) >> 5,
460     dst_fn);     dst_fn);
461   total_entries++;   total_size += zip_header.formatted.ucmpsize;
462     } else {
463     /* short listing -- filenames only */
464     puts(dst_fn);
465     }
466   i = 'n';   i = 'n';
467   } else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */   } else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */
468   i = -1;   i = -1;
469   } else if (last_char_is(dst_fn, '/')) { /* Extract directory */   } else if (last_char_is(dst_fn, '/')) { /* Extract directory */
470   if (stat(dst_fn, &stat_buf) == -1) {   if (stat(dst_fn, &stat_buf) == -1) {
471   if (errno != ENOENT) {   if (errno != ENOENT) {
472   bb_perror_msg_and_die("cannot stat '%s'",dst_fn);   bb_perror_msg_and_die("can't stat '%s'", dst_fn);
473   }   }
474   if (verbosity == v_normal) {   if (verbose) {
475   printf("   creating: %s\n", dst_fn);   printf("   creating: %s\n", dst_fn);
476   }   }
477   unzip_create_leading_dirs(dst_fn);   unzip_create_leading_dirs(dst_fn);
# Line 291  int unzip_main(int argc, char **argv) Line 486  int unzip_main(int argc, char **argv)
486   i = 'n';   i = 'n';
487    
488   } else {  /* Extract file */   } else {  /* Extract file */
489   _check_file:   check_file:
490   if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */   if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */
491   if (errno != ENOENT) {   if (errno != ENOENT) {
492   bb_perror_msg_and_die("cannot stat '%s'",dst_fn);   bb_perror_msg_and_die("can't stat '%s'", dst_fn);
493   }   }
494   i = 'y';   i = 'y';
495   } else { /* File already exists */   } else { /* File already exists */
496   if (overwrite == o_never) {   if (overwrite == O_NEVER) {
497   i = 'n';   i = 'n';
498   } else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */   } else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */
499   if (overwrite == o_always) {   if (overwrite == O_ALWAYS) {
500   i = 'y';   i = 'y';
501   } else {   } else {
502   printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);   printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
503   if (!fgets(key_buf, 512, stdin)) {   if (!fgets(key_buf, sizeof(key_buf), stdin)) {
504   bb_perror_msg_and_die("cannot read input");   bb_perror_msg_and_die("can't read input");
505   }   }
506   i = key_buf[0];   i = key_buf[0];
507   }   }
508   } else { /* File is not regular file */   } else { /* File is not regular file */
509   bb_error_msg_and_die("'%s' exists but is not regular file",dst_fn);   bb_error_msg_and_die("'%s' exists but is not regular file", dst_fn);
510   }   }
511   }   }
512   }   }
# Line 319  int unzip_main(int argc, char **argv) Line 514  int unzip_main(int argc, char **argv)
514    
515   switch (i) {   switch (i) {
516   case 'A':   case 'A':
517   overwrite = o_always;   overwrite = O_ALWAYS;
518   case 'y': /* Open file and fall into unzip */   case 'y': /* Open file and fall into unzip */
519   unzip_create_leading_dirs(dst_fn);   unzip_create_leading_dirs(dst_fn);
520   dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);   dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
521   case -1: /* Unzip */   case -1: /* Unzip */
522   if (verbosity == v_normal) {   if (verbose) {
523   printf("  inflating: %s\n", dst_fn);   printf("  inflating: %s\n", dst_fn);
524   }   }
525   if (unzip_extract(&zip_header, src_fd, dst_fd)) {   unzip_extract(&zip_header, dst_fd);
  failed = 1;  
  }  
526   if (dst_fd != STDOUT_FILENO) {   if (dst_fd != STDOUT_FILENO) {
527   /* closing STDOUT is potentially bad for future business */   /* closing STDOUT is potentially bad for future business */
528   close(dst_fd);   close(dst_fd);
# Line 337  int unzip_main(int argc, char **argv) Line 530  int unzip_main(int argc, char **argv)
530   break;   break;
531    
532   case 'N':   case 'N':
533   overwrite = o_never;   overwrite = O_NEVER;
534   case 'n':   case 'n':
535   /* Skip entry data */   /* Skip entry data */
536   unzip_skip(src_fd, zip_header.formatted.cmpsize);   unzip_skip(zip_header.formatted.cmpsize);
537   break;   break;
538    
539   case 'r':   case 'r':
540   /* Prompt for new name */   /* Prompt for new name */
541   printf("new name: ");   printf("new name: ");
542   if (!fgets(key_buf, 512, stdin)) {   if (!fgets(key_buf, sizeof(key_buf), stdin)) {
543   bb_perror_msg_and_die("cannot read input");   bb_perror_msg_and_die("can't read input");
544   }   }
545   free(dst_fn);   free(dst_fn);
546   dst_fn = xstrdup(key_buf);   dst_fn = xstrdup(key_buf);
547   chomp(dst_fn);   chomp(dst_fn);
548   goto _check_file;   goto check_file;
549    
550   default:   default:
551   printf("error: invalid response [%c]\n",(char)i);   printf("error: invalid response [%c]\n",(char)i);
552   goto _check_file;   goto check_file;
553   }   }
554    
555   /* Data descriptor section */   total_entries++;
  if (zip_header.formatted.flags & 4) {  
  /* skip over duplicate crc, compressed size and uncompressed size */  
  unzip_skip(src_fd, 12);  
  }  
556   }   }
557    
558   if (verbosity == v_list) {   if (listing && verbose) {
559   printf(" --------                   -------\n"   printf(" --------                   -------\n"
560         "%9d                   %d files\n", total_size, total_entries);         "%9d                   %d files\n",
561           total_size, total_entries);
562   }   }
563    
564   return failed;   return 0;
565  }  }

Legend:
Removed from v.815  
changed lines
  Added in v.816