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.

4373 lines
141 KiB

  1. /*
  2. Copyright (c) Microsoft Corporation
  3. */
  4. #include "stdinc.h"
  5. #include <windows.h>
  6. #include "fusionstring.h"
  7. #include "sxsp.h"
  8. #include <stdio.h>
  9. #include "fusionhandle.h"
  10. #include "sxspath.h"
  11. #include "sxsapi.h"
  12. #include "sxsid.h"
  13. #include "sxsidp.h"
  14. #include "strongname.h"
  15. #include "fusiontrace.h"
  16. #include "cassemblyrecoveryinfo.h"
  17. #include "recover.h"
  18. #include "sxsinstall.h"
  19. #include "msi.h"
  20. // diff shrinkers to be propated and removed..
  21. #define IsHexDigit SxspIsHexDigit
  22. #define HexDigitToValue SxspHexDigitToValue
  23. #define ASSEMBLY_NAME_VALID_SPECIAL_CHARACTERS L".-"
  24. #define ASSEMBLY_NAME_INVALID_CHARACTERS L"_\/:?*"
  25. #define ASSEMBLY_NAME_VALID_SEPARATORS L"."
  26. #define ASSEMBLY_NAME_TRIM_INDICATOR L".."
  27. #define ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH 2
  28. #define ASSEMBLY_NAME_PRIM_MAX_LENGTH 64
  29. #define ASSEMBLY_STRONG_NAME_LENGTH 16
  30. #define ULONG_STRING_FORMAT L"%08lx"
  31. #define ULONG_STRING_LENGTH 8
  32. #define MSI_PROVIDEASSEMBLY_NAME ("MsiProvideAssemblyW")
  33. #define MSI_DLL_NAME_W (L"msi.dll")
  34. #ifndef INSTALLMODE_NODETECTION_ANY
  35. #define INSTALLMODE_NODETECTION_ANY (INSTALLMODE)-4
  36. #endif
  37. // Honest, we exist - Including all of sxsprotect.h is too much in this case.
  38. BOOL SxspIsSfcIgnoredStoreSubdir(PCWSTR pwszDir);
  39. // deliberately no surrounding parens or trailing comma
  40. #define STRING_AND_LENGTH(x) (x), (NUMBER_OF(x) - 1)
  41. /*-----------------------------------------------------------------------------
  42. this makes the temp install be %windir%\WinSxs\InstallTemp\uid
  43. instead of %windir%\WinSxs\uid
  44. -----------------------------------------------------------------------------*/
  45. #define SXSP_SEMIREADABLE_INSTALL_TEMP 1
  46. const static HKEY hKeyRunOnceRoot = HKEY_LOCAL_MACHINE;
  47. const static WCHAR rgchRunOnceSubKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
  48. const static WCHAR rgchRunOnceValueNameBase[] = L"WinSideBySideSetupCleanup ";
  49. /*-----------------------------------------------------------------------------
  50. append the directory name to this and put it in RunOnce in the registry
  51. to cleanup crashed installs upon login
  52. -----------------------------------------------------------------------------*/
  53. const static WCHAR rgchRunOnePrefix[] = L"rundll32 sxs.dll,SxspRunDllDeleteDirectory ";
  54. #define SXSP_PROBING_CANDIDATE_FLAG_USES_LANGUAGE_SUBDIRECTORY (0x00000001)
  55. #define SXSP_PROBING_CANDIDATE_FLAG_IS_PRIVATE_ASSEMBLY (0x00000002)
  56. #define SXSP_PROBING_CANDIDATE_FLAG_IS_NDP_GAC (0x00000004)
  57. static const struct _SXSP_PROBING_CANDIDATE
  58. {
  59. PCWSTR Pattern;
  60. DWORD Flags;
  61. } s_rgProbingCandidates[] =
  62. {
  63. { L"$M", 0 },
  64. { L"$G\\$N.DLL", SXSP_PROBING_CANDIDATE_FLAG_IS_NDP_GAC },
  65. { L"$.$L$N.DLL", SXSP_PROBING_CANDIDATE_FLAG_USES_LANGUAGE_SUBDIRECTORY | SXSP_PROBING_CANDIDATE_FLAG_IS_PRIVATE_ASSEMBLY },
  66. { L"$.$L$N.MANIFEST", SXSP_PROBING_CANDIDATE_FLAG_USES_LANGUAGE_SUBDIRECTORY | SXSP_PROBING_CANDIDATE_FLAG_IS_PRIVATE_ASSEMBLY },
  67. { L"$.$L$N\\$N.DLL", SXSP_PROBING_CANDIDATE_FLAG_USES_LANGUAGE_SUBDIRECTORY | SXSP_PROBING_CANDIDATE_FLAG_IS_PRIVATE_ASSEMBLY },
  68. { L"$.$L$N\\$N.MANIFEST", SXSP_PROBING_CANDIDATE_FLAG_USES_LANGUAGE_SUBDIRECTORY | SXSP_PROBING_CANDIDATE_FLAG_IS_PRIVATE_ASSEMBLY },
  69. };
  70. const static struct
  71. {
  72. ULONG ThreadingModel;
  73. WCHAR String[10];
  74. SIZE_T Cch;
  75. } gs_rgTMMap[] =
  76. {
  77. { ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_THREADING_MODEL_APARTMENT, STRING_AND_LENGTH(L"Apartment") },
  78. { ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_THREADING_MODEL_FREE, STRING_AND_LENGTH(L"Free") },
  79. { ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_THREADING_MODEL_SINGLE, STRING_AND_LENGTH(L"Single") },
  80. { ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_THREADING_MODEL_BOTH, STRING_AND_LENGTH(L"Both") },
  81. { ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_THREADING_MODEL_NEUTRAL, STRING_AND_LENGTH(L"Neutral") },
  82. };
  83. PCSTR SxspActivationContextCallbackReasonToString(ULONG activationContextCallbackReason)
  84. {
  85. #if DBG
  86. static const CHAR rgs[][16] =
  87. {
  88. "",
  89. "INIT",
  90. "GENBEGINNING",
  91. "PARSEBEGINNING",
  92. "BEGINCHILDREN",
  93. "ENDCHILDREN",
  94. "ELEMENTPARSED",
  95. "PARSEENDING",
  96. "ALLPARSINGDONE",
  97. "GETSECTIONSIZE",
  98. "GETSECTIONDATA",
  99. "GENENDING",
  100. "UNINIT"
  101. };
  102. if (activationContextCallbackReason > 0 && activationContextCallbackReason <= NUMBER_OF(rgs))
  103. {
  104. return rgs[activationContextCallbackReason-1];
  105. }
  106. return rgs[0];
  107. #else
  108. return "";
  109. #endif
  110. }
  111. PCWSTR SxspInstallDispositionToStringW(ULONG installDisposition)
  112. {
  113. #if DBG
  114. static const WCHAR rgs[][12] =
  115. {
  116. L"",
  117. L"COPIED",
  118. L"QUEUED",
  119. L"PLEASE_COPY",
  120. };
  121. if (installDisposition > 0 && installDisposition <= NUMBER_OF(rgs))
  122. {
  123. return rgs[installDisposition-1];
  124. }
  125. return rgs[0];
  126. #else
  127. return L"";
  128. #endif
  129. }
  130. BOOL
  131. SxspParseThreadingModel(
  132. PCWSTR String,
  133. SIZE_T Cch,
  134. ULONG *ThreadingModel)
  135. {
  136. ULONG i;
  137. BOOL fSuccess = FALSE;
  138. FN_TRACE_WIN32(fSuccess);
  139. // We'll let ProcessorArchitecture be NULL if the caller just wants to
  140. // test whether there is a match.
  141. for (i=0; i<NUMBER_OF(gs_rgTMMap); i++)
  142. {
  143. if (::FusionpCompareStrings(
  144. gs_rgTMMap[i].String,
  145. gs_rgTMMap[i].Cch,
  146. String,
  147. Cch,
  148. true) == 0)
  149. {
  150. if (ThreadingModel != NULL)
  151. *ThreadingModel = gs_rgTMMap[i].ThreadingModel;
  152. break;
  153. }
  154. }
  155. if (i == NUMBER_OF(gs_rgTMMap))
  156. {
  157. ::FusionpDbgPrintEx(
  158. FUSION_DBG_LEVEL_ERROR,
  159. "SXS.DLL: Invalid threading model string\n");
  160. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  161. goto Exit;
  162. }
  163. fSuccess = TRUE;
  164. Exit:
  165. return fSuccess;
  166. }
  167. BOOL
  168. SxspFormatThreadingModel(
  169. ULONG ThreadingModel,
  170. CBaseStringBuffer &Buffer)
  171. {
  172. BOOL fSuccess = FALSE;
  173. FN_TRACE_WIN32(fSuccess);
  174. ULONG i;
  175. for (i=0; i<NUMBER_OF(gs_rgTMMap); i++)
  176. {
  177. if (gs_rgTMMap[i].ThreadingModel == ThreadingModel)
  178. break;
  179. }
  180. PARAMETER_CHECK(i != NUMBER_OF(gs_rgTMMap));
  181. IFW32FALSE_EXIT(Buffer.Win32Assign(gs_rgTMMap[i].String, gs_rgTMMap[i].Cch));
  182. fSuccess = TRUE;
  183. Exit:
  184. return fSuccess;
  185. }
  186. SIZE_T
  187. CchForUSHORT(USHORT us)
  188. {
  189. if (us > 9999)
  190. return 5;
  191. else if (us > 999)
  192. return 4;
  193. else if (us > 99)
  194. return 3;
  195. else if (us > 9)
  196. return 2;
  197. return 1;
  198. }
  199. BOOL
  200. SxspAllocateString(
  201. SIZE_T cch,
  202. PWSTR *StringOut)
  203. {
  204. BOOL fSuccess = FALSE;
  205. FN_TRACE_WIN32(fSuccess);
  206. ASSERT(StringOut != NULL);
  207. if (StringOut != NULL)
  208. *StringOut = NULL;
  209. PARAMETER_CHECK(StringOut != NULL);
  210. PARAMETER_CHECK(cch != 0);
  211. IFALLOCFAILED_EXIT(*StringOut = NEW(WCHAR[cch]));
  212. fSuccess = TRUE;
  213. Exit:
  214. return fSuccess;
  215. }
  216. //
  217. //For deallocation of the output string, use "delete[] StringOut" xiaoyuw@08/31/00
  218. //
  219. BOOL
  220. SxspDuplicateString(
  221. PCWSTR StringIn,
  222. SIZE_T cch,
  223. PWSTR *StringOut)
  224. {
  225. BOOL fSuccess = FALSE;
  226. FN_TRACE_WIN32(fSuccess);
  227. if (StringOut != NULL)
  228. *StringOut = NULL;
  229. PARAMETER_CHECK(StringOut != NULL);
  230. PARAMETER_CHECK((StringIn != NULL) || (cch == 0));
  231. if (cch == 0)
  232. *StringOut = NULL;
  233. else
  234. {
  235. cch++;
  236. IFW32FALSE_EXIT(::SxspAllocateString(cch, StringOut));
  237. memcpy(*StringOut, StringIn, cch * sizeof(WCHAR));
  238. }
  239. fSuccess = TRUE;
  240. Exit:
  241. return fSuccess;
  242. }
  243. #define COMMA ,
  244. extern const WCHAR sxspAssemblyManifestFileNameSuffixes[4][10] = { L"", ASSEMBLY_MANIFEST_FILE_NAME_SUFFIXES(COMMA) };
  245. #undef COMMA
  246. // format an input ULONG to be a string in HEX format
  247. BOOL
  248. SxspFormatULONG(
  249. ULONG ul,
  250. SIZE_T CchBuffer,
  251. WCHAR Buffer[],
  252. SIZE_T *CchWrittenOrRequired)
  253. {
  254. FN_PROLOG_WIN32
  255. if (CchWrittenOrRequired != NULL)
  256. *CchWrittenOrRequired = 0;
  257. PARAMETER_CHECK(Buffer != NULL);
  258. if (CchBuffer < (ULONG_STRING_LENGTH + 1))
  259. {
  260. if (CchWrittenOrRequired != NULL)
  261. *CchWrittenOrRequired = ULONG_STRING_LENGTH + 1;
  262. ORIGINATE_WIN32_FAILURE_AND_EXIT(BufferTooSmall, ERROR_INSUFFICIENT_BUFFER);
  263. }
  264. // Yes, these are char instead of WCHAR; better density and cache behavior -mgrier 12/4/2001
  265. static const char s_rgHex[] = "0123456789ABCDEF";
  266. #define DOCHAR(n) Buffer[n] = (WCHAR) s_rgHex[(ul >> (28 - (n * 4))) & 0xf]
  267. DOCHAR(0);
  268. DOCHAR(1);
  269. DOCHAR(2);
  270. DOCHAR(3);
  271. DOCHAR(4);
  272. DOCHAR(5);
  273. DOCHAR(6);
  274. DOCHAR(7);
  275. #undef DOCHAR
  276. Buffer[8] = L'\0';
  277. if (CchWrittenOrRequired != NULL)
  278. *CchWrittenOrRequired = 8;
  279. FN_EPILOG
  280. }
  281. // besides these specials, the NORMAL CHAR is in [A-Z] or [a-z] or [0-9]
  282. bool
  283. __fastcall
  284. IsValidAssemblyNameCharacter(
  285. WCHAR ch)
  286. {
  287. return
  288. (((ch >= L'A') && (ch <= L'Z')) ||
  289. ((ch >= L'a') && (ch <= L'z')) ||
  290. ((ch >= L'0') && (ch <= L'9')) ||
  291. (ch == L'.') ||
  292. (ch == L'-'));
  293. }
  294. BOOL
  295. SxspGenerateAssemblyNamePrimeFromName(
  296. PCWSTR pszAssemblyName,
  297. SIZE_T CchAssemblyName,
  298. CBaseStringBuffer *Buffer)
  299. {
  300. BOOL fSuccess = FALSE;
  301. FN_TRACE_WIN32(fSuccess);
  302. PWSTR pStart = NULL, pEnd = NULL;
  303. PWSTR qEnd = NULL, pszBuffer = NULL;
  304. ULONG i, j, len, ulSpaceLeft;
  305. ULONG cch;
  306. PWSTR pLeftEnd = NULL, pRightStart = NULL, PureNameEnd = NULL, PureNameStart = NULL;
  307. CStringBuffer buffTemp;
  308. CStringBufferAccessor accessor;
  309. PARAMETER_CHECK(pszAssemblyName != NULL);
  310. PARAMETER_CHECK(Buffer != NULL);
  311. // See how many characters we need max in the temporary buffer.
  312. cch = 0;
  313. for (i=0; i<CchAssemblyName; i++)
  314. {
  315. if (::IsValidAssemblyNameCharacter(pszAssemblyName[i]))
  316. cch++;
  317. }
  318. IFW32FALSE_EXIT(buffTemp.Win32ResizeBuffer(cch + 1, eDoNotPreserveBufferContents));
  319. accessor.Attach(&buffTemp);
  320. pszBuffer = accessor.GetBufferPtr();
  321. j = 0;
  322. for (i=0; i<CchAssemblyName; i++)
  323. {
  324. if (::IsValidAssemblyNameCharacter(pszAssemblyName[i]))
  325. {
  326. pszBuffer[j] = pszAssemblyName[i];
  327. j++;
  328. }
  329. }
  330. ASSERT(j == cch);
  331. pszBuffer[j] = L'\0';
  332. // if the name is not too long, just return ;
  333. if (j < ASSEMBLY_NAME_PRIM_MAX_LENGTH)
  334. { // less or equal 64
  335. IFW32FALSE_EXIT(Buffer->Win32Assign(pszBuffer, cch));
  336. }
  337. else
  338. {
  339. // name is too long, have to trim a little bit
  340. ulSpaceLeft = ASSEMBLY_NAME_PRIM_MAX_LENGTH;
  341. PureNameStart = pszBuffer;
  342. PureNameEnd = pszBuffer + j;
  343. pLeftEnd = PureNameStart;
  344. pRightStart = PureNameEnd;
  345. while (PureNameStart < PureNameEnd)
  346. {
  347. // left end
  348. pStart = PureNameStart;
  349. i = 0;
  350. while ((wcschr(ASSEMBLY_NAME_VALID_SEPARATORS, pStart[i]) == 0) && (pStart+i != pRightStart)) // not a separator character
  351. i++;
  352. pEnd = pStart + i ;
  353. len = i; // it should be length of WCHAR! not BYTE!!!
  354. if (len >= ulSpaceLeft - ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH) {// because we use ".." if trim happen
  355. pLeftEnd += (ulSpaceLeft - ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH);
  356. break;
  357. }
  358. ulSpaceLeft -= len;
  359. pLeftEnd = pEnd; // "abc.xxxxxxx" pointing to "c"
  360. // right end
  361. qEnd = PureNameEnd;
  362. i = 0 ;
  363. while ((qEnd+i != pLeftEnd) && (wcschr(ASSEMBLY_NAME_VALID_SEPARATORS, qEnd[i]) == 0))
  364. i--;
  365. len = 0 - i;
  366. if (len >= ulSpaceLeft - ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH) {// because we use ".." if trim happen
  367. pRightStart -= ulSpaceLeft - ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH;
  368. break;
  369. }
  370. ulSpaceLeft -= len;
  371. PureNameStart = pLeftEnd + 1;
  372. PureNameEnd = pRightStart - 1;
  373. } // end of while
  374. IFW32FALSE_EXIT(Buffer->Win32Assign(pszBuffer, pLeftEnd-pszBuffer));
  375. IFW32FALSE_EXIT(Buffer->Win32Append(ASSEMBLY_NAME_TRIM_INDICATOR, NUMBER_OF(ASSEMBLY_NAME_TRIM_INDICATOR) - 1));
  376. IFW32FALSE_EXIT(Buffer->Win32Append(pRightStart, ::wcslen(pRightStart))); // till end of the buffer
  377. }
  378. fSuccess = TRUE;
  379. Exit:
  380. return fSuccess;
  381. }
  382. // not implemented : assume Jon has this API
  383. BOOL
  384. SxspVerifyPublicKeyAndStrongName(
  385. const WCHAR *pszPublicKey,
  386. SIZE_T CchPublicKey,
  387. const WCHAR *pszStrongName,
  388. SIZE_T CchStrongName,
  389. BOOL & fValid)
  390. {
  391. BOOL fSuccess = FALSE;
  392. FN_TRACE_WIN32(fSuccess);
  393. CSmallStringBuffer buf1;
  394. CSmallStringBuffer buf2;
  395. IFW32FALSE_EXIT(buf1.Win32Assign(pszPublicKey, CchPublicKey));
  396. IFW32FALSE_EXIT(buf2.Win32Assign(pszStrongName, CchStrongName));
  397. IFW32FALSE_EXIT(::SxspDoesStrongNameMatchKey(buf1, buf2, fValid));
  398. fSuccess = TRUE;
  399. Exit:
  400. return fSuccess;
  401. }
  402. BOOL
  403. SxspGenerateSxsPath_ManifestOrPolicyFile(
  404. IN DWORD Flags,
  405. IN const CBaseStringBuffer &AssemblyRootDirectory,
  406. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  407. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  408. IN OUT CBaseStringBuffer &PathBuffer)
  409. {
  410. FN_PROLOG_WIN32
  411. DWORD dwPathType = SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST;
  412. BOOL fIsPolicy = FALSE;
  413. IFW32FALSE_EXIT(::SxspDetermineAssemblyType(AssemblyIdentity, fIsPolicy));
  414. if (fIsPolicy)
  415. {
  416. dwPathType = SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY;
  417. }
  418. return SxspGenerateSxsPath(
  419. Flags,
  420. dwPathType,
  421. static_cast<PCWSTR>(AssemblyRootDirectory),
  422. AssemblyRootDirectory.Cch(),
  423. AssemblyIdentity,
  424. ppac,
  425. PathBuffer);
  426. FN_EPILOG
  427. }
  428. BOOL
  429. SxspGenerateSxsPath_FullPathToManifestOrPolicyFile(
  430. IN const CBaseStringBuffer &AssemblyRootDirectory,
  431. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  432. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  433. IN OUT CBaseStringBuffer &PathBuffer)
  434. {
  435. return SxspGenerateSxsPath_ManifestOrPolicyFile(
  436. 0,
  437. AssemblyRootDirectory,
  438. AssemblyIdentity,
  439. ppac,
  440. PathBuffer);
  441. }
  442. BOOL
  443. SxspGenerateSxsPath_RelativePathToManifestOrPolicyFile(
  444. IN const CBaseStringBuffer &AssemblyRootDirectory,
  445. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  446. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  447. IN OUT CBaseStringBuffer &PathBuffer)
  448. {
  449. return SxspGenerateSxsPath_ManifestOrPolicyFile(
  450. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT,
  451. AssemblyRootDirectory,
  452. AssemblyIdentity,
  453. ppac,
  454. PathBuffer);
  455. }
  456. extern const UNICODE_STRING CatalogFileExtensionUnicodeString = RTL_CONSTANT_STRING(L".cat");
  457. BOOL
  458. SxspGenerateSxsPath_CatalogFile(
  459. IN DWORD Flags,
  460. IN const CBaseStringBuffer &AssemblyRootDirectory,
  461. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  462. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  463. IN OUT CBaseStringBuffer &PathBuffer)
  464. {
  465. FN_PROLOG_WIN32
  466. DWORD dwPathType = SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST;
  467. BOOL fIsPolicy = FALSE;
  468. IFW32FALSE_EXIT(::SxspDetermineAssemblyType(AssemblyIdentity, fIsPolicy));
  469. if (fIsPolicy)
  470. {
  471. dwPathType = SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY;
  472. }
  473. IFW32FALSE_EXIT(SxspGenerateSxsPath(
  474. Flags,
  475. dwPathType,
  476. static_cast<PCWSTR>(AssemblyRootDirectory),
  477. AssemblyRootDirectory.Cch(),
  478. AssemblyIdentity,
  479. ppac,
  480. PathBuffer));
  481. IFW32FALSE_EXIT(PathBuffer.Win32ChangePathExtension(&CatalogFileExtensionUnicodeString, eErrorIfNoExtension));
  482. FN_EPILOG
  483. }
  484. BOOL
  485. SxspGenerateSxsPath_RelativePathToCatalogFile(
  486. IN const CBaseStringBuffer &AssemblyRootDirectory,
  487. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  488. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  489. IN OUT CBaseStringBuffer &PathBuffer)
  490. {
  491. return SxspGenerateSxsPath_CatalogFile(
  492. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT,
  493. AssemblyRootDirectory,
  494. AssemblyIdentity,
  495. ppac,
  496. PathBuffer);
  497. }
  498. BOOL
  499. SxspGenerateSxsPath_FullPathToCatalogFile(
  500. IN const CBaseStringBuffer &AssemblyRootDirectory,
  501. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  502. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  503. IN OUT CBaseStringBuffer &PathBuffer)
  504. {
  505. return SxspGenerateSxsPath_CatalogFile(
  506. 0,
  507. AssemblyRootDirectory,
  508. AssemblyIdentity,
  509. ppac,
  510. PathBuffer);
  511. }
  512. BOOL
  513. SxspGenerateSxsPath_PayloadOrPolicyDirectory(
  514. IN DWORD Flags,
  515. IN const CBaseStringBuffer &AssemblyRootDirectory,
  516. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  517. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  518. IN OUT CBaseStringBuffer &PathBuffer)
  519. {
  520. FN_PROLOG_WIN32
  521. DWORD dwPathType = SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY;
  522. BOOL fIsPolicy = FALSE;
  523. IFW32FALSE_EXIT(::SxspDetermineAssemblyType(AssemblyIdentity, fIsPolicy));
  524. if (fIsPolicy)
  525. {
  526. dwPathType = SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY;
  527. }
  528. IFW32FALSE_EXIT(SxspGenerateSxsPath(
  529. Flags,
  530. dwPathType,
  531. static_cast<PCWSTR>(AssemblyRootDirectory),
  532. AssemblyRootDirectory.Cch(),
  533. AssemblyIdentity,
  534. ppac,
  535. PathBuffer));
  536. if (fIsPolicy)
  537. {
  538. IFW32FALSE_EXIT(PathBuffer.Win32RemoveLastPathElement());
  539. }
  540. FN_EPILOG
  541. }
  542. BOOL
  543. SxspGenerateSxsPath_FullPathToPayloadOrPolicyDirectory(
  544. IN const CBaseStringBuffer &AssemblyRootDirectory,
  545. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  546. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  547. IN OUT CBaseStringBuffer &PathBuffer)
  548. {
  549. return SxspGenerateSxsPath_PayloadOrPolicyDirectory(
  550. 0,
  551. AssemblyRootDirectory,
  552. AssemblyIdentity,
  553. ppac,
  554. PathBuffer);
  555. }
  556. BOOL
  557. SxspGenerateSxsPath_RelativePathToPayloadOrPolicyDirectory(
  558. IN const CBaseStringBuffer &AssemblyRootDirectory,
  559. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  560. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  561. IN OUT CBaseStringBuffer &PathBuffer)
  562. {
  563. return SxspGenerateSxsPath_PayloadOrPolicyDirectory(
  564. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT,
  565. AssemblyRootDirectory,
  566. AssemblyIdentity,
  567. ppac,
  568. PathBuffer);
  569. }
  570. BOOL
  571. SxspGenerateSxsPath(
  572. IN DWORD Flags,
  573. IN ULONG PathType,
  574. IN const WCHAR *AssemblyRootDirectory OPTIONAL,
  575. IN SIZE_T AssemblyRootDirectoryCch,
  576. IN PCASSEMBLY_IDENTITY pAssemblyIdentity,
  577. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  578. IN OUT CBaseStringBuffer &PathBuffer)
  579. {
  580. BOOL fSuccess = FALSE;
  581. FN_TRACE_WIN32(fSuccess);
  582. SIZE_T cch = 0;
  583. PCWSTR pszAssemblyName=NULL, pszVersion=NULL, pszProcessorArchitecture=NULL, pszLanguage=NULL, pszPolicyFileNameWithoutExt = NULL;
  584. PCWSTR pszPublicKeyToken=NULL;
  585. SIZE_T cchAssemblyName = 0, cchPublicKeyToken=0, cchVersion=0, cchProcessorArchitecture=0, cchLanguage=0;
  586. SIZE_T PolicyFileNameWithoutExtCch=0;
  587. BOOL fNeedSlashAfterRoot = FALSE;
  588. ULONG IdentityHash = 0;
  589. const bool fOmitRoot = ((Flags & SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT) != 0);
  590. const bool fPartialPath = ((Flags & SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH) != 0);
  591. WCHAR HashBuffer[ULONG_STRING_LENGTH + 1];
  592. SIZE_T HashBufferCch = 0;
  593. PCWSTR pcwszPolicyPathComponent = NULL;
  594. SIZE_T cchPolicyPathComponent = 0;
  595. // We'll be using this a lot - a bool check is cheaper than two =='s checks everywhere.
  596. const bool fIsInstallingPolicy = ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY) ||
  597. (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_SETUP_POLICY));
  598. CSmallStringBuffer NamePrimeBuffer;
  599. #if DBG_SXS
  600. ::FusionpDbgPrintEx(
  601. FUSION_DBG_LEVEL_INFO,
  602. "SXS.DLL: Entered %s()\n"
  603. " Flags = 0x%08lx\n"
  604. " AssemblyRootDirectory = %p\n"
  605. " AssemblyRootDirectoryCch = %lu\n"
  606. " PathBuffer = %p\n",
  607. __FUNCTION__,
  608. Flags,
  609. AssemblyRootDirectory,
  610. AssemblyRootDirectoryCch,
  611. &PathBuffer);
  612. #endif // DBG_SXS
  613. PARAMETER_CHECK(
  614. (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY) ||
  615. (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) ||
  616. (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY) ||
  617. (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_SETUP_POLICY));
  618. PARAMETER_CHECK(pAssemblyIdentity != NULL);
  619. PARAMETER_CHECK((Flags & ~(SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION | SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT | SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH)) == 0);
  620. // Not supplying the assembly root is only legal if you're asking for it to be left out...
  621. PARAMETER_CHECK((AssemblyRootDirectoryCch != 0) || (Flags & SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT));
  622. // You can't combine SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH with anything else...
  623. PARAMETER_CHECK(
  624. ((Flags & SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH) == 0) ||
  625. ((Flags & ~(SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH)) == 0));
  626. // get AssemblyName
  627. if (ppac != NULL)
  628. {
  629. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_NAME) == 0)
  630. {
  631. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(0, pAssemblyIdentity, &s_IdentityAttribute_name, &pszAssemblyName, &cchAssemblyName));
  632. ppac->pszName = pszAssemblyName;
  633. ppac->cchName = cchAssemblyName;
  634. ppac->dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_NAME;
  635. }
  636. else
  637. {
  638. pszAssemblyName = ppac->pszName;
  639. cchAssemblyName = ppac->cchName;
  640. }
  641. }
  642. else
  643. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(0, pAssemblyIdentity, &s_IdentityAttribute_name, &pszAssemblyName, &cchAssemblyName));
  644. INTERNAL_ERROR_CHECK((pszAssemblyName != NULL) && (cchAssemblyName != 0));
  645. // get AssemblyName' based on AssemblyName
  646. IFW32FALSE_EXIT(::SxspGenerateAssemblyNamePrimeFromName(pszAssemblyName, cchAssemblyName, &NamePrimeBuffer));
  647. // get Assembly Version
  648. if (ppac != NULL)
  649. {
  650. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_VERSION) == 0)
  651. {
  652. IFW32FALSE_EXIT(
  653. ::SxspGetAssemblyIdentityAttributeValue(
  654. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL, // for policy_lookup, no version is used
  655. pAssemblyIdentity,
  656. &s_IdentityAttribute_version,
  657. &pszVersion,
  658. &cchVersion));
  659. ppac->pszVersion = pszVersion;
  660. ppac->cchVersion = cchVersion;
  661. ppac->dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_VERSION;
  662. }
  663. else
  664. {
  665. pszVersion = ppac->pszVersion;
  666. cchVersion = ppac->cchVersion;
  667. }
  668. }
  669. else
  670. IFW32FALSE_EXIT(
  671. ::SxspGetAssemblyIdentityAttributeValue(
  672. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL, // for policy_lookup, no version is used
  673. pAssemblyIdentity,
  674. &s_IdentityAttribute_version,
  675. &pszVersion,
  676. &cchVersion));
  677. if ((Flags & SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION) || fIsInstallingPolicy)
  678. {
  679. // for policy file, version of the policy file is used as policy filename
  680. pszPolicyFileNameWithoutExt = pszVersion;
  681. PolicyFileNameWithoutExtCch = cchVersion;
  682. pszVersion = NULL;
  683. cchVersion = 0;
  684. }
  685. else
  686. {
  687. PARAMETER_CHECK((pszVersion != NULL) && (cchVersion != 0));
  688. }
  689. // get Assembly Langage
  690. if (ppac != NULL)
  691. {
  692. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_LANGUAGE) == 0)
  693. {
  694. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(
  695. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  696. pAssemblyIdentity,
  697. &s_IdentityAttribute_language,
  698. &pszLanguage,
  699. &cchLanguage));
  700. ppac->pszLanguage = pszLanguage;
  701. ppac->cchLanguage = cchLanguage;
  702. ppac->dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_LANGUAGE;
  703. }
  704. else
  705. {
  706. pszLanguage = ppac->pszLanguage;
  707. cchLanguage = ppac->cchLanguage;
  708. }
  709. }
  710. else
  711. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL, pAssemblyIdentity, &s_IdentityAttribute_language, &pszLanguage, &cchLanguage));
  712. if (cchLanguage == 0)
  713. {
  714. pszLanguage = SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_LANGUAGE_MISSING_VALUE;
  715. cchLanguage = NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_LANGUAGE_MISSING_VALUE) - 1;
  716. }
  717. // get Assembly ProcessorArchitecture
  718. if (ppac != NULL)
  719. {
  720. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_PROCESSOR_ARCHITECTURE) == 0)
  721. {
  722. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(
  723. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  724. pAssemblyIdentity,
  725. &s_IdentityAttribute_processorArchitecture,
  726. &pszProcessorArchitecture,
  727. &cchProcessorArchitecture));
  728. ppac->pszProcessorArchitecture = pszProcessorArchitecture;
  729. ppac->cchProcessorArchitecture = cchProcessorArchitecture;
  730. ppac->dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_PROCESSOR_ARCHITECTURE;
  731. }
  732. else
  733. {
  734. pszProcessorArchitecture = ppac->pszProcessorArchitecture;
  735. cchProcessorArchitecture = ppac->cchProcessorArchitecture;
  736. }
  737. }
  738. else
  739. IFW32FALSE_EXIT(
  740. ::SxspGetAssemblyIdentityAttributeValue(
  741. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  742. pAssemblyIdentity,
  743. &s_IdentityAttribute_processorArchitecture,
  744. &pszProcessorArchitecture,
  745. &cchProcessorArchitecture));
  746. if (pszProcessorArchitecture == NULL)
  747. {
  748. pszProcessorArchitecture = L"data";
  749. cchProcessorArchitecture = 4;
  750. }
  751. // get Assembly StrongName
  752. if (ppac != NULL)
  753. {
  754. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_PUBLIC_KEY_TOKEN) == 0)
  755. {
  756. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(
  757. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  758. pAssemblyIdentity,
  759. &s_IdentityAttribute_publicKeyToken,
  760. &pszPublicKeyToken,
  761. &cchPublicKeyToken));
  762. ppac->pszPublicKeyToken = pszPublicKeyToken;
  763. ppac->cchPublicKeyToken = cchPublicKeyToken;
  764. if (pszPublicKeyToken != NULL)
  765. ppac->dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_PUBLIC_KEY_TOKEN;
  766. }
  767. else
  768. {
  769. pszPublicKeyToken = ppac->pszPublicKeyToken;
  770. cchPublicKeyToken = ppac->cchPublicKeyToken;
  771. }
  772. }
  773. else
  774. {
  775. IFW32FALSE_EXIT(
  776. ::SxspGetAssemblyIdentityAttributeValue(
  777. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  778. pAssemblyIdentity,
  779. &s_IdentityAttribute_publicKeyToken,
  780. &pszPublicKeyToken,
  781. &cchPublicKeyToken));
  782. }
  783. if (pszPublicKeyToken == NULL)
  784. {
  785. pszPublicKeyToken = SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_PUBLICKEY_MISSING_VALUE;
  786. cchPublicKeyToken = NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_PUBLICKEY_MISSING_VALUE) - 1;
  787. }
  788. //get Assembly Hash String
  789. if ((Flags & SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION) || fIsInstallingPolicy)
  790. {
  791. IFW32FALSE_EXIT(::SxspHashAssemblyIdentityForPolicy(0, pAssemblyIdentity, IdentityHash));
  792. }
  793. else
  794. {
  795. IFW32FALSE_EXIT(::SxsHashAssemblyIdentity(0, pAssemblyIdentity, &IdentityHash));
  796. }
  797. IFW32FALSE_EXIT(::SxspFormatULONG(IdentityHash, NUMBER_OF(HashBuffer), HashBuffer, &HashBufferCch));
  798. if (!fOmitRoot)
  799. {
  800. // If the assembly root was not passed in, get it.
  801. fNeedSlashAfterRoot = (! ::FusionpIsPathSeparator(AssemblyRootDirectory[AssemblyRootDirectoryCch-1]));
  802. }
  803. else
  804. {
  805. // If we don't want to include the root, then don't account for it below...
  806. AssemblyRootDirectoryCch = 0;
  807. fNeedSlashAfterRoot = FALSE;
  808. }
  809. // this computation can be off by one or a few, it's an optimization
  810. // to pregrow a string buffer
  811. cch =
  812. AssemblyRootDirectoryCch + // "C:\WINNT\WinSxS\"
  813. (fNeedSlashAfterRoot ? 1 : 0);
  814. switch (PathType)
  815. {
  816. case SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST:
  817. // Wacky parens and ... - 1) + 1) to reinforce that it's the number of
  818. // characters in the string not including the null and then an extra separator.
  819. cch += (NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) - 1) + 1;
  820. break;
  821. case SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY:
  822. pcwszPolicyPathComponent = POLICY_ROOT_DIRECTORY_NAME;
  823. cchPolicyPathComponent = (NUMBER_OF(POLICY_ROOT_DIRECTORY_NAME) - 1);
  824. break;
  825. case SXSP_GENERATE_SXS_PATH_PATHTYPE_SETUP_POLICY:
  826. pcwszPolicyPathComponent = SETUP_POLICY_ROOT_DIRECTORY_NAME;
  827. cchPolicyPathComponent = NUMBER_OF(SETUP_POLICY_ROOT_DIRECTORY_NAME) - 1;
  828. break;
  829. }
  830. // Seperator, plus the length of the policy component (if necessary)
  831. cch++;
  832. cch += cchPolicyPathComponent;
  833. // fPartialPath means that we don't actually want to take the assembly's identity into
  834. // account; the caller just wants the path to the manifests or policies directories.
  835. if (!fPartialPath)
  836. {
  837. cch +=
  838. cchProcessorArchitecture + // "x86"
  839. 1 + // "_"
  840. NamePrimeBuffer.Cch() + // "FooBar"
  841. 1 + // "_"
  842. cchPublicKeyToken + // StrongName
  843. 1 + // "_"
  844. cchVersion + // "5.6.2900.42"
  845. 1 + // "_"
  846. cchLanguage + // "0409"
  847. 1 + // "_"
  848. HashBufferCch;
  849. if (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST)
  850. {
  851. cch += NUMBER_OF(ASSEMBLY_LONGEST_MANIFEST_FILE_NAME_SUFFIX); // ".manifest\0"
  852. }
  853. else if (fIsInstallingPolicy)
  854. {
  855. // "_" has already reserve space for "\"
  856. cch += PolicyFileNameWithoutExtCch;
  857. cch += NUMBER_OF(ASSEMBLY_POLICY_FILE_NAME_SUFFIX_POLICY); // ".policy\0"
  858. }
  859. else { // pathType must be SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY
  860. // if (!fOmitRoot)
  861. // cch++;
  862. cch++; // trailing null character
  863. }
  864. }
  865. // We try to ensure that the buffer is big enough up front so that we don't have to do any
  866. // dynamic reallocation during the actual process.
  867. IFW32FALSE_EXIT(PathBuffer.Win32ResizeBuffer(cch, eDoNotPreserveBufferContents));
  868. // Note that since when GENERATE_ASSEMBLY_PATH_OMIT_ROOT is set, we force AssemblyRootDirectoryCch to zero
  869. // and fNeedSlashAfterRoot to FALSE, so the first two entries in this concatenation actually don't
  870. // contribute anything to the string constructed.
  871. if (fPartialPath)
  872. {
  873. const bool fAddExtraSlash = ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) || fIsInstallingPolicy);
  874. IFW32FALSE_EXIT(PathBuffer.Win32AssignW(5,
  875. AssemblyRootDirectory, static_cast<INT>(AssemblyRootDirectoryCch), // "C:\WINNT\WINSXS"
  876. L"\\", (fNeedSlashAfterRoot ? 1 : 0), // optional '\'
  877. // manifests subdir
  878. MANIFEST_ROOT_DIRECTORY_NAME, ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) ? NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) -1 : 0), // "manifests"
  879. // policies subdir
  880. pcwszPolicyPathComponent, cchPolicyPathComponent,
  881. L"\\", fAddExtraSlash ? 1 : 0)); // optional '\'
  882. }
  883. else
  884. {
  885. const bool fAddExtraSlash = ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) || fIsInstallingPolicy);
  886. //
  887. // create one of below
  888. // (1) fully-qualified manifest filename,
  889. // eg, [C:\WINNT\WinSxS\]Manifests\X86_DynamicDll_6595b64144ccf1df_2.0.0.0_en-us_2f433926.Manifest
  890. // (2) fully-qualified policy filename,
  891. // eg, [C:\WINNT\WinSxS\]Policies\x86_policy.1.0.DynamicDll_b54bc117ce08a1e8_en-us_d51541cb\1.1.0.0.cat
  892. // (3) fully-qulified assembly name (w. or w/o a version)
  893. // eg, [C:\WINNT\WinSxS\]x86_DynamicDll_6595b64144ccf1df_6.0.0.0_x-ww_ff9986d7
  894. // (4) fully-qualified policy path during setup
  895. // eg, [C:\WINNT\WinSxS\]SetupPolicies\x86_policy.1.0.DynamicDll_b54bc117ce08a1e8_en-us_d51541cb\1.1.0.0.cat
  896. //
  897. IFW32FALSE_EXIT(
  898. PathBuffer.Win32AssignW(17,
  899. AssemblyRootDirectory, static_cast<INT>(AssemblyRootDirectoryCch), // "C:\WINNT\WINSXS"
  900. L"\\", (fNeedSlashAfterRoot ? 1 : 0), // optional '\'
  901. MANIFEST_ROOT_DIRECTORY_NAME, ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) ? NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) - 1 : 0),
  902. pcwszPolicyPathComponent, cchPolicyPathComponent,
  903. L"\\", (fAddExtraSlash ? 1 : 0), // optional '\'
  904. pszProcessorArchitecture, static_cast<INT>(cchProcessorArchitecture),
  905. L"_", 1,
  906. static_cast<PCWSTR>(NamePrimeBuffer), static_cast<INT>(NamePrimeBuffer.Cch()),
  907. L"_", 1,
  908. pszPublicKeyToken, static_cast<INT>(cchPublicKeyToken),
  909. L"_", (cchVersion != 0) ? 1 : 0,
  910. pszVersion, static_cast<INT>(cchVersion),
  911. L"_", 1,
  912. pszLanguage, static_cast<INT>(cchLanguage),
  913. L"_", 1,
  914. static_cast<PCWSTR>(HashBuffer), static_cast<INT>(HashBufferCch),
  915. L"\\", ((fOmitRoot ||(PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST)) ? 0 : 1)));
  916. if (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST)
  917. {
  918. IFW32FALSE_EXIT(PathBuffer.Win32Append(ASSEMBLY_MANIFEST_FILE_NAME_SUFFIX_MANIFEST, NUMBER_OF(ASSEMBLY_MANIFEST_FILE_NAME_SUFFIX_MANIFEST) - 1));
  919. }
  920. else if (fIsInstallingPolicy)
  921. {
  922. if ((pszPolicyFileNameWithoutExt != NULL) && (PolicyFileNameWithoutExtCch >0))
  923. {
  924. IFW32FALSE_EXIT(PathBuffer.Win32Append(pszPolicyFileNameWithoutExt, PolicyFileNameWithoutExtCch));
  925. IFW32FALSE_EXIT(PathBuffer.Win32Append(ASSEMBLY_POLICY_FILE_NAME_SUFFIX_POLICY, NUMBER_OF(ASSEMBLY_POLICY_FILE_NAME_SUFFIX_POLICY) - 1));
  926. }
  927. }
  928. }
  929. fSuccess = TRUE;
  930. Exit:
  931. return fSuccess;
  932. }
  933. BOOL
  934. SxspGenerateManifestPathForProbing(
  935. ULONG dwLocationIndex,
  936. DWORD dwFlags,
  937. IN PCWSTR AssemblyRootDirectory OPTIONAL,
  938. IN SIZE_T AssemblyRootDirectoryCch OPTIONAL,
  939. IN ULONG ApplicationDirectoryPathType OPTIONAL,
  940. IN PCWSTR ApplicationDirectory OPTIONAL,
  941. IN SIZE_T ApplicationDirectoryCch OPTIONAL,
  942. IN PCASSEMBLY_IDENTITY pAssemblyIdentity,
  943. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  944. IN OUT CBaseStringBuffer &PathBuffer,
  945. BOOL *pfPrivateAssembly,
  946. bool &rfDone)
  947. {
  948. BOOL fSuccess = FALSE;
  949. FN_TRACE_WIN32(fSuccess);
  950. BOOL fIsPrivate = FALSE;
  951. rfDone = false;
  952. if (pfPrivateAssembly != NULL) // init
  953. *pfPrivateAssembly = FALSE;
  954. PathBuffer.Clear();
  955. PARAMETER_CHECK(pAssemblyIdentity != NULL);
  956. PARAMETER_CHECK(AssemblyRootDirectory != NULL);
  957. PARAMETER_CHECK(AssemblyRootDirectoryCch != 0);
  958. PARAMETER_CHECK((dwFlags & ~(SXS_GENERATE_MANIFEST_PATH_FOR_PROBING_NO_APPLICATION_ROOT_PATH_REQUIRED |
  959. SXS_GENERATE_MANIFEST_PATH_FOR_PROBING_SKIP_LANGUAGE_SUBDIRS |
  960. SXS_GENERATE_MANIFEST_PATH_FOR_PROBING_SKIP_PRIVATE_ASSEMBLIES)) == 0);
  961. PARAMETER_CHECK((dwLocationIndex == 0) || (dwFlags & SXS_GENERATE_MANIFEST_PATH_FOR_PROBING_NO_APPLICATION_ROOT_PATH_REQUIRED) || (ApplicationDirectory != NULL));
  962. PARAMETER_CHECK((dwLocationIndex == 0) || (dwFlags & SXS_GENERATE_MANIFEST_PATH_FOR_PROBING_NO_APPLICATION_ROOT_PATH_REQUIRED) || (ApplicationDirectoryCch != 0));
  963. PARAMETER_CHECK(::FusionpIsPathSeparator(AssemblyRootDirectory[AssemblyRootDirectoryCch - 1]));
  964. PARAMETER_CHECK((ApplicationDirectory == NULL) || (ApplicationDirectory[0] == L'\0') || ::FusionpIsPathSeparator(ApplicationDirectory[ApplicationDirectoryCch - 1]));
  965. PARAMETER_CHECK((ApplicationDirectoryPathType == ACTIVATION_CONTEXT_PATH_TYPE_NONE) ||
  966. (ApplicationDirectoryPathType == ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE) ||
  967. (ApplicationDirectoryPathType == ACTIVATION_CONTEXT_PATH_TYPE_URL));
  968. PARAMETER_CHECK((ApplicationDirectoryCch != 0) || (ApplicationDirectoryPathType == ACTIVATION_CONTEXT_PATH_TYPE_NONE));
  969. INTERNAL_ERROR_CHECK(dwLocationIndex <= NUMBER_OF(s_rgProbingCandidates));
  970. if (dwLocationIndex >= NUMBER_OF(s_rgProbingCandidates))
  971. {
  972. rfDone = true;
  973. }
  974. else
  975. {
  976. PCWSTR Candidate = s_rgProbingCandidates[dwLocationIndex].Pattern;
  977. WCHAR wch = 0;
  978. SIZE_T iPosition = 0; // Used to track that $M and $. only appear first
  979. if ((dwFlags & SXS_GENERATE_MANIFEST_PATH_FOR_PROBING_SKIP_LANGUAGE_SUBDIRS) &&
  980. (s_rgProbingCandidates[dwLocationIndex].Flags & SXSP_PROBING_CANDIDATE_FLAG_USES_LANGUAGE_SUBDIRECTORY))
  981. {
  982. // No probing for languages I guess!
  983. fSuccess = TRUE;
  984. goto Exit;
  985. }
  986. if ((dwFlags & SXS_GENERATE_MANIFEST_PATH_FOR_PROBING_SKIP_PRIVATE_ASSEMBLIES) &&
  987. (s_rgProbingCandidates[dwLocationIndex].Flags & SXSP_PROBING_CANDIDATE_FLAG_IS_PRIVATE_ASSEMBLY))
  988. {
  989. fSuccess = TRUE;
  990. goto Exit;
  991. }
  992. while ((wch = *Candidate++) != L'\0')
  993. {
  994. switch (wch)
  995. {
  996. default:
  997. IFW32FALSE_EXIT(PathBuffer.Win32Append(&wch, 1));
  998. break;
  999. case L'$':
  1000. wch = *Candidate++;
  1001. switch (wch)
  1002. {
  1003. default:
  1004. // Bad macro expansion...
  1005. INTERNAL_ERROR_CHECK(FALSE);
  1006. break; // extraneous since there was effectively an unconditional goto in the internal error check...
  1007. case L'M':
  1008. // $M is only allowed as the first element.
  1009. INTERNAL_ERROR_CHECK(iPosition == 0);
  1010. IFW32FALSE_EXIT(
  1011. ::SxspGenerateSxsPath(// "winnt\winsxs\manifests\x86_bar_1000_0409.manifest
  1012. 0,
  1013. SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST,
  1014. AssemblyRootDirectory,
  1015. AssemblyRootDirectoryCch,
  1016. pAssemblyIdentity,
  1017. ppac,
  1018. PathBuffer));
  1019. // and it has to be the only element
  1020. INTERNAL_ERROR_CHECK(*Candidate == L'\0');
  1021. break;
  1022. case L'G':
  1023. IFW32FALSE_EXIT(::SxspGenerateNdpGACPath(0, pAssemblyIdentity, ppac, PathBuffer));
  1024. break;
  1025. case L'.':
  1026. // $. is only allowed as the first element
  1027. INTERNAL_ERROR_CHECK(iPosition == 0);
  1028. if (ApplicationDirectoryPathType == ACTIVATION_CONTEXT_PATH_TYPE_NONE)
  1029. {
  1030. // No local probing...
  1031. fSuccess = TRUE;
  1032. goto Exit;
  1033. }
  1034. IFW32FALSE_EXIT(PathBuffer.Win32Append(ApplicationDirectory, ApplicationDirectoryCch));
  1035. fIsPrivate = TRUE;
  1036. break;
  1037. case L'L': // language
  1038. {
  1039. INTERNAL_ERROR_CHECK((dwFlags & SXS_GENERATE_MANIFEST_PATH_FOR_PROBING_SKIP_LANGUAGE_SUBDIRS) == 0);
  1040. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_LANGUAGE) == 0)
  1041. {
  1042. IFW32FALSE_EXIT(
  1043. ::SxspGetAssemblyIdentityAttributeValue(
  1044. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  1045. pAssemblyIdentity,
  1046. &s_IdentityAttribute_language,
  1047. &ppac->pszLanguage,
  1048. &ppac->cchLanguage));
  1049. ppac->dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_LANGUAGE;
  1050. }
  1051. if (ppac->cchLanguage != 0)
  1052. {
  1053. IFW32FALSE_EXIT(PathBuffer.Win32Append(ppac->pszLanguage, ppac->cchLanguage));
  1054. IFW32FALSE_EXIT(PathBuffer.Win32Append(PathBuffer.PreferredPathSeparatorString(), 1));
  1055. }
  1056. break;
  1057. }
  1058. case L'N': // full assembly name
  1059. {
  1060. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_NAME) == 0)
  1061. {
  1062. IFW32FALSE_EXIT(
  1063. ::SxspGetAssemblyIdentityAttributeValue(
  1064. 0,
  1065. pAssemblyIdentity,
  1066. &s_IdentityAttribute_name,
  1067. &ppac->pszName,
  1068. &ppac->cchName));
  1069. dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_NAME;
  1070. }
  1071. INTERNAL_ERROR_CHECK(ppac->cchName != 0);
  1072. IFW32FALSE_EXIT(PathBuffer.Win32Append(ppac->pszName, ppac->cchName));
  1073. break;
  1074. }
  1075. case L'n': // final segment of assembly name
  1076. {
  1077. PCWSTR pszPartialName = NULL;
  1078. SIZE_T cchPartialName = 0;
  1079. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_NAME) == 0)
  1080. {
  1081. IFW32FALSE_EXIT(
  1082. ::SxspGetAssemblyIdentityAttributeValue(
  1083. 0,
  1084. pAssemblyIdentity,
  1085. &s_IdentityAttribute_name,
  1086. &ppac->pszName,
  1087. &ppac->cchName));
  1088. dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_NAME;
  1089. }
  1090. INTERNAL_ERROR_CHECK(ppac->cchName != 0);
  1091. IFW32FALSE_EXIT(::SxspFindLastSegmentOfAssemblyName(ppac->pszName, ppac->cchName, &pszPartialName, &cchPartialName));
  1092. IFW32FALSE_EXIT(PathBuffer.Win32Append(pszPartialName, cchPartialName));
  1093. break;
  1094. }
  1095. case L'P': // P for Prime because in discussions we always called this "name prime" (vs. "name")
  1096. {
  1097. CSmallStringBuffer buffShortenedAssemblyName;
  1098. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_NAME) == 0)
  1099. {
  1100. IFW32FALSE_EXIT(
  1101. ::SxspGetAssemblyIdentityAttributeValue(
  1102. 0,
  1103. pAssemblyIdentity,
  1104. &s_IdentityAttribute_name,
  1105. &ppac->pszName,
  1106. &ppac->cchName));
  1107. dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_NAME;
  1108. }
  1109. INTERNAL_ERROR_CHECK(ppac->cchName != 0);
  1110. IFW32FALSE_EXIT(::SxspGenerateAssemblyNamePrimeFromName(ppac->pszName, ppac->cchName, &buffShortenedAssemblyName));
  1111. IFW32FALSE_EXIT(PathBuffer.Win32Append(buffShortenedAssemblyName, buffShortenedAssemblyName.Cch()));
  1112. break;
  1113. }
  1114. }
  1115. break;
  1116. }
  1117. iPosition++;
  1118. }
  1119. }
  1120. if (pfPrivateAssembly != NULL)
  1121. *pfPrivateAssembly = fIsPrivate;
  1122. fSuccess = TRUE;
  1123. Exit:
  1124. return fSuccess;
  1125. }
  1126. BOOL
  1127. SxspGetAttributeValue(
  1128. IN DWORD dwFlags,
  1129. IN PCATTRIBUTE_NAME_DESCRIPTOR AttributeNameDescriptor,
  1130. IN PCSXS_NODE_INFO NodeInfo,
  1131. IN SIZE_T NodeCount,
  1132. IN PCACTCTXCTB_PARSE_CONTEXT ParseContext,
  1133. OUT bool &rfFound,
  1134. IN SIZE_T OutputBufferSize,
  1135. OUT PVOID OutputBuffer,
  1136. OUT SIZE_T &rcbOutputBytesWritten,
  1137. IN SXSP_GET_ATTRIBUTE_VALUE_VALIDATION_ROUTINE ValidationRoutine OPTIONAL,
  1138. IN DWORD ValidationRoutineFlags OPTIONAL)
  1139. {
  1140. BOOL fSuccess = FALSE;
  1141. FN_TRACE_WIN32(fSuccess);
  1142. ULONG i = 0;
  1143. PCWSTR AttributeName = NULL;
  1144. PCWSTR AttributeNamespace = NULL;
  1145. SIZE_T AttributeNameCch = 0;
  1146. SIZE_T AttributeNamespaceCch = 0;
  1147. CStringBuffer buffValue;
  1148. BOOL fSmallStringBuffer = FALSE;
  1149. rfFound = false;
  1150. rcbOutputBytesWritten = 0;
  1151. PARAMETER_CHECK((dwFlags & ~(SXSP_GET_ATTRIBUTE_VALUE_FLAG_REQUIRED_ATTRIBUTE)) == 0);
  1152. PARAMETER_CHECK(AttributeNameDescriptor != NULL);
  1153. PARAMETER_CHECK((NodeInfo != NULL) || (NodeCount == 0));
  1154. PARAMETER_CHECK((OutputBuffer != NULL) || (OutputBufferSize == 0));
  1155. PARAMETER_CHECK((ValidationRoutine != NULL) || (ValidationRoutineFlags == 0));
  1156. PARAMETER_CHECK((ValidationRoutine != NULL) ||
  1157. (OutputBufferSize == 0) || (OutputBufferSize == sizeof(CSmallStringBuffer)) || (OutputBufferSize == sizeof(CStringBuffer)));
  1158. if (OutputBufferSize != sizeof(CStringBuffer))
  1159. fSmallStringBuffer = TRUE;
  1160. AttributeName = AttributeNameDescriptor->Name;
  1161. AttributeNameCch = AttributeNameDescriptor->NameCch;
  1162. AttributeNamespace = AttributeNameDescriptor->Namespace;
  1163. AttributeNamespaceCch = AttributeNameDescriptor->NamespaceCch;
  1164. for (i=0; i<NodeCount; i++)
  1165. {
  1166. if ((NodeInfo[i].Type == SXS_ATTRIBUTE) &&
  1167. (::FusionpCompareStrings(// compare name
  1168. NodeInfo[i].pszText,
  1169. NodeInfo[i].cchText,
  1170. AttributeName,
  1171. AttributeNameCch,
  1172. false) == 0))
  1173. {
  1174. //compare namespace
  1175. if (((NodeInfo[i].NamespaceStringBuf.Cch() == 0) && (AttributeNamespaceCch==0)) ||
  1176. (::FusionpCompareStrings(// compare namespace string
  1177. NodeInfo[i].NamespaceStringBuf,
  1178. NodeInfo[i].NamespaceStringBuf.Cch(),
  1179. AttributeNamespace,
  1180. AttributeNamespaceCch,
  1181. false) == 0))
  1182. {
  1183. // We found the attribute. Now we need to start accumulating the parts of the value;
  1184. // entity references (e.g. &amp;) show up as separate nodes.
  1185. while ((++i < NodeCount) &&
  1186. (NodeInfo[i].Type == SXS_PCDATA))
  1187. IFW32FALSE_EXIT(buffValue.Win32Append(NodeInfo[i].pszText, NodeInfo[i].cchText));
  1188. if (ValidationRoutine == NULL)
  1189. {
  1190. if (OutputBuffer != NULL)
  1191. {
  1192. // Have the caller's buffer take over ours
  1193. CBaseStringBuffer *pCallersBuffer = (CBaseStringBuffer *) OutputBuffer;
  1194. IFW32FALSE_EXIT(pCallersBuffer->Win32Assign(buffValue));
  1195. rcbOutputBytesWritten = pCallersBuffer->Cch() * sizeof(WCHAR);
  1196. }
  1197. }
  1198. else
  1199. {
  1200. bool fValid = false;
  1201. IFW32FALSE_EXIT(
  1202. (*ValidationRoutine)(
  1203. ValidationRoutineFlags,
  1204. buffValue,
  1205. fValid,
  1206. OutputBufferSize,
  1207. OutputBuffer,
  1208. rcbOutputBytesWritten));
  1209. if (!fValid)
  1210. {
  1211. (*ParseContext->ErrorCallbacks.InvalidAttributeValue)(
  1212. ParseContext,
  1213. AttributeNameDescriptor);
  1214. ORIGINATE_WIN32_FAILURE_AND_EXIT(AttributeValidation, ERROR_SXS_MANIFEST_PARSE_ERROR);
  1215. }
  1216. }
  1217. rfFound = true;
  1218. break;
  1219. }
  1220. }
  1221. }
  1222. if ((dwFlags & SXSP_GET_ATTRIBUTE_VALUE_FLAG_REQUIRED_ATTRIBUTE) && (!rfFound))
  1223. {
  1224. (*ParseContext->ErrorCallbacks.MissingRequiredAttribute)(
  1225. ParseContext,
  1226. AttributeNameDescriptor);
  1227. ORIGINATE_WIN32_FAILURE_AND_EXIT(MissingRequiredAttribute, ERROR_SXS_MANIFEST_PARSE_ERROR);
  1228. }
  1229. fSuccess = TRUE;
  1230. Exit:
  1231. return fSuccess;
  1232. }
  1233. BOOL
  1234. SxspGetAttributeValue(
  1235. IN DWORD dwFlags,
  1236. IN PCATTRIBUTE_NAME_DESCRIPTOR AttributeNameDescriptor,
  1237. IN PCACTCTXCTB_CBELEMENTPARSED ElementParsed,
  1238. OUT bool &rfFound,
  1239. IN SIZE_T OutputBufferSize,
  1240. OUT PVOID OutputBuffer,
  1241. OUT SIZE_T &rcbOutputBytesWritten,
  1242. IN SXSP_GET_ATTRIBUTE_VALUE_VALIDATION_ROUTINE ValidationRoutine OPTIONAL,
  1243. IN DWORD ValidationRoutineFlags OPTIONAL)
  1244. {
  1245. BOOL fSuccess = FALSE;
  1246. FN_TRACE_WIN32(fSuccess);
  1247. // Since we're doing some parameter validation here, we need to initialize our output parameters
  1248. rfFound = false;
  1249. rcbOutputBytesWritten = 0;
  1250. PARAMETER_CHECK(ElementParsed != NULL);
  1251. // We're going to depend on the other function to do the rest of the parameter validation
  1252. // a little sleazy but what the heck
  1253. IFW32FALSE_EXIT(
  1254. ::SxspGetAttributeValue(
  1255. dwFlags,
  1256. AttributeNameDescriptor,
  1257. ElementParsed->NodeInfo,
  1258. ElementParsed->NodeCount,
  1259. ElementParsed->ParseContext,
  1260. rfFound,
  1261. OutputBufferSize,
  1262. OutputBuffer,
  1263. rcbOutputBytesWritten,
  1264. ValidationRoutine,
  1265. ValidationRoutineFlags));
  1266. fSuccess = TRUE;
  1267. Exit:
  1268. return fSuccess;
  1269. }
  1270. BOOL
  1271. SxspFormatGUID(
  1272. const GUID &rGuid,
  1273. CBaseStringBuffer &rBuffer)
  1274. {
  1275. FN_PROLOG_WIN32
  1276. // It would seem nice to use RtlStringFromGUID(), but it does a dynamic allocation, which we do not
  1277. // want. Instead, we'll just format it ourselves; it's pretty trivial...
  1278. //
  1279. // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
  1280. // 00000000011111111112222222222333333333
  1281. // 12345678901234567890123456789012345678
  1282. //
  1283. // 128 bits / 4 bits per digit = 32 digits
  1284. // + 4 dashes + 2 braces = 38
  1285. #define CCH_GUID (38)
  1286. IFW32FALSE_EXIT(rBuffer.Win32ResizeBuffer(CCH_GUID + 1, eDoNotPreserveBufferContents));
  1287. // It's still unbelievably slow to use swprintf() here, but this is a good opportunity for someone
  1288. // to optimize in the future if it ever is a perf issue.
  1289. IFW32FALSE_EXIT(
  1290. rBuffer.Win32Format(
  1291. L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
  1292. rGuid.Data1, rGuid.Data2, rGuid.Data3, rGuid.Data4[0], rGuid.Data4[1], rGuid.Data4[2], rGuid.Data4[3], rGuid.Data4[4], rGuid.Data4[5], rGuid.Data4[6], rGuid.Data4[7]));
  1293. INTERNAL_ERROR_CHECK(rBuffer.Cch() == CCH_GUID);
  1294. FN_EPILOG
  1295. }
  1296. BOOL
  1297. SxspParseGUID(
  1298. PCWSTR String,
  1299. SIZE_T Cch,
  1300. GUID &rGuid)
  1301. {
  1302. BOOL fSuccess = FALSE;
  1303. FN_TRACE_WIN32(fSuccess);
  1304. SIZE_T ich = 0;
  1305. ULONG i = 0;
  1306. ULONG acc;
  1307. if (Cch != CCH_GUID)
  1308. {
  1309. ::FusionpDbgPrintEx(
  1310. FUSION_DBG_LEVEL_ERROR,
  1311. "SXS.DLL: SxspParseGUID() caller passed in GUID that is %d characters long; GUIDs must be exactly 38 characters long.\n", Cch);
  1312. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1313. goto Exit;
  1314. }
  1315. ich = 1;
  1316. if (*String++ != L'{')
  1317. {
  1318. ::FusionpDbgPrintEx(
  1319. FUSION_DBG_LEVEL_ERROR,
  1320. "SXS.DLL: SxspParseGUID() caller pass in GUID that does not begin with a left brace ('{')\n");
  1321. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1322. goto Exit;
  1323. }
  1324. ich++;
  1325. // Parse the first segment...
  1326. acc = 0;
  1327. for (i=0; i<8; i++)
  1328. {
  1329. WCHAR wch = *String++;
  1330. if (!::IsHexDigit(wch))
  1331. {
  1332. ::FusionpDbgPrintEx(
  1333. FUSION_DBG_LEVEL_ERROR,
  1334. "SXS.DLL: SxspParseGUID() given GUID where character %d is not hexidecimal\n", ich);
  1335. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1336. goto Exit;
  1337. }
  1338. ich++;
  1339. acc = acc << 4;
  1340. acc += HexDigitToValue(wch);
  1341. }
  1342. rGuid.Data1 = acc;
  1343. // Look for the dash...
  1344. if (*String++ != L'-')
  1345. {
  1346. ::FusionpDbgPrintEx(
  1347. FUSION_DBG_LEVEL_ERROR,
  1348. "SXS.DLL: SxspParseGUID() passed in GUID where character %d is not a dash.\n", ich);
  1349. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1350. goto Exit;
  1351. }
  1352. ich++;
  1353. acc = 0;
  1354. for (i=0; i<4; i++)
  1355. {
  1356. WCHAR wch = *String++;
  1357. if (!::IsHexDigit(wch))
  1358. {
  1359. ::FusionpDbgPrintEx(
  1360. FUSION_DBG_LEVEL_ERROR,
  1361. "SXS.DLL: SxspParseGUID() given GUID where character %d is not hexidecimal\n", ich);
  1362. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1363. goto Exit;
  1364. }
  1365. ich++;
  1366. acc = acc << 4;
  1367. acc += HexDigitToValue(wch);
  1368. }
  1369. rGuid.Data2 = static_cast<USHORT>(acc);
  1370. // Look for the dash...
  1371. if (*String++ != L'-')
  1372. {
  1373. ::FusionpDbgPrintEx(
  1374. FUSION_DBG_LEVEL_ERROR,
  1375. "SXS.DLL: SxspParseGUID() passed in GUID where character %d is not a dash.\n", ich);
  1376. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1377. goto Exit;
  1378. }
  1379. ich++;
  1380. acc = 0;
  1381. for (i=0; i<4; i++)
  1382. {
  1383. WCHAR wch = *String++;
  1384. if (!::IsHexDigit(wch))
  1385. {
  1386. ::FusionpDbgPrintEx(
  1387. FUSION_DBG_LEVEL_ERROR,
  1388. "SXS.DLL: SxspParseGUID() given GUID where character %d is not hexidecimal\n", ich);
  1389. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1390. goto Exit;
  1391. }
  1392. ich++;
  1393. acc = acc << 4;
  1394. acc += HexDigitToValue(wch);
  1395. }
  1396. rGuid.Data3 = static_cast<USHORT>(acc);
  1397. // Look for the dash...
  1398. if (*String++ != L'-')
  1399. {
  1400. ::FusionpDbgPrintEx(
  1401. FUSION_DBG_LEVEL_ERROR,
  1402. "SXS.DLL: SxspParseGUID() passed in GUID where character %d is not a dash.\n", ich);
  1403. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1404. goto Exit;
  1405. }
  1406. ich++;
  1407. for (i=0; i<8; i++)
  1408. {
  1409. WCHAR wch1, wch2;
  1410. wch1 = *String++;
  1411. if (!::IsHexDigit(wch1))
  1412. {
  1413. ::FusionpDbgPrintEx(
  1414. FUSION_DBG_LEVEL_ERROR,
  1415. "SXS.DLL: SxspParseGUID() passed in GUID where character %d is not hexidecimal\n", ich);
  1416. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1417. goto Exit;
  1418. }
  1419. ich++;
  1420. wch2 = *String++;
  1421. if (!::IsHexDigit(wch2))
  1422. {
  1423. ::FusionpDbgPrintEx(
  1424. FUSION_DBG_LEVEL_ERROR,
  1425. "SXS.DLL: SxspParseGUID() passed in GUID where character %d is not hexidecimal\n", ich);
  1426. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1427. goto Exit;
  1428. }
  1429. ich++;
  1430. rGuid.Data4[i] = static_cast<unsigned char>((::HexDigitToValue(wch1) << 4) | ::HexDigitToValue(wch2));
  1431. // There's a dash after the 2nd byte
  1432. if (i == 1)
  1433. {
  1434. if (*String++ != L'-')
  1435. {
  1436. ::FusionpDbgPrintEx(
  1437. FUSION_DBG_LEVEL_ERROR,
  1438. "SXS.DLL: SxspParseGUID() passed in GUID where character %d is not a dash.\n", ich);
  1439. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1440. goto Exit;
  1441. }
  1442. ich++;
  1443. }
  1444. }
  1445. // This replacement should be made.
  1446. //INTERNAL_ERROR_CHECK(ich == CCH_GUID);
  1447. ASSERT(ich == CCH_GUID);
  1448. if (*String != L'}')
  1449. {
  1450. ::FusionpDbgPrintEx(
  1451. FUSION_DBG_LEVEL_ERROR,
  1452. "SXS.DLL: SxspParseGUID() passed in GUID which does not terminate with a closing brace ('}')\n");
  1453. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1454. goto Exit;
  1455. }
  1456. fSuccess = TRUE;
  1457. Exit:
  1458. return fSuccess;
  1459. }
  1460. BOOL
  1461. SxspFormatFileTime(
  1462. LARGE_INTEGER ft,
  1463. CBaseStringBuffer &rBuffer)
  1464. {
  1465. FN_PROLOG_WIN32
  1466. SIZE_T Cch = 0;
  1467. CStringBufferAccessor acc;
  1468. if (ft.QuadPart == 0)
  1469. {
  1470. IFW32FALSE_EXIT(rBuffer.Win32Assign(L"n/a", 3));
  1471. Cch = 3;
  1472. }
  1473. else
  1474. {
  1475. SYSTEMTIME st;
  1476. int iResult = 0;
  1477. int cchDate = 0;
  1478. int cchTime = 0;
  1479. IFW32FALSE_ORIGINATE_AND_EXIT(::FileTimeToSystemTime((FILETIME *) &ft, &st));
  1480. IFW32ZERO_ORIGINATE_AND_EXIT(iResult = ::GetDateFormatW(
  1481. LOCALE_USER_DEFAULT,
  1482. LOCALE_USE_CP_ACP,
  1483. &st,
  1484. NULL,
  1485. NULL,
  1486. 0));
  1487. cchDate = iResult - 1;
  1488. IFW32ZERO_ORIGINATE_AND_EXIT(iResult = ::GetTimeFormatW(
  1489. LOCALE_USER_DEFAULT,
  1490. LOCALE_USE_CP_ACP,
  1491. &st,
  1492. NULL,
  1493. NULL,
  1494. 0));
  1495. cchTime = iResult - 1;
  1496. IFW32FALSE_EXIT(rBuffer.Win32ResizeBuffer(cchDate + 1 + cchTime + 1, eDoNotPreserveBufferContents));
  1497. acc.Attach(&rBuffer);
  1498. IFW32ZERO_ORIGINATE_AND_EXIT(iResult = ::GetDateFormatW(
  1499. LOCALE_USER_DEFAULT,
  1500. LOCALE_USE_CP_ACP,
  1501. &st,
  1502. NULL,
  1503. acc.GetBufferPtr(),
  1504. cchDate + 1));
  1505. // This replacement should be made.
  1506. //INTERNAL_ERROR_CHECK(iResult == (cchDate + 1));
  1507. ASSERT(iResult == (cchDate + 1));
  1508. acc.GetBufferPtr()[cchDate] = L' ';
  1509. IFW32ZERO_ORIGINATE_AND_EXIT(iResult = ::GetTimeFormatW(
  1510. LOCALE_USER_DEFAULT,
  1511. LOCALE_USE_CP_ACP,
  1512. &st,
  1513. NULL,
  1514. acc.GetBufferPtr() + cchDate + 1,
  1515. cchTime + 1));
  1516. // This replacement should be made.
  1517. //INTERNAL_ERROR_CHECK(iResult == (cchTime + 1));
  1518. ASSERT(iResult == (cchTime + 1));
  1519. Cch = (cchDate + 1 + cchTime);
  1520. acc.Detach();
  1521. }
  1522. FN_EPILOG
  1523. }
  1524. BOOL
  1525. SxspGetNDPGacRootDirectory(
  1526. OUT CBaseStringBuffer &rRootDirectory)
  1527. {
  1528. FN_PROLOG_WIN32
  1529. static const WCHAR GacDirectory[] = L"\\Assembly\\GAC";
  1530. const PCWSTR SystemRoot = USER_SHARED_DATA->NtSystemRoot;
  1531. //
  1532. // BUGBUG CAUTION: This doesn't know anything about relocating GACs at the moment!
  1533. //
  1534. IFW32FALSE_EXIT(rRootDirectory.Win32Assign(SystemRoot, ::wcslen(SystemRoot)));
  1535. IFW32FALSE_EXIT(rRootDirectory.Win32AppendPathElement(
  1536. GacDirectory,
  1537. NUMBER_OF(GacDirectory) - 1));
  1538. FN_EPILOG
  1539. }
  1540. BOOL
  1541. SxspGetAssemblyRootDirectory(
  1542. CBaseStringBuffer &rBuffer)
  1543. {
  1544. FN_PROLOG_WIN32
  1545. CStringBufferAccessor acc;
  1546. SIZE_T CchRequired = 0;
  1547. // Short-circuit - if someone wanted to use an alternate assembly store, report it instead
  1548. if (g_AlternateAssemblyStoreRoot)
  1549. {
  1550. IFW32FALSE_EXIT(rBuffer.Win32Assign(g_AlternateAssemblyStoreRoot, ::wcslen(g_AlternateAssemblyStoreRoot)));
  1551. FN_SUCCESSFUL_EXIT();
  1552. }
  1553. acc.Attach(&rBuffer);
  1554. if (!::SxspGetAssemblyRootDirectoryHelper(acc.GetBufferCch(), acc.GetBufferPtr(), &CchRequired))
  1555. {
  1556. DWORD dwLastError = ::FusionpGetLastWin32Error();
  1557. if (dwLastError != ERROR_INSUFFICIENT_BUFFER)
  1558. goto Exit;
  1559. acc.Detach();
  1560. IFW32FALSE_EXIT(rBuffer.Win32ResizeBuffer(CchRequired + 1, eDoNotPreserveBufferContents));
  1561. acc.Attach(&rBuffer);
  1562. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectoryHelper(acc.GetBufferCch(), acc.GetBufferPtr(), NULL));
  1563. }
  1564. acc.Detach();
  1565. FN_EPILOG
  1566. }
  1567. BOOL
  1568. SxspFindLastSegmentOfAssemblyName(
  1569. PCWSTR AssemblyName,
  1570. SIZE_T cchAssemblyName,
  1571. PCWSTR *LastSegment,
  1572. SIZE_T *LastSegmentCch)
  1573. {
  1574. BOOL fSuccess = FALSE;
  1575. FN_TRACE_WIN32(fSuccess);
  1576. if (LastSegment != NULL)
  1577. *LastSegment = NULL;
  1578. if (LastSegmentCch != NULL)
  1579. *LastSegmentCch = 0;
  1580. PARAMETER_CHECK(LastSegment != NULL);
  1581. PARAMETER_CHECK((AssemblyName != NULL) || (cchAssemblyName == 0));
  1582. if (cchAssemblyName != 0)
  1583. {
  1584. PCWSTR LastPartOfAssemblyName = AssemblyName + cchAssemblyName - 1;
  1585. SIZE_T LastPartOfAssemblyNameCch = 1;
  1586. while (LastPartOfAssemblyName != AssemblyName)
  1587. {
  1588. const WCHAR wch = *LastPartOfAssemblyName;
  1589. if ((wch == L'.') || (wch == L'\\') || (wch == L'/'))
  1590. {
  1591. LastPartOfAssemblyName++;
  1592. LastPartOfAssemblyNameCch--;
  1593. break;
  1594. }
  1595. LastPartOfAssemblyName--;
  1596. LastPartOfAssemblyNameCch++;
  1597. }
  1598. *LastSegment = LastPartOfAssemblyName;
  1599. if (LastSegmentCch != NULL)
  1600. *LastSegmentCch = LastPartOfAssemblyNameCch;
  1601. }
  1602. else
  1603. {
  1604. *LastSegment = NULL;
  1605. if (LastSegmentCch != NULL)
  1606. *LastSegmentCch = 0;
  1607. }
  1608. fSuccess = TRUE;
  1609. Exit:
  1610. return fSuccess;
  1611. }
  1612. BOOL
  1613. SxspProcessElementPathMap(
  1614. PCACTCTXCTB_PARSE_CONTEXT ParseContext,
  1615. PCELEMENT_PATH_MAP_ENTRY MapEntries,
  1616. SIZE_T MapEntryCount,
  1617. ULONG &MappedValue,
  1618. bool &Found)
  1619. {
  1620. BOOL fSuccess = FALSE;
  1621. FN_TRACE_WIN32(fSuccess);
  1622. ULONG XMLElementDepth = 0;
  1623. PCWSTR ElementPath = NULL;
  1624. SIZE_T ElementPathCch = 0;
  1625. SIZE_T i = 0;
  1626. PARAMETER_CHECK(ParseContext != NULL);
  1627. PARAMETER_CHECK((MapEntries != NULL) || (MapEntryCount == 0));
  1628. XMLElementDepth = ParseContext->XMLElementDepth;
  1629. ElementPath = ParseContext->ElementPath;
  1630. ElementPathCch = ParseContext->ElementPathCch;
  1631. MappedValue = 0;
  1632. Found = false;
  1633. for (i=0; i<MapEntryCount; i++)
  1634. {
  1635. if ((MapEntries[i].ElementDepth == XMLElementDepth) &&
  1636. (MapEntries[i].ElementPathCch == ElementPathCch) &&
  1637. (::FusionpCompareStrings(
  1638. ElementPath,
  1639. ElementPathCch,
  1640. MapEntries[i].ElementPath,
  1641. ElementPathCch,
  1642. false) == 0))
  1643. {
  1644. MappedValue = MapEntries[i].MappedValue;
  1645. Found = true;
  1646. break;
  1647. }
  1648. }
  1649. fSuccess = TRUE;
  1650. Exit:
  1651. return fSuccess;
  1652. }
  1653. BOOL
  1654. SxspParseUSHORT(
  1655. PCWSTR String,
  1656. SIZE_T Cch,
  1657. USHORT *Value)
  1658. {
  1659. BOOL fSuccess = FALSE;
  1660. FN_TRACE_WIN32(fSuccess);
  1661. USHORT Temp = 0;
  1662. PARAMETER_CHECK((String != NULL) || (Cch == 0));
  1663. while (Cch != 0)
  1664. {
  1665. WCHAR wch = *String++;
  1666. if ((wch < L'0') || (wch > L'9'))
  1667. {
  1668. ::FusionpDbgPrintEx(
  1669. FUSION_DBG_LEVEL_ERROR,
  1670. "SXS.DLL: Error parsing 16-bit unsigned short integer; character other than 0-9 found\n");
  1671. ::FusionpSetLastWin32Error(ERROR_SXS_MANIFEST_PARSE_ERROR);
  1672. goto Exit;
  1673. }
  1674. Temp = (Temp * 10) + (wch - L'0');
  1675. Cch--;
  1676. }
  1677. if (Value != NULL)
  1678. *Value = Temp;
  1679. fSuccess = TRUE;
  1680. Exit:
  1681. return fSuccess;
  1682. }
  1683. /*-----------------------------------------------------------------------------
  1684. create a unique temp directory under %windir%\WinSxs
  1685. -----------------------------------------------------------------------------*/
  1686. BOOL
  1687. SxspCreateWinSxsTempDirectory(
  1688. OUT CBaseStringBuffer &rbuffTemp,
  1689. OUT SIZE_T *pcch OPTIONAL,
  1690. OUT CBaseStringBuffer *pbuffUniquePart OPTIONAL,
  1691. OUT SIZE_T *pcchUniquePart OPTIONAL)
  1692. {
  1693. BOOL fSuccess = FALSE;
  1694. FN_TRACE_WIN32(fSuccess);
  1695. INT iTries = 0;
  1696. CSmallStringBuffer uidBuffer;
  1697. CBaseStringBuffer *puidBuffer = (pbuffUniquePart != NULL) ? pbuffUniquePart : &uidBuffer;
  1698. INTERNAL_ERROR_CHECK(rbuffTemp.IsEmpty());
  1699. INTERNAL_ERROR_CHECK(puidBuffer->IsEmpty());
  1700. for (iTries = 0 ; rbuffTemp.IsEmpty() && iTries < 2 ; ++iTries)
  1701. {
  1702. SXSP_LOCALLY_UNIQUE_ID luid;
  1703. IFW32FALSE_EXIT(::SxspCreateLocallyUniqueId(&luid));
  1704. IFW32FALSE_EXIT(::SxspFormatLocallyUniqueId(luid, *puidBuffer));
  1705. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(rbuffTemp));
  1706. IFW32FALSE_EXIT(rbuffTemp.Win32RemoveTrailingPathSeparators()); // CreateDirectory doesn't like them
  1707. // create \winnt\WinSxs, must not delete even on failure
  1708. if (::CreateDirectoryW(rbuffTemp, NULL))
  1709. {
  1710. // We don't care if this fails.
  1711. ::SetFileAttributesW(rbuffTemp, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
  1712. }
  1713. else if (::FusionpGetLastWin32Error() != ERROR_ALREADY_EXISTS)
  1714. {
  1715. TRACE_WIN32_FAILURE_ORIGINATION(CreateDirectoryW);
  1716. goto Exit;
  1717. }
  1718. // create \winnt\winsxs\manifests, must not delete even on failure
  1719. IFW32FALSE_EXIT(rbuffTemp.Win32EnsureTrailingPathSeparator());
  1720. IFW32FALSE_EXIT(rbuffTemp.Win32Append(MANIFEST_ROOT_DIRECTORY_NAME, NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) - 1));
  1721. if (::CreateDirectoryW(rbuffTemp, NULL))
  1722. {
  1723. ::SetFileAttributesW(rbuffTemp, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
  1724. }
  1725. else if (::FusionpGetLastWin32Error() != ERROR_ALREADY_EXISTS)
  1726. {
  1727. TRACE_WIN32_FAILURE_ORIGINATION(CreateDirectoryW);
  1728. goto Exit;
  1729. }
  1730. // restore to be "\winnt\winsxs\"
  1731. IFW32FALSE_EXIT(rbuffTemp.Win32RemoveLastPathElement());
  1732. #if SXSP_SEMIREADABLE_INSTALL_TEMP
  1733. // create \winnt\WinSxs\InstallTemp, must not delete even on failure
  1734. ASSERT(::SxspIsSfcIgnoredStoreSubdir(ASSEMBLY_INSTALL_TEMP_DIR_NAME));
  1735. IFW32FALSE_EXIT(rbuffTemp.Win32AppendPathElement(ASSEMBLY_INSTALL_TEMP_DIR_NAME, NUMBER_OF(ASSEMBLY_INSTALL_TEMP_DIR_NAME) - 1));
  1736. IFW32FALSE_ORIGINATE_AND_EXIT(::CreateDirectoryW(rbuffTemp, NULL) || ::FusionpGetLastWin32Error() == ERROR_ALREADY_EXISTS);
  1737. #endif
  1738. IFW32FALSE_EXIT(rbuffTemp.Win32EnsureTrailingPathSeparator());
  1739. IFW32FALSE_EXIT(rbuffTemp.Win32Append(*puidBuffer, puidBuffer->Cch()));
  1740. if (!::CreateDirectoryW(rbuffTemp, NULL))
  1741. {
  1742. rbuffTemp.Clear();
  1743. if (::FusionpGetLastWin32Error() != ERROR_ALREADY_EXISTS)
  1744. {
  1745. TRACE_WIN32_FAILURE_ORIGINATION(CreateDirectoryW);
  1746. goto Exit;
  1747. }
  1748. }
  1749. }
  1750. INTERNAL_ERROR_CHECK(!rbuffTemp.IsEmpty());
  1751. if (pcch != NULL)
  1752. *pcch = rbuffTemp.Cch();
  1753. if (pcchUniquePart != NULL)
  1754. *pcchUniquePart = pbuffUniquePart->Cch();
  1755. fSuccess = TRUE;
  1756. Exit:
  1757. return fSuccess;
  1758. }
  1759. BOOL
  1760. SxspCreateRunOnceDeleteDirectory(
  1761. IN const CBaseStringBuffer &rbuffDirectoryToDelete,
  1762. IN const CBaseStringBuffer *pbuffUniqueKey OPTIONAL,
  1763. OUT PVOID* cookie)
  1764. {
  1765. BOOL fSuccess = FALSE;
  1766. FN_TRACE_WIN32(fSuccess);
  1767. CRunOnceDeleteDirectory* p = NULL;
  1768. IFALLOCFAILED_EXIT(p = new CRunOnceDeleteDirectory);
  1769. IFW32FALSE_EXIT(p->Initialize(rbuffDirectoryToDelete, pbuffUniqueKey));
  1770. *cookie = p;
  1771. p = NULL;
  1772. fSuccess = TRUE;
  1773. Exit:
  1774. FUSION_DELETE_SINGLETON(p);
  1775. return fSuccess;
  1776. }
  1777. BOOL
  1778. SxspCancelRunOnceDeleteDirectory(
  1779. PVOID cookie)
  1780. {
  1781. BOOL fSuccess = FALSE;
  1782. FN_TRACE_WIN32(fSuccess);
  1783. CRunOnceDeleteDirectory* p = reinterpret_cast<CRunOnceDeleteDirectory*>(cookie);
  1784. IFW32FALSE_EXIT(p->Cancel());
  1785. fSuccess = TRUE;
  1786. Exit:
  1787. return fSuccess;
  1788. }
  1789. BOOL
  1790. CRunOnceDeleteDirectory::Initialize(
  1791. IN const CBaseStringBuffer &rbuffDirectoryToDelete,
  1792. IN const CBaseStringBuffer *pbuffUniqueKey OPTIONAL)
  1793. {
  1794. BOOL fSuccess = FALSE;
  1795. FN_TRACE_WIN32(fSuccess);
  1796. CSmallStringBuffer buffUniqueKey;
  1797. HKEY hKey = NULL;
  1798. DWORD dwRegDisposition = 0;
  1799. LONG lReg = 0;
  1800. CStringBuffer buffValue;
  1801. if (!::SxspAtExit(this))
  1802. {
  1803. TRACE_WIN32_FAILURE(SxspAtExit);
  1804. FUSION_DELETE_SINGLETON(this);
  1805. goto Exit;
  1806. }
  1807. if (pbuffUniqueKey == NULL)
  1808. {
  1809. SXSP_LOCALLY_UNIQUE_ID luid;
  1810. IFW32FALSE_EXIT(::SxspCreateLocallyUniqueId(&luid));
  1811. IFW32FALSE_EXIT(::SxspFormatLocallyUniqueId(luid, buffUniqueKey));
  1812. pbuffUniqueKey = &buffUniqueKey;
  1813. }
  1814. IFREGFAILED_ORIGINATE_AND_EXIT(
  1815. lReg =
  1816. ::RegCreateKeyExW(
  1817. hKeyRunOnceRoot,
  1818. rgchRunOnceSubKey,
  1819. 0, // reserved
  1820. NULL, // class
  1821. REG_OPTION_NON_VOLATILE,
  1822. KEY_SET_VALUE | FUSIONP_KEY_WOW64_64KEY,
  1823. NULL, // security
  1824. &hKey,
  1825. &dwRegDisposition));
  1826. m_hKey = hKey;
  1827. IFW32FALSE_EXIT(m_strValueName.Win32Assign(rgchRunOnceValueNameBase, ::wcslen(rgchRunOnceValueNameBase)));
  1828. IFW32FALSE_EXIT(m_strValueName.Win32Append(*pbuffUniqueKey));
  1829. IFW32FALSE_EXIT(buffValue.Win32Assign(rgchRunOnePrefix, ::wcslen(rgchRunOnePrefix)));
  1830. IFW32FALSE_EXIT(buffValue.Win32Append(rbuffDirectoryToDelete));
  1831. IFREGFAILED_ORIGINATE_AND_EXIT(
  1832. lReg =
  1833. ::RegSetValueExW(
  1834. hKey,
  1835. m_strValueName,
  1836. 0, // reserved
  1837. REG_SZ,
  1838. reinterpret_cast<const BYTE*>(static_cast<PCWSTR>(buffValue)),
  1839. static_cast<ULONG>((buffValue.Cch() + 1) * sizeof(WCHAR))));
  1840. fSuccess = TRUE;
  1841. Exit:
  1842. return fSuccess;
  1843. }
  1844. CRunOnceDeleteDirectory::~CRunOnceDeleteDirectory(
  1845. )
  1846. {
  1847. CSxsPreserveLastError ple;
  1848. this->Cancel();
  1849. ple.Restore();
  1850. }
  1851. BOOL
  1852. CRunOnceDeleteDirectory::Close(
  1853. )
  1854. {
  1855. BOOL fSuccess = FALSE;
  1856. FN_TRACE_WIN32(fSuccess);
  1857. // very unusual.. this is noncrashing, but
  1858. // leaves the stuff in the registry
  1859. m_strValueName.Clear();
  1860. IFW32FALSE_EXIT(m_hKey.Win32Close());
  1861. fSuccess = TRUE;
  1862. Exit:
  1863. return fSuccess;
  1864. }
  1865. BOOL
  1866. CRunOnceDeleteDirectory::Cancel(
  1867. )
  1868. {
  1869. BOOL fSuccess = TRUE;
  1870. FN_TRACE_WIN32(fSuccess);
  1871. if (!m_strValueName.IsEmpty())
  1872. {
  1873. LONG lReg = ::RegDeleteValueW(m_hKey, m_strValueName);
  1874. if (lReg != ERROR_SUCCESS)
  1875. {
  1876. fSuccess = FALSE;
  1877. ::FusionpSetLastWin32Error(lReg);
  1878. ::FusionpDbgPrintEx(
  1879. FUSION_DBG_LEVEL_ERROR,
  1880. "SXS.DLL: %s(): RegDeleteValueW(RunOnce,%ls) failed:%ld\n",
  1881. __FUNCTION__,
  1882. static_cast<PCWSTR>(m_strValueName),
  1883. lReg);
  1884. }
  1885. }
  1886. if (!m_hKey.Win32Close())
  1887. {
  1888. fSuccess = FALSE;
  1889. ::FusionpDbgPrintEx(
  1890. FUSION_DBG_LEVEL_ERROR,
  1891. "SXS.DLL: %s(): RegCloseKey(RunOnce) failed:%ld\n",
  1892. __FUNCTION__,
  1893. ::FusionpGetLastWin32Error()
  1894. );
  1895. }
  1896. m_strValueName.Clear();
  1897. if (fSuccess && ::SxspTryCancelAtExit(this))
  1898. FUSION_DELETE_SINGLETON(this);
  1899. return fSuccess;
  1900. }
  1901. /* ///////////////////////////////////////////////////////////////////////////////////////
  1902. CurrentDirectory
  1903. is fully qualified directory path, for example, "c:\tmp"
  1904. pwszNewDirs
  1905. is a string such as "a\b\c\d", this function would create "c:\tmp\a", "c:\tmp\a\b",
  1906. "c:\tmp\a\b\c", and "c:\tmp\a\b\c\d"
  1907. Merge this with util\io.cpp\FusionpCreateDirectories.
  1908. ///////////////////////////////////////////////////////////////////////////////////////// */
  1909. BOOL SxspCreateMultiLevelDirectory(PCWSTR CurrentDirectory, PCWSTR pwszNewDirs)
  1910. {
  1911. FN_PROLOG_WIN32
  1912. PCWSTR p = NULL;
  1913. CStringBuffer FullPathSubDirBuf;
  1914. PARAMETER_CHECK(pwszNewDirs != NULL);
  1915. p = pwszNewDirs;
  1916. IFW32FALSE_EXIT(FullPathSubDirBuf.Win32Assign(CurrentDirectory, ::wcslen(CurrentDirectory)));
  1917. while (*p)
  1918. {
  1919. SIZE_T cCharsInSegment;
  1920. //
  1921. // How long is this segment?
  1922. //
  1923. cCharsInSegment = wcscspn(p, CUnicodeCharTraits::PathSeparators());
  1924. //
  1925. // Zero characters in this segment?
  1926. //
  1927. if (cCharsInSegment == 0)
  1928. break;
  1929. IFW32FALSE_EXIT(FullPathSubDirBuf.Win32EnsureTrailingPathSeparator());
  1930. IFW32FALSE_EXIT(FullPathSubDirBuf.Win32Append(p, cCharsInSegment));
  1931. IFW32FALSE_ORIGINATE_AND_EXIT(
  1932. CreateDirectoryW(FullPathSubDirBuf, NULL) ||
  1933. ::FusionpGetLastWin32Error() == ERROR_ALREADY_EXISTS);
  1934. //
  1935. // Increment path buffer pointer, and skip the next set of slashes.
  1936. //
  1937. p += cCharsInSegment;
  1938. p += wcsspn(p, CUnicodeCharTraits::PathSeparators());
  1939. }
  1940. FN_EPILOG
  1941. }
  1942. //
  1943. // ISSUE - 2002/05/05 - This is gross, don't rely on GetFileAttributes like this, use
  1944. // SxspDoesFileExist instead.
  1945. //
  1946. BOOL SxspInstallDecompressOrCopyFileW(PCWSTR lpSource, PCWSTR lpDest, BOOL bFailIfExists)
  1947. {
  1948. FN_PROLOG_WIN32
  1949. bool fExist = false;
  1950. IFW32FALSE_EXIT(::SxspDoesFileExist(SXSP_DOES_FILE_EXIST_FLAG_CHECK_FILE_ONLY, lpDest, fExist));
  1951. if (fExist)
  1952. {
  1953. if (bFailIfExists == FALSE)
  1954. {
  1955. IFW32FALSE_ORIGINATE_AND_EXIT(::SetFileAttributesW(lpDest, FILE_ATTRIBUTE_NORMAL));
  1956. IFW32FALSE_ORIGINATE_AND_EXIT(::DeleteFileW(lpDest));
  1957. }else
  1958. {
  1959. ::SetLastError(ERROR_FILE_EXISTS);
  1960. goto Exit;
  1961. }
  1962. }
  1963. DWORD err = ::SetupDecompressOrCopyFileW(lpSource, lpDest, NULL);
  1964. if (err != ERROR_SUCCESS)
  1965. {
  1966. ::SetLastError(err);
  1967. goto Exit;
  1968. }
  1969. FN_EPILOG
  1970. }
  1971. //
  1972. // Function :
  1973. // For files, it try to decompress a compressed file before move,
  1974. // for firectories, it would work as MoveFileExW, fail if the dirs are on different
  1975. // volumns
  1976. //
  1977. BOOL SxspInstallDecompressAndMoveFileExW(
  1978. LPCWSTR lpExistingFileName,
  1979. LPCWSTR lpNewFileName,
  1980. DWORD dwFlags,
  1981. BOOL fAwareNonCompressed)
  1982. {
  1983. FN_PROLOG_WIN32
  1984. DWORD dwTemp1 = 0;
  1985. DWORD dwTemp2 = 0;
  1986. UINT uiCompressType = 0;
  1987. PWSTR pszCompressedFileName = NULL;
  1988. bool fExist = false;
  1989. //
  1990. // make sure that the source file exists, based on SetupGetFileCompressionInfo() in MSDN :
  1991. // Because SetupGetFileCompressionInfo determines the compression by referencing the physical file, your setup application
  1992. // should ensure that the file is present before calling SetupGetFileCompressionInfo.
  1993. //
  1994. IFW32FALSE_EXIT(SxspDoesFileExist(0, lpExistingFileName, fExist));
  1995. if (!fExist)
  1996. {
  1997. if (fAwareNonCompressed)
  1998. {
  1999. goto Exit;
  2000. }
  2001. // it is possible that the file existed is named as a.dl_, while the input file name is a.dll, in this case, we
  2002. // assume that lpExistingFileName is a filename of compressed file, so just go ahead to call SetupDecompressOrCopyFile
  2003. IFW32FALSE_EXIT(::SxspInstallDecompressOrCopyFileW(lpExistingFileName, lpNewFileName, !(dwFlags & MOVEFILE_REPLACE_EXISTING)));
  2004. //
  2005. // try to find the "realname" of the file, which is in compression-format, so that we could delete it
  2006. // because the compressed file is named in a way we do not know, such as a.dl_ or a.dl$,
  2007. if (::SetupGetFileCompressionInfoW(lpExistingFileName, &pszCompressedFileName, &dwTemp1, &dwTemp2, &uiCompressType) != NO_ERROR)
  2008. {
  2009. goto Exit;
  2010. }
  2011. IFW32FALSE_ORIGINATE_AND_EXIT(::SetFileAttributesW(pszCompressedFileName, FILE_ATTRIBUTE_NORMAL));
  2012. IFW32FALSE_ORIGINATE_AND_EXIT(::DeleteFileW(pszCompressedFileName));
  2013. goto WellDone;
  2014. }
  2015. DWORD dwAttributes = 0;
  2016. IFW32FALSE_EXIT(SxspGetFileAttributesW(lpExistingFileName, dwAttributes));
  2017. if ((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  2018. {
  2019. //
  2020. // this file is named in normal way, such as "a.dll" but it is also possible that it is compressed
  2021. //
  2022. IFW32FALSE_EXIT(::SxspDoesFileExist(SXSP_DOES_FILE_EXIST_FLAG_CHECK_FILE_ONLY, lpNewFileName, fExist));
  2023. if (fExist)
  2024. {
  2025. if ((dwFlags & MOVEFILE_REPLACE_EXISTING))
  2026. {
  2027. IFW32FALSE_ORIGINATE_AND_EXIT(::SetFileAttributesW(lpNewFileName, FILE_ATTRIBUTE_NORMAL));
  2028. IFW32FALSE_ORIGINATE_AND_EXIT(::DeleteFileW(lpNewFileName));
  2029. }
  2030. else
  2031. {
  2032. ::SetLastError(ERROR_FILE_EXISTS);
  2033. goto Exit;
  2034. }
  2035. }
  2036. if (! fAwareNonCompressed)
  2037. {
  2038. if (::SetupGetFileCompressionInfoW(lpExistingFileName, &pszCompressedFileName, &dwTemp1, &dwTemp2, &uiCompressType) != NO_ERROR)
  2039. {
  2040. goto Exit;
  2041. }
  2042. LocalFree(pszCompressedFileName);
  2043. pszCompressedFileName = NULL;
  2044. if ((dwTemp1 == dwTemp2) && (uiCompressType == FILE_COMPRESSION_NONE ))
  2045. {
  2046. //BUGBUG:
  2047. // this only mean the compress algo is not recognized, may or maynot be compressed
  2048. //
  2049. IFW32FALSE_ORIGINATE_AND_EXIT(::MoveFileExW(lpExistingFileName, lpNewFileName, dwFlags));
  2050. }
  2051. else
  2052. {
  2053. IFW32FALSE_EXIT(::SxspInstallDecompressOrCopyFileW(lpExistingFileName, lpNewFileName, !(dwFlags & MOVEFILE_REPLACE_EXISTING)));
  2054. //
  2055. // try to delete the original file after copy it into destination
  2056. //
  2057. IFW32FALSE_ORIGINATE_AND_EXIT(::SetFileAttributesW(lpExistingFileName, FILE_ATTRIBUTE_NORMAL));
  2058. IFW32FALSE_ORIGINATE_AND_EXIT(::DeleteFileW(lpExistingFileName));
  2059. }
  2060. }
  2061. else
  2062. {
  2063. // already know that the file is non-compressed, move directly
  2064. IFW32FALSE_ORIGINATE_AND_EXIT(::MoveFileExW(lpExistingFileName, lpNewFileName, dwFlags));
  2065. }
  2066. }
  2067. else
  2068. {
  2069. // move a directory, it would just fail as MoveFileExW if the destination is on a different volumn from the source
  2070. IFW32FALSE_ORIGINATE_AND_EXIT(::MoveFileExW(lpExistingFileName, lpNewFileName, dwFlags));
  2071. }
  2072. WellDone:
  2073. __fSuccess = TRUE;
  2074. Exit:
  2075. if (pszCompressedFileName != NULL)
  2076. LocalFree(pszCompressedFileName);
  2077. return __fSuccess;
  2078. }
  2079. //
  2080. // Function:
  2081. // same as MoveFileExW except
  2082. // (1) if the source is compressed, this func would decompress the file before move
  2083. // (2) if the destination has existed, compare the source and destination in "our" way, if the comparison result is EQUAL
  2084. // exit with TRUE
  2085. //
  2086. // Note: for directories on different Volumn, it would just fail, as MoveFileExW
  2087. BOOL
  2088. SxspInstallMoveFileExW(
  2089. CBaseStringBuffer &moveOrigination,
  2090. CBaseStringBuffer &moveDestination,
  2091. DWORD dwFlags,
  2092. BOOL fAwareNonCompressed
  2093. )
  2094. {
  2095. BOOL fSuccess = FALSE;
  2096. FN_TRACE_WIN32(fSuccess);
  2097. DWORD dwLastError = 0;
  2098. CFusionDirectoryDifference directoryDifference;
  2099. if (::SxspInstallDecompressAndMoveFileExW(moveOrigination, moveDestination, dwFlags, fAwareNonCompressed) == 0) // MoveFileExW failed
  2100. {
  2101. //
  2102. // MoveFileExW failed, but if the existing destination is the "same" as the source, the failure is acceptable
  2103. //
  2104. dwLastError = ::FusionpGetLastWin32Error();
  2105. DWORD dwFileAttributes = 0;
  2106. bool fExist = false;
  2107. IFW32FALSE_EXIT(SxspDoesFileExist(0, moveDestination, fExist));
  2108. if (!fExist)
  2109. {
  2110. #if DBG
  2111. ::FusionpDbgPrintEx(
  2112. FUSION_DBG_LEVEL_ERROR,
  2113. "SXS.DLL: %s(): MoveFile(%ls,%ls,%s) failed %lu\n",
  2114. __FUNCTION__,
  2115. static_cast<PCWSTR>(moveOrigination),
  2116. static_cast<PCWSTR>(moveDestination),
  2117. (dwFlags & MOVEFILE_REPLACE_EXISTING) ? "MOVEFILE_REPLACE_EXISTING" : "0",
  2118. dwLastError
  2119. );
  2120. #endif
  2121. ORIGINATE_WIN32_FAILURE_AND_EXIT(MoveFileExW, dwLastError);
  2122. }
  2123. IFW32FALSE_EXIT(SxspGetFileAttributesW(moveDestination, dwFileAttributes));
  2124. if ((dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  2125. {
  2126. //
  2127. // if the destination file has already been there but the error is not ERROR_ALREADY_EXISTS,
  2128. // we give up, otherwise, we would compare the two files later
  2129. //
  2130. if ((dwLastError != ERROR_ALREADY_EXISTS) &&
  2131. (dwLastError != ERROR_FILE_EXISTS))
  2132. /*
  2133. && dwLastError != ERROR_USER_MAPPED_FILE
  2134. && dwLastError != ERROR_ACCESS_DENIED
  2135. && dwLastError != ERROR_SHARING_VIOLATION
  2136. )*/
  2137. {
  2138. ORIGINATE_WIN32_FAILURE_AND_EXIT(MoveFileExW, dwLastError);
  2139. }
  2140. }
  2141. else
  2142. {
  2143. if (dwLastError != ERROR_ACCESS_DENIED
  2144. && dwLastError != ERROR_ALREADY_EXISTS)
  2145. ORIGINATE_WIN32_FAILURE_AND_EXIT(MoveFileExW, dwLastError);
  2146. }
  2147. //
  2148. // We could delete the file if fReplaceExisting, but that doesn't feel safe.
  2149. //
  2150. //
  2151. // in case there is a preexisting directory, that's probably why the move failed
  2152. //
  2153. if (dwFlags & MOVEFILE_REPLACE_EXISTING)
  2154. {
  2155. CStringBuffer tempDirForRenameExistingAway;
  2156. CSmallStringBuffer uidBuffer;
  2157. CFullPathSplitPointers splitExistingDir;
  2158. BOOL fHaveTempDir = FALSE;
  2159. //
  2160. // try a directory swap,
  2161. // if that fails, say because some of the files are in use, we'll try other
  2162. // things; though some failures we must bail on (like out of memory)
  2163. //
  2164. IFW32FALSE_EXIT(splitExistingDir.Initialize(moveDestination));
  2165. IFW32FALSE_EXIT(::SxspCreateWinSxsTempDirectory(tempDirForRenameExistingAway, NULL, &uidBuffer, NULL));
  2166. fHaveTempDir = TRUE;
  2167. IFW32FALSE_EXIT(
  2168. tempDirForRenameExistingAway.Win32AppendPathElement(
  2169. splitExistingDir.m_name,
  2170. (splitExistingDir.m_name != NULL) ? ::wcslen(splitExistingDir.m_name) : 0));
  2171. //
  2172. // move file into temporary directory, so we do not need worry about Compressed file
  2173. //
  2174. if (!::MoveFileExW(moveDestination, tempDirForRenameExistingAway, FALSE)) // no decompress needed
  2175. {
  2176. dwLastError = ::FusionpGetLastWin32Error();
  2177. if ((dwLastError == ERROR_SHARING_VIOLATION) ||
  2178. (dwLastError == ERROR_USER_MAPPED_FILE))
  2179. {
  2180. goto TryMovingFiles;
  2181. }
  2182. ORIGINATE_WIN32_FAILURE_AND_EXIT(MoveFileExW, dwLastError);
  2183. }
  2184. //
  2185. // try again after move the existing dest file into tempDirectory,
  2186. // use DecompressAndMove instead of move because we are trying to copy file into Destination
  2187. //
  2188. if (!::SxspInstallDecompressAndMoveFileExW(moveOrigination, moveDestination, FALSE, fAwareNonCompressed))
  2189. {
  2190. dwLastError = ::FusionpGetLastWin32Error();
  2191. // rollback from temporaray to dest
  2192. if (!::MoveFileExW(tempDirForRenameExistingAway, moveDestination, FALSE)) // no decompress needed
  2193. {
  2194. // uh oh, rollback failed, very bad, call in SQL Server..
  2195. // so much for transactional + replace existing..
  2196. }
  2197. ORIGINATE_WIN32_FAILURE_AND_EXIT(MoveFileExW, dwLastError);
  2198. }
  2199. // success, now just cleanup, do we care about failure here?
  2200. // \winnt\winsxs\installtemp\1234\x86_comctl_6.0
  2201. // -> \winnt\winsxs\installtemp\1234
  2202. IFW32FALSE_EXIT(tempDirForRenameExistingAway.Win32RemoveLastPathElement());
  2203. if (!::SxspDeleteDirectory(tempDirForRenameExistingAway))
  2204. {
  2205. const DWORD Error = ::FusionpGetLastWin32Error();
  2206. ::FusionpDbgPrintEx(
  2207. FUSION_DBG_LEVEL_ERROR,
  2208. "SXS.DLL: %s(): SxspDeleteDirectory(%ls) failed:%ld\n",
  2209. __FUNCTION__,
  2210. static_cast<PCWSTR>(tempDirForRenameExistingAway),
  2211. Error);
  2212. }
  2213. /*
  2214. if (!::SxspDeleteDirectory(tempDirForRenameExistingAway))
  2215. {
  2216. CRunOnceDeleteDirectory runOnceDeleteRenameExistingAwayDirectory;
  2217. runOnceDeleteRenameExistingAwayDirectory.Initialize(tempDirForRenameExistingAway, NULL);
  2218. runOnceDeleteRenameExistingAwayDirectory.Close(); // leave the data in the registry
  2219. }
  2220. */
  2221. goto TryMoveFilesEnd;
  2222. TryMovingFiles:
  2223. // need parallel directory walk class (we actually do this in SxspMoveFilesAndSubdirUnderDirectory)
  2224. // otherwise punt
  2225. goto Exit;
  2226. //ORIGINATE_WIN32_FAILURE_AND_EXIT(MoveFileExW, dwLastError);
  2227. TryMoveFilesEnd:;
  2228. }
  2229. else // !fReplaceExisting
  2230. {
  2231. // compare them
  2232. // DbgPrint if they vary
  2233. // fail if they vary
  2234. // succeed if they do not vary
  2235. if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  2236. {
  2237. if (!::FusionpCompareDirectoriesSizewiseRecursively(&directoryDifference, moveOrigination, moveDestination))
  2238. {
  2239. const DWORD Error = ::FusionpGetLastWin32Error();
  2240. ::FusionpDbgPrintEx(
  2241. FUSION_DBG_LEVEL_ERROR,
  2242. "SXS.DLL: %s(): FusionpCompareDirectoriesSizewiseRecursively(%ls,%ls) failed:%ld\n",
  2243. __FUNCTION__,
  2244. static_cast<PCWSTR>(moveOrigination),
  2245. static_cast<PCWSTR>(moveDestination),
  2246. Error);
  2247. goto Exit;
  2248. //ORIGINATE_WIN32_FAILURE_AND_EXIT(FusionpCompareDirectoriesSizewiseRecursively, Error);
  2249. }
  2250. if (directoryDifference.m_e != CFusionDirectoryDifference::eEqual)
  2251. {
  2252. ::FusionpDbgPrintEx(
  2253. FUSION_DBG_LEVEL_ERROR,
  2254. "SXS.DLL: %s(): MoveFile(%ls,%ls) failed, UNequal duplicate assembly : ERROR_ALREADY_EXISTS\n",
  2255. __FUNCTION__,
  2256. static_cast<PCWSTR>(moveOrigination),
  2257. static_cast<PCWSTR>(moveDestination));
  2258. directoryDifference.DbgPrint(moveOrigination, moveDestination);
  2259. ORIGINATE_WIN32_FAILURE_AND_EXIT(DifferentAssemblyWithSameIdentityAlreadyInstalledAndNotReplaceExisting, ERROR_ALREADY_EXISTS);
  2260. }
  2261. else
  2262. {
  2263. // They're equal so the installation is effectively done.
  2264. ::FusionpDbgPrintEx(
  2265. FUSION_DBG_LEVEL_INFO | FUSION_DBG_LEVEL_INSTALLATION,
  2266. "SXS.DLL: %s(): MoveFile(%ls,%ls) failed, equal duplicate assembly ignored\n",
  2267. __FUNCTION__,
  2268. static_cast<PCWSTR>(moveOrigination),
  2269. static_cast<PCWSTR>(moveDestination));
  2270. // fall through, no goto Exit
  2271. }
  2272. }
  2273. else // move files
  2274. {
  2275. // At least let's see if they have the same size.
  2276. WIN32_FILE_ATTRIBUTE_DATA wfadOrigination;
  2277. WIN32_FILE_ATTRIBUTE_DATA wfadDestination;
  2278. IFW32FALSE_EXIT(
  2279. ::GetFileAttributesExW(
  2280. moveOrigination,
  2281. GetFileExInfoStandard,
  2282. &wfadOrigination));
  2283. IFW32FALSE_EXIT(
  2284. ::GetFileAttributesExW(
  2285. moveDestination,
  2286. GetFileExInfoStandard,
  2287. &wfadDestination));
  2288. if ((wfadOrigination.nFileSizeHigh == wfadDestination.nFileSizeHigh) &&
  2289. (wfadOrigination.nFileSizeLow == wfadDestination.nFileSizeLow))
  2290. {
  2291. // let's call it even
  2292. // We should use SxspCompareFiles here.
  2293. #if DBG
  2294. ::FusionpDbgPrintEx(
  2295. FUSION_DBG_LEVEL_INSTALLATION,
  2296. "SXS: %s - move %ls -> %ls claimed success because files have same size\n",
  2297. __FUNCTION__,
  2298. static_cast<PCWSTR>(moveOrigination),
  2299. static_cast<PCWSTR>(moveDestination)
  2300. );
  2301. #endif
  2302. }
  2303. else
  2304. {
  2305. ORIGINATE_WIN32_FAILURE_AND_EXIT(SxspInstallMoveFileExW, dwLastError);
  2306. }
  2307. }//end of if (dwFlags == SXS_INSTALLATION_MOVE_DIRECTORY)
  2308. } // end of if (fReplaceFiles)
  2309. } // end of if (MoveFileX())
  2310. fSuccess = TRUE;
  2311. Exit:
  2312. #if DBG
  2313. if (!fSuccess)
  2314. {
  2315. ::FusionpDbgPrintEx(
  2316. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR,
  2317. "SXS: %s(0x%lx, %ls, %ls, %s) failing %lu\n",
  2318. __FUNCTION__, dwFlags, static_cast<PCWSTR>(moveOrigination), static_cast<PCWSTR>(moveDestination),
  2319. (dwFlags & MOVEFILE_REPLACE_EXISTING)? "replace_existing" : "do_not_replace_existing", ::FusionpGetLastWin32Error());
  2320. }
  2321. #endif
  2322. return fSuccess;
  2323. }
  2324. inline
  2325. bool IsErrorInErrorList(
  2326. DWORD dwError,
  2327. SIZE_T cErrors,
  2328. va_list Errors
  2329. )
  2330. {
  2331. for (cErrors; cErrors > 0; cErrors--)
  2332. {
  2333. if (dwError == va_arg(Errors, DWORD))
  2334. return true;
  2335. }
  2336. return false;
  2337. }
  2338. BOOL
  2339. SxspDoesPathCrossReparsePointVa(
  2340. IN PCWSTR pcwszBasePathBuffer,
  2341. IN SIZE_T cchBasePathBuffer,
  2342. IN PCWSTR pcwszTotalPathBuffer,
  2343. IN SIZE_T cchTotalPathBuffer,
  2344. OUT BOOL &CrossesReparsePoint,
  2345. OUT DWORD &rdwLastError,
  2346. SIZE_T cErrors,
  2347. va_list vaOkErrors
  2348. )
  2349. {
  2350. FN_PROLOG_WIN32
  2351. CStringBuffer PathWorker;
  2352. CStringBuffer PathRemainder;
  2353. CrossesReparsePoint = FALSE;
  2354. rdwLastError = ERROR_SUCCESS;
  2355. // If the base path is non-null, then great. Otherwise, the length
  2356. // has to be zero as well.
  2357. PARAMETER_CHECK(
  2358. (pcwszBasePathBuffer != NULL) ||
  2359. ((pcwszBasePathBuffer == NULL) && (cchBasePathBuffer == 0)));
  2360. PARAMETER_CHECK(pcwszTotalPathBuffer != NULL);
  2361. //
  2362. // The base path must start the total path. It might be easier to allow users
  2363. // to specify a base path and then subdirectories, bu then for the 90% case of
  2364. // people having both a root and a total, they'd have to do the work below to
  2365. // seperate the two.
  2366. //
  2367. if (pcwszBasePathBuffer != NULL)
  2368. {
  2369. PARAMETER_CHECK( ::FusionpCompareStrings(
  2370. pcwszBasePathBuffer,
  2371. cchBasePathBuffer,
  2372. pcwszTotalPathBuffer,
  2373. cchBasePathBuffer,
  2374. true ) == 0 );
  2375. }
  2376. //
  2377. // PathWorker will be the path we'll be checking subthings on. Start it off
  2378. // at the base path we were given.
  2379. //
  2380. // PathRemainder is what's left to process.
  2381. //
  2382. IFW32FALSE_EXIT(PathWorker.Win32Assign(pcwszBasePathBuffer, cchBasePathBuffer));
  2383. IFW32FALSE_EXIT(PathRemainder.Win32Assign(pcwszTotalPathBuffer + cchBasePathBuffer,
  2384. cchTotalPathBuffer - cchBasePathBuffer));
  2385. PathRemainder.RemoveLeadingPathSeparators();
  2386. while ( PathRemainder.Cch() && !CrossesReparsePoint )
  2387. {
  2388. CSmallStringBuffer buffSingleChunk;
  2389. DWORD dwAttributes = 0;
  2390. IFW32FALSE_EXIT(PathRemainder.Win32GetFirstPathElement(buffSingleChunk, TRUE));
  2391. if (PathWorker.Cch() == 0)
  2392. {
  2393. IFW32FALSE_EXIT(PathWorker.Win32Assign(buffSingleChunk));
  2394. }
  2395. else
  2396. {
  2397. IFW32FALSE_EXIT(PathWorker.Win32AppendPathElement(buffSingleChunk));
  2398. }
  2399. dwAttributes = ::GetFileAttributesW(PathWorker);
  2400. if ( dwAttributes == INVALID_FILE_ATTRIBUTES )
  2401. {
  2402. const DWORD dwError = ::FusionpGetLastWin32Error();
  2403. if (!IsErrorInErrorList(dwError, cErrors, vaOkErrors))
  2404. ORIGINATE_WIN32_FAILURE_AND_EXIT(GetFileAttributesW, ::FusionpGetLastWin32Error());
  2405. else
  2406. {
  2407. rdwLastError = dwError;
  2408. FN_SUCCESSFUL_EXIT();
  2409. }
  2410. }
  2411. else if ( dwAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  2412. {
  2413. CrossesReparsePoint = TRUE;
  2414. }
  2415. }
  2416. FN_EPILOG
  2417. }
  2418. BOOL
  2419. SxspValidateBoolAttribute(
  2420. DWORD dwFlags,
  2421. const CBaseStringBuffer &rbuff,
  2422. bool &rfValid,
  2423. SIZE_T OutputBufferSize,
  2424. PVOID OutputBuffer,
  2425. SIZE_T &OutputBytesWritten)
  2426. {
  2427. BOOL fSuccess = FALSE;
  2428. FN_TRACE_WIN32(fSuccess);
  2429. bool fValid = false;
  2430. StringComparisonResult scr;
  2431. bool fValue = false;
  2432. rfValid = false;
  2433. PARAMETER_CHECK(dwFlags == 0);
  2434. PARAMETER_CHECK((OutputBufferSize == 0) || (OutputBufferSize == sizeof(bool)));
  2435. if (rbuff.Cch() == 2)
  2436. {
  2437. IFW32FALSE_EXIT(rbuff.Win32Compare(L"no", 2, scr, NORM_IGNORECASE));
  2438. if (scr == eEquals)
  2439. {
  2440. fValid = true;
  2441. fValue = false;
  2442. }
  2443. }
  2444. else if (rbuff.Cch() == 3)
  2445. {
  2446. IFW32FALSE_EXIT(rbuff.Win32Compare(L"yes", 3, scr, NORM_IGNORECASE));
  2447. if (scr == eEquals)
  2448. {
  2449. fValid = true;
  2450. fValue = true;
  2451. }
  2452. }
  2453. if (fValid)
  2454. {
  2455. if (OutputBuffer != NULL)
  2456. *((bool *) OutputBuffer) = fValue;
  2457. OutputBytesWritten = sizeof(bool);
  2458. rfValid = true;
  2459. }
  2460. fSuccess = TRUE;
  2461. Exit:
  2462. return fSuccess;
  2463. }
  2464. BOOL
  2465. SxspValidateUnsigned64Attribute(
  2466. DWORD dwFlags,
  2467. const CBaseStringBuffer &rbuff,
  2468. bool &rfValid,
  2469. SIZE_T OutputBufferSize,
  2470. PVOID OutputBuffer,
  2471. SIZE_T &OutputBytesWritten)
  2472. {
  2473. BOOL fSuccess = FALSE;
  2474. FN_TRACE_WIN32(fSuccess);
  2475. bool fValid = false;
  2476. bool fBadChar = false;
  2477. bool fOverflow = false;
  2478. ULONGLONG ullOldValue = 0;
  2479. ULONGLONG ullNewValue = 0;
  2480. SIZE_T i = 0;
  2481. SIZE_T cch = 0;
  2482. PCWSTR psz = NULL;
  2483. rfValid = false;
  2484. PARAMETER_CHECK(dwFlags == 0);
  2485. PARAMETER_CHECK((OutputBufferSize == 0) || (OutputBufferSize == sizeof(ULONGLONG)));
  2486. OutputBytesWritten = 0;
  2487. cch = rbuff.Cch();
  2488. psz = rbuff;
  2489. for (i=0; i<cch; i++)
  2490. {
  2491. const WCHAR wch = *psz++;
  2492. if ((wch < L'0') || (wch > L'9'))
  2493. {
  2494. fBadChar = true;
  2495. break;
  2496. }
  2497. ullNewValue = (ullOldValue * 10);
  2498. if (ullNewValue < ullOldValue)
  2499. {
  2500. fOverflow = true;
  2501. break;
  2502. }
  2503. ullOldValue = ullNewValue;
  2504. ullNewValue += (wch - L'0');
  2505. if (ullNewValue < ullOldValue)
  2506. {
  2507. fOverflow = true;
  2508. break;
  2509. }
  2510. ullOldValue = ullNewValue;
  2511. }
  2512. if ((cch != 0) && (!fBadChar) && (!fOverflow))
  2513. fValid = true;
  2514. if (fValid && (OutputBuffer != NULL))
  2515. {
  2516. *((ULONGLONG *) OutputBuffer) = ullNewValue;
  2517. OutputBytesWritten = sizeof(ULONGLONG);
  2518. }
  2519. rfValid = fValid;
  2520. fSuccess = TRUE;
  2521. Exit:
  2522. return fSuccess;
  2523. }
  2524. BOOL
  2525. SxspValidateGuidAttribute(
  2526. DWORD dwFlags,
  2527. const CBaseStringBuffer &rbuff,
  2528. bool &rfValid,
  2529. SIZE_T OutputBufferSize,
  2530. PVOID OutputBuffer,
  2531. SIZE_T &OutputBytesWritten)
  2532. {
  2533. BOOL fSuccess = FALSE;
  2534. FN_TRACE_WIN32(fSuccess);
  2535. GUID *pGuid = reinterpret_cast<GUID *>(OutputBuffer);
  2536. GUID guidWorkaround;
  2537. rfValid = false;
  2538. PARAMETER_CHECK(dwFlags == 0);
  2539. PARAMETER_CHECK((OutputBufferSize == 0) || (OutputBufferSize == sizeof(GUID)));
  2540. if (pGuid == NULL)
  2541. pGuid = &guidWorkaround;
  2542. IFW32FALSE_EXIT(::SxspParseGUID(rbuff, rbuff.Cch(), *pGuid));
  2543. rfValid = true;
  2544. fSuccess = TRUE;
  2545. Exit:
  2546. return fSuccess;
  2547. }
  2548. BOOL
  2549. SxspValidateProcessorArchitectureAttribute(
  2550. DWORD dwFlags,
  2551. const CBaseStringBuffer &rbuff,
  2552. bool &rfValid,
  2553. SIZE_T OutputBufferSize,
  2554. PVOID OutputBuffer,
  2555. SIZE_T &OutputBytesWritten)
  2556. {
  2557. BOOL fSuccess = FALSE;
  2558. FN_TRACE_WIN32(fSuccess);
  2559. USHORT *pPA = reinterpret_cast<USHORT *>(OutputBuffer);
  2560. rfValid = false;
  2561. PARAMETER_CHECK((dwFlags & ~(SXSP_VALIDATE_PROCESSOR_ARCHITECTURE_ATTRIBUTE_FLAG_WILDCARD_ALLOWED)) == 0);
  2562. PARAMETER_CHECK((OutputBufferSize == 0) || (OutputBufferSize == sizeof(USHORT)));
  2563. if (dwFlags & SXSP_VALIDATE_PROCESSOR_ARCHITECTURE_ATTRIBUTE_FLAG_WILDCARD_ALLOWED)
  2564. {
  2565. if (rbuff.Cch() == 1)
  2566. {
  2567. if (rbuff[0] == L'*')
  2568. rfValid = true;
  2569. }
  2570. }
  2571. if (!rfValid)
  2572. IFW32FALSE_EXIT(::FusionpParseProcessorArchitecture(rbuff, rbuff.Cch(), pPA, rfValid));
  2573. fSuccess = TRUE;
  2574. Exit:
  2575. return fSuccess;
  2576. }
  2577. BOOL
  2578. SxspValidateLanguageAttribute(
  2579. DWORD dwFlags,
  2580. const CBaseStringBuffer &rbuff,
  2581. bool &rfValid,
  2582. SIZE_T OutputBufferSize,
  2583. PVOID OutputBuffer,
  2584. SIZE_T &OutputBytesWritten)
  2585. {
  2586. BOOL fSuccess = FALSE;
  2587. FN_TRACE_WIN32(fSuccess);
  2588. CBaseStringBuffer *pbuffOut = reinterpret_cast<CBaseStringBuffer *>(OutputBuffer);
  2589. bool fValid = false;
  2590. rfValid = false;
  2591. PARAMETER_CHECK((dwFlags & ~(SXSP_VALIDATE_LANGUAGE_ATTRIBUTE_FLAG_WILDCARD_ALLOWED)) == 0);
  2592. PARAMETER_CHECK((OutputBufferSize == 0) || (OutputBufferSize >= sizeof(CBaseStringBuffer)));
  2593. if (dwFlags & SXSP_VALIDATE_LANGUAGE_ATTRIBUTE_FLAG_WILDCARD_ALLOWED)
  2594. {
  2595. if (rbuff.Cch() == 1)
  2596. {
  2597. if (rbuff[0] == L'*')
  2598. fValid = true;
  2599. }
  2600. }
  2601. if (!fValid)
  2602. {
  2603. PCWSTR Cursor = rbuff;
  2604. bool fDashSeen = false;
  2605. WCHAR wch = 0;
  2606. while ((wch = *Cursor++) != L'\0')
  2607. {
  2608. if (wch == '-')
  2609. {
  2610. if (fDashSeen)
  2611. {
  2612. fValid = false;
  2613. break;
  2614. }
  2615. fDashSeen = true;
  2616. }
  2617. else if (
  2618. ((wch >= L'a') && (wch <= L'z')) ||
  2619. ((wch >= L'A') && (wch <= L'Z')))
  2620. {
  2621. fValid = true;
  2622. }
  2623. else
  2624. {
  2625. fValid = false;
  2626. break;
  2627. }
  2628. }
  2629. }
  2630. rfValid = fValid;
  2631. fSuccess = TRUE;
  2632. Exit:
  2633. return fSuccess;
  2634. }
  2635. #define SXS_MSI_TO_FUSION_ATTRIBUTE_VALUE_CONVERSION_COMMA 0
  2636. #define SXS_MSI_TO_FUSION_ATTRIBUTE_VALUE_CONVERSION_QUOT 1
  2637. // ---------------------------------------------------------------------------------
  2638. // Convert function for Assembly-Attribute-Value :
  2639. // 1. for value of assembly-Name, replace L"&#x2c;" by comma
  2640. // 2. for value of other assembly-identity-attribute, replace L"&#x22;" by quot
  2641. // no new space is allocate, use the old space
  2642. // ---------------------------------------------------------------------------------
  2643. BOOL
  2644. SxspConvertAssemblyNameFromMSInstallerToFusion(
  2645. DWORD dwFlags, /* in */
  2646. PWSTR pszAssemblyStringInOut, /*in, out*/
  2647. SIZE_T CchAssemblyStringIn, /*in */
  2648. SIZE_T* pCchAssemblyStringOut /*out */
  2649. )
  2650. {
  2651. BOOL fSuccess = FALSE;
  2652. FN_TRACE_WIN32(fSuccess);
  2653. PWSTR pCursor = NULL;
  2654. PWSTR pSpecialSubString= NULL;
  2655. WCHAR pSpecialSubStringReplacement = 0;
  2656. SIZE_T index = 0;
  2657. SIZE_T border = 0;
  2658. SIZE_T CchSpecialSubString = 0;
  2659. PARAMETER_CHECK((dwFlags == SXS_MSI_TO_FUSION_ATTRIBUTE_VALUE_CONVERSION_COMMA) ||
  2660. (dwFlags == SXS_MSI_TO_FUSION_ATTRIBUTE_VALUE_CONVERSION_QUOT));
  2661. PARAMETER_CHECK(pszAssemblyStringInOut != NULL);
  2662. PARAMETER_CHECK(pCchAssemblyStringOut != NULL);
  2663. if (dwFlags == SXS_MSI_TO_FUSION_ATTRIBUTE_VALUE_CONVERSION_COMMA)
  2664. {
  2665. pSpecialSubStringReplacement= L',';
  2666. pSpecialSubString = SXS_COMMA_STRING;
  2667. CchSpecialSubString = NUMBER_OF(SXS_COMMA_STRING) - 1;
  2668. }
  2669. else
  2670. {
  2671. pSpecialSubStringReplacement = L'"';
  2672. pSpecialSubString = SXS_QUOT_STRING;
  2673. CchSpecialSubString = NUMBER_OF(SXS_QUOT_STRING) - 1;
  2674. }
  2675. index = 0 ;
  2676. border = CchAssemblyStringIn;
  2677. while (index < border)
  2678. {
  2679. pCursor = wcsstr(pszAssemblyStringInOut, pSpecialSubString);
  2680. if (pCursor == NULL)
  2681. break;
  2682. index = pCursor - pszAssemblyStringInOut;
  2683. if (index < border) {
  2684. *pCursor = pSpecialSubStringReplacement;
  2685. index ++; // skip the special character
  2686. for (SIZE_T i=index; i<border; i++)
  2687. { // reset the input string
  2688. pszAssemblyStringInOut[i] = pszAssemblyStringInOut[i + CchSpecialSubString - 1];
  2689. }
  2690. pCursor ++;
  2691. border -= CchSpecialSubString - 1;
  2692. }
  2693. else
  2694. break;
  2695. }
  2696. *pCchAssemblyStringOut = border;
  2697. fSuccess = TRUE;
  2698. Exit:
  2699. return fSuccess;
  2700. }
  2701. BOOL
  2702. SxspDequoteString(
  2703. IN PCWSTR pcwszString,
  2704. IN SIZE_T cchString,
  2705. OUT CBaseStringBuffer &buffDequotedString
  2706. )
  2707. {
  2708. FN_PROLOG_WIN32
  2709. SIZE_T cchQuotedString = 0;
  2710. BOOL fNotEnoughBuffer = FALSE;
  2711. //
  2712. // the output string *must* be always shorter than input string because of the logic of the replacement.
  2713. // but it would not a very big difference in the real case. By allocating memory at very beginning it would cut
  2714. // the loop below. In very rare case, when the input is "plain" and very long, the loop would not help if we do not
  2715. // allocate space beforehand(bug 360177).
  2716. //
  2717. //
  2718. if (cchString > buffDequotedString.GetBufferCch())
  2719. IFW32FALSE_EXIT(buffDequotedString.Win32ResizeBuffer(cchString + 1, eDoNotPreserveBufferContents));
  2720. for (;;)
  2721. {
  2722. cchQuotedString = buffDequotedString.GetBufferCch();
  2723. CStringBufferAccessor sba;
  2724. sba.Attach(&buffDequotedString);
  2725. IFW32FALSE_EXIT_UNLESS(
  2726. ::SxspDequoteString(
  2727. 0,
  2728. pcwszString,
  2729. cchString,
  2730. sba.GetBufferPtr(),
  2731. &cchQuotedString),
  2732. (::GetLastError() == ERROR_INSUFFICIENT_BUFFER),
  2733. fNotEnoughBuffer );
  2734. if ( fNotEnoughBuffer )
  2735. {
  2736. sba.Detach();
  2737. IFW32FALSE_EXIT(buffDequotedString.Win32ResizeBuffer(cchQuotedString, eDoNotPreserveBufferContents));
  2738. }
  2739. else break;
  2740. }
  2741. FN_EPILOG
  2742. }
  2743. BOOL
  2744. SxspCreateAssemblyIdentityFromTextualString(
  2745. PCWSTR pszTextualAssemblyIdentityString,
  2746. PASSEMBLY_IDENTITY *ppAssemblyIdentity
  2747. )
  2748. {
  2749. FN_PROLOG_WIN32
  2750. CSmartPtrWithNamedDestructor<ASSEMBLY_IDENTITY, &::SxsDestroyAssemblyIdentity> pAssemblyIdentity;
  2751. SXS_ASSEMBLY_IDENTITY_ATTRIBUTE_REFERENCE AttributeReference;
  2752. CSmallStringBuffer buffTextualAttributeValue;
  2753. CSmallStringBuffer buffWorkingString;
  2754. CSmallStringBuffer buffNamespaceTwiddle;
  2755. if (ppAssemblyIdentity != NULL)
  2756. *ppAssemblyIdentity = NULL;
  2757. PARAMETER_CHECK(pszTextualAssemblyIdentityString != NULL);
  2758. PARAMETER_CHECK(*pszTextualAssemblyIdentityString != L'\0');
  2759. PARAMETER_CHECK(ppAssemblyIdentity != NULL);
  2760. IFW32FALSE_EXIT(::SxsCreateAssemblyIdentity(0, ASSEMBLY_IDENTITY_TYPE_DEFINITION, &pAssemblyIdentity, 0, NULL));
  2761. IFW32FALSE_EXIT(buffWorkingString.Win32Assign(pszTextualAssemblyIdentityString, ::wcslen(pszTextualAssemblyIdentityString)));
  2762. PCWSTR pcwszIdentityCursor = buffWorkingString;
  2763. PCWSTR pcwszIdentityEndpoint = pcwszIdentityCursor + buffWorkingString.Cch();
  2764. SIZE_T CchAssemblyName = ::StringComplimentSpan(pcwszIdentityCursor, pcwszIdentityEndpoint, L",");
  2765. // Generate the name of the assembly from the first non-comma'd piece of the string
  2766. IFW32FALSE_EXIT(
  2767. ::SxspDequoteString(
  2768. pcwszIdentityCursor,
  2769. CchAssemblyName,
  2770. buffTextualAttributeValue));
  2771. IFW32FALSE_EXIT(
  2772. ::SxspSetAssemblyIdentityAttributeValue(
  2773. 0,
  2774. pAssemblyIdentity,
  2775. &s_IdentityAttribute_name,
  2776. buffTextualAttributeValue,
  2777. buffTextualAttributeValue.Cch()));
  2778. // Skip the name and the following comma
  2779. pcwszIdentityCursor += ( CchAssemblyName + 1 );
  2780. // Find the namespace:name=value pieces
  2781. while (pcwszIdentityCursor < pcwszIdentityEndpoint)
  2782. {
  2783. SIZE_T cchAttribName = ::StringComplimentSpan(pcwszIdentityCursor, pcwszIdentityEndpoint, L"=");
  2784. SIZE_T cchAfterNamespace = ::StringReverseComplimentSpan(pcwszIdentityCursor, pcwszIdentityCursor + cchAttribName, L":");
  2785. PCWSTR pcwszAttribName = (pcwszIdentityCursor + cchAttribName - cchAfterNamespace);
  2786. // not accounting for the colon, cchNamespace + cchAfterNamespace == cchAttribName
  2787. SIZE_T cchNamespace = (cchAttribName - cchAfterNamespace);
  2788. cchAttribName = cchAfterNamespace; // now just the length without the namespace
  2789. PCWSTR pcwszNamespace = (cchNamespace != 0) ? pcwszIdentityCursor : NULL;
  2790. // don't count the colon in the length
  2791. if (cchNamespace != 0)
  2792. cchNamespace -= 1;
  2793. // The value is one past the = sign in the chunklet
  2794. PCWSTR pcwszValue = pcwszAttribName + (cchAttribName + 1);
  2795. // Then a quote, then the string...
  2796. PARAMETER_CHECK((pcwszValue < pcwszIdentityEndpoint) && (pcwszValue[0] == L'"'));
  2797. pcwszValue++;
  2798. SIZE_T cchValue = ::StringComplimentSpan(pcwszValue, pcwszIdentityEndpoint, L"\"");
  2799. {
  2800. PCWSTR pcwszChunkEndpoint = pcwszValue + cchValue;
  2801. PARAMETER_CHECK((pcwszChunkEndpoint < pcwszIdentityEndpoint) && (pcwszChunkEndpoint[0] == L'\"'));
  2802. }
  2803. IFW32FALSE_EXIT(
  2804. ::SxspDequoteString(
  2805. pcwszValue,
  2806. cchValue,
  2807. buffTextualAttributeValue));
  2808. if (cchNamespace != 0)
  2809. {
  2810. IFW32FALSE_EXIT(buffNamespaceTwiddle.Win32Assign(pcwszNamespace, cchNamespace));
  2811. IFW32FALSE_EXIT(
  2812. ::SxspDequoteString(
  2813. pcwszNamespace,
  2814. cchNamespace,
  2815. buffNamespaceTwiddle));
  2816. AttributeReference.Namespace = buffNamespaceTwiddle;
  2817. AttributeReference.NamespaceCch = buffNamespaceTwiddle.Cch();
  2818. }
  2819. else
  2820. {
  2821. AttributeReference.Namespace = NULL;
  2822. AttributeReference.NamespaceCch = 0;
  2823. }
  2824. AttributeReference.Name = pcwszAttribName;
  2825. AttributeReference.NameCch = cchAttribName;
  2826. {
  2827. IFW32FALSE_EXIT(
  2828. ::SxspSetAssemblyIdentityAttributeValue(
  2829. 0,
  2830. pAssemblyIdentity,
  2831. &AttributeReference,
  2832. buffTextualAttributeValue,
  2833. buffTextualAttributeValue.Cch()));
  2834. }
  2835. pcwszIdentityCursor = pcwszValue + cchValue + 1;
  2836. if (pcwszIdentityCursor == pcwszIdentityEndpoint)
  2837. {
  2838. PARAMETER_CHECK(pcwszIdentityCursor[0] == L'\0');
  2839. }
  2840. else if (pcwszIdentityCursor < pcwszIdentityEndpoint)
  2841. {
  2842. PARAMETER_CHECK(pcwszIdentityCursor[0] == L',');
  2843. pcwszIdentityCursor++;
  2844. }
  2845. else
  2846. ORIGINATE_WIN32_FAILURE_AND_EXIT(BadIdentityString, ERROR_INVALID_PARAMETER);
  2847. }
  2848. *ppAssemblyIdentity = pAssemblyIdentity.Detach();
  2849. FN_EPILOG
  2850. }
  2851. BOOL
  2852. SxspCreateManifestFileNameFromTextualString(
  2853. DWORD dwFlags,
  2854. ULONG PathType,
  2855. const CBaseStringBuffer &AssemblyDirectory,
  2856. PCWSTR pwszTextualAssemblyIdentityString,
  2857. CBaseStringBuffer &sbPathName
  2858. )
  2859. {
  2860. BOOL fSuccess = FALSE;
  2861. FN_TRACE_WIN32(fSuccess);
  2862. PASSEMBLY_IDENTITY pAssemblyIdentity = NULL;
  2863. PARAMETER_CHECK(pwszTextualAssemblyIdentityString != NULL);
  2864. IFW32FALSE_EXIT(::SxspCreateAssemblyIdentityFromTextualString(pwszTextualAssemblyIdentityString, &pAssemblyIdentity));
  2865. //
  2866. // generate a FULLY PATH for manifest, such as I:\WINDOWS\WinSxS\Manifests\x86_xxxxxxxxxxxxx_6.0.0.0_en-us_cd4c0d12.Manifest
  2867. //
  2868. IFW32FALSE_EXIT(
  2869. ::SxspGenerateSxsPath(
  2870. dwFlags,
  2871. PathType,
  2872. AssemblyDirectory,
  2873. AssemblyDirectory.Cch(),
  2874. pAssemblyIdentity,
  2875. NULL,
  2876. sbPathName));
  2877. fSuccess = TRUE;
  2878. Exit:
  2879. if (pAssemblyIdentity != NULL)
  2880. ::SxsDestroyAssemblyIdentity(pAssemblyIdentity);
  2881. return fSuccess ;
  2882. }
  2883. bool IsCharacterNulOrInSet(WCHAR ch, PCWSTR set)
  2884. {
  2885. return (ch == 0 || wcschr(set, ch) != NULL);
  2886. }
  2887. class CSxsQueryAssemblyInfoLocals
  2888. {
  2889. public:
  2890. CSxsQueryAssemblyInfoLocals() { }
  2891. ~CSxsQueryAssemblyInfoLocals() { }
  2892. CStringBuffer buffAssemblyPath;
  2893. CStringBuffer sbManifestFullPathFileName;
  2894. };
  2895. BOOL
  2896. SxsQueryAssemblyInfo(
  2897. DWORD dwFlags,
  2898. PCWSTR pwzTextualAssembly,
  2899. ASSEMBLY_INFO *pAsmInfo
  2900. )
  2901. {
  2902. BOOL fSuccess = FALSE;
  2903. FN_TRACE_WIN32(fSuccess);
  2904. CSmartRef<CAssemblyName> pName;
  2905. BOOL fInstalled = FALSE;
  2906. CSmartPtr<CSxsQueryAssemblyInfoLocals> Locals;
  2907. PARAMETER_CHECK((dwFlags == 0) && (pwzTextualAssembly != NULL));
  2908. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  2909. IFCOMFAILED_EXIT(::CreateAssemblyNameObject((LPASSEMBLYNAME *)&pName, pwzTextualAssembly, CANOF_PARSE_DISPLAY_NAME, NULL));
  2910. IFCOMFAILED_EXIT(pName->IsAssemblyInstalled(fInstalled));
  2911. if (pAsmInfo == NULL)
  2912. {
  2913. if (fInstalled)
  2914. FN_SUCCESSFUL_EXIT();
  2915. // the error value "doesn't matter", Darwin compares against S_OK for equality
  2916. ORIGINATE_WIN32_FAILURE_AND_EXIT(AssemblyNotFound, ERROR_NOT_FOUND);
  2917. }
  2918. if (!fInstalled)
  2919. {
  2920. // pAsmInfo->dwAssemblyFlags |= ASSEMBLYINFO_FLAG_NOT_INSTALLED;
  2921. //
  2922. // Darwin wants FAIL instead of FLAG setting
  2923. //
  2924. ORIGINATE_WIN32_FAILURE_AND_EXIT(AssemblyNotInstalled, ERROR_NOT_FOUND);
  2925. }
  2926. else
  2927. {
  2928. CStringBuffer &buffAssemblyPath = Locals->buffAssemblyPath;
  2929. PCWSTR pszInstalledPath = NULL;
  2930. DWORD CchInstalledPath = 0 ;
  2931. BOOL fIsPolicy = FALSE;
  2932. CStringBuffer &sbManifestFullPathFileName = Locals->sbManifestFullPathFileName;
  2933. pAsmInfo->dwAssemblyFlags |= ASSEMBLYINFO_FLAG_INSTALLED;
  2934. IFCOMFAILED_EXIT(pName->DetermineAssemblyType(fIsPolicy));
  2935. if (!fIsPolicy)
  2936. {
  2937. //
  2938. // check whether the assembly has a manifest ONLY
  2939. //
  2940. IFCOMFAILED_EXIT(pName->GetInstalledAssemblyName(
  2941. 0,
  2942. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
  2943. buffAssemblyPath));
  2944. bool fExist = false;
  2945. IFW32FALSE_EXIT(SxspDoesFileExist(0, buffAssemblyPath, fExist));
  2946. if (!fExist)
  2947. {
  2948. IFCOMFAILED_EXIT(
  2949. pName->GetInstalledAssemblyName(
  2950. 0,
  2951. SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST,
  2952. sbManifestFullPathFileName));
  2953. pszInstalledPath = sbManifestFullPathFileName;
  2954. CchInstalledPath = sbManifestFullPathFileName.GetCchAsDWORD();
  2955. }
  2956. else
  2957. {
  2958. pszInstalledPath = buffAssemblyPath;
  2959. CchInstalledPath = buffAssemblyPath.GetCchAsDWORD();
  2960. }
  2961. }
  2962. else // if (fIsPolicy)// it must be a policy
  2963. {
  2964. IFCOMFAILED_EXIT(
  2965. pName->GetInstalledAssemblyName(
  2966. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION,
  2967. SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY,
  2968. sbManifestFullPathFileName));
  2969. pszInstalledPath = sbManifestFullPathFileName;
  2970. CchInstalledPath = sbManifestFullPathFileName.GetCchAsDWORD();
  2971. }
  2972. if(pAsmInfo->cchBuf >= 1 + CchInstalledPath) // adding 1 for trailing NULL
  2973. {
  2974. memcpy(pAsmInfo->pszCurrentAssemblyPathBuf, pszInstalledPath, CchInstalledPath * sizeof(WCHAR));
  2975. pAsmInfo->pszCurrentAssemblyPathBuf[CchInstalledPath] = L'\0';
  2976. }
  2977. else
  2978. {
  2979. // HACK! It's too late to fix this but Darwin sometimes doesn't want to get the path at all;
  2980. // there's no way for them to indicate this today but we'll take the convention that if
  2981. // the buffer length is 0 and the buffer pointer is NULL, we'll not fail with ERROR_INSUFFICENT_BUFFER.
  2982. // mgrier 6/21/2001
  2983. if ((pAsmInfo->cchBuf != 0) ||
  2984. (pAsmInfo->pszCurrentAssemblyPathBuf != NULL))
  2985. {
  2986. ::FusionpDbgPrintEx(
  2987. FUSION_DBG_LEVEL_INFO,
  2988. "SXS: %s - insufficient buffer passed in. cchBuf passed in: %u; cchPath computed: %u\n",
  2989. __FUNCTION__,
  2990. pAsmInfo->cchBuf,
  2991. CchInstalledPath + 1
  2992. );
  2993. pAsmInfo->cchBuf = 1 + CchInstalledPath;
  2994. ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
  2995. }
  2996. }
  2997. }
  2998. fSuccess = TRUE;
  2999. Exit:
  3000. return fSuccess;
  3001. }
  3002. BOOL
  3003. SxspExpandRelativePathToFull(
  3004. IN PCWSTR wszString,
  3005. IN SIZE_T cchString,
  3006. OUT CBaseStringBuffer &rsbDestination
  3007. )
  3008. {
  3009. BOOL bSuccess = FALSE;
  3010. DWORD dwNeededChars = 0;
  3011. CStringBufferAccessor access;
  3012. FN_TRACE_WIN32(bSuccess);
  3013. access.Attach(&rsbDestination);
  3014. //
  3015. // Try to get the path expansion into our own buffer to start with.
  3016. //
  3017. IFW32ZERO_EXIT(dwNeededChars = ::GetFullPathNameW(wszString, (DWORD)access.GetBufferCch(), access.GetBufferPtr(), NULL));
  3018. //
  3019. // Did we need more characters?
  3020. //
  3021. if (dwNeededChars > access.GetBufferCch())
  3022. {
  3023. //
  3024. // Expand out the buffer to be big enough, then try again. If it fails again,
  3025. // we're just hosed.
  3026. //
  3027. access.Detach();
  3028. IFW32FALSE_EXIT(rsbDestination.Win32ResizeBuffer(dwNeededChars, eDoNotPreserveBufferContents));
  3029. access.Attach(&rsbDestination);
  3030. IFW32ZERO_EXIT(dwNeededChars = ::GetFullPathNameW(wszString, (DWORD)access.GetBufferCch(), access.GetBufferPtr(), NULL));
  3031. if (dwNeededChars > access.GetBufferCch())
  3032. {
  3033. TRACE_WIN32_FAILURE_ORIGINATION(GetFullPathNameW);
  3034. goto Exit;
  3035. }
  3036. }
  3037. FN_EPILOG
  3038. }
  3039. BOOL
  3040. SxspGetShortPathName(
  3041. IN const CBaseStringBuffer &rcbuffLongPathName,
  3042. OUT CBaseStringBuffer &rbuffShortenedVersion
  3043. )
  3044. {
  3045. DWORD dw = 0;
  3046. return ::SxspGetShortPathName(rcbuffLongPathName, rbuffShortenedVersion, dw, 0);
  3047. }
  3048. BOOL
  3049. SxspGetShortPathName(
  3050. IN const CBaseStringBuffer &rcbuffLongPathName,
  3051. OUT CBaseStringBuffer &rbuffShortenedVersion,
  3052. DWORD &rdwWin32Error,
  3053. SIZE_T cExceptionalWin32Errors,
  3054. ...
  3055. )
  3056. {
  3057. FN_PROLOG_WIN32
  3058. va_list ap;
  3059. CStringBufferAccessor sba;
  3060. rdwWin32Error = ERROR_SUCCESS;
  3061. for (;;)
  3062. {
  3063. DWORD dwRequired = 0;
  3064. if (rbuffShortenedVersion.GetBufferCch() < 2)
  3065. {
  3066. IFW32FALSE_EXIT(
  3067. rbuffShortenedVersion.Win32ResizeBuffer(
  3068. 2,
  3069. eDoNotPreserveBufferContents));
  3070. }
  3071. sba.Attach(&rbuffShortenedVersion);
  3072. //
  3073. // We were getting stringbuffer corruption here.
  3074. // Assume that GetShortPathNameW might not nul terminate
  3075. // the buffer. Assume that GetShortPathNameW returns
  3076. // either the number of characters written or the requires
  3077. // number of characters.
  3078. //
  3079. dwRequired = ::GetShortPathNameW(
  3080. rcbuffLongPathName,
  3081. sba.GetBufferPtr(),
  3082. sba.GetBufferCchAsDWORD() - 1);
  3083. sba.GetBufferPtr()[sba.GetBufferCchAsDWORD() - 1] = 0;
  3084. if (dwRequired == 0)
  3085. {
  3086. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  3087. SIZE_T i;
  3088. va_start(ap, cExceptionalWin32Errors);
  3089. for (i=0; i<cExceptionalWin32Errors; i++)
  3090. {
  3091. if (va_arg(ap, DWORD) == dwLastError)
  3092. {
  3093. rdwWin32Error = dwLastError;
  3094. break;
  3095. }
  3096. }
  3097. va_end(ap);
  3098. if (rdwWin32Error != ERROR_SUCCESS)
  3099. FN_SUCCESSFUL_EXIT();
  3100. #if DBG
  3101. ::FusionpDbgPrintEx(
  3102. FUSION_DBG_LEVEL_ERROR,
  3103. "SXS.DLL: GetShortPathNameW(%ls) : %lu\n",
  3104. static_cast<PCWSTR>(rcbuffLongPathName),
  3105. dwLastError
  3106. );
  3107. #endif
  3108. ORIGINATE_WIN32_FAILURE_AND_EXIT(GetShortPathNameW, dwLastError);
  3109. }
  3110. else if (dwRequired >= (sba.GetBufferCch() - 1))
  3111. {
  3112. //
  3113. // If we were merely told that we got back characters
  3114. // filling the buffer and not the required length,
  3115. // double the buffer.
  3116. //
  3117. if (dwRequired <= sba.GetBufferCch())
  3118. {
  3119. dwRequired = (dwRequired + 1) * 2;
  3120. }
  3121. sba.Detach();
  3122. IFW32FALSE_EXIT(
  3123. rbuffShortenedVersion.Win32ResizeBuffer(
  3124. dwRequired + 1,
  3125. eDoNotPreserveBufferContents));
  3126. }
  3127. else
  3128. {
  3129. break;
  3130. }
  3131. }
  3132. FN_EPILOG
  3133. }
  3134. BOOL
  3135. SxspValidateIdentity(
  3136. DWORD Flags,
  3137. ULONG Type,
  3138. PCASSEMBLY_IDENTITY AssemblyIdentity
  3139. )
  3140. {
  3141. BOOL fSuccess = FALSE;
  3142. FN_TRACE_WIN32(fSuccess);
  3143. PCWSTR pszTemp = NULL;
  3144. SIZE_T cchTemp = 0;
  3145. bool fSyntaxValid = false;
  3146. bool fError = false;
  3147. bool fMissingRequiredAttributes = false;
  3148. bool fInvalidAttributeValues = false;
  3149. BOOL fIsPolicy = FALSE;
  3150. PARAMETER_CHECK((Flags & ~(
  3151. SXSP_VALIDATE_IDENTITY_FLAG_VERSION_REQUIRED |
  3152. SXSP_VALIDATE_IDENTITY_FLAG_POLICIES_NOT_ALLOWED |
  3153. SXSP_VALIDATE_IDENTITY_FLAG_VERSION_NOT_ALLOWED)) == 0);
  3154. PARAMETER_CHECK((Type == ASSEMBLY_IDENTITY_TYPE_DEFINITION) || (Type == ASSEMBLY_IDENTITY_TYPE_REFERENCE));
  3155. PARAMETER_CHECK(AssemblyIdentity != NULL);
  3156. //
  3157. // only one of these flags is allowed
  3158. //
  3159. PARAMETER_CHECK(
  3160. (Flags & (SXSP_VALIDATE_IDENTITY_FLAG_VERSION_REQUIRED | SXSP_VALIDATE_IDENTITY_FLAG_VERSION_NOT_ALLOWED)) !=
  3161. (SXSP_VALIDATE_IDENTITY_FLAG_VERSION_REQUIRED | SXSP_VALIDATE_IDENTITY_FLAG_VERSION_NOT_ALLOWED));
  3162. IFW32FALSE_EXIT(::SxspDetermineAssemblyType(AssemblyIdentity, fIsPolicy));
  3163. if (fIsPolicy && ((Flags & SXSP_VALIDATE_IDENTITY_FLAG_POLICIES_NOT_ALLOWED) != 0))
  3164. {
  3165. ORIGINATE_WIN32_FAILURE_AND_EXIT(MissingType, ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE);
  3166. }
  3167. IFW32FALSE_EXIT(
  3168. ::SxspGetAssemblyIdentityAttributeValue(
  3169. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  3170. AssemblyIdentity,
  3171. &s_IdentityAttribute_name,
  3172. &pszTemp,
  3173. &cchTemp));
  3174. if (cchTemp == 0)
  3175. ORIGINATE_WIN32_FAILURE_AND_EXIT(MissingType, ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE);
  3176. IFW32FALSE_EXIT(
  3177. ::SxspGetAssemblyIdentityAttributeValue(
  3178. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  3179. AssemblyIdentity,
  3180. &s_IdentityAttribute_processorArchitecture,
  3181. &pszTemp,
  3182. &cchTemp));
  3183. if (cchTemp == 0)
  3184. ORIGINATE_WIN32_FAILURE_AND_EXIT(MissingType, ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE);
  3185. IFW32FALSE_EXIT(
  3186. ::SxspGetAssemblyIdentityAttributeValue(
  3187. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  3188. AssemblyIdentity,
  3189. &s_IdentityAttribute_version,
  3190. &pszTemp,
  3191. &cchTemp));
  3192. if (cchTemp != 0)
  3193. {
  3194. ASSEMBLY_VERSION av;
  3195. IFW32FALSE_EXIT(CFusionParser::ParseVersion(av, pszTemp, cchTemp, fSyntaxValid));
  3196. if (!fSyntaxValid)
  3197. ORIGINATE_WIN32_FAILURE_AND_EXIT(MissingType, ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE);
  3198. }
  3199. if ((Flags & (SXSP_VALIDATE_IDENTITY_FLAG_VERSION_NOT_ALLOWED | SXSP_VALIDATE_IDENTITY_FLAG_VERSION_REQUIRED)) != 0)
  3200. {
  3201. if (((Flags & SXSP_VALIDATE_IDENTITY_FLAG_VERSION_NOT_ALLOWED) != 0) && (cchTemp != 0))
  3202. ORIGINATE_WIN32_FAILURE_AND_EXIT(MissingType, ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE);
  3203. else if (((Flags & SXSP_VALIDATE_IDENTITY_FLAG_VERSION_REQUIRED) != 0) && (cchTemp == 0))
  3204. ORIGINATE_WIN32_FAILURE_AND_EXIT(MissingType, ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE);
  3205. }
  3206. fSuccess = TRUE;
  3207. Exit:
  3208. return fSuccess;
  3209. }
  3210. BOOL
  3211. SxspGenerateAssemblyNameInRegistry(
  3212. IN PCASSEMBLY_IDENTITY pcAsmIdent,
  3213. OUT CBaseStringBuffer &rbuffRegistryName
  3214. )
  3215. {
  3216. FN_PROLOG_WIN32
  3217. //BOOL fIsWin32, fIsPolicy;
  3218. //
  3219. // the policies for the same Dll would be stored in reg separately. So, the RegKeyName needs the version in it,
  3220. // that is, generate the keyName just like assembly manifest
  3221. // See bug 422195
  3222. //
  3223. //IFW32FALSE_EXIT(::SxspDetermineAssemblyType( pcAsmIdent, fIsWin32, fIsPolicy));
  3224. IFW32FALSE_EXIT(::SxspGenerateSxsPath(
  3225. //SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT | ( fIsPolicy ? SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION : 0 ),
  3226. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT,
  3227. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
  3228. NULL,
  3229. 0,
  3230. pcAsmIdent,
  3231. NULL,
  3232. rbuffRegistryName));
  3233. FN_EPILOG
  3234. }
  3235. BOOL
  3236. SxspGenerateAssemblyNameInRegistry(
  3237. IN const CBaseStringBuffer &rcbuffTextualString,
  3238. OUT CBaseStringBuffer &rbuffRegistryName
  3239. )
  3240. {
  3241. FN_PROLOG_WIN32
  3242. CSmartPtrWithNamedDestructor<ASSEMBLY_IDENTITY, &::SxsDestroyAssemblyIdentity> pAsmIdent;
  3243. IFW32FALSE_EXIT(::SxspCreateAssemblyIdentityFromTextualString(rcbuffTextualString, &pAsmIdent));
  3244. IFW32FALSE_EXIT(::SxspGenerateAssemblyNameInRegistry(pAsmIdent, rbuffRegistryName));
  3245. FN_EPILOG
  3246. }
  3247. BOOL
  3248. SxspGetFullPathName(
  3249. IN PCWSTR pcwszPathName,
  3250. OUT CBaseStringBuffer &rbuffPathName,
  3251. OUT CBaseStringBuffer *pbuffFilePart
  3252. )
  3253. {
  3254. FN_PROLOG_WIN32
  3255. PARAMETER_CHECK(pcwszPathName != NULL);
  3256. rbuffPathName.Clear();
  3257. if ( pbuffFilePart ) pbuffFilePart->Clear();
  3258. do
  3259. {
  3260. CStringBufferAccessor sba;
  3261. DWORD dwRequired;
  3262. PWSTR pcwszFileChunk = NULL;
  3263. sba.Attach(&rbuffPathName);
  3264. dwRequired = ::GetFullPathNameW(
  3265. pcwszPathName,
  3266. sba.GetBufferCchAsDWORD(),
  3267. sba.GetBufferPtr(),
  3268. &pcwszFileChunk );
  3269. //
  3270. // In the strange case that we got a blank path, we'll get back that zero characters
  3271. // are required, but lasterror is ERROR_SUCCESS. Don't fail, but stop trying.
  3272. //
  3273. if (dwRequired == 0)
  3274. {
  3275. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  3276. if (dwLastError != ERROR_SUCCESS)
  3277. ORIGINATE_WIN32_FAILURE_AND_EXIT(GetFullPathNameW, dwLastError);
  3278. else
  3279. break;
  3280. }
  3281. else if (dwRequired >= sba.GetBufferCch())
  3282. {
  3283. sba.Detach();
  3284. IFW32FALSE_EXIT(rbuffPathName.Win32ResizeBuffer(dwRequired+1, eDoNotPreserveBufferContents));
  3285. }
  3286. else
  3287. {
  3288. if ( pcwszFileChunk && pbuffFilePart )
  3289. {
  3290. IFW32FALSE_EXIT(pbuffFilePart->Win32Assign(pcwszFileChunk, ::wcslen(pcwszFileChunk)));
  3291. }
  3292. break;
  3293. }
  3294. }
  3295. while ( true );
  3296. FN_EPILOG
  3297. }
  3298. #define MPR_DLL_NAME (L"mpr.dll")
  3299. BOOL
  3300. SxspGetRemoteUniversalName(
  3301. IN PCWSTR pcszPathName,
  3302. OUT CBaseStringBuffer &rbuffUniversalName
  3303. )
  3304. {
  3305. FN_PROLOG_WIN32
  3306. CFusionArray<BYTE> baBufferData;
  3307. REMOTE_NAME_INFOW *pRemoteInfoData;
  3308. DWORD dwRetVal = 0;
  3309. CDynamicLinkLibrary dllMpr;
  3310. DWORD (APIENTRY * pfnWNetGetUniversalNameW)(
  3311. LPCWSTR lpLocalPath,
  3312. DWORD dwInfoLevel,
  3313. LPVOID lpBuffer,
  3314. LPDWORD lpBufferSize
  3315. );
  3316. IFW32FALSE_EXIT(dllMpr.Win32LoadLibrary(MPR_DLL_NAME));
  3317. IFW32FALSE_EXIT(dllMpr.Win32GetProcAddress("WNetGetUniversalNameW", &pfnWNetGetUniversalNameW));
  3318. IFW32FALSE_EXIT(baBufferData.Win32SetSize( MAX_PATH * 2, CFusionArray<BYTE>::eSetSizeModeExact));
  3319. for (;;)
  3320. {
  3321. DWORD dwDataUsed = baBufferData.GetSizeAsDWORD();
  3322. dwRetVal = (*pfnWNetGetUniversalNameW)(
  3323. pcszPathName,
  3324. UNIVERSAL_NAME_INFO_LEVEL,
  3325. (PVOID)baBufferData.GetArrayPtr(),
  3326. &dwDataUsed );
  3327. if ( dwRetVal == WN_MORE_DATA )
  3328. {
  3329. IFW32FALSE_EXIT(baBufferData.Win32SetSize(
  3330. dwDataUsed,
  3331. CFusionArray<BYTE>::eSetSizeModeExact )) ;
  3332. }
  3333. else if ( dwRetVal == WN_SUCCESS )
  3334. {
  3335. break;
  3336. }
  3337. else
  3338. {
  3339. ORIGINATE_WIN32_FAILURE_AND_EXIT(NPGetUniversalName, dwRetVal);
  3340. }
  3341. }
  3342. pRemoteInfoData = (REMOTE_NAME_INFOW*)baBufferData.GetArrayPtr();
  3343. ASSERT( pRemoteInfoData != NULL );
  3344. IFW32FALSE_EXIT( rbuffUniversalName.Win32Assign(
  3345. pRemoteInfoData->lpUniversalName,
  3346. lstrlenW(pRemoteInfoData->lpUniversalName)));
  3347. FN_EPILOG
  3348. }
  3349. BOOL
  3350. SxspGetVolumePathName(
  3351. IN DWORD dwFlags,
  3352. IN PCWSTR pcwszVolumePath,
  3353. OUT CBaseStringBuffer &buffVolumePathName
  3354. )
  3355. {
  3356. FN_PROLOG_WIN32
  3357. CStringBuffer buffTempPathName;
  3358. CStringBufferAccessor sba;
  3359. PARAMETER_CHECK((dwFlags & ~SXS_GET_VOLUME_PATH_NAME_NO_FULLPATH) == 0);
  3360. IFW32FALSE_EXIT(::SxspGetFullPathName(pcwszVolumePath, buffTempPathName));
  3361. IFW32FALSE_EXIT(
  3362. buffVolumePathName.Win32ResizeBuffer(
  3363. buffTempPathName.Cch() + 1,
  3364. eDoNotPreserveBufferContents));
  3365. buffVolumePathName.Clear();
  3366. //
  3367. // The documentation for this is somewhat suspect. It says that the
  3368. // data size required from GetVolumePathNameW will be /less than/
  3369. // the length of the full path of the path name passed in, hence the
  3370. // call to getfullpath above. (This pattern is suggested by MSDN)
  3371. //
  3372. sba.Attach(&buffVolumePathName);
  3373. IFW32FALSE_ORIGINATE_AND_EXIT(
  3374. ::GetVolumePathNameW(
  3375. buffTempPathName,
  3376. sba.GetBufferPtr(),
  3377. sba.GetBufferCchAsDWORD()));
  3378. sba.Detach();
  3379. FN_EPILOG
  3380. }
  3381. BOOL
  3382. SxspGetVolumeNameForVolumeMountPoint(
  3383. IN PCWSTR pcwszMountPoint,
  3384. OUT CBaseStringBuffer &rbuffMountPoint
  3385. )
  3386. {
  3387. FN_PROLOG_WIN32
  3388. CStringBufferAccessor sba;
  3389. IFW32FALSE_EXIT(rbuffMountPoint.Win32ResizeBuffer(55, eDoNotPreserveBufferContents));
  3390. rbuffMountPoint.Clear();
  3391. sba.Attach(&rbuffMountPoint);
  3392. IFW32FALSE_ORIGINATE_AND_EXIT(
  3393. ::GetVolumeNameForVolumeMountPointW(
  3394. pcwszMountPoint,
  3395. sba.GetBufferPtr(),
  3396. sba.GetBufferCchAsDWORD()));
  3397. sba.Detach();
  3398. FN_EPILOG
  3399. }
  3400. BOOL
  3401. SxspExpandEnvironmentStrings(
  3402. IN PCWSTR pcwszSource,
  3403. OUT CBaseStringBuffer &buffTarget
  3404. )
  3405. {
  3406. FN_PROLOG_WIN32
  3407. // be wary about about subtracting one from unsigned zero
  3408. PARAMETER_CHECK(buffTarget.GetBufferCch() != 0);
  3409. //
  3410. // ExpandEnvironmentStrings is very rude and doesn't put the trailing NULL
  3411. // into the target if the buffer isn't big enough. This causes the accessor
  3412. // detach to record a size == to the number of characters in the buffer,
  3413. // which fails the integrity check later on.
  3414. //
  3415. do
  3416. {
  3417. CStringBufferAccessor sba;
  3418. sba.Attach(&buffTarget);
  3419. DWORD dwNecessary =
  3420. ::ExpandEnvironmentStringsW(
  3421. pcwszSource,
  3422. sba.GetBufferPtr(),
  3423. sba.GetBufferCchAsDWORD() - 1);
  3424. if ( dwNecessary == 0 )
  3425. {
  3426. ORIGINATE_WIN32_FAILURE_AND_EXIT(ExpandEnvironmentStringsW, ::FusionpGetLastWin32Error());
  3427. }
  3428. else if ( dwNecessary >= (sba.GetBufferCch() - 1) )
  3429. {
  3430. (sba.GetBufferPtr())[sba.GetBufferCch()-1] = UNICODE_NULL;
  3431. sba.Detach();
  3432. IFW32FALSE_EXIT(buffTarget.Win32ResizeBuffer(dwNecessary+1, eDoNotPreserveBufferContents));
  3433. }
  3434. else
  3435. {
  3436. break;
  3437. }
  3438. }
  3439. while ( true );
  3440. FN_EPILOG
  3441. }
  3442. BOOL
  3443. SxspDoesMSIStillNeedAssembly(
  3444. IN PCWSTR pcAsmName,
  3445. OUT BOOL &rfNeedsAssembly
  3446. )
  3447. /*++
  3448. Purpose:
  3449. Determines whether or not an assembly is still required, according to
  3450. Darwin. Since Darwin doesn't pass in an assembly reference to the
  3451. installer API's, we have no way of determining whether or not some
  3452. MSI-installed application actually contains a reference to an
  3453. assembly.
  3454. Parameters:
  3455. pcAsmIdent - Identity of the assembly to be checked in text
  3456. rfNeedsAssembly - OUT flag indicating whether or not the assembly is
  3457. still wanted, according to Darwin. This function
  3458. errs on the side of caution, and will send back "true"
  3459. if this information was unavailable, as well as if the
  3460. assembly was really necessary.
  3461. Returns:
  3462. TRUE if there was no error
  3463. FALSE if there was an error.
  3464. --*/
  3465. {
  3466. BOOL fSuccess = FALSE;
  3467. FN_TRACE_WIN32(fSuccess);
  3468. CDynamicLinkLibrary dllMSI;
  3469. CSmallStringBuffer buffAssemblyName;
  3470. UINT (WINAPI *pfMsiProvideAssemblyW)( LPCWSTR, LPCWSTR, DWORD, DWORD, LPWSTR, DWORD* );
  3471. UINT uiError = 0;
  3472. rfNeedsAssembly = TRUE; // err toward caution in the even of an error
  3473. PARAMETER_CHECK(pcAsmName != NULL);
  3474. IFW32FALSE_EXIT(dllMSI.Win32LoadLibrary(MSI_DLL_NAME_W, 0));
  3475. IFW32FALSE_EXIT(dllMSI.Win32GetProcAddress(MSI_PROVIDEASSEMBLY_NAME, &pfMsiProvideAssemblyW));
  3476. //
  3477. // This is based on a detailed reading of the Darwin code.
  3478. //
  3479. uiError = (*pfMsiProvideAssemblyW)(
  3480. pcAsmName, // assembly name
  3481. NULL, // full path to .cfg file
  3482. static_cast<DWORD>(INSTALLMODE_NODETECTION_ANY), // install/reinstall mode
  3483. MSIASSEMBLYINFO_WIN32ASSEMBLY, // dwAssemblyInfo
  3484. NULL, // returned path buffer
  3485. 0); // in/out returned path character count
  3486. switch (uiError)
  3487. {
  3488. default:
  3489. case ERROR_BAD_CONFIGURATION:
  3490. case ERROR_INVALID_PARAMETER:
  3491. ::SetLastError(uiError);
  3492. ORIGINATE_WIN32_FAILURE_AND_EXIT(MsiProvideAssemblyW, uiError);
  3493. break;
  3494. case ERROR_UNKNOWN_COMPONENT:
  3495. rfNeedsAssembly = FALSE;
  3496. fSuccess = TRUE;
  3497. goto Exit;
  3498. case NO_ERROR:
  3499. rfNeedsAssembly = TRUE;
  3500. fSuccess = TRUE;
  3501. goto Exit;
  3502. }
  3503. fSuccess = FALSE; // unusual
  3504. Exit:
  3505. return fSuccess;
  3506. }
  3507. BOOL
  3508. SxspMoveFilesUnderDir(
  3509. DWORD dwFlags,
  3510. CBaseStringBuffer & sbSourceDir,
  3511. CBaseStringBuffer & sbDestDir,
  3512. DWORD dwMoveFileFlags,
  3513. WIN32_FIND_DATAW &findData // avoid allocating one of these in each recursive frame
  3514. )
  3515. {
  3516. FN_PROLOG_WIN32
  3517. SIZE_T CchDestDir = 0;
  3518. SIZE_T CchSourceDir = 0;
  3519. CFindFile findFile;
  3520. PARAMETER_CHECK((dwFlags & ~SXSP_MOVE_FILE_FLAG_COMPRESSION_AWARE) == 0);
  3521. bool fExist = false;
  3522. IFW32FALSE_EXIT(::SxspDoesFileExist(SXSP_DOES_FILE_EXIST_FLAG_CHECK_DIRECTORY_ONLY, sbSourceDir, fExist));
  3523. if (!fExist)
  3524. {
  3525. //
  3526. // File or path not found propagated from GetFileAttributes is probably
  3527. // generally better here.
  3528. //
  3529. PARAMETER_CHECK(fExist);
  3530. }
  3531. fExist = false;
  3532. IFW32FALSE_EXIT(::SxspDoesFileExist(SXSP_DOES_FILE_EXIST_FLAG_CHECK_DIRECTORY_ONLY, sbDestDir, fExist));
  3533. if (!fExist)
  3534. {
  3535. //
  3536. // Other than at the top of the call tree, just CreateDirectory "one"
  3537. // is sufficient.
  3538. //
  3539. IFW32FALSE_EXIT(::FusionpCreateDirectories(sbDestDir, sbDestDir.Cch()));
  3540. }
  3541. IFW32FALSE_EXIT(sbSourceDir.Win32EnsureTrailingPathSeparator());
  3542. IFW32FALSE_EXIT(sbDestDir.Win32EnsureTrailingPathSeparator());
  3543. CchDestDir = sbDestDir.Cch();
  3544. CchSourceDir = sbSourceDir.Cch();
  3545. IFW32FALSE_EXIT(sbSourceDir.Win32Append(L"*", 1));
  3546. IFW32FALSE_EXIT(findFile.Win32FindFirstFile(sbSourceDir, &findData));
  3547. do {
  3548. // skip . and ..
  3549. if (::FusionpIsDotOrDotDot(findData.cFileName))
  3550. continue;
  3551. sbDestDir.Left(CchDestDir);
  3552. sbSourceDir.Left(CchSourceDir);
  3553. IFW32FALSE_EXIT(sbDestDir.Win32Append(findData.cFileName, ::wcslen(findData.cFileName)));
  3554. IFW32FALSE_EXIT(sbSourceDir.Win32Append(findData.cFileName, ::wcslen(findData.cFileName)));
  3555. if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  3556. {
  3557. //
  3558. // call itself recursively
  3559. //
  3560. IFW32FALSE_EXIT(::SxspMoveFilesUnderDir(dwFlags, sbSourceDir, sbDestDir, dwMoveFileFlags, findData));
  3561. }
  3562. if ((dwFlags & SXSP_MOVE_FILE_FLAG_COMPRESSION_AWARE) != 0)
  3563. {
  3564. IFW32FALSE_EXIT(::SxspInstallMoveFileExW(sbSourceDir, sbDestDir, dwMoveFileFlags));
  3565. }
  3566. else
  3567. {
  3568. IFW32FALSE_ORIGINATE_AND_EXIT(::MoveFileExW(sbSourceDir, sbDestDir, dwMoveFileFlags));
  3569. }
  3570. } while (::FindNextFileW(findFile, &findData));
  3571. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  3572. {
  3573. ::FusionpDbgPrintEx(
  3574. FUSION_DBG_LEVEL_ERROR,
  3575. "SXS.DLL: %s(): FindNextFile() failed:%ld\n",
  3576. __FUNCTION__,
  3577. ::FusionpGetLastWin32Error());
  3578. goto Exit;
  3579. }
  3580. if (!findFile.Win32Close())
  3581. {
  3582. ::FusionpDbgPrintEx(
  3583. FUSION_DBG_LEVEL_ERROR,
  3584. "SXS.DLL: %s(): FindClose() failed:%ld\n",
  3585. __FUNCTION__,
  3586. ::FusionpGetLastWin32Error());
  3587. goto Exit;
  3588. }
  3589. FN_EPILOG
  3590. }
  3591. BOOL
  3592. SxspMoveFilesUnderDir(
  3593. DWORD dwFlags,
  3594. CBaseStringBuffer &sbSourceDir,
  3595. CBaseStringBuffer &sbDestDir,
  3596. DWORD dwMoveFileFlags)
  3597. {
  3598. WIN32_FIND_DATAW findData; // avoid allocating one of these in each recursive frame
  3599. return SxspMoveFilesUnderDir(dwFlags, sbSourceDir, sbDestDir, dwMoveFileFlags, findData);
  3600. }
  3601. BOOL
  3602. SxspGenerateNdpGACPath(
  3603. IN DWORD dwFlags,
  3604. IN PCASSEMBLY_IDENTITY pAssemblyIdentity,
  3605. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  3606. OUT CBaseStringBuffer &rPathBuffer)
  3607. /*++
  3608. Description:
  3609. SxspGenerateNdpGACPath
  3610. Generate a path into the NDP GAC for a given assembly identity.
  3611. Parameters:
  3612. dwFlags
  3613. Flags to modify function behavior. All undefined bits must be zero.
  3614. pAssemblyIdentity
  3615. Pointer to assembly identity for which to generate a path.
  3616. rPathBuffer
  3617. Reference to string buffer to fill in.
  3618. --*/
  3619. {
  3620. FN_PROLOG_WIN32
  3621. SIZE_T cchName = 0;
  3622. SIZE_T cchLanguage = 0;
  3623. SIZE_T cchPublicKeyToken = 0;
  3624. SIZE_T cchVersion = 0;
  3625. PCWSTR pszName = NULL;
  3626. PCWSTR pszLanguage = NULL;
  3627. PCWSTR pszPublicKeyToken = NULL;
  3628. PCWSTR pszVersion = NULL;
  3629. PARAMETER_CHECK(dwFlags == 0);
  3630. PARAMETER_CHECK(pAssemblyIdentity != NULL);
  3631. rPathBuffer.Clear();
  3632. #define GET(x, y, z) \
  3633. do { \
  3634. if (ppac != NULL) { \
  3635. if ((ppac->dwFlags & PROBING_ATTRIBUTE_CACHE_FLAG_GOT_ ## z) == 0) { \
  3636. IFW32FALSE_EXIT( \
  3637. ::SxspGetAssemblyIdentityAttributeValue( \
  3638. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL, \
  3639. pAssemblyIdentity, \
  3640. &s_IdentityAttribute_ ## x, \
  3641. &psz ## y, \
  3642. &cch ## y)); \
  3643. ppac->psz ## y = psz ## y; \
  3644. ppac->cch ## y = cch ## y; \
  3645. ppac->dwFlags |= PROBING_ATTRIBUTE_CACHE_FLAG_GOT_ ## z; \
  3646. } else { \
  3647. psz ## y = ppac->psz ## y; \
  3648. cch ## y = ppac->cch ## y; \
  3649. } \
  3650. } else { \
  3651. IFW32FALSE_EXIT( \
  3652. ::SxspGetAssemblyIdentityAttributeValue( \
  3653. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL, \
  3654. pAssemblyIdentity, \
  3655. &s_IdentityAttribute_ ## x, \
  3656. &psz ## y, \
  3657. &cch ## y)); \
  3658. } \
  3659. } while (0)
  3660. GET(name, Name, NAME);
  3661. GET(language, Language, LANGUAGE);
  3662. GET(publicKeyToken, PublicKeyToken, PUBLIC_KEY_TOKEN);
  3663. GET(version, Version, VERSION);
  3664. #undef GET
  3665. IFW32FALSE_EXIT(
  3666. rPathBuffer.Win32AssignW(
  3667. 9,
  3668. USER_SHARED_DATA->NtSystemRoot, -1,
  3669. L"\\assembly\\GAC\\", -1,
  3670. pszName, static_cast<INT>(cchName),
  3671. L"\\", 1,
  3672. pszVersion, static_cast<INT>(cchVersion),
  3673. L"_", 1,
  3674. pszLanguage, static_cast<INT>(cchLanguage),
  3675. L"_", 1,
  3676. pszPublicKeyToken, static_cast<INT>(cchPublicKeyToken)));
  3677. FN_EPILOG
  3678. }
  3679. BOOL
  3680. SxspIsFileNameValidForManifest(
  3681. const CBaseStringBuffer &rsbFileName,
  3682. bool &rfValid)
  3683. {
  3684. FN_PROLOG_WIN32
  3685. static const PCWSTR s_rgDotPatterns[] = {
  3686. L"..\\",
  3687. L"../",
  3688. L"\\..",
  3689. L"/.."
  3690. };
  3691. //
  3692. // Rules for a file name:
  3693. // - Must be 'relative' in the eyes of Rtl
  3694. // - Must not contain ../, ..\, /.., or \..
  3695. //
  3696. rfValid = false;
  3697. //
  3698. // The string has to be less than max-unicode-string max, and it has to
  3699. // be a relative path, and it can't contain the above pattern of dots
  3700. // and slashes.
  3701. //
  3702. if (::SxspDetermineDosPathNameType(rsbFileName) == RtlPathTypeRelative)
  3703. {
  3704. //
  3705. // Ensure that none of the patterns are there.
  3706. //
  3707. for (SIZE_T c = 0; c < NUMBER_OF(s_rgDotPatterns); c++)
  3708. {
  3709. if (wcsstr(rsbFileName, s_rgDotPatterns[c]) != NULL)
  3710. break;
  3711. }
  3712. //
  3713. // Ran to the end of the query items w/o matching
  3714. //
  3715. if (c == NUMBER_OF(s_rgDotPatterns))
  3716. rfValid = true;
  3717. }
  3718. FN_EPILOG
  3719. }