Fixed renaming files vs file locale

This commit is contained in:
Ladislav Zezula
2025-08-06 09:34:58 +02:00
parent 65582d5649
commit db410fd564
7 changed files with 124 additions and 16 deletions

View File

@@ -25,9 +25,13 @@ if exist "%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Enterprise\VC\Auxilia
if exist "%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat
if exist "%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat
:: Build all libraries using Visual Studio 2008 and 202x
:: Build all libraries using Visual Studio 2008
rmdir /S /Q .\bin\%LIB_NAME%
if not "x%VCVARS_2008%" == "x" call :BuildLibs "%VCVARS_2008%" x86 %LIB_NAME%_vs08.sln vs2008
if not "x%VCVARS_2008%" == "x" call :BuildLibs "%VCVARS_2008%" x64 %LIB_NAME%_vs08.sln vs2008
:: Build all libraries using Visual Studio 2017+
rmdir /S /Q .\bin\%LIB_NAME%
if not "x%VCVARS_20xx%" == "x" call :BuildLibs "%VCVARS_20xx%" x86 %LIB_NAME%.sln
if not "x%VCVARS_20xx%" == "x" call :BuildLibs "%VCVARS_20xx%" x64 %LIB_NAME%.sln
goto:eof
@@ -92,7 +96,7 @@ devenv.com %1 /project "%LIB_NAME%" /rebuild "%5|%2"
if not exist ..\aaa goto:eof
if not exist ..\aaa\inc md ..\aaa\inc
if not exist ..\aaa\%3 md ..\aaa\%3
copy /Y /D .\src\StormLib.h ..\aaa\inc >nul
copy /Y /D .\src\StormPort.h ..\aaa\inc >nul
copy /Y /D .\bin\StormLib\%2\%5\%4.lib ..\aaa\%3\%4.lib >nul
copy /Y /D .\bin\StormLib\%2\%5\%4.pdb ..\aaa\%3\%4.pdb >nul
copy /Y .\src\StormLib.h ..\aaa\inc >nul
copy /Y .\src\StormPort.h ..\aaa\inc >nul
copy /Y .\bin\%LIB_NAME%\%2\%5\%4.lib ..\aaa\%3\%4.lib >nul
copy /Y .\bin\%LIB_NAME%\%2\%5\%4.pdb ..\aaa\%3\%4.pdb >nul

View File

@@ -20,10 +20,10 @@ echo.
:BUILD_BINARY_64
echo Building %BINARY_NAME%.lib (64-bit) ...
set DDKBUILDENV=
call %WDKDIR%\bin\setenv.bat %WDKDIR%\ fre x64 WLH
call %WDKDIR%\bin\setenv.bat %WDKDIR%\ fre x64 wnet
cd /d %PROJECT_DIR%
build.exe -czgw
del buildfre_wlh_amd64.log
del buildfre_wnet_amd64.log
echo.
:BUILD_BINARY_32
@@ -42,8 +42,8 @@ if not exist ..\aaa\lib32 md ..\aaa\lib32
if not exist ..\aaa\lib64 md ..\aaa\lib64
copy /Y .\src\StormLib.h ..\aaa\inc >nul
copy /Y .\src\StormPort.h ..\aaa\inc >nul
copy /Y .\objfre_wlh_amd64\amd64\%BINARY_NAME%.lib ..\aaa\lib64\%BINARY_NAME%.lib >nul
copy /Y .\objfre_w2k_x86\i386\%BINARY_NAME%.lib ..\aaa\lib32\%BINARY_NAME%.lib >nul
copy /Y .\objfre_wnet_amd64\amd64\%BINARY_NAME%.lib ..\aaa\lib64\%BINARY_NAME%.lib >nul
copy /Y .\objfre_w2k_x86\i386\%BINARY_NAME%.lib ..\aaa\lib32\%BINARY_NAME%.lib >nul
:CLEANUP
if exist sources-cpp.cpp del sources-cpp.cpp

View File

