Submitted By: Ken Moffat Date: 2019-12-03 Initial Package Version: 6.0 Upstream Status: Some from upstream, but that now appears to be defunct. Origin: Found at fedora (omitting their manpage and symlinks patches) Description: 1. Allow it to use system libbz2.so, this allows unzip and zipinfo to deal with archives which contain bz2 compressed members. 2. Locale fixes to handle non-latin non-unicode filenames, originally from Arch but updated by Canonical to fix buffer overflow and to print them (apparently from fedora or redhat) - not tested! 3. A large number of security fixes, including for CVE-2014-81{39..41}, CVE-2016-9844, CVE-2018-18384, CVE-2018-1000035 as well as several similar overflow fixes not labelled with CVE numbers and a few general fixes. diff -Naur a/crc_i386.S b/crc_i386.S --- a/crc_i386.S 2007-01-07 05:02:58.000000000 +0000 +++ b/crc_i386.S 2019-12-01 23:48:05.278335299 +0000 @@ -302,3 +302,6 @@ #endif /* i386 || _i386 || _I386 || __i386 */ #endif /* !USE_ZLIB && !CRC_TABLE_ONLY */ + +.section .note.GNU-stack, "", @progbits +.previous diff -Naur a/crypt.c b/crypt.c --- a/crypt.c 2007-01-05 15:47:36.000000000 +0000 +++ b/crypt.c 2019-12-02 00:37:13.921788251 +0000 @@ -465,7 +465,17 @@ GLOBAL(pInfo->encrypted) = FALSE; defer_leftover_input(__G); for (n = 0; n < RAND_HEAD_LEN; n++) { - b = NEXTBYTE; + /* 2012-11-23 SMS. (OUSPG report.) + * Quit early if compressed size < HEAD_LEN. The resulting + * error message ("unable to get password") could be improved, + * but it's better than trying to read nonexistent data, and + * then continuing with a negative G.csize. (See + * fileio.c:readbyte()). + */ + if ((b = NEXTBYTE) == (ush)EOF) + { + return PK_ERR; + } h[n] = (uch)b; Trace((stdout, " (%02x)", h[n])); } diff -Naur a/extract.c b/extract.c --- a/extract.c 2009-03-14 01:32:52.000000000 +0000 +++ b/extract.c 2019-12-02 01:05:52.857702371 +0000 @@ -1,5 +1,5 @@ /* - Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + Copyright (c) 1990-2014 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2009-Jan-02 or later (the contents of which are also included in unzip.h) for terms of use. @@ -298,6 +298,8 @@ #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 TooSmallEBlength[] = "bad extra-field entry:\n \ + EF block length (%u bytes) invalid (< %d)\n"; static ZCONST char Far InvalidComprDataEAs[] = " invalid compressed data for EAs\n"; # if (defined(WIN32) && defined(NTSD_EAS)) @@ -472,8 +474,8 @@ */ Info(slide, 0x401, ((char *)slide, LoadFarString(CentSigMsg), j + blknum*DIR_BLKSIZ + 1)); - Info(slide, 0x401, ((char *)slide, - LoadFarString(ReportMsg))); + Info(slide, 0x401, + ((char *)slide,"%s", LoadFarString(ReportMsg))); error_in_archive = PK_BADERR; } reached_end = TRUE; /* ...so no more left to do */ @@ -752,8 +754,8 @@ #ifndef SFX if (no_endsig_found) { /* just to make sure */ - Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg))); - Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg))); + Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg))); + Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(ReportMsg))); if (!error_in_archive) /* don't overwrite stronger error */ error_in_archive = PK_WARN; } @@ -1255,8 +1257,17 @@ if (G.lrec.compression_method == STORED) { zusz_t csiz_decrypted = G.lrec.csize; - if (G.pInfo->encrypted) + if (G.pInfo->encrypted) { + if (csiz_decrypted < 12) { + /* handle the error now to prevent unsigned overflow */ + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipNoFile), + LoadFarString(InvalidComprData), + LoadFarStringSmall2(Inflate))); + return PK_ERR; + } csiz_decrypted -= 12; + } if (G.lrec.ucsize != csiz_decrypted) { Info(slide, 0x401, ((char *)slide, LoadFarStringSmall2(WrnStorUCSizCSizDiff), @@ -1924,24 +1935,21 @@ #ifdef VMS /* VMS: required even for stdout! (final flush) */ if (!uO.tflag) /* don't close NULL file */ - close_outfile(__G); + error = close_outfile(__G); #else #ifdef DLL if (!uO.tflag && (!uO.cflag || G.redirect_data)) { if (G.redirect_data) FINISH_REDIRECT(); else - close_outfile(__G); + error = close_outfile(__G); } #else if (!uO.tflag && !uO.cflag) /* don't close NULL file or stdout */ - close_outfile(__G); + error = close_outfile(__G); #endif #endif /* VMS */ - /* GRR: CONVERT close_outfile() TO NON-VOID: CHECK FOR ERRORS! */ - - if (G.disk_full) { /* set by flush() */ if (G.disk_full > 1) { #if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK)) @@ -2023,7 +2031,8 @@ ebID = makeword(ef); ebLen = (unsigned)makeword(ef+EB_LEN); - if (ebLen > (ef_len - EB_HEADSIZE)) { + if (ebLen > (ef_len - EB_HEADSIZE)) + { /* Discovered some extra field inconsistency! */ if (uO.qflag) Info(slide, 1, ((char *)slide, "%-22s ", @@ -2158,11 +2167,29 @@ } 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))); + /* 2015-01-30 SMS. Added sufficient-bytes test/message + * here. (Removed defective ebLen test above.) + * + * If sufficient bytes (EB_PKVMS_MINLEN) are available, + * then compare the stored CRC value with the calculated + * CRC for the remainder of the data (and complain about + * a mismatch). + */ + if (ebLen < EB_PKVMS_MINLEN) + { + /* Insufficient bytes available. */ + Info( slide, 1, + ((char *)slide, LoadFarString( TooSmallEBlength), + ebLen, EB_PKVMS_MINLEN)); + } + else if (makelong(ef+ EB_HEADSIZE) != + crc32(CRCVAL_INITIAL, + (ef+ EB_HEADSIZE+ EB_PKVMS_MINLEN), + (extent)(ebLen- EB_PKVMS_MINLEN))) + { + Info(slide, 1, ((char *)slide, + LoadFarString(BadCRC_EAs))); + } break; case EF_PKW32: case EF_PKUNIX: @@ -2217,14 +2244,28 @@ ulg eb_ucsize; uch *eb_ucptr; int r; + ush method; if (compr_offset < 4) /* field is not compressed: */ return PK_OK; /* do nothing and signal OK */ + /* Return no/bad-data error status if any problem is found: + * 1. eb_size is too small to hold the uncompressed size + * (eb_ucsize). (Else extract eb_ucsize.) + * 2. eb_ucsize is zero (invalid). 2014-12-04 SMS. + * 3. eb_ucsize is positive, but eb_size is too small to hold + * the compressed data header. + */ 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; /* no compressed data! */ + ((eb_ucsize = makelong( eb+ (EB_HEADSIZE+ EB_UCSIZE_P))) == 0L) || + ((eb_ucsize > 0L) && (eb_size <= (compr_offset + EB_CMPRHEADLEN)))) + return IZ_EF_TRUNC; /* no/bad compressed data! */ + + method = makeword(eb + (EB_HEADSIZE + compr_offset)); + if ((method == STORED) && (eb_size != compr_offset + EB_CMPRHEADLEN + eb_ucsize)) + return PK_ERR; /* compressed & uncompressed + * should match in STORED + * method */ if ( #ifdef INT_16BIT @@ -2542,8 +2583,21 @@ } /* end function set_deferred_symlink() */ #endif /* SYMLINKS */ +/* + * If Unicode is supported, assume we have what we need to do this + * check using wide characters, avoiding MBCS issues. + */ - +#ifndef UZ_FNFILTER_REPLACECHAR + /* A convenient choice for the replacement of unprintable char codes is + * the "single char wildcard", as this character is quite unlikely to + * appear in filenames by itself. The following default definition + * sets the replacement char to a question mark as the most common + * "single char wildcard"; this setting should be overridden in the + * appropiate system-specific configuration header when needed. + */ +# define UZ_FNFILTER_REPLACECHAR '?' +#endif /*************************/ /* Function fnfilter() */ /* here instead of in list.c for SFX */ @@ -2555,48 +2609,168 @@ extent size; { #ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */ - ZCONST uch *r=(ZCONST uch *)raw; + ZCONST uch *r; // =(ZCONST uch *)raw; uch *s=space; uch *slim=NULL; uch *se=NULL; int have_overflow = FALSE; - if (size > 0) { - slim = space + size -#ifdef _MBCS - - (MB_CUR_MAX - 1) -#endif - - 4; +# if defined( UNICODE_SUPPORT) && defined( _MBCS) +/* If Unicode support is enabled, and we have multi-byte characters, + * then do the isprint() checks by first converting to wide characters + * and checking those. This avoids our having to parse multi-byte + * characters for ourselves. After the wide-char replacements have been + * made, the wide string is converted back to the local character set. + */ + wchar_t *wstring; /* wchar_t version of raw */ + size_t wslen; /* length of wstring */ + wchar_t *wostring; /* wchar_t version of output string */ + size_t woslen; /* length of wostring */ + char *newraw; /* new raw */ + + /* 2012-11-06 SMS. + * Changed to check the value returned by mbstowcs(), and bypass the + * Unicode processing if it fails. This seems to fix a problem + * reported in the SourceForge forum, but it's not clear that we + * should be doing any Unicode processing without some evidence that + * the name actually is Unicode. (Check bit 11 in the flags before + * coming here?) + * http://sourceforge.net/p/infozip/bugs/40/ + */ + + if (MB_CUR_MAX <= 1) + { + /* There's no point to converting multi-byte chars if there are + * no multi-byte chars. + */ + wslen = (size_t)-1; } - while (*r) { - if (size > 0 && s >= slim && se == NULL) { - se = s; - } -#ifdef QDOS - if (qlflag & 2) { - if (*r == '/' || *r == '.') { + else + { + /* Get Unicode wide character count (for storage allocation). */ + wslen = mbstowcs( NULL, raw, 0); + } + + if (wslen != (size_t)-1) + { + /* Apparently valid Unicode. Allocate wide-char storage. */ + wstring = (wchar_t *)malloc((wslen + 1) * sizeof(wchar_t)); + if (wstring == NULL) { + strcpy( (char *)space, raw); + return (char *)space; + } + wostring = (wchar_t *)malloc(2 * (wslen + 1) * sizeof(wchar_t)); + if (wostring == NULL) { + free(wstring); + strcpy( (char *)space, raw); + return (char *)space; + } + + /* Convert the multi-byte Unicode to wide chars. */ + wslen = mbstowcs(wstring, raw, wslen + 1); + + /* Filter the wide-character string. */ + fnfilterw( wstring, wostring, (2 * (wslen + 1) * sizeof(wchar_t))); + + /* Convert filtered wide chars back to multi-byte. */ + woslen = wcstombs( NULL, wostring, 0); + if ((newraw = malloc(woslen + 1)) == NULL) { + free(wstring); + free(wostring); + strcpy( (char *)space, raw); + return (char *)space; + } + woslen = wcstombs( newraw, wostring, (woslen * MB_CUR_MAX) + 1); + + if (size > 0) { + slim = space + size - 4; + } + r = (ZCONST uch *)newraw; + while (*r) { + if (size > 0 && s >= slim && se == NULL) { + se = s; + } +# ifdef QDOS + if (qlflag & 2) { + if (*r == '/' || *r == '.') { + if (se != NULL && (s > (space + (size-3)))) { + have_overflow = TRUE; + break; + } + ++r; + *s++ = '_'; + continue; + } + } else +# endif + { if (se != NULL && (s > (space + (size-3)))) { have_overflow = TRUE; break; } - ++r; - *s++ = '_'; - continue; + *s++ = *r++; } - } else + } + if (have_overflow) { + strcpy((char *)se, "..."); + } else { + *s = '\0'; + } + + free(wstring); + free(wostring); + free(newraw); + } + else +# endif /* defined( UNICODE_SUPPORT) && defined( _MBCS) */ + { + /* No Unicode support, or apparently invalid Unicode. */ + r = (ZCONST uch *)raw; + + if (size > 0) { + slim = space + size +#ifdef _MBCS + - (MB_CUR_MAX - 1) +#endif + - 4; + } + while (*r) { + if (size > 0 && s >= slim && se == NULL) { + se = s; + } +#ifdef QDOS + if (qlflag & 2) { + if (*r == '/' || *r == '.') { + if (se != NULL && (s > (space + (size-3)))) { + have_overflow = TRUE; + break; + } + ++r; + *s++ = '_'; + continue; + } + } else #endif #ifdef HAVE_WORKING_ISPRINT -# ifndef UZ_FNFILTER_REPLACECHAR - /* A convenient choice for the replacement of unprintable char codes is - * the "single char wildcard", as this character is quite unlikely to - * appear in filenames by itself. The following default definition - * sets the replacement char to a question mark as the most common - * "single char wildcard"; this setting should be overridden in the - * appropiate system-specific configuration header when needed. - */ -# define UZ_FNFILTER_REPLACECHAR '?' -# endif - if (!isprint(*r)) { + if (!isprint(*r)) { + if (*r < 32) { + /* ASCII control codes are escaped as "^{letter}". */ + if (se != NULL && (s > (space + (size-4)))) { + have_overflow = TRUE; + break; + } + *s++ = '^', *s++ = (uch)(64 + *r++); + } else { + /* Other unprintable codes are replaced by the + * placeholder character. */ + if (se != NULL && (s > (space + (size-3)))) { + have_overflow = TRUE; + break; + } + *s++ = UZ_FNFILTER_REPLACECHAR; + INCSTR(r); + } +#else /* !HAVE_WORKING_ISPRINT */ if (*r < 32) { /* ASCII control codes are escaped as "^{letter}". */ if (se != NULL && (s > (space + (size-4)))) { @@ -2604,47 +2778,30 @@ break; } *s++ = '^', *s++ = (uch)(64 + *r++); +#endif /* ?HAVE_WORKING_ISPRINT */ } else { - /* Other unprintable codes are replaced by the - * placeholder character. */ +#ifdef _MBCS + unsigned i = CLEN(r); + if (se != NULL && (s > (space + (size-i-2)))) { + have_overflow = TRUE; + break; + } + for (; i > 0; i--) + *s++ = *r++; +#else if (se != NULL && (s > (space + (size-3)))) { have_overflow = TRUE; break; } - *s++ = UZ_FNFILTER_REPLACECHAR; - INCSTR(r); - } -#else /* !HAVE_WORKING_ISPRINT */ - if (*r < 32) { - /* ASCII control codes are escaped as "^{letter}". */ - if (se != NULL && (s > (space + (size-4)))) { - have_overflow = TRUE; - break; - } - *s++ = '^', *s++ = (uch)(64 + *r++); -#endif /* ?HAVE_WORKING_ISPRINT */ - } else { -#ifdef _MBCS - unsigned i = CLEN(r); - if (se != NULL && (s > (space + (size-i-2)))) { - have_overflow = TRUE; - break; - } - for (; i > 0; i--) *s++ = *r++; -#else - if (se != NULL && (s > (space + (size-3)))) { - have_overflow = TRUE; - break; - } - *s++ = *r++; #endif - } - } - if (have_overflow) { - strcpy((char *)se, "..."); - } else { - *s = '\0'; + } + } + if (have_overflow) { + strcpy((char *)se, "..."); + } else { + *s = '\0'; + } } #ifdef WINDLL @@ -2666,6 +2823,53 @@ } /* end function fnfilter() */ +#if defined( UNICODE_SUPPORT) && defined( _MBCS) + +/****************************/ +/* Function fnfilter[w]() */ /* (Here instead of in list.c for SFX.) */ +/****************************/ + +/* fnfilterw() - Convert wide name to safely printable form. */ + +/* fnfilterw() - Convert wide-character name to safely printable form. */ + +wchar_t *fnfilterw( src, dst, siz) + ZCONST wchar_t *src; /* Pointer to source char (string). */ + wchar_t *dst; /* Pointer to destination char (string). */ + extent siz; /* Not used (!). */ +{ + wchar_t *dsx = dst; + + /* Filter the wide chars. */ + while (*src) + { + if (iswprint( *src)) + { + /* Printable code. Copy it. */ + *dst++ = *src; + } + else + { + /* Unprintable code. Substitute something printable for it. */ + if (*src < 32) + { + /* Replace ASCII control code with "^{letter}". */ + *dst++ = (wchar_t)'^'; + *dst++ = (wchar_t)(64 + *src); + } + else + { + /* Replace other unprintable code with the placeholder. */ + *dst++ = (wchar_t)UZ_FNFILTER_REPLACECHAR; + } + } + src++; + } + *dst = (wchar_t)0; /* NUL-terminate the destination string. */ + return dsx; +} /* fnfilterw(). */ + +#endif /* defined( UNICODE_SUPPORT) && defined( _MBCS) */ #ifdef SET_DIR_ATTRIB @@ -2701,6 +2905,12 @@ int repeated_buf_err; bz_stream bstrm; + if (G.incnt <= 0 && G.csize <= 0L) { + /* avoid an infinite loop */ + Trace((stderr, "UZbunzip2() got empty input\n")); + return 2; + } + #if (defined(DLL) && !defined(NO_SLIDE_REDIR)) if (G.redirect_slide) wsize = G.redirect_size, redirSlide = G.redirect_buffer; diff -Naur a/extract.c.orig b/extract.c.orig --- a/extract.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ b/extract.c.orig 2019-12-02 00:37:13.921788251 +0000 @@ -0,0 +1,2867 @@ +/* + Copyright (c) 1990-2014 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2009-Jan-02 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() + find_compr_idx() + extract_or_test_entrylist() + extract_or_test_member() + TestExtraField() + test_compr_eb() + memextract() + memflush() + extract_izvms_block() (VMS or VMS_TEXT_CONV) + set_deferred_symlink() (SYMLINKS only) + fnfilter() + dircomp() (SET_DIR_ATTRIB only) + UZbunzip2() (USE_BZIP2 only) + + ---------------------------------------------------------------------------*/ + + +#define __EXTRACT_C /* identifies this source module */ +#define UNZIP_INTERNAL +#include "unzip.h" +#ifdef WINDLL +# ifdef POCKET_UNZIP +# include "wince/intrface.h" +# else +# include "windll/windll.h" +# endif +#endif +#include "crc32.h" +#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, zoff_t *pold_extra_bytes, + unsigned *pnum_dirs, direntry **pdirlist, + int error_in_archive)); +#else +static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk, + ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *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 SYMLINKS + static void set_deferred_symlink OF((__GPRO__ slinkentry *slnk_entry)); +#endif +#ifdef SET_DIR_ATTRIB + static int Cdecl dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b)); +#endif + + + +/*******************************/ +/* Strings used in extract.c */ +/*******************************/ + +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 CmprBzip[] = "bzip2"; + static ZCONST char Far CmprLZMA[] = "LZMA"; + static ZCONST char Far CmprIBMTerse[] = "IBM/Terse"; + static ZCONST char Far CmprIBMLZ77[] = "IBM LZ77"; + static ZCONST char Far CmprWavPack[] = "WavPack"; + static ZCONST char Far CmprPPMd[] = "PPMd"; + static ZCONST char Far *ComprNames[NUM_METHODS] = { + CmprNone, CmprShrink, CmprReduce, CmprReduce, CmprReduce, CmprReduce, + CmprImplode, CmprTokenize, CmprDeflate, CmprDeflat64, CmprDCLImplode, + CmprBzip, CmprLZMA, CmprIBMTerse, CmprIBMLZ77, CmprWavPack, CmprPPMd + }; + static ZCONST unsigned ComprIDs[NUM_METHODS] = { + STORED, SHRUNK, REDUCED1, REDUCED2, REDUCED3, REDUCED4, + IMPLODED, TOKENIZED, DEFLATED, ENHDEFLATED, DCLIMPLODED, + BZIPPED, LZMAED, IBMTERSED, IBMLZ77ED, WAVPACKED, PPMDED + }; +#endif /* !SFX */ +static ZCONST char Far FilNamMsg[] = + "%s: bad filename length (%s)\n"; +#ifndef SFX + static ZCONST char Far WarnNoMemCFName[] = + "%s: warning, no memory for comparison with local header\n"; + static ZCONST char Far LvsCFNamMsg[] = + "%s: mismatching \"local\" filename (%s),\n\ + continuing with \"central\" filename version\n"; +#endif /* !SFX */ +#if (!defined(SFX) && defined(UNICODE_SUPPORT)) + static ZCONST char Far GP11FlagsDiffer[] = + "file #%lu (%s):\n\ + mismatch between local and central GPF bit 11 (\"UTF-8\"),\n\ + continuing with central flag (IsUTF8 = %d)\n"; +#endif /* !SFX && UNICODE_SUPPORT */ +static ZCONST char Far WrnStorUCSizCSizDiff[] = + "%s: ucsize %s <> csize %s for STORED entry\n\ + continuing with \"compressed\" size value\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: %s bytes required to uncompress to %s bytes;\n %s\ + supposed to require %s 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 /* messages of code for setting directory attributes */ + 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"; + static ZCONST char Far DirlistFailAttrSum[] = + " failed setting times/attribs for %lu dir entries"; +#endif + +#ifdef SYMLINKS /* messages of the deferred symlinks handler */ + static ZCONST char Far SymLnkWarnNoMem[] = + "warning: deferred symlink (%s) failed:\n\ + out of memory\n"; + static ZCONST char Far SymLnkWarnInvalid[] = + "warning: deferred symlink (%s) failed:\n\ + invalid placeholder file\n"; + static ZCONST char Far SymLnkDeferred[] = + "finishing deferred symbolic links:\n"; + static ZCONST char Far SymLnkFinish[] = + " %-22s -> %s\n"; +#endif + +#ifndef WINDLL + static ZCONST char Far ReplaceQuery[] = +# ifdef VMS + "new version of %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: "; +# else + "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: "; +# endif + static ZCONST char Far AssumeNone[] = + " NULL\n(EOF or read error, treating as \"[N]one\" ...)\n"; + static ZCONST char Far NewNameQuery[] = "new name: "; + static ZCONST char Far InvalidResponse[] = + "error: invalid response [%s]\n"; +#endif /* !WINDLL */ + +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"; +#ifdef USE_BZIP2 + static ZCONST char Far BUnzip[] = "bunzip"; +#endif + +#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"; + + /* TruncEAs[] also used in OS/2 mapname(), close_outfile() */ +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 TooSmallEBlength[] = "bad extra-field entry:\n \ + EF block length (%u bytes) invalid (< %d)\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 /* !SFX */ + +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"; + + + + + +/**************************************/ +/* Function extract_or_test_files() */ +/**************************************/ + +int extract_or_test_files(__G) /* return PK-type error code */ + __GDEF +{ + unsigned i, j; + zoff_t cd_bufstart; + uch *cd_inptr; + int cd_incnt; + ulg filnum=0L, blknum=0L; + int reached_end; +#ifndef SFX + int no_endsig_found; +#endif + int error, error_in_archive=PK_COOL; + int *fn_matched=NULL, *xn_matched=NULL; + zucn_t members_processed; + ulg num_skipped=0L, num_bad_pwd=0L; + zoff_t old_extra_bytes = 0L; +#ifdef SET_DIR_ATTRIB + unsigned num_dirs=0; + direntry *dirlist=(direntry *)NULL, **sorted_dirlist=(direntry **)NULL; +#endif + + /* + * First, two general initializations are applied. These have been moved + * here from process_zipfiles() because they are only needed for accessing + * and/or extracting the data content of the zip archive. + */ + + /* a) initialize the CRC table pointer (once) */ + if (CRC_32_TAB == NULL) { + if ((CRC_32_TAB = get_crc_table()) == NULL) { + return PK_MEM; + } + } + +#if (!defined(SFX) || defined(SFX_EXDIR)) + /* b) check out if specified extraction root directory exists */ + if (uO.exdir != (char *)NULL && G.extract_flag) { + G.create_dirs = !uO.fflag; + if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) { + /* out of memory, or file in way */ + return (error == MPN_NOMEM ? PK_MEM : PK_ERR); + } + } +#endif /* !SFX || SFX_EXDIR */ + +/*--------------------------------------------------------------------------- + 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 + + /* malloc space for check on unmatched filespecs (OK if one or both NULL) */ + 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; +#ifndef SFX + no_endsig_found = FALSE; +#endif + 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; /* ...so no more left to do */ + break; + } + if (memcmp(G.sig, central_hdr_sig, 4)) { /* is it a new entry? */ + /* no new central directory entry + * -> is the number of processed entries compatible with the + * number of entries as stored in the end_central record? + */ + if ((members_processed + & (G.ecrec.have_ecr64 ? MASK_ZUCN64 : MASK_ZUCN16)) + == G.ecrec.total_entries_central_dir) { +#ifndef SFX + /* yes, so look if we ARE back at the end_central record + */ + no_endsig_found = + ( (memcmp(G.sig, + (G.ecrec.have_ecr64 ? + end_central64_sig : end_central_sig), + 4) != 0) + && (!G.ecrec.is_zip64_archive) + && (memcmp(G.sig, end_central_sig, 4) != 0) + ); +#endif /* !SFX */ + } else { + /* no; we have found an error in the central directory + * -> 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,"%s", LoadFarString(ReportMsg))); + error_in_archive = PK_BADERR; + } + reached_end = TRUE; /* ...so no more left to do */ + break; + } + /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */ + if ((error = process_cdir_file_hdr(__G)) != PK_COOL) { + error_in_archive = error; /* only PK_EOF defined */ + reached_end = TRUE; /* ...so no more left to do */ + 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) { /* fatal: no more left to do */ + 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) { /* fatal */ + 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) { /* fatal */ + Info(slide, 0x421, ((char *)slide, + LoadFarString(BadFileCommLength), + FnFilter1(G.filename))); + reached_end = TRUE; + break; + } + } + if (G.process_all_files) { + if (store_info(__G)) + ++j; /* file is OK; info[] stored; continue with next */ + else + ++num_skipped; + } else { + int do_this_file; + + if (G.filespecs == 0) + do_this_file = TRUE; + else { /* check if this entry matches an `include' argument */ + do_this_file = FALSE; + for (i = 0; i < G.filespecs; i++) + if (match(G.filename, G.pfnames[i], uO.C_flag WISEP)) { + do_this_file = TRUE; /* ^-- ignore case or not? */ + if (fn_matched) + fn_matched[i] = TRUE; + break; /* found match, so stop looping */ + } + } + if (do_this_file) { /* check if this is an excluded file */ + for (i = 0; i < G.xfilespecs; i++) + if (match(G.filename, G.pxnames[i], uO.C_flag WISEP)) { + do_this_file = FALSE; /* ^-- ignore case or not? */ + if (xn_matched) + xn_matched[i] = TRUE; + break; + } + } + if (do_this_file) { + if (store_info(__G)) + ++j; /* file is OK */ + else + ++num_skipped; /* unsupp. compression or encryption */ + } + } /* end if (process_all_files) */ + + members_processed++; + + } /* end while-loop (adding files to current block) */ + + /* save position in central directory so can come back later */ + 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; + /* ...and keep going (unless disk full or user break) */ + if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) { + /* clear reached_end to signal premature stop ... */ + reached_end = FALSE; + /* ... and cancel scanning the central directory */ + break; + } + } + + + /* + * Jump back to where we were in the central directory, then go and do + * the next batch of files. + */ + +#ifdef USE_STRM_INPUT + zfseeko(G.zipfd, cd_bufstart, SEEK_SET); + G.cur_zipfile_bufstart = zftello(G.zipfd); +#else /* !USE_STRM_INPUT */ + G.cur_zipfile_bufstart = + zlseek(G.zipfd, cd_bufstart, SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + read(G.zipfd, (char *)G.inbuf, INBUFSIZ); /* been here before... */ + 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 + + } /* end while-loop (blocks of files in central directory) */ + +/*--------------------------------------------------------------------------- + Process the list of deferred symlink extractions and finish up + the symbolic links. + ---------------------------------------------------------------------------*/ + +#ifdef SYMLINKS + if (G.slink_last != NULL) { + if (QCOND2) + Info(slide, 0, ((char *)slide, LoadFarString(SymLnkDeferred))); + while (G.slink_head != NULL) { + set_deferred_symlink(__G__ G.slink_head); + /* remove the processed entry from the chain and free its memory */ + G.slink_last = G.slink_head; + G.slink_head = G.slink_last->next; + free(G.slink_last); + } + G.slink_last = NULL; + } +#endif /* SYMLINKS */ + +/*--------------------------------------------------------------------------- + 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 = (direntry **)malloc(num_dirs*sizeof(direntry *)); + if (sorted_dirlist == (direntry **)NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(DirlistSortNoMem))); + while (dirlist != (direntry *)NULL) { + direntry *d = dirlist; + + dirlist = dirlist->next; + free(d); + } + } else { + ulg ndirs_fail = 0; + + 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(direntry *), + dircomp); + } + + Trace((stderr, "setting directory times/perms/attributes\n")); + for (i = 0; i < num_dirs; ++i) { + direntry *d = sorted_dirlist[i]; + + Trace((stderr, "dir = %s\n", d->fn)); + if ((error = set_direc_attribs(__G__ d)) != PK_OK) { + ndirs_fail++; + Info(slide, 0x201, ((char *)slide, + LoadFarString(DirlistSetAttrFailed), d->fn)); + if (!error_in_archive) + error_in_archive = error; + } + free(d); + } + free(sorted_dirlist); + if (!uO.tflag && QCOND2) { + if (ndirs_fail > 0) + Info(slide, 0, ((char *)slide, + LoadFarString(DirlistFailAttrSum), ndirs_fail)); + } + } + } +#endif /* SET_DIR_ATTRIB */ + +/*--------------------------------------------------------------------------- + Check for unmatched filespecs on command line and print warning if any + found. Free allocated memory. (But suppress check when central dir + scan was interrupted prematurely.) + ---------------------------------------------------------------------------*/ + + if (fn_matched) { + if (reached_end) 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; /* some files not found */ + } + free((zvoid *)fn_matched); + } + if (xn_matched) { + if (reached_end) 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); + } + +/*--------------------------------------------------------------------------- + Now, all locally allocated memory has been released. When the central + directory processing has been interrupted prematurely, it is safe to + return immediately. All completeness checks and summary messages are + skipped in this case. + ---------------------------------------------------------------------------*/ + if (!reached_end) + return error_in_archive; + +/*--------------------------------------------------------------------------- + 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) { /* just to make sure */ + Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg))); + Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(ReportMsg))); + if (!error_in_archive) /* don't overwrite stronger error */ + error_in_archive = PK_WARN; + } +#endif /* !SFX */ + if (uO.tflag) { + ulg num = filnum - num_bad_pwd; + + if (uO.qflag < 2) { /* GRR 930710: was (uO.qflag == 1) */ + 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 /* CRYPT */ + } + } + + /* give warning if files not tested or extracted (first condition can still + * 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; /* unsupport. compression/encryption */ + else + error_in_archive = PK_FIND; /* no files found at all */ + } +#if CRYPT + else if ((filnum == num_bad_pwd) && error_in_archive <= PK_WARN) + error_in_archive = IZ_BADPWD; /* bad passwd => all files skipped */ +#endif + else if ((num_skipped > 0L) && error_in_archive <= PK_WARN) + error_in_archive = IZ_UNSUP; /* was PK_WARN; Jean-loup complained */ +#if CRYPT + else if ((num_bad_pwd > 0L) && !error_in_archive) + error_in_archive = PK_WARN; +#endif + + return error_in_archive; + +} /* end function extract_or_test_files() */ + + + + + +/***************************/ +/* Function store_info() */ +/***************************/ + +static int store_info(__G) /* return 0 if skipping, 1 if OK */ + __GDEF +{ +#ifdef USE_BZIP2 +# define UNKN_BZ2 (G.crec.compression_method!=BZIPPED) +#else +# define UNKN_BZ2 TRUE /* bzip2 unknown */ +#endif + +#ifdef USE_LZMA +# define UNKN_LZMA (G.crec.compression_method!=LZMAED) +#else +# define UNKN_LZMA TRUE /* LZMA unknown */ +#endif + +#ifdef USE_WAVP +# define UNKN_WAVP (G.crec.compression_method!=WAVPACKED) +#else +# define UNKN_WAVP TRUE /* WavPack unknown */ +#endif + +#ifdef USE_PPMD +# define UNKN_PPMD (G.crec.compression_method!=PPMDED) +#else +# define UNKN_PPMD TRUE /* PPMd unknown */ +#endif + +#ifdef SFX +# ifdef USE_DEFLATE64 +# define UNKN_COMPR \ + (G.crec.compression_method!=STORED && G.crec.compression_methodENHDEFLATED \ + && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD) +# else +# define UNKN_COMPR \ + (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED\ + && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD) +# endif +#else +# ifdef COPYRIGHT_CLEAN /* no reduced files */ +# 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 /* no shrunk files */ +# 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 && UNKN_BZ2 && UNKN_LZMA \ + && UNKN_WAVP && UNKN_PPMD)) +# else +# define UNKN_COMPR (UNKN_RED || UNKN_SHR || \ + G.crec.compression_method==TOKENIZED || \ + (G.crec.compression_method>DEFLATED && UNKN_BZ2 && UNKN_LZMA \ + && UNKN_WAVP && UNKN_PPMD)) +# endif +#endif + +#if (defined(USE_BZIP2) && (UNZIP_VERSION < UNZIP_BZ2VERS)) + int unzvers_support = (UNKN_BZ2 ? UNZIP_VERSION : UNZIP_BZ2VERS); +# define UNZVERS_SUPPORT unzvers_support +#else +# define UNZVERS_SUPPORT UNZIP_VERSION +#endif + +/*--------------------------------------------------------------------------- + Check central directory info for version/compatibility requirements. + ---------------------------------------------------------------------------*/ + + G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1; /* bit field */ + G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8; /* bit */ + G.pInfo->textfile = G.crec.internal_file_attributes & 1; /* bit field */ + 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; /* bit field */ + break; + case 1: + G.pInfo->textmode = G.pInfo->textfile; /* auto-convert mode */ + break; + default: /* case 2: */ + 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 /* won't be able to use extra field, but still have data */ + else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */ + Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery), + FnFilter1(G.filename))); + fgets(G.answerbuf, sizeof(G.answerbuf), stdin); + if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y')) + return 0; + } +#endif /* !VMS */ + /* usual file type: don't need VMS to extract */ + } else if (G.crec.version_needed_to_extract[0] > UNZVERS_SUPPORT) { + 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, + UNZVERS_SUPPORT / 10, UNZVERS_SUPPORT % 10)); + return 0; + } + + if (UNKN_COMPR) { + if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) { +#ifndef SFX + unsigned cmpridx; + + if ((cmpridx = find_compr_idx(G.crec.compression_method)) + < NUM_METHODS) + Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName), + FnFilter1(G.filename), + LoadFarStringSmall(ComprNames[cmpridx]))); + 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 /* !CRYPT */ + +#ifndef SFX + /* store a copy of the central header filename for later comparison */ + if ((G.pInfo->cfilname = zfmalloc(strlen(G.filename) + 1)) == NULL) { + Info(slide, 0x401, ((char *)slide, LoadFarString(WarnNoMemCFName), + FnFilter1(G.filename))); + } else + zfstrcpy(G.pInfo->cfilname, G.filename); +#endif /* !SFX */ + + /* map whatever file attributes we have into the local format */ + mapattr(__G); /* GRR: worry about return value later */ + + G.pInfo->diskstart = G.crec.disk_number_start; + G.pInfo->offset = (zoff_t)G.crec.relative_offset_local_header; + return 1; + +} /* end function store_info() */ + + + + + +#ifndef SFX +/*******************************/ +/* Function find_compr_idx() */ +/*******************************/ + +unsigned find_compr_idx(compr_methodnum) + unsigned compr_methodnum; +{ + unsigned i; + + for (i = 0; i < NUM_METHODS; i++) { + if (ComprIDs[i] == compr_methodnum) break; + } + return i; +} +#endif /* !SFX */ + + + + + +/******************************************/ +/* Function extract_or_test_entrylist() */ +/******************************************/ + +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) /* return PK-type error code */ + __GDEF + unsigned numchunk; + ulg *pfilnum; + ulg *pnum_bad_pwd; + zoff_t *pold_extra_bytes; +#ifdef SET_DIR_ATTRIB + unsigned *pnum_dirs; + direntry **pdirlist; +#endif + int error_in_archive; +{ + unsigned i; + int renamed, query; + int skip_entry; + zoff_t bufstart, inbuf_offset, request; + int error, errcode; + +/* possible values for local skip_entry flag: */ +#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)++; /* *pfilnum = i + blknum*DIR_BLKSIZ + 1; */ + G.pInfo = &G.info[i]; +#ifdef NOVELL_BUG_FAILSAFE + G.dne = FALSE; /* assume file exists until stat() says otherwise */ +#endif + + /* if the target position is not within the current input buffer + * (either haven't yet read far enough, or (maybe) skipping back- + * ward), skip to the target position and reset readbuf(). */ + + /* seek_zipf(__G__ pInfo->offset); */ + request = G.pInfo->offset + G.extra_bytes; + inbuf_offset = request % INBUFSIZ; + bufstart = request - inbuf_offset; + + Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n", + (long)request, (long)inbuf_offset)); + Trace((stderr, + "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n", + (long)bufstart, (long)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; /* could also check if != 0 */ + inbuf_offset = request % INBUFSIZ; + bufstart = request - inbuf_offset; + Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n", + (long)request, (long)inbuf_offset)); + Trace((stderr, + "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n", + (long)bufstart, (long)G.cur_zipfile_bufstart)); + /* try again */ + 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; /* this one hosed; try next */ + } + } + + if (bufstart != G.cur_zipfile_bufstart) { + Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n")); +#ifdef USE_STRM_INPUT + zfseeko(G.zipfd, bufstart, SEEK_SET); + G.cur_zipfile_bufstart = zftello(G.zipfd); +#else /* !USE_STRM_INPUT */ + G.cur_zipfile_bufstart = + zlseek(G.zipfd, bufstart, SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0) + { + Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), + *pfilnum, "lseek", (long)bufstart)); + error_in_archive = PK_BADERR; + continue; /* can still do next file */ + } + 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; + } + + /* should be in proper position now, so check for sig */ + if (readbuf(__G__ G.sig, 4) == 0) { /* bad offset */ + Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), + *pfilnum, "EOF", (long)request)); + error_in_archive = PK_BADERR; + continue; /* but can still try next one */ + } + if (memcmp(G.sig, local_hdr_sig, 4)) { + Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg), + *pfilnum, LoadFarStringSmall(LocalHdrSig), (long)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; /* third attempt */ + if (((error = seek_zipf(__G__ G.pInfo->offset)) != PK_OK) || + (readbuf(__G__ G.sig, 4) == 0)) { /* bad offset */ + if (error != PK_BADERR) + Info(slide, 0x401, ((char *)slide, + LoadFarString(OffsetMsg), *pfilnum, "EOF", + (long)request)); + error_in_archive = PK_BADERR; + continue; /* but can still try next one */ + } + if (memcmp(G.sig, local_hdr_sig, 4)) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(OffsetMsg), *pfilnum, + LoadFarStringSmall(LocalHdrSig), (long)request)); + error_in_archive = PK_BADERR; + continue; + } + } else + continue; /* this one hosed; try next */ + } + if ((error = process_local_file_hdr(__G)) != PK_COOL) { + Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr), + *pfilnum)); + error_in_archive = error; /* only PK_EOF defined */ + continue; /* can still try next one */ + } +#if (!defined(SFX) && defined(UNICODE_SUPPORT)) + if (((G.lrec.general_purpose_bit_flag & (1 << 11)) == (1 << 11)) + != (G.pInfo->GPFIsUTF8 != 0)) { + if (QCOND2) { +# ifdef SMALL_MEM + char *temp_cfilnam = slide + (7 * (WSIZE>>3)); + + zfstrcpy((char Far *)temp_cfilnam, G.pInfo->cfilname); +# define cFile_PrintBuf temp_cfilnam +# else +# define cFile_PrintBuf G.pInfo->cfilname +# endif + Info(slide, 0x421, ((char *)slide, + LoadFarStringSmall2(GP11FlagsDiffer), + *pfilnum, FnFilter1(cFile_PrintBuf), G.pInfo->GPFIsUTF8)); +# undef cFile_PrintBuf + } + if (error_in_archive < PK_WARN) + error_in_archive = PK_WARN; + } +#endif /* !SFX && UNICODE_SUPPORT */ + 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; /* go on to next one */ + } + } + 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; /* go on */ + } + } +#ifndef SFX + /* Filename consistency checks must come after reading in the local + * extra field, so that a UTF-8 entry name e.f. block has already + * been processed. + */ + if (G.pInfo->cfilname != (char Far *)NULL) { + if (zfstrcmp(G.pInfo->cfilname, G.filename) != 0) { +# ifdef SMALL_MEM + char *temp_cfilnam = slide + (7 * (WSIZE>>3)); + + zfstrcpy((char Far *)temp_cfilnam, G.pInfo->cfilname); +# define cFile_PrintBuf temp_cfilnam +# else +# define cFile_PrintBuf G.pInfo->cfilname +# endif + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall2(LvsCFNamMsg), + FnFilter2(cFile_PrintBuf), FnFilter1(G.filename))); +# undef cFile_PrintBuf + zfstrcpy(G.filename, G.pInfo->cfilname); + if (error_in_archive < PK_WARN) + error_in_archive = PK_WARN; + } + zffree(G.pInfo->cfilname); + G.pInfo->cfilname = (char Far *)NULL; + } +#endif /* !SFX */ + /* Size consistency checks must come after reading in the local extra + * field, so that any Zip64 extension local e.f. block has already + * been processed. + */ + if (G.lrec.compression_method == STORED) { + zusz_t csiz_decrypted = G.lrec.csize; + + if (G.pInfo->encrypted) { + if (csiz_decrypted < 12) { + /* handle the error now to prevent unsigned overflow */ + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipNoFile), + LoadFarString(InvalidComprData), + LoadFarStringSmall2(Inflate))); + return PK_ERR; + } + csiz_decrypted -= 12; + } + if (G.lrec.ucsize != csiz_decrypted) { + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall2(WrnStorUCSizCSizDiff), + FnFilter1(G.filename), + FmZofft(G.lrec.ucsize, NULL, "u"), + FmZofft(csiz_decrypted, NULL, "u"))); + G.lrec.ucsize = csiz_decrypted; + if (error_in_archive < PK_WARN) + error_in_archive = PK_WARN; + } + } + +#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 { /* (error > PK_WARN) */ + if (error > error_in_archive) + error_in_archive = error; + Info(slide, 0x401, ((char *)slide, + LoadFarString(SkipCannotGetPasswd), + FnFilter1(G.filename))); + } + continue; /* go on to next file */ + } +#endif /* CRYPT */ + + /* + * 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; /* user hasn't renamed output file yet */ + +startover: + query = FALSE; + skip_entry = SKIP_NO; + /* for files from DOS FAT, check for use of backslash instead + * 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 /* !SFX */ + + if (!renamed) { + /* remove absolute path specs */ + 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] == '/'); + } + } + + /* mapname can create dirs if not freshening or if renamed */ + 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 + direntry *d_entry; + + error = defer_dir_attribs(__G__ &d_entry); + if (d_entry == (direntry *)NULL) { + /* There may be no dir_attribs info available, or + * we have encountered a mem allocation error. + * In case of an error, report it and set program + * error state to warning level. + */ + if (error) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(DirlistEntryNoMem))); + if (!error_in_archive) + error_in_archive = PK_WARN; + } + } else { + d_entry->next = (*pdirlist); + (*pdirlist) = d_entry; + ++(*pnum_dirs); + } +#endif /* SET_DIR_ATTRIB */ + } 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; /* go on to next file */ + } + +#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; /* stat() says file DOES NOT EXIST */ +#endif + /* freshen (no new files): skip unless just renamed */ + 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) + /* never overwrite: skip file */ + skip_entry = SKIP_Y_EXISTING; + else if (!IS_OVERWRT_ALL) + query = TRUE; + } + break; + case EXISTS_AND_NEWER: /* (or equal) */ +#ifdef UNIXBACKUP + if ((!uO.B_flag && IS_OVERWRT_NONE) || +#else + if (IS_OVERWRT_NONE || +#endif + (uO.uflag && !renamed)) { + /* skip if update/freshen & orig name */ + skip_entry = SKIP_Y_EXISTING; + } else { +#ifdef UNIXBACKUP + if (!IS_OVERWRT_ALL && !uO.B_flag) +#else + if (!IS_OVERWRT_ALL) +#endif + query = TRUE; + } + break; + } +#ifdef VMS + /* 2008-07-24 SMS. + * On VMS, if the file name includes a version number, + * and "-V" ("retain VMS version numbers", V_flag) is in + * effect, then the VMS-specific code will handle any + * conflicts with an existing file, making this query + * redundant. (Implicit "y" response here.) + */ + if (query && uO.V_flag) { + /* Not discarding file versions. Look for one. */ + int cndx = strlen(G.filename) - 1; + + while ((cndx > 0) && (isdigit(G.filename[cndx]))) + cndx--; + if (G.filename[cndx] == ';') + /* File version found; skip the generic query, + * proceeding with its default response "y". + */ + query = FALSE; + } +#endif /* VMS */ + if (query) { +#ifdef WINDLL + switch (G.lpUserFunctions->replace != NULL ? + (*G.lpUserFunctions->replace)(G.filename, FILNAMSIZ) : + IDM_REPLACE_NONE) { + case IDM_REPLACE_RENAME: + _ISO_INTERN(G.filename); + renamed = TRUE; + goto startover; + case IDM_REPLACE_ALL: + G.overwrite_mode = OVERWRT_ALWAYS; + /* FALL THROUGH, extract */ + case IDM_REPLACE_YES: + break; + case IDM_REPLACE_NONE: + G.overwrite_mode = OVERWRT_NEVER; + /* FALL THROUGH, skip */ + case IDM_REPLACE_NO: + skip_entry = SKIP_Y_EXISTING; + break; + } +#else /* !WINDLL */ + extent fnlen; +reprompt: + Info(slide, 0x81, ((char *)slide, + LoadFarString(ReplaceQuery), + FnFilter1(G.filename))); + if (fgets(G.answerbuf, sizeof(G.answerbuf), stdin) + == (char *)NULL) { + Info(slide, 1, ((char *)slide, + LoadFarString(AssumeNone))); + *G.answerbuf = 'N'; + if (!error_in_archive) + error_in_archive = 1; /* not extracted: warning */ + } + switch (*G.answerbuf) { + case 'r': + case 'R': + do { + Info(slide, 0x81, ((char *)slide, + LoadFarString(NewNameQuery))); + fgets(G.filename, FILNAMSIZ, stdin); + /* usually get \n here: better check for it */ + fnlen = strlen(G.filename); + if (lastchar(G.filename, fnlen) == '\n') + G.filename[--fnlen] = '\0'; + } while (fnlen == 0); +#ifdef WIN32 /* WIN32 fgets( ... , stdin) returns OEM coded strings */ + _OEM_INTERN(G.filename); +#endif + renamed = TRUE; + goto startover; /* sorry for a goto */ + case 'A': /* dangerous option: force caps */ + G.overwrite_mode = OVERWRT_ALWAYS; + /* FALL THROUGH, extract */ + case 'y': + case 'Y': + break; + case 'N': + G.overwrite_mode = OVERWRT_NEVER; + /* FALL THROUGH, skip */ + case 'n': + /* skip file */ + skip_entry = SKIP_Y_EXISTING; + break; + case '\n': + case '\r': + /* Improve echo of '\n' and/or '\r' + (sizeof(G.answerbuf) == 10 (see globals.h), so + there is enough space for the provided text...) */ + strcpy(G.answerbuf, "{ENTER}"); + /* fall through ... */ + default: + /* usually get \n here: remove it for nice display + (fnlen can be re-used here, we are outside the + "enter new filename" loop) */ + fnlen = strlen(G.answerbuf); + if (lastchar(G.answerbuf, fnlen) == '\n') + G.answerbuf[--fnlen] = '\0'; + Info(slide, 1, ((char *)slide, + LoadFarString(InvalidResponse), G.answerbuf)); + goto reprompt; /* yet another goto? */ + } /* end switch (*answerbuf) */ +#endif /* ?WINDLL */ + } /* end if (query) */ + if (skip_entry != SKIP_NO) { +#ifdef WINDLL + if (skip_entry == SKIP_Y_EXISTING) { + /* report skipping of an existing entry */ + Info(slide, 0, ((char *)slide, + ((IS_OVERWRT_NONE || !uO.uflag || renamed) ? + "Target file exists. Skipping %s\n" : + "Target file newer. Skipping %s\n"), + FnFilter1(G.filename))); + } +#endif /* WINDLL */ + continue; + } + } /* end if (extracting to disk) */ + +#ifdef DLL + if ((G.statreportcb != NULL) && + (*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn, + G.filename, NULL)) { + return IZ_CTRLC; /* cancel operation by user request */ + } +#endif +#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */ + 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; /* ...and keep going */ +#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; /* cancel operation by user request */ + } +#endif +#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */ + UserStop(); +#endif + } /* end for-loop (i: files in current block) */ + + return error_in_archive; + +} /* end function extract_or_test_entrylist() */ + + + + + +/* wsize is used in extract_or_test_member() and UZbunzip2() */ +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) +# define wsize G._wsize /* wsize is a variable */ +#else +# define wsize WSIZE /* wsize is a constant */ +#endif + +/***************************************/ +/* Function extract_or_test_member() */ +/***************************************/ + +static int extract_or_test_member(__G) /* return PK-type error code */ + __GDEF +{ + char *nul="[empty] ", *txt="[text] ", *bin="[binary]"; +#ifdef CMS_MVS + char *ebc="[ebcdic]"; +#endif + register int b; + int r, error=PK_COOL; + + +/*--------------------------------------------------------------------------- + Initialize variables, buffers, etc. + ---------------------------------------------------------------------------*/ + + G.bits_left = 0; + G.bitbuf = 0L; /* unreduce and unshrink only */ + G.zipeof = 0; + G.newfile = TRUE; + G.crc32val = CRCVAL_INITIAL; + +#ifdef SYMLINKS + /* If file is a (POSIX-compatible) symbolic link and we are extracting + * to disk, prepare to restore the link. */ + G.symlnk = (G.pInfo->symlink && + !uO.tflag && !uO.cflag && (G.lrec.ucsize > 0)); +#endif /* SYMLINKS */ + + 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); /* VAC++ ignores setmode */ +#else + G.outfile = stdout; +#endif +#ifdef DOS_FLX_NLM_OS2_W32 +#if (defined(__HIGHC__) && !defined(FLEXOS)) + setmode(G.outfile, _BINARY); +#else /* !(defined(__HIGHC__) && !defined(FLEXOS)) */ + setmode(fileno(G.outfile), O_BINARY); +#endif /* ?(defined(__HIGHC__) && !defined(FLEXOS)) */ +# define NEWLINE "\r\n" +#else /* !DOS_FLX_NLM_OS2_W32 */ +# define NEWLINE "\n" +#endif /* ?DOS_FLX_NLM_OS2_W32 */ +#ifdef VMS + /* VMS: required even for stdout! */ + if ((r = open_outfile(__G)) != 0) + switch (r) { + case OPENOUT_SKIPOK: + return PK_OK; + case OPENOUT_SKIPWARN: + return PK_WARN; + default: + return PK_DISK; + } + } else if ((r = open_outfile(__G)) != 0) + switch (r) { + case OPENOUT_SKIPOK: + return PK_OK; + case OPENOUT_SKIPWARN: + return PK_WARN; + default: + return PK_DISK; + } +#else /* !VMS */ + } else if (open_outfile(__G)) + return PK_DISK; +#endif /* ?VMS */ + } + +/*--------------------------------------------------------------------------- + Unpack the file. + ---------------------------------------------------------------------------*/ + + defer_leftover_input(__G); /* so NEXTBYTE bounds check will work */ + switch (G.lrec.compression_method) { + case STORED: + if (!uO.tflag && QCOND2) { +#ifdef SYMLINKS + if (G.symlnk) /* can also be deflated, but rarer... */ + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + "link", FnFilter1(G.filename), "", "")); + else +#endif /* SYMLINKS */ + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + "extract", FnFilter1(G.filename), + (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? + "" : (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 final (partial) buffer */ + r = flush(__G__ redirSlide, G.outcnt, 0); + if (error < r) error = r; + } + 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==G.pInfo->textmode */)? + "" : (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), r == PK_MEM3 ? + LoadFarString(NotEnoughMem) : + LoadFarString(InvalidComprData), + LoadFarStringSmall2(Unshrink), + FnFilter1(G.filename))); + else + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipNoFile), r == PK_MEM3 ? + LoadFarString(NotEnoughMem) : + LoadFarString(InvalidComprData), + LoadFarStringSmall2(Unshrink))); + } + error = r; + } + break; +#endif /* !LZW_CLEAN */ + +#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==G.pInfo->textmode */)? + "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); + } + if ((r = unreduce(__G)) != PK_COOL) { + /* unreduce() returns only PK_COOL, PK_DISK, or IZ_CTRLC */ + error = r; + } + break; +#endif /* !COPYRIGHT_CLEAN */ + + case IMPLODED: + if (!uO.tflag && QCOND2) { + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + "explod", FnFilter1(G.filename), + (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? + "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); + } + if ((r = explode(__G)) != 0) { + if (r == 5) { /* treat 5 specially */ + int warning = ((zusz_t)G.used_csize <= G.lrec.csize); + + if ((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)) + Info(slide, 0x401, ((char *)slide, + LoadFarString(LengthMsg), + "", warning ? "warning" : "error", + FmZofft(G.used_csize, NULL, NULL), + FmZofft(G.lrec.ucsize, NULL, "u"), + warning ? " " : "", + FmZofft(G.lrec.csize, NULL, "u"), + " [", FnFilter1(G.filename), "]")); + else + Info(slide, 0x401, ((char *)slide, + LoadFarString(LengthMsg), + "\n", warning ? "warning" : "error", + FmZofft(G.used_csize, NULL, NULL), + FmZofft(G.lrec.ucsize, NULL, "u"), + warning ? " " : "", + FmZofft(G.lrec.csize, NULL, "u"), + "", "", ".")); + error = warning ? PK_WARN : PK_ERR; + } else 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; + } + } + break; +#endif /* !SFX */ + + 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==G.pInfo->textmode */)? + "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); + } +#ifndef USE_ZLIB /* zlib's function is called inflate(), too */ +# 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; + +#ifdef USE_BZIP2 + case BZIPPED: + if (!uO.tflag && QCOND2) { + Info(slide, 0, ((char *)slide, LoadFarString(ExtractMsg), + "bunzipp", FnFilter1(G.filename), + (uO.aflag != 1 /* && G.pInfo->textfile==G.pInfo->textmode */)? + "" : (G.pInfo->textfile? txt : bin), uO.cflag? NEWLINE : "")); + } + if ((r = UZbunzip2(__G)) != 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(BUnzip), + FnFilter1(G.filename))); + else + Info(slide, 0x401, ((char *)slide, + LoadFarStringSmall(ErrUnzipNoFile), r == 3? + LoadFarString(NotEnoughMem) : + LoadFarString(InvalidComprData), + LoadFarStringSmall2(BUnzip))); + error = ((r == 3) ? PK_MEM3 : PK_ERR); + } else { + error = r; + } + } + break; +#endif /* USE_BZIP2 */ + + default: /* should never get to this point */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(FileUnknownCompMethod), FnFilter1(G.filename))); + /* close and delete file before return? */ + undefer_input(__G); + return PK_WARN; + + } /* end switch (compression method) */ + +/*--------------------------------------------------------------------------- + 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 /* VMS: required even for stdout! (final flush) */ + if (!uO.tflag) /* don't close NULL file */ + error = close_outfile(__G); +#else +#ifdef DLL + if (!uO.tflag && (!uO.cflag || G.redirect_data)) { + if (G.redirect_data) + FINISH_REDIRECT(); + else + error = close_outfile(__G); + } +#else + if (!uO.tflag && !uO.cflag) /* don't close NULL file or stdout */ + error = close_outfile(__G); +#endif +#endif /* VMS */ + + if (G.disk_full) { /* set by flush() */ + if (G.disk_full > 1) { +#if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK)) + /* delete the incomplete file if we can */ + if (unlink(G.filename) != 0) + Trace((stderr, "extract.c: could not delete %s\n", + FnFilter1(G.filename))); +#else + /* warn user about the incomplete file */ + Info(slide, 0x421, ((char *)slide, LoadFarString(FileTruncated), + FnFilter1(G.filename))); +#endif + error = PK_DISK; + } else { + error = PK_WARN; + } + } + + if (error > PK_WARN) {/* don't print redundant CRC error if error already */ + undefer_input(__G); + return error; + } + if (G.crc32val != G.lrec.crc32) { + /* if quiet enough, we haven't output the filename yet: do it */ + 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 /* !SFX */ + if (!uO.qflag) + Info(slide, 0, ((char *)slide, " OK\n")); + } else { + if (QCOND2 && !error) /* GRR: is stdout reset to text mode yet? */ + Info(slide, 0, ((char *)slide, "\n")); + } + + undefer_input(__G); + return error; + +} /* end function extract_or_test_member() */ + + + + + +#ifndef SFX + +/*******************************/ +/* Function TestExtraField() */ +/*******************************/ + +static int TestExtraField(__G__ ef, ef_len) + __GDEF + uch *ef; + unsigned ef_len; +{ + ush ebID; + unsigned ebLen; + unsigned eb_cmpr_offs = 0; + int r; + + /* we know the regular compressed file data tested out OK, or else we + * 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)) + { + /* Discovered some extra field inconsistency! */ + 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: + case EF_ATHEOS: + 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: + case EF_ATHEOS: + 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) /* GRR KLUDGE! */ + 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) /* GRR KLUDGE! */ + Info(slide, 1, ((char *)slide, + LoadFarString(BadCRC_EAs))); + else + Info(slide, 1, ((char *)slide, + LoadFarString(UnknComprMethodEAs), m)); + } + break; + } + return r; + } + break; + case EF_PKVMS: + /* 2015-01-30 SMS. Added sufficient-bytes test/message + * here. (Removed defective ebLen test above.) + * + * If sufficient bytes (EB_PKVMS_MINLEN) are available, + * then compare the stored CRC value with the calculated + * CRC for the remainder of the data (and complain about + * a mismatch). + */ + if (ebLen < EB_PKVMS_MINLEN) + { + /* Insufficient bytes available. */ + Info( slide, 1, + ((char *)slide, LoadFarString( TooSmallEBlength), + ebLen, EB_PKVMS_MINLEN)); + } + else if (makelong(ef+ EB_HEADSIZE) != + crc32(CRCVAL_INITIAL, + (ef+ EB_HEADSIZE+ EB_PKVMS_MINLEN), + (extent)(ebLen- EB_PKVMS_MINLEN))) + { + 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; + +} /* end function TestExtraField() */ + + + + + +/******************************/ +/* Function test_compr_eb() */ +/******************************/ + +#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 /* !PROTO */ +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 /* ?PROTO */ +{ + ulg eb_ucsize; + uch *eb_ucptr; + int r; + ush method; + + if (compr_offset < 4) /* field is not compressed: */ + return PK_OK; /* do nothing and signal OK */ + + /* Return no/bad-data error status if any problem is found: + * 1. eb_size is too small to hold the uncompressed size + * (eb_ucsize). (Else extract eb_ucsize.) + * 2. eb_ucsize is zero (invalid). 2014-12-04 SMS. + * 3. eb_ucsize is positive, but eb_size is too small to hold + * the compressed data header. + */ + if ((eb_size < (EB_UCSIZE_P + 4)) || + ((eb_ucsize = makelong( eb+ (EB_HEADSIZE+ EB_UCSIZE_P))) == 0L) || + ((eb_ucsize > 0L) && (eb_size <= (compr_offset + EB_CMPRHEADLEN)))) + return IZ_EF_TRUNC; /* no/bad compressed data! */ + + method = makeword(eb + (EB_HEADSIZE + compr_offset)); + if ((method == STORED) && (eb_size != compr_offset + EB_CMPRHEADLEN + eb_ucsize)) + return PK_ERR; /* compressed & uncompressed + * should match in STORED + * method */ + + if ( +#ifdef INT_16BIT + (((ulg)(extent)eb_ucsize) != eb_ucsize) || +#endif + (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; + +} /* end function test_compr_eb() */ + +#endif /* !SFX */ + + + + + +/***************************/ +/* Function memextract() */ +/***************************/ + +int memextract(__G__ tgt, tgtsize, src, srcsize) /* extract compressed */ + __GDEF /* extra field block; */ + uch *tgt; /* return PK-type error */ + ulg tgtsize; /* level */ + ZCONST uch *src; + ulg srcsize; +{ + zoff_t 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); + + /* compressed extra field exists completely in memory at this location: */ + G.inptr = (uch *)src + (2 + 4); /* method and extra_field_crc */ + 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 = (ulg)G.csize; /* for CRC calculation */ + 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) /* inflate's final FLUSH sets outcnt */ + break; + break; + default: + if (uO.tflag) + error = PK_ERR | ((int)method << 8); + else { + Info(slide, 0x401, ((char *)slide, + LoadFarString(UnsupportedExtraField), method)); + error = PK_ERR; /* GRR: should be passed on up via SetEAs() */ + } + 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); /* kludge for now */ + else { + Info(slide, 0x401, ((char *)slide, + LoadFarString(BadExtraFieldCRC), G.zipfn, crcval, + extra_field_crc)); + error = PK_ERR; + } + } + } + return error; + +} /* end function memextract() */ + + + + + +/*************************/ +/* Function memflush() */ +/*************************/ + +int memflush(__G__ rawbuf, size) + __GDEF + ZCONST uch *rawbuf; + ulg size; +{ + if (size > G.outsize) + /* Here, PK_DISK is a bit off-topic, but in the sense of marking + "overflow of output space", its use may be tolerated. */ + return PK_DISK; /* more data than output buffer can hold */ + + + + memcpy((char *)G.outbufptr, (char *)rawbuf, (extent)size); + G.outbufptr += (unsigned int)size; + G.outsize -= size; + G.outcnt += size; + + return 0; + +} /* end function memflush() */ + + + + + +#if (defined(VMS) || defined(VMS_TEXT_CONV)) + +/************************************/ +/* Function extract_izvms_block() */ +/************************************/ + +/* + * Extracts block from p. If resulting length is less than 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; /* Pointer to block allocated */ + 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: /* The simplest case */ + 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; + +} /* end of extract_izvms_block */ + + + + + +/********************************/ +/* Function decompress_bits() */ +/********************************/ +/* + * 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; /* Pointer into output block */ + unsigned needlen; /* Size of uncompressed block */ + ZCONST uch *bitptr; /* Pointer into compressed data */ +{ + 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; + } + } +} /* end function decompress_bits() */ + +#endif /* VMS || VMS_TEXT_CONV */ + + + + + +#ifdef SYMLINKS +/***********************************/ +/* Function set_deferred_symlink() */ +/***********************************/ + +static void set_deferred_symlink(__G__ slnk_entry) + __GDEF + slinkentry *slnk_entry; +{ + extent ucsize = slnk_entry->targetlen; + char *linkfname = slnk_entry->fname; + char *linktarget = (char *)malloc(ucsize+1); + + if (!linktarget) { + Info(slide, 0x201, ((char *)slide, + LoadFarString(SymLnkWarnNoMem), FnFilter1(linkfname))); + return; + } + linktarget[ucsize] = '\0'; + G.outfile = zfopen(linkfname, FOPR); /* open link placeholder for reading */ + /* Check that the following conditions are all fulfilled: + * a) the placeholder file exists, + * b) the placeholder file contains exactly "ucsize" bytes + * (read the expected placeholder content length + 1 extra byte, this + * should return the expected content length), + * c) the placeholder content matches the link target specification as + * stored in the symlink control structure. + */ + if (!G.outfile || + fread(linktarget, 1, ucsize+1, G.outfile) != ucsize || + strcmp(slnk_entry->target, linktarget)) + { + Info(slide, 0x201, ((char *)slide, + LoadFarString(SymLnkWarnInvalid), FnFilter1(linkfname))); + free(linktarget); + if (G.outfile) + fclose(G.outfile); + return; + } + fclose(G.outfile); /* close "data" file for good... */ + unlink(linkfname); /* ...and delete it */ + if (QCOND2) + Info(slide, 0, ((char *)slide, LoadFarString(SymLnkFinish), + FnFilter1(linkfname), FnFilter2(linktarget))); + if (symlink(linktarget, linkfname)) /* create the real link */ + perror("symlink error"); + free(linktarget); +#ifdef SET_SYMLINK_ATTRIBS + set_symlnk_attribs(__G__ slnk_entry); +#endif + return; /* can't set time on symlinks */ + +} /* end function set_deferred_symlink() */ +#endif /* SYMLINKS */ + + + + +/*************************/ +/* Function fnfilter() */ /* here instead of in list.c for SFX */ +/*************************/ + +char *fnfilter(raw, space, size) /* convert name to safely printable form */ + ZCONST char *raw; + uch *space; + extent size; +{ +#ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */ + ZCONST uch *r=(ZCONST uch *)raw; + uch *s=space; + uch *slim=NULL; + uch *se=NULL; + int have_overflow = FALSE; + + if (size > 0) { + slim = space + size +#ifdef _MBCS + - (MB_CUR_MAX - 1) +#endif + - 4; + } + while (*r) { + if (size > 0 && s >= slim && se == NULL) { + se = s; + } +#ifdef QDOS + if (qlflag & 2) { + if (*r == '/' || *r == '.') { + if (se != NULL && (s > (space + (size-3)))) { + have_overflow = TRUE; + break; + } + ++r; + *s++ = '_'; + continue; + } + } else +#endif +#ifdef HAVE_WORKING_ISPRINT +# ifndef UZ_FNFILTER_REPLACECHAR + /* A convenient choice for the replacement of unprintable char codes is + * the "single char wildcard", as this character is quite unlikely to + * appear in filenames by itself. The following default definition + * sets the replacement char to a question mark as the most common + * "single char wildcard"; this setting should be overridden in the + * appropiate system-specific configuration header when needed. + */ +# define UZ_FNFILTER_REPLACECHAR '?' +# endif + if (!isprint(*r)) { + if (*r < 32) { + /* ASCII control codes are escaped as "^{letter}". */ + if (se != NULL && (s > (space + (size-4)))) { + have_overflow = TRUE; + break; + } + *s++ = '^', *s++ = (uch)(64 + *r++); + } else { + /* Other unprintable codes are replaced by the + * placeholder character. */ + if (se != NULL && (s > (space + (size-3)))) { + have_overflow = TRUE; + break; + } + *s++ = UZ_FNFILTER_REPLACECHAR; + INCSTR(r); + } +#else /* !HAVE_WORKING_ISPRINT */ + if (*r < 32) { + /* ASCII control codes are escaped as "^{letter}". */ + if (se != NULL && (s > (space + (size-4)))) { + have_overflow = TRUE; + break; + } + *s++ = '^', *s++ = (uch)(64 + *r++); +#endif /* ?HAVE_WORKING_ISPRINT */ + } else { +#ifdef _MBCS + unsigned i = CLEN(r); + if (se != NULL && (s > (space + (size-i-2)))) { + have_overflow = TRUE; + break; + } + for (; i > 0; i--) + *s++ = *r++; +#else + if (se != NULL && (s > (space + (size-3)))) { + have_overflow = TRUE; + break; + } + *s++ = *r++; +#endif + } + } + if (have_overflow) { + strcpy((char *)se, "..."); + } else { + *s = '\0'; + } + +#ifdef WINDLL + INTERN_TO_ISO((char *)space, (char *)space); /* translate to ANSI */ +#else +#if (defined(WIN32) && !defined(_WIN32_WCE)) + /* Win9x console always uses OEM character coding, and + WinNT console is set to OEM charset by default, too */ + INTERN_TO_OEM((char *)space, (char *)space); +#endif /* (WIN32 && !_WIN32_WCE) */ +#endif /* ?WINDLL */ + + return (char *)space; + +#else /* NATIVE: EBCDIC or whatever */ + return (char *)raw; +#endif + +} /* end function fnfilter() */ + + + + +#ifdef SET_DIR_ATTRIB +/* must sort saved directories so can set perms from bottom up */ + +/************************/ +/* Function dircomp() */ +/************************/ + +static int Cdecl dircomp(a, b) /* used by qsort(); swiped from Zip */ + ZCONST zvoid *a, *b; +{ + /* order is significant: this sorts in reverse order (deepest first) */ + return strcmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); + /* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */ +} + +#endif /* SET_DIR_ATTRIB */ + + +#ifdef USE_BZIP2 + +/**************************/ +/* Function UZbunzip2() */ +/**************************/ + +int UZbunzip2(__G) +__GDEF +/* decompress a bzipped entry using the libbz2 routines */ +{ + int retval = 0; /* return code: 0 = "no error" */ + int err=BZ_OK; + int repeated_buf_err; + bz_stream bstrm; + + if (G.incnt <= 0 && G.csize <= 0L) { + /* avoid an infinite loop */ + Trace((stderr, "UZbunzip2() got empty input\n")); + return 2; + } + +#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 + + bstrm.next_out = (char *)redirSlide; + bstrm.avail_out = wsize; + + bstrm.next_in = (char *)G.inptr; + bstrm.avail_in = G.incnt; + + { + /* local buffer for efficiency */ + /* $TODO Check for BZIP LIB version? */ + + bstrm.bzalloc = NULL; + bstrm.bzfree = NULL; + bstrm.opaque = NULL; + + Trace((stderr, "initializing bzlib()\n")); + err = BZ2_bzDecompressInit(&bstrm, 0, 0); + + if (err == BZ_MEM_ERROR) + return 3; + else if (err != BZ_OK) + Trace((stderr, "oops! (BZ2_bzDecompressInit() err = %d)\n", err)); + } + +#ifdef FUNZIP + while (err != BZ_STREAM_END) { +#else /* !FUNZIP */ + while (G.csize > 0) { + Trace((stderr, "first loop: G.csize = %ld\n", G.csize)); +#endif /* ?FUNZIP */ + while (bstrm.avail_out > 0) { + err = BZ2_bzDecompress(&bstrm); + + if (err == BZ_DATA_ERROR) { + retval = 2; goto uzbunzip_cleanup_exit; + } else if (err == BZ_MEM_ERROR) { + retval = 3; goto uzbunzip_cleanup_exit; + } else if (err != BZ_OK && err != BZ_STREAM_END) + Trace((stderr, "oops! (bzip(first loop) err = %d)\n", err)); + +#ifdef FUNZIP + if (err == BZ_STREAM_END) /* "END-of-entry-condition" ? */ +#else /* !FUNZIP */ + if (G.csize <= 0L) /* "END-of-entry-condition" ? */ +#endif /* ?FUNZIP */ + break; + + if (bstrm.avail_in == 0) { + if (fillinbuf(__G) == 0) { + /* no "END-condition" yet, but no more data */ + retval = 2; goto uzbunzip_cleanup_exit; + } + + bstrm.next_in = (char *)G.inptr; + bstrm.avail_in = G.incnt; + } + Trace((stderr, " avail_in = %u\n", bstrm.avail_in)); + } + /* flush slide[] */ + if ((retval = FLUSH(wsize - bstrm.avail_out)) != 0) + goto uzbunzip_cleanup_exit; + Trace((stderr, "inside loop: flushing %ld bytes (ptr diff = %ld)\n", + (long)(wsize - bstrm.avail_out), + (long)(bstrm.next_out-(char *)redirSlide))); + bstrm.next_out = (char *)redirSlide; + bstrm.avail_out = wsize; + } + + /* no more input, so loop until we have all output */ + Trace((stderr, "beginning final loop: err = %d\n", err)); + repeated_buf_err = FALSE; + while (err != BZ_STREAM_END) { + err = BZ2_bzDecompress(&bstrm); + if (err == BZ_DATA_ERROR) { + retval = 2; goto uzbunzip_cleanup_exit; + } else if (err == BZ_MEM_ERROR) { + retval = 3; goto uzbunzip_cleanup_exit; + } else if (err != BZ_OK && err != BZ_STREAM_END) { + Trace((stderr, "oops! (bzip(final loop) err = %d)\n", err)); + DESTROYGLOBALS(); + EXIT(PK_MEM3); + } + /* final flush of slide[] */ + if ((retval = FLUSH(wsize - bstrm.avail_out)) != 0) + goto uzbunzip_cleanup_exit; + Trace((stderr, "final loop: flushing %ld bytes (ptr diff = %ld)\n", + (long)(wsize - bstrm.avail_out), + (long)(bstrm.next_out-(char *)redirSlide))); + bstrm.next_out = (char *)redirSlide; + bstrm.avail_out = wsize; + } +#ifdef LARGE_FILE_SUPPORT + Trace((stderr, "total in = %llu, total out = %llu\n", + (zusz_t)(bstrm.total_in_lo32) + ((zusz_t)(bstrm.total_in_hi32))<<32, + (zusz_t)(bstrm.total_out_lo32) + ((zusz_t)(bstrm.total_out_hi32))<<32)); +#else + Trace((stderr, "total in = %lu, total out = %lu\n", bstrm.total_in_lo32, + bstrm.total_out_lo32)); +#endif + + G.inptr = (uch *)bstrm.next_in; + G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */ + +uzbunzip_cleanup_exit: + err = BZ2_bzDecompressEnd(&bstrm); + if (err != BZ_OK) + Trace((stderr, "oops! (BZ2_bzDecompressEnd() err = %d)\n", err)); + + return retval; +} /* end function UZbunzip2() */ +#endif /* USE_BZIP2 */ diff -Naur a/fileio.c b/fileio.c --- a/fileio.c 2009-04-20 01:03:44.000000000 +0100 +++ b/fileio.c 2019-12-02 01:45:40.913845391 +0000 @@ -1,5 +1,5 @@ /* - Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + Copyright (c) 1990-2017 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2009-Jan-02 or later (the contents of which are also included in unzip.h) for terms of use. @@ -176,6 +176,8 @@ #endif static ZCONST char Far ExtraFieldTooLong[] = "warning: extra field too long (%d). Ignoring...\n"; +static ZCONST char Far ExtraFieldCorrupt[] = + "warning: extra field (type: 0x%04x) corrupt. Continuing...\n"; #ifdef WINDLL static ZCONST char Far DiskFullQuery[] = @@ -1580,6 +1582,8 @@ int r = IZ_PW_ENTERED; char *m; char *prompt; + char *ep; + char *zp; #ifndef REENTRANT /* tell picky compilers to shut up about "unused variable" warnings */ @@ -1588,9 +1592,12 @@ if (*rcnt == 0) { /* First call for current entry */ *rcnt = 2; - if ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL) { - sprintf(prompt, LoadFarString(PasswPrompt), - FnFilter1(zfn), FnFilter2(efn)); + zp = FnFilter1( zfn); + ep = FnFilter2( efn); + prompt = (char *)malloc( /* Slightly too long (2* "%s"). */ + sizeof( PasswPrompt)+ strlen( zp)+ strlen( ep)); + if (prompt != (char *)NULL) { + sprintf(prompt, LoadFarString(PasswPrompt), zp, ep); m = prompt; } else m = (char *)LoadFarString(PasswPrompt2); @@ -2006,6 +2013,7 @@ unsigned comment_bytes_left; unsigned int block_len; int error=PK_OK; + unsigned int length2; #ifdef AMIGA char tmp_fnote[2 * AMIGA_FILENOTELEN]; /* extra room for squozen chars */ #endif @@ -2292,10 +2300,20 @@ seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes + (G.inptr-G.inbuf) + length); } else { - if (readbuf(__G__ (char *)G.extra_field, length) == 0) + if ((length2 = readbuf(__G__ (char *)G.extra_field, length)) == 0) return PK_EOF; + if(length2 < length) { + memset (__G__ (char *)G.extra_field+length2, 0 , length-length2); + length = length2; + } /* Looks like here is where extra fields are read */ - getZip64Data(__G__ G.extra_field, length); + if (getZip64Data(__G__ G.extra_field, length) != PK_COOL) + { + Info(slide, 0x401, ((char *)slide, + LoadFarString( ExtraFieldCorrupt), EF_PKSZ64)); + error = PK_WARN; + } + #ifdef UNICODE_SUPPORT G.unipath_filename = NULL; if (G.UzO.U_flag < 2) { diff -Naur a/list.c b/list.c --- a/list.c 2009-02-08 17:11:34.000000000 +0000 +++ b/list.c 2019-12-02 01:48:07.035331859 +0000 @@ -97,7 +97,7 @@ { int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL; #ifndef WINDLL - char sgn, cfactorstr[10]; + char sgn, cfactorstr[1+10+1+1]; /* %NUL */ int longhdr=(uO.vflag>1); #endif int date_format; @@ -181,7 +181,7 @@ Info(slide, 0x401, ((char *)slide, LoadFarString(CentSigMsg), j)); Info(slide, 0x401, - ((char *)slide, LoadFarString(ReportMsg))); + ((char *)slide,"%s", LoadFarString(ReportMsg))); return PK_BADERR; /* sig not found */ } } @@ -339,7 +339,19 @@ G.crec.compression_method == ENHDEFLATED) { methbuf[5] = dtype[(G.crec.general_purpose_bit_flag>>1) & 3]; } else if (methnum >= NUM_METHODS) { - sprintf(&methbuf[4], "%03u", G.crec.compression_method); + /* 2013-02-26 SMS. + * http://sourceforge.net/tracker/?func=detail + * &aid=2861648&group_id=118012&atid=679786 + * Unexpectedly large compression methods overflow + * &methbuf[]. Use the old, three-digit decimal format + * for values which fit. Otherwise, sacrifice the + * colon, and use four-digit hexadecimal. + */ + if (G.crec.compression_method <= 999) { + sprintf( &methbuf[ 4], "%03u", G.crec.compression_method); + } else { + sprintf( &methbuf[ 3], "%04X", G.crec.compression_method); + } } #if 0 /* GRR/Euro: add this? */ @@ -378,9 +390,9 @@ } #else /* !WINDLL */ if (cfactor == 100) - sprintf(cfactorstr, LoadFarString(CompFactor100)); + snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100)); else - sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor); + snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor); if (longhdr) Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats), FmZofft(G.crec.ucsize, "8", "u"), methbuf, @@ -460,9 +472,9 @@ #else /* !WINDLL */ if (cfactor == 100) - sprintf(cfactorstr, LoadFarString(CompFactor100)); + snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100)); else - sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor); + snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor); if (longhdr) { Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer), FmZofft(tot_ucsize, "8", "u"), FmZofft(tot_csize, "8", "u"), @@ -507,7 +519,8 @@ && (!G.ecrec.is_zip64_archive) && (memcmp(G.sig, end_central_sig, 4) != 0) ) { /* just to make sure again */ - Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg))); + Info(slide, 0x401, + ((char *)slide,"%s", LoadFarString(EndSigMsg))); error_in_archive = PK_WARN; /* didn't find sig */ } @@ -591,7 +604,7 @@ Info(slide, 0x401, ((char *)slide, LoadFarString(CentSigMsg), j)); Info(slide, 0x401, - ((char *)slide, LoadFarString(ReportMsg))); + ((char *)slide,"%s", LoadFarString(ReportMsg))); return PK_BADERR; /* sig not found */ } } @@ -674,7 +687,7 @@ ---------------------------------------------------------------------------*/ if (memcmp(G.sig, end_central_sig, 4)) { /* just to make sure again */ - Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg))); + Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg))); error_in_archive = PK_WARN; } if (*nmember == 0L && error_in_archive <= PK_WARN) diff -Naur a/list.c.orig b/list.c.orig --- a/list.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ b/list.c.orig 2019-12-02 00:34:56.656315493 +0000 @@ -0,0 +1,746 @@ +/* + Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2009-Jan-02 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 +*/ +/*--------------------------------------------------------------------------- + + list.c + + This file contains the non-ZipInfo-specific listing routines for UnZip. + + Contains: list_files() + get_time_stamp() [optional feature] + ratio() + fnprint() + + ---------------------------------------------------------------------------*/ + + +#define UNZIP_INTERNAL +#include "unzip.h" +#ifdef WINDLL +# ifdef POCKET_UNZIP +# include "wince/intrface.h" +# else +# include "windll/windll.h" +# endif +#endif + + +#ifdef TIMESTAMP + static int fn_is_dir OF((__GPRO)); +#endif + +#ifndef WINDLL + static ZCONST char Far CompFactorStr[] = "%c%d%%"; + static ZCONST char Far CompFactor100[] = "100%%"; + +#ifdef OS2_EAS + static ZCONST char Far HeadersS[] = + " Length EAs ACLs Date Time Name"; + static ZCONST char Far HeadersS1[] = + "--------- --- ---- ---------- ----- ----"; +#else + static ZCONST char Far HeadersS[] = + " Length Date Time Name"; + static ZCONST char Far HeadersS1[] = + "--------- ---------- ----- ----"; +#endif + + static ZCONST char Far HeadersL[] = + " Length Method Size Cmpr Date Time CRC-32 Name"; + static ZCONST char Far HeadersL1[] = + "-------- ------ ------- ---- ---------- ----- -------- ----"; + static ZCONST char Far *Headers[][2] = + { {HeadersS, HeadersS1}, {HeadersL, HeadersL1} }; + + static ZCONST char Far CaseConversion[] = + "%s (\"^\" ==> case\n%s conversion)\n"; + static ZCONST char Far LongHdrStats[] = + "%s %-7s%s %4s %02u%c%02u%c%02u %02u:%02u %08lx %c"; + static ZCONST char Far LongFileTrailer[] = + "-------- ------- --- \ + -------\n%s %s %4s %lu file%s\n"; +#ifdef OS2_EAS + static ZCONST char Far ShortHdrStats[] = + "%s %6lu %6lu %02u%c%02u%c%02u %02u:%02u %c"; + static ZCONST char Far ShortFileTrailer[] = + "--------- ----- ----- \ + -------\n%s %6lu %6lu %lu file%s\n"; + static ZCONST char Far OS2ExtAttrTrailer[] = + "%lu file%s %lu bytes of OS/2 extended attributes attached.\n"; + static ZCONST char Far OS2ACLTrailer[] = + "%lu file%s %lu bytes of access control lists attached.\n"; +#else + static ZCONST char Far ShortHdrStats[] = + "%s %02u%c%02u%c%02u %02u:%02u %c"; + static ZCONST char Far ShortFileTrailer[] = + "--------- -------\n%s\ + %lu file%s\n"; +#endif /* ?OS2_EAS */ +#endif /* !WINDLL */ + + + + + +/*************************/ +/* Function list_files() */ +/*************************/ + +int list_files(__G) /* return PK-type error code */ + __GDEF +{ + int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL; +#ifndef WINDLL + char sgn, cfactorstr[13]; + int longhdr=(uO.vflag>1); +#endif + int date_format; + char dt_sepchar; + ulg members=0L; + zusz_t j; + unsigned methnum; +#ifdef USE_EF_UT_TIME + iztimes z_utime; + struct tm *t; +#endif + unsigned yr, mo, dy, hh, mm; + zusz_t csiz, tot_csize=0L, tot_ucsize=0L; +#ifdef OS2_EAS + ulg ea_size, tot_easize=0L, tot_eafiles=0L; + ulg acl_size, tot_aclsize=0L, tot_aclfiles=0L; +#endif + min_info info; + char methbuf[8]; + static ZCONST char dtype[]="NXFS"; /* see zi_short() */ + static ZCONST char Far method[NUM_METHODS+1][8] = + {"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4", + "Implode", "Token", "Defl:#", "Def64#", "ImplDCL", "BZip2", + "LZMA", "Terse", "IBMLZ77", "WavPack", "PPMd", "Unk:###"}; + + + +/*--------------------------------------------------------------------------- + Unlike extract_or_test_files(), this routine confines itself to the cen- + tral directory. Thus its structure is somewhat simpler, since we can do + just a single loop through the entire directory, listing files as we go. + + So to start off, print the heading line and then begin main loop through + the central directory. The results will look vaguely like the following: + + Length Method Size Ratio Date Time CRC-32 Name ("^" ==> case +-------- ------ ------- ----- ---- ---- ------ ---- conversion) + 44004 Implode 13041 71% 11-02-89 19:34 8b4207f7 Makefile.UNIX + 3438 Shrunk 2209 36% 09-15-90 14:07 a2394fd8 ^dos-file.ext + 16717 Defl:X 5252 69% 11-03-97 06:40 1ce0f189 WHERE +-------- ------- --- ------- + 64159 20502 68% 3 files + ---------------------------------------------------------------------------*/ + + G.pInfo = &info; + date_format = DATE_FORMAT; + dt_sepchar = DATE_SEPCHAR; + +#ifndef WINDLL + if (uO.qflag < 2) { + if (uO.L_flag) + Info(slide, 0, ((char *)slide, LoadFarString(CaseConversion), + LoadFarStringSmall(Headers[longhdr][0]), + LoadFarStringSmall2(Headers[longhdr][1]))); + else + Info(slide, 0, ((char *)slide, "%s\n%s\n", + LoadFarString(Headers[longhdr][0]), + LoadFarStringSmall(Headers[longhdr][1]))); + } +#endif /* !WINDLL */ + + for (j = 1L;;j++) { + + if (readbuf(__G__ G.sig, 4) == 0) + return PK_EOF; + if (memcmp(G.sig, central_hdr_sig, 4)) { /* is it a CentDir entry? */ + /* no new central directory entry + * -> is the number of processed entries compatible with the + * number of entries as stored in the end_central record? + */ + if (((j - 1) & + (ulg)(G.ecrec.have_ecr64 ? MASK_ZUCN64 : MASK_ZUCN16)) + == (ulg)G.ecrec.total_entries_central_dir) + { + /* "j modulus 4T/64k" matches the reported 64/16-bit-unsigned + * number of directory entries -> probably, the regular + * end of the central directory has been reached + */ + break; + } else { + Info(slide, 0x401, + ((char *)slide, LoadFarString(CentSigMsg), j)); + Info(slide, 0x401, + ((char *)slide,"%s", LoadFarString(ReportMsg))); + return PK_BADERR; /* sig not found */ + } + } + /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag, ...: */ + if ((error = process_cdir_file_hdr(__G)) != PK_COOL) + return error; /* only PK_EOF defined */ + + /* + * We could DISPLAY the filename instead of storing (and possibly trun- + * cating, in the case of a very long name) and printing it, but that + * has the disadvantage of not allowing case conversion--and it's nice + * to be able to see in the listing precisely how you have to type each + * filename in order for unzip to consider it a match. Speaking of + * which, if member names were specified on the command line, check in + * with match() to see if the current file is one of them, and make a + * note of it if it is. + */ + + if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) != + PK_COOL) /* ^--(uses pInfo->lcflag) */ + { + error_in_archive = error; + if (error > PK_WARN) /* fatal: can't continue */ + return error; + } + if (G.extra_field != (uch *)NULL) { + free(G.extra_field); + G.extra_field = (uch *)NULL; + } + if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD)) + != 0) + { + error_in_archive = error; + if (error > PK_WARN) /* fatal */ + return error; + } + if (!G.process_all_files) { /* check if specified on command line */ + unsigned i; + + if (G.filespecs == 0) + do_this_file = TRUE; + else { /* check if this entry matches an `include' argument */ + do_this_file = FALSE; + for (i = 0; i < G.filespecs; i++) + if (match(G.filename, G.pfnames[i], uO.C_flag WISEP)) { + do_this_file = TRUE; + break; /* found match, so stop looping */ + } + } + if (do_this_file) { /* check if this is an excluded file */ + for (i = 0; i < G.xfilespecs; i++) + if (match(G.filename, G.pxnames[i], uO.C_flag WISEP)) { + do_this_file = FALSE; /* ^-- ignore case in match */ + break; + } + } + } + /* + * If current file was specified on command line, or if no names were + * specified, do the listing for this file. Otherwise, get rid of the + * file comment and go back for the next file. + */ + + if (G.process_all_files || do_this_file) { + +#ifdef OS2DLL + /* this is used by UzpFileTree() to allow easy processing of lists + * of zip directory contents */ + if (G.processExternally) { + if ((G.processExternally)(G.filename, &G.crec)) + break; + ++members; + } else { +#endif +#ifdef OS2_EAS + { + uch *ef_ptr = G.extra_field; + int ef_size, ef_len = G.crec.extra_field_length; + ea_size = acl_size = 0; + + while (ef_len >= EB_HEADSIZE) { + ef_size = makeword(&ef_ptr[EB_LEN]); + switch (makeword(&ef_ptr[EB_ID])) { + case EF_OS2: + ea_size = makelong(&ef_ptr[EB_HEADSIZE]); + break; + case EF_ACL: + acl_size = makelong(&ef_ptr[EB_HEADSIZE]); + break; + } + ef_ptr += (ef_size + EB_HEADSIZE); + ef_len -= (ef_size + EB_HEADSIZE); + } + } +#endif +#ifdef USE_EF_UT_TIME + if (G.extra_field && +#ifdef IZ_CHECK_TZ + G.tz_is_valid && +#endif + (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1, + G.crec.last_mod_dos_datetime, &z_utime, NULL) + & EB_UT_FL_MTIME)) + { + TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7.0, Mac */ + t = localtime(&(z_utime.mtime)); + } else + t = (struct tm *)NULL; + if (t != (struct tm *)NULL) { + mo = (unsigned)(t->tm_mon + 1); + dy = (unsigned)(t->tm_mday); + yr = (unsigned)(t->tm_year + 1900); + hh = (unsigned)(t->tm_hour); + mm = (unsigned)(t->tm_min); + } else +#endif /* USE_EF_UT_TIME */ + { + yr = ((((unsigned)(G.crec.last_mod_dos_datetime >> 25) & 0x7f) + + 1980)); + mo = ((unsigned)(G.crec.last_mod_dos_datetime >> 21) & 0x0f); + dy = ((unsigned)(G.crec.last_mod_dos_datetime >> 16) & 0x1f); + hh = (((unsigned)G.crec.last_mod_dos_datetime >> 11) & 0x1f); + mm = (((unsigned)G.crec.last_mod_dos_datetime >> 5) & 0x3f); + } + /* permute date so it displays according to nat'l convention + * ('methnum' is not yet set, it is used as temporary buffer) */ + switch (date_format) { + case DF_YMD: + methnum = mo; + mo = yr; yr = dy; dy = methnum; + break; + case DF_DMY: + methnum = mo; + mo = dy; dy = methnum; + } + + csiz = G.crec.csize; + if (G.crec.general_purpose_bit_flag & 1) + csiz -= 12; /* if encrypted, don't count encryption header */ + if ((cfactor = ratio(G.crec.ucsize, csiz)) < 0) { +#ifndef WINDLL + sgn = '-'; +#endif + cfactor = (-cfactor + 5) / 10; + } else { +#ifndef WINDLL + sgn = ' '; +#endif + cfactor = (cfactor + 5) / 10; + } + + methnum = find_compr_idx(G.crec.compression_method); + zfstrcpy(methbuf, method[methnum]); + if (G.crec.compression_method == DEFLATED || + G.crec.compression_method == ENHDEFLATED) { + methbuf[5] = dtype[(G.crec.general_purpose_bit_flag>>1) & 3]; + } else if (methnum >= NUM_METHODS) { + /* 2013-02-26 SMS. + * http://sourceforge.net/tracker/?func=detail + * &aid=2861648&group_id=118012&atid=679786 + * Unexpectedly large compression methods overflow + * &methbuf[]. Use the old, three-digit decimal format + * for values which fit. Otherwise, sacrifice the + * colon, and use four-digit hexadecimal. + */ + if (G.crec.compression_method <= 999) { + sprintf( &methbuf[ 4], "%03u", G.crec.compression_method); + } else { + sprintf( &methbuf[ 3], "%04X", G.crec.compression_method); + } + } + +#if 0 /* GRR/Euro: add this? */ +#if defined(DOS_FLX_NLM_OS2_W32) || defined(THEOS) || defined(UNIX) + for (p = G.filename; *p; ++p) + if (!isprint(*p)) + *p = '?'; /* change non-printable chars to '?' */ +#endif /* DOS_FLX_NLM_OS2_W32 || THEOS || UNIX */ +#endif /* 0 */ + +#ifdef WINDLL + /* send data to application for formatting and printing */ + if (G.lpUserFunctions->SendApplicationMessage != NULL) + (*G.lpUserFunctions->SendApplicationMessage)(G.crec.ucsize, + csiz, (unsigned)cfactor, mo, dy, yr, hh, mm, + (char)(G.pInfo->lcflag ? '^' : ' '), + (LPCSTR)fnfilter(G.filename, slide, (WSIZE>>1)), + (LPCSTR)methbuf, G.crec.crc32, + (char)((G.crec.general_purpose_bit_flag & 1) ? 'E' : ' ')); + else if (G.lpUserFunctions->SendApplicationMessage_i32 != NULL) { + unsigned long ucsize_lo, csiz_lo; + unsigned long ucsize_hi=0L, csiz_hi=0L; + ucsize_lo = (unsigned long)(G.crec.ucsize); + csiz_lo = (unsigned long)(csiz); +#ifdef ZIP64_SUPPORT + ucsize_hi = (unsigned long)(G.crec.ucsize >> 32); + csiz_hi = (unsigned long)(csiz >> 32); +#endif /* ZIP64_SUPPORT */ + (*G.lpUserFunctions->SendApplicationMessage_i32)(ucsize_lo, + ucsize_hi, csiz_lo, csiz_hi, (unsigned)cfactor, + mo, dy, yr, hh, mm, + (char)(G.pInfo->lcflag ? '^' : ' '), + (LPCSTR)fnfilter(G.filename, slide, (WSIZE>>1)), + (LPCSTR)methbuf, G.crec.crc32, + (char)((G.crec.general_purpose_bit_flag & 1) ? 'E' : ' ')); + } +#else /* !WINDLL */ + if (cfactor == 100) + sprintf(cfactorstr, LoadFarString(CompFactor100)); + else + sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor); + if (longhdr) + Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats), + FmZofft(G.crec.ucsize, "8", "u"), methbuf, + FmZofft(csiz, "8", "u"), cfactorstr, + mo, dt_sepchar, dy, dt_sepchar, yr, hh, mm, + G.crec.crc32, (G.pInfo->lcflag? '^':' '))); + else +#ifdef OS2_EAS + Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats), + FmZofft(G.crec.ucsize, "9", "u"), ea_size, acl_size, + mo, dt_sepchar, dy, dt_sepchar, yr, hh, mm, + (G.pInfo->lcflag? '^':' '))); +#else + Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats), + FmZofft(G.crec.ucsize, "9", "u"), + mo, dt_sepchar, dy, dt_sepchar, yr, hh, mm, + (G.pInfo->lcflag? '^':' '))); +#endif + fnprint(__G); +#endif /* ?WINDLL */ + + if ((error = do_string(__G__ G.crec.file_comment_length, + QCOND? DISPL_8 : SKIP)) != 0) + { + error_in_archive = error; /* might be just warning */ + if (error > PK_WARN) /* fatal */ + return error; + } + tot_ucsize += G.crec.ucsize; + tot_csize += csiz; + ++members; +#ifdef OS2_EAS + if (ea_size) { + tot_easize += ea_size; + ++tot_eafiles; + } + if (acl_size) { + tot_aclsize += acl_size; + ++tot_aclfiles; + } +#endif +#ifdef OS2DLL + } /* end of "if (G.processExternally) {...} else {..." */ +#endif + } else { /* not listing this file */ + SKIP_(G.crec.file_comment_length) + } + } /* end for-loop (j: files in central directory) */ + +/*--------------------------------------------------------------------------- + Print footer line and totals (compressed size, uncompressed size, number + of members in zipfile). + ---------------------------------------------------------------------------*/ + + if (uO.qflag < 2 +#ifdef OS2DLL + && !G.processExternally +#endif + ) { + if ((cfactor = ratio(tot_ucsize, tot_csize)) < 0) { +#ifndef WINDLL + sgn = '-'; +#endif + cfactor = (-cfactor + 5) / 10; + } else { +#ifndef WINDLL + sgn = ' '; +#endif + cfactor = (cfactor + 5) / 10; + } +#ifdef WINDLL + /* pass the totals back to the calling application */ + G.lpUserFunctions->TotalSizeComp = tot_csize; + G.lpUserFunctions->TotalSize = tot_ucsize; + G.lpUserFunctions->CompFactor = (ulg)cfactor; + G.lpUserFunctions->NumMembers = members; + +#else /* !WINDLL */ + if (cfactor == 100) + sprintf(cfactorstr, LoadFarString(CompFactor100)); + else + sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor); + if (longhdr) { + Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer), + FmZofft(tot_ucsize, "8", "u"), FmZofft(tot_csize, "8", "u"), + cfactorstr, members, members==1? "":"s")); +#ifdef OS2_EAS + if (tot_easize || tot_aclsize) + Info(slide, 0, ((char *)slide, "\n")); + if (tot_eafiles && tot_easize) + Info(slide, 0, ((char *)slide, LoadFarString(OS2ExtAttrTrailer), + tot_eafiles, tot_eafiles == 1? " has" : "s have a total of", + tot_easize)); + if (tot_aclfiles && tot_aclsize) + Info(slide, 0, ((char *)slide, LoadFarString(OS2ACLTrailer), + tot_aclfiles, + tot_aclfiles == 1 ? " has" : "s have a total of", + tot_aclsize)); +#endif /* OS2_EAS */ + } else +#ifdef OS2_EAS + Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer), + FmZofft(tot_ucsize, "9", "u"), tot_easize, tot_aclsize, + members, members == 1 ? "" : "s")); +#else + Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer), + FmZofft(tot_ucsize, "9", "u"), + members, members == 1 ? "" : "s")); +#endif /* OS2_EAS */ +#endif /* ?WINDLL */ + } + + /* Skip the following checks in case of a premature listing break. */ + if (error_in_archive <= PK_WARN) { + +/*--------------------------------------------------------------------------- + Double check that we're back at the end-of-central-directory record. + ---------------------------------------------------------------------------*/ + + if ( (memcmp(G.sig, + (G.ecrec.have_ecr64 ? + end_central64_sig : end_central_sig), + 4) != 0) + && (!G.ecrec.is_zip64_archive) + && (memcmp(G.sig, end_central_sig, 4) != 0) + ) { /* just to make sure again */ + Info(slide, 0x401, + ((char *)slide,"%s", LoadFarString(EndSigMsg))); + error_in_archive = PK_WARN; /* didn't find sig */ + } + + /* Set specific return code when no files have been found. */ + if (members == 0L && error_in_archive <= PK_WARN) + error_in_archive = PK_FIND; + + } + + return error_in_archive; + +} /* end function list_files() */ + + + + + +#ifdef TIMESTAMP + +/************************/ +/* Function fn_is_dir() */ +/************************/ + +static int fn_is_dir(__G) /* returns TRUE if G.filename is directory */ + __GDEF +{ + extent fn_len = strlen(G.filename); + register char endc; + + return fn_len > 0 && + ((endc = lastchar(G.filename, fn_len)) == '/' || + (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/') && + endc == '\\')); +} + + + + + +/*****************************/ +/* Function get_time_stamp() */ +/*****************************/ + +int get_time_stamp(__G__ last_modtime, nmember) /* return PK-type error code */ + __GDEF + time_t *last_modtime; + ulg *nmember; +{ + int do_this_file=FALSE, error, error_in_archive=PK_COOL; + ulg j; +#ifdef USE_EF_UT_TIME + iztimes z_utime; +#endif + min_info info; + + +/*--------------------------------------------------------------------------- + Unlike extract_or_test_files() but like list_files(), this function works + on information in the central directory alone. Thus we have a single, + large loop through the entire directory, searching for the latest time + stamp. + ---------------------------------------------------------------------------*/ + + *last_modtime = 0L; /* assuming no zipfile data older than 1970 */ + *nmember = 0L; + G.pInfo = &info; + + for (j = 1L;; j++) { + + if (readbuf(__G__ G.sig, 4) == 0) + return PK_EOF; + if (memcmp(G.sig, central_hdr_sig, 4)) { /* is it a CentDir entry? */ + if (((unsigned)(j - 1) & (unsigned)0xFFFF) == + (unsigned)G.ecrec.total_entries_central_dir) { + /* "j modulus 64k" matches the reported 16-bit-unsigned + * number of directory entries -> probably, the regular + * end of the central directory has been reached + */ + break; + } else { + Info(slide, 0x401, + ((char *)slide, LoadFarString(CentSigMsg), j)); + Info(slide, 0x401, + ((char *)slide,"%s", LoadFarString(ReportMsg))); + return PK_BADERR; /* sig not found */ + } + } + /* process_cdir_file_hdr() sets pInfo->lcflag: */ + if ((error = process_cdir_file_hdr(__G)) != PK_COOL) + return error; /* only PK_EOF defined */ + if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) != PK_OK) + { /* ^-- (uses pInfo->lcflag) */ + error_in_archive = error; + if (error > PK_WARN) /* fatal: can't continue */ + return error; + } + if (G.extra_field != (uch *)NULL) { + free(G.extra_field); + G.extra_field = (uch *)NULL; + } + if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD)) + != 0) + { + error_in_archive = error; + if (error > PK_WARN) /* fatal */ + return error; + } + if (!G.process_all_files) { /* check if specified on command line */ + unsigned i; + + if (G.filespecs == 0) + do_this_file = TRUE; + else { /* check if this entry matches an `include' argument */ + do_this_file = FALSE; + for (i = 0; i < G.filespecs; i++) + if (match(G.filename, G.pfnames[i], uO.C_flag WISEP)) { + do_this_file = TRUE; + break; /* found match, so stop looping */ + } + } + if (do_this_file) { /* check if this is an excluded file */ + for (i = 0; i < G.xfilespecs; i++) + if (match(G.filename, G.pxnames[i], uO.C_flag WISEP)) { + do_this_file = FALSE; /* ^-- ignore case in match */ + break; + } + } + } + + /* If current file was specified on command line, or if no names were + * specified, check the time for this file. Either way, get rid of the + * file comment and go back for the next file. + * Directory entries are always ignored, to stay compatible with both + * Zip and PKZIP. + */ + if ((G.process_all_files || do_this_file) && !fn_is_dir(__G)) { +#ifdef USE_EF_UT_TIME + if (G.extra_field && +#ifdef IZ_CHECK_TZ + G.tz_is_valid && +#endif + (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1, + G.crec.last_mod_dos_datetime, &z_utime, NULL) + & EB_UT_FL_MTIME)) + { + if (*last_modtime < z_utime.mtime) + *last_modtime = z_utime.mtime; + } else +#endif /* USE_EF_UT_TIME */ + { + time_t modtime = dos_to_unix_time(G.crec.last_mod_dos_datetime); + + if (*last_modtime < modtime) + *last_modtime = modtime; + } + ++*nmember; + } + SKIP_(G.crec.file_comment_length) + + } /* end for-loop (j: files in central directory) */ + +/*--------------------------------------------------------------------------- + Double check that we're back at the end-of-central-directory record. + ---------------------------------------------------------------------------*/ + + if (memcmp(G.sig, end_central_sig, 4)) { /* just to make sure again */ + Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg))); + error_in_archive = PK_WARN; + } + if (*nmember == 0L && error_in_archive <= PK_WARN) + error_in_archive = PK_FIND; + + return error_in_archive; + +} /* end function get_time_stamp() */ + +#endif /* TIMESTAMP */ + + + + + +/********************/ +/* Function ratio() */ /* also used by ZipInfo routines */ +/********************/ + +int ratio(uc, c) + zusz_t uc, c; +{ + zusz_t denom; + + if (uc == 0) + return 0; + if (uc > 2000000L) { /* risk signed overflow if multiply numerator */ + denom = uc / 1000L; + return ((uc >= c) ? + (int) ((uc-c + (denom>>1)) / denom) : + -((int) ((c-uc + (denom>>1)) / denom))); + } else { /* ^^^^^^^^ rounding */ + denom = uc; + return ((uc >= c) ? + (int) ((1000L*(uc-c) + (denom>>1)) / denom) : + -((int) ((1000L*(c-uc) + (denom>>1)) / denom))); + } /* ^^^^^^^^ rounding */ +} + + + + + +/************************/ +/* Function fnprint() */ /* also used by ZipInfo routines */ +/************************/ + +void fnprint(__G) /* print filename (after filtering) and newline */ + __GDEF +{ + char *name = fnfilter(G.filename, slide, (extent)(WSIZE>>1)); + + (*G.message)((zvoid *)&G, (uch *)name, (ulg)strlen(name), 0); + (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); + +} /* end function fnprint() */ diff -Naur a/match.c b/match.c --- a/match.c 2005-08-14 18:00:36.000000000 +0100 +++ b/match.c 2019-12-02 00:19:45.331163073 +0000 @@ -27,16 +27,14 @@ --------------------------------------------------------------------------- - Copyright on recmatch() from Zip's util.c (although recmatch() was almost - certainly written by Mark Adler...ask me how I can tell :-) ): + Copyright on recmatch() from Zip's util.c + Copyright (c) 1990-2005 Info-ZIP. All rights reserved. - Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly, - Kai Uwe Rommel and Igor Mandrichenko. + See the accompanying file LICENSE, version 2004-May-22 or later + for terms of use. + If, for some reason, both of these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html - Permission is granted to any individual or institution to use, copy, - or redistribute this software so long as all of the original files are - included unmodified, that it is not sold for profit, and that this copy- - right notice is retained. --------------------------------------------------------------------------- @@ -53,7 +51,7 @@ A set is composed of characters or ranges; a range looks like ``character hyphen character'' (as in 0-9 or A-Z). [0-9a-zA-Z_] is the minimal set of - characters allowed in the [..] pattern construct. Other characters are + characters ALlowed in the [..] pattern construct. Other characters are allowed (i.e., 8-bit characters) if your system will support them. To suppress the special syntactic significance of any of ``[]*?!^-\'', in- @@ -101,8 +99,32 @@ # define WILDCHAR '?' # define BEG_RANGE '[' # define END_RANGE ']' +# define WILDCHR_SINGLE '?' +# define DIRSEP_CHR '/' +# define WILDCHR_MULTI '*' #endif +#ifdef WILD_STOP_AT_DIR + int wild_stop_at_dir = 1; /* default wildcards do not include / in matches */ +#else + int wild_stop_at_dir = 0; /* default wildcards do include / in matches */ +#endif + + + +/* + * case mapping functions. case_map is used to ignore case in comparisons, + * to_up is used to force upper case even on Unix (for dosify option). + */ +#ifdef USE_CASE_MAP +# define case_map(c) upper[(c) & 0xff] +# define to_up(c) upper[(c) & 0xff] +#else +# define case_map(c) (c) +# define to_up(c) ((c) >= 'a' && (c) <= 'z' ? (c)-'a'+'A' : (c)) +#endif /* USE_CASE_MAP */ + + #if 0 /* GRR: add this to unzip.h someday... */ #if !(defined(MSDOS) && defined(DOSWILD)) #ifdef WILD_STOP_AT_DIR @@ -114,8 +136,8 @@ int ignore_case __WDLPRO)); #endif #endif /* 0 */ -static int recmatch OF((ZCONST uch *pattern, ZCONST uch *string, - int ignore_case __WDLPRO)); +static int recmatch OF((ZCONST char *, ZCONST char *, + int)); static char *isshexp OF((ZCONST char *p)); static int namecmp OF((ZCONST char *s1, ZCONST char *s2)); @@ -154,192 +176,240 @@ } dospattern[j-1] = '\0'; /* nuke the end "." */ } - j = recmatch((uch *)dospattern, (uch *)string, ignore_case __WDL); + j = recmatch(dospattern, string, ignore_case); free(dospattern); return j == 1; } else #endif /* MSDOS && DOSWILD */ - return recmatch((uch *)pattern, (uch *)string, ignore_case __WDL) == 1; + return recmatch(pattern, string, ignore_case) == 1; } +#ifdef _MBCS + +char *___tmp_ptr; +#endif -static int recmatch(p, s, ic __WDL) - ZCONST uch *p; /* sh pattern to match */ - ZCONST uch *s; /* string to which to match it */ - int ic; /* true for case insensitivity */ - __WDLDEF /* directory sepchar for WildStopAtDir mode, or 0 */ +static int recmatch(p, s, ci) +ZCONST char *p; /* sh pattern to match */ +ZCONST char *s; /* string to match it to */ +int ci; /* flag: force case-insensitive matching */ /* Recursively compare the sh pattern p with the string s and return 1 if - * they match, and 0 or 2 if they don't or if there is a syntax error in the - * pattern. This routine recurses on itself no more deeply than the number - * of characters in the pattern. */ + they match, and 0 or 2 if they don't or if there is a syntax error in the + pattern. This routine recurses on itself no deeper than the number of + characters in the pattern. */ { - unsigned int c; /* pattern char or start of range in [-] loop */ + int c; /* pattern char or start of range in [-] loop */ + /* Get first character, the pattern for new recmatch calls follows */ + /* borrowed from Zip's global.c */ + int no_wild = 0; + int allow_regex=1; + /* This fix provided by akt@m5.dion.ne.jp for Japanese. + See 21 July 2006 mail. + It only applies when p is pointing to a doublebyte character and + things like / and wildcards are not doublebyte. This probably + should not be needed. */ - /* Get first character, the pattern for new recmatch calls follows */ - c = *p; INCSTR(p); +#ifdef _MBCS + if (CLEN(p) == 2) { + if (CLEN(s) == 2) { + return (*p == *s && *(p+1) == *(s+1)) ? + recmatch(p + 2, s + 2, ci) : 0; + } else { + return 0; + } + } +#endif /* ?_MBCS */ - /* If that was the end of the pattern, match if string empty too */ - if (c == 0) - return *s == 0; + c = *POSTINCSTR(p); - /* '?' (or '%') matches any character (but not an empty string). */ - if (c == WILDCHAR) -#ifdef WILD_STOP_AT_DIR - /* If uO.W_flag is non-zero, it won't match '/' */ - return (*s && (!sepc || *s != (uch)sepc)) - ? recmatch(p, s + CLEN(s), ic, sepc) : 0; -#else - return *s ? recmatch(p, s + CLEN(s), ic) : 0; -#endif + /* If that was the end of the pattern, match if string empty too */ + if (c == 0) + return *s == 0; + + /* '?' (or '%' or '#') matches any character (but not an empty string) */ + if (c == WILDCHR_SINGLE) { + if (wild_stop_at_dir) + return (*s && *s != DIRSEP_CHR) ? recmatch(p, s + CLEN(s), ci) : 0; + else + return *s ? recmatch(p, s + CLEN(s), ci) : 0; + } - /* '*' matches any number of characters, including zero */ + /* WILDCHR_MULTI ('*') matches any number of characters, including zero */ #ifdef AMIGA - if (c == '#' && *p == '?') /* "#?" is Amiga-ese for "*" */ - c = '*', p++; + if (!no_wild && c == '#' && *p == '?') /* "#?" is Amiga-ese for "*" */ + c = WILDCHR_MULTI, p++; #endif /* AMIGA */ - if (c == '*') { -#ifdef WILD_STOP_AT_DIR - if (sepc) { - /* check for single "*" or double "**" */ -# ifdef AMIGA - if ((c = p[0]) == '#' && p[1] == '?') /* "#?" is Amiga-ese for "*" */ - c = '*', p++; - if (c != '*') { -# else /* !AMIGA */ - if (*p != '*') { -# endif /* ?AMIGA */ - /* single "*": this doesn't match the dirsep character */ - for (; *s && *s != (uch)sepc; INCSTR(s)) - if ((c = recmatch(p, s, ic, sepc)) != 0) - return (int)c; - /* end of pattern: matched if at end of string, else continue */ - if (*p == '\0') - return (*s == 0); - /* continue to match if at sepc in pattern, else give up */ - return (*p == (uch)sepc || (*p == '\\' && p[1] == (uch)sepc)) - ? recmatch(p, s, ic, sepc) : 2; - } - /* "**": this matches slashes */ - ++p; /* move p behind the second '*' */ - /* and continue with the non-W_flag code variant */ - } -#endif /* WILD_STOP_AT_DIR */ + if (!no_wild && c == WILDCHR_MULTI) + { + if (wild_stop_at_dir) { + /* Check for an immediately following WILDCHR_MULTI */ +# ifdef AMIGA + if ((c = p[0]) == '#' && p[1] == '?') /* "#?" is Amiga-ese for "*" */ + c = WILDCHR_MULTI, p++; + if (c != WILDCHR_MULTI) { +# else /* !AMIGA */ + if (*p != WILDCHR_MULTI) { +# endif /* ?AMIGA */ + /* Single WILDCHR_MULTI ('*'): this doesn't match slashes */ + for (; *s && *s != DIRSEP_CHR; INCSTR(s)) + if ((c = recmatch(p, s, ci)) != 0) + return c; + /* end of pattern: matched if at end of string, else continue */ if (*p == 0) - return 1; - if (isshexp((ZCONST char *)p) == NULL) { - /* Optimization for rest of pattern being a literal string: - * If there are no other shell expression chars in the rest - * of the pattern behind the multi-char wildcard, then just - * compare the literal string tail. - */ - ZCONST uch *srest; - - srest = s + (strlen((ZCONST char *)s) - strlen((ZCONST char *)p)); - if (srest - s < 0) - /* remaining literal string from pattern is longer than rest - * of test string, there can't be a match - */ - return 0; - else - /* compare the remaining literal pattern string with the last - * bytes of the test string to check for a match - */ + return (*s == 0); + /* continue to match if at DIRSEP_CHR in pattern, else give up */ + return (*p == DIRSEP_CHR || (*p == '\\' && p[1] == DIRSEP_CHR)) + ? recmatch(p, s, ci) : 2; + } + /* Two consecutive WILDCHR_MULTI ("**"): this matches DIRSEP_CHR ('/') */ + p++; /* move p past the second WILDCHR_MULTI */ + /* continue with the normal non-WILD_STOP_AT_DIR code */ + } /* wild_stop_at_dir */ + + /* Not wild_stop_at_dir */ + if (*p == 0) + return 1; + if (!isshexp((char *)p)) + { + /* optimization for rest of pattern being a literal string */ + + /* optimization to handle patterns like *.txt */ + /* if the first char in the pattern is '*' and there */ + /* are no other shell expression chars, i.e. a literal string */ + /* then just compare the literal string at the end */ + + ZCONST char *srest; + + srest = s + (strlen(s) - strlen(p)); + if (srest - s < 0) + /* remaining literal string from pattern is longer than rest of + test string, there can't be a match + */ + return 0; + else + /* compare the remaining literal pattern string with the last bytes + of the test string to check for a match */ #ifdef _MBCS - { - ZCONST uch *q = s; + { + ZCONST char *q = s; - /* MBCS-aware code must not scan backwards into a string from - * the end. - * So, we have to move forward by character from our well-known - * character position s in the test string until we have - * advanced to the srest position. - */ - while (q < srest) - INCSTR(q); - /* In case the byte *srest is a trailing byte of a multibyte - * character in the test string s, we have actually advanced - * past the position (srest). - * For this case, the match has failed! - */ - if (q != srest) - return 0; - return ((ic - ? namecmp((ZCONST char *)p, (ZCONST char *)q) - : strcmp((ZCONST char *)p, (ZCONST char *)q) - ) == 0); - } + /* MBCS-aware code must not scan backwards into a string from + * the end. + * So, we have to move forward by character from our well-known + * character position s in the test string until we have advanced + * to the srest position. + */ + while (q < srest) + INCSTR(q); + /* In case the byte *srest is a trailing byte of a multibyte + * character, we have actually advanced past the position (srest). + * For this case, the match has failed! + */ + if (q != srest) + return 0; + return ((!ci ? strcmp(p, q) : namecmp(p, q)) == 0); + } #else /* !_MBCS */ - return ((ic - ? namecmp((ZCONST char *)p, (ZCONST char *)srest) - : strcmp((ZCONST char *)p, (ZCONST char *)srest) - ) == 0); + return ((!ci ? strcmp(p, srest) : namecmp(p, srest)) == 0); #endif /* ?_MBCS */ - } else { - /* pattern contains more wildcards, continue with recursion... */ - for (; *s; INCSTR(s)) - if ((c = recmatch(p, s, ic __WDL)) != 0) - return (int)c; - return 2; /* 2 means give up--match will return false */ - } } - - /* Parse and process the list of characters and ranges in brackets */ - if (c == BEG_RANGE) { - int e; /* flag true if next char to be taken literally */ - ZCONST uch *q; /* pointer to end of [-] group */ - int r; /* flag true to match anything but the range */ - - if (*s == 0) /* need a character to match */ - return 0; - p += (r = (*p == '!' || *p == '^')); /* see if reverse */ - for (q = p, e = 0; *q; INCSTR(q)) /* find closing bracket */ - if (e) - e = 0; - else - if (*q == '\\') /* GRR: change to ^ for MS-DOS, OS/2? */ - e = 1; - else if (*q == END_RANGE) - break; - if (*q != END_RANGE) /* nothing matches if bad syntax */ - return 0; - for (c = 0, e = (*p == '-'); p < q; INCSTR(p)) { - /* go through the list */ - if (!e && *p == '\\') /* set escape flag if \ */ - e = 1; - else if (!e && *p == '-') /* set start of range if - */ - c = *(p-1); - else { - unsigned int cc = Case(*s); - - if (*(p+1) != '-') - for (c = c ? c : *p; c <= *p; c++) /* compare range */ - if ((unsigned)Case(c) == cc) /* typecast for MSC bug */ - return r ? 0 : recmatch(q + 1, s + 1, ic __WDL); - c = e = 0; /* clear range, escape flags */ - } - } - return r ? recmatch(q + CLEN(q), s + CLEN(s), ic __WDL) : 0; - /* bracket match failed */ + else + { + /* pattern contains more wildcards, continue with recursion... */ + for (; *s; INCSTR(s)) + if ((c = recmatch(p, s, ci)) != 0) + return c; + return 2; /* 2 means give up--shmatch will return false */ } + } - /* if escape ('\\'), just compare next character */ - if (c == '\\' && (c = *p++) == 0) /* if \ at end, then syntax error */ - return 0; +#ifndef VMS /* No bracket matching in VMS */ + /* Parse and process the list of characters and ranges in brackets */ + if (!no_wild && allow_regex && c == '[') + { + int e; /* flag true if next char to be taken literally */ + ZCONST char *q; /* pointer to end of [-] group */ + int r; /* flag true to match anything but the range */ + + if (*s == 0) /* need a character to match */ + return 0; + p += (r = (*p == '!' || *p == '^')); /* see if reverse */ + for (q = p, e = 0; *q; q++) /* find closing bracket */ + if (e) + e = 0; + else + if (*q == '\\') + e = 1; + else if (*q == ']') + break; + if (*q != ']') /* nothing matches if bad syntax */ + return 0; + for (c = 0, e = *p == '-'; p < q; p++) /* go through the list */ + { + if (e == 0 && *p == '\\') /* set escape flag if \ */ + e = 1; + else if (e == 0 && *p == '-') /* set start of range if - */ + c = *(p-1); + else + { + uch cc = (!ci ? (uch)*s : to_up((uch)*s)); + uch uc = (uch) c; + if (*(p+1) != '-') + for (uc = uc ? uc : (uch)*p; uc <= (uch)*p; uc++) + /* compare range */ + if ((!ci ? uc : to_up(uc)) == cc) + return r ? 0 : recmatch(q + CLEN(q), s + CLEN(s), ci); + c = e = 0; /* clear range, escape flags */ + } + } + return r ? recmatch(q + CLEN(q), s + CLEN(s), ci) : 0; + /* bracket match failed */ + } +#endif /* !VMS */ - /* just a character--compare it */ -#ifdef QDOS - return QMatch(Case((uch)c), Case(*s)) ? - recmatch(p, s + CLEN(s), ic __WDL) : 0; -#else - return Case((uch)c) == Case(*s) ? - recmatch(p, s + CLEN(s), ic __WDL) : 0; -#endif + /* If escape ('\'), just compare next character */ + if (!no_wild && c == '\\') + if ((c = *p++) == '\0') /* if \ at end, then syntax error */ + return 0; + +#ifdef VMS + /* 2005-11-06 SMS. + Handle "..." wildcard in p with "." or "]" in s. + */ + if ((c == '.') && (*p == '.') && (*(p+ CLEN( p)) == '.') && + ((*s == '.') || (*s == ']'))) + { + /* Match "...]" with "]". Continue after "]" in both. */ + if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']')) + return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), ci); + + /* Else, look for a reduced match in s, until "]" in or end of s. */ + for (; *s && (*s != ']'); INCSTR(s)) + if (*s == '.') + /* If reduced match, then continue after "..." in p, "." in s. */ + if ((c = recmatch( (p+ CLEN( p)), s, ci)) != 0) + return (int)c; + + /* Match "...]" with "]". Continue after "]" in both. */ + if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']')) + return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), ci); + + /* No reduced match. Quit. */ + return 2; + } + +#endif /* def VMS */ + + /* Just a character--compare it */ + return (!ci ? c == *s : to_up((uch)c) == to_up((uch)*s)) ? + recmatch(p, s + CLEN(s), ci) : 0; +} -} /* end function recmatch() */ +/*************************************************************************************************/ static char *isshexp(p) ZCONST char *p; /* If p is a sh expression, a pointer to the first special character is diff -Naur a/process.c b/process.c --- a/process.c 2009-03-06 01:25:10.000000000 +0000 +++ b/process.c 2019-12-02 01:44:23.792587920 +0000 @@ -1,5 +1,5 @@ /* - Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + Copyright (c) 1990-2014 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2009-Jan-02 or later (the contents of which are also included in unzip.h) for terms of use. @@ -1888,48 +1888,83 @@ and a 4-byte version of disk start number. Sets both local header and central header fields. Not terribly clever, but it means that this procedure is only called in one place. + + 2014-12-05 SMS. + Added checks to ensure that enough data are available before calling + makeint64() or makelong(). Replaced various sizeof() values with + simple ("4" or "8") constants. (The Zip64 structures do not depend + on our variable sizes.) Error handling is crude, but we should now + stay within the buffer. ---------------------------------------------------------------------------*/ +#define Z64FLGS 0xffff +#define Z64FLGL 0xffffffff + if (ef_len == 0 || ef_buf == NULL) return PK_COOL; Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n", ef_len)); - while (ef_len >= EB_HEADSIZE) { + while (ef_len >= EB_HEADSIZE) + { eb_id = makeword(EB_ID + ef_buf); eb_len = makeword(EB_LEN + ef_buf); - if (eb_len > (ef_len - EB_HEADSIZE)) { - /* discovered some extra field inconsistency! */ + if (eb_len > (ef_len - EB_HEADSIZE)) + { + /* Extra block length exceeds remaining extra field length. */ Trace((stderr, "getZip64Data: block length %u > rest ef_size %u\n", eb_len, ef_len - EB_HEADSIZE)); break; } - if (eb_id == EF_PKSZ64) { + if (eb_id == EF_PKSZ64) + { int offset = EB_HEADSIZE; - if (G.crec.ucsize == 0xffffffff || G.lrec.ucsize == 0xffffffff){ - G.lrec.ucsize = G.crec.ucsize = makeint64(offset + ef_buf); - offset += sizeof(G.crec.ucsize); + if ((G.crec.ucsize == Z64FLGL) || (G.lrec.ucsize == Z64FLGL)) + { + if (offset+ 8 > ef_len) + return PK_ERR; + + G.crec.ucsize = G.lrec.ucsize = makeint64(offset + ef_buf); + offset += 8; } - if (G.crec.csize == 0xffffffff || G.lrec.csize == 0xffffffff){ - G.csize = G.lrec.csize = G.crec.csize = makeint64(offset + ef_buf); - offset += sizeof(G.crec.csize); + + if ((G.crec.csize == Z64FLGL) || (G.lrec.csize == Z64FLGL)) + { + if (offset+ 8 > ef_len) + return PK_ERR; + + G.csize = G.crec.csize = G.lrec.csize = makeint64(offset + ef_buf); + offset += 8; } - if (G.crec.relative_offset_local_header == 0xffffffff){ + + if (G.crec.relative_offset_local_header == Z64FLGL) + { + if (offset+ 8 > ef_len) + return PK_ERR; + G.crec.relative_offset_local_header = makeint64(offset + ef_buf); - offset += sizeof(G.crec.relative_offset_local_header); + offset += 8; } - if (G.crec.disk_number_start == 0xffff){ + + if (G.crec.disk_number_start == Z64FLGS) + { + if (offset+ 4 > ef_len) + return PK_ERR; + G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf); - offset += sizeof(G.crec.disk_number_start); + offset += 4; } +#if 0 + break; /* Expect only one EF_PKSZ64 block. */ +#endif /* 0 */ } - /* Skip this extra field block */ + /* Skip this extra field block. */ ef_buf += (eb_len + EB_HEADSIZE); ef_len -= (eb_len + EB_HEADSIZE); } @@ -2867,10 +2902,13 @@ break; case EF_IZUNIX2: - if (have_new_type_eb == 0) { - flags &= ~0x0ff; /* ignore any previous IZUNIX field */ + if (have_new_type_eb == 0) { /* (< 1) */ have_new_type_eb = 1; } + if (have_new_type_eb <= 1) { + /* Ignore any prior (EF_IZUNIX/EF_PKUNIX) UID/GID. */ + flags &= 0x0ff; + } #ifdef IZ_HAVE_UXUIDGID if (have_new_type_eb > 1) break; /* IZUNIX3 overrides IZUNIX2 e.f. block ! */ @@ -2886,6 +2924,8 @@ /* new 3rd generation Unix ef */ have_new_type_eb = 2; + /* Ignore any prior EF_IZUNIX/EF_PKUNIX/EF_IZUNIX2 UID/GID. */ + flags &= 0x0ff; /* Version 1 byte version of this extra field, currently 1 UIDSize 1 byte Size of UID field @@ -2895,9 +2935,9 @@ */ #ifdef IZ_HAVE_UXUIDGID - if (eb_len >= EB_UX3_MINLEN - && z_uidgid != NULL - && (*((EB_HEADSIZE + 0) + ef_buf) == 1) + if ((eb_len >= EB_UX3_MINLEN) + && (z_uidgid != NULL) + && ((*((EB_HEADSIZE + 0) + ef_buf) == 1))) /* only know about version 1 */ { uch uid_size; @@ -2906,13 +2946,11 @@ uid_size = *((EB_HEADSIZE + 1) + ef_buf); gid_size = *((EB_HEADSIZE + uid_size + 2) + ef_buf); - flags &= ~0x0ff; /* ignore any previous UNIX field */ - if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf, - uid_size, z_uidgid[0]) + uid_size, &z_uidgid[0]) && read_ux3_value((EB_HEADSIZE + uid_size + 3) + ef_buf, - gid_size, z_uidgid[1]) ) + gid_size, &z_uidgid[1]) ) { flags |= EB_UX2_VALID; /* signal success */ } diff -Naur a/process.c.orig b/process.c.orig --- a/process.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ b/process.c.orig 2019-12-02 00:32:11.309743527 +0000 @@ -0,0 +1,3123 @@ +/* + Copyright (c) 1990-2014 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2009-Jan-02 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 +*/ +/*--------------------------------------------------------------------------- + + process.c + + This file contains the top-level routines for processing multiple zipfiles. + + Contains: process_zipfiles() + free_G_buffers() + do_seekable() + file_size() + rec_find() + find_ecrec64() + find_ecrec() + process_zip_cmmnt() + process_cdir_file_hdr() + get_cdir_ent() + process_local_file_hdr() + getZip64Data() + ef_scan_for_izux() + getRISCOSexfield() + + ---------------------------------------------------------------------------*/ + + +#define UNZIP_INTERNAL +#include "unzip.h" +#ifdef WINDLL +# ifdef POCKET_UNZIP +# include "wince/intrface.h" +# else +# include "windll/windll.h" +# endif +#endif +#if defined(DYNALLOC_CRCTAB) || defined(UNICODE_SUPPORT) +# include "crc32.h" +#endif + +static int do_seekable OF((__GPRO__ int lastchance)); +#ifdef DO_SAFECHECK_2GB +# ifdef USE_STRM_INPUT +static zoff_t file_size OF((FILE *file)); +# else +static zoff_t file_size OF((int fh)); +# endif +#endif /* DO_SAFECHECK_2GB */ +static int rec_find OF((__GPRO__ zoff_t, char *, int)); +static int find_ecrec64 OF((__GPRO__ zoff_t searchlen)); +static int find_ecrec OF((__GPRO__ zoff_t searchlen)); +static int process_zip_cmmnt OF((__GPRO)); +static int get_cdir_ent OF((__GPRO)); +#ifdef IZ_HAVE_UXUIDGID +static int read_ux3_value OF((ZCONST uch *dbuf, unsigned uidgid_sz, + ulg *p_uidgid)); +#endif /* IZ_HAVE_UXUIDGID */ + + +static ZCONST char Far CannotAllocateBuffers[] = + "error: cannot allocate unzip buffers\n"; + +#ifdef SFX + static ZCONST char Far CannotFindMyself[] = + "unzipsfx: cannot find myself! [%s]\n"; +# ifdef CHEAP_SFX_AUTORUN + static ZCONST char Far AutorunPrompt[] = + "\nAuto-run command: %s\nExecute this command? [y/n] "; + static ZCONST char Far NotAutoRunning[] = + "Not executing auto-run command."; +# endif + +#else /* !SFX */ + /* process_zipfiles() strings */ +# if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME)) + static ZCONST char Far WarnInvalidTZ[] = + "Warning: TZ environment variable not found, cannot use UTC times!!\n"; +# endif +# if !(defined(UNIX) || defined(AMIGA)) + static ZCONST char Far CannotFindWildcardMatch[] = + "%s: cannot find any matches for wildcard specification \"%s\".\n"; +# endif /* !(UNIX || AMIGA) */ + static ZCONST char Far FilesProcessOK[] = + "%d archive%s successfully processed.\n"; + static ZCONST char Far ArchiveWarning[] = + "%d archive%s had warnings but no fatal errors.\n"; + static ZCONST char Far ArchiveFatalError[] = + "%d archive%s had fatal errors.\n"; + static ZCONST char Far FileHadNoZipfileDir[] = + "%d file%s had no zipfile directory.\n"; + static ZCONST char Far ZipfileWasDir[] = "1 \"zipfile\" was a directory.\n"; + static ZCONST char Far ManyZipfilesWereDir[] = + "%d \"zipfiles\" were directories.\n"; + static ZCONST char Far NoZipfileFound[] = "No zipfiles found.\n"; + + /* do_seekable() strings */ +# ifdef UNIX + static ZCONST char Far CannotFindZipfileDirMsg[] = + "%s: cannot find zipfile directory in one of %s or\n\ + %s%s.zip, and cannot find %s, period.\n"; + static ZCONST char Far CannotFindEitherZipfile[] = + "%s: cannot find or open %s, %s.zip or %s.\n"; +# else /* !UNIX */ + static ZCONST char Far CannotFindZipfileDirMsg[] = + "%s: cannot find zipfile directory in %s,\n\ + %sand cannot find %s, period.\n"; +# ifdef VMS + static ZCONST char Far CannotFindEitherZipfile[] = + "%s: cannot find %s (%s).\n"; +# else /* !VMS */ + static ZCONST char Far CannotFindEitherZipfile[] = + "%s: cannot find either %s or %s.\n"; +# endif /* ?VMS */ +# endif /* ?UNIX */ + extern ZCONST char Far Zipnfo[]; /* in unzip.c */ +#ifndef WINDLL + static ZCONST char Far Unzip[] = "unzip"; +#else + static ZCONST char Far Unzip[] = "UnZip DLL"; +#endif +#ifdef DO_SAFECHECK_2GB + static ZCONST char Far ZipfileTooBig[] = + "Trying to read large file (> 2 GiB) without large file support\n"; +#endif /* DO_SAFECHECK_2GB */ + static ZCONST char Far MaybeExe[] = + "note: %s may be a plain executable, not an archive\n"; + static ZCONST char Far CentDirNotInZipMsg[] = "\n\ + [%s]:\n\ + Zipfile is disk %lu of a multi-disk archive, and this is not the disk on\n\ + which the central zipfile directory begins (disk %lu).\n"; + static ZCONST char Far EndCentDirBogus[] = + "\nwarning [%s]: end-of-central-directory record claims this\n\ + is disk %lu but that the central directory starts on disk %lu; this is a\n\ + contradiction. Attempting to process anyway.\n"; +# ifdef NO_MULTIPART + static ZCONST char Far NoMultiDiskArcSupport[] = + "\nerror [%s]: zipfile is part of multi-disk archive\n\ + (sorry, not yet supported).\n"; + static ZCONST char Far MaybePakBug[] = "warning [%s]:\ + zipfile claims to be 2nd disk of a 2-part archive;\n\ + attempting to process anyway. If no further errors occur, this archive\n\ + was probably created by PAK v2.51 or earlier. This bug was reported to\n\ + NoGate in March 1991 and was supposed to have been fixed by mid-1991; as\n\ + of mid-1992 it still hadn't been. (If further errors do occur, archive\n\ + was probably created by PKZIP 2.04c or later; UnZip does not yet support\n\ + multi-part archives.)\n"; +# else + static ZCONST char Far MaybePakBug[] = "warning [%s]:\ + zipfile claims to be last disk of a multi-part archive;\n\ + attempting to process anyway, assuming all parts have been concatenated\n\ + together in order. Expect \"errors\" and warnings...true multi-part support\ +\n doesn't exist yet (coming soon).\n"; +# endif + static ZCONST char Far ExtraBytesAtStart[] = + "warning [%s]: %s extra byte%s at beginning or within zipfile\n\ + (attempting to process anyway)\n"; +#endif /* ?SFX */ + +#if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO)) + static ZCONST char Far LogInitline[] = "Archive: %s\n"; +#endif + +static ZCONST char Far MissingBytes[] = + "error [%s]: missing %s bytes in zipfile\n\ + (attempting to process anyway)\n"; +static ZCONST char Far NullCentDirOffset[] = + "error [%s]: NULL central directory offset\n\ + (attempting to process anyway)\n"; +static ZCONST char Far ZipfileEmpty[] = "warning [%s]: zipfile is empty\n"; +static ZCONST char Far CentDirStartNotFound[] = + "error [%s]: start of central directory not found;\n\ + zipfile corrupt.\n%s"; +static ZCONST char Far Cent64EndSigSearchErr[] = + "fatal error: read failure while seeking for End-of-centdir-64 signature.\n\ + This zipfile is corrupt.\n"; +static ZCONST char Far Cent64EndSigSearchOff[] = + "error: End-of-centdir-64 signature not where expected (prepended bytes?)\n\ + (attempting to process anyway)\n"; +#ifndef SFX + static ZCONST char Far CentDirTooLong[] = + "error [%s]: reported length of central directory is\n\ + %s bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1\n\ + zipfile?). Compensating...\n"; + static ZCONST char Far CentDirEndSigNotFound[] = "\ + End-of-central-directory signature not found. Either this file is not\n\ + a zipfile, or it constitutes one disk of a multi-part archive. In the\n\ + latter case the central directory and zipfile comment will be found on\n\ + the last disk(s) of this archive.\n"; +#else /* SFX */ + static ZCONST char Far CentDirEndSigNotFound[] = + " End-of-central-directory signature not found.\n"; +#endif /* ?SFX */ +#ifdef TIMESTAMP + static ZCONST char Far ZipTimeStampFailed[] = + "warning: cannot set time for %s\n"; + static ZCONST char Far ZipTimeStampSuccess[] = + "Updated time stamp for %s.\n"; +#endif +static ZCONST char Far ZipfileCommTrunc1[] = + "\ncaution: zipfile comment truncated\n"; +#ifndef NO_ZIPINFO + static ZCONST char Far NoZipfileComment[] = + "There is no zipfile comment.\n"; + static ZCONST char Far ZipfileCommentDesc[] = + "The zipfile comment is %u bytes long and contains the following text:\n"; + static ZCONST char Far ZipfileCommBegin[] = + "======================== zipfile comment begins\ + ==========================\n"; + static ZCONST char Far ZipfileCommEnd[] = + "========================= zipfile comment ends\ + ===========================\n"; + static ZCONST char Far ZipfileCommTrunc2[] = + "\n The zipfile comment is truncated.\n"; +#endif /* !NO_ZIPINFO */ +#ifdef UNICODE_SUPPORT + static ZCONST char Far UnicodeVersionError[] = + "\nwarning: Unicode Path version > 1\n"; + static ZCONST char Far UnicodeMismatchError[] = + "\nwarning: Unicode Path checksum invalid\n"; +#endif + + + + +/*******************************/ +/* Function process_zipfiles() */ +/*******************************/ + +int process_zipfiles(__G) /* return PK-type error code */ + __GDEF +{ +#ifndef SFX + char *lastzipfn = (char *)NULL; + int NumWinFiles, NumLoseFiles, NumWarnFiles; + int NumMissDirs, NumMissFiles; +#endif + int error=0, error_in_archive=0; + + +/*--------------------------------------------------------------------------- + Start by allocating buffers and (re)constructing the various PK signature + strings. + ---------------------------------------------------------------------------*/ + + G.inbuf = (uch *)malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */ + G.outbuf = (uch *)malloc(OUTBUFSIZ + 1); /* 1 extra for string term. */ + + if ((G.inbuf == (uch *)NULL) || (G.outbuf == (uch *)NULL)) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(CannotAllocateBuffers))); + return(PK_MEM); + } + G.hold = G.inbuf + INBUFSIZ; /* to check for boundary-spanning sigs */ +#ifndef VMS /* VMS uses its own buffer scheme for textmode flush(). */ +#ifdef SMALL_MEM + G.outbuf2 = G.outbuf+RAWBUFSIZ; /* never changes */ +#endif +#endif /* !VMS */ + +#if 0 /* CRC_32_TAB has been NULLified by CONSTRUCTGLOBALS !!!! */ + /* allocate the CRC table later when we know we can read zipfile data */ + CRC_32_TAB = NULL; +#endif /* 0 */ + + /* finish up initialization of magic signature strings */ + local_hdr_sig[0] /* = extd_local_sig[0] */ = /* ASCII 'P', */ + central_hdr_sig[0] = end_central_sig[0] = /* not EBCDIC */ + end_centloc64_sig[0] = end_central64_sig[0] = 0x50; + + local_hdr_sig[1] /* = extd_local_sig[1] */ = /* ASCII 'K', */ + central_hdr_sig[1] = end_central_sig[1] = /* not EBCDIC */ + end_centloc64_sig[1] = end_central64_sig[1] = 0x4B; + +/*--------------------------------------------------------------------------- + Make sure timezone info is set correctly; localtime() returns GMT on some + OSes (e.g., Solaris 2.x) if this isn't done first. The ifdefs around + tzset() were initially copied from dos_to_unix_time() in fileio.c. They + may still be too strict; any listed OS that supplies tzset(), regardless + of whether the function does anything, should be removed from the ifdefs. + ---------------------------------------------------------------------------*/ + +#if (defined(WIN32) && defined(USE_EF_UT_TIME)) + /* For the Win32 environment, we may have to "prepare" the environment + prior to the tzset() call, to work around tzset() implementation bugs. + */ + iz_w32_prepareTZenv(); +#endif + +#if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME)) +# ifndef VALID_TIMEZONE +# define VALID_TIMEZONE(tmp) \ + (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0')) +# endif + { + char *p; + G.tz_is_valid = VALID_TIMEZONE(p); +# ifndef SFX + if (!G.tz_is_valid) { + Info(slide, 0x401, ((char *)slide, LoadFarString(WarnInvalidTZ))); + error_in_archive = error = PK_WARN; + } +# endif /* !SFX */ + } +#endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */ + +/* For systems that do not have tzset() but supply this function using another + name (_tzset() or something similar), an appropiate "#define tzset ..." + should be added to the system specifc configuration section. */ +#if (!defined(T20_VMS) && !defined(MACOS) && !defined(RISCOS) && !defined(QDOS)) +#if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM)) + tzset(); +#endif +#endif + +/* Initialize UnZip's built-in pseudo hard-coded "ISO <--> OEM" translation, + depending on the detected codepage setup. */ +#ifdef NEED_ISO_OEM_INIT + prepare_ISO_OEM_translat(__G); +#endif + +/*--------------------------------------------------------------------------- + Initialize the internal flag holding the mode of processing "overwrite + existing file" cases. We do not use the calling interface flags directly + because the overwrite mode may be changed by user interaction while + processing archive files. Such a change should not affect the option + settings as passed through the DLL calling interface. + In case of conflicting options, the 'safer' flag uO.overwrite_none takes + precedence. + ---------------------------------------------------------------------------*/ + G.overwrite_mode = (uO.overwrite_none ? OVERWRT_NEVER : + (uO.overwrite_all ? OVERWRT_ALWAYS : OVERWRT_QUERY)); + +/*--------------------------------------------------------------------------- + Match (possible) wildcard zipfile specification with existing files and + attempt to process each. If no hits, try again after appending ".zip" + suffix. If still no luck, give up. + ---------------------------------------------------------------------------*/ + +#ifdef SFX + if ((error = do_seekable(__G__ 0)) == PK_NOZIP) { +#ifdef EXE_EXTENSION + int len=strlen(G.argv0); + + /* append .exe if appropriate; also .sfx? */ + if ( (G.zipfn = (char *)malloc(len+sizeof(EXE_EXTENSION))) != + (char *)NULL ) { + strcpy(G.zipfn, G.argv0); + strcpy(G.zipfn+len, EXE_EXTENSION); + error = do_seekable(__G__ 0); + free(G.zipfn); + G.zipfn = G.argv0; /* for "cannot find myself" message only */ + } +#endif /* EXE_EXTENSION */ +#ifdef WIN32 + G.zipfn = G.argv0; /* for "cannot find myself" message only */ +#endif + } + if (error) { + if (error == IZ_DIR) + error_in_archive = PK_NOZIP; + else + error_in_archive = error; + if (error == PK_NOZIP) + Info(slide, 1, ((char *)slide, LoadFarString(CannotFindMyself), + G.zipfn)); + } +#ifdef CHEAP_SFX_AUTORUN + if (G.autorun_command[0] && !uO.qflag) { /* NO autorun without prompt! */ + Info(slide, 0x81, ((char *)slide, LoadFarString(AutorunPrompt), + FnFilter1(G.autorun_command))); + if (fgets(G.answerbuf, 9, stdin) != (char *)NULL + && toupper(*G.answerbuf) == 'Y') + system(G.autorun_command); + else + Info(slide, 1, ((char *)slide, LoadFarString(NotAutoRunning))); + } +#endif /* CHEAP_SFX_AUTORUN */ + +#else /* !SFX */ + NumWinFiles = NumLoseFiles = NumWarnFiles = 0; + NumMissDirs = NumMissFiles = 0; + + while ((G.zipfn = do_wild(__G__ G.wildzipfn)) != (char *)NULL) { + Trace((stderr, "do_wild( %s ) returns %s\n", G.wildzipfn, G.zipfn)); + + lastzipfn = G.zipfn; + + /* print a blank line between the output of different zipfiles */ + if (!uO.qflag && error != PK_NOZIP && error != IZ_DIR +#ifdef TIMESTAMP + && (!uO.T_flag || uO.zipinfo_mode) +#endif + && (NumWinFiles+NumLoseFiles+NumWarnFiles+NumMissFiles) > 0) + (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); + + if ((error = do_seekable(__G__ 0)) == PK_WARN) + ++NumWarnFiles; + else if (error == IZ_DIR) + ++NumMissDirs; + else if (error == PK_NOZIP) + ++NumMissFiles; + else if (error != PK_OK) + ++NumLoseFiles; + else + ++NumWinFiles; + + Trace((stderr, "do_seekable(0) returns %d\n", error)); + if (error != IZ_DIR && error > error_in_archive) + error_in_archive = error; +#ifdef WINDLL + if (error == IZ_CTRLC) { + free_G_buffers(__G); + return error; + } +#endif + + } /* end while-loop (wildcard zipfiles) */ + + if ((NumWinFiles + NumWarnFiles + NumLoseFiles) == 0 && + (NumMissDirs + NumMissFiles) == 1 && lastzipfn != (char *)NULL) + { +#if (!defined(UNIX) && !defined(AMIGA)) /* filenames with wildcard characters */ + if (iswild(G.wildzipfn)) { + if (iswild(lastzipfn)) { + NumMissDirs = NumMissFiles = 0; + error_in_archive = PK_COOL; + if (uO.qflag < 3) + Info(slide, 0x401, ((char *)slide, + LoadFarString(CannotFindWildcardMatch), + LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), + G.wildzipfn)); + } + } else +#endif + { +#ifndef VMS + /* 2004-11-24 SMS. + * VMS has already tried a default file type of ".zip" in + * do_wild(), so adding ZSUFX here only causes confusion by + * corrupting some valid (though nonexistent) file names. + * Complaining below about "fred;4.zip" is unlikely to be + * helpful to the victim. + */ + /* 2005-08-14 Chr. Spieler + * Although we already "know" the failure result, we call + * do_seekable() again with the same zipfile name (and the + * lastchance flag set), just to trigger the error report... + */ +#if defined(UNIX) || defined(QDOS) + char *p = +#endif + strcpy(lastzipfn + strlen(lastzipfn), ZSUFX); +#endif /* !VMS */ + + G.zipfn = lastzipfn; + + NumMissDirs = NumMissFiles = 0; + error_in_archive = PK_COOL; + +#if defined(UNIX) || defined(QDOS) + /* only Unix has case-sensitive filesystems */ + /* Well FlexOS (sometimes) also has them, but support is per media */ + /* and a pig to code for, so treat as case insensitive for now */ + /* we do this under QDOS to check for .zip as well as _zip */ + if ((error = do_seekable(__G__ 0)) == PK_NOZIP || error == IZ_DIR) { + if (error == IZ_DIR) + ++NumMissDirs; + strcpy(p, ALT_ZSUFX); + error = do_seekable(__G__ 1); + } +#else + error = do_seekable(__G__ 1); +#endif + Trace((stderr, "do_seekable(1) returns %d\n", error)); + switch (error) { + case PK_WARN: + ++NumWarnFiles; + break; + case IZ_DIR: + ++NumMissDirs; + error = PK_NOZIP; + break; + case PK_NOZIP: + /* increment again => bug: + "1 file had no zipfile directory." */ + /* ++NumMissFiles */ ; + break; + default: + if (error) + ++NumLoseFiles; + else + ++NumWinFiles; + break; + } + + if (error > error_in_archive) + error_in_archive = error; +#ifdef WINDLL + if (error == IZ_CTRLC) { + free_G_buffers(__G); + return error; + } +#endif + } + } +#endif /* ?SFX */ + +/*--------------------------------------------------------------------------- + Print summary of all zipfiles, assuming zipfile spec was a wildcard (no + need for a summary if just one zipfile). + ---------------------------------------------------------------------------*/ + +#ifndef SFX + if (iswild(G.wildzipfn) && uO.qflag < 3 +#ifdef TIMESTAMP + && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag > 1) +#endif + ) + { + if ((NumMissFiles + NumLoseFiles + NumWarnFiles > 0 || NumWinFiles != 1) +#ifdef TIMESTAMP + && !(uO.T_flag && !uO.zipinfo_mode && uO.qflag) +#endif + && !(uO.tflag && uO.qflag > 1)) + (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0x401); + if ((NumWinFiles > 1) || + (NumWinFiles == 1 && + NumMissDirs + NumMissFiles + NumLoseFiles + NumWarnFiles > 0)) + Info(slide, 0x401, ((char *)slide, LoadFarString(FilesProcessOK), + NumWinFiles, (NumWinFiles == 1)? " was" : "s were")); + if (NumWarnFiles > 0) + Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveWarning), + NumWarnFiles, (NumWarnFiles == 1)? "" : "s")); + if (NumLoseFiles > 0) + Info(slide, 0x401, ((char *)slide, LoadFarString(ArchiveFatalError), + NumLoseFiles, (NumLoseFiles == 1)? "" : "s")); + if (NumMissFiles > 0) + Info(slide, 0x401, ((char *)slide, + LoadFarString(FileHadNoZipfileDir), NumMissFiles, + (NumMissFiles == 1)? "" : "s")); + if (NumMissDirs == 1) + Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileWasDir))); + else if (NumMissDirs > 0) + Info(slide, 0x401, ((char *)slide, + LoadFarString(ManyZipfilesWereDir), NumMissDirs)); + if (NumWinFiles + NumLoseFiles + NumWarnFiles == 0) + Info(slide, 0x401, ((char *)slide, LoadFarString(NoZipfileFound))); + } +#endif /* !SFX */ + + /* free allocated memory */ + free_G_buffers(__G); + + return error_in_archive; + +} /* end function process_zipfiles() */ + + + + + +/*****************************/ +/* Function free_G_buffers() */ +/*****************************/ + +void free_G_buffers(__G) /* releases all memory allocated in global vars */ + __GDEF +{ +#ifndef SFX + unsigned i; +#endif + +#ifdef SYSTEM_SPECIFIC_DTOR + SYSTEM_SPECIFIC_DTOR(__G); +#endif + + inflate_free(__G); + checkdir(__G__ (char *)NULL, END); + +#ifdef DYNALLOC_CRCTAB + if (CRC_32_TAB) { + free_crc_table(); + CRC_32_TAB = NULL; + } +#endif + + if (G.key != (char *)NULL) { + free(G.key); + G.key = (char *)NULL; + } + + if (G.extra_field != (uch *)NULL) { + free(G.extra_field); + G.extra_field = (uch *)NULL; + } + +#if (!defined(VMS) && !defined(SMALL_MEM)) + /* VMS uses its own buffer scheme for textmode flush() */ + if (G.outbuf2) { + free(G.outbuf2); /* malloc'd ONLY if unshrink and -a */ + G.outbuf2 = (uch *)NULL; + } +#endif + + if (G.outbuf) + free(G.outbuf); + if (G.inbuf) + free(G.inbuf); + G.inbuf = G.outbuf = (uch *)NULL; + +#ifdef UNICODE_SUPPORT + if (G.filename_full) { + free(G.filename_full); + G.filename_full = (char *)NULL; + G.fnfull_bufsize = 0; + } +#endif /* UNICODE_SUPPORT */ + +#ifndef SFX + for (i = 0; i < DIR_BLKSIZ; i++) { + if (G.info[i].cfilname != (char Far *)NULL) { + zffree(G.info[i].cfilname); + G.info[i].cfilname = (char Far *)NULL; + } + } +#endif + +#ifdef MALLOC_WORK + if (G.area.Slide) { + free(G.area.Slide); + G.area.Slide = (uch *)NULL; + } +#endif + +} /* end function free_G_buffers() */ + + + + + +/**************************/ +/* Function do_seekable() */ +/**************************/ + +static int do_seekable(__G__ lastchance) /* return PK-type error code */ + __GDEF + int lastchance; +{ +#ifndef SFX + /* static int no_ecrec = FALSE; SKM: moved to globals.h */ + int maybe_exe=FALSE; + int too_weird_to_continue=FALSE; +#ifdef TIMESTAMP + time_t uxstamp; + ulg nmember = 0L; +#endif +#endif + int error=0, error_in_archive; + + +/*--------------------------------------------------------------------------- + Open the zipfile for reading in BINARY mode to prevent CR/LF translation, + which would corrupt the bit streams. + ---------------------------------------------------------------------------*/ + + if (SSTAT(G.zipfn, &G.statbuf) || +#ifdef THEOS + (error = S_ISLIB(G.statbuf.st_mode)) != 0 || +#endif + (error = S_ISDIR(G.statbuf.st_mode)) != 0) + { +#ifndef SFX + if (lastchance && (uO.qflag < 3)) { +#if defined(UNIX) || defined(QDOS) + if (G.no_ecrec) + Info(slide, 1, ((char *)slide, + LoadFarString(CannotFindZipfileDirMsg), + LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), + G.wildzipfn, uO.zipinfo_mode? " " : "", G.wildzipfn, + G.zipfn)); + else + Info(slide, 1, ((char *)slide, + LoadFarString(CannotFindEitherZipfile), + LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), + G.wildzipfn, G.wildzipfn, G.zipfn)); +#else /* !(UNIX || QDOS) */ + if (G.no_ecrec) + Info(slide, 0x401, ((char *)slide, + LoadFarString(CannotFindZipfileDirMsg), + LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), + G.wildzipfn, uO.zipinfo_mode? " " : "", G.zipfn)); + else +#ifdef VMS + Info(slide, 0x401, ((char *)slide, + LoadFarString(CannotFindEitherZipfile), + LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), + G.wildzipfn, + (*G.zipfn ? G.zipfn : vms_msg_text()))); +#else /* !VMS */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(CannotFindEitherZipfile), + LoadFarStringSmall((uO.zipinfo_mode ? Zipnfo : Unzip)), + G.wildzipfn, G.zipfn)); +#endif /* ?VMS */ +#endif /* ?(UNIX || QDOS) */ + } +#endif /* !SFX */ + return error? IZ_DIR : PK_NOZIP; + } + G.ziplen = G.statbuf.st_size; + +#ifndef SFX +#if defined(UNIX) || defined(DOS_OS2_W32) || defined(THEOS) + if (G.statbuf.st_mode & S_IEXEC) /* no extension on Unix exes: might */ + maybe_exe = TRUE; /* find unzip, not unzip.zip; etc. */ +#endif +#endif /* !SFX */ + +#ifdef VMS + if (check_format(__G)) /* check for variable-length format */ + return PK_ERR; +#endif + + if (open_input_file(__G)) /* this should never happen, given */ + return PK_NOZIP; /* the stat() test above, but... */ + +#ifdef DO_SAFECHECK_2GB + /* Need more care: Do not trust the size returned by stat() but + determine it by reading beyond the end of the file. */ + G.ziplen = file_size(G.zipfd); + + if (G.ziplen == EOF) { + Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileTooBig))); + /* + printf( +" We need a better error message for: 64-bit file, 32-bit program.\n"); + */ + CLOSE_INFILE(); + return IZ_ERRBF; + } +#endif /* DO_SAFECHECK_2GB */ + +/*--------------------------------------------------------------------------- + Find and process the end-of-central-directory header. UnZip need only + check last 65557 bytes of zipfile: comment may be up to 65535, end-of- + central-directory record is 18 bytes, and signature itself is 4 bytes; + add some to allow for appended garbage. Since ZipInfo is often used as + a debugging tool, search the whole zipfile if zipinfo_mode is true. + ---------------------------------------------------------------------------*/ + + G.cur_zipfile_bufstart = 0; + G.inptr = G.inbuf; + +#if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO)) +# if (!defined(WINDLL) && !defined(SFX)) + if ( (!uO.zipinfo_mode && !uO.qflag +# ifdef TIMESTAMP + && !uO.T_flag +# endif + ) +# ifndef NO_ZIPINFO + || (uO.zipinfo_mode && uO.hflag) +# endif + ) +# else /* not (!WINDLL && !SFX) ==> !NO_ZIPINFO !! */ + if (uO.zipinfo_mode && uO.hflag) +# endif /* if..else..: (!WINDLL && !SFX) */ +# ifdef WIN32 /* Win32 console may require codepage conversion for G.zipfn */ + Info(slide, 0, ((char *)slide, LoadFarString(LogInitline), + FnFilter1(G.zipfn))); +# else + Info(slide, 0, ((char *)slide, LoadFarString(LogInitline), G.zipfn)); +# endif +#endif /* (!WINDLL && !SFX) || !NO_ZIPINFO */ + + if ( (error_in_archive = find_ecrec(__G__ +#ifndef NO_ZIPINFO + uO.zipinfo_mode ? G.ziplen : +#endif + MIN(G.ziplen, 66000L))) + > PK_WARN ) + { + CLOSE_INFILE(); + +#ifdef SFX + ++lastchance; /* avoid picky compiler warnings */ + return error_in_archive; +#else + if (maybe_exe) + Info(slide, 0x401, ((char *)slide, LoadFarString(MaybeExe), + G.zipfn)); + if (lastchance) + return error_in_archive; + else { + G.no_ecrec = TRUE; /* assume we found wrong file: e.g., */ + return PK_NOZIP; /* unzip instead of unzip.zip */ + } +#endif /* ?SFX */ + } + + if ((uO.zflag > 0) && !uO.zipinfo_mode) { /* unzip: zflag = comment ONLY */ + CLOSE_INFILE(); + return error_in_archive; + } + +/*--------------------------------------------------------------------------- + Test the end-of-central-directory info for incompatibilities (multi-disk + archives) or inconsistencies (missing or extra bytes in zipfile). + ---------------------------------------------------------------------------*/ + +#ifdef NO_MULTIPART + error = !uO.zipinfo_mode && (G.ecrec.number_this_disk == 1) && + (G.ecrec.num_disk_start_cdir == 1); +#else + error = !uO.zipinfo_mode && (G.ecrec.number_this_disk != 0); +#endif + +#ifndef SFX + if (uO.zipinfo_mode && + G.ecrec.number_this_disk != G.ecrec.num_disk_start_cdir) + { + if (G.ecrec.number_this_disk > G.ecrec.num_disk_start_cdir) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(CentDirNotInZipMsg), G.zipfn, + (ulg)G.ecrec.number_this_disk, + (ulg)G.ecrec.num_disk_start_cdir)); + error_in_archive = PK_FIND; + too_weird_to_continue = TRUE; + } else { + Info(slide, 0x401, ((char *)slide, + LoadFarString(EndCentDirBogus), G.zipfn, + (ulg)G.ecrec.number_this_disk, + (ulg)G.ecrec.num_disk_start_cdir)); + error_in_archive = PK_WARN; + } +#ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */ + } else if (!uO.zipinfo_mode && !error && G.ecrec.number_this_disk != 0) { + Info(slide, 0x401, ((char *)slide, LoadFarString(NoMultiDiskArcSupport), + G.zipfn)); + error_in_archive = PK_FIND; + too_weird_to_continue = TRUE; +#endif + } + + if (!too_weird_to_continue) { /* (relatively) normal zipfile: go for it */ + if (error) { + Info(slide, 0x401, ((char *)slide, LoadFarString(MaybePakBug), + G.zipfn)); + error_in_archive = PK_WARN; + } +#endif /* !SFX */ + if ((G.extra_bytes = G.real_ecrec_offset-G.expect_ecrec_offset) < + (zoff_t)0) + { + Info(slide, 0x401, ((char *)slide, LoadFarString(MissingBytes), + G.zipfn, FmZofft((-G.extra_bytes), NULL, NULL))); + error_in_archive = PK_ERR; + } else if (G.extra_bytes > 0) { + if ((G.ecrec.offset_start_central_directory == 0) && + (G.ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */ + { + Info(slide, 0x401, ((char *)slide, + LoadFarString(NullCentDirOffset), G.zipfn)); + G.ecrec.offset_start_central_directory = G.extra_bytes; + G.extra_bytes = 0; + error_in_archive = PK_ERR; + } +#ifndef SFX + else { + Info(slide, 0x401, ((char *)slide, + LoadFarString(ExtraBytesAtStart), G.zipfn, + FmZofft(G.extra_bytes, NULL, NULL), + (G.extra_bytes == 1)? "":"s")); + error_in_archive = PK_WARN; + } +#endif /* !SFX */ + } + + /*----------------------------------------------------------------------- + Check for empty zipfile and exit now if so. + -----------------------------------------------------------------------*/ + + if (G.expect_ecrec_offset==0L && G.ecrec.size_central_directory==0) { + if (uO.zipinfo_mode) + Info(slide, 0, ((char *)slide, "%sEmpty zipfile.\n", + uO.lflag>9? "\n " : "")); + else + Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileEmpty), + G.zipfn)); + CLOSE_INFILE(); + return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN; + } + + /*----------------------------------------------------------------------- + Compensate for missing or extra bytes, and seek to where the start + of central directory should be. If header not found, uncompensate + and try again (necessary for at least some Atari archives created + with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1). + -----------------------------------------------------------------------*/ + + error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); + if (error == PK_BADERR) { + CLOSE_INFILE(); + return PK_BADERR; + } +#ifdef OLD_SEEK_TEST + if (error != PK_OK || readbuf(__G__ G.sig, 4) == 0) { + CLOSE_INFILE(); + return PK_ERR; /* file may be locked, or possibly disk error(?) */ + } + if (memcmp(G.sig, central_hdr_sig, 4)) +#else + if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) || + memcmp(G.sig, central_hdr_sig, 4)) +#endif + { +#ifndef SFX + zoff_t tmp = G.extra_bytes; +#endif + + G.extra_bytes = 0; + error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); + if ((error != PK_OK) || (readbuf(__G__ G.sig, 4) == 0) || + memcmp(G.sig, central_hdr_sig, 4)) + { + if (error != PK_BADERR) + Info(slide, 0x401, ((char *)slide, + LoadFarString(CentDirStartNotFound), G.zipfn, + LoadFarStringSmall(ReportMsg))); + CLOSE_INFILE(); + return (error != PK_OK ? error : PK_BADERR); + } +#ifndef SFX + Info(slide, 0x401, ((char *)slide, LoadFarString(CentDirTooLong), + G.zipfn, FmZofft((-tmp), NULL, NULL))); +#endif + error_in_archive = PK_ERR; + } + + /*----------------------------------------------------------------------- + Seek to the start of the central directory one last time, since we + have just read the first entry's signature bytes; then list, extract + or test member files as instructed, and close the zipfile. + -----------------------------------------------------------------------*/ + + error = seek_zipf(__G__ G.ecrec.offset_start_central_directory); + if (error != PK_OK) { + CLOSE_INFILE(); + return error; + } + + Trace((stderr, "about to extract/list files (error = %d)\n", + error_in_archive)); + +#ifdef DLL + /* G.fValidate is used only to look at an archive to see if + it appears to be a valid archive. There is no interest + in what the archive contains, nor in validating that the + entries in the archive are in good condition. This is + currently used only in the Windows DLLs for purposes of + checking archives within an archive to determine whether + or not to display the inner archives. + */ + if (!G.fValidate) +#endif + { +#ifndef NO_ZIPINFO + if (uO.zipinfo_mode) + error = zipinfo(__G); /* ZIPINFO 'EM */ + else +#endif +#ifndef SFX +#ifdef TIMESTAMP + if (uO.T_flag) + error = get_time_stamp(__G__ &uxstamp, &nmember); + else +#endif + if (uO.vflag && !uO.tflag && !uO.cflag) + error = list_files(__G); /* LIST 'EM */ + else +#endif /* !SFX */ + error = extract_or_test_files(__G); /* EXTRACT OR TEST 'EM */ + + Trace((stderr, "done with extract/list files (error = %d)\n", + error)); + } + + if (error > error_in_archive) /* don't overwrite stronger error */ + error_in_archive = error; /* with (for example) a warning */ +#ifndef SFX + } /* end if (!too_weird_to_continue) */ +#endif + + CLOSE_INFILE(); + +#ifdef TIMESTAMP + if (uO.T_flag && !uO.zipinfo_mode && (nmember > 0L)) { +# ifdef WIN32 + if (stamp_file(__G__ G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */ +# else + if (stamp_file(G.zipfn, uxstamp)) { /* TIME-STAMP 'EM */ +# endif + if (uO.qflag < 3) + Info(slide, 0x201, ((char *)slide, + LoadFarString(ZipTimeStampFailed), G.zipfn)); + if (error_in_archive < PK_WARN) + error_in_archive = PK_WARN; + } else { + if (!uO.qflag) + Info(slide, 0, ((char *)slide, + LoadFarString(ZipTimeStampSuccess), G.zipfn)); + } + } +#endif + return error_in_archive; + +} /* end function do_seekable() */ + + + + +#ifdef DO_SAFECHECK_2GB +/************************/ +/* Function file_size() */ +/************************/ +/* File size determination which does not mislead for large files in a + small-file program. Probably should be somewhere else. + The file has to be opened previously +*/ +#ifdef USE_STRM_INPUT +static zoff_t file_size(file) + FILE *file; +{ + int sts; + size_t siz; +#else /* !USE_STRM_INPUT */ +static zoff_t file_size(fh) + int fh; +{ + int siz; +#endif /* ?USE_STRM_INPUT */ + zoff_t ofs; + char waste[4]; + +#ifdef USE_STRM_INPUT + /* Seek to actual EOF. */ + sts = zfseeko(file, 0, SEEK_END); + if (sts != 0) { + /* fseeko() failed. (Unlikely.) */ + ofs = EOF; + } else { + /* Get apparent offset at EOF. */ + ofs = zftello(file); + if (ofs < 0) { + /* Offset negative (overflow). File too big. */ + ofs = EOF; + } else { + /* Seek to apparent EOF offset. + Won't be at actual EOF if offset was truncated. + */ + sts = zfseeko(file, ofs, SEEK_SET); + if (sts != 0) { + /* fseeko() failed. (Unlikely.) */ + ofs = EOF; + } else { + /* Read a byte at apparent EOF. Should set EOF flag. */ + siz = fread(waste, 1, 1, file); + if (feof(file) == 0) { + /* Not at EOF, but should be. File too big. */ + ofs = EOF; + } + } + } + } +#else /* !USE_STRM_INPUT */ + /* Seek to actual EOF. */ + ofs = zlseek(fh, 0, SEEK_END); + if (ofs == (zoff_t) -1) { + /* zlseek() failed. (Unlikely.) */ + ofs = EOF; + } else if (ofs < 0) { + /* Offset negative (overflow). File too big. */ + ofs = EOF; + } else { + /* Seek to apparent EOF offset. + Won't be at actual EOF if offset was truncated. + */ + ofs = zlseek(fh, ofs, SEEK_SET); + if (ofs == (zoff_t) -1) { + /* zlseek() failed. (Unlikely.) */ + ofs = EOF; + } else { + /* Read a byte at apparent EOF. Should set EOF flag. */ + siz = read(fh, waste, 1); + if (siz != 0) { + /* Not at EOF, but should be. File too big. */ + ofs = EOF; + } + } + } +#endif /* ?USE_STRM_INPUT */ + return ofs; +} /* end function file_size() */ +#endif /* DO_SAFECHECK_2GB */ + + + + +/***********************/ +/* Function rec_find() */ +/***********************/ + +static int rec_find(__G__ searchlen, signature, rec_size) + /* return 0 when rec found, 1 when not found, 2 in case of read error */ + __GDEF + zoff_t searchlen; + char* signature; + int rec_size; +{ + int i, numblks, found=FALSE; + zoff_t tail_len; + +/*--------------------------------------------------------------------------- + Zipfile is longer than INBUFSIZ: may need to loop. Start with short + block at end of zipfile (if not TOO short). + ---------------------------------------------------------------------------*/ + + if ((tail_len = G.ziplen % INBUFSIZ) > rec_size) { +#ifdef USE_STRM_INPUT + zfseeko(G.zipfd, G.ziplen-tail_len, SEEK_SET); + G.cur_zipfile_bufstart = zftello(G.zipfd); +#else /* !USE_STRM_INPUT */ + G.cur_zipfile_bufstart = zlseek(G.zipfd, G.ziplen-tail_len, SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + if ((G.incnt = read(G.zipfd, (char *)G.inbuf, + (unsigned int)tail_len)) != (int)tail_len) + return 2; /* it's expedient... */ + + /* 'P' must be at least (rec_size+4) bytes from end of zipfile */ + for (G.inptr = G.inbuf+(int)tail_len-(rec_size+4); + G.inptr >= G.inbuf; + --G.inptr) { + if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ + !memcmp((char *)G.inptr, signature, 4) ) { + G.incnt -= (int)(G.inptr - G.inbuf); + found = TRUE; + break; + } + } + /* sig may span block boundary: */ + memcpy((char *)G.hold, (char *)G.inbuf, 3); + } else + G.cur_zipfile_bufstart = G.ziplen - tail_len; + +/*----------------------------------------------------------------------- + Loop through blocks of zipfile data, starting at the end and going + toward the beginning. In general, need not check whole zipfile for + signature, but may want to do so if testing. + -----------------------------------------------------------------------*/ + + numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ); + /* ==amount= ==done== ==rounding== =blksiz= */ + + for (i = 1; !found && (i <= numblks); ++i) { + G.cur_zipfile_bufstart -= INBUFSIZ; +#ifdef USE_STRM_INPUT + zfseeko(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET); +#else /* !USE_STRM_INPUT */ + zlseek(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + if ((G.incnt = read(G.zipfd,(char *)G.inbuf,INBUFSIZ)) + != INBUFSIZ) + return 2; /* read error is fatal failure */ + + for (G.inptr = G.inbuf+INBUFSIZ-1; G.inptr >= G.inbuf; --G.inptr) + if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ + !memcmp((char *)G.inptr, signature, 4) ) { + G.incnt -= (int)(G.inptr - G.inbuf); + found = TRUE; + break; + } + /* sig may span block boundary: */ + memcpy((char *)G.hold, (char *)G.inbuf, 3); + } + return (found ? 0 : 1); +} /* end function rec_find() */ + + + + +#if 0 +/********************************/ +/* Function check_ecrec_zip64() */ +/********************************/ + +static int check_ecrec_zip64(__G) + __GDEF +{ + return G.ecrec.offset_start_central_directory == 0xFFFFFFFFL + || G.ecrec.size_central_directory == 0xFFFFFFFFL + || G.ecrec.total_entries_central_dir == 0xFFFF + || G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF + || G.ecrec.num_disk_start_cdir == 0xFFFF + || G.ecrec.number_this_disk == 0xFFFF; +} /* end function check_ecrec_zip64() */ +#endif /* never */ + + + +/***************************/ +/* Function find_ecrec64() */ +/***************************/ + +static int find_ecrec64(__G__ searchlen) /* return PK-class error */ + __GDEF + zoff_t searchlen; +{ + ec_byte_rec64 byterec; /* buf for ecrec64 */ + ec_byte_loc64 byterecL; /* buf for ecrec64 locator */ + zoff_t ecloc64_start_offset; /* start offset of ecrec64 locator */ + zusz_t ecrec64_start_offset; /* start offset of ecrec64 */ + zuvl_t ecrec64_start_disk; /* start disk of ecrec64 */ + zuvl_t ecloc64_total_disks; /* total disks */ + zuvl_t ecrec64_disk_cdstart; /* disk number of central dir start */ + zucn_t ecrec64_this_entries; /* entries on disk with ecrec64 */ + zucn_t ecrec64_tot_entries; /* total number of entries */ + zusz_t ecrec64_cdirsize; /* length of central dir */ + zusz_t ecrec64_offs_cdstart; /* offset of central dir start */ + + /* First, find the ecrec64 locator. By definition, this must be before + ecrec with nothing in between. We back up the size of the ecrec64 + locator and check. */ + + ecloc64_start_offset = G.real_ecrec_offset - (ECLOC64_SIZE+4); + if (ecloc64_start_offset < 0) + /* Seeking would go past beginning, so probably empty archive */ + return PK_COOL; + +#ifdef USE_STRM_INPUT + zfseeko(G.zipfd, ecloc64_start_offset, SEEK_SET); + G.cur_zipfile_bufstart = zftello(G.zipfd); +#else /* !USE_STRM_INPUT */ + G.cur_zipfile_bufstart = zlseek(G.zipfd, ecloc64_start_offset, SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + + if ((G.incnt = read(G.zipfd, (char *)byterecL, ECLOC64_SIZE+4)) + != (ECLOC64_SIZE+4)) { + if (uO.qflag || uO.zipinfo_mode) + Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); + Info(slide, 0x401, ((char *)slide, + LoadFarString(Cent64EndSigSearchErr))); + return PK_ERR; + } + + if (memcmp((char *)byterecL, end_centloc64_sig, 4) ) { + /* not found */ + return PK_COOL; + } + + /* Read the locator. */ + ecrec64_start_disk = (zuvl_t)makelong(&byterecL[NUM_DISK_START_EOCDR64]); + ecrec64_start_offset = (zusz_t)makeint64(&byterecL[OFFSET_START_EOCDR64]); + ecloc64_total_disks = (zuvl_t)makelong(&byterecL[NUM_THIS_DISK_LOC64]); + + /* Check for consistency */ +#ifdef TEST + fprintf(stdout,"\nnumber of disks (ECR) %u, (ECLOC64) %lu\n", + G.ecrec.number_this_disk, ecloc64_total_disks); fflush(stdout); +#endif + if ((G.ecrec.number_this_disk != 0xFFFF) && + (G.ecrec.number_this_disk != ecloc64_total_disks - 1)) { + /* Note: For some unknown reason, the developers at PKWARE decided to + store the "zip64 total disks" value as a counter starting from 1, + whereas all other "split/span volume" related fields use 0-based + volume numbers. Sigh... */ + /* When the total number of disks as found in the traditional ecrec + is not 0xFFFF, the disk numbers in ecrec and ecloc64 must match. + When this is not the case, the found ecrec64 locator cannot be valid. + -> This is not a Zip64 archive. + */ + Trace((stderr, + "\ninvalid ECLOC64, differing disk# (ECR %u, ECL64 %lu)\n", + G.ecrec.number_this_disk, ecloc64_total_disks - 1)); + return PK_COOL; + } + + /* If found locator, look for ecrec64 where the locator says it is. */ + + /* For now assume that ecrec64 is on the same disk as ecloc64 and ecrec, + which is usually the case and is how Zip writes it. To do this right, + however, we should allow the ecrec64 to be on another disk since + the AppNote allows it and the ecrec64 can be large, especially if + Version 2 is used (AppNote uses 8 bytes for the size of this record). */ + + /* FIX BELOW IF ADD SUPPORT FOR MULTIPLE DISKS */ + + if (ecrec64_start_offset > (zusz_t)ecloc64_start_offset) { + /* ecrec64 has to be before ecrec64 locator */ + if (uO.qflag || uO.zipinfo_mode) + Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); + Info(slide, 0x401, ((char *)slide, + LoadFarString(Cent64EndSigSearchErr))); + return PK_ERR; + } + +#ifdef USE_STRM_INPUT + zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET); + G.cur_zipfile_bufstart = zftello(G.zipfd); +#else /* !USE_STRM_INPUT */ + G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + + if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4)) + != (ECREC64_SIZE+4)) { + if (uO.qflag || uO.zipinfo_mode) + Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); + Info(slide, 0x401, ((char *)slide, + LoadFarString(Cent64EndSigSearchErr))); + return PK_ERR; + } + + if (memcmp((char *)byterec, end_central64_sig, 4) ) { + /* Zip64 EOCD Record not found */ + /* Since we already have seen the Zip64 EOCD Locator, it's + possible we got here because there are bytes prepended + to the archive, like the sfx prefix. */ + + /* Make a guess as to where the Zip64 EOCD Record might be */ + ecrec64_start_offset = ecloc64_start_offset - ECREC64_SIZE - 4; + +#ifdef USE_STRM_INPUT + zfseeko(G.zipfd, ecrec64_start_offset, SEEK_SET); + G.cur_zipfile_bufstart = zftello(G.zipfd); +#else /* !USE_STRM_INPUT */ + G.cur_zipfile_bufstart = zlseek(G.zipfd, ecrec64_start_offset, SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + + if ((G.incnt = read(G.zipfd, (char *)byterec, ECREC64_SIZE+4)) + != (ECREC64_SIZE+4)) { + if (uO.qflag || uO.zipinfo_mode) + Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); + Info(slide, 0x401, ((char *)slide, + LoadFarString(Cent64EndSigSearchErr))); + return PK_ERR; + } + + if (memcmp((char *)byterec, end_central64_sig, 4) ) { + /* Zip64 EOCD Record not found */ + /* Probably something not so easy to handle so exit */ + if (uO.qflag || uO.zipinfo_mode) + Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); + Info(slide, 0x401, ((char *)slide, + LoadFarString(Cent64EndSigSearchErr))); + return PK_ERR; + } + + if (uO.qflag || uO.zipinfo_mode) + Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); + Info(slide, 0x401, ((char *)slide, + LoadFarString(Cent64EndSigSearchOff))); + } + + /* Check consistency of found ecrec64 with ecloc64 (and ecrec): */ + if ( (zuvl_t)makelong(&byterec[NUMBER_THIS_DSK_REC64]) + != ecrec64_start_disk ) + /* found ecrec64 does not match ecloc64 info -> no Zip64 archive */ + return PK_COOL; + /* Read all relevant ecrec64 fields and compare them to the corresponding + ecrec fields unless those are set to "all-ones". + */ + ecrec64_disk_cdstart = + (zuvl_t)makelong(&byterec[NUM_DISK_START_CEN_DIR64]); + if ( (G.ecrec.num_disk_start_cdir != 0xFFFF) && + (G.ecrec.num_disk_start_cdir != ecrec64_disk_cdstart) ) + return PK_COOL; + ecrec64_this_entries + = makeint64(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK64]); + if ( (G.ecrec.num_entries_centrl_dir_ths_disk != 0xFFFF) && + (G.ecrec.num_entries_centrl_dir_ths_disk != ecrec64_this_entries) ) + return PK_COOL; + ecrec64_tot_entries + = makeint64(&byterec[TOTAL_ENTRIES_CENTRAL_DIR64]); + if ( (G.ecrec.total_entries_central_dir != 0xFFFF) && + (G.ecrec.total_entries_central_dir != ecrec64_tot_entries) ) + return PK_COOL; + ecrec64_cdirsize + = makeint64(&byterec[SIZE_CENTRAL_DIRECTORY64]); + if ( (G.ecrec.size_central_directory != 0xFFFFFFFFL) && + (G.ecrec.size_central_directory != ecrec64_cdirsize) ) + return PK_COOL; + ecrec64_offs_cdstart + = makeint64(&byterec[OFFSET_START_CENTRAL_DIRECT64]); + if ( (G.ecrec.offset_start_central_directory != 0xFFFFFFFFL) && + (G.ecrec.offset_start_central_directory != ecrec64_offs_cdstart) ) + return PK_COOL; + + /* Now, we are (almost) sure that we have a Zip64 archive. */ + G.ecrec.have_ecr64 = 1; + + /* Update the "end-of-central-dir offset" for later checks. */ + G.real_ecrec_offset = ecrec64_start_offset; + + /* Update all ecdir_rec data that are flagged to be invalid + in Zip64 mode. Set the ecrec64-mandatory flag when such a + case is found. */ + if (G.ecrec.number_this_disk == 0xFFFF) { + G.ecrec.number_this_disk = ecrec64_start_disk; + if (ecrec64_start_disk != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; + } + if (G.ecrec.num_disk_start_cdir == 0xFFFF) { + G.ecrec.num_disk_start_cdir = ecrec64_disk_cdstart; + if (ecrec64_disk_cdstart != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; + } + if (G.ecrec.num_entries_centrl_dir_ths_disk == 0xFFFF) { + G.ecrec.num_entries_centrl_dir_ths_disk = ecrec64_this_entries; + if (ecrec64_this_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; + } + if (G.ecrec.total_entries_central_dir == 0xFFFF) { + G.ecrec.total_entries_central_dir = ecrec64_tot_entries; + if (ecrec64_tot_entries != 0xFFFF) G.ecrec.is_zip64_archive = TRUE; + } + if (G.ecrec.size_central_directory == 0xFFFFFFFFL) { + G.ecrec.size_central_directory = ecrec64_cdirsize; + if (ecrec64_cdirsize != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE; + } + if (G.ecrec.offset_start_central_directory == 0xFFFFFFFFL) { + G.ecrec.offset_start_central_directory = ecrec64_offs_cdstart; + if (ecrec64_offs_cdstart != 0xFFFFFFFF) G.ecrec.is_zip64_archive = TRUE; + } + + return PK_COOL; +} /* end function find_ecrec64() */ + + + +/*************************/ +/* Function find_ecrec() */ +/*************************/ + +static int find_ecrec(__G__ searchlen) /* return PK-class error */ + __GDEF + zoff_t searchlen; +{ + int found = FALSE; + int error_in_archive; + int result; + ec_byte_rec byterec; + +/*--------------------------------------------------------------------------- + Treat case of short zipfile separately. + ---------------------------------------------------------------------------*/ + + if (G.ziplen <= INBUFSIZ) { +#ifdef USE_STRM_INPUT + zfseeko(G.zipfd, 0L, SEEK_SET); +#else /* !USE_STRM_INPUT */ + zlseek(G.zipfd, 0L, SEEK_SET); +#endif /* ?USE_STRM_INPUT */ + if ((G.incnt = read(G.zipfd,(char *)G.inbuf,(unsigned int)G.ziplen)) + == (int)G.ziplen) + + /* 'P' must be at least (ECREC_SIZE+4) bytes from end of zipfile */ + for (G.inptr = G.inbuf+(int)G.ziplen-(ECREC_SIZE+4); + G.inptr >= G.inbuf; + --G.inptr) { + if ( (*G.inptr == (uch)0x50) && /* ASCII 'P' */ + !memcmp((char *)G.inptr, end_central_sig, 4)) { + G.incnt -= (int)(G.inptr - G.inbuf); + found = TRUE; + break; + } + } + +/*--------------------------------------------------------------------------- + Zipfile is longer than INBUFSIZ: + + MB - this next block of code moved to rec_find so that same code can be + used to look for zip64 ec record. No need to include code above since + a zip64 ec record will only be looked for if it is a BIG file. + ---------------------------------------------------------------------------*/ + + } else { + found = + (rec_find(__G__ searchlen, end_central_sig, ECREC_SIZE) == 0 + ? TRUE : FALSE); + } /* end if (ziplen > INBUFSIZ) */ + +/*--------------------------------------------------------------------------- + Searched through whole region where signature should be without finding + it. Print informational message and die a horrible death. + ---------------------------------------------------------------------------*/ + + if (!found) { + if (uO.qflag || uO.zipinfo_mode) + Info(slide, 0x401, ((char *)slide, "[%s]\n", G.zipfn)); + Info(slide, 0x401, ((char *)slide, + LoadFarString(CentDirEndSigNotFound))); + return PK_ERR; /* failed */ + } + +/*--------------------------------------------------------------------------- + Found the signature, so get the end-central data before returning. Do + any necessary machine-type conversions (byte ordering, structure padding + compensation) by reading data into character array and copying to struct. + ---------------------------------------------------------------------------*/ + + G.real_ecrec_offset = G.cur_zipfile_bufstart + (G.inptr-G.inbuf); +#ifdef TEST + printf("\n found end-of-central-dir signature at offset %s (%sh)\n", + FmZofft(G.real_ecrec_offset, NULL, NULL), + FmZofft(G.real_ecrec_offset, FZOFFT_HEX_DOT_WID, "X")); + printf(" from beginning of file; offset %d (%.4Xh) within block\n", + G.inptr-G.inbuf, G.inptr-G.inbuf); +#endif + + if (readbuf(__G__ (char *)byterec, ECREC_SIZE+4) == 0) + return PK_EOF; + + G.ecrec.number_this_disk = + makeword(&byterec[NUMBER_THIS_DISK]); + G.ecrec.num_disk_start_cdir = + makeword(&byterec[NUM_DISK_WITH_START_CEN_DIR]); + G.ecrec.num_entries_centrl_dir_ths_disk = + makeword(&byterec[NUM_ENTRIES_CEN_DIR_THS_DISK]); + G.ecrec.total_entries_central_dir = + makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]); + G.ecrec.size_central_directory = + makelong(&byterec[SIZE_CENTRAL_DIRECTORY]); + G.ecrec.offset_start_central_directory = + makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]); + G.ecrec.zipfile_comment_length = + makeword(&byterec[ZIPFILE_COMMENT_LENGTH]); + + /* Now, we have to read the archive comment, BEFORE the file pointer + is moved away backwards to seek for a Zip64 ECLOC64 structure. + */ + if ( (error_in_archive = process_zip_cmmnt(__G)) > PK_WARN ) + return error_in_archive; + + /* Next: Check for existence of Zip64 end-of-cent-dir locator + ECLOC64. This structure must reside on the same volume as the + classic ECREC, at exactly (ECLOC64_SIZE+4) bytes in front + of the ECREC. + The ECLOC64 structure directs to the longer ECREC64 structure + A ECREC64 will ALWAYS exist for a proper Zip64 archive, as + the "Version Needed To Extract" field is required to be set + to 4.5 or higher whenever any Zip64 features are used anywhere + in the archive, so just check for that to see if this is a + Zip64 archive. + */ + result = find_ecrec64(__G__ searchlen+76); + /* 76 bytes for zip64ec & zip64 locator */ + if (result != PK_COOL) { + if (error_in_archive < result) + error_in_archive = result; + return error_in_archive; + } + + G.expect_ecrec_offset = G.ecrec.offset_start_central_directory + + G.ecrec.size_central_directory; + +#ifndef NO_ZIPINFO + if (uO.zipinfo_mode) { + /* In ZipInfo mode, additional info about the data found in the + end-of-central-directory areas is printed out. + */ + zi_end_central(__G); + } +#endif + + return error_in_archive; + +} /* end function find_ecrec() */ + + + + + +/********************************/ +/* Function process_zip_cmmnt() */ +/********************************/ + +static int process_zip_cmmnt(__G) /* return PK-type error code */ + __GDEF +{ + int error = PK_COOL; + + +/*--------------------------------------------------------------------------- + Get the zipfile comment (up to 64KB long), if any, and print it out. + ---------------------------------------------------------------------------*/ + +#ifdef WINDLL + /* for comment button: */ + if ((!G.fValidate) && (G.lpUserFunctions != NULL)) + G.lpUserFunctions->cchComment = G.ecrec.zipfile_comment_length; +#endif /* WINDLL */ + +#ifndef NO_ZIPINFO + /* ZipInfo, verbose format */ + if (uO.zipinfo_mode && uO.lflag > 9) { + /*------------------------------------------------------------------- + Get the zipfile comment, if any, and print it out. + (Comment may be up to 64KB long. May the fleas of a thousand + camels infest the arm-pits of anyone who actually takes advantage + of this fact.) + -------------------------------------------------------------------*/ + + if (!G.ecrec.zipfile_comment_length) + Info(slide, 0, ((char *)slide, LoadFarString(NoZipfileComment))); + else { + Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommentDesc), + G.ecrec.zipfile_comment_length)); + Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommBegin))); + if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) + error = PK_WARN; + Info(slide, 0, ((char *)slide, LoadFarString(ZipfileCommEnd))); + if (error) + Info(slide, 0, ((char *)slide, + LoadFarString(ZipfileCommTrunc2))); + } /* endif (comment exists) */ + + /* ZipInfo, non-verbose mode: print zipfile comment only if requested */ + } else if (G.ecrec.zipfile_comment_length && + (uO.zflag > 0) && uO.zipinfo_mode) { + if (do_string(__G__ G.ecrec.zipfile_comment_length, DISPLAY)) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(ZipfileCommTrunc1))); + error = PK_WARN; + } + } else +#endif /* !NO_ZIPINFO */ + if ( G.ecrec.zipfile_comment_length && + (uO.zflag > 0 +#ifndef WINDLL + || (uO.zflag == 0 +# ifndef NO_ZIPINFO + && !uO.zipinfo_mode +# endif +# ifdef TIMESTAMP + && !uO.T_flag +# endif + && !uO.qflag) +#endif /* !WINDLL */ + ) ) + { + if (do_string(__G__ G.ecrec.zipfile_comment_length, +#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) +# ifndef NO_ZIPINFO + (oU.zipinfo_mode ? DISPLAY : CHECK_AUTORUN) +# else + CHECK_AUTORUN +# endif +#else + DISPLAY +#endif + )) + { + Info(slide, 0x401, ((char *)slide, + LoadFarString(ZipfileCommTrunc1))); + error = PK_WARN; + } + } +#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) + else if (G.ecrec.zipfile_comment_length) { + if (do_string(__G__ G.ecrec.zipfile_comment_length, CHECK_AUTORUN_Q)) + { + Info(slide, 0x401, ((char *)slide, + LoadFarString(ZipfileCommTrunc1))); + error = PK_WARN; + } + } +#endif + return error; + +} /* end function process_zip_cmmnt() */ + + + + + +/************************************/ +/* Function process_cdir_file_hdr() */ +/************************************/ + +int process_cdir_file_hdr(__G) /* return PK-type error code */ + __GDEF +{ + int error; + + +/*--------------------------------------------------------------------------- + Get central directory info, save host and method numbers, and set flag + for lowercase conversion of filename, depending on the OS from which the + file is coming. + ---------------------------------------------------------------------------*/ + + if ((error = get_cdir_ent(__G)) != 0) + return error; + + G.pInfo->hostver = G.crec.version_made_by[0]; + G.pInfo->hostnum = MIN(G.crec.version_made_by[1], NUM_HOSTS); +/* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */ + + G.pInfo->lcflag = 0; + if (uO.L_flag == 1) /* name conversion for monocase systems */ + switch (G.pInfo->hostnum) { + case FS_FAT_: /* PKZIP and zip -k store in uppercase */ + case CPM_: /* like MS-DOS, right? */ + case VM_CMS_: /* all caps? */ + case MVS_: /* all caps? */ + case TANDEM_: + case TOPS20_: + case VMS_: /* our Zip uses lowercase, but ASi's doesn't */ + /* case Z_SYSTEM_: ? */ + /* case QDOS_: ? */ + G.pInfo->lcflag = 1; /* convert filename to lowercase */ + break; + + default: /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, ATARI_, */ + break; /* FS_VFAT_, ATHEOS_, BEOS_ (Z_SYSTEM_), THEOS_: */ + /* no conversion */ + } + else if (uO.L_flag > 1) /* let -LL force lower case for all names */ + G.pInfo->lcflag = 1; + + /* do Amigas (AMIGA_) also have volume labels? */ + if (IS_VOLID(G.crec.external_file_attributes) && + (G.pInfo->hostnum == FS_FAT_ || G.pInfo->hostnum == FS_HPFS_ || + G.pInfo->hostnum == FS_NTFS_ || G.pInfo->hostnum == ATARI_)) + { + G.pInfo->vollabel = TRUE; + G.pInfo->lcflag = 0; /* preserve case of volume labels */ + } else + G.pInfo->vollabel = FALSE; + + /* this flag is needed to detect archives made by "PKZIP for Unix" when + deciding which kind of codepage conversion has to be applied to + strings (see do_string() function in fileio.c) */ + G.pInfo->HasUxAtt = (G.crec.external_file_attributes & 0xffff0000L) != 0L; + +#ifdef UNICODE_SUPPORT + /* remember the state of GPB11 (General Purpuse Bit 11) which indicates + that the standard path and comment are UTF-8. */ + G.pInfo->GPFIsUTF8 + = (G.crec.general_purpose_bit_flag & (1 << 11)) == (1 << 11); +#endif + + return PK_COOL; + +} /* end function process_cdir_file_hdr() */ + + + + + +/***************************/ +/* Function get_cdir_ent() */ +/***************************/ + +static int get_cdir_ent(__G) /* return PK-type error code */ + __GDEF +{ + cdir_byte_hdr byterec; + + +/*--------------------------------------------------------------------------- + Read the next central directory entry and do any necessary machine-type + conversions (byte ordering, structure padding compensation--do so by + copying the data from the array into which it was read (byterec) to the + usable struct (crec)). + ---------------------------------------------------------------------------*/ + + if (readbuf(__G__ (char *)byterec, CREC_SIZE) == 0) + return PK_EOF; + + G.crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0]; + G.crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1]; + G.crec.version_needed_to_extract[0] = + byterec[C_VERSION_NEEDED_TO_EXTRACT_0]; + G.crec.version_needed_to_extract[1] = + byterec[C_VERSION_NEEDED_TO_EXTRACT_1]; + + G.crec.general_purpose_bit_flag = + makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]); + G.crec.compression_method = + makeword(&byterec[C_COMPRESSION_METHOD]); + G.crec.last_mod_dos_datetime = + makelong(&byterec[C_LAST_MOD_DOS_DATETIME]); + G.crec.crc32 = + makelong(&byterec[C_CRC32]); + G.crec.csize = + makelong(&byterec[C_COMPRESSED_SIZE]); + G.crec.ucsize = + makelong(&byterec[C_UNCOMPRESSED_SIZE]); + G.crec.filename_length = + makeword(&byterec[C_FILENAME_LENGTH]); + G.crec.extra_field_length = + makeword(&byterec[C_EXTRA_FIELD_LENGTH]); + G.crec.file_comment_length = + makeword(&byterec[C_FILE_COMMENT_LENGTH]); + G.crec.disk_number_start = + makeword(&byterec[C_DISK_NUMBER_START]); + G.crec.internal_file_attributes = + makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]); + G.crec.external_file_attributes = + makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */ + G.crec.relative_offset_local_header = + makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]); + + return PK_COOL; + +} /* end function get_cdir_ent() */ + + + + + +/*************************************/ +/* Function process_local_file_hdr() */ +/*************************************/ + +int process_local_file_hdr(__G) /* return PK-type error code */ + __GDEF +{ + local_byte_hdr byterec; + + +/*--------------------------------------------------------------------------- + Read the next local file header and do any necessary machine-type con- + versions (byte ordering, structure padding compensation--do so by copy- + ing the data from the array into which it was read (byterec) to the + usable struct (lrec)). + ---------------------------------------------------------------------------*/ + + if (readbuf(__G__ (char *)byterec, LREC_SIZE) == 0) + return PK_EOF; + + G.lrec.version_needed_to_extract[0] = + byterec[L_VERSION_NEEDED_TO_EXTRACT_0]; + G.lrec.version_needed_to_extract[1] = + byterec[L_VERSION_NEEDED_TO_EXTRACT_1]; + + G.lrec.general_purpose_bit_flag = + makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]); + G.lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]); + G.lrec.last_mod_dos_datetime = makelong(&byterec[L_LAST_MOD_DOS_DATETIME]); + G.lrec.crc32 = makelong(&byterec[L_CRC32]); + G.lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]); + G.lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]); + G.lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]); + G.lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]); + + if ((G.lrec.general_purpose_bit_flag & 8) != 0) { + /* can't trust local header, use central directory: */ + G.lrec.crc32 = G.pInfo->crc; + G.lrec.csize = G.pInfo->compr_size; + G.lrec.ucsize = G.pInfo->uncompr_size; + } + + G.csize = G.lrec.csize; + + return PK_COOL; + +} /* end function process_local_file_hdr() */ + + +/*******************************/ +/* Function getZip64Data() */ +/*******************************/ + +int getZip64Data(__G__ ef_buf, ef_len) + __GDEF + ZCONST uch *ef_buf; /* buffer containing extra field */ + unsigned ef_len; /* total length of extra field */ +{ + unsigned eb_id; + unsigned eb_len; + +/*--------------------------------------------------------------------------- + This function scans the extra field for zip64 information, ie 8-byte + versions of compressed file size, uncompressed file size, relative offset + and a 4-byte version of disk start number. + Sets both local header and central header fields. Not terribly clever, + but it means that this procedure is only called in one place. + + 2014-12-05 SMS. + Added checks to ensure that enough data are available before calling + makeint64() or makelong(). Replaced various sizeof() values with + simple ("4" or "8") constants. (The Zip64 structures do not depend + on our variable sizes.) Error handling is crude, but we should now + stay within the buffer. + ---------------------------------------------------------------------------*/ + +#define Z64FLGS 0xffff +#define Z64FLGL 0xffffffff + + if (ef_len == 0 || ef_buf == NULL) + return PK_COOL; + + Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n", + ef_len)); + + while (ef_len >= EB_HEADSIZE) + { + eb_id = makeword(EB_ID + ef_buf); + eb_len = makeword(EB_LEN + ef_buf); + + if (eb_len > (ef_len - EB_HEADSIZE)) + { + /* Extra block length exceeds remaining extra field length. */ + Trace((stderr, + "getZip64Data: block length %u > rest ef_size %u\n", eb_len, + ef_len - EB_HEADSIZE)); + break; + } + + if (eb_id == EF_PKSZ64) + { + int offset = EB_HEADSIZE; + + if ((G.crec.ucsize == Z64FLGL) || (G.lrec.ucsize == Z64FLGL)) + { + if (offset+ 8 > ef_len) + return PK_ERR; + + G.crec.ucsize = G.lrec.ucsize = makeint64(offset + ef_buf); + offset += 8; + } + + if ((G.crec.csize == Z64FLGL) || (G.lrec.csize == Z64FLGL)) + { + if (offset+ 8 > ef_len) + return PK_ERR; + + G.csize = G.crec.csize = G.lrec.csize = makeint64(offset + ef_buf); + offset += 8; + } + + if (G.crec.relative_offset_local_header == Z64FLGL) + { + if (offset+ 8 > ef_len) + return PK_ERR; + + G.crec.relative_offset_local_header = makeint64(offset + ef_buf); + offset += 8; + } + + if (G.crec.disk_number_start == Z64FLGS) + { + if (offset+ 4 > ef_len) + return PK_ERR; + + G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf); + offset += 4; + } +#if 0 + break; /* Expect only one EF_PKSZ64 block. */ +#endif /* 0 */ + } + + /* Skip this extra field block. */ + ef_buf += (eb_len + EB_HEADSIZE); + ef_len -= (eb_len + EB_HEADSIZE); + } + + return PK_COOL; +} /* end function getZip64Data() */ + + +#ifdef UNICODE_SUPPORT + +/*******************************/ +/* Function getUnicodeData() */ +/*******************************/ + +int getUnicodeData(__G__ ef_buf, ef_len) + __GDEF + ZCONST uch *ef_buf; /* buffer containing extra field */ + unsigned ef_len; /* total length of extra field */ +{ + unsigned eb_id; + unsigned eb_len; + +/*--------------------------------------------------------------------------- + This function scans the extra field for Unicode information, ie UTF-8 + path extra fields. + + On return, G.unipath_filename = + NULL, if no Unicode path extra field or error + "", if the standard path is UTF-8 (free when done) + null-terminated UTF-8 path (free when done) + Return PK_COOL if no error. + ---------------------------------------------------------------------------*/ + + G.unipath_filename = NULL; + + if (ef_len == 0 || ef_buf == NULL) + return PK_COOL; + + Trace((stderr,"\ngetUnicodeData: scanning extra field of length %u\n", + ef_len)); + + while (ef_len >= EB_HEADSIZE) { + eb_id = makeword(EB_ID + ef_buf); + eb_len = makeword(EB_LEN + ef_buf); + + if (eb_len > (ef_len - EB_HEADSIZE)) { + /* discovered some extra field inconsistency! */ + Trace((stderr, + "getUnicodeData: block length %u > rest ef_size %u\n", eb_len, + ef_len - EB_HEADSIZE)); + break; + } + if (eb_id == EF_UNIPATH) { + + int offset = EB_HEADSIZE; + ush ULen = eb_len - 5; + ulg chksum = CRCVAL_INITIAL; + + /* version */ + G.unipath_version = (uch) *(offset + ef_buf); + offset += 1; + if (G.unipath_version > 1) { + /* can do only version 1 */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(UnicodeVersionError))); + return PK_ERR; + } + + /* filename CRC */ + G.unipath_checksum = makelong(offset + ef_buf); + offset += 4; + + /* + * Compute 32-bit crc + */ + + chksum = crc32(chksum, (uch *)(G.filename_full), + strlen(G.filename_full)); + + /* If the checksums's don't match then likely filename has been + * modified and the Unicode Path is no longer valid. + */ + if (chksum != G.unipath_checksum) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(UnicodeMismatchError))); + if (G.unicode_mismatch == 1) { + /* warn and continue */ + } else if (G.unicode_mismatch == 2) { + /* ignore and continue */ + } else if (G.unicode_mismatch == 0) { + } + return PK_ERR; + } + + /* UTF-8 Path */ + if ((G.unipath_filename = malloc(ULen + 1)) == NULL) { + return PK_ERR; + } + if (ULen == 0) { + /* standard path is UTF-8 so use that */ + G.unipath_filename[0] = '\0'; + } else { + /* UTF-8 path */ + strncpy(G.unipath_filename, + (ZCONST char *)(offset + ef_buf), ULen); + G.unipath_filename[ULen] = '\0'; + } + } + + /* Skip this extra field block */ + ef_buf += (eb_len + EB_HEADSIZE); + ef_len -= (eb_len + EB_HEADSIZE); + } + + return PK_COOL; +} /* end function getUnicodeData() */ + + + + +#ifdef UNICODE_WCHAR + /*--------------------------------------------- + * Unicode conversion functions + * + * Based on functions provided by Paul Kienitz + * + *--------------------------------------------- + */ + +/* + NOTES APPLICABLE TO ALL STRING FUNCTIONS: + + All of the x_to_y functions take parameters for an output buffer and + its available length, and return an int. The value returned is the + length of the string that the input produces, which may be larger than + the provided buffer length. If the returned value is less than the + buffer length, then the contents of the buffer will be null-terminated; + otherwise, it will not be terminated and may be invalid, possibly + stopping in the middle of a multibyte sequence. + + In all cases you may pass NULL as the buffer and/or 0 as the length, if + you just want to learn how much space the string is going to require. + + The functions will return -1 if the input is invalid UTF-8 or cannot be + encoded as UTF-8. +*/ + +static int utf8_char_bytes OF((ZCONST char *utf8)); +static ulg ucs4_char_from_utf8 OF((ZCONST char **utf8)); +static int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *ucs4buf, + int buflen)); + +/* utility functions for managing UTF-8 and UCS-4 strings */ + + +/* utf8_char_bytes + * + * Returns the number of bytes used by the first character in a UTF-8 + * string, or -1 if the UTF-8 is invalid or null. + */ +static int utf8_char_bytes(utf8) + ZCONST char *utf8; +{ + int t, r; + unsigned lead; + + if (!utf8) + return -1; /* no input */ + lead = (unsigned char) *utf8; + if (lead < 0x80) + r = 1; /* an ascii-7 character */ + else if (lead < 0xC0) + return -1; /* error: trailing byte without lead byte */ + else if (lead < 0xE0) + r = 2; /* an 11 bit character */ + else if (lead < 0xF0) + r = 3; /* a 16 bit character */ + else if (lead < 0xF8) + r = 4; /* a 21 bit character (the most currently used) */ + else if (lead < 0xFC) + r = 5; /* a 26 bit character (shouldn't happen) */ + else if (lead < 0xFE) + r = 6; /* a 31 bit character (shouldn't happen) */ + else + return -1; /* error: invalid lead byte */ + for (t = 1; t < r; t++) + if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0) + return -1; /* error: not enough valid trailing bytes */ + return r; +} + + +/* ucs4_char_from_utf8 + * + * Given a reference to a pointer into a UTF-8 string, returns the next + * UCS-4 character and advances the pointer to the next character sequence. + * Returns ~0 (= -1 in twos-complement notation) and does not advance the + * pointer when input is ill-formed. + */ +static ulg ucs4_char_from_utf8(utf8) + ZCONST char **utf8; +{ + ulg ret; + int t, bytes; + + if (!utf8) + return ~0L; /* no input */ + bytes = utf8_char_bytes(*utf8); + if (bytes <= 0) + return ~0L; /* invalid input */ + if (bytes == 1) + ret = **utf8; /* ascii-7 */ + else + ret = **utf8 & (0x7F >> bytes); /* lead byte of a multibyte sequence */ + (*utf8)++; + for (t = 1; t < bytes; t++) /* consume trailing bytes */ + ret = (ret << 6) | (*((*utf8)++) & 0x3F); + return (zwchar) ret; +} + + +#if 0 /* currently unused */ +/* utf8_from_ucs4_char - Convert UCS char to UTF-8 + * + * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6, + * or -1 if ch is too large to represent. utf8buf must have room for 6 bytes. + */ +static int utf8_from_ucs4_char(utf8buf, ch) + char *utf8buf; + ulg ch; +{ + int trailing = 0; + int leadmask = 0x80; + int leadbits = 0x3F; + int tch = ch; + int ret; + + if (ch > 0x7FFFFFFFL) + return -1; /* UTF-8 can represent 31 bits */ + if (ch < 0x7F) + { + *utf8buf++ = (char) ch; /* ascii-7 */ + return 1; + } + do { + trailing++; + leadmask = (leadmask >> 1) | 0x80; + leadbits >>= 1; + tch >>= 6; + } while (tch & ~leadbits); + ret = trailing + 1; + /* produce lead byte */ + *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing))); + while (--trailing >= 0) + /* produce trailing bytes */ + *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F)); + return ret; +} +#endif /* unused */ + + +/*===================================================================*/ + +/* utf8_to_ucs4_string - convert UTF-8 string to UCS string + * + * Return UCS count. Now returns int so can return -1. + */ +static int utf8_to_ucs4_string(utf8, ucs4buf, buflen) + ZCONST char *utf8; + ulg *ucs4buf; + int buflen; +{ + int count = 0; + + for (;;) + { + ulg ch = ucs4_char_from_utf8(&utf8); + if (ch == ~0L) + return -1; + else + { + if (ucs4buf && count < buflen) + ucs4buf[count] = ch; + if (ch == 0) + return count; + count++; + } + } +} + + +#if 0 /* currently unused */ +/* ucs4_string_to_utf8 + * + * + */ +static int ucs4_string_to_utf8(ucs4, utf8buf, buflen) + ZCONST ulg *ucs4; + char *utf8buf; + int buflen; +{ + char mb[6]; + int count = 0; + + if (!ucs4) + return -1; + for (;;) + { + int mbl = utf8_from_ucs4_char(mb, *ucs4++); + int c; + if (mbl <= 0) + return -1; + /* We could optimize this a bit by passing utf8buf + count */ + /* directly to utf8_from_ucs4_char when buflen >= count + 6... */ + c = buflen - count; + if (mbl < c) + c = mbl; + if (utf8buf && count < buflen) + strncpy(utf8buf + count, mb, c); + if (mbl == 1 && !mb[0]) + return count; /* terminating nul */ + count += mbl; + } +} + + +/* utf8_chars + * + * Wrapper: counts the actual unicode characters in a UTF-8 string. + */ +static int utf8_chars(utf8) + ZCONST char *utf8; +{ + return utf8_to_ucs4_string(utf8, NULL, 0); +} +#endif /* unused */ + +/* --------------------------------------------------- */ +/* Unicode Support + * + * These functions common for all Unicode ports. + * + * These functions should allocate and return strings that can be + * freed with free(). + * + * 8/27/05 EG + * + * Use zwchar for wide char which is unsigned long + * in zip.h and 32 bits. This avoids problems with + * different sizes of wchar_t. + */ + +#if 0 /* currently unused */ +/* is_ascii_string + * Checks if a string is all ascii + */ +int is_ascii_string(mbstring) + ZCONST char *mbstring; +{ + char *p; + uch c; + + for (p = mbstring; c = (uch)*p; p++) { + if (c > 0x7F) { + return 0; + } + } + return 1; +} + +/* local to UTF-8 */ +char *local_to_utf8_string(local_string) + ZCONST char *local_string; +{ + return wide_to_utf8_string(local_to_wide_string(local_string)); +} +# endif /* unused */ + +/* wide_to_escape_string + provides a string that represents a wide char not in local char set + + An initial try at an algorithm. Suggestions welcome. + + According to the standard, Unicode character points are restricted to + the number range from 0 to 0x10FFFF, respective 21 bits. + For a hexadecimal notation, 2 octets are sufficient for the mostly + used characters from the "Basic Multilingual Plane", all other + Unicode characters can be represented by 3 octets (= 6 hex digits). + The Unicode standard suggests to write Unicode character points + as 4 resp. 6 hex digits, preprended by "U+". + (e.g.: U+10FFFF for the highest character point, or U+0030 for the ASCII + digit "0") + + However, for the purpose of escaping non-ASCII chars in an ASCII character + stream, the "U" is not a very good escape initializer. Therefore, we + use the following convention within our Info-ZIP code: + + If not an ASCII char probably need 2 bytes at least. So if + a 2-byte wide encode it as 4 hex digits with a leading #U. If + needs 3 bytes then prefix the string with #L. So + #U1234 + is a 2-byte wide character with bytes 0x12 and 0x34 while + #L123456 + is a 3-byte wide character with bytes 0x12, 0x34, 0x56. + On Windows, wide that need two wide characters need to be converted + to a single number. + */ + + /* set this to the max bytes an escape can be */ +#define MAX_ESCAPE_BYTES 8 + +char *wide_to_escape_string(wide_char) + zwchar wide_char; +{ + int i; + zwchar w = wide_char; + uch b[sizeof(zwchar)]; + char d[3]; + char e[11]; + int len; + char *r; + + /* fill byte array with zeros */ + memzero(b, sizeof(zwchar)); + /* get bytes in right to left order */ + for (len = 0; w; len++) { + b[len] = (char)(w % 0x100); + w /= 0x100; + } + strcpy(e, "#"); + /* either 2 bytes or 3 bytes */ + if (len <= 2) { + len = 2; + strcat(e, "U"); + } else { + strcat(e, "L"); + } + for (i = len - 1; i >= 0; i--) { + sprintf(d, "%02x", b[i]); + strcat(e, d); + } + if ((r = malloc(strlen(e) + 1)) == NULL) { + return NULL; + } + strcpy(r, e); + return r; +} + +#if 0 /* currently unused */ +/* returns the wide character represented by the escape string */ +zwchar escape_string_to_wide(escape_string) + ZCONST char *escape_string; +{ + int i; + zwchar w; + char c; + int len; + ZCONST char *e = escape_string; + + if (e == NULL) { + return 0; + } + if (e[0] != '#') { + /* no leading # */ + return 0; + } + len = strlen(e); + /* either #U1234 or #L123456 format */ + if (len != 6 && len != 8) { + return 0; + } + w = 0; + if (e[1] == 'L') { + if (len != 8) { + return 0; + } + /* 3 bytes */ + for (i = 2; i < 8; i++) { + c = e[i]; + if (c < '0' || c > '9') { + return 0; + } + w = w * 0x10 + (zwchar)(c - '0'); + } + } else if (e[1] == 'U') { + /* 2 bytes */ + for (i = 2; i < 6; i++) { + c = e[i]; + if (c < '0' || c > '9') { + return 0; + } + w = w * 0x10 + (zwchar)(c - '0'); + } + } + return w; +} +#endif /* unused */ + +#ifndef WIN32 /* WIN32 supplies a special variant of this function */ +/* convert wide character string to multi-byte character string */ +char *wide_to_local_string(wide_string, escape_all) + ZCONST zwchar *wide_string; + int escape_all; +{ + int i; + wchar_t wc; + int b; + int state_dependent; + int wsize = 0; + int max_bytes = MB_CUR_MAX; + char buf[9]; + char *buffer = NULL; + char *local_string = NULL; + + for (wsize = 0; wide_string[wsize]; wsize++) ; + + if (max_bytes < MAX_ESCAPE_BYTES) + max_bytes = MAX_ESCAPE_BYTES; + + if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) { + return NULL; + } + + /* convert it */ + buffer[0] = '\0'; + /* set initial state if state-dependent encoding */ + wc = (wchar_t)'a'; + b = wctomb(NULL, wc); + if (b == 0) + state_dependent = 0; + else + state_dependent = 1; + for (i = 0; i < wsize; i++) { + if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) { + /* wchar_t probably 2 bytes */ + /* could do surrogates if state_dependent and wctomb can do */ + wc = zwchar_to_wchar_t_default_char; + } else { + wc = (wchar_t)wide_string[i]; + } + b = wctomb(buf, wc); + if (escape_all) { + if (b == 1 && (uch)buf[0] <= 0x7f) { + /* ASCII */ + strncat(buffer, buf, b); + } else { + /* use escape for wide character */ + char *escape_string = wide_to_escape_string(wide_string[i]); + strcat(buffer, escape_string); + free(escape_string); + } + } else if (b > 0) { + /* multi-byte char */ + strncat(buffer, buf, b); + } else { + /* no MB for this wide */ + /* use escape for wide character */ + char *escape_string = wide_to_escape_string(wide_string[i]); + strcat(buffer, escape_string); + free(escape_string); + } + } + if ((local_string = (char *)malloc(strlen(buffer) + 1)) != NULL) { + strcpy(local_string, buffer); + } + free(buffer); + + return local_string; +} +#endif /* !WIN32 */ + +#if 0 /* currently unused */ +/* convert local string to display character set string */ +char *local_to_display_string(local_string) + ZCONST char *local_string; +{ + char *display_string; + + /* For Windows, OEM string should never be bigger than ANSI string, says + CharToOem description. + For all other ports, just make a copy of local_string. + */ + if ((display_string = (char *)malloc(strlen(local_string) + 1)) == NULL) { + return NULL; + } + + strcpy(display_string, local_string); + +#ifdef EBCDIC + { + char *ebc; + + if ((ebc = malloc(strlen(display_string) + 1)) == NULL) { + return NULL; + } + strtoebc(ebc, display_string); + free(display_string); + display_string = ebc; + } +#endif + + return display_string; +} +#endif /* unused */ + +/* UTF-8 to local */ +char *utf8_to_local_string(utf8_string, escape_all) + ZCONST char *utf8_string; + int escape_all; +{ + zwchar *wide = utf8_to_wide_string(utf8_string); + char *loc = wide_to_local_string(wide, escape_all); + free(wide); + return loc; +} + +#if 0 /* currently unused */ +/* convert multi-byte character string to wide character string */ +zwchar *local_to_wide_string(local_string) + ZCONST char *local_string; +{ + int wsize; + wchar_t *wc_string; + zwchar *wide_string; + + /* for now try to convert as string - fails if a bad char in string */ + wsize = mbstowcs(NULL, local_string, strlen(local_string) + 1); + if (wsize == (size_t)-1) { + /* could not convert */ + return NULL; + } + + /* convert it */ + if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) { + return NULL; + } + wsize = mbstowcs(wc_string, local_string, strlen(local_string) + 1); + wc_string[wsize] = (wchar_t) 0; + + /* in case wchar_t is not zwchar */ + if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) { + return NULL; + } + for (wsize = 0; wide_string[wsize] = (zwchar)wc_string[wsize]; wsize++) ; + wide_string[wsize] = (zwchar) 0; + free(wc_string); + + return wide_string; +} + + +/* convert wide string to UTF-8 */ +char *wide_to_utf8_string(wide_string) + ZCONST zwchar *wide_string; +{ + int mbcount; + char *utf8_string; + + /* get size of utf8 string */ + mbcount = ucs4_string_to_utf8(wide_string, NULL, 0); + if (mbcount == -1) + return NULL; + if ((utf8_string = (char *) malloc(mbcount + 1)) == NULL) { + return NULL; + } + mbcount = ucs4_string_to_utf8(wide_string, utf8_string, mbcount + 1); + if (mbcount == -1) + return NULL; + + return utf8_string; +} +#endif /* unused */ + +/* convert UTF-8 string to wide string */ +zwchar *utf8_to_wide_string(utf8_string) + ZCONST char *utf8_string; +{ + int wcount; + zwchar *wide_string; + + wcount = utf8_to_ucs4_string(utf8_string, NULL, 0); + if (wcount == -1) + return NULL; + if ((wide_string = (zwchar *) malloc((wcount + 1) * sizeof(zwchar))) + == NULL) { + return NULL; + } + wcount = utf8_to_ucs4_string(utf8_string, wide_string, wcount + 1); + + return wide_string; +} + +#endif /* UNICODE_WCHAR */ +#endif /* UNICODE_SUPPORT */ + + + + + +#ifdef USE_EF_UT_TIME + +#ifdef IZ_HAVE_UXUIDGID +static int read_ux3_value(dbuf, uidgid_sz, p_uidgid) + ZCONST uch *dbuf; /* buffer a uid or gid value */ + unsigned uidgid_sz; /* size of uid/gid value */ + ulg *p_uidgid; /* return storage: uid or gid value */ +{ + zusz_t uidgid64; + + switch (uidgid_sz) { + case 2: + *p_uidgid = (ulg)makeword(dbuf); + break; + case 4: + *p_uidgid = (ulg)makelong(dbuf); + break; + case 8: + uidgid64 = makeint64(dbuf); +#ifndef LARGE_FILE_SUPPORT + if (uidgid64 == (zusz_t)0xffffffffL) + return FALSE; +#endif + *p_uidgid = (ulg)uidgid64; + if ((zusz_t)(*p_uidgid) != uidgid64) + return FALSE; + break; + } + return TRUE; +} +#endif /* IZ_HAVE_UXUIDGID */ + + +/*******************************/ +/* Function ef_scan_for_izux() */ +/*******************************/ + +unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime, + z_utim, z_uidgid) + ZCONST uch *ef_buf; /* buffer containing extra field */ + unsigned ef_len; /* total length of extra field */ + int ef_is_c; /* flag indicating "is central extra field" */ + ulg dos_mdatetime; /* last_mod_file_date_time in DOS format */ + iztimes *z_utim; /* return storage: atime, mtime, ctime */ + ulg *z_uidgid; /* return storage: uid and gid */ +{ + unsigned flags = 0; + unsigned eb_id; + unsigned eb_len; + int have_new_type_eb = 0; + long i_time; /* buffer for Unix style 32-bit integer time value */ +#ifdef TIME_T_TYPE_DOUBLE + int ut_in_archive_sgn = 0; +#else + int ut_zip_unzip_compatible = FALSE; +#endif + +/*--------------------------------------------------------------------------- + This function scans the extra field for EF_TIME, EF_IZUNIX2, EF_IZUNIX, or + EF_PKUNIX blocks containing Unix-style time_t (GMT) values for the entry's + access, creation, and modification time. + If a valid block is found, the time stamps are copied to the iztimes + structure (provided the z_utim pointer is not NULL). + If a IZUNIX2 block is found or the IZUNIX block contains UID/GID fields, + and the z_uidgid array pointer is valid (!= NULL), the owner info is + transfered as well. + The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring all + data from probably present obsolete EF_IZUNIX blocks. + If multiple blocks of the same type are found, only the information from + the last block is used. + The return value is a combination of the EF_TIME Flags field with an + additional flag bit indicating the presence of valid UID/GID info, + or 0 in case of failure. + ---------------------------------------------------------------------------*/ + + if (ef_len == 0 || ef_buf == NULL || (z_utim == 0 && z_uidgid == NULL)) + return 0; + + TTrace((stderr,"\nef_scan_for_izux: scanning extra field of length %u\n", + ef_len)); + + while (ef_len >= EB_HEADSIZE) { + eb_id = makeword(EB_ID + ef_buf); + eb_len = makeword(EB_LEN + ef_buf); + + if (eb_len > (ef_len - EB_HEADSIZE)) { + /* discovered some extra field inconsistency! */ + TTrace((stderr, + "ef_scan_for_izux: block length %u > rest ef_size %u\n", eb_len, + ef_len - EB_HEADSIZE)); + break; + } + + switch (eb_id) { + case EF_TIME: + flags &= ~0x0ff; /* ignore previous IZUNIX or EF_TIME fields */ + have_new_type_eb = 1; + if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) { + unsigned eb_idx = EB_UT_TIME1; + TTrace((stderr,"ef_scan_for_izux: found TIME extra field\n")); + flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x0ff); + if ((flags & EB_UT_FL_MTIME)) { + if ((eb_idx+4) <= eb_len) { + i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); + eb_idx += 4; + TTrace((stderr," UT e.f. modification time = %ld\n", + i_time)); + +#ifdef TIME_T_TYPE_DOUBLE + if ((ulg)(i_time) & (ulg)(0x80000000L)) { + if (dos_mdatetime == DOSTIME_MINIMUM) { + ut_in_archive_sgn = -1; + z_utim->mtime = + (time_t)((long)i_time | (~(long)0x7fffffffL)); + } else if (dos_mdatetime >= DOSTIME_2038_01_18) { + ut_in_archive_sgn = 1; + z_utim->mtime = + (time_t)((ulg)i_time & (ulg)0xffffffffL); + } else { + ut_in_archive_sgn = 0; + /* cannot determine sign of mtime; + without modtime: ignore complete UT field */ + flags &= ~0x0ff; /* no time_t times available */ + TTrace((stderr, + " UT modtime range error; ignore e.f.!\n")); + break; /* stop scanning this field */ + } + } else { + /* cannot determine, safe assumption is FALSE */ + ut_in_archive_sgn = 0; + z_utim->mtime = (time_t)i_time; + } +#else /* !TIME_T_TYPE_DOUBLE */ + if ((ulg)(i_time) & (ulg)(0x80000000L)) { + ut_zip_unzip_compatible = + ((time_t)0x80000000L < (time_t)0L) + ? (dos_mdatetime == DOSTIME_MINIMUM) + : (dos_mdatetime >= DOSTIME_2038_01_18); + if (!ut_zip_unzip_compatible) { + /* UnZip interprets mtime differently than Zip; + without modtime: ignore complete UT field */ + flags &= ~0x0ff; /* no time_t times available */ + TTrace((stderr, + " UT modtime range error; ignore e.f.!\n")); + break; /* stop scanning this field */ + } + } else { + /* cannot determine, safe assumption is FALSE */ + ut_zip_unzip_compatible = FALSE; + } + z_utim->mtime = (time_t)i_time; +#endif /* ?TIME_T_TYPE_DOUBLE */ + } else { + flags &= ~EB_UT_FL_MTIME; + TTrace((stderr," UT e.f. truncated; no modtime\n")); + } + } + if (ef_is_c) { + break; /* central version of TIME field ends here */ + } + + if (flags & EB_UT_FL_ATIME) { + if ((eb_idx+4) <= eb_len) { + i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); + eb_idx += 4; + TTrace((stderr," UT e.f. access time = %ld\n", + i_time)); +#ifdef TIME_T_TYPE_DOUBLE + if ((ulg)(i_time) & (ulg)(0x80000000L)) { + if (ut_in_archive_sgn == -1) + z_utim->atime = + (time_t)((long)i_time | (~(long)0x7fffffffL)); + } else if (ut_in_archive_sgn == 1) { + z_utim->atime = + (time_t)((ulg)i_time & (ulg)0xffffffffL); + } else { + /* sign of 32-bit time is unknown -> ignore it */ + flags &= ~EB_UT_FL_ATIME; + TTrace((stderr, + " UT access time range error: skip time!\n")); + } + } else { + z_utim->atime = (time_t)i_time; + } +#else /* !TIME_T_TYPE_DOUBLE */ + if (((ulg)(i_time) & (ulg)(0x80000000L)) && + !ut_zip_unzip_compatible) { + flags &= ~EB_UT_FL_ATIME; + TTrace((stderr, + " UT access time range error: skip time!\n")); + } else { + z_utim->atime = (time_t)i_time; + } +#endif /* ?TIME_T_TYPE_DOUBLE */ + } else { + flags &= ~EB_UT_FL_ATIME; + } + } + if (flags & EB_UT_FL_CTIME) { + if ((eb_idx+4) <= eb_len) { + i_time = (long)makelong((EB_HEADSIZE+eb_idx) + ef_buf); + TTrace((stderr," UT e.f. creation time = %ld\n", + i_time)); +#ifdef TIME_T_TYPE_DOUBLE + if ((ulg)(i_time) & (ulg)(0x80000000L)) { + if (ut_in_archive_sgn == -1) + z_utim->ctime = + (time_t)((long)i_time | (~(long)0x7fffffffL)); + } else if (ut_in_archive_sgn == 1) { + z_utim->ctime = + (time_t)((ulg)i_time & (ulg)0xffffffffL); + } else { + /* sign of 32-bit time is unknown -> ignore it */ + flags &= ~EB_UT_FL_CTIME; + TTrace((stderr, + " UT creation time range error: skip time!\n")); + } + } else { + z_utim->ctime = (time_t)i_time; + } +#else /* !TIME_T_TYPE_DOUBLE */ + if (((ulg)(i_time) & (ulg)(0x80000000L)) && + !ut_zip_unzip_compatible) { + flags &= ~EB_UT_FL_CTIME; + TTrace((stderr, + " UT creation time range error: skip time!\n")); + } else { + z_utim->ctime = (time_t)i_time; + } +#endif /* ?TIME_T_TYPE_DOUBLE */ + } else { + flags &= ~EB_UT_FL_CTIME; + } + } + } + break; + + case EF_IZUNIX2: + if (have_new_type_eb == 0) { + flags &= ~0x0ff; /* ignore any previous IZUNIX field */ + have_new_type_eb = 1; + } +#ifdef IZ_HAVE_UXUIDGID + if (have_new_type_eb > 1) + break; /* IZUNIX3 overrides IZUNIX2 e.f. block ! */ + if (eb_len == EB_UX2_MINLEN && z_uidgid != NULL) { + z_uidgid[0] = (ulg)makeword((EB_HEADSIZE+EB_UX2_UID) + ef_buf); + z_uidgid[1] = (ulg)makeword((EB_HEADSIZE+EB_UX2_GID) + ef_buf); + flags |= EB_UX2_VALID; /* signal success */ + } +#endif + break; + + case EF_IZUNIX3: + /* new 3rd generation Unix ef */ + have_new_type_eb = 2; + + /* + Version 1 byte version of this extra field, currently 1 + UIDSize 1 byte Size of UID field + UID Variable UID for this entry + GIDSize 1 byte Size of GID field + GID Variable GID for this entry + */ + +#ifdef IZ_HAVE_UXUIDGID + if ((eb_len >= EB_UX3_MINLEN) + && (z_uidgid != NULL) + && ((*((EB_HEADSIZE + 0) + ef_buf) == 1))) + /* only know about version 1 */ + { + uch uid_size; + uch gid_size; + + uid_size = *((EB_HEADSIZE + 1) + ef_buf); + gid_size = *((EB_HEADSIZE + uid_size + 2) + ef_buf); + + flags &= ~0x0ff; /* ignore any previous UNIX field */ + + if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf, + uid_size, &z_uidgid[0]) + && + read_ux3_value((EB_HEADSIZE + uid_size + 3) + ef_buf, + gid_size, &z_uidgid[1]) ) + { + flags |= EB_UX2_VALID; /* signal success */ + } + } +#endif /* IZ_HAVE_UXUIDGID */ + break; + + case EF_IZUNIX: + case EF_PKUNIX: /* PKUNIX e.f. layout is identical to IZUNIX */ + if (eb_len >= EB_UX_MINLEN) { + TTrace((stderr,"ef_scan_for_izux: found %s extra field\n", + (eb_id == EF_IZUNIX ? "IZUNIX" : "PKUNIX"))); + if (have_new_type_eb > 0) { + break; /* Ignore IZUNIX extra field block ! */ + } + if (z_utim != NULL) { + flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME); + i_time = (long)makelong((EB_HEADSIZE+EB_UX_MTIME)+ef_buf); + TTrace((stderr," Unix EF modtime = %ld\n", i_time)); +#ifdef TIME_T_TYPE_DOUBLE + if ((ulg)(i_time) & (ulg)(0x80000000L)) { + if (dos_mdatetime == DOSTIME_MINIMUM) { + ut_in_archive_sgn = -1; + z_utim->mtime = + (time_t)((long)i_time | (~(long)0x7fffffffL)); + } else if (dos_mdatetime >= DOSTIME_2038_01_18) { + ut_in_archive_sgn = 1; + z_utim->mtime = + (time_t)((ulg)i_time & (ulg)0xffffffffL); + } else { + ut_in_archive_sgn = 0; + /* cannot determine sign of mtime; + without modtime: ignore complete UT field */ + flags &= ~0x0ff; /* no time_t times available */ + TTrace((stderr, + " UX modtime range error: ignore e.f.!\n")); + } + } else { + /* cannot determine, safe assumption is FALSE */ + ut_in_archive_sgn = 0; + z_utim->mtime = (time_t)i_time; + } +#else /* !TIME_T_TYPE_DOUBLE */ + if ((ulg)(i_time) & (ulg)(0x80000000L)) { + ut_zip_unzip_compatible = + ((time_t)0x80000000L < (time_t)0L) + ? (dos_mdatetime == DOSTIME_MINIMUM) + : (dos_mdatetime >= DOSTIME_2038_01_18); + if (!ut_zip_unzip_compatible) { + /* UnZip interpretes mtime differently than Zip; + without modtime: ignore complete UT field */ + flags &= ~0x0ff; /* no time_t times available */ + TTrace((stderr, + " UX modtime range error: ignore e.f.!\n")); + } + } else { + /* cannot determine, safe assumption is FALSE */ + ut_zip_unzip_compatible = FALSE; + } + z_utim->mtime = (time_t)i_time; +#endif /* ?TIME_T_TYPE_DOUBLE */ + i_time = (long)makelong((EB_HEADSIZE+EB_UX_ATIME)+ef_buf); + TTrace((stderr," Unix EF actime = %ld\n", i_time)); +#ifdef TIME_T_TYPE_DOUBLE + if ((ulg)(i_time) & (ulg)(0x80000000L)) { + if (ut_in_archive_sgn == -1) + z_utim->atime = + (time_t)((long)i_time | (~(long)0x7fffffffL)); + } else if (ut_in_archive_sgn == 1) { + z_utim->atime = + (time_t)((ulg)i_time & (ulg)0xffffffffL); + } else if (flags & 0x0ff) { + /* sign of 32-bit time is unknown -> ignore it */ + flags &= ~EB_UT_FL_ATIME; + TTrace((stderr, + " UX access time range error: skip time!\n")); + } + } else { + z_utim->atime = (time_t)i_time; + } +#else /* !TIME_T_TYPE_DOUBLE */ + if (((ulg)(i_time) & (ulg)(0x80000000L)) && + !ut_zip_unzip_compatible && (flags & 0x0ff)) { + /* atime not in range of UnZip's time_t */ + flags &= ~EB_UT_FL_ATIME; + TTrace((stderr, + " UX access time range error: skip time!\n")); + } else { + z_utim->atime = (time_t)i_time; + } +#endif /* ?TIME_T_TYPE_DOUBLE */ + } +#ifdef IZ_HAVE_UXUIDGID + if (eb_len >= EB_UX_FULLSIZE && z_uidgid != NULL) { + z_uidgid[0] = makeword((EB_HEADSIZE+EB_UX_UID) + ef_buf); + z_uidgid[1] = makeword((EB_HEADSIZE+EB_UX_GID) + ef_buf); + flags |= EB_UX2_VALID; + } +#endif /* IZ_HAVE_UXUIDGID */ + } + break; + + default: + break; + } + + /* Skip this extra field block */ + ef_buf += (eb_len + EB_HEADSIZE); + ef_len -= (eb_len + EB_HEADSIZE); + } + + return flags; +} + +#endif /* USE_EF_UT_TIME */ + + +#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) + +#define SPARKID_2 0x30435241 /* = "ARC0" */ + +/*******************************/ +/* Function getRISCOSexfield() */ +/*******************************/ + +zvoid *getRISCOSexfield(ef_buf, ef_len) + ZCONST uch *ef_buf; /* buffer containing extra field */ + unsigned ef_len; /* total length of extra field */ +{ + unsigned eb_id; + unsigned eb_len; + +/*--------------------------------------------------------------------------- + This function scans the extra field for a Acorn SPARK filetype ef-block. + If a valid block is found, the function returns a pointer to the start + of the SPARK_EF block in the extra field buffer. Otherwise, a NULL + pointer is returned. + ---------------------------------------------------------------------------*/ + + if (ef_len == 0 || ef_buf == NULL) + return NULL; + + Trace((stderr,"\ngetRISCOSexfield: scanning extra field of length %u\n", + ef_len)); + + while (ef_len >= EB_HEADSIZE) { + eb_id = makeword(EB_ID + ef_buf); + eb_len = makeword(EB_LEN + ef_buf); + + if (eb_len > (ef_len - EB_HEADSIZE)) { + /* discovered some extra field inconsistency! */ + Trace((stderr, + "getRISCOSexfield: block length %u > rest ef_size %u\n", eb_len, + ef_len - EB_HEADSIZE)); + break; + } + + if (eb_id == EF_SPARK && (eb_len == 24 || eb_len == 20)) { + if (makelong(EB_HEADSIZE + ef_buf) == SPARKID_2) { + /* Return a pointer to the valid SPARK filetype ef block */ + return (zvoid *)ef_buf; + } + } + + /* Skip this extra field block */ + ef_buf += (eb_len + EB_HEADSIZE); + ef_len -= (eb_len + EB_HEADSIZE); + } + + return NULL; +} + +#endif /* (RISCOS || ACORN_FTYPE_NFS) */ diff -Naur a/unix/configure b/unix/configure --- a/unix/configure 2009-04-16 20:25:12.000000000 +0100 +++ b/unix/configure 2019-12-01 23:54:04.330597267 +0000 @@ -17,7 +17,7 @@ IZ_BZIP2=${3} CFLAGS="${CFLAGS} -I. -DUNIX" LFLAGS1="" -LFLAGS2="-s" +LFLAGS2="${LFLAGS2}" LN="ln -s" CFLAGS_OPT='' @@ -640,7 +640,24 @@ D_USE_BZ2="-DUSE_BZIP2" L_BZ2="${BZLF} -lbz2" else - echo "-- bzip2 sources not found - no bzip2 support" + echo " Check if OS already has bzip2 library installed" + cat > conftest.c << _EOF_ +#include "bzlib.h" +int main() +{ + bz_stream strm; + BZ2_bzCompressEnd(&strm); + return 0; +} +_EOF_ + $CC $CFLAGS -o conftest conftest.c -lbz2 > /dev/null 2>/dev/null + if test $? -eq 0; then + echo "-- OS supports bzip2 - linking in bzip2" + D_USE_BZ2="-DUSE_BZIP2" + L_BZ2="${BZLF} -lbz2" + else + echo "-- Either bzlib.h or libbz2.a not found - no bzip2" + fi fi fi diff -Naur a/unix/unix.c b/unix/unix.c --- a/unix/unix.c 2009-01-23 23:31:26.000000000 +0000 +++ b/unix/unix.c 2019-12-02 01:49:39.894641004 +0000 @@ -30,6 +30,9 @@ #define UNZIP_INTERNAL #include "unzip.h" +#include +#include + #ifdef SCO_XENIX # define SYSNDIR #else /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */ @@ -1096,10 +1099,41 @@ #ifndef MTS /****************************/ +/* Function CloseError() */ +/***************************/ + +int CloseError(__G) + __GDEF +{ + int errval = PK_OK; + + if (fclose(G.outfile) < 0) { + switch (errno) { + case ENOSPC: + /* Do we need this on fileio.c? */ + Info(slide, 0x4a1, ((char *)slide, "%s: write error (disk full?). Continue? (y/n/^C) ", + FnFilter1(G.filename))); + fgets(G.answerbuf, 9, stdin); + if (*G.answerbuf == 'y') /* stop writing to this file */ + G.disk_full = 1; /* pass to next */ + else + G.disk_full = 2; /* no: exit program */ + + errval = PK_DISK; + break; + + default: + errval = PK_WARN; + } + } + return errval; +} /* End of CloseError() */ + +/****************************/ /* Function close_outfile() */ /****************************/ -void close_outfile(__G) /* GRR: change to return PK-style warning level */ +int close_outfile(__G) __GDEF { union { @@ -1108,6 +1142,7 @@ } zt; ulg z_uidgid[2]; int have_uidgid_flg; + int errval = PK_OK; have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid); @@ -1141,16 +1176,16 @@ Info(slide, 0x201, ((char *)slide, "warning: symbolic link (%s) failed: mem alloc overflow\n", FnFilter1(G.filename))); - fclose(G.outfile); - return; + errval = CloseError(G.outfile, G.filename); + return errval ? errval : PK_WARN; } if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) { Info(slide, 0x201, ((char *)slide, "warning: symbolic link (%s) failed: no mem\n", FnFilter1(G.filename))); - fclose(G.outfile); - return; + errval = CloseError(G.outfile, G.filename); + return errval ? errval : PK_WARN; } slnk_entry->next = NULL; slnk_entry->targetlen = ucsize; @@ -1174,10 +1209,10 @@ "warning: symbolic link (%s) failed\n", FnFilter1(G.filename))); free(slnk_entry); - fclose(G.outfile); - return; + errval = CloseError(G.outfile, G.filename); + return errval ? errval : PK_WARN; } - fclose(G.outfile); /* close "link" file for good... */ + errval = CloseError(G.outfile, G.filename); /* close "link" file for good... */ slnk_entry->target[ucsize] = '\0'; if (QCOND2) Info(slide, 0, ((char *)slide, "-> %s ", @@ -1188,7 +1223,7 @@ else G.slink_head = slnk_entry; G.slink_last = slnk_entry; - return; + return errval; } #endif /* SYMLINKS */ @@ -1201,7 +1236,7 @@ #endif #if (defined(NO_FCHOWN)) - fclose(G.outfile); + errval = CloseError(G.outfile, G.filename); #endif /* if -X option was specified and we have UID/GID info, restore it */ @@ -1227,7 +1262,7 @@ } #if (!defined(NO_FCHOWN) && defined(NO_FCHMOD)) - fclose(G.outfile); + errval = CloseError(G.outfile, G.filename); #endif #if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD)) @@ -1239,7 +1274,7 @@ if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr))) perror("fchmod (file attributes) error"); - fclose(G.outfile); + errval = CloseError(G.outfile, G.filename); #endif /* !NO_FCHOWN && !NO_FCHMOD */ /* skip restoring time stamps on user's request */ @@ -1267,6 +1302,7 @@ #endif #endif /* NO_FCHOWN || NO_FCHMOD */ + return errval; } /* end function close_outfile() */ #endif /* !MTS */ @@ -1874,3 +1910,104 @@ } } #endif /* QLZIP */ + + +typedef struct { + char *local_charset; + char *archive_charset; +} CHARSET_MAP; + +/* A mapping of local <-> archive charsets used by default to convert filenames + * of DOS/Windows Zip archives. Currently very basic. */ +static CHARSET_MAP dos_charset_map[] = { + { "ANSI_X3.4-1968", "CP850" }, + { "ISO-8859-1", "CP850" }, + { "CP1252", "CP850" }, + { "UTF-8", "CP866" }, + { "KOI8-R", "CP866" }, + { "KOI8-U", "CP866" }, + { "ISO-8859-5", "CP866" } +}; + +char OEM_CP[MAX_CP_NAME] = ""; +char ISO_CP[MAX_CP_NAME] = ""; + +/* Try to guess the default value of OEM_CP based on the current locale. + * ISO_CP is left alone for now. */ +void init_conversion_charsets() +{ + const char *local_charset; + int i; + + /* Make a guess only if OEM_CP not already set. */ + if(*OEM_CP == '\0') { + local_charset = nl_langinfo(CODESET); + for(i = 0; i < sizeof(dos_charset_map)/sizeof(CHARSET_MAP); i++) + if(!strcasecmp(local_charset, dos_charset_map[i].local_charset)) { + strncpy(OEM_CP, dos_charset_map[i].archive_charset, + MAX_CP_NAME - 1); + + OEM_CP[MAX_CP_NAME - 1] = '\0'; + break; + } + } +} + +/* Convert a string from one encoding to the current locale using iconv(). + * Be as non-intrusive as possible. If error is encountered during covertion + * just leave the string intact. */ +static void charset_to_intern(char *string, char *from_charset) +{ + iconv_t cd; + char *s,*d, *buf; + size_t slen, dlen, buflen; + const char *local_charset; + + if(*from_charset == '\0') + return; + + buf = NULL; + local_charset = nl_langinfo(CODESET); + + if((cd = iconv_open(local_charset, from_charset)) == (iconv_t)-1) + return; + + slen = strlen(string); + s = string; + + /* Make sure OUTBUFSIZ + 1 never ends up smaller than FILNAMSIZ + * as this function also gets called with G.outbuf in fileio.c + */ + buflen = FILNAMSIZ; + if (OUTBUFSIZ + 1 < FILNAMSIZ) + { + buflen = OUTBUFSIZ + 1; + } + + d = buf = malloc(buflen); + if(!d) + goto cleanup; + + bzero(buf,buflen); + dlen = buflen - 1; + + if(iconv(cd, &s, &slen, &d, &dlen) == (size_t)-1) + goto cleanup; + strncpy(string, buf, buflen); + + cleanup: + free(buf); + iconv_close(cd); +} + +/* Convert a string from OEM_CP to the current locale charset. */ +inline void oem_intern(char *string) +{ + charset_to_intern(string, OEM_CP); +} + +/* Convert a string from ISO_CP to the current locale charset. */ +inline void iso_intern(char *string) +{ + charset_to_intern(string, ISO_CP); +} diff -Naur a/unix/unix.c.orig b/unix/unix.c.orig --- a/unix/unix.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ b/unix/unix.c.orig 2019-12-01 23:53:08.675401658 +0000 @@ -0,0 +1,1909 @@ +/* + Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2009-Jan-02 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 +*/ +/*--------------------------------------------------------------------------- + + unix.c + + Unix-specific routines for use with Info-ZIP's UnZip 5.41 and later. + + Contains: readdir() + do_wild() <-- generic enough to put in fileio.c? + mapattr() + mapname() + checkdir() + mkdir() + close_outfile() + defer_dir_attribs() + set_direc_attribs() + stamp_file() + version() + + ---------------------------------------------------------------------------*/ + + +#define UNZIP_INTERNAL +#include "unzip.h" + +#ifdef SCO_XENIX +# define SYSNDIR +#else /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */ +# if defined(__convexc__) || defined(SYSV) || defined(CRAY) || defined(BSD4_4) +# define DIRENT +# endif +#endif +#if defined(_AIX) || defined(__mpexl) +# define DIRENT +#endif +#ifdef COHERENT +# if defined(_I386) || (defined(__COHERENT__) && (__COHERENT__ >= 0x420)) +# define DIRENT +# endif +#endif + +#ifdef _POSIX_VERSION +# ifndef DIRENT +# define DIRENT +# endif +#endif + +#ifdef DIRENT +# include +#else +# ifdef SYSV +# ifdef SYSNDIR +# include +# else +# include +# endif +# else /* !SYSV */ +# ifndef NO_SYSDIR +# include +# endif +# endif /* ?SYSV */ +# ifndef dirent +# define dirent direct +# endif +#endif /* ?DIRENT */ + +#ifdef SET_DIR_ATTRIB +typedef struct uxdirattr { /* struct for holding unix style directory */ + struct uxdirattr *next; /* info until can be sorted and set at end */ + char *fn; /* filename of directory */ + union { + iztimes t3; /* mtime, atime, ctime */ + ztimbuf t2; /* modtime, actime */ + } u; + unsigned perms; /* same as min_info.file_attr */ + int have_uidgid; /* flag */ + ulg uidgid[2]; + char fnbuf[1]; /* buffer stub for directory name */ +} uxdirattr; +#define UxAtt(d) ((uxdirattr *)d) /* typecast shortcut */ +#endif /* SET_DIR_ATTRIB */ + +#ifdef ACORN_FTYPE_NFS +/* Acorn bits for NFS filetyping */ +typedef struct { + uch ID[2]; + uch size[2]; + uch ID_2[4]; + uch loadaddr[4]; + uch execaddr[4]; + uch attr[4]; +} RO_extra_block; + +#endif /* ACORN_FTYPE_NFS */ + +/* static int created_dir; */ /* used in mapname(), checkdir() */ +/* static int renamed_fullpath; */ /* ditto */ + +static unsigned filtattr OF((__GPRO__ unsigned perms)); + + +/*****************************/ +/* Strings used multiple */ +/* times in unix.c */ +/*****************************/ + +#ifndef MTS +/* messages of code for setting file/directory attributes */ +static ZCONST char CannotSetItemUidGid[] = + "warning: cannot set UID %lu and/or GID %lu for %s\n %s\n"; +static ZCONST char CannotSetUidGid[] = + " (warning) cannot set UID %lu and/or GID %lu\n %s"; +static ZCONST char CannotSetItemTimestamps[] = + "warning: cannot set modif./access times for %s\n %s\n"; +static ZCONST char CannotSetTimestamps[] = + " (warning) cannot set modif./access times\n %s"; +#endif /* !MTS */ + + +#ifndef SFX +#ifdef NO_DIR /* for AT&T 3B1 */ + +#define opendir(path) fopen(path,"r") +#define closedir(dir) fclose(dir) +typedef FILE DIR; +typedef struct zdir { + FILE *dirhandle; + struct dirent *entry; +} DIR +DIR *opendir OF((ZCONST char *dirspec)); +void closedir OF((DIR *dirp)); +struct dirent *readdir OF((DIR *dirp)); + +DIR *opendir(dirspec) + ZCONST char *dirspec; +{ + DIR *dirp; + + if ((dirp = malloc(sizeof(DIR)) != NULL) { + if ((dirp->dirhandle = fopen(dirspec, "r")) == NULL) { + free(dirp); + dirp = NULL; + } + } + return dirp; +} + +void closedir(dirp) + DIR *dirp; +{ + fclose(dirp->dirhandle); + free(dirp); +} + +/* + * Apparently originally by Rich Salz. + * Cleaned up and modified by James W. Birdsall. + */ +struct dirent *readdir(dirp) + DIR *dirp; +{ + + if (dirp == NULL) + return NULL; + + for (;;) + if (fread(&(dirp->entry), sizeof (struct dirent), 1, + dirp->dirhandle) == 0) + return (struct dirent *)NULL; + else if ((dirp->entry).d_ino) + return &(dirp->entry); + +} /* end function readdir() */ + +#endif /* NO_DIR */ + + +/**********************/ +/* Function do_wild() */ /* for porting: dir separator; match(ignore_case) */ +/**********************/ + +char *do_wild(__G__ wildspec) + __GDEF + ZCONST char *wildspec; /* only used first time on a given dir */ +{ +/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in unxcfg.h: + static DIR *wild_dir = (DIR *)NULL; + static ZCONST char *wildname; + static char *dirname, matchname[FILNAMSIZ]; + static int notfirstcall=FALSE, have_dirname, dirnamelen; +*/ + struct dirent *file; + + /* Even when we're just returning wildspec, we *always* do so in + * matchname[]--calling routine is allowed to append four characters + * to the returned string, and wildspec may be a pointer to argv[]. + */ + if (!G.notfirstcall) { /* first call: must initialize everything */ + G.notfirstcall = TRUE; + + if (!iswild(wildspec)) { + strncpy(G.matchname, wildspec, FILNAMSIZ); + G.matchname[FILNAMSIZ-1] = '\0'; + G.have_dirname = FALSE; + G.wild_dir = NULL; + return G.matchname; + } + + /* break the wildspec into a directory part and a wildcard filename */ + if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL) { + G.dirname = "."; + G.dirnamelen = 1; + G.have_dirname = FALSE; + G.wildname = wildspec; + } else { + ++G.wildname; /* point at character after '/' */ + G.dirnamelen = G.wildname - wildspec; + if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == (char *)NULL) { + Info(slide, 0x201, ((char *)slide, + "warning: cannot allocate wildcard buffers\n")); + strncpy(G.matchname, wildspec, FILNAMSIZ); + G.matchname[FILNAMSIZ-1] = '\0'; + return G.matchname; /* but maybe filespec was not a wildcard */ + } + strncpy(G.dirname, wildspec, G.dirnamelen); + G.dirname[G.dirnamelen] = '\0'; /* terminate for strcpy below */ + G.have_dirname = TRUE; + } + + if ((G.wild_dir = (zvoid *)opendir(G.dirname)) != (zvoid *)NULL) { + while ((file = readdir((DIR *)G.wild_dir)) != + (struct dirent *)NULL) { + Trace((stderr, "do_wild: readdir returns %s\n", + FnFilter1(file->d_name))); + if (file->d_name[0] == '.' && G.wildname[0] != '.') + continue; /* Unix: '*' and '?' do not match leading dot */ + if (match(file->d_name, G.wildname, 0 WISEP) &&/*0=case sens.*/ + /* skip "." and ".." directory entries */ + strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) { + Trace((stderr, "do_wild: match() succeeds\n")); + if (G.have_dirname) { + strcpy(G.matchname, G.dirname); + strcpy(G.matchname+G.dirnamelen, file->d_name); + } else + strcpy(G.matchname, file->d_name); + return G.matchname; + } + } + /* if we get to here directory is exhausted, so close it */ + closedir((DIR *)G.wild_dir); + G.wild_dir = (zvoid *)NULL; + } + Trace((stderr, "do_wild: opendir(%s) returns NULL\n", + FnFilter1(G.dirname))); + + /* return the raw wildspec in case that works (e.g., directory not + * searchable, but filespec was not wild and file is readable) */ + strncpy(G.matchname, wildspec, FILNAMSIZ); + G.matchname[FILNAMSIZ-1] = '\0'; + return G.matchname; + } + + /* last time through, might have failed opendir but returned raw wildspec */ + if ((DIR *)G.wild_dir == (DIR *)NULL) { + G.notfirstcall = FALSE; /* nothing left--reset for new wildspec */ + if (G.have_dirname) + free(G.dirname); + return (char *)NULL; + } + + /* If we've gotten this far, we've read and matched at least one entry + * successfully (in a previous call), so dirname has been copied into + * matchname already. + */ + while ((file = readdir((DIR *)G.wild_dir)) != (struct dirent *)NULL) { + Trace((stderr, "do_wild: readdir returns %s\n", + FnFilter1(file->d_name))); + if (file->d_name[0] == '.' && G.wildname[0] != '.') + continue; /* Unix: '*' and '?' do not match leading dot */ + if (match(file->d_name, G.wildname, 0 WISEP)) { /* 0 == case sens. */ + Trace((stderr, "do_wild: match() succeeds\n")); + if (G.have_dirname) { + /* strcpy(G.matchname, G.dirname); */ + strcpy(G.matchname+G.dirnamelen, file->d_name); + } else + strcpy(G.matchname, file->d_name); + return G.matchname; + } + } + + closedir((DIR *)G.wild_dir); /* at least one entry read; nothing left */ + G.wild_dir = (zvoid *)NULL; + G.notfirstcall = FALSE; /* reset for new wildspec */ + if (G.have_dirname) + free(G.dirname); + return (char *)NULL; + +} /* end function do_wild() */ + +#endif /* !SFX */ + + + + +#ifndef S_ISUID +# define S_ISUID 0004000 /* set user id on execution */ +#endif +#ifndef S_ISGID +# define S_ISGID 0002000 /* set group id on execution */ +#endif +#ifndef S_ISVTX +# define S_ISVTX 0001000 /* save swapped text even after use */ +#endif + +/************************/ +/* Function filtattr() */ +/************************/ +/* This is used to clear or keep the SUID and SGID bits on file permissions. + * It's possible that a file in an archive could have one of these bits set + * and, unknown to the person unzipping, could allow others to execute the + * file as the user or group. The new option -K bypasses this check. + */ + +static unsigned filtattr(__G__ perms) + __GDEF + unsigned perms; +{ + /* keep setuid/setgid/tacky perms? */ + if (!uO.K_flag) + perms &= ~(S_ISUID | S_ISGID | S_ISVTX); + + return (0xffff & perms); +} /* end function filtattr() */ + + + + + +/**********************/ +/* Function mapattr() */ +/**********************/ + +int mapattr(__G) + __GDEF +{ + int r; + ulg tmp = G.crec.external_file_attributes; + + G.pInfo->file_attr = 0; + /* initialized to 0 for check in "default" branch below... */ + + switch (G.pInfo->hostnum) { + case AMIGA_: + tmp = (unsigned)(tmp>>17 & 7); /* Amiga RWE bits */ + G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp); + break; + case THEOS_: + tmp &= 0xF1FFFFFFL; + if ((tmp & 0xF0000000L) != 0x40000000L) + tmp &= 0x01FFFFFFL; /* not a dir, mask all ftype bits */ + else + tmp &= 0x41FFFFFFL; /* leave directory bit as set */ + /* fall through! */ + case UNIX_: + case VMS_: + case ACORN_: + case ATARI_: + case ATHEOS_: + case BEOS_: + case QDOS_: + case TANDEM_: + r = FALSE; + G.pInfo->file_attr = (unsigned)(tmp >> 16); + if (G.pInfo->file_attr == 0 && G.extra_field) { + /* Some (non-Info-ZIP) implementations of Zip for Unix and + * VMS (and probably others ??) leave 0 in the upper 16-bit + * part of the external_file_attributes field. Instead, they + * store file permission attributes in some extra field. + * As a work-around, we search for the presence of one of + * these extra fields and fall back to the MSDOS compatible + * part of external_file_attributes if one of the known + * e.f. types has been detected. + * Later, we might implement extraction of the permission + * bits from the VMS extra field. But for now, the work-around + * should be sufficient to provide "readable" extracted files. + * (For ASI Unix e.f., an experimental remap of the e.f. + * mode value IS already provided!) + */ + ush ebID; + unsigned ebLen; + uch *ef = G.extra_field; + unsigned ef_len = G.crec.extra_field_length; + + while (!r && ef_len >= EB_HEADSIZE) { + ebID = makeword(ef); + ebLen = (unsigned)makeword(ef+EB_LEN); + if (ebLen > (ef_len - EB_HEADSIZE)) + /* discoverd some e.f. inconsistency! */ + break; + switch (ebID) { + case EF_ASIUNIX: + if (ebLen >= (EB_ASI_MODE+2)) { + G.pInfo->file_attr = + (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE)); + /* force stop of loop: */ + ef_len = (ebLen + EB_HEADSIZE); + break; + } + /* else: fall through! */ + case EF_PKVMS: + /* "found nondecypherable e.f. with perm. attr" */ + r = TRUE; + default: + break; + } + ef_len -= (ebLen + EB_HEADSIZE); + ef += (ebLen + EB_HEADSIZE); + } + } + if (!r) { +#ifdef SYMLINKS + /* Check if the file is a (POSIX-compatible) symbolic link. + * We restrict symlink support to those "made-by" hosts that + * are known to support symbolic links. + */ + G.pInfo->symlink = S_ISLNK(G.pInfo->file_attr) && + SYMLINK_HOST(G.pInfo->hostnum); +#endif + return 0; + } + /* fall through! */ + /* all remaining cases: expand MSDOS read-only bit into write perms */ + case FS_FAT_: + /* PKWARE's PKZip for Unix marks entries as FS_FAT_, but stores the + * Unix attributes in the upper 16 bits of the external attributes + * field, just like Info-ZIP's Zip for Unix. We try to use that + * value, after a check for consistency with the MSDOS attribute + * bits (see below). + */ + G.pInfo->file_attr = (unsigned)(tmp >> 16); + /* fall through! */ + case FS_HPFS_: + case FS_NTFS_: + case MAC_: + case TOPS20_: + default: + /* Ensure that DOS subdir bit is set when the entry's name ends + * in a '/'. Some third-party Zip programs fail to set the subdir + * bit for directory entries. + */ + if ((tmp & 0x10) == 0) { + extent fnlen = strlen(G.filename); + if (fnlen > 0 && G.filename[fnlen-1] == '/') + tmp |= 0x10; + } + /* read-only bit --> write perms; subdir bit --> dir exec bit */ + tmp = !(tmp & 1) << 1 | (tmp & 0x10) >> 4; + if ((G.pInfo->file_attr & 0700) == (unsigned)(0400 | tmp<<6)) { + /* keep previous G.pInfo->file_attr setting, when its "owner" + * part appears to be consistent with DOS attribute flags! + */ +#ifdef SYMLINKS + /* Entries "made by FS_FAT_" could have been zipped on a + * system that supports POSIX-style symbolic links. + */ + G.pInfo->symlink = S_ISLNK(G.pInfo->file_attr) && + (G.pInfo->hostnum == FS_FAT_); +#endif + return 0; + } + G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp); + break; + } /* end switch (host-OS-created-by) */ + + /* for originating systems with no concept of "group," "other," "system": */ + umask( (int)(tmp=umask(0)) ); /* apply mask to expanded r/w(/x) perms */ + G.pInfo->file_attr &= ~tmp; + + return 0; + +} /* end function mapattr() */ + + + + + +/************************/ +/* Function mapname() */ +/************************/ + +int mapname(__G__ renamed) + __GDEF + int renamed; +/* + * returns: + * MPN_OK - no problem detected + * MPN_INF_TRUNC - caution (truncated filename) + * MPN_INF_SKIP - info "skip entry" (dir doesn't exist) + * MPN_ERR_SKIP - error -> skip entry + * MPN_ERR_TOOLONG - error -> path is too long + * MPN_NOMEM - error (memory allocation failed) -> skip entry + * [also MPN_VOL_LABEL, MPN_CREATED_DIR] + */ +{ + char pathcomp[FILNAMSIZ]; /* path-component buffer */ + char *pp, *cp=(char *)NULL; /* character pointers */ + char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */ +#ifdef ACORN_FTYPE_NFS + char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */ + RO_extra_block *ef_spark; /* pointer Acorn FTYPE ef block */ +#endif + int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */ + int error = MPN_OK; + register unsigned workch; /* hold the character being tested */ + + +/*--------------------------------------------------------------------------- + Initialize various pointers and counters and stuff. + ---------------------------------------------------------------------------*/ + + if (G.pInfo->vollabel) + return MPN_VOL_LABEL; /* can't set disk volume labels in Unix */ + + /* can create path as long as not just freshening, or if user told us */ + G.create_dirs = (!uO.fflag || renamed); + + G.created_dir = FALSE; /* not yet */ + + /* user gave full pathname: don't prepend rootpath */ + G.renamed_fullpath = (renamed && (*G.filename == '/')); + + if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM) + return MPN_NOMEM; /* initialize path buffer, unless no memory */ + + *pathcomp = '\0'; /* initialize translation buffer */ + pp = pathcomp; /* point to translation buffer */ + if (uO.jflag) /* junking directories */ + cp = (char *)strrchr(G.filename, '/'); + if (cp == (char *)NULL) /* no '/' or not junking dirs */ + cp = G.filename; /* point to internal zipfile-member pathname */ + else + ++cp; /* point to start of last component of path */ + +/*--------------------------------------------------------------------------- + Begin main loop through characters in filename. + ---------------------------------------------------------------------------*/ + + while ((workch = (uch)*cp++) != 0) { + + switch (workch) { + case '/': /* can assume -j flag not given */ + *pp = '\0'; + if (strcmp(pathcomp, ".") == 0) { + /* don't bother appending "./" to the path */ + *pathcomp = '\0'; + } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) { + /* "../" dir traversal detected, skip over it */ + *pathcomp = '\0'; + killed_ddot = TRUE; /* set "show message" flag */ + } + /* when path component is not empty, append it now */ + if (*pathcomp != '\0' && + ((error = checkdir(__G__ pathcomp, APPEND_DIR)) + & MPN_MASK) > MPN_INF_TRUNC) + return error; + pp = pathcomp; /* reset conversion buffer for next piece */ + lastsemi = (char *)NULL; /* leave direct. semi-colons alone */ + break; + +#ifdef __CYGWIN__ /* Cygwin runs on Win32, apply FAT/NTFS filename rules */ + case ':': /* drive spec not stored, so no colon allowed */ + case '\\': /* '\\' may come as normal filename char (not */ + case '<': /* dir sep char!) from unix-like file system */ + case '>': /* no redirection symbols allowed either */ + case '|': /* no pipe signs allowed */ + case '"': /* no double quotes allowed */ + case '?': /* no wildcards allowed */ + case '*': + *pp++ = '_'; /* these rules apply equally to FAT and NTFS */ + break; +#endif + + case ';': /* VMS version (or DEC-20 attrib?) */ + lastsemi = pp; + *pp++ = ';'; /* keep for now; remove VMS ";##" */ + break; /* later, if requested */ + +#ifdef ACORN_FTYPE_NFS + case ',': /* NFS filetype extension */ + lastcomma = pp; + *pp++ = ','; /* keep for now; may need to remove */ + break; /* later, if requested */ +#endif + +#ifdef MTS + case ' ': /* change spaces to underscore under */ + *pp++ = '_'; /* MTS; leave as spaces under Unix */ + break; +#endif + + default: + /* disable control character filter when requested, + * else allow 8-bit characters (e.g. UTF-8) in filenames: + */ + if (uO.cflxflag || + (isprint(workch) || (128 <= workch && workch <= 254))) + *pp++ = (char)workch; + } /* end switch */ + + } /* end while loop */ + + /* Show warning when stripping insecure "parent dir" path components */ + if (killed_ddot && QCOND2) { + Info(slide, 0, ((char *)slide, + "warning: skipped \"../\" path component(s) in %s\n", + FnFilter1(G.filename))); + if (!(error & ~MPN_MASK)) + error = (error & MPN_MASK) | PK_WARN; + } + +/*--------------------------------------------------------------------------- + Report if directory was created (and no file to create: filename ended + in '/'), check name to be sure it exists, and combine path and name be- + fore exiting. + ---------------------------------------------------------------------------*/ + + if (G.filename[strlen(G.filename) - 1] == '/') { + checkdir(__G__ G.filename, GETPATH); + if (G.created_dir) { + if (QCOND2) { + Info(slide, 0, ((char *)slide, " creating: %s\n", + FnFilter1(G.filename))); + } +#ifndef NO_CHMOD + /* Filter out security-relevant attributes bits. */ + G.pInfo->file_attr = filtattr(__G__ G.pInfo->file_attr); + /* When extracting non-UNIX directories or when extracting + * without UID/GID restoration or SGID preservation, any + * SGID flag inherited from the parent directory should be + * maintained to allow files extracted into this new folder + * to inherit the GID setting from the parent directory. + */ + if (G.pInfo->hostnum != UNIX_ || !(uO.X_flag || uO.K_flag)) { + /* preserve SGID bit when inherited from parent dir */ + if (!SSTAT(G.filename, &G.statbuf)) { + G.pInfo->file_attr |= G.statbuf.st_mode & S_ISGID; + } else { + perror("Could not read directory attributes"); + } + } + + /* set approx. dir perms (make sure can still read/write in dir) */ + if (chmod(G.filename, G.pInfo->file_attr | 0700)) + perror("chmod (directory attributes) error"); +#endif + /* set dir time (note trailing '/') */ + return (error & ~MPN_MASK) | MPN_CREATED_DIR; + } + /* dir existed already; don't look for data to extract */ + return (error & ~MPN_MASK) | MPN_INF_SKIP; + } + + *pp = '\0'; /* done with pathcomp: terminate it */ + + /* if not saving them, remove VMS version numbers (appended ";###") */ + if (!uO.V_flag && lastsemi) { + pp = lastsemi + 1; + while (isdigit((uch)(*pp))) + ++pp; + if (*pp == '\0') /* only digits between ';' and end: nuke */ + *lastsemi = '\0'; + } + + /* On UNIX (and compatible systems), "." and ".." are reserved for + * directory navigation and cannot be used as regular file names. + * These reserved one-dot and two-dot names are mapped to "_" and "__". + */ + if (strcmp(pathcomp, ".") == 0) + *pathcomp = '_'; + else if (strcmp(pathcomp, "..") == 0) + strcpy(pathcomp, "__"); + +#ifdef ACORN_FTYPE_NFS + /* translate Acorn filetype information if asked to do so */ + if (uO.acorn_nfs_ext && + (ef_spark = (RO_extra_block *) + getRISCOSexfield(G.extra_field, G.lrec.extra_field_length)) + != (RO_extra_block *)NULL) + { + /* file *must* have a RISC OS extra field */ + long ft = (long)makelong(ef_spark->loadaddr); + /*32-bit*/ + if (lastcomma) { + pp = lastcomma + 1; + while (isxdigit((uch)(*pp))) ++pp; + if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */ + } + if ((ft & 1<<31)==0) ft=0x000FFD00; + sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF); + } +#endif /* ACORN_FTYPE_NFS */ + + if (*pathcomp == '\0') { + Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n", + FnFilter1(G.filename))); + return (error & ~MPN_MASK) | MPN_ERR_SKIP; + } + + checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */ + checkdir(__G__ G.filename, GETPATH); + + return error; + +} /* end function mapname() */ + + + + +#if 0 /*========== NOTES ==========*/ + + extract-to dir: a:path/ + buildpath: path1/path2/ ... (NULL-terminated) + pathcomp: filename + + mapname(): + loop over chars in zipfile member name + checkdir(path component, COMPONENT | CREATEDIR) --> map as required? + (d:/tmp/unzip/) (disk:[tmp.unzip.) + (d:/tmp/unzip/jj/) (disk:[tmp.unzip.jj.) + (d:/tmp/unzip/jj/temp/) (disk:[tmp.unzip.jj.temp.) + finally add filename itself and check for existence? (could use with rename) + (d:/tmp/unzip/jj/temp/msg.outdir) (disk:[tmp.unzip.jj.temp]msg.outdir) + checkdir(name, GETPATH) --> copy path to name and free space + +#endif /* 0 */ + + + + +/***********************/ +/* Function checkdir() */ +/***********************/ + +int checkdir(__G__ pathcomp, flag) + __GDEF + char *pathcomp; + int flag; +/* + * returns: + * MPN_OK - no problem detected + * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename + * MPN_INF_SKIP - path doesn't exist, not allowed to create + * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path + * exists and is not a directory, but is supposed to be + * MPN_ERR_TOOLONG - path is too long + * MPN_NOMEM - can't allocate memory for filename buffers + */ +{ + /* static int rootlen = 0; */ /* length of rootpath */ + /* static char *rootpath; */ /* user's "extract-to" directory */ + /* static char *buildpath; */ /* full path (so far) to extracted file */ + /* static char *end; */ /* pointer to end of buildpath ('\0') */ + +# define FN_MASK 7 +# define FUNCTION (flag & FN_MASK) + + + +/*--------------------------------------------------------------------------- + APPEND_DIR: append the path component to the path being built and check + for its existence. If doesn't exist and we are creating directories, do + so for this one; else signal success or error as appropriate. + ---------------------------------------------------------------------------*/ + + if (FUNCTION == APPEND_DIR) { + int too_long = FALSE; +#ifdef SHORT_NAMES + char *old_end = end; +#endif + + Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp))); + while ((*G.end = *pathcomp++) != '\0') + ++G.end; +#ifdef SHORT_NAMES /* path components restricted to 14 chars, typically */ + if ((G.end-old_end) > FILENAME_MAX) /* GRR: proper constant? */ + *(G.end = old_end + FILENAME_MAX) = '\0'; +#endif + + /* GRR: could do better check, see if overrunning buffer as we go: + * check end-buildpath after each append, set warning variable if + * within 20 of FILNAMSIZ; then if var set, do careful check when + * appending. Clear variable when begin new path. */ + + /* next check: need to append '/', at least one-char name, '\0' */ + if ((G.end-G.buildpath) > FILNAMSIZ-3) + too_long = TRUE; /* check if extracting dir? */ + if (SSTAT(G.buildpath, &G.statbuf)) { /* path doesn't exist */ + if (!G.create_dirs) { /* told not to create (freshening) */ + free(G.buildpath); + return MPN_INF_SKIP; /* path doesn't exist: nothing to do */ + } + if (too_long) { + Info(slide, 1, ((char *)slide, + "checkdir error: path too long: %s\n", + FnFilter1(G.buildpath))); + free(G.buildpath); + /* no room for filenames: fatal */ + return MPN_ERR_TOOLONG; + } + if (mkdir(G.buildpath, 0777) == -1) { /* create the directory */ + Info(slide, 1, ((char *)slide, + "checkdir error: cannot create %s\n\ + %s\n\ + unable to process %s.\n", + FnFilter2(G.buildpath), + strerror(errno), + FnFilter1(G.filename))); + free(G.buildpath); + /* path didn't exist, tried to create, failed */ + return MPN_ERR_SKIP; + } + G.created_dir = TRUE; + } else if (!S_ISDIR(G.statbuf.st_mode)) { + Info(slide, 1, ((char *)slide, + "checkdir error: %s exists but is not directory\n\ + unable to process %s.\n", + FnFilter2(G.buildpath), FnFilter1(G.filename))); + free(G.buildpath); + /* path existed but wasn't dir */ + return MPN_ERR_SKIP; + } + if (too_long) { + Info(slide, 1, ((char *)slide, + "checkdir error: path too long: %s\n", FnFilter1(G.buildpath))); + free(G.buildpath); + /* no room for filenames: fatal */ + return MPN_ERR_TOOLONG; + } + *G.end++ = '/'; + *G.end = '\0'; + Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath))); + return MPN_OK; + + } /* end if (FUNCTION == APPEND_DIR) */ + +/*--------------------------------------------------------------------------- + GETPATH: copy full path to the string pointed at by pathcomp, and free + G.buildpath. + ---------------------------------------------------------------------------*/ + + if (FUNCTION == GETPATH) { + strcpy(pathcomp, G.buildpath); + Trace((stderr, "getting and freeing path [%s]\n", + FnFilter1(pathcomp))); + free(G.buildpath); + G.buildpath = G.end = (char *)NULL; + return MPN_OK; + } + +/*--------------------------------------------------------------------------- + APPEND_NAME: assume the path component is the filename; append it and + return without checking for existence. + ---------------------------------------------------------------------------*/ + + if (FUNCTION == APPEND_NAME) { +#ifdef SHORT_NAMES + char *old_end = end; +#endif + + Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp))); + while ((*G.end = *pathcomp++) != '\0') { + ++G.end; +#ifdef SHORT_NAMES /* truncate name at 14 characters, typically */ + if ((G.end-old_end) > FILENAME_MAX) /* GRR: proper constant? */ + *(G.end = old_end + FILENAME_MAX) = '\0'; +#endif + if ((G.end-G.buildpath) >= FILNAMSIZ) { + *--G.end = '\0'; + Info(slide, 0x201, ((char *)slide, + "checkdir warning: path too long; truncating\n\ + %s\n -> %s\n", + FnFilter1(G.filename), FnFilter2(G.buildpath))); + return MPN_INF_TRUNC; /* filename truncated */ + } + } + Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath))); + /* could check for existence here, prompt for new name... */ + return MPN_OK; + } + +/*--------------------------------------------------------------------------- + INIT: allocate and initialize buffer space for the file currently being + extracted. If file was renamed with an absolute path, don't prepend the + extract-to path. + ---------------------------------------------------------------------------*/ + +/* GRR: for VMS and TOPS-20, add up to 13 to strlen */ + + if (FUNCTION == INIT) { + Trace((stderr, "initializing buildpath to ")); +#ifdef ACORN_FTYPE_NFS + if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+ + (uO.acorn_nfs_ext ? 5 : 1))) +#else + if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1)) +#endif + == (char *)NULL) + return MPN_NOMEM; + if ((G.rootlen > 0) && !G.renamed_fullpath) { + strcpy(G.buildpath, G.rootpath); + G.end = G.buildpath + G.rootlen; + } else { + *G.buildpath = '\0'; + G.end = G.buildpath; + } + Trace((stderr, "[%s]\n", FnFilter1(G.buildpath))); + return MPN_OK; + } + +/*--------------------------------------------------------------------------- + ROOT: if appropriate, store the path in rootpath and create it if + necessary; else assume it's a zipfile member and return. This path + segment gets used in extracting all members from every zipfile specified + on the command line. + ---------------------------------------------------------------------------*/ + +#if (!defined(SFX) || defined(SFX_EXDIR)) + if (FUNCTION == ROOT) { + Trace((stderr, "initializing root path to [%s]\n", + FnFilter1(pathcomp))); + if (pathcomp == (char *)NULL) { + G.rootlen = 0; + return MPN_OK; + } + if (G.rootlen > 0) /* rootpath was already set, nothing to do */ + return MPN_OK; + if ((G.rootlen = strlen(pathcomp)) > 0) { + char *tmproot; + + if ((tmproot = (char *)malloc(G.rootlen+2)) == (char *)NULL) { + G.rootlen = 0; + return MPN_NOMEM; + } + strcpy(tmproot, pathcomp); + if (tmproot[G.rootlen-1] == '/') { + tmproot[--G.rootlen] = '\0'; + } + if (G.rootlen > 0 && (SSTAT(tmproot, &G.statbuf) || + !S_ISDIR(G.statbuf.st_mode))) + { /* path does not exist */ + if (!G.create_dirs /* || iswild(tmproot) */ ) { + free(tmproot); + G.rootlen = 0; + /* skip (or treat as stored file) */ + return MPN_INF_SKIP; + } + /* create the directory (could add loop here scanning tmproot + * to create more than one level, but why really necessary?) */ + if (mkdir(tmproot, 0777) == -1) { + Info(slide, 1, ((char *)slide, + "checkdir: cannot create extraction directory: %s\n\ + %s\n", + FnFilter1(tmproot), strerror(errno))); + free(tmproot); + G.rootlen = 0; + /* path didn't exist, tried to create, and failed: */ + /* file exists, or 2+ subdir levels required */ + return MPN_ERR_SKIP; + } + } + tmproot[G.rootlen++] = '/'; + tmproot[G.rootlen] = '\0'; + if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) { + free(tmproot); + G.rootlen = 0; + return MPN_NOMEM; + } + Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath))); + } + return MPN_OK; + } +#endif /* !SFX || SFX_EXDIR */ + +/*--------------------------------------------------------------------------- + END: free rootpath, immediately prior to program exit. + ---------------------------------------------------------------------------*/ + + if (FUNCTION == END) { + Trace((stderr, "freeing rootpath\n")); + if (G.rootlen > 0) { + free(G.rootpath); + G.rootlen = 0; + } + return MPN_OK; + } + + return MPN_INVALID; /* should never reach */ + +} /* end function checkdir() */ + + + + + +#ifdef NO_MKDIR + +/********************/ +/* Function mkdir() */ +/********************/ + +int mkdir(path, mode) + ZCONST char *path; + int mode; /* ignored */ +/* + * returns: 0 - successful + * -1 - failed (errno not set, however) + */ +{ + char command[FILNAMSIZ+40]; /* buffer for system() call */ + + /* GRR 930416: added single quotes around path to avoid bug with + * creating directories with ampersands in name; not yet tested */ + sprintf(command, "IFS=\" \t\n\" /bin/mkdir '%s' 2>/dev/null", path); + if (system(command)) + return -1; + return 0; +} + +#endif /* NO_MKDIR */ + + + + +#if (!defined(MTS) || defined(SET_DIR_ATTRIB)) +static int get_extattribs OF((__GPRO__ iztimes *pzt, ulg z_uidgid[2])); + +static int get_extattribs(__G__ pzt, z_uidgid) + __GDEF + iztimes *pzt; + ulg z_uidgid[2]; +{ +/*--------------------------------------------------------------------------- + Convert from MSDOS-format local time and date to Unix-format 32-bit GMT + time: adjust base year from 1980 to 1970, do usual conversions from + yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day- + light savings time differences. If we have a Unix extra field, however, + we're laughing: both mtime and atime are ours. On the other hand, we + then have to check for restoration of UID/GID. + ---------------------------------------------------------------------------*/ + int have_uidgid_flg; + unsigned eb_izux_flg; + + 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 ? pzt : NULL), +#else + pzt, +#endif + z_uidgid) : 0); + if (eb_izux_flg & EB_UT_FL_MTIME) { + TTrace((stderr, "\nget_extattribs: Unix e.f. modif. time = %ld\n", + pzt->mtime)); + } else { + pzt->mtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime); + } + if (eb_izux_flg & EB_UT_FL_ATIME) { + TTrace((stderr, "get_extattribs: Unix e.f. access time = %ld\n", + pzt->atime)); + } else { + pzt->atime = pzt->mtime; + TTrace((stderr, "\nget_extattribs: modification/access times = %ld\n", + pzt->mtime)); + } + + /* if -X option was specified and we have UID/GID info, restore it */ + have_uidgid_flg = +#ifdef RESTORE_UIDGID + (uO.X_flag && (eb_izux_flg & EB_UX2_VALID)); +#else + 0; +#endif + return have_uidgid_flg; +} +#endif /* !MTS || SET_DIR_ATTRIB */ + + + +#ifndef MTS + +/****************************/ +/* Function CloseError() */ +/***************************/ + +int CloseError(__G) + __GDEF +{ + int errval = PK_OK; + + if (fclose(G.outfile) < 0) { + switch (errno) { + case ENOSPC: + /* Do we need this on fileio.c? */ + Info(slide, 0x4a1, ((char *)slide, "%s: write error (disk full?). Continue? (y/n/^C) ", + FnFilter1(G.filename))); + fgets(G.answerbuf, 9, stdin); + if (*G.answerbuf == 'y') /* stop writing to this file */ + G.disk_full = 1; /* pass to next */ + else + G.disk_full = 2; /* no: exit program */ + + errval = PK_DISK; + break; + + default: + errval = PK_WARN; + } + } + return errval; +} /* End of CloseError() */ + +/****************************/ +/* Function close_outfile() */ +/****************************/ + +int close_outfile(__G) + __GDEF +{ + union { + iztimes t3; /* mtime, atime, ctime */ + ztimbuf t2; /* modtime, actime */ + } zt; + ulg z_uidgid[2]; + int have_uidgid_flg; + int errval = PK_OK; + + have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid); + +/*--------------------------------------------------------------------------- + If symbolic links are supported, allocate storage for a symlink control + structure, put the uncompressed "data" and other required info in it, and + add the structure to the "deferred symlinks" chain. Since we know it's a + symbolic link to start with, we shouldn't have to worry about overflowing + unsigned ints with unsigned longs. + ---------------------------------------------------------------------------*/ + +#ifdef SYMLINKS + if (G.symlnk) { + extent ucsize = (extent)G.lrec.ucsize; +# ifdef SET_SYMLINK_ATTRIBS + extent attribsize = sizeof(unsigned) + + (have_uidgid_flg ? sizeof(z_uidgid) : 0); +# else + extent attribsize = 0; +# endif + /* size of the symlink entry is the sum of + * (struct size (includes 1st '\0') + 1 additional trailing '\0'), + * system specific attribute data size (might be 0), + * and the lengths of name and link target. + */ + extent slnk_entrysize = (sizeof(slinkentry) + 1) + attribsize + + ucsize + strlen(G.filename); + slinkentry *slnk_entry; + + if (slnk_entrysize < ucsize) { + Info(slide, 0x201, ((char *)slide, + "warning: symbolic link (%s) failed: mem alloc overflow\n", + FnFilter1(G.filename))); + errval = CloseError(G.outfile, G.filename); + return errval ? errval : PK_WARN; + } + + if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) { + Info(slide, 0x201, ((char *)slide, + "warning: symbolic link (%s) failed: no mem\n", + FnFilter1(G.filename))); + errval = CloseError(G.outfile, G.filename); + return errval ? errval : PK_WARN; + } + slnk_entry->next = NULL; + slnk_entry->targetlen = ucsize; + slnk_entry->attriblen = attribsize; +# ifdef SET_SYMLINK_ATTRIBS + memcpy(slnk_entry->buf, &(G.pInfo->file_attr), + sizeof(unsigned)); + if (have_uidgid_flg) + memcpy(slnk_entry->buf + 4, z_uidgid, sizeof(z_uidgid)); +# endif + slnk_entry->target = slnk_entry->buf + slnk_entry->attriblen; + slnk_entry->fname = slnk_entry->target + ucsize + 1; + strcpy(slnk_entry->fname, G.filename); + + /* move back to the start of the file to re-read the "link data" */ + rewind(G.outfile); + + if (fread(slnk_entry->target, 1, ucsize, G.outfile) != ucsize) + { + Info(slide, 0x201, ((char *)slide, + "warning: symbolic link (%s) failed\n", + FnFilter1(G.filename))); + free(slnk_entry); + errval = CloseError(G.outfile, G.filename); + return errval ? errval : PK_WARN; + } + errval = CloseError(G.outfile, G.filename); /* close "link" file for good... */ + slnk_entry->target[ucsize] = '\0'; + if (QCOND2) + Info(slide, 0, ((char *)slide, "-> %s ", + FnFilter1(slnk_entry->target))); + /* add this symlink record to the list of deferred symlinks */ + if (G.slink_last != NULL) + G.slink_last->next = slnk_entry; + else + G.slink_head = slnk_entry; + G.slink_last = slnk_entry; + return errval; + } +#endif /* SYMLINKS */ + +#ifdef QLZIP + if (G.extra_field) { + static void qlfix OF((__GPRO__ uch *ef_ptr, unsigned ef_len)); + + qlfix(__G__ G.extra_field, G.lrec.extra_field_length); + } +#endif + +#if (defined(NO_FCHOWN)) + errval = CloseError(G.outfile, G.filename); +#endif + + /* if -X option was specified and we have UID/GID info, restore it */ + if (have_uidgid_flg + /* check that both uid and gid values fit into their data sizes */ + && ((ulg)(uid_t)(z_uidgid[0]) == z_uidgid[0]) + && ((ulg)(gid_t)(z_uidgid[1]) == z_uidgid[1])) { + TTrace((stderr, "close_outfile: restoring Unix UID/GID info\n")); +#if (defined(NO_FCHOWN)) + if (chown(G.filename, (uid_t)z_uidgid[0], (gid_t)z_uidgid[1])) +#else + if (fchown(fileno(G.outfile), (uid_t)z_uidgid[0], (gid_t)z_uidgid[1])) +#endif + { + if (uO.qflag) + Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid, + z_uidgid[0], z_uidgid[1], FnFilter1(G.filename), + strerror(errno))); + else + Info(slide, 0x201, ((char *)slide, CannotSetUidGid, + z_uidgid[0], z_uidgid[1], strerror(errno))); + } + } + +#if (!defined(NO_FCHOWN) && defined(NO_FCHMOD)) + errval = CloseError(G.outfile, G.filename); +#endif + +#if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD)) +/*--------------------------------------------------------------------------- + Change the file permissions from default ones to those stored in the + zipfile. + ---------------------------------------------------------------------------*/ + + if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr))) + perror("fchmod (file attributes) error"); + + errval = CloseError(G.outfile, G.filename); +#endif /* !NO_FCHOWN && !NO_FCHMOD */ + + /* skip restoring time stamps on user's request */ + if (uO.D_flag <= 1) { + /* set the file's access and modification times */ + if (utime(G.filename, &(zt.t2))) { + if (uO.qflag) + Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps, + FnFilter1(G.filename), strerror(errno))); + else + Info(slide, 0x201, ((char *)slide, CannotSetTimestamps, + strerror(errno))); + } + } + +#if (defined(NO_FCHOWN) || defined(NO_FCHMOD)) +/*--------------------------------------------------------------------------- + Change the file permissions from default ones to those stored in the + zipfile. + ---------------------------------------------------------------------------*/ + +#ifndef NO_CHMOD + if (chmod(G.filename, filtattr(__G__ G.pInfo->file_attr))) + perror("chmod (file attributes) error"); +#endif +#endif /* NO_FCHOWN || NO_FCHMOD */ + + return errval; +} /* end function close_outfile() */ + +#endif /* !MTS */ + + +#if (defined(SYMLINKS) && defined(SET_SYMLINK_ATTRIBS)) +int set_symlnk_attribs(__G__ slnk_entry) + __GDEF + slinkentry *slnk_entry; +{ + if (slnk_entry->attriblen > 0) { +# if (!defined(NO_LCHOWN)) + if (slnk_entry->attriblen > sizeof(unsigned)) { + ulg *z_uidgid_p = (zvoid *)(slnk_entry->buf + sizeof(unsigned)); + /* check that both uid and gid values fit into their data sizes */ + if (((ulg)(uid_t)(z_uidgid_p[0]) == z_uidgid_p[0]) && + ((ulg)(gid_t)(z_uidgid_p[1]) == z_uidgid_p[1])) { + TTrace((stderr, + "set_symlnk_attribs: restoring Unix UID/GID info for\n\ + %s\n", + FnFilter1(slnk_entry->fname))); + if (lchown(slnk_entry->fname, + (uid_t)z_uidgid_p[0], (gid_t)z_uidgid_p[1])) + { + Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid, + z_uidgid_p[0], z_uidgid_p[1], FnFilter1(slnk_entry->fname), + strerror(errno))); + } + } + } +# endif /* !NO_LCHOWN */ +# if (!defined(NO_LCHMOD)) + TTrace((stderr, + "set_symlnk_attribs: restoring Unix attributes for\n %s\n", + FnFilter1(slnk_entry->fname))); + if (lchmod(slnk_entry->fname, + filtattr(__G__ *(unsigned *)(zvoid *)slnk_entry->buf))) + perror("lchmod (file attributes) error"); +# endif /* !NO_LCHMOD */ + } + /* currently, no error propagation... */ + return PK_OK; +} /* end function set_symlnk_attribs() */ +#endif /* SYMLINKS && SET_SYMLINK_ATTRIBS */ + + +#ifdef SET_DIR_ATTRIB +/* messages of code for setting directory attributes */ +# ifndef NO_CHMOD + static ZCONST char DirlistChmodFailed[] = + "warning: cannot set permissions for %s\n %s\n"; +# endif + + +int defer_dir_attribs(__G__ pd) + __GDEF + direntry **pd; +{ + uxdirattr *d_entry; + + d_entry = (uxdirattr *)malloc(sizeof(uxdirattr) + strlen(G.filename)); + *pd = (direntry *)d_entry; + if (d_entry == (uxdirattr *)NULL) { + return PK_MEM; + } + d_entry->fn = d_entry->fnbuf; + strcpy(d_entry->fn, G.filename); + + d_entry->perms = G.pInfo->file_attr; + + d_entry->have_uidgid = get_extattribs(__G__ &(d_entry->u.t3), + d_entry->uidgid); + return PK_OK; +} /* end function defer_dir_attribs() */ + + +int set_direc_attribs(__G__ d) + __GDEF + direntry *d; +{ + int errval = PK_OK; + + if (UxAtt(d)->have_uidgid && + /* check that both uid and gid values fit into their data sizes */ + ((ulg)(uid_t)(UxAtt(d)->uidgid[0]) == UxAtt(d)->uidgid[0]) && + ((ulg)(gid_t)(UxAtt(d)->uidgid[1]) == UxAtt(d)->uidgid[1]) && + chown(UxAtt(d)->fn, (uid_t)UxAtt(d)->uidgid[0], + (gid_t)UxAtt(d)->uidgid[1])) + { + Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid, + UxAtt(d)->uidgid[0], UxAtt(d)->uidgid[1], FnFilter1(d->fn), + strerror(errno))); + if (!errval) + errval = PK_WARN; + } + /* Skip restoring directory time stamps on user' request. */ + if (uO.D_flag <= 0) { + /* restore directory timestamps */ + if (utime(d->fn, &UxAtt(d)->u.t2)) { + Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps, + FnFilter1(d->fn), strerror(errno))); + if (!errval) + errval = PK_WARN; + } + } +#ifndef NO_CHMOD + if (chmod(d->fn, UxAtt(d)->perms)) { + Info(slide, 0x201, ((char *)slide, DirlistChmodFailed, + FnFilter1(d->fn), strerror(errno))); + if (!errval) + errval = PK_WARN; + } +#endif /* !NO_CHMOD */ + return errval; +} /* end function set_direc_attribs() */ + +#endif /* SET_DIR_ATTRIB */ + + + + +#ifdef TIMESTAMP + +/***************************/ +/* Function stamp_file() */ +/***************************/ + +int stamp_file(fname, modtime) + ZCONST char *fname; + time_t modtime; +{ + ztimbuf tp; + + tp.modtime = tp.actime = modtime; + return (utime(fname, &tp)); + +} /* end function stamp_file() */ + +#endif /* TIMESTAMP */ + + + + +#ifndef SFX + +/************************/ +/* Function version() */ +/************************/ + +void version(__G) + __GDEF +{ +#if (defined(__GNUC__) && defined(NX_CURRENT_COMPILER_RELEASE)) + char cc_namebuf[40]; + char cc_versbuf[40]; +#else +#if (defined(__SUNPRO_C)) + char cc_versbuf[17]; +#else +#if (defined(__HP_cc) || defined(__IBMC__)) + char cc_versbuf[25]; +#else +#if (defined(__DECC_VER)) + char cc_versbuf[17]; + int cc_verstyp; +#else +#if (defined(CRAY) && defined(_RELEASE)) + char cc_versbuf[40]; +#endif /* (CRAY && _RELEASE) */ +#endif /* __DECC_VER */ +#endif /* __HP_cc || __IBMC__ */ +#endif /* __SUNPRO_C */ +#endif /* (__GNUC__ && NX_CURRENT_COMPILER_RELEASE) */ + +#if ((defined(CRAY) || defined(cray)) && defined(_UNICOS)) + char os_namebuf[40]; +#else +#if defined(__NetBSD__) + char os_namebuf[40]; +#endif +#endif + + /* Pyramid, NeXT have problems with huge macro expansion, too: no Info() */ + sprintf((char *)slide, LoadFarString(CompiledWith), + +#ifdef __GNUC__ +# ifdef NX_CURRENT_COMPILER_RELEASE + (sprintf(cc_namebuf, "NeXT DevKit %d.%02d ", + NX_CURRENT_COMPILER_RELEASE/100, NX_CURRENT_COMPILER_RELEASE%100), + cc_namebuf), + (strlen(__VERSION__) > 8)? "(gcc)" : + (sprintf(cc_versbuf, "(gcc %s)", __VERSION__), cc_versbuf), +# else + "gcc ", __VERSION__, +# endif +#else +#if defined(__SUNPRO_C) + "Sun C ", (sprintf(cc_versbuf, "version %x", __SUNPRO_C), cc_versbuf), +#else +#if (defined(__HP_cc)) + "HP C ", + (((__HP_cc% 100) == 0) ? + (sprintf(cc_versbuf, "version A.%02d.%02d", + (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100))) : + (sprintf(cc_versbuf, "version A.%02d.%02d.%02d", + (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100), (__HP_cc% 100))), + cc_versbuf), +#else +#if (defined(__DECC_VER)) + "DEC C ", + (sprintf(cc_versbuf, "%c%d.%d-%03d", + ((cc_verstyp = (__DECC_VER / 10000) % 10) == 6 ? 'T' : + (cc_verstyp == 8 ? 'S' : 'V')), + __DECC_VER / 10000000, + (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000), + cc_versbuf), +#else +#if defined(CRAY) && defined(_RELEASE) + "cc ", (sprintf(cc_versbuf, "version %d", _RELEASE), cc_versbuf), +#else +#ifdef __IBMC__ + "IBM C ", + (sprintf(cc_versbuf, "version %d.%d.%d", + (__IBMC__ / 100), ((__IBMC__ / 10) % 10), (__IBMC__ % 10)), + cc_versbuf), +#else +#ifdef __VERSION__ +# ifndef IZ_CC_NAME +# define IZ_CC_NAME "cc " +# endif + IZ_CC_NAME, __VERSION__ +#else +# ifndef IZ_CC_NAME +# define IZ_CC_NAME "cc" +# endif + IZ_CC_NAME, "", +#endif /* ?__VERSION__ */ +#endif /* ?__IBMC__ */ +#endif /* ?(CRAY && _RELEASE) */ +#endif /* ?__DECC_VER */ +#endif /* ?__HP_cc */ +#endif /* ?__SUNPRO_C */ +#endif /* ?__GNUC__ */ + +#ifndef IZ_OS_NAME +# define IZ_OS_NAME "Unix" +#endif + IZ_OS_NAME, + +#if defined(sgi) || defined(__sgi) + " (Silicon Graphics IRIX)", +#else +#ifdef sun +# ifdef sparc +# ifdef __SVR4 + " (Sun SPARC/Solaris)", +# else /* may or may not be SunOS */ + " (Sun SPARC)", +# endif +# else +# if defined(sun386) || defined(i386) + " (Sun 386i)", +# else +# if defined(mc68020) || defined(__mc68020__) + " (Sun 3)", +# else /* mc68010 or mc68000: Sun 2 or earlier */ + " (Sun 2)", +# endif +# endif +# endif +#else +#ifdef __hpux + " (HP-UX)", +#else +#ifdef __osf__ + " (DEC OSF/1)", +#else +#ifdef _AIX + " (IBM AIX)", +#else +#ifdef aiws + " (IBM RT/AIX)", +#else +#if defined(CRAY) || defined(cray) +# ifdef _UNICOS + (sprintf(os_namebuf, " (Cray UNICOS release %d)", _UNICOS), os_namebuf), +# else + " (Cray UNICOS)", +# endif +#else +#if defined(uts) || defined(UTS) + " (Amdahl UTS)", +#else +#ifdef NeXT +# ifdef mc68000 + " (NeXTStep/black)", +# else + " (NeXTStep for Intel)", +# endif +#else /* the next dozen or so are somewhat order-dependent */ +#ifdef LINUX +# ifdef __ELF__ + " (Linux ELF)", +# else + " (Linux a.out)", +# endif +#else +#ifdef MINIX + " (Minix)", +#else +#ifdef M_UNIX + " (SCO Unix)", +#else +#ifdef M_XENIX + " (SCO Xenix)", +#else +#ifdef __NetBSD__ +# ifdef NetBSD0_8 + (sprintf(os_namebuf, " (NetBSD 0.8%c)", (char)(NetBSD0_8 - 1 + 'A')), + os_namebuf), +# else +# ifdef NetBSD0_9 + (sprintf(os_namebuf, " (NetBSD 0.9%c)", (char)(NetBSD0_9 - 1 + 'A')), + os_namebuf), +# else +# ifdef NetBSD1_0 + (sprintf(os_namebuf, " (NetBSD 1.0%c)", (char)(NetBSD1_0 - 1 + 'A')), + os_namebuf), +# else + (BSD4_4 == 0.5)? " (NetBSD before 0.9)" : " (NetBSD 1.1 or later)", +# endif +# endif +# endif +#else +#ifdef __FreeBSD__ + (BSD4_4 == 0.5)? " (FreeBSD 1.x)" : " (FreeBSD 2.0 or later)", +#else +#ifdef __bsdi__ + (BSD4_4 == 0.5)? " (BSD/386 1.0)" : " (BSD/386 1.1 or later)", +#else +#ifdef __386BSD__ + (BSD4_4 == 1)? " (386BSD, post-4.4 release)" : " (386BSD)", +#else +#ifdef __CYGWIN__ + " (Cygwin)", +#else +#if defined(i686) || defined(__i686) || defined(__i686__) + " (Intel 686)", +#else +#if defined(i586) || defined(__i586) || defined(__i586__) + " (Intel 586)", +#else +#if defined(i486) || defined(__i486) || defined(__i486__) + " (Intel 486)", +#else +#if defined(i386) || defined(__i386) || defined(__i386__) + " (Intel 386)", +#else +#ifdef pyr + " (Pyramid)", +#else +#ifdef ultrix +# ifdef mips + " (DEC/MIPS)", +# else +# ifdef vax + " (DEC/VAX)", +# else /* __alpha? */ + " (DEC/Alpha)", +# endif +# endif +#else +#ifdef gould + " (Gould)", +#else +#ifdef MTS + " (MTS)", +#else +#ifdef __convexc__ + " (Convex)", +#else +#ifdef __QNX__ + " (QNX 4)", +#else +#ifdef __QNXNTO__ + " (QNX Neutrino)", +#else +#ifdef Lynx + " (LynxOS)", +#else +#ifdef __APPLE__ +# ifdef __i386__ + " Mac OS X Intel i32", +# else +# ifdef __ppc__ + " Mac OS X PowerPC", +# else +# ifdef __ppc64__ + " Mac OS X PowerPC64", +# else + " Mac OS X", +# endif /* __ppc64__ */ +# endif /* __ppc__ */ +# endif /* __i386__ */ +#else + "", +#endif /* Apple */ +#endif /* Lynx */ +#endif /* QNX Neutrino */ +#endif /* QNX 4 */ +#endif /* Convex */ +#endif /* MTS */ +#endif /* Gould */ +#endif /* DEC */ +#endif /* Pyramid */ +#endif /* 386 */ +#endif /* 486 */ +#endif /* 586 */ +#endif /* 686 */ +#endif /* Cygwin */ +#endif /* 386BSD */ +#endif /* BSDI BSD/386 */ +#endif /* NetBSD */ +#endif /* FreeBSD */ +#endif /* SCO Xenix */ +#endif /* SCO Unix */ +#endif /* Minix */ +#endif /* Linux */ +#endif /* NeXT */ +#endif /* Amdahl */ +#endif /* Cray */ +#endif /* RT/AIX */ +#endif /* AIX */ +#endif /* OSF/1 */ +#endif /* HP-UX */ +#endif /* Sun */ +#endif /* SGI */ + +#ifdef __DATE__ + " on ", __DATE__ +#else + "", "" +#endif + ); + + (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0); + +} /* end function version() */ + +#endif /* !SFX */ + + + + +#ifdef QLZIP + +struct qdirect { + long d_length __attribute__ ((packed)); /* file length */ + unsigned char d_access __attribute__ ((packed)); /* file access type */ + unsigned char d_type __attribute__ ((packed)); /* file type */ + long d_datalen __attribute__ ((packed)); /* data length */ + long d_reserved __attribute__ ((packed));/* Unused */ + short d_szname __attribute__ ((packed)); /* size of name */ + char d_name[36] __attribute__ ((packed));/* name area */ + long d_update __attribute__ ((packed)); /* last update */ + long d_refdate __attribute__ ((packed)); + long d_backup __attribute__ ((packed)); /* EOD */ +}; + +#define LONGID "QDOS02" +#define EXTRALEN (sizeof(struct qdirect) + 8) +#define JBLONGID "QZHD" +#define JBEXTRALEN (sizeof(jbextra) - 4 * sizeof(char)) + +typedef struct { + char eb_header[4] __attribute__ ((packed)); /* place_holder */ + char longid[8] __attribute__ ((packed)); + struct qdirect header __attribute__ ((packed)); +} qdosextra; + +typedef struct { + char eb_header[4]; /* place_holder */ + char longid[4]; + struct qdirect header; +} jbextra; + + + +/* The following two functions SH() and LG() convert big-endian short + * and long numbers into native byte order. They are some kind of + * counterpart to the generic UnZip's makeword() and makelong() functions. + */ +static ush SH(ush val) +{ + uch swapbuf[2]; + + swapbuf[1] = (uch)(val & 0xff); + swapbuf[0] = (uch)(val >> 8); + return (*(ush *)swapbuf); +} + + + +static ulg LG(ulg val) +{ + /* convert the big-endian unsigned long number `val' to the machine + * dependent representation + */ + ush swapbuf[2]; + + swapbuf[1] = SH((ush)(val & 0xffff)); + swapbuf[0] = SH((ush)(val >> 16)); + return (*(ulg *)swapbuf); +} + + + +static void qlfix(__G__ ef_ptr, ef_len) + __GDEF + uch *ef_ptr; + unsigned ef_len; +{ + while (ef_len >= EB_HEADSIZE) + { + unsigned eb_id = makeword(EB_ID + ef_ptr); + unsigned eb_len = makeword(EB_LEN + ef_ptr); + + if (eb_len > (ef_len - EB_HEADSIZE)) { + /* discovered some extra field inconsistency! */ + Trace((stderr, + "qlfix: block length %u > rest ef_size %u\n", eb_len, + ef_len - EB_HEADSIZE)); + break; + } + + switch (eb_id) { + case EF_QDOS: + { + struct _ntc_ + { + long id; + long dlen; + } ntc; + long dlen = 0; + + qdosextra *extra = (qdosextra *)ef_ptr; + jbextra *jbp = (jbextra *)ef_ptr; + + if (!strncmp(extra->longid, LONGID, strlen(LONGID))) + { + if (eb_len != EXTRALEN) + if (uO.qflag) + Info(slide, 0x201, ((char *)slide, + "warning: invalid length in Qdos field for %s\n", + FnFilter1(G.filename))); + else + Info(slide, 0x201, ((char *)slide, + "warning: invalid length in Qdos field")); + + if (extra->header.d_type) + { + dlen = extra->header.d_datalen; + } + } + + if (!strncmp(jbp->longid, JBLONGID, strlen(JBLONGID))) + { + if (eb_len != JBEXTRALEN) + if (uO.qflag) + Info(slide, 0x201, ((char *)slide, + "warning: invalid length in QZ field for %s\n", + FnFilter1(G.filename))); + else + Info(slide, 0x201, ((char *)slide, + "warning: invalid length in QZ field")); + if (jbp->header.d_type) + { + dlen = jbp->header.d_datalen; + } + } + + if ((long)LG(dlen) > 0) + { + zfseeko(G.outfile, -8, SEEK_END); + fread(&ntc, 8, 1, G.outfile); + if (ntc.id != *(long *)"XTcc") + { + ntc.id = *(long *)"XTcc"; + ntc.dlen = dlen; + fwrite (&ntc, 8, 1, G.outfile); + } + Info(slide, 0x201, ((char *)slide, "QData = %d", LG(dlen))); + } + return; /* finished, cancel further extra field scanning */ + } + + default: + Trace((stderr,"qlfix: unknown extra field block, ID=%d\n", + eb_id)); + } + + /* Skip this extra field block */ + ef_ptr += (eb_len + EB_HEADSIZE); + ef_len -= (eb_len + EB_HEADSIZE); + } +} +#endif /* QLZIP */ diff -Naur a/unix/unxcfg.h b/unix/unxcfg.h --- a/unix/unxcfg.h 2009-04-16 19:36:12.000000000 +0100 +++ b/unix/unxcfg.h 2019-12-02 01:49:39.894641004 +0000 @@ -227,4 +227,30 @@ /* wild_dir, dirname, wildname, matchname[], dirnamelen, have_dirname, */ /* and notfirstcall are used by do_wild(). */ + +#define MAX_CP_NAME 25 + 1 + +#ifdef SETLOCALE +# undef SETLOCALE +#endif +#define SETLOCALE(category, locale) setlocale(category, locale) +#include + +#ifdef _ISO_INTERN +# undef _ISO_INTERN +#endif +#define _ISO_INTERN(str1) iso_intern(str1) + +#ifdef _OEM_INTERN +# undef _OEM_INTERN +#endif +#ifndef IZ_OEM2ISO_ARRAY +# define IZ_OEM2ISO_ARRAY +#endif +#define _OEM_INTERN(str1) oem_intern(str1) + +void iso_intern(char *); +void oem_intern(char *); +void init_conversion_charsets(void); + #endif /* !__unxcfg_h */ diff -Naur a/unix/unxcfg.h.orig b/unix/unxcfg.h.orig --- a/unix/unxcfg.h.orig 1970-01-01 01:00:00.000000000 +0100 +++ b/unix/unxcfg.h.orig 2009-04-16 19:36:12.000000000 +0100 @@ -0,0 +1,230 @@ +/* + Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2009-Jan-02 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 +*/ +/*--------------------------------------------------------------------------- + Unix specific configuration section: + ---------------------------------------------------------------------------*/ + +#ifndef __unxcfg_h +#define __unxcfg_h + + +/* LARGE FILE SUPPORT - 10/6/04 EG */ +/* This needs to be set before the includes so they set the right sizes */ + +#if (defined(NO_LARGE_FILE_SUPPORT) && defined(LARGE_FILE_SUPPORT)) +# undef LARGE_FILE_SUPPORT +#endif + +/* Automatically set ZIP64_SUPPORT if LFS */ +#ifdef LARGE_FILE_SUPPORT +# if (!defined(NO_ZIP64_SUPPORT) && !defined(ZIP64_SUPPORT)) +# define ZIP64_SUPPORT +# endif +#endif + +/* NO_ZIP64_SUPPORT takes preceedence over ZIP64_SUPPORT */ +#if defined(NO_ZIP64_SUPPORT) && defined(ZIP64_SUPPORT) +# undef ZIP64_SUPPORT +#endif + +#ifdef LARGE_FILE_SUPPORT + /* 64-bit Large File Support */ + + /* The following Large File Summit (LFS) defines turn on large file support + on Linux (probably 2.4 or later kernel) and many other unixen */ + + /* These have to be before any include that sets types so the large file + versions of the types are set in the includes */ + +# define _LARGEFILE_SOURCE /* some OSes need this for fseeko */ +# define _LARGEFILE64_SOURCE +# define _FILE_OFFSET_BITS 64 /* select default interface as 64 bit */ +# define _LARGE_FILES /* some OSes need this for 64-bit off_t */ +# define __USE_LARGEFILE64 +#endif /* LARGE_FILE_SUPPORT */ + + +#include /* off_t, time_t, dev_t, ... */ +#include + +#ifdef NO_OFF_T + typedef long zoff_t; +#else + typedef off_t zoff_t; +#endif +#define ZOFF_T_DEFINED +typedef struct stat z_stat; +#define Z_STAT_DEFINED + +#ifndef COHERENT +# include /* O_BINARY for open() w/o CR/LF translation */ +#else /* COHERENT */ +# ifdef _I386 +# include /* Coherent 4.0.x, Mark Williams C */ +# else +# include /* Coherent 3.10, Mark Williams C */ +# endif +# define SHORT_SYMS +# ifndef __COHERENT__ /* Coherent 4.2 has tzset() */ +# define tzset settz +# endif +#endif /* ?COHERENT */ + +#ifndef NO_PARAM_H +# ifdef NGROUPS_MAX +# undef NGROUPS_MAX /* SCO bug: defined again in */ +# endif +# ifdef BSD +# define TEMP_BSD /* may be defined again in */ +# undef BSD +# endif +# include /* conflict with , some systems? */ +# ifdef TEMP_BSD +# undef TEMP_BSD +# ifndef BSD +# define BSD +# endif +# endif +#endif /* !NO_PARAM_H */ + +#ifdef __osf__ +# define DIRENT +# ifdef BSD +# undef BSD +# endif +#endif /* __osf__ */ + +#ifdef __CYGWIN__ +# include +# define DIRENT +# define HAVE_TERMIOS_H +# ifndef timezone +# define timezone _timezone +# endif +#endif + +#ifdef BSD +# include +# include +# if (defined(_AIX) || defined(__GLIBC__) || defined(__GNU__)) +# include +# endif +#else +# include + struct tm *gmtime(), *localtime(); +#endif + +#if (defined(BSD4_4) || (defined(SYSV) && defined(MODERN))) +# include /* this includes utime.h on SGIs */ +# if (defined(BSD4_4) || defined(linux) || defined(__GLIBC__)) +# include +# define GOT_UTIMBUF +# endif +# if (!defined(GOT_UTIMBUF) && (defined(__hpux) || defined(__SUNPRO_C))) +# include +# define GOT_UTIMBUF +# endif +# if (!defined(GOT_UTIMBUF) && defined(__GNU__)) +# include +# define GOT_UTIMBUF +# endif +#endif +#if (defined(__DGUX__) && !defined(GOT_UTIMBUF)) + /* DG/UX requires this because of a non-standard struct utimebuf */ +# include +# define GOT_UTIMBUF +#endif + +#if (defined(V7) || defined(pyr_bsd)) +# define strchr index +# define strrchr rindex +#endif +#ifdef V7 +# define O_RDONLY 0 +# define O_WRONLY 1 +# define O_RDWR 2 +#endif + +#if defined(NO_UNICODE_SUPPORT) && defined(UNICODE_SUPPORT) + /* disable Unicode (UTF-8) support when requested */ +# undef UNICODE_SUPPORT +#endif + +#if (defined(_MBCS) && defined(NO_MBCS)) + /* disable MBCS support when requested */ +# undef _MBCS +#endif + +#if (!defined(NO_SETLOCALE) && !defined(_MBCS)) +# if (!defined(UNICODE_SUPPORT) || !defined(UTF8_MAYBE_NATIVE)) + /* enable setlocale here, unless this happens later for UTF-8 and/or + * MBCS support */ +# include +# ifndef SETLOCALE +# define SETLOCALE(category, locale) setlocale(category, locale) +# endif +# endif +#endif +#ifndef NO_SETLOCALE +# if (!defined(NO_WORKING_ISPRINT) && !defined(HAVE_WORKING_ISPRINT)) + /* enable "enhanced" unprintable chars detection in fnfilter() */ +# define HAVE_WORKING_ISPRINT +# endif +#endif + +#ifdef MINIX +# include +#endif +#if (!defined(HAVE_STRNICMP) & !defined(NO_STRNICMP)) +# define NO_STRNICMP +#endif +#ifndef DATE_FORMAT +# define DATE_FORMAT DF_MDY /* GRR: customize with locale.h somehow? */ +#endif +#define lenEOL 1 +#ifdef EBCDIC +# define PutNativeEOL *q++ = '\n'; +#else +# define PutNativeEOL *q++ = native(LF); +#endif +#define SCREENSIZE(ttrows, ttcols) screensize(ttrows, ttcols) +#define SCREENWIDTH 80 +#define SCREENLWRAP 1 +#define USE_EF_UT_TIME +#if (!defined(NO_LCHOWN) || !defined(NO_LCHMOD)) +# define SET_SYMLINK_ATTRIBS +#endif +#ifdef MTS +# ifdef SET_DIR_ATTRIB +# undef SET_DIR_ATTRIB +# endif +#else /* !MTS */ +# define SET_DIR_ATTRIB +# if (!defined(NOTIMESTAMP) && !defined(TIMESTAMP)) /* GRR 970513 */ +# define TIMESTAMP +# endif +# define RESTORE_UIDGID +#endif /* ?MTS */ + +/* Static variables that we have to add to Uz_Globs: */ +#define SYSTEM_SPECIFIC_GLOBALS \ + int created_dir, renamed_fullpath;\ + char *rootpath, *buildpath, *end;\ + ZCONST char *wildname;\ + char *dirname, matchname[FILNAMSIZ];\ + int rootlen, have_dirname, dirnamelen, notfirstcall;\ + zvoid *wild_dir; + +/* created_dir, and renamed_fullpath are used by both mapname() and */ +/* checkdir(). */ +/* rootlen, rootpath, buildpath and end are used by checkdir(). */ +/* wild_dir, dirname, wildname, matchname[], dirnamelen, have_dirname, */ +/* and notfirstcall are used by do_wild(). */ + +#endif /* !__unxcfg_h */ diff -Naur a/unzip.c b/unzip.c --- a/unzip.c 2009-04-16 19:26:52.000000000 +0100 +++ b/unzip.c 2019-12-02 01:49:39.895641007 +0000 @@ -327,11 +327,21 @@ -2 just filenames but allow -h/-t/-z -l long Unix \"ls -l\" format\n\ -v verbose, multi-page format\n"; +#ifndef UNIX static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\ -h print header line -t print totals for listed files or for all\n\ -z print zipfile comment -T print file times in sortable decimal format\ \n -C be case-insensitive %s\ -x exclude filenames that follow from listing\n"; +#else /* UNIX */ +static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\ + -h print header line -t print totals for listed files or for all\n\ + -z print zipfile comment %c-T%c print file times in sortable decimal format\ +\n %c-C%c be case-insensitive %s\ + -x exclude filenames that follow from listing\n\ + -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\ + -I CHARSET specify a character encoding for UNIX and other archives\n"; +#endif /* !UNIX */ #ifdef MORE static ZCONST char Far ZipInfoUsageLine4[] = " -M page output through built-in \"more\"\n"; @@ -665,6 +675,17 @@ -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\ -C match filenames case-insensitively -L make (some) names \ lowercase\n %-42s -V retain VMS version numbers\n%s"; +#elif (defined UNIX) +static ZCONST char Far UnzipUsageLine4[] = "\ +modifiers:\n\ + -n never overwrite existing files -q quiet mode (-qq => quieter)\n\ + -o overwrite files WITHOUT prompting -a auto-convert any text files\n\ + -j junk paths (do not make directories) -aa treat ALL files as text\n\ + -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\ + -C match filenames case-insensitively -L make (some) names \ +lowercase\n %-42s -V retain VMS version numbers\n%s\ + -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\ + -I CHARSET specify a character encoding for UNIX and other archives\n\n"; #else /* !VMS */ static ZCONST char Far UnzipUsageLine4[] = "\ modifiers:\n\ @@ -803,6 +824,10 @@ #endif /* UNICODE_SUPPORT */ +#ifdef UNIX + init_conversion_charsets(); +#endif + #if (defined(__IBMC__) && defined(__DEBUG_ALLOC__)) extern void DebugMalloc(void); @@ -1336,6 +1361,11 @@ argc = *pargc; argv = *pargv; +#ifdef UNIX + extern char OEM_CP[MAX_CP_NAME]; + extern char ISO_CP[MAX_CP_NAME]; +#endif + while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) { s = *argv + 1; while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */ @@ -1517,6 +1547,37 @@ } break; #endif /* MACOS */ +#ifdef UNIX + case ('I'): + if (negative) { + Info(slide, 0x401, ((char *)slide, + "error: encodings can't be negated")); + return(PK_PARAM); + } else { + if(*s) { /* Handle the -Icharset case */ + /* Assume that charsets can't start with a dash to spot arguments misuse */ + if(*s == '-') { + Info(slide, 0x401, ((char *)slide, + "error: a valid character encoding should follow the -I argument")); + return(PK_PARAM); + } + strncpy(ISO_CP, s, MAX_CP_NAME - 1); + ISO_CP[MAX_CP_NAME - 1] = '\0'; + } else { /* -I charset */ + ++argv; + if(!(--argc > 0 && *argv != NULL && **argv != '-')) { + Info(slide, 0x401, ((char *)slide, + "error: a valid character encoding should follow the -I argument")); + return(PK_PARAM); + } + s = *argv; + strncpy(ISO_CP, s, MAX_CP_NAME - 1); + ISO_CP[MAX_CP_NAME - 1] = '\0'; + } + while(*(++s)); /* No params straight after charset name */ + } + break; +#endif /* ?UNIX */ case ('j'): /* junk pathnames/directory structure */ if (negative) uO.jflag = FALSE, negative = 0; @@ -1592,6 +1653,37 @@ } else ++uO.overwrite_all; break; +#ifdef UNIX + case ('O'): + if (negative) { + Info(slide, 0x401, ((char *)slide, + "error: encodings can't be negated")); + return(PK_PARAM); + } else { + if(*s) { /* Handle the -Ocharset case */ + /* Assume that charsets can't start with a dash to spot arguments misuse */ + if(*s == '-') { + Info(slide, 0x401, ((char *)slide, + "error: a valid character encoding should follow the -I argument")); + return(PK_PARAM); + } + strncpy(OEM_CP, s, MAX_CP_NAME - 1); + OEM_CP[MAX_CP_NAME - 1] = '\0'; + } else { /* -O charset */ + ++argv; + if(!(--argc > 0 && *argv != NULL && **argv != '-')) { + Info(slide, 0x401, ((char *)slide, + "error: a valid character encoding should follow the -O argument")); + return(PK_PARAM); + } + s = *argv; + strncpy(OEM_CP, s, MAX_CP_NAME - 1); + OEM_CP[MAX_CP_NAME - 1] = '\0'; + } + while(*(++s)); /* No params straight after charset name */ + } + break; +#endif /* ?UNIX */ case ('p'): /* pipes: extract to stdout, no messages */ if (negative) { uO.cflag = FALSE; diff -Naur a/unzip.c.orig b/unzip.c.orig --- a/unzip.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ b/unzip.c.orig 2009-04-16 19:26:52.000000000 +0100 @@ -0,0 +1,2655 @@ +/* + Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2009-Jan-02 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 +*/ +/*--------------------------------------------------------------------------- + + unzip.c + + UnZip - a zipfile extraction utility. See below for make instructions, or + read the comments in Makefile and the various Contents files for more de- + tailed explanations. To report a bug, submit a *complete* description via + //www.info-zip.org/zip-bug.html; include machine type, operating system and + version, compiler and version, and reasonably detailed error messages or + problem report. To join Info-ZIP, see the instructions in README. + + UnZip 5.x is a greatly expanded and partially rewritten successor to 4.x, + which in turn was almost a complete rewrite of version 3.x. For a detailed + revision history, see UnzpHist.zip at quest.jpl.nasa.gov. For a list of + the many (near infinite) contributors, see "CONTRIBS" in the UnZip source + distribution. + + UnZip 6.0 adds support for archives larger than 4 GiB using the Zip64 + extensions as well as support for Unicode information embedded per the + latest zip standard additions. + + --------------------------------------------------------------------------- + + [from original zipinfo.c] + + This program reads great gobs of totally nifty information, including the + central directory stuff, from ZIP archives ("zipfiles" for short). It + started as just a testbed for fooling with zipfiles, but at this point it + is actually a useful utility. It also became the basis for the rewrite of + UnZip (3.16 -> 4.0), using the central directory for processing rather than + the individual (local) file headers. + + As of ZipInfo v2.0 and UnZip v5.1, the two programs are combined into one. + If the executable is named "unzip" (or "unzip.exe", depending), it behaves + like UnZip by default; if it is named "zipinfo" or "ii", it behaves like + ZipInfo. The ZipInfo behavior may also be triggered by use of unzip's -Z + option; for example, "unzip -Z [zipinfo_options] archive.zip". + + Another dandy product from your buddies at Newtware! + + Author: Greg Roelofs, newt@pobox.com, http://pobox.com/~newt/ + 23 August 1990 -> April 1997 + + --------------------------------------------------------------------------- + + Version: unzip5??.{tar.Z | tar.gz | zip} for Unix, VMS, OS/2, MS-DOS, Amiga, + Atari, Windows 3.x/95/NT/CE, Macintosh, Human68K, Acorn RISC OS, + AtheOS, BeOS, SMS/QDOS, VM/CMS, MVS, AOS/VS, Tandem NSK, Theos + and TOPS-20. + + Copyrights: see accompanying file "LICENSE" in UnZip source distribution. + (This software is free but NOT IN THE PUBLIC DOMAIN.) + + ---------------------------------------------------------------------------*/ + + + +#define __UNZIP_C /* identifies this source module */ +#define UNZIP_INTERNAL +#include "unzip.h" /* includes, typedefs, macros, prototypes, etc. */ +#include "crypt.h" +#include "unzvers.h" + +#ifndef WINDLL /* The WINDLL port uses windll/windll.c instead... */ + +/***************************/ +/* Local type declarations */ +/***************************/ + +#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS)) +typedef struct _sign_info + { + struct _sign_info *previous; + void (*sighandler)(int); + int sigtype; + } savsigs_info; +#endif + +/*******************/ +/* Local Functions */ +/*******************/ + +#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS)) +static int setsignalhandler OF((__GPRO__ savsigs_info **p_savedhandler_chain, + int signal_type, void (*newhandler)(int))); +#endif +#ifndef SFX +static void help_extended OF((__GPRO)); +static void show_version_info OF((__GPRO)); +#endif + + +/*************/ +/* Constants */ +/*************/ + +#include "consts.h" /* all constant global variables are in here */ + /* (non-constant globals were moved to globals.c) */ + +/* constant local variables: */ + +#ifndef SFX +#ifndef _WIN32_WCE /* Win CE does not support environment variables */ + static ZCONST char Far EnvUnZip[] = ENV_UNZIP; + static ZCONST char Far EnvUnZip2[] = ENV_UNZIP2; + static ZCONST char Far EnvZipInfo[] = ENV_ZIPINFO; + static ZCONST char Far EnvZipInfo2[] = ENV_ZIPINFO2; +#ifdef RISCOS + static ZCONST char Far EnvUnZipExts[] = ENV_UNZIPEXTS; +#endif /* RISCOS */ + static ZCONST char Far NoMemEnvArguments[] = + "envargs: cannot get memory for arguments"; +#endif /* !_WIN32_WCE */ + static ZCONST char Far CmdLineParamTooLong[] = + "error: command line parameter #%d exceeds internal size limit\n"; +#endif /* !SFX */ + +#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS)) + static ZCONST char Far CantSaveSigHandler[] = + "error: cannot save signal handler settings\n"; +#endif + +#if (!defined(SFX) || defined(SFX_EXDIR)) + static ZCONST char Far NotExtracting[] = + "caution: not extracting; -d ignored\n"; + static ZCONST char Far MustGiveExdir[] = + "error: must specify directory to which to extract with -d option\n"; + static ZCONST char Far OnlyOneExdir[] = + "error: -d option used more than once (only one exdir allowed)\n"; +#endif +#if (defined(UNICODE_SUPPORT) && !defined(UNICODE_WCHAR)) + static ZCONST char Far UTF8EscapeUnSupp[] = + "warning: -U \"escape all non-ASCII UTF-8 chars\" is not supported\n"; +#endif + +#if CRYPT + static ZCONST char Far MustGivePasswd[] = + "error: must give decryption password with -P option\n"; +#endif + +#ifndef SFX + static ZCONST char Far Zfirst[] = + "error: -Z must be first option for ZipInfo mode (check UNZIP variable?)\n"; +#endif +static ZCONST char Far InvalidOptionsMsg[] = "error:\ + -fn or any combination of -c, -l, -p, -t, -u and -v options invalid\n"; +static ZCONST char Far IgnoreOOptionMsg[] = + "caution: both -n and -o specified; ignoring -o\n"; + +/* usage() strings */ +#ifndef SFX +#ifdef VMS + static ZCONST char Far Example3[] = "vms.c"; + static ZCONST char Far Example2[] = " unzip \"-V\" foo \"Bar\"\ + (Quote names to preserve case, unless SET PROC/PARS=EXT)\n"; +#else /* !VMS */ + static ZCONST char Far Example3[] = "ReadMe"; +#ifdef RISCOS + static ZCONST char Far Example2[] = +" unzip foo -d RAM:$ => extract all files from foo into RAMDisc\n"; +#else /* !RISCOS */ +#if (defined(OS2) || (defined(DOS_FLX_OS2_W32) && defined(MORE))) + static ZCONST char Far Example2[] = + ""; /* no room: too many local3[] items */ +#else /* !OS2 */ +#ifdef MACOS + static ZCONST char Far Example2[] = ""; /* not needed */ +#else /* !MACOS */ + static ZCONST char Far Example2[] = " \ + unzip -p foo | more => send contents of foo.zip via pipe into program more\n"; +#endif /* ?MACOS */ +#endif /* ?OS2 */ +#endif /* ?RISCOS */ +#endif /* ?VMS */ + +/* local1[]: command options */ +#if defined(TIMESTAMP) + static ZCONST char Far local1[] = + " -T timestamp archive to latest"; +#else /* !TIMESTAMP */ + static ZCONST char Far local1[] = ""; +#endif /* ?TIMESTAMP */ + +/* local2[] and local3[]: modifier options */ +#ifdef DOS_FLX_H68_OS2_W32 +#ifdef FLEXOS + static ZCONST char Far local2[] = ""; +#else + static ZCONST char Far local2[] = + " -$ label removables (-$$ => fixed disks)"; +#endif +#ifdef OS2 +#ifdef MORE + static ZCONST char Far local3[] = "\ + -X restore ACLs if supported -s spaces in filenames => '_'\n\ + -M pipe through \"more\" pager\n"; +#else + static ZCONST char Far local3[] = " \ + -X restore ACLs if supported -s spaces in filenames => '_'\n\n"; +#endif /* ?MORE */ +#else /* !OS2 */ +#ifdef WIN32 +#ifdef NTSD_EAS +#ifdef MORE + static ZCONST char Far local3[] = "\ + -X restore ACLs (-XX => use privileges) -s spaces in filenames => '_'\n\ + -M pipe through \"more\" pager\n"; +#else + static ZCONST char Far local3[] = " \ + -X restore ACLs (-XX => use privileges) -s spaces in filenames => '_'\n\n"; +#endif /* ?MORE */ +#else /* !NTSD_EAS */ +#ifdef MORE + static ZCONST char Far local3[] = "\ + -M pipe through \"more\" pager \ + -s spaces in filenames => '_'\n\n"; +#else + static ZCONST char Far local3[] = " \ + -s spaces in filenames => '_'\n\n"; +#endif /* ?MORE */ +#endif /* ?NTSD_EAS */ +#else /* !WIN32 */ +#ifdef MORE + static ZCONST char Far local3[] = " -\ +M pipe through \"more\" pager -s spaces in filenames => '_'\n\n"; +#else + static ZCONST char Far local3[] = "\ + -s spaces in filenames => '_'\n"; +#endif +#endif /* ?WIN32 */ +#endif /* ?OS2 || ?WIN32 */ +#else /* !DOS_FLX_OS2_W32 */ +#ifdef VMS + static ZCONST char Far local2[] = " -X restore owner/ACL protection info"; +#ifdef MORE + static ZCONST char Far local3[] = "\ + -Y treat \".nnn\" as \";nnn\" version -2 force ODS2 names\n\ + --D restore dir (-D: no) timestamps -M pipe through \"more\" pager\n\ + (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)\ +\n\n"; +#else + static ZCONST char Far local3[] = "\n\ + -Y treat \".nnn\" as \";nnn\" version -2 force ODS2 names\n\ + --D restore dir (-D: no) timestamps\n\ + (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)\ +\n\n"; +#endif +#else /* !VMS */ +#ifdef ATH_BEO_UNX + static ZCONST char Far local2[] = " -X restore UID/GID info"; +#ifdef MORE + static ZCONST char Far local3[] = "\ + -K keep setuid/setgid/tacky permissions -M pipe through \"more\" pager\n"; +#else + static ZCONST char Far local3[] = "\ + -K keep setuid/setgid/tacky permissions\n"; +#endif +#else /* !ATH_BEO_UNX */ +#ifdef TANDEM + static ZCONST char Far local2[] = "\ + -X restore Tandem User ID -r remove file extensions\n\ + -b create 'C' (180) text files "; +#ifdef MORE + static ZCONST char Far local3[] = " \ + -M pipe through \"more\" pager\n"; +#else + static ZCONST char Far local3[] = "\n"; +#endif +#else /* !TANDEM */ +#ifdef AMIGA + static ZCONST char Far local2[] = " -N restore comments as filenotes"; +#ifdef MORE + static ZCONST char Far local3[] = " \ + -M pipe through \"more\" pager\n"; +#else + static ZCONST char Far local3[] = "\n"; +#endif +#else /* !AMIGA */ +#ifdef MACOS + static ZCONST char Far local2[] = " -E show Mac info during extraction"; + static ZCONST char Far local3[] = " \ + -i ignore filenames in mac extra info -J junk (ignore) Mac extra info\n\ +\n"; +#else /* !MACOS */ +#ifdef MORE + static ZCONST char Far local2[] = " -M pipe through \"more\" pager"; + static ZCONST char Far local3[] = "\n"; +#else + static ZCONST char Far local2[] = ""; /* Atari, Mac, CMS/MVS etc. */ + static ZCONST char Far local3[] = ""; +#endif +#endif /* ?MACOS */ +#endif /* ?AMIGA */ +#endif /* ?TANDEM */ +#endif /* ?ATH_BEO_UNX */ +#endif /* ?VMS */ +#endif /* ?DOS_FLX_OS2_W32 */ +#endif /* !SFX */ + +#ifndef NO_ZIPINFO +#ifdef VMS + static ZCONST char Far ZipInfoExample[] = "* or % (e.g., \"*font-%.zip\")"; +#else + static ZCONST char Far ZipInfoExample[] = "*, ?, [] (e.g., \"[a-j]*.zip\")"; +#endif + +static ZCONST char Far ZipInfoUsageLine1[] = "\ +ZipInfo %d.%d%d%s of %s, by Greg Roelofs and the Info-ZIP group.\n\ +\n\ +List name, date/time, attribute, size, compression method, etc., about files\n\ +in list (excluding those in xlist) contained in the specified .zip archive(s).\ +\n\"file[.zip]\" may be a wildcard name containing %s.\n\n\ + usage: zipinfo [-12smlvChMtTz] file[.zip] [list...] [-x xlist...]\n\ + or: unzip %s-Z%s [-12smlvChMtTz] file[.zip] [list...] [-x xlist...]\n"; + +static ZCONST char Far ZipInfoUsageLine2[] = "\nmain\ + listing-format options: -s short Unix \"ls -l\" format (def.)\n\ + -1 filenames ONLY, one per line -m medium Unix \"ls -l\" format\n\ + -2 just filenames but allow -h/-t/-z -l long Unix \"ls -l\" format\n\ + -v verbose, multi-page format\n"; + +static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\ + -h print header line -t print totals for listed files or for all\n\ + -z print zipfile comment -T print file times in sortable decimal format\ +\n -C be case-insensitive %s\ + -x exclude filenames that follow from listing\n"; +#ifdef MORE + static ZCONST char Far ZipInfoUsageLine4[] = + " -M page output through built-in \"more\"\n"; +#else /* !MORE */ + static ZCONST char Far ZipInfoUsageLine4[] = ""; +#endif /* ?MORE */ +#endif /* !NO_ZIPINFO */ + +#ifdef BETA +# ifdef VMSCLI + /* BetaVersion[] is also used in vms/cmdline.c: do not make it static */ + ZCONST char Far BetaVersion[] = "%s\ + THIS IS STILL A BETA VERSION OF UNZIP%s -- DO NOT DISTRIBUTE.\n\n"; +# else + static ZCONST char Far BetaVersion[] = "%s\ + THIS IS STILL A BETA VERSION OF UNZIP%s -- DO NOT DISTRIBUTE.\n\n"; +# endif +#endif + +#ifdef SFX +# ifdef VMSCLI + /* UnzipSFXBanner[] is also used in vms/cmdline.c: do not make it static */ + ZCONST char Far UnzipSFXBanner[] = +# else + static ZCONST char Far UnzipSFXBanner[] = +# endif + "UnZipSFX %d.%d%d%s of %s, by Info-ZIP (http://www.info-zip.org).\n"; +# ifdef SFX_EXDIR + static ZCONST char Far UnzipSFXOpts[] = + "Valid options are -tfupcz and -d ; modifiers are -abjnoqCL%sV%s.\n"; +# else + static ZCONST char Far UnzipSFXOpts[] = + "Valid options are -tfupcz; modifiers are -abjnoqCL%sV%s.\n"; +# endif +#else /* !SFX */ + static ZCONST char Far CompileOptions[] = + "UnZip special compilation options:\n"; + static ZCONST char Far CompileOptFormat[] = " %s\n"; +#ifndef _WIN32_WCE /* Win CE does not support environment variables */ + static ZCONST char Far EnvOptions[] = + "\nUnZip and ZipInfo environment options:\n"; + static ZCONST char Far EnvOptFormat[] = "%16s: %.1024s\n"; +#endif + static ZCONST char Far None[] = "[none]"; +# ifdef ACORN_FTYPE_NFS + static ZCONST char Far AcornFtypeNFS[] = "ACORN_FTYPE_NFS"; +# endif +# ifdef ASM_CRC + static ZCONST char Far AsmCRC[] = "ASM_CRC"; +# endif +# ifdef ASM_INFLATECODES + static ZCONST char Far AsmInflateCodes[] = "ASM_INFLATECODES"; +# endif +# ifdef CHECK_VERSIONS + static ZCONST char Far Check_Versions[] = "CHECK_VERSIONS"; +# endif +# ifdef COPYRIGHT_CLEAN + static ZCONST char Far Copyright_Clean[] = + "COPYRIGHT_CLEAN (PKZIP 0.9x unreducing method not supported)"; +# endif +# ifdef DEBUG + static ZCONST char Far UDebug[] = "DEBUG"; +# endif +# ifdef DEBUG_TIME + static ZCONST char Far DebugTime[] = "DEBUG_TIME"; +# endif +# ifdef DLL + static ZCONST char Far Dll[] = "DLL"; +# endif +# ifdef DOSWILD + static ZCONST char Far DosWild[] = "DOSWILD"; +# endif +# ifdef LZW_CLEAN + static ZCONST char Far LZW_Clean[] = + "LZW_CLEAN (PKZIP/Zip 1.x unshrinking method not supported)"; +# endif +# ifndef MORE + static ZCONST char Far No_More[] = "NO_MORE"; +# endif +# ifdef NO_ZIPINFO + static ZCONST char Far No_ZipInfo[] = "NO_ZIPINFO"; +# endif +# ifdef NTSD_EAS + static ZCONST char Far NTSDExtAttrib[] = "NTSD_EAS"; +# endif +# if defined(WIN32) && defined(NO_W32TIMES_IZFIX) + static ZCONST char Far W32NoIZTimeFix[] = "NO_W32TIMES_IZFIX"; +# endif +# ifdef OLD_THEOS_EXTRA + static ZCONST char Far OldTheosExtra[] = + "OLD_THEOS_EXTRA (handle also old Theos port extra field)"; +# endif +# ifdef OS2_EAS + static ZCONST char Far OS2ExtAttrib[] = "OS2_EAS"; +# endif +# ifdef QLZIP + static ZCONST char Far SMSExFldOnUnix[] = "QLZIP"; +# endif +# ifdef REENTRANT + static ZCONST char Far Reentrant[] = "REENTRANT"; +# endif +# ifdef REGARGS + static ZCONST char Far RegArgs[] = "REGARGS"; +# endif +# ifdef RETURN_CODES + static ZCONST char Far Return_Codes[] = "RETURN_CODES"; +# endif +# ifdef SET_DIR_ATTRIB + static ZCONST char Far SetDirAttrib[] = "SET_DIR_ATTRIB"; +# endif +# ifdef SYMLINKS + static ZCONST char Far SymLinkSupport[] = + "SYMLINKS (symbolic links supported, if RTL and file system permit)"; +# endif +# ifdef TIMESTAMP + static ZCONST char Far TimeStamp[] = "TIMESTAMP"; +# endif +# ifdef UNIXBACKUP + static ZCONST char Far UnixBackup[] = "UNIXBACKUP"; +# endif +# ifdef USE_EF_UT_TIME + static ZCONST char Far Use_EF_UT_time[] = "USE_EF_UT_TIME"; +# endif +# ifndef LZW_CLEAN + static ZCONST char Far Use_Unshrink[] = + "USE_UNSHRINK (PKZIP/Zip 1.x unshrinking method supported)"; +# endif +# ifndef COPYRIGHT_CLEAN + static ZCONST char Far Use_Smith_Code[] = + "USE_SMITH_CODE (PKZIP 0.9x unreducing method supported)"; +# endif +# ifdef USE_DEFLATE64 + static ZCONST char Far Use_Deflate64[] = + "USE_DEFLATE64 (PKZIP 4.x Deflate64(tm) supported)"; +# endif +# ifdef UNICODE_SUPPORT +# ifdef UTF8_MAYBE_NATIVE +# ifdef UNICODE_WCHAR + /* direct native UTF-8 check AND charset transform via wchar_t */ + static ZCONST char Far Use_Unicode[] = + "UNICODE_SUPPORT [wide-chars, char coding: %s] (handle UTF-8 paths)"; +# else + /* direct native UTF-8 check, only */ + static ZCONST char Far Use_Unicode[] = + "UNICODE_SUPPORT [char coding: %s] (handle UTF-8 paths)"; +# endif + static ZCONST char Far SysChUTF8[] = "UTF-8"; + static ZCONST char Far SysChOther[] = "other"; +# else /* !UTF8_MAYBE_NATIVE */ + /* charset transform via wchar_t, no native UTF-8 support */ + static ZCONST char Far Use_Unicode[] = + "UNICODE_SUPPORT [wide-chars] (handle UTF-8 paths)"; +# endif /* ?UTF8_MAYBE_NATIVE */ +# endif /* UNICODE_SUPPORT */ +# ifdef _MBCS + static ZCONST char Far Have_MBCS_Support[] = + "MBCS-support (multibyte character support, MB_CUR_MAX = %u)"; +# endif +# ifdef MULT_VOLUME + static ZCONST char Far Use_MultiVol[] = + "MULT_VOLUME (multi-volume archives supported)"; +# endif +# ifdef LARGE_FILE_SUPPORT + static ZCONST char Far Use_LFS[] = + "LARGE_FILE_SUPPORT (large files over 2 GiB supported)"; +# endif +# ifdef ZIP64_SUPPORT + static ZCONST char Far Use_Zip64[] = + "ZIP64_SUPPORT (archives using Zip64 for large files supported)"; +# endif +# if (defined(__DJGPP__) && (__DJGPP__ >= 2)) +# ifdef USE_DJGPP_ENV + static ZCONST char Far Use_DJGPP_Env[] = "USE_DJGPP_ENV"; +# endif +# ifdef USE_DJGPP_GLOB + static ZCONST char Far Use_DJGPP_Glob[] = "USE_DJGPP_GLOB"; +# endif +# endif /* __DJGPP__ && (__DJGPP__ >= 2) */ +# ifdef USE_VFAT + static ZCONST char Far Use_VFAT_support[] = "USE_VFAT"; +# endif +# ifdef USE_ZLIB + static ZCONST char Far UseZlib[] = + "USE_ZLIB (compiled with version %s; using version %s)"; +# endif +# ifdef USE_BZIP2 + static ZCONST char Far UseBZip2[] = + "USE_BZIP2 (PKZIP 4.6+, using bzip2 lib version %s)"; +# endif +# ifdef VMS_TEXT_CONV + static ZCONST char Far VmsTextConv[] = "VMS_TEXT_CONV"; +# endif +# ifdef VMSCLI + static ZCONST char Far VmsCLI[] = "VMSCLI"; +# endif +# ifdef VMSWILD + static ZCONST char Far VmsWild[] = "VMSWILD"; +# endif +# ifdef WILD_STOP_AT_DIR + static ZCONST char Far WildStopAtDir[] = "WILD_STOP_AT_DIR"; +# endif +# if CRYPT +# ifdef PASSWD_FROM_STDIN + static ZCONST char Far PasswdStdin[] = "PASSWD_FROM_STDIN"; +# endif + static ZCONST char Far Decryption[] = + " [decryption, version %d.%d%s of %s]\n"; + static ZCONST char Far CryptDate[] = CR_VERSION_DATE; +# endif +# ifndef __RSXNT__ +# ifdef __EMX__ + static ZCONST char Far EnvEMX[] = "EMX"; + static ZCONST char Far EnvEMXOPT[] = "EMXOPT"; +# endif +# if (defined(__GO32__) && (!defined(__DJGPP__) || (__DJGPP__ < 2))) + static ZCONST char Far EnvGO32[] = "GO32"; + static ZCONST char Far EnvGO32TMP[] = "GO32TMP"; +# endif +# endif /* !__RSXNT__ */ + +#ifdef VMS +/* UnzipUsageLine1[] is also used in vms/cmdline.c: do not make it static */ + ZCONST char Far UnzipUsageLine1[] = "\ +UnZip %d.%d%d%s of %s, by Info-ZIP. For more details see: unzip -v.\n\n"; +# ifdef COPYRIGHT_CLEAN + static ZCONST char Far UnzipUsageLine1v[] = "\ +UnZip %d.%d%d%s of %s, by Info-ZIP. Maintained by C. Spieler. Send\n\ +bug reports using http://www.info-zip.org/zip-bug.html; see README for details.\ +\n\n"; +# else + static ZCONST char Far UnzipUsageLine1v[] = "\ +UnZip %d.%d%d%s of %s, by Info-ZIP. UnReduce (c) 1989 by S. H. Smith.\n\ +Send bug reports using //www.info-zip.org/zip-bug.html; see README for details.\ +\n\n"; +# endif /* ?COPYRIGHT_CLEAN */ +#else /* !VMS */ +# ifdef COPYRIGHT_CLEAN + static ZCONST char Far UnzipUsageLine1[] = "\ +UnZip %d.%d%d%s of %s, by Info-ZIP. Maintained by C. Spieler. Send\n\ +bug reports using http://www.info-zip.org/zip-bug.html; see README for details.\ +\n\n"; +# else + static ZCONST char Far UnzipUsageLine1[] = "\ +UnZip %d.%d%d%s of %s, by Info-ZIP. UnReduce (c) 1989 by S. H. Smith.\n\ +Send bug reports using //www.info-zip.org/zip-bug.html; see README for details.\ +\n\n"; +# endif /* ?COPYRIGHT_CLEAN */ +# define UnzipUsageLine1v UnzipUsageLine1 +#endif /* ?VMS */ + +static ZCONST char Far UnzipUsageLine2v[] = "\ +Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip/ ;\ +\nsee ftp://ftp.info-zip.org/pub/infozip/UnZip.html for other sites.\ +\n\n"; + +#ifdef MACOS +static ZCONST char Far UnzipUsageLine2[] = "\ +Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-d exdir]\n \ + Default action is to extract files in list, to exdir;\n\ + file[.zip] may be a wildcard. %s\n"; +#else /* !MACOS */ +#ifdef VM_CMS +static ZCONST char Far UnzipUsageLine2[] = "\ +Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d fm]\n \ + Default action is to extract files in list, except those in xlist, to disk fm;\ +\n file[.zip] may be a wildcard. %s\n"; +#else /* !VM_CMS */ +static ZCONST char Far UnzipUsageLine2[] = "\ +Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]\n \ + Default action is to extract files in list, except those in xlist, to exdir;\n\ + file[.zip] may be a wildcard. %s\n"; +#endif /* ?VM_CMS */ +#endif /* ?MACOS */ + +#ifdef NO_ZIPINFO +# define ZIPINFO_MODE_OPTION "" + static ZCONST char Far ZipInfoMode[] = + "(ZipInfo mode is disabled in this version.)"; +#else +# define ZIPINFO_MODE_OPTION "[-Z] " + static ZCONST char Far ZipInfoMode[] = + "-Z => ZipInfo mode (\"unzip -Z\" for usage)."; +#endif /* ?NO_ZIPINFO */ + +#ifdef VMS + static ZCONST char Far VMSusageLine2b[] = "\ +=> define foreign command symbol in LOGIN.COM: $ unzip :== $dev:[dir]unzip.exe\ +\n"; +#endif + +#ifdef MACOS +static ZCONST char Far UnzipUsageLine3[] = "\n\ + -d extract files into exdir -l list files (short format)\n\ + -f freshen existing files, create none -t test compressed archive data\n\ + -u update files, create if necessary -z display archive comment only\n\ + -v list verbosely/show version info %s\n"; +#else /* !MACOS */ +#ifdef VM_CMS +static ZCONST char Far UnzipUsageLine3[] = "\n\ + -p extract files to pipe, no messages -l list files (short format)\n\ + -f freshen existing files, create none -t test compressed archive data\n\ + -u update files, create if necessary -z display archive comment only\n\ + -v list verbosely/show version info %s\n\ + -x exclude files that follow (in xlist) -d extract files onto disk fm\n"; +#else /* !VM_CMS */ +static ZCONST char Far UnzipUsageLine3[] = "\n\ + -p extract files to pipe, no messages -l list files (short format)\n\ + -f freshen existing files, create none -t test compressed archive data\n\ + -u update files, create if necessary -z display archive comment only\n\ + -v list verbosely/show version info %s\n\ + -x exclude files that follow (in xlist) -d extract files into exdir\n"; +#endif /* ?VM_CMS */ +#endif /* ?MACOS */ + +/* There is not enough space on a standard 80x25 Windows console screen for + * the additional line advertising the UTF-8 debugging options. This may + * eventually also be the case for other ports. Probably, the -U option need + * not be shown on the introductory screen at all. [Chr. Spieler, 2008-02-09] + * + * Likely, other advanced options should be moved to an extended help page and + * the option to list that page put here. [E. Gordon, 2008-3-16] + */ +#if (defined(UNICODE_SUPPORT) && !defined(WIN32)) +#ifdef VMS +static ZCONST char Far UnzipUsageLine4[] = "\ +modifiers:\n\ + -n never overwrite or make a new version of an existing file\n\ + -o always make a new version (-oo: overwrite original) of an existing file\n\ + -q quiet mode (-qq => quieter) -a auto-convert any text files\n\ + -j junk paths (do not make directories) -aa treat ALL files as text\n\ + -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\ + -C match filenames case-insensitively -L make (some) names \ +lowercase\n %-42s -V retain VMS version numbers\n%s"; +#else /* !VMS */ +static ZCONST char Far UnzipUsageLine4[] = "\ +modifiers:\n\ + -n never overwrite existing files -q quiet mode (-qq => quieter)\n\ + -o overwrite files WITHOUT prompting -a auto-convert any text files\n\ + -j junk paths (do not make directories) -aa treat ALL files as text\n\ + -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\ + -C match filenames case-insensitively -L make (some) names \ +lowercase\n %-42s -V retain VMS version numbers\n%s"; +#endif /* ?VMS */ +#else /* !UNICODE_SUPPORT */ +#ifdef VMS +static ZCONST char Far UnzipUsageLine4[] = "\ +modifiers:\n\ + -n never overwrite or make a new version of an existing file\n\ + -o always make a new version (-oo: overwrite original) of an existing file\n\ + -q quiet mode (-qq => quieter) -a auto-convert any text files\n\ + -j junk paths (do not make directories) -aa treat ALL files as text\n\ + -C match filenames case-insensitively -L make (some) names \ +lowercase\n %-42s -V retain VMS version numbers\n%s"; +#else /* !VMS */ +static ZCONST char Far UnzipUsageLine4[] = "\ +modifiers:\n\ + -n never overwrite existing files -q quiet mode (-qq => quieter)\n\ + -o overwrite files WITHOUT prompting -a auto-convert any text files\n\ + -j junk paths (do not make directories) -aa treat ALL files as text\n\ + -C match filenames case-insensitively -L make (some) names \ +lowercase\n %-42s -V retain VMS version numbers\n%s"; +#endif /* ?VMS */ +#endif /* ?UNICODE_SUPPORT */ + +static ZCONST char Far UnzipUsageLine5[] = "\ +See \"unzip -hh\" or unzip.txt for more help. Examples:\n\ + unzip data1 -x joe => extract all files except joe from zipfile data1.zip\n\ +%s\ + unzip -fo foo %-6s => quietly replace existing %s if archive file newer\n"; +#endif /* ?SFX */ + + + + + +/*****************************/ +/* main() / UzpMain() stub */ +/*****************************/ + +int MAIN(argc, argv) /* return PK-type error code (except under VMS) */ + int argc; + char *argv[]; +{ + int r; + + CONSTRUCTGLOBALS(); + r = unzip(__G__ argc, argv); + DESTROYGLOBALS(); + RETURN(r); +} + + + + +/*******************************/ +/* Primary UnZip entry point */ +/*******************************/ + +int unzip(__G__ argc, argv) + __GDEF + int argc; + char *argv[]; +{ +#ifndef NO_ZIPINFO + char *p; +#endif +#if (defined(DOS_FLX_H68_NLM_OS2_W32) || !defined(SFX)) + int i; +#endif + int retcode, error=FALSE; +#ifndef NO_EXCEPT_SIGNALS +#ifdef REENTRANT + savsigs_info *oldsighandlers = NULL; +# define SET_SIGHANDLER(sigtype, newsighandler) \ + if ((retcode = setsignalhandler(__G__ &oldsighandlers, (sigtype), \ + (newsighandler))) > PK_WARN) \ + goto cleanup_and_exit +#else +# define SET_SIGHANDLER(sigtype, newsighandler) \ + signal((sigtype), (newsighandler)) +#endif +#endif /* NO_EXCEPT_SIGNALS */ + + /* initialize international char support to the current environment */ + SETLOCALE(LC_CTYPE, ""); + +#ifdef UNICODE_SUPPORT + /* see if can use UTF-8 Unicode locale */ +# ifdef UTF8_MAYBE_NATIVE + { + char *codeset; +# if !(defined(NO_NL_LANGINFO) || defined(NO_LANGINFO_H)) + /* get the codeset (character set encoding) currently used */ +# include + + codeset = nl_langinfo(CODESET); +# else /* NO_NL_LANGINFO || NO_LANGINFO_H */ + /* query the current locale setting for character classification */ + codeset = setlocale(LC_CTYPE, NULL); + if (codeset != NULL) { + /* extract the codeset portion of the locale name */ + codeset = strchr(codeset, '.'); + if (codeset != NULL) ++codeset; + } +# endif /* ?(NO_NL_LANGINFO || NO_LANGINFO_H) */ + /* is the current codeset UTF-8 ? */ + if ((codeset != NULL) && (strcmp(codeset, "UTF-8") == 0)) { + /* successfully found UTF-8 char coding */ + G.native_is_utf8 = TRUE; + } else { + /* Current codeset is not UTF-8 or cannot be determined. */ + G.native_is_utf8 = FALSE; + } + /* Note: At least for UnZip, trying to change the process codeset to + * UTF-8 does not work. For the example Linux setup of the + * UnZip maintainer, a successful switch to "en-US.UTF-8" + * resulted in garbage display of all non-basic ASCII characters. + */ + } +# endif /* UTF8_MAYBE_NATIVE */ + + /* initialize Unicode */ + G.unicode_escape_all = 0; + G.unicode_mismatch = 0; + + G.unipath_version = 0; + G.unipath_checksum = 0; + G.unipath_filename = NULL; +#endif /* UNICODE_SUPPORT */ + + +#if (defined(__IBMC__) && defined(__DEBUG_ALLOC__)) + extern void DebugMalloc(void); + + atexit(DebugMalloc); +#endif + +#ifdef MALLOC_WORK + /* The following (rather complex) expression determines the allocation + size of the decompression work area. It simulates what the + combined "union" and "struct" declaration of the "static" work + area reservation achieves automatically at compile time. + Any decent compiler should evaluate this expression completely at + compile time and provide constants to the zcalloc() call. + (For better readability, some subexpressions are encapsulated + in temporarly defined macros.) + */ +# define UZ_SLIDE_CHUNK (sizeof(shrint)+sizeof(uch)+sizeof(uch)) +# define UZ_NUMOF_CHUNKS \ + (unsigned)(((WSIZE+UZ_SLIDE_CHUNK-1)/UZ_SLIDE_CHUNK > HSIZE) ? \ + (WSIZE+UZ_SLIDE_CHUNK-1)/UZ_SLIDE_CHUNK : HSIZE) + G.area.Slide = (uch *)zcalloc(UZ_NUMOF_CHUNKS, UZ_SLIDE_CHUNK); +# undef UZ_SLIDE_CHUNK +# undef UZ_NUMOF_CHUNKS + G.area.shrink.Parent = (shrint *)G.area.Slide; + G.area.shrink.value = G.area.Slide + (sizeof(shrint)*(HSIZE)); + G.area.shrink.Stack = G.area.Slide + + (sizeof(shrint) + sizeof(uch))*(HSIZE); +#endif + +/*--------------------------------------------------------------------------- + Set signal handler for restoring echo, warn of zipfile corruption, etc. + ---------------------------------------------------------------------------*/ +#ifndef NO_EXCEPT_SIGNALS +#ifdef SIGINT + SET_SIGHANDLER(SIGINT, handler); +#endif +#ifdef SIGTERM /* some systems really have no SIGTERM */ + SET_SIGHANDLER(SIGTERM, handler); +#endif +#if defined(SIGABRT) && !(defined(AMIGA) && defined(__SASC)) + SET_SIGHANDLER(SIGABRT, handler); +#endif +#ifdef SIGBREAK + SET_SIGHANDLER(SIGBREAK, handler); +#endif +#ifdef SIGBUS + SET_SIGHANDLER(SIGBUS, handler); +#endif +#ifdef SIGILL + SET_SIGHANDLER(SIGILL, handler); +#endif +#ifdef SIGSEGV + SET_SIGHANDLER(SIGSEGV, handler); +#endif +#endif /* NO_EXCEPT_SIGNALS */ + +#if (defined(WIN32) && defined(__RSXNT__)) + for (i = 0 ; i < argc; i++) { + _ISO_INTERN(argv[i]); + } +#endif + +/*--------------------------------------------------------------------------- + Macintosh initialization code. + ---------------------------------------------------------------------------*/ + +#ifdef MACOS + { + int a; + + for (a = 0; a < 4; ++a) + G.rghCursor[a] = GetCursor(a+128); + G.giCursor = 0; + } +#endif + +/*--------------------------------------------------------------------------- + NetWare initialization code. + ---------------------------------------------------------------------------*/ + +#ifdef NLM + InitUnZipConsole(); +#endif + +/*--------------------------------------------------------------------------- + Acorn RISC OS initialization code. + ---------------------------------------------------------------------------*/ + +#ifdef RISCOS + set_prefix(); +#endif + +/*--------------------------------------------------------------------------- + Theos initialization code. + ---------------------------------------------------------------------------*/ + +#ifdef THEOS + /* The easiest way found to force creation of libraries when selected + * members are to be unzipped. Explicitly add libraries names to the + * arguments list before the first member of the library. + */ + if (! _setargv(&argc, &argv)) { + Info(slide, 0x401, ((char *)slide, "cannot process argv\n")); + retcode = PK_MEM; + goto cleanup_and_exit; + } +#endif + +/*--------------------------------------------------------------------------- + Sanity checks. Commentary by Otis B. Driftwood and Fiorello: + + D: It's all right. That's in every contract. That's what they + call a sanity clause. + + F: Ha-ha-ha-ha-ha. You can't fool me. There ain't no Sanity + Claus. + ---------------------------------------------------------------------------*/ + +#ifdef DEBUG +# ifdef LARGE_FILE_SUPPORT + /* test if we can support large files - 10/6/04 EG */ + if (sizeof(zoff_t) < 8) { + Info(slide, 0x401, ((char *)slide, "LARGE_FILE_SUPPORT set but not supported\n")); + retcode = PK_BADERR; + goto cleanup_and_exit; + } + /* test if we can show 64-bit values */ + { + zoff_t z = ~(zoff_t)0; /* z should be all 1s now */ + char *sz; + + sz = FmZofft(z, FZOFFT_HEX_DOT_WID, "X"); + if ((sz[0] != 'F') || (strlen(sz) != 16)) + { + z = 0; + } + + /* shift z so only MSB is set */ + z <<= 63; + sz = FmZofft(z, FZOFFT_HEX_DOT_WID, "X"); + if ((sz[0] != '8') || (strlen(sz) != 16)) + { + Info(slide, 0x401, ((char *)slide, + "Can't show 64-bit values correctly\n")); + retcode = PK_BADERR; + goto cleanup_and_exit; + } + } +# endif /* LARGE_FILE_SUPPORT */ + + /* 2004-11-30 SMS. + Test the NEXTBYTE macro for proper operation. + */ + { + int test_char; + static uch test_buf[2] = { 'a', 'b' }; + + G.inptr = test_buf; + G.incnt = 1; + + test_char = NEXTBYTE; /* Should get 'a'. */ + if (test_char == 'a') + { + test_char = NEXTBYTE; /* Should get EOF, not 'b'. */ + } + if (test_char != EOF) + { + Info(slide, 0x401, ((char *)slide, + "NEXTBYTE macro failed. Try compiling with ALT_NEXTBYTE defined?")); + + retcode = PK_BADERR; + goto cleanup_and_exit; + } + } +#endif /* DEBUG */ + +/*--------------------------------------------------------------------------- + First figure out if we're running in UnZip mode or ZipInfo mode, and put + the appropriate environment-variable options into the queue. Then rip + through any command-line options lurking about... + ---------------------------------------------------------------------------*/ + +#ifdef SFX + G.argv0 = argv[0]; +#if (defined(OS2) || defined(WIN32)) + G.zipfn = GetLoadPath(__G);/* non-MSC NT puts path into G.filename[] */ +#else + G.zipfn = G.argv0; +#endif + +#ifdef VMSCLI + { + ulg status = vms_unzip_cmdline(&argc, &argv); + if (!(status & 1)) { + retcode = (int)status; + goto cleanup_and_exit; + } + } +#endif /* VMSCLI */ + + uO.zipinfo_mode = FALSE; + error = uz_opts(__G__ &argc, &argv); /* UnZipSFX call only */ + +#else /* !SFX */ + +#ifdef RISCOS + /* get the extensions to swap from environment */ + getRISCOSexts(ENV_UNZIPEXTS); +#endif + +#ifdef MSDOS + /* extract MKS extended argument list from environment (before envargs!) */ + mksargs(&argc, &argv); +#endif + +#ifdef VMSCLI + { + ulg status = vms_unzip_cmdline(&argc, &argv); + if (!(status & 1)) { + retcode = (int)status; + goto cleanup_and_exit; + } + } +#endif /* VMSCLI */ + + G.noargs = (argc == 1); /* no options, no zipfile, no anything */ + +#ifndef NO_ZIPINFO + for (p = argv[0] + strlen(argv[0]); p >= argv[0]; --p) { + if (*p == DIR_END +#ifdef DIR_END2 + || *p == DIR_END2 +#endif + ) + break; + } + ++p; + +#ifdef THEOS + if (strncmp(p, "ZIPINFO.",8) == 0 || strstr(p, ".ZIPINFO:") != NULL || + strncmp(p, "II.",3) == 0 || strstr(p, ".II:") != NULL || +#else + if (STRNICMP(p, LoadFarStringSmall(Zipnfo), 7) == 0 || + STRNICMP(p, "ii", 2) == 0 || +#endif + (argc > 1 && strncmp(argv[1], "-Z", 2) == 0)) + { + uO.zipinfo_mode = TRUE; +#ifndef _WIN32_WCE /* Win CE does not support environment variables */ + if ((error = envargs(&argc, &argv, LoadFarStringSmall(EnvZipInfo), + LoadFarStringSmall2(EnvZipInfo2))) != PK_OK) + perror(LoadFarString(NoMemEnvArguments)); +#endif + } else +#endif /* !NO_ZIPINFO */ + { + uO.zipinfo_mode = FALSE; +#ifndef _WIN32_WCE /* Win CE does not support environment variables */ + if ((error = envargs(&argc, &argv, LoadFarStringSmall(EnvUnZip), + LoadFarStringSmall2(EnvUnZip2))) != PK_OK) + perror(LoadFarString(NoMemEnvArguments)); +#endif + } + + if (!error) { + /* Check the length of all passed command line parameters. + * Command arguments might get sent through the Info() message + * system, which uses the sliding window area as string buffer. + * As arguments may additionally get fed through one of the FnFilter + * macros, we require all command line arguments to be shorter than + * WSIZE/4 (and ca. 2 standard line widths for fixed message text). + */ + for (i = 1 ; i < argc; i++) { + if (strlen(argv[i]) > ((WSIZE>>2) - 160)) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(CmdLineParamTooLong), i)); + retcode = PK_PARAM; + goto cleanup_and_exit; + } + } +#ifndef NO_ZIPINFO + if (uO.zipinfo_mode) + error = zi_opts(__G__ &argc, &argv); + else +#endif /* !NO_ZIPINFO */ + error = uz_opts(__G__ &argc, &argv); + } + +#endif /* ?SFX */ + + if ((argc < 0) || error) { + retcode = error; + goto cleanup_and_exit; + } + +/*--------------------------------------------------------------------------- + Now get the zipfile name from the command line and then process any re- + maining options and file specifications. + ---------------------------------------------------------------------------*/ + +#ifdef DOS_FLX_H68_NLM_OS2_W32 + /* convert MSDOS-style 'backward slash' directory separators to Unix-style + * 'forward slashes' for user's convenience (include zipfile name itself) + */ +#ifdef SFX + for (G.pfnames = argv, i = argc; i > 0; --i) { +#else + /* argc does not include the zipfile specification */ + for (G.pfnames = argv, i = argc+1; i > 0; --i) { +#endif +#ifdef __human68k__ + extern char *_toslash(char *); + _toslash(*G.pfnames); +#else /* !__human68k__ */ + char *q = *G.pfnames; + + while (*q != '\0') { + if (*q == '\\') + *q = '/'; + INCSTR(q); + } +#endif /* ?__human68k__ */ + ++G.pfnames; + } +#endif /* DOS_FLX_H68_NLM_OS2_W32 */ + +#ifndef SFX + G.wildzipfn = *argv++; +#endif + +#if (defined(SFX) && !defined(SFX_EXDIR)) /* only check for -x */ + + G.filespecs = argc; + G.xfilespecs = 0; + + if (argc > 0) { + char **pp = argv-1; + + G.pfnames = argv; + while (*++pp) + if (strcmp(*pp, "-x") == 0) { + if (pp > argv) { + *pp = 0; /* terminate G.pfnames */ + G.filespecs = pp - G.pfnames; + } else { + G.pfnames = (char **)fnames; /* defaults */ + G.filespecs = 0; + } + G.pxnames = pp + 1; /* excluded-names ptr: _after_ -x */ + G.xfilespecs = argc - G.filespecs - 1; + break; /* skip rest of args */ + } + G.process_all_files = FALSE; + } else + G.process_all_files = TRUE; /* for speed */ + +#else /* !SFX || SFX_EXDIR */ /* check for -x or -d */ + + G.filespecs = argc; + G.xfilespecs = 0; + + if (argc > 0) { + int in_files=FALSE, in_xfiles=FALSE; + char **pp = argv-1; + + G.process_all_files = FALSE; + G.pfnames = argv; + while (*++pp) { + Trace((stderr, "pp - argv = %d\n", pp-argv)); +#ifdef CMS_MVS + if (!uO.exdir && STRNICMP(*pp, "-d", 2) == 0) { +#else + if (!uO.exdir && strncmp(*pp, "-d", 2) == 0) { +#endif + int firstarg = (pp == argv); + + uO.exdir = (*pp) + 2; + if (in_files) { /* ... zipfile ... -d exdir ... */ + *pp = (char *)NULL; /* terminate G.pfnames */ + G.filespecs = pp - G.pfnames; + in_files = FALSE; + } else if (in_xfiles) { + *pp = (char *)NULL; /* terminate G.pxnames */ + G.xfilespecs = pp - G.pxnames; + /* "... -x xlist -d exdir": nothing left */ + } + /* first check for "-dexdir", then for "-d exdir" */ + if (*uO.exdir == '\0') { + if (*++pp) + uO.exdir = *pp; + else { + Info(slide, 0x401, ((char *)slide, + LoadFarString(MustGiveExdir))); + /* don't extract here by accident */ + retcode = PK_PARAM; + goto cleanup_and_exit; + } + } + if (firstarg) { /* ... zipfile -d exdir ... */ + if (pp[1]) { + G.pfnames = pp + 1; /* argv+2 */ + G.filespecs = argc - (G.pfnames-argv); /* for now... */ + } else { + G.process_all_files = TRUE; + G.pfnames = (char **)fnames; /* GRR: necessary? */ + G.filespecs = 0; /* GRR: necessary? */ + break; + } + } + } else if (!in_xfiles) { + if (strcmp(*pp, "-x") == 0) { + in_xfiles = TRUE; + if (pp == G.pfnames) { + G.pfnames = (char **)fnames; /* defaults */ + G.filespecs = 0; + } else if (in_files) { + *pp = 0; /* terminate G.pfnames */ + G.filespecs = pp - G.pfnames; /* adjust count */ + in_files = FALSE; + } + G.pxnames = pp + 1; /* excluded-names ptr starts after -x */ + G.xfilespecs = argc - (G.pxnames-argv); /* anything left */ + } else + in_files = TRUE; + } + } + } else + G.process_all_files = TRUE; /* for speed */ + + if (uO.exdir != (char *)NULL && !G.extract_flag) /* -d ignored */ + Info(slide, 0x401, ((char *)slide, LoadFarString(NotExtracting))); +#endif /* ?(SFX && !SFX_EXDIR) */ + +#ifdef UNICODE_SUPPORT + /* set Unicode-escape-all if option -U used */ + if (uO.U_flag == 1) +# ifdef UNICODE_WCHAR + G.unicode_escape_all = TRUE; +# else + Info(slide, 0x401, ((char *)slide, LoadFarString(UTF8EscapeUnSupp))); +# endif +#endif + + +/*--------------------------------------------------------------------------- + Okey dokey, we have everything we need to get started. Let's roll. + ---------------------------------------------------------------------------*/ + + retcode = process_zipfiles(__G); + +cleanup_and_exit: +#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS)) + /* restore all signal handlers back to their state at function entry */ + while (oldsighandlers != NULL) { + savsigs_info *thissigsav = oldsighandlers; + + signal(thissigsav->sigtype, thissigsav->sighandler); + oldsighandlers = thissigsav->previous; + free(thissigsav); + } +#endif +#if (defined(MALLOC_WORK) && !defined(REENTRANT)) + if (G.area.Slide != (uch *)NULL) { + free(G.area.Slide); + G.area.Slide = (uch *)NULL; + } +#endif +#if (defined(MSDOS) && !defined(SFX) && !defined(WINDLL)) + if (retcode != PK_OK) + check_for_windows("UnZip"); +#endif + return(retcode); + +} /* end main()/unzip() */ + + + + + +#if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS)) +/*******************************/ +/* Function setsignalhandler() */ +/*******************************/ + +static int setsignalhandler(__G__ p_savedhandler_chain, signal_type, + newhandler) + __GDEF + savsigs_info **p_savedhandler_chain; + int signal_type; + void (*newhandler)(int); +{ + savsigs_info *savsig; + + savsig = malloc(sizeof(savsigs_info)); + if (savsig == NULL) { + /* error message and break */ + Info(slide, 0x401, ((char *)slide, LoadFarString(CantSaveSigHandler))); + return PK_MEM; + } + savsig->sigtype = signal_type; + savsig->sighandler = signal(SIGINT, newhandler); + if (savsig->sighandler == SIG_ERR) { + free(savsig); + } else { + savsig->previous = *p_savedhandler_chain; + *p_savedhandler_chain = savsig; + } + return PK_OK; + +} /* end function setsignalhandler() */ + +#endif /* REENTRANT && !NO_EXCEPT_SIGNALS */ + + + + + +/**********************/ +/* Function uz_opts() */ +/**********************/ + +int uz_opts(__G__ pargc, pargv) + __GDEF + int *pargc; + char ***pargv; +{ + char **argv, *s; + int argc, c, error=FALSE, negative=0, showhelp=0; + + + argc = *pargc; + argv = *pargv; + + while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) { + s = *argv + 1; + while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */ +#ifdef CMS_MVS + switch (tolower(c)) +#else + switch (c) +#endif + { + case ('-'): + ++negative; + break; +#ifdef RISCOS + case ('/'): + if (negative) { /* negative not allowed with -/ swap */ + Info(slide, 0x401, ((char *)slide, + "error: must give extensions list")); + return(PK_PARAM); /* don't extract here by accident */ + } + exts2swap = s; /* override Unzip$Exts */ + s += strlen(s); + break; +#endif + case ('a'): + if (negative) { + uO.aflag = MAX(uO.aflag-negative,0); + negative = 0; + } else + ++uO.aflag; + break; +#if (defined(DLL) && defined(API_DOC)) + case ('A'): /* extended help for API */ + APIhelp(__G__ argc, argv); + *pargc = -1; /* signal to exit successfully */ + return 0; +#endif + case ('b'): + if (negative) { +#if (defined(TANDEM) || defined(VMS)) + uO.bflag = MAX(uO.bflag-negative,0); +#endif + negative = 0; /* do nothing: "-b" is default */ + } else { +#ifdef VMS + if (uO.aflag == 0) + ++uO.bflag; +#endif +#ifdef TANDEM + ++uO.bflag; +#endif + uO.aflag = 0; + } + break; +#ifdef UNIXBACKUP + case ('B'): /* -B: back up existing files */ + if (negative) + uO.B_flag = FALSE, negative = 0; + else + uO.B_flag = TRUE; + break; +#endif + case ('c'): + if (negative) { + uO.cflag = FALSE, negative = 0; +#ifdef NATIVE + uO.aflag = 0; +#endif + } else { + uO.cflag = TRUE; +#ifdef NATIVE + uO.aflag = 2; /* so you can read it on the screen */ +#endif +#ifdef DLL + if (G.redirect_text) + G.redirect_data = 2; +#endif + } + break; +#ifndef CMS_MVS + case ('C'): /* -C: match filenames case-insensitively */ + if (negative) + uO.C_flag = FALSE, negative = 0; + else + uO.C_flag = TRUE; + break; +#endif /* !CMS_MVS */ +#if (!defined(SFX) || defined(SFX_EXDIR)) + case ('d'): + if (negative) { /* negative not allowed with -d exdir */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(MustGiveExdir))); + return(PK_PARAM); /* don't extract here by accident */ + } + if (uO.exdir != (char *)NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(OnlyOneExdir))); + return(PK_PARAM); /* GRR: stupid restriction? */ + } else { + /* first check for "-dexdir", then for "-d exdir" */ + uO.exdir = s; + if (*uO.exdir == '\0') { + if (argc > 1) { + --argc; + uO.exdir = *++argv; + if (*uO.exdir == '-') { + Info(slide, 0x401, ((char *)slide, + LoadFarString(MustGiveExdir))); + return(PK_PARAM); + } + /* else uO.exdir points at extraction dir */ + } else { + Info(slide, 0x401, ((char *)slide, + LoadFarString(MustGiveExdir))); + return(PK_PARAM); + } + } + /* uO.exdir now points at extraction dir (-dexdir or + * -d exdir); point s at end of exdir to avoid mis- + * interpretation of exdir characters as more options + */ + if (*s != 0) + while (*++s != 0) + ; + } + break; +#endif /* !SFX || SFX_EXDIR */ +#if (!defined(NO_TIMESTAMPS)) + case ('D'): /* -D: Skip restoring dir (or any) timestamp. */ + if (negative) { + uO.D_flag = MAX(uO.D_flag-negative,0); + negative = 0; + } else + uO.D_flag++; + break; +#endif /* (!NO_TIMESTAMPS) */ + case ('e'): /* just ignore -e, -x options (extract) */ + break; +#ifdef MACOS + case ('E'): /* -E [MacOS] display Mac e.f. when restoring */ + if( negative ) { + uO.E_flag = FALSE, negative = 0; + } else { + uO.E_flag = TRUE; + } + break; +#endif /* MACOS */ + case ('f'): /* "freshen" (extract only newer files) */ + if (negative) + uO.fflag = uO.uflag = FALSE, negative = 0; + else + uO.fflag = uO.uflag = TRUE; + break; +#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) + case ('F'): /* Acorn filetype & NFS extension handling */ + if (negative) + uO.acorn_nfs_ext = FALSE, negative = 0; + else + uO.acorn_nfs_ext = TRUE; + break; +#endif /* RISCOS || ACORN_FTYPE_NFS */ + case ('h'): /* just print help message and quit */ + if (showhelp == 0) { +#ifndef SFX + if (*s == 'h') + showhelp = 2; + else +#endif /* !SFX */ + { + showhelp = 1; + } + } + break; +#ifdef MACOS + case ('i'): /* -i [MacOS] ignore filenames stored in Mac ef */ + if( negative ) { + uO.i_flag = FALSE, negative = 0; + } else { + uO.i_flag = TRUE; + } + break; +#endif /* MACOS */ + case ('j'): /* junk pathnames/directory structure */ + if (negative) + uO.jflag = FALSE, negative = 0; + else + uO.jflag = TRUE; + break; +#if (defined(ATH_BEO) || defined(MACOS)) + case ('J'): /* Junk AtheOS, BeOS or MacOS file attributes */ + if( negative ) { + uO.J_flag = FALSE, negative = 0; + } else { + uO.J_flag = TRUE; + } + break; +#endif /* ATH_BEO || MACOS */ +#ifdef ATH_BEO_UNX + case ('K'): + if (negative) { + uO.K_flag = FALSE, negative = 0; + } else { + uO.K_flag = TRUE; + } + break; +#endif /* ATH_BEO_UNX */ +#ifndef SFX + case ('l'): + if (negative) { + uO.vflag = MAX(uO.vflag-negative,0); + negative = 0; + } else + ++uO.vflag; + break; +#endif /* !SFX */ +#ifndef CMS_MVS + case ('L'): /* convert (some) filenames to lowercase */ + if (negative) { + uO.L_flag = MAX(uO.L_flag-negative,0); + negative = 0; + } else + ++uO.L_flag; + break; +#endif /* !CMS_MVS */ +#ifdef MORE +#ifdef CMS_MVS + case ('m'): +#endif + case ('M'): /* send all screen output through "more" fn. */ +/* GRR: eventually check for numerical argument => height */ + if (negative) + G.M_flag = FALSE, negative = 0; + else + G.M_flag = TRUE; + break; +#endif /* MORE */ + case ('n'): /* don't overwrite any files */ + if (negative) + uO.overwrite_none = FALSE, negative = 0; + else + uO.overwrite_none = TRUE; + break; +#ifdef AMIGA + case ('N'): /* restore comments as filenotes */ + if (negative) + uO.N_flag = FALSE, negative = 0; + else + uO.N_flag = TRUE; + break; +#endif /* AMIGA */ + case ('o'): /* OK to overwrite files without prompting */ + if (negative) { + uO.overwrite_all = MAX(uO.overwrite_all-negative,0); + negative = 0; + } else + ++uO.overwrite_all; + break; + case ('p'): /* pipes: extract to stdout, no messages */ + if (negative) { + uO.cflag = FALSE; + uO.qflag = MAX(uO.qflag-999,0); + negative = 0; + } else { + uO.cflag = TRUE; + uO.qflag += 999; + } + break; +#if CRYPT + /* GRR: yes, this is highly insecure, but dozens of people + * have pestered us for this, so here we go... */ + case ('P'): + if (negative) { /* negative not allowed with -P passwd */ + Info(slide, 0x401, ((char *)slide, + LoadFarString(MustGivePasswd))); + return(PK_PARAM); /* don't extract here by accident */ + } + if (uO.pwdarg != (char *)NULL) { +/* + GRR: eventually support multiple passwords? + Info(slide, 0x401, ((char *)slide, + LoadFarString(OnlyOnePasswd))); + return(PK_PARAM); + */ + } else { + /* first check for "-Ppasswd", then for "-P passwd" */ + uO.pwdarg = s; + if (*uO.pwdarg == '\0') { + if (argc > 1) { + --argc; + uO.pwdarg = *++argv; + if (*uO.pwdarg == '-') { + Info(slide, 0x401, ((char *)slide, + LoadFarString(MustGivePasswd))); + return(PK_PARAM); + } + /* else pwdarg points at decryption password */ + } else { + Info(slide, 0x401, ((char *)slide, + LoadFarString(MustGivePasswd))); + return(PK_PARAM); + } + } + /* pwdarg now points at decryption password (-Ppasswd or + * -P passwd); point s at end of passwd to avoid mis- + * interpretation of passwd characters as more options + */ + if (*s != 0) + while (*++s != 0) + ; + } + break; +#endif /* CRYPT */ + case ('q'): /* quiet: fewer comments/messages */ + if (negative) { + uO.qflag = MAX(uO.qflag-negative,0); + negative = 0; + } else + ++uO.qflag; + break; +#ifdef QDOS + case ('Q'): /* QDOS flags */ + qlflag ^= strtol(s, &s, 10); + break; /* we XOR this as we can config qlflags */ +#endif +#ifdef TANDEM + case ('r'): /* remove file extensions */ + if (negative) + uO.rflag = FALSE, negative = 0; + else + uO.rflag = TRUE; + break; +#endif /* TANDEM */ +#ifdef DOS_FLX_NLM_OS2_W32 + case ('s'): /* spaces in filenames: allow by default */ + if (negative) + uO.sflag = FALSE, negative = 0; + else + uO.sflag = TRUE; + break; +#endif /* DOS_FLX_NLM_OS2_W32 */ +#ifdef VMS + /* VMS: extract "text" files in Stream_LF format (-a[a]) */ + case ('S'): + if (negative) + uO.S_flag = FALSE, negative = 0; + else + uO.S_flag = TRUE; + break; +#endif /* VMS */ + case ('t'): + if (negative) + uO.tflag = FALSE, negative = 0; + else + uO.tflag = TRUE; + break; +#ifdef TIMESTAMP + case ('T'): + if (negative) + uO.T_flag = FALSE, negative = 0; + else + uO.T_flag = TRUE; + break; +#endif + case ('u'): /* update (extract only new and newer files) */ + if (negative) + uO.uflag = FALSE, negative = 0; + else + uO.uflag = TRUE; + break; +#ifdef UNICODE_SUPPORT + case ('U'): /* escape UTF-8, or disable UTF-8 support */ + if (negative) { + uO.U_flag = MAX(uO.U_flag-negative,0); + negative = 0; + } else + uO.U_flag++; + break; +#else /* !UNICODE_SUPPORT */ +#ifndef CMS_MVS + case ('U'): /* obsolete; to be removed in version 6.0 */ + if (negative) + uO.L_flag = TRUE, negative = 0; + else + uO.L_flag = FALSE; + break; +#endif /* !CMS_MVS */ +#endif /* ?UNICODE_SUPPORT */ +#ifndef SFX + case ('v'): /* verbose */ + if (negative) { + uO.vflag = MAX(uO.vflag-negative,0); + negative = 0; + } else if (uO.vflag) + ++uO.vflag; + else + uO.vflag = 2; + break; +#endif /* !SFX */ +#ifndef CMS_MVS + case ('V'): /* Version (retain VMS/DEC-20 file versions) */ + if (negative) + uO.V_flag = FALSE, negative = 0; + else + uO.V_flag = TRUE; + break; +#endif /* !CMS_MVS */ +#ifdef WILD_STOP_AT_DIR + case ('W'): /* Wildcard interpretation (stop at '/'?) */ + if (negative) + uO.W_flag = FALSE, negative = 0; + else + uO.W_flag = TRUE; + break; +#endif /* WILD_STOP_AT_DIR */ + case ('x'): /* extract: default */ +#ifdef SFX + /* when 'x' is the only option in this argument, and the + * next arg is not an option, assume this initiates an + * exclusion list (-x xlist): terminate option-scanning + * and leave uz_opts with argv still pointing to "-x"; + * the xlist is processed later + */ + if (s - argv[0] == 2 && *s == '\0' && + argc > 1 && argv[1][0] != '-') { + /* break out of nested loops without "++argv;--argc" */ + goto opts_done; + } +#endif /* SFX */ + break; +#if (defined(RESTORE_UIDGID) || defined(RESTORE_ACL)) + case ('X'): /* restore owner/protection info (need privs?) */ + if (negative) { + uO.X_flag = MAX(uO.X_flag-negative,0); + negative = 0; + } else + ++uO.X_flag; + break; +#endif /* RESTORE_UIDGID || RESTORE_ACL */ +#ifdef VMS + case ('Y'): /* Treat ".nnn" as ";nnn" version. */ + if (negative) + uO.Y_flag = FALSE, negative = 0; + else + uO.Y_flag = TRUE; + break; +#endif /* VMS */ + case ('z'): /* display only the archive comment */ + if (negative) { + uO.zflag = MAX(uO.zflag-negative,0); + negative = 0; + } else + ++uO.zflag; + break; +#ifndef SFX + case ('Z'): /* should have been first option (ZipInfo) */ + Info(slide, 0x401, ((char *)slide, LoadFarString(Zfirst))); + error = TRUE; + break; +#endif /* !SFX */ +#ifdef VMS + case ('2'): /* Force ODS2-compliant names. */ + if (negative) + uO.ods2_flag = FALSE, negative = 0; + else + uO.ods2_flag = TRUE; + break; +#endif /* VMS */ +#ifdef DOS_H68_OS2_W32 + case ('$'): + if (negative) { + uO.volflag = MAX(uO.volflag-negative,0); + negative = 0; + } else + ++uO.volflag; + break; +#endif /* DOS_H68_OS2_W32 */ +#if (!defined(RISCOS) && !defined(CMS_MVS) && !defined(TANDEM)) + case (':'): /* allow "parent dir" path components */ + if (negative) { + uO.ddotflag = MAX(uO.ddotflag-negative,0); + negative = 0; + } else + ++uO.ddotflag; + break; +#endif /* !RISCOS && !CMS_MVS && !TANDEM */ +#ifdef UNIX + case ('^'): /* allow control chars in filenames */ + if (negative) { + uO.cflxflag = MAX(uO.cflxflag-negative,0); + negative = 0; + } else + ++uO.cflxflag; + break; +#endif /* UNIX */ + default: + error = TRUE; + break; + + } /* end switch */ + } /* end while (not end of argument string) */ + } /* end while (not done with switches) */ + +/*--------------------------------------------------------------------------- + Check for nonsensical combinations of options. + ---------------------------------------------------------------------------*/ + +#ifdef SFX +opts_done: /* yes, very ugly...but only used by UnZipSFX with -x xlist */ +#endif + + if (showhelp > 0) { /* just print help message and quit */ + *pargc = -1; +#ifndef SFX + if (showhelp == 2) { + help_extended(__G); + return PK_OK; + } else +#endif /* !SFX */ + { + return USAGE(PK_OK); + } + } + + if ((uO.cflag && (uO.tflag || uO.uflag)) || + (uO.tflag && uO.uflag) || (uO.fflag && uO.overwrite_none)) + { + Info(slide, 0x401, ((char *)slide, LoadFarString(InvalidOptionsMsg))); + error = TRUE; + } + if (uO.aflag > 2) + uO.aflag = 2; +#ifdef VMS + if (uO.bflag > 2) + uO.bflag = 2; + /* Clear -s flag when converting text files. */ + if (uO.aflag <= 0) + uO.S_flag = 0; +#endif /* VMS */ + if (uO.overwrite_all && uO.overwrite_none) { + Info(slide, 0x401, ((char *)slide, LoadFarString(IgnoreOOptionMsg))); + uO.overwrite_all = FALSE; + } +#ifdef MORE + if (G.M_flag && !isatty(1)) /* stdout redirected: "more" func. useless */ + G.M_flag = 0; +#endif + +#ifdef SFX + if (error) +#else + if ((argc-- == 0) || error) +#endif + { + *pargc = argc; + *pargv = argv; +#ifndef SFX + if (uO.vflag >= 2 && argc == -1) { /* "unzip -v" */ + show_version_info(__G); + return PK_OK; + } + if (!G.noargs && !error) + error = TRUE; /* had options (not -h or -v) but no zipfile */ +#endif /* !SFX */ + return USAGE(error); + } + +#ifdef SFX + /* print our banner unless we're being fairly quiet */ + if (uO.qflag < 2) + Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner), + UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL, + LoadFarStringSmall(VersionDate))); +#ifdef BETA + /* always print the beta warning: no unauthorized distribution!! */ + Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(BetaVersion), "\n", + "SFX")); +#endif +#endif /* SFX */ + + if (uO.cflag || uO.tflag || uO.vflag || uO.zflag +#ifdef TIMESTAMP + || uO.T_flag +#endif + ) + G.extract_flag = FALSE; + else + G.extract_flag = TRUE; + + *pargc = argc; + *pargv = argv; + return PK_OK; + +} /* end function uz_opts() */ + + + + +/********************/ +/* Function usage() */ +/********************/ + +#ifdef SFX +# ifdef VMS +# define LOCAL "X.\n\ +(Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)" +# endif +# ifdef UNIX +# define LOCAL "X" +# endif +# ifdef DOS_OS2_W32 +# define LOCAL "s$" +# endif +# if (defined(FLEXOS) || defined(NLM)) +# define LOCAL "s" +# endif +# ifdef AMIGA +# define LOCAL "N" +# endif + /* Default for all other systems: */ +# ifndef LOCAL +# define LOCAL "" +# endif + +# ifndef NO_TIMESTAMP +# ifdef MORE +# define SFXOPT1 "DM" +# else +# define SFXOPT1 "D" +# endif +# else +# ifdef MORE +# define SFXOPT1 "M" +# else +# define SFXOPT1 "" +# endif +# endif + +int usage(__G__ error) /* return PK-type error code */ + __GDEF + int error; +{ + Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner), + UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL, + LoadFarStringSmall(VersionDate))); + Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXOpts), + SFXOPT1, LOCAL)); +#ifdef BETA + Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(BetaVersion), "\n", + "SFX")); +#endif + + if (error) + return PK_PARAM; + else + return PK_COOL; /* just wanted usage screen: no error */ + +} /* end function usage() */ + + + + + +#else /* !SFX */ +# ifdef VMS +# define QUOT '\"' +# define QUOTS "\"" +# else +# define QUOT ' ' +# define QUOTS "" +# endif + +int usage(__G__ error) /* return PK-type error code */ + __GDEF + int error; +{ + int flag = (error? 1 : 0); + + +/*--------------------------------------------------------------------------- + Print either ZipInfo usage or UnZip usage, depending on incantation. + (Strings must be no longer than 512 bytes for Turbo C, apparently.) + ---------------------------------------------------------------------------*/ + + if (uO.zipinfo_mode) { + +#ifndef NO_ZIPINFO + + Info(slide, flag, ((char *)slide, LoadFarString(ZipInfoUsageLine1), + ZI_MAJORVER, ZI_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL, + LoadFarStringSmall(VersionDate), + LoadFarStringSmall2(ZipInfoExample), QUOTS,QUOTS)); + Info(slide, flag, ((char *)slide, LoadFarString(ZipInfoUsageLine2))); + Info(slide, flag, ((char *)slide, LoadFarString(ZipInfoUsageLine3), + LoadFarStringSmall(ZipInfoUsageLine4))); +#ifdef VMS + Info(slide, flag, ((char *)slide, "\n\ +You must quote non-lowercase options and filespecs, unless SET PROC/PARSE=EXT.\ +\n")); +#endif + +#endif /* !NO_ZIPINFO */ + + } else { /* UnZip mode */ + + Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine1), + UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL, + LoadFarStringSmall(VersionDate))); +#ifdef BETA + Info(slide, flag, ((char *)slide, LoadFarString(BetaVersion), "", "")); +#endif + + Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine2), + ZIPINFO_MODE_OPTION, LoadFarStringSmall(ZipInfoMode))); +#ifdef VMS + if (!error) /* maybe no command-line tail found; show extra help */ + Info(slide, flag, ((char *)slide, LoadFarString(VMSusageLine2b))); +#endif + + Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine3), + LoadFarStringSmall(local1))); + + Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine4), + LoadFarStringSmall(local2), LoadFarStringSmall2(local3))); + + /* This is extra work for SMALL_MEM, but it will work since + * LoadFarStringSmall2 uses the same buffer. Remember, this + * is a hack. */ + Info(slide, flag, ((char *)slide, LoadFarString(UnzipUsageLine5), + LoadFarStringSmall(Example2), LoadFarStringSmall2(Example3), + LoadFarStringSmall2(Example3))); + + } /* end if (uO.zipinfo_mode) */ + + if (error) + return PK_PARAM; + else + return PK_COOL; /* just wanted usage screen: no error */ + +} /* end function usage() */ + +#endif /* ?SFX */ + + + + +#ifndef SFX + +/* Print extended help to stdout. */ +static void help_extended(__G) + __GDEF +{ + extent i; /* counter for help array */ + + /* help array */ + static ZCONST char *text[] = { + "", + "Extended Help for UnZip", + "", + "See the UnZip Manual for more detailed help", + "", + "", + "UnZip lists and extracts files in zip archives. The default action is to", + "extract zipfile entries to the current directory, creating directories as", + "needed. With appropriate options, UnZip lists the contents of archives", + "instead.", + "", + "Basic unzip command line:", + " unzip [-Z] options archive[.zip] [file ...] [-x xfile ...] [-d exdir]", + "", + "Some examples:", + " unzip -l foo.zip - list files in short format in archive foo.zip", + "", + " unzip -t foo - test the files in archive foo", + "", + " unzip -Z foo - list files using more detailed zipinfo format", + "", + " unzip foo - unzip the contents of foo in current dir", + "", + " unzip -a foo - unzip foo and convert text files to local OS", + "", + "If unzip is run in zipinfo mode, a more detailed list of archive contents", + "is provided. The -Z option sets zipinfo mode and changes the available", + "options.", + "", + "Basic zipinfo command line:", + " zipinfo options archive[.zip] [file ...] [-x xfile ...]", + " unzip -Z options archive[.zip] [file ...] [-x xfile ...]", + "", + "Below, Mac OS refers to Mac OS before Mac OS X. Mac OS X is a Unix based", + "port and is referred to as Unix Apple.", + "", + "", + "unzip options:", + " -Z Switch to zipinfo mode. Must be first option.", + " -hh Display extended help.", + " -A [OS/2, Unix DLL] Print extended help for DLL.", + " -c Extract files to stdout/screen. As -p but include names. Also,", + " -a allowed and EBCDIC conversions done if needed.", + " -f Freshen by extracting only if older file on disk.", + " -l List files using short form.", + " -p Extract files to pipe (stdout). Only file data is output and all", + " files extracted in binary mode (as stored).", + " -t Test archive files.", + " -T Set timestamp on archive(s) to that of newest file. Similar to", + " zip -o but faster.", + " -u Update existing older files on disk as -f and extract new files.", + " -v Use verbose list format. If given alone as unzip -v show version", + " information. Also can be added to other list commands for more", + " verbose output.", + " -z Display only archive comment.", + "", + "unzip modifiers:", + " -a Convert text files to local OS format. Convert line ends, EOF", + " marker, and from or to EBCDIC character set as needed.", + " -b Treat all files as binary. [Tandem] Force filecode 180 ('C').", + " [VMS] Autoconvert binary files. -bb forces convert of all files.", + " -B [UNIXBACKUP compile option enabled] Save a backup copy of each", + " overwritten file in foo~ or foo~99999 format.", + " -C Use case-insensitive matching.", + " -D Skip restoration of timestamps for extracted directories. On VMS this", + " is on by default and -D essentially becames -DD.", + " -DD Skip restoration of timestamps for all entries.", + " -E [MacOS (not Unix Apple)] Display contents of MacOS extra field during", + " restore.", + " -F [Acorn] Suppress removal of NFS filetype extension. [Non-Acorn if", + " ACORN_FTYPE_NFS] Translate filetype and append to name.", + " -i [MacOS] Ignore filenames in MacOS extra field. Instead, use name in", + " standard header.", + " -j Junk paths and deposit all files in extraction directory.", + " -J [BeOS] Junk file attributes. [MacOS] Ignore MacOS specific info.", + " -K [AtheOS, BeOS, Unix] Restore SUID/SGID/Tacky file attributes.", + " -L Convert to lowercase any names from uppercase only file system.", + " -LL Convert all files to lowercase.", + " -M Pipe all output through internal pager similar to Unix more(1).", + " -n Never overwrite existing files. Skip extracting that file, no prompt.", + " -N [Amiga] Extract file comments as Amiga filenotes.", + " -o Overwrite existing files without prompting. Useful with -f. Use with", + " care.", + " -P p Use password p to decrypt files. THIS IS INSECURE! Some OS show", + " command line to other users.", + " -q Perform operations quietly. The more q (as in -qq) the quieter.", + " -s [OS/2, NT, MS-DOS] Convert spaces in filenames to underscores.", + " -S [VMS] Convert text files (-a, -aa) into Stream_LF format.", + " -U [UNICODE enabled] Show non-local characters as #Uxxxx or #Lxxxxxx ASCII", + " text escapes where x is hex digit. [Old] -U used to leave names", + " uppercase if created on MS-DOS, VMS, etc. See -L.", + " -UU [UNICODE enabled] Disable use of stored UTF-8 paths. Note that UTF-8", + " paths stored as native local paths are still processed as Unicode.", + " -V Retain VMS file version numbers.", + " -W [Only if WILD_STOP_AT_DIR] Modify pattern matching so ? and * do not", + " match directory separator /, but ** does. Allows matching at specific", + " directory levels.", + " -X [VMS, Unix, OS/2, NT, Tandem] Restore UICs and ACL entries under VMS,", + " or UIDs/GIDs under Unix, or ACLs under certain network-enabled", + " versions of OS/2, or security ACLs under Windows NT. Can require", + " user privileges.", + " -XX [NT] Extract NT security ACLs after trying to enable additional", + " system privileges.", + " -Y [VMS] Treat archived name endings of .nnn as VMS version numbers.", + " -$ [MS-DOS, OS/2, NT] Restore volume label if extraction medium is", + " removable. -$$ allows fixed media (hard drives) to be labeled.", + " -/ e [Acorn] Use e as extension list.", + " -: [All but Acorn, VM/CMS, MVS, Tandem] Allow extract archive members into", + " locations outside of current extraction root folder. This allows", + " paths such as ../foo to be extracted above the current extraction", + " directory, which can be a security problem.", + " -^ [Unix] Allow control characters in names of extracted entries. Usually", + " this is not a good thing and should be avoided.", + " -2 [VMS] Force unconditional conversion of names to ODS-compatible names.", + " Default is to exploit destination file system, preserving cases and", + " extended name characters on ODS5 and applying ODS2 filtering on ODS2.", + "", + "", + "Wildcards:", + " Internally unzip supports the following wildcards:", + " ? (or %% or #, depending on OS) matches any single character", + " * matches any number of characters, including zero", + " [list] matches char in list (regex), can do range [ac-f], all but [!bf]", + " If port supports [], must escape [ as [[]", + " For shells that expand wildcards, escape (\\* or \"*\") so unzip can recurse.", + "", + "Include and Exclude:", + " -i pattern pattern ... include files that match a pattern", + " -x pattern pattern ... exclude files that match a pattern", + " Patterns are paths with optional wildcards and match paths as stored in", + " archive. Exclude and include lists end at next option or end of line.", + " unzip archive -x pattern pattern ...", + "", + "Multi-part (split) archives (archives created as a set of split files):", + " Currently split archives are not readable by unzip. A workaround is", + " to use zip to convert the split archive to a single-file archive and", + " use unzip on that. See the manual page for Zip 3.0 or later.", + "", + "Streaming (piping into unzip):", + " Currently unzip does not support streaming. The funzip utility can be", + " used to process the first entry in a stream.", + " cat archive | funzip", + "", + "Testing archives:", + " -t test contents of archive", + " This can be modified using -q for quieter operation, and -qq for even", + " quieter operation.", + "", + "Unicode:", + " If compiled with Unicode support, unzip automatically handles archives", + " with Unicode entries. Currently Unicode on Win32 systems is limited.", + " Characters not in the current character set are shown as ASCII escapes", + " in the form #Uxxxx where the Unicode character number fits in 16 bits,", + " or #Lxxxxxx where it doesn't, where x is the ASCII character for a hex", + " digit.", + "", + "", + "zipinfo options (these are used in zipinfo mode (unzip -Z ...)):", + " -1 List names only, one per line. No headers/trailers. Good for scripts.", + " -2 List names only as -1, but include headers, trailers, and comments.", + " -s List archive entries in short Unix ls -l format. Default list format.", + " -m List in long Unix ls -l format. As -s, but includes compression %.", + " -l List in long Unix ls -l format. As -m, but compression in bytes.", + " -v List zipfile information in verbose, multi-page format.", + " -h List header line. Includes archive name, actual size, total files.", + " -M Pipe all output through internal pager similar to Unix more(1) command.", + " -t List totals for files listed or for all files. Includes uncompressed", + " and compressed sizes, and compression factors.", + " -T Print file dates and times in a sortable decimal format (yymmdd.hhmmss)", + " Default date and time format is a more human-readable version.", + " -U [UNICODE] If entry has a UTF-8 Unicode path, display any characters", + " not in current character set as text #Uxxxx and #Lxxxxxx escapes", + " representing the Unicode character number of the character in hex.", + " -UU [UNICODE] Disable use of any UTF-8 path information.", + " -z Include archive comment if any in listing.", + "", + "", + "funzip stream extractor:", + " funzip extracts the first member in an archive to stdout. Typically", + " used to unzip the first member of a stream or pipe. If a file argument", + " is given, read from that file instead of stdin.", + "", + "funzip command line:", + " funzip [-password] [input[.zip|.gz]]", + "", + "", + "unzipsfx self extractor:", + " Self-extracting archives made with unzipsfx are no more (or less)", + " portable across different operating systems than unzip executables.", + " In general, a self-extracting archive made on a particular Unix system,", + " for example, will only self-extract under the same flavor of Unix.", + " Regular unzip may still be used to extract embedded archive however.", + "", + "unzipsfx command line:", + " [-options] [file(s) ... [-x xfile(s) ...]]", + "", + "unzipsfx options:", + " -c, -p - Output to pipe. (See above for unzip.)", + " -f, -u - Freshen and Update, as for unzip.", + " -t - Test embedded archive. (Can be used to list contents.)", + " -z - Print archive comment. (See unzip above.)", + "", + "unzipsfx modifiers:", + " Most unzip modifiers are supported. These include", + " -a - Convert text files.", + " -n - Never overwrite.", + " -o - Overwrite without prompting.", + " -q - Quiet operation.", + " -C - Match names case-insensitively.", + " -j - Junk paths.", + " -V - Keep version numbers.", + " -s - Convert spaces to underscores.", + " -$ - Restore volume label.", + "", + "If unzipsfx compiled with SFX_EXDIR defined, -d option also available:", + " -d exd - Extract to directory exd.", + "By default, all files extracted to current directory. This option", + "forces extraction to specified directory.", + "", + "See unzipsfx manual page for more information.", + "" + }; + + for (i = 0; i < sizeof(text)/sizeof(char *); i++) + { + Info(slide, 0, ((char *)slide, "%s\n", text[i])); + } +} /* end function help_extended() */ + + + + +#ifndef _WIN32_WCE /* Win CE does not support environment variables */ +#if (!defined(MODERN) || defined(NO_STDLIB_H)) +/* Declare getenv() to be sure (might be missing in some environments) */ +extern char *getenv(); +#endif +#endif + +/********************************/ +/* Function show_version_info() */ +/********************************/ + +static void show_version_info(__G) + __GDEF +{ + if (uO.qflag > 3) /* "unzip -vqqqq" */ + Info(slide, 0, ((char *)slide, "%d\n", + (UZ_MAJORVER*100 + UZ_MINORVER*10 + UZ_PATCHLEVEL))); + else { +#ifndef _WIN32_WCE /* Win CE does not support environment variables */ + char *envptr; +#endif + int numopts = 0; + + Info(slide, 0, ((char *)slide, LoadFarString(UnzipUsageLine1v), + UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL, + LoadFarStringSmall(VersionDate))); + Info(slide, 0, ((char *)slide, + LoadFarString(UnzipUsageLine2v))); + version(__G); + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptions))); +#ifdef ACORN_FTYPE_NFS + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(AcornFtypeNFS))); + ++numopts; +#endif +#ifdef ASM_CRC + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(AsmCRC))); + ++numopts; +#endif +#ifdef ASM_INFLATECODES + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(AsmInflateCodes))); + ++numopts; +#endif +#ifdef CHECK_VERSIONS + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Check_Versions))); + ++numopts; +#endif +#ifdef COPYRIGHT_CLEAN + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Copyright_Clean))); + ++numopts; +#endif +#ifdef DEBUG + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(UDebug))); + ++numopts; +#endif +#ifdef DEBUG_TIME + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(DebugTime))); + ++numopts; +#endif +#ifdef DLL + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Dll))); + ++numopts; +#endif +#ifdef DOSWILD + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(DosWild))); + ++numopts; +#endif +#ifdef LZW_CLEAN + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(LZW_Clean))); + ++numopts; +#endif +#ifndef MORE + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(No_More))); + ++numopts; +#endif +#ifdef NO_ZIPINFO + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(No_ZipInfo))); + ++numopts; +#endif +#ifdef NTSD_EAS + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(NTSDExtAttrib))); + ++numopts; +#endif +#if defined(WIN32) && defined(NO_W32TIMES_IZFIX) + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(W32NoIZTimeFix))); + ++numopts; +#endif +#ifdef OLD_THEOS_EXTRA + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(OldTheosExtra))); + ++numopts; +#endif +#ifdef OS2_EAS + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(OS2ExtAttrib))); + ++numopts; +#endif +#ifdef QLZIP + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(SMSExFldOnUnix))); + ++numopts; +#endif +#ifdef REENTRANT + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Reentrant))); + ++numopts; +#endif +#ifdef REGARGS + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(RegArgs))); + ++numopts; +#endif +#ifdef RETURN_CODES + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Return_Codes))); + ++numopts; +#endif +#ifdef SET_DIR_ATTRIB + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(SetDirAttrib))); + ++numopts; +#endif +#ifdef SYMLINKS + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(SymLinkSupport))); + ++numopts; +#endif +#ifdef TIMESTAMP + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(TimeStamp))); + ++numopts; +#endif +#ifdef UNIXBACKUP + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(UnixBackup))); + ++numopts; +#endif +#ifdef USE_EF_UT_TIME + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_EF_UT_time))); + ++numopts; +#endif +#ifndef COPYRIGHT_CLEAN + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_Smith_Code))); + ++numopts; +#endif +#ifndef LZW_CLEAN + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_Unshrink))); + ++numopts; +#endif +#ifdef USE_DEFLATE64 + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_Deflate64))); + ++numopts; +#endif +#ifdef UNICODE_SUPPORT +# ifdef UTF8_MAYBE_NATIVE + sprintf((char *)(slide+256), LoadFarStringSmall(Use_Unicode), + LoadFarStringSmall2(G.native_is_utf8 ? SysChUTF8 : SysChOther)); + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + (char *)(slide+256))); +# else + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_Unicode))); +# endif + ++numopts; +#endif +#ifdef _MBCS + sprintf((char *)(slide+256), LoadFarStringSmall(Have_MBCS_Support), + (unsigned int)MB_CUR_MAX); + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + (char *)(slide+256))); + ++numopts; +#endif +#ifdef MULT_VOLUME + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_MultiVol))); + ++numopts; +#endif +#ifdef LARGE_FILE_SUPPORT + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_LFS))); + ++numopts; +#endif +#ifdef ZIP64_SUPPORT + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_Zip64))); + ++numopts; +#endif +#if (defined(__DJGPP__) && (__DJGPP__ >= 2)) +# ifdef USE_DJGPP_ENV + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_DJGPP_Env))); + ++numopts; +# endif +# ifdef USE_DJGPP_GLOB + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_DJGPP_Glob))); + ++numopts; +# endif +#endif /* __DJGPP__ && (__DJGPP__ >= 2) */ +#ifdef USE_VFAT + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(Use_VFAT_support))); + ++numopts; +#endif +#ifdef USE_ZLIB + sprintf((char *)(slide+256), LoadFarStringSmall(UseZlib), + ZLIB_VERSION, zlibVersion()); + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + (char *)(slide+256))); + ++numopts; +#endif +#ifdef USE_BZIP2 + sprintf((char *)(slide+256), LoadFarStringSmall(UseBZip2), + BZ2_bzlibVersion()); + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + (char *)(slide+256))); + ++numopts; +#endif +#ifdef VMS_TEXT_CONV + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(VmsTextConv))); + ++numopts; +#endif +#ifdef VMSCLI + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(VmsCLI))); + ++numopts; +#endif +#ifdef VMSWILD + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(VmsWild))); + ++numopts; +#endif +#ifdef WILD_STOP_AT_DIR + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(WildStopAtDir))); + ++numopts; +#endif +#if CRYPT +# ifdef PASSWD_FROM_STDIN + Info(slide, 0, ((char *)slide, LoadFarString(CompileOptFormat), + LoadFarStringSmall(PasswdStdin))); +# endif + Info(slide, 0, ((char *)slide, LoadFarString(Decryption), + CR_MAJORVER, CR_MINORVER, CR_BETA_VER, + LoadFarStringSmall(CryptDate))); + ++numopts; +#endif /* CRYPT */ + if (numopts == 0) + Info(slide, 0, ((char *)slide, + LoadFarString(CompileOptFormat), + LoadFarStringSmall(None))); + +#ifndef _WIN32_WCE /* Win CE does not support environment variables */ + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptions))); + envptr = getenv(LoadFarStringSmall(EnvUnZip)); + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat), + LoadFarStringSmall(EnvUnZip), + (envptr == (char *)NULL || *envptr == 0)? + LoadFarStringSmall2(None) : envptr)); + envptr = getenv(LoadFarStringSmall(EnvUnZip2)); + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat), + LoadFarStringSmall(EnvUnZip2), + (envptr == (char *)NULL || *envptr == 0)? + LoadFarStringSmall2(None) : envptr)); + envptr = getenv(LoadFarStringSmall(EnvZipInfo)); + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat), + LoadFarStringSmall(EnvZipInfo), + (envptr == (char *)NULL || *envptr == 0)? + LoadFarStringSmall2(None) : envptr)); + envptr = getenv(LoadFarStringSmall(EnvZipInfo2)); + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat), + LoadFarStringSmall(EnvZipInfo2), + (envptr == (char *)NULL || *envptr == 0)? + LoadFarStringSmall2(None) : envptr)); +#ifndef __RSXNT__ +#ifdef __EMX__ + envptr = getenv(LoadFarStringSmall(EnvEMX)); + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat), + LoadFarStringSmall(EnvEMX), + (envptr == (char *)NULL || *envptr == 0)? + LoadFarStringSmall2(None) : envptr)); + envptr = getenv(LoadFarStringSmall(EnvEMXOPT)); + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat), + LoadFarStringSmall(EnvEMXOPT), + (envptr == (char *)NULL || *envptr == 0)? + LoadFarStringSmall2(None) : envptr)); +#endif /* __EMX__ */ +#if (defined(__GO32__) && (!defined(__DJGPP__) || (__DJGPP__ < 2))) + envptr = getenv(LoadFarStringSmall(EnvGO32)); + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat), + LoadFarStringSmall(EnvGO32), + (envptr == (char *)NULL || *envptr == 0)? + LoadFarStringSmall2(None) : envptr)); + envptr = getenv(LoadFarStringSmall(EnvGO32TMP)); + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat), + LoadFarStringSmall(EnvGO32TMP), + (envptr == (char *)NULL || *envptr == 0)? + LoadFarStringSmall2(None) : envptr)); +#endif /* __GO32__ && !(__DJGPP__ >= 2) */ +#endif /* !__RSXNT__ */ +#ifdef RISCOS + envptr = getenv(LoadFarStringSmall(EnvUnZipExts)); + Info(slide, 0, ((char *)slide, LoadFarString(EnvOptFormat), + LoadFarStringSmall(EnvUnZipExts), + (envptr == (char *)NULL || *envptr == 0)? + LoadFarStringSmall2(None) : envptr)); +#endif /* RISCOS */ +#endif /* !_WIN32_WCE */ + } +} /* end function show_version() */ + +#endif /* !SFX */ +#endif /* !WINDLL */ diff -Naur a/unzpriv.h b/unzpriv.h --- a/unzpriv.h 2009-04-20 00:59:26.000000000 +0100 +++ b/unzpriv.h 2019-12-02 01:05:52.857702371 +0000 @@ -1211,6 +1211,7 @@ # ifdef UNICODE_WCHAR # if !(defined(_WIN32_WCE) || defined(POCKET_UNZIP)) # include +# include # endif # endif # ifndef _MBCS /* no need to include twice, see below */ @@ -1806,6 +1807,8 @@ #define EB_NTSD_VERSION 4 /* offset of NTSD version byte */ #define EB_NTSD_MAX_VER (0) /* maximum version # we know how to handle */ +#define EB_PKVMS_MINLEN 4 /* minimum data length of PKVMS extra block */ + #define EB_ASI_CRC32 0 /* offset of ASI Unix field's crc32 checksum */ #define EB_ASI_MODE 4 /* offset of ASI Unix permission mode field */ @@ -2393,6 +2396,12 @@ char *fnfilter OF((ZCONST char *raw, uch *space, extent size)); +# if defined( UNICODE_SUPPORT) && defined( _MBCS) +wchar_t *fnfilterw OF((ZCONST wchar_t *src, wchar_t *dst, + extent siz)); +#endif + + /*--------------------------------------------------------------------------- Decompression functions: ---------------------------------------------------------------------------*/ @@ -2604,7 +2613,7 @@ int SetFileSize OF((FILE *file, zusz_t filesize)); /* local */ #endif #ifndef MTS /* macro in MTS */ - void close_outfile OF((__GPRO)); /* local */ + int close_outfile OF((__GPRO)); /* local */ #endif #ifdef SET_SYMLINK_ATTRIBS int set_symlnk_attribs OF((__GPRO__ slinkentry *slnk_entry)); /* local */ @@ -3008,7 +3017,7 @@ !(((islochdr) || (isuxatt)) && \ ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \ (hostnum) == FS_HPFS_ || \ - ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \ + ((hostnum) == FS_NTFS_ /* && (hostver) == 50 */ )) { \ _OEM_INTERN((string)); \ } else { \ _ISO_INTERN((string)); \ diff -Naur a/unzpriv.h.orig b/unzpriv.h.orig --- a/unzpriv.h.orig 1970-01-01 01:00:00.000000000 +0100 +++ b/unzpriv.h.orig 2019-12-02 01:04:10.077348607 +0000 @@ -0,0 +1,3125 @@ +/* + Copyright (c) 1990-2009 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2009-Jan-02 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 +*/ +/*--------------------------------------------------------------------------- + + unzpriv.h + + This header file contains private (internal) macros, typedefs, prototypes + and global-variable declarations used by all of the UnZip source files. + In a prior life it was part of the main unzip.h header, but now it is only + included by that header if UNZIP_INTERNAL is defined. + + ---------------------------------------------------------------------------*/ + + + +#ifndef __unzpriv_h /* prevent multiple inclusions */ +#define __unzpriv_h + +/* First thing: Signal all following code that we compile UnZip utilities! */ +#ifndef UNZIP +# define UNZIP +#endif + +/* GRR 960204: MORE defined here in preparation for removal altogether */ +#ifndef MORE +# ifndef RISCOS +# define MORE +# endif +#endif + +/* fUnZip should never need to be reentrant */ +#ifdef FUNZIP +# ifdef REENTRANT +# undef REENTRANT +# endif +# ifdef DLL +# undef DLL +# endif +# ifdef SFX /* fUnZip is NOT the sfx stub! */ +# undef SFX +# endif +# ifdef USE_BZIP2 /* fUnZip does not support bzip2 decompression */ +# undef USE_BZIP2 +# endif +#endif + +#if (defined(USE_ZLIB) && !defined(HAVE_ZL_INFLAT64) && !defined(NO_DEFLATE64)) + /* zlib does not (yet?) provide Deflate64(tm) support */ +# define NO_DEFLATE64 +#endif + +#ifdef NO_DEFLATE64 + /* disable support for Deflate64(tm) */ +# ifdef USE_DEFLATE64 +# undef USE_DEFLATE64 +# endif +#else + /* enable Deflate64(tm) support unless compiling for SFX stub */ +# if (!defined(USE_DEFLATE64) && !defined(SFX)) +# define USE_DEFLATE64 +# endif +#endif + +/* disable bzip2 support for SFX stub, unless explicitly requested */ +#if (defined(SFX) && !defined(BZIP2_SFX) && defined(USE_BZIP2)) +# undef USE_BZIP2 +#endif + +#if (defined(NO_VMS_TEXT_CONV) || defined(VMS)) +# ifdef VMS_TEXT_CONV +# undef VMS_TEXT_CONV +# endif +#else +# if (!defined(VMS_TEXT_CONV) && !defined(SFX)) +# define VMS_TEXT_CONV +# endif +#endif + +/* Enable -B option per default on specific systems, to allow backing up + * files that would be overwritten. + * (This list of systems must be kept in sync with the list of systems + * that add the B_flag to the UzpOpts structure, see unzip.h.) + */ +#if (!defined(NO_UNIXBACKUP) && !defined(UNIXBACKUP)) +# if defined(UNIX) || defined(OS2) || defined(WIN32) +# define UNIXBACKUP +# endif +#endif + +#if (defined(DLL) && !defined(REENTRANT)) +# define REENTRANT +#endif + +#if (!defined(DYNAMIC_CRC_TABLE) && !defined(FUNZIP)) +# define DYNAMIC_CRC_TABLE +#endif + +#if (defined(DYNAMIC_CRC_TABLE) && !defined(REENTRANT)) +# ifndef DYNALLOC_CRCTAB +# define DYNALLOC_CRCTAB +# endif +#endif + +/*--------------------------------------------------------------------------- + OS-dependent configuration for UnZip internals + ---------------------------------------------------------------------------*/ + +/* Some compiler distributions for Win32/i386 systems try to emulate + * a Unix (POSIX-compatible) environment. + */ +#if (defined(WIN32) && defined(UNIX)) + /* UnZip does not support merging both ports in a single executable. */ +# if (defined(FORCE_WIN32_OVER_UNIX) && defined(FORCE_UNIX_OVER_WIN32)) + /* conflicting choice requests -> we prefer the Win32 environment */ +# undef FORCE_UNIX_OVER_WIN32 +# endif +# ifdef FORCE_WIN32_OVER_UNIX + /* native Win32 support was explicitly requested... */ +# undef UNIX +# else + /* use the POSIX (Unix) emulation features by default... */ +# undef WIN32 +# endif +#endif + +/* bad or (occasionally?) missing stddef.h: */ +#if (defined(M_XENIX) || defined(DNIX)) +# define NO_STDDEF_H +#endif + +#if (defined(M_XENIX) && !defined(M_UNIX)) /* SCO Xenix only, not SCO Unix */ +# define SCO_XENIX +# define NO_LIMITS_H /* no limits.h, but MODERN defined */ +# define NO_UID_GID /* no uid_t/gid_t */ +# define size_t int +#endif + +#ifdef realix /* Modcomp Real/IX, real-time SysV.3 variant */ +# define SYSV +# define NO_UID_GID /* no uid_t/gid_t */ +#endif + +#if (defined(_AIX) && !defined(_ALL_SOURCE)) +# define _ALL_SOURCE +#endif + +#if defined(apollo) /* defines __STDC__ */ +# define NO_STDLIB_H +#endif + +#ifdef DNIX +# define SYSV +# define SHORT_NAMES /* 14-char limitation on path components */ +/* # define FILENAME_MAX 14 */ +# define FILENAME_MAX NAME_MAX /* GRR: experiment */ +#endif + +#if (defined(SYSTEM_FIVE) || defined(__SYSTEM_FIVE)) +# ifndef SYSV +# define SYSV +# endif +#endif /* SYSTEM_FIVE || __SYSTEM_FIVE */ +#if (defined(M_SYSV) || defined(M_SYS5)) +# ifndef SYSV +# define SYSV +# endif +#endif /* M_SYSV || M_SYS5 */ +/* __SVR4 and __svr4__ catch Solaris on at least some combos of compiler+OS */ +#if (defined(__SVR4) || defined(__svr4__) || defined(sgi) || defined(__hpux)) +# ifndef SYSV +# define SYSV +# endif +#endif /* __SVR4 || __svr4__ || sgi || __hpux */ +#if (defined(LINUX) || defined(__QNX__)) +# ifndef SYSV +# define SYSV +# endif +#endif /* LINUX || __QNX__ */ + +#if (defined(ultrix) || defined(__ultrix) || defined(bsd4_2)) +# if (!defined(BSD) && !defined(SYSV)) +# define BSD +# endif +#endif /* ultrix || __ultrix || bsd4_2 */ +#if (defined(sun) || defined(pyr) || defined(CONVEX)) +# if (!defined(BSD) && !defined(SYSV)) +# define BSD +# endif +#endif /* sun || pyr || CONVEX */ + +#ifdef pyr /* Pyramid: has BSD and AT&T "universes" */ +# ifdef BSD +# define pyr_bsd +# define USE_STRINGS_H /* instead of more common string.h */ +# define ZMEM /* ZMEM now uses bcopy/bzero: not in AT&T universe */ +# endif /* (AT&T memcpy claimed to be very slow, though) */ +# define DECLARE_ERRNO +#endif /* pyr */ + +/* stat() bug for Borland, VAX C RTL, and Atari ST MiNT on TOS + * filesystems: returns 0 for wildcards! (returns 0xffffffff on Minix + * filesystem or `U:' drive under Atari MiNT.) Watcom C was previously + * included on this list; it would be good to know what version the problem + * was fixed at, if it did exist. */ +#if (defined(__TURBOC__) && !defined(WIN32)) +/*# define WILD_STAT_BUG*/ +#endif +#if (defined(VMS) || defined(__MINT__)) +# define WILD_STAT_BUG +#endif + +/*--------------------------------------------------------------------------- + OS-dependent includes + ---------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------- + API (DLL) section: + ---------------------------------------------------------------------------*/ + +#ifdef DLL +# define MAIN UZ_EXP UzpMain /* was UzpUnzip */ +# ifdef OS2DLL +# undef Info +# define REDIRECTC(c) varputchar(__G__ c) +# define REDIRECTPRINT(buf,size) varmessage(__G__ buf, size) +# define FINISH_REDIRECT() finish_REXX_redirect(__G) +# else +# define REDIRECTC(c) +# define REDIRECTPRINT(buf,size) 0 +# define FINISH_REDIRECT() close_redirect(__G) +# endif +#endif + +/*--------------------------------------------------------------------------- + Acorn RISCOS section: + ---------------------------------------------------------------------------*/ + +#ifdef RISCOS +# include "acorn/riscos.h" +#endif + +/*--------------------------------------------------------------------------- + Amiga section: + ---------------------------------------------------------------------------*/ + +#ifdef AMIGA +# include "amiga/amiga.h" +#endif + +/*--------------------------------------------------------------------------- + AOS/VS section (somewhat similar to Unix, apparently): + ---------------------------------------------------------------------------*/ + +#ifdef AOS_VS +# ifdef __FILEIO_C +# include "aosvs/aosvs.h" +# endif +#endif + +/*--------------------------------------------------------------------------- + Atari ST section: + ---------------------------------------------------------------------------*/ + +#ifdef ATARI +# include +# include +# include +# include +# define SYMLINKS +# define EXE_EXTENSION ".tos" +# ifndef DATE_FORMAT +# define DATE_FORMAT DF_DMY +# endif +# define DIR_END '/' +# define INT_SPRINTF +# define timezone _timezone +# define lenEOL 2 +# define PutNativeEOL {*q++ = native(CR); *q++ = native(LF);} +# undef SHORT_NAMES +# if (!defined(NOTIMESTAMP) && !defined(TIMESTAMP)) +# define TIMESTAMP +# endif +#endif + +/*--------------------------------------------------------------------------- + AtheOS section: + ---------------------------------------------------------------------------*/ + +#ifdef __ATHEOS__ +# include "atheos/athcfg.h" +#endif + +/*--------------------------------------------------------------------------- + BeOS section: + ---------------------------------------------------------------------------*/ + +#ifdef __BEOS__ +# include "beos/beocfg.h" +#endif + +/*--------------------------------------------------------------------------- + Human68k/X680x0 section: + ---------------------------------------------------------------------------*/ + +#ifdef __human68k__ + /* DO NOT DEFINE DOS_OS2 HERE! If Human68k is so much */ + /* like MS-DOS and/or OS/2, create DOS_H68_OS2 macro. */ +# if (!defined(_MBCS) && !defined(NO_MBCS)) + /* enable MBCS support by default for this system */ +# define _MBCS +# endif +# if (defined(_MBCS) && defined(NO_MBCS)) + /* disable MBCS support when explicitely requested */ +# undef _MBCS +# endif +# include +# include +# include +# include +# include +# ifdef HAVE_MBSTRING_H +# include +# endif +# ifdef HAVE_MBCTYPE_H +# include +# else +# ifndef _ismbblead +# define _ismbblead(c) (0x80 <= (c) && ((c) < 0xa0 || 0xe0 <= (c))) +# endif +# endif +# ifndef DATE_FORMAT +# define DATE_FORMAT DF_YMD /* Japanese standard */ +# endif +# define lenEOL 1 +# define PutNativeEOL *q++ = native(LF); +# define INT_SPRINTF +# define SYMLINKS +# ifdef SFX +# define MAIN main_sfx +# endif +#endif + +/*--------------------------------------------------------------------------- + Mac section: + ---------------------------------------------------------------------------*/ + +#ifdef MACOS +# include "maccfg.h" +#endif /* MACOS */ + +/*--------------------------------------------------------------------------- + MS-DOS, OS/2, FLEXOS section: + ---------------------------------------------------------------------------*/ + +#ifdef WINDLL +# ifdef MORE +# undef MORE +# endif +# ifdef OS2_EAS +# undef OS2_EAS +# endif +#endif + +#if (defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__))) +# ifndef MSC +# define MSC /* This should work for older MSC, too! */ +# endif +#endif + +#if (defined(MSDOS) || defined(OS2) || defined(FLEXOS)) +# include /* off_t, time_t, dev_t, ... */ +# include +# include /* lseek(), open(), setftime(), dup(), creat() */ +# include /* localtime() */ +# include /* O_BINARY for open() w/o CR/LF translation */ + +# ifdef OS2 /* defined for all OS/2 compilers */ +# include "os2/os2cfg.h" +# else +# ifdef FLEXOS +# include "flexos/flxcfg.h" +# else +# include "msdos/doscfg.h" +# endif +# endif + +# if (defined(_MSC_VER) && (_MSC_VER == 700) && !defined(GRR)) + /* + * ARGH. MSC 7.0 libraries think times are based on 1899 Dec 31 00:00, not + * 1970 Jan 1 00:00. So we have to diddle time_t's appropriately: add or + * subtract 70 years' worth of seconds; i.e., number of days times 86400; + * i.e., (70*365 regular days + 17 leap days + 1 1899 day) * 86400 == + * (25550 + 17 + 1) * 86400 == 2209075200 seconds. We know time_t is an + * unsigned long (ulg) on the only system with this bug. + */ +# define TIMET_TO_NATIVE(x) (x) += (ulg)2209075200L; +# define NATIVE_TO_TIMET(x) (x) -= (ulg)2209075200L; +# endif +# if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x0450)) +# define timezone _timezone +# endif +# if (defined(__GO32__) || defined(FLEXOS)) +# define DIR_END '/' +# else +# define DIR_END '\\' /* OS uses '\\' as directory separator */ +# define DIR_END2 '/' /* also check for '/' (RTL may convert) */ +# endif +# ifdef DATE_FORMAT +# undef DATE_FORMAT +# endif +# define DATE_FORMAT dateformat() +# define lenEOL 2 +# define PutNativeEOL {*q++ = native(CR); *q++ = native(LF);} +# if (!defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)) +# define USE_EF_UT_TIME +# endif +#endif /* MSDOS || OS2 || FLEXOS */ + +/*--------------------------------------------------------------------------- + MTS section (piggybacks UNIX, I think): + ---------------------------------------------------------------------------*/ + +#ifdef MTS +# include /* off_t, time_t, dev_t, ... */ +# include +# include /* MTS uses this instead of fcntl.h */ +# include +# include +# include /* some important non-ANSI routines */ +# define mkdir(s,n) (-1) /* no "make directory" capability */ +# define EBCDIC /* set EBCDIC conversion on */ +# define NO_STRNICMP /* unzip's is as good the one in MTS */ +# define USE_FWRITE +# define close_outfile() fclose(G.outfile) /* can't set time on files */ +# define umask(n) /* don't have umask() on MTS */ +# define FOPWT "w" /* open file for writing in TEXT mode */ +# ifndef DATE_FORMAT +# define DATE_FORMAT DF_MDY +# endif +# define lenEOL 1 +# define PutNativeEOL *q++ = native(LF); +#endif /* MTS */ + + /*--------------------------------------------------------------------------- + Novell Netware NLM section + ---------------------------------------------------------------------------*/ + +#ifdef NLM +# include "netware/nlmcfg.h" +#endif + + /*--------------------------------------------------------------------------- + QDOS section + ---------------------------------------------------------------------------*/ + +#ifdef QDOS +# define DIRENT +# include +# include +# include +# include +# include "qdos/izqdos.h" +# ifndef DATE_FORMAT +# define DATE_FORMAT DF_MDY +# endif +# define lenEOL 1 +# define PutNativeEOL *q++ = native(LF); +# define DIR_END '_' +# define RETURN QReturn +# undef PATH_MAX +# define PATH_MAX 36 +# if (!defined(NOTIMESTAMP) && !defined(TIMESTAMP)) +# define TIMESTAMP +# endif +# define SCREENSIZE(ttrows, ttcols) screensize(ttrows, ttcols) +# define SCREENWIDTH 80 +#endif + +/*--------------------------------------------------------------------------- + Tandem NSK section: + ---------------------------------------------------------------------------*/ + +#ifdef TANDEM +# include "tandem.h" +# include +# ifndef __INT32 + /* We are compiling with non-WIDE memory model, int = 16 bits */ +# ifndef INT_16BIT +# define INT_16BIT /* report "int" size is 16-bit to inflate setup */ +# endif +# ifdef USE_DEFLATE64 + /* Following required for 64k WSIZE of Deflate64 support */ +# define MED_MEM /* else OUTBUFSIZ is 64K and fails in do_string */ +# define INBUFSIZ 8192 /* but larger buffer for real OSes */ +# endif +# endif + /* use a single LF delimiter so that writes to 101 text files work */ +# define PutNativeEOL *q++ = native(LF); +# define lenEOL 1 +# ifndef DATE_FORMAT +# define DATE_FORMAT DF_DMY +# endif +# define SCREENLINES 25 + /* USE_EF_UT_TIME is set in tandem.h */ +# define RESTORE_UIDGID +# define NO_STRNICMP +#endif + +/*--------------------------------------------------------------------------- + THEOS section: + ---------------------------------------------------------------------------*/ + +#ifdef THEOS +# include "theos/thscfg.h" +#endif + +/*--------------------------------------------------------------------------- + TOPS-20 section: + ---------------------------------------------------------------------------*/ + +#ifdef TOPS20 +# include /* off_t, time_t, dev_t, ... */ +# include +# include +# include +# include +# include +# include +# include /* get amazing monsym() macro */ + extern int open(), close(), read(); + extern int stat(), unlink(), jsys(), fcntl(); + extern long lseek(), dup(), creat(); +# define strchr index /* GRR: necessary? */ +# define strrchr rindex +# define REALLY_SHORT_SYMS +# define NO_MKDIR +# ifndef HAVE_STRNICMP +# define NO_STRNICMP /* probably not provided by TOPS20 C RTL */ +# endif +# define DIR_BEG '<' +# define DIR_END '>' +# define DIR_EXT ".directory" +# ifndef DATE_FORMAT +# define DATE_FORMAT DF_MDY +# endif +# define EXE_EXTENSION ".exe" /* just a guess... */ +#endif /* TOPS20 */ + +/*--------------------------------------------------------------------------- + Unix section: + ---------------------------------------------------------------------------*/ + +#ifdef UNIX +# include "unix/unxcfg.h" +#endif /* UNIX */ + +/*--------------------------------------------------------------------------- + VM/CMS and MVS section: + ---------------------------------------------------------------------------*/ + +#ifdef CMS_MVS +# include "vmmvs.h" +# define CLOSE_INFILE() close_infile(__G) +#endif + +/*--------------------------------------------------------------------------- + VMS section: + ---------------------------------------------------------------------------*/ + +#ifdef VMS +# include "vms/vmscfg.h" +#endif /* VMS */ + +/*--------------------------------------------------------------------------- + Win32 (Windows 95/NT) section: + ---------------------------------------------------------------------------*/ + +#if (defined(WIN32) && !defined(POCKET_UNZIP) && !defined(_WIN32_WCE)) +# include "win32/w32cfg.h" +#endif + +/*--------------------------------------------------------------------------- + Win32 Windows CE section (also POCKET_UNZIP) + ---------------------------------------------------------------------------*/ + +#if (defined(_WIN32_WCE) || defined(POCKET_UNZIP)) +# include "wince/wcecfg.h" +#endif + + + +/* ---------------------------------------------------------------------------- + MUST BE AFTER LARGE FILE INCLUDES + ---------------------------------------------------------------------------- */ +/* This stuff calls in types and messes up large file includes. It needs to + go after large file defines in local includes. + I am guessing that moving them here probably broke some ports, but hey. + 10/31/2004 EG */ +/* ---------------------------------------------------------------------------- + Common includes + ---------------------------------------------------------------------------- */ + +/* Some ports apply specific adjustments which must be in effect before + reading the "standard" include headers. + */ + +#ifdef EFT +# define Z_OFF_T off_t /* Amdahl UTS nonsense ("extended file types") */ +#else +#if (defined(UNIX) && defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)) +# define Z_OFF_T off_t /* 64bit offsets to support 2GB < zipfile size < 4GB */ +#else +# define Z_OFF_T long +#endif +#endif + +#ifndef ZOFF_T_DEFINED + typedef Z_OFF_T zoff_t; +# define ZOFF_T_DEFINED +#endif +#ifndef Z_STAT_DEFINED + typedef struct stat z_stat; +# define Z_STAT_DEFINED +#endif + +#ifndef MINIX /* Minix needs it after all the other includes (?) */ +# include +#endif + +#include /* skip for VMS, to use tolower() function? */ +#include /* used in mapname() */ +#ifdef USE_STRINGS_H +# include /* strcpy, strcmp, memcpy, index/rindex, etc. */ +#else +# include /* strcpy, strcmp, memcpy, strchr/strrchr, etc. */ +#endif +#if (defined(MODERN) && !defined(NO_LIMITS_H)) +# include /* MAX/MIN constant symbols for system types... */ +#endif + +/* this include must be down here for SysV.4, for some reason... */ +#include /* used in unzip.c, fileio.c */ + + +#ifdef MODERN +# ifndef NO_STDDEF_H +# include +# endif +# ifndef NO_STDLIB_H +# include /* standard library prototypes, malloc(), etc. */ +# endif + typedef size_t extent; +#else /* !MODERN */ +# ifndef AOS_VS /* mostly modern? */ + Z_OFF_T lseek(); +# ifdef VAXC /* not fully modern, but has stdlib.h and void */ +# include +# else + char *malloc(); +# endif /* ?VAXC */ +# endif /* !AOS_VS */ + typedef unsigned int extent; +#endif /* ?MODERN */ + + + + +/*************/ +/* Defines */ +/*************/ + +#define UNZIP_BZ2VERS 46 +#ifdef ZIP64_SUPPORT +# ifdef USE_BZIP2 +# define UNZIP_VERSION UNZIP_BZ2VERS +# else +# define UNZIP_VERSION 45 +# endif +#else +#ifdef USE_DEFLATE64 +# define UNZIP_VERSION 21 /* compatible with PKUNZIP 4.0 */ +#else +# define UNZIP_VERSION 20 /* compatible with PKUNZIP 2.0 */ +#endif +#endif +#define VMS_UNZIP_VERSION 42 /* if OS-needed-to-extract is VMS: can do */ + +#if (defined(MSDOS) || defined(OS2)) +# define DOS_OS2 +#endif + +#if (defined(OS2) || defined(WIN32)) +# define OS2_W32 +#endif + +#if (defined(DOS_OS2) || defined(WIN32)) +# define DOS_OS2_W32 +# define DOS_W32_OS2 /* historical: don't use */ +#endif + +#if (defined(DOS_OS2_W32) || defined(__human68k__)) +# define DOS_H68_OS2_W32 +#endif + +#if (defined(DOS_OS2) || defined(FLEXOS)) +# define DOS_FLX_OS2 +#endif + +#if (defined(DOS_OS2_W32) || defined(FLEXOS)) +# define DOS_FLX_OS2_W32 +#endif + +#if (defined(DOS_H68_OS2_W32) || defined(FLEXOS)) +# define DOS_FLX_H68_OS2_W32 +#endif + +#if (defined(DOS_FLX_OS2) || defined(NLM)) +# define DOS_FLX_NLM_OS2 +#endif + +#if (defined(DOS_FLX_OS2_W32) || defined(NLM)) +# define DOS_FLX_NLM_OS2_W32 +#endif + +#if (defined(DOS_FLX_H68_OS2_W32) || defined(NLM)) +# define DOS_FLX_H68_NLM_OS2_W32 +#endif + +#if (defined(TOPS20) || defined(VMS)) +# define T20_VMS +#endif + +#if (defined(MSDOS) || defined(T20_VMS)) +# define DOS_T20_VMS +#endif + +#if (defined(__ATHEOS__) || defined(__BEOS__)) +# define ATH_BEO +#endif + +#if (defined(ATH_BEO) || defined(UNIX)) +# define ATH_BEO_UNX +#endif + +#if (defined(ATH_BEO_UNX) || defined(THEOS)) +# define ATH_BEO_THS_UNX +#endif + +/* clean up with a few defaults */ +#ifndef DIR_END +# define DIR_END '/' /* last char before program name or filename */ +#endif +#ifndef DATE_FORMAT +# ifdef DATEFMT_ISO_DEFAULT +# define DATE_FORMAT DF_YMD /* defaults to invariant ISO-style */ +# else +# define DATE_FORMAT DF_MDY /* defaults to US convention */ +# endif +#endif +#ifndef DATE_SEPCHAR +# define DATE_SEPCHAR '-' +#endif +#ifndef CLOSE_INFILE +# define CLOSE_INFILE() close(G.zipfd) +#endif +#ifndef RETURN +# define RETURN return /* only used in main() */ +#endif +#ifndef EXIT +# define EXIT exit +#endif +#ifndef USAGE +# define USAGE(ret) usage(__G__ (ret)) /* used in unzip.c, zipinfo.c */ +#endif +#ifndef TIMET_TO_NATIVE /* everybody but MSC 7.0 and Macintosh */ +# define TIMET_TO_NATIVE(x) +# define NATIVE_TO_TIMET(x) +#endif +#ifndef STRNICMP +# ifdef NO_STRNICMP +# define STRNICMP zstrnicmp +# else +# define STRNICMP strnicmp +# endif +#endif + + +#if (defined(DOS_FLX_NLM_OS2_W32) || defined(ATH_BEO_UNX) || defined(RISCOS)) +# ifndef HAVE_UNLINK +# define HAVE_UNLINK +# endif +#endif +#if (defined(AOS_VS) || defined(ATARI)) /* GRR: others? */ +# ifndef HAVE_UNLINK +# define HAVE_UNLINK +# endif +#endif + +/* OS-specific exceptions to the "ANSI <--> INT_SPRINTF" rule */ + +#if (!defined(PCHAR_SPRINTF) && !defined(INT_SPRINTF)) +# if (defined(SYSV) || defined(CONVEX) || defined(NeXT) || defined(BSD4_4)) +# define INT_SPRINTF /* sprintf() returns int: SysVish/Posix */ +# endif +# if (defined(DOS_FLX_NLM_OS2_W32) || defined(VMS) || defined(AMIGA)) +# define INT_SPRINTF /* sprintf() returns int: ANSI */ +# endif +# if (defined(ultrix) || defined(__ultrix)) /* Ultrix 4.3 and newer */ +# if (defined(POSIX) || defined(__POSIX)) +# define INT_SPRINTF /* sprintf() returns int: ANSI/Posix */ +# endif +# ifdef __GNUC__ +# define PCHAR_SPRINTF /* undetermined actual return value */ +# endif +# endif +# if (defined(__osf__) || defined(_AIX) || defined(CMS_MVS) || defined(THEOS)) +# define INT_SPRINTF /* sprintf() returns int: ANSI/Posix */ +# endif +# if defined(sun) +# define PCHAR_SPRINTF /* sprintf() returns char *: SunOS cc *and* gcc */ +# endif +#endif + +/* defaults that we hope will take care of most machines in the future */ + +#if (!defined(PCHAR_SPRINTF) && !defined(INT_SPRINTF)) +# ifdef __STDC__ +# define INT_SPRINTF /* sprintf() returns int: ANSI */ +# endif +# ifndef INT_SPRINTF +# define PCHAR_SPRINTF /* sprintf() returns char *: BSDish */ +# endif +#endif + +#define MSG_STDERR(f) (f & 1) /* bit 0: 0 = stdout, 1 = stderr */ +#define MSG_INFO(f) ((f & 6) == 0) /* bits 1 and 2: 0 = info */ +#define MSG_WARN(f) ((f & 6) == 2) /* bits 1 and 2: 1 = warning */ +#define MSG_ERROR(f) ((f & 6) == 4) /* bits 1 and 2: 2 = error */ +#define MSG_FATAL(f) ((f & 6) == 6) /* bits 1 and 2: (3 = fatal error) */ +#define MSG_ZFN(f) (f & 0x0008) /* bit 3: 1 = print zipfile name */ +#define MSG_FN(f) (f & 0x0010) /* bit 4: 1 = print filename */ +#define MSG_LNEWLN(f) (f & 0x0020) /* bit 5: 1 = leading newline if !SOL */ +#define MSG_TNEWLN(f) (f & 0x0040) /* bit 6: 1 = trailing newline if !SOL */ +#define MSG_MNEWLN(f) (f & 0x0080) /* bit 7: 1 = trailing NL for prompts */ +/* the following are subject to change */ +#define MSG_NO_WGUI(f) (f & 0x0100) /* bit 8: 1 = skip if Windows GUI */ +#define MSG_NO_AGUI(f) (f & 0x0200) /* bit 9: 1 = skip if Acorn GUI */ +#define MSG_NO_DLL2(f) (f & 0x0400) /* bit 10: 1 = skip if OS/2 DLL */ +#define MSG_NO_NDLL(f) (f & 0x0800) /* bit 11: 1 = skip if WIN32 DLL */ +#define MSG_NO_WDLL(f) (f & 0x1000) /* bit 12: 1 = skip if Windows DLL */ + +#if (defined(MORE) && !defined(SCREENLINES)) +# ifdef DOS_FLX_NLM_OS2_W32 +# define SCREENLINES 25 /* can be (should be) a function instead */ +# else +# define SCREENLINES 24 /* VT-100s are assumed to be minimal hardware */ +# endif +#endif +#if (defined(MORE) && !defined(SCREENSIZE)) +# ifndef SCREENWIDTH +# define SCREENSIZE(scrrows, scrcols) { \ + if ((scrrows) != NULL) *(scrrows) = SCREENLINES; } +# else +# define SCREENSIZE(scrrows, scrcols) { \ + if ((scrrows) != NULL) *(scrrows) = SCREENLINES; \ + if ((scrcols) != NULL) *(scrcols) = SCREENWIDTH; } +# endif +#endif + +#if (defined(__16BIT__) || defined(MED_MEM) || defined(SMALL_MEM)) +# define DIR_BLKSIZ 64 /* number of directory entries per block + * (should fit in 4096 bytes, usually) */ +#else +# define DIR_BLKSIZ 16384 /* use more memory, to reduce long-range seeks */ +#endif + +#ifndef WSIZE +# ifdef USE_DEFLATE64 +# define WSIZE 65536L /* window size--must be a power of two, and */ +# else /* at least 64K for PKZip's deflate64 method */ +# define WSIZE 0x8000 /* window size--must be a power of two, and */ +# endif /* at least 32K for zip's deflate method */ +#endif + +#ifdef __16BIT__ +# ifndef INT_16BIT +# define INT_16BIT /* on 16-bit systems int size is 16 bits */ +# endif +#else +# define nearmalloc malloc +# define nearfree free +# if (!defined(__IBMC__) || !defined(OS2)) +# ifndef near +# define near +# endif +# ifndef far +# define far +# endif +# endif +#endif + +#if (defined(DYNALLOC_CRCTAB) && !defined(DYNAMIC_CRC_TABLE)) +# undef DYNALLOC_CRCTAB +#endif + +#if (defined(DYNALLOC_CRCTAB) && defined(REENTRANT)) +# undef DYNALLOC_CRCTAB /* not safe with reentrant code */ +#endif + +#if (defined(USE_ZLIB) && !defined(USE_OWN_CRCTAB)) +# ifdef DYNALLOC_CRCTAB +# undef DYNALLOC_CRCTAB +# endif +#endif + +#if (defined(USE_ZLIB) && defined(ASM_CRC)) +# undef ASM_CRC +#endif + +#ifdef USE_ZLIB +# ifdef IZ_CRC_BE_OPTIMIZ +# undef IZ_CRC_BE_OPTIMIZ +# endif +# ifdef IZ_CRC_LE_OPTIMIZ +# undef IZ_CRC_LE_OPTIMIZ +# endif +#endif +#if (!defined(IZ_CRC_BE_OPTIMIZ) && !defined(IZ_CRC_LE_OPTIMIZ)) +# ifdef IZ_CRCOPTIM_UNFOLDTBL +# undef IZ_CRCOPTIM_UNFOLDTBL +# endif +#endif + +#ifndef INBUFSIZ +# if (defined(MED_MEM) || defined(SMALL_MEM)) +# define INBUFSIZ 2048 /* works for MS-DOS small model */ +# else +# define INBUFSIZ 8192 /* larger buffers for real OSes */ +# endif +#endif + +#if (defined(INT_16BIT) && (defined(USE_DEFLATE64) || lenEOL > 1)) + /* For environments using 16-bit integers OUTBUFSIZ must be limited to + * less than 64k (do_string() uses "unsigned" in calculations involving + * OUTBUFSIZ). This is achieved by defining MED_MEM when WSIZE = 64k (aka + * Deflate64 support enabled) or EOL markers contain multiple characters. + * (The rule gets applied AFTER the default rule for INBUFSIZ because it + * is not neccessary to reduce INBUFSIZE in this case.) + */ +# if (!defined(SMALL_MEM) && !defined(MED_MEM)) +# define MED_MEM +# endif +#endif + +/* Logic for case of small memory, length of EOL > 1: if OUTBUFSIZ == 2048, + * OUTBUFSIZ>>1 == 1024 and OUTBUFSIZ>>7 == 16; therefore rawbuf is 1008 bytes + * and transbuf 1040 bytes. Have room for 32 extra EOL chars; 1008/32 == 31.5 + * chars/line, smaller than estimated 35-70 characters per line for C source + * and normal text. Hence difference is sufficient for most "average" files. + * (Argument scales for larger OUTBUFSIZ.) + */ +#ifdef SMALL_MEM /* i.e., 16-bit OSes: MS-DOS, OS/2 1.x, etc. */ +# define LoadFarString(x) fLoadFarString(__G__ (x)) +# define LoadFarStringSmall(x) fLoadFarStringSmall(__G__ (x)) +# define LoadFarStringSmall2(x) fLoadFarStringSmall2(__G__ (x)) +# if (defined(_MSC_VER) && (_MSC_VER >= 600)) +# define zfstrcpy(dest, src) _fstrcpy((dest), (src)) +# define zfstrcmp(s1, s2) _fstrcmp((s1), (s2)) +# endif +# if !(defined(SFX) || defined(FUNZIP)) +# if (defined(_MSC_VER)) +# define zfmalloc(sz) _fmalloc((sz)) +# define zffree(x) _ffree(x) +# endif +# if (defined(__TURBOC__)) +# include +# define zfmalloc(sz) farmalloc((unsigned long)(sz)) +# define zffree(x) farfree(x) +# endif +# endif /* !(SFX || FUNZIP) */ +# ifndef Far +# define Far far /* __far only works for MSC 6.00, not 6.0a or Borland */ +# endif +# define OUTBUFSIZ INBUFSIZ +# if (lenEOL == 1) +# define RAWBUFSIZ (OUTBUFSIZ>>1) +# else +# define RAWBUFSIZ ((OUTBUFSIZ>>1) - (OUTBUFSIZ>>7)) +# endif +# define TRANSBUFSIZ (OUTBUFSIZ-RAWBUFSIZ) + typedef short shrint; /* short/int or "shrink int" (unshrink) */ +#else +# define zfstrcpy(dest, src) strcpy((dest), (src)) +# define zfstrcmp(s1, s2) strcmp((s1), (s2)) +# define zfmalloc malloc +# define zffree(x) free(x) +# ifdef QDOS +# define LoadFarString(x) Qstrfix(x) /* fix up _ for '.' */ +# define LoadFarStringSmall(x) Qstrfix(x) +# define LoadFarStringSmall2(x) Qstrfix(x) +# else +# define LoadFarString(x) (char *)(x) +# define LoadFarStringSmall(x) (char *)(x) +# define LoadFarStringSmall2(x) (char *)(x) +# endif +# ifdef MED_MEM +# define OUTBUFSIZ 0xFF80 /* can't malloc arrays of 0xFFE8 or more */ +# define TRANSBUFSIZ 0xFF80 + typedef short shrint; +# else +# define OUTBUFSIZ (lenEOL*WSIZE) /* more efficient text conversion */ +# define TRANSBUFSIZ (lenEOL*OUTBUFSIZ) +# ifdef AMIGA + typedef short shrint; +# else + typedef int shrint; /* for efficiency/speed, we hope... */ +# endif +# endif /* ?MED_MEM */ +# define RAWBUFSIZ OUTBUFSIZ +#endif /* ?SMALL_MEM */ + +#ifndef Far +# define Far +#endif + +#ifndef Cdecl +# define Cdecl +#endif + +#ifndef MAIN +# define MAIN main +#endif + +#ifdef SFX /* disable some unused features for SFX executables */ +# ifndef NO_ZIPINFO +# define NO_ZIPINFO +# endif +# ifdef TIMESTAMP +# undef TIMESTAMP +# endif +#endif + +#ifdef SFX +# ifdef CHEAP_SFX_AUTORUN +# ifndef NO_SFX_EXDIR +# define NO_SFX_EXDIR +# endif +# endif +# ifndef NO_SFX_EXDIR +# ifndef SFX_EXDIR +# define SFX_EXDIR +# endif +# else +# ifdef SFX_EXDIR +# undef SFX_EXDIR +# endif +# endif +#endif + +/* user may have defined both by accident... NOTIMESTAMP takes precedence */ +#if (defined(TIMESTAMP) && defined(NOTIMESTAMP)) +# undef TIMESTAMP +#endif + +#if (!defined(COPYRIGHT_CLEAN) && !defined(USE_SMITH_CODE)) +# define COPYRIGHT_CLEAN +#endif + +/* The LZW patent is expired worldwide since 2004-Jul-07, so USE_UNSHRINK + * is now enabled by default. See unshrink.c. + */ +#if (!defined(LZW_CLEAN) && !defined(USE_UNSHRINK)) +# define USE_UNSHRINK +#endif + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +#ifndef PIPE_ERROR +# ifndef EPIPE +# define EPIPE -1 +# endif +# define PIPE_ERROR (errno == EPIPE) +#endif + +/* File operations--use "b" for binary if allowed or fixed length 512 on VMS */ +#ifdef VMS +# define FOPR "r","ctx=stm" +# define FOPM "r+","ctx=stm","rfm=fix","mrs=512" +# define FOPW "w","ctx=stm","rfm=fix","mrs=512" +# define FOPWR "w+","ctx=stm","rfm=fix","mrs=512" +#endif /* VMS */ + +#ifdef CMS_MVS +/* Binary files must be RECFM=F,LRECL=1 for ftell() to get correct pos */ +/* ...unless byteseek is used. Let's try that for a while. */ +# define FOPR "rb,byteseek" +# define FOPM "r+b,byteseek" +# ifdef MVS +# define FOPW "wb,recfm=u,lrecl=32760,byteseek" /* New binary files */ +# define FOPWE "wb" /* Existing binary files */ +# define FOPWT "w,lrecl=133" /* New text files */ +# define FOPWTE "w" /* Existing text files */ +# else +# define FOPW "wb,recfm=v,lrecl=32760" +# define FOPWT "w" +# endif +#endif /* CMS_MVS */ + +#ifdef TOPS20 /* TOPS-20 MODERN? You kidding? */ +# define FOPW "w8" +#endif /* TOPS20 */ + +/* Defaults when nothing special has been defined previously. */ +#ifdef MODERN +# ifndef FOPR +# define FOPR "rb" +# endif +# ifndef FOPM +# define FOPM "r+b" +# endif +# ifndef FOPW +# define FOPW "wb" +# endif +# ifndef FOPWT +# define FOPWT "wt" +# endif +# ifndef FOPWR +# define FOPWR "w+b" +# endif +#else /* !MODERN */ +# ifndef FOPR +# define FOPR "r" +# endif +# ifndef FOPM +# define FOPM "r+" +# endif +# ifndef FOPW +# define FOPW "w" +# endif +# ifndef FOPWT +# define FOPWT "w" +# endif +# ifndef FOPWR +# define FOPWR "w+" +# endif +#endif /* ?MODERN */ + +/* + * If exists on most systems, should include that, since it may + * define some or all of the following: NAME_MAX, PATH_MAX, _POSIX_NAME_MAX, + * _POSIX_PATH_MAX. + */ +#ifdef DOS_FLX_NLM_OS2_W32 +# include +#endif + +/* 2008-07-22 SMS. + * Unfortunately, on VMS, exists, and is included by + * (so it's pretty much unavoidable), and it defines PATH_MAX to a fixed + * short value (256, correct only for older systems without ODS-5 support), + * rather than one based on the real RMS NAM[L] situation. So, we + * artificially undefine it here, to allow our better-defined _MAX_PATH + * (see vms/vmscfg.h) to be used. + */ +#ifdef VMS +# undef PATH_MAX +#endif + +#ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN /* in on some systems */ +# else +# ifdef _MAX_PATH +# define PATH_MAX _MAX_PATH +# else +# if FILENAME_MAX > 255 +# define PATH_MAX FILENAME_MAX /* used like PATH_MAX on some systems */ +# else +# define PATH_MAX 1024 +# endif +# endif /* ?_MAX_PATH */ +# endif /* ?MAXPATHLEN */ +#endif /* !PATH_MAX */ + +/* + * buffer size required to hold the longest legal local filepath + * (including the trailing '\0') + */ +#define FILNAMSIZ PATH_MAX + +#ifdef UNICODE_SUPPORT +# if !(defined(UTF8_MAYBE_NATIVE) || defined(UNICODE_WCHAR)) +# undef UNICODE_SUPPORT +# endif +#endif +/* 2007-09-18 SMS. + * Include here if it will be needed later for Unicode. + * Otherwise, SETLOCALE may be defined here, and then defined again + * (differently) when is read later. + */ +#ifdef UNICODE_SUPPORT +# ifdef UNICODE_WCHAR +# if !(defined(_WIN32_WCE) || defined(POCKET_UNZIP)) +# include +# endif +# endif +# ifndef _MBCS /* no need to include twice, see below */ +# include +# ifndef SETLOCALE +# define SETLOCALE(category, locale) setlocale(category, locale) +# endif +# endif +#endif /* UNICODE_SUPPORT */ + +/* DBCS support for Info-ZIP (mainly for japanese (-: ) + * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp) + */ +#ifdef _MBCS +# include + /* Multi Byte Character Set */ +# define ___MBS_TMP_DEF char *___tmp_ptr; +# define ___TMP_PTR ___tmp_ptr +# ifndef CLEN +# define NEED_UZMBCLEN +# define CLEN(ptr) (int)uzmbclen((ZCONST unsigned char *)(ptr)) +# endif +# ifndef PREINCSTR +# define PREINCSTR(ptr) (ptr += CLEN(ptr)) +# endif +# define POSTINCSTR(ptr) (___TMP_PTR=(char *)(ptr), PREINCSTR(ptr),___TMP_PTR) + char *plastchar OF((ZCONST char *ptr, extent len)); +# define lastchar(ptr, len) ((int)(unsigned)*plastchar(ptr, len)) +# ifndef MBSCHR +# define NEED_UZMBSCHR +# define MBSCHR(str,c) (char *)uzmbschr((ZCONST unsigned char *)(str), c) +# endif +# ifndef MBSRCHR +# define NEED_UZMBSRCHR +# define MBSRCHR(str,c) (char *)uzmbsrchr((ZCONST unsigned char *)(str), c) +# endif +# ifndef SETLOCALE +# define SETLOCALE(category, locale) setlocale(category, locale) +# endif +#else /* !_MBCS */ +# define ___MBS_TMP_DEF +# define ___TMP_PTR +# define CLEN(ptr) 1 +# define PREINCSTR(ptr) (++(ptr)) +# define POSTINCSTR(ptr) ((ptr)++) +# define plastchar(ptr, len) (&ptr[(len)-1]) +# define lastchar(ptr, len) (ptr[(len)-1]) +# define MBSCHR(str, c) strchr(str, c) +# define MBSRCHR(str, c) strrchr(str, c) +# ifndef SETLOCALE +# define SETLOCALE(category, locale) +# endif +#endif /* ?_MBCS */ +#define INCSTR(ptr) PREINCSTR(ptr) + + +#if (defined(MALLOC_WORK) && !defined(MY_ZCALLOC)) + /* Any system without a special calloc function */ +# ifndef zcalloc +# define zcalloc(items, size) \ + (zvoid far *)calloc((unsigned)(items), (unsigned)(size)) +# endif +# ifndef zcfree +# define zcfree free +# endif +#endif /* MALLOC_WORK && !MY_ZCALLOC */ + +#if (defined(CRAY) && defined(ZMEM)) +# undef ZMEM +#endif + +#ifdef ZMEM +# undef ZMEM +# define memcmp(b1,b2,len) bcmp(b2,b1,len) +# define memcpy(dest,src,len) bcopy(src,dest,len) +# define memzero bzero +#else +# define memzero(dest,len) memset(dest,0,len) +#endif + +#ifndef TRUE +# define TRUE 1 /* sort of obvious */ +#endif +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif + +#if (!defined(S_IEXEC) && defined(S_IXUSR)) +# define S_IEXEC S_IXUSR +#endif + +#if (defined(UNIX) && defined(S_IFLNK) && !defined(MTS)) +# define SYMLINKS +# ifndef S_ISLNK +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# endif +#endif /* UNIX && S_IFLNK && !MTS */ + +#ifndef S_ISDIR +# ifdef CMS_MVS +# define S_ISDIR(m) (FALSE) +# else +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# endif +#endif + +#ifndef IS_VOLID +# define IS_VOLID(m) ((m) & 0x08) +#endif + +/***********************************/ +/* LARGE_FILE_SUPPORT */ +/***********************************/ +/* This whole section lifted from Zip 3b tailor.h + + * Types are in OS dependent headers (eg, w32cfg.h) + * + * LARGE_FILE_SUPPORT and ZIP64_SUPPORT are automatically + * set in OS dependent headers (for some ports) based on the port and compiler. + * + * Function prototypes are below as OF is defined earlier in this file + * but after OS dependent header is included. + * + * E. Gordon 9/21/2003 + * Updated 1/28/2004 + * Lifted and placed here 6/7/2004 - Myles Bennett + */ +#ifdef LARGE_FILE_SUPPORT + /* 64-bit Large File Support */ + +/* ---------------------------- */ + +# if defined(UNIX) || defined(VMS) + + /* 64-bit stat functions */ +# define zstat stat +# define zfstat fstat + + /* 64-bit fseeko */ +# define zlseek lseek +# define zfseeko fseeko + + /* 64-bit ftello */ +# define zftello ftello + + /* 64-bit fopen */ +# define zfopen fopen +# define zfdopen fdopen + +# endif /* UNIX || VMS */ + +/* ---------------------------- */ + +# ifdef WIN32 + +# if defined(_MSC_VER) || defined(__MINGW32__) || defined(__LCC__) + /* MS C (VC), MinGW GCC port and LCC-32 use the MS C Runtime lib */ + + /* 64-bit stat functions */ +# define zstat _stati64 +# define zfstat _fstati64 + + /* 64-bit lseek */ +# define zlseek _lseeki64 + +# if defined(_MSC_VER) && (_MSC_VER >= 1400) + /* Beginning with VS 8.0 (Visual Studio 2005, MSC 14), the Microsoft + C rtl publishes its (previously internal) implmentations of + "fseeko" and "ftello" for 64-bit file offsets. */ + /* 64-bit fseeko */ +# define zfseeko _fseeki64 + /* 64-bit ftello */ +# define zftello _ftelli64 + +# else /* not (defined(_MSC_VER) && (_MSC_VER >= 1400)) */ + +# if defined(__MSVCRT_VERSION__) && (__MSVCRT_VERSION__ >= 0x800) + /* Up-to-date versions of MinGW define the macro __MSVCRT_VERSION__ + to denote the version of the MS C rtl dll used for linking. When + configured to link against the runtime of MS Visual Studio 8 (or + newer), the built-in 64-bit fseek/ftell functions are available. */ + /* 64-bit fseeko */ +# define zfseeko _fseeki64 + /* 64-bit ftello */ +# define zftello _ftelli64 + +# else /* !(defined(__MSVCRT_VERSION__) && (__MSVCRT_VERSION__>=0x800)) */ + /* The version of the C runtime is lower than MSC 14 or unknown. */ + + /* The newest MinGW port contains built-in extensions to the MSC rtl + that provide fseeko and ftello, but our implementations will do + for now. */ + /* 64-bit fseeko */ + int zfseeko OF((FILE *, zoff_t, int)); + + /* 64-bit ftello */ + zoff_t zftello OF((FILE *)); + +# endif /* ? (__MSVCRT_VERSION__ >= 0x800) */ +# endif /* ? (_MSC_VER >= 1400) */ + + /* 64-bit fopen */ +# define zfopen fopen +# define zfdopen fdopen + +# endif /* _MSC_VER || __MINGW__ || __LCC__ */ + +# ifdef __CYGWIN__ + /* CYGWIN GCC Posix emulator on Windows + (configuration not yet finished/tested) */ + + /* 64-bit stat functions */ +# define zstat _stati64 +# define zfstat _fstati64 + + /* 64-bit lseek */ +# define zlseek _lseeki64 + + /* 64-bit fseeko */ +# define zfseeko fseeko + + /* 64-bit ftello */ +# define zftello ftello + + /* 64-bit fopen */ +# define zfopen fopen +# define zfdopen fdopen + +# endif +# if defined(__WATCOMC__) || defined(__BORLANDC__) + /* WATCOM C and Borland C provide their own C runtime libraries, + but they are sufficiently compatible with MS CRTL. */ + + /* 64-bit stat functions */ +# define zstat _stati64 +# define zfstat _fstati64 + +# ifdef __WATCOMC__ + /* 64-bit lseek */ +# define zlseek _lseeki64 +# endif + + /* 64-bit fseeko */ + int zfseeko OF((FILE *, zoff_t, int)); + + /* 64-bit ftello */ + zoff_t zftello OF((FILE *)); + + /* 64-bit fopen */ +# define zfopen fopen +# define zfdopen fdopen + +# endif +# ifdef __IBMC__ + /* IBM C */ + + /* 64-bit stat functions */ + + /* 64-bit fseeko */ + + /* 64-bit ftello */ + + /* 64-bit fopen */ + +# endif + +# endif /* WIN32 */ + +#else + /* No Large File Support */ + +# ifndef REGULUS /* returns the inode number on success(!)...argh argh argh */ +# define zstat stat +# endif +# define zfstat fstat +# define zlseek lseek +# define zfseeko fseek +# define zftello ftell +# define zfopen fopen +# define zfdopen fdopen + +# if defined(UNIX) || defined(VMS) || defined(WIN32) + /* For these systems, implement "64bit file vs. 32bit prog" check */ +# ifndef DO_SAFECHECK_2GB +# define DO_SAFECHECK_2GB +# endif +# endif + +#endif + +/* No "64bit file vs. 32bit prog" check for SFX stub, to save space */ +#if (defined(DO_SAFECHECK_2GB) && defined(SFX)) +# undef DO_SAFECHECK_2GB +#endif + +#ifndef SSTAT +# ifdef WILD_STAT_BUG +# define SSTAT(path,pbuf) (iswild(path) || zstat(path,pbuf)) +# else +# define SSTAT zstat +# endif +#endif + + +/* Default fzofft() format selection. */ + +#ifndef FZOFFT_FMT + +# ifdef LARGE_FILE_SUPPORT +# define FZOFFT_FMT "ll" +# define FZOFFT_HEX_WID_VALUE "16" +# else /* def LARGE_FILE_SUPPORT */ +# define FZOFFT_FMT "l" +# define FZOFFT_HEX_WID_VALUE "8" +# endif /* def LARGE_FILE_SUPPORT */ + +#endif /* ndef FZOFFT_FMT */ + +#define FZOFFT_HEX_WID ((char *) -1) +#define FZOFFT_HEX_DOT_WID ((char *) -2) + +#define FZOFFT_NUM 4 /* Number of chambers. */ +#define FZOFFT_LEN 24 /* Number of characters/chamber. */ + + +#ifdef SHORT_SYMS /* Mark Williams C, ...? */ +# define extract_or_test_files xtr_or_tst_files +# define extract_or_test_member xtr_or_tst_member +#endif + +#ifdef REALLY_SHORT_SYMS /* TOPS-20 linker: first 6 chars */ +# define process_cdir_file_hdr XXpcdfh +# define process_local_file_hdr XXplfh +# define extract_or_test_files XXxotf /* necessary? */ +# define extract_or_test_member XXxotm /* necessary? */ +# define check_for_newer XXcfn +# define overwrite_all XXoa +# define process_all_files XXpaf +# define extra_field XXef +# define explode_lit8 XXel8 +# define explode_lit4 XXel4 +# define explode_nolit8 XXnl8 +# define explode_nolit4 XXnl4 +# define cpdist8 XXcpdist8 +# define inflate_codes XXic +# define inflate_stored XXis +# define inflate_fixed XXif +# define inflate_dynamic XXid +# define inflate_block XXib +# define maxcodemax XXmax +#endif + +#ifndef S_TIME_T_MAX /* max value of signed (>= 32-bit) time_t */ +# define S_TIME_T_MAX ((time_t)(ulg)0x7fffffffL) +#endif +#ifndef U_TIME_T_MAX /* max value of unsigned (>= 32-bit) time_t */ +# define U_TIME_T_MAX ((time_t)(ulg)0xffffffffL) +#endif +#ifdef DOSTIME_MINIMUM /* min DOSTIME value (1980-01-01) */ +# undef DOSTIME_MINIMUM +#endif +#define DOSTIME_MINIMUM ((ulg)0x00210000L) +#ifdef DOSTIME_2038_01_18 /* approximate DOSTIME equivalent of */ +# undef DOSTIME_2038_01_18 /* the signed-32-bit time_t limit */ +#endif +#define DOSTIME_2038_01_18 ((ulg)0x74320000L) + +#ifdef QDOS +# define ZSUFX "_zip" +# define ALT_ZSUFX ".zip" +#else +# ifdef RISCOS +# define ZSUFX "/zip" +# else +# define ZSUFX ".zip" +# endif +# define ALT_ZSUFX ".ZIP" /* Unix-only so far (only case-sensitive fs) */ +#endif + +#define CENTRAL_HDR_SIG "\001\002" /* the infamous "PK" signature bytes, */ +#define LOCAL_HDR_SIG "\003\004" /* w/o "PK" (so unzip executable not */ +#define END_CENTRAL_SIG "\005\006" /* mistaken for zipfile itself) */ +#define EXTD_LOCAL_SIG "\007\010" /* [ASCII "\113" == EBCDIC "\080" ??] */ + +/** internal-only return codes **/ +#define IZ_DIR 76 /* potential zipfile is a directory */ +/* special return codes for mapname() */ +#define MPN_OK 0 /* mapname successful */ +#define MPN_INF_TRUNC (1<<8) /* caution - filename truncated */ +#define MPN_INF_SKIP (2<<8) /* info - skipped because nothing to do */ +#define MPN_ERR_SKIP (3<<8) /* error - entry skipped */ +#define MPN_ERR_TOOLONG (4<<8) /* error - path too long */ +#define MPN_NOMEM (10<<8) /* error - out of memory, file skipped */ +#define MPN_CREATED_DIR (16<<8) /* directory created: set time & permission */ +#define MPN_VOL_LABEL (17<<8) /* volume label, but can't set on hard disk */ +#define MPN_INVALID (99<<8) /* internal logic error, should never reach */ +/* mask for internal mapname&checkdir return codes */ +#define MPN_MASK 0x7F00 +/* error code for extracting/testing extra field blocks */ +#define IZ_EF_TRUNC 79 /* local extra field truncated (PKZIP'd) */ + +/* choice of activities for do_string() */ +#define SKIP 0 /* skip header block */ +#define DISPLAY 1 /* display archive comment (ASCII) */ +#define DISPL_8 5 /* display file comment (ext. ASCII) */ +#define DS_FN 2 /* read filename (ext. ASCII, chead) */ +#define DS_FN_C 2 /* read filename from central header */ +#define DS_FN_L 6 /* read filename from local header */ +#define EXTRA_FIELD 3 /* copy extra field into buffer */ +#define DS_EF 3 +#ifdef AMIGA +# define FILENOTE 4 /* convert file comment to filenote */ +#endif +#if (defined(SFX) && defined(CHEAP_SFX_AUTORUN)) +# define CHECK_AUTORUN 7 /* copy command, display remainder */ +# define CHECK_AUTORUN_Q 8 /* copy command, skip remainder */ +#endif + +#define DOES_NOT_EXIST -1 /* return values for check_for_newer() */ +#define EXISTS_AND_OLDER 0 +#define EXISTS_AND_NEWER 1 + +#define OVERWRT_QUERY 0 /* status values for G.overwrite_mode */ +#define OVERWRT_ALWAYS 1 +#define OVERWRT_NEVER 2 + +#define IS_OVERWRT_ALL (G.overwrite_mode == OVERWRT_ALWAYS) +#define IS_OVERWRT_NONE (G.overwrite_mode == OVERWRT_NEVER) + +#ifdef VMS + /* return codes for VMS-specific open_outfile() function */ +# define OPENOUT_OK 0 /* file openend normally */ +# define OPENOUT_FAILED 1 /* file open failed */ +# define OPENOUT_SKIPOK 2 /* file not opened, skip at error level OK */ +# define OPENOUT_SKIPWARN 3 /* file not opened, skip at error level WARN */ +#endif /* VMS */ + +#define ROOT 0 /* checkdir() extract-to path: called once */ +#define INIT 1 /* allocate buildpath: called once per member */ +#define APPEND_DIR 2 /* append a dir comp.: many times per member */ +#define APPEND_NAME 3 /* append actual filename: once per member */ +#define GETPATH 4 /* retrieve the complete path and free it */ +#define END 5 /* free root path prior to exiting program */ + +/* version_made_by codes (central dir): make sure these */ +/* are not defined on their respective systems!! */ +#define FS_FAT_ 0 /* filesystem used by MS-DOS, OS/2, Win32 */ +#define AMIGA_ 1 +#define VMS_ 2 +#define UNIX_ 3 +#define VM_CMS_ 4 +#define ATARI_ 5 /* what if it's a minix filesystem? [cjh] */ +#define FS_HPFS_ 6 /* filesystem used by OS/2 (and NT 3.x) */ +#define MAC_ 7 /* HFS filesystem used by MacOS */ +#define Z_SYSTEM_ 8 +#define CPM_ 9 +#define TOPS20_ 10 +#define FS_NTFS_ 11 /* filesystem used by Windows NT */ +#define QDOS_ 12 +#define ACORN_ 13 /* Archimedes Acorn RISC OS */ +#define FS_VFAT_ 14 /* filesystem used by Windows 95, NT */ +#define MVS_ 15 +#define BEOS_ 16 /* hybrid POSIX/database filesystem */ +#define TANDEM_ 17 /* Tandem NSK */ +#define THEOS_ 18 /* THEOS */ +#define MAC_OSX_ 19 /* Mac OS/X (Darwin) */ +#define ATHEOS_ 30 /* AtheOS */ +#define NUM_HOSTS 31 /* index of last system + 1 */ +/* don't forget to update zipinfo.c appropiately if NUM_HOSTS changes! */ + +#define STORED 0 /* compression methods */ +#define SHRUNK 1 +#define REDUCED1 2 +#define REDUCED2 3 +#define REDUCED3 4 +#define REDUCED4 5 +#define IMPLODED 6 +#define TOKENIZED 7 +#define DEFLATED 8 +#define ENHDEFLATED 9 +#define DCLIMPLODED 10 +#define BZIPPED 12 +#define LZMAED 14 +#define IBMTERSED 18 +#define IBMLZ77ED 19 +#define WAVPACKED 97 +#define PPMDED 98 +#define NUM_METHODS 17 /* number of known method IDs */ +/* don't forget to update list.c (list_files()), extract.c and zipinfo.c + * appropriately if NUM_METHODS changes */ + +/* (the PK-class error codes are public and have been moved into unzip.h) */ + +#define DF_MDY 0 /* date format 10/26/91 (USA only) */ +#define DF_DMY 1 /* date format 26/10/91 (most of the world) */ +#define DF_YMD 2 /* date format 91/10/26 (a few countries) */ + +/*--------------------------------------------------------------------------- + Extra-field block ID values and offset info. + ---------------------------------------------------------------------------*/ +/* extra-field ID values, all little-endian: */ +#define EF_PKSZ64 0x0001 /* PKWARE's 64-bit filesize extensions */ +#define EF_AV 0x0007 /* PKWARE's authenticity verification */ +#define EF_EFS 0x0008 /* PKWARE's extended language encoding */ +#define EF_OS2 0x0009 /* OS/2 extended attributes */ +#define EF_PKW32 0x000a /* PKWARE's Win95/98/WinNT filetimes */ +#define EF_PKVMS 0x000c /* PKWARE's VMS */ +#define EF_PKUNIX 0x000d /* PKWARE's Unix */ +#define EF_PKFORK 0x000e /* PKWARE's future stream/fork descriptors */ +#define EF_PKPATCH 0x000f /* PKWARE's patch descriptor */ +#define EF_PKPKCS7 0x0014 /* PKWARE's PKCS#7 store for X.509 Certs */ +#define EF_PKFX509 0x0015 /* PKWARE's file X.509 Cert&Signature ID */ +#define EF_PKCX509 0x0016 /* PKWARE's central dir X.509 Cert ID */ +#define EF_PKENCRHD 0x0017 /* PKWARE's Strong Encryption header */ +#define EF_PKRMCTL 0x0018 /* PKWARE's Record Management Controls*/ +#define EF_PKLSTCS7 0x0019 /* PKWARE's PKCS#7 Encr. Recipient Cert List */ +#define EF_PKIBM 0x0065 /* PKWARE's IBM S/390 & AS/400 attributes */ +#define EF_PKIBM2 0x0066 /* PKWARE's IBM S/390 & AS/400 compr. attribs */ +#define EF_IZVMS 0x4d49 /* Info-ZIP's VMS ("IM") */ +#define EF_IZUNIX 0x5855 /* Info-ZIP's first Unix[1] ("UX") */ +#define EF_IZUNIX2 0x7855 /* Info-ZIP's second Unix[2] ("Ux") */ +#define EF_IZUNIX3 0x7875 /* Info-ZIP's newest Unix[3] ("ux") */ +#define EF_TIME 0x5455 /* universal timestamp ("UT") */ +#define EF_UNIPATH 0x7075 /* Info-ZIP Unicode Path ("up") */ +#define EF_UNICOMNT 0x6375 /* Info-ZIP Unicode Comment ("uc") */ +#define EF_MAC3 0x334d /* Info-ZIP's new Macintosh (= "M3") */ +#define EF_JLMAC 0x07c8 /* Johnny Lee's old Macintosh (= 1992) */ +#define EF_ZIPIT 0x2605 /* Thomas Brown's Macintosh (ZipIt) */ +#define EF_ZIPIT2 0x2705 /* T. Brown's Mac (ZipIt) v 1.3.8 and newer ? */ +#define EF_SMARTZIP 0x4d63 /* Mac SmartZip by Marco Bambini */ +#define EF_VMCMS 0x4704 /* Info-ZIP's VM/CMS ("\004G") */ +#define EF_MVS 0x470f /* Info-ZIP's MVS ("\017G") */ +#define EF_ACL 0x4c41 /* (OS/2) access control list ("AL") */ +#define EF_NTSD 0x4453 /* NT security descriptor ("SD") */ +#define EF_ATHEOS 0x7441 /* AtheOS ("At") */ +#define EF_BEOS 0x6542 /* BeOS ("Be") */ +#define EF_QDOS 0xfb4a /* SMS/QDOS ("J\373") */ +#define EF_AOSVS 0x5356 /* AOS/VS ("VS") */ +#define EF_SPARK 0x4341 /* David Pilling's Acorn/SparkFS ("AC") */ +#define EF_TANDEM 0x4154 /* Tandem NSK ("TA") */ +#define EF_THEOS 0x6854 /* Jean-Michel Dubois' Theos "Th" */ +#define EF_THEOSO 0x4854 /* old Theos port */ +#define EF_MD5 0x4b46 /* Fred Kantor's MD5 ("FK") */ +#define EF_ASIUNIX 0x756e /* ASi's Unix ("nu") */ + +#define EB_HEADSIZE 4 /* length of extra field block header */ +#define EB_ID 0 /* offset of block ID in header */ +#define EB_LEN 2 /* offset of data length field in header */ +#define EB_UCSIZE_P 0 /* offset of ucsize field in compr. data */ +#define EB_CMPRHEADLEN 6 /* lenght of compression header */ + +#define EB_UX_MINLEN 8 /* minimal "UX" field contains atime, mtime */ +#define EB_UX_FULLSIZE 12 /* full "UX" field (atime, mtime, uid, gid) */ +#define EB_UX_ATIME 0 /* offset of atime in "UX" extra field data */ +#define EB_UX_MTIME 4 /* offset of mtime in "UX" extra field data */ +#define EB_UX_UID 8 /* byte offset of UID in "UX" field data */ +#define EB_UX_GID 10 /* byte offset of GID in "UX" field data */ + +#define EB_UX2_MINLEN 4 /* minimal "Ux" field contains UID/GID */ +#define EB_UX2_UID 0 /* byte offset of UID in "Ux" field data */ +#define EB_UX2_GID 2 /* byte offset of GID in "Ux" field data */ +#define EB_UX2_VALID (1 << 8) /* UID/GID present */ + +#define EB_UX3_MINLEN 7 /* minimal "ux" field size (2-byte UID/GID) */ + +#define EB_UT_MINLEN 1 /* minimal UT field contains Flags byte */ +#define EB_UT_FLAGS 0 /* byte offset of Flags field */ +#define EB_UT_TIME1 1 /* byte offset of 1st time value */ +#define EB_UT_FL_MTIME (1 << 0) /* mtime present */ +#define EB_UT_FL_ATIME (1 << 1) /* atime present */ +#define EB_UT_FL_CTIME (1 << 2) /* ctime present */ + +#define EB_FLGS_OFFS 4 /* offset of flags area in generic compressed + extra field blocks (BEOS, MAC, and others) */ +#define EB_OS2_HLEN 4 /* size of OS2/ACL compressed data header */ +#define EB_BEOS_HLEN 5 /* length of BeOS&AtheOS e.f attribute header */ +#define EB_BE_FL_UNCMPR 0x01 /* "BeOS&AtheOS attribs uncompr." bit flag */ +#define EB_MAC3_HLEN 14 /* length of Mac3 attribute block header */ +#define EB_SMARTZIP_HLEN 64 /* fixed length of the SmartZip extra field */ +#define EB_M3_FL_DATFRK 0x01 /* "this entry is data fork" flag */ +#define EB_M3_FL_UNCMPR 0x04 /* "Mac3 attributes uncompressed" bit flag */ +#define EB_M3_FL_TIME64 0x08 /* "Mac3 time fields are 64 bit wide" flag */ +#define EB_M3_FL_NOUTC 0x10 /* "Mac3 timezone offset fields missing" flag */ + +#define EB_NTSD_C_LEN 4 /* length of central NT security data */ +#define EB_NTSD_L_LEN 5 /* length of minimal local NT security data */ +#define EB_NTSD_VERSION 4 /* offset of NTSD version byte */ +#define EB_NTSD_MAX_VER (0) /* maximum version # we know how to handle */ + +#define EB_PKVMS_MINLEN 4 /* minimum data length of PKVMS extra block */ + +#define EB_ASI_CRC32 0 /* offset of ASI Unix field's crc32 checksum */ +#define EB_ASI_MODE 4 /* offset of ASI Unix permission mode field */ + +#define EB_IZVMS_HLEN 12 /* length of IZVMS attribute block header */ +#define EB_IZVMS_FLGS 4 /* offset of compression type flag */ +#define EB_IZVMS_UCSIZ 6 /* offset of ucsize field in IZVMS header */ +#define EB_IZVMS_BCMASK 07 /* 3 bits for compression type */ +#define EB_IZVMS_BCSTOR 0 /* Stored */ +#define EB_IZVMS_BC00 1 /* 0byte -> 0bit compression */ +#define EB_IZVMS_BCDEFL 2 /* Deflated */ + + +/*--------------------------------------------------------------------------- + True sizes of the various headers (excluding their 4-byte signatures), + as defined by PKWARE--so it is not likely that these will ever change. + But if they do, make sure both these defines AND the typedefs below get + updated accordingly. + + 12/27/2006 + The Zip64 End Of Central Directory record is variable size and now + comes in two flavors, version 1 and the new version 2 that supports + central directory encryption. We only use the old fields at the + top of the Zip64 EOCDR, and this block is a fixed size still, but + need to be aware of the stuff following. + ---------------------------------------------------------------------------*/ +#define LREC_SIZE 26 /* lengths of local file headers, central */ +#define CREC_SIZE 42 /* directory headers, end-of-central-dir */ +#define ECREC_SIZE 18 /* record, zip64 end-of-cent-dir locator */ +#define ECLOC64_SIZE 16 /* and zip64 end-of-central-dir record, */ +#define ECREC64_SIZE 52 /* respectively */ + +#define MAX_BITS 13 /* used in unshrink() */ +#define HSIZE (1 << MAX_BITS) /* size of global work area */ + +#define LF 10 /* '\n' on ASCII machines; must be 10 due to EBCDIC */ +#define CR 13 /* '\r' on ASCII machines; must be 13 due to EBCDIC */ +#define CTRLZ 26 /* DOS & OS/2 EOF marker (used in fileio.c, vms.c) */ + +#ifdef EBCDIC +# define foreign(c) ascii[(uch)(c)] +# define native(c) ebcdic[(uch)(c)] +# define NATIVE "EBCDIC" +# define NOANSIFILT +#endif + +#ifdef VMS +# define ENV_UNZIP "UNZIP_OPTS" /* names of environment variables */ +# define ENV_ZIPINFO "ZIPINFO_OPTS" +#endif /* VMS */ +#ifdef RISCOS +# define ENV_UNZIP "Unzip$Options" +# define ENV_ZIPINFO "Zipinfo$Options" +# define ENV_UNZIPEXTS "Unzip$Exts" +#endif /* RISCOS */ +#ifndef ENV_UNZIP +# define ENV_UNZIP "UNZIP" /* the standard names */ +# define ENV_ZIPINFO "ZIPINFO" +#endif +#define ENV_UNZIP2 "UNZIPOPT" /* alternate names, for zip compat. */ +#define ENV_ZIPINFO2 "ZIPINFOOPT" + +#if (!defined(QQ) && !defined(NOQQ)) +# define QQ +#endif + +#ifdef QQ /* Newtware version: no file */ +# define QCOND (!uO.qflag) /* comments with -vq or -vqq */ +#else /* Bill Davidsen version: no way to */ +# define QCOND (longhdr) /* kill file comments when listing */ +#endif + +#ifdef OLD_QQ +# define QCOND2 (uO.qflag < 2) +#else +# define QCOND2 (!uO.qflag) +#endif + +#ifdef WILD_STOP_AT_DIR +# define __WDLPRO , int sepc +# define __WDL , sepc +# define __WDLDEF int sepc; +# define WISEP , (uO.W_flag ? '/' : '\0') +#else +# define __WDLPRO +# define __WDL +# define __WDLDEF +# define WISEP +#endif + + + + +/**************/ +/* Typedefs */ +/**************/ + +#ifdef ZIP64_SUPPORT +# ifndef Z_UINT8_DEFINED +# if (defined(__GNUC__) || defined(__hpux) || defined(__SUNPRO_C)) + typedef unsigned long long z_uint8; +# else + typedef unsigned __int64 z_uint8; +# endif +# define Z_UINT8_DEFINED +# endif +#endif +#ifndef Z_UINT4_DEFINED +# if (defined(MODERN) && !defined(NO_LIMITS_H)) +# if (defined(UINT_MAX) && (UINT_MAX == 0xffffffffUL)) + typedef unsigned int z_uint4; +# define Z_UINT4_DEFINED +# else +# if (defined(ULONG_MAX) && (ULONG_MAX == 0xffffffffUL)) + typedef unsigned long z_uint4; +# define Z_UINT4_DEFINED +# else +# if (defined(USHRT_MAX) && (USHRT_MAX == 0xffffffffUL)) + typedef unsigned short z_uint4; +# define Z_UINT4_DEFINED +# endif +# endif +# endif +# endif /* MODERN && !NO_LIMITS_H */ +#endif /* !Z_UINT4_DEFINED */ +#ifndef Z_UINT4_DEFINED + typedef ulg z_uint4; +# define Z_UINT4_DEFINED +#endif + +/* The following three user-defined unsigned integer types are used for + holding zipfile entities (required widths without / with Zip64 support): + a) sizes and offset of zipfile entries + (4 bytes / 8 bytes) + b) enumeration and counts of zipfile entries + (2 bytes / 8 bytes) + Remark: internally, we use 4 bytes for archive member counting in the + No-Zip64 case, because UnZip supports more than 64k entries for + classic Zip archives without Zip64 extensions. + c) enumeration and counts of zipfile volumes of multivolume archives + (2 bytes / 4 bytes) + */ +#ifdef ZIP64_SUPPORT + typedef z_uint8 zusz_t; /* zipentry sizes & offsets */ + typedef z_uint8 zucn_t; /* archive entry counts */ + typedef z_uint4 zuvl_t; /* multivolume numbers */ +# define MASK_ZUCN64 (~(zucn_t)0) +/* In case we ever get to support an environment where z_uint8 may be WIDER + than 64 bit wide, we will have to apply a construct similar to + #define MASK_ZUCN64 (~(zucn_t)0 & (zucn_t)0xffffffffffffffffULL) + for the 64-bit mask. + */ +#else + typedef ulg zusz_t; /* zipentry sizes & offsets */ + typedef unsigned int zucn_t; /* archive entry counts */ + typedef unsigned short zuvl_t; /* multivolume numbers */ +# define MASK_ZUCN64 (~(zucn_t)0) +#endif +#define MASK_ZUCN16 ((zucn_t)0xFFFF) + +#ifdef NO_UID_GID +# ifdef UID_USHORT + typedef unsigned short uid_t; /* TI SysV.3 */ + typedef unsigned short gid_t; +# else + typedef unsigned int uid_t; /* SCO Xenix */ + typedef unsigned int gid_t; +# endif +#endif + +#if (defined(GOT_UTIMBUF) || defined(sgi) || defined(ATARI)) + typedef struct utimbuf ztimbuf; +#else + typedef struct ztimbuf { + time_t actime; /* new access time */ + time_t modtime; /* new modification time */ + } ztimbuf; +#endif + +typedef struct iztimes { + time_t atime; /* new access time */ + time_t mtime; /* new modification time */ + time_t ctime; /* used for creation time; NOT same as st_ctime */ +} iztimes; + +#ifdef SET_DIR_ATTRIB + typedef struct direntry { /* head of system-specific struct holding */ + struct direntry *next; /* defered directory attributes info */ + char *fn; /* filename of directory */ + char buf[1]; /* start of system-specific internal data */ + } direntry; +#endif /* SET_DIR_ATTRIB */ + +#ifdef SYMLINKS + typedef struct slinkentry { /* info for deferred symlink creation */ + struct slinkentry *next; /* pointer to next entry in chain */ + extent targetlen; /* length of target filespec */ + extent attriblen; /* length of system-specific attrib data */ + char *target; /* pointer to target filespec */ + char *fname; /* pointer to name of link */ + char buf[1]; /* data/name/link buffer */ + } slinkentry; +#endif /* SYMLINKS */ + +typedef struct min_info { + zoff_t offset; + zusz_t compr_size; /* compressed size (needed if extended header) */ + zusz_t uncompr_size; /* uncompressed size (needed if extended header) */ + ulg crc; /* crc (needed if extended header) */ + zuvl_t diskstart; /* no of volume where this entry starts */ + uch hostver; + uch hostnum; + unsigned file_attr; /* local flavor, as used by creat(), chmod()... */ + unsigned encrypted : 1; /* file encrypted: decrypt before uncompressing */ + unsigned ExtLocHdr : 1; /* use time instead of CRC for decrypt check */ + unsigned textfile : 1; /* file is text (according to zip) */ + unsigned textmode : 1; /* file is to be extracted as text */ + unsigned lcflag : 1; /* convert filename to lowercase */ + unsigned vollabel : 1; /* "file" is an MS-DOS volume (disk) label */ +#ifdef SYMLINKS + unsigned symlink : 1; /* file is a symbolic link */ +#endif + unsigned HasUxAtt : 1; /* crec ext_file_attr has Unix style mode bits */ +#ifdef UNICODE_SUPPORT + unsigned GPFIsUTF8: 1; /* crec gen_purpose_flag UTF-8 bit 11 is set */ +#endif +#ifndef SFX + char Far *cfilname; /* central header version of filename */ +#endif +} min_info; + +typedef struct VMStimbuf { + char *revdate; /* (both roughly correspond to Unix modtime/st_mtime) */ + char *credate; +} VMStimbuf; + +/*--------------------------------------------------------------------------- + Zipfile work area declarations. + ---------------------------------------------------------------------------*/ + +#ifdef MALLOC_WORK + union work { + struct { /* unshrink(): */ + shrint *Parent; /* pointer to (8192 * sizeof(shrint)) */ + uch *value; /* pointer to 8KB char buffer */ + uch *Stack; /* pointer to another 8KB char buffer */ + } shrink; + uch *Slide; /* explode(), inflate(), unreduce() */ + }; +#else /* !MALLOC_WORK */ + union work { + struct { /* unshrink(): */ + shrint Parent[HSIZE]; /* (8192 * sizeof(shrint)) == 16KB minimum */ + uch value[HSIZE]; /* 8KB */ + uch Stack[HSIZE]; /* 8KB */ + } shrink; /* total = 32KB minimum; 80KB on Cray/Alpha */ + uch Slide[WSIZE]; /* explode(), inflate(), unreduce() */ + }; +#endif /* ?MALLOC_WORK */ + +#define slide G.area.Slide + +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) +# define redirSlide G.redirect_sldptr +#else +# define redirSlide G.area.Slide +#endif + +/*--------------------------------------------------------------------------- + Zipfile layout declarations. If these headers ever change, make sure the + xxREC_SIZE defines (above) change with them! + ---------------------------------------------------------------------------*/ + + typedef uch local_byte_hdr[ LREC_SIZE ]; +# define L_VERSION_NEEDED_TO_EXTRACT_0 0 +# define L_VERSION_NEEDED_TO_EXTRACT_1 1 +# define L_GENERAL_PURPOSE_BIT_FLAG 2 +# define L_COMPRESSION_METHOD 4 +# define L_LAST_MOD_DOS_DATETIME 6 +# define L_CRC32 10 +# define L_COMPRESSED_SIZE 14 +# define L_UNCOMPRESSED_SIZE 18 +# define L_FILENAME_LENGTH 22 +# define L_EXTRA_FIELD_LENGTH 24 + + typedef uch cdir_byte_hdr[ CREC_SIZE ]; +# define C_VERSION_MADE_BY_0 0 +# define C_VERSION_MADE_BY_1 1 +# define C_VERSION_NEEDED_TO_EXTRACT_0 2 +# define C_VERSION_NEEDED_TO_EXTRACT_1 3 +# define C_GENERAL_PURPOSE_BIT_FLAG 4 +# define C_COMPRESSION_METHOD 6 +# define C_LAST_MOD_DOS_DATETIME 8 +# define C_CRC32 12 +# define C_COMPRESSED_SIZE 16 +# define C_UNCOMPRESSED_SIZE 20 +# define C_FILENAME_LENGTH 24 +# define C_EXTRA_FIELD_LENGTH 26 +# define C_FILE_COMMENT_LENGTH 28 +# define C_DISK_NUMBER_START 30 +# define C_INTERNAL_FILE_ATTRIBUTES 32 +# define C_EXTERNAL_FILE_ATTRIBUTES 34 +# define C_RELATIVE_OFFSET_LOCAL_HEADER 38 + + typedef uch ec_byte_rec[ ECREC_SIZE+4 ]; +/* define SIGNATURE 0 space-holder only */ +# define NUMBER_THIS_DISK 4 +# define NUM_DISK_WITH_START_CEN_DIR 6 +# define NUM_ENTRIES_CEN_DIR_THS_DISK 8 +# define TOTAL_ENTRIES_CENTRAL_DIR 10 +# define SIZE_CENTRAL_DIRECTORY 12 +# define OFFSET_START_CENTRAL_DIRECTORY 16 +# define ZIPFILE_COMMENT_LENGTH 20 + + typedef uch ec_byte_loc64[ ECLOC64_SIZE+4 ]; +# define NUM_DISK_START_EOCDR64 4 +# define OFFSET_START_EOCDR64 8 +# define NUM_THIS_DISK_LOC64 16 + + typedef uch ec_byte_rec64[ ECREC64_SIZE+4 ]; +# define ECREC64_LENGTH 4 +# define EC_VERSION_MADE_BY_0 12 +# define EC_VERSION_NEEDED_0 14 +# define NUMBER_THIS_DSK_REC64 16 +# define NUM_DISK_START_CEN_DIR64 20 +# define NUM_ENTRIES_CEN_DIR_THS_DISK64 24 +# define TOTAL_ENTRIES_CENTRAL_DIR64 32 +# define SIZE_CENTRAL_DIRECTORY64 40 +# define OFFSET_START_CENTRAL_DIRECT64 48 + + +/* The following structs are used to hold all header data of a zip entry. + Traditionally, the structs' layouts followed the data layout of the + corresponding zipfile header structures. However, the zipfile header + layouts were designed in the old ages of 16-bit CPUs, they are subject + to structure padding and/or alignment issues on newer systems with a + "natural word width" of more than 2 bytes. + Please note that the structure members are now reordered by size + (top-down), to prevent internal padding and optimize memory usage! + */ + typedef struct local_file_header { /* LOCAL */ + zusz_t csize; + zusz_t ucsize; + ulg last_mod_dos_datetime; + ulg crc32; + uch version_needed_to_extract[2]; + ush general_purpose_bit_flag; + ush compression_method; + ush filename_length; + ush extra_field_length; + } local_file_hdr; + + typedef struct central_directory_file_header { /* CENTRAL */ + zusz_t csize; + zusz_t ucsize; + zusz_t relative_offset_local_header; + ulg last_mod_dos_datetime; + ulg crc32; + ulg external_file_attributes; + zuvl_t disk_number_start; + ush internal_file_attributes; + uch version_made_by[2]; + uch version_needed_to_extract[2]; + ush general_purpose_bit_flag; + ush compression_method; + ush filename_length; + ush extra_field_length; + ush file_comment_length; + } cdir_file_hdr; + + typedef struct end_central_dir_record { /* END CENTRAL */ + zusz_t size_central_directory; + zusz_t offset_start_central_directory; + zucn_t num_entries_centrl_dir_ths_disk; + zucn_t total_entries_central_dir; + zuvl_t number_this_disk; + zuvl_t num_disk_start_cdir; + int have_ecr64; /* valid Zip64 ecdir-record exists */ + int is_zip64_archive; /* Zip64 ecdir-record is mandatory */ + ush zipfile_comment_length; + } ecdir_rec; + + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). + Valid extra bits are 0..16. e == 31 is EOB (end of block), e == 32 + means that v is a literal, 32 < e < 64 means that v is a pointer to + the next table, which codes (e & 31) bits, and lastly e == 99 indicates + an unused code. If a code with e == 99 is looked up, this implies an + error in the data. */ + +struct huft { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } v; +}; + + +typedef struct _APIDocStruct { + char *compare; + char *function; + char *syntax; + char *purpose; +} APIDocStruct; + + + + +/*************/ +/* Globals */ +/*************/ + +#if (defined(OS2) && !defined(FUNZIP)) +# include "os2/os2data.h" +#endif + +#include "globals.h" + + + +/*************************/ +/* Function Prototypes */ +/*************************/ + +/*--------------------------------------------------------------------------- + Functions in unzip.c (initialization routines): + ---------------------------------------------------------------------------*/ + +#ifndef WINDLL + int MAIN OF((int argc, char **argv)); + int unzip OF((__GPRO__ int argc, char **argv)); + int uz_opts OF((__GPRO__ int *pargc, char ***pargv)); + int usage OF((__GPRO__ int error)); +#endif /* !WINDLL */ + +/*--------------------------------------------------------------------------- + Functions in process.c (main driver routines): + ---------------------------------------------------------------------------*/ + +int process_zipfiles OF((__GPRO)); +void free_G_buffers OF((__GPRO)); +/* static int do_seekable OF((__GPRO__ int lastchance)); */ +/* static int find_ecrec OF((__GPRO__ long searchlen)); */ +/* static int process_central_comment OF((__GPRO)); */ +int process_cdir_file_hdr OF((__GPRO)); +int process_local_file_hdr OF((__GPRO)); +int getZip64Data OF((__GPRO__ ZCONST uch *ef_buf, + unsigned ef_len)); +#ifdef UNICODE_SUPPORT + int getUnicodeData OF((__GPRO__ ZCONST uch *ef_buf, + unsigned ef_len)); +#endif +unsigned ef_scan_for_izux OF((ZCONST uch *ef_buf, unsigned ef_len, + int ef_is_c, ulg dos_mdatetime, + iztimes *z_utim, ulg *z_uidgid)); +#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) + zvoid *getRISCOSexfield OF((ZCONST uch *ef_buf, unsigned ef_len)); +#endif + +#ifndef SFX + +/*--------------------------------------------------------------------------- + Functions in zipinfo.c (`zipinfo-style' listing routines): + ---------------------------------------------------------------------------*/ + +#ifndef NO_ZIPINFO +#ifndef WINDLL + int zi_opts OF((__GPRO__ int *pargc, char ***pargv)); +#endif +void zi_end_central OF((__GPRO)); +int zipinfo OF((__GPRO)); +/* static int zi_long OF((__GPRO__ zusz_t *pEndprev)); */ +/* static int zi_short OF((__GPRO)); */ +/* static char *zi_time OF((__GPRO__ ZCONST ulg *datetimez, + ZCONST time_t *modtimez, char *d_t_str));*/ +#endif /* !NO_ZIPINFO */ + +/*--------------------------------------------------------------------------- + Functions in list.c (generic zipfile-listing routines): + ---------------------------------------------------------------------------*/ + +int list_files OF((__GPRO)); +#ifdef TIMESTAMP + int get_time_stamp OF((__GPRO__ time_t *last_modtime, + ulg *nmember)); +#endif +int ratio OF((zusz_t uc, zusz_t c)); +void fnprint OF((__GPRO)); + +#endif /* !SFX */ + +/*--------------------------------------------------------------------------- + Functions in fileio.c: + ---------------------------------------------------------------------------*/ + +int open_input_file OF((__GPRO)); +int open_outfile OF((__GPRO)); /* also vms.c */ +void undefer_input OF((__GPRO)); +void defer_leftover_input OF((__GPRO)); +unsigned readbuf OF((__GPRO__ char *buf, register unsigned len)); +int readbyte OF((__GPRO)); +int fillinbuf OF((__GPRO)); +int seek_zipf OF((__GPRO__ zoff_t abs_offset)); +#ifdef FUNZIP + int flush OF((__GPRO__ ulg size)); /* actually funzip.c */ +#else + int flush OF((__GPRO__ uch *buf, ulg size, int unshrink)); +#endif +/* static int disk_error OF((__GPRO)); */ +void handler OF((int signal)); +time_t dos_to_unix_time OF((ulg dos_datetime)); +int check_for_newer OF((__GPRO__ char *filename)); /* os2,vmcms,vms */ +int do_string OF((__GPRO__ unsigned int length, int option)); +ush makeword OF((ZCONST uch *b)); +ulg makelong OF((ZCONST uch *sig)); +zusz_t makeint64 OF((ZCONST uch *sig)); +char *fzofft OF((__GPRO__ zoff_t val, + ZCONST char *pre, ZCONST char *post)); +#if (!defined(STR_TO_ISO) || defined(NEED_STR2ISO)) + char *str2iso OF((char *dst, ZCONST char *src)); +#endif +#if (!defined(STR_TO_OEM) || defined(NEED_STR2OEM)) + char *str2oem OF((char *dst, ZCONST char *src)); +#endif +#ifdef NO_STRNICMP + int zstrnicmp OF((register ZCONST char *s1, + register ZCONST char *s2, + register unsigned n)); +#endif +#ifdef REGULUS + int zstat OF((ZCONST char *p, struct stat *s)); +#endif +#ifdef ZMEM /* MUST be ifdef'd because of conflicts with the standard def. */ + zvoid *memset OF((register zvoid *, register int, register unsigned int)); + int memcmp OF((register ZCONST zvoid*, register ZCONST zvoid *, + register unsigned int)); + zvoid *memcpy OF((register zvoid *, register ZCONST zvoid *, + register unsigned int)); +#endif +#ifdef NEED_UZMBCLEN + extent uzmbclen OF((ZCONST unsigned char *ptr)); +#endif +#ifdef NEED_UZMBSCHR + unsigned char *uzmbschr OF((ZCONST unsigned char *str, unsigned int c)); +#endif +#ifdef NEED_UZMBSRCHR + unsigned char *uzmbsrchr OF((ZCONST unsigned char *str, unsigned int c)); +#endif +#ifdef SMALL_MEM + char *fLoadFarString OF((__GPRO__ const char Far *sz)); + char *fLoadFarStringSmall OF((__GPRO__ const char Far *sz)); + char *fLoadFarStringSmall2 OF((__GPRO__ const char Far *sz)); + #ifndef zfstrcpy + char Far * Far zfstrcpy OF((char Far *s1, const char Far *s2)); + #endif + #if (!defined(SFX) && !defined(zfstrcmp)) + int Far zfstrcmp OF((const char Far *s1, const char Far *s2)); + #endif +#endif + + +/*--------------------------------------------------------------------------- + Functions in extract.c: + ---------------------------------------------------------------------------*/ + +int extract_or_test_files OF((__GPRO)); +/* static int store_info OF((void)); */ +/* static int extract_or_test_member OF((__GPRO)); */ +/* static int TestExtraField OF((__GPRO__ uch *ef, unsigned ef_len)); */ +/* static int test_OS2 OF((__GPRO__ uch *eb, unsigned eb_size)); */ +/* static int test_NT OF((__GPRO__ uch *eb, unsigned eb_size)); */ +#ifndef SFX + unsigned find_compr_idx OF((unsigned compr_methodnum)); +#endif +int memextract OF((__GPRO__ uch *tgt, ulg tgtsize, + ZCONST uch *src, ulg srcsize)); +int memflush OF((__GPRO__ ZCONST uch *rawbuf, ulg size)); +#if (defined(VMS) || defined(VMS_TEXT_CONV)) + uch *extract_izvms_block OF((__GPRO__ ZCONST uch *ebdata, + unsigned size, unsigned *retlen, + ZCONST uch *init, unsigned needlen)); +#endif +char *fnfilter OF((ZCONST char *raw, uch *space, + extent size)); + +/*--------------------------------------------------------------------------- + Decompression functions: + ---------------------------------------------------------------------------*/ + +#if (!defined(SFX) && !defined(FUNZIP)) +int explode OF((__GPRO)); /* explode.c */ +#endif +int huft_free OF((struct huft *t)); /* inflate.c */ +int huft_build OF((__GPRO__ ZCONST unsigned *b, unsigned n, + unsigned s, ZCONST ush *d, ZCONST uch *e, + struct huft **t, unsigned *m)); +#ifdef USE_ZLIB + int UZinflate OF((__GPRO__ int is_defl64)); /* inflate.c */ +# define inflate_free(x) inflateEnd(&((Uz_Globs *)(&G))->dstrm) +#else + int inflate OF((__GPRO__ int is_defl64)); /* inflate.c */ + int inflate_free OF((__GPRO)); /* inflate.c */ +#endif /* ?USE_ZLIB */ +#if (!defined(SFX) && !defined(FUNZIP)) +#ifndef COPYRIGHT_CLEAN + int unreduce OF((__GPRO)); /* unreduce.c */ +/* static void LoadFollowers OF((__GPRO__ f_array *follower, uch *Slen)); + * unreduce.c */ +#endif /* !COPYRIGHT_CLEAN */ +#ifndef LZW_CLEAN + int unshrink OF((__GPRO)); /* unshrink.c */ +/* static void partial_clear OF((__GPRO)); * unshrink.c */ +#endif /* !LZW_CLEAN */ +#endif /* !SFX && !FUNZIP */ +#ifdef USE_BZIP2 + int UZbunzip2 OF((__GPRO)); /* extract.c */ + void bz_internal_error OF((int bzerrcode)); /* ubz2err.c */ +#endif + +/*--------------------------------------------------------------------------- + Internal API functions (only included in DLL versions): + ---------------------------------------------------------------------------*/ + +#ifdef DLL + void setFileNotFound OF((__GPRO)); /* api.c */ + int unzipToMemory OF((__GPRO__ char *zip, char *file, + UzpBuffer *retstr)); /* api.c */ + int redirect_outfile OF((__GPRO)); /* api.c */ + int writeToMemory OF((__GPRO__ ZCONST uch *rawbuf, + extent size)); /* api.c */ + int close_redirect OF((__GPRO)); /* api.c */ + /* this obsolescent entry point kept for compatibility: */ + int UzpUnzip OF((int argc, char **argv));/* use UzpMain */ +#ifdef OS2DLL + int varmessage OF((__GPRO__ ZCONST uch *buf, ulg size)); + int varputchar OF((__GPRO__ int c)); /* rexxapi.c */ + int finish_REXX_redirect OF((__GPRO)); /* rexxapi.c */ +#endif +#ifdef API_DOC + void APIhelp OF((__GPRO__ int argc, char **argv)); +#endif /* apihelp.c */ +#endif /* DLL */ + +/*--------------------------------------------------------------------------- + MSDOS-only functions: + ---------------------------------------------------------------------------*/ + +#ifdef MSDOS +#if (!defined(FUNZIP) && !defined(SFX) && !defined(WINDLL)) + void check_for_windows OF((ZCONST char *app)); /* msdos.c */ +#endif +#if (defined(__GO32__) || defined(__EMX__)) + unsigned _dos_getcountryinfo(void *); /* msdos.c */ +#if (!defined(__DJGPP__) || (__DJGPP__ < 2)) + unsigned _dos_setftime(int, unsigned, unsigned); /* msdos.c */ + unsigned _dos_setfileattr(const char *, unsigned); /* msdos.c */ + unsigned _dos_creat(const char *, unsigned, int *); /* msdos.c */ + void _dos_getdrive(unsigned *); /* msdos.c */ + unsigned _dos_close(int); /* msdos.c */ +#endif /* !__DJGPP__ || (__DJGPP__ < 2) */ +#endif /* __GO32__ || __EMX__ */ +#endif + +/*--------------------------------------------------------------------------- + OS/2-only functions: + ---------------------------------------------------------------------------*/ + +#ifdef OS2 /* GetFileTime conflicts with something in Win32 header files */ +#if (defined(REENTRANT) && defined(USETHREADID)) + ulg GetThreadId OF((void)); +#endif + int GetCountryInfo OF((void)); /* os2.c */ + long GetFileTime OF((ZCONST char *name)); /* os2.c */ +/* static void SetPathAttrTimes OF((__GPRO__ int flags, int dir)); os2.c */ +/* static int SetEAs OF((__GPRO__ const char *path, + void *eablock)); os2.c */ +/* static int SetACL OF((__GPRO__ const char *path, + void *eablock)); os2.c */ +/* static int IsFileNameValid OF((const char *name)); os2.c */ +/* static void map2fat OF((char *pathcomp, char **pEndFAT)); os2.c */ +/* static int SetLongNameEA OF((char *name, char *longname)); os2.c */ +/* static void InitNLS OF((void)); os2.c */ + int IsUpperNLS OF((int nChr)); /* os2.c */ + int ToLowerNLS OF((int nChr)); /* os2.c */ + void DebugMalloc OF((void)); /* os2.c */ +#endif + +/*--------------------------------------------------------------------------- + QDOS-only functions: + ---------------------------------------------------------------------------*/ + +#ifdef QDOS + int QMatch (uch, uch); + void QFilename (__GPRO__ char *); + char *Qstrfix (char *); + int QReturn (int zip_error); +#endif + +/*--------------------------------------------------------------------------- + TOPS20-only functions: + ---------------------------------------------------------------------------*/ + +#ifdef TOPS20 + int upper OF((char *s)); /* tops20.c */ + int enquote OF((char *s)); /* tops20.c */ + int dequote OF((char *s)); /* tops20.c */ + int fnlegal OF(()); /* error if prototyped? */ /* tops20.c */ +#endif + +/*--------------------------------------------------------------------------- + VM/CMS- and MVS-only functions: + ---------------------------------------------------------------------------*/ + +#ifdef CMS_MVS + extent getVMMVSexfield OF((char *type, uch *ef_block, unsigned datalen)); + FILE *vmmvs_open_infile OF((__GPRO)); /* vmmvs.c */ + void close_infile OF((__GPRO)); /* vmmvs.c */ +#endif + +/*--------------------------------------------------------------------------- + VMS-only functions: + ---------------------------------------------------------------------------*/ + +#ifdef VMS + int check_format OF((__GPRO)); /* vms.c */ +/* int open_outfile OF((__GPRO)); * (see fileio.c) vms.c */ +/* int flush OF((__GPRO__ uch *rawbuf, unsigned size, + int final_flag)); * (see fileio.c) vms.c */ + char *vms_msg_text OF((void)); /* vms.c */ +#ifdef RETURN_CODES + void return_VMS OF((__GPRO__ int zip_error)); /* vms.c */ +#else + void return_VMS OF((int zip_error)); /* vms.c */ +#endif +#ifdef VMSCLI + ulg vms_unzip_cmdline OF((int *, char ***)); /* cmdline.c */ + int VMSCLI_usage OF((__GPRO__ int error)); /* cmdline.c */ +#endif +#endif + +/*--------------------------------------------------------------------------- + WIN32-only functions: + ---------------------------------------------------------------------------*/ + +#ifdef WIN32 + int IsWinNT OF((void)); /* win32.c */ +#ifdef NTSD_EAS + void process_defer_NT OF((__GPRO)); /* win32.c */ + int test_NTSD OF((__GPRO__ uch *eb, unsigned eb_size, + uch *eb_ucptr, ulg eb_ucsize)); /* win32.c */ +# define TEST_NTSD test_NTSD +#endif +#ifdef W32_STAT_BANDAID + int zstat_win32 OF((__W32STAT_GLOBALS__ + const char *path, z_stat *buf)); /* win32.c */ +#endif +#endif + +/*--------------------------------------------------------------------------- + Miscellaneous/shared functions: + ---------------------------------------------------------------------------*/ + +Uz_Globs *globalsCtor OF((void)); /* globals.c */ + +int envargs OF((int *Pargc, char ***Pargv, + ZCONST char *envstr, ZCONST char *envstr2)); + /* envargs.c */ +void mksargs OF((int *argcp, char ***argvp)); /* envargs.c */ + +int match OF((ZCONST char *s, ZCONST char *p, + int ic __WDLPRO)); /* match.c */ +int iswild OF((ZCONST char *p)); /* match.c */ + +/* declarations of public CRC-32 functions have been moved into crc32.h + (free_crc_table(), get_crc_table(), crc32()) crc32.c */ + +int dateformat OF((void)); /* local */ +char dateseparator OF((void)); /* local */ +#ifndef WINDLL + void version OF((__GPRO)); /* local */ +#endif +int mapattr OF((__GPRO)); /* local */ +int mapname OF((__GPRO__ int renamed)); /* local */ +int checkdir OF((__GPRO__ char *pathcomp, int flag)); /* local */ +char *do_wild OF((__GPRO__ ZCONST char *wildzipfn)); /* local */ +char *GetLoadPath OF((__GPRO)); /* local */ +#if (defined(MORE) && (defined(ATH_BEO_UNX) || defined(QDOS) || defined(VMS))) + int screensize OF((int *tt_rows, int *tt_cols)); /* local */ +# if defined(VMS) + int screenlinewrap OF((void)); /* local */ +# endif +#endif /* MORE && (ATH_BEO_UNX || QDOS || VMS) */ +#ifdef OS2_W32 + int SetFileSize OF((FILE *file, zusz_t filesize)); /* local */ +#endif +#ifndef MTS /* macro in MTS */ + int close_outfile OF((__GPRO)); /* local */ +#endif +#ifdef SET_SYMLINK_ATTRIBS + int set_symlnk_attribs OF((__GPRO__ slinkentry *slnk_entry)); /* local */ +#endif +#ifdef SET_DIR_ATTRIB + int defer_dir_attribs OF((__GPRO__ direntry **pd)); /* local */ + int set_direc_attribs OF((__GPRO__ direntry *d)); /* local */ +#endif +#ifdef TIMESTAMP +# ifdef WIN32 + int stamp_file OF((__GPRO__ + ZCONST char *fname, time_t modtime)); /* local */ +# else + int stamp_file OF((ZCONST char *fname, time_t modtime)); /* local */ +# endif +#endif +#ifdef NEED_ISO_OEM_INIT + void prepare_ISO_OEM_translat OF((__GPRO)); /* local */ +#endif +#if (defined(MALLOC_WORK) && defined(MY_ZCALLOC)) + zvoid far *zcalloc OF((unsigned int, unsigned int)); + zvoid zcfree OF((zvoid far *)); +#endif /* MALLOC_WORK && MY_ZCALLOC */ +#ifdef SYSTEM_SPECIFIC_CTOR + void SYSTEM_SPECIFIC_CTOR OF((__GPRO)); /* local */ +#endif +#ifdef SYSTEM_SPECIFIC_DTOR + void SYSTEM_SPECIFIC_DTOR OF((__GPRO)); /* local */ +#endif + + + + + +/************/ +/* Macros */ +/************/ + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifdef DEBUG +# if (defined(THEOS) && defined(NO_BOGUS_SPC)) +# define NO_DEBUG_IN_MACROS +# define Trace(x) _fprintf x +# else +# define Trace(x) fprintf x +# endif +#else +# define Trace(x) +#endif + +#ifdef DEBUG_TIME +# define TTrace(x) fprintf x +#else +# define TTrace(x) +#endif + +#ifdef NO_DEBUG_IN_MACROS +# define MTrace(x) +#else +# define MTrace(x) Trace(x) +#endif + +#if (defined(UNIX) || defined(T20_VMS)) /* generally old systems */ +# define ToLower(x) ((char)(isupper((int)x)? tolower((int)x) : x)) +#else +# define ToLower tolower /* assumed "smart"; used in match() */ +#endif + +#ifdef USE_STRM_INPUT + /* ``Replace'' the unbuffered UNIX style I/O function with similar + * standard C functions from . + */ +# define read(fd,buf,n) fread((buf),1,(n),(FILE *)(fd)) +# ifdef zlseek +# undef zlseek +# endif +# define zlseek(fd,o,w) zfseeko((FILE *)(fd),(o),(w)) +# define close(fd) fclose((FILE *)(fd)) +#endif /* USE_STRM_INPUT */ + +/* The return value of the Info() "macro function" is never checked in + * UnZip. Otherwise, to get the same behaviour as for (*G.message)(), the + * Info() definition for "FUNZIP" would have to be corrected: + * #define Info(buf,flag,sprf_arg) \ + * (fputs((char *)(sprintf sprf_arg, (buf)), \ + * (flag)&1? stderr : stdout) < 0) + */ +#ifndef Info /* may already have been defined for redirection */ +# ifdef FUNZIP +# define Info(buf,flag,sprf_arg) \ + fputs((char *)(sprintf sprf_arg, (buf)), (flag)&1? stderr : stdout) +# else +# ifdef INT_SPRINTF /* optimized version for "int sprintf()" flavour */ +# define Info(buf,flag,sprf_arg) \ + (*G.message)((zvoid *)&G, (uch *)(buf), (ulg)sprintf sprf_arg, (flag)) +# else /* generic version, does not use sprintf() return value */ +# define Info(buf,flag,sprf_arg) \ + (*G.message)((zvoid *)&G, (uch *)(buf), \ + (ulg)(sprintf sprf_arg, strlen((char *)(buf))), (flag)) +# endif +# endif +#endif /* !Info */ + +/* This wrapper macro around fzofft() is just defined to "hide" the + * argument needed to reference the global storage buffers. + */ +#define FmZofft(val, pre, post) fzofft(__G__ val, pre, post) + +/* The following macro wrappers around the fnfilter function are used many + * times to prepare archive entry names or name components for displaying + * listings and (warning/error) messages. They use sections in the upper half + * of 'slide' as buffer, since their output is normally fed through the + * Info() macro with 'slide' (the start of this area) as message buffer. + */ +#define FnFilter1(fname) \ + fnfilter((fname), slide + (extent)(WSIZE>>1), (extent)(WSIZE>>2)) +#define FnFilter2(fname) \ + fnfilter((fname), slide + (extent)((WSIZE>>1) + (WSIZE>>2)),\ + (extent)(WSIZE>>2)) + +#ifndef FUNZIP /* used only in inflate.c */ +# define MESSAGE(str,len,flag) (*G.message)((zvoid *)&G,(str),(len),(flag)) +#endif + +#if 0 /* Optimization: use the (const) result of crc32(0L,NULL,0) */ +# define CRCVAL_INITIAL crc32(0L, NULL, 0) +#else +# define CRCVAL_INITIAL 0L +#endif + +#ifdef SYMLINKS + /* This macro defines the Zip "made by" hosts that are considered + to support storing symbolic link entries. */ +# define SYMLINK_HOST(hn) ((hn) == UNIX_ || (hn) == ATARI_ || \ + (hn) == ATHEOS_ || (hn) == BEOS_ || (hn) == VMS_) +#endif + +#ifndef TEST_NTSD /* "NTSD valid?" checking function */ +# define TEST_NTSD NULL /* ... is not available */ +#endif + +#define SKIP_(length) if(length&&((error=do_string(__G__ length,SKIP))!=0))\ + {error_in_archive=error; if(error>1) return error;} + +/* + * Skip a variable-length field, and report any errors. Used in zipinfo.c + * and unzip.c in several functions. + * + * macro SKIP_(length) + * ush length; + * { + * if (length && ((error = do_string(length, SKIP)) != 0)) { + * error_in_archive = error; /-* might be warning *-/ + * if (error > 1) /-* fatal *-/ + * return (error); + * } + * } + * + */ + + +#ifdef FUNZIP +# define FLUSH(w) flush(__G__ (ulg)(w)) +# define NEXTBYTE getc(G.in) /* redefined in crypt.h if full version */ +#else +# define FLUSH(w) ((G.mem_mode) ? memflush(__G__ redirSlide,(ulg)(w)) \ + : flush(__G__ redirSlide,(ulg)(w),0)) +# define NEXTBYTE (G.incnt-- > 0 ? (int)(*G.inptr++) : readbyte(__G)) +#endif + + +#define READBITS(nbits,zdest) {if(nbits>G.bits_left) {int temp; G.zipeof=1;\ + while (G.bits_left<=8*(int)(sizeof(G.bitbuf)-1) && (temp=NEXTBYTE)!=EOF) {\ + G.bitbuf|=(ulg)temp<>=nbits;\ + G.bits_left-=nbits;} + +/* + * macro READBITS(nbits,zdest) * only used by unreduce and unshrink * + * { + * if (nbits > G.bits_left) { * fill G.bitbuf, 8*sizeof(ulg) bits * + * int temp; + * + * G.zipeof = 1; + * while (G.bits_left <= 8*(int)(sizeof(G.bitbuf)-1) && + * (temp = NEXTBYTE) != EOF) { + * G.bitbuf |= (ulg)temp << G.bits_left; + * G.bits_left += 8; + * G.zipeof = 0; + * } + * } + * zdest = (shrint)((unsigned)G.bitbuf & mask_bits[nbits]); + * G.bitbuf >>= nbits; + * G.bits_left -= nbits; + * } + * + */ + + +/* GRR: should use StringLower for STRLOWER macro if possible */ + +/* + * Copy the zero-terminated string in str1 into str2, converting any + * uppercase letters to lowercase as we go. str2 gets zero-terminated + * as well, of course. str1 and str2 may be the same character array. + */ +#ifdef _MBCS +# define STRLOWER(str1, str2) \ + { \ + char *p, *q, c; unsigned i; \ + p = (char *)(str1); \ + q = (char *)(str2); \ + while ((c = *p) != '\0') { \ + if ((i = CLEN(p)) > 1) { \ + while (i--) *q++ = *p++; \ + } else { \ + *q++ = (char)(isupper((int)(c))? tolower((int)(c)) : c); \ + p++; \ + } \ + } \ + *q = '\0'; \ + } +#else +# define STRLOWER(str1, str2) \ + { \ + char *p, *q; \ + p = (char *)(str1) - 1; \ + q = (char *)(str2); \ + while (*++p) \ + *q++ = (char)(isupper((int)(*p))? tolower((int)(*p)) : *p); \ + *q = '\0'; \ + } +#endif +/* + * NOTES: This macro makes no assumptions about the characteristics of + * the tolower() function or macro (beyond its existence), nor does it + * make assumptions about the structure of the character set (i.e., it + * should work on EBCDIC machines, too). The fact that either or both + * of isupper() and tolower() may be macros has been taken into account; + * watch out for "side effects" (in the C sense) when modifying this + * macro. + */ + +#ifndef foreign +# define foreign(c) (c) +#endif + +#ifndef native +# define native(c) (c) +# define A_TO_N(str1) +#else +# ifndef NATIVE +# define NATIVE "native chars" +# endif +# define A_TO_N(str1) {register uch *p;\ + for (p=(uch *)(str1); *p; p++) *p=native(*p);} +#endif +/* + * Translate the zero-terminated string in str1 from ASCII to the native + * character set. The translation is performed in-place and uses the + * "native" macro to translate each character. + * + * NOTE: Using the "native" macro means that is it the only part of unzip + * which knows which translation table (if any) is actually in use to + * produce the native character set. This makes adding new character set + * translation tables easy, insofar as all that is needed is an appropriate + * "native" macro definition and the translation table itself. Currently, + * the only non-ASCII native character set implemented is EBCDIC, but this + * may not always be so. + */ + + +/* default setup for internal codepage: assume ISO 8859-1 compatibility!! */ +#if (!defined(NATIVE) && !defined(CRTL_CP_IS_ISO) && !defined(CRTL_CP_IS_OEM)) +# define CRTL_CP_IS_ISO +#endif + + +/* Translate "extended ASCII" chars (OEM coding for DOS and OS/2; else + * ISO-8859-1 [ISO Latin 1, Win Ansi,...]) into the internal "native" + * code page. As with A_TO_N(), conversion is done in place. + */ +#ifndef _ISO_INTERN +# ifdef CRTL_CP_IS_OEM +# ifndef IZ_ISO2OEM_ARRAY +# define IZ_ISO2OEM_ARRAY +# endif +# define _ISO_INTERN(str1) if (iso2oem) {register uch *p;\ + for (p=(uch *)(str1); *p; p++)\ + *p = native((*p & 0x80) ? iso2oem[*p & 0x7f] : *p);} +# else +# define _ISO_INTERN(str1) A_TO_N(str1) +# endif +#endif + +#ifndef _OEM_INTERN +# ifdef CRTL_CP_IS_OEM +# define _OEM_INTERN(str1) A_TO_N(str1) +# else +# ifndef IZ_OEM2ISO_ARRAY +# define IZ_OEM2ISO_ARRAY +# endif +# define _OEM_INTERN(str1) if (oem2iso) {register uch *p;\ + for (p=(uch *)(str1); *p; p++)\ + *p = native((*p & 0x80) ? oem2iso[*p & 0x7f] : *p);} +# endif +#endif + +#ifndef STR_TO_ISO +# ifdef CRTL_CP_IS_ISO +# define STR_TO_ISO strcpy +# else +# define STR_TO_ISO str2iso +# define NEED_STR2ISO +# endif +#endif + +#ifndef STR_TO_OEM +# ifdef CRTL_CP_IS_OEM +# define STR_TO_OEM strcpy +# else +# define STR_TO_OEM str2oem +# define NEED_STR2OEM +# endif +#endif + +#if (!defined(INTERN_TO_ISO) && !defined(ASCII2ISO)) +# ifdef CRTL_CP_IS_OEM + /* know: "ASCII" is "OEM" */ +# define ASCII2ISO(c) \ + ((((c) & 0x80) && oem2iso) ? oem2iso[(c) & 0x7f] : (c)) +# if (defined(NEED_STR2ISO) && !defined(CRYP_USES_OEM2ISO)) +# define CRYP_USES_OEM2ISO +# endif +# else + /* assume: "ASCII" is "ISO-ANSI" */ +# define ASCII2ISO(c) (c) +# endif +#endif + +#if (!defined(INTERN_TO_OEM) && !defined(ASCII2OEM)) +# ifdef CRTL_CP_IS_OEM + /* know: "ASCII" is "OEM" */ +# define ASCII2OEM(c) (c) +# else + /* assume: "ASCII" is "ISO-ANSI" */ +# define ASCII2OEM(c) \ + ((((c) & 0x80) && iso2oem) ? iso2oem[(c) & 0x7f] : (c)) +# if (defined(NEED_STR2OEM) && !defined(CRYP_USES_ISO2OEM)) +# define CRYP_USES_ISO2OEM +# endif +# endif +#endif + +/* codepage conversion setup for testp() in crypt.c */ +#ifdef CRTL_CP_IS_ISO +# ifndef STR_TO_CP2 +# define STR_TO_CP2 STR_TO_OEM +# endif +#else +# ifdef CRTL_CP_IS_OEM +# ifndef STR_TO_CP2 +# define STR_TO_CP2 STR_TO_ISO +# endif +# else /* native internal CP is neither ISO nor OEM */ +# ifndef STR_TO_CP1 +# define STR_TO_CP1 STR_TO_ISO +# endif +# ifndef STR_TO_CP2 +# define STR_TO_CP2 STR_TO_OEM +# endif +# endif +#endif + + +/* Convert filename (and file comment string) into "internal" charset. + * This macro assumes that Zip entry filenames are coded in OEM (IBM DOS) + * codepage when made on + * -> DOS (this includes 16-bit Windows 3.1) (FS_FAT_) + * -> OS/2 (FS_HPFS_) + * -> Win95/WinNT with Nico Mak's WinZip (FS_NTFS_ && hostver == "5.0") + * EXCEPTIONS: + * PKZIP for Windows 2.5, 2.6, and 4.0 flag their entries as "FS_FAT_", but + * the filename stored in the local header is coded in Windows ANSI (CP 1252 + * resp. ISO 8859-1 on US and western Europe locale settings). + * Likewise, PKZIP for UNIX 2.51 flags its entries as "FS_FAT_", but the + * filenames stored in BOTH the local and the central header are coded + * in the local system's codepage (usually ANSI codings like ISO 8859-1). + * + * All other ports are assumed to code zip entry filenames in ISO 8859-1. + */ +#ifndef Ext_ASCII_TO_Native +# define Ext_ASCII_TO_Native(string, hostnum, hostver, isuxatt, islochdr) \ + if (((hostnum) == FS_FAT_ && \ + !(((islochdr) || (isuxatt)) && \ + ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \ + (hostnum) == FS_HPFS_ || \ + ((hostnum) == FS_NTFS_ /* && (hostver) == 50 */ )) { \ + _OEM_INTERN((string)); \ + } else { \ + _ISO_INTERN((string)); \ + } +#endif + + + +/**********************/ +/* Global constants */ +/**********************/ + + extern ZCONST unsigned near mask_bits[17]; + extern ZCONST char *fnames[2]; + +#ifdef EBCDIC + extern ZCONST uch ebcdic[]; +#endif +#ifdef IZ_ISO2OEM_ARRAY + extern ZCONST uch Far *iso2oem; + extern ZCONST uch Far iso2oem_850[]; +#endif +#ifdef IZ_OEM2ISO_ARRAY + extern ZCONST uch Far *oem2iso; + extern ZCONST uch Far oem2iso_850[]; +#endif + + extern ZCONST char Far VersionDate[]; + extern ZCONST char Far CentSigMsg[]; +#ifndef SFX + extern ZCONST char Far EndSigMsg[]; +#endif + extern ZCONST char Far SeekMsg[]; + extern ZCONST char Far FilenameNotMatched[]; + extern ZCONST char Far ExclFilenameNotMatched[]; + extern ZCONST char Far ReportMsg[]; + +#ifndef SFX + extern ZCONST char Far Zipnfo[]; + extern ZCONST char Far CompiledWith[]; +#endif /* !SFX */ + + + +/***********************************/ +/* Global (shared?) RTL variables */ +/***********************************/ + +#ifdef DECLARE_ERRNO + extern int errno; +#endif + +/*--------------------------------------------------------------------- + Unicode Support + 28 August 2005 + ---------------------------------------------------------------------*/ +#if (defined(UNICODE_SUPPORT) && defined(UNICODE_WCHAR)) + + /* Default character when a zwchar too big for wchar_t */ +# define zwchar_to_wchar_t_default_char '_' + + /* Default character string when wchar_t does not convert to mb */ +# define wide_to_mb_default_string "_" + + /* wide character type */ + typedef unsigned long zwchar; + + /* UTF-8 related conversion functions, currently found in process.c */ + +# if 0 /* currently unused */ + /* check if string is all ASCII */ + int is_ascii_string OF((ZCONST char *mbstring)); +# endif /* unused */ + + /* convert UTF-8 string to multi-byte string */ + char *utf8_to_local_string OF((ZCONST char *utf8_string, int escape_all)); + + /* convert UTF-8 string to wide string */ + zwchar *utf8_to_wide_string OF((ZCONST char *utf8_string)); + + /* convert wide string to multi-byte string */ + char *wide_to_local_string OF((ZCONST zwchar *wide_string, int escape_all)); + +# if 0 /* currently unused */ + /* convert local string to multi-byte display string */ + char *local_to_display_string OF((ZCONST char *local_string)); +# endif /* unused */ + + /* convert wide character to escape string */ + char *wide_to_escape_string OF((unsigned long)); + +# define utf8_to_escaped_string(utf8_string) \ + utf8_to_local_string(utf8_string, TRUE) + +# if 0 /* currently unused */ + /* convert escape string to wide character */ + unsigned long escape_string_to_wide OF((ZCONST char *escape_string)); + + /* convert local to UTF-8 */ + char *local_to_utf8_string OF ((ZCONST char *local_string)); + + /* convert local to wide string */ + zwchar *local_to_wide_string OF ((ZCONST char *local_string)); + + /* convert wide string to UTF-8 */ + char *wide_to_utf8_string OF((ZCONST zwchar *wide_string)); +# endif /* unused */ + +#endif /* UNICODE_SUPPORT && UNICODE_WCHAR */ + + +#endif /* !__unzpriv_h */ diff -Naur a/zipinfo.c b/zipinfo.c --- a/zipinfo.c 2009-02-08 17:04:30.000000000 +0000 +++ b/zipinfo.c 2019-12-02 01:49:39.895641007 +0000 @@ -457,6 +457,10 @@ int tflag_slm=TRUE, tflag_2v=FALSE; int explicit_h=FALSE, explicit_t=FALSE; +#ifdef UNIX + extern char OEM_CP[MAX_CP_NAME]; + extern char ISO_CP[MAX_CP_NAME]; +#endif #ifdef MACOS uO.lflag = LFLAG; /* reset default on each call */ @@ -501,6 +505,37 @@ uO.lflag = 0; } break; +#ifdef UNIX + case ('I'): + if (negative) { + Info(slide, 0x401, ((char *)slide, + "error: encodings can't be negated")); + return(PK_PARAM); + } else { + if(*s) { /* Handle the -Icharset case */ + /* Assume that charsets can't start with a dash to spot arguments misuse */ + if(*s == '-') { + Info(slide, 0x401, ((char *)slide, + "error: a valid character encoding should follow the -I argument")); + return(PK_PARAM); + } + strncpy(ISO_CP, s, MAX_CP_NAME - 1); + ISO_CP[MAX_CP_NAME - 1] = '\0'; + } else { /* -I charset */ + ++argv; + if(!(--argc > 0 && *argv != NULL && **argv != '-')) { + Info(slide, 0x401, ((char *)slide, + "error: a valid character encoding should follow the -I argument")); + return(PK_PARAM); + } + s = *argv; + strncpy(ISO_CP, s, MAX_CP_NAME - 1); + ISO_CP[MAX_CP_NAME - 1] = '\0'; + } + while(*(++s)); /* No params straight after charset name */ + } + break; +#endif /* ?UNIX */ case 'l': /* longer form of "ls -l" type listing */ if (negative) uO.lflag = -2, negative = 0; @@ -521,6 +556,37 @@ G.M_flag = TRUE; break; #endif +#ifdef UNIX + case ('O'): + if (negative) { + Info(slide, 0x401, ((char *)slide, + "error: encodings can't be negated")); + return(PK_PARAM); + } else { + if(*s) { /* Handle the -Ocharset case */ + /* Assume that charsets can't start with a dash to spot arguments misuse */ + if(*s == '-') { + Info(slide, 0x401, ((char *)slide, + "error: a valid character encoding should follow the -I argument")); + return(PK_PARAM); + } + strncpy(OEM_CP, s, MAX_CP_NAME - 1); + OEM_CP[MAX_CP_NAME - 1] = '\0'; + } else { /* -O charset */ + ++argv; + if(!(--argc > 0 && *argv != NULL && **argv != '-')) { + Info(slide, 0x401, ((char *)slide, + "error: a valid character encoding should follow the -O argument")); + return(PK_PARAM); + } + s = *argv; + strncpy(OEM_CP, s, MAX_CP_NAME - 1); + OEM_CP[MAX_CP_NAME - 1] = '\0'; + } + while(*(++s)); /* No params straight after charset name */ + } + break; +#endif /* ?UNIX */ case 's': /* default: shorter "ls -l" type listing */ if (negative) uO.lflag = -2, negative = 0; @@ -771,7 +837,7 @@ Info(slide, 0x401, ((char *)slide, LoadFarString(CentSigMsg), j)); Info(slide, 0x401, - ((char *)slide, LoadFarString(ReportMsg))); + ((char *)slide,"%s", LoadFarString(ReportMsg))); error_in_archive = PK_BADERR; /* sig not found */ break; } @@ -960,7 +1026,8 @@ && (!G.ecrec.is_zip64_archive) && (memcmp(G.sig, end_central_sig, 4) != 0) ) { /* just to make sure again */ - Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg))); + Info(slide, 0x401, + ((char *)slide,"%s", LoadFarString(EndSigMsg))); error_in_archive = PK_WARN; /* didn't find sig */ } @@ -1881,7 +1948,7 @@ #endif int k, error, error_in_archive=PK_COOL; unsigned hostnum, hostver, methid, methnum, xattr; - char *p, workspace[12], attribs[16]; + char *p, workspace[12], attribs[17]; char methbuf[5]; static ZCONST char dtype[5]="NXFS"; /* normal, maximum, fast, superfast */ static ZCONST char Far os[NUM_HOSTS+1][4] = { @@ -1921,7 +1988,19 @@ ush dnum=(ush)((G.crec.general_purpose_bit_flag>>1) & 3); methbuf[3] = dtype[dnum]; } else if (methnum >= NUM_METHODS) { /* unknown */ - sprintf(&methbuf[1], "%03u", G.crec.compression_method); + /* 2016-12-05 SMS. + * https://launchpad.net/bugs/1643750 + * Unexpectedly large compression methods overflow + * &methbuf[]. Use the old, three-digit decimal format + * for values which fit. Otherwise, sacrifice the "u", + * and use four-digit hexadecimal. + */ + if (G.crec.compression_method <= 999) { + sprintf( &methbuf[ 1], "%03u", G.crec.compression_method); + } else { + sprintf( &methbuf[ 0], "%04X", G.crec.compression_method); + } + } for (k = 0; k < 15; ++k)