aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorunknown <E:\Ladik\Mail>2015-04-18 16:58:14 +0200
committerunknown <E:\Ladik\Mail>2015-04-18 16:58:14 +0200
commitd47864c13d4d5015445343f652ef3d3b3b73cb25 (patch)
tree9f8ef9089f2e68a1ad2ed2ca27106e9ebaef1da0 /src
parentef12717cf92d9efb5dd32b1d1e3780c05fd83ee3 (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.cpp4
-rw-r--r--src/SFileListFile.cpp131
-rw-r--r--src/SFileOpenArchive.cpp4
-rw-r--r--src/StormLib.h56
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
{