Skip to content

Commit 0f626fe

Browse files
committed
Addendum #2 to 2ab6fe0 (Sync up to code review fixes from master)
1 parent 35bdc25 commit 0f626fe

6 files changed

Lines changed: 47 additions & 59 deletions

File tree

Client/loader/CInstallManager.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,20 @@ void CInstallManager::SetMTASAPathSource(const SString& strCommandLineIn)
315315
// The override must be installed before UpdateSettingsForReportLog runs, because that helper
316316
// reaches GetInstallPathForLauncher / GetMTASAPath through UpdateMTAVersionApplicationSetting.
317317
const SString strRealInstallRoot = m_pSequencer->GetVariable(INSTALL_ROOT);
318-
if (!strRealInstallRoot.empty() && IsUsableMtasaInstallRoot(strRealInstallRoot) && !IsTemporaryUpdateLaunchPath(strRealInstallRoot))
318+
if (strRealInstallRoot.empty())
319+
{
320+
AddReportLog(1063, "CInstallManager::SetMTASAPathSource: no sequencer install root, falling back to registry");
321+
}
322+
else if (SharedUtil::IsUsableMtasaInstallRoot(strRealInstallRoot) && !SharedUtil::IsTemporaryUpdateLaunchPath(strRealInstallRoot))
323+
{
324+
AddReportLog(1063, SString("CInstallManager::SetMTASAPathSource: honoring sequencer install root '%s'", strRealInstallRoot.c_str()));
319325
SharedUtil::SetMTASABaseDirOverride(strRealInstallRoot);
326+
}
327+
else
328+
{
329+
AddReportLog(1063, SString("CInstallManager::SetMTASAPathSource: rejecting unusable sequencer install root '%s', falling back to registry",
330+
strRealInstallRoot.c_str()));
331+
}
320332

321333
::SetMTASAPathSource(true);
322334
}

Client/loader/Main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ namespace
150150

151151
// A temp updater shouldnt load the install root's core.dll before RunInstall;
152152
// the localization module stays loaded and would block replacement.
153-
if (!IsTemporaryUpdateLaunchPath(GetLaunchPath()))
153+
if (!SharedUtil::IsTemporaryUpdateLaunchPath(GetLaunchPath()))
154154
InitLocalization(false);
155155

156156
// Handle commands from the installer

