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

  1. /*
  2. Copyright (c) Microsoft Corporation
  3. */
  4. #include "stdinc.h"
  5. #include <windows.h>
  6. #include "sxsp.h"
  7. #include "gsgenctx.h"
  8. #include "sxsexceptionhandling.h"
  9. typedef struct _CALLBACKDATA
  10. {
  11. union
  12. {
  13. GUID_SECTION_GENERATION_CONTEXT_CBDATA_GETDATASIZE GetDataSize;
  14. GUID_SECTION_GENERATION_CONTEXT_CBDATA_GETDATA GetData;
  15. GUID_SECTION_GENERATION_CONTEXT_CBDATA_ENTRYDELETED EntryDeleted;
  16. GUID_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATASIZE GetUserDataSize;
  17. GUID_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATA GetUserData;
  18. } u;
  19. } CALLBACKDATA, *PCALLBACKDATA;
  20. BOOL CGSGenCtx::Create(
  21. PGUID_SECTION_GENERATION_CONTEXT *GSGenContext,
  22. ULONG DataFormatVersion,
  23. GUID_SECTION_GENERATION_CONTEXT_CALLBACK_FUNCTION CallbackFunction,
  24. PVOID CallbackContext
  25. )
  26. {
  27. FN_PROLOG_WIN32
  28. CGSGenCtx *pGSGenCtx;
  29. if (GSGenContext != NULL)
  30. *GSGenContext = NULL;
  31. PARAMETER_CHECK(GSGenContext != NULL);
  32. PARAMETER_CHECK(CallbackFunction != NULL);
  33. IFALLOCFAILED_EXIT(pGSGenCtx = new CGSGenCtx);
  34. pGSGenCtx->m_CallbackFunction = CallbackFunction;
  35. pGSGenCtx->m_CallbackContext = CallbackContext;
  36. pGSGenCtx->m_DataFormatVersion = DataFormatVersion;
  37. *GSGenContext = (PGUID_SECTION_GENERATION_CONTEXT) pGSGenCtx;
  38. FN_EPILOG
  39. }
  40. CGSGenCtx::CGSGenCtx()
  41. {
  42. m_HashTableSize = 0;
  43. }
  44. CGSGenCtx::~CGSGenCtx()
  45. {
  46. CSxsPreserveLastError ple;
  47. CALLBACKDATA CBData;
  48. CGuidPtrTableIter<Entry, EntryGuidTableHelper> iter(m_Table);
  49. for (iter.Reset(); iter.More(); iter.Next())
  50. {
  51. CBData.u.EntryDeleted.DataContext = iter->m_DataContext;
  52. (*m_CallbackFunction)(
  53. m_CallbackContext,
  54. GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_ENTRYDELETED,
  55. &CBData);
  56. iter->m_DataContext = NULL;
  57. }
  58. ple.Restore();
  59. }
  60. void
  61. CGSGenCtx::EntryGuidTableHelper::FinalizeValue(
  62. CGSGenCtx::Entry *&rpEntry
  63. )
  64. {
  65. FUSION_DELETE_SINGLETON(rpEntry);
  66. rpEntry = NULL;
  67. }
  68. BOOL
  69. CGSGenCtx::Add(
  70. const GUID &rGuid,
  71. PVOID DataContext,
  72. ULONG AssemblyRosterIndex,
  73. DWORD DuplicateErrorCode
  74. )
  75. {
  76. FN_PROLOG_WIN32
  77. CSmartPtr<Entry> pEntry;
  78. PARAMETER_CHECK(DuplicateErrorCode != ERROR_SUCCESS);
  79. // We'll assume that duplicates are rare, so we'll allocate the entry up front.
  80. IFW32FALSE_EXIT(pEntry.Win32Allocate(__FILE__, __LINE__));
  81. IFW32FALSE_EXIT(pEntry->Initialize(DataContext, AssemblyRosterIndex));
  82. IFW32FALSE_EXIT(m_Table.Insert(rGuid, pEntry));
  83. pEntry.Detach();
  84. FN_EPILOG
  85. }
  86. BOOL
  87. CGSGenCtx::Find(
  88. const GUID &rGuid,
  89. PVOID *DataContext
  90. )
  91. {
  92. FN_PROLOG_WIN32
  93. Entry *pEntry = NULL;
  94. if (DataContext != NULL)
  95. *DataContext = NULL;
  96. IFW32FALSE_EXIT(m_Table.Find(rGuid, pEntry));
  97. if (pEntry == NULL)
  98. ORIGINATE_WIN32_FAILURE_AND_EXIT(GuidNotInSection, ERROR_SXS_KEY_NOT_FOUND);
  99. if (DataContext != NULL)
  100. *DataContext = pEntry->m_DataContext;
  101. FN_EPILOG
  102. }
  103. BOOL
  104. CGSGenCtx::GetSectionSize(
  105. PSIZE_T SizeOut
  106. )
  107. {
  108. FN_PROLOG_WIN32
  109. SIZE_T UserDataSize = 0;
  110. SIZE_T HeaderSize = 0;
  111. SIZE_T EntryListSize = 0;
  112. SIZE_T EntryDataSize = 0;
  113. CALLBACKDATA CBData;
  114. Entry *pEntry = NULL;
  115. CGuidPtrTableIter<Entry, EntryGuidTableHelper> iter(m_Table);
  116. if (SizeOut != NULL)
  117. *SizeOut = 0;
  118. PARAMETER_CHECK(SizeOut != NULL);
  119. HeaderSize = sizeof(ACTIVATION_CONTEXT_GUID_SECTION_HEADER);
  120. CBData.u.GetUserDataSize.DataSize = 0;
  121. IFW32FALSE_EXIT((*m_CallbackFunction)(m_CallbackContext, GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATASIZE, &CBData));
  122. UserDataSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserDataSize.DataSize);
  123. for (iter.Reset(); iter.More(); iter.Next())
  124. {
  125. EntryListSize += sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY);
  126. CBData.u.GetDataSize.DataContext = iter->m_DataContext;
  127. CBData.u.GetDataSize.DataSize = 0;
  128. (*m_CallbackFunction)(m_CallbackContext, GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE, &CBData);
  129. EntryDataSize += ROUND_ACTCTXDATA_SIZE(CBData.u.GetDataSize.DataSize);
  130. }
  131. *SizeOut = HeaderSize + UserDataSize + EntryListSize + EntryDataSize;
  132. FN_EPILOG
  133. }
  134. BOOL
  135. CGSGenCtx::GetSectionData(
  136. SIZE_T BufferSize,
  137. PVOID Buffer,
  138. PSIZE_T BytesWritten
  139. )
  140. {
  141. FN_PROLOG_WIN32
  142. SIZE_T BytesSoFar = 0;
  143. SIZE_T BytesLeft = BufferSize;
  144. SIZE_T RoundedSize;
  145. PACTIVATION_CONTEXT_GUID_SECTION_HEADER Header;
  146. CALLBACKDATA CBData;
  147. PVOID Cursor = NULL;
  148. CGuidPtrTableIter<Entry, EntryGuidTableHelper> iter(m_Table);
  149. SIZE_T EntryCount = m_Table.GetEntryCount();
  150. if (BytesWritten != NULL)
  151. *BytesWritten = 0;
  152. if (BytesLeft < sizeof(ACTIVATION_CONTEXT_GUID_SECTION_HEADER))
  153. ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
  154. Header = (PACTIVATION_CONTEXT_GUID_SECTION_HEADER) Buffer;
  155. Cursor = (PVOID) (Header + 1);
  156. Header->Magic = ACTIVATION_CONTEXT_GUID_SECTION_MAGIC;
  157. Header->HeaderSize = sizeof(ACTIVATION_CONTEXT_GUID_SECTION_HEADER);
  158. Header->FormatVersion = ACTIVATION_CONTEXT_GUID_SECTION_FORMAT_WHISTLER;
  159. Header->DataFormatVersion = m_DataFormatVersion;
  160. Header->Flags = 0;
  161. Header->ElementCount = static_cast<ULONG>(EntryCount);
  162. Header->ElementListOffset = 0; // filled in after we figure out the user data area
  163. Header->SearchStructureOffset = 0;
  164. Header->UserDataOffset = 0; // filled in below
  165. Header->UserDataSize = 0;
  166. BytesLeft -= sizeof(*Header);
  167. BytesSoFar += sizeof(*Header);
  168. CBData.u.GetUserDataSize.DataSize = 0;
  169. IFW32FALSE_EXIT(
  170. (*m_CallbackFunction)(
  171. m_CallbackContext,
  172. GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATASIZE,
  173. &CBData));
  174. RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserDataSize.DataSize);
  175. if (RoundedSize != 0)
  176. {
  177. CBData.u.GetUserData.SectionHeader = Header;
  178. CBData.u.GetUserData.BufferSize = RoundedSize;
  179. CBData.u.GetUserData.Buffer = Cursor;
  180. CBData.u.GetUserData.BytesWritten = 0;
  181. IFW32FALSE_EXIT(
  182. (*m_CallbackFunction)(
  183. m_CallbackContext,
  184. GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATA,
  185. &CBData));
  186. ASSERT(CBData.u.GetUserData.BytesWritten <= RoundedSize);
  187. if (CBData.u.GetUserData.BytesWritten != 0)
  188. {
  189. RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserData.BytesWritten);
  190. BytesLeft -= RoundedSize;
  191. BytesSoFar += RoundedSize;
  192. Header->UserDataSize = static_cast<ULONG>(CBData.u.GetUserData.BytesWritten);
  193. Header->UserDataOffset = static_cast<LONG>(((LONG_PTR) Cursor) - ((LONG_PTR) Header));
  194. Cursor = (PVOID) (((ULONG_PTR) Cursor) + RoundedSize);
  195. }
  196. }
  197. // Finally the array of entries...
  198. if (EntryCount != 0)
  199. {
  200. PVOID DataCursor;
  201. PACTIVATION_CONTEXT_GUID_SECTION_ENTRY DstEntry;
  202. PACTIVATION_CONTEXT_GUID_SECTION_ENTRY DstEntryArrayFirstElement;
  203. if (BytesLeft < (EntryCount * sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY)))
  204. ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
  205. BytesLeft -= (EntryCount * sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY));
  206. BytesSoFar += (EntryCount * sizeof(ACTIVATION_CONTEXT_GUID_SECTION_ENTRY));
  207. //
  208. // DstEntryArrayFirstElement actually points to the first thing that we'll
  209. // be writing out, as DstEntry is ++'d across each of the elements as we
  210. // zip through the output buffer.
  211. //
  212. DstEntryArrayFirstElement = (PACTIVATION_CONTEXT_GUID_SECTION_ENTRY) Cursor;
  213. DstEntry = DstEntryArrayFirstElement;
  214. Header->ElementListOffset = static_cast<LONG>(((LONG_PTR) DstEntry) - ((LONG_PTR) Header));
  215. DataCursor = (PVOID) (DstEntry + EntryCount);
  216. for (iter.Reset(); iter.More(); iter.Next())
  217. {
  218. CBData.u.GetDataSize.DataContext = iter->m_DataContext;
  219. CBData.u.GetDataSize.DataSize = 0;
  220. IFW32FALSE_EXIT(
  221. (*m_CallbackFunction)(
  222. m_CallbackContext,
  223. GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE,
  224. &CBData));
  225. RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetDataSize.DataSize);
  226. #if DBG
  227. ::FusionpDbgPrintEx(
  228. FUSION_DBG_LEVEL_INFO,
  229. "SXS.DLL: Guid section generation callback (_GETDATASIZE) returned data size of %d (rounded to %Id)\n", CBData.u.GetDataSize.DataSize, RoundedSize);
  230. #endif
  231. if (RoundedSize != 0)
  232. {
  233. if (BytesLeft < RoundedSize)
  234. ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
  235. CBData.u.GetData.SectionHeader = Header;
  236. CBData.u.GetData.DataContext = iter->m_DataContext;
  237. CBData.u.GetData.BufferSize = RoundedSize;
  238. CBData.u.GetData.Buffer = DataCursor;
  239. CBData.u.GetData.BytesWritten = 0;
  240. #if DBG
  241. ::FusionpDbgPrintEx(
  242. FUSION_DBG_LEVEL_INFO,
  243. "SXS.DLL: Calling guid section generation callback with reason GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATA\n"
  244. " .DataContext = %p\n"
  245. " .BufferSize = %d\n"
  246. " .Buffer = %p\n",
  247. CBData.u.GetData.DataContext,
  248. CBData.u.GetData.BufferSize,
  249. CBData.u.GetData.Buffer);
  250. #endif
  251. IFW32FALSE_EXIT(
  252. (*m_CallbackFunction)(
  253. m_CallbackContext,
  254. GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATA,
  255. &CBData));
  256. if (CBData.u.GetData.BytesWritten != 0)
  257. {
  258. ASSERT(CBData.u.GetData.BytesWritten <= RoundedSize);
  259. RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetData.BytesWritten);
  260. INTERNAL_ERROR_CHECK(CBData.u.GetData.BytesWritten <= RoundedSize);
  261. BytesLeft -= RoundedSize;
  262. BytesSoFar += RoundedSize;
  263. DstEntry->Offset = static_cast<LONG>(((LONG_PTR) DataCursor) - ((LONG_PTR) Header));
  264. }
  265. else
  266. DstEntry->Offset = 0;
  267. DstEntry->Length = static_cast<ULONG>(CBData.u.GetData.BytesWritten);
  268. DstEntry->AssemblyRosterIndex = iter->m_AssemblyRosterIndex;
  269. DataCursor = (PVOID) (((ULONG_PTR) DataCursor) + RoundedSize);
  270. }
  271. else
  272. {
  273. DstEntry->Offset = 0;
  274. DstEntry->Length = 0;
  275. DstEntry->AssemblyRosterIndex = 0;
  276. }
  277. DstEntry->Guid = iter.GetKey();
  278. DstEntry++;
  279. }
  280. //
  281. // We compare the blobs via memcmp
  282. //
  283. if (m_HashTableSize == 0)
  284. {
  285. ::qsort(DstEntryArrayFirstElement, EntryCount, sizeof(*DstEntry), &CGSGenCtx::SortGuidSectionEntries);
  286. Header->Flags |= ACTIVATION_CONTEXT_GUID_SECTION_ENTRIES_IN_ORDER;
  287. }
  288. }
  289. if (BytesWritten != NULL)
  290. *BytesWritten = BytesSoFar;
  291. FN_EPILOG
  292. }
  293. int __cdecl
  294. CGSGenCtx::SortGuidSectionEntries(
  295. const void *elem1,
  296. const void *elem2
  297. )
  298. {
  299. //
  300. // The first thing in the structure is actually the GUID itself, but
  301. // we'll save problems later by casting and following the Guid
  302. // member.
  303. //
  304. const PACTIVATION_CONTEXT_GUID_SECTION_ENTRY pLeft = (const PACTIVATION_CONTEXT_GUID_SECTION_ENTRY)elem1;
  305. const PACTIVATION_CONTEXT_GUID_SECTION_ENTRY pRight = (const PACTIVATION_CONTEXT_GUID_SECTION_ENTRY)elem2;
  306. return memcmp( (const void*)&pLeft->Guid, (const void*)&pRight->Guid, sizeof(GUID) );
  307. }
  308. BOOL
  309. CGSGenCtx::Entry::Initialize(
  310. PVOID DataContext,
  311. ULONG AssemblyRosterIndex
  312. )
  313. {
  314. m_DataContext = DataContext;
  315. m_AssemblyRosterIndex = AssemblyRosterIndex;
  316. return TRUE;
  317. }