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