diff options
author | unknown <E:\Ladik\Mail> | 2015-04-18 16:58:14 +0200 |
---|---|---|
committer | unknown <E:\Ladik\Mail> | 2015-04-18 16:58:14 +0200 |
commit | d47864c13d4d5015445343f652ef3d3b3b73cb25 (patch) | |
tree | 9f8ef9089f2e68a1ad2ed2ca27106e9ebaef1da0 /src | |
parent | ef12717cf92d9efb5dd32b1d1e3780c05fd83ee3 (diff) |
+ Fixed use-after-free in SListFileFindFirstFile
+ Replaces SFileMpqIsReadOnly with SFileMpqFlags
+ New MPQ flag: MPQ_FLAG_WAR3_MAP
Diffstat (limited to 'src')
-rw-r--r-- | src/SFileGetFileInfo.cpp | 4 | ||||
-rw-r--r-- | src/SFileListFile.cpp | 131 | ||||
-rw-r--r-- | src/SFileOpenArchive.cpp | 4 | ||||
-rw-r--r-- | src/StormLib.h | 56 |
4 files changed, 119 insertions, 76 deletions
diff --git a/src/SFileGetFileInfo.cpp b/src/SFileGetFileInfo.cpp index 9cf8038..753d2fd 100644 --- a/src/SFileGetFileInfo.cpp +++ b/src/SFileGetFileInfo.cpp @@ -603,11 +603,11 @@ bool WINAPI SFileGetFileInfo( } break; - case SFileMpqIsReadOnly: + case SFileMpqFlags: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { - dwInt32Value = (ha->dwFlags & MPQ_FLAG_READ_ONLY) ? 1 : 0; + dwInt32Value = ha->dwFlags; pvSrcFileInfo = &dwInt32Value; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; diff --git a/src/SFileListFile.cpp b/src/SFileListFile.cpp index ab6dff2..f5251bc 100644 --- a/src/SFileListFile.cpp +++ b/src/SFileListFile.cpp @@ -17,6 +17,7 @@ // Listfile entry structure #define CACHE_BUFFER_SIZE 0x1000 // Size of the cache buffer +#define MAX_LISTFILE_SIZE 0x04000000 // Maximum accepted listfile size is about 68 MB struct TListFileCache { @@ -106,6 +107,70 @@ static TListFileCache * CreateListFileCache(HANDLE hListFile, const char * szMas return pCache; } +#ifdef _DEBUG +/* +TMPQNameCache * CreateNameCache(HANDLE hListFile, const char * szSearchMask) +{ + TMPQNameCache * pNameCache; + char * szCachePointer; + size_t cbToAllocate; + size_t nMaskLength = 1; + DWORD dwBytesRead = 0; + DWORD dwFileSize; + + // Get the size of the listfile. Ignore zero or too long ones + dwFileSize = SFileGetFileSize(hListFile, NULL); + if(dwFileSize == 0 || dwFileSize > MAX_LISTFILE_SIZE) + return NULL; + + // Get the length of the search mask + if(szSearchMask == NULL) + szSearchMask = "*"; + nMaskLength = strlen(szSearchMask) + 1; + + // Allocate the name cache + cbToAllocate = sizeof(TMPQNameCache) + nMaskLength + dwFileSize + 1; + pNameCache = (TMPQNameCache *)STORM_ALLOC(BYTE, cbToAllocate); + if(pNameCache != NULL) + { + // Initialize the name cache + memset(pNameCache, 0, sizeof(TMPQNameCache)); + pNameCache->TotalCacheSize = (DWORD)(nMaskLength + dwFileSize + 1); + szCachePointer = (char *)(pNameCache + 1); + + // Copy the search mask, if any + memcpy(szCachePointer, szSearchMask, nMaskLength); + pNameCache->FirstNameOffset = (DWORD)nMaskLength; + pNameCache->FreeSpaceOffset = (DWORD)nMaskLength; + + // Read the listfile itself + SFileSetFilePointer(hListFile, 0, NULL, FILE_BEGIN); + SFileReadFile(hListFile, szCachePointer + nMaskLength, dwFileSize, &dwBytesRead, NULL); + + // If nothing has been read from the listfile, clear the cache + if(dwBytesRead == 0) + { + STORM_FREE(pNameCache); + return NULL; + } + + // Move the free space offset + pNameCache->FreeSpaceOffset = pNameCache->FirstNameOffset + dwBytesRead + 1; + szCachePointer[nMaskLength + dwBytesRead] = 0; + } + + return pNameCache; +} + +static void FreeNameCache(TMPQNameCache * pNameCache) +{ + if(pNameCache != NULL) + STORM_FREE(pNameCache); + pNameCache = NULL; +} +*/ +#endif // _DEBUG + // Reloads the cache. Returns number of characters // that has been loaded into the cache. static DWORD ReloadListFileCache(TListFileCache * pCache) @@ -568,54 +633,54 @@ HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const } // Open the local/internal listfile - if(!SFileOpenFileEx(hMpq, szListFile, dwSearchScope, &hListFile)) - nError = GetLastError(); - - // Load the listfile to cache - if(nError == ERROR_SUCCESS) - { - pCache = CreateListFileCache(hListFile, szMask); - if(pCache == NULL) - nError = ERROR_FILE_CORRUPT; - } - - // Perform file search - if(nError == ERROR_SUCCESS) + if(SFileOpenFileEx(hMpq, szListFile, dwSearchScope, &hListFile)) { - // The listfile handle is in the cache now - hListFile = NULL; +#ifdef _DEBUG +// TMPQNameCache * pNameCache = CreateNameCache(hListFile, szMask); +// FreeNameCache(pNameCache); +#endif - // Iterate through the listfile - for(;;) + // Load the listfile to cache + pCache = CreateListFileCache(hListFile, szMask); + if(pCache != NULL) { - // Read the (next) line - nLength = ReadListFileLine(pCache, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName)); - if(nLength == 0) + // Iterate through the listfile + for(;;) { - nError = ERROR_NO_MORE_FILES; - break; - } + // Read the (next) line + nLength = ReadListFileLine(pCache, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName)); + if(nLength == 0) + { + nError = ERROR_NO_MORE_FILES; + break; + } - // If some mask entered, check it - if(CheckWildCard(lpFindFileData->cFileName, pCache->szMask)) - break; + // If some mask entered, check it + if(CheckWildCard(lpFindFileData->cFileName, pCache->szMask)) + break; + } } + else + { + SFileCloseFile(hListFile); + nError = ERROR_FILE_CORRUPT; + } + } + else + { + nError = GetLastError(); } // Cleanup & exit if(nError != ERROR_SUCCESS) { - if(pCache != NULL) - FreeListFileCache(pCache); - pCache = NULL; - memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA)); + FreeListFileCache(pCache); SetLastError(nError); + pCache = NULL; } - // Close remaining unowned listfile handle - if(hListFile != NULL) - SFileCloseFile(hListFile); + // Return the listfile cache as handle return (HANDLE)pCache; } diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index 35e12d6..ffd5bfe 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -370,6 +370,10 @@ bool WINAPI SFileOpenArchive( if(dwFlags & (MPQ_OPEN_NO_LISTFILE | MPQ_OPEN_NO_ATTRIBUTES)) ha->dwFlags |= MPQ_FLAG_READ_ONLY; + // Remember whether whis is a map for Warcraft III + if(bIsWarcraft3Map) + ha->dwFlags |= MPQ_FLAG_WAR3_MAP; + // Set the size of file sector ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize); diff --git a/src/StormLib.h b/src/StormLib.h index af10f16..e523b3e 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -185,6 +185,7 @@ extern "C" { #define MPQ_FLAG_SIGNATURE_INVALID 0x00000100 // If set, it means that the (signature) has been invalidated #define MPQ_FLAG_SAVING_TABLES 0x00000200 // If set, we are saving MPQ internal files and MPQ tables #define MPQ_FLAG_PATCH 0x00000400 // If set, this MPQ is a patch archive +#define MPQ_FLAG_WAR3_MAP 0x00000800 // If set, this MPQ is a map for Warcraft III // Values for TMPQArchive::dwSubType #define MPQ_SUBTYPE_MPQ 0x00000000 // The file is a MPQ file (Blizzard games) @@ -406,7 +407,7 @@ typedef enum _SFileInfoClass SFileMpqNumberOfFiles, // Number of files (DWORD) SFileMpqRawChunkSize, // Size of the raw data chunk for MD5 SFileMpqStreamFlags, // Stream flags (DWORD) - SFileMpqIsReadOnly, // Nonzero if the MPQ is read only (DWORD) + SFileMpqFlags, // Nonzero if the MPQ is read only (DWORD) // Info classes for files SFileInfoPatchChain, // Chain of patches where the file is (TCHAR []) @@ -428,46 +429,6 @@ typedef enum _SFileInfoClass } SFileInfoClass; //----------------------------------------------------------------------------- -// Deprecated flags. These are going to be removed in next releases. - -/* - -STORMLIB_DEPRECATED_FLAG(DWORD, STREAM_PROVIDER_LINEAR, STREAM_PROVIDER_FLAT); -STORMLIB_DEPRECATED_FLAG(DWORD, STREAM_PROVIDER_ENCRYPTED, STREAM_PROVIDER_MPQE); -STORMLIB_DEPRECATED_FLAG(DWORD, MPQ_OPEN_ENCRYPTED, STREAM_PROVIDER_MPQE); -STORMLIB_DEPRECATED_FLAG(DWORD, MPQ_OPEN_PARTIAL, STREAM_PROVIDER_PARTIAL); - -// MPQ_FILE_COMPRESSED is deprecated. Do not use. -STORMLIB_DEPRECATED_FLAG(DWORD, MPQ_FILE_COMPRESSED, MPQ_FILE_COMPRESS_MASK); - -// Legacy values for file info classes. Included for backward compatibility, do not use. -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_ARCHIVE_NAME, SFileMpqFileName); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_ARCHIVE_SIZE, SFileMpqArchiveSize); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_MAX_FILE_COUNT, SFileMpqMaxFileCount); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_HASH_TABLE_SIZE, SFileMpqHashTableSize); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_BLOCK_TABLE_SIZE, SFileMpqBlockTableSize); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_SECTOR_SIZE, SFileMpqSectorSize); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_HASH_TABLE, SFileMpqHashTable); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_BLOCK_TABLE, SFileMpqBlockTable); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_NUM_FILES, SFileMpqNumberOfFiles); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_STREAM_FLAGS, SFileMpqStreamFlags); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_IS_READ_ONLY, SFileMpqIsReadOnly); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_HASH_INDEX, SFileInfoHashIndex); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_CODENAME1, SFileInfoNameHash1); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_CODENAME2, SFileInfoNameHash2); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_LOCALEID, SFileInfoLocale); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_BLOCKINDEX, SFileInfoFileIndex); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_FILE_SIZE, SFileInfoFileSize); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_COMPRESSED_SIZE, SFileInfoCompressedSize); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_FLAGS, SFileInfoFlags); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_POSITION, SFileInfoByteOffset); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_KEY, SFileInfoEncryptionKey); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_KEY_UNFIXED, SFileInfoEncryptionKeyRaw); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_FILETIME, SFileInfoFileTime); -STORMLIB_DEPRECATED_FLAG(SFileInfoClass, SFILE_INFO_PATCH_CHAIN, SFileInfoPatchChain); -*/ - -//----------------------------------------------------------------------------- // Callback functions // Values for compact callback @@ -834,6 +795,19 @@ typedef struct _TMPQNamePrefix char szPatchPrefix[1]; // Patch name prefix (variable length). If not empty, it always starts with backslash. } TMPQNamePrefix; +// Structure for name cache +typedef struct _TMPQNameCache +{ + DWORD FirstNameOffset; // Offset of the first name in the name list (in bytes) + DWORD FreeSpaceOffset; // Offset of the first free byte in the name cache (in bytes) + DWORD TotalCacheSize; // Size, in bytes, of the cache. Includes wildcard + DWORD SearchOffset; // Used by SListFileFindFirstFile + + // Followed by search mask (ASCIIZ, '\0' if none) + // Followed by name cache (ANSI multistring) + +} TMPQNameCache; + // Archive handle structure typedef struct _TMPQArchive { |