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