1/*
2  Copyright (c) 1990-2001 Info-ZIP.  All rights reserved.
3
4  See the accompanying file LICENSE, version 2000-Apr-09 or later
5  (the contents of which are also included in unzip.h) for terms of use.
6  If, for some reason, all these files are missing, the Info-ZIP license
7  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8*/
9/*---------------------------------------------------------------------------
10
11  process.c
12
13  This file contains the top-level routines for processing multiple zipfiles.
14
15  Contains:  process_zipfiles()
16             free_G_buffers()
17             do_seekable()
18             find_ecrec()
19             uz_end_central()
20             process_cdir_file_hdr()
21             get_cdir_ent()
22             process_local_file_hdr()
23             ef_scan_for_izux()
24             getRISCOSexfield()
25
26  ---------------------------------------------------------------------------*/
27
28
29#define UNZIP_INTERNAL
30#include "unzip.h"
31#ifdef WINDLL
32#  ifdef POCKET_UNZIP
33#    include "wince/intrface.h"
34#  else
35#    include "windll/windll.h"
36#  endif
37#endif
38
39static int    do_seekable        OF((__GPRO__ int lastchance));
40static int    find_ecrec         OF((__GPRO__ long searchlen));
41
42static ZCONST char Far CannotAllocateBuffers[] =
43  "error:  cannot allocate unzip buffers\n";
44
45#ifdef SFX
46   static ZCONST char Far CannotFindMyself[] =
47     "unzipsfx:  cannot find myself! [%s]\n";
48# ifdef CHEAP_SFX_AUTORUN
49   static ZCONST char Far AutorunPrompt[] =
50     "\nAuto-run command: %s\nExecute this command? [y/n] ";
51   static ZCONST char Far NotAutoRunning[] =
52     "Not executing auto-run command.";
53# endif
54
55#else /* !SFX */
56   /* process_zipfiles() strings */
57# if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
58     static ZCONST char Far WarnInvalidTZ[] =
59       "Warning: TZ environment variable not found, cannot use UTC times!!\n";
60# endif
61   static ZCONST char Far FilesProcessOK[] =
62     "%d archive%s successfully processed.\n";
63   static ZCONST char Far ArchiveWarning[] =
64     "%d archive%s had warnings but no fatal errors.\n";
65   static ZCONST char Far ArchiveFatalError[] =
66     "%d archive%s had fatal errors.\n";
67   static ZCONST char Far FileHadNoZipfileDir[] =
68     "%d file%s had no zipfile directory.\n";
69   static ZCONST char Far ZipfileWasDir[] = "1 \"zipfile\" was a directory.\n";
70   static ZCONST char Far ManyZipfilesWereDir[] =
71     "%d \"zipfiles\" were directories.\n";
72   static ZCONST char Far NoZipfileFound[] = "No zipfiles found.\n";
73
74   /* do_seekable() strings */
75# ifdef UNIX
76   static ZCONST char Far CannotFindZipfileDirMsg[] =
77     "%s:  cannot find zipfile directory in one of %s or\n\
78        %s%s.zip, and cannot find %s, period.\n";
79   static ZCONST char Far CannotFindEitherZipfile[] =
80     "%s:  cannot find %s, %s.zip or %s.\n";
81# else /* !UNIX */
82# ifndef AMIGA
83   static ZCONST char Far CannotFindWildcardMatch[] =
84     "%s:  cannot find any matches for wildcard specification \"%s\".\n";
85# endif /* !AMIGA */
86   static ZCONST char Far CannotFindZipfileDirMsg[] =
87     "%s:  cannot find zipfile directory in %s,\n\
88        %sand cannot find %s, period.\n";
89   static ZCONST char Far CannotFindEitherZipfile[] =
90     "%s:  cannot find either %s or %s.\n";
91# endif /* ?UNIX */
92   extern ZCONST char Far Zipnfo[];       /* in unzip.c */
93#ifndef WINDLL
94   static ZCONST char Far Unzip[] = "unzip";
95#else
96   static ZCONST char Far Unzip[] = "UnZip DLL";
97#endif
98   static ZCONST char Far MaybeExe[] =
99     "note:  %s may be a plain executable, not an archive\n";
100   static ZCONST char Far CentDirNotInZipMsg[] = "\n\
101   [%s]:\n\
102     Zipfile is disk %u of a multi-disk archive, and this is not the disk on\n\
103     which the central zipfile directory begins (disk %u).\n";
104   static ZCONST char Far EndCentDirBogus[] =
105     "\nwarning [%s]:  end-of-central-directory record claims this\n\
106  is disk %u but that the central directory starts on disk %u; this is a\n\
107  contradiction.  Attempting to process anyway.\n";
108# ifdef NO_MULTIPART
109   static ZCONST char Far NoMultiDiskArcSupport[] =
110     "\nerror [%s]:  zipfile is part of multi-disk archive\n\
111  (sorry, not yet supported).\n";
112   static ZCONST char Far MaybePakBug[] = "warning [%s]:\
113  zipfile claims to be 2nd disk of a 2-part archive;\n\
114  attempting to process anyway.  If no further errors occur, this archive\n\
115  was probably created by PAK v2.51 or earlier.  This bug was reported to\n\
116  NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\
117  of mid-1992 it still hadn't been.  (If further errors do occur, archive\n\
118  was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\
119  multi-part archives.)\n";
120# else
121   static ZCONST char Far MaybePakBug[] = "warning [%s]:\
122  zipfile claims to be last disk of a multi-part archive;\n\
123  attempting to process anyway, assuming all parts have been concatenated\n\
124  together in order.  Expect \"errors\" and warnings...true multi-part support\
125\n  doesn't exist yet (coming soon).\n";
126# endif
127   static ZCONST char Far ExtraBytesAtStart[] =
128     "warning [%s]:  %ld extra byte%s at beginning or within zipfile\n\
129  (attempting to process anyway)\n";
130#endif /* ?SFX */
131
132static ZCONST char Far MissingBytes[] =
133  "error [%s]:  missing %ld bytes in zipfile\n\
134  (attempting to process anyway)\n";
135static ZCONST char Far NullCentDirOffset[] =
136  "error [%s]:  NULL central directory offset\n\
137  (attempting to process anyway)\n";
138static ZCONST char Far ZipfileEmpty[] = "warning [%s]:  zipfile is empty\n";
139static ZCONST char Far CentDirStartNotFound[] =
140  "error [%s]:  start of central directory not found;\n\
141  zipfile corrupt.\n%s";
142#ifndef SFX
143   static ZCONST char Far CentDirTooLong[] =
144     "error [%s]:  reported length of central directory is\n\
145  %ld bytes too long (Atari STZip zipfile?  J.H.Holm ZIPSPLIT 1.1\n\
146  zipfile?).  Compensating...\n";
147   static ZCONST char Far CentDirEndSigNotFound[] = "\
148  End-of-central-directory signature not found.  Either this file is not\n\
149  a zipfile, or it constitutes one disk of a multi-part archive.  In the\n\
150  latter case the central directory and zipfile comment will be found on\n\
151  the last disk(s) of this archive.\n";
152#else /* SFX */
153   static ZCONST char Far CentDirEndSigNotFound[] =
154     "  End-of-central-directory signature not found.\n";
155#endif /* ?SFX */
156static ZCONST char Far ZipfileCommTrunc1[] =
157  "\ncaution:  zipfile comment truncated\n";
158
159
160
161
162/*******************************/
163/* Function process_zipfiles() */
164/*******************************/
165
166int process_zipfiles(__G)    /* return PK-type error code */
167    __GDEF
168{
169#ifndef SFX
170    char *lastzipfn = (char *)NULL;
171    int NumWinFiles, NumLoseFiles, NumWarnFiles;
172    int NumMissDirs, NumMissFiles;
173#endif
174    int error=0, error_in_archive=0;
175
176
177/*---------------------------------------------------------------------------
178    Start by allocating buffers and (re)constructing the various PK signature
179    strings.
180  ---------------------------------------------------------------------------*/
181
182    G.inbuf = (uch *)malloc(INBUFSIZ + 4);    /* 4 extra for hold[] (below) */
183    G.outbuf = (uch *)malloc(OUTBUFSIZ + 1);  /* 1 extra for string term. */
184
185    if ((G.inbuf == (uch *)NULL) || (G.outbuf == (uch *)NULL)) {
186        Info(slide, 0x401, ((char *)slide,
187          LoadFarString(CannotAllocateBuffers)));
188        return(PK_MEM);
189    }
190    G.hold = G.inbuf + INBUFSIZ;     /* to check for boundary-spanning sigs */
191#ifndef VMS     /* VMS uses its own buffer scheme for textmode flush(). */
192#ifdef SMALL_MEM
193    G.outbuf2 = G.outbuf+RAWBUFSIZ;  /* never changes */
194#endif
195#endif /* !VMS */
196
197#if 0 /* CRC_32_TAB has been NULLified by CONSTRUCTGLOBALS !!!! */
198    /* allocate the CRC table only later when we know we have a zipfile */
199    CRC_32_TAB = NULL;
200#endif /* 0 */
201
202    /* finish up initialization of magic signature strings */
203    local_hdr_sig[0]  /* = extd_local_sig[0] */ =       /* ASCII 'P', */
204      central_hdr_sig[0] = end_central_sig[0] = 0x50;   /* not EBCDIC */
205
206    local_hdr_sig[1]  /* = extd_local_sig[1] */ =       /* ASCII 'K', */
207      central_hdr_sig[1] = end_central_sig[1] = 0x4B;   /* not EBCDIC */
208
209/*---------------------------------------------------------------------------
210    Make sure timezone info is set correctly; localtime() returns GMT on
211    some OSes (e.g., Solaris 2.x) if this isn't done first.  The ifdefs were
212    initially copied from dos_to_unix_time() in fileio.c. probably, they are
213    still too strict; any listed OS that supplies tzset(), regardless of
214    whether the function does anything, should be removed from the ifdefs.
215  ---------------------------------------------------------------------------*/
216
217#if (defined(WIN32) && defined(USE_EF_UT_TIME))
218    /* For the Win32 environment, we may have to "prepare" the environment
219       prior to the tzset() call, to work around tzset() implementation bugs.
220     */
221    iz_w32_prepareTZenv();
222#endif
223
224#if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
225#  ifndef VALID_TIMEZONE
226#     define VALID_TIMEZONE(tmp) \
227             (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0'))
228#  endif
229    {
230        char *p;
231        G.tz_is_valid = VALID_TIMEZONE(p);
232#  ifndef SFX
233        if (!G.tz_is_valid) {
234            Info(slide, 0x401, ((char *)slide, LoadFarString(WarnInvalidTZ)));
235            error_in_archive = error = PK_WARN;
236        }
237#  endif /* !SFX */
238    }
239#endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
240
241/* For systems that do not have tzset() but supply this function using another
242   name (_tzset() or something similar), an appropiate "#define tzset ..."
243   should be added to the system specifc configuration section.  */
244#if (!defined(T20_VMS) && !defined(MACOS) && !defined(RISCOS) && !defined(QDOS))
245#if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM))
246    tzset();
247#endif
248#endif
249
250/*---------------------------------------------------------------------------
251    Initialize the internal flag holding the mode of processing "overwrite
252    existing file" cases.  We do not use the calling interface flags directly
253    because the overwrite mode may be changed by user interaction while
254    processing archive files.  Such a change should not affect the option
255    settings as passed through the DLL calling interface.
256    In case of conflicting options, the 'safer' flag uO.overwrite_none takes
257    precedence.
258  ---------------------------------------------------------------------------*/
259    G.overwrite_mode = (uO.overwrite_none ? OVERWRT_NEVER :
260                        (uO.overwrite_all ? OVERWRT_ALWAYS : OVERWRT_QUERY));
261
262/*---------------------------------------------------------------------------
263    Match (possible) wildcard zipfile specification with existing files and
264    attempt to process each.  If no hits, try again after appending ".zip"
265    suffix.  If still no luck, give up.
266  ---------------------------------------------------------------------------*/
267
268#ifdef SFX
269    if ((error = do_seekable(__G__ 0)) == PK_NOZIP) {
270#ifdef EXE_EXTENSION
271        int len=strlen(G.argv0);
272
273        /* append .exe if appropriate; also .sfx? */
274        if ( (G.zipfn = (char *)malloc(len+sizeof(EXE_EXTENSION))) !=
275             (char *)NULL ) {
276            strcpy(G.zipfn, G.argv0);
277            strcpy(G.zipfn+len, EXE_EXTENSION);
278            error = do_seekable(__G__ 0);
279            free(G.zipfn);
280            G.zipfn = G.argv0;  /* for "cannot find myself" message only */
281        }
282#endif /* EXE_EXTENSION */
283#ifdef WIN32
284        G.zipfn = G.argv0;  /* for "cannot find myself" message only */
285#endif
286    }
287    if (error) {
288        if (error == IZ_DIR)
289            error_in_archive = PK_NOZIP;
290        else
291            error_in_archive = error;
292        if (error == PK_NOZIP)
293            Info(slide, 1, ((char *)slide, LoadFarString(CannotFindMyself),
294              G.zipfn));
295    }
296#ifdef CHEAP_SFX_AUTORUN
297    if (G.autorun_command[0] && !uO.qflag) { /* NO autorun without prompt! */
298        Info(slide, 0x81, ((char *)slide, LoadFarString(AutorunPrompt),
299                      FnFilter1(G.autorun_command)));
300        if (fgets(G.answerbuf, 9, stdin) != (char *)NULL
301            && toupper(*G.answerbuf) == 'Y')
302            system(G.autorun_command);
303        else
304            Info(slide, 1, ((char *)slide, LoadFarString(NotAutoRunning)));
305    }
306#endif /* CHEAP_SFX_AUTORUN */
307
308#else /* !SFX */
309    NumWinFiles = NumLoseFiles = NumWarnFiles = 0;
310    NumMissDirs = NumMissFiles = 0;
311
312    while ((G.zipfn = do_wild(__G__ G.wildzipfn)) != (char *)NULL) {
313        Trace((stderr, "do_wild( %s ) returns %s\n", G.wildzipfn, G.zipfn));
314
315        lastzipfn = G.zipfn;
316
317        /* print a blank line between the output of different zipfiles */
318        if (!uO.qflag  &&  error != PK_NOZIP  &&  error != IZ_DIR
319#ifdef TIMESTAMP
320            && (!uO.T_flag || uO.zipinfo_mode)
321#endif
322            && (NumWinFiles+NumLoseFiles+NumWarnFiles+NumMissFiles) > 0)
323            (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0);
324
325        if ((error = do_seekable(__G__ 0)) == PK_WARN)
326            ++NumWarnFiles;
327        else if (error == IZ_DIR)
328            ++NumMissDirs;
329        else if (error == PK_NOZIP)
330            ++NumMissFiles;
331        else if (error)
332            ++NumLoseFiles;
333        else
334            ++NumWinFiles;
335
336        Trace((stderr, "do_seekable(0) returns %d\n", error));
337        if (error != IZ_DIR && error > error_in_archive)
338            error_in_archive = error;
339#ifdef WINDLL
340        if (error == IZ_CTRLC) {
341            free_G_buffers(__G);
342            return error;
343        }
344#endif
345
346    } /* end while-loop (wildcard zipfiles) */
347
348    if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0  &&
349        (NumMissDirs + NumMissFiles) == 1  &&  lastzipfn != (char *)NULL)
350    {
351        NumMissDirs = NumMissFiles = 0;
352        if (error_in_archive == PK_NOZIP)
353            error_in_archive = PK_COOL;
354
355#if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */
356        if (iswild(G.wildzipfn))
357            Info(slide, 0x401, ((char *)slide,
358              LoadFarString(CannotFindWildcardMatch), uO.zipinfo_mode?
359              LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
360              G.wildzipfn));
361        else
362#endif
363        {
364            char *p = lastzipfn + strlen(lastzipfn);
365
366            G.zipfn = lastzipfn;
367            strcpy(p, ZSUFX);
368
369#if defined(UNIX) || defined(QDOS)
370   /* only Unix has case-sensitive filesystems */
371   /* Well FlexOS (sometimes) also has them,  but support is per media */
372   /* and a pig to code for,  so treat as case insensitive for now */
373   /* we do this under QDOS to check for .zip as well as _zip */
374            if ((error = do_seekable(__G__ 0)) == PK_NOZIP || error == IZ_DIR) {
375                if (error == IZ_DIR)
376                    ++NumMissDirs;
377                strcpy(p, ALT_ZSUFX);
378                error = do_seekable(__G__ 1);
379            }
380#else
381            error = do_seekable(__G__ 1);
382#endif
383            Trace((stderr, "do_seekable(1) returns %d\n", error));
384            switch (error) {
385              case PK_WARN:
386                ++NumWarnFiles;
387                break;
388              case IZ_DIR:
389                ++NumMissDirs;
390                error = PK_NOZIP;
391                break;
392              case PK_NOZIP:
393                /* increment again => bug:
394                   "1 file had no zipfile directory." */
395                /* ++NumMissFiles */ ;
396                break;
397              default:
398                if (error)
399                    ++NumLoseFiles;
400                else
401                    ++NumWinFiles;
402                break;
403            }
404
405            if (error > error_in_archive)
406                error_in_archive = error;
407#ifdef WINDLL
408            if (error == IZ_CTRLC) {
409                free_G_buffers(__G);
410                return error;
411            }
412#endif
413        }
414    }
415#endif /* ?SFX */
416
417/*---------------------------------------------------------------------------
418    Print summary of all zipfiles, assuming zipfile spec was a wildcard (no
419    need for a summary if just one zipfile).
420  ---------------------------------------------------------------------------*/
421
422#ifndef SFX
423    if (iswild(G.wildzipfn) && uO.qflag < 3
424#ifdef TIMESTAMP
425        && !(uO.T_flag && uO.qflag && !uO.zipinfo_mode)
426#endif
427                                                    )
428    {
429        if ((NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1)
430#ifdef TIMESTAMP
431            && !(uO.T_flag && !uO.zipinfo_mode)
432#endif
433            && !(uO.tflag && uO.qflag > 1))
434            (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0x401);
435        if ((NumWinFiles > 1) || (NumWinFiles == 1 &&
436            NumMissDirs + NumMissFiles + NumLoseFiles + NumWarnFiles > 0))
437            Info(slide, 0x401, ((char *)slide, LoadFarString(FilesProcessOK),
438              NumWinFiles, (NumWinFiles == 1)? " was" : "s were"));
439        if (NumWarnFiles > 0)
440            Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveWarning),
441              NumWarnFiles, (NumWarnFiles == 1)? "" : "s"));
442        if (NumLoseFiles > 0)
443            Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveFatalError),
444              NumLoseFiles, (NumLoseFiles == 1)? "" : "s"));
445        if (NumMissFiles > 0)
446            Info(slide, 0x401, ((char *)slide,
447              LoadFarString(FileHadNoZipfileDir), NumMissFiles,
448              (NumMissFiles == 1)? "" : "s"));
449        if (NumMissDirs == 1)
450            Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileWasDir)));
451        else if (NumMissDirs > 0)
452            Info(slide, 0x401, ((char *)slide,
453              LoadFarString(ManyZipfilesWereDir), NumMissDirs));
454        if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0)
455            Info(slide, 0x401, ((char *)slide, LoadFarString(NoZipfileFound)));
456    }
457#endif /* !SFX */
458
459    /* free allocated memory */
460    free_G_buffers(__G);
461
462    return error_in_archive;
463
464} /* end function process_zipfiles() */
465
466
467
468
469
470/*****************************/
471/* Function free_G_buffers() */
472/*****************************/
473
474void free_G_buffers(__G)     /* releases all memory allocated in global vars */
475    __GDEF
476{
477    inflate_free(__G);
478    checkdir(__G__ (char *)NULL, END);
479
480#ifdef DYNALLOC_CRCTAB
481    if (CRC_32_TAB) {
482        free_crc_table();
483        CRC_32_TAB = NULL;
484    }
485#endif
486
487   if (G.key != (char *)NULL) {
488        free(G.key);
489        G.key = (char *)NULL;
490   }
491
492   if (G.extra_field != (uch *)NULL) {
493        free(G.extra_field);
494        G.extra_field = (uch *)NULL;
495   }
496
497#if (!defined(VMS) && !defined(SMALL_MEM))
498    /* VMS uses its own buffer scheme for textmode flush() */
499    if (G.outbuf2) {
500        free(G.outbuf2);   /* malloc'd ONLY if unshrink and -a */
501        G.outbuf2 = (uch *)NULL;
502    }
503#endif
504
505    if (G.outbuf)
506        free(G.outbuf);
507    if (G.inbuf)
508        free(G.inbuf);
509    G.inbuf = G.outbuf = (uch *)NULL;
510
511#ifdef MALLOC_WORK
512    if (G.area.Slide) {
513        free(G.area.Slide);
514        G.area.Slide = (uch *)NULL;
515    }
516#endif
517
518} /* end function free_G_buffers() */
519
520
521
522
523
524/**************************/
525/* Function do_seekable() */
526/**************************/
527
528static int do_seekable(__G__ lastchance)        /* return PK-type error code */
529    __GDEF
530    int lastchance;
531{
532#ifndef SFX
533    /* static int no_ecrec = FALSE;  SKM: moved to globals.h */
534    int maybe_exe=FALSE;
535    int too_weird_to_continue=FALSE;
536#ifdef TIMESTAMP
537    time_t uxstamp;
538    ulg nmember = 0L;
539#endif
540#endif
541    int error=0, error_in_archive;
542
543
544/*---------------------------------------------------------------------------
545    Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
546    which would corrupt the bit streams.
547  ---------------------------------------------------------------------------*/
548
549    if (SSTAT(G.zipfn, &G.statbuf) ||
550#ifdef THEOS
551        (error = S_ISLIB(G.statbuf.st_mode)) != 0 ||
552#endif
553        (error = S_ISDIR(G.statbuf.st_mode)) != 0)
554    {
555#ifndef SFX
556        if (lastchance && (uO.qflag < 3)) {
557#if defined(UNIX) || defined(QDOS)
558            if (G.no_ecrec)
559                Info(slide, 1, ((char *)slide,
560                  LoadFarString(CannotFindZipfileDirMsg), uO.zipinfo_mode?
561                  LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
562                  G.wildzipfn, uO.zipinfo_mode? "  " : "", G.wildzipfn,
563                  G.zipfn));
564            else
565                Info(slide, 1, ((char *)slide,
566                  LoadFarString(CannotFindEitherZipfile), uO.zipinfo_mode?
567                  LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
568                  G.wildzipfn, G.wildzipfn, G.zipfn));
569#else /* !(UNIX || QDOS) */
570            if (G.no_ecrec)
571                Info(slide, 0x401, ((char *)slide,
572                  LoadFarString(CannotFindZipfileDirMsg), uO.zipinfo_mode?
573                  LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
574                  G.wildzipfn, uO.zipinfo_mode? "  " : "", G.zipfn));
575            else
576                Info(slide, 0x401, ((char *)slide,
577                  LoadFarString(CannotFindEitherZipfile), uO.zipinfo_mode?
578                  LoadFarStringSmall(Zipnfo) : LoadFarStringSmall(Unzip),
579                  G.wildzipfn, G.zipfn));
580#endif /* ?(UNIX || QDOS) */
581        }
582#endif /* !SFX */
583        return error? IZ_DIR : PK_NOZIP;
584    }
585    G.ziplen = G.statbuf.st_size;
586
587#ifndef SFX
588#if defined(UNIX) || defined(DOS_OS2_W32) || defined(THEOS)
589    if (G.statbuf.st_mode & S_IEXEC)   /* no extension on Unix exes:  might */
590        maybe_exe = TRUE;               /*  find unzip, not unzip.zip; etc. */
591#endif
592#endif /* !SFX */
593
594#ifdef VMS
595    if (check_format(__G))              /* check for variable-length format */
596        return PK_ERR;
597#endif
598
599    if (open_input_file(__G))   /* this should never happen, given */
600        return PK_NOZIP;        /*  the stat() test above, but... */
601
602/*---------------------------------------------------------------------------
603    Find and process the end-of-central-directory header.  UnZip need only
604    check last 65557 bytes of zipfile:  comment may be up to 65535, end-of-
605    central-directory record is 18 bytes, and signature itself is 4 bytes;
606    add some to allow for appended garbage.  Since ZipInfo is often used as
607    a debugging tool, search the whole zipfile if zipinfo_mode is true.
608  ---------------------------------------------------------------------------*/
609
610    /* initialize the CRC table pointer (once) */
611    if (CRC_32_TAB == NULL) {
612        if ((CRC_32_TAB = get_crc_table()) == NULL) {
613            CLOSE_INFILE();
614            return PK_MEM;
615        }
616    }
617
618#if (!defined(SFX) || defined(SFX_EXDIR))
619    /* check out if specified extraction root directory exists */
620    if (uO.exdir != (char *)NULL && G.extract_flag) {
621        G.create_dirs = !uO.fflag;
622        if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) {
623            /* out of memory, or file in way */
624            CLOSE_INFILE();
625            return (error == MPN_NOMEM ? PK_MEM : PK_ERR);
626        }
627    }
628#endif /* !SFX || SFX_EXDIR */
629
630    G.cur_zipfile_bufstart = 0;
631    G.inptr = G.inbuf;
632
633#if (!defined(WINDLL) && !defined(SFX))
634#ifdef TIMESTAMP
635    if (!uO.zipinfo_mode && !uO.qflag && !uO.T_flag)
636#else
637    if (!uO.zipinfo_mode && !uO.qflag)
638#endif
639#ifdef WIN32    /* Win32 console may require codepage conversion for G.zipfn */
640        Info(slide, 0, ((char *)slide, "Archive:  %s\n", FnFilter1(G.zipfn)));
641#else
642        Info(slide, 0, ((char *)slide, "Archive:  %s\n", G.zipfn));
643#endif
644#endif /* !WINDLL && !SFX */
645
646    if ((
647#ifndef NO_ZIPINFO
648         uO.zipinfo_mode &&
649          ((error_in_archive = find_ecrec(__G__ G.ziplen)) != 0 ||
650          (error_in_archive = zi_end_central(__G)) > PK_WARN))
651        || (!uO.zipinfo_mode &&
652#endif
653          ((error_in_archive = find_ecrec(__G__ MIN(G.ziplen,66000L))) != 0 ||
654          (error_in_archive = uz_end_central(__G)) > PK_WARN)))
655    {
656        CLOSE_INFILE();
657
658#ifdef SFX
659        ++lastchance;   /* avoid picky compiler warnings */
660        return error_in_archive;
661#else
662        if (maybe_exe)
663            Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeExe),
664            G.zipfn));
665        if (lastchance)
666            return error_in_archive;
667        else {
668            G.no_ecrec = TRUE;    /* assume we found wrong file:  e.g., */
669            return PK_NOZIP;       /*  unzip instead of unzip.zip */
670        }
671#endif /* ?SFX */
672    }
673
674    if ((uO.zflag > 0) && !uO.zipinfo_mode) { /* unzip: zflag = comment ONLY */
675        CLOSE_INFILE();
676        return error_in_archive;
677    }
678
679/*---------------------------------------------------------------------------
680    Test the end-of-central-directory info for incompatibilities (multi-disk
681    archives) or inconsistencies (missing or extra bytes in zipfile).
682  ---------------------------------------------------------------------------*/
683
684#ifdef NO_MULTIPART
685    error = !uO.zipinfo_mode && (G.ecrec.number_this_disk == 1) &&
686            (G.ecrec.num_disk_start_cdir == 1);
687#else
688    error = !uO.zipinfo_mode && (G.ecrec.number_this_disk != 0);
689#endif
690
691#ifndef SFX
692    if (uO.zipinfo_mode &&
693        G.ecrec.number_this_disk != G.ecrec.num_disk_start_cdir)
694    {
695        if (G.ecrec.number_this_disk > G.ecrec.num_disk_start_cdir) {
696            Info(slide, 0x401, ((char *)slide,
697              LoadFarString(CentDirNotInZipMsg), G.zipfn,
698              G.ecrec.number_this_disk, G.ecrec.num_disk_start_cdir));
699            error_in_archive = PK_FIND;
700            too_weird_to_continue = TRUE;
701        } else {
702            Info(slide, 0x401, ((char *)slide,
703              LoadFarString(EndCentDirBogus), G.zipfn,
704              G.ecrec.number_this_disk, G.ecrec.num_disk_start_cdir));
705            error_in_archive = PK_WARN;
706        }
707#ifdef NO_MULTIPART   /* concatenation of multiple parts works in some cases */
708    } else if (!uO.zipinfo_mode && !error && G.ecrec.number_this_disk != 0) {
709        Info(slide, 0x401, ((char *)slide, LoadFarString(NoMultiDiskArcSupport),
710          G.zipfn));
711        error_in_archive = PK_FIND;
712        too_weird_to_continue = TRUE;
713#endif
714    }
715
716    if (!too_weird_to_continue) {  /* (relatively) normal zipfile:  go for it */
717        if (error) {
718            Info(slide, 0x401, ((char *)slide, LoadFarString(MaybePakBug),
719              G.zipfn));
720            error_in_archive = PK_WARN;
721        }
722#endif /* !SFX */
723        if ((G.extra_bytes = G.real_ecrec_offset-G.expect_ecrec_offset) <
724            (LONGINT)0)
725        {
726            Info(slide, 0x401, ((char *)slide, LoadFarString(MissingBytes),
727              G.zipfn, (long)(-G.extra_bytes)));
728            error_in_archive = PK_ERR;
729        } else if (G.extra_bytes > 0) {
730            if ((G.ecrec.offset_start_central_directory == 0) &&
731                (G.ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
732            {
733                Info(slide, 0x401, ((char *)slide,
734                  LoadFarString(NullCentDirOffset), G.zipfn));
735                G.ecrec.offset_start_central_directory = G.extra_bytes;
736                G.extra_bytes = 0;
737                error_in_archive = PK_ERR;
738            }
739#ifndef SFX
740            else {
741                Info(slide, 0x401, ((char *)slide,
742                  LoadFarString(ExtraBytesAtStart), G.zipfn,
743                  (long)G.extra_bytes, (G.extra_bytes == 1)? "":"s"));
744                error_in_archive = PK_WARN;
745            }
746#endif /* !SFX */
747        }
748
749    /*-----------------------------------------------------------------------
750        Check for empty zipfile and exit now if so.
751      -----------------------------------------------------------------------*/
752
753        if (G.expect_ecrec_offset==0L && G.ecrec.size_central_directory==0) {
754            if (uO.zipinfo_mode)
755                Info(slide, 0, ((char *)slide, "%sEmpty zipfile.\n",
756                  uO.lflag>9? "\n  " : ""));
757            else
758                Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileEmpty),
759                                    G.zipfn));
760            CLOSE_INFILE();
761            return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN;
762        }
763
764    /*-----------------------------------------------------------------------
765        Compensate for missing or extra bytes, and seek to where the start
766        of central directory should be.  If header not found, uncompensate
767        and try again (necessary for at least some Atari archives created
768        with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
769      -----------------------------------------------------------------------*/
770
771        error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
772        if (error == PK_BADERR) {
773            CLOSE_INFILE();
774            return PK_BADERR;
775        }
776#ifdef OLD_SEEK_TEST
777        if (error != PK_OK || readbuf(__G__ G.sig, 4) == 0) {
778            CLOSE_INFILE();
779            return PK_ERR;  /* file may be locked, or possibly disk error(?) */
780        }
781        if (strncmp(G.sig, central_hdr_sig, 4))
782#else
783        if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) ||
784            strncmp(G.sig, central_hdr_sig, 4))
785#endif
786        {
787#ifndef SFX
788            long tmp = G.extra_bytes;
789#endif
790
791            G.extra_bytes = 0;
792            error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
793            if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) ||
794                strncmp(G.sig, central_hdr_sig, 4))
795            {
796                if (error != PK_BADERR)
797                  Info(slide, 0x401, ((char *)slide,
798                    LoadFarString(CentDirStartNotFound), G.zipfn,
799                    LoadFarStringSmall(ReportMsg)));
800                CLOSE_INFILE();
801                return (error != PK_OK ? error : PK_BADERR);
802            }
803#ifndef SFX
804            Info(slide, 0x401, ((char *)slide, LoadFarString(CentDirTooLong),
805              G.zipfn, -tmp));
806#endif
807            error_in_archive = PK_ERR;
808        }
809
810    /*-----------------------------------------------------------------------
811        Seek to the start of the central directory one last time, since we
812        have just read the first entry's signature bytes; then list, extract
813        or test member files as instructed, and close the zipfile.
814      -----------------------------------------------------------------------*/
815
816        error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
817        if (error != PK_OK) {
818            CLOSE_INFILE();
819            return error;
820        }
821
822        Trace((stderr, "about to extract/list files (error = %d)\n",
823          error_in_archive));
824
825#ifdef DLL
826        /* G.fValidate is used only to look at an archive to see if
827           it appears to be a valid archive.  There is no interest
828           in what the archive contains, nor in validating that the
829           entries in the archive are in good condition.  This is
830           currently used only in the Windows DLLs for purposes of
831           checking archives within an archive to determine whether
832           or not to display the inner archives.
833         */
834        if (!G.fValidate)
835#endif
836        {
837#ifndef NO_ZIPINFO
838            if (uO.zipinfo_mode)
839                error = zipinfo(__G);                 /* ZIPINFO 'EM */
840            else
841#endif
842#ifndef SFX
843#ifdef TIMESTAMP
844            if (uO.T_flag)
845                error = get_time_stamp(__G__ &uxstamp, &nmember);
846            else
847#endif
848            if (uO.vflag && !uO.tflag && !uO.cflag)
849                error = list_files(__G);              /* LIST 'EM */
850            else
851#endif /* !SFX */
852                error = extract_or_test_files(__G);   /* EXTRACT OR TEST 'EM */
853
854            Trace((stderr, "done with extract/list files (error = %d)\n",
855                   error));
856        }
857
858        if (error > error_in_archive)   /* don't overwrite stronger error */
859            error_in_archive = error;   /*  with (for example) a warning */
860#ifndef SFX
861    } /* end if (!too_weird_to_continue) */
862#endif
863
864    CLOSE_INFILE();
865
866#ifdef TIMESTAMP
867    if (uO.T_flag && !uO.zipinfo_mode && (nmember > 0L)) {
868# ifdef WIN32
869        if (stamp_file(__G__ G.zipfn, uxstamp)) {       /* TIME-STAMP 'EM */
870# else
871        if (stamp_file(G.zipfn, uxstamp)) {             /* TIME-STAMP 'EM */
872# endif
873            if (uO.qflag < 3)
874                Info(slide, 0x201, ((char *)slide,
875                  "warning:  cannot set time for %s\n", G.zipfn));
876            if (error_in_archive < PK_WARN)
877                error_in_archive = PK_WARN;
878        }
879    }
880#endif
881    return error_in_archive;
882
883} /* end function do_seekable() */
884
885
886
887
888
889/*************************/
890/* Function find_ecrec() */
891/*************************/
892
893static int find_ecrec(__G__ searchlen)          /* return PK-class error */
894    __GDEF
895    long searchlen;
896{
897    int i, numblks, found=FALSE;
898    LONGINT tail_len;
899    ec_byte_rec byterec;
900
901
902/*---------------------------------------------------------------------------
903    Treat case of short zipfile separately.
904  ---------------------------------------------------------------------------*/
905
906    if (G.ziplen <= INBUFSIZ) {
907        lseek(G.zipfd, 0L, SEEK_SET);
908        if ((G.incnt = read(G.zipfd,(char *)G.inbuf,(unsigned int)G.ziplen))
909            == (int)G.ziplen)
910
911            /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */
912            for (G.inptr = G.inbuf+(int)G.ziplen-(ECREC_SIZE+4);
913                 G.inptr >= G.inbuf;
914                 --G.inptr) {
915                if ( (*G.inptr == (uch)0x50) &&         /* ASCII 'P' */
916                     !strncmp((char *)G.inptr, end_central_sig, 4)) {
917                    G.incnt -= (int)(G.inptr - G.inbuf);
918                    found = TRUE;
919                    break;
920                }
921            }
922
923/*---------------------------------------------------------------------------
924    Zipfile is longer than INBUFSIZ:  may need to loop.  Start with short
925    block at end of zipfile (if not TOO short).
926  ---------------------------------------------------------------------------*/
927
928    } else {
929        if ((tail_len = G.ziplen % INBUFSIZ) > ECREC_SIZE) {
930#ifdef USE_STRM_INPUT
931            fseek((FILE *)G.zipfd, G.ziplen-tail_len, SEEK_SET);
932            G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd);
933#else /* !USE_STRM_INPUT */
934            G.cur_zipfile_bufstart = lseek(G.zipfd, G.ziplen-tail_len,
935              SEEK_SET);
936#endif /* ?USE_STRM_INPUT */
937            if ((G.incnt = read(G.zipfd, (char *)G.inbuf,
938                (unsigned int)tail_len)) != (int)tail_len)
939                goto fail;      /* it's expedient... */
940
941            /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */
942            for (G.inptr = G.inbuf+(int)tail_len-(ECREC_SIZE+4);
943                 G.inptr >= G.inbuf;
944                 --G.inptr) {
945                if ( (*G.inptr == (uch)0x50) &&         /* ASCII 'P' */
946                     !strncmp((char *)G.inptr, end_central_sig, 4)) {
947                    G.incnt -= (int)(G.inptr - G.inbuf);
948                    found = TRUE;
949                    break;
950                }
951            }
952            /* sig may span block boundary: */
953            memcpy((char *)G.hold, (char *)G.inbuf, 3);
954        } else
955            G.cur_zipfile_bufstart = G.ziplen - tail_len;
956
957    /*-----------------------------------------------------------------------
958        Loop through blocks of zipfile data, starting at the end and going
959        toward the beginning.  In general, need not check whole zipfile for
960        signature, but may want to do so if testing.
961      -----------------------------------------------------------------------*/
962
963        numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
964        /*               ==amount=   ==done==   ==rounding==    =blksiz=  */
965
966        for (i = 1;  !found && (i <= numblks);  ++i) {
967            G.cur_zipfile_bufstart -= INBUFSIZ;
968            lseek(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET);
969            if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ))
970                != INBUFSIZ)
971                break;          /* fall through and fail */
972
973            for (G.inptr = G.inbuf+INBUFSIZ-1;  G.inptr >= G.inbuf;
974                 --G.inptr)
975                if ((native(*G.inptr) == 'P')  &&
976                     !strncmp((char *)G.inptr, end_central_sig, 4)) {
977                    G.incnt -= (int)(G.inptr - G.inbuf);
978                    found = TRUE;
979                    break;
980                }
981            /* sig may span block boundary: */
982            memcpy((char *)G.hold, (char *)G.inbuf, 3);
983        }
984    } /* end if (ziplen > INBUFSIZ) */
985
986/*---------------------------------------------------------------------------
987    Searched through whole region where signature should be without finding
988    it.  Print informational message and die a horrible death.
989  ---------------------------------------------------------------------------*/
990
991fail:
992    if (!found) {
993        if (uO.qflag || uO.zipinfo_mode)
994            Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn));
995        Info(slide, 0x401, ((char *)slide,
996          LoadFarString(CentDirEndSigNotFound)));
997        return PK_ERR;   /* failed */
998    }
999
1000/*---------------------------------------------------------------------------
1001    Found the signature, so get the end-central data before returning.  Do
1002    any necessary machine-type conversions (byte ordering, structure padding
1003    compensation) by reading data into character array and copying to struct.
1004  ---------------------------------------------------------------------------*/
1005
1006    G.real_ecrec_offset = G.cur_zipfile_bufstart + (G.inptr-G.inbuf);
1007#ifdef TEST
1008    printf("\n  found end-of-central-dir signature at offset %ld (%.8lXh)\n",
1009      G.real_ecrec_offset, G.real_ecrec_offset);
1010    printf("    from beginning of file; offset %d (%.4Xh) within block\n",
1011      G.inptr-G.inbuf, G.inptr-G.inbuf);
1012#endif
1013
1014    if (readbuf(__G__ (char *)byterec, ECREC_SIZE+4) == 0)
1015        return PK_EOF;
1016
1017    G.ecrec.number_this_disk =
1018      makeword(&byterec[NUMBER_THIS_DISK]);
1019    G.ecrec.num_disk_start_cdir =
1020      makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
1021    G.ecrec.num_entries_centrl_dir_ths_disk =
1022      makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
1023    G.ecrec.total_entries_central_dir =
1024      makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
1025    G.ecrec.size_central_directory =
1026      makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
1027    G.ecrec.offset_start_central_directory =
1028      makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
1029    G.ecrec.zipfile_comment_length =
1030      makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
1031
1032    G.expect_ecrec_offset = G.ecrec.offset_start_central_directory +
1033                          G.ecrec.size_central_directory;
1034    return PK_COOL;
1035
1036} /* end function find_ecrec() */
1037
1038
1039
1040
1041
1042/*****************************/
1043/* Function uz_end_central() */
1044/*****************************/
1045
1046int uz_end_central(__G)    /* return PK-type error code */
1047    __GDEF
1048{
1049    int error = PK_COOL;
1050
1051
1052/*---------------------------------------------------------------------------
1053    Get the zipfile comment (up to 64KB long), if any, and print it out.
1054    Then position the file pointer to the beginning of the central directory
1055    and fill buffer.
1056  ---------------------------------------------------------------------------*/
1057
1058#ifdef WINDLL
1059    /* for comment button: */
1060    if ((!G.fValidate) && (G.lpUserFunctions != NULL))
1061       G.lpUserFunctions->cchComment = G.ecrec.zipfile_comment_length;
1062    if (G.ecrec.zipfile_comment_length && (uO.zflag > 0))
1063#else /* !WINDLL */
1064    if (G.ecrec.zipfile_comment_length && (uO.zflag > 0 ||
1065        (uO.zflag == 0 &&
1066#ifdef TIMESTAMP
1067                          !uO.T_flag &&
1068#endif
1069                                        !uO.qflag)))
1070#endif /* ?WINDLL */
1071    {
1072#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1073        if (do_string(__G__ G.ecrec.zipfile_comment_length, CHECK_AUTORUN)) {
1074#else
1075        if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) {
1076#endif
1077            Info(slide, 0x401, ((char *)slide,
1078              LoadFarString(ZipfileCommTrunc1)));
1079            error = PK_WARN;
1080        }
1081    }
1082#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1083    else if (G.ecrec.zipfile_comment_length) {
1084        if (do_string(__G__ G.ecrec.zipfile_comment_length, CHECK_AUTORUN_Q)) {
1085            Info(slide, 0x401, ((char *)slide,
1086              LoadFarString(ZipfileCommTrunc1)));
1087            error = PK_WARN;
1088        }
1089    }
1090#endif
1091    return error;
1092
1093} /* end function uz_end_central() */
1094
1095
1096
1097
1098
1099/************************************/
1100/* Function process_cdir_file_hdr() */
1101/************************************/
1102
1103int process_cdir_file_hdr(__G)    /* return PK-type error code */
1104    __GDEF
1105{
1106    int error;
1107
1108
1109/*---------------------------------------------------------------------------
1110    Get central directory info, save host and method numbers, and set flag
1111    for lowercase conversion of filename, depending on the OS from which the
1112    file is coming.
1113  ---------------------------------------------------------------------------*/
1114
1115    if ((error = get_cdir_ent(__G)) != 0)
1116        return error;
1117
1118    G.pInfo->hostver = G.crec.version_made_by[0];
1119    G.pInfo->hostnum = MIN(G.crec.version_made_by[1], NUM_HOSTS);
1120/*  extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
1121
1122    G.pInfo->lcflag = 0;
1123    if (uO.L_flag == 1)       /* name conversion for monocase systems */
1124        switch (G.pInfo->hostnum) {
1125            case FS_FAT_:     /* PKZIP and zip -k store in uppercase */
1126            case CPM_:        /* like MS-DOS, right? */
1127            case VM_CMS_:     /* all caps? */
1128            case MVS_:        /* all caps? */
1129            case TANDEM_:
1130            case TOPS20_:
1131            case VMS_:        /* our Zip uses lowercase, but ASi's doesn't */
1132        /*  case Z_SYSTEM_:   ? */
1133        /*  case QDOS_:       ? */
1134                G.pInfo->lcflag = 1;   /* convert filename to lowercase */
1135                break;
1136
1137            default:     /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */
1138                break;   /*  FS_VFAT_, BEOS_ (Z_SYSTEM_), THEOS_: */
1139                         /*  no conversion */
1140        }
1141    else if (uO.L_flag > 1)   /* let -LL force lower case for all names */
1142        G.pInfo->lcflag = 1;
1143
1144    /* do Amigas (AMIGA_) also have volume labels? */
1145    if (IS_VOLID(G.crec.external_file_attributes) &&
1146        (G.pInfo->hostnum == FS_FAT_ || G.pInfo->hostnum == FS_HPFS_ ||
1147         G.pInfo->hostnum == FS_NTFS_ || G.pInfo->hostnum == ATARI_))
1148    {
1149        G.pInfo->vollabel = TRUE;
1150        G.pInfo->lcflag = 0;        /* preserve case of volume labels */
1151    } else
1152        G.pInfo->vollabel = FALSE;
1153
1154    /* this flag is needed to detect archives made by "PKZIP for Unix" when
1155       deciding which kind of codepage conversion has to be applied to
1156       strings (see do_string() function in fileio.c) */
1157    G.pInfo->HasUxAtt = (G.crec.external_file_attributes & 0xffff0000L) != 0L;
1158
1159    return PK_COOL;
1160
1161} /* end function process_cdir_file_hdr() */
1162
1163
1164
1165
1166
1167/***************************/
1168/* Function get_cdir_ent() */
1169/***************************/
1170
1171int get_cdir_ent(__G)   /* return PK-type error code */
1172    __GDEF
1173{
1174    cdir_byte_hdr byterec;
1175
1176
1177/*---------------------------------------------------------------------------
1178    Read the next central directory entry and do any necessary machine-type
1179    conversions (byte ordering, structure padding compensation--do so by
1180    copying the data from the array into which it was read (byterec) to the
1181    usable struct (crec)).
1182  ---------------------------------------------------------------------------*/
1183
1184    if (readbuf(__G__ (char *)byterec, CREC_SIZE) == 0)
1185        return PK_EOF;
1186
1187    G.crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
1188    G.crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
1189    G.crec.version_needed_to_extract[0] =
1190      byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
1191    G.crec.version_needed_to_extract[1] =
1192      byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
1193
1194    G.crec.general_purpose_bit_flag =
1195      makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
1196    G.crec.compression_method =
1197      makeword(&byterec[C_COMPRESSION_METHOD]);
1198    G.crec.last_mod_dos_datetime =
1199      makelong(&byterec[C_LAST_MOD_DOS_DATETIME]);
1200    G.crec.crc32 =
1201      makelong(&byterec[C_CRC32]);
1202    G.crec.csize =
1203      makelong(&byterec[C_COMPRESSED_SIZE]);
1204    G.crec.ucsize =
1205      makelong(&byterec[C_UNCOMPRESSED_SIZE]);
1206    G.crec.filename_length =
1207      makeword(&byterec[C_FILENAME_LENGTH]);
1208    G.crec.extra_field_length =
1209      makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
1210    G.crec.file_comment_length =
1211      makeword(&byterec[C_FILE_COMMENT_LENGTH]);
1212    G.crec.disk_number_start =
1213      makeword(&byterec[C_DISK_NUMBER_START]);
1214    G.crec.internal_file_attributes =
1215      makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
1216    G.crec.external_file_attributes =
1217      makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]);  /* LONG, not word! */
1218    G.crec.relative_offset_local_header =
1219      makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
1220
1221    return PK_COOL;
1222
1223} /* end function get_cdir_ent() */
1224
1225
1226
1227
1228
1229/*************************************/
1230/* Function process_local_file_hdr() */
1231/*************************************/
1232
1233int process_local_file_hdr(__G)    /* return PK-type error code */
1234    __GDEF
1235{
1236    local_byte_hdr byterec;
1237
1238
1239/*---------------------------------------------------------------------------
1240    Read the next local file header and do any necessary machine-type con-
1241    versions (byte ordering, structure padding compensation--do so by copy-
1242    ing the data from the array into which it was read (byterec) to the
1243    usable struct (lrec)).
1244  ---------------------------------------------------------------------------*/
1245
1246    if (readbuf(__G__ (char *)byterec, LREC_SIZE) == 0)
1247        return PK_EOF;
1248
1249    G.lrec.version_needed_to_extract[0] =
1250      byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
1251    G.lrec.version_needed_to_extract[1] =
1252      byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
1253
1254    G.lrec.general_purpose_bit_flag =
1255      makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
1256    G.lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
1257    G.lrec.last_mod_dos_datetime = makelong(&byterec[L_LAST_MOD_DOS_DATETIME]);
1258    G.lrec.crc32 = makelong(&byterec[L_CRC32]);
1259    G.lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]);
1260    G.lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
1261    G.lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
1262    G.lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
1263
1264    if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
1265        /* can't trust local header, use central directory: */
1266        G.lrec.crc32 = G.pInfo->crc;
1267        G.lrec.csize = G.pInfo->compr_size;
1268        G.lrec.ucsize = G.pInfo->uncompr_size;
1269    }
1270
1271    G.csize = (long)G.lrec.csize;
1272
1273    return PK_COOL;
1274
1275} /* end function process_local_file_hdr() */
1276
1277
1278#ifdef USE_EF_UT_TIME
1279
1280/*******************************/
1281/* Function ef_scan_for_izux() */
1282/*******************************/
1283
1284unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime,
1285                          z_utim, z_uidgid)
1286    ZCONST uch *ef_buf; /* buffer containing extra field */
1287    unsigned ef_len;    /* total length of extra field */
1288    int ef_is_c;        /* flag indicating "is central extra field" */
1289    ulg dos_mdatetime;  /* last_mod_file_date_time in DOS format */
1290    iztimes *z_utim;    /* return storage: atime, mtime, ctime */
1291    ush *z_uidgid;      /* return storage: uid and gid */
1292{
1293    unsigned flags = 0;
1294    unsigned eb_id;
1295    unsigned eb_len;
1296    int have_new_type_eb = FALSE;
1297    long i_time;        /* buffer for Unix style 32-bit integer time value */
1298#ifdef TIME_T_TYPE_DOUBLE
1299    int ut_in_archive_sgn = 0;
1300#else
1301    int ut_zip_unzip_compatible = FALSE;
1302#endif
1303
1304/*---------------------------------------------------------------------------
1305    This function scans the extra field for EF_TIME, EF_IZUNIX2, EF_IZUNIX, or
1306    EF_PKUNIX blocks containing Unix-style time_t (GMT) values for the entry's
1307    access, creation, and modification time.
1308    If a valid block is found, the time stamps are copied to the iztimes
1309    structure (provided the z_utim pointer is not NULL).
1310    If a IZUNIX2 block is found or the IZUNIX block contains UID/GID fields,
1311    and the z_uidgid array pointer is valid (!= NULL), the owner info is
1312    transfered as well.
1313    The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring all
1314    data from probably present obsolete EF_IZUNIX blocks.
1315    If multiple blocks of the same type are found, only the information from
1316    the last block is used.
1317    The return value is a combination of the EF_TIME Flags field with an
1318    additional flag bit indicating the presence of valid UID/GID info,
1319    or 0 in case of failure.
1320  ---------------------------------------------------------------------------*/
1321
1322    if (ef_len == 0 || ef_buf == NULL || (z_utim == 0 && z_uidgid == NULL))
1323        return 0;
1324
1325    TTrace((stderr,"\nef_scan_for_izux: scanning extra field of length %u\n",
1326      ef_len));
1327
1328    while (ef_len >= EB_HEADSIZE) {
1329        eb_id = makeword(EB_ID + ef_buf);
1330        eb_len = makeword(EB_LEN + ef_buf);
1331
1332        if (eb_len > (ef_len - EB_HEADSIZE)) {
1333            /* discovered some extra field inconsistency! */
1334            TTrace((stderr,
1335              "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len,
1336              ef_len - EB_HEADSIZE));
1337            break;
1338        }
1339
1340        switch (eb_id) {
1341          case EF_TIME:
1342            flags &= ~0x0ff;    /* ignore previous IZUNIX or EF_TIME fields */
1343            have_new_type_eb = TRUE;
1344            if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) {
1345                unsigned eb_idx = EB_UT_TIME1;
1346                TTrace((stderr,"ef_scan_for_izux: found TIME extra field\n"));
1347                flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x0ff);
1348                if ((flags & EB_UT_FL_MTIME)) {
1349                    if ((eb_idx+4) <= eb_len) {
1350                        i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf);
1351                        eb_idx += 4;
1352                        TTrace((stderr,"  UT e.f. modification time = %ld\n",
1353                                i_time));
1354
1355#ifdef TIME_T_TYPE_DOUBLE
1356                        if ((ulg)(i_time) & (ulg)(0x80000000L)) {
1357                            if (dos_mdatetime == DOSTIME_MINIMUM) {
1358                              ut_in_archive_sgn = -1;
1359                              z_utim->mtime =
1360                                (time_t)((long)i_time | (~(long)0x7fffffffL));
1361                            } else if (dos_mdatetime >= DOSTIME_2038_01_18) {
1362                              ut_in_archive_sgn = 1;
1363                              z_utim->mtime =
1364                                (time_t)((ulg)i_time & (ulg)0xffffffffL);
1365                            } else {
1366                              ut_in_archive_sgn = 0;
1367                              /* cannot determine sign of mtime;
1368                                 without modtime: ignore complete UT field */
1369                              flags &= ~0x0ff;  /* no time_t times available */
1370                              TTrace((stderr,
1371                                "  UT modtime range error; ignore e.f.!\n"));
1372                              break;            /* stop scanning this field */
1373                            }
1374                        } else {
1375                            /* cannot determine, safe assumption is FALSE */
1376                            ut_in_archive_sgn = 0;
1377                            z_utim->mtime = (time_t)i_time;
1378                        }
1379#else /* !TIME_T_TYPE_DOUBLE */
1380                        if ((ulg)(i_time) & (ulg)(0x80000000L)) {
1381                            ut_zip_unzip_compatible =
1382                              ((time_t)0x80000000L < (time_t)0L)
1383                              ? (dos_mdatetime == DOSTIME_MINIMUM)
1384                              : (dos_mdatetime >= DOSTIME_2038_01_18);
1385                            if (!ut_zip_unzip_compatible) {
1386                              /* UnZip interprets mtime differently than Zip;
1387                                 without modtime: ignore complete UT field */
1388                              flags &= ~0x0ff;  /* no time_t times available */
1389                              TTrace((stderr,
1390                                "  UT modtime range error; ignore e.f.!\n"));
1391                              break;            /* stop scanning this field */
1392                            }
1393                        } else {
1394                            /* cannot determine, safe assumption is FALSE */
1395                            ut_zip_unzip_compatible = FALSE;
1396                        }
1397                        z_utim->mtime = (time_t)i_time;
1398#endif /* ?TIME_T_TYPE_DOUBLE */
1399                    } else {
1400                        flags &= ~EB_UT_FL_MTIME;
1401                        TTrace((stderr,"  UT e.f. truncated; no modtime\n"));
1402                    }
1403                }
1404                if (ef_is_c) {
1405                    break;      /* central version of TIME field ends here */
1406                }
1407
1408                if (flags & EB_UT_FL_ATIME) {
1409                    if ((eb_idx+4) <= eb_len) {
1410                        i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf);
1411                        eb_idx += 4;
1412                        TTrace((stderr,"  UT e.f. access time = %ld\n",
1413                                i_time));
1414#ifdef TIME_T_TYPE_DOUBLE
1415                        if ((ulg)(i_time) & (ulg)(0x80000000L)) {
1416                            if (ut_in_archive_sgn == -1)
1417                              z_utim->atime =
1418                                (time_t)((long)i_time | (~(long)0x7fffffffL));
1419                            } else if (ut_in_archive_sgn == 1) {
1420                              z_utim->atime =
1421                                (time_t)((ulg)i_time & (ulg)0xffffffffL);
1422                            } else {
1423                              /* sign of 32-bit time is unknown -> ignore it */
1424                              flags &= ~EB_UT_FL_ATIME;
1425                              TTrace((stderr,
1426                                "  UT access time range error: skip time!\n"));
1427                            }
1428                        } else {
1429                            z_utim->atime = (time_t)i_time;
1430                        }
1431#else /* !TIME_T_TYPE_DOUBLE */
1432                        if (((ulg)(i_time) & (ulg)(0x80000000L)) &&
1433                            !ut_zip_unzip_compatible) {
1434                            flags &= ~EB_UT_FL_ATIME;
1435                            TTrace((stderr,
1436                              "  UT access time range error: skip time!\n"));
1437                        } else {
1438                            z_utim->atime = (time_t)i_time;
1439                        }
1440#endif /* ?TIME_T_TYPE_DOUBLE */
1441                    } else {
1442                        flags &= ~EB_UT_FL_ATIME;
1443                    }
1444                }
1445                if (flags & EB_UT_FL_CTIME) {
1446                    if ((eb_idx+4) <= eb_len) {
1447                        i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf);
1448                        TTrace((stderr,"  UT e.f. creation time = %ld\n",
1449                                i_time));
1450#ifdef TIME_T_TYPE_DOUBLE
1451                        if ((ulg)(i_time) & (ulg)(0x80000000L)) {
1452                            if (ut_in_archive_sgn == -1)
1453                              z_utim->ctime =
1454                                (time_t)((long)i_time | (~(long)0x7fffffffL));
1455                            } else if (ut_in_archive_sgn == 1) {
1456                              z_utim->ctime =
1457                                (time_t)((ulg)i_time & (ulg)0xffffffffL);
1458                            } else {
1459                              /* sign of 32-bit time is unknown -> ignore it */
1460                              flags &= ~EB_UT_FL_CTIME;
1461                              TTrace((stderr,
1462                              "  UT creation time range error: skip time!\n"));
1463                            }
1464                        } else {
1465                            z_utim->ctime = (time_t)i_time;
1466                        }
1467#else /* !TIME_T_TYPE_DOUBLE */
1468                        if (((ulg)(i_time) & (ulg)(0x80000000L)) &&
1469                            !ut_zip_unzip_compatible) {
1470                            flags &= ~EB_UT_FL_CTIME;
1471                            TTrace((stderr,
1472                              "  UT creation time range error: skip time!\n"));
1473                        } else {
1474                            z_utim->ctime = (time_t)i_time;
1475                        }
1476#endif /* ?TIME_T_TYPE_DOUBLE */
1477                    } else {
1478                        flags &= ~EB_UT_FL_CTIME;
1479                    }
1480                }
1481            }
1482            break;
1483
1484          case EF_IZUNIX2:
1485            if (!have_new_type_eb) {
1486                flags &= ~0x0ff;        /* ignore any previous IZUNIX field */
1487                have_new_type_eb = TRUE;
1488            }
1489            if (eb_len >= EB_UX2_MINLEN && z_uidgid != NULL) {
1490                z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX2_UID) + ef_buf);
1491                z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX2_GID) + ef_buf);
1492                flags |= EB_UX2_VALID;   /* signal success */
1493            }
1494            break;
1495
1496          case EF_IZUNIX:
1497          case EF_PKUNIX:       /* PKUNIX e.f. layout is identical to IZUNIX */
1498            if (eb_len >= EB_UX_MINLEN) {
1499                TTrace((stderr,"ef_scan_for_izux: found %s extra field\n",
1500                        (eb_id == EF_IZUNIX ? "IZUNIX" : "PKUNIX")));
1501                if (have_new_type_eb) {
1502                    break;      /* Ignore IZUNIX extra field block ! */
1503                }
1504                if (z_utim != NULL) {
1505                    flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
1506                    i_time = (long)makelong((EB_HEADSIZE+EB_UX_MTIME)+ef_buf);
1507                    TTrace((stderr,"  Unix EF modtime = %ld\n", i_time));
1508#ifdef TIME_T_TYPE_DOUBLE
1509                    if ((ulg)(i_time) & (ulg)(0x80000000L)) {
1510                        if (dos_mdatetime == DOSTIME_MINIMUM) {
1511                            ut_in_archive_sgn = -1;
1512                            z_utim->mtime =
1513                              (time_t)((long)i_time | (~(long)0x7fffffffL));
1514                        } else if (dos_mdatetime >= DOSTIME_2038_01_18) {
1515                            ut_in_archive_sgn = 1;
1516                            z_utim->mtime =
1517                              (time_t)((ulg)i_time & (ulg)0xffffffffL);
1518                        } else {
1519                            ut_in_archive_sgn = 0;
1520                            /* cannot determine sign of mtime;
1521                               without modtime: ignore complete UT field */
1522                            flags &= ~0x0ff;    /* no time_t times available */
1523                            TTrace((stderr,
1524                                  "  UX modtime range error: ignore e.f.!\n"));
1525                        }
1526                    } else {
1527                        /* cannot determine, safe assumption is FALSE */
1528                        ut_in_archive_sgn = 0;
1529                        z_utim->mtime = (time_t)i_time;
1530                    }
1531#else /* !TIME_T_TYPE_DOUBLE */
1532                    if ((ulg)(i_time) & (ulg)(0x80000000L)) {
1533                        ut_zip_unzip_compatible =
1534                          ((time_t)0x80000000L < (time_t)0L)
1535                          ? (dos_mdatetime == DOSTIME_MINIMUM)
1536                          : (dos_mdatetime >= DOSTIME_2038_01_18);
1537                        if (!ut_zip_unzip_compatible) {
1538                            /* UnZip interpretes mtime differently than Zip;
1539                               without modtime: ignore complete UT field */
1540                            flags &= ~0x0ff;    /* no time_t times available */
1541                            TTrace((stderr,
1542                                  "  UX modtime range error: ignore e.f.!\n"));
1543                        }
1544                    } else {
1545                        /* cannot determine, safe assumption is FALSE */
1546                        ut_zip_unzip_compatible = FALSE;
1547                    }
1548                    z_utim->mtime = (time_t)i_time;
1549#endif /* ?TIME_T_TYPE_DOUBLE */
1550                    i_time = (long)makelong((EB_HEADSIZE+EB_UX_ATIME)+ef_buf);
1551                    TTrace((stderr,"  Unix EF actime = %ld\n", i_time));
1552#ifdef TIME_T_TYPE_DOUBLE
1553                    if ((ulg)(i_time) & (ulg)(0x80000000L)) {
1554                        if (ut_in_archive_sgn == -1)
1555                            z_utim->atime =
1556                              (time_t)((long)i_time | (~(long)0x7fffffffL));
1557                        } else if (ut_in_archive_sgn == 1) {
1558                            z_utim->atime =
1559                              (time_t)((ulg)i_time & (ulg)0xffffffffL);
1560                        } else if (flags & 0x0ff) {
1561                            /* sign of 32-bit time is unknown -> ignore it */
1562                            flags &= ~EB_UT_FL_ATIME;
1563                            TTrace((stderr,
1564                                "  UX access time range error: skip time!\n"));
1565                        }
1566                    } else {
1567                        z_utim->atime = (time_t)i_time;
1568                    }
1569#else /* !TIME_T_TYPE_DOUBLE */
1570                    if (((ulg)(i_time) & (ulg)(0x80000000L)) &&
1571                        !ut_zip_unzip_compatible && (flags & 0x0ff)) {
1572                        /* atime not in range of UnZip's time_t */
1573                        flags &= ~EB_UT_FL_ATIME;
1574                        TTrace((stderr,
1575                                "  UX access time range error: skip time!\n"));
1576                    } else {
1577                        z_utim->atime = (time_t)i_time;
1578                    }
1579#endif /* ?TIME_T_TYPE_DOUBLE */
1580                }
1581                if (eb_len >= EB_UX_FULLSIZE && z_uidgid != NULL) {
1582                    z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX_UID) + ef_buf);
1583                    z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX_GID) + ef_buf);
1584                    flags |= EB_UX2_VALID;
1585                }
1586            }
1587            break;
1588
1589          default:
1590            break;
1591        }
1592
1593        /* Skip this extra field block */
1594        ef_buf += (eb_len + EB_HEADSIZE);
1595        ef_len -= (eb_len + EB_HEADSIZE);
1596    }
1597
1598    return flags;
1599}
1600
1601#endif /* USE_EF_UT_TIME */
1602
1603
1604#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
1605
1606#define SPARKID_2 0x30435241    /* = "ARC0" */
1607
1608/*******************************/
1609/* Function getRISCOSexfield() */
1610/*******************************/
1611
1612zvoid *getRISCOSexfield(ef_buf, ef_len)
1613    ZCONST uch *ef_buf; /* buffer containing extra field */
1614    unsigned ef_len;    /* total length of extra field */
1615{
1616    unsigned eb_id;
1617    unsigned eb_len;
1618
1619/*---------------------------------------------------------------------------
1620    This function scans the extra field for a Acorn SPARK filetype ef-block.
1621    If a valid block is found, the function returns a pointer to the start
1622    of the SPARK_EF block in the extra field buffer.  Otherwise, a NULL
1623    pointer is returned.
1624  ---------------------------------------------------------------------------*/
1625
1626    if (ef_len == 0 || ef_buf == NULL)
1627        return NULL;
1628
1629    TTrace((stderr,"\ngetRISCOSexfield: scanning extra field of length %u\n",
1630      ef_len));
1631
1632    while (ef_len >= EB_HEADSIZE) {
1633        eb_id = makeword(EB_ID + ef_buf);
1634        eb_len = makeword(EB_LEN + ef_buf);
1635
1636        if (eb_len > (ef_len - EB_HEADSIZE)) {
1637            /* discovered some extra field inconsistency! */
1638            TTrace((stderr,
1639              "getRISCOSexfield: block length %u > rest ef_size %u\n", eb_len,
1640              ef_len - EB_HEADSIZE));
1641            break;
1642        }
1643
1644        if (eb_id == EF_SPARK && (eb_len == 24 || eb_len == 20)) {
1645            if (makelong(EB_HEADSIZE + ef_buf) == SPARKID_2) {
1646                /* Return a pointer to the valid SPARK filetype ef block */
1647                return (zvoid *)ef_buf;
1648            }
1649        }
1650
1651        /* Skip this extra field block */
1652        ef_buf += (eb_len + EB_HEADSIZE);
1653        ef_len -= (eb_len + EB_HEADSIZE);
1654    }
1655
1656    return NULL;
1657}
1658
1659#endif /* (RISCOS || ACORN_FTYPE_NFS) */
1660