Fix patch registration states during plan and apply.

Add logging for slipstreamed patches.

#6297
This commit is contained in:
Sean Hall 2021-02-22 19:58:44 -06:00
Родитель 4f4c85ed66
Коммит a98115d996
12 изменённых файлов: 348 добавлений и 168 удалений

Просмотреть файл

@ -2032,7 +2032,7 @@ static HRESULT ExecuteMsiPackage(
LExit:
if (fExecuted)
{
MsiEngineUpdateInstallRegistrationState(pExecuteAction, hrExecute, fInsideMsiTransaction);
MsiEngineUpdateInstallRegistrationState(pExecuteAction, fRollback, hrExecute, fInsideMsiTransaction);
}
if (fBeginCalled)
@ -2248,7 +2248,20 @@ static HRESULT ExecuteDependencyAction(
{
pAction->packageDependency.pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
}
if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pAction->packageDependency.pPackage->installRegistrationState)
if (BURN_PACKAGE_TYPE_MSP == pAction->packageDependency.pPackage->type)
{
for (DWORD i = 0; i < pAction->packageDependency.pPackage->Msp.cTargetProductCodes; ++i)
{
BURN_MSPTARGETPRODUCT* pTargetProduct = pAction->packageDependency.pPackage->Msp.rgTargetProducts + i;
if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pTargetProduct->registrationState)
{
pTargetProduct->registrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
}
}
}
else if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pAction->packageDependency.pPackage->installRegistrationState)
{
pAction->packageDependency.pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
}
@ -2259,7 +2272,20 @@ static HRESULT ExecuteDependencyAction(
{
pAction->packageDependency.pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
}
if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pAction->packageDependency.pPackage->installRegistrationState)
if (BURN_PACKAGE_TYPE_MSP == pAction->packageDependency.pPackage->type)
{
for (DWORD i = 0; i < pAction->packageDependency.pPackage->Msp.cTargetProductCodes; ++i)
{
BURN_MSPTARGETPRODUCT* pTargetProduct = pAction->packageDependency.pPackage->Msp.rgTargetProducts + i;
if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pTargetProduct->registrationState)
{
pTargetProduct->registrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
}
}
}
else if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pAction->packageDependency.pPackage->installRegistrationState)
{
pAction->packageDependency.pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
}

Просмотреть файл

@ -1814,15 +1814,30 @@ static void LogPackages(
LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingBoolToString(pPackage->fAcquire), LoggingBoolToString(pPackage->fUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState));
if (BURN_PACKAGE_TYPE_MSI == pPackage->type && pPackage->Msi.cFeatures)
if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
{
LogId(REPORT_STANDARD, MSG_PLANNED_MSI_FEATURES, pPackage->Msi.cFeatures, pPackage->sczId);
for (DWORD j = 0; j < pPackage->Msi.cFeatures; ++j)
if (pPackage->Msi.cFeatures)
{
const BURN_MSIFEATURE* pFeature = &pPackage->Msi.rgFeatures[j];
LogId(REPORT_STANDARD, MSG_PLANNED_MSI_FEATURES, pPackage->Msi.cFeatures, pPackage->sczId);
LogId(REPORT_STANDARD, MSG_PLANNED_MSI_FEATURE, pFeature->sczId, LoggingMsiFeatureStateToString(pFeature->currentState), LoggingMsiFeatureStateToString(pFeature->defaultRequested), LoggingMsiFeatureStateToString(pFeature->requested), LoggingMsiFeatureActionToString(pFeature->execute), LoggingMsiFeatureActionToString(pFeature->rollback));
for (DWORD j = 0; j < pPackage->Msi.cFeatures; ++j)
{
const BURN_MSIFEATURE* pFeature = &pPackage->Msi.rgFeatures[j];
LogId(REPORT_STANDARD, MSG_PLANNED_MSI_FEATURE, pFeature->sczId, LoggingMsiFeatureStateToString(pFeature->currentState), LoggingMsiFeatureStateToString(pFeature->defaultRequested), LoggingMsiFeatureStateToString(pFeature->requested), LoggingMsiFeatureActionToString(pFeature->execute), LoggingMsiFeatureActionToString(pFeature->rollback));
}
}
if (pPackage->Msi.cSlipstreamMspPackages)
{
LogId(REPORT_STANDARD, MSG_PLANNED_SLIPSTREAMED_MSP_TARGETS, pPackage->Msi.cSlipstreamMspPackages, pPackage->sczId);
for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j)
{
const BURN_SLIPSTREAM_MSP* pSlipstreamMsp = &pPackage->Msi.rgSlipstreamMsps[j];
LogId(REPORT_STANDARD, MSG_PLANNED_SLIPSTREAMED_MSP_TARGET, pSlipstreamMsp->pMspPackage->sczId, LoggingActionStateToString(pSlipstreamMsp->execute), LoggingActionStateToString(pSlipstreamMsp->rollback));
}
}
}
else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.cTargetProductCodes)

