Bug Summary

File:s/lib/jar/jarfile.c
Warning:line 516, column 11
Although the value stored to 'signatures' is used in the enclosing expression, the value is never actually read from 'signatures'

Annotated Source Code

Press '?' to see keyboard shortcuts

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