windows-nt/Source/XPSP1/NT/base/win32/fusion/sxs/gsgenctx.cpp
2020-09-26 16:20:57 +08:00

420 lines
12 KiB
C++

#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
)
{
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
CGSGenCtx *pGSGenCtx;
IFALLOCFAILED_EXIT(pGSGenCtx = new CGSGenCtx);
pGSGenCtx->m_CallbackFunction = CallbackFunction;
pGSGenCtx->m_CallbackContext = CallbackContext;
pGSGenCtx->m_DataFormatVersion = DataFormatVersion;
*GSGenContext = (PGUID_SECTION_GENERATION_CONTEXT) pGSGenCtx;
fSuccess = TRUE;
Exit:
return fSuccess;
}
CGSGenCtx::CGSGenCtx()
{
m_FirstEntry = NULL;
m_LastEntry = NULL;
m_EntryCount = 0;
m_HashTableSize = 0;
}
CGSGenCtx::~CGSGenCtx()
{
CSxsPreserveLastError ple;
CALLBACKDATA CBData;
Entry *pEntry = m_FirstEntry;
while (pEntry != NULL)
{
Entry *pNext = pEntry->m_Next;
CBData.u.EntryDeleted.DataContext = pEntry->m_DataContext;
(*m_CallbackFunction)(
m_CallbackContext,
GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_ENTRYDELETED,
&CBData);
FUSION_DELETE_SINGLETON(pEntry);
pEntry = pNext;
}
ple.Restore();
}
BOOL
CGSGenCtx::Add(
const GUID &rGuid,
PVOID DataContext,
ULONG AssemblyRosterIndex,
DWORD DuplicateErrorCode
)
{
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
Entry *pEntry = NULL;
PARAMETER_CHECK(DuplicateErrorCode != ERROR_SUCCESS);
#if DBG_SXS
CSmallStringBuffer buffGuid;
::SxspFormatGUID(rGuid, buffGuid);
#endif // DBG_SXS
for (pEntry = m_FirstEntry; pEntry != NULL; pEntry = pEntry->m_Next)
{
if (pEntry->m_Guid == rGuid)
{
::FusionpSetLastWin32Error(DuplicateErrorCode);
pEntry = NULL;
goto Exit;
}
}
IFALLOCFAILED_EXIT(pEntry = new Entry);
IFW32FALSE_EXIT(pEntry->Initialize(rGuid, DataContext, AssemblyRosterIndex));
if (m_LastEntry == NULL)
m_FirstEntry = pEntry;
else
m_LastEntry->m_Next = pEntry;
m_LastEntry = pEntry;
pEntry = NULL;
m_EntryCount++;
fSuccess = TRUE;
Exit:
FUSION_DELETE_SINGLETON(pEntry);
return fSuccess;
}
BOOL
CGSGenCtx::Find(
const GUID &rGuid,
PVOID *DataContext
)
{
BOOL fSuccess = FALSE;
Entry *pEntry = NULL;
if (DataContext != NULL)
*DataContext = NULL;
for (pEntry = m_FirstEntry; pEntry != NULL; pEntry = pEntry->m_Next)
{
if (pEntry->m_Guid == rGuid)
break;
}
if (pEntry == NULL)
{
::FusionpSetLastWin32Error(ERROR_SXS_KEY_NOT_FOUND);
goto Exit;
}
if (DataContext != NULL)
*DataContext = pEntry->m_DataContext;
fSuccess = TRUE;
Exit:
return fSuccess;
}
BOOL
CGSGenCtx::GetSectionSize(
PSIZE_T SizeOut
)
{
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
SIZE_T UserDataSize = 0;
SIZE_T HeaderSize = 0;
SIZE_T EntryListSize = 0;
SIZE_T EntryDataSize = 0;
CALLBACKDATA CBData;
Entry *pEntry = NULL;
if (SizeOut != NULL)
*SizeOut = 0;
PARAMETER_CHECK(SizeOut != NULL);
HeaderSize = sizeof(ACTIVATION_CONTEXT_GUID_SECTION_HEADER);
CBData.u.GetUserDataSize.DataSize = 0;
(*m_CallbackFunction)(m_CallbackContext, GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATASIZE, &CBData);
UserDataSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserDataSize.DataSize);
if ((m_EntryCount != 0) || (UserDataSize != 0))
{
EntryListSize = m_EntryCount * sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY);
for (pEntry = m_FirstEntry; pEntry != NULL; pEntry = pEntry->m_Next)
{
CBData.u.GetDataSize.DataContext = pEntry->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;
}
fSuccess = TRUE;
Exit:
return fSuccess;
}
BOOL
CGSGenCtx::GetSectionData(
SIZE_T BufferSize,
PVOID Buffer,
PSIZE_T BytesWritten
)
{
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
SIZE_T BytesSoFar = 0;
SIZE_T BytesLeft = BufferSize;
SIZE_T RoundedSize;
PACTIVATION_CONTEXT_GUID_SECTION_HEADER Header;
CALLBACKDATA CBData;
PVOID Cursor = NULL;
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 = m_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;
(*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;
(*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 (m_EntryCount != 0)
{
PVOID DataCursor;
PACTIVATION_CONTEXT_GUID_SECTION_ENTRY DstEntry;
PACTIVATION_CONTEXT_GUID_SECTION_ENTRY DstEntryArrayFirstElement;
Entry *SrcEntry;
if (BytesLeft < (m_EntryCount * sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY)))
ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
BytesLeft -= (m_EntryCount * sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY));
BytesSoFar += (m_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 + m_EntryCount);
SrcEntry = m_FirstEntry;
while (SrcEntry != NULL)
{
CBData.u.GetDataSize.DataContext = SrcEntry->m_DataContext;
CBData.u.GetDataSize.DataSize = 0;
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_INFO,
"SXS.DLL: Calling guid section generation callback with reason GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE\n"
" .DataContext = %p\n",
CBData.u.GetData.DataContext);
(*m_CallbackFunction)(m_CallbackContext, GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE, &CBData);
RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetDataSize.DataSize);
::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);
if (RoundedSize != 0)
{
if (BytesLeft < RoundedSize)
ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
CBData.u.GetData.SectionHeader = Header;
CBData.u.GetData.DataContext = SrcEntry->m_DataContext;
CBData.u.GetData.BufferSize = RoundedSize;
CBData.u.GetData.Buffer = DataCursor;
CBData.u.GetData.BytesWritten = 0;
::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);
(*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 = SrcEntry->m_AssemblyRosterIndex;
DataCursor = (PVOID) (((ULONG_PTR) DataCursor) + RoundedSize);
}
else
{
DstEntry->Offset = 0;
DstEntry->Length = 0;
DstEntry->AssemblyRosterIndex = 0;
}
DstEntry->Guid = SrcEntry->m_Guid;
SrcEntry = SrcEntry->m_Next;
DstEntry++;
}
//
// We compare the blobs via memcmp
//
if ( m_HashTableSize == 0 )
{
qsort( DstEntryArrayFirstElement, m_EntryCount, sizeof(*DstEntry), &CGSGenCtx::SortGuidSectionEntries );
Header->Flags |= ACTIVATION_CONTEXT_GUID_SECTION_ENTRIES_IN_ORDER;
}
}
if (BytesWritten != NULL)
*BytesWritten = BytesSoFar;
fSuccess = TRUE;
Exit:
return fSuccess;
}
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(
const GUID &rGuid,
PVOID DataContext,
ULONG AssemblyRosterIndex
)
{
m_Guid = rGuid;
m_DataContext = DataContext;
m_AssemblyRosterIndex = AssemblyRosterIndex;
return TRUE;
}