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

2426 lines
82 KiB

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