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.

704 lines
17 KiB

  1. #include <wbemcomn.h>
  2. #include "a51tools.h"
  3. #include "heap.h"
  4. #define ROSWELL_MAIN_FILE_SUFFIX L".hea"
  5. #define ROSWELL_FREE_FILE_SUFFIX L".fre"
  6. #define ROSWELL_INFINITE_BLOCK_SIZE 0x7FFFFFFF
  7. #define A51_HEAP_MAIN_FILE_INDEX 0
  8. #define A51_HEAP_FREE_FILE_INDEX 1
  9. CFileHeap::~CFileHeap()
  10. {
  11. }
  12. long CFileHeap::Initialize( CAbstractFileSource* pSource,
  13. LPCWSTR wszFileNameBase)
  14. {
  15. CInCritSec ics(&m_cs);
  16. if (m_bInit)
  17. return ERROR_SUCCESS;
  18. long lRes;
  19. //
  20. // Open both files
  21. //
  22. WCHAR wszMainFilePath[MAX_PATH+1];
  23. wcscpy(wszMainFilePath, wszFileNameBase);
  24. wcscat(wszMainFilePath, ROSWELL_MAIN_FILE_SUFFIX);
  25. HANDLE h;
  26. h = CreateFileW(wszMainFilePath, GENERIC_READ | GENERIC_WRITE,
  27. FILE_SHARE_READ, NULL, OPEN_ALWAYS,
  28. FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED,
  29. NULL);
  30. if(h == INVALID_HANDLE_VALUE)
  31. {
  32. lRes = GetLastError();
  33. _ASSERT(lRes != ERROR_SUCCESS, L"Success from failure");
  34. return lRes;
  35. }
  36. lRes = pSource->Register(h, A51_HEAP_MAIN_FILE_INDEX, false, &m_pMainFile);
  37. if (ERROR_SUCCESS != lRes)
  38. {
  39. return lRes;
  40. }
  41. WCHAR wszFreeFilePath[MAX_PATH+1];
  42. wcscpy(wszFreeFilePath, wszFileNameBase);
  43. wcscat(wszFreeFilePath, ROSWELL_FREE_FILE_SUFFIX);
  44. h = CreateFileW(wszFreeFilePath, GENERIC_READ | GENERIC_WRITE,
  45. FILE_SHARE_READ, NULL, OPEN_ALWAYS,
  46. FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED,
  47. NULL);
  48. if(h == INVALID_HANDLE_VALUE)
  49. {
  50. lRes = GetLastError();
  51. _ASSERT(lRes != ERROR_SUCCESS, L"Success from failure");
  52. return lRes;
  53. }
  54. lRes = pSource->Register(h, A51_HEAP_FREE_FILE_INDEX, false, &m_pFreeFile);
  55. if (ERROR_SUCCESS != lRes)
  56. {
  57. return lRes;
  58. }
  59. //
  60. // Read in the free list
  61. //
  62. m_bInit = TRUE; // set the status here, otherwise it will fail
  63. lRes = ReadFreeList();
  64. if(lRes != ERROR_SUCCESS)
  65. {
  66. m_bInit = FALSE;
  67. return lRes;
  68. }
  69. return ERROR_SUCCESS;
  70. }
  71. long CFileHeap::Uninitialize()
  72. {
  73. CInCritSec ics(&m_cs);
  74. if (!m_bInit)
  75. return ERROR_SUCCESS;
  76. if (m_pMainFile)
  77. {
  78. delete m_pMainFile;
  79. m_pMainFile = NULL;
  80. }
  81. if (m_pFreeFile)
  82. {
  83. delete m_pFreeFile;
  84. m_pFreeFile = NULL;
  85. }
  86. m_mapFree.clear();
  87. m_mapFreeOffset.clear();
  88. m_bInit = FALSE;
  89. return ERROR_SUCCESS;
  90. }
  91. //
  92. // this is a private function that uses a critsec,
  93. // but the public function invalidate cache does not use it
  94. //
  95. long CFileHeap::ReadFreeList()
  96. {
  97. CInCritSec ics(&m_cs);
  98. if (!m_bInit)
  99. return -1;
  100. long lRes;
  101. //
  102. // Clear it out
  103. //
  104. m_mapFree.clear();
  105. m_mapFreeOffset.clear();
  106. DWORD dwSize;
  107. //
  108. // Figure out the size of the free list file
  109. //
  110. lRes = m_pFreeFile->GetFileLength(&dwSize);
  111. if(dwSize > 0)
  112. {
  113. //
  114. // Figure out how many records that is
  115. //
  116. _ASSERT(dwSize % GetFreeListRecordSize() == 0,
  117. L"Wrong length of free file");
  118. int nNumRecords = dwSize / GetFreeListRecordSize();
  119. //ERRORTRACE((LOG_WBEMCORE, "Rereading %d records\n", nNumRecords));
  120. BYTE* aBuffer = (BYTE*)TempAlloc(dwSize);
  121. if(aBuffer == NULL)
  122. return ERROR_OUTOFMEMORY;
  123. CTempFreeMe tfm(aBuffer);
  124. lRes = ReadFromFreeFile(0, aBuffer, dwSize);
  125. if(lRes != ERROR_SUCCESS)
  126. {
  127. return lRes;
  128. }
  129. //
  130. // Insert them all into the map
  131. //
  132. BYTE* pCurrent = aBuffer;
  133. for(int i = 0; i < nNumRecords; i++)
  134. {
  135. DWORD dwSize;
  136. TOffset nOffset;
  137. memcpy(&dwSize, pCurrent, sizeof(DWORD));
  138. memcpy(&nOffset, pCurrent + sizeof(DWORD), sizeof(TOffset));
  139. //ERRORTRACE((LOG_WBEMCORE, "Offset %d, Size %d\n", nOffset, dwSize));
  140. pCurrent += GetFreeListRecordSize();
  141. try
  142. {
  143. m_mapFree.insert(TFreeValue(dwSize, CRecordInfo(i, nOffset)));
  144. if(dwSize)
  145. m_mapFreeOffset.insert(TFreeOffsetValue(nOffset, dwSize));
  146. }
  147. catch(...)
  148. {
  149. ERRORTRACE((LOG_WBEMCORE, "Crash1\n"));
  150. return ERROR_OUTOFMEMORY;
  151. }
  152. }
  153. }
  154. else
  155. {
  156. //
  157. // Populate with an inifinite block
  158. //
  159. lRes = InsertFreeBlock(0, ROSWELL_INFINITE_BLOCK_SIZE);
  160. if(lRes != ERROR_SUCCESS)
  161. return lRes;
  162. }
  163. return ERROR_SUCCESS;
  164. }
  165. long CFileHeap::InvalidateCache()
  166. {
  167. return ReadFreeList();
  168. }
  169. long CFileHeap::FindNextFree(TOffset nCurrentOffset, TOffset* pnNextFreeOffset,
  170. DWORD* pdwNextFreeLength)
  171. {
  172. CInCritSec ics(&m_cs);
  173. if (!m_bInit)
  174. return -1;
  175. TFreeOffsetIterator it = m_mapFreeOffset.lower_bound(nCurrentOffset);
  176. _ASSERT(it != m_mapFreeOffset.end(), L"Missing end-block");
  177. *pnNextFreeOffset = it->first;
  178. *pdwNextFreeLength = it->second;
  179. return ERROR_SUCCESS;
  180. }
  181. DWORD CFileHeap::GetFreeListRecordSize()
  182. {
  183. return sizeof(DWORD) // size
  184. + sizeof(TOffset); // offset
  185. }
  186. long CFileHeap::Allocate(DWORD dwLength, TOffset* pnOffset)
  187. {
  188. CInCritSec ics(&m_cs);
  189. if (!m_bInit)
  190. return -1;
  191. long lRes;
  192. //
  193. // Inform transaction manager that we are doing stuff in this transaction,
  194. // so that real rollback needs to be performed in case of failure
  195. //
  196. m_pMainFile->Touch();
  197. //
  198. // Find the smallest number not smaller than dwLength in the map
  199. //
  200. TFreeIterator it = m_mapFree.lower_bound(dwLength);
  201. _ASSERT(it != m_mapFree.end(), L"Missing infinite block");
  202. //
  203. // Cut it off
  204. //
  205. *pnOffset = it->second.m_nOffset;
  206. DWORD dwBlockSize = it->first;
  207. _ASSERT(dwBlockSize >= dwLength, L"Found a smaller block");
  208. DWORD dwSig = 0;
  209. lRes = ReadBytes(*pnOffset, (BYTE*)&dwSig, sizeof(DWORD));
  210. if(lRes != ERROR_SUCCESS)
  211. return lRes;
  212. /*
  213. _ASSERT(dwSig == 0x51515151, L"Mismatched block");
  214. ERRORTRACE((LOG_WBEMCORE, "Allocate %d at %d out of %d\n",
  215. (int)dwLength, (int)*pnOffset, (int)dwBlockSize));
  216. */
  217. //
  218. // Real block --- remove it and insert a shorter one (unless exact)
  219. //
  220. if(dwBlockSize != dwLength)
  221. {
  222. lRes = ReplaceFreeBlockByFreeIt(it, *pnOffset + dwLength,
  223. dwBlockSize - dwLength);
  224. if(lRes != ERROR_SUCCESS)
  225. return lRes;
  226. }
  227. else
  228. {
  229. lRes = EraseFreeBlockByFreeIt(it);
  230. if(lRes != ERROR_SUCCESS)
  231. return lRes;
  232. }
  233. return ERROR_SUCCESS;
  234. }
  235. long CFileHeap::FreeAllocation(TOffset nOffset, DWORD dwLength)
  236. {
  237. CInCritSec ics(&m_cs);
  238. if (!m_bInit)
  239. return -1;
  240. long lRes;
  241. if(dwLength == 0)
  242. return ERROR_SUCCESS;
  243. //
  244. // Inform transaction manager that we are doing stuff in this transaction,
  245. // so that real rollback needs to be performed in case of failure
  246. //
  247. m_pMainFile->Touch();
  248. //
  249. // First, see if there is a free block after us
  250. //
  251. int nExtraLengthAtEnd = 0;
  252. TFreeOffsetIterator itAfter = m_mapFreeOffset.lower_bound(nOffset);
  253. _ASSERT(itAfter != m_mapFreeOffset.end(), L"Missing end-block");
  254. _ASSERT(itAfter->first != nOffset, L"Found block we are deallocating "
  255. L"in free list");
  256. // ERRORTRACE((LOG_WBEMCORE, "Free %d at %d\n", (int)dwLength, (int)nOffset));
  257. //
  258. // See if it starts at our end
  259. //
  260. if(itAfter->first == nOffset + dwLength)
  261. {
  262. nExtraLengthAtEnd = itAfter->second;
  263. }
  264. //
  265. // Now, check the block before us
  266. //
  267. int nExtraLengthInFront = 0;
  268. TFreeOffsetIterator itBefore = itAfter;
  269. if(itBefore != m_mapFreeOffset.begin())
  270. {
  271. itBefore--;
  272. //
  273. // See if it ends at our start
  274. //
  275. if(itBefore->first + itBefore->second == nOffset)
  276. {
  277. nExtraLengthInFront = itBefore->second;
  278. }
  279. }
  280. if(nExtraLengthInFront == 0 && nExtraLengthAtEnd == 0)
  281. {
  282. //
  283. // No coalescing.
  284. //
  285. lRes = InsertFreeBlock(nOffset, dwLength);
  286. if(lRes != ERROR_SUCCESS)
  287. return lRes;
  288. }
  289. else
  290. {
  291. //
  292. // We shall coalesce this block into our neighbor
  293. //
  294. if(nExtraLengthInFront && nExtraLengthAtEnd)
  295. {
  296. //
  297. // Coalesce all three
  298. //
  299. TOffset nNewOffset = itBefore->first;
  300. DWORD dwNewLength = itBefore->second + dwLength + itAfter->second;
  301. lRes = EraseFreeBlockByOffsetIt(itBefore);
  302. if(lRes != ERROR_SUCCESS)
  303. return lRes;
  304. //
  305. // NOTE: it is very important that we Replace the block that
  306. // follows us, since the very last block is special, and we never
  307. // want to erase it.
  308. //
  309. lRes = ReplaceFreeBlockByOffsetIt(itAfter, nNewOffset, dwNewLength);
  310. if(lRes != ERROR_SUCCESS)
  311. return lRes;
  312. }
  313. else if(nExtraLengthInFront)
  314. {
  315. //
  316. // Collapse into the front block
  317. //
  318. TOffset nNewOffset = itBefore->first;
  319. DWORD dwNewLength = itBefore->second + dwLength;
  320. lRes = ReplaceFreeBlockByOffsetIt(itBefore, nNewOffset,
  321. dwNewLength);
  322. if(lRes != ERROR_SUCCESS)
  323. return lRes;
  324. }
  325. else
  326. {
  327. //
  328. // Collapse into the back block
  329. //
  330. TOffset nNewOffset = nOffset;
  331. DWORD dwNewLength = itAfter->second + dwLength;
  332. lRes = ReplaceFreeBlockByOffsetIt(itAfter, nNewOffset, dwNewLength);
  333. if(lRes != ERROR_SUCCESS)
  334. return lRes;
  335. }
  336. }
  337. return ERROR_SUCCESS;
  338. }
  339. long CFileHeap::ReadBytes(TOffset nOffset, BYTE* pBuffer, DWORD dwLength)
  340. {
  341. CInCritSec ics(&m_cs);
  342. if (!m_bInit)
  343. return -1;
  344. return m_pMainFile->Read(nOffset, pBuffer, dwLength, NULL);
  345. }
  346. long CFileHeap::WriteBytes(TOffset nOffset, BYTE* pBuffer, DWORD dwLength)
  347. {
  348. CInCritSec ics(&m_cs);
  349. if (!m_bInit)
  350. return -1;
  351. // ERRORTRACE((LOG_WBEMCORE, "Write %d bytes at %d\n", (int)dwLength, (int)nOffset));
  352. return m_pMainFile->Write(nOffset, pBuffer, dwLength, NULL);
  353. }
  354. //
  355. //
  356. // here are the private functions
  357. // the private finctions are supposed to be called by the public ones
  358. // that are guarded by a Critical Section
  359. //
  360. ///////////////////////////////////////////////////////////////////
  361. long CFileHeap::InsertFreeBlock(TOffset nOffset, DWORD dwLength)
  362. {
  363. //
  364. // We need to find an empty record --- they are the ones with 0 length
  365. //
  366. DWORD dwIndex;
  367. TFreeIterator it = m_mapFree.find(0);
  368. if(it == m_mapFree.end())
  369. {
  370. //
  371. // No free records --- just add one.
  372. //
  373. dwIndex = m_mapFree.size();
  374. }
  375. else
  376. {
  377. dwIndex = it->second.m_dwIndex;
  378. try
  379. {
  380. m_mapFree.erase(it);
  381. }
  382. catch(...)
  383. {
  384. ERRORTRACE((LOG_WBEMCORE, "Crash2\n"));
  385. return ERROR_OUTOFMEMORY;
  386. }
  387. }
  388. CRecordInfo Info(dwIndex, nOffset);
  389. try
  390. {
  391. m_mapFree.insert(TFreeValue(dwLength, Info));
  392. m_mapFreeOffset.insert(TFreeOffsetValue(nOffset, dwLength));
  393. }
  394. catch(...)
  395. {
  396. ERRORTRACE((LOG_WBEMCORE, "Crash3\n"));
  397. return ERROR_OUTOFMEMORY;
  398. }
  399. return WriteAllocationRecordToDisk(Info, dwLength);
  400. }
  401. CFileHeap::TFreeOffsetIterator CFileHeap::GetOffsetIteratorFromFree(
  402. TFreeIterator itFree)
  403. {
  404. return m_mapFreeOffset.find(itFree->second.m_nOffset);
  405. }
  406. CFileHeap::TFreeIterator CFileHeap::GetFreeIteratorFromOffset(
  407. TFreeOffsetIterator itOffset)
  408. {
  409. //
  410. // Can't just look it up --- walk all entries of this size looking for the
  411. // right offset
  412. //
  413. TOffset nOffset = itOffset->first;
  414. DWORD dwSize = itOffset->second;
  415. TFreeIterator itFree = m_mapFree.lower_bound(dwSize);
  416. while(itFree != m_mapFree.end() && itFree->first == dwSize &&
  417. itFree->second.m_nOffset != nOffset)
  418. {
  419. itFree++;
  420. }
  421. return itFree;
  422. }
  423. long CFileHeap::EraseFreeBlockByFreeIt(CFileHeap::TFreeIterator itFree)
  424. {
  425. return EraseFreeBlock(itFree, GetOffsetIteratorFromFree(itFree));
  426. }
  427. long CFileHeap::EraseFreeBlockByOffsetIt(CFileHeap::TFreeOffsetIterator itFreeOffset)
  428. {
  429. return EraseFreeBlock(GetFreeIteratorFromOffset(itFreeOffset),
  430. itFreeOffset);
  431. }
  432. long CFileHeap::EraseFreeBlock(CFileHeap::TFreeIterator itFree,
  433. CFileHeap::TFreeOffsetIterator itOffset)
  434. {
  435. _ASSERT(itFree != m_mapFree.end() && itOffset != m_mapFreeOffset.end(),
  436. L"Erasing a block that's not in one of the maps");
  437. //
  438. // Move the block to the free free-block list
  439. //
  440. CRecordInfo Info = itFree->second;
  441. Info.m_nOffset = ROSWELL_INVALID_OFFSET;
  442. try
  443. {
  444. m_mapFree.erase(itFree);
  445. m_mapFree.insert(TFreeValue(0, Info));
  446. m_mapFreeOffset.erase(itOffset);
  447. }
  448. catch(...)
  449. {
  450. ERRORTRACE((LOG_WBEMCORE, "Crash4\n"));
  451. return ERROR_OUTOFMEMORY;
  452. }
  453. return WriteAllocationRecordToDisk(Info, 0);
  454. }
  455. long CFileHeap::ReplaceFreeBlockByFreeIt(CFileHeap::TFreeIterator itFree, TOffset nOffset,
  456. DWORD dwSize)
  457. {
  458. return ReplaceFreeBlock(itFree, GetOffsetIteratorFromFree(itFree),
  459. nOffset, dwSize);
  460. }
  461. long CFileHeap::ReplaceFreeBlockByOffsetIt(CFileHeap::TFreeOffsetIterator itFreeOffset,
  462. TOffset nOffset, DWORD dwSize)
  463. {
  464. return ReplaceFreeBlock(GetFreeIteratorFromOffset(itFreeOffset),
  465. itFreeOffset, nOffset, dwSize);
  466. }
  467. long CFileHeap::ReplaceFreeBlock(CFileHeap::TFreeIterator itFree,
  468. CFileHeap::TFreeOffsetIterator itOffset,
  469. TOffset nOffset, DWORD dwSize)
  470. {
  471. long lRes;
  472. //
  473. // Check if the offset we are replacing is the ending offset.
  474. //
  475. bool bTruncate = false;
  476. TFreeOffsetIterator itNext = itOffset;
  477. itNext++;
  478. if(itNext == m_mapFreeOffset.end())
  479. {
  480. if(nOffset < itOffset->first)
  481. bTruncate = true;
  482. }
  483. //
  484. // Compute the info block --- old index, new offset
  485. //
  486. CRecordInfo Info = itFree->second;
  487. Info.m_nOffset = nOffset;
  488. try
  489. {
  490. //
  491. // If the size changed, remove and insert an entry into the by-size
  492. // map. Otherwise, just change the info there
  493. //
  494. if(itFree->first != dwSize)
  495. {
  496. m_mapFree.erase(itFree);
  497. m_mapFree.insert(TFreeValue(dwSize, Info));
  498. }
  499. else
  500. {
  501. itFree->second = Info;
  502. }
  503. //
  504. // If the offset changed, remove and insert an entry into the by-offset
  505. // map. Otherwise, just change the info there
  506. //
  507. if(itOffset->first != nOffset)
  508. {
  509. m_mapFreeOffset.erase(itOffset);
  510. m_mapFreeOffset.insert(TFreeOffsetValue(Info.m_nOffset, dwSize));
  511. }
  512. else
  513. {
  514. itOffset->second = dwSize;
  515. }
  516. }
  517. catch(...)
  518. {
  519. ERRORTRACE((LOG_WBEMCORE, "Crash5\n"));
  520. return ERROR_OUTOFMEMORY;
  521. }
  522. if(bTruncate && 0)
  523. {
  524. //
  525. // Truncate the file
  526. //
  527. lRes = m_pMainFile->SetFileLength(nOffset);
  528. if(lRes != ERROR_SUCCESS)
  529. return lRes;
  530. }
  531. return WriteAllocationRecordToDisk(Info, dwSize);
  532. }
  533. long CFileHeap::WriteAllocationRecordToDisk(const CRecordInfo& Info,
  534. DWORD dwSize)
  535. {
  536. BYTE* pBuffer = (BYTE*)TempAlloc(GetFreeListRecordSize());
  537. if(pBuffer == NULL)
  538. return ERROR_OUTOFMEMORY;
  539. CTempFreeMe tfm(pBuffer);
  540. memcpy(pBuffer, &dwSize, sizeof(DWORD));
  541. memcpy(pBuffer + sizeof(DWORD), &Info.m_nOffset, sizeof(TOffset));
  542. if(Info.m_nOffset != ROSWELL_INVALID_OFFSET && dwSize >= sizeof(DWORD))
  543. {
  544. DWORD dwSig = 0x51515151;
  545. long lRes = WriteBytes(Info.m_nOffset, (BYTE*)&dwSig, sizeof(DWORD));
  546. if(lRes != ERROR_SUCCESS)
  547. return lRes;
  548. }
  549. //
  550. // Position in the file is identified by the index
  551. //
  552. return WriteToFreeFile(GetFreeListRecordSize() * Info.m_dwIndex,
  553. pBuffer, GetFreeListRecordSize());
  554. }
  555. long CFileHeap::ReadFromFreeFile(TOffset nOffset, BYTE* pBuffer, DWORD dwLength)
  556. {
  557. return m_pFreeFile->Read(nOffset, pBuffer, dwLength, NULL);
  558. }
  559. long CFileHeap::WriteToFreeFile(TOffset nOffset, BYTE* pBuffer, DWORD dwLength)
  560. {
  561. return m_pFreeFile->Write(nOffset, pBuffer, dwLength, NULL);
  562. }