Magellan Linux

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

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

revision 1122 by niro, Sun May 30 11:32:42 2010 UTC revision 1123 by niro, Wed Aug 18 21:56:57 2010 UTC
# Line 25  Line 25 
25  enum {  enum {
26  #if BB_BIG_ENDIAN  #if BB_BIG_ENDIAN
27   ZIP_FILEHEADER_MAGIC = 0x504b0304,   ZIP_FILEHEADER_MAGIC = 0x504b0304,
28   ZIP_CDS_MAGIC        = 0x504b0102,   ZIP_CDF_MAGIC        = 0x504b0102, /* central directory's file header */
29   ZIP_CDE_MAGIC        = 0x504b0506,   ZIP_CDE_MAGIC        = 0x504b0506, /* "end of central directory" record */
30   ZIP_DD_MAGIC         = 0x504b0708,   ZIP_DD_MAGIC         = 0x504b0708,
31  #else  #else
32   ZIP_FILEHEADER_MAGIC = 0x04034b50,   ZIP_FILEHEADER_MAGIC = 0x04034b50,
33   ZIP_CDS_MAGIC        = 0x02014b50,   ZIP_CDF_MAGIC        = 0x02014b50,
34   ZIP_CDE_MAGIC        = 0x06054b50,   ZIP_CDE_MAGIC        = 0x06054b50,
35   ZIP_DD_MAGIC         = 0x08074b50,   ZIP_DD_MAGIC         = 0x08074b50,
36  #endif  #endif
# Line 42  typedef union { Line 42  typedef union {
42   uint8_t raw[ZIP_HEADER_LEN];   uint8_t raw[ZIP_HEADER_LEN];
43   struct {   struct {
44   uint16_t version;               /* 0-1 */   uint16_t version;               /* 0-1 */
45   uint16_t flags;                 /* 2-3 */   uint16_t zip_flags;             /* 2-3 */
46   uint16_t method;                /* 4-5 */   uint16_t method;                /* 4-5 */
47   uint16_t modtime;               /* 6-7 */   uint16_t modtime;               /* 6-7 */
48   uint16_t moddate;               /* 8-9 */   uint16_t moddate;               /* 8-9 */
# Line 66  struct BUG_zip_header_must_be_26_bytes { Line 66  struct BUG_zip_header_must_be_26_bytes {
66    
67  #define FIX_ENDIANNESS_ZIP(zip_header) do { \  #define FIX_ENDIANNESS_ZIP(zip_header) do { \
68   (zip_header).formatted.version      = SWAP_LE16((zip_header).formatted.version     ); \   (zip_header).formatted.version      = SWAP_LE16((zip_header).formatted.version     ); \
  (zip_header).formatted.flags        = SWAP_LE16((zip_header).formatted.flags       ); \  
69   (zip_header).formatted.method       = SWAP_LE16((zip_header).formatted.method      ); \   (zip_header).formatted.method       = SWAP_LE16((zip_header).formatted.method      ); \
70   (zip_header).formatted.modtime      = SWAP_LE16((zip_header).formatted.modtime     ); \   (zip_header).formatted.modtime      = SWAP_LE16((zip_header).formatted.modtime     ); \
71   (zip_header).formatted.moddate      = SWAP_LE16((zip_header).formatted.moddate     ); \   (zip_header).formatted.moddate      = SWAP_LE16((zip_header).formatted.moddate     ); \
# Line 77  struct BUG_zip_header_must_be_26_bytes { Line 76  struct BUG_zip_header_must_be_26_bytes {
76   (zip_header).formatted.extra_len    = SWAP_LE16((zip_header).formatted.extra_len   ); \   (zip_header).formatted.extra_len    = SWAP_LE16((zip_header).formatted.extra_len   ); \
77  } while (0)  } while (0)
78    
79  #define CDS_HEADER_LEN 42  #define CDF_HEADER_LEN 42
80    
81  typedef union {  typedef union {
82   uint8_t raw[CDS_HEADER_LEN];   uint8_t raw[CDF_HEADER_LEN];
83   struct {   struct {
84   /* uint32_t signature; 50 4b 01 02 */   /* uint32_t signature; 50 4b 01 02 */
85   uint16_t version_made_by;       /* 0-1 */   uint16_t version_made_by;       /* 0-1 */
86   uint16_t version_needed;        /* 2-3 */   uint16_t version_needed;        /* 2-3 */
87   uint16_t cds_flags;             /* 4-5 */   uint16_t cdf_flags;             /* 4-5 */
88   uint16_t method;                /* 6-7 */   uint16_t method;                /* 6-7 */
89   uint16_t mtime;                 /* 8-9 */   uint16_t mtime;                 /* 8-9 */
90   uint16_t mdate;                 /* 10-11 */   uint16_t mdate;                 /* 10-11 */
# Line 100  typedef union { Line 99  typedef union {
99   uint32_t external_file_attributes PACKED; /* 34-37 */   uint32_t external_file_attributes PACKED; /* 34-37 */
100   uint32_t relative_offset_of_local_header PACKED; /* 38-41 */   uint32_t relative_offset_of_local_header PACKED; /* 38-41 */
101   } formatted PACKED;   } formatted PACKED;
102  } cds_header_t;  } cdf_header_t;
103    
104  struct BUG_cds_header_must_be_42_bytes {  struct BUG_cdf_header_must_be_42_bytes {
105   char BUG_cds_header_must_be_42_bytes[   char BUG_cdf_header_must_be_42_bytes[
106   offsetof(cds_header_t, formatted.relative_offset_of_local_header) + 4   offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4
107   == CDS_HEADER_LEN ? 1 : -1];   == CDF_HEADER_LEN ? 1 : -1];
108  };  };
109    
110  #define FIX_ENDIANNESS_CDS(cds_header) do { \  #define FIX_ENDIANNESS_CDF(cdf_header) do { \
111   (cds_header).formatted.crc32        = SWAP_LE32((cds_header).formatted.crc32       ); \   (cdf_header).formatted.crc32        = SWAP_LE32((cdf_header).formatted.crc32       ); \
112   (cds_header).formatted.cmpsize      = SWAP_LE32((cds_header).formatted.cmpsize     ); \   (cdf_header).formatted.cmpsize      = SWAP_LE32((cdf_header).formatted.cmpsize     ); \
113   (cds_header).formatted.ucmpsize     = SWAP_LE32((cds_header).formatted.ucmpsize    ); \   (cdf_header).formatted.ucmpsize     = SWAP_LE32((cdf_header).formatted.ucmpsize    ); \
114   (cds_header).formatted.file_name_length = SWAP_LE16((cds_header).formatted.file_name_length); \   (cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \
115   (cds_header).formatted.extra_field_length = SWAP_LE16((cds_header).formatted.extra_field_length); \   (cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \
116   (cds_header).formatted.file_comment_length = SWAP_LE16((cds_header).formatted.file_comment_length); \   (cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \
117     IF_DESKTOP( \
118     (cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \
119     (cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \
120     ) \
121  } while (0)  } while (0)
122    
123  #define CDE_HEADER_LEN 16  #define CDE_HEADER_LEN 16
# Line 124  typedef union { Line 127  typedef union {
127   struct {   struct {
128   /* uint32_t signature; 50 4b 05 06 */   /* uint32_t signature; 50 4b 05 06 */
129   uint16_t this_disk_no;   uint16_t this_disk_no;
130   uint16_t disk_with_cds_no;   uint16_t disk_with_cdf_no;
131   uint16_t cds_entries_on_this_disk;   uint16_t cdf_entries_on_this_disk;
132   uint16_t cds_entries_total;   uint16_t cdf_entries_total;
133   uint32_t cds_size;   uint32_t cdf_size;
134   uint32_t cds_offset;   uint32_t cdf_offset;
135   /* uint16_t file_comment_length; */   /* uint16_t file_comment_length; */
136   /* .ZIP file comment (variable size) */   /* .ZIP file comment (variable size) */
137   } formatted PACKED;   } formatted PACKED;
# Line 140  struct BUG_cde_header_must_be_16_bytes { Line 143  struct BUG_cde_header_must_be_16_bytes {
143  };  };
144    
145  #define FIX_ENDIANNESS_CDE(cde_header) do { \  #define FIX_ENDIANNESS_CDE(cde_header) do { \
146   (cde_header).formatted.cds_offset = SWAP_LE32((cde_header).formatted.cds_offset); \   (cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \
147  } while (0)  } while (0)
148    
149  enum { zip_fd = 3 };  enum { zip_fd = 3 };
150    
151    
152  #if ENABLE_DESKTOP  #if ENABLE_DESKTOP
153    
154    #define PEEK_FROM_END 16384
155    
156  /* NB: does not preserve file position! */  /* NB: does not preserve file position! */
157  static uint32_t find_cds_offset(void)  static uint32_t find_cdf_offset(void)
158  {  {
  unsigned char buf[1024];  
159   cde_header_t cde_header;   cde_header_t cde_header;
160   unsigned char *p;   unsigned char *p;
161   off_t end;   off_t end;
162     unsigned char *buf = xzalloc(PEEK_FROM_END);
163    
164   end = xlseek(zip_fd, 0, SEEK_END);   end = xlseek(zip_fd, 0, SEEK_END);
165   if (end < 1024)   end -= PEEK_FROM_END;
166   end = 1024;   if (end < 0)
167   end -= 1024;   end = 0;
168   xlseek(zip_fd, end, SEEK_SET);   xlseek(zip_fd, end, SEEK_SET);
169   full_read(zip_fd, buf, 1024);   full_read(zip_fd, buf, PEEK_FROM_END);
170    
171   p = buf;   p = buf;
172   while (p <= buf + 1024 - CDE_HEADER_LEN - 4) {   while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) {
173   if (*p != 'P') {   if (*p != 'P') {
174   p++;   p++;
175   continue;   continue;
# Line 177  static uint32_t find_cds_offset(void) Line 183  static uint32_t find_cds_offset(void)
183   /* we found CDE! */   /* we found CDE! */
184   memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);   memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);
185   FIX_ENDIANNESS_CDE(cde_header);   FIX_ENDIANNESS_CDE(cde_header);
186   return cde_header.formatted.cds_offset;   free(buf);
187     return cde_header.formatted.cdf_offset;
188   }   }
189     //free(buf);
190   bb_error_msg_and_die("can't find file table");   bb_error_msg_and_die("can't find file table");
191  };  };
192    
193  static uint32_t read_next_cds(int count_m1, uint32_t cds_offset, cds_header_t *cds_ptr)  static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
194  {  {
195   off_t org;   off_t org;
196    
197   org = xlseek(zip_fd, 0, SEEK_CUR);   org = xlseek(zip_fd, 0, SEEK_CUR);
198    
199   if (!cds_offset)   if (!cdf_offset)
200   cds_offset = find_cds_offset();   cdf_offset = find_cdf_offset();
201    
202   while (count_m1-- >= 0) {   xlseek(zip_fd, cdf_offset + 4, SEEK_SET);
203   xlseek(zip_fd, cds_offset + 4, SEEK_SET);   xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN);
204   xread(zip_fd, cds_ptr->raw, CDS_HEADER_LEN);   FIX_ENDIANNESS_CDF(*cdf_ptr);
205   FIX_ENDIANNESS_CDS(*cds_ptr);   cdf_offset += 4 + CDF_HEADER_LEN
206   cds_offset += 4 + CDS_HEADER_LEN   + cdf_ptr->formatted.file_name_length
207   + cds_ptr->formatted.file_name_length   + cdf_ptr->formatted.extra_field_length
208   + cds_ptr->formatted.extra_field_length   + cdf_ptr->formatted.file_comment_length;
  + cds_ptr->formatted.file_comment_length;  
  }  
209    
210   xlseek(zip_fd, org, SEEK_SET);   xlseek(zip_fd, org, SEEK_SET);
211   return cds_offset;   return cdf_offset;
212  };  };
213  #endif  #endif
214    
# Line 258  int unzip_main(int argc, char **argv) Line 264  int unzip_main(int argc, char **argv)
264   smallint listing = 0;   smallint listing = 0;
265   smallint overwrite = O_PROMPT;   smallint overwrite = O_PROMPT;
266  #if ENABLE_DESKTOP  #if ENABLE_DESKTOP
267   uint32_t cds_offset;   uint32_t cdf_offset;
  unsigned cds_entries;  
