Annotation of coherent/b/bin/unzip/zipinfo.c, revision 1.1.1.1

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() */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.