Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2636 lines
93 KiB

/*++
Copyright (C) 2000-2002 Microsoft Corporation
--*/
#include "precomp.h"
#include <wbemidl.h>
#include <wbemint.h>
#include <stdio.h>
#include <wbemcomn.h>
#include <ql.h>
#include <time.h>
#include "a51rep.h"
#include <md5.h>
#include <objpath.h>
#include "a51tools.h"
#include "corex.h"
#include <persistcfg.h>
#include "upgrade.h"
extern DWORD g_dwSecTlsIndex;
//=====================================================================
//
// CLocalizationUpgrade::CLocalizationUpgrade
//
// Description:
//
// Parameters:
// pContol Life Control
// pRepository Pointer to repository pointer
//=====================================================================
CLocalizationUpgrade::CLocalizationUpgrade(CLifeControl* pControl, CRepository * pRepository)
: m_pControl(pControl), m_pRepository(pRepository)
{
}
//=====================================================================
//
// CLocalizationUpgrade::~CLocalizationUpgrade
//
// Description:
//
// Parameters:
//
//=====================================================================
CLocalizationUpgrade::~CLocalizationUpgrade()
{
}
//=====================================================================
//
// CLocalizationUpgrade::DoUpgrade
//
// Description:
// Control routing to bootstrap the upgrade process. If the registry key
// already exists then it does nothing.
//
// Parameters:
//
//=====================================================================
HRESULT CLocalizationUpgrade::DoUpgrade()
{
HRESULT hRes = 0;
//Check to make sure we even need to do the upgrade!
HKEY hKey;
LONG lRes;
bool bDoUpgrade = false;
//Get the current database version
DWORD dwVal = 0;
CDbVerRead cfg;
cfg.TidyUp();
cfg.ReadDbVer(dwVal);
if (dwVal != 6)
return WBEM_NO_ERROR;
try
{
hRes = OldHash(L"__namespace", m_namespaceClassHash);
if (FAILED(hRes))
return hRes;
hRes = OldHash(L"", m_emptyClassHash);
if (FAILED(hRes))
return hRes;
hRes = OldHash(A51_SYSTEMCLASS_NS, m_systemNamespaceHash);
if (FAILED(hRes))
return hRes;
//Reset a TLS entry if necessary! Otherwise we may not find any
//instances of __thisNamespace!
LPVOID pOldTlsEntry = NULL;
if (g_dwSecTlsIndex != -1)
{
pOldTlsEntry = TlsGetValue(g_dwSecTlsIndex);
TlsSetValue(g_dwSecTlsIndex, 0);
}
//Set the Class Cache size to 0 bytes so it does not
//cache anything during this process. if it did, we
//would get kind of screwed up really badly!
g_Glob.m_ForestCache.SetMaxMemory(0, 10000);
CAutoWriteLock lock(&g_readWriteLock);
if (lock.Lock())
{
lRes = g_Glob.m_FileCache.BeginTransaction();
if (lRes)
hRes = A51TranslateErrorCode(lRes);
if (SUCCEEDED(hRes))
{
m_pass = 1;
DEBUGTRACE((LOG_REPDRV, "============== LOCALE UPGRADE : Enumerate Child Namespaces =============\n"));
//1 Enumeration all namespaces
//Deals with class enumeration, and deletion if there is a conflict,
//and enumerates all the instances in the namespace checking both types
//of hashes and recording differences
hRes = EnumerateChildNamespaces(L"root");
//1 Don't do anything unless we have something to do!
if (m_keyHash.Size() ||m_pathHash.Size())
{
//1 Process namespace collisions
if (SUCCEEDED(hRes))
{
m_pass = 2;
DEBUGTRACE((LOG_REPDRV, "============== LOCALE UPGRADE : Namespace Collision Detection =============\n"));
hRes = ProcessNamespaceCollisions();
}
if (SUCCEEDED(hRes))
{
m_pass = 3;
DEBUGTRACE((LOG_REPDRV, "============== LOCALE UPGRADE: Fixup BTree Changes =============\n"));
//1 Phase 3 - fixup changed hashes
//Iterate through the entire BTree and fix-up all failures
hRes = FixupBTree();
}
}
else
{
ERRORTRACE((LOG_REPDRV, "============== LOCALE UPGRADE : No Changes Needed! =============\n"));
}
}
if (SUCCEEDED(hRes))
{
ERRORTRACE((LOG_REPDRV, "============== LOCALE UPGRADE: Committing Changes =============\n"));
g_Glob.m_FileCache.CommitTransaction();
}
else
{
ERRORTRACE((LOG_REPDRV, "============== LOCALE UPGRADE: Rolling back all Changes =============\n"));
g_Glob.m_FileCache.AbortTransaction();
}
//Regardless of the error code, the class cache is probably totally screwed
//up, so we need to do dramatic stuff to it!
//This will also reset the class cache to it's default sizes!
g_Glob.m_ForestCache.Deinitialize();
g_Glob.m_ForestCache.Initialize();
}
if (g_dwSecTlsIndex != -1)
{
TlsSetValue(g_dwSecTlsIndex, pOldTlsEntry);
}
if (SUCCEEDED(hRes))
{
ERRORTRACE((LOG_REPDRV, "============== LOCALE UPGRADE: Fixup SUCCEEDED =============\n"));
}
else
{
ERRORTRACE((LOG_REPDRV, "============== LOCALE UPGRADE: Fixup FAILED =============\n"));
}
}
catch (...)
{
g_Glob.m_FileCache.AbortTransaction();
ERRORTRACE((LOG_REPDRV, "============== LOCALE UPGRADE: Something threw an exception =============\n"));
}
CPersistentConfig pCfg;
pCfg.SetPersistentCfgValue(PERSIST_CFGVAL_CORE_FSREP_VERSION, A51_REP_FS_VERSION);
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::EnumerateChildNamespaces
//
// Description:
// Enumerates all child namespaces of the namespace passed, adds
// the namespaces to the m_namespaces structure, and iterates down
// into those namespaces
//
// Parameters:
// wsRootNamespace Namespace name to enumerate. E.G. root\default
//
//=====================================================================
HRESULT CLocalizationUpgrade::EnumerateChildNamespaces(const wchar_t * wsRootNamespace)
{
//We know the namespace we need to look under, we know the class key root, so we
//can enumerate all the instances of that class and do a FileToInstance on them all. From
//that we can add the event and the entry to the namespace list, and do the enumeration
//of child namespaces on them
LONG lRes = 0;
HRESULT hRes = 0;
CFileName wsNamespaceHash;
if (wsNamespaceHash == NULL)
return WBEM_E_OUT_OF_MEMORY;
wchar_t *wszNewNamespaceHash = new wchar_t[MAX_HASH_LEN+1];
if (wszNewNamespaceHash == NULL)
return WBEM_E_OUT_OF_MEMORY;
CVectorDeleteMe<wchar_t> vdm(wszNewNamespaceHash);
hRes = NewHash(wsRootNamespace, wszNewNamespaceHash);
if (FAILED(hRes))
return hRes;
//Create the hashed path to the Key Root for the namespace
StringCchCopyW(wsNamespaceHash, MAX_PATH, g_Glob.GetRootDir());
StringCchCatW(wsNamespaceHash, MAX_PATH, L"\\NS_");
hRes = OldHash(wsRootNamespace, wsNamespaceHash + g_Glob.GetRootDirLen()+4);
if (FAILED(hRes))
return hRes;
hRes = IndexExists(wsNamespaceHash);
if (hRes == WBEM_E_NOT_FOUND)
{
//Try using NewHash instead!
hRes = NewHash(wsRootNamespace, wsNamespaceHash + g_Glob.GetRootDirLen()+4);
if (FAILED(hRes))
return hRes;
hRes = IndexExists(wsNamespaceHash);
if (hRes == WBEM_E_NOT_FOUND)
return WBEM_NO_ERROR; //NOthing in this namespace!
else if (FAILED(hRes))
return hRes;
}
else if (FAILED(hRes))
return hRes;
DEBUGTRACE((LOG_REPDRV, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"));
DEBUGTRACE((LOG_REPDRV, "Processing namespace: %S, %S\n", wsRootNamespace, wsNamespaceHash+g_Glob.GetRootDirLen()+1));
//2 Store namespace path for pass 2 of update
hRes = m_namespaces.AddStrings(wsRootNamespace, wsNamespaceHash);
if (FAILED(hRes))
return hRes;
//2 Create a CNamespaceHandle so we can access objects in this namespace
CNamespaceHandle *pNs = new CNamespaceHandle(m_pControl, m_pRepository);
if (pNs == NULL)
return WBEM_E_OUT_OF_MEMORY;
CDeleteMe<CNamespaceHandle> cdm(pNs);
hRes = pNs->Initialize2(wsRootNamespace, wsNamespaceHash+g_Glob.GetRootDirLen()+4);
if (FAILED(hRes))
return hRes;
//2 Fixup all the classes in this namespace
//NOTE: We need to do this BEFORE we process the hash for the namespace
//because otherwise it will be stored in a different place and so
//instance enumeration will fail!
hRes = ProcessSystemClassesRecursively(pNs,
wsNamespaceHash+g_Glob.GetRootDirLen()+4,
m_emptyClassHash);
if (FAILED(hRes))
return hRes;
hRes = ProcessClassesRecursively(pNs,
wsNamespaceHash+g_Glob.GetRootDirLen()+4,
m_emptyClassHash);
if (FAILED(hRes))
return hRes;
hRes = EnumerateInstances(pNs, wszNewNamespaceHash);
if (FAILED(hRes))
return hRes;
StringCchCatW(wsNamespaceHash, MAX_PATH, L"\\" A51_KEYROOTINST_DIR_PREFIX);
StringCchCatW(wsNamespaceHash, MAX_PATH, m_namespaceClassHash);
StringCchCatW(wsNamespaceHash, MAX_PATH, L"\\" A51_INSTDEF_FILE_PREFIX);
//2 Process Hash for this namespace
bool bDifferent = false;
hRes = ProcessHash(wsRootNamespace, &bDifferent);
if (FAILED(hRes))
return hRes;
//2 Enumerate all the child namespaces
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.ObjectEnumerationBegin(wsNamespaceHash, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
BYTE *pBlob = NULL;
DWORD dwSize = 0;
while(1)
{
lRes = g_Glob.m_FileCache.ObjectEnumerationNext(pEnumHandle, wsNamespaceHash, &pBlob, &dwSize);
if (lRes == ERROR_NO_MORE_FILES)
{
lRes = ERROR_SUCCESS;
break;
}
else if (lRes)
break;
//Get the instance
_IWmiObject* pInstance = NULL;
hRes = pNs->FileToInstance(NULL, wsNamespaceHash, pBlob, dwSize, &pInstance, true);
//Free the blob
g_Glob.m_FileCache.ObjectEnumerationFree(pEnumHandle, pBlob);
if (FAILED(hRes))
break;
CReleaseMe rm2(pInstance);
//Extract the string from the object
VARIANT vName;
VariantInit(&vName);
CClearMe cm(&vName);
hRes = pInstance->Get(L"Name", 0, &vName, NULL, NULL);
if(FAILED(hRes))
break;
if(V_VT(&vName) != VT_BSTR)
{
hRes = WBEM_E_INVALID_OBJECT;
break;
}
//Create the full namespace path
wchar_t *wszChildNamespacePath = new wchar_t[wcslen(wsRootNamespace)+1+wcslen(V_BSTR(&vName)) + 1];
if (wszChildNamespacePath == NULL)
{
hRes = WBEM_E_OUT_OF_MEMORY;
break;
}
CVectorDeleteMe<wchar_t> vdm(wszChildNamespacePath);
StringCchCopyW(wszChildNamespacePath, MAX_PATH, wsRootNamespace);
StringCchCatW(wszChildNamespacePath, MAX_PATH, L"\\");
StringCchCatW(wszChildNamespacePath, MAX_PATH, V_BSTR(&vName));
//2 Process all child namespaces in this namespace
hRes = EnumerateChildNamespaces(wszChildNamespacePath);
if (FAILED(hRes))
break;
}
g_Glob.m_FileCache.ObjectEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
}
if (lRes)
hRes = A51TranslateErrorCode(lRes);
return hRes;
}
HRESULT CLocalizationUpgrade::ProcessSystemClassesRecursively(CNamespaceHandle *pNs,
const wchar_t *namespaceHash,
const wchar_t *parentClassHash)
{
HRESULT hRes= 0;
unsigned long lRes = 0;
CFileName wszChildClasses;
if (wszChildClasses == NULL)
return WBEM_E_OUT_OF_MEMORY;
wchar_t *childClassHash = new wchar_t[MAX_HASH_LEN+1];
if (childClassHash == NULL)
return WBEM_E_OUT_OF_MEMORY;
CVectorDeleteMe<wchar_t> vdm(childClassHash);
//Create full class reference path for parent/class relationship
StringCchCopyW(wszChildClasses, wszChildClasses.Length(), g_Glob.GetRootDir());
StringCchCatW(wszChildClasses, wszChildClasses.Length(), L"\\NS_");
StringCchCatW(wszChildClasses, wszChildClasses.Length(), m_systemNamespaceHash);
StringCchCatW(wszChildClasses, wszChildClasses.Length(), L"\\CR_");
StringCchCatW(wszChildClasses, wszChildClasses.Length(), parentClassHash);
StringCchCatW(wszChildClasses, wszChildClasses.Length(), L"\\C_");
//Enumerate the child classes
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.IndexEnumerationBegin(wszChildClasses, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
while(1)
{
lRes = g_Glob.m_FileCache.IndexEnumerationNext(pEnumHandle, wszChildClasses, true);
if (lRes == ERROR_NO_MORE_FILES)
{
hRes = ERROR_SUCCESS;
break;
}
else if (lRes)
{
hRes = A51TranslateErrorCode(lRes);
break;
}
//extract the class hash
StringCchCopyW(childClassHash, MAX_HASH_LEN+1, wszChildClasses + wcslen(wszChildClasses)-32);
//Process user derived classes from this system class
hRes = ProcessClassesRecursively(pNs, namespaceHash, childClassHash);
if (FAILED(hRes))
break;
//Process other system classes that are derived from this class
hRes = ProcessSystemClassesRecursively(pNs, namespaceHash, childClassHash);
if (FAILED(hRes))
break;
}
g_Glob.m_FileCache.IndexEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
if (lRes)
hRes = A51TranslateErrorCode(lRes);
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::ProcessClassesRecursively
//
// Description:
// Recursively enumerates all the classes from the one specified
// and fixes it up as necessary
//
// Parameters:
// classIndex full path to a class definition
//
//=====================================================================
HRESULT CLocalizationUpgrade::ProcessClassesRecursively(CNamespaceHandle *pNs,
const wchar_t *namespaceHash,
const wchar_t *parentClassHash)
{
HRESULT hRes= 0;
unsigned long lRes = 0;
CFileName wszChildClasses;
if (wszChildClasses == NULL)
return WBEM_E_OUT_OF_MEMORY;
wchar_t *childClassHash = new wchar_t[MAX_HASH_LEN+1];
if (childClassHash == NULL)
return WBEM_E_OUT_OF_MEMORY;
CVectorDeleteMe<wchar_t> vdm(childClassHash);
//Create full class reference path for parent/class relationship
StringCchCopyW(wszChildClasses, wszChildClasses.Length(), g_Glob.GetRootDir());
StringCchCatW(wszChildClasses, wszChildClasses.Length(), L"\\NS_");
StringCchCatW(wszChildClasses, wszChildClasses.Length(), namespaceHash);
StringCchCatW(wszChildClasses, wszChildClasses.Length(), L"\\CR_");
StringCchCatW(wszChildClasses, wszChildClasses.Length(), parentClassHash);
StringCchCatW(wszChildClasses, wszChildClasses.Length(), L"\\C_");
//Enumerate the child classes
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.IndexEnumerationBegin(wszChildClasses, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
while(1)
{
lRes = g_Glob.m_FileCache.IndexEnumerationNext(pEnumHandle, wszChildClasses, true);
if (lRes == ERROR_NO_MORE_FILES)
{
hRes = ERROR_SUCCESS;
break;
}
else if (lRes)
{
hRes = A51TranslateErrorCode(lRes);
break;
}
//extract the class hash
StringCchCopyW(childClassHash, MAX_HASH_LEN+1, wszChildClasses + wcslen(wszChildClasses)-32);
//Process this class - this class calls back into this class to do the recursion!
hRes = ProcessClass(pNs, namespaceHash, parentClassHash, childClassHash);
if (FAILED(hRes))
break;
}
g_Glob.m_FileCache.IndexEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
if (lRes)
hRes = A51TranslateErrorCode(lRes);
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::ProcessClass
//
// Description:
// retrieves the class, calculates new and old class hash, and
// if they are different fixes up the CD hash, child class hashes
// and the parent class hash to this one
//
// Parameters:
// namespaceHash namespace hash
// parentClassHash parent class hash
// childClassHash hash of class to process
//
//=====================================================================
HRESULT CLocalizationUpgrade::ProcessClass(CNamespaceHandle *pNs,
const wchar_t *namespaceHash,
const wchar_t *parentClassHash,
const wchar_t *childClassHash)
{
HRESULT hRes = 0;
//Make a class definition string for this class class
CFileName classDefinition;
if (classDefinition == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(classDefinition, classDefinition.Length(), g_Glob.GetRootDir());
StringCchCatW(classDefinition, classDefinition.Length(), L"\\NS_");
StringCchCatW(classDefinition, classDefinition.Length(), namespaceHash);
StringCchCatW(classDefinition, classDefinition.Length(), L"\\CD_");
StringCchCatW(classDefinition, classDefinition.Length(), childClassHash);
_IWmiObject * pClass = NULL;
__int64 nTime;
bool bSystemClass;
hRes = pNs->FileToClass(classDefinition, &pClass, false, &nTime, &bSystemClass);
if (FAILED(hRes))
return hRes;
CReleaseMe rm(pClass);
//Extract the string from the object
VARIANT vName;
VariantInit(&vName);
CClearMe cm(&vName);
hRes = pClass->Get(L"__class", 0, &vName, NULL, NULL);
if(FAILED(hRes))
return hRes;
if(V_VT(&vName) != VT_BSTR)
return WBEM_E_INVALID_OBJECT;
MoveMemory(classDefinition, classDefinition+g_Glob.GetRootDirLen()+1, (wcslen(classDefinition+g_Glob.GetRootDirLen()+1)+1)*sizeof(wchar_t));
DEBUGTRACE((LOG_REPDRV, "Processing Class: %S, %S\n", V_BSTR(&vName), classDefinition));
bool bDifferent = false;
hRes = ProcessHash(V_BSTR(&vName), &bDifferent);
if (FAILED(hRes))
return hRes;
//Lets check that the hash we just generated was not the same as the one we are using!
if (bDifferent)
{
wchar_t *newClassHash;
hRes=GetNewHash(childClassHash, &newClassHash);
if (hRes == WBEM_E_NOT_FOUND)
{
//There are no differences!
hRes=WBEM_NO_ERROR;
bDifferent = false;
}
}
if (bDifferent)
{
CFileName newIndexEntry;
if (newIndexEntry == NULL)
return WBEM_E_OUT_OF_MEMORY;
//We need to fixup this entry
hRes = FixupIndex(classDefinition, newIndexEntry, bDifferent);
if (FAILED(hRes))
return hRes;
bool bClassDeleted = false;
if (bDifferent)
{
hRes = WriteClassIndex(pNs, classDefinition, newIndexEntry, &bClassDeleted);
if (FAILED(hRes))
return hRes;
}
//Now we need to fix up parent/class relationships?
//Finally, process the child classes
if (!bClassDeleted)
return ProcessClassesRecursively(pNs, namespaceHash, newIndexEntry+wcslen(newIndexEntry)-32);
else
return WBEM_NO_ERROR;
}
else
return ProcessClassesRecursively(pNs, namespaceHash, childClassHash);
}
//=====================================================================
//
// CLocalizationUpgrade::EnumerateInstances
//
// Description:
// Enumerates all instances in a specified namespace
//
// Parameters:
// pNs - We need to retrieve an instance, so we need a namespace handle to do that
//
//=====================================================================
HRESULT CLocalizationUpgrade::EnumerateInstances(CNamespaceHandle *pNs, const wchar_t *wszNewNamespaceHash)
{
unsigned long lRes = 0;
HRESULT hRes = 0;
CFileName wsInstancePath;
if (wsInstancePath == NULL)
return WBEM_E_OUT_OF_MEMORY;
CFileName wsInstanceShortPath;
if (wsInstanceShortPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wsInstancePath, wsInstancePath.Length(), pNs->m_wszClassRootDir);
StringCchCatW(wsInstancePath, wsInstancePath.Length(), L"\\" A51_KEYROOTINST_DIR_PREFIX);
//Enumerate all the objects
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.IndexEnumerationBegin(wsInstancePath, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
while(1)
{
lRes = g_Glob.m_FileCache.IndexEnumerationNext(pEnumHandle, wsInstanceShortPath, true);
if (lRes == ERROR_NO_MORE_FILES)
{
lRes = ERROR_SUCCESS;
break;
}
else if (lRes)
break;
//Need to strip out the .X.Y.Z and make long path version
wcstok(wsInstanceShortPath, L".");
StringCchCopyW(wsInstancePath + g_Glob.GetRootDirLen()+1, wsInstancePath.Length() - g_Glob.GetRootDirLen() -1, wsInstanceShortPath);
//2 check if this is an INSTANCE or a REFERENCE!
//We are only interested if we are an instance. Instances are ns_..\KI..\I_..x.y.z
//Reference is ns_..\KI_..\IR_..\R_..\I_..x.y.z
//We can validate this by checking for the existance of the _ in the I_ entry!
//for reference it would be an R from the IR_ entry!
if ((wcslen(wsInstanceShortPath) > 73) && (wsInstanceShortPath[73] == L'_'))
{
//2 Retrieve the object blob
DWORD dwLen = 0;
BYTE *pBuffer = NULL;
lRes = g_Glob.m_FileCache.ReadObject(wsInstancePath, &dwLen, &pBuffer);
if (lRes)
{
hRes = A51TranslateErrorCode(lRes);
break;
}
CTempFreeMe tfm(pBuffer, dwLen);
//2 Extract class hash from blob
wchar_t *wsOldClassHash = new wchar_t[MAX_HASH_LEN+1];
wchar_t *wsNewClassHash = NULL;
if (wsOldClassHash == NULL)
{
hRes = WBEM_E_OUT_OF_MEMORY;
break;
}
CVectorDeleteMe<wchar_t> vdm(wsOldClassHash);
StringCchCopyNW(wsOldClassHash, MAX_HASH_LEN+1, (wchar_t*)pBuffer, 32);
hRes = GetNewHash(wsOldClassHash, &wsNewClassHash);
if (hRes == WBEM_E_NOT_FOUND)
hRes = WBEM_NO_ERROR;
else if (FAILED(hRes))
break;
else
StringCchCopyW(wsOldClassHash, MAX_HASH_LEN+1, wsNewClassHash);
//Build up the full class definition fror this class
CFileName wszClassDefinition;
if (wszClassDefinition == NULL)
{
hRes = WBEM_E_OUT_OF_MEMORY;
break;
}
StringCchCopyW(wszClassDefinition, wszClassDefinition.Length(), g_Glob.GetRootDir());
StringCchCatW(wszClassDefinition, wszClassDefinition.Length(), L"\\");
StringCchCatNW(wszClassDefinition, wszClassDefinition.Length(), wsInstanceShortPath, 3+32+1);
StringCchCatW(wszClassDefinition, wszClassDefinition.Length(), L"CD_");
StringCchCatW(wszClassDefinition, wszClassDefinition.Length(), wsOldClassHash);
_IWmiObject *pClass = NULL;
__int64 nTime;
bool bSystemClass;
hRes = pNs->FileToClass(wszClassDefinition, &pClass, false, &nTime, &bSystemClass);
if (FAILED(hRes))
break;
CReleaseMe rm3(pClass);
//2 Get the instance
_IWmiObject* pInstance = NULL;
hRes = pNs->FileToInstance(pClass, wsInstancePath, pBuffer, dwLen, &pInstance, true);
if (FAILED(hRes))
break;
CReleaseMe rm2(pInstance);
//2 Get the path
VARIANT var;
VariantInit(&var);
hRes = pInstance->Get(L"__relpath", 0, &var, 0, 0);
if (FAILED(hRes))
break;
CClearMe cm2(&var);
dwLen = (wcslen(V_BSTR(&var)) + 1) ;
wchar_t *strKey = (WCHAR*)TempAlloc(dwLen* sizeof(WCHAR));
if(strKey == NULL)
{
hRes = WBEM_E_OUT_OF_MEMORY;
break;
}
CTempFreeMe tfm3(strKey, dwLen* sizeof(WCHAR));
bool bIsClass;
LPWSTR __wszClassName = NULL;
hRes = pNs->ComputeKeyFromPath(V_BSTR(&var), strKey, dwLen, &__wszClassName, &bIsClass);
if(FAILED(hRes))
break;
DEBUGTRACE((LOG_REPDRV, "Processing Instance Hash: %S='%S', %S\n", __wszClassName, strKey, wsInstanceShortPath));
TempFree(__wszClassName);
bool bDifferent = false;
hRes = ProcessHash(strKey, &bDifferent);
if (FAILED(hRes))
break;
hRes = ProcessFullPath(wsInstancePath, wszNewNamespaceHash);
if (FAILED(hRes))
break;
}
else
{
DEBUGTRACE((LOG_REPDRV, "Ignoring Instance reference: %S\n", wsInstanceShortPath));
}
}
g_Glob.m_FileCache.IndexEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
}
if (lRes)
hRes = A51TranslateErrorCode(lRes);
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::ProcessHash
//
// Description:
// Does the actual comparison of old and new hash of the given string.
// If different it records it for later use.
//
// Parameters:
// wszName Class name, namespace name, instance key.
//
//=====================================================================
HRESULT CLocalizationUpgrade::ProcessHash(const wchar_t *wszName, bool *pDifferent)
{
//Hash using old ToUpper method
//Hash using new ToUpper method
//If they are not the same add to the m_keyHash structure
HRESULT hRes = 0;
wchar_t wszOldHash[MAX_HASH_LEN+1];
wchar_t wszNewHash[MAX_HASH_LEN+1];
hRes = OldHash(wszName, wszOldHash);
if (SUCCEEDED(hRes))
hRes = NewHash(wszName, wszNewHash);
if (SUCCEEDED(hRes))
{
if (wcscmp(wszOldHash, wszNewHash) != 0)
{
DEBUGTRACE((LOG_REPDRV, "Hash difference detected for: %S, %S, %S\n", wszName, wszOldHash, wszNewHash));
//2 The hashes are different! We need to process them
hRes = m_keyHash.AddStrings(wszOldHash, wszNewHash);
*pDifferent = true;
}
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::ProcessFullPath
//
// Description:
// Takes an key root instance path and checks that the full hash using
// old and new methods match. If they are different it records for later
// usage
//
// Parameters:
// wszOldPath - Instance string c:\windows\...\NS_<hash>\KI_<hash>\I_hash.X.Y.Z
//
//=====================================================================
HRESULT CLocalizationUpgrade::ProcessFullPath(CFileName &wszOldFullPath, const wchar_t *wszNewNamespaceHash)
{
//Hash using old ToUpper method
//Hash using new ToUpper method
//If they are not the same add to the m_pathHash structure
HRESULT hRes = 0;
bool bChanged = false;
wchar_t wszOldHash[MAX_HASH_LEN+1];
wchar_t wszNewHash[MAX_HASH_LEN+1];
CFileName wsOldShortPath;
CFileName wszNewFullPath;
CFileName wszNewShortPath;
if ((wsOldShortPath == NULL) || (wszNewFullPath == NULL) || (wszNewShortPath == NULL))
return WBEM_E_OUT_OF_MEMORY;
//Need to fixup the old path with new hashes before we continue!
//Fixup requires short path to work and we have full path currently!
StringCchCopyW(wsOldShortPath, wsOldShortPath.Length(), wszOldFullPath+g_Glob.GetRootDirLen()+1);
hRes = FixupIndex(wsOldShortPath, wszNewShortPath, bChanged);
if (FAILED(hRes) || !bChanged)
return hRes;
//Copy the new namespace hash into the string to be sure!
wmemcpy(wszNewShortPath+3, wszNewNamespaceHash, 32);
//Now we need to add the FULL path to the start of each path before we hash it. Kind
//of crazy, but that's the way it was done!
StringCchCopyW(wszNewFullPath, wszNewFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszNewFullPath, wszNewFullPath.Length(), L"\\");
StringCchCatW(wszNewFullPath, wszNewFullPath.Length(), wszNewShortPath);
hRes = OldHash(wszOldFullPath, wszOldHash);
if (FAILED(hRes))
return hRes;
hRes = NewHash(wszNewFullPath, wszNewHash);
if (FAILED(hRes))
return hRes;
if (wcscmp(wszOldHash, wszNewHash) != 0)
{
//2 The hashes are different! We need to process them
DEBUGTRACE((LOG_REPDRV, "Path difference detected for: %S, %S, %S, %S\n", wszOldFullPath, wszNewShortPath, wszOldHash, wszNewHash));
hRes = m_pathHash.AddStrings(wszOldHash, wszNewHash);
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::OldHash
//
// Description:
// Generates a 32 character hash of the given string. It does it in
// the OLD way which is case screwed up
//
// Parameters:
// wszName Name to hash
// wszHash Returns the hash of the name
//
//=====================================================================
static wchar_t g_HexDigit[] = { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F'};
HRESULT CLocalizationUpgrade::OldHash(const wchar_t *wszName, wchar_t *wszHash)
{
DWORD dwBufferSize = wcslen(wszName)*2+2;
LPWSTR wszBuffer = (WCHAR*)TempAlloc(dwBufferSize);
if (wszBuffer == NULL)
return WBEM_E_OUT_OF_MEMORY;
CTempFreeMe vdm(wszBuffer, dwBufferSize);
OldStringToUpper(wszBuffer, wszName);
BYTE RawHash[16];
MD5::Transform((void*)wszBuffer, wcslen(wszBuffer)*2, RawHash);
WCHAR* pwc = wszHash;
for(int i = 0; i < 16; i++)
{
*(pwc++) = g_HexDigit[RawHash[i]/16];
*(pwc++) = g_HexDigit[RawHash[i]%16];
}
*pwc = 0;
return WBEM_NO_ERROR;
}
//=====================================================================
//
// CLocalizationUpgrade::NewHash
//
// Description:
// Hashes the given name using the new locale invariant specific
// conversion to upper case
//
// Parameters:
// wszName - Name to hash
// wszHash - Returns hash
//
//=====================================================================
HRESULT CLocalizationUpgrade::NewHash(const wchar_t *wszName, wchar_t *wszHash)
{
DWORD dwBufferSize = wcslen(wszName)*2+2;
LPWSTR wszBuffer = (WCHAR*)TempAlloc(dwBufferSize);
if (wszBuffer == NULL)
return WBEM_E_OUT_OF_MEMORY;
CTempFreeMe vdm(wszBuffer, dwBufferSize);
NewStringToUpper(wszBuffer, wszName);
BYTE RawHash[16];
MD5::Transform((void*)wszBuffer, wcslen(wszBuffer)*2, RawHash);
WCHAR* pwc = wszHash;
for(int i = 0; i < 16; i++)
{
*(pwc++) = g_HexDigit[RawHash[i]/16];
*(pwc++) = g_HexDigit[RawHash[i]%16];
}
*pwc = 0;
return WBEM_NO_ERROR;
}
//=====================================================================
//
// CLocalizationUpgrade::FixupBTree
//
// Description:
// Method that bootstraps the fixup of the BTree by iterating through
// all namespaces
//
// Parameters:
//
//=====================================================================
HRESULT CLocalizationUpgrade::FixupBTree()
{
HRESULT hRes = NO_ERROR;
//Lets iterate through the namespace list and iterate through everything in that namespace
//fixing things up and fixing things as we go
for (unsigned int i = 0; i != m_namespaces.Size(); i++)
{
hRes = FixupNamespace(m_namespaces[i]->m_wsz2);
if (FAILED(hRes))
break;
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::FixupNamespace
//
// Description:
// Enumerates all items within the namespace, andcalls into method to
// do all the work
//
// Parameters:
// wszNamespace - in the format of a FULL namespace path... c:\windows\...\NS_<hash>
//
//=====================================================================
HRESULT CLocalizationUpgrade::FixupNamespace(const wchar_t *wszNamespace)
{
HRESULT hRes = NO_ERROR;
long lRes = NO_ERROR;
CFileName indexEntry;
if (indexEntry == NULL)
return WBEM_E_OUT_OF_MEMORY;
CFileName newEntry;
if (newEntry == NULL)
return WBEM_E_OUT_OF_MEMORY;
bool bChanged = false;
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.IndexEnumerationBegin(wszNamespace, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
while(1)
{
lRes = g_Glob.m_FileCache.IndexEnumerationNext(pEnumHandle, indexEntry, true);
if (lRes == ERROR_NO_MORE_FILES)
{
lRes = ERROR_SUCCESS;
break;
}
else if (lRes)
break;
bChanged = false;
hRes = FixupIndex(indexEntry, newEntry, bChanged);
if (FAILED(hRes))
break;
if (bChanged)
{
hRes = WriteIndex(indexEntry, newEntry);
if (FAILED(hRes))
break;
}
if (IsInstanceReference(newEntry))
{
hRes = FixupIndexReferenceBlob(newEntry);
if (FAILED(hRes))
break;
}
if (IsKeyRootInstancePath(newEntry))
{
hRes = FixupInstanceBlob(newEntry);
if (FAILED(hRes))
break;
}
}
g_Glob.m_FileCache.IndexEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
}
if (lRes)
hRes = A51TranslateErrorCode(lRes);
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::FixupIndex
//
// Description:
// Fixes up the entry with all the new hashes we detected and returns the new entry
//
// Parameters:
// oldIndexEntry - Entry to fix up, in format of NS_<hash>\....
// newIndexEntry - oldIndexEntry with all hashes substituted to new entries
// bChanged - Returns a flag to say if it was changed
//
//=====================================================================
HRESULT CLocalizationUpgrade::FixupIndex(CFileName &oldIndexEntry, CFileName &newIndexEntry, bool &bChanged)
{
//Need to check each hash to see if it has a problem. To do this we can search for each '_'
//character and check the hash after that entry. If we see a match, we need to correct it.
//Any changes we detect need to be written back, then we need to delete the main entry.
//If we write it back, we need to check an entry doesn't already exist because if it does we
//need to discard this entry, and if we have an associated object we need to delete it, then log
//an event log entry to describe what we did!
CFileName scratchIndex;
if (scratchIndex == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(scratchIndex, scratchIndex.Length(), oldIndexEntry);
StringCchCopyW(newIndexEntry, newIndexEntry.Length(), oldIndexEntry);
wchar_t *wszSection = wcstok(scratchIndex, L"_");;
wchar_t *wszHash = wcstok(NULL, L"\\.");
wchar_t *pNewHash = NULL;
bool bInstanceReferenceDetected = false;
bool bUsePathHash = false;
HRESULT hRes = 0;
while (wszHash != NULL)
{
if (!bInstanceReferenceDetected)
{
if (wcsncmp(wszSection, A51_INSTREF_DIR_PREFIX, 2) == 0)
{
bInstanceReferenceDetected = true;
}
}
else if (bInstanceReferenceDetected && (wszSection != NULL))
{
if (wcsncmp(wszSection, A51_REF_FILE_PREFIX, 1) == 0)
{
bUsePathHash = true;
}
}
//Now the wszCursor points to just the hash, so we can check the hash out!
if (bUsePathHash)
{
hRes = GetNewPath(wszHash, &pNewHash);
bUsePathHash = false;
}
else
{
hRes = GetNewHash(wszHash, &pNewHash);
}
if (hRes == WBEM_NO_ERROR)
{
if ((m_pass != 3) && (wcsncmp(wszSection, L"NS_", 3) == 0))
{
//Do nothing!
}
else
{
//We have a difference
bChanged = true;
wmemcpy(((wchar_t*)newIndexEntry)+(wszHash-((wchar_t*)scratchIndex)), pNewHash, MAX_HASH_LEN);
}
}
else if (hRes == WBEM_E_NOT_FOUND)
hRes = WBEM_NO_ERROR;
//Search for next extry
wszSection = wcstok(NULL, L"_");
if (wszSection)
wszHash = wcstok(NULL, L"\\.");
else
wszHash = NULL;
}
if (bChanged)
{
DEBUGTRACE((LOG_REPDRV, "Fixed up index: %S, %S\n", (const wchar_t *)oldIndexEntry, (const wchar_t *)newIndexEntry));
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::GetNewHash
//
// Description:
// Given an old hash, returns a new hash if one exists, otherwise WBEM_E_NOT_FOUND
//
// Parameters:
// wszOldHash - Old hash string to search for - 32 character string
// pNewHash - pointer to a 32-character string of new entry if one exists, NULL otherwise
//
// Return Code
// WBEM_E_NOT_FOUND if a HASH is not found
//
//=====================================================================
HRESULT CLocalizationUpgrade::GetNewHash(const wchar_t *wszOldHash, wchar_t **pNewHash)
{
return m_keyHash.FindStrings(wszOldHash, pNewHash);
}
//=====================================================================
//
// CLocalizationUpgrade::GetNewPath
//
// Description:
// Given an old hash, returns a new hash if one exists, otherwise WBEM_E_NOT_FOUND
//
// Parameters:
// wszOldHash - Old hash string to search for - 32 character string
// pNewHash - pointer to a 32-character string of new entry if one exists, NULL otherwise
//
// Return Code
// WBEM_E_NOT_FOUND if a HASH is not found
//
//=====================================================================
HRESULT CLocalizationUpgrade::GetNewPath(const wchar_t *wszOldHash, wchar_t **pNewHash)
{
return m_pathHash.FindStrings(wszOldHash, pNewHash);
}
//=====================================================================
//
// CLocalizationUpgrade::WriteIndex
//
// Description:
// Checks if the new index exists. If not writes the new entry and deletes the old one. If the link points to an
// object then it deletes that, unless this is the instance class link object link.
// If there is a conflict calls into the method to deal with that.
//
// Parameters:
// wszOldIndex - old path of format NS_<hash>\...
// wszNewIndex - new path of format NS_<hash>\...
//
//=====================================================================
HRESULT CLocalizationUpgrade::WriteIndex(CFileName &wszOldIndex, const wchar_t *wszNewIndex)
{
//We need to determine if we have a collision before we write the index. Therefore we
//need to strip off the X.Y.Z entry if it exists and retrieve it. If it exists then we have
//to delete our index and delete the associated object
CFileName wszScratchIndex;
if (wszScratchIndex == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszScratchIndex, wszScratchIndex.Length(), wszNewIndex);
wchar_t *wszObjectLocation = NULL;
if (wcstok(wszScratchIndex, L".") != NULL)
wszObjectLocation = wcstok(NULL, L"");
CFileName wszFullPath;
if (wszFullPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszScratchIndex);
HRESULT hRes = IndexExists(wszFullPath);
if (hRes == WBEM_NO_ERROR)
{
//2 We have a conflict, therefore we need to delete the OLD entry!
long lRes = 0;
DEBUGTRACE((LOG_REPDRV, "Index Collision detected: %S\n", (const wchar_t *)wszOldIndex));
hRes = FixupIndexConflict(wszOldIndex);
}
else if (hRes == WBEM_E_NOT_FOUND)
{
hRes = WBEM_NO_ERROR;
//2 Write the new index
if (wszObjectLocation)
{
//Put the .X.Y.Z on the end!
StringCchCatW(wszFullPath, wszFullPath.Length(), L".");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszObjectLocation);
}
long lRes = g_Glob.m_FileCache.WriteLink(wszFullPath);
if(lRes != ERROR_SUCCESS)
hRes = A51TranslateErrorCode(lRes);
else
{
//2 Delete the old link
//strip off .X.Y.Z off old entry
StringCchCopyW(wszScratchIndex, wszScratchIndex.Length(), wszOldIndex);
wcstok(wszScratchIndex, L".");
//Build path
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszScratchIndex);
//Do delete
lRes = g_Glob.m_FileCache.DeleteLink(wszFullPath);
if(lRes != ERROR_SUCCESS)
hRes = A51TranslateErrorCode(lRes);
}
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::WriteClassIndex
//
// Description:
// Checks if the new index exists. If not writes the new entry and deletes the old one. If the link points to an
// object then it deletes that, unless this is the instance class link object link.
// If there is a conflict calls into the method to deal with that.
//
// Parameters:
// wszOldIndex - old path of format NS_<hash>\...
// wszNewIndex - new path of format NS_<hash>\...
//
//=====================================================================
HRESULT CLocalizationUpgrade::WriteClassIndex(CNamespaceHandle *pNs, CFileName &wszOldIndex, const wchar_t *wszNewIndex, bool *pClassDeleted)
{
//We need to re-read the old index because we don't have the .X.Y.X on the end.
HRESULT hRes = g_Glob.m_FileCache.ReadNextIndex(wszOldIndex, wszOldIndex);
if (FAILED(hRes))
return hRes;
//Save off and remove the .X.Y.Z
wchar_t *wszObjectLocation = NULL;
if (wcstok(wszOldIndex, L".") != NULL)
wszObjectLocation = wcstok(NULL, L"");
//We need to determine if we have a collision before we write the index.
//If it exists then we have
//to delete our index and delete the associated object
CFileName wszFullPath;
if (wszFullPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszNewIndex);
hRes = IndexExists(wszFullPath);
if (hRes == WBEM_NO_ERROR)
{
//2 We have a conflict, therefore we need to delete the old class!
DEBUGTRACE((LOG_REPDRV, "Class Index Collision detected: %S\n", (const wchar_t *)wszOldIndex));
*pClassDeleted = true;
hRes = DeleteClass(pNs, wszOldIndex);
}
else if (hRes == WBEM_E_NOT_FOUND)
{
hRes = WBEM_NO_ERROR;
//2 Write the new index
if (wszObjectLocation)
{
//Put the .X.Y.Z on the end!
StringCchCatW(wszFullPath, wszFullPath.Length(), L".");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszObjectLocation);
}
long lRes = g_Glob.m_FileCache.WriteLink(wszFullPath);
if(lRes != ERROR_SUCCESS)
hRes = A51TranslateErrorCode(lRes);
else
{
//2 Delete the old link
//Build path
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszOldIndex);
//Do delete
lRes = g_Glob.m_FileCache.DeleteLink(wszFullPath);
if(lRes != ERROR_SUCCESS)
hRes = A51TranslateErrorCode(lRes);
}
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::IndexExists
//
// Description:
// Checks to see if a specific index exists. Returns WBEM_E_NOT_FOUND if not, or WBEM_NO_ERROR if it
// does.
//
// Parameters:
// wszIndex - full path of index to find - c:\windows\...\ns_<>\....
//
// Returns:
// WBEM_E_NOT_FOUND if index does not exist
// WBEM_NO_ERROR if it exists.
//
//=====================================================================
HRESULT CLocalizationUpgrade::IndexExists(const wchar_t *wszIndex)
{
HRESULT hRes = NO_ERROR;
long lRes = NO_ERROR;
CFileName indexEntry;
if (indexEntry == NULL)
return WBEM_E_OUT_OF_MEMORY;
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.IndexEnumerationBegin(wszIndex, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
lRes = g_Glob.m_FileCache.IndexEnumerationNext(pEnumHandle, indexEntry, true);
g_Glob.m_FileCache.IndexEnumerationEnd(pEnumHandle);
}
if (lRes)
hRes = A51TranslateErrorCode(lRes);
//make sure index we retrieved was from this index
if (SUCCEEDED(hRes))
if (wcsncmp(wszIndex+g_Glob.GetRootDirLen()+1, indexEntry, wcslen(wszIndex+g_Glob.GetRootDirLen()+1)) != 0)
hRes = WBEM_E_NOT_FOUND;
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::ProcessNamespaceCollisions
//
// Description:
// Searches through the namespace list for collisions. If one exists then we delete the namespace
// recursively
//
// Parameters:
//
//=====================================================================
HRESULT CLocalizationUpgrade::ProcessNamespaceCollisions()
{
HRESULT hRes = NO_ERROR;
wchar_t thisNamespace[MAX_HASH_LEN+1];
wchar_t thatNamespace[MAX_HASH_LEN+1];
bool bDeletedSomething = false;
//Lets iterate through the namespace list and calculate the hash.
//Then we will itterate through the rest of the namespace list and check the
//hash with that one. If we have a collision, we need to delete it!
do
{
bDeletedSomething = false;
for (int i = 0; i != m_namespaces.Size(); i++)
{
//Hash this entry
hRes = NewHash(m_namespaces[i]->m_wsz1, thisNamespace);
if (FAILED(hRes))
break;
for (int j = (i+1); j < m_namespaces.Size(); j++)
{
//Hash this entry
hRes = NewHash(m_namespaces[j]->m_wsz1, thatNamespace);
if (FAILED(hRes))
break;
//If they are the same we need to delete this one
if (wcscmp(thisNamespace, thatNamespace) == 0)
{
//OK, so we have a collision! Lets deal with it!
hRes = DeleteNamespaceRecursive(m_namespaces[i]->m_wsz1);
if (FAILED(hRes))
break;
//We need to start again with the iteration as we may have deleted several entries
//from the array at this point
bDeletedSomething = true;
break;
}
}
if (FAILED(hRes) || bDeletedSomething)
break;
}
} while (SUCCEEDED(hRes) && bDeletedSomething);
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::DeleteNamespaceRecursive
//
// Description:
// Searches through the namespace list for any which start with the one we passed in. Any matches are
// deleted
//
// Parameters:
// wszNamespace - namespace name in the format like root\default
//
//=====================================================================
HRESULT CLocalizationUpgrade::DeleteNamespaceRecursive(const wchar_t *wszNamespace)
{
LONG lRes = 0;
HRESULT hRes = NO_ERROR;
wchar_t *wszNamespaceHash = new wchar_t[MAX_HASH_LEN+1];
if (wszNamespaceHash == NULL)
return WBEM_E_OUT_OF_MEMORY;
hRes = OldHash(wszNamespace, wszNamespaceHash);
if (FAILED(hRes))
return hRes;
CFileName wszNamespacePath;
if (wszNamespacePath == NULL)
return WBEM_E_OUT_OF_MEMORY;
//Create the hashed path to the Key Root for the namespace
StringCchCopyW(wszNamespacePath, MAX_PATH, g_Glob.GetRootDir());
StringCchCatW(wszNamespacePath, MAX_PATH, L"\\NS_");
StringCchCatW(wszNamespacePath, MAX_PATH, wszNamespaceHash);
DEBUGTRACE((LOG_REPDRV, "Deleting namespace (recursive): %S, %S\n", wszNamespace, wszNamespacePath+g_Glob.GetRootDirLen()+1));
//2 Create a CNamespaceHandle so we can access objects in this namespace
CNamespaceHandle *pNs = new CNamespaceHandle(m_pControl, m_pRepository);
if (pNs == NULL)
return WBEM_E_OUT_OF_MEMORY;
CDeleteMe<CNamespaceHandle> cdm(pNs);
hRes = pNs->Initialize2(wszNamespace, wszNamespaceHash);
if (FAILED(hRes))
return hRes;
StringCchCatW(wszNamespacePath, MAX_PATH, L"\\" A51_KEYROOTINST_DIR_PREFIX);
StringCchCatW(wszNamespacePath, MAX_PATH, m_namespaceClassHash);
StringCchCatW(wszNamespacePath, MAX_PATH, L"\\" A51_INSTDEF_FILE_PREFIX);
//2 Enumerate all the child namespaces
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.ObjectEnumerationBegin(wszNamespacePath, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
BYTE *pBlob = NULL;
DWORD dwSize = 0;
while(1)
{
lRes = g_Glob.m_FileCache.ObjectEnumerationNext(pEnumHandle, wszNamespacePath, &pBlob, &dwSize);
if (lRes == ERROR_NO_MORE_FILES)
{
lRes = ERROR_SUCCESS;
break;
}
else if (lRes)
break;
//Get the instance
_IWmiObject* pInstance = NULL;
hRes = pNs->FileToInstance(NULL, wszNamespacePath, pBlob, dwSize, &pInstance, true);
//Free the blob
g_Glob.m_FileCache.ObjectEnumerationFree(pEnumHandle, pBlob);
if (FAILED(hRes))
break;
CReleaseMe rm2(pInstance);
//Extract the string from the object
VARIANT vName;
VariantInit(&vName);
CClearMe cm(&vName);
hRes = pInstance->Get(L"Name", 0, &vName, NULL, NULL);
if(FAILED(hRes))
break;
if(V_VT(&vName) != VT_BSTR)
{
hRes = WBEM_E_INVALID_OBJECT;
break;
}
//Create the full namespace path
wchar_t *wszChildNamespacePath = new wchar_t[wcslen(wszNamespace)+1+wcslen(V_BSTR(&vName)) + 1];
if (wszChildNamespacePath == NULL)
{
hRes = WBEM_E_OUT_OF_MEMORY;
break;
}
CVectorDeleteMe<wchar_t> vdm(wszChildNamespacePath);
StringCchCopyW(wszChildNamespacePath, MAX_PATH, wszNamespace);
StringCchCatW(wszChildNamespacePath, MAX_PATH, L"\\");
StringCchCatW(wszChildNamespacePath, MAX_PATH, V_BSTR(&vName));
//2 Process all child namespaces in this namespace
hRes = DeleteNamespaceRecursive(wszChildNamespacePath);
if (FAILED(hRes))
break;
}
g_Glob.m_FileCache.ObjectEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
}
if (lRes)
hRes = A51TranslateErrorCode(lRes);
if (SUCCEEDED(hRes))
{
StringCchCopyW(wszNamespacePath, MAX_PATH, g_Glob.GetRootDir());
StringCchCatW(wszNamespacePath, MAX_PATH, L"\\NS_");
StringCchCatW(wszNamespacePath, MAX_PATH, wszNamespaceHash);
hRes = DeleteNamespace(wszNamespace, wszNamespacePath);
}
//2 Remote namespace path
if (SUCCEEDED(hRes))
{
hRes = m_namespaces.RemoveString(wszNamespace);
//Small chance that we get NOT_FOUND if we have not done full enumeration yet!
if (hRes == WBEM_E_NOT_FOUND)
hRes = WBEM_NO_ERROR;
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::DeleteNamespace
//
// Description:
// Deletes the specified namespace using the DeleteNode, then goes into the parent namespace and deletes
// the instance from that namespace
//
// Parameters:
// wszNamespaceName - namespace name in format root\default
// wszNamespaceHash - Full namespace hash in format c:\windows\...\NS_<hash>
//
//=====================================================================
HRESULT CLocalizationUpgrade::DeleteNamespace(const wchar_t *wszNamespaceName,const wchar_t *wszNamespaceHash)
{
HRESULT hRes = NO_ERROR;
LONG lRes = NO_ERROR;
DEBUGTRACE((LOG_REPDRV, "Deleting namespace: %S, %S\n", wszNamespaceName, wszNamespaceHash+g_Glob.GetRootDirLen()+1));
//2 Delete the actual namespace contents
lRes = g_Glob.m_FileCache.DeleteNode(wszNamespaceHash);
if (lRes != 0)
return A51TranslateErrorCode(lRes);
//2 Calculate parent namespace name
wchar_t *wszParentNamespaceName = new wchar_t[wcslen(wszNamespaceName)+1];
wchar_t *wszThisNamespaceName = NULL;
if (wszParentNamespaceName == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszParentNamespaceName, wcslen(wszNamespaceName)+1, wszNamespaceName);
for (int i = wcslen(wszParentNamespaceName) - 1; i != 0; i--)
{
if (wszParentNamespaceName[i] == L'\\')
{
wszParentNamespaceName[i] = L'\0';
wszThisNamespaceName = wszParentNamespaceName+i+1;
break;
}
}
//2 Calculate parent namespace hash
wchar_t wszParentNamespaceHash[MAX_HASH_LEN+1];
hRes = OldHash(wszParentNamespaceName, wszParentNamespaceHash);
if (FAILED(hRes))
return hRes;
//2Calculate this namespaces hash
wchar_t wszThisNamespaceHash[MAX_HASH_LEN+1];
hRes = OldHash(wszThisNamespaceName, wszThisNamespaceHash);
if (FAILED(hRes))
return hRes;
//2 Calculate __namespace class hash
wchar_t wszNamespaceClassHash[MAX_HASH_LEN+1];
hRes = OldHash(L"__namespace", wszNamespaceClassHash);
if (FAILED(hRes))
return hRes;
CFileName wszKI;
CFileName wszCI;
if ((wszKI == NULL) || (wszCI == NULL))
return WBEM_E_OUT_OF_MEMORY;
//2 Build KI instance path
StringCchCopyW(wszKI,wszKI.Length(), g_Glob.GetRootDir());
StringCchCatW(wszKI, wszKI.Length(), L"\\NS_");
StringCchCatW(wszKI, wszKI.Length(), wszParentNamespaceHash);
StringCchCopyW(wszCI, wszCI.Length(), wszKI);
StringCchCatW(wszKI, wszKI.Length(), L"\\KI_");
StringCchCatW(wszKI, wszKI.Length(), wszNamespaceClassHash);
StringCchCatW(wszKI, wszKI.Length(), L"\\I_");
StringCchCatW(wszKI, wszKI.Length(), wszThisNamespaceHash);
//2 Retrieve instance blob so we can get the class hash for this instance
wchar_t wszClassHash[MAX_HASH_LEN+1];
BYTE *pBuffer = NULL;
DWORD dwLen = 0;
lRes = g_Glob.m_FileCache.ReadObject(wszKI, &dwLen, &pBuffer, false);
if (lRes)
{
//If this object does not exist, then we have probably already deleted the parent namespace!
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = 0;
return A51TranslateErrorCode(lRes);
}
StringCchCopyNW(wszClassHash, MAX_HASH_LEN+1, (wchar_t*)pBuffer, MAX_HASH_LEN);
TempFree(pBuffer, dwLen);
//2 Build the CI instance path
StringCchCatW(wszCI, wszCI.Length(), L"\\CI_");
StringCchCatW(wszCI, wszCI.Length(), wszClassHash);
StringCchCatW(wszCI, wszCI.Length(), L"\\IL_");
StringCchCatW(wszCI, wszCI.Length(), wszThisNamespaceHash);
//2 Delete the KI link and object
lRes = g_Glob.m_FileCache.DeleteObject(wszKI);
if (lRes)
return A51TranslateErrorCode(lRes);
//2Delete the CI link only
lRes = g_Glob.m_FileCache.DeleteLink(wszCI);
if (lRes)
return A51TranslateErrorCode(lRes);
//OK, now, in theory, we should really, if we were really good citizens, delete any references that could be in this object!
//However nothing too bad will happen if we don't, so we won't!
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::FixupIndexConflict
//
// Description:
// Method is called if the old and new index exists. If the link is for a class definition, we have a lot more
// work to do, so call into the handling method. Otherwise we just delete the old index, and object
// if it exists. If it is a KI_ index then we do not delete the object because the CI index entry will
// delete it instead
//
// Parameters:
// wszOldIndex -- Index to update in format NS_<hash>\KI_<>\I_<>.X.Y.Z. It must have the
// X.Y.Z entry if one exists
//
//=====================================================================
HRESULT CLocalizationUpgrade::FixupIndexConflict(CFileName &wszOldIndex)
{
//If it is a class definition, we have a lot of work to do as we need to delete the class, all sub-classes, and all instances.
//If the class is derived from __namespace then we need to delete the namespace recursively as well
if (IsClassDefinitionPath(wszOldIndex))
{
DEBUGTRACE((LOG_REPDRV, "TRYING TO FIX UP A CLASS IN THE WRONG PLACE\n"));
_ASSERT(1, L"TRYING TO FIX UP A CLASS IN THE WRONG PLACE");
return WBEM_E_FAILED;
}
else
{
LONG lRes = 0;
//This is the simple case, we just have to delete the old link or object
CFileName wszFullPath;
if (wszFullPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszOldIndex);
//Strip off the .X.Y.Z entry if it exists
wchar_t *wszObjectLocation = wcstok(wszFullPath+g_Glob.GetRootDirLen()+1, L".");
if (wszObjectLocation)
wszObjectLocation = wcstok(NULL, L"");
if (wszObjectLocation && !IsKeyRootInstancePath(wszOldIndex))
lRes = g_Glob.m_FileCache.DeleteObject(wszFullPath);
else
lRes = g_Glob.m_FileCache.DeleteLink(wszFullPath);
return A51TranslateErrorCode(lRes);
}
}
//=====================================================================
//
// CLocalizationUpgrade::IsClassDefinitionPath
//
// Description:
// Checks the link to see if this is a class definition or not
//
// Parameters:
// wszPath - link in the format NS_<>\CD_<>, or something else
//
// Returns:
// true - link is a class definition
// false - is not one
//
//=====================================================================
bool CLocalizationUpgrade::IsClassDefinitionPath(const wchar_t *wszPath)
{
WCHAR* pDot = wcschr(wszPath, L'\\');
if(pDot == NULL)
return false;
pDot++;
if ((*pDot == L'C') && (*(pDot+1) == L'D')&& (*(pDot+2) == L'_'))
return true;
else
return false;
}
//=====================================================================
//
// CLocalizationUpgrade::IsKeyRootInstancePath
//
// Description:
// Returns if this is a key root instance entry
//
// Parameters:
// wszPath - index in format NS_<>\KI_<>\I_, or somthing like that
//
// Returns:
// true - if this is a KI_<>\I_<> entry
// false - otherwise
//
//=====================================================================
bool CLocalizationUpgrade::IsKeyRootInstancePath(const wchar_t *wszPath)
{
WCHAR* pDot = wcschr(wszPath, L'\\');
if(pDot == NULL)
return false;
pDot++;
pDot = wcschr(pDot, L'\\');
if(pDot == NULL)
return false;
pDot++;
if ((*pDot == L'I') && (*(pDot+1) == L'_'))
return true;
else
return false;
}
//=====================================================================
//
// CLocalizationUpgrade::IsInstanceReference
//
// Description:
// Returns if this is a instance reference entry
//
// Parameters:
// wszPath - index in format NS_<>\KI_<>\IR_<>\R, or somthing like that
//
// Returns:
// true - if this is a NS_<>\KI_<>\IR_<>\R entry
// false - otherwise
//
//=====================================================================
bool CLocalizationUpgrade::IsInstanceReference(const wchar_t *wszPath)
{
WCHAR* pDot = wcschr(wszPath, L'\\');
if(pDot == NULL)
return false;
pDot++;
pDot = wcschr(pDot, L'\\');
if(pDot == NULL)
return false;
pDot++;
pDot = wcschr(pDot, L'\\');
if(pDot == NULL)
return false;
pDot++;
if ((*pDot == L'R') && (*(pDot+1) == L'_'))
return true;
else
return false;
}
//=====================================================================
//
// CLocalizationUpgrade::DeleteClass
//
// Description:
// Recursively deletes the class definition, sub-classes and instances. If the instance is
// a namespace then we need to delete that also
//
// Parameters:
// wszClassDefinitionPath - short path of class definition (ns_...\CD_....X.Y.Z. XYZ is optional! We kill it!
//
//=====================================================================
HRESULT CLocalizationUpgrade::DeleteClass(CNamespaceHandle *pNs, CFileName &wszClassDefinitionPath)
{
HRESULT hRes =0;
LONG lRes = 0;
DEBUGTRACE((LOG_REPDRV, "Deleting Class: %S\n", wszClassDefinitionPath));
CFileName wszKeyRootClass;
if (wszKeyRootClass == NULL)
return WBEM_E_OUT_OF_MEMORY;
CFileName wszFullPath;
if (wszFullPath == NULL)
hRes = WBEM_E_OUT_OF_MEMORY;
wchar_t *wszParentClassHash = new wchar_t[MAX_HASH_LEN+1];
if (wszParentClassHash == NULL)
return WBEM_E_OUT_OF_MEMORY;
//Kill the .X.Y.Z on the end of the definition, in case it was passed in that way
wcstok((wchar_t*)wszClassDefinitionPath,L".");
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszClassDefinitionPath);
hRes = DeleteChildClasses(pNs, wszClassDefinitionPath);
if (SUCCEEDED(hRes))
hRes = RetrieveKeyRootClass(wszClassDefinitionPath, wszKeyRootClass);
if (SUCCEEDED(hRes))
{
hRes = RetrieveParentClassHash(wszFullPath, wszParentClassHash);
if (hRes == WBEM_S_NO_MORE_DATA)
hRes = 0;
}
if (SUCCEEDED(hRes) && wcslen(wszKeyRootClass) > 0)
hRes = DeleteInstances(pNs, wszClassDefinitionPath, wszKeyRootClass);
if (SUCCEEDED(hRes))
{
//Need to build the full path
lRes = g_Glob.m_FileCache.DeleteObject(wszFullPath);
hRes = A51TranslateErrorCode(lRes);
}
if (SUCCEEDED(hRes))
hRes = DeleteClassRelationships(wszFullPath, wszParentClassHash);
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::DeleteChildClasses
//
// Description:
// Enumerates child classes from a given parent class definition, and calls DeleteClass on each
//
// Parameters:
// wszParentClassDefinition - NS_<>\CD_<> of parent class
//
//=====================================================================
HRESULT CLocalizationUpgrade::DeleteChildClasses(CNamespaceHandle *pNs, const wchar_t *wszParentClassDefinition)
{
HRESULT hRes= 0;
unsigned long lRes = 0;
//Build up a string for this classes c:\...\NS_...\CR_...\C_ enumeration
CFileName wszChildClasses;
if (wszChildClasses == NULL)
return WBEM_E_OUT_OF_MEMORY;
CFileName wszClassDefinition;
if (wszClassDefinition == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszClassDefinition, wszClassDefinition.Length(), wszParentClassDefinition);
//Create full class definition path
StringCchCopyW(wszChildClasses, wszChildClasses.Length(), g_Glob.GetRootDir());
StringCchCatW(wszChildClasses, wszChildClasses.Length(), L"\\");
StringCchCatW(wszChildClasses, wszChildClasses.Length(), wszParentClassDefinition);
//change the CD_ into CR_
wszChildClasses[g_Glob.GetRootDirLen()+1+3+32+2] = L'R';
//Add the \C_ on the end
StringCchCatW(wszChildClasses, wszChildClasses.Length(), L"\\C_");
//Enumerate the child classes
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.IndexEnumerationBegin(wszChildClasses, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
while(1)
{
lRes = g_Glob.m_FileCache.IndexEnumerationNext(pEnumHandle, wszChildClasses, true);
if (lRes == ERROR_NO_MORE_FILES)
{
hRes = ERROR_SUCCESS;
break;
}
else if (lRes)
{
hRes = A51TranslateErrorCode(lRes);
break;
}
//Build a NS_...\CD_... from the NS_...\CR_...\C_... path, using last hash
StringCchCopyW(wszClassDefinition+wcslen(wszClassDefinition) - 32,
wszClassDefinition.Length() - wcslen(wszClassDefinition) + 32,
wszChildClasses + wcslen(wszChildClasses)-32);
//Delete all child classes
hRes = DeleteClass(pNs, wszClassDefinition);
if (FAILED(hRes))
break;
}
g_Glob.m_FileCache.IndexEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
if (lRes)
hRes = A51TranslateErrorCode(lRes);
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::DeleteInstances
//
// Description:
// Enumerates all instances for a specified class definition and calls DeleteInstance
//
// Parameters:
// wszClassDefinition - NS_<>\CD_<> of class whose instances are to be deleted
// wszKeyRootClass - hash of key root class in 32-character format
//
//=====================================================================
HRESULT CLocalizationUpgrade::DeleteInstances(CNamespaceHandle *pNs, const wchar_t *wszClassDefinition, CFileName &wszKeyRootClass)
{
LONG lRes = 0;
HRESULT hRes = 0;
//Need to enumerate all NS_\CI_<class defn hash>\IL_...
//for each, we need to deltete the instance
CFileName wszClassInstance;
if (wszClassInstance == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszClassInstance, wszClassInstance.Length(), g_Glob.GetRootDir());
StringCchCatW(wszClassInstance, wszClassInstance.Length(), L"\\");
StringCchCatW(wszClassInstance, wszClassInstance.Length(), wszClassDefinition);
wszClassInstance[g_Glob.GetRootDirLen() + 1+3+32+1+1] = L'I';
StringCchCatW(wszClassInstance, wszClassInstance.Length(), L"\\IL_");
//Enumerate the instances
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.IndexEnumerationBegin(wszClassInstance, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
while(1)
{
lRes = g_Glob.m_FileCache.IndexEnumerationNext(pEnumHandle, wszClassInstance, true);
if (lRes == ERROR_NO_MORE_FILES)
{
hRes = ERROR_SUCCESS;
break;
}
else if (lRes)
{
hRes = A51TranslateErrorCode(lRes);
break;
}
hRes = DeleteInstance(pNs, wszClassInstance, wszKeyRootClass);
if (FAILED(hRes))
break;
}
g_Glob.m_FileCache.IndexEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
if (lRes)
hRes = A51TranslateErrorCode(lRes);
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::DeleteInstance
//
// Description:
// Deletes the instance links for a given instance
//
// Parameters:
// wszClassInstanceLink - NS_<>\CI_<>\IL_<> format of instance to delete
// wszKeyRoot - Hash of key root class for this instance
//
//=====================================================================
HRESULT CLocalizationUpgrade::DeleteInstance(CNamespaceHandle *pNs, const wchar_t *wszClassInstanceLink, CFileName &wszKeyRoot)
{
HRESULT hRes = 0;
LONG lRes = 0;
//Remove .X.Y.Z from end of string if it exists
wcstok((wchar_t *)wszClassInstanceLink, L".");
DEBUGTRACE((LOG_REPDRV, "Deleting Instance: %S\n", wszClassInstanceLink));
if (wcscmp(wszKeyRoot, m_namespaceClassHash) == 0)
{
return DeleteInstanceAsNamespace(pNs, wszClassInstanceLink);
}
//build KI entry and delete the object
CFileName wszKI;
if (wszKI == NULL)
return NULL;
StringCchCopyW(wszKI, wszKI.Length(), g_Glob.GetRootDir());
StringCchCatW(wszKI, wszKI.Length(), L"\\");
StringCchCatNW(wszKI, wszKI.Length(), wszClassInstanceLink, 3+32);
StringCchCatW(wszKI, wszKI.Length(), L"\\KI_");
StringCchCatW(wszKI, wszKI.Length(), wszKeyRoot);
StringCchCatW(wszKI, wszKI.Length(), L"\\I_");
StringCchCatW(wszKI, wszKI.Length(), wszClassInstanceLink + wcslen(wszClassInstanceLink) - 32);
lRes = g_Glob.m_FileCache.DeleteObject(wszKI);
if (lRes)
return A51TranslateErrorCode(lRes);
//Build instance reference enumerator link
StringCchCopyW(wszKI, wszKI.Length(), g_Glob.GetRootDir());
StringCchCatW(wszKI, wszKI.Length(), L"\\");
StringCchCatNW(wszKI, wszKI.Length(), wszClassInstanceLink, 3+32);
StringCchCatW(wszKI, wszKI.Length(), L"\\KI_");
StringCchCatW(wszKI, wszKI.Length(), wszKeyRoot);
StringCchCatW(wszKI, wszKI.Length(), L"\\IR_");
StringCchCatW(wszKI, wszKI.Length(), wszClassInstanceLink + wcslen(wszClassInstanceLink) - 32);
StringCchCatW(wszKI, wszKI.Length(), L"\\R_");
hRes = DeleteInstanceReferences(wszKI);
if (SUCCEEDED(hRes))
{
//Now delete the class instance link
StringCchCopyW(wszKI, wszKI.Length(), g_Glob.GetRootDir());
StringCchCatW(wszKI, wszKI.Length(), L"\\");
StringCchCatW(wszKI, wszKI.Length(), wszClassInstanceLink);
lRes = g_Glob.m_FileCache.DeleteLink(wszKI);
if (lRes)
hRes = A51TranslateErrorCode(lRes);
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::DeleteInstanceReferences
//
// Description:
// Enumerates the instance references for the given instance link and deletes the link and object
//
// Parameters:
// wszInstLink - key root instance link of references to be deleted in format NS_<>\KI_<>\I_<>
//
//=====================================================================
//NOTE: FULL LINK PASSED IN!
HRESULT CLocalizationUpgrade::DeleteInstanceReferences(CFileName &wszInstLink)
{
LONG lRes = 0;
CFileName wszFullPath;
if (wszFullPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
//Enumerate the instances
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.IndexEnumerationBegin(wszInstLink, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
while(1)
{
lRes = g_Glob.m_FileCache.IndexEnumerationNext(pEnumHandle, wszInstLink, true);
if (lRes == ERROR_NO_MORE_FILES)
{
lRes = ERROR_SUCCESS;
break;
}
else if (lRes)
{
break;
}
//Convert to a FULL path
StringCchCatW(wszFullPath+g_Glob.GetRootDirLen()+1, wszFullPath.Length()-g_Glob.GetRootDirLen()-1, wszInstLink);
lRes = g_Glob.m_FileCache.DeleteObject(wszFullPath);
if (lRes)
break;
}
g_Glob.m_FileCache.IndexEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
}
return A51TranslateErrorCode(lRes);;
}
//=====================================================================
//
// CLocalizationUpgrade::DeleteClassRelationships
//
// Description:
// Deletes all class relationships, including parent/child and references
//
// Parameters:
// wszPath - Full path of class definition, c:\windows\...\NS_<>\CD_<>
//
//=====================================================================
HRESULT CLocalizationUpgrade::DeleteClassRelationships(CFileName &wszPath,
const wchar_t wszParentClassHash[MAX_HASH_LEN+1])
{
//Convert from the class definition to a class relationship path
CFileName wszCRLink;
if (wszCRLink == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszCRLink, wszCRLink.Length(), wszPath);
wszCRLink[g_Glob.GetRootDirLen()+1+3+32+1+1] = L'R';
HRESULT hRes = 0;
LONG lRes = 0;
CFileName wszFullPath;
if (wszFullPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
//Enumerate the instances
LPVOID pEnumHandle = NULL;
lRes = g_Glob.m_FileCache.IndexEnumerationBegin(wszCRLink, &pEnumHandle);
if (lRes == ERROR_SUCCESS)
{
while(1)
{
lRes = g_Glob.m_FileCache.IndexEnumerationNext(pEnumHandle, wszCRLink, true);
if (lRes == ERROR_NO_MORE_FILES)
{
lRes = ERROR_SUCCESS;
break;
}
else if (lRes)
{
break;
}
//Convert to a FULL path
StringCchCopyW(wszFullPath+g_Glob.GetRootDirLen()+1, wszFullPath.Length()-g_Glob.GetRootDirLen()-1, wszCRLink);
lRes = g_Glob.m_FileCache.DeleteLink(wszFullPath);
if (lRes)
break;
}
g_Glob.m_FileCache.IndexEnumerationEnd(pEnumHandle);
}
else
{
if (lRes == ERROR_FILE_NOT_FOUND)
lRes = ERROR_SUCCESS;
}
hRes = A51TranslateErrorCode(lRes);
if (SUCCEEDED(hRes))
{
//Now we need to delete our parent's relationship to us!
StringCchCopyW(wszCRLink, wszCRLink.Length(), wszPath);
wszCRLink[g_Glob.GetRootDirLen()+1+3+32+1+1] = L'R';
StringCchCopyW(wszCRLink+g_Glob.GetRootDirLen()+1+3+32+1+3, wszCRLink.Length()-g_Glob.GetRootDirLen()-1-3-32-1-3, wszParentClassHash);
StringCchCatW(wszCRLink, wszCRLink.Length(), L"\\C_");
StringCchCatW(wszCRLink, wszCRLink.Length(), wszPath+g_Glob.GetRootDirLen()+1+3+32+1+3);
lRes = g_Glob.m_FileCache.DeleteLink(wszCRLink);
hRes = A51TranslateErrorCode(lRes);
}
return hRes;
}
//=====================================================================
//
// CLocalizationUpgrade::RetrieveKeyRootClass
//
// Description:
// Searches for instances under KI_<> for all classes in the hierarchy chain for the specified class.
// This is a slower process because we have to retrieve each class blob and get the hash of the
// parent class
//
// Parameters:
// wszClassDefinitionPath - Path of class definition to retrieve key root class, NS_<>\CD_<>
// wszKeyRootClass - This is where we put the 32-character hash of the key root class
// or empty string if there is none!
//
//=====================================================================
HRESULT CLocalizationUpgrade::RetrieveKeyRootClass(CFileName &wszClassDefinitionPath, CFileName &wszKeyRootClass)
{
HRESULT hRes = 0;
LONG lRes = 0;
CFileName wszFullClassPath;
if (wszFullClassPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
CFileName wszFullKIPath;
if (wszFullKIPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszFullClassPath, wszFullClassPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullClassPath, wszFullClassPath.Length(), L"\\");
StringCchCatW(wszFullClassPath, wszFullClassPath.Length(), wszClassDefinitionPath);
StringCchCopyW(wszFullKIPath, wszFullKIPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullKIPath, wszFullKIPath.Length(), L"\\");
StringCchCatW(wszFullKIPath, wszFullKIPath.Length(), wszClassDefinitionPath);
//convert the class definition to a instance definition
wszFullKIPath[g_Glob.GetRootDirLen()+1+3+32+1]=L'K';
wszFullKIPath[g_Glob.GetRootDirLen()+1+3+32+2]=L'I';
StringCchCatW(wszFullKIPath, wszFullKIPath.Length(), L"\\I_");
wszKeyRootClass[0] = L'\0';
do
{
//Check if we have any instances
hRes = IndexExists(wszFullKIPath);
if (SUCCEEDED(hRes))
{
//We have the entry we are looking for
StringCchCopyNW(wszKeyRootClass, wszKeyRootClass.Length(), wszFullKIPath+g_Glob.GetRootDirLen()+1+3+32+1+3, 32);
break;
}
else if (hRes != WBEM_E_NOT_FOUND)
{
break;
}
hRes = 0;
//Retrieve the class hash of the parent class
hRes = RetrieveParentClassHash(wszFullClassPath, wszFullKIPath + g_Glob.GetRootDirLen() + 1 + 3 + 32 + 1 + 3);
if (hRes == WBEM_S_NO_MORE_DATA)
{
hRes = 0;
break;
}
StringCchCatW(wszFullKIPath, wszFullKIPath.Length(), L"\\I_");
StringCchCopyNW(wszFullClassPath + g_Glob.GetRootDirLen() + 1 + 3 + 32 + 1 + 3,
wszFullClassPath.Length() - g_Glob.GetRootDirLen() - 1 - 3 - 32 - 1 - 3,
wszFullKIPath + g_Glob.GetRootDirLen() + 1 + 3 + 32 + 1 + 3,
32);
if (FAILED(hRes))
break;
} while (1);
return hRes;
}
HRESULT CLocalizationUpgrade::RetrieveParentClassHash(CFileName &wszFullClassPath,
wchar_t wszParentClassHash[MAX_HASH_LEN+1])
{
LONG lRes = 0;
HRESULT hRes = 0;
//Retrieve the class hash of the parent class
BYTE *pBuffer = NULL;
DWORD dwLen = 0;
lRes = g_Glob.m_FileCache.ReadObject(wszFullClassPath, &dwLen, &pBuffer, true);
if (lRes == ERROR_FILE_NOT_FOUND)
{
//This is probably a class from the system namespace!
CFileName wszSysClassPath;
if (wszSysClassPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszSysClassPath, wszSysClassPath.Length(), wszFullClassPath);
wmemcpy(wszSysClassPath+g_Glob.GetRootDirLen()+1+3, m_systemNamespaceHash, 32);
lRes = g_Glob.m_FileCache.ReadObject(wszSysClassPath, &dwLen, &pBuffer, true);
if (lRes)
return A51TranslateErrorCode(lRes);
}
else if (lRes)
{
return A51TranslateErrorCode(lRes);
}
CTempFreeMe tfm(pBuffer, dwLen);
//Null terminate the class name - safe to update buffer as it is always bigger than
//just the name!
wchar_t *wszSuperclassName = (wchar_t*)(pBuffer+sizeof(DWORD));
wszSuperclassName[*(DWORD*)pBuffer] = L'\0';
//Now we need to validate that this parent is generated using the OldHash
//method and not NewHash!
wchar_t wszOldHash[MAX_HASH_LEN+1];
wchar_t wszNewHash[MAX_HASH_LEN+1];
hRes = OldHash(wszSuperclassName, wszOldHash);
if (FAILED(hRes))
return hRes;
hRes = NewHash(wszSuperclassName, wszNewHash);
if (FAILED(hRes))
return hRes;
if (wcsncmp(L"", wszSuperclassName, *((DWORD*)pBuffer)) == 0)
{
StringCchCopyW(wszParentClassHash, MAX_HASH_LEN+1, wszNewHash);
return WBEM_S_NO_MORE_DATA;
}
if (wcscmp(wszOldHash, wszNewHash) == 0)
{
//No difference so nothing extra to do!
StringCchCopyW(wszParentClassHash, MAX_HASH_LEN+1, wszNewHash);
return WBEM_NO_ERROR;
}
//There is a possibility of using either new or old, so we need to dig deeper!
CFileName wszParentClass;
if (wszParentClass == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszParentClass, wszParentClass.Length(), wszFullClassPath);
wmemcpy(wszParentClass+g_Glob.GetRootDirLen()+1+3+32+1+3, wszOldHash, 32);
hRes = IndexExists(wszParentClass);
if (hRes == WBEM_E_NOT_FOUND)
{
//Try with the other hash!
wmemcpy(wszParentClass+g_Glob.GetRootDirLen()+1+3+32+1+3, wszNewHash, 32);
hRes = IndexExists(wszParentClass);
if (hRes == WBEM_NO_ERROR)
StringCchCopyW(wszParentClassHash, MAX_HASH_LEN+1, wszNewHash);
}
else if (hRes == WBEM_NO_ERROR)
{
StringCchCopyW(wszParentClassHash, MAX_HASH_LEN+1, wszOldHash);
}
return hRes;
}
HRESULT CLocalizationUpgrade::DeleteInstanceAsNamespace(CNamespaceHandle *pNs,
const wchar_t *wszClassInstanceLink)
{
HRESULT hRes = NULL;
//Retrieve the instance and get the key from it
CFileName wszKIInstanceLink;
if (wszKIInstanceLink == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszKIInstanceLink, wszKIInstanceLink.Length(),g_Glob.GetRootDir());
StringCchCatW(wszKIInstanceLink, wszKIInstanceLink.Length(), L"\\");
StringCchCatNW(wszKIInstanceLink, wszKIInstanceLink.Length(), wszClassInstanceLink, 3+32);
StringCchCatW(wszKIInstanceLink, wszKIInstanceLink.Length(), L"\\KI_");
StringCchCatW(wszKIInstanceLink, wszKIInstanceLink.Length(), m_namespaceClassHash);
StringCchCatW(wszKIInstanceLink, wszKIInstanceLink.Length(), L"\\I_");
StringCchCatW(wszKIInstanceLink, wszKIInstanceLink.Length(), wszClassInstanceLink + wcslen(wszClassInstanceLink) - 32);
_IWmiObject *pInstance = NULL;
hRes = pNs->FileToInstance(NULL, wszKIInstanceLink, NULL, 0, &pInstance, true);
if (FAILED(hRes))
return hRes;
CReleaseMe rm2(pInstance);
//Extract the string from the object
VARIANT vName;
VariantInit(&vName);
CClearMe cm(&vName);
hRes = pInstance->Get(L"Name", 0, &vName, NULL, NULL);
if(FAILED(hRes))
return hRes;
if(V_VT(&vName) != VT_BSTR)
{
return WBEM_E_INVALID_OBJECT;
}
//Build the full namespace name
size_t len = wcslen(pNs->m_wsNamespace) + 1 + wcslen(V_BSTR(&vName)) + 1;
wchar_t *wszNamespaceName = new wchar_t[len];
if (wszNamespaceName == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszNamespaceName, len, pNs->m_wsNamespace);
StringCchCatW(wszNamespaceName, len, L"\\");
StringCchCatW(wszNamespaceName, len, V_BSTR(&vName));
return DeleteNamespaceRecursive(wszNamespaceName);
}
//=====================================================================
//
// CLocalizationUpgrade::FixupIndexReferenceBlob
//
// Description:
// Retrieves the instance reference blob and fixes up the entry in
// there, then writes it back.
//
// Parameters:
// wszReferenceIndex - Path to an index reference path: ns\ki\ir\r
//
//=====================================================================
HRESULT CLocalizationUpgrade::FixupIndexReferenceBlob(CFileName &wszReferenceIndex)
{
HRESULT hRes =0;
//Create full path name
CFileName wszFullPath;
if (wszFullPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszReferenceIndex);
//remove the .X.Y.Z as this would screw everything up - both reading and writing
wcstok(wszFullPath + g_Glob.GetRootDirLen(), L".");
//Retrieve the blob
LONG lRes = 0;
DWORD dwLen = 0;
BYTE *pBuffer = NULL;
lRes = g_Glob.m_FileCache.ReadObject(wszFullPath, &dwLen, &pBuffer);
if (lRes)
return A51TranslateErrorCode(lRes);
CTempFreeMe tfm(pBuffer, dwLen);
//Find the path
BYTE *pPath = pBuffer;
DWORD dwLen2;
memcpy(&dwLen2, pPath, sizeof(DWORD));
pPath += (sizeof(wchar_t)*dwLen2) + sizeof(DWORD);
memcpy(&dwLen2, pPath, sizeof(DWORD));
pPath += (sizeof(wchar_t)*dwLen2) + sizeof(DWORD);
memcpy(&dwLen2, pPath, sizeof(DWORD));
pPath += (sizeof(wchar_t)*dwLen2) + sizeof(DWORD);
memcpy(&dwLen2, pPath, sizeof(DWORD));
pPath += sizeof(DWORD) + sizeof(L'\\');
dwLen2 --;
//Extract the path
CFileName wszInstPath, wszNewInstPath;
if ((wszInstPath == NULL) || (wszNewInstPath == NULL))
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyNW(wszInstPath, wszInstPath.Length(), (wchar_t*)pPath, dwLen2);
//fixup the path
bool bChanged = false;
hRes = FixupIndex(wszInstPath, wszNewInstPath, bChanged);
if (FAILED(hRes))
return hRes;
if (bChanged)
{
DEBUGTRACE((LOG_REPDRV, "Fixing up instance path in reference blob: %S\n", wszReferenceIndex));
//re-insert into the blob
wmemcpy((wchar_t*)pPath, wszNewInstPath, dwLen2);
//write back
lRes = g_Glob.m_FileCache.WriteObject(wszFullPath, NULL, dwLen, pBuffer);
if (lRes)
return A51TranslateErrorCode(lRes);
}
return 0;
}
//=====================================================================
//
// CLocalizationUpgrade::FixupInstanceBlob
//
// Description:
// Retrieves the instance blob and fixes up the class entry in
// there, then writes it back.
//
// Parameters:
// wszInstanceIndex - Path to an instance reference path: ns\ki\i
//
//=====================================================================
HRESULT CLocalizationUpgrade::FixupInstanceBlob(CFileName &wszInstanceIndex)
{
HRESULT hRes =0;
//Create full path name
CFileName wszFullPath;
if (wszFullPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wszFullPath, wszFullPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wszFullPath, wszFullPath.Length(), L"\\");
StringCchCatW(wszFullPath, wszFullPath.Length(), wszInstanceIndex);
//remove the .X.Y.Z as this would screw everything up - both reading and writing
wcstok(wszFullPath + g_Glob.GetRootDirLen(), L".");
//Retrieve the blob
LONG lRes = 0;
DWORD dwLen = 0;
BYTE *pBuffer = NULL;
lRes = g_Glob.m_FileCache.ReadObject(wszFullPath, &dwLen, &pBuffer);
if (lRes)
return A51TranslateErrorCode(lRes);
CTempFreeMe tfm(pBuffer, dwLen);
//Extract the class hash
wchar_t *wszClassHash = new wchar_t [MAX_HASH_LEN+1];
if (wszClassHash == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyNW(wszClassHash, MAX_HASH_LEN+1, (wchar_t*)pBuffer, 32);
//fixup the path
wchar_t *wszNewHash = NULL;
hRes = GetNewHash(wszClassHash, &wszNewHash);
if (hRes == WBEM_E_NOT_FOUND)
return WBEM_NO_ERROR;
else if (FAILED(hRes))
return hRes;
else
{
DEBUGTRACE((LOG_REPDRV, "Fixing up class hash in instance blob: %S\n", wszInstanceIndex));
//re-insert into the blob
wmemcpy((wchar_t*)pBuffer, wszNewHash, 32);
//Build the CI full path also as we need to write both back
CFileName wsCIPath;
if (wsCIPath == NULL)
return WBEM_E_OUT_OF_MEMORY;
StringCchCopyW(wsCIPath, wsCIPath.Length(), g_Glob.GetRootDir());
StringCchCatW(wsCIPath, wsCIPath.Length(), L"\\");
StringCchCatNW(wsCIPath, wsCIPath.Length(), wszInstanceIndex, 3+32);
StringCchCatW(wsCIPath, wsCIPath.Length(), L"\\CI_");
StringCchCatW(wsCIPath, wsCIPath.Length(), wszNewHash);
StringCchCatW(wsCIPath, wsCIPath.Length(), L"\\IL_");
StringCchCatN(wsCIPath, wsCIPath.Length(), wszInstanceIndex + 3+32+1+3+32+1+2, 32);
//write back
lRes = g_Glob.m_FileCache.WriteObject(wszFullPath, wsCIPath, dwLen, pBuffer);
if (lRes)
return A51TranslateErrorCode(lRes);
}
return 0;
}