268  #endif  #endif
269   unsigned long total_usize;   unsigned long total_usize;
270   unsigned long total_size;   unsigned long total_size;
# Line 435  int unzip_main(int argc, char **argv) Line 440  int unzip_main(int argc, char **argv)
440   }   }
441   }   }
442    
443    /* Example of an archive with one 0-byte long file named 'z'
444     * created by Zip 2.31 on Unix:
445     * 0000 [50 4b]03 04 0a 00 00 00 00 00 42 1a b8 3c 00 00 |PK........B..<..|
446     *       sig........ vneed flags compr mtime mdate crc32>
447     * 0010  00 00 00 00 00 00 00 00 00 00 01 00 15 00 7a 55 |..............zU|
448     *      >..... csize...... usize...... fnlen exlen fn ex>
449     * 0020  54 09 00 03 cc d3 f9 4b cc d3 f9 4b 55 78 04 00 |T......K...KUx..|
450     *      >tra_field......................................
451     * 0030  00 00 00 00[50 4b]01 02 17 03 0a 00 00 00 00 00 |....PK..........|
452     *       ........... sig........ vmade vneed flags compr
453     * 0040  42 1a b8 3c 00 00 00 00 00 00 00 00 00 00 00 00 |B..<............|
454     *       mtime mdate crc32...... csize...... usize......
455     * 0050  01 00 0d 00 00 00 00 00 00 00 00 00 a4 81 00 00 |................|
456     *       fnlen exlen clen. dnum. iattr eattr...... relofs> (eattr = rw-r--r--)
457     * 0060  00 00 7a 55 54 05 00 03 cc d3 f9 4b 55 78 00 00 |..zUT......KUx..|
458     *      >..... fn extra_field...........................
459     * 0070 [50 4b]05 06 00 00 00 00 01 00 01 00 3c 00 00 00 |PK..........<...|
460     * 0080  34 00 00 00 00 00                               |4.....|
461     */
462   total_usize = 0;   total_usize = 0;
463   total_size = 0;   total_size = 0;
464   total_entries = 0;   total_entries = 0;
465  #if ENABLE_DESKTOP  #if ENABLE_DESKTOP
466   cds_entries = 0;   cdf_offset = 0;
  cds_offset = 0;  
