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