From 9453eaa9a38f78e248526ddd996485140a5d4d9a Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Sun, 13 Mar 2022 23:51:36 -0500 Subject: Make engine skip planning if there are any downgrade related bundles. Fixes 6677, 6722 Reverts 6537 --- src/burn/engine/core.cpp | 39 +++++++++++---- src/burn/engine/engine.mc | 14 ++++++ src/burn/engine/plan.cpp | 19 ++++++- src/burn/engine/plan.h | 1 + src/burn/engine/userexperience.cpp | 24 +++++++++ src/burn/engine/userexperience.h | 4 ++ src/burn/test/BurnUnitTest/PlanTest.cpp | 88 +++++++++++++++++++++++++++++++++ 7 files changed, 178 insertions(+), 11 deletions(-) (limited to 'src/burn') diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 9d4ea43e..37872e52 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -527,8 +527,15 @@ extern "C" HRESULT CorePlan( hr = PlanRelatedBundlesInitialize(&pEngineState->userExperience, &pEngineState->registration, pEngineState->command.relationType, &pEngineState->plan); ExitOnFailure(hr, "Failed to initialize related bundles for plan."); - hr = PlanRegistration(&pEngineState->plan, &pEngineState->registration, &pEngineState->dependencies, pEngineState->command.resumeType, pEngineState->command.relationType, &fContinuePlanning); - ExitOnFailure(hr, "Failed to plan registration."); + if (pEngineState->plan.fDowngrade) + { + fContinuePlanning = FALSE; + } + else + { + hr = PlanRegistration(&pEngineState->plan, &pEngineState->registration, &pEngineState->dependencies, pEngineState->command.resumeType, pEngineState->command.relationType, &fContinuePlanning); + ExitOnFailure(hr, "Failed to plan registration."); + } if (fContinuePlanning) { @@ -615,6 +622,7 @@ extern "C" HRESULT CoreApply( { HRESULT hr = S_OK; HANDLE hLock = NULL; + BOOL fApplyBegan = FALSE; BOOL fApplyInitialize = FALSE; BOOL fElevated = FALSE; BOOL fRegistered = FALSE; @@ -627,8 +635,6 @@ extern "C" HRESULT CoreApply( DWORD dwPhaseCount = 0; BOOTSTRAPPER_APPLYCOMPLETE_ACTION applyCompleteAction = BOOTSTRAPPER_APPLYCOMPLETE_ACTION_NONE; - LogId(REPORT_STANDARD, MSG_APPLY_BEGIN); - if (!pEngineState->fPlanned) { ExitOnFailure(hr = E_INVALIDSTATE, "Apply cannot be done without a successful Plan."); @@ -638,6 +644,10 @@ extern "C" HRESULT CoreApply( ExitOnFailure(hr = E_INVALIDSTATE, "Plans cannot be applied multiple times."); } + fApplyBegan = TRUE; + + LogId(REPORT_STANDARD, MSG_APPLY_BEGIN); + // Ensure any previous attempts to execute are reset. ApplyReset(&pEngineState->userExperience, &pEngineState->packages); @@ -653,6 +663,14 @@ extern "C" HRESULT CoreApply( hr = UserExperienceOnApplyBegin(&pEngineState->userExperience, dwPhaseCount); ExitOnRootFailure(hr, "BA aborted apply begin."); + if (pEngineState->plan.fDowngrade) + { + hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_VERSION); + UserExperienceOnApplyDowngrade(&pEngineState->userExperience, &hr); + + ExitFunction(); + } + pEngineState->plan.fAffectedMachineState = pEngineState->plan.fCanAffectMachineState; hr = ApplyLock(FALSE, &hLock); @@ -804,13 +822,16 @@ LExit: DeleteCriticalSection(&applyContext.csApply); } - UserExperienceOnApplyComplete(&pEngineState->userExperience, hr, restart, &applyCompleteAction); - if (BOOTSTRAPPER_APPLYCOMPLETE_ACTION_RESTART == applyCompleteAction) + if (fApplyBegan) { - pEngineState->fRestart = TRUE; - } + UserExperienceOnApplyComplete(&pEngineState->userExperience, hr, restart, &applyCompleteAction); + if (BOOTSTRAPPER_APPLYCOMPLETE_ACTION_RESTART == applyCompleteAction) + { + pEngineState->fRestart = TRUE; + } - LogId(REPORT_STANDARD, MSG_APPLY_COMPLETE, hr, LoggingRestartToString(restart), LoggingBoolToString(pEngineState->fRestart)); + LogId(REPORT_STANDARD, MSG_APPLY_COMPLETE, hr, LoggingRestartToString(restart), LoggingBoolToString(pEngineState->fRestart)); + } return hr; } diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index a5c4e2ba..53e6b256 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc @@ -499,6 +499,20 @@ Language=English Ignoring bundle dependents due to action UnsafeUninstall... . +MessageId=224 +Severity=Warning +SymbolicName=MSG_PLAN_SKIPPED_DUE_TO_DOWNGRADE +Language=English +Plan skipped due to related bundle of plan type Downgrade: +. + +MessageId=225 +Severity=Warning +SymbolicName=MSG_UPGRADE_BUNDLE_DOWNGRADE +Language=English + id: %1!ls!, version: %2!ls! +. + MessageId=299 Severity=Success SymbolicName=MSG_PLAN_COMPLETE diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index dcb919c7..46680636 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -1328,11 +1328,12 @@ LExit: extern "C" HRESULT PlanRelatedBundlesInitialize( __in BURN_USER_EXPERIENCE* pUserExperience, __in BURN_REGISTRATION* pRegistration, - __in BOOTSTRAPPER_RELATION_TYPE /*relationType*/, - __in BURN_PLAN* /*pPlan*/ + __in BOOTSTRAPPER_RELATION_TYPE relationType, + __in BURN_PLAN* pPlan ) { HRESULT hr = S_OK; + BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action; for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i) { @@ -1356,6 +1357,19 @@ extern "C" HRESULT PlanRelatedBundlesInitialize( hr = UserExperienceOnPlanRelatedBundleType(pUserExperience, pRelatedBundle->package.sczId, &pRelatedBundle->planRelationType); ExitOnRootFailure(hr, "BA aborted plan related bundle type."); + + if (BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE == pRelatedBundle->planRelationType && + pRelatedBundle->fPlannable && !fUninstalling && BOOTSTRAPPER_RELATION_UPGRADE != relationType) + { + if (!pPlan->fDowngrade) + { + pPlan->fDowngrade = TRUE; + + LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DUE_TO_DOWNGRADE); + } + + LogId(REPORT_VERBOSE, MSG_UPGRADE_BUNDLE_DOWNGRADE, pRelatedBundle->package.sczId, pRelatedBundle->pVersion->sczVersion); + } } RelatedBundlesSortPlan(&pRegistration->relatedBundles); @@ -3011,6 +3025,7 @@ extern "C" void PlanDump( LogStringLine(PlanDumpLevel, " can affect machine state: %hs", LoggingTrueFalseToString(pPlan->fCanAffectMachineState)); LogStringLine(PlanDumpLevel, " disable-rollback: %hs", LoggingTrueFalseToString(pPlan->fDisableRollback)); LogStringLine(PlanDumpLevel, " disallow-removal: %hs", LoggingTrueFalseToString(pPlan->fDisallowRemoval)); + LogStringLine(PlanDumpLevel, " downgrade: %hs", LoggingTrueFalseToString(pPlan->fDowngrade)); LogStringLine(PlanDumpLevel, " registration options: %hs", LoggingRegistrationOptionsToString(pPlan->dwRegistrationOperations)); LogStringLine(PlanDumpLevel, " estimated size: %llu", pPlan->qwEstimatedSize); if (pPlan->sczLayoutDirectory) diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 1f3fe07c..e73cbcfa 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h @@ -250,6 +250,7 @@ typedef struct _BURN_PLAN BOOL fAffectedMachineState; LPWSTR sczLayoutDirectory; BOOL fPlanPackageCacheRollback; + BOOL fDowngrade; DWORD64 qwCacheSizeTotal; diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index 8668cf6f..81ce8bb9 100644 --- a/src/burn/engine/userexperience.cpp +++ b/src/burn/engine/userexperience.cpp @@ -335,6 +335,30 @@ LExit: return hr; } +EXTERN_C BAAPI UserExperienceOnApplyDowngrade( + __in BURN_USER_EXPERIENCE* pUserExperience, + __inout HRESULT* phrStatus + ) +{ + HRESULT hr = S_OK; + BA_ONAPPLYDOWNGRADE_ARGS args = { }; + BA_ONAPPLYDOWNGRADE_RESULTS results = { }; + + args.cbSize = sizeof(args); + args.hrRecommended = *phrStatus; + + results.cbSize = sizeof(results); + results.hrStatus = *phrStatus; + + hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE, &args, &results); + ExitOnFailure(hr, "BA OnApplyDowngrade failed."); + + *phrStatus = results.hrStatus; + +LExit: + return hr; +} + EXTERN_C BAAPI UserExperienceOnBeginMsiTransactionBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in LPCWSTR wzTransactionId diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h index 11344365..2f18acdd 100644 --- a/src/burn/engine/userexperience.h +++ b/src/burn/engine/userexperience.h @@ -110,6 +110,10 @@ BAAPI UserExperienceOnApplyComplete( __in BOOTSTRAPPER_APPLY_RESTART restart, __inout BOOTSTRAPPER_APPLYCOMPLETE_ACTION* pAction ); +BAAPI UserExperienceOnApplyDowngrade( + __in BURN_USER_EXPERIENCE* pUserExperience, + __inout HRESULT* phrStatus + ); BAAPI UserExperienceOnBeginMsiTransactionBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in LPCWSTR wzTransactionId diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index a3b58426..0a8ac369 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp @@ -67,6 +67,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -226,6 +227,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -358,6 +360,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -457,6 +460,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -575,6 +579,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -677,6 +682,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -741,6 +747,76 @@ namespace Bootstrapper ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT); } + [Fact] + void SingleMsiDowngradeTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPackagesAsAbsent(pEngineState); + DetectRelatedBundle(pEngineState, L"{AF8355C9-CCDD-4D61-BF5F-EA5F948D8F01}", L"1.1.0.0", BOOTSTRAPPER_RELATION_UPGRADE); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + NativeAssert::Succeeded(hr, "CorePlan failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + NativeAssert::StringEqual(L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", pPlan->wzBundleId); + NativeAssert::StringEqual(L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", pPlan->wzBundleProviderKey); + Assert::Equal(FALSE, pPlan->fEnabledForwardCompatibleBundle); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(FALSE, pPlan->fCanAffectMachineState); + Assert::Equal(FALSE, pPlan->fDisableRollback); + Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(TRUE, pPlan->fDowngrade); + + BOOL fRollback = FALSE; + DWORD dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRegistrationActions); + + fRollback = TRUE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions); + + fRollback = FALSE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cCacheActions); + + fRollback = TRUE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); + + Assert::Equal(0ull, pPlan->qwEstimatedSize); + Assert::Equal(0ull, pPlan->qwCacheSizeTotal); + + fRollback = FALSE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cExecuteActions); + + fRollback = TRUE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRollbackActions); + + Assert::Equal(0ul, pPlan->cExecutePackagesTotal); + Assert::Equal(0ul, pPlan->cOverallProgressTicksTotal); + + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); + + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cCleanActions); + + UINT uIndex = 0; + ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL); + Assert::Equal(uIndex, pPlan->cPlannedProviders); + + Assert::Equal(1ul, pEngineState->packages.cPackages); + ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN, BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN); + } + [Fact] void SingleMsiForceAbsentTest() { @@ -770,6 +846,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -858,6 +935,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -948,6 +1026,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -1053,6 +1132,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -1131,6 +1211,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -1225,6 +1306,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(TRUE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -1294,6 +1376,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -1377,6 +1460,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(TRUE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -1471,6 +1555,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -1601,6 +1686,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -1716,6 +1802,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; @@ -1810,6 +1897,7 @@ namespace Bootstrapper Assert::Equal(TRUE, pPlan->fCanAffectMachineState); Assert::Equal(FALSE, pPlan->fDisableRollback); Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); BOOL fRollback = FALSE; DWORD dwIndex = 0; -- cgit v1.2.3-55-g6feb