|
|
1.1 ! root 1: /*--------------------------------------------------------------------------- ! 2: ! 3: unzip.c ! 4: ! 5: UnZip - a zipfile extraction utility. See below for make instructions, or ! 6: read the comments in Makefile and the various Contents files for more de- ! 7: tailed explanations. To report a bug, send a *complete* description to ! 8: [email protected]; include machine type, operating system and version, ! 9: compiler and version, and reasonably detailed error messages or problem ! 10: report. To join Info-ZIP, send a message to [email protected]. ! 11: ! 12: UnZip 5.x is a greatly expanded and partially rewritten successor to 4.x, ! 13: which in turn was almost a complete rewrite of version 3.x. For a detailed ! 14: revision history, see UnzpHist.zip at Info-ZIP headquarters (below). For a ! 15: (partial) list of the many (near infinite) contributors, see "CONTRIBS" in ! 16: the UnZip source distribution. ! 17: ! 18: --------------------------------------------------------------------------- ! 19: ! 20: To compile (partial instructions): ! 21: ! 22: under Unix (cc): make <system name> ! 23: (type "make list" for a list of valid names, or read Makefile for ! 24: details. "make unzip" works for most systems. If you have a NEW ! 25: system, not covered by any of the existing targets, send FULL infor- ! 26: mation--hardware, OS, versions, etc.--to [email protected]) ! 27: ! 28: under MS-DOS (MSC, Turbo C, or Borland C++): use the makefiles or ! 29: project files in the MSDOS sub-archive; edit or otherwise modify ! 30: as appropriate. For MSC, use NMAKE. ! 31: ! 32: under MS Windows 3.x: get wunz12sr.{zip | zoo | whatever} and use ! 33: the included makefile ! 34: ! 35: under OS/2 (MSC, gcc, IBM C Set/2, Watcom C): make -f makefile.os2 ! 36: (from OS2 sub-archive; for MSC, use NMAKE) ! 37: ! 38: under VMS (VAX C or GNU C): @make_unzip_vaxc or @make_unzip_gcc ! 39: (from VMS sub-archive; can also use MMS or MAKE/VMS; see VMS.notes) ! 40: ! 41: under Macintosh OS: Double click on unzip.make. Press <Command>-M. ! 42: (from MAC sub-archive) ! 43: ! 44: under Windows NT: use makefile.nt (from NT sub-archive) ! 45: ! 46: under AmigaDOS: try one of the makefiles in the AMIGA sub-archive; ! 47: may need some work yet... ! 48: ! 49: under Atari TOS: needs considerable work yet... ! 50: ! 51: --------------------------------------------------------------------------- ! 52: ! 53: Version: unz50p1.{tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS, Windows, ! 54: Windows NT, Macintosh and Amiga. Decryption requires sources ! 55: in zcrypt19.zip, and Windows (not NT) support requires sources ! 56: in wunz12sr.zip. See accompanying file "Where" in the main ! 57: source distribution for ftp, uucp and mail-server sites. ! 58: Copyrights: see accompanying file "COPYING" in UnZip source distribution. ! 59: ! 60: ---------------------------------------------------------------------------*/ ! 61: ! 62: ! 63: ! 64: ! 65: ! 66: #include "unzip.h" /* includes, defines, and macros */ ! 67: #ifdef MSWIN ! 68: # include "wizunzip.h" /* see History.500 for version history */ ! 69: #endif ! 70: ! 71: #define VERSION "5.0p1 of 12 January 1993" ! 72: /* #define VERSION "v5.0p BETA of 8-21-92" */ /* internal beta level */ ! 73: #define PAKFIX /* temporary(?) solution to PAK-created zipfiles */ ! 74: ! 75: ! 76: ! 77: ! 78: ! 79: /**********************/ ! 80: /* Global Variables */ ! 81: /**********************/ ! 82: ! 83: int aflag=0; /* -a: do ASCII to EBCDIC translation, or CR-LF */ ! 84: /* to CR or LF conversion of extracted files */ ! 85: /* int bflag=0; RESERVED for -b: extract as binary */ ! 86: int cflag=0; /* -c: output to stdout */ ! 87: int fflag=0; /* -f: "freshen" (extract only newer files) */ ! 88: int jflag=0; /* -j: junk pathnames */ ! 89: int overwrite_none=0; /* -n: never overwrite files (no prompting) */ ! 90: int overwrite_all=0; /* -o: OK to overwrite files without prompting */ ! 91: int force_flag=0; /* (shares -o for now): force to override errors, etc. */ ! 92: int quietflg=0; /* -q: produce a lot less output */ ! 93: #ifdef DOS_OS2 ! 94: int sflag=1; /* -s: allow spaces (blanks) in filenames */ ! 95: #endif /* DOS_OS2 */ ! 96: int tflag=0; /* -t: test */ ! 97: int uflag=0; /* -u: "update" (extract only newer & brand-new files) */ ! 98: static int U_flag=0; /* -U: leave filenames in upper or mixed case */ ! 99: static int vflag=0; /* -v: view directory (only used in unzip.c) */ ! 100: int V_flag=0; /* -V: don't strip VMS version numbers */ ! 101: #ifdef VMS ! 102: int secinf=0; /* -X: keep owner/protection */ ! 103: #endif /* VMS */ ! 104: int zflag=0; /* -z: display only the archive comment */ ! 105: int process_all_files=0; ! 106: ! 107: longint csize; /* used by list_files(), ReadByte(): must be signed */ ! 108: longint ucsize; /* used by list_files(), unReduce(), explode() */ ! 109: ! 110: char *fnames[2] = {"*", NULL}; /* default filenames vector */ ! 111: char **fnv = fnames; ! 112: char sig[5]; ! 113: char answerbuf[10]; ! 114: ! 115: min_info info[DIR_BLKSIZ], *pInfo=info; ! 116: ! 117: #ifdef OS2 ! 118: int longname; /* used in extract.c, mapname.c and file_io.c */ ! 119: char longfilename[FILNAMSIZ]; ! 120: #endif /* OS2 */ ! 121: ! 122: #ifdef CRYPT ! 123: char *key = (char *)NULL; /* password with which to decrypt data, or NULL */ ! 124: #endif /* CRYPT */ ! 125: ! 126: /*--------------------------------------------------------------------------- ! 127: unShrink/unReduce/explode/inflate working storage and globals: ! 128: ---------------------------------------------------------------------------*/ ! 129: ! 130: union work area; /* see unzip.h for the definition of work */ ! 131: ULONG crc32val; ! 132: ! 133: UWORD mask_bits[] = { ! 134: 0x0000, ! 135: 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, ! 136: 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff ! 137: }; ! 138: ! 139: /*--------------------------------------------------------------------------- ! 140: Input file variables: ! 141: ---------------------------------------------------------------------------*/ ! 142: ! 143: byte *inbuf, *inptr; /* input buffer (any size is legal) and pointer */ ! 144: int incnt; ! 145: ! 146: ULONG bitbuf; ! 147: int bits_left; ! 148: boolean zipeof; ! 149: ! 150: int zipfd; /* zipfile file handle */ ! 151: #ifdef MSWIN ! 152: char *zipfn; ! 153: #else ! 154: char zipfn[FILNAMSIZ]; ! 155: #endif ! 156: ! 157: char local_hdr_sig[5] = "\120"; /* remaining signature bytes come later */ ! 158: char central_hdr_sig[5] = "\120"; /* (must initialize at runtime so unzip */ ! 159: char end_central_sig[5] = "\120"; /* executable won't look like a zipfile) */ ! 160: /* char extd_local_sig[5] = "\120"; NOT USED YET */ ! 161: ! 162: cdir_file_hdr crec; /* used in unzip.c, extract.c, misc.c */ ! 163: local_file_hdr lrec; /* used in unzip.c, extract.c */ ! 164: ecdir_rec ecrec; /* used in unzip.c, extract.c */ ! 165: struct stat statbuf; /* used by main(), mapped_name(), check_for_newer() */ ! 166: ! 167: longint extra_bytes = 0; /* used in unzip.c, misc.c */ ! 168: longint cur_zipfile_bufstart; /* extract_or_test_files, readbuf, ReadByte */ ! 169: ! 170: #ifdef MACOS ! 171: short gnVRefNum; ! 172: long glDirID; ! 173: OSType gostCreator; ! 174: OSType gostType; ! 175: boolean fMacZipped; ! 176: boolean macflag; ! 177: CursHandle rghCursor[4]; /* status cursors */ ! 178: short giCursor = 0; ! 179: #endif ! 180: ! 181: /*--------------------------------------------------------------------------- ! 182: Output stream variables: ! 183: ---------------------------------------------------------------------------*/ ! 184: ! 185: byte *outbuf; /* buffer for rle look-back */ ! 186: byte *outptr; ! 187: #ifdef MSWIN ! 188: byte __far *outout; ! 189: char *filename; ! 190: #else /* !MSWIN */ ! 191: byte *outout; /* scratch pad for ASCII-native trans */ ! 192: char filename[FILNAMSIZ]; ! 193: #endif /* ?MSWIN */ ! 194: byte *extra_field = (byte *)NULL; /* used by VMS, Mac and OS/2 versions */ ! 195: longint outpos; /* absolute position in outfile */ ! 196: int outcnt; /* current position in outbuf */ ! 197: int outfd; ! 198: int mem_mode = 0; ! 199: int disk_full; ! 200: ! 201: /*--------------------------------------------------------------------------- ! 202: unzip.c static global variables (visible only within this file): ! 203: ---------------------------------------------------------------------------*/ ! 204: ! 205: static byte *hold; ! 206: static char unkn[10]; ! 207: static longint ziplen; ! 208: static UWORD methnum; ! 209: ! 210: /*--------------------------------------------------------------------------- ! 211: unzip.c repeated error messages (we use all of these at least twice) ! 212: ---------------------------------------------------------------------------*/ ! 213: ! 214: char *EndSigMsg = "\nwarning:\ ! 215: didn't find end-of-central-dir signature at end of central dir.\n"; ! 216: char *CentSigMsg = ! 217: "error: expected central file header signature not found (file #%u).\n"; ! 218: char *SeekMsg = ! 219: "error: attempt to seek before beginning of zipfile\n%s"; ! 220: ! 221: #ifdef VMS ! 222: char *ReportMsg = "\ ! 223: (please check that you have transferred or created the zipfile in the\n\ ! 224: appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n"; ! 225: #else /* !VMS */ ! 226: char *ReportMsg = "\ ! 227: (please check that you have transferred or created the zipfile in the\n\ ! 228: appropriate BINARY mode and that you have compiled unzip properly)\n"; ! 229: #endif /* ?VMS */ ! 230: ! 231: ! 232: #ifdef MSWIN ! 233: /* MS Windows Setup and Take-Down functions bracket calls to ! 234: * process_zipfile(). ! 235: * These functions allocate and free the necessary buffers, set and clear ! 236: * any global variables so that process_zipfile() can be called multiple ! 237: * times in the same session of WizUnzip. You'll recognize some of the ! 238: * code from main() in SetUpToProcessZipFile(). ! 239: */ ! 240: HANDLE hOutBuf; ! 241: HANDLE hOutOut; /* added 04/03/92 for version 1.1 */ ! 242: HANDLE hInBuf; ! 243: HANDLE hZipFN; ! 244: HANDLE hFileName; ! 245: ! 246: BOOL FSetUpToProcessZipFile(int ncflag, int ntflag, int nvflag, int nUflag, ! 247: int nzflag, int ndflag, int noflag, int naflag, int argc, ! 248: LPSTR lpszZipFN, PSTR *FNV) ! 249: { ! 250: /* clear all global flags -- need to or not. */ ! 251: ! 252: tflag = vflag=cflag=aflag=U_flag=quietflg=zflag = 0; ! 253: overwrite_all=overwrite_none=0; ! 254: fnv = &fnames[0]; /* assign default file name vector */ ! 255: ! 256: cflag = ncflag ; overwrite_all = noflag; ! 257: tflag = ntflag ; vflag = nvflag; zflag = nzflag; U_flag = nUflag; ! 258: aflag = naflag; ! 259: sflag = 1; ! 260: ! 261: local_hdr_sig[0] = central_hdr_sig[0] = end_central_sig[0] = '\120'; ! 262: local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0'; ! 263: ! 264: if (!(hZipFN = LocalAlloc(LMEM_MOVEABLE, FILNAMSIZ))) ! 265: return FALSE; ! 266: ! 267: zipfn = (char *)LocalLock(hZipFN); ! 268: lstrcpy(zipfn, lpszZipFN); ! 269: if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR) ! 270: strcat(zipfn, ZSUFX); ! 271: ! 272: if (stat(zipfn, &statbuf)) { /* try again */ ! 273: fprintf(stderr, "error: can't find zipfile [ %s ]\n", zipfn); ! 274: return TRUE; /* 9: file not found */ ! 275: } else ! 276: ziplen = statbuf.st_size; ! 277: ! 278: if (argc != 0) { ! 279: fnv = FNV; ! 280: process_all_files = FALSE; ! 281: } else ! 282: process_all_files = TRUE; /* for speed */ ! 283: ! 284: /*--------------------------------------------------------------------------- ! 285: Okey dokey, we have everything we need to get started. Let's roll. ! 286: ---------------------------------------------------------------------------*/ ! 287: ! 288: if (hInBuf = LocalAlloc(LMEM_MOVEABLE, INBUFSIZ+4)) { /* 4 extra: hold[] */ ! 289: inbuf = (byte *) LocalLock(hInBuf); ! 290: WinAssert(inbuf); ! 291: } ! 292: if (hOutBuf = LocalAlloc(LMEM_MOVEABLE, OUTBUFSIZ+1)) { /* extra: ASCIIZ */ ! 293: outbuf = (byte *)LocalLock(hOutBuf); ! 294: WinAssert(outbuf); ! 295: if (aflag) { /* if LF => CR,LF translation */ ! 296: if (hOutOut = GlobalAlloc(GMEM_MOVEABLE,OUTBUFSIZ)) { ! 297: outout = (byte _far *)GlobalLock(hOutOut); ! 298: WinAssert(outout); ! 299: } ! 300: } else /* no translation; just re-use output buffer */ ! 301: outout = (byte _far *)outbuf; /* point to outbuf */ ! 302: } ! 303: if ( hFileName = LocalAlloc(LMEM_MOVEABLE, FILNAMSIZ)) { ! 304: filename = (char *)LocalLock(hFileName); ! 305: WinAssert(filename); ! 306: } ! 307: ! 308: if ((inbuf == NULL) || (outbuf == NULL) || (outout == NULL) || ! 309: (zipfn == NULL) || (filename == NULL)) ! 310: return FALSE; ! 311: ! 312: hold = &inbuf[INBUFSIZ]; /* to check for boundary-spanning signatures */ ! 313: ! 314: return TRUE; /* set up was OK */ ! 315: } ! 316: ! 317: void TakeDownFromProcessZipFile(void) ! 318: { ! 319: if (inbuf) { ! 320: LocalUnlock(hInBuf); ! 321: inbuf = NULL; ! 322: } ! 323: if (hInBuf) ! 324: hInBuf = LocalFree(hInBuf); ! 325: ! 326: if (outbuf) { ! 327: LocalUnlock(hOutBuf); ! 328: outbuf = NULL; ! 329: } ! 330: if (hOutBuf) ! 331: hOutBuf = LocalFree(hOutBuf); ! 332: ! 333: if (aflag && outout) /* if doing LF => CR,LF translation */ ! 334: GlobalUnlock(hOutOut); ! 335: outout = NULL; /* free now, translation or not */ ! 336: if (hOutOut) ! 337: hOutOut = GlobalFree(hOutOut); /* mark buffer as freed */ ! 338: ! 339: if (zipfn) { ! 340: LocalUnlock(hZipFN); ! 341: zipfn = NULL; ! 342: } ! 343: if (hZipFN) ! 344: hZipFN = LocalFree(hZipFN); ! 345: ! 346: if (filename) { ! 347: LocalUnlock(hFileName); ! 348: filename = NULL; ! 349: } ! 350: if (hFileName) ! 351: hFileName = LocalFree(hFileName); ! 352: } ! 353: ! 354: #else /* !MSWIN */ ! 355: ! 356: /******************/ ! 357: /* Main program */ ! 358: /******************/ ! 359: ! 360: int main(argc, argv) /* return PK-type error code (except under VMS) */ ! 361: int argc; ! 362: char *argv[]; ! 363: { ! 364: char *s; ! 365: int c, error=FALSE, negative=0; ! 366: ! 367: ! 368: /*--------------------------------------------------------------------------- ! 369: Macintosh initialization code. ! 370: ---------------------------------------------------------------------------*/ ! 371: ! 372: #ifdef MACOS ! 373: #ifdef THINK_C ! 374: # include <console.h> ! 375: static char *argstr[30], args[30*64]; ! 376: Point p; ! 377: SFTypeList sfT; ! 378: EventRecord theEvent; ! 379: short eMask; ! 380: SFReply fileRep; ! 381: #endif /* THINK_C */ ! 382: int a; ! 383: ! 384: for (a = 0; a < 4; ++a) ! 385: rghCursor[a] = GetCursor(a+128); ! 386: giCursor = 0; ! 387: ! 388: area.Slide = (byte *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char)); ! 389: area.shrink.Prefix_of = (short *)area.Slide; ! 390: area.shrink.Suffix_of = area.Slide + (sizeof(short)*(HSIZE+1)); ! 391: area.shrink.Stack = area.Slide + (sizeof(short) + sizeof(char))*(HSIZE+1); ! 392: ! 393: #ifdef THINK_C ! 394: for (a = 0; a < 30; ++a) ! 395: argstr[a] = &args[a*64]; ! 396: start: ! 397: tflag=vflag=cflag=aflag=jflag=U_flag=quietflg=fflag=uflag=zflag = 0; ! 398: local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0'; ! 399: /* extd_local_sig[1] = '\0'; */ ! 400: error = FALSE; ! 401: ! 402: argc = ccommand(&argv); ! 403: SetPt(&p, 40, 40); ! 404: ! 405: SFGetFile(p, "\pSpecify ZIP file:", 0L, -1, sfT, 0L, &fileRep); ! 406: if (fileRep.good) { ! 407: macfstest(fileRep.vRefNum); ! 408: ResolveMacVol(fileRep.vRefNum, &gnVRefNum, &glDirID, NULL); ! 409: for (a = 1; a < argc; ++a) ! 410: if (argv[a][0] == '-') ! 411: BlockMove(argv[a], argstr[a], (strlen(argv[a]) > 63) ? 64 : ! 412: strlen(argv[a])+1); ! 413: else ! 414: break; ! 415: PtoCstr((char *)fileRep.fName); ! 416: strcpy(argstr[a], (char *)fileRep.fName); ! 417: for (; a < argc; ++a) ! 418: BlockMove(argv[a], argstr[a+1], (strlen(argv[a]) > 63) ? 64 : ! 419: strlen(argv[a])+1); ! 420: ++argc; ! 421: argv = argstr; ! 422: ! 423: if (hfsflag == FALSE) /* can't support directories: junk pathnames */ ! 424: jflag = 1; ! 425: } ! 426: #endif /* THINK_C */ ! 427: #endif /* MACOS */ ! 428: ! 429: /*--------------------------------------------------------------------------- ! 430: Set signal handler for restoring echo, warn of zipfile corruption, etc. ! 431: ---------------------------------------------------------------------------*/ ! 432: ! 433: signal(SIGINT, handler); ! 434: signal(SIGTERM, handler); ! 435: #ifdef SIGBUS ! 436: signal(SIGBUS, handler); ! 437: #endif ! 438: #ifdef SIGSEGV ! 439: signal(SIGSEGV, handler); ! 440: #endif ! 441: ! 442: /*--------------------------------------------------------------------------- ! 443: Debugging info for checking on structure padding: ! 444: ---------------------------------------------------------------------------*/ ! 445: ! 446: #ifdef DEBUG_STRUC ! 447: printf("local_file_hdr size: %X\n", ! 448: sizeof(local_file_hdr)); ! 449: printf("local_byte_hdr size: %X\n", ! 450: sizeof(local_byte_hdr)); ! 451: printf("actual size of local headers: %X\n", LREC_SIZE); ! 452: ! 453: printf("central directory header size: %X\n", ! 454: sizeof(cdir_file_hdr)); ! 455: printf("central directory byte header size: %X\n", ! 456: sizeof(cdir_byte_hdr)); ! 457: printf("actual size of central dir headers: %X\n", CREC_SIZE); ! 458: ! 459: printf("end central dir record size: %X\n", ! 460: sizeof(ecdir_rec)); ! 461: printf("end central dir byte record size: %X\n", ! 462: sizeof(ec_byte_rec)); ! 463: printf("actual size of end-central-dir record: %X\n", ECREC_SIZE); ! 464: #endif /* DEBUG_STRUC */ ! 465: ! 466: /*--------------------------------------------------------------------------- ! 467: Put environment-variable options into the queue, then rip through any ! 468: command-line options lurking about... ! 469: ---------------------------------------------------------------------------*/ ! 470: ! 471: envargs(&argc, &argv, ENV_UNZIP); ! 472: ! 473: while (--argc > 0 && (*++argv)[0] == '-') { ! 474: s = argv[0] + 1; ! 475: while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */ ! 476: switch (c) { ! 477: case ('-'): ! 478: ++negative; ! 479: break; ! 480: case ('a'): ! 481: if (negative) ! 482: aflag = FALSE, negative = 0; ! 483: else ! 484: aflag = TRUE; ! 485: break; ! 486: #if 0 ! 487: case ('b'): /* force binary mode */ ! 488: if (negative) ! 489: bflag = FALSE, negative = 0; ! 490: else ! 491: bflag = TRUE; ! 492: break; ! 493: #endif ! 494: case ('c'): ! 495: if (negative) { ! 496: cflag = FALSE, negative = 0; ! 497: #ifdef NATIVE ! 498: aflag = FALSE; ! 499: #endif ! 500: } else { ! 501: cflag = TRUE; ! 502: #ifdef NATIVE ! 503: aflag = TRUE; /* so you can read it on the screen */ ! 504: #endif ! 505: } ! 506: break; ! 507: case ('d'): /* re-create directory structure (default) */ ! 508: if (negative) ! 509: jflag = TRUE, negative = 0; ! 510: break; ! 511: case ('e'): /* just ignore -e, -x options (extract) */ ! 512: break; ! 513: case ('f'): /* "freshen" (extract only newer files) */ ! 514: if (negative) ! 515: fflag = uflag = FALSE, negative = 0; ! 516: else ! 517: fflag = uflag = TRUE; ! 518: break; ! 519: case ('j'): /* junk pathnames/directory structure */ ! 520: if (negative) ! 521: jflag = FALSE, negative = 0; ! 522: else ! 523: jflag = TRUE; ! 524: break; ! 525: case ('l'): ! 526: if (negative) { ! 527: vflag = MAX(vflag-negative,0); ! 528: negative = 0; ! 529: } else ! 530: ++vflag; ! 531: break; ! 532: case ('n'): /* don't overwrite any files */ ! 533: if (negative) ! 534: overwrite_none = FALSE, negative = 0; ! 535: else ! 536: overwrite_none = TRUE; ! 537: break; ! 538: case ('o'): /* OK to overwrite files without prompting */ ! 539: if (negative) { ! 540: overwrite_all = MAX(overwrite_all-negative,0); ! 541: force_flag = MAX(force_flag-negative,0); ! 542: negative = 0; ! 543: } else { ! 544: ++overwrite_all; ! 545: ++force_flag; /* (share -o for now) force to cont. */ ! 546: } ! 547: break; ! 548: case ('p'): /* pipes: stdout, no tranlation, no messages */ ! 549: if (negative) { ! 550: cflag = FALSE; ! 551: quietflg = MAX(quietflg-999,0); ! 552: negative = 0; ! 553: } else { ! 554: cflag = TRUE; ! 555: quietflg += 999; ! 556: } ! 557: break; ! 558: case ('q'): /* quiet: fewer comments/messages */ ! 559: if (negative) { ! 560: quietflg = MAX(quietflg-negative,0); ! 561: negative = 0; ! 562: } else ! 563: ++quietflg; ! 564: break; ! 565: #ifdef DOS_OS2 ! 566: case ('s'): /* spaces in filenames: allow by default */ ! 567: if (negative) ! 568: sflag = TRUE, negative = 0; ! 569: else ! 570: sflag = FALSE; ! 571: break; ! 572: #endif ! 573: case ('t'): ! 574: if (negative) ! 575: tflag = FALSE, negative = 0; ! 576: else ! 577: tflag = TRUE; ! 578: break; ! 579: case ('U'): /* Uppercase (don't convert to all-lower) */ ! 580: if (negative) ! 581: U_flag = FALSE, negative = 0; ! 582: else ! 583: U_flag = TRUE; ! 584: break; ! 585: case ('u'): /* update (extract only new and newer files) */ ! 586: if (negative) ! 587: uflag = FALSE, negative = 0; ! 588: else ! 589: uflag = TRUE; ! 590: break; ! 591: case ('V'): /* Version (retain VMS/DEC-20 file versions) */ ! 592: if (negative) ! 593: V_flag = FALSE, negative = 0; ! 594: else ! 595: V_flag = TRUE; ! 596: break; ! 597: case ('v'): /* verbose */ ! 598: if (negative) { ! 599: vflag = MAX(vflag-negative,0); ! 600: negative = 0; ! 601: } else if (vflag) ! 602: ++vflag; ! 603: else ! 604: vflag = 2; ! 605: break; ! 606: #ifdef VMS ! 607: case ('X'): /* restore owner/protection info (need privs?) */ ! 608: if (negative) ! 609: secinf = FALSE, negative = 0; ! 610: else ! 611: secinf = TRUE; ! 612: break; ! 613: #endif /* VMS */ ! 614: case ('x'): /* extract: default */ ! 615: break; ! 616: case ('z'): /* display only the archive comment */ ! 617: if (negative) { ! 618: zflag = MAX(zflag-negative,0); ! 619: negative = 0; ! 620: } else ! 621: ++zflag; ! 622: break; ! 623: default: ! 624: error = TRUE; ! 625: break; ! 626: ! 627: } /* end switch */ ! 628: } /* end while (not end of argument string) */ ! 629: } /* end while (not done with switches) */ ! 630: ! 631: /*--------------------------------------------------------------------------- ! 632: Make sure we aren't trying to do too many things here. [This seems like ! 633: kind of a brute-force way to do things; but aside from that, isn't the ! 634: -a option useful when listing the directory (i.e., for reading zipfile ! 635: comments)? It's a modifier, not an action in and of itself, so perhaps ! 636: it should not be included in the test--certainly, in the case of zipfile ! 637: testing, it can just be ignored.] ! 638: ---------------------------------------------------------------------------*/ ! 639: ! 640: if ((aflag && tflag) || (aflag && vflag) || (cflag && tflag) || ! 641: (cflag && uflag) || (cflag && vflag) || (tflag && uflag) || ! 642: (tflag && vflag) || (uflag && vflag) || (fflag && overwrite_none)) { ! 643: fprintf(stderr, "error:\ ! 644: -at, -av, -ct, -cu, -cv, -fn, -tu, -tv, -uv combinations not allowed\n"); ! 645: error = TRUE; ! 646: } ! 647: if (quietflg && zflag) ! 648: quietflg = 0; ! 649: if (overwrite_all && overwrite_none) { ! 650: fprintf(stderr, "caution: both -n and -o specified; ignoring -o\n"); ! 651: overwrite_all = FALSE; ! 652: } ! 653: if ((argc-- == 0) || error) ! 654: RETURN(usage(error)); ! 655: ! 656: /*--------------------------------------------------------------------------- ! 657: Now get the zipfile name from the command line and see if it exists as a ! 658: regular (non-directory) file. If not, append the ".zip" suffix. We don't ! 659: immediately check to see if this results in a good name, but we will do so ! 660: later. In the meantime, see if there are any member filespecs on the com- ! 661: mand line, and if so, set the filename pointer to point at them. ! 662: ---------------------------------------------------------------------------*/ ! 663: ! 664: strcpy(zipfn, *argv++); ! 665: if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR) ! 666: strcat(zipfn, ZSUFX); ! 667: #if (defined(UNIX) && !defined(VMS)) /* Unix executables have no extension-- */ ! 668: else if (statbuf.st_mode & S_IXUSR) /* might find zip, not zip.zip; etc */ ! 669: fprintf(stderr, "\nnote: file [ %s ] may be an executable\n\n", zipfn); ! 670: #endif /* UNIX && !VMS */ ! 671: ! 672: if (stat(zipfn, &statbuf)) {/* try again */ ! 673: fprintf(stderr, "error: can't find zipfile [ %s ]\n", zipfn); ! 674: RETURN(9); /* 9: file not found */ ! 675: } else ! 676: ziplen = statbuf.st_size; ! 677: ! 678: if (argc != 0) { ! 679: fnv = argv; ! 680: process_all_files = FALSE; ! 681: } else ! 682: process_all_files = TRUE; /* for speed */ ! 683: ! 684: /*--------------------------------------------------------------------------- ! 685: Okey dokey, we have everything we need to get started. Let's roll. ! 686: ---------------------------------------------------------------------------*/ ! 687: ! 688: inbuf = (byte *) malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */ ! 689: outbuf = (byte *) malloc(OUTBUFSIZ + 1); /* 1 extra for string termin. */ ! 690: #ifndef DOS_OS2 ! 691: if (aflag) /* if need an ascebc scratch, */ ! 692: outout = (byte *) malloc(OUTBUFSIZ); ! 693: else /* allocate it... */ ! 694: #endif /* !DOS_OS2 */ ! 695: outout = outbuf; /* else just point to outbuf */ ! 696: ! 697: if ((inbuf == (byte *)NULL) || (outbuf == (byte *)NULL) || ! 698: (outout == (byte *)NULL)) { ! 699: fprintf(stderr, "error: can't allocate unzip buffers\n"); ! 700: RETURN(4); /* 4-8: insufficient memory */ ! 701: } ! 702: hold = &inbuf[INBUFSIZ]; /* to check for boundary-spanning signatures */ ! 703: ! 704: RETURN(process_zipfile()); /* keep passing errors back... */ ! 705: ! 706: } /* end main() */ ! 707: ! 708: ! 709: ! 710: ! 711: ! 712: /**********************/ ! 713: /* Function usage() */ ! 714: /**********************/ ! 715: ! 716: int usage(error) /* return PK-type error code */ ! 717: int error; ! 718: { ! 719: #ifdef NATIVE ! 720: #ifdef EBCDIC ! 721: char *astring = "-a convert ASCII to EBCDIC"; ! 722: #else /* !EBCDIC */ ! 723: char *astring = "-a convert ASCII to native chars"; ! 724: #endif /* ?EBCDIC */ ! 725: /* char *astring = "-a convert ASCII to " NATIVE; (ANSI C concatenation) */ ! 726: char *loc_str = ""; ! 727: #else /* !NATIVE */ ! 728: #ifdef DOS_OS2 ! 729: char *astring = "-a convert text (LF => CR LF)"; ! 730: char *loc_str = "-s spaces in filenames => _"; ! 731: #else /* !DOS_OS2 */ ! 732: #ifdef MACOS ! 733: char *astring = "-a convert text (CR LF => CR)"; ! 734: char *loc_str = ""; ! 735: #else /* !MACOS: UNIX, VMS */ ! 736: char *astring = "-a convert text (CR LF => LF)"; ! 737: #ifdef VMS ! 738: char *loc_str = "-X restore owner/protection info"; ! 739: #else /* !VMS */ ! 740: char *loc_str = ""; ! 741: #endif /* ?VMS */ ! 742: #endif /* ?MACOS */ ! 743: #endif /* ?DOS_OS2 */ ! 744: #endif /* ?NATIVE */ ! 745: FILE *usagefp; ! 746: ! 747: ! 748: /*--------------------------------------------------------------------------- ! 749: If user requested usage, send it to stdout; else send to stderr. ! 750: ---------------------------------------------------------------------------*/ ! 751: ! 752: if (error) ! 753: usagefp = (FILE *) stderr; ! 754: else ! 755: usagefp = (FILE *) stdout; ! 756: ! 757: fprintf(usagefp, "\ ! 758: UnZip %s, by Info-ZIP. Portions (c) 1989 by S. H. Smith.\n\ ! 759: Bug reports ONLY to zip-bugs%%[email protected]; see README for detail\ ! 760: s\n\n", VERSION); ! 761: ! 762: fprintf(usagefp, "\ ! 763: Usage: unzip [ -options[modifiers] ] file[.zip] [filespec...]\n\ ! 764: -x extract files (default) -l list files (short format)\n\ ! 765: -c extract files to stdout/screen (CRT) -v list files (verbose format)\n\ ! 766: -f freshen existing files, create none -p extract to pipe, no messages\n\ ! 767: -u update files, create if necessary -t test archive integrity\n\ ! 768: -z display archive comment\n\ ! 769: modifiers:\n\ ! 770: -n never overwrite existing files %s\n", loc_str); ! 771: fprintf(usagefp, "\ ! 772: -o overwrite files WITHOUT prompting %s\n\ ! 773: -j junk paths (don't make directories) -U don't make names lowercase\n\ ! 774: -q quiet mode (-qq => quieter) -V retain VMS version numbers\ ! 775: \n\n\ ! 776: Examples: (See manual for more information)\n\ ! 777: unzip data1 ReadMe => extracts file ReadMe from zipfile data1.zip\n\ ! 778: unzip -p foo | more => send contents of foo.zip via pipe into program more\n\ ! 779: unzip -fo foo => quietly replace existing files if archive files newer\ ! 780: \n", astring); ! 781: ! 782: #ifdef VMS ! 783: fprintf(usagefp, "\ ! 784: unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS\ ! 785: \n"); ! 786: #endif ! 787: ! 788: if (error) ! 789: return 10; /* 10: bad or illegal parameters specified */ ! 790: else ! 791: return 0; /* just wanted usage screen: no error */ ! 792: ! 793: } /* end function usage() */ ! 794: ! 795: #endif /* ?MSWIN */ ! 796: ! 797: ! 798: ! 799: ! 800: /********************************/ ! 801: /* Function process_zipfile() */ ! 802: /********************************/ ! 803: ! 804: int process_zipfile() /* return PK-type error code */ ! 805: { ! 806: int error=0, error_in_archive; ! 807: longint real_ecrec_offset, expect_ecrec_offset; ! 808: ! 809: ! 810: /*--------------------------------------------------------------------------- ! 811: Open the zipfile for reading and in BINARY mode to prevent CR/LF trans- ! 812: lation, which would corrupt the bitstreams. ! 813: ---------------------------------------------------------------------------*/ ! 814: ! 815: #ifdef VMS ! 816: if (check_format()) /* check for variable-length format */ ! 817: return 2; /* 2: error in zipfile */ ! 818: #endif /* VMS */ ! 819: ! 820: if (open_input_file()) /* this should never happen, given the */ ! 821: return 9; /* stat() test in main(), but... */ ! 822: ! 823: /*--------------------------------------------------------------------------- ! 824: Reconstruct the various PK signature strings, and find and process the ! 825: end-of-central-directory header. ! 826: ---------------------------------------------------------------------------*/ ! 827: ! 828: strcat(local_hdr_sig, LOCAL_HDR_SIG); ! 829: strcat(central_hdr_sig, CENTRAL_HDR_SIG); ! 830: strcat(end_central_sig, END_CENTRAL_SIG); ! 831: /* strcat(extd_local_sig, EXTD_LOCAL_SIG); */ ! 832: ! 833: if (find_end_central_dir()) { /* not found; nothing to do */ ! 834: close(zipfd); ! 835: return 2; /* 2: error in zipfile */ ! 836: } ! 837: ! 838: real_ecrec_offset = cur_zipfile_bufstart+(inptr-inbuf); ! 839: #ifdef TEST ! 840: printf("\n found end-of-central-dir signature at offset %ld (%.8lXh)\n", ! 841: real_ecrec_offset, real_ecrec_offset); ! 842: printf(" from beginning of file; offset %d (%.4Xh) within block\n", ! 843: inptr-inbuf, inptr-inbuf); ! 844: #endif ! 845: ! 846: if ((error_in_archive = process_end_central_dir()) > 1) { ! 847: close(zipfd); ! 848: return error_in_archive; ! 849: } ! 850: ! 851: if (zflag) { ! 852: close(zipfd); ! 853: return 0; ! 854: } ! 855: ! 856: /*--------------------------------------------------------------------------- ! 857: Test the end-of-central-directory info for incompatibilities and incon- ! 858: sistencies. ! 859: ---------------------------------------------------------------------------*/ ! 860: ! 861: #ifndef PAKFIX ! 862: if (ecrec.number_this_disk == 0) { ! 863: #else /* PAKFIX */ ! 864: error = ((ecrec.number_this_disk == 1) && ! 865: (ecrec.num_disk_with_start_central_dir == 1)); ! 866: if ((ecrec.number_this_disk == 0) || error) { ! 867: if (error) { ! 868: fprintf(stderr, ! 869: "\n Warning: zipfile claims to be disk 2 of a two-part archive;\n\ ! 870: attempting to process anyway. If no further errors occur, this\n\ ! 871: archive was probably created by PAK v2.51 or earlier. This bug\n\ ! 872: was reported to NoGate in March 1991 and was supposed to have been\n\ ! 873: fixed by mid-1991; as of mid-1992 it still hadn't been.\n\n"); ! 874: error_in_archive = 1; /* 1: warning */ ! 875: } ! 876: #endif /* ?PAKFIX */ ! 877: expect_ecrec_offset = ecrec.offset_start_central_directory + ! 878: ecrec.size_central_directory; ! 879: if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) { ! 880: fprintf(stderr, "\nerror: missing %ld bytes in zipfile (\ ! 881: attempting to process anyway)\n\n", -extra_bytes); ! 882: error_in_archive = 2; /* 2: (weak) error in zipfile */ ! 883: } else if (extra_bytes > 0) { ! 884: if ((ecrec.offset_start_central_directory == 0) && ! 885: (ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */ ! 886: { ! 887: fprintf(stderr, "\nerror: NULL central directory offset (\ ! 888: attempting to process anyway)\n\n"); ! 889: ecrec.offset_start_central_directory = extra_bytes; ! 890: extra_bytes = 0; ! 891: error_in_archive = 2; /* 2: (weak) error in zipfile */ ! 892: } else { ! 893: fprintf(stderr, "\nwarning: extra %ld bytes at beginning or\ ! 894: within zipfile\n (attempting to process anyway)\n\n", extra_bytes); ! 895: error_in_archive = 1; /* 1: warning error */ ! 896: } ! 897: } ! 898: ! 899: /*----------------------------------------------------------------------- ! 900: Check for empty zipfile and exit now if so. ! 901: -----------------------------------------------------------------------*/ ! 902: ! 903: if (expect_ecrec_offset == 0L && ecrec.size_central_directory == 0) { ! 904: fprintf(stderr, "warning: zipfile is empty\n"); ! 905: close(zipfd); ! 906: return (error_in_archive > 1)? error_in_archive : 1; ! 907: } ! 908: ! 909: /*----------------------------------------------------------------------- ! 910: Compensate for missing or extra bytes, and seek to where the start ! 911: of central directory should be. If header not found, uncompensate ! 912: and try again (necessary for at least some Atari archives created ! 913: with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT). ! 914: -----------------------------------------------------------------------*/ ! 915: ! 916: LSEEK( ecrec.offset_start_central_directory ) ! 917: if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) { ! 918: longint tmp = extra_bytes; ! 919: ! 920: extra_bytes = 0; ! 921: LSEEK( ecrec.offset_start_central_directory ) ! 922: if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) { ! 923: fprintf(stderr, ! 924: "error: start of central directory not found; zipfile corrupt.\n"); ! 925: fprintf(stderr, ReportMsg); ! 926: close(zipfd); ! 927: return 3; /* 3: severe error in zipfile */ ! 928: } ! 929: fprintf(stderr, "error: reported length of central directory is \ ! 930: %d bytes too\n long (Atari STZIP zipfile? J.H. Holm ZIPSPLIT zipfile?)\ ! 931: .\n Compensating...\n\n", -tmp); ! 932: error_in_archive = 2; /* 2: (weak) error in zipfile */ ! 933: } ! 934: ! 935: /*----------------------------------------------------------------------- ! 936: Seek to the start of the central directory one last time, since we ! 937: have just read the first entry's signature bytes; then list, extract ! 938: or test member files as instructed, and close the zipfile. ! 939: -----------------------------------------------------------------------*/ ! 940: ! 941: LSEEK( ecrec.offset_start_central_directory ) ! 942: if (vflag) ! 943: error = list_files(); /* LIST 'EM */ ! 944: else ! 945: error = extract_or_test_files(); /* EXTRACT OR TEST 'EM */ ! 946: if (error > error_in_archive) /* don't overwrite stronger error */ ! 947: error_in_archive = error; /* with (for example) a warning */ ! 948: } else { ! 949: fprintf(stderr, "\nerror: zipfile is part of multi-disk archive \ ! 950: (sorry, not supported).\n"); ! 951: /* fprintf(stderr, "Please report to [email protected]\n"); */ ! 952: error_in_archive = 11; /* 11: no files found */ ! 953: } ! 954: ! 955: close(zipfd); ! 956: return error_in_archive; ! 957: ! 958: } /* end function process_zipfile() */ ! 959: ! 960: ! 961: ! 962: ! 963: ! 964: /************************************/ ! 965: /* Function find_end_central_dir() */ ! 966: /************************************/ ! 967: ! 968: int find_end_central_dir() /* return 0 if found, 1 otherwise */ ! 969: { ! 970: int i, numblks; ! 971: longint tail_len; ! 972: ! 973: ! 974: ! 975: /*--------------------------------------------------------------------------- ! 976: Treat case of short zipfile separately. ! 977: ---------------------------------------------------------------------------*/ ! 978: ! 979: if (ziplen <= INBUFSIZ) { ! 980: lseek(zipfd, 0L, SEEK_SET); ! 981: if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)ziplen)) == ! 982: (int)ziplen) ! 983: ! 984: /* 'P' must be at least 22 bytes from end of zipfile */ ! 985: for (inptr = inbuf+(int)ziplen-22; inptr >= inbuf; --inptr) ! 986: if ((ascii_to_native(*inptr) == 'P') && ! 987: !strncmp((char *)inptr, end_central_sig, 4)) { ! 988: incnt -= inptr - inbuf; ! 989: return 0; /* found it! */ ! 990: } /* ...otherwise fall through & fail */ ! 991: ! 992: /*--------------------------------------------------------------------------- ! 993: Zipfile is longer than INBUFSIZ: may need to loop. Start with short ! 994: block at end of zipfile (if not TOO short). ! 995: ---------------------------------------------------------------------------*/ ! 996: ! 997: } else { ! 998: if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) { ! 999: cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET); ! 1000: if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)tail_len)) != ! 1001: (int)tail_len) ! 1002: goto fail; /* shut up; it's expedient. */ ! 1003: ! 1004: /* 'P' must be at least 22 bytes from end of zipfile */ ! 1005: for (inptr = inbuf+(int)tail_len-22; inptr >= inbuf; --inptr) ! 1006: if ((ascii_to_native(*inptr) == 'P') && ! 1007: !strncmp((char *)inptr, end_central_sig, 4)) { ! 1008: incnt -= inptr - inbuf; ! 1009: return 0; /* found it */ ! 1010: } /* ...otherwise search next block */ ! 1011: strncpy((char *)hold, (char *)inbuf, 3); /* sig may span block ! 1012: boundary */ ! 1013: } else { ! 1014: cur_zipfile_bufstart = ziplen - tail_len; ! 1015: } ! 1016: ! 1017: /*----------------------------------------------------------------------- ! 1018: Loop through blocks of zipfile data, starting at the end and going ! 1019: toward the beginning. Need only check last 65557 bytes of zipfile: ! 1020: comment may be up to 65535 bytes long, end-of-central-directory rec- ! 1021: ord is 18 bytes (shouldn't hardcode this number, but what the hell: ! 1022: already did so above (22=18+4)), and sig itself is 4 bytes. ! 1023: -----------------------------------------------------------------------*/ ! 1024: ! 1025: numblks = (int) ! 1026: ((MIN(ziplen,65557L) - tail_len + (INBUFSIZ-1)) / INBUFSIZ); ! 1027: /* =amount to search= ==done== ==rounding== =blksiz= */ ! 1028: ! 1029: for (i = 1; i <= numblks; ++i) { ! 1030: cur_zipfile_bufstart -= INBUFSIZ; ! 1031: lseek(zipfd, cur_zipfile_bufstart, SEEK_SET); ! 1032: if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) != INBUFSIZ) ! 1033: break; /* fall through and fail */ ! 1034: ! 1035: for (inptr = inbuf+INBUFSIZ-1; inptr >= inbuf; --inptr) ! 1036: if ((ascii_to_native(*inptr) == 'P') && ! 1037: !strncmp((char *)inptr, end_central_sig, 4)) { ! 1038: incnt -= inptr - inbuf; ! 1039: return 0; /* found it */ ! 1040: } ! 1041: strncpy((char *)hold, (char *)inbuf, 3); /* sig may span block ! 1042: boundary */ ! 1043: } ! 1044: ! 1045: } /* end if (ziplen > INBUFSIZ) */ ! 1046: ! 1047: /*--------------------------------------------------------------------------- ! 1048: Searched through whole region where signature should be without finding ! 1049: it. Print informational message and die a horrible death. ! 1050: ---------------------------------------------------------------------------*/ ! 1051: ! 1052: fail: ! 1053: #ifdef MSWIN ! 1054: MessageBeep(1); ! 1055: #endif ! 1056: ! 1057: fprintf(stderr, "\nFile: %s\n\n\ ! 1058: End-of-central-directory signature not found. Either this file is not\n\ ! 1059: a zipfile, or it constitutes one disk of a multi-part archive. In the\n\ ! 1060: latter case the central directory and zipfile comment will be found on\n\ ! 1061: the last disk(s) of this archive.\n", zipfn); ! 1062: return 1; ! 1063: ! 1064: } /* end function find_end_central_dir() */ ! 1065: ! 1066: ! 1067: ! 1068: ! 1069: ! 1070: /***************************************/ ! 1071: /* Function process_end_central_dir() */ ! 1072: /***************************************/ ! 1073: ! 1074: int process_end_central_dir() /* return PK-type error code */ ! 1075: { ! 1076: ec_byte_rec byterec; ! 1077: int error=0; ! 1078: ! 1079: ! 1080: /*--------------------------------------------------------------------------- ! 1081: Read the end-of-central-directory record and do any necessary machine- ! 1082: type conversions (byte ordering, structure padding compensation) by ! 1083: reading data into character array, then copying to struct. ! 1084: ---------------------------------------------------------------------------*/ ! 1085: ! 1086: if (readbuf((char *) byterec, ECREC_SIZE+4) <= 0) ! 1087: return 51; ! 1088: ! 1089: ecrec.number_this_disk = ! 1090: makeword(&byterec[NUMBER_THIS_DISK]); ! 1091: ecrec.num_disk_with_start_central_dir = ! 1092: makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]); ! 1093: ecrec.num_entries_centrl_dir_ths_disk = ! 1094: makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]); ! 1095: ecrec.total_entries_central_dir = ! 1096: makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]); ! 1097: ecrec.size_central_directory = ! 1098: makelong(&byterec[SIZE_CENTRAL_DIRECTORY]); ! 1099: ecrec.offset_start_central_directory = ! 1100: makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]); ! 1101: ecrec.zipfile_comment_length = ! 1102: makeword(&byterec[ZIPFILE_COMMENT_LENGTH]); ! 1103: ! 1104: /*--------------------------------------------------------------------------- ! 1105: Get the zipfile comment, if any, and print it out. (Comment may be up ! 1106: to 64KB long. May the fleas of a thousand camels infest the armpits of ! 1107: anyone who actually takes advantage of this fact.) Then position the ! 1108: file pointer to the beginning of the central directory and fill buffer. ! 1109: ---------------------------------------------------------------------------*/ ! 1110: ! 1111: #ifdef MSWIN ! 1112: cchComment = ecrec.zipfile_comment_length; /* save for comment button */ ! 1113: if (ecrec.zipfile_comment_length && zflag) { ! 1114: #else /* !MSWIN */ ! 1115: if (ecrec.zipfile_comment_length && !quietflg) { ! 1116: if (!zflag) ! 1117: printf("[%s] comment:\n", zipfn); ! 1118: #endif /* ?MSWIN */ ! 1119: if (do_string(ecrec.zipfile_comment_length,DISPLAY)) { ! 1120: fprintf(stderr, "\ncaution: zipfile comment truncated\n"); ! 1121: error = 1; /* 1: warning error */ ! 1122: } ! 1123: } ! 1124: ! 1125: return error; ! 1126: ! 1127: } /* end function process_end_central_dir() */ ! 1128: ! 1129: ! 1130: ! 1131: ! 1132: ! 1133: /* also referenced in UpdateListBox() in updatelb.c (Windows version) */ ! 1134: char *Headers[][2] = { ! 1135: {" Length Date Time Name", ! 1136: " ------ ---- ---- ----"}, ! 1137: {" Length Method Size Ratio Date Time CRC-32 Name", ! 1138: " ------ ------ ---- ----- ---- ---- ------ ----"} ! 1139: }; ! 1140: ! 1141: /*************************/ ! 1142: /* Function list_files() */ ! 1143: /*************************/ ! 1144: ! 1145: int list_files() /* return PK-type error code */ ! 1146: { ! 1147: char **fnamev; ! 1148: int do_this_file=FALSE, ratio, error, error_in_archive=0; ! 1149: int which_hdr=(vflag>1), date_format; ! 1150: UWORD j, yr, mo, dy, hh, mm, members=0; ! 1151: ULONG tot_csize=0L, tot_ucsize=0L; ! 1152: #ifdef OS2 ! 1153: ULONG tot_easize=0L, tot_eafiles=0L, ea_size; ! 1154: #endif ! 1155: #ifdef MSWIN ! 1156: PSTR psLBEntry; /* list box entry */ ! 1157: #endif ! 1158: min_info info; ! 1159: static char *method[NUM_METHODS+1] = ! 1160: {"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4", ! 1161: "Implode", "Token", "Deflate", unkn}; ! 1162: ! 1163: ! 1164: ! 1165: /*--------------------------------------------------------------------------- ! 1166: Unlike extract_or_test_files(), this routine confines itself to the cen- ! 1167: tral directory. Thus its structure is somewhat simpler, since we can do ! 1168: just a single loop through the entire directory, listing files as we go. ! 1169: ! 1170: So to start off, print the heading line and then begin main loop through ! 1171: the central directory. The results will look vaguely like the following: ! 1172: ! 1173: Length Method Size Ratio Date Time CRC-32 Name ("^" ==> case ! 1174: ------ ------ ---- ----- ---- ---- ------ ---- conversion) ! 1175: 44004 Implode 13041 71% 11-02-89 19:34 8b4207f7 Makefile.UNIX ! 1176: 3438 Shrunk 2209 36% 09-15-90 14:07 a2394fd8 ^dos-file.ext ! 1177: ---------------------------------------------------------------------------*/ ! 1178: ! 1179: pInfo = &info; ! 1180: date_format = dateformat(); ! 1181: ! 1182: #ifndef MSWIN ! 1183: if (quietflg < 2) ! 1184: if (U_flag) ! 1185: printf("%s\n%s\n", Headers[which_hdr][0], Headers[which_hdr][1]); ! 1186: else ! 1187: printf("%s (\"^\" ==> case\n%s conversion)\n", ! 1188: Headers[which_hdr][0], Headers[which_hdr][1]); ! 1189: #endif /* !MSWIN */ ! 1190: ! 1191: for (j = 0; j < ecrec.total_entries_central_dir; ++j) { ! 1192: ! 1193: if (readbuf(sig, 4) <= 0) ! 1194: return 51; /* 51: unexpected EOF */ ! 1195: if (strncmp(sig, central_hdr_sig, 4)) { /* just to make sure */ ! 1196: fprintf(stderr, CentSigMsg, j); /* sig not found */ ! 1197: fprintf(stderr, ReportMsg); /* check binary transfers */ ! 1198: return 3; /* 3: error in zipfile */ ! 1199: } ! 1200: if ((error = process_cdir_file_hdr()) != 0) /* (sets pInfo->lcflag) */ ! 1201: return error; /* only 51 (EOF) defined */ ! 1202: ! 1203: /* ! 1204: * We could DISPLAY the filename instead of storing (and possibly trun- ! 1205: * cating, in the case of a very long name) and printing it, but that ! 1206: * has the disadvantage of not allowing case conversion--and it's nice ! 1207: * to be able to see in the listing precisely how you have to type each ! 1208: * filename in order for unzip to consider it a match. Speaking of ! 1209: * which, if member names were specified on the command line, check in ! 1210: * with match() to see if the current file is one of them, and make a ! 1211: * note of it if it is. ! 1212: */ ! 1213: ! 1214: if ((error = do_string(crec.filename_length, FILENAME)) != 0) { ! 1215: error_in_archive = error; /* ^--(uses pInfo->lcflag) */ ! 1216: if (error > 1) /* fatal: can't continue */ ! 1217: return error; ! 1218: } ! 1219: if (extra_field != (byte *)NULL) ! 1220: free(extra_field); ! 1221: extra_field = (byte *)NULL; ! 1222: if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0) { ! 1223: error_in_archive = error; ! 1224: if (error > 1) /* fatal: can't continue */ ! 1225: return error; ! 1226: } ! 1227: if (!process_all_files) { /* check if specified on command line */ ! 1228: do_this_file = FALSE; ! 1229: fnamev = fnv; /* don't destroy permanent filename ptr */ ! 1230: for (--fnamev; *++fnamev;) ! 1231: if (match(filename, *fnamev)) { ! 1232: do_this_file = TRUE; ! 1233: break; /* found match, so stop looping */ ! 1234: } ! 1235: } ! 1236: /* ! 1237: * If current file was specified on command line, or if no names were ! 1238: * specified, do the listing for this file. Otherwise, get rid of the ! 1239: * file comment and go back for the next file. ! 1240: */ ! 1241: ! 1242: if (process_all_files || do_this_file) { ! 1243: ! 1244: yr = (((crec.last_mod_file_date >> 9) & 0x7f) + 80) % (unsigned)100; ! 1245: mo = (crec.last_mod_file_date >> 5) & 0x0f; ! 1246: dy = crec.last_mod_file_date & 0x1f; ! 1247: ! 1248: /* twist date so it displays according to national convention */ ! 1249: switch (date_format) { ! 1250: case DF_YMD: ! 1251: hh = mo; mo = yr; yr = dy; dy = hh; break; ! 1252: case DF_DMY: ! 1253: hh = mo; mo = dy; dy = hh; ! 1254: } ! 1255: hh = (crec.last_mod_file_time >> 11) & 0x1f; ! 1256: mm = (crec.last_mod_file_time >> 5) & 0x3f; ! 1257: ! 1258: csize = (longint) crec.compressed_size; ! 1259: ucsize = (longint) crec.uncompressed_size; ! 1260: if (crec.general_purpose_bit_flag & 1) ! 1261: csize -= 12; /* if encrypted, don't count encrypt hdr */ ! 1262: ! 1263: ratio = (ucsize == 0) ? 0 : /* .zip can have 0-length members */ ! 1264: ((ucsize > 2000000L) ? /* risk signed overflow if mult. */ ! 1265: (int) ((ucsize-csize) / (ucsize/1000L)) + 5 : /* big */ ! 1266: (int) ((1000L*(ucsize-csize)) / ucsize) + 5); /* small */ ! 1267: ! 1268: #if 0 /* GRR/Euro: add this? define p above */ ! 1269: #if (defined(DOS_OS2) || (defined(UNIX) && !defined(VMS))) ! 1270: for (p = filename; *p; ++p) ! 1271: if (!isprint(*p)) ! 1272: *p = '?'; /* change non-printable chars to '?' */ ! 1273: #endif /* DOS_OS2 || UNIX */ ! 1274: #endif /* 0 */ ! 1275: ! 1276: #ifdef MSWIN ! 1277: #ifdef NEED_EARLY_REDRAW ! 1278: /* turn on listbox redrawing just before adding last line */ ! 1279: if (j == (ecrec.total_entries_central_dir-1)) ! 1280: (void)SendMessage(hWndList, WM_SETREDRAW, TRUE, 0L); ! 1281: #endif /* NEED_EARLY_REDRAW */ ! 1282: psLBEntry = ! 1283: (PSTR)LocalAlloc(LMEM_FIXED, FILNAMSIZ+LONG_FORM_FNAME_INX); ! 1284: switch (which_hdr) { ! 1285: case 0: /* short form */ ! 1286: OemToAnsi(filename, filename); /* translate to ANSI */ ! 1287: wsprintf(psLBEntry, "%7ld %02u-%02u-%02u %02u:%02u %c%s", ! 1288: (long)ucsize, mo, dy, yr, hh, mm, (pInfo->lcflag?'^':' '), ! 1289: (LPSTR)filename); ! 1290: SendMessage(hWndList, LB_ADDSTRING, 0, ! 1291: (LONG)(LPSTR)psLBEntry); ! 1292: break; ! 1293: case 1: /* verbose */ ! 1294: OemToAnsi(filename, filename); /* translate to ANSI */ ! 1295: wsprintf(psLBEntry, ! 1296: "%7ld %-7s%7ld %3d%% %02u-%02u-%02u %02u:%02u %08lx %c%s", ! 1297: (long)ucsize, (LPSTR)method[methnum], (long)csize, ! 1298: ratio/10, mo, dy, yr, hh, mm, (unsigned long)crec.crc32, ! 1299: (pInfo->lcflag?'^':' '), (LPSTR)filename); ! 1300: SendMessage(hWndList, LB_ADDSTRING, 0, ! 1301: (LONG)(LPSTR)psLBEntry); ! 1302: } ! 1303: LocalFree((HANDLE)psLBEntry); ! 1304: #else /* !MSWIN */ ! 1305: switch (which_hdr) { ! 1306: case 0: /* short form */ ! 1307: printf("%7ld %02u-%02u-%02u %02u:%02u %c%s\n", ! 1308: ucsize, mo, dy, yr, hh, mm, (pInfo->lcflag?'^':' '), ! 1309: filename); ! 1310: break; ! 1311: case 1: /* verbose */ ! 1312: printf( ! 1313: "%7ld %-7s%7ld %3d%% %02u-%02u-%02u %02u:%02u %08lx %c%s\n", ! 1314: ucsize, method[methnum], csize, ratio/10, mo, dy, yr, ! 1315: hh, mm, crec.crc32, (pInfo->lcflag?'^':' '), filename); ! 1316: } ! 1317: #endif /* ?MSWIN */ ! 1318: ! 1319: error = do_string(crec.file_comment_length, (QCOND? DISPLAY:SKIP)); ! 1320: if (error) { ! 1321: error_in_archive = error; /* might be just warning */ ! 1322: if (error > 1) /* fatal */ ! 1323: return error; ! 1324: } ! 1325: tot_ucsize += (ULONG) ucsize; ! 1326: tot_csize += (ULONG) csize; ! 1327: ++members; ! 1328: #ifdef OS2 ! 1329: if ((ea_size = SizeOfEAs(extra_field)) != 0) { ! 1330: tot_easize += ea_size; ! 1331: tot_eafiles++; ! 1332: } ! 1333: #endif ! 1334: } else { /* not listing this file */ ! 1335: SKIP_(crec.file_comment_length) ! 1336: } ! 1337: } /* end for-loop (j: files in central directory) */ ! 1338: ! 1339: /*--------------------------------------------------------------------------- ! 1340: Print footer line and totals (compressed size, uncompressed size, number ! 1341: of members in zipfile). ! 1342: ---------------------------------------------------------------------------*/ ! 1343: ! 1344: ratio = (tot_ucsize == 0) ? ! 1345: 0 : ((tot_ucsize > 4000000L) ? /* risk unsigned overflow if mult. */ ! 1346: (int) ((tot_ucsize - tot_csize) / (tot_ucsize/1000L)) + 5 : ! 1347: (int) ((tot_ucsize - tot_csize) * 1000L / tot_ucsize) + 5); ! 1348: ! 1349: if (quietflg < 2) { ! 1350: #ifdef MSWIN ! 1351: /* Display just the totals since the dashed lines get displayed ! 1352: * in UpdateListBox(). Get just enough space to display total. ! 1353: */ ! 1354: switch (which_hdr) { ! 1355: case 0: /* short */ ! 1356: wsprintf(lpumb->szTotalsLine, "%7lu %-7u", ! 1357: (ULONG)tot_ucsize, members); ! 1358: break; ! 1359: case 1: /* verbose */ ! 1360: wsprintf(lpumb->szTotalsLine, ! 1361: "%7lu %7lu %3d%% %-7u", ! 1362: (ULONG)tot_ucsize, (ULONG)tot_csize, ratio / 10, members); ! 1363: break; ! 1364: } ! 1365: #else /* !MSWIN */ ! 1366: switch (which_hdr) { ! 1367: case 0: /* short */ ! 1368: printf("%s\n%7lu %-7u\n", ! 1369: " ------ -------", ! 1370: tot_ucsize, members); ! 1371: break; ! 1372: case 1: /* verbose */ ! 1373: printf( ! 1374: "%s\n%7lu %7lu %3d%% %-7u\n", ! 1375: " ------ ------ --- -------", ! 1376: tot_ucsize, tot_csize, ratio / 10, members); ! 1377: } ! 1378: #endif /* ?MSWIN */ ! 1379: #ifdef OS2 ! 1380: if (tot_eafiles && tot_easize) ! 1381: printf("\n%ld file%s %ld bytes of EA's attached.\n", tot_eafiles, ! 1382: tot_eafiles == 1 ? " has" : "s have a total of", tot_easize); ! 1383: #endif ! 1384: } ! 1385: /*--------------------------------------------------------------------------- ! 1386: Double check that we're back at the end-of-central-directory record. ! 1387: ---------------------------------------------------------------------------*/ ! 1388: ! 1389: readbuf(sig, 4); ! 1390: if (strncmp(sig, end_central_sig, 4)) { /* just to make sure again */ ! 1391: fprintf(stderr, EndSigMsg); /* didn't find end-of-central-dir sig */ ! 1392: /* fprintf(stderr, ReportMsg); */ ! 1393: error_in_archive = 1; /* 1: warning error */ ! 1394: } ! 1395: return error_in_archive; ! 1396: ! 1397: } /* end function list_files() */ ! 1398: ! 1399: ! 1400: ! 1401: ! 1402: ! 1403: /**************************************/ ! 1404: /* Function process_cdir_file_hdr() */ ! 1405: /**************************************/ ! 1406: ! 1407: int process_cdir_file_hdr() /* return PK-type error code */ ! 1408: { ! 1409: cdir_byte_hdr byterec; ! 1410: ! 1411: ! 1412: /*--------------------------------------------------------------------------- ! 1413: Read the next central directory entry and do any necessary machine-type ! 1414: conversions (byte ordering, structure padding compensation--do so by ! 1415: copying the data from the array into which it was read (byterec) to the ! 1416: usable struct (crec)). ! 1417: ---------------------------------------------------------------------------*/ ! 1418: ! 1419: if (readbuf((char *) byterec, CREC_SIZE) <= 0) ! 1420: return 51; /* 51: unexpected EOF */ ! 1421: ! 1422: crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0]; ! 1423: crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1]; ! 1424: crec.version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0]; ! 1425: crec.version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1]; ! 1426: ! 1427: crec.general_purpose_bit_flag = ! 1428: makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]); ! 1429: crec.compression_method = ! 1430: makeword(&byterec[C_COMPRESSION_METHOD]); ! 1431: crec.last_mod_file_time = ! 1432: makeword(&byterec[C_LAST_MOD_FILE_TIME]); ! 1433: crec.last_mod_file_date = ! 1434: makeword(&byterec[C_LAST_MOD_FILE_DATE]); ! 1435: crec.crc32 = ! 1436: makelong(&byterec[C_CRC32]); ! 1437: crec.compressed_size = ! 1438: makelong(&byterec[C_COMPRESSED_SIZE]); ! 1439: crec.uncompressed_size = ! 1440: makelong(&byterec[C_UNCOMPRESSED_SIZE]); ! 1441: crec.filename_length = ! 1442: makeword(&byterec[C_FILENAME_LENGTH]); ! 1443: crec.extra_field_length = ! 1444: makeword(&byterec[C_EXTRA_FIELD_LENGTH]); ! 1445: crec.file_comment_length = ! 1446: makeword(&byterec[C_FILE_COMMENT_LENGTH]); ! 1447: crec.disk_number_start = ! 1448: makeword(&byterec[C_DISK_NUMBER_START]); ! 1449: crec.internal_file_attributes = ! 1450: makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]); ! 1451: crec.external_file_attributes = ! 1452: makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */ ! 1453: crec.relative_offset_local_header = ! 1454: makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]); ! 1455: ! 1456: pInfo->hostnum = MIN(crec.version_made_by[1], NUM_HOSTS); ! 1457: /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */ ! 1458: methnum = MIN(crec.compression_method, NUM_METHODS); ! 1459: if (methnum == NUM_METHODS) ! 1460: sprintf(unkn, "Unk:%03d", crec.compression_method); ! 1461: ! 1462: /*--------------------------------------------------------------------------- ! 1463: Set flag for lowercase conversion of filename, depending on which OS the ! 1464: file is coming from. This section could be ifdef'd if some people have ! 1465: come to love DOS uppercase filenames under Unix...but really, guys, get ! 1466: a life. :) NOTE THAT ALL SYSTEM NAMES NOW HAVE TRAILING UNDERSCORES!!! ! 1467: This is to prevent interference with compiler command-line defines such ! 1468: as -DUNIX, for example, which are then used in "#ifdef UNIX" constructs. ! 1469: ---------------------------------------------------------------------------*/ ! 1470: ! 1471: pInfo->lcflag = 0; ! 1472: if (!U_flag) /* as long as user hasn't specified case-preservation */ ! 1473: switch (pInfo->hostnum) { ! 1474: case DOS_OS2_FAT_: ! 1475: /* case VMS_: VMS Zip converts filenames to lowercase */ ! 1476: case VM_CMS_: /* all caps? */ ! 1477: case CPM_: /* like DOS, right? */ ! 1478: /* case ATARI_: ? */ ! 1479: /* case Z_SYSTEM_: ? */ ! 1480: /* case TOPS20_: (if we had such a thing...) */ ! 1481: pInfo->lcflag = 1; /* convert filename to lowercase */ ! 1482: break; ! 1483: ! 1484: default: /* AMIGA_, UNIX_, (ATARI_), OS2_HPFS_, */ ! 1485: break; /* MAC_, (Z_SYSTEM_): no conversion */ ! 1486: } ! 1487: ! 1488: return 0; ! 1489: ! 1490: } /* end function process_cdir_file_hdr() */ ! 1491: ! 1492: ! 1493: ! 1494: ! 1495: ! 1496: /***************************************/ ! 1497: /* Function process_local_file_hdr() */ ! 1498: /***************************************/ ! 1499: ! 1500: int process_local_file_hdr() /* return PK-type error code */ ! 1501: { ! 1502: local_byte_hdr byterec; ! 1503: ! 1504: ! 1505: /*--------------------------------------------------------------------------- ! 1506: Read the next local file header and do any necessary machine-type con- ! 1507: versions (byte ordering, structure padding compensation--do so by copy- ! 1508: ing the data from the array into which it was read (byterec) to the ! 1509: usable struct (lrec)). ! 1510: ---------------------------------------------------------------------------*/ ! 1511: ! 1512: if (readbuf((char *) byterec, LREC_SIZE) <= 0) ! 1513: return 51; /* 51: unexpected EOF */ ! 1514: ! 1515: lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0]; ! 1516: lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1]; ! 1517: ! 1518: lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]); ! 1519: lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]); ! 1520: lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]); ! 1521: lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]); ! 1522: lrec.crc32 = makelong(&byterec[L_CRC32]); ! 1523: lrec.compressed_size = makelong(&byterec[L_COMPRESSED_SIZE]); ! 1524: lrec.uncompressed_size = makelong(&byterec[L_UNCOMPRESSED_SIZE]); ! 1525: lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]); ! 1526: lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]); ! 1527: ! 1528: csize = (longint) lrec.compressed_size; ! 1529: ucsize = (longint) lrec.uncompressed_size; ! 1530: ! 1531: if ((lrec.general_purpose_bit_flag & 8) != 0) { ! 1532: /* Can't trust local header, use central directory: */ ! 1533: lrec.crc32 = pInfo->crc; ! 1534: lrec.compressed_size = pInfo->compr_size; ! 1535: csize = (longint) lrec.compressed_size; ! 1536: } ! 1537: ! 1538: return 0; /* 0: no error */ ! 1539: ! 1540: } /* end function process_local_file_hdr() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.