zip.c (19819B)
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 #include "signtool.h" 6 #include "zip.h" 7 #include "zlib.h" 8 #include "prmem.h" 9 10 static void inttox(int in, char *out); 11 static void longtox(long in, char *out); 12 13 /**************************************************************** 14 * 15 * J z i p O p e n 16 * 17 * Opens a new ZIP file and creates a new ZIPfile structure to 18 * control the process of installing files into a zip. 19 */ 20 ZIPfile * 21 JzipOpen(char *filename, char *comment) 22 { 23 ZIPfile *zipfile; 24 PRExplodedTime prtime; 25 26 zipfile = PORT_ZAlloc(sizeof(ZIPfile)); 27 if (!zipfile) 28 out_of_memory(); 29 30 /* Construct time and date */ 31 PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime); 32 zipfile->date = ((prtime.tm_year - 1980) << 9) | 33 ((prtime.tm_month + 1) << 5) | 34 prtime.tm_mday; 35 zipfile->time = (prtime.tm_hour << 11) | 36 (prtime.tm_min << 5) | 37 (prtime.tm_sec & 0x3f); 38 39 zipfile->fp = NULL; 40 if (filename && 41 (zipfile->fp = PR_Open(filename, 42 PR_WRONLY | 43 PR_CREATE_FILE | 44 PR_TRUNCATE, 45 0777)) == NULL) { 46 char *nsprErr; 47 if (PR_GetErrorTextLength()) { 48 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 49 PR_GetErrorText(nsprErr); 50 } else { 51 nsprErr = NULL; 52 } 53 PR_fprintf(errorFD, "%s: can't open output jar, %s.%s\n", 54 PROGRAM_NAME, 55 filename, nsprErr ? nsprErr : ""); 56 if (nsprErr) 57 PR_Free(nsprErr); 58 errorCount++; 59 exit(ERRX); 60 } 61 62 zipfile->list = NULL; 63 if (filename) { 64 zipfile->filename = PORT_ZAlloc(strlen(filename) + 1); 65 if (!zipfile->filename) 66 out_of_memory(); 67 PORT_Strcpy(zipfile->filename, filename); 68 } 69 if (comment) { 70 zipfile->comment = PORT_ZAlloc(strlen(comment) + 1); 71 if (!zipfile->comment) 72 out_of_memory(); 73 PORT_Strcpy(zipfile->comment, comment); 74 } 75 76 return zipfile; 77 } 78 79 static void * 80 my_alloc_func(void *opaque, uInt items, uInt size) 81 { 82 return PORT_Alloc(items * size); 83 } 84 85 static void 86 my_free_func(void *opaque, void *address) 87 { 88 PORT_Free(address); 89 } 90 91 static void 92 handle_zerror(int err, char *msg) 93 { 94 if (!msg) { 95 msg = ""; 96 } 97 98 errorCount++; /* unless Z_OK...see below */ 99 100 switch (err) { 101 case Z_OK: 102 PR_fprintf(errorFD, "No error: %s\n", msg); 103 errorCount--; /* this was incremented above */ 104 break; 105 case Z_MEM_ERROR: 106 PR_fprintf(errorFD, "Deflation ran out of memory: %s\n", msg); 107 break; 108 case Z_STREAM_ERROR: 109 PR_fprintf(errorFD, "Invalid compression level: %s\n", msg); 110 break; 111 case Z_VERSION_ERROR: 112 PR_fprintf(errorFD, "Incompatible compression library version: %s\n", 113 msg); 114 break; 115 case Z_DATA_ERROR: 116 PR_fprintf(errorFD, "Compression data error: %s\n", msg); 117 break; 118 default: 119 PR_fprintf(errorFD, "Unknown error in compression library: %s\n", msg); 120 break; 121 } 122 } 123 124 /**************************************************************** 125 * 126 * J z i p A d d 127 * 128 * Adds a new file into a ZIP file. The ZIP file must have already 129 * been opened with JzipOpen. 130 */ 131 int 132 JzipAdd(char *fullname, char *filename, ZIPfile *zipfile, int lvl) 133 { 134 ZIPentry *entry; 135 PRFileDesc *readfp; 136 PRFileDesc *zipfp; 137 unsigned long crc; 138 unsigned long local_size_pos; 139 int num; 140 int err; 141 int deflate_percent; 142 z_stream zstream; 143 Bytef inbuf[BUFSIZ]; 144 Bytef outbuf[BUFSIZ]; 145 146 if (!fullname || !filename || !zipfile) { 147 return -1; 148 } 149 150 zipfp = zipfile->fp; 151 if (!zipfp) 152 return -1; 153 154 if ((readfp = PR_Open(fullname, PR_RDONLY, 0777)) == NULL) { 155 char *nsprErr; 156 if (PR_GetErrorTextLength()) { 157 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 158 PR_GetErrorText(nsprErr); 159 } else { 160 nsprErr = NULL; 161 } 162 PR_fprintf(errorFD, "%s: %s\n", fullname, nsprErr ? nsprErr : ""); 163 errorCount++; 164 if (nsprErr) 165 PR_Free(nsprErr); 166 exit(ERRX); 167 } 168 169 /* 170 * Make sure the input file is not the output file. 171 * Add a few bytes to the end of the JAR file and see if the input file 172 * twitches 173 */ 174 { 175 PRInt32 endOfJar; 176 PRInt32 inputSize; 177 PRBool isSame; 178 179 inputSize = PR_Available(readfp); 180 181 endOfJar = PR_Seek(zipfp, 0L, PR_SEEK_CUR); 182 183 if (PR_Write(zipfp, "abcde", 5) < 5) { 184 char *nsprErr; 185 186 if (PR_GetErrorTextLength()) { 187 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 188 PR_GetErrorText(nsprErr); 189 } else { 190 nsprErr = NULL; 191 } 192 PR_fprintf(errorFD, "Writing to zip file: %s\n", 193 nsprErr ? nsprErr : ""); 194 if (nsprErr) 195 PR_Free(nsprErr); 196 errorCount++; 197 exit(ERRX); 198 } 199 200 isSame = (PR_Available(readfp) != inputSize); 201 202 PR_Seek(zipfp, endOfJar, PR_SEEK_SET); 203 204 if (isSame) { 205 /* It's the same file! Forget it! */ 206 PR_Close(readfp); 207 return 0; 208 } 209 } 210 211 if (verbosity >= 0) { 212 PR_fprintf(outputFD, "adding %s to %s...", fullname, zipfile->filename); 213 } 214 215 entry = PORT_ZAlloc(sizeof(ZIPentry)); 216 if (!entry) 217 out_of_memory(); 218 219 entry->filename = PORT_Strdup(filename); 220 entry->comment = NULL; 221 222 /* Set up local file header */ 223 longtox(LSIG, entry->local.signature); 224 inttox(strlen(filename), entry->local.filename_len); 225 inttox(zipfile->time, entry->local.time); 226 inttox(zipfile->date, entry->local.date); 227 inttox(Z_DEFLATED, entry->local.method); 228 229 /* Set up central directory entry */ 230 longtox(CSIG, entry->central.signature); 231 inttox(strlen(filename), entry->central.filename_len); 232 if (entry->comment) { 233 inttox(strlen(entry->comment), entry->central.commentfield_len); 234 } 235 longtox(PR_Seek(zipfile->fp, 0, PR_SEEK_CUR), 236 entry->central.localhdr_offset); 237 inttox(zipfile->time, entry->central.time); 238 inttox(zipfile->date, entry->central.date); 239 inttox(Z_DEFLATED, entry->central.method); 240 241 /* Compute crc. Too bad we have to process the whole file to do this*/ 242 crc = crc32(0L, NULL, 0); 243 while ((num = PR_Read(readfp, inbuf, BUFSIZ)) > 0) { 244 crc = crc32(crc, inbuf, num); 245 } 246 PR_Seek(readfp, 0L, PR_SEEK_SET); 247 248 /* Store CRC */ 249 longtox(crc, entry->local.crc32); 250 longtox(crc, entry->central.crc32); 251 252 /* Stick this entry onto the end of the list */ 253 entry->next = NULL; 254 if (zipfile->list == NULL) { 255 /* First entry */ 256 zipfile->list = entry; 257 } else { 258 ZIPentry *pe; 259 260 pe = zipfile->list; 261 while (pe->next != NULL) { 262 pe = pe->next; 263 } 264 pe->next = entry; 265 } 266 267 /* 268 * Start writing stuff out 269 */ 270 271 local_size_pos = PR_Seek(zipfp, 0, PR_SEEK_CUR) + 18; 272 /* File header */ 273 if (PR_Write(zipfp, &entry->local, sizeof(struct ZipLocal)) < 274 sizeof(struct ZipLocal)) { 275 char *nsprErr; 276 if (PR_GetErrorTextLength()) { 277 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 278 PR_GetErrorText(nsprErr); 279 } else { 280 nsprErr = NULL; 281 } 282 PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); 283 if (nsprErr) 284 PR_Free(nsprErr); 285 errorCount++; 286 exit(ERRX); 287 } 288 289 /* File Name */ 290 if (PR_Write(zipfp, filename, strlen(filename)) < strlen(filename)) { 291 char *nsprErr; 292 if (PR_GetErrorTextLength()) { 293 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 294 PR_GetErrorText(nsprErr); 295 } else { 296 nsprErr = NULL; 297 } 298 PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); 299 if (nsprErr) 300 PR_Free(nsprErr); 301 errorCount++; 302 exit(ERRX); 303 } 304 305 /* 306 * File data 307 */ 308 /* Initialize zstream */ 309 zstream.zalloc = my_alloc_func; 310 zstream.zfree = my_free_func; 311 zstream.opaque = NULL; 312 zstream.next_in = inbuf; 313 zstream.avail_in = BUFSIZ; 314 zstream.next_out = outbuf; 315 zstream.avail_out = BUFSIZ; 316 /* Setting the windowBits to -MAX_WBITS is an undocumented feature of 317 * zlib (see deflate.c in zlib). It is the same thing that Java does 318 * when you specify the nowrap option for deflation in java.util.zip. 319 * It causes zlib to leave out its headers and footers, which don't 320 * work in PKZIP files. 321 */ 322 err = deflateInit2(&zstream, lvl, Z_DEFLATED, 323 -MAX_WBITS, 8 /*default*/, Z_DEFAULT_STRATEGY); 324 if (err != Z_OK) { 325 handle_zerror(err, zstream.msg); 326 exit(ERRX); 327 } 328 329 while ((zstream.avail_in = PR_Read(readfp, inbuf, BUFSIZ)) > 0) { 330 zstream.next_in = inbuf; 331 /* Process this chunk of data */ 332 while (zstream.avail_in > 0) { 333 err = deflate(&zstream, Z_NO_FLUSH); 334 if (err != Z_OK) { 335 handle_zerror(err, zstream.msg); 336 exit(ERRX); 337 } 338 if (zstream.avail_out <= 0) { 339 if (PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) { 340 char *nsprErr; 341 if (PR_GetErrorTextLength()) { 342 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 343 PR_GetErrorText(nsprErr); 344 } else { 345 nsprErr = NULL; 346 } 347 PR_fprintf(errorFD, "Writing zip data: %s\n", 348 nsprErr ? nsprErr : ""); 349 if (nsprErr) 350 PR_Free(nsprErr); 351 errorCount++; 352 exit(ERRX); 353 } 354 zstream.next_out = outbuf; 355 zstream.avail_out = BUFSIZ; 356 } 357 } 358 } 359 360 /* Now flush everything */ 361 while (1) { 362 err = deflate(&zstream, Z_FINISH); 363 if (err == Z_STREAM_END) { 364 break; 365 } else if (err == Z_OK) { 366 /* output buffer full, repeat */ 367 } else { 368 handle_zerror(err, zstream.msg); 369 exit(ERRX); 370 } 371 if (PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) { 372 char *nsprErr; 373 if (PR_GetErrorTextLength()) { 374 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 375 PR_GetErrorText(nsprErr); 376 } else { 377 nsprErr = NULL; 378 } 379 PR_fprintf(errorFD, "Writing zip data: %s\n", 380 nsprErr ? nsprErr : ""); 381 if (nsprErr) 382 PR_Free(nsprErr); 383 errorCount++; 384 exit(ERRX); 385 } 386 zstream.avail_out = BUFSIZ; 387 zstream.next_out = outbuf; 388 } 389 390 /* If there's any output left, write it out. */ 391 if (zstream.next_out != outbuf) { 392 if (PR_Write(zipfp, outbuf, zstream.next_out - outbuf) < 393 zstream.next_out - outbuf) { 394 char *nsprErr; 395 if (PR_GetErrorTextLength()) { 396 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 397 PR_GetErrorText(nsprErr); 398 } else { 399 nsprErr = NULL; 400 } 401 PR_fprintf(errorFD, "Writing zip data: %s\n", 402 nsprErr ? nsprErr : ""); 403 if (nsprErr) 404 PR_Free(nsprErr); 405 errorCount++; 406 exit(ERRX); 407 } 408 zstream.avail_out = BUFSIZ; 409 zstream.next_out = outbuf; 410 } 411 412 /* Now that we know the compressed size, write this to the headers */ 413 longtox(zstream.total_in, entry->local.orglen); 414 longtox(zstream.total_out, entry->local.size); 415 if (PR_Seek(zipfp, local_size_pos, PR_SEEK_SET) == -1) { 416 char *nsprErr; 417 if (PR_GetErrorTextLength()) { 418 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 419 PR_GetErrorText(nsprErr); 420 } else { 421 nsprErr = NULL; 422 } 423 PR_fprintf(errorFD, "Accessing zip file: %s\n", nsprErr ? nsprErr : ""); 424 if (nsprErr) 425 PR_Free(nsprErr); 426 errorCount++; 427 exit(ERRX); 428 } 429 if (PR_Write(zipfp, entry->local.size, 8) != 8) { 430 char *nsprErr; 431 if (PR_GetErrorTextLength()) { 432 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 433 PR_GetErrorText(nsprErr); 434 } else { 435 nsprErr = NULL; 436 } 437 PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); 438 if (nsprErr) 439 PR_Free(nsprErr); 440 errorCount++; 441 exit(ERRX); 442 } 443 if (PR_Seek(zipfp, 0L, PR_SEEK_END) == -1) { 444 char *nsprErr; 445 if (PR_GetErrorTextLength()) { 446 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 447 PR_GetErrorText(nsprErr); 448 } else { 449 nsprErr = NULL; 450 } 451 PR_fprintf(errorFD, "Accessing zip file: %s\n", 452 nsprErr ? nsprErr : ""); 453 if (nsprErr) 454 PR_Free(nsprErr); 455 errorCount++; 456 exit(ERRX); 457 } 458 longtox(zstream.total_in, entry->central.orglen); 459 longtox(zstream.total_out, entry->central.size); 460 461 /* Close out the deflation operation */ 462 err = deflateEnd(&zstream); 463 if (err != Z_OK) { 464 handle_zerror(err, zstream.msg); 465 exit(ERRX); 466 } 467 468 PR_Close(readfp); 469 470 if ((zstream.total_in > zstream.total_out) && (zstream.total_in > 0)) { 471 deflate_percent = (int)((zstream.total_in - 472 zstream.total_out) * 473 100 / zstream.total_in); 474 } else { 475 deflate_percent = 0; 476 } 477 if (verbosity >= 0) { 478 PR_fprintf(outputFD, "(deflated %d%%)\n", deflate_percent); 479 } 480 481 return 0; 482 } 483 484 /******************************************************************** 485 * J z i p C l o s e 486 * 487 * Finishes the ZipFile. ALSO DELETES THE ZIPFILE STRUCTURE PASSED IN!! 488 */ 489 int 490 JzipClose(ZIPfile *zipfile) 491 { 492 ZIPentry *pe, *dead; 493 PRFileDesc *zipfp; 494 struct ZipEnd zipend; 495 unsigned int entrycount = 0; 496 497 if (!zipfile) { 498 return -1; 499 } 500 501 if (!zipfile->filename) { 502 /* bogus */ 503 return 0; 504 } 505 506 zipfp = zipfile->fp; 507 zipfile->central_start = PR_Seek(zipfp, 0L, PR_SEEK_CUR); 508 509 /* Write out all the central directories */ 510 pe = zipfile->list; 511 while (pe) { 512 entrycount++; 513 514 /* Write central directory info */ 515 if (PR_Write(zipfp, &pe->central, sizeof(struct ZipCentral)) < 516 sizeof(struct ZipCentral)) { 517 char *nsprErr; 518 if (PR_GetErrorTextLength()) { 519 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 520 PR_GetErrorText(nsprErr); 521 } else { 522 nsprErr = NULL; 523 } 524 PR_fprintf(errorFD, "Writing zip data: %s\n", 525 nsprErr ? nsprErr : ""); 526 if (nsprErr) 527 PR_Free(nsprErr); 528 errorCount++; 529 exit(ERRX); 530 } 531 532 /* Write filename */ 533 if (PR_Write(zipfp, pe->filename, strlen(pe->filename)) < 534 strlen(pe->filename)) { 535 char *nsprErr; 536 if (PR_GetErrorTextLength()) { 537 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 538 PR_GetErrorText(nsprErr); 539 } else { 540 nsprErr = NULL; 541 } 542 PR_fprintf(errorFD, "Writing zip data: %s\n", 543 nsprErr ? nsprErr : ""); 544 if (nsprErr) 545 PR_Free(nsprErr); 546 errorCount++; 547 exit(ERRX); 548 } 549 550 /* Write file comment */ 551 if (pe->comment) { 552 if (PR_Write(zipfp, pe->comment, strlen(pe->comment)) < 553 strlen(pe->comment)) { 554 char *nsprErr; 555 if (PR_GetErrorTextLength()) { 556 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 557 PR_GetErrorText(nsprErr); 558 } else { 559 nsprErr = NULL; 560 } 561 PR_fprintf(errorFD, "Writing zip data: %s\n", 562 nsprErr ? nsprErr : ""); 563 if (nsprErr) 564 PR_Free(nsprErr); 565 errorCount++; 566 exit(ERRX); 567 } 568 } 569 570 /* Delete the structure */ 571 dead = pe; 572 pe = pe->next; 573 if (dead->filename) { 574 PORT_Free(dead->filename); 575 } 576 if (dead->comment) { 577 PORT_Free(dead->comment); 578 } 579 PORT_Free(dead); 580 } 581 zipfile->central_end = PR_Seek(zipfile->fp, 0L, PR_SEEK_CUR); 582 583 /* Create the ZipEnd structure */ 584 PORT_Memset(&zipend, 0, sizeof(zipend)); 585 longtox(ESIG, zipend.signature); 586 inttox(entrycount, zipend.total_entries_disk); 587 inttox(entrycount, zipend.total_entries_archive); 588 longtox(zipfile->central_end - zipfile->central_start, 589 zipend.central_dir_size); 590 longtox(zipfile->central_start, zipend.offset_central_dir); 591 if (zipfile->comment) { 592 inttox(strlen(zipfile->comment), zipend.commentfield_len); 593 } 594 595 /* Write out ZipEnd xtructure */ 596 if (PR_Write(zipfp, &zipend, sizeof(zipend)) < sizeof(zipend)) { 597 char *nsprErr; 598 if (PR_GetErrorTextLength()) { 599 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 600 PR_GetErrorText(nsprErr); 601 } else { 602 nsprErr = NULL; 603 } 604 PR_fprintf(errorFD, "Writing zip data: %s\n", 605 nsprErr ? nsprErr : ""); 606 if (nsprErr) 607 PR_Free(nsprErr); 608 errorCount++; 609 exit(ERRX); 610 } 611 612 /* Write out Zipfile comment */ 613 if (zipfile->comment) { 614 if (PR_Write(zipfp, zipfile->comment, strlen(zipfile->comment)) < 615 strlen(zipfile->comment)) { 616 char *nsprErr; 617 if (PR_GetErrorTextLength()) { 618 nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1); 619 PR_GetErrorText(nsprErr); 620 } else { 621 nsprErr = NULL; 622 } 623 PR_fprintf(errorFD, "Writing zip data: %s\n", 624 nsprErr ? nsprErr : ""); 625 if (nsprErr) 626 PR_Free(nsprErr); 627 errorCount++; 628 exit(ERRX); 629 } 630 } 631 632 PR_Close(zipfp); 633 634 /* Free the memory of the zipfile structure */ 635 if (zipfile->filename) { 636 PORT_Free(zipfile->filename); 637 } 638 if (zipfile->comment) { 639 PORT_Free(zipfile->comment); 640 } 641 PORT_Free(zipfile); 642 643 return 0; 644 } 645 646 /********************************************** 647 * i n t t o x 648 * 649 * Converts a two byte ugly endianed integer 650 * to our platform's integer. 651 * 652 */ 653 654 static void 655 inttox(int in, char *out) 656 { 657 out[0] = (in & 0xFF); 658 out[1] = (in & 0xFF00) >> 8; 659 } 660 661 /********************************************* 662 * l o n g t o x 663 * 664 * Converts a four byte ugly endianed integer 665 * to our platform's integer. 666 * 667 */ 668 669 static void 670 longtox(long in, char *out) 671 { 672 out[0] = (in & 0xFF); 673 out[1] = (in & 0xFF00) >> 8; 674 out[2] = (in & 0xFF0000) >> 16; 675 out[3] = (in & 0xFF000000) >> 24; 676 }