/*--------------------------------------------------------------------------- unzip.c UnZip - a zipfile extraction utility. See below for make instructions, or read the comments in Makefile and the various Contents files for more de- tailed explanations. To report a bug, send a *complete* description to zip-bugs@wkuvx1.wku.edu; include machine type, operating system and ver- sion, compiler and version, and reasonably detailed error messages or prob- lem report. To join Info-ZIP, see the instructions in README. UnZip 5.x is a greatly expanded and partially rewritten successor to 4.x, which in turn was almost a complete rewrite of version 3.x. For a detailed revision history, see UnzpHist.zip at quest.jpl.nasa.gov. For a list of the many (near infinite) contributors, see "CONTRIBS" in the UnZip source distribution. --------------------------------------------------------------------------- [from original zipinfo.c] This program reads great gobs of totally nifty information, including the central directory stuff, from ZIP archives ("zipfiles" for short). It started as just a testbed for fooling with zipfiles, but at this point it is actually a useful utility. It also became the basis for the rewrite of UnZip (3.16 -> 4.0), using the central directory for processing rather than the individual (local) file headers. As of ZipInfo v2.0 and UnZip v5.1, the two programs are combined into one. If the executable is named "unzip" (or "unzip.exe", depending), it behaves like UnZip by default; if it is named "zipinfo" or "ii", it behaves like ZipInfo. The ZipInfo behavior may also be triggered by use of unzip's -Z option; for example, "unzip -Z [zipinfo_options] archive.zip". Another dandy product from your buddies at Newtware! Author: Greg Roelofs, newt@uchicago.edu, 23 August 1990 -> ... 1994 --------------------------------------------------------------------------- Version: unzip512.{tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS, Windows, Windows NT, Macintosh, Amiga, Atari, Human68K and TOPS-20. De- cryption requires sources in zcrypt23.zip, and Windows (not NT) support requires sources in wunz20sr.zip (not up to date). See accompanying file "Where" in the main source distribution for ftp, uucp and mail-server sites. Copyrights: see accompanying file "COPYING" in UnZip source distribution. ---------------------------------------------------------------------------*/ #include "unzip.h" /* includes, typedefs, macros, prototypes, etc. */ #include "crypt.h" #include "version.h" #ifdef MSWIN # include "wizunzip.h" #endif /**********************/ /* Global Variables */ /**********************/ int zipinfo_mode; /* behave like ZipInfo or like normal UnZip? */ int aflag=0; /* -a: do ASCII-EBCDIC and/or end-of-line translation */ int cflag=0; /* -c: output to stdout */ int C_flag=0; /* -C: match filenames case-insensitively */ int dflag=0; /* -d: all args are files/dirs to be extracted */ int fflag=0; /* -f: "freshen" (extract only newer files) */ int hflag=0; /* -h: header line (zipinfo) */ int jflag=0; /* -j: junk pathnames (unzip) */ int lflag=(-1); /* -12slmv: listing format (zipinfo) */ int L_flag=0; /* -L: convert filenames from some OSes to lowercase */ int overwrite_none=0; /* -n: never overwrite files (no prompting) */ int overwrite_all=0; /* -o: OK to overwrite files without prompting */ int force_flag=0; /* (shares -o for now): force to override errors, etc. */ int qflag=0; /* -q: produce a lot less output */ #ifdef DOS_NT_OS2 int sflag=0; /* -s: convert filename spaces (blanks) to underscores */ int volflag=0; /* -$: extract volume labels */ #endif int tflag=0; /* -t: test (unzip) or totals line (zipinfo) */ int T_flag=0; /* -T: decimal time format (zipinfo) */ int uflag=0; /* -u: "update" (extract only newer & brand-new files) */ int vflag=0; /* -v: (verbosely) list directory */ int V_flag=0; /* -V: don't strip VMS version numbers */ #ifdef VMS int secinf=0; /* -X: keep owner/protection */ #endif int zflag=0; /* -z: display the zipfile comment (only, for unzip) */ int filespecs; /* number of real file specifications to be matched */ int xfilespecs; /* number of excluded filespecs to be matched */ int process_all_files = 0; int create_dirs; /* used by main(), mapname(), checkdir() */ int extract_flag; #if (defined(CRYPT) || !defined(NO_ZIPINFO)) int newzip; /* used in extract.c, crypt.c, zipinfo.c */ #endif LONGINT real_ecrec_offset, expect_ecrec_offset; long csize; /* used by list_files(), ReadByte(): must be signed */ long ucsize; /* used by list_files(), unReduce(), explode() */ long used_csize; /* used by extract_or_test_member(), explode() */ static char *fnames[2] = {"*", NULL}; /* default filenames vector */ char **pfnames = fnames, **pxnames = &fnames[1]; char near sig[5]; char near answerbuf[10]; min_info info[DIR_BLKSIZ], *pInfo=info; /*--------------------------------------------------------------------------- unreduce/unshrink/explode/inflate working storage and globals: ---------------------------------------------------------------------------*/ union work area; /* see unzip.h for the definition of work */ ulg crc32val; ush near mask_bits[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; /*--------------------------------------------------------------------------- Input file variables: ---------------------------------------------------------------------------*/ uch *inbuf, *inptr; /* input buffer (any size is OK) and pointer */ int incnt; ulg bitbuf; int bits_left; boolean zipeof; #ifdef SFX char *argv0; /* used for NT and EXE_EXTENSION */ #else char *wildzipfn; #endif char *zipfn; /* GRR: MSWIN: must nuke any malloc'd zipfn... */ int zipfd; /* zipfile file handle */ LONGINT ziplen; uch *hold; char near local_hdr_sig[5]; /* initialize signatures at runtime so unzip */ char near central_hdr_sig[5]; /* executable won't look like a zipfile */ char near end_central_sig[5]; /* char extd_local_sig[5]; NOT USED YET */ cdir_file_hdr crec; /* used in unzip.c, extract.c, misc.c */ local_file_hdr lrec; /* used in unzip.c, extract.c */ ecdir_rec ecrec; /* used in unzip.c, extract.c */ struct stat statbuf; /* used by main, mapname, check_for_newer */ LONGINT cur_zipfile_bufstart; /* extract_or_test_files, readbuf, ReadByte */ LONGINT extra_bytes = 0; /* used in unzip.c, misc.c */ uch *extra_field = (uch *)NULL; /* used by VMS, Mac and OS/2 versions */ #ifdef MACOS short gnVRefNum; long glDirID; OSType gostCreator; OSType gostType; boolean fMacZipped; boolean macflag; CursHandle rghCursor[4]; /* status cursors */ short giCursor = 0; #endif /*--------------------------------------------------------------------------- Output stream variables: ---------------------------------------------------------------------------*/ int mem_mode = 0; int disk_full; #ifdef SYMLINKS int symlnk; #endif FILE *outfile; uch *outbuf; uch *outptr; ulg outcnt; /* number of chars stored in outbuf */ #ifdef SMALL_MEM uch *outbuf2; /* initialized in main() (never changes) */ #else uch *outbuf2 = (uch *)NULL; /* malloc'd ONLY if unshrink and -a */ #endif #ifdef MSWIN char *filename; #else char near filename[FILNAMSIZ]; /* also used by NT for temporary SFX path */ #endif /********************/ /* Global strings */ /********************/ char Far UnzipVersion[] = UZ_VERSION; /* now defined in version.h */ #ifndef NO_ZIPINFO char Far ZipinfoVersion[] = ZI_VERSION; #endif char Far EndSigMsg[] = "\nnote:\ didn't find end-of-central-dir signature at end of central dir.\n"; char Far CentSigMsg[] = "error: expected central file header signature not found (file #%u).\n"; char Far SeekMsg[] = "error [%s]: attempt to seek before beginning of zipfile\n%s"; char Far FilenameNotMatched[] = "caution: filename not matched: %s\n"; char Far ExclFilenameNotMatched[] = "caution: excluded filename not matched: %s\n"; #ifndef SFX char Far CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n"; #endif #ifdef VMS char Far ReportMsg[] = "\ (please check that you have transferred or created the zipfile in the\n\ appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n"; #else char Far ReportMsg[] = "\ (please check that you have transferred or created the zipfile in the\n\ appropriate BINARY mode and that you have compiled unzip properly)\n"; #endif /*******************/ /* Local strings */ /*******************/ #ifndef SFX static char Far EnvUnZip[] = ENV_UNZIP; static char Far EnvUnZip2[] = ENV_UNZIP2; static char Far EnvZipInfo[] = ENV_ZIPINFO; static char Far EnvZipInfo2[] = ENV_ZIPINFO2; #endif #if (!defined(SFX) || defined(SFX_EXDIR)) static char Far NotExtracting[] = "caution: not extracting; -d ignored\n"; static char Far MustGiveExdir[] = "error: must specify directory to which to extract with -d option\n"; #endif static char Far CentDirTooLong[] = "error [%s]: reported length of central directory is\n\ %d bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1\n\ zipfile?). Compensating...\n"; static char Far InvalidOptionsMsg[] = "error:\ -fn or any combination of -c, -l, -p, -t, -u and -v options invalid\n"; static char Far IgnoreOOptionMsg[] = "caution: both -n and -o specified; ignoring -o\n"; static char Far CantAllocateBuffers[] = "error: can't allocate unzip buffers\n"; /* usage() strings */ #ifndef VMSCLI #ifndef SFX #ifdef VMS static char Far Example2[] = "vms.c"; static char Far Example1[] = "unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS"; #else static char Far Example2[] = "ReadMe"; static char Far Example1[] = "unzip -p foo | more => send contents of foo.zip via pipe into program more"; #endif /* ?VMS */ #ifdef DOS_NT_OS2 static char Far loc_str[] = " -$ label removables (-$$ => fixed disks)"; static char Far loc2str[] = "\ -s spaces in filenames => '_'\n"; #else /* !DOS_NT_OS2 */ #ifdef VMS static char Far loc_str[] = "\"-X\" restore owner/protection info"; static char Far loc2str[] = "\n"; #else static char Far loc_str[] = ""; /* Unix, Amiga, Mac, etc. */ /* char Far loc_str[] = " -X restore UID/GID info"; Unix version, in 5.2 */ static char Far loc2str[] = ""; #endif /* ?VMS */ #endif /* ?DOS_NT_OS2 */ #endif /* !SFX */ #ifndef NO_ZIPINFO #ifdef VMSWILD static char Far ZipInfoExample[] = "* or % (e.g., \"*font-%.zip\")"; #else static char Far ZipInfoExample[] = "*, ?, [] (e.g., \"[a-j]*.zip\")"; #endif static char Far ZipInfoUsageLine1[] = "\ ZipInfo %s, by Newtware and the fine folks at Info-ZIP.\n\ \n\ List name, date/time, attribute, size, compression method, etc., about files\n\ in list (excluding those in xlist) contained in the specified .zip archive(s).\ \n\"file[.zip]\" may be a wildcard name containing %s.\n\n\ usage: zipinfo [-12smlvhtTz] file[.zip] [list...] [-x xlist...]\n\ or: unzip %s-Z%s [-12smlvhtTz] file[.zip] [list...] [-x xlist...]\n"; static char Far ZipInfoUsageLine2[] = "\nmain\ listing-format options: -s short Unix \"ls -l\" format (def.)\n\ -1 filenames ONLY, one per line -m medium Unix \"ls -l\" format\n\ -2 just filenames but allow -h/-t/-z -l long Unix \"ls -l\" format\n\ -v verbose, multi-page format\n"; static char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\ -h print header line -t print totals for listed files or for all\n\ -z print zipfile comment %c-T%c print file times in sortable decimal format\ \n -x exclude filenames that follow from listing\n"; /*" -p disable automatic \"more\" function (for pipes) [not implemented]\n";*/ #endif /* !NO_ZIPINFO */ #endif /* !VMSCLI */ #ifdef BETA static char Far BetaVersion[] = "%s\ THIS IS STILL A BETA VERSION OF UNZIP%s -- DO NOT DISTRIBUTE.\n\n"; #endif #ifdef SFX # if (defined(SFX_EXDIR) && !defined(VMS)) static char Far UnzipSFXUsage[] = "\ UnZipSFX %s, by Info-ZIP (zip-bugs@wkuvx1.wku.edu).\n\ Valid options are -tfupcz and -d ; modifiers are -abjnoqCLV%s.\n"; # else static char Far UnzipSFXUsage[] = "\ UnZipSFX %s, by Info-ZIP (zip-bugs@wkuvx1.wku.edu).\n\ Valid options are -tfupcz; modifiers are -abjnoqCLV%s.\n"; # endif static char Far CantFindMyself[] = "unzipsfx: can't find myself! [%s]\n"; #else /* !SFX */ static char Far CompileOptions[] = "UnZip special compilation options:\n"; static char Far CompileOptFormat[] = "\t%s\n"; static char Far EnvOptions[] = "\nUnZip and ZipInfo environment options:\n"; static char Far EnvOptFormat[] = "%16s: %s\n"; static char Far None[] = "[none]"; # ifdef NO_ZIPINFO static char Far No_ZipInfo[] = "NO_ZIPINFO"; # endif # ifdef CHECK_EOF static char Far Check_EOF[] = "CHECK_EOF"; # endif # ifdef DOSWILD static char Far DosWild[] = "DOSWILD"; # endif # ifdef VMSWILD static char Far VmsWild[] = "VMSWILD"; # endif # ifdef VMSCLI static char Far VmsCLI[] = "VMSCLI"; # endif # ifdef ASM_INFLATECODES static char Far AsmInflateCodes[] = "ASM_INFLATECODES"; # endif # ifdef ASM_CRC static char Far AsmCRC[] = "ASM_CRC"; # endif # ifdef REGARGS static char Far RegArgs[] = "REGARGS"; # endif # ifdef OLD_EXDIR static char Far Old_Exdir[] = "OLD_EXDIR"; # endif # ifdef CHECK_VERSIONS static char Far Check_Versions[] = "CHECK_VERSIONS"; # endif # ifdef RETURN_CODES static char Far Return_Codes[] = "RETURN_CODES"; # endif # ifdef RETURN_SEVERITY static char Far Return_Severity[] = "RETURN_SEVERITY"; # endif # ifdef DEBUG static char Far Debug[] = "DEBUG"; # endif # ifdef DEBUG_TIME static char Far DebugTime[] = "DEBUG_TIME"; # endif # ifdef CRYPT static char Far Decryption[] = "[decryption]"; # endif # ifdef __EMX__ static char Far EnvEMX[] = "EMX"; static char Far EnvEMXOPT[] = "EMXOPT"; # endif # ifdef __GO32__ static char Far EnvGO32[] = "GO32"; static char Far EnvGO32TMP[] = "GO32TMP"; # endif /* UnzipUsageLine1[] is also used in vms/cmdline.c: do not make it static */ char Far UnzipUsageLine1[] = "\ UnZip %s, by Info-ZIP. Portions (c) 1989 by S. H. Smith.\n\ Send bug reports to authors at zip-bugs@wkuvx1.wku.edu; see README for details.\ \n\n"; static char Far UnzipUsageLine2a[] = "\ Latest sources and executables are always in ftp.uu.net:/pub/archiving/zip, at\ \nleast as of date of this release; see \"Where\" for other ftp and non-ftp \ sites.\n\n"; #ifndef VMSCLI static char Far UnzipUsageLine2[] = "\ Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]\n \ Default action is to extract files in list, except those in xlist, to exdir;\n\ file[.zip] may be a wildcard. %s\n\n"; #ifdef NO_ZIPINFO # define ZIPINFO_MODE_OPTION "" static char Far ZipinfoMode[] = "(ZipInfo mode is disabled in this version.)"; #else # define ZIPINFO_MODE_OPTION "[-Z] " # ifdef VMS static char Far ZipinfoMode[] = "\"-Z\" => ZipInfo mode (`unzip \"-Z\"' for usage)."; # else static char Far ZipinfoMode[] = "-Z => ZipInfo mode (\"unzip -Z\" for usage)."; # endif #endif /* ?NO_ZIPINFO */ static char Far UnzipUsageLine3[] = "\ -p extract files to pipe, no messages -l list files (short format)\n\ -f freshen existing files, create none -t test compressed archive data\n\ -u update files, create if necessary -z display archive comment\n\ -x exclude files which follow (in xlist) -d extract files into exdir\n\n"; static char Far UnzipUsageLine4[] = "\ modifiers: -q quiet mode (-qq => quieter)\n\ -n never overwrite existing files -a auto-convert any text files\n\ -o overwrite files WITHOUT prompting -aa treat ALL files as text\n \ -j junk paths (don't make directories) -v be verbose/print version info\n\ %c-C%c match filenames case-insensitively %c-L%c make (some) names \ lowercase\n %-42s %c-V%c retain VMS version numbers\n%s"; static char Far UnzipUsageLine5[] = "\ Examples (see unzip.doc for more info):\n\ unzip data1 -x joe => extract all files except joe from zipfile data1.zip\n\ %s\n\ unzip -fo foo %-6s => quietly replace existing %s if archive file newer\n"; #endif /* !VMSCLI */ /* process_zipfiles() strings */ static char Far FilesProcessOK[] = "%d archive%s successfully processed.\n"; static char Far ArchiveWarning[] = "%d archive%s had warnings but no fatal errors.\n"; static char Far ArchiveFatalError[] = "%d archive%s had fatal errors.\n"; static char Far FileHadNoZipfileDir[] = "%d file%s had no zipfile directory.\n"; static char Far ZipfileWasDir[] = "1 \"zipfile\" was a directory.\n"; static char Far ManyZipfilesWereDir[] = "%d \"zipfiles\" were directories.\n"; static char Far NoZipfileFound[] = "No zipfiles found.\n"; #endif /* ?SFX */ /* do_seekable() strings */ #ifndef SFX #ifdef UNIX static char Far CantFindZipfileDirMsg[] = "%s: can't find zipfile directory in one of %s or\n\ %s%s.zip, and can't find %s, period.\n"; static char Far CantFindEitherZipfile[] = "%s: can't find %s, %s.zip or %s, so there.\n"; #else /* !UNIX */ static char Far CantFindZipfileDirMsg[] = "%s: can't find zipfile directory in %s,\n\ %sand can't find %s, period.\n"; static char Far CantFindEitherZipfile[] = "%s: can't find either %s or %s, so there.\n"; #endif /* ?UNIX */ static char Far MaybeExe[] = "note: %s may be a plain executable, not an archive\n"; static char Far CentDirNotInZipMsg[] = "\n\ Zipfile is part of a multi-disk archive, and this is not the disk on\n\ which the central zipfile directory begins.\n"; #ifdef NO_MULTIPART static char Far NoMultiDiskArcSupport[] = "\nerror [%s]: zipfile is part of multi-disk archive\n\ (sorry, not yet supported).\n"; static char Far MaybePakBug[] = "warning [%s]:\ zipfile claims to be 2nd disk of a 2-part archive;\n\ attempting to process anyway. If no further errors occur, this archive\n\ was probably created by PAK v2.51 or earlier. This bug was reported to\n\ NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\ of mid-1992 it still hadn't been. (If further errors do occur, archive\n\ was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\ multi-part archives.)\n"; #else static char Far MaybePakBug[] = "warning [%s]:\ zipfile claims to be last disk of a multi-part archive;\n\ attempting to process anyway, assuming all parts have been concatenated\n\ together in order. Expect \"errors\" and warnings...true multi-part support\ \n doesn't exist yet (coming soon).\n"; #endif static char Far ExtraBytesAtStart[] = "warning [%s]: extra %ld bytes at beginning or within zipfile\n\ (attempting to process anyway)\n"; #endif /* !SFX */ static char Far MissingBytes[] = "error [%s]: missing %ld bytes in zipfile\n\ (attempting to process anyway)\n"; static char Far NullCentDirOffset[] = "error [%s]: NULL central directory offset\n\ (attempting to process anyway)\n"; static char Far ZipfileEmpty[] = "warning [%s]: zipfile is empty\n"; static char Far CentDirStartNotFound[] = "error [%s]: start of central directory not found;\n\ zipfile corrupt.\n%s"; static char Far ZipfileCommTrunc1[] = "\ncaution: zipfile comment truncated\n"; #ifdef MSWIN # include "winsetup.c" /* duplicates some code in main() */ #else /* !MSWIN */ /******************/ /* Main program */ /******************/ int MAIN(argc, argv) /* return PK-type error code (except under VMS) */ int argc; char *argv[]; { #ifndef NO_ZIPINFO char *p; #endif int error=FALSE; #if defined(__IBMC__) && defined(__DEBUG_ALLOC__) extern void DebugMalloc(void); atexit(DebugMalloc); #endif /*--------------------------------------------------------------------------- Macintosh initialization code. ---------------------------------------------------------------------------*/ #ifdef MACOS int a; for (a = 0; a < 4; ++a) rghCursor[a] = GetCursor(a+128); giCursor = 0; aflag=cflag=dflag=fflag=L_flag=jflag=qflag=tflag=uflag=vflag=zflag = 0; local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0'; /* extd_local_sig[1] = '\0'; */ error = FALSE; overwrite_none = overwrite_all = force_flag = 0; #endif /* MACOS */ #ifdef MALLOC_WORK area.Slide = (uch *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char)); area.shrink.Prefix_of = (short *)area.Slide; area.shrink.Suffix_of = area.Slide + (sizeof(short)*(HSIZE+1)); area.shrink.Stack = area.Slide + (sizeof(short) + sizeof(char))*(HSIZE+1); #endif /*--------------------------------------------------------------------------- Human68K initialization code. ---------------------------------------------------------------------------*/ #ifdef __human68k__ InitTwentyOne(); #endif /*--------------------------------------------------------------------------- Set signal handler for restoring echo, warn of zipfile corruption, etc. ---------------------------------------------------------------------------*/ signal(SIGINT, handler); #ifdef SIGTERM /* some systems really have no SIGTERM */ signal(SIGTERM, handler); #endif #ifdef SIGBUS signal(SIGBUS, handler); #endif #ifdef SIGSEGV signal(SIGSEGV, handler); #endif /*--------------------------------------------------------------------------- First figure out if we're running in UnZip mode or ZipInfo mode, and put the appropriate environment-variable options into the queue. Then rip through any command-line options lurking about... ---------------------------------------------------------------------------*/ #ifdef SFX argv0 = argv[0]; #if defined(OS2) || defined(NT) zipfn = GetLoadPath(); /* non-MSC NT puts path into filename[] */ #else zipfn = argv0; #endif zipinfo_mode = FALSE; if ((error = uz_opts(&argc, &argv)) != 0) RETURN(error); #else /* !SFX */ #ifdef MSDOS /* extract MKS extended argument list from environment (before envargs!) */ mksargs(&argc, &argv); #endif #ifdef VMSCLI { ulg status = vms_unzip_cmdline(&argc, &argv); if (!(status & 1)) return status; } #endif /* VMSCLI */ #ifndef NO_ZIPINFO if ((p = strrchr(argv[0], DIR_END)) == (char *)NULL) p = argv[0]; else ++p; if (STRNICMP(p, "zipinfo", 7) == 0 || STRNICMP(p, "ii", 2) == 0 || (argc > 1 && strncmp(argv[1], "-Z", 2) == 0)) { zipinfo_mode = TRUE; envargs(&argc, &argv, LoadFarStringSmall(EnvZipInfo), LoadFarStringSmall2(EnvZipInfo2)); error = zi_opts(&argc, &argv); } else #endif /* NO_ZIPINFO */ { zipinfo_mode = FALSE; envargs(&argc, &argv, LoadFarStringSmall(EnvUnZip), LoadFarStringSmall2(EnvUnZip2)); error = uz_opts(&argc, &argv); } if ((argc < 0) || error) RETURN(error); #endif /* ?SFX */ /*--------------------------------------------------------------------------- Now get the zipfile name from the command line and then process any re- maining options and file specifications. ---------------------------------------------------------------------------*/ #ifdef DOS_NT_OS2 /* convert MSDOS-style directory separators to Unix-style ones for * user's convenience (include zipfile name itself) */ pfnames = argv; while (*pfnames != NULL) { char *q; for (q = *pfnames; *q; ++q) if (*q == '\\') *q = '/'; ++pfnames; } #endif /* DOS_NT_OS2 */ #ifndef SFX wildzipfn = *argv++; #endif #if (defined(OLD_EXDIR) || (defined(SFX) && !defined(SFX_EXDIR))) #ifndef SFX if (argc > 0) { /* -d: "name/" immediately after zipfile name is a stored directory to * be extracted--do NOT treat as directory to which to extract files */ if (extract_flag && !dflag) { create_dirs = !fflag; if ((error = checkdir(*argv, ROOT)) > 2) /* mem, or file in way */ RETURN(error); else if (!error) { /* it IS extract-to dir, so adjust pointers */ ++argv; --argc; } } } #endif /* !SFX */ filespecs = argc; xfilespecs = 0; if (argc > 0) { char **pp = argv-1; pfnames = argv; while (*++pp) if (strcmp(*pp, "-x") == 0) { if (pp > argv) { *pp = 0; /* terminate pfnames */ filespecs = pp - pfnames; } else { pfnames = fnames; /* defaults */ filespecs = 0; } pxnames = pp + 1; /* excluded-names ptr starts after -x */ xfilespecs = argc - filespecs - 1; break; /* skip rest of args */ } process_all_files = FALSE; } else process_all_files = TRUE; /* for speed */ #else /* !(OLD_EXDIR || (SFX && !SFX_EXDIR)) */ filespecs = argc; xfilespecs = 0; if (argc > 0) { int in_files=FALSE, in_xfiles=FALSE; char **pp = argv-1; process_all_files = FALSE; pfnames = argv; while (*++pp) { Trace((stderr, "pp - argv = %d\n", pp-argv)); if (!dflag && strncmp(*pp, "-d", 2) == 0) { char *q = *pp; int firstarg = (pp == argv); dflag = TRUE; if (in_files) { /* ... zipfile ... -d exdir ... */ *pp = 0; /* terminate pfnames */ filespecs = pp - pfnames; in_files = FALSE; } else if (in_xfiles) { *pp = 0; /* terminate pxnames */ xfilespecs = pp - pxnames; /* "... -x xlist -d exdir": nothing left */ } /* first check for "-dpath", then for "-d path" */ if (q[2]) q += 2; else if (*++pp) q = *pp; else { FPRINTF(stderr, LoadFarString(MustGiveExdir)); RETURN(PK_PARAM); /* don't extract here by accident */ } if (extract_flag) { create_dirs = !fflag; if ((error = checkdir(q, ROOT)) > 2) RETURN(error); /* out of memory, or file in way */ } else FPRINTF(stderr, LoadFarString(NotExtracting)); if (firstarg) /* ... zipfile -d exdir ... */ if (pp[1]) { pfnames = pp + 1; /* argv+2 */ filespecs = argc - (pfnames-argv); /* for now... */ } else { process_all_files = TRUE; pfnames = fnames; /* GRR: necessary? */ filespecs = 0; /* GRR: necessary? */ break; } } else if (!in_xfiles) { if (strcmp(*pp, "-x") == 0) { in_xfiles = TRUE; if (pp == argv || (pp == argv+2 && dflag)) { pfnames = fnames; /* defaults */ filespecs = 0; } else if (in_files) { *pp = 0; /* terminate pfnames */ filespecs = pp - pfnames; /* adjust count */ in_files = FALSE; } pxnames = pp + 1; /* excluded-names ptr starts after -x */ xfilespecs = argc - (pxnames-argv); /* anything left... */ } else in_files = TRUE; } } } else process_all_files = TRUE; /* for speed */ #endif /* ?(OLD_EXDIR || (SFX && !SFX_EXDIR)) */ /*--------------------------------------------------------------------------- Okey dokey, we have everything we need to get started. Let's roll. ---------------------------------------------------------------------------*/ inbuf = (uch *)malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */ outbuf = (uch *)malloc(OUTBUFSIZ + 1); /* 1 extra for string termin. */ if ((inbuf == (uch *)NULL) || (outbuf == (uch *)NULL)) { FPRINTF(stderr, LoadFarString(CantAllocateBuffers)); RETURN(PK_MEM); } hold = inbuf + INBUFSIZ; /* to check for boundary-spanning signatures */ #ifdef SMALL_MEM outbuf2 = outbuf+RAWBUFSIZ; /* never changes */ #endif RETURN(process_zipfiles()); /* keep passing errors back... */ } /* end main() */ /**********************/ /* Function uz_opts() */ /**********************/ int uz_opts(pargc, pargv) int *pargc; char ***pargv; { char **argv, *s; int argc, c, error=FALSE, negative=0; argc = *pargc; argv = *pargv; while (--argc > 0 && (*++argv)[0] == '-') { s = argv[0] + 1; while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */ switch (c) { case ('-'): ++negative; break; case ('a'): if (negative) { aflag = MAX(aflag-negative,0); negative = 0; } else ++aflag; break; case ('b'): if (negative) negative = 0; /* do nothing: "-b" is default */ else aflag = 0; break; case ('c'): if (negative) { cflag = FALSE, negative = 0; #ifdef NATIVE aflag = 0; #endif } else { cflag = TRUE; #ifdef NATIVE aflag = 2; /* so you can read it on the screen */ #endif } break; case ('C'): /* -C: match filenames case-insensitively */ if (negative) C_flag = FALSE, negative = 0; else C_flag = TRUE; break; case ('d'): /* arg after zipfn is stored dir, not extract-to */ #ifdef OLD_EXDIR if (negative) dflag = FALSE, negative = 0; else dflag = TRUE; #endif break; case ('e'): /* just ignore -e, -x options (extract) */ break; case ('f'): /* "freshen" (extract only newer files) */ if (negative) fflag = uflag = FALSE, negative = 0; else fflag = uflag = TRUE; break; case ('j'): /* junk pathnames/directory structure */ if (negative) jflag = FALSE, negative = 0; else jflag = TRUE; break; #ifndef SFX case ('l'): if (negative) { vflag = MAX(vflag-negative,0); negative = 0; } else ++vflag; break; #endif /* !SFX */ case ('L'): /* convert (some) filenames to lowercase */ if (negative) L_flag = FALSE, negative = 0; else L_flag = TRUE; break; case ('n'): /* don't overwrite any files */ if (negative) overwrite_none = FALSE, negative = 0; else overwrite_none = TRUE; break; case ('o'): /* OK to overwrite files without prompting */ if (negative) { overwrite_all = MAX(overwrite_all-negative,0); force_flag = MAX(force_flag-negative,0); negative = 0; } else { ++overwrite_all; ++force_flag; /* (share -o for now) force to cont. */ } break; case ('p'): /* pipes: extract to stdout, no messages */ if (negative) { cflag = FALSE; qflag = MAX(qflag-999,0); negative = 0; } else { cflag = TRUE; qflag += 999; } break; case ('q'): /* quiet: fewer comments/messages */ if (negative) { qflag = MAX(qflag-negative,0); negative = 0; } else ++qflag; break; #ifdef DOS_NT_OS2 case ('s'): /* spaces in filenames: allow by default */ if (negative) sflag = FALSE, negative = 0; else sflag = TRUE; break; #endif case ('t'): if (negative) tflag = FALSE, negative = 0; else tflag = TRUE; break; case ('u'): /* update (extract only new and newer files) */ if (negative) uflag = FALSE, negative = 0; else uflag = TRUE; break; case ('U'): /* obsolete; to be removed in future release */ if (negative) L_flag = TRUE, negative = 0; else L_flag = FALSE; break; #ifndef SFX case ('v'): /* verbose */ if (negative) { vflag = MAX(vflag-negative,0); negative = 0; } else if (vflag) ++vflag; else vflag = 2; break; #endif /* !SFX */ case ('V'): /* Version (retain VMS/DEC-20 file versions) */ if (negative) V_flag = FALSE, negative = 0; else V_flag = TRUE; break; case ('x'): /* extract: default */ break; #ifdef VMS case ('X'): /* restore owner/protection info (need privs?) */ if (negative) secinf = FALSE, negative = 0; else secinf = TRUE; break; #endif /* VMS */ case ('z'): /* display only the archive comment */ if (negative) { zflag -= negative; negative = 0; } else ++zflag; break; #ifdef DOS_NT_OS2 case ('$'): if (negative) { volflag = MAX(volflag-negative,0); negative = 0; } else ++volflag; break; #endif /* DOS_NT_OS2 */ default: error = TRUE; break; } /* end switch */ } /* end while (not end of argument string) */ } /* end while (not done with switches) */ /*--------------------------------------------------------------------------- Check for nonsensical combinations of options. ---------------------------------------------------------------------------*/ if ((cflag && tflag) || (cflag && uflag) || (tflag && uflag) || (fflag && overwrite_none)) { FPRINTF(stderr, LoadFarString(InvalidOptionsMsg)); error = TRUE; } if (aflag > 2) aflag = 2; if (overwrite_all && overwrite_none) { FPRINTF(stderr, LoadFarString(IgnoreOOptionMsg)); overwrite_all = FALSE; } #ifdef SFX if (error) #else if ((argc-- == 0) || error) #endif { *pargc = argc; *pargv = argv; #ifndef SFX if (vflag >= 2 && argc == -1) { if (qflag > 3) PRINTF("%d\n", (UZ_MAJORVER*100 + UZ_MINORVER*10 + PATCHLEVEL)); else { char *envptr, *getenv(); int numopts = 0; PRINTF(LoadFarString(UnzipUsageLine1), LoadFarStringSmall(UnzipVersion)); PRINTF(LoadFarString(UnzipUsageLine2a)); version(); PRINTF(LoadFarString(CompileOptions)); #ifdef NO_ZIPINFO PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(No_ZipInfo)); ++numopts; #endif #ifdef CHECK_EOF PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(Check_EOF)); ++numopts; #endif #ifdef DOSWILD PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(DosWild)); ++numopts; #endif #ifdef VMSWILD PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(VmsWild)); ++numopts; #endif #ifdef VMSCLI PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(VmsCLI)); ++numopts; #endif #ifdef ASM_INFLATECODES PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(AsmInflateCodes)); ++numopts; #endif #ifdef ASM_CRC PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(AsmCRC)); ++numopts; #endif #ifdef REGARGS PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(RegArgs)); ++numopts; #endif #ifdef OLD_EXDIR PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(Old_Exdir)); ++numopts; #endif #ifdef CHECK_VERSIONS PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(Check_Versions)); ++numopts; #endif #ifdef RETURN_CODES PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(Return_Codes)); ++numopts; #endif #ifdef RETURN_SEVERITY PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(Return_Severity)); ++numopts; #endif #ifdef DEBUG PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(Debug)); ++numopts; #endif #ifdef DEBUG_TIME PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(DebugTime)); ++numopts; #endif #ifdef CRYPT PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(Decryption)); ++numopts; #endif if (numopts == 0) PRINTF(LoadFarString(CompileOptFormat), LoadFarStringSmall(None)); PRINTF(LoadFarString(EnvOptions)); envptr = getenv(LoadFarStringSmall(EnvUnZip)); PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvUnZip), (envptr == (char *)NULL || *envptr == 0)? LoadFarStringSmall2(None) : envptr); envptr = getenv(LoadFarStringSmall(EnvUnZip2)); PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvUnZip2), (envptr == (char *)NULL || *envptr == 0)? LoadFarStringSmall2(None) : envptr); envptr = getenv(LoadFarStringSmall(EnvZipInfo)); PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvZipInfo), (envptr == (char *)NULL || *envptr == 0)? LoadFarStringSmall2(None) : envptr); envptr = getenv(LoadFarStringSmall(EnvZipInfo2)); PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvZipInfo2), (envptr == (char *)NULL || *envptr == 0)? LoadFarStringSmall2(None) : envptr); #ifdef __EMX__ envptr = getenv(LoadFarStringSmall(EnvEMX)); PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvEMX), (envptr == (char *)NULL || *envptr == 0)? LoadFarStringSmall2(None) : envptr); envptr = getenv(LoadFarStringSmall(EnvEMXOPT)); PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvEMXOPT), (envptr == (char *)NULL || *envptr == 0)? LoadFarStringSmall2(None) : envptr); #endif /* __EMX__ */ #ifdef __GO32__ envptr = getenv(LoadFarStringSmall(EnvGO32)); PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvGO32), (envptr == (char *)NULL || *envptr == 0)? LoadFarStringSmall2(None) : envptr); envptr = getenv(LoadFarStringSmall(EnvGO32TMP)); PRINTF(LoadFarString(EnvOptFormat), LoadFarStringSmall(EnvGO32TMP), (envptr == (char *)NULL || *envptr == 0)? LoadFarStringSmall2(None) : envptr); #endif /* __GO32__ */ } return 0; } else #endif /* !SFX */ return usage(error); } if (cflag || tflag || vflag) extract_flag = FALSE; else extract_flag = TRUE; *pargc = argc; *pargv = argv; return 0; } /* end function uz_opts() */ /********************/ /* Function usage() */ /********************/ #ifdef SFX # ifdef VMS # define LOCAL "X. Quote uppercase options" # else # ifdef DOS_NT_OS2 # define LOCAL "s$" # else # ifdef AMIGA # define LOCAL "$" # else # define LOCAL "" # endif # endif /* ?DOS_NT_OS2 */ # endif /* ?VMS */ int usage(error) /* return PK-type error code */ int error; { FILE *usagefp; if (error) usagefp = (FILE *)stderr; else usagefp = (FILE *)stdout; FPRINTF(usagefp, LoadFarString(UnzipSFXUsage), LoadFarStringSmall(UnzipVersion), LOCAL); #ifdef BETA FPRINTF(usagefp, LoadFarString(BetaVersion), "\n", "SFX"); #endif if (error) return PK_PARAM; else return PK_COOL; /* just wanted usage screen: no error */ } /* end function usage() */ #else /* !SFX */ #ifndef VMSCLI int usage(error) /* return PK-type error code */ int error; { #ifdef VMS # define QUOT '\"' # define QUOTS "\"" #else # define QUOT ' ' # define QUOTS "" #endif FILE *usagefp; /*--------------------------------------------------------------------------- If user requested usage, send it to stdout; else send to stderr. ---------------------------------------------------------------------------*/ if (error) usagefp = (FILE *)stderr; else usagefp = (FILE *)stdout; /*--------------------------------------------------------------------------- Print either ZipInfo usage or UnZip usage, depending on incantation. (Strings must be no longer than 512 bytes for Turbo C, apparently.) ---------------------------------------------------------------------------*/ if (zipinfo_mode) { #ifndef NO_ZIPINFO FPRINTF(usagefp, LoadFarString(ZipInfoUsageLine1), LoadFarStringSmall(ZipinfoVersion), LoadFarStringSmall2(ZipInfoExample), QUOTS,QUOTS); FPRINTF(usagefp, LoadFarString(ZipInfoUsageLine2)); FPRINTF(usagefp, LoadFarString(ZipInfoUsageLine3), QUOT,QUOT); #ifdef VMS FPRINTF(usagefp, "\nRemember that non-lowercase filespecs must be\ quoted in VMS (e.g., \"Makefile\").\n"); #endif #endif /* !NO_ZIPINFO */ } else { /* UnZip mode */ FPRINTF(usagefp, LoadFarString(UnzipUsageLine1), LoadFarStringSmall(UnzipVersion)); #ifdef BETA FPRINTF(usagefp, LoadFarString(BetaVersion), "", ""); #endif FPRINTF(usagefp, LoadFarString(UnzipUsageLine2), ZIPINFO_MODE_OPTION, LoadFarStringSmall(ZipinfoMode)); FPRINTF(usagefp, LoadFarString(UnzipUsageLine3)); FPRINTF(usagefp, LoadFarString(UnzipUsageLine4), QUOT,QUOT, QUOT,QUOT, LoadFarStringSmall(loc_str), QUOT,QUOT, LoadFarStringSmall2(loc2str)); /* This is extra work for SMALL_MEM, but it will work since * LoadFarStringSmall2 uses the same buffer. Remember, this * is a hack. */ FPRINTF(usagefp, LoadFarString(UnzipUsageLine5), LoadFarStringSmall(Example1), LoadFarStringSmall2(Example2), LoadFarStringSmall2(Example2)); } if (error) return PK_PARAM; else return PK_COOL; /* just wanted usage screen: no error */ } /* end function usage() */ #endif /* !VMSCLI */ #endif /* ?SFX */ #endif /* ?MSWIN */ /*******************************/ /* Function process_zipfiles() */ /*******************************/ int process_zipfiles() /* return PK-type error code */ { #ifndef SFX char *lastzipfn = (char *)NULL; int NumWinFiles, NumLoseFiles, NumWarnFiles; int NumMissDirs, NumMissFiles; #endif int error=0, error_in_archive=0; /*--------------------------------------------------------------------------- Start by constructing the various PK signature strings. ---------------------------------------------------------------------------*/ local_hdr_sig[0] /* = extd_local_sig[0] */ = '\120'; /* ASCII 'P', */ central_hdr_sig[0] = end_central_sig[0] = '\120'; /* not EBCDIC */ strcpy(local_hdr_sig+1, LOCAL_HDR_SIG); strcpy(central_hdr_sig+1, CENTRAL_HDR_SIG); strcpy(end_central_sig+1, END_CENTRAL_SIG); /* strcpy(extd_local_sig+1, EXTD_LOCAL_SIG); still to be used in multi? */ /*--------------------------------------------------------------------------- Match (possible) wildcard zipfile specification with existing files and attempt to process each. If no hits, try again after appending ".zip" suffix. If still no luck, give up. ---------------------------------------------------------------------------*/ #ifdef SFX if ((error = do_seekable(0)) == PK_NOZIP) { #ifdef EXE_EXTENSION int len=strlen(argv0); /* append .exe if appropriate; also .sfx? */ if ((zipfn = (char *)malloc(len+5)) != (char *)NULL) { strcpy(zipfn, argv0); strcpy(zipfn+len, EXE_EXTENSION); error = do_seekable(0); free(zipfn); zipfn = argv0; /* for "can't find myself" message only */ } #endif /* EXE_EXTENSION */ #ifdef NT zipfn = argv0; /* for "can't find myself" message only */ #endif } if (error) { if (error == IZ_DIR) error_in_archive = PK_NOZIP; else error_in_archive = error; if (error == PK_NOZIP) FPRINTF(stderr, LoadFarString(CantFindMyself), zipfn); } #else /* !SFX */ NumWinFiles = NumLoseFiles = NumWarnFiles = 0; NumMissDirs = NumMissFiles = 0; while ((zipfn = do_wild(wildzipfn)) != (char *)NULL) { Trace((stderr, "do_wild( %s ) returns %s\n", wildzipfn, zipfn)); lastzipfn = zipfn; /* print a blank line between the output of different zipfiles */ if (!qflag && error != PK_NOZIP && error != IZ_DIR && (NumWinFiles+NumLoseFiles+NumWarnFiles+NumMissFiles) > 0) PRINTF("\n"); FFLUSH(stdout); if ((error = do_seekable(0)) == PK_WARN) ++NumWarnFiles; else if (error == IZ_DIR) ++NumMissDirs; else if (error == PK_NOZIP) ++NumMissFiles; else if (error) ++NumLoseFiles; else ++NumWinFiles; if (error != IZ_DIR && error > error_in_archive) error_in_archive = error; Trace((stderr, "do_seekable(0) returns %d\n", error)); } /* end while-loop (wildcard zipfiles) */ if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0 && (NumMissDirs + NumMissFiles) == 1 && lastzipfn != (char *)NULL) { char *p = lastzipfn + strlen(lastzipfn); NumMissDirs = NumMissFiles = 0; if (error_in_archive == PK_NOZIP) error_in_archive = PK_COOL; zipfn = lastzipfn; strcpy(p, ".zip"); #ifdef UNIX if ((error = do_seekable(0)) == PK_NOZIP || error == IZ_DIR) { if (error == IZ_DIR) ++NumMissDirs; strcpy(p, ".ZIP"); error = do_seekable(1); } #else error = do_seekable(1); #endif if (error == PK_WARN) ++NumWarnFiles; else if (error == IZ_DIR) ++NumMissDirs; else if (error == PK_NOZIP) /* if increment again => bug: "1 file had no zipfile directory." */ /* ++NumMissFiles */ ; else if (error) ++NumLoseFiles; else ++NumWinFiles; if (error > error_in_archive) error_in_archive = error; Trace((stderr, "do_seekable(1) returns %d\n", error)); } #endif /* ?SFX */ FFLUSH(stdout); FFLUSH(stderr); /*--------------------------------------------------------------------------- Print summary of all zipfiles, assuming zipfile spec was a wildcard (no need for a summary if just one zipfile). ---------------------------------------------------------------------------*/ #ifndef SFX if (iswild(wildzipfn)) { if (NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1) FPRINTF(stderr, "\n"); if ((NumWinFiles > 1) || (NumWinFiles == 1 && NumMissDirs + NumMissFiles + NumLoseFiles + NumWarnFiles > 0)) FPRINTF(stderr, LoadFarString(FilesProcessOK), NumWinFiles, (NumWinFiles == 1)? " was" : "s were"); if (NumWarnFiles > 0) FPRINTF(stderr, LoadFarString(ArchiveWarning), NumWarnFiles, (NumWarnFiles == 1)? "" : "s"); if (NumLoseFiles > 0) FPRINTF(stderr, LoadFarString(ArchiveFatalError), NumLoseFiles, (NumLoseFiles == 1)? "" : "s"); if (NumMissFiles > 0) FPRINTF(stderr, LoadFarString(FileHadNoZipfileDir), NumMissFiles, (NumMissFiles == 1)? "" : "s"); if (NumMissDirs == 1) FPRINTF(stderr, LoadFarString(ZipfileWasDir)); else if (NumMissDirs > 0) FPRINTF(stderr, LoadFarString(ManyZipfilesWereDir), NumMissDirs); if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0) FPRINTF(stderr, LoadFarString(NoZipfileFound)); } #endif /* !SFX */ /* free allocated memory */ inflate_free(); checkdir((char *)NULL, END); #ifndef SMALL_MEM if (outbuf2) free(outbuf2); /* malloc'd ONLY if unshrink and -a */ #endif free(outbuf); free(inbuf); return error_in_archive; } /* end function process_zipfiles() */ /**************************/ /* Function do_seekable() */ /**************************/ int do_seekable(lastchance) /* return PK-type error code */ int lastchance; { #ifndef SFX static int no_ecrec = FALSE; int maybe_exe=FALSE; #endif int error=0, error_in_archive; /*--------------------------------------------------------------------------- Open the zipfile for reading in BINARY mode to prevent CR/LF translation, which would corrupt the bit streams. ---------------------------------------------------------------------------*/ if (SSTAT(zipfn, &statbuf) || (error = S_ISDIR(statbuf.st_mode)) != 0) { #ifndef SFX if (lastchance) if (no_ecrec) FPRINTF(stderr, LoadFarString(CantFindZipfileDirMsg), zipinfo_mode? "zipinfo" : "unzip", wildzipfn, zipinfo_mode? " " : "", #ifdef UNIX wildzipfn, #endif zipfn); else FPRINTF(stderr, LoadFarString(CantFindEitherZipfile), zipinfo_mode? "zipinfo" : "unzip", wildzipfn, #ifdef UNIX wildzipfn, #endif zipfn); #endif /* !SFX */ return error? IZ_DIR : PK_NOZIP; } ziplen = statbuf.st_size; #ifndef SFX #if defined(UNIX) || defined(DOS_NT_OS2) if (statbuf.st_mode & S_IEXEC) /* no extension on Unix exec's: might */ maybe_exe = TRUE; /* find unzip, not unzip.zip; etc. */ #endif #endif /* !SFX */ #ifdef VMS if (check_format()) /* check for variable-length format */ return PK_ERR; #endif if (open_input_file()) /* this should never happen, given */ return PK_NOZIP; /* the stat() test above, but... */ /*--------------------------------------------------------------------------- Find and process the end-of-central-directory header. UnZip need only check last 65557 bytes of zipfile: comment may be up to 65535, end-of- central-directory record is 18 bytes, and signature itself is 4 bytes; add some to allow for appended garbage. Since ZipInfo is often used as a debugging tool, search the whole zipfile if zipinfo_mode is true. ---------------------------------------------------------------------------*/ cur_zipfile_bufstart = 0; inptr = inbuf; if (!qflag && !zipinfo_mode) PRINTF("Archive: %s\n", zipfn); if (( #ifndef NO_ZIPINFO zipinfo_mode && ((error_in_archive = find_ecrec(ziplen)) != 0 || (error_in_archive = zi_end_central()) > PK_WARN)) || (!zipinfo_mode && #endif ((error_in_archive = find_ecrec(MIN(ziplen,66000L))) != 0 || (error_in_archive = uz_end_central()) > PK_WARN))) { close(zipfd); #ifdef SFX ++lastchance; /* avoid picky compiler warnings */ return error_in_archive; #else if (maybe_exe) FPRINTF(stderr, LoadFarString(MaybeExe), zipfn); if (lastchance) return error_in_archive; else { no_ecrec = TRUE; /* assume we found wrong file: e.g., */ return PK_NOZIP; /* unzip instead of unzip.zip */ } #endif /* ?SFX */ } if ((zflag > 0) && !zipinfo_mode) { /* in unzip, zflag = comment ONLY */ close(zipfd); return error_in_archive; } /*--------------------------------------------------------------------------- Test the end-of-central-directory info for incompatibilities (multi-disk archives) or inconsistencies (missing or extra bytes in zipfile). ---------------------------------------------------------------------------*/ #ifdef NO_MULTIPART error = !zipinfo_mode && (ecrec.number_this_disk == 1) && (ecrec.num_disk_with_start_central_dir == 1); #else error = !zipinfo_mode && (ecrec.number_this_disk != 0); #endif #ifndef SFX if (zipinfo_mode && ecrec.number_this_disk != ecrec.num_disk_with_start_central_dir) { FPRINTF(stderr, LoadFarString(CentDirNotInZipMsg)); error_in_archive = PK_FIND; #ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */ } else if (!zipinfo_mode && !error && ecrec.number_this_disk != 0) { FPRINTF(stderr, LoadFarString(NoMultiDiskArcSupport), zipfn); error_in_archive = PK_FIND; #endif } else { /* this is a (relatively) normal zipfile: process normally */ if (error) { FPRINTF(stderr, LoadFarString(MaybePakBug), zipfn); error_in_archive = PK_WARN; } #endif if ((extra_bytes = real_ecrec_offset-expect_ecrec_offset) < (LONGINT)0) { FPRINTF(stderr, LoadFarString(MissingBytes), zipfn, (long)(-extra_bytes)); error_in_archive = PK_ERR; } else if (extra_bytes > 0) { if ((ecrec.offset_start_central_directory == 0) && (ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */ { FPRINTF(stderr, LoadFarString(NullCentDirOffset), zipfn); ecrec.offset_start_central_directory = extra_bytes; extra_bytes = 0; error_in_archive = PK_ERR; } #ifndef SFX else { FPRINTF(stderr, LoadFarString(ExtraBytesAtStart), zipfn, (long)extra_bytes); error_in_archive = PK_WARN; } #endif } /*----------------------------------------------------------------------- Check for empty zipfile and exit now if so. -----------------------------------------------------------------------*/ if (expect_ecrec_offset == 0L && ecrec.size_central_directory == 0) { if (zipinfo_mode) PRINTF("%sEmpty zipfile.\n", lflag>9 ? "\n " : ""); else FPRINTF(stderr, LoadFarString(ZipfileEmpty), zipfn); close(zipfd); return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN; } /*----------------------------------------------------------------------- Compensate for missing or extra bytes, and seek to where the start of central directory should be. If header not found, uncompensate and try again (necessary for at least some Atari archives created with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1). -----------------------------------------------------------------------*/ LSEEK( ecrec.offset_start_central_directory ) #ifdef OLD_SEEK_TEST if (readbuf(sig, 4) == 0) { close(zipfd); return PK_ERR; /* file may be locked, or possibly disk error(?) */ } if (strncmp(sig, central_hdr_sig, 4)) #else if ((readbuf(sig, 4) == 0) || strncmp(sig, central_hdr_sig, 4)) #endif { long tmp = extra_bytes; extra_bytes = 0; LSEEK( ecrec.offset_start_central_directory ) if ((readbuf(sig, 4) == 0) || strncmp(sig, central_hdr_sig, 4)) { FPRINTF(stderr, LoadFarString(CentDirStartNotFound), zipfn, LoadFarStringSmall(ReportMsg)); close(zipfd); return PK_BADERR; } FPRINTF(stderr, LoadFarString(CentDirTooLong), zipfn, -tmp); error_in_archive = PK_ERR; } /*----------------------------------------------------------------------- Seek to the start of the central directory one last time, since we have just read the first entry's signature bytes; then list, extract or test member files as instructed, and close the zipfile. -----------------------------------------------------------------------*/ Trace((stderr, "about to extract/list files (error = %d)\n", error_in_archive)); LSEEK( ecrec.offset_start_central_directory ) #ifndef NO_ZIPINFO if (zipinfo_mode) { error = zipinfo(); /* ZIPINFO 'EM */ if (lflag > 9) PRINTF("\n"); } else #endif #ifndef SFX if (vflag && !tflag && !cflag) error = list_files(); /* LIST 'EM */ else #endif error = extract_or_test_files(); /* EXTRACT OR TEST 'EM */ Trace((stderr, "done with extract/list files (error = %d)\n", error)); if (error > error_in_archive) /* don't overwrite stronger error */ error_in_archive = error; /* with (for example) a warning */ #ifndef SFX } #endif close(zipfd); return error_in_archive; } /* end function do_seekable() */ /*****************************/ /* Function uz_end_central() */ /*****************************/ int uz_end_central() /* return PK-type error code */ { int error = PK_COOL; /*--------------------------------------------------------------------------- Get the zipfile comment (up to 64KB long), if any, and print it out. Then position the file pointer to the beginning of the central directory and fill buffer. ---------------------------------------------------------------------------*/ #ifdef MSWIN cchComment = ecrec.zipfile_comment_length; /* save for comment button */ if (ecrec.zipfile_comment_length && (zflag > 0)) #else if (ecrec.zipfile_comment_length && (zflag > 0 || (zflag == 0 && !qflag))) #endif { #if 0 #ifndef MSWIN if (zflag == 0) (add "&& single_zipfile" perhaps; unnecessary with PRINTF("[%s] comment:\n", zipfn); multiple zipfiles: "Archive:...") #endif /* !MSWIN */ #endif /* 0 */ if (do_string(ecrec.zipfile_comment_length,DISPLAY)) { FPRINTF(stderr, LoadFarString(ZipfileCommTrunc1)); error = PK_WARN; } } return error; } /* end function uz_end_central() */ /************************************/ /* Function process_cdir_file_hdr() */ /************************************/ int process_cdir_file_hdr() /* return PK-type error code */ { int error; /*--------------------------------------------------------------------------- Get central directory info, save host and method numbers, and set flag for lowercase conversion of filename, depending on the OS from which the file is coming. ---------------------------------------------------------------------------*/ if ((error = get_cdir_ent()) != 0) return error; pInfo->hostnum = MIN(crec.version_made_by[1], NUM_HOSTS); /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */ pInfo->lcflag = 0; if (L_flag) /* user specified case-conversion */ switch (pInfo->hostnum) { case FS_FAT_: /* PKZIP and zip -k store in uppercase */ case ATARI_: /* MS-DOS filesystem */ case CPM_: /* like MS-DOS, right? */ case VM_CMS_: /* all caps? */ case TOPS20_: case VMS_: /* our Zip uses lowercase, but ASi's doesn't */ /* case Z_SYSTEM_: ? */ /* case QDOS_: ? */ pInfo->lcflag = 1; /* convert filename to lowercase */ break; default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, */ break; /* (Z_SYSTEM_): no conversion */ } /* do Amigas (AMIGA_) also have volume labels? */ if (IS_VOLID(crec.external_file_attributes) && (pInfo->hostnum == FS_FAT_ || pInfo->hostnum == FS_HPFS_ || pInfo->hostnum == FS_NTFS_ || pInfo->hostnum == ATARI_)) { pInfo->vollabel = TRUE; pInfo->lcflag = 0; /* preserve case of volume labels */ } else pInfo->vollabel = FALSE; return PK_COOL; } /* end function process_cdir_file_hdr() */ /*************************************/ /* Function process_local_file_hdr() */ /*************************************/ int process_local_file_hdr() /* return PK-type error code */ { local_byte_hdr byterec; /*--------------------------------------------------------------------------- Read the next local file header and do any necessary machine-type con- versions (byte ordering, structure padding compensation--do so by copy- ing the data from the array into which it was read (byterec) to the usable struct (lrec)). ---------------------------------------------------------------------------*/ if (readbuf((char *)byterec, LREC_SIZE) == 0) return PK_EOF; lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0]; lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1]; lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]); lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]); lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]); lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]); lrec.crc32 = makelong(&byterec[L_CRC32]); lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]); lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]); lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]); lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]); csize = (long) lrec.csize; ucsize = (long) lrec.ucsize; if ((lrec.general_purpose_bit_flag & 8) != 0) { /* can't trust local header, use central directory: */ lrec.crc32 = pInfo->crc; csize = (long)(lrec.csize = pInfo->compr_size); } return PK_COOL; } /* end function process_local_file_hdr() */