Просмотреть файл

@ -774,6 +774,18 @@ static HRESULT DetectPackageDependents(
{
pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
}
if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
{
for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
{
BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i;
if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pTargetProduct->registrationState)
{
pTargetProduct->registrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
}
}
}
}
LExit:

Просмотреть файл

@ -855,6 +855,9 @@ extern "C" HRESULT ElevationExecuteMsiPackage(
DWORD dwResult = 0;
// serialize message data
hr = BuffWriteNumber(&pbData, &cbData, (DWORD)fRollback);
ExitOnFailure(hr, "Failed to write rollback flag to message buffer.");
hr = BuffWriteString(&pbData, &cbData, pExecuteAction->msiPackage.pPackage->sczId);
ExitOnFailure(hr, "Failed to write package id to message buffer.");
@ -886,16 +889,15 @@ extern "C" HRESULT ElevationExecuteMsiPackage(
// Slipstream patches actions.
for (DWORD i = 0; i < pExecuteAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++i)
{
hr = BuffWriteNumber(&pbData, &cbData, (DWORD)pExecuteAction->msiPackage.rgSlipstreamPatches[i]);
BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pExecuteAction->msiPackage.pPackage->Msi.rgSlipstreamMsps + i;
BOOTSTRAPPER_ACTION_STATE* pAction = fRollback ? &pSlipstreamMsp->rollback : &pSlipstreamMsp->execute;
hr = BuffWriteNumber(&pbData, &cbData, (DWORD)*pAction);
ExitOnFailure(hr, "Failed to write slipstream patch action to message buffer.");
}
hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData);
ExitOnFailure(hr, "Failed to write variables.");
hr = BuffWriteNumber(&pbData, &cbData, (DWORD)fRollback);
ExitOnFailure(hr, "Failed to write rollback flag to message buffer.");
// send message
context.pfnMessageHandler = pfnMessageHandler;
@ -2263,6 +2265,9 @@ static HRESULT OnExecuteMsiPackage(
executeAction.type = BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE;
// Deserialize message data.
hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback);
ExitOnFailure(hr, "Failed to read rollback flag.");
hr = BuffReadString(pbData, cbData, &iData, &sczPackage);
ExitOnFailure(hr, "Failed to read MSI package id.");
@ -2303,12 +2308,11 @@ static HRESULT OnExecuteMsiPackage(
// Read slipstream patches actions.
if (executeAction.msiPackage.pPackage->Msi.cSlipstreamMspPackages)
{
executeAction.msiPackage.rgSlipstreamPatches = (BOOTSTRAPPER_ACTION_STATE*)MemAlloc(executeAction.msiPackage.pPackage->Msi.cSlipstreamMspPackages * sizeof(BOOTSTRAPPER_ACTION_STATE), TRUE);
ExitOnNull(executeAction.msiPackage.rgSlipstreamPatches, hr, E_OUTOFMEMORY, "Failed to allocate memory for slipstream patch actions.");
for (DWORD i = 0; i < executeAction.msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++i)
{
hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&executeAction.msiPackage.rgSlipstreamPatches[i]);
BURN_SLIPSTREAM_MSP* pSlipstreamMsp = executeAction.msiPackage.pPackage->Msi.rgSlipstreamMsps + i;
BOOTSTRAPPER_ACTION_STATE* pAction = fRollback ? &pSlipstreamMsp->rollback : &pSlipstreamMsp->execute;
hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)pAction);
ExitOnFailure(hr, "Failed to read slipstream action.");
}
}
@ -2316,9 +2320,6 @@ static HRESULT OnExecuteMsiPackage(
hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData);
ExitOnFailure(hr, "Failed to read variables.");
hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback);
ExitOnFailure(hr, "Failed to read rollback flag.");
// Execute MSI package.
hr = MsiEngineExecutePackage(hwndParent, &executeAction, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart);
ExitOnFailure(hr, "Failed to execute MSI package.");

