main
cpp 3,142 lines 121 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4
5 #define PlanDumpLevel REPORT_DEBUG
6
7 // internal struct definitions
8
9
10 // internal function definitions
11
12 static void PlannedExecutePackage(
13 __in BURN_PLAN* pPlan,
14 __in BURN_PACKAGE* pPackage
15 );
16 static void UninitializeRegistrationAction(
17 __in BURN_DEPENDENT_REGISTRATION_ACTION* pAction
18 );
19 static void UninitializeCacheAction(
20 __in BURN_CACHE_ACTION* pCacheAction
21 );
22 static void ResetPlannedContainerState(
23 __in BURN_CONTAINER* pContainer
24 );
25 static void ResetPlannedPayloadsState(
26 __in BURN_PAYLOADS* pPayloads
27 );
28 static void ResetPlannedPayloadGroupState(
29 __in BURN_PAYLOAD_GROUP* pPayloadGroup
30 );
31 static void ResetPlannedPackageState(
32 __in BURN_PACKAGE* pPackage
33 );
34 static void ResetPlannedRollbackBoundaryState(
35 __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary
36 );
37 static HRESULT PlanPackagesHelper(
38 __in BURN_PACKAGE* rgPackages,
39 __in DWORD cPackages,
40 __in BURN_USER_EXPERIENCE* pUX,
41 __in BURN_PLAN* pPlan,
42 __in BURN_LOGGING* pLog,
43 __in BURN_VARIABLES* pVariables
44 );
45 static HRESULT InitializePackage(
46 __in BURN_PLAN* pPlan,
47 __in BURN_USER_EXPERIENCE* pUX,
48 __in BURN_VARIABLES* pVariables,
49 __in BURN_PACKAGE* pPackage
50 );
51 static HRESULT ProcessPackage(
52 __in BOOL fBundlePerMachine,
53 __in BURN_USER_EXPERIENCE* pUX,
54 __in BURN_PLAN* pPlan,
55 __in BURN_PACKAGE* pPackage,
56 __in BURN_LOGGING* pLog,
57 __in BURN_VARIABLES* pVariables,
58 __inout BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary
59 );
60 static HRESULT ProcessPackageRollbackBoundary(
61 __in BURN_PLAN* pPlan,
62 __in BURN_USER_EXPERIENCE* pUX,
63 __in BURN_LOGGING* pLog,
64 __in BURN_VARIABLES* pVariables,
65 __in_opt BURN_ROLLBACK_BOUNDARY* pEffectiveRollbackBoundary,
66 __inout BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary
67 );
68 static HRESULT GetActionDefaultRequestState(
69 __in BOOTSTRAPPER_ACTION action,
70 __in BOOTSTRAPPER_PACKAGE_STATE currentState,
71 __out BOOTSTRAPPER_REQUEST_STATE* pRequestState
72 );
73 static HRESULT AddRegistrationAction(
74 __in BURN_PLAN* pPlan,
75 __in BURN_DEPENDENT_REGISTRATION_ACTION_TYPE type,
76 __in_z LPCWSTR wzDependentProviderKey,
77 __in_z LPCWSTR wzOwnerBundleId
78 );
79 static HRESULT AddCachePackage(
80 __in BURN_PLAN* pPlan,
81 __in BURN_PACKAGE* pPackage,
82 __in BOOL fVital
83 );
84 static HRESULT AddCachePackageHelper(
85 __in BURN_PLAN* pPlan,
86 __in BURN_PACKAGE* pPackage,
87 __in BOOL fVital
88 );
89 static HRESULT AddCacheSlipstreamMsps(
90 __in BURN_PLAN* pPlan,
91 __in BURN_PACKAGE* pPackage
92 );
93 static DWORD GetNextCheckpointId(
94 __in BURN_PLAN* pPlan
95 );
96 static HRESULT AppendCacheAction(
97 __in BURN_PLAN* pPlan,
98 __out BURN_CACHE_ACTION** ppCacheAction
99 );
100 static HRESULT AppendRollbackCacheAction(
101 __in BURN_PLAN* pPlan,
102 __out BURN_CACHE_ACTION** ppCacheAction
103 );
104 static HRESULT AppendCleanAction(
105 __in BURN_PLAN* pPlan,
106 __out BURN_CLEAN_ACTION** ppCleanAction
107 );
108 static HRESULT AppendRestoreRelatedBundleAction(
109 __in BURN_PLAN* pPlan,
110 __out BURN_EXECUTE_ACTION** ppExecuteAction
111 );
112 static HRESULT ProcessPayloadGroup(
113 __in BURN_PLAN* pPlan,
114 __in BURN_PAYLOAD_GROUP* pPayloadGroup
115 );
116 static void RemoveUnnecessaryActions(
117 __in BOOL fExecute,
118 __in BURN_EXECUTE_ACTION* rgActions,
119 __in DWORD cActions
120 );
121 static void FinalizePatchActions(
122 __in BOOL fExecute,
123 __in BURN_EXECUTE_ACTION* rgActions,
124 __in DWORD cActions
125 );
126 static void CalculateExpectedRegistrationStates(
127 __in BURN_PACKAGE* rgPackages,
128 __in DWORD cPackages
129 );
130 static HRESULT PlanDependencyActions(
131 __in BOOL fBundlePerMachine,
132 __in BURN_PLAN* pPlan,
133 __in BURN_PACKAGE* pPackage
134 );
135 static HRESULT CalculateExecuteActions(
136 __in BURN_PACKAGE* pPackage,
137 __in_opt BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary
138 );
139 static BURN_CACHE_PACKAGE_TYPE GetCachePackageType(
140 __in BURN_PACKAGE* pPackage,
141 __in BOOL fExecute
142 );
143 static BOOL ForceCache(
144 __in BURN_PLAN* pPlan,
145 __in BURN_PACKAGE* pPackage
146 );
147
148 // function definitions
149
150 extern "C" void PlanReset(
151 __in BURN_PLAN* pPlan,
152 __in BURN_VARIABLES* pVariables,
153 __in BURN_CONTAINERS* pContainers,
154 __in BURN_PACKAGES* pPackages,
155 __in BURN_PAYLOAD_GROUP* pLayoutPayloads
156 )
157 {
158 ReleaseNullStr(pPlan->sczLayoutDirectory);
159 PackageUninitialize(&pPlan->forwardCompatibleBundle);
160
161 if (pPlan->rgRegistrationActions)
162 {
163 for (DWORD i = 0; i < pPlan->cRegistrationActions; ++i)
164 {
165 UninitializeRegistrationAction(&pPlan->rgRegistrationActions[i]);
166 }
167 MemFree(pPlan->rgRegistrationActions);
168 }
169
170 if (pPlan->rgRollbackRegistrationActions)
171 {
172 for (DWORD i = 0; i < pPlan->cRollbackRegistrationActions; ++i)
173 {
174 UninitializeRegistrationAction(&pPlan->rgRollbackRegistrationActions[i]);
175 }
176 MemFree(pPlan->rgRollbackRegistrationActions);
177 }
178
179 if (pPlan->rgCacheActions)
180 {
181 for (DWORD i = 0; i < pPlan->cCacheActions; ++i)
182 {
183 UninitializeCacheAction(&pPlan->rgCacheActions[i]);
184 }
185 MemFree(pPlan->rgCacheActions);
186 }
187
188 if (pPlan->rgExecuteActions)
189 {
190 for (DWORD i = 0; i < pPlan->cExecuteActions; ++i)
191 {
192 PlanUninitializeExecuteAction(&pPlan->rgExecuteActions[i]);
193 }
194 MemFree(pPlan->rgExecuteActions);
195 }
196
197 if (pPlan->rgRollbackActions)
198 {
199 for (DWORD i = 0; i < pPlan->cRollbackActions; ++i)
200 {
201 PlanUninitializeExecuteAction(&pPlan->rgRollbackActions[i]);
202 }
203 MemFree(pPlan->rgRollbackActions);
204 }
205
206 if (pPlan->rgRestoreRelatedBundleActions)
207 {
208 for (DWORD i = 0; i < pPlan->cRestoreRelatedBundleActions; ++i)
209 {
210 PlanUninitializeExecuteAction(&pPlan->rgRestoreRelatedBundleActions[i]);
211 }
212 MemFree(pPlan->rgRestoreRelatedBundleActions);
213 }
214
215 if (pPlan->rgCleanActions)
216 {
217 // Nothing needs to be freed inside clean actions today.
218 MemFree(pPlan->rgCleanActions);
219 }
220
221 if (pPlan->rgPlannedProviders)
222 {
223 ReleaseDependencyArray(pPlan->rgPlannedProviders, pPlan->cPlannedProviders);
224 }
225
226 if (pPlan->rgContainerProgress)
227 {
228 MemFree(pPlan->rgContainerProgress);
229 }
230
231 if (pPlan->shContainerProgress)
232 {
233 ReleaseDict(pPlan->shContainerProgress);
234 }
235
236 if (pPlan->rgPayloadProgress)
237 {
238 MemFree(pPlan->rgPayloadProgress);
239 }
240
241 if (pPlan->shPayloadProgress)
242 {
243 ReleaseDict(pPlan->shPayloadProgress);
244 }
245
246 if (pPlan->pPayloads)
247 {
248 ResetPlannedPayloadsState(pPlan->pPayloads);
249 }
250
251 memset(pPlan, 0, sizeof(BURN_PLAN));
252
253 if (pContainers->rgContainers)
254 {
255 for (DWORD i = 0; i < pContainers->cContainers; ++i)
256 {
257 ResetPlannedContainerState(&pContainers->rgContainers[i]);
258 }
259 }
260
261 // Reset the planned actions for each package.
262 if (pPackages->rgPackages)
263 {
264 for (DWORD i = 0; i < pPackages->cPackages; ++i)
265 {
266 ResetPlannedPackageState(&pPackages->rgPackages[i]);
267 }
268 }
269
270 ResetPlannedPayloadGroupState(pLayoutPayloads);
271
272 // Reset the planned state for each rollback boundary.
273 if (pPackages->rgRollbackBoundaries)
274 {
275 for (DWORD i = 0; i < pPackages->cRollbackBoundaries; ++i)
276 {
277 ResetPlannedRollbackBoundaryState(&pPackages->rgRollbackBoundaries[i]);
278 }
279 }
280
281 PlanSetVariables(BOOTSTRAPPER_ACTION_UNKNOWN, pVariables);
282 }
283
284 extern "C" void PlanUninitializeExecuteAction(
285 __in BURN_EXECUTE_ACTION* pExecuteAction
286 )
287 {
288 switch (pExecuteAction->type)
289 {
290 case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE:
291 ReleaseStr(pExecuteAction->relatedBundle.sczIgnoreDependencies);
292 ReleaseStr(pExecuteAction->relatedBundle.sczAncestors);
293 ReleaseStr(pExecuteAction->relatedBundle.sczEngineWorkingDirectory);
294 break;
295
296 case BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE:
297 ReleaseStr(pExecuteAction->bundlePackage.sczParent);
298 ReleaseStr(pExecuteAction->bundlePackage.sczIgnoreDependencies);
299 ReleaseStr(pExecuteAction->bundlePackage.sczAncestors);
300 ReleaseStr(pExecuteAction->bundlePackage.sczEngineWorkingDirectory);
301 break;
302
303 case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE:
304 ReleaseStr(pExecuteAction->exePackage.sczAncestors);
305 ReleaseStr(pExecuteAction->exePackage.sczEngineWorkingDirectory);
306 break;
307
308 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
309 ReleaseStr(pExecuteAction->msiPackage.sczLogPath);
310 ReleaseMem(pExecuteAction->msiPackage.rgFeatures);
311 break;
312
313 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
314 ReleaseStr(pExecuteAction->mspTarget.sczTargetProductCode);
315 ReleaseStr(pExecuteAction->mspTarget.sczLogPath);
316 ReleaseMem(pExecuteAction->mspTarget.rgOrderedPatches);
317 break;
318
319 case BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE:
320 ReleaseStr(pExecuteAction->msuPackage.sczLogPath);
321 break;
322
323 case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY:
324 ReleaseStr(pExecuteAction->packageDependency.sczBundleProviderKey);
325 break;
326
327 case BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
328 ReleaseStr(pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath);
329 break;
330 }
331 }
332
333 extern "C" HRESULT PlanSetVariables(
334 __in BOOTSTRAPPER_ACTION action,
335 __in BURN_VARIABLES* pVariables
336 )
337 {
338 HRESULT hr = S_OK;
339
340 hr = VariableSetNumeric(pVariables, BURN_BUNDLE_ACTION, action, TRUE);
341 ExitOnFailure(hr, "Failed to set the bundle action built-in variable.");
342
343 LExit:
344 return hr;
345 }
346
347 extern "C" HRESULT PlanDefaultPackageRequestState(
348 __in BURN_PACKAGE_TYPE packageType,
349 __in BOOTSTRAPPER_PACKAGE_STATE currentState,
350 __in BOOTSTRAPPER_ACTION action,
351 __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition,
352 __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT repairCondition,
353 __in BOOTSTRAPPER_RELATION_TYPE relationType,
354 __out BOOTSTRAPPER_REQUEST_STATE* pRequestState
355 )
356 {
357 HRESULT hr = S_OK;
358 BOOTSTRAPPER_REQUEST_STATE defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
359
360 // If doing layout, then always default to requesting the package be cached.
361 if (BOOTSTRAPPER_ACTION_LAYOUT == action)
362 {
363 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_CACHE;
364 }
365 else if (BOOTSTRAPPER_ACTION_CACHE == action)
366 {
367 switch (currentState)
368 {
369 case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: __fallthrough;
370 case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
371 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
372 break;
373
374 default:
375 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_CACHE;
376 break;
377 }
378 }
379 else if (BOOTSTRAPPER_RELATION_PATCH == relationType && BURN_PACKAGE_TYPE_MSP == packageType)
380 {
381 // For patch related bundles, only install a patch if currently absent during install, modify, or repair.
382 if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT != currentState)
383 {
384 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
385 }
386 else if (BOOTSTRAPPER_ACTION_INSTALL == action ||
387 BOOTSTRAPPER_ACTION_MODIFY == action ||
388 BOOTSTRAPPER_ACTION_REPAIR == action)
389 {
390 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
391 }
392 }
393 else // pick the best option for the action state and install condition.
394 {
395 hr = GetActionDefaultRequestState(action, currentState, &defaultRequestState);
396 ExitOnFailure(hr, "Failed to get default request state for action.");
397
398 if (BOOTSTRAPPER_ACTION_UNINSTALL != action && BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL != action)
399 {
400 // If we're not doing an uninstall, use the install condition
401 // to determine whether to use the default request state or make the package absent.
402 if (BOOTSTRAPPER_PACKAGE_CONDITION_FALSE == installCondition)
403 {
404 defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT;
405 }
406 // Obsolete means the package is not on the machine and should not be installed,
407 // *except* patches can be obsolete and present.
408 // Superseded means the package is on the machine but not active, so only uninstall operations are allowed.
409 // All other operations do nothing.
410 else if (BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE == currentState || BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED == currentState)
411 {
412 defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT <= defaultRequestState ? BOOTSTRAPPER_REQUEST_STATE_NONE : defaultRequestState;
413 }
414 else if (BOOTSTRAPPER_ACTION_REPAIR == action && BOOTSTRAPPER_PACKAGE_CONDITION_FALSE == repairCondition)
415 {
416 defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
417 }
418 }
419
420 *pRequestState = defaultRequestState;
421 }
422
423 LExit:
424 return hr;
425 }
426
427 extern "C" HRESULT PlanLayoutBundle(
428 __in BURN_PLAN* pPlan,
429 __in_z LPCWSTR wzExecutableName,
430 __in DWORD64 qwBundleSize,
431 __in BURN_VARIABLES* pVariables,
432 __in BURN_PAYLOAD_GROUP* pLayoutPayloads
433 )
434 {
435 HRESULT hr = S_OK;
436 BURN_CACHE_ACTION* pCacheAction = NULL;
437 LPWSTR sczLayoutDirectory = NULL;
438 LPWSTR sczExecutablePath = NULL;
439
440 // Get the layout directory.
441 hr = VariableGetString(pVariables, BURN_BUNDLE_LAYOUT_DIRECTORY, &sczLayoutDirectory);
442 if (E_NOTFOUND == hr) // if not set, use the current directory as the layout directory.
443 {
444 hr = PathForCurrentProcess(&sczExecutablePath, NULL);
445 ExitOnFailure(hr, "Failed to get path for current executing process as layout directory.");
446
447 hr = PathGetDirectory(sczExecutablePath, &sczLayoutDirectory);
448 ExitOnFailure(hr, "Failed to get executing process as layout directory.");
449 }
450 ExitOnFailure(hr, "Failed to get bundle layout directory property.");
451
452 hr = PathGetFullPathName(sczLayoutDirectory, &pPlan->sczLayoutDirectory, NULL, NULL);
453 ExitOnFailure(hr, "Failed to ensure layout directory is fully qualified.");
454
455 hr = PathBackslashTerminate(&pPlan->sczLayoutDirectory);
456 ExitOnFailure(hr, "Failed to ensure layout directory is backslash terminated.");
457
458 hr = ProcessPayloadGroup(pPlan, pLayoutPayloads);
459 ExitOnFailure(hr, "Failed to process payload group for bundle.");
460
461 // Plan the layout of the bundle engine itself.
462 hr = AppendCacheAction(pPlan, &pCacheAction);
463 ExitOnFailure(hr, "Failed to append bundle start action.");
464
465 pCacheAction->type = BURN_CACHE_ACTION_TYPE_LAYOUT_BUNDLE;
466
467 hr = StrAllocString(&pCacheAction->bundleLayout.sczExecutableName, wzExecutableName, 0);
468 ExitOnFailure(hr, "Failed to to copy executable name for bundle.");
469
470 hr = CacheCalculateBundleLayoutWorkingPath(pPlan->pCache, pPlan->wzBundleId, &pCacheAction->bundleLayout.sczUnverifiedPath);
471 ExitOnFailure(hr, "Failed to calculate bundle layout working path.");
472
473 pCacheAction->bundleLayout.qwBundleSize = qwBundleSize;
474 pCacheAction->bundleLayout.pPayloadGroup = pLayoutPayloads;
475
476 // Acquire + Verify + Finalize
477 pPlan->qwCacheSizeTotal += 3 * qwBundleSize;
478
479 ++pPlan->cOverallProgressTicksTotal;
480
481 LExit:
482 ReleaseStr(sczExecutablePath);
483 ReleaseStr(sczLayoutDirectory);
484
485 return hr;
486 }
487
488 extern "C" HRESULT PlanForwardCompatibleBundles(
489 __in BURN_USER_EXPERIENCE* pUX,
490 __in BURN_PLAN* pPlan,
491 __in BURN_REGISTRATION* pRegistration
492 )
493 {
494 HRESULT hr = S_OK;
495 BOOL fRecommendIgnore = TRUE;
496 BOOL fIgnoreBundle = FALSE;
497 BOOTSTRAPPER_ACTION action = pPlan->action;
498
499 if (!pRegistration->fForwardCompatibleBundleExists)
500 {
501 ExitFunction();
502 }
503
504 // Only change the recommendation if an active parent was provided.
505 if (pPlan->pInternalCommand->sczActiveParent && *pPlan->pInternalCommand->sczActiveParent)
506 {
507 // On install, recommend running the forward compatible bundle because there is an active parent. This
508 // will essentially register the parent with the forward compatible bundle.
509 if (BOOTSTRAPPER_ACTION_INSTALL == action)
510 {
511 fRecommendIgnore = FALSE;
512 }
513 else if (BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == action ||
514 BOOTSTRAPPER_ACTION_UNINSTALL == action ||
515 BOOTSTRAPPER_ACTION_MODIFY == action ||
516 BOOTSTRAPPER_ACTION_REPAIR == action)
517 {
518 // When modifying the bundle, only recommend running the forward compatible bundle if the parent
519 // is already registered as a dependent of the provider key.
520 if (pRegistration->fParentRegisteredAsDependent)
521 {
522 fRecommendIgnore = FALSE;
523 }
524 }
525 }
526
527 for (DWORD iRelatedBundle = 0; iRelatedBundle < pRegistration->relatedBundles.cRelatedBundles; ++iRelatedBundle)
528 {
529 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle;
530 if (!pRelatedBundle->fForwardCompatible)
531 {
532 continue;
533 }
534
535 fIgnoreBundle = fRecommendIgnore;
536
537 hr = BACallbackOnPlanForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->detectRelationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, &fIgnoreBundle);
538 ExitOnRootFailure(hr, "BA aborted plan forward compatible bundle.");
539
540 if (!fIgnoreBundle)
541 {
542 hr = PseudoBundleInitializePassthrough(&pPlan->forwardCompatibleBundle, pPlan->pInternalCommand, pPlan->pCommand, &pRelatedBundle->package);
543 ExitOnFailure(hr, "Failed to initialize pass through bundle.");
544
545 pPlan->fEnabledForwardCompatibleBundle = TRUE;
546 break;
547 }
548 }
549
550 LExit:
551 return hr;
552 }
553
554 extern "C" HRESULT PlanPackages(
555 __in BURN_USER_EXPERIENCE* pUX,
556 __in BURN_PACKAGES* pPackages,
557 __in BURN_PLAN* pPlan,
558 __in BURN_LOGGING* pLog,
559 __in BURN_VARIABLES* pVariables
560 )
561 {
562 HRESULT hr = S_OK;
563
564 hr = PlanPackagesHelper(pPackages->rgPackages, pPackages->cPackages, pUX, pPlan, pLog, pVariables);
565
566 return hr;
567 }
568
569 extern "C" HRESULT PlanRegistration(
570 __in BURN_PLAN* pPlan,
571 __in BURN_REGISTRATION* pRegistration,
572 __in BURN_DEPENDENCIES* pDependencies,
573 __in BOOTSTRAPPER_RESUME_TYPE /*resumeType*/,
574 __in BOOTSTRAPPER_RELATION_TYPE relationType,
575 __inout BOOL* pfContinuePlanning
576 )
577 {
578 HRESULT hr = S_OK;
579 STRINGDICT_HANDLE sdBundleDependents = NULL;
580 STRINGDICT_HANDLE sdIgnoreDependents = NULL;
581 BOOL fDependentBlocksUninstall = FALSE;
582
583 pPlan->fCanAffectMachineState = TRUE; // register the bundle since we're modifying machine state.
584 pPlan->fDisallowRemoval = FALSE; // by default the bundle can be planned to be removed
585
586 // Ensure the bundle is cached if not running from the cache.
587 if (!CacheBundleRunningFromCache(pPlan->pCache))
588 {
589 pPlan->dwRegistrationOperations |= BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE;
590 }
591
592 if (pPlan->pInternalCommand->fArpSystemComponent)
593 {
594 pPlan->dwRegistrationOperations |= BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT;
595 }
596
597 if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action)
598 {
599 // If our provider key was not owned by a different bundle,
600 // then plan to write our provider key registration to "fix it" if broken
601 // in case the bundle isn't successfully uninstalled.
602 if (!pRegistration->fDetectedForeignProviderKeyBundleId)
603 {
604 pPlan->dwRegistrationOperations |= BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY;
605 }
606
607 // Create the dictionary of dependents that should be ignored.
608 hr = DictCreateStringList(&sdIgnoreDependents, 5, DICT_FLAG_CASEINSENSITIVE);
609 ExitOnFailure(hr, "Failed to create the string dictionary.");
610
611 // If the self-dependent dependent exists, plan its removal. If we did not do this, we
612 // would prevent self-removal.
613 if (pRegistration->fSelfRegisteredAsDependent)
614 {
615 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_UNREGISTER, pDependencies->wzSelfDependent, pRegistration->sczId);
616 ExitOnFailure(hr, "Failed to allocate registration action.");
617
618 hr = DependencyAddIgnoreDependencies(sdIgnoreDependents, pDependencies->wzSelfDependent);
619 ExitOnFailure(hr, "Failed to add self-dependent to ignore dependents.");
620 }
621
622 if (!pDependencies->fIgnoreAllDependents)
623 {
624 // If we are not doing an upgrade, we check to see if there are still dependents on us and if so we skip planning.
625 // However, when being upgraded, we always execute our uninstall because a newer version of us is probably
626 // already on the machine and we need to clean up the stuff specific to this bundle.
627 if (BOOTSTRAPPER_RELATION_UPGRADE != relationType)
628 {
629 // If there were other dependencies to ignore, add them.
630 for (DWORD iDependency = 0; iDependency < pDependencies->cIgnoredDependencies; ++iDependency)
631 {
632 DEPENDENCY* pDependency = pDependencies->rgIgnoredDependencies + iDependency;
633
634 hr = DictKeyExists(sdIgnoreDependents, pDependency->sczKey);
635 if (E_NOTFOUND != hr)
636 {
637 ExitOnFailure(hr, "Failed to check the dictionary of ignored dependents.");
638 }
639 else
640 {
641 hr = DictAddKey(sdIgnoreDependents, pDependency->sczKey);
642 ExitOnFailure(hr, "Failed to add dependent key to ignored dependents.");
643 }
644 }
645
646 // For addon or patch bundles, dependent related bundles should be ignored. This allows
647 // that addon or patch to be removed even though bundles it targets still are registered.
648 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
649 {
650 const BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i;
651
652 if (BOOTSTRAPPER_RELATION_DEPENDENT_ADDON == pRelatedBundle->planRelationType ||
653 BOOTSTRAPPER_RELATION_DEPENDENT_PATCH == pRelatedBundle->planRelationType)
654 {
655 for (DWORD j = 0; j < pRelatedBundle->package.cDependencyProviders; ++j)
656 {
657 const BURN_DEPENDENCY_PROVIDER* pProvider = pRelatedBundle->package.rgDependencyProviders + j;
658
659 hr = DependencyAddIgnoreDependencies(sdIgnoreDependents, pProvider->sczKey);
660 ExitOnFailure(hr, "Failed to add dependent bundle provider key to ignore dependents.");
661 }
662 }
663 }
664
665 // If there are any (non-ignored and not-planned-to-be-removed) dependents left, skip planning.
666 for (DWORD iDependent = 0; iDependent < pRegistration->cDependents; ++iDependent)
667 {
668 DEPENDENCY* pDependent = pRegistration->rgDependents + iDependent;
669
670 hr = DictKeyExists(sdIgnoreDependents, pDependent->sczKey);
671 if (E_NOTFOUND == hr)
672 {
673 hr = S_OK;
674
675 // TODO: callback to the BA and let it have the option to ignore this dependent?
676 if (!fDependentBlocksUninstall)
677 {
678 fDependentBlocksUninstall = TRUE;
679
680 LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS);
681 }
682
683 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_BUNDLE_DEPENDENT, pDependent->sczKey, LoggingStringOrUnknownIfNull(pDependent->sczName));
684 }
685 ExitOnFailure(hr, "Failed to check for remaining dependents during planning.");
686 }
687
688 if (fDependentBlocksUninstall)
689 {
690 if (BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action)
691 {
692 fDependentBlocksUninstall = FALSE;
693 LogId(REPORT_STANDARD, MSG_PLAN_NOT_SKIPPED_DUE_TO_DEPENDENTS);
694 }
695 else
696 {
697 pPlan->fDisallowRemoval = TRUE; // ensure the registration stays
698 *pfContinuePlanning = FALSE; // skip the rest of planning.
699 }
700 }
701 }
702 }
703 }
704 else
705 {
706 BOOL fAddonOrPatchBundle = (pRegistration->cAddonCodes || pRegistration->cPatchCodes);
707
708 // Always plan to write our provider key registration when installing/modify/repair to "fix it"
709 // if broken.
710 pPlan->dwRegistrationOperations |= BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY;
711
712 // Create the dictionary of bundle dependents.
713 hr = DictCreateStringList(&sdBundleDependents, 5, DICT_FLAG_CASEINSENSITIVE);
714 ExitOnFailure(hr, "Failed to create the string dictionary.");
715
716 for (DWORD iDependent = 0; iDependent < pRegistration->cDependents; ++iDependent)
717 {
718 DEPENDENCY* pDependent = pRegistration->rgDependents + iDependent;
719
720 hr = DictKeyExists(sdBundleDependents, pDependent->sczKey);
721 if (E_NOTFOUND == hr)
722 {
723 hr = DictAddKey(sdBundleDependents, pDependent->sczKey);
724 ExitOnFailure(hr, "Failed to add dependent key to bundle dependents.");
725 }
726 ExitOnFailure(hr, "Failed to check the dictionary of bundle dependents.");
727 }
728
729 // Register each dependent related bundle. The ensures that addons and patches are reference
730 // counted and stick around until the last targeted bundle is removed.
731 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
732 {
733 const BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i;
734
735 if (BOOTSTRAPPER_RELATION_DEPENDENT_ADDON == pRelatedBundle->planRelationType ||
736 BOOTSTRAPPER_RELATION_DEPENDENT_PATCH == pRelatedBundle->planRelationType)
737 {
738 for (DWORD j = 0; j < pRelatedBundle->package.cDependencyProviders; ++j)
739 {
740 const BURN_DEPENDENCY_PROVIDER* pProvider = pRelatedBundle->package.rgDependencyProviders + j;
741
742 hr = DictKeyExists(sdBundleDependents, pProvider->sczKey);
743 if (E_NOTFOUND == hr)
744 {
745 hr = DictAddKey(sdBundleDependents, pProvider->sczKey);
746 ExitOnFailure(hr, "Failed to add new dependent key to bundle dependents.");
747
748 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER, pProvider->sczKey, pRelatedBundle->package.sczId);
749 ExitOnFailure(hr, "Failed to add registration action for dependent related bundle.");
750 }
751 ExitOnFailure(hr, "Failed to check the dictionary of bundle dependents.");
752 }
753 }
754 }
755
756 // Only do the following if we decided there was a dependent self to register. If so and and an explicit parent was
757 // provided, register dependent self. Otherwise, if this bundle is not an addon or patch bundle then self-regisiter
758 // as our own dependent.
759 if (pDependencies->wzSelfDependent && !pRegistration->fSelfRegisteredAsDependent && (pDependencies->wzActiveParent || !fAddonOrPatchBundle))
760 {
761 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER, pDependencies->wzSelfDependent, pRegistration->sczId);
762 ExitOnFailure(hr, "Failed to add registration action for self dependent.");
763 }
764 }
765
766 LExit:
767 ReleaseDict(sdBundleDependents);
768 ReleaseDict(sdIgnoreDependents);
769
770 return hr;
771 }
772
773 extern "C" HRESULT PlanPassThroughBundle(
774 __in BURN_USER_EXPERIENCE* pUX,
775 __in BURN_PACKAGE* pPackage,
776 __in BURN_PLAN* pPlan,
777 __in BURN_LOGGING* pLog,
778 __in BURN_VARIABLES* pVariables
779 )
780 {
781 HRESULT hr = S_OK;
782
783 // Plan passthrough package.
784 hr = PlanPackagesHelper(pPackage, 1, pUX, pPlan, pLog, pVariables);
785 ExitOnFailure(hr, "Failed to process passthrough package.");
786
787 LExit:
788 return hr;
789 }
790
791 extern "C" HRESULT PlanUpdateBundle(
792 __in BURN_USER_EXPERIENCE* pUX,
793 __in BURN_PACKAGE* pPackage,
794 __in BURN_PLAN* pPlan,
795 __in BURN_LOGGING* pLog,
796 __in BURN_VARIABLES* pVariables
797 )
798 {
799 HRESULT hr = S_OK;
800
801 Assert(!pPackage->fPerMachine);
802 Assert(BURN_PACKAGE_TYPE_EXE == pPackage->type);
803 pPackage->Exe.fFireAndForget = BOOTSTRAPPER_ACTION_UPDATE_REPLACE == pPlan->action;
804
805 // Plan update package.
806 hr = PlanPackagesHelper(pPackage, 1, pUX, pPlan, pLog, pVariables);
807 ExitOnFailure(hr, "Failed to process update package.");
808
809 LExit:
810 return hr;
811 }
812
813 static HRESULT PlanPackagesHelper(
814 __in BURN_PACKAGE* rgPackages,
815 __in DWORD cPackages,
816 __in BURN_USER_EXPERIENCE* pUX,
817 __in BURN_PLAN* pPlan,
818 __in BURN_LOGGING* pLog,
819 __in BURN_VARIABLES* pVariables
820 )
821 {
822 HRESULT hr = S_OK;
823 BOOL fBundlePerMachine = pPlan->fPerMachine; // bundle is per-machine if plan starts per-machine.
824 BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = NULL;
825 BOOL fReverseOrder = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action;
826
827 // Initialize the packages.
828 for (DWORD i = 0; i < cPackages; ++i)
829 {
830 DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i;
831 BURN_PACKAGE* pPackage = rgPackages + iPackage;
832
833 hr = InitializePackage(pPlan, pUX, pVariables, pPackage);
834 ExitOnFailure(hr, "Failed to initialize package.");
835 }
836
837 // Initialize the patch targets after all packages, since they could rely on the requested state of packages that are after the patch's package in the chain.
838 for (DWORD i = 0; i < cPackages; ++i)
839 {
840 DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i;
841 BURN_PACKAGE* pPackage = rgPackages + iPackage;
842
843 if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
844 {
845 hr = MspEnginePlanInitializePackage(pPackage, pUX);
846 ExitOnFailure(hr, "Failed to initialize plan package: %ls", pPackage->sczId);
847 }
848 }
849
850 // Plan the packages.
851 for (DWORD i = 0; i < cPackages; ++i)
852 {
853 DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i;
854 BURN_PACKAGE* pPackage = rgPackages + iPackage;
855
856 hr = ProcessPackage(fBundlePerMachine, pUX, pPlan, pPackage, pLog, pVariables, &pRollbackBoundary);
857 ExitOnFailure(hr, "Failed to process package.");
858 }
859
860 // If we still have an open rollback boundary, complete it.
861 if (pRollbackBoundary)
862 {
863 hr = PlanRollbackBoundaryComplete(pPlan);
864 ExitOnFailure(hr, "Failed to plan final rollback boundary complete.");
865
866 pRollbackBoundary = NULL;
867 }
868
869 // Passthrough packages are never cleaned up by the calling bundle (they delete themselves when appropriate).
870 if (!pPlan->fEnabledForwardCompatibleBundle && BOOTSTRAPPER_ACTION_LAYOUT != pPlan->action)
871 {
872 // Plan clean up of packages.
873 for (DWORD i = 0; i < cPackages; ++i)
874 {
875 DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i;
876 BURN_PACKAGE* pPackage = rgPackages + iPackage;
877
878 hr = PlanCleanPackage(pPlan, pPackage);
879 ExitOnFailure(hr, "Failed to plan clean package.");
880 }
881 }
882
883 // Remove unnecessary actions.
884 hr = PlanFinalizeActions(pPlan);
885 ExitOnFailure(hr, "Failed to remove unnecessary actions from plan.");
886
887 CalculateExpectedRegistrationStates(rgPackages, cPackages);
888
889 // Let the BA know the actions that were planned.
890 for (DWORD i = 0; i < cPackages; ++i)
891 {
892 DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i;
893 BURN_PACKAGE* pPackage = rgPackages + iPackage;
894
895 BACallbackOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, NULL != pPackage->hCacheEvent, pPackage->fPlannedUncache);
896
897 if (pPackage->compatiblePackage.fPlannable)
898 {
899 BACallbackOnPlannedCompatiblePackage(pUX, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.fRemove);
900 }
901 }
902
903 LExit:
904 return hr;
905 }
906
907 static HRESULT InitializePackage(
908 __in BURN_PLAN* pPlan,
909 __in BURN_USER_EXPERIENCE* pUX,
910 __in BURN_VARIABLES* pVariables,
911 __in BURN_PACKAGE* pPackage
912 )
913 {
914 HRESULT hr = S_OK;
915 BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition = BOOTSTRAPPER_PACKAGE_CONDITION_DEFAULT;
916 BOOTSTRAPPER_PACKAGE_CONDITION_RESULT repairCondition = BOOTSTRAPPER_PACKAGE_CONDITION_DEFAULT;
917 BOOL fEvaluatedCondition = FALSE;
918 BOOL fBeginCalled = FALSE;
919 BOOTSTRAPPER_RELATION_TYPE relationType = pPlan->pCommand->relationType;
920
921 if (BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fPseudoPackage)
922 {
923 // Exe pseudo packages are not configurable.
924 // The BA already requested this package to be executed
925 // * by the overall plan action for UpdateReplace
926 // * by enabling the forward compatible bundle for Passthrough
927 pPackage->defaultRequested = pPackage->requested = BOOTSTRAPPER_REQUEST_STATE_FORCE_PRESENT;
928 ExitFunction();
929 }
930
931 if (pPackage->fCanAffectRegistration)
932 {
933 pPackage->expectedCacheRegistrationState = pPackage->cacheRegistrationState;
934 pPackage->expectedInstallRegistrationState = pPackage->installRegistrationState;
935 }
936
937 if (pPackage->sczInstallCondition && *pPackage->sczInstallCondition)
938 {
939 hr = ConditionEvaluate(pVariables, pPackage->sczInstallCondition, &fEvaluatedCondition);
940 ExitOnFailure(hr, "Failed to evaluate install condition.");
941
942 installCondition = fEvaluatedCondition ? BOOTSTRAPPER_PACKAGE_CONDITION_TRUE : BOOTSTRAPPER_PACKAGE_CONDITION_FALSE;
943 }
944
945 if (pPackage->sczRepairCondition && *pPackage->sczRepairCondition)
946 {
947 hr = ConditionEvaluate(pVariables, pPackage->sczRepairCondition, &fEvaluatedCondition);
948 ExitOnFailure(hr, "Failed to evaluate repair condition.");
949
950 repairCondition = fEvaluatedCondition ? BOOTSTRAPPER_PACKAGE_CONDITION_TRUE : BOOTSTRAPPER_PACKAGE_CONDITION_FALSE;
951 }
952
953 // Remember the default requested state so the engine doesn't get blamed for planning the wrong thing if the BA changes it.
954 hr = PlanDefaultPackageRequestState(pPackage->type, pPackage->currentState, pPlan->action, installCondition, repairCondition, relationType, &pPackage->defaultRequested);
955 ExitOnFailure(hr, "Failed to set default package state.");
956
957 pPackage->requested = pPackage->defaultRequested;
958 fBeginCalled = TRUE;
959
960 hr = BACallbackOnPlanPackageBegin(pUX, pPackage->sczId, pPackage->currentState, pPackage->fCached, installCondition, repairCondition, &pPackage->requested, &pPackage->cacheType);
961 ExitOnRootFailure(hr, "BA aborted plan package begin.");
962
963 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
964 {
965 hr = MsiEnginePlanInitializePackage(pPackage, pPlan->action, pVariables, pUX);
966 ExitOnFailure(hr, "Failed to initialize plan package: %ls", pPackage->sczId);
967 }
968
969 LExit:
970 if (fBeginCalled)
971 {
972 BACallbackOnPlanPackageComplete(pUX, pPackage->sczId, hr, pPackage->requested);
973 }
974
975 return hr;
976 }
977
978 static HRESULT ProcessPackage(
979 __in BOOL fBundlePerMachine,
980 __in BURN_USER_EXPERIENCE* pUX,
981 __in BURN_PLAN* pPlan,
982 __in BURN_PACKAGE* pPackage,
983 __in BURN_LOGGING* pLog,
984 __in BURN_VARIABLES* pVariables,
985 __inout BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary
986 )
987 {
988 HRESULT hr = S_OK;
989 BURN_ROLLBACK_BOUNDARY* pEffectiveRollbackBoundary = NULL;
990 BOOL fBackward = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action;
991
992 pEffectiveRollbackBoundary = fBackward ? pPackage->pRollbackBoundaryBackward : pPackage->pRollbackBoundaryForward;
993 hr = ProcessPackageRollbackBoundary(pPlan, pUX, pLog, pVariables, pEffectiveRollbackBoundary, ppRollbackBoundary);
994 ExitOnFailure(hr, "Failed to process package rollback boundary.");
995
996 if (BOOTSTRAPPER_ACTION_LAYOUT == pPlan->action)
997 {
998 if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested)
999 {
1000 hr = PlanLayoutPackage(pPlan, pPackage, TRUE);
1001 ExitOnFailure(hr, "Failed to plan layout package.");
1002 }
1003 }
1004 else
1005 {
1006 if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested || pPackage->compatiblePackage.fRequested)
1007 {
1008 // If the package is in a requested state, plan it.
1009 hr = PlanExecutePackage(fBundlePerMachine, pUX, pPlan, pPackage, pLog, pVariables);
1010 ExitOnFailure(hr, "Failed to plan execute package.");
1011 }
1012 else
1013 {
1014 if (ForceCache(pPlan, pPackage))
1015 {
1016 hr = AddCachePackage(pPlan, pPackage, TRUE);
1017 ExitOnFailure(hr, "Failed to plan cache package.");
1018
1019 if (pPackage->fPerMachine)
1020 {
1021 pPlan->fPerMachine = TRUE;
1022 }
1023 }
1024
1025 // Make sure the package is properly ref-counted even if no plan is requested.
1026 hr = PlanDependencyActions(fBundlePerMachine, pPlan, pPackage);
1027 ExitOnFailure(hr, "Failed to plan dependency actions for package: %ls", pPackage->sczId);
1028 }
1029 }
1030
1031 // Add the checkpoint after each package and dependency registration action.
1032 if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute || BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback || BURN_DEPENDENCY_ACTION_NONE != pPackage->dependencyExecute)
1033 {
1034 hr = PlanExecuteCheckpoint(pPlan);
1035 ExitOnFailure(hr, "Failed to append execute checkpoint.");
1036 }
1037
1038 LExit:
1039 return hr;
1040 }
1041
1042 static HRESULT ProcessPackageRollbackBoundary(
1043 __in BURN_PLAN* pPlan,
1044 __in BURN_USER_EXPERIENCE* pUX,
1045 __in BURN_LOGGING* pLog,
1046 __in BURN_VARIABLES* pVariables,
1047 __in_opt BURN_ROLLBACK_BOUNDARY* pEffectiveRollbackBoundary,
1048 __inout BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary
1049 )
1050 {
1051 HRESULT hr = S_OK;
1052
1053 // If the package marks the start of a rollback boundary, start a new one.
1054 if (pEffectiveRollbackBoundary)
1055 {
1056 // Complete previous rollback boundary.
1057 if (*ppRollbackBoundary)
1058 {
1059 hr = PlanRollbackBoundaryComplete(pPlan);
1060 ExitOnFailure(hr, "Failed to plan rollback boundary complete.");
1061 }
1062
1063 // Start new rollback boundary.
1064 hr = PlanRollbackBoundaryBegin(pPlan, pUX, pLog, pVariables, pEffectiveRollbackBoundary);
1065 ExitOnFailure(hr, "Failed to plan rollback boundary begin.");
1066
1067 *ppRollbackBoundary = pEffectiveRollbackBoundary;
1068 }
1069
1070 LExit:
1071 return hr;
1072 }
1073
1074 extern "C" HRESULT PlanLayoutContainer(
1075 __in BURN_PLAN* pPlan,
1076 __in BURN_CONTAINER* pContainer
1077 )
1078 {
1079 HRESULT hr = S_OK;
1080 BURN_CACHE_ACTION* pCacheAction = NULL;
1081
1082 Assert(!pContainer->fPlanned);
1083 pContainer->fPlanned = TRUE;
1084
1085 if (pPlan->sczLayoutDirectory)
1086 {
1087 if (!pContainer->fAttached)
1088 {
1089 hr = AppendCacheAction(pPlan, &pCacheAction);
1090 ExitOnFailure(hr, "Failed to append package start action.");
1091
1092 pCacheAction->type = BURN_CACHE_ACTION_TYPE_CONTAINER;
1093 pCacheAction->container.pContainer = pContainer;
1094
1095 // Acquire + Verify + Finalize
1096 pPlan->qwCacheSizeTotal += 3 * pContainer->qwFileSize;
1097 }
1098 }
1099 else
1100 {
1101 if (!pContainer->fActuallyAttached)
1102 {
1103 // Acquire
1104 pPlan->qwCacheSizeTotal += pContainer->qwFileSize;
1105 }
1106 }
1107
1108 if (!pContainer->sczUnverifiedPath)
1109 {
1110 if (pContainer->fActuallyAttached)
1111 {
1112 hr = PathForCurrentProcess(&pContainer->sczUnverifiedPath, NULL);
1113 ExitOnFailure(hr, "Failed to get path for executing module as attached container working path.");
1114 }
1115 else
1116 {
1117 hr = CacheCalculateContainerWorkingPath(pPlan->pCache, pContainer, &pContainer->sczUnverifiedPath);
1118 ExitOnFailure(hr, "Failed to calculate unverified path for container.");
1119 }
1120 }
1121
1122 LExit:
1123 return hr;
1124 }
1125
1126 extern "C" HRESULT PlanLayoutPackage(
1127 __in BURN_PLAN* pPlan,
1128 __in BURN_PACKAGE* pPackage,
1129 __in BOOL fVital
1130 )
1131 {
1132 HRESULT hr = S_OK;
1133 BURN_CACHE_ACTION* pCacheAction = NULL;
1134
1135 AssertSz(!pPlan->fEnabledForwardCompatibleBundle, "Passthrough packages must already be cached");
1136
1137 hr = ProcessPayloadGroup(pPlan, &pPackage->payloads);
1138 ExitOnFailure(hr, "Failed to process payload group for package: %ls.", pPackage->sczId);
1139
1140 hr = AppendCacheAction(pPlan, &pCacheAction);
1141 ExitOnFailure(hr, "Failed to append package start action.");
1142
1143 pCacheAction->type = BURN_CACHE_ACTION_TYPE_PACKAGE;
1144 pCacheAction->package.pPackage = pPackage;
1145 pPackage->fCacheVital = fVital;
1146
1147 ++pPlan->cOverallProgressTicksTotal;
1148
1149 LExit:
1150 return hr;
1151 }
1152
1153 extern "C" HRESULT PlanExecutePackage(
1154 __in BOOL fPerMachine,
1155 __in BURN_USER_EXPERIENCE* pUserExperience,
1156 __in BURN_PLAN* pPlan,
1157 __in BURN_PACKAGE* pPackage,
1158 __in BURN_LOGGING* pLog,
1159 __in BURN_VARIABLES* pVariables
1160 )
1161 {
1162 HRESULT hr = S_OK;
1163 BOOTSTRAPPER_DISPLAY display = pPlan->pCommand->display;
1164 BOOL fRequestedCache = BOOTSTRAPPER_CACHE_TYPE_REMOVE < pPackage->cacheType && (BOOTSTRAPPER_REQUEST_STATE_CACHE == pPackage->requested || ForceCache(pPlan, pPackage));
1165
1166 hr = CalculateExecuteActions(pPackage, pPlan->pActiveRollbackBoundary);
1167 ExitOnFailure(hr, "Failed to calculate plan actions for package: %ls", pPackage->sczId);
1168
1169 // Calculate package states based on reference count and plan certain dependency actions prior to planning the package execute action.
1170 hr = DependencyPlanPackageBegin(fPerMachine, pPackage, pPlan);
1171 ExitOnFailure(hr, "Failed to begin plan dependency actions for package: %ls", pPackage->sczId);
1172
1173 pPackage->executeCacheType = fRequestedCache ? BURN_CACHE_PACKAGE_TYPE_REQUIRED : GetCachePackageType(pPackage, TRUE);
1174 pPackage->rollbackCacheType = GetCachePackageType(pPackage, FALSE);
1175
1176 if (BURN_CACHE_PACKAGE_TYPE_NONE != pPackage->executeCacheType || BURN_CACHE_PACKAGE_TYPE_NONE != pPackage->rollbackCacheType)
1177 {
1178 hr = AddCachePackage(pPlan, pPackage, BURN_CACHE_PACKAGE_TYPE_REQUIRED == pPackage->executeCacheType);
1179 ExitOnFailure(hr, "Failed to plan cache package.");
1180 }
1181
1182 // Add execute actions.
1183 switch (pPackage->type)
1184 {
1185 case BURN_PACKAGE_TYPE_BUNDLE:
1186 hr = BundlePackageEnginePlanAddPackage(pPackage, pPlan, pLog, pVariables);
1187 break;
1188
1189 case BURN_PACKAGE_TYPE_EXE:
1190 hr = ExeEnginePlanAddPackage(pPackage, pPlan, pLog, pVariables);
1191 break;
1192
1193 case BURN_PACKAGE_TYPE_MSI:
1194 hr = MsiEnginePlanAddPackage(display, pUserExperience, pPackage, pPlan, pLog, pVariables);
1195 break;
1196
1197 case BURN_PACKAGE_TYPE_MSP:
1198 hr = MspEnginePlanAddPackage(display, pUserExperience, pPackage, pPlan, pLog, pVariables);
1199 break;
1200
1201 case BURN_PACKAGE_TYPE_MSU:
1202 hr = MsuEnginePlanAddPackage(pPackage, pPlan, pLog, pVariables);
1203 break;
1204
1205 default:
1206 hr = E_UNEXPECTED;
1207 ExitOnFailure(hr, "Invalid package type.");
1208 }
1209 ExitOnFailure(hr, "Failed to add plan actions for package: %ls", pPackage->sczId);
1210
1211 // Plan certain dependency actions after planning the package execute action.
1212 hr = DependencyPlanPackageComplete(pPackage, pPlan);
1213 ExitOnFailure(hr, "Failed to complete plan dependency actions for package: %ls", pPackage->sczId);
1214
1215 // If we are going to take any action on this package, add progress for it.
1216 if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute || BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback)
1217 {
1218 PlannedExecutePackage(pPlan, pPackage);
1219 }
1220
1221 // If we are going to take any action on the compatible package, add progress for it.
1222 if (pPackage->compatiblePackage.fRemove)
1223 {
1224 PlannedExecutePackage(pPlan, pPackage);
1225 }
1226
1227 LExit:
1228 return hr;
1229 }
1230
1231 extern "C" HRESULT PlanDefaultRelatedBundlePlanType(
1232 __in BOOTSTRAPPER_RELATION_TYPE relatedBundleRelationType,
1233 __in VERUTIL_VERSION* pRegistrationVersion,
1234 __in VERUTIL_VERSION* pRelatedBundleVersion,
1235 __inout BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE* pPlanRelationType
1236 )
1237 {
1238 HRESULT hr = S_OK;
1239 int nCompareResult = 0;
1240
1241 switch (relatedBundleRelationType)
1242 {
1243 case BOOTSTRAPPER_RELATION_UPGRADE:
1244 hr = VerCompareParsedVersions(pRegistrationVersion, pRelatedBundleVersion, &nCompareResult);
1245 ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistrationVersion->sczVersion, pRelatedBundleVersion->sczVersion);
1246
1247 if (nCompareResult < 0)
1248 {
1249 *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE;
1250 }
1251 else
1252 {
1253 *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE;
1254 }
1255 break;
1256 case BOOTSTRAPPER_RELATION_ADDON:
1257 *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_ADDON;
1258 break;
1259 case BOOTSTRAPPER_RELATION_PATCH:
1260 *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_PATCH;
1261 break;
1262 case BOOTSTRAPPER_RELATION_DEPENDENT_ADDON:
1263 *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON;
1264 break;
1265 case BOOTSTRAPPER_RELATION_DEPENDENT_PATCH:
1266 *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH;
1267 break;
1268 case BOOTSTRAPPER_RELATION_DETECT:
1269 break;
1270 default:
1271 hr = E_UNEXPECTED;
1272 ExitOnFailure(hr, "Unexpected relation type encountered during plan: %d", relatedBundleRelationType);
1273 break;
1274 }
1275
1276 LExit:
1277 return hr;
1278 }
1279
1280 extern "C" HRESULT PlanDefaultRelatedBundleRequestState(
1281 __in BOOTSTRAPPER_RELATION_TYPE commandRelationType,
1282 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relatedBundleRelationType,
1283 __in BOOTSTRAPPER_ACTION action,
1284 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestState
1285 )
1286 {
1287 HRESULT hr = S_OK;
1288 BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == action;
1289
1290 // Never touch related bundles during Cache.
1291 if (BOOTSTRAPPER_ACTION_CACHE == action)
1292 {
1293 ExitFunction1(*pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE);
1294 }
1295
1296 switch (relatedBundleRelationType)
1297 {
1298 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE:
1299 if (BOOTSTRAPPER_RELATION_UPGRADE != commandRelationType && !fUninstalling)
1300 {
1301 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT;
1302 }
1303 break;
1304 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_PATCH: __fallthrough;
1305 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_ADDON:
1306 if (fUninstalling)
1307 {
1308 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT;
1309 }
1310 else if (BOOTSTRAPPER_ACTION_INSTALL == action || BOOTSTRAPPER_ACTION_MODIFY == action)
1311 {
1312 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_FORCE_PRESENT;
1313 }
1314 else if (BOOTSTRAPPER_ACTION_REPAIR == action)
1315 {
1316 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR;
1317 }
1318 break;
1319 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON: __fallthrough;
1320 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH:
1321 // Automatically repair dependent bundles to restore missing
1322 // packages after uninstall unless we're being upgraded with the
1323 // assumption that upgrades are cumulative (as intended).
1324 if (BOOTSTRAPPER_RELATION_UPGRADE != commandRelationType && fUninstalling)
1325 {
1326 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR;
1327 }
1328 break;
1329 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE: __fallthrough;
1330 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE:
1331 break;
1332 default:
1333 hr = E_UNEXPECTED;
1334 ExitOnFailure(hr, "Unexpected plan relation type encountered during plan: %d", relatedBundleRelationType);
1335 break;
1336 }
1337
1338 LExit:
1339 return hr;
1340 }
1341
1342 extern "C" HRESULT PlanRelatedBundlesInitialize(
1343 __in BURN_USER_EXPERIENCE* pUserExperience,
1344 __in BURN_REGISTRATION* pRegistration,
1345 __in BOOTSTRAPPER_RELATION_TYPE relationType,
1346 __in BURN_PLAN* pPlan
1347 )
1348 {
1349 HRESULT hr = S_OK;
1350 BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action;
1351
1352 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
1353 {
1354 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i;
1355
1356 pRelatedBundle->defaultRequestedRestore = BOOTSTRAPPER_REQUEST_STATE_NONE;
1357 pRelatedBundle->requestedRestore = BOOTSTRAPPER_REQUEST_STATE_NONE;
1358 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_NONE;
1359 pRelatedBundle->package.defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1360 pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1361 pRelatedBundle->defaultPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE;
1362 pRelatedBundle->planRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE;
1363 pRelatedBundle->package.executeCacheType = BURN_CACHE_PACKAGE_TYPE_NONE;
1364 pRelatedBundle->package.rollbackCacheType = BURN_CACHE_PACKAGE_TYPE_NONE;
1365
1366 // Determine the plan relation type even if later it is ignored due to the planned action, the command relation type, or the related bundle not being plannable.
1367 // This gives more information to the BA in case it wants to override default behavior.
1368 // Doing it during plan instead of Detect allows the BA to change its mind without having to go all the way through Detect again.
1369 hr = PlanDefaultRelatedBundlePlanType(pRelatedBundle->detectRelationType, pRegistration->pVersion, pRelatedBundle->pVersion, &pRelatedBundle->defaultPlanRelationType);
1370 ExitOnFailure(hr, "Failed to get default plan type for related bundle.");
1371
1372 pRelatedBundle->planRelationType = pRelatedBundle->defaultPlanRelationType;
1373
1374 hr = BACallbackOnPlanRelatedBundleType(pUserExperience, pRelatedBundle->package.sczId, &pRelatedBundle->planRelationType);
1375 ExitOnRootFailure(hr, "BA aborted plan related bundle type.");
1376
1377 if (BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE == pRelatedBundle->planRelationType &&
1378 pRelatedBundle->fPlannable && !fUninstalling && BOOTSTRAPPER_RELATION_UPGRADE != relationType)
1379 {
1380 if (!pPlan->fDowngrade)
1381 {
1382 pPlan->fDowngrade = TRUE;
1383
1384 LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DUE_TO_DOWNGRADE);
1385 }
1386
1387 LogId(REPORT_VERBOSE, MSG_UPGRADE_BUNDLE_DOWNGRADE, pRelatedBundle->package.sczId, pRelatedBundle->pVersion->sczVersion);
1388 }
1389 }
1390
1391 RelatedBundlesSortPlan(&pRegistration->relatedBundles);
1392
1393 LExit:
1394 return hr;
1395 }
1396
1397 extern "C" HRESULT PlanRelatedBundlesBegin(
1398 __in BURN_USER_EXPERIENCE* pUserExperience,
1399 __in BURN_REGISTRATION* pRegistration,
1400 __in BOOTSTRAPPER_RELATION_TYPE relationType,
1401 __in BURN_PLAN* pPlan
1402 )
1403 {
1404 HRESULT hr = S_OK;
1405 LPWSTR* rgsczAncestors = NULL;
1406 UINT cAncestors = 0;
1407 STRINGDICT_HANDLE sdAncestors = NULL;
1408 BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action;
1409
1410 if (pPlan->pInternalCommand->sczAncestors)
1411 {
1412 hr = StrSplitAllocArray(&rgsczAncestors, &cAncestors, pPlan->pInternalCommand->sczAncestors, L";");
1413 ExitOnFailure(hr, "Failed to create string array from ancestors.");
1414
1415 hr = DictCreateStringListFromArray(&sdAncestors, rgsczAncestors, cAncestors, DICT_FLAG_CASEINSENSITIVE);
1416 ExitOnFailure(hr, "Failed to create dictionary from ancestors array.");
1417 }
1418
1419 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
1420 {
1421 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgpPlanSortedRelatedBundles[i];
1422
1423 if (!pRelatedBundle->fPlannable)
1424 {
1425 continue;
1426 }
1427
1428 BOOL fDependent = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON == pRelatedBundle->planRelationType ||
1429 BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH == pRelatedBundle->planRelationType;
1430
1431 // Do not execute the same bundle twice.
1432 if (sdAncestors)
1433 {
1434 hr = DictKeyExists(sdAncestors, pRelatedBundle->package.sczId);
1435 if (SUCCEEDED(hr))
1436 {
1437 LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_RELATED_BUNDLE_SCHEDULED, pRelatedBundle->package.sczId);
1438 continue;
1439 }
1440 else if (E_NOTFOUND != hr)
1441 {
1442 ExitOnFailure(hr, "Failed to lookup the bundle ID in the ancestors dictionary.");
1443 }
1444 }
1445 else if (fDependent && BOOTSTRAPPER_RELATION_NONE != relationType)
1446 {
1447 // Avoid repair loops for older bundles that do not handle ancestors.
1448 LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_RELATED_BUNDLE_DEPENDENT, pRelatedBundle->package.sczId, LoggingRelationTypeToString(relationType));
1449 continue;
1450 }
1451
1452 // Pass along any ancestors and ourself to prevent infinite loops.
1453 pRelatedBundle->package.Bundle.wzAncestors = pRegistration->sczBundlePackageAncestors;
1454 pRelatedBundle->package.Bundle.wzEngineWorkingDirectory = pPlan->pInternalCommand->sczEngineWorkingDirectory;
1455
1456 hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->planRelationType, pPlan->action, &pRelatedBundle->package.requested);
1457 ExitOnFailure(hr, "Failed to get default request state for related bundle.");
1458
1459 pRelatedBundle->package.defaultRequested = pRelatedBundle->package.requested;
1460
1461 hr = BACallbackOnPlanRelatedBundle(pUserExperience, pRelatedBundle->package.sczId, &pRelatedBundle->package.requested);
1462 ExitOnRootFailure(hr, "BA aborted plan related bundle.");
1463
1464 // If uninstalling and the dependent related bundle may be executed, ignore its provider key to allow for downgrades with ref-counting.
1465 if (fUninstalling && fDependent && BOOTSTRAPPER_REQUEST_STATE_NONE != pRelatedBundle->package.requested)
1466 {
1467 if (0 < pRelatedBundle->package.cDependencyProviders)
1468 {
1469 // Bundles only support a single provider key.
1470 const BURN_DEPENDENCY_PROVIDER* pProvider = pRelatedBundle->package.rgDependencyProviders;
1471
1472 hr = DepDependencyArrayAlloc(&pPlan->rgPlannedProviders, &pPlan->cPlannedProviders, pProvider->sczKey, pProvider->sczDisplayName);
1473 ExitOnFailure(hr, "Failed to add the package provider key \"%ls\" to the planned list.", pProvider->sczKey);
1474 }
1475 }
1476 }
1477
1478 LExit:
1479 ReleaseDict(sdAncestors);
1480 ReleaseStrArray(rgsczAncestors, cAncestors);
1481
1482 return hr;
1483 }
1484
1485 extern "C" HRESULT PlanRelatedBundlesComplete(
1486 __in BURN_USER_EXPERIENCE* pUserExperience,
1487 __in BURN_REGISTRATION* pRegistration,
1488 __in BURN_PLAN* pPlan,
1489 __in BURN_LOGGING* pLog,
1490 __in BURN_VARIABLES* pVariables,
1491 __in DWORD dwExecuteActionEarlyIndex
1492 )
1493 {
1494 HRESULT hr = S_OK;
1495 LPWSTR sczIgnoreDependencies = NULL;
1496 STRINGDICT_HANDLE sdProviderKeys = NULL;
1497 BOOL fExecutingAnyPackage = FALSE;
1498 BOOL fInstallingAnyPackage = FALSE;
1499 BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action;
1500
1501 // Get the list of dependencies to ignore to pass to related bundles.
1502 hr = DependencyAllocIgnoreDependencies(pPlan, &sczIgnoreDependencies);
1503 ExitOnFailure(hr, "Failed to get the list of dependencies to ignore.");
1504
1505 hr = DictCreateStringList(&sdProviderKeys, pPlan->cExecuteActions, DICT_FLAG_CASEINSENSITIVE);
1506 ExitOnFailure(hr, "Failed to create dictionary for planned packages.");
1507
1508 for (DWORD i = 0; i < pPlan->cExecuteActions; ++i)
1509 {
1510 BOOTSTRAPPER_ACTION_STATE packageAction = BOOTSTRAPPER_ACTION_STATE_NONE;
1511 BURN_PACKAGE* pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package;
1512 BOOL fBundle = FALSE;
1513
1514 switch (pPlan->rgExecuteActions[i].type)
1515 {
1516 case BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE:
1517 packageAction = pPlan->rgExecuteActions[i].bundlePackage.action;
1518 pPackage = pPlan->rgExecuteActions[i].bundlePackage.pPackage;
1519 fBundle = TRUE;
1520 break;
1521
1522 case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE:
1523 packageAction = pPlan->rgExecuteActions[i].exePackage.action;
1524 pPackage = pPlan->rgExecuteActions[i].exePackage.pPackage;
1525 fBundle = pPackage->Exe.fBundle;
1526 break;
1527
1528 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
1529 packageAction = pPlan->rgExecuteActions[i].msiPackage.action;
1530 break;
1531
1532 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
1533 packageAction = pPlan->rgExecuteActions[i].mspTarget.action;
1534 break;
1535
1536 case BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE:
1537 packageAction = pPlan->rgExecuteActions[i].msuPackage.action;
1538 break;
1539 }
1540
1541 if (fBundle && BOOTSTRAPPER_ACTION_STATE_NONE != packageAction)
1542 {
1543 if (pPackage->cDependencyProviders)
1544 {
1545 // Bundles only support a single provider key.
1546 const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders;
1547 DictAddKey(sdProviderKeys, pProvider->sczKey);
1548 }
1549 }
1550
1551 fExecutingAnyPackage |= BOOTSTRAPPER_ACTION_STATE_NONE != packageAction;
1552 fInstallingAnyPackage |= BOOTSTRAPPER_ACTION_STATE_INSTALL == packageAction || BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE == packageAction;
1553 }
1554
1555 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
1556 {
1557 DWORD *pdwInsertIndex = NULL;
1558 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgpPlanSortedRelatedBundles[i];
1559 BOOL fDependent = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON == pRelatedBundle->planRelationType ||
1560 BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH == pRelatedBundle->planRelationType;
1561 BOOL fAddonOrPatch = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_ADDON == pRelatedBundle->planRelationType ||
1562 BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_PATCH == pRelatedBundle->planRelationType;
1563
1564 if (!pRelatedBundle->fPlannable)
1565 {
1566 continue;
1567 }
1568
1569 // Do not execute if a major upgrade to the related bundle is an embedded bundle (Provider keys are the same)
1570 if (0 < pRelatedBundle->package.cDependencyProviders)
1571 {
1572 // Bundles only support a single provider key.
1573 const BURN_DEPENDENCY_PROVIDER* pProvider = pRelatedBundle->package.rgDependencyProviders;
1574 hr = DictKeyExists(sdProviderKeys, pProvider->sczKey);
1575 if (E_NOTFOUND != hr)
1576 {
1577 ExitOnFailure(hr, "Failed to check the dictionary for a related bundle provider key: \"%ls\".", pProvider->sczKey);
1578 // Key found, so there is an embedded bundle with the same provider key that will be executed. So this related bundle should not be added to the plan
1579 LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_RELATED_BUNDLE_EMBEDDED_BUNDLE_NEWER, pRelatedBundle->package.sczId, pProvider->sczKey);
1580 continue;
1581 }
1582 else
1583 {
1584 hr = S_OK;
1585 }
1586 }
1587
1588 // For an uninstall, there is no need to repair dependent bundles if no packages are executing.
1589 if (!fExecutingAnyPackage && fDependent && BOOTSTRAPPER_REQUEST_STATE_REPAIR == pRelatedBundle->package.requested && fUninstalling)
1590 {
1591 pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1592 LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DEPENDENT_BUNDLE_REPAIR, pRelatedBundle->package.sczId);
1593 }
1594
1595 if (fAddonOrPatch)
1596 {
1597 // Addon and patch bundles will be passed a list of dependencies to ignore for planning.
1598 hr = StrAllocString(&pRelatedBundle->package.Bundle.sczIgnoreDependencies, sczIgnoreDependencies, 0);
1599 ExitOnFailure(hr, "Failed to copy the list of dependencies to ignore.");
1600
1601 // Uninstall addons and patches early in the chain, before other packages are uninstalled.
1602 if (fUninstalling)
1603 {
1604 pdwInsertIndex = &dwExecuteActionEarlyIndex;
1605 }
1606 }
1607
1608 if (BOOTSTRAPPER_REQUEST_STATE_NONE != pRelatedBundle->package.requested)
1609 {
1610 hr = BundlePackageEnginePlanCalculatePackage(&pRelatedBundle->package);
1611 ExitOnFailure(hr, "Failed to calculate plan for related bundle: %ls", pRelatedBundle->package.sczId);
1612
1613 // Calculate package states based on reference count for addon and patch related bundles.
1614 if (fAddonOrPatch)
1615 {
1616 hr = DependencyPlanPackageBegin(pRegistration->fPerMachine, &pRelatedBundle->package, pPlan);
1617 ExitOnFailure(hr, "Failed to begin plan dependency actions to package: %ls", pRelatedBundle->package.sczId);
1618
1619 // If uninstalling a related bundle, make sure the bundle is uninstalled after removing registration.
1620 if (pdwInsertIndex && fUninstalling)
1621 {
1622 ++(*pdwInsertIndex);
1623 }
1624 }
1625
1626 hr = BundlePackageEnginePlanAddRelatedBundle(pdwInsertIndex, pRelatedBundle, pPlan, pLog, pVariables);
1627 ExitOnFailure(hr, "Failed to add to plan related bundle: %ls", pRelatedBundle->package.sczId);
1628
1629 // Calculate package states based on reference count for addon and patch related bundles.
1630 if (fAddonOrPatch)
1631 {
1632 hr = DependencyPlanPackageComplete(&pRelatedBundle->package, pPlan);
1633 ExitOnFailure(hr, "Failed to complete plan dependency actions for related bundle package: %ls", pRelatedBundle->package.sczId);
1634 }
1635
1636 // If we are going to take any action on this package, add progress for it.
1637 if (BOOTSTRAPPER_ACTION_STATE_NONE != pRelatedBundle->package.execute || BOOTSTRAPPER_ACTION_STATE_NONE != pRelatedBundle->package.rollback)
1638 {
1639 PlannedExecutePackage(pPlan, &pRelatedBundle->package);
1640 }
1641 }
1642 else if (fAddonOrPatch)
1643 {
1644 // Make sure the package is properly ref-counted even if no plan is requested.
1645 hr = DependencyPlanPackageBegin(pRegistration->fPerMachine, &pRelatedBundle->package, pPlan);
1646 ExitOnFailure(hr, "Failed to begin plan dependency actions for related bundle package: %ls", pRelatedBundle->package.sczId);
1647
1648 hr = DependencyPlanPackage(pdwInsertIndex, &pRelatedBundle->package, pPlan);
1649 ExitOnFailure(hr, "Failed to plan related bundle package provider actions.");
1650
1651 hr = DependencyPlanPackageComplete(&pRelatedBundle->package, pPlan);
1652 ExitOnFailure(hr, "Failed to complete plan dependency actions for related bundle package: %ls", pRelatedBundle->package.sczId);
1653 }
1654
1655 if (fInstallingAnyPackage && BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE == pRelatedBundle->planRelationType)
1656 {
1657 BURN_EXECUTE_ACTION* pAction = NULL;
1658
1659 pRelatedBundle->defaultRequestedRestore = pRelatedBundle->requestedRestore = BOOTSTRAPPER_REQUEST_STATE_FORCE_PRESENT;
1660
1661 hr = BACallbackOnPlanRestoreRelatedBundle(pUserExperience, pRelatedBundle->package.sczId, &pRelatedBundle->requestedRestore);
1662 ExitOnRootFailure(hr, "BA aborted plan restore related bundle.");
1663
1664 switch (pRelatedBundle->requestedRestore)
1665 {
1666 case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
1667 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_REPAIR;
1668 break;
1669 case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough;
1670 case BOOTSTRAPPER_REQUEST_STATE_CACHE: __fallthrough;
1671 case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT:
1672 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
1673 break;
1674 case BOOTSTRAPPER_REQUEST_STATE_FORCE_PRESENT:
1675 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_INSTALL;
1676 break;
1677 default:
1678 pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_NONE;
1679 break;
1680 }
1681
1682 if (BOOTSTRAPPER_ACTION_STATE_NONE != pRelatedBundle->restore)
1683 {
1684 hr = AppendRestoreRelatedBundleAction(pPlan, &pAction);
1685 ExitOnFailure(hr, "Failed to append restore related bundle action to plan.");
1686
1687 pAction->type = BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE;
1688 pAction->relatedBundle.pRelatedBundle = pRelatedBundle;
1689 pAction->relatedBundle.action = pRelatedBundle->restore;
1690
1691 if (pRelatedBundle->package.Bundle.sczIgnoreDependencies)
1692 {
1693 hr = StrAllocString(&pAction->relatedBundle.sczIgnoreDependencies, pRelatedBundle->package.Bundle.sczIgnoreDependencies, 0);
1694 ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore.");
1695 }
1696
1697 if (pRelatedBundle->package.Bundle.wzAncestors)
1698 {
1699 hr = StrAllocString(&pAction->relatedBundle.sczAncestors, pRelatedBundle->package.Bundle.wzAncestors, 0);
1700 ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
1701 }
1702
1703 if (pRelatedBundle->package.Bundle.wzEngineWorkingDirectory)
1704 {
1705 hr = StrAllocString(&pAction->relatedBundle.sczEngineWorkingDirectory, pRelatedBundle->package.Bundle.wzEngineWorkingDirectory, 0);
1706 ExitOnFailure(hr, "Failed to allocate the custom working directory.");
1707 }
1708 }
1709 }
1710 }
1711
1712 LExit:
1713 ReleaseDict(sdProviderKeys);
1714 ReleaseStr(sczIgnoreDependencies);
1715
1716 return hr;
1717 }
1718
1719 extern "C" HRESULT PlanFinalizeActions(
1720 __in BURN_PLAN* pPlan
1721 )
1722 {
1723 HRESULT hr = S_OK;
1724
1725 FinalizePatchActions(TRUE, pPlan->rgExecuteActions, pPlan->cExecuteActions);
1726
1727 FinalizePatchActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions);
1728
1729 RemoveUnnecessaryActions(TRUE, pPlan->rgExecuteActions, pPlan->cExecuteActions);
1730
1731 RemoveUnnecessaryActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions);
1732
1733 return hr;
1734 }
1735
1736 extern "C" HRESULT PlanCleanPackage(
1737 __in BURN_PLAN* pPlan,
1738 __in BURN_PACKAGE* pPackage
1739 )
1740 {
1741 HRESULT hr = S_OK;
1742 BOOL fPlanCleanPackage = FALSE;
1743 BURN_CLEAN_ACTION* pCleanAction = NULL;
1744 BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action;
1745
1746 // The following is a complex set of logic that determines when a package should be cleaned from the cache.
1747 if (BOOTSTRAPPER_CACHE_TYPE_FORCE > pPackage->cacheType || fUninstalling)
1748 {
1749 // The following are all different reasons why the package should be cleaned from the cache.
1750 // The else-ifs are used to make the conditions easier to see (rather than have them combined
1751 // in one huge condition).
1752 if (BOOTSTRAPPER_CACHE_TYPE_KEEP > pPackage->cacheType) // easy, package is not supposed to stay cached.
1753 {
1754 fPlanCleanPackage = TRUE;
1755 }
1756 else if ((BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT == pPackage->requested ||
1757 BOOTSTRAPPER_REQUEST_STATE_ABSENT == pPackage->requested) && // requested to be removed and
1758 BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute) // actually being removed.
1759 {
1760 fPlanCleanPackage = TRUE;
1761 }
1762 else if ((BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT == pPackage->requested ||
1763 BOOTSTRAPPER_REQUEST_STATE_ABSENT == pPackage->requested) && // requested to be removed but
1764 BOOTSTRAPPER_ACTION_STATE_NONE == pPackage->execute && // execute is do nothing and
1765 !pPackage->fDependencyManagerWasHere && // dependency manager didn't change execute and
1766 BOOTSTRAPPER_PACKAGE_STATE_PRESENT > pPackage->currentState) // currently not installed.
1767 {
1768 fPlanCleanPackage = TRUE;
1769 }
1770 else if (fUninstalling && // uninstalling and
1771 BOOTSTRAPPER_REQUEST_STATE_NONE == pPackage->requested && // requested do nothing (aka: default) and
1772 BOOTSTRAPPER_ACTION_STATE_NONE == pPackage->execute && // execute is still do nothing and
1773 !pPackage->fDependencyManagerWasHere && // dependency manager didn't change execute and
1774 BOOTSTRAPPER_PACKAGE_STATE_PRESENT > pPackage->currentState) // currently not installed.
1775 {
1776 fPlanCleanPackage = TRUE;
1777 }
1778 }
1779
1780 if (fPlanCleanPackage)
1781 {
1782 hr = AppendCleanAction(pPlan, &pCleanAction);
1783 ExitOnFailure(hr, "Failed to append clean action to plan.");
1784
1785 pCleanAction->type = BURN_CLEAN_ACTION_TYPE_PACKAGE;
1786 pCleanAction->pPackage = pPackage;
1787
1788 pPackage->fPlannedUncache = TRUE;
1789
1790 if (pPackage->fCanAffectRegistration)
1791 {
1792 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
1793 }
1794 }
1795
1796 if (pPackage->compatiblePackage.fRemove)
1797 {
1798 hr = AppendCleanAction(pPlan, &pCleanAction);
1799 ExitOnFailure(hr, "Failed to append clean action to plan.");
1800
1801 pCleanAction->type = BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE;
1802 pCleanAction->pPackage = pPackage;
1803 }
1804
1805 LExit:
1806 return hr;
1807 }
1808
1809 extern "C" HRESULT PlanExecuteCacheSyncAndRollback(
1810 __in BURN_PLAN* pPlan,
1811 __in BURN_PACKAGE* pPackage
1812 )
1813 {
1814 HRESULT hr = S_OK;
1815 BURN_EXECUTE_ACTION* pAction = NULL;
1816
1817 if (pPlan->fPlanPackageCacheRollback)
1818 {
1819 hr = PlanAppendRollbackAction(pPlan, &pAction);
1820 ExitOnFailure(hr, "Failed to append rollback action.");
1821
1822 pAction->type = BURN_EXECUTE_ACTION_TYPE_UNCACHE_PACKAGE;
1823 pAction->uncachePackage.pPackage = pPackage;
1824 }
1825
1826 hr = PlanExecuteCheckpoint(pPlan);
1827 ExitOnFailure(hr, "Failed to append execute checkpoint for cache rollback.");
1828
1829 hr = PlanAppendExecuteAction(pPlan, &pAction);
1830 ExitOnFailure(hr, "Failed to append wait action for caching.");
1831
1832 pAction->type = BURN_EXECUTE_ACTION_TYPE_WAIT_CACHE_PACKAGE;
1833 pAction->waitCachePackage.pPackage = pPackage;
1834
1835 LExit:
1836 return hr;
1837 }
1838
1839 extern "C" HRESULT PlanExecuteCheckpoint(
1840 __in BURN_PLAN* pPlan
1841 )
1842 {
1843 HRESULT hr = S_OK;
1844 BURN_EXECUTE_ACTION* pAction = NULL;
1845 DWORD dwCheckpointId = GetNextCheckpointId(pPlan);
1846
1847 // execute checkpoint
1848 hr = PlanAppendExecuteAction(pPlan, &pAction);
1849 ExitOnFailure(hr, "Failed to append execute action.");
1850
1851 pAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT;
1852 pAction->checkpoint.dwId = dwCheckpointId;
1853 pAction->checkpoint.pActiveRollbackBoundary = pPlan->pActiveRollbackBoundary;
1854
1855 // rollback checkpoint
1856 hr = PlanAppendRollbackAction(pPlan, &pAction);
1857 ExitOnFailure(hr, "Failed to append rollback action.");
1858
1859 pAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT;
1860 pAction->checkpoint.dwId = dwCheckpointId;
1861 pAction->checkpoint.pActiveRollbackBoundary = pPlan->pActiveRollbackBoundary;
1862
1863 LExit:
1864 return hr;
1865 }
1866
1867 extern "C" HRESULT PlanInsertExecuteAction(
1868 __in DWORD dwIndex,
1869 __in BURN_PLAN* pPlan,
1870 __out BURN_EXECUTE_ACTION** ppExecuteAction
1871 )
1872 {
1873 HRESULT hr = S_OK;
1874
1875 hr = MemInsertIntoArray((void**)&pPlan->rgExecuteActions, dwIndex, 1, pPlan->cExecuteActions + 1, sizeof(BURN_EXECUTE_ACTION), 5);
1876 ExitOnFailure(hr, "Failed to grow plan's array of execute actions.");
1877
1878 *ppExecuteAction = pPlan->rgExecuteActions + dwIndex;
1879 ++pPlan->cExecuteActions;
1880
1881 LExit:
1882 return hr;
1883 }
1884
1885 extern "C" HRESULT PlanInsertRollbackAction(
1886 __in DWORD dwIndex,
1887 __in BURN_PLAN* pPlan,
1888 __out BURN_EXECUTE_ACTION** ppRollbackAction
1889 )
1890 {
1891 HRESULT hr = S_OK;
1892
1893 hr = MemInsertIntoArray((void**)&pPlan->rgRollbackActions, dwIndex, 1, pPlan->cRollbackActions + 1, sizeof(BURN_EXECUTE_ACTION), 5);
1894 ExitOnFailure(hr, "Failed to grow plan's array of rollback actions.");
1895
1896 *ppRollbackAction = pPlan->rgRollbackActions + dwIndex;
1897 ++pPlan->cRollbackActions;
1898
1899 LExit:
1900 return hr;
1901 }
1902
1903 extern "C" HRESULT PlanAppendExecuteAction(
1904 __in BURN_PLAN* pPlan,
1905 __out BURN_EXECUTE_ACTION** ppExecuteAction
1906 )
1907 {
1908 HRESULT hr = S_OK;
1909
1910 hr = MemEnsureArraySize((void**)&pPlan->rgExecuteActions, pPlan->cExecuteActions + 1, sizeof(BURN_EXECUTE_ACTION), 5);
1911 ExitOnFailure(hr, "Failed to grow plan's array of execute actions.");
1912
1913 *ppExecuteAction = pPlan->rgExecuteActions + pPlan->cExecuteActions;
1914 ++pPlan->cExecuteActions;
1915
1916 LExit:
1917 return hr;
1918 }
1919
1920 extern "C" HRESULT PlanAppendRollbackAction(
1921 __in BURN_PLAN* pPlan,
1922 __out BURN_EXECUTE_ACTION** ppRollbackAction
1923 )
1924 {
1925 HRESULT hr = S_OK;
1926
1927 hr = MemEnsureArraySize((void**)&pPlan->rgRollbackActions, pPlan->cRollbackActions + 1, sizeof(BURN_EXECUTE_ACTION), 5);
1928 ExitOnFailure(hr, "Failed to grow plan's array of rollback actions.");
1929
1930 *ppRollbackAction = pPlan->rgRollbackActions + pPlan->cRollbackActions;
1931 ++pPlan->cRollbackActions;
1932
1933 LExit:
1934 return hr;
1935 }
1936
1937 extern "C" HRESULT PlanRollbackBoundaryBegin(
1938 __in BURN_PLAN* pPlan,
1939 __in BURN_USER_EXPERIENCE* pUX,
1940 __in BURN_LOGGING* pLog,
1941 __in BURN_VARIABLES* pVariables,
1942 __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary
1943 )
1944 {
1945 HRESULT hr = S_OK;
1946 BURN_EXECUTE_ACTION* pExecuteAction = NULL;
1947
1948 AssertSz(!pPlan->pActiveRollbackBoundary, "PlanRollbackBoundaryBegin called without completing previous RollbackBoundary");
1949 pPlan->pActiveRollbackBoundary = pRollbackBoundary;
1950
1951 // Add begin rollback boundary to execute plan.
1952 hr = PlanAppendExecuteAction(pPlan, &pExecuteAction);
1953 ExitOnFailure(hr, "Failed to append rollback boundary begin action.");
1954
1955 pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY_START;
1956 pExecuteAction->rollbackBoundary.pRollbackBoundary = pRollbackBoundary;
1957
1958 // Add begin rollback boundary to rollback plan.
1959 hr = PlanAppendRollbackAction(pPlan, &pExecuteAction);
1960 ExitOnFailure(hr, "Failed to append rollback boundary begin action.");
1961
1962 pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY_START;
1963 pExecuteAction->rollbackBoundary.pRollbackBoundary = pRollbackBoundary;
1964
1965 hr = BACallbackOnPlanRollbackBoundary(pUX, pRollbackBoundary->sczId, &pRollbackBoundary->fTransaction);
1966 ExitOnRootFailure(hr, "BA aborted plan rollback boundary.");
1967
1968 // Only use MSI transaction if authored and the BA requested it.
1969 if (!pRollbackBoundary->fTransactionAuthored || !pRollbackBoundary->fTransaction)
1970 {
1971 pRollbackBoundary->fTransaction = FALSE;
1972 }
1973 else
1974 {
1975 LoggingSetTransactionVariable(pRollbackBoundary, NULL, pLog, pVariables); // ignore errors.
1976
1977 // Add begin MSI transaction to execute plan.
1978 hr = PlanExecuteCheckpoint(pPlan);
1979 ExitOnFailure(hr, "Failed to append checkpoint before MSI transaction begin action.");
1980
1981 hr = PlanAppendExecuteAction(pPlan, &pExecuteAction);
1982 ExitOnFailure(hr, "Failed to append MSI transaction begin action.");
1983
1984 pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION;
1985 pExecuteAction->msiTransaction.pRollbackBoundary = pRollbackBoundary;
1986 }
1987
1988 LExit:
1989 return hr;
1990 }
1991
1992 extern "C" HRESULT PlanRollbackBoundaryComplete(
1993 __in BURN_PLAN* pPlan
1994 )
1995 {
1996 HRESULT hr = S_OK;
1997 BURN_EXECUTE_ACTION* pExecuteAction = NULL;
1998 BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = pPlan->pActiveRollbackBoundary;
1999
2000 AssertSz(pRollbackBoundary, "PlanRollbackBoundaryComplete called without an active RollbackBoundary");
2001
2002 if (pRollbackBoundary && pRollbackBoundary->fTransaction)
2003 {
2004 // Add commit MSI transaction to execute plan.
2005 hr = PlanAppendExecuteAction(pPlan, &pExecuteAction);
2006 ExitOnFailure(hr, "Failed to append MSI transaction commit action.");
2007
2008 pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION;
2009 pExecuteAction->msiTransaction.pRollbackBoundary = pRollbackBoundary;
2010 }
2011
2012 pPlan->pActiveRollbackBoundary = NULL;
2013
2014 // Add checkpoints.
2015 hr = PlanExecuteCheckpoint(pPlan);
2016
2017 // Add complete rollback boundary to execute plan.
2018 hr = PlanAppendExecuteAction(pPlan, &pExecuteAction);
2019 ExitOnFailure(hr, "Failed to append rollback boundary complete action.");
2020
2021 pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY_END;
2022
2023 // Add begin rollback boundary to rollback plan.
2024 hr = PlanAppendRollbackAction(pPlan, &pExecuteAction);
2025 ExitOnFailure(hr, "Failed to append rollback boundary complete action.");
2026
2027 pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY_END;
2028
2029 LExit:
2030 return hr;
2031 }
2032
2033 /*******************************************************************
2034 PlanSetResumeCommand - Initializes resume command string
2035
2036 *******************************************************************/
2037 extern "C" HRESULT PlanSetResumeCommand(
2038 __in BURN_PLAN* pPlan,
2039 __in BURN_REGISTRATION* pRegistration,
2040 __in BURN_LOGGING* pLog
2041 )
2042 {
2043 HRESULT hr = S_OK;
2044
2045 // build the resume command-line.
2046 hr = CoreCreateResumeCommandLine(&pRegistration->sczResumeCommandLine, pPlan, pLog);
2047 ExitOnFailure(hr, "Failed to create resume command-line.");
2048
2049 LExit:
2050 return hr;
2051 }
2052
2053
2054 // internal function definitions
2055
2056
2057 static void PlannedExecutePackage(
2058 __in BURN_PLAN* pPlan,
2059 __in BURN_PACKAGE* pPackage
2060 )
2061 {
2062 LoggingIncrementPackageSequence();
2063
2064 ++pPlan->cExecutePackagesTotal;
2065 ++pPlan->cOverallProgressTicksTotal;
2066
2067 // If package is per-machine and is being executed, flag the plan to be per-machine as well.
2068 if (pPackage->fPerMachine)
2069 {
2070 pPlan->fPerMachine = TRUE;
2071 }
2072 }
2073
2074 static void UninitializeRegistrationAction(
2075 __in BURN_DEPENDENT_REGISTRATION_ACTION* pAction
2076 )
2077 {
2078 ReleaseStr(pAction->sczDependentProviderKey);
2079 ReleaseStr(pAction->sczBundleId);
2080 memset(pAction, 0, sizeof(BURN_DEPENDENT_REGISTRATION_ACTION));
2081 }
2082
2083 static void UninitializeCacheAction(
2084 __in BURN_CACHE_ACTION* pCacheAction
2085 )
2086 {
2087 switch (pCacheAction->type)
2088 {
2089 case BURN_CACHE_ACTION_TYPE_LAYOUT_BUNDLE:
2090 ReleaseStr(pCacheAction->bundleLayout.sczExecutableName);
2091 ReleaseStr(pCacheAction->bundleLayout.sczUnverifiedPath);
2092 break;
2093 }
2094 }
2095
2096 static void ResetPlannedContainerState(
2097 __in BURN_CONTAINER* pContainer
2098 )
2099 {
2100 pContainer->fPlanned = FALSE;
2101 pContainer->qwExtractSizeTotal = 0;
2102 pContainer->qwCommittedCacheProgress = 0;
2103 pContainer->qwCommittedExtractProgress = 0;
2104 pContainer->fExtracted = FALSE;
2105 pContainer->fFailedVerificationFromAcquisition = FALSE;
2106 ReleaseNullStr(pContainer->sczFailedLocalAcquisitionPath);
2107 }
2108
2109 static void ResetPlannedPayloadsState(
2110 __in BURN_PAYLOADS* pPayloads
2111 )
2112 {
2113 for (DWORD i = 0; i < pPayloads->cPayloads; ++i)
2114 {
2115 BURN_PAYLOAD* pPayload = pPayloads->rgPayloads + i;
2116
2117 pPayload->cRemainingInstances = 0;
2118 pPayload->state = BURN_PAYLOAD_STATE_NONE;
2119 pPayload->fFailedVerificationFromAcquisition = FALSE;
2120 ReleaseNullStr(pPayload->sczLocalFilePath);
2121 ReleaseNullStr(pPayload->sczFailedLocalAcquisitionPath);
2122 }
2123 }
2124
2125 static void ResetPlannedPayloadGroupState(
2126 __in BURN_PAYLOAD_GROUP* pPayloadGroup
2127 )
2128 {
2129 for (DWORD i = 0; i < pPayloadGroup->cItems; ++i)
2130 {
2131 BURN_PAYLOAD_GROUP_ITEM* pItem = pPayloadGroup->rgItems + i;
2132
2133 pItem->fCached = FALSE;
2134 pItem->qwCommittedCacheProgress = 0;
2135 }
2136 }
2137
2138 static void ResetPlannedPackageState(
2139 __in BURN_PACKAGE* pPackage
2140 )
2141 {
2142 // Reset package state that is a result of planning.
2143 pPackage->cacheType = pPackage->authoredCacheType;
2144 pPackage->defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE;
2145 pPackage->requested = BOOTSTRAPPER_REQUEST_STATE_NONE;
2146 pPackage->fCacheVital = FALSE;
2147 pPackage->fPlannedUncache = FALSE;
2148 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
2149 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
2150 pPackage->fProviderExecute = FALSE;
2151 pPackage->fProviderRollback = FALSE;
2152 pPackage->dependencyExecute = BURN_DEPENDENCY_ACTION_NONE;
2153 pPackage->dependencyRollback = BURN_DEPENDENCY_ACTION_NONE;
2154 pPackage->fDependencyManagerWasHere = FALSE;
2155 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
2156 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
2157 pPackage->executeCacheType = BURN_CACHE_PACKAGE_TYPE_NONE;
2158 pPackage->rollbackCacheType = BURN_CACHE_PACKAGE_TYPE_NONE;
2159 ReleaseHandle(pPackage->hCacheEvent);
2160
2161 ReleaseNullStr(pPackage->sczCacheFolder);
2162
2163 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
2164 {
2165 for (DWORD i = 0; i < pPackage->Msi.cFeatures; ++i)
2166 {
2167 BURN_MSIFEATURE* pFeature = &pPackage->Msi.rgFeatures[i];
2168
2169 pFeature->expectedState = BOOTSTRAPPER_FEATURE_STATE_UNKNOWN;
2170 pFeature->defaultRequested = BOOTSTRAPPER_FEATURE_STATE_UNKNOWN;
2171 pFeature->requested = BOOTSTRAPPER_FEATURE_STATE_UNKNOWN;
2172 pFeature->execute = BOOTSTRAPPER_FEATURE_ACTION_NONE;
2173 pFeature->rollback = BOOTSTRAPPER_FEATURE_ACTION_NONE;
2174 }
2175
2176 for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i)
2177 {
2178 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = &pPackage->Msi.rgSlipstreamMsps[i];
2179
2180 pSlipstreamMsp->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
2181 pSlipstreamMsp->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
2182 }
2183 }
2184 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.rgTargetProducts)
2185 {
2186 for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
2187 {
2188 BURN_MSPTARGETPRODUCT* pTargetProduct = &pPackage->Msp.rgTargetProducts[i];
2189
2190 pTargetProduct->defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE;
2191 pTargetProduct->requested = BOOTSTRAPPER_REQUEST_STATE_NONE;
2192 pTargetProduct->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
2193 pTargetProduct->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
2194 pTargetProduct->executeSkip = BURN_PATCH_SKIP_STATE_NONE;
2195 pTargetProduct->rollbackSkip = BURN_PATCH_SKIP_STATE_NONE;
2196 }
2197 }
2198
2199 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
2200 {
2201 BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
2202
2203 pProvider->dependentExecute = BURN_DEPENDENCY_ACTION_NONE;
2204 pProvider->dependentRollback = BURN_DEPENDENCY_ACTION_NONE;
2205 pProvider->providerExecute = BURN_DEPENDENCY_ACTION_NONE;
2206 pProvider->providerRollback = BURN_DEPENDENCY_ACTION_NONE;
2207 }
2208
2209 ResetPlannedPayloadGroupState(&pPackage->payloads);
2210 }
2211
2212 static void ResetPlannedRollbackBoundaryState(
2213 __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary
2214 )
2215 {
2216 pRollbackBoundary->fActiveTransaction = FALSE;
2217 pRollbackBoundary->fTransaction = pRollbackBoundary->fTransactionAuthored;
2218 ReleaseNullStr(pRollbackBoundary->sczLogPath);
2219 }
2220
2221 static HRESULT GetActionDefaultRequestState(
2222 __in BOOTSTRAPPER_ACTION action,
2223 __in BOOTSTRAPPER_PACKAGE_STATE currentState,
2224 __out BOOTSTRAPPER_REQUEST_STATE* pRequestState
2225 )
2226 {
2227 HRESULT hr = S_OK;
2228
2229 switch (action)
2230 {
2231 case BOOTSTRAPPER_ACTION_INSTALL:
2232 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
2233 break;
2234
2235 case BOOTSTRAPPER_ACTION_REPAIR:
2236 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR;
2237 break;
2238
2239 case BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL: __fallthrough;
2240 case BOOTSTRAPPER_ACTION_UNINSTALL:
2241 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT;
2242 break;
2243
2244 case BOOTSTRAPPER_ACTION_MODIFY:
2245 switch (currentState)
2246 {
2247 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
2248 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT;
2249 break;
2250
2251 case BOOTSTRAPPER_PACKAGE_STATE_PRESENT:
2252 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
2253 break;
2254
2255 default:
2256 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
2257 break;
2258 }
2259 break;
2260
2261 default:
2262 hr = E_INVALIDARG;
2263 ExitOnRootFailure(hr, "Invalid action state.");
2264 }
2265
2266 LExit:
2267 return hr;
2268 }
2269
2270 static HRESULT AddRegistrationAction(
2271 __in BURN_PLAN* pPlan,
2272 __in BURN_DEPENDENT_REGISTRATION_ACTION_TYPE type,
2273 __in_z LPCWSTR wzDependentProviderKey,
2274 __in_z LPCWSTR wzOwnerBundleId
2275 )
2276 {
2277 HRESULT hr = S_OK;
2278 BURN_DEPENDENT_REGISTRATION_ACTION_TYPE rollbackType = (BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER == type) ? BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_UNREGISTER : BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER;
2279 BURN_DEPENDENT_REGISTRATION_ACTION* pAction = NULL;
2280
2281 // Create forward registration action.
2282 hr = MemEnsureArraySize((void**)&pPlan->rgRegistrationActions, pPlan->cRegistrationActions + 1, sizeof(BURN_DEPENDENT_REGISTRATION_ACTION), 5);
2283 ExitOnFailure(hr, "Failed to grow plan's array of registration actions.");
2284
2285 pAction = pPlan->rgRegistrationActions + pPlan->cRegistrationActions;
2286 ++pPlan->cRegistrationActions;
2287
2288 pAction->type = type;
2289
2290 hr = StrAllocString(&pAction->sczBundleId, wzOwnerBundleId, 0);
2291 ExitOnFailure(hr, "Failed to copy owner bundle to registration action.");
2292
2293 hr = StrAllocString(&pAction->sczDependentProviderKey, wzDependentProviderKey, 0);
2294 ExitOnFailure(hr, "Failed to copy dependent provider key to registration action.");
2295
2296 // Create rollback registration action.
2297 hr = MemEnsureArraySize((void**)&pPlan->rgRollbackRegistrationActions, pPlan->cRollbackRegistrationActions + 1, sizeof(BURN_DEPENDENT_REGISTRATION_ACTION), 5);
2298 ExitOnFailure(hr, "Failed to grow plan's array of rollback registration actions.");
2299
2300 pAction = pPlan->rgRollbackRegistrationActions + pPlan->cRollbackRegistrationActions;
2301 ++pPlan->cRollbackRegistrationActions;
2302
2303 pAction->type = rollbackType;
2304
2305 hr = StrAllocString(&pAction->sczBundleId, wzOwnerBundleId, 0);
2306 ExitOnFailure(hr, "Failed to copy owner bundle to registration action.");
2307
2308 hr = StrAllocString(&pAction->sczDependentProviderKey, wzDependentProviderKey, 0);
2309 ExitOnFailure(hr, "Failed to copy dependent provider key to rollback registration action.");
2310
2311 LExit:
2312 return hr;
2313 }
2314
2315 static HRESULT AddCachePackage(
2316 __in BURN_PLAN* pPlan,
2317 __in BURN_PACKAGE* pPackage,
2318 __in BOOL fVital
2319 )
2320 {
2321 HRESULT hr = S_OK;
2322
2323 // If this is an MSI package with slipstream MSPs, ensure the MSPs are cached first.
2324 // TODO: Slipstream packages are not accounted for when caching the MSI package is optional.
2325 if (BURN_PACKAGE_TYPE_MSI == pPackage->type && 0 < pPackage->Msi.cSlipstreamMspPackages && fVital)
2326 {
2327 hr = AddCacheSlipstreamMsps(pPlan, pPackage);
2328 ExitOnFailure(hr, "Failed to plan slipstream patches for package.");
2329 }
2330
2331 hr = AddCachePackageHelper(pPlan, pPackage, fVital);
2332 ExitOnFailure(hr, "Failed to plan cache package.");
2333
2334 LExit:
2335 return hr;
2336 }
2337
2338 static HRESULT AddCachePackageHelper(
2339 __in BURN_PLAN* pPlan,
2340 __in BURN_PACKAGE* pPackage,
2341 __in BOOL fVital
2342 )
2343 {
2344 AssertSz(pPackage->sczCacheId && *pPackage->sczCacheId, "AddCachePackageHelper() expects the package to have a cache id.");
2345
2346 HRESULT hr = S_OK;
2347 BURN_CACHE_ACTION* pCacheAction = NULL;
2348 DWORD dwCheckpoint = 0;
2349
2350 if (pPlan->fEnabledForwardCompatibleBundle) // Passthrough packages must already be cached.
2351 {
2352 ExitFunction();
2353 }
2354
2355 if (pPackage->hCacheEvent) // Only cache the package once.
2356 {
2357 ExitFunction();
2358 }
2359
2360 pPackage->hCacheEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL);
2361 ExitOnNullWithLastError(pPackage->hCacheEvent, hr, "Failed to create syncpoint event.");
2362
2363 // Cache checkpoints happen before the package is cached because downloading packages'
2364 // payloads will not roll themselves back the way installation packages rollback on
2365 // failure automatically.
2366 dwCheckpoint = GetNextCheckpointId(pPlan);
2367
2368 hr = AppendCacheAction(pPlan, &pCacheAction);
2369 ExitOnFailure(hr, "Failed to append checkpoint before package start action.");
2370
2371 pCacheAction->type = BURN_CACHE_ACTION_TYPE_CHECKPOINT;
2372 pCacheAction->checkpoint.dwId = dwCheckpoint;
2373
2374 if (pPlan->fPlanPackageCacheRollback)
2375 {
2376 // Create a package cache rollback action *before* the checkpoint.
2377 hr = AppendRollbackCacheAction(pPlan, &pCacheAction);
2378 ExitOnFailure(hr, "Failed to append rollback cache action.");
2379
2380 pCacheAction->type = BURN_CACHE_ACTION_TYPE_ROLLBACK_PACKAGE;
2381 pCacheAction->rollbackPackage.pPackage = pPackage;
2382
2383 hr = AppendRollbackCacheAction(pPlan, &pCacheAction);
2384 ExitOnFailure(hr, "Failed to append rollback cache action.");
2385
2386 pCacheAction->type = BURN_CACHE_ACTION_TYPE_CHECKPOINT;
2387 pCacheAction->checkpoint.dwId = dwCheckpoint;
2388 }
2389
2390 hr = PlanLayoutPackage(pPlan, pPackage, fVital);
2391 ExitOnFailure(hr, "Failed to plan cache for package.");
2392
2393 // Create syncpoint action.
2394 hr = AppendCacheAction(pPlan, &pCacheAction);
2395 ExitOnFailure(hr, "Failed to append cache action.");
2396
2397 pCacheAction->type = BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT;
2398 pCacheAction->syncpoint.pPackage = pPackage;
2399
2400 hr = PlanExecuteCacheSyncAndRollback(pPlan, pPackage);
2401 ExitOnFailure(hr, "Failed to plan package cache syncpoint");
2402
2403 if (pPackage->fCanAffectRegistration)
2404 {
2405 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2406 }
2407
2408 LExit:
2409 return hr;
2410 }
2411
2412 static HRESULT AddCacheSlipstreamMsps(
2413 __in BURN_PLAN* pPlan,
2414 __in BURN_PACKAGE* pPackage
2415 )
2416 {
2417 HRESULT hr = S_OK;
2418
2419 AssertSz(BURN_PACKAGE_TYPE_MSI == pPackage->type, "Only MSI packages can have slipstream patches.");
2420
2421 for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i)
2422 {
2423 BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[i].pMspPackage;
2424 AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches.");
2425
2426 hr = AddCachePackageHelper(pPlan, pMspPackage, TRUE);
2427 ExitOnFailure(hr, "Failed to plan slipstream MSP: %ls", pMspPackage->sczId);
2428 }
2429
2430 LExit:
2431 return hr;
2432 }
2433
2434 static DWORD GetNextCheckpointId(
2435 __in BURN_PLAN* pPlan
2436 )
2437 {
2438 return ++pPlan->dwNextCheckpointId;
2439 }
2440
2441 static HRESULT AppendCacheAction(
2442 __in BURN_PLAN* pPlan,
2443 __out BURN_CACHE_ACTION** ppCacheAction
2444 )
2445 {
2446 HRESULT hr = S_OK;
2447
2448 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPlan->rgCacheActions), pPlan->cCacheActions + 1, sizeof(BURN_CACHE_ACTION), 5);
2449 ExitOnFailure(hr, "Failed to grow plan's array of cache actions.");
2450
2451 *ppCacheAction = pPlan->rgCacheActions + pPlan->cCacheActions;
2452 ++pPlan->cCacheActions;
2453
2454 LExit:
2455 return hr;
2456 }
2457
2458 static HRESULT AppendRollbackCacheAction(
2459 __in BURN_PLAN* pPlan,
2460 __out BURN_CACHE_ACTION** ppCacheAction
2461 )
2462 {
2463 HRESULT hr = S_OK;
2464
2465 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPlan->rgRollbackCacheActions), pPlan->cRollbackCacheActions + 1, sizeof(BURN_CACHE_ACTION), 5);
2466 ExitOnFailure(hr, "Failed to grow plan's array of rollback cache actions.");
2467
2468 *ppCacheAction = pPlan->rgRollbackCacheActions + pPlan->cRollbackCacheActions;
2469 ++pPlan->cRollbackCacheActions;
2470
2471 LExit:
2472 return hr;
2473 }
2474
2475 static HRESULT AppendCleanAction(
2476 __in BURN_PLAN* pPlan,
2477 __out BURN_CLEAN_ACTION** ppCleanAction
2478 )
2479 {
2480 HRESULT hr = S_OK;
2481
2482 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pPlan->rgCleanActions), pPlan->cCleanActions, 1, sizeof(BURN_CLEAN_ACTION), 5);
2483 ExitOnFailure(hr, "Failed to grow plan's array of clean actions.");
2484
2485
2486 *ppCleanAction = pPlan->rgCleanActions + pPlan->cCleanActions;
2487 ++pPlan->cCleanActions;
2488
2489 LExit:
2490 return hr;
2491 }
2492
2493 static HRESULT AppendRestoreRelatedBundleAction(
2494 __in BURN_PLAN* pPlan,
2495 __out BURN_EXECUTE_ACTION** ppExecuteAction
2496 )
2497 {
2498 HRESULT hr = S_OK;
2499
2500 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pPlan->rgRestoreRelatedBundleActions), pPlan->cRestoreRelatedBundleActions, 1, sizeof(BURN_EXECUTE_ACTION), 5);
2501 ExitOnFailure(hr, "Failed to grow plan's array of restore related bundle actions.");
2502
2503 *ppExecuteAction = pPlan->rgRestoreRelatedBundleActions + pPlan->cRestoreRelatedBundleActions;
2504 ++pPlan->cRestoreRelatedBundleActions;
2505
2506 LExit:
2507 return hr;
2508 }
2509
2510 static HRESULT ProcessPayloadGroup(
2511 __in BURN_PLAN* pPlan,
2512 __in BURN_PAYLOAD_GROUP* pPayloadGroup
2513 )
2514 {
2515 HRESULT hr = S_OK;
2516
2517 for (DWORD i = 0; i < pPayloadGroup->cItems; ++i)
2518 {
2519 BURN_PAYLOAD_GROUP_ITEM* pItem = pPayloadGroup->rgItems + i;
2520 BURN_PAYLOAD* pPayload = pItem->pPayload;
2521
2522 pPayload->cRemainingInstances += 1;
2523
2524 if (pPayload->pContainer && !pPayload->pContainer->fPlanned)
2525 {
2526 hr = PlanLayoutContainer(pPlan, pPayload->pContainer);
2527 ExitOnFailure(hr, "Failed to plan container: %ls", pPayload->pContainer->sczId);
2528 }
2529
2530 if (!pPlan->sczLayoutDirectory || !pPayload->pContainer)
2531 {
2532 // Acquire + Verify + Finalize
2533 pPlan->qwCacheSizeTotal += 3 * pPayload->qwFileSize;
2534
2535 if (!pPlan->sczLayoutDirectory)
2536 {
2537 // Staging
2538 pPlan->qwCacheSizeTotal += pPayload->qwFileSize;
2539 }
2540 }
2541
2542 if (!pPlan->sczLayoutDirectory && pPayload->pContainer && 1 == pPayload->cRemainingInstances)
2543 {
2544 // Extract
2545 pPlan->qwCacheSizeTotal += pPayload->qwFileSize;
2546 pPayload->pContainer->qwExtractSizeTotal += pPayload->qwFileSize;
2547 }
2548
2549 if (!pPayload->sczUnverifiedPath)
2550 {
2551 hr = CacheCalculatePayloadWorkingPath(pPlan->pCache, pPayload, &pPayload->sczUnverifiedPath);
2552 ExitOnFailure(hr, "Failed to calculate unverified path for payload.");
2553 }
2554 }
2555
2556 LExit:
2557 return hr;
2558 }
2559
2560 static void RemoveUnnecessaryActions(
2561 __in BOOL fExecute,
2562 __in BURN_EXECUTE_ACTION* rgActions,
2563 __in DWORD cActions
2564 )
2565 {
2566 LPCSTR szExecuteOrRollback = fExecute ? "execute" : "rollback";
2567
2568 for (DWORD i = 0; i < cActions; ++i)
2569 {
2570 BURN_EXECUTE_ACTION* pAction = rgActions + i;
2571
2572 if (BURN_EXECUTE_ACTION_TYPE_MSP_TARGET == pAction->type && pAction->mspTarget.pChainedTargetPackage)
2573 {
2574 BURN_MSPTARGETPRODUCT* pFirstTargetProduct = pAction->mspTarget.rgOrderedPatches->pTargetProduct;
2575 BURN_PATCH_SKIP_STATE skipState = fExecute ? pFirstTargetProduct->executeSkip : pFirstTargetProduct->rollbackSkip;
2576 BOOTSTRAPPER_ACTION_STATE chainedTargetPackageAction = fExecute ? pAction->mspTarget.pChainedTargetPackage->execute : pAction->mspTarget.pChainedTargetPackage->rollback;
2577
2578 switch (skipState)
2579 {
2580 case BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL:
2581 pAction->fDeleted = TRUE;
2582 LogId(REPORT_STANDARD, MSG_PLAN_SKIP_PATCH_ACTION, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.pChainedTargetPackage->sczId, LoggingActionStateToString(chainedTargetPackageAction), szExecuteOrRollback);
2583 break;
2584 case BURN_PATCH_SKIP_STATE_SLIPSTREAM:
2585 pAction->fDeleted = TRUE;
2586 LogId(REPORT_STANDARD, MSG_PLAN_SKIP_SLIPSTREAM_ACTION, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.pChainedTargetPackage->sczId, LoggingActionStateToString(chainedTargetPackageAction), szExecuteOrRollback);
2587 break;
2588 }
2589 }
2590 }
2591 }
2592
2593 static void FinalizePatchActions(
2594 __in BOOL fExecute,
2595 __in BURN_EXECUTE_ACTION* rgActions,
2596 __in DWORD cActions
2597 )
2598 {
2599 for (DWORD i = 0; i < cActions; ++i)
2600 {
2601 BURN_EXECUTE_ACTION* pAction = rgActions + i;
2602
2603 if (BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE == pAction->type)
2604 {
2605 BURN_PACKAGE* pPackage = pAction->msiPackage.pPackage;
2606 AssertSz(BOOTSTRAPPER_ACTION_STATE_NONE < pAction->msiPackage.action, "Planned execute MSI action to do nothing");
2607
2608 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pAction->msiPackage.action)
2609 {
2610 // If we are uninstalling the MSI, we must skip all the patches.
2611 for (DWORD j = 0; j < pPackage->Msi.cChainedPatches; ++j)
2612 {
2613 BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + j;
2614 BURN_MSPTARGETPRODUCT* pTargetProduct = pChainedPatch->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
2615
2616 if (fExecute)
2617 {
2618 pTargetProduct->execute = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
2619 pTargetProduct->executeSkip = BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL;
2620 }
2621 else
2622 {
2623 pTargetProduct->rollback = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
2624 pTargetProduct->rollbackSkip = BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL;
2625 }
2626 }
2627 }
2628 else
2629 {
2630 // If the slipstream target is being installed or upgraded (not uninstalled or repaired) then we will slipstream so skip
2631 // the patch's standalone action. Also, if the slipstream target is being repaired and the patch is being
2632 // repaired, skip this operation since it will be redundant.
2633 //
2634 // The primary goal here is to ensure that a slipstream patch that is yet not installed is installed even if the MSI
2635 // is already on the machine. The slipstream must be installed standalone if the MSI is being repaired.
2636 for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j)
2637 {
2638 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + j;
2639 BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + pSlipstreamMsp->dwMsiChainedPatchIndex;
2640 BURN_MSPTARGETPRODUCT* pTargetProduct = pSlipstreamMsp->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
2641 BOOTSTRAPPER_ACTION_STATE action = fExecute ? pTargetProduct->execute : pTargetProduct->rollback;
2642 BOOL fSlipstream = BOOTSTRAPPER_ACTION_STATE_UNINSTALL < action &&
2643 (BOOTSTRAPPER_ACTION_STATE_REPAIR != pAction->msiPackage.action || BOOTSTRAPPER_ACTION_STATE_REPAIR == action);
2644
2645 if (fSlipstream)
2646 {
2647 if (fExecute)
2648 {
2649 pSlipstreamMsp->execute = action;
2650 pTargetProduct->executeSkip = BURN_PATCH_SKIP_STATE_SLIPSTREAM;
2651 }
2652 else
2653 {
2654 pSlipstreamMsp->rollback = action;
2655 pTargetProduct->rollbackSkip = BURN_PATCH_SKIP_STATE_SLIPSTREAM;
2656 }
2657 }
2658 }
2659 }
2660 }
2661 }
2662 }
2663
2664 static void CalculateExpectedRegistrationStates(
2665 __in BURN_PACKAGE* rgPackages,
2666 __in DWORD cPackages
2667 )
2668 {
2669 for (DWORD i = 0; i < cPackages; ++i)
2670 {
2671 BURN_PACKAGE* pPackage = rgPackages + i;
2672
2673 // MspPackages can have actions throughout the plan, so the plan needed to be finalized before anything could be calculated.
2674 if (BURN_PACKAGE_TYPE_MSP == pPackage->type && !pPackage->fDependencyManagerWasHere)
2675 {
2676 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
2677 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
2678
2679 for (DWORD j = 0; j < pPackage->Msp.cTargetProductCodes; ++j)
2680 {
2681 BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + j;
2682
2683 // The highest aggregate action state found will be used.
2684 if (pPackage->execute < pTargetProduct->execute)
2685 {
2686 pPackage->execute = pTargetProduct->execute;
2687 }
2688
2689 if (pPackage->rollback < pTargetProduct->rollback)
2690 {
2691 pPackage->rollback = pTargetProduct->rollback;
2692 }
2693 }
2694 }
2695
2696 if (pPackage->fCanAffectRegistration)
2697 {
2698 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < pPackage->execute)
2699 {
2700 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2701 }
2702 else if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
2703 {
2704 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
2705 }
2706
2707 if (BURN_DEPENDENCY_ACTION_REGISTER == pPackage->dependencyExecute)
2708 {
2709 if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedCacheRegistrationState)
2710 {
2711 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2712 }
2713 if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedInstallRegistrationState)
2714 {
2715 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2716 }
2717 }
2718 else if (BURN_DEPENDENCY_ACTION_UNREGISTER == pPackage->dependencyExecute)
2719 {
2720 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedCacheRegistrationState)
2721 {
2722 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
2723 }
2724 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedInstallRegistrationState)
2725 {
2726 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
2727 }
2728 }
2729 }
2730 }
2731 }
2732
2733 static HRESULT PlanDependencyActions(
2734 __in BOOL fBundlePerMachine,
2735 __in BURN_PLAN* pPlan,
2736 __in BURN_PACKAGE* pPackage
2737 )
2738 {
2739 HRESULT hr = S_OK;
2740
2741 hr = DependencyPlanPackageBegin(fBundlePerMachine, pPackage, pPlan);
2742 ExitOnFailure(hr, "Failed to begin plan dependency actions for package: %ls", pPackage->sczId);
2743
2744 hr = DependencyPlanPackage(NULL, pPackage, pPlan);
2745 ExitOnFailure(hr, "Failed to plan package dependency actions.");
2746
2747 hr = DependencyPlanPackageComplete(pPackage, pPlan);
2748 ExitOnFailure(hr, "Failed to complete plan dependency actions for package: %ls", pPackage->sczId);
2749
2750 LExit:
2751 return hr;
2752 }
2753
2754 static HRESULT CalculateExecuteActions(
2755 __in BURN_PACKAGE* pPackage,
2756 __in_opt BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary
2757 )
2758 {
2759 HRESULT hr = S_OK;
2760 BOOL fInsideMsiTransaction = pActiveRollbackBoundary && pActiveRollbackBoundary->fTransaction;
2761
2762 // Calculate execute actions.
2763 switch (pPackage->type)
2764 {
2765 case BURN_PACKAGE_TYPE_BUNDLE:
2766 hr = BundlePackageEnginePlanCalculatePackage(pPackage);
2767 break;
2768
2769 case BURN_PACKAGE_TYPE_EXE:
2770 hr = ExeEnginePlanCalculatePackage(pPackage);
2771 break;
2772
2773 case BURN_PACKAGE_TYPE_MSI:
2774 hr = MsiEnginePlanCalculatePackage(pPackage, fInsideMsiTransaction);
2775 break;
2776
2777 case BURN_PACKAGE_TYPE_MSP:
2778 hr = MspEnginePlanCalculatePackage(pPackage, fInsideMsiTransaction);
2779 break;
2780
2781 case BURN_PACKAGE_TYPE_MSU:
2782 hr = MsuEnginePlanCalculatePackage(pPackage);
2783 break;
2784
2785 default:
2786 hr = E_UNEXPECTED;
2787 ExitOnFailure(hr, "Invalid package type.");
2788 }
2789
2790 pPackage->compatiblePackage.fRemove = pPackage->compatiblePackage.fPlannable && pPackage->compatiblePackage.fRequested;
2791
2792 LExit:
2793 return hr;
2794 }
2795
2796 static BURN_CACHE_PACKAGE_TYPE GetCachePackageType(
2797 __in BURN_PACKAGE* pPackage,
2798 __in BOOL fExecute
2799 )
2800 {
2801 BURN_CACHE_PACKAGE_TYPE cachePackageType = BURN_CACHE_PACKAGE_TYPE_NONE;
2802
2803 switch (fExecute ? pPackage->execute : pPackage->rollback)
2804 {
2805 case BOOTSTRAPPER_ACTION_STATE_NONE:
2806 break;
2807 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
2808 if (BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_DETECTION_TYPE_ARP != pPackage->Exe.detectionType)
2809 {
2810 // non-ArpEntry Exe packages require the package for all operations (even uninstall).
2811 cachePackageType = BURN_CACHE_PACKAGE_TYPE_REQUIRED;
2812 }
2813 else if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type)
2814 {
2815 // Bundle packages prefer the cache but can fallback to the ARP registration.
2816 cachePackageType = BURN_CACHE_PACKAGE_TYPE_OPTIONAL;
2817 }
2818 else
2819 {
2820 // The other package types can uninstall without the original package.
2821 cachePackageType = BURN_CACHE_PACKAGE_TYPE_NONE;
2822 }
2823 break;
2824 case BOOTSTRAPPER_ACTION_STATE_INSTALL: __fallthrough;
2825 case BOOTSTRAPPER_ACTION_STATE_MODIFY: __fallthrough;
2826 case BOOTSTRAPPER_ACTION_STATE_REPAIR: __fallthrough;
2827 case BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE: __fallthrough;
2828 default:
2829 // TODO: bundles could theoretically use package cache.
2830 cachePackageType = BURN_CACHE_PACKAGE_TYPE_REQUIRED;
2831 break;
2832 }
2833
2834 return cachePackageType;
2835 }
2836
2837 static BOOL ForceCache(
2838 __in BURN_PLAN* pPlan,
2839 __in BURN_PACKAGE* pPackage
2840 )
2841 {
2842 switch (pPackage->cacheType)
2843 {
2844 case BOOTSTRAPPER_CACHE_TYPE_KEEP:
2845 // During actions that are expected to have source media available,
2846 // all packages that have cacheType set to keep should be cached if the package is going to be present.
2847 return (BOOTSTRAPPER_ACTION_CACHE == pPlan->action || BOOTSTRAPPER_ACTION_INSTALL == pPlan->action) &&
2848 BOOTSTRAPPER_REQUEST_STATE_CACHE < pPackage->requested;
2849 case BOOTSTRAPPER_CACHE_TYPE_FORCE:
2850 // All packages that have cacheType set to force should be cached if the bundle is going to be present.
2851 return BOOTSTRAPPER_ACTION_UNINSTALL != pPlan->action && BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL != pPlan->action;
2852 default:
2853 return FALSE;
2854 }
2855 }
2856
2857 static void DependentRegistrationActionLog(
2858 __in DWORD iAction,
2859 __in BURN_DEPENDENT_REGISTRATION_ACTION* pAction,
2860 __in BOOL fRollback
2861 )
2862 {
2863 LPCWSTR wzBase = fRollback ? L" Rollback dependent registration" : L" Dependent registration";
2864 LPCWSTR wzType = NULL;
2865
2866 switch (pAction->type)
2867 {
2868 case BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER:
2869 wzType = L"REGISTER";
2870 break;
2871
2872 case BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_UNREGISTER:
2873 wzType = L"UNREGISTER";
2874 break;
2875
2876 default:
2877 AssertSz(FALSE, "Unknown cache action type.");
2878 break;
2879 }
2880
2881 if (wzType)
2882 {
2883 LogStringLine(PlanDumpLevel, "%ls action[%u]: %ls bundle id: %ls, provider key: %ls", wzBase, iAction, wzType, pAction->sczBundleId, pAction->sczDependentProviderKey);
2884 }
2885 }
2886
2887 static void CacheActionLog(
2888 __in DWORD iAction,
2889 __in BURN_CACHE_ACTION* pAction,
2890 __in BOOL fRollback
2891 )
2892 {
2893 LPCWSTR wzBase = fRollback ? L" Rollback cache" : L" Cache";
2894 switch (pAction->type)
2895 {
2896 case BURN_CACHE_ACTION_TYPE_CHECKPOINT:
2897 LogStringLine(PlanDumpLevel, "%ls action[%u]: CHECKPOINT id: %u", wzBase, iAction, pAction->checkpoint.dwId);
2898 break;
2899
2900 case BURN_CACHE_ACTION_TYPE_LAYOUT_BUNDLE:
2901 LogStringLine(PlanDumpLevel, "%ls action[%u]: LAYOUT_BUNDLE working path: %ls, exe name: %ls", wzBase, iAction, pAction->bundleLayout.sczUnverifiedPath, pAction->bundleLayout.sczExecutableName);
2902 break;
2903
2904 case BURN_CACHE_ACTION_TYPE_CONTAINER:
2905 LogStringLine(PlanDumpLevel, "%ls action[%u]: CONTAINER container id: %ls, working path: %ls", wzBase, iAction, pAction->container.pContainer->sczId, pAction->container.pContainer->sczUnverifiedPath);
2906 break;
2907
2908 case BURN_CACHE_ACTION_TYPE_PACKAGE:
2909 LogStringLine(PlanDumpLevel, "%ls action[%u]: PACKAGE id: %ls, vital: %hs, execute cache type: %hs, rollback cache type: %hs", wzBase, iAction, pAction->package.pPackage->sczId, LoggingBoolToString(pAction->package.pPackage->fCacheVital), LoggingCachePackageTypeToString(pAction->package.pPackage->executeCacheType), LoggingCachePackageTypeToString(pAction->package.pPackage->rollbackCacheType));
2910 break;
2911
2912 case BURN_CACHE_ACTION_TYPE_ROLLBACK_PACKAGE:
2913 LogStringLine(PlanDumpLevel, "%ls action[%u]: ROLLBACK_PACKAGE id: %ls", wzBase, iAction, pAction->rollbackPackage.pPackage->sczId);
2914 break;
2915
2916 case BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT:
2917 LogStringLine(PlanDumpLevel, "%ls action[%u]: SIGNAL_SYNCPOINT package id: %ls, event handle: 0x%p", wzBase, iAction, pAction->syncpoint.pPackage->sczId, pAction->syncpoint.pPackage->hCacheEvent);
2918 break;
2919
2920 default:
2921 AssertSz(FALSE, "Unknown cache action type.");
2922 break;
2923 }
2924 }
2925
2926 static void ExecuteActionLog(
2927 __in DWORD iAction,
2928 __in BURN_EXECUTE_ACTION* pAction,
2929 __in BOOL fRollback
2930 )
2931 {
2932 LPCWSTR wzBase = fRollback ? L" Rollback" : L" Execute";
2933 switch (pAction->type)
2934 {
2935 case BURN_EXECUTE_ACTION_TYPE_CHECKPOINT:
2936 LogStringLine(PlanDumpLevel, "%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)");
2937 break;
2938
2939 case BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER:
2940 LogStringLine(PlanDumpLevel, "%ls action[%u]: PACKAGE_PROVIDER package id: %ls", wzBase, iAction, pAction->packageProvider.pPackage->sczId);
2941 for (DWORD j = 0; j < pAction->packageProvider.pPackage->cDependencyProviders; ++j)
2942 {
2943 const BURN_DEPENDENCY_PROVIDER* pProvider = pAction->packageProvider.pPackage->rgDependencyProviders + j;
2944 LogStringLine(PlanDumpLevel, " Provider[%u]: key: %ls, action: %hs", j, pProvider->sczKey, LoggingDependencyActionToString(fRollback ? pProvider->providerRollback : pProvider->providerExecute));
2945 }
2946 break;
2947
2948 case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY:
2949 LogStringLine(PlanDumpLevel, "%ls action[%u]: PACKAGE_DEPENDENCY package id: %ls, bundle provider key: %ls", wzBase, iAction, pAction->packageDependency.pPackage->sczId, pAction->packageDependency.sczBundleProviderKey);
2950 for (DWORD j = 0; j < pAction->packageProvider.pPackage->cDependencyProviders; ++j)
2951 {
2952 const BURN_DEPENDENCY_PROVIDER* pProvider = pAction->packageProvider.pPackage->rgDependencyProviders + j;
2953 LogStringLine(PlanDumpLevel, " Provider[%u]: key: %ls, action: %hs", j, pProvider->sczKey, LoggingDependencyActionToString(fRollback ? pProvider->dependentRollback : pProvider->dependentExecute));
2954 }
2955 break;
2956
2957 case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE:
2958 LogStringLine(PlanDumpLevel, "%ls action[%u]: RELATED_BUNDLE package id: %ls, action: %hs, ignore dependencies: %ls", wzBase, iAction, pAction->relatedBundle.pRelatedBundle->package.sczId, LoggingActionStateToString(pAction->relatedBundle.action), pAction->relatedBundle.sczIgnoreDependencies);
2959 break;
2960
2961 case BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE:
2962 LogStringLine(PlanDumpLevel, "%ls action[%u]: BUNDLE_PACKAGE package id: %ls, action: %hs", wzBase, iAction, pAction->bundlePackage.pPackage->sczId, LoggingActionStateToString(pAction->bundlePackage.action));
2963 break;
2964
2965 case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE:
2966 LogStringLine(PlanDumpLevel, "%ls action[%u]: EXE_PACKAGE package id: %ls, action: %hs", wzBase, iAction, pAction->exePackage.pPackage->sczId, LoggingActionStateToString(pAction->exePackage.action));
2967 break;
2968
2969 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
2970 LogStringLine(PlanDumpLevel, "%ls action[%u]: MSI_PACKAGE package id: %ls, action: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %hs, file versioning: %hs, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->msiPackage.pPackage->sczId, LoggingActionStateToString(pAction->msiPackage.action), LoggingBurnMsiPropertyToString(pAction->msiPackage.actionMsiProperty), pAction->msiPackage.uiLevel, LoggingBoolToString(pAction->msiPackage.fDisableExternalUiHandler), LoggingMsiFileVersioningToString(pAction->msiPackage.fileVersioning), pAction->msiPackage.sczLogPath, pAction->msiPackage.dwLoggingAttributes);
2971 for (DWORD j = 0; j < pAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++j)
2972 {
2973 const BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pAction->msiPackage.pPackage->Msi.rgSlipstreamMsps + j;
2974 LogStringLine(PlanDumpLevel, " Patch[%u]: msp package id: %ls, action: %hs", j, pSlipstreamMsp->pMspPackage->sczId, LoggingActionStateToString(fRollback ? pSlipstreamMsp->rollback : pSlipstreamMsp->execute));
2975 }
2976 break;
2977
2978 case BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
2979 LogStringLine(PlanDumpLevel, "%ls action[%u]: UNINSTALL_MSI_COMPATIBLE_PACKAGE package id: %ls, compatible package id: %ls, cache id: %ls, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->uninstallMsiCompatiblePackage.pParentPackage->sczId, pAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.compatibleEntry.sczId, pAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.sczCacheId, pAction->uninstallMsiCompatiblePackage.sczLogPath, pAction->uninstallMsiCompatiblePackage.dwLoggingAttributes);
2980 break;
2981
2982 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
2983 LogStringLine(PlanDumpLevel, "%ls action[%u]: MSP_TARGET package id: %ls, action: %hs, target product code: %ls, target per-machine: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %hs, file versioning: %hs, log path: %ls", wzBase, iAction, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.sczTargetProductCode, LoggingBoolToString(pAction->mspTarget.fPerMachineTarget), LoggingBurnMsiPropertyToString(pAction->mspTarget.actionMsiProperty), pAction->mspTarget.uiLevel, LoggingBoolToString(pAction->mspTarget.fDisableExternalUiHandler), LoggingMsiFileVersioningToString(pAction->mspTarget.fileVersioning), pAction->mspTarget.sczLogPath);
2984 for (DWORD j = 0; j < pAction->mspTarget.cOrderedPatches; ++j)
2985 {
2986 LogStringLine(PlanDumpLevel, " Patch[%u]: order: %u, msp package id: %ls", j, pAction->mspTarget.rgOrderedPatches[j].pTargetProduct->dwOrder, pAction->mspTarget.rgOrderedPatches[j].pPackage->sczId);
2987 }
2988 break;
2989
2990 case BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE:
2991 LogStringLine(PlanDumpLevel, "%ls action[%u]: MSU_PACKAGE package id: %ls, action: %hs, log path: %ls", wzBase, iAction, pAction->msuPackage.pPackage->sczId, LoggingActionStateToString(pAction->msuPackage.action), pAction->msuPackage.sczLogPath);
2992 break;
2993
2994 case BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY_START:
2995 LogStringLine(PlanDumpLevel, "%ls action[%u]: ROLLBACK_BOUNDARY_START id: %ls, vital: %ls", wzBase, iAction, pAction->rollbackBoundary.pRollbackBoundary->sczId, pAction->rollbackBoundary.pRollbackBoundary->fVital ? L"yes" : L"no");
2996 break;
2997
2998 case BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY_END:
2999 LogStringLine(PlanDumpLevel, "%ls action[%u]: ROLLBACK_BOUNDARY_END", wzBase, iAction);
3000 break;
3001
3002 case BURN_EXECUTE_ACTION_TYPE_WAIT_CACHE_PACKAGE:
3003 LogStringLine(PlanDumpLevel, "%ls action[%u]: WAIT_CACHE_PACKAGE id: %ls, event handle: 0x%p", wzBase, iAction, pAction->waitCachePackage.pPackage->sczId, pAction->waitCachePackage.pPackage->hCacheEvent);
3004 break;
3005
3006 case BURN_EXECUTE_ACTION_TYPE_UNCACHE_PACKAGE:
3007 LogStringLine(PlanDumpLevel, "%ls action[%u]: UNCACHE_PACKAGE id: %ls", wzBase, iAction, pAction->uncachePackage.pPackage->sczId);
3008 break;
3009
3010 case BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION:
3011 LogStringLine(PlanDumpLevel, "%ls action[%u]: BEGIN_MSI_TRANSACTION id: %ls", wzBase, iAction, pAction->msiTransaction.pRollbackBoundary->sczId);
3012 break;
3013
3014 case BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION:
3015 LogStringLine(PlanDumpLevel, "%ls action[%u]: COMMIT_MSI_TRANSACTION id: %ls", wzBase, iAction, pAction->msiTransaction.pRollbackBoundary->sczId);
3016 break;
3017
3018 default:
3019 AssertSz(FALSE, "Unknown execute action type.");
3020 break;
3021 }
3022
3023 if (pAction->fDeleted)
3024 {
3025 LogStringLine(PlanDumpLevel, " (deleted action)");
3026 }
3027 }
3028
3029 static void RestoreRelatedBundleActionLog(
3030 __in DWORD iAction,
3031 __in BURN_EXECUTE_ACTION* pAction
3032 )
3033 {
3034 switch (pAction->type)
3035 {
3036 case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE:
3037 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);
3038 break;
3039
3040 default:
3041 AssertSz(FALSE, "Unknown execute action type.");
3042 break;
3043 }
3044
3045 if (pAction->fDeleted)
3046 {
3047 LogStringLine(PlanDumpLevel, " (deleted action)");
3048 }
3049 }
3050
3051 static void CleanActionLog(
3052 __in DWORD iAction,
3053 __in BURN_CLEAN_ACTION* pAction
3054 )
3055 {
3056 switch (pAction->type)
3057 {
3058 case BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE:
3059 LogStringLine(PlanDumpLevel, " Clean action[%u]: CLEAN_COMPATIBLE_PACKAGE package id: %ls", iAction, pAction->pPackage->sczId);
3060 break;
3061
3062 case BURN_CLEAN_ACTION_TYPE_PACKAGE:
3063 LogStringLine(PlanDumpLevel, " Clean action[%u]: CLEAN_PACKAGE package id: %ls", iAction, pAction->pPackage->sczId);
3064 break;
3065
3066 default:
3067 AssertSz(FALSE, "Unknown clean action type.");
3068 break;
3069 }
3070 }
3071
3072 extern "C" void PlanDump(
3073 __in BURN_PLAN* pPlan
3074 )
3075 {
3076 LogStringLine(PlanDumpLevel, "--- Begin plan dump ---");
3077
3078 LogStringLine(PlanDumpLevel, "Plan action: %hs", LoggingBurnActionToString(pPlan->action));
3079 LogStringLine(PlanDumpLevel, " bundle id: %ls", pPlan->wzBundleId);
3080 LogStringLine(PlanDumpLevel, " bundle provider key: %ls", pPlan->wzBundleProviderKey);
3081 LogStringLine(PlanDumpLevel, " use-forward-compatible: %hs", LoggingTrueFalseToString(pPlan->fEnabledForwardCompatibleBundle));
3082 LogStringLine(PlanDumpLevel, " per-machine: %hs", LoggingTrueFalseToString(pPlan->fPerMachine));
3083 LogStringLine(PlanDumpLevel, " can affect machine state: %hs", LoggingTrueFalseToString(pPlan->fCanAffectMachineState));
3084 LogStringLine(PlanDumpLevel, " disable-rollback: %hs", LoggingTrueFalseToString(pPlan->fDisableRollback));
3085 LogStringLine(PlanDumpLevel, " disallow-removal: %hs", LoggingTrueFalseToString(pPlan->fDisallowRemoval));
3086 LogStringLine(PlanDumpLevel, " downgrade: %hs", LoggingTrueFalseToString(pPlan->fDowngrade));
3087 LogStringLine(PlanDumpLevel, " registration options: %hs", LoggingRegistrationOptionsToString(pPlan->dwRegistrationOperations));
3088 if (pPlan->sczLayoutDirectory)
3089 {
3090 LogStringLine(PlanDumpLevel, " layout directory: %ls", pPlan->sczLayoutDirectory);
3091 }
3092
3093 for (DWORD i = 0; i < pPlan->cRegistrationActions; ++i)
3094 {
3095 DependentRegistrationActionLog(i, pPlan->rgRegistrationActions + i, FALSE);
3096 }
3097
3098 for (DWORD i = 0; i < pPlan->cRollbackRegistrationActions; ++i)
3099 {
3100 DependentRegistrationActionLog(i, pPlan->rgRollbackRegistrationActions + i, TRUE);
3101 }
3102
3103 LogStringLine(PlanDumpLevel, "Plan cache size: %llu", pPlan->qwCacheSizeTotal);
3104 for (DWORD i = 0; i < pPlan->cCacheActions; ++i)
3105 {
3106 CacheActionLog(i, pPlan->rgCacheActions + i, FALSE);
3107 }
3108
3109 for (DWORD i = 0; i < pPlan->cRollbackCacheActions; ++i)
3110 {
3111 CacheActionLog(i, pPlan->rgRollbackCacheActions + i, TRUE);
3112 }
3113
3114 LogStringLine(PlanDumpLevel, "Plan execute package count: %u", pPlan->cExecutePackagesTotal);
3115 LogStringLine(PlanDumpLevel, " overall progress ticks: %u", pPlan->cOverallProgressTicksTotal);
3116 for (DWORD i = 0; i < pPlan->cExecuteActions; ++i)
3117 {
3118 ExecuteActionLog(i, pPlan->rgExecuteActions + i, FALSE);
3119 }
3120
3121 for (DWORD i = 0; i < pPlan->cRollbackActions; ++i)
3122 {
3123 ExecuteActionLog(i, pPlan->rgRollbackActions + i, TRUE);
3124 }
3125
3126 for (DWORD i = 0; i < pPlan->cRestoreRelatedBundleActions; ++i)
3127 {
3128 RestoreRelatedBundleActionLog(i, pPlan->rgRestoreRelatedBundleActions + i);
3129 }
3130
3131 for (DWORD i = 0; i < pPlan->cCleanActions; ++i)
3132 {
3133 CleanActionLog(i, pPlan->rgCleanActions + i);
3134 }
3135
3136 for (DWORD i = 0; i < pPlan->cPlannedProviders; ++i)
3137 {
3138 LogStringLine(PlanDumpLevel, " Dependency action[%u]: PLANNED_PROVIDER key: %ls, name: %ls", i, pPlan->rgPlannedProviders[i].sczKey, pPlan->rgPlannedProviders[i].sczName);
3139 }
3140
3141 LogStringLine(PlanDumpLevel, "--- End plan dump ---");
3142 }