1 /*
2   Copyright (c) 1990-2014 Info-ZIP.  All rights reserved.
3 
4   See the accompanying file LICENSE, version 2009-Jan-02 or later
5   (the contents of which are also included in unzip.h) for terms of use.
6   If, for some reason, all these files are missing, the Info-ZIP license
7   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /*---------------------------------------------------------------------------
10 
11   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              find_compr_idx()
20              extract_or_test_entrylist()
21              extract_or_test_member()
22              TestExtraField()
23              test_compr_eb()
24              memextract()
25              memflush()
26              extract_izvms_block()    (VMS or VMS_TEXT_CONV)
27              set_deferred_symlink()   (SYMLINKS only)
28              fnfilter()
29              dircomp()                (SET_DIR_ATTRIB only)
30              UZbunzip2()              (USE_BZIP2 only)
31 
32   ---------------------------------------------------------------------------*/
33 
34 
35 #define __EXTRACT_C     /* identifies this source module */
36 #define UNZIP_INTERNAL
37 #include "unzip.h"
38 #ifdef WINDLL
39 #  ifdef POCKET_UNZIP
40 #    include "wince/intrface.h"
41 #  else
42 #    include "windll/windll.h"
43 #  endif
44 #endif
45 #include "crc32.h"
46 #include "crypt.h"
47 
48 #define GRRDUMP(buf,len) { \
49     int i, j; \
50  \
51     for (j = 0;  j < (len)/16;  ++j) { \
52         printf("        "); \
53         for (i = 0;  i < 16;  ++i) \
54             printf("%02x ", (uch)(buf)[i+(j<<4)]); \
55         printf("\n        "); \
56         for (i = 0;  i < 16;  ++i) { \
57             char c = (char)(buf)[i+(j<<4)]; \
58  \
59             if (c == '\n') \
60                 printf("\\n "); \
61             else if (c == '\r') \
62                 printf("\\r "); \
63             else \
64                 printf(" %c ", c); \
65         } \
66         printf("\n"); \
67     } \
68     if ((len) % 16) { \
69         printf("        "); \
70         for (i = j<<4;  i < (len);  ++i) \
71             printf("%02x ", (uch)(buf)[i]); \
72         printf("\n        "); \
73         for (i = j<<4;  i < (len);  ++i) { \
74             char c = (char)(buf)[i]; \
75  \
76             if (c == '\n') \
77                 printf("\\n "); \
78             else if (c == '\r') \
79                 printf("\\r "); \
80             else \
81                 printf(" %c ", c); \
82         } \
83         printf("\n"); \
84     } \
85 }
86 
87 static int store_info OF((__GPRO));
88 #ifdef SET_DIR_ATTRIB
89 static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
90                 ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes,
91                 unsigned *pnum_dirs, direntry **pdirlist,
92                 int error_in_archive));
93 #else
94 static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
95                 ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes,
96                 int error_in_archive));
97 #endif
98 static int extract_or_test_member OF((__GPRO));
99 #ifndef SFX
100    static int TestExtraField OF((__GPRO__ uch *ef, unsigned ef_len));
101    static int test_compr_eb OF((__GPRO__ uch *eb, unsigned eb_size,
102         unsigned compr_offset,
103         int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size,
104                               uch *eb_ucptr, ulg eb_ucsize)));
105 #endif
106 #if (defined(VMS) || defined(VMS_TEXT_CONV))
107    static void decompress_bits OF((uch *outptr, unsigned needlen,
108                                    ZCONST uch *bitptr));
109 #endif
110 #ifdef SYMLINKS
111    static void set_deferred_symlink OF((__GPRO__ slinkentry *slnk_entry));
112 #endif
113 #ifdef SET_DIR_ATTRIB
114    static int Cdecl dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b));
115 #endif
116 
117 
118 
119 /*******************************/
120 /*  Strings used in extract.c  */
121 /*******************************/
122 
123 static ZCONST char Far VersionMsg[] =
124   "   skipping: %-22s  need %s compat. v%u.%u (can do v%u.%u)\n";
125 static ZCONST char Far ComprMsgNum[] =
126   "   skipping: %-22s  unsupported compression method %u\n";
127 #ifndef SFX
128    static ZCONST char Far ComprMsgName[] =
129      "   skipping: %-22s  `%s' method not supported\n";
130    static ZCONST char Far CmprNone[]       = "store";
131    static ZCONST char Far CmprShrink[]     = "shrink";
132    static ZCONST char Far CmprReduce[]     = "reduce";
133    static ZCONST char Far CmprImplode[]    = "implode";
134    static ZCONST char Far CmprTokenize[]   = "tokenize";
135    static ZCONST char Far CmprDeflate[]    = "deflate";
136    static ZCONST char Far CmprDeflat64[]   = "deflate64";
137    static ZCONST char Far CmprDCLImplode[] = "DCL implode";
138    static ZCONST char Far CmprBzip[]       = "bzip2";
139    static ZCONST char Far CmprLZMA[]       = "LZMA";
140    static ZCONST char Far CmprIBMTerse[]   = "IBM/Terse";
141    static ZCONST char Far CmprIBMLZ77[]    = "IBM LZ77";
142    static ZCONST char Far CmprWavPack[]    = "WavPack";
143    static ZCONST char Far CmprPPMd[]       = "PPMd";
144    static ZCONST char Far *ComprNames[NUM_METHODS] = {
145      CmprNone, CmprShrink, CmprReduce, CmprReduce, CmprReduce, CmprReduce,
146      CmprImplode, CmprTokenize, CmprDeflate, CmprDeflat64, CmprDCLImplode,
147      CmprBzip, CmprLZMA, CmprIBMTerse, CmprIBMLZ77, CmprWavPack, CmprPPMd
148    };
149    static ZCONST unsigned ComprIDs[NUM_METHODS] = {
150      STORED, SHRUNK, REDUCED1, REDUCED2, REDUCED3, REDUCED4,
151      IMPLODED, TOKENIZED, DEFLATED, ENHDEFLATED, DCLIMPLODED,
152      BZIPPED, LZMAED, IBMTERSED, IBMLZ77ED, WAVPACKED, PPMDED
153    };
154 #endif /* !SFX */
155 static ZCONST char Far FilNamMsg[] =
156   "%s:  bad filename length (%s)\n";
157 #ifndef SFX
158    static ZCONST char Far WarnNoMemCFName[] =
159      "%s:  warning, no memory for comparison with local header\n";
160    static ZCONST char Far LvsCFNamMsg[] =
161      "%s:  mismatching \"local\" filename (%s),\n\
162          continuing with \"central\" filename version\n";
163 #endif /* !SFX */
164 #if (!defined(SFX) && defined(UNICODE_SUPPORT))
165    static ZCONST char Far GP11FlagsDiffer[] =
166      "file #%lu (%s):\n\
167          mismatch between local and central GPF bit 11 (\"UTF-8\"),\n\
168          continuing with central flag (IsUTF8 = %d)\n";
169 #endif /* !SFX && UNICODE_SUPPORT */
170 static ZCONST char Far WrnStorUCSizCSizDiff[] =
171   "%s:  ucsize %s <> csize %s for STORED entry\n\
172          continuing with \"compressed\" size value\n";
173 static ZCONST char Far ExtFieldMsg[] =
174   "%s:  bad extra field length (%s)\n";
175 static ZCONST char Far OffsetMsg[] =
176   "file #%lu:  bad zipfile offset (%s):  %ld\n";
177 static ZCONST char Far ExtractMsg[] =
178   "%8sing: %-22s  %s%s";
179 #ifndef SFX
180    static ZCONST char Far LengthMsg[] =
181      "%s  %s:  %s bytes required to uncompress to %s bytes;\n    %s\
182       supposed to require %s bytes%s%s%s\n";
183 #endif
184 
185 static ZCONST char Far BadFileCommLength[] = "%s:  bad file comment length\n";
186 static ZCONST char Far LocalHdrSig[] = "local header sig";
187 static ZCONST char Far BadLocalHdr[] = "file #%lu:  bad local header\n";
188 static ZCONST char Far AttemptRecompensate[] =
189   "  (attempting to re-compensate)\n";
190 #ifndef SFX
191    static ZCONST char Far BackslashPathSep[] =
192      "warning:  %s appears to use backslashes as path separators\n";
193 #endif
194 static ZCONST char Far AbsolutePathWarning[] =
195   "warning:  stripped absolute path spec from %s\n";
196 static ZCONST char Far SkipVolumeLabel[] =
197   "   skipping: %-22s  %svolume label\n";
198 
199 #ifdef SET_DIR_ATTRIB   /* messages of code for setting directory attributes */
200    static ZCONST char Far DirlistEntryNoMem[] =
201      "warning:  cannot alloc memory for dir times/permissions/UID/GID\n";
202    static ZCONST char Far DirlistSortNoMem[] =
203      "warning:  cannot alloc memory to sort dir times/perms/etc.\n";
204    static ZCONST char Far DirlistSetAttrFailed[] =
205      "warning:  set times/attribs failed for %s\n";
206    static ZCONST char Far DirlistFailAttrSum[] =
207      "     failed setting times/attribs for %lu dir entries";
208 #endif
209 
210 #ifdef SYMLINKS         /* messages of the deferred symlinks handler */
211    static ZCONST char Far SymLnkWarnNoMem[] =
212      "warning:  deferred symlink (%s) failed:\n\
213           out of memory\n";
214    static ZCONST char Far SymLnkWarnInvalid[] =
215      "warning:  deferred symlink (%s) failed:\n\
216           invalid placeholder file\n";
217    static ZCONST char Far SymLnkDeferred[] =
218      "finishing deferred symbolic links:\n";
219    static ZCONST char Far SymLnkFinish[] =
220      "  %-22s -> %s\n";
221 #endif
222 
223 #ifndef WINDLL
224    static ZCONST char Far ReplaceQuery[] =
225 # ifdef VMS
226      "new version of %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ";
227 # else
228      "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ";
229 # endif
230    static ZCONST char Far AssumeNone[] =
231      " NULL\n(EOF or read error, treating as \"[N]one\" ...)\n";
232    static ZCONST char Far NewNameQuery[] = "new name: ";
233    static ZCONST char Far InvalidResponse[] =
234      "error:  invalid response [%s]\n";
235 #endif /* !WINDLL */
236 
237 static ZCONST char Far ErrorInArchive[] =
238   "At least one %serror was detected in %s.\n";
239 static ZCONST char Far ZeroFilesTested[] =
240   "Caution:  zero files tested in %s.\n";
241 
242 #ifndef VMS
243    static ZCONST char Far VMSFormatQuery[] =
244      "\n%s:  stored in VMS format.  Extract anyway? (y/n) ";
245 #endif
246 
247 #if CRYPT
248    static ZCONST char Far SkipCannotGetPasswd[] =
249      "   skipping: %-22s  unable to get password\n";
250    static ZCONST char Far SkipIncorrectPasswd[] =
251      "   skipping: %-22s  incorrect password\n";
252    static ZCONST char Far FilesSkipBadPasswd[] =
253      "%lu file%s skipped because of incorrect password.\n";
254    static ZCONST char Far MaybeBadPasswd[] =
255      "    (may instead be incorrect password)\n";
256 #else
257    static ZCONST char Far SkipEncrypted[] =
258      "   skipping: %-22s  encrypted (not supported)\n";
259 #endif
260 
261 static ZCONST char Far NoErrInCompData[] =
262   "No errors detected in compressed data of %s.\n";
263 static ZCONST char Far NoErrInTestedFiles[] =
264   "No errors detected in %s for the %lu file%s tested.\n";
265 static ZCONST char Far FilesSkipped[] =
266   "%lu file%s skipped because of unsupported compression or encoding.\n";
267 
268 static ZCONST char Far ErrUnzipFile[] = "  error:  %s%s %s\n";
269 static ZCONST char Far ErrUnzipNoFile[] = "\n  error:  %s%s\n";
270 static ZCONST char Far NotEnoughMem[] = "not enough memory to ";
271 static ZCONST char Far InvalidComprData[] = "invalid compressed data to ";
272 static ZCONST char Far Inflate[] = "inflate";
273 #ifdef USE_BZIP2
274   static ZCONST char Far BUnzip[] = "bunzip";
275 #endif
276 
277 #ifndef SFX
278    static ZCONST char Far Explode[] = "explode";
279 #ifndef LZW_CLEAN
280    static ZCONST char Far Unshrink[] = "unshrink";
281 #endif
282 #endif
283 
284 #if (!defined(DELETE_IF_FULL) || !defined(HAVE_UNLINK))
285    static ZCONST char Far FileTruncated[] =
286      "warning:  %s is probably truncated\n";
287 #endif
288 
289 static ZCONST char Far FileUnknownCompMethod[] =
290   "%s:  unknown compression method\n";
291 static ZCONST char Far BadCRC[] = " bad CRC %08lx  (should be %08lx)\n";
292 
293       /* TruncEAs[] also used in OS/2 mapname(), close_outfile() */
294 char ZCONST Far TruncEAs[] = " compressed EA data missing (%d bytes)%s";
295 char ZCONST Far TruncNTSD[] =
296   " compressed WinNT security data missing (%d bytes)%s";
297 
298 #ifndef SFX
299    static ZCONST char Far InconsistEFlength[] = "bad extra-field entry:\n \
300      EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n";
301    static ZCONST char Far TooSmallEFlength[] = "bad extra-field entry:\n \
302      EF block length (%u bytes) invalid (< %d)\n";
303    static ZCONST char Far InvalidComprDataEAs[] =
304      " invalid compressed data for EAs\n";
305 #  if (defined(WIN32) && defined(NTSD_EAS))
306      static ZCONST char Far InvalidSecurityEAs[] =
307        " EAs fail security check\n";
308 #  endif
309    static ZCONST char Far UnsuppNTSDVersEAs[] =
310      " unsupported NTSD EAs version %d\n";
311    static ZCONST char Far BadCRC_EAs[] = " bad CRC for extended attributes\n";
312    static ZCONST char Far UnknComprMethodEAs[] =
313      " unknown compression method for EAs (%u)\n";
314    static ZCONST char Far NotEnoughMemEAs[] =
315      " out of memory while inflating EAs\n";
316    static ZCONST char Far UnknErrorEAs[] =
317      " unknown error on extended attributes\n";
318 #endif /* !SFX */
319 
320 static ZCONST char Far UnsupportedExtraField[] =
321   "\nerror:  unsupported extra-field compression type (%u)--skipping\n";
322 static ZCONST char Far BadExtraFieldCRC[] =
323   "error [%s]:  bad extra-field CRC %08lx (should be %08lx)\n";
324 
325 
326 
327 
328 
329 /**************************************/
330 /*  Function extract_or_test_files()  */
331 /**************************************/
332 
extract_or_test_files(__G)333 int extract_or_test_files(__G)    /* return PK-type error code */
334      __GDEF
335 {
336     unsigned i, j;
337     zoff_t cd_bufstart;
338     uch *cd_inptr;
339     int cd_incnt;
340     ulg filnum=0L, blknum=0L;
341     int reached_end;
342 #ifndef SFX
343     int no_endsig_found;
344 #endif
345     int error, error_in_archive=PK_COOL;
346     int *fn_matched=NULL, *xn_matched=NULL;
347     zucn_t members_processed;
348     ulg num_skipped=0L, num_bad_pwd=0L;
349     zoff_t old_extra_bytes = 0L;
350 #ifdef SET_DIR_ATTRIB
351     unsigned num_dirs=0;
352     direntry *dirlist=(direntry *)NULL, **sorted_dirlist=(direntry **)NULL;
353 #endif
354 
355     /*
356      * First, two general initializations are applied. These have been moved
357      * here from process_zipfiles() because they are only needed for accessing
358      * and/or extracting the data content of the zip archive.
359      */
360 
361     /* a) initialize the CRC table pointer (once) */
362     if (CRC_32_TAB == NULL) {
363         if ((CRC_32_TAB = get_crc_table()) == NULL) {
364             return PK_MEM;
365         }
366     }
367 
368 #if (!defined(SFX) || defined(SFX_EXDIR))
369     /* b) check out if specified extraction root directory exists */
370     if (uO.exdir != (char *)NULL && G.extract_flag) {
371         G.create_dirs = !uO.fflag;
372         if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) {
373             /* out of memory, or file in way */
374             return (error == MPN_NOMEM ? PK_MEM : PK_ERR);
375         }
376     }
377 #endif /* !SFX || SFX_EXDIR */
378 
379 /*---------------------------------------------------------------------------
380     The basic idea of this function is as follows.  Since the central di-
381     rectory lies at the end of the zipfile and the member files lie at the
382     beginning or middle or wherever, it is not very desirable to simply
383     read a central directory entry, jump to the member and extract it, and
384     then jump back to the central directory.  In the case of a large zipfile
385     this would lead to a whole lot of disk-grinding, especially if each mem-
386     ber file is small.  Instead, we read from the central directory the per-
387     tinent information for a block of files, then go extract/test the whole
388     block.  Thus this routine contains two small(er) loops within a very
389     large outer loop:  the first of the small ones reads a block of files
390     from the central directory; the second extracts or tests each file; and
391     the outer one loops over blocks.  There's some file-pointer positioning
392     stuff in between, but that's about it.  Btw, it's because of this jump-
393     ing around that we can afford to be lenient if an error occurs in one of
394     the member files:  we should still be able to go find the other members,
395     since we know the offset of each from the beginning of the zipfile.
396   ---------------------------------------------------------------------------*/
397 
398     G.pInfo = G.info;
399 
400 #if CRYPT
401     G.newzip = TRUE;
402 #endif
403 #ifndef SFX
404     G.reported_backslash = FALSE;
405 #endif
406 
407     /* malloc space for check on unmatched filespecs (OK if one or both NULL) */
408     if (G.filespecs > 0  &&
409         (fn_matched=(int *)malloc(G.filespecs*sizeof(int))) != (int *)NULL)
410         for (i = 0;  i < G.filespecs;  ++i)
411             fn_matched[i] = FALSE;
412     if (G.xfilespecs > 0  &&
413         (xn_matched=(int *)malloc(G.xfilespecs*sizeof(int))) != (int *)NULL)
414         for (i = 0;  i < G.xfilespecs;  ++i)
415             xn_matched[i] = FALSE;
416 
417 /*---------------------------------------------------------------------------
418     Begin main loop over blocks of member files.  We know the entire central
419     directory is on this disk:  we would not have any of this information un-
420     less the end-of-central-directory record was on this disk, and we would
421     not have gotten to this routine unless this is also the disk on which
422     the central directory starts.  In practice, this had better be the ONLY
423     disk in the archive, but we'll add multi-disk support soon.
424   ---------------------------------------------------------------------------*/
425 
426     members_processed = 0;
427 #ifndef SFX
428     no_endsig_found = FALSE;
429 #endif
430     reached_end = FALSE;
431     while (!reached_end) {
432         j = 0;
433 #ifdef AMIGA
434         memzero(G.filenotes, DIR_BLKSIZ * sizeof(char *));
435 #endif
436 
437         /*
438          * Loop through files in central directory, storing offsets, file
439          * attributes, case-conversion and text-conversion flags until block
440          * size is reached.
441          */
442 
443         while ((j < DIR_BLKSIZ)) {
444             G.pInfo = &G.info[j];
445 
446             if (readbuf(__G__ G.sig, 4) == 0) {
447                 error_in_archive = PK_EOF;
448                 reached_end = TRUE;     /* ...so no more left to do */
449                 break;
450             }
451             if (memcmp(G.sig, central_hdr_sig, 4)) {  /* is it a new entry? */
452                 /* no new central directory entry
453                  * -> is the number of processed entries compatible with the
454                  *    number of entries as stored in the end_central record?
455                  */
456                 if ((members_processed
457                      & (G.ecrec.have_ecr64 ? MASK_ZUCN64 : MASK_ZUCN16))
458                     == G.ecrec.total_entries_central_dir) {
459 #ifndef SFX
460                     /* yes, so look if we ARE back at the end_central record
461                      */
462                     no_endsig_found =
463                       ( (memcmp(G.sig,
464                                 (G.ecrec.have_ecr64 ?
465                                  end_central64_sig : end_central_sig),
466                                 4) != 0)
467                        && (!G.ecrec.is_zip64_archive)
468                        && (memcmp(G.sig, end_central_sig, 4) != 0)
469                       );
470 #endif /* !SFX */
471                 } else {
472                     /* no; we have found an error in the central directory
473                      * -> report it and stop searching for more Zip entries
474                      */
475                     Info(slide, 0x401, ((char *)slide,
476                       LoadFarString(CentSigMsg), j + blknum*DIR_BLKSIZ + 1));
477                     Info(slide, 0x401, ((char *)slide,
478                       LoadFarString(ReportMsg)));
479                     error_in_archive = PK_BADERR;
480                 }
481                 reached_end = TRUE;     /* ...so no more left to do */
482                 break;
483             }
484             /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */
485             if ((error = process_cdir_file_hdr(__G)) != PK_COOL) {
486                 error_in_archive = error;   /* only PK_EOF defined */
487                 reached_end = TRUE;     /* ...so no more left to do */
488                 break;
489             }
490             if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) !=
491                  PK_COOL)
492             {
493                 if (error > error_in_archive)
494                     error_in_archive = error;
495                 if (error > PK_WARN) {  /* fatal:  no more left to do */
496                     Info(slide, 0x401, ((char *)slide,
497                       LoadFarString(FilNamMsg),
498                       FnFilter1(G.filename), "central"));
499                     reached_end = TRUE;
500                     break;
501                 }
502             }
503             if ((error = do_string(__G__ G.crec.extra_field_length,
504                 EXTRA_FIELD)) != 0)
505             {
506                 if (error > error_in_archive)
507                     error_in_archive = error;
508                 if (error > PK_WARN) {  /* fatal */
509                     Info(slide, 0x401, ((char *)slide,
510                       LoadFarString(ExtFieldMsg),
511                       FnFilter1(G.filename), "central"));
512                     reached_end = TRUE;
513                     break;
514                 }
515             }
516 #ifdef AMIGA
517             G.filenote_slot = j;
518             if ((error = do_string(__G__ G.crec.file_comment_length,
519                                    uO.N_flag ? FILENOTE : SKIP)) != PK_COOL)
520 #else
521             if ((error = do_string(__G__ G.crec.file_comment_length, SKIP))
522                 != PK_COOL)
523 #endif
524             {
525                 if (error > error_in_archive)
526                     error_in_archive = error;
527                 if (error > PK_WARN) {  /* fatal */
528                     Info(slide, 0x421, ((char *)slide,
529                       LoadFarString(BadFileCommLength),
530                       FnFilter1(G.filename)));
531                     reached_end = TRUE;
532                     break;
533                 }
534             }
535             if (G.process_all_files) {
536                 if (store_info(__G))
537                     ++j;  /* file is OK; info[] stored; continue with next */
538                 else
539                     ++num_skipped;
540             } else {
541                 int   do_this_file;
542 
543                 if (G.filespecs == 0)
544                     do_this_file = TRUE;
545                 else {  /* check if this entry matches an `include' argument */
546                     do_this_file = FALSE;
547                     for (i = 0; i < G.filespecs; i++)
548                         if (match(G.filename, G.pfnames[i], uO.C_flag WISEP)) {
549                             do_this_file = TRUE;  /* ^-- ignore case or not? */
550                             if (fn_matched)
551                                 fn_matched[i] = TRUE;
552                             break;       /* found match, so stop looping */
553                         }
554                 }
555                 if (do_this_file) {  /* check if this is an excluded file */
556                     for (i = 0; i < G.xfilespecs; i++)
557                         if (match(G.filename, G.pxnames[i], uO.C_flag WISEP)) {
558                             do_this_file = FALSE; /* ^-- ignore case or not? */
559                             if (xn_matched)
560                                 xn_matched[i] = TRUE;
561                             break;
562                         }
563                 }
564                 if (do_this_file) {
565                     if (store_info(__G))
566                         ++j;            /* file is OK */
567                     else
568                         ++num_skipped;  /* unsupp. compression or encryption */
569                 }
570             } /* end if (process_all_files) */
571 
572             members_processed++;
573 
574         } /* end while-loop (adding files to current block) */
575 
576         /* save position in central directory so can come back later */
577         cd_bufstart = G.cur_zipfile_bufstart;
578         cd_inptr = G.inptr;
579         cd_incnt = G.incnt;
580 
581     /*-----------------------------------------------------------------------
582         Second loop:  process files in current block, extracting or testing
583         each one.
584       -----------------------------------------------------------------------*/
585 
586         error = extract_or_test_entrylist(__G__ j,
587                         &filnum, &num_bad_pwd, &old_extra_bytes,
588 #ifdef SET_DIR_ATTRIB
589                         &num_dirs, &dirlist,
590 #endif
591                         error_in_archive);
592         if (error != PK_COOL) {
593             if (error > error_in_archive)
594                 error_in_archive = error;
595             /* ...and keep going (unless disk full or user break) */
596             if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
597                 /* clear reached_end to signal premature stop ... */
598                 reached_end = FALSE;
599                 /* ... and cancel scanning the central directory */
600                 break;
601             }
602         }
603 
604 
605         /*
606          * Jump back to where we were in the central directory, then go and do
607          * the next batch of files.
608          */
609 
610 #ifdef USE_STRM_INPUT
611         zfseeko(G.zipfd, cd_bufstart, SEEK_SET);
612         G.cur_zipfile_bufstart = zftello(G.zipfd);
613 #else /* !USE_STRM_INPUT */
614         G.cur_zipfile_bufstart =
615           zlseek(G.zipfd, cd_bufstart, SEEK_SET);
616 #endif /* ?USE_STRM_INPUT */
617         read(G.zipfd, (char *)G.inbuf, INBUFSIZ);  /* been here before... */
618         G.inptr = cd_inptr;
619         G.incnt = cd_incnt;
620         ++blknum;
621 
622 #ifdef TEST
623         printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart);
624         printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart,
625           cur_zipfile_bufstart);
626         printf("inptr-inbuf = %d\n", G.inptr-G.inbuf);
627         printf("incnt = %d\n\n", G.incnt);
628 #endif
629 
630     } /* end while-loop (blocks of files in central directory) */
631 
632 /*---------------------------------------------------------------------------
633     Process the list of deferred symlink extractions and finish up
634     the symbolic links.
635   ---------------------------------------------------------------------------*/
636 
637 #ifdef SYMLINKS
638     if (G.slink_last != NULL) {
639         if (QCOND2)
640             Info(slide, 0, ((char *)slide, LoadFarString(SymLnkDeferred)));
641         while (G.slink_head != NULL) {
642            set_deferred_symlink(__G__ G.slink_head);
643            /* remove the processed entry from the chain and free its memory */
644            G.slink_last = G.slink_head;
645            G.slink_head = G.slink_last->next;
646            free(G.slink_last);
647        }
648        G.slink_last = NULL;
649     }
650 #endif /* SYMLINKS */
651 
652 /*---------------------------------------------------------------------------
653     Go back through saved list of directories, sort and set times/perms/UIDs
654     and GIDs from the deepest level on up.
655   ---------------------------------------------------------------------------*/
656 
657 #ifdef SET_DIR_ATTRIB
658     if (num_dirs > 0) {
659         sorted_dirlist = (direntry **)malloc(num_dirs*sizeof(direntry *));
660         if (sorted_dirlist == (direntry **)NULL) {
661             Info(slide, 0x401, ((char *)slide,
662               LoadFarString(DirlistSortNoMem)));
663             while (dirlist != (direntry *)NULL) {
664                 direntry *d = dirlist;
665 
666                 dirlist = dirlist->next;
667                 free(d);
668             }
669         } else {
670             ulg ndirs_fail = 0;
671 
672             if (num_dirs == 1)
673                 sorted_dirlist[0] = dirlist;
674             else {
675                 for (i = 0;  i < num_dirs;  ++i) {
676                     sorted_dirlist[i] = dirlist;
677                     dirlist = dirlist->next;
678                 }
679                 qsort((char *)sorted_dirlist, num_dirs, sizeof(direntry *),
680                   dircomp);
681             }
682 
683             Trace((stderr, "setting directory times/perms/attributes\n"));
684             for (i = 0;  i < num_dirs;  ++i) {
685                 direntry *d = sorted_dirlist[i];
686 
687                 Trace((stderr, "dir = %s\n", d->fn));
688                 if ((error = set_direc_attribs(__G__ d)) != PK_OK) {
689                     ndirs_fail++;
690                     Info(slide, 0x201, ((char *)slide,
691                       LoadFarString(DirlistSetAttrFailed), d->fn));
692                     if (!error_in_archive)
693                         error_in_archive = error;
694                 }
695                 free(d);
696             }
697             free(sorted_dirlist);
698             if (!uO.tflag && QCOND2) {
699                 if (ndirs_fail > 0)
700                     Info(slide, 0, ((char *)slide,
701                       LoadFarString(DirlistFailAttrSum), ndirs_fail));
702             }
703         }
704     }
705 #endif /* SET_DIR_ATTRIB */
706 
707 /*---------------------------------------------------------------------------
708     Check for unmatched filespecs on command line and print warning if any
709     found.  Free allocated memory.  (But suppress check when central dir
710     scan was interrupted prematurely.)
711   ---------------------------------------------------------------------------*/
712 
713     if (fn_matched) {
714         if (reached_end) for (i = 0;  i < G.filespecs;  ++i)
715             if (!fn_matched[i]) {
716 #ifdef DLL
717                 if (!G.redirect_data && !G.redirect_text)
718                     Info(slide, 0x401, ((char *)slide,
719                       LoadFarString(FilenameNotMatched), G.pfnames[i]));
720                 else
721                     setFileNotFound(__G);
722 #else
723                 Info(slide, 1, ((char *)slide,
724                   LoadFarString(FilenameNotMatched), G.pfnames[i]));
725 #endif
726                 if (error_in_archive <= PK_WARN)
727                     error_in_archive = PK_FIND;   /* some files not found */
728             }
729         free((zvoid *)fn_matched);
730     }
731     if (xn_matched) {
732         if (reached_end) for (i = 0;  i < G.xfilespecs;  ++i)
733             if (!xn_matched[i])
734                 Info(slide, 0x401, ((char *)slide,
735                   LoadFarString(ExclFilenameNotMatched), G.pxnames[i]));
736         free((zvoid *)xn_matched);
737     }
738 
739 /*---------------------------------------------------------------------------
740     Now, all locally allocated memory has been released.  When the central
741     directory processing has been interrupted prematurely, it is safe to
742     return immediately.  All completeness checks and summary messages are
743     skipped in this case.
744   ---------------------------------------------------------------------------*/
745     if (!reached_end)
746         return error_in_archive;
747 
748 /*---------------------------------------------------------------------------
749     Double-check that we're back at the end-of-central-directory record, and
750     print quick summary of results, if we were just testing the archive.  We
751     send the summary to stdout so that people doing the testing in the back-
752     ground and redirecting to a file can just do a "tail" on the output file.
753   ---------------------------------------------------------------------------*/
754 
755 #ifndef SFX
756     if (no_endsig_found) {                      /* just to make sure */
757         Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
758         Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg)));
759         if (!error_in_archive)       /* don't overwrite stronger error */
760             error_in_archive = PK_WARN;
761     }
762 #endif /* !SFX */
763     if (uO.tflag) {
764         ulg num = filnum - num_bad_pwd;
765 
766         if (uO.qflag < 2) {        /* GRR 930710:  was (uO.qflag == 1) */
767             if (error_in_archive)
768                 Info(slide, 0, ((char *)slide, LoadFarString(ErrorInArchive),
769                   (error_in_archive == PK_WARN)? "warning-" : "", G.zipfn));
770             else if (num == 0L)
771                 Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested),
772                   G.zipfn));
773             else if (G.process_all_files && (num_skipped+num_bad_pwd == 0L))
774                 Info(slide, 0, ((char *)slide, LoadFarString(NoErrInCompData),
775                   G.zipfn));
776             else
777                 Info(slide, 0, ((char *)slide, LoadFarString(NoErrInTestedFiles)
778                   , G.zipfn, num, (num==1L)? "":"s"));
779             if (num_skipped > 0L)
780                 Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipped),
781                   num_skipped, (num_skipped==1L)? "":"s"));
782 #if CRYPT
783             if (num_bad_pwd > 0L)
784                 Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipBadPasswd)
785                   , num_bad_pwd, (num_bad_pwd==1L)? "":"s"));
786 #endif /* CRYPT */
787         }
788     }
789 
790     /* give warning if files not tested or extracted (first condition can still
791      * happen if zipfile is empty and no files specified on command line) */
792 
793     if ((filnum == 0) && error_in_archive <= PK_WARN) {
794         if (num_skipped > 0L)
795             error_in_archive = IZ_UNSUP; /* unsupport. compression/encryption */
796         else
797             error_in_archive = PK_FIND;  /* no files found at all */
798     }
799 #if CRYPT
800     else if ((filnum == num_bad_pwd) && error_in_archive <= PK_WARN)
801         error_in_archive = IZ_BADPWD;    /* bad passwd => all files skipped */
802 #endif
803     else if ((num_skipped > 0L) && error_in_archive <= PK_WARN)
804         error_in_archive = IZ_UNSUP;     /* was PK_WARN; Jean-loup complained */
805 #if CRYPT
806     else if ((num_bad_pwd > 0L) && !error_in_archive)
807         error_in_archive = PK_WARN;
808 #endif
809 
810     return error_in_archive;
811 
812 } /* end function extract_or_test_files() */
813 
814 
815 
816 
817 
818 /***************************/
819 /*  Function store_info()  */
820 /***************************/
821 
store_info(__G)822 static int store_info(__G)   /* return 0 if skipping, 1 if OK */
823     __GDEF
824 {
825 #ifdef USE_BZIP2
826 #  define UNKN_BZ2 (G.crec.compression_method!=BZIPPED)
827 #else
828 #  define UNKN_BZ2 TRUE       /* bzip2 unknown */
829 #endif
830 
831 #ifdef USE_LZMA
832 #  define UNKN_LZMA (G.crec.compression_method!=LZMAED)
833 #else
834 #  define UNKN_LZMA TRUE      /* LZMA unknown */
835 #endif
836 
837 #ifdef USE_WAVP
838 #  define UNKN_WAVP (G.crec.compression_method!=WAVPACKED)
839 #else
840 #  define UNKN_WAVP TRUE      /* WavPack unknown */
841 #endif
842 
843 #ifdef USE_PPMD
844 #  define UNKN_PPMD (G.crec.compression_method!=PPMDED)
845 #else
846 #  define UNKN_PPMD TRUE      /* PPMd unknown */
847 #endif
848 
849 #ifdef SFX
850 #  ifdef USE_DEFLATE64
851 #    define UNKN_COMPR \
852      (G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \
853       && G.crec.compression_method>ENHDEFLATED \
854       && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
855 #  else
856 #    define UNKN_COMPR \
857      (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED\
858       && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
859 #  endif
860 #else
861 #  ifdef COPYRIGHT_CLEAN  /* no reduced files */
862 #    define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
863                       G.crec.compression_method <= REDUCED4)
864 #  else
865 #    define UNKN_RED  FALSE  /* reducing not unknown */
866 #  endif
867 #  ifdef LZW_CLEAN  /* no shrunk files */
868 #    define UNKN_SHR (G.crec.compression_method == SHRUNK)
869 #  else
870 #    define UNKN_SHR  FALSE  /* unshrinking not unknown */
871 #  endif
872 #  ifdef USE_DEFLATE64
873 #    define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
874      G.crec.compression_method==TOKENIZED || \
875      (G.crec.compression_method>ENHDEFLATED && UNKN_BZ2 && UNKN_LZMA \
876       && UNKN_WAVP && UNKN_PPMD))
877 #  else
878 #    define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
879      G.crec.compression_method==TOKENIZED || \
880      (G.crec.compression_method>DEFLATED && UNKN_BZ2 && UNKN_LZMA \
881       && UNKN_WAVP && UNKN_PPMD))
882 #  endif
883 #endif
884 
885 #if (defined(USE_BZIP2) && (UNZIP_VERSION < UNZIP_BZ2VERS))
886     int unzvers_support = (UNKN_BZ2 ? UNZIP_VERSION : UNZIP_BZ2VERS);
887 #   define UNZVERS_SUPPORT  unzvers_support
888 #else
889 #   define UNZVERS_SUPPORT  UNZIP_VERSION
890 #endif
891 
892 /*---------------------------------------------------------------------------
893     Check central directory info for version/compatibility requirements.
894   ---------------------------------------------------------------------------*/
895 
896     G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1;   /* bit field */
897     G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8;  /* bit */
898     G.pInfo->textfile = G.crec.internal_file_attributes & 1;    /* bit field */
899     G.pInfo->crc = G.crec.crc32;
900     G.pInfo->compr_size = G.crec.csize;
901     G.pInfo->uncompr_size = G.crec.ucsize;
902 
903     switch (uO.aflag) {
904         case 0:
905             G.pInfo->textmode = FALSE;   /* bit field */
906             break;
907         case 1:
908             G.pInfo->textmode = G.pInfo->textfile;   /* auto-convert mode */
909             break;
910         default:  /* case 2: */
911             G.pInfo->textmode = TRUE;
912             break;
913     }
914 
915     if (G.crec.version_needed_to_extract[1] == VMS_) {
916         if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) {
917             if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
918                 Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
919                   FnFilter1(G.filename), "VMS",
920                   G.crec.version_needed_to_extract[0] / 10,
921                   G.crec.version_needed_to_extract[0] % 10,
922                   VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10));
923             return 0;
924         }
925 #ifndef VMS   /* won't be able to use extra field, but still have data */
926         else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */
927             Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery),
928               FnFilter1(G.filename)));
929             fgets(G.answerbuf, sizeof(G.answerbuf), stdin);
930             if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y'))
931                 return 0;
932         }
933 #endif /* !VMS */
934     /* usual file type:  don't need VMS to extract */
935     } else if (G.crec.version_needed_to_extract[0] > UNZVERS_SUPPORT) {
936         if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
937             Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
938               FnFilter1(G.filename), "PK",
939               G.crec.version_needed_to_extract[0] / 10,
940               G.crec.version_needed_to_extract[0] % 10,
941               UNZVERS_SUPPORT / 10, UNZVERS_SUPPORT % 10));
942         return 0;
943     }
944 
945     if (UNKN_COMPR) {
946         if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) {
947 #ifndef SFX
948             unsigned cmpridx;
949 
950             if ((cmpridx = find_compr_idx(G.crec.compression_method))
951                 < NUM_METHODS)
952                 Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName),
953                   FnFilter1(G.filename),
954                   LoadFarStringSmall(ComprNames[cmpridx])));
955             else
956 #endif
957                 Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum),
958                   FnFilter1(G.filename),
959                   G.crec.compression_method));
960         }
961         return 0;
962     }
963 #if (!CRYPT)
964     if (G.pInfo->encrypted) {
965         if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
966             Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted),
967               FnFilter1(G.filename)));
968         return 0;
969     }
970 #endif /* !CRYPT */
971 
972 #ifndef SFX
973     /* store a copy of the central header filename for later comparison */
974     if ((G.pInfo->cfilname = zfmalloc(strlen(G.filename) + 1)) == NULL) {
975         Info(slide, 0x401, ((char *)slide, LoadFarString(WarnNoMemCFName),
976           FnFilter1(G.filename)));
977     } else
978         zfstrcpy(G.pInfo->cfilname, G.filename);
979 #endif /* !SFX */
980 
981     /* map whatever file attributes we have into the local format */
982     mapattr(__G);   /* GRR:  worry about return value later */
983 
984     G.pInfo->diskstart = G.crec.disk_number_start;
985     G.pInfo->offset = (zoff_t)G.crec.relative_offset_local_header;
986     return 1;
987 
988 } /* end function store_info() */
989 
990 
991 
992 
993 
994 #ifndef SFX
995 /*******************************/
996 /*  Function find_compr_idx()  */
997 /*******************************/
998 
find_compr_idx(compr_methodnum)999 unsigned find_compr_idx(compr_methodnum)
1000     unsigned compr_methodnum;
1001 {
1002     unsigned i;
1003 
1004     for (i = 0; i < NUM_METHODS; i++) {
1005         if (ComprIDs[i] == compr_methodnum) break;
1006     }
1007     return i;
1008 }
1009 #endif /* !SFX */
1010 
1011 
1012 
1013 
1014 
1015 /******************************************/
1016 /*  Function extract_or_test_entrylist()  */
1017 /******************************************/
1018 
1019 static int extract_or_test_entrylist(__G__ numchunk,
1020                 pfilnum, pnum_bad_pwd, pold_extra_bytes,
1021 #ifdef SET_DIR_ATTRIB
1022                 pnum_dirs, pdirlist,
1023 #endif
1024                 error_in_archive)    /* return PK-type error code */
1025     __GDEF
1026     unsigned numchunk;
1027     ulg *pfilnum;
1028     ulg *pnum_bad_pwd;
1029     zoff_t *pold_extra_bytes;
1030 #ifdef SET_DIR_ATTRIB
1031     unsigned *pnum_dirs;
1032     direntry **pdirlist;
1033 #endif
1034     int error_in_archive;
1035 {
1036     unsigned i;
1037     int renamed, query;
1038     int skip_entry;
1039     zoff_t bufstart, inbuf_offset, request;
1040     int error, errcode;
1041 
1042 /* possible values for local skip_entry flag: */
1043 #define SKIP_NO         0       /* do not skip this entry */
1044 #define SKIP_Y_EXISTING 1       /* skip this entry, do not overwrite file */
1045 #define SKIP_Y_NONEXIST 2       /* skip this entry, do not create new file */
1046 
1047     /*-----------------------------------------------------------------------
1048         Second loop:  process files in current block, extracting or testing
1049         each one.
1050       -----------------------------------------------------------------------*/
1051 
1052     for (i = 0; i < numchunk; ++i) {
1053         (*pfilnum)++;   /* *pfilnum = i + blknum*DIR_BLKSIZ + 1; */
1054         G.pInfo = &G.info[i];
1055 #ifdef NOVELL_BUG_FAILSAFE
1056         G.dne = FALSE;  /* assume file exists until stat() says otherwise */
1057 #endif
1058 
1059         /* if the target position is not within the current input buffer
1060          * (either haven't yet read far enough, or (maybe) skipping back-
1061          * ward), skip to the target position and reset readbuf(). */
1062 
1063         /* seek_zipf(__G__ pInfo->offset);  */
1064         request = G.pInfo->offset + G.extra_bytes;
1065         inbuf_offset = request % INBUFSIZ;
1066         bufstart = request - inbuf_offset;
1067 
1068         Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n",
1069           (long)request, (long)inbuf_offset));
1070         Trace((stderr,
1071           "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
1072           (long)bufstart, (long)G.cur_zipfile_bufstart));
1073         if (request < 0) {
1074             Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg),
1075               G.zipfn, LoadFarString(ReportMsg)));
1076             error_in_archive = PK_ERR;
1077             if (*pfilnum == 1 && G.extra_bytes != 0L) {
1078                 Info(slide, 0x401, ((char *)slide,
1079                   LoadFarString(AttemptRecompensate)));
1080                 *pold_extra_bytes = G.extra_bytes;
1081                 G.extra_bytes = 0L;
1082                 request = G.pInfo->offset;  /* could also check if != 0 */
1083                 inbuf_offset = request % INBUFSIZ;
1084                 bufstart = request - inbuf_offset;
1085                 Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n",
1086                   (long)request, (long)inbuf_offset));
1087                 Trace((stderr,
1088                   "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
1089                   (long)bufstart, (long)G.cur_zipfile_bufstart));
1090                 /* try again */
1091                 if (request < 0) {
1092                     Trace((stderr,
1093                       "debug: recompensated request still < 0\n"));
1094                     Info(slide, 0x401, ((char *)slide,
1095                       LoadFarStringSmall(SeekMsg),
1096                       G.zipfn, LoadFarString(ReportMsg)));
1097                     error_in_archive = PK_BADERR;
1098                     continue;
1099                 }
1100             } else {
1101                 error_in_archive = PK_BADERR;
1102                 continue;  /* this one hosed; try next */
1103             }
1104         }
1105 
1106         if (bufstart != G.cur_zipfile_bufstart) {
1107             Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n"));
1108 #ifdef USE_STRM_INPUT
1109             zfseeko(G.zipfd, bufstart, SEEK_SET);
1110             G.cur_zipfile_bufstart = zftello(G.zipfd);
1111 #else /* !USE_STRM_INPUT */
1112             G.cur_zipfile_bufstart =
1113               zlseek(G.zipfd, bufstart, SEEK_SET);
1114 #endif /* ?USE_STRM_INPUT */
1115             if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0)
1116             {
1117                 Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
1118                   *pfilnum, "lseek", (long)bufstart));
1119                 error_in_archive = PK_BADERR;
1120                 continue;   /* can still do next file */
1121             }
1122             G.inptr = G.inbuf + (int)inbuf_offset;
1123             G.incnt -= (int)inbuf_offset;
1124         } else {
1125             G.incnt += (int)(G.inptr-G.inbuf) - (int)inbuf_offset;
1126             G.inptr = G.inbuf + (int)inbuf_offset;
1127         }
1128 
1129         /* should be in proper position now, so check for sig */
1130         if (readbuf(__G__ G.sig, 4) == 0) {  /* bad offset */
1131             Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
1132               *pfilnum, "EOF", (long)request));
1133             error_in_archive = PK_BADERR;
1134             continue;   /* but can still try next one */
1135         }
1136         if (memcmp(G.sig, local_hdr_sig, 4)) {
1137             Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
1138               *pfilnum, LoadFarStringSmall(LocalHdrSig), (long)request));
1139             /*
1140                 GRRDUMP(G.sig, 4)
1141                 GRRDUMP(local_hdr_sig, 4)
1142              */
1143             error_in_archive = PK_ERR;
1144             if ((*pfilnum == 1 && G.extra_bytes != 0L) ||
1145                 (G.extra_bytes == 0L && *pold_extra_bytes != 0L)) {
1146                 Info(slide, 0x401, ((char *)slide,
1147                   LoadFarString(AttemptRecompensate)));
1148                 if (G.extra_bytes) {
1149                     *pold_extra_bytes = G.extra_bytes;
1150                     G.extra_bytes = 0L;
1151                 } else
1152                     G.extra_bytes = *pold_extra_bytes; /* third attempt */
1153                 if (((error = seek_zipf(__G__ G.pInfo->offset)) != PK_OK) ||
1154                     (readbuf(__G__ G.sig, 4) == 0)) {  /* bad offset */
1155                     if (error != PK_BADERR)
1156                       Info(slide, 0x401, ((char *)slide,
1157                         LoadFarString(OffsetMsg), *pfilnum, "EOF",
1158                         (long)request));
1159                     error_in_archive = PK_BADERR;
1160                     continue;   /* but can still try next one */
1161                 }
1162                 if (memcmp(G.sig, local_hdr_sig, 4)) {
1163                     Info(slide, 0x401, ((char *)slide,
1164                       LoadFarString(OffsetMsg), *pfilnum,
1165                       LoadFarStringSmall(LocalHdrSig), (long)request));
1166                     error_in_archive = PK_BADERR;
1167                     continue;
1168                 }
1169             } else
1170                 continue;  /* this one hosed; try next */
1171         }
1172         if ((error = process_local_file_hdr(__G)) != PK_COOL) {
1173             Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr),
1174               *pfilnum));
1175             error_in_archive = error;   /* only PK_EOF defined */
1176             continue;   /* can still try next one */
1177         }
1178 #if (!defined(SFX) && defined(UNICODE_SUPPORT))
1179         if (((G.lrec.general_purpose_bit_flag & (1 << 11)) == (1 << 11))
1180             != (G.pInfo->GPFIsUTF8 != 0)) {
1181             if (QCOND2) {
1182 #  ifdef SMALL_MEM
1183                 char *temp_cfilnam = slide + (7 * (WSIZE>>3));
1184 
1185                 zfstrcpy((char Far *)temp_cfilnam, G.pInfo->cfilname);
1186 #    define  cFile_PrintBuf  temp_cfilnam
1187 #  else
1188 #    define  cFile_PrintBuf  G.pInfo->cfilname
1189 #  endif
1190                 Info(slide, 0x421, ((char *)slide,
1191                   LoadFarStringSmall2(GP11FlagsDiffer),
1192                   *pfilnum, FnFilter1(cFile_PrintBuf), G.pInfo->GPFIsUTF8));
1193 #  undef    cFile_PrintBuf
1194             }
1195             if (error_in_archive < PK_WARN)
1196                 error_in_archive = PK_WARN;
1197         }
1198 #endif /* !SFX && UNICODE_SUPPORT */
1199         if ((error = do_string(__G__ G.lrec.filename_length, DS_FN_L)) !=
1200              PK_COOL)
1201         {
1202             if (error > error_in_archive)
1203                 error_in_archive = error;
1204             if (error > PK_WARN) {
1205                 Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg),
1206                   FnFilter1(G.filename), "local"));
1207                 continue;   /* go on to next one */
1208             }
1209         }
1210         if (G.extra_field != (uch *)NULL) {
1211             free(G.extra_field);
1212             G.extra_field = (uch *)NULL;
1213         }
1214         if ((error =
1215              do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0)
1216         {
1217             if (error > error_in_archive)
1218                 error_in_archive = error;
1219             if (error > PK_WARN) {
1220                 Info(slide, 0x401, ((char *)slide,
1221                   LoadFarString(ExtFieldMsg),
1222                   FnFilter1(G.filename), "local"));
1223                 continue;   /* go on */
1224             }
1225         }
1226 #ifndef SFX
1227         /* Filename consistency checks must come after reading in the local
1228          * extra field, so that a UTF-8 entry name e.f. block has already
1229          * been processed.
1230          */
1231         if (G.pInfo->cfilname != (char Far *)NULL) {
1232             if (zfstrcmp(G.pInfo->cfilname, G.filename) != 0) {
1233 #  ifdef SMALL_MEM
1234                 char *temp_cfilnam = slide + (7 * (WSIZE>>3));
1235 
1236                 zfstrcpy((char Far *)temp_cfilnam, G.pInfo->cfilname);
1237 #    define  cFile_PrintBuf  temp_cfilnam
1238 #  else
1239 #    define  cFile_PrintBuf  G.pInfo->cfilname
1240 #  endif
1241                 Info(slide, 0x401, ((char *)slide,
1242                   LoadFarStringSmall2(LvsCFNamMsg),
1243                   FnFilter2(cFile_PrintBuf), FnFilter1(G.filename)));
1244 #  undef    cFile_PrintBuf
1245                 zfstrcpy(G.filename, G.pInfo->cfilname);
1246                 if (error_in_archive < PK_WARN)
1247                     error_in_archive = PK_WARN;
1248             }
1249             zffree(G.pInfo->cfilname);
1250             G.pInfo->cfilname = (char Far *)NULL;
1251         }
1252 #endif /* !SFX */
1253         /* Size consistency checks must come after reading in the local extra
1254          * field, so that any Zip64 extension local e.f. block has already
1255          * been processed.
1256          */
1257         if (G.lrec.compression_method == STORED) {
1258             zusz_t csiz_decrypted = G.lrec.csize;
1259 
1260             if (G.pInfo->encrypted)
1261                 csiz_decrypted -= 12;
1262             if (G.lrec.ucsize != csiz_decrypted) {
1263                 Info(slide, 0x401, ((char *)slide,
1264                   LoadFarStringSmall2(WrnStorUCSizCSizDiff),
1265                   FnFilter1(G.filename),
1266                   FmZofft(G.lrec.ucsize, NULL, "u"),
1267                   FmZofft(csiz_decrypted, NULL, "u")));
1268                 G.lrec.ucsize = csiz_decrypted;
1269                 if (error_in_archive < PK_WARN)
1270                     error_in_archive = PK_WARN;
1271             }
1272         }
1273 
1274 #if CRYPT
1275         if (G.pInfo->encrypted &&
1276             (error = decrypt(__G__ uO.pwdarg)) != PK_COOL) {
1277             if (error == PK_WARN) {
1278                 if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
1279                     Info(slide, 0x401, ((char *)slide,
1280                       LoadFarString(SkipIncorrectPasswd),
1281                       FnFilter1(G.filename)));
1282                 ++(*pnum_bad_pwd);
1283             } else {  /* (error > PK_WARN) */
1284                 if (error > error_in_archive)
1285                     error_in_archive = error;
1286                 Info(slide, 0x401, ((char *)slide,
1287                   LoadFarString(SkipCannotGetPasswd),
1288                   FnFilter1(G.filename)));
1289             }
1290             continue;   /* go on to next file */
1291         }
1292 #endif /* CRYPT */
1293 
1294         /*
1295          * just about to extract file:  if extracting to disk, check if
1296          * already exists, and if so, take appropriate action according to
1297          * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
1298          * loop because we don't store the possibly renamed filename[] in
1299          * info[])
1300          */
1301 #ifdef DLL
1302         if (!uO.tflag && !uO.cflag && !G.redirect_data)
1303 #else
1304         if (!uO.tflag && !uO.cflag)
1305 #endif
1306         {
1307             renamed = FALSE;   /* user hasn't renamed output file yet */
1308 
1309 startover:
1310             query = FALSE;
1311             skip_entry = SKIP_NO;
1312             /* for files from DOS FAT, check for use of backslash instead
1313              *  of slash as directory separator (bug in some zipper(s); so
1314              *  far, not a problem in HPFS, NTFS or VFAT systems)
1315              */
1316 #ifndef SFX
1317             if (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/')) {
1318                 char *p=G.filename;
1319 
1320                 if (*p) do {
1321                     if (*p == '\\') {
1322                         if (!G.reported_backslash) {
1323                             Info(slide, 0x21, ((char *)slide,
1324                               LoadFarString(BackslashPathSep), G.zipfn));
1325                             G.reported_backslash = TRUE;
1326                             if (!error_in_archive)
1327                                 error_in_archive = PK_WARN;
1328                         }
1329                         *p = '/';
1330                     }
1331                 } while (*PREINCSTR(p));
1332             }
1333 #endif /* !SFX */
1334 
1335             if (!renamed) {
1336                /* remove absolute path specs */
1337                if (G.filename[0] == '/') {
1338                    Info(slide, 0x401, ((char *)slide,
1339                         LoadFarString(AbsolutePathWarning),
1340                         FnFilter1(G.filename)));
1341                    if (!error_in_archive)
1342                        error_in_archive = PK_WARN;
1343                    do {
1344                        char *p = G.filename + 1;
1345                        do {
1346                            *(p-1) = *p;
1347                        } while (*p++ != '\0');
1348                    } while (G.filename[0] == '/');
1349                }
1350             }
1351 
1352             /* mapname can create dirs if not freshening or if renamed */
1353             error = mapname(__G__ renamed);
1354             if ((errcode = error & ~MPN_MASK) != PK_OK &&
1355                 error_in_archive < errcode)
1356                 error_in_archive = errcode;
1357             if ((errcode = error & MPN_MASK) > MPN_INF_TRUNC) {
1358                 if (errcode == MPN_CREATED_DIR) {
1359 #ifdef SET_DIR_ATTRIB
1360                     direntry *d_entry;
1361 
1362                     error = defer_dir_attribs(__G__ &d_entry);
1363                     if (d_entry == (direntry *)NULL) {
1364                         /* There may be no dir_attribs info available, or
1365                          * we have encountered a mem allocation error.
1366                          * In case of an error, report it and set program
1367                          * error state to warning level.
1368                          */
1369                         if (error) {
1370                             Info(slide, 0x401, ((char *)slide,
1371                                  LoadFarString(DirlistEntryNoMem)));
1372                             if (!error_in_archive)
1373                                 error_in_archive = PK_WARN;
1374                         }
1375                     } else {
1376                         d_entry->next = (*pdirlist);
1377                         (*pdirlist) = d_entry;
1378                         ++(*pnum_dirs);
1379                     }
1380 #endif /* SET_DIR_ATTRIB */
1381                 } else if (errcode == MPN_VOL_LABEL) {
1382 #ifdef DOS_OS2_W32
1383                     Info(slide, 0x401, ((char *)slide,
1384                       LoadFarString(SkipVolumeLabel),
1385                       FnFilter1(G.filename),
1386                       uO.volflag? "hard disk " : ""));
1387 #else
1388                     Info(slide, 1, ((char *)slide,
1389                       LoadFarString(SkipVolumeLabel),
1390                       FnFilter1(G.filename), ""));
1391 #endif
1392                 } else if (errcode > MPN_INF_SKIP &&
1393                            error_in_archive < PK_ERR)
1394                     error_in_archive = PK_ERR;
1395                 Trace((stderr, "mapname(%s) returns error code = %d\n",
1396                   FnFilter1(G.filename), error));
1397                 continue;   /* go on to next file */
1398             }
1399 
1400 #ifdef QDOS
1401             QFilename(__G__ G.filename);
1402 #endif
1403             switch (check_for_newer(__G__ G.filename)) {
1404                 case DOES_NOT_EXIST:
1405 #ifdef NOVELL_BUG_FAILSAFE
1406                     G.dne = TRUE;   /* stat() says file DOES NOT EXIST */
1407 #endif
1408                     /* freshen (no new files): skip unless just renamed */
1409                     if (uO.fflag && !renamed)
1410                         skip_entry = SKIP_Y_NONEXIST;
1411                     break;
1412                 case EXISTS_AND_OLDER:
1413 #ifdef UNIXBACKUP
1414                     if (!uO.B_flag)
1415 #endif
1416                     {
1417                         if (IS_OVERWRT_NONE)
1418                             /* never overwrite:  skip file */
1419                             skip_entry = SKIP_Y_EXISTING;
1420                         else if (!IS_OVERWRT_ALL)
1421                             query = TRUE;
1422                     }
1423                     break;
1424                 case EXISTS_AND_NEWER:             /* (or equal) */
1425 #ifdef UNIXBACKUP
1426                     if ((!uO.B_flag && IS_OVERWRT_NONE) ||
1427 #else
1428                     if (IS_OVERWRT_NONE ||
1429 #endif
1430                         (uO.uflag && !renamed)) {
1431                         /* skip if update/freshen & orig name */
1432                         skip_entry = SKIP_Y_EXISTING;
1433                     } else {
1434 #ifdef UNIXBACKUP
1435                         if (!IS_OVERWRT_ALL && !uO.B_flag)
1436 #else
1437                         if (!IS_OVERWRT_ALL)
1438 #endif
1439                             query = TRUE;
1440                     }
1441                     break;
1442             }
1443 #ifdef VMS
1444             /* 2008-07-24 SMS.
1445              * On VMS, if the file name includes a version number,
1446              * and "-V" ("retain VMS version numbers", V_flag) is in
1447              * effect, then the VMS-specific code will handle any
1448              * conflicts with an existing file, making this query
1449              * redundant.  (Implicit "y" response here.)
1450              */
1451             if (query && uO.V_flag) {
1452                 /* Not discarding file versions.  Look for one. */
1453                 int cndx = strlen(G.filename) - 1;
1454 
1455                 while ((cndx > 0) && (isdigit(G.filename[cndx])))
1456                     cndx--;
1457                 if (G.filename[cndx] == ';')
1458                     /* File version found; skip the generic query,
1459                      * proceeding with its default response "y".
1460                      */
1461                     query = FALSE;
1462             }
1463 #endif /* VMS */
1464             if (query) {
1465 #ifdef WINDLL
1466                 switch (G.lpUserFunctions->replace != NULL ?
1467                         (*G.lpUserFunctions->replace)(G.filename, FILNAMSIZ) :
1468                         IDM_REPLACE_NONE) {
1469                     case IDM_REPLACE_RENAME:
1470                         _ISO_INTERN(G.filename);
1471                         renamed = TRUE;
1472                         goto startover;
1473                     case IDM_REPLACE_ALL:
1474                         G.overwrite_mode = OVERWRT_ALWAYS;
1475                         /* FALL THROUGH, extract */
1476                     case IDM_REPLACE_YES:
1477                         break;
1478                     case IDM_REPLACE_NONE:
1479                         G.overwrite_mode = OVERWRT_NEVER;
1480                         /* FALL THROUGH, skip */
1481                     case IDM_REPLACE_NO:
1482                         skip_entry = SKIP_Y_EXISTING;
1483                         break;
1484                 }
1485 #else /* !WINDLL */
1486                 extent fnlen;
1487 reprompt:
1488                 Info(slide, 0x81, ((char *)slide,
1489                   LoadFarString(ReplaceQuery),
1490                   FnFilter1(G.filename)));
1491                 if (fgets(G.answerbuf, sizeof(G.answerbuf), stdin)
1492                     == (char *)NULL) {
1493                     Info(slide, 1, ((char *)slide,
1494                       LoadFarString(AssumeNone)));
1495                     *G.answerbuf = 'N';
1496                     if (!error_in_archive)
1497                         error_in_archive = 1;  /* not extracted:  warning */
1498                 }
1499                 switch (*G.answerbuf) {
1500                     case 'r':
1501                     case 'R':
1502                         do {
1503                             Info(slide, 0x81, ((char *)slide,
1504                               LoadFarString(NewNameQuery)));
1505                             fgets(G.filename, FILNAMSIZ, stdin);
1506                             /* usually get \n here:  better check for it */
1507                             fnlen = strlen(G.filename);
1508                             if (lastchar(G.filename, fnlen) == '\n')
1509                                 G.filename[--fnlen] = '\0';
1510                         } while (fnlen == 0);
1511 #ifdef WIN32  /* WIN32 fgets( ... , stdin) returns OEM coded strings */
1512                         _OEM_INTERN(G.filename);
1513 #endif
1514                         renamed = TRUE;
1515                         goto startover;   /* sorry for a goto */
1516                     case 'A':   /* dangerous option:  force caps */
1517                         G.overwrite_mode = OVERWRT_ALWAYS;
1518                         /* FALL THROUGH, extract */
1519                     case 'y':
1520                     case 'Y':
1521                         break;
1522                     case 'N':
1523                         G.overwrite_mode = OVERWRT_NEVER;
1524                         /* FALL THROUGH, skip */
1525                     case 'n':
1526                         /* skip file */
1527                         skip_entry = SKIP_Y_EXISTING;
1528                         break;
1529                     case '\n':
1530                     case '\r':
1531                         /* Improve echo of '\n' and/or '\r'
1532                            (sizeof(G.answerbuf) == 10 (see globals.h), so
1533                            there is enough space for the provided text...) */
1534                         strcpy(G.answerbuf, "{ENTER}");
1535                         /* fall through ... */
1536                     default:
1537                         /* usually get \n here:  remove it for nice display
1538                            (fnlen can be re-used here, we are outside the
1539                            "enter new filename" loop) */
1540                         fnlen = strlen(G.answerbuf);
1541                         if (lastchar(G.answerbuf, fnlen) == '\n')
1542                             G.answerbuf[--fnlen] = '\0';
1543                         Info(slide, 1, ((char *)slide,
1544                           LoadFarString(InvalidResponse), G.answerbuf));
1545                         goto reprompt;   /* yet another goto? */
1546                 } /* end switch (*answerbuf) */
1547 #endif /* ?WINDLL */
1548             } /* end if (query) */
1549             if (skip_entry != SKIP_NO) {
1550 #ifdef WINDLL
1551                 if (skip_entry == SKIP_Y_EXISTING) {
1552                     /* report skipping of an existing entry */
1553                     Info(slide, 0, ((char *)slide,
1554                       ((IS_OVERWRT_NONE || !uO.uflag || renamed) ?
1555                        "Target file exists.  Skipping %s\n" :
1556                        "Target file newer.  Skipping %s\n"),
1557                       FnFilter1(G.filename)));
1558                 }
1559 #endif /* WINDLL */
1560                 continue;
1561             }
1562         } /* end if (extracting to disk) */
1563 
1564 #ifdef DLL
1565         if ((G.statreportcb != NULL) &&
1566             (*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn,
1567                               G.filename, NULL)) {
1568             return IZ_CTRLC;        /* cancel operation by user request */
1569         }
1570 #endif
1571 #ifdef MACOS  /* MacOS is no preemptive OS, thus call event-handling by hand */
1572         UserStop();
1573 #endif
1574 #ifdef AMIGA
1575         G.filenote_slot = i;
1576 #endif
1577         G.disk_full = 0;
1578         if ((error = extract_or_test_member(__G)) != PK_COOL) {
1579             if (error > error_in_archive)
1580                 error_in_archive = error;       /* ...and keep going */
1581 #ifdef DLL
1582             if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
1583 #else
1584             if (G.disk_full > 1) {
1585 #endif
1586                 return error_in_archive;        /* (unless disk full) */
1587             }
1588         }
1589 #ifdef DLL
1590         if ((G.statreportcb != NULL) &&
1591             (*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn,
1592                               G.filename, (zvoid *)&G.lrec.ucsize)) {
1593             return IZ_CTRLC;        /* cancel operation by user request */
1594         }
1595 #endif
1596 #ifdef MACOS  /* MacOS is no preemptive OS, thus call event-handling by hand */
1597         UserStop();
1598 #endif
1599     } /* end for-loop (i:  files in current block) */
1600 
1601     return error_in_archive;
1602 
1603 } /* end function extract_or_test_entrylist() */
1604 
1605 
1606 
1607 
1608 
1609 /* wsize is used in extract_or_test_member() and UZbunzip2() */
1610 #if (defined(DLL) && !defined(NO_SLIDE_REDIR))
1611 #  define wsize G._wsize    /* wsize is a variable */
1612 #else
1613 #  define wsize WSIZE       /* wsize is a constant */
1614 #endif
1615 
1616 /***************************************/
1617 /*  Function extract_or_test_member()  */
1618 /***************************************/
1619 
extract_or_test_member(__G)1620 static int extract_or_test_member(__G)    /* return PK-type error code */
1621      __GDEF
1622 {
1623     char *nul="[empty] ", *txt="[text]  ", *bin="[binary]";
1624 #ifdef CMS_MVS
1625     char *ebc="[ebcdic]";
1626 #endif
1627     register int b;
1628     int r, error=PK_COOL;
1629 
1630 
1631 /*---------------------------------------------------------------------------
1632     Initialize variables, buffers, etc.
1633   ---------------------------------------------------------------------------*/
1634 
1635     G.bits_left = 0;
1636     G.bitbuf = 0L;       /* unreduce and unshrink only */
1637     G.zipeof = 0;
1638     G.newfile = TRUE;
1639     G.crc32val = CRCVAL_INITIAL;
1640 
1641 #ifdef SYMLINKS
1642     /* If file is a (POSIX-compatible) symbolic link and we are extracting
1643      * to disk, prepare to restore the link. */
1644     G.symlnk = (G.pInfo->symlink &&
1645                 !uO.tflag && !uO.cflag && (G.lrec.ucsize > 0));
1646 #endif /* SYMLINKS */
1647 
1648     if (uO.tflag) {
1649         if (!uO.qflag)
1650             Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), "test",
1651               FnFilter1(G.filename), "", ""));
1652     } else {
1653 #ifdef DLL
1654         if (uO.cflag && !G.redirect_data)
1655 #else
1656         if (uO.cflag)
1657 #endif
1658         {
1659 #if (defined(OS2) && defined(__IBMC__) && (__IBMC__ >= 200))
1660             G.outfile = freopen("", "wb", stdout);   /* VAC++ ignores setmode */
1661 #else
1662             G.outfile = stdout;
1663 #endif
1664 #ifdef DOS_FLX_NLM_OS2_W32
1665 #if (defined(__HIGHC__) && !defined(FLEXOS))
1666             setmode(G.outfile, _BINARY);
1667 #else /* !(defined(__HIGHC__) && !defined(FLEXOS)) */
1668             setmode(fileno(G.outfile), O_BINARY);
1669 #endif /* ?(defined(__HIGHC__) && !defined(FLEXOS)) */
1670 #           define NEWLINE "\r\n"
1671 #else /* !DOS_FLX_NLM_OS2_W32 */
1672 #           define NEWLINE "\n"
1673 #endif /* ?DOS_FLX_NLM_OS2_W32 */
1674 #ifdef VMS
1675             /* VMS:  required even for stdout! */
1676             if ((r = open_outfile(__G)) != 0)
1677                 switch (r) {
1678                   case OPENOUT_SKIPOK:
1679                     return PK_OK;
1680                   case OPENOUT_SKIPWARN:
1681                     return PK_WARN;
1682                   default:
1683                     return PK_DISK;
1684                 }
1685         } else if ((r = open_outfile(__G)) != 0)
1686             switch (r) {
1687               case OPENOUT_SKIPOK:
1688                 return PK_OK;
1689               case OPENOUT_SKIPWARN:
1690                 return PK_WARN;
1691               default:
1692                 return PK_DISK;
1693             }
1694 #else /* !VMS */
1695         } else if (open_outfile(__G))
1696             return PK_DISK;
1697 #endif /* ?VMS */
1698     }
1699 
1700 /*---------------------------------------------------------------------------
1701     Unpack the file.
1702   ---------------------------------------------------------------------------*/
1703 
1704     defer_leftover_input(__G);    /* so NEXTBYTE bounds check will work */
1705     switch (G.lrec.compression_method) {
1706         case STORED:
1707             if (!uO.tflag && QCOND2) {
1708 #ifdef SYMLINKS
1709                 if (G.symlnk)   /* can also be deflated, but rarer... */
1710                     Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1711                       "link", FnFilter1(G.filename), "", ""));
1712                 else
1713 #endif /* SYMLINKS */
1714                 Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1715                   "extract", FnFilter1(G.filename),
1716                   (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1717                   "" : (G.lrec.ucsize == 0L? nul : (G.pInfo->textfile? txt :
1718                   bin)), uO.cflag? NEWLINE : ""));
1719             }
1720 #if (defined(DLL) && !defined(NO_SLIDE_REDIR))
1721             if (G.redirect_slide) {
1722                 wsize = G.redirect_size; redirSlide = G.redirect_buffer;
1723             } else {
1724                 wsize = WSIZE; redirSlide = slide;
1725             }
1726 #endif
1727             G.outptr = redirSlide;
1728             G.outcnt = 0L;
1729             while ((b = NEXTBYTE) != EOF) {
1730                 *G.outptr++ = (uch)b;
1731                 if (++G.outcnt == wsize) {
1732                     error = flush(__G__ redirSlide, G.outcnt, 0);
1733                     G.outptr = redirSlide;
1734                     G.outcnt = 0L;
1735                     if (error != PK_COOL || G.disk_full) break;
1736                 }
1737             }
1738             if (G.outcnt) {        /* flush final (partial) buffer */
1739                 r = flush(__G__ redirSlide, G.outcnt, 0);
1740                 if (error < r) error = r;
1741             }
1742             break;
1743 
1744 #ifndef SFX
1745 #ifndef LZW_CLEAN
1746         case SHRUNK:
1747             if (!uO.tflag && QCOND2) {
1748                 Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1749                   LoadFarStringSmall(Unshrink), FnFilter1(G.filename),
1750                   (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1751                   "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
1752             }
1753             if ((r = unshrink(__G)) != PK_COOL) {
1754                 if (r < PK_DISK) {
1755                     if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1756                         Info(slide, 0x401, ((char *)slide,
1757                           LoadFarStringSmall(ErrUnzipFile), r == PK_MEM3 ?
1758                           LoadFarString(NotEnoughMem) :
1759                           LoadFarString(InvalidComprData),
1760                           LoadFarStringSmall2(Unshrink),
1761                           FnFilter1(G.filename)));
1762                     else
1763                         Info(slide, 0x401, ((char *)slide,
1764                           LoadFarStringSmall(ErrUnzipNoFile), r == PK_MEM3 ?
1765                           LoadFarString(NotEnoughMem) :
1766                           LoadFarString(InvalidComprData),
1767                           LoadFarStringSmall2(Unshrink)));
1768                 }
1769                 error = r;
1770             }
1771             break;
1772 #endif /* !LZW_CLEAN */
1773 
1774 #ifndef COPYRIGHT_CLEAN
1775         case REDUCED1:
1776         case REDUCED2:
1777         case REDUCED3:
1778         case REDUCED4:
1779             if (!uO.tflag && QCOND2) {
1780                 Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1781                   "unreduc", FnFilter1(G.filename),
1782                   (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1783                   "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
1784             }
1785             if ((r = unreduce(__G)) != PK_COOL) {
1786                 /* unreduce() returns only PK_COOL, PK_DISK, or IZ_CTRLC */
1787                 error = r;
1788             }
1789             break;
1790 #endif /* !COPYRIGHT_CLEAN */
1791 
1792         case IMPLODED:
1793             if (!uO.tflag && QCOND2) {
1794                 Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1795                   "explod", FnFilter1(G.filename),
1796                   (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1797                   "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
1798             }
1799             if ((r = explode(__G)) != 0) {
1800                 if (r == 5) { /* treat 5 specially */
1801                     int warning = ((zusz_t)G.used_csize <= G.lrec.csize);
1802 
1803                     if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1804                         Info(slide, 0x401, ((char *)slide,
1805                           LoadFarString(LengthMsg),
1806                           "", warning ? "warning" : "error",
1807                           FmZofft(G.used_csize, NULL, NULL),
1808                           FmZofft(G.lrec.ucsize, NULL, "u"),
1809                           warning ? "  " : "",
1810                           FmZofft(G.lrec.csize, NULL, "u"),
1811                           " [", FnFilter1(G.filename), "]"));
1812                     else
1813                         Info(slide, 0x401, ((char *)slide,
1814                           LoadFarString(LengthMsg),
1815                           "\n", warning ? "warning" : "error",
1816                           FmZofft(G.used_csize, NULL, NULL),
1817                           FmZofft(G.lrec.ucsize, NULL, "u"),
1818                           warning ? "  " : "",
1819                           FmZofft(G.lrec.csize, NULL, "u"),
1820                           "", "", "."));
1821                     error = warning ? PK_WARN : PK_ERR;
1822                 } else if (r < PK_DISK) {
1823                     if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1824                         Info(slide, 0x401, ((char *)slide,
1825                           LoadFarStringSmall(ErrUnzipFile), r == 3?
1826                           LoadFarString(NotEnoughMem) :
1827                           LoadFarString(InvalidComprData),
1828                           LoadFarStringSmall2(Explode),
1829                           FnFilter1(G.filename)));
1830                     else
1831                         Info(slide, 0x401, ((char *)slide,
1832                           LoadFarStringSmall(ErrUnzipNoFile), r == 3?
1833                           LoadFarString(NotEnoughMem) :
1834                           LoadFarString(InvalidComprData),
1835                           LoadFarStringSmall2(Explode)));
1836                     error = ((r == 3) ? PK_MEM3 : PK_ERR);
1837                 } else {
1838                     error = r;
1839                 }
1840             }
1841             break;
1842 #endif /* !SFX */
1843 
1844         case DEFLATED:
1845 #ifdef USE_DEFLATE64
1846         case ENHDEFLATED:
1847 #endif
1848             if (!uO.tflag && QCOND2) {
1849                 Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1850                   "inflat", FnFilter1(G.filename),
1851                   (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1852                   "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
1853             }
1854 #ifndef USE_ZLIB  /* zlib's function is called inflate(), too */
1855 #  define UZinflate inflate
1856 #endif
1857             if ((r = UZinflate(__G__
1858                                (G.lrec.compression_method == ENHDEFLATED)))
1859                 != 0) {
1860                 if (r < PK_DISK) {
1861                     if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1862                         Info(slide, 0x401, ((char *)slide,
1863                           LoadFarStringSmall(ErrUnzipFile), r == 3?
1864                           LoadFarString(NotEnoughMem) :
1865                           LoadFarString(InvalidComprData),
1866                           LoadFarStringSmall2(Inflate),
1867                           FnFilter1(G.filename)));
1868                     else
1869                         Info(slide, 0x401, ((char *)slide,
1870                           LoadFarStringSmall(ErrUnzipNoFile), r == 3?
1871                           LoadFarString(NotEnoughMem) :
1872                           LoadFarString(InvalidComprData),
1873                           LoadFarStringSmall2(Inflate)));
1874                     error = ((r == 3) ? PK_MEM3 : PK_ERR);
1875                 } else {
1876                     error = r;
1877                 }
1878             }
1879             break;
1880 
1881 #ifdef USE_BZIP2
1882         case BZIPPED:
1883             if (!uO.tflag && QCOND2) {
1884                 Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
1885                   "bunzipp", FnFilter1(G.filename),
1886                   (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)?
1887                   "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
1888             }
1889             if ((r = UZbunzip2(__G)) != 0) {
1890                 if (r < PK_DISK) {
1891                     if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1892                         Info(slide, 0x401, ((char *)slide,
1893                           LoadFarStringSmall(ErrUnzipFile), r == 3?
1894                           LoadFarString(NotEnoughMem) :
1895                           LoadFarString(InvalidComprData),
1896                           LoadFarStringSmall2(BUnzip),
1897                           FnFilter1(G.filename)));
1898                     else
1899                         Info(slide, 0x401, ((char *)slide,
1900                           LoadFarStringSmall(ErrUnzipNoFile), r == 3?
1901                           LoadFarString(NotEnoughMem) :
1902                           LoadFarString(InvalidComprData),
1903                           LoadFarStringSmall2(BUnzip)));
1904                     error = ((r == 3) ? PK_MEM3 : PK_ERR);
1905                 } else {
1906                     error = r;
1907                 }
1908             }
1909             break;
1910 #endif /* USE_BZIP2 */
1911 
1912         default:   /* should never get to this point */
1913             Info(slide, 0x401, ((char *)slide,
1914               LoadFarString(FileUnknownCompMethod), FnFilter1(G.filename)));
1915             /* close and delete file before return? */
1916             undefer_input(__G);
1917             return PK_WARN;
1918 
1919     } /* end switch (compression method) */
1920 
1921 /*---------------------------------------------------------------------------
1922     Close the file and set its date and time (not necessarily in that order),
1923     and make sure the CRC checked out OK.  Logical-AND the CRC for 64-bit
1924     machines (redundant on 32-bit machines).
1925   ---------------------------------------------------------------------------*/
1926 
1927 #ifdef VMS                  /* VMS:  required even for stdout! (final flush) */
1928     if (!uO.tflag)           /* don't close NULL file */
1929         close_outfile(__G);
1930 #else
1931 #ifdef DLL
1932     if (!uO.tflag && (!uO.cflag || G.redirect_data)) {
1933         if (G.redirect_data)
1934             FINISH_REDIRECT();
1935         else
1936             close_outfile(__G);
1937     }
1938 #else
1939     if (!uO.tflag && !uO.cflag)   /* don't close NULL file or stdout */
1940         close_outfile(__G);
1941 #endif
1942 #endif /* VMS */
1943 
1944             /* GRR: CONVERT close_outfile() TO NON-VOID:  CHECK FOR ERRORS! */
1945 
1946 
1947     if (G.disk_full) {            /* set by flush() */
1948         if (G.disk_full > 1) {
1949 #if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK))
1950             /* delete the incomplete file if we can */
1951             if (unlink(G.filename) != 0)
1952                 Trace((stderr, "extract.c:  could not delete %s\n",
1953                   FnFilter1(G.filename)));
1954 #else
1955             /* warn user about the incomplete file */
1956             Info(slide, 0x421, ((char *)slide, LoadFarString(FileTruncated),
1957               FnFilter1(G.filename)));
1958 #endif
1959             error = PK_DISK;
1960         } else {
1961             error = PK_WARN;
1962         }
1963     }
1964 
1965     if (error > PK_WARN) {/* don't print redundant CRC error if error already */
1966         undefer_input(__G);
1967         return error;
1968     }
1969     if (G.crc32val != G.lrec.crc32) {
1970         /* if quiet enough, we haven't output the filename yet:  do it */
1971         if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
1972             Info(slide, 0x401, ((char *)slide, "%-22s ",
1973               FnFilter1(G.filename)));
1974         Info(slide, 0x401, ((char *)slide, LoadFarString(BadCRC), G.crc32val,
1975           G.lrec.crc32));
1976 #if CRYPT
1977         if (G.pInfo->encrypted)
1978             Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeBadPasswd)));
1979 #endif
1980         error = PK_ERR;
1981     } else if (uO.tflag) {
1982 #ifndef SFX
1983         if (G.extra_field) {
1984             if ((r = TestExtraField(__G__ G.extra_field,
1985                                     G.lrec.extra_field_length)) > error)
1986                 error = r;
1987         } else
1988 #endif /* !SFX */
1989         if (!uO.qflag)
1990             Info(slide, 0, ((char *)slide, " OK\n"));
1991     } else {
1992         if (QCOND2 && !error)   /* GRR:  is stdout reset to text mode yet? */
1993             Info(slide, 0, ((char *)slide, "\n"));
1994     }
1995 
1996     undefer_input(__G);
1997     return error;
1998 
1999 } /* end function extract_or_test_member() */
2000 
2001 
2002 
2003 
2004 
2005 #ifndef SFX
2006 
2007 /*******************************/
2008 /*  Function TestExtraField()  */
2009 /*******************************/
2010 
2011 static int TestExtraField(__G__ ef, ef_len)
2012     __GDEF
2013     uch *ef;
2014     unsigned ef_len;
2015 {
2016     ush ebID;
2017     unsigned ebLen;
2018     unsigned eb_cmpr_offs = 0;
2019     int r;
2020 
2021     /* we know the regular compressed file data tested out OK, or else we
2022      * wouldn't be here ==> print filename if any extra-field errors found
2023      */
2024     while (ef_len >= EB_HEADSIZE) {
2025         ebID = makeword(ef);
2026         ebLen = (unsigned)makeword(ef+EB_LEN);
2027 
2028         if (ebLen > (ef_len - EB_HEADSIZE))
2029         {
2030            /* Discovered some extra field inconsistency! */
2031             if (uO.qflag)
2032                 Info(slide, 1, ((char *)slide, "%-22s ",
2033                   FnFilter1(G.filename)));
2034             Info(slide, 1, ((char *)slide, LoadFarString(InconsistEFlength),
2035               ebLen, (ef_len - EB_HEADSIZE)));
2036             return PK_ERR;
2037         }
2038         else if (ebLen < EB_HEADSIZE)
2039         {
2040             /* Extra block length smaller than header length. */
2041             if (uO.qflag)
2042                 Info(slide, 1, ((char *)slide, "%-22s ",
2043                   FnFilter1(G.filename)));
2044             Info(slide, 1, ((char *)slide, LoadFarString(TooSmallEFlength),
2045               ebLen, EB_HEADSIZE));
2046             return PK_ERR;
2047         }
2048 
2049         switch (ebID) {
2050             case EF_OS2:
2051             case EF_ACL:
2052             case EF_MAC3:
2053             case EF_BEOS:
2054             case EF_ATHEOS:
2055                 switch (ebID) {
2056                   case EF_OS2:
2057                   case EF_ACL:
2058                     eb_cmpr_offs = EB_OS2_HLEN;
2059                     break;
2060                   case EF_MAC3:
2061                     if (ebLen >= EB_MAC3_HLEN &&
2062                         (makeword(ef+(EB_HEADSIZE+EB_FLGS_OFFS))
2063                          & EB_M3_FL_UNCMPR) &&
2064                         (makelong(ef+EB_HEADSIZE) == ebLen - EB_MAC3_HLEN))
2065                         eb_cmpr_offs = 0;
2066                     else
2067                         eb_cmpr_offs = EB_MAC3_HLEN;
2068                     break;
2069                   case EF_BEOS:
2070                   case EF_ATHEOS:
2071                     if (ebLen >= EB_BEOS_HLEN &&
2072                         (*(ef+(EB_HEADSIZE+EB_FLGS_OFFS)) & EB_BE_FL_UNCMPR) &&
2073                         (makelong(ef+EB_HEADSIZE) == ebLen - EB_BEOS_HLEN))
2074                         eb_cmpr_offs = 0;
2075                     else
2076                         eb_cmpr_offs = EB_BEOS_HLEN;
2077                     break;
2078                 }
2079                 if ((r = test_compr_eb(__G__ ef, ebLen, eb_cmpr_offs, NULL))
2080                     != PK_OK) {
2081                     if (uO.qflag)
2082                         Info(slide, 1, ((char *)slide, "%-22s ",
2083                           FnFilter1(G.filename)));
2084                     switch (r) {
2085                         case IZ_EF_TRUNC:
2086                             Info(slide, 1, ((char *)slide,
2087                               LoadFarString(TruncEAs),
2088                               ebLen-(eb_cmpr_offs+EB_CMPRHEADLEN), "\n"));
2089                             break;
2090                         case PK_ERR:
2091                             Info(slide, 1, ((char *)slide,
2092                               LoadFarString(InvalidComprDataEAs)));
2093                             break;
2094                         case PK_MEM3:
2095                         case PK_MEM4:
2096                             Info(slide, 1, ((char *)slide,
2097                               LoadFarString(NotEnoughMemEAs)));
2098                             break;
2099                         default:
2100                             if ((r & 0xff) != PK_ERR)
2101                                 Info(slide, 1, ((char *)slide,
2102                                   LoadFarString(UnknErrorEAs)));
2103                             else {
2104                                 ush m = (ush)(r >> 8);
2105                                 if (m == DEFLATED)            /* GRR KLUDGE! */
2106                                     Info(slide, 1, ((char *)slide,
2107                                       LoadFarString(BadCRC_EAs)));
2108                                 else
2109                                     Info(slide, 1, ((char *)slide,
2110                                       LoadFarString(UnknComprMethodEAs), m));
2111                             }
2112                             break;
2113                     }
2114                     return r;
2115                 }
2116                 break;
2117 
2118             case EF_NTSD:
2119                 Trace((stderr, "ebID: %i / ebLen: %u\n", ebID, ebLen));
2120                 r = ebLen < EB_NTSD_L_LEN ? IZ_EF_TRUNC :
2121                     ((ef[EB_HEADSIZE+EB_NTSD_VERSION] > EB_NTSD_MAX_VER) ?
2122                      (PK_WARN | 0x4000) :
2123                      test_compr_eb(__G__ ef, ebLen, EB_NTSD_L_LEN, TEST_NTSD));
2124                 if (r != PK_OK) {
2125                     if (uO.qflag)
2126                         Info(slide, 1, ((char *)slide, "%-22s ",
2127                           FnFilter1(G.filename)));
2128                     switch (r) {
2129                         case IZ_EF_TRUNC:
2130                             Info(slide, 1, ((char *)slide,
2131                               LoadFarString(TruncNTSD),
2132                               ebLen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n"));
2133                             break;
2134 #if (defined(WIN32) && defined(NTSD_EAS))
2135                         case PK_WARN:
2136                             Info(slide, 1, ((char *)slide,
2137                               LoadFarString(InvalidSecurityEAs)));
2138                             break;
2139 #endif
2140                         case PK_ERR:
2141                             Info(slide, 1, ((char *)slide,
2142                               LoadFarString(InvalidComprDataEAs)));
2143                             break;
2144                         case PK_MEM3:
2145                         case PK_MEM4:
2146                             Info(slide, 1, ((char *)slide,
2147                               LoadFarString(NotEnoughMemEAs)));
2148                             break;
2149                         case (PK_WARN | 0x4000):
2150                             Info(slide, 1, ((char *)slide,
2151                               LoadFarString(UnsuppNTSDVersEAs),
2152                               (int)ef[EB_HEADSIZE+EB_NTSD_VERSION]));
2153                             r = PK_WARN;
2154                             break;
2155                         default:
2156                             if ((r & 0xff) != PK_ERR)
2157                                 Info(slide, 1, ((char *)slide,
2158                                   LoadFarString(UnknErrorEAs)));
2159                             else {
2160                                 ush m = (ush)(r >> 8);
2161                                 if (m == DEFLATED)            /* GRR KLUDGE! */
2162                                     Info(slide, 1, ((char *)slide,
2163                                       LoadFarString(BadCRC_EAs)));
2164                                 else
2165                                     Info(slide, 1, ((char *)slide,
2166                                       LoadFarString(UnknComprMethodEAs), m));
2167                             }
2168                             break;
2169                     }
2170                     return r;
2171                 }
2172                 break;
2173             case EF_PKVMS:
2174                 if (makelong(ef+EB_HEADSIZE) !=
2175                     crc32(CRCVAL_INITIAL, ef+(EB_HEADSIZE+4),
2176                           (extent)(ebLen-4)))
2177                     Info(slide, 1, ((char *)slide,
2178                       LoadFarString(BadCRC_EAs)));
2179                 break;
2180             case EF_PKW32:
2181             case EF_PKUNIX:
2182             case EF_ASIUNIX:
2183             case EF_IZVMS:
2184             case EF_IZUNIX:
2185             case EF_VMCMS:
2186             case EF_MVS:
2187             case EF_SPARK:
2188             case EF_TANDEM:
2189             case EF_THEOS:
2190             case EF_AV:
2191             default:
2192                 break;
2193         }
2194         ef_len -= (ebLen + EB_HEADSIZE);
2195         ef += (ebLen + EB_HEADSIZE);
2196     }
2197 
2198     if (!uO.qflag)
2199         Info(slide, 0, ((char *)slide, " OK\n"));
2200 
2201     return PK_COOL;
2202 
2203 } /* end function TestExtraField() */
2204 
2205 
2206 
2207 
2208 
2209 /******************************/
2210 /*  Function test_compr_eb()  */
2211 /******************************/
2212 
2213 #ifdef PROTO
test_compr_eb(__GPRO__ uch * eb,unsigned eb_size,unsigned compr_offset,int (* test_uc_ebdata)(__GPRO__ uch * eb,unsigned eb_size,uch * eb_ucptr,ulg eb_ucsize))2214 static int test_compr_eb(
2215     __GPRO__
2216     uch *eb,
2217     unsigned eb_size,
2218     unsigned compr_offset,
2219     int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size,
2220                           uch *eb_ucptr, ulg eb_ucsize))
2221 #else /* !PROTO */
2222 static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
2223     __GDEF
2224     uch *eb;
2225     unsigned eb_size;
2226     unsigned compr_offset;
2227     int (*test_uc_ebdata)();
2228 #endif /* ?PROTO */
2229 {
2230     ulg eb_ucsize;
2231     uch *eb_ucptr;
2232     int r;
2233     ush method;
2234 
2235     if (compr_offset < 4)                /* field is not compressed: */
2236         return PK_OK;                    /* do nothing and signal OK */
2237 
2238     /* Return no/bad-data error status if any problem is found:
2239      *    1. eb_size is too small to hold the uncompressed size
2240      *       (eb_ucsize).  (Else extract eb_ucsize.)
2241      *    2. eb_ucsize is zero (invalid).  2014-12-04 SMS.
2242      *    3. eb_ucsize is positive, but eb_size is too small to hold
2243      *       the compressed data header.
2244      */
2245     if ((eb_size < (EB_UCSIZE_P + 4)) ||
2246      ((eb_ucsize = makelong( eb+ (EB_HEADSIZE+ EB_UCSIZE_P))) == 0L) ||
2247      ((eb_ucsize > 0L) && (eb_size <= (compr_offset + EB_CMPRHEADLEN))))
2248         return IZ_EF_TRUNC;             /* no/bad compressed data! */
2249 
2250     method = makeword(eb + (EB_HEADSIZE + compr_offset));
2251     if ((method == STORED) && (eb_size - compr_offset != eb_ucsize))
2252 	return PK_ERR;			  /* compressed & uncompressed
2253 					   * should match in STORED
2254 					   * method */
2255 
2256     if (
2257 #ifdef INT_16BIT
2258         (((ulg)(extent)eb_ucsize) != eb_ucsize) ||
2259 #endif
2260         (eb_ucptr = (uch *)malloc((extent)eb_ucsize)) == (uch *)NULL)
2261         return PK_MEM4;
2262 
2263     r = memextract(__G__ eb_ucptr, eb_ucsize,
2264                    eb + (EB_HEADSIZE + compr_offset),
2265                    (ulg)(eb_size - compr_offset));
2266 
2267     if (r == PK_OK && test_uc_ebdata != NULL)
2268         r = (*test_uc_ebdata)(__G__ eb, eb_size, eb_ucptr, eb_ucsize);
2269 
2270     free(eb_ucptr);
2271     return r;
2272 
2273 } /* end function test_compr_eb() */
2274 
2275 #endif /* !SFX */
2276 
2277 
2278 
2279 
2280 
2281 /***************************/
2282 /*  Function memextract()  */
2283 /***************************/
2284 
2285 int memextract(__G__ tgt, tgtsize, src, srcsize)  /* extract compressed */
2286     __GDEF                                        /*  extra field block; */
2287     uch *tgt;                                     /*  return PK-type error */
2288     ulg tgtsize;                                  /*  level */
2289     ZCONST uch *src;
2290     ulg srcsize;
2291 {
2292     zoff_t old_csize=G.csize;
2293     uch   *old_inptr=G.inptr;
2294     int    old_incnt=G.incnt;
2295     int    r, error=PK_OK;
2296     ush    method;
2297     ulg    extra_field_crc;
2298 
2299 
2300     method = makeword(src);
2301     extra_field_crc = makelong(src+2);
2302 
2303     /* compressed extra field exists completely in memory at this location: */
2304     G.inptr = (uch *)src + (2 + 4);     /* method and extra_field_crc */
2305     G.incnt = (int)(G.csize = (long)(srcsize - (2 + 4)));
2306     G.mem_mode = TRUE;
2307     G.outbufptr = tgt;
2308     G.outsize = tgtsize;
2309 
2310     switch (method) {
2311         case STORED:
2312             memcpy((char *)tgt, (char *)G.inptr, (extent)G.incnt);
2313             G.outcnt = (ulg)G.csize;    /* for CRC calculation */
2314             break;
2315         case DEFLATED:
2316 #ifdef USE_DEFLATE64
2317         case ENHDEFLATED:
2318 #endif
2319             G.outcnt = 0L;
2320             if ((r = UZinflate(__G__ (method == ENHDEFLATED))) != 0) {
2321                 if (!uO.tflag)
2322                     Info(slide, 0x401, ((char *)slide,
2323                       LoadFarStringSmall(ErrUnzipNoFile), r == 3?
2324                       LoadFarString(NotEnoughMem) :
2325                       LoadFarString(InvalidComprData),
2326                       LoadFarStringSmall2(Inflate)));
2327                 error = (r == 3)? PK_MEM3 : PK_ERR;
2328             }
2329             if (G.outcnt == 0L)   /* inflate's final FLUSH sets outcnt */
2330                 break;
2331             break;
2332         default:
2333             if (uO.tflag)
2334                 error = PK_ERR | ((int)method << 8);
2335             else {
2336                 Info(slide, 0x401, ((char *)slide,
2337                   LoadFarString(UnsupportedExtraField), method));
2338                 error = PK_ERR;  /* GRR:  should be passed on up via SetEAs() */
2339             }
2340             break;
2341     }
2342 
2343     G.inptr = old_inptr;
2344     G.incnt = old_incnt;
2345     G.csize = old_csize;
2346     G.mem_mode = FALSE;
2347 
2348     if (!error) {
2349         register ulg crcval = crc32(CRCVAL_INITIAL, tgt, (extent)G.outcnt);
2350 
2351         if (crcval != extra_field_crc) {
2352             if (uO.tflag)
2353                 error = PK_ERR | (DEFLATED << 8);  /* kludge for now */
2354             else {
2355                 Info(slide, 0x401, ((char *)slide,
2356                   LoadFarString(BadExtraFieldCRC), G.zipfn, crcval,
2357                   extra_field_crc));
2358                 error = PK_ERR;
2359             }
2360         }
2361     }
2362     return error;
2363 
2364 } /* end function memextract() */
2365 
2366 
2367 
2368 
2369 
2370 /*************************/
2371 /*  Function memflush()  */
2372 /*************************/
2373 
2374 int memflush(__G__ rawbuf, size)
2375     __GDEF
2376     ZCONST uch *rawbuf;
2377     ulg size;
2378 {
2379     if (size > G.outsize)
2380         /* Here, PK_DISK is a bit off-topic, but in the sense of marking
2381            "overflow of output space", its use may be tolerated. */
2382         return PK_DISK;   /* more data than output buffer can hold */
2383 
2384 
2385 
2386     memcpy((char *)G.outbufptr, (char *)rawbuf, (extent)size);
2387     G.outbufptr += (unsigned int)size;
2388     G.outsize -= size;
2389     G.outcnt += size;
2390 
2391     return 0;
2392 
2393 } /* end function memflush() */
2394 
2395 
2396 
2397 
2398 
2399 #if (defined(VMS) || defined(VMS_TEXT_CONV))
2400 
2401 /************************************/
2402 /*  Function extract_izvms_block()  */
2403 /************************************/
2404 
2405 /*
2406  * Extracts block from p. If resulting length is less than needed, fill
2407  * extra space with corresponding bytes from 'init'.
2408  * Currently understands 3 formats of block compression:
2409  * - Simple storing
2410  * - Compression of zero bytes to zero bits
2411  * - Deflation (see memextract())
2412  * The IZVMS block data is returned in malloc'd space.
2413  */
2414 uch *extract_izvms_block(__G__ ebdata, size, retlen, init, needlen)
2415     __GDEF
2416     ZCONST uch *ebdata;
2417     unsigned size;
2418     unsigned *retlen;
2419     ZCONST uch *init;
2420     unsigned needlen;
2421 {
2422     uch *ucdata;       /* Pointer to block allocated */
2423     int cmptype;
2424     unsigned usiz, csiz;
2425 
2426     cmptype = (makeword(ebdata+EB_IZVMS_FLGS) & EB_IZVMS_BCMASK);
2427     csiz = size - EB_IZVMS_HLEN;
2428     usiz = (cmptype == EB_IZVMS_BCSTOR ?
2429             csiz : makeword(ebdata+EB_IZVMS_UCSIZ));
2430 
2431     if (retlen)
2432         *retlen = usiz;
2433 
2434     if ((ucdata = (uch *)malloc(MAX(needlen, usiz))) == NULL)
2435         return NULL;
2436 
2437     if (init && (usiz < needlen))
2438         memcpy((char *)ucdata, (ZCONST char *)init, needlen);
2439 
2440     switch (cmptype)
2441     {
2442         case EB_IZVMS_BCSTOR: /* The simplest case */
2443             memcpy(ucdata, ebdata+EB_IZVMS_HLEN, usiz);
2444             break;
2445         case EB_IZVMS_BC00:
2446             decompress_bits(ucdata, usiz, ebdata+EB_IZVMS_HLEN);
2447             break;
2448         case EB_IZVMS_BCDEFL:
2449             memextract(__G__ ucdata, (ulg)usiz,
2450                        ebdata+EB_IZVMS_HLEN, (ulg)csiz);
2451             break;
2452         default:
2453             free(ucdata);
2454             ucdata = NULL;
2455     }
2456     return ucdata;
2457 
2458 } /* end of extract_izvms_block */
2459 
2460 
2461 
2462 
2463 
2464 /********************************/
2465 /*  Function decompress_bits()  */
2466 /********************************/
2467 /*
2468  *  Simple uncompression routine. The compression uses bit stream.
2469  *  Compression scheme:
2470  *
2471  *  if (byte!=0)
2472  *      putbit(1),putbyte(byte)
2473  *  else
2474  *      putbit(0)
2475  */
decompress_bits(outptr,needlen,bitptr)2476 static void decompress_bits(outptr, needlen, bitptr)
2477     uch *outptr;        /* Pointer into output block */
2478     unsigned needlen;   /* Size of uncompressed block */
2479     ZCONST uch *bitptr; /* Pointer into compressed data */
2480 {
2481     ulg bitbuf = 0;
2482     int bitcnt = 0;
2483 
2484 #define _FILL   {       bitbuf |= (*bitptr++) << bitcnt;\
2485                         bitcnt += 8;                    \
2486                 }
2487 
2488     while (needlen--)
2489     {
2490         if (bitcnt <= 0)
2491             _FILL;
2492 
2493         if (bitbuf & 1)
2494         {
2495             bitbuf >>= 1;
2496             if ((bitcnt -= 1) < 8)
2497                 _FILL;
2498             *outptr++ = (uch)bitbuf;
2499             bitcnt -= 8;
2500             bitbuf >>= 8;
2501         }
2502         else
2503         {
2504             *outptr++ = '\0';
2505             bitcnt -= 1;
2506             bitbuf >>= 1;
2507         }
2508     }
2509 } /* end function decompress_bits() */
2510 
2511 #endif /* VMS || VMS_TEXT_CONV */
2512 
2513 
2514 
2515 
2516 
2517 #ifdef SYMLINKS
2518 /***********************************/
2519 /* Function set_deferred_symlink() */
2520 /***********************************/
2521 
2522 static void set_deferred_symlink(__G__ slnk_entry)
2523     __GDEF
2524     slinkentry *slnk_entry;
2525 {
2526     extent ucsize = slnk_entry->targetlen;
2527     char *linkfname = slnk_entry->fname;
2528     char *linktarget = (char *)malloc(ucsize+1);
2529 
2530     if (!linktarget) {
2531         Info(slide, 0x201, ((char *)slide,
2532           LoadFarString(SymLnkWarnNoMem), FnFilter1(linkfname)));
2533         return;
2534     }
2535     linktarget[ucsize] = '\0';
2536     G.outfile = zfopen(linkfname, FOPR); /* open link placeholder for reading */
2537     /* Check that the following conditions are all fulfilled:
2538      * a) the placeholder file exists,
2539      * b) the placeholder file contains exactly "ucsize" bytes
2540      *    (read the expected placeholder content length + 1 extra byte, this
2541      *    should return the expected content length),
2542      * c) the placeholder content matches the link target specification as
2543      *    stored in the symlink control structure.
2544      */
2545     if (!G.outfile ||
2546         fread(linktarget, 1, ucsize+1, G.outfile) != ucsize ||
2547         strcmp(slnk_entry->target, linktarget))
2548     {
2549         Info(slide, 0x201, ((char *)slide,
2550           LoadFarString(SymLnkWarnInvalid), FnFilter1(linkfname)));
2551         free(linktarget);
2552         if (G.outfile)
2553             fclose(G.outfile);
2554         return;
2555     }
2556     fclose(G.outfile);                  /* close "data" file for good... */
2557     unlink(linkfname);                  /* ...and delete it */
2558     if (QCOND2)
2559         Info(slide, 0, ((char *)slide, LoadFarString(SymLnkFinish),
2560           FnFilter1(linkfname), FnFilter2(linktarget)));
2561     if (symlink(linktarget, linkfname))  /* create the real link */
2562         perror("symlink error");
2563     free(linktarget);
2564 #ifdef SET_SYMLINK_ATTRIBS
2565     set_symlnk_attribs(__G__ slnk_entry);
2566 #endif
2567     return;                             /* can't set time on symlinks */
2568 
2569 } /* end function set_deferred_symlink() */
2570 #endif /* SYMLINKS */
2571 
2572 
2573 
2574 
2575 /*************************/
2576 /*  Function fnfilter()  */        /* here instead of in list.c for SFX */
2577 /*************************/
2578 
fnfilter(raw,space,size)2579 char *fnfilter(raw, space, size)   /* convert name to safely printable form */
2580     ZCONST char *raw;
2581     uch *space;
2582     extent size;
2583 {
2584 #ifndef NATIVE   /* ASCII:  filter ANSI escape codes, etc. */
2585     ZCONST uch *r=(ZCONST uch *)raw;
2586     uch *s=space;
2587     uch *slim=NULL;
2588     uch *se=NULL;
2589     int have_overflow = FALSE;
2590 
2591     if (size > 0) {
2592         slim = space + size
2593 #ifdef _MBCS
2594                      - (MB_CUR_MAX - 1)
2595 #endif
2596                      - 4;
2597     }
2598     while (*r) {
2599         if (size > 0 && s >= slim && se == NULL) {
2600             se = s;
2601         }
2602 #ifdef QDOS
2603         if (qlflag & 2) {
2604             if (*r == '/' || *r == '.') {
2605                 if (se != NULL && (s > (space + (size-3)))) {
2606                     have_overflow = TRUE;
2607                     break;
2608                 }
2609                 ++r;
2610                 *s++ = '_';
2611                 continue;
2612             }
2613         } else
2614 #endif
2615 #ifdef HAVE_WORKING_ISPRINT
2616 # ifndef UZ_FNFILTER_REPLACECHAR
2617     /* A convenient choice for the replacement of unprintable char codes is
2618      * the "single char wildcard", as this character is quite unlikely to
2619      * appear in filenames by itself.  The following default definition
2620      * sets the replacement char to a question mark as the most common
2621      * "single char wildcard"; this setting should be overridden in the
2622      * appropiate system-specific configuration header when needed.
2623      */
2624 #   define UZ_FNFILTER_REPLACECHAR      '?'
2625 # endif
2626         if (!isprint(*r)) {
2627             if (*r < 32) {
2628                 /* ASCII control codes are escaped as "^{letter}". */
2629                 if (se != NULL && (s > (space + (size-4)))) {
2630                     have_overflow = TRUE;
2631                     break;
2632                 }
2633                 *s++ = '^', *s++ = (uch)(64 + *r++);
2634             } else {
2635                 /* Other unprintable codes are replaced by the
2636                  * placeholder character. */
2637                 if (se != NULL && (s > (space + (size-3)))) {
2638                     have_overflow = TRUE;
2639                     break;
2640                 }
2641                 *s++ = UZ_FNFILTER_REPLACECHAR;
2642                 INCSTR(r);
2643             }
2644 #else /* !HAVE_WORKING_ISPRINT */
2645         if (*r < 32) {
2646             /* ASCII control codes are escaped as "^{letter}". */
2647             if (se != NULL && (s > (space + (size-4)))) {
2648                 have_overflow = TRUE;
2649                 break;
2650             }
2651             *s++ = '^', *s++ = (uch)(64 + *r++);
2652 #endif /* ?HAVE_WORKING_ISPRINT */
2653         } else {
2654 #ifdef _MBCS
2655             unsigned i = CLEN(r);
2656             if (se != NULL && (s > (space + (size-i-2)))) {
2657                 have_overflow = TRUE;
2658                 break;
2659             }
2660             for (; i > 0; i--)
2661                 *s++ = *r++;
2662 #else
2663             if (se != NULL && (s > (space + (size-3)))) {
2664                 have_overflow = TRUE;
2665                 break;
2666             }
2667             *s++ = *r++;
2668 #endif
2669          }
2670     }
2671     if (have_overflow) {
2672         strcpy((char *)se, "...");
2673     } else {
2674         *s = '\0';
2675     }
2676 
2677 #ifdef WINDLL
2678     INTERN_TO_ISO((char *)space, (char *)space);  /* translate to ANSI */
2679 #else
2680 #if (defined(WIN32) && !defined(_WIN32_WCE))
2681     /* Win9x console always uses OEM character coding, and
2682        WinNT console is set to OEM charset by default, too */
2683     INTERN_TO_OEM((char *)space, (char *)space);
2684 #endif /* (WIN32 && !_WIN32_WCE) */
2685 #endif /* ?WINDLL */
2686 
2687     return (char *)space;
2688 
2689 #else /* NATIVE:  EBCDIC or whatever */
2690     return (char *)raw;
2691 #endif
2692 
2693 } /* end function fnfilter() */
2694 
2695 
2696 
2697 
2698 #ifdef SET_DIR_ATTRIB
2699 /* must sort saved directories so can set perms from bottom up */
2700 
2701 /************************/
2702 /*  Function dircomp()  */
2703 /************************/
2704 
dircomp(a,b)2705 static int Cdecl dircomp(a, b)  /* used by qsort(); swiped from Zip */
2706     ZCONST zvoid *a, *b;
2707 {
2708     /* order is significant:  this sorts in reverse order (deepest first) */
2709     return strcmp((*(direntry **)b)->fn, (*(direntry **)a)->fn);
2710  /* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */
2711 }
2712 
2713 #endif /* SET_DIR_ATTRIB */
2714 
2715 
2716 #ifdef USE_BZIP2
2717 
2718 /**************************/
2719 /*  Function UZbunzip2()  */
2720 /**************************/
2721 
UZbunzip2(__G)2722 int UZbunzip2(__G)
2723 __GDEF
2724 /* decompress a bzipped entry using the libbz2 routines */
2725 {
2726     int retval = 0;     /* return code: 0 = "no error" */
2727     int err=BZ_OK;
2728     int repeated_buf_err;
2729     bz_stream bstrm;
2730 
2731     if (G.incnt <= 0 && G.csize <= 0L) {
2732         /* avoid an infinite loop */
2733         Trace((stderr, "UZbunzip2() got empty input\n"));
2734         return 2;
2735     }
2736 
2737 #if (defined(DLL) && !defined(NO_SLIDE_REDIR))
2738     if (G.redirect_slide)
2739         wsize = G.redirect_size, redirSlide = G.redirect_buffer;
2740     else
2741         wsize = WSIZE, redirSlide = slide;
2742 #endif
2743 
2744     bstrm.next_out = (char *)redirSlide;
2745     bstrm.avail_out = wsize;
2746 
2747     bstrm.next_in = (char *)G.inptr;
2748     bstrm.avail_in = G.incnt;
2749 
2750     {
2751         /* local buffer for efficiency */
2752         /* $TODO Check for BZIP LIB version? */
2753 
2754         bstrm.bzalloc = NULL;
2755         bstrm.bzfree = NULL;
2756         bstrm.opaque = NULL;
2757 
2758         Trace((stderr, "initializing bzlib()\n"));
2759         err = BZ2_bzDecompressInit(&bstrm, 0, 0);
2760 
2761         if (err == BZ_MEM_ERROR)
2762             return 3;
2763         else if (err != BZ_OK)
2764             Trace((stderr, "oops!  (BZ2_bzDecompressInit() err = %d)\n", err));
2765     }
2766 
2767 #ifdef FUNZIP
2768     while (err != BZ_STREAM_END) {
2769 #else /* !FUNZIP */
2770     while (G.csize > 0) {
2771         Trace((stderr, "first loop:  G.csize = %ld\n", G.csize));
2772 #endif /* ?FUNZIP */
2773         while (bstrm.avail_out > 0) {
2774             err = BZ2_bzDecompress(&bstrm);
2775 
2776             if (err == BZ_DATA_ERROR) {
2777                 retval = 2; goto uzbunzip_cleanup_exit;
2778             } else if (err == BZ_MEM_ERROR) {
2779                 retval = 3; goto uzbunzip_cleanup_exit;
2780             } else if (err != BZ_OK && err != BZ_STREAM_END)
2781                 Trace((stderr, "oops!  (bzip(first loop) err = %d)\n", err));
2782 
2783 #ifdef FUNZIP
2784             if (err == BZ_STREAM_END)    /* "END-of-entry-condition" ? */
2785 #else /* !FUNZIP */
2786             if (G.csize <= 0L)          /* "END-of-entry-condition" ? */
2787 #endif /* ?FUNZIP */
2788                 break;
2789 
2790             if (bstrm.avail_in == 0) {
2791                 if (fillinbuf(__G) == 0) {
2792                     /* no "END-condition" yet, but no more data */
2793                     retval = 2; goto uzbunzip_cleanup_exit;
2794                 }
2795 
2796                 bstrm.next_in = (char *)G.inptr;
2797                 bstrm.avail_in = G.incnt;
2798             }
2799             Trace((stderr, "     avail_in = %u\n", bstrm.avail_in));
2800         }
2801         /* flush slide[] */
2802         if ((retval = FLUSH(wsize - bstrm.avail_out)) != 0)
2803             goto uzbunzip_cleanup_exit;
2804         Trace((stderr, "inside loop:  flushing %ld bytes (ptr diff = %ld)\n",
2805           (long)(wsize - bstrm.avail_out),
2806           (long)(bstrm.next_out-(char *)redirSlide)));
2807         bstrm.next_out = (char *)redirSlide;
2808         bstrm.avail_out = wsize;
2809     }
2810 
2811     /* no more input, so loop until we have all output */
2812     Trace((stderr, "beginning final loop:  err = %d\n", err));
2813     repeated_buf_err = FALSE;
2814     while (err != BZ_STREAM_END) {
2815         err = BZ2_bzDecompress(&bstrm);
2816         if (err == BZ_DATA_ERROR) {
2817             retval = 2; goto uzbunzip_cleanup_exit;
2818         } else if (err == BZ_MEM_ERROR) {
2819             retval = 3; goto uzbunzip_cleanup_exit;
2820         } else if (err != BZ_OK && err != BZ_STREAM_END) {
2821             Trace((stderr, "oops!  (bzip(final loop) err = %d)\n", err));
2822             DESTROYGLOBALS();
2823             EXIT(PK_MEM3);
2824         }
2825         /* final flush of slide[] */
2826         if ((retval = FLUSH(wsize - bstrm.avail_out)) != 0)
2827             goto uzbunzip_cleanup_exit;
2828         Trace((stderr, "final loop:  flushing %ld bytes (ptr diff = %ld)\n",
2829           (long)(wsize - bstrm.avail_out),
2830           (long)(bstrm.next_out-(char *)redirSlide)));
2831         bstrm.next_out = (char *)redirSlide;
2832         bstrm.avail_out = wsize;
2833     }
2834 #ifdef LARGE_FILE_SUPPORT
2835     Trace((stderr, "total in = %llu, total out = %llu\n",
2836       (zusz_t)(bstrm.total_in_lo32) + ((zusz_t)(bstrm.total_in_hi32))<<32,
2837       (zusz_t)(bstrm.total_out_lo32) + ((zusz_t)(bstrm.total_out_hi32))<<32));
2838 #else
2839     Trace((stderr, "total in = %lu, total out = %lu\n", bstrm.total_in_lo32,
2840       bstrm.total_out_lo32));
2841 #endif
2842 
2843     G.inptr = (uch *)bstrm.next_in;
2844     G.incnt = (G.inbuf + INBUFSIZ) - G.inptr;  /* reset for other routines */
2845 
2846 uzbunzip_cleanup_exit:
2847     err = BZ2_bzDecompressEnd(&bstrm);
2848     if (err != BZ_OK)
2849         Trace((stderr, "oops!  (BZ2_bzDecompressEnd() err = %d)\n", err));
2850 
2851     return retval;
2852 } /* end function UZbunzip2() */
2853 #endif /* USE_BZIP2 */
2854