Client/loader/Utils.cpp

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,8 @@ namespace
579579
DWORD valueType = REG_SZ;
580580
DWORD valueSize = 0;
581581
LONG result = RegQueryValueExW(hKey, wstrValueName.c_str(), nullptr, &valueType, nullptr, &valueSize);
582-
if (result != ERROR_SUCCESS || (valueType != REG_SZ && valueType != REG_EXPAND_SZ) || valueSize == 0 || valueSize > kMaxRegistryValueBytes)
582+
if (result != ERROR_SUCCESS || (valueType != REG_SZ && valueType != REG_EXPAND_SZ) || valueSize == 0 || valueSize > kMaxRegistryValueBytes ||
583+
(valueSize % sizeof(wchar_t)) != 0)
583584
{
584585
RegCloseKey(hKey);
585586
return "";
@@ -589,13 +590,11 @@ namespace
589590
result = RegQueryValueExW(hKey, wstrValueName.c_str(), nullptr, &valueType, reinterpret_cast<LPBYTE>(buffer.data()), &valueSize);
590591
RegCloseKey(hKey);
591592

592-
if (result != ERROR_SUCCESS || (valueType != REG_SZ && valueType != REG_EXPAND_SZ) || valueSize > kMaxRegistryValueBytes)
593+
if (result != ERROR_SUCCESS || (valueType != REG_SZ && valueType != REG_EXPAND_SZ) || valueSize > kMaxRegistryValueBytes ||
594+
(valueSize % sizeof(wchar_t)) != 0)
593595
return "";
594596

595-
if (valueSize >= sizeof(wchar_t))
596-
buffer[(valueSize / sizeof(wchar_t)) - 1u] = L'\0';
597-
else
598-
buffer[0] = L'\0';
597+
buffer[valueSize / sizeof(wchar_t)] = L'\0';
599598

600599
// Expand environment variable references for REG_EXPAND_SZ values so callers see a real
601600
// filesystem path. Without this, a value like "%ProgramFiles%\..." would fail validation.
@@ -620,7 +619,7 @@ namespace
620619
SString GetInstallPathForLauncher()
621620
{
622621
const SString strLaunchPath = GetLaunchPath();
623-
if (!IsTemporaryUpdateLaunchPath(strLaunchPath))
622+
if (!SharedUtil::IsTemporaryUpdateLaunchPath(strLaunchPath))
624623
return strLaunchPath;
625624

626625
// Prefer the resolved base dir over the registry when one was already established. In the
@@ -633,7 +632,7 @@ SString GetInstallPathForLauncher()
633632
// back into GetInstallPathForLauncher() and would recurse for any temp launcher whose g_strMTASAPath
634633
// has not yet been populated by the far-update sequencer path. Empty string falls through to the
635634
// per-view registry loop below, preserving the temp-launcher-without-far-update fallback.
636-
if (!g_strMTASAPath.empty() && IsUsableMtasaInstallRoot(g_strMTASAPath) && !IsTemporaryUpdateLaunchPath(g_strMTASAPath) &&
635+
if (!g_strMTASAPath.empty() && SharedUtil::IsUsableMtasaInstallRoot(g_strMTASAPath) && !SharedUtil::IsTemporaryUpdateLaunchPath(g_strMTASAPath) &&
637636
!g_strMTASAPath.CompareI(strLaunchPath))
638637
return g_strMTASAPath;
639638

@@ -651,7 +650,7 @@ SString GetInstallPathForLauncher()
651650
for (int i = 0; i < viewCount; ++i)
652651
{
653652
const SString strSavedInstallPath = ReadInstallRootRegistryView(viewFlags[i]);
654-
if (IsUsableMtasaInstallRoot(strSavedInstallPath) && !IsTemporaryUpdateLaunchPath(strSavedInstallPath))
653+
if (SharedUtil::IsUsableMtasaInstallRoot(strSavedInstallPath) && !SharedUtil::IsTemporaryUpdateLaunchPath(strSavedInstallPath))
655654
return strSavedInstallPath;
656655
}
657656

@@ -661,30 +660,6 @@ SString GetInstallPathForLauncher()
661660
return SString();
662661
}
663662

664-
bool IsUsableMtasaInstallRoot(const SString& strPath)
665-
{
666-
if (strPath.empty())
667-
return false;
668-
669-
return FileExists(PathJoin(strPath, "Multi Theft Auto.exe")) || FileExists(PathJoin(strPath, "Multi Theft Auto_d.exe")) ||
670-
FileExists(PathJoin(strPath, "mta", "core.dll")) || FileExists(PathJoin(strPath, "MTA", "core.dll")) ||
671-
FileExists(PathJoin(strPath, "mta", "core_d.dll")) || FileExists(PathJoin(strPath, "MTA", "core_d.dll"));
672-
}
673-
674-
bool IsTemporaryUpdateLaunchPath(const SString& strLaunchPath)
675-
{
676-
if (strLaunchPath.empty())
677-
return false;
678-
679-
if (!strLaunchPath.ContainsI("\\upcache\\"))
680-
return false;
681-
682-
// The auto-update flow creates the extraction directory in Install.cpp::CheckOnRestartCommand
683-
// as MakeUniquePath("...\\upcache\\_<archiveName>_tmp_"), so the leaf always begins with '_'.
684-
const SString strLeaf = ExtractFilename(strLaunchPath);
685-
return strLeaf.BeginsWith("_") && strLeaf.ContainsI("_tmp_");
686-
}
687-
688663
void SetMTASAPathSource(bool bReadFromRegistry)
689664
{
690665
if (bReadFromRegistry)
@@ -718,7 +693,7 @@ void SetMTASAPathSource(bool bReadFromRegistry)
718693
// values. A temp launcher started without the far-update sequencer state would otherwise
719694
// contaminate Last Run Location with an upcache\_*_tmp_* path that gets deleted later by
720695
// CleanDownloadCache, leaving a stale registry pointer that produces U01 on the next launch.
721-
if (IsTemporaryUpdateLaunchPath(strLaunchPath))
696+
if (SharedUtil::IsTemporaryUpdateLaunchPath(strLaunchPath))
722697
{
723698
AddReportLog(1063, SString("SetMTASAPathSource: refusing to record temp launch path '%s' in registry", strLaunchPath.c_str()));
724699
g_strMTASAPath = strLaunchPath;
@@ -1391,7 +1366,7 @@ void UpdateMTAVersionApplicationSetting(bool bQuiet)
13911366
bool bFreeModule = false;
13921367

13931368
const SString strInstallPath = GetInstallPathForLauncher();
1394-
if (IsUsableMtasaInstallRoot(strInstallPath))
1369+
if (SharedUtil::IsUsableMtasaInstallRoot(strInstallPath))
13951370
{
13961371
hModule = LoadVersionModule(strInstallPath, dwLastError);
13971372
bFreeModule = hModule != NULL;
@@ -1404,7 +1379,7 @@ void UpdateMTAVersionApplicationSetting(bool bQuiet)
14041379
if (!hModule)
14051380
{
14061381
const SString strBaseDirPath = GetMTASAPath();
1407-
if (IsUsableMtasaInstallRoot(strBaseDirPath) && !strBaseDirPath.CompareI(strInstallPath))
1382+
if (SharedUtil::IsUsableMtasaInstallRoot(strBaseDirPath) && !strBaseDirPath.CompareI(strInstallPath))
14081383
{
14091384
hModule = LoadVersionModule(strBaseDirPath, dwLastError);
14101385
bFreeModule = hModule != NULL;

Client/loader/Utils.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ auto GetGameBaseDirectory() -> std::filesystem::path;
7979
auto GetGameLaunchDirectory() -> std::filesystem::path;
8080
auto GetGameExecutablePath() -> std::filesystem::path;
8181
SString GetInstallPathForLauncher();
82-
bool IsUsableMtasaInstallRoot(const SString& strPath);
83-
bool IsTemporaryUpdateLaunchPath(const SString& strLaunchPath);
8482

8583
void SetMTASAPathSource(bool bReadFromRegistry);
8684
SString GetMTASAPath();

Shared/sdk/SharedUtil.Misc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ namespace SharedUtil
123123
//
124124
void SetMTASABaseDirOverride(const SString& strPath);
125125

126+
bool IsUsableMtasaInstallRoot(const SString& strPath);
127+
bool IsTemporaryUpdateLaunchPath(const SString& strLaunchPath);
128+
126129
//
127130
// Get startup directory as saved in the registry by the launcher
128131
// Used in the Win32 Client only

Shared/sdk/SharedUtil.Misc.hpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ void SharedUtil::SetMTASABaseDirOverride(const SString& strPath)
396396
strInstallRootOverride = strPath;
397397
}
398398

399-
static bool IsUsableMtasaInstallRoot(const SString& strPath)
399+
bool SharedUtil::IsUsableMtasaInstallRoot(const SString& strPath)
400400
{
401401
if (strPath.empty())
402402
return false;
@@ -406,22 +406,23 @@ static bool IsUsableMtasaInstallRoot(const SString& strPath)
406406
FileExists(PathJoin(strPath, "mta", "core_d.dll")) || FileExists(PathJoin(strPath, "MTA", "core_d.dll"));
407407
}
408408

409-
// A path inside upcache\_<archive>_tmp_<n> is a transient extraction directory used by the auto-update
410-
// flow. Such a path can satisfy IsUsableMtasaInstallRoot while it still exists, but it must never be
411-
// accepted as the durable MTA install root. The launcher-side helper in Client/loader/Utils.cpp uses
412-
// the same shape; if either copy changes, update both.
413-
static bool IsTemporaryUpdateLaunchPath(const SString& strLaunchPath)
409+
// A path inside upcache\_<archive>_tmp_<n> is an auto-update extraction directory.
410+
// It can look like a usable install root while it exists, but it must not be kept as the real install root.
411+
bool SharedUtil::IsTemporaryUpdateLaunchPath(const SString& strLaunchPath)
414412
{
415413
if (strLaunchPath.empty())
416414
return false;
417415

418-
if (!strLaunchPath.ContainsI("\\upcache\\"))
416+
const SString strNormalizedLaunchPath = PathConform(strLaunchPath).TrimEnd("\\");
417+
if (strNormalizedLaunchPath.empty())
419418
return false;
420419

421-
// The auto-update flow creates the extraction directory in Install.cpp::CheckOnRestartCommand
422-
// as MakeUniquePath("...\\upcache\\_<archiveName>_tmp_"), so the leaf always begins with '_'.
423-
const SString strLeaf = ExtractFilename(strLaunchPath);
424-
return strLeaf.BeginsWith("_") && strLeaf.ContainsI("_tmp_");
420+
const SString strLeaf = ExtractFilename(strNormalizedLaunchPath);
421+
if (!strLeaf.BeginsWith("_") || !strLeaf.ContainsI("_tmp_"))
422+
return false;
423+
424+
const SString strParent = ExtractFilename(ExtractPath(strNormalizedLaunchPath));
425+
return strParent.CompareI("upcache");
425426
}
426427

427428
// Read Last Run Location from a specific registry view. viewFlag should be one of
@@ -443,7 +444,8 @@ static SString ReadInstallRootRegistryValueView(REGSAM viewFlag)
443444
DWORD dwType = REG_SZ;
444445
DWORD dwSize = 0;
445446
LONG result = RegQueryValueExW(hkTemp, wstrValue, NULL, &dwType, NULL, &dwSize);
446-
if (result != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_EXPAND_SZ) || dwSize == 0 || dwSize > kMaxRegistryValueBytes)
447+
if (result != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_EXPAND_SZ) || dwSize == 0 || dwSize > kMaxRegistryValueBytes ||
448+
(dwSize % sizeof(wchar_t)) != 0)
447449
{
448450
RegCloseKey(hkTemp);
449451
return "";
@@ -453,13 +455,11 @@ static SString ReadInstallRootRegistryValueView(REGSAM viewFlag)
453455
result = RegQueryValueExW(hkTemp, wstrValue, NULL, &dwType, reinterpret_cast<LPBYTE>(buffer.data()), &dwSize);
454456
RegCloseKey(hkTemp);
455457

456-
if (result != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_EXPAND_SZ) || dwSize > kMaxRegistryValueBytes)
458+
if (result != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_EXPAND_SZ) || dwSize > kMaxRegistryValueBytes ||
459+
(dwSize % sizeof(wchar_t)) != 0)
457460
return "";
458461

459-
if (dwSize >= sizeof(wchar_t))
460-
buffer[(dwSize / sizeof(wchar_t)) - 1u] = L'\0';
461-
else
462-
buffer[0] = L'\0';
462+
buffer[dwSize / sizeof(wchar_t)] = L'\0';
463463

464464
// Expand environment variable references for REG_EXPAND_SZ values so callers see a real
465465
// filesystem path. Without this, a value like "%ProgramFiles%\..." would fail validation.
@@ -499,7 +499,7 @@ SString SharedUtil::GetMTASABaseDir()
499499
// install-root checks used elsewhere and reject temp update paths so the parent-process
500500
// branch cannot point this process at a directory that is about to be deleted.
501501
SString strParentDir = ExtractPath(GetParentProcessPathFilename(GetCurrentProcessId()));
502-
if (IsUsableMtasaInstallRoot(strParentDir) && !IsTemporaryUpdateLaunchPath(strParentDir))
502+
if (SharedUtil::IsUsableMtasaInstallRoot(strParentDir) && !SharedUtil::IsTemporaryUpdateLaunchPath(strParentDir))
503503
{
504504
strInstallRoot = strParentDir;
505505
strInstallRootSource = "parent process";
@@ -543,7 +543,7 @@ SString SharedUtil::GetMTASABaseDir()
543543
continue;
544544
if (strFirstNonEmptyRegistryValue.empty())
545545
strFirstNonEmptyRegistryValue = strCandidate;
546-
if (IsUsableMtasaInstallRoot(strCandidate) && !IsTemporaryUpdateLaunchPath(strCandidate))
546+
if (SharedUtil::IsUsableMtasaInstallRoot(strCandidate) && !SharedUtil::IsTemporaryUpdateLaunchPath(strCandidate))
547547
{
548548
strInstallRoot = strCandidate;
549549
strInstallRootSource = (viewFlags[i] == 0) ? "registry" :

0 commit comments

Comments
 (0)