diff options
author | unknown <E:\Ladik\Mail> | 2015-05-06 16:33:45 +0200 |
---|---|---|
committer | unknown <E:\Ladik\Mail> | 2015-05-06 16:33:45 +0200 |
commit | 3cfa7f2a1a81b226f5a5c3a43f4f9bd5704881f9 (patch) | |
tree | 8b99777e696e16f1cacc94b0b17b9b26a7b1d886 /src/SFileAddFile.cpp | |
parent | abd17ec91e0ab54a9d29af02c36710c1ed4b0ee0 (diff) |
+ Fixed possible stack overflow in HashStringJenkins
+ StormLib now creates a listfile even for empty archives to make sure it will be maintained at later point when files are added to it
+ Bug fixes in listfile loading
Diffstat (limited to 'src/SFileAddFile.cpp')
-rw-r--r-- | src/SFileAddFile.cpp | 174 |
1 files changed, 121 insertions, 53 deletions
diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp index 70a857b..ea3c5f9 100644 --- a/src/SFileAddFile.cpp +++ b/src/SFileAddFile.cpp @@ -80,6 +80,45 @@ static bool IsWaveFile_16BitsPerAdpcmSample( return false; } +static int FillWritableHandle( + TMPQArchive * ha, + TMPQFile * hf, + ULONGLONG FileTime, + DWORD dwFileSize, + DWORD dwFlags) +{ + TFileEntry * pFileEntry = hf->pFileEntry; + + // Initialize the hash entry for the file + hf->RawFilePos = ha->MpqPos + hf->MpqFilePos; + hf->dwDataSize = dwFileSize; + + // Initialize the block table entry for the file + pFileEntry->ByteOffset = hf->MpqFilePos; + pFileEntry->dwFileSize = dwFileSize; + pFileEntry->dwCmpSize = 0; + pFileEntry->dwFlags = dwFlags | MPQ_FILE_EXISTS; + + // Initialize the file time, CRC32 and MD5 + assert(sizeof(hf->hctx) >= sizeof(hash_state)); + memset(pFileEntry->md5, 0, MD5_DIGEST_SIZE); + md5_init((hash_state *)hf->hctx); + pFileEntry->dwCrc32 = crc32(0, Z_NULL, 0); + + // If the caller gave us a file time, use it. + pFileEntry->FileTime = FileTime; + + // Mark the archive as modified + ha->dwFlags |= MPQ_FLAG_CHANGED; + + // Call the callback, if needed + if(ha->pfnAddFileCB != NULL) + ha->pfnAddFileCB(ha->pvAddFileUserData, 0, hf->dwDataSize, false); + hf->nAddFileError = ERROR_SUCCESS; + + return ERROR_SUCCESS; +} + //----------------------------------------------------------------------------- // MPQ write data functions @@ -366,7 +405,6 @@ int SFileAddFile_Init( TMPQFile ** phf) { TFileEntry * pFileEntry = NULL; - ULONGLONG TempPos; // For various file offset calculations TMPQFile * hf = NULL; // File structure for newly added file DWORD dwHashIndex = HASH_ENTRY_FREE; int nError = ERROR_SUCCESS; @@ -395,28 +433,9 @@ int SFileAddFile_Init( lcLocale = 0; // Allocate the TMPQFile entry for newly added file - hf = CreateFileHandle(ha, NULL); + hf = CreateWritableHandle(ha, dwFileSize); if(hf == NULL) - nError = ERROR_NOT_ENOUGH_MEMORY; - - // Find a free space in the MPQ and verify if it's not over 4 GB on MPQs v1 - if(nError == ERROR_SUCCESS) - { - // Find the position where the file will be stored - hf->MpqFilePos = FindFreeMpqSpace(ha); - hf->RawFilePos = ha->MpqPos + hf->MpqFilePos; - hf->bIsWriteHandle = true; - - // When format V1, the size of the archive cannot exceed 4 GB - if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) - { - TempPos = hf->MpqFilePos + dwFileSize; - TempPos += ha->pHeader->dwHashTableSize * sizeof(TMPQHash); - TempPos += ha->dwFileTableSize * sizeof(TMPQBlock); - if((TempPos >> 32) != 0) - nError = ERROR_DISK_FULL; - } - } + nError = GetLastError(); // Allocate file entry in the MPQ if(nError == ERROR_SUCCESS) @@ -440,6 +459,24 @@ int SFileAddFile_Init( if(pFileEntry == NULL) nError = ERROR_DISK_FULL; } + + // Set the file entry to the file structure + hf->pFileEntry = pFileEntry; + } + + // Prepare the pointer to hash table entry + if(nError == ERROR_SUCCESS && ha->pHashTable != NULL && dwHashIndex < ha->pHeader->dwHashTableSize) + { + hf->pHashEntry = ha->pHashTable + dwHashIndex; + hf->pHashEntry->lcLocale = (USHORT)lcLocale; + } + + // Prepare the file key + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_ENCRYPTED)) + { + hf->dwFileKey = DecryptFileKey(szFileName, hf->MpqFilePos, dwFileSize, dwFlags); + if(hf->dwFileKey == 0) + nError = ERROR_UNKNOWN_FILE_KEY; } // Fill the file entry and TMPQFile structure @@ -449,46 +486,77 @@ int SFileAddFile_Init( assert(pFileEntry->szFileName != NULL); assert(_stricmp(pFileEntry->szFileName, szFileName) == 0); - // Initialize the hash entry for the file - hf->pFileEntry = pFileEntry; - hf->dwDataSize = dwFileSize; + nError = FillWritableHandle(ha, hf, FileTime, dwFileSize, dwFlags); + } - // Set the hash table entry - if(ha->pHashTable != NULL && dwHashIndex < ha->pHeader->dwHashTableSize) - { - hf->pHashEntry = ha->pHashTable + dwHashIndex; - hf->pHashEntry->lcLocale = (USHORT)lcLocale; - } + // Free the file handle if failed + if(nError != ERROR_SUCCESS && hf != NULL) + FreeFileHandle(hf); + + // Give the handle to the caller + *phf = hf; + return nError; +} + +int SFileAddFile_Init( + TMPQArchive * ha, + TMPQFile * hfSrc, + TMPQFile ** phf) +{ + TFileEntry * pFileEntry = NULL; + TMPQFile * hf = NULL; // File structure for newly added file + ULONGLONG FileTime = hfSrc->pFileEntry->FileTime; + DWORD dwFileSize = hfSrc->pFileEntry->dwFileSize; + DWORD dwFlags = hfSrc->pFileEntry->dwFlags; + int nError = ERROR_SUCCESS; + + // Allocate the TMPQFile entry for newly added file + hf = CreateWritableHandle(ha, dwFileSize); + if(hf == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; - // Decrypt the file key - if(dwFlags & MPQ_FILE_ENCRYPTED) - hf->dwFileKey = DecryptFileKey(szFileName, hf->MpqFilePos, dwFileSize, dwFlags); + // We need to keep the file entry index the same like in the source archive + // This is because multiple hash table entries can point to the same file entry + if(nError == ERROR_SUCCESS) + { + // Retrieve the file entry for the target file + pFileEntry = ha->pFileTable + (hfSrc->pFileEntry - hfSrc->ha->pFileTable); - // Initialize the block table entry for the file - pFileEntry->ByteOffset = hf->MpqFilePos; - pFileEntry->dwFileSize = dwFileSize; - pFileEntry->dwCmpSize = 0; - pFileEntry->dwFlags = dwFlags | MPQ_FILE_EXISTS; + // Copy all variables except file name + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0) + { + pFileEntry[0] = hfSrc->pFileEntry[0]; + pFileEntry->szFileName = NULL; + } + else + nError = ERROR_ALREADY_EXISTS; - // Initialize the file time, CRC32 and MD5 - assert(sizeof(hf->hctx) >= sizeof(hash_state)); - memset(pFileEntry->md5, 0, MD5_DIGEST_SIZE); - md5_init((hash_state *)hf->hctx); - pFileEntry->dwCrc32 = crc32(0, Z_NULL, 0); + // Set the file entry to the file structure + hf->pFileEntry = pFileEntry; + } - // If the caller gave us a file time, use it. - pFileEntry->FileTime = FileTime; + // Prepare the pointer to hash table entry + if(nError == ERROR_SUCCESS && ha->pHashTable != NULL && hfSrc->pHashEntry != NULL) + { + hf->dwHashIndex = (DWORD)(hfSrc->pHashEntry - hfSrc->ha->pHashTable); + hf->pHashEntry = ha->pHashTable + hf->dwHashIndex; + } - // Mark the archive as modified - ha->dwFlags |= MPQ_FLAG_CHANGED; + // Prepare the file key (copy from source file) + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_ENCRYPTED)) + { + hf->dwFileKey = hfSrc->dwFileKey; + if(hf->dwFileKey == 0) + nError = ERROR_UNKNOWN_FILE_KEY; + } - // Call the callback, if needed - if(ha->pfnAddFileCB != NULL) - ha->pfnAddFileCB(ha->pvAddFileUserData, 0, hf->dwDataSize, false); - hf->nAddFileError = ERROR_SUCCESS; + // Fill the file entry and TMPQFile structure + if(nError == ERROR_SUCCESS) + { + nError = FillWritableHandle(ha, hf, FileTime, dwFileSize, dwFlags); } - // Fre the file handle if failed + // Free the file handle if failed if(nError != ERROR_SUCCESS && hf != NULL) FreeFileHandle(hf); |