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.

683 lines
17 KiB

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