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.
1012 lines
28 KiB
1012 lines
28 KiB
/*++
|
|
|
|
Copyright (C) 2000-2001 Microsoft Corporation
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
#include <wbemcomn.h>
|
|
#include <ql.h>
|
|
#include <time.h>
|
|
#include "a51rep.h"
|
|
#include <md5.h>
|
|
#include <objpath.h>
|
|
#include "lock.h"
|
|
#include <persistcfg.h>
|
|
#include "a51fib.h"
|
|
#include "RepositoryPackager.h"
|
|
#include "Win9xSecurity.h"
|
|
#include <scopeguard.h>
|
|
#include <malloc.h>
|
|
#include "Upgrade.h"
|
|
|
|
#define A51REP_CACHE_FLUSH_TIMEOUT 60000
|
|
#define A51REP_THREAD_IDLE_TIMEOUT 60000
|
|
|
|
//Checkpoint timeout is how long between getting a write notification it takes
|
|
//before we commit all transactions
|
|
#define A51_WRITE_CHECKPOINT 7500
|
|
|
|
//Number of pages from each of the paged files to be moved from the end to a
|
|
//place earlier in the file
|
|
#define A51_WRITE_OPERATION_COMPACT 10
|
|
|
|
//
|
|
|
|
LONG g_RecoverFailureCnt[FailCntLast];
|
|
|
|
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CLock g_readWriteLock;
|
|
bool g_bShuttingDown = false;
|
|
CNamespaceHandle *g_pSystemClassNamespace = NULL;
|
|
DWORD g_dwOldRepositoryVersion = 0;
|
|
DWORD g_dwCurrentRepositoryVersion = 0;
|
|
DWORD g_dwSecTlsIndex = 0xFFFFFFFF ;
|
|
|
|
DWORD CRepository::m_ShutDownFlags = 0;
|
|
HANDLE CRepository::m_hShutdownEvent = 0;
|
|
HANDLE CRepository::m_hFlusherThread = 0;
|
|
LONG CRepository::m_ulReadCount = 0;
|
|
LONG CRepository::m_ulWriteCount = 0;
|
|
HANDLE CRepository::m_hWriteEvent = 0;
|
|
HANDLE CRepository::m_hReadEvent = 0;
|
|
int CRepository::m_threadState = CRepository::ThreadStateDead;
|
|
CStaticCritSec CRepository::m_cs;
|
|
LONG CRepository::m_threadCount = 0;
|
|
LONG CRepository::m_nFlushFailureCount = 0;
|
|
|
|
DWORD g_FileSD[] = {
|
|
0x80040001, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000014, 0x00340002, 0x00000002, 0x00140000,
|
|
FILE_ALL_ACCESS, 0x00000101, 0x05000000, 0x00000012,
|
|
0x00180000, FILE_ALL_ACCESS, 0x00000201, 0x05000000,
|
|
0x00000020, 0x00000220
|
|
};
|
|
|
|
SECURITY_ATTRIBUTES g_SA = {sizeof(SECURITY_ATTRIBUTES),g_FileSD,FALSE};
|
|
|
|
//*****************************************************************************
|
|
|
|
HRESULT CRepository::Initialize()
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
InitializeRepositoryVersions();
|
|
|
|
//
|
|
// Initialize time index
|
|
//
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
FILETIME ft;
|
|
GetSystemTimeAsFileTime(&ft);
|
|
|
|
g_nCurrentTime = ft.dwLowDateTime + ((__int64)ft.dwHighDateTime << 32);
|
|
}
|
|
|
|
//
|
|
// Get the repository directory
|
|
// sets g_Glob.GetRootDir()
|
|
//
|
|
if (SUCCEEDED(hRes))
|
|
hRes = GetRepositoryDirectory();
|
|
|
|
//Do the upgrade of the repository if necessary
|
|
if (SUCCEEDED(hRes))
|
|
hRes = UpgradeRepositoryFormat();
|
|
//
|
|
// initialze all our global resources
|
|
//
|
|
if (SUCCEEDED(hRes))
|
|
hRes = InitializeGlobalVariables();
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
long lRes;
|
|
if (ERROR_SUCCESS != (lRes = g_Glob.m_FileCache.Initialize(g_Glob.GetRootDir())))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "CFileCache::Initialize returned %x\n",lRes));
|
|
if (WBEM_E_FAILED == (hRes = A51TranslateErrorCode(lRes)))
|
|
hRes = WBEM_E_INITIALIZATION_FAILURE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize class cache. It will read the registry itself to find out
|
|
// its size limitations
|
|
//
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = g_Glob.Initialize();
|
|
if(hRes != S_OK)
|
|
{
|
|
hRes = WBEM_E_INITIALIZATION_FAILURE;
|
|
}
|
|
}
|
|
|
|
//If we need to create the system class namespace then go ahead and do that...
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
g_pSystemClassNamespace = new CNamespaceHandle(m_pControl, this);
|
|
if (g_pSystemClassNamespace == NULL)
|
|
{
|
|
hRes = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
g_pSystemClassNamespace->AddRef();
|
|
hRes = g_pSystemClassNamespace->Initialize(A51_SYSTEMCLASS_NS);
|
|
}
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
m_hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hWriteEvent == NULL)
|
|
hRes = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
m_hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hReadEvent == NULL)
|
|
hRes = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
m_hShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hShutdownEvent == NULL)
|
|
hRes = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
|
|
//We need to reset the shutting down flag as the flusher thread
|
|
//will not start without it. The problem is that the next 2
|
|
//operations (CreateSystemClasses and Import security do things
|
|
//that will re-create the thread even though we don't do it above
|
|
//
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
g_bShuttingDown = false;
|
|
}
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
CAutoWriteLock lock(&g_readWriteLock);
|
|
if (!lock.Lock())
|
|
hRes = WBEM_E_FAILED;
|
|
else
|
|
hRes = g_pSystemClassNamespace->CreateSystemClasses(m_aSystemClasses);
|
|
}
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
// import Win9x security data if necessary
|
|
CWin9xSecurity win9xSecurity(m_pControl, this);
|
|
if (win9xSecurity.Win9xBlobFileExists())
|
|
hRes = win9xSecurity.ImportWin9xSecurity();
|
|
}
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
CLocalizationUpgrade upgrade(m_pControl, this);
|
|
hRes = upgrade.DoUpgrade();
|
|
}
|
|
|
|
if (FAILED(hRes))
|
|
{
|
|
g_bShuttingDown = true; //Reset to true as we cleared it earlier!
|
|
g_Glob.m_FileCache.Uninitialize(0);
|
|
|
|
g_Glob.m_ForestCache.Deinitialize();
|
|
|
|
if (g_pSystemClassNamespace)
|
|
{
|
|
delete g_pSystemClassNamespace;
|
|
g_pSystemClassNamespace = NULL;
|
|
}
|
|
|
|
if (m_hWriteEvent != NULL)
|
|
{
|
|
CloseHandle(m_hWriteEvent);
|
|
m_hWriteEvent = NULL;
|
|
}
|
|
if (m_hReadEvent != NULL)
|
|
{
|
|
CloseHandle(m_hReadEvent);
|
|
m_hReadEvent = NULL;
|
|
}
|
|
if (m_hShutdownEvent != NULL)
|
|
{
|
|
CloseHandle(m_hShutdownEvent);
|
|
m_hShutdownEvent = NULL;
|
|
}
|
|
HANDLE hTmp = NULL;
|
|
if (hTmp = InterlockedCompareExchangePointer(&m_hFlusherThread,0,m_hFlusherThread))
|
|
{
|
|
CloseHandle(hTmp);
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT CRepository::InitializeRepositoryVersions()
|
|
{
|
|
DWORD dwVal = 0;
|
|
CPersistentConfig cfg;
|
|
cfg.GetPersistentCfgValue(PERSIST_CFGVAL_CORE_FSREP_VERSION, dwVal);
|
|
if (dwVal == 0)
|
|
dwVal = A51_REP_FS_VERSION;
|
|
|
|
g_dwOldRepositoryVersion = dwVal;
|
|
g_dwCurrentRepositoryVersion = A51_REP_FS_VERSION;
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
HRESULT CRepository::UpgradeRepositoryFormat()
|
|
{
|
|
HRESULT hRes = WBEM_E_DATABASE_VER_MISMATCH;
|
|
CPersistentConfig cfg;
|
|
DWORD dwVal = 0;
|
|
cfg.GetPersistentCfgValue(PERSIST_CFGVAL_CORE_FSREP_VERSION, dwVal);
|
|
|
|
if (dwVal == 0)
|
|
{
|
|
//
|
|
// First time --- write the right version in
|
|
//
|
|
hRes = WBEM_S_NO_ERROR;
|
|
|
|
cfg.SetPersistentCfgValue(PERSIST_CFGVAL_CORE_FSREP_VERSION,
|
|
A51_REP_FS_VERSION);
|
|
}
|
|
else if ((dwVal > 0) && (dwVal < 5))
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Repository cannot upgrade this version of the repository. Version found = <%ld>, version expected = <%ld>\n", dwVal, A51_REP_FS_VERSION ));
|
|
hRes = WBEM_E_DATABASE_VER_MISMATCH;
|
|
}
|
|
else if (dwVal == 5)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE, "Repository does not support upgrade from version 5. We are deleting the old version and re-initializing it. Version found = <%ld>, version expected = <%ld>\n", dwVal, A51_REP_FS_VERSION ));
|
|
//Need to delete the old repostiory
|
|
CFileName fn;
|
|
if (fn == NULL)
|
|
hRes = WBEM_E_OUT_OF_MEMORY;
|
|
else
|
|
{
|
|
StringCchCopyW(fn, fn.Length(), g_Glob.GetRootDir());
|
|
StringCchCatW(fn, fn.Length(), L"\\index.btr");
|
|
DeleteFileW(fn);
|
|
StringCchCopyW(fn, fn.Length(), g_Glob.GetRootDir());
|
|
StringCchCatW(fn, fn.Length(), L"\\lowstage.dat");
|
|
DeleteFileW(fn);
|
|
StringCchCopyW(fn, fn.Length(), g_Glob.GetRootDir());
|
|
StringCchCatW(fn, fn.Length(), L"\\objheap.fre");
|
|
DeleteFileW(fn);
|
|
StringCchCopyW(fn, fn.Length(), g_Glob.GetRootDir());
|
|
StringCchCatW(fn, fn.Length(), L"\\objheap.hea");
|
|
DeleteFileW(fn);
|
|
|
|
cfg.SetPersistentCfgValue(PERSIST_CFGVAL_CORE_FSREP_VERSION, A51_REP_FS_VERSION);
|
|
hRes = WBEM_S_NO_ERROR;
|
|
}
|
|
}
|
|
else if (dwVal == 6)
|
|
{
|
|
//We need to run a Locale Upgrade on the repository... but we do nothing now!
|
|
hRes = WBEM_S_NO_ERROR;
|
|
}
|
|
else if (dwVal == A51_REP_FS_VERSION)
|
|
hRes = WBEM_S_NO_ERROR;
|
|
|
|
if (hRes == WBEM_E_DATABASE_VER_MISMATCH)
|
|
{
|
|
//
|
|
// Unsupported version
|
|
//
|
|
|
|
ERRORTRACE((LOG_WBEMCORE, "Repository cannot initialize "
|
|
"due to the detection of an unknown repository version. Version found = <%ld>, version expected = <%ld>\n", dwVal, A51_REP_FS_VERSION ));
|
|
return WBEM_E_DATABASE_VER_MISMATCH;
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
|
|
HRESULT CRepository::GetRepositoryDirectory()
|
|
{
|
|
HKEY hKey;
|
|
long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
|
|
0, KEY_READ, &hKey);
|
|
if(lRes)
|
|
return WBEM_E_FAILED;
|
|
|
|
CFileName wszTmp;
|
|
if (wszTmp == NULL)
|
|
{
|
|
RegCloseKey(hKey);
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
DWORD dwLen = wszTmp.Length() * sizeof(wchar_t);
|
|
lRes = RegQueryValueExW(hKey, L"Repository Directory", NULL, NULL,
|
|
(LPBYTE)(wchar_t*)wszTmp, &dwLen);
|
|
RegCloseKey(hKey);
|
|
if(lRes)
|
|
return WBEM_E_FAILED;
|
|
|
|
CFileName wszRepDir;
|
|
if (wszRepDir == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
if (ExpandEnvironmentStringsW(wszTmp,wszRepDir,wszTmp.Length()) == 0)
|
|
return WBEM_E_FAILED;
|
|
|
|
|
|
lRes = EnsureDirectory(wszRepDir);
|
|
if(lRes != ERROR_SUCCESS)
|
|
return WBEM_E_FAILED;
|
|
|
|
//
|
|
// Append standard postfix --- that is our root
|
|
//
|
|
StringCchCopyW(g_Glob.GetRootDir(), MAX_PATH, wszRepDir);
|
|
StringCchCatW(g_Glob.GetRootDir(), MAX_PATH, L"\\FS");
|
|
g_Glob.SetRootDirLen(wcslen(g_Glob.GetRootDir()));
|
|
|
|
//
|
|
// Ensure the directory is there
|
|
//
|
|
|
|
lRes = EnsureDirectory(g_Glob.GetRootDir());
|
|
if(lRes != ERROR_SUCCESS)
|
|
return WBEM_E_FAILED;
|
|
|
|
SetFileAttributesW(g_Glob.GetRootDir(), FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
HRESULT CRepository::InitializeGlobalVariables()
|
|
{
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
HRESULT DoAutoDatabaseRestore()
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
//We may need to do a database restore!
|
|
CFileName wszBackupFile;
|
|
if (wszBackupFile == NULL)
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
int nLen = g_Glob.GetRootDirLen();
|
|
|
|
StringCchCopyNW(wszBackupFile, wszBackupFile.Length(), g_Glob.GetRootDir(), nLen - 3); // exclude "\FS" from path
|
|
wszBackupFile[nLen - 3] = '\0';
|
|
StringCchCatW(wszBackupFile, wszBackupFile.Length(), L"\\repdrvfs.rec");
|
|
|
|
DWORD dwAttributes = GetFileAttributesW(wszBackupFile);
|
|
if (dwAttributes != -1)
|
|
{
|
|
DWORD dwMask = FILE_ATTRIBUTE_DEVICE |
|
|
FILE_ATTRIBUTE_DIRECTORY |
|
|
FILE_ATTRIBUTE_OFFLINE |
|
|
FILE_ATTRIBUTE_REPARSE_POINT |
|
|
FILE_ATTRIBUTE_SPARSE_FILE;
|
|
|
|
if (!(dwAttributes & dwMask))
|
|
{
|
|
CRepositoryPackager packager;
|
|
hRes = packager.UnpackageRepository(wszBackupFile);
|
|
|
|
//We are going to ignore the error so if there was a problem we will just
|
|
//load all the standard MOFs.
|
|
//WHY OH WHY WAS THIS PUT HERE? IT BREAKS BACKUP/RESTORE FUNCTIONALIUTY BECAUSE
|
|
//WE GET NO ERROR CODES PROPAGATED BACK!
|
|
//if (hRes != WBEM_E_OUT_OF_MEMORY)
|
|
// hRes = WBEM_S_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CRepository::Logon(
|
|
WMIDB_LOGON_TEMPLATE *pLogonParms,
|
|
DWORD dwFlags,
|
|
DWORD dwRequestedHandleType,
|
|
IWmiDbSession **ppSession,
|
|
IWmiDbHandle **ppRootNamespace
|
|
)
|
|
{
|
|
//
|
|
// Get the SecFlag TLS index from the logon parameters. Store this away in global
|
|
// g_dwSecTlsIndex
|
|
//
|
|
if ( pLogonParms == NULL )
|
|
{
|
|
return WBEM_E_FAILED ;
|
|
}
|
|
else if ( g_dwSecTlsIndex == -1 )
|
|
{
|
|
g_dwSecTlsIndex = (DWORD)V_I4(&pLogonParms->pParm->Value) ;
|
|
}
|
|
|
|
//If not initialized, initialize all subsystems...
|
|
if (!g_Glob.IsInit())
|
|
{
|
|
HRESULT hres = Initialize();
|
|
if (FAILED(hres))
|
|
return hres;
|
|
}
|
|
|
|
CSession* pSession = new CSession(m_pControl);
|
|
if (pSession == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
pSession->AddRef();
|
|
CReleaseMe rm1(pSession);
|
|
|
|
CNamespaceHandle* pHandle = new CNamespaceHandle(m_pControl, this);
|
|
if (pHandle == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
pHandle->AddRef();
|
|
CTemplateReleaseMe<CNamespaceHandle> rm2(pHandle);
|
|
|
|
HRESULT hres = pHandle->Initialize(L"");
|
|
if(FAILED(hres))
|
|
return hres;
|
|
|
|
*ppRootNamespace = pHandle;
|
|
pHandle->AddRef();
|
|
*ppSession = pSession;
|
|
pSession->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CRepository::GetLogonTemplate(
|
|
LCID lLocale,
|
|
DWORD dwFlags,
|
|
WMIDB_LOGON_TEMPLATE **ppLogonTemplate
|
|
)
|
|
{
|
|
WMIDB_LOGON_TEMPLATE* lt = (WMIDB_LOGON_TEMPLATE*)CoTaskMemAlloc(sizeof(WMIDB_LOGON_TEMPLATE));
|
|
WMIDB_LOGON_PARAMETER* lp = (WMIDB_LOGON_PARAMETER*) CoTaskMemAlloc(sizeof(WMIDB_LOGON_PARAMETER));
|
|
|
|
if ((lt == 0) || (lp == 0))
|
|
{
|
|
CoTaskMemFree(lt);
|
|
CoTaskMemFree(lp);
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
VARIANT v ;
|
|
VariantInit ( &v ) ;
|
|
lp->Value = v ;
|
|
|
|
lt->dwArraySize = 1;
|
|
lt->pParm = lp ;
|
|
|
|
*ppLogonTemplate = lt;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CRepository::FreeLogonTemplate(
|
|
WMIDB_LOGON_TEMPLATE **ppTemplate
|
|
)
|
|
{
|
|
WMIDB_LOGON_TEMPLATE* pTemp = *ppTemplate ;
|
|
WMIDB_LOGON_PARAMETER* pParam = pTemp->pParm ;
|
|
VariantClear ( &(pParam->Value) );
|
|
|
|
CoTaskMemFree((*ppTemplate)->pParm);
|
|
CoTaskMemFree(*ppTemplate);
|
|
*ppTemplate = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CRepository::Shutdown(
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
g_bShuttingDown = true;
|
|
m_ShutDownFlags = dwFlags;
|
|
|
|
//Trigger the flusher thread to shutdown
|
|
SetEvent(m_hShutdownEvent);
|
|
SetEvent(m_hWriteEvent);
|
|
|
|
if (m_hFlusherThread)
|
|
WaitForSingleObject(m_hFlusherThread, INFINITE);
|
|
|
|
bool bUnlock = (CLock::NoError == g_readWriteLock.WriteLock());
|
|
|
|
//Mark thread as dead
|
|
m_threadState = ThreadStateDead;
|
|
|
|
if (WMIDB_SHUTDOWN_MACHINE_DOWN != dwFlags)
|
|
{
|
|
if (g_pSystemClassNamespace)
|
|
g_pSystemClassNamespace->Release();
|
|
g_pSystemClassNamespace = NULL;
|
|
|
|
g_Glob.m_ForestCache.Deinitialize();
|
|
}
|
|
|
|
g_Glob.m_FileCache.Flush(false);
|
|
|
|
g_Glob.m_FileCache.Uninitialize(dwFlags);
|
|
|
|
|
|
if (WMIDB_SHUTDOWN_MACHINE_DOWN != dwFlags)
|
|
{
|
|
g_Glob.Deinitialize();
|
|
if (bUnlock)
|
|
g_readWriteLock.WriteUnlock();
|
|
}
|
|
|
|
if (m_hShutdownEvent != NULL)
|
|
{
|
|
CloseHandle(m_hShutdownEvent);
|
|
m_hShutdownEvent = NULL;
|
|
}
|
|
if (m_hWriteEvent != NULL)
|
|
{
|
|
CloseHandle(m_hWriteEvent);
|
|
m_hWriteEvent = NULL;
|
|
}
|
|
if (m_hReadEvent != NULL)
|
|
{
|
|
CloseHandle(m_hReadEvent);
|
|
m_hReadEvent = NULL;
|
|
}
|
|
HANDLE hTmp = NULL;
|
|
if (hTmp = InterlockedCompareExchangePointer(&m_hFlusherThread,0,m_hFlusherThread))
|
|
{
|
|
CloseHandle(hTmp);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CRepository::SetCallTimeout(
|
|
DWORD dwMaxTimeout
|
|
)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CRepository::SetCacheValue(
|
|
DWORD dwMaxBytes
|
|
)
|
|
{
|
|
HKEY hKey;
|
|
long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
|
|
0, KEY_READ | KEY_WRITE, &hKey);
|
|
if(lRes)
|
|
return lRes;
|
|
CRegCloseMe cm(hKey);
|
|
DWORD dwLen = sizeof(DWORD);
|
|
DWORD dwMaxAge;
|
|
lRes = RegQueryValueExW(hKey, L"Max Class Cache Item Age (ms)", NULL, NULL,
|
|
(LPBYTE)&dwMaxAge, &dwLen);
|
|
|
|
if(lRes != ERROR_SUCCESS)
|
|
{
|
|
dwMaxAge = 10000;
|
|
lRes = RegSetValueExW(hKey, L"Max Class Cache Item Age (ms)", 0,
|
|
REG_DWORD, (LPBYTE)&dwMaxAge, sizeof(DWORD));
|
|
}
|
|
g_Glob.m_ForestCache.SetMaxMemory(dwMaxBytes, dwMaxAge);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CRepository::FlushCache(
|
|
DWORD dwFlags
|
|
)
|
|
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CRepository::GetStatistics(
|
|
DWORD dwParameter,
|
|
DWORD *pdwValue
|
|
)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CRepository::GetRepositoryVersions(DWORD *pdwOldVersion,
|
|
DWORD *pdwCurrentVersion)
|
|
{
|
|
*pdwOldVersion = g_dwOldRepositoryVersion;
|
|
*pdwCurrentVersion = g_dwCurrentRepositoryVersion;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CRepository::GetNamespaceHandle(LPCWSTR wszNamespaceName,
|
|
RELEASE_ME CNamespaceHandle** ppHandle)
|
|
{
|
|
HRESULT hres;
|
|
|
|
//
|
|
// No validation --- that would be too hard. Just create a handle and
|
|
// return
|
|
//
|
|
|
|
CNamespaceHandle* pNewHandle = new CNamespaceHandle(m_pControl, this);
|
|
if (pNewHandle == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
pNewHandle->AddRef();
|
|
CReleaseMe rm1(pNewHandle);
|
|
|
|
hres = pNewHandle->Initialize(wszNamespaceName);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
|
|
*ppHandle = pNewHandle;
|
|
pNewHandle->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CRepository::Backup(LPCWSTR wszBackupFile, long lFlags)
|
|
{
|
|
TIMETRACEBACKUP;
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
// params have already been verified by the calling method (CWbemBackupRestore::DoBackup),
|
|
// but do it again just in case things change and this is no longer the case
|
|
if (NULL == wszBackupFile || (lFlags != 0))
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
|
|
if (FAILED(hRes = LockRepository()))
|
|
return hRes;
|
|
|
|
CRepositoryPackager packager;
|
|
hRes = packager.PackageRepository(wszBackupFile);
|
|
|
|
UnlockRepository();
|
|
|
|
return hRes;
|
|
}
|
|
HRESULT CRepository::Restore(LPCWSTR wszBackupFile, long lFlags)
|
|
{
|
|
return WBEM_E_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
#define MaxTraceSizeBackup (11)
|
|
|
|
struct BackUpTraces {
|
|
DWORD ThreadId;
|
|
PVOID Trace[MaxTraceSizeBackup];
|
|
} g_Backup[2];
|
|
|
|
LONG g_NumTimes;
|
|
|
|
HRESULT CRepository::LockRepository()
|
|
{
|
|
#ifdef _X86_
|
|
DWORD * pDW = (DWORD *)_alloca(sizeof(DWORD));
|
|
#endif
|
|
//Lock the database so no one writes to it
|
|
if (CLock::NoError != g_readWriteLock.WriteLock())
|
|
return WBEM_E_FAILED;
|
|
|
|
ScopeGuard lockGuard = MakeObjGuard(g_readWriteLock, &CLock::WriteUnlock);
|
|
|
|
if (g_bShuttingDown)
|
|
{
|
|
return WBEM_E_SHUTTING_DOWN;
|
|
}
|
|
|
|
InterlockedIncrement(&g_NumTimes);
|
|
g_Backup[0].ThreadId = GetCurrentThreadId();
|
|
ULONG Hash;
|
|
RtlCaptureStackBackTrace(0,MaxTraceSizeBackup,g_Backup[0].Trace,&Hash);
|
|
g_Backup[1].ThreadId = 0;
|
|
|
|
//We need to wait for the transaction manager write to flush...
|
|
long lRes = g_Glob.m_FileCache.Flush(false);
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
if (CLock::NoError != g_readWriteLock.DowngradeLock())
|
|
return WBEM_E_FAILED;
|
|
|
|
lockGuard.Dismiss();
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
HRESULT CRepository::UnlockRepository()
|
|
{
|
|
#ifdef _X86_
|
|
DWORD * pDW = (DWORD *)_alloca(sizeof(DWORD));
|
|
#endif
|
|
g_readWriteLock.ReadUnlock();
|
|
|
|
InterlockedDecrement(&g_NumTimes);
|
|
g_Backup[1].ThreadId = GetCurrentThreadId();
|
|
ULONG Hash;
|
|
RtlCaptureStackBackTrace(0,MaxTraceSizeBackup,g_Backup[1].Trace,&Hash);
|
|
g_Backup[0].ThreadId = 0;
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
DWORD WINAPI CRepository::_FlusherThread(void *)
|
|
{
|
|
// ERRORTRACE((LOG_REPDRV, "Flusher thread stated, thread = %lu\n", GetCurrentThreadId()));
|
|
InterlockedIncrement(&m_threadCount);
|
|
|
|
HANDLE aHandles[2];
|
|
aHandles[0] = m_hWriteEvent;
|
|
aHandles[1] = m_hReadEvent;
|
|
|
|
DWORD dwTimeout = INFINITE;
|
|
LONG ulPreviousReadCount = m_ulReadCount;
|
|
LONG ulPreviousWriteCount = m_ulWriteCount;
|
|
bool bShutdownThread = false;
|
|
|
|
while (!g_bShuttingDown && !bShutdownThread)
|
|
{
|
|
DWORD dwRet = WaitForMultipleObjects(2, aHandles, FALSE, dwTimeout);
|
|
|
|
switch(dwRet)
|
|
{
|
|
case WAIT_OBJECT_0: //Write event
|
|
{
|
|
dwRet = WaitForSingleObject(m_hShutdownEvent, A51_WRITE_CHECKPOINT);
|
|
switch (dwRet)
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
break; //Shutting down, we cannot grab the lock so let the
|
|
//initiator of shutdown do the flush for us
|
|
case WAIT_TIMEOUT:
|
|
{
|
|
//We need to do a flush... either shutting down or idle
|
|
CAutoWriteLock lock(&g_readWriteLock);
|
|
if (lock.Lock())
|
|
{
|
|
long lResInner;
|
|
if (NO_ERROR != (lResInner = g_Glob.m_FileCache.Flush(true)))
|
|
{
|
|
//Flush failed, so we need to retry in a little while!
|
|
SetEvent(m_hWriteEvent);
|
|
m_nFlushFailureCount++;
|
|
}
|
|
else
|
|
m_nFlushFailureCount = 0;
|
|
}
|
|
break;
|
|
}
|
|
case WAIT_FAILED:
|
|
break;
|
|
}
|
|
|
|
//Transition to flush mode
|
|
dwTimeout = A51REP_CACHE_FLUSH_TIMEOUT;
|
|
ulPreviousReadCount = m_ulReadCount;
|
|
m_threadState = ThreadStateFlush;
|
|
break;
|
|
}
|
|
|
|
case WAIT_OBJECT_0+1: //Read event
|
|
//Reset the flush mode as read happened
|
|
dwTimeout = A51REP_CACHE_FLUSH_TIMEOUT;
|
|
ulPreviousReadCount = m_ulReadCount;
|
|
m_threadState = ThreadStateFlush;
|
|
break;
|
|
|
|
case WAIT_TIMEOUT: //Timeout, so flush caches
|
|
{
|
|
//Check for if we are in an idle shutdown state...
|
|
m_cs.Enter();
|
|
if (m_threadState == ThreadStateIdle)
|
|
{
|
|
m_threadState = ThreadStateDead;
|
|
bShutdownThread = true;
|
|
// since we are setting the status to "dead", decrement also the thread counter
|
|
InterlockedDecrement(&m_threadCount);
|
|
}
|
|
m_cs.Leave();
|
|
|
|
if (bShutdownThread)
|
|
break;
|
|
|
|
//Not thread shutdown, so we check for cache flush
|
|
if (ulPreviousReadCount == m_ulReadCount)
|
|
{
|
|
//Mark the idle for the next phase so if another
|
|
//request comes in while we are doing this we will
|
|
//be brought out of the idle state...
|
|
dwTimeout = A51REP_THREAD_IDLE_TIMEOUT;
|
|
m_threadState = ThreadStateIdle;
|
|
m_ulReadCount = 0;
|
|
|
|
CAutoWriteLock lock(&g_readWriteLock);
|
|
if (lock.Lock())
|
|
{
|
|
//Compact the database again!
|
|
long lResInner;
|
|
if ( NO_ERROR != (lResInner= g_Glob.m_FileCache.Flush(true)))
|
|
{
|
|
//Flush failed, so we need to make sure it happens again
|
|
SetEvent(m_hWriteEvent);
|
|
break;
|
|
}
|
|
|
|
//Flush the caches
|
|
g_Glob.m_ForestCache.Clear();
|
|
g_Glob.m_FileCache.EmptyCaches();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//We need to sleep for some more as some more reads happened
|
|
ulPreviousReadCount = m_ulReadCount;
|
|
dwTimeout = A51REP_CACHE_FLUSH_TIMEOUT;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_bShuttingDown && !bShutdownThread)
|
|
InterlockedDecrement(&m_threadCount);
|
|
|
|
return 0;
|
|
}
|
|
|
|
HRESULT CRepository::ReadOperationNotification()
|
|
{
|
|
// ERRORTRACE((LOG_REPDRV, "Read Operation logged\n"));
|
|
//Check to make sure the thread is active, if not we need to activate it!
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
m_cs.Enter();
|
|
if (m_threadState == ThreadStateDead)
|
|
{
|
|
m_threadState = ThreadStateOperationPending;
|
|
HANDLE hTmp = NULL;
|
|
if (hTmp = InterlockedCompareExchangePointer(&m_hFlusherThread,0,m_hFlusherThread))
|
|
{
|
|
CloseHandle(hTmp);
|
|
}
|
|
m_hFlusherThread = CreateThread(NULL, 0, _FlusherThread, 0, 0, NULL);
|
|
}
|
|
if (m_hFlusherThread != NULL)
|
|
m_threadState = ThreadStateOperationPending;
|
|
else
|
|
hRes = WBEM_E_FAILED;
|
|
m_cs.Leave();
|
|
if ((m_hFlusherThread != NULL) &&(InterlockedIncrement(&m_ulReadCount) == 1))
|
|
SetEvent(m_hReadEvent);
|
|
return hRes;
|
|
}
|
|
HRESULT CRepository::WriteOperationNotification()
|
|
{
|
|
// ERRORTRACE((LOG_REPDRV, "Write Operation logged\n"));
|
|
//Check to make sure the thread is active, if not we need to activate it!
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
m_cs.Enter();
|
|
if (m_threadState == ThreadStateDead)
|
|
{
|
|
m_threadState = ThreadStateOperationPending;
|
|
HANDLE hTmp = NULL;
|
|
if (hTmp = InterlockedCompareExchangePointer(&m_hFlusherThread,0,m_hFlusherThread))
|
|
{
|
|
CloseHandle(hTmp);
|
|
}
|
|
m_hFlusherThread = CreateThread(NULL, 0, _FlusherThread, 0, 0, NULL);
|
|
}
|
|
if (m_hFlusherThread != NULL)
|
|
m_threadState = ThreadStateOperationPending;
|
|
else
|
|
hRes = WBEM_E_FAILED;
|
|
m_cs.Leave();
|
|
SetEvent(m_hWriteEvent);
|
|
return hRes;
|
|
}
|
|
|
|
|
|
#ifdef DBG
|
|
class CErrorRecover
|
|
{
|
|
private:
|
|
enum { ErrorsMax = 1024};
|
|
long Errors_[ErrorsMax];
|
|
long Index_;
|
|
public:
|
|
CErrorRecover():Index_(-1){};
|
|
void AddError(long lRes)
|
|
{
|
|
Errors_[InterlockedIncrement(&Index_)%ErrorsMax] = lRes;
|
|
};
|
|
} g_ErrorRecover;
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CGlobals g_Glob;
|
|
|
|
|
|
HRESULT
|
|
CGlobals::Initialize()
|
|
{
|
|
CInCritSec ics(&m_cs);
|
|
|
|
if (m_bInit)
|
|
return S_OK;
|
|
|
|
HRESULT hRes;
|
|
|
|
hRes = CoCreateInstance(CLSID_IWmiCoreServices, NULL,
|
|
CLSCTX_INPROC_SERVER, IID__IWmiCoreServices,
|
|
(void**)&m_pCoreServices);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = m_ForestCache.Initialize();
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
DWORD dwSize = sizeof(m_ComputerName)/sizeof(m_ComputerName[0]);
|
|
::GetComputerNameW(m_ComputerName, &dwSize);
|
|
m_bInit = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_pCoreServices->Release();
|
|
m_pCoreServices = NULL;
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CGlobals::Deinitialize()
|
|
{
|
|
CInCritSec ics(&m_cs);
|
|
|
|
if (!m_bInit)
|
|
return S_OK;
|
|
|
|
HRESULT hRes;
|
|
|
|
m_pCoreServices->Release();
|
|
m_pCoreServices = NULL;
|
|
|
|
hRes = m_ForestCache.Deinitialize();
|
|
|
|
m_bInit = FALSE;
|
|
return hRes;
|
|
}
|
|
|