Просмотреть файл

@ -321,14 +321,14 @@ MessageId=203
Severity=Success
SymbolicName=MSG_PLANNED_MSI_FEATURE
Language=English
Planned feature: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute action: %5!hs!, rollback action: %6!hs!
Planned feature: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute action: %5!hs!, rollback action: %6!hs!
.
MessageId=204
Severity=Success
SymbolicName=MSG_PLANNED_MSI_FEATURES
Language=English
Plan %1!u! msi features for package: %2!ls!
Plan %1!u! msi features for package: %2!ls!
.
MessageId=205
@ -419,14 +419,28 @@ MessageId=218
Severity=Success
SymbolicName=MSG_PLANNED_MSP_TARGETS
Language=English
Plan %1!u! patch targets for package: %2!ls!
Plan %1!u! patch targets for package: %2!ls!
.
MessageId=219
Severity=Success
SymbolicName=MSG_PLANNED_MSP_TARGET
Language=English
Planned patch target: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!
Planned patch target: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!
.
MessageId=220
Severity=Success
SymbolicName=MSG_PLANNED_SLIPSTREAMED_MSP_TARGETS
Language=English
Plan %1!u! slipstream patches for package: %2!ls!
.
MessageId=221
Severity=Success
SymbolicName=MSG_PLANNED_SLIPSTREAMED_MSP_TARGET
Language=English
Planned slipstreamed patch: %1!ls!, execute: %2!hs!, rollback: %3!hs!
.
MessageId=299

Просмотреть файл

