From fc3e4722307c86b5d06918f0721b98323735bb40 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Mon, 21 Mar 2022 23:22:23 -0500 Subject: Add `ExePackage/@Bundle` to opt-in to v3 behavior. Automatically add '-norestart' for bundle ExePackages. Fixes 6252 --- src/burn/engine/core.cpp | 5 ++ src/burn/engine/elevation.cpp | 44 ++++++++++++++++ src/burn/engine/exeengine.cpp | 91 ++++++++++++++++++++++++++++----- src/burn/engine/package.h | 4 ++ src/burn/engine/plan.cpp | 33 ++++++++---- src/burn/engine/plan.h | 3 ++ src/burn/test/BurnUnitTest/PlanTest.cpp | 10 ++-- 7 files changed, 163 insertions(+), 27 deletions(-) (limited to 'src/burn') diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index e077d224..551843f2 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -234,6 +234,11 @@ extern "C" HRESULT CoreInitializeConstants( pPackage->Bundle.wzAncestors = pRegistration->sczBundlePackageAncestors; pPackage->Bundle.wzEngineWorkingDirectory = pInternalCommand->sczEngineWorkingDirectory; } + else if (BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fBundle) + { + pPackage->Exe.wzAncestors = pRegistration->sczBundlePackageAncestors; + pPackage->Exe.wzEngineWorkingDirectory = pInternalCommand->sczEngineWorkingDirectory; + } } LExit: diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index ea56e242..8488b649 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -940,6 +940,15 @@ extern "C" HRESULT ElevationExecuteExePackage( hr = BuffWriteNumber(&pbData, &cbData, fRollback); ExitOnFailure(hr, "Failed to write rollback."); + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczIgnoreDependencies); + ExitOnFailure(hr, "Failed to write the list of dependencies to ignore to the message buffer."); + + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczAncestors); + ExitOnFailure(hr, "Failed to write the list of ancestors to the message buffer."); + + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczEngineWorkingDirectory); + ExitOnFailure(hr, "Failed to write the custom working directory to the message buffer."); + hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData); ExitOnFailure(hr, "Failed to write variables."); @@ -2844,6 +2853,9 @@ static HRESULT OnExecuteExePackage( LPWSTR sczPackage = NULL; DWORD dwRollback = 0; BURN_EXECUTE_ACTION executeAction = { }; + LPWSTR sczIgnoreDependencies = NULL; + LPWSTR sczAncestors = NULL; + LPWSTR sczEngineWorkingDirectory = NULL; BOOTSTRAPPER_APPLY_RESTART exeRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE; @@ -2858,6 +2870,15 @@ static HRESULT OnExecuteExePackage( hr = BuffReadNumber(pbData, cbData, &iData, &dwRollback); ExitOnFailure(hr, "Failed to read rollback."); + hr = BuffReadString(pbData, cbData, &iData, &sczIgnoreDependencies); + ExitOnFailure(hr, "Failed to read the list of dependencies to ignore."); + + hr = BuffReadString(pbData, cbData, &iData, &sczAncestors); + ExitOnFailure(hr, "Failed to read the list of ancestors."); + + hr = BuffReadString(pbData, cbData, &iData, &sczEngineWorkingDirectory); + ExitOnFailure(hr, "Failed to read the custom working directory."); + hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData); ExitOnFailure(hr, "Failed to read variables."); @@ -2869,11 +2890,34 @@ static HRESULT OnExecuteExePackage( ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an EXE package: %ls", sczPackage); } + // Pass the list of dependencies to ignore, if any, to the related bundle. + if (sczIgnoreDependencies && *sczIgnoreDependencies) + { + hr = StrAllocString(&executeAction.exePackage.sczIgnoreDependencies, sczIgnoreDependencies, 0); + ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); + } + + // Pass the list of ancestors, if any, to the related bundle. + if (sczAncestors && *sczAncestors) + { + hr = StrAllocString(&executeAction.exePackage.sczAncestors, sczAncestors, 0); + ExitOnFailure(hr, "Failed to allocate the list of ancestors."); + } + + if (sczEngineWorkingDirectory && *sczEngineWorkingDirectory) + { + hr = StrAllocString(&executeAction.exePackage.sczEngineWorkingDirectory, sczEngineWorkingDirectory, 0); + ExitOnFailure(hr, "Failed to allocate the custom working directory."); + } + // Execute EXE package. hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast(dwRollback), GenericExecuteMessageHandler, hPipe, &exeRestart); ExitOnFailure(hr, "Failed to execute EXE package."); LExit: + ReleaseStr(sczEngineWorkingDirectory); + ReleaseStr(sczAncestors); + ReleaseStr(sczIgnoreDependencies); ReleaseStr(sczPackage); PlanUninitializeExecuteAction(&executeAction); diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index a1049006..9754002f 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp @@ -40,6 +40,10 @@ extern "C" HRESULT ExeEngineParsePackageFromXml( hr = XmlGetYesNoAttribute(pixnExePackage, L"Uninstallable", &pPackage->Exe.fUninstallable); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Uninstallable."); + // @Bundle + hr = XmlGetYesNoAttribute(pixnExePackage, L"Bundle", &pPackage->Exe.fBundle); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Bundle."); + // @Protocol hr = XmlGetAttributeEx(pixnExePackage, L"Protocol", &scz); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Protocol."); @@ -87,6 +91,7 @@ extern "C" void ExeEnginePackageUninitialize( ReleaseStr(pPackage->Exe.sczInstallArguments); ReleaseStr(pPackage->Exe.sczRepairArguments); ReleaseStr(pPackage->Exe.sczUninstallArguments); + ReleaseStr(pPackage->Exe.sczIgnoreDependencies); ReleaseMem(pPackage->Exe.rgExitCodes); // free command-line arguments @@ -286,6 +291,24 @@ extern "C" HRESULT ExeEnginePlanAddPackage( pAction->exePackage.pPackage = pPackage; pAction->exePackage.action = pPackage->rollback; + if (pPackage->Exe.sczIgnoreDependencies) + { + hr = StrAllocString(&pAction->exePackage.sczIgnoreDependencies, pPackage->Exe.sczIgnoreDependencies, 0); + ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); + } + + if (pPackage->Exe.wzAncestors) + { + hr = StrAllocString(&pAction->exePackage.sczAncestors, pPackage->Exe.wzAncestors, 0); + ExitOnFailure(hr, "Failed to allocate the list of ancestors."); + } + + if (pPackage->Exe.wzEngineWorkingDirectory) + { + hr = StrAllocString(&pAction->exePackage.sczEngineWorkingDirectory, pPackage->Exe.wzEngineWorkingDirectory, 0); + ExitOnFailure(hr, "Failed to allocate the custom working directory."); + } + LoggingSetPackageVariable(pPackage, NULL, TRUE, pLog, pVariables, NULL); // ignore errors. hr = PlanExecuteCheckpoint(pPlan); @@ -302,6 +325,24 @@ extern "C" HRESULT ExeEnginePlanAddPackage( pAction->exePackage.pPackage = pPackage; pAction->exePackage.action = pPackage->execute; + if (pPackage->Exe.sczIgnoreDependencies) + { + hr = StrAllocString(&pAction->exePackage.sczIgnoreDependencies, pPackage->Exe.sczIgnoreDependencies, 0); + ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); + } + + if (pPackage->Exe.wzAncestors) + { + hr = StrAllocString(&pAction->exePackage.sczAncestors, pPackage->Exe.wzAncestors, 0); + ExitOnFailure(hr, "Failed to allocate the list of ancestors."); + } + + if (pPackage->Exe.wzEngineWorkingDirectory) + { + hr = StrAllocString(&pAction->exePackage.sczEngineWorkingDirectory, pPackage->Exe.wzEngineWorkingDirectory, 0); + ExitOnFailure(hr, "Failed to allocate the custom working directory."); + } + LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, NULL); // ignore errors. } @@ -406,27 +447,53 @@ extern "C" HRESULT ExeEngineExecutePackage( } // build command - if (*sczArguments) + AppAppendCommandLineArgument(&sczCommand, sczExecutablePath); + ExitOnFailure(hr, "Failed to create executable command."); + + if (pPackage->Exe.fBundle) + { + hr = StrAllocConcat(&sczCommand, L" -norestart", 0); + ExitOnFailure(hr, "Failed to append quiet argument."); + + // Add the list of dependencies to ignore, if any, to the burn command line. + if (pExecuteAction->exePackage.sczIgnoreDependencies) + { + hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->exePackage.sczIgnoreDependencies); + ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); + } + + // Add the list of ancestors, if any, to the burn command line. + if (pExecuteAction->exePackage.sczAncestors) + { + hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", sczCommand, BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->exePackage.sczAncestors); + ExitOnFailure(hr, "Failed to append the list of ancestors to the command line."); + } + + if (pExecuteAction->exePackage.sczEngineWorkingDirectory) + { + hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->exePackage.sczEngineWorkingDirectory, &sczCommand, NULL); + ExitOnFailure(hr, "Failed to append the custom working directory to the exepackage command line."); + } + + hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, NULL); + ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); + } + + // Always add user supplied arguments last. + if (sczArguments && *sczArguments) { hr = VariableFormatString(pVariables, sczArguments, &sczArgumentsFormatted, NULL); ExitOnFailure(hr, "Failed to format argument string."); - hr = StrAllocFormattedSecure(&sczCommand, L"\"%ls\" %ls", sczExecutablePath, sczArgumentsFormatted); - ExitOnFailure(hr, "Failed to create executable command."); - hr = VariableFormatStringObfuscated(pVariables, sczArguments, &sczArgumentsObfuscated, NULL); ExitOnFailure(hr, "Failed to format obfuscated argument string."); - hr = StrAllocFormatted(&sczCommandObfuscated, L"\"%ls\" %ls", sczExecutablePath, sczArgumentsObfuscated); - } - else - { - hr = StrAllocFormatted(&sczCommand, L"\"%ls\"", sczExecutablePath); - ExitOnFailure(hr, "Failed to create executable command."); + hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczCommand, sczArgumentsObfuscated); + ExitOnFailure(hr, "Failed to copy obfuscated formatted arguments."); - hr = StrAllocFormatted(&sczCommandObfuscated, L"\"%ls\"", sczExecutablePath); + hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", sczArgumentsFormatted); + ExitOnFailure(hr, "Failed to copy formatted arguments."); } - ExitOnFailure(hr, "Failed to create obfuscated executable command."); // Log before we add the secret pipe name and client token for embedded processes. LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), sczExecutablePath, sczCommandObfuscated); diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index e3e39c51..deab47b7 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -324,7 +324,11 @@ typedef struct _BURN_PACKAGE LPWSTR sczInstallArguments; LPWSTR sczRepairArguments; LPWSTR sczUninstallArguments; + LPWSTR sczIgnoreDependencies; + LPCWSTR wzAncestors; // points directly into engine state. + LPCWSTR wzEngineWorkingDirectory; // points directly into engine state. + BOOL fBundle; BOOL fPseudoPackage; BOOL fFireAndForget; BOOL fRepairable; diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index 5e1d2654..cb50b0c9 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -291,6 +291,12 @@ extern "C" void PlanUninitializeExecuteAction( ReleaseStr(pExecuteAction->relatedBundle.sczEngineWorkingDirectory); break; + case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: + ReleaseStr(pExecuteAction->exePackage.sczIgnoreDependencies); + ReleaseStr(pExecuteAction->exePackage.sczAncestors); + ReleaseStr(pExecuteAction->exePackage.sczEngineWorkingDirectory); + break; + case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: ReleaseStr(pExecuteAction->msiPackage.sczLogPath); ReleaseMem(pExecuteAction->msiPackage.rgFeatures); @@ -1495,26 +1501,21 @@ extern "C" HRESULT PlanRelatedBundlesComplete( for (DWORD i = 0; i < pPlan->cExecuteActions; ++i) { BOOTSTRAPPER_ACTION_STATE packageAction = BOOTSTRAPPER_ACTION_STATE_NONE; + BURN_PACKAGE* pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package; + BOOL fBundle = FALSE; switch (pPlan->rgExecuteActions[i].type) { case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE: packageAction = pPlan->rgExecuteActions[i].relatedBundle.action; - - if (BOOTSTRAPPER_ACTION_STATE_NONE != packageAction) - { - BURN_PACKAGE* pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package; - if (pPackage->cDependencyProviders) - { - // Bundles only support a single provider key. - const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders; - DictAddKey(sdProviderKeys, pProvider->sczKey); - } - } + pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package; + fBundle = TRUE; break; case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: packageAction = pPlan->rgExecuteActions[i].exePackage.action; + pPackage = pPlan->rgExecuteActions[i].exePackage.pPackage; + fBundle = TRUE; break; case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: @@ -1530,6 +1531,16 @@ extern "C" HRESULT PlanRelatedBundlesComplete( break; } + if (fBundle && BOOTSTRAPPER_ACTION_STATE_NONE != packageAction) + { + if (pPackage->cDependencyProviders) + { + // Bundles only support a single provider key. + const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders; + DictAddKey(sdProviderKeys, pProvider->sczKey); + } + } + fExecutingAnyPackage |= BOOTSTRAPPER_ACTION_STATE_NONE != packageAction; fInstallingAnyPackage |= BOOTSTRAPPER_ACTION_STATE_INSTALL == packageAction || BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE == packageAction; } diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 834d2567..6e9a1ff5 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h @@ -164,6 +164,9 @@ typedef struct _BURN_EXECUTE_ACTION { BURN_PACKAGE* pPackage; BOOTSTRAPPER_ACTION_STATE action; + LPWSTR sczIgnoreDependencies; + LPWSTR sczAncestors; + LPWSTR sczEngineWorkingDirectory; } exePackage; struct { diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 2febe277..143ca7d7 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp @@ -716,7 +716,7 @@ namespace Bootstrapper ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"ExeA"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_INSTALL); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); @@ -727,7 +727,7 @@ namespace Bootstrapper dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -2125,7 +2125,7 @@ namespace Bootstrapper ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web"); - ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", BOOTSTRAPPER_ACTION_STATE_INSTALL); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); dwExecuteCheckpointId += 1; // cache checkpoints ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -2683,13 +2683,15 @@ namespace Bootstrapper __in BOOL fRollback, __in DWORD dwIndex, __in LPCWSTR wzPackageId, - __in BOOTSTRAPPER_ACTION_STATE action + __in BOOTSTRAPPER_ACTION_STATE action, + __in LPCWSTR wzIgnoreDependencies ) { BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); Assert::Equal(BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE, pAction->type); NativeAssert::StringEqual(wzPackageId, pAction->exePackage.pPackage->sczId); Assert::Equal(action, pAction->exePackage.action); + NativeAssert::StringEqual(wzIgnoreDependencies, pAction->exePackage.sczIgnoreDependencies); Assert::Equal(FALSE, pAction->fDeleted); } -- cgit v1.2.3-55-g6feb