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.

2345 lines
81 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. sxsinstall.cpp
  5. Abstract:
  6. Installation support
  7. Author:
  8. Jay Krell (a-JayK, JayKrell) April 2000
  9. Revision History:
  10. --*/
  11. #include "stdinc.h"
  12. #include "sxsp.h"
  13. #include "nodefactory.h"
  14. #include "fusionarray.h"
  15. #include "sxsinstall.h"
  16. #include "sxspath.h"
  17. #include "recover.h"
  18. #include "cassemblyrecoveryinfo.h"
  19. #include "sxsexceptionhandling.h"
  20. #include "npapi.h"
  21. #include "util.h"
  22. #include "idp.h"
  23. #include "sxscabinet.h"
  24. #include "fusionprintf.h"
  25. #if DBG
  26. BOOL g_SxsOfflineInstall;
  27. #else
  28. #define g_SxsOfflineInstall FALSE
  29. #endif
  30. #define SXS_LANG_DEFAULT (MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) // "0x0409"
  31. BOOL
  32. WINAPI
  33. SxspInstallCallbackSetupCopyQueue(
  34. PSXS_INSTALLATION_FILE_COPY_CALLBACK_PARAMETERS
  35. );
  36. BOOL
  37. WINAPI
  38. SxspInstallCallbackSetupCopyQueueEx(
  39. PSXS_INSTALLATION_FILE_COPY_CALLBACK_PARAMETERS
  40. );
  41. CAssemblyInstall::CAssemblyInstall()
  42. :
  43. m_pInstallInfo(NULL),
  44. m_bSuccessfulSoFar(TRUE)
  45. {
  46. }
  47. BOOL
  48. CAssemblyInstall::BeginAssemblyInstall(
  49. DWORD dwManifestOperationFlags,
  50. PSXS_INSTALLATION_FILE_COPY_CALLBACK installationCallback,
  51. PVOID installationContext,
  52. const CImpersonationData &ImpersonationData
  53. )
  54. {
  55. BOOL fSuccess = FALSE;
  56. FN_TRACE_WIN32(fSuccess);
  57. PARAMETER_CHECK((installationCallback != NULL) || (installationContext == NULL));
  58. // check for the "built in" ones, translate from bogus PFN values (1, 2, etc.)
  59. // to real functions
  60. if (installationCallback == SXS_INSTALLATION_FILE_COPY_CALLBACK_SETUP_COPY_QUEUE)
  61. {
  62. PARAMETER_CHECK(installationContext != NULL);
  63. installationCallback = SxspInstallCallbackSetupCopyQueue;
  64. // we can't verify that this is a valid setup copy queue..
  65. }
  66. else if (installationCallback == SXS_INSTALLATION_FILE_COPY_CALLBACK_SETUP_COPY_QUEUE_EX)
  67. {
  68. PCSXS_INSTALLATION_SETUP_COPY_QUEUE_EX_PARAMETERS typedContext =
  69. reinterpret_cast<PCSXS_INSTALLATION_SETUP_COPY_QUEUE_EX_PARAMETERS>(installationContext);
  70. PARAMETER_CHECK(installationContext != NULL);
  71. PARAMETER_CHECK(typedContext->cbSize >= sizeof(SXS_INSTALLATION_SETUP_COPY_QUEUE_EX_PARAMETERS));
  72. installationCallback = SxspInstallCallbackSetupCopyQueueEx;
  73. }
  74. m_ImpersonationData = ImpersonationData;
  75. IFW32FALSE_EXIT(
  76. ::SxspInitActCtxGenCtx(
  77. &m_ActCtxGenCtx, // context out
  78. MANIFEST_OPERATION_INSTALL,
  79. 0,
  80. dwManifestOperationFlags,
  81. ImpersonationData,
  82. 0, // processor architecture
  83. //0 // langid
  84. SXS_LANG_DEFAULT, // langid "0x0409"
  85. ACTIVATION_CONTEXT_PATH_TYPE_NONE,
  86. 0,
  87. NULL));
  88. //
  89. // Oh where oh where did our call-back go? Oh where, oh where could it be?
  90. //
  91. m_ActCtxGenCtx.m_InstallationContext.Callback = installationCallback;
  92. m_ActCtxGenCtx.m_InstallationContext.Context = installationContext;
  93. fSuccess = TRUE;
  94. Exit:
  95. m_bSuccessfulSoFar = m_bSuccessfulSoFar && fSuccess;
  96. return fSuccess;
  97. }
  98. class CInstallDirectoryDirWalkContext
  99. {
  100. public:
  101. CAssemblyInstall* m_pThis;
  102. DWORD m_dwManifestOperationFlags;
  103. };
  104. CDirWalk::ECallbackResult
  105. CAssemblyInstall::InstallDirectoryDirWalkCallback(
  106. CDirWalk::ECallbackReason reason,
  107. CDirWalk* dirWalk,
  108. DWORD dwManifestOperationFlags,
  109. DWORD dwWalkDirFlags
  110. )
  111. {
  112. #if DBG
  113. #define SET_LINE() Line = __LINE__
  114. ULONG Line = __LINE__;
  115. #else
  116. #define SET_LINE() /* nothing */
  117. #endif
  118. CDirWalk::ECallbackResult result = CDirWalk::eKeepWalking;
  119. //
  120. // We short circuit more code by doing this up front rather
  121. // waiting for a directory notification; it'd be even quicker
  122. // if we could seed the value in CDirWalk, but we can't.
  123. //
  124. // actually, what we could do is turn off all file walking
  125. // by returning eStopWalkingFiles at every directory notification,
  126. // and and at each directory notification, try the exactly three
  127. // file names we accept
  128. //
  129. if ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE) == 0)
  130. {
  131. result = CDirWalk::eStopWalkingDirectories;
  132. }
  133. if (reason == CDirWalk::eBeginDirectory)
  134. {
  135. // Prepend a / only if the current path is non-blank - otherwise, just prepend the
  136. // path element.
  137. if (m_buffCodebaseRelativePath.Cch() != 0)
  138. {
  139. if (!m_buffCodebaseRelativePath.Win32Append(m_wchCodebasePathSeparator))
  140. {
  141. TRACE_WIN32_FAILURE(m_buffCodebaseRelativePath.Win32Append);
  142. SET_LINE();
  143. goto Error;
  144. }
  145. }
  146. if (!m_buffCodebaseRelativePath.Win32Append(dirWalk->m_strLastObjectFound))
  147. {
  148. TRACE_WIN32_FAILURE(m_buffCodebaseRelativePath.Win32Append);
  149. SET_LINE();
  150. goto Error;
  151. }
  152. }
  153. else if (reason == CDirWalk::eFile)
  154. {
  155. //
  156. // the manifest must be in a file whose base name matches its
  157. // directory's base name, otherwise ignore it and keep going
  158. //
  159. // inefficient, but reusing code.
  160. // check whether this is a catalog file, if so, we would not install it
  161. {
  162. PWSTR p = wcsrchr(dirWalk->m_strLastObjectFound, L'.');
  163. if (p != NULL)
  164. {
  165. SIZE_T x = ::wcslen(p);
  166. if (::FusionpCompareStrings(p, x, (x == 4)? L".cat" : L".catalog", (x == 4)? 4 : 8, true) == 0)
  167. {
  168. SET_LINE();
  169. goto Exit;
  170. }
  171. }
  172. }
  173. {
  174. CFullPathSplitPointers splitParent;
  175. CFullPathSplitPointers splitChild;
  176. CSmallStringBuffer child;
  177. CSmallStringBuffer buffChildCodebase;
  178. //
  179. // OS installations get some special treatment.
  180. //
  181. if ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_OSSETUP) && (!(dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_MIGRATION)))
  182. {
  183. CSmallStringBuffer buffParentWorker;
  184. CSmallStringBuffer buffChunklet;
  185. //
  186. // If this is an OS-installation, then we need the last two bits of
  187. // the parent path. So if we were walking "C:\$win_nt$.~ls\i386\asms", we need
  188. // the "i386\asms" part out of that. So we'll generate this differently.
  189. //
  190. if (!buffParentWorker.Win32Assign(dirWalk->m_strParent, dirWalk->m_cchOriginalPath))
  191. {
  192. SET_LINE();
  193. goto Error;
  194. }
  195. if (!buffParentWorker.Win32RemoveTrailingPathSeparators())
  196. {
  197. SET_LINE();
  198. goto Error;
  199. }
  200. //
  201. // For now, take at most the last two items off the thing.
  202. //
  203. for ( ULONG ulItems = 0; (ulItems < 2) && (buffParentWorker.Cch() > 0); ulItems++ )
  204. {
  205. CSmallStringBuffer buffChunklet;
  206. if (( ulItems != 0 ) && (!buffChildCodebase.Win32Prepend(m_wchCodebasePathSeparator)))
  207. {
  208. SET_LINE();
  209. goto Error;
  210. }
  211. if (!buffParentWorker.Win32GetLastPathElement(buffChunklet))
  212. {
  213. SET_LINE();
  214. goto Error;
  215. }
  216. if (!buffChildCodebase.Win32Prepend(buffChunklet))
  217. {
  218. SET_LINE();
  219. goto Error;
  220. }
  221. if (!buffParentWorker.Win32RemoveLastPathElement())
  222. {
  223. SET_LINE();
  224. goto Error;
  225. }
  226. }
  227. if (!buffChildCodebase.Win32Append(m_wchCodebasePathSeparator))
  228. {
  229. SET_LINE();
  230. goto Exit;
  231. }
  232. if (!buffChildCodebase.Win32Append(m_buffCodebaseRelativePath))
  233. {
  234. SET_LINE();
  235. goto Exit;
  236. }
  237. }
  238. else
  239. {
  240. if (!buffChildCodebase.Win32Assign(m_buffCodebaseRelativePath))
  241. {
  242. SET_LINE();
  243. goto Error;
  244. }
  245. }
  246. if (!buffChildCodebase.Win32Append(m_wchCodebasePathSeparator))
  247. {
  248. SET_LINE();
  249. goto Error;
  250. }
  251. if (!buffChildCodebase.Win32Append(dirWalk->m_strLastObjectFound))
  252. {
  253. SET_LINE();
  254. goto Error;
  255. }
  256. if (!child.Win32Assign(dirWalk->m_strParent))
  257. {
  258. SET_LINE();
  259. goto Error;
  260. }
  261. if (!child.Win32AppendPathElement(dirWalk->m_strLastObjectFound))
  262. {
  263. SET_LINE();
  264. goto Error;
  265. }
  266. if (!splitParent.Initialize(dirWalk->m_strParent))
  267. {
  268. SET_LINE();
  269. goto Error;
  270. }
  271. if (!splitChild.Initialize(child))
  272. {
  273. SET_LINE();
  274. goto Error;
  275. }
  276. //
  277. // Note - we can't just compare bases, as the 'base' of the directory
  278. // path "c:\foo\bar.bas" is "bar", while the base of the file
  279. // "c:\foo\bar.bas\bar.bas.man" is "bar.bas" So, we need to compare
  280. // the 'name' parent path (foo.bar) with the base of the child path
  281. // (foo.bar)
  282. //
  283. if (!::FusionpEqualStrings(
  284. splitChild.m_base,
  285. splitChild.m_baseEnd - splitChild.m_base,
  286. splitParent.m_name,
  287. StringLength(splitParent.m_name),
  288. true))
  289. {
  290. SET_LINE();
  291. goto Exit;
  292. }
  293. ::FusionpDbgPrintEx(
  294. FUSION_DBG_LEVEL_INSTALLATION,
  295. "SXS.DLL: Installing file \"%S\"\n", static_cast<PCWSTR>(child));
  296. if (!this->InstallFile(child, buffChildCodebase))
  297. {
  298. ::FusionpDbgPrintEx(
  299. FUSION_DBG_LEVEL_SETUPLOG,
  300. "Failed to install assembly from manifest: \"%S\"; Win32 Error Code = %lu\n", static_cast<PCWSTR>(child), ::GetLastError());
  301. //
  302. // If it was .man or .manifest, then it must be a manifest else error.
  303. //
  304. // If it was .dll, well, arbitrary .dlls don't necessarily contain
  305. // manifests, but we already look for .man and .manifest and this
  306. // .dll's base name matches its directory's name, so this is also
  307. // an error.
  308. //
  309. result = CDirWalk::eError;
  310. SET_LINE();
  311. goto Exit;
  312. }
  313. }
  314. //
  315. // we have a manifest in this directory, don't look for any manifests
  316. // in this directory or any of its children
  317. //
  318. // if we want to enforce one manifest per directory, then we'd have
  319. // to keep walking, or actually do a two pass in order to not install
  320. // when we would error later
  321. //
  322. result = (CDirWalk::eStopWalkingFiles | CDirWalk::eStopWalkingDirectories);
  323. SET_LINE();
  324. goto Exit;
  325. }
  326. else if (reason == CDirWalk::eEndDirectory)
  327. {
  328. // Trim back to the previous codebase path separator...
  329. PCWSTR pszPathSeparator = wcsrchr(m_buffCodebaseRelativePath, m_wchCodebasePathSeparator);
  330. if (pszPathSeparator != NULL)
  331. m_buffCodebaseRelativePath.Left(pszPathSeparator - m_buffCodebaseRelativePath);
  332. else
  333. { // It's just one path element.
  334. m_buffCodebaseRelativePath.Clear();
  335. }
  336. //
  337. // find at least one file under the dir, however, no manifest available, this is an error case
  338. //
  339. if (((dwWalkDirFlags & SXSP_DIR_WALK_FLAGS_FIND_AT_LEAST_ONE_FILEUNDER_CURRENTDIR) != 0) &&
  340. ((dwWalkDirFlags & SXSP_DIR_WALK_FLAGS_INSTALL_ASSEMBLY_UNDER_CURRECTDIR_SUCCEED) == 0))
  341. {
  342. ::FusionpLogError(
  343. MSG_SXS_MANIFEST_MISSING_DURING_SETUP,
  344. CEventLogString(dirWalk->m_strParent)); // this would log error to Setup.log if it is during setup
  345. SET_LINE();
  346. result |= CDirWalk::eError;
  347. }
  348. }
  349. #if DBG
  350. if (Line == 0)
  351. SET_LINE();
  352. #endif
  353. Exit:
  354. #if DBG
  355. if ((result & CDirWalk::eError) != 0)
  356. {
  357. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "%s(%lu): %s\n", __FILE__, Line, __FUNCTION__);
  358. }
  359. #endif
  360. return result;
  361. Error:
  362. result = CDirWalk::eError;
  363. goto Exit;
  364. #undef SET_LINE
  365. }
  366. CDirWalk::ECallbackResult
  367. CAssemblyInstall::StaticInstallDirectoryDirWalkCallback(
  368. CDirWalk::ECallbackReason reason,
  369. CDirWalk* dirWalk,
  370. DWORD dwWalkDirFlags
  371. )
  372. {
  373. FN_TRACE();
  374. ASSERT(dirWalk != NULL);
  375. CInstallDirectoryDirWalkContext* context = reinterpret_cast<CInstallDirectoryDirWalkContext*>(dirWalk->m_context);
  376. CDirWalk::ECallbackResult result = context->m_pThis->InstallDirectoryDirWalkCallback(reason, dirWalk, context->m_dwManifestOperationFlags, dwWalkDirFlags);
  377. return result;
  378. }
  379. BOOL
  380. CAssemblyInstall::InstallDirectory(
  381. const CBaseStringBuffer &rbuffPath,
  382. DWORD dwFlags,
  383. WCHAR wchCodebasePathSeparator
  384. )
  385. {
  386. /*
  387. NTRAID#NTBUG9-591148-2002/03/31-JayKrell
  388. This function can recurse indefinitely, running out of stack and crashing,
  389. including in msiexec.exe. Is this ok?
  390. */
  391. FN_PROLOG_WIN32
  392. #define COMMA ,
  393. const static PCWSTR filters[] = {L"*" INSTALL_MANIFEST_FILE_NAME_SUFFIXES(COMMA L"*") };
  394. #undef COMMA
  395. CDirWalk dirWalk;
  396. CInstallDirectoryDirWalkContext context = { this, dwFlags };
  397. m_wchCodebasePathSeparator = wchCodebasePathSeparator;
  398. m_buffCodebaseRelativePath.Clear();
  399. dirWalk.m_fileFiltersBegin = filters;
  400. dirWalk.m_fileFiltersEnd = filters + NUMBER_OF(filters);
  401. dirWalk.m_context = &context;
  402. dirWalk.m_callback = StaticInstallDirectoryDirWalkCallback;
  403. IFW32FALSE_EXIT(dirWalk.m_strParent.Win32Assign(rbuffPath));
  404. IFW32FALSE_EXIT(dirWalk.m_strParent.Win32RemoveTrailingPathSeparators());
  405. IFW32FALSE_EXIT(dirWalk.Walk());
  406. FN_EPILOG
  407. }
  408. BOOL
  409. SxspGenerateInstallationInfo(
  410. IN OUT CAssemblyRecoveryInfo &rRecovery,
  411. IN const CBaseStringBuffer &rbuffManifestSourcePath,
  412. IN const CBaseStringBuffer &rbuffRelativeCodebasePath,
  413. IN PCSXS_INSTALL_SOURCE_INFO pInstallInfo,
  414. IN PCWSTR pcwszAssemblyRoot,
  415. IN SIZE_T cchAssemblyRoot,
  416. IN const ASSEMBLY *pAssemblyInfo,
  417. OUT CCodebaseInformation &rCodebaseInfo
  418. )
  419. {
  420. FN_PROLOG_WIN32
  421. BOOL fHasCatalog = FALSE;
  422. CSmallStringBuffer buffAssemblyDirName;
  423. CSmallStringBuffer buffFinalCodebase;
  424. CSmallStringBuffer buffFilePath;
  425. BOOL fIsPolicy = FALSE;
  426. BOOL fInstalledbySetup = FALSE;
  427. SxsWFPResolveCodebase CodebaseType = CODEBASE_RESOLVED_URLHEAD_UNKNOWN;
  428. PARAMETER_CHECK(pInstallInfo != NULL);
  429. // We either need a codebase or this had better be a darwin install
  430. PARAMETER_CHECK(
  431. ((pInstallInfo->dwFlags & SXSINSTALLSOURCE_HAS_CODEBASE) != 0) ||
  432. ((pInstallInfo->dwFlags & SXSINSTALLSOURCE_INSTALL_BY_DARWIN) != 0));
  433. PARAMETER_CHECK(pAssemblyInfo != NULL);
  434. IFW32FALSE_EXIT(rCodebaseInfo.Initialize());
  435. //
  436. // None of the installation context information actually contains the
  437. // unparsed name of the assembly. As such, we re-generate the installation
  438. // path and then use it later.
  439. //
  440. IFW32FALSE_EXIT(::SxspDetermineAssemblyType(pAssemblyInfo->GetAssemblyIdentity(), fIsPolicy));
  441. // x86_policy.1.0.dynamicdll_b54bc117ce08a1e8_en-us_b74d3d95 (w/o version) or
  442. // x86_dynamicdll_b54bc117ce08a1e8_1.1.0.0_en-us_d51541cb (w version)
  443. IFW32FALSE_EXIT(
  444. ::SxspGenerateSxsPath(
  445. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT | (fIsPolicy ? SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION : 0),
  446. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
  447. pcwszAssemblyRoot,
  448. cchAssemblyRoot,
  449. pAssemblyInfo->GetAssemblyIdentity(),
  450. NULL,
  451. buffAssemblyDirName));
  452. //
  453. // Blindly add this registration information to the registry. We really should
  454. // try to validate that it's a valid manifest/catalog pair (with strong name
  455. // and everything) before doing this, but it's happened several times before
  456. // (in theory) if we're being called during setup. Since setup/install are our
  457. // only clients as of yet, we can be reasonably sure that there won't be a
  458. // "rogue" call through here to install bogus assembly information.
  459. //
  460. fHasCatalog = ((pInstallInfo->dwFlags & SXSINSTALLSOURCE_HAS_CATALOG) != 0);
  461. if ((pInstallInfo->dwFlags & SXSINSTALLSOURCE_HAS_CODEBASE) != 0)
  462. {
  463. IFW32FALSE_EXIT(buffFinalCodebase.Win32Assign(pInstallInfo->pcwszCodebaseName, ::wcslen(pInstallInfo->pcwszCodebaseName)));
  464. if (!g_SxsOfflineInstall)
  465. {
  466. IFW32FALSE_EXIT(buffFinalCodebase.Win32Append(rbuffRelativeCodebasePath));
  467. }
  468. }
  469. if (buffFinalCodebase.Cch() == 0)
  470. {
  471. // eg: darwin, for which we don't write codebases to the registry
  472. CodebaseType = CODEBASE_RESOLVED_URLHEAD_UNKNOWN;
  473. }
  474. else
  475. {
  476. IFW32FALSE_EXIT(::SxspDetermineCodebaseType(buffFinalCodebase, CodebaseType, &buffFilePath));
  477. }
  478. // If this is a file-ish codebase, let's abstract it (e.g. replace cdrom drive info with cdrom: URL,
  479. // turn mapped drive letters into UNC paths.
  480. if (CodebaseType == CODEBASE_RESOLVED_URLHEAD_FILE)
  481. {
  482. //
  483. // Now, let's intuit the type of stuff we're supposed to be putting in the
  484. // registry based on the input path.
  485. //
  486. UINT uiDriveType = 0;
  487. CSmallStringBuffer buffDriveRoot;
  488. CSmallStringBuffer buffFullManifestSourcePath;
  489. // Convert the source path to a full path (in case it isn't) so that we can use the length of
  490. // the found volume root as an index into the full manifest source path.
  491. IFW32FALSE_EXIT(::SxspGetFullPathName(rbuffManifestSourcePath, buffFullManifestSourcePath, NULL));
  492. IFW32FALSE_EXIT(::SxspGetVolumePathName(0, buffFullManifestSourcePath, buffDriveRoot));
  493. uiDriveType = ::GetDriveTypeW(buffDriveRoot);
  494. ::FusionpDbgPrintEx(
  495. FUSION_DBG_LEVEL_INSTALLATION,
  496. "SXS: %s - Decided that drive for path \"%ls\" was \"%ls\" and type is %u\n",
  497. __FUNCTION__,
  498. static_cast<PCWSTR>(rbuffManifestSourcePath),
  499. static_cast<PCWSTR>(buffDriveRoot),
  500. uiDriveType);
  501. if (uiDriveType == DRIVE_CDROM)
  502. {
  503. // Neat, there's a good amount of work we have to do to get this up and
  504. // working... In the interest of not blowing stack with really long buffers
  505. // here (or CStringBuffer objects), this is a heap-allocated string buffer.
  506. // Before you complain about heap usage, this path is /rarely/ ever hit.
  507. CSmartArrayPtr<WCHAR> pcwszVolumeName;
  508. const DWORD dwPathChars = MAX_PATH * 2;
  509. PCWSTR pszPostVolumeRootPath = NULL;
  510. // Find the name of the media
  511. IFW32FALSE_EXIT(pcwszVolumeName.Win32Allocate(dwPathChars, __FILE__, __LINE__));
  512. IFW32FALSE_ORIGINATE_AND_EXIT(
  513. ::GetVolumeInformationW(
  514. buffDriveRoot,
  515. pcwszVolumeName,
  516. dwPathChars,
  517. NULL,
  518. NULL,
  519. NULL,
  520. NULL,
  521. 0));
  522. pszPostVolumeRootPath = static_cast<PCWSTR>(buffFullManifestSourcePath) + buffDriveRoot.Cch();
  523. // construct the cdrom: URL...
  524. IFW32FALSE_EXIT(
  525. buffFinalCodebase.Win32AssignW(
  526. 6,
  527. URLHEAD_CDROM, URLHEAD_LENGTH_CDROM, // cdrom:
  528. URLHEAD_CDROM_TYPE_VOLUMENAME, URLHEAD_LENGTH_CDROM_TYPE_VOLUMENAME, // volumename
  529. L"/", 1, // /
  530. static_cast<PCWSTR>(pcwszVolumeName), static_cast<int>((pcwszVolumeName != NULL) ? ::wcslen(pcwszVolumeName) : 0), // <volume-name>
  531. L"/", 1, // /
  532. pszPostVolumeRootPath, static_cast<int>(::wcslen(pszPostVolumeRootPath)))); // <rest-of-path>
  533. // e.g. cdrom:name/AOE/aoesetup.exe
  534. }
  535. else if (uiDriveType == DRIVE_UNKNOWN)
  536. {
  537. ORIGINATE_WIN32_FAILURE_AND_EXIT(GetDriveTypeW, ERROR_BAD_PATHNAME);
  538. }
  539. else if (uiDriveType == DRIVE_REMOTE)
  540. {
  541. //
  542. // If this is a UNC path, then use it.
  543. //
  544. if (::SxspDetermineDosPathNameType(rbuffManifestSourcePath) == RtlPathTypeUncAbsolute)
  545. {
  546. IFW32FALSE_EXIT(buffFinalCodebase.Win32Assign(rbuffManifestSourcePath));
  547. }
  548. else
  549. {
  550. // This is a remote drive - figure out what the path was to get connected,
  551. // the put that into the buffFinalCodebase thing
  552. IFW32FALSE_EXIT(
  553. ::SxspGetRemoteUniversalName(
  554. rbuffManifestSourcePath,
  555. buffFinalCodebase));
  556. }
  557. }
  558. }
  559. //
  560. // Now let's fill out the recovery information object
  561. //
  562. IFW32FALSE_EXIT(rRecovery.SetAssemblyIdentity(pAssemblyInfo->GetAssemblyIdentity()));
  563. if ((pInstallInfo->dwFlags & SXSINSTALLSOURCE_HAS_PROMPT) != 0)
  564. {
  565. if (pInstallInfo->pcwszPromptOnRefresh != NULL)
  566. IFW32FALSE_EXIT(rCodebaseInfo.SetPromptText(
  567. pInstallInfo->pcwszPromptOnRefresh,
  568. ::wcslen(pInstallInfo->pcwszPromptOnRefresh)));
  569. }
  570. IFW32FALSE_EXIT(rCodebaseInfo.SetCodebase(buffFinalCodebase));
  571. FN_EPILOG
  572. }
  573. BOOL
  574. CAssemblyInstall::InstallFile(
  575. const CBaseStringBuffer &rManifestPath,
  576. const CBaseStringBuffer &rRelativeCodebasePath
  577. )
  578. {
  579. BOOL fSuccess = FALSE;
  580. FN_TRACE_WIN32(fSuccess);
  581. PASSEMBLY Asm = NULL;
  582. CInstalledItemEntry CurrentInstallEntry;
  583. const DWORD &dwManifestOperationFlags = m_ActCtxGenCtx.m_ManifestOperationFlags;
  584. IFALLOCFAILED_EXIT(Asm = new ASSEMBLY);
  585. //
  586. // refresh means wfp is doing a recovery..don't muck with the registry..and
  587. // also no logfile..this is expedient..and possibly proper.
  588. //
  589. if ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REFRESH) == 0)
  590. {
  591. IFW32FALSE_EXIT(CurrentInstallEntry.m_RecoveryInfo.Initialize());
  592. IFW32FALSE_EXIT(CurrentInstallEntry.m_RecoveryInfo.GetCodeBaseList().Win32SetSize(1)); // ??
  593. m_ActCtxGenCtx.m_InstallationContext.SecurityMetaData = &CurrentInstallEntry.m_RecoveryInfo.GetSecurityInformation();
  594. }
  595. //
  596. // The main code deals with the paths that the assembly is
  597. // being installed from, not where it is being installed to.
  598. //
  599. {
  600. CProbedAssemblyInformation AssemblyInfo;
  601. IFW32FALSE_EXIT(AssemblyInfo.Initialize(&m_ActCtxGenCtx));
  602. IFW32FALSE_EXIT(AssemblyInfo.SetManifestPath(ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, rManifestPath));
  603. IFW32FALSE_EXIT(AssemblyInfo.SetManifestLastWriteTime(m_ImpersonationData));
  604. IFW32FALSE_EXIT(AssemblyInfo.SetManifestFlags(ASSEMBLY_MANIFEST_FILETYPE_AUTO_DETECT));
  605. IFW32FALSE_EXIT(::SxspInitAssembly(Asm, AssemblyInfo));
  606. }
  607. IFW32FALSE_EXIT(::SxspIncorporateAssembly(&m_ActCtxGenCtx, Asm));
  608. //
  609. // refresh means wfp is doing a recovery..don't muck with the registry..and
  610. // also no logfile..this is expedient..and possibly proper.
  611. //
  612. if ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REFRESH) == 0)
  613. {
  614. //
  615. // Track the installation data for this assembly
  616. //
  617. IFW32FALSE_EXIT(
  618. ::SxspGenerateInstallationInfo(
  619. CurrentInstallEntry.m_RecoveryInfo,
  620. rManifestPath,
  621. rRelativeCodebasePath,
  622. m_pInstallInfo,
  623. m_ActCtxGenCtx.m_AssemblyRootDirectoryBuffer,
  624. m_ActCtxGenCtx.m_AssemblyRootDirectoryBuffer.Cch(),
  625. Asm,
  626. CurrentInstallEntry.m_CodebaseInfo));
  627. CurrentInstallEntry.m_dwValidItems |= CINSTALLITEM_VALID_RECOVERY;
  628. //
  629. // Track the installation reference for this assembly
  630. //
  631. if ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REFERENCE_VALID) != 0)
  632. {
  633. IFW32FALSE_EXIT(CurrentInstallEntry.m_InstallReference.Initialize(
  634. static_cast<PCSXS_INSTALL_REFERENCEW>(m_ActCtxGenCtx.m_InstallationContext.InstallReferenceData)));
  635. IFW32FALSE_EXIT(CurrentInstallEntry.m_InstallReference.SetIdentity(Asm->GetAssemblyIdentity()));
  636. CurrentInstallEntry.m_CodebaseInfo.SetReference(CurrentInstallEntry.m_InstallReference.GetGeneratedIdentifier());
  637. CurrentInstallEntry.m_dwValidItems |= CINSTALLITEM_VALID_REFERENCE;
  638. }
  639. //
  640. // Track the identity that was incorporated
  641. //
  642. INTERNAL_ERROR_CHECK(CurrentInstallEntry.m_AssemblyIdentity == NULL);
  643. IFW32FALSE_EXIT(::SxsDuplicateAssemblyIdentity(
  644. 0,
  645. Asm->GetAssemblyIdentity(),
  646. &CurrentInstallEntry.m_AssemblyIdentity));
  647. CurrentInstallEntry.m_dwValidItems |= CINSTALLITEM_VALID_IDENTITY;
  648. //
  649. // And, if we're logfiling..
  650. //
  651. if ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_CREATE_LOGFILE) != 0)
  652. {
  653. IFW32FALSE_EXIT(CurrentInstallEntry.m_buffLogFileName.Win32Assign(
  654. m_pInstallInfo->pcwszLogFileName,
  655. m_pInstallInfo->pcwszLogFileName != NULL ? ::wcslen(m_pInstallInfo->pcwszLogFileName) : 0));
  656. CurrentInstallEntry.m_dwValidItems |= CINSTALLITEM_VALID_LOGFILE;
  657. }
  658. IFW32FALSE_EXIT(m_ItemsInstalled.Win32Append(CurrentInstallEntry));
  659. }
  660. fSuccess = TRUE;
  661. Exit:
  662. // We delete the ASSEMBLY here regardless of success vs. failure; the incorporate call above
  663. // does not actually add the PASSEMBLY to the list of assemblies associated with the activation
  664. // context. [mgrier 8/9/2000]
  665. if (Asm != NULL)
  666. {
  667. CSxsPreserveLastError ple;
  668. Asm->Release();
  669. ple.Restore();
  670. }
  671. return fSuccess;
  672. }
  673. BOOL
  674. CAssemblyInstall::InstallAssembly(
  675. DWORD dwManifestOperationFlags,
  676. PCWSTR ManifestPath,
  677. PCSXS_INSTALL_SOURCE_INFO pInstallSourceInfo,
  678. PCSXS_INSTALL_REFERENCEW pvReference
  679. )
  680. {
  681. BOOL fSuccess = FALSE;
  682. FN_TRACE_WIN32(fSuccess);
  683. DWORD dwManifestOperationFlags_Saved = m_ActCtxGenCtx.m_ManifestOperationFlags;
  684. CSmallStringBuffer strPath;
  685. RTL_PATH_TYPE ManifestPathType = static_cast<RTL_PATH_TYPE>(0);
  686. BOOL fAreWeInSetupMode = FALSE;
  687. const WCHAR wchCodebasePathSeparator = L'/';
  688. IFW32FALSE_EXIT(::FusionpAreWeInOSSetupMode(&fAreWeInSetupMode));
  689. ::FusionpDbgPrintEx(
  690. FUSION_DBG_LEVEL_INSTALLATION,
  691. "SXS.DLL: %s()\n"
  692. " dwManifestOperationFlags = 0x%08lx\n"
  693. " ManifestPath = \"%S\"\n"
  694. " pInstallSourceInfo = %p\n",
  695. __FUNCTION__,
  696. dwManifestOperationFlags,
  697. ManifestPath,
  698. pInstallSourceInfo);
  699. PARAMETER_CHECK(ManifestPath != NULL);
  700. PARAMETER_CHECK(ManifestPath[0] != L'\0');
  701. PARAMETER_CHECK(
  702. (pInstallSourceInfo == NULL) ||
  703. ((dwManifestOperationFlags &
  704. (MANIFEST_OPERATION_INSTALL_FLAG_INCLUDE_CODEBASE |
  705. MANIFEST_OPERATION_INSTALL_FLAG_CREATE_LOGFILE |
  706. MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_DARWIN |
  707. MANIFEST_OPERATION_INSTALL_FLAG_REFRESH |
  708. MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_OSSETUP |
  709. MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_MIGRATION |
  710. MANIFEST_OPERATION_INSTALL_FLAG_FORCE_LOOK_FOR_CATALOG |
  711. MANIFEST_OPERATION_INSTALL_FLAG_REFERENCE_VALID)) != 0));
  712. PARAMETER_CHECK((dwManifestOperationFlags &
  713. (MANIFEST_OPERATION_INSTALL_FLAG_ABORT |
  714. MANIFEST_OPERATION_INSTALL_FLAG_COMMIT)) == 0);
  715. PARAMETER_CHECK(
  716. ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_CREATE_LOGFILE) == 0) ||
  717. (pInstallSourceInfo != NULL));
  718. ManifestPathType = ::SxspDetermineDosPathNameType(ManifestPath);
  719. PARAMETER_CHECK(
  720. (ManifestPathType == RtlPathTypeUncAbsolute) ||
  721. (ManifestPathType == RtlPathTypeLocalDevice) ||
  722. (ManifestPathType == RtlPathTypeDriveAbsolute) ||
  723. (ManifestPathType == RtlPathTypeDriveRelative) ||
  724. (ManifestPathType == RtlPathTypeRelative));
  725. m_ActCtxGenCtx.m_ManifestOperationFlags |= dwManifestOperationFlags;
  726. //
  727. // Expand the input path to a full path that we can use later.
  728. //
  729. IFW32FALSE_EXIT(::SxspExpandRelativePathToFull(ManifestPath, ::wcslen(ManifestPath), strPath));
  730. if (m_ActCtxGenCtx.m_ManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_ABORT)
  731. FN_SUCCESSFUL_EXIT();
  732. DWORD dwFileAttributes;
  733. IFW32FALSE_EXIT(::SxspGetFileAttributesW(strPath, dwFileAttributes));
  734. // They can only ask for directory based installation iff the path they pass
  735. // in is a directory
  736. PARAMETER_CHECK(
  737. ((dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  738. ==
  739. ((dwManifestOperationFlags &
  740. (MANIFEST_OPERATION_INSTALL_FLAG_FROM_DIRECTORY |
  741. MANIFEST_OPERATION_INSTALL_FLAG_FROM_CABINET |
  742. MANIFEST_OPERATION_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE)) != 0));
  743. //
  744. // If we're expecting to create a logfile, or we want to specify where this
  745. // assembly can be reloaded from, you'll need to tell us that in the operation
  746. // flags.
  747. //
  748. if (dwManifestOperationFlags & (MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_DARWIN | MANIFEST_OPERATION_INSTALL_FLAG_CREATE_LOGFILE | MANIFEST_OPERATION_INSTALL_FLAG_INCLUDE_CODEBASE))
  749. {
  750. //
  751. // Constness protection: Copy the data to our own structure, then pass along
  752. // the pointer to ourselves rather than the caller's
  753. //
  754. m_CurrentInstallInfoCopy = *pInstallSourceInfo;
  755. m_pInstallInfo = &m_CurrentInstallInfoCopy;
  756. m_ActCtxGenCtx.m_InstallationContext.InstallSource = m_pInstallInfo;
  757. //
  758. // So is wanting to create a logfile and not actively telling us where to
  759. // put it.
  760. //
  761. if (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_CREATE_LOGFILE)
  762. {
  763. PARAMETER_CHECK(m_pInstallInfo->pcwszLogFileName);
  764. }
  765. #if DBG
  766. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_INSTALLATION,
  767. "SXS.DLL: %s - m_pInstallInfo->dwFlags : 0x%lx\n",
  768. __FUNCTION__, m_pInstallInfo->dwFlags);
  769. #endif
  770. }
  771. if (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REFERENCE_VALID)
  772. {
  773. PARAMETER_CHECK(pvReference->dwFlags == 0);
  774. PARAMETER_CHECK(pvReference->cbSize >= sizeof(SXS_INSTALL_REFERENCEW));
  775. PARAMETER_CHECK(
  776. (pvReference->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL) ||
  777. (pvReference->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING) ||
  778. (pvReference->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_UNINSTALLKEY) ||
  779. (pvReference->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_KEYFILE) ||
  780. (pvReference->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_SXS_INSTALL_ASSEMBLY));
  781. //
  782. // OS-setup scheme is only valid if we're really doing setup.
  783. //
  784. PARAMETER_CHECK((pvReference->guidScheme != SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL)
  785. || fAreWeInSetupMode);
  786. if ( (pvReference->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL) ||
  787. (pvReference->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_SXS_INSTALL_ASSEMBLY))
  788. {
  789. PARAMETER_CHECK(pvReference->lpIdentifier == NULL);
  790. }
  791. else
  792. {
  793. PARAMETER_CHECK((pvReference->lpIdentifier != NULL) && (pvReference->lpIdentifier[0] != UNICODE_NULL));
  794. }
  795. m_ActCtxGenCtx.m_InstallationContext.InstallReferenceData = pvReference;
  796. }
  797. else
  798. m_ActCtxGenCtx.m_InstallationContext.InstallReferenceData = NULL;
  799. if ((dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  800. {
  801. if (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_FROM_CABINET)
  802. {
  803. //
  804. // This does all the work to do the installation
  805. //
  806. IFW32FALSE_EXIT(SxspInstallAsmsDotCabEtAl(
  807. 0,
  808. *this,
  809. strPath,
  810. NULL));
  811. }
  812. else
  813. {
  814. IFW32FALSE_EXIT(strPath.Win32EnsureTrailingPathSeparator());
  815. ::FusionpDbgPrintEx(
  816. FUSION_DBG_LEVEL_INSTALLATION,
  817. "SXS: Installing directory \"%S\" (installation flags: 0x%08lx)\n",
  818. static_cast<PCWSTR>(strPath),
  819. m_ActCtxGenCtx.m_ManifestOperationFlags);
  820. IFW32FALSE_EXIT(this->InstallDirectory(strPath, m_ActCtxGenCtx.m_ManifestOperationFlags, wchCodebasePathSeparator));
  821. }
  822. }
  823. else
  824. {
  825. CTinyStringBuffer buffRelativeCodebase;
  826. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_INSTALLATION,
  827. "SXS.DLL: Installing file \"%S\"\n",
  828. static_cast<PCWSTR>(strPath));
  829. IFW32FALSE_EXIT(this->InstallFile(strPath, buffRelativeCodebase));
  830. }
  831. fSuccess = TRUE;
  832. Exit:
  833. m_ActCtxGenCtx.m_ManifestOperationFlags = dwManifestOperationFlags_Saved;
  834. m_bSuccessfulSoFar = m_bSuccessfulSoFar && fSuccess;
  835. return fSuccess;
  836. }
  837. BOOL
  838. CAssemblyInstall::WriteSingleInstallLog(
  839. const CInstalledItemEntry &rLogItemEntry,
  840. BOOL fOverWrite
  841. )
  842. {
  843. FN_PROLOG_WIN32
  844. static const WCHAR header[] = { 0xFEFF };
  845. static const WCHAR eoln[] = L"\r\n";
  846. CFileStream LogFileStream;
  847. CSmallStringBuffer buffWritingText;
  848. //
  849. // Only call if you've got a log file name, an identity, and a reference.
  850. //
  851. PARAMETER_CHECK((rLogItemEntry.m_dwValidItems &
  852. (CINSTALLITEM_VALID_LOGFILE | CINSTALLITEM_VALID_IDENTITY | CINSTALLITEM_VALID_REFERENCE)) != 0);
  853. IFW32FALSE_EXIT(
  854. LogFileStream.OpenForWrite(
  855. rLogItemEntry.m_buffLogFileName,
  856. FILE_SHARE_READ,
  857. fOverWrite ? CREATE_ALWAYS : OPEN_ALWAYS,
  858. FILE_FLAG_SEQUENTIAL_SCAN));
  859. //
  860. // If we're overwriting, then clip off whatever was
  861. // already there (if anything.)
  862. //
  863. if (fOverWrite)
  864. {
  865. ULARGE_INTEGER li;
  866. li.QuadPart = 0;
  867. IFCOMFAILED_EXIT(LogFileStream.SetSize(li));
  868. }
  869. //
  870. // Not overwriting? Zing to the end instead.
  871. //
  872. if (!fOverWrite)
  873. {
  874. LARGE_INTEGER li;
  875. li.QuadPart = 0;
  876. IFCOMFAILED_EXIT(LogFileStream.Seek(li, STREAM_SEEK_END, NULL));
  877. }
  878. //
  879. // Convert the installed identity to something that we can save to disk.
  880. //
  881. IFW32FALSE_EXIT(
  882. SxspGenerateTextualIdentity(
  883. 0,
  884. rLogItemEntry.m_AssemblyIdentity,
  885. buffWritingText));
  886. //
  887. // Write the assembly identity
  888. //
  889. IFW32FALSE_EXIT(buffWritingText.Win32Append(eoln, NUMBER_OF(eoln)-1));
  890. IFCOMFAILED_EXIT(
  891. LogFileStream.Write(
  892. static_cast<PCWSTR>(buffWritingText),
  893. (ULONG)(buffWritingText.Cch() * sizeof(WCHAR)),
  894. NULL));
  895. //
  896. // And the reference
  897. //
  898. IFW32FALSE_EXIT(rLogItemEntry.m_InstallReference.GetIdentifierValue(buffWritingText));
  899. IFW32FALSE_EXIT(buffWritingText.Win32Append(eoln, NUMBER_OF(eoln)-1));
  900. IFCOMFAILED_EXIT(LogFileStream.Write(
  901. static_cast<PCWSTR>(buffWritingText),
  902. (ULONG)(buffWritingText.Cch() * sizeof(WCHAR)),
  903. NULL));
  904. IFW32FALSE_EXIT(LogFileStream.Close());
  905. FN_EPILOG
  906. }
  907. BOOL
  908. SxspEnsureInstallReferencePresent(
  909. DWORD dwFlags,
  910. IN const CAssemblyInstallReferenceInformation &rcInstRef,
  911. OUT BOOL &rfWasAdded
  912. )
  913. /*++
  914. Purpose:
  915. Ensure that the installation reference given in pAsmIdent and pAsmInstallReference
  916. is really present in the registry. If the reference is not present, then it is
  917. added. If it's present already, it sets *pfWasPresent and returns.
  918. Parameters:
  919. dwFlags - Future use, must be zero
  920. pAsmIdent - Assembly identity to add this reference to
  921. pAsmInstallReference - Assembly installation reference data, from the calling
  922. installer application.
  923. --*/
  924. {
  925. FN_PROLOG_WIN32
  926. CFusionRegKey hkAsmInstallInfo;
  927. CFusionRegKey hkAsmRefcount;
  928. CFusionRegKey hkAllInstallInfo;
  929. DWORD dwCreated = 0;
  930. CSmallStringBuffer buffAssemblyDirNameInRegistry;
  931. CSmallStringBuffer buffRefcountValueName;
  932. PCASSEMBLY_IDENTITY pAsmIdent = NULL;
  933. rfWasAdded = FALSE;
  934. PARAMETER_CHECK(dwFlags == 0);
  935. PARAMETER_CHECK((pAsmIdent = rcInstRef.GetIdentity().GetAssemblyIdentity()) != NULL);
  936. if (SXS_AVOID_WRITING_REGISTRY)
  937. FN_SUCCESSFUL_EXIT();
  938. //
  939. // Open installation data key
  940. //
  941. IFW32FALSE_EXIT(::SxspOpenAssemblyInstallationKey(0, KEY_READ, hkAllInstallInfo));
  942. //
  943. // Open the specific assembly name key
  944. //
  945. IFW32FALSE_EXIT(::SxspGenerateAssemblyNameInRegistry(pAsmIdent, buffAssemblyDirNameInRegistry));
  946. IFW32FALSE_EXIT(hkAllInstallInfo.OpenOrCreateSubKey(
  947. hkAsmInstallInfo,
  948. buffAssemblyDirNameInRegistry,
  949. KEY_ALL_ACCESS,
  950. 0,
  951. NULL,
  952. NULL));
  953. INTERNAL_ERROR_CHECK(hkAsmInstallInfo != CFusionRegKey::GetInvalidValue());
  954. //
  955. // Open the subey for refcounting
  956. //
  957. IFW32FALSE_EXIT(hkAsmInstallInfo.OpenOrCreateSubKey(
  958. hkAsmRefcount,
  959. WINSXS_INSTALLATION_REFERENCES_SUBKEY,
  960. KEY_SET_VALUE,
  961. 0,
  962. &dwCreated,
  963. NULL));
  964. INTERNAL_ERROR_CHECK(hkAsmRefcount != CFusionRegKey::GetInvalidValue());
  965. //
  966. // Generate the installation data that will be populated here.
  967. //
  968. IFW32FALSE_EXIT(rcInstRef.WriteIntoRegistry(hkAsmRefcount));
  969. rfWasAdded = TRUE;
  970. FN_EPILOG
  971. }
  972. BOOL
  973. CAssemblyInstall::EndAssemblyInstall(
  974. DWORD dwManifestOperationFlags,
  975. PVOID
  976. )
  977. {
  978. BOOL fSuccess = FALSE;
  979. FN_TRACE_WIN32(fSuccess);
  980. PARAMETER_CHECK(
  981. (dwManifestOperationFlags & ~(
  982. MANIFEST_OPERATION_INSTALL_FLAG_ABORT
  983. | MANIFEST_OPERATION_INSTALL_FLAG_COMMIT
  984. | MANIFEST_OPERATION_INSTALL_FLAG_REFRESH
  985. )) == 0);
  986. // one of these but not both must be set
  987. PARAMETER_CHECK((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_ABORT)
  988. ^ (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_COMMIT));
  989. //
  990. // PARAMETER_CHECK above ensures that this only has known bits set.
  991. // If PARAMETER_CHECK above is expanded to allow more flags, maintain
  992. // this line appropriately.
  993. //
  994. m_ActCtxGenCtx.m_ManifestOperationFlags |= dwManifestOperationFlags;
  995. //
  996. // Clear out some metadata in the registry.
  997. //
  998. if ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_ABORT) == 0)
  999. {
  1000. for (ULONG ul = 0; ul < m_ItemsInstalled.GetSize(); ul++)
  1001. {
  1002. if (m_ItemsInstalled[ul].m_dwValidItems & CINSTALLITEM_VALID_RECOVERY)
  1003. {
  1004. IFW32FALSE_EXIT(m_ItemsInstalled[ul].m_RecoveryInfo.ClearExistingRegistryData());
  1005. }
  1006. }
  1007. }
  1008. IFW32FALSE_EXIT(::SxspFireActCtxGenEnding(&m_ActCtxGenCtx));
  1009. //
  1010. // write register before copy files into winsxs : see bug 316380
  1011. //
  1012. if ( ( dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_ABORT ) == 0 )
  1013. {
  1014. BOOL fWasAdded = FALSE;
  1015. //
  1016. // Post installation tidyup
  1017. //
  1018. for (ULONG ul = 0; ul < m_ItemsInstalled.GetSize(); ul++)
  1019. {
  1020. CInstalledItemEntry &Item = m_ItemsInstalled[ul];
  1021. if (Item.m_dwValidItems & CINSTALLITEM_VALID_RECOVERY)
  1022. {
  1023. //
  1024. // Add the codebase for this reference. If one exists for the ref,
  1025. // update its URL, prompt, etc.
  1026. //
  1027. CCodebaseInformation* pCodebaseInfo = NULL;
  1028. CCodebaseInformationList &rCodebaseList = Item.m_RecoveryInfo.GetCodeBaseList();
  1029. ULONG Flags = 0;
  1030. IFW32FALSE_EXIT(rCodebaseList.FindCodebase(
  1031. Item.m_InstallReference.GetGeneratedIdentifier(),
  1032. pCodebaseInfo));
  1033. if ( pCodebaseInfo != NULL )
  1034. {
  1035. IFW32FALSE_EXIT(pCodebaseInfo->Initialize(Item.m_CodebaseInfo));
  1036. }
  1037. else
  1038. {
  1039. IFW32FALSE_EXIT(rCodebaseList.Win32Append(Item.m_CodebaseInfo));
  1040. }
  1041. if (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REFRESH)
  1042. {
  1043. Flags |= SXSP_ADD_ASSEMBLY_INSTALLATION_INFO_FLAG_REFRESH;
  1044. #if DBG
  1045. ::FusionpDbgPrintEx(
  1046. FUSION_DBG_LEVEL_WFP | FUSION_DBG_LEVEL_INSTALLATION,
  1047. "SXS.DLL: %s - propping recovery flag to SxspAddAssemblyInstallationInfo\n",
  1048. __FUNCTION__);
  1049. #endif
  1050. }
  1051. IFW32FALSE_EXIT(::SxspAddAssemblyInstallationInfo(Flags, Item.m_RecoveryInfo, Item.m_CodebaseInfo));
  1052. }
  1053. //
  1054. // Adding a reference? Don't touch references when recovering assembly via wfp/sfc.
  1055. //
  1056. if ((dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REFRESH) == 0)
  1057. {
  1058. if (Item.m_dwValidItems & CINSTALLITEM_VALID_REFERENCE)
  1059. {
  1060. IFW32FALSE_EXIT(::SxspEnsureInstallReferencePresent(0, Item.m_InstallReference, fWasAdded));
  1061. }
  1062. }
  1063. else
  1064. {
  1065. #if DBG
  1066. ::FusionpDbgPrintEx(
  1067. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_WFP,
  1068. "SXS: %s() - not writing reference to registry in recovery/wfp/sfc\n",
  1069. __FUNCTION__
  1070. );
  1071. #endif
  1072. }
  1073. //
  1074. // Creating a logfile?
  1075. //
  1076. if ((Item.m_dwValidItems & (CINSTALLITEM_VALID_IDENTITY | CINSTALLITEM_VALID_LOGFILE)) &&
  1077. (m_ActCtxGenCtx.m_ManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_CREATE_LOGFILE))
  1078. {
  1079. IFW32FALSE_EXIT(this->WriteSingleInstallLog(Item));
  1080. }
  1081. }
  1082. }
  1083. fSuccess = TRUE;
  1084. Exit:
  1085. if (!fSuccess)
  1086. {
  1087. CSxsPreserveLastError ple;
  1088. for (ULONG ul = 0; ul < m_ItemsInstalled.GetSize(); ul++)
  1089. {
  1090. m_ItemsInstalled[ul].m_RecoveryInfo.RestorePreviouslyExistingRegistryData();
  1091. }
  1092. ple.Restore();
  1093. }
  1094. m_bSuccessfulSoFar= m_bSuccessfulSoFar && fSuccess;
  1095. return fSuccess;
  1096. }
  1097. BOOL
  1098. WINAPI
  1099. SxsBeginAssemblyInstall(
  1100. DWORD Flags,
  1101. PSXS_INSTALLATION_FILE_COPY_CALLBACK InstallationCallback,
  1102. PVOID InstallationContext,
  1103. PSXS_IMPERSONATION_CALLBACK ImpersonationCallback,
  1104. PVOID ImpersonationContext,
  1105. PVOID *ppvInstallCookie
  1106. )
  1107. {
  1108. BOOL fSuccess = FALSE;
  1109. FN_TRACE_WIN32(fSuccess);
  1110. DWORD dwManifestOperationFlags = 0;
  1111. CAssemblyInstall* pInstall = NULL;
  1112. CImpersonationData ImpersonationData(ImpersonationCallback, ImpersonationContext);
  1113. if (ppvInstallCookie != NULL)
  1114. *ppvInstallCookie = NULL;
  1115. PARAMETER_CHECK(ppvInstallCookie != NULL);
  1116. PARAMETER_CHECK(
  1117. (Flags & ~(
  1118. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_MOVE |
  1119. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_RESOURCE |
  1120. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_DIRECTORY |
  1121. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE |
  1122. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NOT_TRANSACTIONAL |
  1123. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NO_VERIFY |
  1124. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_REPLACE_EXISTING)) == 0);
  1125. #define MAP_FLAG(x) do { if (Flags & SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_ ## x) dwManifestOperationFlags |= MANIFEST_OPERATION_INSTALL_FLAG_ ## x; } while (0)
  1126. MAP_FLAG(MOVE);
  1127. MAP_FLAG(FROM_RESOURCE);
  1128. MAP_FLAG(FROM_DIRECTORY);
  1129. MAP_FLAG(FROM_DIRECTORY_RECURSIVE);
  1130. MAP_FLAG(NOT_TRANSACTIONAL);
  1131. MAP_FLAG(NO_VERIFY);
  1132. MAP_FLAG(REPLACE_EXISTING);
  1133. #undef MAP_FLAG
  1134. IFALLOCFAILED_EXIT(pInstall = new CAssemblyInstall);
  1135. IFW32FALSE_EXIT(pInstall->BeginAssemblyInstall(dwManifestOperationFlags, InstallationCallback, InstallationContext, ImpersonationData));
  1136. *ppvInstallCookie = pInstall;
  1137. pInstall = NULL;
  1138. fSuccess = TRUE;
  1139. Exit:
  1140. FUSION_DELETE_SINGLETON(pInstall);
  1141. return fSuccess;
  1142. }
  1143. BOOL
  1144. SxsInstallW(
  1145. PSXS_INSTALLW lpInstallIn
  1146. )
  1147. {
  1148. /*
  1149. NTRAID#NTBUG9-612092-2002/05/16-JayKrell
  1150. large frame -- over 3500 bytes
  1151. */
  1152. BOOL fSuccess = FALSE;
  1153. FN_TRACE_WIN32(fSuccess);
  1154. SXS_INSTALL_SOURCE_INFO sisi;
  1155. PSXS_INSTALL_SOURCE_INFO psisi = NULL;
  1156. CAssemblyInstall* pInstall = NULL;
  1157. CSmartPtr<CAssemblyInstall> defaultAssemblyInstall;
  1158. CImpersonationData ImpersonationData;
  1159. DWORD dwManifestOperationFlags = 0;
  1160. SXS_INSTALL_REFERENCEW BlankReference;
  1161. BOOL fAreWeInOSSetupMode = FALSE;
  1162. SXS_INSTALLW InstallCopy = { sizeof(SXS_INSTALLW) };
  1163. CSmallStringBuffer buffConstructedCodebaseBuffer;
  1164. CSmallStringBuffer rgbFilenameBuffer;
  1165. PARAMETER_CHECK(
  1166. (lpInstallIn != NULL) &&
  1167. RTL_CONTAINS_FIELD(lpInstallIn, lpInstallIn->cbSize, lpManifestPath));
  1168. PARAMETER_CHECK((lpInstallIn->lpManifestPath != NULL) && (lpInstallIn->lpManifestPath[0] != L'\0'));
  1169. PARAMETER_CHECK(
  1170. (lpInstallIn->dwFlags & ~(
  1171. SXS_INSTALL_FLAG_CODEBASE_URL_VALID |
  1172. SXS_INSTALL_FLAG_MOVE |
  1173. SXS_INSTALL_FLAG_FROM_RESOURCE |
  1174. SXS_INSTALL_FLAG_FROM_DIRECTORY |
  1175. SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE |
  1176. SXS_INSTALL_FLAG_NOT_TRANSACTIONAL |
  1177. SXS_INSTALL_FLAG_NO_VERIFY |
  1178. SXS_INSTALL_FLAG_REPLACE_EXISTING |
  1179. SXS_INSTALL_FLAG_LOG_FILE_NAME_VALID |
  1180. SXS_INSTALL_FLAG_INSTALLED_BY_DARWIN |
  1181. SXS_INSTALL_FLAG_INSTALLED_BY_OSSETUP |
  1182. SXS_INSTALL_FLAG_INSTALLED_BY_MIGRATION |
  1183. SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID |
  1184. SXS_INSTALL_FLAG_REFERENCE_VALID |
  1185. SXS_INSTALL_FLAG_REFRESH |
  1186. SXS_INSTALL_FLAG_FROM_CABINET |
  1187. SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID)) == 0);
  1188. #define FLAG_FIELD_CHECK(_flagname, _fieldname) PARAMETER_CHECK(((lpInstallIn->dwFlags & _flagname) == 0) || (RTL_CONTAINS_FIELD(lpInstallIn, lpInstallIn->cbSize, _fieldname)))
  1189. FLAG_FIELD_CHECK(SXS_INSTALL_FLAG_CODEBASE_URL_VALID, lpCodebaseURL);
  1190. FLAG_FIELD_CHECK(SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID, pvInstallCookie);
  1191. FLAG_FIELD_CHECK(SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID, lpRefreshPrompt);
  1192. FLAG_FIELD_CHECK(SXS_INSTALL_FLAG_LOG_FILE_NAME_VALID, lpLogFileName);
  1193. FLAG_FIELD_CHECK(SXS_INSTALL_FLAG_REFERENCE_VALID, lpReference);
  1194. #undef FLAG_FIELD_CHECK
  1195. // If they said they have a codebase, they need to really have one.
  1196. PARAMETER_CHECK(
  1197. ((lpInstallIn->dwFlags & SXS_INSTALL_FLAG_CODEBASE_URL_VALID) == 0) ||
  1198. ((lpInstallIn->lpCodebaseURL != NULL) &&
  1199. (lpInstallIn->lpCodebaseURL[0] != L'\0')));
  1200. #if DBG
  1201. if (lpInstallIn != NULL)
  1202. {
  1203. #define X(x,y,z) if ((lpInstallIn->dwFlags & x) != 0) \
  1204. Y(y,z)
  1205. #define Y(y,z) ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_INSTALLATION, "SXS: %s() lpInstallIn->" #y " : " z "\n", __FUNCTION__, lpInstallIn->y)
  1206. X(SXS_INSTALL_FLAG_CODEBASE_URL_VALID, lpCodebaseURL, " %ls");
  1207. X(SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID, pvInstallCookie, "%p");
  1208. X(SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID, lpRefreshPrompt, "%ls");
  1209. X(SXS_INSTALL_FLAG_LOG_FILE_NAME_VALID, lpLogFileName, " %ls");
  1210. X(SXS_INSTALL_FLAG_REFERENCE_VALID, lpReference, " %p");
  1211. Y( lpManifestPath, " %ls");
  1212. Y( dwFlags, " 0x%lx");
  1213. #undef Y
  1214. #undef X
  1215. }
  1216. #endif
  1217. // If they say they have a valid cookie, make sure it is.
  1218. PARAMETER_CHECK(
  1219. ((lpInstallIn->dwFlags & SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID) == 0) ||
  1220. (lpInstallIn->pvInstallCookie != NULL));
  1221. // Darwin installs have implied codebases, so don't let both flags be set.
  1222. PARAMETER_CHECK(
  1223. ((lpInstallIn->dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_DARWIN) == 0) ||
  1224. ((lpInstallIn->dwFlags & SXS_INSTALL_FLAG_CODEBASE_URL_VALID) == 0));
  1225. // OS Setup only makes sense with from-directory-recursive. Otherwise we
  1226. // can't figure out the magic x-ms-windows-source: url to put into the codebase.
  1227. PARAMETER_CHECK(
  1228. ((lpInstallIn->dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_OSSETUP) == 0) ||
  1229. ((lpInstallIn->dwFlags & SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE) != 0) ||
  1230. ((lpInstallIn->dwFlags & SXS_INSTALL_FLAG_FROM_CABINET) != 0) ||
  1231. ((lpInstallIn->dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_MIGRATION) != 0) );
  1232. // PARAMETER CHECKING IS DONE! Let's copy the fields that don't have flags to
  1233. // indicate that they're (optionally) set and start applying defaults.
  1234. InstallCopy.dwFlags = lpInstallIn->dwFlags;
  1235. InstallCopy.lpManifestPath = lpInstallIn->lpManifestPath;
  1236. // Copy fields that the caller supplied and indicated were valid:
  1237. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID)
  1238. InstallCopy.pvInstallCookie = lpInstallIn->pvInstallCookie;
  1239. else
  1240. InstallCopy.pvInstallCookie = NULL;
  1241. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_CODEBASE_URL_VALID)
  1242. InstallCopy.lpCodebaseURL = lpInstallIn->lpCodebaseURL;
  1243. else
  1244. InstallCopy.lpCodebaseURL = NULL;
  1245. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID)
  1246. InstallCopy.lpRefreshPrompt = lpInstallIn->lpRefreshPrompt;
  1247. else
  1248. InstallCopy.lpRefreshPrompt = NULL;
  1249. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_LOG_FILE_NAME_VALID)
  1250. InstallCopy.lpLogFileName = lpInstallIn->lpLogFileName;
  1251. else
  1252. InstallCopy.lpLogFileName = NULL;
  1253. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_REFERENCE_VALID)
  1254. InstallCopy.lpReference = lpInstallIn->lpReference;
  1255. else
  1256. InstallCopy.lpReference = NULL;
  1257. // APPLY DEFAULTS
  1258. //
  1259. // Fix up blank reference for non-darwin installations to at least indicate the
  1260. // executable which performed the installation.
  1261. //
  1262. if (((InstallCopy.dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_DARWIN) == 0) &&
  1263. ((InstallCopy.dwFlags & SXS_INSTALL_FLAG_REFERENCE_VALID) == 0))
  1264. {
  1265. ZeroMemory(&BlankReference, sizeof(BlankReference));
  1266. BlankReference.cbSize = sizeof(BlankReference);
  1267. BlankReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_SXS_INSTALL_ASSEMBLY;
  1268. BlankReference.lpIdentifier = NULL;
  1269. IFW32FALSE_EXIT(FusionpGetModuleFileName(0, GetModuleHandleW(NULL), rgbFilenameBuffer));
  1270. BlankReference.lpNonCanonicalData = rgbFilenameBuffer;
  1271. InstallCopy.lpReference = &BlankReference;
  1272. InstallCopy.dwFlags |= SXS_INSTALL_FLAG_REFERENCE_VALID;
  1273. }
  1274. IFW32FALSE_EXIT(::FusionpAreWeInOSSetupMode(&fAreWeInOSSetupMode));
  1275. if (!g_SxsOfflineInstall)
  1276. {
  1277. // If this is an OS install and a codebase was not passed, we'll fill in the magical
  1278. // one that says to look under the os setup information key. Since the are-we-in-
  1279. // ossetup flag always overrides, ensure that the "are we in os setup" flag is set
  1280. // in the structure as well.
  1281. if ((InstallCopy.dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_OSSETUP) != 0)
  1282. {
  1283. InstallCopy.lpCodebaseURL = URLHEAD_WINSOURCE;
  1284. InstallCopy.dwFlags |= SXS_INSTALL_FLAG_CODEBASE_URL_VALID | SXS_INSTALL_FLAG_INSTALLED_BY_OSSETUP;
  1285. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_MIGRATION)
  1286. InstallCopy.dwFlags |= SXS_INSTALL_FLAG_CODEBASE_URL_VALID | SXS_INSTALL_FLAG_INSTALLED_BY_MIGRATION;
  1287. }
  1288. }
  1289. // If there's no codebase (and this isn't an MSI install);
  1290. // we'll assume that the manifest path is a sufficient codebase.
  1291. if (((InstallCopy.dwFlags & SXS_INSTALL_FLAG_CODEBASE_URL_VALID) == 0) &&
  1292. ((InstallCopy.dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_DARWIN) == 0))
  1293. {
  1294. InstallCopy.lpCodebaseURL = InstallCopy.lpManifestPath;
  1295. InstallCopy.dwFlags |= SXS_INSTALL_FLAG_CODEBASE_URL_VALID;
  1296. }
  1297. #define MAP_FLAG(x) do { if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_ ## x) dwManifestOperationFlags |= MANIFEST_OPERATION_INSTALL_FLAG_ ## x; } while (0)
  1298. MAP_FLAG(MOVE);
  1299. MAP_FLAG(FROM_RESOURCE);
  1300. MAP_FLAG(NO_VERIFY);
  1301. MAP_FLAG(NOT_TRANSACTIONAL);
  1302. MAP_FLAG(REPLACE_EXISTING);
  1303. MAP_FLAG(FROM_DIRECTORY);
  1304. MAP_FLAG(FROM_DIRECTORY_RECURSIVE);
  1305. MAP_FLAG(INSTALLED_BY_DARWIN);
  1306. MAP_FLAG(INSTALLED_BY_OSSETUP);
  1307. MAP_FLAG(INSTALLED_BY_MIGRATION);
  1308. MAP_FLAG(REFERENCE_VALID);
  1309. MAP_FLAG(REFRESH);
  1310. MAP_FLAG(FROM_CABINET);
  1311. #undef MAP_FLAG
  1312. // Because we didn't have time to go through and get rid of the SXS_INSTALL_SOURCE_INFO struct
  1313. // usage, we have to now map the SXS_INSTALLW to a legacy SXS_INSTALL_SOURCE_INFO.
  1314. memset(&sisi, 0, sizeof(sisi));
  1315. sisi.cbSize = sizeof(sisi);
  1316. //
  1317. // We could do this above, but that makes things 'messy' - a smart compiler
  1318. // might merge the two..
  1319. //
  1320. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_CODEBASE_URL_VALID)
  1321. {
  1322. sisi.pcwszCodebaseName = InstallCopy.lpCodebaseURL;
  1323. sisi.dwFlags |= SXSINSTALLSOURCE_HAS_CODEBASE;
  1324. psisi = &sisi;
  1325. }
  1326. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID)
  1327. {
  1328. sisi.pcwszPromptOnRefresh = InstallCopy.lpRefreshPrompt;
  1329. sisi.dwFlags |= SXSINSTALLSOURCE_HAS_PROMPT;
  1330. psisi = &sisi;
  1331. }
  1332. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_LOG_FILE_NAME_VALID)
  1333. {
  1334. dwManifestOperationFlags |= MANIFEST_OPERATION_INSTALL_FLAG_CREATE_LOGFILE;
  1335. sisi.pcwszLogFileName = InstallCopy.lpLogFileName;
  1336. sisi.dwFlags |= SXSINSTALLSOURCE_CREATE_LOGFILE;
  1337. psisi = &sisi;
  1338. }
  1339. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_DARWIN)
  1340. {
  1341. sisi.dwFlags |= SXSINSTALLSOURCE_INSTALL_BY_DARWIN;
  1342. psisi = &sisi;
  1343. }
  1344. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_OSSETUP)
  1345. {
  1346. sisi.dwFlags |= SXSINSTALLSOURCE_INSTALL_BY_OSSETUP;
  1347. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_INSTALLED_BY_MIGRATION)
  1348. sisi.dwFlags |= SXSINSTALLSOURCE_INSTALL_BY_MIGRATION;
  1349. psisi = &sisi;
  1350. }
  1351. if (InstallCopy.dwFlags & SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID)
  1352. pInstall = reinterpret_cast<CAssemblyInstall*>(InstallCopy.pvInstallCookie);
  1353. else
  1354. {
  1355. IFW32FALSE_EXIT(defaultAssemblyInstall.Win32Allocate(__FILE__, __LINE__));
  1356. IFW32FALSE_EXIT(defaultAssemblyInstall->BeginAssemblyInstall(dwManifestOperationFlags, NULL, NULL, ImpersonationData));
  1357. pInstall = defaultAssemblyInstall;
  1358. }
  1359. //
  1360. // If psisi is non-null, we've filled out some about the codebase information,
  1361. // so set the manifest operation flag.
  1362. //
  1363. if (psisi != NULL)
  1364. {
  1365. dwManifestOperationFlags |= MANIFEST_OPERATION_INSTALL_FLAG_INCLUDE_CODEBASE;
  1366. }
  1367. fSuccess = pInstall->InstallAssembly(
  1368. dwManifestOperationFlags,
  1369. InstallCopy.lpManifestPath,
  1370. psisi,
  1371. InstallCopy.lpReference);
  1372. if (InstallCopy.pvInstallCookie == NULL)
  1373. {
  1374. DWORD dwError = ::FusionpGetLastWin32Error();
  1375. BOOL fEndStatus = pInstall->EndAssemblyInstall(
  1376. (fSuccess ? MANIFEST_OPERATION_INSTALL_FLAG_COMMIT : MANIFEST_OPERATION_INSTALL_FLAG_ABORT)
  1377. | (dwManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_REFRESH)
  1378. );
  1379. if (!fEndStatus)
  1380. {
  1381. ::FusionpDbgPrintEx(
  1382. FUSION_DBG_LEVEL_ERROR,
  1383. "SXS: %s() - Failed call to EndAssemblyInstall, previous winerror was %lu, error after EndAssemblyInstall %lu\n",
  1384. __FUNCTION__,
  1385. dwError,
  1386. ::FusionpGetLastWin32Error());
  1387. }
  1388. //
  1389. // If the install failed but the end succeeded, we want the status of the install, right?
  1390. //
  1391. // I think it should always keep the error status of installation failure no matter whether EndInstall succeed or not.
  1392. // so I change the code from
  1393. // if (bEndStatus && !fSuccess)
  1394. // to
  1395. // if (!fSuccess)
  1396. //
  1397. if (!fSuccess)
  1398. {
  1399. ::FusionpSetLastWin32Error(dwError);
  1400. }
  1401. fSuccess = (fSuccess && fEndStatus);
  1402. }
  1403. Exit:
  1404. // add assembly-install info into setup log file
  1405. {
  1406. CSxsPreserveLastError ple;
  1407. if (fAreWeInOSSetupMode)
  1408. {
  1409. if (fSuccess)
  1410. {
  1411. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_SETUPLOG, "SXS Installation Succeed for %S \n", InstallCopy.lpManifestPath);
  1412. }
  1413. else // if the installation fails, we need specify what and why
  1414. {
  1415. ASSERT(ple.LastError()!= 0);
  1416. CHAR rgchLastError[160];
  1417. rgchLastError[0] = 0;
  1418. if (!::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, ple.LastError(), 0, rgchLastError, NUMBER_OF(rgchLastError), NULL))
  1419. {
  1420. FusionpFormatStringA(rgchLastError, NUMBER_OF(rgchLastError), "Message not avaiable for display, please refer error# :%d\n", ::FusionpGetLastWin32Error());
  1421. }
  1422. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_SETUPLOG | FUSION_DBG_LEVEL_ERROR, "Installation Failed: %S. Error Message : %s\n", InstallCopy.lpManifestPath, rgchLastError);
  1423. }
  1424. }
  1425. ple.Restore();
  1426. }
  1427. return fSuccess;
  1428. }
  1429. BOOL
  1430. WINAPI
  1431. SxsEndAssemblyInstall(
  1432. PVOID pvInstallCookie,
  1433. DWORD dwFlags,
  1434. PVOID pvReserved
  1435. )
  1436. {
  1437. BOOL fSuccess = FALSE;
  1438. FN_TRACE_WIN32(fSuccess);
  1439. CAssemblyInstall* pInstall = NULL;
  1440. DWORD dwManifestOperationFlags = 0;
  1441. PBOOL pvReservedAsPointerToBool = NULL;
  1442. if ((dwFlags & SXS_END_ASSEMBLY_INSTALL_FLAG_GET_STATUS) && pvReserved != NULL)
  1443. {
  1444. pvReservedAsPointerToBool = reinterpret_cast<PBOOL>(pvReserved);
  1445. *pvReservedAsPointerToBool = FALSE;
  1446. }
  1447. PARAMETER_CHECK(pvInstallCookie != NULL);
  1448. PARAMETER_CHECK(
  1449. (dwFlags & ~(
  1450. SXS_END_ASSEMBLY_INSTALL_FLAG_COMMIT |
  1451. SXS_END_ASSEMBLY_INSTALL_FLAG_ABORT |
  1452. SXS_END_ASSEMBLY_INSTALL_FLAG_NO_VERIFY |
  1453. SXS_END_ASSEMBLY_INSTALL_FLAG_GET_STATUS)) == 0);
  1454. #define X SXS_END_ASSEMBLY_INSTALL_FLAG_ABORT
  1455. #define Y SXS_END_ASSEMBLY_INSTALL_FLAG_COMMIT
  1456. PARAMETER_CHECK(((dwFlags & (X | Y)) == X)
  1457. || ((dwFlags & (X | Y)) == Y));
  1458. #undef X
  1459. #undef Y
  1460. //
  1461. // Want the install status? Don't forget to tell us where to put it.
  1462. //
  1463. PARAMETER_CHECK(!(
  1464. (dwFlags & SXS_END_ASSEMBLY_INSTALL_FLAG_GET_STATUS) &&
  1465. (pvReserved != NULL)));
  1466. #define MAP_FLAG(x) do { if (dwFlags & SXS_END_ASSEMBLY_INSTALL_FLAG_ ## x) dwManifestOperationFlags |= MANIFEST_OPERATION_INSTALL_FLAG_ ## x; } while (0)
  1467. MAP_FLAG(COMMIT);
  1468. MAP_FLAG(ABORT);
  1469. MAP_FLAG(NO_VERIFY);
  1470. #undef MAP_FLAG
  1471. pInstall = reinterpret_cast<CAssemblyInstall*>(pvInstallCookie);
  1472. IFW32FALSE_EXIT(pInstall->EndAssemblyInstall(dwManifestOperationFlags));
  1473. if (dwFlags & SXS_END_ASSEMBLY_INSTALL_FLAG_GET_STATUS)
  1474. {
  1475. INTERNAL_ERROR_CHECK(pvReserved != NULL);
  1476. INTERNAL_ERROR_CHECK(pvReservedAsPointerToBool != NULL);
  1477. *pvReservedAsPointerToBool = pInstall->m_bSuccessfulSoFar;
  1478. }
  1479. fSuccess = TRUE;
  1480. Exit:
  1481. CSxsPreserveLastError ple;
  1482. FUSION_DELETE_SINGLETON(pInstall); // no matter failed or succeed, delete it
  1483. ple.Restore();
  1484. return fSuccess;
  1485. }
  1486. /*-----------------------------------------------------------------------------
  1487. predefined setup callbacks
  1488. -----------------------------------------------------------------------------*/
  1489. /*
  1490. NTRAID#NTBUG9-591148-2002/03/31-JayKrell
  1491. remove dead code SxspInstallCallbackSetupCopyQueueEx
  1492. */
  1493. BOOL
  1494. WINAPI
  1495. SxspInstallCallbackSetupCopyQueueEx(
  1496. PSXS_INSTALLATION_FILE_COPY_CALLBACK_PARAMETERS parameters
  1497. )
  1498. {
  1499. /*
  1500. NTRAID#NTBUG9-591148-2002/03/31-JayKrell
  1501. large stack frame -- over 1200 bytes
  1502. */
  1503. BOOL fSuccess = FALSE;
  1504. FN_TRACE_WIN32(fSuccess);
  1505. PSXS_INSTALLATION_SETUP_COPY_QUEUE_EX_PARAMETERS parameters2 = reinterpret_cast<PSXS_INSTALLATION_SETUP_COPY_QUEUE_EX_PARAMETERS>(parameters->pvContext);
  1506. ASSERT(parameters->cbSize == sizeof(*parameters));
  1507. ASSERT(parameters2->cbSize == sizeof(*parameters2));
  1508. CSetupCopyQueuePathParameters setupCopyQueueParameters;
  1509. IFW32FALSE_EXIT(setupCopyQueueParameters.Initialize(parameters->pSourceFile, parameters->pDestinationFile));
  1510. IFW32FALSE_EXIT(
  1511. ::SetupQueueCopyW(
  1512. parameters2->hSetupCopyQueue,
  1513. setupCopyQueueParameters.m_sourceRoot,
  1514. setupCopyQueueParameters.m_sourcePath,
  1515. setupCopyQueueParameters.m_sourceName,
  1516. parameters2->pszSourceDescription,
  1517. NULL, // tag file
  1518. setupCopyQueueParameters.m_destinationDirectory,
  1519. setupCopyQueueParameters.m_destinationName,
  1520. parameters2->dwCopyStyle));
  1521. parameters->nDisposition = SXS_INSTALLATION_FILE_COPY_DISPOSITION_FILE_QUEUED;
  1522. fSuccess = TRUE;
  1523. Exit:
  1524. ASSERT(HeapValidate(FUSION_DEFAULT_PROCESS_HEAP(), 0, NULL));
  1525. return fSuccess;
  1526. }
  1527. /*
  1528. NTRAID#NTBUG9-591148-2002/03/31-JayKrell
  1529. remove dead code SxspInstallCallbackSetupCopyQueue
  1530. */
  1531. BOOL
  1532. WINAPI
  1533. SxspInstallCallbackSetupCopyQueue(
  1534. PSXS_INSTALLATION_FILE_COPY_CALLBACK_PARAMETERS parameters
  1535. )
  1536. {
  1537. BOOL fSuccess = FALSE;
  1538. FN_TRACE_WIN32(fSuccess);
  1539. ASSERT(parameters->cbSize == sizeof(*parameters));
  1540. HSPFILEQ hSetupCopyQueue = reinterpret_cast<HSPFILEQ>(parameters->pvContext);
  1541. SXS_INSTALLATION_SETUP_COPY_QUEUE_EX_PARAMETERS parameters2 = {sizeof(parameters2)};
  1542. parameters2.hSetupCopyQueue = hSetupCopyQueue;
  1543. parameters2.pszSourceDescription = NULL;
  1544. parameters2.dwCopyStyle = 0;
  1545. // copy to not violate const
  1546. SXS_INSTALLATION_FILE_COPY_CALLBACK_PARAMETERS parameters3 = *parameters;
  1547. parameters3.pvContext = &parameters2;
  1548. IFW32FALSE_EXIT(::SxspInstallCallbackSetupCopyQueueEx(&parameters3));
  1549. parameters->nDisposition = parameters3.nDisposition;
  1550. fSuccess = TRUE;
  1551. Exit:
  1552. ASSERT(HeapValidate(FUSION_DEFAULT_PROCESS_HEAP(), 0, NULL));
  1553. return fSuccess;
  1554. }
  1555. VOID
  1556. CALLBACK
  1557. SxsRunDllInstallAssemblyW(HWND hwnd, HINSTANCE hinst, PWSTR lpszCmdLine, int nCmdShow)
  1558. {
  1559. FN_PROLOG_VOID
  1560. SXS_INSTALLW Install = { sizeof(SXS_INSTALLW) };
  1561. SXS_INSTALL_REFERENCEW Reference = { sizeof(SXS_INSTALL_REFERENCEW) };
  1562. CSmallStringBuffer FullPath;
  1563. IFW32FALSE_EXIT(::SxspExpandRelativePathToFull(lpszCmdLine, ::wcslen(lpszCmdLine), FullPath));
  1564. Install.dwFlags = SXS_INSTALL_FLAG_REPLACE_EXISTING |
  1565. SXS_INSTALL_FLAG_REFERENCE_VALID |
  1566. SXS_INSTALL_FLAG_CODEBASE_URL_VALID;
  1567. Install.lpManifestPath = FullPath;
  1568. Install.lpCodebaseURL = FullPath;
  1569. Install.lpReference = &Reference;
  1570. Reference.dwFlags = 0;
  1571. Reference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING;
  1572. Reference.lpIdentifier = L"RunDll32";
  1573. ::SxsInstallW(&Install);
  1574. FN_EPILOG
  1575. }
  1576. /*
  1577. NTRAID#NTBUG9-591148-2002/03/31-JayKrell
  1578. remove dead ansi code SxsRunDllInstallAssembly
  1579. */
  1580. VOID
  1581. CALLBACK
  1582. SxsRunDllInstallAssembly(HWND hwnd, HINSTANCE hinst, PSTR lpszCmdLine, int nCmdShow)
  1583. {
  1584. FN_TRACE_SMART_TLS();
  1585. CSmallStringBuffer buffer;
  1586. if (buffer.Win32Assign(lpszCmdLine, ::strlen(lpszCmdLine)))
  1587. {
  1588. ::SxsRunDllInstallAssemblyW(hwnd, hinst, const_cast<PWSTR>(static_cast<PCWSTR>(buffer)), nCmdShow);
  1589. }
  1590. }
  1591. BOOL
  1592. CAssemblyInstallReferenceInformation::WriteIntoRegistry(
  1593. const CFusionRegKey &rhkTargetKey
  1594. ) const
  1595. {
  1596. if (SXS_AVOID_WRITING_REGISTRY)
  1597. return TRUE;
  1598. FN_PROLOG_WIN32
  1599. INTERNAL_ERROR_CHECK(this->m_fIdentityStuffReady);
  1600. IFW32FALSE_EXIT(
  1601. rhkTargetKey.SetValue(
  1602. m_buffGeneratedIdentifier,
  1603. this->GetCanonicalData()));
  1604. FN_EPILOG
  1605. }
  1606. CAssemblyInstallReferenceInformation::CAssemblyInstallReferenceInformation()
  1607. : m_SchemeGuid(GUID_NULL), m_fIdentityStuffReady(FALSE), m_dwFlags(0)
  1608. {
  1609. }
  1610. BOOL
  1611. CAssemblyInstallReferenceInformation::GenerateFileReference(
  1612. IN const CBaseStringBuffer &buffKeyfileName,
  1613. OUT CBaseStringBuffer &buffDrivePath,
  1614. OUT CBaseStringBuffer &buffFilePart,
  1615. OUT DWORD &dwDriveSerial
  1616. )
  1617. {
  1618. FN_PROLOG_WIN32
  1619. CSmallStringBuffer buffWorking;
  1620. CSmallStringBuffer buffTemp;
  1621. bool fIsUncPath = false;
  1622. dwDriveSerial = 0;
  1623. /*
  1624. NTRAID#NTBUG9-591148-2002/03/31-JayKrell
  1625. case mapping of ':' ?
  1626. */
  1627. // The key file must either start with "\\" or "x:\" to be valid.
  1628. PARAMETER_CHECK(buffKeyfileName.Cch() >= 3);
  1629. PARAMETER_CHECK(
  1630. ((::FusionpIsPathSeparator(buffKeyfileName[0]) &&
  1631. ::FusionpIsPathSeparator(buffKeyfileName[1])) ||
  1632. (::FusionpIsDriveLetter(buffKeyfileName[0]) &&
  1633. (buffKeyfileName[1] == L':') &&
  1634. ::FusionpIsPathSeparator(buffKeyfileName[2]))));
  1635. //
  1636. // Steps:
  1637. // - Strip potential file name from buffKeyfileName.
  1638. // - Call GetVolumePathName on buffKeyfileName, store that
  1639. // in buffDrivePath
  1640. // - Call GetVolumeNameForVolumeMountPoint on buffDrivePath,
  1641. // store into some temporary
  1642. // - Call GetVolumeInformation on the temporary to
  1643. // obtain the serial number.
  1644. // - Call GetDriveType on the temporary to see what kind of
  1645. // drive type the key is on.
  1646. // - If it's on a network, call SxspGetUniversalName to get
  1647. // the network path (call on buffDrivePath)
  1648. //
  1649. IFW32FALSE_EXIT(::SxspGetFullPathName(buffKeyfileName, buffWorking));
  1650. IFW32FALSE_EXIT(::SxspGetVolumePathName(0, buffWorking, buffDrivePath));
  1651. IFW32FALSE_EXIT(buffFilePart.Win32Assign(buffWorking));
  1652. // If the user pointed us to something that is a volume path but did not include the
  1653. // trailing path separator, we'll actually end up with a buffDrivePath like "c:\mountpoint\"
  1654. // but the buffFilePart will be "c:\mountpoint". we'll explicitly handle
  1655. // this situation; there does not seem to be a generalization. -mgrier 6/26/2001
  1656. if ((buffDrivePath.Cch() == (buffFilePart.Cch() + 1)) &&
  1657. buffDrivePath.HasTrailingPathSeparator() &&
  1658. !buffFilePart.HasTrailingPathSeparator())
  1659. {
  1660. buffFilePart.Clear();
  1661. }
  1662. else
  1663. {
  1664. INTERNAL_ERROR_CHECK(buffFilePart.Cch() >= buffDrivePath.Cch());
  1665. IFW32FALSE_EXIT(buffFilePart.Right(buffFilePart.Cch() - buffDrivePath.Cch()));
  1666. }
  1667. fIsUncPath = false;
  1668. //
  1669. // \\machine\share is unc
  1670. // \\?\unc is unc
  1671. // \\?foo is not unc
  1672. //
  1673. if (buffDrivePath.Cch() > 3)
  1674. {
  1675. if (::FusionpIsPathSeparator(buffDrivePath[0]))
  1676. {
  1677. if (::FusionpIsPathSeparator(buffDrivePath[1]))
  1678. {
  1679. if (buffDrivePath[2] == L'?')
  1680. {
  1681. if (::FusionpIsPathSeparator(buffDrivePath[3]))
  1682. {
  1683. if (buffDrivePath.Cch() > 7)
  1684. {
  1685. if (::FusionpEqualStringsI(&buffDrivePath[4], 3, L"unc", 3) &&
  1686. ::FusionpIsPathSeparator(buffDrivePath[7]))
  1687. fIsUncPath = true;
  1688. }
  1689. }
  1690. }
  1691. }
  1692. else
  1693. fIsUncPath = true;
  1694. }
  1695. }
  1696. if ((::GetDriveTypeW(buffDrivePath) == DRIVE_REMOTE) && !fIsUncPath)
  1697. {
  1698. IFW32FALSE_EXIT(::SxspGetRemoteUniversalName(buffDrivePath, buffTemp));
  1699. IFW32FALSE_EXIT(buffDrivePath.Win32Assign(buffTemp));
  1700. // This seems gross, but the drive letter can be mapped to \\server\share\dir, so we'll
  1701. // trim it down to the volume path name, and anything that's after that we'll shift over
  1702. // to the file part.
  1703. //
  1704. // Luckily the string always seems to be of the form \\server\share\path1\path2\ (note
  1705. // the trailing slash), and GetVolumePathName() should always return "\\server\share\"
  1706. // so relatively simple string manipulation should clean this up.
  1707. IFW32FALSE_EXIT(::SxspGetVolumePathName(0, buffDrivePath, buffTemp));
  1708. INTERNAL_ERROR_CHECK(buffTemp.Cch() <= buffDrivePath.Cch());
  1709. if (buffTemp.Cch() != buffDrivePath.Cch())
  1710. {
  1711. IFW32FALSE_EXIT(buffFilePart.Win32Prepend(buffDrivePath + buffTemp.Cch(), buffDrivePath.Cch() - buffTemp.Cch()));
  1712. IFW32FALSE_EXIT(buffDrivePath.Win32Assign(buffTemp));
  1713. }
  1714. }
  1715. IFW32FALSE_ORIGINATE_AND_EXIT(::GetVolumeInformationW(
  1716. buffDrivePath,
  1717. NULL,
  1718. 0,
  1719. &dwDriveSerial,
  1720. NULL,
  1721. NULL,
  1722. NULL,
  1723. 0));
  1724. //
  1725. // Convert NT path to Win32 Path.
  1726. //
  1727. // \\?\unc\machine\share\foo => \\machine\share\foo
  1728. // \\?\c:\foo => c:\
  1729. //
  1730. if (buffDrivePath.Cch() > 3)
  1731. {
  1732. if (::FusionpIsPathSeparator(buffDrivePath[0]) &&
  1733. ::FusionpIsPathSeparator(buffDrivePath[1]) &&
  1734. (buffDrivePath[2] == L'?') &&
  1735. ::FusionpIsPathSeparator(buffDrivePath[3]))
  1736. {
  1737. if (buffDrivePath.Cch() > 7)
  1738. {
  1739. if (::FusionpEqualStringsI(&buffDrivePath[4], 3, L"unc", 3) &&
  1740. ::FusionpIsPathSeparator(buffDrivePath[7]))
  1741. {
  1742. // "\\?\UNC\machine\share" -> "\machine\share"
  1743. buffDrivePath.Right(buffDrivePath.Cch() - 7);
  1744. // "\machine\share" -> "\\machine\share"
  1745. IFW32FALSE_EXIT(buffDrivePath.Win32Prepend(L'\\'));
  1746. }
  1747. }
  1748. else
  1749. {
  1750. // "\\?foo" -> "foo"
  1751. // "\\?\c:\foo" -> "c:\foo"
  1752. buffDrivePath.Right(buffDrivePath.Cch() - 4);
  1753. }
  1754. }
  1755. }
  1756. FN_EPILOG
  1757. }
  1758. BOOL
  1759. pMapSchemeGuidToString(
  1760. IN const GUID &rcGuid,
  1761. OUT CBaseStringBuffer &rbuffIdentifier
  1762. )
  1763. {
  1764. FN_PROLOG_WIN32
  1765. static struct {
  1766. const GUID* pguid;
  1767. PCWSTR pcwsz;
  1768. SIZE_T cch;
  1769. } gds[] = {
  1770. { &SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL, SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL_STRING, NUMBER_OF(SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL_STRING) - 1 },
  1771. { &SXS_INSTALL_REFERENCE_SCHEME_SXS_INSTALL_ASSEMBLY, L"SIAW", 4 },
  1772. { &SXS_INSTALL_REFERENCE_SCHEME_UNINSTALLKEY, L"U", 1 },
  1773. { &SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING, L"S", 1 },
  1774. { &SXS_INSTALL_REFERENCE_SCHEME_KEYFILE, L"F", 1 },
  1775. };
  1776. ULONG ul;
  1777. for ( ul = 0; ul < NUMBER_OF(gds); ul++ )
  1778. {
  1779. if ( *(gds[ul].pguid) == rcGuid )
  1780. {
  1781. IFW32FALSE_EXIT(rbuffIdentifier.Win32Assign(gds[ul].pcwsz, gds[ul].cch));
  1782. break;
  1783. }
  1784. }
  1785. if ( ul == NUMBER_OF(gds) )
  1786. {
  1787. IFW32FALSE_EXIT(::SxspFormatGUID(rcGuid, rbuffIdentifier));
  1788. }
  1789. FN_EPILOG
  1790. }
  1791. BOOL
  1792. CAssemblyInstallReferenceInformation::GenerateIdentifierValue(
  1793. OUT CBaseStringBuffer *pbuffTarget
  1794. )
  1795. {
  1796. FN_PROLOG_WIN32
  1797. if ( pbuffTarget != NULL )
  1798. pbuffTarget->Clear();
  1799. if (m_fIdentityStuffReady)
  1800. {
  1801. if (pbuffTarget != NULL)
  1802. IFW32FALSE_EXIT(pbuffTarget->Win32Assign(m_buffGeneratedIdentifier));
  1803. }
  1804. else
  1805. {
  1806. const GUID& SchemeGuid = this->GetSchemeGuid();
  1807. IFW32FALSE_EXIT(::pMapSchemeGuidToString(SchemeGuid, m_buffGeneratedIdentifier));
  1808. if ((SchemeGuid != SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL) &&
  1809. (SchemeGuid != SXS_INSTALL_REFERENCE_SCHEME_SXS_INSTALL_ASSEMBLY))
  1810. {
  1811. IFW32FALSE_EXIT(m_buffGeneratedIdentifier.Win32Append(
  1812. SXS_REFERENCE_CHUNK_SEPERATOR,
  1813. SXS_REFERENCE_CHUNK_SEPERATOR_CCH));
  1814. if ((SchemeGuid == SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING) ||
  1815. (SchemeGuid == SXS_INSTALL_REFERENCE_SCHEME_UNINSTALLKEY))
  1816. {
  1817. //
  1818. // Both of these just use the value in the lpIdentifier member. It was
  1819. // validated above, so it's OK to use here directly
  1820. //
  1821. IFW32FALSE_EXIT(m_buffGeneratedIdentifier.Win32Append(this->GetIdentifier()));
  1822. }
  1823. else if (SchemeGuid == SXS_INSTALL_REFERENCE_SCHEME_KEYFILE)
  1824. {
  1825. CSmallStringBuffer buffDrivePath;
  1826. CSmallStringBuffer buffFilePart;
  1827. DWORD dwDriveSerialNumber = 0;
  1828. IFW32FALSE_EXIT(this->GenerateFileReference(
  1829. this->GetIdentifier(),
  1830. buffDrivePath,
  1831. buffFilePart,
  1832. dwDriveSerialNumber));
  1833. //
  1834. // Now form up the value stuff.
  1835. //
  1836. IFW32FALSE_EXIT(buffDrivePath.Win32EnsureTrailingPathSeparator());
  1837. buffFilePart.RemoveLeadingPathSeparators();
  1838. IFW32FALSE_EXIT(m_buffGeneratedIdentifier.Win32FormatAppend(
  1839. L"%ls;%08lx;%ls",
  1840. static_cast<PCWSTR>(buffDrivePath),
  1841. dwDriveSerialNumber,
  1842. static_cast<PCWSTR>(buffFilePart)));
  1843. }
  1844. }
  1845. this->m_fIdentityStuffReady = TRUE;
  1846. if ( pbuffTarget != NULL )
  1847. {
  1848. IFW32FALSE_EXIT(pbuffTarget->Win32Assign(m_buffGeneratedIdentifier));
  1849. }
  1850. }
  1851. FN_EPILOG
  1852. }
  1853. BOOL
  1854. CAssemblyInstallReferenceInformation::Initialize(
  1855. PCSXS_INSTALL_REFERENCEW pRefData
  1856. )
  1857. {
  1858. FN_PROLOG_WIN32
  1859. PARAMETER_CHECK(pRefData != NULL);
  1860. //
  1861. // One of our good GUIDs
  1862. //
  1863. PARAMETER_CHECK(
  1864. (pRefData->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL) ||
  1865. (pRefData->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING) ||
  1866. (pRefData->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_UNINSTALLKEY) ||
  1867. (pRefData->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_KEYFILE) ||
  1868. (pRefData->guidScheme == SXS_INSTALL_REFERENCE_SCHEME_SXS_INSTALL_ASSEMBLY));
  1869. //
  1870. // If this is not the OS-install scheme, or the SxsInstallAssemblyW legacy API,
  1871. // then ensure that there's at least the identifier data present.
  1872. //
  1873. if ((pRefData->guidScheme != SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL) &&
  1874. (pRefData->guidScheme != SXS_INSTALL_REFERENCE_SCHEME_SXS_INSTALL_ASSEMBLY))
  1875. {
  1876. PARAMETER_CHECK((pRefData->lpIdentifier != NULL) && (pRefData->lpIdentifier[0] != UNICODE_NULL));
  1877. }
  1878. this->m_fIdentityStuffReady = FALSE;
  1879. this->m_dwFlags = pRefData->dwFlags;
  1880. this->m_SchemeGuid = pRefData->guidScheme;
  1881. if ( pRefData->lpIdentifier != NULL)
  1882. {
  1883. IFW32FALSE_EXIT(this->m_buffIdentifier.Win32Assign(
  1884. pRefData->lpIdentifier,
  1885. ::wcslen(pRefData->lpIdentifier)));
  1886. }
  1887. if ( pRefData->lpNonCanonicalData != NULL )
  1888. {
  1889. IFW32FALSE_EXIT(this->m_buffNonCanonicalData.Win32Assign(
  1890. pRefData->lpNonCanonicalData,
  1891. ::wcslen(pRefData->lpNonCanonicalData)));
  1892. }
  1893. IFW32FALSE_EXIT(this->GenerateIdentifierValue());
  1894. FN_EPILOG
  1895. }
  1896. BOOL
  1897. CAssemblyInstallReferenceInformation::AcquireContents(
  1898. const CAssemblyInstallReferenceInformation& rcOther
  1899. )
  1900. {
  1901. FN_PROLOG_WIN32
  1902. if (m_IdentityReference.IsInitialized())
  1903. IFW32FALSE_EXIT(m_IdentityReference.Assign(rcOther.m_IdentityReference));
  1904. else
  1905. IFW32FALSE_EXIT(m_IdentityReference.Initialize(rcOther.m_IdentityReference));
  1906. IFW32FALSE_EXIT(m_buffGeneratedIdentifier.Win32Assign(rcOther.m_buffGeneratedIdentifier));
  1907. IFW32FALSE_EXIT(m_buffIdentifier.Win32Assign(rcOther.m_buffIdentifier));
  1908. IFW32FALSE_EXIT(m_buffNonCanonicalData.Win32Assign(rcOther.m_buffNonCanonicalData));
  1909. m_dwFlags = rcOther.m_dwFlags;
  1910. m_fIdentityStuffReady = rcOther.m_fIdentityStuffReady;
  1911. m_SchemeGuid = rcOther.m_SchemeGuid;
  1912. FN_EPILOG
  1913. }
  1914. BOOL
  1915. CAssemblyInstallReferenceInformation::IsReferencePresentIn(
  1916. const CFusionRegKey &rhkQueryKey,
  1917. BOOL &rfPresent,
  1918. BOOL *pfNonCanonicalDataMatches
  1919. ) const
  1920. {
  1921. FN_PROLOG_WIN32
  1922. CSmallStringBuffer buffData;
  1923. DWORD dwError = 0;
  1924. if ( pfNonCanonicalDataMatches )
  1925. *pfNonCanonicalDataMatches = FALSE;
  1926. INTERNAL_ERROR_CHECK(this->m_fIdentityStuffReady);
  1927. IFW32FALSE_EXIT(
  1928. ::FusionpRegQuerySzValueEx(
  1929. 0,
  1930. rhkQueryKey,
  1931. this->m_buffGeneratedIdentifier,
  1932. buffData,
  1933. dwError,
  1934. 2,
  1935. ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND));
  1936. rfPresent = (dwError == ERROR_SUCCESS);
  1937. if (pfNonCanonicalDataMatches)
  1938. {
  1939. bool fMatchesTemp;
  1940. IFW32FALSE_EXIT(this->m_buffNonCanonicalData.Win32Equals(buffData, fMatchesTemp, true));
  1941. rfPresent = fMatchesTemp;
  1942. }
  1943. FN_EPILOG
  1944. }
  1945. BOOL
  1946. CAssemblyInstallReferenceInformation::DeleteReferenceFrom(
  1947. const CFusionRegKey &rhkQueryKey,
  1948. BOOL &rfWasDeleted
  1949. ) const
  1950. {
  1951. FN_PROLOG_WIN32
  1952. DWORD dwWin32Error;
  1953. rfWasDeleted = FALSE;
  1954. INTERNAL_ERROR_CHECK(this->m_fIdentityStuffReady);
  1955. IFW32FALSE_EXIT(
  1956. rhkQueryKey.DeleteValue(
  1957. m_buffGeneratedIdentifier,
  1958. dwWin32Error,
  1959. 2,
  1960. ERROR_FILE_NOT_FOUND,
  1961. ERROR_PATH_NOT_FOUND));
  1962. rfWasDeleted = (dwWin32Error == ERROR_SUCCESS);
  1963. FN_EPILOG
  1964. }
  1965. BOOL
  1966. CInstalledItemEntry::AcquireContents(
  1967. const CInstalledItemEntry &other
  1968. )
  1969. {
  1970. FN_PROLOG_WIN32
  1971. m_dwValidItems = other.m_dwValidItems;
  1972. if ( m_dwValidItems & CINSTALLITEM_VALID_REFERENCE )
  1973. {
  1974. IFW32FALSE_EXIT(m_InstallReference.AcquireContents(other.m_InstallReference));
  1975. }
  1976. if ( m_dwValidItems & CINSTALLITEM_VALID_RECOVERY )
  1977. {
  1978. IFW32FALSE_EXIT(m_RecoveryInfo.CopyValue(other.m_RecoveryInfo));
  1979. IFW32FALSE_EXIT(m_CodebaseInfo.Initialize(other.m_CodebaseInfo));
  1980. }
  1981. if ( m_dwValidItems & CINSTALLITEM_VALID_LOGFILE )
  1982. {
  1983. IFW32FALSE_EXIT(m_buffLogFileName.Win32Assign(other.m_buffLogFileName));
  1984. }
  1985. if ( m_dwValidItems & CINSTALLITEM_VALID_IDENTITY )
  1986. {
  1987. m_AssemblyIdentity.Finalize();
  1988. IFW32FALSE_EXIT(::SxsDuplicateAssemblyIdentity(
  1989. 0,
  1990. other.m_AssemblyIdentity,
  1991. &m_AssemblyIdentity));
  1992. }
  1993. FN_EPILOG
  1994. }