@ -42,7 +42,7 @@ static HRESULT ConcatFeatureActionProperties(
);
static HRESULT ConcatPatchProperty(
__in BURN_PACKAGE* pPackage,
__in_opt BOOTSTRAPPER_ACTION_STATE* rgSlipstreamPatchActions,
__in BOOL fRollback,
__inout_z LPWSTR* psczArguments
);
static void RegisterSourceDirectory(
@ -1180,10 +1180,10 @@ extern "C" HRESULT MsiEngineExecutePackage(
ExitOnFailure(hr, "Failed to add feature action properties to obfuscated argument string.");
// add slipstream patch properties
hr = ConcatPatchProperty(pExecuteAction->msiPackage.pPackage, pExecuteAction->msiPackage.rgSlipstreamPatches, &sczProperties);
hr = ConcatPatchProperty(pExecuteAction->msiPackage.pPackage, fRollback, &sczProperties);
ExitOnFailure(hr, "Failed to add patch properties to argument string.");
hr = ConcatPatchProperty(pExecuteAction->msiPackage.pPackage, pExecuteAction->msiPackage.rgSlipstreamPatches, &sczObfuscatedProperties);
hr = ConcatPatchProperty(pExecuteAction->msiPackage.pPackage, fRollback, &sczObfuscatedProperties);
ExitOnFailure(hr, "Failed to add patch properties to obfuscated argument string.");
hr = MsiEngineConcatActionProperty(pExecuteAction->msiPackage.actionMsiProperty, &sczProperties);
@ -1432,6 +1432,7 @@ extern "C" HRESULT MsiEngineCalculateInstallUiLevel(
extern "C" void MsiEngineUpdateInstallRegistrationState(
__in BURN_EXECUTE_ACTION* pAction,
__in BOOL fRollback,
__in HRESULT hrExecute,
__in BOOL fInsideMsiTransaction
)
@ -1462,6 +1463,49 @@ extern "C" void MsiEngineUpdateInstallRegistrationState(
pPackage->installRegistrationState = newState;
}
if (BURN_PACKAGE_REGISTRATION_STATE_ABSENT == newState)
{
for (DWORD i = 0; i < pPackage->Msi.cChainedPatches; ++i)
{
BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + i;
BURN_MSPTARGETPRODUCT* pTargetProduct = pChainedPatch->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
if (fInsideMsiTransaction)
{
pTargetProduct->transactionRegistrationState = newState;
}
else
{
pTargetProduct->registrationState = newState;
}
}
}
else
{
for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i)
{
BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + i;
BOOTSTRAPPER_ACTION_STATE patchExecuteAction = fRollback ? pSlipstreamMsp->rollback : pSlipstreamMsp->execute;
if (BOOTSTRAPPER_ACTION_STATE_INSTALL > patchExecuteAction)
{
continue;
}
BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + pSlipstreamMsp->dwMsiChainedPatchIndex;
BURN_MSPTARGETPRODUCT* pTargetProduct = pChainedPatch->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
if (fInsideMsiTransaction)
{
pTargetProduct->transactionRegistrationState = newState;
}
else
{
pTargetProduct->registrationState = newState;
}
}
}
LExit:
return;
}
@ -1911,7 +1955,7 @@ LExit:
static HRESULT ConcatPatchProperty(
__in BURN_PACKAGE* pPackage,
__in_opt BOOTSTRAPPER_ACTION_STATE* rgSlipstreamPatchActions,
__in BOOL fRollback,
__inout_z LPWSTR* psczArguments
)
{
@ -1921,14 +1965,14 @@ static HRESULT ConcatPatchProperty(
LPWSTR sczPatches = NULL;
// If there are slipstream patch actions, build up their patch action.
if (rgSlipstreamPatchActions)
if (pPackage->Msi.cSlipstreamMspPackages)
{
for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i)
{
BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[i].pMspPackage;
AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches.");
BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + i;
BURN_PACKAGE* pMspPackage = pSlipstreamMsp->pMspPackage;
BOOTSTRAPPER_ACTION_STATE patchExecuteAction = fRollback ? pSlipstreamMsp->rollback : pSlipstreamMsp->execute;
BOOTSTRAPPER_ACTION_STATE patchExecuteAction = rgSlipstreamPatchActions[i];
if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < patchExecuteAction)
{
hr = CacheGetCompletedPath(pMspPackage->fPerMachine, pMspPackage->sczCacheId, &sczCachedDirectory);

Просмотреть файл

@ -95,6 +95,7 @@ HRESULT MsiEngineCalculateInstallUiLevel(
);
void MsiEngineUpdateInstallRegistrationState(
__in BURN_EXECUTE_ACTION* pAction,
__in BOOL fRollback,
__in HRESULT hrExecute,
__in BOOL fInsideMsiTransaction
);

Просмотреть файл

@ -372,6 +372,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
)
{
HRESULT hr = S_OK;
BOOL fWillUninstallAll = TRUE;
for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
{
@ -388,6 +389,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
{
case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
execute = BOOTSTRAPPER_ACTION_STATE_REPAIR;
fWillUninstallAll = FALSE;
break;
case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough;
@ -401,6 +403,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
default:
execute = BOOTSTRAPPER_ACTION_STATE_NONE;
fWillUninstallAll = FALSE;
break;
}
break;
@ -411,6 +414,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough;
case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
execute = BOOTSTRAPPER_ACTION_STATE_INSTALL;
fWillUninstallAll = FALSE;
break;
default:
@ -418,6 +422,13 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
break;
}
break;
default:
if (pTargetProduct->fInstalled)
{
fWillUninstallAll = FALSE;
}
break;
}
// Calculate the rollback action if there is an execute action.
@ -475,6 +486,13 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
}
}
// The dependency manager will do the wrong thing if the package level action is UNINSTALL
// when the patch will still be applied to at least one product.
if (!fWillUninstallAll && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
{
pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
}
return hr;
}
@ -776,16 +794,22 @@ extern "C" void MspEngineFinalizeInstallRegistrationState(
ExitFunction();
}
pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
if (!pPackage->Msp.cTargetProductCodes)
{
BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i;
pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
}
else
{
pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pTargetProduct->registrationState)
for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
{
pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
break;
BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i;
if (pPackage->installRegistrationState < pTargetProduct->registrationState)
{
pPackage->installRegistrationState = pTargetProduct->registrationState;
}
}
}

Просмотреть файл

@ -83,8 +83,8 @@ enum BOOTSTRAPPER_FEATURE_ACTION
enum BURN_PACKAGE_REGISTRATION_STATE
{
BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN,
BURN_PACKAGE_REGISTRATION_STATE_IGNORED,
BURN_PACKAGE_REGISTRATION_STATE_ABSENT,
BURN_PACKAGE_REGISTRATION_STATE_IGNORED,
BURN_PACKAGE_REGISTRATION_STATE_PRESENT,
};
@ -186,6 +186,9 @@ typedef struct _BURN_SLIPSTREAM_MSP
{
BURN_PACKAGE* pMspPackage;
DWORD dwMsiChainedPatchIndex; // index into the Msi.rgChainedPatches
BOOTSTRAPPER_ACTION_STATE execute; // only valid during Plan.
BOOTSTRAPPER_ACTION_STATE rollback; // only valid during Plan.
} BURN_SLIPSTREAM_MSP;
typedef struct _BURN_PACKAGE_PAYLOAD