467  #endif  #endif
468   while (1) {   while (1) {
469   uint32_t magic;   uint32_t magic;
470     mode_t dir_mode = 0777;
471    #if ENABLE_DESKTOP
472     mode_t file_mode = 0666;
473    #endif
474    
475   /* Check magic number */   /* Check magic number */
476   xread(zip_fd, &magic, 4);   xread(zip_fd, &magic, 4);
477   /* Central directory? It's at the end, so exit */   /* Central directory? It's at the end, so exit */
478   if (magic == ZIP_CDS_MAGIC)   if (magic == ZIP_CDF_MAGIC)
479   break;   break;
480  #if ENABLE_DESKTOP  #if ENABLE_DESKTOP
481   /* Data descriptor? It was a streaming file, go on */   /* Data descriptor? It was a streaming file, go on */
# Line 468  int unzip_main(int argc, char **argv) Line 495  int unzip_main(int argc, char **argv)
495   bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);   bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
496   }   }
497  #if !ENABLE_DESKTOP  #if !ENABLE_DESKTOP
498   if (zip_header.formatted.flags & 0x0009) {   if (zip_header.formatted.zip_flags & SWAP_LE16(0x0009)) {
499   bb_error_msg_and_die("zip flags 1 and 8 are not supported");   bb_error_msg_and_die("zip flags 1 and 8 are not supported");
500   }   }
501  #else  #else
502   if (zip_header.formatted.flags & 0x0001) {   if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) {
503   /* 0x0001 - encrypted */   /* 0x0001 - encrypted */
504   bb_error_msg_and_die("zip flag 1 (encryption) is not supported");   bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
505   }   }
506   if (zip_header.formatted.flags & 0x0008) {  
507   cds_header_t cds_header;   {
508   /* 0x0008 - streaming. [u]cmpsize can be reliably gotten   cdf_header_t cdf_header;
509   * only from Central Directory. See unzip_doc.txt */   cdf_offset = read_next_cdf(cdf_offset, &cdf_header);
510   cds_offset = read_next_cds(total_entries - cds_entries, cds_offset, &cds_header);   if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) {
511   cds_entries = total_entries + 1;   /* 0x0008 - streaming. [u]cmpsize can be reliably gotten
512   zip_header.formatted.crc32    = cds_header.formatted.crc32;   * only from Central Directory. See unzip_doc.txt */
513   zip_header.formatted.cmpsize  = cds_header.formatted.cmpsize;   zip_header.formatted.crc32    = cdf_header.formatted.crc32;
514   zip_header.formatted.ucmpsize = cds_header.formatted.ucmpsize;   zip_header.formatted.cmpsize  = cdf_header.formatted.cmpsize;
515     zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize;
516     }
517     if ((cdf_header.formatted.version_made_by >> 8) == 3) {
518     /* this archive is created on Unix */
519     dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16);
520     }
521   }   }
522  #endif  #endif
523    
# Line 550  int unzip_main(int argc, char **argv) Line 583  int unzip_main(int argc, char **argv)
583   printf("   creating: %s\n", dst_fn);   printf("   creating: %s\n", dst_fn);
584   }   }
585   unzip_create_leading_dirs(dst_fn);   unzip_create_leading_dirs(dst_fn);
586   if (bb_make_directory(dst_fn, 0777, 0)) {   if (bb_make_directory(dst_fn, dir_mode, 0)) {
587   bb_error_msg_and_die("exiting");   bb_error_msg_and_die("exiting");
588   }   }
589   } else {   } else {
# Line 592  int unzip_main(int argc, char **argv) Line 625  int unzip_main(int argc, char **argv)
625   overwrite = O_ALWAYS;   overwrite = O_ALWAYS;
626   case 'y': /* Open file and fall into unzip */   case 'y': /* Open file and fall into unzip */
627   unzip_create_leading_dirs(dst_fn);   unzip_create_leading_dirs(dst_fn);
628    #if ENABLE_DESKTOP
629     dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode);
630    #else
631   dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);   dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
632    #endif
633   case -1: /* Unzip */   case -1: /* Unzip */
634   if (!quiet) {   if (!quiet) {
635   printf("  inflating: %s\n", dst_fn);   printf("  inflating: %s\n", dst_fn);

Legend:
Removed from v.1122  
changed lines
  Added in v.1123