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