コード例 #1
0
ファイル: UnzProc.cpp プロジェクト: geoffsmith82/delphizip
/* ===========================================================================
 *                     Function do_seekable()
 * return PK-type error code */
int UnzOpr::do_seekable(int lastchance)
{
	/* static int no_ecrec = FALSE;  SKM: moved to globals.h */
	ulg sig;
	struct stati64 stt64;
	int maybe_exe = false;
	int too_weird_to_continue = false;
	int error = 0, error_in_archive;

	if (Verbose < 0)
		Notify(ITRACE, _T("starting do_seekable"));

	/* ---------------------------------------------------------------------------
	 * Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
	 * which would corrupt the bit streams.
	 *--------------------------------------------------------------------------- */
	if (_tstati64(fzipfn.c_str(), &stt64) || (error = S_ISDIR(stt64.st_mode)) != 0)
		return error ? IZ_DIR : PK_NOZIP;

	fziplen = stt64.st_size;

	if (stt64.st_mode & S_IEXEC)
		maybe_exe = true;
	/* might find unzip, not unzip.zip; etc. */

	if (Verbose) // < 0)
		Notify(ITRACE, _T("opening zip file; fname=%s"), fzipfn.c_str());
	fUnzInfile = NULL;
	AutoStream uzfile(&fUnzInfile);

	fUnzInfile = new ZFile(this, fzipfn,
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS);
	if (!uzfile.Stream()->IsOpen())
	{
		if (Verbose < 0)
			Notify(ITRACE, _T("could not open: %s [%s]"), fzipfn.c_str(),
			SysMsg().c_str());

		throw DZException(DZ_ERM_ERROR_CREATE);
	}

	if (Verbose < 0)
		Notify(ITRACE, _T("zip file %s opened OK"), fzipfn.c_str());
	/* the stat() test above, but... */
	// if (Verbose < 0)
	// Notify(ITRACE, "do_seekable, loc 3");

	/* ---------------------------------------------------------------------------
	 * Find and process the end-of-central-directory header.  UnZip need only
	 * check last 65557 bytes of zipfile:  comment may be up to 65535, end-of-
	 * central-directory record is 18 bytes, and signature itself is 4 bytes;
	 * add some to allow for appended garbage.
	 *--------------------------------------------------------------------------- */

	fcur_zipfile_bufstart = 0;
	finptr = finbuf;

#ifdef TIMESTAMP
	if (!fqflag && !fT_flag)
#else
		if (!fqflag)
#endif

			Notify(0, _T("Archive:  %s"), fzipfn.c_str());

	if (Verbose < 0)
		Notify(ITRACE, _T("do_seekable, loc 4"));
	if ((((error_in_archive = find_ecrec(MIN(fziplen, 66000L))) != 0 ||
				((error_in_archive = uz_end_central()) != 0 && DZ_ERR
					(error_in_archive) != PK_WARN))))
	{
		delete fUnzInfile;
		fUnzInfile = NULL;

		if (maybe_exe)
			Notify(0, _T("maybe an EXE file: %s"), fzipfn.c_str());
		if (lastchance)
			return error_in_archive;
		else
		{
			fno_ecrec = true;
			/* assume we found wrong file:  e.g., */
			return PK_NOZIP;
			/* unzip instead of unzip.zip */
		}
	}

	if (Verbose < 0)
		Notify(ITRACE, _T("do_seekable, loc 5"));
	if (fzflag > 0)
	{
		delete fUnzInfile;
		fUnzInfile = NULL;
		return error_in_archive;
	}

	/* ---------------------------------------------------------------------------
	 * Test the end-of-central-directory info for incompatibilities (multi-disk
	 * archives) or inconsistencies (missing or extra bytes in zipfile).
	 *--------------------------------------------------------------------------- */
#ifdef NO_MULTIPART
	error = (fecrec.number_this_disk == 1) && (fecrec.num_disk_start_cdir == 1);
#else
	error = (fecrec.number_this_disk != 0);
#endif
#ifdef NO_MULTIPART /* concatenation of multiple parts works in some cases */
	// else
	if (!error && fecrec.number_this_disk != 0)
	{
		DZError(DZ_ERM_ZIP_MULTI);
		error_in_archive = PK_FIND;
		too_weird_to_continue = true;
	}
#endif

	if (Verbose < 0)
		Notify(ITRACE, _T("do_seekable, loc 6"));
	if (!too_weird_to_continue)
	{
		/* (relatively) normal zipfile:  go for it */
		if (error)
		{
			Notify(0, _T("maybe a pak bug in %s"), fzipfn.c_str());
			error_in_archive = PK_WARN;
		}

		if ((fextra_bytes = freal_ecrec_offset - fexpect_ecrec_offset) < 0L)
		{
			Notify(0, _T("missing bytes in zipfile"));
			error_in_archive = PK_ERR;
		}
		else if (fextra_bytes > 0)
		{
			if ((fecrec.offset_start_central_directory == 0) &&
				(fecrec.size_central_directory != 0))
			{
				/* zip 1.5 -go bug */
				Notify(0, _T("NULL central dir"));
				fecrec.offset_start_central_directory = fextra_bytes;
				fextra_bytes = 0;
				error_in_archive = PK_ERR;
			}
			else
			{
				Notify(0, _T("Warning: extra bytes at start of zipfile"));
				error_in_archive = PK_WARN;
			}
		}

		/* -----------------------------------------------------------------------
		 *       Check for empty zipfile and exit now if so.
		 *----------------------------------------------------------------------- */
		if (Verbose < 0)
			Notify(ITRACE, _T("do_seekable, loc 7"));
		if (fexpect_ecrec_offset == 0L && fecrec.size_central_directory == 0)
		{
			Notify(0, _T("Empty zipfile"));
			delete fUnzInfile;
			fUnzInfile = NULL;
			return PK_ERR_NOWARN(error_in_archive) ? error_in_archive : PK_WARN;
		}

		/* -----------------------------------------------------------------------
		 * Compensate for missing or extra bytes, and seek to where the start
		 * of central directory should be.  If header not found, uncompensate
		 * and try again (necessary for at least some Atari archives created
		 * with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
		 *----------------------------------------------------------------------- */
		zlseek(fecrec.offset_start_central_directory);
#ifdef OLD_SEEK_TEST
		if (readbuf((char*) & sig, 4) == 0)
		{
			close(fzipfd);
			fzipfd = 0;
			/* RCV added 29-1-99 */
			return PK_ERR;
			/* file may be locked, or possibly disk error(?) */
		}

		if (strncmp(fsig, fcentral_hdr_sig, 4))
#else
			if ((readbuf((char*) & sig, 4) == 0) || sig != CentralFileHeaderSig)
#endif
			{
				if (Verbose < 0)
					Notify(ITRACE, _T("central dir found"));
				fextra_bytes = 0;
				zlseek(fecrec.offset_start_central_directory);
				if ((readbuf((char*) & sig, 4) == 0)
					|| sig != CentralFileHeaderSig)
				{
					DZError(DZ_ERM_NO_CENTRAL);
					delete fUnzInfile;
					fUnzInfile = NULL;

					return PK_BADERR;
				}

				Notify(0, _T("central dir too long"));
				error_in_archive = PK_ERR;
			}

		/* -----------------------------------------------------------------------
		 * Seek to the start of the central directory one last time, since we
		 * have just read the first entry's signature bytes; then list, extract
		 * or test member files as instructed, and close the zipfile.
		 *----------------------------------------------------------------------- */
		if (Verbose < 0)
			Notify(ITRACE, _T("about to extract files (error = %d)"),
			error_in_archive);
		zlseek(fecrec.offset_start_central_directory);
		// GO DO EXTRACT OR TEST
		error = extract_or_test_files();
		/* EXTRACT OR TEST 'EM */

		if (Verbose < 0)
			Notify(ITRACE, _T("Done with extract/list files (error = %d)"),
			error);
		if (error > error_in_archive) /* don't overwrite stronger error */
				error_in_archive = error;
		/* with (for example) a warning */
	}
	/* end if (!too_weird_to_continue) */

	delete fUnzInfile;
	fUnzInfile = NULL;

	return error_in_archive;
}
コード例 #2
0
ファイル: Process.c プロジェクト: halaszk/old-delphi-codes
/* ===========================================================================
 *									Function do_seekable()
 * return PK-type error code
 */
