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.

682 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. using namespace a51converter;
  8. long CFileCache::Initialize(LPCWSTR wszBaseName)
  9. {
  10. long lRes;
  11. wcscpy(m_wszBaseName, wszBaseName);
  12. wcscat(m_wszBaseName, L"\\");
  13. m_dwBaseNameLen = wcslen(m_wszBaseName);
  14. //
  15. // Read the maximum stage-file size from the registry
  16. //
  17. HKEY hKey;
  18. lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  19. L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
  20. 0, KEY_READ | KEY_WRITE, &hKey);
  21. if(lRes)
  22. return lRes;
  23. CRegCloseMe cm(hKey);
  24. DWORD dwLen = sizeof(DWORD);
  25. DWORD dwMaxLen;
  26. lRes = RegQueryValueExW(hKey, L"Max Stage File Size", NULL, NULL,
  27. (LPBYTE)&dwMaxLen, &dwLen);
  28. //
  29. // If not there, set to default and write the default into the registry
  30. //
  31. if(lRes != ERROR_SUCCESS)
  32. {
  33. dwMaxLen = 5000000;
  34. lRes = RegSetValueExW(hKey, L"Max Stage File Size", 0, REG_DWORD,
  35. (LPBYTE)&dwMaxLen, sizeof(DWORD));
  36. }
  37. dwLen = sizeof(DWORD);
  38. DWORD dwAbortTransactionLen;
  39. lRes = RegQueryValueExW(hKey, L"Absolute Max Stage File Size", NULL, NULL,
  40. (LPBYTE)&dwAbortTransactionLen, &dwLen);
  41. //
  42. // If not there, set to default and write the default into the registry
  43. //
  44. if(lRes != ERROR_SUCCESS || dwAbortTransactionLen == dwMaxLen * 10)
  45. {
  46. dwAbortTransactionLen = 0x7FFFFFFF;
  47. lRes = RegSetValueExW(hKey, L"Absolute Max Stage File Size", 0,
  48. REG_DWORD, (LPBYTE)&dwAbortTransactionLen, sizeof(DWORD));
  49. }
  50. if(dwMaxLen == 0)
  51. {
  52. //
  53. // Staged writes are disabled!
  54. //
  55. m_pMainStage = NULL;
  56. }
  57. else
  58. {
  59. //
  60. // Create the main staging area
  61. //
  62. CFileName wszStagingName;
  63. if (wszStagingName == NULL)
  64. return ERROR_OUTOFMEMORY;
  65. swprintf(wszStagingName, L"%s\\MainStage.dat", wszBaseName);
  66. m_pMainStage = new CExecutableStagingFile(this, m_wszBaseName,
  67. dwMaxLen, dwAbortTransactionLen);
  68. /*
  69. m_pMainStage = new CPermanentStagingFile(this, m_wszBaseName);
  70. */
  71. if(m_pMainStage == NULL)
  72. return E_OUTOFMEMORY;
  73. long lRes = m_pMainStage->Create(wszStagingName);
  74. if(lRes != ERROR_SUCCESS)
  75. return lRes;
  76. if(m_apStages.Add(m_pMainStage) < 0)
  77. {
  78. delete m_pMainStage;
  79. return E_OUTOFMEMORY;
  80. }
  81. }
  82. return ERROR_SUCCESS;
  83. }
  84. long CFileCache::RepositoryExists(LPCWSTR wszBaseName)
  85. {
  86. CFileName wszStagingName;
  87. if (wszStagingName == NULL)
  88. return ERROR_OUTOFMEMORY;
  89. swprintf(wszStagingName, L"%s\\MainStage.dat", wszBaseName);
  90. DWORD dwAttributes = GetFileAttributesW(wszStagingName);
  91. if (dwAttributes == -1)
  92. return ERROR_FILE_NOT_FOUND;
  93. return ERROR_SUCCESS;
  94. }
  95. CFileCache::CFileCache()
  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. //
  287. // Allocate the buffer from scratch
  288. //
  289. *pdwLen = fi.nFileSizeLow;
  290. *ppBuffer = (BYTE*)TempAlloc(*pdwLen);
  291. if(*ppBuffer == NULL)
  292. return E_OUTOFMEMORY;
  293. DWORD dwRead;
  294. if(!::ReadFile(hFile, *ppBuffer, *pdwLen, &dwRead, NULL))
  295. {
  296. lRes = GetLastError();
  297. ERRORTRACE((LOG_WBEMCORE, "Repository driver unable to read %d "
  298. "bytes from file with error %d\n", *pdwLen, lRes));
  299. _ASSERT(lRes != ERROR_SUCCESS, L"Success reported on failure");
  300. TempFree(*ppBuffer);
  301. //_ASSERT(!bMustBeThere, L"Must-be-there file is not found!");
  302. return lRes;
  303. }
  304. else
  305. {
  306. if(*pdwLen != dwRead)
  307. {
  308. _ASSERT(false, L"Read the wrong number of bytes");
  309. TempFree(*ppBuffer);
  310. return E_OUTOFMEMORY;
  311. }
  312. else
  313. return ERROR_SUCCESS;
  314. }
  315. }
  316. }
  317. }
  318. long CFileCache::FindFirst(LPCWSTR wszFilePrefix, WIN32_FIND_DATAW* pfd,
  319. void** ppHandle)
  320. {
  321. CInCritSec ics(&m_cs);
  322. //
  323. // Construct an enumerator
  324. //
  325. CFileEnumerator* pEnum = new CFileEnumerator(this, m_dwBaseNameLen);
  326. if (pEnum == NULL)
  327. return E_OUTOFMEMORY;
  328. long lRes = pEnum->GetFirst(wszFilePrefix, pfd);
  329. if(lRes != ERROR_SUCCESS)
  330. {
  331. delete pEnum;
  332. return lRes;
  333. }
  334. *ppHandle = (void*)pEnum;
  335. return ERROR_SUCCESS;
  336. }
  337. long CFileCache::FindNext(void* pHandle, WIN32_FIND_DATAW* pfd)
  338. {
  339. CInCritSec ics(&m_cs);
  340. CFileEnumerator* pEnum = (CFileEnumerator*)pHandle;
  341. return pEnum->GetNext(pfd);
  342. }
  343. void CFileCache::FindClose(void* pHandle)
  344. {
  345. CInCritSec ics(&m_cs);
  346. delete (CFileEnumerator*)pHandle;
  347. }
  348. long CFileCache::BeginTransaction()
  349. {
  350. if(GetMainStagingFile())
  351. return GetMainStagingFile()->BeginTransaction();
  352. else
  353. return ERROR_SUCCESS;
  354. }
  355. long CFileCache::CommitTransaction()
  356. {
  357. A51TRACE(("Committing Transaction!\n"));
  358. if(GetMainStagingFile())
  359. return GetMainStagingFile()->CommitTransaction();
  360. else
  361. return ERROR_SUCCESS;
  362. }
  363. long CFileCache::AbortTransaction()
  364. {
  365. A51TRACE(("Aborting Transaction!\n"));
  366. if(GetMainStagingFile())
  367. return GetMainStagingFile()->AbortTransaction();
  368. else
  369. return ERROR_SUCCESS;
  370. }
  371. CFileCache::CFileEnumerator::~CFileEnumerator()
  372. {
  373. if(m_pStageEnumerator)
  374. m_pCache->GetStageFile(m_nCurrentStage)->FindClose(m_pStageEnumerator);
  375. if(m_hFileEnum)
  376. ::FindClose(m_hFileEnum);
  377. }
  378. long CFileCache::CFileEnumerator::GetFirst(LPCWSTR wszPrefix,
  379. WIN32_FIND_DATAW* pfd)
  380. {
  381. long lRes;
  382. wcscpy(m_wszPrefix, wszPrefix);
  383. WCHAR* pwcLastSlash = wcsrchr(m_wszPrefix, L'\\');
  384. if(pwcLastSlash == NULL)
  385. return E_OUTOFMEMORY;
  386. m_dwPrefixDirLen = pwcLastSlash - m_wszPrefix;
  387. //
  388. // We are going to start with the first staging area
  389. //
  390. m_nCurrentStage = 0;
  391. m_bUseFiles = false;
  392. //
  393. // Everything is set up to indicate that we are at the very beginning ---
  394. // GetNext will retrieve the first
  395. //
  396. lRes = GetNext(pfd);
  397. //
  398. // One last thing --- absense of files is ERROR_NO_MORE_FILES for GetNext,
  399. // but ERROR_FILE_NOT_FOUND for GetFirst, so translate
  400. //
  401. if(lRes == ERROR_NO_MORE_FILES)
  402. lRes = ERROR_FILE_NOT_FOUND;
  403. return lRes;
  404. }
  405. long CFileCache::CFileEnumerator::GetFirstFile(WIN32_FIND_DATAW* pfd)
  406. {
  407. m_bUseFiles = true;
  408. CFileName wszMask;
  409. if (wszMask == NULL)
  410. return ERROR_OUTOFMEMORY;
  411. wcscpy(wszMask, m_wszPrefix);
  412. wcscat(wszMask, L"*");
  413. m_hFileEnum = ::FindFirstFileW(wszMask, pfd);
  414. long lRes = GetLastError();
  415. A51TRACE(("Actual FindFirstFileW on %S returning %p %d\n",
  416. wszMask, (void*)m_hFileEnum, lRes));
  417. if(m_hFileEnum == INVALID_HANDLE_VALUE)
  418. {
  419. if(lRes == ERROR_PATH_NOT_FOUND)
  420. return ERROR_FILE_NOT_FOUND;
  421. else
  422. return lRes;
  423. }
  424. else
  425. return ERROR_SUCCESS;
  426. }
  427. void CFileCache::CFileEnumerator::ComputeCanonicalName(WIN32_FIND_DATAW* pfd,
  428. wchar_t *wszFilePath)
  429. {
  430. wcsncpy(wszFilePath, m_wszPrefix, m_dwPrefixDirLen+1);
  431. wbem_wcsupr(wszFilePath+m_dwPrefixDirLen+1, pfd->cFileName);
  432. }
  433. long CFileCache::CFileEnumerator::GetNext(WIN32_FIND_DATAW* pfd)
  434. {
  435. long lRes;
  436. //
  437. // Go through the files in the enumerator until we find a new and valid one
  438. //
  439. while((lRes = GetRawNext(pfd)) == ERROR_SUCCESS)
  440. {
  441. //
  442. // Compute the full name
  443. //
  444. CFileName wszFullName;
  445. if (wszFullName == NULL)
  446. return ERROR_OUTOFMEMORY;
  447. ComputeCanonicalName(pfd, wszFullName);
  448. //
  449. // Check if it is already in our map of returned files
  450. //
  451. if(m_setSent.find((const wchar_t*)wszFullName) != m_setSent.end())
  452. continue;
  453. //
  454. // Check if this file is deleted
  455. //
  456. bool bDeleted = false;
  457. for(int i = 0; i < m_nCurrentStage; i++)
  458. {
  459. long hres = m_pCache->GetStageFile(i)->IsDeleted(wszFullName + m_dwBaseNameLen);
  460. if (hres == S_OK)
  461. {
  462. bDeleted = true;
  463. break;
  464. }
  465. else if (FAILED(hres))
  466. {
  467. return hres;
  468. }
  469. }
  470. if(bDeleted)
  471. continue;
  472. //
  473. // All clear!
  474. //
  475. if(!m_bUseFiles)
  476. m_setSent.insert((const wchar_t*)wszFullName);
  477. return ERROR_SUCCESS;
  478. }
  479. return lRes;
  480. }
  481. long CFileCache::CFileEnumerator::GetRawNext(WIN32_FIND_DATAW* pfd)
  482. {
  483. long lRes;
  484. if(m_bUseFiles)
  485. {
  486. //
  487. // Get the next file
  488. //
  489. if(!FindNextFileW(m_hFileEnum, pfd))
  490. {
  491. lRes = GetLastError();
  492. ::FindClose(m_hFileEnum);
  493. m_hFileEnum = NULL;
  494. return lRes;
  495. }
  496. else
  497. {
  498. return ERROR_SUCCESS;
  499. }
  500. }
  501. else
  502. {
  503. //
  504. // Check if we even have a stage enumerator
  505. //
  506. if(m_pStageEnumerator)
  507. {
  508. //
  509. // Get the next file from the same stage
  510. //
  511. lRes = m_pCache->GetStageFile(m_nCurrentStage)->
  512. FindNext(m_pStageEnumerator, pfd);
  513. if(lRes != ERROR_NO_MORE_FILES)
  514. return lRes;
  515. //
  516. // Advance to the next one
  517. //
  518. m_pCache->GetStageFile(m_nCurrentStage)->
  519. FindClose(m_pStageEnumerator);
  520. m_pStageEnumerator = NULL;
  521. m_nCurrentStage++;
  522. }
  523. else
  524. {
  525. //
  526. // This is our first time --- we are all set up to pick up the first
  527. // file from the first stage
  528. //
  529. }
  530. while(1)
  531. {
  532. if(m_nCurrentStage >= m_pCache->GetNumStages())
  533. {
  534. //
  535. // Go to files
  536. //
  537. lRes = GetFirstFile(pfd);
  538. if(lRes == ERROR_FILE_NOT_FOUND)
  539. return ERROR_NO_MORE_FILES;
  540. else
  541. return lRes;
  542. }
  543. else
  544. {
  545. //
  546. // Initialize the next stage
  547. //
  548. lRes = m_pCache->GetStageFile(m_nCurrentStage)->
  549. FindFirst(m_wszPrefix + m_dwBaseNameLen, pfd, &m_pStageEnumerator);
  550. if(lRes == ERROR_FILE_NOT_FOUND)
  551. {
  552. //
  553. // This stage has nothing to contribute --- move along
  554. //
  555. m_nCurrentStage++;
  556. continue;
  557. }
  558. else
  559. return lRes;
  560. }
  561. }
  562. }
  563. return 0;
  564. }