xref: /haiku/src/bin/unzip/process.c (revision 17049c451a91f427aec94b944b75876b611103e7)
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 
39 static int    do_seekable        OF((__GPRO__ int lastchance));
40 static int    find_ecrec         OF((__GPRO__ long searchlen));
41 
42 static 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 
132 static ZCONST char Far MissingBytes[] =
133   "error [%s]:  missing %ld bytes in zipfile\n\
134   (attempting to process anyway)\n";
135 static ZCONST char Far NullCentDirOffset[] =
136   "error [%s]:  NULL central directory offset\n\
137   (attempting to process anyway)\n";
138 static ZCONST char Far ZipfileEmpty[] = "warning [%s]:  zipfile is empty\n";
139 static 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 */
156 static ZCONST char Far ZipfileCommTrunc1[] =
157   "\ncaution:  zipfile comment truncated\n";
158 
159 
160 
161 
162 /*******************************/
163 /* Function process_zipfiles() */
164 /*******************************/
165 
process_zipfiles(__G)166 int 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 
free_G_buffers(__G)474 void 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 
528 static 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 
893 static 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 
991 fail:
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 
uz_end_central(__G)1046 int 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 
1103 int 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 
1171 int 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 
1233 int 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 
1284 unsigned 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 
1612 zvoid *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