~ubuntu-branches/ubuntu/raring/nss/raring-security

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Chris Coulson
  • Date: 2010-03-25 13:46:06 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20100325134606-bl6liuok2w9l7snv
Tags: 3.12.6-0ubuntu1
* New upstream release 3.12.6 RTM (NSS_3_12_6_RTM)
  - fixes CVE-2009-3555 aka US-CERT VU#120541
* Adjust patches to changed upstream code base
  - update debian/patches/38_kbsd.patch
  - update debian/patches/38_mips64_build.patch
  - update debian/patches/85_security_load.patch
* Remove patches that are merged upstream
  - delete debian/patches/91_nonexec_stack.patch
  - update debian/patches/series
* Bump nspr dependency to 4.8
  - update debian/control
* Add new symbols for 3.12.6
  - update debian/libnss3-1d.symbols

Show diffs side-by-side

added added

removed removed

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