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.

411 lines
12 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. fusemig.cpp
  5. Abstract:
  6. migration support
  7. Author:
  8. xiaoyuw wu @ 09/2001
  9. Revision History:
  10. --*/
  11. #include "stdinc.h"
  12. #include "macros.h"
  13. #include "common.h"
  14. #include <msi.h>
  15. #include <Shlwapi.h>
  16. #include "fusionbuffer.h"
  17. #include "fuseio.h"
  18. #define MsiInstallDir L"%windir%\\installer\\"
  19. BOOL WINAPI DllMain(
  20. HINSTANCE hinstDLL,
  21. DWORD fdwReason,
  22. LPVOID lpvReserved
  23. )
  24. {
  25. return TRUE;
  26. }
  27. const char g_szMSIUserDataTreeKeyName[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData";
  28. const char g_szMSIW98KeyName[]="Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Components\\";
  29. const char g_szComponentKeyName[] = "Components";
  30. BOOL IsMsiFile(PCWSTR filename)
  31. {
  32. PWSTR p = NULL;
  33. p = wcsrchr(filename, L'.');
  34. if ( p == NULL)
  35. return FALSE;
  36. if (_wcsicmp(p, L".msi") == 0)
  37. {
  38. //
  39. // check the existence of the file
  40. //
  41. DWORD dwAttribute = GetFileAttributesW(filename);
  42. if ((dwAttribute == (DWORD) -1) || (dwAttribute & FILE_ATTRIBUTE_DIRECTORY)) // odd case
  43. {
  44. return FALSE;
  45. }
  46. return TRUE;
  47. }
  48. else
  49. return FALSE;
  50. }
  51. //
  52. // Function
  53. // from {AA2C6017-9D29-4CE2-8EC6-23E8E8F3C088} to 7106C2AA92D92EC4E86C328E8E3F0C88, which is
  54. // {AA2C6017-9D29-4CE2-8EC6-23E8E8F3C088} compared with
  55. // {7106C2AA-92D9-2EC4-E86C-328E8E3F0C88}
  56. //
  57. HRESULT ConvertComponentGUID(PCWSTR pszComponentGUID, PWSTR pszRegKey, DWORD cchRegKey)
  58. {
  59. HRESULT hr = S_OK;
  60. PWSTR pp = const_cast<PWSTR>(pszComponentGUID);
  61. if ( cchRegKey < wcslen(pszComponentGUID) - 3)
  62. {
  63. SET_HRERR_AND_EXIT(ERROR_INSUFFICIENT_BUFFER);
  64. }
  65. ASSERT_NTC(pp[0] == L'{');
  66. pp++;
  67. // switch the first 8 digit : switch every 8
  68. for ( DWORD i = 0; i < 8; i++)
  69. pszRegKey[i] = pp[7 - i];
  70. // 1st 4 digits : switch every 4
  71. pp = pp + 8 + 1; // skip "-"
  72. for ( i = 0; i < 4; i++)
  73. {
  74. pszRegKey[i + 8]= pp[3 - i];
  75. }
  76. // 2nd 4 digits : switch every 4
  77. pp = pp + 4 + 1; // skip "-"
  78. for ( i = 0; i < 4; i++)
  79. {
  80. pszRegKey[i + 8 + 4]= pp[3 - i];
  81. }
  82. // 3rd 4 digits : switch every 2
  83. pp = pp + 4 + 1; // skip "-"
  84. for ( i = 0; i < 2; i++)
  85. {
  86. pszRegKey[2*i + 8 + 4 + 4]= pp[2*i + 1];
  87. pszRegKey[2*i + 8 + 4 + 4 + 1]= pp[2*i];
  88. }
  89. // for the last 12 digits
  90. pp = pp + 4 + 1; // skip "-"
  91. for (i=0; i<6; i++)
  92. {
  93. pszRegKey[2*i + 8 + 4 + 4 + 4]= pp[2*i + 1];
  94. pszRegKey[2*i + 8 + 4 + 4 + 4 + 1]= pp[2*i];
  95. }
  96. pszRegKey[32] = L'\0';
  97. Exit:
  98. return hr;
  99. }
  100. HRESULT W98DeleteComponentKeyFromMsiUserData(PCWSTR pszComponentRegKeyName)
  101. {
  102. HRESULT hr = S_OK;
  103. CStringBuffer sbRegKey;
  104. LONG iRet;
  105. IFFALSE_EXIT(sbRegKey.Win32Assign(g_szMSIW98KeyName, NUMBER_OF(g_szMSIW98KeyName)-1));
  106. IFFALSE_EXIT(sbRegKey.Win32Append(pszComponentRegKeyName, wcslen(pszComponentRegKeyName)));
  107. //
  108. // About RegDeleteKey :
  109. // Windows 95/98/Me: The function also deletes all subkeys and values. To delete a key only if the key has no subkeys
  110. // or values, use the SHDeleteEmptyKey function.
  111. //
  112. // Windows NT/2000 or later: The subkey to be deleted must not have subkeys. To delete a key and all its subkeys, you
  113. // need to recursively enumerate the subkeys and delete them individually. To recursively delete keys, use the SHDeleteKey
  114. // function.
  115. iRet = RegDeleteKeyW(HKEY_LOCAL_MACHINE, sbRegKey);
  116. if (iRet != ERROR_SUCCESS)
  117. {
  118. if (iRet == ERROR_FILE_NOT_FOUND) // this RegKey does not exist
  119. {
  120. goto Exit;
  121. }
  122. else if (iRet == ERROR_ACCESS_DENIED) // have subKeys underneath
  123. {
  124. if (SHDeleteKey(HKEY_LOCAL_MACHINE, sbRegKey) == ERROR_SUCCESS)
  125. goto Exit;
  126. }
  127. SET_HRERR_AND_EXIT(::GetLastError());
  128. }
  129. Exit:
  130. return hr;
  131. }
  132. HRESULT NtDeleteComponentKeyFromMsiUserData(PCWSTR pszComponentRegKeyName)
  133. {
  134. HRESULT hr = S_OK;
  135. CStringBuffer sbRegKey;
  136. LONG iRet;
  137. HKEY hkUserData = NULL;
  138. SIZE_T cchRegKey;
  139. WCHAR bufSID[128]; //S-1-5-21-2127521184-1604012920-1887927527-88882
  140. DWORD cchSID = NUMBER_OF(bufSID);
  141. DWORD index;
  142. IFFALSE_EXIT(sbRegKey.Win32Assign(g_szMSIUserDataTreeKeyName, NUMBER_OF(g_szMSIUserDataTreeKeyName)-1));
  143. IF_NOTSUCCESS_SET_HRERR_EXIT(RegOpenKeyExW(HKEY_LOCAL_MACHINE, sbRegKey, 0, KEY_READ, &hkUserData));
  144. cchRegKey = sbRegKey.Cch();
  145. index = 0;
  146. iRet = RegEnumKeyExW(hkUserData, index, bufSID, &cchSID, NULL, NULL, NULL, NULL);
  147. while ((iRet == ERROR_SUCCESS) || (iRet == ERROR_MORE_DATA))
  148. {
  149. sbRegKey.Left(cchRegKey);
  150. //
  151. // construct RegKey name of a Component
  152. // in the format of HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\0020F700D33C1D112897000CF42C6133
  153. //
  154. IFFALSE_EXIT(sbRegKey.Win32EnsureTrailingPathSeparator());
  155. IFFALSE_EXIT(sbRegKey.Win32Append(bufSID, cchSID));
  156. IFFALSE_EXIT(sbRegKey.Win32EnsureTrailingPathSeparator());
  157. IFFALSE_EXIT(sbRegKey.Win32Append(g_szComponentKeyName, NUMBER_OF(g_szComponentKeyName)-1));
  158. IFFALSE_EXIT(sbRegKey.Win32EnsureTrailingPathSeparator());
  159. IFFALSE_EXIT(sbRegKey.Win32Append(pszComponentRegKeyName, wcslen(pszComponentRegKeyName)));
  160. //
  161. // About RegDeleteKey :
  162. // Windows 95/98/Me: The function also deletes all subkeys and values. To delete a key only if the key has no subkeys
  163. // or values, use the SHDeleteEmptyKey function.
  164. //
  165. // Windows NT/2000 or later: The subkey to be deleted must not have subkeys. To delete a key and all its subkeys, you
  166. // need to recursively enumerate the subkeys and delete them individually. To recursively delete keys, use the SHDeleteKey
  167. // function.
  168. iRet = RegDeleteKeyW(HKEY_LOCAL_MACHINE, sbRegKey);
  169. if (iRet != ERROR_SUCCESS)
  170. {
  171. if (iRet == ERROR_FILE_NOT_FOUND) // this RegKey does not exist
  172. {
  173. goto cont;
  174. }
  175. else if (iRet == ERROR_ACCESS_DENIED) // have subKeys underneath
  176. {
  177. if (SHDeleteKey(HKEY_LOCAL_MACHINE, sbRegKey) == ERROR_SUCCESS)
  178. goto cont;
  179. }
  180. SET_HRERR_AND_EXIT(::GetLastError());
  181. }
  182. cont:
  183. index ++;
  184. cchSID = NUMBER_OF(bufSID);
  185. iRet = RegEnumKeyExW(hkUserData, index, bufSID, &cchSID, NULL, NULL, NULL, NULL);
  186. if (cchSID > NUMBER_OF(bufSID))
  187. {
  188. SET_HRERR_AND_EXIT(ERROR_INSUFFICIENT_BUFFER);
  189. }
  190. if (iRet == ERROR_NO_MORE_ITEMS)
  191. break;
  192. }
  193. if (iRet != ERROR_NO_MORE_ITEMS)
  194. {
  195. SET_HRERR_AND_EXIT(::GetLastError());
  196. }
  197. Exit:
  198. RegCloseKey(hkUserData);
  199. return hr;
  200. }
  201. HRESULT DeleteComponentKeyFromMsiUserData(PCWSTR pszComponentRegKeyName)
  202. {
  203. HRESULT hr = S_OK;
  204. if (GetModuleHandleA("w95upgnt.dll") == NULL) // no Freelibrary is needed, ref counter is not changed
  205. {
  206. // must be upgration from NT(4.0 or 5)to xp
  207. hr = NtDeleteComponentKeyFromMsiUserData(pszComponentRegKeyName);
  208. }
  209. else
  210. {
  211. // must be upgrate from w9x to xp
  212. hr = W98DeleteComponentKeyFromMsiUserData(pszComponentRegKeyName);
  213. }
  214. return hr;
  215. }
  216. // Function:
  217. // (1) open database
  218. // (2) if (this msi contain at least win32 assembly component)
  219. // (3) get this componentID
  220. // (4) delete the RegKey from all subtrees under
  221. // (5) endif
  222. //
  223. HRESULT MigrateSingleFusionWin32AssemblyToXP(PCWSTR filename)
  224. {
  225. HRESULT hr = S_OK;
  226. PMSIHANDLE hdb = NULL;
  227. PMSIHANDLE hView = NULL;
  228. MSIHANDLE hRecord = NULL;
  229. WCHAR sqlbuf[CA_MAX_BUF * 2];
  230. WCHAR szComponentID[CA_MAX_BUF];
  231. DWORD cchComponentID;
  232. WCHAR szComponentRegKey[CA_MAX_BUF];
  233. DWORD cchComponentRegKey;
  234. BOOL fExist;
  235. ULONG iRet;
  236. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiOpenDatabaseW(filename, LPCWSTR(MSIDBOPEN_DIRECT), &hdb));
  237. IFFAILED_EXIT(MSI_IsTableExist(hdb, L"MsiAssembly", fExist));
  238. if ( fExist == FALSE)
  239. goto Exit;
  240. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, ca_sqlQuery[CA_SQL_QUERY_MSIASSEMBLY], &hView));
  241. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
  242. for (;;)
  243. {
  244. //
  245. // for each entry in MsiAssembly Table
  246. //
  247. iRet = MsiViewFetch(hView, &hRecord);
  248. if (iRet == ERROR_NO_MORE_ITEMS)
  249. break;
  250. if (iRet != ERROR_SUCCESS )
  251. SET_HRERR_AND_EXIT(iRet);
  252. iRet = MsiRecordGetInteger(hRecord, 1);
  253. if ( iRet != MSI_FUSION_WIN32_ASSEMBLY)
  254. continue;
  255. //
  256. // get componentID
  257. //
  258. cchComponentID = NUMBER_OF(szComponentID);
  259. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 3, szComponentID, &cchComponentID));
  260. MsiCloseHandle(hRecord);
  261. break;
  262. }
  263. //
  264. // get Component GUID
  265. //
  266. swprintf(sqlbuf, ca_sqlQuery[CA_SQL_QUERY_COMPONENT_FOR_COMPONENTGUID], szComponentID);
  267. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, sqlbuf, &hView));
  268. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
  269. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiViewFetch(hView, &hRecord));
  270. cchComponentID = NUMBER_OF(szComponentID); // reuse szComponentID
  271. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 1, szComponentID, &cchComponentID));
  272. //
  273. // get MSI-ComponentRegKey
  274. //
  275. cchComponentRegKey = NUMBER_OF(szComponentRegKey);
  276. IFFAILED_EXIT(ConvertComponentGUID(szComponentID, szComponentRegKey, cchComponentRegKey));
  277. // delete MSI-ComponentRegKey from all subtrees of \\install\userdata\user-sid
  278. IFFAILED_EXIT(DeleteComponentKeyFromMsiUserData(szComponentRegKey));
  279. Exit:
  280. MsiCloseHandle(hRecord);
  281. return hr;
  282. }
  283. CDirWalk::ECallbackResult
  284. MsiInstallerDirectoryDirWalkCallback(
  285. CDirWalk::ECallbackReason reason,
  286. CDirWalk* dirWalk
  287. )
  288. {
  289. CDirWalk::ECallbackResult result = CDirWalk::eKeepWalking;
  290. if (reason == CDirWalk::eFile)
  291. {
  292. //
  293. CStringBuffer filename;
  294. if (filename.Win32Assign(dirWalk->m_strParent) == FALSE)
  295. {
  296. goto Error;
  297. }
  298. if (!filename.Win32AppendPathElement(dirWalk->m_strLastObjectFound))
  299. {
  300. goto Error;
  301. }
  302. #if DBG
  303. ASSERT_NTC(IsMsiFile(filename) == TRUE);
  304. #endif
  305. if (!SUCCEEDED(MigrateSingleFusionWin32AssemblyToXP(filename)))
  306. {
  307. goto Error;
  308. }
  309. }
  310. Exit:
  311. return result;
  312. Error:
  313. result = CDirWalk::eError;
  314. goto Exit;
  315. }
  316. HRESULT MsiInstallerDirectoryDirWalk(PCWSTR pszParentDirectory)
  317. {
  318. HRESULT hr = S_OK;
  319. CDirWalk dirWalk;
  320. const static PCWSTR filters[]={L"*.msi"};
  321. PWSTR pszParentDir = NULL;
  322. WCHAR buf[64];
  323. #if DBG
  324. MessageBox(NULL, "In fusemig.dll", "fusemig", MB_OK);
  325. #endif
  326. if (pszParentDirectory == NULL)
  327. {
  328. UINT iret = ExpandEnvironmentStringsW(MsiInstallDir, buf, NUMBER_OF(buf));
  329. if ((iret == 0) || (iret > NUMBER_OF(buf)))
  330. {
  331. SET_HRERR_AND_EXIT(::GetLastError());
  332. }
  333. pszParentDir = buf;
  334. }else
  335. {
  336. pszParentDir = const_cast<PWSTR>(pszParentDirectory);
  337. }
  338. dirWalk.m_fileFiltersBegin = filters;
  339. dirWalk.m_fileFiltersEnd = filters + NUMBER_OF(filters);
  340. dirWalk.m_context = NULL;
  341. dirWalk.m_callback = MsiInstallerDirectoryDirWalkCallback;
  342. IFFALSE_EXIT(dirWalk.m_strParent.Win32Assign(pszParentDir, wcslen(pszParentDir)));
  343. IFFALSE_EXIT(dirWalk.m_strParent.Win32RemoveTrailingPathSeparators());
  344. IFFALSE_EXIT(dirWalk.Walk());
  345. Exit:
  346. return hr;
  347. }