static int do_seekable( struct Globals *pG, int lastchance ) {
	/* static int no_ecrec = FALSE;  SKM: moved to globals.h */
	int maybe_exe = false;
	int too_weird_to_continue = false;
	int error = 0, error_in_archive;

	diag( pG, "starting do_seekable" );
	/*---------------------------------------------------------------------------
	 * Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
	 * which would corrupt the bit streams.
	 *---------------------------------------------------------------------------*/
	if ( stat( pG->zipfn, &pG->statbuf ) || (error = S_ISDIR( pG->statbuf.st_mode )) != 0 ) {
		if ( lastchance )
			if ( pG->no_ecrec )
				printf( "can't find zip file dir" );
			else
				printf( "can't find either zip file" );
		return error ? IZ_DIR : PK_NOZIP;
	}
	pG->ziplen = pG->statbuf.st_size;

	if ( pG->statbuf.st_mode & S_IEXEC )
		maybe_exe = true;           /* might find unzip, not unzip.zip; etc. */

	diag( pG, "do_seekable, loc 2" );
	if ( open_input_file( pG ) )   /* this should never happen, given */
		return PK_NOZIP;            /* the stat() test above, but... */
	diag( pG, "do_seekable, loc 3" );
	/*---------------------------------------------------------------------------
	 * Find and process the end-of-central-directory header.  UnZip need only
	 * check last 65557 bytes of zipfile:  comment may be up to 65535, end-of-
	 * central-directory record is 18 bytes, and signature itself is 4 bytes;
	 * add some to allow for appended garbage.
	 *---------------------------------------------------------------------------*/
	/* initialize the CRC table pointer (once) */
	// EWE: This "get" of CRC table will be done again by crc32.c.
	// I have used a statically allocated table, so it doesn't matter.
	if ( CRC_32_TAB == NULL ) {
		if ( (CRC_32_TAB = (ulg *)get_crc_table()) == NULL ) return PK_MEM2;
	}
	pG->cur_zipfile_bufstart = 0;
	pG->inptr = pG->inbuf;

#ifdef TIMESTAMP
	if ( !pG->qflag && !pG->T_flag && !pG->zipinfo_mode )
#else
	if ( !pG->qflag && !pG->zipinfo_mode )
#endif
		printf( "Archive:  %s", pG->zipfn );

	diag( pG, "do_seekable, loc 4" );
	if ( ( ((error_in_archive = find_ecrec( pG, MIN( pG->ziplen, 66000L ))) != 0 ||
           (error_in_archive = uz_end_central( pG )) > PK_WARN)) ) {
		close( pG->zipfd );
		pG->zipfd = 0;		/* RCV added 29-1-99 */
		if ( maybe_exe ) printf( "maybe an EXE file: %s", pG->zipfn );
		if ( lastchance ) return error_in_archive;
		else {
			pG->no_ecrec = true;    /* assume we found wrong file:  e.g., */
			return PK_NOZIP;        /* unzip instead of unzip.zip         */
		}
	}
	diag( pG, "do_seekable, loc 5" );
	if ( pG->zflag > 0 && !pG->zipinfo_mode ) {  /* unzip: zflag = comment ONLY */
		close( pG->zipfd );
		pG->zipfd = 0;		/* RCV added 29-1-99 */
		return error_in_archive;
	}

	/*---------------------------------------------------------------------------
	 * Test the end-of-central-directory info for incompatibilities (multi-disk
	 * archives) or inconsistencies (missing or extra bytes in zipfile).
	 *---------------------------------------------------------------------------*/
#ifdef NO_MULTIPART
	error = !pG->zipinfo_mode && (pG->ecrec.number_this_disk == 1) &&
			(pG->ecrec.num_disk_start_cdir == 1);
#else
	error = !pG->zipinfo_mode && (pG->ecrec.number_this_disk != 0);
#endif

	if ( pG->zipinfo_mode && pG->ecrec.number_this_disk != pG->ecrec.num_disk_start_cdir ) {
		if ( pG->ecrec.number_this_disk > pG->ecrec.num_disk_start_cdir ) {
			UnzErr( pG, UEN_MISC01 );
			error_in_archive = PK_FIND;
			too_weird_to_continue = true;
		} else {
			printf( "Central dir bogus" );
			error_in_archive = PK_WARN;
		}
#ifdef NO_MULTIPART   /* concatenation of multiple parts works in some cases */
	} else if ( !pG->zipinfo_mode && !error && pG->ecrec.number_this_disk != 0 ) {
		UnzErr( pG, UEN_MISC02 );
		error_in_archive = PK_FIND;
		too_weird_to_continue = true;
#endif
	}

	diag( pG, "do_seekable, loc 6" );
	if ( !too_weird_to_continue ) {  /* (relatively) normal zipfile:  go for it */
		if ( error ) {
			printf( "maybe a pak bug in %s", pG->zipfn );
			error_in_archive = PK_WARN;
		}
		if ( (pG->extra_bytes = pG->real_ecrec_offset - pG->expect_ecrec_offset) < 0L ) {
			printf( "missing bytes in zipfile" );
			error_in_archive = PK_ERR;
		} else if ( pG->extra_bytes > 0 ) {
			if ( (pG->ecrec.offset_start_central_directory == 0) &&
                (pG->ecrec.size_central_directory != 0) ) {  /* zip 1.5 -go bug */
				printf( "NULL central dir" );
				pG->ecrec.offset_start_central_directory = pG->extra_bytes;
				pG->extra_bytes = 0;
				error_in_archive = PK_ERR;
			} else {
				printf( "Warning: extra bytes at start of zipfile" );
				error_in_archive = PK_WARN;
			}
		}

		/*-----------------------------------------------------------------------
		 *       Check for empty zipfile and exit now if so.
		 *-----------------------------------------------------------------------*/
		diag( pG, "do_seekable, loc 7" );
		if ( pG->expect_ecrec_offset == 0L && pG->ecrec.size_central_directory == 0 ) {
			printf( "Empty zipfile" );
			close( pG->zipfd );
			pG->zipfd = 0;		/* RCV added 29-1-99 */
			return (error_in_archive > PK_WARN) ? error_in_archive : PK_WARN;
		}

		/*-----------------------------------------------------------------------
		 * Compensate for missing or extra bytes, and seek to where the start
		 * of central directory should be.  If header not found, uncompensate
		 * and try again (necessary for at least some Atari archives created
		 * with STZip, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
		 *-----------------------------------------------------------------------*/
		ZLSEEK( pG->ecrec.offset_start_central_directory )
#ifdef OLD_SEEK_TEST
		if ( readbuf( pG->sig, 4 ) == 0 ) {
			close( pG->zipfd );
			pG->zipfd = 0;		/* RCV added 29-1-99 */
			return PK_ERR;		/* file may be locked, or possibly disk error(?) */
		}
		if ( strncmp( pG->sig, pG->central_hdr_sig, 4 ) )
#else
		if ( (readbuf( pG, pG->sig, 4 ) == 0) || strncmp( pG->sig, pG->central_hdr_sig, 4 ) )
#endif
		{
			// long tmp = pG->extra_bytes;

			diag( pG, "central dir found" );
			pG->extra_bytes = 0;
			ZLSEEK( pG->ecrec.offset_start_central_directory )
			if ( (readbuf( pG, pG->sig, 4 ) == 0 ) || strncmp( pG->sig, pG->central_hdr_sig, 4 ) ) {
				UnzErr( pG, UEN_FORM18 );
				close( pG->zipfd );
				pG->zipfd = 0;		/* RCV added 29-1-99 */
				return PK_BADERR;
			}
			printf( "central dir too long" );
			error_in_archive = PK_ERR;
		}
		/*-----------------------------------------------------------------------
		 * Seek to the start of the central directory one last time, since we
		 * have just read the first entry's signature bytes; then list, extract
		 * or test member files as instructed, and close the zipfile.
		 *-----------------------------------------------------------------------*/
		Trace( (pG, "about to extract/list files (error = %d)\n", error_in_archive) );
		ZLSEEK( pG->ecrec.offset_start_central_directory )

#ifdef TIMESTAMP
		// EWE  do some work here???
		// How can you timestamp a file before you extract it?
		//          if ( pG->T_flag )
		//              error = time_stamp( pG );              /* TIME-STAMP 'EM */
		//          else
#endif
		//          if ( pG->vflag && !pG->tflag && !pG->cflag )
		//              error = //list_files( pG );              /* LIST 'EM */
		//          else
		//              GO DO EXTRACT OR TEST
		error = extract_or_test_files( pG );   /* EXTRACT OR TEST 'EM */

		Trace( (pG, "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 */
	} /* end if (!too_weird_to_continue) */