Archive-Unzip-Burst
view release on metacpan or search on metacpan
unzip-6.0/fileio.c view on Meta::CPAN
/*
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
*/
/*---------------------------------------------------------------------------
fileio.c
This file contains routines for doing direct but relatively generic input/
output, file-related sorts of things, plus some miscellaneous stuff. Most
of the stuff has to do with opening, closing, reading and/or writing files.
Contains: open_input_file()
open_outfile() (not: VMS, AOS/VS, CMSMVS, MACOS, TANDEM)
undefer_input()
defer_leftover_input()
readbuf()
readbyte()
fillinbuf()
seek_zipf()
flush() (non-VMS)
is_vms_varlen_txt() (non-VMS, VMS_TEXT_CONV only)
disk_error() (non-VMS)
UzpMessagePrnt()
UzpMessageNull() (DLL only)
UzpInput()
UzpMorePause()
UzpPassword() (non-WINDLL)
handler()
dos_to_unix_time() (non-VMS, non-VM/CMS, non-MVS)
check_for_newer() (non-VMS, non-OS/2, non-VM/CMS, non-MVS)
do_string()
makeword()
makelong()
makeint64()
fzofft()
str2iso() (CRYPT && NEED_STR2ISO, only)
str2oem() (CRYPT && NEED_STR2OEM, only)
memset() (ZMEM only)
memcpy() (ZMEM only)
zstrnicmp() (NO_STRNICMP only)
zstat() (REGULUS only)
plastchar() (_MBCS only)
uzmbclen() (_MBCS && NEED_UZMBCLEN, only)
uzmbschr() (_MBCS && NEED_UZMBSCHR, only)
uzmbsrchr() (_MBCS && NEED_UZMBSRCHR, only)
fLoadFarString() (SMALL_MEM only)
fLoadFarStringSmall() (SMALL_MEM only)
fLoadFarStringSmall2() (SMALL_MEM only)
zfstrcpy() (SMALL_MEM only)
zfstrcmp() (SMALL_MEM && !(SFX || FUNZIP) only)
---------------------------------------------------------------------------*/
#define __FILEIO_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
# include <setjmp.h>
#endif
#include "crc32.h"
#include "crypt.h"
#include "ttyio.h"
/* setup of codepage conversion for decryption passwords */
#if CRYPT
# if (defined(CRYP_USES_ISO2OEM) && !defined(IZ_ISO2OEM_ARRAY))
# define IZ_ISO2OEM_ARRAY /* pull in iso2oem[] table */
# endif
# if (defined(CRYP_USES_OEM2ISO) && !defined(IZ_OEM2ISO_ARRAY))
# define IZ_OEM2ISO_ARRAY /* pull in oem2iso[] table */
# endif
#endif
#include "ebcdic.h" /* definition/initialization of ebcdic[] */
/*
Note: Under Windows, the maximum size of the buffer that can be used
with any of the *printf calls is 16,384, so win_fprintf was used to
feed the fprintf clone no more than 16K chunks at a time. This should
be valid for anything up to 64K (and probably beyond, assuming your
buffers are that big).
*/
#ifdef WINDLL
# define WriteError(buf,len,strm) \
(win_fprintf(pG, strm, (extent)len, (char far *)buf) != (int)(len))
#else /* !WINDLL */
# ifdef USE_FWRITE
# define WriteError(buf,len,strm) \
((extent)fwrite((char *)(buf),1,(extent)(len),strm) != (extent)(len))
# else
# define WriteError(buf,len,strm) \
((extent)write(fileno(strm),(char *)(buf),(extent)(len)) != (extent)(len))
# endif
#endif /* ?WINDLL */
/*
2005-09-16 SMS.
On VMS, when output is redirected to a file, as in a command like
"PIPE UNZIP -v > X.OUT", the output file is created with VFC record
format, and multiple calls to write() or fwrite() will produce multiple
records, even when there's no newline terminator in the buffer.
The result is unsightly output with spurious newlines. Using fprintf()
instead of write() here, and disabling a fflush(stdout) in UzpMessagePrnt()
below, together seem to solve the problem.
According to the C RTL manual, "The write and decc$record_write
functions always generate at least one record." Also, "[T]he fwrite
function always generates at least <number_items> records." So,
"fwrite(buf, len, 1, strm)" is much better ("1" record) than
"fwrite(buf, 1, len, strm)" ("len" (1-character) records, _really_
ugly), but neither is better than write(). Similarly, "The fflush
function always generates a record if there is unwritten data in the
buffer." Apparently fprintf() buffers the stuff somewhere, and puts
out a record (only) when it sees a newline.
*/
#ifdef VMS
# define WriteTxtErr(buf,len,strm) \
((extent)fprintf(strm, "%.*s", len, buf) != (extent)(len))
#else
# define WriteTxtErr(buf,len,strm) WriteError(buf,len,strm)
#endif
#if (defined(USE_DEFLATE64) && defined(__16BIT__))
static int partflush OF((__GPRO__ uch *rawbuf, ulg size, int unshrink));
#endif
#ifdef VMS_TEXT_CONV
static int is_vms_varlen_txt OF((__GPRO__ uch *ef_buf, unsigned ef_len));
#endif
static int disk_error OF((__GPRO));
/****************************/
/* Strings used in fileio.c */
/****************************/
static ZCONST char Far CannotOpenZipfile[] =
"error: cannot open zipfile [ %s ]\n %s\n";
#if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS))
#if (!defined(TANDEM))
#if (defined(ATH_BEO_THS_UNX) || defined(DOS_FLX_NLM_OS2_W32))
static ZCONST char Far CannotDeleteOldFile[] =
"error: cannot delete old %s\n %s\n";
#ifdef UNIXBACKUP
static ZCONST char Far CannotRenameOldFile[] =
"error: cannot rename old %s\n %s\n";
static ZCONST char Far BackupSuffix[] = "~";
#endif
#endif /* ATH_BEO_THS_UNX || DOS_FLX_NLM_OS2_W32 */
#ifdef NOVELL_BUG_FAILSAFE
static ZCONST char Far NovellBug[] =
"error: %s: stat() says does not exist, but fopen() found anyway\n";
#endif
static ZCONST char Far CannotCreateFile[] =
"error: cannot create %s\n %s\n";
#endif /* !TANDEM */
#endif /* !VMS && !AOS_VS && !CMS_MVS && !MACOS */
static ZCONST char Far ReadError[] = "error: zipfile read error\n";
static ZCONST char Far FilenameTooLongTrunc[] =
"warning: filename too long--truncating.\n";
#ifdef UNICODE_SUPPORT
static ZCONST char Far UFilenameTooLongTrunc[] =
"warning: Converted unicode filename too long--truncating.\n";
#endif
static ZCONST char Far ExtraFieldTooLong[] =
"warning: extra field too long (%d). Ignoring...\n";
#ifdef WINDLL
static ZCONST char Far DiskFullQuery[] =
"%s: write error (disk full?).\n";
#else
static ZCONST char Far DiskFullQuery[] =
"%s: write error (disk full?). Continue? (y/n/^C) ";
static ZCONST char Far ZipfileCorrupt[] =
"error: zipfile probably corrupt (%s)\n";
# ifdef SYMLINKS
static ZCONST char Far FileIsSymLink[] =
"%s exists and is a symbolic link%s.\n";
# endif
# ifdef MORE
static ZCONST char Far MorePrompt[] = "--More--(%lu)";
# endif
static ZCONST char Far QuitPrompt[] =
"--- Press `Q' to quit, or any other key to continue ---";
static ZCONST char Far HidePrompt[] = /* "\r \r"; */
"\r \r";
# if CRYPT
# ifdef MACOS
/* SPC: are names on MacOS REALLY so much longer than elsewhere ??? */
static ZCONST char Far PasswPrompt[] = "[%s]\n %s password: ";
# else
static ZCONST char Far PasswPrompt[] = "[%s] %s password: ";
# endif
static ZCONST char Far PasswPrompt2[] = "Enter password: ";
static ZCONST char Far PasswRetry[] = "password incorrect--reenter: ";
# endif /* CRYPT */
#endif /* !WINDLL */
/******************************/
/* Function open_input_file() */
/******************************/
int open_input_file(__G) /* return 1 if open failed */
__GDEF
{
/*
* open the zipfile for reading and in BINARY mode to prevent cr/lf
* translation, which would corrupt the bitstreams
*/
#ifdef VMS
G.zipfd = open(G.zipfn, O_RDONLY, 0, OPNZIP_RMS_ARGS);
#else /* !VMS */
#ifdef MACOS
G.zipfd = open(G.zipfn, 0);
#else /* !MACOS */
#ifdef CMS_MVS
G.zipfd = vmmvs_open_infile(__G);
#else /* !CMS_MVS */
#ifdef USE_STRM_INPUT
G.zipfd = fopen(G.zipfn, FOPR);
#else /* !USE_STRM_INPUT */
G.zipfd = open(G.zipfn, O_RDONLY | O_BINARY);
#endif /* ?USE_STRM_INPUT */
#endif /* ?CMS_MVS */
#endif /* ?MACOS */
#endif /* ?VMS */
#ifdef USE_STRM_INPUT
if (G.zipfd == NULL)
#else
/* if (G.zipfd < 0) */ /* no good for Windows CE port */
if (G.zipfd == -1)
#endif
{
Info(slide, 0x401, ((char *)slide, LoadFarString(CannotOpenZipfile),
G.zipfn, strerror(errno)));
return 1;
}
return 0;
} /* end function open_input_file() */
#if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS))
#if (!defined(TANDEM))
/***************************/
/* Function open_outfile() */
/***************************/
int open_outfile(__G) /* return 1 if fail */
__GDEF
{
#ifdef DLL
if (G.redirect_data)
return (redirect_outfile(__G) == FALSE);
#endif
#ifdef QDOS
QFilename(__G__ G.filename);
#endif
#if (defined(DOS_FLX_NLM_OS2_W32) || defined(ATH_BEO_THS_UNX))
#ifdef BORLAND_STAT_BUG
/* Borland 5.0's stat() barfs if the filename has no extension and the
* file doesn't exist. */
if (access(G.filename, 0) == -1) {
FILE *tmp = fopen(G.filename, "wb+");
/* file doesn't exist, so create a dummy file to keep stat() from
* failing (will be over-written anyway) */
fputc('0', tmp); /* just to have something in the file */
fclose(tmp);
}
#endif /* BORLAND_STAT_BUG */
#ifdef SYMLINKS
if (SSTAT(G.filename, &G.statbuf) == 0 ||
lstat(G.filename, &G.statbuf) == 0)
#else
if (SSTAT(G.filename, &G.statbuf) == 0)
#endif /* ?SYMLINKS */
{
Trace((stderr, "open_outfile: stat(%s) returns 0: file exists\n",
FnFilter1(G.filename)));
#ifdef UNIXBACKUP
if (uO.B_flag) { /* do backup */
char *tname;
z_stat tmpstat;
int blen, flen, tlen;
blen = strlen(BackupSuffix);
flen = strlen(G.filename);
tlen = flen + blen + 6; /* includes space for 5 digits */
if (tlen >= FILNAMSIZ) { /* in case name is too long, truncate */
tname = (char *)malloc(FILNAMSIZ);
if (tname == NULL)
return 1; /* in case we run out of space */
tlen = FILNAMSIZ - 1 - blen;
strcpy(tname, G.filename); /* make backup name */
tname[tlen] = '\0';
if (flen > tlen) flen = tlen;
tlen = FILNAMSIZ;
} else {
tname = (char *)malloc(tlen);
if (tname == NULL)
return 1; /* in case we run out of space */
strcpy(tname, G.filename); /* make backup name */
}
strcpy(tname+flen, BackupSuffix);
if (IS_OVERWRT_ALL) {
/* If there is a previous backup file, delete it,
* otherwise the following rename operation may fail.
*/
if (SSTAT(tname, &tmpstat) == 0)
unlink(tname);
} else {
/* Check if backupname exists, and, if it's true, try
* appending numbers of up to 5 digits (or the maximum
* "unsigned int" number on 16-bit systems) to the
* BackupSuffix, until an unused name is found.
*/
unsigned maxtail, i;
char *numtail = tname + flen + blen;
/* take account of the "unsigned" limit on 16-bit systems: */
maxtail = ( ((~0) >= 99999L) ? 99999 : (~0) );
switch (tlen - flen - blen - 1) {
case 4: maxtail = 9999; break;
case 3: maxtail = 999; break;
case 2: maxtail = 99; break;
case 1: maxtail = 9; break;
case 0: maxtail = 0; break;
}
/* while filename exists */
for (i = 0; (i < maxtail) && (SSTAT(tname, &tmpstat) == 0);)
sprintf(numtail,"%u", ++i);
}
if (rename(G.filename, tname) != 0) { /* move file */
Info(slide, 0x401, ((char *)slide,
LoadFarString(CannotRenameOldFile),
FnFilter1(G.filename), strerror(errno)));
unzip-6.0/fileio.c view on Meta::CPAN
TTrace((stderr, " m_time after DST = %lu\n", (ulg)m_time));
#endif /* !BSD4_4 */
#ifdef WIN32
}
#endif
#endif /* !MACOS && !RISCOS && !QDOS && !TANDEM */
#endif /* ?TOPS20 */
#endif /* ?HAVE_MKTIME */
if ( (dosdatetime >= DOSTIME_2038_01_18) &&
(m_time < (time_t)0x70000000L) )
m_time = U_TIME_T_MAX; /* saturate in case of (unsigned) overflow */
if (m_time < (time_t)0L) /* a converted DOS time cannot be negative */
m_time = S_TIME_T_MAX; /* -> saturate at max signed time_t value */
return m_time;
} /* end function dos_to_unix_time() */
#endif /* !OS2 || TIMESTAMP */
#endif /* !VMS && !CMS_MVS */
#if (!defined(VMS) && !defined(OS2) && !defined(CMS_MVS))
/******************************/
/* Function check_for_newer() */ /* used for overwriting/freshening/updating */
/******************************/
int check_for_newer(__G__ filename) /* return 1 if existing file is newer */
__GDEF /* or equal; 0 if older; -1 if doesn't */
char *filename; /* exist yet */
{
time_t existing, archive;
#ifdef USE_EF_UT_TIME
iztimes z_utime;
#endif
#ifdef AOS_VS
long dyy, dmm, ddd, dhh, dmin, dss;
dyy = (lrec.last_mod_dos_datetime >> 25) + 1980;
dmm = (lrec.last_mod_dos_datetime >> 21) & 0x0f;
ddd = (lrec.last_mod_dos_datetime >> 16) & 0x1f;
dhh = (lrec.last_mod_dos_datetime >> 11) & 0x1f;
dmin = (lrec.last_mod_dos_datetime >> 5) & 0x3f;
dss = (lrec.last_mod_dos_datetime & 0x1f) * 2;
/* under AOS/VS, file times can only be set at creation time,
* with the info in a special DG format. Make sure we can create
* it here - we delete it later & re-create it, whether or not
* it exists now.
*/
if (!zvs_create(filename, (((ulg)dgdate(dmm, ddd, dyy)) << 16) |
(dhh*1800L + dmin*30L + dss/2L), -1L, -1L, (char *) -1, -1, -1, -1))
return DOES_NOT_EXIST;
#endif /* AOS_VS */
Trace((stderr, "check_for_newer: doing stat(%s)\n", FnFilter1(filename)));
if (SSTAT(filename, &G.statbuf)) {
Trace((stderr,
"check_for_newer: stat(%s) returns %d: file does not exist\n",
FnFilter1(filename), SSTAT(filename, &G.statbuf)));
#ifdef SYMLINKS
Trace((stderr, "check_for_newer: doing lstat(%s)\n",
FnFilter1(filename)));
/* GRR OPTION: could instead do this test ONLY if G.symlnk is true */
if (lstat(filename, &G.statbuf) == 0) {
Trace((stderr,
"check_for_newer: lstat(%s) returns 0: symlink does exist\n",
FnFilter1(filename)));
if (QCOND2 && !IS_OVERWRT_ALL)
Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
FnFilter1(filename), " with no real file"));
return EXISTS_AND_OLDER; /* symlink dates are meaningless */
}
#endif /* SYMLINKS */
return DOES_NOT_EXIST;
}
Trace((stderr, "check_for_newer: stat(%s) returns 0: file exists\n",
FnFilter1(filename)));
#ifdef SYMLINKS
/* GRR OPTION: could instead do this test ONLY if G.symlnk is true */
if (lstat(filename, &G.statbuf) == 0 && S_ISLNK(G.statbuf.st_mode)) {
Trace((stderr, "check_for_newer: %s is a symbolic link\n",
FnFilter1(filename)));
if (QCOND2 && !IS_OVERWRT_ALL)
Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
FnFilter1(filename), ""));
return EXISTS_AND_OLDER; /* symlink dates are meaningless */
}
#endif /* SYMLINKS */
NATIVE_TO_TIMET(G.statbuf.st_mtime) /* NOP unless MSC 7.0 or Macintosh */
#ifdef USE_EF_UT_TIME
/* The `Unix extra field mtime' should be used for comparison with the
* time stamp of the existing file >>>ONLY<<< when the EF info is also
* used to set the modification time of the extracted file.
*/
if (G.extra_field &&
#ifdef IZ_CHECK_TZ
G.tz_is_valid &&
#endif
(ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
G.lrec.last_mod_dos_datetime, &z_utime, NULL)
& EB_UT_FL_MTIME))
{
TTrace((stderr, "check_for_newer: using Unix extra field mtime\n"));
existing = G.statbuf.st_mtime;
archive = z_utime.mtime;
} else {
/* round up existing filetime to nearest 2 seconds for comparison,
* but saturate in case of arithmetic overflow
*/
existing = ((G.statbuf.st_mtime & 1) &&
(G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
}
#else /* !USE_EF_UT_TIME */
/* round up existing filetime to nearest 2 seconds for comparison,
* but saturate in case of arithmetic overflow
*/
existing = ((G.statbuf.st_mtime & 1) &&
(G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
archive = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
#endif /* ?USE_EF_UT_TIME */
TTrace((stderr, "check_for_newer: existing %lu, archive %lu, e-a %ld\n",
(ulg)existing, (ulg)archive, (long)(existing-archive)));
return (existing >= archive);
} /* end function check_for_newer() */
#endif /* !VMS && !OS2 && !CMS_MVS */
/************************/
unzip-6.0/fileio.c view on Meta::CPAN
return c;
} while (--len > 0)
return 0;
}
/*********************/
/* Function memcpy() */
/*********************/
zvoid *memcpy(dst, src, len)
register zvoid *dst;
register ZCONST zvoid *src;
register unsigned int len;
{
zvoid *start;
start = dst;
while (len-- > 0)
*((char *)dst)++ = *((ZCONST char *)src)++;
return start;
}
#endif /* ZMEM */
#ifdef NO_STRNICMP
/************************/
/* Function zstrnicmp() */
/************************/
int zstrnicmp(s1, s2, n)
register ZCONST char *s1, *s2;
register unsigned n;
{
for (; n > 0; --n, ++s1, ++s2) {
if (ToLower(*s1) != ToLower(*s2))
/* test includes early termination of one string */
return ((uch)ToLower(*s1) < (uch)ToLower(*s2))? -1 : 1;
if (*s1 == '\0') /* both strings terminate early */
return 0;
}
return 0;
}
#endif /* NO_STRNICMP */
#ifdef REGULUS /* returns the inode number on success(!)...argh argh argh */
# undef stat
/********************/
/* Function zstat() */
/********************/
int zstat(p, s)
ZCONST char *p;
struct stat *s;
{
return (stat((char *)p,s) >= 0? 0 : (-1));
}
#endif /* REGULUS */
#ifdef _MBCS
/* DBCS support for Info-ZIP's zip (mainly for japanese (-: )
* by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp)
* This code is public domain! Date: 1998/12/20
*/
/************************/
/* Function plastchar() */
/************************/
char *plastchar(ptr, len)
ZCONST char *ptr;
extent len;
{
unsigned clen;
ZCONST char *oldptr = ptr;
while(*ptr != '\0' && len > 0){
oldptr = ptr;
clen = CLEN(ptr);
ptr += clen;
len -= clen;
}
return (char *)oldptr;
}
#ifdef NEED_UZMBCLEN
/***********************/
/* Function uzmbclen() */
/***********************/
extent uzmbclen(ptr)
ZCONST unsigned char *ptr;
{
int mbl;
mbl = mblen((ZCONST char *)ptr, MB_CUR_MAX);
/* For use in code scanning through MBCS strings, we need a strictly
positive "MB char bytes count". For our scanning purpose, it is not
not relevant whether the MB character is valid or not. And, the NUL
char '\0' has a byte count of 1, but mblen() returns 0. So, we make
sure that the uzmbclen() return value is not less than 1.
*/
return (extent)(mbl > 0 ? mbl : 1);
}
#endif /* NEED_UZMBCLEN */
#ifdef NEED_UZMBSCHR
/***********************/
/* Function uzmbschr() */
/***********************/
( run in 2.485 seconds using v1.01-cache-2.11-cpan-2e0ccfb7a10 )