@@ -1163,8 +1163,11 @@ bool WINAPI SFileRemoveFile(HANDLE hMpq, const char * szFileName, DWORD dwSearch
bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szFileName, const char * szNewFileName)
{
TMPQArchive * ha = IsValidMpqHandle(hMpq);
TFileEntry * pFileEntry;
TMPQFile * hf;
DWORD dwHashIndex = 0;
DWORD dwErrCode = ERROR_SUCCESS;
LCID lcFileLocale = 0;
// Test the valid parameters
if(ha == NULL)
@@ -1181,11 +1184,25 @@ bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szFileName, const char * s
dwErrCode = ERROR_ACCESS_DENIED;
}
// Open the new file. If exists, we don't allow rename operation
// Retrieve the locale of the existing file
// Could be the preferred one or neutral one
if(dwErrCode == ERROR_SUCCESS && ha->pHashTable != NULL)
{
if((pFileEntry = GetFileEntryLocale(ha, szFileName, g_lcFileLocale, &dwHashIndex)) != NULL)
{
lcFileLocale = ha->pHashTable[dwHashIndex].Locale;
}
else
dwErrCode = ERROR_FILE_NOT_FOUND;
}
// The target file entry must not be there
if(dwErrCode == ERROR_SUCCESS)
{
if(GetFileEntryLocale(ha, szNewFileName, g_lcFileLocale) != NULL)
if(GetFileEntryExact(ha, szNewFileName, lcFileLocale) != NULL)
{
dwErrCode = ERROR_ALREADY_EXISTS;
}
}
// Open the file from the MPQ
@@ -1195,9 +1212,9 @@ bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szFileName, const char * s
if(SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_BASE_FILE, (HANDLE *)&hf))
{
ULONGLONG RawDataOffs;
TFileEntry * pFileEntry = hf->pFileEntry;
// Invalidate the entries for internal files
pFileEntry = hf->pFileEntry;
InvalidateInternalFiles(ha);
// Rename the file entry in the table
@@ -1266,15 +1283,21 @@ bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
TFileEntry * pFileEntry;
TMPQFile * hf = IsValidFileHandle(hFile);
// Invalid handle => do nothing
// Invalid file handle => return error
if(hf == NULL)
{
SErrSetLastError(ERROR_INVALID_HANDLE);
return false;
}
// Invalid archive handle => return error
if((ha = IsValidMpqHandle(hf->ha)) == NULL)
{
SErrSetLastError(ERROR_INVALID_HANDLE);
return false;
}
// Do not allow to rename files in MPQ open for read only
ha = hf->ha;
if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
{
SErrSetLastError(ERROR_ACCESS_DENIED);

View File

@@ -366,7 +366,7 @@ void FreeBetTable(TMPQBetTable * pBetTable);
// Functions for finding files in the file table
TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale, LPDWORD PtrHashIndex = NULL);
TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale, LPDWORD PtrHashIndex);
TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale, LPDWORD PtrHashIndex = NULL);
// Allocates file name in the file entry
void AllocateFileName(TMPQArchive * ha, TFileEntry * pFileEntry, const char * szFileName);

View File

@@ -9,7 +9,7 @@
static WRes GetError()
{
DWORD res = SErrGetLastError();
DWORD res = GetLastError();
return (res) ? (WRes)(res) : 1;
}

View File

