Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
See the accompanying file LICENSE, version 2000-Apr-09 or later
(the contents of which are also included in unzip.h) for terms of use.
If, for some reason, all these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
*/
extract.c
This file contains the high-level routines ("driver routines") for extrac-
ting and testing zipfile members. It calls the low-level routines in files
explode.c, inflate.c, unreduce.c and unshrink.c.
Contains: extract_or_test_files()
store_info()
extract_or_test_entrylist()
extract_or_test_member()
TestExtraField()
test_compr_eb()
memextract()
memflush()
extract_izvms_block() (VMS or VMS_TEXT_CONV)
fnfilter()
---------------------------------------------------------------------------*/
#define __EXTRACT_C
#define UNZIP_INTERNAL
#include "unzip.h"
#ifdef WINDLL
# ifdef POCKET_UNZIP
# include "wince/intrface.h"
# else
# include "windll/windll.h"
# endif
#endif
#include "crypt.h"
#define GRRDUMP(buf,len) { \
int i, j; \
\
for (j = 0; j < (len)/16; ++j) { \
printf(" "); \
for (i = 0; i < 16; ++i) \
printf("%02x ", (uch)(buf)[i+(j<<4)]); \
printf("\n "); \
for (i = 0; i < 16; ++i) { \
char c = (char)(buf)[i+(j<<4)]; \
\
if (c == '\n') \
printf("\\n "); \
else if (c == '\r') \
printf("\\r "); \
else \
printf(" %c ", c); \
} \
printf("\n"); \
} \
if ((len) % 16) { \
printf(" "); \
for (i = j<<4; i < (len); ++i) \
printf("%02x ", (uch)(buf)[i]); \
printf("\n "); \
for (i = j<<4; i < (len); ++i) { \
char c = (char)(buf)[i]; \
\
if (c == '\n') \
printf("\\n "); \
else if (c == '\r') \
printf("\\r "); \
else \
printf(" %c ", c); \
} \
printf("\n"); \
} \
}
static int store_info OF((__GPRO));
#ifdef SET_DIR_ATTRIB
static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
ulg *pfilnum, ulg *pnum_bad_pwd, LONGINT *pold_extra_bytes,
unsigned *pnum_dirs, dirtime **pdirlist,
int error_in_archive));
#else
static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
ulg *pfilnum, ulg *pnum_bad_pwd, LONGINT *pold_extra_bytes,
int error_in_archive));
#endif
static int extract_or_test_member OF((__GPRO));
#ifndef SFX
static int TestExtraField OF((__GPRO__ uch *ef, unsigned ef_len));
static int test_compr_eb OF((__GPRO__ uch *eb, unsigned eb_size,
unsigned compr_offset,
int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size,
uch *eb_ucptr, ulg eb_ucsize)));
#endif
#if (defined(VMS) || defined(VMS_TEXT_CONV))
static void decompress_bits OF((uch *outptr, unsigned needlen,
ZCONST uch *bitptr));
#endif
#ifdef SET_DIR_ATTRIB
static int dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b));
#endif
static ZCONST char Far VersionMsg[] =
" skipping: %-22s need %s compat. v%u.%u (can do v%u.%u)\n";
static ZCONST char Far ComprMsgNum[] =
" skipping: %-22s unsupported compression method %u\n";
#ifndef SFX
static ZCONST char Far ComprMsgName[] =
" skipping: %-22s `%s' method not supported\n";
static ZCONST char Far CmprNone[] = "store";
static ZCONST char Far CmprShrink[] = "shrink";
static ZCONST char Far CmprReduce[] = "reduce";
static ZCONST char Far CmprImplode[] = "implode";
static ZCONST char Far CmprTokenize[] = "tokenize";
static ZCONST char Far CmprDeflate[] = "deflate";
static ZCONST char Far CmprDeflat64[] = "deflate64";
static ZCONST char Far CmprDCLImplode[] = "DCL implode";
static ZCONST char Far *ComprNames[NUM_METHODS] = {
CmprNone, CmprShrink, CmprReduce, CmprReduce, CmprReduce, CmprReduce,
CmprImplode, CmprTokenize, CmprDeflate, CmprDeflat64, CmprDCLImplode
};
#endif
static ZCONST char Far FilNamMsg[] =
"%s: bad filename length (%s)\n";
static ZCONST char Far ExtFieldMsg[] =
"%s: bad extra field length (%s)\n";
static ZCONST char Far OffsetMsg[] =
"file #%lu: bad zipfile offset (%s): %ld\n";
static ZCONST char Far ExtractMsg[] =
"%8sing: %-22s %s%s";
#ifndef SFX
static ZCONST char Far LengthMsg[] =
"%s %s: %ld bytes required to uncompress to %lu bytes;\n %s\
supposed to require %lu bytes%s%s%s\n";
#endif
static ZCONST char Far BadFileCommLength[] = "%s: bad file comment length\n";
static ZCONST char Far LocalHdrSig[] = "local header sig";
static ZCONST char Far BadLocalHdr[] = "file #%lu: bad local header\n";
static ZCONST char Far AttemptRecompensate[] =
" (attempting to re-compensate)\n";
#ifndef SFX
static ZCONST char Far BackslashPathSep[] =
"warning: %s appears to use backslashes as path separators\n";
#endif
static ZCONST char Far AbsolutePathWarning[] =
"warning: stripped absolute path spec from %s\n";
static ZCONST char Far SkipVolumeLabel[] =
" skipping: %-22s %svolume label\n";
#ifdef SET_DIR_ATTRIB
static ZCONST char Far DirlistEntryNoMem[] =
"warning: cannot alloc memory for dir times/permissions/UID/GID\n";
static ZCONST char Far DirlistSortNoMem[] =
"warning: cannot alloc memory to sort dir times/perms/etc.\n";
static ZCONST char Far DirlistSetAttrFailed[] =
"warning: set times/attribs failed for %s\n";
#endif
#ifndef WINDLL
static ZCONST char Far ReplaceQuery[] =
"replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ";
static ZCONST char Far AssumeNone[] = " NULL\n(assuming [N]one)\n";
static ZCONST char Far NewNameQuery[] = "new name: ";
static ZCONST char Far InvalidResponse[] = "error: invalid response [%c]\n";
#endif
static ZCONST char Far ErrorInArchive[] =
"At least one %serror was detected in %s.\n";
static ZCONST char Far ZeroFilesTested[] =
"Caution: zero files tested in %s.\n";
#ifndef VMS
static ZCONST char Far VMSFormatQuery[] =
"\n%s: stored in VMS format. Extract anyway? (y/n) ";
#endif
#if CRYPT
static ZCONST char Far SkipCannotGetPasswd[] =
" skipping: %-22s unable to get password\n";
static ZCONST char Far SkipIncorrectPasswd[] =
" skipping: %-22s incorrect password\n";
static ZCONST char Far FilesSkipBadPasswd[] =
"%lu file%s skipped because of incorrect password.\n";
static ZCONST char Far MaybeBadPasswd[] =
" (may instead be incorrect password)\n";
#else
static ZCONST char Far SkipEncrypted[] =
" skipping: %-22s encrypted (not supported)\n";
#endif
static ZCONST char Far NoErrInCompData[] =
"No errors detected in compressed data of %s.\n";
static ZCONST char Far NoErrInTestedFiles[] =
"No errors detected in %s for the %lu file%s tested.\n";
static ZCONST char Far FilesSkipped[] =
"%lu file%s skipped because of unsupported compression or encoding.\n";
static ZCONST char Far ErrUnzipFile[] = " error: %s%s %s\n";
static ZCONST char Far ErrUnzipNoFile[] = "\n error: %s%s\n";
static ZCONST char Far NotEnoughMem[] = "not enough memory to ";
static ZCONST char Far InvalidComprData[] = "invalid compressed data to ";
static ZCONST char Far Inflate[] = "inflate";
#ifndef SFX
static ZCONST char Far Explode[] = "explode";
#ifndef LZW_CLEAN
static ZCONST char Far Unshrink[] = "unshrink";
#endif
#endif
#if (!defined(DELETE_IF_FULL) || !defined(HAVE_UNLINK))
static ZCONST char Far FileTruncated[] =
"warning: %s is probably truncated\n";
#endif
static ZCONST char Far FileUnknownCompMethod[] =
"%s: unknown compression method\n";
static ZCONST char Far BadCRC[] = " bad CRC %08lx (should be %08lx)\n";
char ZCONST Far TruncEAs[] = " compressed EA data missing (%d bytes)%s";
char ZCONST Far TruncNTSD[] =
" compressed WinNT security data missing (%d bytes)%s";
#ifndef SFX
static ZCONST char Far InconsistEFlength[] = "bad extra-field entry:\n \
EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n";
static ZCONST char Far InvalidComprDataEAs[] =
" invalid compressed data for EAs\n";
# if (defined(WIN32) && defined(NTSD_EAS))
static ZCONST char Far InvalidSecurityEAs[] =
" EAs fail security check\n";
# endif
static ZCONST char Far UnsuppNTSDVersEAs[] =
" unsupported NTSD EAs version %d\n";
static ZCONST char Far BadCRC_EAs[] = " bad CRC for extended attributes\n";
static ZCONST char Far UnknComprMethodEAs[] =
" unknown compression method for EAs (%u)\n";
static ZCONST char Far NotEnoughMemEAs[] =
" out of memory while inflating EAs\n";
static ZCONST char Far UnknErrorEAs[] =
" unknown error on extended attributes\n";
#endif
static ZCONST char Far UnsupportedExtraField[] =
"\nerror: unsupported extra-field compression type (%u)--skipping\n";
static ZCONST char Far BadExtraFieldCRC[] =
"error [%s]: bad extra-field CRC %08lx (should be %08lx)\n";
int extract_or_test_files(__G)
__GDEF
{
unsigned i, j;
long cd_bufstart;
uch *cd_inptr;
int cd_incnt;
ulg filnum=0L, blknum=0L;
int reached_end, no_endsig_found;
int error, error_in_archive=PK_COOL;
int *fn_matched=NULL, *xn_matched=NULL;
unsigned members_processed;
ulg num_skipped=0L, num_bad_pwd=0L;
LONGINT old_extra_bytes = 0L;
#ifdef SET_DIR_ATTRIB
unsigned num_dirs=0;
dirtime *dirlist=(dirtime *)NULL, **sorted_dirlist=(dirtime **)NULL;
#endif
The basic idea of this function is as follows. Since the central di-
rectory lies at the end of the zipfile and the member files lie at the
beginning or middle or wherever, it is not very desirable to simply
read a central directory entry, jump to the member and extract it, and
then jump back to the central directory. In the case of a large zipfile
this would lead to a whole lot of disk-grinding, especially if each mem-
ber file is small. Instead, we read from the central directory the per-
tinent information for a block of files, then go extract/test the whole
block. Thus this routine contains two small(er) loops within a very
large outer loop: the first of the small ones reads a block of files
from the central directory; the second extracts or tests each file; and
the outer one loops over blocks. There's some file-pointer positioning
stuff in between, but that's about it. Btw, it's because of this jump-
ing around that we can afford to be lenient if an error occurs in one of
the member files: we should still be able to go find the other members,
since we know the offset of each from the beginning of the zipfile.
---------------------------------------------------------------------------*/
G.pInfo = G.info;
#if CRYPT
G.newzip = TRUE;
#endif
#ifndef SFX
G.reported_backslash = FALSE;
#endif
if (G.filespecs > 0 &&
(fn_matched=(int *)malloc(G.filespecs*sizeof(int))) != (int *)NULL)
for (i = 0; i < G.filespecs; ++i)
fn_matched[i] = FALSE;
if (G.xfilespecs > 0 &&
(xn_matched=(int *)malloc(G.xfilespecs*sizeof(int))) != (int *)NULL)
for (i = 0; i < G.xfilespecs; ++i)
xn_matched[i] = FALSE;
Begin main loop over blocks of member files. We know the entire central
directory is on this disk: we would not have any of this information un-
less the end-of-central-directory record was on this disk, and we would
not have gotten to this routine unless this is also the disk on which
the central directory starts. In practice, this had better be the ONLY
disk in the archive, but we'll add multi-disk support soon.
---------------------------------------------------------------------------*/
members_processed = 0;
no_endsig_found = FALSE;
reached_end = FALSE;
while (!reached_end) {
j = 0;
#ifdef AMIGA
memzero(G.filenotes, DIR_BLKSIZ * sizeof(char *));
#endif
* Loop through files in central directory, storing offsets, file
* attributes, case-conversion and text-conversion flags until block
* size is reached.
*/
while ((j < DIR_BLKSIZ)) {
G.pInfo = &G.info[j];
if (readbuf(__G__ G.sig, 4) == 0) {
error_in_archive = PK_EOF;
reached_end = TRUE;
break;
}
if (strncmp(G.sig, central_hdr_sig, 4)) {
* -> is the number of processed entries compatible with the
* number of entries as stored in the end_central record?
*/
if ((members_processed & (unsigned)0xFFFF) ==
(unsigned)G.ecrec.total_entries_central_dir) {
*/
no_endsig_found =
(strncmp(G.sig, end_central_sig, 4) != 0);
} else {
* -> report it and stop searching for more Zip entries
*/
Info(slide, 0x401, ((char *)slide,
LoadFarString(CentSigMsg), j + blknum*DIR_BLKSIZ + 1));
Info(slide, 0x401, ((char *)slide,
LoadFarString(ReportMsg)));
error_in_archive = PK_BADERR;
}
reached_end = TRUE;
break;
}
if ((error = process_cdir_file_hdr(__G)) != PK_COOL) {
error_in_archive = error;
reached_end = TRUE;
break;
}
if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) !=
PK_COOL)
{
if (error > error_in_archive)
error_in_archive = error;
if (error > PK_WARN) {
Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg),
FnFilter1(G.filename), "central"));
reached_end = TRUE;
break;
}
}
if ((error = do_string(__G__ G.crec.extra_field_length,
EXTRA_FIELD)) != 0)
{
if (error > error_in_archive)
error_in_archive = error;
if (error > PK_WARN) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(ExtFieldMsg),
FnFilter1(G.filename), "central"));
reached_end = TRUE;
break;
}
}
#ifdef AMIGA
G.filenote_slot = j;
if ((error = do_string(__G__ G.crec.file_comment_length,
uO.N_flag ? FILENOTE : SKIP)) != PK_COOL)
#else
if ((error = do_string(__G__ G.crec.file_comment_length, SKIP))
!= PK_COOL)
#endif
{
if (error > error_in_archive)
error_in_archive = error;
if (error > PK_WARN) {
Info(slide, 0x421, ((char *)slide,
LoadFarString(BadFileCommLength),
FnFilter1(G.filename)));
reached_end = TRUE;
break;
}
}
if (G.process_all_files) {
if (store_info(__G))
++j;
else
++num_skipped;
} else {
int do_this_file;
if (G.filespecs == 0)
do_this_file = TRUE;
else {
do_this_file = FALSE;
for (i = 0; i < G.filespecs; i++)
if (match(G.filename, G.pfnames[i], uO.C_flag)) {
do_this_file = TRUE;
if (fn_matched)
fn_matched[i] = TRUE;
break;
}
}
if (do_this_file) {
for (i = 0; i < G.xfilespecs; i++)
if (match(G.filename, G.pxnames[i], uO.C_flag)) {
do_this_file = FALSE;
if (xn_matched)
xn_matched[i] = TRUE;
break;
}
}
if (do_this_file) {
if (store_info(__G))
++j;
else
++num_skipped;
}
}
members_processed++;
}
cd_bufstart = G.cur_zipfile_bufstart;
cd_inptr = G.inptr;
cd_incnt = G.incnt;
Second loop: process files in current block, extracting or testing
each one.
-----------------------------------------------------------------------*/
error = extract_or_test_entrylist(__G__ j,
&filnum, &num_bad_pwd, &old_extra_bytes,
#ifdef SET_DIR_ATTRIB
&num_dirs, &dirlist,
#endif
error_in_archive);
if (error != PK_COOL) {
if (error > error_in_archive)
error_in_archive = error;
if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
if (fn_matched)
free((zvoid *)fn_matched);
if (xn_matched)
free((zvoid *)xn_matched);
return error_in_archive;
}
}
* Jump back to where we were in the central directory, then go and do
* the next batch of files.
*/
#ifdef USE_STRM_INPUT
fseek((FILE *)G.zipfd, (LONGINT)cd_bufstart, SEEK_SET);
G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd);
#else
G.cur_zipfile_bufstart =
lseek(G.zipfd, (LONGINT)cd_bufstart, SEEK_SET);
#endif
read(G.zipfd, (char *)G.inbuf, INBUFSIZ);
G.inptr = cd_inptr;
G.incnt = cd_incnt;
++blknum;
#ifdef TEST
printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart);
printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart,
cur_zipfile_bufstart);
printf("inptr-inbuf = %d\n", G.inptr-G.inbuf);
printf("incnt = %d\n\n", G.incnt);
#endif
}
Go back through saved list of directories, sort and set times/perms/UIDs
and GIDs from the deepest level on up.
---------------------------------------------------------------------------*/
#ifdef SET_DIR_ATTRIB
if (num_dirs > 0) {
sorted_dirlist = (dirtime **)malloc(num_dirs*sizeof(dirtime *));
if (sorted_dirlist == (dirtime **)NULL) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(DirlistSortNoMem)));
while (dirlist != (dirtime *)NULL) {
dirtime *d = dirlist;
dirlist = dirlist->next;
free(d);
}
} else {
if (num_dirs == 1)
sorted_dirlist[0] = dirlist;
else {
for (i = 0; i < num_dirs; ++i) {
sorted_dirlist[i] = dirlist;
dirlist = dirlist->next;
}
qsort((char *)sorted_dirlist, num_dirs, sizeof(dirtime *),
dircomp);
}
Trace((stderr, "setting directory times/perms/attributes\n"));
for (i = 0; i < num_dirs; ++i) {
dirtime *d = sorted_dirlist[i];
Trace((stderr, "dir = %s\n", d->fn));
if ((error = set_direc_attribs(__G__ d)) != PK_OK) {
Info(slide, 0x201, ((char *)slide,
LoadFarString(DirlistSetAttrFailed), d->fn));
if (!error_in_archive)
error_in_archive = error;
}
free(d->fn);
free(d);
}
free(sorted_dirlist);
}
}
#endif
#if (defined(WIN32) && defined(NTSD_EAS))
process_defer_NT(__G);
#endif
Check for unmatched filespecs on command line and print warning if any
found. Free allocated memory.
---------------------------------------------------------------------------*/
if (fn_matched) {
for (i = 0; i < G.filespecs; ++i)
if (!fn_matched[i]) {
#ifdef DLL
if (!G.redirect_data && !G.redirect_text)
Info(slide, 0x401, ((char *)slide,
LoadFarString(FilenameNotMatched), G.pfnames[i]));
else
setFileNotFound(__G);
#else
Info(slide, 1, ((char *)slide,
LoadFarString(FilenameNotMatched), G.pfnames[i]));
#endif
if (error_in_archive <= PK_WARN)
error_in_archive = PK_FIND;
}
free((zvoid *)fn_matched);
}
if (xn_matched) {
for (i = 0; i < G.xfilespecs; ++i)
if (!xn_matched[i])
Info(slide, 0x401, ((char *)slide,
LoadFarString(ExclFilenameNotMatched), G.pxnames[i]));
free((zvoid *)xn_matched);
}
Double-check that we're back at the end-of-central-directory record, and
print quick summary of results, if we were just testing the archive. We
send the summary to stdout so that people doing the testing in the back-
ground and redirecting to a file can just do a "tail" on the output file.
---------------------------------------------------------------------------*/
#ifndef SFX
if (no_endsig_found) {
Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg)));
if (!error_in_archive)
error_in_archive = PK_WARN;
}
#endif
if (uO.tflag) {
ulg num = filnum - num_bad_pwd;
if (uO.qflag < 2) {
if (error_in_archive)
Info(slide, 0, ((char *)slide, LoadFarString(ErrorInArchive),
(error_in_archive == PK_WARN)? "warning-" : "", G.zipfn));
else if (num == 0L)
Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested),
G.zipfn));
else if (G.process_all_files && (num_skipped+num_bad_pwd == 0L))
Info(slide, 0, ((char *)slide, LoadFarString(NoErrInCompData),
G.zipfn));
else
Info(slide, 0, ((char *)slide, LoadFarString(NoErrInTestedFiles)
, G.zipfn, num, (num==1L)? "":"s"));
if (num_skipped > 0L)
Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipped),
num_skipped, (num_skipped==1L)? "":"s"));
#if CRYPT
if (num_bad_pwd > 0L)
Info(slide, 0, ((char *)slide, LoadFarString(FilesSkipBadPasswd)
, num_bad_pwd, (num_bad_pwd==1L)? "":"s"));
#endif
} else if ((uO.qflag == 0) && !error_in_archive && (num == 0))
Info(slide, 0, ((char *)slide, LoadFarString(ZeroFilesTested),
G.zipfn));
}
* happen if zipfile is empty and no files specified on command line) */
if ((filnum == 0) && error_in_archive <= PK_WARN) {
if (num_skipped > 0L)
error_in_archive = IZ_UNSUP;
else
error_in_archive = PK_FIND;
}
#if CRYPT
else if ((filnum == num_bad_pwd) && error_in_archive <= PK_WARN)
error_in_archive = IZ_BADPWD;
#endif
else if ((num_skipped > 0L) && error_in_archive <= PK_WARN)
error_in_archive = IZ_UNSUP;
#if CRYPT
else if ((num_bad_pwd > 0L) && !error_in_archive)
error_in_archive = PK_WARN;
#endif
return error_in_archive;
}
static int store_info(__G)
__GDEF
{
#ifdef SFX
# ifdef USE_DEFLATE64
# define UNKN_COMPR \
(G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \
&& G.crec.compression_method>ENHDEFLATED)
# else
# define UNKN_COMPR \
(G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED)
# endif
#else
# ifdef COPYRIGHT_CLEAN
# define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
G.crec.compression_method <= REDUCED4)
# else
# define UNKN_RED FALSE /* reducing not unknown */
# endif
# ifdef LZW_CLEAN
# define UNKN_SHR (G.crec.compression_method == SHRUNK)
# else
# define UNKN_SHR FALSE /* unshrinking not unknown */
# endif
# ifdef USE_DEFLATE64
# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
G.crec.compression_method==TOKENIZED || \
G.crec.compression_method>ENHDEFLATED)
# else
# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
G.crec.compression_method==TOKENIZED || \
G.crec.compression_method>DEFLATED)
# endif
#endif
Check central directory info for version/compatibility requirements.
---------------------------------------------------------------------------*/
G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1;
G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8;
G.pInfo->textfile = G.crec.internal_file_attributes & 1;
G.pInfo->crc = G.crec.crc32;
G.pInfo->compr_size = G.crec.csize;
G.pInfo->uncompr_size = G.crec.ucsize;
switch (uO.aflag) {
case 0:
G.pInfo->textmode = FALSE;
break;
case 1:
G.pInfo->textmode = G.pInfo->textfile;
break;
default:
G.pInfo->textmode = TRUE;
break;
}
if (G.crec.version_needed_to_extract[1] == VMS_) {
if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) {
if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
FnFilter1(G.filename), "VMS",
G.crec.version_needed_to_extract[0] / 10,
G.crec.version_needed_to_extract[0] % 10,
VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10));
return 0;
}
#ifndef VMS
else if (!uO.tflag && !IS_OVERWRT_ALL) {
Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery),
FnFilter1(G.filename)));
fgets(G.answerbuf, 9, stdin);
if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y'))
return 0;
}
#endif
} else if (G.crec.version_needed_to_extract[0] > UNZIP_VERSION) {
if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
FnFilter1(G.filename), "PK",
G.crec.version_needed_to_extract[0] / 10,
G.crec.version_needed_to_extract[0] % 10,
UNZIP_VERSION / 10, UNZIP_VERSION % 10));
return 0;
}
if UNKN_COMPR {
if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) {
#ifndef SFX
if (G.crec.compression_method < NUM_METHODS)
Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName),
FnFilter1(G.filename),
LoadFarStringSmall(ComprNames[G.crec.compression_method])));
else
#endif
Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum),
FnFilter1(G.filename),
G.crec.compression_method));
}
return 0;
}
#if (!CRYPT)
if (G.pInfo->encrypted) {
if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted),
FnFilter1(G.filename)));
return 0;
}
#endif
mapattr(__G);
G.pInfo->diskstart = G.crec.disk_number_start;
G.pInfo->offset = (long)G.crec.relative_offset_local_header;
return 1;
}
static int extract_or_test_entrylist(__G__ numchunk,
pfilnum, pnum_bad_pwd, pold_extra_bytes,
#ifdef SET_DIR_ATTRIB
pnum_dirs, pdirlist,
#endif
error_in_archive)
__GDEF
unsigned numchunk;
ulg *pfilnum;
ulg *pnum_bad_pwd;
LONGINT *pold_extra_bytes;
#ifdef SET_DIR_ATTRIB
unsigned *pnum_dirs;
dirtime **pdirlist;
#endif
int error_in_archive;
{
unsigned i;
int renamed, query;
int skip_entry;
long bufstart, inbuf_offset, request;
int error, errcode;
#define SKIP_NO 0 /* do not skip this entry */
#define SKIP_Y_EXISTING 1 /* skip this entry, do not overwrite file */
#define SKIP_Y_NONEXIST 2 /* skip this entry, do not create new file */
Second loop: process files in current block, extracting or testing
each one.
-----------------------------------------------------------------------*/
for (i = 0; i < numchunk; ++i) {
(*pfilnum)++;
G.pInfo = &G.info[i];
#ifdef NOVELL_BUG_FAILSAFE
G.dne = FALSE;
#endif
* (either haven't yet read far enough, or (maybe) skipping back-
* ward), skip to the target position and reset readbuf(). */
request = G.pInfo->offset + G.extra_bytes;
inbuf_offset = request % INBUFSIZ;
bufstart = request - inbuf_offset;
Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n",
request, inbuf_offset));
Trace((stderr,
"debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
bufstart, G.cur_zipfile_bufstart));
if (request < 0) {
Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg),
G.zipfn, LoadFarString(ReportMsg)));
error_in_archive = PK_ERR;
if (*pfilnum == 1 && G.extra_bytes != 0L) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(AttemptRecompensate)));
*pold_extra_bytes = G.extra_bytes;
G.extra_bytes = 0L;
request = G.pInfo->offset;
inbuf_offset = request % INBUFSIZ;
bufstart = request - inbuf_offset;
Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n",
request, inbuf_offset));
Trace((stderr,
"debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
bufstart, G.cur_zipfile_bufstart));
if (request < 0) {
Trace((stderr,
"debug: recompensated request still < 0\n"));
Info(slide, 0x401, ((char *)slide,
LoadFarStringSmall(SeekMsg),
G.zipfn, LoadFarString(ReportMsg)));
error_in_archive = PK_BADERR;
continue;
}
} else {
error_in_archive = PK_BADERR;
continue;
}
}
if (bufstart != G.cur_zipfile_bufstart) {
Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n"));
#ifdef USE_STRM_INPUT
fseek((FILE *)G.zipfd, (LONGINT)bufstart, SEEK_SET);
G.cur_zipfile_bufstart = ftell((FILE *)G.zipfd);
#else
G.cur_zipfile_bufstart =
lseek(G.zipfd, (LONGINT)bufstart, SEEK_SET);
#endif
if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ)) <= 0)
{
Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
*pfilnum, "lseek", bufstart));
error_in_archive = PK_BADERR;
continue;
}
G.inptr = G.inbuf + (int)inbuf_offset;
G.incnt -= (int)inbuf_offset;
} else {
G.incnt += (int)(G.inptr-G.inbuf) - (int)inbuf_offset;
G.inptr = G.inbuf + (int)inbuf_offset;
}
if (readbuf(__G__ G.sig, 4) == 0) {
Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
*pfilnum, "EOF", request));
error_in_archive = PK_BADERR;
continue;
}
if (strncmp(G.sig, local_hdr_sig, 4)) {
Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
*pfilnum, LoadFarStringSmall(LocalHdrSig), request));
GRRDUMP(G.sig, 4)
GRRDUMP(local_hdr_sig, 4)
*/
error_in_archive = PK_ERR;
if ((*pfilnum == 1 && G.extra_bytes != 0L) ||
(G.extra_bytes == 0L && *pold_extra_bytes != 0L)) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(AttemptRecompensate)));
if (G.extra_bytes) {
*pold_extra_bytes = G.extra_bytes;
G.extra_bytes = 0L;
} else
G.extra_bytes = *pold_extra_bytes;
if (((error = seek_zipf(__G__ G.pInfo->offset)) != PK_OK) ||
(readbuf(__G__ G.sig, 4) == 0)) {
if (error != PK_BADERR)
Info(slide, 0x401, ((char *)slide,
LoadFarString(OffsetMsg), *pfilnum, "EOF", request));
error_in_archive = PK_BADERR;
continue;
}
if (strncmp(G.sig, local_hdr_sig, 4)) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(OffsetMsg), *pfilnum,
LoadFarStringSmall(LocalHdrSig), request));
error_in_archive = PK_BADERR;
continue;
}
} else
continue;
}
if ((error = process_local_file_hdr(__G)) != PK_COOL) {
Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr),
*pfilnum));
error_in_archive = error;
continue;
}
if ((error = do_string(__G__ G.lrec.filename_length, DS_FN_L)) !=
PK_COOL)
{
if (error > error_in_archive)
error_in_archive = error;
if (error > PK_WARN) {
Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg),
FnFilter1(G.filename), "local"));
continue;
}
}
if (G.extra_field != (uch *)NULL) {
free(G.extra_field);
G.extra_field = (uch *)NULL;
}
if ((error =
do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0)
{
if (error > error_in_archive)
error_in_archive = error;
if (error > PK_WARN) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(ExtFieldMsg),
FnFilter1(G.filename), "local"));
continue;
}
}
#if CRYPT
if (G.pInfo->encrypted &&
(error = decrypt(__G__ uO.pwdarg)) != PK_COOL) {
if (error == PK_WARN) {
if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
Info(slide, 0x401, ((char *)slide,
LoadFarString(SkipIncorrectPasswd),
FnFilter1(G.filename)));
++(*pnum_bad_pwd);
} else {
if (error > error_in_archive)
error_in_archive = error;
Info(slide, 0x401, ((char *)slide,
LoadFarString(SkipCannotGetPasswd),
FnFilter1(G.filename)));
}
continue;
}
#endif
* just about to extract file: if extracting to disk, check if
* already exists, and if so, take appropriate action according to
* fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
* loop because we don't store the possibly renamed filename[] in
* info[])
*/
#ifdef DLL
if (!uO.tflag && !uO.cflag && !G.redirect_data)
#else
if (!uO.tflag && !uO.cflag)
#endif
{
renamed = FALSE;
startover:
query = FALSE;
skip_entry = SKIP_NO;
* of slash as directory separator (bug in some zipper(s); so
* far, not a problem in HPFS, NTFS or VFAT systems)
*/
#ifndef SFX
if (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/')) {
char *p=G.filename;
if (*p) do {
if (*p == '\\') {
if (!G.reported_backslash) {
Info(slide, 0x21, ((char *)slide,
LoadFarString(BackslashPathSep), G.zipfn));
G.reported_backslash = TRUE;
if (!error_in_archive)
error_in_archive = PK_WARN;
}
*p = '/';
}
} while (*PREINCSTR(p));
}
#endif
if (!renamed) {
if (G.filename[0] == '/') {
Info(slide, 0x401, ((char *)slide,
LoadFarString(AbsolutePathWarning),
FnFilter1(G.filename)));
if (!error_in_archive)
error_in_archive = PK_WARN;
do {
char *p = G.filename + 1;
do {
*(p-1) = *p;
} while (*p++ != '\0');
} while (G.filename[0] == '/');
}
}
error = mapname(__G__ renamed);
if ((errcode = error & ~MPN_MASK) != PK_OK &&
error_in_archive < errcode)
error_in_archive = errcode;
if ((errcode = error & MPN_MASK) > MPN_INF_TRUNC) {
if (errcode == MPN_CREATED_DIR) {
#ifdef SET_DIR_ATTRIB
dirtime *d_entry;
d_entry = (dirtime *)malloc(sizeof(dirtime));
if (d_entry == (dirtime *)NULL) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(DirlistEntryNoMem)));
} else {
unsigned eb_izux_flg;
d_entry->next = (*pdirlist);
(*pdirlist) = d_entry;
(*pdirlist)->fn =
(char *)malloc(strlen(G.filename) + 1);
if ((*pdirlist)->fn == (char *)NULL) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(DirlistEntryNoMem)));
(*pdirlist) = d_entry->next;
free(d_entry);
if (!error_in_archive)
error_in_archive = PK_WARN;
continue;
}
strcpy((*pdirlist)->fn, G.filename);
(*pdirlist)->perms = G.pInfo->file_attr;
#ifdef USE_EF_UT_TIME
eb_izux_flg = G.extra_field? ef_scan_for_izux(
G.extra_field, G.lrec.extra_field_length, 0,
G.lrec.last_mod_dos_datetime,
#ifdef IZ_CHECK_TZ
(G.tz_is_valid ? &((*pdirlist)->u.t3) : NULL),
#else
&((*pdirlist)->u.t3),
#endif
(*pdirlist)->uidgid)
: 0;
#else
eb_izux_flg = 0;
#endif
if (eb_izux_flg & EB_UT_FL_MTIME) {
TTrace((stderr,
"\nextract: Unix dir e.f. modtime = %ld\n",
(*pdirlist)->u.t3.mtime));
} else {
(*pdirlist)->u.t3.mtime = dos_to_unix_time(
G.lrec.last_mod_dos_datetime);
}
if (eb_izux_flg & EB_UT_FL_ATIME) {
TTrace((stderr,
"\nextract: Unix dir e.f. actime = %ld\n",
(*pdirlist)->u.t3.atime));
} else {
(*pdirlist)->u.t3.atime =
(*pdirlist)->u.t3.mtime;
}
(*pdirlist)->have_uidgid =
#ifdef RESTORE_UIDGID
(uO.X_flag && (eb_izux_flg & EB_UX2_VALID));
#else
0;
#endif
++(*pnum_dirs);
}
#endif
} else if (errcode == MPN_VOL_LABEL) {
#ifdef DOS_OS2_W32
Info(slide, 0x401, ((char *)slide,
LoadFarString(SkipVolumeLabel),
FnFilter1(G.filename),
uO.volflag? "hard disk " : ""));
#else
Info(slide, 1, ((char *)slide,
LoadFarString(SkipVolumeLabel),
FnFilter1(G.filename), ""));
#endif
} else if (errcode > MPN_INF_SKIP &&
error_in_archive < PK_ERR)
error_in_archive = PK_ERR;
Trace((stderr, "mapname(%s) returns error code = %d\n",
FnFilter1(G.filename), error));
continue;
}
#ifdef QDOS
QFilename(__G__ G.filename);
#endif
switch (check_for_newer(__G__ G.filename)) {
case DOES_NOT_EXIST:
#ifdef NOVELL_BUG_FAILSAFE
G.dne = TRUE;
#endif
if (uO.fflag && !renamed)
skip_entry = SKIP_Y_NONEXIST;
break;
case EXISTS_AND_OLDER:
#ifdef UNIXBACKUP
if (!uO.B_flag)
#endif
{
if (IS_OVERWRT_NONE)
skip_entry = SKIP_Y_EXISTING;
else if (!IS_OVERWRT_ALL)
query = TRUE;
}
break;
case EXISTS_AND_NEWER:
#ifdef UNIXBACKUP
if ((!uO.B_flag && IS_OVERWRT_NONE) ||
#else
if (IS_OVERWRT_NONE ||
#endif
(uO.uflag && !renamed)) {
skip_entry = SKIP_Y_EXISTING;
} else {
#ifdef UNIXBACKUP
if (!IS_OVERWRT_ALL && !uO.B_flag)
#else
if (!IS_OVERWRT_ALL)
#endif
query = TRUE;
}
break;
}
if (query) {
#ifdef WINDLL
switch (G.lpUserFunctions->replace != NULL ?
(*G.lpUserFunctions->replace)(G.filename) :
IDM_REPLACE_NONE) {
case IDM_REPLACE_RENAME:
_ISO_INTERN(G.filename);
renamed = TRUE;
goto startover;
case IDM_REPLACE_ALL:
G.overwrite_mode = OVERWRT_ALWAYS;
case IDM_REPLACE_YES:
break;
case IDM_REPLACE_NONE:
G.overwrite_mode = OVERWRT_NEVER;
case IDM_REPLACE_NO:
skip_entry = SKIP_Y_EXISTING;
break;
}
#else
extent fnlen;
reprompt:
Info(slide, 0x81, ((char *)slide,
LoadFarString(ReplaceQuery),
FnFilter1(G.filename)));
if (fgets(G.answerbuf, 9, stdin) == (char *)NULL) {
Info(slide, 1, ((char *)slide,
LoadFarString(AssumeNone)));
*G.answerbuf = 'N';
if (!error_in_archive)
error_in_archive = 1;
}
switch (*G.answerbuf) {
case 'r':
case 'R':
do {
Info(slide, 0x81, ((char *)slide,
LoadFarString(NewNameQuery)));
fgets(G.filename, FILNAMSIZ, stdin);
fnlen = strlen(G.filename);
if (lastchar(G.filename, fnlen) == '\n')
G.filename[--fnlen] = '\0';
} while (fnlen == 0);
#ifdef WIN32
_OEM_INTERN(G.filename);
#endif
renamed = TRUE;
goto startover;
case 'A':
G.overwrite_mode = OVERWRT_ALWAYS;
case 'y':
case 'Y':
break;
case 'N':
G.overwrite_mode = OVERWRT_NEVER;
case 'n':
skip_entry = SKIP_Y_EXISTING;
break;
default:
Info(slide, 1, ((char *)slide,
LoadFarString(InvalidResponse), *G.answerbuf));
goto reprompt;
}
#endif
}
if (skip_entry != SKIP_NO) {
#ifdef WINDLL
if (skip_entry == SKIP_Y_EXISTING) {
Info(slide, 0, ((char *)slide,
((IS_OVERWRT_NONE || !uO.uflag || renamed) ?
"Target file exists.\nSkipping %s\n" :
"Target file newer.\nSkipping %s\n"),
FnFilter1(G.filename)));
}
#endif
continue;
}
}
#ifdef DLL
if ((G.statreportcb != NULL) &&
(*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn,
G.filename, NULL)) {
return IZ_CTRLC;
}
#endif
#ifdef MACOS
UserStop();
#endif
#ifdef AMIGA
G.filenote_slot = i;
#endif
G.disk_full = 0;
if ((error = extract_or_test_member(__G)) != PK_COOL) {
if (error > error_in_archive)
error_in_archive = error;
#ifdef DLL
if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
#else
if (G.disk_full > 1) {
#endif
return error_in_archive; /* (unless disk full) */
}
}
#ifdef DLL
if ((G.statreportcb != NULL) &&
(*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn,
G.filename, (zvoid *)&G.lrec.ucsize)) {
return IZ_CTRLC;
}
#endif
#ifdef MACOS
UserStop();
#endif
}
return error_in_archive;
}
static int extract_or_test_member(__G)
__GDEF
{
char *nul="[empty] ", *txt="[text] ", *bin="[binary]";
#ifdef CMS_MVS
char *ebc="[ebcdic]";
#endif
register int b;
int r, error=PK_COOL;
#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
ulg wsize;
#else
# define wsize WSIZE
#endif
Initialize variables, buffers, etc.
---------------------------------------------------------------------------*/
G.bits_left = 0;
G.bitbuf = 0L;
G.zipeof = 0;
G.newfile = TRUE;
G.crc32val = CRCVAL_INITIAL;
#ifdef SYMLINKS
* to disk, prepare to restore the link */
if (S_ISLNK(G.pInfo->file_attr) &&
(G.pInfo->hostnum == UNIX_ || G.pInfo->hostnum == ATARI_ ||
G.pInfo->hostnum == BEOS_) &&
!uO.tflag && !uO.cflag && (G.lrec.ucsize > 0))
G.symlnk = TRUE;
else
G.symlnk = FALSE;
#endif
if (uO.tflag) {
if (!uO.qflag)
Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), "test",
FnFilter1(G.filename), "", ""));
} else {
#ifdef DLL
if (uO.cflag && !G.redirect_data)
#else
if (uO.cflag)
#endif
{
#if (defined(OS2) && defined(__IBMC__) && (__IBMC__ >= 200))
G.outfile = freopen("", "wb", stdout);
#else
G.outfile = stdout;
#endif
#ifdef DOS_FLX_NLM_OS2_W32
#if (defined(__HIGHC__) && !defined(FLEXOS))
setmode(G.outfile, _BINARY);
#else
setmode(fileno(G.outfile), O_BINARY);
#endif
# define NEWLINE "\r\n"
#else
# define NEWLINE "\n"
#endif
#ifdef VMS
if (open_outfile(__G))
return PK_DISK;
#endif
} else if (open_outfile(__G))
return PK_DISK;
}
Unpack the file.
---------------------------------------------------------------------------*/
defer_leftover_input(__G);
switch (G.lrec.compression_method) {
case STORED:
if (!uO.tflag && QCOND2) {
#ifdef SYMLINKS
if (G.symlnk)
Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
"link", FnFilter1(G.filename), "", ""));
else
#endif
Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
"extract", FnFilter1(G.filename),
(uO.aflag != 1 )?
"" : (G.lrec.ucsize == 0L? nul : (G.pInfo->textfile? txt :
bin)), uO.cflag? NEWLINE : ""));
}
#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
if (G.redirect_slide) {
wsize = G.redirect_size; redirSlide = G.redirect_buffer;
} else {
wsize = WSIZE; redirSlide = slide;
}
#endif
G.outptr = redirSlide;
G.outcnt = 0L;
while ((b = NEXTBYTE) != EOF) {
*G.outptr++ = (uch)b;
if (++G.outcnt == wsize) {
error = flush(__G__ redirSlide, G.outcnt, 0);
G.outptr = redirSlide;
G.outcnt = 0L;
if (error != PK_COOL || G.disk_full) break;
}
}
if (G.outcnt)
flush(__G__ redirSlide, G.outcnt, 0);
break;
#ifndef SFX
#ifndef LZW_CLEAN
case SHRUNK:
if (!uO.tflag && QCOND2) {
Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
LoadFarStringSmall(Unshrink), FnFilter1(G.filename),
(uO.aflag != 1 )?
"" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
}
if ((r = unshrink(__G)) != PK_COOL) {
if (r < PK_DISK) {
if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
Info(slide, 0x401, ((char *)slide,
LoadFarStringSmall(ErrUnzipFile),
LoadFarString(NotEnoughMem),
LoadFarStringSmall2(Unshrink),
FnFilter1(G.filename)));
else
Info(slide, 0x401, ((char *)slide,
LoadFarStringSmall(ErrUnzipNoFile),
LoadFarString(NotEnoughMem),
LoadFarStringSmall2(Unshrink)));
}
error = r;
}
break;
#endif
#ifndef COPYRIGHT_CLEAN
case REDUCED1:
case REDUCED2:
case REDUCED3:
case REDUCED4:
if (!uO.tflag && QCOND2) {
Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
"unreduc", FnFilter1(G.filename),
(uO.aflag != 1 )?
"" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
}
if ((r = unreduce(__G)) != PK_COOL) {
error = r;
}
break;
#endif
case IMPLODED:
if (!uO.tflag && QCOND2) {
Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
"explod", FnFilter1(G.filename),
(uO.aflag != 1 )?
"" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
}
if (((r = explode(__G)) != 0) && (r != 5)) {
if (r < PK_DISK) {
if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
Info(slide, 0x401, ((char *)slide,
LoadFarStringSmall(ErrUnzipFile), r == 3?
LoadFarString(NotEnoughMem) :
LoadFarString(InvalidComprData),
LoadFarStringSmall2(Explode),
FnFilter1(G.filename)));
else
Info(slide, 0x401, ((char *)slide,
LoadFarStringSmall(ErrUnzipNoFile), r == 3?
LoadFarString(NotEnoughMem) :
LoadFarString(InvalidComprData),
LoadFarStringSmall2(Explode)));
error = (r == 3)? PK_MEM3 : PK_ERR;
} else {
error = r;
}
}
if (r == 5) {
int warning = ((ulg)G.used_csize <= G.lrec.csize);
if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
Info(slide, 0x401, ((char *)slide, LoadFarString(LengthMsg),
"", warning? "warning" : "error", G.used_csize,
G.lrec.ucsize, warning? " " : "", G.lrec.csize,
" [", FnFilter1(G.filename), "]"));
else
Info(slide, 0x401, ((char *)slide, LoadFarString(LengthMsg),
"\n", warning? "warning" : "error", G.used_csize,
G.lrec.ucsize, warning? " ":"", G.lrec.csize,
"", "", "."));
error = warning? PK_WARN : PK_ERR;
}
break;
#endif
case DEFLATED:
#ifdef USE_DEFLATE64
case ENHDEFLATED:
#endif
if (!uO.tflag && QCOND2) {
Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg),
"inflat", FnFilter1(G.filename),
(uO.aflag != 1 )?
"" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : ""));
}
#ifndef USE_ZLIB
# define UZinflate inflate
#endif
if ((r = UZinflate(__G__
(G.lrec.compression_method == ENHDEFLATED)))
!= 0) {
if (r < PK_DISK) {
if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
Info(slide, 0x401, ((char *)slide,
LoadFarStringSmall(ErrUnzipFile), r == 3?
LoadFarString(NotEnoughMem) :
LoadFarString(InvalidComprData),
LoadFarStringSmall2(Inflate),
FnFilter1(G.filename)));
else
Info(slide, 0x401, ((char *)slide,
LoadFarStringSmall(ErrUnzipNoFile), r == 3?
LoadFarString(NotEnoughMem) :
LoadFarString(InvalidComprData),
LoadFarStringSmall2(Inflate)));
error = (r == 3)? PK_MEM3 : PK_ERR;
} else {
error = r;
}
}
break;
default:
Info(slide, 0x401, ((char *)slide,
LoadFarString(FileUnknownCompMethod), FnFilter1(G.filename)));
undefer_input(__G);
return PK_WARN;
}
Close the file and set its date and time (not necessarily in that order),
and make sure the CRC checked out OK. Logical-AND the CRC for 64-bit
machines (redundant on 32-bit machines).
---------------------------------------------------------------------------*/
#ifdef VMS
if (!uO.tflag)
close_outfile(__G);
#else
#ifdef DLL
if (!uO.tflag && (!uO.cflag || G.redirect_data)) {
if (G.redirect_data)
FINISH_REDIRECT();
else
close_outfile(__G);
}
#else
if (!uO.tflag && !uO.cflag)
close_outfile(__G);
#endif
#endif
if (G.disk_full) {
if (G.disk_full > 1) {
#if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK))
if (unlink(G.filename) != 0)
Trace((stderr, "extract.c: could not delete %s\n",
FnFilter1(G.filename)));
#else
Info(slide, 0x421, ((char *)slide, LoadFarString(FileTruncated),
FnFilter1(G.filename)));
#endif
error = PK_DISK;
} else {
error = PK_WARN;
}
}
if (error > PK_WARN) {
undefer_input(__G);
return error;
}
if (G.crc32val != G.lrec.crc32) {
if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))
Info(slide, 0x401, ((char *)slide, "%-22s ",
FnFilter1(G.filename)));
Info(slide, 0x401, ((char *)slide, LoadFarString(BadCRC), G.crc32val,
G.lrec.crc32));
#if CRYPT
if (G.pInfo->encrypted)
Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeBadPasswd)));
#endif
error = PK_ERR;
} else if (uO.tflag) {
#ifndef SFX
if (G.extra_field) {
if ((r = TestExtraField(__G__ G.extra_field,
G.lrec.extra_field_length)) > error)
error = r;
} else
#endif
if (!uO.qflag)
Info(slide, 0, ((char *)slide, " OK\n"));
} else {
if (QCOND2 && !error)
Info(slide, 0, ((char *)slide, "\n"));
}
undefer_input(__G);
return error;
}
#ifndef SFX
static int TestExtraField(__G__ ef, ef_len)
__GDEF
uch *ef;
unsigned ef_len;
{
ush ebID;
unsigned ebLen;
unsigned eb_cmpr_offs = 0;
int r;
* wouldn't be here ==> print filename if any extra-field errors found
*/
while (ef_len >= EB_HEADSIZE) {
ebID = makeword(ef);
ebLen = (unsigned)makeword(ef+EB_LEN);
if (ebLen > (ef_len - EB_HEADSIZE)) {
if (uO.qflag)
Info(slide, 1, ((char *)slide, "%-22s ",
FnFilter1(G.filename)));
Info(slide, 1, ((char *)slide, LoadFarString(InconsistEFlength),
ebLen, (ef_len - EB_HEADSIZE)));
return PK_ERR;
}
switch (ebID) {
case EF_OS2:
case EF_ACL:
case EF_MAC3:
case EF_BEOS:
switch (ebID) {
case EF_OS2:
case EF_ACL:
eb_cmpr_offs = EB_OS2_HLEN;
break;
case EF_MAC3:
if (ebLen >= EB_MAC3_HLEN &&
(makeword(ef+(EB_HEADSIZE+EB_FLGS_OFFS))
& EB_M3_FL_UNCMPR) &&
(makelong(ef+EB_HEADSIZE) == ebLen - EB_MAC3_HLEN))
eb_cmpr_offs = 0;
else
eb_cmpr_offs = EB_MAC3_HLEN;
break;
case EF_BEOS:
if (ebLen >= EB_BEOS_HLEN &&
(*(ef+(EB_HEADSIZE+EB_FLGS_OFFS)) & EB_BE_FL_UNCMPR) &&
(makelong(ef+EB_HEADSIZE) == ebLen - EB_BEOS_HLEN))
eb_cmpr_offs = 0;
else
eb_cmpr_offs = EB_BEOS_HLEN;
break;
}
if ((r = test_compr_eb(__G__ ef, ebLen, eb_cmpr_offs, NULL))
!= PK_OK) {
if (uO.qflag)
Info(slide, 1, ((char *)slide, "%-22s ",
FnFilter1(G.filename)));
switch (r) {
case IZ_EF_TRUNC:
Info(slide, 1, ((char *)slide,
LoadFarString(TruncEAs),
ebLen-(eb_cmpr_offs+EB_CMPRHEADLEN), "\n"));
break;
case PK_ERR:
Info(slide, 1, ((char *)slide,
LoadFarString(InvalidComprDataEAs)));
break;
case PK_MEM3:
case PK_MEM4:
Info(slide, 1, ((char *)slide,
LoadFarString(NotEnoughMemEAs)));
break;
default:
if ((r & 0xff) != PK_ERR)
Info(slide, 1, ((char *)slide,
LoadFarString(UnknErrorEAs)));
else {
ush m = (ush)(r >> 8);
if (m == DEFLATED)
Info(slide, 1, ((char *)slide,
LoadFarString(BadCRC_EAs)));
else
Info(slide, 1, ((char *)slide,
LoadFarString(UnknComprMethodEAs), m));
}
break;
}
return r;
}
break;
case EF_NTSD:
Trace((stderr, "ebID: %i / ebLen: %u\n", ebID, ebLen));
r = ebLen < EB_NTSD_L_LEN ? IZ_EF_TRUNC :
((ef[EB_HEADSIZE+EB_NTSD_VERSION] > EB_NTSD_MAX_VER) ?
(PK_WARN | 0x4000) :
test_compr_eb(__G__ ef, ebLen, EB_NTSD_L_LEN, TEST_NTSD));
if (r != PK_OK) {
if (uO.qflag)
Info(slide, 1, ((char *)slide, "%-22s ",
FnFilter1(G.filename)));
switch (r) {
case IZ_EF_TRUNC:
Info(slide, 1, ((char *)slide,
LoadFarString(TruncNTSD),
ebLen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n"));
break;
#if (defined(WIN32) && defined(NTSD_EAS))
case PK_WARN:
Info(slide, 1, ((char *)slide,
LoadFarString(InvalidSecurityEAs)));
break;
#endif
case PK_ERR:
Info(slide, 1, ((char *)slide,
LoadFarString(InvalidComprDataEAs)));
break;
case PK_MEM3:
case PK_MEM4:
Info(slide, 1, ((char *)slide,
LoadFarString(NotEnoughMemEAs)));
break;
case (PK_WARN | 0x4000):
Info(slide, 1, ((char *)slide,
LoadFarString(UnsuppNTSDVersEAs),
(int)ef[EB_HEADSIZE+EB_NTSD_VERSION]));
r = PK_WARN;
break;
default:
if ((r & 0xff) != PK_ERR)
Info(slide, 1, ((char *)slide,
LoadFarString(UnknErrorEAs)));
else {
ush m = (ush)(r >> 8);
if (m == DEFLATED)
Info(slide, 1, ((char *)slide,
LoadFarString(BadCRC_EAs)));
else
Info(slide, 1, ((char *)slide,
LoadFarString(UnknComprMethodEAs), m));
}
break;
}
return r;
}
break;
case EF_PKVMS:
if (makelong(ef+EB_HEADSIZE) !=
crc32(CRCVAL_INITIAL, ef+(EB_HEADSIZE+4),
(extent)(ebLen-4)))
Info(slide, 1, ((char *)slide,
LoadFarString(BadCRC_EAs)));
break;
case EF_PKW32:
case EF_PKUNIX:
case EF_ASIUNIX:
case EF_IZVMS:
case EF_IZUNIX:
case EF_VMCMS:
case EF_MVS:
case EF_SPARK:
case EF_TANDEM:
case EF_THEOS:
case EF_AV:
default:
break;
}
ef_len -= (ebLen + EB_HEADSIZE);
ef += (ebLen + EB_HEADSIZE);
}
if (!uO.qflag)
Info(slide, 0, ((char *)slide, " OK\n"));
return PK_COOL;
}
#ifdef PROTO
static int test_compr_eb(
__GPRO__
uch *eb,
unsigned eb_size,
unsigned compr_offset,
int (*test_uc_ebdata)(__GPRO__ uch *eb, unsigned eb_size,
uch *eb_ucptr, ulg eb_ucsize))
#else
static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
__GDEF
uch *eb;
unsigned eb_size;
unsigned compr_offset;
int (*test_uc_ebdata)();
#endif
{
ulg eb_ucsize;
uch *eb_ucptr;
int r;
if (compr_offset < 4)
return PK_OK;
if ((eb_size < (EB_UCSIZE_P + 4)) ||
((eb_ucsize = makelong(eb+(EB_HEADSIZE+EB_UCSIZE_P))) > 0L &&
eb_size <= (compr_offset + EB_CMPRHEADLEN)))
return IZ_EF_TRUNC;
if ((eb_ucptr = (uch *)malloc((extent)eb_ucsize)) == (uch *)NULL)
return PK_MEM4;
r = memextract(__G__ eb_ucptr, eb_ucsize,
eb + (EB_HEADSIZE + compr_offset),
(ulg)(eb_size - compr_offset));
if (r == PK_OK && test_uc_ebdata != NULL)
r = (*test_uc_ebdata)(__G__ eb, eb_size, eb_ucptr, eb_ucsize);
free(eb_ucptr);
return r;
}
#endif
int memextract(__G__ tgt, tgtsize, src, srcsize)
__GDEF
uch *tgt;
ulg tgtsize;
ZCONST uch *src;
ulg srcsize;
{
long old_csize=G.csize;
uch *old_inptr=G.inptr;
int old_incnt=G.incnt;
int r, error=PK_OK;
ush method;
ulg extra_field_crc;
method = makeword(src);
extra_field_crc = makelong(src+2);
G.inptr = (uch *)src + (2 + 4);
G.incnt = (int)(G.csize = (long)(srcsize - (2 + 4)));
G.mem_mode = TRUE;
G.outbufptr = tgt;
G.outsize = tgtsize;
switch (method) {
case STORED:
memcpy((char *)tgt, (char *)G.inptr, (extent)G.incnt);
G.outcnt = G.csize;
break;
case DEFLATED:
#ifdef USE_DEFLATE64
case ENHDEFLATED:
#endif
G.outcnt = 0L;
if ((r = UZinflate(__G__ (method == ENHDEFLATED))) != 0) {
if (!uO.tflag)
Info(slide, 0x401, ((char *)slide,
LoadFarStringSmall(ErrUnzipNoFile), r == 3?
LoadFarString(NotEnoughMem) :
LoadFarString(InvalidComprData),
LoadFarStringSmall2(Inflate)));
error = (r == 3)? PK_MEM3 : PK_ERR;
}
if (G.outcnt == 0L)
break;
break;
default:
if (uO.tflag)
error = PK_ERR | ((int)method << 8);
else {
Info(slide, 0x401, ((char *)slide,
LoadFarString(UnsupportedExtraField), method));
error = PK_ERR;
}
break;
}
G.inptr = old_inptr;
G.incnt = old_incnt;
G.csize = old_csize;
G.mem_mode = FALSE;
if (!error) {
register ulg crcval = crc32(CRCVAL_INITIAL, tgt, (extent)G.outcnt);
if (crcval != extra_field_crc) {
if (uO.tflag)
error = PK_ERR | (DEFLATED << 8);
else {
Info(slide, 0x401, ((char *)slide,
LoadFarString(BadExtraFieldCRC), G.zipfn, crcval,
extra_field_crc));
error = PK_ERR;
}
}
}
return error;
}
int memflush(__G__ rawbuf, size)
__GDEF
ZCONST uch *rawbuf;
ulg size;
{
if (size > G.outsize)
"overflow of output space", its use may be tolerated. */
return PK_DISK;
memcpy((char *)G.outbufptr, (char *)rawbuf, (extent)size);
G.outbufptr += (unsigned int)size;
G.outsize -= size;
G.outcnt += size;
return 0;
}
#if (defined(VMS) || defined(VMS_TEXT_CONV))
* Extracts block from p. If resulting length is less then needed, fill
* extra space with corresponding bytes from 'init'.
* Currently understands 3 formats of block compression:
* - Simple storing
* - Compression of zero bytes to zero bits
* - Deflation (see memextract())
* The IZVMS block data is returned in malloc'd space.
*/
uch *extract_izvms_block(__G__ ebdata, size, retlen, init, needlen)
__GDEF
ZCONST uch *ebdata;
unsigned size;
unsigned *retlen;
ZCONST uch *init;
unsigned needlen;
{
uch *ucdata;
int cmptype;
unsigned usiz, csiz;
cmptype = (makeword(ebdata+EB_IZVMS_FLGS) & EB_IZVMS_BCMASK);
csiz = size - EB_IZVMS_HLEN;
usiz = (cmptype == EB_IZVMS_BCSTOR ?
csiz : makeword(ebdata+EB_IZVMS_UCSIZ));
if (retlen)
*retlen = usiz;
if ((ucdata = (uch *)malloc(MAX(needlen, usiz))) == NULL)
return NULL;
if (init && (usiz < needlen))
memcpy((char *)ucdata, (ZCONST char *)init, needlen);
switch (cmptype)
{
case EB_IZVMS_BCSTOR:
memcpy(ucdata, ebdata+EB_IZVMS_HLEN, usiz);
break;
case EB_IZVMS_BC00:
decompress_bits(ucdata, usiz, ebdata+EB_IZVMS_HLEN);
break;
case EB_IZVMS_BCDEFL:
memextract(__G__ ucdata, (ulg)usiz,
ebdata+EB_IZVMS_HLEN, (ulg)csiz);
break;
default:
free(ucdata);
ucdata = NULL;
}
return ucdata;
}
* Simple uncompression routine. The compression uses bit stream.
* Compression scheme:
*
* if (byte!=0)
* putbit(1),putbyte(byte)
* else
* putbit(0)
*/
static void decompress_bits(outptr, needlen, bitptr)
uch *outptr;
unsigned needlen;
ZCONST uch *bitptr;
{
ulg bitbuf = 0;
int bitcnt = 0;
#define _FILL { bitbuf |= (*bitptr++) << bitcnt;\
bitcnt += 8; \
}
while (needlen--)
{
if (bitcnt <= 0)
_FILL;
if (bitbuf & 1)
{
bitbuf >>= 1;
if ((bitcnt -= 1) < 8)
_FILL;
*outptr++ = (uch)bitbuf;
bitcnt -= 8;
bitbuf >>= 8;
}
else
{
*outptr++ = '\0';
bitcnt -= 1;
bitbuf >>= 1;
}
}
}
#endif
char *fnfilter(raw, space)
ZCONST char *raw;
uch *space;
{
#ifndef NATIVE
ZCONST uch *r=(ZCONST uch *)raw;
uch *s=space;
while (*r) {
#ifdef QDOS
if (qlflag & 2) {
if (*r == '/' || *r == '.') {
++r;
*s++ = '_';
continue;
}
} else
#endif
if (*r < 32) {
*s++ = '^', *s++ = (uch)(64 + *r++);
} else {
#ifdef _MBCS
unsigned i;
for (i = CLEN(r); i > 0; i--)
*s++ = *r++;
#else
*s++ = *r++;
#endif
}
}
*s = '\0';
#ifdef WINDLL
INTERN_TO_ISO((char *)space, (char *)space);
#else
#ifdef WIN32
WinNT console is set to OEM charset by default, too */
INTERN_TO_OEM((char *)space, (char *)space);
#endif
#endif
return (char *)space;
#else
return (char *)raw;
#endif
}
#ifdef SET_DIR_ATTRIB
static int dircomp(a, b)
ZCONST zvoid *a, *b;
{
return strcmp((*(dirtime **)b)->fn, (*(dirtime **)a)->fn);
}
#if 0
static int namecmp(s1, s2)
ZCONST char *s1, *s2;
{
int d;
for (;;) {
d = (int)(uch)case_map(*s1)
- (int)(uch)case_map(*s2);
if (d || *s1 == 0 || *s2 == 0)
return d;
s1++;
s2++;
}
}
#endif
#endif