2 Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
4 See the accompanying file LICENSE, version 2000-Apr-09 or later
5 (the contents of which are also included in unzip.h) for terms of use.
6 If, for some reason, all these files are missing, the Info-ZIP license
7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
9 /*---------------------------------------------------------------------------
13 This file contains the top-level routines for processing multiple zipfiles.
15 Contains: process_zipfiles()
20 process_cdir_file_hdr()
22 process_local_file_hdr()
26 ---------------------------------------------------------------------------*/
29 #define UNZIP_INTERNAL
33 # include "wince/intrface.h"
35 # include "windll/windll.h"
39 static int do_seekable
OF((__GPRO__
int lastchance
));
40 static int find_ecrec
OF((__GPRO__
long searchlen
));
42 static ZCONST
char Far CannotAllocateBuffers
[] =
43 "error: cannot allocate unzip buffers\n";
46 static ZCONST
char Far CannotFindMyself
[] =
47 "unzipsfx: cannot find myself! [%s]\n";
48 # ifdef CHEAP_SFX_AUTORUN
49 static ZCONST
char Far AutorunPrompt
[] =
50 "\nAuto-run command: %s\nExecute this command? [y/n] ";
51 static ZCONST
char Far NotAutoRunning
[] =
52 "Not executing auto-run command.";
56 /* process_zipfiles() strings */
57 # if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
58 static ZCONST
char Far WarnInvalidTZ
[] =
59 "Warning: TZ environment variable not found, cannot use UTC times!!\n";
61 static ZCONST
char Far FilesProcessOK
[] =
62 "%d archive%s successfully processed.\n";
63 static ZCONST
char Far ArchiveWarning
[] =
64 "%d archive%s had warnings but no fatal errors.\n";
65 static ZCONST
char Far ArchiveFatalError
[] =
66 "%d archive%s had fatal errors.\n";
67 static ZCONST
char Far FileHadNoZipfileDir
[] =
68 "%d file%s had no zipfile directory.\n";
69 static ZCONST
char Far ZipfileWasDir
[] = "1 \"zipfile\" was a directory.\n";
70 static ZCONST
char Far ManyZipfilesWereDir
[] =
71 "%d \"zipfiles\" were directories.\n";
72 static ZCONST
char Far NoZipfileFound
[] = "No zipfiles found.\n";
74 /* do_seekable() strings */
76 static ZCONST
char Far CannotFindZipfileDirMsg
[] =
77 "%s: cannot find zipfile directory in one of %s or\n\
78 %s%s.zip, and cannot find %s, period.\n";
79 static ZCONST
char Far CannotFindEitherZipfile
[] =
80 "%s: cannot find %s, %s.zip or %s.\n";
83 static ZCONST
char Far CannotFindWildcardMatch
[] =
84 "%s: cannot find any matches for wildcard specification \"%s\".\n";
86 static ZCONST
char Far CannotFindZipfileDirMsg
[] =
87 "%s: cannot find zipfile directory in %s,\n\
88 %sand cannot find %s, period.\n";
89 static ZCONST
char Far CannotFindEitherZipfile
[] =
90 "%s: cannot find either %s or %s.\n";
92 extern ZCONST
char Far Zipnfo
[]; /* in unzip.c */
94 static ZCONST
char Far Unzip
[] = "unzip";
96 static ZCONST
char Far Unzip
[] = "UnZip DLL";
98 static ZCONST
char Far MaybeExe
[] =
99 "note: %s may be a plain executable, not an archive\n";
100 static ZCONST
char Far CentDirNotInZipMsg
[] = "\n\
102 Zipfile is disk %u of a multi-disk archive, and this is not the disk on\n\
103 which the central zipfile directory begins (disk %u).\n";
104 static ZCONST
char Far EndCentDirBogus
[] =
105 "\nwarning [%s]: end-of-central-directory record claims this\n\
106 is disk %u but that the central directory starts on disk %u; this is a\n\
107 contradiction. Attempting to process anyway.\n";
109 static ZCONST
char Far NoMultiDiskArcSupport
[] =
110 "\nerror [%s]: zipfile is part of multi-disk archive\n\
111 (sorry, not yet supported).\n";
112 static ZCONST
char Far MaybePakBug
[] = "warning [%s]:\
113 zipfile claims to be 2nd disk of a 2-part archive;\n\
114 attempting to process anyway. If no further errors occur, this archive\n\
115 was probably created by PAK v2.51 or earlier. This bug was reported to\n\
116 NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\
117 of mid-1992 it still hadn't been. (If further errors do occur, archive\n\
118 was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\
119 multi-part archives.)\n";
121 static ZCONST
char Far MaybePakBug
[] = "warning [%s]:\
122 zipfile claims to be last disk of a multi-part archive;\n\
123 attempting to process anyway, assuming all parts have been concatenated\n\
124 together in order. Expect \"errors\" and warnings...true multi-part support\
125 \n doesn't exist yet (coming soon).\n";
127 static ZCONST
char Far ExtraBytesAtStart
[] =
128 "warning [%s]: %ld extra byte%s at beginning or within zipfile\n\
129 (attempting to process anyway)\n";
132 static ZCONST
char Far MissingBytes
[] =
133 "error [%s]: missing %ld bytes in zipfile\n\
134 (attempting to process anyway)\n";
135 static ZCONST
char Far NullCentDirOffset
[] =
136 "error [%s]: NULL central directory offset\n\
137 (attempting to process anyway)\n";
138 static ZCONST
char Far ZipfileEmpty
[] = "warning [%s]: zipfile is empty\n";
139 static ZCONST
char Far CentDirStartNotFound
[] =
140 "error [%s]: start of central directory not found;\n\
141 zipfile corrupt.\n%s";
143 static ZCONST
char Far CentDirTooLong
[] =
144 "error [%s]: reported length of central directory is\n\
145 %ld bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1\n\
146 zipfile?). Compensating...\n";
147 static ZCONST
char Far CentDirEndSigNotFound
[] = "\
148 End-of-central-directory signature not found. Either this file is not\n\
149 a zipfile, or it constitutes one disk of a multi-part archive. In the\n\
150 latter case the central directory and zipfile comment will be found on\n\
151 the last disk(s) of this archive.\n";
153 static ZCONST
char Far CentDirEndSigNotFound
[] =
154 " End-of-central-directory signature not found.\n";
156 static ZCONST
char Far ZipfileCommTrunc1
[] =
157 "\ncaution: zipfile comment truncated\n";
162 /*******************************/
163 /* Function process_zipfiles() */
164 /*******************************/
166 int process_zipfiles(__G
) /* return PK-type error code */
170 char *lastzipfn
= (char *)NULL
;
171 int NumWinFiles
, NumLoseFiles
, NumWarnFiles
;
172 int NumMissDirs
, NumMissFiles
;
174 int error
=0, error_in_archive
=0;
177 /*---------------------------------------------------------------------------
178 Start by allocating buffers and (re)constructing the various PK signature
180 ---------------------------------------------------------------------------*/
182 G
.inbuf
= (uch
*)malloc(INBUFSIZ
+ 4); /* 4 extra for hold[] (below) */
183 G
.outbuf
= (uch
*)malloc(OUTBUFSIZ
+ 1); /* 1 extra for string term. */
185 if ((G
.inbuf
== (uch
*)NULL
) || (G
.outbuf
== (uch
*)NULL
)) {
186 Info(slide
, 0x401, ((char *)slide
,
187 LoadFarString(CannotAllocateBuffers
)));
190 G
.hold
= G
.inbuf
+ INBUFSIZ
; /* to check for boundary-spanning sigs */
191 #ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */
193 G
.outbuf2
= G
.outbuf
+RAWBUFSIZ
; /* never changes */
197 #if 0 /* CRC_32_TAB has been NULLified by CONSTRUCTGLOBALS !!!! */
198 /* allocate the CRC table only later when we know we have a zipfile */
202 /* finish up initialization of magic signature strings */
203 local_hdr_sig
[0] /* = extd_local_sig[0] */ = /* ASCII 'P', */
204 central_hdr_sig
[0] = end_central_sig
[0] = 0x50; /* not EBCDIC */
206 local_hdr_sig
[1] /* = extd_local_sig[1] */ = /* ASCII 'K', */
207 central_hdr_sig
[1] = end_central_sig
[1] = 0x4B; /* not EBCDIC */
209 /*---------------------------------------------------------------------------
210 Make sure timezone info is set correctly; localtime() returns GMT on
211 some OSes (e.g., Solaris 2.x) if this isn't done first. The ifdefs were
212 initially copied from dos_to_unix_time() in fileio.c. probably, they are
213 still too strict; any listed OS that supplies tzset(), regardless of
214 whether the function does anything, should be removed from the ifdefs.
215 ---------------------------------------------------------------------------*/
217 #if (defined(WIN32) && defined(USE_EF_UT_TIME))
218 /* For the Win32 environment, we may have to "prepare" the environment
219 prior to the tzset() call, to work around tzset() implementation bugs.
221 iz_w32_prepareTZenv();
224 #if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
225 # ifndef VALID_TIMEZONE
226 # define VALID_TIMEZONE(tmp) \
227 (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0'))
231 G
.tz_is_valid
= VALID_TIMEZONE(p
);
233 if (!G
.tz_is_valid
) {
234 Info(slide
, 0x401, ((char *)slide
, LoadFarString(WarnInvalidTZ
)));
235 error_in_archive
= error
= PK_WARN
;
239 #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
241 /* For systems that do not have tzset() but supply this function using another
242 name (_tzset() or something similar), an appropiate "#define tzset ..."
243 should be added to the system specifc configuration section. */
244 #if (!defined(T20_VMS) && !defined(MACOS) && !defined(RISCOS) && !defined(QDOS))
245 #if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM))
250 /*---------------------------------------------------------------------------
251 Initialize the internal flag holding the mode of processing "overwrite
252 existing file" cases. We do not use the calling interface flags directly
253 because the overwrite mode may be changed by user interaction while
254 processing archive files. Such a change should not affect the option
255 settings as passed through the DLL calling interface.
256 In case of conflicting options, the 'safer' flag uO.overwrite_none takes
258 ---------------------------------------------------------------------------*/
259 G
.overwrite_mode
= (uO
.overwrite_none
? OVERWRT_NEVER
:
260 (uO
.overwrite_all
? OVERWRT_ALWAYS
: OVERWRT_QUERY
));
262 /*---------------------------------------------------------------------------
263 Match (possible) wildcard zipfile specification with existing files and
264 attempt to process each. If no hits, try again after appending ".zip"
265 suffix. If still no luck, give up.
266 ---------------------------------------------------------------------------*/
269 if ((error
= do_seekable(__G__
0)) == PK_NOZIP
) {
271 int len
=strlen(G
.argv0
);
273 /* append .exe if appropriate; also .sfx? */
274 if ( (G
.zipfn
= (char *)malloc(len
+sizeof(EXE_EXTENSION
))) !=
276 strcpy(G
.zipfn
, G
.argv0
);
277 strcpy(G
.zipfn
+len
, EXE_EXTENSION
);
278 error
= do_seekable(__G__
0);
280 G
.zipfn
= G
.argv0
; /* for "cannot find myself" message only */
282 #endif /* EXE_EXTENSION */
284 G
.zipfn
= G
.argv0
; /* for "cannot find myself" message only */
289 error_in_archive
= PK_NOZIP
;
291 error_in_archive
= error
;
292 if (error
== PK_NOZIP
)
293 Info(slide
, 1, ((char *)slide
, LoadFarString(CannotFindMyself
),
296 #ifdef CHEAP_SFX_AUTORUN
297 if (G
.autorun_command
[0] && !uO
.qflag
) { /* NO autorun without prompt! */
298 Info(slide
, 0x81, ((char *)slide
, LoadFarString(AutorunPrompt
),
299 FnFilter1(G
.autorun_command
)));
300 if (fgets(G
.answerbuf
, 9, stdin
) != (char *)NULL
301 && toupper(*G
.answerbuf
) == 'Y')
302 system(G
.autorun_command
);
304 Info(slide
, 1, ((char *)slide
, LoadFarString(NotAutoRunning
)));
306 #endif /* CHEAP_SFX_AUTORUN */
309 NumWinFiles
= NumLoseFiles
= NumWarnFiles
= 0;
310 NumMissDirs
= NumMissFiles
= 0;
312 while ((G
.zipfn
= do_wild(__G__ G
.wildzipfn
)) != (char *)NULL
) {
313 Trace((stderr
, "do_wild( %s ) returns %s\n", G
.wildzipfn
, G
.zipfn
));
317 /* print a blank line between the output of different zipfiles */
318 if (!uO
.qflag
&& error
!= PK_NOZIP
&& error
!= IZ_DIR
320 && (!uO
.T_flag
|| uO
.zipinfo_mode
)
322 && (NumWinFiles
+NumLoseFiles
+NumWarnFiles
+NumMissFiles
) > 0)
323 (*G
.message
)((zvoid
*)&G
, (uch
*)"\n", 1L, 0);
325 if ((error
= do_seekable(__G__
0)) == PK_WARN
)
327 else if (error
== IZ_DIR
)
329 else if (error
== PK_NOZIP
)
336 Trace((stderr
, "do_seekable(0) returns %d\n", error
));
337 if (error
!= IZ_DIR
&& error
> error_in_archive
)
338 error_in_archive
= error
;
340 if (error
== IZ_CTRLC
) {
346 } /* end while-loop (wildcard zipfiles) */
348 if ((NumWinFiles
+ NumWarnFiles
+ NumLoseFiles
) == 0 &&
349 (NumMissDirs
+ NumMissFiles
) == 1 && lastzipfn
!= (char *)NULL
)
351 NumMissDirs
= NumMissFiles
= 0;
352 if (error_in_archive
== PK_NOZIP
)
353 error_in_archive
= PK_COOL
;
355 #if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */
356 if (iswild(G
.wildzipfn
))
357 Info(slide
, 0x401, ((char *)slide
,
358 LoadFarString(CannotFindWildcardMatch
), uO
.zipinfo_mode
?
359 LoadFarStringSmall(Zipnfo
) : LoadFarStringSmall(Unzip
),
364 char *p
= lastzipfn
+ strlen(lastzipfn
);
369 #if defined(UNIX) || defined(QDOS)
370 /* only Unix has case-sensitive filesystems */
371 /* Well FlexOS (sometimes) also has them, but support is per media */
372 /* and a pig to code for, so treat as case insensitive for now */
373 /* we do this under QDOS to check for .zip as well as _zip */
374 if ((error
= do_seekable(__G__
0)) == PK_NOZIP
|| error
== IZ_DIR
) {
377 strcpy(p
, ALT_ZSUFX
);
378 error
= do_seekable(__G__
1);
381 error
= do_seekable(__G__
1);
383 Trace((stderr
, "do_seekable(1) returns %d\n", error
));
393 /* increment again => bug:
394 "1 file had no zipfile directory." */
395 /* ++NumMissFiles */ ;
405 if (error
> error_in_archive
)
406 error_in_archive
= error
;
408 if (error
== IZ_CTRLC
) {
417 /*---------------------------------------------------------------------------
418 Print summary of all zipfiles, assuming zipfile spec was a wildcard (no
419 need for a summary if just one zipfile).
420 ---------------------------------------------------------------------------*/
423 if (iswild(G
.wildzipfn
) && uO
.qflag
< 3
425 && !(uO
.T_flag
&& uO
.qflag
&& !uO
.zipinfo_mode
)
429 if ((NumMissFiles
+ NumLoseFiles
+ NumWarnFiles
> 0 || NumWinFiles
!= 1)
431 && !(uO
.T_flag
&& !uO
.zipinfo_mode
)
433 && !(uO
.tflag
&& uO
.qflag
> 1))
434 (*G
.message
)((zvoid
*)&G
, (uch
*)"\n", 1L, 0x401);
435 if ((NumWinFiles
> 1) || (NumWinFiles
== 1 &&
436 NumMissDirs
+ NumMissFiles
+ NumLoseFiles
+ NumWarnFiles
> 0))
437 Info(slide
, 0x401, ((char *)slide
, LoadFarString(FilesProcessOK
),
438 NumWinFiles
, (NumWinFiles
== 1)? " was" : "s were"));
439 if (NumWarnFiles
> 0)
440 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ArchiveWarning
),
441 NumWarnFiles
, (NumWarnFiles
== 1)? "" : "s"));
442 if (NumLoseFiles
> 0)
443 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ArchiveFatalError
),
444 NumLoseFiles
, (NumLoseFiles
== 1)? "" : "s"));
445 if (NumMissFiles
> 0)
446 Info(slide
, 0x401, ((char *)slide
,
447 LoadFarString(FileHadNoZipfileDir
), NumMissFiles
,
448 (NumMissFiles
== 1)? "" : "s"));
449 if (NumMissDirs
== 1)
450 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ZipfileWasDir
)));
451 else if (NumMissDirs
> 0)
452 Info(slide
, 0x401, ((char *)slide
,
453 LoadFarString(ManyZipfilesWereDir
), NumMissDirs
));
454 if (NumWinFiles
+ NumLoseFiles
+ NumWarnFiles
== 0)
455 Info(slide
, 0x401, ((char *)slide
, LoadFarString(NoZipfileFound
)));
459 /* free allocated memory */
462 return error_in_archive
;
464 } /* end function process_zipfiles() */
470 /*****************************/
471 /* Function free_G_buffers() */
472 /*****************************/
474 void free_G_buffers(__G
) /* releases all memory allocated in global vars */
478 checkdir(__G__ (char *)NULL
, END
);
480 #ifdef DYNALLOC_CRCTAB
487 if (G
.key
!= (char *)NULL
) {
489 G
.key
= (char *)NULL
;
492 if (G
.extra_field
!= (uch
*)NULL
) {
494 G
.extra_field
= (uch
*)NULL
;
497 #if (!defined(VMS) && !defined(SMALL_MEM))
498 /* VMS uses its own buffer scheme for textmode flush() */
500 free(G
.outbuf2
); /* malloc'd ONLY if unshrink and -a */
501 G
.outbuf2
= (uch
*)NULL
;
509 G
.inbuf
= G
.outbuf
= (uch
*)NULL
;
514 G
.area
.Slide
= (uch
*)NULL
;
518 } /* end function free_G_buffers() */
524 /**************************/
525 /* Function do_seekable() */
526 /**************************/
528 static int do_seekable(__G__ lastchance
) /* return PK-type error code */
533 /* static int no_ecrec = FALSE; SKM: moved to globals.h */
535 int too_weird_to_continue
=FALSE
;
541 int error
=0, error_in_archive
;
544 /*---------------------------------------------------------------------------
545 Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
546 which would corrupt the bit streams.
547 ---------------------------------------------------------------------------*/
549 if (SSTAT(G
.zipfn
, &G
.statbuf
) ||
551 (error
= S_ISLIB(G
.statbuf
.st_mode
)) != 0 ||
553 (error
= S_ISDIR(G
.statbuf
.st_mode
)) != 0)
556 if (lastchance
&& (uO
.qflag
< 3)) {
557 #if defined(UNIX) || defined(QDOS)
559 Info(slide
, 1, ((char *)slide
,
560 LoadFarString(CannotFindZipfileDirMsg
), uO
.zipinfo_mode
?
561 LoadFarStringSmall(Zipnfo
) : LoadFarStringSmall(Unzip
),
562 G
.wildzipfn
, uO
.zipinfo_mode
? " " : "", G
.wildzipfn
,
565 Info(slide
, 1, ((char *)slide
,
566 LoadFarString(CannotFindEitherZipfile
), uO
.zipinfo_mode
?
567 LoadFarStringSmall(Zipnfo
) : LoadFarStringSmall(Unzip
),
568 G
.wildzipfn
, G
.wildzipfn
, G
.zipfn
));
569 #else /* !(UNIX || QDOS) */
571 Info(slide
, 0x401, ((char *)slide
,
572 LoadFarString(CannotFindZipfileDirMsg
), uO
.zipinfo_mode
?
573 LoadFarStringSmall(Zipnfo
) : LoadFarStringSmall(Unzip
),
574 G
.wildzipfn
, uO
.zipinfo_mode
? " " : "", G
.zipfn
));
576 Info(slide
, 0x401, ((char *)slide
,
577 LoadFarString(CannotFindEitherZipfile
), uO
.zipinfo_mode
?
578 LoadFarStringSmall(Zipnfo
) : LoadFarStringSmall(Unzip
),
579 G
.wildzipfn
, G
.zipfn
));
580 #endif /* ?(UNIX || QDOS) */
583 return error
? IZ_DIR
: PK_NOZIP
;
585 G
.ziplen
= G
.statbuf
.st_size
;
588 #if defined(UNIX) || defined(DOS_OS2_W32) || defined(THEOS)
589 if (G
.statbuf
.st_mode
& S_IEXEC
) /* no extension on Unix exes: might */
590 maybe_exe
= TRUE
; /* find unzip, not unzip.zip; etc. */
595 if (check_format(__G
)) /* check for variable-length format */
599 if (open_input_file(__G
)) /* this should never happen, given */
600 return PK_NOZIP
; /* the stat() test above, but... */
602 /*---------------------------------------------------------------------------
603 Find and process the end-of-central-directory header. UnZip need only
604 check last 65557 bytes of zipfile: comment may be up to 65535, end-of-
605 central-directory record is 18 bytes, and signature itself is 4 bytes;
606 add some to allow for appended garbage. Since ZipInfo is often used as
607 a debugging tool, search the whole zipfile if zipinfo_mode is true.
608 ---------------------------------------------------------------------------*/
610 /* initialize the CRC table pointer (once) */
611 if (CRC_32_TAB
== NULL
) {
612 if ((CRC_32_TAB
= get_crc_table()) == NULL
) {
618 #if (!defined(SFX) || defined(SFX_EXDIR))
619 /* check out if specified extraction root directory exists */
620 if (uO
.exdir
!= (char *)NULL
&& G
.extract_flag
) {
621 G
.create_dirs
= !uO
.fflag
;
622 if ((error
= checkdir(__G__ uO
.exdir
, ROOT
)) > MPN_INF_SKIP
) {
623 /* out of memory, or file in way */
625 return (error
== MPN_NOMEM
? PK_MEM
: PK_ERR
);
628 #endif /* !SFX || SFX_EXDIR */
630 G
.cur_zipfile_bufstart
= 0;
633 #if (!defined(WINDLL) && !defined(SFX))
635 if (!uO
.zipinfo_mode
&& !uO
.qflag
&& !uO
.T_flag
)
637 if (!uO
.zipinfo_mode
&& !uO
.qflag
)
639 #ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */
640 Info(slide
, 0, ((char *)slide
, "Archive: %s\n", FnFilter1(G
.zipfn
)));
642 Info(slide
, 0, ((char *)slide
, "Archive: %s\n", G
.zipfn
));
644 #endif /* !WINDLL && !SFX */
649 ((error_in_archive
= find_ecrec(__G__ G
.ziplen
)) != 0 ||
650 (error_in_archive
= zi_end_central(__G
)) > PK_WARN
))
651 || (!uO
.zipinfo_mode
&&
653 ((error_in_archive
= find_ecrec(__G__
MIN(G
.ziplen
,66000L))) != 0 ||
654 (error_in_archive
= uz_end_central(__G
)) > PK_WARN
)))
659 ++lastchance
; /* avoid picky compiler warnings */
660 return error_in_archive
;
663 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybeExe
),
666 return error_in_archive
;
668 G
.no_ecrec
= TRUE
; /* assume we found wrong file: e.g., */
669 return PK_NOZIP
; /* unzip instead of unzip.zip */
674 if ((uO
.zflag
> 0) && !uO
.zipinfo_mode
) { /* unzip: zflag = comment ONLY */
676 return error_in_archive
;
679 /*---------------------------------------------------------------------------
680 Test the end-of-central-directory info for incompatibilities (multi-disk
681 archives) or inconsistencies (missing or extra bytes in zipfile).
682 ---------------------------------------------------------------------------*/
685 error
= !uO
.zipinfo_mode
&& (G
.ecrec
.number_this_disk
== 1) &&
686 (G
.ecrec
.num_disk_start_cdir
== 1);
688 error
= !uO
.zipinfo_mode
&& (G
.ecrec
.number_this_disk
!= 0);
692 if (uO
.zipinfo_mode
&&
693 G
.ecrec
.number_this_disk
!= G
.ecrec
.num_disk_start_cdir
)
695 if (G
.ecrec
.number_this_disk
> G
.ecrec
.num_disk_start_cdir
) {
696 Info(slide
, 0x401, ((char *)slide
,
697 LoadFarString(CentDirNotInZipMsg
), G
.zipfn
,
698 G
.ecrec
.number_this_disk
, G
.ecrec
.num_disk_start_cdir
));
699 error_in_archive
= PK_FIND
;
700 too_weird_to_continue
= TRUE
;
702 Info(slide
, 0x401, ((char *)slide
,
703 LoadFarString(EndCentDirBogus
), G
.zipfn
,
704 G
.ecrec
.number_this_disk
, G
.ecrec
.num_disk_start_cdir
));
705 error_in_archive
= PK_WARN
;
707 #ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */
708 } else if (!uO
.zipinfo_mode
&& !error
&& G
.ecrec
.number_this_disk
!= 0) {
709 Info(slide
, 0x401, ((char *)slide
, LoadFarString(NoMultiDiskArcSupport
),
711 error_in_archive
= PK_FIND
;
712 too_weird_to_continue
= TRUE
;
716 if (!too_weird_to_continue
) { /* (relatively) normal zipfile: go for it */
718 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybePakBug
),
720 error_in_archive
= PK_WARN
;
723 if ((G
.extra_bytes
= G
.real_ecrec_offset
-G
.expect_ecrec_offset
) <
726 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MissingBytes
),
727 G
.zipfn
, (long)(-G
.extra_bytes
)));
728 error_in_archive
= PK_ERR
;
729 } else if (G
.extra_bytes
> 0) {
730 if ((G
.ecrec
.offset_start_central_directory
== 0) &&
731 (G
.ecrec
.size_central_directory
!= 0)) /* zip 1.5 -go bug */
733 Info(slide
, 0x401, ((char *)slide
,
734 LoadFarString(NullCentDirOffset
), G
.zipfn
));
735 G
.ecrec
.offset_start_central_directory
= G
.extra_bytes
;
737 error_in_archive
= PK_ERR
;
741 Info(slide
, 0x401, ((char *)slide
,
742 LoadFarString(ExtraBytesAtStart
), G
.zipfn
,
743 (long)G
.extra_bytes
, (G
.extra_bytes
== 1)? "":"s"));
744 error_in_archive
= PK_WARN
;
749 /*-----------------------------------------------------------------------
750 Check for empty zipfile and exit now if so.
751 -----------------------------------------------------------------------*/
753 if (G
.expect_ecrec_offset
==0L && G
.ecrec
.size_central_directory
==0) {
755 Info(slide
, 0, ((char *)slide
, "%sEmpty zipfile.\n",
756 uO
.lflag
>9? "\n " : ""));
758 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ZipfileEmpty
),
761 return (error_in_archive
> PK_WARN
)? error_in_archive
: PK_WARN
;
764 /*-----------------------------------------------------------------------
765 Compensate for missing or extra bytes, and seek to where the start
766 of central directory should be. If header not found, uncompensate
767 and try again (necessary for at least some Atari archives created
768 with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
769 -----------------------------------------------------------------------*/
771 error
= seek_zipf(__G__ G
.ecrec
.offset_start_central_directory
);
772 if (error
== PK_BADERR
) {
777 if (error
!= PK_OK
|| readbuf(__G__ G
.sig
, 4) == 0) {
779 return PK_ERR
; /* file may be locked, or possibly disk error(?) */
781 if (strncmp(G
.sig
, central_hdr_sig
, 4))
783 if ((error
!= PK_OK
) || (readbuf(__G__ G
.sig
, 4) == 0) ||
784 strncmp(G
.sig
, central_hdr_sig
, 4))
788 long tmp
= G
.extra_bytes
;
792 error
= seek_zipf(__G__ G
.ecrec
.offset_start_central_directory
);
793 if ((error
!= PK_OK
) || (readbuf(__G__ G
.sig
, 4) == 0) ||
794 strncmp(G
.sig
, central_hdr_sig
, 4))
796 if (error
!= PK_BADERR
)
797 Info(slide
, 0x401, ((char *)slide
,
798 LoadFarString(CentDirStartNotFound
), G
.zipfn
,
799 LoadFarStringSmall(ReportMsg
)));
801 return (error
!= PK_OK
? error
: PK_BADERR
);
804 Info(slide
, 0x401, ((char *)slide
, LoadFarString(CentDirTooLong
),
807 error_in_archive
= PK_ERR
;
810 /*-----------------------------------------------------------------------
811 Seek to the start of the central directory one last time, since we
812 have just read the first entry's signature bytes; then list, extract
813 or test member files as instructed, and close the zipfile.
814 -----------------------------------------------------------------------*/
816 error
= seek_zipf(__G__ G
.ecrec
.offset_start_central_directory
);
817 if (error
!= PK_OK
) {
822 Trace((stderr
, "about to extract/list files (error = %d)\n",
826 /* G.fValidate is used only to look at an archive to see if
827 it appears to be a valid archive. There is no interest
828 in what the archive contains, nor in validating that the
829 entries in the archive are in good condition. This is
830 currently used only in the Windows DLLs for purposes of
831 checking archives within an archive to determine whether
832 or not to display the inner archives.
839 error
= zipinfo(__G
); /* ZIPINFO 'EM */
845 error
= get_time_stamp(__G__
&uxstamp
, &nmember
);
848 if (uO
.vflag
&& !uO
.tflag
&& !uO
.cflag
)
849 error
= list_files(__G
); /* LIST 'EM */
852 error
= extract_or_test_files(__G
); /* EXTRACT OR TEST 'EM */
854 Trace((stderr
, "done with extract/list files (error = %d)\n",
858 if (error
> error_in_archive
) /* don't overwrite stronger error */
859 error_in_archive
= error
; /* with (for example) a warning */
861 } /* end if (!too_weird_to_continue) */
867 if (uO
.T_flag
&& !uO
.zipinfo_mode
&& (nmember
> 0L)) {
869 if (stamp_file(__G__ G
.zipfn
, uxstamp
)) { /* TIME-STAMP 'EM */
871 if (stamp_file(G
.zipfn
, uxstamp
)) { /* TIME-STAMP 'EM */
874 Info(slide
, 0x201, ((char *)slide
,
875 "warning: cannot set time for %s\n", G
.zipfn
));
876 if (error_in_archive
< PK_WARN
)
877 error_in_archive
= PK_WARN
;
881 return error_in_archive
;
883 } /* end function do_seekable() */
889 /*************************/
890 /* Function find_ecrec() */
891 /*************************/
893 static int find_ecrec(__G__ searchlen
) /* return PK-class error */
897 int i
, numblks
, found
=FALSE
;
902 /*---------------------------------------------------------------------------
903 Treat case of short zipfile separately.
904 ---------------------------------------------------------------------------*/
906 if (G
.ziplen
<= INBUFSIZ
) {
907 lseek(G
.zipfd
, 0L, SEEK_SET
);
908 if ((G
.incnt
= read(G
.zipfd
,(char *)G
.inbuf
,(unsigned int)G
.ziplen
))
911 /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */
912 for (G
.inptr
= G
.inbuf
+(int)G
.ziplen
-(ECREC_SIZE
+4);
915 if ( (*G
.inptr
== (uch
)0x50) && /* ASCII 'P' */
916 !strncmp((char *)G
.inptr
, end_central_sig
, 4)) {
917 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
923 /*---------------------------------------------------------------------------
924 Zipfile is longer than INBUFSIZ: may need to loop. Start with short
925 block at end of zipfile (if not TOO short).
926 ---------------------------------------------------------------------------*/
929 if ((tail_len
= G
.ziplen
% INBUFSIZ
) > ECREC_SIZE
) {
930 #ifdef USE_STRM_INPUT
931 fseek((FILE *)G
.zipfd
, G
.ziplen
-tail_len
, SEEK_SET
);
932 G
.cur_zipfile_bufstart
= ftell((FILE *)G
.zipfd
);
933 #else /* !USE_STRM_INPUT */
934 G
.cur_zipfile_bufstart
= lseek(G
.zipfd
, G
.ziplen
-tail_len
,
936 #endif /* ?USE_STRM_INPUT */
937 if ((G
.incnt
= read(G
.zipfd
, (char *)G
.inbuf
,
938 (unsigned int)tail_len
)) != (int)tail_len
)
939 goto fail
; /* it's expedient... */
941 /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */
942 for (G
.inptr
= G
.inbuf
+(int)tail_len
-(ECREC_SIZE
+4);
945 if ( (*G
.inptr
== (uch
)0x50) && /* ASCII 'P' */
946 !strncmp((char *)G
.inptr
, end_central_sig
, 4)) {
947 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
952 /* sig may span block boundary: */
953 memcpy((char *)G
.hold
, (char *)G
.inbuf
, 3);
955 G
.cur_zipfile_bufstart
= G
.ziplen
- tail_len
;
957 /*-----------------------------------------------------------------------
958 Loop through blocks of zipfile data, starting at the end and going
959 toward the beginning. In general, need not check whole zipfile for
960 signature, but may want to do so if testing.
961 -----------------------------------------------------------------------*/
963 numblks
= (int)((searchlen
- tail_len
+ (INBUFSIZ
-1)) / INBUFSIZ
);
964 /* ==amount= ==done== ==rounding== =blksiz= */
966 for (i
= 1; !found
&& (i
<= numblks
); ++i
) {
967 G
.cur_zipfile_bufstart
-= INBUFSIZ
;
968 lseek(G
.zipfd
, G
.cur_zipfile_bufstart
, SEEK_SET
);
969 if ((G
.incnt
= read(G
.zipfd
,(char *)G
.inbuf
,INBUFSIZ
))
971 break; /* fall through and fail */
973 for (G
.inptr
= G
.inbuf
+INBUFSIZ
-1; G
.inptr
>= G
.inbuf
;
975 if ((native(*G
.inptr
) == 'P') &&
976 !strncmp((char *)G
.inptr
, end_central_sig
, 4)) {
977 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
981 /* sig may span block boundary: */
982 memcpy((char *)G
.hold
, (char *)G
.inbuf
, 3);
984 } /* end if (ziplen > INBUFSIZ) */
986 /*---------------------------------------------------------------------------
987 Searched through whole region where signature should be without finding
988 it. Print informational message and die a horrible death.
989 ---------------------------------------------------------------------------*/
993 if (uO
.qflag
|| uO
.zipinfo_mode
)
994 Info(slide
, 0x401, ((char *)slide
, "[%s]\n", G
.zipfn
));
995 Info(slide
, 0x401, ((char *)slide
,
996 LoadFarString(CentDirEndSigNotFound
)));
997 return PK_ERR
; /* failed */
1000 /*---------------------------------------------------------------------------
1001 Found the signature, so get the end-central data before returning. Do
1002 any necessary machine-type conversions (byte ordering, structure padding
1003 compensation) by reading data into character array and copying to struct.
1004 ---------------------------------------------------------------------------*/
1006 G
.real_ecrec_offset
= G
.cur_zipfile_bufstart
+ (G
.inptr
-G
.inbuf
);
1008 printf("\n found end-of-central-dir signature at offset %ld (%.8lXh)\n",
1009 G
.real_ecrec_offset
, G
.real_ecrec_offset
);
1010 printf(" from beginning of file; offset %d (%.4Xh) within block\n",
1011 G
.inptr
-G
.inbuf
, G
.inptr
-G
.inbuf
);
1014 if (readbuf(__G__ (char *)byterec
, ECREC_SIZE
+4) == 0)
1017 G
.ecrec
.number_this_disk
=
1018 makeword(&byterec
[NUMBER_THIS_DISK
]);
1019 G
.ecrec
.num_disk_start_cdir
=
1020 makeword(&byterec
[NUM_DISK_WITH_START_CENTRAL_DIR
]);
1021 G
.ecrec
.num_entries_centrl_dir_ths_disk
=
1022 makeword(&byterec
[NUM_ENTRIES_CENTRL_DIR_THS_DISK
]);
1023 G
.ecrec
.total_entries_central_dir
=
1024 makeword(&byterec
[TOTAL_ENTRIES_CENTRAL_DIR
]);
1025 G
.ecrec
.size_central_directory
=
1026 makelong(&byterec
[SIZE_CENTRAL_DIRECTORY
]);
1027 G
.ecrec
.offset_start_central_directory
=
1028 makelong(&byterec
[OFFSET_START_CENTRAL_DIRECTORY
]);
1029 G
.ecrec
.zipfile_comment_length
=
1030 makeword(&byterec
[ZIPFILE_COMMENT_LENGTH
]);
1032 G
.expect_ecrec_offset
= G
.ecrec
.offset_start_central_directory
+
1033 G
.ecrec
.size_central_directory
;
1036 } /* end function find_ecrec() */
1042 /*****************************/
1043 /* Function uz_end_central() */
1044 /*****************************/
1046 int uz_end_central(__G
) /* return PK-type error code */
1049 int error
= PK_COOL
;
1052 /*---------------------------------------------------------------------------
1053 Get the zipfile comment (up to 64KB long), if any, and print it out.
1054 Then position the file pointer to the beginning of the central directory
1056 ---------------------------------------------------------------------------*/
1059 /* for comment button: */
1060 if ((!G
.fValidate
) && (G
.lpUserFunctions
!= NULL
))
1061 G
.lpUserFunctions
->cchComment
= G
.ecrec
.zipfile_comment_length
;
1062 if (G
.ecrec
.zipfile_comment_length
&& (uO
.zflag
> 0))
1064 if (G
.ecrec
.zipfile_comment_length
&& (uO
.zflag
> 0 ||
1070 #endif /* ?WINDLL */
1072 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1073 if (do_string(__G__ G
.ecrec
.zipfile_comment_length
, CHECK_AUTORUN
)) {
1075 if (do_string(__G__ G
.ecrec
.zipfile_comment_length
, DISPLAY
)) {
1077 Info(slide
, 0x401, ((char *)slide
,
1078 LoadFarString(ZipfileCommTrunc1
)));
1082 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1083 else if (G
.ecrec
.zipfile_comment_length
) {
1084 if (do_string(__G__ G
.ecrec
.zipfile_comment_length
, CHECK_AUTORUN_Q
)) {
1085 Info(slide
, 0x401, ((char *)slide
,
1086 LoadFarString(ZipfileCommTrunc1
)));
1093 } /* end function uz_end_central() */
1099 /************************************/
1100 /* Function process_cdir_file_hdr() */
1101 /************************************/
1103 int process_cdir_file_hdr(__G
) /* return PK-type error code */
1109 /*---------------------------------------------------------------------------
1110 Get central directory info, save host and method numbers, and set flag
1111 for lowercase conversion of filename, depending on the OS from which the
1113 ---------------------------------------------------------------------------*/
1115 if ((error
= get_cdir_ent(__G
)) != 0)
1118 G
.pInfo
->hostver
= G
.crec
.version_made_by
[0];
1119 G
.pInfo
->hostnum
= MIN(G
.crec
.version_made_by
[1], NUM_HOSTS
);
1120 /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
1122 G
.pInfo
->lcflag
= 0;
1123 if (uO
.L_flag
== 1) /* name conversion for monocase systems */
1124 switch (G
.pInfo
->hostnum
) {
1125 case FS_FAT_
: /* PKZIP and zip -k store in uppercase */
1126 case CPM_
: /* like MS-DOS, right? */
1127 case VM_CMS_
: /* all caps? */
1128 case MVS_
: /* all caps? */
1131 case VMS_
: /* our Zip uses lowercase, but ASi's doesn't */
1132 /* case Z_SYSTEM_: ? */
1134 G
.pInfo
->lcflag
= 1; /* convert filename to lowercase */
1137 default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */
1138 break; /* FS_VFAT_, BEOS_ (Z_SYSTEM_), THEOS_: */
1141 else if (uO
.L_flag
> 1) /* let -LL force lower case for all names */
1142 G
.pInfo
->lcflag
= 1;
1144 /* do Amigas (AMIGA_) also have volume labels? */
1145 if (IS_VOLID(G
.crec
.external_file_attributes
) &&
1146 (G
.pInfo
->hostnum
== FS_FAT_
|| G
.pInfo
->hostnum
== FS_HPFS_
||
1147 G
.pInfo
->hostnum
== FS_NTFS_
|| G
.pInfo
->hostnum
== ATARI_
))
1149 G
.pInfo
->vollabel
= TRUE
;
1150 G
.pInfo
->lcflag
= 0; /* preserve case of volume labels */
1152 G
.pInfo
->vollabel
= FALSE
;
1154 /* this flag is needed to detect archives made by "PKZIP for Unix" when
1155 deciding which kind of codepage conversion has to be applied to
1156 strings (see do_string() function in fileio.c) */
1157 G
.pInfo
->HasUxAtt
= (G
.crec
.external_file_attributes
& 0xffff0000L
) != 0L;
1161 } /* end function process_cdir_file_hdr() */
1167 /***************************/
1168 /* Function get_cdir_ent() */
1169 /***************************/
1171 int get_cdir_ent(__G
) /* return PK-type error code */
1174 cdir_byte_hdr byterec
;
1177 /*---------------------------------------------------------------------------
1178 Read the next central directory entry and do any necessary machine-type
1179 conversions (byte ordering, structure padding compensation--do so by
1180 copying the data from the array into which it was read (byterec) to the
1181 usable struct (crec)).
1182 ---------------------------------------------------------------------------*/
1184 if (readbuf(__G__ (char *)byterec
, CREC_SIZE
) == 0)
1187 G
.crec
.version_made_by
[0] = byterec
[C_VERSION_MADE_BY_0
];
1188 G
.crec
.version_made_by
[1] = byterec
[C_VERSION_MADE_BY_1
];
1189 G
.crec
.version_needed_to_extract
[0] =
1190 byterec
[C_VERSION_NEEDED_TO_EXTRACT_0
];
1191 G
.crec
.version_needed_to_extract
[1] =
1192 byterec
[C_VERSION_NEEDED_TO_EXTRACT_1
];
1194 G
.crec
.general_purpose_bit_flag
=
1195 makeword(&byterec
[C_GENERAL_PURPOSE_BIT_FLAG
]);
1196 G
.crec
.compression_method
=
1197 makeword(&byterec
[C_COMPRESSION_METHOD
]);
1198 G
.crec
.last_mod_dos_datetime
=
1199 makelong(&byterec
[C_LAST_MOD_DOS_DATETIME
]);
1201 makelong(&byterec
[C_CRC32
]);
1203 makelong(&byterec
[C_COMPRESSED_SIZE
]);
1205 makelong(&byterec
[C_UNCOMPRESSED_SIZE
]);
1206 G
.crec
.filename_length
=
1207 makeword(&byterec
[C_FILENAME_LENGTH
]);
1208 G
.crec
.extra_field_length
=
1209 makeword(&byterec
[C_EXTRA_FIELD_LENGTH
]);
1210 G
.crec
.file_comment_length
=
1211 makeword(&byterec
[C_FILE_COMMENT_LENGTH
]);
1212 G
.crec
.disk_number_start
=
1213 makeword(&byterec
[C_DISK_NUMBER_START
]);
1214 G
.crec
.internal_file_attributes
=
1215 makeword(&byterec
[C_INTERNAL_FILE_ATTRIBUTES
]);
1216 G
.crec
.external_file_attributes
=
1217 makelong(&byterec
[C_EXTERNAL_FILE_ATTRIBUTES
]); /* LONG, not word! */
1218 G
.crec
.relative_offset_local_header
=
1219 makelong(&byterec
[C_RELATIVE_OFFSET_LOCAL_HEADER
]);
1223 } /* end function get_cdir_ent() */
1229 /*************************************/
1230 /* Function process_local_file_hdr() */
1231 /*************************************/
1233 int process_local_file_hdr(__G
) /* return PK-type error code */
1236 local_byte_hdr byterec
;
1239 /*---------------------------------------------------------------------------
1240 Read the next local file header and do any necessary machine-type con-
1241 versions (byte ordering, structure padding compensation--do so by copy-
1242 ing the data from the array into which it was read (byterec) to the
1243 usable struct (lrec)).
1244 ---------------------------------------------------------------------------*/
1246 if (readbuf(__G__ (char *)byterec
, LREC_SIZE
) == 0)
1249 G
.lrec
.version_needed_to_extract
[0] =
1250 byterec
[L_VERSION_NEEDED_TO_EXTRACT_0
];
1251 G
.lrec
.version_needed_to_extract
[1] =
1252 byterec
[L_VERSION_NEEDED_TO_EXTRACT_1
];
1254 G
.lrec
.general_purpose_bit_flag
=
1255 makeword(&byterec
[L_GENERAL_PURPOSE_BIT_FLAG
]);
1256 G
.lrec
.compression_method
= makeword(&byterec
[L_COMPRESSION_METHOD
]);
1257 G
.lrec
.last_mod_dos_datetime
= makelong(&byterec
[L_LAST_MOD_DOS_DATETIME
]);
1258 G
.lrec
.crc32
= makelong(&byterec
[L_CRC32
]);
1259 G
.lrec
.csize
= makelong(&byterec
[L_COMPRESSED_SIZE
]);
1260 G
.lrec
.ucsize
= makelong(&byterec
[L_UNCOMPRESSED_SIZE
]);
1261 G
.lrec
.filename_length
= makeword(&byterec
[L_FILENAME_LENGTH
]);
1262 G
.lrec
.extra_field_length
= makeword(&byterec
[L_EXTRA_FIELD_LENGTH
]);
1264 if ((G
.lrec
.general_purpose_bit_flag
& 8) != 0) {
1265 /* can't trust local header, use central directory: */
1266 G
.lrec
.crc32
= G
.pInfo
->crc
;
1267 G
.lrec
.csize
= G
.pInfo
->compr_size
;
1268 G
.lrec
.ucsize
= G
.pInfo
->uncompr_size
;
1271 G
.csize
= (long)G
.lrec
.csize
;
1275 } /* end function process_local_file_hdr() */
1278 #ifdef USE_EF_UT_TIME
1280 /*******************************/
1281 /* Function ef_scan_for_izux() */
1282 /*******************************/
1284 unsigned ef_scan_for_izux(ef_buf
, ef_len
, ef_is_c
, dos_mdatetime
,
1286 ZCONST uch
*ef_buf
; /* buffer containing extra field */
1287 unsigned ef_len
; /* total length of extra field */
1288 int ef_is_c
; /* flag indicating "is central extra field" */
1289 ulg dos_mdatetime
; /* last_mod_file_date_time in DOS format */
1290 iztimes
*z_utim
; /* return storage: atime, mtime, ctime */
1291 ush
*z_uidgid
; /* return storage: uid and gid */
1296 int have_new_type_eb
= FALSE
;
1297 long i_time
; /* buffer for Unix style 32-bit integer time value */
1298 #ifdef TIME_T_TYPE_DOUBLE
1299 int ut_in_archive_sgn
= 0;
1301 int ut_zip_unzip_compatible
= FALSE
;
1304 /*---------------------------------------------------------------------------
1305 This function scans the extra field for EF_TIME, EF_IZUNIX2, EF_IZUNIX, or
1306 EF_PKUNIX blocks containing Unix-style time_t (GMT) values for the entry's
1307 access, creation, and modification time.
1308 If a valid block is found, the time stamps are copied to the iztimes
1309 structure (provided the z_utim pointer is not NULL).
1310 If a IZUNIX2 block is found or the IZUNIX block contains UID/GID fields,
1311 and the z_uidgid array pointer is valid (!= NULL), the owner info is
1313 The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring all
1314 data from probably present obsolete EF_IZUNIX blocks.
1315 If multiple blocks of the same type are found, only the information from
1316 the last block is used.
1317 The return value is a combination of the EF_TIME Flags field with an
1318 additional flag bit indicating the presence of valid UID/GID info,
1319 or 0 in case of failure.
1320 ---------------------------------------------------------------------------*/
1322 if (ef_len
== 0 || ef_buf
== NULL
|| (z_utim
== 0 && z_uidgid
== NULL
))
1325 TTrace((stderr
,"\nef_scan_for_izux: scanning extra field of length %u\n",
1328 while (ef_len
>= EB_HEADSIZE
) {
1329 eb_id
= makeword(EB_ID
+ ef_buf
);
1330 eb_len
= makeword(EB_LEN
+ ef_buf
);
1332 if (eb_len
> (ef_len
- EB_HEADSIZE
)) {
1333 /* discovered some extra field inconsistency! */
1335 "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len
,
1336 ef_len
- EB_HEADSIZE
));
1342 flags
&= ~0x0ff; /* ignore previous IZUNIX or EF_TIME fields */
1343 have_new_type_eb
= TRUE
;
1344 if ( eb_len
>= EB_UT_MINLEN
&& z_utim
!= NULL
) {
1345 unsigned eb_idx
= EB_UT_TIME1
;
1346 TTrace((stderr
,"ef_scan_for_izux: found TIME extra field\n"));
1347 flags
|= (ef_buf
[EB_HEADSIZE
+EB_UT_FLAGS
] & 0x0ff);
1348 if ((flags
& EB_UT_FL_MTIME
)) {
1349 if ((eb_idx
+4) <= eb_len
) {
1350 i_time
= (long)makelong((EB_HEADSIZE
+eb_idx
) + ef_buf
);
1352 TTrace((stderr
," UT e.f. modification time = %ld\n",
1355 #ifdef TIME_T_TYPE_DOUBLE
1356 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
1357 if (dos_mdatetime
== DOSTIME_MINIMUM
) {
1358 ut_in_archive_sgn
= -1;
1360 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
1361 } else if (dos_mdatetime
>= DOSTIME_2038_01_18
) {
1362 ut_in_archive_sgn
= 1;
1364 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
1366 ut_in_archive_sgn
= 0;
1367 /* cannot determine sign of mtime;
1368 without modtime: ignore complete UT field */
1369 flags
&= ~0x0ff; /* no time_t times available */
1371 " UT modtime range error; ignore e.f.!\n"));
1372 break; /* stop scanning this field */
1375 /* cannot determine, safe assumption is FALSE */
1376 ut_in_archive_sgn
= 0;
1377 z_utim
->mtime
= (time_t)i_time
;
1379 #else /* !TIME_T_TYPE_DOUBLE */
1380 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
1381 ut_zip_unzip_compatible
=
1382 ((time_t)0x80000000L
< (time_t)0L)
1383 ? (dos_mdatetime
== DOSTIME_MINIMUM
)
1384 : (dos_mdatetime
>= DOSTIME_2038_01_18
);
1385 if (!ut_zip_unzip_compatible
) {
1386 /* UnZip interprets mtime differently than Zip;
1387 without modtime: ignore complete UT field */
1388 flags
&= ~0x0ff; /* no time_t times available */
1390 " UT modtime range error; ignore e.f.!\n"));
1391 break; /* stop scanning this field */
1394 /* cannot determine, safe assumption is FALSE */
1395 ut_zip_unzip_compatible
= FALSE
;
1397 z_utim
->mtime
= (time_t)i_time
;
1398 #endif /* ?TIME_T_TYPE_DOUBLE */
1400 flags
&= ~EB_UT_FL_MTIME
;
1401 TTrace((stderr
," UT e.f. truncated; no modtime\n"));
1405 break; /* central version of TIME field ends here */
1408 if (flags
& EB_UT_FL_ATIME
) {
1409 if ((eb_idx
+4) <= eb_len
) {
1410 i_time
= (long)makelong((EB_HEADSIZE
+eb_idx
) + ef_buf
);
1412 TTrace((stderr
," UT e.f. access time = %ld\n",
1414 #ifdef TIME_T_TYPE_DOUBLE
1415 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
1416 if (ut_in_archive_sgn
== -1)
1418 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
1419 } else if (ut_in_archive_sgn
== 1) {
1421 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
1423 /* sign of 32-bit time is unknown -> ignore it */
1424 flags
&= ~EB_UT_FL_ATIME
;
1426 " UT access time range error: skip time!\n"));
1429 z_utim
->atime
= (time_t)i_time
;
1431 #else /* !TIME_T_TYPE_DOUBLE */
1432 if (((ulg
)(i_time
) & (ulg
)(0x80000000L
)) &&
1433 !ut_zip_unzip_compatible
) {
1434 flags
&= ~EB_UT_FL_ATIME
;
1436 " UT access time range error: skip time!\n"));
1438 z_utim
->atime
= (time_t)i_time
;
1440 #endif /* ?TIME_T_TYPE_DOUBLE */
1442 flags
&= ~EB_UT_FL_ATIME
;
1445 if (flags
& EB_UT_FL_CTIME
) {
1446 if ((eb_idx
+4) <= eb_len
) {
1447 i_time
= (long)makelong((EB_HEADSIZE
+eb_idx
) + ef_buf
);
1448 TTrace((stderr
," UT e.f. creation time = %ld\n",
1450 #ifdef TIME_T_TYPE_DOUBLE
1451 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
1452 if (ut_in_archive_sgn
== -1)
1454 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
1455 } else if (ut_in_archive_sgn
== 1) {
1457 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
1459 /* sign of 32-bit time is unknown -> ignore it */
1460 flags
&= ~EB_UT_FL_CTIME
;
1462 " UT creation time range error: skip time!\n"));
1465 z_utim
->ctime
= (time_t)i_time
;
1467 #else /* !TIME_T_TYPE_DOUBLE */
1468 if (((ulg
)(i_time
) & (ulg
)(0x80000000L
)) &&
1469 !ut_zip_unzip_compatible
) {
1470 flags
&= ~EB_UT_FL_CTIME
;
1472 " UT creation time range error: skip time!\n"));
1474 z_utim
->ctime
= (time_t)i_time
;
1476 #endif /* ?TIME_T_TYPE_DOUBLE */
1478 flags
&= ~EB_UT_FL_CTIME
;
1485 if (!have_new_type_eb
) {
1486 flags
&= ~0x0ff; /* ignore any previous IZUNIX field */
1487 have_new_type_eb
= TRUE
;
1489 if (eb_len
>= EB_UX2_MINLEN
&& z_uidgid
!= NULL
) {
1490 z_uidgid
[0] = makeword((EB_HEADSIZE
+EB_UX2_UID
) + ef_buf
);
1491 z_uidgid
[1] = makeword((EB_HEADSIZE
+EB_UX2_GID
) + ef_buf
);
1492 flags
|= EB_UX2_VALID
; /* signal success */
1497 case EF_PKUNIX
: /* PKUNIX e.f. layout is identical to IZUNIX */
1498 if (eb_len
>= EB_UX_MINLEN
) {
1499 TTrace((stderr
,"ef_scan_for_izux: found %s extra field\n",
1500 (eb_id
== EF_IZUNIX
? "IZUNIX" : "PKUNIX")));
1501 if (have_new_type_eb
) {
1502 break; /* Ignore IZUNIX extra field block ! */
1504 if (z_utim
!= NULL
) {
1505 flags
|= (EB_UT_FL_MTIME
| EB_UT_FL_ATIME
);
1506 i_time
= (long)makelong((EB_HEADSIZE
+EB_UX_MTIME
)+ef_buf
);
1507 TTrace((stderr
," Unix EF modtime = %ld\n", i_time
));
1508 #ifdef TIME_T_TYPE_DOUBLE
1509 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
1510 if (dos_mdatetime
== DOSTIME_MINIMUM
) {
1511 ut_in_archive_sgn
= -1;
1513 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
1514 } else if (dos_mdatetime
>= DOSTIME_2038_01_18
) {
1515 ut_in_archive_sgn
= 1;
1517 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
1519 ut_in_archive_sgn
= 0;
1520 /* cannot determine sign of mtime;
1521 without modtime: ignore complete UT field */
1522 flags
&= ~0x0ff; /* no time_t times available */
1524 " UX modtime range error: ignore e.f.!\n"));
1527 /* cannot determine, safe assumption is FALSE */
1528 ut_in_archive_sgn
= 0;
1529 z_utim
->mtime
= (time_t)i_time
;
1531 #else /* !TIME_T_TYPE_DOUBLE */
1532 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
1533 ut_zip_unzip_compatible
=
1534 ((time_t)0x80000000L
< (time_t)0L)
1535 ? (dos_mdatetime
== DOSTIME_MINIMUM
)
1536 : (dos_mdatetime
>= DOSTIME_2038_01_18
);
1537 if (!ut_zip_unzip_compatible
) {
1538 /* UnZip interpretes mtime differently than Zip;
1539 without modtime: ignore complete UT field */
1540 flags
&= ~0x0ff; /* no time_t times available */
1542 " UX modtime range error: ignore e.f.!\n"));
1545 /* cannot determine, safe assumption is FALSE */
1546 ut_zip_unzip_compatible
= FALSE
;
1548 z_utim
->mtime
= (time_t)i_time
;
1549 #endif /* ?TIME_T_TYPE_DOUBLE */
1550 i_time
= (long)makelong((EB_HEADSIZE
+EB_UX_ATIME
)+ef_buf
);
1551 TTrace((stderr
," Unix EF actime = %ld\n", i_time
));
1552 #ifdef TIME_T_TYPE_DOUBLE
1553 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
1554 if (ut_in_archive_sgn
== -1)
1556 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
1557 } else if (ut_in_archive_sgn
== 1) {
1559 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
1560 } else if (flags
& 0x0ff) {
1561 /* sign of 32-bit time is unknown -> ignore it */
1562 flags
&= ~EB_UT_FL_ATIME
;
1564 " UX access time range error: skip time!\n"));
1567 z_utim
->atime
= (time_t)i_time
;
1569 #else /* !TIME_T_TYPE_DOUBLE */
1570 if (((ulg
)(i_time
) & (ulg
)(0x80000000L
)) &&
1571 !ut_zip_unzip_compatible
&& (flags
& 0x0ff)) {
1572 /* atime not in range of UnZip's time_t */
1573 flags
&= ~EB_UT_FL_ATIME
;
1575 " UX access time range error: skip time!\n"));
1577 z_utim
->atime
= (time_t)i_time
;
1579 #endif /* ?TIME_T_TYPE_DOUBLE */
1581 if (eb_len
>= EB_UX_FULLSIZE
&& z_uidgid
!= NULL
) {
1582 z_uidgid
[0] = makeword((EB_HEADSIZE
+EB_UX_UID
) + ef_buf
);
1583 z_uidgid
[1] = makeword((EB_HEADSIZE
+EB_UX_GID
) + ef_buf
);
1584 flags
|= EB_UX2_VALID
;
1593 /* Skip this extra field block */
1594 ef_buf
+= (eb_len
+ EB_HEADSIZE
);
1595 ef_len
-= (eb_len
+ EB_HEADSIZE
);
1601 #endif /* USE_EF_UT_TIME */
1604 #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
1606 #define SPARKID_2 0x30435241 /* = "ARC0" */
1608 /*******************************/
1609 /* Function getRISCOSexfield() */
1610 /*******************************/
1612 zvoid
*getRISCOSexfield(ef_buf
, ef_len
)
1613 ZCONST uch
*ef_buf
; /* buffer containing extra field */
1614 unsigned ef_len
; /* total length of extra field */
1619 /*---------------------------------------------------------------------------
1620 This function scans the extra field for a Acorn SPARK filetype ef-block.
1621 If a valid block is found, the function returns a pointer to the start
1622 of the SPARK_EF block in the extra field buffer. Otherwise, a NULL
1623 pointer is returned.
1624 ---------------------------------------------------------------------------*/
1626 if (ef_len
== 0 || ef_buf
== NULL
)
1629 TTrace((stderr
,"\ngetRISCOSexfield: scanning extra field of length %u\n",
1632 while (ef_len
>= EB_HEADSIZE
) {
1633 eb_id
= makeword(EB_ID
+ ef_buf
);
1634 eb_len
= makeword(EB_LEN
+ ef_buf
);
1636 if (eb_len
> (ef_len
- EB_HEADSIZE
)) {
1637 /* discovered some extra field inconsistency! */
1639 "getRISCOSexfield: block length %u > rest ef_size %u\n", eb_len
,
1640 ef_len
- EB_HEADSIZE
));
1644 if (eb_id
== EF_SPARK
&& (eb_len
== 24 || eb_len
== 20)) {
1645 if (makelong(EB_HEADSIZE
+ ef_buf
) == SPARKID_2
) {
1646 /* Return a pointer to the valid SPARK filetype ef block */
1647 return (zvoid
*)ef_buf
;
1651 /* Skip this extra field block */
1652 ef_buf
+= (eb_len
+ EB_HEADSIZE
);
1653 ef_len
-= (eb_len
+ EB_HEADSIZE
);
1659 #endif /* (RISCOS || ACORN_FTYPE_NFS) */