bool WINAPI SFileRemoveFile(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope) { TMPQArchive * ha = (TMPQArchive *)hMpq; TMPQBlockEx * pBlockEx = NULL; // Block entry of deleted file TMPQBlock * pBlock = NULL; // Block entry of deleted file TMPQHash * pHash = NULL; // Hash entry of deleted file DWORD dwBlockIndex = 0; int nError = ERROR_SUCCESS; // Check the parameters if(nError == ERROR_SUCCESS) { if(!IsValidMpqHandle(ha)) nError = ERROR_INVALID_HANDLE; if(dwSearchScope != SFILE_OPEN_BY_INDEX && *szFileName == 0) nError = ERROR_INVALID_PARAMETER; } if(nError == ERROR_SUCCESS) { // Do not allow to remove files from MPQ open for read only if(ha->dwFlags & MPQ_FLAG_READ_ONLY) nError = ERROR_ACCESS_DENIED; // Do not allow to remove internal files if(dwSearchScope != SFILE_OPEN_BY_INDEX) { if(IsInternalMpqFileName(szFileName)) nError = ERROR_INTERNAL_FILE; } } // Get hash entry belonging to this file if(nError == ERROR_SUCCESS) { if(dwSearchScope == SFILE_OPEN_FROM_MPQ) { if((pHash = GetHashEntryExact(ha, (char *)szFileName, lcFileLocale)) == NULL) nError = ERROR_FILE_NOT_FOUND; } else { if((pHash = GetHashEntryByIndex(ha, (DWORD)(DWORD_PTR)szFileName)) == NULL) nError = ERROR_FILE_NOT_FOUND; } } // If index was not found, or is greater than number of files, exit. if(nError == ERROR_SUCCESS) { if((dwBlockIndex = pHash->dwBlockIndex) > ha->pHeader->dwBlockTableSize) nError = ERROR_FILE_NOT_FOUND; } // Get block and test if the file is not already deleted if(nError == ERROR_SUCCESS) { pBlockEx = ha->pExtBlockTable + dwBlockIndex; pBlock = ha->pBlockTable + dwBlockIndex; if((pBlock->dwFlags & MPQ_FILE_EXISTS) == 0) nError = ERROR_FILE_NOT_FOUND; } // Remove the file from the list file if(nError == ERROR_SUCCESS) nError = SListFileRemoveNode(ha, pHash); if(nError == ERROR_SUCCESS) { // Now invalidate the block entry and the hash entry. Do not make any // relocations and file copying, use SFileCompactArchive for it. pBlockEx->wFilePosHigh = 0; pBlock->dwFilePos = 0; pBlock->dwFSize = 0; pBlock->dwCSize = 0; pBlock->dwFlags = 0; pHash->dwName1 = 0xFFFFFFFF; pHash->dwName2 = 0xFFFFFFFF; pHash->lcLocale = 0xFFFF; pHash->wPlatform = 0xFFFF; pHash->dwBlockIndex = HASH_ENTRY_DELETED; // Note: We don't decrease size of the block table, // even if this was the last blocktable entry. // Update MPQ archive ha->dwFlags |= MPQ_FLAG_CHANGED; } // Resolve error and exit if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
// Renames the file within the archive. BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * szNewFileName) { TMPQArchive * ha = (TMPQArchive *)hMPQ; TMPQBlock * pBlock; TMPQHash * pOldHash = NULL; // Hash entry for the original file TMPQHash * pNewHash = NULL; // Hash entry for the renamed file DWORD dwSaveBlockIndex = 0; LCID lcSaveLocale = 0; int nError = ERROR_SUCCESS; // Test the valid parameters if(nError == ERROR_SUCCESS) { if(hMPQ == NULL || szNewFileName == NULL || *szNewFileName == 0) nError = ERROR_INVALID_PARAMETER; if(szFileName == NULL || *szFileName == 0) nError = ERROR_INVALID_PARAMETER; } // Do not allow to rename listfile if(nError == ERROR_SUCCESS) { if(!_stricmp(szFileName, LISTFILE_NAME)) nError = ERROR_ACCESS_DENIED; } // Get the hash table entry for the original file if(nError == ERROR_SUCCESS) { if((pOldHash = GetHashEntryEx(ha, szFileName, lcLocale)) == NULL) nError = ERROR_FILE_NOT_FOUND; } // Test if the file already exists in the archive if(nError == ERROR_SUCCESS) { if((pNewHash = GetHashEntryEx(ha, szNewFileName, pOldHash->lcLocale)) != NULL) nError = ERROR_ALREADY_EXISTS; } // We have to know the decryption seed, otherwise we cannot re-crypt // the file after renaming if(nError == ERROR_SUCCESS) { // Save block table index and remove the hash table entry dwSaveBlockIndex = pOldHash->dwBlockIndex; lcSaveLocale = pOldHash->lcLocale; pBlock = ha->pBlockTable + dwSaveBlockIndex; // If the file is encrypted, we have to re-crypt the file content // with the new decryption seed if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED) { nError = RecryptFileData(ha, dwSaveBlockIndex, szFileName, szNewFileName); } } // Get the hash table entry for the renamed file if(nError == ERROR_SUCCESS) { SListFileRemoveNode(ha, szFileName, lcSaveLocale); pOldHash->dwName1 = 0xFFFFFFFF; pOldHash->dwName2 = 0xFFFFFFFF; pOldHash->lcLocale = 0xFFFF; pOldHash->wPlatform = 0xFFFF; pOldHash->dwBlockIndex = HASH_ENTRY_DELETED; if((pNewHash = FindFreeHashEntry(ha, szNewFileName)) == NULL) nError = ERROR_CAN_NOT_COMPLETE; } // Save the block index and clear the hash entry if(nError == ERROR_SUCCESS) { // Copy the block table index pNewHash->dwBlockIndex = dwSaveBlockIndex; pNewHash->lcLocale = (USHORT)lcSaveLocale; ha->dwFlags |= MPQ_FLAG_CHANGED; // Create new name node for the listfile nError = SListFileCreateNode(ha, szNewFileName, lcSaveLocale); } // Resolve error and return if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
// Renames the file within the archive. bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szFileName, const char * szNewFileName) { TMPQArchive * ha = (TMPQArchive *)hMpq; TMPQBlock * pBlock; TMPQHash * pOldHash = NULL; // Hash entry for the original file TMPQHash * pNewHash = NULL; // Hash entry for the renamed file TMPQFile * hf; DWORD dwOldBlockIndex = 0; LCID lcSaveLocale = 0; int nError = ERROR_SUCCESS; // Test the valid parameters if(nError == ERROR_SUCCESS) { if(!IsValidMpqHandle(ha)) nError = ERROR_INVALID_HANDLE; if(szFileName == NULL || *szFileName == 0 || szNewFileName == NULL || *szNewFileName == 0) nError = ERROR_INVALID_PARAMETER; } if(nError == ERROR_SUCCESS) { // Do not allow to rename files in MPQ open for read only if(ha->dwFlags & MPQ_FLAG_READ_ONLY) nError = ERROR_ACCESS_DENIED; // Do not allow to rename any of the internal files // Also do not allow to rename any of files to an internal file if(IsInternalMpqFileName(szFileName) || IsInternalMpqFileName(szNewFileName)) nError = ERROR_INTERNAL_FILE; } // Get the hash table entry for the original file if(nError == ERROR_SUCCESS) { if((pOldHash = GetHashEntryExact(ha, szFileName, lcFileLocale)) == NULL) nError = ERROR_FILE_NOT_FOUND; } // Test if the file already exists in the archive if(nError == ERROR_SUCCESS) { if((pNewHash = GetHashEntryExact(ha, szNewFileName, lcFileLocale)) != NULL) nError = ERROR_ALREADY_EXISTS; } // We have to know the decryption key, otherwise we cannot re-crypt // the file after renaming if(nError == ERROR_SUCCESS) { // Save block table index and remove the hash table entry dwOldBlockIndex = pOldHash->dwBlockIndex; lcSaveLocale = pOldHash->lcLocale; pBlock = ha->pBlockTable + dwOldBlockIndex; // If the file is encrypted, we have to re-crypt the file content // with the new decryption key if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED) { hf = CreateMpqFile(ha, "<renaming>"); if(hf != NULL) { hf->pHash = pOldHash; hf->pBlock = ha->pBlockTable + dwOldBlockIndex; hf->pBlockEx = ha->pExtBlockTable + dwOldBlockIndex; nError = RecryptFileData(ha, hf, szFileName, szNewFileName); FreeMPQFile(hf); } else { nError = ERROR_NOT_ENOUGH_MEMORY; } } } // Get the hash table entry for the renamed file if(nError == ERROR_SUCCESS) { SListFileRemoveNode(ha, pOldHash); pOldHash->dwName1 = 0xFFFFFFFF; pOldHash->dwName2 = 0xFFFFFFFF; pOldHash->lcLocale = 0xFFFF; pOldHash->wPlatform = 0xFFFF; pOldHash->dwBlockIndex = HASH_ENTRY_DELETED; // Note that this should always succeed; even if the hash table // was full, one entry was freed before. if((pNewHash = FindFreeHashEntry(ha, szNewFileName)) == NULL) nError = ERROR_CAN_NOT_COMPLETE; } // Save the block index and clear the hash entry if(nError == ERROR_SUCCESS) { // Copy the block table index pNewHash->dwBlockIndex = dwOldBlockIndex; pNewHash->lcLocale = (USHORT)lcSaveLocale; ha->dwFlags |= MPQ_FLAG_CHANGED; // Create new name node for the listfile nError = SListFileCreateNode(ha, szNewFileName, pNewHash); } // Resolve error and return if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope) { TMPQArchive * ha = (TMPQArchive *)hMPQ; TMPQBlockEx * pBlockEx = NULL; // Block entry of deleted file TMPQBlock * pBlock = NULL; // Block entry of deleted file TMPQHash * pHash = NULL; // Hash entry of deleted file DWORD dwBlockIndex = 0; int nError = ERROR_SUCCESS; // Check the parameters if(nError == ERROR_SUCCESS) { if(IsValidMpqHandle(ha) == FALSE) nError = ERROR_INVALID_PARAMETER; if(dwSearchScope != SFILE_OPEN_BY_INDEX && *szFileName == 0) nError = ERROR_INVALID_PARAMETER; } // Do not allow to remove listfile if(nError == ERROR_SUCCESS) { if(dwSearchScope != SFILE_OPEN_BY_INDEX && !_stricmp(szFileName, LISTFILE_NAME)) nError = ERROR_ACCESS_DENIED; } // Remove the file from the list file if(nError == ERROR_SUCCESS) nError = SListFileRemoveNode(ha, szFileName, lcLocale); // Get hash entry belonging to this file if(nError == ERROR_SUCCESS) { if((pHash = GetHashEntryEx(ha, (char *)szFileName, lcLocale)) == NULL) nError = ERROR_FILE_NOT_FOUND; } // If index was not found, or is greater than number of files, exit. if(nError == ERROR_SUCCESS) { if((dwBlockIndex = pHash->dwBlockIndex) > ha->pHeader->dwBlockTableSize) nError = ERROR_FILE_NOT_FOUND; } // Get block and test if the file is not already deleted if(nError == ERROR_SUCCESS) { pBlockEx = ha->pExtBlockTable + dwBlockIndex; pBlock = ha->pBlockTable + dwBlockIndex; if((pBlock->dwFlags & MPQ_FILE_EXISTS) == 0) nError = ERROR_FILE_NOT_FOUND; } // Now invalidate the block entry and the hash entry. Do not make any // relocations and file copying, use SFileCompactArchive for it. if(nError == ERROR_SUCCESS) { pBlockEx->wFilePosHigh = 0; pBlock->dwFilePos = 0; pBlock->dwFSize = 0; pBlock->dwCSize = 0; pBlock->dwFlags = 0; pHash->dwName1 = 0xFFFFFFFF; pHash->dwName2 = 0xFFFFFFFF; pHash->lcLocale = 0xFFFF; pHash->wPlatform = 0xFFFF; pHash->dwBlockIndex = HASH_ENTRY_DELETED; // Update MPQ archive ha->dwFlags |= MPQ_FLAG_CHANGED; } // Resolve error and exit if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }