MI_Result SetConfiguration()

in LCM/dsc/engine/ConfigurationManager/LocalConfigManagerHelper.c [1775:2062]


MI_Result SetConfiguration(
    _In_reads_bytes_(dataSize) const MI_Uint8* ConfigData,
    MI_Uint32 dataSize,
    MI_Boolean force,
    _In_ LCMProviderContext *lcmContext,
    MI_Uint32 dwFlags,
    _Outptr_result_maybenull_ MI_Instance **cimErrorDetails)
{
    MI_Result result = MI_RESULT_OK;
    MI_Result deleteResult = MI_RESULT_OK;
    ModuleManager *moduleManager = NULL;
    MSFT_DSCMetaConfiguration *metaConfigInstance = NULL;
    MI_Value value;
    MI_Uint32 flags;
    MI_Uint32 resultStatus = 0;
    MI_Char *partialConfigFileDataStoreLocation = NULL;

    //Debug Log 
    DSC_EventWriteLocalConfigMethodParameters(__WFUNCTION__,dataSize,dwFlags,lcmContext->executionMode);

    if (cimErrorDetails == NULL)
    {
        return MI_RESULT_INVALID_PARAMETER; 
    }

    *cimErrorDetails = NULL;    // Explicitly set *cimErrorDetails to NULL as _Outptr_ requires setting this at least once. 
    result = ValidateConfigurationDirectory(cimErrorDetails);
    if (result != MI_RESULT_OK)
    {   
        if (cimErrorDetails && *cimErrorDetails)
        {
            return result;
        }

        return GetCimMIError(result, cimErrorDetails, ID_LCMHELPER_VALIDATE_CONFGDIR_FAILED);
    }

    result = InitializeModuleManager(0, cimErrorDetails, &moduleManager);
    if (result != MI_RESULT_OK)
    {      
        return result;
    }

    if (moduleManager == NULL)
    {    
        return GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_ENGINEHELPER_MEMORY_ERROR);         
    }

    result = GetMetaConfig((MSFT_DSCMetaConfiguration **)&metaConfigInstance);
    if (result != MI_RESULT_OK)
    {
        moduleManager->ft->Close(moduleManager, NULL);
        return GetCimMIError(result, cimErrorDetails, ID_LCM_FAILED_TO_GET_METACONFIGURATION);
    }

    result = MI_Instance_GetElement((MI_Instance*)metaConfigInstance, MSFT_DSCMetaConfiguration_RefreshMode, &value, NULL, &flags, NULL);
    if (result != MI_RESULT_OK)
    {
        MI_Instance_Delete((MI_Instance *)metaConfigInstance);
        moduleManager->ft->Close(moduleManager, NULL);
        return GetCimMIError(result, cimErrorDetails, ID_LCM_FAILED_TO_GET_METACONFIGURATION);
    }

    if (flags & MI_FLAG_NULL)
    {
        value.string = METADATA_REFRESHMODE_PUSH;
    }

    if (Tcscasecmp(value.string , METADATA_REFRESHMODE_PULL) == 0)
    {
        /* Force converts the PULL to a PUSH otherwise PULL cannot convert to PUSH */
        if (force == MI_TRUE)
        {
            value.string = METADATA_REFRESHMODE_PUSH;
            result = MI_Instance_SetElement((MI_Instance*)metaConfigInstance,  MSFT_DSCMetaConfiguration_RefreshMode, &value, MI_STRING, 0);
            if (result != MI_RESULT_OK)
            {
                MI_Instance_Delete((MI_Instance *)metaConfigInstance);
                moduleManager->ft->Close(moduleManager, NULL);
                return result;
            }

            result = SetMetaConfig((MI_Instance*)metaConfigInstance, cimErrorDetails);
            if (result != MI_RESULT_OK)
            {
                MI_Instance_Delete((MI_Instance *)metaConfigInstance);
                moduleManager->ft->Close(moduleManager, NULL);
                return result;
            }
        }
        else
        {
            MI_Instance_Delete((MI_Instance *)metaConfigInstance);
            moduleManager->ft->Close(moduleManager, NULL);
            return GetCimMIError(MI_RESULT_INVALID_PARAMETER, cimErrorDetails, ID_LCM_PUSH_REQUESTED_ON_PULL_WO_FORCE);
        }
    }

    if (dwFlags & LCM_SET_METACONFIG)
    {
        MI_Instance_Delete((MI_Instance *)metaConfigInstance);
        result = SaveFile(GetMetaConfigTmpFileName(), ConfigData, dataSize, cimErrorDetails);
        if (result != MI_RESULT_OK)
        {
            moduleManager->ft->Close(moduleManager, NULL);
            if (cimErrorDetails && *cimErrorDetails)
            {
                return result;
            }

            return GetCimMIError(MI_RESULT_ALREADY_EXISTS, cimErrorDetails, ID_LCMHELPER_SAVE_METATMP_ERROR);
        }

        dwFlags |= VALIDATE_METACONFIG_INSTANCE;
        result = ApplyMetaConfig(lcmContext, moduleManager, dwFlags, &resultStatus, cimErrorDetails);
        moduleManager->ft->Close(moduleManager, NULL);
        deleteResult = RetryDeleteFile(GetMetaConfigTmpFileName());
        if (result != MI_RESULT_OK)
        {
            return result;
        }

        if (deleteResult != MI_RESULT_OK)
        {
            return GetCimMIError(deleteResult, cimErrorDetails, ID_LCMHELPER_DEL_METATMPFILEAFTER_FAILED);
        } 
    }
    else
    {
        //If there's a partial configuration in the metaconfig, do not save as pending, save in data store instead.
        if (ShouldUsePartialConfigurations((MI_Instance*)metaConfigInstance, MI_FALSE)) //Don't need to check if there are files in the partial config directory
        {
            //If it isn't a publishonly command, then this is not supported. Throw an error
            if (!(dwFlags & LCM_SETFLAGS_SAVETOPENDINGONLY))
            {
                result = GetCimMIError(MI_RESULT_NOT_SUPPORTED, cimErrorDetails, ID_LCM_CANNOTUSE_PARTIALCONFIG_PUSHMODE_WITHOUTPUBLISH);
                goto Cleanup;
            }
            DSC_EventWriteLCMIdentifiedModePartial();
            
            //Save the partial config file into the data store.
            result = GetPartialConfigStoreLocation(moduleManager, ConfigData, dataSize, cimErrorDetails, &partialConfigFileDataStoreLocation);
            GOTO_CLEANUP_IF_FAILED(result, Cleanup);
            //Store configFileName as path c:\windows\system32\configuration\partialconfigurations +_+ value.string + .mof
            result = CheckAndSaveConfigDataIntoFile(partialConfigFileDataStoreLocation, ConfigData, dataSize, MI_TRUE, cimErrorDetails, ID_LCMHELPER_OLDCONFPENDING_ERROR, ID_LCMHELPER_SAVE_PENDING_ERROR);
            //Note, you're passing force as true over here always because you want to delete the old existing partial configs no matter what. Check if this is okay , for now we go with this
            GOTO_CLEANUP_IF_FAILED(result, Cleanup);
            result = ValidatePartialConfiguration(moduleManager, partialConfigFileDataStoreLocation, (MI_Instance*) metaConfigInstance, cimErrorDetails);
            GOTO_CLEANUP_IF_FAILED(result, Cleanup);
            
            SetMessageInContext(ID_OUTPUT_OPERATION_END, ID_OUTPUT_ITEM_SET, lcmContext);
            LCM_BuildMessage(lcmContext, ID_LCM_WRITEMESSAGE_SAVETOPARTIAL, EMPTY_STRING, MI_WRITEMESSAGE_CHANNEL_VERBOSE);

Cleanup:
            
            moduleManager->ft->Close(moduleManager, NULL);
            //If there was a failure, ensure the partial config file(if exists) is deleted.
            if (result != MI_RESULT_OK && partialConfigFileDataStoreLocation != NULL)
            {
                RetryDeleteFile(partialConfigFileDataStoreLocation);
            }
            DSCFREE_IF_NOT_NULL(partialConfigFileDataStoreLocation);
        }
        else //Only in the case of no partial configuration should you save it in pending.mof and do pushdependency check.
        {
            // If Current.mof exists, move Current.mof to Previous.mof
            if (File_ExistT(GetCurrentConfigFileName()) == 0)
            {
                result = CopyConfigAndRemoveSource(CONFIGURATION_LOCATION_CURRENT, CONFIGURATION_LOCATION_PREVIOUS, cimErrorDetails);
                if (result != MI_RESULT_OK)
                {
                    MI_Instance_Delete((MI_Instance *)metaConfigInstance);            
                    moduleManager->ft->Close(moduleManager, NULL);
                    return result;
                }
            }

            // If Pending.mof exists, throw an error if Force was not specified
            if (File_ExistT(GetPendingConfigFileName()) != -1)
            {
                if (force == MI_TRUE)
                {
                    deleteResult = RetryDeleteFile(GetPendingConfigFileName());
                    if (deleteResult != MI_RESULT_OK)
                    {
                        MI_Instance_Delete((MI_Instance *)metaConfigInstance);            
                        moduleManager->ft->Close(moduleManager, NULL);
                        return GetCimMIError(deleteResult, cimErrorDetails, ID_LCMHELPER_OLDCONFPENDING_ERROR);
                    }
                }
                else
                {
                    MI_Instance_Delete((MI_Instance *)metaConfigInstance);            
                    moduleManager->ft->Close(moduleManager, NULL);
                    return GetCimMIError(MI_RESULT_ALREADY_EXISTS, cimErrorDetails, ID_LCMHELPER_OLDCONFPENDING_ERROR);
                }
            }
            
            // Save the new configuration to Pending.mof
            result = SaveFile(GetPendingConfigFileName(), ConfigData, dataSize, cimErrorDetails);
            if ( result != MI_RESULT_OK)
            {
                MI_Instance_Delete((MI_Instance *)metaConfigInstance);            
                moduleManager->ft->Close(moduleManager, NULL);
                if (cimErrorDetails && *cimErrorDetails)
                {
                    return result;
                }
                
                return GetCimMIError(MI_RESULT_ALREADY_EXISTS, cimErrorDetails, ID_LCMHELPER_SAVE_PENDING_ERROR);
            }
            
            if (dwFlags & LCM_SETFLAGS_SAVETOPENDINGONLY )
            {
                LCM_BuildMessage(lcmContext, ID_LCM_WRITEMESSAGE_SAVETOPENDING, EMPTY_STRING, MI_WRITEMESSAGE_CHANNEL_VERBOSE); 
                MI_Instance_Delete((MI_Instance *)metaConfigInstance);
                moduleManager->ft->Close(moduleManager, NULL);
                return MI_RESULT_OK;
            }
            
            result = ApplyPendingConfig(lcmContext, moduleManager, dwFlags, &resultStatus, cimErrorDetails);
            if (result != MI_RESULT_OK)
            {
                MI_Instance_Delete((MI_Instance *)metaConfigInstance);
                moduleManager->ft->Close(moduleManager, NULL);
                return result;
            }
            
            if (File_ExistT(g_MetaConfigFileName) == -1)
            {
                // If there is no meta config file, create the one which is default meta config, and creates new task.
                // The operation must be done before reboot operation to avoid possible incomplete update.
                result = SetMetaConfig((MI_Instance *)metaConfigInstance, cimErrorDetails);
                if (result != MI_RESULT_OK)
                {
                    MI_Instance_Delete((MI_Instance *)metaConfigInstance);
                    moduleManager->ft->Close(moduleManager, NULL);
                    return result;
                }
            }
            
            if (resultStatus & DSC_RESTART_SYSTEM_FLAG)
            {
                SetLCMStatusReboot();
            }
            
            MI_Instance_Delete((MI_Instance *)metaConfigInstance);
            moduleManager->ft->Close(moduleManager, NULL);
        }
    }
        
    DSC_EventWriteMethodEnd(__WFUNCTION__);
    if(overWroteUserSpecifiedRefreshFreqMins != NULL)
    {
        MI_Context* mi_context = (MI_Context*) lcmContext->context;
        Intlstr pTempStr = Intlstr_Null;
        GetResourceString1Param(ID_LCMHELPER_OVERWROTE_USER_SPECIFIED_REFRESH_FREQUENCY, overWroteUserSpecifiedRefreshFreqMins , &pTempStr);
#if defined(BUILD_OMS)
        DSC_LOG_WARNING("%s", pTempStr.str);
#else
        MI_Context_WriteWarning(mi_context, pTempStr.str);
#endif
        if(pTempStr.str)
        {
            Intlstr_Free(pTempStr);
        }
        overWroteUserSpecifiedRefreshFreqMins = NULL;
    }
    if (overWroteUserSpecifiedConfModeFreqMins != NULL)
    {
        MI_Context* mi_context = (MI_Context*) lcmContext->context;
        Intlstr pTempStr = Intlstr_Null;
        GetResourceString1Param(ID_LCMHELPER_OVERWROTE_USER_SPECIFIED_CONFMODE_FREQUENCY, overWroteUserSpecifiedConfModeFreqMins, &pTempStr);
#if defined(BUILD_OMS)
        DSC_LOG_WARNING("%s", pTempStr.str);
#else
        MI_Context_WriteWarning(mi_context, pTempStr.str);
#endif
        if (pTempStr.str)
        {
            Intlstr_Free(pTempStr);
        }
        overWroteUserSpecifiedConfModeFreqMins = NULL;
    }

    return result;

}