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