/* =========================================================================== * 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; }
/* =========================================================================== * 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) */