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.

715 lines
17 KiB

  1. /*++
  2. Copyright (C) 2000-2001 Microsoft Corporation
  3. --*/
  4. #include <windows.h>
  5. #include <stdio.h>
  6. #include <wbemcomn.h>
  7. #include <reposit.h>
  8. #include "filecach.h"
  9. #include "creposit.h"
  10. //
  11. // assumes inside m_cs
  12. //
  13. long CFileCache::InnerInitialize(LPCWSTR wszBaseName)
  14. {
  15. long lRes;
  16. wcscpy(m_wszBaseName, wszBaseName);
  17. wcscat(m_wszBaseName, L"\\");
  18. m_dwBaseNameLen = wcslen(m_wszBaseName);
  19. //
  20. // Read the maximum stage-file size from the registry
  21. //
  22. HKEY hKey;
  23. lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  24. L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
  25. 0, KEY_READ | KEY_WRITE, &hKey);
  26. if(lRes)
  27. return lRes;
  28. CRegCloseMe cm(hKey);
  29. DWORD dwLen = sizeof(DWORD);
  30. DWORD dwMaxLen;
  31. lRes = RegQueryValueExW(hKey, L"Max Stage File Size", NULL, NULL,
  32. (LPBYTE)&dwMaxLen, &dwLen);
  33. //
  34. // If not there, set to default and write the default into the registry
  35. //
  36. if(lRes != ERROR_SUCCESS)
  37. {
  38. dwMaxLen = 5000000;
  39. lRes = RegSetValueExW(hKey, L"Max Stage File Size", 0, REG_DWORD,
  40. (LPBYTE)&dwMaxLen, sizeof(DWORD));
  41. }
  42. dwLen = sizeof(DWORD);
  43. DWORD dwAbortTransactionLen;
  44. lRes = RegQueryValueExW(hKey, L"Absolute Max Stage File Size", NULL, NULL,
  45. (LPBYTE)&dwAbortTransactionLen, &dwLen);
  46. //
  47. // If not there, set to default and write the default into the registry
  48. //
  49. if(lRes != ERROR_SUCCESS || dwAbortTransactionLen == dwMaxLen * 10)
  50. {
  51. dwAbortTransactionLen = 0x7FFFFFFF;
  52. lRes = RegSetValueExW(hKey, L"Absolute Max Stage File Size", 0,
  53. REG_DWORD, (LPBYTE)&dwAbortTransactionLen, sizeof(DWORD));
  54. }
  55. if(dwMaxLen == 0)
  56. {
  57. //
  58. // Staged writes are disabled!
  59. //
  60. }
  61. else
  62. {
  63. //
  64. // Create the main staging area
  65. //
  66. CFileName wszStagingName;
  67. if (wszStagingName == NULL)
  68. return ERROR_OUTOFMEMORY;
  69. swprintf(wszStagingName, L"%s\\LowStage.dat", wszBaseName);
  70. lRes = m_AbstractSource.Create(wszStagingName, dwMaxLen,
  71. dwAbortTransactionLen);
  72. if(lRes != ERROR_SUCCESS)
  73. return lRes;
  74. }
  75. CFileName wszObjHeapName;
  76. if(wszObjHeapName == NULL)
  77. return ERROR_OUTOFMEMORY;
  78. swprintf(wszObjHeapName, L"%s\\ObjHeap", wszBaseName);
  79. lRes = m_ObjectHeap.Initialize(&m_AbstractSource,
  80. (WCHAR*)wszObjHeapName,
  81. (WCHAR*)wszBaseName,
  82. m_dwBaseNameLen);
  83. if(lRes != ERROR_SUCCESS)
  84. return lRes;
  85. lRes = m_AbstractSource.Start();
  86. if(lRes != ERROR_SUCCESS)
  87. return lRes;
  88. return ERROR_SUCCESS;
  89. }
  90. //
  91. // assumes inside m_cs
  92. //
  93. long CFileCache::RepositoryExists(LPCWSTR wszBaseName)
  94. {
  95. CFileName wszStagingName;
  96. if (wszStagingName == NULL)
  97. return ERROR_OUTOFMEMORY;
  98. swprintf(wszStagingName, L"%s\\LowStage.dat", wszBaseName);
  99. DWORD dwAttributes = GetFileAttributesW(wszStagingName);
  100. if (dwAttributes == -1)
  101. return ERROR_FILE_NOT_FOUND;
  102. return ERROR_SUCCESS;
  103. }
  104. long CFileCache::Initialize(LPCWSTR wszBaseName)
  105. {
  106. long lRes;
  107. CInCritSec ics(&m_cs);
  108. if (m_bInit)
  109. return ERROR_SUCCESS;
  110. lRes = RepositoryExists(wszBaseName);
  111. if (ERROR_FILE_NOT_FOUND == lRes)
  112. {
  113. //If we have a database restore to do, go ahead and do it...
  114. lRes = DoAutoDatabaseRestore();
  115. }
  116. //
  117. // Initialize file cache. It will read the registry itself to find out
  118. // its size limitations
  119. //
  120. if (SUCCEEDED(lRes))
  121. {
  122. lRes = InnerInitialize(wszBaseName);
  123. if (ERROR_SUCCESS == lRes)
  124. {
  125. m_bInit = TRUE;
  126. }
  127. }
  128. return lRes;
  129. }
  130. CFileCache::CFileCache()
  131. : m_lRef(1), m_bInit(FALSE)
  132. {
  133. }
  134. CFileCache::~CFileCache()
  135. {
  136. }
  137. void CFileCache::Clear(DWORD dwShutDownFlags)
  138. {
  139. m_AbstractSource.Stop(dwShutDownFlags);
  140. m_ObjectHeap.Uninitialize(dwShutDownFlags);
  141. //for(int i = 0; i < m_apStages.GetSize(); i++)
  142. // m_apStages[i]->Stop(g_ShutDownFlags);
  143. //if (WMIDB_SHUTDOWN_MACHINE_DOWN != g_ShutDownFlags)
  144. //{
  145. // m_apStages.RemoveAll();
  146. //}
  147. }
  148. long
  149. CFileCache::Uninitialize(DWORD dwShutDownFlags)
  150. {
  151. CInCritSec ics(&m_cs);
  152. if (!m_bInit)
  153. return 0;
  154. Clear(dwShutDownFlags);
  155. m_bInit = FALSE;
  156. return 0;
  157. }
  158. bool CFileCache::IsFullyFlushed()
  159. {
  160. CInCritSec ics(&m_cs);
  161. if (!m_bInit)
  162. return false;
  163. //for(int i = 0; i < m_apStages.GetSize(); i++)
  164. //{
  165. // if(!m_apStages[i]->IsFullyFlushed())
  166. // return false;
  167. //}
  168. return true;
  169. }
  170. bool CFileCache::GetFlushFailure(long* plFlushStatus)
  171. {
  172. CInCritSec ics(&m_cs);
  173. *plFlushStatus = 0;
  174. //for(int i = 0; i < m_apStages.GetSize(); i++)
  175. //{
  176. // if(m_apStages[i]->GetFailedBefore())
  177. // {
  178. // *plFlushStatus = m_apStages[i]->GetStatus();
  179. // return true;
  180. // }
  181. //}
  182. return false;
  183. }
  184. long CFileCache::WriteFile(LPCWSTR wszFileName, DWORD dwLen, BYTE* pBuffer)
  185. {
  186. CInCritSec ics(&m_cs);
  187. if (!m_bInit)
  188. return -1;
  189. //
  190. // Write the file into the main staging file
  191. //
  192. //if(GetMainStagingFile())
  193. //{
  194. // return GetMainStagingFile()->WriteFile(wszFileName + m_dwBaseNameLen,
  195. // dwLen, pBuffer);
  196. //}
  197. //else
  198. {
  199. return m_ObjectHeap.WriteFile(wszFileName, dwLen, pBuffer);
  200. }
  201. }
  202. long CFileCache::DeleteFile(LPCWSTR wszFileName)
  203. {
  204. CInCritSec ics(&m_cs);
  205. if (!m_bInit)
  206. return -1;
  207. //
  208. // Write the file into the main staging file
  209. //
  210. //if(GetMainStagingFile())
  211. //{
  212. // return GetMainStagingFile()->DeleteFile(wszFileName + m_dwBaseNameLen);
  213. //}
  214. //else
  215. {
  216. return m_ObjectHeap.DeleteFile(wszFileName);
  217. }
  218. }
  219. long CFileCache::RemoveDirectory(LPCWSTR wszFileName, bool bMustSucceed)
  220. {
  221. CInCritSec ics(&m_cs);
  222. if (!m_bInit)
  223. return -1;
  224. //
  225. // Write the file into the main staging file
  226. //
  227. //if(GetMainStagingFile())
  228. //{
  229. // return GetMainStagingFile()->
  230. // RemoveDirectory(wszFileName + m_dwBaseNameLen);
  231. //}
  232. //else
  233. {
  234. // No need to remove "directories" in the index
  235. return ERROR_SUCCESS;
  236. }
  237. }
  238. HRESULT CFileCache::ReadFile(LPCWSTR wszFileName, DWORD* pdwLen,
  239. BYTE** ppBuffer, bool bMustBeThere)
  240. {
  241. CInCritSec ics(&m_cs);
  242. if (!m_bInit)
  243. return -1;
  244. long lRes;
  245. //
  246. // Search all staging files in order
  247. //
  248. //for(int i = 0; i < m_apStages.GetSize(); i++)
  249. //{
  250. // lRes = m_apStages[i]->ReadFile(wszFileName + m_dwBaseNameLen, pdwLen,
  251. // ppBuffer, bMustBeThere);
  252. // if(lRes != ERROR_NO_INFORMATION)
  253. // {
  254. // if(lRes != ERROR_SUCCESS && lRes != ERROR_FILE_NOT_FOUND &&
  255. // lRes != ERROR_PATH_NOT_FOUND)
  256. // {
  257. // ERRORTRACE((LOG_WBEMCORE, "Repository driver cannot read file "
  258. // "'%S' from the stage with error code %d\n", wszFileName,
  259. // lRes));
  260. // }
  261. // return lRes;
  262. // }
  263. //}
  264. //
  265. // Not in the staging areas --- get from disk!
  266. //
  267. return m_ObjectHeap.ReadFile(wszFileName, pdwLen, ppBuffer);
  268. }
  269. long CFileCache::FindFirst(LPCWSTR wszFilePrefix, WIN32_FIND_DATAW* pfd,
  270. void** ppHandle)
  271. {
  272. CInCritSec ics(&m_cs);
  273. if (!m_bInit)
  274. return -1;
  275. //
  276. // Construct an enumerator
  277. //
  278. CFileEnumerator* pEnum = new CFileEnumerator(this, m_dwBaseNameLen);
  279. if (pEnum == NULL)
  280. return E_OUTOFMEMORY;
  281. long lRes = pEnum->GetFirst(wszFilePrefix, pfd, (ppHandle != NULL));
  282. if(lRes != ERROR_SUCCESS)
  283. {
  284. delete pEnum;
  285. return lRes;
  286. }
  287. if(ppHandle)
  288. *ppHandle = (void*)pEnum;
  289. else
  290. delete pEnum;
  291. return ERROR_SUCCESS;
  292. }
  293. long CFileCache::FindNext(void* pHandle, WIN32_FIND_DATAW* pfd)
  294. {
  295. CInCritSec ics(&m_cs);
  296. if (!m_bInit)
  297. return -1;
  298. CFileEnumerator* pEnum = (CFileEnumerator*)pHandle;
  299. return pEnum->GetNext(pfd, true);
  300. }
  301. void CFileCache::FindClose(void* pHandle)
  302. {
  303. CInCritSec ics(&m_cs);
  304. // do not bail out if un-initialized
  305. // we always want to free memory via the scoped obejct
  306. delete (CFileEnumerator*)pHandle;
  307. }
  308. //
  309. //
  310. // this is a shortcut chain for going straight to the BtrIdx
  311. //
  312. ///////////////////////////////////////////////////////////////////////
  313. long CFileCache::FindFirstIdx(LPCWSTR wszFilePrefix, WIN32_FIND_DATAW* pfd,
  314. void** ppHandle)
  315. {
  316. return m_ObjectHeap.FindFirst(wszFilePrefix, pfd, ppHandle);
  317. }
  318. long CFileCache::FindNextIdx(void* pHandle, WIN32_FIND_DATAW* pfd)
  319. {
  320. return m_ObjectHeap.FindNext(pHandle, pfd);
  321. }
  322. void CFileCache::FindCloseIdx(void* pHandle)
  323. {
  324. m_ObjectHeap.FindClose(pHandle);
  325. }
  326. long CFileCache::BeginTransaction()
  327. {
  328. if (!m_bInit)
  329. return -1;
  330. //if(GetMainStagingFile())
  331. // return GetMainStagingFile()->BeginTransaction();
  332. //else
  333. return m_AbstractSource.Begin(NULL);
  334. }
  335. long CFileCache::CommitTransaction()
  336. {
  337. if (!m_bInit)
  338. return -1;
  339. A51TRACE(("Committing Transaction!\n"));
  340. //if(GetMainStagingFile())
  341. // return GetMainStagingFile()->CommitTransaction();
  342. //else
  343. return m_AbstractSource.Commit(0);
  344. }
  345. long CFileCache::AbortTransaction()
  346. {
  347. if (!m_bInit)
  348. return -1;
  349. A51TRACE(("Aborting Transaction!\n"));
  350. //if(GetMainStagingFile())
  351. // return GetMainStagingFile()->AbortTransaction(NULL);
  352. //else
  353. {
  354. //
  355. // Actually rollback the staging file
  356. //
  357. bool bNonEmpty = false;
  358. long lRes = m_AbstractSource.Rollback(0, &bNonEmpty);
  359. if(lRes != ERROR_SUCCESS)
  360. return lRes;
  361. if(bNonEmpty)
  362. {
  363. //
  364. // We rolled back a non-empty transaction, which means that the
  365. // in-memory caches (which already took the transaction into
  366. // account) may no longer be valid. Invalidate all caches
  367. //
  368. m_ObjectHeap.InvalidateCache();
  369. }
  370. return ERROR_SUCCESS;
  371. }
  372. }
  373. CFileCache::CFileEnumerator::~CFileEnumerator()
  374. {
  375. //if(m_pStageEnumerator)
  376. // m_pCache->GetStageFile(m_nCurrentStage)->FindClose(m_pStageEnumerator);
  377. if(m_hFileEnum)
  378. m_pCache->m_ObjectHeap.FindClose(m_hFileEnum);
  379. }
  380. long CFileCache::CFileEnumerator::GetFirst(LPCWSTR wszPrefix,
  381. WIN32_FIND_DATAW* pfd,
  382. bool bNeedToContinue)
  383. {
  384. long lRes;
  385. wcscpy(m_wszPrefix, wszPrefix);
  386. WCHAR* pwcLastSlash = wcsrchr(m_wszPrefix, L'\\');
  387. if(pwcLastSlash == NULL)
  388. return E_OUTOFMEMORY;
  389. m_dwPrefixDirLen = pwcLastSlash - m_wszPrefix;
  390. //
  391. // We are going to start with the first staging area
  392. //
  393. m_nCurrentStage = 0;
  394. m_bUseFiles = false;
  395. //
  396. // Everything is set up to indicate that we are at the very beginning ---
  397. // GetNext will retrieve the first
  398. //
  399. lRes = GetNext(pfd, bNeedToContinue);
  400. //
  401. // One last thing --- absense of files is ERROR_NO_MORE_FILES for GetNext,
  402. // but ERROR_FILE_NOT_FOUND for GetFirst, so translate
  403. //
  404. if(lRes == ERROR_NO_MORE_FILES)
  405. lRes = ERROR_FILE_NOT_FOUND;
  406. return lRes;
  407. }
  408. long CFileCache::CFileEnumerator::GetFirstFile(WIN32_FIND_DATAW* pfd,
  409. bool bNeedToContinue)
  410. {
  411. long lRes;
  412. m_bUseFiles = true;
  413. if(bNeedToContinue)
  414. lRes = m_pCache->FindFirstIdx(m_wszPrefix, pfd, &m_hFileEnum);
  415. else
  416. lRes = m_pCache->FindFirstIdx(m_wszPrefix, pfd, NULL);
  417. A51TRACE(("Actual FindFirstFileW on %S returning %p %d\n",
  418. wszMask, (void*)m_hFileEnum, lRes));
  419. if(lRes != ERROR_SUCCESS)
  420. {
  421. if(lRes == ERROR_PATH_NOT_FOUND)
  422. return ERROR_FILE_NOT_FOUND;
  423. else
  424. return lRes;
  425. }
  426. else
  427. return ERROR_SUCCESS;
  428. }
  429. void CFileCache::CFileEnumerator::ComputeCanonicalName(WIN32_FIND_DATAW* pfd,
  430. wchar_t *wszFilePath)
  431. {
  432. wcsncpy(wszFilePath, m_wszPrefix, m_dwPrefixDirLen+1);
  433. wbem_wcsupr(wszFilePath+m_dwPrefixDirLen+1, pfd->cFileName);
  434. }
  435. long CFileCache::CFileEnumerator::GetNext(WIN32_FIND_DATAW* pfd,
  436. bool bNeedToContinue)
  437. {
  438. //
  439. // Need-to-continue optimizations are not possible if staging is used at
  440. // this level because even though the caller is only asking for one object,
  441. // we may need to retrieve more than that from the store since some of the
  442. // objects in the store may be overriden by the stage file deletions
  443. //
  444. //if(m_pCache->GetNumStages() > 0)
  445. // bNeedToContinue = true;
  446. long lRes;
  447. //
  448. // Go through the files in the enumerator until we find a new and valid one
  449. //
  450. while((lRes = GetRawNext(pfd, bNeedToContinue)) == ERROR_SUCCESS)
  451. {
  452. //
  453. // Compute the full name
  454. //
  455. CFileName wszFullName;
  456. if (wszFullName == NULL)
  457. return ERROR_OUTOFMEMORY;
  458. ComputeCanonicalName(pfd, wszFullName);
  459. //
  460. // Check if it is already in our map of returned files
  461. //
  462. if(m_setSent.find((const wchar_t*)wszFullName) != m_setSent.end())
  463. continue;
  464. //
  465. // Check if this file is deleted
  466. //
  467. bool bDeleted = false;
  468. /*
  469. for(int i = 0; i < m_nCurrentStage; i++)
  470. {
  471. long hres = m_pCache->GetStageFile(i)->IsDeleted(wszFullName + m_dwBaseNameLen);
  472. if (hres == S_OK)
  473. {
  474. bDeleted = true;
  475. break;
  476. }
  477. else if (FAILED(hres))
  478. {
  479. return hres;
  480. }
  481. }
  482. */
  483. if(bDeleted)
  484. continue;
  485. //
  486. // All clear!
  487. //
  488. if(!m_bUseFiles)
  489. m_setSent.insert((const wchar_t*)wszFullName);
  490. return ERROR_SUCCESS;
  491. }
  492. return lRes;
  493. }
  494. long CFileCache::CFileEnumerator::GetRawNext(WIN32_FIND_DATAW* pfd,
  495. bool bNeedToContinue)
  496. {
  497. long lRes;
  498. if(m_bUseFiles)
  499. {
  500. _ASSERT(bNeedToContinue, L"Continuing without need?");
  501. //
  502. // Get the next file
  503. //
  504. lRes = m_pCache->FindNextIdx(m_hFileEnum, pfd);
  505. if(lRes != ERROR_SUCCESS)
  506. {
  507. m_pCache->FindCloseIdx(m_hFileEnum);
  508. m_hFileEnum = NULL;
  509. return lRes;
  510. }
  511. return ERROR_SUCCESS;
  512. }
  513. else
  514. {
  515. //
  516. // Check if we even have a stage enumerator
  517. //
  518. /*
  519. if(m_pStageEnumerator)
  520. {
  521. _ASSERT(bNeedToContinue, L"Continuing without need?");
  522. //
  523. // Get the next file from the same stage
  524. //
  525. lRes = m_pCache->GetStageFile(m_nCurrentStage)->
  526. FindNext(m_pStageEnumerator, pfd);
  527. if(lRes != ERROR_NO_MORE_FILES)
  528. return lRes;
  529. //
  530. // Advance to the next one
  531. //
  532. m_pCache->GetStageFile(m_nCurrentStage)->
  533. FindClose(m_pStageEnumerator);
  534. m_pStageEnumerator = NULL;
  535. m_nCurrentStage++;
  536. }
  537. else
  538. {
  539. //
  540. // This is our first time --- we are all set up to pick up the first
  541. // file from the first stage
  542. //
  543. }
  544. */
  545. while(1)
  546. {
  547. //if(m_nCurrentStage >= m_pCache->GetNumStages())
  548. {
  549. //
  550. // Go to files
  551. //
  552. lRes = GetFirstFile(pfd, bNeedToContinue);
  553. if(lRes == ERROR_FILE_NOT_FOUND)
  554. return ERROR_NO_MORE_FILES;
  555. else
  556. return lRes;
  557. }
  558. /*
  559. else
  560. {
  561. _ASSERT(bNeedToContinue, L"Continuing without need?");
  562. //
  563. // Initialize the next stage
  564. //
  565. lRes = m_pCache->GetStageFile(m_nCurrentStage)->
  566. FindFirst(m_wszPrefix + m_dwBaseNameLen, pfd, &m_pStageEnumerator);
  567. if(lRes == ERROR_FILE_NOT_FOUND)
  568. {
  569. //
  570. // This stage has nothing to contribute --- move along
  571. //
  572. m_nCurrentStage++;
  573. continue;
  574. }
  575. else
  576. return lRes;
  577. }
  578. */
  579. }
  580. }
  581. return 0;
  582. }