|
|
1.1 ! root 1: /*--------------------------------------------------------------------------- ! 2: ! 3: zipinfo.c ! 4: ! 5: This program reads all sorts of totally nifty information, including the ! 6: central directory stuff, from a ZIP archive ("zipfile" for short). It ! 7: started as just a testbed for fooling with zipfiles, but at this point ! 8: it's actually a moderately useful utility. It also became the basis ! 9: for the rewrite of unzip (3.16 -> 4.0), using the central directory for ! 10: processing rather than the individual (local) file headers. ! 11: ! 12: For myself, I find it convenient to define an alias "ii" (under Unix and ! 13: VMS) or to rename the executable to "ii.exe" (OS/2 and DOS). This nicely ! 14: complements my Unix long-listing "ll" alias (ls -lF), since zipinfo's de- ! 15: fault action is to produce a Unix-like listing of the archive's contents. ! 16: "ii zipfile" is easier to type than "zipinfo zipfile"... ! 17: ! 18: Another dandy product from your buddies at Newtware! ! 19: ! 20: --------------------------------------------------------------------------- ! 21: ! 22: To compile (partial instructions; some of this stuff doesn't exist yet): ! 23: ! 24: under Unix (cc): make zipinfo ! 25: ! 26: under MS-DOS (TurboC): make -fMKZIPINF.DOS (edit appropriately) ! 27: ! 28: under MS-DOS (MSC): make MKZIPINF.DOS ! 29: (or use Makefile if you have MSC 6.0: "nmake zi_dos") ! 30: ! 31: under OS/2 (MSC): make MKZIPINF.DOS (edit appropriately) ! 32: (or use Makefile if you have MSC 6.0: "nmake zi_os2") ! 33: ! 34: under Atari OS: beats me... ! 35: ! 36: under VMS: @MAKE_ZIPINFO (see also VMSNOTES) ! 37: ZIPINFO == $DISKNAME:[DIRECTORY]ZIPINFO.EXE ! 38: ! 39: under Macintosh OS: who knows? ! 40: ! 41: --------------------------------------------------------------------------- ! 42: ! 43: Source: unz50p1.zip (.tar.Z, etc.) for Unix, VMS, OS/2 and MS-DOS; see ! 44: `Where' in source distribution for ftp, uucp and mail-server ! 45: sites. ! 46: Author: Greg Roelofs, [email protected], 23 August 1990 ! 47: Copyright: Portions copyright 1992 Greg Roelofs. Portions adapted from ! 48: unzip 3.1. SizeOfEAs() by Kai Uwe Rommel. ! 49: ! 50: ---------------------------------------------------------------------------*/ ! 51: ! 52: ! 53: ! 54: ! 55: #ifndef ZIPINFO ! 56: # define ZIPINFO /* needed for Unix permissions in non-Unix environments */ ! 57: #endif /* !ZIPINFO */ ! 58: #include "unzip.h" ! 59: ! 60: #define VERSION "v1.0p1 of 10 January 1993" ! 61: ! 62: #define LFLAG 3 /* for short "ls -l" type listing */ ! 63: ! 64: #define EAID 0x0009 /* OS/2 EA extra field ID */ ! 65: typedef struct { /* for OS/2 info in OS/2 and non-OS/2 environments */ ! 66: unsigned short nID; ! 67: unsigned short nSize; ! 68: ULONG lSize; ! 69: } EAHEADER, *PEAHEADER; ! 70: ! 71: ! 72: ! 73: ! 74: /**********************/ ! 75: /* Global Variables */ ! 76: /**********************/ ! 77: ! 78: #ifdef EBCDIC ! 79: int aflag=1; /* this is so you can read it on the screen */ ! 80: #else /* (basically, entire program is "unzip -c") */ ! 81: int aflag=0; ! 82: #endif ! 83: int lflag=(-1); /* '-1slmv': listing format */ ! 84: int hflag=0; /* '-h': header line */ ! 85: int tflag=0; /* '-t': totals line */ ! 86: ! 87: byte *inbuf, *inptr; /* input buffer (any size is legal) and pointer */ ! 88: int incnt; ! 89: ! 90: int zipfd; /* zipfile file handle */ ! 91: char zipfn[FILNAMSIZ]; ! 92: ! 93: char local_hdr_sig[5] = "\120"; /* remaining signature bytes come later: */ ! 94: char central_hdr_sig[5] = "\120"; /* must initialize at runtime so zipinfo */ ! 95: char end_central_sig[5] = "\120"; /* executable won't look like a zipfile */ ! 96: char extd_local_sig[5] = "\120"; ! 97: ! 98: cdir_file_hdr crec; /* used in zipinfo.c, misc.c */ ! 99: local_file_hdr lrec; ! 100: ecdir_rec ecrec; ! 101: struct stat statbuf; /* used by main() */ ! 102: ! 103: int process_all_files; ! 104: longint real_ecrec_offset, expect_ecrec_offset; ! 105: longint extra_bytes=0; /* used in zipinfo.c, misc.c */ ! 106: longint cur_zipfile_bufstart; /* find_end_central_dir, readbuf */ ! 107: ! 108: min_info info, *pInfo=(&info); ! 109: ! 110: byte *extra_field = NULL; /* used by VMS, Mac and OS/2 versions */ ! 111: byte *outbuf; /* buffer for rle look-back, zipfile comment */ ! 112: byte *outout; /* scratch pad for ASCII-native trans */ ! 113: ! 114: char filename[FILNAMSIZ]; ! 115: char sig[5]; ! 116: char *fnames[2] = {"*", NULL}; /* default filenames vector */ ! 117: char **fnv = fnames; ! 118: ! 119: static byte *hold; ! 120: static longint ziplen; ! 121: static UWORD hostnum; ! 122: static UWORD methnum; ! 123: static UWORD extnum; ! 124: ! 125: char *EndSigMsg = "\nwarning:\ ! 126: didn't find end-of-central-dir signature at end of central dir.\n"; ! 127: char *CentSigMsg = ! 128: "error: expected central file header signature not found (file #%u).\n"; ! 129: char *SeekMsg = ! 130: "error: attempt to seek before beginning of zipfile\n%s"; ! 131: ! 132: #ifdef VMS ! 133: char *ReportMsg = "\ ! 134: (please check that you have transferred or created the zipfile in the\n\ ! 135: appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n"; ! 136: #else /* !VMS */ ! 137: char *ReportMsg = "\ ! 138: (please check that you have transferred or created the zipfile in the\n\ ! 139: appropriate BINARY mode and that you have compiled unzip properly)\n"; ! 140: #endif /* ?VMS */ ! 141: ! 142: ! 143: ! 144: ! 145: ! 146: ! 147: /******************/ ! 148: /* Main program */ ! 149: /******************/ ! 150: ! 151: main(argc, argv) ! 152: int argc; ! 153: char *argv[]; ! 154: { ! 155: char *s; ! 156: int c, error=FALSE, negative=0; ! 157: int hflag_slmv=TRUE, hflag_1=FALSE; /* diff options => diff defaults */ ! 158: int tflag_slm=TRUE, tflag_1v=FALSE; ! 159: int explicit_h=FALSE, explicit_t=FALSE; ! 160: ! 161: ! 162: ! 163: /*--------------------------------------------------------------------------- ! 164: Everybody is now "NOTINT16," but this is a nice little piece of code, so ! 165: just comment it out for future reference. :-) ! 166: ---------------------------------------------------------------------------*/ ! 167: ! 168: #if 0 ! 169: # ifndef KNOW_IT_WORKS /* define this to save space, if things already work */ ! 170: # ifndef DOS_OS2 /* already works (no RISCy OS/2's yet...) */ ! 171: # ifndef NOTINT16 /* whole point is to see if this NEEDS defining */ ! 172: { ! 173: int error=0; ! 174: long testsig; ! 175: static char *mach_type[3] = {"big-endian", "structure-padding", ! 176: "big-endian and structure-padding"}; ! 177: ! 178: strcpy((char *)&testsig,"012"); ! 179: if (testsig != 0x00323130) ! 180: error = 1; ! 181: if (sizeof(cdir_file_hdr) != CREC_SIZE) ! 182: error += 2; ! 183: if (error--) ! 184: fprintf(stderr, "It appears that your machine is %s. If errors\n\ ! 185: occur, please try recompiling with \"NOTINT16\" defined (read the\n\ ! 186: Makefile, or try \"make zipinfo\").\n\n", mach_type[error]); ! 187: } ! 188: # endif /* !NOTINT16 */ ! 189: # endif /* !DOS_OS2 */ ! 190: # endif /* !KNOW_IT_WORKS */ ! 191: #endif /* 0 */ ! 192: ! 193: /*--------------------------------------------------------------------------- ! 194: Put environment-variable options into the queue, then rip through any ! 195: command-line options lurking about... ! 196: ---------------------------------------------------------------------------*/ ! 197: ! 198: envargs(&argc, &argv, ENV_ZIPINFO); ! 199: ! 200: while (--argc > 0 && (*++argv)[0] == '-') { ! 201: s = argv[0] + 1; ! 202: while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */ ! 203: switch (c) { ! 204: case '-': ! 205: ++negative; ! 206: break; ! 207: case '1': /* shortest listing: just filenames */ ! 208: if (negative) ! 209: lflag = -2, negative = 0; ! 210: else ! 211: lflag = 1; ! 212: break; ! 213: case 'h': /* header line */ ! 214: if (negative) ! 215: hflag_1 = hflag_slmv = FALSE, negative = 0; ! 216: else { ! 217: hflag_1 = hflag_slmv = explicit_h = TRUE; ! 218: if (lflag == -1) ! 219: lflag = 0; ! 220: } ! 221: break; ! 222: case 'l': /* longer form of "ls -l" type listing */ ! 223: if (negative) ! 224: lflag = -2, negative = 0; ! 225: else ! 226: lflag = 5; ! 227: break; ! 228: case 'm': /* medium form of "ls -l" type listing */ ! 229: if (negative) ! 230: lflag = -2, negative = 0; ! 231: else ! 232: lflag = 4; ! 233: break; ! 234: case 's': /* default: shorter "ls -l" type listing */ ! 235: if (negative) ! 236: lflag = -2, negative = 0; ! 237: else ! 238: lflag = 3; ! 239: break; ! 240: case 't': /* totals line */ ! 241: if (negative) ! 242: tflag_1v = tflag_slm = FALSE, negative = 0; ! 243: else { ! 244: tflag_1v = tflag_slm = explicit_t = TRUE; ! 245: if (lflag == -1) ! 246: lflag = 0; ! 247: } ! 248: break; ! 249: case 'v': /* turbo-verbose listing */ ! 250: if (negative) ! 251: lflag = -2, negative = 0; ! 252: else ! 253: lflag = 10; ! 254: break; ! 255: default: ! 256: error = TRUE; ! 257: break; ! 258: } ! 259: } ! 260: } ! 261: if ((argc-- == 0) || error) ! 262: RETURN(usage(error)); ! 263: ! 264: if (argc != 0) ! 265: process_all_files = FALSE; ! 266: else ! 267: process_all_files = TRUE; /* for speed */ ! 268: ! 269: /* if no listing options given (or all negated), or if only -h/-t given ! 270: * with individual files specified, use default listing format */ ! 271: if ((lflag < 0) || (!process_all_files && (lflag == 0))) ! 272: lflag = LFLAG; ! 273: ! 274: /* set header and totals flags to default or specified values */ ! 275: switch (lflag) { ! 276: case 0: /* 0: can only occur if either -t or -h explicitly given; */ ! 277: case 1: /* therefore set both flags equal to normally false value */ ! 278: hflag = hflag_1; ! 279: tflag = tflag_1v; ! 280: break; ! 281: case 3: ! 282: case 4: ! 283: case 5: ! 284: hflag = (!process_all_files && !explicit_h)? FALSE : hflag_slmv; ! 285: tflag = (!process_all_files && !explicit_t)? FALSE : tflag_slm; ! 286: break; ! 287: case 10: ! 288: hflag = hflag_slmv; ! 289: tflag = tflag_1v; ! 290: break; ! 291: } ! 292: ! 293: /*--------------------------------------------------------------------------- ! 294: Now get the zipfile name from the command line and see if it exists as a ! 295: regular (non-directory) file. If not, append the ".zip" suffix. We don't ! 296: immediately check to see if this results in a good name, but we will do so ! 297: later. In the meantime, see if there are any member filespecs on the com- ! 298: mand line, and if so, set the filename pointer to point at them. ! 299: ---------------------------------------------------------------------------*/ ! 300: ! 301: strcpy(zipfn, *argv++); ! 302: if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR) ! 303: strcat(zipfn, ZSUFX); ! 304: #if defined(UNIX) && !defined(VMS) /* Unix executables have no extension-- */ ! 305: else if (statbuf.st_mode & S_IXUSR) /* might find zip, not zip.zip; etc */ ! 306: fprintf(stderr, "\nnote: file [ %s ] may be an executable\n\n", zipfn); ! 307: #endif /* UNIX && !VMS */ ! 308: ! 309: if (stat(zipfn, &statbuf)) { /* try again */ ! 310: fprintf(stderr, "error: can't find zipfile [ %s ]\n", zipfn); ! 311: RETURN(9); /* 9: file not found */ ! 312: } else ! 313: ziplen = statbuf.st_size; ! 314: ! 315: if (!process_all_files) ! 316: fnv = argv; ! 317: ! 318: /*--------------------------------------------------------------------------- ! 319: Okey dokey, we have everything we need to get started. Let's roll. ! 320: ---------------------------------------------------------------------------*/ ! 321: ! 322: inbuf = (byte *) (malloc(INBUFSIZ + 4)); /* 4 extra for hold[] (below) */ ! 323: outbuf = (byte *) (malloc(OUTBUFSIZ + 1)); /* 1 extra for string termin. */ ! 324: if (aflag) /* if need an ascebc scratch, */ ! 325: outout = (byte *) (malloc(OUTBUFSIZ)); ! 326: else /* allocate it... */ ! 327: outout = outbuf; /* else just point to outbuf */ ! 328: ! 329: if ((inbuf == NULL) || (outbuf == NULL) || (outout == NULL)) { ! 330: fprintf(stderr, "error: can't allocate zipinfo buffers\n"); ! 331: RETURN(4); /* 4-8: insufficient memory */ ! 332: } ! 333: hold = &inbuf[INBUFSIZ]; /* to check for boundary-spanning signatures */ ! 334: ! 335: RETURN(process_zipfile()); /* keep passing errors back... */ ! 336: ! 337: } /* end main() */ ! 338: ! 339: ! 340: ! 341: ! 342: ! 343: /**********************/ ! 344: /* Function usage() */ ! 345: /**********************/ ! 346: ! 347: int usage(error) ! 348: int error; ! 349: { ! 350: FILE *usagefp; ! 351: ! 352: ! 353: /*--------------------------------------------------------------------------- ! 354: If user requested usage, send it to stdout; else send to stderr. ! 355: ---------------------------------------------------------------------------*/ ! 356: ! 357: if (error) ! 358: usagefp = (FILE *) stderr; ! 359: else ! 360: usagefp = (FILE *) stdout; ! 361: ! 362: fprintf(usagefp, "\ ! 363: ZipInfo: Zipfile Information Utility %s\n\ ! 364: (brought to you by Newtware, Inc., and the fine folks at Info-ZIP)\n\n\ ! 365: Usage: zipinfo [-1smlvht] file[.zip] [filespec...]\n", VERSION); ! 366: fprintf(usagefp, "\ ! 367: -1 list filenames only, one per line (useful for pipes)\n\ ! 368: -s list zipfile info in short Unix \"ls -l\" format: default\n\ ! 369: -m list zipfile info in medium Unix \"ls -l\" format\n\ ! 370: -l list zipfile info in long Unix \"ls -l\" format\n\ ! 371: -v list zipfile information in verbose, multi-page format\n\ ! 372: -h list header line\n\ ! 373: -t list totals for files listed or for all files\n"); ! 374: /* ! 375: -p disable automatic \"more\" function (for pipes) [not implemented]\n"); ! 376: */ ! 377: ! 378: #ifdef VMS ! 379: fprintf(usagefp, "\nRemember that non-lowercase filespecs must be quoted\ ! 380: in VMS (e.g., \"Makefile\").\n"); ! 381: #endif ! 382: ! 383: if (error) ! 384: return 10; /* 10: bad or illegal parameters specified */ ! 385: else ! 386: return 0; /* just wanted usage screen: no error */ ! 387: ! 388: } /* end function usage() */ ! 389: ! 390: ! 391: ! 392: ! 393: ! 394: /********************************/ ! 395: /* Function process_zipfile() */ ! 396: /********************************/ ! 397: ! 398: int process_zipfile() /* return PK-type error code */ ! 399: { ! 400: int error=0, error_in_archive; ! 401: ! 402: ! 403: /*--------------------------------------------------------------------------- ! 404: Open the zipfile for reading and in BINARY mode to prevent CR/LF trans- ! 405: lation, which would corrupt the bitstreams. ! 406: ---------------------------------------------------------------------------*/ ! 407: ! 408: #ifdef VMS ! 409: if (check_format()) /* check for variable-length format */ ! 410: return 2; /* 2: error in zipfile */ ! 411: #endif /* VMS */ ! 412: ! 413: if (open_input_file()) /* this should never happen, given the */ ! 414: return 9; /* stat() test in main(), but... */ ! 415: ! 416: /*--------------------------------------------------------------------------- ! 417: Reconstruct the various PK signature strings, and find and process the ! 418: end-of-central-directory header. ! 419: ---------------------------------------------------------------------------*/ ! 420: ! 421: strcat(local_hdr_sig, LOCAL_HDR_SIG); ! 422: strcat(central_hdr_sig, CENTRAL_HDR_SIG); ! 423: strcat(end_central_sig, END_CENTRAL_SIG); ! 424: strcat(extd_local_sig, EXTD_LOCAL_SIG); ! 425: ! 426: if (find_end_central_dir()) { /* not found; nothing to do */ ! 427: close(zipfd); ! 428: return 2; /* 2: error in zipfile */ ! 429: } ! 430: ! 431: real_ecrec_offset = cur_zipfile_bufstart + (inptr-inbuf); ! 432: #ifdef TEST ! 433: printf("\n found end-of-central-dir signature at offset %ld (%.8lXh)\n", ! 434: real_ecrec_offset, real_ecrec_offset); ! 435: printf(" from beginning of file; offset %d (%.4Xh) within block\n", ! 436: inptr-inbuf, inptr-inbuf); ! 437: #endif ! 438: ! 439: /* sets expect_ecrec_offset: */ ! 440: if ((error_in_archive = process_end_central_dir()) > 1) { ! 441: close(zipfd); ! 442: return error_in_archive; ! 443: } ! 444: ! 445: /*--------------------------------------------------------------------------- ! 446: Test the end-of-central-directory info for incompatibilities (multi-disk ! 447: archives) or inconsistencies (missing or extra bytes in zipfile). ! 448: ---------------------------------------------------------------------------*/ ! 449: ! 450: if (ecrec.number_this_disk != ecrec.num_disk_with_start_central_dir) { ! 451: fprintf(stderr, "\n\ ! 452: Zipfile is part of a multi-disk archive, and this is not the disk on\ ! 453: which the central zipfile directory begins.\n"); ! 454: error_in_archive = 11; /* 11: no files found */ ! 455: } else { ! 456: if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) { ! 457: fprintf(stderr, "\nerror: missing %ld bytes in zipfile (\ ! 458: attempting to process anyway)\n\n", -extra_bytes); ! 459: error_in_archive = 2; /* 2: (weak) error in zipfile */ ! 460: } else if (extra_bytes > 0) { ! 461: if ((ecrec.offset_start_central_directory == 0) && ! 462: (ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */ ! 463: { ! 464: fprintf(stderr, "\nerror: NULL central directory offset (\ ! 465: attempting to process anyway)\n\n"); ! 466: error_in_archive = 2; /* 2: (weak) error in zipfile */ ! 467: } else { ! 468: fprintf(stderr, "\nwarning: extra %ld bytes at beginning or\ ! 469: within zipfile\n (attempting to process anyway)\n\n", extra_bytes); ! 470: error_in_archive = 1; /* 1: warning error */ ! 471: } ! 472: } ! 473: ! 474: /*----------------------------------------------------------------------- ! 475: Check for empty zipfile and exit now if so. ! 476: -----------------------------------------------------------------------*/ ! 477: ! 478: if (expect_ecrec_offset == 0L && ecrec.size_central_directory == 0) { ! 479: printf("%sEmpty zipfile.\n", lflag>9 ? "\n " : ""); ! 480: close(zipfd); ! 481: return (error_in_archive > 1)? error_in_archive : 1; ! 482: } ! 483: ! 484: /*----------------------------------------------------------------------- ! 485: Compensate for missing or extra bytes, and seek to where the start ! 486: of central directory should be. If header not found, uncompensate ! 487: and try again (necessary for at least some Atari archives created ! 488: with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT). ! 489: -----------------------------------------------------------------------*/ ! 490: ! 491: LSEEK( ecrec.offset_start_central_directory ) ! 492: if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) { ! 493: longint tmp = extra_bytes; ! 494: ! 495: extra_bytes = 0; ! 496: LSEEK( ecrec.offset_start_central_directory ) ! 497: if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) { ! 498: fprintf(stderr, ! 499: "error: start of central directory not found; zipfile corrupt.\n"); ! 500: fprintf(stderr, ReportMsg); ! 501: close(zipfd); ! 502: return 3; /* 3: severe error in zipfile */ ! 503: } ! 504: fprintf(stderr, "error: reported length of central directory is \ ! 505: %d bytes too\n long (Atari STZIP zipfile? J.H. Holm ZIPSPLIT zipfile?)\ ! 506: .\n Compensating...\n\n", -tmp); ! 507: error_in_archive = 2; /* 2: (weak) error in zipfile */ ! 508: } ! 509: ! 510: /*----------------------------------------------------------------------- ! 511: Seek to the start of the central directory one last time, since we ! 512: have just read the first entry's signature bytes; then do the central ! 513: directory and close the zipfile. ! 514: -----------------------------------------------------------------------*/ ! 515: ! 516: LSEEK( ecrec.offset_start_central_directory ) ! 517: if ((error = process_central_dir()) > error_in_archive) ! 518: error_in_archive = error; /* don't overwrite stronger error */ ! 519: if (lflag > 9) ! 520: printf("\n"); ! 521: } ! 522: ! 523: close(zipfd); ! 524: return error_in_archive; ! 525: ! 526: } /* end function process_zipfile() */ ! 527: ! 528: ! 529: ! 530: ! 531: ! 532: /*************************************/ ! 533: /* Function find_end_central_dir() */ ! 534: /*************************************/ ! 535: ! 536: int find_end_central_dir() /* return 0 if found, 1 otherwise */ ! 537: { ! 538: int i, numblks; ! 539: longint tail_len; ! 540: ! 541: ! 542: ! 543: /*--------------------------------------------------------------------------- ! 544: Treat case of short zipfile separately. ! 545: ---------------------------------------------------------------------------*/ ! 546: ! 547: if (ziplen <= INBUFSIZ) { ! 548: lseek(zipfd, 0L, SEEK_SET); ! 549: if ((incnt = read(zipfd,inbuf,(unsigned int)ziplen)) == (int)ziplen) ! 550: /* 'P' must be at least 22 bytes from end of zipfile */ ! 551: for (inptr = inbuf+(int)ziplen-22; inptr >= inbuf; --inptr) ! 552: if ((ascii_to_native(*inptr) == 'P') && ! 553: !strncmp((char *)inptr, end_central_sig, 4)) { ! 554: incnt -= inptr - inbuf; ! 555: return 0; /* found it! */ ! 556: } /* ...otherwise fall through & fail */ ! 557: ! 558: /*--------------------------------------------------------------------------- ! 559: Zipfile is longer than INBUFSIZ: may need to loop. Start with short ! 560: block at end of zipfile (if not TOO short). ! 561: ---------------------------------------------------------------------------*/ ! 562: ! 563: } else { ! 564: if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) { ! 565: cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET); ! 566: if ((incnt = read(zipfd,inbuf,(unsigned int)tail_len)) != ! 567: (int)tail_len) ! 568: goto fail; /* shut up; it's expedient. */ ! 569: ! 570: /* 'P' must be at least 22 bytes from end of zipfile */ ! 571: for (inptr = inbuf+(int)tail_len-22; inptr >= inbuf; --inptr) ! 572: if ((ascii_to_native(*inptr) == 'P') && ! 573: !strncmp((char *)inptr, end_central_sig, 4)) { ! 574: incnt -= inptr - inbuf; ! 575: return 0; /* found it */ ! 576: } /* ...otherwise search next block */ ! 577: /* sig may span block boundary: */ ! 578: strncpy((char *)hold, (char *)inbuf, 3); ! 579: } else ! 580: cur_zipfile_bufstart = ziplen - tail_len; ! 581: ! 582: /* ! 583: * Loop through blocks of zipfile data, starting at the end and going ! 584: * toward the beginning. Need only check last 65557 bytes of zipfile: ! 585: * comment may be up to 65535 bytes long, end-of-central-directory rec- ! 586: * ord is 18 bytes (shouldn't hardcode this number, but what the hell: ! 587: * already did so above (22=18+4)), and sig itself is 4 bytes. ! 588: * ! 589: * zipinfo: check the whole file, just in case some transfer protocol ! 590: * has appended a whole bunch of garbage at the end of the archive. ! 591: * ! 592: * =todo= ==done== ==rounding== =blksiz= */ ! 593: numblks = (int) ((ziplen - tail_len + (INBUFSIZ-1)) / INBUFSIZ); ! 594: ! 595: for (i = 1; i <= numblks; ++i) { ! 596: cur_zipfile_bufstart -= INBUFSIZ; ! 597: lseek(zipfd, cur_zipfile_bufstart, SEEK_SET); ! 598: if ((incnt = read(zipfd,inbuf,INBUFSIZ)) != INBUFSIZ) ! 599: break; /* fall through and fail */ ! 600: ! 601: for (inptr = inbuf+INBUFSIZ-1; inptr >= inbuf; --inptr) ! 602: if ((ascii_to_native(*inptr) == 'P') && ! 603: !strncmp((char *)inptr, end_central_sig, 4)) { ! 604: incnt -= inptr - inbuf; ! 605: return 0; /* found it */ ! 606: } ! 607: /* sig may span block boundary: */ ! 608: strncpy((char *)hold, (char *)inbuf, 3); ! 609: } ! 610: ! 611: } /* end if (ziplen > INBUFSIZ) */ ! 612: ! 613: /*--------------------------------------------------------------------------- ! 614: Searched through whole region where signature should be without finding ! 615: it. Print informational message and die a horrible death. ! 616: ---------------------------------------------------------------------------*/ ! 617: ! 618: fail: ! 619: ! 620: fprintf(stderr, "\n\ ! 621: %s:\n\n\ ! 622: End-of-central-directory signature not found. Either this file is not\n\ ! 623: a zipfile, or it constitutes one disk of a multi-part archive. In the\n\ ! 624: latter case the central directory and zipfile comment will be found on\n\ ! 625: the last disk(s) of this archive.\n", zipfn); ! 626: return 1; /* failed */ ! 627: ! 628: } /* end function find_end_central_dir() */ ! 629: ! 630: ! 631: ! 632: ! 633: ! 634: /****************************************/ ! 635: /* Function process_end_central_dir() */ ! 636: /****************************************/ ! 637: ! 638: int process_end_central_dir() /* return PK-type error code */ ! 639: { ! 640: ec_byte_rec byterec; ! 641: int error=0; ! 642: ! 643: ! 644: /*-------------------------------------------------------------------------- ! 645: Read the end-of-central-directory record and do any necessary machine- ! 646: type conversions (byte ordering, structure padding compensation) by ! 647: copying character array to struct. ! 648: ---------------------------------------------------------------------------*/ ! 649: ! 650: if (readbuf((char *)byterec, ECREC_SIZE+4) <= 0) ! 651: return 51; ! 652: ! 653: ecrec.number_this_disk = ! 654: makeword(&byterec[NUMBER_THIS_DISK]); ! 655: ecrec.num_disk_with_start_central_dir = ! 656: makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]); ! 657: ecrec.num_entries_centrl_dir_ths_disk = ! 658: makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]); ! 659: ecrec.total_entries_central_dir = ! 660: makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]); ! 661: ecrec.size_central_directory = ! 662: makelong(&byterec[SIZE_CENTRAL_DIRECTORY]); ! 663: ecrec.offset_start_central_directory = ! 664: makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]); ! 665: ecrec.zipfile_comment_length = ! 666: makeword(&byterec[ZIPFILE_COMMENT_LENGTH]); ! 667: ! 668: expect_ecrec_offset = ecrec.offset_start_central_directory + ! 669: ecrec.size_central_directory; ! 670: ! 671: /*--------------------------------------------------------------------------- ! 672: Print out various interesting things about the zipfile. ! 673: ---------------------------------------------------------------------------*/ ! 674: ! 675: /* header fits on one line, for anything up to 10GB and 10000 files: */ ! 676: if (hflag) ! 677: printf((strlen(zipfn)<39)? "Archive: %s %ld bytes %d file%s\n" ! 678: : "Archive: %s %ld %d\n", zipfn, ziplen, ! 679: ecrec.total_entries_central_dir, ! 680: (ecrec.total_entries_central_dir==1)? "":"s"); ! 681: ! 682: /* verbose format */ ! 683: if (lflag > 9) { ! 684: printf("\nEnd-of-central-directory record:\n"); ! 685: printf("-------------------------------\n\n"); ! 686: ! 687: printf("\ ! 688: Actual offset of end-of-central-dir record: %9ld (%.8lXh)\n\ ! 689: Expected offset of end-of-central-dir record: %9ld (%.8lXh)\n\ ! 690: (based on the length of the central directory and its expected offset)\n\n", ! 691: real_ecrec_offset, real_ecrec_offset, ! 692: expect_ecrec_offset, expect_ecrec_offset); ! 693: ! 694: if (ecrec.number_this_disk == 0) { ! 695: printf("\ ! 696: This zipfile constitutes the sole disk of a single-part archive; its\n\ ! 697: central directory contains %u %s. The central directory is %lu\n\ ! 698: (%.8lXh) bytes long, and its (expected) offset in bytes from the\n\ ! 699: beginning of the zipfile is %lu (%.8lXh).\n\n", ! 700: ecrec.total_entries_central_dir, ! 701: (ecrec.total_entries_central_dir == 1)? "entry" : "entries", ! 702: ecrec.size_central_directory, ecrec.size_central_directory, ! 703: ecrec.offset_start_central_directory, ! 704: ecrec.offset_start_central_directory); ! 705: } else { ! 706: printf("\ ! 707: This zipfile constitutes disk %u of a multi-part archive. The central\n\ ! 708: directory starts on disk %u; %u of its entries %s contained within\n\ ! 709: this zipfile, out of a total of %u %s. The entire central\n\ ! 710: directory is %lu (%.8lXh) bytes long, and its offset in bytes from\n\ ! 711: the beginning of the zipfile in which it begins is %lu (%.8lXh).\n\n", ! 712: ecrec.number_this_disk, ! 713: ecrec.num_disk_with_start_central_dir, ! 714: ecrec.num_entries_centrl_dir_ths_disk, ! 715: (ecrec.num_entries_centrl_dir_ths_disk == 1)? "is" : "are", ! 716: ecrec.total_entries_central_dir, ! 717: (ecrec.total_entries_central_dir == 1) ? "entry" : "entries", ! 718: ecrec.size_central_directory, ecrec.size_central_directory, ! 719: ecrec.offset_start_central_directory, ! 720: ecrec.offset_start_central_directory); ! 721: } ! 722: ! 723: /*----------------------------------------------------------------------- ! 724: Get the zipfile comment, if any, and print it out. (Comment may be ! 725: up to 64KB long. May the fleas of a thousand camels infest the arm- ! 726: pits of anyone who actually takes advantage of this fact.) ! 727: -----------------------------------------------------------------------*/ ! 728: ! 729: if (!ecrec.zipfile_comment_length) ! 730: printf(" There is no zipfile comment.\n"); ! 731: else { ! 732: printf(" The zipfile comment is %u bytes long and contains the following text:\n\n", ! 733: ecrec.zipfile_comment_length ); ! 734: printf("======================== zipfile comment begins ==========================\n"); ! 735: if (do_string(ecrec.zipfile_comment_length, DISPLAY)) ! 736: error = 1; /* 1: warning error */ ! 737: printf("\n========================= zipfile comment ends ===========================\n"); ! 738: if (error) ! 739: printf("\n The zipfile comment is truncated.\n"); ! 740: } /* endif (comment exists) */ ! 741: ! 742: } /* endif (verbose) */ ! 743: ! 744: return error; ! 745: ! 746: } /* end function process_end_central_dir() */ ! 747: ! 748: ! 749: ! 750: ! 751: ! 752: /************************************/ ! 753: /* Function process_central_dir() */ ! 754: /************************************/ ! 755: ! 756: int process_central_dir() /* return PK-type error code */ ! 757: { ! 758: char **fnamev; ! 759: int do_this_file=FALSE, none_found=TRUE, error, error_in_archive=0; ! 760: UWORD j, members=0; ! 761: ULONG c=0L, uc=0L; ! 762: ! 763: ! 764: /*--------------------------------------------------------------------------- ! 765: Set file pointer to start of central directory, then loop through cen- ! 766: tral directory entries. Check that directory-entry signature bytes are ! 767: actually there (just a precaution), then process the entry. We know ! 768: the entire central directory is on this disk: we wouldn't have any of ! 769: this information unless the end-of-central-directory record was on this ! 770: disk, and we wouldn't have gotten to this routine unless this is also ! 771: the disk on which the central directory starts. In practice, this had ! 772: better be the *only* disk in the archive, but maybe someday we'll add ! 773: multi-disk support. ! 774: ---------------------------------------------------------------------------*/ ! 775: ! 776: pInfo->lcflag = 0; /* match(), do_string(): never TRUE in zipinfo */ ! 777: ! 778: for (j = 0; j < ecrec.total_entries_central_dir; ++j) { ! 779: if (readbuf(sig, 4) <= 0) ! 780: return 51; /* 51: unexpected EOF */ ! 781: if (strncmp(sig, central_hdr_sig, 4)) { /* just to make sure */ ! 782: fprintf(stderr, CentSigMsg, j); /* sig not found */ ! 783: return 3; /* 3: error in zipfile */ ! 784: } ! 785: if ((error = process_cdir_file_hdr()) != 0) ! 786: return error; /* only 51 (EOF) defined */ ! 787: if ((error = do_string(crec.filename_length, FILENAME)) != 0) { ! 788: error_in_archive = error; /* might be warning */ ! 789: if (error > 1) /* fatal */ ! 790: return error; ! 791: } ! 792: ! 793: if (!process_all_files) { /* check if specified on command line */ ! 794: do_this_file = FALSE; ! 795: fnamev = fnv; /* don't destroy permanent filename ptr */ ! 796: for (--fnamev; *++fnamev; ) ! 797: if (match(filename, *fnamev)) { ! 798: do_this_file = TRUE; ! 799: none_found = FALSE; ! 800: break; /* found match, so stop looping */ ! 801: } ! 802: } ! 803: ! 804: /*----------------------------------------------------------------------- ! 805: If current file was specified on command line, or if no names were ! 806: specified, do the listing for this file. Otherwise, get rid of the ! 807: file comment and go back for the next file. ! 808: -----------------------------------------------------------------------*/ ! 809: ! 810: if (process_all_files || do_this_file) { ! 811: switch (lflag) { ! 812: case 1: ! 813: printf("%s\n", filename); ! 814: SKIP_(crec.extra_field_length) ! 815: SKIP_(crec.file_comment_length) ! 816: break; ! 817: ! 818: case 3: ! 819: case 4: ! 820: case 5: ! 821: if ((error = short_info()) != 0) { ! 822: error_in_archive = error; /* might be warning */ ! 823: if (error > 1) /* fatal */ ! 824: return error; ! 825: } ! 826: break; ! 827: ! 828: case 10: ! 829: #ifdef VMS /* GRR: FIX THIS (no pipes: add cbreak-style "more" function) */ ! 830: printf("\nCentral directory entry #%d:\n", j); ! 831: #else /* !VMS */ ! 832: /* formfeed/CR for piping to "more": */ ! 833: printf("%s\nCentral directory entry #%d:\n", "\014", j); ! 834: #endif /* ?VMS */ ! 835: printf("---------------------------\n\n"); ! 836: ! 837: if ((error = long_info()) != 0) { ! 838: error_in_archive = error; /* might be warning */ ! 839: if (error > 1) /* fatal */ ! 840: return error; ! 841: } ! 842: break; ! 843: ! 844: default: ! 845: SKIP_(crec.extra_field_length) ! 846: SKIP_(crec.file_comment_length) ! 847: break; ! 848: ! 849: } /* end switch (lflag) */ ! 850: ! 851: uc += crec.uncompressed_size; ! 852: c += crec.compressed_size; ! 853: if (crec.general_purpose_bit_flag & 1) ! 854: c -= 12; /* if encrypted, don't count encryption header */ ! 855: ++members; ! 856: ! 857: } else { /* not listing */ ! 858: SKIP_(crec.extra_field_length) ! 859: SKIP_(crec.file_comment_length) ! 860: ! 861: } /* end if (list member?) */ ! 862: ! 863: } /* end for-loop (j: member files) */ ! 864: ! 865: /*--------------------------------------------------------------------------- ! 866: Double check that we're back at the end-of-central-directory record. ! 867: ---------------------------------------------------------------------------*/ ! 868: ! 869: readbuf(sig, 4); ! 870: if (strncmp(sig, end_central_sig, 4)) { /* just to make sure again */ ! 871: fprintf(stderr, EndSigMsg); /* didn't find end-of-central-dir sig */ ! 872: error_in_archive = 1; /* 1: warning error */ ! 873: } ! 874: ! 875: /*--------------------------------------------------------------------------- ! 876: Check that we actually found requested files; if so, print totals. ! 877: ---------------------------------------------------------------------------*/ ! 878: ! 879: if (none_found && !process_all_files) { ! 880: fnamev = fnv; /* don't destroy permanent filename ptr */ ! 881: for (--fnamev; *++fnamev; ) ! 882: printf("zipinfo: %s not found in %s\n", *fnamev, zipfn); ! 883: } else if (tflag) ! 884: printf( ! 885: "%d file%s, %lu bytes uncompressed, %lu bytes compressed: %d%%\n", ! 886: members, (members==1)? "":"s", uc, c, (uc==0)? 0 : ((uc>2000000L)? ! 887: ((int)((uc-c)/(uc/1000L))+5)/10 : ((int)((1000L*(uc-c))/uc)+5)/10) ); ! 888: ! 889: return error_in_archive; ! 890: ! 891: } /* end function process_central_dir() */ ! 892: ! 893: ! 894: ! 895: ! 896: ! 897: /**************************************/ ! 898: /* Function process_cdir_file_hdr() */ ! 899: /**************************************/ ! 900: ! 901: int process_cdir_file_hdr() /* return PK-type error code */ ! 902: { ! 903: cdir_byte_hdr byterec; ! 904: ! 905: ! 906: /*--------------------------------------------------------------------------- ! 907: Read the next central directory entry and do any necessary machine-type ! 908: conversions (byte ordering, structure padding compensation--do so by ! 909: copying the data from the array into which it was read (byterec) to the ! 910: usable struct (crec)). ! 911: ---------------------------------------------------------------------------*/ ! 912: ! 913: if (readbuf((char *) byterec, CREC_SIZE) <= 0) ! 914: return 51; /* 51: unexpected EOF */ ! 915: ! 916: crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0]; ! 917: crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1]; ! 918: crec.version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0]; ! 919: crec.version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1]; ! 920: ! 921: crec.general_purpose_bit_flag = ! 922: makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]); ! 923: crec.compression_method = ! 924: makeword(&byterec[C_COMPRESSION_METHOD]); ! 925: crec.last_mod_file_time = ! 926: makeword(&byterec[C_LAST_MOD_FILE_TIME]); ! 927: crec.last_mod_file_date = ! 928: makeword(&byterec[C_LAST_MOD_FILE_DATE]); ! 929: crec.crc32 = ! 930: makelong(&byterec[C_CRC32]); ! 931: crec.compressed_size = ! 932: makelong(&byterec[C_COMPRESSED_SIZE]); ! 933: crec.uncompressed_size = ! 934: makelong(&byterec[C_UNCOMPRESSED_SIZE]); ! 935: crec.filename_length = ! 936: makeword(&byterec[C_FILENAME_LENGTH]); ! 937: crec.extra_field_length = ! 938: makeword(&byterec[C_EXTRA_FIELD_LENGTH]); ! 939: crec.file_comment_length = ! 940: makeword(&byterec[C_FILE_COMMENT_LENGTH]); ! 941: crec.disk_number_start = ! 942: makeword(&byterec[C_DISK_NUMBER_START]); ! 943: crec.internal_file_attributes = ! 944: makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]); ! 945: crec.external_file_attributes = ! 946: makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */ ! 947: crec.relative_offset_local_header = ! 948: makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]); ! 949: ! 950: return 0; ! 951: ! 952: } /* end function process_cdir_file_hdr() */ ! 953: ! 954: ! 955: ! 956: ! 957: /**************************/ ! 958: /* Function long_info() */ ! 959: /**************************/ ! 960: ! 961: int long_info() /* return PK-type error code */ ! 962: { ! 963: int error, error_in_archive=0; ! 964: UWORD hostver, extver, xattr; ! 965: char workspace[12], attribs[22]; ! 966: static char unkn[16]; ! 967: static char *os[NUM_HOSTS+1] = {"MS-DOS or OS/2 FAT", "Amiga", "VAX VMS", ! 968: "Unix", "VM/CMS", "Atari ST", "OS/2 HPFS", "Macintosh", ! 969: "Z-System", "CP/M", "unknown" }; ! 970: static char *method[NUM_METHODS+1] = {"none (stored)", "shrunk", ! 971: "reduced (factor 1)", "reduced (factor 2)", ! 972: "reduced (factor 3)", "reduced (factor 4)", ! 973: "imploded", "tokenized", "deflated", unkn}; ! 974: static char *dtype[4] = {"normal", "maximum", "fast", "superfast"}; ! 975: ! 976: ! 977: /*--------------------------------------------------------------------------- ! 978: Print out various interesting things about the compressed file. ! 979: ---------------------------------------------------------------------------*/ ! 980: ! 981: hostnum = MIN(crec.version_made_by[1], NUM_HOSTS); ! 982: hostver = crec.version_made_by[0]; ! 983: extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); ! 984: extver = crec.version_needed_to_extract[0]; ! 985: methnum = MIN(crec.compression_method, NUM_METHODS); ! 986: if (methnum == NUM_METHODS) ! 987: sprintf(unkn, "unknown (%d)", crec.compression_method); ! 988: ! 989: printf(" %s\n", filename); ! 990: ! 991: printf("\n host operating system (created on): %s\n", ! 992: os[hostnum]); ! 993: printf(" version of encoding software: %d.%d\n", ! 994: hostver/10, hostver%10); ! 995: printf(" minimum operating system compatibility required: %s\n", ! 996: os[extnum]); ! 997: printf(" minimum software version required to extract: %d.%d\n", ! 998: extver/10, extver%10); ! 999: printf(" compression method: %s\n", ! 1000: method[methnum]); ! 1001: if (methnum == IMPLODED) { ! 1002: printf(" size of sliding dictionary (implosion): %cK\n", ! 1003: (crec.general_purpose_bit_flag & 2)? '8' : '4'); ! 1004: printf(" number of Shannon-Fano trees (implosion): %c\n", ! 1005: (crec.general_purpose_bit_flag & 4)? '3' : '2'); ! 1006: } else if (methnum == DEFLATED) { ! 1007: UWORD dnum=(crec.general_purpose_bit_flag>>1) & 3; ! 1008: printf(" compression sub-type (deflation): %s\n", ! 1009: dtype[dnum]); ! 1010: } ! 1011: printf(" file security status: %sencrypted\n", ! 1012: (crec.general_purpose_bit_flag & 1)? "" : "not "); ! 1013: printf(" extended local header: %s\n", ! 1014: (crec.general_purpose_bit_flag & 8)? "yes" : "no"); ! 1015: /* print upper 3 bits for amusement? */ ! 1016: printf(" file last modified on: %s\n", ! 1017: zipinfo_time(&crec.last_mod_file_date, &crec.last_mod_file_time)); ! 1018: printf(" 32-bit CRC value (hex): %.8lx\n", ! 1019: crec.crc32); ! 1020: printf(" compressed size: %lu bytes\n", ! 1021: crec.compressed_size); ! 1022: printf(" uncompressed size: %lu bytes\n", ! 1023: crec.uncompressed_size); ! 1024: printf(" length of filename: %u characters\n", ! 1025: crec.filename_length); ! 1026: printf(" length of extra field: %u bytes\n", ! 1027: crec.extra_field_length); ! 1028: printf(" length of file comment: %u characters\n", ! 1029: crec.file_comment_length); ! 1030: printf(" disk number on which file begins: disk %u\n", ! 1031: crec.disk_number_start); ! 1032: printf(" apparent file type: %s\n", ! 1033: (crec.internal_file_attributes & 1)? "text" : "binary"); ! 1034: /* ! 1035: printf(" external file attributes (hex): %.8lx\n", ! 1036: crec.external_file_attributes); ! 1037: */ ! 1038: xattr = (UWORD) ((crec.external_file_attributes >> 16) & 0xFFFF); ! 1039: if (hostnum == VMS_) { ! 1040: char *p=attribs, *q=attribs+1; ! 1041: int i, j, k; ! 1042: ! 1043: for (k = 0; k < 12; ++k) ! 1044: workspace[k] = 0; ! 1045: if (xattr & S_IRUSR) ! 1046: workspace[0] = 'R'; ! 1047: if (xattr & S_IWUSR) { ! 1048: workspace[1] = 'W'; ! 1049: workspace[3] = 'D'; ! 1050: } ! 1051: if (xattr & S_IXUSR) ! 1052: workspace[2] = 'E'; ! 1053: if (xattr & S_IRGRP) ! 1054: workspace[4] = 'R'; ! 1055: if (xattr & S_IWGRP) { ! 1056: workspace[5] = 'W'; ! 1057: workspace[7] = 'D'; ! 1058: } ! 1059: if (xattr & S_IXGRP) ! 1060: workspace[6] = 'E'; ! 1061: if (xattr & S_IROTH) ! 1062: workspace[8] = 'R'; ! 1063: if (xattr & S_IWOTH) { ! 1064: workspace[9] = 'W'; ! 1065: workspace[11] = 'D'; ! 1066: } ! 1067: if (xattr & S_IXOTH) ! 1068: workspace[10] = 'E'; ! 1069: ! 1070: *p++ = '('; ! 1071: for (k = j = 0; j < 3; ++j) { /* loop over groups of permissions */ ! 1072: for (i = 0; i < 4; ++i, ++k) /* loop over perms within a group */ ! 1073: if (workspace[k]) ! 1074: *p++ = workspace[k]; ! 1075: *p++ = ','; /* group separator */ ! 1076: if (j == 0) ! 1077: while ((*p++ = *q++) != ','); /* system, owner perms are same */ ! 1078: } ! 1079: *p-- = 0; ! 1080: *p = ')'; /* overwrite last comma */ ! 1081: printf(" VMS file attributes (%06o octal): %s\n", ! 1082: xattr, attribs); ! 1083: ! 1084: } else if ((hostnum != DOS_OS2_FAT_) && (hostnum != OS2_HPFS_)) { ! 1085: /* assume Unix-like */ ! 1086: switch (xattr & S_IFMT) { ! 1087: case S_IFREG: attribs[0] = '-'; break; ! 1088: case S_IFLNK: attribs[0] = 'l'; break; ! 1089: case S_IFBLK: attribs[0] = 'b'; break; ! 1090: case S_IFCHR: attribs[0] = 'c'; break; ! 1091: case S_IFIFO: attribs[0] = 'p'; break; ! 1092: case S_IFSOCK: attribs[0] = 's'; break; ! 1093: case S_IFDIR: attribs[0] = 'd'; break; ! 1094: default: attribs[0] = '?'; break; ! 1095: } ! 1096: if (xattr & S_IRUSR) /* no read-permission: user */ ! 1097: attribs[1] = 'r'; ! 1098: else ! 1099: attribs[1] = '-'; ! 1100: if (xattr & S_IWUSR) /* no write-permission: user */ ! 1101: attribs[2] = 'w'; ! 1102: else ! 1103: attribs[2] = '-'; ! 1104: if (xattr & S_IXUSR) /* no execute-permission: user */ ! 1105: if (xattr & S_ISUID) ! 1106: attribs[3] = 's'; ! 1107: else ! 1108: attribs[3] = 'x'; ! 1109: else ! 1110: if (xattr & S_ISUID) ! 1111: attribs[3] = 'S'; /* undefined state */ ! 1112: else ! 1113: attribs[3] = '-'; ! 1114: if (xattr & S_IRGRP) /* no read-permission: group */ ! 1115: attribs[4] = 'r'; ! 1116: else ! 1117: attribs[4] = '-'; ! 1118: if (xattr & S_IWGRP) /* no write-permission: group */ ! 1119: attribs[5] = 'w'; ! 1120: else ! 1121: attribs[5] = '-'; ! 1122: if (xattr & S_IXGRP) /* no execute-permission: group */ ! 1123: if (xattr & S_ISGID) ! 1124: attribs[6] = 's'; ! 1125: else ! 1126: attribs[6] = 'x'; ! 1127: else ! 1128: if (xattr & S_ISGID) /* or could use S_ENFMT (same) */ ! 1129: attribs[6] = 'l'; ! 1130: else ! 1131: attribs[6] = '-'; ! 1132: if (xattr & S_IROTH) /* no read-permission: other */ ! 1133: attribs[7] = 'r'; ! 1134: else ! 1135: attribs[7] = '-'; ! 1136: if (xattr & S_IWOTH) /* no write-permission: other */ ! 1137: attribs[8] = 'w'; ! 1138: else ! 1139: attribs[8] = '-'; ! 1140: if (xattr & S_IXOTH) /* no execute-permission: other */ ! 1141: if (xattr & S_ISVTX) /* "sticky bit" */ ! 1142: attribs[9] = 't'; ! 1143: else ! 1144: attribs[9] = 'x'; ! 1145: else ! 1146: if (xattr & S_ISVTX) ! 1147: attribs[9] = 'T'; /* undefined state */ ! 1148: else ! 1149: attribs[9] = '-'; ! 1150: attribs[10] = 0; ! 1151: printf(" Unix file attributes (%06o octal): %s\n", ! 1152: xattr, attribs); ! 1153: ! 1154: } /* endif (hostnum: external attributes format) */ ! 1155: ! 1156: if ((xattr=(UWORD)(crec.external_file_attributes & 0xFF)) == 0) ! 1157: printf(" MS-DOS file attributes (%02X hex): none\n", ! 1158: xattr); ! 1159: else if (xattr == 1) ! 1160: printf( ! 1161: " MS-DOS file attributes (%02X hex): read-only\n", ! 1162: xattr); ! 1163: else ! 1164: printf( ! 1165: " MS-DOS file attributes (%02X hex): %s%s%s%s%s%s\n", ! 1166: xattr, (xattr&1)?"rdo ":"", (xattr&2)?"hid ":"", (xattr&4)?"sys ":"", ! 1167: (xattr&8)?"lab ":"", (xattr&16)?"dir ":"", (xattr&32)?"arc":""); ! 1168: printf( ! 1169: " offset of local header from start of archive: %lu (%.8lXh) bytes\n", ! 1170: crec.relative_offset_local_header, crec.relative_offset_local_header); ! 1171: ! 1172: /*--------------------------------------------------------------------------- ! 1173: Skip the extra field, if any, and print the file comment, if any (the ! 1174: filename has already been printed, above). That finishes up this file ! 1175: entry... ! 1176: ---------------------------------------------------------------------------*/ ! 1177: ! 1178: if (crec.extra_field_length > 0) { ! 1179: /* #ifdef OS2 */ ! 1180: #if TRUE ! 1181: ULONG ea_size; ! 1182: if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0) { ! 1183: error_in_archive = error; ! 1184: if (error > 1) /* fatal: can't continue */ ! 1185: return (error); ! 1186: } ! 1187: if ((ea_size = SizeOfEAs(extra_field)) != 0) ! 1188: printf("\n\ ! 1189: This file has %lu bytes of OS/2 EA's in the local extra field.\n\ ! 1190: (May not match OS/2 \"dir\" amount due to storage method.)\n\n", ! 1191: ea_size); ! 1192: else ! 1193: printf("\n There is an unknown extra field (skipping).\n"); ! 1194: #else ! 1195: printf("\n There is an extra field (skipping).\n"); ! 1196: SKIP_(crec.extra_field_length) ! 1197: #endif ! 1198: } else ! 1199: printf("\n"); ! 1200: ! 1201: if (!crec.file_comment_length) ! 1202: printf(" There is no file comment.\n"); ! 1203: else { ! 1204: printf("\ ! 1205: ------------------------- file comment begins ----------------------------\n"); ! 1206: if ((error = do_string(crec.file_comment_length, DISPLAY)) != 0) { ! 1207: error_in_archive = error; /* might be warning */ ! 1208: if (error > 1) /* fatal */ ! 1209: return error; ! 1210: } ! 1211: printf("\n\ ! 1212: -------------------------- file comment ends -----------------------------\n"); ! 1213: } ! 1214: ! 1215: return error_in_archive; ! 1216: ! 1217: } /* end function long_info() */ ! 1218: ! 1219: ! 1220: ! 1221: ! 1222: ! 1223: /**************************/ ! 1224: /* Function SizeOfEAs() */ ! 1225: /**************************/ ! 1226: ! 1227: ULONG SizeOfEAs(extra_field) /* Author: Kai Uwe Rommel */ ! 1228: void *extra_field; ! 1229: { ! 1230: EAHEADER *pEAblock = (PEAHEADER) extra_field; ! 1231: ! 1232: if ( extra_field != NULL && pEAblock -> nID == EAID ) ! 1233: return pEAblock -> lSize; ! 1234: ! 1235: return 0L; ! 1236: } ! 1237: ! 1238: ! 1239: ! 1240: ! 1241: ! 1242: /***************************/ ! 1243: /* Function short_info() */ ! 1244: /***************************/ ! 1245: ! 1246: int short_info() /* return PK-type error code */ ! 1247: { ! 1248: int k, error, error_in_archive=0; ! 1249: UWORD hostver, xattr; ! 1250: char workspace[12], attribs[16]; ! 1251: static char impl[5]="i#:#", defl[5]="def#", unkn[8]; ! 1252: static char dtype[5]="NXFS"; /* normal, maximum, fast, superfast */ ! 1253: static char *os[NUM_HOSTS+1] = {"dos", "ami", "vms", "unx", "cms", ! 1254: "atr", "os2", "mac", "zzz", "cpm", "???" }; ! 1255: static char *method[NUM_METHODS+1] = {"stor", "shrk", "re:1", "re:2", ! 1256: "re:3", "re:4", impl, "tokn", defl, unkn}; ! 1257: ! 1258: ! 1259: /*--------------------------------------------------------------------------- ! 1260: Print out various interesting things about the compressed file. ! 1261: ---------------------------------------------------------------------------*/ ! 1262: ! 1263: methnum = MIN(crec.compression_method, NUM_METHODS); ! 1264: hostnum = MIN(crec.version_made_by[1], NUM_HOSTS); ! 1265: hostver = crec.version_made_by[0]; ! 1266: /* ! 1267: extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); ! 1268: extver = crec.version_needed_to_extract[0]; ! 1269: */ ! 1270: ! 1271: if (methnum == IMPLODED) { ! 1272: impl[1] = (crec.general_purpose_bit_flag & 2)? '8' : '4'; ! 1273: impl[3] = (crec.general_purpose_bit_flag & 4)? '3' : '2'; ! 1274: } else if (methnum == DEFLATED) { ! 1275: UWORD dnum=(crec.general_purpose_bit_flag>>1) & 3; ! 1276: defl[3] = dtype[dnum]; ! 1277: } else if (methnum == NUM_METHODS) { /* unknown */ ! 1278: sprintf(unkn, "u%03d", crec.compression_method); ! 1279: } ! 1280: ! 1281: for (k = 0; k < 15; ++k) ! 1282: attribs[k] = ' '; ! 1283: attribs[15] = 0; ! 1284: ! 1285: xattr = (UWORD) ((crec.external_file_attributes >> 16) & 0xFFFF); ! 1286: switch (hostnum) { ! 1287: case VMS_: ! 1288: { char *p=attribs; ! 1289: int i, j; ! 1290: ! 1291: for (k = 0; k < 12; ++k) ! 1292: workspace[k] = 0; ! 1293: if (xattr & S_IRUSR) ! 1294: workspace[0] = 'R'; ! 1295: if (xattr & S_IWUSR) { ! 1296: workspace[1] = 'W'; ! 1297: workspace[3] = 'D'; ! 1298: } ! 1299: if (xattr & S_IXUSR) ! 1300: workspace[2] = 'E'; ! 1301: if (xattr & S_IRGRP) ! 1302: workspace[4] = 'R'; ! 1303: if (xattr & S_IWGRP) { ! 1304: workspace[5] = 'W'; ! 1305: workspace[7] = 'D'; ! 1306: } ! 1307: if (xattr & S_IXGRP) ! 1308: workspace[6] = 'E'; ! 1309: if (xattr & S_IROTH) ! 1310: workspace[8] = 'R'; ! 1311: if (xattr & S_IWOTH) { ! 1312: workspace[9] = 'W'; ! 1313: workspace[11] = 'D'; ! 1314: } ! 1315: if (xattr & S_IXOTH) ! 1316: workspace[10] = 'E'; ! 1317: ! 1318: for (k = j = 0; j < 3; ++j) { /* groups of permissions */ ! 1319: for (i = 0; i < 4; ++i, ++k) /* perms within a group */ ! 1320: if (workspace[k]) ! 1321: *p++ = workspace[k]; ! 1322: *p++ = ','; /* group separator */ ! 1323: } ! 1324: *--p = ' '; /* overwrite last comma */ ! 1325: if ((p - attribs) < 12) ! 1326: sprintf(&attribs[12], "%d.%d", hostver/10, hostver%10); ! 1327: } ! 1328: break; ! 1329: ! 1330: case DOS_OS2_FAT_: ! 1331: case OS2_HPFS_: ! 1332: xattr = (UWORD) (crec.external_file_attributes & 0xFF); ! 1333: sprintf(attribs, "%s,%s,%s,%s", (xattr&32)?"arc":"", ! 1334: (xattr&2)?"hid":"", (xattr&1)?"rdo":"rw", (xattr&4)?"sys":""); ! 1335: if ((k = strlen(attribs)) < 15) ! 1336: attribs[k] = ' '; /* overwrite '\0' */ ! 1337: if (k < 12) ! 1338: sprintf(&attribs[12], "%d.%d", hostver/10, hostver%10); ! 1339: break; ! 1340: ! 1341: default: /* assume Unix-like */ ! 1342: switch (xattr & S_IFMT) { ! 1343: case S_IFREG: attribs[0] = '-'; break; ! 1344: case S_IFLNK: attribs[0] = 'l'; break; ! 1345: case S_IFBLK: attribs[0] = 'b'; break; ! 1346: case S_IFCHR: attribs[0] = 'c'; break; ! 1347: case S_IFIFO: attribs[0] = 'p'; break; ! 1348: case S_IFSOCK: attribs[0] = 's'; break; ! 1349: case S_IFDIR: attribs[0] = 'd'; break; ! 1350: default: attribs[0] = '?'; break; ! 1351: } ! 1352: if (xattr & S_IRUSR) /* no read-permission: user */ ! 1353: attribs[1] = 'r'; ! 1354: else ! 1355: attribs[1] = '-'; ! 1356: if (xattr & S_IWUSR) /* no write-permission: user */ ! 1357: attribs[2] = 'w'; ! 1358: else ! 1359: attribs[2] = '-'; ! 1360: if (xattr & S_IXUSR) /* no execute-permission: user */ ! 1361: if (xattr & S_ISUID) ! 1362: attribs[3] = 's'; ! 1363: else ! 1364: attribs[3] = 'x'; ! 1365: else ! 1366: if (xattr & S_ISUID) ! 1367: attribs[3] = 'S'; /* undefined state */ ! 1368: else ! 1369: attribs[3] = '-'; ! 1370: if (xattr & S_IRGRP) /* no read-permission: group */ ! 1371: attribs[4] = 'r'; ! 1372: else ! 1373: attribs[4] = '-'; ! 1374: if (xattr & S_IWGRP) /* no write-permission: group */ ! 1375: attribs[5] = 'w'; ! 1376: else ! 1377: attribs[5] = '-'; ! 1378: if (xattr & S_IXGRP) /* no execute-permission: group */ ! 1379: if (xattr & S_ISGID) ! 1380: attribs[6] = 's'; ! 1381: else ! 1382: attribs[6] = 'x'; ! 1383: else ! 1384: if (xattr & S_ISGID) /* or could use S_ENFMT (same) */ ! 1385: attribs[6] = 'l'; ! 1386: else ! 1387: attribs[6] = '-'; ! 1388: if (xattr & S_IROTH) /* no read-permission: other */ ! 1389: attribs[7] = 'r'; ! 1390: else ! 1391: attribs[7] = '-'; ! 1392: if (xattr & S_IWOTH) /* no write-permission: other */ ! 1393: attribs[8] = 'w'; ! 1394: else ! 1395: attribs[8] = '-'; ! 1396: if (xattr & S_IXOTH) /* no execute-permission: other */ ! 1397: if (xattr & S_ISVTX) /* "sticky bit" */ ! 1398: attribs[9] = 't'; ! 1399: else ! 1400: attribs[9] = 'x'; ! 1401: else ! 1402: if (xattr & S_ISVTX) ! 1403: attribs[9] = 'T'; /* undefined state */ ! 1404: else ! 1405: attribs[9] = '-'; ! 1406: sprintf(&attribs[12], "%d.%d", hostver/10, hostver%10); ! 1407: break; ! 1408: ! 1409: } /* end switch (hostnum: external attributes format) */ ! 1410: ! 1411: printf("%s %s %7lu %c%c", attribs, os[hostnum], crec.uncompressed_size, ! 1412: (crec.general_purpose_bit_flag & 1)? ! 1413: ((crec.internal_file_attributes & 1)? 'T' : 'B') : /* encrypted */ ! 1414: ((crec.internal_file_attributes & 1)? 't' : 'b'), /* plaintext */ ! 1415: (crec.general_purpose_bit_flag & 8)? (crec.extra_field_length? 'X' : 'l') ! 1416: : (crec.extra_field_length? 'x' : '-')); ! 1417: if (lflag == 4) { ! 1418: longint c = (longint) crec.compressed_size; ! 1419: longint uc = (longint) crec.uncompressed_size; ! 1420: ! 1421: if (crec.general_purpose_bit_flag & 1) ! 1422: c -= 12; /* if encrypted, don't count encryption header */ ! 1423: /* risk signed overflow if blindly multiply: */ ! 1424: printf("%3d%%", (uc==0)? 0 : ((uc>2000000L)? ! 1425: ((int)((uc-c)/(uc/1000L))+5)/10 : ((int)((1000L*(uc-c))/uc)+5)/10) ); ! 1426: } else if (lflag == 5) ! 1427: printf(" %7lu", crec.compressed_size); ! 1428: ! 1429: printf(" %s %s %s\n", method[methnum], ! 1430: zipinfo_time(&crec.last_mod_file_date, &crec.last_mod_file_time), ! 1431: filename); ! 1432: ! 1433: /*--------------------------------------------------------------------------- ! 1434: Skip the extra field and/or the file comment, if any (the filename has ! 1435: already been printed, above). That finishes up this file entry... ! 1436: ---------------------------------------------------------------------------*/ ! 1437: ! 1438: SKIP_(crec.extra_field_length) ! 1439: SKIP_(crec.file_comment_length) ! 1440: ! 1441: return error_in_archive; ! 1442: ! 1443: } /* end function short_info() */ ! 1444: ! 1445: ! 1446: ! 1447: ! 1448: ! 1449: /*****************************/ ! 1450: /* Function zipinfo_time() */ ! 1451: /*****************************/ ! 1452: ! 1453: char *zipinfo_time(datez, timez) ! 1454: UWORD *datez, *timez; ! 1455: { ! 1456: UWORD yr, mo, dy, hh, mm, ss; ! 1457: static char d_t_str[21]; ! 1458: static char *month[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", ! 1459: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; ! 1460: ! 1461: ! 1462: ! 1463: /*--------------------------------------------------------------------------- ! 1464: Convert the file-modification date and time info to a string of the form ! 1465: "23 Feb 1990 17:15:00" or "23-Feb-91 17:15," depending on value of lflag. ! 1466: ---------------------------------------------------------------------------*/ ! 1467: ! 1468: yr = ((*datez >> 9) & 0x7f) + 80; /* dissect date */ ! 1469: mo = ((*datez >> 5) & 0x0f) - 1; ! 1470: dy = *datez & 0x1f; ! 1471: ! 1472: hh = (*timez >> 11) & 0x1f; /* dissect time */ ! 1473: mm = (*timez >> 5) & 0x3f; ! 1474: ss = (*timez & 0x1f) * 2; ! 1475: ! 1476: if ((lflag >= 3) && (lflag <= 5)) ! 1477: sprintf(d_t_str, "%2u-%s-%u %02u:%02u", dy, month[mo], yr, hh, mm); ! 1478: else if (lflag > 9) /* verbose listing format */ ! 1479: sprintf(d_t_str, "%u %s %u %02u:%02u:%02u", dy, month[mo], yr+1900, ! 1480: hh, mm, ss); ! 1481: ! 1482: return d_t_str; ! 1483: ! 1484: } /* end function zipinfo_time() */ ! 1485: ! 1486: ! 1487: ! 1488: ! 1489: ! 1490: /********************************/ ! 1491: /* Function open_input_file() */ ! 1492: /********************************/ ! 1493: ! 1494: int open_input_file() /* return 1 if open failed */ ! 1495: { ! 1496: /* ! 1497: * open the zipfile for reading and in BINARY mode to prevent cr/lf ! 1498: * translation, which would corrupt the bitstreams ! 1499: */ ! 1500: ! 1501: #ifdef VMS ! 1502: zipfd = open(zipfn, O_RDONLY, 0, "ctx=stm"); ! 1503: #else /* !VMS */ ! 1504: #ifdef UNIX ! 1505: zipfd = open(zipfn, O_RDONLY); ! 1506: #else /* !UNIX */ ! 1507: #ifdef MACOS ! 1508: zipfd = open(zipfn, 0); ! 1509: #else /* !MACOS */ ! 1510: zipfd = open(zipfn, O_RDONLY | O_BINARY); ! 1511: #endif /* ?MACOS */ ! 1512: #endif /* ?UNIX */ ! 1513: #endif /* ?VMS */ ! 1514: if (zipfd < 1) { ! 1515: fprintf(stderr, "error: can't open zipfile [ %s ]\n", zipfn); ! 1516: return 1; ! 1517: } ! 1518: return 0; ! 1519: ! 1520: } /* end function open_input_file() */ ! 1521: ! 1522: ! 1523: ! 1524: ! 1525: ! 1526: /************************/ ! 1527: /* Function readbuf() */ ! 1528: /************************/ ! 1529: ! 1530: int readbuf(buf, size) /* return number of bytes read into buf */ ! 1531: char *buf; ! 1532: register unsigned size; ! 1533: { ! 1534: register int count; ! 1535: int n; ! 1536: ! 1537: n = size; ! 1538: while (size) { ! 1539: if (incnt == 0) { ! 1540: if ((incnt = read(zipfd, inbuf, INBUFSIZ)) <= 0) ! 1541: return (n-size); ! 1542: /* buffer ALWAYS starts on a block boundary: */ ! 1543: cur_zipfile_bufstart += INBUFSIZ; ! 1544: inptr = inbuf; ! 1545: } ! 1546: count = MIN(size, (unsigned)incnt); ! 1547: memcpy(buf, inptr, count); ! 1548: buf += count; ! 1549: inptr += count; ! 1550: incnt -= count; ! 1551: size -= count; ! 1552: } ! 1553: return n; ! 1554: ! 1555: } /* end function readbuf() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.