Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

3481 lines
96 KiB

//***************************************************************************
//
// (c) 1999-2001 by Microsoft Corp. All Rights Reserved.
//
// repcache.cpp
//
// cvadai 19-Mar-99 Created as prototype for Quasar.
//
//***************************************************************************
#define _REPDRVR_CPP_
#pragma warning( disable : 4786 ) // identifier was truncated to 'number' characters in the
#pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class
#define _WIN32_DCOM
#include "precomp.h"
#include <repcache.h>
#include <wbemint.h>
#include <repdrvr.h>
#include <objbase.h>
#include <reputils.h>
#include <crc64.h>
#include <smrtptr.h>
typedef std::map<SQL_ID, bool> SQL_IDMap;
typedef std::map<SQL_ID, ULONG> SQLRefCountMap;
typedef std::map <SQL_ID, ClassData *> ClassCache;
typedef std::map <DWORD, DWORD> Properties;
typedef std::vector <SQL_ID> SQLIDs;
typedef std::map <_bstr_t, SQL_ID, _bstr_tNoCase> ClassNames;
#define MAX_WIDTH_SCHEMANAME 127 // Smallest property name for Jet / SQL
//***************************************************************************
//
// CObjectCache::CObjectCache
//
//***************************************************************************
CObjectCache::CObjectCache()
{
m_dwMaxSize = 262140;
InitializeCriticalSection(&m_cs);
m_dwUsed = 0;
}
//***************************************************************************
//
// CObjectCache::~CObjectCache
//
//***************************************************************************
CObjectCache::~CObjectCache()
{
EmptyCache();
DeleteCriticalSection(&m_cs);
}
//***************************************************************************
//
// CObjectCache::EmptyCache
//
//***************************************************************************
void CObjectCache::EmptyCache()
{
_WMILockit lkt(&m_cs);
m_ObjCache.Empty();
m_dwUsed = 0;
}
//***************************************************************************
//
// CObjectCache::GetObject
//
//***************************************************************************
HRESULT CObjectCache::GetObject (LPCWSTR lpPath, IWbemClassObject **ppObj,
SQL_ID *dScopeId)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
DWORD dwLock = 0;
SQL_ID dwID = 0;
dwID = CRC64::GenerateHashValue(lpPath);
hr = GetObject (dwID, ppObj, dScopeId);
return hr;
}
//***************************************************************************
//
// CObjectCache::GetObject
//
//***************************************************************************
HRESULT CObjectCache::GetObject (SQL_ID dObjectId, IWbemClassObject **ppObj,
SQL_ID *dScopeId)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
CacheInfo *pObj = NULL;
hr = m_ObjCache.Get(dObjectId, &pObj);
if (pObj)
{
pObj->m_tLastAccess = time(0);
if (ppObj)
{
hr = pObj->m_pObj->Clone(ppObj);
}
if (dScopeId)
*dScopeId = pObj->m_dScopeId;
}
else
hr = WBEM_E_NOT_FOUND;
return hr;
}
//***************************************************************************
//
// CObjectCache::GetObjectId
//
//***************************************************************************
HRESULT CObjectCache::GetObjectId (LPCWSTR lpPath, SQL_ID &dObjId, SQL_ID &dClassId, SQL_ID *dScopeId)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
if (lpPath == NULL)
hr = WBEM_E_INVALID_PARAMETER;
else
{
dObjId = CRC64::GenerateHashValue(lpPath);
CacheInfo *pTemp = NULL;
hr = m_ObjCache.Get(dObjId, &pTemp);
if (SUCCEEDED(hr))
{
dClassId = pTemp->m_dClassId;
if (dScopeId)
*dScopeId = pTemp->m_dScopeId;
}
}
return hr;
}
//***************************************************************************
//
// CObjectCache::PutObject
//
//***************************************************************************
HRESULT CObjectCache::PutObject (SQL_ID dID, SQL_ID dClassId, SQL_ID dScopeId, LPCWSTR lpPath, bool bStrongCache, IWbemClassObject *_pObj)
{
// The cache can't exceed the maximum byte size.
// and must set current used
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
bool bNew = false;
if (!_pObj)
return WBEM_E_INVALID_PARAMETER;
IWbemClassObject *pObj = NULL;
hr = _pObj->Clone(&pObj);
if (FAILED(hr))
return hr;
// Don't cache security descriptor
hr = pObj->Put(L"__SECURITY_DESCRIPTOR", 0, NULL, CIM_UINT8|CIM_FLAG_ARRAY);
CacheInfo *pTemp = NULL;
size_t NewSize;
hr = m_ObjCache.Get(dID, &pTemp);
if (FAILED(hr))
{
bNew = true;
NewSize = GetSize(pObj) + sizeof(CacheInfo) + wcslen(lpPath);
hr = WBEM_S_NO_ERROR;
}
else
NewSize = (GetSize(pObj) - GetSize(pTemp->m_pObj));
if ((NewSize + m_dwUsed) > m_dwMaxSize)
hr = ResizeCache(NewSize, dID, bStrongCache);
if (SUCCEEDED(hr) && NewSize)
{
if (pTemp)
{
IWbemClassObject *pTempObj = pTemp->m_pObj;
if (pTempObj)
pTempObj->Release();
}
else
{
pTemp = new CacheInfo;
if (!pTemp)
return WBEM_E_OUT_OF_MEMORY;
pTemp->m_bStrong = bStrongCache;
}
pTemp->m_dObjectId = dID;
pTemp->m_dClassId = dClassId;
pTemp->m_dScopeId = dScopeId;
pTemp->m_tLastAccess = time(0);
delete pTemp->m_sPath;
pTemp->m_sPath = Macro_CloneLPWSTR(lpPath);
pTemp->m_pObj = pObj;
pTemp->m_bStrong = ((int)pTemp->m_bStrong > (int)bStrongCache) ? pTemp->m_bStrong : bStrongCache; // Strong has precendence.
if (bNew)
{
hr = m_ObjCache.Insert(dID, pTemp);
}
m_dwUsed += NewSize;
}
return hr;
}
//***************************************************************************
//
// CObjectCache::DeleteObject
//
//***************************************************************************
HRESULT CObjectCache::DeleteObject (SQL_ID dID)
{
// Set current used
// Recalculate the number of bytes used.
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
CacheInfo *pObj = NULL;
hr = m_ObjCache.Get(dID, &pObj);
if (SUCCEEDED(hr))
{
if (pObj->m_pObj)
{
m_dwUsed -= GetSize(pObj->m_pObj);
// pObj->m_pObj->Release();
}
m_dwUsed -= sizeof(CacheInfo);
m_dwUsed -= wcslen(pObj->m_sPath);
hr = m_ObjCache.Delete(dID);
}
if (hr == WBEM_E_NOT_FOUND)
hr = WBEM_S_NO_ERROR;
return hr;
}
//***************************************************************************
//
// CObjectCache::ObjectExists
//
//***************************************************************************
bool CObjectCache::ObjectExists (SQL_ID dObjectId)
{
return (m_ObjCache.Exists(dObjectId));
}
//***************************************************************************
//
// CObjectCache::SetCacheSize
//
//***************************************************************************
HRESULT CObjectCache::SetCacheSize(const DWORD dwMaxSize)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
// Physically resize the cache.
// If that works, set the variable
if (dwMaxSize == 0)
{
_WMILockit lkt(&m_cs);
EmptyCache();
}
else if (m_dwMaxSize > dwMaxSize)
{
DWORD dwDiff = m_dwMaxSize - dwMaxSize;
hr = ResizeCache(dwDiff, 0);
}
if (SUCCEEDED(hr))
m_dwMaxSize = dwMaxSize;
return hr;
}
//***************************************************************************
//
// CObjectCache::GetCurrentUsage
//
//***************************************************************************
HRESULT CObjectCache::GetCurrentUsage(DWORD &dwBytesUsed)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
dwBytesUsed = m_dwUsed;
return hr;
}
//***************************************************************************
//
// CObjectCache::GetCacheSize
//
//***************************************************************************
HRESULT CObjectCache::GetCacheSize(DWORD &dwSizeInBytes)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
dwSizeInBytes = m_dwMaxSize;
return hr;
}
//***************************************************************************
//
// CObjectCache::FindFirst
//
//***************************************************************************
HRESULT CObjectCache::FindFirst(SQL_ID &dObjectId, SQL_ID &dClassId, SQL_ID *dScopeId)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
CListElement *pTemp = NULL;
pTemp = m_ObjCache.FindFirst();
if (pTemp != NULL)
{
CacheInfo *pTmp = (CacheInfo *)pTemp->m_pObj;
pTmp->m_tLastAccess = time(0);
dObjectId = pTmp->m_dObjectId;
dClassId = pTmp->m_dClassId;
if (dScopeId)
*dScopeId = pTmp->m_dScopeId;
delete pTemp;
}
else
hr = WBEM_E_NOT_FOUND;
return hr;
}
//***************************************************************************
//
// CObjectCache::FindNext
//
//***************************************************************************
HRESULT CObjectCache::FindNext (SQL_ID dLastId, SQL_ID &dObjectId, SQL_ID &dClassId, SQL_ID *dScopeId)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
CListElement *pTemp = NULL;
pTemp = m_ObjCache.FindNext(dLastId);
if (pTemp != NULL)
{
CacheInfo *pTmp = (CacheInfo *)pTemp->m_pObj;
pTmp->m_tLastAccess = time(0);
dObjectId = pTmp->m_dObjectId;
dClassId = pTmp->m_dClassId;
if (dScopeId)
*dScopeId = pTmp->m_dScopeId;
delete pTemp;
}
else
hr = WBEM_E_NOT_FOUND;
return hr;
}
//***************************************************************************
//
// CObjectCache::GetSize
//
//***************************************************************************
DWORD CObjectCache::GetSize(IWbemClassObject *pObj)
{
DWORD dwRet = 0;
_IWmiObject *pInt = NULL;
HRESULT hr = 0;
hr = pObj->QueryInterface(IID__IWmiObject, (void **)&pInt);
CReleaseMe rInt (pInt);
if (SUCCEEDED(hr))
{
/* No idea how big this can be. Is there a better way to do this?*/
DWORD dwSize = 0;
pInt->GetObjectMemory(NULL, dwSize, &dwRet);
}
return dwRet;
}
//***************************************************************************
//
// CObjectCache::ResizeCache
//
//***************************************************************************
HRESULT CObjectCache::ResizeCache(DWORD dwReqBytes, SQL_ID dLeave, bool bForce)
{
HRESULT hr = WBEM_S_NO_ERROR;
// Try to free up dwReqBytes, starting with
// the oldest weakly cached objects.
// ========================================
while ((dwReqBytes + m_dwUsed) > m_dwMaxSize)
{
hr = WBEM_E_BUFFER_TOO_SMALL;
CListElement *pTemp = NULL;
pTemp = m_ObjCache.FindFirst();
while (pTemp != NULL)
{
SQL_ID dID = pTemp->m_dId;
if (dID && dID != dLeave)
{
CacheInfo *pTmp = (CacheInfo *)pTemp->m_pObj;
if (!pTmp->m_bStrong)
DeleteObject(dID);
if ((dwReqBytes + m_dwUsed) <= m_dwMaxSize)
{
hr = WBEM_S_NO_ERROR;
break;
}
}
delete pTemp;
pTemp = m_ObjCache.FindNext(dID);
}
if ((dwReqBytes + m_dwUsed) <= m_dwMaxSize)
{
hr = WBEM_S_NO_ERROR;
break;
}
// Only remove other strong cached elements
// if we have to.
// =========================================
if (bForce)
{
pTemp = m_ObjCache.FindFirst();
while (pTemp != NULL)
{
SQL_ID dID = pTemp->m_dId;
if (dID != dLeave)
{
DeleteObject(dID);
if ((dwReqBytes + m_dwUsed) <= m_dwMaxSize)
{
hr = WBEM_S_NO_ERROR;
break;
}
}
pTemp = m_ObjCache.FindNext(dID);
}
}
break; // if here, cache is empty.
}
return hr;
}
//***************************************************************************
//
// LockData::GetMaxLock
//
//***************************************************************************
DWORD LockData::GetMaxLock(bool bImmediate, bool bSubScopeOnly)
{
DWORD dwRet = 0;
for (int i = 0; i < m_List.size(); i++)
{
LockItem *pItem = m_List.at(i);
if (pItem)
{
if (bImmediate && pItem->m_bLockOnChild)
continue;
if (bSubScopeOnly && !(pItem->m_dwHandleType & WMIDB_HANDLE_TYPE_SUBSCOPED))
continue;
dwRet = GetMaxBytes(pItem->m_dwHandleType, dwRet);
}
}
return dwRet;
}
//***************************************************************************
//
// LockData::LockExists
//
//***************************************************************************
bool LockData::LockExists (DWORD dwHandleType)
{
bool bRet = false;
for (int i = 0; i < m_List.size(); i++)
{
LockItem *pItem = m_List.at(i);
if (pItem)
{
if (!pItem->m_bLockOnChild)
{
if ((pItem->m_dwHandleType & dwHandleType) == dwHandleType)
{
bRet = true;
break;
}
}
}
}
return bRet;
}
//***************************************************************************
//
// CLockCache::~CLockCache
//
//***************************************************************************
CLockCache::~CLockCache()
{
DeleteCriticalSection(&m_cs);
}
//***************************************************************************
//
// CLockCache::GetHandle
//
//***************************************************************************
HRESULT CLockCache::GetHandle(SQL_ID ObjId, DWORD dwType, IWmiDbHandle **ppRet)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
*ppRet = NULL;
LockData *temp = NULL;
hr = m_Cache.Get(ObjId, &temp);
if (SUCCEEDED(hr))
{
LockData *pData = (LockData *)temp;
if (pData)
{
LockItem *pItem = NULL;
for (int i = 0; i < pData->m_List.size(); i++)
{
pItem = pData->m_List.at(i);
if (pItem->m_dwHandleType == dwType)
{
if (pItem->m_pObj)
{
pItem->m_pObj->AddRef();
*ppRet = (IWmiDbHandle *)pItem->m_pObj;
}
break;
}
}
}
}
return hr;
}
//***************************************************************************
//
// CLockCache::AddLock
//
//***************************************************************************
HRESULT CLockCache::AddLock(bool bImmediate, SQL_ID ObjId, DWORD Type, IUnknown *pUnk, SQL_ID dNsId,
SQL_ID dClassId, CSchemaCache *pCache, bool bChg, bool bChildLock, SQL_ID SourceId,
DWORD *dwVersion)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
SQL_ID dParentId = 0;
if (bChildLock)
Type &= ~WMIDB_HANDLE_TYPE_AUTODELETE;
if (Type & WMIDB_HANDLE_TYPE_AUTODELETE)
{
DWORD dwParentLock = 0;
GetCurrentLock(dNsId, false, dwParentLock);
if (!(dwParentLock & WMIDB_HANDLE_TYPE_AUTODELETE))
{
GetCurrentLock(dClassId, false, dwParentLock);
if (!(dwParentLock & WMIDB_HANDLE_TYPE_AUTODELETE))
{
SQL_ID ClassId = dClassId, dParentId = 0;
while (SUCCEEDED(pCache->GetParentId(ClassId, dParentId)))
{
GetCurrentLock(dParentId, false, dwParentLock);
if (dwParentLock & WMIDB_HANDLE_TYPE_AUTODELETE)
break;
ClassId = dParentId;
}
}
}
if (dwParentLock & WMIDB_HANDLE_TYPE_AUTODELETE)
return WBEM_E_INVALID_HANDLE_REQUEST;
}
// If this is a cookie, we really don't
// care what locks exist, and we do
// not need to add it to the list.
// Unless its an auto-delete handle...
// ======================================
if ((Type & 0xF)== WMIDB_HANDLE_TYPE_COOKIE &&
!(Type & WMIDB_HANDLE_TYPE_AUTODELETE))
return WBEM_S_NO_ERROR;
// If this is a class,
// use its own ID as the Class ID.
// ==============================
if (dClassId == 1)
dClassId = ObjId;
LockData *temp = NULL;
hr = m_Cache.Get(ObjId, &temp);
LockData *pData = NULL;
if (SUCCEEDED(hr))
{
pData = (LockData *)temp;
}
else
{
hr = WBEM_S_NO_ERROR;
pData = new LockData;
if (pData)
{
pData->m_dObjectId = ObjId;
pData->m_dwStatus = 0; // Calculated at the end.
pData->m_dwNumLocks = 0;
pData->m_dwCompositeStatus = 0;
pData->m_dwVersion = 1;
pData->m_dwCompositeVersion = 1;
m_Cache.Insert(ObjId, pData);
// Load the owner list
if (!bChildLock)
{
SQL_ID dParent = 0, dClass = 0;
if (dClassId != 2)
{
pCache->GetParentNamespace(dNsId, dParent, &dClass);
while (dParent) // Don't propogate locks across namespaces!
{
pData->m_OwnerIds[dParent];
if (dClass == 2)
break;
pCache->GetParentNamespace(dParent, dParent, &dClass);
}
pData->m_OwnerIds[dNsId] = true;
}
if (dClassId != ObjId)
pData->m_OwnerIds[dClassId] = true;
while (SUCCEEDED(pCache->GetParentId(dClassId, dParentId)))
{
pData->m_OwnerIds[dParentId] = 1;
dClassId = dParentId;
}
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
if (SUCCEEDED(hr))
{
// Make sure the parent objects aren't directly locked.
// ====================================================
if (!CanLockHandle(ObjId, Type, bImmediate, false))
hr = WBEM_E_ACCESS_DENIED;
if (SUCCEEDED(hr))
{
SQL_IDMap::iterator item = pData->m_OwnerIds.begin();
while (item != pData->m_OwnerIds.end())
{
if (!CanLockHandle((*item).first, (Type &~WMIDB_HANDLE_TYPE_SUBSCOPED), true, true))
{
hr = WBEM_E_ACCESS_DENIED;
break;
}
item++;
}
}
// If all that worked, we can now attempt to
// add the lock to this object.
// =========================================
if (SUCCEEDED(hr))
{
LockItem *pItem = NULL;
// Now we need to see if this lock already exists
// for this handle type.
// ==============================================
pItem = new LockItem;
if (pItem)
{
pItem->m_dwHandleType = Type;
pItem->m_pObj = pUnk;
pItem->m_dSourceId = SourceId;
pItem->m_dwVersion = pData->m_dwVersion;
if (bChildLock)
pItem->m_bLockOnChild = true;
else
pItem->m_bLockOnChild = false;
// Attempt to lock all the parent objects.
// Pass in zeroes for namespace and class Ids
// so we don't recurse.
if (dNsId && dClassId != 2)
{
hr = AddLock(true, dNsId, (Type &~WMIDB_HANDLE_TYPE_SUBSCOPED), pUnk, 0, 0, 0, bChg, true, ObjId);
if (SUCCEEDED(hr))
{
SQL_ID dParent = 0, dClass = 0;
pCache->GetParentNamespace(dNsId, dParent, &dClass);
while (dParent)
{
hr = AddLock(true, dParent, (Type &~WMIDB_HANDLE_TYPE_SUBSCOPED), pUnk, 0, 0, 0, bChg, true, ObjId);
// Don't propogate locks across namespaces.
if (dClass == 2)
break;
pCache->GetParentNamespace(dParent, dParent, &dClass);
}
}
}
if (dClassId != 1 && dClassId != 0) // Disregard the __Class class
{
if (dClassId != ObjId) // We already saved this one.
hr = AddLock(true, dClassId, (Type &~WMIDB_HANDLE_TYPE_SUBSCOPED), pUnk, 0, 0, 0, bChg, true, ObjId);
hr = pCache->GetParentId(dClassId, dParentId);
while (SUCCEEDED(hr))
{
hr = AddLock(true, dParentId, (Type &~WMIDB_HANDLE_TYPE_SUBSCOPED), pUnk, 0, 0, 0, bChg, true, ObjId);
hr = pCache->GetParentId(dParentId, dParentId);
}
hr = WBEM_S_NO_ERROR;
}
// If this is a blocking handle, make sure
// we lock out any existing handles on child
// objects. If there any other locks on sub
// components of this object, they should be
// in the list at this point.
// If this is a versioned handle, that needs
// to be invalidated if there is an immediate
// change to the parent object!!
if (Type & WMIDB_HANDLE_TYPE_SUBSCOPED)
{
for (int i = 0; i < pData->m_List.size(); i++)
{
LockItem *pTemp = pData->m_List.at(i);
if (pTemp && pTemp->m_dSourceId != 0)
AddLock(true, pTemp->m_dSourceId, (Type &~WMIDB_HANDLE_TYPE_SUBSCOPED), pUnk, 0, 0, 0, bChg, false, ObjId);
}
}
// Only increment version type if this object changed,
// or if there is an outstanding versioned|subscoped
// handle type on this object and a child object chgd.
// ====================================================
if (bChg)
{
if (!bChildLock)
{
pData->m_dwVersion++;
pData->m_dwCompositeVersion++;
pItem->m_dwVersion = pData->m_dwVersion;
}
else if (bChildLock && pData->LockExists(WMIDB_HANDLE_TYPE_VERSIONED|WMIDB_HANDLE_TYPE_SUBSCOPED))
pData->m_dwCompositeVersion++;
}
pData->m_List.push_back(pItem);
pData->m_dwNumLocks++;
// Update the lock type
// ====================
pData->m_dwStatus = pData->GetMaxLock(true);
pData->m_dwCompositeStatus = pData->GetMaxLock(false);
if (dwVersion)
{
if (bImmediate)
*dwVersion = pData->m_dwVersion;
else
*dwVersion = pData->m_dwCompositeVersion;
}
}
}
}
return hr;
}
//***************************************************************************
//
// CLockCache::DeleteLock
//
//***************************************************************************
HRESULT CLockCache::DeleteLock(SQL_ID ObjId, bool bChildLock, DWORD HandleType, bool bDelChildren, void *pObj)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
// If this is the only lock,
// remove the whole thing.
// Otherwise just remove the item
// Update the master lock
// ==============================
LockData *pData = NULL;
LockData *temp = NULL;
hr = m_Cache.Get(ObjId, &temp);
if (SUCCEEDED(hr))
{
pData = (LockData *)temp;
// If they specify a handle of zero,
// we delete all entries for this ID.
if (HandleType)
{
BOOL bFound = FALSE;
LockItem *pItem = NULL;
for (int i = 0; i < pData->m_List.size(); i++)
{
pItem = pData->m_List.at(i);
if (pItem->m_dwHandleType == HandleType && (pItem->m_pObj == pObj))
{
if (bChildLock && !pItem->m_bLockOnChild)
continue;
if (pItem->m_pObj)
((CWmiDbHandle *)pItem->m_pObj)->m_dwHandleType = 0;
delete pItem;
pData->m_List.erase(&pData->m_List.at(i));
pData->m_dwNumLocks--;
bFound = TRUE;
break;
}
}
if (!pObj && !bFound)
{
for (int i = 0; i < pData->m_List.size(); i++)
{
pItem = pData->m_List.at(i);
if (pItem->m_dwHandleType == HandleType)
{
if (bChildLock && !pItem->m_bLockOnChild)
continue;
delete pItem;
pData->m_List.erase(&pData->m_List.at(i));
pData->m_dwNumLocks--;
bFound = TRUE;
break;
}
}
}
if (bDelChildren)
{
// Remove this lock from all the
// owner objects (namespaces, classes)
// ===================================
SQL_IDMap::iterator walk = pData->m_OwnerIds.begin();
while (walk != pData->m_OwnerIds.end())
{
SQL_ID dId = (*walk).first;
hr = DeleteLock(dId, true, (HandleType &~WMIDB_HANDLE_TYPE_SUBSCOPED), false, pObj);
if (FAILED(hr))
break;
walk++;
}
// Remove this lock from the child
// objects that we previously
// locked out.
// ===============================
if (HandleType & WMIDB_HANDLE_TYPE_SUBSCOPED)
{
for (int i = 0; i < pData->m_List.size(); i++)
{
LockItem *pTemp = pData->m_List.at(i);
if (pTemp && pTemp->m_dSourceId != 0)
DeleteLock(pTemp->m_dSourceId, true, (HandleType &~WMIDB_HANDLE_TYPE_SUBSCOPED), false, pObj);
}
}
}
// If that worked, we can
// remove this entry from the
// the lock cache.
// ===========================
if (SUCCEEDED(hr))
{
pData->m_dwStatus = pData->GetMaxLock(true);
pData->m_dwCompositeStatus = pData->GetMaxLock(false);
// Delete if this is the last lock...
if (!pData->m_dwNumLocks)
hr = m_Cache.Delete(ObjId);
}
}
else
{
// This object was deleted. We have to
// invalidate all the handles for this object.
// ==========================================
LockItem *pItem = NULL;
for (int i = 0; i < pData->m_List.size(); i++)
{
pItem = pData->m_List.at(i);
if (pItem && pItem->m_pObj)
((CWmiDbHandle *)pItem->m_pObj)->m_dwHandleType = WMIDB_HANDLE_TYPE_INVALID;
}
hr = m_Cache.Delete(ObjId);
}
}
else if (hr == WBEM_E_NOT_FOUND)
hr = WBEM_S_NO_ERROR;
return hr;
}
//***************************************************************************
//
// CLockCache::GetCurrentLock
//
//***************************************************************************
HRESULT CLockCache::GetCurrentLock(SQL_ID ObjId, bool bImmediate, DWORD &HandleType, DWORD *Version)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
LockData *pData = NULL;
LockData *temp;
hr = m_Cache.Get(ObjId, &temp);
if (SUCCEEDED(hr))
{
pData = (LockData *)temp;
if (bImmediate)
HandleType = pData->m_dwStatus;
else
HandleType = pData->m_dwCompositeStatus;
if (Version)
{
if (bImmediate)
*Version = pData->m_dwVersion;
else
*Version = pData->m_dwCompositeVersion;
}
}
return hr;
}
//***************************************************************************
//
// CLockCache::GetAllLocks
//
//***************************************************************************
HRESULT CLockCache::GetAllLocks(SQL_ID ObjId, SQL_ID ClassId, SQL_ID NsId, CSchemaCache *pSchema,
bool bImmediate, DWORD &HandleType, DWORD *Version)
{
HRESULT hr = WBEM_S_NO_ERROR;
DWORD dwCurrType = 0, dwTemp = 0;
SQL_ID dParentId = 0;
hr = GetCurrentLock(ObjId, bImmediate, dwCurrType, Version);
if (SUCCEEDED(GetCurrentLock(ClassId, bImmediate, dwTemp)))
{
if (dwTemp & WMIDB_HANDLE_TYPE_SUBSCOPED)
dwCurrType = GetMaxBytes(dwCurrType, dwTemp);
}
if (SUCCEEDED(GetCurrentLock(NsId, bImmediate, dwTemp)))
{
if (dwTemp & WMIDB_HANDLE_TYPE_SUBSCOPED)
dwCurrType = GetMaxBytes(dwCurrType, dwTemp);
}
if (ClassId)
{
while (SUCCEEDED(pSchema->GetParentId(ClassId, dParentId)))
{
if (SUCCEEDED(GetCurrentLock(dParentId, bImmediate, dwTemp)))
{
if (dwTemp & WMIDB_HANDLE_TYPE_SUBSCOPED)
dwCurrType = GetMaxBytes(dwCurrType, dwTemp);
}
ClassId = dParentId;
}
}
HandleType = dwCurrType;
return hr;
}
//***************************************************************************
//
// CLockCache::CanLockHandle
//
//***************************************************************************
bool CLockCache::CanLockHandle (SQL_ID ObjId, DWORD RequestedHandleType, bool bImmediate, bool bSubscopedOnly)
{
bool bRet = true; // If not found, they can definitely lock it...
DWORD dwCurrType = 0;
_WMILockit lkt(&m_cs);
LockData *pData = NULL;
LockData *temp;
HRESULT hr = m_Cache.Get(ObjId, &temp);
if (SUCCEEDED(hr))
{
pData = (LockData *)temp;
dwCurrType = pData->GetMaxLock(bImmediate, bSubscopedOnly);
if (bRet)
{
switch (dwCurrType & 0xF)
{
case WMIDB_HANDLE_TYPE_COOKIE:
case WMIDB_HANDLE_TYPE_VERSIONED: // Weak handles always succeed.
bRet = true;
break;
case WMIDB_HANDLE_TYPE_EXCLUSIVE: // Exclusive access.
if ((RequestedHandleType & 0xF) != WMIDB_HANDLE_TYPE_COOKIE &&
(RequestedHandleType & 0xF) != WMIDB_HANDLE_TYPE_VERSIONED)
bRet = false;
break;
case WMIDB_HANDLE_TYPE_PROTECTED: // Read only
if ((RequestedHandleType & 0xF) != WMIDB_HANDLE_TYPE_EXCLUSIVE)
bRet = true;
else
bRet = false;
break;
default:
bRet = true;
break;
}
}
}
return bRet;
}
//***************************************************************************
//
// CLockCache::CanRenderObject
//
//***************************************************************************
bool CLockCache::CanRenderObject (SQL_ID ObjId, SQL_ID ClassId, SQL_ID NsId, CSchemaCache *pSchema, DWORD RequestedHandleType, bool bImmediate)
{
bool bRet = true; // If not found, they can definitely lock it...
DWORD dwCurrType;
SQL_ID dParentId = 0;
// Get the lock for this
// object and all its ancestors.
// =============================
HRESULT hr = GetAllLocks(ObjId, ClassId, NsId, pSchema, bImmediate, RequestedHandleType);
if (SUCCEEDED(hr))
{
dwCurrType = RequestedHandleType & 0xF;
switch (dwCurrType)
{
case WMIDB_HANDLE_TYPE_COOKIE:
case WMIDB_HANDLE_TYPE_VERSIONED: // Weak handles always succeed.
bRet = true;
break;
case WMIDB_HANDLE_TYPE_EXCLUSIVE: // Exclusive access.
bRet = false;
break;
case WMIDB_HANDLE_TYPE_PROTECTED: // Read only
if ((RequestedHandleType & 0xF) != WMIDB_HANDLE_TYPE_EXCLUSIVE)
bRet = true;
else
bRet = false;
break;
default:
bRet = true;
break;
}
}
return bRet;
}
//***************************************************************************
//
// CLockCache::IncrementVersion
//
//***************************************************************************
HRESULT CLockCache::IncrementVersion(SQL_ID ObjId)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
LockData *pData = NULL;
LockData *temp;
hr = m_Cache.Get(ObjId, &temp);
if (SUCCEEDED(hr))
{
pData = (LockData *)temp;
pData->m_dwVersion++;
pData->m_dwCompositeVersion++;
}
return hr;
}
//***************************************************************************
//
// PropertyData::PropertyData
//
//***************************************************************************
PropertyData::PropertyData()
{
m_dwClassID = 0;
m_dwStorageType = 0;
m_dwCIMType = 0;
m_dwFlags = 0;
m_dwRefClassID = 0;
m_dwQPropID = 0;
m_dwFlavor = 0;
m_sPropertyName = NULL;
m_sDefaultValue = NULL;
}
//***************************************************************************
//
// PropertyData::GetSize
//
//***************************************************************************
DWORD PropertyData::GetSize()
{
DWORD dwSize = 0;
if (m_sPropertyName)
dwSize += wcslen(m_sPropertyName)*2;
else
dwSize += sizeof(LPWSTR);
if (m_sDefaultValue)
dwSize += wcslen(m_sDefaultValue)*2;
else
dwSize += sizeof(LPWSTR);
dwSize += sizeof(m_dwClassID) +
sizeof(m_dwStorageType) +
sizeof(m_dwCIMType) +
sizeof(m_dwFlags) +
sizeof(m_dwRefClassID) +
sizeof(m_dwQPropID) +
sizeof(m_dwFlavor);
return dwSize;
}
//***************************************************************************
//
// ClassData::ClassData
//
//***************************************************************************
ClassData::ClassData()
{
m_dwClassID = 0;
m_dwSuperClassID = 0;
m_dwDynastyID = 0;
m_dwScopeID = 0;
m_dwFlags = 0;
m_Properties = new PropertyList[10];
m_dwNumProps = 0;
m_dwArraySize = 10;
m_sName = NULL;
m_sObjectPath = NULL;
}
//***************************************************************************
//
// ClassData::GetSize
//
//***************************************************************************
DWORD ClassData::GetSize()
{
DWORD dwSize = 0;
if (m_sName)
dwSize += wcslen(m_sName)*2;
else
dwSize += sizeof(LPWSTR);
if (m_sObjectPath)
dwSize += wcslen(m_sObjectPath)*2;
else
dwSize += dwSize += sizeof(LPWSTR);
dwSize += sizeof(m_dwClassID) +
sizeof(m_dwSuperClassID) +
sizeof(m_dwDynastyID) +
sizeof(m_dwScopeID) +
sizeof(m_dwNumProps) +
sizeof(m_dwArraySize) +
sizeof(m_dwFlags);
for (int i=0; i < m_dwNumProps; i++)
{
dwSize += sizeof(PropertyList);
}
return dwSize;
}
//***************************************************************************
//
// ClassData::InsertProperty
//
//***************************************************************************
void ClassData::InsertProperty (DWORD PropId, BOOL bIsKey)
{
BOOL bFound = FALSE;
if (m_Properties)
{
for (int i = 0; i < m_dwNumProps; i++)
{
if (m_Properties[i].m_dwPropertyId == PropId)
{
bFound = TRUE;
m_Properties[i].m_bIsKey = bIsKey;
break;
}
}
if (!bFound)
{
if (m_dwNumProps == m_dwArraySize)
{
PropertyList *pList = new PropertyList[m_dwArraySize + 10];
if (pList)
{
memcpy(pList, m_Properties, sizeof(PropertyList) * m_dwArraySize);
delete m_Properties;
m_Properties = pList;
m_dwArraySize += 10;
}
}
m_Properties[m_dwNumProps].m_dwPropertyId = PropId;
m_Properties[m_dwNumProps].m_bIsKey = bIsKey;
m_dwNumProps++;
}
}
}
void ClassData::DeleteProperty (DWORD PropId)
{
// Should we clean up the gaps here?
if (m_Properties)
{
for (int i = 0; i < m_dwNumProps; i++)
{
if (m_Properties[i].m_dwPropertyId == PropId)
{
m_Properties[i].m_dwPropertyId = 0;
m_Properties[i].m_bIsKey = 0;
break;
}
}
}
}
void ClassData::InsertDerivedClass (SQL_ID dID)
{
BOOL bFound = FALSE;
for (int i = 0; i < m_DerivedIDs.size(); i++)
{
if (m_DerivedIDs.at(i) == dID)
{
bFound = TRUE;
break;
}
}
if (!bFound)
m_DerivedIDs.push_back(dID);
}
void ClassData::DeleteDerivedClass (SQL_ID dID)
{
for (int i = 0; i < m_DerivedIDs.size(); i++)
{
if (m_DerivedIDs.at(i) == dID)
{
m_DerivedIDs.erase(&m_DerivedIDs.at(i));
break;
}
}
}
//***************************************************************************
//
// NamespaceData::GetSize
//
//***************************************************************************
DWORD NamespaceData::GetSize()
{
DWORD dwSize = 0;
if (m_sNamespaceName)
dwSize += wcslen(m_sNamespaceName)*2;
else
dwSize += sizeof(LPWSTR);
if (m_sNamespaceKey)
dwSize += wcslen(m_sNamespaceKey)*2;
else
dwSize += sizeof(LPWSTR);
dwSize += sizeof(m_dNamespaceId) +
sizeof(m_dParentId) +
sizeof(m_dClassId);
return dwSize;
}
//***************************************************************************
//
// CSchemaCache::CSchemaCache
//
//***************************************************************************
CSchemaCache::CSchemaCache()
{
m_dwTotalSize = 0;
m_dwMaxSize = 204800;
InitializeCriticalSection(&m_cs);
}
//***************************************************************************
//
// CSchemaCache::~CSchemaCache
//
//***************************************************************************
CSchemaCache::~CSchemaCache()
{
EmptyCache();
DeleteCriticalSection(&m_cs);
}
//***************************************************************************
//
// CSchemaCache::EmptyCache
//
//***************************************************************************
void CSchemaCache::EmptyCache()
{
_WMILockit lkt(&m_cs);
m_Cache.Empty();
m_CCache.Empty();
m_CIndex.clear();
m_dwTotalSize = 0;
}
//***************************************************************************
//
// CSchemaCache::GetPropertyInfo
//
//***************************************************************************
HRESULT CSchemaCache::GetPropertyInfo (DWORD dwPropertyID, _bstr_t *sName, SQL_ID *dwClassID, DWORD *dwStorageType,
DWORD *dwCIMType, DWORD *dwFlags, SQL_ID *dwRefClassID, _bstr_t *sDefaultValue, DWORD *pdwRefId, DWORD *pdwFlavor)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
PropertyData *pData = NULL;
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pData);
if (pData != NULL)
{
if (sName) *sName = pData->m_sPropertyName;
if (dwClassID) *dwClassID = pData->m_dwClassID;
if (dwStorageType) *dwStorageType = pData->m_dwStorageType;
if (dwCIMType) *dwCIMType = pData->m_dwCIMType;
if (dwFlags) *dwFlags = pData->m_dwFlags;
if (dwRefClassID) *dwRefClassID = pData->m_dwRefClassID;
if (sDefaultValue) *sDefaultValue = pData->m_sDefaultValue;
if (pdwRefId) *pdwRefId = pData->m_dwQPropID;
if (pdwFlavor) *pdwFlavor = pData->m_dwFlavor;
}
else
hr = WBEM_E_NOT_FOUND;
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetPropertyID
//
//***************************************************************************
HRESULT CSchemaCache::GetPropertyID (LPCWSTR lpName, SQL_ID dClassID, DWORD dwFlags, CIMTYPE ct,
DWORD &PropertyID, SQL_ID *ActualClass, DWORD *Flags, DWORD *Type, BOOL bSys)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
_bstr_t sIndexKey;
SQL_ID dCurrClass = dClassID;
PropertyID = 0;
if (lpName && wcslen(lpName) > 2 && lpName[0] == L'_' && lpName[1] == L'_')
bSys = TRUE;
// Try to find this property in this class,
// or its parent classes.
if (dClassID)
{
ClassData *pClass = NULL;
m_CCache.Get(dClassID, &pClass);
while (pClass)
{
for (int i = 0; i < pClass->m_dwNumProps; i++)
{
DWORD dwPropertyID = pClass->m_Properties[i].m_dwPropertyId;
PropertyData *pPData = NULL;
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pPData);
if (!pPData)
continue;
if (!_wcsnicmp(pPData->m_sPropertyName, lpName, MAX_WIDTH_SCHEMANAME))
{
BOOL bMatch = TRUE;
if ((dwFlags & REPDRVR_FLAG_NONPROP) ==
(pPData->m_dwFlags & REPDRVR_FLAG_NONPROP))
{
if (dwFlags & REPDRVR_FLAG_NONPROP)
{
if (ct != REPDRVR_IGNORE_CIMTYPE)
{
if (ct != pPData->m_dwCIMType)
bMatch = FALSE;
}
}
if (bMatch)
{
if (ActualClass)
*ActualClass = dCurrClass;
if (Flags)
*Flags = pPData->m_dwFlags;
if (Type)
*Type = pPData->m_dwStorageType;
PropertyID = dwPropertyID;
}
break;
}
}
}
dCurrClass = pClass->m_dwSuperClassID;
if (PropertyID || !dCurrClass)
break;
pClass = NULL;
m_CCache.Get(dCurrClass, &pClass);
}
}
else
{
CListElement *pNext = m_Cache.FindFirst();
while (pNext)
{
SQL_ID dLast = pNext->m_dId;
PropertyData *pTemp = (PropertyData *)pNext->m_pObj;
if (pTemp)
{
if (!_wcsnicmp(pTemp->m_sPropertyName,lpName, MAX_WIDTH_SCHEMANAME))
{
PropertyID = pNext->m_dId;
if (ActualClass)
*ActualClass = pTemp->m_dwClassID;
if (Flags)
*Flags = pTemp->m_dwFlags;
if (Type)
*Type = pTemp->m_dwStorageType;
break;
}
}
delete pNext;
pNext = m_Cache.FindNext(dLast);
}
}
if (PropertyID == 0)
{
if (!bSys)
hr = WBEM_E_NOT_FOUND;
else if (dClassID!= 1)
hr = GetPropertyID(lpName, 1, dwFlags, ct, PropertyID, ActualClass, Flags, Type, FALSE);
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::AddPropertyInfo
//
//***************************************************************************
HRESULT CSchemaCache::AddPropertyInfo (DWORD dwPropertyID, LPCWSTR lpName, SQL_ID dwClassID, DWORD dwStorageType,
DWORD dwCIMType, DWORD dwFlags, SQL_ID dwRefClassID, LPCWSTR lpDefault, DWORD dwRefPropID, DWORD dwFlavor)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
PropertyData *pData = NULL;
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pData);
if (pData == NULL)
{
pData = new PropertyData;
if (!pData)
hr = WBEM_E_OUT_OF_MEMORY;
else
m_Cache.Insert(dTemp, pData);
}
else
m_dwTotalSize -= pData->GetSize();
if (pData)
{
bool bTruncated = FALSE;
delete pData->m_sPropertyName;
pData->m_sPropertyName = TruncateLongText(lpName, MAX_WIDTH_SCHEMANAME,
bTruncated, MAX_WIDTH_SCHEMANAME, FALSE);
if (!pData->m_dwClassID)
pData->m_dwClassID = dwClassID;
pData->m_dwStorageType = dwStorageType;
pData->m_dwCIMType = dwCIMType;
pData->m_dwFlags = dwFlags;
pData->m_dwRefClassID = dwRefClassID;
pData->m_dwQPropID = dwRefPropID;
pData->m_dwFlavor = dwFlavor;
ClassData *pCData = NULL;
m_CCache.Get(dwClassID, &pCData);
if (pCData)
{
pCData->InsertProperty(dwPropertyID, FALSE);
if (dwFlags & REPDRVR_FLAG_KEYHOLE)
pCData->m_dwFlags |= REPDRVR_FLAG_KEYHOLE;
if (dwStorageType == WMIDB_STORAGE_IMAGE)
pCData->m_dwFlags |= REPDRVR_FLAG_IMAGE;
if (dwCIMType == CIM_OBJECT)
pCData->m_dwFlags |= REPDRVR_FLAG_IMAGE;
m_dwTotalSize += pCData->GetSize();
}
m_dwTotalSize += pData->GetSize();
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::PropertyChanged
//
//***************************************************************************
bool CSchemaCache::PropertyChanged (LPCWSTR lpName, SQL_ID dwClassID, DWORD dwCIMType, LPCWSTR lpDefault,
DWORD dwFlags, SQL_ID dwRefClassID, DWORD dwRefPropID, DWORD dwFlavor)
{
_WMILockit lkt(&m_cs);
bool bChg = true;
HRESULT hr = WBEM_S_NO_ERROR;
DWORD dwPropertyID = 0;
PropertyData *pData = NULL;
hr = GetPropertyID(lpName, dwClassID, dwFlags, dwCIMType, dwPropertyID);
if (SUCCEEDED(hr))
{
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pData);
if (pData != NULL)
{
bChg = false;
if (pData->m_dwFlags != dwFlags ||
pData->m_dwCIMType != dwCIMType ||
pData->m_dwRefClassID != dwRefClassID ||
pData->m_dwQPropID != dwRefPropID ||
_wcsicmp(pData->m_sDefaultValue,lpDefault) ||
pData->m_dwFlavor != dwFlavor)
bChg = true;
}
}
return bChg;
}
//***************************************************************************
//
// CSchemaCache::IsQualifier
//
//***************************************************************************
bool CSchemaCache::IsQualifier(DWORD dwPropertyId)
{
bool bRet = false;
_WMILockit lkt(&m_cs);
PropertyData *pData = NULL;
SQL_ID dTemp = dwPropertyId;
m_Cache.Get(dTemp, &pData);
if (pData)
{
if (pData->m_dwFlags & REPDRVR_FLAG_QUALIFIER)
bRet = true;
}
return bRet;
}
//***************************************************************************
//
// CSchemaCache::SetAuxiliaryPropertyInfo
//
//***************************************************************************
HRESULT CSchemaCache::SetAuxiliaryPropertyInfo (DWORD dwPropertyID, LPWSTR lpDefault, DWORD dwRefID)
{
HRESULT hr = WBEM_S_NO_ERROR;
PropertyData *pData = NULL;
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pData);
if (pData)
{
delete pData->m_sDefaultValue;
pData->m_sDefaultValue = Macro_CloneLPWSTR(lpDefault);
pData->m_dwQPropID = dwRefID;
}
else
hr = WBEM_E_NOT_FOUND;
return hr;
}
//***************************************************************************
//
// CSchemaCache::DeleteProperty
//
//***************************************************************************
HRESULT CSchemaCache::DeleteProperty (DWORD dwPropertyID, SQL_ID dClassId)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
PropertyData *pData = NULL;
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pData);
if (pData)
{
SQL_ID dwClassID = pData->m_dwClassID;
if (dwClassID == dClassId)
{
m_dwTotalSize -= pData->GetSize();
// delete pData;
m_Cache.Delete(dwPropertyID);
ClassData *pCData = NULL;
m_CCache.Get(dwClassID, &pCData);
if (pCData)
{
m_dwTotalSize -= pCData->GetSize();
pCData->DeleteProperty(dwPropertyID);
}
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetClassInfo
//
//***************************************************************************
HRESULT CSchemaCache::GetClassInfo (SQL_ID dwClassID, _bstr_t &sPath, SQL_ID &dwSuperClassID, SQL_ID &dwScopeID,
DWORD &dwTemp, _bstr_t *pName)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
ClassData *pClass = NULL;
m_CCache.Get(dwClassID, &pClass);
if (pClass)
{
sPath = pClass->m_sObjectPath;
if (pName)
*pName = pClass->m_sName;
dwSuperClassID = pClass->m_dwSuperClassID;
dwScopeID = pClass->m_dwScopeID;
dwTemp = pClass->m_dwFlags;
}
else
hr = WBEM_E_NOT_FOUND;
return hr;
}
//***************************************************************************
//
// CSchemaCache::AddClassInfo
//
//***************************************************************************
HRESULT CSchemaCache::AddClassInfo (SQL_ID dwClassID, LPCWSTR lpName, SQL_ID dwSuperClassID, SQL_ID dDynastyId, SQL_ID dwScopeID,
LPCWSTR lpPath, DWORD dwFlags)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
ClassData *pClass = NULL;
m_CCache.Get(dwClassID, &pClass);
if (!pClass)
{
pClass = new ClassData;
if (!pClass)
hr = WBEM_E_OUT_OF_MEMORY;
}
else
m_dwTotalSize -= pClass->GetSize();
if (pClass)
{
m_CCache.Insert(dwClassID, pClass);
wchar_t *wTemp = new wchar_t [MAX_WIDTH_SCHEMANAME+30];
CDeleteMe <wchar_t> r (wTemp);
if (wTemp)
{
bool bTruncated = FALSE;
delete pClass->m_sName;
pClass->m_sName = TruncateLongText(lpName, MAX_WIDTH_SCHEMANAME,
bTruncated, MAX_WIDTH_SCHEMANAME, FALSE);
if (wcslen(pClass->m_sName))
{
swprintf(wTemp , L"%s_%I64d", pClass->m_sName, dwScopeID);
m_CIndex[_bstr_t(wTemp)] = dwClassID;
}
pClass->m_dwClassID = dwClassID;
pClass->m_dwSuperClassID = dwSuperClassID;
pClass->m_dwDynastyID = dDynastyId;
pClass->m_dwScopeID = dwScopeID;
delete pClass->m_sObjectPath;
pClass->m_sObjectPath = Macro_CloneLPWSTR(lpPath);
pClass->m_dwFlags = dwFlags;
m_dwTotalSize += pClass->GetSize();
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
if (dwSuperClassID)
{
hr = m_CCache.Get(dwSuperClassID, &pClass);
if (FAILED(hr))
{
hr = AddClassInfo(dwSuperClassID, L"", 0, 0, 0, L"", 0);
if (SUCCEEDED(hr))
{
hr = m_CCache.Get(dwSuperClassID, &pClass);
}
}
if (SUCCEEDED(hr))
{
pClass->InsertDerivedClass(dwClassID);
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::DeleteClass
//
//***************************************************************************
HRESULT CSchemaCache::DeleteClass (SQL_ID dwClassID)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
SQL_ID dParent = 0;
// Ignore requests to delete meta_class.
if (dwClassID == 1)
return WBEM_S_NO_ERROR;
ClassData *pClass = NULL;
m_CCache.Get(dwClassID, &pClass);
if (pClass)
{
dParent = pClass->m_dwSuperClassID;
wchar_t *wTemp = new wchar_t [wcslen(pClass->m_sName)+25];
CDeleteMe <wchar_t> r (wTemp);
if (wTemp)
{
swprintf(wTemp, L"%s_%I64d", pClass->m_sName, pClass->m_dwScopeID);
for (int i = 0; i < pClass->m_dwNumProps; i++)
DeleteProperty(pClass->m_Properties[i].m_dwPropertyId, dwClassID);
if (dParent != 0 && dParent != 1)
{
hr = m_CCache.Get(dParent, &pClass);
if (SUCCEEDED(hr))
{
m_dwTotalSize -= pClass->GetSize();
pClass->DeleteDerivedClass(dwClassID);
}
}
ClassNames::iterator it = m_CIndex.find(wTemp);
if (it != m_CIndex.end())
m_CIndex.erase(it);
m_CCache.Delete(dwClassID);
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetClassID
//
//***************************************************************************
HRESULT CSchemaCache::GetClassID (LPCWSTR lpName, SQL_ID dwScopeID, SQL_ID &dClassID, SQL_ID *pDynasty)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
BOOL bInNamespace = FALSE;
SQL_ID dClass;
dClassID = 0;
if (!lpName)
return WBEM_E_NOT_FOUND;
GetNamespaceClass(dwScopeID, dClass);
if (dClass == NAMESPACECLASSID ||
IsDerivedClass(NAMESPACECLASSID, dClass))
bInNamespace = TRUE;
SQL_ID dParent = 0;
bool bTrunc = FALSE;
LPWSTR lpClassName = TruncateLongText(lpName, MAX_WIDTH_SCHEMANAME,
bTrunc, MAX_WIDTH_SCHEMANAME, FALSE);
CDeleteMe<wchar_t> c (lpClassName);
int iLen = wcslen(lpClassName);
wchar_t *pTmp = new wchar_t [iLen+25];
CDeleteMe <wchar_t> r (pTmp);
if (pTmp)
{
swprintf(pTmp, L"%s_%I64d", lpClassName, dwScopeID);
dClassID = m_CIndex[pTmp];
if (!dClassID)
{
if (dwScopeID != 0)
{
// Check the hierarchy. Maybe this is
// under a different scope.
dParent = dwScopeID;
while (TRUE)
{
GetParentNamespace(dParent, dParent);
GetNamespaceClass(dParent, dClass);
if (dClass == NAMESPACECLASSID ||
IsDerivedClass(NAMESPACECLASSID, dClass))
{
if (bInNamespace)
break;
else
bInNamespace = TRUE;
}
swprintf(pTmp, L"%s_%I64d", lpClassName, dParent);
dClassID = m_CIndex[pTmp];
if (!dParent || dClassID)
break;
}
}
if (!dClassID)
{
swprintf(pTmp, L"%s_0", lpClassName);
dClassID = m_CIndex[pTmp];
}
}
if (!dClassID)
hr = WBEM_E_NOT_FOUND;
else if (pDynasty)
{
ClassData *pClass = NULL;
hr = m_CCache.Get(dClassID, &pClass);
if (SUCCEEDED(hr))
*pDynasty = pClass->m_dwDynastyID;
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetDynasty
//
//***************************************************************************
HRESULT CSchemaCache::GetDynasty (SQL_ID dClassId, SQL_ID &dDynasty, _bstr_t &sClassName)
{
HRESULT hr = 0;
_WMILockit lk(&m_cs);
ClassData *pClass = NULL;
dDynasty = 0;
hr = m_CCache.Get(dClassId, &pClass);
if (SUCCEEDED(hr))
{
if (pClass->m_dwSuperClassID == 1 || pClass->m_dwSuperClassID == 0)
{
dDynasty = dClassId;
sClassName = pClass->m_sName;
}
else
{
hr = GetDynasty(pClass->m_dwSuperClassID, dDynasty, sClassName);
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetNamespaceID
//
//***************************************************************************
HRESULT CSchemaCache::GetNamespaceID(LPCWSTR lpKey, SQL_ID &dObjectId)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
_bstr_t sName = lpKey;
if (!sName.length())
sName = L"root";
dObjectId = CRC64::GenerateHashValue(sName);
if (!m_NamespaceIds.Exists(dObjectId))
hr = WBEM_E_NOT_FOUND;
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetNamespaceClass
//
//***************************************************************************
HRESULT CSchemaCache::GetNamespaceClass(SQL_ID dScopeId, SQL_ID &dScopeClassId)
{
NamespaceData *pTemp = NULL;
HRESULT hr = m_NamespaceIds.Get(dScopeId, &pTemp);
if (SUCCEEDED(hr))
{
dScopeClassId=pTemp->m_dClassId;
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetParentNamespace
//
//***************************************************************************
HRESULT CSchemaCache::GetParentNamespace(SQL_ID dObjectId, SQL_ID &dParentId, SQL_ID *dParentClassId)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
dParentId = 0;
if (dObjectId)
{
NamespaceData *pTemp = NULL;
hr = m_NamespaceIds.Get(dObjectId, &pTemp);
if (SUCCEEDED(hr))
{
dParentId = pTemp->m_dParentId;
if (dParentClassId && dParentId)
{
m_NamespaceIds.Get(dParentId, &pTemp);
*dParentClassId = pTemp->m_dClassId;
}
else if (dParentClassId)
*dParentClassId = 0;
}
}
else
hr = WBEM_E_INVALID_PARAMETER;
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetNamespaceName
//
//***************************************************************************
HRESULT CSchemaCache::GetNamespaceName(SQL_ID dObjectId, _bstr_t *sName, _bstr_t *sKey)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
if (dObjectId)
{
NamespaceData *pTemp = NULL;
hr = m_NamespaceIds.Get(dObjectId, &pTemp);
if (SUCCEEDED(hr))
{
if (sName)
*sName = pTemp->m_sNamespaceName;
if (sKey)
*sKey = pTemp->m_sNamespaceName;
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::AddNamespace
//
//***************************************************************************
HRESULT CSchemaCache::AddNamespace(LPCWSTR lpName, LPCWSTR lpKey, SQL_ID dObjectId, SQL_ID dParentId, SQL_ID dClassId)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
if (dParentId == dObjectId)
hr = WBEM_E_INVALID_PARAMETER;
else
{
// We need to generate an artificial key here,
// since our real key was generated from a compressed
// version of the key.
if (lpName && wcslen(lpName) && dObjectId != 0)
{
NamespaceData *pTemp = new NamespaceData;
if (pTemp)
{
pTemp->m_dNamespaceId = dObjectId;
delete pTemp->m_sNamespaceName;
pTemp->m_sNamespaceName = Macro_CloneLPWSTR(lpName);
pTemp->m_dParentId = dParentId;
pTemp->m_dClassId = dClassId;
m_NamespaceIds.Insert(dObjectId, pTemp);
m_dwTotalSize += pTemp->GetSize();
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
else
hr = WBEM_E_INVALID_PARAMETER;
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::DeleteNamespace
//
//***************************************************************************
HRESULT CSchemaCache::DeleteNamespace(SQL_ID dId)
{
_WMILockit lkt(&m_cs);
HRESULT hr = 0;
if (dId)
{
NamespaceData *pTemp = NULL;
hr = m_NamespaceIds.Get(dId, &pTemp);
if (SUCCEEDED(hr))
{
pTemp -= pTemp->GetSize();
m_NamespaceIds.Delete(dId);
}
hr = WBEM_S_NO_ERROR;
}
else
hr = WBEM_E_INVALID_PARAMETER;
return hr;
}
//***************************************************************************
//
// CSchemaCache::IsSubScope
//
//***************************************************************************
bool CSchemaCache::IsSubScope(SQL_ID dParent, SQL_ID dPotentialSubScope)
{
bool bRet = false;
SQL_ID dParentID, dScopeClass = 0;
HRESULT hr = GetParentNamespace(dPotentialSubScope, dParentID, &dScopeClass);
while (SUCCEEDED(hr))
{
if (dParent == dParentID)
{
bRet = true;
break;
}
// Stop when we hit our own namespace
if (IsDerivedClass(NAMESPACECLASSID, dParent))
break;
hr = GetParentNamespace(dParentID, dParentID);
}
return bRet;
}
//***************************************************************************
//
// CSchemaCache::GetSubScopes
//
//***************************************************************************
HRESULT CSchemaCache::GetSubScopes(SQL_ID dId, SQL_ID **ppScopes, int &iNumScopes)
{
HRESULT hr = 0;
int iSize = 10;
iNumScopes = 0;
SQL_ID *pTemp = new SQL_ID [iSize];
if (!pTemp)
return WBEM_E_OUT_OF_MEMORY;
CListElement *pData = NULL;
SQL_ID dPrevious = 0;
pData = m_NamespaceIds.FindFirst();
while (pData != NULL && SUCCEEDED(hr))
{
dPrevious = pData->m_dId;
if (IsSubScope(dId, pData->m_dId))
{
if (iNumScopes >= iSize)
{
iSize += 10;
SQL_ID *ppNew = new SQL_ID [iSize];
if (ppNew)
{
memcpy(ppNew, pTemp, sizeof(SQL_ID) * iSize-10);
delete pTemp;
pTemp = ppNew;
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
break;
}
}
pTemp[iNumScopes] = pData->m_dId;
iNumScopes++;
}
delete pData;
pData = m_NamespaceIds.FindNext(dPrevious);
if (!pData)
break;
}
*ppScopes = pTemp;
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetClassObject
//
//***************************************************************************
HRESULT CSchemaCache::GetClassObject (LPWSTR lpMachineName, LPWSTR lpNamespaceName, SQL_ID dScopeId,
SQL_ID dClassId, IWbemClassObject *pTemp)
{
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
IWbemQualifierSet *pQS = NULL;
ClassData *pData = NULL;
m_CCache.Get(dClassId, &pData);
if (!pData)
hr = WBEM_E_NOT_FOUND;
else
{
if (SUCCEEDED(hr))
{
VARIANT var;
VariantInit(&var);
// __CLASS
V_BSTR(&var) = Macro_CloneLPWSTR(pData->m_sName);
var.vt = VT_BSTR;
hr = pTemp->Put(L"__Class", 0, &var, CIM_STRING);
VariantClear(&var);
hr = DecorateWbemObj(lpMachineName, lpNamespaceName, dScopeId, pTemp, dClassId);
// Set common qualifiers.
pTemp->GetQualifierSet(&pQS);
if (pData->m_dwFlags & REPDRVR_FLAG_ABSTRACT)
SetBoolQualifier(pQS, L"abstract", 0);
pQS->Release();
// Get every property and qualifier
// for this class and all its parents.
// =======================================
hr = WBEM_S_NO_ERROR;
while (TRUE)
{
for (int i = 0; i < pData->m_dwNumProps; i++)
{
DWORD dwPropertyID = pData->m_Properties[i].m_dwPropertyId;
PropertyData *pPData = NULL;
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pPData);
if (!pPData)
continue;
if (pPData->m_dwFlags & REPDRVR_FLAG_SYSTEM)
continue;
// If the property is an embedded object, we
// need to instantiate a new instance of this
// class and add it. Each property/qualifier
// will need to be added also.
// ===========================================
if (!(pPData->m_dwFlags & REPDRVR_FLAG_QUALIFIER) && !(pPData->m_dwFlags & REPDRVR_FLAG_METHOD)
&& !(pPData->m_dwFlags & REPDRVR_FLAG_IN_PARAM) && !(pPData->m_dwFlags & REPDRVR_FLAG_OUT_PARAM))
{
IWbemQualifierSet *pQS = NULL;
CIMTYPE ct = pPData->m_dwCIMType;
if (pPData->m_dwFlags & REPDRVR_FLAG_ARRAY)
{
ct |= CIM_FLAG_ARRAY;
var.vt = VT_NULL;
}
else
{
if (wcslen(pPData->m_sDefaultValue) > 0)
{
V_BSTR(&var) = SysAllocString(pPData->m_sDefaultValue);
var.vt = VT_BSTR;
}
else
{
var.vt = VT_NULL;
}
}
hr = pTemp->Put(pPData->m_sPropertyName, 0, &var, ct);
VariantClear(&var);
}
}
if (FAILED(hr))
break;
for (i = 0; i < pData->m_dwNumProps; i++)
{
DWORD dwPropertyID = pData->m_Properties[i].m_dwPropertyId;
PropertyData *pPData = NULL;
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pPData);
if (!pPData)
continue;
if (pPData->m_dwFlags & REPDRVR_FLAG_SYSTEM)
continue;
if (pPData->m_dwFlags & REPDRVR_FLAG_QUALIFIER)
{
if (wcslen(pPData->m_sDefaultValue))
{
IWbemQualifierSet *pQS = NULL;
if (pPData->m_dwQPropID != 0)
{
// property or method qualifier
PropertyData *pData = NULL;
SQL_ID dTemp = pPData->m_dwQPropID;
m_Cache.Get(dTemp, &pData);
if (pData)
{
if (pData->m_dwFlags & REPDRVR_FLAG_METHOD)
hr = pTemp->GetMethodQualifierSet(pData->m_sPropertyName, &pQS);
else
hr = pTemp->GetPropertyQualifierSet(pData->m_sPropertyName, &pQS);
}
else
hr = WBEM_E_NOT_FOUND;
if (SUCCEEDED(hr))
{
V_BSTR(&var) = SysAllocString(pPData->m_sDefaultValue);
var.vt = VT_BSTR;
pQS->Put(pPData->m_sPropertyName, &var, pPData->m_dwFlavor);
pQS->Release();
}
}
else
{
// class qualifier
hr = pTemp->GetQualifierSet(&pQS);
if (SUCCEEDED(hr))
{
V_BSTR(&var) = SysAllocString(pPData->m_sDefaultValue);
var.vt = VT_BSTR;
pQS->Put(pPData->m_sPropertyName, &var, pPData->m_dwFlavor);
pQS->Release();
}
}
}
}
else
{
IWbemClassObject *pIn = NULL, *pOut = NULL;
// This is a method or one of its parameters.
if (pPData->m_dwFlags & REPDRVR_FLAG_METHOD)
{
hr = pTemp->PutMethod(pPData->m_sPropertyName, 0, NULL, NULL);
}
else if ((pPData->m_dwFlags & REPDRVR_FLAG_IN_PARAM) ||
(pPData->m_dwFlags & REPDRVR_FLAG_OUT_PARAM))
{
// This is handled in GetObjectData.
}
}
VariantClear(&var);
}
if (pData->m_dwSuperClassID <= 1)
break;
else
{
m_CCache.Get(pData->m_dwSuperClassID, &pData);
if (!pData)
break;
}
if (FAILED(hr))
break;
}
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetParentId
//
//***************************************************************************
HRESULT CSchemaCache::GetParentId (SQL_ID dClassId, SQL_ID &dParentId)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
ClassData *pData = NULL;
m_CCache.Get(dClassId, &pData);
if (pData)
{
dParentId = pData->m_dwSuperClassID;
if (!dParentId || dParentId == 1) // Disregard __Class.
hr = WBEM_E_NOT_FOUND;
}
else
hr = WBEM_E_NOT_FOUND;
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetKeyholeProperty
//
//***************************************************************************
HRESULT CSchemaCache::GetKeyholeProperty (SQL_ID dClassId, DWORD &dwPropID, _bstr_t &sPropName)
{
HRESULT hr = WBEM_E_NOT_FOUND;
_WMILockit lkt(&m_cs);
ClassData *pData = NULL;
m_CCache.Get(dClassId, &pData);
if (pData)
{
if (pData->m_dwFlags & REPDRVR_FLAG_KEYHOLE)
{
// We know we have one.
for (int i = 0; i < pData->m_dwNumProps; i++)
{
DWORD dwPropertyID = pData->m_Properties[i].m_dwPropertyId;
PropertyData *pPData = NULL;
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pPData);
if (pPData && pPData->m_dwFlags & REPDRVR_FLAG_KEYHOLE)
{
dwPropID = dwPropertyID;
sPropName = pPData->m_sPropertyName;
hr = WBEM_S_NO_ERROR;
break;
}
}
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::IsInHierarchy
//
//***************************************************************************
bool CSchemaCache::IsInHierarchy(SQL_ID dParentId, SQL_ID dPotentialChild)
{
HRESULT hr = WBEM_S_NO_ERROR;
bool bRet = false;
_WMILockit lk(&m_cs);
if (dParentId == dPotentialChild)
bRet = true;
else
{
bRet = IsDerivedClass(dParentId, dPotentialChild);
if (!bRet)
{
bRet = IsDerivedClass(dPotentialChild, dParentId);
}
}
return bRet;
}
//***************************************************************************
//
// CSchemaCache::IsDerivedClass
//
//***************************************************************************
bool CSchemaCache::IsDerivedClass(SQL_ID dParentId, SQL_ID dPotentialChild)
{
HRESULT hr = WBEM_S_NO_ERROR;
bool bRet = false;
_WMILockit lk(&m_cs);
ClassData *pData = NULL;
hr = m_CCache.Get(dPotentialChild, &pData);
while (SUCCEEDED(hr))
{
if (pData->m_dwSuperClassID == dParentId)
{
bRet = true;
break;
}
hr = m_CCache.Get(pData->m_dwSuperClassID, &pData);
}
return bRet;
}
//***************************************************************************
//
// CSchemaCache::HasImageProp
//
//***************************************************************************
bool CSchemaCache::HasImageProp (SQL_ID dClassId)
{
bool bRet = false;
_WMILockit lkt(&m_cs);
ClassData *pData = NULL;
m_CCache.Get(dClassId, &pData);
if (pData)
{
if (pData->m_dwFlags & REPDRVR_FLAG_IMAGE)
{
bRet = true;
}
}
return bRet;
}
//***************************************************************************
//
// CSchemaCache::Exists
//
//***************************************************************************
BOOL CSchemaCache::Exists (SQL_ID dClassId)
{
BOOL bRet = FALSE;
_WMILockit lkt(&m_cs);
ClassData *pData = NULL;
m_CCache.Get(dClassId, &pData);
if (pData && pData->m_dwDynastyID != 0)
bRet = TRUE;
return bRet;
}
//***************************************************************************
//
// CSchemaCache::DecorateWbemObj
//
//***************************************************************************
HRESULT CSchemaCache::DecorateWbemObj(LPWSTR lpMachineName, LPWSTR lpNamespaceName,
SQL_ID dScopeId, IWbemClassObject *pTemp, SQL_ID dClassId)
{
_IWmiObject *pInt = NULL;
HRESULT hr = pTemp->QueryInterface(IID__IWmiObject, (void **)&pInt);
CReleaseMe r (pInt);
if (pInt)
{
wchar_t *pNs = NULL;
// Decorate this instance. This will let it generate the path.
// __NAMESPACE
NamespaceData *pTemp = NULL;
hr = m_NamespaceIds.Get(dScopeId, &pTemp);
if (SUCCEEDED(hr) && _wcsicmp(pTemp->m_sNamespaceName, L"root"))
{
pNs = new wchar_t [wcslen(lpNamespaceName)+wcslen(pTemp->m_sNamespaceName) + 2];
if (pNs)
swprintf(pNs, L"%s\\%s", lpNamespaceName, pTemp->m_sNamespaceName);
}
else
{
pNs = new wchar_t [wcslen(lpNamespaceName) + 1];
if (pNs)
wcscpy(pNs, lpNamespaceName);
}
CDeleteMe <wchar_t> d (pNs);
// Call some method to decorate the object
hr = pInt->SetDecoration(lpMachineName, pNs);
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetKeys
//
//***************************************************************************
HRESULT CSchemaCache::GetKeys(SQL_ID dNsID, LPCWSTR lpClassName, CWStringArray &arrKeys)
{
HRESULT hr = WBEM_S_NO_ERROR;
SQL_ID dClassId;
hr = GetClassID(lpClassName, dNsID, dClassId);
if (SUCCEEDED(hr))
{
_WMILockit lkt(&m_cs);
ClassData *pClass = NULL;
m_CCache.Get(dClassId, &pClass);
if (!pClass)
hr = WBEM_E_NOT_FOUND;
while (pClass)
{
for (int i = 0; i < pClass->m_dwNumProps; i++)
{
if (pClass->m_Properties[i].m_bIsKey)
{
PropertyData *pProp = NULL;
SQL_ID dTemp = pClass->m_Properties[i].m_dwPropertyId;
m_Cache.Get(dTemp, &pProp);
if (pProp)
arrKeys.Add(pProp->m_sPropertyName);
}
}
SQL_ID dSC = pClass->m_dwSuperClassID;
pClass = NULL;
if (!arrKeys.Size() && dSC)
m_CCache.Get(dSC, &pClass);
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::IsKey
//
//***************************************************************************
BOOL CSchemaCache::IsKey(SQL_ID dClassId, DWORD dwPropID, BOOL &bLocal)
{
// Does this property already exist in the hierarchy as a key??
BOOL bRet = FALSE;
_WMILockit lkt(&m_cs);
BOOL bDone = FALSE;
ClassData *pClass = NULL;
m_CCache.Get(dClassId, &pClass);
bLocal = TRUE;
if (!pClass)
bRet = FALSE;
while (pClass)
{
for (int i = 0; i < pClass->m_dwNumProps; i++)
{
PropertyData *pProp = NULL;
SQL_ID dTemp = pClass->m_Properties[i].m_dwPropertyId;
if (dwPropID == dTemp)
{
bRet = (pClass->m_Properties[i].m_bIsKey); // Return the first place this ID is defined.
bDone = TRUE;
break;
}
}
if (bDone)
break;
SQL_ID dSC = pClass->m_dwSuperClassID;
pClass = NULL;
if (!bRet && !dSC)
{
m_CCache.Get(dSC, &pClass);
bLocal = FALSE;
}
}
return bRet;
}
//***************************************************************************
//
// CSchemaCache::SetIsKey
//
//***************************************************************************
HRESULT CSchemaCache::SetIsKey (SQL_ID dClassId, DWORD dwPropID, BOOL bIsKey)
{
HRESULT hr = 0;
BOOL bDone = FALSE;
_WMILockit lkt(&m_cs);
ClassData *pClass = NULL;
m_CCache.Get(dClassId, &pClass);
if (!pClass)
hr = WBEM_E_NOT_FOUND;
else
pClass->InsertProperty(dwPropID, bIsKey);
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetKeyRoot
//
//***************************************************************************
LPWSTR CSchemaCache::GetKeyRoot (LPWSTR lpClassName, SQL_ID dScopeId)
{
LPWSTR lpRet = NULL;
SQL_ID dClassId;
SQL_ID dRetClass = 0;
HRESULT hr = GetClassID (lpClassName, dScopeId, dClassId);
if (SUCCEEDED(hr))
{
_WMILockit lkt(&m_cs);
ClassData *pClass = NULL;
m_CCache.Get(dClassId, &pClass);
if (!pClass)
hr = WBEM_E_NOT_FOUND;
while (pClass)
{
// Find the topmost class that has a key property,
// or the topmost singleton or unkeyed class.
if (pClass->m_dwFlags & REPDRVR_FLAG_SINGLETON ||
pClass->m_dwFlags & REPDRVR_FLAG_UNKEYED)
{
dRetClass = pClass->m_dwClassID;
}
else
{
for (int i = 0; i < pClass->m_dwNumProps; i++)
{
if (pClass->m_Properties[i].m_bIsKey)
{
dRetClass = pClass->m_dwClassID;
break;
}
}
}
SQL_ID dSC = pClass->m_dwSuperClassID;
pClass = NULL;
if (dSC)
m_CCache.Get(dSC, &pClass);
else
break;
}
if (dRetClass)
{
m_CCache.Get(dRetClass, &pClass);
int iSize = wcslen(pClass->m_sName);
if (iSize)
{
lpRet = new wchar_t [iSize+1];
if (lpRet)
wcscpy(lpRet, pClass->m_sName);
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
hr = WBEM_E_NOT_FOUND;
}
return lpRet;
}
//***************************************************************************
//
// CSchemaCache::GetPropertyList
//
//***************************************************************************
HRESULT CSchemaCache::GetPropertyList (SQL_ID dClassId, Properties &pProps, DWORD *pwNumProps)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
ClassData *pClass = NULL;
m_CCache.Get(dClassId, &pClass);
if (pClass)
{
for (int i = 0; i < pClass->m_dwNumProps; i++)
{
DWORD dwPropertyID = pClass->m_Properties[i].m_dwPropertyId;
pProps[dwPropertyID] = 0;
}
if (pwNumProps)
*pwNumProps = pClass->m_dwNumProps;
}
else
WBEM_E_NOT_FOUND;
return hr;
}
//***************************************************************************
//
// CSchemaCache::ValidateProperty
//
//***************************************************************************
HRESULT CSchemaCache::ValidateProperty (SQL_ID dObjectId, DWORD dwPropertyID, DWORD dwFlags, CIMTYPE cimtype, DWORD dwStorageType,
LPWSTR lpDefault, BOOL &bChg, BOOL &bIfNoInstances)
{
HRESULT hr = WBEM_S_NO_ERROR;
PropertyData *pData = NULL;
_WMILockit lkt(&m_cs);
bChg = TRUE; // We can't tell if the default changed or not, since it ain't cached.
BOOL bIfNoChildren = FALSE;
SQL_ID dTemp = dwPropertyID;
m_Cache.Get(dTemp, &pData);
if (pData)
{
if (pData->m_dwFlags != dwFlags ||
pData->m_dwCIMType != cimtype)
bChg = TRUE;
BOOL bLocal = FALSE;
BOOL bOldKeyStatus = IsKey(dObjectId, dwPropertyID, bLocal);
BOOL bNewKeyStatus = ((dwFlags & REPDRVR_FLAG_KEY) ? TRUE : FALSE);
if (bOldKeyStatus != bNewKeyStatus)
{
bIfNoChildren = TRUE;
bIfNoInstances = TRUE;
}
// Check for a legal conversion.
// We can only change datatypes to larger types of same storage type
// Except that we can change ints to larger reals.
if (pData->m_dwCIMType != cimtype)
{
if (dwStorageType != pData->m_dwStorageType)
{
if (!(pData->m_dwStorageType == WMIDB_STORAGE_NUMERIC &&
dwStorageType == WMIDB_STORAGE_REAL))
hr = WBEM_E_INVALID_OPERATION;
}
if (SUCCEEDED(hr))
{
// Make sure the conversion is to a bigger or same storage unit.
switch(cimtype)
{
case CIM_UINT8:
case CIM_SINT8:
switch(pData->m_dwCIMType)
{
case CIM_UINT8:
case CIM_SINT8:
case CIM_BOOLEAN:
hr = WBEM_S_NO_ERROR;
break;
default:
hr = WBEM_E_INVALID_OPERATION;
break;
}
break;
case CIM_UINT16:
case CIM_SINT16:
switch(pData->m_dwCIMType)
{
case CIM_UINT16:
case CIM_SINT16:
case CIM_UINT8:
case CIM_SINT8:
case CIM_BOOLEAN:
hr = WBEM_S_NO_ERROR;
break;
default:
hr = WBEM_E_INVALID_OPERATION;
break;
}
break;
case CIM_UINT32:
case CIM_SINT32:
case CIM_REAL32:
switch(pData->m_dwCIMType)
{
case CIM_UINT32:
case CIM_SINT32:
case CIM_UINT16:
case CIM_SINT16:
case CIM_UINT8:
case CIM_SINT8:
case CIM_BOOLEAN:
hr = WBEM_S_NO_ERROR;
break;
default:
hr = WBEM_E_INVALID_OPERATION;
break;
}
break;
case CIM_UINT64:
case CIM_SINT64:
switch(pData->m_dwCIMType)
{
case CIM_UINT64:
case CIM_SINT64:
case CIM_UINT32:
case CIM_SINT32:
case CIM_UINT16:
case CIM_SINT16:
case CIM_UINT8:
case CIM_SINT8:
case CIM_BOOLEAN:
hr = WBEM_S_NO_ERROR;
break;
default:
hr = WBEM_E_INVALID_OPERATION;
break;
}
break;
case CIM_REAL64:
switch(pData->m_dwCIMType)
{
case CIM_REAL32:
case CIM_UINT64:
case CIM_SINT64:
case CIM_UINT32:
case CIM_SINT32:
case CIM_UINT16:
case CIM_SINT16:
case CIM_UINT8:
case CIM_SINT8:
case CIM_BOOLEAN:
hr = WBEM_S_NO_ERROR;
break;
default:
hr = WBEM_E_INVALID_OPERATION;
break;
}
break;
default:
hr = WBEM_E_INVALID_OPERATION; // strings, refs, datetimes, etc.
break;
}
}
}
if (bIfNoChildren)
{
// Fail if we have subclasses.
SQLIDs ids;
int iNumChildren = 0;
hr = GetDerivedClassList(dObjectId, ids, iNumChildren);
if (SUCCEEDED(hr))
{
if (iNumChildren != 0)
hr = WBEM_E_CLASS_HAS_CHILDREN;
}
}
}
else
{
if (dwFlags & REPDRVR_FLAG_KEY)
bIfNoInstances = TRUE; // Can't add a key if there are instances.
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::FindProperty
//
//***************************************************************************
HRESULT CSchemaCache::FindProperty(SQL_ID dObjectId, LPWSTR lpPropName, DWORD dwFlags, CIMTYPE ct)
{
HRESULT hr = WBEM_S_NO_ERROR;
// Does this property already exist in a derived class?
SQLIDs ids;
int iNumChildren = 0;
hr = GetDerivedClassList(dObjectId, ids, iNumChildren);
if (SUCCEEDED(hr))
{
for (int i = 0; i < iNumChildren; i++)
{
SQL_ID dTemp = ids.at(i);
DWORD dwTempID = 0;
if (GetPropertyID(lpPropName, dTemp, dwFlags, ct, dwTempID) == WBEM_S_NO_ERROR)
{
hr = WBEM_E_PROPAGATED_PROPERTY;
break;
}
}
}
else if (!dObjectId)
hr = WBEM_S_NO_ERROR;
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetDerivedClassList
//
//***************************************************************************
HRESULT CSchemaCache::GetDerivedClassList(SQL_ID dObjectId, SQL_ID **ppIDs,
int &iNumChildren, BOOL bImmediate)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
SQLIDs ids;
hr = GetDerivedClassList(dObjectId, ids, iNumChildren, bImmediate);
if (SUCCEEDED(hr))
{
SQL_ID *pTemp = new SQL_ID [iNumChildren];
if (pTemp)
{
for (int i = 0; i < iNumChildren; i++)
{
pTemp[i] = ids.at(i);
}
*ppIDs = pTemp;
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetDerivedClassList
//
//***************************************************************************
HRESULT CSchemaCache::GetDerivedClassList(SQL_ID dObjectId, SQLIDs &children,
int &iNumChildren, BOOL bImmediate)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
ClassData *pClass = NULL;
m_CCache.Get(dObjectId, &pClass);
if (pClass)
{
for (int i = 0; i < pClass->m_DerivedIDs.size(); i++)
{
SQL_ID dChild = pClass->m_DerivedIDs.at(i);
children.push_back(dChild);
iNumChildren++;
if (!bImmediate)
hr = GetDerivedClassList(dChild, children, iNumChildren);
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetHierarchy
//
//***************************************************************************
HRESULT CSchemaCache::GetHierarchy(SQL_ID dObjectId, SQL_ID **ppIDs, int &iNumIDs)
{
HRESULT hr = WBEM_S_NO_ERROR;
int iSize = 0;
// Populate the ID list of derived *and* parent class IDs.
SQLIDs ids;
hr = GetHierarchy(dObjectId, ids, iNumIDs);
if (SUCCEEDED(hr))
{
SQL_ID *pIDs = new SQL_ID [iNumIDs];
if (pIDs)
{
for (int i = 0; i < iNumIDs; i++)
{
pIDs[i] = ids.at(i);
}
*ppIDs = pIDs;
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::GetHierarchy
//
//***************************************************************************
HRESULT CSchemaCache::GetHierarchy(SQL_ID dObjectId, SQLIDs &ids, int &iNumIDs)
{
HRESULT hr = WBEM_S_NO_ERROR;
int iSize = 0;
// Populate the ID list of derived *and* parent class IDs.
hr = GetDerivedClassList(dObjectId, ids, iNumIDs);
if (SUCCEEDED(hr))
{
SQL_ID dTemp = dObjectId;
// Load up all the parents.
while (SUCCEEDED(GetParentId(dTemp, dTemp)))
{
ids.push_back(dTemp);
iNumIDs++;
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::ResizeCache
//
//***************************************************************************
HRESULT CSchemaCache::ResizeCache()
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
SQLIDs ids;
// Unload an existing dynasty to make room.
SQLRefCountMap::iterator item = m_DynastiesInUse.begin();
while (item != m_DynastiesInUse.end())
{
if ((*item).second == 0)
{
hr = DeleteDynasty((*item).first);
ids.push_back((*item).first);
if (m_dwTotalSize < m_dwMaxSize || item == m_DynastiesInUse.end())
break;
}
item++;
}
for (int i = 0; i < ids.size(); i++)
m_DynastiesInUse.erase(m_DynastiesInUse.find(ids.at(i)));
return hr;
}
//***************************************************************************
//
// CSchemaCache::LockDynasty
//
//***************************************************************************
HRESULT CSchemaCache::LockDynasty(SQL_ID dDynastyId)
{
HRESULT hr = WBEM_S_NO_ERROR;
ULONG uRefCount = 0;
_WMILockit lkt(&m_cs);
SQLRefCountMap::iterator it = m_DynastiesInUse.find(dDynastyId);
if (it != m_DynastiesInUse.end())
uRefCount = (*it).second;
InterlockedIncrement((LONG *) &uRefCount);
m_DynastiesInUse[dDynastyId] = uRefCount;
return hr;
}
//***************************************************************************
//
// CSchemaCache::UnlockDynasty
//
//***************************************************************************
HRESULT CSchemaCache::UnlockDynasty(SQL_ID dDynastyId)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
ULONG uRefCount = m_DynastiesInUse[dDynastyId];
InterlockedDecrement((LONG *) &uRefCount);
m_DynastiesInUse[dDynastyId] = uRefCount;
return hr;
}
//***************************************************************************
//
// CSchemaCache::DeleteDynasty
//
//***************************************************************************
HRESULT CSchemaCache::DeleteDynasty(SQL_ID dDynastyId)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (dDynastyId == 1)
return WBEM_S_NO_ERROR;
// Delete all class info for members of this dynasty.
SQLIDs ids;
int iNum;
// Immediate only, so we don't inadvertently
// blow away a protected dynasty.
hr = GetDerivedClassList(dDynastyId, ids, iNum, TRUE);
if (SUCCEEDED(hr))
{
DeleteClass(dDynastyId);
for (int i = 0; i < ids.size(); i++)
{
SQL_ID d = ids.at(i);
ULONG uRefCount = 0;
SQLRefCountMap::iterator it = m_DynastiesInUse.find(d);
if (it != m_DynastiesInUse.end())
uRefCount = (*it).second;
if (!uRefCount)
hr = DeleteDynasty(d);
}
}
return hr;
}
//***************************************************************************
//
// CSchemaCache::IsSystemClass
//
//***************************************************************************
BOOL CSchemaCache::IsSystemClass(SQL_ID dObjectId, SQL_ID dClassId)
{
BOOL bRet = FALSE;
_WMILockit lkt(&m_cs);
HRESULT hr = WBEM_S_NO_ERROR;
ClassData *pClass = NULL;
if (dClassId == 1)
m_CCache.Get(dObjectId, &pClass);
else
m_CCache.Get(dClassId, &pClass);
if (pClass)
{
if (pClass->m_sName && pClass->m_sName[0] == L'_')
bRet = TRUE;
}
return bRet;
}
//***************************************************************************
//
// CSchemaCache::GetWriteToken
//
//***************************************************************************
DWORD CSchemaCache::GetWriteToken(SQL_ID dObjectId, SQL_ID dClassId)
{
DWORD dwRet = WBEM_PARTIAL_WRITE_REP;
BOOL bRet = IsSystemClass(dObjectId, dClassId);
if (bRet)
dwRet = WBEM_FULL_WRITE_REP;
return dwRet;
}