Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / bin / unzip / process.c
blob68bcc8f3078c0b501d1e507ed321e1c65c426eae
1 /*
2 Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
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 /*---------------------------------------------------------------------------
11 process.c
13 This file contains the top-level routines for processing multiple zipfiles.
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()
26 ---------------------------------------------------------------------------*/
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
39 static int do_seekable OF((__GPRO__ int lastchance));
40 static int find_ecrec OF((__GPRO__ long searchlen));
42 static ZCONST char Far CannotAllocateBuffers[] =
43 "error: cannot allocate unzip buffers\n";
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
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";
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 */
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";
162 /*******************************/
163 /* Function process_zipfiles() */
164 /*******************************/
166 int process_zipfiles(__G) /* return PK-type error code */
167 __GDEF
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;
177 /*---------------------------------------------------------------------------
178 Start by allocating buffers and (re)constructing the various PK signature
179 strings.
180 ---------------------------------------------------------------------------*/
182 G.inbuf = (uch *)malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */
183 G.outbuf = (uch *)malloc(OUTBUFSIZ + 1); /* 1 extra for string term. */
185 if ((G.inbuf == (uch *)NULL) || (G.outbuf == (uch *)NULL)) {
186 Info(slide, 0x401, ((char *)slide,
187 LoadFarString(CannotAllocateBuffers)));
188 return(PK_MEM);
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 */
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 */
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 */
206 local_hdr_sig[1] /* = extd_local_sig[1] */ = /* ASCII 'K', */
207 central_hdr_sig[1] = end_central_sig[1] = 0x4B; /* not EBCDIC */
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 ---------------------------------------------------------------------------*/
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.
221 iz_w32_prepareTZenv();
222 #endif
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
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;
237 # endif /* !SFX */
239 #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
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
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));
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 ---------------------------------------------------------------------------*/
268 #ifdef SFX
269 if ((error = do_seekable(__G__ 0)) == PK_NOZIP) {
270 #ifdef EXE_EXTENSION
271 int len=strlen(G.argv0);
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 */
282 #endif /* EXE_EXTENSION */
283 #ifdef WIN32
284 G.zipfn = G.argv0; /* for "cannot find myself" message only */
285 #endif
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));
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)));
306 #endif /* CHEAP_SFX_AUTORUN */
308 #else /* !SFX */
309 NumWinFiles = NumLoseFiles = NumWarnFiles = 0;
310 NumMissDirs = NumMissFiles = 0;
312 while ((G.zipfn = do_wild(__G__ G.wildzipfn)) != (char *)NULL) {
313 Trace((stderr, "do_wild( %s ) returns %s\n", G.wildzipfn, G.zipfn));
315 lastzipfn = G.zipfn;
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);
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;
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;
344 #endif
346 } /* end while-loop (wildcard zipfiles) */
348 if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0 &&
349 (NumMissDirs + NumMissFiles) == 1 && lastzipfn != (char *)NULL)
351 NumMissDirs = NumMissFiles = 0;
352 if (error_in_archive == PK_NOZIP)
353 error_in_archive = PK_COOL;
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
364 char *p = lastzipfn + strlen(lastzipfn);
366 G.zipfn = lastzipfn;
367 strcpy(p, ZSUFX);
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);
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;
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;
412 #endif
415 #endif /* ?SFX */
417 /*---------------------------------------------------------------------------
418 Print summary of all zipfiles, assuming zipfile spec was a wildcard (no
419 need for a summary if just one zipfile).
420 ---------------------------------------------------------------------------*/
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
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)));
457 #endif /* !SFX */
459 /* free allocated memory */
460 free_G_buffers(__G);
462 return error_in_archive;
464 } /* end function process_zipfiles() */
470 /*****************************/
471 /* Function free_G_buffers() */
472 /*****************************/
474 void free_G_buffers(__G) /* releases all memory allocated in global vars */
475 __GDEF
477 inflate_free(__G);
478 checkdir(__G__ (char *)NULL, END);
480 #ifdef DYNALLOC_CRCTAB
481 if (CRC_32_TAB) {
482 free_crc_table();
483 CRC_32_TAB = NULL;
485 #endif
487 if (G.key != (char *)NULL) {
488 free(G.key);
489 G.key = (char *)NULL;
492 if (G.extra_field != (uch *)NULL) {
493 free(G.extra_field);
494 G.extra_field = (uch *)NULL;
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;
503 #endif
505 if (G.outbuf)
506 free(G.outbuf);
507 if (G.inbuf)
508 free(G.inbuf);
509 G.inbuf = G.outbuf = (uch *)NULL;
511 #ifdef MALLOC_WORK
512 if (G.area.Slide) {
513 free(G.area.Slide);
514 G.area.Slide = (uch *)NULL;
516 #endif
518 } /* end function free_G_buffers() */
524 /**************************/
525 /* Function do_seekable() */
526 /**************************/
528 static int do_seekable(__G__ lastchance) /* return PK-type error code */
529 __GDEF
530 int lastchance;
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;
544 /*---------------------------------------------------------------------------
545 Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
546 which would corrupt the bit streams.
547 ---------------------------------------------------------------------------*/
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)
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) */
582 #endif /* !SFX */
583 return error? IZ_DIR : PK_NOZIP;
585 G.ziplen = G.statbuf.st_size;
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 */
594 #ifdef VMS
595 if (check_format(__G)) /* check for variable-length format */
596 return PK_ERR;
597 #endif
599 if (open_input_file(__G)) /* this should never happen, given */
600 return PK_NOZIP; /* the stat() test above, but... */
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 ---------------------------------------------------------------------------*/
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;
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);
628 #endif /* !SFX || SFX_EXDIR */
630 G.cur_zipfile_bufstart = 0;
631 G.inptr = G.inbuf;
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 */
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)))
656 CLOSE_INFILE();
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 */
671 #endif /* ?SFX */
674 if ((uO.zflag > 0) && !uO.zipinfo_mode) { /* unzip: zflag = comment ONLY */
675 CLOSE_INFILE();
676 return error_in_archive;
679 /*---------------------------------------------------------------------------
680 Test the end-of-central-directory info for incompatibilities (multi-disk
681 archives) or inconsistencies (missing or extra bytes in zipfile).
682 ---------------------------------------------------------------------------*/
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
691 #ifndef SFX
692 if (uO.zipinfo_mode &&
693 G.ecrec.number_this_disk != G.ecrec.num_disk_start_cdir)
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;
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
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;
722 #endif /* !SFX */
723 if ((G.extra_bytes = G.real_ecrec_offset-G.expect_ecrec_offset) <
724 (LONGINT)0)
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 */
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;
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;
746 #endif /* !SFX */
749 /*-----------------------------------------------------------------------
750 Check for empty zipfile and exit now if so.
751 -----------------------------------------------------------------------*/
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;
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 -----------------------------------------------------------------------*/
771 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
772 if (error == PK_BADERR) {
773 CLOSE_INFILE();
774 return PK_BADERR;
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(?) */
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
787 #ifndef SFX
788 long tmp = G.extra_bytes;
789 #endif
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))
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);
803 #ifndef SFX
804 Info(slide, 0x401, ((char *)slide, LoadFarString(CentDirTooLong),
805 G.zipfn, -tmp));
806 #endif
807 error_in_archive = PK_ERR;
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 -----------------------------------------------------------------------*/
816 error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
817 if (error != PK_OK) {
818 CLOSE_INFILE();
819 return error;
822 Trace((stderr, "about to extract/list files (error = %d)\n",
823 error_in_archive));
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.
834 if (!G.fValidate)
835 #endif
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 */
854 Trace((stderr, "done with extract/list files (error = %d)\n",
855 error));
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
864 CLOSE_INFILE();
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;
880 #endif
881 return error_in_archive;
883 } /* end function do_seekable() */
889 /*************************/
890 /* Function find_ecrec() */
891 /*************************/
893 static int find_ecrec(__G__ searchlen) /* return PK-class error */
894 __GDEF
895 long searchlen;
897 int i, numblks, found=FALSE;
898 LONGINT tail_len;
899 ec_byte_rec byterec;
902 /*---------------------------------------------------------------------------
903 Treat case of short zipfile separately.
904 ---------------------------------------------------------------------------*/
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)
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;
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 ---------------------------------------------------------------------------*/
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... */
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;
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;
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 -----------------------------------------------------------------------*/
963 numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
964 /* ==amount= ==done== ==rounding== =blksiz= */
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 */
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;
981 /* sig may span block boundary: */
982 memcpy((char *)G.hold, (char *)G.inbuf, 3);
984 } /* end if (ziplen > INBUFSIZ) */
986 /*---------------------------------------------------------------------------
987 Searched through whole region where signature should be without finding
988 it. Print informational message and die a horrible death.
989 ---------------------------------------------------------------------------*/
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 */
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 ---------------------------------------------------------------------------*/
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
1014 if (readbuf(__G__ (char *)byterec, ECREC_SIZE+4) == 0)
1015 return PK_EOF;
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]);
1032 G.expect_ecrec_offset = G.ecrec.offset_start_central_directory +
1033 G.ecrec.size_central_directory;
1034 return PK_COOL;
1036 } /* end function find_ecrec() */
1042 /*****************************/
1043 /* Function uz_end_central() */
1044 /*****************************/
1046 int uz_end_central(__G) /* return PK-type error code */
1047 __GDEF
1049 int error = PK_COOL;
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 ---------------------------------------------------------------------------*/
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 */
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;
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;
1090 #endif
1091 return error;
1093 } /* end function uz_end_central() */
1099 /************************************/
1100 /* Function process_cdir_file_hdr() */
1101 /************************************/
1103 int process_cdir_file_hdr(__G) /* return PK-type error code */
1104 __GDEF
1106 int error;
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 ---------------------------------------------------------------------------*/
1115 if ((error = get_cdir_ent(__G)) != 0)
1116 return error;
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); */
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;
1137 default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */
1138 break; /* FS_VFAT_, BEOS_ (Z_SYSTEM_), THEOS_: */
1139 /* no conversion */
1141 else if (uO.L_flag > 1) /* let -LL force lower case for all names */
1142 G.pInfo->lcflag = 1;
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_))
1149 G.pInfo->vollabel = TRUE;
1150 G.pInfo->lcflag = 0; /* preserve case of volume labels */
1151 } else
1152 G.pInfo->vollabel = FALSE;
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;
1159 return PK_COOL;
1161 } /* end function process_cdir_file_hdr() */
1167 /***************************/
1168 /* Function get_cdir_ent() */
1169 /***************************/
1171 int get_cdir_ent(__G) /* return PK-type error code */
1172 __GDEF
1174 cdir_byte_hdr byterec;
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 ---------------------------------------------------------------------------*/
1184 if (readbuf(__G__ (char *)byterec, CREC_SIZE) == 0)
1185 return PK_EOF;
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];
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]);
1221 return PK_COOL;
1223 } /* end function get_cdir_ent() */
1229 /*************************************/
1230 /* Function process_local_file_hdr() */
1231 /*************************************/
1233 int process_local_file_hdr(__G) /* return PK-type error code */
1234 __GDEF
1236 local_byte_hdr byterec;
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 ---------------------------------------------------------------------------*/
1246 if (readbuf(__G__ (char *)byterec, LREC_SIZE) == 0)
1247 return PK_EOF;
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];
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]);
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;
1271 G.csize = (long)G.lrec.csize;
1273 return PK_COOL;
1275 } /* end function process_local_file_hdr() */
1278 #ifdef USE_EF_UT_TIME
1280 /*******************************/
1281 /* Function ef_scan_for_izux() */
1282 /*******************************/
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 */
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
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 ---------------------------------------------------------------------------*/
1322 if (ef_len == 0 || ef_buf == NULL || (z_utim == 0 && z_uidgid == NULL))
1323 return 0;
1325 TTrace((stderr,"\nef_scan_for_izux: scanning extra field of length %u\n",
1326 ef_len));
1328 while (ef_len >= EB_HEADSIZE) {
1329 eb_id = makeword(EB_ID + ef_buf);
1330 eb_len = makeword(EB_LEN + ef_buf);
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;
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));
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 */
1374 } else {
1375 /* cannot determine, safe assumption is FALSE */
1376 ut_in_archive_sgn = 0;
1377 z_utim->mtime = (time_t)i_time;
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 */
1393 } else {
1394 /* cannot determine, safe assumption is FALSE */
1395 ut_zip_unzip_compatible = FALSE;
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"));
1404 if (ef_is_c) {
1405 break; /* central version of TIME field ends here */
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"));
1428 } else {
1429 z_utim->atime = (time_t)i_time;
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;
1440 #endif /* ?TIME_T_TYPE_DOUBLE */
1441 } else {
1442 flags &= ~EB_UT_FL_ATIME;
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"));
1464 } else {
1465 z_utim->ctime = (time_t)i_time;
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;
1476 #endif /* ?TIME_T_TYPE_DOUBLE */
1477 } else {
1478 flags &= ~EB_UT_FL_CTIME;
1482 break;
1484 case EF_IZUNIX2:
1485 if (!have_new_type_eb) {
1486 flags &= ~0x0ff; /* ignore any previous IZUNIX field */
1487 have_new_type_eb = TRUE;
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 */
1494 break;
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 ! */
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"));
1526 } else {
1527 /* cannot determine, safe assumption is FALSE */
1528 ut_in_archive_sgn = 0;
1529 z_utim->mtime = (time_t)i_time;
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"));
1544 } else {
1545 /* cannot determine, safe assumption is FALSE */
1546 ut_zip_unzip_compatible = FALSE;
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"));
1566 } else {
1567 z_utim->atime = (time_t)i_time;
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;
1579 #endif /* ?TIME_T_TYPE_DOUBLE */
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;
1587 break;
1589 default:
1590 break;
1593 /* Skip this extra field block */
1594 ef_buf += (eb_len + EB_HEADSIZE);
1595 ef_len -= (eb_len + EB_HEADSIZE);
1598 return flags;
1601 #endif /* USE_EF_UT_TIME */
1604 #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
1606 #define SPARKID_2 0x30435241 /* = "ARC0" */
1608 /*******************************/
1609 /* Function getRISCOSexfield() */
1610 /*******************************/
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 */
1616 unsigned eb_id;
1617 unsigned eb_len;
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 ---------------------------------------------------------------------------*/
1626 if (ef_len == 0 || ef_buf == NULL)
1627 return NULL;
1629 TTrace((stderr,"\ngetRISCOSexfield: scanning extra field of length %u\n",
1630 ef_len));
1632 while (ef_len >= EB_HEADSIZE) {
1633 eb_id = makeword(EB_ID + ef_buf);
1634 eb_len = makeword(EB_LEN + ef_buf);
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;
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;
1651 /* Skip this extra field block */
1652 ef_buf += (eb_len + EB_HEADSIZE);
1653 ef_len -= (eb_len + EB_HEADSIZE);
1656 return NULL;
1659 #endif /* (RISCOS || ACORN_FTYPE_NFS) */