#include "stdinc.h" #include #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(CBData.u.GetUserData.BytesWritten); Header->UserDataOffset = static_cast(((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_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_PTR) DataCursor) - ((LONG_PTR) Header)); } else DstEntry->Offset = 0; DstEntry->Length = static_cast(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; }