Source code of Windows XP (NT5)
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.

419 lines
12 KiB

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