Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / cmd / signtool / zip.c
blob2da1623ad87bc232541d12930ed162d848cf53c3
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "signtool.h"
38 #include "zip.h"
39 #include "zlib.h"
40 #include "prmem.h"
42 static void inttox (int in, char *out);
43 static void longtox (long in, char *out);
45 /****************************************************************
47 * J z i p O p e n
49 * Opens a new ZIP file and creates a new ZIPfile structure to
50 * control the process of installing files into a zip.
52 ZIPfile*
53 JzipOpen(char *filename, char *comment)
55 ZIPfile * zipfile;
56 PRExplodedTime prtime;
58 zipfile = PORT_ZAlloc(sizeof(ZIPfile));
59 if (!zipfile)
60 out_of_memory();
62 /* Construct time and date */
63 PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime);
64 zipfile->date = ((prtime.tm_year - 1980) << 9) |
65 ((prtime.tm_month + 1) << 5) |
66 prtime.tm_mday;
67 zipfile->time = (prtime.tm_hour << 11) |
68 (prtime.tm_min << 5) |
69 (prtime.tm_sec & 0x3f);
71 zipfile->fp = NULL;
72 if (filename &&
73 (zipfile->fp = PR_Open(filename,
74 PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777)) == NULL) {
75 char *nsprErr;
76 if (PR_GetErrorTextLength()) {
77 nsprErr = PR_Malloc(PR_GetErrorTextLength());
78 PR_GetErrorText(nsprErr);
79 } else {
80 nsprErr = NULL;
82 PR_fprintf(errorFD, "%s: can't open output jar, %s.%s\n",
83 PROGRAM_NAME,
84 filename, nsprErr ? nsprErr : "");
85 if (nsprErr)
86 PR_Free(nsprErr);
87 errorCount++;
88 exit (ERRX);
91 zipfile->list = NULL;
92 if (filename) {
93 zipfile->filename = PORT_ZAlloc(strlen(filename) + 1);
94 if (!zipfile->filename)
95 out_of_memory();
96 PORT_Strcpy(zipfile->filename, filename);
98 if (comment) {
99 zipfile->comment = PORT_ZAlloc(strlen(comment) + 1);
100 if (!zipfile->comment)
101 out_of_memory();
102 PORT_Strcpy(zipfile->comment, comment);
105 return zipfile;
109 static
110 void*
111 my_alloc_func(void*opaque, uInt items, uInt size)
113 return PORT_Alloc(items * size);
117 static
118 void
119 my_free_func(void*opaque, void*address)
121 PORT_Free(address);
125 static
126 void
127 handle_zerror(int err, char *msg)
129 if (!msg) {
130 msg = "";
133 errorCount++; /* unless Z_OK...see below */
135 switch (err) {
136 case Z_OK:
137 PR_fprintf(errorFD, "No error: %s\n", msg);
138 errorCount--; /* this was incremented above */
139 break;
140 case Z_MEM_ERROR:
141 PR_fprintf(errorFD, "Deflation ran out of memory: %s\n", msg);
142 break;
143 case Z_STREAM_ERROR:
144 PR_fprintf(errorFD, "Invalid compression level: %s\n", msg);
145 break;
146 case Z_VERSION_ERROR:
147 PR_fprintf(errorFD, "Incompatible compression library version: %s\n",
148 msg);
149 break;
150 case Z_DATA_ERROR:
151 PR_fprintf(errorFD, "Compression data error: %s\n", msg);
152 break;
153 default:
154 PR_fprintf(errorFD, "Unknown error in compression library: %s\n", msg);
155 break;
162 /****************************************************************
164 * J z i p A d d
166 * Adds a new file into a ZIP file. The ZIP file must have already
167 * been opened with JzipOpen.
170 JzipAdd(char *fullname, char *filename, ZIPfile *zipfile, int compression_level)
172 ZIPentry * entry;
173 PRFileDesc * readfp;
174 PRFileDesc * zipfp;
175 unsigned long crc;
176 unsigned long local_size_pos;
177 int num;
178 int err;
179 int deflate_percent;
180 z_stream zstream;
181 Bytef inbuf[BUFSIZ];
182 Bytef outbuf[BUFSIZ];
185 if ( !fullname || !filename || !zipfile) {
186 return - 1;
189 zipfp = zipfile->fp;
190 if (!zipfp)
191 return - 1;
194 if ( (readfp = PR_Open(fullname, PR_RDONLY, 0777)) == NULL) {
195 char *nsprErr;
196 if (PR_GetErrorTextLength()) {
197 nsprErr = PR_Malloc(PR_GetErrorTextLength());
198 PR_GetErrorText(nsprErr);
199 } else {
200 nsprErr = NULL;
202 PR_fprintf(errorFD, "%s: %s\n", fullname, nsprErr ? nsprErr :
203 "");
204 errorCount++;
205 if (nsprErr)
206 PR_Free(nsprErr);
207 exit(ERRX);
211 * Make sure the input file is not the output file.
212 * Add a few bytes to the end of the JAR file and see if the input file
213 * twitches
216 PRInt32 endOfJar;
217 PRInt32 inputSize;
218 PRBool isSame;
220 inputSize = PR_Available(readfp);
222 endOfJar = PR_Seek(zipfp, 0L, PR_SEEK_CUR);
224 if (PR_Write(zipfp, "abcde", 5) < 5) {
225 char *nsprErr;
227 if (PR_GetErrorTextLength()) {
228 nsprErr = PR_Malloc(PR_GetErrorTextLength());
229 PR_GetErrorText(nsprErr);
230 } else {
231 nsprErr = NULL;
233 PR_fprintf(errorFD, "Writing to zip file: %s\n",
234 nsprErr ? nsprErr : "");
235 if (nsprErr)
236 PR_Free(nsprErr);
237 errorCount++;
238 exit(ERRX);
241 isSame = (PR_Available(readfp) != inputSize);
243 PR_Seek(zipfp, endOfJar, PR_SEEK_SET);
245 if (isSame) {
246 /* It's the same file! Forget it! */
247 PR_Close(readfp);
248 return 0;
252 if (verbosity >= 0) {
253 PR_fprintf(outputFD, "adding %s to %s...", fullname, zipfile->filename);
256 entry = PORT_ZAlloc(sizeof(ZIPentry));
257 if (!entry)
258 out_of_memory();
260 entry->filename = PORT_Strdup(filename);
261 entry->comment = NULL;
263 /* Set up local file header */
264 longtox(LSIG, entry->local.signature);
265 inttox(strlen(filename), entry->local.filename_len);
266 inttox(zipfile->time, entry->local.time);
267 inttox(zipfile->date, entry->local.date);
268 inttox(Z_DEFLATED, entry->local.method);
270 /* Set up central directory entry */
271 longtox(CSIG, entry->central.signature);
272 inttox(strlen(filename), entry->central.filename_len);
273 if (entry->comment) {
274 inttox(strlen(entry->comment), entry->central.commentfield_len);
276 longtox(PR_Seek(zipfile->fp, 0, PR_SEEK_CUR),
277 entry->central.localhdr_offset);
278 inttox(zipfile->time, entry->central.time);
279 inttox(zipfile->date, entry->central.date);
280 inttox(Z_DEFLATED, entry->central.method);
282 /* Compute crc. Too bad we have to process the whole file to do this*/
283 crc = crc32(0L, NULL, 0);
284 while ( (num = PR_Read(readfp, inbuf, BUFSIZ)) > 0) {
285 crc = crc32(crc, inbuf, num);
287 PR_Seek(readfp, 0L, PR_SEEK_SET);
289 /* Store CRC */
290 longtox(crc, entry->local.crc32);
291 longtox(crc, entry->central.crc32);
293 /* Stick this entry onto the end of the list */
294 entry->next = NULL;
295 if ( zipfile->list == NULL ) {
296 /* First entry */
297 zipfile->list = entry;
298 } else {
299 ZIPentry * pe;
301 pe = zipfile->list;
302 while (pe->next != NULL) {
303 pe = pe->next;
305 pe->next = entry;
309 * Start writing stuff out
312 local_size_pos = PR_Seek(zipfp, 0, PR_SEEK_CUR) + 18;
313 /* File header */
314 if (PR_Write(zipfp, &entry->local, sizeof(struct ZipLocal ))
315 < sizeof(struct ZipLocal )) {
316 char *nsprErr;
317 if (PR_GetErrorTextLength()) {
318 nsprErr = PR_Malloc(PR_GetErrorTextLength());
319 PR_GetErrorText(nsprErr);
320 } else {
321 nsprErr = NULL;
323 PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr :
324 "");
325 if (nsprErr)
326 PR_Free(nsprErr);
327 errorCount++;
328 exit(ERRX);
331 /* File Name */
332 if ( PR_Write(zipfp, filename, strlen(filename)) < strlen(filename)) {
333 char *nsprErr;
334 if (PR_GetErrorTextLength()) {
335 nsprErr = PR_Malloc(PR_GetErrorTextLength());
336 PR_GetErrorText(nsprErr);
337 } else {
338 nsprErr = NULL;
340 PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr :
341 "");
342 if (nsprErr)
343 PR_Free(nsprErr);
344 errorCount++;
345 exit(ERRX);
349 * File data
351 /* Initialize zstream */
352 zstream.zalloc = my_alloc_func;
353 zstream.zfree = my_free_func;
354 zstream.opaque = NULL;
355 zstream.next_in = inbuf;
356 zstream.avail_in = BUFSIZ;
357 zstream.next_out = outbuf;
358 zstream.avail_out = BUFSIZ;
359 /* Setting the windowBits to -MAX_WBITS is an undocumented feature of
360 * zlib (see deflate.c in zlib). It is the same thing that Java does
361 * when you specify the nowrap option for deflation in java.util.zip.
362 * It causes zlib to leave out its headers and footers, which don't
363 * work in PKZIP files.
365 err = deflateInit2(&zstream, compression_level, Z_DEFLATED,
366 -MAX_WBITS, 8 /*default*/, Z_DEFAULT_STRATEGY);
367 if (err != Z_OK) {
368 handle_zerror(err, zstream.msg);
369 exit(ERRX);
372 while ( (zstream.avail_in = PR_Read(readfp, inbuf, BUFSIZ)) > 0) {
373 zstream.next_in = inbuf;
374 /* Process this chunk of data */
375 while (zstream.avail_in > 0) {
376 err = deflate(&zstream, Z_NO_FLUSH);
377 if (err != Z_OK) {
378 handle_zerror(err, zstream.msg);
379 exit(ERRX);
381 if (zstream.avail_out <= 0) {
382 if ( PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) {
383 char *nsprErr;
384 if (PR_GetErrorTextLength()) {
385 nsprErr = PR_Malloc(PR_GetErrorTextLength());
386 PR_GetErrorText(nsprErr);
387 } else {
388 nsprErr = NULL;
390 PR_fprintf(errorFD, "Writing zip data: %s\n",
391 nsprErr ? nsprErr : "");
392 if (nsprErr)
393 PR_Free(nsprErr);
394 errorCount++;
395 exit(ERRX);
397 zstream.next_out = outbuf;
398 zstream.avail_out = BUFSIZ;
403 /* Now flush everything */
404 while (1) {
405 err = deflate(&zstream, Z_FINISH);
406 if (err == Z_STREAM_END) {
407 break;
408 } else if (err == Z_OK) {
409 /* output buffer full, repeat */
410 } else {
411 handle_zerror(err, zstream.msg);
412 exit(ERRX);
414 if ( PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) {
415 char *nsprErr;
416 if (PR_GetErrorTextLength()) {
417 nsprErr = PR_Malloc(PR_GetErrorTextLength());
418 PR_GetErrorText(nsprErr);
419 } else {
420 nsprErr = NULL;
422 PR_fprintf(errorFD, "Writing zip data: %s\n",
423 nsprErr ? nsprErr : "");
424 if (nsprErr)
425 PR_Free(nsprErr);
426 errorCount++;
427 exit(ERRX);
429 zstream.avail_out = BUFSIZ;
430 zstream.next_out = outbuf;
433 /* If there's any output left, write it out. */
434 if (zstream.next_out != outbuf) {
435 if ( PR_Write(zipfp, outbuf, zstream.next_out - outbuf) <
436 zstream.next_out - outbuf) {
437 char *nsprErr;
438 if (PR_GetErrorTextLength()) {
439 nsprErr = PR_Malloc(PR_GetErrorTextLength());
440 PR_GetErrorText(nsprErr);
441 } else {
442 nsprErr = NULL;
444 PR_fprintf(errorFD, "Writing zip data: %s\n",
445 nsprErr ? nsprErr : "");
446 if (nsprErr)
447 PR_Free(nsprErr);
448 errorCount++;
449 exit(ERRX);
451 zstream.avail_out = BUFSIZ;
452 zstream.next_out = outbuf;
455 /* Now that we know the compressed size, write this to the headers */
456 longtox(zstream.total_in, entry->local.orglen);
457 longtox(zstream.total_out, entry->local.size);
458 if (PR_Seek(zipfp, local_size_pos, PR_SEEK_SET) == -1) {
459 char *nsprErr;
460 if (PR_GetErrorTextLength()) {
461 nsprErr = PR_Malloc(PR_GetErrorTextLength());
462 PR_GetErrorText(nsprErr);
463 } else {
464 nsprErr = NULL;
466 PR_fprintf(errorFD, "Accessing zip file: %s\n", nsprErr ? nsprErr : "");
467 if (nsprErr)
468 PR_Free(nsprErr);
469 errorCount++;
470 exit(ERRX);
472 if ( PR_Write(zipfp, entry->local.size, 8) != 8) {
473 char *nsprErr;
474 if (PR_GetErrorTextLength()) {
475 nsprErr = PR_Malloc(PR_GetErrorTextLength());
476 PR_GetErrorText(nsprErr);
477 } else {
478 nsprErr = NULL;
480 PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : "");
481 if (nsprErr)
482 PR_Free(nsprErr);
483 errorCount++;
484 exit(ERRX);
486 if (PR_Seek(zipfp, 0L, PR_SEEK_END) == -1) {
487 char *nsprErr;
488 if (PR_GetErrorTextLength()) {
489 nsprErr = PR_Malloc(PR_GetErrorTextLength());
490 PR_GetErrorText(nsprErr);
491 } else {
492 nsprErr = NULL;
494 PR_fprintf(errorFD, "Accessing zip file: %s\n",
495 nsprErr ? nsprErr : "");
496 if (nsprErr)
497 PR_Free(nsprErr);
498 errorCount++;
499 exit(ERRX);
501 longtox(zstream.total_in, entry->central.orglen);
502 longtox(zstream.total_out, entry->central.size);
504 /* Close out the deflation operation */
505 err = deflateEnd(&zstream);
506 if (err != Z_OK) {
507 handle_zerror(err, zstream.msg);
508 exit(ERRX);
511 PR_Close(readfp);
513 if ((zstream.total_in > zstream.total_out) && (zstream.total_in > 0)) {
514 deflate_percent = (int)
515 ((zstream.total_in - zstream.total_out) *100 / zstream.total_in);
516 } else {
517 deflate_percent = 0;
519 if (verbosity >= 0) {
520 PR_fprintf(outputFD, "(deflated %d%%)\n", deflate_percent);
523 return 0;
527 /********************************************************************
528 * J z i p C l o s e
530 * Finishes the ZipFile. ALSO DELETES THE ZIPFILE STRUCTURE PASSED IN!!
533 JzipClose(ZIPfile *zipfile)
535 ZIPentry * pe, *dead;
536 PRFileDesc * zipfp;
537 struct ZipEnd zipend;
538 unsigned int entrycount = 0;
540 if (!zipfile) {
541 return - 1;
544 if (!zipfile->filename) {
545 /* bogus */
546 return 0;
549 zipfp = zipfile->fp;
550 zipfile->central_start = PR_Seek(zipfp, 0L, PR_SEEK_CUR);
552 /* Write out all the central directories */
553 pe = zipfile->list;
554 while (pe) {
555 entrycount++;
557 /* Write central directory info */
558 if ( PR_Write(zipfp, &pe->central, sizeof(struct ZipCentral ))
559 < sizeof(struct ZipCentral )) {
560 char *nsprErr;
561 if (PR_GetErrorTextLength()) {
562 nsprErr = PR_Malloc(PR_GetErrorTextLength());
563 PR_GetErrorText(nsprErr);
564 } else {
565 nsprErr = NULL;
567 PR_fprintf(errorFD, "Writing zip data: %s\n",
568 nsprErr ? nsprErr : "");
569 if (nsprErr)
570 PR_Free(nsprErr);
571 errorCount++;
572 exit(ERRX);
575 /* Write filename */
576 if ( PR_Write(zipfp, pe->filename, strlen(pe->filename))
577 < strlen(pe->filename)) {
578 char *nsprErr;
579 if (PR_GetErrorTextLength()) {
580 nsprErr = PR_Malloc(PR_GetErrorTextLength());
581 PR_GetErrorText(nsprErr);
582 } else {
583 nsprErr = NULL;
585 PR_fprintf(errorFD, "Writing zip data: %s\n",
586 nsprErr ? nsprErr : "");
587 if (nsprErr)
588 PR_Free(nsprErr);
589 errorCount++;
590 exit(ERRX);
593 /* Write file comment */
594 if (pe->comment) {
595 if ( PR_Write(zipfp, pe->comment, strlen(pe->comment))
596 < strlen(pe->comment)) {
597 char *nsprErr;
598 if (PR_GetErrorTextLength()) {
599 nsprErr = PR_Malloc(PR_GetErrorTextLength());
600 PR_GetErrorText(nsprErr);
601 } else {
602 nsprErr = NULL;
604 PR_fprintf(errorFD, "Writing zip data: %s\n",
605 nsprErr ? nsprErr : "");
606 if (nsprErr)
607 PR_Free(nsprErr);
608 errorCount++;
609 exit(ERRX);
613 /* Delete the structure */
614 dead = pe;
615 pe = pe->next;
616 if (dead->filename) {
617 PORT_Free(dead->filename);
619 if (dead->comment) {
620 PORT_Free(dead->comment);
622 PORT_Free(dead);
624 zipfile->central_end = PR_Seek(zipfile->fp, 0L, PR_SEEK_CUR);
626 /* Create the ZipEnd structure */
627 PORT_Memset(&zipend, 0, sizeof(zipend));
628 longtox(ESIG, zipend.signature);
629 inttox(entrycount, zipend.total_entries_disk);
630 inttox(entrycount, zipend.total_entries_archive);
631 longtox(zipfile->central_end - zipfile->central_start,
632 zipend.central_dir_size);
633 longtox(zipfile->central_start, zipend.offset_central_dir);
634 if (zipfile->comment) {
635 inttox(strlen(zipfile->comment), zipend.commentfield_len);
638 /* Write out ZipEnd xtructure */
639 if ( PR_Write(zipfp, &zipend, sizeof(zipend)) < sizeof(zipend)) {
640 char *nsprErr;
641 if (PR_GetErrorTextLength()) {
642 nsprErr = PR_Malloc(PR_GetErrorTextLength());
643 PR_GetErrorText(nsprErr);
644 } else {
645 nsprErr = NULL;
647 PR_fprintf(errorFD, "Writing zip data: %s\n",
648 nsprErr ? nsprErr : "");
649 if (nsprErr)
650 PR_Free(nsprErr);
651 errorCount++;
652 exit(ERRX);
655 /* Write out Zipfile comment */
656 if (zipfile->comment) {
657 if ( PR_Write(zipfp, zipfile->comment, strlen(zipfile->comment))
658 < strlen(zipfile->comment)) {
659 char *nsprErr;
660 if (PR_GetErrorTextLength()) {
661 nsprErr = PR_Malloc(PR_GetErrorTextLength());
662 PR_GetErrorText(nsprErr);
663 } else {
664 nsprErr = NULL;
666 PR_fprintf(errorFD, "Writing zip data: %s\n",
667 nsprErr ? nsprErr : "");
668 if (nsprErr)
669 PR_Free(nsprErr);
670 errorCount++;
671 exit(ERRX);
675 PR_Close(zipfp);
677 /* Free the memory of the zipfile structure */
678 if (zipfile->filename) {
679 PORT_Free(zipfile->filename);
681 if (zipfile->comment) {
682 PORT_Free(zipfile->comment);
684 PORT_Free(zipfile);
686 return 0;
690 /**********************************************
691 * i n t t o x
693 * Converts a two byte ugly endianed integer
694 * to our platform's integer.
698 static void inttox (int in, char *out)
700 out [0] = (in & 0xFF);
701 out [1] = (in & 0xFF00) >> 8;
705 /*********************************************
706 * l o n g t o x
708 * Converts a four byte ugly endianed integer
709 * to our platform's integer.
713 static void longtox (long in, char *out)
715 out [0] = (in & 0xFF);
716 out [1] = (in & 0xFF00) >> 8;
717 out [2] = (in & 0xFF0000) >> 16;
718 out [3] = (in & 0xFF000000) >> 24;