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