|
|
1.1 ! root 1: /*--------------------------------------------------------------------------- ! 2: ! 3: extract.c ! 4: ! 5: This file contains the high-level routines ("driver routines") for extrac- ! 6: ting and testing zipfile members. It calls the low-level routines in files ! 7: explode.c, inflate.c, unreduce.c and unshrink.c. ! 8: ! 9: ---------------------------------------------------------------------------*/ ! 10: ! 11: ! 12: #include "unzip.h" ! 13: #ifdef MSWIN ! 14: # include "wizunzip.h" ! 15: # include "replace.h" ! 16: #endif /* MSWIN */ ! 17: ! 18: ! 19: /************************************/ ! 20: /* Extract Local Prototypes, etc. */ ! 21: /************************************/ ! 22: ! 23: static int store_info __((void)); ! 24: static int extract_or_test_member __((void)); ! 25: #ifdef CRYPT ! 26: static int decrypt_member __((void)); ! 27: static int testp __((byte *hdr)); ! 28: #endif ! 29: ! 30: static byte *mem_i_buffer; ! 31: static byte *mem_o_buffer; ! 32: static ULONG mem_i_size, mem_i_offset; ! 33: static ULONG mem_o_size, mem_o_offset; ! 34: ! 35: static char *VersionMsg = ! 36: " skipping: %-22s need %s compat. v%u.%u (can do v%u.%u)\n"; ! 37: static char *ComprMsg = ! 38: " skipping: %-22s compression method %d\n"; ! 39: static char *FilNamMsg = ! 40: "%s: bad filename length (%s)\n"; ! 41: static char *ExtFieldMsg = ! 42: "%s: bad extra field length (%s)\n"; ! 43: static char *OffsetMsg = ! 44: "file #%d: bad zipfile offset (%s)\n"; ! 45: ! 46: ! 47: ! 48: ! 49: ! 50: /**************************************/ ! 51: /* Function extract_or_test_files() */ ! 52: /**************************************/ ! 53: ! 54: int extract_or_test_files() /* return PK-type error code */ ! 55: { ! 56: char **fnamev; ! 57: byte *cd_inptr; ! 58: int cd_incnt, error, error_in_archive=0; ! 59: int renamed, query, len, filnum=(-1), blknum=0; ! 60: #ifdef OS2 ! 61: extern int longname; /* from os2unzip.c */ ! 62: #endif ! 63: UWORD i, j, members_remaining, num_skipped=0, num_bad_pwd=0; ! 64: longint cd_bufstart, bufstart, inbuf_offset, request; ! 65: min_info info[DIR_BLKSIZ]; ! 66: ! 67: ! 68: /*--------------------------------------------------------------------------- ! 69: The basic idea of this function is as follows. Since the central di- ! 70: rectory lies at the end of the zipfile and the member files lie at the ! 71: beginning or middle or wherever, it is not very desirable to simply ! 72: read a central directory entry, jump to the member and extract it, and ! 73: then jump back to the central directory. In the case of a large zipfile ! 74: this would lead to a whole lot of disk-grinding, especially if each mem- ! 75: ber file is small. Instead, we read from the central directory the per- ! 76: tinent information for a block of files, then go extract/test the whole ! 77: block. Thus this routine contains two small(er) loops within a very ! 78: large outer loop: the first of the small ones reads a block of files ! 79: from the central directory; the second extracts or tests each file; and ! 80: the outer one loops over blocks. There's some file-pointer positioning ! 81: stuff in between, but that's about it. Btw, it's because of this jump- ! 82: ing around that we can afford to be lenient if an error occurs in one of ! 83: the member files: we should still be able to go find the other members, ! 84: since we know the offset of each from the beginning of the zipfile. ! 85: ! 86: Begin main loop over blocks of member files. We know the entire central ! 87: directory is on this disk: we would not have any of this information un- ! 88: less the end-of-central-directory record was on this disk, and we would ! 89: not have gotten to this routine unless this is also the disk on which ! 90: the central directory starts. In practice, this had better be the ONLY ! 91: disk in the archive, but maybe someday we'll add multi-disk support. ! 92: ---------------------------------------------------------------------------*/ ! 93: ! 94: pInfo = info; ! 95: members_remaining = ecrec.total_entries_central_dir; ! 96: ! 97: while (members_remaining) { ! 98: j = 0; ! 99: ! 100: /* ! 101: * Loop through files in central directory, storing offsets, file ! 102: * attributes, and case-conversion flags until block size is reached. ! 103: */ ! 104: ! 105: while (members_remaining && (j < DIR_BLKSIZ)) { ! 106: --members_remaining; ! 107: pInfo = &info[j]; ! 108: ! 109: if (readbuf(sig, 4) <= 0) { ! 110: error_in_archive = 51; /* 51: unexpected EOF */ ! 111: members_remaining = 0; /* ...so no more left to do */ ! 112: break; ! 113: } ! 114: if (strncmp(sig, central_hdr_sig, 4)) { /* just to make sure */ ! 115: fprintf(stderr, CentSigMsg, j); /* sig not found */ ! 116: fprintf(stderr, ReportMsg); /* check binary transfers */ ! 117: error_in_archive = 3; /* 3: error in zipfile */ ! 118: members_remaining = 0; /* ...so no more left to do */ ! 119: break; ! 120: } ! 121: /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */ ! 122: if ((error = process_cdir_file_hdr()) != 0) { ! 123: error_in_archive = error; /* only 51 (EOF) defined */ ! 124: members_remaining = 0; /* ...so no more left to do */ ! 125: break; ! 126: } ! 127: if ((error = do_string(crec.filename_length, FILENAME)) != 0) { ! 128: if (error > error_in_archive) ! 129: error_in_archive = error; ! 130: if (error > 1) { /* fatal: no more left to do */ ! 131: fprintf(stderr, FilNamMsg, filename, "central"); ! 132: members_remaining = 0; ! 133: break; ! 134: } ! 135: } ! 136: if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0) ! 137: { ! 138: if (error > error_in_archive) ! 139: error_in_archive = error; ! 140: if (error > 1) { /* fatal */ ! 141: fprintf(stderr, ExtFieldMsg, filename, "central"); ! 142: members_remaining = 0; ! 143: break; ! 144: } ! 145: } ! 146: if ((error = do_string(crec.file_comment_length, SKIP)) != 0) { ! 147: if (error > error_in_archive) ! 148: error_in_archive = error; ! 149: if (error > 1) { /* fatal */ ! 150: fprintf(stderr, "\n%s: bad file comment length\n", ! 151: filename); ! 152: members_remaining = 0; ! 153: break; ! 154: } ! 155: } ! 156: if (process_all_files) { ! 157: if (store_info()) ! 158: ++num_skipped; ! 159: else ! 160: ++j; /* file is OK: save info[] and continue with next */ ! 161: } else { ! 162: fnamev = fnv; /* don't destroy permanent filename pointer */ ! 163: for (--fnamev; *++fnamev;) ! 164: if (match(filename, *fnamev)) { ! 165: if (store_info()) ! 166: ++num_skipped; ! 167: else ! 168: ++j; /* file is OK */ ! 169: break; /* found match for filename, so stop looping */ ! 170: } /* end if (match), for-loop (fnamev) */ ! 171: } /* end if (process_all_files) */ ! 172: ! 173: } /* end while-loop (adding files to current block) */ ! 174: ! 175: /* save position in central directory so can come back later */ ! 176: cd_bufstart = cur_zipfile_bufstart; ! 177: cd_inptr = inptr; ! 178: cd_incnt = incnt; ! 179: ! 180: /*----------------------------------------------------------------------- ! 181: Second loop: process files in current block, extracting or testing ! 182: each one. ! 183: -----------------------------------------------------------------------*/ ! 184: ! 185: for (i = 0; i < j; ++i) { ! 186: filnum = i + blknum*DIR_BLKSIZ; ! 187: pInfo = &info[i]; ! 188: /* ! 189: * if the target position is not within the current input buffer ! 190: * (either haven't yet read far enough, or (maybe) skipping back- ! 191: * ward) skip to the target position and reset readbuf(). ! 192: */ ! 193: /* LSEEK(pInfo->offset): */ ! 194: request = pInfo->offset + extra_bytes; ! 195: inbuf_offset = request % INBUFSIZ; ! 196: bufstart = request - inbuf_offset; ! 197: ! 198: if (request < 0) { ! 199: fprintf(stderr, SeekMsg, ReportMsg); ! 200: error_in_archive = 3; /* 3: severe error in zipfile, */ ! 201: continue; /* but can still go on */ ! 202: } else if (bufstart != cur_zipfile_bufstart) { ! 203: cur_zipfile_bufstart = lseek(zipfd, bufstart, SEEK_SET); ! 204: if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) <= 0) { ! 205: fprintf(stderr, OffsetMsg, filnum, "lseek"); ! 206: error_in_archive = 3; /* 3: error in zipfile, but */ ! 207: continue; /* can still do next file */ ! 208: } ! 209: inptr = inbuf + (int)inbuf_offset; ! 210: incnt -= (int)inbuf_offset; ! 211: } else { ! 212: incnt += (inptr-inbuf) - (int)inbuf_offset; ! 213: inptr = inbuf + (int)inbuf_offset; ! 214: } ! 215: ! 216: /* should be in proper position now, so check for sig */ ! 217: if (readbuf(sig, 4) <= 0) { /* bad offset */ ! 218: fprintf(stderr, OffsetMsg, filnum, "EOF"); ! 219: error_in_archive = 3; /* 3: error in zipfile */ ! 220: continue; /* but can still try next one */ ! 221: } ! 222: if (strncmp(sig, local_hdr_sig, 4)) { ! 223: fprintf(stderr, OffsetMsg, filnum, ! 224: "can't find local header sig"); /* bad offset */ ! 225: error_in_archive = 3; ! 226: continue; ! 227: } ! 228: if ((error = process_local_file_hdr()) != 0) { ! 229: fprintf(stderr, "\nfile #%d: bad local header\n", filnum); ! 230: error_in_archive = error; /* only 51 (EOF) defined */ ! 231: continue; /* can still try next one */ ! 232: } ! 233: if ((error = do_string(lrec.filename_length, FILENAME)) != 0) { ! 234: if (error > error_in_archive) ! 235: error_in_archive = error; ! 236: if (error > 1) { ! 237: fprintf(stderr, FilNamMsg, filename, "local"); ! 238: continue; /* go on to next one */ ! 239: } ! 240: } ! 241: if (extra_field != (byte *)NULL) ! 242: free(extra_field); ! 243: extra_field = (byte *)NULL; ! 244: if ((error = do_string(lrec.extra_field_length, EXTRA_FIELD)) != 0) ! 245: { ! 246: if (error > error_in_archive) ! 247: error_in_archive = error; ! 248: if (error > 1) { ! 249: fprintf(stderr, ExtFieldMsg, filename, "local"); ! 250: continue; /* go on */ ! 251: } ! 252: } ! 253: ! 254: /* ! 255: * just about to extract file: if extracting to disk, check if ! 256: * already exists, and if so, take appropriate action according to ! 257: * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper ! 258: * loop because we don't store the possibly renamed filename[] in ! 259: * info[]) ! 260: */ ! 261: if (!tflag && !cflag) { ! 262: renamed = FALSE; /* user hasn't renamed output file yet */ ! 263: #ifdef OS2 ! 264: longname = FALSE; /* no long name has yet been stored */ ! 265: #endif ! 266: ! 267: startover: ! 268: query = FALSE; ! 269: #ifdef MACOS ! 270: macflag = (pInfo->hostnum == MAC_); ! 271: #endif ! 272: /* mapname can create dirs if not freshening or if renamed */ ! 273: if ((error = mapname(!fflag || renamed)) > 1) { /* skip */ ! 274: if ((error > 2) && (error_in_archive < 2)) ! 275: error_in_archive = 2; /* (weak) error in zipfile */ ! 276: continue; /* go on to next file */ ! 277: } ! 278: ! 279: switch (check_for_newer(filename)) { ! 280: case DOES_NOT_EXIST: ! 281: if (fflag && !renamed) /* don't skip if just renamed */ ! 282: continue; /* freshen (no new files): skip */ ! 283: break; ! 284: case EXISTS_AND_OLDER: ! 285: if (overwrite_none) ! 286: continue; /* never overwrite: skip file */ ! 287: if (!overwrite_all && !force_flag) ! 288: query = TRUE; ! 289: break; ! 290: case EXISTS_AND_NEWER: /* (or equal) */ ! 291: if (overwrite_none || (uflag && !renamed)) ! 292: continue; /* skip if update/freshen & orig name */ ! 293: if (!overwrite_all && !force_flag) ! 294: query = TRUE; ! 295: break; ! 296: } ! 297: /*#ifndef VMS*/ /* VMS creates higher version number instead of overwriting ! 298: * (will have to modify for VMS-style names with specific ! 299: * version numbers: just check V_flag? don't use stat?) */ ! 300: if (query) { ! 301: #ifdef MSWIN ! 302: FARPROC lpfnprocReplace; ! 303: int ReplaceDlgRetVal; /* replace dialog return value */ ! 304: ! 305: ShowCursor(FALSE); /* turn off cursor */ ! 306: SetCursor(hSaveCursor); /* restore the cursor */ ! 307: lpfnprocReplace = MakeProcInstance(ReplaceProc, hInst); ! 308: ReplaceDlgRetVal = DialogBoxParam(hInst, "Replace", ! 309: hWndMain, lpfnprocReplace, (DWORD)(LPSTR)filename); ! 310: FreeProcInstance(lpfnprocReplace); ! 311: hSaveCursor = SetCursor(hHourGlass); ! 312: ShowCursor(TRUE); ! 313: switch (ReplaceDlgRetVal) { ! 314: case IDM_REPLACE_RENAME: ! 315: renamed = TRUE; ! 316: goto startover; /* sorry for a goto */ ! 317: case IDM_REPLACE_YES: ! 318: break; ! 319: case IDM_REPLACE_ALL: ! 320: overwrite_all = TRUE; ! 321: overwrite_none = FALSE; /* just to make sure */ ! 322: break; ! 323: case IDM_REPLACE_NONE: ! 324: overwrite_none = TRUE; ! 325: overwrite_all = FALSE; /* make sure */ ! 326: force_flag = FALSE; /* ditto */ ! 327: /* FALL THROUGH, skip */ ! 328: case IDM_REPLACE_NO: ! 329: continue; ! 330: } ! 331: #else /* !MSWIN */ ! 332: reprompt: ! 333: fprintf(stderr, ! 334: "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", ! 335: filename); ! 336: FFLUSH /* for Amiga and Mac MPW */ ! 337: fgets(answerbuf, 9, stdin); ! 338: switch (*answerbuf) { ! 339: case 'A': /* dangerous option: force caps */ ! 340: overwrite_all = TRUE; ! 341: overwrite_none = FALSE; /* just to make sure */ ! 342: break; ! 343: case 'r': ! 344: case 'R': ! 345: do { ! 346: fprintf(stderr, "new name: "); ! 347: FFLUSH /* for AMIGA and Mac MPW */ ! 348: fgets(filename, FILNAMSIZ, stdin); ! 349: /* usually get \n here: better check for it */ ! 350: len = strlen(filename); ! 351: if (filename[len-1] == '\n') ! 352: filename[--len] = 0; ! 353: } while (len == 0); ! 354: renamed = TRUE; ! 355: goto startover; /* sorry for a goto */ ! 356: case 'y': ! 357: case 'Y': ! 358: break; ! 359: case 'N': ! 360: overwrite_none = TRUE; ! 361: overwrite_all = FALSE; /* make sure */ ! 362: force_flag = FALSE; /* ditto */ ! 363: /* FALL THROUGH, skip */ ! 364: case 'n': ! 365: continue; /* skip file */ ! 366: default: ! 367: fprintf(stderr, "error: invalid response [%c]\n", ! 368: *answerbuf); /* warn the user */ ! 369: goto reprompt; /* why not another goto? */ ! 370: } /* end switch (*answerbuf) */ ! 371: #endif /* ?MSWIN */ ! 372: } /* end if (query) */ ! 373: /*#endif*/ /* !VMS */ ! 374: } /* end if (extracting to disk) */ ! 375: ! 376: #ifdef CRYPT ! 377: if (pInfo->encrypted && ((error = decrypt_member()) != 0)) { ! 378: if (error == 10) { ! 379: if (error > error_in_archive) ! 380: error_in_archive = error; ! 381: fprintf(stderr, ! 382: " skipping: %-22s unable to get password\n", filename); ! 383: } else { /* (error == 1) */ ! 384: fprintf(stderr, ! 385: " skipping: %-22s incorrect password\n", filename); ! 386: ++num_bad_pwd; ! 387: } ! 388: continue; /* go on to next file */ ! 389: } ! 390: #endif /* CRYPT */ ! 391: disk_full = 0; ! 392: if ((error = extract_or_test_member()) != 0) { ! 393: if (error > error_in_archive) ! 394: error_in_archive = error; /* ...and keep going */ ! 395: if (disk_full > 1) ! 396: return error_in_archive; /* (unless disk full) */ ! 397: } ! 398: } /* end for-loop (i: files in current block) */ ! 399: ! 400: ! 401: /* ! 402: * Jump back to where we were in the central directory, then go and do ! 403: * the next batch of files. ! 404: */ ! 405: ! 406: cur_zipfile_bufstart = lseek(zipfd, cd_bufstart, SEEK_SET); ! 407: read(zipfd, (char *)inbuf, INBUFSIZ); /* were there b4 ==> no error */ ! 408: inptr = cd_inptr; ! 409: incnt = cd_incnt; ! 410: ++blknum; ! 411: ! 412: #ifdef TEST ! 413: printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart); ! 414: printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart, ! 415: cur_zipfile_bufstart); ! 416: printf("inptr-inbuf = %d\n", inptr-inbuf); ! 417: printf("incnt = %d\n\n", incnt); ! 418: #endif ! 419: ! 420: } /* end while-loop (blocks of files in central directory) */ ! 421: ! 422: /*--------------------------------------------------------------------------- ! 423: Double-check that we're back at the end-of-central-directory record, and ! 424: print quick summary of results, if we were just testing the archive. We ! 425: send the summary to stdout so that people doing the testing in the back- ! 426: ground and redirecting to a file can just do a "tail" on the output file. ! 427: ---------------------------------------------------------------------------*/ ! 428: ! 429: readbuf(sig, 4); ! 430: if (strncmp(sig, end_central_sig, 4)) { /* just to make sure again */ ! 431: fprintf(stderr, EndSigMsg); /* didn't find end-of-central-dir sig */ ! 432: fprintf(stderr, ReportMsg); /* check binary transfers */ ! 433: if (!error_in_archive) /* don't overwrite stronger error */ ! 434: error_in_archive = 1; /* 1: warning error */ ! 435: } ! 436: if (tflag && (quietflg == 1)) { ! 437: int num=filnum+1 - num_bad_pwd; ! 438: ! 439: if (error_in_archive) ! 440: printf("At least one error was detected in %s.\n", zipfn); ! 441: else if (num == 0) ! 442: printf("Caution: zero files tested in %s.\n", zipfn); ! 443: else if (process_all_files && (num_skipped+num_bad_pwd == 0)) ! 444: printf("No errors detected in %s.\n", zipfn); ! 445: else ! 446: printf("No errors detected in %s for the %d file%s tested.\n", ! 447: zipfn, num, (num==1)? "":"s"); ! 448: if (num_skipped > 0) ! 449: printf("%d file%s skipped because of unsupported compression or\ ! 450: encoding.\n", ! 451: num_skipped, (num_skipped==1)? "":"s"); ! 452: #ifdef CRYPT ! 453: if (num_bad_pwd > 0) ! 454: printf("%d file%s skipped because of incorrect password.\n", ! 455: num_bad_pwd, (num_bad_pwd==1)? "":"s"); ! 456: #endif /* CRYPT */ ! 457: } ! 458: if ((num_skipped > 0) && !error_in_archive) /* files not tested or */ ! 459: error_in_archive = 1; /* extracted: warning */ ! 460: #ifdef CRYPT ! 461: if ((num_bad_pwd > 0) && !error_in_archive) /* files not tested or */ ! 462: error_in_archive = 1; /* extracted: warning */ ! 463: #endif /* CRYPT */ ! 464: ! 465: return (error_in_archive); ! 466: ! 467: } /* end function extract_or_test_files() */ ! 468: ! 469: ! 470: ! 471: ! 472: ! 473: /***************************/ ! 474: /* Function store_info() */ ! 475: /***************************/ ! 476: ! 477: static int store_info() /* return 1 if skipping, 0 if OK */ ! 478: { ! 479: ULONG tmp; ! 480: ! 481: #define UNKN_COMPR \ ! 482: (crec.compression_method>IMPLODED && crec.compression_method!=DEFLATED) ! 483: #if 0 /* old */ ! 484: # define UNKN_COMPR (crec.compression_method>IMPLODED) ! 485: #endif ! 486: ! 487: ! 488: /*--------------------------------------------------------------------------- ! 489: Check central directory info for version/compatibility requirements. ! 490: ---------------------------------------------------------------------------*/ ! 491: ! 492: pInfo->encrypted = crec.general_purpose_bit_flag & 1; /* bit field */ ! 493: pInfo->ExtLocHdr = (crec.general_purpose_bit_flag & 8) == 8; /* bit */ ! 494: pInfo->text = crec.internal_file_attributes & 1; /* bit field */ ! 495: pInfo->crc = crec.crc32; ! 496: pInfo->compr_size = crec.compressed_size; ! 497: ! 498: if (crec.version_needed_to_extract[1] == VMS_) { ! 499: if (crec.version_needed_to_extract[0] > VMS_VERSION) { ! 500: fprintf(stderr, VersionMsg, filename, "VMS", ! 501: crec.version_needed_to_extract[0] / 10, ! 502: crec.version_needed_to_extract[0] % 10, ! 503: VMS_VERSION / 10, VMS_VERSION % 10); ! 504: return 1; ! 505: } ! 506: #ifndef VMS /* won't be able to use extra field, but still have data */ ! 507: else if (!tflag && !force_flag) { /* if forcing, extract regardless */ ! 508: fprintf(stderr, ! 509: "\n%s: stored in VMS format. Extract anyway? (y/n) ", ! 510: filename); ! 511: FFLUSH /* for Amiga and Mac MPW */ ! 512: fgets(answerbuf, 9, stdin); ! 513: if ((*answerbuf != 'y') && (*answerbuf != 'Y')) ! 514: return 1; ! 515: } ! 516: #endif /* !VMS */ ! 517: /* usual file type: don't need VMS to extract */ ! 518: } else if (crec.version_needed_to_extract[0] > UNZIP_VERSION) { ! 519: fprintf(stderr, VersionMsg, filename, "PK", ! 520: crec.version_needed_to_extract[0] / 10, ! 521: crec.version_needed_to_extract[0] % 10, ! 522: UNZIP_VERSION / 10, UNZIP_VERSION % 10); ! 523: return 1; ! 524: } ! 525: ! 526: if UNKN_COMPR { ! 527: fprintf(stderr, ComprMsg, filename, crec.compression_method); ! 528: return 1; ! 529: } ! 530: #ifndef CRYPT ! 531: if (pInfo->encrypted) { ! 532: fprintf(stderr, " skipping: %-22s encrypted (not supported)\n", ! 533: filename); ! 534: return 1; ! 535: } ! 536: #endif /* !CRYPT */ ! 537: ! 538: /*--------------------------------------------------------------------------- ! 539: Store some central-directory information (encryption, file attributes, ! 540: offsets) for later use. ! 541: ---------------------------------------------------------------------------*/ ! 542: ! 543: tmp = crec.external_file_attributes; ! 544: ! 545: pInfo->dos_attr = 32; /* set archive bit: file is not backed up */ ! 546: switch (pInfo->hostnum) { ! 547: case UNIX_: ! 548: case VMS_: ! 549: pInfo->unix_attr = (unsigned) (tmp >> 16); ! 550: break; ! 551: case DOS_OS2_FAT_: ! 552: case OS2_HPFS_: ! 553: pInfo->dos_attr = (unsigned) tmp; ! 554: tmp = (!(tmp & 1)) << 1; /* read-only bit */ ! 555: pInfo->unix_attr = (unsigned) (0444 | (tmp<<6) | (tmp<<3) | tmp); ! 556: #ifdef UNIX ! 557: umask( (int)(tmp=umask(0)) ); ! 558: pInfo->unix_attr &= ~tmp; ! 559: #endif ! 560: break; ! 561: case MAC_: ! 562: pInfo->unix_attr = (unsigned) (tmp & 1); /* read-only bit */ ! 563: break; ! 564: default: ! 565: pInfo->unix_attr = 0666; ! 566: break; ! 567: } /* end switch (host-OS-created-by) */ ! 568: ! 569: pInfo->offset = (longint) crec.relative_offset_local_header; ! 570: return 0; ! 571: ! 572: } /* end function store_info() */ ! 573: ! 574: ! 575: ! 576: ! 577: ! 578: /***************************************/ ! 579: /* Function extract_or_test_member() */ ! 580: /***************************************/ ! 581: ! 582: static int extract_or_test_member() /* return PK-type error code */ ! 583: { ! 584: #ifdef S_IFLNK ! 585: int symlnk=FALSE; ! 586: #endif /* S_IFLNK */ ! 587: int r, error=0; ! 588: UWORD b; ! 589: ! 590: ! 591: ! 592: /*--------------------------------------------------------------------------- ! 593: Initialize variables, buffers, etc. ! 594: ---------------------------------------------------------------------------*/ ! 595: ! 596: bits_left = 0; ! 597: bitbuf = 0L; ! 598: outpos = 0L; ! 599: outcnt = 0; ! 600: outptr = outbuf; ! 601: zipeof = 0; ! 602: crc32val = 0xFFFFFFFFL; ! 603: ! 604: #ifdef S_IFLNK ! 605: if ((pInfo->unix_attr & S_IFMT) == S_IFLNK && (pInfo->hostnum == UNIX_) ! 606: && !tflag && !cflag) ! 607: symlnk = TRUE; ! 608: #endif /* S_IFLNK */ ! 609: ! 610: memset(outbuf, 0xaa, OUTBUFSIZ); ! 611: #if (!defined(DOS_OS2) || defined(MSWIN)) ! 612: if (aflag) /* if we have a scratchpad, clear it out */ ! 613: #ifdef MSWIN ! 614: _fmemset(outout, 0xaa, OUTBUFSIZ); ! 615: #else /* !MSWIN */ ! 616: memset(outout, 0xaa, OUTBUFSIZ); ! 617: #endif /* ?MSWIN */ ! 618: #endif /* !DOS_OS2 || MSWIN */ ! 619: ! 620: if (tflag) { ! 621: if (!quietflg) { ! 622: fprintf(stdout, " Testing: %-22s ", filename); ! 623: fflush(stdout); ! 624: } ! 625: } else { ! 626: if (cflag) { /* output to stdout (copy of it) */ ! 627: #if (defined(MACOS) || defined(AMIGA)) ! 628: outfd = 1; ! 629: #else /* !(MACOS || AMIGA) */ ! 630: outfd = dup(1); /* GRR: change this to #define for Mac/Amiga */ ! 631: #endif /* ?(MACOS || AMIGA) */ ! 632: #ifdef DOS_OS2 ! 633: if (!aflag) ! 634: setmode(outfd, O_BINARY); ! 635: #endif /* DOS_OS2 */ ! 636: #ifdef VMS ! 637: if (create_output_file()) /* VMS version required for stdout! */ ! 638: return 50; /* 50: disk full (?) */ ! 639: #endif ! 640: } else ! 641: #ifdef S_IFLNK ! 642: if (!symlnk) /* symlink() takes care of file creation */ ! 643: #endif /* !S_IFLNK */ ! 644: { ! 645: if (create_output_file()) ! 646: return 50; /* 50: disk full (?) */ ! 647: } ! 648: } /* endif (!tflag) */ ! 649: ! 650: /*--------------------------------------------------------------------------- ! 651: Unpack the file. ! 652: ---------------------------------------------------------------------------*/ ! 653: ! 654: switch (lrec.compression_method) { ! 655: ! 656: case STORED: ! 657: if (!tflag && (quietflg < 2)) { ! 658: fprintf(stdout, " Extracting: %-22s ", filename); ! 659: if (cflag) ! 660: fprintf(stdout, "\n"); ! 661: fflush(stdout); ! 662: } ! 663: #ifdef S_IFLNK ! 664: /* ! 665: * If file came from Unix and is a symbolic link and we are extracting ! 666: * to disk, allocate a storage area, put the data in it, and create the ! 667: * link. Since we know it's a symbolic link to start with, shouldn't ! 668: * have to worry about overflowing unsigned ints with unsigned longs. ! 669: * (This doesn't do anything for compressed symlinks, but that can be ! 670: * added later...it also doesn't set the time or permissions of the ! 671: * link, but does anyone really care?) ! 672: */ ! 673: if (symlnk) { ! 674: #if (defined(MTS) || defined(MACOS)) ! 675: fprintf(stdout, "\n warning: symbolic link ignored\n"); ! 676: error = 1; /* 1: warning error */ ! 677: #else /* !(MTS || MACOS) */ ! 678: char *orig = (char *)malloc((unsigned)lrec.uncompressed_size+1); ! 679: char *p = orig; ! 680: ! 681: while (ReadByte(&b)) ! 682: *p++ = b; ! 683: *p = 0; /* terminate string */ ! 684: UpdateCRC((unsigned char *)orig, p-orig); ! 685: if (symlink(orig, filename)) ! 686: if ((errno == EEXIST) && overwrite_all) { /* OK to overwrite */ ! 687: unlink(filename); ! 688: if (symlink(orig, filename)) ! 689: perror("symlink error"); ! 690: } else ! 691: perror("symlink error"); ! 692: free(orig); ! 693: #endif /* ?(MTS || MACOS) */ ! 694: } else ! 695: #endif /* S_IFLNK */ ! 696: while (ReadByte(&b) && !disk_full) ! 697: OUTB(b) ! 698: break; ! 699: ! 700: case SHRUNK: ! 701: if (!tflag && (quietflg < 2)) { ! 702: fprintf(stdout, "UnShrinking: %-22s ", filename); ! 703: if (cflag) ! 704: fprintf(stdout, "\n"); ! 705: fflush(stdout); ! 706: } ! 707: #ifdef S_IFLNK /* !!! This code needs to be added to unShrink, etc. !!! */ ! 708: if (symlnk) { ! 709: fprintf(stdout, "\n warning: symbolic link ignored\n"); ! 710: error = 1; /* 1: warning error */ ! 711: } ! 712: #endif /* S_IFLNK */ ! 713: unShrink(); ! 714: break; ! 715: ! 716: case REDUCED1: ! 717: case REDUCED2: ! 718: case REDUCED3: ! 719: case REDUCED4: ! 720: if (!tflag && (quietflg < 2)) { ! 721: fprintf(stdout, " Expanding: %-22s ", filename); ! 722: if (cflag) ! 723: fprintf(stdout, "\n"); ! 724: fflush(stdout); ! 725: } ! 726: #ifdef S_IFLNK /* !!! This code needs to be added to unShrink, etc. !!! */ ! 727: if (symlnk) { ! 728: fprintf(stdout, "\n warning: symbolic link ignored\n"); ! 729: error = 1; /* 1: warning error */ ! 730: } ! 731: #endif /* S_IFLNK */ ! 732: unReduce(); ! 733: break; ! 734: ! 735: case IMPLODED: ! 736: if (!tflag && (quietflg < 2)) { ! 737: fprintf(stdout, " Exploding: %-22s ", filename); ! 738: if (cflag) ! 739: fprintf(stdout, "\n"); ! 740: fflush(stdout); ! 741: } ! 742: #ifdef S_IFLNK /* !!! This code needs to be added to unShrink, etc. !!! */ ! 743: if (symlnk) { ! 744: fprintf(stdout, "\n warning: symbolic link ignored\n"); ! 745: error = 1; /* 1: warning error */ ! 746: } ! 747: #endif /* S_IFLNK */ ! 748: if (((r = explode()) != 0) && (r != 5)) { /* ignore 5 if seekable */ ! 749: if ((tflag && quietflg) || (!tflag && (quietflg > 1))) ! 750: fprintf(stderr, " error: %s%s\n", r == 3? ! 751: "not enough memory to explode " : ! 752: "invalid compressed (imploded) data for ", filename); ! 753: else ! 754: fprintf(stderr, "\n error: %s\n", r == 3? ! 755: "not enough memory for explode operation" : ! 756: "invalid compressed data for explode format"); ! 757: error = (r == 3)? 5 : 2; ! 758: } ! 759: break; ! 760: ! 761: case DEFLATED: ! 762: if (!tflag && (quietflg < 2)) { ! 763: fprintf(stdout, " Inflating: %-22s ", filename); ! 764: if (cflag) ! 765: fprintf(stdout, "\n"); ! 766: fflush(stdout); ! 767: } ! 768: #ifdef S_IFLNK /* !!! This code needs to be added to unShrink, etc. !!! */ ! 769: if (symlnk) { ! 770: fprintf(stdout, "\n warning: symbolic link ignored\n"); ! 771: error = 1; /* 1: warning error */ ! 772: } ! 773: #endif /* S_IFLNK */ ! 774: if ((r = inflate()) != 0) { ! 775: if ((tflag && quietflg) || (!tflag && (quietflg > 1))) ! 776: fprintf(stderr, " error: %s%s\n", r == 3? ! 777: "not enough memory to inflate " : ! 778: "invalid compressed (deflated) data for ", filename); ! 779: else ! 780: fprintf(stderr, "\n error: %s\n", r == 3? ! 781: "not enough memory for inflate operation" : ! 782: "invalid compressed data for inflate format"); ! 783: error = (r == 3)? 5 : 2; ! 784: } ! 785: break; ! 786: ! 787: default: /* should never get to this point */ ! 788: fprintf(stderr, "%s: unknown compression method\n", filename); ! 789: /* close and delete file before return? */ ! 790: return 1; /* 1: warning error */ ! 791: ! 792: } /* end switch (compression method) */ ! 793: ! 794: if (disk_full) { /* set by FlushOutput()/OUTB() macro */ ! 795: if (disk_full > 1) ! 796: return 50; /* 50: disk full */ ! 797: error = 1; /* 1: warning error */ ! 798: } ! 799: ! 800: /*--------------------------------------------------------------------------- ! 801: Write the last partial buffer, if any; set the file date and time; and ! 802: close the file (not necessarily in that order). Then make sure CRC came ! 803: out OK and print result. ! 804: ---------------------------------------------------------------------------*/ ! 805: ! 806: #ifdef S_IFLNK ! 807: if (!symlnk) { ! 808: #endif /* S_IFLNK */ ! 809: if (!disk_full && FlushOutput()) ! 810: if (disk_full > 1) ! 811: return 50; /* 50: disk full */ ! 812: else { /* disk_full == 1 */ ! 813: fprintf(stderr, "%s: probably corrupt\n", filename); ! 814: error = 1; /* 1: warning error */ ! 815: } ! 816: ! 817: if (!tflag) ! 818: #ifdef VMS ! 819: CloseOutputFile(); ! 820: #else /* !VMS */ ! 821: #ifdef MTS /* MTS can't set file time */ ! 822: close(outfd); ! 823: #else /* !MTS */ ! 824: set_file_time_and_close(); ! 825: #endif /* ?MTS */ ! 826: #endif /* ?VMS */ ! 827: ! 828: #ifdef S_IFLNK ! 829: } /* endif (!symlnk) */ ! 830: #endif /* S_IFLNK */ ! 831: ! 832: if (error > 1) /* don't print redundant CRC error if error already */ ! 833: return error; ! 834: ! 835: /* logical-AND crc32val for 64-bit machines */ ! 836: if ((crc32val = ((~crc32val) & 0xFFFFFFFFL)) != lrec.crc32) { ! 837: /* if quietflg is set, we haven't output the filename yet: do it */ ! 838: if (quietflg) ! 839: printf("%-22s: ", filename); ! 840: fprintf(stdout, " Bad CRC %08lx (should be %08lx)\n", crc32val, ! 841: lrec.crc32); ! 842: error = 1; /* 1: warning error */ ! 843: } else if (tflag) { ! 844: if (!quietflg) ! 845: fprintf(stdout, " OK\n"); ! 846: } else { ! 847: if ((quietflg < 2) && !error) ! 848: fprintf(stdout, "\n"); ! 849: } ! 850: ! 851: return error; ! 852: ! 853: } /* end function extract_or_test_member() */ ! 854: ! 855: ! 856: ! 857: ! 858: ! 859: #ifdef CRYPT ! 860: ! 861: /*******************************/ ! 862: /* Function decrypt_member() */ ! 863: /*******************************/ ! 864: ! 865: static int decrypt_member() /* return 10 if out of memory or can't get */ ! 866: { /* tty; 1 if password bad; 0 if password OK */ ! 867: UWORD b; ! 868: int n, r; ! 869: static int nopwd=FALSE; ! 870: char *m, *prompt; ! 871: byte h[12]; ! 872: ! 873: ! 874: /* get header once (turn off "encrypted" flag temporarily so we don't ! 875: * try to decrypt the same data twice) */ ! 876: pInfo->encrypted = FALSE; ! 877: for (n = 0; n < 12; n++) { ! 878: ReadByte(&b); ! 879: h[n] = (byte) b; ! 880: } ! 881: pInfo->encrypted = TRUE; ! 882: ! 883: /* if have key already, test it; else allocate memory for it */ ! 884: if (key) { ! 885: if (!testp(h)) ! 886: return 0; /* existing password OK (else prompt for new) */ ! 887: else if (nopwd) ! 888: return 1; /* user indicated no more prompting */ ! 889: } else if ((key = (char *)malloc(PWLEN+1)) == (char *)NULL) ! 890: return 10; ! 891: ! 892: if ((prompt = (char *)malloc(FILNAMSIZ+15)) != (char *)NULL) { ! 893: sprintf(prompt, "%s password: ", filename); ! 894: m = prompt; ! 895: } else ! 896: m = "Enter password: "; ! 897: ! 898: /* try a few keys */ ! 899: for (r = 0; r < 3; ++r) { ! 900: m = getp(m, key, PWLEN+1); ! 901: if (prompt != (char *)NULL) { ! 902: free(prompt); ! 903: prompt = (char *)NULL; ! 904: } ! 905: if (m == (char *)NULL) ! 906: return 10; ! 907: if (!testp(h)) ! 908: return 0; ! 909: if (*key == '\0') { ! 910: nopwd = TRUE; ! 911: return 1; ! 912: } ! 913: m = "password incorrect--reenter: "; ! 914: } ! 915: return 1; ! 916: } ! 917: ! 918: ! 919: ! 920: ! 921: ! 922: /**********************/ ! 923: /* Function testp() */ ! 924: /**********************/ ! 925: ! 926: static int testp(h) /* return -1 if bad password; 0 if OK */ ! 927: byte *h; ! 928: { ! 929: UWORD b; ! 930: int n, t; ! 931: byte *p; ! 932: ! 933: /* set keys */ ! 934: init_keys(key); ! 935: ! 936: /* check password */ ! 937: for (n = 0; n < 12; n++) ! 938: b = DECRYPT(h[n]); ! 939: ! 940: #ifdef CRYPT_DEBUG ! 941: printf(" lrec.crc = %08lx crec.crc = %08lx pInfo->ExtLocHdr = %s\n", ! 942: lrec.crc32, pInfo->crc, pInfo->ExtLocHdr? "true":"false"); ! 943: printf(" incnt = %d unzip offset into zipfile = %ld\n", incnt, ! 944: cur_zipfile_bufstart+(inptr-inbuf)); ! 945: printf(" b = %02x (crc >> 24) = %02x (lrec.time >> 8) = %02x\n", ! 946: b, (UWORD)(lrec.crc32 >> 24), (lrec.last_mod_file_time >> 8)); ! 947: #endif /* CRYPT_DEBUG */ ! 948: ! 949: /* same test as in zipbare() in crypt.c (now check only one byte): */ ! 950: if (b != (pInfo->ExtLocHdr? lrec.last_mod_file_time >> 8 : ! 951: (UWORD)(lrec.crc32 >> 24))) ! 952: return -1; /* bad */ ! 953: ! 954: /* password OK: decrypt current buffer contents before leaving */ ! 955: for (n = (longint)incnt > csize ? (int)csize : incnt, p = inptr; n--; p++) ! 956: *p = (byte) DECRYPT(*p); ! 957: return 0; /* OK */ ! 958: ! 959: } /* end function testp() */ ! 960: ! 961: #endif /* CRYPT */ ! 962: ! 963: ! 964: ! 965: ! 966: ! 967: /*******************************/ ! 968: /* Function ReadMemoryByte() */ ! 969: /*******************************/ ! 970: ! 971: int ReadMemoryByte(x) /* return PK-type error code */ ! 972: UWORD *x; ! 973: { ! 974: if (mem_i_offset < mem_i_size) { ! 975: *x = (UWORD) mem_i_buffer[mem_i_offset++]; ! 976: return 8; ! 977: } else ! 978: return 0; ! 979: } ! 980: ! 981: ! 982: ! 983: ! 984: ! 985: /****************************/ ! 986: /* Function FlushMemory() */ ! 987: /****************************/ ! 988: ! 989: int FlushMemory() /* return PK-type error code */ ! 990: { ! 991: if (outcnt == 0) ! 992: return 0; ! 993: ! 994: if (mem_o_offset + outcnt <= mem_o_size) { ! 995: memcpy((char *)(mem_o_buffer+(UWORD)mem_o_offset), (char *)outbuf, ! 996: outcnt); ! 997: mem_o_offset += outcnt; ! 998: return 0; ! 999: } else ! 1000: return 50; ! 1001: } ! 1002: ! 1003: ! 1004: ! 1005: ! 1006: ! 1007: /***************************/ ! 1008: /* Function memextract() */ /* extract compressed extra field block */ ! 1009: /***************************/ ! 1010: ! 1011: int memextract(tgt, tgtsize, src, srcsize) /* return 0 if success, 1 if not */ ! 1012: byte *tgt, *src; ! 1013: ULONG tgtsize, srcsize; ! 1014: { ! 1015: UWORD method, error = 0; ! 1016: ULONG crc, oldcrc; ! 1017: int r; ! 1018: ! 1019: method = makeword(src); ! 1020: crc = makelong(src+2); ! 1021: ! 1022: mem_i_buffer = src + 2 + 4; /* method and crc */ ! 1023: mem_i_size = srcsize - 2 - 4; ! 1024: mem_i_offset = 0; ! 1025: ! 1026: mem_o_buffer = tgt; ! 1027: mem_o_size = tgtsize; ! 1028: mem_o_offset = 0; ! 1029: ! 1030: mem_mode = 1; ! 1031: ! 1032: bits_left = 0; ! 1033: bitbuf = 0L; ! 1034: outpos = 0L; ! 1035: outcnt = 0; ! 1036: outptr = outbuf; ! 1037: zipeof = 0; ! 1038: ! 1039: switch (method) { ! 1040: case STORED: ! 1041: memcpy(tgt, src + 2 + 4, (extent) (srcsize - 2 - 4)); ! 1042: break; ! 1043: case DEFLATED: ! 1044: if ((r = inflate()) != 0) { ! 1045: fprintf(stderr, "error: %s\n", r == 3 ? ! 1046: "not enough memory for inflate operation" : ! 1047: "invalid compressed data for the inflate format"); ! 1048: error = (r == 3)? 5 : 2; ! 1049: } ! 1050: FlushOutput(); ! 1051: break; ! 1052: default: ! 1053: fprintf(stderr, ! 1054: "warning: unsupported extra field compression type--skipping\n"); ! 1055: error = 1; /* GRR: this should be passed on up via SetEAs() */ ! 1056: break; ! 1057: } ! 1058: ! 1059: mem_mode = 0; ! 1060: ! 1061: if (!error) { ! 1062: oldcrc = crc32val; ! 1063: crc32val = 0xFFFFFFFFL; ! 1064: UpdateCRC((unsigned char *) mem_o_buffer, (int) mem_o_size); ! 1065: crc32val = (~crc32val) & 0xFFFFFFFFL; ! 1066: ! 1067: if (crc32val != crc) { ! 1068: printf("(Bad extra field CRC %08lx, should be %08lx)\n", crc32val, ! 1069: crc); ! 1070: error = 1; ! 1071: } ! 1072: crc32val = oldcrc; /* grrr ... this ugly kludge should be fixed */ ! 1073: } ! 1074: ! 1075: return error; ! 1076: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.