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.
 
 
 
 
 
 

6798 lines
229 KiB

//***************************************************************************
//
// (c) 1999-2001 by Microsoft Corp. All Rights Reserved.
//
// repdrvr.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 DBINITCONSTANTS // Initialize OLE constants...
#define INITGUID // ...once in each app.
#define _WIN32_DCOM
#include "precomp.h"
#include <std.h>
#include <sqlexec.h>
#include <sqlcache.h>
#include <repdrvr.h>
#include <wbemint.h>
#include <math.h>
#include <resource.h>
#include <reputils.h>
#include <crc64.h>
#include <smrtptr.h>
#include <wmiutils.h>
#include <wbemtime.h>
#include <reg.h>
//#include <icecap.h>
// Statics
_WMILockit::_WMILockit(CRITICAL_SECTION *pCS)
{
EnterCriticalSection(pCS);
m_cs = pCS;
}
_WMILockit::~_WMILockit()
{
LeaveCriticalSection(m_cs);
}
#define REPDRVR_FLAG_FLUSH_ALL 0x1
extern long g_cObj;
typedef std::map<SQL_ID, CacheInfo *> SchemaCache;
typedef std::map<_bstr_t, SQL_ID, C_wchar_LessCase> PathIndex;
typedef std::map <SQL_ID, LockData *> LockCache;
typedef std::vector<LockItem *> LockList;
typedef std::map <DWORD, DWORD> Properties;
typedef std::vector <SessionLock *> SessionLocks;
typedef std::map <DWORD, CESSHolder *> ESSObjs;
typedef std::map<SQL_ID, bool> SQL_IDMap;
typedef std::vector <SQL_ID> SQLIDs;
typedef std::map <DWORD, SQLIDs> SessionDynasties;
// Contrived method of generating proc names,
// since we are limited to 30 characters.
#define PROCTYPE_GET 1
#define PROCTYPE_PUT 2
#define PROCTYPE_DEL 3
LPWSTR StripSlashes(LPWSTR lpText)
{
wchar_t *pszTemp = NULL;
if (lpText)
{
pszTemp = new wchar_t [wcslen(lpText)+1];
if (pszTemp)
{
int iPos = 0;
int iLen = wcslen(lpText);
if (iLen)
{
BOOL bOnSlash = FALSE;
for (int i = 0; i < iLen; i++)
{
WCHAR t = lpText[i];
if (t == '\\')
{
if (lpText[i+1] == '\\' && !bOnSlash)
{
bOnSlash = TRUE;
continue;
}
}
pszTemp[iPos] = t;
bOnSlash = FALSE;
iPos++;
}
}
pszTemp[iPos] = '\0';
}
}
return pszTemp;
}
int GetDiff(SYSTEMTIME tEnd, SYSTEMTIME tStart)
{
int iRet = 0;
__int64 iTemp = (tEnd.wDay * 1000000000) +
(tEnd.wHour * 10000000) +
(tEnd.wMinute * 100000) +
(tEnd.wSecond * 1000) +
tEnd.wMilliseconds;
iTemp -= ((tStart.wDay * 1000000000) +
(tStart.wHour * 10000000) +
(tStart.wMinute * 100000) +
(tStart.wSecond * 1000) +
tStart.wMilliseconds);
iRet = (int) iTemp;
return iRet;
}
CWbemClassObjectProps::CWbemClassObjectProps
(CWmiDbSession *pSession, CSQLConnection *pConn, IWbemClassObject *pObj, CSchemaCache *pCache, SQL_ID dScopeID)
{
lpClassName = GetPropertyVal(L"__Class", pObj);
lpNamespace = GetPropertyVal(L"__Namespace", pObj);
lpSuperClass = GetPropertyVal(L"__SuperClass", pObj);
lpDynasty = GetPropertyVal(L"__Dynasty", pObj);
LPWSTR lpTemp = GetPropertyVal(L"__Genus", pObj);
CDeleteMe <wchar_t> r(lpTemp);
if (lpTemp)
dwGenus = _wtoi(lpTemp);
// If pConn is blank, this should already be loaded.
if (pConn)
{
if (FAILED(pSession->LoadClassInfo(pConn, lpClassName, dScopeID, FALSE)))
{
if (lpSuperClass)
pSession->LoadClassInfo(pConn, lpSuperClass, dScopeID, FALSE);
}
}
if (dwGenus == 1)
lpRelPath = GetPropertyVal(L"__Class", pObj);
else
{
LPWSTR lpTemp = GetPropertyVal(L"__RelPath", pObj);
CDeleteMe <wchar_t> d (lpTemp);
lpRelPath = StripSlashes(lpTemp);
if (lpRelPath)
{
LPWSTR lpNewClass = pCache->GetKeyRoot(lpClassName, dScopeID);
if (lpNewClass)
{
LPWSTR lpPtr = lpRelPath + wcslen(lpClassName);
LPWSTR lpTemp2 = new wchar_t [wcslen(lpNewClass) + wcslen(lpPtr) + 1];
if (lpTemp2)
{
wcscpy(lpTemp2, lpNewClass);
wcscat(lpTemp2, lpPtr);
delete lpRelPath;
lpRelPath = lpTemp2;
}
delete lpNewClass;
}
}
}
lpKeyString = NULL;
}
CWbemClassObjectProps::~CWbemClassObjectProps()
{
delete lpClassName;
delete lpNamespace;
delete lpRelPath;
delete lpSuperClass;
delete lpKeyString;
delete lpDynasty;
}
//***************************************************************************
//
// ConvertBlobToObject
//
//***************************************************************************
HRESULT ConvertBlobToObject (IWbemClassObject *pNewObj, BYTE *pBuffer, DWORD dwLen, _IWmiObject **ppNewObj)
{
HRESULT hr = WBEM_S_NO_ERROR;
IWbemClassObject *pEmbed = NULL;
_IWmiObject *pInt = NULL;
if (pNewObj)
hr = pNewObj->Clone(&pEmbed);
else
{
_IWmiObject *pClass = NULL;
// Handle blank Instance prototypes
hr = CoCreateInstance(CLSID_WbemClassObject, NULL, CLSCTX_INPROC_SERVER,
IID__IWmiObject, (void **)&pClass);
CReleaseMe r (pClass);
if (pClass)
{
hr = pClass->WriteProp(L"__Class", 0,
4, 4, CIM_STRING, L"X");
if (SUCCEEDED(hr))
{
hr = pClass->SpawnInstance(0, &pEmbed);
}
}
}
if (SUCCEEDED(hr))
{
hr = pEmbed->QueryInterface(IID__IWmiObject, (void **)&pInt);
CReleaseMe r (pInt);
if (SUCCEEDED(hr))
{
LPVOID pTaskMem = NULL;
if (SUCCEEDED(hr))
{
pTaskMem = CoTaskMemAlloc( dwLen );
if ( NULL != pTaskMem )
{
// Copy the memory
CopyMemory( pTaskMem, pBuffer, dwLen );
hr = pInt->SetObjectMemory(pTaskMem, dwLen);
if (SUCCEEDED(hr))
{
*ppNewObj = pInt;
}
else
{
_IWmiObject *pClass = NULL;
hr = CoCreateInstance(CLSID_WbemClassObject, NULL, CLSCTX_INPROC_SERVER,
IID__IWmiObject, (void **)&pClass);
if (SUCCEEDED(hr))
{
hr = pClass->SetObjectMemory(pTaskMem, dwLen);
if (SUCCEEDED(hr))
{
*ppNewObj = pClass;
}
}
}
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
}
}
return hr;
}
void ConvertDataToString(WCHAR * lpKey, BYTE* pData, DWORD dwType, BOOL bQuotes)
{
WCHAR *pFr;
WCHAR *pTo, *pOrig;
pFr = (LPWSTR)pData;
switch(dwType)
{
case CIM_STRING:
case CIM_REFERENCE:
if (bQuotes)
{
pTo = lpKey;
*pTo = L'\"';
*pTo++;
while (*pFr)
{
if (*pFr == L'\"')
{
*pTo = L'\\';
*pTo++;
*pTo = L'\"';
}
else
*pTo = *pFr;
pFr++;
pTo++;
}
*pTo = L'\"';
*pTo++;
*pTo = L'\0';
}
else
wcscpy(lpKey, (LPWSTR)pData);
break;
case CIM_SINT32:
swprintf(lpKey, L"%d", *(int *)pData);
break;
case CIM_UINT32:
swprintf(lpKey, L"%u", *(unsigned *)pData);
break;
case CIM_SINT16:
swprintf(lpKey, L"%hd", *(signed short *)pData);
break;
case CIM_UINT16:
swprintf(lpKey, L"%hu", *(unsigned short *)pData);
break;
case CIM_SINT8:
swprintf(lpKey, L"%d", *(signed char *)pData);
break;
case CIM_UINT8:
swprintf(lpKey, L"%u", *(unsigned char *)pData);
break;
case CIM_UINT64:
swprintf(lpKey, L"%I64u", *(unsigned __int64 *)pData);
break;
case CIM_SINT64:
swprintf(lpKey, L"%I64d", *(__int64 *)pData);
break;
case CIM_BOOLEAN:
// String, either TRUE or FALSE
if (*pFr)
wcscpy(lpKey, L"TRUE");
else
wcscpy(lpKey, L"FALSE");
break;
default:
break;
}
}
HRESULT MakeKeyListString(SQL_ID dScopeId, CSchemaCache *pCache,
LPWSTR lpClass, IWbemPathKeyList *pKeyList, LPWSTR lpKeyString)
{
HRESULT hr = 0;
if (!pKeyList)
return 0;
if (!lpKeyString)
return WBEM_E_INVALID_PARAMETER;
ULONG uNumKeys = 0;
hr = pKeyList->GetCount(&uNumKeys);
if (SUCCEEDED(hr))
{
if (!uNumKeys)
{
ULONGLONG uIsSingleton = 0;
hr = pKeyList->GetInfo(0, &uIsSingleton);
if (SUCCEEDED(hr))
{
if (uIsSingleton)
wcscat(lpKeyString, L"=@");
else
hr = WBEM_E_INVALID_PARAMETER;
}
}
else
{
// Get the key list from the schema cache
CWStringArray arrKeys;
hr = pCache->GetKeys(dScopeId, lpClass, arrKeys);
if (SUCCEEDED(hr))
{
if (arrKeys.Size() != uNumKeys)
{
hr = WBEM_E_INVALID_QUERY;
}
else
{
BOOL bFound = FALSE;
for (int i = 0; i < arrKeys.Size(); i++)
{
bFound = FALSE;
DWORD dwLen2 = 1024;
BYTE bBuff[1024];
wchar_t wName [1024];
ULONG ct;
for (ULONG j = 0; j < arrKeys.Size(); j++)
{
ULONG dwLen1 = 1024, dwLen2 = 1024;
hr = pKeyList->GetKey(j, 0, &dwLen1, wName, &dwLen2, bBuff, &ct);
if (SUCCEEDED(hr) && (!wcslen(wName) || !_wcsnicmp(wName, arrKeys.GetAt(i), 127)))
{
if (i > 0)
wcscat(lpKeyString, L",");
else
wcscat(lpKeyString, L".");
wcscat(lpKeyString, arrKeys.GetAt(i));
wcscat(lpKeyString, L"=");
wchar_t wValue[1024];
ConvertDataToString(wValue, bBuff, ct, TRUE);
if (FAILED(hr))
break;
wcscat(lpKeyString, wValue);
bFound = TRUE;
break;
}
}
if (!bFound)
hr = WBEM_E_INVALID_PARAMETER;
if (FAILED(hr))
break;
}
}
}
}
}
return hr;
}
BOOL IsDerivedFrom(IWbemClassObject *pObj, LPWSTR lpClassName, BOOL bDirectOnly)
{
BOOL bRet = FALSE;
VARIANT vTemp;
CClearMe c (&vTemp);
LPWSTR lpClass = GetPropertyVal(L"__Class", pObj);
CDeleteMe <wchar_t> d (lpClass);
HRESULT hr = WBEM_S_NO_ERROR;
if (!bDirectOnly)
{
if (!_wcsicmp(lpClassName, lpClass))
bRet = TRUE;
}
if (!bRet)
{
hr = pObj->Get(L"__Derivation", 0, &vTemp, NULL, NULL);
if (SUCCEEDED(hr))
{
SAFEARRAY *psaArray = V_ARRAY(&vTemp);
if (psaArray)
{
long lLBound, lUBound;
SafeArrayGetLBound(psaArray, 1, &lLBound);
SafeArrayGetUBound(psaArray, 1, &lUBound);
lUBound -= lLBound;
lUBound += 1;
for (int i = 0; i < lUBound; i++)
{
VARIANT vT2;
VariantInit(&vT2);
LPWSTR lpValue = NULL;
hr = GetVariantFromArray(psaArray, i, VT_BSTR, vT2);
lpValue = GetStr(vT2);
CDeleteMe <wchar_t> r (lpValue);
VariantClear(&vT2);
if (lpValue && !_wcsicmp(lpValue, lpClassName))
{
bRet = TRUE;
break;
}
}
}
}
}
return bRet;
}
POLARITY BOOL SetObjectAccess(
IN HANDLE hObj)
{
PSECURITY_DESCRIPTOR pSD;
DWORD dwLastErr = 0;
BOOL bRet = FALSE;
// no point if we arnt on nt
pSD = (PSECURITY_DESCRIPTOR)CWin32DefaultArena::WbemMemAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
if(pSD == NULL)
return FALSE;
ZeroMemory(pSD, SECURITY_DESCRIPTOR_MIN_LENGTH);
if(!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
goto Cleanup;
if(!SetSecurityDescriptorDacl(pSD, TRUE, NULL, FALSE))
goto Cleanup;
bRet = SetKernelObjectSecurity(hObj, DACL_SECURITY_INFORMATION, pSD);
Cleanup:
if(bRet == FALSE)
dwLastErr = GetLastError();
CWin32DefaultArena::WbemMemFree(pSD);
return bRet;
}
HINSTANCE CWmiDbController::GetResourceDll (LCID lLocale)
{
HINSTANCE hRCDll = NULL;
wchar_t wLibName[501];
GetModuleFileName(NULL, wLibName, 500);
wchar_t *pLibName = wcsrchr(wLibName, L'\\');
wchar_t *pTop = (wchar_t *)wLibName;
if (pLibName)
{
int iPos = pLibName - pTop + 1;
wLibName[iPos] = '\0';
}
swprintf(wLibName, L"%s%08X\\reprc.dll", wLibName, lLocale);
hRCDll = LoadLibrary(wLibName);
return hRCDll;
}
LPWSTR GetKeyString (LPWSTR lpString)
{
if (!lpString)
return NULL;
else
return StripQuotes(lpString);
}
//***************************************************************************
//
// CWmiDbHandle::CWmiDbHandle
//
//***************************************************************************
CWmiDbHandle::CWmiDbHandle()
{
m_dwHandleType = WMIDB_HANDLE_TYPE_NO_CACHE | WMIDB_HANDLE_TYPE_COOKIE;
m_uRefCount = 0;
m_bDefault = TRUE;
m_bSecDesc = FALSE;
m_dObjectId = 0;
m_dClassId = 0;
m_dwVersion = 1;
m_pSession = NULL;
m_pData = NULL;
}
//***************************************************************************
//
// CWmiDbHandle::CWmiDbHandle
//
//***************************************************************************
CWmiDbHandle::~CWmiDbHandle()
{
}
//***************************************************************************
//
// CWmiDbHandle::QueryInterface
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbHandle::QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
{
*ppvObject = 0;
if (IID_IUnknown==riid || IID_IWmiDbHandle==riid )
{
*ppvObject = (IWmiDbHandle*)this;
AddRef();
return S_OK;
}
else if (IID_IWbemClassObject == riid ||
IID__IWmiObject == riid)
{
if (!m_pData && m_pSession && m_dwHandleType != WMIDB_HANDLE_TYPE_INVALID)
{
if (m_dObjectId)
{
HRESULT hr = QueryInterface_Internal(NULL, ppvObject);
return hr;
}
}
else if (m_pData)
{
*ppvObject = m_pData;
m_pData->AddRef();
return S_OK;
}
else
return E_HANDLE;
}
return E_NOINTERFACE;
}
//***************************************************************************
//
// CWmiDbHandle::QueryInterface_Internal
//
//***************************************************************************
HRESULT CWmiDbHandle::QueryInterface_Internal(CSQLConnection *pConn, void __RPC_FAR *__RPC_FAR *ppvObject,
LPWSTR lpKey)
{
IWbemClassObject *pNew = NULL;
HRESULT hr = WBEM_S_NO_ERROR;
try
{
if (m_pData)
{
*ppvObject = m_pData;
m_pData->AddRef();
return S_OK;
}
else
{
hr = ((CWmiDbSession *)m_pSession)->GetObjectData(pConn, m_dObjectId, m_dClassId, m_dScopeId,
m_dwHandleType, m_dwVersion, &pNew, FALSE, lpKey, m_bSecDesc);
if (SUCCEEDED(hr) && pNew)
{
*ppvObject = (IWbemClassObject *)pNew;
// Cookie handles must be reread each time.
if ((m_dwHandleType & 0xF) != WMIDB_HANDLE_TYPE_COOKIE)
{
_WMILockit lkt(((CWmiDbSession *)m_pSession)->GetCS());
m_pData = pNew;
pNew->AddRef(); // For ourselves.
}
return S_OK;
}
else if (SUCCEEDED(hr))
hr = WBEM_E_FAILED;
else if (hr == WBEM_E_CRITICAL_ERROR &&
(!m_pSession || !((CWmiDbSession *)m_pSession)->m_pController))
hr = WBEM_E_SHUTTING_DOWN;
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbHandle::QueryInterface_Internal (%I64d)\n", m_dObjectId));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbHandle::AddRef
//
//***************************************************************************
ULONG STDMETHODCALLTYPE CWmiDbHandle::AddRef( )
{
if (m_pSession)
m_pSession->AddRef();
// We can't safely keep track of this
// so we will only addref it once.
// ==================================
//if (m_pData)
// m_pData->AddRef();
InterlockedIncrement((LONG *) &m_uRefCount);
return m_uRefCount;
}
//***************************************************************************
//
// CWmiDbHandle::Release
//
//***************************************************************************
ULONG STDMETHODCALLTYPE CWmiDbHandle::Release( )
{
ULONG uNewCount = m_uRefCount;
uNewCount = InterlockedDecrement((LONG *) &m_uRefCount);
HRESULT hr = 0;
try
{
// Only if we haven't shut down.
if (m_pSession && (((CWmiDbSession *)m_pSession)->m_pController))
{
if (!uNewCount)
{
if ((m_dwHandleType & 0xF000) == WMIDB_HANDLE_TYPE_AUTODELETE)
{
hr = ((CWmiDbSession *)m_pSession)->Delete((IWmiDbHandle *)this);
if (FAILED(hr))
return uNewCount;
}
else if (m_dwHandleType != WMIDB_HANDLE_TYPE_INVALID)
{
((CWmiDbSession *)m_pSession)->CleanCache(m_dObjectId, m_dwHandleType, this);
}
if (((CWmiDbSession *)m_pSession)->m_pController)
((CWmiDbController *)((CWmiDbSession *)m_pSession)->m_pController)->SubtractHandle();
((CWmiDbSession *)m_pSession)->UnlockDynasties();
}
m_pSession->Release();
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbHandle::Release (%I64d)\n", m_dObjectId));
hr = WBEM_E_CRITICAL_ERROR;
}
if (0 != uNewCount)
return uNewCount;
// To be safe, we will only add ref
// this once, and release it once.
// ================================
if (m_pData)
m_pData->Release();
delete this;
return uNewCount;
}
//***************************************************************************
//
// CWmiDbHandle::GetHandleType
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbHandle::GetHandleType(
/* [out] */ DWORD __RPC_FAR *pdwType)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (pdwType)
*pdwType = m_dwHandleType;
else
hr = WBEM_E_INVALID_PARAMETER;
return hr;
}
//***************************************************************************
//
// CESSManager::CESSManager
//
//***************************************************************************
CESSManager::CESSManager()
{
m_EventSubSys = NULL;
}
//***************************************************************************
//
// CESSManager::~CESSManager
//
//***************************************************************************
CESSManager::~CESSManager()
{
// Release our ESS pointer.
if (m_EventSubSys)
m_EventSubSys->Release();
}
//***************************************************************************
//
// CESSManager::InitializeESS
//
//***************************************************************************
void CESSManager::InitializeESS()
{
HRESULT hres = CoCreateInstance(CLSID_IWmiCoreServices, NULL,
CLSCTX_INPROC_SERVER, IID__IWmiCoreServices,
(void**)&m_EventSubSys);
if(FAILED(hres))
{
ERRORTRACE((LOG_WBEMCORE,"CRITICAL: Event system not available!!!!\n"));
}
}
//***************************************************************************
//
// CESSManager::AddInsertRecord
//
//***************************************************************************
HRESULT CESSManager::AddInsertRecord(CSQLConnection *pConn, LPWSTR lpGUID, LPWSTR lpNamespace, LPWSTR lpClass, DWORD dwGenus,
IWbemClassObject *pOldObj, IWbemClassObject *pNewObj)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (m_EventSubSys)
{
if (lpGUID && wcslen(lpGUID))
{
// Write record to the database.
hr = CSQLExecProcedure::InsertUncommittedEvent(pConn, lpGUID, lpNamespace, lpClass,
pOldObj, pNewObj, m_Schema);
}
else
{
long lType = 0;
if (!pOldObj && pNewObj)
{
if (dwGenus == 1)
lType = WBEM_EVENTTYPE_ClassCreation;
else
{
if (IsDerivedFrom(pNewObj, L"__Namespace"))
lType = WBEM_EVENTTYPE_NamespaceCreation;
else
lType = WBEM_EVENTTYPE_InstanceCreation;
}
}
else
{
if (dwGenus == 1)
lType = WBEM_EVENTTYPE_ClassModification;
else
{
if (IsDerivedFrom(pOldObj, L"__Namespace"))
lType = WBEM_EVENTTYPE_NamespaceModification;
else
lType = WBEM_EVENTTYPE_InstanceModification;
}
}
CESSHolder *pHolder = new CESSHolder (lType, lpNamespace, lpClass,
(_IWmiObject *)pOldObj, (_IWmiObject *)pNewObj);
if (!pHolder)
hr = WBEM_E_OUT_OF_MEMORY;
m_ESSObjs[GetCurrentThreadId()] = pHolder;
}
}
return hr;
}
//***************************************************************************
//
// CESSManager::AddDeleteRecord
//
//***************************************************************************
HRESULT CESSManager::AddDeleteRecord(CSQLConnection *pConn, LPWSTR lpGUID, LPWSTR lpNamespace, LPWSTR lpClass, DWORD dwGenus,
IWbemClassObject *pObj)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (m_EventSubSys)
{
// Write record to the database
if (lpGUID && wcslen(lpGUID))
{
// Write record to the database.
hr = CSQLExecProcedure::InsertUncommittedEvent(pConn, lpGUID, lpNamespace, lpClass, NULL,
pObj, m_Schema);
}
else
{
long lType = 0;
if (dwGenus == 1)
lType = WBEM_EVENTTYPE_ClassDeletion;
else
{
if (IsDerivedFrom(pObj, L"__Namespace"))
lType = WBEM_EVENTTYPE_NamespaceDeletion;
else
lType = WBEM_EVENTTYPE_InstanceDeletion;
}
CESSHolder *pHolder = new CESSHolder (lType, lpNamespace, lpClass, (_IWmiObject *)pObj, NULL);
if (!pHolder)
hr = WBEM_E_OUT_OF_MEMORY;
m_ESSObjs[GetCurrentThreadId()] = pHolder;
}
}
return hr;
}
//***************************************************************************
//
// CESSManager::CommitAll
//
//***************************************************************************
HRESULT CESSManager::CommitAll(LPCWSTR lpGUID, LPCWSTR lpRootNs)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (m_EventSubSys)
{
if (lpGUID && wcslen(lpGUID))
{
CSQLConnection *pConn = NULL;
hr = m_Conns->GetConnection(&pConn, FALSE, FALSE, 30);
if (SUCCEEDED(hr))
{
hr = CSQLExecProcedure::CommitEvents(pConn, m_EventSubSys,
lpRootNs, lpGUID, m_Schema, m_Objects);
m_Conns->ReleaseConnection(pConn);
}
}
else
{
DWORD dwThread = GetCurrentThreadId();
CESSHolder *pH = m_ESSObjs[dwThread];
if (pH)
pH->Deliver(m_EventSubSys, lpRootNs);
delete pH;
m_ESSObjs[dwThread] = NULL;
}
}
return hr;
}
//***************************************************************************
//
// CESSManager::DeleteAll
//
//***************************************************************************
HRESULT CESSManager::DeleteAll(LPCWSTR lpGUID)
{
HRESULT hr = WBEM_S_NO_ERROR;
// Delete from DB
if (m_EventSubSys)
{
if (lpGUID && wcslen(lpGUID))
{
CSQLConnection *pConn = NULL;
hr = m_Conns->GetConnection(&pConn, FALSE, FALSE, 30);
if (SUCCEEDED(hr))
{
hr = CSQLExecProcedure::DeleteUncommittedEvents(pConn, lpGUID, m_Schema, m_Objects);
m_Conns->ReleaseConnection(pConn);
}
}
else
{
DWORD dwThread = GetCurrentThreadId();
CESSHolder *pH = m_ESSObjs[dwThread];
delete pH;
m_ESSObjs[dwThread] = NULL;
}
}
return hr;
}
//***************************************************************************
//
// CESSHolder::CESSHolder
//
//***************************************************************************
CESSHolder::CESSHolder(long lType, LPWSTR lpNs, LPWSTR lpClass, _IWmiObject *pOld, _IWmiObject *pNew)
{
m_lType = lType;
if (lpNs && wcslen(lpNs))
m_sNamespace = lpNs;
else
m_sNamespace = L"";
m_sClass = lpClass;
if (pOld)
pOld->AddRef();
if (pNew)
pNew->AddRef();
pOldObject = pOld;
pNewObject = pNew;
}
//***************************************************************************
//
// CESSHolder::Deliver
//
//***************************************************************************
HRESULT CESSHolder::Deliver (_IWmiCoreServices *pCS, LPCWSTR lpRootNs)
{
HRESULT hr = WBEM_S_NO_ERROR;
DWORD dwNumObjs = 0;
if (pOldObject)
dwNumObjs++;
if (pNewObject)
dwNumObjs++;
_bstr_t sTemp = L"\\\\.\\";
sTemp += lpRootNs;
if (m_sNamespace.length() && _wcsnicmp(m_sNamespace, L"root", 4))
{
sTemp += L"\\";
sTemp += m_sNamespace;
}
_IWmiObject **pObjs = new _IWmiObject * [dwNumObjs];
if (pObjs)
{
if (pNewObject)
pObjs[0] = pNewObject;
else
pObjs[0] = pOldObject;
if (pOldObject && pNewObject)
pObjs[1] = pOldObject;
hr = pCS->DeliverIntrinsicEvent(sTemp, m_lType, NULL,
m_sClass, NULL, dwNumObjs, pObjs);
delete pObjs;
if (pOldObject)
pOldObject->Release();
if (pNewObject)
pNewObject->Release();
}
else
hr = WBEM_E_OUT_OF_MEMORY;
return hr;
}
//***************************************************************************
//
// CWmiDbController::CWmiDbController
//
//***************************************************************************
CWmiDbController::CWmiDbController()
{
InitializeCriticalSection(&m_cs);
m_dwTimeOut = 10*1000; // 30 seconds default
m_dwCurrentStatus = 0; // No status
m_uRefCount = 0;
m_pIMalloc = NULL;
m_InitProperties = NULL;
m_rgInitPropSet = NULL;
m_dwTotalHits = 0;
m_dwCacheHits = 0;
m_dwTotalHandles = 0;
m_bCacheInit = 0;
m_bIsAdmin = 0;
m_bESSEnabled = 0;
CoInitialize(NULL);
ESSMgr.SetConnCache(&ConnCache);
ESSMgr.SetObjectCache(&ObjectCache);
ESSMgr.SetSchemaCache(&SchemaCache);
}
//***************************************************************************
//
// CWmiDbController::CWmiDbController
//
//***************************************************************************
CWmiDbController::~CWmiDbController()
{
Shutdown(0);
if (m_pIMalloc)
m_pIMalloc->Release();
delete m_InitProperties;
delete m_rgInitPropSet;
g_cObj--;
DeleteCriticalSection(&m_cs);
}
//***************************************************************************
//
// CWmiDbController::QueryInterface
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbController::QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
{
*ppvObject = 0;
if (IID_IUnknown==riid || IID_IWmiDbController==riid )
{
*ppvObject = (IWmiDbController*)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
//***************************************************************************
//
// CWmiDbController::AddRef
//
//***************************************************************************
ULONG STDMETHODCALLTYPE CWmiDbController::AddRef( )
{
InterlockedIncrement((LONG *) &m_uRefCount);
return m_uRefCount;
}
//***************************************************************************
//
// CWmiDbController::Release
//
//***************************************************************************
ULONG STDMETHODCALLTYPE CWmiDbController::Release( )
{
ULONG uNewCount = InterlockedDecrement((LONG *) &m_uRefCount);
if (0 != uNewCount)
return uNewCount;
delete this;
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
// CWmiDbController::FreeLogonTemplate
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbController::FreeLogonTemplate(
/* [out][in] */ WMIDB_LOGON_TEMPLATE __RPC_FAR *__RPC_FAR *pTemplate)
{
HRESULT hr = WBEM_S_NO_ERROR;
try
{
if (!pTemplate || !*pTemplate)
hr = WBEM_E_INVALID_PARAMETER;
else
{
WMIDB_LOGON_TEMPLATE *pTemp = *pTemplate;
for (int i = 0; i < (int)pTemp->dwArraySize; i++)
{
VariantClear(&(pTemp->pParm[i].Value));
SysFreeString(pTemp->pParm[i].strParmDisplayName);
}
delete []pTemp->pParm;
delete *pTemplate;
*pTemplate = NULL;
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbController::FreeLogonTemplate\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbController::Logon
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbController::Logon(
/* [in] */ WMIDB_LOGON_TEMPLATE __RPC_FAR *pLogonParms,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwRequestedHandleType,
/* [out] */ IWmiDbSession __RPC_FAR *__RPC_FAR *ppSession,
/* [out] */ IWmiDbHandle __RPC_FAR *__RPC_FAR *ppRootNamespace)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (!pLogonParms)
return WBEM_E_INVALID_PARAMETER;
if (dwFlags &~ WMIDB_FLAG_NO_INIT &~ WMIDB_FLAG_ADMIN_VERIFIED)
return WBEM_E_INVALID_PARAMETER;
// Not yet clear what we need to do.
// Best guess is: we get a SQL connection, shove it into an IWmiDbSession,
// and give it back to the user.
try
{
if (m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
hr = WBEM_E_SHUTTING_DOWN;
else
{
if (!ppSession)
hr = WBEM_E_INVALID_PARAMETER;
else
{
_WMILockit lkt(&m_cs);
IWmiDbSession *pSession = NULL;
hr = GetUnusedSession(pLogonParms, dwFlags, dwRequestedHandleType, &pSession);
if (SUCCEEDED(hr))
{
*ppSession = pSession; // hopefully this interface will be corrected...
if (!(dwFlags & WMIDB_FLAG_NO_INIT))
{
if (!m_bCacheInit)
{
hr = ((CWmiDbSession *)pSession)->LoadSchemaCache();
// We don't want to return a handle if we couldn't load the schema cache.
if (SUCCEEDED(hr))
m_bCacheInit = TRUE;
}
if (dwFlags & WMIDB_FLAG_ADMIN_VERIFIED)
m_bIsAdmin = TRUE;
// Now see if we can get a handle to the root namespace...
hr = ((CWmiDbSession *)pSession)->GetObject_Internal(L"root", dwFlags, dwRequestedHandleType, NULL, ppRootNamespace);
((CWmiDbSession *)pSession)->m_sNamespacePath = L"root"; // Temporary default
wchar_t wMachineName[1024];
DWORD dwLen=1024;
if (!GetComputerName(wMachineName, &dwLen)) {
hr = GetLastError();
return WBEM_E_FAILED;
}
((CWmiDbSession *)pSession)->m_sMachineName = wMachineName;
if (!m_bESSEnabled)
{
ESSMgr.InitializeESS();
if (ESSMgr.m_EventSubSys)
m_bESSEnabled = TRUE;
}
}
else if (ppRootNamespace)
*ppRootNamespace = NULL;
}
}
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbController::Logon\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbController::Shutdown
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbController::Shutdown(
/* [in] */ DWORD dwFlags)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (dwFlags != 0)
return WBEM_E_INVALID_PARAMETER;
if (m_dwCurrentStatus)
hr = m_dwCurrentStatus;
else
m_dwCurrentStatus = WBEM_E_SHUTTING_DOWN;
try
{
FlushCache(REPDRVR_FLAG_FLUSH_ALL);
hr = ConnCache.ClearConnections();
for (int i = 0; i < m_Sessions.size(); i++)
{
IWmiDbSession *pSession = m_Sessions[i];
if (pSession)
{
((CWmiDbSession *)pSession)->ShutDown();
pSession->Release();
}
}
m_Sessions.clear();
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbController::Shutdown\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbController::SetCallTimeout
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbController::SetCallTimeout(
/* [in] */ DWORD dwMaxTimeout)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (dwMaxTimeout < 1000)
return WBEM_E_INVALID_PARAMETER;
if (m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
hr = WBEM_E_SHUTTING_DOWN;
else
m_dwTimeOut = dwMaxTimeout;
return hr;
}
//***************************************************************************
//
// CWmiDbController::SetCacheValue
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbController::SetCacheValue(
/* [in] */ DWORD dwMaxBytes)
{
HRESULT hr = WBEM_S_NO_ERROR;
try
{
if (m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
hr = WBEM_E_SHUTTING_DOWN;
else
{
ObjectCache.SetCacheSize(dwMaxBytes);
SchemaCache.SetMaxSize(dwMaxBytes);
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbController::SetCacheValue\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbController::FlushCache
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbController::FlushCache(
DWORD dwFlags)
{
HRESULT hr = WBEM_S_NO_ERROR;
try
{
// Remove all data from the cache.
{
_WMILockit lkt(&m_cs);
ObjectCache.EmptyCache();
}
if (dwFlags == REPDRVR_FLAG_FLUSH_ALL)
{
// Remove all SQL connections. We will reconnect later.
hr = ConnCache.ClearConnections();
// Clear all internal caches. These will be restored on the next connection.
{
_WMILockit lkt(&m_cs);
SchemaCache.EmptyCache();
}
m_bCacheInit = FALSE;
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbController::FlushCache\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbController::GetStatistics
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbController::GetStatistics(
/* [in] */ DWORD dwParameter,
/* [out] */ DWORD __RPC_FAR *pdwValue)
{
HRESULT hr = WBEM_S_NO_ERROR;
DWORD dwTemp1 = 0;
DWORD dwTemp2 = 0;
_WMILockit _lk(&m_cs);
try
{
if (!pdwValue)
hr = WBEM_E_INVALID_PARAMETER;
else
{
switch (dwParameter)
{
case WMIDB_FLAG_TOTAL_HANDLES:
*pdwValue = m_dwTotalHandles;
break;
case WMIDB_FLAG_CACHE_SATURATION:
ObjectCache.GetCurrentUsage(dwTemp1);
ObjectCache.GetCacheSize(dwTemp2);
if (dwTemp2 > 0)
*pdwValue = 100*(((double)dwTemp1/(double)dwTemp2));
break;
case WMIDB_FLAG_CACHE_HIT_RATE:
if (m_dwTotalHits > 0)
*pdwValue = 100*((double)m_dwCacheHits / (double)m_dwTotalHits);
break;
default:
hr = WBEM_E_NOT_SUPPORTED;
break;
}
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbController::GetStatistics\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbController::GetUnusedSession
//
//***************************************************************************
HRESULT CWmiDbController::GetUnusedSession(WMIDB_LOGON_TEMPLATE *pLogon,
DWORD dwFlags,
DWORD dwHandleType,
IWmiDbSession **pSess)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
CWmiDbSession *pSession = NULL;
Sessions::iterator walk = m_Sessions.begin();
while (walk != m_Sessions.end())
{
pSession = *walk;
if (!(pSession)->m_bInUse)
{
(pSession)->m_bInUse = TRUE;
break;
}
walk++;
}
if (!pSession)
{
hr = SetConnProps(pLogon);
if (SUCCEEDED(hr))
{
pSession = new CWmiDbSession(this);
if (pSession)
{
(pSession)->m_bInUse = TRUE;
pSession->m_dwLocale = pLogon->pParm[4].Value.lVal;
m_Sessions.push_back(pSession);
pSession->m_pIMalloc = m_pIMalloc;
pSession->AddRef(); // For us
pSession->AddRef(); // For the end user.
*pSess = pSession;
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
{
hr = SetConnProps(pLogon);
pSession->m_dwLocale = pLogon->pParm[4].Value.lVal;
pSession->AddRef();
}
hr = ConnCache.SetCredentials(m_rgInitPropSet);
hr = ConnCache.SetMaxConnections (20);
hr = ConnCache.SetTimeoutSecs(60);
if (pLogon->pParm[3].Value.vt == VT_BSTR)
hr = ConnCache.SetDatabase(pLogon->pParm[3].Value.bstrVal);
else
hr = ConnCache.SetDatabase(L""); // This isn't a SQL db.
// Make sure the login credentials worked.
// If they specified "No initialization", they
// don't intend to use the database - they are
// probably going to perform a backup or restore.
if (!(dwFlags & WMIDB_FLAG_NO_INIT))
{
CSQLConnection *pConn;
hr = ConnCache.GetConnection(&pConn, FALSE, FALSE, 30);
if (SUCCEEDED(hr))
ConnCache.ReleaseConnection(pConn);
}
return hr;
}
//***************************************************************************
//
// CWmiDbController::SetConnProps
//
//***************************************************************************
HRESULT CWmiDbController::SetConnProps(WMIDB_LOGON_TEMPLATE *pLogon)
{
HRESULT hr = WBEM_S_NO_ERROR;
ULONG nProps = pLogon->dwArraySize + 2 ;
// This just sets the latest connection properties.
// MOVE ME: SQL Server-specific optimization.
// wchar_t wMachineName[MAX_COMPUTERNAME_LENGTH+1];
// DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
// GetComputerName(wMachineName, &dwSize);
// if (!wcscmp(pLogon->pParm[0].strParmDisplayName, wMachineName))
// wcscpy(wMachineName, L".");
// else
// wcscpy(wMachineName, pLogon->pParm[0].Value.bstrVal);
if (!m_InitProperties)
{
m_InitProperties = new DBPROP[nProps];
if (!m_InitProperties)
return WBEM_E_OUT_OF_MEMORY;
m_rgInitPropSet = new DBPROPSET;
if (!m_rgInitPropSet)
{
delete m_InitProperties;
return WBEM_E_OUT_OF_MEMORY;
}
}
int i = 0;
m_InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
m_InitProperties[i].dwPropertyID = DBPROP_INIT_PROMPT;
m_InitProperties[i].vValue.vt = VT_I2;
m_InitProperties[i].vValue.iVal = DBPROMPT_NOPROMPT;
m_InitProperties[i].colid = DB_NULLID;
i++;
for (i = 1; i < (pLogon->dwArraySize + 1); i++ )
{
m_InitProperties[i].colid = DB_NULLID;
VariantInit(&m_InitProperties[i].vValue);
m_InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
m_InitProperties[i].dwPropertyID = pLogon->pParm[i-1].dwId;
m_InitProperties[i].vValue.vt = pLogon->pParm[i-1].Value.vt;
if (pLogon->pParm[i-1].Value.vt == VT_BSTR)
m_InitProperties[i].vValue.bstrVal = SysAllocString(pLogon->pParm[i-1].Value.bstrVal);
else if (pLogon->pParm[i-1].Value.vt == VT_I4)
m_InitProperties[i].vValue.lVal = pLogon->pParm[i-1].Value.lVal;
}
m_InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
m_InitProperties[i].colid = DB_NULLID;
m_InitProperties[i].dwPropertyID = DBPROP_INIT_TIMEOUT;
m_InitProperties[i].vValue.vt = VT_I4;
m_InitProperties[i].vValue.lVal = (long)m_dwTimeOut;
m_rgInitPropSet->guidPropertySet = DBPROPSET_DBINIT;
m_rgInitPropSet->cProperties = nProps;
m_rgInitPropSet->rgProperties = m_InitProperties;
return hr;
}
//***************************************************************************
//
// CWmiDbController::ReleaseSession
//
//***************************************************************************
HRESULT CWmiDbController::ReleaseSession(IWmiDbSession *pSession)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(&m_cs);
// Mark connection unused and stick back in cache.
Sessions::iterator walk = m_Sessions.begin();
while (walk != m_Sessions.end())
{
CWmiDbSession *pConn2 = *walk;
if (pConn2 == ((CWmiDbSession *)pSession))
{
pConn2->m_bInUse = FALSE;
break;
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbController::IncrementHitCount
//
//***************************************************************************
void CWmiDbController::IncrementHitCount (bool bCacheUsed)
{
_WMILockit lkt(&m_cs);
m_dwTotalHits++;
if (bCacheUsed)
m_dwCacheHits++;
}
//***************************************************************************
//
// CWmiDbController::AddHandle
//
//***************************************************************************
void CWmiDbController::AddHandle()
{
_WMILockit lkt(&m_cs);
m_dwTotalHandles++;
}
//***************************************************************************
//
// CWmiDbController::SubtractHandle
//
//***************************************************************************
void CWmiDbController::SubtractHandle()
{
_WMILockit lkt(&m_cs);
if (m_dwTotalHandles > 0)
m_dwTotalHandles--;
}
//***************************************************************************
//
// CWmiDbController::HasSecurityDescriptor
//
//***************************************************************************
BOOL CWmiDbController::HasSecurityDescriptor(SQL_ID ObjId)
{
BOOL bRet = FALSE;
_WMILockit _Lk(&m_cs);
SQL_IDMap::iterator it = SecuredIDs.find(ObjId);
if (it != SecuredIDs.end())
bRet = TRUE;
return bRet;
}
//***************************************************************************
//
// CWmiDbController::HasSecurityDescriptor
//
//***************************************************************************
void CWmiDbController::AddSecurityDescriptor(SQL_ID ObjId)
{
_WMILockit _Lk(&m_cs);
SecuredIDs[ObjId] = true;
}
//***************************************************************************
//
// CWmiDbController::HasSecurityDescriptor
//
//***************************************************************************
void CWmiDbController::RemoveSecurityDescriptor(SQL_ID ObjId)
{
_WMILockit _Lk(&m_cs);
SQL_IDMap::iterator it = SecuredIDs.find(ObjId);
if (it != SecuredIDs.end())
SecuredIDs.erase(it);
}
//***************************************************************************
//
// CWmiDbSession::CWmiDbSession
//
//***************************************************************************
CWmiDbSession::CWmiDbSession(IWmiDbController *pControl)
{
m_uRefCount = 0;
m_pController = pControl;
m_dwLocale = 0;
m_bInUse = false;
m_pIMalloc = NULL;
m_bIsDistributed = FALSE;
m_pController->AddRef();
}
//***************************************************************************
//
// CWmiDbSession::CWmiDbSession
//
//***************************************************************************
CWmiDbSession::~CWmiDbSession()
{
if (m_pController)
{
((CWmiDbController *)m_pController)->ReleaseSession(this);
m_pController->Release();
}
if (m_pIMalloc)
m_pIMalloc->Release();
}
//***************************************************************************
//
// CWmiDbSession::QueryInterface
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
{
*ppvObject = 0;
if (IID_IUnknown==riid || IID_IWmiDbSession==riid )
{
*ppvObject = (IWmiDbSession*)this;
AddRef();
return S_OK;
}
else if (IID_IWmiDbBatchSession == riid)
{
*ppvObject = (IWmiDbBatchSession*)this;
AddRef();
return S_OK;
}
else if (IID_IWbemTransaction == riid)
{
*ppvObject = (IWbemTransaction*)this;
AddRef();
return S_OK;
}
else if (IID_IWmiDbBackupRestore == riid)
{
*ppvObject = (IWmiDbBackupRestore*)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
//***************************************************************************
//
// CWmiDbSession::AddRef
//
//***************************************************************************
ULONG STDMETHODCALLTYPE CWmiDbSession::AddRef( )
{
InterlockedIncrement((LONG *) &m_uRefCount);
return m_uRefCount;
}
//***************************************************************************
//
// CWmiDbSession::Release
//
//***************************************************************************
ULONG STDMETHODCALLTYPE CWmiDbSession::Release( )
{
ULONG uNewCount = InterlockedDecrement((LONG *) &m_uRefCount);
if (0 != uNewCount)
return uNewCount;
delete this;
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
// CWmiDbSession::GetObject
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::GetObject(
/* [in] */ IWmiDbHandle __RPC_FAR *pScope,
/* [in] */ IWbemPath __RPC_FAR *pPath,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwRequestedHandleType,
/* [out] */ IWmiDbHandle __RPC_FAR *__RPC_FAR *ppResult)
{
HRESULT hr = WBEM_S_NO_ERROR;
// SYSTEMTIME tStartTime, tEndTime;
// GetLocalTime(&tStartTime);
// StartCAP();
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (!pScope
|| !pPath
|| dwRequestedHandleType == WMIDB_HANDLE_TYPE_INVALID
|| !ppResult
|| (dwRequestedHandleType & ~WMIDB_HANDLE_TYPE_COOKIE
&~WMIDB_HANDLE_TYPE_VERSIONED &~WMIDB_HANDLE_TYPE_PROTECTED
&~WMIDB_HANDLE_TYPE_EXCLUSIVE &~ WMIDB_HANDLE_TYPE_WEAK_CACHE
&~WMIDB_HANDLE_TYPE_STRONG_CACHE &~ WMIDB_HANDLE_TYPE_NO_CACHE
&~WMIDB_HANDLE_TYPE_SUBSCOPED &~WMIDB_HANDLE_TYPE_SCOPE
&~WMIDB_HANDLE_TYPE_CONTAINER))
return WBEM_E_INVALID_PARAMETER;
try
{
{
_WMILockit lkt(GetCS());
if (!((CWmiDbController *)m_pController)->m_bCacheInit)
{
hr = LoadSchemaCache();
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->m_bCacheInit = TRUE;
else
return hr;
}
}
_bstr_t sNewPath;
SQL_ID dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
if (SUCCEEDED(hr))
{
LPWSTR lpNewPath = NULL;
BOOL bStoreDefault = TRUE;
SQL_ID dStorageClassId = 0;
hr = NormalizeObjectPathGet(pScope, pPath, &lpNewPath, &bStoreDefault, &dStorageClassId, &dScopeId);
CDeleteMe <wchar_t> r(lpNewPath);
if (SUCCEEDED(hr))
{
if (bStoreDefault)
{
// Handle the __Instances container.
// since this is not a real object.
if (dStorageClassId == INSTANCESCLASSID)
{
if (((dwRequestedHandleType & 0xF) != WMIDB_HANDLE_TYPE_COOKIE &&
(dwRequestedHandleType & 0xF) != WMIDB_HANDLE_TYPE_VERSIONED) ||
!bStoreDefault)
hr = WBEM_E_INVALID_PARAMETER;
else
{
SQL_ID dScopeId2 = dScopeId;
hr = GetObject_Internal(L"__Instances", dwFlags, dwRequestedHandleType,
&dScopeId2, ppResult);
if (SUCCEEDED(hr))
{
SQL_ID dClassId;
hr = GetSchemaCache()->GetClassID(lpNewPath, dScopeId, dClassId);
if (SUCCEEDED(hr))
{
CWmiDbHandle *pTemp = (CWmiDbHandle *)*ppResult;
pTemp->m_dObjectId = dClassId;
pTemp->m_dClassId = INSTANCESCLASSID;
pTemp->m_dScopeId = dScopeId;
}
}
}
}
else
hr = GetObject_Internal(lpNewPath, dwFlags, dwRequestedHandleType, &dScopeId, ppResult);
if (SUCCEEDED(hr))
{
// Mark this object as "custom" if
// this is a descendant of a custom scope,
// or if this is a custom namespace.
CWmiDbHandle *pTemp = (CWmiDbHandle *)*ppResult;
pTemp->m_bDefault = ((CWmiDbHandle *)pScope)->m_bDefault;
if (pTemp->m_dClassId == MAPPEDNSCLASSID)
pTemp->m_bDefault = FALSE;
}
}
// Use the custom storage mechanism.
else
{
// This needs to take care of all security and locks!!
hr = CustomGetObject(pScope, pPath, lpNewPath, dwFlags, dwRequestedHandleType, ppResult);
}
// GetLocalTime(&tEndTime);
// ERRORTRACE((LOG_WBEMCORE, "IWmiDbSession::GetObject (%S) - %ld ms\n", lpNewPath, GetDiff(tEndTime, tStartTime)));
}
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::GetObject\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
// StopCAP();
return hr;
}
//***************************************************************************
//
// CWmiDbSession::GetObjectDirect
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::GetObjectDirect(
/* [in] */ IWmiDbHandle __RPC_FAR *pScope,
/* [in] */ IWbemPath __RPC_FAR *pPath,
/* [in] */ DWORD dwFlags,
/* [in] */ REFIID riid,
/* [iid_is][out] */ LPVOID __RPC_FAR *pObj)
{
HRESULT hr = WBEM_S_NO_ERROR;
try
{
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
IWmiDbHandle *pHandle= NULL;
CSQLConnection *pConn = NULL;
hr = GetSQLCache()->GetConnection(&pConn, FALSE, IsDistributed());
if (SUCCEEDED(hr))
{
LPWSTR lpNewPath = NULL;
BOOL bStoreDefault = TRUE;
SQL_ID dStorageClassId = 0;
SQL_ID dScopeId;
IWmiDbHandle *pHandle = NULL;
hr = NormalizeObjectPathGet(pScope, pPath, &lpNewPath, &bStoreDefault, &dStorageClassId, &dScopeId, pConn);
CDeleteMe <wchar_t> r(lpNewPath);
if (!bStoreDefault || (dStorageClassId == INSTANCESCLASSID))
hr = GetObject(pScope, pPath, dwFlags, WMIDB_HANDLE_TYPE_COOKIE, &pHandle);
else if (SUCCEEDED(hr))
hr = GetObject_Internal(lpNewPath, dwFlags, WMIDB_HANDLE_TYPE_COOKIE, &dScopeId, &pHandle, pConn);
if (SUCCEEDED(hr))
{
CReleaseMe r (pHandle);
hr = ((CWmiDbHandle *)pHandle)->QueryInterface_Internal(pConn, pObj);
}
GetSQLCache()->ReleaseConnection(pConn, hr, IsDistributed());
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::GetObjectDirect\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::GetObject
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::GetObject_Internal(
/* [in] */ LPWSTR lpPath, /* The full path */
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwRequestedHandleType,
/* [in] */ SQL_ID *pScopeId,
/* [out] */ IWmiDbHandle __RPC_FAR *__RPC_FAR *ppResult,
CSQLConnection *pConn)
{
HRESULT hr = WBEM_S_NO_ERROR;
bool bImmediate = !(dwRequestedHandleType & WMIDB_HANDLE_TYPE_SUBSCOPED);
SQL_ID dScopeId = 0;
if (pScopeId)
dScopeId = *pScopeId;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (!lpPath)
return WBEM_E_INVALID_PARAMETER;
*ppResult = NULL;
SQL_ID dObjId = 0, dClassId = 0;
LPWSTR lpKey = GetKeyString(lpPath);
CDeleteMe <wchar_t> r(lpKey);
BOOL bGetScope = FALSE;
BOOL bNeedToRelease = FALSE;
if (!pConn)
{
hr = GetSQLCache()->GetConnection(&pConn, FALSE, IsDistributed());
bNeedToRelease = TRUE;
if (FAILED(hr))
return hr;
}
// Special-case: Go up to the previous scope
if (!wcscmp(lpPath, L".."))
{
hr = GetSchemaCache()->GetParentNamespace(dScopeId, dObjId, &dClassId);
if (FAILED(hr))
{
BOOL bExists = FALSE;
hr = GetObjectCache()->GetObject(dScopeId, NULL, &dObjId);
if (FAILED(hr))
bGetScope = TRUE;
else
hr = CSQLExecProcedure::ObjectExists(pConn, dObjId, bExists, &dClassId, NULL);
}
}
else
hr = GetObjectCache()->GetObjectId(lpKey, dObjId, dClassId, &dScopeId);
if (FAILED(hr))
{
hr = WBEM_S_NO_ERROR;
if (SUCCEEDED(hr))
{
BOOL bExists = FALSE;
if (!bGetScope)
{
hr = CSQLExecProcedure::ObjectExists(pConn, dObjId, bExists, &dClassId, &dScopeId);
if (hr == E_NOTIMPL)
{
hr = CSQLExecProcedure::GetObjectIdByPath(pConn, lpKey, dObjId, dClassId, &dScopeId);
if (dObjId)
bExists = TRUE;
}
}
else
{
// If we are getting the parent object,
// hit the db again to find the essentials there.
hr = CSQLExecProcedure::ObjectExists(pConn, dScopeId, bExists, &dClassId, &dObjId);
if (SUCCEEDED(hr))
hr = CSQLExecProcedure::ObjectExists(pConn, dObjId, bExists, &dClassId, &dScopeId);
}
if (SUCCEEDED(hr) && bExists)
{
// If a cookie or protected handle, just ref count.
// If exclusive, there can be only one.
// If versioned, we need to keep each version separate.
if ((dwRequestedHandleType & 0xF) == WMIDB_HANDLE_TYPE_COOKIE ||
(dwRequestedHandleType & 0xF) == WMIDB_HANDLE_TYPE_PROTECTED)
((CWmiDbController *)m_pController)->LockCache.GetHandle(dObjId, dwRequestedHandleType, ppResult);
if (*ppResult == NULL)
{
// If this object exists, try and obtain the requested lock.
CWmiDbHandle *pTemp = new CWmiDbHandle;
if (pTemp)
{
DWORD dwVersion = 0;
pTemp->m_pSession = this;
AddRef_Lock();
// If this is a class, we want to lock its parents.
if (!(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
{
DWORD dwReq = WBEM_ENABLE;
if (dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
dwReq |= READ_CONTROL;
hr = VerifyObjectSecurity(pConn, dObjId, dClassId, dScopeId, 0, dwReq);
}
if (SUCCEEDED(hr))
{
if (IsDistributed())
{
// Does this lock exist locally?
hr = ((CWmiDbController *)m_pController)->LockCache.AddLock(false, dObjId,
WMIDB_HANDLE_TYPE_PROTECTED, pTemp, dScopeId, dClassId,
&((CWmiDbController *)m_pController)->SchemaCache, false, 0, 0, &dwVersion);
if (FAILED(hr))
{
// OK if the lock has already been taken
// on this session...
if (LockExists(dObjId))
hr = WBEM_S_NO_ERROR;
}
if (SUCCEEDED(hr))
hr = AddTransLock(dObjId, WMIDB_HANDLE_TYPE_PROTECTED);
}
if (SUCCEEDED(hr))
{
hr = ((CWmiDbController *)m_pController)->LockCache.AddLock(bImmediate, dObjId, dwRequestedHandleType, pTemp,
dScopeId, dClassId, &((CWmiDbController *)m_pController)->SchemaCache, false, 0, 0, &dwVersion);
}
}
if (FAILED(hr))
{
delete pTemp;
*ppResult = NULL;
}
else
{
// We have the lock. They will have to call Release() to
// free it up.
((CWmiDbController *)m_pController)->AddHandle();
pTemp->AddRef();
pTemp->m_dwHandleType = dwRequestedHandleType;
pTemp->m_dObjectId = dObjId;
pTemp->m_bDefault = TRUE;
pTemp->m_dClassId = dClassId;
pTemp->m_dScopeId = dScopeId;
pTemp->m_dwVersion = dwVersion;
if (dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
pTemp->m_bSecDesc = TRUE;
if (ppResult)
*ppResult = pTemp;
}
}
else
{
if (ppResult)
*ppResult = NULL;
hr = WBEM_E_OUT_OF_MEMORY;
}
if (m_pController)
((CWmiDbController *)m_pController)->IncrementHitCount(false);
}
}
else if (SUCCEEDED(hr))
hr = WBEM_E_NOT_FOUND;
}
}
else
{
if (!(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
{
DWORD dwReq = WBEM_ENABLE;
if (dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
dwReq |= READ_CONTROL;
hr = VerifyObjectSecurity(pConn, dObjId, dClassId, dScopeId, 0, dwReq);
}
if (SUCCEEDED(hr))
{
// At this point, we know that the object has been
// cached. Try to obtain a lock.
// ===============================================
CWmiDbHandle *pTemp = new CWmiDbHandle;
if (pTemp)
{
DWORD dwVersion = 0;
pTemp->m_pSession = this;
hr = ((CWmiDbController *)m_pController)->LockCache.AddLock(bImmediate, dObjId, dwRequestedHandleType, pTemp,
dScopeId, dClassId, &((CWmiDbController *)m_pController)->SchemaCache, false, 0, 0, &dwVersion);
if (SUCCEEDED(hr))
{
AddRef_Lock();
((CWmiDbController *)m_pController)->AddHandle();
pTemp->AddRef();
pTemp->m_dwHandleType = dwRequestedHandleType;
pTemp->m_dObjectId = dObjId;
pTemp->m_bDefault = TRUE;
pTemp->m_dClassId = dClassId;
pTemp->m_dScopeId = dScopeId;
pTemp->m_dwVersion = dwVersion;
pTemp->m_pData = NULL;
if (dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
pTemp->m_bSecDesc = TRUE;
if (ppResult)
*ppResult = pTemp;
// We won't bother attaching the object part until they
// ask for it.
}
else
{
delete pTemp;
*ppResult = NULL;
}
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
if (m_pController)
((CWmiDbController *)m_pController)->IncrementHitCount(true);
}
if (bNeedToRelease)
GetSQLCache()->ReleaseConnection(pConn, hr, IsDistributed());
if (pScopeId)
*pScopeId = dScopeId;
return hr;
}
//***************************************************************************
//
// CWmiDbSession::PutObject
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::PutObject(
/* [in] */ IWmiDbHandle __RPC_FAR *pScope,
/* [in] */ REFIID riid,
/* [iid_is][in] */ LPVOID pObjToPut,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwRequestedHandleType,
/* [out] */ IWmiDbHandle __RPC_FAR *__RPC_FAR *ppResult)
{
HRESULT hr = 0;
CSQLConnection *pConn = NULL;
AddRef_Lock();
// StartCAP();
//SYSTEMTIME tStartTime, tEndTime;
//GetLocalTime(&tStartTime);
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (dwFlags & ~WBEM_FLAG_CREATE_ONLY & ~WBEM_FLAG_UPDATE_ONLY & ~WBEM_FLAG_CREATE_OR_UPDATE
& ~WMIDB_DISABLE_EVENTS & ~WBEM_FLAG_USE_SECURITY_DESCRIPTOR &~ WBEM_FLAG_REMOVE_CHILD_SECURITY
& ~WMIDB_FLAG_ADMIN_VERIFIED &~ WBEM_FLAG_UPDATE_SAFE_MODE &~ WBEM_FLAG_UPDATE_FORCE_MODE)
return WBEM_E_INVALID_PARAMETER;
if ((ppResult && (dwRequestedHandleType == WMIDB_HANDLE_TYPE_INVALID))
|| !pScope
|| !pObjToPut)
return WBEM_E_INVALID_PARAMETER;
if (riid != IID_IWbemClassObject &&
riid != IID_IWmiDbHandle &&
riid != IID__IWmiObject)
return WBEM_E_NOT_SUPPORTED;
try
{
{
_WMILockit lkt(GetCS());
if (!((CWmiDbController *)m_pController)->m_bCacheInit)
{
hr = LoadSchemaCache();
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->m_bCacheInit = TRUE;
else
return hr;
}
}
hr = GetSQLCache()->GetConnection(&pConn, TRUE, IsDistributed());
if (SUCCEEDED(hr))
{
_bstr_t sWaste = L"";
BOOL bSys = FALSE;
hr = PutObject(pConn, pScope, 0, L"", (IUnknown *)pObjToPut, dwFlags, dwRequestedHandleType, sWaste, ppResult);
if (SUCCEEDED(hr) && ppResult)
{
CWmiDbHandle *pTemp = (CWmiDbHandle *)*ppResult;
pTemp->m_bDefault = ((CWmiDbHandle *)pScope)->m_bDefault;
if (pTemp->m_dClassId == MAPPEDNSCLASSID)
pTemp->m_bDefault = FALSE;
}
GetSQLCache()->ReleaseConnection(pConn, hr, IsDistributed());
if (!(dwFlags & WMIDB_DISABLE_EVENTS) && !IsDistributed())
{
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->ESSMgr.CommitAll(m_sGUID, m_sNamespacePath);
}
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::PutObject\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
// StopCAP();
UnlockDynasties();
return hr;
}
//***************************************************************************
//
// CWmiDbSession::PutObject
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::PutObject(
CSQLConnection *pConn,
IWmiDbHandle __RPC_FAR *pScope,
SQL_ID dScopeID,
LPWSTR lpScopePath,
/* [in] */ IUnknown __RPC_FAR *pObjToPut,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwRequestedHandleType,
_bstr_t &sPath,
/* [out] */ IWmiDbHandle __RPC_FAR *__RPC_FAR *ppResult,
BOOL bStoreAsClass )
{
HRESULT hr = WBEM_S_NO_ERROR;
SQL_ID dObjectId = 0;
IWmiDbHandle *pHandle = NULL;
bool bClass = false, bLockVerified = false;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if ((dwRequestedHandleType == WMIDB_HANDLE_TYPE_INVALID) && ppResult)
return WBEM_E_INVALID_PARAMETER;
if (dwRequestedHandleType & ~WMIDB_HANDLE_TYPE_COOKIE
&~WMIDB_HANDLE_TYPE_VERSIONED &~WMIDB_HANDLE_TYPE_PROTECTED
&~WMIDB_HANDLE_TYPE_EXCLUSIVE &~ WMIDB_HANDLE_TYPE_WEAK_CACHE
&~WMIDB_HANDLE_TYPE_STRONG_CACHE &~ WMIDB_HANDLE_TYPE_NO_CACHE
&~WMIDB_HANDLE_TYPE_SUBSCOPED&~WMIDB_HANDLE_TYPE_AUTODELETE
&~WMIDB_HANDLE_TYPE_CONTAINER &~ WMIDB_HANDLE_TYPE_SCOPE )
return WBEM_E_INVALID_PARAMETER;
bool bImmediate = !(dwRequestedHandleType & WMIDB_HANDLE_TYPE_SUBSCOPED);
SQL_ID dClassId = 0;
// Hand this to the repository, to ensure that it cleans up
// any autodelete objects on failure.
dwFlags |= (dwRequestedHandleType & WMIDB_HANDLE_TYPE_AUTODELETE);
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
// Normalize the object path.
sPath = L"";
BOOL bStoreDefault = TRUE;
IWbemClassObject *pOutObj = NULL;
LPWSTR lpScope = NULL;
if (pScope)
{
if (GetSchemaCache()->IsDerivedClass
(INSTANCESCLASSID, ((CWmiDbHandle *)pScope)->m_dClassId) ||
((CWmiDbHandle *)pScope)->m_dClassId == INSTANCESCLASSID)
hr = WBEM_E_INVALID_OPERATION;
else
{
CWbemClassObjectProps *pProps= NULL;
hr = NormalizeObjectPath(pScope, (LPWSTR)NULL, &lpScope, FALSE, &pProps, &bStoreDefault, pConn);
CDeleteMe <CWbemClassObjectProps> r (pProps);
dScopeID = ((CWmiDbHandle *)pScope)->m_dObjectId;
if (SUCCEEDED(hr) && dScopeID)
{
SQL_ID dParent = 0;
LPWSTR lpScopeKey = GetKeyString(lpScope);
CDeleteMe <wchar_t> r1 (lpScopeKey);
if (FAILED(GetSchemaCache()->GetNamespaceID(lpScopeKey, dParent)))
{
if (pProps)
{
DWORD dwTempHandle = ((CWmiDbHandle *)pScope)->m_dwHandleType;
((CWmiDbHandle *)pScope)->m_dwHandleType |= WMIDB_HANDLE_TYPE_STRONG_CACHE;
IWbemClassObject *pObj = NULL;
hr = ((CWmiDbHandle *)pScope)->QueryInterface_Internal(pConn, (void **)&pObj);
CReleaseMe r (pObj);
((CWmiDbHandle *)pScope)->m_dwHandleType = dwTempHandle;
if (SUCCEEDED(hr))
{
if (pProps->lpNamespace && wcslen(pProps->lpNamespace))
GetSchemaCache()->GetNamespaceID(pProps->lpNamespace, dParent);
hr = GetSchemaCache()->AddNamespace(lpScope, lpScopeKey, dScopeID, dParent,
((CWmiDbHandle *)pScope)->m_dClassId);
CSQLExecProcedure::InsertScopeMap(pConn, dScopeID, lpScopeKey, dParent);
}
}
else if (lpScope && wcslen(lpScope))
{
delete lpScope;
return WBEM_E_INVALID_OPERATION;
}
}
}
}
if (SUCCEEDED(hr) && !dScopeID)
hr = WBEM_E_INVALID_OBJECT;
}
else if (lpScopePath != NULL)
{
lpScope = new wchar_t [wcslen(lpScopePath) + 1];
if (!lpScope)
return WBEM_E_OUT_OF_MEMORY;
wcscpy(lpScope, lpScopePath);
}
CDeleteMe <wchar_t> r (lpScope);
// Validate that this object has permission to
// write this object, and the handle is not out of date.
// =====================================================
if (SUCCEEDED(hr))
{
hr = pObjToPut->QueryInterface(IID_IWmiDbHandle, (void **)&pHandle);
CReleaseMe rHandle (pHandle);
if (SUCCEEDED(hr))
{
CWmiDbHandle *pTemp = (CWmiDbHandle *)pHandle;
dObjectId = pTemp->m_dObjectId;
// If they took out a protected lock,
// they can't modify it either.
// =================================
if (pTemp->m_dwHandleType == WMIDB_HANDLE_TYPE_PROTECTED)
hr = WBEM_E_ACCESS_DENIED;
else
{
hr = VerifyObjectLock(dObjectId, pTemp->m_dwHandleType, pTemp->m_dwVersion);
if (SUCCEEDED(hr))
{
bLockVerified = true;
}
}
}
else
{
dObjectId = 0;
bLockVerified = 0;
hr = 0;
}
if (SUCCEEDED(hr))
{
// Get the IWbemClassobject interface. If none, fail.
IWbemClassObject *pObj = NULL;
bool bClass = false;
hr = pObjToPut->QueryInterface(IID_IWbemClassObject, (void **)&pObj);
CReleaseMe r2 (pObj);
if (SUCCEEDED(hr))
{
VARIANT vTemp;
VariantInit(&vTemp);
CClearMe c (&vTemp);
CWbemClassObjectProps objprops (this, pConn, pObj, &((CWmiDbController *)m_pController)->SchemaCache, dScopeID);
if (!objprops.lpClassName)
{
hr = WBEM_E_INVALID_OBJECT;
goto Exit;
}
BOOL bNs = FALSE;
if (IsDerivedFrom(pObj, L"__Instances"))
{
hr = WBEM_E_INVALID_OPERATION;
}
else
{
if (objprops.dwGenus == 1 || bStoreAsClass)
bClass = true;
if (pScope)
{
SQL_ID dId = ((CWmiDbHandle *)pScope)->m_dClassId;
if (objprops.lpClassName && wcslen(objprops.lpClassName) >=2)
{
if (objprops.lpClassName[0] == L'_' && objprops.lpClassName[1] == L'_')
{
bStoreDefault = TRUE;
if (objprops.dwGenus == 1)
{
dScopeID = 0;
lpScope = NULL;
}
}
else if (dId == MAPPEDNSCLASSID)
bStoreDefault = FALSE;
}
}
if (objprops.dwGenus == 2 &&
IsDerivedFrom(pObj, L"__Namespace"))
{
delete objprops.lpRelPath;
objprops.lpRelPath = GetPropertyVal(L"Name", pObj);
if (!objprops.lpRelPath)
{
hr = WBEM_E_OUT_OF_MEMORY;
goto Exit;
}
bNs = TRUE;
}
if (lpScope && dScopeID != ROOTNAMESPACEID)
{
if (!wcslen(lpScope))
{
ERRORTRACE((LOG_WBEMCORE, "Invalid scope text in CWmiDbSession::PutObject (%I64d) \n", dScopeID));
hr = WBEM_E_INVALID_PARAMETER;
goto Exit;
}
LPWSTR lpPath = NULL, lpPtr = NULL;
int iLen = wcslen(lpScope);
if (objprops.lpRelPath)
{
if (_wcsnicmp(objprops.lpRelPath, lpScope, iLen) ||
((wcslen(objprops.lpRelPath) > iLen) &&
objprops.lpRelPath[iLen] != L'\\'))
{
lpPtr = new wchar_t [wcslen(objprops.lpRelPath) + wcslen(lpScope) + 10];
if (!lpPtr)
{
hr = WBEM_E_OUT_OF_MEMORY;
goto Exit;
}
lpPath = lpPtr;
if (!bNs)
swprintf(lpPath, L"%s:%s", lpScope, objprops.lpRelPath);
else
swprintf(lpPath, L"%s\\%s", lpScope, objprops.lpRelPath);
if (!_wcsnicmp(lpPath, L"root", wcslen(L"root")))
lpPtr += wcslen(L"root")+1;
sPath = lpPtr;
}
else
sPath += objprops.lpRelPath;
}
CDeleteMe <wchar_t> r4 (lpPath);
}
else
{
if (objprops.lpRelPath)
{
sPath += objprops.lpRelPath;
}
}
}
if (wcslen(objprops.lpClassName) > REPDRVR_NAME_LIMIT)
hr = WBEM_E_CLASS_NAME_TOO_WIDE;
else
objprops.lpKeyString = GetKeyString(sPath);
if (dScopeID)
{
//hr = VerifyObjectSecurity(pConn, dObjectId, dClassId, dScopeID, 0, dwRequired);
if (!(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
hr = VerifyObjectSecurity(pConn, dScopeID, 0, sPath, &objprops, dwRequestedHandleType, WBEM_PARTIAL_WRITE_REP, dObjectId, dClassId);
else
hr = VerifyObjectSecurity(pConn, dScopeID, 0, sPath, &objprops, dwRequestedHandleType, 0, dObjectId, dClassId);
}
if (SUCCEEDED(hr))
{
bool bChanged = false;
bool bNew = false;
if (bClass)
{
SQL_ID dTemp = 0;
if (FAILED(GetSchemaCache()->GetClassID(objprops.lpClassName, dScopeID, dTemp)))
bNew = true;
BOOL bIgnoreDefaults = (bStoreAsClass ? TRUE: FALSE);
hr = PutClass(pConn, dScopeID, lpScope, &objprops, pObj, dwFlags, dObjectId, sPath, bChanged, bIgnoreDefaults);
dClassId = 1;
// After we have put the class, *then*
// we see if we need to set it up in the
// custom database.
if (!bStoreDefault && SUCCEEDED(hr))
{
// Update the mapping for this class.
hr = CustomCreateMapping(pConn, objprops.lpClassName, pObj, pScope);
}
}
else if (dClassId)
{
// If this is a custom repository,
// forward this request to the custom rep code.
if (bStoreDefault)
{
hr = PutInstance(pConn, pScope, dScopeID, lpScope, &objprops, pObj, dwFlags, dObjectId, dClassId, sPath, bChanged);
}
else
{
hr = CustomPutInstance(pConn, pScope, dClassId, dwFlags, &pObj);
pOutObj = pObj;
}
}
else
hr = WBEM_E_INVALID_CLASS;
if (SUCCEEDED(hr))
{
if (SUCCEEDED(hr))
{
// Render return handle as needed.
if (ppResult)
{
if (pHandle)
{
pHandle->AddRef();
*ppResult = pHandle;
// Bump up version number, so other outstanding handles
// know this object changed.
hr = ((CWmiDbController *)m_pController)->LockCache.AddLock(bImmediate, dObjectId, WMIDB_HANDLE_TYPE_VERSIONED, NULL,
dScopeID, dClassId, &((CWmiDbController *)m_pController)->SchemaCache, true, 0, 0);
if (SUCCEEDED(hr))
hr = ((CWmiDbController *)m_pController)->LockCache.DeleteLock(dObjectId, false, WMIDB_HANDLE_TYPE_VERSIONED, true, NULL);
}
else
{
DWORD dwVersion = 0;
CWmiDbHandle *pTemp = new CWmiDbHandle;
if (!pTemp)
{
hr = WBEM_E_OUT_OF_MEMORY;
goto Exit;
}
pTemp->m_pSession = this;
hr = ((CWmiDbController *)m_pController)->LockCache.AddLock(bImmediate, dObjectId, dwRequestedHandleType, pTemp,
dScopeID, dClassId, &((CWmiDbController *)m_pController)->SchemaCache, true, 0, 0, &dwVersion);
if (SUCCEEDED(hr))
{
AddRef_Lock();
((CWmiDbController *)m_pController)->AddHandle();
pTemp->m_dObjectId = dObjectId;
pTemp->m_dClassId = dClassId;
pTemp->m_bDefault = TRUE;
pTemp->m_dScopeId = dScopeID;
pTemp->m_pSession = this;
pTemp->m_pData = pOutObj;
if (pOutObj)
pOutObj->AddRef();
pTemp->AddRef();
pTemp->m_dwVersion = dwVersion;
pTemp->m_dwHandleType = dwRequestedHandleType;
if (dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
pTemp->m_bSecDesc = TRUE;
*ppResult = pTemp;
}
else
{
*ppResult = NULL;
delete pTemp;
}
}
}
else
{
// Bump up version number, so other outstanding handles
// know this object changed.
hr = ((CWmiDbController *)m_pController)->LockCache.AddLock(bImmediate, dObjectId, WMIDB_HANDLE_TYPE_VERSIONED, NULL,
dScopeID, dClassId, &((CWmiDbController *)m_pController)->SchemaCache, true, 0, 0);
((CWmiDbController *)m_pController)->LockCache.DeleteLock(dObjectId, false, WMIDB_HANDLE_TYPE_VERSIONED, true, NULL);
}
// Add an exclusive lock on this object...
// If cannot lock, check locally and see if we have one.
if (IsDistributed())
{
hr = ((CWmiDbController *)m_pController)->LockCache.AddLock(false, dObjectId,
WMIDB_HANDLE_TYPE_EXCLUSIVE, NULL, dScopeID, dClassId,
&((CWmiDbController *)m_pController)->SchemaCache, true, 0, 0);
if (FAILED(hr))
{
if (LockExists(dObjectId))
hr = WBEM_S_NO_ERROR;
}
if (SUCCEEDED(hr))
{
hr = AddTransLock(dObjectId, WMIDB_HANDLE_TYPE_EXCLUSIVE);
}
}
// Update the object in the cache if necessary
// Either they want it cached now, or the
// object already exists in the cache.
// ===========================================
if (SUCCEEDED(hr))
{
if (GetObjectCache()->ObjectExists(dObjectId) ||
(dwRequestedHandleType & 0xF00) == WMIDB_HANDLE_TYPE_WEAK_CACHE ||
(dwRequestedHandleType & 0xF00) == WMIDB_HANDLE_TYPE_STRONG_CACHE)
{
bool bCacheType = ((dwRequestedHandleType & 0xF00) == WMIDB_HANDLE_TYPE_STRONG_CACHE) ? 1 : 0;
LPWSTR lpKey = GetKeyString(sPath);
CDeleteMe <wchar_t> r6(lpKey);
GetObjectCache()->PutObject(dObjectId, dClassId, dScopeID, lpKey, bCacheType, pObj);
}
// Regardless, if we have updated a class,
// we need to remove the instances
// and subclasses from the cache.
// ================================
if (bClass && !bNew)
{
SQL_ID dObjId = 0, dClassId = 0;
HRESULT hTemp = GetObjectCache()->FindFirst(dObjId, dClassId);
while (SUCCEEDED(hTemp))
{
if (dClassId == 1)
dClassId = dObjId;
if (GetSchemaCache()->IsDerivedClass(dObjectId, dClassId))
GetObjectCache()->DeleteObject(dObjId);
hTemp = GetObjectCache()->FindNext(dObjId, dObjId, dClassId);
}
}
}
}
}
}
}
}
}
if (SUCCEEDED(hr) && (dwFlags & WBEM_FLAG_REMOVE_CHILD_SECURITY))
{
// Is this a recursive put (WBEM_FLAG_REMOVE_CHILD_SECURITY)? We need to recursively erase all security on all child objects.
// * Enumerate all dependent objects that have SDs.
// * Call PutObject on each *with* the Use_SD flag, but without the remove_child_security
// flag
SQLIDs ObjIds, ClassIds, ScopeIds;
hr = CSQLExecProcedure::EnumerateSecuredChildren(pConn, &((CWmiDbController *)m_pController)->SchemaCache,
dObjectId, dClassId, dScopeID, ObjIds, ClassIds, ScopeIds);
if (SUCCEEDED(hr))
{
for (int i = 0; i < ObjIds.size(); i++)
{
// Get the old object.
// Strip off the __SECURITY_DESCRIPTOR property
// Put it again.
SQL_ID dObjectId = ObjIds.at(i),
dClassId = ClassIds.at(i),
dScopeId = ScopeIds.at(i);
_bstr_t sScopeKey;
hr = GetSchemaCache()->GetNamespaceName(dScopeId, NULL, &sScopeKey);
DWORD dwTemp;
IWbemClassObject *pObj = NULL;
hr = GetObjectData(pConn, dObjectId, dClassId, dScopeId,
0, dwTemp, &pObj, FALSE, NULL);
CReleaseMe r (pObj);
if (SUCCEEDED(hr))
{
hr = pObj->Put(L"__SECURITY_DESCRIPTOR", 0, NULL, CIM_FLAG_ARRAY|CIM_UINT8);
if (SUCCEEDED(hr))
{
_bstr_t sPath;
hr = PutObject(pConn, NULL, dScopeId, sScopeKey, pObj,
WBEM_FLAG_USE_SECURITY_DESCRIPTOR, 0, sPath,
NULL, FALSE);
}
}
}
}
else if (hr == E_NOTIMPL)
hr = WBEM_S_NO_ERROR;
}
Exit:
return hr;
}
//***************************************************************************
//
// CWmiDbSession::UpdateHierarchy
//
//***************************************************************************
HRESULT CWmiDbSession::UpdateHierarchy(CSQLConnection *pConn, SQL_ID dClassId, DWORD dwFlags, LPCWSTR lpScopePath,
CWbemClassObjectProps *pProps, _IWmiObject *pObj)
{
HRESULT hr = WBEM_S_NO_ERROR;
// Enumerate subclasses (from the cache),
// forcibly update them, and add to ESS cache
int iNumDerived = 0;
SQL_ID *pIDs = NULL;
hr = GetSchemaCache()->GetDerivedClassList(dClassId, &pIDs, iNumDerived, TRUE);
if (SUCCEEDED(hr))
{
CDeleteMe <SQL_ID> d3 (pIDs);
// If there are instances, fail now.
BOOL bInstances = FALSE;
hr = CSQLExecProcedure::HasInstances(pConn, dClassId, pIDs, iNumDerived, bInstances);
if (bInstances)
return WBEM_E_CLASS_HAS_INSTANCES;
for (int i = 0; i < iNumDerived; i++)
{
IWbemClassObject *pSubClass = NULL;
hr = GetClassObject(pConn, pIDs[i], &pSubClass);
CReleaseMe r2 (pSubClass);
if (SUCCEEDED(hr))
{
_IWmiObject *pNew = NULL;
hr = ((_IWmiObject *)pObj)->Update(((_IWmiObject *)pSubClass), WBEM_FLAG_UPDATE_FORCE_MODE, &pNew);
if (SUCCEEDED(hr))
{
if(!(dwFlags & WMIDB_DISABLE_EVENTS))
{
((CWmiDbController *)m_pController)->ESSMgr.AddInsertRecord(pConn, m_sGUID,
(LPWSTR)lpScopePath, pProps->lpClassName, pProps->dwGenus, pSubClass, pNew);
}
hr = UpdateHierarchy(pConn, pIDs[i], dwFlags, lpScopePath, pProps, pNew);
if (FAILED(hr))
break;
// Update the subclass object in the repository.
// Can only be done after all children have been updated.
hr = CSQLExecProcedure::UpdateClassBlob(pConn, pIDs[i], pNew);
if (FAILED(hr))
break;
}
else
break;
}
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::PutClass
//
//***************************************************************************
HRESULT CWmiDbSession::PutClass(
CSQLConnection *pConn,
/* [in] */ SQL_ID dScopeID,
/* [in] */ LPCWSTR lpScopePath,
CWbemClassObjectProps *pProps,
/* [in] */ IWbemClassObject *pObj,
DWORD dwFlags,
/* [in/out] */ SQL_ID &dObjectId,
/* [out] */ _bstr_t &sObjectPath,
bool &bChg,
BOOL bIgnoreDefaults)
{
HRESULT hr = WBEM_S_NO_ERROR;
SQL_ID dTempScopeID = 0;
bool bNewObj = (dObjectId == 0) ? 1 : 0;
SQL_ID dSuperClassId = 1;
SQL_ID dDynasty = 0;
wchar_t wSuperClass[450];
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
return WBEM_E_INVALID_PARAMETER;
// See if anything changed.
if (dObjectId)
{
IWbemClassObject *pOldObj = NULL;
DWORD dwTemp;
hr = GetObjectData(pConn, dObjectId, 1, dScopeID,
0, dwTemp, &pOldObj, FALSE, NULL);
CReleaseMe r (pOldObj);
if (SUCCEEDED(hr) && !(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
{
DWORD dwRequired = 0;
if (pProps->lpClassName[0] == L'_')
dwRequired = WBEM_FULL_WRITE_REP;
else
dwRequired = WBEM_PARTIAL_WRITE_REP;
hr = VerifyObjectSecurity(pConn, dObjectId, 1, dScopeID, 0, dwRequired);
if (FAILED(hr))
{
return hr;
}
}
if (SUCCEEDED(hr))
{
// Backward compatibility: always log an event,
// even though nothing has changed.
if(!(dwFlags & WMIDB_DISABLE_EVENTS))
{
((CWmiDbController *)m_pController)->ESSMgr.AddInsertRecord(pConn, m_sGUID,
(LPWSTR)lpScopePath, pProps->lpClassName, pProps->dwGenus, pOldObj, pObj);
}
hr = pOldObj->CompareTo(0, pObj);
if (WBEM_S_NO_ERROR == hr)
return WBEM_S_NO_ERROR; // Nothing changed. Don't bother updating.
else
{
// Did this impact subclasses? If so,
// enumerate and add ESS records.
BOOL bImmediate = FALSE;
hr = ((_IWmiObject *)pOldObj)->ReconcileWith(WMIOBJECT_RECONCILE_FLAG_TESTRECONCILE, (_IWmiObject *)pObj);
if (hr != WBEM_S_NO_ERROR)
{
hr = UpdateHierarchy(pConn, dObjectId, dwFlags, lpScopePath, pProps, (_IWmiObject *)pObj);
}
}
}
else
hr = WBEM_S_NO_ERROR;
}
else
{
if(!(dwFlags & WMIDB_DISABLE_EVENTS))
{
((CWmiDbController *)m_pController)->ESSMgr.AddInsertRecord(pConn, m_sGUID,
(LPWSTR)lpScopePath, pProps->lpClassName, pProps->dwGenus, NULL, pObj);
}
}
bChg = true;
// Generate the object path.
if (!wcslen(pProps->lpRelPath) || !wcslen(pProps->lpClassName))
return WBEM_E_INVALID_OBJECT;
if (pProps->lpSuperClass && wcslen(pProps->lpSuperClass))
{
if (FAILED(GetSchemaCache()->GetClassID (pProps->lpSuperClass, dScopeID, dSuperClassId)))
return WBEM_E_INVALID_CLASS;
if (lpScopePath != NULL && wcslen(lpScopePath))
swprintf(wSuperClass, L"%s:%s", lpScopePath, pProps->lpSuperClass);
else
wcscpy(wSuperClass, pProps->lpSuperClass);
}
else
wSuperClass[0] = L'\0';
(GetSchemaCache()->GetClassID (pProps->lpDynasty, dScopeID, dDynasty));
if (SUCCEEDED(hr))
{
IRowset *pIRowset = NULL;
DWORD dwRows = 0;
DWORD dwClassFlags = 0;
IWbemQualifierSet *pQS = NULL;
hr = pObj->GetQualifierSet(&pQS);
if (SUCCEEDED(hr))
{
CReleaseMe r (pQS);
dwClassFlags = GetQualifierFlag(L"Abstract", pQS) ? REPDRVR_FLAG_ABSTRACT : 0;
dwClassFlags |= GetQualifierFlag(L"Singleton", pQS) ? REPDRVR_FLAG_SINGLETON : 0;
dwClassFlags |= GetQualifierFlag(L"Unkeyed", pQS) ? REPDRVR_FLAG_UNKEYED : 0;
dwClassFlags |= GetQualifierFlag(L"HasClassRefs", pQS) ? REPDRVR_FLAG_CLASSREFS : 0;
BOOL bExists = FALSE;
// If exists, only update the class if super class or flags changed
// (They can't change the name or scope without changing the
// path, right?)
_bstr_t sName;
SQL_ID dSuperClass = 1;
if (SUCCEEDED(GetSchemaCache()->GetClassInfo
(dObjectId, sName, dSuperClass, dTempScopeID, dwFlags)))
bExists = TRUE;
LPWSTR lpObjKey, lpParentKey;
lpObjKey = pProps->lpKeyString;
lpParentKey = GetKeyString(wSuperClass);
CDeleteMe <wchar_t> r2(lpParentKey);
if (!lpObjKey || !wcslen(lpObjKey))
{
ERRORTRACE((LOG_WBEMCORE, "Invalid object path in CWmiDbSession::PutClass (%S) \n", sObjectPath));
hr = WBEM_E_INVALID_PARAMETER;
}
else
{
// Insert the data.
// Ensure that we don't end up reporting to ourself.
// Enumerate the __Derivation property of the IWbemClassObject,
// and see if the class is in its own ancestry.
if (IsDerivedFrom(pObj, pProps->lpClassName, TRUE))
hr = WBEM_E_CIRCULAR_REFERENCE;
if (SUCCEEDED(hr))
{
_IWmiObject *pInt = NULL;
hr = pObj->QueryInterface(IID__IWmiObject, (void **)&pInt);
CReleaseMe r (pInt);
if (SUCCEEDED(hr))
{
BYTE *pBuff;
BYTE buff[128];
DWORD dwLen = 0;
pInt->Unmerge(0, 128, &dwLen, &buff);
if (dwLen > 0)
{
pBuff = new BYTE [dwLen];
if (pBuff)
{
DWORD dwLen1;
hr = pInt->Unmerge(0, dwLen, &dwLen1, pBuff);
if (SUCCEEDED(hr))
{
hr = CSQLExecProcedure::InsertClass(pConn, pProps->lpClassName, lpObjKey, sObjectPath, dScopeID,
dSuperClassId, dDynasty, 0, pBuff, dwLen1, dwClassFlags, dwFlags, dObjectId);
if (SUCCEEDED(hr))
{
if (!dDynasty)
dDynasty = dObjectId;
hr = GetSchemaCache()->AddClassInfo(dObjectId, pProps->lpClassName,
dSuperClassId, dDynasty, dScopeID, lpObjKey, dwClassFlags);
}
}
delete pBuff;
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
}
}
if (SUCCEEDED(hr))
{
// Get a map of this classes' property IDs
// Qualifiers won't be present, but that's OK now.
// ==============================================
Properties props;
if (!bNewObj)
hr = GetSchemaCache()->GetPropertyList(dObjectId, props);
// Iterate through all properties, qualifiers, methods.
// Only update ones that changed and update cache.
// Check off/Add ID as we encounter them.
// ====================================================
BSTR strName;
VARIANT vTemp;
CIMTYPE cimtype;
long lPropFlavor = 0;
IWbemQualifierSet *pQS = NULL;
// Properties
//((_IWmiObject *)pObj)->BeginEnumerationEx(WBEM_FLAG_CLASS_LOCAL_AND_OVERRIDES, WMIOBJECT_BEGINENUMEX_FLAG_GETEXTPROPS);
pObj->BeginEnumeration(WBEM_FLAG_CLASS_LOCAL_AND_OVERRIDES);
while (pObj->Next(0, &strName, &vTemp, &cimtype, &lPropFlavor) == S_OK)
{
CFreeMe f1 (strName);
pObj->GetPropertyQualifierSet(strName, &pQS);
if (pQS)
{
CReleaseMe r (pQS);
lPropFlavor = (REPDRVR_FLAG_CLASSREFS & dwClassFlags);
lPropFlavor |= (GetQualifierFlag(L"key", pQS)) ? REPDRVR_FLAG_KEY : 0;
lPropFlavor |= (GetQualifierFlag(L"indexed", pQS)) ? REPDRVR_FLAG_INDEXED : 0;
lPropFlavor |= (GetQualifierFlag(L"keyhole", pQS)) ? REPDRVR_FLAG_KEYHOLE : 0;
lPropFlavor |= (GetQualifierFlag(L"not_null", pQS)) ? REPDRVR_FLAG_NOT_NULL : 0;
}
if (bIgnoreDefaults)
VariantClear(&vTemp);
hr = InsertPropertyDef(pConn, pObj, dScopeID, dObjectId, strName, vTemp, cimtype, lPropFlavor, 0,props);
VariantClear(&vTemp);
if (FAILED(hr))
break;
}
// No need to insert qualifiers or methods.
// We are only creating schema so it can
// be queried when we get instances.
// Delete any properties, methods that
// were not found, remove from cache.
// Qualifiers can simply be deleted,
// since they aren't cached.
// ===================================
if (SUCCEEDED(hr) && !bNewObj)
{
_bstr_t sSQL;
bool bInit = false;
Properties::iterator item = props.begin();
while (item != props.end())
{
DWORD dwID = (*item).first;
if (!GetSchemaCache()->IsQualifier(dwID))
{
if (!(*item).second)
{
SQL_ID dClass = 0;
hr = GetSchemaCache()->GetPropertyInfo
(dwID, NULL, &dClass);
if (dClass == dObjectId)
{
CSQLExecProcedure::DeleteProperty(pConn, dwID);
GetSchemaCache()->DeleteProperty(dwID, dClass);
}
hr = WBEM_S_NO_ERROR;
}
}
item++;
}
}
else if (FAILED(hr) && bNewObj)
{
hr = GetSchemaCache()->DeleteClass(dObjectId);
}
}
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::InsertPropertyDef
//
//***************************************************************************
HRESULT CWmiDbSession::InsertPropertyDef(CSQLConnection *pConn,
IWbemClassObject *pObj, SQL_ID dScopeId,
SQL_ID dObjectId, LPWSTR lpPropName, VARIANT vDefault,
CIMTYPE cimtype, long dwFlags, DWORD dRefId,
Properties &props)
{
HRESULT hr = WBEM_S_NO_ERROR;
bool bArray = false;
if (cimtype & CIM_FLAG_ARRAY)
bArray = true;
dwFlags |= (bArray) ? REPDRVR_FLAG_ARRAY : 0;
cimtype &= ~CIM_FLAG_ARRAY;
// If this is an embedded object or reference,
// set the class ID of the embedded object, if any.
SQL_ID dRefClassId = 0;
if (cimtype == CIM_REFERENCE || cimtype == CIM_OBJECT)
{
IWbemQualifierSet *pQS = NULL;
hr = pObj->GetPropertyQualifierSet(lpPropName, &pQS);
if (SUCCEEDED(hr))
{
VARIANT vValue;
VariantInit(&vValue);
CReleaseMe r (pQS);
CClearMe c (&vValue);
hr = pQS->Get(L"CIMTYPE", 0, &vValue, NULL);
// Since previously, wbem did not do any type checking of references
// or embedded objects, we generate the IDs for the classes if
// they aren't already present. This will still fail for instances.
if (!_wcsnicmp(vValue.bstrVal, L"ref", 3) &&
wcslen(vValue.bstrVal) > 3)
{
LPWSTR lpPtr = (LPWSTR)vValue.bstrVal;
lpPtr += 4;
hr = GetSchemaCache()->GetClassID(lpPtr, dScopeId, dRefClassId);
if (hr == WBEM_E_NOT_FOUND)
{
_bstr_t sScopeKey;
hr = GetSchemaCache()->GetNamespaceName(dScopeId, NULL, &sScopeKey);
if (SUCCEEDED(hr))
{
_bstr_t sNewName = lpPtr;
sNewName += L"?";
sNewName += sScopeKey;
dRefClassId = CRC64::GenerateHashValue(sNewName);
hr = WBEM_S_NO_ERROR;
}
}
}
else if (!_wcsnicmp(vValue.bstrVal, L"object", 6) &&
wcslen(vValue.bstrVal) > 6)
{
LPWSTR lpPtr = (LPWSTR)vValue.bstrVal;
lpPtr += 7;
hr = GetSchemaCache()->GetClassID(lpPtr, dScopeId, dRefClassId);
if (hr == WBEM_E_NOT_FOUND)
{
_bstr_t sScopeKey;
hr = GetSchemaCache()->GetNamespaceName(dScopeId, NULL, &sScopeKey);
if (SUCCEEDED(hr))
{
_bstr_t sNewName = lpPtr;
sNewName += L"?";
sNewName += sScopeKey;
dRefClassId = CRC64::GenerateHashValue(sNewName);
hr = WBEM_S_NO_ERROR;
}
}
}
}
}
// We can't verify that a property changed, since we currently aren't
// caching the defaults, so will insert regardless.
DWORD dwPropertyID = 0;
if (wcslen(lpPropName) > REPDRVR_NAME_LIMIT)
{
hr = WBEM_E_PROPERTY_NAME_TOO_WIDE;
}
else
{
BOOL bChg = TRUE;
SQL_ID dOrigClass = 0;
if ((GetSchemaCache()->GetPropertyID
(lpPropName, dObjectId, dwFlags, cimtype, dwPropertyID, &dOrigClass)) == WBEM_S_NO_ERROR)
{
}
else if (!(dwFlags & (REPDRVR_FLAG_NONPROP &~ REPDRVR_FLAG_METHOD)))
{
// Does this property exist on the derived class already?
if (SUCCEEDED(hr))
{
hr = GetSchemaCache()->FindProperty(dObjectId, lpPropName, dwFlags, cimtype);
}
}
if (SUCCEEDED(hr))
{
BOOL bIsKey = FALSE;
if (bChg)
{
LPWSTR lpVal = GetStr(vDefault);
CDeleteMe <wchar_t> r(lpVal);
hr = CSQLExecProcedure::InsertClassData(pConn, pObj, &((CWmiDbController *)m_pController)->SchemaCache,
dScopeId, dObjectId, lpPropName, cimtype, GetStorageType(cimtype, bArray), lpVal,
dRefClassId, dRefId, dwFlags, 0, 0, dwPropertyID, dOrigClass, &bIsKey);
}
if (SUCCEEDED(hr))
{
hr = GetSchemaCache()->AddPropertyInfo (dwPropertyID,
lpPropName, dObjectId, GetStorageType(cimtype, bArray), cimtype, dwFlags,
0, L"", dRefId, 0); // don't cache the default!
if (bIsKey)
GetSchemaCache()->SetIsKey(dObjectId, dwPropertyID);
props[dwPropertyID] = 1;
}
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::InsertQualifiers
//
//***************************************************************************
HRESULT CWmiDbSession::InsertQualifiers (CSQLConnection *pConn, IWmiDbHandle *pScope, SQL_ID dObjectId,
DWORD PropID, DWORD Flags, IWbemQualifierSet *pQS,
Properties &props)
{
HRESULT hr = WBEM_S_NO_ERROR;
BSTR strName;
VARIANT vTemp;
VariantInit(&vTemp);
long lPropFlavor = 0;
pQS->BeginEnumeration(0);
while (pQS->Next(0, &strName, &vTemp, &lPropFlavor) == S_OK)
{
CFreeMe f (strName);
lPropFlavor = lPropFlavor&~WBEM_FLAVOR_ORIGIN_PROPAGATED&~WBEM_FLAVOR_ORIGIN_SYSTEM&~WBEM_FLAVOR_AMENDED;
hr = InsertQualifier(pConn, pScope, dObjectId, strName, vTemp,
lPropFlavor, Flags & REPDRVR_FLAG_QUALIFIER, PropID, props);
VariantClear(&vTemp);
if (FAILED(hr))
break;
}
pQS->EndEnumeration();
return hr;
}
//***************************************************************************
//
// CWmiDbSession::InsertQualifier
//
//***************************************************************************
HRESULT CWmiDbSession::InsertQualifier( CSQLConnection *pConn,IWmiDbHandle *pScope,
SQL_ID dObjectId,
LPWSTR lpQualifierName, VARIANT vValue,
long lQfrFlags, DWORD dwFlags, DWORD PropID,
Properties &props)
{
HRESULT hr = WBEM_S_NO_ERROR;
dwFlags |= REPDRVR_FLAG_QUALIFIER;
// This will only insert the qualifier definition
// and the initial data.
// Insert the qualifier, unless its one of the
// system quartet: key, indexed, keyhole, not_null
// ==================================================
if (!_wcsicmp(lpQualifierName, L"abstract"))
return WBEM_S_NO_ERROR;
if (!_wcsicmp(lpQualifierName, L"cimtype"))
{
if ((wcslen(vValue.bstrVal) > 3 && !_wcsnicmp(vValue.bstrVal, L"ref", 3)) ||
(wcslen(vValue.bstrVal) > 6 && !_wcsnicmp(vValue.bstrVal, L"object", 6)))
{
}
else
return WBEM_S_NO_ERROR; // CIMTypes are generated automatically.
}
bool bArray = false;
CIMTYPE ct;
switch((vValue.vt &~ CIM_FLAG_ARRAY))
{
case VT_R4:
case VT_R8:
ct = CIM_REAL64;
break;
case VT_BSTR:
ct = CIM_STRING;
break;
case VT_BOOL:
ct = CIM_BOOLEAN;
break;
default:
ct = CIM_UINT32;
break;
}
if (vValue.vt & VT_ARRAY)
bArray = true;
dwFlags |= (bArray) ? REPDRVR_FLAG_ARRAY : 0;
DWORD dwPropertyID = 0;
if (wcslen(lpQualifierName) > REPDRVR_NAME_LIMIT)
{
hr = WBEM_E_QUALIFIER_NAME_TOO_WIDE;
}
else
{
if (SUCCEEDED(hr))
{
LPWSTR lpVal = GetStr(vValue);
CDeleteMe <wchar_t> r(lpVal);
try
{
GetSchemaCache()->GetPropertyID (lpQualifierName, 1, dwFlags, ct, dwPropertyID);
hr = CSQLExecProcedure::InsertClassData(pConn, NULL, &((CWmiDbController *)m_pController)->SchemaCache, 0, 1, lpQualifierName,
ct, GetStorageType(ct, bArray), lpVal,0, PropID, dwFlags, lQfrFlags, 0, dwPropertyID);
if (SUCCEEDED(hr))
{
hr = GetSchemaCache()->AddPropertyInfo (dwPropertyID,
lpQualifierName, 1, GetStorageType(ct, bArray), ct, dwFlags,
0, L"", PropID, lQfrFlags); // don't cache the default!
// Add any array defaults.
// =======================
if (vValue.vt & VT_ARRAY)
hr = InsertArray(pConn, pScope, dObjectId, 1, dwPropertyID, vValue, lQfrFlags, PropID);
}
}
catch (...)
{
hr = WBEM_E_CRITICAL_ERROR;
}
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::PutInstance
//
//***************************************************************************
HRESULT CWmiDbSession::PutInstance(
CSQLConnection *pConn,
IWmiDbHandle *pScope,
/* [in] */ SQL_ID dScopeID,
/* [in] */ LPCWSTR lpScopePath,
CWbemClassObjectProps *pProps,
/* [in] */ IWbemClassObject *pObj,
DWORD dwFlags,
/* [in/out] */ SQL_ID &dObjectId,
/* [out] */ SQL_ID &dClassId,
/* [out] */ _bstr_t &sObjectPath,
bool &bChg)
{
HRESULT hr = WBEM_S_NO_ERROR;
bool bUpdate = (dObjectId == 0) ? false : true;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
SQL_ID dTestId = dObjectId;
if (!dTestId)
{
if (pProps->lpKeyString)
dTestId = CRC64::GenerateHashValue(pProps->lpKeyString);
}
BOOL bGetSD = FALSE;
if (dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
bGetSD = TRUE;
IWbemClassObject *pOldObj = NULL;
DWORD dwTemp;
hr = GetObjectData(pConn, dTestId, dClassId, dScopeID,
0, dwTemp, &pOldObj, FALSE, NULL, bGetSD);
CReleaseMe r (pOldObj);
if (SUCCEEDED(hr))
{
if (SUCCEEDED(hr) && !(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
{
DWORD dwRequired = 0;
if (dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
dwRequired = WRITE_DAC;
else
{
if (pProps->lpClassName[0] == L'_')
dwRequired = WBEM_FULL_WRITE_REP;
else
dwRequired = WBEM_PARTIAL_WRITE_REP;
}
hr = VerifyObjectSecurity(pConn, dTestId, dClassId, dScopeID, 0, dwRequired);
if (FAILED(hr))
{
return hr;
}
}
if(!(dwFlags & WMIDB_DISABLE_EVENTS))
{
LPWSTR lpClass = pProps->lpClassName;
BOOL bRelease = FALSE;
if (IsDerivedFrom(pObj, L"__Namespace"))
{
lpClass = GetPropertyVal(L"Name", pObj);
bRelease = TRUE;
}
((CWmiDbController *)m_pController)->ESSMgr.AddInsertRecord(pConn, m_sGUID,
(LPWSTR)lpScopePath, lpClass, pProps->dwGenus, pOldObj, pObj);
if (bRelease)
delete lpClass;
}
hr = pOldObj->CompareTo(0, pObj);
if (WBEM_S_NO_ERROR == hr)
return WBEM_S_NO_ERROR; // Nothing changed. Don't bother updating.
}
else
{
hr = WBEM_S_NO_ERROR;
if(!(dwFlags & WMIDB_DISABLE_EVENTS))
{
((CWmiDbController *)m_pController)->ESSMgr.AddInsertRecord(pConn, m_sGUID,
(LPWSTR)lpScopePath, pProps->lpClassName, pProps->dwGenus, NULL, pObj);
}
}
bChg = true;
if (SUCCEEDED(hr))
{
IRowset *pIRowset = NULL;
DWORD dwNumRows = 0;
// Generate unkeyed or keyhole path if none (and if class is one of the two)
if (!bUpdate )
{
bool bUnkeyed = false;
_bstr_t sName;
SQL_ID dTemp1, dTemp2;
DWORD dwFlags = 0;
hr = GetSchemaCache()->GetClassInfo (dClassId, sName, dTemp1, dTemp2, dwFlags);
if (SUCCEEDED(hr) && (dwFlags & REPDRVR_FLAG_UNKEYED))
{
bUnkeyed = true;
hr = CSQLExecProcedure::GetNextUnkeyedPath(pConn, dClassId, sObjectPath);
}
// Cannot add instances to an abstract class.
if (dwFlags & REPDRVR_FLAG_ABSTRACT)
return WBEM_E_INVALID_OPERATION;
DWORD dwKeyholePropID = 0;
_bstr_t sKeyholeProp;
if (SUCCEEDED(hr) && SUCCEEDED(GetSchemaCache()->GetKeyholeProperty(dClassId, dwKeyholePropID, sKeyholeProp)))
{
hr = SetKeyhole(pConn, pObj, dwKeyholePropID, sKeyholeProp, lpScopePath, sObjectPath);
delete pProps->lpRelPath;
pProps->lpRelPath = GetPropertyVal(L"__RelPath", pObj);
}
if (!bUnkeyed && !pProps->lpRelPath)
hr = WBEM_E_INVALID_OBJECT; // path cannot be blank at this point.
}
if (SUCCEEDED(hr)) // we have a valid path.
hr = InsertPropertyValues(pConn, pScope, sObjectPath, dObjectId, dClassId, dScopeID, dwFlags, pProps, pObj);
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::SetKeyhole
//
//***************************************************************************
HRESULT CWmiDbSession::SetKeyhole (CSQLConnection *pConn, IWbemClassObject *pObj, DWORD dwKeyholePropID,
LPWSTR sKeyholeProp, LPCWSTR lpScopePath, _bstr_t &sPath)
{
HRESULT hr = WBEM_S_NO_ERROR;
// See if it is populated.
CIMTYPE ct = 0;
long lFlags = 0;
VARIANT vTemp;
VariantInit(&vTemp);
_bstr_t sNewValue;
SQL_ID dNextId = 0;
hr = pObj->Get(sKeyholeProp, 0, &vTemp, &ct, &lFlags);
LPWSTR lpVal = GetStr(vTemp);
CDeleteMe <wchar_t> r(lpVal);
VariantClear(&vTemp);
if (!lpVal || !wcslen(lpVal) || !_wcsicmp(lpVal,L"0"))
{
// Execute stored procedure.
// =========================
hr = CSQLExecProcedure::GetNextKeyhole(pConn, dwKeyholePropID, dNextId);
if (SUCCEEDED(hr))
{
// If a string property, just
// convert the number to text.
// ==========================
if (ct == CIM_STRING) // We really want a GUID here!!!!
{
wchar_t szTmp[20];
swprintf(szTmp, L"%ld", dNextId);
V_BSTR(&vTemp) = szTmp;
vTemp.vt = VT_BSTR;
}
else
{
V_I4(&vTemp) = dNextId;
vTemp.vt = VT_I4;
}
// Try to update the key value,
// and get the object path again.
// ==============================
hr = pObj->Put(sKeyholeProp, 0, &vTemp, ct);
if (SUCCEEDED(hr))
{
hr = pObj->Get(L"__RelPath", 0, &vTemp, NULL, NULL);
sPath = vTemp.bstrVal;
if (lpScopePath != NULL)
{
_bstr_t sTemp = sPath;
sPath = _bstr_t(lpScopePath) + L":" + sTemp;
}
}
}
}
return hr;
}
InsertQfrValues * ReAllocQfrValues (InsertQfrValues *pVals, int iNumVals, int iAdd)
{
InsertQfrValues * pRet = new InsertQfrValues[iNumVals + iAdd];
if (pRet)
{
int iSize = sizeof(InsertQfrValues) * iNumVals;
/*
for (int i = 0; i < iNumVals; i++)
{
if (pVals[i].pValue)
iSize += wcslen(pVals[i].pValue)+ 1;
if (pVals[i].pRefKey)
iSize += wcslen(pVals[i].pRefKey) + 1;
}
*/
memcpy(pRet, pVals, iSize);
delete pVals;
}
else
delete pVals;
return pRet;
}
// Strip off local prefixes. Any unresolved path
// not in this format might not be an object stored
// in this database.
LPWSTR StripUnresolvedName (LPWSTR lpPath)
{
LPWSTR lpRet = new wchar_t [wcslen(lpPath) + 1];
if (lpRet)
{
if (wcslen(lpPath) > 2)
{
if (wcsstr(lpPath, L"\\\\.\\root"))
lpPath += 9;
}
wcscpy(lpRet, lpPath);
}
return lpRet;
}
//***************************************************************************
//
// TestSD
//
//***************************************************************************
HRESULT TestSD(VARIANT * pvTemp)
{
if(pvTemp->vt != (VT_ARRAY | VT_UI1))
{
return WBEM_E_INVALID_PARAMETER;
}
SAFEARRAY * psa = pvTemp->parray;
PSECURITY_DESCRIPTOR pSD;
HRESULT hr = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pSD);
if(FAILED(hr))
return WBEM_E_INVALID_PARAMETER;
BOOL bRet = IsValidSecurityDescriptor(pSD);
if(bRet == FALSE)
{
SafeArrayUnaccessData(psa);
return WBEM_E_INVALID_PARAMETER;
}
PSID pSid = 0;
BOOL bDefaulted;
BOOL bRes = GetSecurityDescriptorOwner(pSD, &pSid, &bDefaulted);
if (!bRes || !IsValidSid(pSid))
{
SafeArrayUnaccessData(psa);
return WBEM_E_INVALID_PARAMETER;
}
pSid = 0;
bRes = GetSecurityDescriptorGroup(pSD, &pSid, &bDefaulted);
if (!bRes || !IsValidSid(pSid))
{
SafeArrayUnaccessData(psa);
return WBEM_E_INVALID_PARAMETER;
}
SafeArrayUnaccessData(psa);
return (bRet) ? S_OK : WBEM_E_INVALID_PARAMETER;
}
//***************************************************************************
//
// CWmiDbSession::InsertPropertyValues
//
//***************************************************************************
HRESULT CWmiDbSession::InsertPropertyValues (CSQLConnection *pConn,
IWmiDbHandle *pScope,
LPWSTR lpPath,
SQL_ID &dObjectId,
SQL_ID dClassId,
SQL_ID dScopeId,
DWORD dwFlags,
CWbemClassObjectProps *pProps,
IWbemClassObject *pObj)
{
HRESULT hr = WBEM_S_NO_ERROR;
BSTR strName;
CIMTYPE cimtype;
long lPropFlavor = 0;
SQL_ID dRefClassId = 0, dRefID = 0;
CWStringArray arrObjProps;
int iPos = 0, iQfrPos = 0;
bool bDone = false;
VARIANT vTemp;
BOOL bRemoveSD = FALSE;
CClearMe c (&vTemp);
Properties props;
InsertPropValues *pPropValues = NULL;
InsertQfrValues *pQVals = NULL;
LPWSTR lpCount = GetPropertyVal(L"__Property_Count", pObj);
CDeleteMe <wchar_t> r(lpCount);
int iNumProps = 10;
if (lpCount)
iNumProps += _wtoi(lpCount);
if (iNumProps)
{
pPropValues = new InsertPropValues[iNumProps];
if (!pPropValues)
return WBEM_E_OUT_OF_MEMORY;
}
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
{
delete pPropValues;
return WBEM_E_SHUTTING_DOWN;
}
// Insert properties.
// ==================
((_IWmiObject *)pObj)->BeginEnumerationEx(WBEM_FLAG_NONSYSTEM_ONLY, WMIOBJECT_BEGINENUMEX_FLAG_GETEXTPROPS);
// ((_IWmiObject *)pObj)->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
while (pObj->Next(0, &strName, &vTemp, &cimtype, &lPropFlavor) == S_OK)
{
CFreeMe f (strName);
// Ignore security unless they are setting it explicitly.
if (!_wcsicmp(strName, L"__SECURITY_DESCRIPTOR"))
{
if (!(dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR))
{
VariantClear(&vTemp);
continue;
}
else
{
if (vTemp.vt == VT_NULL)
bRemoveSD = TRUE;
}
}
// Skip embedded objects and arrays
// until we have an ObjectId...
// ===================================
IWbemQualifierSet *pQS = NULL;
hr = pObj->GetPropertyQualifierSet(strName, &pQS);
if (SUCCEEDED(hr))
{
CReleaseMe r (pQS);
if ((GetQualifierFlag(L"not_null", pQS) != 0) && (vTemp.vt == VT_NULL))
{
hr = WBEM_E_ILLEGAL_NULL;
VariantClear(&vTemp);
break;
}
}
if ((cimtype == CIM_OBJECT && vTemp.vt == VT_UNKNOWN) || ((cimtype & CIM_FLAG_ARRAY) && (vTemp.vt & CIM_FLAG_ARRAY)))
arrObjProps.Add(strName);
else
{
DWORD dPropID, dwFlags2, dwType;
SQL_ID dNewClassID = dClassId;
hr = GetSchemaCache()->GetPropertyID(strName, dClassId, 0, cimtype,
dPropID, &dNewClassID, &dwFlags2, &dwType);
if (SUCCEEDED(hr))
{
LPWSTR lpVal = GetStr(vTemp);
CDeleteMe <wchar_t> r(lpVal);
pPropValues[iPos].iPropID = dPropID;
pPropValues[iPos].pValue = NULL;
pPropValues[iPos].pRefKey = NULL;
pPropValues[iPos].bLong = false;
pPropValues[iPos].iFlavor = 0;
pPropValues[iPos].iQfrID = 0;
pPropValues[iPos].dClassId = dNewClassID;
pPropValues[iPos].iStorageType = dwType;
pPropValues[iPos].bIndexed = (dwFlags2 & (REPDRVR_FLAG_INDEXED + REPDRVR_FLAG_KEY)) ? TRUE : FALSE;
if (cimtype == CIM_REFERENCE)
{
// If no scope, don't bother trying to
// store this reference,
// since the end result will be invalid.
// ======================================
if (!pScope)
{
VariantClear(&vTemp);
continue;
}
pPropValues[iPos].bIndexed = TRUE; // References are always keys
LPWSTR lpTemp = NULL;
IWbemPath *pPath = NULL;
hr = CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER,
IID_IWbemPath, (LPVOID *) &pPath);
CReleaseMe r8 (pPath);
if (SUCCEEDED(hr))
{
if (lpVal)
{
pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, lpVal);
hr = NormalizeObjectPathGet(pScope, pPath, &lpTemp, NULL, NULL, NULL, pConn);
CDeleteMe <wchar_t> r1(lpTemp);
if (SUCCEEDED(hr))
{
LPWSTR lpTemp2 = NULL;
lpTemp2 = GetKeyString(lpTemp);
CDeleteMe <wchar_t> d (lpTemp2);
pPropValues[iPos].pRefKey = new wchar_t [21];
if (pPropValues[iPos].pRefKey)
swprintf(pPropValues[iPos].pRefKey, L"%I64d", CRC64::GenerateHashValue(lpTemp2));
else
hr = WBEM_E_OUT_OF_MEMORY;
}
else
{
hr = WBEM_S_NO_ERROR;
// Strip off the root namespace prefix and generate the
// pseudo-name. We have no way of knowing if they entered this
// path correctly.
LPWSTR lpTemp3 = StripUnresolvedName (lpVal);
CDeleteMe <wchar_t> d2 (lpTemp3);
LPWSTR lpTemp2 = NULL;
lpTemp2 = GetKeyString(lpTemp3);
CDeleteMe <wchar_t> d (lpTemp2);
pPropValues[iPos].pRefKey = new wchar_t [21];
if (pPropValues[iPos].pRefKey)
swprintf(pPropValues[iPos].pRefKey, L"%I64d", CRC64::GenerateHashValue(lpTemp2));
else
hr = WBEM_E_OUT_OF_MEMORY;
}
pPropValues[iPos].pValue = new wchar_t[wcslen(lpVal)+1];
if (pPropValues[iPos].pValue)
wcscpy(pPropValues[iPos].pValue,lpVal);
else
hr = WBEM_E_OUT_OF_MEMORY;
}
else
pPropValues[iPos].pValue = NULL;
}
else
{
VariantClear(&vTemp);
break;
}
}
else
{
if (lpVal)
{
pPropValues[iPos].pValue = new wchar_t[wcslen(lpVal)+1];
if (pPropValues[iPos].pValue)
wcscpy(pPropValues[iPos].pValue,lpVal);
else
hr = WBEM_E_OUT_OF_MEMORY;
}
else
pPropValues[iPos].pValue = NULL;
pPropValues[iPos].pRefKey = NULL;
}
pPropValues[iPos].iPos = 0;
iPos++;
}
else
{
VariantClear(&vTemp);
break;
}
}
VariantClear(&vTemp);
}
LPWSTR lpObjectKey = pProps->lpKeyString;
if (!wcslen(lpObjectKey))
{
ERRORTRACE((LOG_WBEMCORE, "Invalid object path in CWmiDbSession::InsertPropertyValues (%S) \n", lpPath));
delete pProps->lpKeyString;
lpObjectKey = new wchar_t [wcslen(lpPath)+1];
if (lpObjectKey)
wcscpy(lpObjectKey, lpPath);
else
hr = WBEM_E_OUT_OF_MEMORY;
pProps->lpKeyString = lpObjectKey;
}
if (SUCCEEDED(hr))
{
BOOL bCheck=FALSE;
CSQLExecProcedure::NeedsToCheckKeyMigration(bCheck);
if (bCheck)
{
SQL_ID *pIDs= NULL;
int iNumIDs = 0;
hr = GetSchemaCache()->GetHierarchy(dClassId, &pIDs, iNumIDs);
if (SUCCEEDED(hr))
{
hr = CSQLExecProcedure::CheckKeyMigration(pConn, lpObjectKey, pProps->lpClassName,
dClassId, dScopeId, pIDs, iNumIDs);
delete pIDs;
}
}
}
if (SUCCEEDED(hr))
hr = CSQLExecProcedure::InsertPropertyBatch (pConn, lpObjectKey, lpPath, pProps->lpClassName, dClassId,
dScopeId, dwFlags, pPropValues, iPos,
dObjectId);
delete pPropValues;
// If there's no scope, quit now.
// This can only happen if we are only updating
// the security descriptor.
// ============================================
if (!pScope)
return hr;
// Insert qualifiers next.
// ======================
if (SUCCEEDED(hr))
{
iQfrPos = 0;
iNumProps *=2 + 10 + arrObjProps.Size(); // How do we calculate how many qualifiers there will be??
pQVals = new InsertQfrValues[iNumProps];
if (!pQVals)
return WBEM_E_OUT_OF_MEMORY;
VariantClear(&vTemp);
// PROPERTY QUALIFIERS
pObj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
while (pObj->Next(0, &strName, &vTemp, &cimtype, &lPropFlavor) == S_OK)
{
CFreeMe f (strName);
IWbemQualifierSet *pQS = NULL;
hr = pObj->GetPropertyQualifierSet(strName, &pQS);
if (hr == WBEM_S_NO_ERROR)
{
CReleaseMe r (pQS);
DWORD dwRefID = 0;
hr = GetSchemaCache()->GetPropertyID(strName, dClassId, 0, cimtype, dwRefID);
if (SUCCEEDED(hr))
hr = FormatBatchInsQfrs(pConn, pScope, dObjectId, dClassId, dwRefID, pQS, iQfrPos, &pQVals, props, iNumProps);
}
VariantClear(&vTemp);
}
// Instance qualifiers
if (SUCCEEDED(hr))
{
IWbemQualifierSet *pQS = NULL;
hr = pObj->GetQualifierSet(&pQS);
CReleaseMe r (pQS);
if (SUCCEEDED(hr))
hr = FormatBatchInsQfrs(pConn, pScope, dObjectId, dClassId, 0, pQS, iQfrPos, &pQVals, props, iNumProps);
if (SUCCEEDED(hr))
{
bool bToUpdate = false;
// Insert arrays and embedded objects last...
for (int i = 0; i < arrObjProps.Size(); i++)
{
VARIANT vTemp;
VariantInit(&vTemp);
CIMTYPE cimtype;
// OPTIMIZATION: Retrieve the buffer and write it directly,
// for all byte arrays.
if (!_wcsicmp(arrObjProps.GetAt(i), L"__SECURITY_DESCRIPTOR"))
{
BYTE *pBuff = NULL;
long handle;
hr = ((_IWmiObject *)pObj)->GetPropertyHandleEx(arrObjProps.GetAt(i), 0, NULL, &handle);
if (SUCCEEDED(hr))
{
ULONG uSize = 0;
hr = ((_IWmiObject *)pObj)->GetArrayPropAddrByHandle(handle, 0, &uSize, (LPVOID *)&pBuff);
if (SUCCEEDED(hr))
{
// Set this in the database
long why[1];
unsigned char t;
SAFEARRAYBOUND aBounds[1];
aBounds[0].cElements = uSize;
aBounds[0].lLbound = 0;
SAFEARRAY* pArray = SafeArrayCreate(VT_UI1, 1, aBounds);
vTemp.vt = VT_I1;
for (int i = 0; i < uSize; i++)
{
why[0] = i;
t = pBuff[i];
hr = SafeArrayPutElement(pArray, why, &t);
}
vTemp.vt = VT_ARRAY|VT_UI1;
V_ARRAY(&vTemp) = pArray;
cimtype = CIM_UINT8 + CIM_FLAG_ARRAY;
}
}
}
else
pObj->Get(arrObjProps.GetAt(i), 0, &vTemp, &cimtype, NULL);
if (cimtype == CIM_OBJECT)
{
bToUpdate = true;
IUnknown *pTemp = NULL;
pTemp = V_UNKNOWN(&vTemp);
if (pTemp)
{
DWORD dPropID;
SQL_ID dNewClassID = dClassId;
hr = GetSchemaCache()->GetPropertyID(arrObjProps.GetAt(i), dClassId,
0, CIM_OBJECT, dPropID, &dNewClassID);
if (SUCCEEDED(hr))
hr = InsertArray(pConn, pScope, dObjectId, dClassId, dPropID, vTemp, 0, 0, lpObjectKey, lpPath, dScopeId, cimtype);
else
break;
}
VariantClear(&vTemp);
}
else // Its an array, a blob, or a very long string.
{
DWORD dPropID;
SQL_ID dNewClassID = dClassId;
hr = GetSchemaCache()->GetPropertyID(arrObjProps.GetAt(i),
dClassId, 0, cimtype, dPropID, &dNewClassID);
if (SUCCEEDED(hr))
{
if (!_wcsicmp(arrObjProps.GetAt(i), L"__SECURITY_DESCRIPTOR"))
{
hr = TestSD(&vTemp);
if(FAILED(hr))
{
VariantClear( &vTemp );
break;
}
}
hr = InsertArray(pConn, pScope, dObjectId, dClassId, dPropID, vTemp, 0, 0, lpObjectKey, lpPath, dScopeId, cimtype);
if (SUCCEEDED(hr) && !_wcsicmp(arrObjProps.GetAt(i), L"__SECURITY_DESCRIPTOR"))
{
((CWmiDbController *)m_pController)->AddSecurityDescriptor(dObjectId);
// Is this an instance of __ThisNamespace? We need to copy this SD to the current scope object
if (dClassId == THISNAMESPACEID)
{
hr = InsertArray(pConn, pScope, dScopeId, NAMESPACECLASSID, dPropID, vTemp, 0, 0, NULL, NULL, 0, cimtype);
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->AddSecurityDescriptor(dScopeId);
}
}
}
VariantClear( &vTemp );
}
if (FAILED(hr))
break;
}
if (SUCCEEDED(hr) && iQfrPos)
hr = CSQLExecProcedure::InsertBatch (pConn, dObjectId, dClassId, dScopeId, pQVals, iQfrPos);
}
}
}
if (SUCCEEDED(hr))
{
if ((dClassId == NAMESPACECLASSID || GetSchemaCache()->IsDerivedClass(NAMESPACECLASSID, dClassId)))
{
hr = GetSchemaCache()->AddNamespace(lpPath, lpObjectKey, dObjectId, dScopeId, dClassId);
CSQLExecProcedure::InsertScopeMap(pConn, dObjectId, lpPath, dScopeId);
}
if (bRemoveSD)
{
((CWmiDbController *)m_pController)->RemoveSecurityDescriptor(dObjectId);
if (dClassId == THISNAMESPACEID)
((CWmiDbController *)m_pController)->RemoveSecurityDescriptor(dScopeId);
}
}
delete pQVals;
return hr;
}
//***************************************************************************
//
// CWmiDbSession::FormatBatchInsQfrs
//
//***************************************************************************
HRESULT CWmiDbSession::FormatBatchInsQfrs (CSQLConnection *pConn,IWmiDbHandle *pScope, SQL_ID dObjectId, SQL_ID dClassId,
DWORD dPropID, IWbemQualifierSet *pQS,
int &iPos, InsertQfrValues **ppVals, Properties &props, int &iNumProps)
{
HRESULT hr = WBEM_S_NO_ERROR;
BSTR strTemp;
VARIANT vTemp;
long lTemp;
InsertQfrValues *pVals = *ppVals;
pQS->BeginEnumeration(0);
while (pQS->Next(0, &strTemp, &vTemp, &lTemp) == S_OK)
{
CFreeMe f (strTemp);
// Don't bother with unstorable qualifiers.
if (lTemp & (WBEM_FLAVOR_ORIGIN_SYSTEM+WBEM_FLAVOR_ORIGIN_PROPAGATED+WBEM_FLAVOR_AMENDED))
{
VariantClear(&vTemp);
continue;
}
lTemp &= ~WBEM_FLAVOR_ORIGIN_PROPAGATED&~WBEM_FLAVOR_ORIGIN_SYSTEM&~WBEM_FLAVOR_AMENDED;
// Each qualifier, if not found in the cache,
// will need to be inserted...
DWORD dQfrID =0;
CIMTYPE ct = 0;
switch((vTemp.vt & (0xFFF)))
{
case VT_BSTR:
ct = CIM_STRING;
break;
case VT_R8:
case VT_R4:
ct = CIM_REAL64;
break;
case VT_BOOL:
ct = CIM_BOOLEAN;
break;
default:
ct = CIM_UINT32;
break;
}
if (FAILED(GetSchemaCache()->GetPropertyID(strTemp, 1,
REPDRVR_FLAG_QUALIFIER, ct, dQfrID)))
{
hr = InsertQualifier (pConn, pScope, dObjectId,strTemp, vTemp, lTemp, 0, dPropID,props);
if (FAILED(hr))
{
VariantClear(&vTemp);
break;
}
}
if (FAILED(GetSchemaCache()->GetPropertyID(strTemp, 1,
REPDRVR_FLAG_QUALIFIER, ct, dQfrID)))
continue;
if (iPos == iNumProps)
{
pVals = ReAllocQfrValues (pVals, iNumProps, iNumProps+10);
iNumProps += 10;
if (!pVals)
{
VariantClear(&vTemp);
return WBEM_E_OUT_OF_MEMORY;
}
*ppVals = pVals;
}
// Add this ID to the batch...
hr = FormatBatchInsQfrValues(pConn, pScope, dObjectId, dQfrID, vTemp, lTemp,
pVals, props, iPos, dPropID);
VariantClear(&vTemp);
if (FAILED(hr))
break;
}
pQS->EndEnumeration();
return hr;
}
//***************************************************************************
//
// CWmiDbSession::FormatBatchInsQfrValues
//
//***************************************************************************
HRESULT CWmiDbSession::FormatBatchInsQfrValues(CSQLConnection *pConn,IWmiDbHandle *pScope,
SQL_ID dObjectId, DWORD dwQfrID,
VARIANT &vTemp, long lFlavor, InsertQfrValues *pVals, Properties &props,
int &iPos, DWORD PropID)
{
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
HRESULT hr = WBEM_S_NO_ERROR;
bool bArray = false;
if (vTemp.vt & VT_ARRAY)
bArray = true;
if (!bArray)
{
LPWSTR lpVal = GetStr(vTemp);
CDeleteMe <wchar_t> r1 (lpVal);
pVals[iPos].iPos = 0;
pVals[iPos].iPropID = dwQfrID;
pVals[iPos].pValue = (lpVal ? new wchar_t [wcslen(lpVal)+1] : NULL);
pVals[iPos].pRefKey = NULL;
pVals[iPos].bLong = false;
if (lpVal)
wcscpy(pVals[iPos].pValue, lpVal);
pVals[iPos].iFlavor = lFlavor;
pVals[iPos].iQfrID = PropID;
pVals[iPos].dClassId = 1; // always, for qualifiers.
pVals[iPos].bIndexed = false; // never indexed
switch(vTemp.vt)
{
case VT_BSTR:
pVals[iPos].iStorageType = WMIDB_STORAGE_STRING;
break;
case VT_R4:
case VT_R8:
pVals[iPos].iStorageType = WMIDB_STORAGE_REAL;
break;
default:
pVals[iPos].iStorageType = WMIDB_STORAGE_NUMERIC;
break;
}
iPos++;
}
else
hr = InsertArray(pConn, pScope, dObjectId, 0, dwQfrID, vTemp, lFlavor, PropID);
return hr;
}
//***************************************************************************
//
// CWmiDbSession::DeleteObject
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::DeleteObject(
/* [in] */ IWmiDbHandle __RPC_FAR *pScope,
/* [in] */ DWORD dwFlags,
/* [in] */ REFIID riid,
/* [iid_is][in] */ LPVOID pObjToPut)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (!pObjToPut || !pScope)
return WBEM_E_INVALID_PARAMETER;
if (dwFlags & ~WMIDB_DISABLE_EVENTS & ~WMIDB_FLAG_ADMIN_VERIFIED)
return WBEM_E_INVALID_PARAMETER;
if (riid != IID_IWbemClassObject &&
riid != IID_IWmiDbHandle &&
riid != IID__IWmiObject &&
riid != IID_IWbemPath)
return WBEM_E_NOT_SUPPORTED;
SQL_ID dScopeId, dScopeClassId, dClassId, dObjectId;
LPWSTR lpClass = NULL, lpNamespace = NULL;
_IWmiObject *pObj = NULL;
try
{
{
_WMILockit lkt(GetCS());
if (!((CWmiDbController *)m_pController)->m_bCacheInit)
{
hr = LoadSchemaCache();
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->m_bCacheInit = TRUE;
else
return hr;
}
}
// If this is the __Instances container
// reject this operation..
if (GetSchemaCache()->IsDerivedClass
(INSTANCESCLASSID, ((CWmiDbHandle *)pScope)->m_dClassId) ||
((CWmiDbHandle *)pScope)->m_dClassId == INSTANCESCLASSID)
return WBEM_E_INVALID_OPERATION;
// We only really support IWmiDbHandles and IWbemPaths
CSQLConnection *pConn = NULL;
if (SUCCEEDED(hr))
{
AddRef_Lock();
IWmiDbHandle *pHandle = NULL;
IWbemPath *pPath = 0;
if (riid == IID_IWmiDbHandle)
{
pHandle = (IWmiDbHandle *)pObjToPut;
if (pHandle)
{
dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
dScopeClassId = ((CWmiDbHandle *)pScope)->m_dClassId;
dClassId = ((CWmiDbHandle *)pHandle)->m_dClassId;
dObjectId = ((CWmiDbHandle *)pHandle)->m_dObjectId;
if (!(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
hr = VerifyObjectSecurity(NULL, dObjectId, dClassId, dScopeId, dScopeClassId,
GetSchemaCache()->GetWriteToken(dObjectId, dClassId));
if (SUCCEEDED(hr))
{
hr = GetSQLCache()->GetConnection(&pConn, TRUE, IsDistributed());
if (SUCCEEDED(hr))
{
if(!(dwFlags & WMIDB_DISABLE_EVENTS))
hr = IssueDeletionEvents(pConn, dObjectId, dClassId, dScopeId, NULL);
if (!((CWmiDbHandle *)pHandle)->m_bDefault)
hr = CustomDelete(pConn, pScope, pHandle);
hr = Delete(pHandle, pConn);
GetSQLCache()->ReleaseConnection(pConn, hr, IsDistributed());
}
}
}
}
else if (riid == IID_IWbemPath)
{
pPath = (IWbemPath *)pObjToPut;
if (pPath)
{
hr = GetObject(pScope, pPath, dwFlags, WMIDB_HANDLE_TYPE_COOKIE|WMIDB_HANDLE_TYPE_EXCLUSIVE, &pHandle);
CReleaseMe r2 (pHandle);
if (SUCCEEDED(hr))
{
dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
dScopeClassId = ((CWmiDbHandle *)pScope)->m_dClassId;
dClassId = ((CWmiDbHandle *)pHandle)->m_dClassId;
dObjectId = ((CWmiDbHandle *)pHandle)->m_dObjectId;
if (!(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
hr = VerifyObjectSecurity(NULL, dObjectId, dClassId, dScopeId, dScopeClassId,
GetSchemaCache()->GetWriteToken(dObjectId, dClassId));
if (SUCCEEDED(hr))
{
hr = GetSQLCache()->GetConnection(&pConn, TRUE, IsDistributed());
if (SUCCEEDED(hr))
{
if(!(dwFlags & WMIDB_DISABLE_EVENTS))
hr = IssueDeletionEvents(pConn, dObjectId, dClassId, dScopeId, NULL);
if (!((CWmiDbHandle *)pHandle)->m_bDefault)
hr = CustomDelete(pConn, pScope, pHandle);
hr = Delete(pHandle, pConn);
GetSQLCache()->ReleaseConnection(pConn, hr, IsDistributed());
}
}
}
}
}
else if (riid == IID_IWbemClassObject ||
riid == IID__IWmiObject)
{
pObj = (_IWmiObject *)pObjToPut;
if (pObj)
{
lpClass = GetPropertyVal(L"__Class", pObj);
LPWSTR lpPath = GetPropertyVal(L"__RelPath", pObj);
if (lpPath)
{
hr = CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER,
IID_IWbemPath, (LPVOID *) &pPath);
CReleaseMe r2 (pPath);
if (SUCCEEDED(hr))
{
pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, lpPath);
hr = GetObject(pScope, pPath, dwFlags, WMIDB_HANDLE_TYPE_COOKIE|WMIDB_HANDLE_TYPE_EXCLUSIVE, &pHandle);
CReleaseMe r3 (pHandle);
if (SUCCEEDED(hr))
{
dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
dScopeClassId = ((CWmiDbHandle *)pScope)->m_dClassId;
dClassId = ((CWmiDbHandle *)pHandle)->m_dClassId;
dObjectId = ((CWmiDbHandle *)pHandle)->m_dObjectId;
if (!(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
hr = VerifyObjectSecurity(NULL, dObjectId, dClassId, dScopeId, dScopeClassId,
GetSchemaCache()->GetWriteToken(dObjectId, dClassId));
if (SUCCEEDED(hr))
{
hr = GetSQLCache()->GetConnection(&pConn, TRUE, IsDistributed());
if (SUCCEEDED(hr))
{
if(!(dwFlags & WMIDB_DISABLE_EVENTS))
hr = IssueDeletionEvents(pConn, dObjectId, dClassId, dScopeId, (IWbemClassObject *)pObj);
if (!((CWmiDbHandle *)pHandle)->m_bDefault)
hr = CustomDelete(pConn, pScope, pHandle);
hr = Delete(pHandle, pConn);
GetSQLCache()->ReleaseConnection(pConn, hr, IsDistributed());
}
}
}
}
}
}
}
else
hr = WBEM_E_NOT_SUPPORTED;
if (!IsDistributed() && !(dwFlags & WMIDB_DISABLE_EVENTS) )
{
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->ESSMgr.CommitAll(m_sGUID, m_sNamespacePath);
}
UnlockDynasties();
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::DeleteObject\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::IssueDeletionEvents
//
//***************************************************************************
HRESULT CWmiDbSession::IssueDeletionEvents (CSQLConnection *pConn, SQL_ID dObjectId,
SQL_ID dClassId, SQL_ID dScopeId, IWbemClassObject *_pObj)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (((CWmiDbController *)m_pController)->m_bESSEnabled)
{
if (_pObj)
_pObj->AddRef();
// The rules:
// Instance: we don't issue a deletion event for any subobjects, period.
// Class: issue delete events for all subclasses, not instances
DWORD dwGenus = 1;
if (dClassId != 1)
dwGenus = 2;
IWbemClassObject *pObj = _pObj;
if (!pObj)
{
// Get the object.
if (FAILED(GetObjectCache()->GetObject(dObjectId, &pObj, NULL)))
{
DWORD dwTemp;
hr = GetObjectData(pConn, dObjectId, dClassId, dScopeId,
WMIDB_HANDLE_TYPE_EXCLUSIVE, dwTemp, &pObj, FALSE, NULL);
}
}
CReleaseMe r (pObj);
// FIXME: Need to handle custom repdrvr deletion events!
if (!pObj)
return WBEM_S_NO_ERROR;
// Get the namespace.
_bstr_t sNamespace, sClass;
GetSchemaCache()->GetNamespaceName(dScopeId, &sNamespace);
if (!_wcsicmp(sNamespace, L"root"))
sNamespace = L"";
_bstr_t sPath;
SQL_ID dTemp1, dTemp2;
DWORD dwTemp;
if (dwGenus == 1)
GetSchemaCache()->GetClassInfo (dObjectId, sPath, dTemp1, dTemp2, dwTemp, &sClass);
else
GetSchemaCache()->GetClassInfo (dClassId, sPath, dTemp1, dTemp2, dwTemp, &sClass);
((CWmiDbController *)m_pController)->ESSMgr.AddDeleteRecord(pConn, m_sGUID, sNamespace, sClass, dwGenus, pObj);
// If this is a class, enumerate
// subclasses and issue deletion events
if (dwGenus == 1)
{
SQL_ID *pIDs = NULL;
int iNumDerived = 0;
hr = GetSchemaCache()->GetDerivedClassList(dObjectId, &pIDs, iNumDerived);
if (SUCCEEDED(hr))
{
for (int i = 0; i < iNumDerived; i++)
{
IWbemClassObject *pOldObj = NULL;
hr = GetClassObject(pConn, pIDs[i], &pOldObj);
CReleaseMe r (pOldObj);
if (SUCCEEDED(hr))
{
LPWSTR lpClassName = GetPropertyVal(L"__Class", pOldObj);
CDeleteMe <wchar_t> d2 (lpClassName);
((CWmiDbController *)m_pController)->ESSMgr.AddDeleteRecord(pConn, m_sGUID,
sNamespace, sClass, dwGenus, pOldObj);
}
}
delete pIDs;
}
if (GetSchemaCache()->IsDerivedClass(dObjectId, NAMESPACECLASSID))
{
// If this is a class derived from __Namespace,
// we have to enumerate the INSTANCES and issue events for them
// ============================================================
}
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::RenameObject
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::RenameObject(
/* [in] */ IWbemPath __RPC_FAR *pOldPath,
/* [in] */ IWbemPath __RPC_FAR *pNewPath,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwRequestedHandleType,
/* [out] */ IWmiDbHandle __RPC_FAR *__RPC_FAR *ppResult)
{
HRESULT hr = WBEM_S_NO_ERROR;
IWmiDbHandle *pRet = NULL;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (!pOldPath || !pNewPath)
return WBEM_E_INVALID_PARAMETER;
// This has to handle moving an object from one scope or namespace
// to another, as well as renaming the keys.
// Moving from one container to another does not work.
try
{
ULONGLONG uIsInstance1 = 0, uIsInstance2 = 0;
hr = pOldPath->GetInfo(0, &uIsInstance1);
hr = pNewPath->GetInfo(0, &uIsInstance2);
if (!(uIsInstance1 & WBEMPATH_INFO_IS_INST_REF) || !(uIsInstance2 & WBEMPATH_INFO_IS_INST_REF))
hr = WBEM_E_INVALID_OPERATION;
else
{
DWORD dwLen = 512;
wchar_t wClass1 [512], wClass2[512];
hr = pOldPath->GetClassName(&dwLen, wClass1);
hr = pNewPath->GetClassName(&dwLen, wClass2);
if (wcscmp(wClass1, wClass2))
hr = WBEM_E_INVALID_OPERATION;
else
{
IWmiDbHandle *pOld = NULL;
IWmiDbHandle *pNewScope = NULL;
LPWSTR lpOldPath, lpOldKey, lpNewPath, lpNewKey;
hr = NormalizeObjectPathGet(NULL, pOldPath, &lpOldPath);
if (FAILED(hr))
goto Exit;
CDeleteMe <wchar_t> d10(lpOldPath);
hr = GetObject_Internal(lpOldPath, 0, WMIDB_HANDLE_TYPE_VERSIONED, NULL, &pOld);
if (FAILED(hr))
goto Exit;
CReleaseMe r (pOld);
if (SUCCEEDED(hr))
{
SQL_ID dScopeID = ((CWmiDbHandle *)pOld)->m_dScopeId;
_IWmiObject *pObj = NULL;
hr = pOld->QueryInterface(IID__IWmiObject, (void **)&pObj);
if (SUCCEEDED(hr))
{
CReleaseMe r6 (pObj);
IWbemPathKeyList *pKeys1 = NULL, *pKeys2 = NULL;
CWStringArray arrKeys;
hr = GetSchemaCache()->GetKeys(
dScopeID, wClass1, arrKeys);
if (SUCCEEDED(hr))
{
hr = pOldPath->GetKeyList(&pKeys1);
CReleaseMe r4(pKeys1);
if (FAILED(hr))
goto Exit;
hr = pNewPath->GetKeyList(&pKeys2);
CReleaseMe r5 (pKeys2);
if (FAILED(hr))
goto Exit;
ULONG uOldNum = 0, uNewNum = 0;
hr = pKeys1->GetCount(&uOldNum);
if (FAILED(hr))
goto Exit;
hr = pKeys2->GetCount(&uNewNum);
if (FAILED(hr))
goto Exit;
if (arrKeys.Size() != uOldNum || arrKeys.Size() != uNewNum)
{
hr = WBEM_E_INVALID_OBJECT;
goto Exit;
}
else if (arrKeys.Size() > 0)
{
for (int i = 0; i < arrKeys.Size(); i++)
{
ULONG uBufSize = 512;
ULONG ct2 = 0;
BOOL bFound = FALSE;
for (ULONG j = 0; j < arrKeys.Size(); j++)
{
VARIANT vTemp;
VariantInit(&vTemp);
CClearMe c (&vTemp);
wchar_t wBuff[1024];
ULONG uBufSize = 1024;
CIMTYPE ct = 0;
pObj->Get(arrKeys.GetAt(i), 0, NULL, &ct, NULL);
hr = pKeys2->GetKey2(j, 0, &uBufSize, wBuff, &vTemp, &ct2);
if (FAILED(hr))
goto Exit;
if (!wcslen(wBuff) || !wcscmp(arrKeys.GetAt(i), wBuff))
{
bFound = TRUE;
hr = pObj->Put(arrKeys.GetAt(i), 0, &vTemp, ct);
if (FAILED(hr))
goto Exit;
break;
}
}
if (!bFound)
{
hr = WBEM_E_INVALID_PARAMETER;
goto Exit;
}
}
}
else
hr = WBEM_E_INVALID_OPERATION; // Cannot rename singleton
}
if (SUCCEEDED(hr))
{
pNewPath->DeleteClassPart(0);
LPWSTR lpNewScope = NULL;
hr = NormalizeObjectPathGet(NULL, pNewPath, &lpNewScope);
if (FAILED(hr))
goto Exit;
CDeleteMe <wchar_t> d14 (lpNewScope);
hr = GetObject_Internal(lpNewScope, 0, WMIDB_HANDLE_TYPE_VERSIONED, NULL, &pNewScope);
if (FAILED(hr))
goto Exit;
if (SUCCEEDED(hr))
{
// Create the new object
if (!dwRequestedHandleType)
dwRequestedHandleType = WMIDB_HANDLE_TYPE_COOKIE;
_bstr_t sWaste;
IWmiDbHandle *pHandle = 0;
hr = PutObject( pNewScope, IID_IWbemClassObject, pObj, 0, dwRequestedHandleType, &pHandle);
if (SUCCEEDED(hr))
{
// Enumerate the subscopes of the old object,
IWmiDbIterator *pIt = NULL;
hr = Enumerate(pOld, 0, WMIDB_HANDLE_TYPE_COOKIE, &pIt);
if (SUCCEEDED(hr))
{
IWbemClassObject *pResult = NULL;
DWORD dwNum = 0;
while (pIt->NextBatch(1, 0, 0, 0, IID_IWbemClassObject, &dwNum, (void **)&pResult) == 0)
{
hr = PutObject( pHandle, IID_IWbemClassObject, pResult, 0, 0, NULL);
pResult->Release();
if (FAILED(hr))
break;
}
pIt->Release();
}
((CWmiDbHandle *)pOld)->m_dwHandleType |= WMIDB_HANDLE_TYPE_CONTAINER;
// Enumerate any collection members (if this was a collection).
hr = Enumerate(pOld, 0, WMIDB_HANDLE_TYPE_COOKIE, &pIt);
if (SUCCEEDED(hr))
{
IWbemClassObject *pResult = NULL;
DWORD dwNum = 0;
while (pIt->NextBatch(1, 0, 0, 0, IID_IWbemClassObject, &dwNum, (void **)&pResult) == 0)
{
hr = PutObject( pHandle, IID_IWbemClassObject, pResult, 0, 0, NULL);
pResult->Release();
if (FAILED(hr))
break;
}
pIt->Release();
}
// If all that worked, kill the old object. This will leave
// dangling references, but that's OK.
if (SUCCEEDED(hr))
hr = Delete (pOld);
}
if (ppResult)
*ppResult = pHandle;
else if (pHandle)
pHandle->Release();
}
}
}
}
}
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::RenameObject"));
hr = WBEM_E_CRITICAL_ERROR;
}
Exit:
return hr;
}
//***************************************************************************
//
// CWmiDbSession::AddObject
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::AddObject(
/* [in] */ IWmiDbHandle __RPC_FAR *pScope,
/* [in] */ IWbemPath __RPC_FAR *pPath,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwRequestedHandleType,
/* [out] */ IWmiDbHandle __RPC_FAR *__RPC_FAR *ppResult)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (!pScope || !pPath)
return WBEM_E_INVALID_PARAMETER;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (dwRequestedHandleType & ~WMIDB_HANDLE_TYPE_COOKIE
&~WMIDB_HANDLE_TYPE_VERSIONED &~WMIDB_HANDLE_TYPE_PROTECTED
&~WMIDB_HANDLE_TYPE_EXCLUSIVE &~ WMIDB_HANDLE_TYPE_WEAK_CACHE
&~WMIDB_HANDLE_TYPE_STRONG_CACHE &~ WMIDB_HANDLE_TYPE_NO_CACHE
&~WMIDB_HANDLE_TYPE_SUBSCOPED&~WMIDB_HANDLE_TYPE_CONTAINER&~ WMIDB_HANDLE_TYPE_SCOPE)
return WBEM_E_INVALID_PARAMETER;
try
{
{
_WMILockit lkt(GetCS());
if (!((CWmiDbController *)m_pController)->m_bCacheInit)
{
hr = LoadSchemaCache();
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->m_bCacheInit = TRUE;
else
return hr;
}
}
if (GetSchemaCache()->IsDerivedClass
(INSTANCESCLASSID, ((CWmiDbHandle *)pScope)->m_dClassId) ||
((CWmiDbHandle *)pScope)->m_dClassId == INSTANCESCLASSID )
return WBEM_E_INVALID_OPERATION;
// This needs to add an object as a contained instance.
// * Create a new instance of __Container_Association
// * Call PutObject
IWmiDbHandle *pContainerAssoc = NULL;
hr = GetObject_Internal(L"__Container_Association", 0, WMIDB_HANDLE_TYPE_VERSIONED,
NULL, &pContainerAssoc);
if (SUCCEEDED(hr))
{
IWbemClassObject *pClassObj = NULL;
hr = pContainerAssoc->QueryInterface(IID_IWbemClassObject, (void **)&pClassObj);
CReleaseMe r1 (pClassObj), r2 (pContainerAssoc);
if (SUCCEEDED(hr))
{
IWbemClassObject *pObj = NULL;
pClassObj->SpawnInstance(0, &pObj);
CReleaseMe r (pObj);
LPWSTR lpContainer = NULL, lpContainee;
hr = NormalizeObjectPath(pScope, (LPCWSTR)NULL, &lpContainer);
CDeleteMe <wchar_t> d1 (lpContainer);
if (SUCCEEDED(hr))
{
hr = NormalizeObjectPathGet(NULL, pPath, &lpContainee);
CDeleteMe <wchar_t> d2 (lpContainee);
if (SUCCEEDED(hr))
{
VARIANT vContainer, vContainee;
CClearMe c1 (&vContainer), c2 (&vContainee);
VariantInit(&vContainer);
VariantInit(&vContainee);
vContainer.bstrVal = SysAllocString(lpContainer);
vContainee.bstrVal = SysAllocString(lpContainee);
vContainer.vt = VT_BSTR;
vContainee.vt = VT_BSTR;
hr = pObj->Put(L"Container", 0, &vContainer, CIM_REFERENCE);
if (SUCCEEDED(hr))
{
hr = pObj->Put(L"Containee", 0, &vContainee, CIM_REFERENCE);
if (SUCCEEDED(hr))
{
// Stick this object in the
// parent's scope.
SQL_ID dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
IWmiDbHandle *pParentScope = NULL;
hr = GetObject_Internal(L"..", 0, WMIDB_HANDLE_TYPE_VERSIONED, &dScopeId, &pParentScope);
CReleaseMe r (pParentScope);
if (SUCCEEDED(hr))
hr = PutObject(pParentScope, IID_IWbemClassObject, pObj, dwFlags, dwRequestedHandleType, ppResult);
}
}
}
}
}
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::AddObject\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::RemoveObject
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::RemoveObject(
/* [in] */ IWmiDbHandle __RPC_FAR *pScope,
/* [in] */ IWbemPath __RPC_FAR *pPath,
/* [in] */ DWORD dwFlags)
{
HRESULT hr = WBEM_S_NO_ERROR;
// This needs to remove an object from the container.
// * Retrieves the handle to the container association
// * Calls DeleteObject
if (!pScope || !pPath)
return WBEM_E_INVALID_PARAMETER;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
try
{
{
_WMILockit lkt(GetCS());
if (!((CWmiDbController *)m_pController)->m_bCacheInit)
{
hr = LoadSchemaCache();
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->m_bCacheInit = TRUE;
else
return hr;
}
}
if (GetSchemaCache()->IsDerivedClass
(INSTANCESCLASSID, ((CWmiDbHandle *)pScope)->m_dClassId) ||
((CWmiDbHandle *)pScope)->m_dClassId == INSTANCESCLASSID)
return WBEM_E_INVALID_OPERATION;
LPWSTR lpContainer = NULL, lpContainee;
hr = NormalizeObjectPath(pScope, (LPCWSTR)NULL, &lpContainer);
CDeleteMe <wchar_t> d1 (lpContainer);
if (SUCCEEDED(hr))
{
hr = NormalizeObjectPathGet(NULL, pPath, &lpContainee);
CDeleteMe <wchar_t> d2 (lpContainee);
wchar_t *pTemp = new wchar_t [wcslen(lpContainer)+wcslen(lpContainee)+50];
if (pTemp)
{
CDeleteMe <wchar_t> d (pTemp);
swprintf(pTemp, L"__Container_Association.Container='%s',Containee='%s'",
lpContainer, lpContainee);
IWbemPath *pPath = NULL;
hr = CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER,
IID_IWbemPath, (LPVOID *) &pPath);
CReleaseMe r8 (pPath);
if (SUCCEEDED(hr))
{
hr = pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, pTemp);
IWmiDbHandle *pParentScope = NULL;
SQL_ID dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
hr = GetObject_Internal(L"..", 0, WMIDB_HANDLE_TYPE_VERSIONED, &dScopeId, &pParentScope);
CReleaseMe r (pParentScope);
if (SUCCEEDED(hr))
hr = DeleteObject(pParentScope, dwFlags, IID_IWbemPath, pPath);
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::RemoveObject\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::SetDecoration
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::SetDecoration(
/* [in] */ LPWSTR lpMachineName,
/* [in] */ LPWSTR lpNamespacePath)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
try
{
if (!lpMachineName || !lpNamespacePath)
hr = WBEM_E_INVALID_PARAMETER;
else
{
m_sMachineName = lpMachineName;
m_sNamespacePath = lpNamespacePath;
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::SetDecoration\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::PutObjects
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::PutObjects(
/* [in] */ IWmiDbHandle __RPC_FAR *pScope,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwHandleType,
/* [in] */ WMIOBJECT_BATCH __RPC_FAR *pBatch)
{
HRESULT hr = WBEM_S_NO_ERROR;
HRESULT hrRet=0;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (dwHandleType == WMIDB_HANDLE_TYPE_INVALID || !pBatch ||!pScope)
return WBEM_E_INVALID_PARAMETER;
if (dwFlags &~WMIDB_FLAG_BEST_EFFORT &~WMIDB_FLAG_ATOMIC
& ~WBEM_FLAG_CREATE_ONLY & ~WBEM_FLAG_UPDATE_ONLY & ~WBEM_FLAG_CREATE_OR_UPDATE
& ~WBEM_FLAG_USE_SECURITY_DESCRIPTOR &~ WBEM_FLAG_REMOVE_CHILD_SECURITY)
return WBEM_E_INVALID_PARAMETER;
try
{
CSQLConnection *pConn = NULL;
hr = GetSQLCache()->GetConnection(&pConn, TRUE, IsDistributed());
if (SUCCEEDED(hr))
{
AddRef_Lock();
for (int i = 0; i < pBatch->dwArraySize; i++)
{
IUnknown *pUnk = (IUnknown *)pBatch->pElements[i].pHandle;
if (pUnk)
{
IWmiDbHandle *pTemp = NULL;
_bstr_t sWaste;
hr = PutObject(pConn, pScope, 0, L"", pUnk, dwFlags&~WMIDB_FLAG_BEST_EFFORT&~WMIDB_FLAG_ATOMIC, dwHandleType, sWaste, &pTemp);
if (SUCCEEDED(hr))
pBatch->pElements[i].pReturnHandle = pTemp;
pBatch->pElements[i].hRes = hr;
}
else
{
pBatch->pElements[i].hRes = WBEM_E_INVALID_PARAMETER;
hr = WBEM_E_INVALID_PARAMETER;
}
if (FAILED(hr) && (dwFlags == WMIDB_FLAG_ATOMIC)) // If one fails, keep going.
{
hrRet = hr;
break;
}
else if (FAILED(hr))
hrRet = WBEM_S_PARTIAL_RESULTS;
}
if (FAILED(hr) && !(dwFlags & WMIDB_FLAG_ATOMIC))
hr = WBEM_S_NO_ERROR;
GetSQLCache()->ReleaseConnection(pConn, hr, IsDistributed());
if (!IsDistributed() && !(dwFlags & WMIDB_DISABLE_EVENTS) )
{
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->ESSMgr.CommitAll(m_sGUID, m_sNamespacePath);
}
UnlockDynasties();
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::PutObjects\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hrRet;
}
//***************************************************************************
//
// CWmiDbSession::GetObjects
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::GetObjects(
/* [in] */ IWmiDbHandle __RPC_FAR *pScope,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwHandleType,
/* [in, out] */ WMIOBJECT_BATCH __RPC_FAR *pBatch)
{
HRESULT hr = WBEM_S_NO_ERROR;
HRESULT hrRet = 0;
// This is really just a query, except that we need
// to set return values in the struct.
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (dwHandleType == WMIDB_HANDLE_TYPE_INVALID || !pBatch ||!pScope)
return WBEM_E_INVALID_PARAMETER;
if (dwHandleType & ~WMIDB_HANDLE_TYPE_COOKIE
&~WMIDB_HANDLE_TYPE_VERSIONED &~WMIDB_HANDLE_TYPE_PROTECTED
&~WMIDB_HANDLE_TYPE_EXCLUSIVE &~ WMIDB_HANDLE_TYPE_WEAK_CACHE
&~WMIDB_HANDLE_TYPE_STRONG_CACHE &~ WMIDB_HANDLE_TYPE_NO_CACHE
&~WMIDB_HANDLE_TYPE_SUBSCOPED &~WMIDB_HANDLE_TYPE_SCOPE
&~WMIDB_HANDLE_TYPE_CONTAINER)
return WBEM_E_INVALID_PARAMETER;
if (dwFlags &~WMIDB_FLAG_BEST_EFFORT &~WMIDB_FLAG_ATOMIC & ~WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
return WBEM_E_INVALID_PARAMETER;
try
{
AddRef_Lock();
if (SUCCEEDED(hr))
{
for (int i = 0; i < pBatch->dwArraySize; i++)
{
IWbemPath *pPath = pBatch->pElements[i].pPath;
IWmiDbHandle *pTemp = NULL;
hr = GetObject(pScope, pPath, pBatch->pElements[i].dwFlags, dwHandleType, &pTemp);
if (SUCCEEDED(hr))
{
pBatch->pElements[i].pReturnHandle = pTemp;
pBatch->pElements[i].hRes = hr;
pBatch->pElements[i].dwFlags = dwFlags;
}
if (FAILED(hr) && (dwFlags == WMIDB_FLAG_ATOMIC)) // If one fails, keep going.
{
hrRet = hr;
break;
}
else if (FAILED(hr))
hrRet = WBEM_S_PARTIAL_RESULTS;
}
}
UnlockDynasties();
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::GetObjects\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hrRet;
}
//***************************************************************************
//
// CWmiDbSession::DeleteObjects
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::DeleteObjects(
/* [in] */ IWmiDbHandle __RPC_FAR *pScope,
/* [in] */ DWORD dwFlags,
/* [in] */ WMIOBJECT_BATCH __RPC_FAR *pBatch)
{
HRESULT hr = WBEM_S_NO_ERROR;
HRESULT hrRet = 0;
if (!pBatch || !pScope)
return WBEM_E_INVALID_PARAMETER;
if (dwFlags &~WMIDB_FLAG_BEST_EFFORT &~WMIDB_FLAG_ATOMIC &~ WMIDB_FLAG_ADMIN_VERIFIED)
return WBEM_E_INVALID_PARAMETER;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
try
{
{
_WMILockit lkt(GetCS());
if (!((CWmiDbController *)m_pController)->m_bCacheInit)
{
hr = LoadSchemaCache();
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->m_bCacheInit = TRUE;
else
return hr;
}
}
CSQLConnection *pConn = NULL;
SQL_ID dScopeId, dClassId, dObjectId;
hr = GetSQLCache()->GetConnection(&pConn, TRUE, IsDistributed());
if (SUCCEEDED(hr))
{
AddRef_Lock();
for (int i = 0; i < pBatch->dwArraySize; i++)
{
IUnknown *pUnk = (IUnknown *)pBatch->pElements[i].pHandle;
if (pUnk)
{
IWmiDbHandle *pHandle = NULL;
if (SUCCEEDED(pUnk->QueryInterface(IID_IWmiDbHandle, (void **)&pHandle)))
{
CReleaseMe r (pHandle);
dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
dClassId = ((CWmiDbHandle *)pHandle)->m_dClassId;
dObjectId = ((CWmiDbHandle *)pHandle)->m_dObjectId;
SQL_ID dScopeClassId = ((CWmiDbHandle *)pScope)->m_dClassId;
if (!(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
hr = VerifyObjectSecurity(NULL, dObjectId, dClassId, dScopeId, dScopeClassId,
GetSchemaCache()->GetWriteToken(dObjectId, dClassId));
if (SUCCEEDED(hr))
{
if (!((CWmiDbHandle *)pHandle)->m_bDefault)
hr = CustomDelete(pConn, pScope, pHandle);
hr = Delete(pHandle, pConn);
}
}
else
pBatch->pElements[i].hRes = WBEM_E_INVALID_PARAMETER;
}
else if (pBatch->pElements[i].pPath)
{
// Problem: We need the binary object path to include the scope!!!
IWbemPath *pPath = pBatch->pElements[i].pPath;
if (pPath)
{
IWmiDbHandle *pHandle = NULL;
hr = GetObject(pScope, pPath, dwFlags, WMIDB_HANDLE_TYPE_COOKIE|WMIDB_HANDLE_TYPE_EXCLUSIVE, &pHandle);
CReleaseMe r (pHandle);
if (SUCCEEDED(hr))
{
dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
dClassId = ((CWmiDbHandle *)pHandle)->m_dClassId;
dObjectId = ((CWmiDbHandle *)pHandle)->m_dObjectId;
SQL_ID dScopeClassId = ((CWmiDbHandle *)pScope)->m_dClassId;
if (!(dwFlags & WMIDB_FLAG_ADMIN_VERIFIED))
hr = VerifyObjectSecurity(NULL, dObjectId, dClassId, dScopeId, dScopeClassId,
GetSchemaCache()->GetWriteToken(dObjectId, dClassId));
if (SUCCEEDED(hr))
{
if (!((CWmiDbHandle *)pHandle)->m_bDefault)
hr = CustomDelete(pConn, pScope, pHandle);
hr = Delete(pHandle, pConn);
}
}
}
}
else
pBatch->pElements[i].hRes = WBEM_E_INVALID_PARAMETER;
pBatch->pElements[i].hRes = hr;
if (FAILED(hr) && (dwFlags == WMIDB_FLAG_ATOMIC)) // If one fails, keep going.
{
hrRet = hr;
break;
}
else if (FAILED(hr))
hrRet = WBEM_S_PARTIAL_RESULTS;
}
GetSQLCache()->ReleaseConnection(pConn, hr, IsDistributed());
if (!IsDistributed() && !(dwFlags & WMIDB_DISABLE_EVENTS) )
{
if (SUCCEEDED(hr))
((CWmiDbController *)m_pController)->ESSMgr.CommitAll(m_sGUID, m_sNamespacePath);
}
UnlockDynasties();
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::DeleteObjects\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hrRet;
}
//***************************************************************************
//
// CWmiDbSession::Begin
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::Begin(
/* [in] */ ULONG uTimeout,
/* [in] */ ULONG uFlags,
/* [in] */ GUID __RPC_FAR *pTransGUID)
{
HRESULT hr = WBEM_S_NO_ERROR;
// There can't be an existing transaction.
if (m_sGUID.length() > 0)
return WBEM_E_INVALID_OPERATION;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
// Get or Create a __Transaction instance for this GUID
// Transaction state = Pending
// ================================================
wchar_t wGUID[128];
StringFromGUID2(*pTransGUID, wGUID, 128);
wchar_t wPath[255];
swprintf(wPath, L"__Transaction.GUID=\"%s\"", (LPCWSTR)wGUID);
IWmiDbHandle *pHandle = NULL;
hr = GetObject_Internal(wPath, 0, WMIDB_HANDLE_TYPE_COOKIE, NULL, &pHandle);
CReleaseMe r1 (pHandle);
if (SUCCEEDED(hr))
{
_IWmiObject *pObj = NULL;
hr = pObj->QueryInterface(IID__IWmiObject, (void **)&pObj);
CReleaseMe r2 (pObj);
if (SUCCEEDED(hr))
{
ULONG uState = 0;
LPWSTR lpTemp = NULL;
lpTemp = GetPropertyVal(L"State", pObj);
CDeleteMe <wchar_t> d (lpTemp);
uState = _wtol(lpTemp);
//hr = pObj->ReadProp(L"State", 0, sizeof(ULONG), NULL,
// NULL, NULL, NULL, &uState);
if (uState > WBEM_TRANSACTION_STATE_PENDING)
{
return WBEM_E_ALREADY_EXISTS;
}
}
}
else
{
// Create a new one.
_IWmiObject *pObj = NULL;
hr = GetObject_Internal(L"__Transaction", 0, WMIDB_HANDLE_TYPE_COOKIE,
NULL, &pHandle);
CReleaseMe r2 (pHandle);
if (SUCCEEDED(hr))
{
hr = pHandle->QueryInterface(IID__IWmiObject, (void **)&pObj);
if (SUCCEEDED(hr))
{
CReleaseMe r3 (pObj);
IWbemClassObject *pInst2 = NULL;
pObj->SpawnInstance(0, &pInst2);
CReleaseMe r (pInst2);
if (pInst2)
{
_IWmiObject *pInst = (_IWmiObject *)pInst2;
ULONG uTemp = WBEM_TRANSACTION_STATE_PENDING;
WBEMTime tNow(time(0));
BSTR sTime = tNow.GetDMTF(TRUE);
CFreeMe f (sTime);
pInst->WriteProp(L"GUID", 0, (wcslen(wGUID)*2)+2, 1, CIM_STRING, wGUID);
pInst->WriteProp(L"State", 0, sizeof(ULONG), 1, CIM_UINT32, &uTemp);
pInst->WriteProp(L"Start", 0, (wcslen(sTime)*2)+2, 1, CIM_DATETIME, sTime);
pInst->WriteProp(L"LastUpdate", 0, (wcslen(sTime)*2)+2, 1, CIM_DATETIME, sTime);
CSQLConnection *pConn = NULL;
hr = GetSQLCache()->GetConnection(&pConn, FALSE, FALSE);
if (SUCCEEDED(hr))
{
_bstr_t sPath;
hr = PutObject(pConn, NULL, ROOTNAMESPACEID, L"", pInst, 0, NULL, sPath, NULL, FALSE);
GetSQLCache()->ReleaseConnection(pConn, hr);
}
}
}
}
}
if (SUCCEEDED(hr))
{
m_bIsDistributed = TRUE;
m_sGUID = wGUID;
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::Rollback
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::Rollback(
/* [in] */ ULONG uFlags)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (m_sGUID.length() == 0)
return WBEM_E_INVALID_OPERATION;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
// Rollback and release the transaction.
// ======================================
CSQLConnection *pConn = NULL;
hr = GetSQLCache()->GetConnection(&pConn, FALSE, TRUE);
if (SUCCEEDED(hr))
{
GetSQLCache()->FinalRollback(pConn);
GetSQLCache()->ReleaseConnection(pConn, 0, TRUE);
}
else
return hr;
AddRef_Lock();
CleanTransLocks();
wchar_t wPath[255];
swprintf(wPath, L"__Transaction.GUID=\"%s\"", (LPCWSTR)m_sGUID);
m_sGUID = L"";
m_bIsDistributed = FALSE;
// __Transaction state = rolled back
// =================================
IWmiDbHandle *pHandle = NULL;
hr = GetObject_Internal(wPath, 0, WMIDB_HANDLE_TYPE_COOKIE, NULL, &pHandle);
CReleaseMe r1 (pHandle);
if (SUCCEEDED(hr))
{
_IWmiObject *pObj = NULL;
hr = pHandle->QueryInterface(IID__IWmiObject, (void **)&pObj);
CReleaseMe r2 (pObj);
if (SUCCEEDED(hr))
{
hr = GetSQLCache()->GetConnection(&pConn, FALSE, FALSE);
if (SUCCEEDED(hr))
{
ULONG uState = WBEM_TRANSACTION_STATE_ROLLED_BACK;
pObj->WriteProp(L"State", 0, sizeof(ULONG), 1, CIM_UINT32, &uState);
_bstr_t sPath;
hr = PutObject(pConn, NULL, ROOTNAMESPACEID, L"", pObj, 0, NULL, sPath, NULL, FALSE);
GetSQLCache()->ReleaseConnection(pConn, hr);
}
}
}
// Delete all events and remove all locks.
if (SUCCEEDED(hr))
hr = ((CWmiDbController *)m_pController)->ESSMgr.DeleteAll(m_sGUID);
// Remove any affected dynasties from the cache,
// to make sure we force a reread from the db.
UnlockDynasties(TRUE);
return hr;
}
//***************************************************************************
//
// CWmiDbSession::Commit
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::Commit(
/* [in] */ ULONG uFlags)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (m_sGUID.length() == 0)
return WBEM_E_INVALID_OPERATION;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
// __Transaction state = EventPlayback
// Include this as final query.
// ===================================
AddRef_Lock();
wchar_t wPath[255];
swprintf(wPath, L"__Transaction.GUID=\"%s\"", (LPCWSTR)m_sGUID);
IWmiDbHandle *pHandle = NULL;
hr = GetObject_Internal(wPath, 0, WMIDB_HANDLE_TYPE_COOKIE, NULL, &pHandle);
if (SUCCEEDED(hr))
{
_IWmiObject *pObj = NULL;
hr = pHandle->QueryInterface(IID__IWmiObject, (void **)&pObj);
CReleaseMe r2 (pObj);
if (SUCCEEDED(hr))
{
CSQLConnection *pConn = NULL;
hr = GetSQLCache()->GetConnection(&pConn, FALSE, TRUE);
if (SUCCEEDED(hr))
{
ULONG uState = WBEM_TRANSACTION_STATE_EVENT_PLAYBACK;
pObj->WriteProp(L"State", 0, sizeof(ULONG), 1, CIM_UINT32, &uState);
_bstr_t sPath;
hr = PutObject(pConn, NULL, ROOTNAMESPACEID, L"", pObj, 0, NULL, sPath, NULL, FALSE);
// Commit the transaction in the database
// ======================================
if (SUCCEEDED(hr))
{
GetSQLCache()->FinalCommit(pConn);
GetSQLCache()->ReleaseConnection(pConn, hr, TRUE);
// Commit our events.
// ==================
hr = ((CWmiDbController *)m_pController)->ESSMgr.CommitAll(m_sGUID, m_sNamespacePath);
}
}
}
pHandle->Release();
}
CleanTransLocks();
m_sGUID = L"";
m_bIsDistributed = FALSE;
if (SUCCEEDED(hr))
{
// Transaction state = Completed
IWmiDbHandle *pHandle2 = NULL;
hr = GetObject_Internal(wPath, 0, WMIDB_HANDLE_TYPE_COOKIE, NULL, &pHandle2);
CReleaseMe r3 (pHandle2);
if (SUCCEEDED(hr))
{
_IWmiObject *pObj = NULL;
hr = pHandle2->QueryInterface(IID__IWmiObject, (void **)&pObj);
CReleaseMe r2 (pObj);
if (SUCCEEDED(hr))
{
CSQLConnection *pConn = NULL;
hr = GetSQLCache()->GetConnection(&pConn, FALSE, FALSE);
if (SUCCEEDED(hr))
{
ULONG uState = WBEM_TRANSACTION_STATE_COMPLETED;
pObj->WriteProp(L"State", 0, sizeof(ULONG), 1, CIM_UINT32, &uState);
_bstr_t sPath;
hr = PutObject(pConn, NULL, ROOTNAMESPACEID, L"", pObj, 0, NULL, sPath, NULL, FALSE);
GetSQLCache()->ReleaseConnection(pConn, hr);
}
}
}
}
UnlockDynasties();
return hr;
}
//***************************************************************************
//
// CWmiDbSession::QueryState
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiDbSession::QueryState(
/* [in] */ ULONG uFlags,
/* [out] */ ULONG __RPC_FAR *puState)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (m_sGUID.length() == 0)
return WBEM_E_INVALID_OPERATION;
if (!m_pController ||
((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
// This should be stored in the root namespace.
wchar_t wPath[255];
swprintf(wPath, L"__Transaction.GUID=\"%s\"", (LPWSTR)m_sGUID);
IWmiDbHandle *pHandle = NULL;
hr = GetObject_Internal(wPath, 0, WMIDB_HANDLE_TYPE_COOKIE, NULL, &pHandle);
CReleaseMe r1 (pHandle);
if (SUCCEEDED(hr))
{
_IWmiObject *pObj = NULL;
hr = pHandle->QueryInterface(IID__IWmiObject, (void **)&pObj);
CReleaseMe r2 (pObj);
if (SUCCEEDED(hr))
{
LPWSTR lpTemp = GetPropertyVal(L"State", pObj);
CDeleteMe <wchar_t> d (lpTemp);
*puState = _wtol(lpTemp);
//hr = pObj->ReadProp(L"State", 0, sizeof(ULONG), NULL,
// NULL, NULL, NULL, puState);
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::NormalizeObjectPathGet
//
//***************************************************************************
HRESULT CWmiDbSession::NormalizeObjectPathGet(IWmiDbHandle __RPC_FAR *pScope, IWbemPath __RPC_FAR *pPath,
LPWSTR * lpNewPath, BOOL *bDefault, SQL_ID *pClassId, SQL_ID *pScopeId, CSQLConnection *pConn)
{
HRESULT hr = WBEM_S_NO_ERROR;
BOOL bNs = FALSE;
BOOL bDone = FALSE;
LPWSTR lpTempPath = NULL;
BOOL bDelete = TRUE;
BOOL bIsRelative = TRUE;
SQL_ID dScopeId = 0;
if (pScope)
dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
// For retrieval behavior, we only want to know if
// the object is found in the default namespace
// or the custom repository.
if (bDefault)
*bDefault = TRUE;
if (!pPath)
hr = WBEM_E_INVALID_PARAMETER;
else
{
ULONGLONG uIsInstance = 0;
hr = pPath->GetInfo(0, &uIsInstance);
wchar_t wTemp[1];
DWORD dwLen = 1;
if (!(uIsInstance & WBEMPATH_INFO_IS_PARENT))
{
pPath->GetText(WBEMPATH_GET_ORIGINAL, &dwLen, wTemp);
if (dwLen)
{
dwLen += 1024;
lpTempPath = new wchar_t [dwLen];
if (lpTempPath)
hr = pPath->GetText(WBEMPATH_GET_ORIGINAL, &dwLen, lpTempPath);
else
{
hr = WBEM_E_OUT_OF_MEMORY;
goto Exit;
}
}
}
else
{
lpTempPath = new wchar_t [4096];
if (!lpTempPath)
{
hr = WBEM_E_OUT_OF_MEMORY;
goto Exit;
}
}
// First, are we just asking to find the current parent.
// Special case.
if (!(uIsInstance & WBEMPATH_INFO_IS_PARENT) && !wcslen(lpTempPath))
{
hr = WBEM_E_INVALID_PARAMETER;
goto Exit;
}
if (SUCCEEDED(hr))
{
if (uIsInstance & WBEMPATH_INFO_IS_PARENT)
{
if (bDefault)
*bDefault = TRUE;
if (lpNewPath)
{
wcscpy(lpTempPath, L"..");
*lpNewPath = lpTempPath;
bDelete = FALSE;
}
}
// This must be a path to an object.
else
{
wchar_t wServer[128];
ULONG uLen = 128;
hr = pPath->GetServer(&uLen, wServer);
if (SUCCEEDED(hr) && wcslen(wServer) > 1)
bIsRelative = FALSE;
SQL_ID dClassId = 0;
WCHAR *pClass = new wchar_t [512];
if (!pClass)
hr = WBEM_E_OUT_OF_MEMORY;
else
{
DWORD dwLen = 1024;
hr = pPath->GetClassName(&dwLen, pClass);
if (FAILED(hr))
{
delete pClass;
pClass = NULL;
}
CDeleteMe <wchar_t> r0 (pClass);
// We have a valid path (we hope).
// Go through each namespace and scope
// until we have hit the instance or class.
ULONG dwNumNamespaces = 0, dwNumScopes = 0;
wchar_t wBuff[1024];
BOOL bNeedSlash = FALSE;
pPath->GetNamespaceCount(&dwNumNamespaces);
pPath->GetScopeCount(&dwNumScopes);
lpTempPath[0] = L'\0';
// Process the namespaces.
for (ULONG i = 0; i < dwNumNamespaces; i++)
{
dwLen = 1024;
hr = pPath->GetNamespaceAt(i, &dwLen, wBuff);
if (SUCCEEDED(hr))
{
if (bNeedSlash)
wcscat(lpTempPath, L"\\");
else
bNeedSlash = TRUE;
wcscat(lpTempPath, wBuff);
if (!_wcsicmp(lpTempPath, m_sNamespacePath))
{
bNeedSlash = FALSE;
lpTempPath[0] = L'\0';
}
}
}
if (wcslen(lpTempPath))
{
LPWSTR lpKey = GetKeyString(lpTempPath);
CDeleteMe <wchar_t> r2 (lpKey);
if (!lpKey || !wcslen(lpKey))
{
ERRORTRACE((LOG_WBEMCORE, "Invalid scope text in CWmiDbSession::NormalizeObjectPathGet (%S) \n", lpTempPath));
hr = WBEM_E_INVALID_PARAMETER;
goto Exit;
}
hr = GetSchemaCache()->GetNamespaceID(lpKey, dScopeId);
if (FAILED(hr))
goto Exit;
}
// Process scopes.
if (dwNumScopes)
dwNumScopes--;
for ( i = 0; i < dwNumScopes; i++)
{
dwLen = 1024;
IWbemPathKeyList *pScopeKeys = NULL;
hr = pPath->GetScope(i, &dwLen, wBuff, &pScopeKeys);
if (SUCCEEDED(hr))
{
if (bNeedSlash)
wcscat(lpTempPath, L":");
else
bNeedSlash = TRUE;
LoadClassInfo(pConn, wBuff, dScopeId, TRUE);
LPWSTR lpTemp = GetSchemaCache()->GetKeyRoot(wBuff, dScopeId);
CDeleteMe <wchar_t> d (lpTemp);
if (lpTemp)
{
wcscat(lpTempPath, lpTemp);
}
else
wcscat(lpTempPath, wBuff); // OK.. Could be a remote path
hr = MakeKeyListString(dScopeId, &((CWmiDbController *)m_pController)->SchemaCache,
wBuff, pScopeKeys, lpTempPath);
}
}
if (wcslen(lpTempPath))
{
LPWSTR lpKey = GetKeyString(lpTempPath);
CDeleteMe <wchar_t> r2 (lpKey);
if (!lpKey || !wcslen(lpKey))
{
ERRORTRACE((LOG_WBEMCORE, "Invalid scope text in CWmiDbSession::NormalizeObjectPathGet (%S) \n", lpTempPath));
hr = WBEM_E_INVALID_PARAMETER;
goto Exit;
}
hr = GetSchemaCache()->GetNamespaceID(lpKey, dScopeId);
if (FAILED(hr))
goto Exit;
}
if (pClass && wcslen(pClass))
{
BOOL bDeep = (uIsInstance & WBEMPATH_INFO_IS_INST_REF);
// Make sure this dynasty is in the cache.
LoadClassInfo(pConn, pClass, dScopeId, bDeep);
// If this is a class or instance, process the data
hr = GetSchemaCache()->GetClassID (pClass,
dScopeId, dClassId);
if (SUCCEEDED(hr) && pClass)
{
IWbemPathKeyList *pKeyList = NULL;
if (dClassId == INSTANCESCLASSID &&
(uIsInstance & WBEMPATH_INFO_IS_INST_REF))
{
if (lpNewPath)
{
dwLen = 1024;
hr = pPath->GetKeyList(&pKeyList);
CReleaseMe r (pKeyList);
hr = pKeyList->GetKey(0, 0, NULL, NULL, &dwLen, lpTempPath, NULL);
*lpNewPath = lpTempPath;
bDelete = FALSE;
bDone = TRUE;
}
}
else
{
// If they specified a path like '__Namespace="root" '...
if ((!_wcsicmp(pClass, L"__Namespace") ||
GetSchemaCache()->IsDerivedClass(NAMESPACECLASSID, dClassId))
&& (uIsInstance & WBEMPATH_INFO_IS_INST_REF))
{
bNs = TRUE;
hr = pPath->GetKeyList(&pKeyList);
CReleaseMe r (pKeyList);
if (SUCCEEDED(hr))
{
dwLen = 1024;
hr = pKeyList->GetKey(0, 0, NULL, NULL, &dwLen, lpTempPath, NULL);
}
}
else
{
if (bNeedSlash)
wcscat(lpTempPath, L":");
if (uIsInstance & WBEMPATH_INFO_IS_CLASS_REF)
wcscat(lpTempPath, pClass);
else
{
LPWSTR lpTemp = GetSchemaCache()->GetKeyRoot(pClass, dScopeId);
CDeleteMe <wchar_t> d (lpTemp);
if (lpTemp)
wcscat(lpTempPath, lpTemp);
else
{
hr = WBEM_E_INVALID_OBJECT_PATH;
goto Exit;
}
}
if (uIsInstance & WBEMPATH_INFO_IS_CLASS_REF && wcslen(pClass) > 2 && pClass[0] == L'_' && pClass[1] == L'_')
{
*lpNewPath = lpTempPath;
bDelete = FALSE;
bDone = TRUE;
}
else if (uIsInstance & WBEMPATH_INFO_IS_INST_REF)
{
hr = pPath->GetKeyList(&pKeyList);
CReleaseMe r (pKeyList);
if (SUCCEEDED(hr))
{
hr = MakeKeyListString(dScopeId, &((CWmiDbController *)m_pController)->SchemaCache,
pClass, pKeyList, lpTempPath);
}
if (bDefault)
{
// Instances of system classes are always default
// Other instances are whatever their scope is.
if (wcslen(pClass) >= 2 && pClass[0] == L'_' && pClass[1] == L'_')
*bDefault = TRUE; // all system classes are default
else if (pScope) // other instances inherit from the scope.
*bDefault = ((CWmiDbHandle *)pScope)->m_bDefault;
}
}
}
}
}
else
{
if (uIsInstance & WBEMPATH_INFO_IS_INST_REF)
{
IWbemPathKeyList *pKeyList = NULL;
hr = pPath->GetKeyList(&pKeyList);
CReleaseMe rm1(pKeyList);
if (SUCCEEDED(hr))
{
ULONG uNumKeys = 0;
hr = pKeyList->GetCount(&uNumKeys);
if (SUCCEEDED(hr))
{
if (!uNumKeys)
bNs = TRUE;
}
}
else
bNs = TRUE;
}
else
bNs = TRUE;
if (bNs)
{
if (!wcslen(lpTempPath) && pClass)
wcscpy(lpTempPath, pClass);
}
else
hr = WBEM_E_NOT_FOUND;
}
}
else
bNs = TRUE;
if (bNs)
{
// This is a namespace.
dClassId = NAMESPACECLASSID;
hr = WBEM_S_NO_ERROR;
}
if (dClassId == INSTANCESCLASSID)
bDone = TRUE;
if (SUCCEEDED(hr) && !bDone)
{
hr = NormalizeObjectPath(pScope, lpTempPath, lpNewPath, bNs, NULL, NULL, pConn, TRUE);
bDelete = TRUE;
}
else if (SUCCEEDED(hr))
{
*lpNewPath = lpTempPath;
bDelete = FALSE;
}
if (pClassId)
*pClassId = dClassId;
if (pScopeId)
*pScopeId = dScopeId;
}
}
}
}
Exit:
if (bDelete || FAILED(hr))
delete lpTempPath;
return hr;
}
//***************************************************************************
//
// CWmiDbSession::NormalizeObjectPath
//
//***************************************************************************
HRESULT CWmiDbSession::NormalizeObjectPath(IWmiDbHandle __RPC_FAR *pScope, LPCWSTR lpPath, LPWSTR * lpNewPath,
BOOL bNamespace, CWbemClassObjectProps **ppProps, BOOL *bDefault,
CSQLConnection *pConn, BOOL bNoTrunc)
{
HRESULT hr = WBEM_S_NO_ERROR;
IWbemClassObject *pScObj = NULL;
// For other behavior, we are interested if the
// object is part of a custom mapping.
// Don't use our default phony namespace.
if (pScope && ((CWmiDbHandle *)pScope)->m_dObjectId != ROOTNAMESPACEID)
{
DWORD dwTempHandle = ((CWmiDbHandle *)pScope)->m_dwHandleType;
((CWmiDbHandle *)pScope)->m_dwHandleType |= WMIDB_HANDLE_TYPE_STRONG_CACHE;
LoadClassInfo(pConn, ((CWmiDbHandle *)pScope)->m_dClassId, FALSE);
hr = ((CWmiDbHandle *)pScope)->QueryInterface_Internal(pConn, (void **)&pScObj);
((CWmiDbHandle *)pScope)->m_dwHandleType = dwTempHandle;
}
CReleaseMe r (pScObj);
if (SUCCEEDED(hr))
hr = NormalizeObjectPath(pScObj, pScope, lpPath, lpNewPath, bNamespace, ppProps, bDefault, bNoTrunc);
return hr;
}
//***************************************************************************
//
// CWmiDbSession::NormalizeObjectPath
//
//***************************************************************************
HRESULT CWmiDbSession::NormalizeObjectPath(IWbemClassObject __RPC_FAR *pScope, IWmiDbHandle *pScope2, LPCWSTR lpPath, LPWSTR * lpNewPath,
BOOL bNamespace, CWbemClassObjectProps **ppProps,
BOOL *bDefault, BOOL bNoTrunc)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(GetCS());
int iSize = 0;
if (lpPath)
iSize += wcslen(lpPath);
iSize += m_sNamespacePath.length();
LPWSTR lpTemp = NULL;
// Don't add our phony namespace to the path.
if (pScope)
{
CWbemClassObjectProps *pProps = new CWbemClassObjectProps(this, NULL, pScope,
&((CWmiDbController *)m_pController)->SchemaCache, ((CWmiDbHandle *)pScope2)->m_dScopeId);
// Next, *undecorate* it. See if the front
// matches the default stuff, and if so, strip it off.
// If it doesn't this is an invalid decoration.
if (pProps)
{
if (pProps->lpRelPath)
iSize += wcslen(pProps->lpRelPath);
iSize += 50;
if (pProps->lpNamespace)
iSize += wcslen(pProps->lpNamespace)+1;
lpTemp = new wchar_t [iSize]; // Save this pointer, since we are assigning it to the return value.
if (lpTemp)
{
wcscpy(lpTemp,L"");
if (pProps->lpNamespace)
{
int iLen = wcslen(m_sNamespacePath);
if (!_wcsnicmp(pProps->lpNamespace, (const wchar_t*)m_sNamespacePath, iLen))
{
if (wcslen(pProps->lpNamespace) == iLen)
{
wcscpy(pProps->lpNamespace, L"");
}
else
{
wchar_t *wTmp = new wchar_t [wcslen(pProps->lpNamespace) + 1];
if (wTmp)
{
CDeleteMe <wchar_t> r (wTmp);
wcscpy(wTmp, pProps->lpNamespace);
LPWSTR lpTmp = wTmp + iLen + 1;
wcscpy(lpTemp, lpTmp);
if (ppProps)
{
delete pProps->lpNamespace;
pProps->lpNamespace = new wchar_t [wcslen(lpTemp)+1];
if (pProps->lpNamespace)
wcscpy(pProps->lpNamespace, lpTemp);
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
hr = WBEM_E_INVALID_NAMESPACE;
}
if (SUCCEEDED(hr))
{
SQL_ID dClassId = 0;
GetSchemaCache()->GetClassID (pProps->lpClassName,
((CWmiDbHandle *)pScope2)->m_dObjectId, dClassId);
if (!_wcsicmp(L"__Namespace", pProps->lpClassName) ||
GetSchemaCache()->IsDerivedClass(NAMESPACECLASSID, dClassId) )
{
VARIANT vTemp;
CClearMe v (&vTemp);
if (wcslen(lpTemp))
wcscat(lpTemp, L"\\");
pScope->Get(L"Name", 0, &vTemp, NULL, NULL);
if (vTemp.vt == VT_BSTR)
wcscat(lpTemp, vTemp.bstrVal);
}
else
{
if (wcslen(lpTemp))
wcscat(lpTemp, L":");
if (pProps->lpRelPath)
{
wcscat(lpTemp, pProps->lpRelPath);
}
else
hr = WBEM_E_INVALID_OBJECT;
}
if (lpPath != NULL)
{
int iLen = wcslen(lpTemp);
BOOL bAppend = TRUE;
if (!_wcsnicmp(lpPath, lpTemp, iLen))
{
int iLen2 = wcslen(lpPath);
if (iLen2 > iLen)
{
if (lpPath[iLen] == L':' ||
lpPath[iLen] == L'\\')
bAppend = FALSE;
}
else if (iLen2 == iLen)
bAppend = FALSE;
}
if (bAppend)
{
if (!bNamespace)
wcscat(lpTemp, L":");
else
wcscat(lpTemp, L"\\");
wcscat(lpTemp, lpPath);
}
else
wcscpy(lpTemp, lpPath);
}
}
if (SUCCEEDED(hr))
{
if (ppProps)
*ppProps = pProps;
else
delete pProps;
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
else
{
if (!lpPath)
iSize = 20;
lpTemp = new wchar_t [iSize];
if (lpTemp)
{
if (lpPath)
wcscpy(lpTemp, lpPath);
else
lpTemp[0] = L'\0';
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
if (SUCCEEDED(hr))
*lpNewPath = lpTemp;
else
delete lpTemp;
return hr;
}
//***************************************************************************
//
// CWmiDbSession::CleanCache
//
//***************************************************************************
HRESULT CWmiDbSession::CleanCache(SQL_ID dObjId, DWORD dwLockType, void *pObj)
{
HRESULT hr = WBEM_S_NO_ERROR;
hr = ((CWmiDbController *)m_pController)->LockCache.DeleteLock(dObjId, false, dwLockType, true, pObj);
if (SUCCEEDED(hr))
{
// Only remove this item from the cache
// if we deleted the object itself.
// ====================================
if (!dwLockType)
{
GetObjectCache()->DeleteObject(dObjId);
GetSchemaCache()->DeleteClass(dObjId);
GetSchemaCache()->DeleteNamespace(dObjId);
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::VerifyObjectLock
//
//***************************************************************************
HRESULT CWmiDbSession::VerifyObjectLock (SQL_ID dObjectId, DWORD dwType, DWORD dwVer)
{
HRESULT hr = WBEM_S_NO_ERROR;
DWORD dwLockType, dwVersion;
bool bImmediate = true;
if ((dwType & 0xF0000000) == WMIDB_HANDLE_TYPE_SUBSCOPED)
bImmediate = false;
hr = ((CWmiDbController *)m_pController)->LockCache.GetCurrentLock(dObjectId, bImmediate, dwLockType, &dwVersion);
if (SUCCEEDED(hr))
{
// This handle was invalidated by someone else.
if (!dwType)
hr = E_HANDLE;
// This is a versioned handle, which was out-of-date.
else if ((dwType & 0xF) == WMIDB_HANDLE_TYPE_VERSIONED)
{
if (dwVer < dwVersion)
hr = WBEM_E_HANDLE_OUT_OF_DATE;
}
// There is a lock outstanding which has precedence
// over this one.
if (((dwLockType & 0xF) == WMIDB_HANDLE_TYPE_PROTECTED ||
(dwLockType & 0xF) == WMIDB_HANDLE_TYPE_EXCLUSIVE) &&
((dwLockType & 0xF) != (dwType & 0xF)))
hr = WBEM_E_ACCESS_DENIED;
}
else
hr = 0;
return hr;
}
//***************************************************************************
//
// CWmiDbSession::ShutDown
//
//***************************************************************************
HRESULT CWmiDbSession::ShutDown ()
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(GetCS());
try
{
if (m_pController)
{
((CWmiDbController *)m_pController)->ReleaseSession(this);
m_pController->Release();
m_pController = NULL;
}
}
catch (...)
{
ERRORTRACE((LOG_WBEMCORE, "Fatal error in CWmiDbSession::ShutDown\n"));
hr = WBEM_E_CRITICAL_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::AddTransLock
//
//***************************************************************************
HRESULT CWmiDbSession::AddTransLock(SQL_ID dObjectId, DWORD dwHandleType)
{
HRESULT hr = WBEM_S_NO_ERROR;
SessionLock *pLock = new SessionLock;
if (pLock)
{
DWORD dwVersion = 0;
pLock->dObjectId = dObjectId;
pLock->dwHandleType = dwHandleType;
m_TransLocks.push_back(pLock);
}
else
hr = WBEM_E_OUT_OF_MEMORY;
return hr;
}
//***************************************************************************
//
// CWmiDbSession::CleanTransLocks
//
//***************************************************************************
HRESULT CWmiDbSession::CleanTransLocks()
{
HRESULT hr = WBEM_S_NO_ERROR;
for (int i = 0; i < m_TransLocks.size(); i++)
{
SessionLock *pLock = m_TransLocks.at(i);
if (pLock)
{
hr = ((CWmiDbController *)m_pController)->LockCache.DeleteLock(
pLock->dObjectId, false, pLock->dwHandleType);
}
}
m_TransLocks.clear();
return hr;
}
//***************************************************************************
//
// CWmiDbSession::LockExists
//
//***************************************************************************
BOOL CWmiDbSession::LockExists (SQL_ID dObjId)
{
BOOL bRet = FALSE;
for (int i = 0; i < m_TransLocks.size(); i++)
{
SessionLock *pLock = m_TransLocks.at(i);
if (pLock)
{
if (pLock->dObjectId == dObjId)
{
bRet = TRUE;
break;
}
}
}
return bRet;
}
//***************************************************************************
//
// CWmiDbSession::UnlockDynasties
//
//***************************************************************************
HRESULT CWmiDbSession::UnlockDynasties(BOOL bDelete)
{
HRESULT hr = WBEM_S_NO_ERROR;
_WMILockit lkt(GetCS());
DWORD dwRefCount = Release_Lock();
if (!dwRefCount)
{
DWORD dwThread = GetCurrentThreadId();
SQLIDs *pIDs = &m_Dynasties[dwThread];
// Reference count per object (IWmiDbHandle, IWmiDbIterator)
// Backup fail-safe for handles and queries.
if (pIDs)
{
for (int i = 0; i < pIDs->size(); i++)
{
SQL_ID dClass = pIDs->at(i);
if (!bDelete)
GetSchemaCache()->UnlockDynasty(dClass);
else
GetSchemaCache()->DeleteDynasty(dClass);
}
pIDs->clear();
}
SessionDynasties::iterator it = m_Dynasties.find(dwThread);
if (it != m_Dynasties.end())
m_Dynasties.erase(it);
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::DeleteRows
//
//***************************************************************************
HRESULT CWmiDbSession::DeleteRows(IWmiDbHandle *pScope, IWmiDbIterator *pIterator, REFIID iid)
{
HRESULT hr = WBEM_S_NO_ERROR;
CFlexArray arrHandles;
IUnknown *pRet = NULL;
DWORD dwNumRet = 0;
// WARNING: This is NOT SCALABLE!!!!
// We're doing it this way because ESS expects
// an event to be fired for each result row of a
// delete query. This should be optimized by
// deleting all the results in one go, and notifying
// ESS that the class had some of its members deleted
HRESULT hRes = pIterator->NextBatch(1, 0, 0, WMIDB_HANDLE_TYPE_COOKIE,
iid, &dwNumRet, (void **)&pRet);
while (SUCCEEDED(hRes) && dwNumRet)
{
arrHandles.Add(pRet);
hRes = pIterator->NextBatch(1, 0, 0, WMIDB_HANDLE_TYPE_COOKIE,
iid, &dwNumRet, (void **)&pRet);
}
// When the iterator returns the last row,
// it will release the db connection
if (arrHandles.Size())
{
// Transact this operation so we don't fire events until
// all objects have been deleted.
int iPos = 0;
GUID transguid;
CoCreateGuid(&transguid);
hr = Begin(0, 0, &transguid);
if (SUCCEEDED(hr))
{
for (iPos = 0; iPos < arrHandles.Size(); iPos++)
{
IUnknown *pHandle = (IUnknown *)arrHandles.GetAt(iPos);
if (FAILED(hr = DeleteObject(pScope, 0, iid, (void *)pHandle)))
{
pHandle->Release();
break;
}
pHandle->Release();
}
}
if (SUCCEEDED(hr))
hr = Commit(0);
else
{
hr = Rollback(0);
// Clean up the handles that were left over.
for (int i = iPos+1; i < arrHandles.Size(); i++)
{
IUnknown *pHandle = (IUnknown *)arrHandles.GetAt(i);
pHandle->Release();
}
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::AddRef_Lock
//
//***************************************************************************
DWORD CWmiDbSession::AddRef_Lock()
{
DWORD dwThreadId = GetCurrentThreadId();
DWORD dwRefCount = m_ThreadRefCount[dwThreadId];
InterlockedIncrement((LONG *) &dwRefCount);
m_ThreadRefCount[dwThreadId] = dwRefCount;
return dwRefCount;
}
//***************************************************************************
//
// CWmiDbSession::Release_Lock
//
//***************************************************************************
DWORD CWmiDbSession::Release_Lock()
{
DWORD dwThreadId = GetCurrentThreadId();
DWORD dwRefCount = m_ThreadRefCount[dwThreadId];
if (dwRefCount > 0)
InterlockedDecrement((LONG *) &dwRefCount);
m_ThreadRefCount[dwThreadId] = dwRefCount;
return dwRefCount;
}