home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!munnari.oz.au!network.ucsd.edu!mvb.saic.com!vmsnet-sources
- From: goathunter@wkuvx1.bitnet
- Newsgroups: vmsnet.sources
- Subject: Zip v1.9 & UnZip v5.0, part 14/22
- Message-ID: <8009680@MVB.SAIC.COM>
- Date: Tue, 01 Sep 1992 22:53:02 GMT
- Organization: Western Kentucky University, Bowling Green, KY
- Lines: 1271
- Approved: Mark.Berryman@Mvb.Saic.Com
-
- Submitted-by: goathunter@wkuvx1.bitnet
- Posting-number: Volume 3, Issue 136
- Archive-name: zip_unzip/part14
-
- -+-+-+-+-+-+-+-+ START OF PART 14 -+-+-+-+-+-+-+-+
- Xfirst hyphen and go from there. It is also consistent with the behavior
- Xof the Unix command \fRnice\fP(1).
- X.PD
- X.SH EXAMPLES
- XTo get a basic, short-format listing of the complete contents of a ZIP`20
- Xarchive `60`60storage.zip,'' with both header and totals lines, use only
- Xthe archive name as an argument to zipinfo:
- X.PP
- X.IP "\t\fIzipinfo\fP storage"
- X.PP
- XTo produce a basic, long-format listing (not verbose), including header and
- Xtotals lines, use \-l:
- X.PP
- X.IP "\t\fIzipinfo\fP \-l storage"
- X.PP
- XTo list the complete contents of the archive without header and totals
- Xlines, either negate the \-h and \-t options or else specify the contents
- Xexplicitly:
- X.PP
- X.IP "\t\fIzipinfo\fP \-\-h\-t storage"
- X.IP "\t\fIzipinfo\fP storage \e*"
- X.PP
- X(where the backslash is required only if the shell would otherwise expand
- Xthe `60*' wildcard, as in Unix when globbing is turned on--double quotes aro
- Vund
- Xthe asterisk would have worked as well). To turn off the totals line by
- Xdefault, use the environment variable (C shell is assumed here):
- X.PP
- X.IP "\tsetenv ZIPINFO \-\-t"
- X.IP "\t\fIzipinfo\fP storage"
- X.PP
- XTo get the full, short-format listing of the first example again, given
- Xthat the environment variable is set as in the previous example, it is
- Xnecessary to specify the \-s option explicitly, since the \-t
- Xoption by itself implies that ONLY the footer line is to be printed:
- X.PP
- X.IP "\tsetenv ZIPINFO \-\-t"
- X.IP "\t\fIzipinfo\fP \-t storage\t`5Bonly totals line`5D"
- X.IP "\t\fIzipinfo\fP \-st storage\t`5Bfull listing`5D"
- X.PP
- XThe \-s option, like \-m and \-l, includes headers and footers by default,
- Xunless otherwise specified. Since the environment variable specified no
- Xfooters and that has a higher precedence than the default behavior of \-s,
- Xan explicit \-t option was necessary to produce the full listing. Nothing`2
- V0
- Xwas indicated about the header, however, so the \-s option was sufficient.
- XNote that both the \-h and \-t options, when used by themselves or with
- Xeach other, override any default listing of member files; only the header
- Xand/or footer are printed. This behavior will be more`20
- Xuseful when \fIZipInfo\fP accepts wildcards for the zipfile name; one
- Xmay then summarize the contents of all zipfiles with a single command.
- X.PP
- XTo list information on a single file within the archive, in medium format,
- Xspecify the filename explicitly:
- X.PP
- X.IP "\t\fIzipinfo\fP \-m storage unshrink.c"
- X.PP
- XThe specification of any member file, as in this example, will override
- Xthe default header and totals lines; only the single line of information
- Xabout the requested file will be printed. This is intuitively what one
- Xwould expect when requesting information about a single file. For multiple
- Xfiles, it is often useful to know the total compressed and uncompressed
- Xsize; in such cases \-t may be specified explicitly:
- X.PP
- X.IP "\t\fIzipinfo\fP \-mt storage ""*.`5Bch`5D Mak\e*"
- X.PP
- XFinally, to get maximal information about the ZIP archive, use the verbose`2
- V0
- Xoption. It is usually wise to pipe the output into a filter such as`20
- X\fRmore\fP(1):
- X.PP
- X.IP "\t\fIzipinfo\fP \-v storage `7C more"
- X.PD
- X.SH TIPS
- XThe author finds it convenient to set up an alias `60`60ii'' for \fIZipInfo\
- VfP
- Xon systems which allow aliases, or else to set up a batch file `60`60ii.bat'
- V'
- Xor to rename the executable to `60`60ii.exe'' on systems such as MS-DOS whic
- Vh
- Xhave no provision for aliases. The `60`60ii'' usage parallels the common
- X`60`60ll'' alias for long listings in Unix, and the similarity between the
- Xoutputs of the two commands was intentional.
- X.PD
- X.SH SEE ALSO
- Xfunzip(1), unzip(1), zip(1), zipcloak(1), zipnote(1), zipsplit(1)
- X.PD
- X.SH AUTHOR
- XGreg Roelofs (also known as Cave Newt). \fIZipInfo\fP is partly based on
- XS. H. Smith's \fRunzip\fP and contains pattern-matching code by J. Kercheval
- V,
- Xbut mostly it was written from scratch. The OS/2 extra-field code is by
- XKai Uwe Rommel.
- $ CALL UNPACK [.UNZIP50]ZIPINFO.1;1 1997710893
- $ create 'f'
- X/*--------------------------------------------------------------------------
- V-
- X
- X zipinfo.c
- X
- X This program reads all sorts of totally nifty information, including the
- X central directory stuff, from a ZIP archive ("zipfile" for short). It
- X started as just a testbed for fooling with zipfiles, but at this point
- X it's actually a moderately useful utility. It also became the basis
- X for the rewrite of unzip (3.16 -> 4.0), using the central directory for
- X processing rather than the individual (local) file headers.
- X
- X For myself, I find it convenient to define an alias "ii" (under Unix and
- X VMS) or to rename the executable to "ii.exe" (OS/2 and DOS). This nicely
- X complements my Unix long-listing "ll" alias (ls -lF), since zipinfo's de-
- X fault action is to produce a Unix-like listing of the archive's contents.
- X "ii zipfile" is easier to type than "zipinfo zipfile"...
- X
- X Another dandy product from your buddies at Newtware!
- X
- X --------------------------------------------------------------------------
- V-
- X
- X To compile (partial instructions; some of this stuff doesn't exist yet):
- X
- X under Unix (cc): make zipinfo
- X
- X under MS-DOS (TurboC): make -fMKZIPINF.DOS (edit appropriately)
- X
- X under MS-DOS (MSC): make MKZIPINF.DOS
- X (or use Makefile if you have MSC 6.0: "nmake zi_dos")
- X
- X under OS/2 (MSC): make MKZIPINF.DOS (edit appropriately)
- X (or use Makefile if you have MSC 6.0: "nmake zi_os2")
- X
- X under Atari OS: beats me...
- X
- X under VMS: @MAKE_ZIPINFO (see also VMSNOTES)
- X ZIPINFO == $DISKNAME:`5BDIRECTORY`5DZIPINFO.EXE
- X
- X under Macintosh OS: who knows?
- X
- X --------------------------------------------------------------------------
- V-
- X
- X Source: unzip50.zip (.tar.Z, etc.) for Unix, VMS, OS/2 and MS-DOS; see
- X `60Where' in source distribution for ftp, uucp and mail-server
- X sites.
- X Author: Greg Roelofs, roelofs@nas.nasa.gov, 23 August 1990
- X Copyright: Portions copyright 1992 Greg Roelofs. Portions adapted from
- X unzip 3.1. SizeOfEAs() by Kai Uwe Rommel.
- X
- X --------------------------------------------------------------------------
- V-*/
- X
- X
- X
- X
- X#ifndef ZIPINFO
- X# define ZIPINFO /* needed for Unix permissions in non-Unix environments
- V */
- X#endif /* !ZIPINFO */
- X#include "unzip.h"
- X
- X#define VERSION "v1.0 of 21 August 92"
- X
- X#define LFLAG 3 /* for short "ls -l" type listing */
- X
- X#define EAID 0x0009 /* OS/2 EA extra field ID */
- Xtypedef struct `7B /* for OS/2 info in OS/2 and non-OS/2 environmen
- Vts */
- X unsigned short nID;
- X unsigned short nSize;
- X ULONG lSize;
- X`7D EAHEADER, *PEAHEADER;
- X
- X
- X
- X
- X/**********************/
- X/* Global Variables */
- X/**********************/
- X
- X#ifdef EBCDIC
- X int aflag=1; /* this is so you can read it on the screen */
- X#else /* (basically, entire program is "unzip -c") */
- X int aflag=0;
- X#endif
- Xint lflag=(-1); /* '-1slmv': listing format */
- Xint hflag=0; /* '-h': header line */
- Xint tflag=0; /* '-t': totals line */
- X
- Xbyte *inbuf, *inptr; /* input buffer (any size is legal) and pointer */
- Xint incnt;
- X
- Xint zipfd; /* zipfile file handle */
- Xchar zipfn`5BFILNAMSIZ`5D;
- X
- Xchar local_hdr_sig`5B5`5D = "\120"; /* remaining signature bytes come lat
- Ver: */
- Xchar central_hdr_sig`5B5`5D = "\120"; /* must initialize at runtime so zip
- Vinfo */
- Xchar end_central_sig`5B5`5D = "\120"; /* executable won't look like a zipf
- Vile */
- Xchar extd_local_sig`5B5`5D = "\120";
- X
- Xcdir_file_hdr crec; /* used in zipinfo.c, misc.c */
- Xlocal_file_hdr lrec;
- Xecdir_rec ecrec;
- Xstruct stat statbuf; /* used by main() */
- X
- Xint process_all_files;
- Xlongint real_ecrec_offset, expect_ecrec_offset;
- Xlongint extra_bytes=0; /* used in zipinfo.c, misc.c */
- Xlongint cur_zipfile_bufstart; /* find_end_central_dir, readbuf */
- X
- Xmin_info info, *pInfo=(&info);
- X
- Xbyte *extra_field = NULL; /* used by VMS, Mac and OS/2 versions */
- Xbyte *outbuf; /* buffer for rle look-back, zipfile comment
- V */
- Xbyte *outout; /* scratch pad for ASCII-native trans */
- X
- Xchar filename`5BFILNAMSIZ`5D;
- Xchar sig`5B5`5D;
- Xchar *fnames`5B2`5D = `7B"*", NULL`7D; /* default filenames vector */
- Xchar **fnv = fnames;
- X
- Xstatic byte *hold;
- Xstatic longint ziplen;
- Xstatic UWORD hostnum;
- Xstatic UWORD methnum;
- Xstatic UWORD extnum;
- X
- Xchar *EndSigMsg = "\nwarning:\
- X didn't find end-of-central-dir signature at end of central dir.\n";
- Xchar *CentSigMsg =
- X "error: expected central file header signature not found (file #%u).\n";
- Xchar *SeekMsg =
- X "error: attempt to seek before beginning of zipfile\n%s";
- X
- X#ifdef VMS
- Xchar *ReportMsg = "\
- X (please check that you have transferred or created the zipfile in the\n\
- X appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\
- Vn";
- X#else /* !VMS */
- Xchar *ReportMsg = "\
- X (please check that you have transferred or created the zipfile in the\n\
- X appropriate BINARY mode and that you have compiled unzip properly)\n";
- X#endif /* ?VMS */
- X
- X
- X
- X
- X
- X
- X/******************/
- X/* Main program */
- X/******************/
- X
- Xmain(argc, argv)
- X int argc;
- X char *argv`5B`5D;
- X`7B
- X char *s;
- X int c, error=FALSE, negative=0;
- X int hflag_slmv=TRUE, hflag_1=FALSE; /* diff options => diff defaults
- V */
- X int tflag_slm=TRUE, tflag_1v=FALSE;
- X int explicit_h=FALSE, explicit_t=FALSE;
- X
- X
- X
- X/*--------------------------------------------------------------------------
- V-
- X Everybody is now "NOTINT16," but this is a nice little piece of code, so
- X just comment it out for future reference. :-)
- X --------------------------------------------------------------------------
- V-*/
- X
- X#if 0
- X# ifndef KNOW_IT_WORKS /* define this to save space, if things already work
- V */
- X# ifndef DOS_OS2 /* already works (no RISCy OS/2's yet...) */
- X# ifndef NOTINT16 /* whole point is to see if this NEEDS defining */
- X `7B
- X int error=0;
- X long testsig;
- X static char *mach_type`5B3`5D = `7B"big-endian", "structure-padding"
- V,
- X "big-endian and structure-padding"`7D;
- X
- X strcpy((char *)&testsig,"012");
- X if (testsig != 0x00323130)
- X error = 1;
- X if (sizeof(cdir_file_hdr) != CREC_SIZE)
- X error += 2;
- X if (error--)
- X fprintf(stderr, "It appears that your machine is %s. If errors\
- Vn\
- Xoccur, please try recompiling with \"NOTINT16\" defined (read the\n\
- XMakefile, or try \"make zipinfo\").\n\n", mach_type`5Berror`5D);
- X `7D
- X# endif /* !NOTINT16 */
- X# endif /* !DOS_OS2 */
- X# endif /* !KNOW_IT_WORKS */
- X#endif /* 0 */
- X
- X/*--------------------------------------------------------------------------
- V-
- X Put environment-variable options into the queue, then rip through any
- X command-line options lurking about...
- X --------------------------------------------------------------------------
- V-*/
- X
- X envargs(&argc, &argv, ENV_ZIPINFO);
- X
- X while (--argc > 0 && (*++argv)`5B0`5D == '-') `7B
- X s = argv`5B0`5D + 1;
- X while ((c = *s++) != 0) `7B /* "!= 0": prevent Turbo C warning *
- V/
- X switch (c) `7B
- X case '-':
- X ++negative;
- X break;
- X case '1': /* shortest listing: just filenames */
- X if (negative)
- X lflag = -2, negative = 0;
- X else
- X lflag = 1;
- X break;
- X case 'h': /* header line */
- X if (negative)
- X hflag_1 = hflag_slmv = FALSE, negative = 0;
- X else `7B
- X hflag_1 = hflag_slmv = explicit_h = TRUE;
- X if (lflag == -1)
- X lflag = 0;
- X `7D
- X break;
- X case 'l': /* longer form of "ls -l" type listing */
- X if (negative)
- X lflag = -2, negative = 0;
- X else
- X lflag = 5;
- X break;
- X case 'm': /* medium form of "ls -l" type listing */
- X if (negative)
- X lflag = -2, negative = 0;
- X else
- X lflag = 4;
- X break;
- X case 's': /* default: shorter "ls -l" type listing */
- X if (negative)
- X lflag = -2, negative = 0;
- X else
- X lflag = 3;
- X break;
- X case 't': /* totals line */
- X if (negative)
- X tflag_1v = tflag_slm = FALSE, negative = 0;
- X else `7B
- X tflag_1v = tflag_slm = explicit_t = TRUE;
- X if (lflag == -1)
- X lflag = 0;
- X `7D
- X break;
- X case 'v': /* turbo-verbose listing */
- X if (negative)
- X lflag = -2, negative = 0;
- X else
- X lflag = 10;
- X break;
- X default:
- X error = TRUE;
- X break;
- X `7D
- X `7D
- X `7D
- X if ((argc-- == 0) `7C`7C error)
- X RETURN(usage(error));
- X
- X if (argc != 0)
- X process_all_files = FALSE;
- X else
- X process_all_files = TRUE; /* for speed */
- X
- X /* if no listing options given (or all negated), or if only -h/-t given
- X * with individual files specified, use default listing format */
- X if ((lflag < 0) `7C`7C (!process_all_files && (lflag == 0)))
- X lflag = LFLAG;
- X
- X /* set header and totals flags to default or specified values */
- X switch (lflag) `7B
- X case 0: /* 0: can only occur if either -t or -h explicitly given;
- V */
- X case 1: /* therefore set both flags equal to normally false value
- V */
- X hflag = hflag_1;
- X tflag = tflag_1v;
- X break;
- X case 3:
- X case 4:
- X case 5:
- X hflag = (!process_all_files && !explicit_h)? FALSE : hflag_slmv;
- X tflag = (!process_all_files && !explicit_t)? FALSE : tflag_slm;
- X break;
- X case 10:
- X hflag = hflag_slmv;
- X tflag = tflag_1v;
- X break;
- X `7D
- X
- X/*--------------------------------------------------------------------------
- V-
- X Now get the zipfile name from the command line and see if it exists as a
- X regular (non-directory) file. If not, append the ".zip" suffix. We don
- V't
- X immediately check to see if this results in a good name, but we will do
- V so
- X later. In the meantime, see if there are any member filespecs on the co
- Vm-
- X mand line, and if so, set the filename pointer to point at them.
- X --------------------------------------------------------------------------
- V-*/
- X
- X strcpy(zipfn, *argv++);
- X if (stat(zipfn, &statbuf) `7C`7C (statbuf.st_mode & S_IFMT) == S_IFDIR)
- X strcat(zipfn, ZSUFX);
- X#if defined(UNIX) && !defined(VMS) /* Unix executables have no extension--
- V */
- X else if (statbuf.st_mode & S_IXUSR) /* might find zip, not zip.zip; etc
- V */
- X fprintf(stderr, "\nnote: file `5B %s `5D may be an executable\n\n",
- V zipfn);
- X#endif /* UNIX && !VMS */
- X
- X if (stat(zipfn, &statbuf)) `7B /* try again */
- X fprintf(stderr, "error: can't find zipfile `5B %s `5D\n", zipfn);
- X RETURN(9); /* 9: file not found */
- X `7D else
- X ziplen = statbuf.st_size;
- X
- X if (!process_all_files)
- X fnv = argv;
- X
- X/*--------------------------------------------------------------------------
- V-
- X Okey dokey, we have everything we need to get started. Let's roll.
- X --------------------------------------------------------------------------
- V-*/
- X
- X inbuf = (byte *) (malloc(INBUFSIZ + 4)); /* 4 extra for hold`5B`5D (b
- Velow) */
- X outbuf = (byte *) (malloc(OUTBUFSIZ + 1)); /* 1 extra for string termin
- V. */
- X if (aflag) /* if need an ascebc scratch, */
- X outout = (byte *) (malloc(OUTBUFSIZ));
- X else /* allocate it... */
- X outout = outbuf; /* else just point to outbuf */
- X
- X if ((inbuf == NULL) `7C`7C (outbuf == NULL) `7C`7C (outout == NULL)) `7B
- X fprintf(stderr, "error: can't allocate zipinfo buffers\n");
- X RETURN(4); /* 4-8: insufficient memory */
- X `7D
- X hold = &inbuf`5BINBUFSIZ`5D; /* to check for boundary-spanning signat
- Vures */
- X
- X RETURN(process_zipfile()); /* keep passing errors back... */
- X
- X`7D /* end main() */
- X
- X
- X
- X
- X
- X/**********************/
- X/* Function usage() */
- X/**********************/
- X
- Xint usage(error)
- X int error;
- X`7B
- X FILE *usagefp;
- X
- X
- X/*--------------------------------------------------------------------------
- V-
- X If user requested usage, send it to stdout; else send to stderr.
- X --------------------------------------------------------------------------
- V-*/
- X
- X if (error)
- X usagefp = (FILE *) stderr;
- X else
- X usagefp = (FILE *) stdout;
- X
- X fprintf(usagefp, "\
- X ZipInfo: Zipfile Information Utility %s\n\
- X (brought to you by Newtware, Inc., and the fine folks at Info-ZIP)\n\n\
- X Usage: zipinfo `5B-1smlvht`5D file`5B.zip`5D `5Bfilespec...`5D\n", VERSI
- VON);
- X fprintf(usagefp, "\
- X -1 list filenames only, one per line (useful for pipes)\n\
- X -s list zipfile info in short Unix \"ls -l\" format: default\n\
- X -m list zipfile info in medium Unix \"ls -l\" format\n\
- X -l list zipfile info in long Unix \"ls -l\" format\n\
- X -v list zipfile information in verbose, multi-page format\n\
- X -h list header line\n\
- X -t list totals for files listed or for all files\n");
- X/*
- X -p disable automatic \"more\" function (for pipes) `5Bnot implemented`
- V5D\n");
- X */
- X
- X#ifdef VMS
- X fprintf(usagefp, "\nRemember that non-lowercase filespecs must be quoted
- V\
- X in VMS (e.g., \"Makefile\").\n");
- X#endif
- X
- X if (error)
- X return 10; /* 10: bad or illegal parameters specified */
- X else
- X return 0; /* just wanted usage screen: no error */
- X
- X`7D /* end function usage() */
- X
- X
- X
- X
- X
- X/********************************/
- X/* Function process_zipfile() */
- X/********************************/
- X
- Xint process_zipfile() /* return PK-type error code */
- X`7B
- X int error=0, error_in_archive;
- X
- X
- X/*--------------------------------------------------------------------------
- V-
- X Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
- X lation, which would corrupt the bitstreams.
- X --------------------------------------------------------------------------
- V-*/
- X
- X#ifdef VMS
- X if (check_format()) /* check for variable-length format */
- X return 2; /* 2: error in zipfile */
- X#endif /* VMS */
- X
- X if (open_input_file()) /* this should never happen, given the */
- X return 9; /* stat() test in main(), but... */
- X
- X/*--------------------------------------------------------------------------
- V-
- X Reconstruct the various PK signature strings, and find and process the
- X end-of-central-directory header.
- X --------------------------------------------------------------------------
- V-*/
- X
- X strcat(local_hdr_sig, LOCAL_HDR_SIG);
- X strcat(central_hdr_sig, CENTRAL_HDR_SIG);
- X strcat(end_central_sig, END_CENTRAL_SIG);
- X strcat(extd_local_sig, EXTD_LOCAL_SIG);
- X
- X if (find_end_central_dir()) `7B /* not found; nothing to do */
- X close(zipfd);
- X return 2; /* 2: error in zipfile */
- X `7D
- X
- X real_ecrec_offset = cur_zipfile_bufstart + (inptr-inbuf);
- X#ifdef TEST
- X printf("\n found end-of-central-dir signature at offset %ld (%.8lXh)\n"
- V,
- X real_ecrec_offset, real_ecrec_offset);
- X printf(" from beginning of file; offset %d (%.4Xh) within block\n",
- X inptr-inbuf, inptr-inbuf);
- X#endif
- X
- X /* sets expect_ecrec_offset: */
- X if ((error_in_archive = process_end_central_dir()) > 1) `7B
- X close(zipfd);
- X return error_in_archive;
- X `7D
- X
- X/*--------------------------------------------------------------------------
- V-
- X Test the end-of-central-directory info for incompatibilities (multi-disk
- X archives) or inconsistencies (missing or extra bytes in zipfile).
- X --------------------------------------------------------------------------
- V-*/
- X
- X if (ecrec.number_this_disk != ecrec.num_disk_with_start_central_dir) `7B
- X fprintf(stderr, "\n\
- X Zipfile is part of a multi-disk archive, and this is not the disk on\
- X which the central zipfile directory begins.\n");
- X error_in_archive = 11; /* 11: no files found */
- X `7D else `7B
- X if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) `7B
- X fprintf(stderr, "\nerror: missing %ld bytes in zipfile (\
- Xattempting to process anyway)\n\n", -extra_bytes);
- X error_in_archive = 2; /* 2: (weak) error in zipfile */
- X `7D else if (extra_bytes > 0) `7B
- X if ((ecrec.offset_start_central_directory == 0) &&
- X (ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */
- X `7B
- X fprintf(stderr, "\nerror: NULL central directory offset (\
- Xattempting to process anyway)\n\n");
- X error_in_archive = 2; /* 2: (weak) error in zipfile */
- X `7D else `7B
- X fprintf(stderr, "\nwarning: extra %ld bytes at beginning or
- V\
- X within zipfile\n (attempting to process anyway)\n\n", extra_bytes)
- V;
- X error_in_archive = 1; /* 1: warning error */
- X `7D
- X `7D
- X
- X /*----------------------------------------------------------------------
- V-
- X Check for empty zipfile and exit now if so.
- X ----------------------------------------------------------------------
- V-*/
- X
- X if (expect_ecrec_offset == 0L && ecrec.size_central_directory == 0
- V) `7B
- X printf("%sEmpty zipfile.\n", lflag>9 ? "\n " : "");
- X close(zipfd);
- X return (error_in_archive > 1)? error_in_archive : 1;
- X `7D
- X
- X /*----------------------------------------------------------------------
- V-
- X Compensate for missing or extra bytes, and seek to where the start
- X of central directory should be. If header not found, uncompensate
- X and try again (necessary for at least some Atari archives created
- X with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT).
- X ----------------------------------------------------------------------
- V-*/
- X
- X LSEEK( ecrec.offset_start_central_directory )
- X if ((readbuf(sig, 4) <= 0) `7C`7C strncmp(sig, central_hdr_sig, 4))
- V `7B
- X longint tmp = extra_bytes;
- X
- X extra_bytes = 0;
- X LSEEK( ecrec.offset_start_central_directory )
- X if ((readbuf(sig, 4) <= 0) `7C`7C strncmp(sig, central_hdr_sig,
- V 4)) `7B
- X fprintf(stderr,
- X "error: start of central directory not found; zipfile corrupt.\
- Vn");
- X fprintf(stderr, ReportMsg);
- X close(zipfd);
- X return 3; /* 3: severe error in zipfile */
- X `7D
- X fprintf(stderr, "error: reported length of central directory is
- V \
- X%d bytes too\n long (Atari STZIP zipfile? J.H. Holm ZIPSPLIT zipfile
- V?)\
- X.\n Compensating...\n\n", -tmp);
- X error_in_archive = 2; /* 2: (weak) error in zipfile */
- X `7D
- X
- X /*----------------------------------------------------------------------
- V-
- X Seek to the start of the central directory one last time, since we
- X have just read the first entry's signature bytes; then do the centra
- Vl
- X directory and close the zipfile.
- X ----------------------------------------------------------------------
- V-*/
- X
- X LSEEK( ecrec.offset_start_central_directory )
- X if ((error = process_central_dir()) > error_in_archive)
- X error_in_archive = error; /* don't overwrite stronger error *
- V/
- X if (lflag > 9)
- X printf("\n");
- X `7D
- X
- X close(zipfd);
- X return error_in_archive;
- X
- X`7D /* end function process_zipfile() */
- X
- X
- X
- X
- X
- X/*************************************/
- X/* Function find_end_central_dir() */
- X/*************************************/
- X
- Xint find_end_central_dir() /* return 0 if found, 1 otherwise */
- X`7B
- X int i, numblks;
- X longint tail_len;
- X
- X
- X
- X/*--------------------------------------------------------------------------
- V-
- X Treat case of short zipfile separately.
- X --------------------------------------------------------------------------
- V-*/
- X
- X if (ziplen <= INBUFSIZ) `7B
- X lseek(zipfd, 0L, SEEK_SET);
- X if ((incnt = read(zipfd,inbuf,(unsigned int)ziplen)) == (int)ziplen)
- X /* 'P' must be at least 22 bytes from end of zipfile */
- X for (inptr = inbuf+(int)ziplen-22; inptr >= inbuf; --inptr)
- X if ((ascii_to_native(*inptr) == 'P') &&
- X !strncmp((char *)inptr, end_central_sig, 4)) `7B
- X incnt -= inptr - inbuf;
- X return 0; /* found it! */
- X `7D /* ...otherwise fall through & fail */
- X
- X/*--------------------------------------------------------------------------
- V-
- X Zipfile is longer than INBUFSIZ: may need to loop. Start with short
- X block at end of zipfile (if not TOO short).
- X --------------------------------------------------------------------------
- V-*/
- X
- X `7D else `7B
- X if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) `7B
- X cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
- X if ((incnt = read(zipfd,inbuf,(unsigned int)tail_len)) !=
- X (int)tail_len)
- X goto fail; /* shut up; it's expedient. */
- X
- X /* 'P' must be at least 22 bytes from end of zipfile */
- X for (inptr = inbuf+(int)tail_len-22; inptr >= inbuf; --inptr)
- X if ((ascii_to_native(*inptr) == 'P') &&
- X !strncmp((char *)inptr, end_central_sig, 4)) `7B
- X incnt -= inptr - inbuf;
- X return 0; /* found it */
- X `7D /* ...otherwise search next block */
- X /* sig may span block boundary: */
- X strncpy((char *)hold, (char *)inbuf, 3);
- X `7D else
- X cur_zipfile_bufstart = ziplen - tail_len;
- X
- X /*
- X * Loop through blocks of zipfile data, starting at the end and goin
- Vg
- X * toward the beginning. Need only check last 65557 bytes of zipfil
- Ve:
- X * comment may be up to 65535 bytes long, end-of-central-directory r
- Vec-
- X * ord is 18 bytes (shouldn't hardcode this number, but what the hel
- Vl:
- X * already did so above (22=18+4)), and sig itself is 4 bytes.
- X *`20
- X * zipinfo: check the whole file, just in case some transfer protoc
- Vol
- X * has appended a whole bunch of garbage at the end of the archive.
- X *
- X * =todo= ==done== ==rounding== =blksiz=
- V */
- X numblks = (int) ((ziplen - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
- X
- X for (i = 1; i <= numblks; ++i) `7B
- X cur_zipfile_bufstart -= INBUFSIZ;
- X lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
- X if ((incnt = read(zipfd,inbuf,INBUFSIZ)) != INBUFSIZ)
- X break; /* fall through and fail */
- X
- X for (inptr = inbuf+INBUFSIZ-1; inptr >= inbuf; --inptr)
- X if ((ascii_to_native(*inptr) == 'P') &&
- X !strncmp((char *)inptr, end_central_sig, 4)) `7B
- X incnt -= inptr - inbuf;
- X return 0; /* found it */
- X `7D
- X /* sig may span block boundary: */
- X strncpy((char *)hold, (char *)inbuf, 3);
- X `7D
- X
- X `7D /* end if (ziplen > INBUFSIZ) */
- X
- X/*--------------------------------------------------------------------------
- V-
- X Searched through whole region where signature should be without finding
- X it. Print informational message and die a horrible death.
- X --------------------------------------------------------------------------
- V-*/
- X
- Xfail:
- X
- X fprintf(stderr, "\n\
- X %s:\n\n\
- X End-of-central-directory signature not found. Either this file is not\
- Vn\
- X a zipfile, or it constitutes one disk of a multi-part archive. In the\
- Vn\
- X latter case the central directory and zipfile comment will be found on\
- Vn\
- X the last disk(s) of this archive.\n", zipfn);
- X return 1; /* failed */
- X
- X`7D /* end function find_end_central_dir() */
- X
- X
- X
- X
- X
- X/****************************************/
- X/* Function process_end_central_dir() */
- X/****************************************/
- X
- Xint process_end_central_dir() /* return PK-type error code */
- X`7B
- X ec_byte_rec byterec;
- X int error=0;
- X
- X
- X/*--------------------------------------------------------------------------
- X Read the end-of-central-directory record and do any necessary machine-
- X type conversions (byte ordering, structure padding compensation) by
- X copying character array to struct.
- X --------------------------------------------------------------------------
- V-*/
- X
- X if (readbuf((char *)byterec, ECREC_SIZE+4) <= 0)
- X return 51;
- X
- X ecrec.number_this_disk =
- X makeword(&byterec`5BNUMBER_THIS_DISK`5D);
- X ecrec.num_disk_with_start_central_dir =
- X makeword(&byterec`5BNUM_DISK_WITH_START_CENTRAL_DIR`5D);
- X ecrec.num_entries_centrl_dir_ths_disk =
- X makeword(&byterec`5BNUM_ENTRIES_CENTRL_DIR_THS_DISK`5D);
- X ecrec.total_entries_central_dir =
- X makeword(&byterec`5BTOTAL_ENTRIES_CENTRAL_DIR`5D);
- X ecrec.size_central_directory =
- X makelong(&byterec`5BSIZE_CENTRAL_DIRECTORY`5D);
- X ecrec.offset_start_central_directory =
- X makelong(&byterec`5BOFFSET_START_CENTRAL_DIRECTORY`5D);
- X ecrec.zipfile_comment_length =
- X makeword(&byterec`5BZIPFILE_COMMENT_LENGTH`5D);
- X
- X expect_ecrec_offset = ecrec.offset_start_central_directory +
- X ecrec.size_central_directory;
- X
- X/*--------------------------------------------------------------------------
- V-
- X Print out various interesting things about the zipfile.
- X --------------------------------------------------------------------------
- V-*/
- X
- X /* header fits on one line, for anything up to 10GB and 10000 files: */
- X if (hflag)
- X printf((strlen(zipfn)<39)? "Archive: %s %ld bytes %d file%s\n"
- X : "Archive: %s %ld %d\n", zipfn, ziplen,
- X ecrec.total_entries_central_dir,
- X (ecrec.total_entries_central_dir==1)? "":"s");
- X
- X /* verbose format */
- X if (lflag > 9) `7B
- X printf("\nEnd-of-central-directory record:\n");
- X printf("-------------------------------\n\n");
- X
- X printf("\
- X Actual offset of end-of-central-dir record: %9ld (%.8lXh)\n\
- X Expected offset of end-of-central-dir record: %9ld (%.8lXh)\n\
- X (based on the length of the central directory and its expected offset)\n\n
- V",
- X expect_ecrec_offset, expect_ecrec_offset,
- X real_ecrec_offset, real_ecrec_offset);
- X
- X if (ecrec.number_this_disk == 0) `7B
- X printf("\
- X This zipfile constitutes the sole disk of a single-part archive; its\n\
- X central directory contains %u %s. The central directory is %lu\n\
- X (%.8lXh) bytes long, and its (expected) offset in bytes from the\n\
- X beginning of the zipfile is %lu (%.8lXh).\n\n",
- X ecrec.total_entries_central_dir,
- X (ecrec.total_entries_central_dir == 1)? "entry" : "entries",
- X ecrec.size_central_directory, ecrec.size_central_directory,
- X ecrec.offset_start_central_directory,
- X ecrec.offset_start_central_directory);
- X `7D else `7B
- X printf("\
- X This zipfile constitutes disk %u of a multi-part archive. The central\n\
- X directory starts on disk %u; %u of its entries %s contained within\n\
- X this zipfile, out of a total of %u %s. The entire central\n\
- X directory is %lu (%.8lXh) bytes long, and its offset in bytes from\n\
- X the beginning of the zipfile in which it begins is %lu (%.8lXh).\n\n",
- X ecrec.number_this_disk,
- X ecrec.num_disk_with_start_central_dir,
- X ecrec.num_entries_centrl_dir_ths_disk,
- X (ecrec.num_entries_centrl_dir_ths_disk == 1)? "is" : "are",
- X ecrec.total_entries_central_dir,
- X (ecrec.total_entries_central_dir == 1) ? "entry" : "entries",
- X ecrec.size_central_directory, ecrec.size_central_directory,
- X ecrec.offset_start_central_directory,
- X ecrec.offset_start_central_directory);
- X `7D
- X
- X /*----------------------------------------------------------------------
- V-
- X Get the zipfile comment, if any, and print it out. (Comment may be
- X up to 64KB long. May the fleas of a thousand camels infest the arm-
- X pits of anyone who actually takes advantage of this fact.)
- X ----------------------------------------------------------------------
- V-*/
- X
- X if (!ecrec.zipfile_comment_length)
- X printf(" There is no zipfile comment.\n");
- X else `7B
- X printf(" The zipfile comment is %u bytes long and contains the
- V following text:\n\n",
- X ecrec.zipfile_comment_length );
- X printf("======================== zipfile comment begins ========
- V==================\n");
- X if (do_string(ecrec.zipfile_comment_length, DISPLAY))
- X error = 1; /* 1: warning error */
- X printf("\n========================= zipfile comment ends =======
- V====================\n");
- X if (error)
- X printf("\n The zipfile comment is truncated.\n");
- X `7D /* endif (comment exists) */
- X
- X `7D /* endif (verbose) */
- X
- X return error;
- X
- X`7D /* end function process_end_central_dir() */
- X
- X
- X
- X
- X
- X/************************************/
- X/* Function process_central_dir() */
- X/************************************/
- X
- Xint process_central_dir() /* return PK-type error code */
- X`7B
- X char **fnamev;
- X int do_this_file=FALSE, none_found=TRUE, error, error_in_archive=0;
- X UWORD j, members=0;
- X ULONG c=0L, uc=0L;
- X
- X
- X/*--------------------------------------------------------------------------
- V-
- X Set file pointer to start of central directory, then loop through cen-
- X tral directory entries. Check that directory-entry signature bytes are
- X actually there (just a precaution), then process the entry. We know
- X the entire central directory is on this disk: we wouldn't have any of
- X this information unless the end-of-central-directory record was on this
- X disk, and we wouldn't have gotten to this routine unless this is also
- X the disk on which the central directory starts. In practice, this had
- X better be the *only* disk in the archive, but maybe someday we'll add
- X multi-disk support.
- X --------------------------------------------------------------------------
- V-*/
- X
- X pInfo->lcflag = 0; /* match(), do_string(): never TRUE in zipinfo */
- X
- X for (j = 0; j < ecrec.total_entries_central_dir; ++j) `7B
- X if (readbuf(sig, 4) <= 0)
- X return 51; /* 51: unexpected EOF */
- X if (strncmp(sig, central_hdr_sig, 4)) `7B /* just to make sure */
- X fprintf(stderr, CentSigMsg, j); /* sig not found */
- X return 3; /* 3: error in zipfile */
- X `7D
- X if ((error = process_cdir_file_hdr()) != 0)
- X return error; /* only 51 (EOF) defined */
- X if ((error = do_string(crec.filename_length, FILENAME)) != 0) `7B
- X error_in_archive = error; /* might be warning */
- X if (error > 1) /* fatal */
- X return error;
- X `7D
- X
- X if (!process_all_files) `7B /* check if specified on command line
- V */
- X do_this_file = FALSE;
- X fnamev = fnv; /* don't destroy permanent filename ptr */
- X for (--fnamev; *++fnamev; )
- X if (match(filename, *fnamev)) `7B
- X do_this_file = TRUE;
- X none_found = FALSE;
- X break; /* found match, so stop looping */
- X `7D
- X `7D
- X
- X /*----------------------------------------------------------------------
- V-
- X If current file was specified on command line, or if no names were
- X specified, do the listing for this file. Otherwise, get rid of the
- X file comment and go back for the next file.
- X ----------------------------------------------------------------------
- V-*/
- X
- X if (process_all_files `7C`7C do_this_file) `7B
- X switch (lflag) `7B
- X case 1:
- X printf("%s\n", filename);
- X SKIP_(crec.extra_field_length)
- X SKIP_(crec.file_comment_length)
- X break;
- X
- X case 3:
- X case 4:
- X case 5:
- X if ((error = short_info()) != 0) `7B
- X error_in_archive = error; /* might be warning */
- X if (error > 1) /* fatal */
- X return error;
- X `7D
- X break;
- X
- X case 10:
- X#ifdef VMS /* GRR: FIX THIS (no pipes: add cbreak-style "more" function)
- V */
- X printf("\nCentral directory entry #%d:\n", j);
- X#else /* !VMS */
- X /* formfeed/CR for piping to "more": */
- X printf("%s\nCentral directory entry #%d:\n", "\014", j);
- X#endif /* ?VMS */
- X printf("---------------------------\n\n");
- X
- X if ((error = long_info()) != 0) `7B
- X error_in_archive = error; /* might be warning */
- X if (error > 1) /* fatal */
- X return error;
- X `7D
- X break;
- X
- X default:
- X SKIP_(crec.extra_field_length)
- X SKIP_(crec.file_comment_length)
- X break;
- X
- X `7D /* end switch (lflag) */
- X
- X uc += crec.uncompressed_size;
- X c += crec.compressed_size;
- X if (crec.general_purpose_bit_flag & 1)
- X c -= 12; /* if encrypted, don't count encryption header *
- V/
- X ++members;
- X
- X `7D else `7B /* not listing */
- X SKIP_(crec.extra_field_length)
- X SKIP_(crec.file_comment_length)
- X
- X `7D /* end if (list member?) */
- X
- X `7D /* end for-loop (j: member files) */
- X
- X/*--------------------------------------------------------------------------
- V-
- X Double check that we're back at the end-of-central-directory record.
- X --------------------------------------------------------------------------
- V-*/
- X
- X readbuf(sig, 4);
- X if (strncmp(sig, end_central_sig, 4)) `7B /* just to make sure again
- V */
- X fprintf(stderr, EndSigMsg); /* didn't find end-of-central-dir sig *
- V/
- X error_in_archive = 1; /* 1: warning error */
- X `7D
- X
- X/*--------------------------------------------------------------------------
- V-
- X Check that we actually found requested files; if so, print totals.
- X --------------------------------------------------------------------------
- V-*/
- X
- X if (none_found && !process_all_files) `7B
- X fnamev = fnv; /* don't destroy permanent filename ptr */
- X for (--fnamev; *++fnamev; )
- X printf("zipinfo: %s not found in %s\n", *fnamev, zipfn);
- X `7D else if (tflag)
- X printf(
- X "%d file%s, %lu bytes uncompressed, %lu bytes compressed: %d%%\n"
- V,
- X members, (members==1)? "":"s", uc, c, (uc==0)? 0 : ((uc>2000000L)?
- X ((int)((uc-c)/(uc/1000L))+5)/10 : ((int)((1000L*(uc-c))/uc)+5)/10)
- V );
- X
- X return error_in_archive;
- X
- X`7D /* end function process_central_dir() */
- X
- X
- X
- X
- X
- X/**************************************/
- X/* Function process_cdir_file_hdr() */
- X/**************************************/
- X
- Xint process_cdir_file_hdr() /* return PK-type error code */
- X`7B
- X cdir_byte_hdr byterec;
- X
- X
- X/*--------------------------------------------------------------------------
- V-
- X Read the next central directory entry and do any necessary machine-type
- X conversions (byte ordering, structure padding compensation--do so by
- X copying the data from the array into which it was read (byterec) to the
- X usable struct (crec)).
- X --------------------------------------------------------------------------
- V-*/
- X
- X if (readbuf((char *) byterec, CREC_SIZE) <= 0)
- X return 51; /* 51: unexpected EOF */
- X
- X crec.version_made_by`5B0`5D = byterec`5BC_VERSION_MADE_BY_0`5D;
- X crec.version_made_by`5B1`5D = byterec`5BC_VERSION_MADE_BY_1`5D;
- X crec.version_needed_to_extract`5B0`5D = byterec`5BC_VERSION_NEEDED_TO_EX
- VTRACT_0`5D;
- X crec.version_needed_to_extract`5B1`5D = byterec`5BC_VERSION_NEEDED_TO_EX
- VTRACT_1`5D;
- X
- X crec.general_purpose_bit_flag =
- X makeword(&byterec`5BC_GENERAL_PURPOSE_BIT_FLAG`5D);
- X crec.compression_method =
- X makeword(&byterec`5BC_COMPRESSION_METHOD`5D);
- X crec.last_mod_file_time =
- X makeword(&byterec`5BC_LAST_MOD_FILE_TIME`5D);
- X crec.last_mod_file_date =
- X makeword(&byterec`5BC_LAST_MOD_FILE_DATE`5D);
- X crec.crc32 =
- X makelong(&byterec`5BC_CRC32`5D);
- X crec.compressed_size =
- X makelong(&byterec`5BC_COMPRESSED_SIZE`5D);
- X crec.uncompressed_size =
- X makelong(&byterec`5BC_UNCOMPRESSED_SIZE`5D);
- X crec.filename_length =
- X makeword(&byterec`5BC_FILENAME_LENGTH`5D);
- X crec.extra_field_length =
- X makeword(&byterec`5BC_EXTRA_FIELD_LENGTH`5D);
- X crec.file_comment_length =
- X makeword(&byterec`5BC_FILE_COMMENT_LENGTH`5D);
- X crec.disk_number_start =
- X makeword(&byterec`5BC_DISK_NUMBER_START`5D);
- X crec.internal_file_attributes =
- X makeword(&byterec`5BC_INTERNAL_FILE_ATTRIBUTES`5D);
- X crec.external_file_attributes =
- X makelong(&byterec`5BC_EXTERNAL_FILE_ATTRIBUTES`5D); /* LONG, not wor
- Vd! */
- X crec.relative_offset_local_header =
- X makelong(&byterec`5BC_RELATIVE_OFFSET_LOCAL_HEADER`5D);
- X
- X return 0;
- X
- X`7D /* end function process_cdir_file_hdr() */
- X
- X
- X
- X
- X/**************************/
- X/* Function long_info() */
- X/**************************/
- X
- Xint long_info() /* return PK-type error code */
- X`7B
- X int error, error_in_archive=0;
- X UWORD hostver, extver, xattr;
- X char workspace`5B12`5D, attribs`5B22`5D;
- X static char unkn`5B16`5D;
- X static char *os`5BNUM_HOSTS+1`5D = `7B"MS-DOS or OS/2 FAT", "Amiga", "
- VVAX VMS",
- X "Unix", "VM/CMS", "Atari ST", "OS/2 HPFS", "Macintosh"
- V,
- X "Z-System", "CP/M", "unknown" `7D;
- X static char *method`5BNUM_METHODS+1`5D = `7B"none (stored)", "shrunk",
- X "reduced (factor 1)", "reduced (factor 2)",
- X "reduced (factor 3)", "reduced (factor 4)",
- X "imploded", "tokenized", "deflated", unkn`7D;
- X static char *dtype`5B4`5D = `7B"normal", "maximum", "fastest", "undefi
- Vned"`7D;
- X
- X
- X/*--------------------------------------------------------------------------
- V-
- X Print out various interesting things about the compressed file.
- X --------------------------------------------------------------------------
- V-*/
- X
- X hostnum = MIN(crec.version_made_by`5B1`5D, NUM_HOSTS);
- X hostver = crec.version_made_by`5B0`5D;
- X extnum = MIN(crec.version_needed_to_extract`5B1`5D, NUM_HOSTS);
- X extver = crec.version_needed_to_extract`5B0`5D;
- X methnum = MIN(crec.compression_method, NUM_METHODS);
- X if (methnum == NUM_METHODS)
- X sprintf(unkn, "unknown (%d)", crec.compression_method);
- X
- X printf(" %s\n", filename);
- X
- X printf("\n host operating system (created on): %s\n",
- X os`5Bhostnum`5D);
- X printf(" version of encoding software: %d.%d\n",
- X hostver/10, hostver%10);
- X printf(" minimum operating system compatibility required: %s\n",
- X os`5Bextnum`5D);
- X printf(" minimum software version required to extract: %d.%d\n",
- X extver/10, extver%10);
- X printf(" compression method: %s\n",
- X method`5Bmethnum`5D);
- X if (methnum == IMPLODED) `7B
- X printf(" size of sliding dictionary (implosion): %cK\n",
- X (crec.general_purpose_bit_flag & 2)? '8' : '4');
- X printf(" number of Shannon-Fano trees (implosion): %c\n",
- X (crec.general_purpose_bit_flag & 4)? '3' : '2');
- X `7D else if (methnum == DEFLATED) `7B
- X UWORD dnum=(crec.general_purpose_bit_flag>>1) & 3;
- X printf(" compression sub-type (deflation): %s\n",
- X dtype`5Bdnum`5D);
- X `7D
- X printf(" file security status: %sencrypted\
- Vn",
- X (crec.general_purpose_bit_flag & 1)? "" : "not ");
- X printf(" extended local header: %s\n",
- X (crec.general_purpose_bit_flag & 8)? "yes" : "no");
- X /* print upper 3 bits for amusement? */
- X printf(" file last modified on: %s\n",
- X zipinfo_time(&crec.last_mod_file_date, &crec.last_mod_file_time));
- X printf(" 32-bit CRC value (hex): %.8lx\n",
- X crec.crc32);
- X printf(" compressed size: %lu bytes\n"
- V,
- X crec.compressed_size);
- X printf(" uncompressed size: %lu bytes\n"
- V,
- X crec.uncompressed_size);
- X printf(" length of filename: %u character
- Vs\n",
- X crec.filename_length);
- X printf(" length of extra field: %u bytes\n",
- X crec.extra_field_length);
- X printf(" length of file comment: %u character
- Vs\n",
- X crec.file_comment_length);
- X printf(" disk number on which file begins: disk %u\n",
- X crec.disk_number_start);
- X printf(" apparent file type: %s\n",
- X (crec.internal_file_attributes & 1)? "text" : "binary");
- X/*
- X printf(" external file attributes (hex): %.8lx\n",
- X crec.external_file_attributes);
- X */
- X xattr = (UWORD) ((crec.external_file_attributes >> 16) & 0xFFFF);
- X if (hostnum == VMS_) `7B
- X char *p=attribs, *q=attribs+1;
- X int i, j, k;
- X
- X for (k = 0; k < 12; ++k)
- X workspace`5Bk`5D = 0;
- X if (xattr & S_IRUSR)
- X workspace`5B0`5D = 'R';
- X if (xattr & S_IWUSR) `7B
- X workspace`5B1`5D = 'W';
- X workspace`5B3`5D = 'D';
- X `7D
- X if (xattr & S_IXUSR)
- X workspace`5B2`5D = 'E';
- X if (xattr & S_IRGRP)
- +-+-+-+-+-+-+-+- END OF PART 14 +-+-+-+-+-+-+-+-
-