Просмотреть файл

@ -154,11 +154,15 @@ static void RemoveUnnecessaryActions(
__in BURN_EXECUTE_ACTION* rgActions,
__in DWORD cActions
);
static HRESULT FinalizeSlipstreamPatchActions(
static void FinalizePatchActions(
__in BOOL fExecute,
__in BURN_EXECUTE_ACTION* rgActions,
__in DWORD cActions
);
static void CalculateExpectedRegistrationStates(
__in BURN_PACKAGE* rgPackages,
__in DWORD cPackages
);
static HRESULT PlanDependencyActions(
__in BOOL fBundlePerMachine,
__in BURN_PLAN* pPlan,
@ -301,7 +305,6 @@ extern "C" void PlanUninitializeExecuteAction(
case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
ReleaseStr(pExecuteAction->msiPackage.sczLogPath);
ReleaseMem(pExecuteAction->msiPackage.rgFeatures);
ReleaseMem(pExecuteAction->msiPackage.rgSlipstreamPatches);
break;
case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
@ -823,6 +826,8 @@ static HRESULT PlanPackagesHelper(
hr = PlanFinalizeActions(pPlan);
ExitOnFailure(hr, "Failed to remove unnecessary actions from plan.");
CalculateExpectedRegistrationStates(rgPackages, cPackages);
// Let the BA know the actions that were planned.
for (DWORD i = 0; i < cPackages; ++i)
{
@ -848,6 +853,12 @@ static HRESULT InitializePackage(
BOOL fInstallCondition = FALSE;
BOOL fBeginCalled = FALSE;
if (pPackage->fCanAffectRegistration)
{
pPackage->expectedCacheRegistrationState = pPackage->cacheRegistrationState;
pPackage->expectedInstallRegistrationState = pPackage->installRegistrationState;
}
if (pPackage->sczInstallCondition && *pPackage->sczInstallCondition)
{
hr = ConditionEvaluate(pVariables, pPackage->sczInstallCondition, &fInstallCondition);
@ -903,68 +914,24 @@ static HRESULT ProcessPackage(
hr = ProcessPackageRollbackBoundary(pPlan, pEffectiveRollbackBoundary, ppRollbackBoundary);
ExitOnFailure(hr, "Failed to process package rollback boundary.");
if (pPackage->fCanAffectRegistration)
if (BOOTSTRAPPER_ACTION_LAYOUT == pPlan->action)
{
pPackage->expectedCacheRegistrationState = pPackage->cacheRegistrationState;
pPackage->expectedInstallRegistrationState = pPackage->installRegistrationState;
hr = PlanLayoutPackage(pPlan, pPackage, wzLayoutDirectory);
ExitOnFailure(hr, "Failed to plan layout package.");
}
// If the package is in a requested state, plan it.
if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested)
else
{
if (BOOTSTRAPPER_ACTION_LAYOUT == pPlan->action)
if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested)
{
hr = PlanLayoutPackage(pPlan, pPackage, wzLayoutDirectory);
ExitOnFailure(hr, "Failed to plan layout package.");
// If the package is in a requested state, plan it.
hr = PlanExecutePackage(fBundlePerMachine, display, pUX, pPlan, pPackage, pLog, pVariables, phSyncpointEvent);
ExitOnFailure(hr, "Failed to plan execute package.");
}
else
{
hr = PlanExecutePackage(fBundlePerMachine, display, pUX, pPlan, pPackage, pLog, pVariables, phSyncpointEvent);
ExitOnFailure(hr, "Failed to plan execute package.");
if (pPackage->fCanAffectRegistration)
{
if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < pPackage->execute)
{
pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
}
else if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
{
pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
}
}
}
}
else if (BOOTSTRAPPER_ACTION_LAYOUT != pPlan->action)
{
// Make sure the package is properly ref-counted even if no plan is requested.
hr = PlanDependencyActions(fBundlePerMachine, pPlan, pPackage);
ExitOnFailure(hr, "Failed to plan dependency actions for package: %ls", pPackage->sczId);
}
if (pPackage->fCanAffectRegistration)
{
if (BURN_DEPENDENCY_ACTION_REGISTER == pPackage->dependencyExecute)
{
if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedCacheRegistrationState)
{
pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
}
if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedInstallRegistrationState)
{
pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
}
}
else if (BURN_DEPENDENCY_ACTION_UNREGISTER == pPackage->dependencyExecute)
{
if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedCacheRegistrationState)
{
pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
}
if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedInstallRegistrationState)
{
pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
}
// Make sure the package is properly ref-counted even if no plan is requested.
hr = PlanDependencyActions(fBundlePerMachine, pPlan, pPackage);
ExitOnFailure(hr, "Failed to plan dependency actions for package: %ls", pPackage->sczId);
}
}
@ -1498,17 +1465,14 @@ extern "C" HRESULT PlanFinalizeActions(
{
HRESULT hr = S_OK;
FinalizePatchActions(TRUE, pPlan->rgExecuteActions, pPlan->cExecuteActions);
FinalizePatchActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions);
RemoveUnnecessaryActions(TRUE, pPlan->rgExecuteActions, pPlan->cExecuteActions);
RemoveUnnecessaryActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions);
hr = FinalizeSlipstreamPatchActions(TRUE, pPlan->rgExecuteActions, pPlan->cExecuteActions);
ExitOnFailure(hr, "Failed to finalize slipstream execute actions.");
hr = FinalizeSlipstreamPatchActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions);
ExitOnFailure(hr, "Failed to finalize slipstream rollback actions.");
LExit:
return hr;
}
@ -1868,7 +1832,7 @@ static void ResetPlannedPackageState(
pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
if (BURN_PACKAGE_TYPE_MSI == pPackage->type && pPackage->Msi.rgFeatures)
if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
{
for (DWORD i = 0; i < pPackage->Msi.cFeatures; ++i)
{
@ -1880,6 +1844,14 @@ static void ResetPlannedPackageState(
pFeature->execute = BOOTSTRAPPER_FEATURE_ACTION_NONE;
pFeature->rollback = BOOTSTRAPPER_FEATURE_ACTION_NONE;
}
for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i)
{
BURN_SLIPSTREAM_MSP* pSlipstreamMsp = &pPackage->Msi.rgSlipstreamMsps[i];
pSlipstreamMsp->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
pSlipstreamMsp->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
}
}
else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.rgTargetProducts)
{
@ -2716,47 +2688,91 @@ static void RemoveUnnecessaryActions(
{
BURN_EXECUTE_ACTION* pAction = rgActions + i;
// If this MSP targets a package in the chain, check the target's execute state
// to see if this patch should be skipped.
if (BURN_EXECUTE_ACTION_TYPE_MSP_TARGET == pAction->type && pAction->mspTarget.pChainedTargetPackage)
{
BURN_MSPTARGETPRODUCT* pFirstTargetProduct = pAction->mspTarget.rgOrderedPatches->pTargetProduct;
BURN_PATCH_SKIP_STATE skipState = fExecute ? pFirstTargetProduct->executeSkip : pFirstTargetProduct->rollbackSkip;
BOOTSTRAPPER_ACTION_STATE chainedTargetPackageAction = fExecute ? pAction->mspTarget.pChainedTargetPackage->execute : pAction->mspTarget.pChainedTargetPackage->rollback;
BURN_PATCH_SKIP_STATE skipState = BURN_PATCH_SKIP_STATE_NONE;
if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == chainedTargetPackageAction)
switch (skipState)
{
skipState = BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL;
case BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL:
pAction->fDeleted = TRUE;
LogId(REPORT_STANDARD, MSG_PLAN_SKIP_PATCH_ACTION, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.pChainedTargetPackage->sczId, LoggingActionStateToString(chainedTargetPackageAction), szExecuteOrRollback);
break;
case BURN_PATCH_SKIP_STATE_SLIPSTREAM:
pAction->fDeleted = TRUE;
LogId(REPORT_STANDARD, MSG_PLAN_SKIP_SLIPSTREAM_ACTION, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.pChainedTargetPackage->sczId, LoggingActionStateToString(chainedTargetPackageAction), szExecuteOrRollback);
break;
}
else if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < chainedTargetPackageAction && pAction->mspTarget.fSlipstream && BOOTSTRAPPER_ACTION_STATE_UNINSTALL < pAction->mspTarget.action)
}
}
}
static void FinalizePatchActions(
__in BOOL fExecute,
__in BURN_EXECUTE_ACTION* rgActions,
__in DWORD cActions
)
{
for (DWORD i = 0; i < cActions; ++i)
{
BURN_EXECUTE_ACTION* pAction = rgActions + i;
if (BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE == pAction->type)
{
BURN_PACKAGE* pPackage = pAction->msiPackage.pPackage;
AssertSz(BOOTSTRAPPER_ACTION_STATE_NONE < pAction->msiPackage.action, "Planned execute MSI action to do nothing");
if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pAction->msiPackage.action)
{
// If we are uninstalling the MSI, we must skip all the patches.
for (DWORD j = 0; j < pPackage->Msi.cChainedPatches; ++j)
{
BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + j;
BURN_MSPTARGETPRODUCT* pTargetProduct = pChainedPatch->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
if (fExecute)
{
pTargetProduct->execute = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
pTargetProduct->executeSkip = BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL;
}
else
{
pTargetProduct->rollback = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
pTargetProduct->rollbackSkip = BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL;
}
}
}
else
{
// If the slipstream target is being installed or upgraded (not uninstalled or repaired) then we will slipstream so skip
// this action to install the patch standalone. Also, if the slipstream target is being repaired and the patch is being
// the patch's standalone action. Also, if the slipstream target is being repaired and the patch is being
// repaired, skip this operation since it will be redundant.
//
// The primary goal here is to ensure that a slipstream patch that is yet not installed is installed even if the MSI
// is already on the machine. The slipstream must be installed standalone if the MSI is being repaired.
if (BOOTSTRAPPER_ACTION_STATE_REPAIR != chainedTargetPackageAction || BOOTSTRAPPER_ACTION_STATE_REPAIR == pAction->mspTarget.action)
for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j)
{
skipState = BURN_PATCH_SKIP_STATE_SLIPSTREAM;
LogId(REPORT_STANDARD, MSG_PLAN_SKIP_SLIPSTREAM_ACTION, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.pChainedTargetPackage->sczId, LoggingActionStateToString(chainedTargetPackageAction), szExecuteOrRollback);
}
}
BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + j;
BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + pSlipstreamMsp->dwMsiChainedPatchIndex;
BURN_MSPTARGETPRODUCT* pTargetProduct = pSlipstreamMsp->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
BOOTSTRAPPER_ACTION_STATE action = fExecute ? pTargetProduct->execute : pTargetProduct->rollback;
BOOL fSlipstream = BOOTSTRAPPER_ACTION_STATE_UNINSTALL < action &&
(BOOTSTRAPPER_ACTION_STATE_REPAIR != pAction->msiPackage.action || BOOTSTRAPPER_ACTION_STATE_REPAIR == action);
if (BURN_PATCH_SKIP_STATE_NONE != skipState)
{
pAction->fDeleted = TRUE;
for (DWORD j = 0; j < pAction->mspTarget.cOrderedPatches; ++j)
{
BURN_MSPTARGETPRODUCT* pTargetProduct = pAction->mspTarget.rgOrderedPatches[j].pTargetProduct;
if (fExecute)
if (fSlipstream)
{
pTargetProduct->executeSkip = skipState;
}
else
{
pTargetProduct->rollbackSkip = skipState;
if (fExecute)
{
pSlipstreamMsp->execute = action;
pTargetProduct->executeSkip = BURN_PATCH_SKIP_STATE_SLIPSTREAM;
}
else
{
pSlipstreamMsp->rollback = action;
pTargetProduct->rollbackSkip = BURN_PATCH_SKIP_STATE_SLIPSTREAM;
}
}
}
}
@ -2764,53 +2780,73 @@ static void RemoveUnnecessaryActions(
}
}
static HRESULT FinalizeSlipstreamPatchActions(
__in BOOL fExecute,
__in BURN_EXECUTE_ACTION* rgActions,
__in DWORD cActions
static void CalculateExpectedRegistrationStates(
__in BURN_PACKAGE* rgPackages,
__in DWORD cPackages
)
{
HRESULT hr = S_OK;
for (DWORD i = 0; i < cActions; ++i)
for (DWORD i = 0; i < cPackages; ++i)
{
BURN_EXECUTE_ACTION* pAction = rgActions + i;
BURN_PACKAGE* pPackage = rgPackages + i;
// If this MSI package contains slipstream patches store the slipstream actions.
if (BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE == pAction->type && pAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages)
// MspPackages can have actions throughout the plan, so the plan needed to be finalized before anything could be calculated.
if (BURN_PACKAGE_TYPE_MSP == pPackage->type && !pPackage->fDependencyManagerWasHere)
{
BURN_PACKAGE* pPackage = pAction->msiPackage.pPackage;
pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
// By default all slipstream actions will be initialized to "no action" (aka: 0).
pAction->msiPackage.rgSlipstreamPatches = (BOOTSTRAPPER_ACTION_STATE*)MemAlloc(sizeof(BOOTSTRAPPER_ACTION_STATE) * pPackage->Msi.cSlipstreamMspPackages, TRUE);
ExitOnNull(pAction->msiPackage.rgSlipstreamPatches, hr, E_OUTOFMEMORY, "Failed to allocate memory for patch actions.");
// If we are uninstalling or repairing the MSI, we must ignore all the slipstream patches because they cannot
// be applied right now.
if (BOOTSTRAPPER_ACTION_STATE_REPAIR != pAction->msiPackage.action && BOOTSTRAPPER_ACTION_STATE_UNINSTALL != pAction->msiPackage.action)
for (DWORD j = 0; j < pPackage->Msp.cTargetProductCodes; ++j)
{
for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j)
{
BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[j].pMspPackage;
AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches.");
BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + j;
pAction->msiPackage.rgSlipstreamPatches[j] = fExecute ? pMspPackage->execute : pMspPackage->rollback;
for (DWORD k = 0; k < pMspPackage->Msp.cTargetProductCodes; ++k)
{
BURN_MSPTARGETPRODUCT* pTargetProduct = pMspPackage->Msp.rgTargetProducts + k;
if (pPackage == pTargetProduct->pChainedTargetPackage)
{
pAction->msiPackage.rgSlipstreamPatches[j] = fExecute ? pTargetProduct->execute : pTargetProduct->rollback;
break;
}
}
// The highest aggregate action state found will be used.
if (pPackage->execute < pTargetProduct->execute)
{
pPackage->execute = pTargetProduct->execute;
}
if (pPackage->rollback < pTargetProduct->rollback)
{
pPackage->rollback = pTargetProduct->rollback;
}
}
}
if (pPackage->fCanAffectRegistration)
{
if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < pPackage->execute)
{
pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
}
else if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
{
pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
}
if (BURN_DEPENDENCY_ACTION_REGISTER == pPackage->dependencyExecute)
{
if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedCacheRegistrationState)
{
pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
}
if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedInstallRegistrationState)
{
pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
}
}
else if (BURN_DEPENDENCY_ACTION_UNREGISTER == pPackage->dependencyExecute)
{
if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedCacheRegistrationState)
{
pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
}
if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedInstallRegistrationState)
{
pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
}
}
}
}
LExit:
return hr;
}
static HRESULT PlanDependencyActions(
@ -3064,6 +3100,11 @@ static void ExecuteActionLog(
case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
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);
for (DWORD j = 0; j < pAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++j)
{
const BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pAction->msiPackage.pPackage->Msi.rgSlipstreamMsps + j;
LogStringLine(PlanDumpLevel, " Patch[%u]: msp package id: %ls, action: %hs", j, pSlipstreamMsp->pMspPackage->sczId, LoggingActionStateToString(fRollback ? pSlipstreamMsp->rollback : pSlipstreamMsp->execute));
}
break;
case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:

Просмотреть файл

@ -253,7 +253,6 @@ typedef struct _BURN_EXECUTE_ACTION
BOOTSTRAPPER_ACTION_STATE action;
BOOTSTRAPPER_FEATURE_ACTION* rgFeatures;
BOOTSTRAPPER_ACTION_STATE* rgSlipstreamPatches;
} msiPackage;
struct
{

Просмотреть файл

@ -760,7 +760,7 @@ namespace Bootstrapper
Assert::Equal(3ul, pEngineState->packages.cPackages);
ValidatePermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"NetFx48Web");
ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PatchA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PatchA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
}
[Fact]