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.
 
 
 
 
 
 

396 lines
12 KiB

/*
Copyright (c) Microsoft Corporation
*/
#include "stdinc.h"
#include <windows.h>
#include "sxsp.h"
#include "gsgenctx.h"
#include "sxsexceptionhandling.h"
typedef struct _CALLBACKDATA
{
union
{
GUID_SECTION_GENERATION_CONTEXT_CBDATA_GETDATASIZE GetDataSize;
GUID_SECTION_GENERATION_CONTEXT_CBDATA_GETDATA GetData;
GUID_SECTION_GENERATION_CONTEXT_CBDATA_ENTRYDELETED EntryDeleted;
GUID_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATASIZE GetUserDataSize;
GUID_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATA GetUserData;
} u;
} CALLBACKDATA, *PCALLBACKDATA;
BOOL CGSGenCtx::Create(
PGUID_SECTION_GENERATION_CONTEXT *GSGenContext,
ULONG DataFormatVersion,
GUID_SECTION_GENERATION_CONTEXT_CALLBACK_FUNCTION CallbackFunction,
PVOID CallbackContext
)
{
FN_PROLOG_WIN32
CGSGenCtx *pGSGenCtx;
if (GSGenContext != NULL)
*GSGenContext = NULL;
PARAMETER_CHECK(GSGenContext != NULL);
PARAMETER_CHECK(CallbackFunction != NULL);
IFALLOCFAILED_EXIT(pGSGenCtx = new CGSGenCtx);
pGSGenCtx->m_CallbackFunction = CallbackFunction;
pGSGenCtx->m_CallbackContext = CallbackContext;
pGSGenCtx->m_DataFormatVersion = DataFormatVersion;
*GSGenContext = (PGUID_SECTION_GENERATION_CONTEXT) pGSGenCtx;
FN_EPILOG
}
CGSGenCtx::CGSGenCtx()
{
m_HashTableSize = 0;
}
CGSGenCtx::~CGSGenCtx()
{
CSxsPreserveLastError ple;
CALLBACKDATA CBData;
CGuidPtrTableIter<Entry, EntryGuidTableHelper> iter(m_Table);
for (iter.Reset(); iter.More(); iter.Next())
{
CBData.u.EntryDeleted.DataContext = iter->m_DataContext;
(*m_CallbackFunction)(
m_CallbackContext,
GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_ENTRYDELETED,
&CBData);
iter->m_DataContext = NULL;
}
ple.Restore();
}
void
CGSGenCtx::EntryGuidTableHelper::FinalizeValue(
CGSGenCtx::Entry *&rpEntry
)
{
FUSION_DELETE_SINGLETON(rpEntry);
rpEntry = NULL;
}
BOOL
CGSGenCtx::Add(
const GUID &rGuid,
PVOID DataContext,
ULONG AssemblyRosterIndex,
DWORD DuplicateErrorCode
)
{
FN_PROLOG_WIN32
CSmartPtr<Entry> pEntry;
PARAMETER_CHECK(DuplicateErrorCode != ERROR_SUCCESS);
// We'll assume that duplicates are rare, so we'll allocate the entry up front.
IFW32FALSE_EXIT(pEntry.Win32Allocate(__FILE__, __LINE__));
IFW32FALSE_EXIT(pEntry->Initialize(DataContext, AssemblyRosterIndex));
IFW32FALSE_EXIT(m_Table.Insert(rGuid, pEntry));
pEntry.Detach();
FN_EPILOG
}
BOOL
CGSGenCtx::Find(
const GUID &rGuid,
PVOID *DataContext
)
{
FN_PROLOG_WIN32
Entry *pEntry = NULL;
if (DataContext != NULL)
*DataContext = NULL;
IFW32FALSE_EXIT(m_Table.Find(rGuid, pEntry));
if (pEntry == NULL)
ORIGINATE_WIN32_FAILURE_AND_EXIT(GuidNotInSection, ERROR_SXS_KEY_NOT_FOUND);
if (DataContext != NULL)
*DataContext = pEntry->m_DataContext;
FN_EPILOG
}
BOOL
CGSGenCtx::GetSectionSize(
PSIZE_T SizeOut
)
{
FN_PROLOG_WIN32
SIZE_T UserDataSize = 0;
SIZE_T HeaderSize = 0;
SIZE_T EntryListSize = 0;
SIZE_T EntryDataSize = 0;
CALLBACKDATA CBData;
Entry *pEntry = NULL;
CGuidPtrTableIter<Entry, EntryGuidTableHelper> iter(m_Table);
if (SizeOut != NULL)
*SizeOut = 0;
PARAMETER_CHECK(SizeOut != NULL);
HeaderSize = sizeof(ACTIVATION_CONTEXT_GUID_SECTION_HEADER);
CBData.u.GetUserDataSize.DataSize = 0;
IFW32FALSE_EXIT((*m_CallbackFunction)(m_CallbackContext, GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATASIZE, &CBData));
UserDataSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserDataSize.DataSize);
for (iter.Reset(); iter.More(); iter.Next())
{
EntryListSize += sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY);
CBData.u.GetDataSize.DataContext = iter->m_DataContext;
CBData.u.GetDataSize.DataSize = 0;
(*m_CallbackFunction)(m_CallbackContext, GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE, &CBData);
EntryDataSize += ROUND_ACTCTXDATA_SIZE(CBData.u.GetDataSize.DataSize);
}
*SizeOut = HeaderSize + UserDataSize + EntryListSize + EntryDataSize;
FN_EPILOG
}
BOOL
CGSGenCtx::GetSectionData(
SIZE_T BufferSize,
PVOID Buffer,
PSIZE_T BytesWritten
)
{
FN_PROLOG_WIN32
SIZE_T BytesSoFar = 0;
SIZE_T BytesLeft = BufferSize;
SIZE_T RoundedSize;
PACTIVATION_CONTEXT_GUID_SECTION_HEADER Header;
CALLBACKDATA CBData;
PVOID Cursor = NULL;
CGuidPtrTableIter<Entry, EntryGuidTableHelper> iter(m_Table);
SIZE_T EntryCount = m_Table.GetEntryCount();
if (BytesWritten != NULL)
*BytesWritten = 0;
if (BytesLeft < sizeof(ACTIVATION_CONTEXT_GUID_SECTION_HEADER))
ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
Header = (PACTIVATION_CONTEXT_GUID_SECTION_HEADER) Buffer;
Cursor = (PVOID) (Header + 1);
Header->Magic = ACTIVATION_CONTEXT_GUID_SECTION_MAGIC;
Header->HeaderSize = sizeof(ACTIVATION_CONTEXT_GUID_SECTION_HEADER);
Header->FormatVersion = ACTIVATION_CONTEXT_GUID_SECTION_FORMAT_WHISTLER;
Header->DataFormatVersion = m_DataFormatVersion;
Header->Flags = 0;
Header->ElementCount = static_cast<ULONG>(EntryCount);
Header->ElementListOffset = 0; // filled in after we figure out the user data area
Header->SearchStructureOffset = 0;
Header->UserDataOffset = 0; // filled in below
Header->UserDataSize = 0;
BytesLeft -= sizeof(*Header);
BytesSoFar += sizeof(*Header);
CBData.u.GetUserDataSize.DataSize = 0;
IFW32FALSE_EXIT(
(*m_CallbackFunction)(
m_CallbackContext,
GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATASIZE,
&CBData));
RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserDataSize.DataSize);
if (RoundedSize != 0)
{
CBData.u.GetUserData.SectionHeader = Header;
CBData.u.GetUserData.BufferSize = RoundedSize;
CBData.u.GetUserData.Buffer = Cursor;
CBData.u.GetUserData.BytesWritten = 0;
IFW32FALSE_EXIT(
(*m_CallbackFunction)(
m_CallbackContext,
GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATA,
&CBData));
ASSERT(CBData.u.GetUserData.BytesWritten <= RoundedSize);
if (CBData.u.GetUserData.BytesWritten != 0)
{
RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserData.BytesWritten);
BytesLeft -= RoundedSize;
BytesSoFar += RoundedSize;
Header->UserDataSize = static_cast<ULONG>(CBData.u.GetUserData.BytesWritten);
Header->UserDataOffset = static_cast<LONG>(((LONG_PTR) Cursor) - ((LONG_PTR) Header));
Cursor = (PVOID) (((ULONG_PTR) Cursor) + RoundedSize);
}
}
// Finally the array of entries...
if (EntryCount != 0)
{
PVOID DataCursor;
PACTIVATION_CONTEXT_GUID_SECTION_ENTRY DstEntry;
PACTIVATION_CONTEXT_GUID_SECTION_ENTRY DstEntryArrayFirstElement;
if (BytesLeft < (EntryCount * sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY)))
ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
BytesLeft -= (EntryCount * sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY));
BytesSoFar += (EntryCount * sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY));
//
// DstEntryArrayFirstElement actually points to the first thing that we'll
// be writing out, as DstEntry is ++'d across each of the elements as we
// zip through the output buffer.
//
DstEntryArrayFirstElement = (PACTIVATION_CONTEXT_GUID_SECTION_ENTRY) Cursor;
DstEntry = DstEntryArrayFirstElement;
Header->ElementListOffset = static_cast<LONG>(((LONG_PTR) DstEntry) - ((LONG_PTR) Header));
DataCursor = (PVOID) (DstEntry + EntryCount);
for (iter.Reset(); iter.More(); iter.Next())
{
CBData.u.GetDataSize.DataContext = iter->m_DataContext;
CBData.u.GetDataSize.DataSize = 0;
IFW32FALSE_EXIT(
(*m_CallbackFunction)(
m_CallbackContext,
GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE,
&CBData));
RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetDataSize.DataSize);
#if DBG
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_INFO,
"SXS.DLL: Guid section generation callback (_GETDATASIZE) returned data size of %d (rounded to %Id)\n", CBData.u.GetDataSize.DataSize, RoundedSize);
#endif
if (RoundedSize != 0)
{
if (BytesLeft < RoundedSize)
ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
CBData.u.GetData.SectionHeader = Header;
CBData.u.GetData.DataContext = iter->m_DataContext;
CBData.u.GetData.BufferSize = RoundedSize;
CBData.u.GetData.Buffer = DataCursor;
CBData.u.GetData.BytesWritten = 0;
#if DBG
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_INFO,
"SXS.DLL: Calling guid section generation callback with reason GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATA\n"
" .DataContext = %p\n"
" .BufferSize = %d\n"
" .Buffer = %p\n",
CBData.u.GetData.DataContext,
CBData.u.GetData.BufferSize,
CBData.u.GetData.Buffer);
#endif
IFW32FALSE_EXIT(
(*m_CallbackFunction)(
m_CallbackContext,
GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATA,
&CBData));
if (CBData.u.GetData.BytesWritten != 0)
{
ASSERT(CBData.u.GetData.BytesWritten <= RoundedSize);
RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetData.BytesWritten);
INTERNAL_ERROR_CHECK(CBData.u.GetData.BytesWritten <= RoundedSize);
BytesLeft -= RoundedSize;
BytesSoFar += RoundedSize;
DstEntry->Offset = static_cast<LONG>(((LONG_PTR) DataCursor) - ((LONG_PTR) Header));
}
else
DstEntry->Offset = 0;
DstEntry->Length = static_cast<ULONG>(CBData.u.GetData.BytesWritten);
DstEntry->AssemblyRosterIndex = iter->m_AssemblyRosterIndex;
DataCursor = (PVOID) (((ULONG_PTR) DataCursor) + RoundedSize);
}
else
{
DstEntry->Offset = 0;
DstEntry->Length = 0;
DstEntry->AssemblyRosterIndex = 0;
}
DstEntry->Guid = iter.GetKey();
DstEntry++;
}
//
// We compare the blobs via memcmp
//
if (m_HashTableSize == 0)
{
::qsort(DstEntryArrayFirstElement, EntryCount, sizeof(*DstEntry), &CGSGenCtx::SortGuidSectionEntries);
Header->Flags |= ACTIVATION_CONTEXT_GUID_SECTION_ENTRIES_IN_ORDER;
}
}
if (BytesWritten != NULL)
*BytesWritten = BytesSoFar;
FN_EPILOG
}
int __cdecl
CGSGenCtx::SortGuidSectionEntries(
const void *elem1,
const void *elem2
)
{
//
// The first thing in the structure is actually the GUID itself, but
// we'll save problems later by casting and following the Guid
// member.
//
const PACTIVATION_CONTEXT_GUID_SECTION_ENTRY pLeft = (const PACTIVATION_CONTEXT_GUID_SECTION_ENTRY)elem1;
const PACTIVATION_CONTEXT_GUID_SECTION_ENTRY pRight = (const PACTIVATION_CONTEXT_GUID_SECTION_ENTRY)elem2;
return memcmp( (const void*)&pLeft->Guid, (const void*)&pRight->Guid, sizeof(GUID) );
}
BOOL
CGSGenCtx::Entry::Initialize(
PVOID DataContext,
ULONG AssemblyRosterIndex
)
{
m_DataContext = DataContext;
m_AssemblyRosterIndex = AssemblyRosterIndex;
return TRUE;
}