@@ -1049,6 +1049,25 @@ static DWORD GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileN
return nPatchCount;
}
static DWORD SetLocaleForFileOperations(HANDLE hMpq, LPCSTR szFileName, LCID lcLocale)
{
HANDLE hFile = NULL;
DWORD dwErrCode = ERROR_SUCCESS;
if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile))
{
if(!SFileSetFileLocale(hFile, lcLocale))
dwErrCode = SErrGetLastError();
SFileSetLocale(lcLocale);
SFileCloseFile(hFile);
}
else
{
dwErrCode = SErrGetLastError();
}
return dwErrCode;
}
static DWORD VerifyFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, DWORD dwExpectedPatchCount)
{
DWORD dwPatchCount = 0;
@@ -3057,6 +3076,61 @@ static DWORD TestCreateArchive(const TEST_INFO2 & TestInfo)
return TestCreateArchive(szPlainNameT, TestInfo.szName2, TestInfo.dwFlags);
}
static DWORD TestRenameFile(LPCTSTR szPlainName)
{
TLogHelper Logger("TestRenameFile", szPlainName);
LPCSTR szSourceFile = "war3map.mmp";
LPCSTR szTargetFile = "war3map.wts";
HANDLE hMpq = NULL;
DWORD dwErrCode;
DWORD dwFailed = 0;
LCID LCID_RURU = 0x0419;
LCID LCID_ESES = 0x040A;
// Create copy of the archive and open it
dwErrCode = OpenExistingArchiveWithCopy(&Logger, szPlainName, szPlainName, &hMpq);
if(dwErrCode == ERROR_SUCCESS)
{
// Try to rename an existing file to "war3map.wts".
// This must fail because the file already exists.
if(SFileRenameFile(hMpq, szSourceFile, szTargetFile))
dwFailed++;
// Now change locale of an existing file to Russian
if(SetLocaleForFileOperations(hMpq, szSourceFile, LCID_RURU) != ERROR_SUCCESS)
dwFailed++;
// The rename should work now
if(!SFileRenameFile(hMpq, szSourceFile, szTargetFile))
dwFailed++;
// Changing the file locale to Neutral should fail now,
// because such file already exists
if(SetLocaleForFileOperations(hMpq, szTargetFile, 0) != ERROR_ALREADY_EXISTS)
dwFailed++;
// Pick another source file
szSourceFile = "war3map.shd";
// Change the file locale to Spain
if(SetLocaleForFileOperations(hMpq, szSourceFile, LCID_ESES) != ERROR_SUCCESS)
dwFailed++;
// This rename should also work, because there is no target file with Spanish locale
if(!SFileRenameFile(hMpq, szSourceFile, szTargetFile))
dwFailed++;
// Evaluate the result
if(dwFailed != 0)
dwErrCode = ERROR_CAN_NOT_COMPLETE;
SFileCloseArchive(hMpq);
}
// Restore the original file locale
SFileSetLocale(LANG_NEUTRAL);
return dwErrCode;
}
static DWORD TestCreateArchive_TestGaps(LPCTSTR szPlainName)
{
TLogHelper Logger("TestCreateGaps", szPlainName);
@@ -3322,6 +3396,7 @@ static DWORD TestCreateArchive_FileFlagTest(LPCTSTR szPlainName)
// Create paths for local file to be added
CreateFullPathName(szFileName1, _countof(szFileName1), szDataFileDir, _T("new-file.exe"));
CreateFullPathName(szFileName2, _countof(szFileName2), szDataFileDir, _T("new-file.bin"));
SFileSetLocale(LANG_NEUTRAL);
// Create an empty file that will serve as holder for the MPQ
dwErrCode = CreateEmptyFile(&Logger, szPlainName, 0x100000, szFullPath);
@@ -4503,6 +4578,11 @@ int _tmain(int argc, TCHAR * argv[])
#endif
#ifdef TEST_MISC_MPQS
// Test creating of an archive the same way like MPQ Editor does
if(dwErrCode == ERROR_SUCCESS)
dwErrCode = TestRenameFile(_T("MPQ_2002_v1_StrongSignature.w3m"));
// Test creating of an archive the same way like MPQ Editor does
if(dwErrCode == ERROR_SUCCESS)
dwErrCode = TestCreateArchive_TestGaps(_T("StormLibTest_GapsTest.mpq"));

View File

@@ -163,6 +163,7 @@ CreateNewMpq (StormLibTest_简体中文.mpq) succeeded.
CreateNewMpq (StormLibTest_الععربية.mpq) succeeded.
CreateNewMpq (StormLibTest_NonStdNames.mpq) succeeded.
CreateNewMpq (StormLibTest_MpqEditorTest.mpq) succeeded.
TestRenameFile (MPQ_2002_v1_StrongSignature.w3m) succeeded.
TestCreateGaps (StormLibTest_GapsTest.mpq) succeeded.
TestCreateFull (StormLibTest_FileTableFull.mpq) succeeded.
TestCreateFull (StormLibTest_FileTableFull.mpq) succeeded.