in src/extensions/update_manifest_handlers/steps_handler/src/steps_handler.cpp [499:690]
static ADUC_Result StepsHandler_Download(const tagADUC_WorkflowData* workflowData)
{
ADUC_Result result;
result.ResultCode = ADUC_Result_Failure;
result.ExtendedResultCode = 0;
ADUC_WorkflowHandle handle = workflowData->WorkflowHandle;
ADUC_WorkflowHandle stepHandle = nullptr;
char* workFolder = workflow_get_workfolder(handle);
JSON_Array* selectedComponentsArray = nullptr;
int workflowLevel = workflow_get_level(handle);
int workflowStep = workflow_get_step_index(handle);
int selectedComponentsCount = 0;
char* serializedComponentString = nullptr;
bool isComponentsEnumeratorRegistered = ExtensionManager::IsComponentsEnumeratorRegistered();
int createResult = 0;
if (workflow_is_cancel_requested(handle))
{
result.ResultCode = ADUC_Result_Failure_Cancelled;
result.ExtendedResultCode = 0;
goto done;
}
Log_Debug(
"\n#\n#Download task begin (level: %d, step:%d, wfid:%s, h_addr:0x%x).",
workflowLevel,
workflowStep,
workflow_peek_id(handle),
handle);
createResult = ADUC_SystemUtils_MkSandboxDirRecursive(workFolder);
if (createResult != 0)
{
Log_Error("Unable to create folder %s, error %d", workFolder, createResult);
result = { ADUC_Result_Failure, ADUC_ERC_STEPS_HANDLER_CREATE_SANDBOX_FAILURE };
goto done;
}
result = PrepareStepsWorkflowDataObject(handle);
if (IsAducResultCodeFailure(result.ResultCode))
{
workflow_set_result_details(handle, "Invalid steps workflow collection");
goto done;
}
result = HandleComponents(
workflowLevel,
workflowStep,
isComponentsEnumeratorRegistered,
handle,
selectedComponentsArray,
&selectedComponentsCount);
if (IsAducResultCodeFailure(result.ResultCode))
{
goto done;
}
// For each selected component, perform step's backup, install & apply phase, restore phase if needed, in order.
for (size_t iCom = 0, stepsCount = workflow_get_children_count(handle); iCom < selectedComponentsCount; iCom++)
{
serializedComponentString = CreateComponentSerializedString(selectedComponentsArray, iCom);
//
// For each step (child workflow), invoke backup, install and apply actions.
// if install or apply fails, invoke restore action.
//
for (size_t i = 0; i < stepsCount; i++)
{
if (IsStepsHandlerExtraDebugLogsEnabled())
{
Log_Debug(
"Perform download action of child step #%lu on component #%d.\n#### Component ####\n%s\n###################\n",
i,
iCom,
serializedComponentString);
}
// Use a wrapper workflow to hold a stepHandle.
ADUC_WorkflowData stepWorkflow = {};
stepHandle = workflow_get_child(handle, i);
if (stepHandle == nullptr)
{
const char* errorFmt = "Cannot process step #%lu due to missing (child) workflow data.";
Log_Error(errorFmt, i);
result.ExtendedResultCode = ADUC_ERC_STEPS_HANDLER_DOWNLOAD_FAILURE_MISSING_CHILD_WORKFLOW;
workflow_set_result_details(handle, errorFmt, i);
goto done;
}
stepWorkflow.WorkflowHandle = stepHandle;
// For inline step - set current component info on the workflow.
if (serializedComponentString != nullptr && workflow_is_inline_step(handle, i))
{
if (!workflow_set_selected_components(stepHandle, serializedComponentString))
{
result.ResultCode = ADUC_Result_Failure;
result.ExtendedResultCode = ADUC_ERC_STEPS_HANDLER_SET_SELECTED_COMPONENTS_FAILURE;
workflow_set_result_details(handle, "Cannot select target component(s) for step #%lu", i);
goto done;
}
}
ContentHandler* contentHandler = nullptr;
const char* stepUpdateType = workflow_is_inline_step(handle, i)
? workflow_peek_update_manifest_step_handler(handle, i)
: DEFAULT_REF_STEP_HANDLER;
Log_Info("Loading handler for step #%lu (handler: '%s')", i, stepUpdateType);
result = ExtensionManager::LoadUpdateContentHandlerExtension(stepUpdateType, &contentHandler);
if (IsAducResultCodeFailure(result.ResultCode))
{
const char* errorFmt = "Cannot load a handler for step #%lu (handler :%s)";
Log_Error(errorFmt, i, stepUpdateType);
workflow_set_result(stepHandle, result);
workflow_set_result_details(handle, errorFmt, i, stepUpdateType == nullptr ? "NULL" : stepUpdateType);
goto done;
}
ADUC_ExtensionContractInfo contractInfo = contentHandler->GetContractInfo();
if (ADUC_ContractUtils_IsV1Contract(&contractInfo))
{
result = DoV1DownloadWork(&stepWorkflow, contentHandler, handle, stepHandle);
if (IsAducResultCodeFailure(result.ResultCode))
{
goto done;
}
if (result.ResultCode == ADUC_Result_Install_Skipped_UpdateAlreadyInstalled)
{
goto instanceDone;
}
}
else
{
result = handleUnsupportedContractVersion(&contractInfo, stepUpdateType, handle);
goto done;
}
instanceDone:
stepHandle = nullptr;
if (IsAducResultCodeFailure(result.ResultCode))
{
goto componentDone;
}
} // instances loop
componentDone:
json_free_serialized_string(serializedComponentString);
serializedComponentString = nullptr;
if (IsAducResultCodeFailure(result.ResultCode))
{
goto done;
}
// Set step's result.
}
result.ResultCode = ADUC_Result_Download_Success;
result.ExtendedResultCode = 0;
done:
// NOTE: Do not free child workflow here, so that it can be reused in the next phase.
// Only free child handle when the workflow is done.
//
// Alternatively, we can persist child workflow state, to free up some memory, and
// load the state when needed in the next phase
workflow_set_result(handle, result);
if (IsAducResultCodeSuccess(result.ResultCode))
{
workflow_set_state(handle, ADUCITF_State_DownloadSucceeded);
}
else
{
workflow_set_state(handle, ADUCITF_State_Failed);
}
json_free_serialized_string(serializedComponentString);
workflow_free_string(workFolder);
Log_Debug("Steps_Handler Download end (level %d).", workflowLevel);
return result;
}