Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6725 | siemargl | 1 | /* |
2 | Copyright (c) 1990-2009 Info-ZIP. All rights reserved. |
||
3 | |||
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 |
||
8 | */ |
||
9 | /*--------------------------------------------------------------------------- |
||
10 | |||
11 | process.c |
||
12 | |||
13 | This file contains the top-level routines for processing multiple zipfiles. |
||
14 | |||
15 | Contains: process_zipfiles() |
||
16 | free_G_buffers() |
||
17 | do_seekable() |
||
18 | file_size() |
||
19 | rec_find() |
||
20 | find_ecrec64() |
||
21 | find_ecrec() |
||
22 | process_zip_cmmnt() |
||
23 | process_cdir_file_hdr() |
||
24 | get_cdir_ent() |
||
25 | process_local_file_hdr() |
||
26 | getZip64Data() |
||
27 | ef_scan_for_izux() |
||
28 | getRISCOSexfield() |
||
29 | |||
30 | ---------------------------------------------------------------------------*/ |
||
31 | |||
32 | |||
33 | #define UNZIP_INTERNAL |
||
34 | #include "unzip.h" |
||
35 | #ifdef WINDLL |
||
36 | # ifdef POCKET_UNZIP |
||
37 | # include "wince/intrface.h" |
||
38 | # else |
||
39 | # include "windll/windll.h" |
||
40 | # endif |
||
41 | #endif |
||
42 | #if defined(DYNALLOC_CRCTAB) || defined(UNICODE_SUPPORT) |
||
43 | # include "crc32.h" |
||
44 | #endif |
||
45 | |||
46 | static int do_seekable OF((__GPRO__ int lastchance)); |
||
47 | #ifdef DO_SAFECHECK_2GB |
||
48 | # ifdef USE_STRM_INPUT |
||
49 | static zoff_t file_size OF((FILE *file)); |
||
50 | # else |
||
51 | static zoff_t file_size OF((int fh)); |
||
52 | # endif |
||
53 | #endif /* DO_SAFECHECK_2GB */ |
||
54 | static int rec_find OF((__GPRO__ zoff_t, char *, int)); |
||
55 | static int find_ecrec64 OF((__GPRO__ zoff_t searchlen)); |
||
56 | static int find_ecrec OF((__GPRO__ zoff_t searchlen)); |
||
57 | static int process_zip_cmmnt OF((__GPRO)); |
||
58 | static int get_cdir_ent OF((__GPRO)); |
||
59 | #ifdef IZ_HAVE_UXUIDGID |
||
60 | static int read_ux3_value OF((ZCONST uch *dbuf, unsigned uidgid_sz, |
||
61 | ulg *p_uidgid)); |
||
62 | #endif /* IZ_HAVE_UXUIDGID */ |
||
63 | |||
64 | |||
65 | static ZCONST char Far CannotAllocateBuffers[] = |
||
66 | "error: cannot allocate unzip buffers\n"; |
||
67 | |||
68 | #ifdef SFX |
||
69 | static ZCONST char Far CannotFindMyself[] = |
||
70 | "unzipsfx: cannot find myself! [%s]\n"; |
||
71 | # ifdef CHEAP_SFX_AUTORUN |
||
72 | static ZCONST char Far AutorunPrompt[] = |
||
73 | "\nAuto-run command: %s\nExecute this command? [y/n] "; |
||
74 | static ZCONST char Far NotAutoRunning[] = |
||
75 | "Not executing auto-run command."; |
||
76 | # endif |
||
77 | |||
78 | #else /* !SFX */ |
||
79 | /* process_zipfiles() strings */ |
||
80 | # if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME)) |
||
81 | static ZCONST char Far WarnInvalidTZ[] = |
||
82 | "Warning: TZ environment variable not found, cannot use UTC times!!\n"; |
||
83 | # endif |
||
84 | # if !(defined(UNIX) || defined(AMIGA)) |
||
85 | static ZCONST char Far CannotFindWildcardMatch[] = |
||
86 | "%s: cannot find any matches for wildcard specification \"%s\".\n"; |
||
87 | # endif /* !(UNIX || AMIGA) */ |
||
88 | static ZCONST char Far FilesProcessOK[] = |
||
89 | "%d archive%s successfully processed.\n"; |
||
90 | static ZCONST char Far ArchiveWarning[] = |
||
91 | "%d archive%s had warnings but no fatal errors.\n"; |
||
92 | static ZCONST char Far ArchiveFatalError[] = |
||
93 | "%d archive%s had fatal errors.\n"; |
||
94 | static ZCONST char Far FileHadNoZipfileDir[] = |
||
95 | "%d file%s had no zipfile directory.\n"; |
||
96 | static ZCONST char Far ZipfileWasDir[] = "1 \"zipfile\" was a directory.\n"; |
||
97 | static ZCONST char Far ManyZipfilesWereDir[] = |
||
98 | "%d \"zipfiles\" were directories.\n"; |
||
99 | static ZCONST char Far NoZipfileFound[] = "No zipfiles found.\n"; |
||
100 | |||
101 | /* do_seekable() strings */ |
||
102 | # ifdef UNIX |
||
103 | static ZCONST char Far CannotFindZipfileDirMsg[] = |
||
104 | "%s: cannot find zipfile directory in one of %s or\n\ |
||
105 | %s%s.zip, and cannot find %s, period.\n"; |
||
106 | static ZCONST char Far CannotFindEitherZipfile[] = |
||
107 | "%s: cannot find or open %s, %s.zip or %s.\n"; |
||
108 | # else /* !UNIX */ |
||
109 | static ZCONST char Far CannotFindZipfileDirMsg[] = |
||
110 | "%s: cannot find zipfile directory in %s,\n\ |
||
111 | %sand cannot find %s, period.\n"; |
||
112 | # ifdef VMS |
||
113 | static ZCONST char Far CannotFindEitherZipfile[] = |
||
114 | "%s: cannot find %s (%s).\n"; |
||
115 | # else /* !VMS */ |
||
116 | static ZCONST char Far CannotFindEitherZipfile[] = |
||
117 | "%s: cannot find either %s or %s.\n"; |
||
118 | # endif /* ?VMS */ |
||
119 | # endif /* ?UNIX */ |
||
120 | extern ZCONST char Far Zipnfo[]; /* in unzip.c */ |
||
121 | #ifndef WINDLL |
||
122 | static ZCONST char Far Unzip[] = "unzip"; |
||
123 | #else |
||
124 | static ZCONST char Far Unzip[] = "UnZip DLL"; |
||
125 | #endif |
||
126 | #ifdef DO_SAFECHECK_2GB |
||
127 | static ZCONST char Far ZipfileTooBig[] = |
||
128 | "Trying to read large file (> 2 GiB) without large file support\n"; |
||
129 | #endif /* DO_SAFECHECK_2GB */ |
||
130 | static ZCONST char Far MaybeExe[] = |
||
131 | "note: %s may be a plain executable, not an archive\n"; |
||
132 | static ZCONST char Far CentDirNotInZipMsg[] = "\n\ |
||
133 | [%s]:\n\ |
||
134 | Zipfile is disk %lu of a multi-disk archive, and this is not the disk on\n\ |
||
135 | which the central zipfile directory begins (disk %lu).\n"; |
||
136 | static ZCONST char Far EndCentDirBogus[] = |
||
137 | "\nwarning [%s]: end-of-central-directory record claims this\n\ |
||
138 | is disk %lu but that the central directory starts on disk %lu; this is a\n\ |
||
139 | contradiction. Attempting to process anyway.\n"; |
||
140 | # ifdef NO_MULTIPART |
||
141 | static ZCONST char Far NoMultiDiskArcSupport[] = |
||
142 | "\nerror [%s]: zipfile is part of multi-disk archive\n\ |
||
143 | (sorry, not yet supported).\n"; |
||
144 | static ZCONST char Far MaybePakBug[] = "warning [%s]:\ |
||
145 | zipfile claims to be 2nd disk of a 2-part archive;\n\ |
||
146 | attempting to process anyway. If no further errors occur, this archive\n\ |
||
147 | was probably created by PAK v2.51 or earlier. This bug was reported to\n\ |
||
148 | NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\ |
||
149 | of mid-1992 it still hadn't been. (If further errors do occur, archive\n\ |
||
150 | was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\ |
||
151 | multi-part archives.)\n"; |
||
152 | # else |
||
153 | static ZCONST char Far MaybePakBug[] = "warning [%s]:\ |
||
154 | zipfile claims to be last disk of a multi-part archive;\n\ |
||
155 | attempting to process anyway, assuming all parts have been concatenated\n\ |
||
156 | together in order. Expect \"errors\" and warnings...true multi-part support\ |
||
157 | \n doesn't exist yet (coming soon).\n"; |
||
158 | # endif |
||
159 | static ZCONST char Far ExtraBytesAtStart[] = |
||
160 | "warning [%s]: %s extra byte%s at beginning or within zipfile\n\ |
||
161 | (attempting to process anyway)\n"; |
||
162 | #endif /* ?SFX */ |
||
163 | |||
164 | #if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO)) |
||
165 | static ZCONST char Far LogInitline[] = "Archive: %s\n"; |
||
166 | #endif |
||
167 | |||
168 | static ZCONST char Far MissingBytes[] = |
||
169 | "error [%s]: missing %s bytes in zipfile\n\ |
||
170 | (attempting to process anyway)\n"; |
||
171 | static ZCONST char Far NullCentDirOffset[] = |
||
172 | "error [%s]: NULL central directory offset\n\ |
||
173 | (attempting to process anyway)\n"; |
||
174 | static ZCONST char Far ZipfileEmpty[] = "warning [%s]: zipfile is empty\n"; |
||
175 | static ZCONST char Far CentDirStartNotFound[] = |
||
176 | "error [%s]: start of central directory not found;\n\ |
||
177 | zipfile corrupt.\n%s"; |
||
178 | static ZCONST char Far Cent64EndSigSearchErr[] = |
||
179 | "fatal error: read failure while seeking for End-of-centdir-64 signature.\n\ |
||
180 | This zipfile is corrupt.\n"; |
||
181 | static ZCONST char Far Cent64EndSigSearchOff[] = |
||
182 | "error: End-of-centdir-64 signature not where expected (prepended bytes?)\n\ |
||
183 | (attempting to process anyway)\n"; |
||
184 | #ifndef SFX |
||
185 | static ZCONST char Far CentDirTooLong[] = |
||
186 | "error [%s]: reported length of central directory is\n\ |
||
187 | %s bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1\n\ |
||
188 | zipfile?). Compensating...\n"; |
||
189 | static ZCONST char Far CentDirEndSigNotFound[] = "\ |
||
190 | End-of-central-directory signature not found. Either this file is not\n\ |
||
191 | a zipfile, or it constitutes one disk of a multi-part archive. In the\n\ |
||
192 | latter case the central directory and zipfile comment will be found on\n\ |
||
193 | the last disk(s) of this archive.\n"; |
||
194 | #else /* SFX */ |
||
195 | static ZCONST char Far CentDirEndSigNotFound[] = |
||
196 | " End-of-central-directory signature not found.\n"; |
||
197 | #endif /* ?SFX */ |
||
198 | #ifdef TIMESTAMP |
||
199 | static ZCONST char Far ZipTimeStampFailed[] = |
||
200 | "warning: cannot set time for %s\n"; |
||
201 | static ZCONST char Far ZipTimeStampSuccess[] = |
||
202 | "Updated time stamp for %s.\n"; |
||
203 | #endif |
||
204 | static ZCONST char Far ZipfileCommTrunc1[] = |
||
205 | "\ncaution: zipfile comment truncated\n"; |
||
206 | #ifndef NO_ZIPINFO |
||
207 | static ZCONST char Far NoZipfileComment[] = |
||
208 | "There is no zipfile comment.\n"; |
||
209 | static ZCONST char Far ZipfileCommentDesc[] = |
||
210 | "The zipfile comment is %u bytes long and contains the following text:\n"; |
||
211 | static ZCONST char Far ZipfileCommBegin[] = |
||
212 | "======================== zipfile comment begins\ |
||
213 | ==========================\n"; |
||
214 | static ZCONST char Far ZipfileCommEnd[] = |
||
215 | "========================= zipfile comment ends\ |
||
216 | ===========================\n"; |
||
217 | static ZCONST char Far ZipfileCommTrunc2[] = |
||
218 | "\n The zipfile comment is truncated.\n"; |
||
219 | #endif /* !NO_ZIPINFO */ |
||
220 | #ifdef UNICODE_SUPPORT |
||
221 | static ZCONST char Far UnicodeVersionError[] = |
||
222 | "\nwarning: Unicode Path version > 1\n"; |
||
223 | static ZCONST char Far UnicodeMismatchError[] = |
||
224 | "\nwarning: Unicode Path checksum invalid\n"; |
||
225 | #endif |
||
226 | |||
227 | |||
228 | |||
229 | |||
230 | /*******************************/ |
||
231 | /* Function process_zipfiles() */ |
||
232 | /*******************************/ |
||
233 | |||
234 | int process_zipfiles(__G) /* return PK-type error code */ |
||
235 | __GDEF |
||
236 | { |
||
237 | #ifndef SFX |
||
238 | char *lastzipfn = (char *)NULL; |
||
239 | int NumWinFiles, NumLoseFiles, NumWarnFiles; |
||
240 | int NumMissDirs, NumMissFiles; |
||
241 | #endif |
||
242 | int error=0, error_in_archive=0; |
||
243 | |||
244 | |||
245 | /*--------------------------------------------------------------------------- |
||
246 | Start by allocating buffers and (re)constructing the various PK signature |
||
247 | strings. |
||
248 | ---------------------------------------------------------------------------*/ |
||
249 | |||
250 | G.inbuf = (uch *)malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */ |
||
251 | G.outbuf = (uch *)malloc(OUTBUFSIZ + 1); /* 1 extra for string term. */ |
||
252 | |||
253 | if ((G.inbuf == (uch *)NULL) || (G.outbuf == (uch *)NULL)) { |
||
254 | Info(slide, 0x401, ((char *)slide, |
||
255 | LoadFarString(CannotAllocateBuffers))); |
||
256 | return(PK_MEM); |
||
257 | } |
||
258 | G.hold = G.inbuf + INBUFSIZ; /* to check for boundary-spanning sigs */ |
||
259 | #ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */ |
||
260 | #ifdef SMALL_MEM |
||
261 | G.outbuf2 = G.outbuf+RAWBUFSIZ; /* never changes */ |
||
262 | #endif |
||
263 | #endif /* !VMS */ |
||
264 | |||
265 | #if 0 /* CRC_32_TAB has been NULLified by CONSTRUCTGLOBALS !!!! */ |
||
266 | /* allocate the CRC table later when we know we can read zipfile data */ |
||
267 | CRC_32_TAB = NULL; |
||
268 | #endif /* 0 */ |
||
269 | |||
270 | /* finish up initialization of magic signature strings */ |
||
271 | local_hdr_sig[0] /* = extd_local_sig[0] */ = /* ASCII 'P', */ |
||
272 | central_hdr_sig[0] = end_central_sig[0] = /* not EBCDIC */ |
||
273 | end_centloc64_sig[0] = end_central64_sig[0] = 0x50; |
||
274 | |||
275 | local_hdr_sig[1] /* = extd_local_sig[1] */ = /* ASCII 'K', */ |
||
276 | central_hdr_sig[1] = end_central_sig[1] = /* not EBCDIC */ |
||
277 | end_centloc64_sig[1] = end_central64_sig[1] = 0x4B; |
||
278 | |||
279 | /*--------------------------------------------------------------------------- |
||
280 | Make sure timezone info is set correctly; localtime() returns GMT on some |
||
281 | OSes (e.g., Solaris 2.x) if this isn't done first. The ifdefs around |
||
282 | tzset() were initially copied from dos_to_unix_time() in fileio.c. They |
||
283 | may still be too strict; any listed OS that supplies tzset(), regardless |
||
284 | of whether the function does anything, should be removed from the ifdefs. |
||
285 | ---------------------------------------------------------------------------*/ |
||
286 | |||
287 | #if (defined(WIN32) && defined(USE_EF_UT_TIME)) |
||
288 | /* For the Win32 environment, we may have to "prepare" the environment |
||
289 | prior to the tzset() call, to work around tzset() implementation bugs. |
||
290 | */ |
||
291 | iz_w32_prepareTZenv(); |
||
292 | #endif |
||
293 | |||
294 | #if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME)) |
||
295 | # ifndef VALID_TIMEZONE |
||
296 | # define VALID_TIMEZONE(tmp) \ |
||
297 | (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0')) |
||
298 | # endif |
||
299 | { |
||
300 | char *p; |
||
301 | G.tz_is_valid = VALID_TIMEZONE(p); |
||
302 | # ifndef SFX |
||
303 | if (!G.tz_is_valid) { |
||
304 | Info(slide, 0x401, ((char *)slide, LoadFarString(WarnInvalidTZ))); |
||
305 | error_in_archive = error = PK_WARN; |
||
306 | } |
||
307 | # endif /* !SFX */ |
||
308 | } |
||
309 | #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */ |
||
310 | |||
311 | /* For systems that do not have tzset() but supply this function using another |
||
312 | name (_tzset() or something similar), an appropiate "#define tzset ..." |
||
313 | should be added to the system specifc configuration section. */ |
||
314 | #if (!defined(T20_VMS) && !defined(MACOS) && !defined(RISCOS) && !defined(QDOS)) |
||
315 | #if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM)) |
||
316 | tzset(); |
||
317 | #endif |
||
318 | #endif |
||
319 | |||
320 | /* Initialize UnZip's built-in pseudo hard-coded "ISO <--> OEM" translation, |
||
321 | depending on the detected codepage setup. */ |
||
322 | #ifdef NEED_ISO_OEM_INIT |
||
323 | prepare_ISO_OEM_translat(__G); |
||
324 | #endif |
||
325 | |||
326 | /*--------------------------------------------------------------------------- |
||
327 | Initialize the internal flag holding the mode of processing "overwrite |
||
328 | existing file" cases. We do not use the calling interface flags directly |
||
329 | because the overwrite mode may be changed by user interaction while |
||
330 | processing archive files. Such a change should not affect the option |
||
331 | settings as passed through the DLL calling interface. |
||
332 | In case of conflicting options, the 'safer' flag uO.overwrite_none takes |
||
333 | precedence. |
||
334 | ---------------------------------------------------------------------------*/ |
||
335 | G.overwrite_mode = (uO.overwrite_none ? OVERWRT_NEVER : |
||
336 | (uO.overwrite_all ? OVERWRT_ALWAYS : OVERWRT_QUERY)); |
||
337 | |||
338 | /*--------------------------------------------------------------------------- |
||
339 | Match (possible) wildcard zipfile specification with existing files and |
||
340 | attempt to process each. If no hits, try again after appending ".zip" |
||
341 | suffix. If still no luck, give up. |
||
342 | ---------------------------------------------------------------------------*/ |
||
343 | |||
344 | #ifdef SFX |
||
345 | if ((error = do_seekable(__G__ 0)) == PK_NOZIP) { |
||
346 | #ifdef EXE_EXTENSION |
||
347 | int len=strlen(G.argv0); |
||
348 | |||
349 | /* append .exe if appropriate; also .sfx? */ |
||
350 | if ( (G.zipfn = (char *)malloc(len+sizeof(EXE_EXTENSION))) != |
||
351 | (char *)NULL ) { |
||
352 | strcpy(G.zipfn, G.argv0); |
||
353 | strcpy(G.zipfn+len, EXE_EXTENSION); |
||
354 | error = do_seekable(__G__ 0); |
||
355 | free(G.zipfn); |
||
356 | G.zipfn = G.argv0; /* for "cannot find myself" message only */ |
||
357 | } |
||
358 | #endif /* EXE_EXTENSION */ |
||
359 | #ifdef WIN32 |
||
360 | G.zipfn = G.argv0; /* for "cannot find myself" message only */ |
||
361 | #endif |
||
362 | } |
||
363 | if (error) { |
||
364 | if (error == IZ_DIR) |
||
365 | error_in_archive = PK_NOZIP; |
||
366 | else |
||
367 | error_in_archive = error; |
||
368 | if (error == PK_NOZIP) |
||
369 | Info(slide, 1, ((char *)slide, LoadFarString(CannotFindMyself), |
||
370 | G.zipfn)); |
||
371 | } |
||
372 | #ifdef CHEAP_SFX_AUTORUN |
||
373 | if (G.autorun_command[0] && !uO.qflag) { /* NO autorun without prompt! */ |
||
374 | Info(slide, 0x81, ((char *)slide, LoadFarString(AutorunPrompt), |
||
375 | FnFilter1(G.autorun_command))); |
||
376 | if (fgets(G.answerbuf, 9, stdin) != (char *)NULL |
||
377 | && toupper(*G.answerbuf) == 'Y') |
||
378 | system(G.autorun_command); |
||
379 | else |
||
380 | Info(slide, 1, ((char *)slide, LoadFarString(NotAutoRunning))); |
||
381 | } |
||
382 | #endif /* CHEAP_SFX_AUTORUN */ |
||
383 | |||
384 | #else /* !SFX */ |
||
385 | NumWinFiles = NumLoseFiles = NumWarnFiles = 0; |
||
386 | NumMissDirs = NumMissFiles = 0; |
||
387 | |||
388 | while ((G.zipfn = do_wild(__G__ G.wildzipfn)) != (char *)NULL) { |
||
389 | Trace((stderr, "do_wild( %s ) returns %s\n", G.wildzipfn, G.zipfn)); |
||
390 | |||
391 | lastzipfn = G.zipfn; |
||
392 | |||
393 | /* print a blank line between the output of different zipfiles */ |
||
394 | if (!uO.qflag && error != PK_NOZIP && error != IZ_DIR |
||
395 | #ifdef TIMESTAMP |
||
396 | && (!uO.T_flag || uO.zipinfo_mode) |
||
397 | #endif |
||
398 | && (NumWinFiles+NumLoseFiles+NumWarnFiles+NumMissFiles) > 0) |
||
399 | (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); |
||
400 | |||
401 | if ((error = do_seekable(__G__ 0)) == PK_WARN) |
||
402 | ++NumWarnFiles; |
||
403 | else if (error == IZ_DIR) |
||
404 | ++NumMissDirs; |
||
405 | else if (error == PK_NOZIP) |
||
406 | ++NumMissFiles; |
||
407 | else if (error != PK_OK) |
||
408 | ++NumLoseFiles; |
||
409 | else |
||
410 | ++NumWinFiles; |
||
411 | |||
412 | Trace((stderr, "do_seekable(0) returns %d\n", error)); |
||
413 | if (error != IZ_DIR && error > error_in_archive) |
||
414 | error_in_archive = error; |
||
415 | #ifdef WINDLL |
||
416 | if (error == IZ_CTRLC) { |
||
417 | free_G_buffers(__G); |
||
418 | return error; |
||
419 | } |
||
420 | #endif |
||
421 | |||
422 | } /* end while-loop (wildcard zipfiles) */ |
||
423 | |||
424 | if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0 && |
||
425 | (NumMissDirs + NumMissFiles) == 1 && lastzipfn != (char *)NULL) |
||
426 | { |
||
427 | #if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */ |
||
428 | if (iswild(G.wildzipfn)) { |
||
429 | if (iswild(lastzipfn)) { |
||
430 | NumMissDirs = NumMissFiles = 0; |
||
431 | error_in_archive = PK_COOL; |
||
432 | if (uO.qflag < 3) |
||
433 | Info(slide, 0x401, ((char *)slide, |
||
434 | LoadFarString(CannotFindWildcardMatch), |
||
435 | LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), |
||
436 | G.wildzipfn)); |
||
437 | } |
||
438 | } else |
||
439 | #endif |
||
440 | { |
||
441 | #ifndef VMS |
||
442 | /* 2004-11-24 SMS. |
||
443 | * VMS has already tried a default file type of ".zip" in |
||
444 | * do_wild(), so adding ZSUFX here only causes confusion by |
||
445 | * corrupting some valid (though nonexistent) file names. |
||
446 | * Complaining below about "fred;4.zip" is unlikely to be |
||
447 | * helpful to the victim. |
||
448 | */ |
||
449 | /* 2005-08-14 Chr. Spieler |
||
450 | * Although we already "know" the failure result, we call |
||
451 | * do_seekable() again with the same zipfile name (and the |
||
452 | * lastchance flag set), just to trigger the error report... |
||
453 | */ |
||
454 | #if defined(UNIX) || defined(QDOS) |
||
455 | char *p = |
||
456 | #endif |
||
457 | strcpy(lastzipfn + strlen(lastzipfn), ZSUFX); |
||
458 | #endif /* !VMS */ |
||
459 | |||
460 | G.zipfn = lastzipfn; |
||
461 | |||
462 | NumMissDirs = NumMissFiles = 0; |
||
463 | error_in_archive = PK_COOL; |
||
464 | |||
465 | #if defined(UNIX) || defined(QDOS) |
||
466 | /* only Unix has case-sensitive filesystems */ |
||
467 | /* Well FlexOS (sometimes) also has them, but support is per media */ |
||
468 | /* and a pig to code for, so treat as case insensitive for now */ |
||
469 | /* we do this under QDOS to check for .zip as well as _zip */ |
||
470 | if ((error = do_seekable(__G__ 0)) == PK_NOZIP || error == IZ_DIR) { |
||
471 | if (error == IZ_DIR) |
||
472 | ++NumMissDirs; |
||
473 | strcpy(p, ALT_ZSUFX); |
||
474 | error = do_seekable(__G__ 1); |
||
475 | } |
||
476 | #else |
||
477 | error = do_seekable(__G__ 1); |
||
478 | #endif |
||
479 | Trace((stderr, "do_seekable(1) returns %d\n", error)); |
||
480 | switch (error) { |
||
481 | case PK_WARN: |
||
482 | ++NumWarnFiles; |
||
483 | break; |
||
484 | case IZ_DIR: |
||
485 | ++NumMissDirs; |
||
486 | error = PK_NOZIP; |
||
487 | break; |
||
488 | case PK_NOZIP: |
||
489 | /* increment again => bug: |
||
490 | "1 file had no zipfile directory." */ |
||
491 | /* ++NumMissFiles */ ; |
||
492 | break; |
||
493 | default: |
||
494 | if (error) |
||
495 | ++NumLoseFiles; |
||
496 | else |
||
497 | ++NumWinFiles; |
||
498 | break; |
||
499 | } |
||
500 | |||
501 | if (error > error_in_archive) |
||
502 | error_in_archive = error; |
||
503 | #ifdef WINDLL |
||
504 | if (error == IZ_CTRLC) { |
||
505 | free_G_buffers(__G); |
||
506 | return error; |
||
507 | } |
||
508 | #endif |
||
509 | } |
||
510 | } |
||
511 | #endif /* ?SFX */ |
||
512 | |||
513 | /*--------------------------------------------------------------------------- |
||
514 | Print summary of all zipfiles, assuming zipfile spec was a wildcard (no |
||
515 | need for a summary if just one zipfile). |
||
516 | ---------------------------------------------------------------------------*/ |
||
517 | |||
518 | #ifndef SFX |
||
519 | if (iswild(G.wildzipfn) && uO.qflag < 3 |
||
520 | #ifdef TIMESTAMP |
||
521 | && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag > 1) |
||
522 | #endif |
||
523 | ) |
||
524 | { |
||
525 | if ((NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1) |
||
526 | #ifdef TIMESTAMP |
||
527 | && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag) |
||
528 | #endif |
||
529 | && !(uO.tflag && uO.qflag > 1)) |
||
530 | (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0x401); |
||
531 | if ((NumWinFiles > 1) || |
||
532 | (NumWinFiles == 1 && |
||
533 | NumMissDirs + NumMissFiles + NumLoseFiles + NumWarnFiles > 0)) |
||
534 | Info(slide, 0x401, ((char *)slide, LoadFarString(FilesProcessOK), |
||
535 | NumWinFiles, (NumWinFiles == 1)? " was" : "s were")); |
||
536 | if (NumWarnFiles > 0) |
||
537 | Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveWarning), |
||
538 | NumWarnFiles, (NumWarnFiles == 1)? "" : "s")); |
||
539 | if (NumLoseFiles > 0) |
||
540 | Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveFatalError), |
||
541 | NumLoseFiles, (NumLoseFiles == 1)? "" : "s")); |
||
542 | if (NumMissFiles > 0) |
||
543 | Info(slide, 0x401, ((char *)slide, |
||
544 | LoadFarString(FileHadNoZipfileDir), NumMissFiles, |
||
545 | (NumMissFiles == 1)? "" : "s")); |
||
546 | if (NumMissDirs == 1) |
||
547 | Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileWasDir))); |
||
548 | else if (NumMissDirs > 0) |
||
549 | Info(slide, 0x401, ((char *)slide, |
||
550 | LoadFarString(ManyZipfilesWereDir), NumMissDirs)); |
||
551 | if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0) |
||
552 | Info(slide, 0x401, ((char *)slide, LoadFarString(NoZipfileFound))); |
||
553 | } |
||
554 | #endif /* !SFX */ |
||
555 | |||
556 | /* free allocated memory */ |
||
557 | free_G_buffers(__G); |
||
558 | |||
559 | return error_in_archive; |
||
560 | |||
561 | } /* end function process_zipfiles() */ |
||
562 | |||
563 | |||
564 | |||
565 | |||
566 | |||
567 | /*****************************/ |
||
568 | /* Function free_G_buffers() */ |
||
569 | /*****************************/ |
||
570 | |||
571 | void free_G_buffers(__G) /* releases all memory allocated in global vars */ |
||
572 | __GDEF |
||
573 | { |
||
574 | #ifndef SFX |
||
575 | unsigned i; |
||
576 | #endif |
||
577 | |||
578 | #ifdef SYSTEM_SPECIFIC_DTOR |
||
579 | SYSTEM_SPECIFIC_DTOR(__G); |
||
580 | #endif |
||
581 | |||
582 | inflate_free(__G); |
||
583 | checkdir(__G__ (char *)NULL, END); |
||
584 | |||
585 | #ifdef DYNALLOC_CRCTAB |
||
586 | if (CRC_32_TAB) { |
||
587 | free_crc_table(); |
||
588 | CRC_32_TAB = NULL; |
||
589 | } |
||
590 | #endif |
||
591 | |||
592 | if (G.key != (char *)NULL) { |
||
593 | free(G.key); |
||
594 | G.key = (char *)NULL; |
||
595 | } |
||
596 | |||
597 | if (G.extra_field != (uch *)NULL) { |
||
598 | free(G.extra_field); |
||
599 | G.extra_field = (uch *)NULL; |
||
600 | } |
||
601 | |||
602 | #if (!defined(VMS) && !defined(SMALL_MEM)) |
||
603 | /* VMS uses its own buffer scheme for textmode flush() */ |
||
604 | if (G.outbuf2) { |
||
605 | free(G.outbuf2); /* malloc'd ONLY if unshrink and -a */ |
||
606 | G.outbuf2 = (uch *)NULL; |
||
607 | } |
||
608 | #endif |
||
609 | |||
610 | if (G.outbuf) |
||
611 | free(G.outbuf); |
||
612 | if (G.inbuf) |
||
613 | free(G.inbuf); |
||
614 | G.inbuf = G.outbuf = (uch *)NULL; |
||
615 | |||
616 | #ifdef UNICODE_SUPPORT |
||
617 | if (G.filename_full) { |
||
618 | free(G.filename_full); |
||
619 | G.filename_full = (char *)NULL; |
||
620 | G.fnfull_bufsize = 0; |
||
621 | } |
||
622 | #endif /* UNICODE_SUPPORT */ |
||
623 | |||
624 | #ifndef SFX |
||
625 | for (i = 0; i < DIR_BLKSIZ; i++) { |
||
626 | if (G.info[i].cfilname != (char Far *)NULL) { |
||
627 | zffree(G.info[i].cfilname); |
||
628 | G.info[i].cfilname = (char Far *)NULL; |
||
629 | } |
||
630 | } |
||
631 | #endif |
||
632 | |||
633 | #ifdef MALLOC_WORK |
||
634 | if (G.area.Slide) { |
||
635 | free(G.area.Slide); |
||
636 | G.area.Slide = (uch *)NULL; |
||
637 | } |
||
638 | #endif |
||
639 | |||
640 | } /* end function free_G_buffers() */ |
||
641 | |||
642 | |||
643 | |||
644 | |||
645 | |||
646 | /**************************/ |
||
647 | /* Function do_seekable() */ |
||
648 | /**************************/ |
||
649 | |||
650 | static int do_seekable(__G__ lastchance) /* return PK-type error code */ |
||
651 | __GDEF |
||
652 | int lastchance; |
||
653 | { |
||
654 | #ifndef SFX |
||
655 | /* static int no_ecrec = FALSE; SKM: moved to globals.h */ |
||
656 | int maybe_exe=FALSE; |
||
657 | int too_weird_to_continue=FALSE; |
||
658 | #ifdef TIMESTAMP |
||
659 | time_t uxstamp; |
||
660 | ulg nmember = 0L; |
||
661 | #endif |
||
662 | #endif |
||
663 | int error=0, error_in_archive; |
||
664 | |||
665 | |||
666 | /*--------------------------------------------------------------------------- |
||
667 | Open the zipfile for reading in BINARY mode to prevent CR/LF translation, |
||
668 | which would corrupt the bit streams. |
||
669 | ---------------------------------------------------------------------------*/ |
||
670 | |||
671 | if (SSTAT(G.zipfn, &G.statbuf) || |
||
672 | #ifdef THEOS |
||
673 | (error = S_ISLIB(G.statbuf.st_mode)) != 0 || |
||
674 | #endif |
||
675 | (error = S_ISDIR(G.statbuf.st_mode)) != 0) |
||
676 | { |
||
677 | #ifndef SFX |
||
678 | if (lastchance && (uO.qflag < 3)) { |
||
679 | #if defined(UNIX) || defined(QDOS) |
||
680 | if (G.no_ecrec) |
||
681 | Info(slide, 1, ((char *)slide, |
||
682 | LoadFarString(CannotFindZipfileDirMsg), |
||
683 | LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), |
||
684 | G.wildzipfn, uO.zipinfo_mode? " " : "", G.wildzipfn, |
||
685 | G.zipfn)); |
||
686 | else |
||
687 | Info(slide, 1, ((char *)slide, |
||
688 | LoadFarString(CannotFindEitherZipfile), |
||
689 | LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), |
||
690 | G.wildzipfn, G.wildzipfn, G.zipfn)); |
||
691 | #else /* !(UNIX || QDOS) */ |
||
692 | if (G.no_ecrec) |
||
693 | Info(slide, 0x401, ((char *)slide, |
||
694 | LoadFarString(CannotFindZipfileDirMsg), |
||
695 | LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), |
||
696 | G.wildzipfn, uO.zipinfo_mode? " " : "", G.zipfn)); |
||
697 | else |
||
698 | #ifdef VMS |
||
699 | Info(slide, 0x401, ((char *)slide, |
||
700 | LoadFarString(CannotFindEitherZipfile), |
||
701 | LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), |
||
702 | G.wildzipfn, |
||
703 | (*G.zipfn ? G.zipfn : vms_msg_text()))); |
||
704 | #else /* !VMS */ |
||
705 | Info(slide, 0x401, ((char *)slide, |
||
706 | LoadFarString(CannotFindEitherZipfile), |
||
707 | LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), |
||
708 | G.wildzipfn, G.zipfn)); |
||
709 | #endif /* ?VMS */ |
||
710 | #endif /* ?(UNIX || QDOS) */ |
||
711 | } |
||
712 | #endif /* !SFX */ |
||
713 | return error? IZ_DIR : PK_NOZIP; |
||
714 | } |
||
715 | G.ziplen = G.statbuf.st_size; |
||
716 | |||
717 | #ifndef SFX |
||
718 | #if defined(UNIX) || defined(DOS_OS2_W32) || defined(THEOS) |
||
719 | if (G.statbuf.st_mode & S_IEXEC) /* no extension on Unix exes: might */ |
||
720 | maybe_exe = TRUE; /* find unzip, not unzip.zip; etc. */ |
||
721 | #endif |
||
722 | #endif /* !SFX */ |
||
723 | |||
724 | #ifdef VMS |
||
725 | if (check_format(__G)) /* check for variable-length format */ |
||
726 | return PK_ERR; |
||
727 | #endif |
||
728 | |||
729 | if (open_input_file(__G)) /* this should never happen, given */ |
||
730 | return PK_NOZIP; /* the stat() test above, but... */ |
||
731 | |||
732 | #ifdef DO_SAFECHECK_2GB |
||
733 | /* Need more care: Do not trust the size returned by stat() but |
||
734 | determine it by reading beyond the end of the file. */ |
||
735 | G.ziplen = file_size(G.zipfd); |
||
736 | |||
737 | if (G.ziplen == EOF) { |
||
738 | Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileTooBig))); |
||
739 | /* |
||
740 | printf( |
||
741 | " We need a better error message for: 64-bit file, 32-bit program.\n"); |
||
742 | */ |
||
743 | CLOSE_INFILE(); |
||
744 | return IZ_ERRBF; |
||
745 | } |
||
746 | #endif /* DO_SAFECHECK_2GB */ |
||
747 | |||
748 | /*--------------------------------------------------------------------------- |
||
749 | Find and process the end-of-central-directory header. UnZip need only |
||
750 | check last 65557 bytes of zipfile: comment may be up to 65535, end-of- |
||
751 | central-directory record is 18 bytes, and signature itself is 4 bytes; |
||
752 | add some to allow for appended garbage. Since ZipInfo is often used as |
||
753 | a debugging tool, search the whole zipfile if zipinfo_mode is true. |
||
754 | ---------------------------------------------------------------------------*/ |
||
755 | |||
756 | G.cur_zipfile_bufstart = 0; |
||
757 | G.inptr = G.inbuf; |
||
758 | |||
759 | #if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO)) |
||
760 | # if (!defined(WINDLL) && !defined(SFX)) |
||
761 | if ( (!uO.zipinfo_mode && !uO.qflag |
||
762 | # ifdef TIMESTAMP |
||
763 | && !uO.T_flag |
||
764 | # endif |
||
765 | ) |
||
766 | # ifndef NO_ZIPINFO |
||
767 | || (uO.zipinfo_mode && uO.hflag) |
||
768 | # endif |
||
769 | ) |
||
770 | # else /* not (!WINDLL && !SFX) ==> !NO_ZIPINFO !! */ |
||
771 | if (uO.zipinfo_mode && uO.hflag) |
||
772 | # endif /* if..else..: (!WINDLL && !SFX) */ |
||
773 | # ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */ |
||
774 | Info(slide, 0, ((char *)slide, LoadFarString(LogInitline), |
||
775 | FnFilter1(G.zipfn))); |
||
776 | # else |
||
777 | Info(slide, 0, ((char *)slide, LoadFarString(LogInitline), G.zipfn)); |
||
778 | # endif |
||
779 | #endif /* (!WINDLL && !SFX) || !NO_ZIPINFO */ |
||
780 | |||
781 | if ( (error_in_archive = find_ecrec(__G__ |
||
782 | #ifndef NO_ZIPINFO |
||
783 | uO.zipinfo_mode ? G.ziplen : |
||
784 | #endif |
||
785 | MIN(G.ziplen, 66000L))) |
||
786 | > PK_WARN ) |
||
787 | { |
||
788 | CLOSE_INFILE(); |
||
789 | |||
790 | #ifdef SFX |
||
791 | ++lastchance; /* avoid picky compiler warnings */ |
||
792 | return error_in_archive; |
||
793 | #else |
||
794 | if (maybe_exe) |
||
795 | Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeExe), |
||
796 | G.zipfn)); |
||
797 | if (lastchance) |
||
798 | return error_in_archive; |
||
799 | else { |
||
800 | G.no_ecrec = TRUE; /* assume we found wrong file: e.g., */ |
||
801 | return PK_NOZIP; /* unzip instead of unzip.zip */ |
||
802 | } |
||
803 | #endif /* ?SFX */ |
||
804 | } |
||
805 | |||
806 | if ((uO.zflag > 0) && !uO.zipinfo_mode) { /* unzip: zflag = comment ONLY */ |
||
807 | CLOSE_INFILE(); |
||
808 | return error_in_archive; |
||
809 | } |
||
810 | |||
811 | /*--------------------------------------------------------------------------- |
||
812 | Test the end-of-central-directory info for incompatibilities (multi-disk |
||
813 | archives) or inconsistencies (missing or extra bytes in zipfile). |
||
814 | ---------------------------------------------------------------------------*/ |
||
815 | |||
816 | #ifdef NO_MULTIPART |
||
817 | error = !uO.zipinfo_mode && (G.ecrec.number_this_disk == 1) && |
||
818 | (G.ecrec.num_disk_start_cdir == 1); |
||
819 | #else |
||
820 | error = !uO.zipinfo_mode && (G.ecrec.number_this_disk != 0); |
||
821 | #endif |
||
822 | |||
823 | #ifndef SFX |
||
824 | if (uO.zipinfo_mode && |
||
825 | G.ecrec.number_this_disk != G.ecrec.num_disk_start_cdir) |
||
826 | { |
||
827 | if (G.ecrec.number_this_disk > G.ecrec.num_disk_start_cdir) { |
||
828 | Info(slide, 0x401, ((char *)slide, |
||
829 | LoadFarString(CentDirNotInZipMsg), G.zipfn, |
||
830 | (ulg)G.ecrec.number_this_disk, |
||
831 | (ulg)G.ecrec.num_disk_start_cdir)); |
||
832 | error_in_archive = PK_FIND; |
||
833 | too_weird_to_continue = TRUE; |
||
834 | } else { |
||
835 | Info(slide, 0x401, ((char *)slide, |
||
836 | LoadFarString(EndCentDirBogus), G.zipfn, |
||
837 | (ulg)G.ecrec.number_this_disk, |
||
838 | (ulg)G.ecrec.num_disk_start_cdir)); |
||
839 | error_in_archive = PK_WARN; |
||
840 | } |
||
841 | #ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */ |
||
842 | } else if (!uO.zipinfo_mode && !error && G.ecrec.number_this_disk != 0) { |
||
843 | Info(slide, 0x401, ((char *)slide, LoadFarString(NoMultiDiskArcSupport), |
||
844 | G.zipfn)); |
||
845 | error_in_archive = PK_FIND; |
||
846 | too_weird_to_continue = TRUE; |
||
847 | #endif |
||
848 | } |
||
849 | |||
850 | if (!too_weird_to_continue) { /* (relatively) normal zipfile: go for it */ |
||
851 | if (error) { |
||
852 | Info(slide, 0x401, ((char *)slide, LoadFarString(MaybePakBug), |
||
853 | G.zipfn)); |
||
854 | error_in_archive = PK_WARN; |
||
855 | } |
||
856 | #endif /* !SFX */ |
||
857 | if ((G.extra_bytes = G.real_ecrec_offset-G.expect_ecrec_offset) < |
||
858 | (zoff_t)0) |
||
859 | { |
||
860 | Info(slide, 0x401, ((char *)slide, LoadFarString(MissingBytes), |
||
861 | G.zipfn, FmZofft((-G.extra_bytes), NULL, NULL))); |
||
862 | error_in_archive = PK_ERR; |
||
863 | } else if (G.extra_bytes > 0) { |
||
864 | if ((G.ecrec.offset_start_central_directory == 0) && |
||
865 | (G.ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */ |
||
866 | { |
||
867 | Info(slide, 0x401, ((char *)slide, |
||
868 | LoadFarString(NullCentDirOffset), G.zipfn)); |
||
869 | G.ecrec.offset_start_central_directory = G.extra_bytes; |
||
870 | G.extra_bytes = 0; |
||
871 | error_in_archive = PK_ERR; |
||
872 | } |
||
873 | #ifndef SFX |
||
874 | else { |
||
875 | Info(slide, 0x401, ((char *)slide, |
||
876 | LoadFarString(ExtraBytesAtStart), G.zipfn, |
||
877 | FmZofft(G.extra_bytes, NULL, NULL), |
||
878 | (G.extra_bytes == 1)? "":"s")); |
||
879 | error_in_archive = PK_WARN; |
||
880 | } |
||
881 | #endif /* !SFX */ |
||
882 | } |
||
883 | |||
884 | /*----------------------------------------------------------------------- |
||
885 | Check for empty zipfile and exit now if so. |
||
886 | -----------------------------------------------------------------------*/ |
||
887 | |||
888 | if (G.expect_ecrec_offset==0L && G.ecrec.size_central_directory==0) { |
||
889 | if (uO.zipinfo_mode) |
||
890 | Info(slide, 0, ((char *)slide, "%sEmpty zipfile.\n", |
||
891 | uO.lflag>9? "\n " : "")); |
||
892 | else |
||
893 | Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileEmpty), |
||
894 | G.zipfn)); |
||
895 | CLOSE_INFILE(); |
||
896 | return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN; |
||
897 | } |
||
898 | |||
899 | /*----------------------------------------------------------------------- |
||
900 | Compensate for missing or extra bytes, and seek to where the start |
||
901 | of central directory should be. If header not found, uncompensate |
||
902 | and try again (necessary for at least some Atari archives created |
||
903 | with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1). |
||
904 | -----------------------------------------------------------------------*/ |
||
905 | |||
906 | error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); |
||
907 | if (error == PK_BADERR) { |
||
908 | CLOSE_INFILE(); |
||
909 | return PK_BADERR; |
||
910 | } |
||
911 | #ifdef OLD_SEEK_TEST |
||
912 | if (error != PK_OK || readbuf(__G__ G.sig, 4) == 0) { |
||
913 | CLOSE_INFILE(); |
||
914 | return PK_ERR; /* file may be locked, or possibly disk error(?) */ |
||
915 | } |
||
916 | if (memcmp(G.sig, central_hdr_sig, 4)) |
||
917 | #else |
||
918 | if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) || |
||
919 | memcmp(G.sig, central_hdr_sig, 4)) |
||
920 | #endif |
||
921 | { |
||
922 | #ifndef SFX |
||
923 | zoff_t tmp = G.extra_bytes; |
||
924 | #endif |
||
925 | |||
926 | G.extra_bytes = 0; |
||
927 | error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); |
||
928 | if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) || |
||
929 | memcmp(G.sig, central_hdr_sig, 4)) |
||
930 | { |
||
931 | if (error != PK_BADERR) |
||
932 | Info(slide, 0x401, ((char *)slide, |
||
933 | LoadFarString(CentDirStartNotFound), G.zipfn, |
||
934 | LoadFarStringSmall(ReportMsg))); |
||
935 | CLOSE_INFILE(); |
||
936 | return (error != PK_OK ? error : PK_BADERR); |
||
937 | } |
||
938 | #ifndef SFX |
||
939 | Info(slide, 0x401, ((char *)slide, LoadFarString(CentDirTooLong), |
||
940 | G.zipfn, FmZofft((-tmp), NULL, NULL))); |
||
941 | #endif |
||
942 | error_in_archive = PK_ERR; |
||
943 | } |
||
944 | |||
945 | /*----------------------------------------------------------------------- |
||
946 | Seek to the start of the central directory one last time, since we |
||
947 | have just read the first entry's signature bytes; then list, extract |
||
948 | or test member files as instructed, and close the zipfile. |
||
949 | -----------------------------------------------------------------------*/ |
||
950 | |||
951 | error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); |
||
952 | if (error != PK_OK) { |
||
953 | CLOSE_INFILE(); |
||
954 | return error; |
||
955 | } |
||
956 | |||
957 | Trace((stderr, "about to extract/list files (error = %d)\n", |
||
958 | error_in_archive)); |
||
959 | |||
960 | #ifdef DLL |
||
961 | /* G.fValidate is used only to look at an archive to see if |
||
962 | it appears to be a valid archive. There is no interest |
||
963 | in what the archive contains, nor in validating that the |
||
964 | entries in the archive are in good condition. This is |
||
965 | currently used only in the Windows DLLs for purposes of |
||
966 | checking archives within an archive to determine whether |
||
967 | or not to display the inner archives. |
||
968 | */ |
||
969 | if (!G.fValidate) |
||
970 | #endif |
||
971 | { |
||
972 | #ifndef NO_ZIPINFO |
||
973 | if (uO.zipinfo_mode) |
||
974 | error = zipinfo(__G); /* ZIPINFO 'EM */ |
||
975 | else |
||
976 | #endif |
||
977 | #ifndef SFX |
||
978 | #ifdef TIMESTAMP |
||
979 | if (uO.T_flag) |
||
980 | error = get_time_stamp(__G__ &uxstamp, &nmember); |
||
981 | else |
||
982 | #endif |
||
983 | if (uO.vflag && !uO.tflag && !uO.cflag) |
||
984 | error = list_files(__G); /* LIST 'EM */ |
||
985 | else |
||
986 | #endif /* !SFX */ |
||
987 | error = extract_or_test_files(__G); /* EXTRACT OR TEST 'EM */ |
||
988 | |||
989 | Trace((stderr, "done with extract/list files (error = %d)\n", |
||
990 | error)); |
||
991 | } |
||
992 | |||
993 | if (error > error_in_archive) /* don't overwrite stronger error */ |
||
994 | error_in_archive = error; /* with (for example) a warning */ |
||
995 | #ifndef SFX |
||
996 | } /* end if (!too_weird_to_continue) */ |
||
997 | #endif |
||
998 | |||
999 | CLOSE_INFILE(); |
||
1000 | |||
1001 | #ifdef TIMESTAMP |
||
1002 | if (uO.T_flag && !uO.zipinfo_mode && (nmember > 0L)) { |
||
1003 | # ifdef WIN32 |
||
1004 | if (stamp_file(__G__ G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */ |
||
1005 | # else |
||
1006 | if (stamp_file(G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */ |
||
1007 | # endif |
||
1008 | if (uO.qflag < 3) |
||
1009 | Info(slide, 0x201, ((char *)slide, |
||
1010 | LoadFarString(ZipTimeStampFailed), G.zipfn)); |
||
1011 | if (error_in_archive < PK_WARN) |
||
1012 | error_in_archive = PK_WARN; |
||
1013 | } else { |
||
1014 | if (!uO.qflag) |
||
1015 | Info(slide, 0, ((char *)slide, |
||
1016 | LoadFarString(ZipTimeStampSuccess), G.zipfn)); |
||
1017 | } |
||
1018 | } |
||
1019 | #endif |
||
1020 | return error_in_archive; |
||
1021 | |||
1022 | } /* end function do_seekable() */ |
||
1023 | |||
1024 | |||
1025 | |||
1026 | |||
1027 | #ifdef DO_SAFECHECK_2GB |
||
1028 | /************************/ |
||
1029 | /* Function file_size() */ |
||
1030 | /************************/ |
||
1031 | /* File size determination which does not mislead for large files in a |
||
1032 | small-file program. Probably should be somewhere else. |
||
1033 | The file has to be opened previously |
||
1034 | */ |
||
1035 | #ifdef USE_STRM_INPUT |
||
1036 | static zoff_t file_size(file) |
||
1037 | FILE *file; |
||
1038 | { |
||
1039 | int sts; |
||
1040 | size_t siz; |
||
1041 | #else /* !USE_STRM_INPUT */ |
||
1042 | static zoff_t file_size(fh) |
||
1043 | int fh; |
||
1044 | { |
||
1045 | int siz; |
||
1046 | #endif /* ?USE_STRM_INPUT */ |
||
1047 | zoff_t ofs; |
||
1048 | char waste[4]; |
||
1049 | |||
1050 | #ifdef USE_STRM_INPUT |
||
1051 | /* Seek to actual EOF. */ |
||
1052 | sts = zfseeko(file, 0, SEEK_END); |
||
1053 | if (sts != 0) { |
||
1054 | /* fseeko() failed. (Unlikely.) */ |
||
1055 | ofs = EOF; |
||
1056 | } else { |
||
1057 | /* Get apparent offset at EOF. */ |
||
1058 | ofs = zftello(file); |
||
1059 | if (ofs < 0) { |
||
1060 | /* Offset negative (overflow). File too big. */ |
||
1061 | ofs = EOF; |
||
1062 | } else { |
||
1063 | /* Seek to apparent EOF offset. |
||
1064 | Won't be at actual EOF if offset was truncated. |
||
1065 | */ |
||
1066 | sts = zfseeko(file, ofs, SEEK_SET); |
||
1067 | if (sts != 0) { |
||
1068 | /* fseeko() failed. (Unlikely.) */ |
||
1069 | ofs = EOF; |
||
1070 | } else { |
||
1071 | /* Read a byte at apparent EOF. Should set EOF flag. */ |
||
1072 | siz = fread(waste, 1, 1, file); |
||
1073 | if (feof(file) == 0) { |
||
1074 | /* Not at EOF, but should be. File too big. */ |
||
1075 | ofs = EOF; |
||
1076 | } |
||
1077 | } |
||
1078 | } |
||
1079 | } |
||
1080 | #else /* !USE_STRM_INPUT */ |
||
1081 | /* Seek to actual EOF. */ |
||
1082 | ofs = zlseek(fh, 0, SEEK_END); |
||
1083 | if (ofs == (zoff_t) -1) { |
||
1084 | /* zlseek() failed. (Unlikely.) */ |
||
1085 | ofs = EOF; |
||
1086 | } else if (ofs < 0) { |
||
1087 | /* Offset negative (overflow). File too big. */ |
||
1088 | ofs = EOF; |
||
1089 | } else { |
||
1090 | /* Seek to apparent EOF offset. |
||
1091 | Won't be at actual EOF if offset was truncated. |
||
1092 | */ |
||
1093 | ofs = zlseek(fh, ofs, SEEK_SET); |
||
1094 | if (ofs == (zoff_t) -1) { |
||
1095 | /* zlseek() failed. (Unlikely.) */ |
||
1096 | ofs = EOF; |
||
1097 | } else { |
||
1098 | /* Read a byte at apparent EOF. Should set EOF flag. */ |
||
1099 | siz = read(fh, waste, 1); |
||
1100 | if (siz != 0) { |
||
1101 | /* Not at EOF, but should be. File too big. */ |
||
1102 | ofs = EOF; |
||
1103 | } |
||
1104 | } |
||
1105 | } |
||
1106 | #endif /* ?USE_STRM_INPUT */ |
||
1107 | return ofs; |
||
1108 | } /* end function file_size() */ |
||
1109 | #endif /* DO_SAFECHECK_2GB */ |
||
1110 | |||
1111 | |||
1112 | |||
1113 | |||
1114 | /***********************/ |
||
1115 | /* Function rec_find() */ |
||
1116 | /***********************/ |
||
1117 | |||
1118 | static int rec_find(__G__ searchlen, signature, rec_size) |
||
1119 | /* return 0 when rec found, 1 when not found, 2 in case of read error */ |
||
1120 | __GDEF |
||
1121 | zoff_t searchlen; |
||
1122 | char* signature; |
||
1123 | int rec_size; |
||
1124 | { |
||
1125 | int i, numblks, found=FALSE; |
||
1126 | zoff_t tail_len; |
||
1127 | |||
1128 | /*--------------------------------------------------------------------------- |
||
1129 | Zipfile is longer than INBUFSIZ: may need to loop. Start with short |
||
1130 | block at end of zipfile (if not TOO short). |
||
1131 | ---------------------------------------------------------------------------*/ |
||
1132 | |||
1133 | if ((tail_len = G.ziplen % INBUFSIZ) > rec_size) { |
||
1134 | #ifdef USE_STRM_INPUT |
||
1135 | zfseeko(G.zipfd, G.ziplen-tail_len, SEEK_SET); |
||
1136 | G.cur_zipfile_bufstart = zftello(G.zipfd); |
||
1137 | #else /* !USE_STRM_INPUT */ |
||
1138 | G.cur_zipfile_bufstart = zlseek(G.zipfd, G.ziplen-tail_len, SEEK_SET); |
||
1139 | #endif /* ?USE_STRM_INPUT */ |
||
1140 | if ((G.incnt = read(G.zipfd, (char *)G.inbuf, |
||
1141 | (unsigned int)tail_len)) != (int)tail_len) |
||
1142 | return 2; /* it's expedient... */ |
||
1143 | |||
1144 | /* 'P' must be at least (rec_size+4) bytes from end of zipfile */ |
||
1145 | for (G.inptr = G.inbuf+(int)tail_len-(rec_size+4); |
||
1146 | G.inptr >= G.inbuf; |
||
1147 | --G.inptr) { |
||
1148 | if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ |
||
1149 | !memcmp((char *)G.inptr, signature, 4) ) { |
||
1150 | G.incnt -= (int)(G.inptr - G.inbuf); |
||
1151 | found = TRUE; |
||
1152 | break; |
||
1153 | } |
||
1154 | } |
||
1155 | /* sig may span block boundary: */ |
||
1156 | memcpy((char *)G.hold, (char *)G.inbuf, 3); |
||
1157 | } else |
||
1158 | G.cur_zipfile_bufstart = G.ziplen - tail_len; |
||
1159 | |||
1160 | /*----------------------------------------------------------------------- |
||
1161 | Loop through blocks of zipfile data, starting at the end and going |
||
1162 | toward the beginning. In general, need not check whole zipfile for |
||
1163 | signature, but may want to do so if testing. |
||
1164 | -----------------------------------------------------------------------*/ |
||
1165 | |||
1166 | numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ); |
||
1167 | /* ==amount= ==done== ==rounding== =blksiz= */ |
||
1168 | |||
1169 | for (i = 1; !found && (i <= numblks); ++i) { |
||
1170 | G.cur_zipfile_bufstart -= INBUFSIZ; |
||
1171 | #ifdef USE_STRM_INPUT |
||
1172 | zfseeko(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET); |
||
1173 | #else /* !USE_STRM_INPUT */ |
||
1174 | zlseek(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET); |
||
1175 | #endif /* ?USE_STRM_INPUT */ |
||
1176 | if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ)) |
||
1177 | != INBUFSIZ) |
||
1178 | return 2; /* read error is fatal failure */ |
||
1179 | |||
1180 | for (G.inptr = G.inbuf+INBUFSIZ-1; G.inptr >= G.inbuf; --G.inptr) |
||
1181 | if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ |
||
1182 | !memcmp((char *)G.inptr, signature, 4) ) { |
||
1183 | G.incnt -= (int)(G.inptr - G.inbuf); |
||
1184 | found = TRUE; |
||
1185 | break; |
||
1186 | } |
||
1187 | /* sig may span block boundary: */ |
||
1188 | memcpy((char *)G.hold, (char *)G.inbuf, 3); |
||
1189 | } |
||
1190 | return (found ? 0 : 1); |
||
1191 | } /* end function rec_find() */ |
||
1192 | |||
1193 | |||
1194 | |||
1195 | |||
1196 | #if 0 |
||
1197 | /********************************/ |
||
1198 | /* Function check_ecrec_zip64() */ |
||
1199 | /********************************/ |
||
1200 | |||
1201 | static int check_ecrec_zip64(__G) |
||
1202 | __GDEF |
||
1203 | { |
||
1204 | return G.ecrec.offset_start_central_directory == 0xFFFFFFFFL |
||
1205 | || G.ecrec.size_central_directory == 0xFFFFFFFFL |
||
1206 | || G.ecrec.total_entries_central_dir == 0xFFFF |
||
1207 | || G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF |
||
1208 | || G.ecrec.num_disk_start_cdir == 0xFFFF |
||
1209 | || G.ecrec.number_this_disk == 0xFFFF; |
||
1210 | } /* end function check_ecrec_zip64() */ |
||
1211 | #endif /* never */ |
||
1212 | |||
1213 | |||
1214 | |||
1215 | /***************************/ |
||
1216 | /* Function find_ecrec64() */ |
||
1217 | /***************************/ |
||
1218 | |||
1219 | static int find_ecrec64(__G__ searchlen) /* return PK-class error */ |
||
1220 | __GDEF |
||
1221 | zoff_t searchlen; |
||
1222 | { |
||
1223 | ec_byte_rec64 byterec; /* buf for ecrec64 */ |
||
1224 | ec_byte_loc64 byterecL; /* buf for ecrec64 locator */ |
||
1225 | zoff_t ecloc64_start_offset; /* start offset of ecrec64 locator */ |
||
1226 | zusz_t ecrec64_start_offset; /* start offset of ecrec64 */ |
||
1227 | zuvl_t ecrec64_start_disk; /* start disk of ecrec64 */ |
||
1228 | zuvl_t ecloc64_total_disks; /* total disks */ |
||
1229 | zuvl_t ecrec64_disk_cdstart; /* disk number of central dir start */ |
||
1230 | zucn_t ecrec64_this_entries; /* entries on disk with ecrec64 */ |
||
1231 | zucn_t ecrec64_tot_entries; /* total number of entries */ |
||
1232 | zusz_t ecrec64_cdirsize; /* length of central dir */ |
||
1233 | zusz_t ecrec64_offs_cdstart; /* offset of central dir start */ |
||
1234 | |||
1235 | /* First, find the ecrec64 locator. By definition, this must be before |
||
1236 | ecrec with nothing in between. We back up the size of the ecrec64 |
||
1237 | locator and check. */ |
||
1238 | |||
1239 | ecloc64_start_offset = G.real_ecrec_offset - (ECLOC64_SIZE+4); |
||
1240 | if (ecloc64_start_offset < 0) |
||
1241 | /* Seeking would go past beginning, so probably empty archive */ |
||
1242 | return PK_COOL; |
||
1243 | |||
1244 | #ifdef USE_STRM_INPUT |
||
1245 | zfseeko(G.zipfd, ecloc64_start_offset, SEEK_SET); |
||
1246 | G.cur_zipfile_bufstart = zftello(G.zipfd); |
||
1247 | #else /* !USE_STRM_INPUT */ |
||
1248 | G.cur_zipfile_bufstart = zlseek(G.zipfd, ecloc64_start_offset, SEEK_SET); |
||
1249 | #endif /* ?USE_STRM_INPUT */ |
||
1250 | |||
1251 | if ((G.incnt = read(G.zipfd, (char *)byterecL, ECLOC64_SIZE+4)) |
||
1252 | != (ECLOC64_SIZE+4)) { |
||
1253 | if (uO.qflag || uO.zipinfo_mode) |
||
1254 | Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); |
||
1255 | Info(slide, 0x401, ((char *)slide, |
||
1256 | LoadFarString(Cent64EndSigSearchErr))); |
||
1257 | return PK_ERR; |
||
1258 | } |
||
1259 | |||
1260 | if (memcmp((char *)byterecL, end_centloc64_sig, 4) ) { |
||
1261 | /* not found */ |
||
1262 | return PK_COOL; |
||
1263 | } |
||
1264 | |||
1265 | /* Read the locator. */ |
||
1266 | ecrec64_start_disk = (zuvl_t)makelong(&byterecL[NUM_DISK_START_EOCDR64]); |
||
1267 | ecrec64_start_offset = (zusz_t)makeint64(&byterecL[OFFSET_START_EOCDR64]); |
||
1268 | ecloc64_total_disks = (zuvl_t)makelong(&byterecL[NUM_THIS_DISK_LOC64]); |
||
1269 | |||
1270 | /* Check for consistency */ |
||
1271 | #ifdef TEST |
||
1272 | fprintf(stdout,"\nnumber of disks (ECR) %u, (ECLOC64) %lu\n", |
||
1273 | G.ecrec.number_this_disk, ecloc64_total_disks); fflush(stdout); |
||
1274 | #endif |
||
1275 | if ((G.ecrec.number_this_disk != 0xFFFF) && |
||
1276 | (G.ecrec.number_this_disk != ecloc64_total_disks - 1)) { |
||
1277 | /* Note: For some unknown reason, the developers at PKWARE decided to |
||
1278 | store the "zip64 total disks" value as a counter starting from 1, |
||
1279 | whereas all other "split/span volume" related fields use 0-based |
||
1280 | volume numbers. Sigh... */ |
||
1281 | /* When the total number of disks as found in the traditional ecrec |
||
1282 | is not 0xFFFF, the disk numbers in ecrec and ecloc64 must match. |
||
1283 | When this is not the case, the found ecrec64 locator cannot be valid. |
||
1284 | -> This is not a Zip64 archive. |
||
1285 | */ |
||
1286 | Trace((stderr, |
||
1287 | "\ninvalid ECLOC64, differing disk# (ECR %u, ECL64 %lu)\n", |
||
1288 | G.ecrec.number_this_disk, ecloc64_total_disks - 1)); |
||
1289 | return PK_COOL; |
||
1290 | } |
||
1291 | |||
1292 | /* If found locator, look for ecrec64 where the locator says it is. */ |
||
1293 | |||
1294 | /* For now assume that ecrec64 is on the same disk as ecloc64 and ecrec, |
||
1295 | which is usually the case and is how Zip writes it. To do this right, |
||
1296 | however, we should allow the ecrec64 to be on another disk since |
||
1297 | the AppNote allows it and the ecrec64 can be large, especially if |
||
1298 | Version 2 is used (AppNote uses 8 bytes for the size of this record). */ |
||
1299 | |||
1300 | /* FIX BELOW IF ADD SUPPORT FOR MULTIPLE DISKS */ |
||
1301 | |||
1302 | if (ecrec64_start_offset > (zusz_t)ecloc64_start_offset) { |
||
1303 | /* ecrec64 has to be before ecrec64 locator */ |
||
1304 | if (uO.qflag || uO.zipinfo_mode) |
||
1305 | Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); |
||
1306 | Info(slide, 0x401, ((char *)slide, |
||
1307 | LoadFarString(Cent64EndSigSearchErr))); |
||
1308 | return PK_ERR; |
||
1309 | } |
||
1310 | |||
1311 | #ifdef USE_STRM_INPUT |
||
1312 | zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET); |
||
1313 | G.cur_zipfile_bufstart = zftello(G.zipfd); |
||
1314 | #else /* !USE_STRM_INPUT */ |
||
1315 | G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET); |
||
1316 | #endif /* ?USE_STRM_INPUT */ |
||
1317 | |||
1318 | if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4)) |
||
1319 | != (ECREC64_SIZE+4)) { |
||
1320 | if (uO.qflag || uO.zipinfo_mode) |
||
1321 | Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); |
||
1322 | Info(slide, 0x401, ((char *)slide, |
||
1323 | LoadFarString(Cent64EndSigSearchErr))); |
||
1324 | return PK_ERR; |
||
1325 | } |
||
1326 | |||
1327 | if (memcmp((char *)byterec, end_central64_sig, 4) ) { |
||
1328 | /* Zip64 EOCD Record not found */ |
||
1329 | /* Since we already have seen the Zip64 EOCD Locator, it's |
||
1330 | possible we got here because there are bytes prepended |
||
1331 | to the archive, like the sfx prefix. */ |
||
1332 | |||
1333 | /* Make a guess as to where the Zip64 EOCD Record might be */ |
||
1334 | ecrec64_start_offset = ecloc64_start_offset - ECREC64_SIZE - 4; |
||
1335 | |||
1336 | #ifdef USE_STRM_INPUT |
||
1337 | zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET); |
||
1338 | G.cur_zipfile_bufstart = zftello(G.zipfd); |
||
1339 | #else /* !USE_STRM_INPUT */ |
||
1340 | G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET); |
||
1341 | #endif /* ?USE_STRM_INPUT */ |
||
1342 | |||
1343 | if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4)) |
||
1344 | != (ECREC64_SIZE+4)) { |
||
1345 | if (uO.qflag || uO.zipinfo_mode) |
||
1346 | Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); |
||
1347 | Info(slide, 0x401, ((char *)slide, |
||
1348 | LoadFarString(Cent64EndSigSearchErr))); |
||
1349 | return PK_ERR; |
||
1350 | } |
||
1351 | |||
1352 | if (memcmp((char *)byterec, end_central64_sig, 4) ) { |
||
1353 | /* Zip64 EOCD Record not found */ |
||
1354 | /* Probably something not so easy to handle so exit */ |
||
1355 | if (uO.qflag || uO.zipinfo_mode) |
||
1356 | Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); |
||
1357 | Info(slide, 0x401, ((char *)slide, |
||
1358 | LoadFarString(Cent64EndSigSearchErr))); |
||
1359 | return PK_ERR; |
||
1360 | } |
||
1361 | |||
1362 | if (uO.qflag || uO.zipinfo_mode) |
||
1363 | Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); |
||
1364 | Info(slide, 0x401, ((char *)slide, |
||
1365 | LoadFarString(Cent64EndSigSearchOff))); |
||
1366 | } |
||
1367 | |||
1368 | /* Check consistency of found ecrec64 with ecloc64 (and ecrec): */ |
||
1369 | if ( (zuvl_t)makelong(&byterec[NUMBER_THIS_DSK_REC64]) |
||
1370 | != ecrec64_start_disk ) |
||
1371 | /* found ecrec64 does not match ecloc64 info -> no Zip64 archive */ |
||
1372 | return PK_COOL; |
||
1373 | /* Read all relevant ecrec64 fields and compare them to the corresponding |
||
1374 | ecrec fields unless those are set to "all-ones". |
||
1375 | */ |
||
1376 | ecrec64_disk_cdstart = |
||
1377 | (zuvl_t)makelong(&byterec[NUM_DISK_START_CEN_DIR64]); |
||
1378 | if ( (G.ecrec.num_disk_start_cdir != 0xFFFF) && |
||
1379 | (G.ecrec.num_disk_start_cdir != ecrec64_disk_cdstart) ) |
||
1380 | return PK_COOL; |
||
1381 | ecrec64_this_entries |
||
1382 | = makeint64(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK64]); |
||
1383 | if ( (G.ecrec.num_entries_centrl_dir_ths_disk != 0xFFFF) && |
||
1384 | (G.ecrec.num_entries_centrl_dir_ths_disk != ecrec64_this_entries) ) |
||
1385 | return PK_COOL; |
||
1386 | ecrec64_tot_entries |
||
1387 | = makeint64(&byterec[TOTAL_ENTRIES_CENTRAL_DIR64]); |
||
1388 | if ( (G.ecrec.total_entries_central_dir != 0xFFFF) && |
||
1389 | (G.ecrec.total_entries_central_dir != ecrec64_tot_entries) ) |
||
1390 | return PK_COOL; |
||
1391 | ecrec64_cdirsize |
||
1392 | = makeint64(&byterec[SIZE_CENTRAL_DIRECTORY64]); |
||
1393 | if ( (G.ecrec.size_central_directory != 0xFFFFFFFFL) && |
||
1394 | (G.ecrec.size_central_directory != ecrec64_cdirsize) ) |
||
1395 | return PK_COOL; |
||
1396 | ecrec64_offs_cdstart |
||
1397 | = makeint64(&byterec[OFFSET_START_CENTRAL_DIRECT64]); |
||
1398 | if ( (G.ecrec.offset_start_central_directory != 0xFFFFFFFFL) && |
||
1399 | (G.ecrec.offset_start_central_directory != ecrec64_offs_cdstart) ) |
||
1400 | return PK_COOL; |
||
1401 | |||
1402 | /* Now, we are (almost) sure that we have a Zip64 archive. */ |
||
1403 | G.ecrec.have_ecr64 = 1; |
||
1404 | |||
1405 | /* Update the "end-of-central-dir offset" for later checks. */ |
||
1406 | G.real_ecrec_offset = ecrec64_start_offset; |
||
1407 | |||
1408 | /* Update all ecdir_rec data that are flagged to be invalid |
||
1409 | in Zip64 mode. Set the ecrec64-mandatory flag when such a |
||
1410 | case is found. */ |
||
1411 | if (G.ecrec.number_this_disk == 0xFFFF) { |
||
1412 | G.ecrec.number_this_disk = ecrec64_start_disk; |
||
1413 | if (ecrec64_start_disk != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; |
||
1414 | } |
||
1415 | if (G.ecrec.num_disk_start_cdir == 0xFFFF) { |
||
1416 | G.ecrec.num_disk_start_cdir = ecrec64_disk_cdstart; |
||
1417 | if (ecrec64_disk_cdstart != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; |
||
1418 | } |
||
1419 | if (G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF) { |
||
1420 | G.ecrec.num_entries_centrl_dir_ths_disk = ecrec64_this_entries; |
||
1421 | if (ecrec64_this_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; |
||
1422 | } |
||
1423 | if (G.ecrec.total_entries_central_dir == 0xFFFF) { |
||
1424 | G.ecrec.total_entries_central_dir = ecrec64_tot_entries; |
||
1425 | if (ecrec64_tot_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; |
||
1426 | } |
||
1427 | if (G.ecrec.size_central_directory == 0xFFFFFFFFL) { |
||
1428 | G.ecrec.size_central_directory = ecrec64_cdirsize; |
||
1429 | if (ecrec64_cdirsize != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE; |
||
1430 | } |
||
1431 | if (G.ecrec.offset_start_central_directory == 0xFFFFFFFFL) { |
||
1432 | G.ecrec.offset_start_central_directory = ecrec64_offs_cdstart; |
||
1433 | if (ecrec64_offs_cdstart != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE; |
||
1434 | } |
||
1435 | |||
1436 | return PK_COOL; |
||
1437 | } /* end function find_ecrec64() */ |
||
1438 | |||
1439 | |||
1440 | |||
1441 | /*************************/ |
||
1442 | /* Function find_ecrec() */ |
||
1443 | /*************************/ |
||
1444 | |||
1445 | static int find_ecrec(__G__ searchlen) /* return PK-class error */ |
||
1446 | __GDEF |
||
1447 | zoff_t searchlen; |
||
1448 | { |
||
1449 | int found = FALSE; |
||
1450 | int error_in_archive; |
||
1451 | int result; |
||
1452 | ec_byte_rec byterec; |
||
1453 | |||
1454 | /*--------------------------------------------------------------------------- |
||
1455 | Treat case of short zipfile separately. |
||
1456 | ---------------------------------------------------------------------------*/ |
||
1457 | |||
1458 | if (G.ziplen <= INBUFSIZ) { |
||
1459 | #ifdef USE_STRM_INPUT |
||
1460 | zfseeko(G.zipfd, 0L, SEEK_SET); |
||
1461 | #else /* !USE_STRM_INPUT */ |
||
1462 | zlseek(G.zipfd, 0L, SEEK_SET); |
||
1463 | #endif /* ?USE_STRM_INPUT */ |
||
1464 | if ((G.incnt = read(G.zipfd,(char *)G.inbuf,(unsigned int)G.ziplen)) |
||
1465 | == (int)G.ziplen) |
||
1466 | |||
1467 | /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */ |
||
1468 | for (G.inptr = G.inbuf+(int)G.ziplen-(ECREC_SIZE+4); |
||
1469 | G.inptr >= G.inbuf; |
||
1470 | --G.inptr) { |
||
1471 | if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ |
||
1472 | !memcmp((char *)G.inptr, end_central_sig, 4)) { |
||
1473 | G.incnt -= (int)(G.inptr - G.inbuf); |
||
1474 | found = TRUE; |
||
1475 | break; |
||
1476 | } |
||
1477 | } |
||
1478 | |||
1479 | /*--------------------------------------------------------------------------- |
||
1480 | Zipfile is longer than INBUFSIZ: |
||
1481 | |||
1482 | MB - this next block of code moved to rec_find so that same code can be |
||
1483 | used to look for zip64 ec record. No need to include code above since |
||
1484 | a zip64 ec record will only be looked for if it is a BIG file. |
||
1485 | ---------------------------------------------------------------------------*/ |
||
1486 | |||
1487 | } else { |
||
1488 | found = |
||
1489 | (rec_find(__G__ searchlen, end_central_sig, ECREC_SIZE) == 0 |
||
1490 | ? TRUE : FALSE); |
||
1491 | } /* end if (ziplen > INBUFSIZ) */ |
||
1492 | |||
1493 | /*--------------------------------------------------------------------------- |
||
1494 | Searched through whole region where signature should be without finding |
||
1495 | it. Print informational message and die a horrible death. |
||
1496 | ---------------------------------------------------------------------------*/ |
||
1497 | |||
1498 | if (!found) { |
||
1499 | if (uO.qflag || uO.zipinfo_mode) |
||
1500 | Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); |
||
1501 | Info(slide, 0x401, ((char *)slide, |
||
1502 | LoadFarString(CentDirEndSigNotFound))); |
||
1503 | return PK_ERR; /* failed */ |
||
1504 | } |
||
1505 | |||
1506 | /*--------------------------------------------------------------------------- |
||
1507 | Found the signature, so get the end-central data before returning. Do |
||
1508 | any necessary machine-type conversions (byte ordering, structure padding |
||
1509 | compensation) by reading data into character array and copying to struct. |
||
1510 | ---------------------------------------------------------------------------*/ |
||
1511 | |||
1512 | G.real_ecrec_offset = G.cur_zipfile_bufstart + (G.inptr-G.inbuf); |
||
1513 | #ifdef TEST |
||
1514 | printf("\n found end-of-central-dir signature at offset %s (%sh)\n", |
||
1515 | FmZofft(G.real_ecrec_offset, NULL, NULL), |
||
1516 | FmZofft(G.real_ecrec_offset, FZOFFT_HEX_DOT_WID, "X")); |
||
1517 | printf(" from beginning of file; offset %d (%.4Xh) within block\n", |
||
1518 | G.inptr-G.inbuf, G.inptr-G.inbuf); |
||
1519 | #endif |
||
1520 | |||
1521 | if (readbuf(__G__ (char *)byterec, ECREC_SIZE+4) == 0) |
||
1522 | return PK_EOF; |
||
1523 | |||
1524 | G.ecrec.number_this_disk = |
||
1525 | makeword(&byterec[NUMBER_THIS_DISK]); |
||
1526 | G.ecrec.num_disk_start_cdir = |
||
1527 | makeword(&byterec[NUM_DISK_WITH_START_CEN_DIR]); |
||
1528 | G.ecrec.num_entries_centrl_dir_ths_disk = |
||
1529 | makeword(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK]); |
||
1530 | G.ecrec.total_entries_central_dir = |
||
1531 | makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]); |
||
1532 | G.ecrec.size_central_directory = |
||
1533 | makelong(&byterec[SIZE_CENTRAL_DIRECTORY]); |
||
1534 | G.ecrec.offset_start_central_directory = |
||
1535 | makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]); |
||
1536 | G.ecrec.zipfile_comment_length = |
||
1537 | makeword(&byterec[ZIPFILE_COMMENT_LENGTH]); |
||
1538 | |||
1539 | /* Now, we have to read the archive comment, BEFORE the file pointer |
||
1540 | is moved away backwards to seek for a Zip64 ECLOC64 structure. |
||
1541 | */ |
||
1542 | if ( (error_in_archive = process_zip_cmmnt(__G)) > PK_WARN ) |
||
1543 | return error_in_archive; |
||
1544 | |||
1545 | /* Next: Check for existence of Zip64 end-of-cent-dir locator |
||
1546 | ECLOC64. This structure must reside on the same volume as the |
||
1547 | classic ECREC, at exactly (ECLOC64_SIZE+4) bytes in front |
||
1548 | of the ECREC. |
||
1549 | The ECLOC64 structure directs to the longer ECREC64 structure |
||
1550 | A ECREC64 will ALWAYS exist for a proper Zip64 archive, as |
||
1551 | the "Version Needed To Extract" field is required to be set |
||
1552 | to 4.5 or higher whenever any Zip64 features are used anywhere |
||
1553 | in the archive, so just check for that to see if this is a |
||
1554 | Zip64 archive. |
||
1555 | */ |
||
1556 | result = find_ecrec64(__G__ searchlen+76); |
||
1557 | /* 76 bytes for zip64ec & zip64 locator */ |
||
1558 | if (result != PK_COOL) { |
||
1559 | if (error_in_archive < result) |
||
1560 | error_in_archive = result; |
||
1561 | return error_in_archive; |
||
1562 | } |
||
1563 | |||
1564 | G.expect_ecrec_offset = G.ecrec.offset_start_central_directory + |
||
1565 | G.ecrec.size_central_directory; |
||
1566 | |||
1567 | #ifndef NO_ZIPINFO |
||
1568 | if (uO.zipinfo_mode) { |
||
1569 | /* In ZipInfo mode, additional info about the data found in the |
||
1570 | end-of-central-directory areas is printed out. |
||
1571 | */ |
||
1572 | zi_end_central(__G); |
||
1573 | } |
||
1574 | #endif |
||
1575 | |||
1576 | return error_in_archive; |
||
1577 | |||
1578 | } /* end function find_ecrec() */ |
||
1579 | |||
1580 | |||
1581 | |||
1582 | |||
1583 | |||
1584 | /********************************/ |
||
1585 | /* Function process_zip_cmmnt() */ |
||
1586 | /********************************/ |
||
1587 | |||
1588 | static int process_zip_cmmnt(__G) /* return PK-type error code */ |
||
1589 | __GDEF |
||
1590 | { |
||
1591 | int error = PK_COOL; |
||
1592 | |||
1593 | |||
1594 | /*--------------------------------------------------------------------------- |
||
1595 | Get the zipfile comment (up to 64KB long), if any, and print it out. |
||
1596 | ---------------------------------------------------------------------------*/ |
||
1597 | |||
1598 | #ifdef WINDLL |
||
1599 | /* for comment button: */ |
||
1600 | if ((!G.fValidate) && (G.lpUserFunctions != NULL)) |
||
1601 | G.lpUserFunctions->cchComment = G.ecrec.zipfile_comment_length; |
||
1602 | #endif /* WINDLL */ |
||
1603 | |||
1604 | #ifndef NO_ZIPINFO |
||
1605 | /* ZipInfo, verbose format */ |
||
1606 | if (uO.zipinfo_mode && uO.lflag > 9) { |
||
1607 | /*------------------------------------------------------------------- |
||
1608 | Get the zipfile comment, if any, and print it out. |
||
1609 | (Comment may be up to 64KB long. May the fleas of a thousand |
||
1610 | camels infest the arm-pits of anyone who actually takes advantage |
||
1611 | of this fact.) |
||
1612 | -------------------------------------------------------------------*/ |
||
1613 | |||
1614 | if (!G.ecrec.zipfile_comment_length) |
||
1615 | Info(slide, 0, ((char *)slide, LoadFarString(NoZipfileComment))); |
||
1616 | else { |
||
1617 | Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommentDesc), |
||
1618 | G.ecrec.zipfile_comment_length)); |
||
1619 | Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommBegin))); |
||
1620 | if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) |
||
1621 | error = PK_WARN; |
||
1622 | Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommEnd))); |
||
1623 | if (error) |
||
1624 | Info(slide, 0, ((char *)slide, |
||
1625 | LoadFarString(ZipfileCommTrunc2))); |
||
1626 | } /* endif (comment exists) */ |
||
1627 | |||
1628 | /* ZipInfo, non-verbose mode: print zipfile comment only if requested */ |
||
1629 | } else if (G.ecrec.zipfile_comment_length && |
||
1630 | (uO.zflag > 0) && uO.zipinfo_mode) { |
||
1631 | if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) { |
||
1632 | Info(slide, 0x401, ((char *)slide, |
||
1633 | LoadFarString(ZipfileCommTrunc1))); |
||
1634 | error = PK_WARN; |
||
1635 | } |
||
1636 | } else |
||
1637 | #endif /* !NO_ZIPINFO */ |
||
1638 | if ( G.ecrec.zipfile_comment_length && |
||
1639 | (uO.zflag > 0 |
||
1640 | #ifndef WINDLL |
||
1641 | || (uO.zflag == 0 |
||
1642 | # ifndef NO_ZIPINFO |
||
1643 | && !uO.zipinfo_mode |
||
1644 | # endif |
||
1645 | # ifdef TIMESTAMP |
||
1646 | && !uO.T_flag |
||
1647 | # endif |
||
1648 | && !uO.qflag) |
||
1649 | #endif /* !WINDLL */ |
||
1650 | ) ) |
||
1651 | { |
||
1652 | if (do_string(__G__ G.ecrec.zipfile_comment_length, |
||
1653 | #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) |
||
1654 | # ifndef NO_ZIPINFO |
||
1655 | (oU.zipinfo_mode ? DISPLAY : CHECK_AUTORUN) |
||
1656 | # else |
||
1657 | CHECK_AUTORUN |
||
1658 | # endif |
||
1659 | #else |
||
1660 | DISPLAY |
||
1661 | #endif |
||
1662 | )) |
||
1663 | { |
||
1664 | Info(slide, 0x401, ((char *)slide, |
||
1665 | LoadFarString(ZipfileCommTrunc1))); |
||
1666 | error = PK_WARN; |
||
1667 | } |
||
1668 | } |
||
1669 | #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) |
||
1670 | else if (G.ecrec.zipfile_comment_length) { |
||
1671 | if (do_string(__G__ G.ecrec.zipfile_comment_length, CHECK_AUTORUN_Q)) |
||
1672 | { |
||
1673 | Info(slide, 0x401, ((char *)slide, |
||
1674 | LoadFarString(ZipfileCommTrunc1))); |
||
1675 | error = PK_WARN; |
||
1676 | } |
||
1677 | } |
||
1678 | #endif |
||
1679 | return error; |
||
1680 | |||
1681 | } /* end function process_zip_cmmnt() */ |
||
1682 | |||
1683 | |||
1684 | |||
1685 | |||
1686 | |||
1687 | /************************************/ |
||
1688 | /* Function process_cdir_file_hdr() */ |
||
1689 | /************************************/ |
||
1690 | |||
1691 | int process_cdir_file_hdr(__G) /* return PK-type error code */ |
||
1692 | __GDEF |
||
1693 | { |
||
1694 | int error; |
||
1695 | |||
1696 | |||
1697 | /*--------------------------------------------------------------------------- |
||
1698 | Get central directory info, save host and method numbers, and set flag |
||
1699 | for lowercase conversion of filename, depending on the OS from which the |
||
1700 | file is coming. |
||
1701 | ---------------------------------------------------------------------------*/ |
||
1702 | |||
1703 | if ((error = get_cdir_ent(__G)) != 0) |
||
1704 | return error; |
||
1705 | |||
1706 | G.pInfo->hostver = G.crec.version_made_by[0]; |
||
1707 | G.pInfo->hostnum = MIN(G.crec.version_made_by[1], NUM_HOSTS); |
||
1708 | /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */ |
||
1709 | |||
1710 | G.pInfo->lcflag = 0; |
||
1711 | if (uO.L_flag == 1) /* name conversion for monocase systems */ |
||
1712 | switch (G.pInfo->hostnum) { |
||
1713 | case FS_FAT_: /* PKZIP and zip -k store in uppercase */ |
||
1714 | case CPM_: /* like MS-DOS, right? */ |
||
1715 | case VM_CMS_: /* all caps? */ |
||
1716 | case MVS_: /* all caps? */ |
||
1717 | case TANDEM_: |
||
1718 | case TOPS20_: |
||
1719 | case VMS_: /* our Zip uses lowercase, but ASi's doesn't */ |
||
1720 | /* case Z_SYSTEM_: ? */ |
||
1721 | /* case QDOS_: ? */ |
||
1722 | G.pInfo->lcflag = 1; /* convert filename to lowercase */ |
||
1723 | break; |
||
1724 | |||
1725 | default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */ |
||
1726 | break; /* FS_VFAT_, ATHEOS_, BEOS_ (Z_SYSTEM_), THEOS_: */ |
||
1727 | /* no conversion */ |
||
1728 | } |
||
1729 | else if (uO.L_flag > 1) /* let -LL force lower case for all names */ |
||
1730 | G.pInfo->lcflag = 1; |
||
1731 | |||
1732 | /* do Amigas (AMIGA_) also have volume labels? */ |
||
1733 | if (IS_VOLID(G.crec.external_file_attributes) && |
||
1734 | (G.pInfo->hostnum == FS_FAT_ || G.pInfo->hostnum == FS_HPFS_ || |
||
1735 | G.pInfo->hostnum == FS_NTFS_ || G.pInfo->hostnum == ATARI_)) |
||
1736 | { |
||
1737 | G.pInfo->vollabel = TRUE; |
||
1738 | G.pInfo->lcflag = 0; /* preserve case of volume labels */ |
||
1739 | } else |
||
1740 | G.pInfo->vollabel = FALSE; |
||
1741 | |||
1742 | /* this flag is needed to detect archives made by "PKZIP for Unix" when |
||
1743 | deciding which kind of codepage conversion has to be applied to |
||
1744 | strings (see do_string() function in fileio.c) */ |
||
1745 | G.pInfo->HasUxAtt = (G.crec.external_file_attributes & 0xffff0000L) != 0L; |
||
1746 | |||
1747 | #ifdef UNICODE_SUPPORT |
||
1748 | /* remember the state of GPB11 (General Purpuse Bit 11) which indicates |
||
1749 | that the standard path and comment are UTF-8. */ |
||
1750 | G.pInfo->GPFIsUTF8 |
||
1751 | = (G.crec.general_purpose_bit_flag & (1 << 11)) == (1 << 11); |
||
1752 | #endif |
||
1753 | |||
1754 | return PK_COOL; |
||
1755 | |||
1756 | } /* end function process_cdir_file_hdr() */ |
||
1757 | |||
1758 | |||
1759 | |||
1760 | |||
1761 | |||
1762 | /***************************/ |
||
1763 | /* Function get_cdir_ent() */ |
||
1764 | /***************************/ |
||
1765 | |||
1766 | static int get_cdir_ent(__G) /* return PK-type error code */ |
||
1767 | __GDEF |
||
1768 | { |
||
1769 | cdir_byte_hdr byterec; |
||
1770 | |||
1771 | |||
1772 | /*--------------------------------------------------------------------------- |
||
1773 | Read the next central directory entry and do any necessary machine-type |
||
1774 | conversions (byte ordering, structure padding compensation--do so by |
||
1775 | copying the data from the array into which it was read (byterec) to the |
||
1776 | usable struct (crec)). |
||
1777 | ---------------------------------------------------------------------------*/ |
||
1778 | |||
1779 | if (readbuf(__G__ (char *)byterec, CREC_SIZE) == 0) |
||
1780 | return PK_EOF; |
||
1781 | |||
1782 | G.crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0]; |
||
1783 | G.crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1]; |
||
1784 | G.crec.version_needed_to_extract[0] = |
||
1785 | byterec[C_VERSION_NEEDED_TO_EXTRACT_0]; |
||
1786 | G.crec.version_needed_to_extract[1] = |
||
1787 | byterec[C_VERSION_NEEDED_TO_EXTRACT_1]; |
||
1788 | |||
1789 | G.crec.general_purpose_bit_flag = |
||
1790 | makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]); |
||
1791 | G.crec.compression_method = |
||
1792 | makeword(&byterec[C_COMPRESSION_METHOD]); |
||
1793 | G.crec.last_mod_dos_datetime = |
||
1794 | makelong(&byterec[C_LAST_MOD_DOS_DATETIME]); |
||
1795 | G.crec.crc32 = |
||
1796 | makelong(&byterec[C_CRC32]); |
||
1797 | G.crec.csize = |
||
1798 | makelong(&byterec[C_COMPRESSED_SIZE]); |
||
1799 | G.crec.ucsize = |
||
1800 | makelong(&byterec[C_UNCOMPRESSED_SIZE]); |
||
1801 | G.crec.filename_length = |
||
1802 | makeword(&byterec[C_FILENAME_LENGTH]); |
||
1803 | G.crec.extra_field_length = |
||
1804 | makeword(&byterec[C_EXTRA_FIELD_LENGTH]); |
||
1805 | G.crec.file_comment_length = |
||
1806 | makeword(&byterec[C_FILE_COMMENT_LENGTH]); |
||
1807 | G.crec.disk_number_start = |
||
1808 | makeword(&byterec[C_DISK_NUMBER_START]); |
||
1809 | G.crec.internal_file_attributes = |
||
1810 | makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]); |
||
1811 | G.crec.external_file_attributes = |
||
1812 | makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */ |
||
1813 | G.crec.relative_offset_local_header = |
||
1814 | makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]); |
||
1815 | |||
1816 | return PK_COOL; |
||
1817 | |||
1818 | } /* end function get_cdir_ent() */ |
||
1819 | |||
1820 | |||
1821 | |||
1822 | |||
1823 | |||
1824 | /*************************************/ |
||
1825 | /* Function process_local_file_hdr() */ |
||
1826 | /*************************************/ |
||
1827 | |||
1828 | int process_local_file_hdr(__G) /* return PK-type error code */ |
||
1829 | __GDEF |
||
1830 | { |
||
1831 | local_byte_hdr byterec; |
||
1832 | |||
1833 | |||
1834 | /*--------------------------------------------------------------------------- |
||
1835 | Read the next local file header and do any necessary machine-type con- |
||
1836 | versions (byte ordering, structure padding compensation--do so by copy- |
||
1837 | ing the data from the array into which it was read (byterec) to the |
||
1838 | usable struct (lrec)). |
||
1839 | ---------------------------------------------------------------------------*/ |
||
1840 | |||
1841 | if (readbuf(__G__ (char *)byterec, LREC_SIZE) == 0) |
||
1842 | return PK_EOF; |
||
1843 | |||
1844 | G.lrec.version_needed_to_extract[0] = |
||
1845 | byterec[L_VERSION_NEEDED_TO_EXTRACT_0]; |
||
1846 | G.lrec.version_needed_to_extract[1] = |
||
1847 | byterec[L_VERSION_NEEDED_TO_EXTRACT_1]; |
||
1848 | |||
1849 | G.lrec.general_purpose_bit_flag = |
||
1850 | makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]); |
||
1851 | G.lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]); |
||
1852 | G.lrec.last_mod_dos_datetime = makelong(&byterec[L_LAST_MOD_DOS_DATETIME]); |
||
1853 | G.lrec.crc32 = makelong(&byterec[L_CRC32]); |
||
1854 | G.lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]); |
||
1855 | G.lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]); |
||
1856 | G.lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]); |
||
1857 | G.lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]); |
||
1858 | |||
1859 | if ((G.lrec.general_purpose_bit_flag & 8) != 0) { |
||
1860 | /* can't trust local header, use central directory: */ |
||
1861 | G.lrec.crc32 = G.pInfo->crc; |
||
1862 | G.lrec.csize = G.pInfo->compr_size; |
||
1863 | G.lrec.ucsize = G.pInfo->uncompr_size; |
||
1864 | } |
||
1865 | |||
1866 | G.csize = G.lrec.csize; |
||
1867 | |||
1868 | return PK_COOL; |
||
1869 | |||
1870 | } /* end function process_local_file_hdr() */ |
||
1871 | |||
1872 | |||
1873 | /*******************************/ |
||
1874 | /* Function getZip64Data() */ |
||
1875 | /*******************************/ |
||
1876 | |||
1877 | int getZip64Data(__G__ ef_buf, ef_len) |
||
1878 | __GDEF |
||
1879 | ZCONST uch *ef_buf; /* buffer containing extra field */ |
||
1880 | unsigned ef_len; /* total length of extra field */ |
||
1881 | { |
||
1882 | unsigned eb_id; |
||
1883 | unsigned eb_len; |
||
1884 | |||
1885 | /*--------------------------------------------------------------------------- |
||
1886 | This function scans the extra field for zip64 information, ie 8-byte |
||
1887 | versions of compressed file size, uncompressed file size, relative offset |
||
1888 | and a 4-byte version of disk start number. |
||
1889 | Sets both local header and central header fields. Not terribly clever, |
||
1890 | but it means that this procedure is only called in one place. |
||
1891 | ---------------------------------------------------------------------------*/ |
||
1892 | |||
1893 | if (ef_len == 0 || ef_buf == NULL) |
||
1894 | return PK_COOL; |
||
1895 | |||
1896 | Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n", |
||
1897 | ef_len)); |
||
1898 | |||
1899 | while (ef_len >= EB_HEADSIZE) { |
||
1900 | eb_id = makeword(EB_ID + ef_buf); |
||
1901 | eb_len = makeword(EB_LEN + ef_buf); |
||
1902 | |||
1903 | if (eb_len > (ef_len - EB_HEADSIZE)) { |
||
1904 | /* discovered some extra field inconsistency! */ |
||
1905 | Trace((stderr, |
||
1906 | "getZip64Data: block length %u > rest ef_size %u\n", eb_len, |
||
1907 | ef_len - EB_HEADSIZE)); |
||
1908 | break; |
||
1909 | } |
||
1910 | if (eb_id == EF_PKSZ64) { |
||
1911 | |||
1912 | int offset = EB_HEADSIZE; |
||
1913 | |||
1914 | if (G.crec.ucsize == 0xffffffff || G.lrec.ucsize == 0xffffffff){ |
||
1915 | G.lrec.ucsize = G.crec.ucsize = makeint64(offset + ef_buf); |
||
1916 | offset += sizeof(G.crec.ucsize); |
||
1917 | } |
||
1918 | if (G.crec.csize == 0xffffffff || G.lrec.csize == 0xffffffff){ |
||
1919 | G.csize = G.lrec.csize = G.crec.csize = makeint64(offset + ef_buf); |
||
1920 | offset += sizeof(G.crec.csize); |
||
1921 | } |
||
1922 | if (G.crec.relative_offset_local_header == 0xffffffff){ |
||
1923 | G.crec.relative_offset_local_header = makeint64(offset + ef_buf); |
||
1924 | offset += sizeof(G.crec.relative_offset_local_header); |
||
1925 | } |
||
1926 | if (G.crec.disk_number_start == 0xffff){ |
||
1927 | G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf); |
||
1928 | offset += sizeof(G.crec.disk_number_start); |
||
1929 | } |
||
1930 | } |
||
1931 | |||
1932 | /* Skip this extra field block */ |
||
1933 | ef_buf += (eb_len + EB_HEADSIZE); |
||
1934 | ef_len -= (eb_len + EB_HEADSIZE); |
||
1935 | } |
||
1936 | |||
1937 | return PK_COOL; |
||
1938 | } /* end function getZip64Data() */ |
||
1939 | |||
1940 | |||
1941 | #ifdef UNICODE_SUPPORT |
||
1942 | |||
1943 | /*******************************/ |
||
1944 | /* Function getUnicodeData() */ |
||
1945 | /*******************************/ |
||
1946 | |||
1947 | int getUnicodeData(__G__ ef_buf, ef_len) |
||
1948 | __GDEF |
||
1949 | ZCONST uch *ef_buf; /* buffer containing extra field */ |
||
1950 | unsigned ef_len; /* total length of extra field */ |
||
1951 | { |
||
1952 | unsigned eb_id; |
||
1953 | unsigned eb_len; |
||
1954 | |||
1955 | /*--------------------------------------------------------------------------- |
||
1956 | This function scans the extra field for Unicode information, ie UTF-8 |
||
1957 | path extra fields. |
||
1958 | |||
1959 | On return, G.unipath_filename = |
||
1960 | NULL, if no Unicode path extra field or error |
||
1961 | "", if the standard path is UTF-8 (free when done) |
||
1962 | null-terminated UTF-8 path (free when done) |
||
1963 | Return PK_COOL if no error. |
||
1964 | ---------------------------------------------------------------------------*/ |
||
1965 | |||
1966 | G.unipath_filename = NULL; |
||
1967 | |||
1968 | if (ef_len == 0 || ef_buf == NULL) |
||
1969 | return PK_COOL; |
||
1970 | |||
1971 | Trace((stderr,"\ngetUnicodeData: scanning extra field of length %u\n", |
||
1972 | ef_len)); |
||
1973 | |||
1974 | while (ef_len >= EB_HEADSIZE) { |
||
1975 | eb_id = makeword(EB_ID + ef_buf); |
||
1976 | eb_len = makeword(EB_LEN + ef_buf); |
||
1977 | |||
1978 | if (eb_len > (ef_len - EB_HEADSIZE)) { |
||
1979 | /* discovered some extra field inconsistency! */ |
||
1980 | Trace((stderr, |
||
1981 | "getUnicodeData: block length %u > rest ef_size %u\n", eb_len, |
||
1982 | ef_len - EB_HEADSIZE)); |
||
1983 | break; |
||
1984 | } |
||
1985 | if (eb_id == EF_UNIPATH) { |
||
1986 | |||
1987 | int offset = EB_HEADSIZE; |
||
1988 | ush ULen = eb_len - 5; |
||
1989 | ulg chksum = CRCVAL_INITIAL; |
||
1990 | |||
1991 | /* version */ |
||
1992 | G.unipath_version = (uch) *(offset + ef_buf); |
||
1993 | offset += 1; |
||
1994 | if (G.unipath_version > 1) { |
||
1995 | /* can do only version 1 */ |
||
1996 | Info(slide, 0x401, ((char *)slide, |
||
1997 | LoadFarString(UnicodeVersionError))); |
||
1998 | return PK_ERR; |
||
1999 | } |
||
2000 | |||
2001 | /* filename CRC */ |
||
2002 | G.unipath_checksum = makelong(offset + ef_buf); |
||
2003 | offset += 4; |
||
2004 | |||
2005 | /* |
||
2006 | * Compute 32-bit crc |
||
2007 | */ |
||
2008 | |||
2009 | chksum = crc32(chksum, (uch *)(G.filename_full), |
||
2010 | strlen(G.filename_full)); |
||
2011 | |||
2012 | /* If the checksums's don't match then likely filename has been |
||
2013 | * modified and the Unicode Path is no longer valid. |
||
2014 | */ |
||
2015 | if (chksum != G.unipath_checksum) { |
||
2016 | Info(slide, 0x401, ((char *)slide, |
||
2017 | LoadFarString(UnicodeMismatchError))); |
||
2018 | if (G.unicode_mismatch == 1) { |
||
2019 | /* warn and continue */ |
||
2020 | } else if (G.unicode_mismatch == 2) { |
||
2021 | /* ignore and continue */ |
||
2022 | } else if (G.unicode_mismatch == 0) { |
||
2023 | } |
||
2024 | return PK_ERR; |
||
2025 | } |
||
2026 | |||
2027 | /* UTF-8 Path */ |
||
2028 | if ((G.unipath_filename = malloc(ULen + 1)) == NULL) { |
||
2029 | return PK_ERR; |
||
2030 | } |
||
2031 | if (ULen == 0) { |
||
2032 | /* standard path is UTF-8 so use that */ |
||
2033 | G.unipath_filename[0] = '\0'; |
||
2034 | } else { |
||
2035 | /* UTF-8 path */ |
||
2036 | strncpy(G.unipath_filename, |
||
2037 | (ZCONST char *)(offset + ef_buf), ULen); |
||
2038 | G.unipath_filename[ULen] = '\0'; |
||
2039 | } |
||
2040 | } |
||
2041 | |||
2042 | /* Skip this extra field block */ |
||
2043 | ef_buf += (eb_len + EB_HEADSIZE); |
||
2044 | ef_len -= (eb_len + EB_HEADSIZE); |
||
2045 | } |
||
2046 | |||
2047 | return PK_COOL; |
||
2048 | } /* end function getUnicodeData() */ |
||
2049 | |||
2050 | |||
2051 | |||
2052 | |||
2053 | #ifdef UNICODE_WCHAR |
||
2054 | /*--------------------------------------------- |
||
2055 | * Unicode conversion functions |
||
2056 | * |
||
2057 | * Based on functions provided by Paul Kienitz |
||
2058 | * |
||
2059 | *--------------------------------------------- |
||
2060 | */ |
||
2061 | |||
2062 | /* |
||
2063 | NOTES APPLICABLE TO ALL STRING FUNCTIONS: |
||
2064 | |||
2065 | All of the x_to_y functions take parameters for an output buffer and |
||
2066 | its available length, and return an int. The value returned is the |
||
2067 | length of the string that the input produces, which may be larger than |
||
2068 | the provided buffer length. If the returned value is less than the |
||
2069 | buffer length, then the contents of the buffer will be null-terminated; |
||
2070 | otherwise, it will not be terminated and may be invalid, possibly |
||
2071 | stopping in the middle of a multibyte sequence. |
||
2072 | |||
2073 | In all cases you may pass NULL as the buffer and/or 0 as the length, if |
||
2074 | you just want to learn how much space the string is going to require. |
||
2075 | |||
2076 | The functions will return -1 if the input is invalid UTF-8 or cannot be |
||
2077 | encoded as UTF-8. |
||
2078 | */ |
||
2079 | |||
2080 | static int utf8_char_bytes OF((ZCONST char *utf8)); |
||
2081 | static ulg ucs4_char_from_utf8 OF((ZCONST char **utf8)); |
||
2082 | static int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *ucs4buf, |
||
2083 | int buflen)); |
||
2084 | |||
2085 | /* utility functions for managing UTF-8 and UCS-4 strings */ |
||
2086 | |||
2087 | |||
2088 | /* utf8_char_bytes |
||
2089 | * |
||
2090 | * Returns the number of bytes used by the first character in a UTF-8 |
||
2091 | * string, or -1 if the UTF-8 is invalid or null. |
||
2092 | */ |
||
2093 | static int utf8_char_bytes(utf8) |
||
2094 | ZCONST char *utf8; |
||
2095 | { |
||
2096 | int t, r; |
||
2097 | unsigned lead; |
||
2098 | |||
2099 | if (!utf8) |
||
2100 | return -1; /* no input */ |
||
2101 | lead = (unsigned char) *utf8; |
||
2102 | if (lead < 0x80) |
||
2103 | r = 1; /* an ascii-7 character */ |
||
2104 | else if (lead < 0xC0) |
||
2105 | return -1; /* error: trailing byte without lead byte */ |
||
2106 | else if (lead < 0xE0) |
||
2107 | r = 2; /* an 11 bit character */ |
||
2108 | else if (lead < 0xF0) |
||
2109 | r = 3; /* a 16 bit character */ |
||
2110 | else if (lead < 0xF8) |
||
2111 | r = 4; /* a 21 bit character (the most currently used) */ |
||
2112 | else if (lead < 0xFC) |
||
2113 | r = 5; /* a 26 bit character (shouldn't happen) */ |
||
2114 | else if (lead < 0xFE) |
||
2115 | r = 6; /* a 31 bit character (shouldn't happen) */ |
||
2116 | else |
||
2117 | return -1; /* error: invalid lead byte */ |
||
2118 | for (t = 1; t < r; t++) |
||
2119 | if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0) |
||
2120 | return -1; /* error: not enough valid trailing bytes */ |
||
2121 | return r; |
||
2122 | } |
||
2123 | |||
2124 | |||
2125 | /* ucs4_char_from_utf8 |
||
2126 | * |
||
2127 | * Given a reference to a pointer into a UTF-8 string, returns the next |
||
2128 | * UCS-4 character and advances the pointer to the next character sequence. |
||
2129 | * Returns ~0 (= -1 in twos-complement notation) and does not advance the |
||
2130 | * pointer when input is ill-formed. |
||
2131 | */ |
||
2132 | static ulg ucs4_char_from_utf8(utf8) |
||
2133 | ZCONST char **utf8; |
||
2134 | { |
||
2135 | ulg ret; |
||
2136 | int t, bytes; |
||
2137 | |||
2138 | if (!utf8) |
||
2139 | return ~0L; /* no input */ |
||
2140 | bytes = utf8_char_bytes(*utf8); |
||
2141 | if (bytes <= 0) |
||
2142 | return ~0L; /* invalid input */ |
||
2143 | if (bytes == 1) |
||
2144 | ret = **utf8; /* ascii-7 */ |
||
2145 | else |
||
2146 | ret = **utf8 & (0x7F >> bytes); /* lead byte of a multibyte sequence */ |
||
2147 | (*utf8)++; |
||
2148 | for (t = 1; t < bytes; t++) /* consume trailing bytes */ |
||
2149 | ret = (ret << 6) | (*((*utf8)++) & 0x3F); |
||
2150 | return (zwchar) ret; |
||
2151 | } |
||
2152 | |||
2153 | |||
2154 | #if 0 /* currently unused */ |
||
2155 | /* utf8_from_ucs4_char - Convert UCS char to UTF-8 |
||
2156 | * |
||
2157 | * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6, |
||
2158 | * or -1 if ch is too large to represent. utf8buf must have room for 6 bytes. |
||
2159 | */ |
||
2160 | static int utf8_from_ucs4_char(utf8buf, ch) |
||
2161 | char *utf8buf; |
||
2162 | ulg ch; |
||
2163 | { |
||
2164 | int trailing = 0; |
||
2165 | int leadmask = 0x80; |
||
2166 | int leadbits = 0x3F; |
||
2167 | int tch = ch; |
||
2168 | int ret; |
||
2169 | |||
2170 | if (ch > 0x7FFFFFFFL) |
||
2171 | return -1; /* UTF-8 can represent 31 bits */ |
||
2172 | if (ch < 0x7F) |
||
2173 | { |
||
2174 | *utf8buf++ = (char) ch; /* ascii-7 */ |
||
2175 | return 1; |
||
2176 | } |
||
2177 | do { |
||
2178 | trailing++; |
||
2179 | leadmask = (leadmask >> 1) | 0x80; |
||
2180 | leadbits >>= 1; |
||
2181 | tch >>= 6; |
||
2182 | } while (tch & ~leadbits); |
||
2183 | ret = trailing + 1; |
||
2184 | /* produce lead byte */ |
||
2185 | *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing))); |
||
2186 | while (--trailing >= 0) |
||
2187 | /* produce trailing bytes */ |
||
2188 | *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F)); |
||
2189 | return ret; |
||
2190 | } |
||
2191 | #endif /* unused */ |
||
2192 | |||
2193 | |||
2194 | /*===================================================================*/ |
||
2195 | |||
2196 | /* utf8_to_ucs4_string - convert UTF-8 string to UCS string |
||
2197 | * |
||
2198 | * Return UCS count. Now returns int so can return -1. |
||
2199 | */ |
||
2200 | static int utf8_to_ucs4_string(utf8, ucs4buf, buflen) |
||
2201 | ZCONST char *utf8; |
||
2202 | ulg *ucs4buf; |
||
2203 | int buflen; |
||
2204 | { |
||
2205 | int count = 0; |
||
2206 | |||
2207 | for (;;) |
||
2208 | { |
||
2209 | ulg ch = ucs4_char_from_utf8(&utf8); |
||
2210 | if (ch == ~0L) |
||
2211 | return -1; |
||
2212 | else |
||
2213 | { |
||
2214 | if (ucs4buf && count < buflen) |
||
2215 | ucs4buf[count] = ch; |
||
2216 | if (ch == 0) |
||
2217 | return count; |
||
2218 | count++; |
||
2219 | } |
||
2220 | } |
||
2221 | } |
||
2222 | |||
2223 | |||
2224 | #if 0 /* currently unused */ |
||
2225 | /* ucs4_string_to_utf8 |
||
2226 | * |
||
2227 | * |
||
2228 | */ |
||
2229 | static int ucs4_string_to_utf8(ucs4, utf8buf, buflen) |
||
2230 | ZCONST ulg *ucs4; |
||
2231 | char *utf8buf; |
||
2232 | int buflen; |
||
2233 | { |
||
2234 | char mb[6]; |
||
2235 | int count = 0; |
||
2236 | |||
2237 | if (!ucs4) |
||
2238 | return -1; |
||
2239 | for (;;) |
||
2240 | { |
||
2241 | int mbl = utf8_from_ucs4_char(mb, *ucs4++); |
||
2242 | int c; |
||
2243 | if (mbl <= 0) |
||
2244 | return -1; |
||
2245 | /* We could optimize this a bit by passing utf8buf + count */ |
||
2246 | /* directly to utf8_from_ucs4_char when buflen >= count + 6... */ |
||
2247 | c = buflen - count; |
||
2248 | if (mbl < c) |
||
2249 | c = mbl; |
||
2250 | if (utf8buf && count < buflen) |
||
2251 | strncpy(utf8buf + count, mb, c); |
||
2252 | if (mbl == 1 && !mb[0]) |
||
2253 | return count; /* terminating nul */ |
||
2254 | count += mbl; |
||
2255 | } |
||
2256 | } |
||
2257 | |||
2258 | |||
2259 | /* utf8_chars |
||
2260 | * |
||
2261 | * Wrapper: counts the actual unicode characters in a UTF-8 string. |
||
2262 | */ |
||
2263 | static int utf8_chars(utf8) |
||
2264 | ZCONST char *utf8; |
||
2265 | { |
||
2266 | return utf8_to_ucs4_string(utf8, NULL, 0); |
||
2267 | } |
||
2268 | #endif /* unused */ |
||
2269 | |||
2270 | /* --------------------------------------------------- */ |
||
2271 | /* Unicode Support |
||
2272 | * |
||
2273 | * These functions common for all Unicode ports. |
||
2274 | * |
||
2275 | * These functions should allocate and return strings that can be |
||
2276 | * freed with free(). |
||
2277 | * |
||
2278 | * 8/27/05 EG |
||
2279 | * |
||
2280 | * Use zwchar for wide char which is unsigned long |
||
2281 | * in zip.h and 32 bits. This avoids problems with |
||
2282 | * different sizes of wchar_t. |
||
2283 | */ |
||
2284 | |||
2285 | #if 0 /* currently unused */ |
||
2286 | /* is_ascii_string |
||
2287 | * Checks if a string is all ascii |
||
2288 | */ |
||
2289 | int is_ascii_string(mbstring) |
||
2290 | ZCONST char *mbstring; |
||
2291 | { |
||
2292 | char *p; |
||
2293 | uch c; |
||
2294 | |||
2295 | for (p = mbstring; c = (uch)*p; p++) { |
||
2296 | if (c > 0x7F) { |
||
2297 | return 0; |
||
2298 | } |
||
2299 | } |
||
2300 | return 1; |
||
2301 | } |
||
2302 | |||
2303 | /* local to UTF-8 */ |
||
2304 | char *local_to_utf8_string(local_string) |
||
2305 | ZCONST char *local_string; |
||
2306 | { |
||
2307 | return wide_to_utf8_string(local_to_wide_string(local_string)); |
||
2308 | } |
||
2309 | # endif /* unused */ |
||
2310 | |||
2311 | /* wide_to_escape_string |
||
2312 | provides a string that represents a wide char not in local char set |
||
2313 | |||
2314 | An initial try at an algorithm. Suggestions welcome. |
||
2315 | |||
2316 | According to the standard, Unicode character points are restricted to |
||
2317 | the number range from 0 to 0x10FFFF, respective 21 bits. |
||
2318 | For a hexadecimal notation, 2 octets are sufficient for the mostly |
||
2319 | used characters from the "Basic Multilingual Plane", all other |
||
2320 | Unicode characters can be represented by 3 octets (= 6 hex digits). |
||
2321 | The Unicode standard suggests to write Unicode character points |
||
2322 | as 4 resp. 6 hex digits, preprended by "U+". |
||
2323 | (e.g.: U+10FFFF for the highest character point, or U+0030 for the ASCII |
||
2324 | digit "0") |
||
2325 | |||
2326 | However, for the purpose of escaping non-ASCII chars in an ASCII character |
||
2327 | stream, the "U" is not a very good escape initializer. Therefore, we |
||
2328 | use the following convention within our Info-ZIP code: |
||
2329 | |||
2330 | If not an ASCII char probably need 2 bytes at least. So if |
||
2331 | a 2-byte wide encode it as 4 hex digits with a leading #U. If |
||
2332 | needs 3 bytes then prefix the string with #L. So |
||
2333 | #U1234 |
||
2334 | is a 2-byte wide character with bytes 0x12 and 0x34 while |
||
2335 | #L123456 |
||
2336 | is a 3-byte wide character with bytes 0x12, 0x34, 0x56. |
||
2337 | On Windows, wide that need two wide characters need to be converted |
||
2338 | to a single number. |
||
2339 | */ |
||
2340 | |||
2341 | /* set this to the max bytes an escape can be */ |
||
2342 | #define MAX_ESCAPE_BYTES 8 |
||
2343 | |||
2344 | char *wide_to_escape_string(wide_char) |
||
2345 | zwchar wide_char; |
||
2346 | { |
||
2347 | int i; |
||
2348 | zwchar w = wide_char; |
||
2349 | uch b[sizeof(zwchar)]; |
||
2350 | char d[3]; |
||
2351 | char e[11]; |
||
2352 | int len; |
||
2353 | char *r; |
||
2354 | |||
2355 | /* fill byte array with zeros */ |
||
2356 | memzero(b, sizeof(zwchar)); |
||
2357 | /* get bytes in right to left order */ |
||
2358 | for (len = 0; w; len++) { |
||
2359 | b[len] = (char)(w % 0x100); |
||
2360 | w /= 0x100; |
||
2361 | } |
||
2362 | strcpy(e, "#"); |
||
2363 | /* either 2 bytes or 3 bytes */ |
||
2364 | if (len <= 2) { |
||
2365 | len = 2; |
||
2366 | strcat(e, "U"); |
||
2367 | } else { |
||
2368 | strcat(e, "L"); |
||
2369 | } |
||
2370 | for (i = len - 1; i >= 0; i--) { |
||
2371 | sprintf(d, "%02x", b[i]); |
||
2372 | strcat(e, d); |
||
2373 | } |
||
2374 | if ((r = malloc(strlen(e) + 1)) == NULL) { |
||
2375 | return NULL; |
||
2376 | } |
||
2377 | strcpy(r, e); |
||
2378 | return r; |
||
2379 | } |
||
2380 | |||
2381 | #if 0 /* currently unused */ |
||
2382 | /* returns the wide character represented by the escape string */ |
||
2383 | zwchar escape_string_to_wide(escape_string) |
||
2384 | ZCONST char *escape_string; |
||
2385 | { |
||
2386 | int i; |
||
2387 | zwchar w; |
||
2388 | char c; |
||
2389 | int len; |
||
2390 | ZCONST char *e = escape_string; |
||
2391 | |||
2392 | if (e == NULL) { |
||
2393 | return 0; |
||
2394 | } |
||
2395 | if (e[0] != '#') { |
||
2396 | /* no leading # */ |
||
2397 | return 0; |
||
2398 | } |
||
2399 | len = strlen(e); |
||
2400 | /* either #U1234 or #L123456 format */ |
||
2401 | if (len != 6 && len != 8) { |
||
2402 | return 0; |
||
2403 | } |
||
2404 | w = 0; |
||
2405 | if (e[1] == 'L') { |
||
2406 | if (len != 8) { |
||
2407 | return 0; |
||
2408 | } |
||
2409 | /* 3 bytes */ |
||
2410 | for (i = 2; i < 8; i++) { |
||
2411 | c = e[i]; |
||
2412 | if (c < '0' || c > '9') { |
||
2413 | return 0; |
||
2414 | } |
||
2415 | w = w * 0x10 + (zwchar)(c - '0'); |
||
2416 | } |
||
2417 | } else if (e[1] == 'U') { |
||
2418 | /* 2 bytes */ |
||
2419 | for (i = 2; i < 6; i++) { |
||
2420 | c = e[i]; |
||
2421 | if (c < '0' || c > '9') { |
||
2422 | return 0; |
||
2423 | } |
||
2424 | w = w * 0x10 + (zwchar)(c - '0'); |
||
2425 | } |
||
2426 | } |
||
2427 | return w; |
||
2428 | } |
||
2429 | #endif /* unused */ |
||
2430 | |||
2431 | #ifndef WIN32 /* WIN32 supplies a special variant of this function */ |
||
2432 | /* convert wide character string to multi-byte character string */ |
||
2433 | char *wide_to_local_string(wide_string, escape_all) |
||
2434 | ZCONST zwchar *wide_string; |
||
2435 | int escape_all; |
||
2436 | { |
||
2437 | int i; |
||
2438 | wchar_t wc; |
||
2439 | int b; |
||
2440 | int state_dependent; |
||
2441 | int wsize = 0; |
||
2442 | int max_bytes = MB_CUR_MAX; |
||
2443 | char buf[9]; |
||
2444 | char *buffer = NULL; |
||
2445 | char *local_string = NULL; |
||
2446 | |||
2447 | for (wsize = 0; wide_string[wsize]; wsize++) ; |
||
2448 | |||
2449 | if (max_bytes < MAX_ESCAPE_BYTES) |
||
2450 | max_bytes = MAX_ESCAPE_BYTES; |
||
2451 | |||
2452 | if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) { |
||
2453 | return NULL; |
||
2454 | } |
||
2455 | |||
2456 | /* convert it */ |
||
2457 | buffer[0] = '\0'; |
||
2458 | /* set initial state if state-dependent encoding */ |
||
2459 | wc = (wchar_t)'a'; |
||
2460 | b = wctomb(NULL, wc); |
||
2461 | if (b == 0) |
||
2462 | state_dependent = 0; |
||
2463 | else |
||
2464 | state_dependent = 1; |
||
2465 | for (i = 0; i < wsize; i++) { |
||
2466 | if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) { |
||
2467 | /* wchar_t probably 2 bytes */ |
||
2468 | /* could do surrogates if state_dependent and wctomb can do */ |
||
2469 | wc = zwchar_to_wchar_t_default_char; |
||
2470 | } else { |
||
2471 | wc = (wchar_t)wide_string[i]; |
||
2472 | } |
||
2473 | b = wctomb(buf, wc); |
||
2474 | if (escape_all) { |
||
2475 | if (b == 1 && (uch)buf[0] <= 0x7f) { |
||
2476 | /* ASCII */ |
||
2477 | strncat(buffer, buf, b); |
||
2478 | } else { |
||
2479 | /* use escape for wide character */ |
||
2480 | char *escape_string = wide_to_escape_string(wide_string[i]); |
||
2481 | strcat(buffer, escape_string); |
||
2482 | free(escape_string); |
||
2483 | } |
||
2484 | } else if (b > 0) { |
||
2485 | /* multi-byte char */ |
||
2486 | strncat(buffer, buf, b); |
||
2487 | } else { |
||
2488 | /* no MB for this wide */ |
||
2489 | /* use escape for wide character */ |
||
2490 | char *escape_string = wide_to_escape_string(wide_string[i]); |
||
2491 | strcat(buffer, escape_string); |
||
2492 | free(escape_string); |
||
2493 | } |
||
2494 | } |
||
2495 | if ((local_string = (char *)malloc(strlen(buffer) + 1)) != NULL) { |
||
2496 | strcpy(local_string, buffer); |
||
2497 | } |
||
2498 | free(buffer); |
||
2499 | |||
2500 | return local_string; |
||
2501 | } |
||
2502 | #endif /* !WIN32 */ |
||
2503 | |||
2504 | #if 0 /* currently unused */ |
||
2505 | /* convert local string to display character set string */ |
||
2506 | char *local_to_display_string(local_string) |
||
2507 | ZCONST char *local_string; |
||
2508 | { |
||
2509 | char *display_string; |
||
2510 | |||
2511 | /* For Windows, OEM string should never be bigger than ANSI string, says |
||
2512 | CharToOem description. |
||
2513 | For all other ports, just make a copy of local_string. |
||
2514 | */ |
||
2515 | if ((display_string = (char *)malloc(strlen(local_string) + 1)) == NULL) { |
||
2516 | return NULL; |
||
2517 | } |
||
2518 | |||
2519 | strcpy(display_string, local_string); |
||
2520 | |||
2521 | #ifdef EBCDIC |
||
2522 | { |
||
2523 | char *ebc; |
||
2524 | |||
2525 | if ((ebc = malloc(strlen(display_string) + 1)) == NULL) { |
||
2526 | return NULL; |
||
2527 | } |
||
2528 | strtoebc(ebc, display_string); |
||
2529 | free(display_string); |
||
2530 | display_string = ebc; |
||
2531 | } |
||
2532 | #endif |
||
2533 | |||
2534 | return display_string; |
||
2535 | } |
||
2536 | #endif /* unused */ |
||
2537 | |||
2538 | /* UTF-8 to local */ |
||
2539 | char *utf8_to_local_string(utf8_string, escape_all) |
||
2540 | ZCONST char *utf8_string; |
||
2541 | int escape_all; |
||
2542 | { |
||
2543 | zwchar *wide = utf8_to_wide_string(utf8_string); |
||
2544 | char *loc = wide_to_local_string(wide, escape_all); |
||
2545 | free(wide); |
||
2546 | return loc; |
||
2547 | } |
||
2548 | |||
2549 | #if 0 /* currently unused */ |
||
2550 | /* convert multi-byte character string to wide character string */ |
||
2551 | zwchar *local_to_wide_string(local_string) |
||
2552 | ZCONST char *local_string; |
||
2553 | { |
||
2554 | int wsize; |
||
2555 | wchar_t *wc_string; |
||
2556 | zwchar *wide_string; |
||
2557 | |||
2558 | /* for now try to convert as string - fails if a bad char in string */ |
||
2559 | wsize = mbstowcs(NULL, local_string, strlen(local_string) + 1); |
||
2560 | if (wsize == (size_t)-1) { |
||
2561 | /* could not convert */ |
||
2562 | return NULL; |
||
2563 | } |
||
2564 | |||
2565 | /* convert it */ |
||
2566 | if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) { |
||
2567 | return NULL; |
||
2568 | } |
||
2569 | wsize = mbstowcs(wc_string, local_string, strlen(local_string) + 1); |
||
2570 | wc_string[wsize] = (wchar_t) 0; |
||
2571 | |||
2572 | /* in case wchar_t is not zwchar */ |
||
2573 | if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) { |
||
2574 | return NULL; |
||
2575 | } |
||
2576 | for (wsize = 0; wide_string[wsize] = (zwchar)wc_string[wsize]; wsize++) ; |
||
2577 | wide_string[wsize] = (zwchar) 0; |
||
2578 | free(wc_string); |
||
2579 | |||
2580 | return wide_string; |
||
2581 | } |
||
2582 | |||
2583 | |||
2584 | /* convert wide string to UTF-8 */ |
||
2585 | char *wide_to_utf8_string(wide_string) |
||
2586 | ZCONST zwchar *wide_string; |
||
2587 | { |
||
2588 | int mbcount; |
||
2589 | char *utf8_string; |
||
2590 | |||
2591 | /* get size of utf8 string */ |
||
2592 | mbcount = ucs4_string_to_utf8(wide_string, NULL, 0); |
||
2593 | if (mbcount == -1) |
||
2594 | return NULL; |
||
2595 | if ((utf8_string = (char *) malloc(mbcount + 1)) == NULL) { |
||
2596 | return NULL; |
||
2597 | } |
||
2598 | mbcount = ucs4_string_to_utf8(wide_string, utf8_string, mbcount + 1); |
||
2599 | if (mbcount == -1) |
||
2600 | return NULL; |
||
2601 | |||
2602 | return utf8_string; |
||
2603 | } |
||
2604 | #endif /* unused */ |
||
2605 | |||
2606 | /* convert UTF-8 string to wide string */ |
||
2607 | zwchar *utf8_to_wide_string(utf8_string) |
||
2608 | ZCONST char *utf8_string; |
||
2609 | { |
||
2610 | int wcount; |
||
2611 | zwchar *wide_string; |
||
2612 | |||
2613 | wcount = utf8_to_ucs4_string(utf8_string, NULL, 0); |
||
2614 | if (wcount == -1) |
||
2615 | return NULL; |
||
2616 | if ((wide_string = (zwchar *) malloc((wcount + 1) * sizeof(zwchar))) |
||
2617 | == NULL) { |
||
2618 | return NULL; |
||
2619 | } |
||
2620 | wcount = utf8_to_ucs4_string(utf8_string, wide_string, wcount + 1); |
||
2621 | |||
2622 | return wide_string; |
||
2623 | } |
||
2624 | |||
2625 | #endif /* UNICODE_WCHAR */ |
||
2626 | #endif /* UNICODE_SUPPORT */ |
||
2627 | |||
2628 | |||
2629 | |||
2630 | |||
2631 | |||
2632 | #ifdef USE_EF_UT_TIME |
||
2633 | |||
2634 | #ifdef IZ_HAVE_UXUIDGID |
||
2635 | static int read_ux3_value(dbuf, uidgid_sz, p_uidgid) |
||
2636 | ZCONST uch *dbuf; /* buffer a uid or gid value */ |
||
2637 | unsigned uidgid_sz; /* size of uid/gid value */ |
||
2638 | ulg *p_uidgid; /* return storage: uid or gid value */ |
||
2639 | { |
||
2640 | zusz_t uidgid64; |
||
2641 | |||
2642 | switch (uidgid_sz) { |
||
2643 | case 2: |
||
2644 | *p_uidgid = (ulg)makeword(dbuf); |
||
2645 | break; |
||
2646 | case 4: |
||
2647 | *p_uidgid = (ulg)makelong(dbuf); |
||
2648 | break; |
||
2649 | case 8: |
||
2650 | uidgid64 = makeint64(dbuf); |
||
2651 | #ifndef LARGE_FILE_SUPPORT |
||
2652 | if (uidgid64 == (zusz_t)0xffffffffL) |
||
2653 | return FALSE; |
||
2654 | #endif |
||
2655 | *p_uidgid = (ulg)uidgid64; |
||
2656 | if ((zusz_t)(*p_uidgid) != uidgid64) |
||
2657 | return FALSE; |
||
2658 | break; |
||
2659 | } |
||
2660 | return TRUE; |
||
2661 | } |
||
2662 | #endif /* IZ_HAVE_UXUIDGID */ |
||
2663 | |||
2664 | |||
2665 | /*******************************/ |
||
2666 | /* Function ef_scan_for_izux() */ |
||
2667 | /*******************************/ |
||
2668 | |||
2669 | unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime, |
||
2670 | z_utim, z_uidgid) |
||
2671 | ZCONST uch *ef_buf; /* buffer containing extra field */ |
||
2672 | unsigned ef_len; /* total length of extra field */ |
||
2673 | int ef_is_c; /* flag indicating "is central extra field" */ |
||
2674 | ulg dos_mdatetime; /* last_mod_file_date_time in DOS format */ |
||
2675 | iztimes *z_utim; /* return storage: atime, mtime, ctime */ |
||
2676 | ulg *z_uidgid; /* return storage: uid and gid */ |
||
2677 | { |
||
2678 | unsigned flags = 0; |
||
2679 | unsigned eb_id; |
||
2680 | unsigned eb_len; |
||
2681 | int have_new_type_eb = 0; |
||
2682 | long i_time; /* buffer for Unix style 32-bit integer time value */ |
||
2683 | #ifdef TIME_T_TYPE_DOUBLE |
||
2684 | int ut_in_archive_sgn = 0; |
||
2685 | #else |
||
2686 | int ut_zip_unzip_compatible = FALSE; |
||
2687 | #endif |
||
2688 | |||
2689 | /*--------------------------------------------------------------------------- |
||
2690 | This function scans the extra field for EF_TIME, EF_IZUNIX2, EF_IZUNIX, or |
||
2691 | EF_PKUNIX blocks containing Unix-style time_t (GMT) values for the entry's |
||
2692 | access, creation, and modification time. |
||
2693 | If a valid block is found, the time stamps are copied to the iztimes |
||
2694 | structure (provided the z_utim pointer is not NULL). |
||
2695 | If a IZUNIX2 block is found or the IZUNIX block contains UID/GID fields, |
||
2696 | and the z_uidgid array pointer is valid (!= NULL), the owner info is |
||
2697 | transfered as well. |
||
2698 | The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring all |
||
2699 | data from probably present obsolete EF_IZUNIX blocks. |
||
2700 | If multiple blocks of the same type are found, only the information from |
||
2701 | the last block is used. |
||
2702 | The return value is a combination of the EF_TIME Flags field with an |
||
2703 | additional flag bit indicating the presence of valid UID/GID info, |
||
2704 | or 0 in case of failure. |
||
2705 | ---------------------------------------------------------------------------*/ |
||
2706 | |||
2707 | if (ef_len == 0 || ef_buf == NULL || (z_utim == 0 && z_uidgid == NULL)) |
||
2708 | return 0; |
||
2709 | |||
2710 | TTrace((stderr,"\nef_scan_for_izux: scanning extra field of length %u\n", |
||
2711 | ef_len)); |
||
2712 | |||
2713 | while (ef_len >= EB_HEADSIZE) { |
||
2714 | eb_id = makeword(EB_ID + ef_buf); |
||
2715 | eb_len = makeword(EB_LEN + ef_buf); |
||
2716 | |||
2717 | if (eb_len > (ef_len - EB_HEADSIZE)) { |
||
2718 | /* discovered some extra field inconsistency! */ |
||
2719 | TTrace((stderr, |
||
2720 | "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len, |
||
2721 | ef_len - EB_HEADSIZE)); |
||
2722 | break; |
||
2723 | } |
||
2724 | |||
2725 | switch (eb_id) { |
||
2726 | case EF_TIME: |
||
2727 | flags &= ~0x0ff; /* ignore previous IZUNIX or EF_TIME fields */ |
||
2728 | have_new_type_eb = 1; |
||
2729 | if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) { |
||
2730 | unsigned eb_idx = EB_UT_TIME1; |
||
2731 | TTrace((stderr,"ef_scan_for_izux: found TIME extra field\n")); |
||
2732 | flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x0ff); |
||
2733 | if ((flags & EB_UT_FL_MTIME)) { |
||
2734 | if ((eb_idx+4) <= eb_len) { |
||
2735 | i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); |
||
2736 | eb_idx += 4; |
||
2737 | TTrace((stderr," UT e.f. modification time = %ld\n", |
||
2738 | i_time)); |
||
2739 | |||
2740 | #ifdef TIME_T_TYPE_DOUBLE |
||
2741 | if ((ulg)(i_time) & (ulg)(0x80000000L)) { |
||
2742 | if (dos_mdatetime == DOSTIME_MINIMUM) { |
||
2743 | ut_in_archive_sgn = -1; |
||
2744 | z_utim->mtime = |
||
2745 | (time_t)((long)i_time | (~(long)0x7fffffffL)); |
||
2746 | } else if (dos_mdatetime >= DOSTIME_2038_01_18) { |
||
2747 | ut_in_archive_sgn = 1; |
||
2748 | z_utim->mtime = |
||
2749 | (time_t)((ulg)i_time & (ulg)0xffffffffL); |
||
2750 | } else { |
||
2751 | ut_in_archive_sgn = 0; |
||
2752 | /* cannot determine sign of mtime; |
||
2753 | without modtime: ignore complete UT field */ |
||
2754 | flags &= ~0x0ff; /* no time_t times available */ |
||
2755 | TTrace((stderr, |
||
2756 | " UT modtime range error; ignore e.f.!\n")); |
||
2757 | break; /* stop scanning this field */ |
||
2758 | } |
||
2759 | } else { |
||
2760 | /* cannot determine, safe assumption is FALSE */ |
||
2761 | ut_in_archive_sgn = 0; |
||
2762 | z_utim->mtime = (time_t)i_time; |
||
2763 | } |
||
2764 | #else /* !TIME_T_TYPE_DOUBLE */ |
||
2765 | if ((ulg)(i_time) & (ulg)(0x80000000L)) { |
||
2766 | ut_zip_unzip_compatible = |
||
2767 | ((time_t)0x80000000L < (time_t)0L) |
||
2768 | ? (dos_mdatetime == DOSTIME_MINIMUM) |
||
2769 | : (dos_mdatetime >= DOSTIME_2038_01_18); |
||
2770 | if (!ut_zip_unzip_compatible) { |
||
2771 | /* UnZip interprets mtime differently than Zip; |
||
2772 | without modtime: ignore complete UT field */ |
||
2773 | flags &= ~0x0ff; /* no time_t times available */ |
||
2774 | TTrace((stderr, |
||
2775 | " UT modtime range error; ignore e.f.!\n")); |
||
2776 | break; /* stop scanning this field */ |
||
2777 | } |
||
2778 | } else { |
||
2779 | /* cannot determine, safe assumption is FALSE */ |
||
2780 | ut_zip_unzip_compatible = FALSE; |
||
2781 | } |
||
2782 | z_utim->mtime = (time_t)i_time; |
||
2783 | #endif /* ?TIME_T_TYPE_DOUBLE */ |
||
2784 | } else { |
||
2785 | flags &= ~EB_UT_FL_MTIME; |
||
2786 | TTrace((stderr," UT e.f. truncated; no modtime\n")); |
||
2787 | } |
||
2788 | } |
||
2789 | if (ef_is_c) { |
||
2790 | break; /* central version of TIME field ends here */ |
||
2791 | } |
||
2792 | |||
2793 | if (flags & EB_UT_FL_ATIME) { |
||
2794 | if ((eb_idx+4) <= eb_len) { |
||
2795 | i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); |
||
2796 | eb_idx += 4; |
||
2797 | TTrace((stderr," UT e.f. access time = %ld\n", |
||
2798 | i_time)); |
||
2799 | #ifdef TIME_T_TYPE_DOUBLE |
||
2800 | if ((ulg)(i_time) & (ulg)(0x80000000L)) { |
||
2801 | if (ut_in_archive_sgn == -1) |
||
2802 | z_utim->atime = |
||
2803 | (time_t)((long)i_time | (~(long)0x7fffffffL)); |
||
2804 | } else if (ut_in_archive_sgn == 1) { |
||
2805 | z_utim->atime = |
||
2806 | (time_t)((ulg)i_time & (ulg)0xffffffffL); |
||
2807 | } else { |
||
2808 | /* sign of 32-bit time is unknown -> ignore it */ |
||
2809 | flags &= ~EB_UT_FL_ATIME; |
||
2810 | TTrace((stderr, |
||
2811 | " UT access time range error: skip time!\n")); |
||
2812 | } |
||
2813 | } else { |
||
2814 | z_utim->atime = (time_t)i_time; |
||
2815 | } |
||
2816 | #else /* !TIME_T_TYPE_DOUBLE */ |
||
2817 | if (((ulg)(i_time) & (ulg)(0x80000000L)) && |
||
2818 | !ut_zip_unzip_compatible) { |
||
2819 | flags &= ~EB_UT_FL_ATIME; |
||
2820 | TTrace((stderr, |
||
2821 | " UT access time range error: skip time!\n")); |
||
2822 | } else { |
||
2823 | z_utim->atime = (time_t)i_time; |
||
2824 | } |
||
2825 | #endif /* ?TIME_T_TYPE_DOUBLE */ |
||
2826 | } else { |
||
2827 | flags &= ~EB_UT_FL_ATIME; |
||
2828 | } |
||
2829 | } |
||
2830 | if (flags & EB_UT_FL_CTIME) { |
||
2831 | if ((eb_idx+4) <= eb_len) { |
||
2832 | i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); |
||
2833 | TTrace((stderr," UT e.f. creation time = %ld\n", |
||
2834 | i_time)); |
||
2835 | #ifdef TIME_T_TYPE_DOUBLE |
||
2836 | if ((ulg)(i_time) & (ulg)(0x80000000L)) { |
||
2837 | if (ut_in_archive_sgn == -1) |
||
2838 | z_utim->ctime = |
||
2839 | (time_t)((long)i_time | (~(long)0x7fffffffL)); |
||
2840 | } else if (ut_in_archive_sgn == 1) { |
||
2841 | z_utim->ctime = |
||
2842 | (time_t)((ulg)i_time & (ulg)0xffffffffL); |
||
2843 | } else { |
||
2844 | /* sign of 32-bit time is unknown -> ignore it */ |
||
2845 | flags &= ~EB_UT_FL_CTIME; |
||
2846 | TTrace((stderr, |
||
2847 | " UT creation time range error: skip time!\n")); |
||
2848 | } |
||
2849 | } else { |
||
2850 | z_utim->ctime = (time_t)i_time; |
||
2851 | } |
||
2852 | #else /* !TIME_T_TYPE_DOUBLE */ |
||
2853 | if (((ulg)(i_time) & (ulg)(0x80000000L)) && |
||
2854 | !ut_zip_unzip_compatible) { |
||
2855 | flags &= ~EB_UT_FL_CTIME; |
||
2856 | TTrace((stderr, |
||
2857 | " UT creation time range error: skip time!\n")); |
||
2858 | } else { |
||
2859 | z_utim->ctime = (time_t)i_time; |
||
2860 | } |
||
2861 | #endif /* ?TIME_T_TYPE_DOUBLE */ |
||
2862 | } else { |
||
2863 | flags &= ~EB_UT_FL_CTIME; |
||
2864 | } |
||
2865 | } |
||
2866 | } |
||
2867 | break; |
||
2868 | |||
2869 | case EF_IZUNIX2: |
||
2870 | if (have_new_type_eb == 0) { |
||
2871 | flags &= ~0x0ff; /* ignore any previous IZUNIX field */ |
||
2872 | have_new_type_eb = 1; |
||
2873 | } |
||
2874 | #ifdef IZ_HAVE_UXUIDGID |
||
2875 | if (have_new_type_eb > 1) |
||
2876 | break; /* IZUNIX3 overrides IZUNIX2 e.f. block ! */ |
||
2877 | if (eb_len == EB_UX2_MINLEN && z_uidgid != NULL) { |
||
2878 | z_uidgid[0] = (ulg)makeword((EB_HEADSIZE+EB_UX2_UID) + ef_buf); |
||
2879 | z_uidgid[1] = (ulg)makeword((EB_HEADSIZE+EB_UX2_GID) + ef_buf); |
||
2880 | flags |= EB_UX2_VALID; /* signal success */ |
||
2881 | } |
||
2882 | #endif |
||
2883 | break; |
||
2884 | |||
2885 | case EF_IZUNIX3: |
||
2886 | /* new 3rd generation Unix ef */ |
||
2887 | have_new_type_eb = 2; |
||
2888 | |||
2889 | /* |
||
2890 | Version 1 byte version of this extra field, currently 1 |
||
2891 | UIDSize 1 byte Size of UID field |
||
2892 | UID Variable UID for this entry |
||
2893 | GIDSize 1 byte Size of GID field |
||
2894 | GID Variable GID for this entry |
||
2895 | */ |
||
2896 | |||
2897 | #ifdef IZ_HAVE_UXUIDGID |
||
2898 | if (eb_len >= EB_UX3_MINLEN |
||
2899 | && z_uidgid != NULL |
||
2900 | && (*((EB_HEADSIZE + 0) + ef_buf) == 1) |
||
2901 | /* only know about version 1 */ |
||
2902 | { |
||
2903 | uch uid_size; |
||
2904 | uch gid_size; |
||
2905 | |||
2906 | uid_size = *((EB_HEADSIZE + 1) + ef_buf); |
||
2907 | gid_size = *((EB_HEADSIZE + uid_size + 2) + ef_buf); |
||
2908 | |||
2909 | flags &= ~0x0ff; /* ignore any previous UNIX field */ |
||
2910 | |||
2911 | if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf, |
||
2912 | uid_size, z_uidgid[0]) |
||
2913 | && |
||
2914 | read_ux3_value((EB_HEADSIZE + uid_size + 3) + ef_buf, |
||
2915 | gid_size, z_uidgid[1]) ) |
||
2916 | { |
||
2917 | flags |= EB_UX2_VALID; /* signal success */ |
||
2918 | } |
||
2919 | } |
||
2920 | #endif /* IZ_HAVE_UXUIDGID */ |
||
2921 | break; |
||
2922 | |||
2923 | case EF_IZUNIX: |
||
2924 | case EF_PKUNIX: /* PKUNIX e.f. layout is identical to IZUNIX */ |
||
2925 | if (eb_len >= EB_UX_MINLEN) { |
||
2926 | TTrace((stderr,"ef_scan_for_izux: found %s extra field\n", |
||
2927 | (eb_id == EF_IZUNIX ? "IZUNIX" : "PKUNIX"))); |
||
2928 | if (have_new_type_eb > 0) { |
||
2929 | break; /* Ignore IZUNIX extra field block ! */ |
||
2930 | } |
||
2931 | if (z_utim != NULL) { |
||
2932 | flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME); |
||
2933 | i_time = (long)makelong((EB_HEADSIZE+EB_UX_MTIME)+ef_buf); |
||
2934 | TTrace((stderr," Unix EF modtime = %ld\n", i_time)); |
||
2935 | #ifdef TIME_T_TYPE_DOUBLE |
||
2936 | if ((ulg)(i_time) & (ulg)(0x80000000L)) { |
||
2937 | if (dos_mdatetime == DOSTIME_MINIMUM) { |
||
2938 | ut_in_archive_sgn = -1; |
||
2939 | z_utim->mtime = |
||
2940 | (time_t)((long)i_time | (~(long)0x7fffffffL)); |
||
2941 | } else if (dos_mdatetime >= DOSTIME_2038_01_18) { |
||
2942 | ut_in_archive_sgn = 1; |
||
2943 | z_utim->mtime = |
||
2944 | (time_t)((ulg)i_time & (ulg)0xffffffffL); |
||
2945 | } else { |
||
2946 | ut_in_archive_sgn = 0; |
||
2947 | /* cannot determine sign of mtime; |
||
2948 | without modtime: ignore complete UT field */ |
||
2949 | flags &= ~0x0ff; /* no time_t times available */ |
||
2950 | TTrace((stderr, |
||
2951 | " UX modtime range error: ignore e.f.!\n")); |
||
2952 | } |
||
2953 | } else { |
||
2954 | /* cannot determine, safe assumption is FALSE */ |
||
2955 | ut_in_archive_sgn = 0; |
||
2956 | z_utim->mtime = (time_t)i_time; |
||
2957 | } |
||
2958 | #else /* !TIME_T_TYPE_DOUBLE */ |
||
2959 | if ((ulg)(i_time) & (ulg)(0x80000000L)) { |
||
2960 | ut_zip_unzip_compatible = |
||
2961 | ((time_t)0x80000000L < (time_t)0L) |
||
2962 | ? (dos_mdatetime == DOSTIME_MINIMUM) |
||
2963 | : (dos_mdatetime >= DOSTIME_2038_01_18); |
||
2964 | if (!ut_zip_unzip_compatible) { |
||
2965 | /* UnZip interpretes mtime differently than Zip; |
||
2966 | without modtime: ignore complete UT field */ |
||
2967 | flags &= ~0x0ff; /* no time_t times available */ |
||
2968 | TTrace((stderr, |
||
2969 | " UX modtime range error: ignore e.f.!\n")); |
||
2970 | } |
||
2971 | } else { |
||
2972 | /* cannot determine, safe assumption is FALSE */ |
||
2973 | ut_zip_unzip_compatible = FALSE; |
||
2974 | } |
||
2975 | z_utim->mtime = (time_t)i_time; |
||
2976 | #endif /* ?TIME_T_TYPE_DOUBLE */ |
||
2977 | i_time = (long)makelong((EB_HEADSIZE+EB_UX_ATIME)+ef_buf); |
||
2978 | TTrace((stderr," Unix EF actime = %ld\n", i_time)); |
||
2979 | #ifdef TIME_T_TYPE_DOUBLE |
||
2980 | if ((ulg)(i_time) & (ulg)(0x80000000L)) { |
||
2981 | if (ut_in_archive_sgn == -1) |
||
2982 | z_utim->atime = |
||
2983 | (time_t)((long)i_time | (~(long)0x7fffffffL)); |
||
2984 | } else if (ut_in_archive_sgn == 1) { |
||
2985 | z_utim->atime = |
||
2986 | (time_t)((ulg)i_time & (ulg)0xffffffffL); |
||
2987 | } else if (flags & 0x0ff) { |
||
2988 | /* sign of 32-bit time is unknown -> ignore it */ |
||
2989 | flags &= ~EB_UT_FL_ATIME; |
||
2990 | TTrace((stderr, |
||
2991 | " UX access time range error: skip time!\n")); |
||
2992 | } |
||
2993 | } else { |
||
2994 | z_utim->atime = (time_t)i_time; |
||
2995 | } |
||
2996 | #else /* !TIME_T_TYPE_DOUBLE */ |
||
2997 | if (((ulg)(i_time) & (ulg)(0x80000000L)) && |
||
2998 | !ut_zip_unzip_compatible && (flags & 0x0ff)) { |
||
2999 | /* atime not in range of UnZip's time_t */ |
||
3000 | flags &= ~EB_UT_FL_ATIME; |
||
3001 | TTrace((stderr, |
||
3002 | " UX access time range error: skip time!\n")); |
||
3003 | } else { |
||
3004 | z_utim->atime = (time_t)i_time; |
||
3005 | } |
||
3006 | #endif /* ?TIME_T_TYPE_DOUBLE */ |
||
3007 | } |
||
3008 | #ifdef IZ_HAVE_UXUIDGID |
||
3009 | if (eb_len >= EB_UX_FULLSIZE && z_uidgid != NULL) { |
||
3010 | z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX_UID) + ef_buf); |
||
3011 | z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX_GID) + ef_buf); |
||
3012 | flags |= EB_UX2_VALID; |
||
3013 | } |
||
3014 | #endif /* IZ_HAVE_UXUIDGID */ |
||
3015 | } |
||
3016 | break; |
||
3017 | |||
3018 | default: |
||
3019 | break; |
||
3020 | } |
||
3021 | |||
3022 | /* Skip this extra field block */ |
||
3023 | ef_buf += (eb_len + EB_HEADSIZE); |
||
3024 | ef_len -= (eb_len + EB_HEADSIZE); |
||
3025 | } |
||
3026 | |||
3027 | return flags; |
||
3028 | } |
||
3029 | |||
3030 | #endif /* USE_EF_UT_TIME */ |
||
3031 | |||
3032 | |||
3033 | #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) |
||
3034 | |||
3035 | #define SPARKID_2 0x30435241 /* = "ARC0" */ |
||
3036 | |||
3037 | /*******************************/ |
||
3038 | /* Function getRISCOSexfield() */ |
||
3039 | /*******************************/ |
||
3040 | |||
3041 | zvoid *getRISCOSexfield(ef_buf, ef_len) |
||
3042 | ZCONST uch *ef_buf; /* buffer containing extra field */ |
||
3043 | unsigned ef_len; /* total length of extra field */ |
||
3044 | { |
||
3045 | unsigned eb_id; |
||
3046 | unsigned eb_len; |
||
3047 | |||
3048 | /*--------------------------------------------------------------------------- |
||
3049 | This function scans the extra field for a Acorn SPARK filetype ef-block. |
||
3050 | If a valid block is found, the function returns a pointer to the start |
||
3051 | of the SPARK_EF block in the extra field buffer. Otherwise, a NULL |
||
3052 | pointer is returned. |
||
3053 | ---------------------------------------------------------------------------*/ |
||
3054 | |||
3055 | if (ef_len == 0 || ef_buf == NULL) |
||
3056 | return NULL; |
||
3057 | |||
3058 | Trace((stderr,"\ngetRISCOSexfield: scanning extra field of length %u\n", |
||
3059 | ef_len)); |
||
3060 | |||
3061 | while (ef_len >= EB_HEADSIZE) { |
||
3062 | eb_id = makeword(EB_ID + ef_buf); |
||
3063 | eb_len = makeword(EB_LEN + ef_buf); |
||
3064 | |||
3065 | if (eb_len > (ef_len - EB_HEADSIZE)) { |
||
3066 | /* discovered some extra field inconsistency! */ |
||
3067 | Trace((stderr, |
||
3068 | "getRISCOSexfield: block length %u > rest ef_size %u\n", eb_len, |
||
3069 | ef_len - EB_HEADSIZE)); |
||
3070 | break; |
||
3071 | } |
||
3072 | |||
3073 | if (eb_id == EF_SPARK && (eb_len == 24 || eb_len == 20)) { |
||
3074 | if (makelong(EB_HEADSIZE + ef_buf) == SPARKID_2) { |
||
3075 | /* Return a pointer to the valid SPARK filetype ef block */ |
||
3076 | return (zvoid *)ef_buf; |
||
3077 | } |
||
3078 | } |
||
3079 | |||
3080 | /* Skip this extra field block */ |
||
3081 | ef_buf += (eb_len + EB_HEADSIZE); |
||
3082 | ef_len -= (eb_len + EB_HEADSIZE); |
||
3083 | } |
||
3084 | |||
3085 | return NULL; |
||
3086 | } |
||
3087 | |||
3088 | #endif /* (RISCOS || ACORN_FTYPE_NFS) */>=>=>>=>=>>>>>>>>=>>>=>>>><>>=>>>>>>>>>>><>><>>=>>=>>>>> |