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.

717 lines
25 KiB

  1. /*
  2. Copyright (c) Microsoft Corporation
  3. */
  4. #include "stdinc.h"
  5. #include "sxsapi.h"
  6. #include "recover.h"
  7. #include "sxsinstall.h"
  8. BOOL
  9. pDeleteFileOrDirectoryHelper(
  10. IN const CBaseStringBuffer &rcbuffFileName
  11. )
  12. /*++
  13. Purpose:
  14. When you need a filesystem object gone, call us.
  15. Parameters:
  16. The absolute name of the thing being killed.
  17. Returns:
  18. TRUE if the object was deleted, false if it (or any subobjects) wasn't.
  19. --*/
  20. {
  21. FN_PROLOG_WIN32
  22. //
  23. // Maybe this is a directory. Trying this won't hurt.
  24. //
  25. bool fExist = false;
  26. IFW32FALSE_EXIT(SxspDoesFileExist(0, rcbuffFileName, fExist));
  27. if (fExist)
  28. {
  29. DWORD dwAttr = 0;
  30. IFW32FALSE_EXIT(SxspGetFileAttributesW(rcbuffFileName, dwAttr));
  31. if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
  32. {
  33. IFW32FALSE_EXIT(::SxspDeleteDirectory(rcbuffFileName));
  34. }else // it should be a file
  35. {
  36. // try to reset FileAttribute for DeleteFile
  37. ::SetFileAttributesW(rcbuffFileName, FILE_ATTRIBUTE_NORMAL);
  38. IFW32FALSE_ORIGINATE_AND_EXIT(::DeleteFileW(rcbuffFileName));
  39. }
  40. }
  41. FN_EPILOG
  42. }
  43. BOOL
  44. pRemovePotentiallyEmptyDirectory(
  45. IN const CBaseStringBuffer &buffDirName
  46. )
  47. {
  48. FN_PROLOG_WIN32
  49. bool fExist = false;
  50. IFW32FALSE_EXIT(::SxspDoesFileExist(SXSP_DOES_FILE_EXIST_FLAG_CHECK_DIRECTORY_ONLY, buffDirName, fExist));
  51. if (fExist)
  52. {
  53. BOOL fDumpBoolean = FALSE;
  54. IFW32FALSE_ORIGINATE_AND_EXIT_UNLESS(
  55. ::SetFileAttributesW(
  56. buffDirName,
  57. FILE_ATTRIBUTE_NORMAL),
  58. FILE_OR_PATH_NOT_FOUND(::FusionpGetLastWin32Error()),
  59. fDumpBoolean);
  60. if (!fDumpBoolean)
  61. {
  62. IFW32FALSE_ORIGINATE_AND_EXIT_UNLESS2(
  63. ::RemoveDirectoryW(buffDirName),
  64. LIST_4(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_DIR_NOT_EMPTY, ERROR_SHARING_VIOLATION),
  65. fDumpBoolean);
  66. }
  67. }
  68. FN_EPILOG
  69. }
  70. BOOL
  71. pCleanUpAssemblyData(
  72. IN const PCASSEMBLY_IDENTITY pcAsmIdent,
  73. OUT BOOL &rfWasRemovedProperly
  74. )
  75. /*++
  76. Purpose:
  77. Deletes registry and filesystem information about the assembly indicated.
  78. Removes installation data from the registry first, so as to avoid SFP
  79. interactions.
  80. Parameters:
  81. pcAsmIdent - Identity of the assembly to be destroyed
  82. rfWasRemovedProperly- Flag to indicate whether or not all the assembly
  83. data was actually removed.
  84. Returns:
  85. FALSE if "anything bad" happened while deleting registry data. See
  86. rfWasRemovedProperly for actual status.
  87. --*/
  88. {
  89. if (SXS_AVOID_WRITING_REGISTRY)
  90. return TRUE;
  91. FN_PROLOG_WIN32
  92. BOOL fDumpBoolean = FALSE;
  93. BOOL fPolicy = FALSE;
  94. CSmallStringBuffer buffSxsStore;
  95. CSmallStringBuffer buffScratchSpace;
  96. CFusionRegKey hkAsmInstallInfo;
  97. CFusionRegKey hkSingleAsmInfo;
  98. //
  99. // Cleanup happens in two phases:
  100. //
  101. // 1 - The registry data is whacked from rhkAsmInstallInfo. Since we're
  102. // uninstalling an assembly, there's no reason to keep anything in it,
  103. // especially because it's got no references. Use DestroyKeyTree and
  104. // then DeleteKey to remove it.
  105. //
  106. // 2 - Delete as many of the on-disk files as possible, esp. the manifest
  107. // and catalog.
  108. //
  109. PARAMETER_CHECK(pcAsmIdent != NULL);
  110. //
  111. // Start this out at true, we'll call it false later on.
  112. //
  113. rfWasRemovedProperly = TRUE;
  114. IFW32FALSE_EXIT(::SxspDetermineAssemblyType(pcAsmIdent, fPolicy));
  115. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(buffSxsStore));
  116. //
  117. // Bye-bye to the registry first
  118. //
  119. IFW32FALSE_EXIT(::SxspOpenAssemblyInstallationKey(0 , KEY_ALL_ACCESS, hkAsmInstallInfo));
  120. IFW32FALSE_EXIT(::SxspGenerateAssemblyNameInRegistry(pcAsmIdent, buffScratchSpace));
  121. IFW32FALSE_EXIT(hkAsmInstallInfo.OpenSubKey(hkSingleAsmInfo, buffScratchSpace, KEY_ALL_ACCESS, 0));
  122. if ( hkSingleAsmInfo != CFusionRegKey::GetInvalidValue() )
  123. {
  124. //
  125. // Failure here isn't so bad...
  126. //
  127. IFW32FALSE_EXIT_UNLESS2(
  128. hkSingleAsmInfo.DestroyKeyTree(),
  129. LIST_3(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_KEY_DELETED),
  130. fDumpBoolean);
  131. if ( !fDumpBoolean )
  132. {
  133. IFW32FALSE_EXIT_UNLESS2(
  134. hkAsmInstallInfo.DeleteKey(buffScratchSpace),
  135. LIST_3(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_KEY_DELETED),
  136. fDumpBoolean);
  137. }
  138. }
  139. //
  140. // Both policies and normal assemblies have a manifest and catalog.
  141. //
  142. IFW32FALSE_EXIT(
  143. ::SxspGenerateSxsPath(
  144. 0,
  145. fPolicy ? SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY : SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST,
  146. buffSxsStore,
  147. buffSxsStore.Cch(),
  148. pcAsmIdent,
  149. NULL,
  150. buffScratchSpace));
  151. rfWasRemovedProperly = rfWasRemovedProperly && ::pDeleteFileOrDirectoryHelper(buffScratchSpace);
  152. IFW32FALSE_EXIT(buffScratchSpace.Win32ChangePathExtension(
  153. FILE_EXTENSION_CATALOG,
  154. FILE_EXTENSION_CATALOG_CCH,
  155. eErrorIfNoExtension));
  156. rfWasRemovedProperly = rfWasRemovedProperly && pDeleteFileOrDirectoryHelper(buffScratchSpace);
  157. //
  158. // Clean up data
  159. //
  160. if (!fPolicy)
  161. {
  162. //
  163. // This just poofs the assembly member files.
  164. // If the delete fails, we'll try to rename the directory to something else.
  165. //
  166. IFW32FALSE_EXIT(
  167. ::SxspGenerateSxsPath(
  168. 0,
  169. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
  170. buffSxsStore,
  171. buffSxsStore.Cch(),
  172. pcAsmIdent,
  173. NULL,
  174. buffScratchSpace));
  175. rfWasRemovedProperly = rfWasRemovedProperly && ::pDeleteFileOrDirectoryHelper(buffScratchSpace);
  176. }
  177. else
  178. {
  179. //
  180. // The policy file above should already have been deleted, so we should
  181. // attempt to remove the actual policy directory if it's empty. The
  182. // directory name is still in buffScratchSpace, if we just yank off the
  183. // last path element.
  184. //
  185. IFW32FALSE_EXIT(buffScratchSpace.Win32RemoveLastPathElement());
  186. rfWasRemovedProperly = rfWasRemovedProperly && ::pRemovePotentiallyEmptyDirectory(buffScratchSpace);
  187. }
  188. //
  189. // Once we've killed all the assembly information, if the Manifests or the
  190. // Policies directory is left empty, go clean them up as well.
  191. //
  192. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(buffScratchSpace));
  193. IFW32FALSE_EXIT(buffScratchSpace.Win32AppendPathElement(
  194. (fPolicy? POLICY_ROOT_DIRECTORY_NAME : MANIFEST_ROOT_DIRECTORY_NAME),
  195. (fPolicy? NUMBER_OF(POLICY_ROOT_DIRECTORY_NAME) - 1 : NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) - 1)));
  196. IFW32FALSE_EXIT(::pRemovePotentiallyEmptyDirectory(buffScratchSpace));
  197. FN_EPILOG
  198. }
  199. bool IsCharacterNulOrInSet(WCHAR ch, PCWSTR set);
  200. BOOL
  201. pAnalyzeLogfileForUninstall(
  202. PCWSTR lpcwszLogFileName
  203. )
  204. {
  205. FN_PROLOG_WIN32
  206. CFusionFile File;
  207. CFileMapping FileMapping;
  208. CMappedViewOfFile MappedViewOfFile;
  209. PCWSTR pCursor = NULL;
  210. ULONGLONG ullFileSize = 0;
  211. ULONGLONG ullFileCharacters = 0;
  212. ULONGLONG ullCursorPos = 0;
  213. const static WCHAR wchLineDividers[] = { L'\r', L'\n', 0xFEFF, 0 };
  214. ULONG ullPairsEncountered = 0;
  215. CSmallStringBuffer buffIdentity;
  216. CSmallStringBuffer buffReference;
  217. IFW32FALSE_EXIT(File.Win32CreateFile(lpcwszLogFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
  218. IFW32FALSE_EXIT(File.Win32GetSize(ullFileSize));
  219. ASSERT(ullFileSize % sizeof(WCHAR) == 0);
  220. ullFileCharacters = ullFileSize / sizeof(WCHAR);
  221. IFW32FALSE_EXIT(FileMapping.Win32CreateFileMapping(File, PAGE_READONLY));
  222. IFW32FALSE_EXIT(MappedViewOfFile.Win32MapViewOfFile(FileMapping, FILE_MAP_READ));
  223. pCursor = reinterpret_cast<PCWSTR>(static_cast<const VOID*>(MappedViewOfFile));
  224. #define SKIP_BREAKERS while ((ullCursorPos < ullFileCharacters) && IsCharacterNulOrInSet(pCursor[ullCursorPos], wchLineDividers)) ullCursorPos++;
  225. #define FIND_NEXT_BREAKER while ((ullCursorPos < ullFileCharacters) && !IsCharacterNulOrInSet(pCursor[ullCursorPos], wchLineDividers)) ullCursorPos++;
  226. #define ENSURE_NOT_EOF if (ullCursorPos >= ullFileCharacters) break;
  227. for ( ullCursorPos = 0; ullCursorPos < ullFileCharacters; ++ullCursorPos )
  228. {
  229. SKIP_BREAKERS
  230. ENSURE_NOT_EOF
  231. PCWSTR pcwszIdentityStart = pCursor + ullCursorPos;
  232. FIND_NEXT_BREAKER
  233. ENSURE_NOT_EOF
  234. PCWSTR pcwszIdentityEnd = pCursor + ullCursorPos;
  235. SKIP_BREAKERS
  236. ENSURE_NOT_EOF
  237. PCWSTR pcwszReferenceStart = pCursor + ullCursorPos;
  238. FIND_NEXT_BREAKER
  239. ENSURE_NOT_EOF
  240. PCWSTR pcwszReferenceEnd = pCursor + ullCursorPos;
  241. ullPairsEncountered++;
  242. IFW32FALSE_EXIT(buffIdentity.Win32Assign(
  243. pcwszIdentityStart,
  244. pcwszIdentityEnd - pcwszIdentityStart));
  245. IFW32FALSE_EXIT(buffReference.Win32Assign(
  246. pcwszReferenceStart,
  247. pcwszReferenceEnd - pcwszReferenceStart));
  248. SXS_UNINSTALLW Uninstall;
  249. ZeroMemory(&Uninstall, sizeof(Uninstall));
  250. Uninstall.cbSize = sizeof(Uninstall);
  251. Uninstall.dwFlags = SXS_UNINSTALL_FLAG_REFERENCE_VALID | SXS_UNINSTALL_FLAG_REFERENCE_COMPUTED;
  252. Uninstall.lpAssemblyIdentity = buffIdentity;
  253. Uninstall.lpInstallReference = reinterpret_cast<PCSXS_INSTALL_REFERENCEW>(static_cast<PCWSTR>(buffReference));
  254. IFW32FALSE_EXIT(::SxsUninstallW(&Uninstall, NULL));
  255. }
  256. PARAMETER_CHECK(ullPairsEncountered != 0);
  257. FN_EPILOG
  258. }
  259. class CSxsUninstallWLocals
  260. {
  261. public:
  262. CSxsUninstallWLocals() { }
  263. ~CSxsUninstallWLocals() { }
  264. CSmallStringBuffer buffAsmNameInRegistry;
  265. CAssemblyInstallReferenceInformation Ref;
  266. };
  267. BOOL
  268. WINAPI
  269. SxsUninstallW(
  270. IN PCSXS_UNINSTALLW pcUnInstallData,
  271. OUT DWORD *pdwDisposition
  272. )
  273. /*++
  274. Parameters:
  275. pcUnInstallData - Contains uninstallation data about the assembly being
  276. removed from the system, including the calling application's reference
  277. to the assembly.
  278. cbSize - Size, in bytes, of the structure pointed to by
  279. pcUnInstallData
  280. dwFlags - Indicates the state of the members of this reference,
  281. showing which of the following fields are valid.
  282. Allowed bitflags are:
  283. SXS_UNINSTALL_FLAG_REFERENCE_VALID
  284. SXS_UNINSTALL_FLAG_FORCE_DELETE
  285. lpAssemblyIdentity - Textual representation of the assembly's identity
  286. as installed by the application.
  287. lpInstallReference - Pointer to a SXS_INSTALL_REFERENCEW structure
  288. that contains the reference information for this
  289. application.
  290. pdwDisposition - Points to a DWORD that will return status about what was
  291. done to the assembly; whether it was uninstalled or not,
  292. and whether the reference given was removed.
  293. Returns:
  294. TRUE if the assembly was able to be uninstalled, FALSE otherwise. If the
  295. uninstall failed, lasterror is set to the probable cause.
  296. --*/
  297. {
  298. BOOL fSuccess = FALSE;
  299. FN_TRACE_WIN32(fSuccess);
  300. CSmartPtrWithNamedDestructor<ASSEMBLY_IDENTITY, &::SxsDestroyAssemblyIdentity> AssemblyIdentity;
  301. CFusionRegKey hkReferences;
  302. CFusionRegKey hkAllInstallInfo;
  303. CFusionRegKey hkAsmInstallInfo;
  304. CSmartPtr<CSxsUninstallWLocals> Locals;
  305. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  306. CSmallStringBuffer &buffAsmNameInRegistry = Locals->buffAsmNameInRegistry;
  307. BOOL fDoRemoveActualBits = FALSE;
  308. if (pdwDisposition != NULL)
  309. *pdwDisposition = 0;
  310. //
  311. // The parameter must be non-null, and must have at least dwFlags and the
  312. // assemblyidentity.
  313. //
  314. PARAMETER_CHECK(pcUnInstallData != NULL);
  315. PARAMETER_CHECK(RTL_CONTAINS_FIELD(pcUnInstallData, pcUnInstallData->cbSize, dwFlags) &&
  316. RTL_CONTAINS_FIELD(pcUnInstallData, pcUnInstallData->cbSize, lpAssemblyIdentity));
  317. //
  318. // Check flags
  319. //
  320. PARAMETER_CHECK((pcUnInstallData->dwFlags &
  321. ~(SXS_UNINSTALL_FLAG_FORCE_DELETE |
  322. SXS_UNINSTALL_FLAG_REFERENCE_VALID |
  323. SXS_UNINSTALL_FLAG_USE_INSTALL_LOG |
  324. SXS_UNINSTALL_FLAG_REFERENCE_COMPUTED)) == 0);
  325. //
  326. // If you specify the uninstall log, then that's the only thing that can be set. XOR
  327. // them together, so only one of the two will be set.
  328. //
  329. PARAMETER_CHECK(
  330. ((pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_USE_INSTALL_LOG) == 0) ||
  331. ((pcUnInstallData->dwFlags & (SXS_UNINSTALL_FLAG_REFERENCE_COMPUTED|SXS_UNINSTALL_FLAG_REFERENCE_VALID|SXS_UNINSTALL_FLAG_FORCE_DELETE)) == 0));
  332. //
  333. // If the reference flag was set, then the member has to be present, and
  334. // non-null as well.
  335. //
  336. PARAMETER_CHECK(((pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_REFERENCE_VALID) == 0) ||
  337. (RTL_CONTAINS_FIELD(pcUnInstallData, pcUnInstallData->cbSize, lpInstallReference) &&
  338. (pcUnInstallData->lpInstallReference != NULL)));
  339. //
  340. // If the log file is not present, the assembly identity can't be a zero-length string, and it can't be null - it's
  341. // required.
  342. //
  343. PARAMETER_CHECK((pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_USE_INSTALL_LOG) || ((pcUnInstallData->lpAssemblyIdentity != NULL) && (pcUnInstallData->lpAssemblyIdentity[0] != UNICODE_NULL)));
  344. //
  345. // If the install log flag was set, then the member needs to be set and non-null
  346. //
  347. PARAMETER_CHECK(((pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_USE_INSTALL_LOG) == 0) ||
  348. (RTL_CONTAINS_FIELD(pcUnInstallData, pcUnInstallData->cbSize, lpInstallLogFile) &&
  349. ((pcUnInstallData->lpInstallLogFile != NULL) && (pcUnInstallData->lpInstallLogFile[0] != UNICODE_NULL))));
  350. if ( pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_USE_INSTALL_LOG )
  351. {
  352. IFW32FALSE_EXIT(pAnalyzeLogfileForUninstall(pcUnInstallData->lpInstallLogFile));
  353. }
  354. else
  355. {
  356. //
  357. // And the reference scheme must not be SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL,
  358. // as you can't "uninstall" OS-installed assemblies!
  359. //
  360. if (pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_REFERENCE_VALID)
  361. {
  362. if (pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_REFERENCE_COMPUTED)
  363. {
  364. PCWSTR pcwszEndOfString = NULL;
  365. GUID gTheGuid;
  366. PCWSTR pcwszReferenceString = reinterpret_cast<PCWSTR>(pcUnInstallData->lpInstallReference);
  367. //
  368. // Non-null, non-zero-length
  369. //
  370. PARAMETER_CHECK((pcwszReferenceString != NULL) && (pcwszReferenceString[0] != L'\0'));
  371. //
  372. // Parse the displayed guid. If there's no _, then ensure that the guid
  373. // is not the os-installed guid.
  374. //
  375. pcwszEndOfString = wcschr(pcwszReferenceString, SXS_REFERENCE_CHUNK_SEPERATOR[0]);
  376. if ( pcwszEndOfString == NULL )
  377. {
  378. pcwszEndOfString = pcwszReferenceString + ::wcslen(pcwszReferenceString);
  379. IFW32FALSE_EXIT(
  380. ::SxspParseGUID(
  381. pcwszReferenceString,
  382. pcwszEndOfString - pcwszReferenceString,
  383. gTheGuid));
  384. PARAMETER_CHECK(gTheGuid != SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL);
  385. }
  386. }
  387. else
  388. {
  389. PARAMETER_CHECK(pcUnInstallData->lpInstallReference->guidScheme != SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL);
  390. }
  391. }
  392. //
  393. // Let's turn the identity back into a real identity object
  394. //
  395. IFW32FALSE_EXIT(
  396. ::SxspCreateAssemblyIdentityFromTextualString(
  397. pcUnInstallData->lpAssemblyIdentity,
  398. &AssemblyIdentity));
  399. IFW32FALSE_EXIT(
  400. ::SxspValidateIdentity(
  401. SXSP_VALIDATE_IDENTITY_FLAG_VERSION_REQUIRED,
  402. ASSEMBLY_IDENTITY_TYPE_REFERENCE,
  403. AssemblyIdentity));
  404. //
  405. // And go open the registry key that corresponds to it
  406. //
  407. IFW32FALSE_EXIT(::SxspOpenAssemblyInstallationKey(
  408. 0,
  409. KEY_ALL_ACCESS,
  410. hkAllInstallInfo));
  411. IFW32FALSE_EXIT(::SxspGenerateAssemblyNameInRegistry(
  412. AssemblyIdentity,
  413. buffAsmNameInRegistry));
  414. IFW32FALSE_EXIT(hkAllInstallInfo.OpenSubKey(
  415. hkAsmInstallInfo,
  416. buffAsmNameInRegistry,
  417. KEY_ALL_ACCESS,
  418. 0));
  419. //
  420. // If the assembly didn't have registry data, then obviously nobody cares
  421. // about it at all. Delete it with great vigor.
  422. //
  423. if (hkAsmInstallInfo == CFusionRegKey::GetInvalidValue())
  424. {
  425. fDoRemoveActualBits = TRUE;
  426. }
  427. else
  428. {
  429. DWORD dwReferenceCount = 0;
  430. BOOL fTempFlag = FALSE;
  431. //
  432. // We're going to need the references key in just a second...
  433. //
  434. IFW32FALSE_EXIT(
  435. hkAsmInstallInfo.OpenOrCreateSubKey(
  436. hkReferences,
  437. WINSXS_INSTALLATION_REFERENCES_SUBKEY,
  438. KEY_ALL_ACCESS,
  439. 0, NULL, NULL));
  440. //
  441. // If we were given an uninstall reference, then attempt to remove it.
  442. //
  443. if (pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_REFERENCE_VALID)
  444. {
  445. CSmartPtr<CAssemblyInstallReferenceInformation> AssemblyReference;
  446. BOOL fWasDeleted = FALSE;
  447. //
  448. // Opened the references key OK?
  449. //
  450. if (hkReferences != CFusionRegKey::GetInvalidValue())
  451. {
  452. IFW32FALSE_EXIT(AssemblyReference.Win32Allocate(__FILE__, __LINE__));
  453. //
  454. // Did the user precompute the reference string?
  455. //
  456. if (pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_REFERENCE_COMPUTED)
  457. IFW32FALSE_EXIT(AssemblyReference->ForceReferenceData(reinterpret_cast<PCWSTR>(pcUnInstallData->lpInstallReference)));
  458. else
  459. IFW32FALSE_EXIT(AssemblyReference->Initialize(pcUnInstallData->lpInstallReference));
  460. IFW32FALSE_EXIT(AssemblyReference->DeleteReferenceFrom(hkReferences, fWasDeleted));
  461. }
  462. if (fWasDeleted)
  463. {
  464. //
  465. // and delete the codebase
  466. //
  467. CFusionRegKey CodeBases;
  468. CFusionRegKey ThisCodeBase;
  469. DWORD Win32Error = NO_ERROR;
  470. IFW32FALSE_ORIGINATE_AND_EXIT_UNLESS3(
  471. hkAsmInstallInfo.OpenSubKey(
  472. CodeBases,
  473. CSMD_TOPLEVEL_CODEBASES,
  474. KEY_ALL_ACCESS,
  475. 0),
  476. LIST_3(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_KEY_DELETED),
  477. Win32Error);
  478. if (Win32Error == NO_ERROR)
  479. {
  480. IFW32FALSE_ORIGINATE_AND_EXIT_UNLESS3(
  481. CodeBases.OpenSubKey(
  482. ThisCodeBase,
  483. AssemblyReference->GetGeneratedIdentifier(),
  484. KEY_ALL_ACCESS,
  485. 0),
  486. LIST_3(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_KEY_DELETED),
  487. Win32Error);
  488. }
  489. if (Win32Error == NO_ERROR)
  490. {
  491. IFW32FALSE_ORIGINATE_AND_EXIT_UNLESS3(
  492. ThisCodeBase.DestroyKeyTree(),
  493. LIST_3(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_KEY_DELETED),
  494. Win32Error);
  495. }
  496. if (Win32Error == NO_ERROR)
  497. {
  498. IFW32FALSE_ORIGINATE_AND_EXIT(ThisCodeBase.Win32Close());
  499. IFW32FALSE_ORIGINATE_AND_EXIT_UNLESS3(
  500. CodeBases.DeleteKey(AssemblyReference->GetGeneratedIdentifier()),
  501. LIST_3(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_KEY_DELETED),
  502. Win32Error);
  503. }
  504. //
  505. // If the assembly reference was removed, tell our caller.
  506. //
  507. if (pdwDisposition != NULL)
  508. {
  509. *pdwDisposition |= SXS_UNINSTALL_DISPOSITION_REMOVED_REFERENCE;
  510. }
  511. }
  512. }
  513. //
  514. // Now see if there are any references left at all.
  515. //
  516. IFREGFAILED_ORIGINATE_AND_EXIT_UNLESS2(
  517. ::RegQueryInfoKeyW(
  518. hkReferences,
  519. NULL, NULL, NULL, NULL, NULL, NULL,
  520. &dwReferenceCount,
  521. NULL, NULL, NULL, NULL),
  522. LIST_3(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_KEY_DELETED),
  523. fTempFlag);
  524. //
  525. // If getting the key information succeeded and there were no more references,
  526. // then pow - make it go away.
  527. //
  528. if ((!fTempFlag) && (dwReferenceCount == 0))
  529. fDoRemoveActualBits = TRUE;
  530. }
  531. //
  532. // Now, if the "force delete" flag was set, set the "nuke this data anyhow"
  533. // flag. MSI still gets to veto the uninstall, so make sure that's done last.
  534. //
  535. if ((!fDoRemoveActualBits) && (pcUnInstallData->dwFlags & SXS_UNINSTALL_FLAG_FORCE_DELETE))
  536. fDoRemoveActualBits = TRUE;
  537. //
  538. // One last chance - we're about to remove the assembly from the system. Does Darwin
  539. // know about it?
  540. //
  541. if ( fDoRemoveActualBits )
  542. {
  543. IFW32FALSE_EXIT(
  544. ::SxspDoesMSIStillNeedAssembly(
  545. pcUnInstallData->lpAssemblyIdentity,
  546. fDoRemoveActualBits));
  547. fDoRemoveActualBits = !fDoRemoveActualBits;
  548. }
  549. if ( fDoRemoveActualBits && (hkReferences != CFusionRegKey::GetInvalidValue()))
  550. {
  551. //
  552. // One last check - is the assembly referenced by the OS? They get absolute
  553. // trump over all the other checks.
  554. //
  555. CAssemblyInstallReferenceInformation &Ref = Locals->Ref;
  556. SXS_INSTALL_REFERENCEW Reference;
  557. ZeroMemory(&Reference, sizeof(Reference));
  558. Reference.cbSize = sizeof(Reference);
  559. Reference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL;
  560. IFW32FALSE_EXIT(Ref.Initialize(&Reference));
  561. IFW32FALSE_EXIT(Ref.IsReferencePresentIn(hkReferences, fDoRemoveActualBits));
  562. //
  563. // If it was present, then don't remove!
  564. //
  565. fDoRemoveActualBits = !fDoRemoveActualBits;
  566. }
  567. //
  568. // Now, if we're still supposed to delete the assembly, go yank it out of the
  569. // registry and the filesystem; pCleanupAssemblyData knows how to do that.
  570. //
  571. if (fDoRemoveActualBits)
  572. {
  573. BOOL fWasRemovedProperly;
  574. IFW32FALSE_EXIT(::pCleanUpAssemblyData(AssemblyIdentity, fWasRemovedProperly));
  575. if (fWasRemovedProperly && (pdwDisposition != NULL))
  576. *pdwDisposition |= SXS_UNINSTALL_DISPOSITION_REMOVED_ASSEMBLY;
  577. }
  578. }
  579. fSuccess = TRUE;
  580. Exit:
  581. #if DBG
  582. if (!fSuccess && pcUnInstallData != NULL && pcUnInstallData->lpAssemblyIdentity != NULL)
  583. {
  584. ::FusionpDbgPrintEx(
  585. FUSION_DBG_LEVEL_ERROR,
  586. "SXS.DLL: %s(%ls) failed\n",
  587. __FUNCTION__,
  588. pcUnInstallData->lpAssemblyIdentity
  589. );
  590. }
  591. #endif
  592. return fSuccess;
  593. }