Archive-Unzip-Burst

 view release on metacpan or  search on metacpan

unzip-6.0/process.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
*/
/*---------------------------------------------------------------------------

  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 */

unzip-6.0/process.c  view on Meta::CPAN

            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;



( run in 1.247 second using v1.01-cache-2.11-cpan-5735350b133 )