home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume29 / unzip / part02 < prev    next >
Encoding:
Text File  |  1992-04-02  |  53.5 KB  |  1,421 lines

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