aboutsummaryrefslogtreecommitdiff
path: root/src/burn
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-02-10 18:09:34 -0600
committerSean Hall <r.sean.hall@gmail.com>2022-02-10 19:51:19 -0600
commit27a0db4070a2b5756282bf15b957dd7f0021417f (patch)
tree2d0cdfe80d5ccd6d207bdf664a4f8e512281c1cf /src/burn
parent091573d459d6ab4947bd39bd3bc8faee3d18b4fc (diff)
downloadwix-27a0db4070a2b5756282bf15b957dd7f0021417f.tar.gz
wix-27a0db4070a2b5756282bf15b957dd7f0021417f.tar.bz2
wix-27a0db4070a2b5756282bf15b957dd7f0021417f.zip
When rolling back a bundle failure, reinstall all upgrade related bundles.
Fixes #3421
Diffstat (limited to 'src/burn')
-rw-r--r--src/burn/engine/apply.cpp50
-rw-r--r--src/burn/engine/bundlepackageengine.cpp2
-rw-r--r--src/burn/engine/core.cpp4
-rw-r--r--src/burn/engine/engine.mc9
-rw-r--r--src/burn/engine/package.h1
-rw-r--r--src/burn/engine/plan.cpp143
-rw-r--r--src/burn/engine/plan.h4
-rw-r--r--src/burn/engine/pseudobundle.cpp1
-rw-r--r--src/burn/engine/registration.h4
-rw-r--r--src/burn/engine/userexperience.cpp30
-rw-r--r--src/burn/engine/userexperience.h5
-rw-r--r--src/burn/test/BurnUnitTest/PlanTest.cpp64
12 files changed, 291 insertions, 26 deletions
diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp
index 5cc63d02..73f8fc72 100644
--- a/src/burn/engine/apply.cpp
+++ b/src/burn/engine/apply.cpp
@@ -210,6 +210,11 @@ static HRESULT ExecuteRelatedBundle(
210 __out BOOL* pfSuspend, 210 __out BOOL* pfSuspend,
211 __out BOOTSTRAPPER_APPLY_RESTART* pRestart 211 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
212 ); 212 );
213static HRESULT DoRestoreRelatedBundleActions(
214 __in BURN_ENGINE_STATE* pEngineState,
215 __in BURN_EXECUTE_CONTEXT* pContext,
216 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
217 );
213static HRESULT ExecuteExePackage( 218static HRESULT ExecuteExePackage(
214 __in BURN_ENGINE_STATE* pEngineState, 219 __in BURN_ENGINE_STATE* pEngineState,
215 __in BURN_EXECUTE_ACTION* pExecuteAction, 220 __in BURN_EXECUTE_ACTION* pExecuteAction,
@@ -788,6 +793,9 @@ extern "C" HRESULT ApplyExecute(
788 { 793 {
789 if (pCheckpoint->pActiveRollbackBoundary->fVital) 794 if (pCheckpoint->pActiveRollbackBoundary->fVital)
790 { 795 {
796 hrRollback = DoRestoreRelatedBundleActions(pEngineState, &context, pRestart);
797 IgnoreRollbackError(hrRollback, "Failed rollback actions");
798
791 // If the rollback boundary is vital, end execution here. 799 // If the rollback boundary is vital, end execution here.
792 break; 800 break;
793 } 801 }
@@ -2590,6 +2598,48 @@ LExit:
2590 return hr; 2598 return hr;
2591} 2599}
2592 2600
2601static HRESULT DoRestoreRelatedBundleActions(
2602 __in BURN_ENGINE_STATE* pEngineState,
2603 __in BURN_EXECUTE_CONTEXT* pContext,
2604 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
2605 )
2606{
2607 HRESULT hr = S_OK;
2608 BOOL fRetryIgnored = FALSE;
2609 BOOL fSuspendIgnored = FALSE;
2610
2611 // execute restore related bundle actions
2612 for (DWORD i = 0; i < pEngineState->plan.cRestoreRelatedBundleActions; ++i)
2613 {
2614 BURN_EXECUTE_ACTION* pRestoreRelatedBundleAction = &pEngineState->plan.rgRestoreRelatedBundleActions[i];
2615 if (pRestoreRelatedBundleAction->fDeleted)
2616 {
2617 continue;
2618 }
2619
2620 BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2621 switch (pRestoreRelatedBundleAction->type)
2622 {
2623 case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE:
2624 hr = ExecuteRelatedBundle(pEngineState, pRestoreRelatedBundleAction, pContext, TRUE, &fRetryIgnored, &fSuspendIgnored, &restart);
2625 IgnoreRollbackError(hr, "Failed to restore related bundle package.");
2626 break;
2627
2628 default:
2629 hr = E_UNEXPECTED;
2630 ExitOnFailure(hr, "Invalid restore related bundle action: %d.", pRestoreRelatedBundleAction->type);
2631 }
2632
2633 if (*pRestart < restart)
2634 {
2635 *pRestart = restart;
2636 }
2637 }
2638
2639LExit:
2640 return hr;
2641}
2642
2593static HRESULT ExecuteExePackage( 2643static HRESULT ExecuteExePackage(
2594 __in BURN_ENGINE_STATE* pEngineState, 2644 __in BURN_ENGINE_STATE* pEngineState,
2595 __in BURN_EXECUTE_ACTION* pExecuteAction, 2645 __in BURN_EXECUTE_ACTION* pExecuteAction,
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp
index cd84601f..b5fc51e5 100644
--- a/src/burn/engine/bundlepackageengine.cpp
+++ b/src/burn/engine/bundlepackageengine.cpp
@@ -51,7 +51,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
51 execute = BOOTSTRAPPER_ACTION_STATE_NONE; 51 execute = BOOTSTRAPPER_ACTION_STATE_NONE;
52 break; 52 break;
53 case BOOTSTRAPPER_REQUEST_STATE_REPAIR: 53 case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
54 execute = pPackage->Bundle.fRepairable ? BOOTSTRAPPER_ACTION_STATE_REPAIR : BOOTSTRAPPER_ACTION_STATE_NONE; 54 execute = BOOTSTRAPPER_ACTION_STATE_REPAIR;
55 break; 55 break;
56 case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough; 56 case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough;
57 case BOOTSTRAPPER_REQUEST_STATE_CACHE: 57 case BOOTSTRAPPER_REQUEST_STATE_CACHE:
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index 7f7a915e..8fac7bd0 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -558,7 +558,7 @@ extern "C" HRESULT CorePlan(
558 ExitOnFailure(hr, "Failed to plan packages."); 558 ExitOnFailure(hr, "Failed to plan packages.");
559 559
560 // Schedule the update of related bundles last. 560 // Schedule the update of related bundles last.
561 hr = PlanRelatedBundlesComplete(&pEngineState->registration, &pEngineState->plan, &pEngineState->log, &pEngineState->variables, dwExecuteActionEarlyIndex); 561 hr = PlanRelatedBundlesComplete(&pEngineState->userExperience, &pEngineState->registration, &pEngineState->plan, &pEngineState->log, &pEngineState->variables, dwExecuteActionEarlyIndex);
562 ExitOnFailure(hr, "Failed to schedule related bundles."); 562 ExitOnFailure(hr, "Failed to schedule related bundles.");
563 } 563 }
564 } 564 }
@@ -2309,7 +2309,7 @@ static void LogRelatedBundles(
2309 2309
2310 if (pRelatedBundle->fPlannable) 2310 if (pRelatedBundle->fPlannable)
2311 { 2311 {
2312 LogId(REPORT_STANDARD, MSG_PLANNED_RELATED_BUNDLE, pPackage->sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingDependencyActionToString(pPackage->dependencyExecute)); 2312 LogId(REPORT_STANDARD, MSG_PLANNED_RELATED_BUNDLE, pPackage->sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingRequestStateToString(pRelatedBundle->defaultRequestedRestore), LoggingRequestStateToString(pRelatedBundle->requestedRestore), LoggingActionStateToString(pRelatedBundle->restore), LoggingDependencyActionToString(pPackage->dependencyExecute));
2313 } 2313 }
2314 } 2314 }
2315 } 2315 }
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc
index b8c9a2d3..675a5644 100644
--- a/src/burn/engine/engine.mc
+++ b/src/burn/engine/engine.mc
@@ -352,13 +352,6 @@ Language=English
352Planned package: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!, default cache strategy: %7!hs!, ba requested strategy: %8!hs!, cache: %9!hs!, uncache: %10!hs!, dependency: %11!hs!, expected install registration state: %12!hs!, expected cache registration state: %13!hs! 352Planned package: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!, default cache strategy: %7!hs!, ba requested strategy: %8!hs!, cache: %9!hs!, uncache: %10!hs!, dependency: %11!hs!, expected install registration state: %12!hs!, expected cache registration state: %13!hs!
353. 353.
354 354
355MessageId=202
356Severity=Success
357SymbolicName=MSG_PLANNED_BUNDLE_UX_CHANGED_REQUEST
358Language=English
359Planned bundle: %1!ls!, ba requested state: %2!hs! over default: %3!hs!
360.
361
362MessageId=203 355MessageId=203
363Severity=Success 356Severity=Success
364SymbolicName=MSG_PLANNED_MSI_FEATURE 357SymbolicName=MSG_PLANNED_MSI_FEATURE
@@ -391,7 +384,7 @@ MessageId=207
391Severity=Success 384Severity=Success
392SymbolicName=MSG_PLANNED_RELATED_BUNDLE 385SymbolicName=MSG_PLANNED_RELATED_BUNDLE
393Language=English 386Language=English
394Planned related bundle: %1!ls!, type: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!, dependency: %7!hs! 387Planned related bundle: %1!ls!, type: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!, default requested restore: %7!hs!, ba requested restore: %8!hs!, restore: %9!hs!, dependency: %10!hs!
395. 388.
396 389
397MessageId=208 390MessageId=208
diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h
index 6d1b5dd9..1e61d92b 100644
--- a/src/burn/engine/package.h
+++ b/src/burn/engine/package.h
@@ -309,7 +309,6 @@ typedef struct _BURN_PACKAGE
309 LPCWSTR wzAncestors; // points directly into engine state. 309 LPCWSTR wzAncestors; // points directly into engine state.
310 LPCWSTR wzEngineWorkingDirectory; // points directly into engine state. 310 LPCWSTR wzEngineWorkingDirectory; // points directly into engine state.
311 311
312 BOOL fRepairable;
313 BOOL fSupportsBurnProtocol; 312 BOOL fSupportsBurnProtocol;
314 313
315 BURN_EXE_EXIT_CODE* rgExitCodes; 314 BURN_EXE_EXIT_CODE* rgExitCodes;
diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp
index f850d49c..f1fb87b8 100644
--- a/src/burn/engine/plan.cpp
+++ b/src/burn/engine/plan.cpp
@@ -103,6 +103,10 @@ static HRESULT AppendCleanAction(
103 __in BURN_PLAN* pPlan, 103 __in BURN_PLAN* pPlan,
104 __out BURN_CLEAN_ACTION** ppCleanAction 104 __out BURN_CLEAN_ACTION** ppCleanAction
105 ); 105 );
106static HRESULT AppendRestoreRelatedBundleAction(
107 __in BURN_PLAN* pPlan,
108 __out BURN_EXECUTE_ACTION** ppExecuteAction
109 );
106static HRESULT ProcessPayloadGroup( 110static HRESULT ProcessPayloadGroup(
107 __in BURN_PLAN* pPlan, 111 __in BURN_PLAN* pPlan,
108 __in BURN_PAYLOAD_GROUP* pPayloadGroup 112 __in BURN_PAYLOAD_GROUP* pPayloadGroup
@@ -196,6 +200,15 @@ extern "C" void PlanReset(
196 MemFree(pPlan->rgRollbackActions); 200 MemFree(pPlan->rgRollbackActions);
197 } 201 }
198 202
203 if (pPlan->rgRestoreRelatedBundleActions)
204 {
205 for (DWORD i = 0; i < pPlan->cRestoreRelatedBundleActions; ++i)
206 {
207 PlanUninitializeExecuteAction(&pPlan->rgRestoreRelatedBundleActions[i]);
208 }
209 MemFree(pPlan->rgRestoreRelatedBundleActions);
210 }
211
199 if (pPlan->rgCleanActions) 212 if (pPlan->rgCleanActions)
200 { 213 {
201 // Nothing needs to be freed inside clean actions today. 214 // Nothing needs to be freed inside clean actions today.
@@ -1276,6 +1289,9 @@ extern "C" HRESULT PlanRelatedBundlesBegin(
1276 continue; 1289 continue;
1277 } 1290 }
1278 1291
1292 pRelatedBundle->defaultRequestedRestore = BOOTSTRAPPER_REQUEST_STATE_NONE;
1293 pRelatedBundle->requestedRestore = BOOTSTRAPPER_REQUEST_STATE_NONE;
1294 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_NONE;
1279 pRelatedBundle->package.defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE; 1295 pRelatedBundle->package.defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1280 pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE; 1296 pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1281 1297
@@ -1312,12 +1328,6 @@ extern "C" HRESULT PlanRelatedBundlesBegin(
1312 hr = UserExperienceOnPlanRelatedBundle(pUserExperience, pRelatedBundle->package.sczId, &pRelatedBundle->package.requested); 1328 hr = UserExperienceOnPlanRelatedBundle(pUserExperience, pRelatedBundle->package.sczId, &pRelatedBundle->package.requested);
1313 ExitOnRootFailure(hr, "BA aborted plan related bundle."); 1329 ExitOnRootFailure(hr, "BA aborted plan related bundle.");
1314 1330
1315 // Log when the BA changed the bundle state so the engine doesn't get blamed for planning the wrong thing.
1316 if (pRelatedBundle->package.requested != pRelatedBundle->package.defaultRequested)
1317 {
1318 LogId(REPORT_STANDARD, MSG_PLANNED_BUNDLE_UX_CHANGED_REQUEST, pRelatedBundle->package.sczId, LoggingRequestStateToString(pRelatedBundle->package.requested), LoggingRequestStateToString(pRelatedBundle->package.defaultRequested));
1319 }
1320
1321 // If uninstalling and the dependent related bundle may be executed, ignore its provider key to allow for downgrades with ref-counting. 1331 // If uninstalling and the dependent related bundle may be executed, ignore its provider key to allow for downgrades with ref-counting.
1322 if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action && BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType && BOOTSTRAPPER_REQUEST_STATE_NONE != pRelatedBundle->package.requested) 1332 if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action && BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType && BOOTSTRAPPER_REQUEST_STATE_NONE != pRelatedBundle->package.requested)
1323 { 1333 {
@@ -1340,6 +1350,7 @@ LExit:
1340} 1350}
1341 1351
1342extern "C" HRESULT PlanRelatedBundlesComplete( 1352extern "C" HRESULT PlanRelatedBundlesComplete(
1353 __in BURN_USER_EXPERIENCE* pUserExperience,
1343 __in BURN_REGISTRATION* pRegistration, 1354 __in BURN_REGISTRATION* pRegistration,
1344 __in BURN_PLAN* pPlan, 1355 __in BURN_PLAN* pPlan,
1345 __in BURN_LOGGING* pLog, 1356 __in BURN_LOGGING* pLog,
@@ -1359,16 +1370,19 @@ extern "C" HRESULT PlanRelatedBundlesComplete(
1359 ExitOnFailure(hr, "Failed to create dictionary for planned packages."); 1370 ExitOnFailure(hr, "Failed to create dictionary for planned packages.");
1360 1371
1361 BOOL fExecutingAnyPackage = FALSE; 1372 BOOL fExecutingAnyPackage = FALSE;
1373 BOOL fInstallingAnyPackage = FALSE;
1362 1374
1363 for (DWORD i = 0; i < pPlan->cExecuteActions; ++i) 1375 for (DWORD i = 0; i < pPlan->cExecuteActions; ++i)
1364 { 1376 {
1377 BOOTSTRAPPER_ACTION_STATE packageAction = BOOTSTRAPPER_ACTION_STATE_NONE;
1378
1365 switch (pPlan->rgExecuteActions[i].type) 1379 switch (pPlan->rgExecuteActions[i].type)
1366 { 1380 {
1367 case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE: 1381 case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE:
1368 if (BOOTSTRAPPER_ACTION_STATE_NONE != pPlan->rgExecuteActions[i].relatedBundle.action) 1382 packageAction = pPlan->rgExecuteActions[i].relatedBundle.action;
1369 {
1370 fExecutingAnyPackage = TRUE;
1371 1383
1384 if (BOOTSTRAPPER_ACTION_STATE_NONE != packageAction)
1385 {
1372 BURN_PACKAGE* pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package; 1386 BURN_PACKAGE* pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package;
1373 if (pPackage->cDependencyProviders) 1387 if (pPackage->cDependencyProviders)
1374 { 1388 {
@@ -1380,21 +1394,24 @@ extern "C" HRESULT PlanRelatedBundlesComplete(
1380 break; 1394 break;
1381 1395
1382 case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: 1396 case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE:
1383 fExecutingAnyPackage |= (BOOTSTRAPPER_ACTION_STATE_NONE != pPlan->rgExecuteActions[i].exePackage.action); 1397 packageAction = pPlan->rgExecuteActions[i].exePackage.action;
1384 break; 1398 break;
1385 1399
1386 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: 1400 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
1387 fExecutingAnyPackage |= (BOOTSTRAPPER_ACTION_STATE_NONE != pPlan->rgExecuteActions[i].msiPackage.action); 1401 packageAction = pPlan->rgExecuteActions[i].msiPackage.action;
1388 break; 1402 break;
1389 1403
1390 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET: 1404 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
1391 fExecutingAnyPackage |= (BOOTSTRAPPER_ACTION_STATE_NONE != pPlan->rgExecuteActions[i].mspTarget.action); 1405 packageAction = pPlan->rgExecuteActions[i].mspTarget.action;
1392 break; 1406 break;
1393 1407
1394 case BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE: 1408 case BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE:
1395 fExecutingAnyPackage |= (BOOTSTRAPPER_ACTION_STATE_NONE != pPlan->rgExecuteActions[i].msuPackage.action); 1409 packageAction = pPlan->rgExecuteActions[i].msuPackage.action;
1396 break; 1410 break;
1397 } 1411 }
1412
1413 fExecutingAnyPackage |= BOOTSTRAPPER_ACTION_STATE_NONE != packageAction;
1414 fInstallingAnyPackage |= BOOTSTRAPPER_ACTION_STATE_INSTALL == packageAction || BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE == packageAction;
1398 } 1415 }
1399 1416
1400 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i) 1417 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
@@ -1492,6 +1509,62 @@ extern "C" HRESULT PlanRelatedBundlesComplete(
1492 hr = DependencyPlanPackageComplete(&pRelatedBundle->package, pPlan); 1509 hr = DependencyPlanPackageComplete(&pRelatedBundle->package, pPlan);
1493 ExitOnFailure(hr, "Failed to complete plan dependency actions for related bundle package: %ls", pRelatedBundle->package.sczId); 1510 ExitOnFailure(hr, "Failed to complete plan dependency actions for related bundle package: %ls", pRelatedBundle->package.sczId);
1494 } 1511 }
1512
1513 if (fInstallingAnyPackage && BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->relationType)
1514 {
1515 BURN_EXECUTE_ACTION* pAction = NULL;
1516
1517 pRelatedBundle->defaultRequestedRestore = pRelatedBundle->requestedRestore = BOOTSTRAPPER_REQUEST_STATE_FORCE_PRESENT;
1518
1519 hr = UserExperienceOnPlanRestoreRelatedBundle(pUserExperience, pRelatedBundle->package.sczId, &pRelatedBundle->requestedRestore);
1520 ExitOnRootFailure(hr, "BA aborted plan restore related bundle.");
1521
1522 switch (pRelatedBundle->requestedRestore)
1523 {
1524 case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
1525 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_REPAIR;
1526 break;
1527 case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough;
1528 case BOOTSTRAPPER_REQUEST_STATE_CACHE: __fallthrough;
1529 case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT:
1530 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
1531 break;
1532 case BOOTSTRAPPER_REQUEST_STATE_FORCE_PRESENT:
1533 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_INSTALL;
1534 break;
1535 default:
1536 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_NONE;
1537 break;
1538 }
1539
1540 if (BOOTSTRAPPER_ACTION_STATE_NONE != pRelatedBundle->restore)
1541 {
1542 hr = AppendRestoreRelatedBundleAction(pPlan, &pAction);
1543 ExitOnFailure(hr, "Failed to append restore related bundle action to plan.");
1544
1545 pAction->type = BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE;
1546 pAction->relatedBundle.pRelatedBundle = pRelatedBundle;
1547 pAction->relatedBundle.action = pRelatedBundle->restore;
1548
1549 if (pRelatedBundle->package.Bundle.sczIgnoreDependencies)
1550 {
1551 hr = StrAllocString(&pAction->relatedBundle.sczIgnoreDependencies, pRelatedBundle->package.Bundle.sczIgnoreDependencies, 0);
1552 ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore.");
1553 }
1554
1555 if (pRelatedBundle->package.Bundle.wzAncestors)
1556 {
1557 hr = StrAllocString(&pAction->relatedBundle.sczAncestors, pRelatedBundle->package.Bundle.wzAncestors, 0);
1558 ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
1559 }
1560
1561 if (pRelatedBundle->package.Bundle.wzEngineWorkingDirectory)
1562 {
1563 hr = StrAllocString(&pAction->relatedBundle.sczEngineWorkingDirectory, pRelatedBundle->package.Bundle.wzEngineWorkingDirectory, 0);
1564 ExitOnFailure(hr, "Failed to allocate the custom working directory.");
1565 }
1566 }
1567 }
1495 } 1568 }
1496 1569
1497LExit: 1570LExit:
@@ -2269,6 +2342,23 @@ LExit:
2269 return hr; 2342 return hr;
2270} 2343}
2271 2344
2345static HRESULT AppendRestoreRelatedBundleAction(
2346 __in BURN_PLAN* pPlan,
2347 __out BURN_EXECUTE_ACTION** ppExecuteAction
2348 )
2349{
2350 HRESULT hr = S_OK;
2351
2352 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pPlan->rgRestoreRelatedBundleActions), pPlan->cRestoreRelatedBundleActions, 1, sizeof(BURN_EXECUTE_ACTION), 5);
2353 ExitOnFailure(hr, "Failed to grow plan's array of restore related bundle actions.");
2354
2355 *ppExecuteAction = pPlan->rgRestoreRelatedBundleActions + pPlan->cRestoreRelatedBundleActions;
2356 ++pPlan->cRestoreRelatedBundleActions;
2357
2358LExit:
2359 return hr;
2360}
2361
2272static HRESULT ProcessPayloadGroup( 2362static HRESULT ProcessPayloadGroup(
2273 __in BURN_PLAN* pPlan, 2363 __in BURN_PLAN* pPlan,
2274 __in BURN_PAYLOAD_GROUP* pPayloadGroup 2364 __in BURN_PAYLOAD_GROUP* pPayloadGroup
@@ -2725,6 +2815,28 @@ static void ExecuteActionLog(
2725 } 2815 }
2726} 2816}
2727 2817
2818static void RestoreRelatedBundleActionLog(
2819 __in DWORD iAction,
2820 __in BURN_EXECUTE_ACTION* pAction
2821 )
2822{
2823 switch (pAction->type)
2824 {
2825 case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE:
2826 LogStringLine(PlanDumpLevel, "Restore action[%u]: RELATED_BUNDLE package id: %ls, action: %hs, ignore dependencies: %ls", iAction, pAction->relatedBundle.pRelatedBundle->package.sczId, LoggingActionStateToString(pAction->relatedBundle.action), pAction->relatedBundle.sczIgnoreDependencies);
2827 break;
2828
2829 default:
2830 AssertSz(FALSE, "Unknown execute action type.");
2831 break;
2832 }
2833
2834 if (pAction->fDeleted)
2835 {
2836 LogStringLine(PlanDumpLevel, " (deleted action)");
2837 }
2838}
2839
2728static void CleanActionLog( 2840static void CleanActionLog(
2729 __in DWORD iAction, 2841 __in DWORD iAction,
2730 __in BURN_CLEAN_ACTION* pAction 2842 __in BURN_CLEAN_ACTION* pAction
@@ -2784,6 +2896,11 @@ extern "C" void PlanDump(
2784 ExecuteActionLog(i, pPlan->rgRollbackActions + i, TRUE); 2896 ExecuteActionLog(i, pPlan->rgRollbackActions + i, TRUE);
2785 } 2897 }
2786 2898
2899 for (DWORD i = 0; i < pPlan->cRestoreRelatedBundleActions; ++i)
2900 {
2901 RestoreRelatedBundleActionLog(i, pPlan->rgRestoreRelatedBundleActions + i);
2902 }
2903
2787 for (DWORD i = 0; i < pPlan->cCleanActions; ++i) 2904 for (DWORD i = 0; i < pPlan->cCleanActions; ++i)
2788 { 2905 {
2789 CleanActionLog(i, pPlan->rgCleanActions + i); 2906 CleanActionLog(i, pPlan->rgCleanActions + i);
diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h
index 0734e39f..3dce8e5d 100644
--- a/src/burn/engine/plan.h
+++ b/src/burn/engine/plan.h
@@ -280,6 +280,9 @@ typedef struct _BURN_PLAN
280 BURN_EXECUTE_ACTION* rgRollbackActions; 280 BURN_EXECUTE_ACTION* rgRollbackActions;
281 DWORD cRollbackActions; 281 DWORD cRollbackActions;
282 282
283 BURN_EXECUTE_ACTION* rgRestoreRelatedBundleActions;
284 DWORD cRestoreRelatedBundleActions;
285
283 BURN_CLEAN_ACTION* rgCleanActions; 286 BURN_CLEAN_ACTION* rgCleanActions;
284 DWORD cCleanActions; 287 DWORD cCleanActions;
285 288
@@ -394,6 +397,7 @@ HRESULT PlanRelatedBundlesBegin(
394 __in BURN_PLAN* pPlan 397 __in BURN_PLAN* pPlan
395 ); 398 );
396HRESULT PlanRelatedBundlesComplete( 399HRESULT PlanRelatedBundlesComplete(
400 __in BURN_USER_EXPERIENCE* pUserExperience,
397 __in BURN_REGISTRATION* pRegistration, 401 __in BURN_REGISTRATION* pRegistration,
398 __in BURN_PLAN* pPlan, 402 __in BURN_PLAN* pPlan,
399 __in BURN_LOGGING* pLog, 403 __in BURN_LOGGING* pLog,
diff --git a/src/burn/engine/pseudobundle.cpp b/src/burn/engine/pseudobundle.cpp
index 94b095c5..082c4487 100644
--- a/src/burn/engine/pseudobundle.cpp
+++ b/src/burn/engine/pseudobundle.cpp
@@ -51,7 +51,6 @@ extern "C" HRESULT PseudoBundleInitializeRelated(
51 pPackage->fVital = FALSE; 51 pPackage->fVital = FALSE;
52 52
53 pPackage->fPermanent = FALSE; 53 pPackage->fPermanent = FALSE;
54 pPackage->Bundle.fRepairable = TRUE;
55 pPackage->Bundle.fSupportsBurnProtocol = fSupportsBurnProtocol; 54 pPackage->Bundle.fSupportsBurnProtocol = fSupportsBurnProtocol;
56 55
57 hr = StrAllocString(&pPackage->sczId, wzId, 0); 56 hr = StrAllocString(&pPackage->sczId, wzId, 0);
diff --git a/src/burn/engine/registration.h b/src/burn/engine/registration.h
index 0ae61974..64191828 100644
--- a/src/burn/engine/registration.h
+++ b/src/burn/engine/registration.h
@@ -61,6 +61,10 @@ typedef struct _BURN_RELATED_BUNDLE
61 BOOL fPlannable; 61 BOOL fPlannable;
62 62
63 BURN_PACKAGE package; 63 BURN_PACKAGE package;
64
65 BOOTSTRAPPER_REQUEST_STATE defaultRequestedRestore;
66 BOOTSTRAPPER_REQUEST_STATE requestedRestore;
67 BOOTSTRAPPER_ACTION_STATE restore;
64} BURN_RELATED_BUNDLE; 68} BURN_RELATED_BUNDLE;
65 69
66typedef struct _BURN_RELATED_BUNDLES 70typedef struct _BURN_RELATED_BUNDLES
diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp
index 1439f5f2..59988bef 100644
--- a/src/burn/engine/userexperience.cpp
+++ b/src/burn/engine/userexperience.cpp
@@ -2176,6 +2176,36 @@ LExit:
2176 return hr; 2176 return hr;
2177} 2177}
2178 2178
2179EXTERN_C BAAPI UserExperienceOnPlanRestoreRelatedBundle(
2180 __in BURN_USER_EXPERIENCE* pUserExperience,
2181 __in_z LPCWSTR wzBundleId,
2182 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState
2183 )
2184{
2185 HRESULT hr = S_OK;
2186 BA_ONPLANRESTORERELATEDBUNDLE_ARGS args = { };
2187 BA_ONPLANRESTORERELATEDBUNDLE_RESULTS results = { };
2188
2189 args.cbSize = sizeof(args);
2190 args.wzBundleId = wzBundleId;
2191 args.recommendedState = *pRequestedState;
2192
2193 results.cbSize = sizeof(results);
2194 results.requestedState = *pRequestedState;
2195
2196 hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRESTORERELATEDBUNDLE, &args, &results);
2197 ExitOnFailure(hr, "BA OnPlanRestoreRelatedBundle failed.");
2198
2199 if (results.fCancel)
2200 {
2201 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
2202 }
2203 *pRequestedState = results.requestedState;
2204
2205LExit:
2206 return hr;
2207}
2208
2179EXTERN_C BAAPI UserExperienceOnPlanRollbackBoundary( 2209EXTERN_C BAAPI UserExperienceOnPlanRollbackBoundary(
2180 __in BURN_USER_EXPERIENCE* pUserExperience, 2210 __in BURN_USER_EXPERIENCE* pUserExperience,
2181 __in_z LPCWSTR wzRollbackBoundaryId, 2211 __in_z LPCWSTR wzRollbackBoundaryId,
diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h
index e8341120..8106d7f7 100644
--- a/src/burn/engine/userexperience.h
+++ b/src/burn/engine/userexperience.h
@@ -497,6 +497,11 @@ BAAPI UserExperienceOnPlanRelatedBundle(
497 __in_z LPCWSTR wzBundleId, 497 __in_z LPCWSTR wzBundleId,
498 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState 498 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState
499 ); 499 );
500BAAPI UserExperienceOnPlanRestoreRelatedBundle(
501 __in BURN_USER_EXPERIENCE* pUserExperience,
502 __in_z LPCWSTR wzBundleId,
503 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState
504 );
500BAAPI UserExperienceOnPlanRollbackBoundary( 505BAAPI UserExperienceOnPlanRollbackBoundary(
501 __in BURN_USER_EXPERIENCE* pUserExperience, 506 __in BURN_USER_EXPERIENCE* pUserExperience,
502 __in_z LPCWSTR wzRollbackBoundaryId, 507 __in_z LPCWSTR wzRollbackBoundaryId,
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp
index 99644115..81484234 100644
--- a/src/burn/test/BurnUnitTest/PlanTest.cpp
+++ b/src/burn/test/BurnUnitTest/PlanTest.cpp
@@ -170,6 +170,10 @@ namespace Bootstrapper
170 Assert::Equal(7ul, pPlan->cOverallProgressTicksTotal); 170 Assert::Equal(7ul, pPlan->cOverallProgressTicksTotal);
171 171
172 dwIndex = 0; 172 dwIndex = 0;
173 ValidateRestoreRelatedBundle(pPlan, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL);
174 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
175
176 dwIndex = 0;
173 Assert::Equal(dwIndex, pPlan->cCleanActions); 177 Assert::Equal(dwIndex, pPlan->cCleanActions);
174 178
175 UINT uIndex = 0; 179 UINT uIndex = 0;
@@ -277,6 +281,9 @@ namespace Bootstrapper
277 Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal); 281 Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal);
278 282
279 dwIndex = 0; 283 dwIndex = 0;
284 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
285
286 dwIndex = 0;
280 ValidateCleanAction(pPlan, dwIndex++, L"PackageC"); 287 ValidateCleanAction(pPlan, dwIndex++, L"PackageC");
281 ValidateCleanAction(pPlan, dwIndex++, L"PackageB"); 288 ValidateCleanAction(pPlan, dwIndex++, L"PackageB");
282 ValidateCleanAction(pPlan, dwIndex++, L"PackageA"); 289 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
@@ -350,6 +357,9 @@ namespace Bootstrapper
350 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal); 357 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
351 358
352 dwIndex = 0; 359 dwIndex = 0;
360 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
361
362 dwIndex = 0;
353 ValidateCleanAction(pPlan, dwIndex++, L"PackageA"); 363 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
354 ValidateCleanCompatibleAction(pPlan, dwIndex++, L"PackageA"); 364 ValidateCleanCompatibleAction(pPlan, dwIndex++, L"PackageA");
355 Assert::Equal(dwIndex, pPlan->cCleanActions); 365 Assert::Equal(dwIndex, pPlan->cCleanActions);
@@ -438,6 +448,9 @@ namespace Bootstrapper
438 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); 448 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
439 449
440 dwIndex = 0; 450 dwIndex = 0;
451 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
452
453 dwIndex = 0;
441 Assert::Equal(dwIndex, pPlan->cCleanActions); 454 Assert::Equal(dwIndex, pPlan->cCleanActions);
442 455
443 UINT uIndex = 0; 456 UINT uIndex = 0;
@@ -508,6 +521,9 @@ namespace Bootstrapper
508 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal); 521 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
509 522
510 dwIndex = 0; 523 dwIndex = 0;
524 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
525
526 dwIndex = 0;
511 Assert::Equal(dwIndex, pPlan->cCleanActions); 527 Assert::Equal(dwIndex, pPlan->cCleanActions);
512 528
513 UINT uIndex = 0; 529 UINT uIndex = 0;
@@ -579,6 +595,9 @@ namespace Bootstrapper
579 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); 595 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
580 596
581 dwIndex = 0; 597 dwIndex = 0;
598 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
599
600 dwIndex = 0;
582 ValidateCleanAction(pPlan, dwIndex++, L"PackageA"); 601 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
583 Assert::Equal(dwIndex, pPlan->cCleanActions); 602 Assert::Equal(dwIndex, pPlan->cCleanActions);
584 603
@@ -658,6 +677,10 @@ namespace Bootstrapper
658 Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal); 677 Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal);
659 678
660 dwIndex = 0; 679 dwIndex = 0;
680 ValidateRestoreRelatedBundle(pPlan, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL);
681 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
682
683 dwIndex = 0;
661 Assert::Equal(dwIndex, pPlan->cCleanActions); 684 Assert::Equal(dwIndex, pPlan->cCleanActions);
662 685
663 UINT uIndex = 0; 686 UINT uIndex = 0;
@@ -744,6 +767,10 @@ namespace Bootstrapper
744 Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal); 767 Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal);
745 768
746 dwIndex = 0; 769 dwIndex = 0;
770 ValidateRestoreRelatedBundle(pPlan, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL);
771 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
772
773 dwIndex = 0;
747 Assert::Equal(dwIndex, pPlan->cCleanActions); 774 Assert::Equal(dwIndex, pPlan->cCleanActions);
748 775
749 UINT uIndex = 0; 776 UINT uIndex = 0;
@@ -805,6 +832,9 @@ namespace Bootstrapper
805 Assert::Equal(0ul, pPlan->cOverallProgressTicksTotal); 832 Assert::Equal(0ul, pPlan->cOverallProgressTicksTotal);
806 833
807 dwIndex = 0; 834 dwIndex = 0;
835 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
836
837 dwIndex = 0;
808 ValidateCleanAction(pPlan, dwIndex++, L"PackageA"); 838 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
809 Assert::Equal(dwIndex, pPlan->cCleanActions); 839 Assert::Equal(dwIndex, pPlan->cCleanActions);
810 840
@@ -879,6 +909,9 @@ namespace Bootstrapper
879 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal); 909 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
880 910
881 dwIndex = 0; 911 dwIndex = 0;
912 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
913
914 dwIndex = 0;
882 ValidateCleanAction(pPlan, dwIndex++, L"PackageA"); 915 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
883 Assert::Equal(dwIndex, pPlan->cCleanActions); 916 Assert::Equal(dwIndex, pPlan->cCleanActions);
884 917
@@ -946,6 +979,9 @@ namespace Bootstrapper
946 Assert::Equal(0ul, pPlan->cOverallProgressTicksTotal); 979 Assert::Equal(0ul, pPlan->cOverallProgressTicksTotal);
947 980
948 dwIndex = 0; 981 dwIndex = 0;
982 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
983
984 dwIndex = 0;
949 Assert::Equal(dwIndex, pPlan->cCleanActions); 985 Assert::Equal(dwIndex, pPlan->cCleanActions);
950 986
951 UINT uIndex = 0; 987 UINT uIndex = 0;
@@ -1057,6 +1093,9 @@ namespace Bootstrapper
1057 Assert::Equal(5ul, pPlan->cOverallProgressTicksTotal); 1093 Assert::Equal(5ul, pPlan->cOverallProgressTicksTotal);
1058 1094
1059 dwIndex = 0; 1095 dwIndex = 0;
1096 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
1097
1098 dwIndex = 0;
1060 Assert::Equal(dwIndex, pPlan->cCleanActions); 1099 Assert::Equal(dwIndex, pPlan->cCleanActions);
1061 1100
1062 UINT uIndex = 0; 1101 UINT uIndex = 0;
@@ -1147,6 +1186,9 @@ namespace Bootstrapper
1147 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); 1186 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
1148 1187
1149 dwIndex = 0; 1188 dwIndex = 0;
1189 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
1190
1191 dwIndex = 0;
1150 ValidateCleanAction(pPlan, dwIndex++, L"PatchA"); 1192 ValidateCleanAction(pPlan, dwIndex++, L"PatchA");
1151 ValidateCleanAction(pPlan, dwIndex++, L"PackageA"); 1193 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
1152 Assert::Equal(dwIndex, pPlan->cCleanActions); 1194 Assert::Equal(dwIndex, pPlan->cCleanActions);
@@ -1829,6 +1871,28 @@ namespace Bootstrapper
1829 NativeAssert::StringEqual(wzName, pProvider->sczName); 1871 NativeAssert::StringEqual(wzName, pProvider->sczName);
1830 } 1872 }
1831 1873
1874 void ValidateRestoreRelatedBundle(
1875 __in BURN_PLAN* pPlan,
1876 __in DWORD dwIndex,
1877 __in LPCWSTR wzPackageId,
1878 __in BOOTSTRAPPER_ACTION_STATE action,
1879 __in LPCWSTR wzIgnoreDependencies
1880 )
1881 {
1882 BURN_EXECUTE_ACTION* pAction = ValidateRestoreRelatedBundleActionExists(pPlan, dwIndex);
1883 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE, pAction->type);
1884 NativeAssert::StringEqual(wzPackageId, pAction->relatedBundle.pRelatedBundle->package.sczId);
1885 Assert::Equal<DWORD>(action, pAction->relatedBundle.action);
1886 NativeAssert::StringEqual(wzIgnoreDependencies, pAction->relatedBundle.sczIgnoreDependencies);
1887 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1888 }
1889
1890 BURN_EXECUTE_ACTION* ValidateRestoreRelatedBundleActionExists(BURN_PLAN* pPlan, DWORD dwIndex)
1891 {
1892 Assert::InRange(dwIndex + 1ul, 1ul, pPlan->cRestoreRelatedBundleActions);
1893 return pPlan->rgRestoreRelatedBundleActions + dwIndex;
1894 }
1895
1832 void ValidateUninstallMsiCompatiblePackage( 1896 void ValidateUninstallMsiCompatiblePackage(
1833 __in BURN_PLAN* pPlan, 1897 __in BURN_PLAN* pPlan,
1834 __in BOOL fRollback, 1898 __in BOOL fRollback,