aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2002-09-17 21:02:16 +0000
committerManuel Novoa III <mjn3@codepoet.org>2002-09-17 21:02:16 +0000
commit6c32a8add480f2b7b86809d3d79a4555fa884c7f (patch)
tree8f14d6267d5f0362bd474334639c85db1adbe66b
parent60943c5d5c0cee31476ca9bf71e4f539cbe2aa57 (diff)
downloadbusybox-w32-6c32a8add480f2b7b86809d3d79a4555fa884c7f.tar.gz
busybox-w32-6c32a8add480f2b7b86809d3d79a4555fa884c7f.tar.bz2
busybox-w32-6c32a8add480f2b7b86809d3d79a4555fa884c7f.zip
Modified so that it "works" for archs other than i386... arm in particular.
Also tried to clean up the logic a little, and ensure that read errors or invalid archives resulted in error returns. This could use a lot more work... Volunteers?
-rw-r--r--archival/libunarchive/get_header_zip.c155
1 files changed, 108 insertions, 47 deletions
diff --git a/archival/libunarchive/get_header_zip.c b/archival/libunarchive/get_header_zip.c
index 84f2a54f2..5fa3a6c8c 100644
--- a/archival/libunarchive/get_header_zip.c
+++ b/archival/libunarchive/get_header_zip.c
@@ -19,92 +19,153 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22#include <stddef.h>
22#include <stdio.h> 23#include <stdio.h>
23#include <stdlib.h> 24#include <stdlib.h>
24#include <string.h> 25#include <string.h>
25#include "unarchive.h" 26#include "unarchive.h"
26#include "libbb.h" 27#include "libbb.h"
27 28
28#define ZIP_FILEHEADER_MAGIC 0x04034b50 29#define ZIP_FILEHEADER_MAGIC 0x04034b50
29#define ZIP_CDS_MAGIC 0x02014b50 30#define ZIP_CDS_MAGIC 0x02014b50
30#define ZIP_CDS_END_MAGIC 0x06054b50 31#define ZIP_CDS_END_MAGIC 0x06054b50
31#define ZIP_DD_MAGIC 0x8074b50 32#define ZIP_DD_MAGIC 0x08074b50
33
34
35enum {
36 zh_version,
37 zh_flags,
38 zh_method,
39 zh_modtime,
40 zh_moddate,
41 zh_crc32,
42 zh_cmpsize,
43 zh_ucmpsize,
44 zh_filename_len,
45 zh_extra_len
46};
47
48static const char fail_msg[] = "Invalid file or read error";
49
50static int le_read_int(FILE *fp, int n)
51{
52 int r = 0;
53 int s = 1;
54 int c;
55
56 archive_offset += n;
57
58 do {
59 if ((c = fgetc(fp)) == EOF) {
60 error_msg_and_die(fail_msg);
61 }
62 r += s * c;
63 s <<= 8;
64 } while (--n);
65
66 return r;
67}
68
69static void read_header(FILE *fp, int *zh)
70{
71 static const char s[] = { 2, 2, 2, 2, 2, 4, 4, 4, 2, 2, 0 };
72 int i = 0;
73
74 do {
75 zh[i] = le_read_int(fp, s[i]);
76 } while (s[++i]);
77}
32 78
33file_header_t *get_header_zip(FILE *zip_stream) 79file_header_t *get_header_zip(FILE *zip_stream)
34{ 80{
35 struct { 81 int zip_header[10];
36 short version __attribute__ ((packed));
37 short flags __attribute__ ((packed));
38 short method __attribute__ ((packed));
39 short modtime __attribute__ ((packed));
40 short moddate __attribute__ ((packed));
41 int crc32 __attribute__ ((packed));
42 int cmpsize __attribute__ ((packed));
43 int ucmpsize __attribute__ ((packed));
44 short filename_len __attribute__ ((packed));
45 short extra_len __attribute__ ((packed));
46 } zip_header;
47 file_header_t *zip_entry = NULL; 82 file_header_t *zip_entry = NULL;
48 int magic; 83 int magic, tmpmagic;
49 static int dd_ahead = 0; // If this is true, the we didn't know how long the last extraced file was 84 /* If dd_ahead is true, we didn't know the last extracted file's length. */
85 static int dd_ahead = 0;
50 86
51 fread (&magic, 4, 1, zip_stream); 87 magic = le_read_int(zip_stream, 4);
52 archive_offset += 4;
53 88
54 if (feof(zip_stream)) return(NULL); 89 checkmagic:
55checkmagic:
56 switch (magic) { 90 switch (magic) {
57 case ZIP_FILEHEADER_MAGIC: 91 case ZIP_FILEHEADER_MAGIC:
58 zip_entry = xcalloc(1, sizeof(file_header_t)); 92 zip_entry = xcalloc(1, sizeof(file_header_t));
59 fread (&zip_header, sizeof(zip_header), 1, zip_stream); 93
60 archive_offset += sizeof(zip_header); 94 read_header(zip_stream, zip_header);
61 if (!(zip_header.method == 8 || zip_header.method == 0)) { printf("Unsupported compression method %d\n", zip_header.method); return(NULL); } 95
62 zip_entry->name = calloc(zip_header.filename_len + 1, sizeof(char)); 96 if (zip_header[zh_method] == 8) {
63 fread (zip_entry->name, sizeof(char), zip_header.filename_len, zip_stream); 97 zip_entry->extract_func = &inflate;
64 archive_offset += zip_header.filename_len; 98 } else if (zip_header[zh_method] != 0) {
65 seek_sub_file(zip_stream, zip_header.extra_len); 99 error_msg_and_die("Unsupported compression method %d\n",
66 zip_entry->size = zip_header.cmpsize; 100 zip_header[zh_method]);
67 if (zip_header.method == 8) zip_entry->extract_func = &inflate; 101 }
102
103 zip_entry->name = xmalloc(zip_header[zh_filename_len] + 1);
104 if (!fread(zip_entry->name, zip_header[zh_filename_len], 1, zip_stream)) {
105 error_msg_and_die(fail_msg);
106 }
107 archive_offset += zip_header[zh_filename_len];
108
109 seek_sub_file(zip_stream, zip_header[zh_extra_len]);
110
111 zip_entry->size = zip_header[zh_cmpsize];
112
68 zip_entry->mode = S_IFREG | 0777; 113 zip_entry->mode = S_IFREG | 0777;
69 // Time/Date? 114
70 if (*(zip_entry->name + strlen(zip_entry->name) - 1) == '/') { // Files that end in a / are directories 115 /* Time/Date? */
116
117 zip_entry->name[zip_header[zh_filename_len]] = 0;
118 if (*(zip_entry->name + zip_header[zh_filename_len] - 1) == '/') {
119 /* Files that end in a / are directories */
120 /* Remove trailing / so unarchive doesn't get confused */
121 *(zip_entry->name + zip_header[zh_filename_len] - 1) = '\0';
71 zip_entry->mode ^= S_IFREG; 122 zip_entry->mode ^= S_IFREG;
72 zip_entry->mode |= S_IFDIR; 123 zip_entry->mode |= S_IFDIR;
73 *(zip_entry->name + strlen(zip_entry->name) - 1) = '\0'; // Remove trailing / so unarchive doesn't get confused
74 } 124 }
75 //printf("cmpsize: %d, ucmpsize: %d, method: %d\n", zip_header.cmpsize, zip_header.ucmpsize, zip_header.method); 125
76 if (zip_header.flags & 0x8) { // crc32, and sizes are in the data description _after_ the file 126 if (zip_header[zh_flags] & 0x8) {
77 if (zip_header.cmpsize == 0) dd_ahead = 1; // As we don't know how long this file it is difficult to skip! but it is compressed, so normally its ok 127 /* crc32, and sizes are in the data description _after_ the file */
78 if (zip_header.ucmpsize != 0) dd_ahead = 2; // Humm... we would otherwise skip this twice - not good! 128 if (zip_header[zh_cmpsize] == 0) {
129 /* As we don't know how long this file it is difficult to skip!
130 * but it is compressed, so normally its ok */
131 dd_ahead = 1;
132 }
133 if (zip_header[zh_ucmpsize] != 0) {
134 /* Humm... we would otherwise skip this twice - not good! */
135 dd_ahead = 2;
136 }
79 } 137 }
80 break; 138 break;
139
81 case ZIP_CDS_MAGIC: /* FALLTHRU */ 140 case ZIP_CDS_MAGIC: /* FALLTHRU */
82 case ZIP_CDS_END_MAGIC: 141 case ZIP_CDS_END_MAGIC:
83 return(NULL); 142 return(NULL);
84 break; 143 break;
144
85 case ZIP_DD_MAGIC: { 145 case ZIP_DD_MAGIC: {
86 int cmpsize; 146 int cmpsize;
87 seek_sub_file(zip_stream, 4); // Skip crc32 147 seek_sub_file(zip_stream, 4); // Skip crc32
88 fread(&cmpsize, 4, 1, zip_stream); 148 cmpsize = le_read_int(zip_stream, 4);
89 archive_offset += 4;
90 if (dd_ahead == 1) archive_offset += cmpsize; 149 if (dd_ahead == 1) archive_offset += cmpsize;
91 seek_sub_file(zip_stream, 4); // Skip uncompressed size 150 seek_sub_file(zip_stream, 4); // Skip uncompressed size
92 dd_ahead = 0; 151 dd_ahead = 0;
93 return (get_header_zip(zip_stream)); 152 return (get_header_zip(zip_stream));
94 break; } 153 break; }
154
95 default: 155 default:
96 if (!dd_ahead) error_msg("Invalid magic (%#x): Trying to skip junk", magic); 156 if (!dd_ahead) error_msg("Invalid magic (%#x): Trying to skip junk", magic);
97 dd_ahead = 0; 157 dd_ahead = 0;
98 while (!feof(zip_stream)) { 158 while ((tmpmagic = fgetc(zip_stream)) != EOF) {
99 int tmpmagic;
100 tmpmagic = fgetc(zip_stream);
101 archive_offset++; 159 archive_offset++;
102 magic = ((magic >> 8) & 0x00ffffff) | ((tmpmagic << 24) & 0xff000000); 160 magic = ((magic >> 8) & 0x00ffffff) | ((tmpmagic << 24) & 0xff000000);
103 if (magic == ZIP_FILEHEADER_MAGIC || magic == ZIP_CDS_MAGIC || magic == ZIP_CDS_END_MAGIC) goto checkmagic; 161 if (magic == ZIP_FILEHEADER_MAGIC
162 || magic == ZIP_CDS_MAGIC
163 || magic == ZIP_CDS_END_MAGIC) {
164 goto checkmagic;
165 }
104 } 166 }
105 error_msg("End of archive reached: Bad archive"); 167 error_msg_and_die(fail_msg);
106 return(NULL);
107 } 168 }
108 //if (archive_offset != ftell(zip_stream)) printf("Archive offset out of sync (%d,%d)\n", (int) archive_offset, (int) ftell(zip_stream)); 169
109 return(zip_entry); 170 return(zip_entry);
110} 171}