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"
32 extern int installstate
;
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
);
40 char *replacestr(char *str1
, char *str2
, char *str3
);
42 static int do_seekable
OF((__GPRO__
int lastchance
));
43 static int find_ecrec
OF((__GPRO__
long searchlen
));
45 static ZCONST
char Far CannotAllocateBuffers
[] =
46 "error: cannot allocate unzip buffers\n";
49 static ZCONST
char Far CannotFindMyself
[] =
50 "unzipsfx: cannot find myself! [%s]\n";
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";
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";
71 /* do_seekable() strings */
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 */
80 static ZCONST
char Far CannotFindWildcardMatch
[] =
81 "%s: cannot find any matches for wildcard specification \"%s\".\n";
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 */
89 extern ZCONST
char Far Zipnfo
[]; /* in unzip.c */
91 static ZCONST
char Far Unzip
[] = "unzip";
93 static ZCONST
char Far Unzip
[] = "UnZip DLL";
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\
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";
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";
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";
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";
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";
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";
150 static ZCONST
char Far CentDirEndSigNotFound
[] =
151 " End-of-central-directory signature not found.\n";
153 static ZCONST
char Far ZipfileCommTrunc1
[] =
154 "\ncaution: zipfile comment truncated\n";
159 /*******************************/
160 /* Function process_zipfiles() */
161 /*******************************/
163 int process_zipfiles(__G
) /* return PK-type error code */
167 char *lastzipfn
= (char *)NULL
;
168 int NumWinFiles
, NumLoseFiles
, NumWarnFiles
;
169 int NumMissDirs
, NumMissFiles
;
171 int error
=0, error_in_archive
=0;
172 extern unsigned current_file
;
173 extern char installdir2
[];
176 /*---------------------------------------------------------------------------
177 Start by allocating buffers and (re)constructing the various PK signature
179 ---------------------------------------------------------------------------*/
181 G
.inbuf
= (uch
*)malloc(INBUFSIZ
+ 4); /* 4 extra for hold[] (below) */
182 G
.outbuf
= (uch
*)malloc(OUTBUFSIZ
+ 1); /* 1 extra for string term. */
184 if ((G
.inbuf
== (uch
*)NULL
) || (G
.outbuf
== (uch
*)NULL
)) {
185 Info(slide
, 0x401, ((char *)slide
,
186 LoadFarString(CannotAllocateBuffers
)));
189 G
.hold
= G
.inbuf
+ INBUFSIZ
; /* to check for boundary-spanning sigs */
190 #ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */
192 G
.outbuf2
= G
.outbuf
+RAWBUFSIZ
; /* never changes */
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 */
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 */
205 local_hdr_sig
[1] /* = extd_local_sig[1] */ = 0x4B; /* ASCII 'K', */
206 central_hdr_sig
[1] = end_central_sig
[1] = 0x4B; /* not EBCDIC */
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 ---------------------------------------------------------------------------*/
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'))
223 G
.tz_is_valid
= VALID_TIMEZONE(p
);
225 if (!G
.tz_is_valid
) {
226 Info(slide
, 0x401, ((char *)slide
, LoadFarString(WarnInvalidTZ
)));
227 error_in_archive
= error
= PK_WARN
;
231 #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
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))
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 ---------------------------------------------------------------------------*/
249 if ((error
= do_seekable(__G__
0)) == PK_NOZIP
) {
251 int len
=strlen(G
.argv0
);
253 /* append .exe if appropriate; also .sfx? */
254 if ( (G
.zipfn
= (char *)malloc(len
+sizeof(EXE_EXTENSION
))) !=
256 strcpy(G
.zipfn
, G
.argv0
);
257 strcpy(G
.zipfn
+len
, EXE_EXTENSION
);
258 error
= do_seekable(__G__
0);
260 G
.zipfn
= G
.argv0
; /* for "cannot find myself" message only */
262 #endif /* EXE_EXTENSION */
264 G
.zipfn
= G
.argv0
; /* for "cannot find myself" message only */
269 error_in_archive
= PK_NOZIP
;
271 error_in_archive
= error
;
272 if (error
== PK_NOZIP
)
273 Info(slide
, 1, ((char *)slide
, LoadFarString(CannotFindMyself
),
278 NumWinFiles
= NumLoseFiles
= NumWarnFiles
= 0;
279 current_file
= NumMissDirs
= NumMissFiles
= 0;
281 while ((G
.zipfn
= do_wild(__G__ G
.wildzipfn
)) != (char *)NULL
) {
282 Trace((stderr
, "do_wild( %s ) returns %s\n", G
.wildzipfn
, G
.zipfn
));
286 /* print a blank line between the output of different zipfiles */
287 if (!uO
.qflag
&& error
!= PK_NOZIP
&& error
!= IZ_DIR
289 && (!uO
.T_flag
|| uO
.zipinfo_mode
)
291 && (NumWinFiles
+NumLoseFiles
+NumWarnFiles
+NumMissFiles
) > 0)
292 (*G
.message
)((zvoid
*)&G
, (uch
*)"\n", 1L, 0);
294 if ((error
= do_seekable(__G__
0)) == PK_WARN
)
296 else if (error
== IZ_DIR
)
298 else if (error
== PK_NOZIP
)
305 current_file
= NumWinFiles
;
307 if(installstate
== INSTALLING
)
310 if (error
!= IZ_DIR
&& error
> error_in_archive
)
311 error_in_archive
= error
;
312 Trace((stderr
, "do_seekable(0) returns %d\n", error
));
314 if (error
== IZ_CTRLC
) {
320 } /* end while-loop (wildcard zipfiles) */
322 if ((NumWinFiles
+ NumWarnFiles
+ NumLoseFiles
) == 0 &&
323 (NumMissDirs
+ NumMissFiles
) == 1 && lastzipfn
!= (char *)NULL
)
325 NumMissDirs
= NumMissFiles
= 0;
326 if (error_in_archive
== PK_NOZIP
)
327 error_in_archive
= PK_COOL
;
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
),
338 char *p
= lastzipfn
+ strlen(lastzipfn
);
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
) {
351 strcpy(p
, ALT_ZSUFX
);
352 error
= do_seekable(__G__
1);
355 error
= do_seekable(__G__
1);
357 if (error
== PK_WARN
) /* GRR: make this a switch/case stmt ... */
359 else if (error
== IZ_DIR
)
361 else if (error
== PK_NOZIP
)
362 /* increment again => bug: "1 file had no zipfile directory." */
363 /* ++NumMissFiles */ ;
369 if (error
> error_in_archive
)
370 error_in_archive
= error
;
371 Trace((stderr
, "do_seekable(1) returns %d\n", error
));
373 if (error
== IZ_CTRLC
) {
382 /*---------------------------------------------------------------------------
383 Print summary of all zipfiles, assuming zipfile spec was a wildcard (no
384 need for a summary if just one zipfile).
385 ---------------------------------------------------------------------------*/
388 if (iswild(G
.wildzipfn
) && uO
.qflag
< 3
390 && !(uO
.T_flag
&& uO
.qflag
&& !uO
.zipinfo_mode
)
394 if ((NumMissFiles
+ NumLoseFiles
+ NumWarnFiles
> 0 || NumWinFiles
!= 1)
396 && !(uO
.T_flag
&& !uO
.zipinfo_mode
)
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
)));
424 /* free allocated memory */
427 return error_in_archive
;
429 } /* end function process_zipfiles() */
435 /*****************************/
436 /* Function free_G_buffers() */
437 /*****************************/
439 void free_G_buffers(__G
) /* releases all memory allocated in global vars */
443 checkdir(__G__ (char *)NULL
, END
);
445 #ifdef DYNALLOC_CRCTAB
452 if (G
.key
!= (char *)NULL
) {
454 G
.key
= (char *)NULL
;
457 #if (!defined(VMS) && !defined(SMALL_MEM))
458 /* VMS uses its own buffer scheme for textmode flush() */
460 free(G
.outbuf2
); /* malloc'd ONLY if unshrink and -a */
461 G
.outbuf2
= (uch
*)NULL
;
469 G
.inbuf
= G
.outbuf
= (uch
*)NULL
;
474 G
.area
.Slide
= (uch
*)NULL
;
478 } /* end function free_G_buffers() */
484 /**************************/
485 /* Function do_seekable() */
486 /**************************/
488 static int do_seekable(__G__ lastchance
) /* return PK-type error code */
493 /* static int no_ecrec = FALSE; SKM: moved to globals.h */
495 int too_weird_to_continue
=FALSE
;
498 unsigned nmember
= 0;
501 int error
=0, error_in_archive
;
504 /*---------------------------------------------------------------------------
505 Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
506 which would corrupt the bit streams.
507 ---------------------------------------------------------------------------*/
510 if (SSTAT(G
.zipfn
, &G
.statbuf
) ||
511 (error
= S_ISDIR(G
.statbuf
.st_mode
)) != 0)
515 #if defined(UNIX) || defined(QDOS)
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
,
523 Info(slide
, 1, ((char *)slide
,
524 LoadFarString(CannotFindEitherZipfile
), uO
.zipinfo_mode
?
525 LoadFarStringSmall(Zipnfo
) : LoadFarStringSmall(Unzip
),
526 G
.wildzipfn
, G
.wildzipfn
, G
.zipfn
));
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
));
534 Info(slide
, 0x401, ((char *)slide
,
535 LoadFarString(CannotFindEitherZipfile
), uO
.zipinfo_mode
?
536 LoadFarStringSmall(Zipnfo
) : LoadFarStringSmall(Unzip
),
537 G
.wildzipfn
, G
.zipfn
));
541 return error
? IZ_DIR
: PK_NOZIP
;
543 G
.ziplen
= G
.statbuf
.st_size
;
545 G
.ziplen
= acesize();
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. */
555 if (check_format(__G
)) /* check for variable-length format */
559 if (open_input_file(__G
)) /* this should never happen, given */
560 return PK_NOZIP
; /* the stat() test above, but... */
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 ---------------------------------------------------------------------------*/
570 /* initialize the CRC table pointer (once) */
571 if (CRC_32_TAB
== NULL
) {
572 if ((CRC_32_TAB
= get_crc_table()) == NULL
)
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 */
583 #endif /* !SFX || SFX_EXDIR */
585 G
.cur_zipfile_bufstart
= 0;
588 #if (!defined(WINDLL) && !defined(SFX))
590 if (!uO
.zipinfo_mode
&& !uO
.qflag
&& !uO
.T_flag
)
592 if (!uO
.zipinfo_mode
&& !uO
.qflag
)
594 #ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */
595 Info(slide
, 0, ((char *)slide
, "Archive: %s\n", FnFilter1(G
.zipfn
)));
597 Info(slide
, 0, ((char *)slide
, "Archive: %s\n", G
.zipfn
));
599 #endif /* !WINDLL && !SFX */
604 ((error_in_archive
= find_ecrec(__G__ G
.ziplen
)) != 0 ||
605 (error_in_archive
= zi_end_central(__G
)) > PK_WARN
))
606 || (!uO
.zipinfo_mode
&&
608 ((error_in_archive
= find_ecrec(__G__
MIN(G
.ziplen
,66000L))) != 0 ||
609 (error_in_archive
= uz_end_central(__G
)) > PK_WARN
)))
614 ++lastchance
; /* avoid picky compiler warnings */
615 return error_in_archive
;
618 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybeExe
),
621 return error_in_archive
;
623 G
.no_ecrec
= TRUE
; /* assume we found wrong file: e.g., */
624 return PK_NOZIP
; /* unzip instead of unzip.zip */
629 if ((uO
.zflag
> 0) && !uO
.zipinfo_mode
) { /* unzip: zflag = comment ONLY */
631 return error_in_archive
;
634 /*---------------------------------------------------------------------------
635 Test the end-of-central-directory info for incompatibilities (multi-disk
636 archives) or inconsistencies (missing or extra bytes in zipfile).
637 ---------------------------------------------------------------------------*/
640 error
= !uO
.zipinfo_mode
&& (G
.ecrec
.number_this_disk
== 1) &&
641 (G
.ecrec
.num_disk_start_cdir
== 1);
643 error
= !uO
.zipinfo_mode
&& (G
.ecrec
.number_this_disk
!= 0);
647 if (uO
.zipinfo_mode
&&
648 G
.ecrec
.number_this_disk
!= G
.ecrec
.num_disk_start_cdir
)
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
;
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
;
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
),
666 error_in_archive
= PK_FIND
;
667 too_weird_to_continue
= TRUE
;
671 if (!too_weird_to_continue
) { /* (relatively) normal zipfile: go for it */
673 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybePakBug
),
675 error_in_archive
= PK_WARN
;
678 if ((G
.extra_bytes
= G
.real_ecrec_offset
-G
.expect_ecrec_offset
) <
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 */
688 Info(slide
, 0x401, ((char *)slide
,
689 LoadFarString(NullCentDirOffset
), G
.zipfn
));
690 G
.ecrec
.offset_start_central_directory
= G
.extra_bytes
;
692 error_in_archive
= PK_ERR
;
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
;
704 /*-----------------------------------------------------------------------
705 Check for empty zipfile and exit now if so.
706 -----------------------------------------------------------------------*/
708 if (G
.expect_ecrec_offset
==0L && G
.ecrec
.size_central_directory
==0) {
710 Info(slide
, 0, ((char *)slide
, "%sEmpty zipfile.\n",
711 uO
.lflag
>9? "\n " : ""));
713 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ZipfileEmpty
),
716 return (error_in_archive
> PK_WARN
)? error_in_archive
: PK_WARN
;
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 -----------------------------------------------------------------------*/
726 ZLSEEK( G
.ecrec
.offset_start_central_directory
)
728 if (readbuf(G
.sig
, 4) == 0) {
730 return PK_ERR
; /* file may be locked, or possibly disk error(?) */
732 if (strncmp(G
.sig
, central_hdr_sig
, 4))
734 if ((readbuf(__G__ G
.sig
, 4) == 0) ||
735 strncmp(G
.sig
, central_hdr_sig
, 4))
739 long tmp
= G
.extra_bytes
;
743 ZLSEEK( G
.ecrec
.offset_start_central_directory
)
744 if ((readbuf(__G__ G
.sig
, 4) == 0) ||
745 strncmp(G
.sig
, central_hdr_sig
, 4))
747 Info(slide
, 0x401, ((char *)slide
,
748 LoadFarString(CentDirStartNotFound
), G
.zipfn
,
749 LoadFarStringSmall(ReportMsg
)));
754 Info(slide
, 0x401, ((char *)slide
, LoadFarString(CentDirTooLong
),
757 error_in_archive
= PK_ERR
;
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 -----------------------------------------------------------------------*/
766 Trace((stderr
, "about to extract/list files (error = %d)\n",
769 ZLSEEK( G
.ecrec
.offset_start_central_directory
)
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.
785 error
= zipinfo(__G
); /* ZIPINFO 'EM */
791 error
= get_time_stamp(__G__
&uxstamp
, &nmember
);
794 if (uO
.vflag
&& !uO
.tflag
&& !uO
.cflag
)
795 error
= list_files(__G
); /* LIST 'EM */
798 error
= extract_or_test_files(__G
); /* EXTRACT OR TEST 'EM */
800 Trace((stderr
, "done with extract/list files (error = %d)\n",
804 if (error
> error_in_archive
) /* don't overwrite stronger error */
805 error_in_archive
= error
; /* with (for example) a warning */
807 } /* end if (!too_weird_to_continue) */
813 if (uO
.T_flag
&& !uO
.zipinfo_mode
&& (nmember
> 0)) {
815 if (stamp_file(__G__ G
.zipfn
, uxstamp
)) { /* TIME-STAMP 'EM */
817 if (stamp_file(G
.zipfn
, uxstamp
)) { /* TIME-STAMP 'EM */
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
;
826 return error_in_archive
;
828 } /* end function do_seekable() */
834 /*************************/
835 /* Function find_ecrec() */
836 /*************************/
838 static int find_ecrec(__G__ searchlen
) /* return PK-class error */
842 int i
, numblks
, found
=FALSE
;
847 /*---------------------------------------------------------------------------
848 Treat case of short zipfile separately.
849 ---------------------------------------------------------------------------*/
851 if (G
.ziplen
<= INBUFSIZ
) {
852 acelseek(0L, SEEK_SET
);
853 if ((G
.incnt
= aceread((char *)G
.inbuf
,(unsigned int)G
.ziplen
))
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
;
859 if ((native(*G
.inptr
) == 'P') &&
860 !strncmp((char *)G
.inptr
, end_central_sig
, 4)) {
861 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
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 ---------------------------------------------------------------------------*/
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
,
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... */
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
;
887 if ((native(*G
.inptr
) == 'P') &&
888 !strncmp((char *)G
.inptr
, end_central_sig
, 4)) {
889 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
893 /* sig may span block boundary: */
894 strncpy((char *)G
.hold
, (char *)G
.inbuf
, 3);
896 G
.cur_zipfile_bufstart
= G
.ziplen
- tail_len
;
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 -----------------------------------------------------------------------*/
904 numblks
= (int)((searchlen
- tail_len
+ (INBUFSIZ
-1)) / INBUFSIZ
);
905 /* ==amount= ==done== ==rounding== =blksiz= */
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
))
912 break; /* fall through and fail */
914 for (G
.inptr
= G
.inbuf
+INBUFSIZ
-1; G
.inptr
>= G
.inbuf
;
916 if ((native(*G
.inptr
) == 'P') &&
917 !strncmp((char *)G
.inptr
, end_central_sig
, 4)) {
918 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
922 /* sig may span block boundary: */
923 strncpy((char *)G
.hold
, (char *)G
.inbuf
, 3);
925 } /* end if (ziplen > INBUFSIZ) */
927 /*---------------------------------------------------------------------------
928 Searched through whole region where signature should be without finding
929 it. Print informational message and die a horrible death.
930 ---------------------------------------------------------------------------*/
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 */
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 ---------------------------------------------------------------------------*/
947 G
.real_ecrec_offset
= G
.cur_zipfile_bufstart
+ (G
.inptr
-G
.inbuf
);
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
);
955 if (readbuf(__G__ (char *)byterec
, ECREC_SIZE
+4) == 0)
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
]);
973 G
.expect_ecrec_offset
= G
.ecrec
.offset_start_central_directory
+
974 G
.ecrec
.size_central_directory
;
977 } /* end function find_ecrec() */
983 /*****************************/
984 /* Function uz_end_central() */
985 /*****************************/
987 int uz_end_central(__G
) /* return PK-type error code */
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
997 ---------------------------------------------------------------------------*/
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))
1005 if (G
.ecrec
.zipfile_comment_length
&& (uO
.zflag
> 0 ||
1011 #endif /* ?WINDLL */
1013 if (do_string(__G__ G
.ecrec
.zipfile_comment_length
, DISPLAY
)) {
1014 Info(slide
, 0x401, ((char *)slide
,
1015 LoadFarString(ZipfileCommTrunc1
)));
1021 } /* end function uz_end_central() */
1027 /************************************/
1028 /* Function process_cdir_file_hdr() */
1029 /************************************/
1031 int process_cdir_file_hdr(__G
) /* return PK-type error code */
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
1041 ---------------------------------------------------------------------------*/
1043 if ((error
= get_cdir_ent(__G
)) != 0)
1046 G
.pInfo
->hostnum
= MIN(G
.crec
.version_made_by
[1], NUM_HOSTS
);
1047 /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
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? */
1058 case VMS_
: /* our Zip uses lowercase, but ASi's doesn't */
1059 /* case Z_SYSTEM_: ? */
1061 G
.pInfo
->lcflag
= 1; /* convert filename to lowercase */
1064 default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */
1065 break; /* FS_VFAT_, BEOS_ (Z_SYSTEM_): no conversion */
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_
))
1073 G
.pInfo
->vollabel
= TRUE
;
1074 G
.pInfo
->lcflag
= 0; /* preserve case of volume labels */
1076 G
.pInfo
->vollabel
= FALSE
;
1080 } /* end function process_cdir_file_hdr() */
1086 /***************************/
1087 /* Function get_cdir_ent() */
1088 /***************************/
1090 int get_cdir_ent(__G
) /* return PK-type error code */
1093 cdir_byte_hdr byterec
;
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 ---------------------------------------------------------------------------*/
1103 if (readbuf(__G__ (char *)byterec
, CREC_SIZE
) == 0)
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
];
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
]);
1120 makelong(&byterec
[C_CRC32
]);
1122 makelong(&byterec
[C_COMPRESSED_SIZE
]);
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
]);
1142 } /* end function get_cdir_ent() */
1148 /*************************************/
1149 /* Function process_local_file_hdr() */
1150 /*************************************/
1152 int process_local_file_hdr(__G
) /* return PK-type error code */
1155 local_byte_hdr byterec
;
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 ---------------------------------------------------------------------------*/
1165 if (readbuf(__G__ (char *)byterec
, LREC_SIZE
) == 0)
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
];
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
]);
1183 G
.csize
= (long) G
.lrec
.csize
;
1184 G
.ucsize
= (long) G
.lrec
.ucsize
;
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
);
1195 } /* end function process_local_file_hdr() */
1198 #ifdef USE_EF_UT_TIME
1200 /*******************************/
1201 /* Function ef_scan_for_izux() */
1202 /*******************************/
1204 unsigned ef_scan_for_izux(ef_buf
, ef_len
, ef_is_c
, dos_mdatetime
,
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 */
1216 int have_new_type_eb
= FALSE
;
1217 int ut_zip_unzip_compatible
= FALSE
;
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
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 ---------------------------------------------------------------------------*/
1237 if (ef_len
== 0 || ef_buf
== NULL
|| (z_utim
== 0 && z_uidgid
== NULL
))
1240 TTrace((stderr
,"\nef_scan_for_izux: scanning extra field of length %u\n",
1243 while (ef_len
>= EB_HEADSIZE
) {
1244 eb_id
= makeword(EB_ID
+ ef_buf
);
1245 eb_len
= makeword(EB_LEN
+ ef_buf
);
1247 if (eb_len
> (ef_len
- EB_HEADSIZE
)) {
1248 /* discovered some extra field inconsistency! */
1250 "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len
,
1251 ef_len
- EB_HEADSIZE
));
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
);
1267 TTrace((stderr
," UT e.f. modification time = %ld\n",
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 */
1280 " UT modtime range error; ignore e.f.!\n"));
1281 break; /* stop scanning this field */
1284 /* cannot determine, safe assumption is FALSE */
1285 ut_zip_unzip_compatible
= FALSE
;
1288 flags
&= ~EB_UT_FL_MTIME
;
1289 TTrace((stderr
," UT e.f. truncated; no modtime\n"));
1293 break; /* central version of TIME field ends here */
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
);
1300 TTrace((stderr
," UT e.f. access time = %ld\n",
1302 if (((ulg
)(z_utim
->atime
) & (ulg
)(0x80000000L
)) &&
1303 !ut_zip_unzip_compatible
) {
1304 flags
&= ~EB_UT_FL_ATIME
;
1306 " UT access time range error: skip time!\n"));
1309 flags
&= ~EB_UT_FL_ATIME
;
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",
1317 if (((ulg
)(z_utim
->ctime
) & (ulg
)(0x80000000L
)) &&
1318 !ut_zip_unzip_compatible
) {
1319 flags
&= ~EB_UT_FL_CTIME
;
1321 " UT creation time range error: skip time!\n"));
1324 flags
&= ~EB_UT_FL_CTIME
;
1331 if (!have_new_type_eb
) {
1332 flags
&= ~0x0ff; /* ignore any previous IZUNIX field */
1333 have_new_type_eb
= TRUE
;
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 */
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 ! */
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 */
1366 " UX modtime range error: ignore e.f.!\n"));
1369 /* cannot determine, safe assumption is FALSE */
1370 ut_zip_unzip_compatible
= FALSE
;
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
;
1377 " UX access time range error: skip time!\n"));
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
;
1392 /* Skip this extra field block */
1393 ef_buf
+= (eb_len
+ EB_HEADSIZE
);
1394 ef_len
-= (eb_len
+ EB_HEADSIZE
);
1400 #endif /* USE_EF_UT_TIME */