aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-05-24 04:33:02 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-05-24 04:33:02 +0200
commit4e8ff73e20ed15e5552f960358f1e5bb4d25c44b (patch)
tree071f6381070277e3f0cc0b596007795a773f4450
parentad7a5d436c8dec563f834a0a9bdad9e69b333cc9 (diff)
downloadbusybox-w32-4e8ff73e20ed15e5552f960358f1e5bb4d25c44b.tar.gz
busybox-w32-4e8ff73e20ed15e5552f960358f1e5bb4d25c44b.tar.bz2
busybox-w32-4e8ff73e20ed15e5552f960358f1e5bb4d25c44b.zip
unzip: restore unix file mode if possible. closes bug 1045
function old new delta unzip_main 2197 2188 -9 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 0/1 up/down: 173/-182) Total: -9 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--archival/unzip.c143
1 files changed, 88 insertions, 55 deletions
diff --git a/archival/unzip.c b/archival/unzip.c
index afab3280d..868166bb1 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -25,12 +25,12 @@
25enum { 25enum {
26#if BB_BIG_ENDIAN 26#if BB_BIG_ENDIAN
27 ZIP_FILEHEADER_MAGIC = 0x504b0304, 27 ZIP_FILEHEADER_MAGIC = 0x504b0304,
28 ZIP_CDS_MAGIC = 0x504b0102, 28 ZIP_CDF_MAGIC = 0x504b0102, /* central directory's file header */
29 ZIP_CDE_MAGIC = 0x504b0506, 29 ZIP_CDE_MAGIC = 0x504b0506, /* "end of central directory" record */
30 ZIP_DD_MAGIC = 0x504b0708, 30 ZIP_DD_MAGIC = 0x504b0708,
31#else 31#else
32 ZIP_FILEHEADER_MAGIC = 0x04034b50, 32 ZIP_FILEHEADER_MAGIC = 0x04034b50,
33 ZIP_CDS_MAGIC = 0x02014b50, 33 ZIP_CDF_MAGIC = 0x02014b50,
34 ZIP_CDE_MAGIC = 0x06054b50, 34 ZIP_CDE_MAGIC = 0x06054b50,
35 ZIP_DD_MAGIC = 0x08074b50, 35 ZIP_DD_MAGIC = 0x08074b50,
36#endif 36#endif
@@ -77,15 +77,15 @@ struct BUG_zip_header_must_be_26_bytes {
77 (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \ 77 (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \
78} while (0) 78} while (0)
79 79
80#define CDS_HEADER_LEN 42 80#define CDF_HEADER_LEN 42
81 81
82typedef union { 82typedef union {
83 uint8_t raw[CDS_HEADER_LEN]; 83 uint8_t raw[CDF_HEADER_LEN];
84 struct { 84 struct {
85 /* uint32_t signature; 50 4b 01 02 */ 85 /* uint32_t signature; 50 4b 01 02 */
86 uint16_t version_made_by; /* 0-1 */ 86 uint16_t version_made_by; /* 0-1 */
87 uint16_t version_needed; /* 2-3 */ 87 uint16_t version_needed; /* 2-3 */
88 uint16_t cds_flags; /* 4-5 */ 88 uint16_t cdf_flags; /* 4-5 */
89 uint16_t method; /* 6-7 */ 89 uint16_t method; /* 6-7 */
90 uint16_t mtime; /* 8-9 */ 90 uint16_t mtime; /* 8-9 */
91 uint16_t mdate; /* 10-11 */ 91 uint16_t mdate; /* 10-11 */
@@ -100,21 +100,25 @@ typedef union {
100 uint32_t external_file_attributes PACKED; /* 34-37 */ 100 uint32_t external_file_attributes PACKED; /* 34-37 */
101 uint32_t relative_offset_of_local_header PACKED; /* 38-41 */ 101 uint32_t relative_offset_of_local_header PACKED; /* 38-41 */
102 } formatted PACKED; 102 } formatted PACKED;
103} cds_header_t; 103} cdf_header_t;
104 104
105struct BUG_cds_header_must_be_42_bytes { 105struct BUG_cdf_header_must_be_42_bytes {
106 char BUG_cds_header_must_be_42_bytes[ 106 char BUG_cdf_header_must_be_42_bytes[
107 offsetof(cds_header_t, formatted.relative_offset_of_local_header) + 4 107 offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4
108 == CDS_HEADER_LEN ? 1 : -1]; 108 == CDF_HEADER_LEN ? 1 : -1];
109}; 109};
110 110
111#define FIX_ENDIANNESS_CDS(cds_header) do { \ 111#define FIX_ENDIANNESS_CDF(cdf_header) do { \
112 (cds_header).formatted.crc32 = SWAP_LE32((cds_header).formatted.crc32 ); \ 112 (cdf_header).formatted.crc32 = SWAP_LE32((cdf_header).formatted.crc32 ); \
113 (cds_header).formatted.cmpsize = SWAP_LE32((cds_header).formatted.cmpsize ); \ 113 (cdf_header).formatted.cmpsize = SWAP_LE32((cdf_header).formatted.cmpsize ); \
114 (cds_header).formatted.ucmpsize = SWAP_LE32((cds_header).formatted.ucmpsize ); \ 114 (cdf_header).formatted.ucmpsize = SWAP_LE32((cdf_header).formatted.ucmpsize ); \
115 (cds_header).formatted.file_name_length = SWAP_LE16((cds_header).formatted.file_name_length); \ 115 (cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \
116 (cds_header).formatted.extra_field_length = SWAP_LE16((cds_header).formatted.extra_field_length); \ 116 (cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \
117 (cds_header).formatted.file_comment_length = SWAP_LE16((cds_header).formatted.file_comment_length); \ 117 (cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \
118 IF_DESKTOP( \
119 (cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \
120 (cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \
121 ) \
118} while (0) 122} while (0)
119 123
120#define CDE_HEADER_LEN 16 124#define CDE_HEADER_LEN 16
@@ -124,11 +128,11 @@ typedef union {
124 struct { 128 struct {
125 /* uint32_t signature; 50 4b 05 06 */ 129 /* uint32_t signature; 50 4b 05 06 */
126 uint16_t this_disk_no; 130 uint16_t this_disk_no;
127 uint16_t disk_with_cds_no; 131 uint16_t disk_with_cdf_no;
128 uint16_t cds_entries_on_this_disk; 132 uint16_t cdf_entries_on_this_disk;
129 uint16_t cds_entries_total; 133 uint16_t cdf_entries_total;
130 uint32_t cds_size; 134 uint32_t cdf_size;
131 uint32_t cds_offset; 135 uint32_t cdf_offset;
132 /* uint16_t file_comment_length; */ 136 /* uint16_t file_comment_length; */
133 /* .ZIP file comment (variable size) */ 137 /* .ZIP file comment (variable size) */
134 } formatted PACKED; 138 } formatted PACKED;
@@ -140,7 +144,7 @@ struct BUG_cde_header_must_be_16_bytes {
140}; 144};
141 145
142#define FIX_ENDIANNESS_CDE(cde_header) do { \ 146#define FIX_ENDIANNESS_CDE(cde_header) do { \
143 (cde_header).formatted.cds_offset = SWAP_LE32((cde_header).formatted.cds_offset); \ 147 (cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \
144} while (0) 148} while (0)
145 149
146enum { zip_fd = 3 }; 150enum { zip_fd = 3 };
@@ -148,7 +152,7 @@ enum { zip_fd = 3 };
148 152
149#if ENABLE_DESKTOP 153#if ENABLE_DESKTOP
150/* NB: does not preserve file position! */ 154/* NB: does not preserve file position! */
151static uint32_t find_cds_offset(void) 155static uint32_t find_cdf_offset(void)
152{ 156{
153 unsigned char buf[1024]; 157 unsigned char buf[1024];
154 cde_header_t cde_header; 158 cde_header_t cde_header;
@@ -177,32 +181,30 @@ static uint32_t find_cds_offset(void)
177 /* we found CDE! */ 181 /* we found CDE! */
178 memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN); 182 memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);
179 FIX_ENDIANNESS_CDE(cde_header); 183 FIX_ENDIANNESS_CDE(cde_header);
180 return cde_header.formatted.cds_offset; 184 return cde_header.formatted.cdf_offset;
181 } 185 }
182 bb_error_msg_and_die("can't find file table"); 186 bb_error_msg_and_die("can't find file table");
183}; 187};
184 188
185static uint32_t read_next_cds(int count_m1, uint32_t cds_offset, cds_header_t *cds_ptr) 189static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
186{ 190{
187 off_t org; 191 off_t org;
188 192
189 org = xlseek(zip_fd, 0, SEEK_CUR); 193 org = xlseek(zip_fd, 0, SEEK_CUR);
190 194
191 if (!cds_offset) 195 if (!cdf_offset)
192 cds_offset = find_cds_offset(); 196 cdf_offset = find_cdf_offset();
193 197
194 while (count_m1-- >= 0) { 198 xlseek(zip_fd, cdf_offset + 4, SEEK_SET);
195 xlseek(zip_fd, cds_offset + 4, SEEK_SET); 199 xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN);
196 xread(zip_fd, cds_ptr->raw, CDS_HEADER_LEN); 200 FIX_ENDIANNESS_CDF(*cdf_ptr);
197 FIX_ENDIANNESS_CDS(*cds_ptr); 201 cdf_offset += 4 + CDF_HEADER_LEN
198 cds_offset += 4 + CDS_HEADER_LEN 202 + cdf_ptr->formatted.file_name_length
199 + cds_ptr->formatted.file_name_length 203 + cdf_ptr->formatted.extra_field_length
200 + cds_ptr->formatted.extra_field_length 204 + cdf_ptr->formatted.file_comment_length;
201 + cds_ptr->formatted.file_comment_length;
202 }
203 205
204 xlseek(zip_fd, org, SEEK_SET); 206 xlseek(zip_fd, org, SEEK_SET);
205 return cds_offset; 207 return cdf_offset;
206}; 208};
207#endif 209#endif
208 210
@@ -258,8 +260,7 @@ int unzip_main(int argc, char **argv)
258 smallint listing = 0; 260 smallint listing = 0;
259 smallint overwrite = O_PROMPT; 261 smallint overwrite = O_PROMPT;
260#if ENABLE_DESKTOP 262#if ENABLE_DESKTOP
261 uint32_t cds_offset; 263 uint32_t cdf_offset;
262 unsigned cds_entries;
263#endif 264#endif
264 unsigned long total_usize; 265 unsigned long total_usize;
265 unsigned long total_size; 266 unsigned long total_size;
@@ -435,20 +436,42 @@ int unzip_main(int argc, char **argv)
435 } 436 }
436 } 437 }
437 438
439/* Example of an archive with one 0-byte long file named 'z'
440 * created by Zip 2.31 on Unix:
441 * 0000 [50 4b]03 04 0a 00 00 00 00 00 42 1a b8 3c 00 00 |PK........B..<..|
442 * sig........ vneed flags compr mtime mdate crc32>
443 * 0010 00 00 00 00 00 00 00 00 00 00 01 00 15 00 7a 55 |..............zU|
444 * >..... csize...... usize...... fnlen exlen fn ex>
445 * 0020 54 09 00 03 cc d3 f9 4b cc d3 f9 4b 55 78 04 00 |T......K...KUx..|
446 * >tra_field......................................
447 * 0030 00 00 00 00[50 4b]01 02 17 03 0a 00 00 00 00 00 |....PK..........|
448 * ........... sig........ vmade vneed flags compr
449 * 0040 42 1a b8 3c 00 00 00 00 00 00 00 00 00 00 00 00 |B..<............|
450 * mtime mdate crc32...... csize...... usize......
451 * 0050 01 00 0d 00 00 00 00 00 00 00 00 00 a4 81 00 00 |................|
452 * fnlen exlen clen. dnum. iattr eattr...... relofs> (eattr = rw-r--r--)
453 * 0060 00 00 7a 55 54 05 00 03 cc d3 f9 4b 55 78 00 00 |..zUT......KUx..|
454 * >..... fn extra_field...........................
455 * 0070 [50 4b]05 06 00 00 00 00 01 00 01 00 3c 00 00 00 |PK..........<...|
456 * 0080 34 00 00 00 00 00 |4.....|
457 */
438 total_usize = 0; 458 total_usize = 0;
439 total_size = 0; 459 total_size = 0;
440 total_entries = 0; 460 total_entries = 0;
441#if ENABLE_DESKTOP 461#if ENABLE_DESKTOP
442 cds_entries = 0; 462 cdf_offset = 0;
443 cds_offset = 0;
444#endif 463#endif
445 while (1) { 464 while (1) {
446 uint32_t magic; 465 uint32_t magic;
466 mode_t dir_mode = 0777;
467#if ENABLE_DESKTOP
468 mode_t file_mode = 0666;
469#endif
447 470
448 /* Check magic number */ 471 /* Check magic number */
449 xread(zip_fd, &magic, 4); 472 xread(zip_fd, &magic, 4);
450 /* Central directory? It's at the end, so exit */ 473 /* Central directory? It's at the end, so exit */
451 if (magic == ZIP_CDS_MAGIC) 474 if (magic == ZIP_CDF_MAGIC)
452 break; 475 break;
453#if ENABLE_DESKTOP 476#if ENABLE_DESKTOP
454 /* Data descriptor? It was a streaming file, go on */ 477 /* Data descriptor? It was a streaming file, go on */
@@ -476,15 +499,21 @@ int unzip_main(int argc, char **argv)
476 /* 0x0001 - encrypted */ 499 /* 0x0001 - encrypted */
477 bb_error_msg_and_die("zip flag 1 (encryption) is not supported"); 500 bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
478 } 501 }
479 if (zip_header.formatted.flags & 0x0008) { 502
480 cds_header_t cds_header; 503 {
481 /* 0x0008 - streaming. [u]cmpsize can be reliably gotten 504 cdf_header_t cdf_header;
482 * only from Central Directory. See unzip_doc.txt */ 505 cdf_offset = read_next_cdf(cdf_offset, &cdf_header);
483 cds_offset = read_next_cds(total_entries - cds_entries, cds_offset, &cds_header); 506 if (zip_header.formatted.flags & 0x0008) {
484 cds_entries = total_entries + 1; 507 /* 0x0008 - streaming. [u]cmpsize can be reliably gotten
485 zip_header.formatted.crc32 = cds_header.formatted.crc32; 508 * only from Central Directory. See unzip_doc.txt */
486 zip_header.formatted.cmpsize = cds_header.formatted.cmpsize; 509 zip_header.formatted.crc32 = cdf_header.formatted.crc32;
487 zip_header.formatted.ucmpsize = cds_header.formatted.ucmpsize; 510 zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize;
511 zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize;
512 }
513 if ((cdf_header.formatted.version_made_by >> 8) == 3) {
514 /* this archive is created on Unix */
515 dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16);
516 }
488 } 517 }
489#endif 518#endif
490 519
@@ -550,7 +579,7 @@ int unzip_main(int argc, char **argv)
550 printf(" creating: %s\n", dst_fn); 579 printf(" creating: %s\n", dst_fn);
551 } 580 }
552 unzip_create_leading_dirs(dst_fn); 581 unzip_create_leading_dirs(dst_fn);
553 if (bb_make_directory(dst_fn, 0777, 0)) { 582 if (bb_make_directory(dst_fn, dir_mode, 0)) {
554 bb_error_msg_and_die("exiting"); 583 bb_error_msg_and_die("exiting");
555 } 584 }
556 } else { 585 } else {
@@ -592,7 +621,11 @@ int unzip_main(int argc, char **argv)
592 overwrite = O_ALWAYS; 621 overwrite = O_ALWAYS;
593 case 'y': /* Open file and fall into unzip */ 622 case 'y': /* Open file and fall into unzip */
594 unzip_create_leading_dirs(dst_fn); 623 unzip_create_leading_dirs(dst_fn);
624#if ENABLE_DESKTOP
625 dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode);
626#else
595 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC); 627 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
628#endif
596 case -1: /* Unzip */ 629 case -1: /* Unzip */
597 if (!quiet) { 630 if (!quiet) {
598 printf(" inflating: %s\n", dst_fn); 631 printf(" inflating: %s\n", dst_fn);