Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1280 lines
40 KiB

  1. /*
  2. Copyright (c) Microsoft Corporation
  3. */
  4. #include "stdinc.h"
  5. #include "fusionheap.h"
  6. #include "fusionbuffer.h"
  7. #include "fusionparser.h"
  8. #include "strongname.h"
  9. #include "cassemblyrecoveryinfo.h"
  10. #include "hashfile.h"
  11. #include "fusionhandle.h"
  12. #include "util.h"
  13. #include "sxsp.h"
  14. #include "recover.h"
  15. extern const UNICODE_STRING UnicodeString_URLHEAD_WINSOURCE =
  16. {
  17. sizeof(URLHEAD_WINSOURCE) - sizeof(URLHEAD_WINSOURCE[0]),
  18. sizeof(URLHEAD_WINSOURCE),
  19. const_cast<PWSTR>(URLHEAD_WINSOURCE)
  20. };
  21. class CSxspMapShortNameToAssemblyLocals
  22. {
  23. public:
  24. CSxspMapShortNameToAssemblyLocals() { }
  25. ~CSxspMapShortNameToAssemblyLocals() { }
  26. CSmallStringBuffer buffManifestName;
  27. CSmallStringBuffer buffCatalogName;
  28. CStringBuffer buffKeyName;
  29. CSmallStringBuffer buffAcquiredShortName;
  30. };
  31. BOOL
  32. pMapShortNameToAssembly(
  33. IN OUT CBaseStringBuffer &rbuffAssemblyName,
  34. IN const CRegKey &hkInstallInfoKey,
  35. OUT CRegKey &hRequestedAsm,
  36. IN REGSAM rsReadRights = KEY_READ
  37. )
  38. {
  39. FN_PROLOG_WIN32
  40. CSmartPtr<CSxspMapShortNameToAssemblyLocals> Locals;
  41. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  42. CSmallStringBuffer &buffManifestName = Locals->buffManifestName;
  43. CSmallStringBuffer &buffCatalogName = Locals->buffCatalogName;
  44. DWORD dwIndex = 0;
  45. PCWSTR pszValueName = NULL;
  46. hRequestedAsm = CRegKey::GetInvalidValue();
  47. IFW32FALSE_EXIT(buffManifestName.Win32Assign(rbuffAssemblyName));
  48. IFW32FALSE_EXIT(buffManifestName.Win32Append(L".man", 4));
  49. IFW32FALSE_EXIT(buffCatalogName.Win32Assign(rbuffAssemblyName));
  50. IFW32FALSE_EXIT(buffCatalogName.Win32Append(L".cat", 4));
  51. //
  52. // Look for this under the CSMD_TOPLEVEL_SHORTNAME first
  53. //
  54. for (;;)
  55. {
  56. CStringBuffer &buffKeyName = Locals->buffKeyName;
  57. CSmallStringBuffer &buffAcquiredShortName = Locals->buffAcquiredShortName;
  58. BOOL fTempBoolean = FALSE;
  59. CRegKey hAsm;
  60. buffKeyName.Clear();
  61. buffAcquiredShortName.Clear();
  62. IFW32FALSE_EXIT(hkInstallInfoKey.EnumKey(
  63. dwIndex++,
  64. buffKeyName,
  65. NULL,
  66. &fTempBoolean));
  67. if (fTempBoolean)
  68. break;
  69. IFW32FALSE_EXIT(hkInstallInfoKey.OpenSubKey(hAsm, buffKeyName, rsReadRights));
  70. //
  71. // Get the value of the key
  72. //
  73. IFW32FALSE_EXIT(
  74. ::FusionpRegQuerySzValueEx(
  75. FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING,
  76. hAsm,
  77. CSMD_TOPLEVEL_SHORTNAME,
  78. buffAcquiredShortName));
  79. //
  80. // If the key was there to be read:
  81. //
  82. if (buffAcquiredShortName.Cch() != 0)
  83. {
  84. if (::FusionpEqualStringsI(
  85. buffAcquiredShortName,
  86. rbuffAssemblyName
  87. ))
  88. {
  89. IFW32FALSE_EXIT(rbuffAssemblyName.Win32Assign(buffKeyName));
  90. IFW32FALSE_EXIT(hkInstallInfoKey.OpenSubKey( hRequestedAsm, buffKeyName, rsReadRights ) );
  91. break;
  92. }
  93. }
  94. //
  95. // Get the value of the key
  96. //
  97. IFW32FALSE_EXIT(
  98. ::FusionpRegQuerySzValueEx(
  99. FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING,
  100. hAsm,
  101. CSMD_TOPLEVEL_SHORTMANIFEST,
  102. buffAcquiredShortName));
  103. //
  104. // If the key was there to be read:
  105. //
  106. if (buffAcquiredShortName.Cch() != 0)
  107. {
  108. if (::FusionpEqualStringsI(
  109. buffAcquiredShortName,
  110. buffManifestName
  111. ))
  112. {
  113. IFW32FALSE_EXIT(rbuffAssemblyName.Win32Assign(buffKeyName));
  114. IFW32FALSE_EXIT(hkInstallInfoKey.OpenSubKey(hRequestedAsm, buffKeyName, rsReadRights));
  115. break;
  116. }
  117. }
  118. //
  119. // Get the value of the key
  120. //
  121. IFW32FALSE_EXIT(
  122. ::FusionpRegQuerySzValueEx(
  123. FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING,
  124. hAsm,
  125. CSMD_TOPLEVEL_SHORTCATALOG,
  126. buffAcquiredShortName));
  127. //
  128. // If the key was there to be read:
  129. //
  130. if (buffAcquiredShortName.Cch() != 0)
  131. {
  132. if (::FusionpEqualStringsI(
  133. buffAcquiredShortName,
  134. buffCatalogName
  135. ))
  136. {
  137. IFW32FALSE_EXIT(rbuffAssemblyName.Win32Assign(buffKeyName));
  138. IFW32FALSE_EXIT(hkInstallInfoKey.OpenSubKey(hRequestedAsm, buffKeyName, rsReadRights));
  139. break;
  140. }
  141. }
  142. }
  143. FN_EPILOG
  144. }
  145. class CAssemblyRecoveryInfoResolveCDRomURLLocals
  146. {
  147. public:
  148. CAssemblyRecoveryInfoResolveCDRomURLLocals()
  149. {
  150. rgchVolumeName[0] = 0;
  151. chBuffer[0] = 0;
  152. }
  153. ~CAssemblyRecoveryInfoResolveCDRomURLLocals() { }
  154. CStringBuffer sbIdentKind, sbIdentData1, sbIdentData2;
  155. CSmallStringBuffer buffDriveStrings;
  156. WCHAR rgchVolumeName[MAX_PATH];
  157. CHAR chBuffer[MAX_PATH];
  158. CStringBuffer sbContents;
  159. };
  160. BOOL
  161. CAssemblyRecoveryInfo::ResolveCDRomURL(
  162. PCWSTR pszSource,
  163. CBaseStringBuffer &rsbDestination
  164. ) const
  165. {
  166. BOOL fSuccess = TRUE;
  167. FN_TRACE_WIN32(fSuccess);
  168. CStringBufferAccessor acc;
  169. BOOL fFoundMedia = FALSE;
  170. CSmartPtr<CAssemblyRecoveryInfoResolveCDRomURLLocals> Locals;
  171. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  172. CStringBuffer & sbIdentKind = Locals->sbIdentKind;
  173. CStringBuffer & sbIdentData1 = Locals->sbIdentData1;
  174. CStringBuffer & sbIdentData2 = Locals->sbIdentData2;
  175. CSmallStringBuffer & buffDriveStrings = Locals->buffDriveStrings;
  176. SIZE_T HeadLength = 0;
  177. PCWSTR wcsCursor = NULL;
  178. ULONG ulSerialNumber = 0;
  179. CDRomSearchType SearchType = static_cast<CDRomSearchType>(0);
  180. PARAMETER_CHECK(pszSource != NULL);
  181. if (!_wcsnicmp(pszSource, URLHEAD_CDROM_TYPE_TAG, URLHEAD_LENGTH_CDROM_TYPE_TAG))
  182. {
  183. HeadLength = URLHEAD_LENGTH_CDROM_TYPE_TAG;
  184. SearchType = CDRST_Tagfile;
  185. }
  186. else if (!_wcsnicmp(
  187. pszSource,
  188. URLHEAD_CDROM_TYPE_SERIALNUMBER,
  189. URLHEAD_LENGTH_CDROM_TYPE_SERIALNUMBER))
  190. {
  191. HeadLength = URLHEAD_LENGTH_CDROM_TYPE_SERIALNUMBER;
  192. SearchType = CDRST_SerialNumber;
  193. }
  194. else if (!_wcsnicmp(
  195. pszSource,
  196. URLHEAD_CDROM_TYPE_VOLUMENAME,
  197. URLHEAD_LENGTH_CDROM_TYPE_VOLUMENAME))
  198. {
  199. HeadLength = URLHEAD_LENGTH_CDROM_TYPE_VOLUMENAME;
  200. SearchType = CDRST_VolumeName;
  201. }
  202. else
  203. {
  204. ::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
  205. goto Exit;
  206. }
  207. //
  208. // Get the type of identifier here, and then move the cursor past them and
  209. // the slashes in the url.
  210. //
  211. IFW32FALSE_EXIT(sbIdentKind.Win32Assign(pszSource, HeadLength));
  212. pszSource += HeadLength;
  213. pszSource += wcsspn(pszSource, CUnicodeCharTraits::PathSeparators());
  214. //
  215. // Spin past slashes, assign chunklets
  216. //
  217. IFW32FALSE_EXIT(sbIdentData1.Win32Assign(pszSource, wcscspn(pszSource, CUnicodeCharTraits::PathSeparators())));
  218. pszSource += sbIdentData1.Cch();
  219. pszSource += wcsspn(pszSource, CUnicodeCharTraits::PathSeparators());
  220. //
  221. // If this is a tagfile, also get another blobbet of data off the string
  222. //
  223. if (SearchType == CDRST_Tagfile)
  224. {
  225. IFW32FALSE_EXIT(sbIdentData2.Win32Assign(pszSource, wcscspn(pszSource, CUnicodeCharTraits::PathSeparators())));
  226. pszSource += sbIdentData2.Cch();
  227. pszSource += wcsspn(pszSource, CUnicodeCharTraits::PathSeparators());
  228. }
  229. else if (SearchType == CDRST_SerialNumber)
  230. {
  231. IFW32FALSE_EXIT(CFusionParser::ParseULONG(
  232. ulSerialNumber,
  233. sbIdentData1,
  234. sbIdentData1.Cch(),
  235. 16));
  236. }
  237. //
  238. // Now let's do ... interesting ... things to the CD-roms.
  239. //
  240. IFW32FALSE_EXIT(buffDriveStrings.Win32ResizeBuffer(GetLogicalDriveStringsW(0, NULL) + 1, eDoNotPreserveBufferContents));
  241. acc.Attach(&buffDriveStrings);
  242. IFW32FALSE_ORIGINATE_AND_EXIT(
  243. ::GetLogicalDriveStringsW(
  244. static_cast<DWORD>(acc.GetBufferCch()),
  245. acc));
  246. acc.Detach();
  247. wcsCursor = buffDriveStrings;
  248. //
  249. // Look at all the found drive letters
  250. //
  251. while (wcsCursor && *wcsCursor && !fFoundMedia)
  252. {
  253. DWORD dwSerialNumber = 0;
  254. const DWORD dwDriveType = ::GetDriveTypeW(wcsCursor);
  255. if (dwDriveType == DRIVE_CDROM)
  256. {
  257. //
  258. // I argue that a failure in GetVolumeInformationW isn't "bad enough"
  259. // to kill the call to this function. Instead, it should just skip
  260. // the check of the failed drive letter, as it does here.
  261. //
  262. if(!::GetVolumeInformationW(
  263. wcsCursor,
  264. Locals->rgchVolumeName,
  265. NUMBER_OF(Locals->rgchVolumeName),
  266. &dwSerialNumber,
  267. NULL,
  268. NULL,
  269. NULL,
  270. 0))
  271. {
  272. #if DBG
  273. ::FusionpDbgPrintEx(
  274. FUSION_DBG_LEVEL_WFP,
  275. "SXS.DLL: %s() - Failed getting volume information for drive letter %ls (Win32 Error = %ld), skipping\n",
  276. __FUNCTION__,
  277. wcsCursor,
  278. ::FusionpGetLastWin32Error());
  279. #endif
  280. continue;
  281. }
  282. switch (SearchType)
  283. {
  284. case CDRST_Tagfile:
  285. {
  286. CFusionFile FileHandle;
  287. CStringBuffer &sbContents = Locals->sbContents;
  288. DWORD dwTextLength;
  289. if (FileHandle.Win32CreateFile(sbIdentData1, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING))
  290. {
  291. IFW32FALSE_ORIGINATE_AND_EXIT(
  292. ::ReadFile(
  293. FileHandle,
  294. Locals->chBuffer, NUMBER_OF(Locals->chBuffer),
  295. &dwTextLength, NULL));
  296. IFW32FALSE_EXIT(sbContents.Win32Assign(Locals->chBuffer, dwTextLength));
  297. fFoundMedia = !_wcsnicmp(sbContents, sbIdentData2, sbIdentData2.Cch());
  298. }
  299. }
  300. break;
  301. case CDRST_SerialNumber:
  302. fFoundMedia = (dwSerialNumber == ulSerialNumber);
  303. break;
  304. case CDRST_VolumeName:
  305. fFoundMedia = (::FusionpStrCmpI(Locals->rgchVolumeName, sbIdentData1) == 0);
  306. break;
  307. default:
  308. break;
  309. }
  310. }
  311. if (!fFoundMedia)
  312. wcsCursor += ::wcslen(wcsCursor) + 1;
  313. }
  314. if (fFoundMedia)
  315. {
  316. IFW32FALSE_EXIT(rsbDestination.Win32Assign(wcsCursor, ::wcslen(wcsCursor)));
  317. IFW32FALSE_EXIT(rsbDestination.Win32AppendPathElement(pszSource, ::wcslen(pszSource)));
  318. }
  319. fSuccess = TRUE;
  320. Exit:
  321. //
  322. // Failure indicated by an empty destination.
  323. //
  324. if (!fSuccess)
  325. {
  326. rsbDestination.Clear();
  327. }
  328. return fSuccess;
  329. }
  330. BOOL
  331. CAssemblyRecoveryInfo::ResolveWinSourceMediaURL(
  332. PCWSTR wcsUrlTrailer,
  333. CBaseStringBuffer &rsbDestination
  334. ) const
  335. {
  336. CStringBuffer buffWindowsInstallSource;
  337. const static PCWSTR AssemblySourceStrings[] = {
  338. WINSXS_INSTALL_SVCPACK_REGKEY,
  339. WINSXS_INSTALL_SOURCEPATH_REGKEY
  340. };
  341. SIZE_T iWhichSource = 0;
  342. BOOL fSuccess = TRUE;
  343. BOOL fFoundCodebase = FALSE;
  344. CFusionRegKey hkSetupInfo;
  345. DWORD dwWasFromCDRom = 0;
  346. FN_TRACE_WIN32(fSuccess);
  347. PARAMETER_CHECK(wcsUrlTrailer != NULL);
  348. IFREGFAILED_ORIGINATE_AND_EXIT(
  349. ::RegOpenKeyExW(
  350. HKEY_LOCAL_MACHINE,
  351. WINSXS_INSTALL_SOURCE_BASEDIR,
  352. 0,
  353. KEY_READ | FUSIONP_KEY_WOW64_64KEY,
  354. &hkSetupInfo));
  355. if (!::FusionpRegQueryDwordValueEx(
  356. 0,
  357. hkSetupInfo,
  358. WINSXS_INSTALL_SOURCE_IS_CDROM,
  359. &dwWasFromCDRom))
  360. {
  361. dwWasFromCDRom = 0;
  362. }
  363. while (iWhichSource < NUMBER_OF(AssemblySourceStrings))
  364. {
  365. IFW32FALSE_EXIT(
  366. ::FusionpRegQuerySzValueEx(
  367. FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING,
  368. hkSetupInfo,
  369. AssemblySourceStrings[iWhichSource],
  370. buffWindowsInstallSource));
  371. //
  372. // This really _really_ should not be empty. If it is, then someone
  373. // went and fiddled with the registry on us.
  374. //
  375. ASSERT(buffWindowsInstallSource.Cch() != 0);
  376. if (buffWindowsInstallSource.Cch() == 0)
  377. {
  378. iWhichSource++;
  379. continue;
  380. }
  381. //
  382. // If this was from a CD, then spin through the list of CD's in the system
  383. // and see if we can match the codebase against the root dir of the CD
  384. //
  385. if (dwWasFromCDRom)
  386. {
  387. CSmallStringBuffer buffDriveStrings;
  388. CStringBufferAccessor acc;
  389. PCWSTR pszCursor = NULL;
  390. DWORD dwSize = 0;
  391. IFW32FALSE_EXIT(
  392. buffDriveStrings.Win32ResizeBuffer(
  393. dwSize = (::GetLogicalDriveStringsW(0, NULL) + 1),
  394. eDoNotPreserveBufferContents));
  395. acc.Attach(&buffDriveStrings);
  396. ::GetLogicalDriveStringsW(
  397. static_cast<DWORD>(acc.GetBufferCch()),
  398. acc);
  399. acc.Detach();
  400. pszCursor = buffDriveStrings;
  401. while (*pszCursor)
  402. {
  403. if (::GetDriveTypeW(pszCursor) == DRIVE_CDROM)
  404. {
  405. DWORD dwAttributes;
  406. DWORD dwWin32Error;
  407. IFW32FALSE_EXIT(rsbDestination.Win32Assign(pszCursor, ::wcslen(pszCursor)));
  408. IFW32FALSE_EXIT(rsbDestination.Win32AppendPathElement(wcsUrlTrailer, ::wcslen(wcsUrlTrailer)));
  409. IFW32FALSE_EXIT(
  410. ::SxspGetFileAttributesW(
  411. rsbDestination,
  412. dwAttributes,
  413. dwWin32Error,
  414. 4,
  415. ERROR_FILE_NOT_FOUND,
  416. ERROR_PATH_NOT_FOUND,
  417. ERROR_NOT_READY,
  418. ERROR_ACCESS_DENIED));
  419. if (dwWin32Error == ERROR_SUCCESS)
  420. {
  421. fFoundCodebase = TRUE;
  422. FN_SUCCESSFUL_EXIT();
  423. }
  424. }
  425. pszCursor += ::wcslen(pszCursor) + 1;
  426. }
  427. }
  428. //
  429. // This wasn't a CD-rom installation, so prepend the install source path to
  430. // the string that was passed in.
  431. //
  432. else
  433. {
  434. IFW32FALSE_EXIT(rsbDestination.Win32Assign(buffWindowsInstallSource, buffWindowsInstallSource.Cch()));
  435. IFW32FALSE_EXIT(rsbDestination.Win32AppendPathElement(wcsUrlTrailer, ::wcslen(wcsUrlTrailer)));
  436. bool fExist = false;
  437. IFW32FALSE_EXIT(::SxspDoesFileExist(SXSP_DOES_FILE_EXIST_FLAG_CHECK_DIRECTORY_ONLY, rsbDestination, fExist));
  438. if (fExist)
  439. {
  440. fFoundCodebase = TRUE;
  441. fSuccess = TRUE;
  442. goto Exit;
  443. }
  444. }
  445. iWhichSource++;
  446. }
  447. fSuccess = TRUE;
  448. Exit:
  449. if (!fFoundCodebase)
  450. {
  451. rsbDestination.Clear();
  452. }
  453. return fSuccess;
  454. }
  455. BOOL
  456. CAssemblyRecoveryInfo::AssociateWithAssembly(
  457. IN OUT CBaseStringBuffer &rsbSourceAssemblyName,
  458. bool &rfNoAssembly
  459. )
  460. {
  461. //
  462. // First check the manifest that the assembly came out of. If it still exists,
  463. // then nifty, go and load the info from it. Otherwise, we should look in the
  464. // registry for information instead.
  465. //
  466. FN_PROLOG_WIN32
  467. CFusionRegKey hInstallInfoKey;
  468. CFusionRegKey hRequestedAsm;
  469. rfNoAssembly = true;
  470. //
  471. // First attempt - try to load it directly off the root installation key.
  472. //
  473. if (!m_fLoadedAndReady)
  474. {
  475. IFW32FALSE_EXIT(this->Initialize());
  476. IFW32FALSE_EXIT(::SxspOpenAssemblyInstallationKey(0, KEY_READ, hInstallInfoKey));
  477. IFW32FALSE_EXIT(
  478. hInstallInfoKey.OpenSubKey(
  479. hRequestedAsm,
  480. rsbSourceAssemblyName,
  481. KEY_READ));
  482. //
  483. // This direct entry wasn't found, so let's go see if we can map it back to some
  484. // other assembly name using the shortname stuff.
  485. //
  486. if (hRequestedAsm == CRegKey::GetInvalidValue())
  487. {
  488. IFW32FALSE_EXIT(
  489. ::pMapShortNameToAssembly(
  490. rsbSourceAssemblyName, // if this is a short name of an assembly, this function would set this to be real assembly name if match is found
  491. hInstallInfoKey,
  492. hRequestedAsm));
  493. //
  494. // Still not found? Darn.
  495. //
  496. if (hRequestedAsm == CRegKey::GetInvalidValue())
  497. FN_SUCCESSFUL_EXIT();
  498. }
  499. IFW32FALSE_EXIT(this->m_sbAssemblyDirectoryName.Win32Assign(rsbSourceAssemblyName));
  500. IFW32FALSE_EXIT(this->m_SecurityMetaData.LoadFromRegistryKey(hRequestedAsm));
  501. this->m_fLoadedAndReady = TRUE;
  502. }
  503. //
  504. // Only set the "no assembly" if we were able to associate (before or
  505. // above.)
  506. //
  507. if ( this->m_fLoadedAndReady )
  508. rfNoAssembly = false;
  509. FN_EPILOG
  510. }
  511. BOOL
  512. SxspDetermineCodebaseType(
  513. IN const CBaseStringBuffer &rcbuffUrlString,
  514. OUT SxsWFPResolveCodebase &rcbaseType,
  515. OUT CBaseStringBuffer *pbuffRemainder
  516. )
  517. {
  518. FN_PROLOG_WIN32
  519. PCWSTR pcwszStringTop = rcbuffUrlString;
  520. SIZE_T cch = rcbuffUrlString.Cch();
  521. SIZE_T i = 0;
  522. CSmallStringBuffer buffTemp; // may be used if we mangle the URL text more
  523. rcbaseType = CODEBASE_RESOLVED_URLHEAD_UNKNOWN;
  524. if (pbuffRemainder != NULL)
  525. pbuffRemainder->Clear();
  526. #define ENTRY(_x) { URLHEAD_ ## _x, NUMBER_OF(URLHEAD_ ## _x) - 1, NUMBER_OF(URLHEAD_ ## _x) - 1, CODEBASE_RESOLVED_URLHEAD_ ## _x },
  527. static const struct
  528. {
  529. PCWSTR pszPrefix;
  530. SIZE_T cchPrefix;
  531. SIZE_T cchAdvance;
  532. SxsWFPResolveCodebase cbaseType;
  533. } s_rgMap[] =
  534. {
  535. ENTRY(FILE)
  536. ENTRY(WINSOURCE)
  537. ENTRY(CDROM)
  538. ENTRY(HTTP)
  539. };
  540. #undef ENTRY
  541. for (i=0; i<NUMBER_OF(s_rgMap); i++)
  542. {
  543. if (_wcsnicmp(pcwszStringTop, s_rgMap[i].pszPrefix, s_rgMap[i].cchPrefix) == 0)
  544. {
  545. pcwszStringTop += s_rgMap[i].cchAdvance;
  546. cch -= s_rgMap[i].cchAdvance;
  547. rcbaseType = s_rgMap[i].cbaseType;
  548. break;
  549. }
  550. }
  551. // If there wasn't an entry, we'll assume it's a simple file path.
  552. if (i == NUMBER_OF(s_rgMap))
  553. {
  554. rcbaseType = CODEBASE_RESOLVED_URLHEAD_FILE;
  555. }
  556. else
  557. {
  558. // If it was a real file: codebase, there's ambiguity about whether there is supposed
  559. // to be 0, 1, 2 or 3 slashes, so we'll just absorb up to 3 slashes to get to what hopefully
  560. // is then a local path. e.g.
  561. //
  562. // file:c:\foo\bar.manifest
  563. // file://c:\foo\bar.manifest
  564. // file:///c:\foo\bar.manifest
  565. //
  566. // all turn into c:\foo\bar.manifest. The URL standard seems clear that non-absolute
  567. // URLs are interpreted in the context of their containing document. In the case
  568. // of a free-standing codebase, that would seem to mean that the hostname field is
  569. // required, where the general form is (by my reading):
  570. //
  571. // file:[//[hostname]]/path
  572. //
  573. // it kind of makes sense to imagine that file:/c:\foo.manifest is reasonable; the only
  574. // useful context to get the hostname from is the local machine. file:///c:\foo.manifest
  575. // meets the standards for URLs not contained in a web document. file:c:\foo.manifest
  576. // also makes sense if you believe the point of the slash is separate the hostname specification
  577. // from the host-specific part of the URL, since if you're happy omitting the hostname
  578. // part, there's nothing to separate. (Note that really file:c:\foo.manifest should
  579. // be considered relative to the current document since it doesn't have the slash at the
  580. // front of the name, but even less than we have a current hostname, we certainly
  581. // don't have a point in the filesystem hierarchy that it makes sense to consider "current".)
  582. //
  583. // file://c:\foo\bar.manifest seems to have become popular even though it doesn't
  584. // have any useful definition in any way shape or form. The two slashes should indicate
  585. // that the next thing should be hostname; instead we see c:\
  586. //
  587. // That's all just a long-winded justifcation for absorbing up to 3 slashes at the
  588. // beginning of the remainder of the string. If there are four or more, we'll let it fail
  589. // as a bad path later on.
  590. //
  591. // mgrier 6/27/2001
  592. if (rcbaseType == CODEBASE_RESOLVED_URLHEAD_FILE)
  593. {
  594. if ((cch > 0) && (pcwszStringTop[0] == L'/'))
  595. {
  596. cch--;
  597. pcwszStringTop++;
  598. }
  599. if ((cch > 0) && (pcwszStringTop[0] == L'/'))
  600. {
  601. cch--;
  602. pcwszStringTop++;
  603. }
  604. if ((cch > 0) && (pcwszStringTop[0] == L'/'))
  605. {
  606. cch--;
  607. pcwszStringTop++;
  608. }
  609. }
  610. else if (rcbaseType == CODEBASE_RESOLVED_URLHEAD_HTTP)
  611. {
  612. // Hey, on Whistler, we have the WebDAV redirector, so
  613. // we can turn this URL into a UNC path!
  614. bool fGeneratedUNCPath = false;
  615. IFW32FALSE_EXIT(buffTemp.Win32Assign(L"\\\\", 2));
  616. if (pcwszStringTop[0] == L'/')
  617. {
  618. if (pcwszStringTop[1] == L'/')
  619. {
  620. // http:// so far; the next thing must be a hostname!
  621. PCWSTR pszSlash = wcschr(pcwszStringTop + 2, L'/');
  622. if (pszSlash != NULL)
  623. {
  624. // //foo/bar (http: removed earlier...)
  625. // pcwszStringTop == [0]
  626. // pszSlash == [5]
  627. // cch == 9
  628. IFW32FALSE_EXIT(buffTemp.Win32Append(pcwszStringTop + 2, (pszSlash - pcwszStringTop) - 3));
  629. IFW32FALSE_EXIT(buffTemp.Win32Append(L"\\", 1));
  630. IFW32FALSE_EXIT(buffTemp.Win32Append(pszSlash + 1, cch - (pszSlash - pcwszStringTop) - 1));
  631. fGeneratedUNCPath = true;
  632. }
  633. }
  634. }
  635. if (fGeneratedUNCPath)
  636. {
  637. // poof, it's a file path
  638. pcwszStringTop = buffTemp;
  639. cch = buffTemp.Cch();
  640. rcbaseType = CODEBASE_RESOLVED_URLHEAD_FILE;
  641. }
  642. }
  643. }
  644. if (pbuffRemainder != NULL)
  645. {
  646. IFW32FALSE_EXIT(
  647. pbuffRemainder->Win32Assign(pcwszStringTop, cch));
  648. }
  649. #if DBG
  650. {
  651. CUnicodeString a(rcbuffUrlString, rcbuffUrlString.Cch());
  652. CUnicodeString b(rcbuffUrlString, (cch <= rcbuffUrlString.Cch()) ? (rcbuffUrlString.Cch() - cch) : 0);
  653. CUnicodeString c(pcwszStringTop, (cch <= ::wcslen(pcwszStringTop)) ? cch : 0);
  654. ::FusionpDbgPrintEx(
  655. FUSION_DBG_LEVEL_WFP,
  656. "SXS: %s - split \"%wZ\" into \"%wZ\" and \"%wZ\"\n",
  657. __FUNCTION__, &a, &b, &c);
  658. }
  659. #endif
  660. FN_EPILOG
  661. }
  662. BOOL
  663. CAssemblyRecoveryInfo::CopyValue(const CAssemblyRecoveryInfo& other)
  664. {
  665. BOOL bSuccess = FALSE;
  666. FN_TRACE_WIN32(bSuccess);
  667. if (&other != this)
  668. {
  669. IFW32FALSE_EXIT(m_sbAssemblyDirectoryName.Win32Assign(other.m_sbAssemblyDirectoryName));
  670. IFW32FALSE_EXIT(m_SecurityMetaData.Initialize(other.m_SecurityMetaData));
  671. m_fLoadedAndReady = other.m_fLoadedAndReady;
  672. }
  673. bSuccess = TRUE;
  674. Exit:
  675. if ( !bSuccess )
  676. {
  677. this->m_fLoadedAndReady = FALSE;
  678. }
  679. return bSuccess;
  680. }
  681. BOOL
  682. CAssemblyRecoveryInfo::SetAssemblyIdentity(
  683. IN PCASSEMBLY_IDENTITY pcidAssembly
  684. )
  685. {
  686. FN_PROLOG_WIN32
  687. CTinyStringBuffer sbTextualEncoding;
  688. IFW32FALSE_EXIT(::SxspGenerateTextualIdentity(0, pcidAssembly, sbTextualEncoding));
  689. IFW32FALSE_EXIT( this->SetAssemblyIdentity( sbTextualEncoding ) );
  690. FN_EPILOG
  691. }
  692. class CAssemblyRecoveryInfoPrepareForWritingLocals
  693. {
  694. public:
  695. CAssemblyRecoveryInfoPrepareForWritingLocals() { }
  696. ~CAssemblyRecoveryInfoPrepareForWritingLocals() { }
  697. CStringBuffer buffTemp1;
  698. CStringBuffer buffTemp2;
  699. CSmallStringBuffer buffAsmRoot;
  700. CStringBuffer buffManifestPath;
  701. };
  702. BOOL
  703. CAssemblyRecoveryInfo::PrepareForWriting()
  704. {
  705. FN_PROLOG_WIN32
  706. CSmartPtrWithNamedDestructor<ASSEMBLY_IDENTITY, &::SxsDestroyAssemblyIdentity> pIdentity;
  707. CSmartPtr<CAssemblyRecoveryInfoPrepareForWritingLocals> Locals;
  708. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  709. CSmallStringBuffer &buffAsmRoot = Locals->buffAsmRoot;
  710. CStringBuffer &buffTemp1 = Locals->buffTemp1;
  711. CStringBuffer &buffTemp2 = Locals->buffTemp2;
  712. const CBaseStringBuffer& OurTextualIdentity = m_SecurityMetaData.GetTextualIdentity();
  713. BOOL fIsPolicy = FALSE;
  714. DWORD dwWin32Error = 0;
  715. ::FusionpDbgPrintEx(
  716. FUSION_DBG_LEVEL_WFP,
  717. "SXS.DLL: %s - handling assembly \"%ls\"\n",
  718. __FUNCTION__,
  719. static_cast<PCWSTR>(OurTextualIdentity));
  720. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(buffAsmRoot));
  721. IFW32FALSE_EXIT(::SxspCreateAssemblyIdentityFromTextualString(OurTextualIdentity, &pIdentity));
  722. IFW32FALSE_EXIT(::SxspDetermineAssemblyType(pIdentity, fIsPolicy));
  723. //
  724. // It's likely that this short name hasn't been generated yet, mostly because the files
  725. // may not have been copied around just yet.
  726. //
  727. if (this->m_SecurityMetaData.GetInstalledDirShortName().Cch() == 0)
  728. {
  729. IFW32FALSE_EXIT(
  730. ::SxspGenerateSxsPath(
  731. fIsPolicy ? SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION : 0,
  732. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY | ( fIsPolicy ? SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY : 0 ),
  733. buffAsmRoot,
  734. buffAsmRoot.Cch(),
  735. pIdentity,
  736. NULL,
  737. buffTemp2));
  738. IFW32FALSE_EXIT(
  739. ::SxspGetShortPathName(
  740. buffTemp2,
  741. buffTemp1,
  742. dwWin32Error,
  743. 4,
  744. ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND, ERROR_BAD_NET_NAME, ERROR_BAD_NETPATH));
  745. if (dwWin32Error == ERROR_SUCCESS)
  746. {
  747. IFW32FALSE_EXIT(buffTemp1.Win32RemoveTrailingPathSeparators());
  748. IFW32FALSE_EXIT(buffTemp1.Win32GetLastPathElement(buffTemp2));
  749. IFW32FALSE_EXIT(m_SecurityMetaData.SetInstalledDirShortName(buffTemp2));
  750. ::FusionpDbgPrintEx(
  751. FUSION_DBG_LEVEL_WFP,
  752. "SXS: %s - decided that the short dir name is \"%ls\"\n",
  753. __FUNCTION__,
  754. static_cast<PCWSTR>(buffTemp2));
  755. }
  756. else
  757. {
  758. ::FusionpDbgPrintEx(
  759. FUSION_DBG_LEVEL_WFP,
  760. "SXS: %s - unable to determine short name for \"%ls\"\n",
  761. __FUNCTION__,
  762. static_cast<PCWSTR>(buffTemp2));
  763. }
  764. }
  765. //
  766. // Get the public key token string
  767. //
  768. {
  769. PCWSTR wchString = NULL;
  770. SIZE_T cchString = 0;
  771. CFusionByteArray baStrongNameBits;
  772. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(
  773. SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
  774. pIdentity,
  775. &s_IdentityAttribute_publicKeyToken,
  776. &wchString,
  777. &cchString));
  778. if (cchString != 0)
  779. {
  780. IFW32FALSE_EXIT(::SxspHashStringToBytes(wchString, cchString, baStrongNameBits));
  781. IFW32FALSE_EXIT(m_SecurityMetaData.SetSignerPublicKeyTokenBits(baStrongNameBits));
  782. }
  783. }
  784. //
  785. // And now the short name of the manifest and catalog, but only if this
  786. // isn't a policy
  787. //
  788. if (!fIsPolicy)
  789. {
  790. CStringBuffer &buffManifestPath = Locals->buffManifestPath;
  791. IFW32FALSE_EXIT(
  792. ::SxspCreateManifestFileNameFromTextualString(
  793. 0,
  794. ( fIsPolicy ? SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY : SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST ),
  795. buffAsmRoot,
  796. OurTextualIdentity,
  797. buffManifestPath));
  798. // Get the manifest short path first
  799. IFW32FALSE_EXIT(::SxspGetShortPathName(buffManifestPath, buffTemp1));
  800. IFW32FALSE_EXIT(buffTemp1.Win32GetLastPathElement(buffTemp2));
  801. ::FusionpDbgPrintEx(
  802. FUSION_DBG_LEVEL_WFP,
  803. "SXS: %s - manifest short path name determined to be \"%ls\"\n",
  804. __FUNCTION__,
  805. static_cast<PCWSTR>(buffTemp2));
  806. IFW32FALSE_EXIT(m_SecurityMetaData.SetShortManifestPath(buffTemp2));
  807. // Then swap extensions, get the catalog short path
  808. IFW32FALSE_EXIT(
  809. buffManifestPath.Win32ChangePathExtension(
  810. FILE_EXTENSION_CATALOG,
  811. FILE_EXTENSION_CATALOG_CCH,
  812. eAddIfNoExtension));
  813. IFW32FALSE_EXIT(::SxspGetShortPathName(buffManifestPath, buffTemp1));
  814. IFW32FALSE_EXIT(buffTemp1.Win32GetLastPathElement(buffTemp2));
  815. ::FusionpDbgPrintEx(
  816. FUSION_DBG_LEVEL_WFP,
  817. "SXS: %s - catalog short path name determined to be \"%ls\"\n",
  818. __FUNCTION__,
  819. static_cast<PCWSTR>(buffTemp2));
  820. IFW32FALSE_EXIT(m_SecurityMetaData.SetShortCatalogPath(buffTemp2));
  821. }
  822. FN_EPILOG
  823. }
  824. BOOL
  825. CAssemblyRecoveryInfo::WriteSecondaryAssemblyInfoIntoRegistryKey(
  826. CRegKey & rhkRegistryNode
  827. ) const
  828. {
  829. if (SXS_AVOID_WRITING_REGISTRY)
  830. return TRUE;
  831. FN_PROLOG_WIN32
  832. IFW32FALSE_EXIT(m_SecurityMetaData.WriteSecondaryAssemblyInfoIntoRegistryKey(rhkRegistryNode));
  833. FN_EPILOG
  834. }
  835. BOOL
  836. CAssemblyRecoveryInfo::WritePrimaryAssemblyInfoToRegistryKey(
  837. ULONG Flags,
  838. CRegKey & rhkRegistryNode
  839. ) const
  840. {
  841. if (SXS_AVOID_WRITING_REGISTRY)
  842. return TRUE;
  843. FN_PROLOG_WIN32
  844. PARAMETER_CHECK((Flags & ~(SXSP_WRITE_PRIMARY_ASSEMBLY_INFO_TO_REGISTRY_KEY_FLAG_REFRESH)) == 0);
  845. ULONG Flags2 = 0;
  846. if (Flags & SXSP_WRITE_PRIMARY_ASSEMBLY_INFO_TO_REGISTRY_KEY_FLAG_REFRESH)
  847. {
  848. Flags2 |= SXSP_WRITE_PRIMARY_ASSEMBLY_INFO_INTO_REGISTRY_KEY_FLAG_REFRESH;
  849. #if DBG
  850. ::FusionpDbgPrintEx(
  851. FUSION_DBG_LEVEL_WFP | FUSION_DBG_LEVEL_INSTALLATION,
  852. "SXS.DLL: %s - propping recovery flag to WritePrimaryAssemblyInfoIntoRegistryKey\n",
  853. __FUNCTION__);
  854. #endif
  855. }
  856. IFW32FALSE_EXIT(m_SecurityMetaData.WritePrimaryAssemblyInfoIntoRegistryKey(Flags2, rhkRegistryNode));
  857. FN_EPILOG
  858. }
  859. BOOL
  860. CAssemblyRecoveryInfo::OpenInstallationSubKey(
  861. CFusionRegKey& hkSingleAssemblyInfo,
  862. DWORD OpenOrCreate,
  863. DWORD Access)
  864. {
  865. FN_PROLOG_WIN32
  866. CSmallStringBuffer buffRegKeyName;
  867. CFusionRegKey hkAllInstallationInfo;
  868. CSmartPtrWithNamedDestructor<ASSEMBLY_IDENTITY, &::SxsDestroyAssemblyIdentity> pAssemblyIdentity;
  869. IFW32FALSE_EXIT(::SxspOpenAssemblyInstallationKey(
  870. 0,
  871. OpenOrCreate,
  872. hkAllInstallationInfo));
  873. IFW32FALSE_EXIT( SxspCreateAssemblyIdentityFromTextualString(
  874. this->m_SecurityMetaData.GetTextualIdentity(),
  875. &pAssemblyIdentity ) );
  876. IFW32FALSE_EXIT( ::SxspGenerateSxsPath(
  877. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT,
  878. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
  879. NULL, 0,
  880. pAssemblyIdentity,
  881. NULL,
  882. buffRegKeyName ) );
  883. IFW32FALSE_EXIT( hkAllInstallationInfo.OpenSubKey(
  884. hkSingleAssemblyInfo,
  885. buffRegKeyName,
  886. Access,
  887. 0));
  888. FN_EPILOG
  889. }
  890. VOID
  891. CAssemblyRecoveryInfo::RestorePreviouslyExistingRegistryData()
  892. {
  893. FN_PROLOG_VOID
  894. if (m_fHadCatalog)
  895. {
  896. CFusionRegKey hkSingleAssemblyInfo;
  897. #if DBG
  898. ::FusionpDbgPrintEx(
  899. FUSION_DBG_LEVEL_INSTALLATION,
  900. "SXS.DLL: %s() - restoring registry data for %ls\n",
  901. __FUNCTION__,
  902. static_cast<PCWSTR>(this->m_SecurityMetaData.GetTextualIdentity()));
  903. #endif
  904. IFW32FALSE_EXIT(
  905. this->OpenInstallationSubKey(
  906. hkSingleAssemblyInfo,
  907. KEY_CREATE_SUB_KEY, KEY_WRITE | KEY_READ | FUSIONP_KEY_WOW64_64KEY));
  908. IFW32FALSE_EXIT(
  909. hkSingleAssemblyInfo.SetValue(
  910. CSMD_TOPLEVEL_CATALOG,
  911. static_cast<DWORD>(1)));
  912. }
  913. FN_EPILOG
  914. }
  915. BOOL
  916. CAssemblyRecoveryInfo::ClearExistingRegistryData()
  917. {
  918. if (SXS_AVOID_WRITING_REGISTRY)
  919. return TRUE;
  920. //
  921. // Do not be so eager to delete registry metadata, so that
  922. // an assembly for which refresh failed might succeed if another
  923. // file change comes in, or sfc /scannow.
  924. //
  925. // As well, if a replace-existing install fails, don't destroy
  926. // the metadata for previously successfully installed instances
  927. // of the same assembly.
  928. //
  929. const static struct
  930. {
  931. PCWSTR Data;
  932. SIZE_T Length;
  933. }
  934. DeletableValues[] =
  935. {
  936. #define ENTRY(x) { x, NUMBER_OF(x) - 1 }
  937. ENTRY(CSMD_TOPLEVEL_CATALOG),
  938. };
  939. #undef ENTRY
  940. static const PCWSTR DeletableKeys[] =
  941. {
  942. NULL,
  943. };
  944. FN_PROLOG_WIN32
  945. CFusionRegKey hkSingleAssemblyInfo;
  946. IFW32FALSE_EXIT(this->OpenInstallationSubKey(hkSingleAssemblyInfo, KEY_CREATE_SUB_KEY, KEY_WRITE | KEY_READ | FUSIONP_KEY_WOW64_64KEY));
  947. //
  948. // We need to delete the installation information for a single assembly - everything
  949. // this class owns.
  950. //
  951. if ( hkSingleAssemblyInfo != CFusionRegKey::GetInvalidValue() )
  952. {
  953. ULONG ul = 0;
  954. //
  955. // Clear values
  956. //
  957. for ( ul = 0; ul < NUMBER_OF(DeletableValues); ul++ )
  958. {
  959. DWORD dwWin32Error = NO_ERROR;
  960. IFW32FALSE_EXIT(
  961. hkSingleAssemblyInfo.DeleteValue(
  962. DeletableValues[ul].Data,
  963. dwWin32Error,
  964. 2,
  965. ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND));
  966. if (dwWin32Error == NO_ERROR
  967. && !m_fHadCatalog
  968. && ::FusionpEqualStrings(
  969. DeletableValues[ul].Data,
  970. DeletableValues[ul].Length,
  971. CSMD_TOPLEVEL_CATALOG,
  972. NUMBER_OF(CSMD_TOPLEVEL_CATALOG) - 1,
  973. FALSE
  974. ))
  975. {
  976. m_fHadCatalog = true;
  977. }
  978. }
  979. //
  980. // Delete eligible keys
  981. //
  982. for ( ul = 0; ul < NUMBER_OF(DeletableKeys); ul++ )
  983. {
  984. if (DeletableKeys[ul] != NULL && DeletableKeys[ul][0] != L'\0')
  985. {
  986. CFusionRegKey hkTempKey;
  987. IFW32FALSE_EXIT(hkSingleAssemblyInfo.OpenSubKey(hkTempKey, DeletableKeys[ul], KEY_WRITE, 0));
  988. if ( hkTempKey != CFusionRegKey::GetInvalidValue() )
  989. {
  990. IFW32FALSE_EXIT(hkTempKey.DestroyKeyTree());
  991. IFW32FALSE_EXIT(hkSingleAssemblyInfo.DeleteKey(DeletableKeys[ul]));
  992. }
  993. }
  994. }
  995. }
  996. FN_EPILOG
  997. }
  998. BOOL
  999. SxspLooksLikeAssemblyDirectoryName(
  1000. const CBaseStringBuffer &rsbSupposedAsmDirectoryName,
  1001. BOOL &rfLooksLikeAssemblyName
  1002. )
  1003. /*++
  1004. Most of this was copied directly from SxspParseAssemblyReference, which
  1005. is no longer valid, because it can't know how to turn the string back
  1006. into the actual assembly reference just based on the hash value and
  1007. public key of a string.
  1008. --*/
  1009. {
  1010. FN_PROLOG_WIN32
  1011. PCWSTR pszCursor = NULL;
  1012. PCWSTR wsNextBlock = NULL;
  1013. SIZE_T cchSegment = 0;
  1014. ASSEMBLY_VERSION Version;
  1015. const WCHAR UNDERSCORE = L'_';
  1016. bool fSyntaxValid = false;
  1017. bool fAttributeValid = false;
  1018. rfLooksLikeAssemblyName = FALSE;
  1019. pszCursor = rsbSupposedAsmDirectoryName;
  1020. //
  1021. // Processor architecture
  1022. //
  1023. if ((wsNextBlock = ::StringFindChar(pszCursor, UNDERSCORE)) == NULL)
  1024. FN_SUCCESSFUL_EXIT();
  1025. if ((cchSegment = (wsNextBlock - pszCursor)) == 0)
  1026. FN_SUCCESSFUL_EXIT();
  1027. IFW32FALSE_EXIT(::FusionpParseProcessorArchitecture(pszCursor, cchSegment, NULL, fAttributeValid));
  1028. if (!fAttributeValid)
  1029. FN_SUCCESSFUL_EXIT();
  1030. pszCursor = wsNextBlock + 1;
  1031. //
  1032. // Name
  1033. //
  1034. if ((wsNextBlock = StringFindChar(pszCursor, UNDERSCORE)) == NULL)
  1035. FN_SUCCESSFUL_EXIT();
  1036. if ((cchSegment = wsNextBlock - pszCursor) == 0)
  1037. FN_SUCCESSFUL_EXIT();
  1038. pszCursor = wsNextBlock + 1;
  1039. //
  1040. // Public key string
  1041. //
  1042. if ((wsNextBlock = StringFindChar(pszCursor, UNDERSCORE)) == NULL)
  1043. FN_SUCCESSFUL_EXIT();
  1044. if ((cchSegment = wsNextBlock - pszCursor) == 0)
  1045. FN_SUCCESSFUL_EXIT();
  1046. if ((::FusionpCompareStrings(
  1047. pszCursor,
  1048. cchSegment,
  1049. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_PUBLICKEY_MISSING_VALUE,
  1050. NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_PUBLICKEY_MISSING_VALUE) - 1,
  1051. true) == 0) ||
  1052. !::SxspIsFullHexString(pszCursor, cchSegment))
  1053. FN_SUCCESSFUL_EXIT();
  1054. pszCursor = wsNextBlock + 1;
  1055. //
  1056. // Version string
  1057. //
  1058. if ((wsNextBlock = StringFindChar(pszCursor, UNDERSCORE)) == NULL)
  1059. FN_SUCCESSFUL_EXIT();
  1060. if ((cchSegment = wsNextBlock - pszCursor) == 0)
  1061. FN_SUCCESSFUL_EXIT();
  1062. IFW32FALSE_EXIT(CFusionParser::ParseVersion(Version, pszCursor, cchSegment, fSyntaxValid));
  1063. if (!fSyntaxValid)
  1064. FN_SUCCESSFUL_EXIT();
  1065. pszCursor = wsNextBlock + 1;
  1066. //
  1067. // Language ID
  1068. //
  1069. if ((wsNextBlock = ::StringFindChar(pszCursor, UNDERSCORE)) == NULL)
  1070. FN_SUCCESSFUL_EXIT();
  1071. if ((cchSegment = wsNextBlock - pszCursor) == 0)
  1072. FN_SUCCESSFUL_EXIT();
  1073. //
  1074. // BUGBUG (jonwis) - It seems that langids are no longer four-character hex
  1075. // string representations of shorts anymore. All we're checking at the moment
  1076. // is to see that the string isn't blank. Is this the Right Thing?
  1077. //
  1078. pszCursor = wsNextBlock + 1;
  1079. //
  1080. // Last block should just be the hash
  1081. //
  1082. if (!::SxspIsFullHexString(pszCursor, ::wcslen(pszCursor)))
  1083. FN_SUCCESSFUL_EXIT();
  1084. // We ran the gauntlet; all the segments of the path look good, let's use it.
  1085. rfLooksLikeAssemblyName = TRUE;
  1086. FN_EPILOG
  1087. }