Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4402 lines
135 KiB

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