]>
Commit | Line | Data |
---|---|---|
1 | /*--------------------------------------------------------------------------- | |
2 | ||
3 | extract.c | |
4 | ||
5 | This file contains the high-level routines ("driver routines") for extrac- | |
6 | ting and testing zipfile members. It calls the low-level routines in files | |
7 | explode.c, inflate.c, unreduce.c and unshrink.c. | |
8 | ||
9 | Contains: extract_or_test_files() | |
10 | store_info() | |
11 | extract_or_test_member() | |
12 | TestExtraField() | |
13 | test_compr_eb() | |
14 | memextract() | |
15 | memflush() | |
16 | fnfilter() | |
17 | ||
18 | ---------------------------------------------------------------------------*/ | |
19 | ||
20 | ||
21 | #define EXTRACT_C | |
22 | #define UNZIP_INTERNAL | |
23 | #include "unzip.h" | |
24 | #include "crypt.h" | |
25 | #ifdef WINDLL | |
26 | # ifdef POCKET_UNZIP | |
27 | # include "wince/intrface.h" | |
28 | # else | |
29 | # include "windll/windll.h" | |
30 | # endif | |
31 | #endif | |
32 | ||
33 | #define GRRDUMP(buf,len) { \ | |
34 | int i, j; \ | |
35 | \ | |
36 | for (j = 0; j < (len)/16; ++j) { \ | |
37 | pipeit(" "); \ | |
38 | for (i = 0; i < 16; ++i) \ | |
39 | pipeit("%02x ", (uch)(buf)[i+(j<<4)]); \ | |
40 | pipeit("\n "); \ | |
41 | for (i = 0; i < 16; ++i) { \ | |
42 | char c = (char)(buf)[i+(j<<4)]; \ | |
43 | \ | |
44 | if (c == '\n') \ | |
45 | pipeit("\\n "); \ | |
46 | else if (c == '\r') \ | |
47 | pipeit("\\r "); \ | |
48 | else \ | |
49 | pipeit(" %c ", c); \ | |
50 | } \ | |
51 | pipeit("\n"); \ | |
52 | } \ | |
53 | if ((len) % 16) { \ | |
54 | pipeit(" "); \ | |
55 | for (i = j<<4; i < (len); ++i) \ | |
56 | pipeit("%02x ", (uch)(buf)[i]); \ | |
57 | pipeit("\n "); \ | |
58 | for (i = j<<4; i < (len); ++i) { \ | |
59 | char c = (char)(buf)[i]; \ | |
60 | \ | |
61 | if (c == '\n') \ | |
62 | pipeit("\\n "); \ | |
63 | else if (c == '\r') \ | |
64 | pipeit("\\r "); \ | |
65 | else \ | |
66 | pipeit(" %c ", c); \ | |
67 | } \ | |
68 | pipeit("\n"); \ | |
69 | } \ | |
70 | } | |
71 | ||
72 | static int store_info OF((__GPRO)); | |
73 | static int extract_or_test_member OF((__GPRO)); | |
74 | #ifndef SFX | |
75 | static int TestExtraField OF((__GPRO__ uch *ef, unsigned ef_len)); | |
76 | static int test_compr_eb OF((__GPRO__ uch *eb, unsigned eb_size, | |
77 | unsigned compr_offset, | |
78 | int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size, | |
79 | uch *eb_ucptr, ulg eb_ucsize))); | |
80 | #endif | |
81 | #ifdef SET_DIR_ATTRIB | |
82 | static int dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b)); | |
83 | #endif | |
84 | ||
85 | ||
86 | ||
87 | /*******************************/ | |
88 | /* Strings used in extract.c */ | |
89 | /*******************************/ | |
90 | ||
91 | static ZCONST char Far VersionMsg[] = | |
92 | " skipping: %-22s need %s compat. v%u.%u (can do v%u.%u)\n"; | |
93 | static ZCONST char Far ComprMsgNum[] = | |
94 | " skipping: %-22s unsupported compression method %u\n"; | |
95 | #ifndef SFX | |
96 | static ZCONST char Far ComprMsgName[] = | |
97 | " skipping: %-22s `%s' method not supported\n"; | |
98 | static ZCONST char Far CmprNone[] = "store"; | |
99 | static ZCONST char Far CmprShrink[] = "shrink"; | |
100 | static ZCONST char Far CmprReduce[] = "reduce"; | |
101 | static ZCONST char Far CmprImplode[] = "implode"; | |
102 | static ZCONST char Far CmprTokenize[] = "tokenize"; | |
103 | static ZCONST char Far CmprDeflate[] = "deflate"; | |
104 | static ZCONST char Far CmprEnDeflate[] = "enhanced deflate"; | |
105 | static ZCONST char Far CmprDCLImplode[] = "DCL implode"; | |
106 | static ZCONST char Far *ComprNames[NUM_METHODS] = { | |
107 | CmprNone, CmprShrink, CmprReduce, CmprReduce, CmprReduce, CmprReduce, | |
108 | CmprImplode, CmprTokenize, CmprDeflate, CmprEnDeflate, CmprDCLImplode | |
109 | }; | |
110 | #endif /* !SFX */ | |
111 | static ZCONST char Far FilNamMsg[] = | |
112 | "%s: bad filename length (%s)\n"; | |
113 | static ZCONST char Far ExtFieldMsg[] = | |
114 | "%s: bad extra field length (%s)\n"; | |
115 | static ZCONST char Far OffsetMsg[] = | |
116 | "file #%u: bad zipfile offset (%s): %ld\n"; | |
117 | static ZCONST char Far ExtractMsg[] = | |
118 | "%8sing: %-22s %s%s"; | |
119 | #ifndef SFX | |
120 | static ZCONST char Far LengthMsg[] = | |
121 | "%s %s: %ld bytes required to uncompress to %lu bytes;\n %s\ | |
122 | supposed to require %lu bytes%s%s%s\n"; | |
123 | #endif | |
124 | ||
125 | static ZCONST char Far BadFileCommLength[] = "%s: bad file comment length\n"; | |
126 | static ZCONST char Far LocalHdrSig[] = "local header sig"; | |
127 | static ZCONST char Far BadLocalHdr[] = "file #%u: bad local header\n"; | |
128 | static ZCONST char Far AttemptRecompensate[] = | |
129 | " (attempting to re-compensate)\n"; | |
130 | #ifndef SFX | |
131 | static ZCONST char Far BackslashPathSep[] = | |
132 | "warning: %s appears to use backslashes as path separators\n"; | |
133 | #endif | |
134 | static ZCONST char Far SkipVolumeLabel[] = | |
135 | " skipping: %-22s %svolume label\n"; | |
136 | ||
137 | #ifdef SET_DIR_ATTRIB /* messages of code for setting directory attributes */ | |
138 | static ZCONST char Far DirlistEntryNoMem[] = | |
139 | "warning: cannot alloc memory for dir times/permissions/UID/GID\n"; | |
140 | static ZCONST char Far DirlistSortNoMem[] = | |
141 | "warning: cannot alloc memory to sort dir times/perms/etc.\n"; | |
142 | static ZCONST char Far DirlistSetAttrFailed[] = | |
143 | "warning: set times/attribs failed for %s\n"; | |
144 | #endif | |
145 | ||
146 | #ifndef WINDLL | |
147 | static ZCONST char Far ReplaceQuery[] = | |
148 | "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: "; | |
149 | static ZCONST char Far AssumeNone[] = " NULL\n(assuming [N]one)\n"; | |
150 | static ZCONST char Far NewNameQuery[] = "new name: "; | |
151 | static ZCONST char Far InvalidResponse[] = "error: invalid response [%c]\n"; | |
152 | #endif /* !WINDLL */ | |
153 | ||
154 | static ZCONST char Far ErrorInArchive[] = | |
155 | "At least one %serror was detected in %s.\n"; | |
156 | static ZCONST char Far ZeroFilesTested[] = | |
157 | "Caution: zero files tested in %s.\n"; | |
158 | ||
159 | #ifndef VMS | |
160 | static ZCONST char Far VMSFormatQuery[] = | |
161 | "\n%s: stored in VMS format. Extract anyway? (y/n) "; | |
162 | #endif | |
163 | ||
164 | #if CRYPT | |
165 | static ZCONST char Far SkipCannotGetPasswd[] = | |
166 | " skipping: %-22s unable to get password\n"; | |
167 | static ZCONST char Far SkipIncorrectPasswd[] = | |
168 | " skipping: %-22s incorrect password\n"; | |
169 | static ZCONST char Far FilesSkipBadPasswd[] = | |
170 | "%u file%s skipped because of incorrect password.\n"; | |
171 | static ZCONST char Far MaybeBadPasswd[] = | |
172 | " (may instead be incorrect password)\n"; | |
173 | #else | |
174 | static ZCONST char Far SkipEncrypted[] = | |
175 | " skipping: %-22s encrypted (not supported)\n"; | |
176 | #endif | |
177 | ||
178 | static ZCONST char Far NoErrInCompData[] = | |
179 | "No errors detected in compressed data of %s.\n"; | |
180 | static ZCONST char Far NoErrInTestedFiles[] = | |
181 | "No errors detected in %s for the %u file%s tested.\n"; | |
182 | static ZCONST char Far FilesSkipped[] = | |
183 | "%u file%s skipped because of unsupported compression or encoding.\n"; | |
184 | ||
185 | static ZCONST char Far ErrUnzipFile[] = " error: %s%s %s\n"; | |
186 | static ZCONST char Far ErrUnzipNoFile[] = "\n error: %s%s\n"; | |
187 | static ZCONST char Far NotEnoughMem[] = "not enough memory to "; | |
188 | static ZCONST char Far InvalidComprData[] = "invalid compressed data to "; | |
189 | static ZCONST char Far Inflate[] = "inflate"; | |
190 | ||
191 | #ifndef SFX | |
192 | static ZCONST char Far Explode[] = "explode"; | |
193 | #ifndef LZW_CLEAN | |
194 | static ZCONST char Far Unshrink[] = "unshrink"; | |
195 | #endif | |
196 | #endif | |
197 | ||
198 | #if (!defined(DELETE_IF_FULL) || !defined(HAVE_UNLINK)) | |
199 | static ZCONST char Far FileTruncated[] = | |
200 | "warning: %s is probably truncated\n"; | |
201 | #endif | |
202 | ||
203 | static ZCONST char Far FileUnknownCompMethod[] = | |
204 | "%s: unknown compression method\n"; | |
205 | static ZCONST char Far BadCRC[] = " bad CRC %08lx (should be %08lx)\n"; | |
206 | ||
207 | /* TruncEAs[] also used in OS/2 mapname(), close_outfile() */ | |
208 | char ZCONST Far TruncEAs[] = " compressed EA data missing (%d bytes)%s"; | |
209 | char ZCONST Far TruncNTSD[] = | |
210 | " compressed WinNT security data missing (%d bytes)%s"; | |
211 | ||
212 | #ifndef SFX | |
213 | static ZCONST char Far InconsistEFlength[] = "bad extra-field entry:\n \ | |
214 | EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n"; | |
215 | static ZCONST char Far InvalidComprDataEAs[] = | |
216 | " invalid compressed data for EAs\n"; | |
217 | # if (defined(WIN32) && defined(NTSD_EAS)) | |
218 | static ZCONST char Far InvalidSecurityEAs[] = | |
219 | " EAs fail security check\n"; | |
220 | # endif | |
221 | static ZCONST char Far UnsuppNTSDVersEAs[] = | |
222 | " unsupported NTSD EAs version %d\n"; | |
223 | static ZCONST char Far BadCRC_EAs[] = " bad CRC for extended attributes\n"; | |
224 | static ZCONST char Far UnknComprMethodEAs[] = | |
225 | " unknown compression method for EAs (%u)\n"; | |
226 | static ZCONST char Far NotEnoughMemEAs[] = | |
227 | " out of memory while inflating EAs\n"; | |
228 | static ZCONST char Far UnknErrorEAs[] = | |
229 | " unknown error on extended attributes\n"; | |
230 | #endif /* !SFX */ | |
231 | ||
232 | static ZCONST char Far UnsupportedExtraField[] = | |
233 | "\nerror: unsupported extra-field compression type (%u)--skipping\n"; | |
234 | static ZCONST char Far BadExtraFieldCRC[] = | |
235 | "error [%s]: bad extra-field CRC %08lx (should be %08lx)\n"; | |
236 | ||
237 | ||
238 | ||
239 | ||
240 | ||
241 | /**************************************/ | |
242 | /* Function extract_or_test_files() */ | |
243 | /**************************************/ | |
244 | ||
245 | int extract_or_test_files(__G) /* return PK-type error code */ | |
246 | __GDEF | |
247 | { | |
248 | uch *cd_inptr; | |
249 | unsigned i, j, filnum=0, blknum=0; | |
250 | int cd_incnt, renamed, query; | |
251 | int error, error_in_archive=PK_COOL, *fn_matched=NULL, *xn_matched=NULL; | |
252 | #ifdef WINDLL | |
253 | int done_once = 0; | |
254 | #else | |
255 | extent len; | |
256 | #endif | |
257 | unsigned members_remaining, num_skipped=0, num_bad_pwd=0; | |
258 | long cd_bufstart, bufstart, inbuf_offset, request; | |
259 | LONGINT old_extra_bytes = 0L; | |
260 | #ifdef SET_DIR_ATTRIB | |
261 | unsigned num_dirs=0; | |
262 | dirtime *dirlist=(dirtime *)NULL, **sorted_dirlist=(dirtime **)NULL; | |
263 | #endif | |
264 | ||
265 | ||
266 | /*--------------------------------------------------------------------------- | |
267 | The basic idea of this function is as follows. Since the central di- | |
268 | rectory lies at the end of the zipfile and the member files lie at the | |
269 | beginning or middle or wherever, it is not very desirable to simply | |
270 | read a central directory entry, jump to the member and extract it, and | |
271 | then jump back to the central directory. In the case of a large zipfile | |
272 | this would lead to a whole lot of disk-grinding, especially if each mem- | |
273 | ber file is small. Instead, we read from the central directory the per- | |
274 | tinent information for a block of files, then go extract/test the whole | |
275 | block. Thus this routine contains two small(er) loops within a very | |
276 | large outer loop: the first of the small ones reads a block of files | |
277 | from the central directory; the second extracts or tests each file; and | |
278 | the outer one loops over blocks. There's some file-pointer positioning | |
279 | stuff in between, but that's about it. Btw, it's because of this jump- | |
280 | ing around that we can afford to be lenient if an error occurs in one of | |
281 | the member files: we should still be able to go find the other members, | |
282 | since we know the offset of each from the beginning of the zipfile. | |
283 | ---------------------------------------------------------------------------*/ | |
284 | ||
285 | G.pInfo = G.info; | |
286 | members_remaining = (unsigned)G.ecrec.total_entries_central_dir; | |
287 | ||
288 | #if CRYPT | |
289 | G.newzip = TRUE; | |
290 | #endif | |
291 | #ifndef SFX | |
292 | G.reported_backslash = FALSE; | |
293 | #endif | |
294 | ||
295 | /* malloc space for check on unmatched filespecs (OK if one or both NULL) */ | |
296 | if (G.filespecs > 0 && | |
297 | (fn_matched=(int *)malloc(G.filespecs*sizeof(int))) != (int *)NULL) | |
298 | for (i = 0; i < G.filespecs; ++i) | |
299 | fn_matched[i] = FALSE; | |
300 | if (G.xfilespecs > 0 && | |
301 | (xn_matched=(int *)malloc(G.xfilespecs*sizeof(int))) != (int *)NULL) | |
302 | for (i = 0; i < G.xfilespecs; ++i) | |
303 | xn_matched[i] = FALSE; | |
304 | ||
305 | /*--------------------------------------------------------------------------- | |
306 | Begin main loop over blocks of member files. We know the entire central | |
307 | directory is on this disk: we would not have any of this information un- | |
308 | less the end-of-central-directory record was on this disk, and we would | |
309 | not have gotten to this routine unless this is also the disk on which | |
310 | the central directory starts. In practice, this had better be the ONLY | |
311 | disk in the archive, but we'll add multi-disk support soon. | |
312 | ---------------------------------------------------------------------------*/ | |
313 | ||
314 | while (members_remaining) { | |
315 | j = 0; | |
316 | #ifdef AMIGA | |
317 | memzero(G.filenotes, DIR_BLKSIZ * sizeof(char *)); | |
318 | #endif | |
319 | ||
320 | /* | |
321 | * Loop through files in central directory, storing offsets, file | |
322 | * attributes, case-conversion and text-conversion flags until block | |
323 | * size is reached. | |
324 | */ | |
325 | ||
326 | while (members_remaining && (j < DIR_BLKSIZ)) { | |
327 | --members_remaining; | |
328 | G.pInfo = &G.info[j]; | |
329 | ||
330 | if (readbuf(__G__ G.sig, 4) == 0) { | |
331 | error_in_archive = PK_EOF; | |
332 | members_remaining = 0; /* ...so no more left to do */ | |
333 | break; | |
334 | } | |
335 | if (strncmp(G.sig, central_hdr_sig, 4)) { /* just to make sure */ | |
336 | Info(slide, 0x401, ((char *)slide, LoadFarString(CentSigMsg), | |
337 | j + blknum*DIR_BLKSIZ + 1)); | |
338 | Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg))); | |
339 | error_in_archive = PK_BADERR; | |
340 | members_remaining = 0; /* ...so no more left to do */ | |
341 | break; | |
342 | } | |
343 | /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */ | |
344 | if ((error = process_cdir_file_hdr(__G)) != PK_COOL) { | |
345 | error_in_archive = error; /* only PK_EOF defined */ | |
346 | members_remaining = 0; /* ...so no more left to do */ | |
347 | break; | |
348 | } | |
349 | if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) != | |
350 | PK_COOL) | |
351 | { | |
352 | if (error > error_in_archive) | |
353 | error_in_archive = error; | |
354 | if (error > PK_WARN) { /* fatal: no more left to do */ | |
355 | Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg), | |
356 | FnFilter1(G.filename), "central")); | |
357 | members_remaining = 0; | |
358 | break; | |
359 | } | |
360 | } | |
361 | if ((error = do_string(__G__ G.crec.extra_field_length, | |
362 | EXTRA_FIELD)) != 0) | |
363 | { | |
364 | if (error > error_in_archive) | |
365 | error_in_archive = error; | |
366 | if (error > PK_WARN) { /* fatal */ | |
367 | Info(slide, 0x401, ((char *)slide, | |
368 | LoadFarString(ExtFieldMsg), | |
369 | FnFilter1(G.filename), "central")); | |
370 | members_remaining = 0; | |
371 | break; | |
372 | } | |
373 | } | |
374 | #ifdef AMIGA | |
375 | G.filenote_slot = j; | |
376 | if ((error = do_string(__G__ G.crec.file_comment_length, | |
377 | uO.N_flag ? FILENOTE : SKIP)) != PK_COOL) | |
378 | #else | |
379 | if ((error = do_string(__G__ G.crec.file_comment_length, SKIP)) | |
380 | != PK_COOL) | |
381 | #endif | |
382 | { | |
383 | if (error > error_in_archive) | |
384 | error_in_archive = error; | |
385 | if (error > PK_WARN) { /* fatal */ | |
386 | Info(slide, 0x421, ((char *)slide, | |
387 | LoadFarString(BadFileCommLength), | |
388 | FnFilter1(G.filename))); | |
389 | members_remaining = 0; | |
390 | break; | |
391 | } | |
392 | } | |
393 | if (G.process_all_files) { | |
394 | if (store_info(__G)) | |
395 | ++j; /* file is OK; info[] stored; continue with next */ | |
396 | else | |
397 | ++num_skipped; | |
398 | } else { | |
399 | int do_this_file; | |
400 | ||
401 | if (G.filespecs == 0) | |
402 | do_this_file = TRUE; | |
403 | else { /* check if this entry matches an `include' argument */ | |
404 | do_this_file = FALSE; | |
405 | for (i = 0; i < G.filespecs; i++) | |
406 | if (match(G.filename, G.pfnames[i], uO.C_flag)) { | |
407 | do_this_file = TRUE; /* ^-- ignore case or not? */ | |
408 | if (fn_matched) | |
409 | fn_matched[i] = TRUE; | |
410 | break; /* found match, so stop looping */ | |
411 | } | |
412 | } | |
413 | if (do_this_file) { /* check if this is an excluded file */ | |
414 | for (i = 0; i < G.xfilespecs; i++) | |
415 | if (match(G.filename, G.pxnames[i], uO.C_flag)) { | |
416 | do_this_file = FALSE; /* ^-- ignore case or not? */ | |
417 | if (xn_matched) | |
418 | xn_matched[i] = TRUE; | |
419 | break; | |
420 | } | |
421 | } | |
422 | if (do_this_file) { | |
423 | if (store_info(__G)) | |
424 | ++j; /* file is OK */ | |
425 | else | |
426 | ++num_skipped; /* unsupp. compression or encryption */ | |
427 | } | |
428 | } /* end if (process_all_files) */ | |
429 | ||
430 | ||
431 | } /* end while-loop (adding files to current block) */ | |
432 | ||
433 | /* save position in central directory so can come back later */ | |
434 | cd_bufstart = G.cur_zipfile_bufstart; | |
435 | cd_inptr = G.inptr; | |
436 | cd_incnt = G.incnt; | |
437 | ||
438 | /*----------------------------------------------------------------------- | |
439 | Second loop: process files in current block, extracting or testing | |
440 | each one. | |
441 | -----------------------------------------------------------------------*/ | |
442 | ||
443 | for (i = 0; i < j; ++i) { | |
444 | filnum++; /* filnum = i + blknum*DIR_BLKSIZ + 1; */ | |
445 | G.pInfo = &G.info[i]; | |
446 | #ifdef NOVELL_BUG_FAILSAFE | |
447 | G.dne = FALSE; /* assume file exists until stat() says otherwise */ | |
448 | #endif | |
449 | ||
450 | /* if the target position is not within the current input buffer | |
451 | * (either haven't yet read far enough, or (maybe) skipping back- | |
452 | * ward), skip to the target position and reset readbuf(). */ | |
453 | ||
454 | /* ZLSEEK(pInfo->offset): */ | |
455 | request = G.pInfo->offset + G.extra_bytes; | |
456 | inbuf_offset = request % INBUFSIZ; | |
457 | bufstart = request - inbuf_offset; | |
458 | ||
459 | Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n", | |
460 | request, inbuf_offset)); | |
461 | Trace((stderr, | |
462 | "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n", | |
463 | bufstart, G.cur_zipfile_bufstart)); | |
464 | if (request < 0) { | |
465 | Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg), | |
466 | G.zipfn, LoadFarString(ReportMsg))); | |
467 | error_in_archive = PK_ERR; | |
468 | if (filnum == 1 && G.extra_bytes != 0L) { | |
469 | Info(slide, 0x401, ((char *)slide, | |
470 | LoadFarString(AttemptRecompensate))); | |
471 | old_extra_bytes = G.extra_bytes; | |
472 | G.extra_bytes = 0L; | |
473 | request = G.pInfo->offset; /* could also check if != 0 */ | |
474 | inbuf_offset = request % INBUFSIZ; | |
475 | bufstart = request - inbuf_offset; | |
476 | Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n", | |
477 | request, inbuf_offset)); | |
478 | Trace((stderr, | |
479 | "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n", | |
480 | bufstart, G.cur_zipfile_bufstart)); | |
481 | } else { | |
482 | error_in_archive = PK_BADERR; | |
483 | continue; /* this one hosed; try next */ | |
484 | } | |
485 | } | |
486 | /* try again */ | |
487 | if (request < 0) { | |
488 | Trace((stderr, "debug: recompensated request still < 0\n")); | |
489 | Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg), | |
490 | G.zipfn, LoadFarString(ReportMsg))); | |
491 | error_in_archive = PK_BADERR; | |
492 | continue; | |
493 | } else if (bufstart != G.cur_zipfile_bufstart) { | |
494 | Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n")); | |
495 | #ifdef USE_STRM_INPUT | |
496 | fseek((FILE *)G.zipfd,(LONGINT)bufstart,SEEK_SET); | |
497 | G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd); | |
498 | #else /* !USE_STRM_INPUT */ | |
499 | G.cur_zipfile_bufstart = | |
500 | lseek(G.zipfd,(LONGINT)bufstart,SEEK_SET); | |
501 | #endif /* ?USE_STRM_INPUT */ | |
502 | if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ)) <= 0) | |
503 | { | |
504 | Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), | |
505 | filnum, "lseek", bufstart)); | |
506 | error_in_archive = PK_BADERR; | |
507 | continue; /* can still do next file */ | |
508 | } | |
509 | G.inptr = G.inbuf + (int)inbuf_offset; | |
510 | G.incnt -= (int)inbuf_offset; | |
511 | } else { | |
512 | G.incnt += (int)(G.inptr-G.inbuf) - (int)inbuf_offset; | |
513 | G.inptr = G.inbuf + (int)inbuf_offset; | |
514 | } | |
515 | ||
516 | /* should be in proper position now, so check for sig */ | |
517 | if (readbuf(__G__ G.sig, 4) == 0) { /* bad offset */ | |
518 | Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), | |
519 | filnum, "EOF", request)); | |
520 | error_in_archive = PK_BADERR; | |
521 | continue; /* but can still try next one */ | |
522 | } | |
523 | if (strncmp(G.sig, local_hdr_sig, 4)) { | |
524 | Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), | |
525 | filnum, LoadFarStringSmall(LocalHdrSig), request)); | |
526 | /* | |
527 | GRRDUMP(G.sig, 4) | |
528 | GRRDUMP(local_hdr_sig, 4) | |
529 | */ | |
530 | error_in_archive = PK_ERR; | |
531 | if ((filnum == 1 && G.extra_bytes != 0L) || | |
532 | (G.extra_bytes == 0L && old_extra_bytes != 0L)) { | |
533 | Info(slide, 0x401, ((char *)slide, | |
534 | LoadFarString(AttemptRecompensate))); | |
535 | if (G.extra_bytes) { | |
536 | old_extra_bytes = G.extra_bytes; | |
537 | G.extra_bytes = 0L; | |
538 | } else | |
539 | G.extra_bytes = old_extra_bytes; /* third attempt */ | |
540 | ZLSEEK(G.pInfo->offset) | |
541 | if (readbuf(__G__ G.sig, 4) == 0) { /* bad offset */ | |
542 | Info(slide, 0x401, ((char *)slide, | |
543 | LoadFarString(OffsetMsg), filnum, "EOF", request)); | |
544 | error_in_archive = PK_BADERR; | |
545 | continue; /* but can still try next one */ | |
546 | } | |
547 | if (strncmp(G.sig, local_hdr_sig, 4)) { | |
548 | Info(slide, 0x401, ((char *)slide, | |
549 | LoadFarString(OffsetMsg), filnum, | |
550 | LoadFarStringSmall(LocalHdrSig), request)); | |
551 | error_in_archive = PK_BADERR; | |
552 | continue; | |
553 | } | |
554 | } else | |
555 | continue; /* this one hosed; try next */ | |
556 | } | |
557 | if ((error = process_local_file_hdr(__G)) != PK_COOL) { | |
558 | Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr), | |
559 | filnum)); | |
560 | error_in_archive = error; /* only PK_EOF defined */ | |
561 | continue; /* can still try next one */ | |
562 | } | |
563 | if ((error = do_string(__G__ G.lrec.filename_length, DS_FN)) != | |
564 | PK_COOL) | |
565 | { | |
566 | if (error > error_in_archive) | |
567 | error_in_archive = error; | |
568 | if (error > PK_WARN) { | |
569 | Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg), | |
570 | FnFilter1(G.filename), "local")); | |
571 | continue; /* go on to next one */ | |
572 | } | |
573 | } | |
574 | if (G.extra_field != (uch *)NULL) { | |
575 | free(G.extra_field); | |
576 | G.extra_field = (uch *)NULL; | |
577 | } | |
578 | if ((error = | |
579 | do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0) | |
580 | { | |
581 | if (error > error_in_archive) | |
582 | error_in_archive = error; | |
583 | if (error > PK_WARN) { | |
584 | Info(slide, 0x401, ((char *)slide, | |
585 | LoadFarString(ExtFieldMsg), | |
586 | FnFilter1(G.filename), "local")); | |
587 | continue; /* go on */ | |
588 | } | |
589 | } | |
590 | ||
591 | #if CRYPT | |
592 | if (G.pInfo->encrypted && | |
593 | (error = decrypt(__G__ uO.pwdarg)) != PK_COOL) { | |
594 | if (error == PK_WARN) { | |
595 | if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) | |
596 | Info(slide, 0x401, ((char *)slide, | |
597 | LoadFarString(SkipIncorrectPasswd), | |
598 | FnFilter1(G.filename))); | |
599 | ++num_bad_pwd; | |
600 | } else { /* (error > PK_WARN) */ | |
601 | if (error > error_in_archive) | |
602 | error_in_archive = error; | |
603 | Info(slide, 0x401, ((char *)slide, | |
604 | LoadFarString(SkipCannotGetPasswd), | |
605 | FnFilter1(G.filename))); | |
606 | } | |
607 | continue; /* go on to next file */ | |
608 | } | |
609 | #endif /* CRYPT */ | |
610 | ||
611 | /* | |
612 | * just about to extract file: if extracting to disk, check if | |
613 | * already exists, and if so, take appropriate action according to | |
614 | * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper | |
615 | * loop because we don't store the possibly renamed filename[] in | |
616 | * info[]) | |
617 | */ | |
618 | #ifdef DLL | |
619 | if (!uO.tflag && !uO.cflag && !G.redirect_data) | |
620 | #else | |
621 | if (!uO.tflag && !uO.cflag) | |
622 | #endif | |
623 | { | |
624 | renamed = FALSE; /* user hasn't renamed output file yet */ | |
625 | ||
626 | startover: | |
627 | query = FALSE; | |
628 | /* for files from DOS FAT, check for use of backslash instead | |
629 | * of slash as directory separator (bug in some zipper(s); so | |
630 | * far, not a problem in HPFS, NTFS or VFAT systems) | |
631 | */ | |
632 | #ifndef SFX | |
633 | if (G.pInfo->hostnum == FS_FAT_ && !strchr(G.filename, '/')) { | |
634 | char *p=G.filename-1; | |
635 | ||
636 | while (*++p) { | |
637 | if (*p == '\\') { | |
638 | if (!G.reported_backslash) { | |
639 | Info(slide, 0x21, ((char *)slide, | |
640 | LoadFarString(BackslashPathSep), G.zipfn)); | |
641 | G.reported_backslash = TRUE; | |
642 | if (!error_in_archive) | |
643 | error_in_archive = PK_WARN; | |
644 | } | |
645 | *p = '/'; | |
646 | } | |
647 | } | |
648 | } | |
649 | #endif /* !SFX */ | |
650 | ||
651 | /* mapname can create dirs if not freshening or if renamed */ | |
652 | if ((error = mapname(__G__ renamed)) > PK_WARN) { | |
653 | if (error == IZ_CREATED_DIR) { | |
654 | #ifdef SET_DIR_ATTRIB | |
655 | dirtime *d_entry; | |
656 | ||
657 | d_entry = (dirtime *)malloc(sizeof(dirtime)); | |
658 | if (d_entry == (dirtime *)NULL) { | |
659 | Info(slide, 0x401, ((char *)slide, | |
660 | LoadFarString(DirlistEntryNoMem))); | |
661 | } else { | |
662 | unsigned eb_izux_flg; | |
663 | ||
664 | d_entry->next = dirlist; | |
665 | dirlist = d_entry; | |
666 | dirlist->fn = | |
667 | (char *)malloc(strlen(G.filename) + 1); | |
668 | if (dirlist->fn == (char *)NULL) { | |
669 | Info(slide, 0x401, ((char *)slide, | |
670 | LoadFarString(DirlistEntryNoMem))); | |
671 | dirlist = d_entry->next; | |
672 | free(d_entry); | |
673 | if (!error_in_archive) | |
674 | error_in_archive = PK_WARN; | |
675 | continue; | |
676 | } | |
677 | strcpy(dirlist->fn, G.filename); | |
678 | dirlist->perms = G.pInfo->file_attr; | |
679 | #ifdef USE_EF_UT_TIME | |
680 | eb_izux_flg = G.extra_field? ef_scan_for_izux( | |
681 | G.extra_field, G.lrec.extra_field_length, 0, | |
682 | G.lrec.last_mod_dos_datetime, | |
683 | #ifdef IZ_CHECK_TZ | |
684 | (G.tz_is_valid ? &(dirlist->u.t3) : NULL), | |
685 | #else | |
686 | &(dirlist->u.t3), | |
687 | #endif | |
688 | dirlist->uidgid) | |
689 | : 0; | |
690 | #else /* !USE_EF_UT_TIME */ | |
691 | eb_izux_flg = 0; | |
692 | #endif /* ?USE_EF_UT_TIME */ | |
693 | if (eb_izux_flg & EB_UT_FL_MTIME) { | |
694 | TTrace((stderr, | |
695 | "\nextract: Unix dir e.f. modtime = %ld\n", | |
696 | dirlist->u.t3.mtime)); | |
697 | } else { | |
698 | dirlist->u.t3.mtime = dos_to_unix_time( | |
699 | G.lrec.last_mod_dos_datetime); | |
700 | } | |
701 | if (eb_izux_flg & EB_UT_FL_ATIME) { | |
702 | TTrace((stderr, | |
703 | "\nextract: Unix dir e.f. actime = %ld\n", | |
704 | dirlist->u.t3.atime)); | |
705 | } else { | |
706 | dirlist->u.t3.atime = | |
707 | dirlist->u.t3.mtime; | |
708 | } | |
709 | dirlist->have_uidgid = | |
710 | (uO.X_flag && (eb_izux_flg & EB_UX2_VALID)); | |
711 | ++num_dirs; | |
712 | } | |
713 | #endif /* SET_DIR_ATTRIB */ | |
714 | } else if (error == IZ_VOL_LABEL) { | |
715 | #ifdef DOS_OS2_W32 | |
716 | Info(slide, 0x401, ((char *)slide, | |
717 | LoadFarString(SkipVolumeLabel), | |
718 | FnFilter1(G.filename), | |
719 | uO.volflag? "hard disk " : "")); | |
720 | #else | |
721 | Info(slide, 1, ((char *)slide, | |
722 | LoadFarString(SkipVolumeLabel), | |
723 | FnFilter1(G.filename), "")); | |
724 | #endif | |
725 | /* if (!error_in_archive) | |
726 | error_in_archive = PK_WARN; */ | |
727 | } else if (error > PK_ERR && error_in_archive < PK_ERR) | |
728 | error_in_archive = PK_ERR; | |
729 | Trace((stderr, "mapname(%s) returns error = %d\n", | |
730 | FnFilter1(G.filename), error)); | |
731 | continue; /* go on to next file */ | |
732 | } | |
733 | ||
734 | #ifdef QDOS | |
735 | QFilename(__G__ G.filename); | |
736 | #endif | |
737 | switch (check_for_newer(__G__ G.filename)) { | |
738 | case DOES_NOT_EXIST: | |
739 | #ifdef NOVELL_BUG_FAILSAFE | |
740 | G.dne = TRUE; /* stat() says file DOES NOT EXIST */ | |
741 | #endif | |
742 | /* if freshening, don't skip if just renamed */ | |
743 | if (uO.fflag && !renamed) | |
744 | continue; /* freshen (no new files): skip */ | |
745 | break; | |
746 | case EXISTS_AND_OLDER: | |
747 | if (uO.overwrite_none) { | |
748 | #ifdef WINDLL | |
749 | char szStr[FILNAMSIZ+40]; /* add. space for text */ | |
750 | ||
751 | if ((!G.prompt_always) || (done_once)) { | |
752 | sprintf(szStr, | |
753 | "Target file exists.\nSkipping %s\n", | |
754 | FnFilter1(G.filename)); | |
755 | win_fprintf((zvoid *)&G, stdout, | |
756 | strlen(szStr), szStr); | |
757 | } else { | |
758 | query = TRUE; | |
759 | break; | |
760 | } | |
761 | #endif /* WINDLL */ | |
762 | continue; /* never overwrite: skip file */ | |
763 | } | |
764 | #ifdef UNIXBACKUP | |
765 | if (!uO.overwrite_all && !uO.B_flag) | |
766 | #else | |
767 | if (!uO.overwrite_all) | |
768 | #endif | |
769 | query = TRUE; | |
770 | break; | |
771 | case EXISTS_AND_NEWER: /* (or equal) */ | |
772 | if (uO.overwrite_none || (uO.uflag && !renamed)) { | |
773 | #ifdef WINDLL | |
774 | char szStr[FILNAMSIZ+40]; /* add. space for text */ | |
775 | ||
776 | if ((!G.prompt_always) || (done_once)) { | |
777 | sprintf(szStr, | |
778 | "Target file newer.\nSkipping %s\n", | |
779 | FnFilter1(G.filename)); | |
780 | win_fprintf((zvoid *)&G, stdout, | |
781 | strlen(szStr), szStr); | |
782 | } else { | |
783 | query = TRUE; | |
784 | break; | |
785 | } | |
786 | #endif /* WINDLL */ | |
787 | continue; /* skip if update/freshen & orig name */ | |
788 | } | |
789 | #ifdef UNIXBACKUP | |
790 | if (!uO.overwrite_all && !uO.B_flag) | |
791 | #else | |
792 | if (!uO.overwrite_all) | |
793 | #endif | |
794 | query = TRUE; | |
795 | break; | |
796 | } | |
797 | if (query) { | |
798 | #ifdef WINDLL | |
799 | switch (G.lpUserFunctions->replace != NULL ? | |
800 | (*G.lpUserFunctions->replace)(G.filename) : | |
801 | IDM_REPLACE_NONE) { | |
802 | case IDM_REPLACE_RENAME: | |
803 | _ISO_INTERN(G.filename); | |
804 | renamed = TRUE; | |
805 | goto startover; | |
806 | case IDM_REPLACE_YES: | |
807 | break; | |
808 | case IDM_REPLACE_ALL: | |
809 | uO.overwrite_all = TRUE; | |
810 | uO.overwrite_none = FALSE; /* just to make sure */ | |
811 | break; | |
812 | case IDM_REPLACE_NONE: | |
813 | uO.overwrite_none = TRUE; | |
814 | uO.overwrite_all = FALSE; /* make sure */ | |
815 | done_once = TRUE; | |
816 | /* FALL THROUGH, skip */ | |
817 | case IDM_REPLACE_NO: | |
818 | { | |
819 | char szStr[FILNAMSIZ+40]; | |
820 | ||
821 | sprintf(szStr, | |
822 | "Target file newer.\nSkipping %s\n", | |
823 | FnFilter1(G.filename)); | |
824 | win_fprintf((zvoid *)&G, stdout, | |
825 | strlen(szStr), szStr); | |
826 | } | |
827 | continue; | |
828 | } | |
829 | #else /* !WINDLL */ | |
830 | reprompt: | |
831 | Info(slide, 0x81, ((char *)slide, | |
832 | LoadFarString(ReplaceQuery), | |
833 | FnFilter1(G.filename))); | |
834 | if (fgets(G.answerbuf, 9, stdin) == (char *)NULL) { | |
835 | Info(slide, 1, ((char *)slide, | |
836 | LoadFarString(AssumeNone))); | |
837 | *G.answerbuf = 'N'; | |
838 | if (!error_in_archive) | |
839 | error_in_archive = 1; /* not extracted: warning */ | |
840 | } | |
841 | switch (*G.answerbuf) { | |
842 | case 'A': /* dangerous option: force caps */ | |
843 | uO.overwrite_all = TRUE; | |
844 | uO.overwrite_none = FALSE; /* just to make sure */ | |
845 | break; | |
846 | case 'r': | |
847 | case 'R': | |
848 | do { | |
849 | Info(slide, 0x81, ((char *)slide, | |
850 | LoadFarString(NewNameQuery))); | |
851 | fgets(G.filename, FILNAMSIZ, stdin); | |
852 | /* usually get \n here: better check for it */ | |
853 | len = strlen(G.filename); | |
854 | if (G.filename[len-1] == '\n') | |
855 | G.filename[--len] = '\0'; | |
856 | } while (len == 0); | |
857 | #ifdef WIN32 /* WIN32 fgets( ... , stdin) returns OEM coded strings */ | |
858 | _OEM_INTERN(G.filename); | |
859 | #endif | |
860 | renamed = TRUE; | |
861 | goto startover; /* sorry for a goto */ | |
862 | case 'y': | |
863 | case 'Y': | |
864 | break; | |
865 | case 'N': | |
866 | uO.overwrite_none = TRUE; | |
867 | uO.overwrite_all = FALSE; /* make sure */ | |
868 | /* FALL THROUGH, skip */ | |
869 | case 'n': | |
870 | continue; /* skip file */ | |
871 | default: | |
872 | Info(slide, 1, ((char *)slide, | |
873 | LoadFarString(InvalidResponse), *G.answerbuf)); | |
874 | goto reprompt; /* yet another goto? */ | |
875 | } /* end switch (*answerbuf) */ | |
876 | #endif /* ?WINDLL */ | |
877 | } /* end if (query) */ | |
878 | } /* end if (extracting to disk) */ | |
879 | ||
880 | #ifdef DLL | |
881 | if ((G.statreportcb != NULL) && | |
882 | (*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn, | |
883 | G.filename, NULL)) { | |
884 | if (fn_matched) | |
885 | free((zvoid *)fn_matched); | |
886 | if (xn_matched) | |
887 | free((zvoid *)xn_matched); | |
888 | return IZ_CTRLC; /* cancel operation by user request */ | |
889 | } | |
890 | #endif | |
891 | #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */ | |
892 | UserStop(); | |
893 | #endif | |
894 | #ifdef AMIGA | |
895 | G.filenote_slot = i; | |
896 | #endif | |
897 | G.disk_full = 0; | |
898 | if ((error = extract_or_test_member(__G)) != PK_COOL) { | |
899 | if (error > error_in_archive) | |
900 | error_in_archive = error; /* ...and keep going */ | |
901 | #ifdef DLL | |
902 | if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) { | |
903 | #else | |
904 | if (G.disk_full > 1) { | |
905 | #endif | |
906 | if (fn_matched) | |
907 | free((zvoid *)fn_matched); | |
908 | if (xn_matched) | |
909 | free((zvoid *)xn_matched); | |
910 | return error_in_archive; /* (unless disk full) */ | |
911 | } | |
912 | } | |
913 | #ifdef DLL | |
914 | if ((G.statreportcb != NULL) && | |
915 | (*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn, | |
916 | G.filename, (zvoid *)&G.lrec.ucsize)) { | |
917 | if (fn_matched) | |
918 | free((zvoid *)fn_matched); | |
919 | if (xn_matched) | |
920 | free((zvoid *)xn_matched); | |
921 | return IZ_CTRLC; /* cancel operation by user request */ | |
922 | } | |
923 | #endif | |
924 | #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */ | |
925 | UserStop(); | |
926 | #endif | |
927 | } /* end for-loop (i: files in current block) */ | |
928 | ||
929 | ||
930 | /* | |
931 | * Jump back to where we were in the central directory, then go and do | |
932 | * the next batch of files. | |
933 | */ | |
934 | ||
935 | #ifdef USE_STRM_INPUT | |
936 | fseek((FILE *)G.zipfd, (LONGINT)cd_bufstart, SEEK_SET); | |
937 | G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd); | |
938 | #else /* !USE_STRM_INPUT */ | |
939 | G.cur_zipfile_bufstart = lseek(G.zipfd,(LONGINT)cd_bufstart,SEEK_SET); | |
940 | #endif /* ?USE_STRM_INPUT */ | |
941 | read(G.zipfd, (char *)G.inbuf, INBUFSIZ); /* been here before... */ | |
942 | G.inptr = cd_inptr; | |
943 | G.incnt = cd_incnt; | |
944 | ++blknum; | |
945 | ||
946 | #ifdef TEST | |
947 | pipeit("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart); | |
948 | pipeit("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart, | |
949 | cur_zipfile_bufstart); | |
950 | pipeit("inptr-inbuf = %d\n", G.inptr-G.inbuf); | |
951 | pipeit("incnt = %d\n\n", G.incnt); | |
952 | #endif | |
953 | ||
954 | } /* end while-loop (blocks of files in central directory) */ | |
955 | ||
956 | /*--------------------------------------------------------------------------- | |
957 | Go back through saved list of directories, sort and set times/perms/UIDs | |
958 | and GIDs from the deepest level on up. | |
959 | ---------------------------------------------------------------------------*/ | |
960 | ||
961 | #ifdef SET_DIR_ATTRIB | |
962 | if (num_dirs > 0) { | |
963 | sorted_dirlist = (dirtime **)malloc(num_dirs*sizeof(dirtime *)); | |
964 | if (sorted_dirlist == (dirtime **)NULL) { | |
965 | Info(slide, 0x401, ((char *)slide, | |
966 | LoadFarString(DirlistSortNoMem))); | |
967 | while (dirlist != (dirtime *)NULL) { | |
968 | dirtime *d = dirlist; | |
969 | ||
970 | dirlist = dirlist->next; | |
971 | free(d); | |
972 | } | |
973 | } else { | |
974 | if (num_dirs == 1) | |
975 | sorted_dirlist[0] = dirlist; | |
976 | else { | |
977 | for (i = 0; i < num_dirs; ++i) { | |
978 | sorted_dirlist[i] = dirlist; | |
979 | dirlist = dirlist->next; | |
980 | } | |
981 | qsort((char *)sorted_dirlist, num_dirs, sizeof(dirtime *), | |
982 | dircomp); | |
983 | } | |
984 | ||
985 | Trace((stderr, "setting directory times/perms/attributes\n")); | |
986 | for (i = 0; i < num_dirs; ++i) { | |
987 | dirtime *d = sorted_dirlist[i]; | |
988 | ||
989 | Trace((stderr, "dir = %s\n", d->fn)); | |
990 | if ((error = set_direc_attribs(__G__ d)) != PK_OK) { | |
991 | Info(slide, 0x201, ((char *)slide, | |
992 | LoadFarString(DirlistSetAttrFailed), d->fn)); | |
993 | if (!error_in_archive) | |
994 | error_in_archive = error; | |
995 | } | |
996 | free(d->fn); | |
997 | free(d); | |
998 | } | |
999 | free(sorted_dirlist); | |
1000 | } | |
1001 | } | |
1002 | #endif /* SET_DIR_ATTRIB */ | |
1003 | ||
1004 | #if (defined(WIN32) && defined(NTSD_EAS)) | |
1005 | process_defer_NT(__G); /* process any deferred items for this .zip file */ | |
1006 | #endif | |
1007 | ||
1008 | /*--------------------------------------------------------------------------- | |
1009 | Check for unmatched filespecs on command line and print warning if any | |
1010 | found. Free allocated memory. | |
1011 | ---------------------------------------------------------------------------*/ | |
1012 | ||
1013 | if (fn_matched) { | |
1014 | for (i = 0; i < G.filespecs; ++i) | |
1015 | if (!fn_matched[i]) { | |
1016 | #ifdef DLL | |
1017 | if (!G.redirect_data && !G.redirect_text) | |
1018 | Info(slide, 0x401, ((char *)slide, | |
1019 | LoadFarString(FilenameNotMatched), G.pfnames[i])); | |
1020 | else | |
1021 | setFileNotFound(__G); | |
1022 | #else | |
1023 | Info(slide, 1, ((char *)slide, | |
1024 | LoadFarString(FilenameNotMatched), G.pfnames[i])); | |
1025 | #endif | |
1026 | if (error_in_archive <= PK_WARN) | |
1027 | error_in_archive = PK_FIND; /* some files not found */ | |
1028 | } | |
1029 | free((zvoid *)fn_matched); | |
1030 | } | |
1031 | if (xn_matched) { | |
1032 | for (i = 0; i < G.xfilespecs; ++i) | |
1033 | if (!xn_matched[i]) | |
1034 | Info(slide, 0x401, ((char *)slide, | |
1035 | LoadFarString(ExclFilenameNotMatched), G.pxnames[i])); | |
1036 | free((zvoid *)xn_matched); | |
1037 | } | |
1038 | ||
1039 | /*--------------------------------------------------------------------------- | |
1040 | Double-check that we're back at the end-of-central-directory record, and | |
1041 | print quick summary of results, if we were just testing the archive. We | |
1042 | send the summary to stdout so that people doing the testing in the back- | |
1043 | ground and redirecting to a file can just do a "tail" on the output file. | |
1044 | ---------------------------------------------------------------------------*/ | |
1045 | ||
1046 | #ifndef SFX | |
1047 | if (readbuf(__G__ G.sig, 4) == 0) | |
1048 | error_in_archive = PK_EOF; | |
1049 | if (strncmp(G.sig, end_central_sig, 4)) { /* just to make sure */ | |
1050 | Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg))); | |
1051 | Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg))); | |
1052 | if (!error_in_archive) /* don't overwrite stronger error */ | |
1053 | error_in_archive = PK_WARN; | |
1054 | } | |
1055 | #endif /* !SFX */ | |
1056 | if (uO.tflag) { | |
1057 | unsigned num = filnum - num_bad_pwd; | |
1058 | ||
1059 | if (uO.qflag < 2) { /* GRR 930710: was (uO.qflag == 1) */ | |
1060 | if (error_in_archive) | |
1061 | Info(slide, 0, ((char *)slide, LoadFarString(ErrorInArchive), | |
1062 | (error_in_archive == 1)? "warning-" : "", G.zipfn)); | |
1063 | else if (num == 0) | |
1064 | Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested), | |
1065 | G.zipfn)); | |
1066 | else if (G.process_all_files && (num_skipped+num_bad_pwd == 0)) | |
1067 | Info(slide, 0, ((char *)slide, LoadFarString(NoErrInCompData), | |
1068 | G.zipfn)); | |
1069 | else | |
1070 | Info(slide, 0, ((char *)slide, LoadFarString(NoErrInTestedFiles) | |
1071 | , G.zipfn, num, (num==1)? "":"s")); | |
1072 | if (num_skipped > 0) | |
1073 | Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipped), | |
1074 | num_skipped, (num_skipped==1)? "":"s")); | |
1075 | #if CRYPT | |
1076 | if (num_bad_pwd > 0) | |
1077 | Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipBadPasswd) | |
1078 | , num_bad_pwd, (num_bad_pwd==1)? "":"s")); | |
1079 | #endif /* CRYPT */ | |
1080 | } else if ((uO.qflag == 0) && !error_in_archive && (num == 0)) | |
1081 | Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested), | |
1082 | G.zipfn)); | |
1083 | } | |
1084 | ||
1085 | /* give warning if files not tested or extracted (first condition can still | |
1086 | * happen if zipfile is empty and no files specified on command line) */ | |
1087 | ||
1088 | if ((filnum == 0) && error_in_archive <= PK_WARN) { | |
1089 | if (num_skipped > 0) | |
1090 | error_in_archive = IZ_UNSUP; /* unsupport. compression/encryption */ | |
1091 | else | |
1092 | error_in_archive = PK_FIND; /* no files found at all */ | |
1093 | } | |
1094 | #if CRYPT | |
1095 | else if ((filnum == num_bad_pwd) && error_in_archive <= PK_WARN) | |
1096 | error_in_archive = IZ_BADPWD; /* bad passwd => all files skipped */ | |
1097 | #endif | |
1098 | else if ((num_skipped > 0) && error_in_archive <= PK_WARN) | |
1099 | error_in_archive = IZ_UNSUP; /* was PK_WARN; Jean-loup complained */ | |
1100 | #if CRYPT | |
1101 | else if ((num_bad_pwd > 0) && !error_in_archive) | |
1102 | error_in_archive = PK_WARN; | |
1103 | #endif | |
1104 | ||
1105 | return error_in_archive; | |
1106 | ||
1107 | } /* end function extract_or_test_files() */ | |
1108 | ||
1109 | ||
1110 | ||
1111 | ||
1112 | ||
1113 | /***************************/ | |
1114 | /* Function store_info() */ | |
1115 | /***************************/ | |
1116 | ||
1117 | static int store_info(__G) /* return 0 if skipping, 1 if OK */ | |
1118 | __GDEF | |
1119 | { | |
1120 | #ifdef SFX | |
1121 | # define UNKN_COMPR \ | |
1122 | (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED) | |
1123 | #else | |
1124 | # ifdef COPYRIGHT_CLEAN /* no reduced files */ | |
1125 | # define UNKN_RED (G.crec.compression_method >= REDUCED1 && \ | |
1126 | G.crec.compression_method <= REDUCED4) | |
1127 | # else | |
1128 | # define UNKN_RED FALSE /* reducing not unknown */ | |
1129 | # endif | |
1130 | # ifdef LZW_CLEAN /* no shrunk files */ | |
1131 | # define UNKN_SHR (G.crec.compression_method == SHRUNK) | |
1132 | # else | |
1133 | # define UNKN_SHR FALSE /* unshrinking not unknown */ | |
1134 | # endif | |
1135 | # define UNKN_COMPR (UNKN_RED || UNKN_SHR || \ | |
1136 | G.crec.compression_method==TOKENIZED || G.crec.compression_method>DEFLATED) | |
1137 | #endif | |
1138 | ||
1139 | /*--------------------------------------------------------------------------- | |
1140 | Check central directory info for version/compatibility requirements. | |
1141 | ---------------------------------------------------------------------------*/ | |
1142 | ||
1143 | G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1; /* bit field */ | |
1144 | G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8; /* bit */ | |
1145 | G.pInfo->textfile = G.crec.internal_file_attributes & 1; /* bit field */ | |
1146 | G.pInfo->crc = G.crec.crc32; | |
1147 | G.pInfo->compr_size = G.crec.csize; | |
1148 | G.pInfo->uncompr_size = G.crec.ucsize; | |
1149 | ||
1150 | switch (uO.aflag) { | |
1151 | case 0: | |
1152 | G.pInfo->textmode = FALSE; /* bit field */ | |
1153 | break; | |
1154 | case 1: | |
1155 | G.pInfo->textmode = G.pInfo->textfile; /* auto-convert mode */ | |
1156 | break; | |
1157 | default: /* case 2: */ | |
1158 | G.pInfo->textmode = TRUE; | |
1159 | break; | |
1160 | } | |
1161 | ||
1162 | if (G.crec.version_needed_to_extract[1] == VMS_) { | |
1163 | if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) { | |
1164 | if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) | |
1165 | Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg), | |
1166 | FnFilter1(G.filename), "VMS", | |
1167 | G.crec.version_needed_to_extract[0] / 10, | |
1168 | G.crec.version_needed_to_extract[0] % 10, | |
1169 | VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10)); | |
1170 | return 0; | |
1171 | } | |
1172 | #ifndef VMS /* won't be able to use extra field, but still have data */ | |
1173 | else if (!uO.tflag && !uO.overwrite_all) { /* if -o, extract anyway */ | |
1174 | Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery), | |
1175 | FnFilter1(G.filename))); | |
1176 | fgets(G.answerbuf, 9, stdin); | |
1177 | if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y')) | |
1178 | return 0; | |
1179 | } | |
1180 | #endif /* !VMS */ | |
1181 | /* usual file type: don't need VMS to extract */ | |
1182 | } else if (G.crec.version_needed_to_extract[0] > UNZIP_VERSION) { | |
1183 | if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) | |
1184 | Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg), | |
1185 | FnFilter1(G.filename), "PK", | |
1186 | G.crec.version_needed_to_extract[0] / 10, | |
1187 | G.crec.version_needed_to_extract[0] % 10, | |
1188 | UNZIP_VERSION / 10, UNZIP_VERSION % 10)); | |
1189 | return 0; | |
1190 | } | |
1191 | ||
1192 | if UNKN_COMPR { | |
1193 | if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) { | |
1194 | #ifndef SFX | |
1195 | if (G.crec.compression_method < NUM_METHODS) | |
1196 | Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName), | |
1197 | FnFilter1(G.filename), | |
1198 | LoadFarStringSmall(ComprNames[G.crec.compression_method]))); | |
1199 | else | |
1200 | #endif | |
1201 | Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum), | |
1202 | FnFilter1(G.filename), | |
1203 | G.crec.compression_method)); | |
1204 | } | |
1205 | return 0; | |
1206 | } | |
1207 | #if (!CRYPT) | |
1208 | if (G.pInfo->encrypted) { | |
1209 | if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) | |
1210 | Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted), | |
1211 | FnFilter1(G.filename))); | |
1212 | return 0; | |
1213 | } | |
1214 | #endif /* !CRYPT */ | |
1215 | ||
1216 | /* map whatever file attributes we have into the local format */ | |
1217 | mapattr(__G); /* GRR: worry about return value later */ | |
1218 | ||
1219 | G.pInfo->offset = (long)G.crec.relative_offset_local_header; | |
1220 | return 1; | |
1221 | ||
1222 | } /* end function store_info() */ | |
1223 | ||
1224 | ||
1225 | ||
1226 | ||
1227 | ||
1228 | /***************************************/ | |
1229 | /* Function extract_or_test_member() */ | |
1230 | /***************************************/ | |
1231 | ||
1232 | static int extract_or_test_member(__G) /* return PK-type error code */ | |
1233 | __GDEF | |
1234 | { | |
1235 | char *nul="[empty] ", *txt="[text] ", *bin="[binary]"; | |
1236 | #ifdef CMS_MVS | |
1237 | char *ebc="[ebcdic]"; | |
1238 | #endif | |
1239 | register int b; | |
1240 | int r, error=PK_COOL; | |
1241 | #if (defined(DLL) && !defined(NO_SLIDE_REDIR)) | |
1242 | ulg wsize; | |
1243 | #else | |
1244 | # define wsize WSIZE | |
1245 | #endif | |
1246 | ||
1247 | ||
1248 | /*--------------------------------------------------------------------------- | |
1249 | Initialize variables, buffers, etc. | |
1250 | ---------------------------------------------------------------------------*/ | |
1251 | ||
1252 | G.bits_left = 0; | |
1253 | G.bitbuf = 0L; /* unreduce and unshrink only */ | |
1254 | G.zipeof = 0; | |
1255 | G.newfile = TRUE; | |
1256 | G.crc32val = CRCVAL_INITIAL; | |
1257 | ||
1258 | #ifdef SYMLINKS | |
1259 | /* if file came from Unix and is a symbolic link and we are extracting | |
1260 | * to disk, prepare to restore the link */ | |
1261 | if (S_ISLNK(G.pInfo->file_attr) && | |
1262 | (G.pInfo->hostnum == UNIX_ || G.pInfo->hostnum == ATARI_ || | |
1263 | G.pInfo->hostnum == BEOS_) && | |
1264 | !uO.tflag && !uO.cflag && (G.lrec.ucsize > 0)) | |
1265 | G.symlnk = TRUE; | |
1266 | else | |
1267 | G.symlnk = FALSE; | |
1268 | #endif /* SYMLINKS */ | |
1269 | ||
1270 | if (uO.tflag) { | |
1271 | if (!uO.qflag) | |
1272 | Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), "test", | |
1273 | FnFilter1(G.filename), "", "")); | |
1274 | } else { | |
1275 | #ifdef DLL | |
1276 | if (uO.cflag && !G.redirect_data) | |
1277 | #else | |
1278 | if (uO.cflag) | |
1279 | #endif | |
1280 | { | |
1281 | #if (defined(OS2) && defined(__IBMC__) && (__IBMC__ >= 200)) | |
1282 | G.outfile = freopen("", "wb", stdout); /* VAC++ ignores setmode */ | |
1283 | #else | |
1284 | G.outfile = stdout; | |
1285 | #endif | |
1286 | #ifdef DOS_FLX_H68_OS2_W32 | |
1287 | #if (defined(__HIGHC__) && !defined(FLEXOS)) | |
1288 | setmode(G.outfile, _BINARY); | |
1289 | #else /* !(defined(__HIGHC__) && !defined(FLEXOS)) */ | |
1290 | setmode(fileno(G.outfile), O_BINARY); | |
1291 | #endif /* ?(defined(__HIGHC__) && !defined(FLEXOS)) */ | |
1292 | # define NEWLINE "\r\n" | |
1293 | #else /* !DOS_FLX_H68_OS2_W32 */ | |
1294 | # define NEWLINE "\n" | |
1295 | #endif /* ?DOS_FLX_H68_OS2_W32 */ | |
1296 | #ifdef VMS | |
1297 | if (open_outfile(__G)) /* VMS: required even for stdout! */ | |
1298 | return PK_DISK; | |
1299 | #endif | |
1300 | } else if (open_outfile(__G)) | |
1301 | return PK_DISK; | |
1302 | } | |
1303 | ||
1304 | /*--------------------------------------------------------------------------- | |
1305 | Unpack the file. | |
1306 | ---------------------------------------------------------------------------*/ | |
1307 | ||
1308 | defer_leftover_input(__G); /* so NEXTBYTE bounds check will work */ | |
1309 | switch (G.lrec.compression_method) { | |
1310 | case STORED: | |
1311 | if (!uO.tflag && QCOND2) { | |
1312 | #ifdef SYMLINKS | |
1313 | if (G.symlnk) /* can also be deflated, but rarer... */ | |
1314 | Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), | |
1315 | "link", FnFilter1(G.filename), "", "")); | |
1316 | else | |
1317 | #endif /* SYMLINKS */ | |
1318 | Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), | |
1319 | "extract", FnFilter1(G.filename), | |
1320 | (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? | |
1321 | "" : (G.lrec.ucsize == 0L? nul : (G.pInfo->textfile? txt : | |
1322 | bin)), uO.cflag? NEWLINE : "")); | |
1323 | } | |
1324 | #if (defined(DLL) && !defined(NO_SLIDE_REDIR)) | |
1325 | if (G.redirect_slide) { | |
1326 | wsize = G.redirect_size; redirSlide = G.redirect_buffer; | |
1327 | } else { | |
1328 | wsize = WSIZE; redirSlide = slide; | |
1329 | } | |
1330 | #endif | |
1331 | G.outptr = redirSlide; | |
1332 | G.outcnt = 0L; | |
1333 | while ((b = NEXTBYTE) != EOF && !G.disk_full) { | |
1334 | *G.outptr++ = (uch)b; | |
1335 | if (++G.outcnt == wsize) { | |
1336 | flush(__G__ redirSlide, G.outcnt, 0); | |
1337 | G.outptr = redirSlide; | |
1338 | G.outcnt = 0L; | |
1339 | } | |
1340 | } | |
1341 | if (G.outcnt) /* flush final (partial) buffer */ | |
1342 | flush(__G__ redirSlide, G.outcnt, 0); | |
1343 | break; | |
1344 | ||
1345 | #ifndef SFX | |
1346 | #ifndef LZW_CLEAN | |
1347 | case SHRUNK: | |
1348 | if (!uO.tflag && QCOND2) { | |
1349 | Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), | |
1350 | LoadFarStringSmall(Unshrink), FnFilter1(G.filename), | |
1351 | (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? | |
1352 | "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); | |
1353 | } | |
1354 | if ((r = unshrink(__G)) != PK_COOL) { | |
1355 | if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) | |
1356 | Info(slide, 0x401, ((char *)slide, | |
1357 | LoadFarStringSmall(ErrUnzipFile), | |
1358 | LoadFarString(NotEnoughMem), | |
1359 | LoadFarStringSmall2(Unshrink), | |
1360 | FnFilter1(G.filename))); | |
1361 | else | |
1362 | Info(slide, 0x401, ((char *)slide, | |
1363 | LoadFarStringSmall(ErrUnzipNoFile), | |
1364 | LoadFarString(NotEnoughMem), | |
1365 | LoadFarStringSmall2(Unshrink))); | |
1366 | error = r; | |
1367 | } | |
1368 | break; | |
1369 | #endif /* !LZW_CLEAN */ | |
1370 | ||
1371 | #ifndef COPYRIGHT_CLEAN | |
1372 | case REDUCED1: | |
1373 | case REDUCED2: | |
1374 | case REDUCED3: | |
1375 | case REDUCED4: | |
1376 | if (!uO.tflag && QCOND2) { | |
1377 | Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), | |
1378 | "unreduc", FnFilter1(G.filename), | |
1379 | (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? | |
1380 | "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); | |
1381 | } | |
1382 | unreduce(__G); | |
1383 | break; | |
1384 | #endif /* !COPYRIGHT_CLEAN */ | |
1385 | ||
1386 | case IMPLODED: | |
1387 | if (!uO.tflag && QCOND2) { | |
1388 | Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), | |
1389 | "explod", FnFilter1(G.filename), | |
1390 | (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? | |
1391 | "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); | |
1392 | } | |
1393 | if (((r = explode(__G)) != 0) && (r != 5)) { /* treat 5 specially */ | |
1394 | if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) | |
1395 | Info(slide, 0x401, ((char *)slide, | |
1396 | LoadFarStringSmall(ErrUnzipFile), r == 3? | |
1397 | LoadFarString(NotEnoughMem) : | |
1398 | LoadFarString(InvalidComprData), | |
1399 | LoadFarStringSmall2(Explode), | |
1400 | FnFilter1(G.filename))); | |
1401 | else | |
1402 | Info(slide, 0x401, ((char *)slide, | |
1403 | LoadFarStringSmall(ErrUnzipNoFile), r == 3? | |
1404 | LoadFarString(NotEnoughMem) : | |
1405 | LoadFarString(InvalidComprData), | |
1406 | LoadFarStringSmall2(Explode))); | |
1407 | error = (r == 3)? PK_MEM3 : PK_ERR; | |
1408 | } | |
1409 | if (r == 5) { | |
1410 | int warning = ((ulg)G.used_csize <= G.lrec.csize); | |
1411 | ||
1412 | if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) | |
1413 | Info(slide, 0x401, ((char *)slide, LoadFarString(LengthMsg), | |
1414 | "", warning? "warning" : "error", G.used_csize, | |
1415 | G.lrec.ucsize, warning? " " : "", G.lrec.csize, | |
1416 | " [", FnFilter1(G.filename), "]")); | |
1417 | else | |
1418 | Info(slide, 0x401, ((char *)slide, LoadFarString(LengthMsg), | |
1419 | "\n", warning? "warning" : "error", G.used_csize, | |
1420 | G.lrec.ucsize, warning? " ":"", G.lrec.csize, | |
1421 | "", "", ".")); | |
1422 | error = warning? PK_WARN : PK_ERR; | |
1423 | } | |
1424 | break; | |
1425 | #endif /* !SFX */ | |
1426 | ||
1427 | case DEFLATED: | |
1428 | if (!uO.tflag && QCOND2) { | |
1429 | Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), | |
1430 | "inflat", FnFilter1(G.filename), | |
1431 | (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? | |
1432 | "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); | |
1433 | } | |
1434 | #ifndef USE_ZLIB /* zlib's function is called inflate(), too */ | |
1435 | # define UZinflate inflate | |
1436 | #endif | |
1437 | if ((r = UZinflate(__G)) != 0) { | |
1438 | if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) | |
1439 | Info(slide, 0x401, ((char *)slide, | |
1440 | LoadFarStringSmall(ErrUnzipFile), r == 3? | |
1441 | LoadFarString(NotEnoughMem) : | |
1442 | LoadFarString(InvalidComprData), | |
1443 | LoadFarStringSmall2(Inflate), | |
1444 | FnFilter1(G.filename))); | |
1445 | else | |
1446 | Info(slide, 0x401, ((char *)slide, | |
1447 | LoadFarStringSmall(ErrUnzipNoFile), r == 3? | |
1448 | LoadFarString(NotEnoughMem) : | |
1449 | LoadFarString(InvalidComprData), | |
1450 | LoadFarStringSmall2(Inflate))); | |
1451 | error = (r == 3)? PK_MEM3 : PK_ERR; | |
1452 | } | |
1453 | break; | |
1454 | ||
1455 | default: /* should never get to this point */ | |
1456 | Info(slide, 0x401, ((char *)slide, | |
1457 | LoadFarString(FileUnknownCompMethod), FnFilter1(G.filename))); | |
1458 | /* close and delete file before return? */ | |
1459 | undefer_input(__G); | |
1460 | return PK_WARN; | |
1461 | ||
1462 | } /* end switch (compression method) */ | |
1463 | ||
1464 | /*--------------------------------------------------------------------------- | |
1465 | Close the file and set its date and time (not necessarily in that order), | |
1466 | and make sure the CRC checked out OK. Logical-AND the CRC for 64-bit | |
1467 | machines (redundant on 32-bit machines). | |
1468 | ---------------------------------------------------------------------------*/ | |
1469 | ||
1470 | #ifdef VMS /* VMS: required even for stdout! (final flush) */ | |
1471 | if (!uO.tflag) /* don't close NULL file */ | |
1472 | close_outfile(__G); | |
1473 | #else | |
1474 | #ifdef DLL | |
1475 | if (!uO.tflag && (!uO.cflag || G.redirect_data)) { | |
1476 | if (G.redirect_data) | |
1477 | FINISH_REDIRECT(); | |
1478 | else | |
1479 | close_outfile(__G); | |
1480 | } | |
1481 | #else | |
1482 | if (!uO.tflag && !uO.cflag) /* don't close NULL file or stdout */ | |
1483 | close_outfile(__G); | |
1484 | #endif | |
1485 | #endif /* VMS */ | |
1486 | ||
1487 | /* GRR: CONVERT close_outfile() TO NON-VOID: CHECK FOR ERRORS! */ | |
1488 | ||
1489 | ||
1490 | if (G.disk_full) { /* set by flush() */ | |
1491 | if (G.disk_full > 1) { | |
1492 | #if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK)) | |
1493 | /* delete the incomplete file if we can */ | |
1494 | if (unlink(G.filename) != 0) | |
1495 | Trace((stderr, "extract.c: could not delete %s\n", | |
1496 | FnFilter1(G.filename))); | |
1497 | #else | |
1498 | /* warn user about the incomplete file */ | |
1499 | Info(slide, 0x421, ((char *)slide, LoadFarString(FileTruncated), | |
1500 | FnFilter1(G.filename))); | |
1501 | #endif | |
1502 | error = PK_DISK; | |
1503 | } else { | |
1504 | error = PK_WARN; | |
1505 | } | |
1506 | } | |
1507 | ||
1508 | if (error > PK_WARN) {/* don't print redundant CRC error if error already */ | |
1509 | undefer_input(__G); | |
1510 | return error; | |
1511 | } | |
1512 | if (G.crc32val != G.lrec.crc32) { | |
1513 | /* if quiet enough, we haven't output the filename yet: do it */ | |
1514 | if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) | |
1515 | Info(slide, 0x401, ((char *)slide, "%-22s ", | |
1516 | FnFilter1(G.filename))); | |
1517 | Info(slide, 0x401, ((char *)slide, LoadFarString(BadCRC), G.crc32val, | |
1518 | G.lrec.crc32)); | |
1519 | #if CRYPT | |
1520 | if (G.pInfo->encrypted) | |
1521 | Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeBadPasswd))); | |
1522 | #endif | |
1523 | error = PK_ERR; | |
1524 | } else if (uO.tflag) { | |
1525 | #ifndef SFX | |
1526 | if (G.extra_field) { | |
1527 | if ((r = TestExtraField(__G__ G.extra_field, | |
1528 | G.lrec.extra_field_length)) > error) | |
1529 | error = r; | |
1530 | } else | |
1531 | #endif /* !SFX */ | |
1532 | if (!uO.qflag) | |
1533 | Info(slide, 0, ((char *)slide, " OK\n")); | |
1534 | } else { | |
1535 | if (QCOND2 && !error) /* GRR: is stdout reset to text mode yet? */ | |
1536 | Info(slide, 0, ((char *)slide, "\n")); | |
1537 | } | |
1538 | ||
1539 | undefer_input(__G); | |
1540 | return error; | |
1541 | ||
1542 | } /* end function extract_or_test_member() */ | |
1543 | ||
1544 | ||
1545 | ||
1546 | ||
1547 | ||
1548 | #ifndef SFX | |
1549 | ||
1550 | /*******************************/ | |
1551 | /* Function TestExtraField() */ | |
1552 | /*******************************/ | |
1553 | ||
1554 | static int TestExtraField(__G__ ef, ef_len) | |
1555 | __GDEF | |
1556 | uch *ef; | |
1557 | unsigned ef_len; | |
1558 | { | |
1559 | ush ebID; | |
1560 | unsigned ebLen; | |
1561 | unsigned eb_cmpr_offs = 0; | |
1562 | int r; | |
1563 | ||
1564 | /* we know the regular compressed file data tested out OK, or else we | |
1565 | * wouldn't be here ==> print filename if any extra-field errors found | |
1566 | */ | |
1567 | while (ef_len >= EB_HEADSIZE) { | |
1568 | ebID = makeword(ef); | |
1569 | ebLen = (unsigned)makeword(ef+EB_LEN); | |
1570 | ||
1571 | if (ebLen > (ef_len - EB_HEADSIZE)) { | |
1572 | /* Discovered some extra field inconsistency! */ | |
1573 | if (uO.qflag) | |
1574 | Info(slide, 1, ((char *)slide, "%-22s ", | |
1575 | FnFilter1(G.filename))); | |
1576 | Info(slide, 1, ((char *)slide, LoadFarString(InconsistEFlength), | |
1577 | ebLen, (ef_len - EB_HEADSIZE))); | |
1578 | return PK_ERR; | |
1579 | } | |
1580 | ||
1581 | switch (ebID) { | |
1582 | case EF_OS2: | |
1583 | case EF_ACL: | |
1584 | case EF_MAC3: | |
1585 | case EF_BEOS: | |
1586 | switch (ebID) { | |
1587 | case EF_OS2: | |
1588 | case EF_ACL: | |
1589 | eb_cmpr_offs = EB_OS2_HLEN; | |
1590 | break; | |
1591 | case EF_MAC3: | |
1592 | if (ebLen >= EB_MAC3_HLEN && | |
1593 | (makeword(ef+(EB_HEADSIZE+EB_FLGS_OFFS)) | |
1594 | & EB_M3_FL_UNCMPR) && | |
1595 | (makelong(ef+EB_HEADSIZE) == ebLen - EB_MAC3_HLEN)) | |
1596 | eb_cmpr_offs = 0; | |
1597 | else | |
1598 | eb_cmpr_offs = EB_MAC3_HLEN; | |
1599 | break; | |
1600 | case EF_BEOS: | |
1601 | if (ebLen >= EB_BEOS_HLEN && | |
1602 | (*(ef+(EB_HEADSIZE+EB_FLGS_OFFS)) & EB_BE_FL_UNCMPR) && | |
1603 | (makelong(ef+EB_HEADSIZE) == ebLen - EB_BEOS_HLEN)) | |
1604 | eb_cmpr_offs = 0; | |
1605 | else | |
1606 | eb_cmpr_offs = EB_BEOS_HLEN; | |
1607 | break; | |
1608 | } | |
1609 | if ((r = test_compr_eb(__G__ ef, ebLen, eb_cmpr_offs, NULL)) | |
1610 | != PK_OK) { | |
1611 | if (uO.qflag) | |
1612 | Info(slide, 1, ((char *)slide, "%-22s ", | |
1613 | FnFilter1(G.filename))); | |
1614 | switch (r) { | |
1615 | case IZ_EF_TRUNC: | |
1616 | Info(slide, 1, ((char *)slide, | |
1617 | LoadFarString(TruncEAs), | |
1618 | ebLen-(eb_cmpr_offs+EB_CMPRHEADLEN), "\n")); | |
1619 | break; | |
1620 | case PK_ERR: | |
1621 | Info(slide, 1, ((char *)slide, | |
1622 | LoadFarString(InvalidComprDataEAs))); | |
1623 | break; | |
1624 | case PK_MEM3: | |
1625 | case PK_MEM4: | |
1626 | Info(slide, 1, ((char *)slide, | |
1627 | LoadFarString(NotEnoughMemEAs))); | |
1628 | break; | |
1629 | default: | |
1630 | if ((r & 0xff) != PK_ERR) | |
1631 | Info(slide, 1, ((char *)slide, | |
1632 | LoadFarString(UnknErrorEAs))); | |
1633 | else { | |
1634 | ush m = (ush)(r >> 8); | |
1635 | if (m == DEFLATED) /* GRR KLUDGE! */ | |
1636 | Info(slide, 1, ((char *)slide, | |
1637 | LoadFarString(BadCRC_EAs))); | |
1638 | else | |
1639 | Info(slide, 1, ((char *)slide, | |
1640 | LoadFarString(UnknComprMethodEAs), m)); | |
1641 | } | |
1642 | break; | |
1643 | } | |
1644 | return r; | |
1645 | } | |
1646 | break; | |
1647 | ||
1648 | case EF_NTSD: | |
1649 | Trace((stderr, "ebID: %i / ebLen: %u\n", ebID, ebLen)); | |
1650 | r = ebLen < EB_NTSD_L_LEN ? IZ_EF_TRUNC : | |
1651 | ((ef[EB_HEADSIZE+EB_NTSD_VERSION] > EB_NTSD_MAX_VER) ? | |
1652 | (PK_WARN | 0x4000) : | |
1653 | test_compr_eb(__G__ ef, ebLen, EB_NTSD_L_LEN, TEST_NTSD)); | |
1654 | if (r != PK_OK) { | |
1655 | if (uO.qflag) | |
1656 | Info(slide, 1, ((char *)slide, "%-22s ", | |
1657 | FnFilter1(G.filename))); | |
1658 | switch (r) { | |
1659 | case IZ_EF_TRUNC: | |
1660 | Info(slide, 1, ((char *)slide, | |
1661 | LoadFarString(TruncNTSD), | |
1662 | ebLen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n")); | |
1663 | break; | |
1664 | #if (defined(WIN32) && defined(NTSD_EAS)) | |
1665 | case PK_WARN: | |
1666 | Info(slide, 1, ((char *)slide, | |
1667 | LoadFarString(InvalidSecurityEAs))); | |
1668 | break; | |
1669 | #endif | |
1670 | case PK_ERR: | |
1671 | Info(slide, 1, ((char *)slide, | |
1672 | LoadFarString(InvalidComprDataEAs))); | |
1673 | break; | |
1674 | case PK_MEM3: | |
1675 | case PK_MEM4: | |
1676 | Info(slide, 1, ((char *)slide, | |
1677 | LoadFarString(NotEnoughMemEAs))); | |
1678 | break; | |
1679 | case (PK_WARN | 0x4000): | |
1680 | Info(slide, 1, ((char *)slide, | |
1681 | LoadFarString(UnsuppNTSDVersEAs), | |
1682 | (int)ef[EB_HEADSIZE+EB_NTSD_VERSION])); | |
1683 | r = PK_WARN; | |
1684 | break; | |
1685 | default: | |
1686 | if ((r & 0xff) != PK_ERR) | |
1687 | Info(slide, 1, ((char *)slide, | |
1688 | LoadFarString(UnknErrorEAs))); | |
1689 | else { | |
1690 | ush m = (ush)(r >> 8); | |
1691 | if (m == DEFLATED) /* GRR KLUDGE! */ | |
1692 | Info(slide, 1, ((char *)slide, | |
1693 | LoadFarString(BadCRC_EAs))); | |
1694 | else | |
1695 | Info(slide, 1, ((char *)slide, | |
1696 | LoadFarString(UnknComprMethodEAs), m)); | |
1697 | } | |
1698 | break; | |
1699 | } | |
1700 | return r; | |
1701 | } | |
1702 | break; | |
1703 | case EF_PKVMS: | |
1704 | case EF_PKW32: | |
1705 | case EF_PKUNIX: | |
1706 | case EF_ASIUNIX: | |
1707 | case EF_IZVMS: | |
1708 | case EF_IZUNIX: | |
1709 | case EF_VMCMS: | |
1710 | case EF_MVS: | |
1711 | case EF_SPARK: | |
1712 | case EF_AV: | |
1713 | default: | |
1714 | break; | |
1715 | } | |
1716 | ef_len -= (ebLen + EB_HEADSIZE); | |
1717 | ef += (ebLen + EB_HEADSIZE); | |
1718 | } | |
1719 | ||
1720 | if (!uO.qflag) | |
1721 | Info(slide, 0, ((char *)slide, " OK\n")); | |
1722 | ||
1723 | return PK_COOL; | |
1724 | ||
1725 | } /* end function TestExtraField() */ | |
1726 | ||
1727 | ||
1728 | ||
1729 | ||
1730 | ||
1731 | /******************************/ | |
1732 | /* Function test_compr_eb() */ | |
1733 | /******************************/ | |
1734 | ||
1735 | #ifdef PROTO | |
1736 | static int test_compr_eb( | |
1737 | __GPRO__ | |
1738 | uch *eb, | |
1739 | unsigned eb_size, | |
1740 | unsigned compr_offset, | |
1741 | int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size, | |
1742 | uch *eb_ucptr, ulg eb_ucsize)) | |
1743 | #else /* !PROTO */ | |
1744 | static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata) | |
1745 | __GDEF | |
1746 | uch *eb; | |
1747 | unsigned eb_size; | |
1748 | unsigned compr_offset; | |
1749 | int (*test_uc_ebdata)(); | |
1750 | #endif /* ?PROTO */ | |
1751 | { | |
1752 | ulg eb_ucsize; | |
1753 | uch *eb_ucptr; | |
1754 | int r; | |
1755 | ||
1756 | if (compr_offset < 4) /* field is not compressed: */ | |
1757 | return PK_OK; /* do nothing and signal OK */ | |
1758 | ||
1759 | if ((eb_size < (EB_UCSIZE_P + 4)) || | |
1760 | ((eb_ucsize = makelong(eb+(EB_HEADSIZE+EB_UCSIZE_P))) > 0L && | |
1761 | eb_size <= (compr_offset + EB_CMPRHEADLEN))) | |
1762 | return IZ_EF_TRUNC; /* no compressed data! */ | |
1763 | ||
1764 | if ((eb_ucptr = (uch *)malloc((extent)eb_ucsize)) == (uch *)NULL) | |
1765 | return PK_MEM4; | |
1766 | ||
1767 | r = memextract(__G__ eb_ucptr, eb_ucsize, | |
1768 | eb + (EB_HEADSIZE + compr_offset), | |
1769 | (ulg)(eb_size - compr_offset)); | |
1770 | ||
1771 | if (r == PK_OK && test_uc_ebdata != NULL) | |
1772 | r = (*test_uc_ebdata)(__G__ eb, eb_size, eb_ucptr, eb_ucsize); | |
1773 | ||
1774 | free(eb_ucptr); | |
1775 | return r; | |
1776 | ||
1777 | } /* end function test_compr_eb() */ | |
1778 | ||
1779 | #endif /* !SFX */ | |
1780 | ||
1781 | ||
1782 | ||
1783 | ||
1784 | ||
1785 | /***************************/ | |
1786 | /* Function memextract() */ | |
1787 | /***************************/ | |
1788 | ||
1789 | int memextract(__G__ tgt, tgtsize, src, srcsize) /* extract compressed */ | |
1790 | __GDEF /* extra field block; */ | |
1791 | uch *tgt, *src; /* return PK-type error */ | |
1792 | ulg tgtsize, srcsize; /* level */ | |
1793 | { | |
1794 | long old_csize=G.csize; | |
1795 | uch *old_inptr=G.inptr; | |
1796 | int old_incnt=G.incnt; | |
1797 | int r, error=PK_OK; | |
1798 | ush method; | |
1799 | ulg extra_field_crc; | |
1800 | ||
1801 | ||
1802 | method = makeword(src); | |
1803 | extra_field_crc = makelong(src+2); | |
1804 | ||
1805 | /* compressed extra field exists completely in memory at this location: */ | |
1806 | G.inptr = src + 2 + 4; /* method and extra_field_crc */ | |
1807 | G.incnt = (int)(G.csize = (long)(srcsize - (2 + 4))); | |
1808 | G.mem_mode = TRUE; | |
1809 | G.outbufptr = tgt; | |
1810 | G.outsize = tgtsize; | |
1811 | ||
1812 | switch (method) { | |
1813 | case STORED: | |
1814 | memcpy((char *)tgt, (char *)G.inptr, (extent)G.incnt); | |
1815 | G.outcnt = G.csize; /* for CRC calculation */ | |
1816 | break; | |
1817 | case DEFLATED: | |
1818 | G.outcnt = 0L; | |
1819 | if ((r = UZinflate(__G)) != 0) { | |
1820 | if (!uO.tflag) | |
1821 | Info(slide, 0x401, ((char *)slide, | |
1822 | LoadFarStringSmall(ErrUnzipNoFile), r == 3? | |
1823 | LoadFarString(NotEnoughMem) : | |
1824 | LoadFarString(InvalidComprData), | |
1825 | LoadFarStringSmall2(Inflate))); | |
1826 | error = (r == 3)? PK_MEM3 : PK_ERR; | |
1827 | } | |
1828 | if (G.outcnt == 0L) /* inflate's final FLUSH sets outcnt */ | |
1829 | break; | |
1830 | break; | |
1831 | default: | |
1832 | if (uO.tflag) | |
1833 | error = PK_ERR | ((int)method << 8); | |
1834 | else { | |
1835 | Info(slide, 0x401, ((char *)slide, | |
1836 | LoadFarString(UnsupportedExtraField), method)); | |
1837 | error = PK_ERR; /* GRR: should be passed on up via SetEAs() */ | |
1838 | } | |
1839 | break; | |
1840 | } | |
1841 | ||
1842 | G.inptr = old_inptr; | |
1843 | G.incnt = old_incnt; | |
1844 | G.csize = old_csize; | |
1845 | G.mem_mode = FALSE; | |
1846 | ||
1847 | if (!error) { | |
1848 | register ulg crcval = crc32(CRCVAL_INITIAL, tgt, (extent)G.outcnt); | |
1849 | ||
1850 | if (crcval != extra_field_crc) { | |
1851 | if (uO.tflag) | |
1852 | error = PK_ERR | (DEFLATED << 8); /* kludge for now */ | |
1853 | else { | |
1854 | Info(slide, 0x401, ((char *)slide, | |
1855 | LoadFarString(BadExtraFieldCRC), G.zipfn, crcval, | |
1856 | extra_field_crc)); | |
1857 | error = PK_ERR; | |
1858 | } | |
1859 | } | |
1860 | } | |
1861 | return error; | |
1862 | ||
1863 | } /* end function memextract() */ | |
1864 | ||
1865 | ||
1866 | ||
1867 | ||
1868 | ||
1869 | /*************************/ | |
1870 | /* Function memflush() */ | |
1871 | /*************************/ | |
1872 | ||
1873 | int memflush(__G__ rawbuf, size) | |
1874 | __GDEF | |
1875 | uch *rawbuf; | |
1876 | ulg size; | |
1877 | { | |
1878 | if (size > G.outsize) | |
1879 | return 50; /* more data than output buffer can hold */ | |
1880 | ||
1881 | memcpy((char *)G.outbufptr, (char *)rawbuf, (extent)size); | |
1882 | G.outbufptr += (unsigned int)size; | |
1883 | G.outsize -= size; | |
1884 | G.outcnt += size; | |
1885 | ||
1886 | return 0; | |
1887 | ||
1888 | } /* end function memflush() */ | |
1889 | ||
1890 | ||
1891 | ||
1892 | ||
1893 | ||
1894 | /*************************/ | |
1895 | /* Function fnfilter() */ /* here instead of in list.c for SFX */ | |
1896 | /*************************/ | |
1897 | ||
1898 | char *fnfilter(raw, space) /* convert name to safely printable form */ | |
1899 | ZCONST char *raw; | |
1900 | uch *space; | |
1901 | { | |
1902 | #ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */ | |
1903 | uch *r=(uch *)raw, *s=space; | |
1904 | ||
1905 | while (*r) { | |
1906 | #ifdef QDOS | |
1907 | if (qlflag & 2) { | |
1908 | if (*r == '/' || *r == '.') { | |
1909 | ++r; | |
1910 | *s++ = '_'; | |
1911 | continue; | |
1912 | } | |
1913 | } else | |
1914 | #endif | |
1915 | if (*r < 32) | |
1916 | *s++ = '^', *s++ = (uch)(64 + *r++); | |
1917 | else | |
1918 | *s++ = *r++; | |
1919 | } | |
1920 | *s = 0; | |
1921 | ||
1922 | #ifdef WINDLL | |
1923 | INTERN_TO_ISO((char *)space, (char *)space); /* translate to ANSI */ | |
1924 | #else | |
1925 | #ifdef WIN32 | |
1926 | /* Win9x console always uses OEM character coding, and | |
1927 | WinNT console is set to OEM charset by default, too */ | |
1928 | INTERN_TO_OEM((char *)space, (char *)space); | |
1929 | #endif /* WIN32 */ | |
1930 | #endif /* ?WINDLL */ | |
1931 | ||
1932 | return (char *)space; | |
1933 | ||
1934 | #else /* NATIVE: EBCDIC or whatever */ | |
1935 | return (char *)raw; | |
1936 | #endif | |
1937 | ||
1938 | } /* end function fnfilter() */ | |
1939 | ||
1940 | ||
1941 | ||
1942 | ||
1943 | ||
1944 | #ifdef SET_DIR_ATTRIB | |
1945 | /* must sort saved directories so can set perms from bottom up */ | |
1946 | ||
1947 | /************************/ | |
1948 | /* Function dircomp() */ | |
1949 | /************************/ | |
1950 | ||
1951 | static int dircomp(a, b) /* used by qsort(); swiped from Zip */ | |
1952 | ZCONST zvoid *a, *b; | |
1953 | { | |
1954 | /* order is significant: this sorts in reverse order (deepest first) */ | |
1955 | return strcmp((*(dirtime **)b)->fn, (*(dirtime **)a)->fn); | |
1956 | /* return namecmp((*(dirtime **)b)->fn, (*(dirtime **)a)->fn); */ | |
1957 | } | |
1958 | ||
1959 | ||
1960 | ||
1961 | #if 0 /* not used in Unix, but maybe for future OSes? */ | |
1962 | ||
1963 | /************************/ | |
1964 | /* Function namecmp() */ | |
1965 | /************************/ | |
1966 | ||
1967 | static int namecmp(s1, s2) /* [not] used by dircomp(); swiped from Zip */ | |
1968 | ZCONST char *s1, *s2; | |
1969 | { | |
1970 | int d; | |
1971 | ||
1972 | for (;;) { | |
1973 | d = (int)(uch)case_map(*s1) | |
1974 | - (int)(uch)case_map(*s2); | |
1975 | ||
1976 | if (d || *s1 == 0 || *s2 == 0) | |
1977 | return d; | |
1978 | ||
1979 | s1++; | |
1980 | s2++; | |
1981 | } | |
1982 | } | |
1983 | ||
1984 | #endif /* 0 */ | |
1985 | #endif /* SET_DIR_ATTRIB */ |