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.

922 lines
24 KiB

  1. #include "nt.h"
  2. #include "ntdef.h"
  3. #include "ntrtl.h"
  4. #include "nturtl.h"
  5. #include "stdio.h"
  6. #include "sxs-rtl.h"
  7. #include "fasterxml.h"
  8. #include "skiplist.h"
  9. #include "namespacemanager.h"
  10. #include "xmlstructure.h"
  11. #include "stdlib.h"
  12. #include "xmlassert.h"
  13. #ifdef INVALID_HANDLE_VALUE
  14. #undef INVALID_HANDLE_VALUE
  15. #endif
  16. #include "windows.h"
  17. #ifndef NUMBER_OF
  18. #define NUMBER_OF(x) (sizeof(x)/sizeof(*x))
  19. #endif
  20. NTSTATUS FASTCALL
  21. MyAllocator(SIZE_T cb, PVOID* pvOutput, PVOID pvAllocContext) {
  22. ASSERT(pvAllocContext == NULL);
  23. *pvOutput = HeapAlloc(GetProcessHeap(), 0, cb);
  24. return *pvOutput ? STATUS_SUCCESS : STATUS_NO_MEMORY;
  25. }
  26. NTSTATUS FASTCALL
  27. MyFreer(PVOID pv, PVOID pvAllocContext) {
  28. ASSERT(pvAllocContext == NULL);
  29. return HeapFree(GetProcessHeap(), 0, pv) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  30. }
  31. EXTERN_C RTL_ALLOCATOR g_DefaultAllocator = {MyAllocator, MyFreer, NULL};
  32. //
  33. // The longest an assembly name on-disk can be is:
  34. //
  35. // wow6432 (7)
  36. // _ (1)
  37. // {name} (64)
  38. // _ (1)
  39. // PKT (16)
  40. // _ (1)
  41. // Version (35)
  42. // _ (1)
  43. // Language (5)
  44. // _ (1)
  45. // {Hash} (8)
  46. //
  47. // Total: ----> 140 (plus NULL)
  48. //
  49. #define MAX_ASSEMBLY_NAME_LENGTH (140)
  50. #define MAX_ASSEMBLY_COMPONENT_LENGTH (64)
  51. typedef struct _tagASM_IDENT_COMPONENT {
  52. PXML_TOKENIZATION_STATE pState;
  53. XML_EXTENT Namespace;
  54. XML_EXTENT Attribute;
  55. XML_EXTENT Value;
  56. }
  57. ASM_IDENT_COMPONENT, *PASM_IDENT_COMPONENT;
  58. #define MAKE_SPECIAL(q) { L ## q, NUMBER_OF(L##q) - 1 }
  59. static XML_SPECIAL_STRING AssemblyIdentity = MAKE_SPECIAL("assemblyIdentity");
  60. static XML_SPECIAL_STRING Assembly = MAKE_SPECIAL("assembly");
  61. static XML_SPECIAL_STRING OurNamespace = MAKE_SPECIAL("urn:schemas-microsoft-com:asm.v1");
  62. static XML_SPECIAL_STRING ss_ident_Name = MAKE_SPECIAL("name");
  63. static XML_SPECIAL_STRING ss_ident_Version = MAKE_SPECIAL("version");
  64. static XML_SPECIAL_STRING ss_ident_PKT = MAKE_SPECIAL("publicKeyToken");
  65. static XML_SPECIAL_STRING ss_ident_Language = MAKE_SPECIAL("language");
  66. static XML_SPECIAL_STRING ss_ident_ProcArch = MAKE_SPECIAL("processorArchitecture");
  67. int __cdecl
  68. _CompareIdentityComponents(
  69. const void *pvLeft,
  70. const void *pvRight
  71. )
  72. {
  73. PASM_IDENT_COMPONENT pCompLeft = (PASM_IDENT_COMPONENT)pvLeft;
  74. PASM_IDENT_COMPONENT pCompRight = (PASM_IDENT_COMPONENT)pvRight;
  75. NTSTATUS status = STATUS_SUCCESS;
  76. XML_STRING_COMPARE Result;
  77. int iResult = 0;
  78. ASSERT(pCompLeft->pState == pCompRight->pState);
  79. status = pCompLeft->pState->pfnCompareStrings(
  80. pCompLeft->pState,
  81. &pCompLeft->Namespace,
  82. &pCompRight->Namespace,
  83. &Result);
  84. //
  85. // We're sorting... can't really stop here, return "equal"
  86. //
  87. if (!NT_SUCCESS(status)) {
  88. goto Exit;
  89. }
  90. //
  91. // Same namespace, compare attribute names
  92. //
  93. if (Result == XML_STRING_COMPARE_EQUALS) {
  94. int printf(const char*, ...);
  95. status = pCompLeft->pState->pfnCompareStrings(
  96. pCompLeft->pState,
  97. &pCompLeft->Attribute,
  98. &pCompRight->Attribute,
  99. &Result);
  100. if (!NT_SUCCESS(status)) {
  101. goto Exit;
  102. }
  103. //
  104. // Nicely enough, the result really has -1, 1, 0 property.
  105. //
  106. iResult = (int)Result;
  107. //
  108. // Ick, we should never have two attributes with the same name
  109. // in the same namespace on an element.
  110. //
  111. ASSERT(iResult != 0);
  112. }
  113. Exit:
  114. return iResult;
  115. }
  116. static NTSTATUS
  117. _CompareStrings(
  118. PVOID pvContext,
  119. PXML_EXTENT pLeft,
  120. PXML_EXTENT pRight,
  121. BOOLEAN *pfMatches
  122. )
  123. {
  124. XML_LOGICAL_STATE *pState = (XML_LOGICAL_STATE*)pvContext;
  125. NTSTATUS status;
  126. XML_STRING_COMPARE Compare;
  127. *pfMatches = FALSE;
  128. status = pState->ParseState.pfnCompareStrings(
  129. &pState->ParseState,
  130. pLeft,
  131. pRight,
  132. &Compare);
  133. if (NT_SUCCESS(status)) {
  134. *pfMatches = (Compare == XML_STRING_COMPARE_EQUALS);
  135. }
  136. return status;
  137. }
  138. #define HASH_MULT_CONSTANT (65599)
  139. static NTSTATUS FASTCALL
  140. HashXmlExtent(
  141. PXML_RAWTOKENIZATION_STATE pState,
  142. PXML_EXTENT pExtent,
  143. PULONG pulHash
  144. )
  145. {
  146. PVOID pvOriginal;
  147. ULONG ulCharacter;
  148. ULONG ulHashResult = 0;
  149. NTSTATUS status = STATUS_SUCCESS;
  150. SIZE_T cbHashed = 0;
  151. *pulHash = 0;
  152. ASSERT(pState->cbBytesInLastRawToken == pState->DefaultCharacterSize);
  153. ASSERT(NT_SUCCESS(pState->NextCharacterResult));
  154. pvOriginal = pState->pvCursor;
  155. pState->pvCursor = pExtent->pvData;
  156. for (cbHashed = 0; cbHashed < pExtent->cbData;) {
  157. ulCharacter = pState->pfnNextChar(pState);
  158. if ((ulCharacter == 0) && !NT_SUCCESS(pState->NextCharacterResult)) {
  159. status = pState->NextCharacterResult;
  160. goto Exit;
  161. }
  162. else if (ulCharacter > 0xFFFF) {
  163. status = STATUS_INVALID_PARAMETER;
  164. goto Exit;
  165. }
  166. ulHashResult = (ulHashResult * HASH_MULT_CONSTANT) + towupper((WCHAR)ulCharacter);
  167. pState->pvCursor = (PBYTE)pState->pvCursor + pState->cbBytesInLastRawToken;
  168. cbHashed += pState->cbBytesInLastRawToken;
  169. if (pState->cbBytesInLastRawToken != pState->DefaultCharacterSize) {
  170. pState->cbBytesInLastRawToken = pState->DefaultCharacterSize;
  171. }
  172. }
  173. *pulHash = ulHashResult;
  174. Exit:
  175. pState->pvCursor = pvOriginal;
  176. return status;
  177. }
  178. static NTSTATUS FASTCALL
  179. HashIdentityElement(
  180. PASM_IDENT_COMPONENT pIdent,
  181. PULONG pulHash
  182. )
  183. {
  184. ULONG ulHashValue = 0;
  185. ULONG ulTempHashValue = 0;
  186. NTSTATUS status = STATUS_SUCCESS;
  187. XML_STRING_COMPARE Compare;
  188. status = HashXmlExtent(&pIdent->pState->RawTokenState, &pIdent->Namespace, &ulTempHashValue);
  189. ulHashValue = (ulHashValue * HASH_MULT_CONSTANT) + ulTempHashValue;
  190. if (!NT_SUCCESS(status)) {
  191. goto Exit;
  192. }
  193. status = HashXmlExtent(&pIdent->pState->RawTokenState, &pIdent->Attribute, &ulTempHashValue);
  194. ulHashValue = (ulHashValue * HASH_MULT_CONSTANT) + ulTempHashValue;
  195. if (!NT_SUCCESS(status)) {
  196. goto Exit;
  197. }
  198. status = HashXmlExtent(&pIdent->pState->RawTokenState, &pIdent->Value, &ulTempHashValue);
  199. ulHashValue = (ulHashValue * HASH_MULT_CONSTANT) + ulTempHashValue;
  200. if (!NT_SUCCESS(status)) {
  201. goto Exit;
  202. }
  203. *pulHash = ulHashValue;
  204. Exit:
  205. return status;
  206. }
  207. static NTSTATUS
  208. CalculateIdentityHash(
  209. PASM_IDENT_COMPONENT pIdents,
  210. SIZE_T cIdents,
  211. ULONG *pulHash
  212. )
  213. {
  214. SIZE_T c = 0;
  215. ULONG ulHash = 0;
  216. NTSTATUS status = STATUS_SUCCESS;
  217. *pulHash = 0;
  218. for (c = 0; c < cIdents; c++) {
  219. ULONG ulTempHash;
  220. status = HashIdentityElement(pIdents + c, &ulTempHash);
  221. if (!NT_SUCCESS(status)) {
  222. goto Exit;
  223. }
  224. ulHash = (ulHash * HASH_MULT_CONSTANT) + ulTempHash;
  225. }
  226. *pulHash = ulHash;
  227. Exit:
  228. return status;
  229. }
  230. static int __cdecl
  231. _FindIdentityComponents(
  232. const XML_SPECIAL_STRING* pKeyString,
  233. const PASM_IDENT_COMPONENT pComponent
  234. )
  235. {
  236. NTSTATUS status;
  237. XML_STRING_COMPARE Compare = XML_STRING_COMPARE_GT;
  238. //
  239. // Our attributes all live in the 'null' namespace
  240. //
  241. if (pComponent->Namespace.cbData == 0) {
  242. status = pComponent->pState->pfnCompareSpecialString(
  243. pComponent->pState,
  244. &pComponent->Attribute,
  245. (XML_SPECIAL_STRING*)pKeyString,
  246. &Compare);
  247. ASSERT(NT_SUCCESS(status));
  248. //
  249. // On failure, make sure we don't match this one - checked builds
  250. // will assert above and point out the error
  251. //
  252. if (!NT_SUCCESS(status)) {
  253. Compare = XML_STRING_COMPARE_GT;
  254. }
  255. }
  256. return (int)Compare;
  257. }
  258. int (__cdecl *pfnIdentCompare)(const void*, const void*) = (int (__cdecl*)(const void*, const void*))_FindIdentityComponents;
  259. #define NO_PKT_PRESENT ("no-public-key")
  260. #define NO_VERSION_PRESENT ("0.0.0.0")
  261. #define WORLD_WIDE_LANGUAGE ("x-ww")
  262. #define IsValidChar(q) (((q >= 'a') && (q <= 'z')) || ((q >= 'A') && (q <= 'Z')) || ((q >= '0') && (q <= '9')) || (q == '.') || (q == '-'))
  263. static NTSTATUS
  264. ExtentToPurifiedString(
  265. PASM_IDENT_COMPONENT pIdent,
  266. PCSTR pcszDefault,
  267. PSTR *pszPureString,
  268. PSIZE_T pcchThis
  269. )
  270. {
  271. NTSTATUS status = STATUS_SUCCESS;
  272. WCHAR wchBuffer[MAX_ASSEMBLY_COMPONENT_LENGTH];
  273. PWSTR pwszString = wchBuffer;
  274. SIZE_T cchWritten = 0;
  275. SIZE_T cchOutput = 0;
  276. SIZE_T i;
  277. if ((*pcchThis > 0) && (*pszPureString == NULL)) {
  278. return STATUS_INVALID_PARAMETER;
  279. }
  280. if (!pIdent) {
  281. //
  282. // Input string too small? Allocate and return a new one
  283. //
  284. if (strlen(pcszDefault) > *pcchThis) {
  285. *pszPureString = HeapAlloc(GetProcessHeap(), 0, *pcchThis);
  286. }
  287. strcpy(*pszPureString, pcszDefault);
  288. *pcchThis = strlen(pcszDefault);
  289. goto Exit;
  290. }
  291. //
  292. // Start by getting the string out of the extent
  293. //
  294. cchWritten = NUMBER_OF(wchBuffer);
  295. status = RtlXmlCopyStringOut(
  296. pIdent->pState,
  297. &pIdent->Value,
  298. wchBuffer,
  299. &cchWritten);
  300. //
  301. // Oops, allocate a buffer large enough and try again
  302. //
  303. if (status == STATUS_BUFFER_TOO_SMALL) {
  304. pwszString = (PWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (++cchWritten));
  305. if (pwszString == NULL) {
  306. status = STATUS_NO_MEMORY;
  307. goto Exit;
  308. }
  309. status = RtlXmlCopyStringOut(pIdent->pState, &pIdent->Value, pwszString, &cchWritten);
  310. }
  311. if (!NT_SUCCESS(status)) {
  312. goto Exit;
  313. }
  314. //
  315. // How long is the output string?
  316. //
  317. for (i = 0; i < cchWritten; i++) {
  318. if (IsValidChar(pwszString[i])) {
  319. cchOutput++;
  320. }
  321. }
  322. //
  323. // Needs more in the output, reallocate
  324. //
  325. if (cchOutput >= *pcchThis) {
  326. *pszPureString = (PSTR)HeapAlloc(GetProcessHeap(), 0, cchOutput + 1);
  327. }
  328. *pcchThis = cchOutput;
  329. cchOutput = 0;
  330. //
  331. // Now copy characters over
  332. //
  333. for (i = 0; i < cchWritten; i++) {
  334. if (IsValidChar(pwszString[i])) {
  335. (*pszPureString)[cchOutput++] = (CHAR)(pwszString[i] & 0xFF);
  336. }
  337. }
  338. (*pszPureString)[cchOutput] = 0;
  339. Exit:
  340. if ((pwszString != wchBuffer) && pwszString) {
  341. HeapFree(GetProcessHeap(), 0, (PVOID)pwszString);
  342. pwszString = wchBuffer;
  343. }
  344. return status;
  345. }
  346. static NTSTATUS
  347. FixUpNamePortion(
  348. PSTR pszOutputCursor,
  349. PSIZE_T pcchThis
  350. )
  351. {
  352. ULONG ulSpaceLeft = 64;
  353. ULONG i, len;
  354. PSTR pszOriginalStart = pszOutputCursor;
  355. PSTR pszOriginalEnd = pszOriginalStart + *pcchThis;
  356. PSTR pLeftEnd = pszOutputCursor;
  357. PSTR pRightStart = pszOriginalEnd;
  358. PSTR pszStart, pszEnd, qEnd;
  359. CHAR chBuffer[64];
  360. while (pszOriginalStart < pszOriginalEnd) {
  361. pszStart = pszOriginalStart;
  362. i = 0;
  363. while((strchr(".-", pszStart[i]) == 0) && ((pszStart + i) != pRightStart))
  364. i++;
  365. pszEnd = pszStart + i;
  366. len = i;
  367. if (len >= (ulSpaceLeft - 2)) {
  368. pLeftEnd += (ulSpaceLeft - 2);
  369. break;
  370. }
  371. ulSpaceLeft -= len;
  372. pLeftEnd = pszEnd;
  373. qEnd = pszOriginalEnd;
  374. i = 0;
  375. while (((qEnd + i) != pLeftEnd) && (strchr(".-", qEnd[i]) == 0))
  376. i--;
  377. len = 0 - i;
  378. if (len >= (ulSpaceLeft - 2)) {
  379. pRightStart -= ulSpaceLeft - 2;
  380. break;
  381. }
  382. ulSpaceLeft -= len;
  383. pszOriginalStart = pLeftEnd + 1;
  384. pszOriginalEnd = pRightStart - 1;
  385. }
  386. strncpy(chBuffer, pszOutputCursor, pLeftEnd - pszOutputCursor);
  387. strcat(chBuffer, "..");
  388. strcat(chBuffer, pRightStart);
  389. strcpy(pszOutputCursor, chBuffer);
  390. *pcchThis = strlen(chBuffer);
  391. return STATUS_SUCCESS;
  392. }
  393. static NTSTATUS
  394. ProcessFile(
  395. PVOID pvData,
  396. SIZE_T cbData,
  397. PSTR pszTarget,
  398. SIZE_T *pcchTarget
  399. )
  400. {
  401. WCHAR wchComponentBuffer[MAX_ASSEMBLY_COMPONENT_LENGTH];
  402. ULONG ulIdentComponents = 0;
  403. ULONG i = 0;
  404. ULONG ulHash;
  405. NTSTATUS status;
  406. NS_MANAGER NamespaceManager;
  407. XMLDOC_THING DocumentPiece;
  408. RTL_GROWING_LIST AttributeList;
  409. XML_STRING_COMPARE fMatching;
  410. XML_LOGICAL_STATE MasterParseState;
  411. PASM_IDENT_COMPONENT pIdentComponents = NULL;
  412. status = RtlInitializeGrowingList(
  413. &AttributeList,
  414. sizeof(XMLDOC_ATTRIBUTE),
  415. 20,
  416. NULL,
  417. 0,
  418. &g_DefaultAllocator);
  419. if (!NT_SUCCESS(status)) {
  420. return status;
  421. }
  422. status = RtlXmlInitializeNextLogicalThing(
  423. &MasterParseState,
  424. pvData,
  425. cbData,
  426. &g_DefaultAllocator);
  427. status = RtlNsInitialize(
  428. &NamespaceManager,
  429. RtlXmlDefaultCompareStrings,
  430. &MasterParseState,
  431. &g_DefaultAllocator);
  432. while (NT_SUCCESS(status)) {
  433. status = RtlXmlNextLogicalThing(
  434. &MasterParseState,
  435. &NamespaceManager,
  436. &DocumentPiece,
  437. &AttributeList);
  438. if (!NT_SUCCESS(status)) {
  439. break;
  440. }
  441. if ((DocumentPiece.ulThingType == XMLDOC_THING_ERROR) ||
  442. (DocumentPiece.ulThingType == XMLDOC_THING_END_OF_STREAM)) {
  443. break;
  444. }
  445. //
  446. // Level 1 or non-elements are simply ignored
  447. //
  448. if ((DocumentPiece.ulDocumentDepth != 1) || (DocumentPiece.ulThingType != XMLDOC_THING_ELEMENT))
  449. continue;
  450. //
  451. // Find out the namespace that this thing is in
  452. //
  453. status = MasterParseState.ParseState.pfnCompareSpecialString(
  454. &MasterParseState.ParseState,
  455. &DocumentPiece.Element.NsPrefix,
  456. &OurNamespace,
  457. &fMatching);
  458. //
  459. // Error, stop
  460. //
  461. if (!NT_SUCCESS(status)) {
  462. goto Exit;
  463. }
  464. //
  465. // Go on then, off with ye.
  466. //
  467. else if (fMatching != XML_STRING_COMPARE_EQUALS) {
  468. continue;
  469. }
  470. //
  471. // Is this assembly identity?
  472. //
  473. status = MasterParseState.ParseState.pfnCompareSpecialString(
  474. &MasterParseState.ParseState,
  475. &DocumentPiece.Element.Name,
  476. &AssemblyIdentity,
  477. &fMatching);
  478. if (!NT_SUCCESS(status)) {
  479. goto Exit;
  480. }
  481. else if (fMatching != XML_STRING_COMPARE_EQUALS) {
  482. continue;
  483. }
  484. //
  485. // Good, so now we need to look at the attributes
  486. //
  487. ulIdentComponents = DocumentPiece.Element.ulAttributeCount;
  488. pIdentComponents = (PASM_IDENT_COMPONENT)HeapAlloc(
  489. GetProcessHeap(),
  490. HEAP_ZERO_MEMORY,
  491. ulIdentComponents * sizeof(*pIdentComponents));
  492. //
  493. // Copy stuff around
  494. //
  495. for (i = 0; i < ulIdentComponents; i++) {
  496. PXMLDOC_ATTRIBUTE pThisAttribute = NULL;
  497. status = RtlIndexIntoGrowingList(
  498. &AttributeList,
  499. i,
  500. (PVOID*)&pThisAttribute,
  501. FALSE);
  502. if (!NT_SUCCESS(status)) {
  503. goto Exit;
  504. }
  505. pIdentComponents[i].Attribute = pThisAttribute->Name;
  506. pIdentComponents[i].Namespace = pThisAttribute->NsPrefix;
  507. pIdentComponents[i].Value = pThisAttribute->Value;
  508. pIdentComponents[i].pState = &MasterParseState.ParseState;
  509. }
  510. break;
  511. }
  512. //
  513. // Something bad? Quit.
  514. //
  515. if (!NT_SUCCESS(status) || !pIdentComponents) {
  516. goto Exit;
  517. }
  518. //
  519. // Sort attributes first, then go and create the list of things to be sent to the
  520. // identity generator
  521. //
  522. qsort(pIdentComponents, ulIdentComponents, sizeof(ASM_IDENT_COMPONENT), _CompareIdentityComponents);
  523. //
  524. // Now for each component of the name part...
  525. //
  526. if (!NT_SUCCESS(status = CalculateIdentityHash(pIdentComponents, ulIdentComponents, &ulHash))) {
  527. return status;
  528. }
  529. //
  530. // Sort and send out the pointer on success
  531. //
  532. if (NT_SUCCESS(status) && pIdentComponents && ulIdentComponents) {
  533. struct {
  534. XML_SPECIAL_STRING *pNameBit;
  535. PCSTR pszDefault;
  536. BOOL fIsName;
  537. } NameOperations[] =
  538. {
  539. { &ss_ident_ProcArch, "data", FALSE },
  540. { &ss_ident_Name, NULL, TRUE },
  541. { &ss_ident_PKT, NO_PKT_PRESENT, FALSE },
  542. { &ss_ident_Version, NO_VERSION_PRESENT, FALSE },
  543. { &ss_ident_Language, WORLD_WIDE_LANGUAGE, FALSE }
  544. };
  545. PSTR pszOutputCursor = pszTarget;
  546. SIZE_T cchTotal = 0, cchThis, cchRemaining;
  547. for (i = 0; i < NUMBER_OF(NameOperations); i++) {
  548. PASM_IDENT_COMPONENT pThisOne = NULL;
  549. CHAR szStaticPureString[64];
  550. PSTR pszPureString = szStaticPureString;
  551. SIZE_T cchPureString = NUMBER_OF(szStaticPureString);
  552. //
  553. // This segment can have this many characters in it
  554. //
  555. cchThis = *pcchTarget - cchTotal;
  556. //
  557. // Find the identity part
  558. //
  559. pThisOne = bsearch(NameOperations[i].pNameBit, pIdentComponents, ulIdentComponents, sizeof(*pIdentComponents), pfnIdentCompare);
  560. //
  561. // Append the extent to the output cursor
  562. //
  563. status = ExtentToPurifiedString(
  564. pThisOne,
  565. NameOperations[i].pszDefault,
  566. &pszPureString,
  567. &cchPureString);
  568. //
  569. // If this is the name part, adjust it downward sizewize before seeing if there's space
  570. // in the output buffer
  571. //
  572. if (NameOperations[i].fIsName && (cchPureString > 64)) {
  573. status = FixUpNamePortion(pszPureString, &cchPureString);
  574. if (!NT_SUCCESS(status)) {
  575. //
  576. // Ensure the buffer is freed before returning
  577. //
  578. if (pszPureString && (pszPureString != szStaticPureString)) {
  579. HeapFree(GetProcessHeap(), 0, (PVOID)pszPureString);
  580. pszPureString = szStaticPureString;
  581. }
  582. goto Exit;
  583. }
  584. }
  585. //
  586. // No space in the output buffer, or there was no output buffer
  587. //
  588. if (!pszOutputCursor || (cchPureString > (*pcchTarget - cchTotal))) {
  589. pszOutputCursor = NULL;
  590. cchThis = cchPureString + 1;
  591. }
  592. //
  593. // Otherwise, copy the pure string onto the output cursor
  594. //
  595. else {
  596. strncpy(pszOutputCursor, pszPureString, cchPureString);
  597. pszOutputCursor[cchPureString] = '_';
  598. cchThis = cchPureString + 1;
  599. pszOutputCursor += cchThis;
  600. }
  601. if (pszPureString && (pszPureString != szStaticPureString)) {
  602. HeapFree(GetProcessHeap(), 0, (PVOID)pszPureString);
  603. }
  604. cchTotal += cchThis;
  605. }
  606. if (pszOutputCursor && ((*pcchTarget - cchTotal) > 8)) {
  607. sprintf(pszOutputCursor, "%08lx", ulHash);
  608. }
  609. cchTotal += 9;
  610. if (*pcchTarget < cchTotal) {
  611. status = STATUS_BUFFER_TOO_SMALL;
  612. }
  613. *pcchTarget = cchTotal;
  614. }
  615. Exit:
  616. if (pIdentComponents) {
  617. HeapFree(GetProcessHeap(), 0, (PVOID)pIdentComponents);
  618. pIdentComponents = NULL;
  619. }
  620. RtlDestroyGrowingList(&AttributeList);
  621. return status;
  622. }
  623. BOOL
  624. SxsIdentDetermineManifestPlacementPathEx(
  625. DWORD dwFlags,
  626. PVOID pvManifestData,
  627. SIZE_T cbLength,
  628. PSTR pszPlacementPath,
  629. SIZE_T *pcchPlacementPath
  630. )
  631. {
  632. BOOL fSuccess = FALSE;
  633. NTSTATUS status;
  634. if (pszPlacementPath) {
  635. *pszPlacementPath = UNICODE_NULL;
  636. }
  637. //
  638. // Go do the thing
  639. //
  640. status = ProcessFile(pvManifestData, cbLength, pszPlacementPath, pcchPlacementPath);
  641. switch (status) {
  642. case STATUS_NO_MEMORY:
  643. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  644. break;
  645. case STATUS_BUFFER_TOO_SMALL:
  646. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  647. break;
  648. case STATUS_NOT_FOUND:
  649. SetLastError(ERROR_FILE_NOT_FOUND);
  650. break;
  651. case STATUS_SUCCESS:
  652. fSuccess = TRUE;
  653. SetLastError(ERROR_SUCCESS);
  654. break;
  655. default:
  656. SetLastError(ERROR_GEN_FAILURE);
  657. break;
  658. }
  659. return fSuccess;
  660. }
  661. BOOL
  662. SxsIdentDetermineManifestPlacementPath(
  663. DWORD dwFlags,
  664. PCWSTR pcwszManifestPath,
  665. PSTR pszPlacementPath,
  666. SIZE_T *cchPlacementPath
  667. )
  668. {
  669. UINT cchUserBufferSize;
  670. BOOL fSuccess = FALSE;
  671. HANDLE hFile = INVALID_HANDLE_VALUE;
  672. PVOID pvFileData = NULL;
  673. HANDLE hFileMapping = INVALID_HANDLE_VALUE;
  674. DWORD dwFileSize = 0;
  675. PASM_IDENT_COMPONENT pAsmIdentSorted = NULL;
  676. SIZE_T cAsmIdent = 0, cTemp;
  677. //
  678. // Some minimal requirements
  679. //
  680. if ((dwFlags != 0) || !pcwszManifestPath || !cchPlacementPath ||
  681. ((*cchPlacementPath > 0) && (pszPlacementPath == NULL)))
  682. {
  683. SetLastError(ERROR_INVALID_PARAMETER);
  684. goto Exit;
  685. }
  686. if (pszPlacementPath) {
  687. *pszPlacementPath = UNICODE_NULL;
  688. }
  689. hFile = CreateFileW(
  690. pcwszManifestPath,
  691. GENERIC_READ,
  692. FILE_SHARE_READ,
  693. NULL,
  694. OPEN_EXISTING,
  695. FILE_ATTRIBUTE_NORMAL,
  696. NULL);
  697. if (hFile == INVALID_HANDLE_VALUE) {
  698. goto Exit;
  699. }
  700. dwFileSize = GetFileSize(hFile, NULL);
  701. hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);
  702. if ((hFileMapping == NULL) || (hFileMapping == INVALID_HANDLE_VALUE)) {
  703. goto Exit;
  704. }
  705. pvFileData = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, dwFileSize);
  706. if (pvFileData == NULL) {
  707. goto Exit;
  708. }
  709. fSuccess = SxsIdentDetermineManifestPlacementPathEx(
  710. dwFlags,
  711. pvFileData,
  712. dwFileSize,
  713. pszPlacementPath,
  714. cchPlacementPath);
  715. Exit:
  716. if (pvFileData != NULL) {
  717. UnmapViewOfFile(pvFileData);
  718. pvFileData = NULL;
  719. }
  720. if (hFile != INVALID_HANDLE_VALUE) {
  721. CloseHandle(hFile);
  722. hFile = INVALID_HANDLE_VALUE;
  723. }
  724. if (hFileMapping != INVALID_HANDLE_VALUE) {
  725. CloseHandle(hFileMapping);
  726. hFileMapping = INVALID_HANDLE_VALUE;
  727. }
  728. return fSuccess;
  729. }