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