From e71de85e4ec2899ecd01ac236603cf1dddc4a6c7 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Sun, 15 Nov 2020 21:38:57 -0600 Subject: Use plan to decide when to begin, commit, or rollback MSI transactions --- src/engine/apply.cpp | 194 ++++++++++++++++++------------------- src/engine/msiengine.cpp | 5 +- src/engine/msiengine.h | 1 + src/engine/mspengine.cpp | 5 +- src/engine/mspengine.h | 1 + src/engine/package.h | 1 + src/engine/plan.cpp | 86 ++++++++++++---- src/engine/plan.h | 20 +++- src/test/BurnUnitTest/PlanTest.cpp | 62 +++++++----- 9 files changed, 226 insertions(+), 149 deletions(-) diff --git a/src/engine/apply.cpp b/src/engine/apply.cpp index 909fb159..53422807 100644 --- a/src/engine/apply.cpp +++ b/src/engine/apply.cpp @@ -3,6 +3,12 @@ #include "precomp.h" +#ifdef DEBUG + #define IgnoreRollbackError(x, f, ...) if (FAILED(x)) { TraceError(x, f, __VA_ARGS__); } +#else + #define IgnoreRollbackError(x, f, ...) +#endif + const DWORD BURN_CACHE_MAX_RECOMMENDED_VERIFY_TRYAGAIN_ATTEMPTS = 2; // structs @@ -134,7 +140,7 @@ static HRESULT DoExecuteAction( __in_opt HANDLE hCacheThread, __in BURN_EXECUTE_CONTEXT* pContext, __inout BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary, - __out DWORD* pdwCheckpoint, + __inout BURN_EXECUTE_ACTION_CHECKPOINT** ppCheckpoint, __out BOOL* pfKeepRegistration, __out BOOL* pfSuspend, __out BOOTSTRAPPER_APPLY_RESTART* pRestart @@ -143,7 +149,6 @@ static HRESULT DoRollbackActions( __in BURN_ENGINE_STATE* pEngineState, __in BURN_EXECUTE_CONTEXT* pContext, __in DWORD dwCheckpoint, - __in BOOL fInTransaction, __out BOOL* pfKeepRegistration, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); @@ -200,15 +205,17 @@ static HRESULT ExecuteCompatiblePackageAction( ); static HRESULT ExecuteMsiBeginTransaction( __in BURN_ENGINE_STATE* pEngineState, - __in LPCWSTR wzName, + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary, __in BURN_EXECUTE_CONTEXT* pContext ); static HRESULT ExecuteMsiCommitTransaction( __in BURN_ENGINE_STATE* pEngineState, + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary, __in BURN_EXECUTE_CONTEXT* pContext ); static HRESULT ExecuteMsiRollbackTransaction( __in BURN_ENGINE_STATE* pEngineState, + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary, __in BURN_EXECUTE_CONTEXT* pContext ); static HRESULT CleanPackage( @@ -732,11 +739,11 @@ extern "C" HRESULT ApplyExecute( ) { HRESULT hr = S_OK; - DWORD dwCheckpoint = 0; + HRESULT hrRollback = S_OK; + BURN_EXECUTE_ACTION_CHECKPOINT* pCheckpoint = NULL; BURN_EXECUTE_CONTEXT context = { }; BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = NULL; BOOL fSeekNextRollbackBoundary = FALSE; - BOOL fInTransaction = FALSE; context.pUX = &pEngineState->userExperience; context.cExecutePackagesTotal = pEngineState->plan.cExecutePackagesTotal; @@ -755,36 +762,6 @@ extern "C" HRESULT ApplyExecute( continue; } - // Transaction end/start - if (BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY == pExecuteAction->type) - { - // End previous transaction - if (fInTransaction) - { - LogString(REPORT_STANDARD, "Committing MSI transaction\n"); - hr = ExecuteMsiCommitTransaction(pEngineState, &context); - ExitOnFailure(hr, "Failed committing an MSI transaction"); - fInTransaction = FALSE; - } - - // Start New transaction - if (!fInTransaction && pExecuteAction->rollbackBoundary.pRollbackBoundary && pExecuteAction->rollbackBoundary.pRollbackBoundary->fTransaction) - { - // Transactions don't go together with DisableRollback. - if (pEngineState->fDisableRollback) - { - LogString(REPORT_STANDARD, "Ignoring Transaction flag due to DisableRollback flag\n"); - } - else - { - LogString(REPORT_STANDARD, "Starting a new MSI transaction\n"); - hr = ExecuteMsiBeginTransaction(pEngineState, pExecuteAction->rollbackBoundary.pRollbackBoundary->sczId, &context); - ExitOnFailure(hr, "Failed beginning an MSI transaction"); - fInTransaction = TRUE; - } - } - } - // If we are seeking the next rollback boundary, skip if this action wasn't it. if (fSeekNextRollbackBoundary) { @@ -799,11 +776,11 @@ extern "C" HRESULT ApplyExecute( } // Execute the action. - hr = DoExecuteAction(pEngineState, pExecuteAction, hCacheThread, &context, &pRollbackBoundary, &dwCheckpoint, pfKeepRegistration, pfSuspend, pRestart); + hr = DoExecuteAction(pEngineState, pExecuteAction, hCacheThread, &context, &pRollbackBoundary, &pCheckpoint, pfKeepRegistration, pfSuspend, pRestart); if (*pfSuspend || BOOTSTRAPPER_APPLY_RESTART_INITIATED == *pRestart) { - if (fInTransaction) + if (pCheckpoint && pCheckpoint->pActiveRollbackBoundary && pCheckpoint->pActiveRollbackBoundary->fActiveTransaction) { hr = E_INVALIDSTATE; LogString(REPORT_ERROR, "Ilegal state: Reboot requested within an MSI transaction. Transaction will rollback."); @@ -816,37 +793,43 @@ extern "C" HRESULT ApplyExecute( if (FAILED(hr)) { - // If we failed, but rollback is disabled just bail with our error code. - if (pEngineState->fDisableRollback) + // If rollback is disabled, keep what we have and always end execution here. + if (pEngineState->plan.fDisableRollback) { + if (pCheckpoint && pCheckpoint->pActiveRollbackBoundary && pCheckpoint->pActiveRollbackBoundary->fActiveTransaction) + { + hrRollback = ExecuteMsiCommitTransaction(pEngineState, pCheckpoint->pActiveRollbackBoundary, &context); + IgnoreRollbackError(hrRollback, "Failed commit transaction from disable rollback"); + } + *pfRollback = TRUE; break; } - else // the action failed, roll back to previous rollback boundary. + + // If inside a MSI transaction, roll it back. + if (pCheckpoint && pCheckpoint->pActiveRollbackBoundary && pCheckpoint->pActiveRollbackBoundary->fActiveTransaction) { - HRESULT hrRollback = DoRollbackActions(pEngineState, &context, dwCheckpoint, fInTransaction, pfKeepRegistration, pRestart); - UNREFERENCED_PARAMETER(hrRollback); - fInTransaction = FALSE; + hrRollback = ExecuteMsiRollbackTransaction(pEngineState, pCheckpoint->pActiveRollbackBoundary, &context); + IgnoreRollbackError(hrRollback, "Failed rolling back transaction"); + } - // If the rollback boundary is vital, end execution here. - if (pRollbackBoundary && pRollbackBoundary->fVital) - { - *pfRollback = TRUE; - break; - } + // The action failed, roll back to previous rollback boundary. + if (pCheckpoint) + { + hrRollback = DoRollbackActions(pEngineState, &context, pCheckpoint->dwId, pfKeepRegistration, pRestart); + IgnoreRollbackError(hrRollback, "Failed rollback actions"); + } - // Move forward to next rollback boundary. - fSeekNextRollbackBoundary = TRUE; + // If the rollback boundary is vital, end execution here. + if (pRollbackBoundary && pRollbackBoundary->fVital) + { + *pfRollback = TRUE; + break; } - } - } - if (fInTransaction) - { - LogString(REPORT_STANDARD, "Committing an MSI transaction\n"); - hr = ExecuteMsiCommitTransaction(pEngineState, &context); - ExitOnFailure(hr, "Failed committing an MSI transaction"); - fInTransaction = FALSE; + // Move forward to next rollback boundary. + fSeekNextRollbackBoundary = TRUE; + } } LExit: @@ -1653,7 +1636,7 @@ static HRESULT DoExecuteAction( __in_opt HANDLE hCacheThread, __in BURN_EXECUTE_CONTEXT* pContext, __inout BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary, - __out DWORD* pdwCheckpoint, + __inout BURN_EXECUTE_ACTION_CHECKPOINT** ppCheckpoint, __out BOOL* pfKeepRegistration, __out BOOL* pfSuspend, __out BOOTSTRAPPER_APPLY_RESTART* pRestart @@ -1674,7 +1657,7 @@ static HRESULT DoExecuteAction( switch (pExecuteAction->type) { case BURN_EXECUTE_ACTION_TYPE_CHECKPOINT: - *pdwCheckpoint = pExecuteAction->checkpoint.dwId; + *ppCheckpoint = &pExecuteAction->checkpoint; break; case BURN_EXECUTE_ACTION_TYPE_WAIT_SYNCPOINT: @@ -1748,6 +1731,18 @@ static HRESULT DoExecuteAction( *ppRollbackBoundary = pExecuteAction->rollbackBoundary.pRollbackBoundary; break; + case BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION: + LogString(REPORT_STANDARD, "Starting a new MSI transaction\n"); + hr = ExecuteMsiBeginTransaction(pEngineState, pExecuteAction->msiTransaction.pRollbackBoundary, pContext); + ExitOnFailure(hr, "Failed to execute begin MSI transaction action."); + break; + + case BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION: + LogString(REPORT_STANDARD, "Committing MSI transaction\n"); + hr = ExecuteMsiCommitTransaction(pEngineState, pExecuteAction->msiTransaction.pRollbackBoundary, pContext); + ExitOnFailure(hr, "Failed to execute commit MSI transaction action."); + break; + case BURN_EXECUTE_ACTION_TYPE_SERVICE_STOP: __fallthrough; case BURN_EXECUTE_ACTION_TYPE_SERVICE_START: __fallthrough; default: @@ -1769,7 +1764,6 @@ static HRESULT DoRollbackActions( __in BURN_ENGINE_STATE* pEngineState, __in BURN_EXECUTE_CONTEXT* pContext, __in DWORD dwCheckpoint, - __in BOOL fInTransaction, __out BOOL* pfKeepRegistration, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) @@ -1781,13 +1775,6 @@ static HRESULT DoRollbackActions( pContext->fRollback = TRUE; - // Rollback MSI transaction - if (fInTransaction) - { - hr = ExecuteMsiRollbackTransaction(pEngineState, pContext); - ExitOnFailure(hr, "Failed rolling back transaction"); - } - // scan to last checkpoint for (DWORD i = 0; i < pEngineState->plan.cRollbackActions; ++i) { @@ -1827,53 +1814,32 @@ static HRESULT DoRollbackActions( case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: hr = ExecuteExePackage(pEngineState, pRollbackAction, pContext, TRUE, &fRetryIgnored, &fSuspendIgnored, &restart); - TraceError(hr, "Failed to rollback EXE package."); - hr = S_OK; + IgnoreRollbackError(hr, "Failed to rollback EXE package."); break; case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: - if (fInTransaction) - { - LogString(REPORT_STANDARD, "Skipping rolling back an MSI package- already done in transaction rollback\n"); - break; - } hr = ExecuteMsiPackage(pEngineState, pRollbackAction, pContext, TRUE, &fRetryIgnored, &fSuspendIgnored, &restart); - TraceError(hr, "Failed to rollback MSI package."); - hr = S_OK; + IgnoreRollbackError(hr, "Failed to rollback MSI package."); break; case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET: - if (fInTransaction) - { - LogString(REPORT_STANDARD, "Skipping rolling back an MSP package- already done in transaction rollback\n"); - break; - } hr = ExecuteMspPackage(pEngineState, pRollbackAction, pContext, TRUE, &fRetryIgnored, &fSuspendIgnored, &restart); - TraceError(hr, "Failed to rollback MSP package."); - hr = S_OK; + IgnoreRollbackError(hr, "Failed to rollback MSP package."); break; case BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE: - if (fInTransaction) - { - LogString(REPORT_STANDARD, "Skipping rolling back an MSU package- already done in transaction rollback\n"); - break; - } hr = ExecuteMsuPackage(pEngineState, pRollbackAction, pContext, TRUE, FALSE, &fRetryIgnored, &fSuspendIgnored, &restart); - TraceError(hr, "Failed to rollback MSU package."); - hr = S_OK; + IgnoreRollbackError(hr, "Failed to rollback MSU package."); break; case BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER: hr = ExecutePackageProviderAction(pEngineState, pRollbackAction, pContext); - TraceError(hr, "Failed to rollback package provider action."); - hr = S_OK; + IgnoreRollbackError(hr, "Failed to rollback package provider action."); break; case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY: hr = ExecuteDependencyAction(pEngineState, pRollbackAction, pContext); - TraceError(hr, "Failed to rollback dependency action."); - hr = S_OK; + IgnoreRollbackError(hr, "Failed to rollback dependency action."); break; case BURN_EXECUTE_ACTION_TYPE_REGISTRATION: @@ -1885,6 +1851,7 @@ static HRESULT DoRollbackActions( case BURN_EXECUTE_ACTION_TYPE_UNCACHE_PACKAGE: hr = CleanPackage(pEngineState->companionConnection.hPipe, pRollbackAction->uncachePackage.pPackage); + IgnoreRollbackError(hr, "Failed to uncache package for rollback."); break; case BURN_EXECUTE_ACTION_TYPE_SERVICE_STOP: __fallthrough; @@ -2234,20 +2201,30 @@ LExit: static HRESULT ExecuteMsiBeginTransaction( __in BURN_ENGINE_STATE* pEngineState, - __in LPCWSTR wzName, + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary, __in BURN_EXECUTE_CONTEXT* /*pContext*/ ) { HRESULT hr = S_OK; + if (pRollbackBoundary->fActiveTransaction) + { + ExitFunction1(hr = E_INVALIDSTATE); + } + if (pEngineState->plan.fPerMachine) { - hr = ElevationMsiBeginTransaction(pEngineState->companionConnection.hPipe, wzName); + hr = ElevationMsiBeginTransaction(pEngineState->companionConnection.hPipe, pRollbackBoundary->sczId); ExitOnFailure(hr, "Failed to begin an elevated MSI transaction."); } else { - hr = MsiEngineBeginTransaction(wzName); + hr = MsiEngineBeginTransaction(pRollbackBoundary->sczId); + } + + if (SUCCEEDED(hr)) + { + pRollbackBoundary->fActiveTransaction = TRUE; } LExit: @@ -2256,11 +2233,17 @@ LExit: static HRESULT ExecuteMsiCommitTransaction( __in BURN_ENGINE_STATE* pEngineState, + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary, __in BURN_EXECUTE_CONTEXT* /*pContext*/ ) { HRESULT hr = S_OK; + if (!pRollbackBoundary->fActiveTransaction) + { + ExitFunction1(hr = E_INVALIDSTATE); + } + if (pEngineState->plan.fPerMachine) { hr = ElevationMsiCommitTransaction(pEngineState->companionConnection.hPipe); @@ -2271,17 +2254,28 @@ static HRESULT ExecuteMsiCommitTransaction( hr = MsiEngineCommitTransaction(); } + if (SUCCEEDED(hr)) + { + pRollbackBoundary->fActiveTransaction = FALSE; + } + LExit: return hr; } static HRESULT ExecuteMsiRollbackTransaction( __in BURN_ENGINE_STATE* pEngineState, + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary, __in BURN_EXECUTE_CONTEXT* /*pContext*/ ) { HRESULT hr = S_OK; + if (!pRollbackBoundary->fActiveTransaction) + { + ExitFunction(); + } + if (pEngineState->plan.fPerMachine) { hr = ElevationMsiRollbackTransaction(pEngineState->companionConnection.hPipe); @@ -2293,6 +2287,8 @@ static HRESULT ExecuteMsiRollbackTransaction( } LExit: + pRollbackBoundary->fActiveTransaction = FALSE; + return hr; } diff --git a/src/engine/msiengine.cpp b/src/engine/msiengine.cpp index fcd8817d..b056cb7e 100644 --- a/src/engine/msiengine.cpp +++ b/src/engine/msiengine.cpp @@ -717,7 +717,8 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage( __in BURN_PACKAGE* pPackage, __in BURN_VARIABLES* pVariables, __in BURN_USER_EXPERIENCE* pUserExperience, - __out BOOL* pfBARequestedCache + __in BOOL fInsideMsiTransaction, + __out_opt BOOL* pfBARequestedCache ) { Trace(REPORT_STANDARD, "Planning MSI package 0x%p", pPackage); @@ -853,7 +854,7 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage( } // Calculate the rollback action if there is an execute action. - if (BOOTSTRAPPER_ACTION_STATE_NONE != execute) + if (BOOTSTRAPPER_ACTION_STATE_NONE != execute && !fInsideMsiTransaction) { switch (BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN != pPackage->expected ? pPackage->expected : pPackage->currentState) { diff --git a/src/engine/msiengine.h b/src/engine/msiengine.h index 63393006..76030528 100644 --- a/src/engine/msiengine.h +++ b/src/engine/msiengine.h @@ -35,6 +35,7 @@ HRESULT MsiEnginePlanCalculatePackage( __in BURN_PACKAGE* pPackage, __in BURN_VARIABLES* pVariables, __in BURN_USER_EXPERIENCE* pUserExperience, + __in BOOL fInsideMsiTransaction, __out_opt BOOL* pfBARequestedCache ); HRESULT MsiEnginePlanAddPackage( diff --git a/src/engine/mspengine.cpp b/src/engine/mspengine.cpp index 0854862b..e14173d1 100644 --- a/src/engine/mspengine.cpp +++ b/src/engine/mspengine.cpp @@ -266,6 +266,7 @@ LExit: extern "C" HRESULT MspEnginePlanCalculatePackage( __in BURN_PACKAGE* pPackage, __in BURN_USER_EXPERIENCE* pUserExperience, + __in BOOL fInsideMsiTransaction, __out BOOL* pfBARequestedCache ) { @@ -329,7 +330,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage( } // Calculate the rollback action if there is an execute action. - if (BOOTSTRAPPER_ACTION_STATE_NONE != execute) + if (BOOTSTRAPPER_ACTION_STATE_NONE != execute && !fInsideMsiTransaction) { switch (BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN != pPackage->expected ? pPackage->expected : pPackage->currentState) { @@ -442,7 +443,7 @@ extern "C" HRESULT MspEnginePlanAddPackage( if (BOOTSTRAPPER_ACTION_STATE_NONE != pTargetProduct->rollback) { hr = PlanTargetProduct(display, pUserExperience, TRUE, pPlan, pLog, pVariables, pTargetProduct->rollback, pPackage, pTargetProduct, hCacheEvent); - ExitOnFailure(hr, "Failed to plan rollack target product."); + ExitOnFailure(hr, "Failed to plan rollback target product."); } } diff --git a/src/engine/mspengine.h b/src/engine/mspengine.h index 1f0c31df..e08fe992 100644 --- a/src/engine/mspengine.h +++ b/src/engine/mspengine.h @@ -35,6 +35,7 @@ HRESULT MspEngineDetectPackage( HRESULT MspEnginePlanCalculatePackage( __in BURN_PACKAGE* pPackage, __in BURN_USER_EXPERIENCE* pUserExperience, + __in BOOL fInsideMsiTransaction, __out_opt BOOL* pfBARequestedCache ); HRESULT MspEnginePlanAddPackage( diff --git a/src/engine/package.h b/src/engine/package.h index c5873765..f3e817eb 100644 --- a/src/engine/package.h +++ b/src/engine/package.h @@ -155,6 +155,7 @@ typedef struct _BURN_ROLLBACK_BOUNDARY LPWSTR sczId; BOOL fVital; BOOL fTransaction; + BOOL fActiveTransaction; // only valid during Apply. } BURN_ROLLBACK_BOUNDARY; typedef struct _BURN_PATCH_TARGETCODE diff --git a/src/engine/plan.cpp b/src/engine/plan.cpp index e2a3437d..22b7033e 100644 --- a/src/engine/plan.cpp +++ b/src/engine/plan.cpp @@ -23,9 +23,12 @@ static void UninitializeCacheAction( static void ResetPlannedPackageState( __in BURN_PACKAGE* pPackage ); +static void ResetPlannedRollbackBoundaryState( + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary + ); static HRESULT ProcessPackage( __in BOOL fBundlePerMachine, - __in BURN_PACKAGE* pCompatiblePackageParent, + __in_opt BURN_PACKAGE* pCompatiblePackageParent, __in BURN_USER_EXPERIENCE* pUX, __in BURN_PLAN* pPlan, __in BURN_PACKAGE* pPackage, @@ -153,6 +156,7 @@ static HRESULT CalculateExecuteActions( __in BURN_USER_EXPERIENCE* pUserExperience, __in BURN_PACKAGE* pPackage, __in BURN_VARIABLES* pVariables, + __in_opt BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary, __out_opt BOOL* pfBARequestedCache ); static BOOL NeedsCache( @@ -263,6 +267,15 @@ extern "C" void PlanReset( ResetPlannedPackageState(&pPackages->rgPackages[i]); } } + + // Reset the planned state for each rollback boundary. + if (pPackages->rgRollbackBoundaries) + { + for (DWORD i = 0; i < pPackages->cRollbackBoundaries; ++i) + { + ResetPlannedRollbackBoundaryState(&pPackages->rgRollbackBoundaries[i]); + } + } } extern "C" void PlanUninitializeExecuteAction( @@ -853,7 +866,7 @@ LExit: static HRESULT ProcessPackage( __in BOOL fBundlePerMachine, - __in BURN_PACKAGE* pCompatiblePackageParent, + __in_opt BURN_PACKAGE* pCompatiblePackageParent, __in BURN_USER_EXPERIENCE* pUX, __in BURN_PLAN* pPlan, __in BURN_PACKAGE* pPackage, @@ -1069,7 +1082,7 @@ extern "C" HRESULT PlanCachePackage( BOOL fBARequestedCache = FALSE; // Calculate the execute actions because we need them to decide whether the package should be cached. - hr = CalculateExecuteActions(pUserExperience, pPackage, pVariables, &fBARequestedCache); + hr = CalculateExecuteActions(pUserExperience, pPackage, pVariables, pPlan->pActiveRollbackBoundary, &fBARequestedCache); ExitOnFailure(hr, "Failed to calculate execute actions for package: %ls", pPackage->sczId); if (fBARequestedCache || NeedsCache(pPlan, pPackage)) @@ -1105,7 +1118,7 @@ extern "C" HRESULT PlanExecutePackage( HRESULT hr = S_OK; BOOL fBARequestedCache = FALSE; - hr = CalculateExecuteActions(pUserExperience, pPackage, pVariables, &fBARequestedCache); + hr = CalculateExecuteActions(pUserExperience, pPackage, pVariables, pPlan->pActiveRollbackBoundary, &fBARequestedCache); ExitOnFailure(hr, "Failed to calculate plan actions for package: %ls", pPackage->sczId); // Calculate package states based on reference count and plan certain dependency actions prior to planning the package execute action. @@ -1631,6 +1644,7 @@ extern "C" HRESULT PlanExecuteCheckpoint( pAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT; pAction->checkpoint.dwId = dwCheckpointId; + pAction->checkpoint.pActiveRollbackBoundary = pPlan->pActiveRollbackBoundary; // rollback checkpoint hr = PlanAppendRollbackAction(pPlan, &pAction); @@ -1638,6 +1652,7 @@ extern "C" HRESULT PlanExecuteCheckpoint( pAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT; pAction->checkpoint.dwId = dwCheckpointId; + pAction->checkpoint.pActiveRollbackBoundary = pPlan->pActiveRollbackBoundary; LExit: return hr; @@ -1783,6 +1798,9 @@ extern "C" HRESULT PlanRollbackBoundaryBegin( HRESULT hr = S_OK; BURN_EXECUTE_ACTION* pExecuteAction = NULL; + AssertSz(!pPlan->pActiveRollbackBoundary, "PlanRollbackBoundaryBegin called without completing previous RollbackBoundary"); + pPlan->pActiveRollbackBoundary = pRollbackBoundary; + // Add begin rollback boundary to execute plan. hr = PlanAppendExecuteAction(pPlan, &pExecuteAction); ExitOnFailure(hr, "Failed to append rollback boundary begin action."); @@ -1797,6 +1815,19 @@ extern "C" HRESULT PlanRollbackBoundaryBegin( pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY; pExecuteAction->rollbackBoundary.pRollbackBoundary = pRollbackBoundary; + // Add begin MSI transaction to execute plan. + if (pRollbackBoundary->fTransaction) + { + hr = PlanExecuteCheckpoint(pPlan); + ExitOnFailure(hr, "Failed to append checkpoint before MSI transaction begin action."); + + hr = PlanAppendExecuteAction(pPlan, &pExecuteAction); + ExitOnFailure(hr, "Failed to append MSI transaction begin action."); + + pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION; + pExecuteAction->msiTransaction.pRollbackBoundary = pRollbackBoundary; + } + LExit: return hr; } @@ -1807,22 +1838,24 @@ extern "C" HRESULT PlanRollbackBoundaryComplete( { HRESULT hr = S_OK; BURN_EXECUTE_ACTION* pExecuteAction = NULL; - DWORD dwCheckpointId = 0; + BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = pPlan->pActiveRollbackBoundary; - // Add checkpoints. - dwCheckpointId = GetNextCheckpointId(pPlan); + AssertSz(pRollbackBoundary, "PlanRollbackBoundaryComplete called without an active RollbackBoundary"); - hr = PlanAppendExecuteAction(pPlan, &pExecuteAction); - ExitOnFailure(hr, "Failed to append execute action."); + if (pRollbackBoundary && pRollbackBoundary->fTransaction) + { + // Add commit MSI transaction to execute plan. + hr = PlanAppendExecuteAction(pPlan, &pExecuteAction); + ExitOnFailure(hr, "Failed to append MSI transaction commit action."); - pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT; - pExecuteAction->checkpoint.dwId = dwCheckpointId; + pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION; + pExecuteAction->msiTransaction.pRollbackBoundary = pRollbackBoundary; + } - hr = PlanAppendRollbackAction(pPlan, &pExecuteAction); - ExitOnFailure(hr, "Failed to append rollback action."); + pPlan->pActiveRollbackBoundary = NULL; - pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT; - pExecuteAction->checkpoint.dwId = dwCheckpointId; + // Add checkpoints. + hr = PlanExecuteCheckpoint(pPlan); LExit: return hr; @@ -1936,6 +1969,13 @@ static void ResetPlannedPackageState( } } +static void ResetPlannedRollbackBoundaryState( + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary + ) +{ + pRollbackBoundary->fActiveTransaction = FALSE; +} + static HRESULT GetActionDefaultRequestState( __in BOOTSTRAPPER_ACTION action, __in BOOL fPermanent, @@ -2848,10 +2888,12 @@ static HRESULT CalculateExecuteActions( __in BURN_USER_EXPERIENCE* pUserExperience, __in BURN_PACKAGE* pPackage, __in BURN_VARIABLES* pVariables, + __in_opt BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary, __out_opt BOOL* pfBARequestedCache ) { HRESULT hr = S_OK; + BOOL fInsideMsiTransaction = pActiveRollbackBoundary && pActiveRollbackBoundary->fTransaction; // Calculate execute actions. switch (pPackage->type) @@ -2861,11 +2903,11 @@ static HRESULT CalculateExecuteActions( break; case BURN_PACKAGE_TYPE_MSI: - hr = MsiEnginePlanCalculatePackage(pPackage, pVariables, pUserExperience, pfBARequestedCache); + hr = MsiEnginePlanCalculatePackage(pPackage, pVariables, pUserExperience, fInsideMsiTransaction, pfBARequestedCache); break; case BURN_PACKAGE_TYPE_MSP: - hr = MspEnginePlanCalculatePackage(pPackage, pUserExperience, pfBARequestedCache); + hr = MspEnginePlanCalculatePackage(pPackage, pUserExperience, fInsideMsiTransaction, pfBARequestedCache); break; case BURN_PACKAGE_TYPE_MSU: @@ -3065,7 +3107,7 @@ static void ExecuteActionLog( switch (pAction->type) { case BURN_EXECUTE_ACTION_TYPE_CHECKPOINT: - LogStringLine(REPORT_STANDARD, "%ls action[%u]: CHECKPOINT id: %u", wzBase, iAction, pAction->checkpoint.dwId); + LogStringLine(REPORT_STANDARD, "%ls action[%u]: CHECKPOINT id: %u, msi transaction id: %ls", wzBase, iAction, pAction->checkpoint.dwId, pAction->checkpoint.pActiveRollbackBoundary && pAction->checkpoint.pActiveRollbackBoundary->fTransaction ? pAction->checkpoint.pActiveRollbackBoundary->sczId : L"(none)"); break; case BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER: @@ -3120,6 +3162,14 @@ static void ExecuteActionLog( LogStringLine(REPORT_STANDARD, "%ls action[%u]: COMPATIBLE_PACKAGE reference id: %ls, installed ProductCode: %ls", wzBase, iAction, pAction->compatiblePackage.pReferencePackage->sczId, pAction->compatiblePackage.sczInstalledProductCode); break; + case BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION: + LogStringLine(REPORT_STANDARD, "%ls action[%u]: BEGIN_MSI_TRANSACTION id: %ls", wzBase, iAction, pAction->msiTransaction.pRollbackBoundary->sczId); + break; + + case BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION: + LogStringLine(REPORT_STANDARD, "%ls action[%u]: COMMIT_MSI_TRANSACTION id: %ls", wzBase, iAction, pAction->msiTransaction.pRollbackBoundary->sczId); + break; + default: AssertSz(FALSE, "Unknown execute action type."); break; diff --git a/src/engine/plan.h b/src/engine/plan.h index 5fddd72f..407c1d48 100644 --- a/src/engine/plan.h +++ b/src/engine/plan.h @@ -68,6 +68,8 @@ enum BURN_EXECUTE_ACTION_TYPE BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY, BURN_EXECUTE_ACTION_TYPE_REGISTRATION, BURN_EXECUTE_ACTION_TYPE_COMPATIBLE_PACKAGE, + BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION, + BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION, }; enum BURN_CLEAN_ACTION_TYPE @@ -214,16 +216,19 @@ typedef struct _BURN_ORDERED_PATCHES BURN_PACKAGE* pPackage; } BURN_ORDERED_PATCHES; +typedef struct _BURN_EXECUTE_ACTION_CHECKPOINT +{ + DWORD dwId; + BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary; +} BURN_EXECUTE_ACTION_CHECKPOINT; + typedef struct _BURN_EXECUTE_ACTION { BURN_EXECUTE_ACTION_TYPE type; BOOL fDeleted; // used to skip an action after it was planned since deleting actions out of the plan is too hard. union { - struct - { - DWORD dwId; - } checkpoint; + BURN_EXECUTE_ACTION_CHECKPOINT checkpoint; struct { HANDLE hEvent; @@ -307,6 +312,10 @@ typedef struct _BURN_EXECUTE_ACTION LPWSTR sczInstalledProductCode; VERUTIL_VERSION* pInstalledVersion; } compatiblePackage; + struct + { + BURN_ROLLBACK_BOUNDARY* pRollbackBoundary; + } msiTransaction; }; } BURN_EXECUTE_ACTION; @@ -368,7 +377,8 @@ typedef struct _BURN_PLAN DWORD cPayloadProgress; STRINGDICT_HANDLE shPayloadProgress; - DWORD dwNextCheckpointId; + DWORD dwNextCheckpointId; // for plan internal use + BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary; // for plan internal use } BURN_PLAN; diff --git a/src/test/BurnUnitTest/PlanTest.cpp b/src/test/BurnUnitTest/PlanTest.cpp index 86bc646b..d3b10678 100644 --- a/src/test/BurnUnitTest/PlanTest.cpp +++ b/src/test/BurnUnitTest/PlanTest.cpp @@ -173,7 +173,7 @@ namespace Bootstrapper ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"cab1QmlL013Hqv_44W64R0cvnHn_2c", TRUE, FALSE, dwPackageStart); ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PackageA", FALSE); ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE); - ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 8); + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 9); dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PackageB", 14, 2, 33753, FALSE); ValidateCacheAcquireContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", TRUE); ValidateCacheExtractContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", FALSE, dwPackageStart, 2); @@ -195,10 +195,6 @@ namespace Bootstrapper dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE); - ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 8); - ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageB", FALSE); - ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 14); - ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageC", FALSE); Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); Assert::Equal(106166ull, pPlan->qwEstimatedSize); @@ -220,30 +216,31 @@ namespace Bootstrapper ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteBeginMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ"); ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[15].syncpoint.hEvent); - dwExecuteCheckpointId = 9; + dwExecuteCheckpointId += 1; // cache checkpoints ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_REGISTER); - ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[23].syncpoint.hEvent); - dwExecuteCheckpointId = 15; + dwExecuteCheckpointId += 1; // cache checkpoints ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_REGISTER); - ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCommitMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[23].syncpoint.hEvent); ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); - Assert::Equal(34ul, pPlan->cExecuteActions); + Assert::Equal(dwIndex, pPlan->cExecuteActions); fRollback = TRUE; dwIndex = 0; @@ -261,29 +258,26 @@ namespace Bootstrapper ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageB"); - dwExecuteCheckpointId = 9; + dwExecuteCheckpointId += 1; // cache checkpoints ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_UNREGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); - ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageC"); - dwExecuteCheckpointId = 15; + dwExecuteCheckpointId += 1; // cache checkpoints ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_UNREGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); - ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); - Assert::Equal(33ul, pPlan->cRollbackActions); + Assert::Equal(dwIndex, pPlan->cRollbackActions); Assert::Equal(4ul, pPlan->cExecutePackagesTotal); Assert::Equal(7ul, pPlan->cOverallProgressTicksTotal); @@ -331,19 +325,20 @@ namespace Bootstrapper DWORD dwExecuteCheckpointId = 1; ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteBeginMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_UNREGISTER); - ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_UNREGISTER); - ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCommitMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -361,19 +356,16 @@ namespace Bootstrapper dwIndex = 0; dwExecuteCheckpointId = 1; ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_REGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); - ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_REGISTER); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); - ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); @@ -818,6 +810,18 @@ namespace Bootstrapper return (fRollback ? pPlan->rgRollbackActions : pPlan->rgExecuteActions) + dwIndex; } + void ValidateExecuteBeginMsiTransaction( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzRollbackBoundaryId + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION, pAction->type); + NativeAssert::StringEqual(wzRollbackBoundaryId, pAction->msiTransaction.pRollbackBoundary->sczId); + } + void ValidateExecuteCheckpoint( __in BURN_PLAN* pPlan, __in BOOL fRollback, @@ -830,6 +834,18 @@ namespace Bootstrapper Assert::Equal(dwId, pAction->checkpoint.dwId); } + void ValidateExecuteCommitMsiTransaction( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzRollbackBoundaryId + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION, pAction->type); + NativeAssert::StringEqual(wzRollbackBoundaryId, pAction->msiTransaction.pRollbackBoundary->sczId); + } + void ValidateExecuteExePackage( __in BURN_PLAN* pPlan, __in BOOL fRollback, -- cgit v1.2.3-55-g6feb