1 /*---------------------------------------------------------------------------
5 This file contains the top-level routines for processing multiple zipfiles.
7 Contains: process_zipfiles()
12 process_cdir_file_hdr()
14 process_local_file_hdr()
17 ---------------------------------------------------------------------------*/
20 #define UNZIP_INTERNAL
24 # include "wince/intrface.h"
26 # include "windll/windll.h"
30 static int do_seekable
OF((__GPRO__
int lastchance
));
31 static int find_ecrec
OF((__GPRO__
long searchlen
));
35 static ZCONST
char Far CannotAllocateBuffers
[] =
36 "error: cannot allocate unzip buffers\n";
39 static ZCONST
char Far CannotFindMyself
[] =
40 "unzipsfx: cannot find myself! [%s]\n";
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";
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";
61 /* do_seekable() strings */
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 */
70 static ZCONST
char Far CannotFindWildcardMatch
[] =
71 "%s: cannot find any matches for wildcard specification \"%s\".\n";
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 */
79 extern ZCONST
char Far Zipnfo
[]; /* in unzip.c */
81 static ZCONST
char Far Unzip
[] = "unzip";
83 static ZCONST
char Far Unzip
[] = "UnZip DLL";
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\
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";
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";
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";
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";
119 static ZCONST
char Far MissingBytes
[] =
120 "error [%s]: missing %ld bytes in zipfile\n\
121 (attempting to process anyway)\n";
122 static ZCONST
char Far NullCentDirOffset
[] =
123 "error [%s]: NULL central directory offset\n\
124 (attempting to process anyway)\n";
125 static ZCONST
char Far ZipfileEmpty
[] = "warning [%s]: zipfile is empty\n";
126 static ZCONST
char Far CentDirStartNotFound
[] =
127 "error [%s]: start of central directory not found;\n\
128 zipfile corrupt.\n%s";
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";
140 static ZCONST
char Far CentDirEndSigNotFound
[] =
141 " End-of-central-directory signature not found.\n";
143 static ZCONST
char Far ZipfileCommTrunc1
[] =
144 "\ncaution: zipfile comment truncated\n";
149 /*******************************/
150 /* Function process_zipfiles() */
151 /*******************************/
153 int process_zipfiles(__G
) /* return PK-type error code */
157 char *lastzipfn
= (char *)NULL
;
158 int NumWinFiles
, NumLoseFiles
, NumWarnFiles
;
159 int NumMissDirs
, NumMissFiles
;
161 int error
=0, error_in_archive
=0;
164 /*---------------------------------------------------------------------------
165 Start by allocating buffers and (re)constructing the various PK signature
167 ---------------------------------------------------------------------------*/
169 G
.inbuf
= (uch
*)malloc(INBUFSIZ
+ 4); /* 4 extra for hold[] (below) */
170 G
.outbuf
= (uch
*)malloc(OUTBUFSIZ
+ 1); /* 1 extra for string term. */
172 if ((G
.inbuf
== (uch
*)NULL
) || (G
.outbuf
== (uch
*)NULL
)) {
173 Info(slide
, 0x401, ((char *)slide
,
174 LoadFarString(CannotAllocateBuffers
)));
177 G
.hold
= G
.inbuf
+ INBUFSIZ
; /* to check for boundary-spanning sigs */
178 #ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */
180 G
.outbuf2
= G
.outbuf
+RAWBUFSIZ
; /* never changes */
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 */
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 */
193 local_hdr_sig
[1] /* = extd_local_sig[1] */ = 0x4B; /* ASCII 'K', */
194 central_hdr_sig
[1] = end_central_sig
[1] = 0x4B; /* not EBCDIC */
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 ---------------------------------------------------------------------------*/
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'))
211 G
.tz_is_valid
= VALID_TIMEZONE(p
);
213 if (!G
.tz_is_valid
) {
214 Info(slide
, 0x401, ((char *)slide
, LoadFarString(WarnInvalidTZ
)));
215 error_in_archive
= error
= PK_WARN
;
219 #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
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))
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 ---------------------------------------------------------------------------*/
237 if ((error
= do_seekable(__G__
0)) == PK_NOZIP
) {
239 int len
=strlen(G
.argv0
);
241 /* append .exe if appropriate; also .sfx? */
242 if ( (G
.zipfn
= (char *)malloc(len
+sizeof(EXE_EXTENSION
))) !=
244 strcpy(G
.zipfn
, G
.argv0
);
245 strcpy(G
.zipfn
+len
, EXE_EXTENSION
);
246 error
= do_seekable(__G__
0);
248 G
.zipfn
= G
.argv0
; /* for "cannot find myself" message only */
250 #endif /* EXE_EXTENSION */
252 G
.zipfn
= G
.argv0
; /* for "cannot find myself" message only */
257 error_in_archive
= PK_NOZIP
;
259 error_in_archive
= error
;
260 if (error
== PK_NOZIP
)
261 Info(slide
, 1, ((char *)slide
, LoadFarString(CannotFindMyself
),
266 NumWinFiles
= NumLoseFiles
= NumWarnFiles
= 0;
267 files
= NumMissDirs
= NumMissFiles
= 0;
269 while ((G
.zipfn
= do_wild(__G__ G
.wildzipfn
)) != (char *)NULL
) {
270 Trace((stderr
, "do_wild( %s ) returns %s\n", G
.wildzipfn
, G
.zipfn
));
274 /* print a blank line between the output of different zipfiles */
275 if (!uO
.qflag
&& error
!= PK_NOZIP
&& error
!= IZ_DIR
277 && (!uO
.T_flag
|| uO
.zipinfo_mode
)
279 && (NumWinFiles
+NumLoseFiles
+NumWarnFiles
+NumMissFiles
) > 0)
280 (*G
.message
)((zvoid
*)&G
, (uch
*)"\n", 1L, 0);
282 if ((error
= do_seekable(__G__
0)) == PK_WARN
)
284 else if (error
== IZ_DIR
)
286 else if (error
== PK_NOZIP
)
296 if (error
!= IZ_DIR
&& error
> error_in_archive
)
297 error_in_archive
= error
;
298 Trace((stderr
, "do_seekable(0) returns %d\n", error
));
300 if (error
== IZ_CTRLC
) {
306 } /* end while-loop (wildcard zipfiles) */
308 if ((NumWinFiles
+ NumWarnFiles
+ NumLoseFiles
) == 0 &&
309 (NumMissDirs
+ NumMissFiles
) == 1 && lastzipfn
!= (char *)NULL
)
311 NumMissDirs
= NumMissFiles
= 0;
312 if (error_in_archive
== PK_NOZIP
)
313 error_in_archive
= PK_COOL
;
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
),
324 char *p
= lastzipfn
+ strlen(lastzipfn
);
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
) {
337 strcpy(p
, ALT_ZSUFX
);
338 error
= do_seekable(__G__
1);
341 error
= do_seekable(__G__
1);
343 if (error
== PK_WARN
) /* GRR: make this a switch/case stmt ... */
345 else if (error
== IZ_DIR
)
347 else if (error
== PK_NOZIP
)
348 /* increment again => bug: "1 file had no zipfile directory." */
349 /* ++NumMissFiles */ ;
355 if (error
> error_in_archive
)
356 error_in_archive
= error
;
357 Trace((stderr
, "do_seekable(1) returns %d\n", error
));
359 if (error
== IZ_CTRLC
) {
368 /*---------------------------------------------------------------------------
369 Print summary of all zipfiles, assuming zipfile spec was a wildcard (no
370 need for a summary if just one zipfile).
371 ---------------------------------------------------------------------------*/
374 if (iswild(G
.wildzipfn
) && uO
.qflag
< 3
376 && !(uO
.T_flag
&& uO
.qflag
&& !uO
.zipinfo_mode
)
380 if ((NumMissFiles
+ NumLoseFiles
+ NumWarnFiles
> 0 || NumWinFiles
!= 1)
382 && !(uO
.T_flag
&& !uO
.zipinfo_mode
)
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
)));
410 /* free allocated memory */
413 return error_in_archive
;
415 } /* end function process_zipfiles() */
421 /*****************************/
422 /* Function free_G_buffers() */
423 /*****************************/
425 void free_G_buffers(__G
) /* releases all memory allocated in global vars */
429 checkdir(__G__ (char *)NULL
, END
);
431 #ifdef DYNALLOC_CRCTAB
438 if (G
.key
!= (char *)NULL
) {
440 G
.key
= (char *)NULL
;
443 #if (!defined(VMS) && !defined(SMALL_MEM))
444 /* VMS uses its own buffer scheme for textmode flush() */
446 free(G
.outbuf2
); /* malloc'd ONLY if unshrink and -a */
447 G
.outbuf2
= (uch
*)NULL
;
455 G
.inbuf
= G
.outbuf
= (uch
*)NULL
;
460 G
.area
.Slide
= (uch
*)NULL
;
464 } /* end function free_G_buffers() */
470 /**************************/
471 /* Function do_seekable() */
472 /**************************/
474 static int do_seekable(__G__ lastchance
) /* return PK-type error code */
479 /* static int no_ecrec = FALSE; SKM: moved to globals.h */
481 int too_weird_to_continue
=FALSE
;
484 unsigned nmember
= 0;
487 int error
=0, error_in_archive
;
490 /*---------------------------------------------------------------------------
491 Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
492 which would corrupt the bit streams.
493 ---------------------------------------------------------------------------*/
495 if (SSTAT(G
.zipfn
, &G
.statbuf
) ||
496 (error
= S_ISDIR(G
.statbuf
.st_mode
)) != 0)
500 #if defined(UNIX) || defined(QDOS)
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
,
508 Info(slide
, 1, ((char *)slide
,
509 LoadFarString(CannotFindEitherZipfile
), uO
.zipinfo_mode
?
510 LoadFarStringSmall(Zipnfo
) : LoadFarStringSmall(Unzip
),
511 G
.wildzipfn
, G
.wildzipfn
, G
.zipfn
));
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
));
519 Info(slide
, 0x401, ((char *)slide
,
520 LoadFarString(CannotFindEitherZipfile
), uO
.zipinfo_mode
?
521 LoadFarStringSmall(Zipnfo
) : LoadFarStringSmall(Unzip
),
522 G
.wildzipfn
, G
.zipfn
));
526 return error
? IZ_DIR
: PK_NOZIP
;
528 G
.ziplen
= G
.statbuf
.st_size
;
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. */
538 if (check_format(__G
)) /* check for variable-length format */
542 if (open_input_file(__G
)) /* this should never happen, given */
543 return PK_NOZIP
; /* the stat() test above, but... */
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 ---------------------------------------------------------------------------*/
553 /* initialize the CRC table pointer (once) */
554 if (CRC_32_TAB
== NULL
) {
555 if ((CRC_32_TAB
= get_crc_table()) == NULL
)
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 */
566 #endif /* !SFX || SFX_EXDIR */
568 G
.cur_zipfile_bufstart
= 0;
571 #if (!defined(WINDLL) && !defined(SFX))
573 if (!uO
.zipinfo_mode
&& !uO
.qflag
&& !uO
.T_flag
)
575 if (!uO
.zipinfo_mode
&& !uO
.qflag
)
577 #ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */
578 Info(slide
, 0, ((char *)slide
, "Archive: %s\n", FnFilter1(G
.zipfn
)));
580 Info(slide
, 0, ((char *)slide
, "Archive: %s\n", G
.zipfn
));
582 #endif /* !WINDLL && !SFX */
587 ((error_in_archive
= find_ecrec(__G__ G
.ziplen
)) != 0 ||
588 (error_in_archive
= zi_end_central(__G
)) > PK_WARN
))
589 || (!uO
.zipinfo_mode
&&
591 ((error_in_archive
= find_ecrec(__G__
MIN(G
.ziplen
,66000L))) != 0 ||
592 (error_in_archive
= uz_end_central(__G
)) > PK_WARN
)))
597 ++lastchance
; /* avoid picky compiler warnings */
598 return error_in_archive
;
601 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybeExe
),
604 return error_in_archive
;
606 G
.no_ecrec
= TRUE
; /* assume we found wrong file: e.g., */
607 return PK_NOZIP
; /* unzip instead of unzip.zip */
612 if ((uO
.zflag
> 0) && !uO
.zipinfo_mode
) { /* unzip: zflag = comment ONLY */
614 return error_in_archive
;
617 /*---------------------------------------------------------------------------
618 Test the end-of-central-directory info for incompatibilities (multi-disk
619 archives) or inconsistencies (missing or extra bytes in zipfile).
620 ---------------------------------------------------------------------------*/
623 error
= !uO
.zipinfo_mode
&& (G
.ecrec
.number_this_disk
== 1) &&
624 (G
.ecrec
.num_disk_start_cdir
== 1);
626 error
= !uO
.zipinfo_mode
&& (G
.ecrec
.number_this_disk
!= 0);
630 if (uO
.zipinfo_mode
&&
631 G
.ecrec
.number_this_disk
!= G
.ecrec
.num_disk_start_cdir
)
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
;
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
;
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
),
649 error_in_archive
= PK_FIND
;
650 too_weird_to_continue
= TRUE
;
654 if (!too_weird_to_continue
) { /* (relatively) normal zipfile: go for it */
656 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybePakBug
),
658 error_in_archive
= PK_WARN
;
661 if ((G
.extra_bytes
= G
.real_ecrec_offset
-G
.expect_ecrec_offset
) <
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 */
671 Info(slide
, 0x401, ((char *)slide
,
672 LoadFarString(NullCentDirOffset
), G
.zipfn
));
673 G
.ecrec
.offset_start_central_directory
= G
.extra_bytes
;
675 error_in_archive
= PK_ERR
;
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
;
687 /*-----------------------------------------------------------------------
688 Check for empty zipfile and exit now if so.
689 -----------------------------------------------------------------------*/
691 if (G
.expect_ecrec_offset
==0L && G
.ecrec
.size_central_directory
==0) {
693 Info(slide
, 0, ((char *)slide
, "%sEmpty zipfile.\n",
694 uO
.lflag
>9? "\n " : ""));
696 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ZipfileEmpty
),
699 return (error_in_archive
> PK_WARN
)? error_in_archive
: PK_WARN
;
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 -----------------------------------------------------------------------*/
709 ZLSEEK( G
.ecrec
.offset_start_central_directory
)
711 if (readbuf(G
.sig
, 4) == 0) {
713 return PK_ERR
; /* file may be locked, or possibly disk error(?) */
715 if (strncmp(G
.sig
, central_hdr_sig
, 4))
717 if ((readbuf(__G__ G
.sig
, 4) == 0) ||
718 strncmp(G
.sig
, central_hdr_sig
, 4))
722 long tmp
= G
.extra_bytes
;
726 ZLSEEK( G
.ecrec
.offset_start_central_directory
)
727 if ((readbuf(__G__ G
.sig
, 4) == 0) ||
728 strncmp(G
.sig
, central_hdr_sig
, 4))
730 Info(slide
, 0x401, ((char *)slide
,
731 LoadFarString(CentDirStartNotFound
), G
.zipfn
,
732 LoadFarStringSmall(ReportMsg
)));
737 Info(slide
, 0x401, ((char *)slide
, LoadFarString(CentDirTooLong
),
740 error_in_archive
= PK_ERR
;
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 -----------------------------------------------------------------------*/
749 Trace((stderr
, "about to extract/list files (error = %d)\n",
752 ZLSEEK( G
.ecrec
.offset_start_central_directory
)
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.
768 error
= zipinfo(__G
); /* ZIPINFO 'EM */
774 error
= get_time_stamp(__G__
&uxstamp
, &nmember
);
777 if (uO
.vflag
&& !uO
.tflag
&& !uO
.cflag
)
778 error
= list_files(__G
); /* LIST 'EM */
781 error
= extract_or_test_files(__G
); /* EXTRACT OR TEST 'EM */
783 Trace((stderr
, "done with extract/list files (error = %d)\n",
787 if (error
> error_in_archive
) /* don't overwrite stronger error */
788 error_in_archive
= error
; /* with (for example) a warning */
790 } /* end if (!too_weird_to_continue) */
796 if (uO
.T_flag
&& !uO
.zipinfo_mode
&& (nmember
> 0)) {
798 if (stamp_file(__G__ G
.zipfn
, uxstamp
)) { /* TIME-STAMP 'EM */
800 if (stamp_file(G
.zipfn
, uxstamp
)) { /* TIME-STAMP 'EM */
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
;
809 return error_in_archive
;
811 } /* end function do_seekable() */
817 /*************************/
818 /* Function find_ecrec() */
819 /*************************/
821 static int find_ecrec(__G__ searchlen
) /* return PK-class error */
825 int i
, numblks
, found
=FALSE
;
830 /*---------------------------------------------------------------------------
831 Treat case of short zipfile separately.
832 ---------------------------------------------------------------------------*/
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
))
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
;
842 if ((native(*G
.inptr
) == 'P') &&
843 !strncmp((char *)G
.inptr
, end_central_sig
, 4)) {
844 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
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 ---------------------------------------------------------------------------*/
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
,
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... */
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
;
870 if ((native(*G
.inptr
) == 'P') &&
871 !strncmp((char *)G
.inptr
, end_central_sig
, 4)) {
872 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
876 /* sig may span block boundary: */
877 strncpy((char *)G
.hold
, (char *)G
.inbuf
, 3);
879 G
.cur_zipfile_bufstart
= G
.ziplen
- tail_len
;
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 -----------------------------------------------------------------------*/
887 numblks
= (int)((searchlen
- tail_len
+ (INBUFSIZ
-1)) / INBUFSIZ
);
888 /* ==amount= ==done== ==rounding== =blksiz= */
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
))
895 break; /* fall through and fail */
897 for (G
.inptr
= G
.inbuf
+INBUFSIZ
-1; G
.inptr
>= G
.inbuf
;
899 if ((native(*G
.inptr
) == 'P') &&
900 !strncmp((char *)G
.inptr
, end_central_sig
, 4)) {
901 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
905 /* sig may span block boundary: */
906 strncpy((char *)G
.hold
, (char *)G
.inbuf
, 3);
908 } /* end if (ziplen > INBUFSIZ) */
910 /*---------------------------------------------------------------------------
911 Searched through whole region where signature should be without finding
912 it. Print informational message and die a horrible death.
913 ---------------------------------------------------------------------------*/
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 */
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 ---------------------------------------------------------------------------*/
930 G
.real_ecrec_offset
= G
.cur_zipfile_bufstart
+ (G
.inptr
-G
.inbuf
);
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
);
938 if (readbuf(__G__ (char *)byterec
, ECREC_SIZE
+4) == 0)
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
]);
956 G
.expect_ecrec_offset
= G
.ecrec
.offset_start_central_directory
+
957 G
.ecrec
.size_central_directory
;
960 } /* end function find_ecrec() */
966 /*****************************/
967 /* Function uz_end_central() */
968 /*****************************/
970 int uz_end_central(__G
) /* return PK-type error code */
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
980 ---------------------------------------------------------------------------*/
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))
988 if (G
.ecrec
.zipfile_comment_length
&& (uO
.zflag
> 0 ||
996 if (do_string(__G__ G
.ecrec
.zipfile_comment_length
, DISPLAY
)) {
997 Info(slide
, 0x401, ((char *)slide
,
998 LoadFarString(ZipfileCommTrunc1
)));
1004 } /* end function uz_end_central() */
1010 /************************************/
1011 /* Function process_cdir_file_hdr() */
1012 /************************************/
1014 int process_cdir_file_hdr(__G
) /* return PK-type error code */
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
1024 ---------------------------------------------------------------------------*/
1026 if ((error
= get_cdir_ent(__G
)) != 0)
1029 G
.pInfo
->hostnum
= MIN(G
.crec
.version_made_by
[1], NUM_HOSTS
);
1030 /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
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? */
1041 case VMS_
: /* our Zip uses lowercase, but ASi's doesn't */
1042 /* case Z_SYSTEM_: ? */
1044 G
.pInfo
->lcflag
= 1; /* convert filename to lowercase */
1047 default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */
1048 break; /* FS_VFAT_, BEOS_ (Z_SYSTEM_): no conversion */
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_
))
1056 G
.pInfo
->vollabel
= TRUE
;
1057 G
.pInfo
->lcflag
= 0; /* preserve case of volume labels */
1059 G
.pInfo
->vollabel
= FALSE
;
1063 } /* end function process_cdir_file_hdr() */
1069 /***************************/
1070 /* Function get_cdir_ent() */
1071 /***************************/
1073 int get_cdir_ent(__G
) /* return PK-type error code */
1076 cdir_byte_hdr byterec
;
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 ---------------------------------------------------------------------------*/
1086 if (readbuf(__G__ (char *)byterec
, CREC_SIZE
) == 0)
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
];
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
]);
1103 makelong(&byterec
[C_CRC32
]);
1105 makelong(&byterec
[C_COMPRESSED_SIZE
]);
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
]);
1125 } /* end function get_cdir_ent() */
1131 /*************************************/
1132 /* Function process_local_file_hdr() */
1133 /*************************************/
1135 int process_local_file_hdr(__G
) /* return PK-type error code */
1138 local_byte_hdr byterec
;
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 ---------------------------------------------------------------------------*/
1148 if (readbuf(__G__ (char *)byterec
, LREC_SIZE
) == 0)
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
];
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
]);
1166 G
.csize
= (long) G
.lrec
.csize
;
1167 G
.ucsize
= (long) G
.lrec
.ucsize
;
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
);
1178 } /* end function process_local_file_hdr() */
1181 #ifdef USE_EF_UT_TIME
1183 /*******************************/
1184 /* Function ef_scan_for_izux() */
1185 /*******************************/
1187 unsigned ef_scan_for_izux(ef_buf
, ef_len
, ef_is_c
, dos_mdatetime
,
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 */
1199 int have_new_type_eb
= FALSE
;
1200 int ut_zip_unzip_compatible
= FALSE
;
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
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 ---------------------------------------------------------------------------*/
1220 if (ef_len
== 0 || ef_buf
== NULL
|| (z_utim
== 0 && z_uidgid
== NULL
))
1223 TTrace((stderr
,"\nef_scan_for_izux: scanning extra field of length %u\n",
1226 while (ef_len
>= EB_HEADSIZE
) {
1227 eb_id
= makeword(EB_ID
+ ef_buf
);
1228 eb_len
= makeword(EB_LEN
+ ef_buf
);
1230 if (eb_len
> (ef_len
- EB_HEADSIZE
)) {
1231 /* discovered some extra field inconsistency! */
1233 "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len
,
1234 ef_len
- EB_HEADSIZE
));
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
);
1250 TTrace((stderr
," UT e.f. modification time = %ld\n",
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 */
1263 " UT modtime range error; ignore e.f.!\n"));
1264 break; /* stop scanning this field */
1267 /* cannot determine, safe assumption is FALSE */
1268 ut_zip_unzip_compatible
= FALSE
;
1271 flags
&= ~EB_UT_FL_MTIME
;
1272 TTrace((stderr
," UT e.f. truncated; no modtime\n"));
1276 break; /* central version of TIME field ends here */
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
);
1283 TTrace((stderr
," UT e.f. access time = %ld\n",
1285 if (((ulg
)(z_utim
->atime
) & (ulg
)(0x80000000L
)) &&
1286 !ut_zip_unzip_compatible
) {
1287 flags
&= ~EB_UT_FL_ATIME
;
1289 " UT access time range error: skip time!\n"));
1292 flags
&= ~EB_UT_FL_ATIME
;
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",
1300 if (((ulg
)(z_utim
->ctime
) & (ulg
)(0x80000000L
)) &&
1301 !ut_zip_unzip_compatible
) {
1302 flags
&= ~EB_UT_FL_CTIME
;
1304 " UT creation time range error: skip time!\n"));
1307 flags
&= ~EB_UT_FL_CTIME
;
1314 if (!have_new_type_eb
) {
1315 flags
&= ~0x0ff; /* ignore any previous IZUNIX field */
1316 have_new_type_eb
= TRUE
;
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 */
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 ! */
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 */
1349 " UX modtime range error: ignore e.f.!\n"));
1352 /* cannot determine, safe assumption is FALSE */
1353 ut_zip_unzip_compatible
= FALSE
;
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
;
1360 " UX access time range error: skip time!\n"));
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
;
1375 /* Skip this extra field block */
1376 ef_buf
+= (eb_len
+ EB_HEADSIZE
);
1377 ef_len
-= (eb_len
+ EB_HEADSIZE
);
1383 #endif /* USE_EF_UT_TIME */