OLD | NEW |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | 1 /* This Source Code Form is subject to the terms of the Mozilla Public |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | 2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | 4 |
5 /* | 5 /* |
6 * JARFILE | 6 * JARFILE |
7 * | 7 * |
8 * Parsing of a Jar file | 8 * Parsing of a Jar file |
9 */ | 9 */ |
10 #define JAR_SIZE 256 | 10 #define JAR_SIZE 256 |
11 | 11 |
12 #include "jar.h" | 12 #include "jar.h" |
13 #include "jarint.h" | 13 #include "jarint.h" |
14 #include "jarfile.h" | 14 #include "jarfile.h" |
15 | 15 |
16 /* commercial compression */ | 16 /* commercial compression */ |
17 #include "jzlib.h" | 17 #include "jzlib.h" |
18 | 18 |
19 #if defined(XP_UNIX) || defined(XP_BEOS) | 19 #if defined(XP_UNIX) || defined(XP_BEOS) |
20 #include "sys/stat.h" | 20 #include "sys/stat.h" |
21 #endif | 21 #endif |
22 | 22 |
23 #include "sechash.h"» /* for HASH_GetHashObject() */ | 23 #include "sechash.h" /* for HASH_GetHashObject() */ |
24 | 24 |
25 PR_STATIC_ASSERT(46 == sizeof(struct ZipCentral)); | 25 PR_STATIC_ASSERT(46 == sizeof(struct ZipCentral)); |
26 PR_STATIC_ASSERT(30 == sizeof(struct ZipLocal)); | 26 PR_STATIC_ASSERT(30 == sizeof(struct ZipLocal)); |
27 PR_STATIC_ASSERT(22 == sizeof(struct ZipEnd)); | 27 PR_STATIC_ASSERT(22 == sizeof(struct ZipEnd)); |
28 PR_STATIC_ASSERT(512 == sizeof(union TarEntry)); | 28 PR_STATIC_ASSERT(512 == sizeof(union TarEntry)); |
29 | 29 |
30 /* extracting */ | 30 /* extracting */ |
31 static int | 31 static int jar_guess_jar(const char *filename, JAR_FILE fp); |
32 jar_guess_jar(const char *filename, JAR_FILE fp); | 32 |
33 | 33 static int jar_inflate_memory(unsigned int method, long *length, |
34 static int | 34 long expected_out_len, char **data); |
35 jar_inflate_memory(unsigned int method, long *length, long expected_out_len, | 35 |
36 char **data); | 36 static int jar_physical_extraction(JAR_FILE fp, char *outpath, long offset, |
37 | 37 long length); |
38 static int | 38 |
39 jar_physical_extraction(JAR_FILE fp, char *outpath, long offset, long length); | 39 static int jar_physical_inflate(JAR_FILE fp, char *outpath, long offset, |
40 | 40 long length, unsigned int method); |
41 static int | 41 |
42 jar_physical_inflate(JAR_FILE fp, char *outpath, long offset, long length, | 42 static int jar_verify_extract(JAR *jar, char *path, char *physical_path); |
43 unsigned int method); | 43 |
44 | 44 static JAR_Physical *jar_get_physical(JAR *jar, char *pathname); |
45 static int | 45 |
46 jar_verify_extract(JAR *jar, char *path, char *physical_path); | 46 static int jar_extract_manifests(JAR *jar, jarArch format, JAR_FILE fp); |
47 | 47 |
48 static JAR_Physical * | 48 static int jar_extract_mf(JAR *jar, jarArch format, JAR_FILE fp, char *ext); |
49 jar_get_physical(JAR *jar, char *pathname); | |
50 | |
51 static int | |
52 jar_extract_manifests(JAR *jar, jarArch format, JAR_FILE fp); | |
53 | |
54 static int | |
55 jar_extract_mf(JAR *jar, jarArch format, JAR_FILE fp, char *ext); | |
56 | |
57 | 49 |
58 /* indexing */ | 50 /* indexing */ |
59 static int | 51 static int jar_gen_index(JAR *jar, jarArch format, JAR_FILE fp); |
60 jar_gen_index(JAR *jar, jarArch format, JAR_FILE fp); | 52 |
61 | 53 static int jar_listtar(JAR *jar, JAR_FILE fp); |
62 static int | 54 |
63 jar_listtar(JAR *jar, JAR_FILE fp); | 55 static int jar_listzip(JAR *jar, JAR_FILE fp); |
64 | |
65 static int | |
66 jar_listzip(JAR *jar, JAR_FILE fp); | |
67 | |
68 | 56 |
69 /* conversions */ | 57 /* conversions */ |
70 static int | 58 static int dosdate(char *date, const char *s); |
71 dosdate(char *date, const char *s); | 59 |
72 | 60 static int dostime(char *time, const char *s); |
73 static int | |
74 dostime(char *time, const char *s); | |
75 | 61 |
76 #ifdef NSS_X86_OR_X64 | 62 #ifdef NSS_X86_OR_X64 |
77 #define x86ShortToUint32(ii) ((const PRUint32)*((const PRUint16 *)(ii))) | 63 #define x86ShortToUint32(ii) ((const PRUint32) * ((const PRUint16 *)(ii))) |
78 #define x86LongToUint32(ii) (*(const PRUint32 *)(ii)) | 64 #define x86LongToUint32(ii) (*(const PRUint32 *)(ii)) |
79 #else | 65 #else |
80 static PRUint32 | 66 static PRUint32 x86ShortToUint32(const void *ii); |
81 x86ShortToUint32(const void *ii); | 67 |
82 | 68 static PRUint32 x86LongToUint32(const void *ll); |
83 static PRUint32 | |
84 x86LongToUint32(const void *ll); | |
85 #endif | 69 #endif |
86 | 70 |
87 static long | 71 static long octalToLong(const char *s); |
88 octalToLong(const char *s); | |
89 | 72 |
90 /* | 73 /* |
91 * J A R _ p a s s _ a r c h i v e | 74 * J A R _ p a s s _ a r c h i v e |
92 * | 75 * |
93 * For use by naive clients. Slam an entire archive file | 76 * For use by naive clients. Slam an entire archive file |
94 * into this function. We extract manifests, parse, index | 77 * into this function. We extract manifests, parse, index |
95 * the archive file, and do whatever nastiness. | 78 * the archive file, and do whatever nastiness. |
96 * | 79 * |
97 */ | 80 */ |
98 int | 81 int JAR_pass_archive(JAR *jar, jarArch format, char *filename, |
99 JAR_pass_archive(JAR *jar, jarArch format, char *filename, const char *url) | 82 const char *url) { |
100 { | 83 JAR_FILE fp; |
101 JAR_FILE fp; | 84 int status = 0; |
102 int status = 0; | 85 |
103 | 86 if (filename == NULL) return JAR_ERR_GENERAL; |
104 if (filename == NULL) | 87 |
105 » return JAR_ERR_GENERAL; | 88 if ((fp = JAR_FOPEN(filename, "rb")) != NULL) { |
106 | 89 if (format == jarArchGuess) format = (jarArch)jar_guess_jar(filename, fp); |
107 if ((fp = JAR_FOPEN (filename, "rb")) != NULL) { | 90 |
108 » if (format == jarArchGuess) | 91 jar->format = format; |
109 » format = (jarArch)jar_guess_jar (filename, fp); | 92 jar->url = url ? PORT_Strdup(url) : NULL; |
110 | 93 jar->filename = PORT_Strdup(filename); |
111 » jar->format = format; | 94 |
112 » jar->url = url ? PORT_Strdup (url) : NULL; | 95 status = jar_gen_index(jar, format, fp); |
113 » jar->filename = PORT_Strdup (filename); | 96 if (status == 0) status = jar_extract_manifests(jar, format, fp); |
114 | 97 |
115 » status = jar_gen_index (jar, format, fp); | 98 JAR_FCLOSE(fp); |
116 » if (status == 0) | 99 if (status < 0) return status; |
117 » status = jar_extract_manifests (jar, format, fp); | 100 |
118 | 101 /* people were expecting it this way */ |
119 » JAR_FCLOSE (fp); | 102 return jar->valid; |
120 » if (status < 0) | 103 } |
121 » return status; | 104 /* file not found */ |
122 | 105 return JAR_ERR_FNF; |
123 » /* people were expecting it this way */ | |
124 » return jar->valid; | |
125 } | |
126 /* file not found */ | |
127 return JAR_ERR_FNF; | |
128 } | 106 } |
129 | 107 |
130 /* | 108 /* |
131 * J A R _ p a s s _ a r c h i v e _ u n v e r i f i e d | 109 * J A R _ p a s s _ a r c h i v e _ u n v e r i f i e d |
132 * | 110 * |
133 * Same as JAR_pass_archive, but doesn't parse signatures. | 111 * Same as JAR_pass_archive, but doesn't parse signatures. |
134 * | 112 * |
135 */ | 113 */ |
136 int | 114 int JAR_pass_archive_unverified(JAR *jar, jarArch format, char *filename, |
137 JAR_pass_archive_unverified(JAR *jar, jarArch format, char *filename,· | 115 const char *url) { |
138 const char *url) | 116 JAR_FILE fp; |
139 { | 117 int status = 0; |
140 JAR_FILE fp; | 118 |
141 int status = 0; | 119 if (filename == NULL) { |
142 | 120 return JAR_ERR_GENERAL; |
143 if (filename == NULL) { | 121 } |
144 » return JAR_ERR_GENERAL; | 122 |
145 } | 123 if ((fp = JAR_FOPEN(filename, "rb")) != NULL) { |
146 | 124 if (format == jarArchGuess) { |
147 if ((fp = JAR_FOPEN (filename, "rb")) != NULL) { | 125 format = (jarArch)jar_guess_jar(filename, fp); |
148 » if (format == jarArchGuess) { | 126 } |
149 » format = (jarArch)jar_guess_jar (filename, fp); | 127 |
150 » } | 128 jar->format = format; |
151 | 129 jar->url = url ? PORT_Strdup(url) : NULL; |
152 » jar->format = format; | 130 jar->filename = PORT_Strdup(filename); |
153 » jar->url = url ? PORT_Strdup (url) : NULL; | 131 |
154 » jar->filename = PORT_Strdup (filename); | 132 status = jar_gen_index(jar, format, fp); |
155 | 133 if (status == 0) { |
156 » status = jar_gen_index (jar, format, fp); | 134 status = jar_extract_mf(jar, format, fp, "mf"); |
157 » if (status == 0) { | 135 } |
158 » status = jar_extract_mf(jar, format, fp, "mf"); | 136 |
159 » } | 137 JAR_FCLOSE(fp); |
160 | 138 if (status < 0) { |
161 » JAR_FCLOSE (fp); | 139 return status; |
162 » if (status < 0) { | 140 } |
163 » return status; | 141 |
164 » } | 142 /* people were expecting it this way */ |
165 | 143 return jar->valid; |
166 » /* people were expecting it this way */ | 144 } |
167 » return jar->valid; | 145 /* file not found */ |
168 } | 146 return JAR_ERR_FNF; |
169 /* file not found */ | |
170 return JAR_ERR_FNF; | |
171 } | 147 } |
172 | 148 |
173 /* | 149 /* |
174 * J A R _ v e r i f i e d _ e x t r a c t | 150 * J A R _ v e r i f i e d _ e x t r a c t |
175 * | 151 * |
176 * Optimization: keep a file descriptor open | 152 * Optimization: keep a file descriptor open |
177 * inside the JAR structure, so we don't have to | 153 * inside the JAR structure, so we don't have to |
178 * open the file 25 times to run java. | 154 * open the file 25 times to run java. |
179 * | 155 * |
180 */ | 156 */ |
181 | 157 |
182 int | 158 int JAR_verified_extract(JAR *jar, char *path, char *outpath) { |
183 JAR_verified_extract(JAR *jar, char *path, char *outpath) | 159 int status = JAR_extract(jar, path, outpath); |
184 { | 160 |
185 int status = JAR_extract (jar, path, outpath); | 161 if (status >= 0) return jar_verify_extract(jar, path, outpath); |
186 | 162 return status; |
187 if (status >= 0) | 163 } |
188 » return jar_verify_extract(jar, path, outpath); | 164 |
189 return status; | 165 int JAR_extract(JAR *jar, char *path, char *outpath) { |
190 } | 166 int result; |
191 | 167 JAR_Physical *phy; |
192 int | 168 |
193 JAR_extract(JAR *jar, char *path, char *outpath) | 169 if (jar->fp == NULL && jar->filename) { |
194 { | 170 jar->fp = (FILE *)JAR_FOPEN(jar->filename, "rb"); |
195 int result; | 171 } |
196 JAR_Physical *phy; | 172 if (jar->fp == NULL) { |
197 | 173 /* file not found */ |
198 if (jar->fp == NULL && jar->filename) { | 174 return JAR_ERR_FNF; |
199 » jar->fp = (FILE*)JAR_FOPEN (jar->filename, "rb"); | 175 } |
200 } | 176 |
201 if (jar->fp == NULL) { | 177 phy = jar_get_physical(jar, path); |
202 » /* file not found */ | 178 if (phy) { |
203 » return JAR_ERR_FNF; | 179 if (phy->compression != 0 && phy->compression != 8) { |
204 } | 180 /* unsupported compression method */ |
205 | 181 result = JAR_ERR_CORRUPT; |
206 phy = jar_get_physical (jar, path); | 182 } |
207 if (phy) { | 183 if (phy->compression == 0) { |
208 » if (phy->compression != 0 && phy->compression != 8) { | 184 result = jar_physical_extraction((PRFileDesc *)jar->fp, outpath, |
209 » /* unsupported compression method */ | 185 phy->offset, phy->length); |
210 » result = JAR_ERR_CORRUPT; | 186 } else { |
211 » } | 187 result = |
212 » if (phy->compression == 0) { | 188 jar_physical_inflate((PRFileDesc *)jar->fp, outpath, phy->offset, |
213 » result = jar_physical_extraction | 189 phy->length, (unsigned int)phy->compression); |
214 » » ((PRFileDesc*)jar->fp, outpath, phy->offset, phy->length); | 190 } |
215 » } else { | |
216 » result = jar_physical_inflate((PRFileDesc*)jar->fp, outpath, | |
217 » phy->offset, phy->length, | |
218 » (unsigned int) phy->compression); | |
219 » } | |
220 | 191 |
221 #if defined(XP_UNIX) || defined(XP_BEOS) | 192 #if defined(XP_UNIX) || defined(XP_BEOS) |
222 » if (phy->mode) | 193 if (phy->mode) chmod(outpath, 0400 | (mode_t)phy->mode); |
223 » chmod (outpath, 0400 | (mode_t) phy->mode); | |
224 #endif | 194 #endif |
225 } else { | 195 } else { |
226 » /* pathname not found in archive */ | 196 /* pathname not found in archive */ |
227 » result = JAR_ERR_PNF; | 197 result = JAR_ERR_PNF; |
228 } | 198 } |
229 return result; | 199 return result; |
230 } | 200 } |
231 | 201 |
232 /* | 202 /* |
233 * p h y s i c a l _ e x t r a c t i o n | 203 * p h y s i c a l _ e x t r a c t i o n |
234 * | 204 * |
235 * This needs to be done in chunks of say 32k, instead of | 205 * This needs to be done in chunks of say 32k, instead of |
236 * in one bulk calloc. (Necessary under Win16 platform.) | 206 * in one bulk calloc. (Necessary under Win16 platform.) |
237 * This is done for uncompressed entries only. | 207 * This is done for uncompressed entries only. |
238 * | 208 * |
239 */ | 209 */ |
240 | 210 |
241 #define CHUNK 32768 | 211 #define CHUNK 32768 |
242 | 212 |
243 static int | 213 static int jar_physical_extraction(JAR_FILE fp, char *outpath, long offset, |
244 jar_physical_extraction(JAR_FILE fp, char *outpath, long offset, long length) | 214 long length) { |
245 { | 215 JAR_FILE out; |
246 JAR_FILE out; | 216 char *buffer = (char *)PORT_ZAlloc(CHUNK); |
247 char *buffer = (char *)PORT_ZAlloc(CHUNK); | 217 int status = 0; |
248 int status = 0; | 218 |
249 | 219 if (buffer == NULL) return JAR_ERR_MEMORY; |
250 if (buffer == NULL) | 220 |
251 » return JAR_ERR_MEMORY; | 221 if ((out = JAR_FOPEN(outpath, "wb")) != NULL) { |
252 | 222 long at = 0; |
253 if ((out = JAR_FOPEN (outpath, "wb")) != NULL) { | 223 |
254 » long at = 0; | 224 JAR_FSEEK(fp, offset, (PRSeekWhence)0); |
255 | 225 while (at < length) { |
256 » JAR_FSEEK (fp, offset, (PRSeekWhence)0); | 226 long chunk = (at + CHUNK <= length) ? CHUNK : length - at; |
257 » while (at < length) { | 227 if (JAR_FREAD(fp, buffer, chunk) != chunk) { |
258 » long chunk = (at + CHUNK <= length) ? CHUNK : length - at; | 228 status = JAR_ERR_DISK; |
259 » if (JAR_FREAD (fp, buffer, chunk) != chunk) { | 229 break; |
260 » » status = JAR_ERR_DISK; | 230 } |
261 » » break; | 231 at += chunk; |
262 » } | 232 if (JAR_FWRITE(out, buffer, chunk) < chunk) { |
263 » at += chunk; | 233 /* most likely a disk full error */ |
264 » if (JAR_FWRITE (out, buffer, chunk) < chunk) { | 234 status = JAR_ERR_DISK; |
265 » » /* most likely a disk full error */ | 235 break; |
266 » » status = JAR_ERR_DISK; | 236 } |
267 » » break; | 237 } |
268 » } | 238 JAR_FCLOSE(out); |
269 » } | 239 } else { |
270 » JAR_FCLOSE (out); | 240 /* error opening output file */ |
271 } else { | 241 status = JAR_ERR_DISK; |
272 » /* error opening output file */ | 242 } |
273 » status = JAR_ERR_DISK; | 243 PORT_Free(buffer); |
274 } | 244 return status; |
275 PORT_Free (buffer); | |
276 return status; | |
277 } | 245 } |
278 | 246 |
279 /* | 247 /* |
280 * j a r _ p h y s i c a l _ i n f l a t e | 248 * j a r _ p h y s i c a l _ i n f l a t e |
281 * | 249 * |
282 * Inflate a range of bytes in a file, writing the inflated | 250 * Inflate a range of bytes in a file, writing the inflated |
283 * result to "outpath". Chunk based. | 251 * result to "outpath". Chunk based. |
284 * | 252 * |
285 */ | 253 */ |
286 /* input and output chunks differ, assume 4x compression */ | 254 /* input and output chunks differ, assume 4x compression */ |
287 | 255 |
288 #define ICHUNK 8192 | 256 #define ICHUNK 8192 |
289 #define OCHUNK 32768 | 257 #define OCHUNK 32768 |
290 | 258 |
291 static int | 259 static int jar_physical_inflate(JAR_FILE fp, char *outpath, long offset, |
292 jar_physical_inflate(JAR_FILE fp, char *outpath, long offset, long length, | 260 long length, unsigned int method) { |
293 unsigned int method) | 261 char *inbuf, *outbuf; |
294 { | 262 int status = 0; |
295 char *inbuf, *outbuf; | 263 z_stream zs; |
296 int status = 0; | 264 JAR_FILE out; |
297 z_stream zs; | 265 |
298 JAR_FILE out; | 266 /* Raw inflate in zlib 1.1.4 needs an extra dummy byte at the end */ |
299 | 267 if ((inbuf = (char *)PORT_ZAlloc(ICHUNK + 1)) == NULL) return JAR_ERR_MEMORY; |
300 /* Raw inflate in zlib 1.1.4 needs an extra dummy byte at the end */ | 268 |
301 if ((inbuf = (char *)PORT_ZAlloc(ICHUNK + 1)) == NULL) | 269 if ((outbuf = (char *)PORT_ZAlloc(OCHUNK)) == NULL) { |
302 » return JAR_ERR_MEMORY; | 270 PORT_Free(inbuf); |
303 | 271 return JAR_ERR_MEMORY; |
304 if ((outbuf = (char *)PORT_ZAlloc(OCHUNK)) == NULL) { | 272 } |
305 » PORT_Free (inbuf); | 273 |
306 » return JAR_ERR_MEMORY; | 274 PORT_Memset(&zs, 0, sizeof(zs)); |
307 } | 275 status = inflateInit2(&zs, -MAX_WBITS); |
308 | 276 if (status != Z_OK) { |
309 PORT_Memset (&zs, 0, sizeof (zs)); | 277 PORT_Free(inbuf); |
310 status = inflateInit2 (&zs, -MAX_WBITS); | 278 PORT_Free(outbuf); |
311 if (status != Z_OK) { | 279 return JAR_ERR_GENERAL; |
312 » PORT_Free (inbuf); | 280 } |
313 » PORT_Free (outbuf); | 281 |
314 » return JAR_ERR_GENERAL; | 282 if ((out = JAR_FOPEN(outpath, "wb")) != NULL) { |
315 } | 283 long at = 0; |
316 | 284 |
317 if ((out = JAR_FOPEN (outpath, "wb")) != NULL) { | 285 JAR_FSEEK(fp, offset, (PRSeekWhence)0); |
318 » long at = 0; | 286 while (at < length) { |
319 | 287 long chunk = (at + ICHUNK <= length) ? ICHUNK : length - at; |
320 » JAR_FSEEK (fp, offset, (PRSeekWhence)0); | 288 unsigned long tin; |
321 » while (at < length) { | 289 |
322 » long chunk = (at + ICHUNK <= length) ? ICHUNK : length - at; | 290 if (JAR_FREAD(fp, inbuf, chunk) != chunk) { |
323 » unsigned long tin; | 291 /* incomplete read */ |
324 | 292 JAR_FCLOSE(out); |
325 » if (JAR_FREAD (fp, inbuf, chunk) != chunk) { | 293 PORT_Free(inbuf); |
326 » » /* incomplete read */ | 294 PORT_Free(outbuf); |
327 » » JAR_FCLOSE (out); | 295 return JAR_ERR_CORRUPT; |
328 » » PORT_Free (inbuf); | 296 } |
329 » » PORT_Free (outbuf); | 297 at += chunk; |
330 » » return JAR_ERR_CORRUPT; | 298 if (at == length) { |
331 » } | 299 /* add an extra dummy byte at the end */ |
332 » at += chunk; | 300 inbuf[chunk++] = 0xDD; |
333 » if (at == length) { | 301 } |
334 » » /* add an extra dummy byte at the end */ | 302 zs.next_in = (Bytef *)inbuf; |
335 » » inbuf[chunk++] = 0xDD; | 303 zs.avail_in = chunk; |
336 » } | 304 zs.avail_out = OCHUNK; |
337 » zs.next_in = (Bytef *) inbuf; | 305 tin = zs.total_in; |
338 » zs.avail_in = chunk; | 306 while ((zs.total_in - tin < chunk) || (zs.avail_out == 0)) { |
339 » zs.avail_out = OCHUNK; | 307 unsigned long prev_total = zs.total_out; |
340 » tin = zs.total_in; | 308 unsigned long ochunk; |
341 » while ((zs.total_in - tin < chunk) || (zs.avail_out == 0)) { | 309 |
342 » » unsigned long prev_total = zs.total_out; | 310 zs.next_out = (Bytef *)outbuf; |
343 » » unsigned long ochunk; | 311 zs.avail_out = OCHUNK; |
344 | 312 status = inflate(&zs, Z_NO_FLUSH); |
345 » » zs.next_out = (Bytef *) outbuf; | 313 if (status != Z_OK && status != Z_STREAM_END) { |
346 » » zs.avail_out = OCHUNK; | 314 /* error during decompression */ |
347 » » status = inflate (&zs, Z_NO_FLUSH); | 315 JAR_FCLOSE(out); |
348 » » if (status != Z_OK && status != Z_STREAM_END) { | 316 PORT_Free(inbuf); |
349 » » /* error during decompression */ | 317 PORT_Free(outbuf); |
350 » » JAR_FCLOSE (out); | 318 return JAR_ERR_CORRUPT; |
351 » » PORT_Free (inbuf); | 319 } |
352 » » PORT_Free (outbuf); | 320 ochunk = zs.total_out - prev_total; |
353 » » return JAR_ERR_CORRUPT; | 321 if (JAR_FWRITE(out, outbuf, ochunk) < ochunk) { |
354 » » } | 322 /* most likely a disk full error */ |
355 » » ochunk = zs.total_out - prev_total; | 323 status = JAR_ERR_DISK; |
356 » » if (JAR_FWRITE (out, outbuf, ochunk) < ochunk) { | 324 break; |
357 » » /* most likely a disk full error */ | 325 } |
358 » » status = JAR_ERR_DISK; | 326 if (status == Z_STREAM_END) break; |
359 » » break; | 327 } |
360 » » } | 328 } |
361 » » if (status == Z_STREAM_END) | 329 JAR_FCLOSE(out); |
362 » » break; | 330 status = inflateEnd(&zs); |
363 » } | 331 } else { |
364 » } | 332 /* error opening output file */ |
365 » JAR_FCLOSE (out); | 333 status = JAR_ERR_DISK; |
366 » status = inflateEnd (&zs); | 334 } |
367 } else { | 335 PORT_Free(inbuf); |
368 » /* error opening output file */ | 336 PORT_Free(outbuf); |
369 » status = JAR_ERR_DISK; | 337 return status; |
370 } | |
371 PORT_Free (inbuf); | |
372 PORT_Free (outbuf); | |
373 return status; | |
374 } | 338 } |
375 | 339 |
376 /* | 340 /* |
377 * j a r _ i n f l a t e _ m e m o r y | 341 * j a r _ i n f l a t e _ m e m o r y |
378 * | 342 * |
379 * Call zlib to inflate the given memory chunk. It is re-XP_ALLOC'd, | 343 * Call zlib to inflate the given memory chunk. It is re-XP_ALLOC'd, |
380 * and thus appears to operate inplace to the caller. | 344 * and thus appears to operate inplace to the caller. |
381 * | 345 * |
382 */ | 346 */ |
383 static int | 347 static int jar_inflate_memory(unsigned int method, long *length, |
384 jar_inflate_memory(unsigned int method, long *length, long expected_out_len, | 348 long expected_out_len, char **data) { |
385 char **data) | 349 char *inbuf = *data; |
386 { | 350 char *outbuf = (char *)PORT_ZAlloc(expected_out_len); |
387 char *inbuf = *data; | 351 long insz = *length; |
388 char *outbuf = (char*)PORT_ZAlloc(expected_out_len); | 352 int status; |
389 long insz = *length; | 353 z_stream zs; |
390 int status; | 354 |
391 z_stream zs; | 355 if (outbuf == NULL) return JAR_ERR_MEMORY; |
392 | 356 |
393 if (outbuf == NULL) | 357 PORT_Memset(&zs, 0, sizeof zs); |
394 » return JAR_ERR_MEMORY; | 358 status = inflateInit2(&zs, -MAX_WBITS); |
395 | 359 if (status < 0) { |
396 PORT_Memset(&zs, 0, sizeof zs); | 360 /* error initializing zlib stream */ |
397 status = inflateInit2 (&zs, -MAX_WBITS); | 361 PORT_Free(outbuf); |
398 if (status < 0) { | 362 return JAR_ERR_GENERAL; |
399 » /* error initializing zlib stream */ | 363 } |
400 » PORT_Free (outbuf); | 364 |
401 » return JAR_ERR_GENERAL; | 365 zs.next_in = (Bytef *)inbuf; |
402 } | 366 zs.next_out = (Bytef *)outbuf; |
403 | 367 zs.avail_in = insz; |
404 zs.next_in = (Bytef *) inbuf; | 368 zs.avail_out = expected_out_len; |
405 zs.next_out = (Bytef *) outbuf; | 369 |
406 zs.avail_in = insz; | 370 status = inflate(&zs, Z_FINISH); |
407 zs.avail_out = expected_out_len; | 371 if (status != Z_OK && status != Z_STREAM_END) { |
408 | 372 /* error during deflation */ |
409 status = inflate (&zs, Z_FINISH); | 373 PORT_Free(outbuf); |
410 if (status != Z_OK && status != Z_STREAM_END) { | 374 return JAR_ERR_GENERAL; |
411 » /* error during deflation */ | 375 } |
412 » PORT_Free (outbuf); | 376 |
413 » return JAR_ERR_GENERAL; | 377 status = inflateEnd(&zs); |
414 } | 378 if (status != Z_OK) { |
415 | 379 /* error during deflation */ |
416 status = inflateEnd (&zs); | 380 PORT_Free(outbuf); |
417 if (status != Z_OK) { | 381 return JAR_ERR_GENERAL; |
418 » /* error during deflation */ | 382 } |
419 » PORT_Free (outbuf); | 383 PORT_Free(*data); |
420 » return JAR_ERR_GENERAL; | 384 *data = outbuf; |
421 } | 385 *length = zs.total_out; |
422 PORT_Free(*data); | 386 return 0; |
423 *data = outbuf; | |
424 *length = zs.total_out; | |
425 return 0; | |
426 } | 387 } |
427 | 388 |
428 /* | 389 /* |
429 * v e r i f y _ e x t r a c t | 390 * v e r i f y _ e x t r a c t |
430 * | 391 * |
431 * Validate signature on the freshly extracted file. | 392 * Validate signature on the freshly extracted file. |
432 * | 393 * |
433 */ | 394 */ |
434 static int | 395 static int jar_verify_extract(JAR *jar, char *path, char *physical_path) { |
435 jar_verify_extract(JAR *jar, char *path, char *physical_path) | 396 int status; |
436 { | 397 JAR_Digest dig; |
437 int status; | 398 |
438 JAR_Digest dig; | 399 PORT_Memset(&dig, 0, sizeof dig); |
439 | 400 status = JAR_digest_file(physical_path, &dig); |
440 PORT_Memset (&dig, 0, sizeof dig); | 401 if (!status) status = JAR_verify_digest(jar, path, &dig); |
441 status = JAR_digest_file (physical_path, &dig); | 402 return status; |
442 if (!status) | |
443 » status = JAR_verify_digest (jar, path, &dig); | |
444 return status; | |
445 } | 403 } |
446 | 404 |
447 /* | 405 /* |
448 * g e t _ p h y s i c a l | 406 * g e t _ p h y s i c a l |
449 * | 407 * |
450 * Let's get physical. | 408 * Let's get physical. |
451 * Obtains the offset and length of this file in the jar file. | 409 * Obtains the offset and length of this file in the jar file. |
452 * | 410 * |
453 */ | 411 */ |
454 static JAR_Physical * | 412 static JAR_Physical *jar_get_physical(JAR *jar, char *pathname) { |
455 jar_get_physical(JAR *jar, char *pathname) | 413 ZZLink *link; |
456 { | 414 ZZList *list = jar->phy; |
457 ZZLink *link; | 415 |
458 ZZList *list = jar->phy; | 416 if (ZZ_ListEmpty(list)) return NULL; |
459 | 417 |
460 if (ZZ_ListEmpty (list)) | 418 for (link = ZZ_ListHead(list); !ZZ_ListIterDone(list, link); |
461 » return NULL; | 419 link = link->next) { |
462 | 420 JAR_Item *it = link->thing; |
463 for (link = ZZ_ListHead (list); | 421 |
464 !ZZ_ListIterDone (list, link); | 422 if (it->type == jarTypePhy && it->pathname && |
465 link = link->next) { | 423 !PORT_Strcmp(it->pathname, pathname)) { |
466 » JAR_Item *it = link->thing; | 424 JAR_Physical *phy = (JAR_Physical *)it->data; |
467 | 425 return phy; |
468 » if (it->type == jarTypePhy && | 426 } |
469 » it->pathname && !PORT_Strcmp (it->pathname, pathname)) { | 427 } |
470 » JAR_Physical *phy = (JAR_Physical *)it->data; | 428 return NULL; |
471 » return phy; | |
472 » } | |
473 } | |
474 return NULL; | |
475 } | 429 } |
476 | 430 |
477 /* | 431 /* |
478 * j a r _ e x t r a c t _ m a n i f e s t s | 432 * j a r _ e x t r a c t _ m a n i f e s t s |
479 * | 433 * |
480 * Extract the manifest files and parse them, | 434 * Extract the manifest files and parse them, |
481 * from an open archive file whose contents are known. | 435 * from an open archive file whose contents are known. |
482 * | 436 * |
483 */ | 437 */ |
484 static int | 438 static int jar_extract_manifests(JAR *jar, jarArch format, JAR_FILE fp) { |
485 jar_extract_manifests(JAR *jar, jarArch format, JAR_FILE fp) | 439 int status, signatures; |
486 { | 440 |
487 int status, signatures; | 441 if (format != jarArchZip && format != jarArchTar) return JAR_ERR_CORRUPT; |
488 | 442 |
489 if (format != jarArchZip && format != jarArchTar) | 443 if ((status = jar_extract_mf(jar, format, fp, "mf")) < 0) return status; |
490 » return JAR_ERR_CORRUPT; | 444 if (!status) return JAR_ERR_ORDER; |
491 | 445 if ((status = jar_extract_mf(jar, format, fp, "sf")) < 0) return status; |
492 if ((status = jar_extract_mf (jar, format, fp, "mf")) < 0) | 446 if (!status) return JAR_ERR_ORDER; |
493 » return status; | 447 if ((status = jar_extract_mf(jar, format, fp, "rsa")) < 0) return status; |
494 if (!status) | 448 signatures = status; |
495 » return JAR_ERR_ORDER; | 449 if ((status = jar_extract_mf(jar, format, fp, "dsa")) < 0) return status; |
496 if ((status = jar_extract_mf (jar, format, fp, "sf")) < 0) | 450 if (!(signatures += status)) return JAR_ERR_SIG; |
497 » return status; | 451 return 0; |
498 if (!status) | |
499 » return JAR_ERR_ORDER; | |
500 if ((status = jar_extract_mf (jar, format, fp, "rsa")) < 0) | |
501 » return status; | |
502 signatures = status; | |
503 if ((status = jar_extract_mf (jar, format, fp, "dsa")) < 0) | |
504 » return status; | |
505 if (!(signatures += status)) | |
506 » return JAR_ERR_SIG; | |
507 return 0; | |
508 } | 452 } |
509 | 453 |
510 /* | 454 /* |
511 * j a r _ e x t r a c t _ m f | 455 * j a r _ e x t r a c t _ m f |
512 * | 456 * |
513 * Extracts manifest files based on an extension, which | 457 * Extracts manifest files based on an extension, which |
514 * should be .MF, .SF, .RSA, etc. Order of the files is now no | 458 * should be .MF, .SF, .RSA, etc. Order of the files is now no |
515 * longer important when zipping jar files. | 459 * longer important when zipping jar files. |
516 * | 460 * |
517 */ | 461 */ |
518 static int | 462 static int jar_extract_mf(JAR *jar, jarArch format, JAR_FILE fp, char *ext) { |
519 jar_extract_mf(JAR *jar, jarArch format, JAR_FILE fp, char *ext) | 463 ZZLink *link; |
520 { | 464 ZZList *list = jar->phy; |
521 ZZLink *link; | 465 int ret = 0; |
522 ZZList *list = jar->phy; | 466 |
523 int ret = 0; | 467 if (ZZ_ListEmpty(list)) return JAR_ERR_PNF; |
524 | 468 |
525 if (ZZ_ListEmpty (list)) | 469 for (link = ZZ_ListHead(list); ret >= 0 && !ZZ_ListIterDone(list, link); |
526 » return JAR_ERR_PNF; | 470 link = link->next) { |
527 | 471 JAR_Item *it = link->thing; |
528 for (link = ZZ_ListHead (list); | 472 |
529 ret >= 0 && !ZZ_ListIterDone (list, link); | 473 if (it->type == jarTypePhy && !PORT_Strncmp(it->pathname, "META-INF", 8)) { |
530 link = link->next) { | 474 JAR_Physical *phy = (JAR_Physical *)it->data; |
531 » JAR_Item *it = link->thing; | 475 char *fn = it->pathname + 8; |
532 | 476 char *e; |
533 » if (it->type == jarTypePhy && | 477 char *manifest; |
534 » !PORT_Strncmp (it->pathname, "META-INF", 8)) | 478 long length; |
535 » { | 479 int num, status; |
536 » JAR_Physical *phy = (JAR_Physical *) it->data; | 480 |
537 » char *fn = it->pathname + 8; | 481 if (PORT_Strlen(it->pathname) < 8) continue; |
538 » char *e; | 482 |
539 » char *manifest; | 483 if (*fn == '/' || *fn == '\\') fn++; |
540 » long length; | 484 if (*fn == 0) { |
541 » int num, status; | 485 /* just a directory entry */ |
542 | 486 continue; |
543 » if (PORT_Strlen (it->pathname) < 8) | 487 } |
544 » » continue; | 488 |
545 | 489 /* skip to extension */ |
546 » if (*fn == '/' || *fn == '\\') | 490 for (e = fn; *e && *e != '.'; e++) /* yip */; |
547 » » fn++; | 491 |
548 » if (*fn == 0) { | 492 /* and skip dot */ |
549 » » /* just a directory entry */ | 493 if (*e == '.') e++; |
550 » » continue; | 494 if (PORT_Strcasecmp(ext, e)) { |
551 » } | 495 /* not the right extension */ |
552 | 496 continue; |
553 » /* skip to extension */ | 497 } |
554 » for (e = fn; *e && *e != '.'; e++) | 498 if (phy->length == 0 || phy->length > 0xFFFF) { |
555 » » /* yip */ ; | 499 /* manifest files cannot be zero length or too big! */ |
556 | 500 /* the 0xFFFF limit is per J2SE SDK */ |
557 » /* and skip dot */ | 501 return JAR_ERR_CORRUPT; |
558 » if (*e == '.') | 502 } |
559 » » e++; | 503 |
560 » if (PORT_Strcasecmp (ext, e)) { | 504 /* Read in the manifest and parse it */ |
561 » » /* not the right extension */ | 505 /* Raw inflate in zlib 1.1.4 needs an extra dummy byte at the end */ |
562 » » continue; | 506 manifest = (char *)PORT_ZAlloc(phy->length + 1); |
563 » } | 507 if (!manifest) return JAR_ERR_MEMORY; |
564 » if (phy->length == 0 || phy->length > 0xFFFF) { | 508 |
565 » » /* manifest files cannot be zero length or too big! */ | 509 JAR_FSEEK(fp, phy->offset, (PRSeekWhence)0); |
566 » » /* the 0xFFFF limit is per J2SE SDK */ | 510 num = JAR_FREAD(fp, manifest, phy->length); |
567 » » return JAR_ERR_CORRUPT; | 511 if (num != phy->length) { |
568 » } | 512 /* corrupt archive file */ |
569 | 513 PORT_Free(manifest); |
570 » /* Read in the manifest and parse it */ | 514 return JAR_ERR_CORRUPT; |
571 » /* Raw inflate in zlib 1.1.4 needs an extra dummy byte at the end */ | 515 } |
572 » manifest = (char *)PORT_ZAlloc(phy->length + 1); | 516 |
573 » if (!manifest) | 517 if (phy->compression == 8) { |
574 » » return JAR_ERR_MEMORY; | 518 length = phy->length; |
575 | 519 /* add an extra dummy byte at the end */ |
576 » JAR_FSEEK (fp, phy->offset, (PRSeekWhence)0); | 520 manifest[length++] = 0xDD; |
577 » num = JAR_FREAD (fp, manifest, phy->length); | 521 status = jar_inflate_memory((unsigned int)phy->compression, &length, |
578 » if (num != phy->length) { | 522 phy->uncompressed_length, &manifest); |
579 » » /* corrupt archive file */ | 523 if (status < 0) { |
580 » » PORT_Free (manifest); | 524 PORT_Free(manifest); |
581 » » return JAR_ERR_CORRUPT; | 525 return status; |
582 » } | 526 } |
583 | 527 } else if (phy->compression) { |
584 » if (phy->compression == 8) { | 528 /* unsupported compression method */ |
585 » » length = phy->length; | 529 PORT_Free(manifest); |
586 » » /* add an extra dummy byte at the end */ | 530 return JAR_ERR_CORRUPT; |
587 » » manifest[length++] = 0xDD; | 531 } else |
588 » » status = jar_inflate_memory((unsigned int)phy->compression,· | 532 length = phy->length; |
589 » » » » » &length,·· | 533 |
590 » » » » » phy->uncompressed_length,· | 534 status = JAR_parse_manifest(jar, manifest, length, it->pathname, "url"); |
591 » » » » » &manifest); | 535 PORT_Free(manifest); |
592 » » if (status < 0) { | 536 if (status < 0) |
593 » » PORT_Free (manifest); | 537 ret = status; |
594 » » return status; | 538 else |
595 » » } | 539 ++ret; |
596 » } else if (phy->compression) { | 540 } else if (it->type == jarTypePhy) { |
597 » » /* unsupported compression method */ | 541 /* ordinary file */ |
598 » » PORT_Free (manifest); | 542 } |
599 » » return JAR_ERR_CORRUPT; | 543 } |
600 » } else | 544 return ret; |
601 » » length = phy->length; | |
602 | |
603 » status = JAR_parse_manifest(jar, manifest, length, | |
604 » » » » » it->pathname, "url"); | |
605 » PORT_Free (manifest); | |
606 » if (status < 0) | |
607 » » ret = status; | |
608 » else | |
609 » » ++ret; | |
610 » } else if (it->type == jarTypePhy) { | |
611 » /* ordinary file */ | |
612 » } | |
613 } | |
614 return ret; | |
615 } | 545 } |
616 | 546 |
617 /* | 547 /* |
618 * j a r _ g e n _ i n d e x | 548 * j a r _ g e n _ i n d e x |
619 * | 549 * |
620 * Generate an index for the various types of | 550 * Generate an index for the various types of |
621 * known archive files. Right now .ZIP and .TAR | 551 * known archive files. Right now .ZIP and .TAR |
622 * | 552 * |
623 */ | 553 */ |
624 static int | 554 static int jar_gen_index(JAR *jar, jarArch format, JAR_FILE fp) { |
625 jar_gen_index(JAR *jar, jarArch format, JAR_FILE fp) | 555 int result = JAR_ERR_CORRUPT; |
626 { | 556 |
627 int result = JAR_ERR_CORRUPT; | 557 JAR_FSEEK(fp, 0, (PRSeekWhence)0); |
628 | 558 switch (format) { |
629 JAR_FSEEK (fp, 0, (PRSeekWhence)0); | |
630 switch (format) { | |
631 case jarArchZip: | 559 case jarArchZip: |
632 » result = jar_listzip (jar, fp); | 560 result = jar_listzip(jar, fp); |
633 » break; | 561 break; |
634 | 562 |
635 case jarArchTar: | 563 case jarArchTar: |
636 » result = jar_listtar (jar, fp); | 564 result = jar_listtar(jar, fp); |
637 » break; | 565 break; |
638 | 566 |
639 case jarArchGuess: | 567 case jarArchGuess: |
640 case jarArchNone: | 568 case jarArchNone: |
641 » return JAR_ERR_GENERAL; | 569 return JAR_ERR_GENERAL; |
642 } | 570 } |
643 JAR_FSEEK (fp, 0, (PRSeekWhence)0); | 571 JAR_FSEEK(fp, 0, (PRSeekWhence)0); |
644 return result; | 572 return result; |
645 } | 573 } |
646 | 574 |
647 /* | 575 /* |
648 * j a r _ l i s t z i p | 576 * j a r _ l i s t z i p |
649 * | 577 * |
650 * List the physical contents of a Phil Katz | 578 * List the physical contents of a Phil Katz |
651 * style .ZIP file into the JAR linked list. | 579 * style .ZIP file into the JAR linked list. |
652 * | 580 * |
653 */ | 581 */ |
654 static int | 582 static int jar_listzip(JAR *jar, JAR_FILE fp) { |
655 jar_listzip(JAR *jar, JAR_FILE fp) | 583 ZZLink *ent; |
656 { | 584 JAR_Item *it; |
657 ZZLink *ent; | 585 JAR_Physical *phy; |
658 JAR_Item *it; | 586 struct ZipLocal *Local = PORT_ZNew(struct ZipLocal); |
659 JAR_Physical *phy; | 587 struct ZipCentral *Central = PORT_ZNew(struct ZipCentral); |
660 struct ZipLocal *Local = PORT_ZNew(struct ZipLocal); | 588 struct ZipEnd *End = PORT_ZNew(struct ZipEnd); |
661 struct ZipCentral *Central = PORT_ZNew(struct ZipCentral); | 589 |
662 struct ZipEnd *End = PORT_ZNew(struct ZipEnd); | 590 int err = 0; |
663 | 591 long pos = 0L; |
664 int err = 0; | 592 unsigned int compression; |
665 long pos = 0L; | 593 unsigned int filename_len, extra_len; |
666 unsigned int compression; | 594 |
667 unsigned int filename_len, extra_len; | 595 char filename[JAR_SIZE]; |
668 | 596 char date[9], time[9]; |
669 char filename[JAR_SIZE]; | 597 char sig[4]; |
670 char date[9], time[9]; | 598 |
671 char sig[4]; | 599 if (!Local || !Central || !End) { |
672 | 600 /* out of memory */ |
673 if (!Local || !Central || !End) { | 601 err = JAR_ERR_MEMORY; |
674 » /* out of memory */ | 602 goto loser; |
675 » err = JAR_ERR_MEMORY; | 603 } |
676 » goto loser; | 604 |
677 } | 605 while (1) { |
678 | 606 PRUint32 sigVal; |
679 while (1) { | 607 JAR_FSEEK(fp, pos, (PRSeekWhence)0); |
680 » PRUint32 sigVal; | 608 |
681 » JAR_FSEEK (fp, pos, (PRSeekWhence)0); | 609 if (JAR_FREAD(fp, sig, sizeof sig) != sizeof sig) { |
682 | 610 /* zip file ends prematurely */ |
683 » if (JAR_FREAD(fp, sig, sizeof sig) != sizeof sig) { | 611 err = JAR_ERR_CORRUPT; |
684 » /* zip file ends prematurely */ | 612 goto loser; |
685 » err = JAR_ERR_CORRUPT; | 613 } |
686 » goto loser; | 614 |
687 » } | 615 JAR_FSEEK(fp, pos, (PRSeekWhence)0); |
688 | 616 sigVal = x86LongToUint32(sig); |
689 » JAR_FSEEK (fp, pos, (PRSeekWhence)0); | 617 if (sigVal == LSIG) { |
690 » sigVal = x86LongToUint32(sig); | 618 JAR_FREAD(fp, Local, sizeof *Local); |
691 » if (sigVal == LSIG) { | 619 |
692 » JAR_FREAD (fp, Local, sizeof *Local); | 620 filename_len = x86ShortToUint32(Local->filename_len); |
693 | 621 extra_len = x86ShortToUint32(Local->extrafield_len); |
694 » filename_len = x86ShortToUint32(Local->filename_len); | 622 if (filename_len >= JAR_SIZE) { |
695 » extra_len = x86ShortToUint32(Local->extrafield_len); | 623 /* corrupt zip file */ |
696 » if (filename_len >= JAR_SIZE) { | 624 err = JAR_ERR_CORRUPT; |
697 » » /* corrupt zip file */ | 625 goto loser; |
698 » » err = JAR_ERR_CORRUPT; | 626 } |
699 » » goto loser; | 627 |
700 » } | 628 if (JAR_FREAD(fp, filename, filename_len) != filename_len) { |
701 | 629 /* truncated archive file */ |
702 » if (JAR_FREAD (fp, filename, filename_len) != filename_len) { | 630 err = JAR_ERR_CORRUPT; |
703 » » /* truncated archive file */ | 631 goto loser; |
704 » » err = JAR_ERR_CORRUPT; | 632 } |
705 » » goto loser; | 633 filename[filename_len] = 0; |
706 » } | 634 /* Add this to our jar chain */ |
707 » filename [filename_len] = 0; | 635 phy = PORT_ZNew(JAR_Physical); |
708 » /* Add this to our jar chain */ | 636 if (phy == NULL) { |
709 » phy = PORT_ZNew(JAR_Physical); | 637 err = JAR_ERR_MEMORY; |
710 » if (phy == NULL) { | 638 goto loser; |
711 » » err = JAR_ERR_MEMORY; | 639 } |
712 » » goto loser; | 640 |
713 » } | 641 /* We will index any file that comes our way, but when it comes |
714 | 642 to actually extraction, compression must be 0 or 8 */ |
715 » /* We will index any file that comes our way, but when it comes | 643 compression = x86ShortToUint32(Local->method); |
716 » to actually extraction, compression must be 0 or 8 */ | 644 phy->compression = (compression <= 255) ? compression : 222; |
717 » compression = x86ShortToUint32(Local->method); | 645 /* XXX 222 is bad magic. */ |
718 » phy->compression = (compression <= 255) ? compression : 222; | 646 |
719 » » /* XXX 222 is bad magic. */ | 647 phy->offset = pos + (sizeof *Local) + filename_len + extra_len; |
720 | 648 phy->length = x86LongToUint32(Local->size); |
721 » phy->offset = pos + (sizeof *Local) + filename_len + extra_len; | 649 phy->uncompressed_length = x86LongToUint32(Local->orglen); |
722 » phy->length = x86LongToUint32(Local->size); | 650 |
723 » phy->uncompressed_length = x86LongToUint32(Local->orglen); | 651 dosdate(date, Local->date); |
724 | 652 dostime(time, Local->time); |
725 » dosdate (date, Local->date); | 653 |
726 » dostime (time, Local->time); | 654 it = PORT_ZNew(JAR_Item); |
727 | 655 if (it == NULL) { |
728 » it = PORT_ZNew(JAR_Item); | 656 err = JAR_ERR_MEMORY; |
729 » if (it == NULL) { | 657 goto loser; |
730 » » err = JAR_ERR_MEMORY; | 658 } |
731 » » goto loser; | 659 |
732 » } | 660 it->pathname = PORT_Strdup(filename); |
733 | 661 it->type = jarTypePhy; |
734 » it->pathname = PORT_Strdup(filename); | 662 it->data = (unsigned char *)phy; |
735 » it->type = jarTypePhy; | 663 it->size = sizeof(JAR_Physical); |
736 » it->data = (unsigned char *) phy; | 664 |
737 » it->size = sizeof (JAR_Physical); | 665 ent = ZZ_NewLink(it); |
738 | 666 if (ent == NULL) { |
739 » ent = ZZ_NewLink (it); | 667 err = JAR_ERR_MEMORY; |
740 » if (ent == NULL) { | 668 goto loser; |
741 » » err = JAR_ERR_MEMORY; | 669 } |
742 » » goto loser; | 670 |
743 » } | 671 ZZ_AppendLink(jar->phy, ent); |
744 | 672 pos = phy->offset + phy->length; |
745 » ZZ_AppendLink (jar->phy, ent); | 673 } else if (sigVal == CSIG) { |
746 » pos = phy->offset + phy->length; | 674 unsigned int attr = 0; |
747 » } else if (sigVal == CSIG) { | 675 if (JAR_FREAD(fp, Central, sizeof *Central) != sizeof *Central) { |
748 » unsigned int attr = 0; | 676 /* apparently truncated archive */ |
749 » if (JAR_FREAD(fp, Central, sizeof *Central) != sizeof *Central) { | 677 err = JAR_ERR_CORRUPT; |
750 » » /* apparently truncated archive */ | 678 goto loser; |
751 » » err = JAR_ERR_CORRUPT; | 679 } |
752 » » goto loser; | |
753 » } | |
754 | 680 |
755 #if defined(XP_UNIX) || defined(XP_BEOS) | 681 #if defined(XP_UNIX) || defined(XP_BEOS) |
756 » /* with unix we need to locate any bits from | 682 /* with unix we need to locate any bits from |
757 » the protection mask in the external attributes. */ | 683 the protection mask in the external attributes. */ |
758 » attr = Central->external_attributes [2]; /* magic */ | 684 attr = Central->external_attributes[2]; /* magic */ |
759 » if (attr) { | 685 if (attr) { |
760 » » /* we have to read the filename, again */ | 686 /* we have to read the filename, again */ |
761 » » filename_len = x86ShortToUint32(Central->filename_len); | 687 filename_len = x86ShortToUint32(Central->filename_len); |
762 » » if (filename_len >= JAR_SIZE) { | 688 if (filename_len >= JAR_SIZE) { |
763 » » /* corrupt in central directory */ | 689 /* corrupt in central directory */ |
764 » » err = JAR_ERR_CORRUPT; | 690 err = JAR_ERR_CORRUPT; |
765 » » goto loser; | 691 goto loser; |
766 » » } | 692 } |
767 | 693 |
768 » » if (JAR_FREAD(fp, filename, filename_len) != filename_len) { | 694 if (JAR_FREAD(fp, filename, filename_len) != filename_len) { |
769 » » /* truncated in central directory */ | 695 /* truncated in central directory */ |
770 » » err = JAR_ERR_CORRUPT; | 696 err = JAR_ERR_CORRUPT; |
771 » » goto loser; | 697 goto loser; |
772 » » } | 698 } |
773 » » filename [filename_len] = 0; | 699 filename[filename_len] = 0; |
774 | 700 |
775 » » /* look up this name again */ | 701 /* look up this name again */ |
776 » » phy = jar_get_physical (jar, filename); | 702 phy = jar_get_physical(jar, filename); |
777 » » if (phy) { | 703 if (phy) { |
778 » » /* always allow access by self */ | 704 /* always allow access by self */ |
779 » » phy->mode = 0400 | attr; | 705 phy->mode = 0400 | attr; |
780 » » } | 706 } |
781 » } | 707 } |
782 #endif | 708 #endif |
783 » pos += sizeof(struct ZipCentral) | 709 pos += sizeof(struct ZipCentral) + |
784 » + x86ShortToUint32(Central->filename_len) | 710 x86ShortToUint32(Central->filename_len) + |
785 » » + x86ShortToUint32(Central->commentfield_len) | 711 x86ShortToUint32(Central->commentfield_len) + |
786 » » + x86ShortToUint32(Central->extrafield_len); | 712 x86ShortToUint32(Central->extrafield_len); |
787 » } else if (sigVal == ESIG) { | 713 } else if (sigVal == ESIG) { |
788 » if (JAR_FREAD(fp, End, sizeof *End) != sizeof *End) { | 714 if (JAR_FREAD(fp, End, sizeof *End) != sizeof *End) { |
789 » » err = JAR_ERR_CORRUPT; | 715 err = JAR_ERR_CORRUPT; |
790 » » goto loser; | 716 goto loser; |
791 » } | 717 } |
792 » break; | 718 break; |
793 » } else { | 719 } else { |
794 » /* garbage in archive */ | 720 /* garbage in archive */ |
795 » err = JAR_ERR_CORRUPT; | 721 err = JAR_ERR_CORRUPT; |
796 » goto loser; | 722 goto loser; |
797 » } | 723 } |
798 } | 724 } |
799 | 725 |
800 loser: | 726 loser: |
801 if (Local) | 727 if (Local) PORT_Free(Local); |
802 » PORT_Free(Local); | 728 if (Central) PORT_Free(Central); |
803 if (Central) | 729 if (End) PORT_Free(End); |
804 » PORT_Free(Central); | 730 return err; |
805 if (End) | |
806 » PORT_Free(End); | |
807 return err; | |
808 } | 731 } |
809 | 732 |
810 /* | 733 /* |
811 * j a r _ l i s t t a r | 734 * j a r _ l i s t t a r |
812 * | 735 * |
813 * List the physical contents of a Unix | 736 * List the physical contents of a Unix |
814 * .tar file into the JAR linked list. | 737 * .tar file into the JAR linked list. |
815 * | 738 * |
816 */ | 739 */ |
817 static int | 740 static int jar_listtar(JAR *jar, JAR_FILE fp) { |
818 jar_listtar(JAR *jar, JAR_FILE fp) | 741 char *s; |
819 { | 742 JAR_Physical *phy; |
820 char *s; | 743 long pos = 0L; |
821 JAR_Physical *phy; | 744 long sz, mode; |
822 long pos = 0L; | 745 time_t when; |
823 long sz, mode; | 746 union TarEntry tarball; |
824 time_t when; | 747 |
825 union TarEntry tarball; | 748 while (1) { |
826 | 749 JAR_FSEEK(fp, pos, (PRSeekWhence)0); |
827 while (1) { | 750 |
828 » JAR_FSEEK (fp, pos, (PRSeekWhence)0); | 751 if (JAR_FREAD(fp, &tarball, sizeof tarball) < sizeof tarball) break; |
829 | 752 |
830 » if (JAR_FREAD (fp, &tarball, sizeof tarball) < sizeof tarball) | 753 if (!*tarball.val.filename) break; |
831 » break; | 754 |
832 | 755 when = octalToLong(tarball.val.time); |
833 » if (!*tarball.val.filename) | 756 sz = octalToLong(tarball.val.size); |
834 » break; | 757 mode = octalToLong(tarball.val.mode); |
835 | 758 |
836 » when = octalToLong (tarball.val.time); | 759 /* Tag the end of filename */ |
837 » sz = octalToLong (tarball.val.size); | 760 s = tarball.val.filename; |
838 » mode = octalToLong (tarball.val.mode); | 761 while (*s && *s != ' ') s++; |
839 | 762 *s = 0; |
840 » /* Tag the end of filename */ | 763 |
841 » s = tarball.val.filename; | 764 /* Add to our linked list */ |
842 » while (*s && *s != ' ')· | 765 phy = PORT_ZNew(JAR_Physical); |
843 » s++; | 766 if (phy == NULL) return JAR_ERR_MEMORY; |
844 » *s = 0; | 767 |
845 | 768 phy->compression = 0; |
846 » /* Add to our linked list */ | 769 phy->offset = pos + sizeof tarball; |
847 » phy = PORT_ZNew(JAR_Physical); | 770 phy->length = sz; |
848 » if (phy == NULL) | 771 |
849 » return JAR_ERR_MEMORY; | 772 ADDITEM(jar->phy, jarTypePhy, tarball.val.filename, phy, sizeof *phy); |
850 | 773 |
851 » phy->compression = 0; | 774 /* Advance to next file entry */ |
852 » phy->offset = pos + sizeof tarball; | 775 sz = PR_ROUNDUP(sz, sizeof tarball); |
853 » phy->length = sz; | 776 pos += sz + sizeof tarball; |
854 | 777 } |
855 » ADDITEM(jar->phy, jarTypePhy, tarball.val.filename, phy, | 778 |
856 » sizeof *phy); | 779 return 0; |
857 | |
858 » /* Advance to next file entry */ | |
859 » sz = PR_ROUNDUP(sz,sizeof tarball); | |
860 » pos += sz + sizeof tarball; | |
861 } | |
862 | |
863 return 0; | |
864 } | 780 } |
865 | 781 |
866 /* | 782 /* |
867 * d o s d a t e | 783 * d o s d a t e |
868 * | 784 * |
869 * Not used right now, but keep it in here because | 785 * Not used right now, but keep it in here because |
870 * it will be needed. | 786 * it will be needed. |
871 * | 787 * |
872 */ | 788 */ |
873 static int | 789 static int dosdate(char *date, const char *s) { |
874 dosdate(char *date, const char *s) | 790 PRUint32 num = x86ShortToUint32(s); |
875 { | 791 |
876 PRUint32 num = x86ShortToUint32(s); | 792 PR_snprintf(date, 9, "%02d-%02d-%02d", ((num >> 5) & 0x0F), (num & 0x1F), |
877 | 793 ((num >> 9) + 80)); |
878 PR_snprintf(date, 9, "%02d-%02d-%02d", ((num >> 5) & 0x0F), (num & 0x1F), | 794 return 0; |
879 ((num >> 9) + 80)); | |
880 return 0; | |
881 } | 795 } |
882 | 796 |
883 /* | 797 /* |
884 * d o s t i m e | 798 * d o s t i m e |
885 * | 799 * |
886 * Not used right now, but keep it in here because | 800 * Not used right now, but keep it in here because |
887 * it will be needed. | 801 * it will be needed. |
888 * | 802 * |
889 */ | 803 */ |
890 static int | 804 static int dostime(char *time, const char *s) { |
891 dostime (char *time, const char *s) | 805 PRUint32 num = x86ShortToUint32(s); |
892 { | 806 |
893 PRUint32 num = x86ShortToUint32(s); | 807 PR_snprintf(time, 6, "%02d:%02d", ((num >> 11) & 0x1F), ((num >> 5) & 0x3F)); |
894 | 808 return 0; |
895 PR_snprintf (time, 6, "%02d:%02d", ((num >> 11) & 0x1F), | |
896 ((num >> 5) & 0x3F)); | |
897 return 0; | |
898 } | 809 } |
899 | 810 |
900 #ifndef NSS_X86_OR_X64 | 811 #ifndef NSS_X86_OR_X64 |
901 /* | 812 /* |
902 * Simulates an x86 (little endian, unaligned) ushort fetch from any address. | 813 * Simulates an x86 (little endian, unaligned) ushort fetch from any address. |
903 */ | 814 */ |
904 static PRUint32 | 815 static PRUint32 x86ShortToUint32(const void *v) { |
905 x86ShortToUint32(const void * v) | 816 const unsigned char *ii = (const unsigned char *)v; |
906 { | 817 PRUint32 ret = (PRUint32)(ii[0]) | ((PRUint32)(ii[1]) << 8); |
907 const unsigned char *ii = (const unsigned char *)v; | 818 return ret; |
908 PRUint32 ret = (PRUint32)(ii[0]) | ((PRUint32)(ii[1]) << 8); | |
909 return ret; | |
910 } | 819 } |
911 | 820 |
912 /* | 821 /* |
913 * Simulates an x86 (little endian, unaligned) uint fetch from any address. | 822 * Simulates an x86 (little endian, unaligned) uint fetch from any address. |
914 */ | 823 */ |
915 static PRUint32 | 824 static PRUint32 x86LongToUint32(const void *v) { |
916 x86LongToUint32(const void *v) | 825 const unsigned char *ll = (const unsigned char *)v; |
917 { | 826 PRUint32 ret; |
918 const unsigned char *ll = (const unsigned char *)v; | 827 |
919 PRUint32 ret; | 828 ret = ((((PRUint32)(ll[0])) << 0) | (((PRUint32)(ll[1])) << 8) | |
920 | 829 (((PRUint32)(ll[2])) << 16) | (((PRUint32)(ll[3])) << 24)); |
921 ret = ((((PRUint32)(ll[0])) << 0) | | 830 return ret; |
922 » (((PRUint32)(ll[1])) << 8) | | |
923 » (((PRUint32)(ll[2])) << 16) | | |
924 » (((PRUint32)(ll[3])) << 24)); | |
925 return ret; | |
926 } | 831 } |
927 #endif | 832 #endif |
928 | 833 |
929 /* | 834 /* |
930 * ASCII octal to binary long. | 835 * ASCII octal to binary long. |
931 * Used for integer encoding inside tar files. | 836 * Used for integer encoding inside tar files. |
932 * | 837 * |
933 */ | 838 */ |
934 static long | 839 static long octalToLong(const char *s) { |
935 octalToLong(const char *s) | 840 long num = 0L; |
936 { | 841 |
937 long num = 0L; | 842 while (*s == ' ') s++; |
938 | 843 while (*s >= '0' && *s <= '7') { |
939 while (*s == ' ') | 844 num <<= 3; |
940 » s++; | 845 num += *s++ - '0'; |
941 while (*s >= '0' && *s <= '7') { | 846 } |
942 » num <<= 3; | 847 return num; |
943 » num += *s++ - '0'; | |
944 } | |
945 return num; | |
946 } | 848 } |
947 | 849 |
948 /* | 850 /* |
949 * g u e s s _ j a r | 851 * g u e s s _ j a r |
950 * | 852 * |
951 * Try to guess what kind of JAR file this is. | 853 * Try to guess what kind of JAR file this is. |
952 * Maybe tar, maybe zip. Look in the file for magic | 854 * Maybe tar, maybe zip. Look in the file for magic |
953 * or at its filename. | 855 * or at its filename. |
954 * | 856 * |
955 */ | 857 */ |
956 static int | 858 static int jar_guess_jar(const char *filename, JAR_FILE fp) { |
957 jar_guess_jar(const char *filename, JAR_FILE fp) | 859 PRInt32 len = PORT_Strlen(filename); |
958 { | 860 const char *ext = filename + len - 4; /* 4 for ".tar" */ |
959 PRInt32 len = PORT_Strlen(filename); | 861 |
960 const char *ext = filename + len - 4; /* 4 for ".tar" */ | 862 if (len >= 4 && !PL_strcasecmp(ext, ".tar")) return jarArchTar; |
961 | 863 return jarArchZip; |
962 if (len >= 4 && !PL_strcasecmp(ext, ".tar")) | 864 } |
963 » return jarArchTar; | |
964 return jarArchZip; | |
965 } | |
OLD | NEW |