home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / vmsnet / sources / 331 < prev    next >
Encoding:
Internet Message Format  |  1992-09-01  |  47.4 KB

  1. Path: sparky!uunet!munnari.oz.au!network.ucsd.edu!mvb.saic.com!vmsnet-sources
  2. From: goathunter@wkuvx1.bitnet
  3. Newsgroups: vmsnet.sources
  4. Subject: Zip v1.9 & UnZip v5.0, part 14/22
  5. Message-ID: <8009680@MVB.SAIC.COM>
  6. Date: Tue, 01 Sep 1992 22:53:02 GMT
  7. Organization: Western Kentucky University, Bowling Green, KY
  8. Lines: 1271
  9. Approved: Mark.Berryman@Mvb.Saic.Com
  10.  
  11. Submitted-by: goathunter@wkuvx1.bitnet
  12. Posting-number: Volume 3, Issue 136
  13. Archive-name: zip_unzip/part14
  14.  
  15. -+-+-+-+-+-+-+-+ START OF PART 14 -+-+-+-+-+-+-+-+
  16. Xfirst hyphen and go from there.  It is also consistent with the behavior
  17. Xof the Unix command \fRnice\fP(1).
  18. X.PD
  19. X.SH EXAMPLES
  20. XTo get a basic, short-format listing of the complete contents of a ZIP`20
  21. Xarchive `60`60storage.zip,'' with both header and totals lines, use only
  22. Xthe archive name as an argument to zipinfo:
  23. X.PP
  24. X.IP "\t\fIzipinfo\fP storage"
  25. X.PP
  26. XTo produce a basic, long-format listing (not verbose), including header and
  27. Xtotals lines, use \-l:
  28. X.PP
  29. X.IP "\t\fIzipinfo\fP \-l storage"
  30. X.PP
  31. XTo list the complete contents of the archive without header and totals
  32. Xlines, either negate the \-h and \-t options or else specify the contents
  33. Xexplicitly:
  34. X.PP
  35. X.IP "\t\fIzipinfo\fP \-\-h\-t storage"
  36. X.IP "\t\fIzipinfo\fP storage \e*"
  37. X.PP
  38. X(where the backslash is required only if the shell would otherwise expand
  39. Xthe `60*' wildcard, as in Unix when globbing is turned on--double quotes aro
  40. Vund
  41. Xthe asterisk would have worked as well).  To turn off the totals line by
  42. Xdefault, use the environment variable (C shell is assumed here):
  43. X.PP
  44. X.IP "\tsetenv ZIPINFO \-\-t"
  45. X.IP "\t\fIzipinfo\fP storage"
  46. X.PP
  47. XTo get the full, short-format listing of the first example again, given
  48. Xthat the environment variable is set as in the previous example, it is
  49. Xnecessary to specify the \-s option explicitly, since the \-t
  50. Xoption by itself implies that ONLY the footer line is to be printed:
  51. X.PP
  52. X.IP "\tsetenv ZIPINFO \-\-t"
  53. X.IP "\t\fIzipinfo\fP \-t storage\t`5Bonly totals line`5D"
  54. X.IP "\t\fIzipinfo\fP \-st storage\t`5Bfull listing`5D"
  55. X.PP
  56. XThe \-s option, like \-m and \-l, includes headers and footers by default,
  57. Xunless otherwise specified.  Since the environment variable specified no
  58. Xfooters and that has a higher precedence than the default behavior of \-s,
  59. Xan explicit \-t option was necessary to produce the full listing.  Nothing`2
  60. V0
  61. Xwas indicated about the header, however, so the \-s option was sufficient.
  62. XNote that both the \-h and \-t options, when used by themselves or with
  63. Xeach other, override any default listing of member files; only the header
  64. Xand/or footer are printed.  This behavior will be more`20
  65. Xuseful when \fIZipInfo\fP accepts wildcards for the zipfile name; one
  66. Xmay then summarize the contents of all zipfiles with a single command.
  67. X.PP
  68. XTo list information on a single file within the archive, in medium format,
  69. Xspecify the filename explicitly:
  70. X.PP
  71. X.IP "\t\fIzipinfo\fP \-m storage unshrink.c"
  72. X.PP
  73. XThe specification of any member file, as in this example, will override
  74. Xthe default header and totals lines; only the single line of information
  75. Xabout the requested file will be printed.  This is intuitively what one
  76. Xwould expect when requesting information about a single file.  For multiple
  77. Xfiles, it is often useful to know the total compressed and uncompressed
  78. Xsize; in such cases \-t may be specified explicitly:
  79. X.PP
  80. X.IP "\t\fIzipinfo\fP \-mt storage ""*.`5Bch`5D Mak\e*"
  81. X.PP
  82. XFinally, to get maximal information about the ZIP archive, use the verbose`2
  83. V0
  84. Xoption.  It is usually wise to pipe the output into a filter such as`20
  85. X\fRmore\fP(1):
  86. X.PP
  87. X.IP "\t\fIzipinfo\fP \-v storage `7C more"
  88. X.PD
  89. X.SH TIPS
  90. XThe author finds it convenient to set up an alias `60`60ii'' for \fIZipInfo\
  91. VfP
  92. Xon systems which allow aliases, or else to set up a batch file `60`60ii.bat'
  93. V'
  94. Xor to rename the executable to `60`60ii.exe'' on systems such as MS-DOS whic
  95. Vh
  96. Xhave no provision for aliases.  The `60`60ii'' usage parallels the common
  97. X`60`60ll'' alias for long listings in Unix, and the similarity between the
  98. Xoutputs of the two commands was intentional.
  99. X.PD
  100. X.SH SEE ALSO
  101. Xfunzip(1), unzip(1), zip(1), zipcloak(1), zipnote(1), zipsplit(1)
  102. X.PD
  103. X.SH AUTHOR
  104. XGreg Roelofs (also known as Cave Newt).  \fIZipInfo\fP is partly based on
  105. XS. H. Smith's \fRunzip\fP and contains pattern-matching code by J. Kercheval
  106. V,
  107. Xbut mostly it was written from scratch.  The OS/2 extra-field code is by
  108. XKai Uwe Rommel.
  109. $ CALL UNPACK [.UNZIP50]ZIPINFO.1;1 1997710893
  110. $ create 'f'
  111. X/*--------------------------------------------------------------------------
  112. V-
  113. X
  114. X  zipinfo.c
  115. X
  116. X  This program reads all sorts of totally nifty information, including the
  117. X  central directory stuff, from a ZIP archive ("zipfile" for short).  It
  118. X  started as just a testbed for fooling with zipfiles, but at this point
  119. X  it's actually a moderately useful utility.  It also became the basis
  120. X  for the rewrite of unzip (3.16 -> 4.0), using the central directory for
  121. X  processing rather than the individual (local) file headers.
  122. X
  123. X  For myself, I find it convenient to define an alias "ii" (under Unix and
  124. X  VMS) or to rename the executable to "ii.exe" (OS/2 and DOS).  This nicely
  125. X  complements my Unix long-listing "ll" alias (ls -lF), since zipinfo's de-
  126. X  fault action is to produce a Unix-like listing of the archive's contents.
  127. X  "ii zipfile" is easier to type than "zipinfo zipfile"...
  128. X
  129. X  Another dandy product from your buddies at Newtware!
  130. X
  131. X  --------------------------------------------------------------------------
  132. V-
  133. X
  134. X  To compile (partial instructions; some of this stuff doesn't exist yet):
  135. X
  136. X     under Unix (cc):  make zipinfo
  137. X
  138. X     under MS-DOS (TurboC):  make -fMKZIPINF.DOS   (edit appropriately)
  139. X
  140. X     under MS-DOS (MSC):  make MKZIPINF.DOS
  141. X       (or use Makefile if you have MSC 6.0:  "nmake zi_dos")
  142. X
  143. X     under OS/2 (MSC):  make MKZIPINF.DOS   (edit appropriately)
  144. X       (or use Makefile if you have MSC 6.0:  "nmake zi_os2")
  145. X
  146. X     under Atari OS:  beats me...
  147. X
  148. X     under VMS:  @MAKE_ZIPINFO     (see also VMSNOTES)
  149. X                 ZIPINFO == $DISKNAME:`5BDIRECTORY`5DZIPINFO.EXE
  150. X
  151. X     under Macintosh OS:  who knows?
  152. X
  153. X  --------------------------------------------------------------------------
  154. V-
  155. X
  156. X  Source:     unzip50.zip (.tar.Z, etc.) for Unix, VMS, OS/2 and MS-DOS; see
  157. X              `60Where' in source distribution for ftp, uucp and mail-server
  158. X              sites.
  159. X  Author:     Greg Roelofs, roelofs@nas.nasa.gov, 23 August 1990
  160. X  Copyright:  Portions copyright 1992 Greg Roelofs.  Portions adapted from
  161. X              unzip 3.1.  SizeOfEAs() by Kai Uwe Rommel.
  162. X
  163. X  --------------------------------------------------------------------------
  164. V-*/
  165. X
  166. X
  167. X
  168. X
  169. X#ifndef ZIPINFO
  170. X#  define ZIPINFO   /* needed for Unix permissions in non-Unix environments
  171. V */
  172. X#endif /* !ZIPINFO */
  173. X#include "unzip.h"
  174. X
  175. X#define VERSION  "v1.0 of 21 August 92"
  176. X
  177. X#define LFLAG    3        /* for short "ls -l" type listing */
  178. X
  179. X#define EAID     0x0009   /* OS/2 EA extra field ID */
  180. Xtypedef struct `7B          /* for OS/2 info in OS/2 and non-OS/2 environmen
  181. Vts */
  182. X    unsigned short nID;
  183. X    unsigned short nSize;
  184. X    ULONG lSize;
  185. X`7D EAHEADER, *PEAHEADER;
  186. X
  187. X
  188. X
  189. X
  190. X/**********************/
  191. X/*  Global Variables  */
  192. X/**********************/
  193. X
  194. X#ifdef EBCDIC
  195. X   int  aflag=1;        /* this is so you can read it on the screen  */
  196. X#else                   /* (basically, entire program is "unzip -c") */
  197. X   int  aflag=0;
  198. X#endif
  199. Xint lflag=(-1);         /* '-1slmv':  listing format */
  200. Xint hflag=0;            /* '-h':  header line */
  201. Xint tflag=0;            /* '-t':  totals line */
  202. X
  203. Xbyte *inbuf, *inptr;    /* input buffer (any size is legal) and pointer */
  204. Xint incnt;
  205. X
  206. Xint zipfd;              /* zipfile file handle */
  207. Xchar zipfn`5BFILNAMSIZ`5D;
  208. X
  209. Xchar local_hdr_sig`5B5`5D = "\120";    /* remaining signature bytes come lat
  210. Ver:  */
  211. Xchar central_hdr_sig`5B5`5D = "\120";  /*  must initialize at runtime so zip
  212. Vinfo */
  213. Xchar end_central_sig`5B5`5D = "\120";  /*  executable won't look like a zipf
  214. Vile  */
  215. Xchar extd_local_sig`5B5`5D = "\120";
  216. X
  217. Xcdir_file_hdr crec;             /* used in zipinfo.c, misc.c */
  218. Xlocal_file_hdr lrec;
  219. Xecdir_rec ecrec;
  220. Xstruct stat statbuf;            /* used by main() */
  221. X
  222. Xint process_all_files;
  223. Xlongint real_ecrec_offset, expect_ecrec_offset;
  224. Xlongint extra_bytes=0;          /* used in zipinfo.c, misc.c */
  225. Xlongint cur_zipfile_bufstart;   /* find_end_central_dir, readbuf */
  226. X
  227. Xmin_info info, *pInfo=(&info);
  228. X
  229. Xbyte *extra_field = NULL;       /* used by VMS, Mac and OS/2 versions */
  230. Xbyte *outbuf;                   /* buffer for rle look-back, zipfile comment
  231. V */
  232. Xbyte *outout;                   /* scratch pad for ASCII-native trans */
  233. X
  234. Xchar filename`5BFILNAMSIZ`5D;
  235. Xchar sig`5B5`5D;
  236. Xchar *fnames`5B2`5D = `7B"*", NULL`7D;    /* default filenames vector */
  237. Xchar **fnv = fnames;
  238. X
  239. Xstatic byte *hold;
  240. Xstatic longint ziplen;
  241. Xstatic UWORD hostnum;
  242. Xstatic UWORD methnum;
  243. Xstatic UWORD extnum;
  244. X
  245. Xchar *EndSigMsg = "\nwarning:\
  246. X  didn't find end-of-central-dir signature at end of central dir.\n";
  247. Xchar *CentSigMsg =
  248. X  "error:  expected central file header signature not found (file #%u).\n";
  249. Xchar *SeekMsg =
  250. X  "error:  attempt to seek before beginning of zipfile\n%s";
  251. X
  252. X#ifdef VMS
  253. Xchar *ReportMsg = "\
  254. X  (please check that you have transferred or created the zipfile in the\n\
  255. X  appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\
  256. Vn";
  257. X#else /* !VMS */
  258. Xchar *ReportMsg = "\
  259. X  (please check that you have transferred or created the zipfile in the\n\
  260. X  appropriate BINARY mode and that you have compiled unzip properly)\n";
  261. X#endif /* ?VMS */
  262. X
  263. X
  264. X
  265. X
  266. X
  267. X
  268. X/******************/
  269. X/*  Main program  */
  270. X/******************/
  271. X
  272. Xmain(argc, argv)
  273. X    int    argc;
  274. X    char   *argv`5B`5D;
  275. X`7B
  276. X    char   *s;
  277. X    int    c, error=FALSE, negative=0;
  278. X    int    hflag_slmv=TRUE, hflag_1=FALSE;  /* diff options => diff defaults
  279. V */
  280. X    int    tflag_slm=TRUE, tflag_1v=FALSE;
  281. X    int    explicit_h=FALSE, explicit_t=FALSE;
  282. X
  283. X
  284. X
  285. X/*--------------------------------------------------------------------------
  286. V-
  287. X    Everybody is now "NOTINT16," but this is a nice little piece of code, so
  288. X    just comment it out for future reference. :-)
  289. X  --------------------------------------------------------------------------
  290. V-*/
  291. X
  292. X#if 0
  293. X# ifndef KNOW_IT_WORKS  /* define this to save space, if things already work
  294. V */
  295. X# ifndef DOS_OS2        /* already works (no RISCy OS/2's yet...) */
  296. X# ifndef NOTINT16       /* whole point is to see if this NEEDS defining */
  297. X    `7B
  298. X        int error=0;
  299. X        long testsig;
  300. X        static char *mach_type`5B3`5D = `7B"big-endian", "structure-padding"
  301. V,
  302. X                                     "big-endian and structure-padding"`7D;
  303. X
  304. X        strcpy((char *)&testsig,"012");
  305. X        if (testsig != 0x00323130)
  306. X            error = 1;
  307. X        if (sizeof(cdir_file_hdr) != CREC_SIZE)
  308. X            error += 2;
  309. X        if (error--)
  310. X            fprintf(stderr, "It appears that your machine is %s.  If errors\
  311. Vn\
  312. Xoccur, please try recompiling with \"NOTINT16\" defined (read the\n\
  313. XMakefile, or try \"make zipinfo\").\n\n", mach_type`5Berror`5D);
  314. X    `7D
  315. X# endif /* !NOTINT16 */
  316. X# endif /* !DOS_OS2 */
  317. X# endif /* !KNOW_IT_WORKS */
  318. X#endif /* 0 */
  319. X
  320. X/*--------------------------------------------------------------------------
  321. V-
  322. X    Put environment-variable options into the queue, then rip through any
  323. X    command-line options lurking about...
  324. X  --------------------------------------------------------------------------
  325. V-*/
  326. X
  327. X    envargs(&argc, &argv, ENV_ZIPINFO);
  328. X
  329. X    while (--argc > 0 && (*++argv)`5B0`5D == '-') `7B
  330. X        s = argv`5B0`5D + 1;
  331. X        while ((c = *s++) != 0) `7B    /* "!= 0":  prevent Turbo C warning *
  332. V/
  333. X            switch (c) `7B
  334. X                case '-':
  335. X                    ++negative;
  336. X                    break;
  337. X                case '1':      /* shortest listing:  just filenames */
  338. X                    if (negative)
  339. X                        lflag = -2, negative = 0;
  340. X                    else
  341. X                        lflag = 1;
  342. X                    break;
  343. X                case 'h':      /* header line */
  344. X                    if (negative)
  345. X                        hflag_1 = hflag_slmv = FALSE, negative = 0;
  346. X                    else `7B
  347. X                        hflag_1 = hflag_slmv = explicit_h = TRUE;
  348. X                        if (lflag == -1)
  349. X                            lflag = 0;
  350. X                    `7D
  351. X                    break;
  352. X                case 'l':      /* longer form of "ls -l" type listing */
  353. X                    if (negative)
  354. X                        lflag = -2, negative = 0;
  355. X                    else
  356. X                        lflag = 5;
  357. X                    break;
  358. X                case 'm':      /* medium form of "ls -l" type listing */
  359. X                    if (negative)
  360. X                        lflag = -2, negative = 0;
  361. X                    else
  362. X                        lflag = 4;
  363. X                    break;
  364. X                case 's':      /* default:  shorter "ls -l" type listing */
  365. X                    if (negative)
  366. X                        lflag = -2, negative = 0;
  367. X                    else
  368. X                        lflag = 3;
  369. X                    break;
  370. X                case 't':      /* totals line */
  371. X                    if (negative)
  372. X                        tflag_1v = tflag_slm = FALSE, negative = 0;
  373. X                    else `7B
  374. X                        tflag_1v = tflag_slm = explicit_t = TRUE;
  375. X                        if (lflag == -1)
  376. X                            lflag = 0;
  377. X                    `7D
  378. X                    break;
  379. X                case 'v':      /* turbo-verbose listing */
  380. X                    if (negative)
  381. X                        lflag = -2, negative = 0;
  382. X                    else
  383. X                        lflag = 10;
  384. X                    break;
  385. X                default:
  386. X                    error = TRUE;
  387. X                    break;
  388. X            `7D
  389. X        `7D
  390. X    `7D
  391. X    if ((argc-- == 0) `7C`7C error)
  392. X        RETURN(usage(error));
  393. X
  394. X    if (argc != 0)
  395. X        process_all_files = FALSE;
  396. X    else
  397. X        process_all_files = TRUE;   /* for speed */
  398. X
  399. X    /* if no listing options given (or all negated), or if only -h/-t given
  400. X     * with individual files specified, use default listing format */
  401. X    if ((lflag < 0) `7C`7C (!process_all_files && (lflag == 0)))
  402. X        lflag = LFLAG;
  403. X
  404. X    /* set header and totals flags to default or specified values */
  405. X    switch (lflag) `7B
  406. X        case 0:   /* 0:  can only occur if either -t or -h explicitly given;
  407. V */
  408. X        case 1:   /*  therefore set both flags equal to normally false value
  409. V */
  410. X            hflag = hflag_1;
  411. X            tflag = tflag_1v;
  412. X            break;
  413. X        case 3:
  414. X        case 4:
  415. X        case 5:
  416. X            hflag = (!process_all_files && !explicit_h)? FALSE : hflag_slmv;
  417. X            tflag = (!process_all_files && !explicit_t)? FALSE : tflag_slm;
  418. X            break;
  419. X        case 10:
  420. X            hflag = hflag_slmv;
  421. X            tflag = tflag_1v;
  422. X            break;
  423. X    `7D
  424. X
  425. X/*--------------------------------------------------------------------------
  426. V-
  427. X    Now get the zipfile name from the command line and see if it exists as a
  428. X    regular (non-directory) file.  If not, append the ".zip" suffix.  We don
  429. V't
  430. X    immediately check to see if this results in a good name, but we will do
  431. V so
  432. X    later.  In the meantime, see if there are any member filespecs on the co
  433. Vm-
  434. X    mand line, and if so, set the filename pointer to point at them.
  435. X  --------------------------------------------------------------------------
  436. V-*/
  437. X
  438. X    strcpy(zipfn, *argv++);
  439. X    if (stat(zipfn, &statbuf) `7C`7C (statbuf.st_mode & S_IFMT) == S_IFDIR)
  440. X        strcat(zipfn, ZSUFX);
  441. X#if defined(UNIX) && !defined(VMS)  /* Unix executables have no extension--
  442. V */
  443. X    else if (statbuf.st_mode & S_IXUSR)  /* might find zip, not zip.zip; etc
  444. V */
  445. X        fprintf(stderr, "\nnote:  file `5B %s `5D may be an executable\n\n",
  446. V zipfn);
  447. X#endif /* UNIX && !VMS */
  448. X
  449. X    if (stat(zipfn, &statbuf)) `7B    /* try again */
  450. X        fprintf(stderr, "error:  can't find zipfile `5B %s `5D\n", zipfn);
  451. X        RETURN(9);                  /* 9:  file not found */
  452. X    `7D else
  453. X        ziplen = statbuf.st_size;
  454. X
  455. X    if (!process_all_files)
  456. X        fnv = argv;
  457. X
  458. X/*--------------------------------------------------------------------------
  459. V-
  460. X    Okey dokey, we have everything we need to get started.  Let's roll.
  461. X  --------------------------------------------------------------------------
  462. V-*/
  463. X
  464. X    inbuf = (byte *) (malloc(INBUFSIZ + 4));    /* 4 extra for hold`5B`5D (b
  465. Velow) */
  466. X    outbuf = (byte *) (malloc(OUTBUFSIZ + 1));  /* 1 extra for string termin
  467. V. */
  468. X    if (aflag)                  /* if need an ascebc scratch, */
  469. X        outout = (byte *) (malloc(OUTBUFSIZ));
  470. X    else                        /*  allocate it... */
  471. X        outout = outbuf;        /*  else just point to outbuf */
  472. X
  473. X    if ((inbuf == NULL) `7C`7C (outbuf == NULL) `7C`7C (outout == NULL)) `7B
  474. X        fprintf(stderr, "error:  can't allocate zipinfo buffers\n");
  475. X        RETURN(4);              /* 4-8:  insufficient memory */
  476. X    `7D
  477. X    hold = &inbuf`5BINBUFSIZ`5D;    /* to check for boundary-spanning signat
  478. Vures */
  479. X
  480. X    RETURN(process_zipfile());  /* keep passing errors back... */
  481. X
  482. X`7D /* end main() */
  483. X
  484. X
  485. X
  486. X
  487. X
  488. X/**********************/
  489. X/*  Function usage()  */
  490. X/**********************/
  491. X
  492. Xint usage(error)
  493. X    int error;
  494. X`7B
  495. X    FILE *usagefp;
  496. X
  497. X
  498. X/*--------------------------------------------------------------------------
  499. V-
  500. X    If user requested usage, send it to stdout; else send to stderr.
  501. X  --------------------------------------------------------------------------
  502. V-*/
  503. X
  504. X    if (error)
  505. X        usagefp = (FILE *) stderr;
  506. X    else
  507. X        usagefp = (FILE *) stdout;
  508. X
  509. X    fprintf(usagefp, "\
  510. X   ZipInfo:  Zipfile Information Utility %s\n\
  511. X   (brought to you by Newtware, Inc., and the fine folks at Info-ZIP)\n\n\
  512. X   Usage:  zipinfo `5B-1smlvht`5D file`5B.zip`5D `5Bfilespec...`5D\n", VERSI
  513. VON);
  514. X    fprintf(usagefp, "\
  515. X     -1  list filenames only, one per line (useful for pipes)\n\
  516. X     -s  list zipfile info in short Unix \"ls -l\" format:  default\n\
  517. X     -m  list zipfile info in medium Unix \"ls -l\" format\n\
  518. X     -l  list zipfile info in long Unix \"ls -l\" format\n\
  519. X     -v  list zipfile information in verbose, multi-page format\n\
  520. X     -h  list header line\n\
  521. X     -t  list totals for files listed or for all files\n");
  522. X/*
  523. X     -p  disable automatic \"more\" function (for pipes) `5Bnot implemented`
  524. V5D\n");
  525. X */
  526. X
  527. X#ifdef VMS
  528. X    fprintf(usagefp, "\nRemember that non-lowercase filespecs must be quoted
  529. V\
  530. X in VMS (e.g., \"Makefile\").\n");
  531. X#endif
  532. X
  533. X    if (error)
  534. X        return 10;    /* 10:  bad or illegal parameters specified */
  535. X    else
  536. X        return 0;     /* just wanted usage screen: no error */
  537. X
  538. X`7D /* end function usage() */
  539. X
  540. X
  541. X
  542. X
  543. X
  544. X/********************************/
  545. X/*  Function process_zipfile()  */
  546. X/********************************/
  547. X
  548. Xint process_zipfile()   /* return PK-type error code */
  549. X`7B
  550. X    int error=0, error_in_archive;
  551. X
  552. X
  553. X/*--------------------------------------------------------------------------
  554. V-
  555. X    Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
  556. X    lation, which would corrupt the bitstreams.
  557. X  --------------------------------------------------------------------------
  558. V-*/
  559. X
  560. X#ifdef VMS
  561. X    if (check_format())         /* check for variable-length format */
  562. X        return 2;               /* 2:  error in zipfile */
  563. X#endif /* VMS */
  564. X
  565. X    if (open_input_file())      /* this should never happen, given the */
  566. X        return 9;               /*   stat() test in main(), but... */
  567. X
  568. X/*--------------------------------------------------------------------------
  569. V-
  570. X    Reconstruct the various PK signature strings, and find and process the
  571. X    end-of-central-directory header.
  572. X  --------------------------------------------------------------------------
  573. V-*/
  574. X
  575. X    strcat(local_hdr_sig, LOCAL_HDR_SIG);
  576. X    strcat(central_hdr_sig, CENTRAL_HDR_SIG);
  577. X    strcat(end_central_sig, END_CENTRAL_SIG);
  578. X    strcat(extd_local_sig, EXTD_LOCAL_SIG);
  579. X
  580. X    if (find_end_central_dir()) `7B   /* not found; nothing to do */
  581. X        close(zipfd);
  582. X        return 2;                   /* 2:  error in zipfile */
  583. X    `7D
  584. X
  585. X    real_ecrec_offset = cur_zipfile_bufstart + (inptr-inbuf);
  586. X#ifdef TEST
  587. X    printf("\n  found end-of-central-dir signature at offset %ld (%.8lXh)\n"
  588. V,
  589. X      real_ecrec_offset, real_ecrec_offset);
  590. X    printf("    from beginning of file; offset %d (%.4Xh) within block\n",
  591. X      inptr-inbuf, inptr-inbuf);
  592. X#endif
  593. X
  594. X    /* sets expect_ecrec_offset: */
  595. X    if ((error_in_archive = process_end_central_dir()) > 1) `7B
  596. X        close(zipfd);
  597. X        return error_in_archive;
  598. X    `7D
  599. X
  600. X/*--------------------------------------------------------------------------
  601. V-
  602. X    Test the end-of-central-directory info for incompatibilities (multi-disk
  603. X    archives) or inconsistencies (missing or extra bytes in zipfile).
  604. X  --------------------------------------------------------------------------
  605. V-*/
  606. X
  607. X    if (ecrec.number_this_disk != ecrec.num_disk_with_start_central_dir) `7B
  608. X        fprintf(stderr, "\n\
  609. X     Zipfile is part of a multi-disk archive, and this is not the disk on\
  610. X     which the central zipfile directory begins.\n");
  611. X        error_in_archive = 11;  /* 11:  no files found */
  612. X    `7D else `7B
  613. X        if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) `7B
  614. X            fprintf(stderr, "\nerror:  missing %ld bytes in zipfile (\
  615. Xattempting to process anyway)\n\n", -extra_bytes);
  616. X            error_in_archive = 2;       /* 2:  (weak) error in zipfile */
  617. X        `7D else if (extra_bytes > 0) `7B
  618. X            if ((ecrec.offset_start_central_directory == 0) &&
  619. X                (ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
  620. X            `7B
  621. X                fprintf(stderr, "\nerror:  NULL central directory offset (\
  622. Xattempting to process anyway)\n\n");
  623. X                error_in_archive = 2;   /* 2:  (weak) error in zipfile */
  624. X            `7D else `7B
  625. X                fprintf(stderr, "\nwarning:  extra %ld bytes at beginning or
  626. V\
  627. X within zipfile\n          (attempting to process anyway)\n\n", extra_bytes)
  628. V;
  629. X                error_in_archive = 1;   /* 1:  warning error */
  630. X            `7D
  631. X        `7D
  632. X
  633. X    /*----------------------------------------------------------------------
  634. V-
  635. X        Check for empty zipfile and exit now if so.
  636. X      ----------------------------------------------------------------------
  637. V-*/
  638. X
  639. X        if (expect_ecrec_offset == 0L  &&  ecrec.size_central_directory == 0
  640. V) `7B
  641. X            printf("%sEmpty zipfile.\n", lflag>9 ? "\n  " : "");
  642. X            close(zipfd);
  643. X            return (error_in_archive > 1)? error_in_archive : 1;
  644. X        `7D
  645. X
  646. X    /*----------------------------------------------------------------------
  647. V-
  648. X        Compensate for missing or extra bytes, and seek to where the start
  649. X        of central directory should be.  If header not found, uncompensate
  650. X        and try again (necessary for at least some Atari archives created
  651. X        with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT).
  652. X      ----------------------------------------------------------------------
  653. V-*/
  654. X
  655. X        LSEEK( ecrec.offset_start_central_directory )
  656. X        if ((readbuf(sig, 4) <= 0) `7C`7C strncmp(sig, central_hdr_sig, 4))
  657. V `7B
  658. X            longint tmp = extra_bytes;
  659. X
  660. X            extra_bytes = 0;
  661. X            LSEEK( ecrec.offset_start_central_directory )
  662. X            if ((readbuf(sig, 4) <= 0) `7C`7C strncmp(sig, central_hdr_sig,
  663. V 4)) `7B
  664. X                fprintf(stderr,
  665. X            "error:  start of central directory not found; zipfile corrupt.\
  666. Vn");
  667. X                fprintf(stderr, ReportMsg);
  668. X                close(zipfd);
  669. X                return 3;           /* 3:  severe error in zipfile */
  670. X            `7D
  671. X            fprintf(stderr, "error:  reported length of central directory is
  672. V \
  673. X%d bytes too\n        long (Atari STZIP zipfile?  J.H. Holm ZIPSPLIT zipfile
  674. V?)\
  675. X.\n        Compensating...\n\n", -tmp);
  676. X            error_in_archive = 2;   /* 2:  (weak) error in zipfile */
  677. X        `7D
  678. X
  679. X    /*----------------------------------------------------------------------
  680. V-
  681. X        Seek to the start of the central directory one last time, since we
  682. X        have just read the first entry's signature bytes; then do the centra
  683. Vl
  684. X        directory and close the zipfile.
  685. X      ----------------------------------------------------------------------
  686. V-*/
  687. X
  688. X        LSEEK( ecrec.offset_start_central_directory )
  689. X        if ((error = process_central_dir()) > error_in_archive)
  690. X            error_in_archive = error;    /* don't overwrite stronger error *
  691. V/
  692. X        if (lflag > 9)
  693. X            printf("\n");
  694. X    `7D
  695. X
  696. X    close(zipfd);
  697. X    return error_in_archive;
  698. X
  699. X`7D /* end function process_zipfile() */
  700. X
  701. X
  702. X
  703. X
  704. X
  705. X/*************************************/
  706. X/*  Function find_end_central_dir()  */
  707. X/*************************************/
  708. X
  709. Xint find_end_central_dir()   /* return 0 if found, 1 otherwise */
  710. X`7B
  711. X    int       i, numblks;
  712. X    longint   tail_len;
  713. X
  714. X
  715. X
  716. X/*--------------------------------------------------------------------------
  717. V-
  718. X    Treat case of short zipfile separately.
  719. X  --------------------------------------------------------------------------
  720. V-*/
  721. X
  722. X    if (ziplen <= INBUFSIZ) `7B
  723. X        lseek(zipfd, 0L, SEEK_SET);
  724. X        if ((incnt = read(zipfd,inbuf,(unsigned int)ziplen)) == (int)ziplen)
  725. X            /* 'P' must be at least 22 bytes from end of zipfile */
  726. X            for (inptr = inbuf+(int)ziplen-22;  inptr >= inbuf;  --inptr)
  727. X                if ((ascii_to_native(*inptr) == 'P')  &&
  728. X                     !strncmp((char *)inptr, end_central_sig, 4)) `7B
  729. X                    incnt -= inptr - inbuf;
  730. X                    return 0;   /* found it! */
  731. X                `7D               /* ...otherwise fall through & fail */
  732. X
  733. X/*--------------------------------------------------------------------------
  734. V-
  735. X    Zipfile is longer than INBUFSIZ:  may need to loop.  Start with short
  736. X    block at end of zipfile (if not TOO short).
  737. X  --------------------------------------------------------------------------
  738. V-*/
  739. X
  740. X    `7D else `7B
  741. X        if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) `7B
  742. X            cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
  743. X            if ((incnt = read(zipfd,inbuf,(unsigned int)tail_len)) !=
  744. X                (int)tail_len)
  745. X                goto fail;      /* shut up; it's expedient. */
  746. X
  747. X            /* 'P' must be at least 22 bytes from end of zipfile */
  748. X            for (inptr = inbuf+(int)tail_len-22;  inptr >= inbuf;  --inptr)
  749. X                if ((ascii_to_native(*inptr) == 'P')  &&
  750. X                     !strncmp((char *)inptr, end_central_sig, 4)) `7B
  751. X                    incnt -= inptr - inbuf;
  752. X                    return 0;   /* found it */
  753. X                `7D               /* ...otherwise search next block */
  754. X            /* sig may span block boundary: */
  755. X            strncpy((char *)hold, (char *)inbuf, 3);
  756. X        `7D else
  757. X            cur_zipfile_bufstart = ziplen - tail_len;
  758. X
  759. X        /*
  760. X         * Loop through blocks of zipfile data, starting at the end and goin
  761. Vg
  762. X         * toward the beginning.  Need only check last 65557 bytes of zipfil
  763. Ve:
  764. X         * comment may be up to 65535 bytes long, end-of-central-directory r
  765. Vec-
  766. X         * ord is 18 bytes (shouldn't hardcode this number, but what the hel
  767. Vl:
  768. X         * already did so above (22=18+4)), and sig itself is 4 bytes.
  769. X         *`20
  770. X         * zipinfo:  check the whole file, just in case some transfer protoc
  771. Vol
  772. X         * has appended a whole bunch of garbage at the end of the archive.
  773. X         *
  774. X         *                =todo=   ==done==   ==rounding==    =blksiz=
  775. V      */
  776. X        numblks = (int) ((ziplen - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
  777. X
  778. X        for (i = 1;  i <= numblks;  ++i) `7B
  779. X            cur_zipfile_bufstart -= INBUFSIZ;
  780. X            lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
  781. X            if ((incnt = read(zipfd,inbuf,INBUFSIZ)) != INBUFSIZ)
  782. X                break;          /* fall through and fail */
  783. X
  784. X            for (inptr = inbuf+INBUFSIZ-1;  inptr >= inbuf;  --inptr)
  785. X                if ((ascii_to_native(*inptr) == 'P')  &&
  786. X                     !strncmp((char *)inptr, end_central_sig, 4)) `7B
  787. X                    incnt -= inptr - inbuf;
  788. X                    return 0;   /* found it */
  789. X                `7D
  790. X            /* sig may span block boundary: */
  791. X            strncpy((char *)hold, (char *)inbuf, 3);
  792. X        `7D
  793. X
  794. X    `7D /* end if (ziplen > INBUFSIZ) */
  795. X
  796. X/*--------------------------------------------------------------------------
  797. V-
  798. X    Searched through whole region where signature should be without finding
  799. X    it.  Print informational message and die a horrible death.
  800. X  --------------------------------------------------------------------------
  801. V-*/
  802. X
  803. Xfail:
  804. X
  805. X    fprintf(stderr, "\n\
  806. X     %s:\n\n\
  807. X     End-of-central-directory signature not found.  Either this file is not\
  808. Vn\
  809. X     a zipfile, or it constitutes one disk of a multi-part archive.  In the\
  810. Vn\
  811. X     latter case the central directory and zipfile comment will be found on\
  812. Vn\
  813. X     the last disk(s) of this archive.\n", zipfn);
  814. X    return 1;   /* failed */
  815. X
  816. X`7D /* end function find_end_central_dir() */
  817. X
  818. X
  819. X
  820. X
  821. X
  822. X/****************************************/
  823. X/*  Function process_end_central_dir()  */
  824. X/****************************************/
  825. X
  826. Xint process_end_central_dir()   /* return PK-type error code */
  827. X`7B
  828. X    ec_byte_rec   byterec;
  829. X    int           error=0;
  830. X
  831. X
  832. X/*--------------------------------------------------------------------------
  833. X    Read the end-of-central-directory record and do any necessary machine-
  834. X    type conversions (byte ordering, structure padding compensation) by
  835. X    copying character array to struct.
  836. X  --------------------------------------------------------------------------
  837. V-*/
  838. X
  839. X    if (readbuf((char *)byterec, ECREC_SIZE+4) <= 0)
  840. X        return 51;
  841. X
  842. X    ecrec.number_this_disk =
  843. X        makeword(&byterec`5BNUMBER_THIS_DISK`5D);
  844. X    ecrec.num_disk_with_start_central_dir =
  845. X        makeword(&byterec`5BNUM_DISK_WITH_START_CENTRAL_DIR`5D);
  846. X    ecrec.num_entries_centrl_dir_ths_disk =
  847. X        makeword(&byterec`5BNUM_ENTRIES_CENTRL_DIR_THS_DISK`5D);
  848. X    ecrec.total_entries_central_dir =
  849. X        makeword(&byterec`5BTOTAL_ENTRIES_CENTRAL_DIR`5D);
  850. X    ecrec.size_central_directory =
  851. X        makelong(&byterec`5BSIZE_CENTRAL_DIRECTORY`5D);
  852. X    ecrec.offset_start_central_directory =
  853. X        makelong(&byterec`5BOFFSET_START_CENTRAL_DIRECTORY`5D);
  854. X    ecrec.zipfile_comment_length =
  855. X        makeword(&byterec`5BZIPFILE_COMMENT_LENGTH`5D);
  856. X
  857. X    expect_ecrec_offset = ecrec.offset_start_central_directory +
  858. X                           ecrec.size_central_directory;
  859. X
  860. X/*--------------------------------------------------------------------------
  861. V-
  862. X    Print out various interesting things about the zipfile.
  863. X  --------------------------------------------------------------------------
  864. V-*/
  865. X
  866. X    /* header fits on one line, for anything up to 10GB and 10000 files: */
  867. X    if (hflag)
  868. X        printf((strlen(zipfn)<39)? "Archive:  %s   %ld bytes   %d file%s\n"
  869. X          : "Archive:  %s   %ld   %d\n", zipfn, ziplen,
  870. X          ecrec.total_entries_central_dir,
  871. X          (ecrec.total_entries_central_dir==1)? "":"s");
  872. X
  873. X    /* verbose format */
  874. X    if (lflag > 9) `7B
  875. X        printf("\nEnd-of-central-directory record:\n");
  876. X        printf("-------------------------------\n\n");
  877. X
  878. X        printf("\
  879. X  Actual offset of end-of-central-dir record:   %9ld (%.8lXh)\n\
  880. X  Expected offset of end-of-central-dir record: %9ld (%.8lXh)\n\
  881. X  (based on the length of the central directory and its expected offset)\n\n
  882. V",
  883. X          expect_ecrec_offset, expect_ecrec_offset,
  884. X          real_ecrec_offset, real_ecrec_offset);
  885. X
  886. X        if (ecrec.number_this_disk == 0) `7B
  887. X            printf("\
  888. X  This zipfile constitutes the sole disk of a single-part archive; its\n\
  889. X  central directory contains %u %s.  The central directory is %lu\n\
  890. X  (%.8lXh) bytes long, and its (expected) offset in bytes from the\n\
  891. X  beginning of the zipfile is %lu (%.8lXh).\n\n",
  892. X              ecrec.total_entries_central_dir,
  893. X              (ecrec.total_entries_central_dir == 1)? "entry" : "entries",
  894. X              ecrec.size_central_directory, ecrec.size_central_directory,
  895. X              ecrec.offset_start_central_directory,
  896. X              ecrec.offset_start_central_directory);
  897. X        `7D else `7B
  898. X            printf("\
  899. X  This zipfile constitutes disk %u of a multi-part archive.  The central\n\
  900. X  directory starts on disk %u; %u of its entries %s contained within\n\
  901. X  this zipfile, out of a total of %u %s.  The entire central\n\
  902. X  directory is %lu (%.8lXh) bytes long, and its offset in bytes from\n\
  903. X  the beginning of the zipfile in which it begins is %lu (%.8lXh).\n\n",
  904. X              ecrec.number_this_disk,
  905. X              ecrec.num_disk_with_start_central_dir,
  906. X              ecrec.num_entries_centrl_dir_ths_disk,
  907. X              (ecrec.num_entries_centrl_dir_ths_disk == 1)? "is" : "are",
  908. X              ecrec.total_entries_central_dir,
  909. X              (ecrec.total_entries_central_dir == 1) ? "entry" : "entries",
  910. X              ecrec.size_central_directory, ecrec.size_central_directory,
  911. X              ecrec.offset_start_central_directory,
  912. X              ecrec.offset_start_central_directory);
  913. X        `7D
  914. X
  915. X    /*----------------------------------------------------------------------
  916. V-
  917. X        Get the zipfile comment, if any, and print it out.  (Comment may be
  918. X        up to 64KB long.  May the fleas of a thousand camels infest the arm-
  919. X        pits of anyone who actually takes advantage of this fact.)
  920. X      ----------------------------------------------------------------------
  921. V-*/
  922. X
  923. X        if (!ecrec.zipfile_comment_length)
  924. X            printf("  There is no zipfile comment.\n");
  925. X        else `7B
  926. X            printf("  The zipfile comment is %u bytes long and contains the
  927. V following text:\n\n",
  928. X              ecrec.zipfile_comment_length );
  929. X            printf("======================== zipfile comment begins ========
  930. V==================\n");
  931. X            if (do_string(ecrec.zipfile_comment_length, DISPLAY))
  932. X                error = 1;          /* 1:  warning error */
  933. X            printf("\n========================= zipfile comment ends =======
  934. V====================\n");
  935. X            if (error)
  936. X                printf("\n  The zipfile comment is truncated.\n");
  937. X        `7D /* endif (comment exists) */
  938. X
  939. X    `7D /* endif (verbose) */
  940. X
  941. X    return error;
  942. X
  943. X`7D /* end function process_end_central_dir() */
  944. X
  945. X
  946. X
  947. X
  948. X
  949. X/************************************/
  950. X/*  Function process_central_dir()  */
  951. X/************************************/
  952. X
  953. Xint process_central_dir()   /* return PK-type error code */
  954. X`7B
  955. X    char    **fnamev;
  956. X    int     do_this_file=FALSE, none_found=TRUE, error, error_in_archive=0;
  957. X    UWORD   j, members=0;
  958. X    ULONG   c=0L, uc=0L;
  959. X
  960. X
  961. X/*--------------------------------------------------------------------------
  962. V-
  963. X    Set file pointer to start of central directory, then loop through cen-
  964. X    tral directory entries.  Check that directory-entry signature bytes are
  965. X    actually there (just a precaution), then process the entry.  We know
  966. X    the entire central directory is on this disk:  we wouldn't have any of
  967. X    this information unless the end-of-central-directory record was on this
  968. X    disk, and we wouldn't have gotten to this routine unless this is also
  969. X    the disk on which the central directory starts.  In practice, this had
  970. X    better be the *only* disk in the archive, but maybe someday we'll add
  971. X    multi-disk support.
  972. X  --------------------------------------------------------------------------
  973. V-*/
  974. X
  975. X    pInfo->lcflag = 0;   /* match(), do_string():  never TRUE in zipinfo */
  976. X
  977. X    for (j = 0;  j < ecrec.total_entries_central_dir;  ++j) `7B
  978. X        if (readbuf(sig, 4) <= 0)
  979. X            return 51;          /* 51:  unexpected EOF */
  980. X        if (strncmp(sig, central_hdr_sig, 4)) `7B  /* just to make sure */
  981. X            fprintf(stderr, CentSigMsg, j);  /* sig not found */
  982. X            return 3;           /* 3:  error in zipfile */
  983. X        `7D
  984. X        if ((error = process_cdir_file_hdr()) != 0)
  985. X            return error;       /* only 51 (EOF) defined */
  986. X        if ((error = do_string(crec.filename_length, FILENAME)) != 0) `7B
  987. X          error_in_archive = error;   /* might be warning */
  988. X          if (error > 1)        /* fatal */
  989. X              return error;
  990. X        `7D
  991. X
  992. X        if (!process_all_files) `7B   /* check if specified on command line
  993. V */
  994. X            do_this_file = FALSE;
  995. X            fnamev = fnv;       /* don't destroy permanent filename ptr */
  996. X            for (--fnamev;  *++fnamev; )
  997. X                if (match(filename, *fnamev)) `7B
  998. X                    do_this_file = TRUE;
  999. X                    none_found = FALSE;
  1000. X                    break;      /* found match, so stop looping */
  1001. X                `7D
  1002. X        `7D
  1003. X
  1004. X    /*----------------------------------------------------------------------
  1005. V-
  1006. X        If current file was specified on command line, or if no names were
  1007. X        specified, do the listing for this file.  Otherwise, get rid of the
  1008. X        file comment and go back for the next file.
  1009. X      ----------------------------------------------------------------------
  1010. V-*/
  1011. X
  1012. X        if (process_all_files `7C`7C do_this_file) `7B
  1013. X            switch (lflag) `7B
  1014. X                case 1:
  1015. X                    printf("%s\n", filename);
  1016. X                    SKIP_(crec.extra_field_length)
  1017. X                    SKIP_(crec.file_comment_length)
  1018. X                    break;
  1019. X
  1020. X                case 3:
  1021. X                case 4:
  1022. X                case 5:
  1023. X                    if ((error = short_info()) != 0) `7B
  1024. X                        error_in_archive = error;   /* might be warning */
  1025. X                        if (error > 1)              /* fatal */
  1026. X                            return error;
  1027. X                    `7D
  1028. X                    break;
  1029. X
  1030. X                case 10:
  1031. X#ifdef VMS   /* GRR: FIX THIS (no pipes:  add cbreak-style "more" function)
  1032. V */
  1033. X                    printf("\nCentral directory entry #%d:\n", j);
  1034. X#else /* !VMS */
  1035. X                    /* formfeed/CR for piping to "more": */
  1036. X                    printf("%s\nCentral directory entry #%d:\n", "\014", j);
  1037. X#endif /* ?VMS */
  1038. X                    printf("---------------------------\n\n");
  1039. X
  1040. X                    if ((error = long_info()) != 0) `7B
  1041. X                      error_in_archive = error;   /* might be warning */
  1042. X                      if (error > 1)              /* fatal */
  1043. X                          return error;
  1044. X                    `7D
  1045. X                    break;
  1046. X
  1047. X                default:
  1048. X                    SKIP_(crec.extra_field_length)
  1049. X                    SKIP_(crec.file_comment_length)
  1050. X                    break;
  1051. X
  1052. X            `7D /* end switch (lflag) */
  1053. X
  1054. X            uc += crec.uncompressed_size;
  1055. X            c += crec.compressed_size;
  1056. X            if (crec.general_purpose_bit_flag & 1)
  1057. X                c -= 12;    /* if encrypted, don't count encryption header *
  1058. V/
  1059. X            ++members;
  1060. X
  1061. X        `7D else `7B   /* not listing */
  1062. X            SKIP_(crec.extra_field_length)
  1063. X            SKIP_(crec.file_comment_length)
  1064. X
  1065. X        `7D /* end if (list member?) */
  1066. X
  1067. X    `7D /* end for-loop (j: member files) */
  1068. X
  1069. X/*--------------------------------------------------------------------------
  1070. V-
  1071. X    Double check that we're back at the end-of-central-directory record.
  1072. X  --------------------------------------------------------------------------
  1073. V-*/
  1074. X
  1075. X    readbuf(sig, 4);
  1076. X    if (strncmp(sig, end_central_sig, 4)) `7B     /* just to make sure again
  1077. V */
  1078. X        fprintf(stderr, EndSigMsg);  /* didn't find end-of-central-dir sig *
  1079. V/
  1080. X        error_in_archive = 1;        /* 1:  warning error */
  1081. X    `7D
  1082. X
  1083. X/*--------------------------------------------------------------------------
  1084. V-
  1085. X    Check that we actually found requested files; if so, print totals.
  1086. X  --------------------------------------------------------------------------
  1087. V-*/
  1088. X
  1089. X    if (none_found && !process_all_files) `7B
  1090. X        fnamev = fnv;       /* don't destroy permanent filename ptr */
  1091. X        for (--fnamev;  *++fnamev; )
  1092. X            printf("zipinfo:  %s not found in %s\n", *fnamev, zipfn);
  1093. X    `7D else if (tflag)
  1094. X        printf(
  1095. X          "%d file%s, %lu bytes uncompressed, %lu bytes compressed:  %d%%\n"
  1096. V,
  1097. X          members, (members==1)? "":"s", uc, c, (uc==0)? 0 : ((uc>2000000L)?
  1098. X          ((int)((uc-c)/(uc/1000L))+5)/10 : ((int)((1000L*(uc-c))/uc)+5)/10)
  1099. V );
  1100. X
  1101. X    return error_in_archive;
  1102. X
  1103. X`7D /* end function process_central_dir() */
  1104. X
  1105. X
  1106. X
  1107. X
  1108. X
  1109. X/**************************************/
  1110. X/*  Function process_cdir_file_hdr()  */
  1111. X/**************************************/
  1112. X
  1113. Xint process_cdir_file_hdr()   /* return PK-type error code */
  1114. X`7B
  1115. X    cdir_byte_hdr   byterec;
  1116. X
  1117. X
  1118. X/*--------------------------------------------------------------------------
  1119. V-
  1120. X    Read the next central directory entry and do any necessary machine-type
  1121. X    conversions (byte ordering, structure padding compensation--do so by
  1122. X    copying the data from the array into which it was read (byterec) to the
  1123. X    usable struct (crec)).
  1124. X  --------------------------------------------------------------------------
  1125. V-*/
  1126. X
  1127. X    if (readbuf((char *) byterec, CREC_SIZE) <= 0)
  1128. X        return 51;   /* 51:  unexpected EOF */
  1129. X
  1130. X    crec.version_made_by`5B0`5D = byterec`5BC_VERSION_MADE_BY_0`5D;
  1131. X    crec.version_made_by`5B1`5D = byterec`5BC_VERSION_MADE_BY_1`5D;
  1132. X    crec.version_needed_to_extract`5B0`5D = byterec`5BC_VERSION_NEEDED_TO_EX
  1133. VTRACT_0`5D;
  1134. X    crec.version_needed_to_extract`5B1`5D = byterec`5BC_VERSION_NEEDED_TO_EX
  1135. VTRACT_1`5D;
  1136. X
  1137. X    crec.general_purpose_bit_flag =
  1138. X        makeword(&byterec`5BC_GENERAL_PURPOSE_BIT_FLAG`5D);
  1139. X    crec.compression_method =
  1140. X        makeword(&byterec`5BC_COMPRESSION_METHOD`5D);
  1141. X    crec.last_mod_file_time =
  1142. X        makeword(&byterec`5BC_LAST_MOD_FILE_TIME`5D);
  1143. X    crec.last_mod_file_date =
  1144. X        makeword(&byterec`5BC_LAST_MOD_FILE_DATE`5D);
  1145. X    crec.crc32 =
  1146. X        makelong(&byterec`5BC_CRC32`5D);
  1147. X    crec.compressed_size =
  1148. X        makelong(&byterec`5BC_COMPRESSED_SIZE`5D);
  1149. X    crec.uncompressed_size =
  1150. X        makelong(&byterec`5BC_UNCOMPRESSED_SIZE`5D);
  1151. X    crec.filename_length =
  1152. X        makeword(&byterec`5BC_FILENAME_LENGTH`5D);
  1153. X    crec.extra_field_length =
  1154. X        makeword(&byterec`5BC_EXTRA_FIELD_LENGTH`5D);
  1155. X    crec.file_comment_length =
  1156. X        makeword(&byterec`5BC_FILE_COMMENT_LENGTH`5D);
  1157. X    crec.disk_number_start =
  1158. X        makeword(&byterec`5BC_DISK_NUMBER_START`5D);
  1159. X    crec.internal_file_attributes =
  1160. X        makeword(&byterec`5BC_INTERNAL_FILE_ATTRIBUTES`5D);
  1161. X    crec.external_file_attributes =
  1162. X        makelong(&byterec`5BC_EXTERNAL_FILE_ATTRIBUTES`5D); /* LONG, not wor
  1163. Vd! */
  1164. X    crec.relative_offset_local_header =
  1165. X        makelong(&byterec`5BC_RELATIVE_OFFSET_LOCAL_HEADER`5D);
  1166. X
  1167. X    return 0;
  1168. X
  1169. X`7D /* end function process_cdir_file_hdr() */
  1170. X
  1171. X
  1172. X
  1173. X
  1174. X/**************************/
  1175. X/*  Function long_info()  */
  1176. X/**************************/
  1177. X
  1178. Xint long_info()   /* return PK-type error code */
  1179. X`7B
  1180. X    int           error, error_in_archive=0;
  1181. X    UWORD         hostver, extver, xattr;
  1182. X    char          workspace`5B12`5D, attribs`5B22`5D;
  1183. X    static char   unkn`5B16`5D;
  1184. X    static char   *os`5BNUM_HOSTS+1`5D = `7B"MS-DOS or OS/2 FAT", "Amiga", "
  1185. VVAX VMS",
  1186. X                      "Unix", "VM/CMS", "Atari ST", "OS/2 HPFS", "Macintosh"
  1187. V,
  1188. X                      "Z-System", "CP/M", "unknown" `7D;
  1189. X    static char   *method`5BNUM_METHODS+1`5D = `7B"none (stored)", "shrunk",
  1190. X                      "reduced (factor 1)", "reduced (factor 2)",
  1191. X                      "reduced (factor 3)", "reduced (factor 4)",
  1192. X                      "imploded", "tokenized", "deflated", unkn`7D;
  1193. X    static char   *dtype`5B4`5D = `7B"normal", "maximum", "fastest", "undefi
  1194. Vned"`7D;
  1195. X
  1196. X
  1197. X/*--------------------------------------------------------------------------
  1198. V-
  1199. X    Print out various interesting things about the compressed file.
  1200. X  --------------------------------------------------------------------------
  1201. V-*/
  1202. X
  1203. X    hostnum = MIN(crec.version_made_by`5B1`5D, NUM_HOSTS);
  1204. X    hostver = crec.version_made_by`5B0`5D;
  1205. X    extnum = MIN(crec.version_needed_to_extract`5B1`5D, NUM_HOSTS);
  1206. X    extver = crec.version_needed_to_extract`5B0`5D;
  1207. X    methnum = MIN(crec.compression_method, NUM_METHODS);
  1208. X    if (methnum == NUM_METHODS)
  1209. X        sprintf(unkn, "unknown (%d)", crec.compression_method);
  1210. X
  1211. X    printf("  %s\n", filename);
  1212. X
  1213. X    printf("\n  host operating system (created on):               %s\n",
  1214. X      os`5Bhostnum`5D);
  1215. X    printf("  version of encoding software:                     %d.%d\n",
  1216. X      hostver/10, hostver%10);
  1217. X    printf("  minimum operating system compatibility required:  %s\n",
  1218. X      os`5Bextnum`5D);
  1219. X    printf("  minimum software version required to extract:     %d.%d\n",
  1220. X      extver/10, extver%10);
  1221. X    printf("  compression method:                               %s\n",
  1222. X      method`5Bmethnum`5D);
  1223. X    if (methnum == IMPLODED) `7B
  1224. X        printf("  size of sliding dictionary (implosion):           %cK\n",
  1225. X          (crec.general_purpose_bit_flag & 2)? '8' : '4');
  1226. X        printf("  number of Shannon-Fano trees (implosion):         %c\n",
  1227. X          (crec.general_purpose_bit_flag & 4)? '3' : '2');
  1228. X    `7D else if (methnum == DEFLATED) `7B
  1229. X        UWORD  dnum=(crec.general_purpose_bit_flag>>1) & 3;
  1230. X        printf("  compression sub-type (deflation):                 %s\n",
  1231. X          dtype`5Bdnum`5D);
  1232. X    `7D
  1233. X    printf("  file security status:                             %sencrypted\
  1234. Vn",
  1235. X      (crec.general_purpose_bit_flag & 1)? "" : "not ");
  1236. X    printf("  extended local header:                            %s\n",
  1237. X      (crec.general_purpose_bit_flag & 8)? "yes" : "no");
  1238. X    /* print upper 3 bits for amusement? */
  1239. X    printf("  file last modified on:                            %s\n",
  1240. X      zipinfo_time(&crec.last_mod_file_date, &crec.last_mod_file_time));
  1241. X    printf("  32-bit CRC value (hex):                           %.8lx\n",
  1242. X      crec.crc32);
  1243. X    printf("  compressed size:                                  %lu bytes\n"
  1244. V,
  1245. X      crec.compressed_size);
  1246. X    printf("  uncompressed size:                                %lu bytes\n"
  1247. V,
  1248. X      crec.uncompressed_size);
  1249. X    printf("  length of filename:                               %u character
  1250. Vs\n",
  1251. X      crec.filename_length);
  1252. X    printf("  length of extra field:                            %u bytes\n",
  1253. X      crec.extra_field_length);
  1254. X    printf("  length of file comment:                           %u character
  1255. Vs\n",
  1256. X      crec.file_comment_length);
  1257. X    printf("  disk number on which file begins:                 disk %u\n",
  1258. X      crec.disk_number_start);
  1259. X    printf("  apparent file type:                               %s\n",
  1260. X      (crec.internal_file_attributes & 1)? "text" : "binary");
  1261. X/*
  1262. X    printf("  external file attributes (hex):                   %.8lx\n",
  1263. X      crec.external_file_attributes);
  1264. X */
  1265. X    xattr = (UWORD) ((crec.external_file_attributes >> 16) & 0xFFFF);
  1266. X    if (hostnum == VMS_) `7B
  1267. X        char   *p=attribs, *q=attribs+1;
  1268. X        int    i, j, k;
  1269. X
  1270. X        for (k = 0;  k < 12;  ++k)
  1271. X            workspace`5Bk`5D = 0;
  1272. X        if (xattr & S_IRUSR)
  1273. X            workspace`5B0`5D = 'R';
  1274. X        if (xattr & S_IWUSR) `7B
  1275. X            workspace`5B1`5D = 'W';
  1276. X            workspace`5B3`5D = 'D';
  1277. X        `7D
  1278. X        if (xattr & S_IXUSR)
  1279. X            workspace`5B2`5D = 'E';
  1280. X        if (xattr & S_IRGRP)
  1281. +-+-+-+-+-+-+-+-  END  OF PART 14 +-+-+-+-+-+-+-+-
  1282.