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

1012 lines
28 KiB

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