home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume44
/
unzip
/
part10
< prev
next >
Wrap
Internet Message Format
|
1994-09-19
|
72KB
From: zip-bugs@wkuvx1.wku.edu (Info-ZIP group)
Newsgroups: comp.sources.misc
Subject: v44i075: unzip - Info-ZIP portable UnZip, version 5.12, Part10/20
Date: 18 Sep 1994 23:15:39 -0500
Organization: Sterling Software
Sender: kent@sparky.sterling.com
Approved: kent@sparky.sterling.com
Message-ID: <35j39b$qoo@sparky.sterling.com>
X-Md4-Signature: 12240212bb0bb59b8042f362e7312e91
Submitted-by: zip-bugs@wkuvx1.wku.edu (Info-ZIP group)
Posting-number: Volume 44, Issue 75
Archive-name: unzip/part10
Environment: UNIX, VMS, OS/2, MS-DOS, MACINTOSH, WIN-NT, LINUX, MINIX, COHERENT, AMIGA?, ATARI TOS, SGI, DEC, Cray, Convex, Amdahl, Sun
Supersedes: unzip50: Volume 31, Issue 104-117
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# Contents: unzip-5.12/file_io.c unzip-5.12/tops20/make.mic
# unzip-5.12/unix/unix.c
# Wrapped by kent@sparky on Sat Sep 17 23:33:41 1994
PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 10 (of 20)."'
if test -f 'unzip-5.12/file_io.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'unzip-5.12/file_io.c'\"
else
echo shar: Extracting \"'unzip-5.12/file_io.c'\" \(35360 characters\)
sed "s/^X//" >'unzip-5.12/file_io.c' <<'END_OF_FILE'
X/*---------------------------------------------------------------------------
X
X file_io.c
X
X This file contains routines for doing direct but relatively generic input/
X output, file-related sorts of things, plus some miscellaneous stuff. Most
X of the stuff has to do with opening, closing, reading and/or writing files.
X
X Contains: open_input_file()
X open_outfile() (non-VMS)
X readbuf()
X readbyte()
X flush() (non-VMS)
X disk_error() (non-VMS)
X handler()
X dos_to_unix_time() (non-VMS, non-OS/2)
X check_for_newer() (non-VMS, non-OS/2)
X find_ecrec()
X get_cdir_ent()
X do_string()
X makeword()
X makelong()
X memset() (ZMEM only)
X memcpy() (ZMEM only)
X zstrnicmp()
X zstat() (REGULUS only)
X LoadFarString() (SMALL_MEM only)
X LoadFarStringSmall() (SMALL_MEM only)
X LoadFarStringSmall2() (SMALL_MEM only)
X
X ---------------------------------------------------------------------------*/
X
X
X#define FILE_IO_C
X#include "unzip.h"
X#include "crypt.h"
X#include "tables.h" /* definition/initialization of ebcdic[] */
X
X#ifdef USE_FWRITE
X# define WriteError(buf,len,strm) \
X ((extent)fwrite((char *)(buf),1,(extent)(len),strm) != (extent)(len))
X#else
X# define WriteError(buf,len,strm) \
X ((extent)write(fileno(strm),(char *)(buf),(extent)(len)) != (extent)(len))
X#endif
X
Xstatic int disk_error OF((void));
X
X
X
X/*****************************/
X/* Strings used in file_io.c */
X/*****************************/
X
X#ifdef UNIX
X static char Far CannotDeleteOldFile[] = "\nerror: cannot delete old %s\n";
X#endif
X
Xstatic char Far CantOpenZipfile[] = "error: can't open zipfile [ %s ]\n";
Xstatic char Far CannotCreateFile[] = "\nerror: cannot create %s\n";
Xstatic char Far ReadError[] = "error: zipfile read error\n";
Xstatic char Far DiskFull[] =
X "\n%s: write error (disk full?). Continue? (y/n/^C) ";
Xstatic char Far ZipfileCorrupt[] = "error: zipfile probably corrupt (%s)\n";
Xstatic char Far CentDirEndSigNotFound[] = "\
X End-of-central-directory signature not found. Either this file is not\n\
X a zipfile, or it constitutes one disk of a multi-part archive. In the\n\
X latter case the central directory and zipfile comment will be found on\n\
X the last disk(s) of this archive.\n";
Xstatic char Far FilenameTooLongTrunc[] =
X "warning: filename too long--truncating.\n";
Xstatic char Far ExtraFieldTooLong[] =
X "warning: extra field too long (%d). Ignoring...\n";
X
X
X
X
X
X/******************************/
X/* Function open_input_file() */
X/******************************/
X
Xint open_input_file() /* return 1 if open failed */
X{
X /*
X * open the zipfile for reading and in BINARY mode to prevent cr/lf
X * translation, which would corrupt the bitstreams
X */
X
X#if defined(UNIX) || defined(TOPS20) || defined(ATARI_ST)
X zipfd = open(zipfn, O_RDONLY);
X#else /* !(UNIX || TOPS20) */
X#ifdef VMS
X zipfd = open(zipfn, O_RDONLY, 0, "ctx=stm");
X#else /* !VMS */
X#ifdef MACOS
X zipfd = open(zipfn, 0);
X#else /* !MACOS */
X zipfd = open(zipfn, O_RDONLY | O_BINARY);
X#endif /* ?MACOS */
X#endif /* ?VMS */
X#endif /* ?(UNIX || TOPS20) */
X if (zipfd < 0) {
X FPRINTF(stderr, LoadFarString(CantOpenZipfile), zipfn);
X return 1;
X }
X return 0;
X
X} /* end function open_input_file() */
X
X
X
X
X#ifndef VMS /* for VMS use code in vms.c */
X
X/***************************/
X/* Function open_outfile() */
X/***************************/
X
Xint open_outfile() /* return 1 if fail */
X{
X#ifdef DOS_NT_OS2
X if (stat(filename, &statbuf) == 0 && !(statbuf.st_mode & S_IWRITE))
X chmod(filename, S_IREAD | S_IWRITE);
X#endif
X#ifdef UNIX
X if (stat(filename, &statbuf) == 0 && unlink(filename) < 0) {
X FPRINTF(stderr, LoadFarString(CannotDeleteOldFile), filename);
X return 1;
X }
X#endif
X#ifdef TOPS20
X char *tfilnam;
X
X if ((tfilnam = (char *)malloc(2*strlen(filename)+1)) == (char *)NULL)
X return 1;
X strcpy(tfilnam, filename);
X upper(tfilnam);
X enquote(tfilnam);
X if ((outfile = fopen(tfilnam, FOPW)) == (FILE *)NULL) {
X FPRINTF(stderr, LoadFarString(CannotCreateFile), tfilnam);
X free(tfilnam);
X return 1;
X }
X free(tfilnam);
X#else
X#ifdef MTS
X if (aflag)
X outfile = fopen(filename, FOPWT);
X else
X outfile = fopen(filename, FOPW);
X if (outfile == (FILE *)NULL) {
X FPRINTF(stderr, LoadFarString(CannotCreateFile), filename);
X return 1;
X }
X#else
X if ((outfile = fopen(filename, FOPW)) == (FILE *)NULL) {
X FPRINTF(stderr, LoadFarString(CannotCreateFile), filename);
X return 1;
X }
X#endif
X#endif
X
X#if 0 /* this SUCKS! on Ultrix, it must be writing a byte at a time... */
X setbuf(outfile, (char *)NULL); /* make output unbuffered */
X#endif
X
X#ifdef USE_FWRITE
X#ifdef DOS_NT_OS2
X /* 16-bit MSC: buffer size must be strictly LESS than 32K (WSIZE): bogus */
X setbuf(outfile, (char *)NULL); /* make output unbuffered */
X#else /* !DOS_NT_OS2 */
X#ifdef _IOFBF /* make output fully buffered (works just about like write()) */
X setvbuf(outfile, (char *)slide, _IOFBF, WSIZE);
X#else
X setbuf(outfile, (char *)slide);
X#endif
X#endif /* ?DOS_NT_OS2 */
X#endif /* USE_FWRITE */
X return 0;
X
X} /* end function open_outfile() */
X
X#endif /* !VMS */
X
X
X
X
X
X/**********************/
X/* Function readbuf() */
X/**********************/
X
Xunsigned readbuf(buf, size) /* return number of bytes read into buf */
X char *buf;
X register unsigned size;
X{
X register unsigned count;
X unsigned n;
X
X n = size;
X while (size) {
X if (incnt == 0) {
X#ifdef OLD_READBUF
X if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) <= 0)
X return (n-size);
X#else
X if ((incnt = read(zipfd, (char *)inbuf, INBUFSIZ)) == 0)
X return (n-size);
X else if (incnt < 0) {
X FPRINTF(stderr, LoadFarString(ReadError));
X return 0; /* discarding some data; better than lock-up */
X }
X#endif
X /* buffer ALWAYS starts on a block boundary: */
X cur_zipfile_bufstart += INBUFSIZ;
X inptr = inbuf;
X }
X count = MIN(size, (unsigned)incnt);
X memcpy(buf, inptr, count);
X buf += count;
X inptr += count;
X incnt -= count;
X size -= count;
X }
X return n;
X
X} /* end function readbuf() */
X
X
X
X
X
X/***********************/
X/* Function readbyte() */
X/***********************/
X
Xint readbyte() /* refill inbuf and return a byte if available, else EOF */
X{
X if (mem_mode || (incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) <= 0)
X return EOF;
X cur_zipfile_bufstart += INBUFSIZ; /* always starts on a block boundary */
X inptr = inbuf;
X
X#ifdef CRYPT
X if (pInfo->encrypted) {
X uch *p;
X int n;
X
X for (n = (long)incnt > csize + 1 ? (int)csize + 1 : incnt,
X p = inptr; n--; p++)
X zdecode(*p);
X }
X#endif /* CRYPT */
X
X --incnt;
X return *inptr++;
X
X} /* end function readbyte() */
X
X
X
X
X
X#ifndef VMS /* for VMS use code in vms.c */
X
X/********************/
X/* Function flush() */
X/********************/
X
Xint flush(rawbuf, size, unshrink) /* cflag => always 0; 50 if write error */
X uch *rawbuf;
X ulg size;
X int unshrink;
X{
X#ifdef ASM_CRC
X ulg CalcCRC(ulg *crc_table, ulg crcval, uch *rawbuf, ulg rawbufsize);
X#else
X register ulg crcval = crc32val;
X register ulg n = size;
X#endif
X register uch *p, *q;
X uch *transbuf;
X ulg transbufsiz;
X static int didCRlast = FALSE;
X
X
X/*---------------------------------------------------------------------------
X Compute the CRC first; if testing or if disk is full, that's it.
X ---------------------------------------------------------------------------*/
X
X#ifdef ASM_CRC
X crc32val = CalcCRC(crc_32_tab, crc32val, rawbuf, size);
X#else
X p = rawbuf;
X while (n--)
X crcval = crc_32_tab[((uch)crcval ^ (*p++)) & 0xff] ^ (crcval >> 8);
X crc32val = crcval;
X#endif /* ?ASM_CRC */
X
X if (tflag || size == 0L) /* testing or nothing to write: all done */
X return 0;
X
X if (disk_full)
X return 50; /* disk already full: ignore rest of file */
X
X/*---------------------------------------------------------------------------
X Write the bytes rawbuf[0..size-1] to the output device, first converting
X end-of-lines and ASCII/EBCDIC as needed. If SMALL_MEM or MED_MEM are NOT
X defined, outbuf is assumed to be at least as large as rawbuf and is not
X necessarily checked for overflow.
X ---------------------------------------------------------------------------*/
X
X if (!pInfo->textmode) {
X /* GRR: note that for standard MS-DOS compilers, size argument to
X * fwrite() can never be more than 65534, so WriteError macro will
X * have to be rewritten if size can ever be that large. For now,
X * never more than 32K. Also note that write() returns an int, which
X * doesn't necessarily limit size to 32767 bytes if write() is used
X * on 16-bit systems but does make it more of a pain; however, because
X * at least MSC 5.1 has a lousy implementation of fwrite() (as does
X * DEC Ultrix cc), write() is used anyway.
X */
X if (WriteError(rawbuf, size, outfile)) /* write raw binary data */
X return cflag? 0 : disk_error();
X } else {
X if (unshrink) {
X /* rawbuf = outbuf */
X transbuf = outbuf2;
X transbufsiz = TRANSBUFSIZ;
X } else {
X /* rawbuf = slide */
X transbuf = outbuf;
X transbufsiz = OUTBUFSIZ;
X Trace((stderr, "\ntransbufsiz = OUTBUFSIZ = %u\n", OUTBUFSIZ));
X }
X if (newfile) {
X didCRlast = FALSE; /* no previous buffers written */
X newfile = FALSE;
X }
X p = rawbuf;
X if (*p == LF && didCRlast)
X ++p;
X
X /*-----------------------------------------------------------------------
X Algorithm: CR/LF => native; lone CR => native; lone LF => native.
X This routine is only for non-raw-VMS, non-raw-VM/CMS files (i.e.,
X stream-oriented files, not record-oriented).
X -----------------------------------------------------------------------*/
X
X for (didCRlast = FALSE, q = transbuf; p < rawbuf+size; ++p) {
X if (*p == CR) { /* lone CR or CR/LF: EOL either way */
X PutNativeEOL
X if (p == rawbuf+size-1) /* last char in buffer */
X didCRlast = TRUE;
X else if (p[1] == LF) /* get rid of accompanying LF */
X ++p;
X } else if (*p == LF) /* lone LF */
X PutNativeEOL
X else
X#ifndef DOS_NT_OS2
X if (*p != CTRLZ) /* lose all ^Z's */
X#endif
X *q++ = native(*p);
X
X#if (defined(SMALL_MEM) || defined(MED_MEM))
X# if (lenEOL == 1) /* don't check unshrink: both buffers small but equal */
X if (!unshrink)
X# endif
X /* check for danger of buffer overflow and flush */
X if (q > transbuf+transbufsiz-lenEOL) {
X Trace((stderr,
X "p - rawbuf = %u q-transbuf = %u size = %lu\n",
X (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
X if (WriteError(transbuf, (unsigned)(q-transbuf), outfile))
X return cflag? 0 : disk_error();
X q = transbuf;
X continue;
X }
X#endif /* SMALL_MEM || MED_MEM */
X }
X
X /*-----------------------------------------------------------------------
X Done translating: write whatever we've got to file.
X -----------------------------------------------------------------------*/
X
X Trace((stderr, "p - rawbuf = %u q-transbuf = %u size = %lu\n",
X (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
X if (q > transbuf &&
X WriteError(transbuf, (unsigned)(q-transbuf), outfile))
X return cflag? 0 : disk_error();
X }
X
X return 0;
X
X} /* end function flush() */
X
X
X
X
X
X/*************************/
X/* Function disk_error() */
X/*************************/
X
Xstatic int disk_error()
X{
X FPRINTF(stderr, LoadFarString(DiskFull), filename);
X FFLUSH(stderr);
X
X#ifndef MSWIN
X fgets(answerbuf, 9, stdin);
X if (*answerbuf == 'y') /* stop writing to this file */
X disk_full = 1; /* (outfile bad?), but new OK */
X else
X#endif
X disk_full = 2; /* no: exit program */
X
X return 50; /* 50: disk full */
X
X} /* end function disk_error() */
X
X#endif /* !VMS */
X
X
X
X
X
X/**********************/
X/* Function handler() */
X/**********************/
X
Xvoid handler(signal) /* upon interrupt, turn on echo and exit cleanly */
X int signal;
X{
X#if defined(SIGBUS) || defined(SIGSEGV)
X# ifdef SMALL_MEM
X static char *corrupt;
X corrupt = LoadFarString(ZipfileCorrupt);
X# else
X static char *corrupt = LoadFarString(ZipfileCorrupt);
X# endif
X#endif
X
X#if !defined(DOS_NT_OS2) && !defined(MACOS)
X echon();
X PUTC('\n', stderr);
X#endif /* !DOS_NT_OS2 && !MACOS */
X#ifdef SIGBUS
X if (signal == SIGBUS) {
X FPRINTF(stderr, corrupt, "bus error");
X exit(3);
X }
X#endif /* SIGBUS */
X#ifdef SIGSEGV
X if (signal == SIGSEGV) {
X FPRINTF(stderr, corrupt, "segmentation violation");
X exit(3);
X }
X#endif /* SIGSEGV */
X exit(0);
X}
X
X
X
X
X
X#ifdef DEBUG_TIME
X# define TTrace(x) FPRINTF x
X#else
X# define TTrace(x)
X#endif
X
X#if !defined(VMS) && !defined(OS2)
X
X/*******************************/
X/* Function dos_to_unix_time() */ /* only used for freshening/updating */
X/*******************************/
X
Xtime_t dos_to_unix_time(ddate, dtime)
X unsigned ddate, dtime;
X{
X int yr, mo, dy, hh, mm, ss;
X#ifdef TOPS20
X# define YRBASE 1900
X struct tmx *tmx;
X char temp[20];
X time_t retval;
X#else /* !TOPS20 */
X# define YRBASE 1970
X static short yday[]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
X int leap;
X long m_time, days=0;
X#if (!defined(MACOS) && !defined(MSC))
X#if (defined(BSD) || defined(MTS) || defined(__GO32__))
X#ifndef BSD4_4
X static struct timeb tbp;
X#endif /* !BSD4_4 */
X#else /* !(BSD || MTS || __GO32__) */
X#ifdef ATARI_ST
X extern long _timezone;
X# define timezone _timezone; /* a whoops in our library... */
X#else /* !ATARI_ST */
X extern long timezone; /* declared in <time.h> for MSC (& Borland?) */
X#endif /* ?ATARI_ST */
X#endif /* ?(BSD || MTS || __GO32__) */
X#endif /* !MACOS && !MSC */
X#endif /* ?TOPS20 */
X
X
X /* dissect date */
X yr = ((ddate >> 9) & 0x7f) + (1980 - YRBASE);
X mo = ((ddate >> 5) & 0x0f) - 1;
X dy = (ddate & 0x1f) - 1;
X
X /* dissect time */
X hh = (dtime >> 11) & 0x1f;
X mm = (dtime >> 5) & 0x3f;
X ss = (dtime & 0x1f) * 2;
X
X#ifdef TOPS20
X tmx = (struct tmx *)malloc(sizeof(struct tmx));
X sprintf (temp, "%02d/%02d/%02d %02d:%02d:%02d", mo+1, dy+1, yr, hh, mm, ss);
X time_parse(temp, tmx, (char *)0);
X retval = time_make(tmx);
X free(tmx);
X return retval;
X
X#else /* !TOPS20 */
X /* leap = # of leap years from BASE up to but not including current year */
X leap = ((yr + YRBASE - 1) / 4); /* leap year base factor */
X
X /* calculate days from BASE to this year and add expired days this year */
X days = (yr * 365) + (leap - 492) + yday[mo];
X
X /* if year is a leap year and month is after February, add another day */
X if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100))
X ++days; /* OK through 2199 */
X
X /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */
X m_time = ((long)(days + dy) * 86400L) + ((long)hh * 3600) + (mm * 60) + ss;
X /* - 1; MS-DOS times always rounded up to nearest even second */
X TTrace((stderr, "dos_to_unix_time:\n"));
X TTrace((stderr, " m_time before timezone = %ld\n", m_time));
X
X#ifndef MACOS
X#if (defined(BSD) || defined(MTS) || defined(__GO32__))
X#ifndef BSD4_4
X ftime(&tbp);
X m_time += tbp.timezone * 60L;
X#endif
X#else /* !(BSD || MTS || __GO32__) */
X#ifdef WIN32
X {
X TIME_ZONE_INFORMATION tzinfo;
X DWORD res;
X
X /* account for timezone differences */
X res = GetTimeZoneInformation(&tzinfo);
X if (res == TIME_ZONE_ID_STANDARD)
X m_time += 60*(tzinfo.Bias + tzinfo.StandardBias);
X else if (res == TIME_ZONE_ID_DAYLIGHT)
X m_time += 60*(tzinfo.Bias + tzinfo.DaylightBias);
X /* GRR: are other return-values possible? */
X }
X#else /* !WIN32 */
X tzset(); /* set `timezone' variable */
X m_time += timezone;
X#endif /* ?WIN32 */
X#endif /* ?(BSD || MTS || __GO32__) */
X#endif /* !MACOS */
X TTrace((stderr, " m_time after timezone = %ld\n", m_time));
X
X#ifdef BSD4_4 /* see comments in unix.c */
X m_time -= localtime((time_t *) &m_time)->tm_gmtoff;
X#else /* !BSD4_4 */
X#ifndef WIN32
X if (localtime((time_t *)&m_time)->tm_isdst)
X m_time -= 60L * 60L; /* adjust for daylight savings time */
X#endif /* !WIN32 */
X#endif /* ?BSD4_4 */
X TTrace((stderr, " m_time after DST = %ld\n", m_time));
X
X return m_time;
X#endif /* ?TOPS20 */
X
X} /* end function dos_to_unix_time() */
X
X
X
X
X
X/******************************/
X/* Function check_for_newer() */ /* only used for freshening/updating */
X/******************************/
X
Xint check_for_newer(filename) /* return 1 if existing file newer or equal; */
X char *filename; /* 0 if older; -1 if doesn't exist yet */
X{
X time_t existing, archive;
X
X if (stat(filename, &statbuf))
X return DOES_NOT_EXIST;
X
X /* round up existing filetime to nearest 2 seconds for comparison */
X existing = (statbuf.st_mtime & 1) ? statbuf.st_mtime+1 : statbuf.st_mtime;
X archive = dos_to_unix_time(lrec.last_mod_file_date,
X lrec.last_mod_file_time);
X
X TTrace((stderr, "check_for_newer: existing %ld, archive %ld, e-a %ld\n",
X existing, archive, existing-archive));
X
X return (existing >= archive);
X
X} /* end function check_for_newer() */
X
X#endif /* !VMS && !OS2 */
X
X
X
X
X
X/*************************/
X/* Function find_ecrec() */
X/*************************/
X
Xint find_ecrec(searchlen) /* return PK-class error */
X long searchlen;
X{
X int i, numblks, found=FALSE;
X LONGINT tail_len;
X ec_byte_rec byterec;
X
X
X/*---------------------------------------------------------------------------
X Treat case of short zipfile separately.
X ---------------------------------------------------------------------------*/
X
X if (ziplen <= INBUFSIZ) {
X lseek(zipfd, 0L, SEEK_SET);
X if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)ziplen)) ==
X (int)ziplen)
X
X /* 'P' must be at least 22 bytes from end of zipfile */
X for (inptr = inbuf+(int)ziplen-22; inptr >= inbuf; --inptr)
X if ((native(*inptr) == 'P') &&
X !strncmp((char *)inptr, end_central_sig, 4)) {
X incnt -= inptr - inbuf;
X found = TRUE;
X break;
X }
X
X/*---------------------------------------------------------------------------
X Zipfile is longer than INBUFSIZ: may need to loop. Start with short
X block at end of zipfile (if not TOO short).
X ---------------------------------------------------------------------------*/
X
X } else {
X if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) {
X cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
X if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)tail_len)) !=
X (int)tail_len)
X goto fail; /* shut up; it's expedient */
X
X /* 'P' must be at least 22 bytes from end of zipfile */
X for (inptr = inbuf+(int)tail_len-22; inptr >= inbuf; --inptr)
X if ((native(*inptr) == 'P') &&
X !strncmp((char *)inptr, end_central_sig, 4)) {
X incnt -= inptr - inbuf;
X found = TRUE;
X break;
X }
X /* sig may span block boundary: */
X strncpy((char *)hold, (char *)inbuf, 3);
X } else
X cur_zipfile_bufstart = ziplen - tail_len;
X
X /*-----------------------------------------------------------------------
X Loop through blocks of zipfile data, starting at the end and going
X toward the beginning. In general, need not check whole zipfile for
X signature, but may want to do so if testing.
X -----------------------------------------------------------------------*/
X
X numblks = (int)((searchlen - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
X /* ==amount= ==done== ==rounding== =blksiz= */
X
X for (i = 1; !found && (i <= numblks); ++i) {
X cur_zipfile_bufstart -= INBUFSIZ;
X lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
X if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) != INBUFSIZ)
X break; /* fall through and fail */
X
X for (inptr = inbuf+INBUFSIZ-1; inptr >= inbuf; --inptr)
X if ((native(*inptr) == 'P') &&
X !strncmp((char *)inptr, end_central_sig, 4)) {
X incnt -= inptr - inbuf;
X found = TRUE;
X break;
X }
X /* sig may span block boundary: */
X strncpy((char *)hold, (char *)inbuf, 3);
X }
X } /* end if (ziplen > INBUFSIZ) */
X
X/*---------------------------------------------------------------------------
X Searched through whole region where signature should be without finding
X it. Print informational message and die a horrible death.
X ---------------------------------------------------------------------------*/
X
Xfail:
X if (!found) {
X#ifdef MSWIN
X MessageBeep(1);
X#endif
X if (qflag || (zipinfo_mode && !hflag))
X FPRINTF(stderr, "[%s]\n", zipfn);
X FPRINTF(stderr, LoadFarString(CentDirEndSigNotFound));
X return PK_ERR; /* failed */
X }
X
X/*---------------------------------------------------------------------------
X Found the signature, so get the end-central data before returning. Do
X any necessary machine-type conversions (byte ordering, structure padding
X compensation) by reading data into character array and copying to struct.
X ---------------------------------------------------------------------------*/
X
X real_ecrec_offset = cur_zipfile_bufstart + (inptr-inbuf);
X#ifdef TEST
X printf("\n found end-of-central-dir signature at offset %ld (%.8lXh)\n",
X real_ecrec_offset, real_ecrec_offset);
X printf(" from beginning of file; offset %d (%.4Xh) within block\n",
X inptr-inbuf, inptr-inbuf);
X#endif
X
X if (readbuf((char *)byterec, ECREC_SIZE+4) == 0)
X return PK_EOF;
X
X ecrec.number_this_disk =
X makeword(&byterec[NUMBER_THIS_DISK]);
X ecrec.num_disk_with_start_central_dir =
X makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
X ecrec.num_entries_centrl_dir_ths_disk =
X makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
X ecrec.total_entries_central_dir =
X makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
X ecrec.size_central_directory =
X makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
X ecrec.offset_start_central_directory =
X makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
X ecrec.zipfile_comment_length =
X makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
X
X expect_ecrec_offset = ecrec.offset_start_central_directory +
X ecrec.size_central_directory;
X return PK_COOL;
X
X} /* end function find_ecrec() */
X
X
X
X
X
X/***************************/
X/* Function get_cdir_ent() */
X/***************************/
X
Xint get_cdir_ent() /* return PK-type error code */
X{
X cdir_byte_hdr byterec;
X
X
X/*---------------------------------------------------------------------------
X Read the next central directory entry and do any necessary machine-type
X conversions (byte ordering, structure padding compensation--do so by
X copying the data from the array into which it was read (byterec) to the
X usable struct (crec)).
X ---------------------------------------------------------------------------*/
X
X if (readbuf((char *)byterec, CREC_SIZE) == 0)
X return PK_EOF;
X
X crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
X crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
X crec.version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
X crec.version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
X
X crec.general_purpose_bit_flag =
X makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
X crec.compression_method =
X makeword(&byterec[C_COMPRESSION_METHOD]);
X crec.last_mod_file_time =
X makeword(&byterec[C_LAST_MOD_FILE_TIME]);
X crec.last_mod_file_date =
X makeword(&byterec[C_LAST_MOD_FILE_DATE]);
X crec.crc32 =
X makelong(&byterec[C_CRC32]);
X crec.csize =
X makelong(&byterec[C_COMPRESSED_SIZE]);
X crec.ucsize =
X makelong(&byterec[C_UNCOMPRESSED_SIZE]);
X crec.filename_length =
X makeword(&byterec[C_FILENAME_LENGTH]);
X crec.extra_field_length =
X makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
X crec.file_comment_length =
X makeword(&byterec[C_FILE_COMMENT_LENGTH]);
X crec.disk_number_start =
X makeword(&byterec[C_DISK_NUMBER_START]);
X crec.internal_file_attributes =
X makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
X crec.external_file_attributes =
X makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */
X crec.relative_offset_local_header =
X makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
X
X return PK_COOL;
X
X} /* end function get_cdir_ent() */
X
X
X
X
X
X/************************/
X/* Function do_string() */
X/************************/
X
Xint do_string(len, option) /* return PK-type error code */
X unsigned int len; /* without prototype, ush converted to this */
X int option;
X{
X long comment_bytes_left, block_length;
X int error=PK_OK;
X ush extra_len;
X
X
X/*---------------------------------------------------------------------------
X This function processes arbitrary-length (well, usually) strings. Three
X options are allowed: SKIP, wherein the string is skipped (pretty logical,
X eh?); DISPLAY, wherein the string is printed to standard output after un-
X dergoing any necessary or unnecessary character conversions; and FILENAME,
X wherein the string is put into the filename[] array after undergoing ap-
X propriate conversions (including case-conversion, if that is indicated:
X see the global variable pInfo->lcflag). The latter option should be OK,
X since filename is now dimensioned at 1025, but we check anyway.
X
X The string, by the way, is assumed to start at the current file-pointer
X position; its length is given by len. So start off by checking length
X of string: if zero, we're already done.
X ---------------------------------------------------------------------------*/
X
X if (!len)
X return PK_COOL;
X
X switch (option) {
X
X /*
X * First case: print string on standard output. First set loop vari-
X * ables, then loop through the comment in chunks of OUTBUFSIZ bytes,
X * converting formats and printing as we go. The second half of the
X * loop conditional was added because the file might be truncated, in
X * which case comment_bytes_left will remain at some non-zero value for
X * all time. outbuf and slide are used as scratch buffers because they
X * are available (we should be either before or in between any file pro-
X * cessing).
X */
X
X case DISPLAY:
X comment_bytes_left = len;
X block_length = OUTBUFSIZ; /* for the while statement, first time */
X while (comment_bytes_left > 0 && block_length > 0) {
X#ifndef MSWIN
X register uch *p = outbuf;
X register uch *q = outbuf;
X#endif
X if ((block_length = readbuf((char *)outbuf,
X (unsigned) MIN((long)OUTBUFSIZ, comment_bytes_left))) == 0)
X return PK_EOF;
X comment_bytes_left -= block_length;
X
X /* this is why we allocated an extra byte for outbuf: */
X outbuf[block_length] = '\0'; /* terminate w/zero: ASCIIZ */
X
X /* remove all ASCII carriage returns comment before printing
X * (since used before A_TO_N(), check for CR instead of '\r')
X */
X while (*p) {
X while (*p == CR)
X ++p;
X *q++ = *p++;
X }
X /* could check whether (p - outbuf) == block_length here */
X *q = '\0';
X
X A_TO_N(outbuf); /* translate string to native */
X
X#ifdef MSWIN
X /* ran out of local mem -- had to cheat */
X WriteStringToMsgWin(outbuf, bRealTimeMsgUpdate);
X#else /* !MSWIN */
X#ifdef NATIVE
X PRINTF("%s", outbuf); /* GRR: can ANSI be used with EBCDIC? */
X#else /* ASCII */
X p = outbuf - 1;
X q = slide;
X while (*++p) {
X if (*p == 0x1B) { /* ASCII escape char */
X *q++ = '^';
X *q++ = '[';
X } else
X *q++ = *p;
X if ((unsigned)(q-slide) > WSIZE-3) { /* time to flush */
X *q = '\0';
X PRINTF("%s", slide);
X q = slide;
X }
X }
X *q = '\0';
X PRINTF("%s", slide);
X#endif /* ?NATIVE */
X#endif /* ?MSWIN */
X }
X PRINTF("\n"); /* assume no newline at end */
X break;
X
X /*
X * Second case: read string into filename[] array. The filename should
X * never ever be longer than FILNAMSIZ-1 (1024), but for now we'll check,
X * just to be sure.
X */
X
X case FILENAME:
X extra_len = 0;
X if (len >= FILNAMSIZ) {
X FPRINTF(stderr, LoadFarString(FilenameTooLongTrunc));
X error = PK_WARN;
X extra_len = len - FILNAMSIZ + 1;
X len = FILNAMSIZ - 1;
X }
X if (readbuf(filename, len) == 0)
X return PK_EOF;
X filename[len] = '\0'; /* terminate w/zero: ASCIIZ */
X
X A_TO_N(filename); /* translate string to native */
X
X if (pInfo->lcflag) /* replace with lowercase filename */
X TOLOWER(filename, filename);
X
X if (pInfo->vollabel && len > 8 && filename[8] == '.') {
X char *p = filename+8;
X while (*p++)
X p[-1] = *p; /* disk label, and 8th char is dot: remove dot */
X }
X
X if (!extra_len) /* we're done here */
X break;
X
X /*
X * We truncated the filename, so print what's left and then fall
X * through to the SKIP routine.
X */
X FPRINTF(stderr, "[ %s ]\n", filename);
X len = extra_len;
X /* FALL THROUGH... */
X
X /*
X * Third case: skip string, adjusting readbuf's internal variables
X * as necessary (and possibly skipping to and reading a new block of
X * data).
X */
X
X case SKIP:
X LSEEK(cur_zipfile_bufstart + (inptr-inbuf) + len)
X break;
X
X /*
X * Fourth case: assume we're at the start of an "extra field"; malloc
X * storage for it and read data into the allocated space.
X */
X
X case EXTRA_FIELD:
X if (extra_field != (uch *)NULL)
X free(extra_field);
X if ((extra_field = (uch *)malloc(len)) == (uch *)NULL) {
X FPRINTF(stderr, LoadFarString(ExtraFieldTooLong), len);
X LSEEK(cur_zipfile_bufstart + (inptr-inbuf) + len)
X } else
X if (readbuf((char *)extra_field, len) == 0)
X return PK_EOF;
X break;
X
X } /* end switch (option) */
X return error;
X
X} /* end function do_string() */
X
X
X
X
X
X/***********************/
X/* Function makeword() */
X/***********************/
X
Xush makeword(b)
X uch *b;
X{
X /*
X * Convert Intel style 'short' integer to non-Intel non-16-bit
X * host format. This routine also takes care of byte-ordering.
X */
X return (ush)((b[1] << 8) | b[0]);
X}
X
X
X
X
X
X/***********************/
X/* Function makelong() */
X/***********************/
X
Xulg makelong(sig)
X uch *sig;
X{
X /*
X * Convert intel style 'long' variable to non-Intel non-16-bit
X * host format. This routine also takes care of byte-ordering.
X */
X return (((ulg)sig[3]) << 24)
X + (((ulg)sig[2]) << 16)
X + (((ulg)sig[1]) << 8)
X + ((ulg)sig[0]);
X}
X
X
X
X
X
X#ifdef ZMEM /* memset, memcpy for systems without them */
X
X/*********************/
X/* Function memset() */
X/*********************/
X
Xchar *memset(buf, init, len)
X register char *buf, init; /* buffer loc and initializer */
X register unsigned int len; /* length of the buffer */
X{
X char *start;
X
X start = buf;
X while (len--)
X *(buf++) = init;
X return start;
X}
X
X
X
X
X
X/*********************/
X/* Function memcpy() */
X/*********************/
X
Xchar *memcpy(dst, src, len)
X register char *dst, *src;
X register unsigned int len;
X{
X char *start;
X
X start = dst;
X while (len-- > 0)
X *dst++ = *src++;
X return start;
X}
X
X#endif /* ZMEM */
X
X
X
X
X
X/************************/
X/* Function zstrnicmp() */
X/************************/
X
Xint zstrnicmp(s1, s2, n)
X register char *s1, *s2;
X register int n;
X{
X for (; n > 0; --n, ++s1, ++s2) {
X
X if (ToLower(*s1) != ToLower(*s2))
X /* test includes early termination of one string */
X return (ToLower(*s1) < ToLower(*s2))? -1 : 1;
X
X if (*s1 == '\0') /* both strings terminate early */
X return 0;
X }
X return 0;
X}
X
X
X
X
X
X#ifdef REGULUS /* returns the inode number on success(!)...argh argh argh */
X# undef stat
X
X/********************/
X/* Function zstat() */
X/********************/
X
Xint zstat(p, s)
X char *p;
X struct stat *s;
X{
X return (stat(p,s) >= 0? 0 : (-1));
X}
X
X#endif /* REGULUS */
X
X
X
X
X
X#ifdef SMALL_MEM
X
Xchar rgchBigBuffer[512];
Xchar rgchSmallBuffer[96];
Xchar rgchSmallBuffer2[96];
X
X/******************************/
X/* Function LoadFarString() */ /* (and friends...) */
X/******************************/
X
Xchar *LoadFarString(char Far *sz)
X{
X (void)zfstrcpy(rgchBigBuffer, sz);
X return rgchBigBuffer;
X}
X
Xchar *LoadFarStringSmall(char Far *sz)
X{
X (void)zfstrcpy(rgchSmallBuffer, sz);
X return rgchSmallBuffer;
X}
X
Xchar *LoadFarStringSmall2(char Far *sz)
X{
X (void)zfstrcpy(rgchSmallBuffer2, sz);
X return rgchSmallBuffer2;
X}
X
X
X/*************************/
X/* Function zfstrcpy() */ /* portable clone of _fstrcpy() */
X/*************************/
X
Xchar Far * Far zfstrcpy(char Far *s1, const char Far *s2)
X{
X char Far *p = s1;
X
X while ((*s1++ = *s2++) != '\0');
X return p;
X}
X
X#endif /* SMALL_MEM */
END_OF_FILE
if test 35360 -ne `wc -c <'unzip-5.12/file_io.c'`; then
echo shar: \"'unzip-5.12/file_io.c'\" unpacked with wrong size!
fi
# end of 'unzip-5.12/file_io.c'
fi
if test -f 'unzip-5.12/tops20/make.mic' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'unzip-5.12/tops20/make.mic'\"
else
echo shar: Extracting \"'unzip-5.12/tops20/make.mic'\" \(369 characters\)
sed "s/^X//" >'unzip-5.12/tops20/make.mic' <<'END_OF_FILE'
X@te no pau e
X@cc -c -q unzip
X@cc -c -q crypt
X@cc -c -q envarg
X@cc -c -q explod
X@cc -c -q extrac
X@cc -c -q fileio
X@cc -c -q inflat
X@cc -c -q match
X@cc -c -q unredu
X@cc -c -q unshri
X@cc -c -q zipinf
X@cc -c -q tops20
X@cc -o unzip unzip.rel crypt.rel envarg.rel explod.rel extrac.rel fileio.rel inflat.rel match.rel unredu.rel unshri.rel zipinf.rel tops20.rel -ltmx
X@kmic
END_OF_FILE
if test 369 -ne `wc -c <'unzip-5.12/tops20/make.mic'`; then
echo shar: \"'unzip-5.12/tops20/make.mic'\" unpacked with wrong size!
fi
# end of 'unzip-5.12/tops20/make.mic'
fi
if test -f 'unzip-5.12/unix/unix.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'unzip-5.12/unix/unix.c'\"
else
echo shar: Extracting \"'unzip-5.12/unix/unix.c'\" \(30753 characters\)
sed "s/^X//" >'unzip-5.12/unix/unix.c' <<'END_OF_FILE'
X/*---------------------------------------------------------------------------
X
X unix.c
X
X Unix-specific routines for use with Info-ZIP's UnZip 5.1 and later.
X
X Contains: readdir()
X do_wild() <-- generic enough to put in file_io.c?
X mapattr()
X mapname()
X checkdir()
X mkdir()
X close_outfile()
X version()
X
X ---------------------------------------------------------------------------*/
X
X
X#include "unzip.h"
X
X/* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
X#if defined(__convexc__) || defined(SYSV) || defined(CRAY) || defined(BSD4_4)
X# define DIRENT
X#endif
X#if defined(_AIX)
X# define DIRENT
X#endif
X#ifdef COHERENT
X# if defined(_I386) || (defined(__COHERENT__) && (__COHERENT__ >= 0x420))
X# define DIRENT
X# endif
X#endif
X
X/* GRR: may need to uncomment one or both of these for the relevant systems */
X
X#if 0
X#if defined(_POSIX_VERSION)
X# define DIRENT
X#endif
X#endif
X
X#if 0
X#if defined(M_XENIX)
X# define SYSNDIR
X#endif
X#endif
X
X#ifdef DIRENT
X# include <dirent.h>
X#else
X# ifdef SYSV
X# ifdef SYSNDIR
X# include <sys/ndir.h>
X# else
X# include <ndir.h>
X# endif
X# else /* !SYSV */
X# ifndef NO_SYSDIR
X# include <sys/dir.h>
X# endif
X# endif /* ?SYSV */
X# ifndef dirent
X# define dirent direct
X# endif
X#endif /* ?DIRENT */
X
Xstatic int created_dir; /* used in mapname(), checkdir() */
Xstatic int renamed_fullpath; /* ditto */
X
X
X#ifndef SFX
X#ifdef NO_DIR /* for AT&T 3B1 */
X
X#define opendir(path) fopen(path,"r")
X#define closedir(dir) fclose(dir)
Xtypedef FILE DIR;
X
X/*
X * Apparently originally by Rich Salz.
X * Cleaned up and modified by James W. Birdsall.
X */
Xstruct dirent *readdir(dirp)
X DIR *dirp;
X{
X static struct dirent entry;
X
X if (dirp == NULL)
X return NULL;
X
X for (;;)
X if (fread(&entry, sizeof (struct dirent), 1, dirp) == 0)
X return (struct dirent *)NULL;
X else if (entry.d_ino)
X return &entry;
X
X} /* end function readdir() */
X
X#endif /* NO_DIR */
X
X
X/**********************/
X/* Function do_wild() */ /* for porting: dir separator; match(ignore_case) */
X/**********************/
X
Xchar *do_wild(wildspec)
X char *wildspec; /* only used first time on a given dir */
X{
X static DIR *dir = (DIR *)NULL;
X static char *dirname, *wildname, matchname[FILNAMSIZ];
X static int firstcall=TRUE, have_dirname, dirnamelen;
X struct dirent *file;
X
X
X /* Even when we're just returning wildspec, we *always* do so in
X * matchname[]--calling routine is allowed to append four characters
X * to the returned string, and wildspec may be a pointer to argv[].
X */
X if (firstcall) { /* first call: must initialize everything */
X firstcall = FALSE;
X
X /* break the wildspec into a directory part and a wildcard filename */
X if ((wildname = strrchr(wildspec, '/')) == (char *)NULL) {
X dirname = ".";
X dirnamelen = 1;
X have_dirname = FALSE;
X wildname = wildspec;
X } else {
X ++wildname; /* point at character after '/' */
X dirnamelen = wildname - wildspec;
X if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
X FPRINTF(stderr, "warning: can't allocate wildcard buffers\n");
X strcpy(matchname, wildspec);
X return matchname; /* but maybe filespec was not a wildcard */
X }
X strncpy(dirname, wildspec, dirnamelen);
X dirname[dirnamelen] = '\0'; /* terminate for strcpy below */
X have_dirname = TRUE;
X }
X
X if ((dir = opendir(dirname)) != (DIR *)NULL) {
X while ((file = readdir(dir)) != (struct dirent *)NULL) {
X if (file->d_name[0] == '.' && wildname[0] != '.')
X continue; /* Unix: '*' and '?' do not match leading dot */
X if (match(file->d_name, wildname, 0)) { /* 0 == case sens. */
X if (have_dirname) {
X strcpy(matchname, dirname);
X strcpy(matchname+dirnamelen, file->d_name);
X } else
X strcpy(matchname, file->d_name);
X return matchname;
X }
X }
X /* if we get to here directory is exhausted, so close it */
X closedir(dir);
X dir = (DIR *)NULL;
X }
X
X /* return the raw wildspec in case that works (e.g., directory not
X * searchable, but filespec was not wild and file is readable) */
X strcpy(matchname, wildspec);
X return matchname;
X }
X
X /* last time through, might have failed opendir but returned raw wildspec */
X if (dir == (DIR *)NULL) {
X firstcall = TRUE; /* nothing left to try--reset for new wildspec */
X if (have_dirname)
X free(dirname);
X return (char *)NULL;
X }
X
X /* If we've gotten this far, we've read and matched at least one entry
X * successfully (in a previous call), so dirname has been copied into
X * matchname already.
X */
X while ((file = readdir(dir)) != (struct dirent *)NULL)
X if (match(file->d_name, wildname, 0)) { /* 0 == don't ignore case */
X if (have_dirname) {
X /* strcpy(matchname, dirname); */
X strcpy(matchname+dirnamelen, file->d_name);
X } else
X strcpy(matchname, file->d_name);
X return matchname;
X }
X
X closedir(dir); /* have read at least one dir entry; nothing left */
X dir = (DIR *)NULL;
X firstcall = TRUE; /* reset for new wildspec */
X if (have_dirname)
X free(dirname);
X return (char *)NULL;
X
X} /* end function do_wild() */
X
X#endif /* !SFX */
X
X
X
X
X
X/**********************/
X/* Function mapattr() */
X/**********************/
X
Xint mapattr()
X{
X ulg tmp = crec.external_file_attributes;
X
X switch (pInfo->hostnum) {
X case UNIX_:
X case VMS_:
X pInfo->file_attr = (unsigned)(tmp >> 16);
X return 0;
X case AMIGA_:
X tmp = (unsigned)(tmp>>17 & 7); /* Amiga RWE bits */
X pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
X break;
X /* all remaining cases: expand MSDOS read-only bit into write perms */
X case FS_FAT_:
X case FS_HPFS_:
X case FS_NTFS_:
X case MAC_:
X case ATARI_: /* (used to set = 0666) */
X case TOPS20_:
X default:
X tmp = !(tmp & 1) << 1; /* read-only bit --> write perms bits */
X pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
X break;
X } /* end switch (host-OS-created-by) */
X
X /* for originating systems with no concept of "group," "other," "system": */
X umask( (int)(tmp=umask(0)) ); /* apply mask to expanded r/w(/x) perms */
X pInfo->file_attr &= ~tmp;
X
X return 0;
X
X} /* end function mapattr() */
X
X
X
X
X
X/************************/
X/* Function mapname() */
X/************************/
X
Xint mapname(renamed) /* return 0 if no error, 1 if caution (filename trunc), */
X int renamed; /* 2 if warning (skip file because dir doesn't exist), */
X{ /* 3 if error (skip file), 10 if no memory (skip file) */
X char pathcomp[FILNAMSIZ]; /* path-component buffer */
X char *pp, *cp=(char *)NULL; /* character pointers */
X char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
X int quote = FALSE; /* flags */
X int error = 0;
X register unsigned workch; /* hold the character being tested */
X
X
X/*---------------------------------------------------------------------------
X Initialize various pointers and counters and stuff.
X ---------------------------------------------------------------------------*/
X
X if (pInfo->vollabel)
X return IZ_VOL_LABEL; /* can't set disk volume labels in Unix */
X
X /* can create path as long as not just freshening, or if user told us */
X create_dirs = (!fflag || renamed);
X
X created_dir = FALSE; /* not yet */
X
X /* user gave full pathname: don't prepend rootpath */
X renamed_fullpath = (renamed && (*filename == '/'));
X
X if (checkdir((char *)NULL, INIT) == 10)
X return 10; /* initialize path buffer, unless no memory */
X
X *pathcomp = '\0'; /* initialize translation buffer */
X pp = pathcomp; /* point to translation buffer */
X if (jflag) /* junking directories */
X cp = (char *)strrchr(filename, '/');
X if (cp == (char *)NULL) /* no '/' or not junking dirs */
X cp = filename; /* point to internal zipfile-member pathname */
X else
X ++cp; /* point to start of last component of path */
X
X/*---------------------------------------------------------------------------
X Begin main loop through characters in filename.
X ---------------------------------------------------------------------------*/
X
X while ((workch = (uch)*cp++) != 0) {
X
X if (quote) { /* if character quoted, */
X *pp++ = (char)workch; /* include it literally */
X quote = FALSE;
X } else
X switch (workch) {
X case '/': /* can assume -j flag not given */
X *pp = '\0';
X if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
X return error;
X pp = pathcomp; /* reset conversion buffer for next piece */
X lastsemi = (char *)NULL; /* leave directory semi-colons alone */
X break;
X
X case ';': /* VMS version (or DEC-20 attrib?) */
X lastsemi = pp;
X *pp++ = ';'; /* keep for now; remove VMS ";##" */
X break; /* later, if requested */
X
X case '\026': /* control-V quote for special chars */
X quote = TRUE; /* set flag for next character */
X break;
X
X#ifdef MTS
X case ' ': /* change spaces to underscore under */
X *pp++ = '_'; /* MTS; leave as spaces under Unix */
X break;
X#endif
X
X default:
X /* allow European characters in filenames: */
X if (isprint(workch) || (128 <= workch && workch <= 254))
X *pp++ = (char)workch;
X } /* end switch */
X
X } /* end while loop */
X
X *pp = '\0'; /* done with pathcomp: terminate it */
X
X /* if not saving them, remove VMS version numbers (appended ";###") */
X if (!V_flag && lastsemi) {
X pp = lastsemi + 1;
X while (isdigit((uch)(*pp)))
X ++pp;
X if (*pp == '\0') /* only digits between ';' and end: nuke */
X *lastsemi = '\0';
X }
X
X/*---------------------------------------------------------------------------
X Report if directory was created (and no file to create: filename ended
X in '/'), check name to be sure it exists, and combine path and name be-
X fore exiting.
X ---------------------------------------------------------------------------*/
X
X if (filename[strlen(filename) - 1] == '/') {
X checkdir(filename, GETPATH);
X if (created_dir && QCOND2) {
X FPRINTF(stdout, " creating: %s\n", filename);
X return IZ_CREATED_DIR; /* set dir time (note trailing '/') */
X }
X return 2; /* dir existed already; don't look for data to extract */
X }
X
X if (*pathcomp == '\0') {
X FPRINTF(stderr, "mapname: conversion of %s failed\n", filename);
X return 3;
X }
X
X checkdir(pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
X checkdir(filename, GETPATH);
X
X return error;
X
X} /* end function mapname() */
X
X
X
X
X#if 0 /*========== NOTES ==========*/
X
X extract-to dir: a:path/
X buildpath: path1/path2/ ... (NULL-terminated)
X pathcomp: filename
X
X mapname():
X loop over chars in zipfile member name
X checkdir(path component, COMPONENT | CREATEDIR) --> map as required?
X (d:/tmp/unzip/) (disk:[tmp.unzip.)
X (d:/tmp/unzip/jj/) (disk:[tmp.unzip.jj.)
X (d:/tmp/unzip/jj/temp/) (disk:[tmp.unzip.jj.temp.)
X finally add filename itself and check for existence? (could use with rename)
X (d:/tmp/unzip/jj/temp/msg.outdir) (disk:[tmp.unzip.jj.temp]msg.outdir)
X checkdir(name, COPYFREE) --> copy path to name and free space
X
X#endif /* 0 */
X
X
X
X
X/***********************/
X/* Function checkdir() */
X/***********************/
X
Xint checkdir(pathcomp, flag)
X char *pathcomp;
X int flag;
X/*
X * returns: 1 - (on APPEND_NAME) truncated filename
X * 2 - path doesn't exist, not allowed to create
X * 3 - path doesn't exist, tried to create and failed; or
X * path exists and is not a directory, but is supposed to be
X * 4 - path is too long
X * 10 - can't allocate memory for filename buffers
X */
X{
X static int rootlen = 0; /* length of rootpath */
X static char *rootpath; /* user's "extract-to" directory */
X static char *buildpath; /* full path (so far) to extracted file */
X static char *end; /* pointer to end of buildpath ('\0') */
X
X# define FN_MASK 7
X# define FUNCTION (flag & FN_MASK)
X
X
X
X/*---------------------------------------------------------------------------
X APPEND_DIR: append the path component to the path being built and check
X for its existence. If doesn't exist and we are creating directories, do
X so for this one; else signal success or error as appropriate.
X ---------------------------------------------------------------------------*/
X
X if (FUNCTION == APPEND_DIR) {
X int too_long = FALSE;
X#ifdef SHORT_NAMES
X char *old_end = end;
X#endif
X
X Trace((stderr, "appending dir segment [%s]\n", pathcomp));
X while ((*end = *pathcomp++) != '\0')
X ++end;
X#ifdef SHORT_NAMES /* path components restricted to 14 chars, typically */
X if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
X *(end = old_end + FILENAME_MAX) = '\0';
X#endif
X
X /* GRR: could do better check, see if overrunning buffer as we go:
X * check end-buildpath after each append, set warning variable if
X * within 20 of FILNAMSIZ; then if var set, do careful check when
X * appending. Clear variable when begin new path. */
X
X if ((end-buildpath) > FILNAMSIZ-3) /* need '/', one-char name, '\0' */
X too_long = TRUE; /* check if extracting directory? */
X if (stat(buildpath, &statbuf)) { /* path doesn't exist */
X if (!create_dirs) { /* told not to create (freshening) */
X free(buildpath);
X return 2; /* path doesn't exist: nothing to do */
X }
X if (too_long) {
X FPRINTF(stderr, "checkdir error: path too long: %s\n",
X buildpath);
X fflush(stderr);
X free(buildpath);
X return 4; /* no room for filenames: fatal */
X }
X if (mkdir(buildpath, 0777) == -1) { /* create the directory */
X FPRINTF(stderr, "checkdir error: can't create %s\n\
X unable to process %s.\n", buildpath, filename);
X fflush(stderr);
X free(buildpath);
X return 3; /* path didn't exist, tried to create, failed */
X }
X created_dir = TRUE;
X } else if (!S_ISDIR(statbuf.st_mode)) {
X FPRINTF(stderr, "checkdir error: %s exists but is not directory\n\
X unable to process %s.\n", buildpath, filename);
X fflush(stderr);
X free(buildpath);
X return 3; /* path existed but wasn't dir */
X }
X if (too_long) {
X FPRINTF(stderr, "checkdir error: path too long: %s\n", buildpath);
X fflush(stderr);
X free(buildpath);
X return 4; /* no room for filenames: fatal */
X }
X *end++ = '/';
X *end = '\0';
X Trace((stderr, "buildpath now = [%s]\n", buildpath));
X return 0;
X
X } /* end if (FUNCTION == APPEND_DIR) */
X
X/*---------------------------------------------------------------------------
X GETPATH: copy full path to the string pointed at by pathcomp, and free
X buildpath.
X ---------------------------------------------------------------------------*/
X
X if (FUNCTION == GETPATH) {
X strcpy(pathcomp, buildpath);
X Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
X free(buildpath);
X buildpath = end = (char *)NULL;
X return 0;
X }
X
X/*---------------------------------------------------------------------------
X APPEND_NAME: assume the path component is the filename; append it and
X return without checking for existence.
X ---------------------------------------------------------------------------*/
X
X if (FUNCTION == APPEND_NAME) {
X#ifdef SHORT_NAMES
X char *old_end = end;
X#endif
X
X Trace((stderr, "appending filename [%s]\n", pathcomp));
X while ((*end = *pathcomp++) != '\0') {
X ++end;
X#ifdef SHORT_NAMES /* truncate name at 14 characters, typically */
X if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
X *(end = old_end + FILENAME_MAX) = '\0';
X#endif
X if ((end-buildpath) >= FILNAMSIZ) {
X *--end = '\0';
X FPRINTF(stderr, "checkdir warning: path too long; truncating\n\
Xcheckdir warning: path too long; truncating\n\
X %s\n -> %s\n", filename, buildpath);
X fflush(stderr);
X return 1; /* filename truncated */
X }
X }
X Trace((stderr, "buildpath now = [%s]\n", buildpath));
X return 0; /* could check for existence here, prompt for new name... */
X }
X
X/*---------------------------------------------------------------------------
X INIT: allocate and initialize buffer space for the file currently being
X extracted. If file was renamed with an absolute path, don't prepend the
X extract-to path.
X ---------------------------------------------------------------------------*/
X
X/* GRR: for VMS and TOPS-20, add up to 13 to strlen */
X
X if (FUNCTION == INIT) {
X Trace((stderr, "initializing buildpath to "));
X if ((buildpath = (char *)malloc(strlen(filename)+rootlen+1)) ==
X (char *)NULL)
X return 10;
X if ((rootlen > 0) && !renamed_fullpath) {
X strcpy(buildpath, rootpath);
X end = buildpath + rootlen;
X } else {
X *buildpath = '\0';
X end = buildpath;
X }
X Trace((stderr, "[%s]\n", buildpath));
X return 0;
X }
X
X/*---------------------------------------------------------------------------
X ROOT: if appropriate, store the path in rootpath and create it if neces-
X sary; else assume it's a zipfile member and return. This path segment
X gets used in extracting all members from every zipfile specified on the
X command line.
X ---------------------------------------------------------------------------*/
X
X#if (!defined(SFX) || defined(SFX_EXDIR))
X if (FUNCTION == ROOT) {
X Trace((stderr, "initializing root path to [%s]\n", pathcomp));
X if (pathcomp == (char *)NULL) {
X rootlen = 0;
X return 0;
X }
X if ((rootlen = strlen(pathcomp)) > 0) {
X int had_trailing_pathsep=FALSE;
X
X if (pathcomp[rootlen-1] == '/') {
X pathcomp[--rootlen] = '\0';
X had_trailing_pathsep = TRUE;
X }
X if (rootlen > 0 && (stat(pathcomp, &statbuf) ||
X !S_ISDIR(statbuf.st_mode))) /* path does not exist */
X {
X if (!create_dirs /* || iswild(pathcomp) */
X#ifdef OLD_EXDIR
X || !had_trailing_pathsep
X#endif
X ) {
X rootlen = 0;
X return 2; /* skip (or treat as stored file) */
X }
X /* create the directory (could add loop here to scan pathcomp
X * and create more than one level, but why really necessary?) */
X if (mkdir(pathcomp, 0777) == -1) {
X FPRINTF(stderr,
X "checkdir: can't create extraction directory: %s\n",
X pathcomp);
X fflush(stderr);
X rootlen = 0; /* path didn't exist, tried to create, and */
X return 3; /* failed: file exists, or 2+ levels required */
X }
X }
X if ((rootpath = (char *)malloc(rootlen+2)) == (char *)NULL) {
X rootlen = 0;
X return 10;
X }
X strcpy(rootpath, pathcomp);
X rootpath[rootlen++] = '/';
X rootpath[rootlen] = '\0';
X }
X Trace((stderr, "rootpath now = [%s]\n", rootpath));
X return 0;
X }
X#endif /* !SFX || SFX_EXDIR */
X
X/*---------------------------------------------------------------------------
X END: free rootpath, immediately prior to program exit.
X ---------------------------------------------------------------------------*/
X
X if (FUNCTION == END) {
X Trace((stderr, "freeing rootpath\n"));
X if (rootlen > 0)
X free(rootpath);
X return 0;
X }
X
X return 99; /* should never reach */
X
X} /* end function checkdir() */
X
X
X
X
X
X#ifdef NO_MKDIR
X
X/********************/
X/* Function mkdir() */
X/********************/
X
Xint mkdir(path, mode)
X char *path;
X int mode; /* ignored */
X/*
X * returns: 0 - successful
X * -1 - failed (errno not set, however)
X */
X{
X char command[FILNAMSIZ+40]; /* buffer for system() call */
X
X /* GRR 930416: added single quotes around path to avoid bug with
X * creating directories with ampersands in name; not yet tested */
X sprintf(command, "IFS=\" \t\n\" /bin/mkdir '%s' 2>/dev/null", path);
X if (system(command))
X return -1;
X return 0;
X}
X
X#endif /* NO_MKDIR */
X
X
X
X
X
X#ifndef MTS
X
X/****************************/
X/* Function close_outfile() */
X/****************************/
X
Xvoid close_outfile()
X{
X static short yday[]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
X time_t m_time;
X int yr, mo, dy, hh, mm, ss, leap, days;
X struct utimbuf tp;
X# define YRBASE 1970
X#ifndef BSD4_4
X#ifdef BSD
X static struct timeb tbp;
X#else /* !BSD */
X extern long timezone;
X#endif /* ?BSD */
X#endif /* !BSD4_4 */
X
X
X/*---------------------------------------------------------------------------
X If symbolic links are supported, allocate a storage area, put the uncom-
X pressed "data" in it, and create the link. Since we know it's a symbolic
X link to start with, we shouldn't have to worry about overflowing unsigned
X ints with unsigned longs.
X ---------------------------------------------------------------------------*/
X
X#ifdef SYMLINKS
X if (symlnk) {
X unsigned ucsize = (unsigned)lrec.ucsize;
X char *linktarget = (char *)malloc((unsigned)lrec.ucsize+1);
X
X fclose(outfile); /* close "data" file... */
X outfile = fopen(filename, FOPR); /* ...and reopen for reading */
X if (!linktarget || (fread(linktarget, 1, ucsize, outfile) != ucsize)) {
X FPRINTF(stderr, "\nwarning: symbolic link (%s) failed\n",
X filename);
X if (linktarget)
X free(linktarget);
X fclose(outfile);
X return;
X }
X fclose(outfile); /* close "data" file for good... */
X unlink(filename); /* ...and delete it */
X linktarget[ucsize] = '\0';
X FPRINTF(stdout, "-> %s ", linktarget);
X if (symlink(linktarget, filename)) /* create the real link */
X perror("symlink error");
X free(linktarget);
X return; /* can't set time on symlinks */
X }
X#endif /* SYMLINKS */
X
X fclose(outfile);
X
X/*---------------------------------------------------------------------------
X Change the file permissions from default ones to those stored in the
X zipfile.
X ---------------------------------------------------------------------------*/
X
X#ifndef NO_CHMOD
X if (chmod(filename, 0xffff & pInfo->file_attr))
X perror("chmod (file attributes) error");
X#endif
X
X/*---------------------------------------------------------------------------
X Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
X time: adjust base year from 1980 to 1970, do usual conversions from
X yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
X light savings time differences.
X ---------------------------------------------------------------------------*/
X
X yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + (1980 - YRBASE);
X mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1;
X dy = (lrec.last_mod_file_date & 0x1f) - 1;
X hh = (lrec.last_mod_file_time >> 11) & 0x1f;
X mm = (lrec.last_mod_file_time >> 5) & 0x3f;
X ss = (lrec.last_mod_file_time & 0x1f) * 2;
X
X /* leap = # of leap yrs from YRBASE up to but not including current year */
X leap = ((yr + YRBASE - 1) / 4); /* leap year base factor */
X
X /* how many days from YRBASE to this year? (& add expired days this year) */
X days = (yr * 365) + (leap - 492) + yday[mo];
X
X /* if year is a leap year and month is after February, add another day */
X if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100))
X ++days; /* OK through 2199 */
X
X /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */
X m_time = ((days + dy) * 86400) + (hh * 3600) + (mm * 60) + ss;
X
X /* adjust for local timezone */
X#ifdef BSD
X#ifdef BSD4_4
X m_time -= localtime(&m_time)->tm_gmtoff; /* seconds EAST of GMT: subtr. */
X#else
X ftime(&tbp); /* get `timezone' */
X m_time += tbp.timezone * 60L; /* seconds WEST of GMT: add */
X#endif /* ?BSD4_4 */
X#else /* !BSD */
X tzset(); /* get `timezone' */
X m_time += timezone; /* seconds WEST of GMT: add */
X#endif /* ?BSD */
X
X /* adjust for daylight savings time (or local equivalent) */
X#ifndef BSD4_4 /* (DST already added to tm_gmtoff, so skip tm_isdst) */
X if (localtime(&m_time)->tm_isdst)
X m_time -= 60L * 60L; /* adjust for daylight savings time */
X#endif
X
X /* set the file's access and modification times */
X tp.actime = tp.modtime = m_time;
X if (utime(filename, &tp)) {
X#ifdef AOS_VS
X FPRINTF(stderr, "... can't set time for %s", filename);
X#else
X FPRINTF(stderr, "warning: can't set the time for %s\n", filename);
X#endif
X FFLUSH(stderr);
X }
X
X} /* end function close_outfile() */
X
X#endif /* !MTS */
X
X
X
X
X#ifndef SFX
X
X/************************/
X/* Function version() */
X/************************/
X
Xvoid version()
X{
X extern char Far CompiledWith[];
X#if defined(CRAY) || defined(NetBSD)
X char buf1[40];
X#if defined(CRAY)
X char buf2[40];
X#endif
X#endif
X
X PRINTF(LoadFarString(CompiledWith),
X
X#ifdef __GNUC__
X "gcc ", __VERSION__,
X#else
X# if defined(CRAY) && defined(_RELEASE)
X "cc ", (sprintf(buf1, "version %d", _RELEASE), buf1),
X# else
X# ifdef __VERSION__
X "cc ", __VERSION__,
X# else
X "cc", "",
X# endif
X# endif
X#endif
X
X "Unix",
X
X#if defined(sgi) || defined(__sgi)
X " (Silicon Graphics IRIX)",
X#else
X#ifdef sun
X# ifdef sparc
X# ifdef __SVR4
X " (Sun Sparc/Solaris)",
X# else /* may or may not be SunOS */
X " (Sun Sparc)",
X# endif
X# else
X# if defined(sun386) || defined(i386)
X " (Sun 386i)",
X# else
X# if defined(mc68020) || defined(__mc68020__)
X " (Sun 3)",
X# else /* mc68010 or mc68000: Sun 2 or earlier */
X " (Sun 2)",
X# endif
X# endif
X# endif
X#else
X#ifdef __hpux
X " (HP/UX)",
X#else
X#ifdef __osf__
X " (DEC OSF/1)",
X#else
X#ifdef _AIX
X " (IBM AIX)",
X#else
X#ifdef aiws
X " (IBM RT/AIX)",
X#else
X#if defined(CRAY) || defined(cray)
X# ifdef _UNICOS
X (sprintf(buf2, " (Cray UNICOS release %d)", _UNICOS), buf2),
X# else
X " (Cray UNICOS)",
X# endif
X#else
X#if defined(uts) || defined(UTS)
X " (Amdahl UTS)",
X#else
X#ifdef NeXT
X# ifdef mc68000
X " (NeXTStep/black)",
X# else
X " (NeXTStep for Intel)",
X# endif
X#else /* the next dozen or so are somewhat order-dependent */
X#ifdef LINUX
X " (Linux)",
X#else
X#ifdef MINIX
X " (Minix)",
X#else
X#ifdef M_UNIX
X " (SCO Unix)",
X#else
X#ifdef M_XENIX
X " (SCO Xenix)",
X#else
X#ifdef __NetBSD__
X# ifdef NetBSD0_8
X (sprintf(buf1, " (NetBSD 0.8%c)", (char)(NetBSD0_8 - 1 + 'A')), buf1),
X# else
X# ifdef NetBSD0_9
X (sprintf(buf1, " (NetBSD 0.9%c)", (char)(NetBSD0_9 - 1 + 'A')), buf1),
X# else
X# ifdef NetBSD1_0
X (sprintf(buf1, " (NetBSD 1.0%c)", (char)(NetBSD1_0 - 1 + 'A')), buf1),
X# else
X (BSD4_4 == 0.5)? " (NetBSD before 0.9)" : " (NetBSD 1.1 or later)",
X# endif
X# endif
X# endif
X#else
X#ifdef __FreeBSD__
X (BSD4_4 == 0.5)? " (FreeBSD 1.x)" : " (FreeBSD 2.0 or later)",
X#else
X#ifdef __bsdi__
X (BSD4_4 == 0.5)? " (BSD/386 1.0)" : " (BSD/386 1.1 or later)",
X#else
X#ifdef __386BSD__
X (BSD4_4 == 1)? " (386BSD, post-4.4 release)" : " (386BSD)",
X#else
X#if defined(i486) || defined(__i486) || defined(__i486__)
X " (Intel 486)",
X#else
X#if defined(i386) || defined(__i386) || defined(__i386__)
X " (Intel 386)",
X#else
X#ifdef pyr
X " (Pyramid)",
X#else
X#ifdef ultrix
X# ifdef mips
X " (DEC/MIPS)",
X# else
X# ifdef vax
X " (DEC/VAX)",
X# else /* __alpha? */
X " (DEC/Alpha)",
X# endif
X# endif
X#else
X#ifdef gould
X " (Gould)",
X#else
X#ifdef MTS
X " (MTS)",
X#else
X#ifdef __convexc__
X " (Convex)",
X#else
X "",
X#endif /* Convex */
X#endif /* MTS */
X#endif /* Gould */
X#endif /* DEC */
X#endif /* Pyramid */
X#endif /* 386 */
X#endif /* 486 */
X#endif /* 386BSD */
X#endif /* BSDI BSD/386 */
X#endif /* NetBSD */
X#endif /* FreeBSD */
X#endif /* SCO Xenix */
X#endif /* SCO Unix */
X#endif /* Minix */
X#endif /* Linux */
X#endif /* NeXT */
X#endif /* Amdahl */
X#endif /* Cray */
X#endif /* RT/AIX */
X#endif /* AIX */
X#endif /* OSF/1 */
X#endif /* HP/UX */
X#endif /* Sun */
X#endif /* SGI */
X
X#ifdef __DATE__
X " on ", __DATE__
X#else
X "", ""
X#endif
X );
X
X} /* end function version() */
X
X#endif /* !SFX */
END_OF_FILE
if test 30753 -ne `wc -c <'unzip-5.12/unix/unix.c'`; then
echo shar: \"'unzip-5.12/unix/unix.c'\" unpacked with wrong size!
fi
# end of 'unzip-5.12/unix/unix.c'
fi
echo shar: End of archive 10 \(of 20\).
cp /dev/null ark10isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 20 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...