diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-08 14:14:19 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-01-08 14:14:19 +0100 |
commit | 0ffac1cc22e3e864e64c1e0357ffd127fd1c1b23 (patch) | |
tree | 1ff0357518225673e5d8fd5dc099cbde2ed172b9 | |
parent | 86584e134eec1a81298149f8c04c77727f6dccb9 (diff) | |
download | busybox-w32-0ffac1cc22e3e864e64c1e0357ffd127fd1c1b23.tar.gz busybox-w32-0ffac1cc22e3e864e64c1e0357ffd127fd1c1b23.tar.bz2 busybox-w32-0ffac1cc22e3e864e64c1e0357ffd127fd1c1b23.zip |
unzip: do not use CDF.extra_len, read local file header. Closes 9536
While at it, shorten many field and variable names.
function old new delta
unzip_main 2334 2376 +42
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | archival/unzip.c | 236 | ||||
-rwxr-xr-x | testsuite/unzip.tests | 4 |
2 files changed, 125 insertions, 115 deletions
diff --git a/archival/unzip.c b/archival/unzip.c index 98a71c09d..921493591 100644 --- a/archival/unzip.c +++ b/archival/unzip.c | |||
@@ -62,8 +62,8 @@ | |||
62 | enum { | 62 | enum { |
63 | #if BB_BIG_ENDIAN | 63 | #if BB_BIG_ENDIAN |
64 | ZIP_FILEHEADER_MAGIC = 0x504b0304, | 64 | ZIP_FILEHEADER_MAGIC = 0x504b0304, |
65 | ZIP_CDF_MAGIC = 0x504b0102, /* central directory's file header */ | 65 | ZIP_CDF_MAGIC = 0x504b0102, /* CDF item */ |
66 | ZIP_CDE_MAGIC = 0x504b0506, /* "end of central directory" record */ | 66 | ZIP_CDE_MAGIC = 0x504b0506, /* End of CDF */ |
67 | ZIP_DD_MAGIC = 0x504b0708, | 67 | ZIP_DD_MAGIC = 0x504b0708, |
68 | #else | 68 | #else |
69 | ZIP_FILEHEADER_MAGIC = 0x04034b50, | 69 | ZIP_FILEHEADER_MAGIC = 0x04034b50, |
@@ -91,16 +91,16 @@ typedef union { | |||
91 | /* filename follows (not NUL terminated) */ | 91 | /* filename follows (not NUL terminated) */ |
92 | /* extra field follows */ | 92 | /* extra field follows */ |
93 | /* data follows */ | 93 | /* data follows */ |
94 | } formatted PACKED; | 94 | } fmt PACKED; |
95 | } zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */ | 95 | } zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */ |
96 | 96 | ||
97 | #define FIX_ENDIANNESS_ZIP(zip_header) \ | 97 | #define FIX_ENDIANNESS_ZIP(zip) \ |
98 | do { if (BB_BIG_ENDIAN) { \ | 98 | do { if (BB_BIG_ENDIAN) { \ |
99 | (zip_header).formatted.crc32 = SWAP_LE32((zip_header).formatted.crc32 ); \ | 99 | (zip).fmt.crc32 = SWAP_LE32((zip).fmt.crc32 ); \ |
100 | (zip_header).formatted.cmpsize = SWAP_LE32((zip_header).formatted.cmpsize ); \ | 100 | (zip).fmt.cmpsize = SWAP_LE32((zip).fmt.cmpsize ); \ |
101 | (zip_header).formatted.ucmpsize = SWAP_LE32((zip_header).formatted.ucmpsize ); \ | 101 | (zip).fmt.ucmpsize = SWAP_LE32((zip).fmt.ucmpsize ); \ |
102 | (zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \ | 102 | (zip).fmt.filename_len = SWAP_LE16((zip).fmt.filename_len); \ |
103 | (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \ | 103 | (zip).fmt.extra_len = SWAP_LE16((zip).fmt.extra_len ); \ |
104 | }} while (0) | 104 | }} while (0) |
105 | 105 | ||
106 | #define CDF_HEADER_LEN 42 | 106 | #define CDF_HEADER_LEN 42 |
@@ -118,39 +118,39 @@ typedef union { | |||
118 | uint32_t crc32; /* 12-15 */ | 118 | uint32_t crc32; /* 12-15 */ |
119 | uint32_t cmpsize; /* 16-19 */ | 119 | uint32_t cmpsize; /* 16-19 */ |
120 | uint32_t ucmpsize; /* 20-23 */ | 120 | uint32_t ucmpsize; /* 20-23 */ |
121 | uint16_t file_name_length; /* 24-25 */ | 121 | uint16_t filename_len; /* 24-25 */ |
122 | uint16_t extra_field_length; /* 26-27 */ | 122 | uint16_t extra_len; /* 26-27 */ |
123 | uint16_t file_comment_length; /* 28-29 */ | 123 | uint16_t file_comment_length; /* 28-29 */ |
124 | uint16_t disk_number_start; /* 30-31 */ | 124 | uint16_t disk_number_start; /* 30-31 */ |
125 | uint16_t internal_file_attributes; /* 32-33 */ | 125 | uint16_t internal_attributes; /* 32-33 */ |
126 | uint32_t external_file_attributes PACKED; /* 34-37 */ | 126 | uint32_t external_attributes PACKED; /* 34-37 */ |
127 | uint32_t relative_offset_of_local_header PACKED; /* 38-41 */ | 127 | uint32_t relative_offset_of_local_header PACKED; /* 38-41 */ |
128 | /* filename follows (not NUL terminated) */ | 128 | /* filename follows (not NUL terminated) */ |
129 | /* extra field follows */ | 129 | /* extra field follows */ |
130 | /* comment follows */ | 130 | /* file comment follows */ |
131 | } formatted PACKED; | 131 | } fmt PACKED; |
132 | } cdf_header_t; | 132 | } cdf_header_t; |
133 | 133 | ||
134 | #define FIX_ENDIANNESS_CDF(cdf_header) \ | 134 | #define FIX_ENDIANNESS_CDF(cdf) \ |
135 | do { if (BB_BIG_ENDIAN) { \ | 135 | do { if (BB_BIG_ENDIAN) { \ |
136 | (cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \ | 136 | (cdf).fmt.version_made_by = SWAP_LE16((cdf).fmt.version_made_by); \ |
137 | (cdf_header).formatted.version_needed = SWAP_LE16((cdf_header).formatted.version_needed); \ | 137 | (cdf).fmt.version_needed = SWAP_LE16((cdf).fmt.version_needed); \ |
138 | (cdf_header).formatted.method = SWAP_LE16((cdf_header).formatted.method ); \ | 138 | (cdf).fmt.method = SWAP_LE16((cdf).fmt.method ); \ |
139 | (cdf_header).formatted.modtime = SWAP_LE16((cdf_header).formatted.modtime ); \ | 139 | (cdf).fmt.modtime = SWAP_LE16((cdf).fmt.modtime ); \ |
140 | (cdf_header).formatted.moddate = SWAP_LE16((cdf_header).formatted.moddate ); \ | 140 | (cdf).fmt.moddate = SWAP_LE16((cdf).fmt.moddate ); \ |
141 | (cdf_header).formatted.crc32 = SWAP_LE32((cdf_header).formatted.crc32 ); \ | 141 | (cdf).fmt.crc32 = SWAP_LE32((cdf).fmt.crc32 ); \ |
142 | (cdf_header).formatted.cmpsize = SWAP_LE32((cdf_header).formatted.cmpsize ); \ | 142 | (cdf).fmt.cmpsize = SWAP_LE32((cdf).fmt.cmpsize ); \ |
143 | (cdf_header).formatted.ucmpsize = SWAP_LE32((cdf_header).formatted.ucmpsize ); \ | 143 | (cdf).fmt.ucmpsize = SWAP_LE32((cdf).fmt.ucmpsize ); \ |
144 | (cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \ | 144 | (cdf).fmt.filename_len = SWAP_LE16((cdf).fmt.filename_len); \ |
145 | (cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \ | 145 | (cdf).fmt.extra_len = SWAP_LE16((cdf).fmt.extra_len ); \ |
146 | (cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \ | 146 | (cdf).fmt.file_comment_length = SWAP_LE16((cdf).fmt.file_comment_length); \ |
147 | (cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \ | 147 | (cdf).fmt.external_attributes = SWAP_LE32((cdf).fmt.external_attributes); \ |
148 | }} while (0) | 148 | }} while (0) |
149 | 149 | ||
150 | #define CDE_HEADER_LEN 16 | 150 | #define CDE_LEN 16 |
151 | 151 | ||
152 | typedef union { | 152 | typedef union { |
153 | uint8_t raw[CDE_HEADER_LEN]; | 153 | uint8_t raw[CDE_LEN]; |
154 | struct { | 154 | struct { |
155 | /* uint32_t signature; 50 4b 05 06 */ | 155 | /* uint32_t signature; 50 4b 05 06 */ |
156 | uint16_t this_disk_no; | 156 | uint16_t this_disk_no; |
@@ -159,14 +159,14 @@ typedef union { | |||
159 | uint16_t cdf_entries_total; | 159 | uint16_t cdf_entries_total; |
160 | uint32_t cdf_size; | 160 | uint32_t cdf_size; |
161 | uint32_t cdf_offset; | 161 | uint32_t cdf_offset; |
162 | /* uint16_t file_comment_length; */ | 162 | /* uint16_t archive_comment_length; */ |
163 | /* .ZIP file comment (variable size) */ | 163 | /* archive comment follows */ |
164 | } formatted PACKED; | 164 | } fmt PACKED; |
165 | } cde_header_t; | 165 | } cde_t; |
166 | 166 | ||
167 | #define FIX_ENDIANNESS_CDE(cde_header) \ | 167 | #define FIX_ENDIANNESS_CDE(cde) \ |
168 | do { if (BB_BIG_ENDIAN) { \ | 168 | do { if (BB_BIG_ENDIAN) { \ |
169 | (cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \ | 169 | (cde).fmt.cdf_offset = SWAP_LE32((cde).fmt.cdf_offset); \ |
170 | }} while (0) | 170 | }} while (0) |
171 | 171 | ||
172 | struct BUG { | 172 | struct BUG { |
@@ -175,13 +175,13 @@ struct BUG { | |||
175 | * even though the elements are all in the right place. | 175 | * even though the elements are all in the right place. |
176 | */ | 176 | */ |
177 | char BUG_zip_header_must_be_26_bytes[ | 177 | char BUG_zip_header_must_be_26_bytes[ |
178 | offsetof(zip_header_t, formatted.extra_len) + 2 | 178 | offsetof(zip_header_t, fmt.extra_len) + 2 |
179 | == ZIP_HEADER_LEN ? 1 : -1]; | 179 | == ZIP_HEADER_LEN ? 1 : -1]; |
180 | char BUG_cdf_header_must_be_42_bytes[ | 180 | char BUG_cdf_header_must_be_42_bytes[ |
181 | offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4 | 181 | offsetof(cdf_header_t, fmt.relative_offset_of_local_header) + 4 |
182 | == CDF_HEADER_LEN ? 1 : -1]; | 182 | == CDF_HEADER_LEN ? 1 : -1]; |
183 | char BUG_cde_header_must_be_16_bytes[ | 183 | char BUG_cde_must_be_16_bytes[ |
184 | sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1]; | 184 | sizeof(cde_t) == CDE_LEN ? 1 : -1]; |
185 | }; | 185 | }; |
186 | 186 | ||
187 | 187 | ||
@@ -207,7 +207,7 @@ enum { zip_fd = 3 }; | |||
207 | /* NB: does not preserve file position! */ | 207 | /* NB: does not preserve file position! */ |
208 | static uint32_t find_cdf_offset(void) | 208 | static uint32_t find_cdf_offset(void) |
209 | { | 209 | { |
210 | cde_header_t cde_header; | 210 | cde_t cde; |
211 | unsigned char *buf; | 211 | unsigned char *buf; |
212 | unsigned char *p; | 212 | unsigned char *p; |
213 | off_t end; | 213 | off_t end; |
@@ -228,7 +228,7 @@ static uint32_t find_cdf_offset(void) | |||
228 | 228 | ||
229 | found = BAD_CDF_OFFSET; | 229 | found = BAD_CDF_OFFSET; |
230 | p = buf; | 230 | p = buf; |
231 | while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) { | 231 | while (p <= buf + PEEK_FROM_END - CDE_LEN - 4) { |
232 | if (*p != 'P') { | 232 | if (*p != 'P') { |
233 | p++; | 233 | p++; |
234 | continue; | 234 | continue; |
@@ -240,19 +240,19 @@ static uint32_t find_cdf_offset(void) | |||
240 | if (*++p != 6) | 240 | if (*++p != 6) |
241 | continue; | 241 | continue; |
242 | /* we found CDE! */ | 242 | /* we found CDE! */ |
243 | memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN); | 243 | memcpy(cde.raw, p + 1, CDE_LEN); |
244 | FIX_ENDIANNESS_CDE(cde_header); | 244 | FIX_ENDIANNESS_CDE(cde); |
245 | /* | 245 | /* |
246 | * I've seen .ZIP files with seemingly valid CDEs | 246 | * I've seen .ZIP files with seemingly valid CDEs |
247 | * where cdf_offset points past EOF - ?? | 247 | * where cdf_offset points past EOF - ?? |
248 | * This check ignores such CDEs: | 248 | * This check ignores such CDEs: |
249 | */ | 249 | */ |
250 | if (cde_header.formatted.cdf_offset < end + (p - buf)) { | 250 | if (cde.fmt.cdf_offset < end + (p - buf)) { |
251 | found = cde_header.formatted.cdf_offset; | 251 | found = cde.fmt.cdf_offset; |
252 | dbg("Possible cdf_offset:0x%x at 0x%"OFF_FMT"x", | 252 | dbg("Possible cdf_offset:0x%x at 0x%"OFF_FMT"x", |
253 | (unsigned)found, end + (p-3 - buf)); | 253 | (unsigned)found, end + (p-3 - buf)); |
254 | dbg(" cdf_offset+cdf_size:0x%x", | 254 | dbg(" cdf_offset+cdf_size:0x%x", |
255 | (unsigned)(found + SWAP_LE32(cde_header.formatted.cdf_size))); | 255 | (unsigned)(found + SWAP_LE32(cde.fmt.cdf_size))); |
256 | /* | 256 | /* |
257 | * We do not "break" here because only the last CDE is valid. | 257 | * We do not "break" here because only the last CDE is valid. |
258 | * I've seen a .zip archive which contained a .zip file, | 258 | * I've seen a .zip archive which contained a .zip file, |
@@ -266,7 +266,7 @@ static uint32_t find_cdf_offset(void) | |||
266 | return found; | 266 | return found; |
267 | }; | 267 | }; |
268 | 268 | ||
269 | static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) | 269 | static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf) |
270 | { | 270 | { |
271 | uint32_t magic; | 271 | uint32_t magic; |
272 | 272 | ||
@@ -276,23 +276,25 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) | |||
276 | dbg("Reading CDF at 0x%x", (unsigned)cdf_offset); | 276 | dbg("Reading CDF at 0x%x", (unsigned)cdf_offset); |
277 | xlseek(zip_fd, cdf_offset, SEEK_SET); | 277 | xlseek(zip_fd, cdf_offset, SEEK_SET); |
278 | xread(zip_fd, &magic, 4); | 278 | xread(zip_fd, &magic, 4); |
279 | /* Central Directory End? */ | 279 | /* Central Directory End? Assume CDF has ended. |
280 | * (more correct method is to use cde.cdf_entries_total counter) | ||
281 | */ | ||
280 | if (magic == ZIP_CDE_MAGIC) { | 282 | if (magic == ZIP_CDE_MAGIC) { |
281 | dbg("got ZIP_CDE_MAGIC"); | 283 | dbg("got ZIP_CDE_MAGIC"); |
282 | return 0; /* EOF */ | 284 | return 0; /* EOF */ |
283 | } | 285 | } |
284 | xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); | 286 | xread(zip_fd, cdf->raw, CDF_HEADER_LEN); |
285 | 287 | ||
286 | FIX_ENDIANNESS_CDF(*cdf_ptr); | 288 | FIX_ENDIANNESS_CDF(*cdf); |
287 | dbg(" file_name_length:%u extra_field_length:%u file_comment_length:%u", | 289 | dbg(" filename_len:%u extra_len:%u file_comment_length:%u", |
288 | (unsigned)cdf_ptr->formatted.file_name_length, | 290 | (unsigned)cdf->fmt.filename_len, |
289 | (unsigned)cdf_ptr->formatted.extra_field_length, | 291 | (unsigned)cdf->fmt.extra_len, |
290 | (unsigned)cdf_ptr->formatted.file_comment_length | 292 | (unsigned)cdf->fmt.file_comment_length |
291 | ); | 293 | ); |
292 | cdf_offset += 4 + CDF_HEADER_LEN | 294 | cdf_offset += 4 + CDF_HEADER_LEN |
293 | + cdf_ptr->formatted.file_name_length | 295 | + cdf->fmt.filename_len |
294 | + cdf_ptr->formatted.extra_field_length | 296 | + cdf->fmt.extra_len |
295 | + cdf_ptr->formatted.file_comment_length; | 297 | + cdf->fmt.file_comment_length; |
296 | 298 | ||
297 | return cdf_offset; | 299 | return cdf_offset; |
298 | }; | 300 | }; |
@@ -315,28 +317,28 @@ static void unzip_create_leading_dirs(const char *fn) | |||
315 | free(name); | 317 | free(name); |
316 | } | 318 | } |
317 | 319 | ||
318 | static void unzip_extract(zip_header_t *zip_header, int dst_fd) | 320 | static void unzip_extract(zip_header_t *zip, int dst_fd) |
319 | { | 321 | { |
320 | if (zip_header->formatted.method == 0) { | 322 | if (zip->fmt.method == 0) { |
321 | /* Method 0 - stored (not compressed) */ | 323 | /* Method 0 - stored (not compressed) */ |
322 | off_t size = zip_header->formatted.ucmpsize; | 324 | off_t size = zip->fmt.ucmpsize; |
323 | if (size) | 325 | if (size) |
324 | bb_copyfd_exact_size(zip_fd, dst_fd, size); | 326 | bb_copyfd_exact_size(zip_fd, dst_fd, size); |
325 | } else { | 327 | } else { |
326 | /* Method 8 - inflate */ | 328 | /* Method 8 - inflate */ |
327 | transformer_state_t xstate; | 329 | transformer_state_t xstate; |
328 | init_transformer_state(&xstate); | 330 | init_transformer_state(&xstate); |
329 | xstate.bytes_in = zip_header->formatted.cmpsize; | 331 | xstate.bytes_in = zip->fmt.cmpsize; |
330 | xstate.src_fd = zip_fd; | 332 | xstate.src_fd = zip_fd; |
331 | xstate.dst_fd = dst_fd; | 333 | xstate.dst_fd = dst_fd; |
332 | if (inflate_unzip(&xstate) < 0) | 334 | if (inflate_unzip(&xstate) < 0) |
333 | bb_error_msg_and_die("inflate error"); | 335 | bb_error_msg_and_die("inflate error"); |
334 | /* Validate decompression - crc */ | 336 | /* Validate decompression - crc */ |
335 | if (zip_header->formatted.crc32 != (xstate.crc32 ^ 0xffffffffL)) { | 337 | if (zip->fmt.crc32 != (xstate.crc32 ^ 0xffffffffL)) { |
336 | bb_error_msg_and_die("crc error"); | 338 | bb_error_msg_and_die("crc error"); |
337 | } | 339 | } |
338 | /* Validate decompression - size */ | 340 | /* Validate decompression - size */ |
339 | if (zip_header->formatted.ucmpsize != xstate.bytes_out) { | 341 | if (zip->fmt.ucmpsize != xstate.bytes_out) { |
340 | /* Don't die. Who knows, maybe len calculation | 342 | /* Don't die. Who knows, maybe len calculation |
341 | * was botched somewhere. After all, crc matched! */ | 343 | * was botched somewhere. After all, crc matched! */ |
342 | bb_error_msg("bad length"); | 344 | bb_error_msg("bad length"); |
@@ -563,7 +565,7 @@ int unzip_main(int argc, char **argv) | |||
563 | total_entries = 0; | 565 | total_entries = 0; |
564 | cdf_offset = find_cdf_offset(); /* try to seek to the end, find CDE and CDF start */ | 566 | cdf_offset = find_cdf_offset(); /* try to seek to the end, find CDE and CDF start */ |
565 | while (1) { | 567 | while (1) { |
566 | zip_header_t zip_header; | 568 | zip_header_t zip; |
567 | mode_t dir_mode = 0777; | 569 | mode_t dir_mode = 0777; |
568 | #if ENABLE_FEATURE_UNZIP_CDF | 570 | #if ENABLE_FEATURE_UNZIP_CDF |
569 | mode_t file_mode = 0666; | 571 | mode_t file_mode = 0666; |
@@ -589,7 +591,7 @@ int unzip_main(int argc, char **argv) | |||
589 | 591 | ||
590 | /* Check magic number */ | 592 | /* Check magic number */ |
591 | xread(zip_fd, &magic, 4); | 593 | xread(zip_fd, &magic, 4); |
592 | /* Central directory? It's at the end, so exit */ | 594 | /* CDF item? Assume there are no more files, exit */ |
593 | if (magic == ZIP_CDF_MAGIC) { | 595 | if (magic == ZIP_CDF_MAGIC) { |
594 | dbg("got ZIP_CDF_MAGIC"); | 596 | dbg("got ZIP_CDF_MAGIC"); |
595 | break; | 597 | break; |
@@ -605,71 +607,74 @@ int unzip_main(int argc, char **argv) | |||
605 | bb_error_msg_and_die("invalid zip magic %08X", (int)magic); | 607 | bb_error_msg_and_die("invalid zip magic %08X", (int)magic); |
606 | dbg("got ZIP_FILEHEADER_MAGIC"); | 608 | dbg("got ZIP_FILEHEADER_MAGIC"); |
607 | 609 | ||
608 | xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN); | 610 | xread(zip_fd, zip.raw, ZIP_HEADER_LEN); |
609 | FIX_ENDIANNESS_ZIP(zip_header); | 611 | FIX_ENDIANNESS_ZIP(zip); |
610 | if ((zip_header.formatted.method != 0) | 612 | if ((zip.fmt.method != 0) |
611 | && (zip_header.formatted.method != 8) | 613 | && (zip.fmt.method != 8) |
612 | ) { | 614 | ) { |
613 | /* TODO? method 12: bzip2, method 14: LZMA */ | 615 | /* TODO? method 12: bzip2, method 14: LZMA */ |
614 | bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method); | 616 | bb_error_msg_and_die("unsupported method %d", zip.fmt.method); |
615 | } | 617 | } |
616 | if (zip_header.formatted.zip_flags & SWAP_LE16(0x0009)) { | 618 | if (zip.fmt.zip_flags & SWAP_LE16(0x0009)) { |
617 | bb_error_msg_and_die("zip flags 1 and 8 are not supported"); | 619 | bb_error_msg_and_die("zip flags 1 and 8 are not supported"); |
618 | } | 620 | } |
619 | } | 621 | } |
620 | #if ENABLE_FEATURE_UNZIP_CDF | 622 | #if ENABLE_FEATURE_UNZIP_CDF |
621 | else { | 623 | else { |
622 | /* cdf_offset is valid (and we know the file is seekable) */ | 624 | /* cdf_offset is valid (and we know the file is seekable) */ |
623 | cdf_header_t cdf_header; | 625 | cdf_header_t cdf; |
624 | cdf_offset = read_next_cdf(cdf_offset, &cdf_header); | 626 | cdf_offset = read_next_cdf(cdf_offset, &cdf); |
625 | if (cdf_offset == 0) /* EOF? */ | 627 | if (cdf_offset == 0) /* EOF? */ |
626 | break; | 628 | break; |
627 | # if 0 | 629 | # if 1 |
628 | xlseek(zip_fd, | 630 | xlseek(zip_fd, |
629 | SWAP_LE32(cdf_header.formatted.relative_offset_of_local_header) + 4, | 631 | SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4, |
630 | SEEK_SET); | 632 | SEEK_SET); |
631 | xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN); | 633 | xread(zip_fd, zip.raw, ZIP_HEADER_LEN); |
632 | FIX_ENDIANNESS_ZIP(zip_header); | 634 | FIX_ENDIANNESS_ZIP(zip); |
633 | if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) { | 635 | if (zip.fmt.zip_flags & SWAP_LE16(0x0008)) { |
634 | /* 0x0008 - streaming. [u]cmpsize can be reliably gotten | 636 | /* 0x0008 - streaming. [u]cmpsize can be reliably gotten |
635 | * only from Central Directory. | 637 | * only from Central Directory. |
636 | */ | 638 | */ |
637 | zip_header.formatted.crc32 = cdf_header.formatted.crc32; | 639 | zip.fmt.crc32 = cdf.fmt.crc32; |
638 | zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize; | 640 | zip.fmt.cmpsize = cdf.fmt.cmpsize; |
639 | zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize; | 641 | zip.fmt.ucmpsize = cdf.fmt.ucmpsize; |
640 | } | 642 | } |
641 | # else | 643 | # else |
642 | /* CDF has the same data as local header, no need to read the latter */ | 644 | /* CDF has the same data as local header, no need to read the latter... |
643 | memcpy(&zip_header.formatted.version, | 645 | * ...not really. An archive was seen with cdf.extra_len == 6 but |
644 | &cdf_header.formatted.version_needed, ZIP_HEADER_LEN); | 646 | * zip.extra_len == 0. |
647 | */ | ||
648 | memcpy(&zip.fmt.version, | ||
649 | &cdf.fmt.version_needed, ZIP_HEADER_LEN); | ||
645 | xlseek(zip_fd, | 650 | xlseek(zip_fd, |
646 | SWAP_LE32(cdf_header.formatted.relative_offset_of_local_header) + 4 + ZIP_HEADER_LEN, | 651 | SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4 + ZIP_HEADER_LEN, |
647 | SEEK_SET); | 652 | SEEK_SET); |
648 | # endif | 653 | # endif |
649 | if ((cdf_header.formatted.version_made_by >> 8) == 3) { | 654 | if ((cdf.fmt.version_made_by >> 8) == 3) { |
650 | /* This archive is created on Unix */ | 655 | /* This archive is created on Unix */ |
651 | dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16); | 656 | dir_mode = file_mode = (cdf.fmt.external_attributes >> 16); |
652 | } | 657 | } |
653 | } | 658 | } |
654 | #endif | 659 | #endif |
655 | 660 | ||
656 | if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) { | 661 | if (zip.fmt.zip_flags & SWAP_LE16(0x0001)) { |
657 | /* 0x0001 - encrypted */ | 662 | /* 0x0001 - encrypted */ |
658 | bb_error_msg_and_die("zip flag 1 (encryption) is not supported"); | 663 | bb_error_msg_and_die("zip flag 1 (encryption) is not supported"); |
659 | } | 664 | } |
660 | dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x", | 665 | dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x", |
661 | (unsigned)zip_header.formatted.cmpsize, | 666 | (unsigned)zip.fmt.cmpsize, |
662 | (unsigned)zip_header.formatted.extra_len, | 667 | (unsigned)zip.fmt.extra_len, |
663 | (unsigned)zip_header.formatted.ucmpsize | 668 | (unsigned)zip.fmt.ucmpsize |
664 | ); | 669 | ); |
665 | 670 | ||
666 | /* Read filename */ | 671 | /* Read filename */ |
667 | free(dst_fn); | 672 | free(dst_fn); |
668 | dst_fn = xzalloc(zip_header.formatted.filename_len + 1); | 673 | dst_fn = xzalloc(zip.fmt.filename_len + 1); |
669 | xread(zip_fd, dst_fn, zip_header.formatted.filename_len); | 674 | xread(zip_fd, dst_fn, zip.fmt.filename_len); |
670 | 675 | ||
671 | /* Skip extra header bytes */ | 676 | /* Skip extra header bytes */ |
672 | unzip_skip(zip_header.formatted.extra_len); | 677 | unzip_skip(zip.fmt.extra_len); |
673 | 678 | ||
674 | /* Guard against "/abspath", "/../" and similar attacks */ | 679 | /* Guard against "/abspath", "/../" and similar attacks */ |
675 | overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn)); | 680 | overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn)); |
@@ -684,32 +689,32 @@ int unzip_main(int argc, char **argv) | |||
684 | /* List entry */ | 689 | /* List entry */ |
685 | char dtbuf[sizeof("mm-dd-yyyy hh:mm")]; | 690 | char dtbuf[sizeof("mm-dd-yyyy hh:mm")]; |
686 | sprintf(dtbuf, "%02u-%02u-%04u %02u:%02u", | 691 | sprintf(dtbuf, "%02u-%02u-%04u %02u:%02u", |
687 | (zip_header.formatted.moddate >> 5) & 0xf, // mm: 0x01e0 | 692 | (zip.fmt.moddate >> 5) & 0xf, // mm: 0x01e0 |
688 | (zip_header.formatted.moddate) & 0x1f, // dd: 0x001f | 693 | (zip.fmt.moddate) & 0x1f, // dd: 0x001f |
689 | (zip_header.formatted.moddate >> 9) + 1980, // yy: 0xfe00 | 694 | (zip.fmt.moddate >> 9) + 1980, // yy: 0xfe00 |
690 | (zip_header.formatted.modtime >> 11), // hh: 0xf800 | 695 | (zip.fmt.modtime >> 11), // hh: 0xf800 |
691 | (zip_header.formatted.modtime >> 5) & 0x3f // mm: 0x07e0 | 696 | (zip.fmt.modtime >> 5) & 0x3f // mm: 0x07e0 |
692 | // seconds/2 are not shown, encoded in ----------- 0x001f | 697 | // seconds/2 not shown, encoded in -- 0x001f |
693 | ); | 698 | ); |
694 | if (!verbose) { | 699 | if (!verbose) { |
695 | // " Length Date Time Name\n" | 700 | // " Length Date Time Name\n" |
696 | // "--------- ---------- ----- ----" | 701 | // "--------- ---------- ----- ----" |
697 | printf( "%9u " "%s " "%s\n", | 702 | printf( "%9u " "%s " "%s\n", |
698 | (unsigned)zip_header.formatted.ucmpsize, | 703 | (unsigned)zip.fmt.ucmpsize, |
699 | dtbuf, | 704 | dtbuf, |
700 | dst_fn); | 705 | dst_fn); |
701 | } else { | 706 | } else { |
702 | unsigned long percents = zip_header.formatted.ucmpsize - zip_header.formatted.cmpsize; | 707 | unsigned long percents = zip.fmt.ucmpsize - zip.fmt.cmpsize; |
703 | if ((int32_t)percents < 0) | 708 | if ((int32_t)percents < 0) |
704 | percents = 0; /* happens if ucmpsize < cmpsize */ | 709 | percents = 0; /* happens if ucmpsize < cmpsize */ |
705 | percents = percents * 100; | 710 | percents = percents * 100; |
706 | if (zip_header.formatted.ucmpsize) | 711 | if (zip.fmt.ucmpsize) |
707 | percents /= zip_header.formatted.ucmpsize; | 712 | percents /= zip.fmt.ucmpsize; |
708 | // " Length Method Size Cmpr Date Time CRC-32 Name\n" | 713 | // " Length Method Size Cmpr Date Time CRC-32 Name\n" |
709 | // "-------- ------ ------- ---- ---------- ----- -------- ----" | 714 | // "-------- ------ ------- ---- ---------- ----- -------- ----" |
710 | printf( "%8u %s" "%9u%4u%% " "%s " "%08x " "%s\n", | 715 | printf( "%8u %s" "%9u%4u%% " "%s " "%08x " "%s\n", |
711 | (unsigned)zip_header.formatted.ucmpsize, | 716 | (unsigned)zip.fmt.ucmpsize, |
712 | zip_header.formatted.method == 0 ? "Stored" : "Defl:N", /* Defl is method 8 */ | 717 | zip.fmt.method == 0 ? "Stored" : "Defl:N", /* Defl is method 8 */ |
713 | /* TODO: show other methods? | 718 | /* TODO: show other methods? |
714 | * 1 - Shrunk | 719 | * 1 - Shrunk |
715 | * 2 - Reduced with compression factor 1 | 720 | * 2 - Reduced with compression factor 1 |
@@ -722,15 +727,16 @@ int unzip_main(int argc, char **argv) | |||
722 | * 10 - PKWARE Data Compression Library Imploding | 727 | * 10 - PKWARE Data Compression Library Imploding |
723 | * 11 - Reserved by PKWARE | 728 | * 11 - Reserved by PKWARE |
724 | * 12 - BZIP2 | 729 | * 12 - BZIP2 |
730 | * 14 - LZMA | ||
725 | */ | 731 | */ |
726 | (unsigned)zip_header.formatted.cmpsize, | 732 | (unsigned)zip.fmt.cmpsize, |
727 | (unsigned)percents, | 733 | (unsigned)percents, |
728 | dtbuf, | 734 | dtbuf, |
729 | zip_header.formatted.crc32, | 735 | zip.fmt.crc32, |
730 | dst_fn); | 736 | dst_fn); |
731 | total_size += zip_header.formatted.cmpsize; | 737 | total_size += zip.fmt.cmpsize; |
732 | } | 738 | } |
733 | total_usize += zip_header.formatted.ucmpsize; | 739 | total_usize += zip.fmt.ucmpsize; |
734 | i = 'n'; | 740 | i = 'n'; |
735 | } else if (dst_fd == STDOUT_FILENO) { | 741 | } else if (dst_fd == STDOUT_FILENO) { |
736 | /* Extracting to STDOUT */ | 742 | /* Extracting to STDOUT */ |
@@ -798,9 +804,11 @@ int unzip_main(int argc, char **argv) | |||
798 | #endif | 804 | #endif |
799 | case -1: /* Unzip */ | 805 | case -1: /* Unzip */ |
800 | if (!quiet) { | 806 | if (!quiet) { |
801 | printf(" inflating: %s\n", dst_fn); | 807 | printf(/* zip.fmt.method == 0 |
808 | ? " extracting: %s\n" | ||
809 | : */ " inflating: %s\n", dst_fn); | ||
802 | } | 810 | } |
803 | unzip_extract(&zip_header, dst_fd); | 811 | unzip_extract(&zip, dst_fd); |
804 | if (dst_fd != STDOUT_FILENO) { | 812 | if (dst_fd != STDOUT_FILENO) { |
805 | /* closing STDOUT is potentially bad for future business */ | 813 | /* closing STDOUT is potentially bad for future business */ |
806 | close(dst_fd); | 814 | close(dst_fd); |
@@ -811,7 +819,7 @@ int unzip_main(int argc, char **argv) | |||
811 | overwrite = O_NEVER; | 819 | overwrite = O_NEVER; |
812 | case 'n': | 820 | case 'n': |
813 | /* Skip entry data */ | 821 | /* Skip entry data */ |
814 | unzip_skip(zip_header.formatted.cmpsize); | 822 | unzip_skip(zip.fmt.cmpsize); |
815 | break; | 823 | break; |
816 | 824 | ||
817 | case 'r': | 825 | case 'r': |
diff --git a/testsuite/unzip.tests b/testsuite/unzip.tests index d9c45242c..2e4becdb8 100755 --- a/testsuite/unzip.tests +++ b/testsuite/unzip.tests | |||
@@ -34,7 +34,9 @@ rm foo.zip | |||
34 | optional FEATURE_UNZIP_CDF | 34 | optional FEATURE_UNZIP_CDF |
35 | testing "unzip (bad archive)" "uudecode; unzip bad.zip 2>&1; echo \$?" \ | 35 | testing "unzip (bad archive)" "uudecode; unzip bad.zip 2>&1; echo \$?" \ |
36 | "Archive: bad.zip | 36 | "Archive: bad.zip |
37 | unzip: short read | 37 | inflating: ]3j½r«IK-%Ix |
38 | unzip: corrupted data | ||
39 | unzip: inflate error | ||
38 | 1 | 40 | 1 |
39 | " \ | 41 | " \ |
40 | "" "\ | 42 | "" "\ |