From 90982fbf1c887a3ed3454f9ab3ab8dfbd57a1383 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Thu, 26 May 2022 17:34:48 -0500 Subject: Add PathConcatRelativeToBase and use it in Burn. Fixes 6707 --- src/burn/engine/apply.cpp | 2 +- src/burn/engine/bundlepackageengine.cpp | 34 +++++-- src/burn/engine/cache.cpp | 32 +++--- src/burn/engine/core.cpp | 2 +- src/burn/engine/exeengine.cpp | 28 ++++-- src/burn/engine/msiengine.cpp | 4 +- src/burn/engine/mspengine.cpp | 2 +- src/burn/engine/msuengine.cpp | 2 +- src/burn/engine/payload.cpp | 2 +- src/burn/engine/registration.cpp | 6 +- src/ext/Bal/dnchost/dnchost.cpp | 2 +- src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | 11 +++ src/libs/dutil/WixToolset.DUtil/path2utl.cpp | 40 ++++++++ src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | 107 +++++++++++++++++++++ 14 files changed, 233 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index 41cb6ad4..f9b33333 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp @@ -1371,7 +1371,7 @@ static HRESULT LayoutBundle( ExitOnFailure(hr, "Failed to get path to bundle to layout."); } - hr = PathConcat(pContext->wzLayoutDirectory, wzExecutableName, &sczDestinationPath); + hr = PathConcatRelativeToBase(pContext->wzLayoutDirectory, wzExecutableName, &sczDestinationPath); ExitOnFailure(hr, "Failed to concat layout path for bundle."); // If the destination path is the currently running bundle, bail. diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index 00cf9454..97861436 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp @@ -23,6 +23,7 @@ static HRESULT ExecuteBundle( __in BOOTSTRAPPER_ACTION_STATE action, __in BOOTSTRAPPER_RELATION_TYPE relationType, __in BURN_PACKAGE* pPackage, + __in BOOL fPseudoPackage, __in_z_opt LPCWSTR wzParent, __in_z_opt LPCWSTR wzIgnoreDependencies, __in_z_opt LPCWSTR wzAncestors, @@ -614,7 +615,7 @@ extern "C" HRESULT BundlePackageEngineExecutePackage( BOOTSTRAPPER_RELATION_TYPE relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE; BURN_PACKAGE* pPackage = pExecuteAction->bundlePackage.pPackage; - return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); + return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, FALSE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); } extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( @@ -636,7 +637,7 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pRelatedBundle->planRelationType); BURN_PACKAGE* pPackage = &pRelatedBundle->package; - return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); + return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, TRUE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); } extern "C" void BundlePackageEngineUpdateInstallRegistrationState( @@ -733,6 +734,7 @@ static HRESULT ExecuteBundle( __in BOOTSTRAPPER_ACTION_STATE action, __in BOOTSTRAPPER_RELATION_TYPE relationType, __in BURN_PACKAGE* pPackage, + __in BOOL fPseudoPackage, __in_z_opt LPCWSTR wzParent, __in_z_opt LPCWSTR wzIgnoreDependencies, __in_z_opt LPCWSTR wzAncestors, @@ -759,17 +761,33 @@ static HRESULT ExecuteBundle( LPCWSTR wzOperationCommandLine = NULL; BOOL fRunEmbedded = pPackage->Bundle.fSupportsBurnProtocol; - // get cached executable path - hr = CacheGetCompletedPath(pCache, pPackage->fPerMachine, pPackage->sczCacheId, &sczCachedDirectory); - ExitOnFailure(hr, "Failed to get cached path for package: %ls", pPackage->sczId); + if (fPseudoPackage) + { + if (!PathIsFullyQualified(pPackagePayload->sczFilePath, NULL)) + { + ExitWithRootFailure(hr, E_INVALIDSTATE, "Related bundles must have a fully qualified target path."); + } + + hr = StrAllocString(&sczExecutablePath, pPackagePayload->sczFilePath, 0); + ExitOnFailure(hr, "Failed to build executable path."); + + hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); + ExitOnFailure(hr, "Failed to get cached path for related bundle: %ls", pPackage->sczId); + } + else + { + // get cached executable path + hr = CacheGetCompletedPath(pCache, pPackage->fPerMachine, pPackage->sczCacheId, &sczCachedDirectory); + ExitOnFailure(hr, "Failed to get cached path for package: %ls", pPackage->sczId); + + hr = PathConcatRelativeToBase(sczCachedDirectory, pPackagePayload->sczFilePath, &sczExecutablePath); + ExitOnFailure(hr, "Failed to build executable path."); + } // Best effort to set the execute package cache folder and action variables. VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, sczCachedDirectory, TRUE, FALSE); VariableSetNumeric(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_ACTION, action, TRUE); - hr = PathConcat(sczCachedDirectory, pPackagePayload->sczFilePath, &sczExecutablePath); - ExitOnFailure(hr, "Failed to build executable path."); - // pick arguments switch (action) { diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp index 2b7d6ede..04b2f0ca 100644 --- a/src/burn/engine/cache.cpp +++ b/src/burn/engine/cache.cpp @@ -251,7 +251,7 @@ extern "C" HRESULT CacheInitializeSources( hr = CacheGetCompletedPath(pCache, pRegistration->fPerMachine, pRegistration->sczId, &sczCompletedFolder); ExitOnFailure(hr, "Failed to get completed path for bundle."); - hr = PathConcat(sczCompletedFolder, pRegistration->sczExecutableName, &sczCompletedPath); + hr = PathConcatRelativeToBase(sczCompletedFolder, pRegistration->sczExecutableName, &sczCompletedPath); ExitOnFailure(hr, "Failed to combine working path with engine file name."); hr = PathCompare(sczCurrentPath, sczCompletedPath, &nCompare); @@ -390,7 +390,7 @@ extern "C" HRESULT CacheCalculateBundleLayoutWorkingPath( HRESULT hr = S_OK; - hr = PathConcat(pCache->sczAcquisitionFolder, wzBundleId, psczWorkingPath); + hr = PathConcatRelativeToBase(pCache->sczAcquisitionFolder, wzBundleId, psczWorkingPath); ExitOnFailure(hr, "Failed to append bundle id for bundle layout working path."); LExit: @@ -407,7 +407,7 @@ extern "C" HRESULT CacheCalculatePayloadWorkingPath( HRESULT hr = S_OK; - hr = PathConcat(pCache->sczAcquisitionFolder, pPayload->sczKey, psczWorkingPath); + hr = PathConcatRelativeToBase(pCache->sczAcquisitionFolder, pPayload->sczKey, psczWorkingPath); ExitOnFailure(hr, "Failed to append Id as payload unverified path."); LExit: @@ -424,7 +424,7 @@ extern "C" HRESULT CacheCalculateContainerWorkingPath( HRESULT hr = S_OK; - hr = PathConcat(pCache->sczAcquisitionFolder, pContainer->sczHash, psczWorkingPath); + hr = PathConcatRelativeToBase(pCache->sczAcquisitionFolder, pContainer->sczHash, psczWorkingPath); ExitOnFailure(hr, "Failed to append hash as container unverified path."); LExit: @@ -479,7 +479,7 @@ extern "C" HRESULT CacheGetCompletedPath( // GetRootPath returns S_FALSE if the package cache is redirected elsewhere. fRedirected = S_FALSE == hr; - hr = PathConcat(sczRootPath, wzCacheId, &sczCurrentCompletedPath); + hr = PathConcatRelativeToBase(sczRootPath, wzCacheId, &sczCurrentCompletedPath); ExitOnFailure(hr, "Failed to construct cache path."); hr = PathBackslashTerminate(&sczCurrentCompletedPath); @@ -492,7 +492,7 @@ extern "C" HRESULT CacheGetCompletedPath( hr = GetRootPath(pCache, fPerMachine, FALSE, &sczRootPath); ExitOnFailure(hr, "Failed to get old %hs package cache root directory.", fPerMachine ? "per-machine" : "per-user"); - hr = PathConcat(sczRootPath, wzCacheId, &sczDefaultCompletedPath); + hr = PathConcatRelativeToBase(sczRootPath, wzCacheId, &sczDefaultCompletedPath); ExitOnFailure(hr, "Failed to construct cache path."); hr = PathBackslashTerminate(&sczDefaultCompletedPath); @@ -933,7 +933,7 @@ extern "C" HRESULT CacheLayoutBundle( HRESULT hr = S_OK; LPWSTR sczTargetPath = NULL; - hr = PathConcat(wzLayoutDirectory, wzExecutableName, &sczTargetPath); + hr = PathConcatRelativeToBase(wzLayoutDirectory, wzExecutableName, &sczTargetPath); ExitOnFailure(hr, "Failed to combine completed path with engine file name for layout."); LogStringLine(REPORT_STANDARD, "Layout bundle from: '%ls' to: '%ls'", wzSourceBundlePath, sczTargetPath); @@ -968,7 +968,7 @@ extern "C" HRESULT CacheCompleteBundle( hr = CreateCompletedPath(pCache, fPerMachine, wzBundleId, NULL, &sczTargetDirectory); ExitOnFailure(hr, "Failed to create completed cache path for bundle."); - hr = PathConcat(sczTargetDirectory, wzExecutableName, &sczTargetPath); + hr = PathConcatRelativeToBase(sczTargetDirectory, wzExecutableName, &sczTargetPath); ExitOnFailure(hr, "Failed to combine completed path with engine file name."); // We can't just use wzExecutablePath because we needed to call CreateCompletedPath to ensure that the destination was secured. @@ -1021,7 +1021,7 @@ extern "C" HRESULT CacheLayoutContainer( HRESULT hr = S_OK; LPWSTR sczCachedPath = NULL; - hr = PathConcat(wzLayoutDirectory, pContainer->sczFilePath, &sczCachedPath); + hr = PathConcatRelativeToBase(wzLayoutDirectory, pContainer->sczFilePath, &sczCachedPath); ExitOnFailure(hr, "Failed to concat complete cached path."); hr = VerifyThenTransferContainer(pContainer, sczCachedPath, wzUnverifiedContainerPath, fMove, pfnCacheMessageHandler, pfnProgress, pContext); @@ -1046,7 +1046,7 @@ extern "C" HRESULT CacheLayoutPayload( HRESULT hr = S_OK; LPWSTR sczCachedPath = NULL; - hr = PathConcat(wzLayoutDirectory, pPayload->sczFilePath, &sczCachedPath); + hr = PathConcatRelativeToBase(wzLayoutDirectory, pPayload->sczFilePath, &sczCachedPath); ExitOnFailure(hr, "Failed to concat complete cached path."); hr = VerifyThenTransferPayload(pPayload, sczCachedPath, wzUnverifiedPayloadPath, fMove, pfnCacheMessageHandler, pfnProgress, pContext); @@ -1141,7 +1141,7 @@ extern "C" HRESULT CacheVerifyContainer( HRESULT hr = S_OK; LPWSTR sczCachedPath = NULL; - hr = PathConcat(wzCachedDirectory, pContainer->sczFilePath, &sczCachedPath); + hr = PathConcatRelativeToBase(wzCachedDirectory, pContainer->sczFilePath, &sczCachedPath); ExitOnFailure(hr, "Failed to concat complete cached path."); hr = VerifyFileAgainstContainer(pContainer, sczCachedPath, TRUE, BURN_CACHE_STEP_HASH_TO_SKIP_ACQUIRE, pfnCacheMessageHandler, pfnProgress, pContext); @@ -1163,7 +1163,7 @@ extern "C" HRESULT CacheVerifyPayload( HRESULT hr = S_OK; LPWSTR sczCachedPath = NULL; - hr = PathConcat(wzCachedDirectory, pPayload->sczFilePath, &sczCachedPath); + hr = PathConcatRelativeToBase(wzCachedDirectory, pPayload->sczFilePath, &sczCachedPath); ExitOnFailure(hr, "Failed to concat complete cached path."); hr = VerifyFileAgainstPayload(pPayload, sczCachedPath, TRUE, BURN_CACHE_STEP_HASH_TO_SKIP_ACQUIRE, pfnCacheMessageHandler, pfnProgress, pContext); @@ -1596,7 +1596,7 @@ static HRESULT CreateCompletedPath( else { // Get the cache completed file path. - hr = PathConcat(sczCacheDirectory, wzFilePath, &sczCacheFile); + hr = PathConcatRelativeToBase(sczCacheDirectory, wzFilePath, &sczCacheFile); ExitOnFailure(hr, "Failed to construct cache file."); // Don't reset permissions here. The payload's package must reset its cache folder when it starts caching. @@ -1634,7 +1634,7 @@ static HRESULT CreateUnverifiedPath( pCache->fUnverifiedCacheFolderCreated = TRUE; } - hr = PathConcat(sczUnverifiedCacheFolder, wzPayloadId, psczUnverifiedPayloadPath); + hr = PathConcatRelativeToBase(sczUnverifiedCacheFolder, wzPayloadId, psczUnverifiedPayloadPath); ExitOnFailure(hr, "Failed to concat payload id to unverified folder path."); LExit: @@ -2055,13 +2055,13 @@ static HRESULT CopyEngineToWorkingFolder( hr = CacheEnsureBaseWorkingFolder(pCache, &sczWorkingFolder); ExitOnFailure(hr, "Failed to create working path to copy engine."); - hr = PathConcat(sczWorkingFolder, wzWorkingFolderName, &sczTargetDirectory); + hr = PathConcatRelativeToBase(sczWorkingFolder, wzWorkingFolderName, &sczTargetDirectory); ExitOnFailure(hr, "Failed to calculate the bundle working folder target name."); hr = DirEnsureExists(sczTargetDirectory, NULL); ExitOnFailure(hr, "Failed create bundle working folder."); - hr = PathConcat(sczTargetDirectory, wzExecutableName, &sczTargetPath); + hr = PathConcatRelativeToBase(sczTargetDirectory, wzExecutableName, &sczTargetPath); ExitOnFailure(hr, "Failed to combine working path with engine file name."); // Copy the engine without any attached containers to the working path. diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 19b739f9..4255fa6b 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -2217,7 +2217,7 @@ static HRESULT DetectPackagePayloadsCached( { BURN_PAYLOAD* pPayload = pPackage->payloads.rgItems[i].pPayload; - hr = PathConcat(sczCachePath, pPayload->sczFilePath, &sczPayloadCachePath); + hr = PathConcatRelativeToBase(sczCachePath, pPayload->sczFilePath, &sczPayloadCachePath); ExitOnFailure(hr, "Failed to concat payload cache path."); if (FileExistsEx(sczPayloadCachePath, NULL)) diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index a287d171..c3757e92 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp @@ -361,17 +361,33 @@ extern "C" HRESULT ExeEngineExecutePackage( BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage; BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; - // get cached executable path - hr = CacheGetCompletedPath(pCache, pPackage->fPerMachine, pPackage->sczCacheId, &sczCachedDirectory); - ExitOnFailure(hr, "Failed to get cached path for package: %ls", pPackage->sczId); + if (pPackage->Exe.fPseudoPackage && BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE != pPackagePayload->verification) + { + if (!PathIsFullyQualified(pPackagePayload->sczFilePath, NULL)) + { + ExitWithRootFailure(hr, E_INVALIDSTATE, "Pseudo ExePackages must have a fully qualified target path."); + } + + hr = StrAllocString(&sczExecutablePath, pPackagePayload->sczFilePath, 0); + ExitOnFailure(hr, "Failed to build executable path."); + + hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); + ExitOnFailure(hr, "Failed to get cached path for pseudo-package: %ls", pPackage->sczId); + } + else + { + // get cached executable path + hr = CacheGetCompletedPath(pCache, pPackage->fPerMachine, pPackage->sczCacheId, &sczCachedDirectory); + ExitOnFailure(hr, "Failed to get cached path for package: %ls", pPackage->sczId); + + hr = PathConcatRelativeToBase(sczCachedDirectory, pPackagePayload->sczFilePath, &sczExecutablePath); + ExitOnFailure(hr, "Failed to build executable path."); + } // Best effort to set the execute package cache folder and action variables. VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, sczCachedDirectory, TRUE, FALSE); VariableSetNumeric(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_ACTION, pExecuteAction->exePackage.action, TRUE); - hr = PathConcat(sczCachedDirectory, pPackagePayload->sczFilePath, &sczExecutablePath); - ExitOnFailure(hr, "Failed to build executable path."); - // pick arguments switch (pExecuteAction->exePackage.action) { diff --git a/src/burn/engine/msiengine.cpp b/src/burn/engine/msiengine.cpp index d892b2bc..bfd5710f 100644 --- a/src/burn/engine/msiengine.cpp +++ b/src/burn/engine/msiengine.cpp @@ -1236,7 +1236,7 @@ extern "C" HRESULT MsiEngineExecutePackage( // Best effort to set the execute package cache folder variable. VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, sczCachedDirectory, TRUE, FALSE); - hr = PathConcat(sczCachedDirectory, pPackagePayload->sczFilePath, &sczMsiPath); + hr = PathConcatRelativeToBase(sczCachedDirectory, pPackagePayload->sczFilePath, &sczMsiPath); ExitOnFailure(hr, "Failed to build MSI path."); } @@ -2195,7 +2195,7 @@ static HRESULT ConcatPatchProperty( hr = CacheGetCompletedPath(pCache, pMspPackage->fPerMachine, pMspPackage->sczCacheId, &sczCachedDirectory); ExitOnFailure(hr, "Failed to get cached path for MSP package: %ls", pMspPackage->sczId); - hr = PathConcat(sczCachedDirectory, pMspPackagePayload->sczFilePath, &sczMspPath); + hr = PathConcatRelativeToBase(sczCachedDirectory, pMspPackagePayload->sczFilePath, &sczMspPath); ExitOnFailure(hr, "Failed to build MSP path."); if (!sczPatches) diff --git a/src/burn/engine/mspengine.cpp b/src/burn/engine/mspengine.cpp index 7403e78c..02e2afe4 100644 --- a/src/burn/engine/mspengine.cpp +++ b/src/burn/engine/mspengine.cpp @@ -613,7 +613,7 @@ extern "C" HRESULT MspEngineExecutePackage( // Best effort to set the execute package cache folder variable. VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, sczCachedDirectory, TRUE, FALSE); - hr = PathConcat(sczCachedDirectory, pMspPackagePayload->sczFilePath, &sczMspPath); + hr = PathConcatRelativeToBase(sczCachedDirectory, pMspPackagePayload->sczFilePath, &sczMspPath); ExitOnFailure(hr, "Failed to build MSP path."); wzAppend = sczMspPath; diff --git a/src/burn/engine/msuengine.cpp b/src/burn/engine/msuengine.cpp index de8e8c38..d78943ac 100644 --- a/src/burn/engine/msuengine.cpp +++ b/src/burn/engine/msuengine.cpp @@ -320,7 +320,7 @@ extern "C" HRESULT MsuEngineExecutePackage( // Best effort to set the execute package cache folder variable. VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, sczCachedDirectory, TRUE, FALSE); - hr = PathConcat(sczCachedDirectory, pPackagePayload->sczFilePath, &sczMsuPath); + hr = PathConcatRelativeToBase(sczCachedDirectory, pPackagePayload->sczFilePath, &sczMsuPath); ExitOnFailure(hr, "Failed to build MSU path."); // format command diff --git a/src/burn/engine/payload.cpp b/src/burn/engine/payload.cpp index 6acfcd73..f57f1310 100644 --- a/src/burn/engine/payload.cpp +++ b/src/burn/engine/payload.cpp @@ -294,7 +294,7 @@ extern "C" HRESULT PayloadExtractUXContainer( ExitOnFailure(hr, "Failed to find embedded payload: %ls", sczStreamName); // make file path - hr = PathConcat(wzTargetDir, pPayload->sczFilePath, &pPayload->sczLocalFilePath); + hr = PathConcatRelativeToBase(wzTargetDir, pPayload->sczFilePath, &pPayload->sczLocalFilePath); ExitOnFailure(hr, "Failed to concat file paths."); // extract file diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp index e83e0811..2b3dc4d4 100644 --- a/src/burn/engine/registration.cpp +++ b/src/burn/engine/registration.cpp @@ -1149,7 +1149,7 @@ static HRESULT SetPaths( ExitOnFailure(hr, "Failed to build cache directory."); // build cached executable path - hr = PathConcat(sczCacheDirectory, pRegistration->sczExecutableName, &pRegistration->sczCacheExecutablePath); + hr = PathConcatRelativeToBase(sczCacheDirectory, pRegistration->sczExecutableName, &pRegistration->sczCacheExecutablePath); ExitOnFailure(hr, "Failed to build cached executable path."); // build state file path @@ -1367,7 +1367,7 @@ static HRESULT WriteSoftwareTags( hr = PathConcat(sczRootFolder, SWIDTAG_FOLDER, &sczTagFolder); ExitOnFailure(hr, "Failed to allocate regid folder path."); - hr = PathConcat(sczTagFolder, pSoftwareTag->sczFilename, &sczPath); + hr = PathConcatRelativeToBase(sczTagFolder, pSoftwareTag->sczFilename, &sczPath); ExitOnFailure(hr, "Failed to allocate regid file path."); hr = DirEnsureExists(sczTagFolder, NULL); @@ -1405,7 +1405,7 @@ static HRESULT RemoveSoftwareTags( hr = PathConcat(sczRootFolder, SWIDTAG_FOLDER, &sczTagFolder); ExitOnFailure(hr, "Failed to allocate regid folder path."); - hr = PathConcat(sczTagFolder, pSoftwareTag->sczFilename, &sczPath); + hr = PathConcatRelativeToBase(sczTagFolder, pSoftwareTag->sczFilename, &sczPath); ExitOnFailure(hr, "Failed to allocate regid file path."); // Best effort to delete the software tag file and the regid folder. diff --git a/src/ext/Bal/dnchost/dnchost.cpp b/src/ext/Bal/dnchost/dnchost.cpp index 36970f83..cdf204fb 100644 --- a/src/ext/Bal/dnchost/dnchost.cpp +++ b/src/ext/Bal/dnchost/dnchost.cpp @@ -199,7 +199,7 @@ static HRESULT LoadDncConfiguration( hr = XmlGetAttributeEx(pixnHost, L"FilePath", &sczPayloadName); BalExitOnRequiredXmlQueryFailure(hr, "Failed to get WixBalBAFactoryAssembly/@FilePath."); - hr = PathConcat(pArgs->pCommand->wzBootstrapperWorkingFolder, sczPayloadName, &pState->sczBaFactoryAssemblyPath); + hr = PathConcatRelativeToBase(pArgs->pCommand->wzBootstrapperWorkingFolder, sczPayloadName, &pState->sczBaFactoryAssemblyPath); BalExitOnFailure(hr, "Failed to create BaFactoryAssemblyPath."); LPCWSTR wzFileName = PathFile(pState->sczBaFactoryAssemblyPath); diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h index fc6bb3bb..941793f8 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h @@ -236,6 +236,17 @@ DAPI_(HRESULT) PathConcatCch( __deref_out_z LPWSTR* psczCombined ); +/******************************************************************* + PathConcatRelativeToBase - canonicalizes a relative path before + concatenating it to the base path to ensure the resulting path + is inside the base path. +*******************************************************************/ +DAPI_(HRESULT) PathConcatRelativeToBase( + __in LPCWSTR wzBase, + __in_opt LPCWSTR wzRelative, + __deref_out_z LPWSTR* psczCombined + ); + /******************************************************************* PathCompare - compares the fully expanded path of the two paths using ::CompareStringW(). diff --git a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp index 45157d0b..61c1803a 100644 --- a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp +++ b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp @@ -131,6 +131,46 @@ LExit: return hr; } +DAPI_(HRESULT) PathConcatRelativeToBase( + __in LPCWSTR wzBase, + __in_opt LPCWSTR wzRelative, + __deref_out_z LPWSTR* psczCombined + ) +{ + HRESULT hr = S_OK; + LPWSTR sczCanonicalizedRelative = NULL; + + if (!wzBase || !*wzBase) + { + PathExitWithRootFailure(hr, E_INVALIDARG, "wzBase is required."); + } + + if (PathIsRooted(wzRelative)) + { + PathExitWithRootFailure(hr, E_INVALIDARG, "wzRelative cannot be rooted."); + } + + hr = StrAllocString(psczCombined, wzBase, 0); + PathExitOnFailure(hr, "Failed to copy base to output."); + + if (wzRelative && *wzRelative) + { + hr = PathBackslashTerminate(psczCombined); + PathExitOnFailure(hr, "Failed to backslashify."); + + hr = PathCanonicalizeForComparison(wzRelative, 0, &sczCanonicalizedRelative); + PathExitOnFailure(hr, "Failed to canonicalize wzRelative."); + + hr = StrAllocConcat(psczCombined, sczCanonicalizedRelative, 0); + PathExitOnFailure(hr, "Failed to append relative to output."); + } + +LExit: + ReleaseStr(sczCanonicalizedRelative); + + return hr; +} + DAPI_(HRESULT) PathDirectoryContainsPath( __in_z LPCWSTR wzDirectory, __in_z LPCWSTR wzPath diff --git a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp index 04d0b447..52698b98 100644 --- a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp +++ b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp @@ -220,6 +220,113 @@ namespace DutilTests } } + [Fact] + void PathConcatTest() + { + HRESULT hr = S_OK; + LPWSTR sczPath = NULL; + LPCWSTR rgwzPaths[54] = + { + L"a", NULL, L"a", + L"a", L"", L"a", + L"C:\\", L"a", L"C:\\a", + L"\\a", L"b", L"\\a\\b", + L"a", L"b", L"a\\b", + L"C:\\", L"..\\a", L"C:\\..\\a", + L"C:\\a", L"..\\b", L"C:\\a\\..\\b", + L"\\\\server\\share", L"..\\a", L"\\\\server\\share\\..\\a", + L"\\\\server\\share\\a", L"..\\b", L"\\\\server\\share\\a\\..\\b", + NULL, L"b", L"b", + L"", L"b", L"b", + L"a", L"\\b", L"\\b", + L"a", L"b:", L"b:", + L"a", L"b:\\", L"b:\\", + L"a", L"\\\\?\\b", L"\\\\?\\b", + L"a", L"\\\\?\\UNC\\b", L"\\\\?\\UNC\\b", + L"a", L"\\b", L"\\b", + L"a", L"\\\\", L"\\\\", + }; + + try + { + for (DWORD i = 0; i < countof(rgwzPaths); i += 3) + { + hr = PathConcat(rgwzPaths[i], rgwzPaths[i + 1], &sczPath); + NativeAssert::Succeeded(hr, "PathConcat: {0}, {1}", rgwzPaths[i], rgwzPaths[i + 1]); + NativeAssert::StringEqual(rgwzPaths[i + 2], sczPath); + } + } + finally + { + ReleaseStr(sczPath); + } + } + + [Fact] + void PathConcatRelativeToBaseTest() + { + HRESULT hr = S_OK; + LPWSTR sczPath = NULL; + LPCWSTR rgwzPaths[27] = + { + L"a", NULL, L"a", + L"a", L"", L"a", + L"C:\\", L"a", L"C:\\a", + L"\\a", L"b", L"\\a\\b", + L"a", L"b", L"a\\b", + L"C:\\", L"..\\a", L"C:\\a", + L"C:\\a", L"..\\b", L"C:\\a\\b", + L"\\\\server\\share", L"..\\a", L"\\\\server\\share\\a", + L"\\\\server\\share\\a", L"..\\b", L"\\\\server\\share\\a\\b", + }; + + try + { + for (DWORD i = 0; i < countof(rgwzPaths); i += 3) + { + hr = PathConcatRelativeToBase(rgwzPaths[i], rgwzPaths[i + 1], &sczPath); + NativeAssert::Succeeded(hr, "PathConcatRelativeToBase: {0}, {1}", rgwzPaths[i], rgwzPaths[i + 1]); + NativeAssert::StringEqual(rgwzPaths[i + 2], sczPath); + } + } + finally + { + ReleaseStr(sczPath); + } + } + + [Fact] + void PathConcatRelativeToBaseFailureTest() + { + HRESULT hr = S_OK; + LPWSTR sczPath = NULL; + LPCWSTR rgwzPaths[18] = + { + NULL, L"b", + L"", L"b", + L"a", L"\\b", + L"a", L"b:", + L"a", L"b:\\", + L"a", L"\\\\?\\b", + L"a", L"\\\\?\\UNC\\b", + L"a", L"\\b", + L"a", L"\\\\", + }; + + try + { + for (DWORD i = 0; i < countof(rgwzPaths); i += 2) + { + hr = PathConcatRelativeToBase(rgwzPaths[i], rgwzPaths[i + 1], &sczPath); + NativeAssert::SpecificReturnCode(hr, E_INVALIDARG, "PathConcatRelativeToBase: {0}, {1}", rgwzPaths[i], rgwzPaths[i + 1]); + } + } + finally + { + ReleaseStr(sczPath); + } + } + [Fact] void PathDirectoryContainsPathTest() { -- cgit v1.2.3-55-g6feb