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

/*++
Copyright (C) 1996-2000 Microsoft Corporation
Module Name:
mmfarena2.cpp
Abstract:
CMMFArena2 implementation (arenas based on memory-mapped files).
Used for database upgrade
History:
--*/
#include "precomp.h"
#include <stdio.h>
#define DEPRECATE_SUPPORTED
#define STRSAFE_NO_CB_FUNCTIONS
#include <strsafe.h>
#include "wbemutil.h"
#include "mmfarena2.h"
extern CMMFArena2 * g_pDbArena;
#define MAX_PAGE_SIZE_WIN9X 0x200000 /*2MB*/
#define MAX_PAGE_SIZE_NT 0x3200000 /*50MB*/
struct MMFOffsetItem
{
DWORD_PTR m_dwBaseOffset;
LPBYTE m_pBasePointer;
HANDLE m_hMappingHandle;
DWORD m_dwBlockSize;
};
#if (defined DEBUG || defined _DEBUG)
void MMFDebugBreak()
{
DebugBreak();
}
#else
inline void MMFDebugBreak() {}
#endif
//***************************************************************************
//
// CMMFArena2::CMMFArena2
//
// Constructor. Initialises a few things.
//
//***************************************************************************
CMMFArena2::CMMFArena2()
: m_dwStatus(0), m_hFile(INVALID_HANDLE_VALUE)
{
g_pDbArena = this;
//Get processor granularity
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
m_dwMappingGranularity = sysInfo.dwAllocationGranularity;
m_dwMaxPageSize = MAX_PAGE_SIZE_NT;
}
//***************************************************************************
//
// CMMFArena2::LoadMMF
//
// Loads an existing MMF. Loads in the base page and all pages following
// that
//
// pszFile : Filename of the MMF to open
//
// Return value : false if we failed, true if we succeed.
//
//***************************************************************************
bool CMMFArena2::LoadMMF(const TCHAR *pszFile)
{
//Open the file...
m_hFile = CreateFile(
pszFile,
GENERIC_READ ,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
0
);
if (m_hFile == INVALID_HANDLE_VALUE)
{
_ASSERT(0, "WinMgmt: Failed to open existing repository file");
m_dwStatus = 7;
return false;
}
DWORD dwSizeOfRepository = 0;
MMFOffsetItem *pOffsetItem = 0;
//Open the base page...
pOffsetItem = OpenBasePage(dwSizeOfRepository);
if (pOffsetItem == 0)
{
_ASSERT(0, "WinMgmt: Failed to open base page in MMF");
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
m_dwStatus = 7;
return false;
}
//Add the details to the offset manager...
int nStatus = -1;
nStatus = m_OffsetManager.Add(pOffsetItem);
if (nStatus)
{
_ASSERT(0, "WinMgmt: Failed to add offset information into offset table");
ClosePage(pOffsetItem);
delete pOffsetItem;
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
m_dwStatus = 7;
throw CX_MemoryException();
}
DWORD_PTR dwPageBase = 0;
if (m_pHeapDescriptor->m_dwVersion == 9)
{
//Now loop through all the following pages and load them...
DWORD dwSizeLastPage = 0;
nStatus = -1;
for (dwPageBase = pOffsetItem->m_dwBlockSize; dwPageBase < dwSizeOfRepository; dwPageBase += dwSizeLastPage)
{
//Open the next...
pOffsetItem = OpenExistingPage(dwPageBase);
if (pOffsetItem == 0)
{
_ASSERT(0, "WinMgmt: Failed to open an existing page in the MMF");
//Failed to do that!
CloseAllPages();
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
m_dwStatus = 7;
return false;
}
//Add the information to the offset manager...
nStatus = -1;
nStatus = m_OffsetManager.Add(pOffsetItem);
if (nStatus)
{
_ASSERT(0, "WinMgmt: Failed to add offset information into offset table");
//Failed to do that!
ClosePage(pOffsetItem);
delete pOffsetItem;
CloseAllPages();
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
m_dwStatus = 7;
throw CX_MemoryException();
}
dwSizeLastPage = pOffsetItem->m_dwBlockSize;
}
}
else if ((m_pHeapDescriptor->m_dwVersion == 10) || (m_pHeapDescriptor->m_dwVersion < 9))
{
dwPageBase = pOffsetItem->m_dwBlockSize;
}
else
{
_ASSERT(0, "WinMgmt: Database error... Code has not been added to support the opening of this database!!!!!");
ERRORTRACE((LOG_WBEMCORE, "Database error... Code has not been added to support the opening of this database!!!!!\n"));
}
//Create a mapping entry to mark the end of the MMF
pOffsetItem = new MMFOffsetItem;
if (pOffsetItem == 0)
{
_ASSERT(0, "WinMgmt: Out of memory");
//Failed to do that!
CloseAllPages();
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
m_dwStatus = 7;
throw CX_MemoryException();
}
pOffsetItem->m_dwBaseOffset = dwPageBase;
pOffsetItem->m_dwBlockSize = 0;
pOffsetItem->m_hMappingHandle = 0;
pOffsetItem->m_pBasePointer = 0;
nStatus = -1;
nStatus = m_OffsetManager.Add(pOffsetItem);
if (nStatus)
{
_ASSERT(0, "WinMgmt: Failed to add offset information into offset table");
//Failed to do that!
ClosePage(pOffsetItem);
delete pOffsetItem;
CloseAllPages();
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
m_dwStatus = 7;
throw CX_MemoryException();
}
return true;
};
//***************************************************************************
//
// CMMFArena2::OpenBasePage
//
// Opens the MMF first page which has all the information about the rest
// of the MMF as well as the first page of data.
//
// dwSizeOfRepository : Returns the current size of the repository
//
// Return value : Pointer to an offset item filled in with the base
// page information. NULL if we fail to open the
// base page.
//
//***************************************************************************
MMFOffsetItem *CMMFArena2::OpenBasePage(DWORD &dwSizeOfRepository)
{
MMFOffsetItem *pOffsetItem = 0;
pOffsetItem = new MMFOffsetItem;
if (pOffsetItem == 0)
throw CX_MemoryException();
//Seek to the start of this page...
if (SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
_ASSERT(0, "WinMgmt: Failed to set file pointer on MMF");
delete pOffsetItem;
return 0;
}
//Read in the hear information so we can find the size of this block...
DWORD dwActualRead;
MMF_ARENA_HEADER mmfHeader;
if ((ReadFile(m_hFile, &mmfHeader, sizeof(MMF_ARENA_HEADER), &dwActualRead, 0) == 0) || (dwActualRead != sizeof(MMF_ARENA_HEADER)))
{
_ASSERT(0, "WinMgmt: Failed to read MMF header information");
delete pOffsetItem;
return 0;
}
//Record the current size information...
dwSizeOfRepository = mmfHeader.m_dwCurrentSize;
DWORD dwSizeToMap = 0;
if ((mmfHeader.m_dwVersion < 9) || (mmfHeader.m_dwVersion == 10))
{
//old style database, we map in everything...
dwSizeToMap = mmfHeader.m_dwCurrentSize;
}
else if (mmfHeader.m_dwVersion == 9)
{
//We get the first page...
dwSizeToMap = mmfHeader.m_dwSizeOfFirstPage;
}
else
{
_ASSERT(0, "WinMgmt: Database error... Code has not been added to support the opening of this database!!!!!");
ERRORTRACE((LOG_WBEMCORE, "Database error... Code has not been added to support the opening of this database!!!!!\n"));
}
//Create the file mapping for this page...
HANDLE hMapping = CreateFileMapping(
m_hFile, // Disk file
0, // No security
PAGE_READONLY | SEC_COMMIT, // Extend the file to match the heap size
0, // High-order max size
dwSizeToMap, // Low-order max size
0 // No name for the mapping object
);
if (hMapping == NULL)
{
_ASSERT(0, "WinMgmt: Failed to create file mapping");
delete pOffsetItem;
return 0;
}
// Map this into memory...
LPBYTE pBindingAddress = (LPBYTE)MapViewOfFile(hMapping,
FILE_MAP_READ,
0,
0,
dwSizeToMap
);
if (pBindingAddress == NULL)
{
_ASSERT(0, "WinMgmt: Failed to map MMF into memory");
delete pOffsetItem;
CloseHandle(hMapping);
return 0;
}
//Record the base address of this because we need easy access to the header...
m_pHeapDescriptor = (MMF_ARENA_HEADER*) pBindingAddress;
//Create a mapping entry for this...
pOffsetItem->m_dwBaseOffset = 0;
pOffsetItem->m_dwBlockSize = dwSizeToMap;
pOffsetItem->m_hMappingHandle = hMapping;
pOffsetItem->m_pBasePointer = pBindingAddress;
return pOffsetItem;
}
//***************************************************************************
//
// CMMFArena2::OpenExistingPage
//
// Opens the specified page from the repostory.
//
// dwBaseOffset : Offset within the MMF to map in.
//
// Return value : Pointer to an offset item filled in with the
// page information. NULL if we fail to open the
// page.
//
//***************************************************************************
MMFOffsetItem *CMMFArena2::OpenExistingPage(DWORD_PTR dwBaseOffset)
{
MMFOffsetItem *pOffsetItem = 0;
pOffsetItem = new MMFOffsetItem;
if (pOffsetItem == 0)
throw CX_MemoryException();
//Set the file pointer to the start of this page...
if (SetFilePointer(m_hFile, (LONG)dwBaseOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
//We are in trouble!
_ASSERT(0, "WinMgmt: Failed to determine the size of the next block to load");
delete pOffsetItem;
return 0;
}
//Read in the page information so we can find out how big the page is...
DWORD dwActualRead = 0;
MMF_PAGE_HEADER pageHeader;
if ((ReadFile(m_hFile, &pageHeader, sizeof(MMF_PAGE_HEADER), &dwActualRead, 0) == 0) || (dwActualRead != sizeof(MMF_PAGE_HEADER)))
{
_ASSERT(0, "WinMgmt: Failed to read the next page block size");
delete pOffsetItem;
return 0;
}
//Create the file mapping...
HANDLE hMapping;
hMapping = CreateFileMapping(m_hFile,
0,
PAGE_READONLY| SEC_COMMIT,
0,
(LONG)dwBaseOffset + pageHeader.m_dwSize,
0);
if (hMapping == 0)
{
_ASSERT(0, "WinMgmt: Failed to map in part of the memory mapped file!");
delete pOffsetItem;
return 0;
}
//Map this into memory...
LPBYTE pBindingAddress;
pBindingAddress= (LPBYTE)MapViewOfFile(hMapping,
FILE_MAP_READ,
0,
(LONG)dwBaseOffset,
pageHeader.m_dwSize);
if (pBindingAddress == 0)
{
_ASSERT(0, "WinMgmt: Failed to bind part of the memory mapped file into memory!");
delete pOffsetItem;
CloseHandle(hMapping);
return 0;
}
//Record the information...
pOffsetItem->m_dwBaseOffset = dwBaseOffset;
pOffsetItem->m_dwBlockSize = pageHeader.m_dwSize;
pOffsetItem->m_hMappingHandle = hMapping;
pOffsetItem->m_pBasePointer = pBindingAddress;
return pOffsetItem;
}
//***************************************************************************
//
// CMMFArena2::ClosePage
//
// Closes the page specified
//
// pOffsetItem : Information about the page to close.
//
// Return value : None
//
//***************************************************************************
void CMMFArena2::ClosePage(MMFOffsetItem *pOffsetItem)
{
if (pOffsetItem->m_hMappingHandle)
{
UnmapViewOfFile(pOffsetItem->m_pBasePointer);
CloseHandle(pOffsetItem->m_hMappingHandle);
}
}
//***************************************************************************
//
// CMMFArena2::CloseAllPages
//
// Closes all pages in the offset manager, deleting the pointers of the
// objects in there.
//
// Return value : None
//
//***************************************************************************
void CMMFArena2::CloseAllPages()
{
//Close each of the file mappings...
for (int i = 0; i != m_OffsetManager.Size(); i++)
{
MMFOffsetItem *pItem = (MMFOffsetItem*)m_OffsetManager[i];
ClosePage(pItem);
delete pItem;
}
m_OffsetManager.Empty();
}
//***************************************************************************
//
// CMMFArena2::~CMMFArena2
//
// Destructor flushes the heap, unmaps the view and closes handles.
//
//***************************************************************************
CMMFArena2::~CMMFArena2()
{
if (m_hFile != INVALID_HANDLE_VALUE)
{
//Close each of the file mappings...
CloseAllPages();
//Close the file handle
CloseHandle(m_hFile);
}
}
//***************************************************************************
//
// CMMFArena2::ValidateBlock
//
// Validates the memory block as much as possible and calls a debug break
// point if an error is detected. Does this by analysing the size and
// the trailer DWORDs
//
// Parameters:
// <dwBlock> Offset of block to check
//
// Return value:
// TRUE if success.
//
//***************************************************************************
#if (defined DEBUG || defined _DEBUG)
BOOL CMMFArena2::ValidateBlock(DWORD_PTR dwBlock)
{
try
{
MMF_BLOCK_HEADER *pHeader = (MMF_BLOCK_HEADER *)OffsetToPtr(dwBlock);
MMF_BLOCK_TRAILER *pTrailer = GetTrailerBlock(pHeader);
if (sizeof(pTrailer->m_dwCheckBlock))
{
DWORD dwCheckBit;
//Is it deleted?
if (pHeader->m_dwSize & MMF_DELETED_MASK)
{
//Yes it is, so the we check for 0xFFFF
dwCheckBit = MMF_DEBUG_DELETED_TAG;
}
else
{
dwCheckBit = MMF_DEBUG_INUSE_TAG;
}
for (DWORD dwIndex = 0; dwIndex != (sizeof(pTrailer->m_dwCheckBlock) / sizeof(DWORD)); dwIndex++)
{
if (pTrailer->m_dwCheckBlock[dwIndex] != dwCheckBit)
{
#ifdef DBG
wchar_t string[200];
StringCchPrintfW(string, 200, L"WinMgmt: MMF Arena heap corruption,offset = 0x%p\n", dwBlock);
OutputDebugString(string);
_ASSERT(0, string);
#endif
MMFDebugBreak();
return FALSE;
}
}
}
if (!(pHeader->m_dwSize & MMF_DELETED_MASK))
{
//We are not deleted, so we should have a trailer back pointer of NULL
if (pTrailer->m_dwFLback != 0)
{
#ifdef DBG
wchar_t string[200];
StringCchPrintfW(string, 200, L"WinMgmt: MMF Arena heap corruption, offset = 0x%p\n", dwBlock);
OutputDebugString(string);
_ASSERT(0, string);
#endif
MMFDebugBreak();
return FALSE;
}
}
}
catch (...)
{
#ifdef DBG
wchar_t string[200];
StringCchPrintfW(string, 200, L"WinMgmt: MMF Arena heap corruption, offset = 0x%p\n", dwBlock);
OutputDebugString(string);
_ASSERT(0, string);
#endif
MMFDebugBreak();
return FALSE;
}
return TRUE;
}
#endif
//Some debugging functions...
//***************************************************************************
//
// CMMFArena::GetHeapInfo
//
// Gets detailed summary info about the heap. Completely walks the
// heap to do this.
//
// Parameters:
// <pdwTotalSize> Receives the heap size.
// <pdwActiveBlocks> Receives the number of allocated blocks.
// <pdwActiveBytes> Receives the total allocated bytes.
// <pdwFreeBlocks> Receives the number of 'free' blocks.
// <pdwFreeByte> Receives the number of 'free' bytes.
//
//***************************************************************************
DWORD CMMFArena2::Size(DWORD_PTR dwBlock)
{
if (m_dwStatus != 0)
throw DATABASE_FULL_EXCEPTION();
//Set the address to point to the actual start of the block
dwBlock -= sizeof(MMF_BLOCK_HEADER);
//Check the block is valid...
ValidateBlock(dwBlock);
MMF_BLOCK_HEADER *pBlockHeader = (MMF_BLOCK_HEADER*)OffsetToPtr(dwBlock);
if (pBlockHeader)
return GetSize(pBlockHeader);
else
return 0;
}
//Given an offset, returns a fixed up pointer
LPBYTE CMMFArena2::OffsetToPtr(DWORD_PTR dwOffset)
{
if (dwOffset == 0)
return 0;
if (m_dwStatus != 0)
throw DATABASE_FULL_EXCEPTION();
try
{
LPBYTE pBlock = 0;
int l = 0, u = m_OffsetManager.Size() - 1;
while (l <= u)
{
int m = (l + u) / 2;
if (dwOffset < ((MMFOffsetItem *)m_OffsetManager[m])->m_dwBaseOffset)
{
u = m - 1;
}
else if (dwOffset >= ((MMFOffsetItem *)m_OffsetManager[m+1])->m_dwBaseOffset)
{
l = m + 1;
}
else
{
return ((MMFOffsetItem *)m_OffsetManager[m])->m_pBasePointer + (dwOffset - ((MMFOffsetItem *)m_OffsetManager[m])->m_dwBaseOffset);
}
}
}
catch (...)
{
}
#ifdef DBG
wchar_t string[220];
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);
OutputDebugStringW(string);
_ASSERT(0, string);
#endif
MMFDebugBreak();
return 0;
}
//Given a pointer, returns an offset from the start of the MMF
DWORD_PTR CMMFArena2::PtrToOffset(LPBYTE pBlock)
{
if (m_dwStatus != 0)
throw DATABASE_FULL_EXCEPTION();
for (int i = 0; i < m_OffsetManager.Size(); i++)
{
register MMFOffsetItem *pItem = (MMFOffsetItem *)m_OffsetManager[i];
if ((pBlock >= pItem->m_pBasePointer) &&
(pBlock < (pItem->m_pBasePointer + pItem->m_dwBlockSize)))
{
return pItem->m_dwBaseOffset + (pBlock - pItem->m_pBasePointer);
}
}
#ifdef DBG
wchar_t string[220];
StringCchPrintfW(string, 220, L"WinMgmt: Could not find the offset requested in the repository, pointer requested = 0x%p\n", pBlock);
OutputDebugStringW(string);
_ASSERT(0, string);
#endif
MMFDebugBreak();
return 0;
}