fixed long pk3 entry names causing crashes

when an entry was broken, pack_t::buildBuffer and fs_packFiles would end up wrong
This commit is contained in:
myT 2018-02-08 02:44:03 +01:00
parent 7bfc5d9487
commit 2e3f12c9a2
2 changed files with 52 additions and 15 deletions

View file

@ -23,6 +23,8 @@ chg: on Windows, a fatal error will move the early console window to the foregro
chg: com_hunkMegs doesn't have a maximum value anymore
a value too high would reset it and the engine might fail to load with the default value
fix: broken pk3 files could cause crashes (entry names too long) and mess up the FS
fix: using /demo when running a listen server would load the map and then abort playback
fix: no longer making local copies of all the system info cvars of the current server

View file

@ -1526,6 +1526,17 @@ ZIP FILE LOADING
==========================================================================
*/
static const char* FS_GetFileName( const char* filePath )
{
for ( int i = strlen(filePath) - 1; i >= 0; i-- ) {
if ( filePath[i] == '/' || filePath[i] == '\\' ) {
return filePath + i + 1;
}
}
return filePath;
}
/*
=================
FS_LoadZipFile
@ -1534,7 +1545,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 )
{
unzFile uf;
int err;
@ -1544,6 +1555,8 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename )
int i, len;
long hash;
int fs_numHeaderLongs;
int fileCount;
char* filename_lastchar = &filename_inzip[sizeof(filename_inzip) - 1];
fs_numHeaderLongs = 0;
@ -1553,29 +1566,42 @@ 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);
fileCount = 0;
for (i = 0; i < gi.number_entry; i++)
{
*filename_lastchar = '\0';
err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
if (err != UNZ_OK) {
Com_Printf("^3FS_LoadZipFile: ^7Can't read past entry %d in '%s'\n", i, FS_GetFileName(zipfile));
break;
}
if (*filename_lastchar != '\0') {
Com_Printf("^3FS_LoadZipFile: ^7Entry %d's name is too long in '%s'\n", i, FS_GetFileName(zipfile));
unzGoToNextFile(uf);
continue;
}
len += strlen(filename_inzip) + 1;
unzGoToNextFile(uf);
fileCount++;
}
fileInPack_t* buildBuffer = (fileInPack_t*)Z_Malloc( (gi.number_entry * sizeof( fileInPack_t )) + len );
char* namePtr = ((char*)buildBuffer) + gi.number_entry * sizeof( fileInPack_t );
int* fs_headerLongs = (int*)Z_Malloc( ( gi.number_entry + 1 ) * sizeof(int) );
if ( !fileCount ) {
unzClose(uf);
return NULL;
}
fileInPack_t* buildBuffer = (fileInPack_t*)Z_Malloc( (fileCount * sizeof( fileInPack_t )) + len );
char* namePtr = ((char*)buildBuffer) + fileCount * sizeof( fileInPack_t );
int* fs_headerLongs = (int*)Z_Malloc( ( fileCount + 1 ) * sizeof(int) );
fs_headerLongs[ fs_numHeaderLongs++ ] = LittleLong( fs_checksumFeed );
// get the hash table size from the number of files in the zip
// because lots of custom pk3 files have less than 32 or 64 files
for (i = 1; i <= MAX_FILEHASH_SIZE; i <<= 1) {
if (i > gi.number_entry) {
if (i > fileCount) {
break;
}
}
@ -1596,39 +1622,48 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename )
}
pack->handle = uf;
pack->numfiles = gi.number_entry;
pack->numfiles = fileCount;
unzGoToFirstFile(uf);
fileCount = 0;
for (i = 0; i < gi.number_entry; i++)
{
*filename_lastchar = '\0';
err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
if (err != UNZ_OK) {
break;
}
if (*filename_lastchar != '\0') {
unzGoToNextFile(uf);
continue;
}
if (file_info.uncompressed_size > 0) {
fs_headerLongs[fs_numHeaderLongs++] = LittleLong(file_info.crc);
}
Q_strlwr( filename_inzip );
hash = Q_FileHash( filename_inzip, pack->hashSize );
buildBuffer[i].name = namePtr;
strcpy( buildBuffer[i].name, filename_inzip );
buildBuffer[fileCount].name = namePtr;
strcpy( buildBuffer[fileCount].name, filename_inzip );
namePtr += strlen(filename_inzip) + 1;
// store the file position in the zip
unzGetCurrentFileInfoPosition(uf, &buildBuffer[i].pos);
//
buildBuffer[i].next = pack->hashTable[hash];
pack->hashTable[hash] = &buildBuffer[i];
unzGetCurrentFileInfoPosition(uf, &buildBuffer[fileCount].pos);
buildBuffer[fileCount].next = pack->hashTable[hash];
pack->hashTable[hash] = &buildBuffer[fileCount];
unzGoToNextFile(uf);
fileCount++;
}
pack->checksum = Com_BlockChecksum( &fs_headerLongs[ 1 ], 4 * ( fs_numHeaderLongs - 1 ) );
pack->pure_checksum = Com_BlockChecksum( fs_headerLongs, 4 * fs_numHeaderLongs );
pack->checksum = LittleLong( pack->checksum );
pack->pure_checksum = LittleLong( pack->pure_checksum );
pack->buildBuffer = buildBuffer;
Z_Free(fs_headerLongs);
pack->buildBuffer = buildBuffer;
fs_packFiles += fileCount;
return pack;
}