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.

648 lines
20 KiB

  1. /*++
  2. Copyright (C) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. mmfarena2.cpp
  5. Abstract:
  6. CMMFArena2 implementation (arenas based on memory-mapped files).
  7. Used for database upgrade
  8. History:
  9. --*/
  10. #include "precomp.h"
  11. #include <stdio.h>
  12. #define DEPRECATE_SUPPORTED
  13. #define STRSAFE_NO_CB_FUNCTIONS
  14. #include <strsafe.h>
  15. #include "wbemutil.h"
  16. #include "mmfarena2.h"
  17. extern CMMFArena2 * g_pDbArena;
  18. #define MAX_PAGE_SIZE_WIN9X 0x200000 /*2MB*/
  19. #define MAX_PAGE_SIZE_NT 0x3200000 /*50MB*/
  20. struct MMFOffsetItem
  21. {
  22. DWORD_PTR m_dwBaseOffset;
  23. LPBYTE m_pBasePointer;
  24. HANDLE m_hMappingHandle;
  25. DWORD m_dwBlockSize;
  26. };
  27. #if (defined DEBUG || defined _DEBUG)
  28. void MMFDebugBreak()
  29. {
  30. DebugBreak();
  31. }
  32. #else
  33. inline void MMFDebugBreak() {}
  34. #endif
  35. //***************************************************************************
  36. //
  37. // CMMFArena2::CMMFArena2
  38. //
  39. // Constructor. Initialises a few things.
  40. //
  41. //***************************************************************************
  42. CMMFArena2::CMMFArena2()
  43. : m_dwStatus(0), m_hFile(INVALID_HANDLE_VALUE)
  44. {
  45. g_pDbArena = this;
  46. //Get processor granularity
  47. SYSTEM_INFO sysInfo;
  48. GetSystemInfo(&sysInfo);
  49. m_dwMappingGranularity = sysInfo.dwAllocationGranularity;
  50. m_dwMaxPageSize = MAX_PAGE_SIZE_NT;
  51. }
  52. //***************************************************************************
  53. //
  54. // CMMFArena2::LoadMMF
  55. //
  56. // Loads an existing MMF. Loads in the base page and all pages following
  57. // that
  58. //
  59. // pszFile : Filename of the MMF to open
  60. //
  61. // Return value : false if we failed, true if we succeed.
  62. //
  63. //***************************************************************************
  64. bool CMMFArena2::LoadMMF(const TCHAR *pszFile)
  65. {
  66. //Open the file...
  67. m_hFile = CreateFile(
  68. pszFile,
  69. GENERIC_READ ,
  70. 0,
  71. 0,
  72. OPEN_EXISTING,
  73. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
  74. 0
  75. );
  76. if (m_hFile == INVALID_HANDLE_VALUE)
  77. {
  78. _ASSERT(0, "WinMgmt: Failed to open existing repository file");
  79. m_dwStatus = 7;
  80. return false;
  81. }
  82. DWORD dwSizeOfRepository = 0;
  83. MMFOffsetItem *pOffsetItem = 0;
  84. //Open the base page...
  85. pOffsetItem = OpenBasePage(dwSizeOfRepository);
  86. if (pOffsetItem == 0)
  87. {
  88. _ASSERT(0, "WinMgmt: Failed to open base page in MMF");
  89. CloseHandle(m_hFile);
  90. m_hFile = INVALID_HANDLE_VALUE;
  91. m_dwStatus = 7;
  92. return false;
  93. }
  94. //Add the details to the offset manager...
  95. int nStatus = -1;
  96. nStatus = m_OffsetManager.Add(pOffsetItem);
  97. if (nStatus)
  98. {
  99. _ASSERT(0, "WinMgmt: Failed to add offset information into offset table");
  100. ClosePage(pOffsetItem);
  101. delete pOffsetItem;
  102. CloseHandle(m_hFile);
  103. m_hFile = INVALID_HANDLE_VALUE;
  104. m_dwStatus = 7;
  105. throw CX_MemoryException();
  106. }
  107. DWORD_PTR dwPageBase = 0;
  108. if (m_pHeapDescriptor->m_dwVersion == 9)
  109. {
  110. //Now loop through all the following pages and load them...
  111. DWORD dwSizeLastPage = 0;
  112. nStatus = -1;
  113. for (dwPageBase = pOffsetItem->m_dwBlockSize; dwPageBase < dwSizeOfRepository; dwPageBase += dwSizeLastPage)
  114. {
  115. //Open the next...
  116. pOffsetItem = OpenExistingPage(dwPageBase);
  117. if (pOffsetItem == 0)
  118. {
  119. _ASSERT(0, "WinMgmt: Failed to open an existing page in the MMF");
  120. //Failed to do that!
  121. CloseAllPages();
  122. CloseHandle(m_hFile);
  123. m_hFile = INVALID_HANDLE_VALUE;
  124. m_dwStatus = 7;
  125. return false;
  126. }
  127. //Add the information to the offset manager...
  128. nStatus = -1;
  129. nStatus = m_OffsetManager.Add(pOffsetItem);
  130. if (nStatus)
  131. {
  132. _ASSERT(0, "WinMgmt: Failed to add offset information into offset table");
  133. //Failed to do that!
  134. ClosePage(pOffsetItem);
  135. delete pOffsetItem;
  136. CloseAllPages();
  137. CloseHandle(m_hFile);
  138. m_hFile = INVALID_HANDLE_VALUE;
  139. m_dwStatus = 7;
  140. throw CX_MemoryException();
  141. }
  142. dwSizeLastPage = pOffsetItem->m_dwBlockSize;
  143. }
  144. }
  145. else if ((m_pHeapDescriptor->m_dwVersion == 10) || (m_pHeapDescriptor->m_dwVersion < 9))
  146. {
  147. dwPageBase = pOffsetItem->m_dwBlockSize;
  148. }
  149. else
  150. {
  151. _ASSERT(0, "WinMgmt: Database error... Code has not been added to support the opening of this database!!!!!");
  152. ERRORTRACE((LOG_WBEMCORE, "Database error... Code has not been added to support the opening of this database!!!!!\n"));
  153. }
  154. //Create a mapping entry to mark the end of the MMF
  155. pOffsetItem = new MMFOffsetItem;
  156. if (pOffsetItem == 0)
  157. {
  158. _ASSERT(0, "WinMgmt: Out of memory");
  159. //Failed to do that!
  160. CloseAllPages();
  161. CloseHandle(m_hFile);
  162. m_hFile = INVALID_HANDLE_VALUE;
  163. m_dwStatus = 7;
  164. throw CX_MemoryException();
  165. }
  166. pOffsetItem->m_dwBaseOffset = dwPageBase;
  167. pOffsetItem->m_dwBlockSize = 0;
  168. pOffsetItem->m_hMappingHandle = 0;
  169. pOffsetItem->m_pBasePointer = 0;
  170. nStatus = -1;
  171. nStatus = m_OffsetManager.Add(pOffsetItem);
  172. if (nStatus)
  173. {
  174. _ASSERT(0, "WinMgmt: Failed to add offset information into offset table");
  175. //Failed to do that!
  176. ClosePage(pOffsetItem);
  177. delete pOffsetItem;
  178. CloseAllPages();
  179. CloseHandle(m_hFile);
  180. m_hFile = INVALID_HANDLE_VALUE;
  181. m_dwStatus = 7;
  182. throw CX_MemoryException();
  183. }
  184. return true;
  185. };
  186. //***************************************************************************
  187. //
  188. // CMMFArena2::OpenBasePage
  189. //
  190. // Opens the MMF first page which has all the information about the rest
  191. // of the MMF as well as the first page of data.
  192. //
  193. // dwSizeOfRepository : Returns the current size of the repository
  194. //
  195. // Return value : Pointer to an offset item filled in with the base
  196. // page information. NULL if we fail to open the
  197. // base page.
  198. //
  199. //***************************************************************************
  200. MMFOffsetItem *CMMFArena2::OpenBasePage(DWORD &dwSizeOfRepository)
  201. {
  202. MMFOffsetItem *pOffsetItem = 0;
  203. pOffsetItem = new MMFOffsetItem;
  204. if (pOffsetItem == 0)
  205. throw CX_MemoryException();
  206. //Seek to the start of this page...
  207. if (SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
  208. {
  209. _ASSERT(0, "WinMgmt: Failed to set file pointer on MMF");
  210. delete pOffsetItem;
  211. return 0;
  212. }
  213. //Read in the hear information so we can find the size of this block...
  214. DWORD dwActualRead;
  215. MMF_ARENA_HEADER mmfHeader;
  216. if ((ReadFile(m_hFile, &mmfHeader, sizeof(MMF_ARENA_HEADER), &dwActualRead, 0) == 0) || (dwActualRead != sizeof(MMF_ARENA_HEADER)))
  217. {
  218. _ASSERT(0, "WinMgmt: Failed to read MMF header information");
  219. delete pOffsetItem;
  220. return 0;
  221. }
  222. //Record the current size information...
  223. dwSizeOfRepository = mmfHeader.m_dwCurrentSize;
  224. DWORD dwSizeToMap = 0;
  225. if ((mmfHeader.m_dwVersion < 9) || (mmfHeader.m_dwVersion == 10))
  226. {
  227. //old style database, we map in everything...
  228. dwSizeToMap = mmfHeader.m_dwCurrentSize;
  229. }
  230. else if (mmfHeader.m_dwVersion == 9)
  231. {
  232. //We get the first page...
  233. dwSizeToMap = mmfHeader.m_dwSizeOfFirstPage;
  234. }
  235. else
  236. {
  237. _ASSERT(0, "WinMgmt: Database error... Code has not been added to support the opening of this database!!!!!");
  238. ERRORTRACE((LOG_WBEMCORE, "Database error... Code has not been added to support the opening of this database!!!!!\n"));
  239. }
  240. //Create the file mapping for this page...
  241. HANDLE hMapping = CreateFileMapping(
  242. m_hFile, // Disk file
  243. 0, // No security
  244. PAGE_READONLY | SEC_COMMIT, // Extend the file to match the heap size
  245. 0, // High-order max size
  246. dwSizeToMap, // Low-order max size
  247. 0 // No name for the mapping object
  248. );
  249. if (hMapping == NULL)
  250. {
  251. _ASSERT(0, "WinMgmt: Failed to create file mapping");
  252. delete pOffsetItem;
  253. return 0;
  254. }
  255. // Map this into memory...
  256. LPBYTE pBindingAddress = (LPBYTE)MapViewOfFile(hMapping,
  257. FILE_MAP_READ,
  258. 0,
  259. 0,
  260. dwSizeToMap
  261. );
  262. if (pBindingAddress == NULL)
  263. {
  264. _ASSERT(0, "WinMgmt: Failed to map MMF into memory");
  265. delete pOffsetItem;
  266. CloseHandle(hMapping);
  267. return 0;
  268. }
  269. //Record the base address of this because we need easy access to the header...
  270. m_pHeapDescriptor = (MMF_ARENA_HEADER*) pBindingAddress;
  271. //Create a mapping entry for this...
  272. pOffsetItem->m_dwBaseOffset = 0;
  273. pOffsetItem->m_dwBlockSize = dwSizeToMap;
  274. pOffsetItem->m_hMappingHandle = hMapping;
  275. pOffsetItem->m_pBasePointer = pBindingAddress;
  276. return pOffsetItem;
  277. }
  278. //***************************************************************************
  279. //
  280. // CMMFArena2::OpenExistingPage
  281. //
  282. // Opens the specified page from the repostory.
  283. //
  284. // dwBaseOffset : Offset within the MMF to map in.
  285. //
  286. // Return value : Pointer to an offset item filled in with the
  287. // page information. NULL if we fail to open the
  288. // page.
  289. //
  290. //***************************************************************************
  291. MMFOffsetItem *CMMFArena2::OpenExistingPage(DWORD_PTR dwBaseOffset)
  292. {
  293. MMFOffsetItem *pOffsetItem = 0;
  294. pOffsetItem = new MMFOffsetItem;
  295. if (pOffsetItem == 0)
  296. throw CX_MemoryException();
  297. //Set the file pointer to the start of this page...
  298. if (SetFilePointer(m_hFile, (LONG)dwBaseOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
  299. {
  300. //We are in trouble!
  301. _ASSERT(0, "WinMgmt: Failed to determine the size of the next block to load");
  302. delete pOffsetItem;
  303. return 0;
  304. }
  305. //Read in the page information so we can find out how big the page is...
  306. DWORD dwActualRead = 0;
  307. MMF_PAGE_HEADER pageHeader;
  308. if ((ReadFile(m_hFile, &pageHeader, sizeof(MMF_PAGE_HEADER), &dwActualRead, 0) == 0) || (dwActualRead != sizeof(MMF_PAGE_HEADER)))
  309. {
  310. _ASSERT(0, "WinMgmt: Failed to read the next page block size");
  311. delete pOffsetItem;
  312. return 0;
  313. }
  314. //Create the file mapping...
  315. HANDLE hMapping;
  316. hMapping = CreateFileMapping(m_hFile,
  317. 0,
  318. PAGE_READONLY| SEC_COMMIT,
  319. 0,
  320. (LONG)dwBaseOffset + pageHeader.m_dwSize,
  321. 0);
  322. if (hMapping == 0)
  323. {
  324. _ASSERT(0, "WinMgmt: Failed to map in part of the memory mapped file!");
  325. delete pOffsetItem;
  326. return 0;
  327. }
  328. //Map this into memory...
  329. LPBYTE pBindingAddress;
  330. pBindingAddress= (LPBYTE)MapViewOfFile(hMapping,
  331. FILE_MAP_READ,
  332. 0,
  333. (LONG)dwBaseOffset,
  334. pageHeader.m_dwSize);
  335. if (pBindingAddress == 0)
  336. {
  337. _ASSERT(0, "WinMgmt: Failed to bind part of the memory mapped file into memory!");
  338. delete pOffsetItem;
  339. CloseHandle(hMapping);
  340. return 0;
  341. }
  342. //Record the information...
  343. pOffsetItem->m_dwBaseOffset = dwBaseOffset;
  344. pOffsetItem->m_dwBlockSize = pageHeader.m_dwSize;
  345. pOffsetItem->m_hMappingHandle = hMapping;
  346. pOffsetItem->m_pBasePointer = pBindingAddress;
  347. return pOffsetItem;
  348. }
  349. //***************************************************************************
  350. //
  351. // CMMFArena2::ClosePage
  352. //
  353. // Closes the page specified
  354. //
  355. // pOffsetItem : Information about the page to close.
  356. //
  357. // Return value : None
  358. //
  359. //***************************************************************************
  360. void CMMFArena2::ClosePage(MMFOffsetItem *pOffsetItem)
  361. {
  362. if (pOffsetItem->m_hMappingHandle)
  363. {
  364. UnmapViewOfFile(pOffsetItem->m_pBasePointer);
  365. CloseHandle(pOffsetItem->m_hMappingHandle);
  366. }
  367. }
  368. //***************************************************************************
  369. //
  370. // CMMFArena2::CloseAllPages
  371. //
  372. // Closes all pages in the offset manager, deleting the pointers of the
  373. // objects in there.
  374. //
  375. // Return value : None
  376. //
  377. //***************************************************************************
  378. void CMMFArena2::CloseAllPages()
  379. {
  380. //Close each of the file mappings...
  381. for (int i = 0; i != m_OffsetManager.Size(); i++)
  382. {
  383. MMFOffsetItem *pItem = (MMFOffsetItem*)m_OffsetManager[i];
  384. ClosePage(pItem);
  385. delete pItem;
  386. }
  387. m_OffsetManager.Empty();
  388. }
  389. //***************************************************************************
  390. //
  391. // CMMFArena2::~CMMFArena2
  392. //
  393. // Destructor flushes the heap, unmaps the view and closes handles.
  394. //
  395. //***************************************************************************
  396. CMMFArena2::~CMMFArena2()
  397. {
  398. if (m_hFile != INVALID_HANDLE_VALUE)
  399. {
  400. //Close each of the file mappings...
  401. CloseAllPages();
  402. //Close the file handle
  403. CloseHandle(m_hFile);
  404. }
  405. }
  406. //***************************************************************************
  407. //
  408. // CMMFArena2::ValidateBlock
  409. //
  410. // Validates the memory block as much as possible and calls a debug break
  411. // point if an error is detected. Does this by analysing the size and
  412. // the trailer DWORDs
  413. //
  414. // Parameters:
  415. // <dwBlock> Offset of block to check
  416. //
  417. // Return value:
  418. // TRUE if success.
  419. //
  420. //***************************************************************************
  421. #if (defined DEBUG || defined _DEBUG)
  422. BOOL CMMFArena2::ValidateBlock(DWORD_PTR dwBlock)
  423. {
  424. try
  425. {
  426. MMF_BLOCK_HEADER *pHeader = (MMF_BLOCK_HEADER *)OffsetToPtr(dwBlock);
  427. MMF_BLOCK_TRAILER *pTrailer = GetTrailerBlock(pHeader);
  428. if (sizeof(pTrailer->m_dwCheckBlock))
  429. {
  430. DWORD dwCheckBit;
  431. //Is it deleted?
  432. if (pHeader->m_dwSize & MMF_DELETED_MASK)
  433. {
  434. //Yes it is, so the we check for 0xFFFF
  435. dwCheckBit = MMF_DEBUG_DELETED_TAG;
  436. }
  437. else
  438. {
  439. dwCheckBit = MMF_DEBUG_INUSE_TAG;
  440. }
  441. for (DWORD dwIndex = 0; dwIndex != (sizeof(pTrailer->m_dwCheckBlock) / sizeof(DWORD)); dwIndex++)
  442. {
  443. if (pTrailer->m_dwCheckBlock[dwIndex] != dwCheckBit)
  444. {
  445. #ifdef DBG
  446. wchar_t string[200];
  447. StringCchPrintfW(string, 200, L"WinMgmt: MMF Arena heap corruption,offset = 0x%p\n", dwBlock);
  448. OutputDebugString(string);
  449. _ASSERT(0, string);
  450. #endif
  451. MMFDebugBreak();
  452. return FALSE;
  453. }
  454. }
  455. }
  456. if (!(pHeader->m_dwSize & MMF_DELETED_MASK))
  457. {
  458. //We are not deleted, so we should have a trailer back pointer of NULL
  459. if (pTrailer->m_dwFLback != 0)
  460. {
  461. #ifdef DBG
  462. wchar_t string[200];
  463. StringCchPrintfW(string, 200, L"WinMgmt: MMF Arena heap corruption, offset = 0x%p\n", dwBlock);
  464. OutputDebugString(string);
  465. _ASSERT(0, string);
  466. #endif
  467. MMFDebugBreak();
  468. return FALSE;
  469. }
  470. }
  471. }
  472. catch (...)
  473. {
  474. #ifdef DBG
  475. wchar_t string[200];
  476. StringCchPrintfW(string, 200, L"WinMgmt: MMF Arena heap corruption, offset = 0x%p\n", dwBlock);
  477. OutputDebugString(string);
  478. _ASSERT(0, string);
  479. #endif
  480. MMFDebugBreak();
  481. return FALSE;
  482. }
  483. return TRUE;
  484. }
  485. #endif
  486. //Some debugging functions...
  487. //***************************************************************************
  488. //
  489. // CMMFArena::GetHeapInfo
  490. //
  491. // Gets detailed summary info about the heap. Completely walks the
  492. // heap to do this.
  493. //
  494. // Parameters:
  495. // <pdwTotalSize> Receives the heap size.
  496. // <pdwActiveBlocks> Receives the number of allocated blocks.
  497. // <pdwActiveBytes> Receives the total allocated bytes.
  498. // <pdwFreeBlocks> Receives the number of 'free' blocks.
  499. // <pdwFreeByte> Receives the number of 'free' bytes.
  500. //
  501. //***************************************************************************
  502. DWORD CMMFArena2::Size(DWORD_PTR dwBlock)
  503. {
  504. if (m_dwStatus != 0)
  505. throw DATABASE_FULL_EXCEPTION();
  506. //Set the address to point to the actual start of the block
  507. dwBlock -= sizeof(MMF_BLOCK_HEADER);
  508. //Check the block is valid...
  509. ValidateBlock(dwBlock);
  510. MMF_BLOCK_HEADER *pBlockHeader = (MMF_BLOCK_HEADER*)OffsetToPtr(dwBlock);
  511. if (pBlockHeader)
  512. return GetSize(pBlockHeader);
  513. else
  514. return 0;
  515. }
  516. //Given an offset, returns a fixed up pointer
  517. LPBYTE CMMFArena2::OffsetToPtr(DWORD_PTR dwOffset)
  518. {
  519. if (dwOffset == 0)
  520. return 0;
  521. if (m_dwStatus != 0)
  522. throw DATABASE_FULL_EXCEPTION();
  523. try
  524. {
  525. LPBYTE pBlock = 0;
  526. int l = 0, u = m_OffsetManager.Size() - 1;
  527. while (l <= u)
  528. {
  529. int m = (l + u) / 2;
  530. if (dwOffset < ((MMFOffsetItem *)m_OffsetManager[m])->m_dwBaseOffset)
  531. {
  532. u = m - 1;
  533. }
  534. else if (dwOffset >= ((MMFOffsetItem *)m_OffsetManager[m+1])->m_dwBaseOffset)
  535. {
  536. l = m + 1;
  537. }
  538. else
  539. {
  540. return ((MMFOffsetItem *)m_OffsetManager[m])->m_pBasePointer + (dwOffset - ((MMFOffsetItem *)m_OffsetManager[m])->m_dwBaseOffset);
  541. }
  542. }
  543. }
  544. catch (...)
  545. {
  546. }
  547. #ifdef DBG
  548. wchar_t string[220];
  549. StringCchPrintfW(string, 220, L"WinMgmt: Could not find the block requested in the repository, offset requested = 0x%p, end of repository = 0x%p\n", dwOffset, ((MMFOffsetItem *)m_OffsetManager[m_OffsetManager.Size()-1])->m_dwBaseOffset);
  550. OutputDebugStringW(string);
  551. _ASSERT(0, string);
  552. #endif
  553. MMFDebugBreak();
  554. return 0;
  555. }
  556. //Given a pointer, returns an offset from the start of the MMF
  557. DWORD_PTR CMMFArena2::PtrToOffset(LPBYTE pBlock)
  558. {
  559. if (m_dwStatus != 0)
  560. throw DATABASE_FULL_EXCEPTION();
  561. for (int i = 0; i < m_OffsetManager.Size(); i++)
  562. {
  563. register MMFOffsetItem *pItem = (MMFOffsetItem *)m_OffsetManager[i];
  564. if ((pBlock >= pItem->m_pBasePointer) &&
  565. (pBlock < (pItem->m_pBasePointer + pItem->m_dwBlockSize)))
  566. {
  567. return pItem->m_dwBaseOffset + (pBlock - pItem->m_pBasePointer);
  568. }
  569. }
  570. #ifdef DBG
  571. wchar_t string[220];
  572. StringCchPrintfW(string, 220, L"WinMgmt: Could not find the offset requested in the repository, pointer requested = 0x%p\n", pBlock);
  573. OutputDebugStringW(string);
  574. _ASSERT(0, string);
  575. #endif
  576. MMFDebugBreak();
  577. return 0;
  578. }