xref: /haiku/src/bin/unzip/extract.c (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
1 /*
2   Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
3 
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 /*---------------------------------------------------------------------------
10 
11   extract.c
12 
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.
16 
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()
27 
28   ---------------------------------------------------------------------------*/
29 
30 
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"
42 
43 #define GRRDUMP(buf,len) { \
44     int i, j; \
45  \
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)]; \
53  \
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]; \
70  \
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     } \
80 }
81 
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
108 
109 
110 
111 /*******************************/
112 /*  Strings used in extract.c  */
113 /*******************************/
114 
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
133    };
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
148 
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";
162 
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
171 
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 */
179 
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";
184 
185 #ifndef VMS
186    static ZCONST char Far VMSFormatQuery[] =
187      "\n%s:  stored in VMS format.  Extract anyway? (y/n) ";
188 #endif
189 
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
203 
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";
210 
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";
216 
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
223 
224 #if (!defined(DELETE_IF_FULL) || !defined(HAVE_UNLINK))
225    static ZCONST char Far FileTruncated[] =
226      "warning:  %s is probably truncated\n";
227 #endif
228 
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";
232 
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";
237 
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 */
257 
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";
262 
263 
264 
265 
266 
267 /**************************************/
268 /*  Function extract_or_test_files()  */
269 /**************************************/
270 
271 int extract_or_test_files(__G)    /* return PK-type error code */
272      __GDEF
273 {
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
289 
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   ---------------------------------------------------------------------------*/
308 
309     G.pInfo = G.info;
310 
311 #if CRYPT
312     G.newzip = TRUE;
313 #endif
314 #ifndef SFX
315     G.reported_backslash = FALSE;
316 #endif
317 
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;
327 
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   ---------------------------------------------------------------------------*/
336 
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
345 
346         /*
347          * Loop through files in central directory, storing offsets, file
348          * attributes, case-conversion and text-conversion flags until block
349          * size is reached.
350          */
351 
352         while ((j < DIR_BLKSIZ)) {
353             G.pInfo = &G.info[j];
354 
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;
359             }
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?
364                  */
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
368                      */
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
374                      */
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;
380                 }
381                 reached_end = TRUE;     /* ...so no more left to do */
382                 break;
383             }
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;
389             }
390             if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) !=
391                  PK_COOL)
392             {
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;
400                 }
401             }
402             if ((error = do_string(__G__ G.crec.extra_field_length,
403                 EXTRA_FIELD)) != 0)
404             {
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;
413                 }
414             }
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
423             {
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;
432                 }
433             }
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;
441 
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 */
452                         }
453                 }
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;
461                         }
462                 }
463                 if (do_this_file) {
464                     if (store_info(__G))
465                         ++j;            /* file is OK */
466                     else
467                         ++num_skipped;  /* unsupp. compression or encryption */
468                 }
469             } /* end if (process_all_files) */
470 
471             members_processed++;
472 
473         } /* end while-loop (adding files to current block) */
474 
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;
479 
480     /*-----------------------------------------------------------------------
481         Second loop:  process files in current block, extracting or testing
482         each one.
483       -----------------------------------------------------------------------*/
484 
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) */
500             }
501         }
502 
503 
504         /*
505          * Jump back to where we were in the central directory, then go and do
506          * the next batch of files.
507          */
508 
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;
520 
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
528 
529     } /* end while-loop (blocks of files in central directory) */
530 
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   ---------------------------------------------------------------------------*/
535 
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;
544 
545                 dirlist = dirlist->next;
546                 free(d);
547             }
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;
555                 }
556                 qsort((char *)sorted_dirlist, num_dirs, sizeof(dirtime *),
557                   dircomp);
558             }
559 
560             Trace((stderr, "setting directory times/perms/attributes\n"));
561             for (i = 0;  i < num_dirs;  ++i) {
562                 dirtime *d = sorted_dirlist[i];
563 
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;
570                 }
571                 free(d->fn);
572                 free(d);
573             }
574             free(sorted_dirlist);
575         }
576     }
577 #endif /* SET_DIR_ATTRIB */
578 
579 #if (defined(WIN32) && defined(NTSD_EAS))
580     process_defer_NT(__G);  /* process any deferred items for this .zip file */
581 #endif
582 
583 /*---------------------------------------------------------------------------
584     Check for unmatched filespecs on command line and print warning if any
585     found.  Free allocated memory.
586   ---------------------------------------------------------------------------*/
587 
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 */
603             }
604         free((zvoid *)fn_matched);
605     }
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);
612     }
613 
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   ---------------------------------------------------------------------------*/
620 
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;
627     }
628 #endif /* !SFX */
629     if (uO.tflag) {
630         ulg num = filnum - num_bad_pwd;
631 
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));
656     }
657 
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) */
660 
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 */
666     }
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
677 
678     return error_in_archive;
679 
680 } /* end function extract_or_test_files() */
681 
682 
683 
684 
685 
686 /***************************/
687 /*  Function store_info()  */
688 /***************************/
689 
690 static int store_info(__G)   /* return 0 if skipping, 1 if OK */
691     __GDEF
692 {
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
724 
725 /*---------------------------------------------------------------------------
726     Check central directory info for version/compatibility requirements.
727   ---------------------------------------------------------------------------*/
728 
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;
735 
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;
746     }
747 
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;
757         }
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;
765         }
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;
776     }
777 
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));
790         }
791         return 0;
792     }
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;
799     }
800 #endif /* !CRYPT */
801 
802     /* map whatever file attributes we have into the local format */
803     mapattr(__G);   /* GRR:  worry about return value later */
804 
805     G.pInfo->diskstart = G.crec.disk_number_start;
806     G.pInfo->offset = (long)G.crec.relative_offset_local_header;
807     return 1;
808 
809 } /* end function store_info() */
810 
811 
812 
813 
814 
815 /******************************************/
816 /*  Function extract_or_test_entrylist()  */
817 /******************************************/
818 
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;
835 {
836     unsigned i;
837     int renamed, query;
838     int skip_entry;
839     long bufstart, inbuf_offset, request;
840     int error, errcode;
841 
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 */
846 
847     /*-----------------------------------------------------------------------
848         Second loop:  process files in current block, extracting or testing
849         each one.
850       -----------------------------------------------------------------------*/
851 
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
858 
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(). */
862 
863         /* seek_zipf(__G__ pInfo->offset);  */
864         request = G.pInfo->offset + G.extra_bytes;
865         inbuf_offset = request % INBUFSIZ;
866         bufstart = request - inbuf_offset;
867 
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;
899                 }
900             } else {
901                 error_in_archive = PK_BADERR;
902                 continue;  /* this one hosed; try next */
903             }
904         }
905 
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)
916             {
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 */
921             }
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;
927         }
928 
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 */
935         }
936         if (strncmp(G.sig, local_hdr_sig, 4)) {
937             Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
938               *pfilnum, LoadFarStringSmall(LocalHdrSig), request));
939             /*
940                 GRRDUMP(G.sig, 4)
941                 GRRDUMP(local_hdr_sig, 4)
942              */
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 */
960                 }
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;
967                 }
968             } else
969                 continue;  /* this one hosed; try next */
970         }
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 */
976         }
977         if ((error = do_string(__G__ G.lrec.filename_length, DS_FN_L)) !=
978              PK_COOL)
979         {
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 */
986             }
987         }
988         if (G.extra_field != (uch *)NULL) {
989             free(G.extra_field);
990             G.extra_field = (uch *)NULL;
991         }
992         if ((error =
993              do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0)
994         {
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 */
1002             }
1003         }
1004 
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)));
1020             }
1021             continue;   /* go on to next file */
1022         }
1023 #endif /* CRYPT */
1024 
1025         /*
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[])
1031          */
1032 #ifdef DLL
1033         if (!uO.tflag && !uO.cflag && !G.redirect_data)
1034 #else
1035         if (!uO.tflag && !uO.cflag)
1036 #endif
1037         {
1038             renamed = FALSE;   /* user hasn't renamed output file yet */
1039 
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)
1046              */
1047 #ifndef SFX
1048             if (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/')) {
1049                 char *p=G.filename;
1050 
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;
1059                         }
1060                         *p = '/';
1061                     }
1062                 } while (*PREINCSTR(p));
1063             }
1064 #endif /* !SFX */
1065 
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] == '/');
1080                }
1081             }
1082 
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;
1092 
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;
1099 
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;
1112                         }
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);
1136                         }
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;
1144                         }
1145                         (*pdirlist)->have_uidgid =
1146 #ifdef RESTORE_UIDGID
1147                             (uO.X_flag && (eb_izux_flg & EB_UX2_VALID));
1148 #else
1149                             0;
1150 #endif
1151                         ++(*pnum_dirs);
1152                     }
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 */
1171             }
1172 
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
1189                     {
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;
1195                     }
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;
1213                     }
1214                     break;
1215                 }
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;
1236                 }
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 */
1249                 }
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)));
1296                 }
1297 #endif /* WINDLL */
1298                 continue;
1299             }
1300         } /* end if (extracting to disk) */
1301 
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 */
1307         }
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) */
1325             }
1326         }
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 */
1332         }
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) */
1338 
1339     return error_in_archive;
1340 
1341 } /* end function extract_or_test_entrylist() */
1342 
1343 
1344 
1345 
1346 
1347 /***************************************/
1348 /*  Function extract_or_test_member()  */
1349 /***************************************/
1350 
1351 static int extract_or_test_member(__G)    /* return PK-type error code */
1352      __GDEF
1353 {
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
1365 
1366 
1367 /*---------------------------------------------------------------------------
1368     Initialize variables, buffers, etc.
1369   ---------------------------------------------------------------------------*/
1370 
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;
1376 
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 */
1388 
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
1399         {
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;
1421     }
1422 
1423 /*---------------------------------------------------------------------------
1424     Unpack the file.
1425   ---------------------------------------------------------------------------*/
1426 
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 : ""));
1442             }
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;
1448             }
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;
1459                 }
1460             }
1461             if (G.outcnt)          /* flush final (partial) buffer */
1462                 flush(__G__ redirSlide, G.outcnt, 0);
1463             break;
1464 
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 : ""));
1473             }
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)));
1487                 }
1488                 error = r;
1489             }
1490             break;
1491 #endif /* !LZW_CLEAN */
1492 
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 : ""));
1503             }
1504             if ((r = unreduce(__G)) != PK_COOL) {
1505                 /* unreduce() returns only PK_COOL, PK_DISK, or IZ_CTRLC */
1506                 error = r;
1507             }
1508             break;
1509 #endif /* !COPYRIGHT_CLEAN */
1510 
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 : ""));
1517             }
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;
1536                 }
1537             }
1538             if (r == 5) {
1539                 int warning = ((ulg)G.used_csize <= G.lrec.csize);
1540 
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;
1552             }
1553             break;
1554 #endif /* !SFX */
1555 
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 : ""));
1565             }
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;
1589                 }
1590             }
1591             break;
1592 
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;
1599 
1600     } /* end switch (compression method) */
1601 
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   ---------------------------------------------------------------------------*/
1607 
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);
1618     }
1619 #else
1620     if (!uO.tflag && !uO.cflag)   /* don't close NULL file or stdout */
1621         close_outfile(__G);
1622 #endif
1623 #endif /* VMS */
1624 
1625             /* GRR: CONVERT close_outfile() TO NON-VOID:  CHECK FOR ERRORS! */
1626 
1627 
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;
1643         }
1644     }
1645 
1646     if (error > PK_WARN) {/* don't print redundant CRC error if error already */
1647         undefer_input(__G);
1648         return error;
1649     }
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"));
1675     }
1676 
1677     undefer_input(__G);
1678     return error;
1679 
1680 } /* end function extract_or_test_member() */
1681 
1682 
1683 
1684 
1685 
1686 #ifndef SFX
1687 
1688 /*******************************/
1689 /*  Function TestExtraField()  */
1690 /*******************************/
1691 
1692 static int TestExtraField(__G__ ef, ef_len)
1693     __GDEF
1694     uch *ef;
1695     unsigned ef_len;
1696 {
1697     ush ebID;
1698     unsigned ebLen;
1699     unsigned eb_cmpr_offs = 0;
1700     int r;
1701 
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
1704      */
1705     while (ef_len >= EB_HEADSIZE) {
1706         ebID = makeword(ef);
1707         ebLen = (unsigned)makeword(ef+EB_LEN);
1708 
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;
1717         }
1718 
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;
1746                 }
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));
1779                             }
1780                             break;
1781                     }
1782                     return r;
1783                 }
1784                 break;
1785 
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));
1835                             }
1836                             break;
1837                     }
1838                     return r;
1839                 }
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;
1861         }
1862         ef_len -= (ebLen + EB_HEADSIZE);
1863         ef += (ebLen + EB_HEADSIZE);
1864     }
1865 
1866     if (!uO.qflag)
1867         Info(slide, 0, ((char *)slide, " OK\n"));
1868 
1869     return PK_COOL;
1870 
1871 } /* end function TestExtraField() */
1872 
1873 
1874 
1875 
1876 
1877 /******************************/
1878 /*  Function test_compr_eb()  */
1879 /******************************/
1880 
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 */
1897 {
1898     ulg eb_ucsize;
1899     uch *eb_ucptr;
1900     int r;
1901 
1902     if (compr_offset < 4)                /* field is not compressed: */
1903         return PK_OK;                    /* do nothing and signal OK */
1904 
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! */
1909 
1910     if ((eb_ucptr = (uch *)malloc((extent)eb_ucsize)) == (uch *)NULL)
1911         return PK_MEM4;
1912 
1913     r = memextract(__G__ eb_ucptr, eb_ucsize,
1914                    eb + (EB_HEADSIZE + compr_offset),
1915                    (ulg)(eb_size - compr_offset));
1916 
1917     if (r == PK_OK && test_uc_ebdata != NULL)
1918         r = (*test_uc_ebdata)(__G__ eb, eb_size, eb_ucptr, eb_ucsize);
1919 
1920     free(eb_ucptr);
1921     return r;
1922 
1923 } /* end function test_compr_eb() */
1924 
1925 #endif /* !SFX */
1926 
1927 
1928 
1929 
1930 
1931 /***************************/
1932 /*  Function memextract()  */
1933 /***************************/
1934 
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;
1941 {
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;
1948 
1949 
1950     method = makeword(src);
1951     extra_field_crc = makelong(src+2);
1952 
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;
1959 
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;
1978             }
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() */
1989             }
1990             break;
1991     }
1992 
1993     G.inptr = old_inptr;
1994     G.incnt = old_incnt;
1995     G.csize = old_csize;
1996     G.mem_mode = FALSE;
1997 
1998     if (!error) {
1999         register ulg crcval = crc32(CRCVAL_INITIAL, tgt, (extent)G.outcnt);
2000 
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;
2009             }
2010         }
2011     }
2012     return error;
2013 
2014 } /* end function memextract() */
2015 
2016 
2017 
2018 
2019 
2020 /*************************/
2021 /*  Function memflush()  */
2022 /*************************/
2023 
2024 int memflush(__G__ rawbuf, size)
2025     __GDEF
2026     ZCONST uch *rawbuf;
2027     ulg size;
2028 {
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 */
2033 
2034 
2035 
2036     memcpy((char *)G.outbufptr, (char *)rawbuf, (extent)size);
2037     G.outbufptr += (unsigned int)size;
2038     G.outsize -= size;
2039     G.outcnt += size;
2040 
2041     return 0;
2042 
2043 } /* end function memflush() */
2044 
2045 
2046 
2047 
2048 
2049 #if (defined(VMS) || defined(VMS_TEXT_CONV))
2050 
2051 /************************************/
2052 /*  Function extract_izvms_block()  */
2053 /************************************/
2054 
2055 /*
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.
2063  */
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;
2071 {
2072     uch *ucdata;       /* Pointer to block allocated */
2073     int cmptype;
2074     unsigned usiz, csiz;
2075 
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));
2080 
2081     if (retlen)
2082         *retlen = usiz;
2083 
2084     if ((ucdata = (uch *)malloc(MAX(needlen, usiz))) == NULL)
2085         return NULL;
2086 
2087     if (init && (usiz < needlen))
2088         memcpy((char *)ucdata, (ZCONST char *)init, needlen);
2089 
2090     switch (cmptype)
2091     {
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;
2105     }
2106     return ucdata;
2107 
2108 } /* end of extract_izvms_block */
2109 
2110 
2111 
2112 
2113 
2114 /********************************/
2115 /*  Function decompress_bits()  */
2116 /********************************/
2117 /*
2118  *  Simple uncompression routine. The compression uses bit stream.
2119  *  Compression scheme:
2120  *
2121  *  if (byte!=0)
2122  *      putbit(1),putbyte(byte)
2123  *  else
2124  *      putbit(0)
2125  */
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 */
2130 {
2131     ulg bitbuf = 0;
2132     int bitcnt = 0;
2133 
2134 #define _FILL   {       bitbuf |= (*bitptr++) << bitcnt;\
2135                         bitcnt += 8;                    \
2136                 }
2137 
2138     while (needlen--)
2139     {
2140         if (bitcnt <= 0)
2141             _FILL;
2142 
2143         if (bitbuf & 1)
2144         {
2145             bitbuf >>= 1;
2146             if ((bitcnt -= 1) < 8)
2147                 _FILL;
2148             *outptr++ = (uch)bitbuf;
2149             bitcnt -= 8;
2150             bitbuf >>= 8;
2151         }
2152         else
2153         {
2154             *outptr++ = '\0';
2155             bitcnt -= 1;
2156             bitbuf >>= 1;
2157         }
2158     }
2159 } /* end function decompress_bits() */
2160 
2161 #endif /* VMS || VMS_TEXT_CONV */
2162 
2163 
2164 
2165 
2166 
2167 /*************************/
2168 /*  Function fnfilter()  */        /* here instead of in list.c for SFX */
2169 /*************************/
2170 
2171 char *fnfilter(raw, space)         /* convert name to safely printable form */
2172     ZCONST char *raw;
2173     uch *space;
2174 {
2175 #ifndef NATIVE   /* ASCII:  filter ANSI escape codes, etc. */
2176     ZCONST uch *r=(ZCONST uch *)raw;
2177     uch *s=space;
2178 
2179     while (*r) {
2180 #ifdef QDOS
2181         if (qlflag & 2) {
2182             if (*r == '/' || *r == '.') {
2183                 ++r;
2184                 *s++ = '_';
2185                 continue;
2186             }
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
2199          }
2200     }
2201     *s = '\0';
2202 
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 */
2212 
2213     return (char *)space;
2214 
2215 #else /* NATIVE:  EBCDIC or whatever */
2216     return (char *)raw;
2217 #endif
2218 
2219 } /* end function fnfilter() */
2220 
2221 
2222 
2223 
2224 
2225 #ifdef SET_DIR_ATTRIB
2226 /* must sort saved directories so can set perms from bottom up */
2227 
2228 /************************/
2229 /*  Function dircomp()  */
2230 /************************/
2231 
2232 static int dircomp(a, b)   /* used by qsort(); swiped from Zip */
2233     ZCONST zvoid *a, *b;
2234 {
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); */
2238 }
2239 
2240 
2241 
2242 #if 0   /* not used in Unix, but maybe for future OSes? */
2243 
2244 /************************/
2245 /*  Function namecmp()  */
2246 /************************/
2247 
2248 static int namecmp(s1, s2)   /* [not] used by dircomp(); swiped from Zip */
2249     ZCONST char *s1, *s2;
2250 {
2251     int d;
2252 
2253     for (;;) {
2254         d = (int)(uch)case_map(*s1)
2255           - (int)(uch)case_map(*s2);
2256 
2257         if (d || *s1 == 0 || *s2 == 0)
2258             return d;
2259 
2260         s1++;
2261         s2++;
2262     }
2263 }
2264 
2265 #endif /* 0 */
2266 #endif /* SET_DIR_ATTRIB */
2267