in LCM/dsc/engine/ConfigurationManager/LocalConfigManagerHelper.c [1179:1436]
MI_Result MergePartialConfigurations(_In_ LCMProviderContext *lcmContext,
_In_ ModuleManager* moduleManager,
_In_z_ const MI_Char* targetMofFile,
_In_z_ const MI_Char* targetBaseDocumentMergedFile,
_Outptr_result_maybenull_ MI_Instance** cimErrorDetails)
{
MI_Result result;
MI_Char *partialConfigDir = NULL;
MI_Instance* metaConfigInstance = NULL;
MI_Char* unexpandedPartialConfigFilePath = NULL;
MI_Char* partialConfigFilePath = NULL;
MI_Char* checksumFile = NULL;
MI_InstanceA resourceInstanceArray = { 0 };
Internal_Dir *dirHandle = NULL;
MI_Application application = MI_APPLICATION_NULL;
MI_Boolean applicationInited = MI_FALSE;
MI_Serializer serializer = { 0 };
MI_Value value;
MI_Boolean errorOccured = MI_FALSE;
MI_Boolean serializerInited = MI_FALSE;
MI_Boolean isLocked = MI_FALSE;
MI_Boolean newBaseDocumentIsPlaced = MI_FALSE; //Bool value marked to true if we added our new base doc instance
Internal_DirEnt *dirEntry = NULL;
MI_Instance * baseDocumentInstance = NULL;
MI_Uint32 resultStatus = 0;
/****************************** INITIALIZE EVERYTHING *******************************************/
if (cimErrorDetails == NULL || targetMofFile == NULL || targetBaseDocumentMergedFile == NULL || moduleManager == NULL)
{
return MI_RESULT_INVALID_PARAMETER;
}
*cimErrorDetails = NULL;
result = LoadModuleManager(moduleManager, cimErrorDetails);
RETURN_RESULT_IF_FAILED(result);
result = ExpandPath(CONFIGURATION_PARTIALCONFIG_STORE, &partialConfigDir, cimErrorDetails);
RETURN_RESULT_IF_FAILED(result);
if (File_ExistT(GetPendingConfigFileName()) != -1)
{
File_RemoveT(GetPendingConfigFileName());
}
if (File_ExistT(GetPartialConfigBaseDocumentInstanceFileName()) != -1)
{
File_RemoveT(GetPartialConfigBaseDocumentInstanceFileName());
}
result = MI_Application_Initialize(0, NULL, NULL, &application);
GOTO_CLEANUP_AND_THROW_ERROR_IF_FAILED(result, result, ID_LCMHELPER_ERRORMERGING_PARTIALCONFIGS, cimErrorDetails, Exit)
applicationInited = MI_TRUE;
result = MI_Application_NewSerializer_Mof(&application, 0, MOFCODEC_FORMAT, &serializer);
GOTO_CLEANUP_AND_THROW_ERROR_IF_FAILED(result, result, ID_LCMHELPER_ERRORMERGING_PARTIALCONFIGS, cimErrorDetails, Exit)
serializerInited = MI_TRUE;
//We know the directory exists for sure here so no need for checking for that.
//Open directory and check for the first obtained file
dirHandle = Internal_Dir_Open(partialConfigDir, NitsMakeCallSite(-3, NULL, NULL, 0));
if (dirHandle == NULL || NitsShouldFault(NitsHere(), NitsAutomatic))
{
result = GetCimMIError(MI_RESULT_FAILED, cimErrorDetails, ID_MODMAN_FINDFIRST_FAILED);
goto Exit;
}
dirEntry = Internal_Dir_Read(dirHandle, MOF_EXTENSION);
//From now on until pending.mof is fully done, lock everything
RecursiveLock_Acquire(&gExecutionLock);
isLocked = MI_TRUE;
result = GetMetaConfig((MSFT_DSCMetaConfiguration **) &metaConfigInstance);
GOTO_CLEANUP_IF_FAILED(result, Exit);
DSC_EventWriteLCMAboutToMergePartial();
/****************************** LOGIC TO DESERIALIZE AND SERIALIZEs *******************************************/
//For each file that is obtained, merge it up into the new pending.mof
while (dirEntry != NULL)
{
/* Only process files*/
if (!dirEntry->isDir)
{
//Concatenate directory and filename
result = GetFullPath(partialConfigDir, dirEntry->name, &unexpandedPartialConfigFilePath, cimErrorDetails);
GOTO_CLEANUP_IF_FAILED(result, Exit);
result = ExpandPath(unexpandedPartialConfigFilePath, &partialConfigFilePath, cimErrorDetails);
DSC_free(unexpandedPartialConfigFilePath);
GOTO_CLEANUP_IF_FAILED(result, Exit);
//Validate the configuration - if its correctly placed - sometimes it could have been published first , n then run another set, and you still need to validate, if not valid, silently delete
result = ValidatePartialConfiguration(moduleManager, partialConfigFilePath, metaConfigInstance, cimErrorDetails);
if (result != MI_RESULT_OK)
{
if (*cimErrorDetails)
{//Output the warning with any possible underlying error that came with the above function calls
DSC_WriteWarningFromError1Param((MI_Context*) lcmContext->context, cimErrorDetails, ID_LCM_PARTIALCONFIG_DELETINGFILE_WARNING, partialConfigFilePath);
INSTANCE_DELETE_IF_NOT_NULL(*cimErrorDetails);
}
File_RemoveT(partialConfigFilePath); //Delete the file since its irrelevant
ConcatStrings(&checksumFile, 0, partialConfigFilePath, CHECKSUM_EXTENSION);
File_RemoveT(checksumFile); //Delete the corresponding checksum file as well
dirEntry = Internal_Dir_Read(dirHandle, MOF_EXTENSION);
DSCFREE_IF_NOT_NULL(partialConfigFilePath);
DSCFREE_IF_NOT_NULL(checksumFile);
result = MI_RESULT_OK;
errorOccured = MI_TRUE;
continue; //Carry on to the next file
}
//Check if the required modules are present
/*
result = DoPushDependencyCheck((MI_Char*) partialConfigFilePath, cimErrorDetails);
if (result == MI_RESULT_OK)
{
result = moduleManager->ft->LoadInstanceDocumentFromLocation(moduleManager, VALIDATE_DOCUMENT_INSTANCE, partialConfigFilePath, cimErrorDetails, &resourceInstanceArray, &baseDocumentInstance);
}
*/
result = moduleManager->ft->LoadInstanceDocumentFromLocation(moduleManager, VALIDATE_DOCUMENT_INSTANCE, partialConfigFilePath, cimErrorDetails, &resourceInstanceArray, &baseDocumentInstance);
//If any of the above operations failed, just skip the file and continue to the next one - give them a warning that you're doing this
if (result != MI_RESULT_OK)
{
if (*cimErrorDetails)
{ //Output the warning with any possible underlying error that came with the above function calls
DSC_WriteWarningFromError1Param((MI_Context*) lcmContext->context, cimErrorDetails, ID_LCM_PARTIALCONFIG_SKIPFILE_WARNING, partialConfigFilePath);
INSTANCE_DELETE_IF_NOT_NULL(*cimErrorDetails);
}
dirEntry = Internal_Dir_Read(dirHandle, MOF_EXTENSION);
DSCFREE_IF_NOT_NULL(partialConfigFilePath);
result = MI_RESULT_OK;
errorOccured = MI_TRUE;
continue; //Carry on to the next file
}
//Get the partial configuration name from the document
result = DSC_MI_Instance_GetElement(baseDocumentInstance, OMI_ConfigurationDocument_Name, &value, NULL, NULL, NULL);
GOTO_CLEANUP_IF_FAILED(result, Exit);
DSC_EventWriteLCMMergingPartialConfiguration(value.string);
//For now its just a simple merge, put all of these deserialized stuff into another file and we'll be done, yay!
result = SerializeInstanceArrayToFile(&resourceInstanceArray, GetPendingConfigFileName(), cimErrorDetails, MI_T("ab"), MI_FALSE, &serializer);
GOTO_CLEANUP_IF_FAILED(result, Exit);
//Free the path for the partial config, to rellocate for the next one.
DSCFREE_IF_NOT_NULL(partialConfigFilePath);
result = SerializeSingleInstanceToFile(baseDocumentInstance, GetPartialConfigBaseDocumentInstanceFileName(), cimErrorDetails, MI_T("ab"), MI_FALSE, &serializer);
GOTO_CLEANUP_IF_FAILED(result, Exit);
//Set in the unique base document - happens one time only
if (!newBaseDocumentIsPlaced)
{
value.string = OMI_ConfigurationDocument_PartialConfigAuthor;
result = MI_Instance_SetElement(baseDocumentInstance, OMI_ConfigurationDocument_Author, &value, MI_STRING, 0);
GOTO_CLEANUP_IF_FAILED(result, Exit);
value.string = OMI_ConfigurationDocument_PartialConfigName;
result = MI_Instance_SetElement(baseDocumentInstance, OMI_ConfigurationDocument_Name, &value, MI_STRING, 0);
GOTO_CLEANUP_IF_FAILED(result, Exit);
result = SerializeSingleInstanceToFile(baseDocumentInstance, GetPendingConfigFileName(), cimErrorDetails, MI_T("ab"), MI_FALSE, &serializer);
GOTO_CLEANUP_IF_FAILED(result, Exit);
newBaseDocumentIsPlaced = MI_TRUE;
}
//We can't have multiple base document instances, so remove them from each (we'll add one at the end)
INSTANCE_DELETE_IF_NOT_NULL(baseDocumentInstance);
CleanUpInstanceCache(&resourceInstanceArray); //To clear old file's data
}
dirEntry = Internal_Dir_Read(dirHandle, MOF_EXTENSION);
}//End of recursing directory files
//Now check if the merged file is valid
if (File_ExistT(GetPartialConfigBaseDocumentInstanceFileName()) != -1)
{
result = ValidatePartialConfigMergedFile(moduleManager, GetPendingConfigFileName(), cimErrorDetails);
}
else
{
if (errorOccured)
{
//This means there was an error and hence partial configurations couldn't be merged
result = GetCimMIError(MI_RESULT_NOT_FOUND, cimErrorDetails, ID_PARTIALCONFIG_FAILEDPARTIALCONFIGS);
}
else
{
//That means there was no partial config file found that was valid, so throw error
result = GetCimMIError(MI_RESULT_NOT_FOUND, cimErrorDetails, ID_PARTIALCONFIG_NOPARTIALCONFIGPRESENT);
}
}
GOTO_CLEANUP_IF_FAILED(result, Exit);
// we have a basic merged pending mof file, We will doing filtering to remove the ones that dependsOn is not satisfied
result = moduleManager->ft->LoadInstanceDocumentFromLocation(moduleManager, 0, GetPendingConfigFileName(), cimErrorDetails, &resourceInstanceArray, &baseDocumentInstance);
GOTO_CLEANUP_IF_FAILED(result, Exit);
// clean up the temp file so the filtered configuration will be saved there
if (File_ExistT(GetPendingConfigTmpFileName()) != -1)
{
File_RemoveT(GetPendingConfigTmpFileName());
}
if (File_ExistT(GetPartialConfigBaseDocumentInstanceTmpFileName()) != -1)
{
File_RemoveT(GetPartialConfigBaseDocumentInstanceTmpFileName());
}
lcmContext->serializer = &serializer;
result = ProcessPartialConfigurations(lcmContext, moduleManager, 0, &resultStatus, FilterPartialConfigurations, metaConfigInstance, &resourceInstanceArray, cimErrorDetails);
GOTO_CLEANUP_IF_FAILED(result, Exit);
result = SerializeSingleInstanceToFile(baseDocumentInstance, GetPendingConfigTmpFileName(), cimErrorDetails, MI_T("ab"), MI_FALSE, &serializer);
GOTO_CLEANUP_IF_FAILED(result, Exit);
if (File_ExistT(GetPendingConfigFileName()) != -1)
{
File_RemoveT(GetPendingConfigFileName());
}
if (File_ExistT(GetPartialConfigBaseDocumentInstanceFileName()) != -1)
{
File_RemoveT(GetPartialConfigBaseDocumentInstanceFileName());
}
// If Current.mof exists, move Current.mof to Previous.mof
if (File_ExistT(GetCurrentConfigFileName()) == 0)
{
result = CopyConfigAndRemoveSource(CONFIGURATION_LOCATION_CURRENT, CONFIGURATION_LOCATION_PREVIOUS, cimErrorDetails);
GOTO_CLEANUP_IF_FAILED(result, Exit);
}
File_CopyT(GetPendingConfigTmpFileName(), GetPendingConfigFileName());
File_CopyT(GetPartialConfigBaseDocumentInstanceTmpFileName(), GetPartialConfigBaseDocumentInstanceFileName());
/****************************** CLEANUIP AND RETURN *******************************************/
Exit:
DSCFREE_IF_NOT_NULL(partialConfigFilePath);
DSCFREE_IF_NOT_NULL(partialConfigDir);
INSTANCE_DELETE_IF_NOT_NULL(baseDocumentInstance);
INSTANCE_DELETE_IF_NOT_NULL(metaConfigInstance);
//Note: No need to clean partialConfigInstance variable as it points to a part of metaconfiguration
if (resourceInstanceArray.data != NULL)
{
CleanUpInstanceCache(&resourceInstanceArray);
}
if (serializerInited)
{
MI_Serializer_Close(&serializer);
serializerInited = MI_FALSE;
}
if (applicationInited)
{
MI_Application_Close(&application);
applicationInited = MI_FALSE;
}
if (isLocked)
{
RecursiveLock_Release(&gExecutionLock);
isLocked = MI_FALSE;
}
if (dirHandle != NULL)
Internal_Dir_Close(dirHandle);
return result;
}