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.

937 lines
22 KiB

  1. /*++
  2. Copyright (C) 2000-2001 Microsoft Corporation
  3. --*/
  4. #include <nt.h>
  5. #include <ntrtl.h>
  6. #include <nturtl.h>
  7. #define WIN32_NO_STATUS
  8. #include <windows.h>
  9. #include <wbemidl.h>
  10. #include <wbemint.h>
  11. #include <stdio.h>
  12. #include <wbemcomn.h>
  13. #include <ql.h>
  14. #include <time.h>
  15. #include "a51rep.h"
  16. #include <md5.h>
  17. #include <objpath.h>
  18. #include "lock.h"
  19. #include <persistcfg.h>
  20. #include "a51fib.h"
  21. #include "RepositoryPackager.h"
  22. #include "Win9xSecurity.h"
  23. #include <scopeguard.h>
  24. #include <malloc.h>
  25. CLock g_readWriteLock;
  26. bool g_bShuttingDown = false;
  27. CNamespaceHandle *g_pSystemClassNamespace = NULL;
  28. DWORD g_dwOldRepositoryVersion = 0;
  29. DWORD g_dwCurrentRepositoryVersion = 0;
  30. DWORD CRepository::m_ShutDownFlags = 0;
  31. HANDLE CRepository::m_hShutdownEvent = 0;
  32. HANDLE CRepository::m_hFlusherThread = 0;
  33. LONG CRepository::m_ulReadCount = 0;
  34. LONG CRepository::m_ulWriteCount = 0;
  35. HANDLE CRepository::m_hWriteEvent = 0;
  36. HANDLE CRepository::m_hReadEvent = 0;
  37. int CRepository::m_threadState = CRepository::ThreadStateDead;
  38. CCritSec CRepository::m_cs;
  39. LONG CRepository::m_threadCount = 0;
  40. //*****************************************************************************
  41. HRESULT CRepository::Initialize()
  42. {
  43. HRESULT hRes = WBEM_S_NO_ERROR;
  44. InitializeRepositoryVersions();
  45. //
  46. // Initialize time index
  47. //
  48. if (SUCCEEDED(hRes))
  49. {
  50. FILETIME ft;
  51. GetSystemTimeAsFileTime(&ft);
  52. g_nCurrentTime = ft.dwLowDateTime + ((__int64)ft.dwHighDateTime << 32);
  53. }
  54. //
  55. // Get the repository directory
  56. //
  57. if (SUCCEEDED(hRes))
  58. hRes = GetRepositoryDirectory();
  59. //Do the upgrade of the repository if necessary
  60. if (SUCCEEDED(hRes))
  61. hRes = UpgradeRepositoryFormat();
  62. //
  63. // initialze all our global resources
  64. //
  65. if (SUCCEEDED(hRes))
  66. hRes = InitializeGlobalVariables();
  67. if (SUCCEEDED(hRes))
  68. {
  69. long lRes = g_Glob.GetFileCache()->Initialize(g_Glob.GetRootDir());
  70. hRes = A51TranslateErrorCode(lRes);
  71. }
  72. //
  73. // Initialize class cache. It will read the registry itself to find out
  74. // its size limitations
  75. //
  76. if (SUCCEEDED(hRes))
  77. {
  78. hRes = g_Glob.Initialize();
  79. if(hRes != ERROR_SUCCESS)
  80. {
  81. hRes = WBEM_E_FAILED;
  82. }
  83. }
  84. //If we need to create the system class namespace then go ahead and do that...
  85. if (SUCCEEDED(hRes))
  86. {
  87. g_pSystemClassNamespace = new CNamespaceHandle(m_pControl, this);
  88. if (g_pSystemClassNamespace == NULL)
  89. {
  90. hRes = WBEM_E_OUT_OF_MEMORY;
  91. }
  92. }
  93. if (SUCCEEDED(hRes))
  94. {
  95. g_pSystemClassNamespace->AddRef();
  96. hRes = g_pSystemClassNamespace->Initialize(A51_SYSTEMCLASS_NS);
  97. }
  98. if (SUCCEEDED(hRes))
  99. {
  100. m_hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  101. if (m_hWriteEvent == NULL)
  102. hRes = WBEM_E_CRITICAL_ERROR;
  103. }
  104. if (SUCCEEDED(hRes))
  105. {
  106. m_hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  107. if (m_hReadEvent == NULL)
  108. hRes = WBEM_E_CRITICAL_ERROR;
  109. }
  110. if (SUCCEEDED(hRes))
  111. {
  112. m_hShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  113. if (m_hShutdownEvent == NULL)
  114. hRes = WBEM_E_CRITICAL_ERROR;
  115. }
  116. // *** Don't need to create the thread here because the read/write operation
  117. // *** will create it on demand...
  118. // if (SUCCEEDED(hRes))
  119. // {
  120. // m_hFlusherThread = CreateThread(NULL, 0, _FlusherThread, 0, 0, NULL);
  121. // if (m_hFlusherThread == NULL)
  122. // hRes = WBEM_E_CRITICAL_ERROR;
  123. // else
  124. // m_threadState = ThreadStateOperationPending;
  125. // }
  126. //We need to reset the shutting down flag as the flusher thread
  127. //will not start without it. The problem is that the next 2
  128. //operations (CreateSystemClasses and Import security do things
  129. //that will re-create the thread even though we don't do it above
  130. //
  131. if (SUCCEEDED(hRes))
  132. g_bShuttingDown = false;
  133. if (SUCCEEDED(hRes))
  134. {
  135. CAutoWriteLock lock(&g_readWriteLock);
  136. if (!lock.Lock())
  137. hRes = WBEM_E_FAILED;
  138. else
  139. hRes = g_pSystemClassNamespace->CreateSystemClasses(m_aSystemClasses);
  140. }
  141. if (SUCCEEDED(hRes))
  142. {
  143. // import Win9x security data if necessary
  144. CWin9xSecurity win9xSecurity(m_pControl, this);
  145. if (win9xSecurity.Win9xBlobFileExists())
  146. hRes = win9xSecurity.ImportWin9xSecurity();
  147. }
  148. if (SUCCEEDED(hRes))
  149. g_bShuttingDown = false;
  150. else
  151. {
  152. g_bShuttingDown = true; //Reset to true as we cleared it earlier!
  153. g_Glob.GetFileCache()->Uninitialize(0);
  154. g_Glob.GetForestCache()->Deinitialize();
  155. if (g_pSystemClassNamespace)
  156. {
  157. delete g_pSystemClassNamespace;
  158. g_pSystemClassNamespace = NULL;
  159. }
  160. if (m_hWriteEvent != NULL)
  161. {
  162. CloseHandle(m_hWriteEvent);
  163. m_hWriteEvent = NULL;
  164. }
  165. if (m_hReadEvent != NULL)
  166. {
  167. CloseHandle(m_hReadEvent);
  168. m_hReadEvent = NULL;
  169. }
  170. if (m_hShutdownEvent != NULL)
  171. {
  172. CloseHandle(m_hShutdownEvent);
  173. m_hShutdownEvent = NULL;
  174. }
  175. if (m_hFlusherThread != NULL)
  176. {
  177. CloseHandle(m_hFlusherThread);
  178. m_hFlusherThread = NULL;
  179. }
  180. }
  181. return hRes;
  182. }
  183. HRESULT CRepository::InitializeRepositoryVersions()
  184. {
  185. DWORD dwVal = 0;
  186. CPersistentConfig cfg;
  187. cfg.GetPersistentCfgValue(PERSIST_CFGVAL_CORE_FSREP_VERSION, dwVal);
  188. if (dwVal == 0)
  189. dwVal = A51_REP_FS_VERSION;
  190. g_dwOldRepositoryVersion = dwVal;
  191. g_dwCurrentRepositoryVersion = A51_REP_FS_VERSION;
  192. return WBEM_S_NO_ERROR;
  193. }
  194. HRESULT CRepository::UpgradeRepositoryFormat()
  195. {
  196. HRESULT hRes = WBEM_E_DATABASE_VER_MISMATCH;
  197. CPersistentConfig cfg;
  198. DWORD dwVal = 0;
  199. cfg.GetPersistentCfgValue(PERSIST_CFGVAL_CORE_FSREP_VERSION, dwVal);
  200. if (dwVal == 0)
  201. {
  202. //
  203. // First time --- write the right version in
  204. //
  205. hRes = WBEM_S_NO_ERROR;
  206. cfg.SetPersistentCfgValue(PERSIST_CFGVAL_CORE_FSREP_VERSION,
  207. A51_REP_FS_VERSION);
  208. }
  209. else if ((dwVal > 0) && (dwVal < 5))
  210. {
  211. ERRORTRACE((LOG_WBEMCORE, "Repository cannot upgrade this version of the repository. Version found = <%ld>, version expected = <%ld>\n", dwVal, A51_REP_FS_VERSION ));
  212. hRes = WBEM_E_DATABASE_VER_MISMATCH;
  213. }
  214. else if (dwVal == 5)
  215. {
  216. 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 ));
  217. //Need to delete the old repostiory
  218. CFileName fn;
  219. if (fn == NULL)
  220. hRes = WBEM_E_OUT_OF_MEMORY;
  221. else
  222. {
  223. wcscpy(fn, g_Glob.GetRootDir());
  224. wcscat(fn, L"\\index.btr");
  225. DeleteFileW(fn);
  226. wcscpy(fn, g_Glob.GetRootDir());
  227. wcscat(fn, L"\\lowstage.dat");
  228. DeleteFileW(fn);
  229. wcscpy(fn, g_Glob.GetRootDir());
  230. wcscat(fn, L"\\objheap.fre");
  231. DeleteFileW(fn);
  232. wcscpy(fn, g_Glob.GetRootDir());
  233. wcscat(fn, L"\\objheap.hea");
  234. DeleteFileW(fn);
  235. cfg.SetPersistentCfgValue(PERSIST_CFGVAL_CORE_FSREP_VERSION, A51_REP_FS_VERSION);
  236. hRes = WBEM_S_NO_ERROR;
  237. }
  238. }
  239. else if (dwVal == A51_REP_FS_VERSION)
  240. hRes = WBEM_S_NO_ERROR;
  241. if (hRes == WBEM_E_DATABASE_VER_MISMATCH)
  242. {
  243. //
  244. // Unsupported version
  245. //
  246. ERRORTRACE((LOG_WBEMCORE, "Repository cannot initialize "
  247. "due to the detection of an unknown repository version. Version found = <%ld>, version expected = <%ld>\n", dwVal, A51_REP_FS_VERSION ));
  248. return WBEM_E_DATABASE_VER_MISMATCH;
  249. }
  250. return hRes;
  251. }
  252. HRESULT CRepository::GetRepositoryDirectory()
  253. {
  254. HKEY hKey;
  255. long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  256. L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
  257. 0, KEY_READ, &hKey);
  258. if(lRes)
  259. return WBEM_E_FAILED;
  260. CFileName wszTmp;
  261. if (wszTmp == NULL)
  262. return WBEM_E_OUT_OF_MEMORY;
  263. DWORD dwLen = wszTmp.Length();
  264. lRes = RegQueryValueExW(hKey, L"Repository Directory", NULL, NULL,
  265. (LPBYTE)(wchar_t*)wszTmp, &dwLen);
  266. RegCloseKey(hKey);
  267. if(lRes)
  268. return WBEM_E_FAILED;
  269. CFileName wszRepDir;
  270. if (wszRepDir == NULL)
  271. return WBEM_E_OUT_OF_MEMORY;
  272. if (ExpandEnvironmentStringsW(wszTmp,wszRepDir,wszTmp.Length()) == 0)
  273. return WBEM_E_FAILED;
  274. lRes = EnsureDirectory(wszRepDir);
  275. if(lRes != ERROR_SUCCESS)
  276. return WBEM_E_FAILED;
  277. //
  278. // Append standard postfix --- that is our root
  279. //
  280. wcscpy(g_Glob.GetRootDir(), wszRepDir);
  281. wcscat(g_Glob.GetRootDir(), L"\\FS");
  282. g_Glob.SetRootDirLen(wcslen(g_Glob.GetRootDir()));
  283. //
  284. // Ensure the directory is there
  285. //
  286. lRes = EnsureDirectory(g_Glob.GetRootDir());
  287. if(lRes != ERROR_SUCCESS)
  288. return WBEM_E_FAILED;
  289. SetFileAttributesW(g_Glob.GetRootDir(), FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
  290. return WBEM_S_NO_ERROR;
  291. }
  292. HRESULT CRepository::InitializeGlobalVariables()
  293. {
  294. return WBEM_S_NO_ERROR;
  295. }
  296. HRESULT DoAutoDatabaseRestore()
  297. {
  298. HRESULT hRes = WBEM_S_NO_ERROR;
  299. //We may need to do a database restore!
  300. CFileName wszBackupFile;
  301. if (wszBackupFile == NULL)
  302. {
  303. return WBEM_E_OUT_OF_MEMORY;
  304. }
  305. int nLen = g_Glob.GetRootDirLen();
  306. wcsncpy(wszBackupFile, g_Glob.GetRootDir(), nLen - 3); // exclude "\FS" from path
  307. wszBackupFile[nLen - 3] = '\0';
  308. wcscat(wszBackupFile, L"\\repdrvfs.rec");
  309. DWORD dwAttributes = GetFileAttributesW(wszBackupFile);
  310. if (dwAttributes != -1)
  311. {
  312. DWORD dwMask = FILE_ATTRIBUTE_DEVICE |
  313. FILE_ATTRIBUTE_DIRECTORY |
  314. FILE_ATTRIBUTE_OFFLINE |
  315. FILE_ATTRIBUTE_REPARSE_POINT |
  316. FILE_ATTRIBUTE_SPARSE_FILE;
  317. if (!(dwAttributes & dwMask))
  318. {
  319. CRepositoryPackager packager;
  320. hRes = packager.UnpackageRepository(wszBackupFile);
  321. //We are going to ignore the error so if there was a problem we will just
  322. //load all the standard MOFs.
  323. if (hRes != WBEM_E_OUT_OF_MEMORY)
  324. hRes = WBEM_S_NO_ERROR;
  325. }
  326. }
  327. return hRes;
  328. }
  329. HRESULT STDMETHODCALLTYPE CRepository::Logon(
  330. WMIDB_LOGON_TEMPLATE *pLogonParms,
  331. DWORD dwFlags,
  332. DWORD dwRequestedHandleType,
  333. IWmiDbSession **ppSession,
  334. IWmiDbHandle **ppRootNamespace
  335. )
  336. {
  337. //If not initialized, initialize all subsystems...
  338. if (!g_Glob.IsInit())
  339. {
  340. HRESULT hres = Initialize();
  341. if (FAILED(hres))
  342. return hres;
  343. }
  344. CSession* pSession = new CSession(m_pControl);
  345. if (pSession == NULL)
  346. return WBEM_E_OUT_OF_MEMORY;
  347. pSession->AddRef();
  348. CReleaseMe rm1(pSession);
  349. CNamespaceHandle* pHandle = new CNamespaceHandle(m_pControl, this);
  350. if (pHandle == NULL)
  351. return WBEM_E_OUT_OF_MEMORY;
  352. pHandle->AddRef();
  353. CTemplateReleaseMe<CNamespaceHandle> rm2(pHandle);
  354. HRESULT hres = pHandle->Initialize(L"");
  355. if(FAILED(hres))
  356. return hres;
  357. *ppRootNamespace = pHandle;
  358. pHandle->AddRef();
  359. *ppSession = pSession;
  360. pSession->AddRef();
  361. return S_OK;
  362. }
  363. HRESULT STDMETHODCALLTYPE CRepository::GetLogonTemplate(
  364. LCID lLocale,
  365. DWORD dwFlags,
  366. WMIDB_LOGON_TEMPLATE **ppLogonTemplate
  367. )
  368. {
  369. WMIDB_LOGON_TEMPLATE* lt = (WMIDB_LOGON_TEMPLATE*)CoTaskMemAlloc(sizeof(WMIDB_LOGON_TEMPLATE));
  370. lt->dwArraySize = 0;
  371. lt->pParm = NULL;
  372. *ppLogonTemplate = lt;
  373. return S_OK;
  374. }
  375. HRESULT STDMETHODCALLTYPE CRepository::FreeLogonTemplate(
  376. WMIDB_LOGON_TEMPLATE **ppTemplate
  377. )
  378. {
  379. CoTaskMemFree(*ppTemplate);
  380. *ppTemplate = NULL;
  381. return S_OK;
  382. }
  383. HRESULT STDMETHODCALLTYPE CRepository::Shutdown(
  384. DWORD dwFlags
  385. )
  386. {
  387. g_bShuttingDown = true;
  388. m_ShutDownFlags = dwFlags;
  389. //Trigger the flusher thread to shutdown
  390. SetEvent(m_hShutdownEvent);
  391. SetEvent(m_hWriteEvent);
  392. if (m_hFlusherThread)
  393. WaitForSingleObject(m_hFlusherThread, INFINITE);
  394. bool bUnlock = (CLock::NoError == g_readWriteLock.WriteLock());
  395. //Mark thread as dead
  396. m_threadState = ThreadStateDead;
  397. if (WMIDB_SHUTDOWN_MACHINE_DOWN != dwFlags)
  398. {
  399. if (g_pSystemClassNamespace)
  400. g_pSystemClassNamespace->Release();
  401. g_pSystemClassNamespace = NULL;
  402. g_Glob.GetForestCache()->Deinitialize();
  403. }
  404. g_Glob.GetFileCache()->Flush();
  405. g_Glob.GetFileCache()->Uninitialize(dwFlags);
  406. if (WMIDB_SHUTDOWN_MACHINE_DOWN != dwFlags)
  407. {
  408. g_Glob.Deinitialize();
  409. if (bUnlock)
  410. g_readWriteLock.WriteUnlock();
  411. }
  412. if (m_hShutdownEvent != NULL)
  413. {
  414. CloseHandle(m_hShutdownEvent);
  415. m_hShutdownEvent = NULL;
  416. }
  417. if (m_hWriteEvent != NULL)
  418. {
  419. CloseHandle(m_hWriteEvent);
  420. m_hWriteEvent = NULL;
  421. }
  422. if (m_hReadEvent != NULL)
  423. {
  424. CloseHandle(m_hReadEvent);
  425. m_hReadEvent = NULL;
  426. }
  427. if (m_hFlusherThread != NULL)
  428. {
  429. CloseHandle(m_hFlusherThread);
  430. m_hFlusherThread = NULL;
  431. }
  432. return S_OK;
  433. }
  434. HRESULT STDMETHODCALLTYPE CRepository::SetCallTimeout(
  435. DWORD dwMaxTimeout
  436. )
  437. {
  438. return S_OK;
  439. }
  440. HRESULT STDMETHODCALLTYPE CRepository::SetCacheValue(
  441. DWORD dwMaxBytes
  442. )
  443. {
  444. HKEY hKey;
  445. long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  446. L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
  447. 0, KEY_READ | KEY_WRITE, &hKey);
  448. if(lRes)
  449. return lRes;
  450. CRegCloseMe cm(hKey);
  451. DWORD dwLen = sizeof(DWORD);
  452. DWORD dwMaxAge;
  453. lRes = RegQueryValueExW(hKey, L"Max Class Cache Item Age (ms)", NULL, NULL,
  454. (LPBYTE)&dwMaxAge, &dwLen);
  455. if(lRes != ERROR_SUCCESS)
  456. {
  457. dwMaxAge = 10000;
  458. lRes = RegSetValueExW(hKey, L"Max Class Cache Item Age (ms)", 0,
  459. REG_DWORD, (LPBYTE)&dwMaxAge, sizeof(DWORD));
  460. }
  461. g_Glob.GetForestCache()->SetMaxMemory(dwMaxBytes, dwMaxAge);
  462. return S_OK;
  463. }
  464. HRESULT STDMETHODCALLTYPE CRepository::FlushCache(
  465. DWORD dwFlags
  466. )
  467. {
  468. return S_OK;
  469. }
  470. HRESULT STDMETHODCALLTYPE CRepository::GetStatistics(
  471. DWORD dwParameter,
  472. DWORD *pdwValue
  473. )
  474. {
  475. return S_OK;
  476. }
  477. HRESULT STDMETHODCALLTYPE CRepository::GetRepositoryVersions(DWORD *pdwOldVersion,
  478. DWORD *pdwCurrentVersion)
  479. {
  480. *pdwOldVersion = g_dwOldRepositoryVersion;
  481. *pdwCurrentVersion = g_dwCurrentRepositoryVersion;
  482. return S_OK;
  483. }
  484. HRESULT CRepository::GetNamespaceHandle(LPCWSTR wszNamespaceName,
  485. RELEASE_ME CNamespaceHandle** ppHandle)
  486. {
  487. HRESULT hres;
  488. //
  489. // No validation --- that would be too hard. Just create a handle and
  490. // return
  491. //
  492. CNamespaceHandle* pNewHandle = new CNamespaceHandle(m_pControl, this);
  493. if (pNewHandle == NULL)
  494. return WBEM_E_OUT_OF_MEMORY;
  495. pNewHandle->AddRef();
  496. CReleaseMe rm1(pNewHandle);
  497. hres = pNewHandle->Initialize(wszNamespaceName);
  498. if(FAILED(hres))
  499. return hres;
  500. *ppHandle = pNewHandle;
  501. pNewHandle->AddRef();
  502. return S_OK;
  503. }
  504. HRESULT CRepository::Backup(LPCWSTR wszBackupFile, long lFlags)
  505. {
  506. HRESULT hRes = WBEM_S_NO_ERROR;
  507. // params have already been verified by the calling method (CWbemBackupRestore::DoBackup),
  508. // but do it again just in case things change and this is no longer the case
  509. if (NULL == wszBackupFile || (lFlags != 0))
  510. return WBEM_E_INVALID_PARAMETER;
  511. if (FAILED(hRes = LockRepository()))
  512. return hRes;
  513. CRepositoryPackager packager;
  514. hRes = packager.PackageRepository(wszBackupFile);
  515. UnlockRepository();
  516. return hRes;
  517. }
  518. HRESULT CRepository::Restore(LPCWSTR wszBackupFile, long lFlags)
  519. {
  520. return WBEM_E_NOT_SUPPORTED;
  521. }
  522. #define MaxTraceSizeBackup (11)
  523. struct BackUpTraces {
  524. DWORD ThreadId;
  525. PVOID Trace[MaxTraceSizeBackup];
  526. } g_Backup[2];
  527. LONG g_NumTimes;
  528. HRESULT CRepository::LockRepository()
  529. {
  530. #ifdef _X86_
  531. DWORD * pDW = (DWORD *)_alloca(sizeof(DWORD));
  532. #endif
  533. //Lock the database so no one writes to it
  534. if (CLock::NoError != g_readWriteLock.WriteLock())
  535. return WBEM_E_FAILED;
  536. ScopeGuard lockGuard = MakeObjGuard(g_readWriteLock, &CLock::WriteUnlock);
  537. if (g_bShuttingDown)
  538. {
  539. return WBEM_E_SHUTTING_DOWN;
  540. }
  541. InterlockedIncrement(&g_NumTimes);
  542. g_Backup[0].ThreadId = GetCurrentThreadId();
  543. ULONG Hash;
  544. RtlCaptureStackBackTrace(0,MaxTraceSizeBackup,g_Backup[0].Trace,&Hash);
  545. g_Backup[1].ThreadId = 0;
  546. //We need to wait for the transaction manager write to flush...
  547. long lRes = g_Glob.GetFileCache()->Flush();
  548. if (lRes != ERROR_SUCCESS)
  549. return WBEM_E_FAILED;
  550. if (CLock::NoError != g_readWriteLock.DowngradeLock())
  551. return WBEM_E_FAILED;
  552. lockGuard.Dismiss();
  553. return WBEM_S_NO_ERROR;
  554. }
  555. HRESULT CRepository::UnlockRepository()
  556. {
  557. #ifdef _X86_
  558. DWORD * pDW = (DWORD *)_alloca(sizeof(DWORD));
  559. #endif
  560. g_readWriteLock.ReadUnlock();
  561. InterlockedDecrement(&g_NumTimes);
  562. g_Backup[1].ThreadId = GetCurrentThreadId();
  563. ULONG Hash;
  564. RtlCaptureStackBackTrace(0,MaxTraceSizeBackup,g_Backup[1].Trace,&Hash);
  565. g_Backup[0].ThreadId = 0;
  566. return WBEM_S_NO_ERROR;
  567. }
  568. #define A51REP_CACHE_FLUSH_TIMEOUT 60000
  569. #define A51REP_THREAD_IDLE_TIMEOUT 60000
  570. DWORD WINAPI CRepository::_FlusherThread(void *)
  571. {
  572. // ERRORTRACE((LOG_REPDRV, "Flusher thread stated, thread = %lu\n", GetCurrentThreadId()));
  573. if (InterlockedIncrement(&m_threadCount) != 1)
  574. {
  575. ERRORTRACE((LOG_REPDRV, "Too many flusher threads detected in startup of thread!\n"));
  576. OutputDebugString(L"WinMgmt: Too many flusher threads detected in startup of thread!\n");
  577. DebugBreak();
  578. }
  579. HANDLE aHandles[2];
  580. aHandles[0] = m_hWriteEvent;
  581. aHandles[1] = m_hReadEvent;
  582. DWORD dwTimeout = INFINITE;
  583. LONG ulPreviousReadCount = m_ulReadCount;
  584. LONG ulPreviousWriteCount = m_ulWriteCount;
  585. bool bShutdownThread = false;
  586. while (!g_bShuttingDown && !bShutdownThread)
  587. {
  588. DWORD dwRet = WaitForMultipleObjects(2, aHandles, FALSE, dwTimeout);
  589. switch(dwRet)
  590. {
  591. case WAIT_OBJECT_0: //Write event
  592. {
  593. dwRet = WaitForSingleObject(m_hShutdownEvent, 15000);
  594. switch (dwRet)
  595. {
  596. case WAIT_OBJECT_0:
  597. break; //Shutting down, we cannot grab the lock so let the
  598. //initiator of shutdown do the flush for us
  599. case WAIT_TIMEOUT:
  600. {
  601. //We need to do a flush... either shutting down or idle
  602. CAutoWriteLock lock(&g_readWriteLock);
  603. if (lock.Lock())
  604. {
  605. if (g_Glob.GetFileCache()->Flush() != NO_ERROR)
  606. {
  607. RecoverCheckpoint();
  608. }
  609. }
  610. break;
  611. }
  612. case WAIT_FAILED:
  613. break;
  614. }
  615. //Transition to flush mode
  616. dwTimeout = A51REP_CACHE_FLUSH_TIMEOUT;
  617. ulPreviousReadCount = m_ulReadCount;
  618. m_threadState = ThreadStateFlush;
  619. break;
  620. }
  621. case WAIT_OBJECT_0+1: //Read event
  622. //Reset the flush mode as read happened
  623. dwTimeout = A51REP_CACHE_FLUSH_TIMEOUT;
  624. ulPreviousReadCount = m_ulReadCount;
  625. m_threadState = ThreadStateFlush;
  626. break;
  627. case WAIT_TIMEOUT: //Timeout, so flush caches
  628. {
  629. //Check for if we are in an idle shutdown state...
  630. m_cs.Enter();
  631. if (m_threadState == ThreadStateIdle)
  632. {
  633. m_threadState = ThreadStateDead;
  634. bShutdownThread = true;
  635. }
  636. m_cs.Leave();
  637. if (bShutdownThread)
  638. break;
  639. //Not thread shutdown, so we check for cache flush
  640. if (ulPreviousReadCount == m_ulReadCount)
  641. {
  642. //Mark the idle for the next phase so if another
  643. //request comes in while we are doing this we will
  644. //be brought out of the idle state...
  645. dwTimeout = A51REP_THREAD_IDLE_TIMEOUT;
  646. m_threadState = ThreadStateIdle;
  647. m_ulReadCount = 0;
  648. //Flush the caches
  649. CAutoWriteLock lock(&g_readWriteLock);
  650. if (lock.Lock())
  651. {
  652. g_Glob.GetForestCache()->Clear();
  653. g_Glob.GetFileCache()->EmptyCaches();
  654. //Recover the transaction manager if it has got into a bad state!
  655. g_Glob.GetFileCache()->RollbackCheckpointIfNeeded();
  656. }
  657. }
  658. else
  659. {
  660. //We need to sleep for some more as some more reads happened
  661. ulPreviousReadCount = m_ulReadCount;
  662. dwTimeout = A51REP_CACHE_FLUSH_TIMEOUT;
  663. }
  664. break;
  665. }
  666. }
  667. }
  668. // ERRORTRACE((LOG_REPDRV, "Flusher thread quiting, thread = %lu\n", GetCurrentThreadId()));
  669. if (InterlockedDecrement(&m_threadCount) != 0)
  670. {
  671. ERRORTRACE((LOG_REPDRV, "Too many flusher threads detected on shutdown of thread\n"));
  672. OutputDebugString(L"WinMgmt: Too many flusher threads detected on shutdown of thread!\n");
  673. DebugBreak();
  674. }
  675. return 0;
  676. }
  677. HRESULT CRepository::ReadOperationNotification()
  678. {
  679. // ERRORTRACE((LOG_REPDRV, "Read Operation logged\n"));
  680. //Check to make sure the thread is active, if not we need to activate it!
  681. m_cs.Enter();
  682. if (m_threadState == ThreadStateDead)
  683. {
  684. m_threadState = ThreadStateOperationPending;
  685. if (m_hFlusherThread)
  686. CloseHandle(m_hFlusherThread);
  687. m_hFlusherThread = CreateThread(NULL, 0, _FlusherThread, 0, 0, NULL);
  688. }
  689. m_threadState = ThreadStateOperationPending;
  690. m_cs.Leave();
  691. if (InterlockedIncrement(&m_ulReadCount) == 1)
  692. SetEvent(m_hReadEvent);
  693. return NO_ERROR;
  694. }
  695. HRESULT CRepository::WriteOperationNotification()
  696. {
  697. // ERRORTRACE((LOG_REPDRV, "Write Operation logged\n"));
  698. //Check to make sure the thread is active, if not we need to activate it!
  699. m_cs.Enter();
  700. if (m_threadState == ThreadStateDead)
  701. {
  702. m_threadState = ThreadStateOperationPending;
  703. if (m_hFlusherThread)
  704. CloseHandle(m_hFlusherThread);
  705. m_hFlusherThread = CreateThread(NULL, 0, _FlusherThread, 0, 0, NULL);
  706. }
  707. m_threadState = ThreadStateOperationPending;
  708. m_cs.Leave();
  709. SetEvent(m_hWriteEvent);
  710. return NO_ERROR;
  711. }
  712. HRESULT CRepository::RecoverCheckpoint()
  713. {
  714. LONG lRes = g_Glob.GetFileCache()->RollbackCheckpoint();
  715. g_Glob.GetForestCache()->Clear();
  716. g_Glob.GetFileCache()->EmptyCaches();
  717. if (lRes != 0)
  718. return WBEM_E_FAILED;
  719. else
  720. return WBEM_S_NO_ERROR;
  721. }
  722. //
  723. //
  724. //
  725. //
  726. //////////////////////////////////////////////////////////////////////
  727. CGlobals g_Glob;
  728. HRESULT
  729. CGlobals::Initialize()
  730. {
  731. CInCritSec ics(&m_cs);
  732. if (m_bInit)
  733. return S_OK;
  734. HRESULT hRes;
  735. hRes = CoCreateInstance(CLSID_IWmiCoreServices, NULL,
  736. CLSCTX_INPROC_SERVER, IID__IWmiCoreServices,
  737. (void**)&m_pCoreServices);
  738. if (SUCCEEDED(hRes))
  739. {
  740. hRes = m_ForestCache.Initialize();
  741. if (SUCCEEDED(hRes))
  742. {
  743. m_bInit = TRUE;
  744. }
  745. else
  746. {
  747. m_pCoreServices->Release();
  748. m_pCoreServices = NULL;
  749. }
  750. }
  751. return hRes;
  752. }
  753. HRESULT
  754. CGlobals::Deinitialize()
  755. {
  756. CInCritSec ics(&m_cs);
  757. if (!m_bInit)
  758. return S_OK;
  759. HRESULT hRes;
  760. m_pCoreServices->Release();
  761. m_pCoreServices = NULL;
  762. hRes = m_ForestCache.Deinitialize();
  763. m_bInit = FALSE;
  764. return hRes;
  765. }
  766. _IWmiCoreServices *
  767. CGlobals::GetCoreSvcs()
  768. {
  769. if (m_pCoreServices)
  770. {
  771. m_pCoreServices->AddRef();
  772. }
  773. return m_pCoreServices;
  774. }
  775. CForestCache *
  776. CGlobals::GetForestCache()
  777. {
  778. return &m_ForestCache;
  779. }
  780. CFileCache *
  781. CGlobals::GetFileCache()
  782. {
  783. return &m_FileCache;
  784. }