2 Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
4 See the accompanying file LICENSE, version 2009-Jan-02 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()
23 process_cdir_file_hdr()
25 process_local_file_hdr()
30 ---------------------------------------------------------------------------*/
33 #define UNZIP_INTERNAL
37 # include "wince/intrface.h"
39 # include "windll/windll.h"
42 #if defined(DYNALLOC_CRCTAB) || defined(UNICODE_SUPPORT)
46 #include "unzipfx/appDetails.h"
48 static int do_seekable
OF((__GPRO__
int lastchance
));
49 #ifdef DO_SAFECHECK_2GB
50 # ifdef USE_STRM_INPUT
51 static zoff_t file_size
OF((FILE *file
));
53 static zoff_t file_size
OF((int fh
));
55 #endif /* DO_SAFECHECK_2GB */
56 static int rec_find
OF((__GPRO__ zoff_t
, char *, int));
57 static int find_ecrec64
OF((__GPRO__ zoff_t searchlen
));
58 static int find_ecrec
OF((__GPRO__ zoff_t searchlen
));
59 static int process_zip_cmmnt
OF((__GPRO
));
60 static int get_cdir_ent
OF((__GPRO
));
61 #ifdef IZ_HAVE_UXUIDGID
62 static int read_ux3_value
OF((ZCONST uch
*dbuf
, unsigned uidgid_sz
,
64 #endif /* IZ_HAVE_UXUIDGID */
67 static ZCONST
char Far CannotAllocateBuffers
[] =
68 "error: cannot allocate unzip buffers\n";
71 static ZCONST
char Far CannotFindMyself
[] =
72 "unzipsfx: cannot find myself! [%s]\n";
73 # ifdef CHEAP_SFX_AUTORUN
74 static ZCONST
char Far AutorunPrompt
[] =
75 "\nAuto-run command: %s\nExecute this command? [y/n] ";
76 static ZCONST
char Far NotAutoRunning
[] =
77 "Not executing auto-run command.";
81 /* process_zipfiles() strings */
82 # if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
83 static ZCONST
char Far WarnInvalidTZ
[] =
84 "Warning: TZ environment variable not found, cannot use UTC times!!\n";
86 # if !(defined(UNIX) || defined(AMIGA))
87 static ZCONST
char Far CannotFindWildcardMatch
[] =
88 "%s: cannot find any matches for wildcard specification \"%s\".\n";
89 # endif /* !(UNIX || AMIGA) */
90 static ZCONST
char Far FilesProcessOK
[] =
91 "%d archive%s successfully processed.\n";
92 static ZCONST
char Far ArchiveWarning
[] =
93 "%d archive%s had warnings but no fatal errors.\n";
94 static ZCONST
char Far ArchiveFatalError
[] =
95 "%d archive%s had fatal errors.\n";
96 static ZCONST
char Far FileHadNoZipfileDir
[] =
97 "%d file%s had no zipfile directory.\n";
98 static ZCONST
char Far ZipfileWasDir
[] = "1 \"zipfile\" was a directory.\n";
99 static ZCONST
char Far ManyZipfilesWereDir
[] =
100 "%d \"zipfiles\" were directories.\n";
101 static ZCONST
char Far NoZipfileFound
[] = "No zipfiles found.\n";
103 /* do_seekable() strings */
105 static ZCONST
char Far CannotFindZipfileDirMsg
[] =
106 "%s: cannot find zipfile directory in one of %s or\n\
107 %s%s.zip, and cannot find %s, period.\n";
108 static ZCONST
char Far CannotFindEitherZipfile
[] =
109 "%s: cannot find or open %s, %s.zip or %s.\n";
111 static ZCONST
char Far CannotFindZipfileDirMsg
[] =
112 "%s: cannot find zipfile directory in %s,\n\
113 %sand cannot find %s, period.\n";
115 static ZCONST
char Far CannotFindEitherZipfile
[] =
116 "%s: cannot find %s (%s).\n";
118 static ZCONST
char Far CannotFindEitherZipfile
[] =
119 "%s: cannot find either %s or %s.\n";
122 extern ZCONST
char Far Zipnfo
[]; /* in unzip.c */
124 static ZCONST
char Far Unzip
[] = "unzip";
126 static ZCONST
char Far Unzip
[] = "UnZip DLL";
128 #ifdef DO_SAFECHECK_2GB
129 static ZCONST
char Far ZipfileTooBig
[] =
130 "Trying to read large file (> 2 GiB) without large file support\n";
131 #endif /* DO_SAFECHECK_2GB */
132 static ZCONST
char Far MaybeExe
[] =
133 "note: %s may be a plain executable, not an archive\n";
134 static ZCONST
char Far CentDirNotInZipMsg
[] = "\n\
136 Zipfile is disk %lu of a multi-disk archive, and this is not the disk on\n\
137 which the central zipfile directory begins (disk %lu).\n";
138 static ZCONST
char Far EndCentDirBogus
[] =
139 "\nwarning [%s]: end-of-central-directory record claims this\n\
140 is disk %lu but that the central directory starts on disk %lu; this is a\n\
141 contradiction. Attempting to process anyway.\n";
143 static ZCONST
char Far NoMultiDiskArcSupport
[] =
144 "\nerror [%s]: zipfile is part of multi-disk archive\n\
145 (sorry, not yet supported).\n";
146 static ZCONST
char Far MaybePakBug
[] = "warning [%s]:\
147 zipfile claims to be 2nd disk of a 2-part archive;\n\
148 attempting to process anyway. If no further errors occur, this archive\n\
149 was probably created by PAK v2.51 or earlier. This bug was reported to\n\
150 NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\
151 of mid-1992 it still hadn't been. (If further errors do occur, archive\n\
152 was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\
153 multi-part archives.)\n";
155 static ZCONST
char Far MaybePakBug
[] = "warning [%s]:\
156 zipfile claims to be last disk of a multi-part archive;\n\
157 attempting to process anyway, assuming all parts have been concatenated\n\
158 together in order. Expect \"errors\" and warnings...true multi-part support\
159 \n doesn't exist yet (coming soon).\n";
161 static ZCONST
char Far ExtraBytesAtStart
[] =
162 "warning [%s]: %s extra byte%s at beginning or within zipfile\n\
163 (attempting to process anyway)\n";
166 #if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO))
167 static ZCONST
char Far LogInitline
[] = "Archive: %s\n";
170 static ZCONST
char Far MissingBytes
[] =
171 "error [%s]: missing %s bytes in zipfile\n\
172 (attempting to process anyway)\n";
173 static ZCONST
char Far NullCentDirOffset
[] =
174 "error [%s]: NULL central directory offset\n\
175 (attempting to process anyway)\n";
176 static ZCONST
char Far ZipfileEmpty
[] = "warning [%s]: zipfile is empty\n";
177 static ZCONST
char Far CentDirStartNotFound
[] =
178 "error [%s]: start of central directory not found;\n\
179 zipfile corrupt.\n%s";
180 static ZCONST
char Far Cent64EndSigSearchErr
[] =
181 "fatal error: read failure while seeking for End-of-centdir-64 signature.\n\
182 This zipfile is corrupt.\n";
183 static ZCONST
char Far Cent64EndSigSearchOff
[] =
184 "error: End-of-centdir-64 signature not where expected (prepended bytes?)\n\
185 (attempting to process anyway)\n";
187 static ZCONST
char Far CentDirTooLong
[] =
188 "error [%s]: reported length of central directory is\n\
189 %s bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1\n\
190 zipfile?). Compensating...\n";
191 static ZCONST
char Far CentDirEndSigNotFound
[] = "\
192 End-of-central-directory signature not found. Either this file is not\n\
193 a zipfile, or it constitutes one disk of a multi-part archive. In the\n\
194 latter case the central directory and zipfile comment will be found on\n\
195 the last disk(s) of this archive.\n";
197 static ZCONST
char Far CentDirEndSigNotFound
[] =
198 " End-of-central-directory signature not found.\n";
201 static ZCONST
char Far ZipTimeStampFailed
[] =
202 "warning: cannot set time for %s\n";
203 static ZCONST
char Far ZipTimeStampSuccess
[] =
204 "Updated time stamp for %s.\n";
206 static ZCONST
char Far ZipfileCommTrunc1
[] =
207 "\ncaution: zipfile comment truncated\n";
209 static ZCONST
char Far NoZipfileComment
[] =
210 "There is no zipfile comment.\n";
211 static ZCONST
char Far ZipfileCommentDesc
[] =
212 "The zipfile comment is %u bytes long and contains the following text:\n";
213 static ZCONST
char Far ZipfileCommBegin
[] =
214 "======================== zipfile comment begins\
215 ==========================\n";
216 static ZCONST
char Far ZipfileCommEnd
[] =
217 "========================= zipfile comment ends\
218 ===========================\n";
219 static ZCONST
char Far ZipfileCommTrunc2
[] =
220 "\n The zipfile comment is truncated.\n";
221 #endif /* !NO_ZIPINFO */
222 #ifdef UNICODE_SUPPORT
223 static ZCONST
char Far UnicodeVersionError
[] =
224 "\nwarning: Unicode Path version > 1\n";
225 static ZCONST
char Far UnicodeMismatchError
[] =
226 "\nwarning: Unicode Path checksum invalid\n";
232 /*******************************/
233 /* Function process_zipfiles() */
234 /*******************************/
236 int process_zipfiles(__G
) /* return PK-type error code */
240 char *lastzipfn
= (char *)NULL
;
241 int NumWinFiles
, NumLoseFiles
, NumWarnFiles
;
242 int NumMissDirs
, NumMissFiles
;
244 int error
=0, error_in_archive
=0;
247 /*---------------------------------------------------------------------------
248 Start by allocating buffers and (re)constructing the various PK signature
250 ---------------------------------------------------------------------------*/
252 G
.inbuf
= (uch
*)malloc(INBUFSIZ
+ 4); /* 4 extra for hold[] (below) */
253 G
.outbuf
= (uch
*)malloc(OUTBUFSIZ
+ 1); /* 1 extra for string term. */
255 if ((G
.inbuf
== (uch
*)NULL
) || (G
.outbuf
== (uch
*)NULL
)) {
256 Info(slide
, 0x401, ((char *)slide
,
257 LoadFarString(CannotAllocateBuffers
)));
260 G
.hold
= G
.inbuf
+ INBUFSIZ
; /* to check for boundary-spanning sigs */
261 #ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */
263 G
.outbuf2
= G
.outbuf
+RAWBUFSIZ
; /* never changes */
267 #if 0 /* CRC_32_TAB has been NULLified by CONSTRUCTGLOBALS !!!! */
268 /* allocate the CRC table later when we know we can read zipfile data */
272 /* finish up initialization of magic signature strings */
273 local_hdr_sig
[0] /* = extd_local_sig[0] */ = /* ASCII 'P', */
274 central_hdr_sig
[0] = end_central_sig
[0] = /* not EBCDIC */
275 end_centloc64_sig
[0] = end_central64_sig
[0] = 0x50;
277 local_hdr_sig
[1] /* = extd_local_sig[1] */ = /* ASCII 'K', */
278 central_hdr_sig
[1] = end_central_sig
[1] = /* not EBCDIC */
279 end_centloc64_sig
[1] = end_central64_sig
[1] = 0x4B;
281 /*---------------------------------------------------------------------------
282 Make sure timezone info is set correctly; localtime() returns GMT on some
283 OSes (e.g., Solaris 2.x) if this isn't done first. The ifdefs around
284 tzset() were initially copied from dos_to_unix_time() in fileio.c. They
285 may still be too strict; any listed OS that supplies tzset(), regardless
286 of whether the function does anything, should be removed from the ifdefs.
287 ---------------------------------------------------------------------------*/
289 #if (defined(WIN32) && defined(USE_EF_UT_TIME))
290 /* For the Win32 environment, we may have to "prepare" the environment
291 prior to the tzset() call, to work around tzset() implementation bugs.
293 iz_w32_prepareTZenv();
296 #if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
297 # ifndef VALID_TIMEZONE
298 # define VALID_TIMEZONE(tmp) \
299 (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0'))
303 G
.tz_is_valid
= VALID_TIMEZONE(p
);
305 if (!G
.tz_is_valid
) {
306 Info(slide
, 0x401, ((char *)slide
, LoadFarString(WarnInvalidTZ
)));
307 error_in_archive
= error
= PK_WARN
;
311 #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
313 /* For systems that do not have tzset() but supply this function using another
314 name (_tzset() or something similar), an appropiate "#define tzset ..."
315 should be added to the system specifc configuration section. */
316 #if (!defined(T20_VMS) && !defined(MACOS) && !defined(RISCOS) && !defined(QDOS))
317 #if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM))
322 /* Initialize UnZip's built-in pseudo hard-coded "ISO <--> OEM" translation,
323 depending on the detected codepage setup. */
324 #ifdef NEED_ISO_OEM_INIT
325 prepare_ISO_OEM_translat(__G
);
328 /*---------------------------------------------------------------------------
329 Initialize the internal flag holding the mode of processing "overwrite
330 existing file" cases. We do not use the calling interface flags directly
331 because the overwrite mode may be changed by user interaction while
332 processing archive files. Such a change should not affect the option
333 settings as passed through the DLL calling interface.
334 In case of conflicting options, the 'safer' flag uO.overwrite_none takes
336 ---------------------------------------------------------------------------*/
337 G
.overwrite_mode
= (uO
.overwrite_none
? OVERWRT_NEVER
:
338 (uO
.overwrite_all
? OVERWRT_ALWAYS
: OVERWRT_QUERY
));
340 /*---------------------------------------------------------------------------
341 Match (possible) wildcard zipfile specification with existing files and
342 attempt to process each. If no hits, try again after appending ".zip"
343 suffix. If still no luck, give up.
344 ---------------------------------------------------------------------------*/
347 if ((error
= do_seekable(__G__
0)) == PK_NOZIP
) {
349 int len
=strlen(G
.argv0
);
351 /* append .exe if appropriate; also .sfx? */
352 if ( (G
.zipfn
= (char *)malloc(len
+sizeof(EXE_EXTENSION
))) !=
354 strcpy(G
.zipfn
, G
.argv0
);
355 strcpy(G
.zipfn
+len
, EXE_EXTENSION
);
356 error
= do_seekable(__G__
0);
358 G
.zipfn
= G
.argv0
; /* for "cannot find myself" message only */
360 #endif /* EXE_EXTENSION */
362 G
.zipfn
= G
.argv0
; /* for "cannot find myself" message only */
367 error_in_archive
= PK_NOZIP
;
369 error_in_archive
= error
;
370 if (error
== PK_NOZIP
)
371 Info(slide
, 1, ((char *)slide
, LoadFarString(CannotFindMyself
),
374 #ifdef CHEAP_SFX_AUTORUN
375 if (G
.autorun_command
[0] && !uO
.qflag
) { /* NO autorun without prompt! */
376 Info(slide
, 0x81, ((char *)slide
, LoadFarString(AutorunPrompt
),
377 FnFilter1(G
.autorun_command
)));
378 if (fgets(G
.answerbuf
, 9, stdin
) != (char *)NULL
379 && toupper(*G
.answerbuf
) == 'Y')
380 system(G
.autorun_command
);
382 Info(slide
, 1, ((char *)slide
, LoadFarString(NotAutoRunning
)));
384 #endif /* CHEAP_SFX_AUTORUN */
386 int sfx_app_ret
= sfx_app_autorun_now();
389 NumWinFiles
= NumLoseFiles
= NumWarnFiles
= 0;
390 NumMissDirs
= NumMissFiles
= 0;
392 while ((G
.zipfn
= do_wild(__G__ G
.wildzipfn
)) != (char *)NULL
) {
393 Trace((stderr
, "do_wild( %s ) returns %s\n", G
.wildzipfn
, G
.zipfn
));
397 /* print a blank line between the output of different zipfiles */
398 if (!uO
.qflag
&& error
!= PK_NOZIP
&& error
!= IZ_DIR
400 && (!uO
.T_flag
|| uO
.zipinfo_mode
)
402 && (NumWinFiles
+NumLoseFiles
+NumWarnFiles
+NumMissFiles
) > 0)
403 (*G
.message
)((zvoid
*)&G
, (uch
*)"\n", 1L, 0);
405 if ((error
= do_seekable(__G__
0)) == PK_WARN
)
407 else if (error
== IZ_DIR
)
409 else if (error
== PK_NOZIP
)
411 else if (error
!= PK_OK
)
416 Trace((stderr
, "do_seekable(0) returns %d\n", error
));
417 if (error
!= IZ_DIR
&& error
> error_in_archive
)
418 error_in_archive
= error
;
420 if (error
== IZ_CTRLC
) {
426 } /* end while-loop (wildcard zipfiles) */
428 if ((NumWinFiles
+ NumWarnFiles
+ NumLoseFiles
) == 0 &&
429 (NumMissDirs
+ NumMissFiles
) == 1 && lastzipfn
!= (char *)NULL
)
431 #if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */
432 if (iswild(G
.wildzipfn
)) {
433 if (iswild(lastzipfn
)) {
434 NumMissDirs
= NumMissFiles
= 0;
435 error_in_archive
= PK_COOL
;
437 Info(slide
, 0x401, ((char *)slide
,
438 LoadFarString(CannotFindWildcardMatch
),
439 LoadFarStringSmall((uO
.zipinfo_mode
? Zipnfo
: Unzip
)),
447 * VMS has already tried a default file type of ".zip" in
448 * do_wild(), so adding ZSUFX here only causes confusion by
449 * corrupting some valid (though nonexistent) file names.
450 * Complaining below about "fred;4.zip" is unlikely to be
451 * helpful to the victim.
453 /* 2005-08-14 Chr. Spieler
454 * Although we already "know" the failure result, we call
455 * do_seekable() again with the same zipfile name (and the
456 * lastchance flag set), just to trigger the error report...
458 #if defined(UNIX) || defined(QDOS)
461 strcpy(lastzipfn
+ strlen(lastzipfn
), ZSUFX
);
466 NumMissDirs
= NumMissFiles
= 0;
467 error_in_archive
= PK_COOL
;
469 #if defined(UNIX) || defined(QDOS)
470 /* only Unix has case-sensitive filesystems */
471 /* Well FlexOS (sometimes) also has them, but support is per media */
472 /* and a pig to code for, so treat as case insensitive for now */
473 /* we do this under QDOS to check for .zip as well as _zip */
474 if ((error
= do_seekable(__G__
0)) == PK_NOZIP
|| error
== IZ_DIR
) {
477 strcpy(p
, ALT_ZSUFX
);
478 error
= do_seekable(__G__
1);
481 error
= do_seekable(__G__
1);
483 Trace((stderr
, "do_seekable(1) returns %d\n", error
));
493 /* increment again => bug:
494 "1 file had no zipfile directory." */
495 /* ++NumMissFiles */ ;
505 if (error
> error_in_archive
)
506 error_in_archive
= error
;
508 if (error
== IZ_CTRLC
) {
517 /*---------------------------------------------------------------------------
518 Print summary of all zipfiles, assuming zipfile spec was a wildcard (no
519 need for a summary if just one zipfile).
520 ---------------------------------------------------------------------------*/
523 if (iswild(G
.wildzipfn
) && uO
.qflag
< 3
525 && !(uO
.T_flag
&& !uO
.zipinfo_mode
&& uO
.qflag
> 1)
529 if ((NumMissFiles
+ NumLoseFiles
+ NumWarnFiles
> 0 || NumWinFiles
!= 1)
531 && !(uO
.T_flag
&& !uO
.zipinfo_mode
&& uO
.qflag
)
533 && !(uO
.tflag
&& uO
.qflag
> 1))
534 (*G
.message
)((zvoid
*)&G
, (uch
*)"\n", 1L, 0x401);
535 if ((NumWinFiles
> 1) ||
537 NumMissDirs
+ NumMissFiles
+ NumLoseFiles
+ NumWarnFiles
> 0))
538 Info(slide
, 0x401, ((char *)slide
, LoadFarString(FilesProcessOK
),
539 NumWinFiles
, (NumWinFiles
== 1)? " was" : "s were"));
540 if (NumWarnFiles
> 0)
541 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ArchiveWarning
),
542 NumWarnFiles
, (NumWarnFiles
== 1)? "" : "s"));
543 if (NumLoseFiles
> 0)
544 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ArchiveFatalError
),
545 NumLoseFiles
, (NumLoseFiles
== 1)? "" : "s"));
546 if (NumMissFiles
> 0)
547 Info(slide
, 0x401, ((char *)slide
,
548 LoadFarString(FileHadNoZipfileDir
), NumMissFiles
,
549 (NumMissFiles
== 1)? "" : "s"));
550 if (NumMissDirs
== 1)
551 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ZipfileWasDir
)));
552 else if (NumMissDirs
> 0)
553 Info(slide
, 0x401, ((char *)slide
,
554 LoadFarString(ManyZipfilesWereDir
), NumMissDirs
));
555 if (NumWinFiles
+ NumLoseFiles
+ NumWarnFiles
== 0)
556 Info(slide
, 0x401, ((char *)slide
, LoadFarString(NoZipfileFound
)));
560 /* free allocated memory */
565 } /* end function process_zipfiles() */
571 /*****************************/
572 /* Function free_G_buffers() */
573 /*****************************/
575 void free_G_buffers(__G
) /* releases all memory allocated in global vars */
582 #ifdef SYSTEM_SPECIFIC_DTOR
583 SYSTEM_SPECIFIC_DTOR(__G
);
587 checkdir(__G__ (char *)NULL
, END
);
589 #ifdef DYNALLOC_CRCTAB
596 if (G
.key
!= (char *)NULL
) {
598 G
.key
= (char *)NULL
;
601 if (G
.extra_field
!= (uch
*)NULL
) {
603 G
.extra_field
= (uch
*)NULL
;
606 #if (!defined(VMS) && !defined(SMALL_MEM))
607 /* VMS uses its own buffer scheme for textmode flush() */
609 free(G
.outbuf2
); /* malloc'd ONLY if unshrink and -a */
610 G
.outbuf2
= (uch
*)NULL
;
618 G
.inbuf
= G
.outbuf
= (uch
*)NULL
;
620 #ifdef UNICODE_SUPPORT
621 if (G
.filename_full
) {
622 free(G
.filename_full
);
623 G
.filename_full
= (char *)NULL
;
624 G
.fnfull_bufsize
= 0;
626 #endif /* UNICODE_SUPPORT */
629 for (i
= 0; i
< DIR_BLKSIZ
; i
++) {
630 if (G
.info
[i
].cfilname
!= (char Far
*)NULL
) {
631 zffree(G
.info
[i
].cfilname
);
632 G
.info
[i
].cfilname
= (char Far
*)NULL
;
640 G
.area
.Slide
= (uch
*)NULL
;
644 } /* end function free_G_buffers() */
650 /**************************/
651 /* Function do_seekable() */
652 /**************************/
654 static int do_seekable(__G__ lastchance
) /* return PK-type error code */
659 /* static int no_ecrec = FALSE; SKM: moved to globals.h */
661 int too_weird_to_continue
=FALSE
;
667 int error
=0, error_in_archive
;
670 /*---------------------------------------------------------------------------
671 Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
672 which would corrupt the bit streams.
673 ---------------------------------------------------------------------------*/
675 if (SSTAT(G
.zipfn
, &G
.statbuf
) ||
677 (error
= S_ISLIB(G
.statbuf
.st_mode
)) != 0 ||
679 (error
= S_ISDIR(G
.statbuf
.st_mode
)) != 0)
682 if (lastchance
&& (uO
.qflag
< 3)) {
683 #if defined(UNIX) || defined(QDOS)
685 Info(slide
, 1, ((char *)slide
,
686 LoadFarString(CannotFindZipfileDirMsg
),
687 LoadFarStringSmall((uO
.zipinfo_mode
? Zipnfo
: Unzip
)),
688 G
.wildzipfn
, uO
.zipinfo_mode
? " " : "", G
.wildzipfn
,
691 Info(slide
, 1, ((char *)slide
,
692 LoadFarString(CannotFindEitherZipfile
),
693 LoadFarStringSmall((uO
.zipinfo_mode
? Zipnfo
: Unzip
)),
694 G
.wildzipfn
, G
.wildzipfn
, G
.zipfn
));
695 #else /* !(UNIX || QDOS) */
697 Info(slide
, 0x401, ((char *)slide
,
698 LoadFarString(CannotFindZipfileDirMsg
),
699 LoadFarStringSmall((uO
.zipinfo_mode
? Zipnfo
: Unzip
)),
700 G
.wildzipfn
, uO
.zipinfo_mode
? " " : "", G
.zipfn
));
703 Info(slide
, 0x401, ((char *)slide
,
704 LoadFarString(CannotFindEitherZipfile
),
705 LoadFarStringSmall((uO
.zipinfo_mode
? Zipnfo
: Unzip
)),
707 (*G
.zipfn
? G
.zipfn
: vms_msg_text())));
709 Info(slide
, 0x401, ((char *)slide
,
710 LoadFarString(CannotFindEitherZipfile
),
711 LoadFarStringSmall((uO
.zipinfo_mode
? Zipnfo
: Unzip
)),
712 G
.wildzipfn
, G
.zipfn
));
714 #endif /* ?(UNIX || QDOS) */
717 return error
? IZ_DIR
: PK_NOZIP
;
719 G
.ziplen
= G
.statbuf
.st_size
;
722 #if defined(UNIX) || defined(DOS_OS2_W32) || defined(THEOS)
723 if (G
.statbuf
.st_mode
& S_IEXEC
) /* no extension on Unix exes: might */
724 maybe_exe
= TRUE
; /* find unzip, not unzip.zip; etc. */
729 if (check_format(__G
)) /* check for variable-length format */
733 if (open_input_file(__G
)) /* this should never happen, given */
734 return PK_NOZIP
; /* the stat() test above, but... */
736 #ifdef DO_SAFECHECK_2GB
737 /* Need more care: Do not trust the size returned by stat() but
738 determine it by reading beyond the end of the file. */
739 G
.ziplen
= file_size(G
.zipfd
);
741 if (G
.ziplen
== EOF
) {
742 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ZipfileTooBig
)));
745 " We need a better error message for: 64-bit file, 32-bit program.\n");
750 #endif /* DO_SAFECHECK_2GB */
752 /*---------------------------------------------------------------------------
753 Find and process the end-of-central-directory header. UnZip need only
754 check last 65557 bytes of zipfile: comment may be up to 65535, end-of-
755 central-directory record is 18 bytes, and signature itself is 4 bytes;
756 add some to allow for appended garbage. Since ZipInfo is often used as
757 a debugging tool, search the whole zipfile if zipinfo_mode is true.
758 ---------------------------------------------------------------------------*/
760 G
.cur_zipfile_bufstart
= 0;
763 #if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO))
764 # if (!defined(WINDLL) && !defined(SFX))
765 if ( (!uO
.zipinfo_mode
&& !uO
.qflag
771 || (uO
.zipinfo_mode
&& uO
.hflag
)
774 # else /* not (!WINDLL && !SFX) ==> !NO_ZIPINFO !! */
775 if (uO
.zipinfo_mode
&& uO
.hflag
)
776 # endif /* if..else..: (!WINDLL && !SFX) */
777 # ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */
778 Info(slide
, 0, ((char *)slide
, LoadFarString(LogInitline
),
779 FnFilter1(G
.zipfn
)));
781 Info(slide
, 0, ((char *)slide
, LoadFarString(LogInitline
), G
.zipfn
));
783 #endif /* (!WINDLL && !SFX) || !NO_ZIPINFO */
785 if ( (error_in_archive
= find_ecrec(__G__
787 uO
.zipinfo_mode
? G
.ziplen
:
789 MIN(G
.ziplen
, 66000L)))
795 ++lastchance
; /* avoid picky compiler warnings */
796 return error_in_archive
;
799 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybeExe
),
802 return error_in_archive
;
804 G
.no_ecrec
= TRUE
; /* assume we found wrong file: e.g., */
805 return PK_NOZIP
; /* unzip instead of unzip.zip */
810 if ((uO
.zflag
> 0) && !uO
.zipinfo_mode
) { /* unzip: zflag = comment ONLY */
812 return error_in_archive
;
815 /*---------------------------------------------------------------------------
816 Test the end-of-central-directory info for incompatibilities (multi-disk
817 archives) or inconsistencies (missing or extra bytes in zipfile).
818 ---------------------------------------------------------------------------*/
821 error
= !uO
.zipinfo_mode
&& (G
.ecrec
.number_this_disk
== 1) &&
822 (G
.ecrec
.num_disk_start_cdir
== 1);
824 error
= !uO
.zipinfo_mode
&& (G
.ecrec
.number_this_disk
!= 0);
828 if (uO
.zipinfo_mode
&&
829 G
.ecrec
.number_this_disk
!= G
.ecrec
.num_disk_start_cdir
)
831 if (G
.ecrec
.number_this_disk
> G
.ecrec
.num_disk_start_cdir
) {
832 Info(slide
, 0x401, ((char *)slide
,
833 LoadFarString(CentDirNotInZipMsg
), G
.zipfn
,
834 (ulg
)G
.ecrec
.number_this_disk
,
835 (ulg
)G
.ecrec
.num_disk_start_cdir
));
836 error_in_archive
= PK_FIND
;
837 too_weird_to_continue
= TRUE
;
839 Info(slide
, 0x401, ((char *)slide
,
840 LoadFarString(EndCentDirBogus
), G
.zipfn
,
841 (ulg
)G
.ecrec
.number_this_disk
,
842 (ulg
)G
.ecrec
.num_disk_start_cdir
));
843 error_in_archive
= PK_WARN
;
845 #ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */
846 } else if (!uO
.zipinfo_mode
&& !error
&& G
.ecrec
.number_this_disk
!= 0) {
847 Info(slide
, 0x401, ((char *)slide
, LoadFarString(NoMultiDiskArcSupport
),
849 error_in_archive
= PK_FIND
;
850 too_weird_to_continue
= TRUE
;
854 if (!too_weird_to_continue
) { /* (relatively) normal zipfile: go for it */
856 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MaybePakBug
),
858 error_in_archive
= PK_WARN
;
861 if ((G
.extra_bytes
= G
.real_ecrec_offset
-G
.expect_ecrec_offset
) <
864 Info(slide
, 0x401, ((char *)slide
, LoadFarString(MissingBytes
),
865 G
.zipfn
, FmZofft((-G
.extra_bytes
), NULL
, NULL
)));
866 error_in_archive
= PK_ERR
;
867 } else if (G
.extra_bytes
> 0) {
868 if ((G
.ecrec
.offset_start_central_directory
== 0) &&
869 (G
.ecrec
.size_central_directory
!= 0)) /* zip 1.5 -go bug */
871 Info(slide
, 0x401, ((char *)slide
,
872 LoadFarString(NullCentDirOffset
), G
.zipfn
));
873 G
.ecrec
.offset_start_central_directory
= G
.extra_bytes
;
875 error_in_archive
= PK_ERR
;
879 Info(slide
, 0x401, ((char *)slide
,
880 LoadFarString(ExtraBytesAtStart
), G
.zipfn
,
881 FmZofft(G
.extra_bytes
, NULL
, NULL
),
882 (G
.extra_bytes
== 1)? "":"s"));
883 error_in_archive
= PK_WARN
;
888 /*-----------------------------------------------------------------------
889 Check for empty zipfile and exit now if so.
890 -----------------------------------------------------------------------*/
892 if (G
.expect_ecrec_offset
==0L && G
.ecrec
.size_central_directory
==0) {
894 Info(slide
, 0, ((char *)slide
, "%sEmpty zipfile.\n",
895 uO
.lflag
>9? "\n " : ""));
897 Info(slide
, 0x401, ((char *)slide
, LoadFarString(ZipfileEmpty
),
900 return (error_in_archive
> PK_WARN
)? error_in_archive
: PK_WARN
;
903 /*-----------------------------------------------------------------------
904 Compensate for missing or extra bytes, and seek to where the start
905 of central directory should be. If header not found, uncompensate
906 and try again (necessary for at least some Atari archives created
907 with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
908 -----------------------------------------------------------------------*/
910 error
= seek_zipf(__G__ G
.ecrec
.offset_start_central_directory
);
911 if (error
== PK_BADERR
) {
916 if (error
!= PK_OK
|| readbuf(__G__ G
.sig
, 4) == 0) {
918 return PK_ERR
; /* file may be locked, or possibly disk error(?) */
920 if (memcmp(G
.sig
, central_hdr_sig
, 4))
922 if ((error
!= PK_OK
) || (readbuf(__G__ G
.sig
, 4) == 0) ||
923 memcmp(G
.sig
, central_hdr_sig
, 4))
927 zoff_t tmp
= G
.extra_bytes
;
931 error
= seek_zipf(__G__ G
.ecrec
.offset_start_central_directory
);
932 if ((error
!= PK_OK
) || (readbuf(__G__ G
.sig
, 4) == 0) ||
933 memcmp(G
.sig
, central_hdr_sig
, 4))
935 if (error
!= PK_BADERR
)
936 Info(slide
, 0x401, ((char *)slide
,
937 LoadFarString(CentDirStartNotFound
), G
.zipfn
,
938 LoadFarStringSmall(ReportMsg
)));
940 return (error
!= PK_OK
? error
: PK_BADERR
);
943 Info(slide
, 0x401, ((char *)slide
, LoadFarString(CentDirTooLong
),
944 G
.zipfn
, FmZofft((-tmp
), NULL
, NULL
)));
946 error_in_archive
= PK_ERR
;
949 /*-----------------------------------------------------------------------
950 Seek to the start of the central directory one last time, since we
951 have just read the first entry's signature bytes; then list, extract
952 or test member files as instructed, and close the zipfile.
953 -----------------------------------------------------------------------*/
955 error
= seek_zipf(__G__ G
.ecrec
.offset_start_central_directory
);
956 if (error
!= PK_OK
) {
961 Trace((stderr
, "about to extract/list files (error = %d)\n",
965 /* G.fValidate is used only to look at an archive to see if
966 it appears to be a valid archive. There is no interest
967 in what the archive contains, nor in validating that the
968 entries in the archive are in good condition. This is
969 currently used only in the Windows DLLs for purposes of
970 checking archives within an archive to determine whether
971 or not to display the inner archives.
978 error
= zipinfo(__G
); /* ZIPINFO 'EM */
984 error
= get_time_stamp(__G__
&uxstamp
, &nmember
);
987 if (uO
.vflag
&& !uO
.tflag
&& !uO
.cflag
)
988 error
= list_files(__G
); /* LIST 'EM */
991 error
= extract_or_test_files(__G
); /* EXTRACT OR TEST 'EM */
993 Trace((stderr
, "done with extract/list files (error = %d)\n",
997 if (error
> error_in_archive
) /* don't overwrite stronger error */
998 error_in_archive
= error
; /* with (for example) a warning */
1000 } /* end if (!too_weird_to_continue) */
1006 if (uO
.T_flag
&& !uO
.zipinfo_mode
&& (nmember
> 0L)) {
1008 if (stamp_file(__G__ G
.zipfn
, uxstamp
)) { /* TIME-STAMP 'EM */
1010 if (stamp_file(G
.zipfn
, uxstamp
)) { /* TIME-STAMP 'EM */
1013 Info(slide
, 0x201, ((char *)slide
,
1014 LoadFarString(ZipTimeStampFailed
), G
.zipfn
));
1015 if (error_in_archive
< PK_WARN
)
1016 error_in_archive
= PK_WARN
;
1019 Info(slide
, 0, ((char *)slide
,
1020 LoadFarString(ZipTimeStampSuccess
), G
.zipfn
));
1024 return error_in_archive
;
1026 } /* end function do_seekable() */
1031 #ifdef DO_SAFECHECK_2GB
1032 /************************/
1033 /* Function file_size() */
1034 /************************/
1035 /* File size determination which does not mislead for large files in a
1036 small-file program. Probably should be somewhere else.
1037 The file has to be opened previously
1039 #ifdef USE_STRM_INPUT
1040 static zoff_t
file_size(file
)
1045 #else /* !USE_STRM_INPUT */
1046 static zoff_t
file_size(fh
)
1050 #endif /* ?USE_STRM_INPUT */
1054 #ifdef USE_STRM_INPUT
1055 /* Seek to actual EOF. */
1056 sts
= zfseeko(file
, 0, SEEK_END
);
1058 /* fseeko() failed. (Unlikely.) */
1061 /* Get apparent offset at EOF. */
1062 ofs
= zftello(file
);
1064 /* Offset negative (overflow). File too big. */
1067 /* Seek to apparent EOF offset.
1068 Won't be at actual EOF if offset was truncated.
1070 sts
= zfseeko(file
, ofs
, SEEK_SET
);
1072 /* fseeko() failed. (Unlikely.) */
1075 /* Read a byte at apparent EOF. Should set EOF flag. */
1076 siz
= fread(waste
, 1, 1, file
);
1077 if (feof(file
) == 0) {
1078 /* Not at EOF, but should be. File too big. */
1084 #else /* !USE_STRM_INPUT */
1085 /* Seek to actual EOF. */
1086 ofs
= zlseek(fh
, 0, SEEK_END
);
1087 if (ofs
== (zoff_t
) -1) {
1088 /* zlseek() failed. (Unlikely.) */
1090 } else if (ofs
< 0) {
1091 /* Offset negative (overflow). File too big. */
1094 /* Seek to apparent EOF offset.
1095 Won't be at actual EOF if offset was truncated.
1097 ofs
= zlseek(fh
, ofs
, SEEK_SET
);
1098 if (ofs
== (zoff_t
) -1) {
1099 /* zlseek() failed. (Unlikely.) */
1102 /* Read a byte at apparent EOF. Should set EOF flag. */
1103 siz
= read(fh
, waste
, 1);
1105 /* Not at EOF, but should be. File too big. */
1110 #endif /* ?USE_STRM_INPUT */
1112 } /* end function file_size() */
1113 #endif /* DO_SAFECHECK_2GB */
1118 /***********************/
1119 /* Function rec_find() */
1120 /***********************/
1122 static int rec_find(__G__ searchlen
, signature
, rec_size
)
1123 /* return 0 when rec found, 1 when not found, 2 in case of read error */
1129 int i
, numblks
, found
=FALSE
;
1132 /*---------------------------------------------------------------------------
1133 Zipfile is longer than INBUFSIZ: may need to loop. Start with short
1134 block at end of zipfile (if not TOO short).
1135 ---------------------------------------------------------------------------*/
1137 if ((tail_len
= G
.ziplen
% INBUFSIZ
) > rec_size
) {
1138 #ifdef USE_STRM_INPUT
1139 zfseeko(G
.zipfd
, G
.ziplen
-tail_len
, SEEK_SET
);
1140 G
.cur_zipfile_bufstart
= zftello(G
.zipfd
);
1141 #else /* !USE_STRM_INPUT */
1142 G
.cur_zipfile_bufstart
= zlseek(G
.zipfd
, G
.ziplen
-tail_len
, SEEK_SET
);
1143 #endif /* ?USE_STRM_INPUT */
1144 if ((G
.incnt
= read(G
.zipfd
, (char *)G
.inbuf
,
1145 (unsigned int)tail_len
)) != (int)tail_len
)
1146 return 2; /* it's expedient... */
1148 /* 'P' must be at least (rec_size+4) bytes from end of zipfile */
1149 for (G
.inptr
= G
.inbuf
+(int)tail_len
-(rec_size
+4);
1152 if ( (*G
.inptr
== (uch
)0x50) && /* ASCII 'P' */
1153 !memcmp((char *)G
.inptr
, signature
, 4) ) {
1154 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
1159 /* sig may span block boundary: */
1160 memcpy((char *)G
.hold
, (char *)G
.inbuf
, 3);
1162 G
.cur_zipfile_bufstart
= G
.ziplen
- tail_len
;
1164 /*-----------------------------------------------------------------------
1165 Loop through blocks of zipfile data, starting at the end and going
1166 toward the beginning. In general, need not check whole zipfile for
1167 signature, but may want to do so if testing.
1168 -----------------------------------------------------------------------*/
1170 numblks
= (int)((searchlen
- tail_len
+ (INBUFSIZ
-1)) / INBUFSIZ
);
1171 /* ==amount= ==done== ==rounding== =blksiz= */
1173 for (i
= 1; !found
&& (i
<= numblks
); ++i
) {
1174 G
.cur_zipfile_bufstart
-= INBUFSIZ
;
1175 #ifdef USE_STRM_INPUT
1176 zfseeko(G
.zipfd
, G
.cur_zipfile_bufstart
, SEEK_SET
);
1177 #else /* !USE_STRM_INPUT */
1178 zlseek(G
.zipfd
, G
.cur_zipfile_bufstart
, SEEK_SET
);
1179 #endif /* ?USE_STRM_INPUT */
1180 if ((G
.incnt
= read(G
.zipfd
,(char *)G
.inbuf
,INBUFSIZ
))
1182 return 2; /* read error is fatal failure */
1184 for (G
.inptr
= G
.inbuf
+INBUFSIZ
-1; G
.inptr
>= G
.inbuf
; --G
.inptr
)
1185 if ( (*G
.inptr
== (uch
)0x50) && /* ASCII 'P' */
1186 !memcmp((char *)G
.inptr
, signature
, 4) ) {
1187 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
1191 /* sig may span block boundary: */
1192 memcpy((char *)G
.hold
, (char *)G
.inbuf
, 3);
1194 return (found
? 0 : 1);
1195 } /* end function rec_find() */
1201 /********************************/
1202 /* Function check_ecrec_zip64() */
1203 /********************************/
1205 static int check_ecrec_zip64(__G
)
1208 return G
.ecrec
.offset_start_central_directory
== 0xFFFFFFFFL
1209 || G
.ecrec
.size_central_directory
== 0xFFFFFFFFL
1210 || G
.ecrec
.total_entries_central_dir
== 0xFFFF
1211 || G
.ecrec
.num_entries_centrl_dir_ths_disk
== 0xFFFF
1212 || G
.ecrec
.num_disk_start_cdir
== 0xFFFF
1213 || G
.ecrec
.number_this_disk
== 0xFFFF;
1214 } /* end function check_ecrec_zip64() */
1219 /***************************/
1220 /* Function find_ecrec64() */
1221 /***************************/
1223 static int find_ecrec64(__G__ searchlen
) /* return PK-class error */
1227 ec_byte_rec64 byterec
; /* buf for ecrec64 */
1228 ec_byte_loc64 byterecL
; /* buf for ecrec64 locator */
1229 zoff_t ecloc64_start_offset
; /* start offset of ecrec64 locator */
1230 zusz_t ecrec64_start_offset
; /* start offset of ecrec64 */
1231 zuvl_t ecrec64_start_disk
; /* start disk of ecrec64 */
1232 zuvl_t ecloc64_total_disks
; /* total disks */
1233 zuvl_t ecrec64_disk_cdstart
; /* disk number of central dir start */
1234 zucn_t ecrec64_this_entries
; /* entries on disk with ecrec64 */
1235 zucn_t ecrec64_tot_entries
; /* total number of entries */
1236 zusz_t ecrec64_cdirsize
; /* length of central dir */
1237 zusz_t ecrec64_offs_cdstart
; /* offset of central dir start */
1239 /* First, find the ecrec64 locator. By definition, this must be before
1240 ecrec with nothing in between. We back up the size of the ecrec64
1241 locator and check. */
1243 ecloc64_start_offset
= G
.real_ecrec_offset
- (ECLOC64_SIZE
+4);
1244 if (ecloc64_start_offset
< 0)
1245 /* Seeking would go past beginning, so probably empty archive */
1248 #ifdef USE_STRM_INPUT
1249 zfseeko(G
.zipfd
, ecloc64_start_offset
, SEEK_SET
);
1250 G
.cur_zipfile_bufstart
= zftello(G
.zipfd
);
1251 #else /* !USE_STRM_INPUT */
1252 G
.cur_zipfile_bufstart
= zlseek(G
.zipfd
, ecloc64_start_offset
, SEEK_SET
);
1253 #endif /* ?USE_STRM_INPUT */
1255 if ((G
.incnt
= read(G
.zipfd
, (char *)byterecL
, ECLOC64_SIZE
+4))
1256 != (ECLOC64_SIZE
+4)) {
1257 if (uO
.qflag
|| uO
.zipinfo_mode
)
1258 Info(slide
, 0x401, ((char *)slide
, "[%s]\n", G
.zipfn
));
1259 Info(slide
, 0x401, ((char *)slide
,
1260 LoadFarString(Cent64EndSigSearchErr
)));
1264 if (memcmp((char *)byterecL
, end_centloc64_sig
, 4) ) {
1269 /* Read the locator. */
1270 ecrec64_start_disk
= (zuvl_t
)makelong(&byterecL
[NUM_DISK_START_EOCDR64
]);
1271 ecrec64_start_offset
= (zusz_t
)makeint64(&byterecL
[OFFSET_START_EOCDR64
]);
1272 ecloc64_total_disks
= (zuvl_t
)makelong(&byterecL
[NUM_THIS_DISK_LOC64
]);
1274 /* Check for consistency */
1276 fprintf(stdout
,"\nnumber of disks (ECR) %u, (ECLOC64) %lu\n",
1277 G
.ecrec
.number_this_disk
, ecloc64_total_disks
); fflush(stdout
);
1279 if ((G
.ecrec
.number_this_disk
!= 0xFFFF) &&
1280 (G
.ecrec
.number_this_disk
!= ecloc64_total_disks
- 1)) {
1281 /* Note: For some unknown reason, the developers at PKWARE decided to
1282 store the "zip64 total disks" value as a counter starting from 1,
1283 whereas all other "split/span volume" related fields use 0-based
1284 volume numbers. Sigh... */
1285 /* When the total number of disks as found in the traditional ecrec
1286 is not 0xFFFF, the disk numbers in ecrec and ecloc64 must match.
1287 When this is not the case, the found ecrec64 locator cannot be valid.
1288 -> This is not a Zip64 archive.
1291 "\ninvalid ECLOC64, differing disk# (ECR %u, ECL64 %lu)\n",
1292 G
.ecrec
.number_this_disk
, ecloc64_total_disks
- 1));
1296 /* If found locator, look for ecrec64 where the locator says it is. */
1298 /* For now assume that ecrec64 is on the same disk as ecloc64 and ecrec,
1299 which is usually the case and is how Zip writes it. To do this right,
1300 however, we should allow the ecrec64 to be on another disk since
1301 the AppNote allows it and the ecrec64 can be large, especially if
1302 Version 2 is used (AppNote uses 8 bytes for the size of this record). */
1304 /* FIX BELOW IF ADD SUPPORT FOR MULTIPLE DISKS */
1306 if (ecrec64_start_offset
> (zusz_t
)ecloc64_start_offset
) {
1307 /* ecrec64 has to be before ecrec64 locator */
1308 if (uO
.qflag
|| uO
.zipinfo_mode
)
1309 Info(slide
, 0x401, ((char *)slide
, "[%s]\n", G
.zipfn
));
1310 Info(slide
, 0x401, ((char *)slide
,
1311 LoadFarString(Cent64EndSigSearchErr
)));
1315 #ifdef USE_STRM_INPUT
1316 zfseeko(G
.zipfd
, ecrec64_start_offset
, SEEK_SET
);
1317 G
.cur_zipfile_bufstart
= zftello(G
.zipfd
);
1318 #else /* !USE_STRM_INPUT */
1319 G
.cur_zipfile_bufstart
= zlseek(G
.zipfd
, ecrec64_start_offset
, SEEK_SET
);
1320 #endif /* ?USE_STRM_INPUT */
1322 if ((G
.incnt
= read(G
.zipfd
, (char *)byterec
, ECREC64_SIZE
+4))
1323 != (ECREC64_SIZE
+4)) {
1324 if (uO
.qflag
|| uO
.zipinfo_mode
)
1325 Info(slide
, 0x401, ((char *)slide
, "[%s]\n", G
.zipfn
));
1326 Info(slide
, 0x401, ((char *)slide
,
1327 LoadFarString(Cent64EndSigSearchErr
)));
1331 if (memcmp((char *)byterec
, end_central64_sig
, 4) ) {
1332 /* Zip64 EOCD Record not found */
1333 /* Since we already have seen the Zip64 EOCD Locator, it's
1334 possible we got here because there are bytes prepended
1335 to the archive, like the sfx prefix. */
1337 /* Make a guess as to where the Zip64 EOCD Record might be */
1338 ecrec64_start_offset
= ecloc64_start_offset
- ECREC64_SIZE
- 4;
1340 #ifdef USE_STRM_INPUT
1341 zfseeko(G
.zipfd
, ecrec64_start_offset
, SEEK_SET
);
1342 G
.cur_zipfile_bufstart
= zftello(G
.zipfd
);
1343 #else /* !USE_STRM_INPUT */
1344 G
.cur_zipfile_bufstart
= zlseek(G
.zipfd
, ecrec64_start_offset
, SEEK_SET
);
1345 #endif /* ?USE_STRM_INPUT */
1347 if ((G
.incnt
= read(G
.zipfd
, (char *)byterec
, ECREC64_SIZE
+4))
1348 != (ECREC64_SIZE
+4)) {
1349 if (uO
.qflag
|| uO
.zipinfo_mode
)
1350 Info(slide
, 0x401, ((char *)slide
, "[%s]\n", G
.zipfn
));
1351 Info(slide
, 0x401, ((char *)slide
,
1352 LoadFarString(Cent64EndSigSearchErr
)));
1356 if (memcmp((char *)byterec
, end_central64_sig
, 4) ) {
1357 /* Zip64 EOCD Record not found */
1358 /* Probably something not so easy to handle so exit */
1359 if (uO
.qflag
|| uO
.zipinfo_mode
)
1360 Info(slide
, 0x401, ((char *)slide
, "[%s]\n", G
.zipfn
));
1361 Info(slide
, 0x401, ((char *)slide
,
1362 LoadFarString(Cent64EndSigSearchErr
)));
1366 if (uO
.qflag
|| uO
.zipinfo_mode
)
1367 Info(slide
, 0x401, ((char *)slide
, "[%s]\n", G
.zipfn
));
1368 Info(slide
, 0x401, ((char *)slide
,
1369 LoadFarString(Cent64EndSigSearchOff
)));
1372 /* Check consistency of found ecrec64 with ecloc64 (and ecrec): */
1373 if ( (zuvl_t
)makelong(&byterec
[NUMBER_THIS_DSK_REC64
])
1374 != ecrec64_start_disk
)
1375 /* found ecrec64 does not match ecloc64 info -> no Zip64 archive */
1377 /* Read all relevant ecrec64 fields and compare them to the corresponding
1378 ecrec fields unless those are set to "all-ones".
1380 ecrec64_disk_cdstart
=
1381 (zuvl_t
)makelong(&byterec
[NUM_DISK_START_CEN_DIR64
]);
1382 if ( (G
.ecrec
.num_disk_start_cdir
!= 0xFFFF) &&
1383 (G
.ecrec
.num_disk_start_cdir
!= ecrec64_disk_cdstart
) )
1385 ecrec64_this_entries
1386 = makeint64(&byterec
[NUM_ENTRIES_CEN_DIR_THS_DISK64
]);
1387 if ( (G
.ecrec
.num_entries_centrl_dir_ths_disk
!= 0xFFFF) &&
1388 (G
.ecrec
.num_entries_centrl_dir_ths_disk
!= ecrec64_this_entries
) )
1391 = makeint64(&byterec
[TOTAL_ENTRIES_CENTRAL_DIR64
]);
1392 if ( (G
.ecrec
.total_entries_central_dir
!= 0xFFFF) &&
1393 (G
.ecrec
.total_entries_central_dir
!= ecrec64_tot_entries
) )
1396 = makeint64(&byterec
[SIZE_CENTRAL_DIRECTORY64
]);
1397 if ( (G
.ecrec
.size_central_directory
!= 0xFFFFFFFFL
) &&
1398 (G
.ecrec
.size_central_directory
!= ecrec64_cdirsize
) )
1400 ecrec64_offs_cdstart
1401 = makeint64(&byterec
[OFFSET_START_CENTRAL_DIRECT64
]);
1402 if ( (G
.ecrec
.offset_start_central_directory
!= 0xFFFFFFFFL
) &&
1403 (G
.ecrec
.offset_start_central_directory
!= ecrec64_offs_cdstart
) )
1406 /* Now, we are (almost) sure that we have a Zip64 archive. */
1407 G
.ecrec
.have_ecr64
= 1;
1409 /* Update the "end-of-central-dir offset" for later checks. */
1410 G
.real_ecrec_offset
= ecrec64_start_offset
;
1412 /* Update all ecdir_rec data that are flagged to be invalid
1413 in Zip64 mode. Set the ecrec64-mandatory flag when such a
1415 if (G
.ecrec
.number_this_disk
== 0xFFFF) {
1416 G
.ecrec
.number_this_disk
= ecrec64_start_disk
;
1417 if (ecrec64_start_disk
!= 0xFFFF) G
.ecrec
.is_zip64_archive
= TRUE
;
1419 if (G
.ecrec
.num_disk_start_cdir
== 0xFFFF) {
1420 G
.ecrec
.num_disk_start_cdir
= ecrec64_disk_cdstart
;
1421 if (ecrec64_disk_cdstart
!= 0xFFFF) G
.ecrec
.is_zip64_archive
= TRUE
;
1423 if (G
.ecrec
.num_entries_centrl_dir_ths_disk
== 0xFFFF) {
1424 G
.ecrec
.num_entries_centrl_dir_ths_disk
= ecrec64_this_entries
;
1425 if (ecrec64_this_entries
!= 0xFFFF) G
.ecrec
.is_zip64_archive
= TRUE
;
1427 if (G
.ecrec
.total_entries_central_dir
== 0xFFFF) {
1428 G
.ecrec
.total_entries_central_dir
= ecrec64_tot_entries
;
1429 if (ecrec64_tot_entries
!= 0xFFFF) G
.ecrec
.is_zip64_archive
= TRUE
;
1431 if (G
.ecrec
.size_central_directory
== 0xFFFFFFFFL
) {
1432 G
.ecrec
.size_central_directory
= ecrec64_cdirsize
;
1433 if (ecrec64_cdirsize
!= 0xFFFFFFFF) G
.ecrec
.is_zip64_archive
= TRUE
;
1435 if (G
.ecrec
.offset_start_central_directory
== 0xFFFFFFFFL
) {
1436 G
.ecrec
.offset_start_central_directory
= ecrec64_offs_cdstart
;
1437 if (ecrec64_offs_cdstart
!= 0xFFFFFFFF) G
.ecrec
.is_zip64_archive
= TRUE
;
1441 } /* end function find_ecrec64() */
1445 /*************************/
1446 /* Function find_ecrec() */
1447 /*************************/
1449 static int find_ecrec(__G__ searchlen
) /* return PK-class error */
1454 int error_in_archive
;
1456 ec_byte_rec byterec
;
1458 /*---------------------------------------------------------------------------
1459 Treat case of short zipfile separately.
1460 ---------------------------------------------------------------------------*/
1462 if (G
.ziplen
<= INBUFSIZ
) {
1463 #ifdef USE_STRM_INPUT
1464 zfseeko(G
.zipfd
, 0L, SEEK_SET
);
1465 #else /* !USE_STRM_INPUT */
1466 zlseek(G
.zipfd
, 0L, SEEK_SET
);
1467 #endif /* ?USE_STRM_INPUT */
1468 if ((G
.incnt
= read(G
.zipfd
,(char *)G
.inbuf
,(unsigned int)G
.ziplen
))
1471 /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */
1472 for (G
.inptr
= G
.inbuf
+(int)G
.ziplen
-(ECREC_SIZE
+4);
1475 if ( (*G
.inptr
== (uch
)0x50) && /* ASCII 'P' */
1476 !memcmp((char *)G
.inptr
, end_central_sig
, 4)) {
1477 G
.incnt
-= (int)(G
.inptr
- G
.inbuf
);
1483 /*---------------------------------------------------------------------------
1484 Zipfile is longer than INBUFSIZ:
1486 MB - this next block of code moved to rec_find so that same code can be
1487 used to look for zip64 ec record. No need to include code above since
1488 a zip64 ec record will only be looked for if it is a BIG file.
1489 ---------------------------------------------------------------------------*/
1493 (rec_find(__G__ searchlen
, end_central_sig
, ECREC_SIZE
) == 0
1495 } /* end if (ziplen > INBUFSIZ) */
1497 /*---------------------------------------------------------------------------
1498 Searched through whole region where signature should be without finding
1499 it. Print informational message and die a horrible death.
1500 ---------------------------------------------------------------------------*/
1503 if (uO
.qflag
|| uO
.zipinfo_mode
)
1504 Info(slide
, 0x401, ((char *)slide
, "[%s]\n", G
.zipfn
));
1505 Info(slide
, 0x401, ((char *)slide
,
1506 LoadFarString(CentDirEndSigNotFound
)));
1507 return PK_ERR
; /* failed */
1510 /*---------------------------------------------------------------------------
1511 Found the signature, so get the end-central data before returning. Do
1512 any necessary machine-type conversions (byte ordering, structure padding
1513 compensation) by reading data into character array and copying to struct.
1514 ---------------------------------------------------------------------------*/
1516 G
.real_ecrec_offset
= G
.cur_zipfile_bufstart
+ (G
.inptr
-G
.inbuf
);
1518 printf("\n found end-of-central-dir signature at offset %s (%sh)\n",
1519 FmZofft(G
.real_ecrec_offset
, NULL
, NULL
),
1520 FmZofft(G
.real_ecrec_offset
, FZOFFT_HEX_DOT_WID
, "X"));
1521 printf(" from beginning of file; offset %d (%.4Xh) within block\n",
1522 G
.inptr
-G
.inbuf
, G
.inptr
-G
.inbuf
);
1525 if (readbuf(__G__ (char *)byterec
, ECREC_SIZE
+4) == 0)
1528 G
.ecrec
.number_this_disk
=
1529 makeword(&byterec
[NUMBER_THIS_DISK
]);
1530 G
.ecrec
.num_disk_start_cdir
=
1531 makeword(&byterec
[NUM_DISK_WITH_START_CEN_DIR
]);
1532 G
.ecrec
.num_entries_centrl_dir_ths_disk
=
1533 makeword(&byterec
[NUM_ENTRIES_CEN_DIR_THS_DISK
]);
1534 G
.ecrec
.total_entries_central_dir
=
1535 makeword(&byterec
[TOTAL_ENTRIES_CENTRAL_DIR
]);
1536 G
.ecrec
.size_central_directory
=
1537 makelong(&byterec
[SIZE_CENTRAL_DIRECTORY
]);
1538 G
.ecrec
.offset_start_central_directory
=
1539 makelong(&byterec
[OFFSET_START_CENTRAL_DIRECTORY
]);
1540 G
.ecrec
.zipfile_comment_length
=
1541 makeword(&byterec
[ZIPFILE_COMMENT_LENGTH
]);
1543 /* Now, we have to read the archive comment, BEFORE the file pointer
1544 is moved away backwards to seek for a Zip64 ECLOC64 structure.
1546 if ( (error_in_archive
= process_zip_cmmnt(__G
)) > PK_WARN
)
1547 return error_in_archive
;
1549 /* Next: Check for existence of Zip64 end-of-cent-dir locator
1550 ECLOC64. This structure must reside on the same volume as the
1551 classic ECREC, at exactly (ECLOC64_SIZE+4) bytes in front
1553 The ECLOC64 structure directs to the longer ECREC64 structure
1554 A ECREC64 will ALWAYS exist for a proper Zip64 archive, as
1555 the "Version Needed To Extract" field is required to be set
1556 to 4.5 or higher whenever any Zip64 features are used anywhere
1557 in the archive, so just check for that to see if this is a
1560 result
= find_ecrec64(__G__ searchlen
+76);
1561 /* 76 bytes for zip64ec & zip64 locator */
1562 if (result
!= PK_COOL
) {
1563 if (error_in_archive
< result
)
1564 error_in_archive
= result
;
1565 return error_in_archive
;
1568 G
.expect_ecrec_offset
= G
.ecrec
.offset_start_central_directory
+
1569 G
.ecrec
.size_central_directory
;
1572 if (uO
.zipinfo_mode
) {
1573 /* In ZipInfo mode, additional info about the data found in the
1574 end-of-central-directory areas is printed out.
1576 zi_end_central(__G
);
1580 return error_in_archive
;
1582 } /* end function find_ecrec() */
1588 /********************************/
1589 /* Function process_zip_cmmnt() */
1590 /********************************/
1592 static int process_zip_cmmnt(__G
) /* return PK-type error code */
1595 int error
= PK_COOL
;
1598 /*---------------------------------------------------------------------------
1599 Get the zipfile comment (up to 64KB long), if any, and print it out.
1600 ---------------------------------------------------------------------------*/
1603 /* for comment button: */
1604 if ((!G
.fValidate
) && (G
.lpUserFunctions
!= NULL
))
1605 G
.lpUserFunctions
->cchComment
= G
.ecrec
.zipfile_comment_length
;
1609 /* ZipInfo, verbose format */
1610 if (uO
.zipinfo_mode
&& uO
.lflag
> 9) {
1611 /*-------------------------------------------------------------------
1612 Get the zipfile comment, if any, and print it out.
1613 (Comment may be up to 64KB long. May the fleas of a thousand
1614 camels infest the arm-pits of anyone who actually takes advantage
1616 -------------------------------------------------------------------*/
1618 if (!G
.ecrec
.zipfile_comment_length
)
1619 Info(slide
, 0, ((char *)slide
, LoadFarString(NoZipfileComment
)));
1621 Info(slide
, 0, ((char *)slide
, LoadFarString(ZipfileCommentDesc
),
1622 G
.ecrec
.zipfile_comment_length
));
1623 Info(slide
, 0, ((char *)slide
, LoadFarString(ZipfileCommBegin
)));
1624 if (do_string(__G__ G
.ecrec
.zipfile_comment_length
, DISPLAY
))
1626 Info(slide
, 0, ((char *)slide
, LoadFarString(ZipfileCommEnd
)));
1628 Info(slide
, 0, ((char *)slide
,
1629 LoadFarString(ZipfileCommTrunc2
)));
1630 } /* endif (comment exists) */
1632 /* ZipInfo, non-verbose mode: print zipfile comment only if requested */
1633 } else if (G
.ecrec
.zipfile_comment_length
&&
1634 (uO
.zflag
> 0) && uO
.zipinfo_mode
) {
1635 if (do_string(__G__ G
.ecrec
.zipfile_comment_length
, DISPLAY
)) {
1636 Info(slide
, 0x401, ((char *)slide
,
1637 LoadFarString(ZipfileCommTrunc1
)));
1641 #endif /* !NO_ZIPINFO */
1642 if ( G
.ecrec
.zipfile_comment_length
&&
1653 #endif /* !WINDLL */
1656 if (do_string(__G__ G
.ecrec
.zipfile_comment_length
,
1657 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1659 (oU
.zipinfo_mode
? DISPLAY
: CHECK_AUTORUN
)
1668 Info(slide
, 0x401, ((char *)slide
,
1669 LoadFarString(ZipfileCommTrunc1
)));
1673 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1674 else if (G
.ecrec
.zipfile_comment_length
) {
1675 if (do_string(__G__ G
.ecrec
.zipfile_comment_length
, CHECK_AUTORUN_Q
))
1677 Info(slide
, 0x401, ((char *)slide
,
1678 LoadFarString(ZipfileCommTrunc1
)));
1685 } /* end function process_zip_cmmnt() */
1691 /************************************/
1692 /* Function process_cdir_file_hdr() */
1693 /************************************/
1695 int process_cdir_file_hdr(__G
) /* return PK-type error code */
1701 /*---------------------------------------------------------------------------
1702 Get central directory info, save host and method numbers, and set flag
1703 for lowercase conversion of filename, depending on the OS from which the
1705 ---------------------------------------------------------------------------*/
1707 if ((error
= get_cdir_ent(__G
)) != 0)
1710 G
.pInfo
->hostver
= G
.crec
.version_made_by
[0];
1711 G
.pInfo
->hostnum
= MIN(G
.crec
.version_made_by
[1], NUM_HOSTS
);
1712 /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
1714 G
.pInfo
->lcflag
= 0;
1715 if (uO
.L_flag
== 1) /* name conversion for monocase systems */
1716 switch (G
.pInfo
->hostnum
) {
1717 case FS_FAT_
: /* PKZIP and zip -k store in uppercase */
1718 case CPM_
: /* like MS-DOS, right? */
1719 case VM_CMS_
: /* all caps? */
1720 case MVS_
: /* all caps? */
1723 case VMS_
: /* our Zip uses lowercase, but ASi's doesn't */
1724 /* case Z_SYSTEM_: ? */
1726 G
.pInfo
->lcflag
= 1; /* convert filename to lowercase */
1729 default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */
1730 break; /* FS_VFAT_, ATHEOS_, BEOS_ (Z_SYSTEM_), THEOS_: */
1733 else if (uO
.L_flag
> 1) /* let -LL force lower case for all names */
1734 G
.pInfo
->lcflag
= 1;
1736 /* do Amigas (AMIGA_) also have volume labels? */
1737 if (IS_VOLID(G
.crec
.external_file_attributes
) &&
1738 (G
.pInfo
->hostnum
== FS_FAT_
|| G
.pInfo
->hostnum
== FS_HPFS_
||
1739 G
.pInfo
->hostnum
== FS_NTFS_
|| G
.pInfo
->hostnum
== ATARI_
))
1741 G
.pInfo
->vollabel
= TRUE
;
1742 G
.pInfo
->lcflag
= 0; /* preserve case of volume labels */
1744 G
.pInfo
->vollabel
= FALSE
;
1746 /* this flag is needed to detect archives made by "PKZIP for Unix" when
1747 deciding which kind of codepage conversion has to be applied to
1748 strings (see do_string() function in fileio.c) */
1749 G
.pInfo
->HasUxAtt
= (G
.crec
.external_file_attributes
& 0xffff0000L
) != 0L;
1751 #ifdef UNICODE_SUPPORT
1752 /* remember the state of GPB11 (General Purpuse Bit 11) which indicates
1753 that the standard path and comment are UTF-8. */
1755 = (G
.crec
.general_purpose_bit_flag
& (1 << 11)) == (1 << 11);
1760 } /* end function process_cdir_file_hdr() */
1766 /***************************/
1767 /* Function get_cdir_ent() */
1768 /***************************/
1770 static int get_cdir_ent(__G
) /* return PK-type error code */
1773 cdir_byte_hdr byterec
;
1776 /*---------------------------------------------------------------------------
1777 Read the next central directory entry and do any necessary machine-type
1778 conversions (byte ordering, structure padding compensation--do so by
1779 copying the data from the array into which it was read (byterec) to the
1780 usable struct (crec)).
1781 ---------------------------------------------------------------------------*/
1783 if (readbuf(__G__ (char *)byterec
, CREC_SIZE
) == 0)
1786 G
.crec
.version_made_by
[0] = byterec
[C_VERSION_MADE_BY_0
];
1787 G
.crec
.version_made_by
[1] = byterec
[C_VERSION_MADE_BY_1
];
1788 G
.crec
.version_needed_to_extract
[0] =
1789 byterec
[C_VERSION_NEEDED_TO_EXTRACT_0
];
1790 G
.crec
.version_needed_to_extract
[1] =
1791 byterec
[C_VERSION_NEEDED_TO_EXTRACT_1
];
1793 G
.crec
.general_purpose_bit_flag
=
1794 makeword(&byterec
[C_GENERAL_PURPOSE_BIT_FLAG
]);
1795 G
.crec
.compression_method
=
1796 makeword(&byterec
[C_COMPRESSION_METHOD
]);
1797 G
.crec
.last_mod_dos_datetime
=
1798 makelong(&byterec
[C_LAST_MOD_DOS_DATETIME
]);
1800 makelong(&byterec
[C_CRC32
]);
1802 makelong(&byterec
[C_COMPRESSED_SIZE
]);
1804 makelong(&byterec
[C_UNCOMPRESSED_SIZE
]);
1805 G
.crec
.filename_length
=
1806 makeword(&byterec
[C_FILENAME_LENGTH
]);
1807 G
.crec
.extra_field_length
=
1808 makeword(&byterec
[C_EXTRA_FIELD_LENGTH
]);
1809 G
.crec
.file_comment_length
=
1810 makeword(&byterec
[C_FILE_COMMENT_LENGTH
]);
1811 G
.crec
.disk_number_start
=
1812 makeword(&byterec
[C_DISK_NUMBER_START
]);
1813 G
.crec
.internal_file_attributes
=
1814 makeword(&byterec
[C_INTERNAL_FILE_ATTRIBUTES
]);
1815 G
.crec
.external_file_attributes
=
1816 makelong(&byterec
[C_EXTERNAL_FILE_ATTRIBUTES
]); /* LONG, not word! */
1817 G
.crec
.relative_offset_local_header
=
1818 makelong(&byterec
[C_RELATIVE_OFFSET_LOCAL_HEADER
]);
1822 } /* end function get_cdir_ent() */
1828 /*************************************/
1829 /* Function process_local_file_hdr() */
1830 /*************************************/
1832 int process_local_file_hdr(__G
) /* return PK-type error code */
1835 local_byte_hdr byterec
;
1838 /*---------------------------------------------------------------------------
1839 Read the next local file header and do any necessary machine-type con-
1840 versions (byte ordering, structure padding compensation--do so by copy-
1841 ing the data from the array into which it was read (byterec) to the
1842 usable struct (lrec)).
1843 ---------------------------------------------------------------------------*/
1845 if (readbuf(__G__ (char *)byterec
, LREC_SIZE
) == 0)
1848 G
.lrec
.version_needed_to_extract
[0] =
1849 byterec
[L_VERSION_NEEDED_TO_EXTRACT_0
];
1850 G
.lrec
.version_needed_to_extract
[1] =
1851 byterec
[L_VERSION_NEEDED_TO_EXTRACT_1
];
1853 G
.lrec
.general_purpose_bit_flag
=
1854 makeword(&byterec
[L_GENERAL_PURPOSE_BIT_FLAG
]);
1855 G
.lrec
.compression_method
= makeword(&byterec
[L_COMPRESSION_METHOD
]);
1856 G
.lrec
.last_mod_dos_datetime
= makelong(&byterec
[L_LAST_MOD_DOS_DATETIME
]);
1857 G
.lrec
.crc32
= makelong(&byterec
[L_CRC32
]);
1858 G
.lrec
.csize
= makelong(&byterec
[L_COMPRESSED_SIZE
]);
1859 G
.lrec
.ucsize
= makelong(&byterec
[L_UNCOMPRESSED_SIZE
]);
1860 G
.lrec
.filename_length
= makeword(&byterec
[L_FILENAME_LENGTH
]);
1861 G
.lrec
.extra_field_length
= makeword(&byterec
[L_EXTRA_FIELD_LENGTH
]);
1863 if ((G
.lrec
.general_purpose_bit_flag
& 8) != 0) {
1864 /* can't trust local header, use central directory: */
1865 G
.lrec
.crc32
= G
.pInfo
->crc
;
1866 G
.lrec
.csize
= G
.pInfo
->compr_size
;
1867 G
.lrec
.ucsize
= G
.pInfo
->uncompr_size
;
1870 G
.csize
= G
.lrec
.csize
;
1874 } /* end function process_local_file_hdr() */
1877 /*******************************/
1878 /* Function getZip64Data() */
1879 /*******************************/
1881 int getZip64Data(__G__ ef_buf
, ef_len
)
1883 ZCONST uch
*ef_buf
; /* buffer containing extra field */
1884 unsigned ef_len
; /* total length of extra field */
1889 /*---------------------------------------------------------------------------
1890 This function scans the extra field for zip64 information, ie 8-byte
1891 versions of compressed file size, uncompressed file size, relative offset
1892 and a 4-byte version of disk start number.
1893 Sets both local header and central header fields. Not terribly clever,
1894 but it means that this procedure is only called in one place.
1895 ---------------------------------------------------------------------------*/
1897 if (ef_len
== 0 || ef_buf
== NULL
)
1900 Trace((stderr
,"\ngetZip64Data: scanning extra field of length %u\n",
1903 while (ef_len
>= EB_HEADSIZE
) {
1904 eb_id
= makeword(EB_ID
+ ef_buf
);
1905 eb_len
= makeword(EB_LEN
+ ef_buf
);
1907 if (eb_len
> (ef_len
- EB_HEADSIZE
)) {
1908 /* discovered some extra field inconsistency! */
1910 "getZip64Data: block length %u > rest ef_size %u\n", eb_len
,
1911 ef_len
- EB_HEADSIZE
));
1914 if (eb_id
== EF_PKSZ64
) {
1916 int offset
= EB_HEADSIZE
;
1918 if (G
.crec
.ucsize
== 0xffffffff || G
.lrec
.ucsize
== 0xffffffff){
1919 G
.lrec
.ucsize
= G
.crec
.ucsize
= makeint64(offset
+ ef_buf
);
1920 offset
+= sizeof(G
.crec
.ucsize
);
1922 if (G
.crec
.csize
== 0xffffffff || G
.lrec
.csize
== 0xffffffff){
1923 G
.csize
= G
.lrec
.csize
= G
.crec
.csize
= makeint64(offset
+ ef_buf
);
1924 offset
+= sizeof(G
.crec
.csize
);
1926 if (G
.crec
.relative_offset_local_header
== 0xffffffff){
1927 G
.crec
.relative_offset_local_header
= makeint64(offset
+ ef_buf
);
1928 offset
+= sizeof(G
.crec
.relative_offset_local_header
);
1930 if (G
.crec
.disk_number_start
== 0xffff){
1931 G
.crec
.disk_number_start
= (zuvl_t
)makelong(offset
+ ef_buf
);
1932 offset
+= sizeof(G
.crec
.disk_number_start
);
1936 /* Skip this extra field block */
1937 ef_buf
+= (eb_len
+ EB_HEADSIZE
);
1938 ef_len
-= (eb_len
+ EB_HEADSIZE
);
1942 } /* end function getZip64Data() */
1945 #ifdef UNICODE_SUPPORT
1947 /*******************************/
1948 /* Function getUnicodeData() */
1949 /*******************************/
1951 int getUnicodeData(__G__ ef_buf
, ef_len
)
1953 ZCONST uch
*ef_buf
; /* buffer containing extra field */
1954 unsigned ef_len
; /* total length of extra field */
1959 /*---------------------------------------------------------------------------
1960 This function scans the extra field for Unicode information, ie UTF-8
1963 On return, G.unipath_filename =
1964 NULL, if no Unicode path extra field or error
1965 "", if the standard path is UTF-8 (free when done)
1966 null-terminated UTF-8 path (free when done)
1967 Return PK_COOL if no error.
1968 ---------------------------------------------------------------------------*/
1970 G
.unipath_filename
= NULL
;
1972 if (ef_len
== 0 || ef_buf
== NULL
)
1975 Trace((stderr
,"\ngetUnicodeData: scanning extra field of length %u\n",
1978 while (ef_len
>= EB_HEADSIZE
) {
1979 eb_id
= makeword(EB_ID
+ ef_buf
);
1980 eb_len
= makeword(EB_LEN
+ ef_buf
);
1982 if (eb_len
> (ef_len
- EB_HEADSIZE
)) {
1983 /* discovered some extra field inconsistency! */
1985 "getUnicodeData: block length %u > rest ef_size %u\n", eb_len
,
1986 ef_len
- EB_HEADSIZE
));
1989 if (eb_id
== EF_UNIPATH
) {
1991 int offset
= EB_HEADSIZE
;
1992 ush ULen
= eb_len
- 5;
1993 ulg chksum
= CRCVAL_INITIAL
;
1996 G
.unipath_version
= (uch
) *(offset
+ ef_buf
);
1998 if (G
.unipath_version
> 1) {
1999 /* can do only version 1 */
2000 Info(slide
, 0x401, ((char *)slide
,
2001 LoadFarString(UnicodeVersionError
)));
2006 G
.unipath_checksum
= makelong(offset
+ ef_buf
);
2010 * Compute 32-bit crc
2013 chksum
= crc32(chksum
, (uch
*)(G
.filename_full
),
2014 strlen(G
.filename_full
));
2016 /* If the checksums's don't match then likely filename has been
2017 * modified and the Unicode Path is no longer valid.
2019 if (chksum
!= G
.unipath_checksum
) {
2020 Info(slide
, 0x401, ((char *)slide
,
2021 LoadFarString(UnicodeMismatchError
)));
2022 if (G
.unicode_mismatch
== 1) {
2023 /* warn and continue */
2024 } else if (G
.unicode_mismatch
== 2) {
2025 /* ignore and continue */
2026 } else if (G
.unicode_mismatch
== 0) {
2032 if ((G
.unipath_filename
= malloc(ULen
+ 1)) == NULL
) {
2036 /* standard path is UTF-8 so use that */
2037 G
.unipath_filename
[0] = '\0';
2040 strncpy(G
.unipath_filename
,
2041 (ZCONST
char *)(offset
+ ef_buf
), ULen
);
2042 G
.unipath_filename
[ULen
] = '\0';
2046 /* Skip this extra field block */
2047 ef_buf
+= (eb_len
+ EB_HEADSIZE
);
2048 ef_len
-= (eb_len
+ EB_HEADSIZE
);
2052 } /* end function getUnicodeData() */
2057 #ifdef UNICODE_WCHAR
2058 /*---------------------------------------------
2059 * Unicode conversion functions
2061 * Based on functions provided by Paul Kienitz
2063 *---------------------------------------------
2067 NOTES APPLICABLE TO ALL STRING FUNCTIONS:
2069 All of the x_to_y functions take parameters for an output buffer and
2070 its available length, and return an int. The value returned is the
2071 length of the string that the input produces, which may be larger than
2072 the provided buffer length. If the returned value is less than the
2073 buffer length, then the contents of the buffer will be null-terminated;
2074 otherwise, it will not be terminated and may be invalid, possibly
2075 stopping in the middle of a multibyte sequence.
2077 In all cases you may pass NULL as the buffer and/or 0 as the length, if
2078 you just want to learn how much space the string is going to require.
2080 The functions will return -1 if the input is invalid UTF-8 or cannot be
2084 static int utf8_char_bytes
OF((ZCONST
char *utf8
));
2085 static ulg ucs4_char_from_utf8
OF((ZCONST
char **utf8
));
2086 static int utf8_to_ucs4_string
OF((ZCONST
char *utf8
, ulg
*ucs4buf
,
2089 /* utility functions for managing UTF-8 and UCS-4 strings */
2094 * Returns the number of bytes used by the first character in a UTF-8
2095 * string, or -1 if the UTF-8 is invalid or null.
2097 static int utf8_char_bytes(utf8
)
2104 return -1; /* no input */
2105 lead
= (unsigned char) *utf8
;
2107 r
= 1; /* an ascii-7 character */
2108 else if (lead
< 0xC0)
2109 return -1; /* error: trailing byte without lead byte */
2110 else if (lead
< 0xE0)
2111 r
= 2; /* an 11 bit character */
2112 else if (lead
< 0xF0)
2113 r
= 3; /* a 16 bit character */
2114 else if (lead
< 0xF8)
2115 r
= 4; /* a 21 bit character (the most currently used) */
2116 else if (lead
< 0xFC)
2117 r
= 5; /* a 26 bit character (shouldn't happen) */
2118 else if (lead
< 0xFE)
2119 r
= 6; /* a 31 bit character (shouldn't happen) */
2121 return -1; /* error: invalid lead byte */
2122 for (t
= 1; t
< r
; t
++)
2123 if ((unsigned char) utf8
[t
] < 0x80 || (unsigned char) utf8
[t
] >= 0xC0)
2124 return -1; /* error: not enough valid trailing bytes */
2129 /* ucs4_char_from_utf8
2131 * Given a reference to a pointer into a UTF-8 string, returns the next
2132 * UCS-4 character and advances the pointer to the next character sequence.
2133 * Returns ~0 (= -1 in twos-complement notation) and does not advance the
2134 * pointer when input is ill-formed.
2136 static ulg
ucs4_char_from_utf8(utf8
)
2143 return ~0L; /* no input */
2144 bytes
= utf8_char_bytes(*utf8
);
2146 return ~0L; /* invalid input */
2148 ret
= **utf8
; /* ascii-7 */
2150 ret
= **utf8
& (0x7F >> bytes
); /* lead byte of a multibyte sequence */
2152 for (t
= 1; t
< bytes
; t
++) /* consume trailing bytes */
2153 ret
= (ret
<< 6) | (*((*utf8
)++) & 0x3F);
2154 return (zwchar
) ret
;
2158 #if 0 /* currently unused */
2159 /* utf8_from_ucs4_char - Convert UCS char to UTF-8
2161 * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6,
2162 * or -1 if ch is too large to represent. utf8buf must have room for 6 bytes.
2164 static int utf8_from_ucs4_char(utf8buf
, ch
)
2169 int leadmask
= 0x80;
2170 int leadbits
= 0x3F;
2174 if (ch
> 0x7FFFFFFFL
)
2175 return -1; /* UTF-8 can represent 31 bits */
2178 *utf8buf
++ = (char) ch
; /* ascii-7 */
2183 leadmask
= (leadmask
>> 1) | 0x80;
2186 } while (tch
& ~leadbits
);
2188 /* produce lead byte */
2189 *utf8buf
++ = (char) (leadmask
| (ch
>> (6 * trailing
)));
2190 while (--trailing
>= 0)
2191 /* produce trailing bytes */
2192 *utf8buf
++ = (char) (0x80 | ((ch
>> (6 * trailing
)) & 0x3F));
2198 /*===================================================================*/
2200 /* utf8_to_ucs4_string - convert UTF-8 string to UCS string
2202 * Return UCS count. Now returns int so can return -1.
2204 static int utf8_to_ucs4_string(utf8
, ucs4buf
, buflen
)
2213 ulg ch
= ucs4_char_from_utf8(&utf8
);
2218 if (ucs4buf
&& count
< buflen
)
2219 ucs4buf
[count
] = ch
;
2228 #if 0 /* currently unused */
2229 /* ucs4_string_to_utf8
2233 static int ucs4_string_to_utf8(ucs4
, utf8buf
, buflen
)
2245 int mbl
= utf8_from_ucs4_char(mb
, *ucs4
++);
2249 /* We could optimize this a bit by passing utf8buf + count */
2250 /* directly to utf8_from_ucs4_char when buflen >= count + 6... */
2254 if (utf8buf
&& count
< buflen
)
2255 strncpy(utf8buf
+ count
, mb
, c
);
2256 if (mbl
== 1 && !mb
[0])
2257 return count
; /* terminating nul */
2265 * Wrapper: counts the actual unicode characters in a UTF-8 string.
2267 static int utf8_chars(utf8
)
2270 return utf8_to_ucs4_string(utf8
, NULL
, 0);
2274 /* --------------------------------------------------- */
2277 * These functions common for all Unicode ports.
2279 * These functions should allocate and return strings that can be
2280 * freed with free().
2284 * Use zwchar for wide char which is unsigned long
2285 * in zip.h and 32 bits. This avoids problems with
2286 * different sizes of wchar_t.
2289 #if 0 /* currently unused */
2291 * Checks if a string is all ascii
2293 int is_ascii_string(mbstring
)
2294 ZCONST
char *mbstring
;
2299 for (p
= mbstring
; c
= (uch
)*p
; p
++) {
2307 /* local to UTF-8 */
2308 char *local_to_utf8_string(local_string
)
2309 ZCONST
char *local_string
;
2311 return wide_to_utf8_string(local_to_wide_string(local_string
));
2313 # endif /* unused */
2315 /* wide_to_escape_string
2316 provides a string that represents a wide char not in local char set
2318 An initial try at an algorithm. Suggestions welcome.
2320 According to the standard, Unicode character points are restricted to
2321 the number range from 0 to 0x10FFFF, respective 21 bits.
2322 For a hexadecimal notation, 2 octets are sufficient for the mostly
2323 used characters from the "Basic Multilingual Plane", all other
2324 Unicode characters can be represented by 3 octets (= 6 hex digits).
2325 The Unicode standard suggests to write Unicode character points
2326 as 4 resp. 6 hex digits, preprended by "U+".
2327 (e.g.: U+10FFFF for the highest character point, or U+0030 for the ASCII
2330 However, for the purpose of escaping non-ASCII chars in an ASCII character
2331 stream, the "U" is not a very good escape initializer. Therefore, we
2332 use the following convention within our Info-ZIP code:
2334 If not an ASCII char probably need 2 bytes at least. So if
2335 a 2-byte wide encode it as 4 hex digits with a leading #U. If
2336 needs 3 bytes then prefix the string with #L. So
2338 is a 2-byte wide character with bytes 0x12 and 0x34 while
2340 is a 3-byte wide character with bytes 0x12, 0x34, 0x56.
2341 On Windows, wide that need two wide characters need to be converted
2345 /* set this to the max bytes an escape can be */
2346 #define MAX_ESCAPE_BYTES 8
2348 char *wide_to_escape_string(wide_char
)
2352 zwchar w
= wide_char
;
2353 uch b
[sizeof(zwchar
)];
2359 /* fill byte array with zeros */
2360 memzero(b
, sizeof(zwchar
));
2361 /* get bytes in right to left order */
2362 for (len
= 0; w
; len
++) {
2363 b
[len
] = (char)(w
% 0x100);
2367 /* either 2 bytes or 3 bytes */
2374 for (i
= len
- 1; i
>= 0; i
--) {
2375 sprintf(d
, "%02x", b
[i
]);
2378 if ((r
= malloc(strlen(e
) + 1)) == NULL
) {
2385 #if 0 /* currently unused */
2386 /* returns the wide character represented by the escape string */
2387 zwchar
escape_string_to_wide(escape_string
)
2388 ZCONST
char *escape_string
;
2394 ZCONST
char *e
= escape_string
;
2404 /* either #U1234 or #L123456 format */
2405 if (len
!= 6 && len
!= 8) {
2414 for (i
= 2; i
< 8; i
++) {
2416 if (c
< '0' || c
> '9') {
2419 w
= w
* 0x10 + (zwchar
)(c
- '0');
2421 } else if (e
[1] == 'U') {
2423 for (i
= 2; i
< 6; i
++) {
2425 if (c
< '0' || c
> '9') {
2428 w
= w
* 0x10 + (zwchar
)(c
- '0');
2435 #ifndef WIN32 /* WIN32 supplies a special variant of this function */
2436 /* convert wide character string to multi-byte character string */
2437 char *wide_to_local_string(wide_string
, escape_all
)
2438 ZCONST zwchar
*wide_string
;
2444 int state_dependent
;
2446 int max_bytes
= MB_CUR_MAX
;
2448 char *buffer
= NULL
;
2449 char *local_string
= NULL
;
2451 for (wsize
= 0; wide_string
[wsize
]; wsize
++) ;
2453 if (max_bytes
< MAX_ESCAPE_BYTES
)
2454 max_bytes
= MAX_ESCAPE_BYTES
;
2456 if ((buffer
= (char *)malloc(wsize
* max_bytes
+ 1)) == NULL
) {
2462 /* set initial state if state-dependent encoding */
2464 b
= wctomb(NULL
, wc
);
2466 state_dependent
= 0;
2468 state_dependent
= 1;
2469 for (i
= 0; i
< wsize
; i
++) {
2470 if (sizeof(wchar_t) < 4 && wide_string
[i
] > 0xFFFF) {
2471 /* wchar_t probably 2 bytes */
2472 /* could do surrogates if state_dependent and wctomb can do */
2473 wc
= zwchar_to_wchar_t_default_char
;
2475 wc
= (wchar_t)wide_string
[i
];
2477 b
= wctomb(buf
, wc
);
2479 if (b
== 1 && (uch
)buf
[0] <= 0x7f) {
2481 strncat(buffer
, buf
, b
);
2483 /* use escape for wide character */
2484 char *escape_string
= wide_to_escape_string(wide_string
[i
]);
2485 strcat(buffer
, escape_string
);
2486 free(escape_string
);
2489 /* multi-byte char */
2490 strncat(buffer
, buf
, b
);
2492 /* no MB for this wide */
2493 /* use escape for wide character */
2494 char *escape_string
= wide_to_escape_string(wide_string
[i
]);
2495 strcat(buffer
, escape_string
);
2496 free(escape_string
);
2499 if ((local_string
= (char *)malloc(strlen(buffer
) + 1)) != NULL
) {
2500 strcpy(local_string
, buffer
);
2504 return local_string
;
2508 #if 0 /* currently unused */
2509 /* convert local string to display character set string */
2510 char *local_to_display_string(local_string
)
2511 ZCONST
char *local_string
;
2513 char *display_string
;
2515 /* For Windows, OEM string should never be bigger than ANSI string, says
2516 CharToOem description.
2517 For all other ports, just make a copy of local_string.
2519 if ((display_string
= (char *)malloc(strlen(local_string
) + 1)) == NULL
) {
2523 strcpy(display_string
, local_string
);
2529 if ((ebc
= malloc(strlen(display_string
) + 1)) == NULL
) {
2532 strtoebc(ebc
, display_string
);
2533 free(display_string
);
2534 display_string
= ebc
;
2538 return display_string
;
2542 /* UTF-8 to local */
2543 char *utf8_to_local_string(utf8_string
, escape_all
)
2544 ZCONST
char *utf8_string
;
2547 zwchar
*wide
= utf8_to_wide_string(utf8_string
);
2548 char *loc
= wide_to_local_string(wide
, escape_all
);
2553 #if 0 /* currently unused */
2554 /* convert multi-byte character string to wide character string */
2555 zwchar
*local_to_wide_string(local_string
)
2556 ZCONST
char *local_string
;
2560 zwchar
*wide_string
;
2562 /* for now try to convert as string - fails if a bad char in string */
2563 wsize
= mbstowcs(NULL
, local_string
, strlen(local_string
) + 1);
2564 if (wsize
== (size_t)-1) {
2565 /* could not convert */
2570 if ((wc_string
= (wchar_t *)malloc((wsize
+ 1) * sizeof(wchar_t))) == NULL
) {
2573 wsize
= mbstowcs(wc_string
, local_string
, strlen(local_string
) + 1);
2574 wc_string
[wsize
] = (wchar_t) 0;
2576 /* in case wchar_t is not zwchar */
2577 if ((wide_string
= (zwchar
*)malloc((wsize
+ 1) * sizeof(zwchar
))) == NULL
) {
2580 for (wsize
= 0; wide_string
[wsize
] = (zwchar
)wc_string
[wsize
]; wsize
++) ;
2581 wide_string
[wsize
] = (zwchar
) 0;
2588 /* convert wide string to UTF-8 */
2589 char *wide_to_utf8_string(wide_string
)
2590 ZCONST zwchar
*wide_string
;
2595 /* get size of utf8 string */
2596 mbcount
= ucs4_string_to_utf8(wide_string
, NULL
, 0);
2599 if ((utf8_string
= (char *) malloc(mbcount
+ 1)) == NULL
) {
2602 mbcount
= ucs4_string_to_utf8(wide_string
, utf8_string
, mbcount
+ 1);
2610 /* convert UTF-8 string to wide string */
2611 zwchar
*utf8_to_wide_string(utf8_string
)
2612 ZCONST
char *utf8_string
;
2615 zwchar
*wide_string
;
2617 wcount
= utf8_to_ucs4_string(utf8_string
, NULL
, 0);
2620 if ((wide_string
= (zwchar
*) malloc((wcount
+ 1) * sizeof(zwchar
)))
2624 wcount
= utf8_to_ucs4_string(utf8_string
, wide_string
, wcount
+ 1);
2629 #endif /* UNICODE_WCHAR */
2630 #endif /* UNICODE_SUPPORT */
2636 #ifdef USE_EF_UT_TIME
2638 #ifdef IZ_HAVE_UXUIDGID
2639 static int read_ux3_value(dbuf
, uidgid_sz
, p_uidgid
)
2640 ZCONST uch
*dbuf
; /* buffer a uid or gid value */
2641 unsigned uidgid_sz
; /* size of uid/gid value */
2642 ulg
*p_uidgid
; /* return storage: uid or gid value */
2646 switch (uidgid_sz
) {
2648 *p_uidgid
= (ulg
)makeword(dbuf
);
2651 *p_uidgid
= (ulg
)makelong(dbuf
);
2654 uidgid64
= makeint64(dbuf
);
2655 #ifndef LARGE_FILE_SUPPORT
2656 if (uidgid64
== (zusz_t
)0xffffffffL
)
2659 *p_uidgid
= (ulg
)uidgid64
;
2660 if ((zusz_t
)(*p_uidgid
) != uidgid64
)
2666 #endif /* IZ_HAVE_UXUIDGID */
2669 /*******************************/
2670 /* Function ef_scan_for_izux() */
2671 /*******************************/
2673 unsigned ef_scan_for_izux(ef_buf
, ef_len
, ef_is_c
, dos_mdatetime
,
2675 ZCONST uch
*ef_buf
; /* buffer containing extra field */
2676 unsigned ef_len
; /* total length of extra field */
2677 int ef_is_c
; /* flag indicating "is central extra field" */
2678 ulg dos_mdatetime
; /* last_mod_file_date_time in DOS format */
2679 iztimes
*z_utim
; /* return storage: atime, mtime, ctime */
2680 ulg
*z_uidgid
; /* return storage: uid and gid */
2685 int have_new_type_eb
= 0;
2686 long i_time
; /* buffer for Unix style 32-bit integer time value */
2687 #ifdef TIME_T_TYPE_DOUBLE
2688 int ut_in_archive_sgn
= 0;
2690 int ut_zip_unzip_compatible
= FALSE
;
2693 /*---------------------------------------------------------------------------
2694 This function scans the extra field for EF_TIME, EF_IZUNIX2, EF_IZUNIX, or
2695 EF_PKUNIX blocks containing Unix-style time_t (GMT) values for the entry's
2696 access, creation, and modification time.
2697 If a valid block is found, the time stamps are copied to the iztimes
2698 structure (provided the z_utim pointer is not NULL).
2699 If a IZUNIX2 block is found or the IZUNIX block contains UID/GID fields,
2700 and the z_uidgid array pointer is valid (!= NULL), the owner info is
2702 The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring all
2703 data from probably present obsolete EF_IZUNIX blocks.
2704 If multiple blocks of the same type are found, only the information from
2705 the last block is used.
2706 The return value is a combination of the EF_TIME Flags field with an
2707 additional flag bit indicating the presence of valid UID/GID info,
2708 or 0 in case of failure.
2709 ---------------------------------------------------------------------------*/
2711 if (ef_len
== 0 || ef_buf
== NULL
|| (z_utim
== 0 && z_uidgid
== NULL
))
2714 TTrace((stderr
,"\nef_scan_for_izux: scanning extra field of length %u\n",
2717 while (ef_len
>= EB_HEADSIZE
) {
2718 eb_id
= makeword(EB_ID
+ ef_buf
);
2719 eb_len
= makeword(EB_LEN
+ ef_buf
);
2721 if (eb_len
> (ef_len
- EB_HEADSIZE
)) {
2722 /* discovered some extra field inconsistency! */
2724 "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len
,
2725 ef_len
- EB_HEADSIZE
));
2731 flags
&= ~0x0ff; /* ignore previous IZUNIX or EF_TIME fields */
2732 have_new_type_eb
= 1;
2733 if ( eb_len
>= EB_UT_MINLEN
&& z_utim
!= NULL
) {
2734 unsigned eb_idx
= EB_UT_TIME1
;
2735 TTrace((stderr
,"ef_scan_for_izux: found TIME extra field\n"));
2736 flags
|= (ef_buf
[EB_HEADSIZE
+EB_UT_FLAGS
] & 0x0ff);
2737 if ((flags
& EB_UT_FL_MTIME
)) {
2738 if ((eb_idx
+4) <= eb_len
) {
2739 i_time
= (long)makelong((EB_HEADSIZE
+eb_idx
) + ef_buf
);
2741 TTrace((stderr
," UT e.f. modification time = %ld\n",
2744 #ifdef TIME_T_TYPE_DOUBLE
2745 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
2746 if (dos_mdatetime
== DOSTIME_MINIMUM
) {
2747 ut_in_archive_sgn
= -1;
2749 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
2750 } else if (dos_mdatetime
>= DOSTIME_2038_01_18
) {
2751 ut_in_archive_sgn
= 1;
2753 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
2755 ut_in_archive_sgn
= 0;
2756 /* cannot determine sign of mtime;
2757 without modtime: ignore complete UT field */
2758 flags
&= ~0x0ff; /* no time_t times available */
2760 " UT modtime range error; ignore e.f.!\n"));
2761 break; /* stop scanning this field */
2764 /* cannot determine, safe assumption is FALSE */
2765 ut_in_archive_sgn
= 0;
2766 z_utim
->mtime
= (time_t)i_time
;
2768 #else /* !TIME_T_TYPE_DOUBLE */
2769 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
2770 ut_zip_unzip_compatible
=
2771 ((time_t)0x80000000L
< (time_t)0L)
2772 ? (dos_mdatetime
== DOSTIME_MINIMUM
)
2773 : (dos_mdatetime
>= DOSTIME_2038_01_18
);
2774 if (!ut_zip_unzip_compatible
) {
2775 /* UnZip interprets mtime differently than Zip;
2776 without modtime: ignore complete UT field */
2777 flags
&= ~0x0ff; /* no time_t times available */
2779 " UT modtime range error; ignore e.f.!\n"));
2780 break; /* stop scanning this field */
2783 /* cannot determine, safe assumption is FALSE */
2784 ut_zip_unzip_compatible
= FALSE
;
2786 z_utim
->mtime
= (time_t)i_time
;
2787 #endif /* ?TIME_T_TYPE_DOUBLE */
2789 flags
&= ~EB_UT_FL_MTIME
;
2790 TTrace((stderr
," UT e.f. truncated; no modtime\n"));
2794 break; /* central version of TIME field ends here */
2797 if (flags
& EB_UT_FL_ATIME
) {
2798 if ((eb_idx
+4) <= eb_len
) {
2799 i_time
= (long)makelong((EB_HEADSIZE
+eb_idx
) + ef_buf
);
2801 TTrace((stderr
," UT e.f. access time = %ld\n",
2803 #ifdef TIME_T_TYPE_DOUBLE
2804 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
2805 if (ut_in_archive_sgn
== -1)
2807 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
2808 } else if (ut_in_archive_sgn
== 1) {
2810 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
2812 /* sign of 32-bit time is unknown -> ignore it */
2813 flags
&= ~EB_UT_FL_ATIME
;
2815 " UT access time range error: skip time!\n"));
2818 z_utim
->atime
= (time_t)i_time
;
2820 #else /* !TIME_T_TYPE_DOUBLE */
2821 if (((ulg
)(i_time
) & (ulg
)(0x80000000L
)) &&
2822 !ut_zip_unzip_compatible
) {
2823 flags
&= ~EB_UT_FL_ATIME
;
2825 " UT access time range error: skip time!\n"));
2827 z_utim
->atime
= (time_t)i_time
;
2829 #endif /* ?TIME_T_TYPE_DOUBLE */
2831 flags
&= ~EB_UT_FL_ATIME
;
2834 if (flags
& EB_UT_FL_CTIME
) {
2835 if ((eb_idx
+4) <= eb_len
) {
2836 i_time
= (long)makelong((EB_HEADSIZE
+eb_idx
) + ef_buf
);
2837 TTrace((stderr
," UT e.f. creation time = %ld\n",
2839 #ifdef TIME_T_TYPE_DOUBLE
2840 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
2841 if (ut_in_archive_sgn
== -1)
2843 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
2844 } else if (ut_in_archive_sgn
== 1) {
2846 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
2848 /* sign of 32-bit time is unknown -> ignore it */
2849 flags
&= ~EB_UT_FL_CTIME
;
2851 " UT creation time range error: skip time!\n"));
2854 z_utim
->ctime
= (time_t)i_time
;
2856 #else /* !TIME_T_TYPE_DOUBLE */
2857 if (((ulg
)(i_time
) & (ulg
)(0x80000000L
)) &&
2858 !ut_zip_unzip_compatible
) {
2859 flags
&= ~EB_UT_FL_CTIME
;
2861 " UT creation time range error: skip time!\n"));
2863 z_utim
->ctime
= (time_t)i_time
;
2865 #endif /* ?TIME_T_TYPE_DOUBLE */
2867 flags
&= ~EB_UT_FL_CTIME
;
2874 if (have_new_type_eb
== 0) {
2875 flags
&= ~0x0ff; /* ignore any previous IZUNIX field */
2876 have_new_type_eb
= 1;
2878 #ifdef IZ_HAVE_UXUIDGID
2879 if (have_new_type_eb
> 1)
2880 break; /* IZUNIX3 overrides IZUNIX2 e.f. block ! */
2881 if (eb_len
== EB_UX2_MINLEN
&& z_uidgid
!= NULL
) {
2882 z_uidgid
[0] = (ulg
)makeword((EB_HEADSIZE
+EB_UX2_UID
) + ef_buf
);
2883 z_uidgid
[1] = (ulg
)makeword((EB_HEADSIZE
+EB_UX2_GID
) + ef_buf
);
2884 flags
|= EB_UX2_VALID
; /* signal success */
2890 /* new 3rd generation Unix ef */
2891 have_new_type_eb
= 2;
2894 Version 1 byte version of this extra field, currently 1
2895 UIDSize 1 byte Size of UID field
2896 UID Variable UID for this entry
2897 GIDSize 1 byte Size of GID field
2898 GID Variable GID for this entry
2901 #ifdef IZ_HAVE_UXUIDGID
2902 if (eb_len
>= EB_UX3_MINLEN
2904 && (*((EB_HEADSIZE
+ 0) + ef_buf
) == 1)
2905 /* only know about version 1 */
2910 uid_size
= *((EB_HEADSIZE
+ 1) + ef_buf
);
2911 gid_size
= *((EB_HEADSIZE
+ uid_size
+ 2) + ef_buf
);
2913 flags
&= ~0x0ff; /* ignore any previous UNIX field */
2915 if ( read_ux3_value((EB_HEADSIZE
+ 2) + ef_buf
,
2916 uid_size
, z_uidgid
[0])
2918 read_ux3_value((EB_HEADSIZE
+ uid_size
+ 3) + ef_buf
,
2919 gid_size
, z_uidgid
[1]) )
2921 flags
|= EB_UX2_VALID
; /* signal success */
2924 #endif /* IZ_HAVE_UXUIDGID */
2928 case EF_PKUNIX
: /* PKUNIX e.f. layout is identical to IZUNIX */
2929 if (eb_len
>= EB_UX_MINLEN
) {
2930 TTrace((stderr
,"ef_scan_for_izux: found %s extra field\n",
2931 (eb_id
== EF_IZUNIX
? "IZUNIX" : "PKUNIX")));
2932 if (have_new_type_eb
> 0) {
2933 break; /* Ignore IZUNIX extra field block ! */
2935 if (z_utim
!= NULL
) {
2936 flags
|= (EB_UT_FL_MTIME
| EB_UT_FL_ATIME
);
2937 i_time
= (long)makelong((EB_HEADSIZE
+EB_UX_MTIME
)+ef_buf
);
2938 TTrace((stderr
," Unix EF modtime = %ld\n", i_time
));
2939 #ifdef TIME_T_TYPE_DOUBLE
2940 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
2941 if (dos_mdatetime
== DOSTIME_MINIMUM
) {
2942 ut_in_archive_sgn
= -1;
2944 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
2945 } else if (dos_mdatetime
>= DOSTIME_2038_01_18
) {
2946 ut_in_archive_sgn
= 1;
2948 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
2950 ut_in_archive_sgn
= 0;
2951 /* cannot determine sign of mtime;
2952 without modtime: ignore complete UT field */
2953 flags
&= ~0x0ff; /* no time_t times available */
2955 " UX modtime range error: ignore e.f.!\n"));
2958 /* cannot determine, safe assumption is FALSE */
2959 ut_in_archive_sgn
= 0;
2960 z_utim
->mtime
= (time_t)i_time
;
2962 #else /* !TIME_T_TYPE_DOUBLE */
2963 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
2964 ut_zip_unzip_compatible
=
2965 ((time_t)0x80000000L
< (time_t)0L)
2966 ? (dos_mdatetime
== DOSTIME_MINIMUM
)
2967 : (dos_mdatetime
>= DOSTIME_2038_01_18
);
2968 if (!ut_zip_unzip_compatible
) {
2969 /* UnZip interpretes mtime differently than Zip;
2970 without modtime: ignore complete UT field */
2971 flags
&= ~0x0ff; /* no time_t times available */
2973 " UX modtime range error: ignore e.f.!\n"));
2976 /* cannot determine, safe assumption is FALSE */
2977 ut_zip_unzip_compatible
= FALSE
;
2979 z_utim
->mtime
= (time_t)i_time
;
2980 #endif /* ?TIME_T_TYPE_DOUBLE */
2981 i_time
= (long)makelong((EB_HEADSIZE
+EB_UX_ATIME
)+ef_buf
);
2982 TTrace((stderr
," Unix EF actime = %ld\n", i_time
));
2983 #ifdef TIME_T_TYPE_DOUBLE
2984 if ((ulg
)(i_time
) & (ulg
)(0x80000000L
)) {
2985 if (ut_in_archive_sgn
== -1)
2987 (time_t)((long)i_time
| (~(long)0x7fffffffL
));
2988 } else if (ut_in_archive_sgn
== 1) {
2990 (time_t)((ulg
)i_time
& (ulg
)0xffffffffL
);
2991 } else if (flags
& 0x0ff) {
2992 /* sign of 32-bit time is unknown -> ignore it */
2993 flags
&= ~EB_UT_FL_ATIME
;
2995 " UX access time range error: skip time!\n"));
2998 z_utim
->atime
= (time_t)i_time
;
3000 #else /* !TIME_T_TYPE_DOUBLE */
3001 if (((ulg
)(i_time
) & (ulg
)(0x80000000L
)) &&
3002 !ut_zip_unzip_compatible
&& (flags
& 0x0ff)) {
3003 /* atime not in range of UnZip's time_t */
3004 flags
&= ~EB_UT_FL_ATIME
;
3006 " UX access time range error: skip time!\n"));
3008 z_utim
->atime
= (time_t)i_time
;
3010 #endif /* ?TIME_T_TYPE_DOUBLE */
3012 #ifdef IZ_HAVE_UXUIDGID
3013 if (eb_len
>= EB_UX_FULLSIZE
&& z_uidgid
!= NULL
) {
3014 z_uidgid
[0] = makeword((EB_HEADSIZE
+EB_UX_UID
) + ef_buf
);
3015 z_uidgid
[1] = makeword((EB_HEADSIZE
+EB_UX_GID
) + ef_buf
);
3016 flags
|= EB_UX2_VALID
;
3018 #endif /* IZ_HAVE_UXUIDGID */
3026 /* Skip this extra field block */
3027 ef_buf
+= (eb_len
+ EB_HEADSIZE
);
3028 ef_len
-= (eb_len
+ EB_HEADSIZE
);
3034 #endif /* USE_EF_UT_TIME */
3037 #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
3039 #define SPARKID_2 0x30435241 /* = "ARC0" */
3041 /*******************************/
3042 /* Function getRISCOSexfield() */
3043 /*******************************/
3045 zvoid
*getRISCOSexfield(ef_buf
, ef_len
)
3046 ZCONST uch
*ef_buf
; /* buffer containing extra field */
3047 unsigned ef_len
; /* total length of extra field */
3052 /*---------------------------------------------------------------------------
3053 This function scans the extra field for a Acorn SPARK filetype ef-block.
3054 If a valid block is found, the function returns a pointer to the start
3055 of the SPARK_EF block in the extra field buffer. Otherwise, a NULL
3056 pointer is returned.
3057 ---------------------------------------------------------------------------*/
3059 if (ef_len
== 0 || ef_buf
== NULL
)
3062 Trace((stderr
,"\ngetRISCOSexfield: scanning extra field of length %u\n",
3065 while (ef_len
>= EB_HEADSIZE
) {
3066 eb_id
= makeword(EB_ID
+ ef_buf
);
3067 eb_len
= makeword(EB_LEN
+ ef_buf
);
3069 if (eb_len
> (ef_len
- EB_HEADSIZE
)) {
3070 /* discovered some extra field inconsistency! */
3072 "getRISCOSexfield: block length %u > rest ef_size %u\n", eb_len
,
3073 ef_len
- EB_HEADSIZE
));
3077 if (eb_id
== EF_SPARK
&& (eb_len
== 24 || eb_len
== 20)) {
3078 if (makelong(EB_HEADSIZE
+ ef_buf
) == SPARKID_2
) {
3079 /* Return a pointer to the valid SPARK filetype ef block */
3080 return (zvoid
*)ef_buf
;
3084 /* Skip this extra field block */
3085 ef_buf
+= (eb_len
+ EB_HEADSIZE
);
3086 ef_len
-= (eb_len
+ EB_HEADSIZE
);
3092 #endif /* (RISCOS || ACORN_FTYPE_NFS) */