security/nss/lib/jar/jarfile.c

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

mercurial