From eb53852d7ae6838e54525eb57df1d8ce8a722f9b Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Fri, 24 Jun 2022 12:28:27 -0500 Subject: Add longPathAware to Burn manifest to support long paths. Fixes 3455 --- src/burn/engine/approvedexe.cpp | 9 +++ src/burn/engine/cache.cpp | 6 +- src/burn/engine/engine.cpp | 2 +- src/burn/engine/exeengine.cpp | 7 +++ src/burn/engine/logging.cpp | 18 +++--- src/burn/engine/msuengine.cpp | 9 +-- src/burn/engine/userexperience.cpp | 5 +- src/burn/engine/variable.cpp | 75 ++++++++++--------------- src/burn/test/BurnUnitTest/RegistrationTest.cpp | 6 +- 9 files changed, 65 insertions(+), 72 deletions(-) (limited to 'src/burn') diff --git a/src/burn/engine/approvedexe.cpp b/src/burn/engine/approvedexe.cpp index 2a96868e..d8bd956b 100644 --- a/src/burn/engine/approvedexe.cpp +++ b/src/burn/engine/approvedexe.cpp @@ -148,6 +148,7 @@ extern "C" HRESULT ApprovedExesLaunch( LPWSTR sczCommand = NULL; LPWSTR sczCommandObfuscated = NULL; LPWSTR sczExecutableDirectory = NULL; + size_t cchExecutableDirectory = 0; STARTUPINFOW si = { }; PROCESS_INFORMATION pi = { }; @@ -177,9 +178,17 @@ extern "C" HRESULT ApprovedExesLaunch( // Try to get the directory of the executable so we can set the current directory of the process to help those executables // that expect stuff to be relative to them. Best effort only. hr = PathGetDirectory(pLaunchApprovedExe->sczExecutablePath, &sczExecutableDirectory); + if (SUCCEEDED(hr)) + { + // CreateProcessW has undocumented MAX_PATH restriction for lpCurrentDirectory even when long path support is enabled. + hr = ::StringCchLengthW(sczExecutableDirectory, MAX_PATH - 1, &cchExecutableDirectory); + } + if (FAILED(hr)) { ReleaseNullStr(sczExecutableDirectory); + + hr = S_OK; } LogId(REPORT_STANDARD, MSG_LAUNCHING_APPROVED_EXE, pLaunchApprovedExe->sczExecutablePath, sczCommandObfuscated); diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp index cf9de1c3..eb5cc508 100644 --- a/src/burn/engine/cache.cpp +++ b/src/burn/engine/cache.cpp @@ -174,7 +174,7 @@ extern "C" HRESULT CacheInitialize( // Cache paths are initialized once so they cannot be changed while the engine is caching payloads. // Always construct the default machine package cache path so we can determine if we're redirected. - hr = PathGetKnownFolder(CSIDL_COMMON_APPDATA, &sczAppData); + hr = ShelGetFolder(&sczAppData, CSIDL_COMMON_APPDATA); ExitOnFailure(hr, "Failed to find local %hs appdata directory.", "per-machine"); hr = PathConcat(sczAppData, PACKAGE_CACHE_FOLDER_NAME, &pCache->sczDefaultMachinePackageCache); @@ -210,7 +210,7 @@ extern "C" HRESULT CacheInitialize( pCache->fCustomMachinePackageCache = !fPathEqual; - hr = PathGetKnownFolder(CSIDL_LOCAL_APPDATA, &sczAppData); + hr = ShelGetFolder(&sczAppData, CSIDL_LOCAL_APPDATA); ExitOnFailure(hr, "Failed to find local %hs appdata directory.", "per-user"); hr = PathConcat(sczAppData, PACKAGE_CACHE_FOLDER_NAME, &pCache->sczDefaultUserPackageCache); @@ -1469,7 +1469,7 @@ static HRESULT CalculateWorkingFolders( HRESULT hr = S_OK; LPWSTR sczBaseAcquisitionPath = NULL; - hr = PathGetTempPath(&sczBaseAcquisitionPath); + hr = PathGetTempPath(&sczBaseAcquisitionPath, NULL); ExitOnFailure(hr, "Failed to get temp folder path for acquisition folder base."); hr = PathBackslashTerminate(&sczBaseAcquisitionPath); diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp index 7fca1141..13075497 100644 --- a/src/burn/engine/engine.cpp +++ b/src/burn/engine/engine.cpp @@ -486,7 +486,7 @@ static HRESULT RunUntrusted( si.cb = sizeof(si); si.wShowWindow = static_cast(pEngineState->command.nCmdShow); - if (!::CreateProcessW(wzCleanRoomBundlePath, sczFullCommandLine, NULL, NULL, TRUE, 0, 0, NULL, &si, &pi)) + if (!::CreateProcessW(wzCleanRoomBundlePath, sczFullCommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { ExitWithLastError(hr, "Failed to launch clean room process: %ls", sczFullCommandLine); } diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index f7be082d..701adb74 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp @@ -695,6 +695,7 @@ extern "C" HRESULT ExeEngineRunProcess( BOOL fDelayedCancel = FALSE; BOOL fFireAndForget = BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fFireAndForget; BOOL fInheritHandles = BURN_PACKAGE_TYPE_BUNDLE == pPackage->type; + size_t cchCachedDirectory = 0; // Always add user supplied arguments last. if (wzUserArgs) @@ -703,6 +704,12 @@ extern "C" HRESULT ExeEngineRunProcess( ExitOnFailure(hr, "Failed to append user args."); } + // CreateProcessW has undocumented MAX_PATH restriction for lpCurrentDirectory even when long path support is enabled. + if (wzCachedDirectory && FAILED(::StringCchLengthW(wzCachedDirectory, MAX_PATH - 1, &cchCachedDirectory))) + { + wzCachedDirectory = NULL; + } + // Make the cache location of the executable the current directory to help those executables // that expect stuff to be relative to them. si.cb = sizeof(si); diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 1020d01f..68f0c35b 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp @@ -211,7 +211,7 @@ extern "C" void LoggingOpenFailed() LPCWSTR* lpStrings = const_cast(&LOG_FAILED_EVENT_LOG_MESSAGE); WORD wNumStrings = 1; - hr = LogOpen(NULL, L"Setup", L"_Failed", L"txt", FALSE, FALSE, NULL); + hr = LogOpen(NULL, L"Setup", L"_Failed", L"log", FALSE, FALSE, NULL); if (SUCCEEDED(hr)) { ExitFunction(); @@ -965,19 +965,14 @@ static HRESULT GetNonSessionSpecificTempFolder( ) { HRESULT hr = S_OK; - WCHAR wzTempFolder[MAX_PATH] = { }; + LPWSTR sczTempFolder = NULL; SIZE_T cchTempFolder = 0; DWORD dwSessionId = 0; LPWSTR sczSessionId = 0; SIZE_T cchSessionId = 0; - if (!::GetTempPathW(countof(wzTempFolder), wzTempFolder)) - { - ExitWithLastError(hr, "Failed to get temp folder."); - } - - hr = ::StringCchLengthW(wzTempFolder, countof(wzTempFolder), reinterpret_cast(&cchTempFolder)); - ExitOnFailure(hr, "Failed to get length of temp folder."); + hr = PathGetTempPath(&sczTempFolder, &cchTempFolder); + ExitOnFailure(hr, "Failed to get temp folder."); // If our session id is in the TEMP path then remove that part so we get the non-session // specific temporary folder. @@ -989,17 +984,18 @@ static HRESULT GetNonSessionSpecificTempFolder( hr = ::StringCchLengthW(sczSessionId, STRSAFE_MAX_CCH, reinterpret_cast(&cchSessionId)); ExitOnFailure(hr, "Failed to get length of session id string."); - if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzTempFolder + cchTempFolder - cchSessionId, static_cast(cchSessionId), sczSessionId, static_cast(cchSessionId))) + if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, sczTempFolder + cchTempFolder - cchSessionId, static_cast(cchSessionId), sczSessionId, static_cast(cchSessionId))) { cchTempFolder -= cchSessionId; } } - hr = StrAllocString(psczNonSessionTempFolder, wzTempFolder, cchTempFolder); + hr = StrAllocString(psczNonSessionTempFolder, sczTempFolder, cchTempFolder); ExitOnFailure(hr, "Failed to copy temp folder."); LExit: ReleaseStr(sczSessionId); + ReleaseStr(sczTempFolder); return hr; } diff --git a/src/burn/engine/msuengine.cpp b/src/burn/engine/msuengine.cpp index 1b051165..400fdc92 100644 --- a/src/burn/engine/msuengine.cpp +++ b/src/burn/engine/msuengine.cpp @@ -269,7 +269,6 @@ extern "C" HRESULT MsuEngineExecutePackage( HRESULT hr = S_OK; LPWSTR sczCachedDirectory = NULL; LPWSTR sczMsuPath = NULL; - LPWSTR sczWindowsPath = NULL; LPWSTR sczSystemPath = NULL; LPWSTR sczWusaPath = NULL; LPWSTR sczCommand = NULL; @@ -294,15 +293,12 @@ extern "C" HRESULT MsuEngineExecutePackage( // get wusa.exe path if (fUseSysNativePath) { - hr = PathGetKnownFolder(CSIDL_WINDOWS, &sczWindowsPath); - ExitOnFailure(hr, "Failed to find Windows directory."); - - hr = PathConcat(sczWindowsPath, L"SysNative\\", &sczSystemPath); + hr = PathSystemWindowsSubdirectory(L"SysNative\\", &sczSystemPath); ExitOnFailure(hr, "Failed to append SysNative directory."); } else { - hr = PathGetKnownFolder(CSIDL_SYSTEM, &sczSystemPath); + hr = PathGetSystemDirectory(&sczSystemPath); ExitOnFailure(hr, "Failed to find System32 directory."); } @@ -390,7 +386,6 @@ LExit: ReleaseStr(sczCachedDirectory); ReleaseStr(sczMsuPath); ReleaseStr(sczSystemPath); - ReleaseStr(sczWindowsPath); ReleaseStr(sczWusaPath); ReleaseStr(sczCommand); ReleaseStr(sczEscapedKB); diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index a97234ef..6f84caba 100644 --- a/src/burn/engine/userexperience.cpp +++ b/src/burn/engine/userexperience.cpp @@ -99,6 +99,7 @@ extern "C" HRESULT UserExperienceLoad( HRESULT hr = S_OK; BOOTSTRAPPER_CREATE_ARGS args = { }; BOOTSTRAPPER_CREATE_RESULTS results = { }; + LPCWSTR wzPath = pUserExperience->payloads.rgPayloads[0].sczLocalFilePath; args.cbSize = sizeof(BOOTSTRAPPER_CREATE_ARGS); args.pCommand = pCommand; @@ -109,8 +110,8 @@ extern "C" HRESULT UserExperienceLoad( results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); // Load BA DLL. - pUserExperience->hUXModule = ::LoadLibraryExW(pUserExperience->payloads.rgPayloads[0].sczLocalFilePath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - ExitOnNullWithLastError(pUserExperience->hUXModule, hr, "Failed to load BA DLL."); + pUserExperience->hUXModule = ::LoadLibraryExW(wzPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + ExitOnNullWithLastError(pUserExperience->hUXModule, hr, "Failed to load BA DLL: %ls", wzPath); // Get BootstrapperApplicationCreate entry-point. PFN_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = (PFN_BOOTSTRAPPER_APPLICATION_CREATE)::GetProcAddress(pUserExperience->hUXModule, "BootstrapperApplicationCreate"); diff --git a/src/burn/engine/variable.cpp b/src/burn/engine/variable.cpp index c96e9d95..8d208a66 100644 --- a/src/burn/engine/variable.cpp +++ b/src/burn/engine/variable.cpp @@ -1947,18 +1947,18 @@ static HRESULT InitializeVariableTempFolder( UNREFERENCED_PARAMETER(dwpData); HRESULT hr = S_OK; - WCHAR wzPath[MAX_PATH] = { }; + LPWSTR sczPath = NULL; - if (!::GetTempPathW(MAX_PATH, wzPath)) - { - ExitWithLastError(hr, "Failed to get temp path."); - } + hr = PathGetTempPath(&sczPath, NULL); + ExitOnFailure(hr, "Failed to get temp path."); // set value - hr = BVariantSetString(pValue, wzPath, 0, FALSE); + hr = BVariantSetString(pValue, sczPath, 0, FALSE); ExitOnFailure(hr, "Failed to set variant value."); LExit: + ReleaseStr(sczPath); + return hr; } @@ -1969,7 +1969,7 @@ static HRESULT InitializeVariableSystemFolder( { HRESULT hr = S_OK; BOOL f64 = (BOOL)dwpData; - WCHAR wzSystemFolder[MAX_PATH + 2] = { }; + LPWSTR sczSystemFolder = NULL; #if !defined(_WIN64) BOOL fIsWow64 = FALSE; @@ -1979,57 +1979,43 @@ static HRESULT InitializeVariableSystemFolder( { if (f64) { - if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder))) - { - ExitWithLastError(hr, "Failed to get 64-bit system folder."); - } + hr = PathGetSystemDirectory(&sczSystemFolder); + ExitOnFailure(hr, "Failed to get 64-bit system folder."); } else { - if (!::GetSystemWow64DirectoryW(wzSystemFolder, countof(wzSystemFolder))) - { - ExitWithLastError(hr, "Failed to get 32-bit system folder."); - } + hr = PathGetSystemWow64Directory(&sczSystemFolder); + ExitOnFailure(hr, "Failed to get 32-bit system folder."); } } else { if (!f64) { - if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder))) - { - ExitWithLastError(hr, "Failed to get 32-bit system folder."); - } + hr = PathGetSystemDirectory(&sczSystemFolder); + ExitOnFailure(hr, "Failed to get 32-bit system folder."); } } #else if (f64) { - if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder))) - { - ExitWithLastError(hr, "Failed to get 64-bit system folder."); - } + hr = PathGetSystemDirectory(&sczSystemFolder); + ExitOnFailure(hr, "Failed to get 64-bit system folder."); } else { - if (!::GetSystemWow64DirectoryW(wzSystemFolder, countof(wzSystemFolder))) - { - ExitWithLastError(hr, "Failed to get 32-bit system folder."); - } + hr = PathGetSystemWow64Directory(&sczSystemFolder); + ExitOnFailure(hr, "Failed to get 32-bit system folder."); } #endif - if (*wzSystemFolder) - { - hr = PathFixedBackslashTerminate(wzSystemFolder, countof(wzSystemFolder)); - ExitOnFailure(hr, "Failed to backslash terminate system folder."); - } - // set value - hr = BVariantSetString(pValue, wzSystemFolder, 0, FALSE); + hr = BVariantSetString(pValue, sczSystemFolder, 0, FALSE); ExitOnFailure(hr, "Failed to set system folder variant value."); LExit: + ReleaseStr(sczSystemFolder); + return hr; } @@ -2041,26 +2027,25 @@ static HRESULT InitializeVariableWindowsVolumeFolder( UNREFERENCED_PARAMETER(dwpData); HRESULT hr = S_OK; - WCHAR wzWindowsPath[MAX_PATH] = { }; - WCHAR wzVolumePath[MAX_PATH] = { }; + LPWSTR sczWindowsPath = NULL; + LPWSTR sczVolumePath = NULL; // get windows directory - if (!::GetWindowsDirectoryW(wzWindowsPath, countof(wzWindowsPath))) - { - ExitWithLastError(hr, "Failed to get windows directory."); - } + hr = PathSystemWindowsSubdirectory(NULL, &sczWindowsPath); + ExitOnFailure(hr, "Failed to get windows directory."); // get volume path name - if (!::GetVolumePathNameW(wzWindowsPath, wzVolumePath, MAX_PATH)) - { - ExitWithLastError(hr, "Failed to get volume path name."); - } + hr = PathGetVolumePathName(sczWindowsPath, &sczVolumePath); + ExitOnFailure(hr, "Failed to get volume path name."); // set value - hr = BVariantSetString(pValue, wzVolumePath, 0, FALSE); + hr = BVariantSetString(pValue, sczVolumePath, 0, FALSE); ExitOnFailure(hr, "Failed to set variant value."); LExit: + ReleaseStr(sczWindowsPath); + ReleaseStr(sczVolumePath); + return hr; } diff --git a/src/burn/test/BurnUnitTest/RegistrationTest.cpp b/src/burn/test/BurnUnitTest/RegistrationTest.cpp index 883b9cc8..aa3bd34b 100644 --- a/src/burn/test/BurnUnitTest/RegistrationTest.cpp +++ b/src/burn/test/BurnUnitTest/RegistrationTest.cpp @@ -108,8 +108,8 @@ namespace Bootstrapper TestThrowOnFailure(hr, L"Failed to register bundle."); // verify that registration was created - Assert::True(Directory::Exists(cacheDirectory)); - Assert::True(File::Exists(Path::Combine(cacheDirectory, gcnew String(L"setup.exe")))); + Assert::True(Directory::Exists(cacheDirectory), "Cache directory didn't exist."); + Assert::True(File::Exists(Path::Combine(cacheDirectory, gcnew String(L"setup.exe"))), "Bundle exe wasn't cached."); this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ACTIVE)); this->ValidateRunOnceKeyEntry(cacheExePath); @@ -119,7 +119,7 @@ namespace Bootstrapper TestThrowOnFailure(hr, L"Failed to unregister bundle."); // verify that registration was removed - Assert::False(Directory::Exists(cacheDirectory)); + Assert::False(Directory::Exists(cacheDirectory), "Cache directory wasn't removed."); this->ValidateUninstallKeyNull(L"Resume"); this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr); -- cgit v1.2.3-55-g6feb