From fd57c987c4ccf920f4b167eb065df54bebe2bb20 Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Mon, 19 Oct 2009 22:36:17 +0000 Subject: [PATCH] Fix infinite loop in case an invalid pk3 file has been downloaded from the server. Thanks tjw for reporting (#3074) --- code/client/cl_curl.c | 3 +- code/client/cl_main.c | 20 +++++++++++- code/client/cl_parse.c | 2 -- code/qcommon/files.c | 72 +++++++++++++++++++++++++++++++++--------- code/qcommon/qcommon.h | 1 + 5 files changed, 78 insertions(+), 20 deletions(-) diff --git a/code/client/cl_curl.c b/code/client/cl_curl.c index a7f0879d..170e97b9 100644 --- a/code/client/cl_curl.c +++ b/code/client/cl_curl.c @@ -332,8 +332,7 @@ void CL_cURL_PerformDownload(void) qcurl_easy_strerror(msg->data.result), code, clc.downloadURL); } - *clc.downloadTempName = *clc.downloadName = 0; - Cvar_Set( "cl_downloadName", "" ); + CL_NextDownload(); } #endif /* USE_CURL */ diff --git a/code/client/cl_main.c b/code/client/cl_main.c index f435be01..029dba48 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -1916,11 +1916,25 @@ CL_NextDownload A download completed or failed ================= */ -void CL_NextDownload(void) { +void CL_NextDownload(void) +{ char *s; char *remoteName, *localName; qboolean useCURL = qfalse; + // A download has finished, check whether this matches a referenced checksum + if(*clc.downloadName) + { + char *zippath = FS_BuildOSPath(Cvar_VariableString("fs_homepath"), clc.downloadName, ""); + zippath[strlen(zippath)-1] = '\0'; + + if(!FS_CompareZipChecksum(zippath)) + Com_Error(ERR_DROP, "Incorrect checksum for file: %s", clc.downloadName); + } + + *clc.downloadTempName = *clc.downloadName = 0; + Cvar_Set("cl_downloadName", ""); + // We are looking to start a download here if (*clc.downloadList) { s = clc.downloadList; @@ -2027,6 +2041,10 @@ void CL_InitDownloads(void) { if ( *clc.downloadList ) { // if autodownloading is not enabled on the server cls.state = CA_CONNECTED; + + *clc.downloadTempName = *clc.downloadName = 0; + Cvar_Set( "cl_downloadName", "" ); + CL_NextDownload(); return; } diff --git a/code/client/cl_parse.c b/code/client/cl_parse.c index 588fe39b..687cb5f8 100644 --- a/code/client/cl_parse.c +++ b/code/client/cl_parse.c @@ -619,8 +619,6 @@ void CL_ParseDownload ( msg_t *msg ) { // rename the file FS_SV_Rename ( clc.downloadTempName, clc.downloadName ); } - *clc.downloadTempName = *clc.downloadName = 0; - Cvar_Set( "cl_downloadName", "" ); // send intentions now // We need this because without it, we would hold the last nextdl and then start diff --git a/code/qcommon/files.c b/code/qcommon/files.c index 249470be..3584e302 100644 --- a/code/qcommon/files.c +++ b/code/qcommon/files.c @@ -1660,7 +1660,7 @@ Creates a new pak_t in the search chain for the contents of a zip file. ================= */ -static pack_t *FS_LoadZipFile( char *zipfile, const char *basename ) +static pack_t *FS_LoadZipFile(const char *zipfile, const char *basename) { fileInPack_t *buildBuffer; pack_t *pack; @@ -1683,8 +1683,6 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename ) if (err != UNZ_OK) return NULL; - fs_packFiles += gi.number_entry; - len = 0; unzGoToFirstFile(uf); for (i = 0; i < gi.number_entry; i++) @@ -1751,8 +1749,8 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename ) unzGoToNextFile(uf); } - pack->checksum = Com_BlockChecksum( &fs_headerLongs[ 1 ], 4 * ( fs_numHeaderLongs - 1 ) ); - pack->pure_checksum = Com_BlockChecksum( fs_headerLongs, 4 * fs_numHeaderLongs ); + pack->checksum = Com_BlockChecksum( &fs_headerLongs[ 1 ], sizeof(*fs_headerLongs) * ( fs_numHeaderLongs - 1 ) ); + pack->pure_checksum = Com_BlockChecksum( fs_headerLongs, sizeof(*fs_headerLongs) * fs_numHeaderLongs ); pack->checksum = LittleLong( pack->checksum ); pack->pure_checksum = LittleLong( pack->pure_checksum ); @@ -1762,6 +1760,50 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename ) return pack; } +/* +================= +FS_FreePak + +Frees a pak structure and releases all associated resources +================= +*/ + +static void FS_FreePak(pack_t *thepak) +{ + unzClose(thepak->handle); + Z_Free(thepak->buildBuffer); + Z_Free(thepak); +} + +/* +================= +FS_GetZipChecksum + +Compares whether the given pak file matches a referenced checksum +================= +*/ +qboolean FS_CompareZipChecksum(const char *zipfile) +{ + pack_t *thepak; + int index, checksum; + + thepak = FS_LoadZipFile(zipfile, ""); + + if(!thepak) + return qfalse; + + checksum = thepak->checksum; + FS_FreePak(thepak); + + for(index = 0; index < fs_numServerReferencedPaks; index++) + { + if(checksum == fs_serverReferencedPaks[index]) + return qtrue; + } + + return qfalse; +} + /* ================================================================================= @@ -2466,6 +2508,8 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { continue; // store the game name for downloading strcpy(pak->pakGamename, dir); + + fs_packFiles += pak->numfiles; search = Z_Malloc (sizeof(searchpath_t)); search->pack = pak; @@ -2655,18 +2699,16 @@ void FS_Shutdown( qboolean closemfp ) { } // free everything - for ( p = fs_searchpaths ; p ; p = next ) { + for(p = fs_searchpaths; p; p = next) + { next = p->next; - if ( p->pack ) { - unzClose(p->pack->handle); - Z_Free( p->pack->buildBuffer ); - Z_Free( p->pack ); - } - if ( p->dir ) { - Z_Free( p->dir ); - } - Z_Free( p ); + if(p->pack) + FS_FreePak(p->pack); + if (p->dir) + Z_Free(p->dir); + + Z_Free(p); } // any FS_ calls will now be an error until reinitialized diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index d1cc2fde..566687cb 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -605,6 +605,7 @@ qboolean FS_FileExists( const char *file ); qboolean FS_CreatePath (char *OSPath); char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); +qboolean FS_CompareZipChecksum(const char *zipfile); int FS_LoadStack( void );