~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/security/nss/lib/jar/jarfile.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

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