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.

430 lines
15 KiB

  1. #include "stdinc.h"
  2. #include "macros.h"
  3. #include "common.h"
  4. #include "idp.h"
  5. #include "sxsutil.h"
  6. #include "fusionbuffer.h"
  7. #include "fusionheap.h"
  8. #define FUSION_WIN32_ASSEMBLY_DUP_FILEKEY_PREFIX L"winsxs_"
  9. #define MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME L"MsiFusionWin32AssemblyCache"
  10. #define MSI_ASSEMBLYCACHE_DIRECTORY L"winsxs"
  11. #define MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME L"MsiFusionWin32AssemblyManifestCache"
  12. #define MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY L"Manifests"
  13. #define MSI_ASSEMBLY_MANIFEST_COMPONENT_KEYNAME L"MsiFusionWin32AssemblyManifestComponent"
  14. #define MANIFEST_FILE_EXT L".Manifest"
  15. #define CATALOG_FILE_EXT L".cat"
  16. ///////////////////////////////////////////////////////////////////////////////
  17. // Assumption : at this moment,we asusme that DuplicateFile table EXISTS
  18. /////////////////////////////////////////////////////////////////////////////////
  19. HRESULT CA_DuplicationWin32AssemblyFiles_Callback(const CA_ENM_ASSEMBLY_CALLBACK_INFO * info)
  20. {
  21. HRESULT hr = S_OK;
  22. CStringBuffer sbDupFileKey;
  23. CStringBuffer sbDupFileName;
  24. CSmallStringBuffer sbExt;
  25. bool fManifest = false;
  26. bool fCatalog = false;
  27. PARAMETER_CHECK_NTC(info != NULL);
  28. PARAMETER_CHECK_NTC(info->pszFileID != NULL);
  29. PARAMETER_CHECK_NTC(info->pszFileName);
  30. sbDupFileKey.Win32Assign(FUSION_WIN32_ASSEMBLY_DUP_FILEKEY_PREFIX, wcslen(FUSION_WIN32_ASSEMBLY_DUP_FILEKEY_PREFIX));
  31. sbDupFileKey.Win32Append(info->pszFileID, wcslen(info->pszFileID));
  32. IFFALSE_EXIT(sbDupFileName.Win32Assign(info->pszFileName, wcslen(info->pszFileName)));
  33. IFFALSE_EXIT(sbDupFileName.Win32GetPathExtension(sbExt));
  34. //
  35. //rename manifest file and catalog file
  36. //
  37. if ((FusionpCompareStrings(sbExt, sbExt.Cch(), L"man", wcslen(L"man"), true) == 0) ||
  38. (FusionpCompareStrings(sbExt, sbExt.Cch(), L"manifest", wcslen(L"manifest"), true) == 0))
  39. {
  40. fManifest = true;
  41. }
  42. else
  43. if ((FusionpCompareStrings(sbExt, sbExt.Cch(), L"cat", wcslen(L"cat"), true) == 0) ||
  44. (FusionpCompareStrings(sbExt, sbExt.Cch(), L"catalog", wcslen(L"catalog"), true) == 0))
  45. {
  46. fCatalog = true;
  47. }
  48. if (fManifest || fCatalog)
  49. {
  50. PARAMETER_CHECK_NTC(info->pszAssemblyUniqueDir != NULL);
  51. IFFALSE_EXIT(sbDupFileName.Win32Assign(info->pszAssemblyUniqueDir, wcslen(info->pszAssemblyUniqueDir)));
  52. // reset the extension of manifest file and catalog file in order to keep the same as XP
  53. IFFALSE_EXIT(sbDupFileName.Win32Append(fManifest? MANIFEST_FILE_EXT : CATALOG_FILE_EXT,
  54. fManifest? wcslen(MANIFEST_FILE_EXT) : wcslen(CATALOG_FILE_EXT)));
  55. }else
  56. {
  57. PARAMETER_CHECK_NTC(info->pszFileName != NULL);
  58. IFFALSE_EXIT(sbDupFileName.Win32Assign(info->pszFileName, wcslen(info->pszFileName)));
  59. }
  60. // if it is a .manifest file or it is a catalog file, put it into winsxs\manifests folder,
  61. // otherwise, put it into winsxs\x86_...._12345678
  62. IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, info->hdb,
  63. OPT_DUPLICATEFILE,
  64. NUMBER_OF_PARAM_TO_INSERT_TABLE_DUPLICATEFILE,
  65. MAKE_PCWSTR(sbDupFileKey),
  66. MAKE_PCWSTR(info->pszComponentID),
  67. MAKE_PCWSTR(info->pszFileID),
  68. MAKE_PCWSTR(sbDupFileName),
  69. (fManifest | fCatalog) ? MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME : MAKE_PCWSTR(info->pszDestFolderID)));
  70. Exit:
  71. return hr;
  72. }
  73. HRESULT GetXPInstalledDirectory(const CA_ENM_ASSEMBLY_CALLBACK_INFO * info, CStringBuffer & sbAsmDir)
  74. {
  75. HRESULT hr = S_OK;
  76. WCHAR sqlbuf[CA_MAX_BUF];
  77. PMSIHANDLE hView = NULL;
  78. PMSIHANDLE hRecord = NULL;
  79. WCHAR bufName[CA_MAX_BUF];
  80. DWORD cchName;
  81. WCHAR bufValue[CA_MAX_BUF];
  82. DWORD cchValue;
  83. BOOL fWin32, fWin32Policy;
  84. CStringBuffer sbPathBuffer;
  85. UINT iRet;
  86. ASSEMBLY_IDENTITY_ATTRIBUTE Attribute;
  87. PASSEMBLY_IDENTITY AssemblyIdentity = NULL;
  88. PARAMETER_CHECK_NTC(info != NULL);
  89. PARAMETER_CHECK_NTC(info->pszComponentID != NULL);
  90. PARAMETER_CHECK_NTC(info->hdb != NULL);
  91. IFFALSE_EXIT(::SxsCreateAssemblyIdentity(0, ASSEMBLY_IDENTITY_TYPE_DEFINITION, &AssemblyIdentity, 0, NULL));
  92. swprintf(sqlbuf, L"SELECT Name, Value FROM MsiAssemblyName WHERE Component_='%s'", info->pszComponentID);
  93. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info->hdb, sqlbuf, &hView));
  94. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
  95. for (;;)
  96. {
  97. //
  98. // for each entry in MsiAssembly Table
  99. //
  100. iRet = MsiViewFetch(hView, &hRecord);
  101. if (iRet == ERROR_NO_MORE_ITEMS)
  102. break;
  103. if (iRet != ERROR_SUCCESS )
  104. SET_HRERR_AND_EXIT(iRet);
  105. cchName = NUMBER_OF(bufName);
  106. cchValue = NUMBER_OF(bufValue);
  107. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 1, bufName, &cchName));
  108. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 2, bufValue, &cchValue));
  109. Attribute.Flags = 0;
  110. Attribute.NamespaceCch = 0;
  111. Attribute.Namespace = NULL;
  112. Attribute.NameCch = cchName;
  113. Attribute.Name = bufName;
  114. Attribute.ValueCch = cchValue;
  115. Attribute.Value = bufValue;
  116. //BUGBUG
  117. // Fusion win32 required that the attribute name is case-sensitive, so, for assembly name,
  118. // it should appear as "name" in MsiAssemblyName, however, for some historical reason,
  119. // it appears as "Name", so, we have to force it to the right thing for win32.
  120. //
  121. // for other attribute in MsiAssemblyName table, there is no such problem,
  122. //
  123. //BUGBUG
  124. if ((Attribute.NameCch == 4) && (_wcsicmp(Attribute.Name, L"name") == 0))
  125. {
  126. Attribute.Name = L"name";
  127. }
  128. IFFALSE_EXIT(::SxsInsertAssemblyIdentityAttribute(0, AssemblyIdentity, &Attribute));
  129. }
  130. IFFALSE_EXIT(SxsHashAssemblyIdentity(0, AssemblyIdentity, NULL));
  131. //
  132. // generate the path, something like x86_ms-sxstest-sfp_75e377300ab7b886_1.0.0.0_en_04f354da
  133. //
  134. IFFAILED_EXIT(ca_SxspDetermineAssemblyType(AssemblyIdentity, fWin32, fWin32Policy));
  135. IFFAILED_EXIT(ca_SxspGenerateSxsPath(
  136. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT | (fWin32Policy ? SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION : 0),
  137. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
  138. NULL,
  139. 0,
  140. AssemblyIdentity,
  141. sbPathBuffer));
  142. IFFALSE_EXIT(sbAsmDir.Win32Assign(sbPathBuffer));
  143. hr = S_OK;
  144. Exit:
  145. SxsDestroyAssemblyIdentity(AssemblyIdentity);
  146. return hr;
  147. }
  148. HRESULT IsCertainRecordExistInDirectoryTable(const MSIHANDLE & hdb, PCWSTR DirectoryKey, BOOL & fExist)
  149. {
  150. HRESULT hr = S_OK;
  151. PMSIHANDLE hRecord = NULL;
  152. PMSIHANDLE hView = NULL;
  153. WCHAR sqlBuf[MAX_PATH];
  154. fExist = FALSE;
  155. swprintf(sqlBuf, ca_sqlQuery[CA_SQL_QUERY_DIRECTORY], DirectoryKey);
  156. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, sqlBuf, &hView));
  157. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
  158. UINT iRet = MsiViewFetch(hView, &hRecord);
  159. if (iRet == ERROR_SUCCESS)
  160. {
  161. fExist = TRUE;
  162. }
  163. else if (iRet == ERROR_NO_MORE_ITEMS)
  164. {
  165. fExist = FALSE;
  166. }
  167. else
  168. SET_HRERR_AND_EXIT(iRet);
  169. hr = S_OK;
  170. Exit:
  171. return hr;
  172. }
  173. //
  174. // add entry to Directory Table and CreateFolder Table
  175. //
  176. HRESULT AddFusionAssemblyDirectories(const CA_ENM_ASSEMBLY_CALLBACK_INFO * info, CStringBuffer & sbDestFolderID)
  177. {
  178. HRESULT hr = S_OK;
  179. BOOL fRecordExist = FALSE;
  180. PARAMETER_CHECK_NTC(info != NULL);
  181. PARAMETER_CHECK_NTC(info->pszAssemblyUniqueDir != NULL);
  182. PARAMETER_CHECK_NTC(info->hdb != NULL);
  183. PARAMETER_CHECK_NTC(info->pszComponentID != NULL);
  184. //
  185. // TODO: here we could make the DirectoryID more unique
  186. //
  187. IFFALSE_EXIT(sbDestFolderID.Win32Assign(info->pszAssemblyUniqueDir, wcslen(info->pszAssemblyUniqueDir)));
  188. IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, info->hdb,
  189. OPT_DIRECTORY,
  190. NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
  191. MAKE_PCWSTR(sbDestFolderID),
  192. MAKE_PCWSTR(MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME),
  193. MAKE_PCWSTR(info->pszAssemblyUniqueDir)));
  194. //
  195. // insert entry to CreateFolder Table
  196. //
  197. IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, info->hdb,
  198. OPT_CREATEFOLDER,
  199. NUMBER_OF_PARAM_TO_INSERT_TABLE_CREATEFOLDER,
  200. MAKE_PCWSTR(sbDestFolderID),
  201. MAKE_PCWSTR(info->pszComponentID)));
  202. hr = S_OK;
  203. Exit:
  204. return hr;
  205. }
  206. HRESULT CheckWhetherUserWantMigrate(const CA_ENM_ASSEMBLY_CALLBACK_INFO * info, BOOL & fMigrateDenied)
  207. {
  208. HRESULT hr = S_OK;
  209. WCHAR pwszSQL[MAX_PATH];
  210. PMSIHANDLE hView = NULL;
  211. PMSIHANDLE hRecord = NULL;
  212. UINT err, iRet;
  213. fMigrateDenied = FALSE;
  214. // NTRAID#NTBUG9 - 589779 - 2002/03/26 - xiaoyuw
  215. // should be replaced with _snwprintf
  216. swprintf(pwszSQL, L"SELECT `fMigrate` FROM `%s` WHERE `Component_` = '%s'", WIN32_ASSEMBLY_MIGRATE_TABLE, info->pszComponentID);
  217. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info->hdb, pwszSQL, &hView));
  218. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
  219. err = ::MsiViewFetch(hView, &hRecord);
  220. switch (err) {
  221. case ERROR_NO_MORE_ITEMS: // not exist in the table, default is migrate-enabled
  222. break;
  223. case ERROR_SUCCESS:
  224. iRet = MsiRecordGetInteger(hRecord, 1);
  225. if ( iRet == 0 )
  226. fMigrateDenied = TRUE;
  227. break;
  228. default:
  229. SET_HRERR_AND_EXIT(err);
  230. }
  231. Exit:
  232. return hr;
  233. }
  234. //
  235. // CA for Fusion Win32 Assembly installation on downlevel(only) :
  236. // (1)set entries for each assembly file in DuplicateFile Table
  237. // (2)after all done, set a RegKey so this would not be done everytime
  238. //
  239. HRESULT __stdcall CA_DuplicationWin32Assembly_Callback(CA_ENM_ASSEMBLY_CALLBACK_INFO * info)
  240. {
  241. HRESULT hr = S_OK;
  242. CStringBuffer sbDestFolder;
  243. CStringBuffer sbDestFolderID;
  244. BOOL fExist = FALSE;
  245. BOOL fMigrateDenied = FALSE;
  246. PARAMETER_CHECK_NTC((info->dwFlags == 0) ||(info->dwFlags == CA_ENM_ASSEMBLY_CALLBACK_INFO_FLAG_IGNORE_MIGRATE_DENY_CHECK));
  247. PARAMETER_CHECK_NTC(info->hInstall != NULL);
  248. PARAMETER_CHECK_NTC(info->pszComponentID != NULL);
  249. PARAMETER_CHECK_NTC(info->pszManifestFileID != NULL);
  250. if (! (info->dwFlags & CA_ENM_ASSEMBLY_CALLBACK_INFO_FLAG_IGNORE_MIGRATE_DENY_CHECK))
  251. {
  252. IFFAILED_EXIT(CheckWhetherUserWantMigrate(info, fMigrateDenied));
  253. if (fMigrateDenied)
  254. goto Exit;
  255. }
  256. //
  257. // get sxs component directory in the format of x86_name_publicKeyToken_1.0.0.0_en_hashvalue
  258. //
  259. IFFAILED_EXIT(GetXPInstalledDirectory(info, sbDestFolder));
  260. info->pszAssemblyUniqueDir = sbDestFolder;
  261. //
  262. // Create an entry for this dir in Directory Table, return DirectoryID in Directory Table
  263. //
  264. IFFAILED_EXIT(AddFusionAssemblyDirectories(info, sbDestFolderID));
  265. info->pszDestFolderID = sbDestFolderID;
  266. IFFAILED_EXIT(MSI_EnumComponentFiles(info, CA_DuplicationWin32AssemblyFiles_Callback));
  267. Exit:
  268. return hr;
  269. }
  270. HRESULT __stdcall CustomAction_CopyFusionWin32AsmIntoAsmCache(MSIHANDLE hInstall)
  271. {
  272. HRESULT hr = S_OK;
  273. BOOL fExist;
  274. MSIHANDLE hdb = NULL;
  275. #if DBG
  276. MessageBoxA(NULL, "Enjoy the Debug", "ca_dup", MB_OK);
  277. #endif
  278. // Before enumerate all the assemblies, do common work right here ....
  279. //
  280. // (1) insert MsiAsmcache into Directory Table if not present
  281. //
  282. hdb = MsiGetActiveDatabase(hInstall);
  283. INTERNAL_ERROR_CHECK_NTC(hdb != NULL);
  284. IFFAILED_EXIT(IsCertainRecordExistInDirectoryTable(hdb, L"WindowsFolder", fExist));
  285. if (fExist == FALSE)
  286. {
  287. IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
  288. OPT_DIRECTORY,
  289. NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
  290. MAKE_PCWSTR(L"WindowsFolder"),
  291. MAKE_PCWSTR(L"TARGETDIR"),
  292. MAKE_PCWSTR(".")));
  293. }
  294. // adding winsxs into Directory Table
  295. IFFAILED_EXIT(IsCertainRecordExistInDirectoryTable(hdb, MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME, fExist));
  296. if (fExist == FALSE)
  297. {
  298. IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
  299. OPT_DIRECTORY,
  300. NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
  301. MAKE_PCWSTR(MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME),
  302. MAKE_PCWSTR(L"WindowsFolder"),
  303. MAKE_PCWSTR(MSI_ASSEMBLYCACHE_DIRECTORY)));
  304. }
  305. // adding winsxs\manifests into Directory table
  306. IFFAILED_EXIT(IsCertainRecordExistInDirectoryTable(hdb, MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME, fExist));
  307. if (fExist == FALSE)
  308. {
  309. IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
  310. OPT_DIRECTORY,
  311. NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
  312. MAKE_PCWSTR(MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME),
  313. MAKE_PCWSTR(MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME),
  314. MAKE_PCWSTR(MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY)));
  315. }
  316. // create a component associated with this Directory too
  317. IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
  318. OPT_COMPONENT,
  319. NUMBER_OF_PARAM_TO_INSERT_TABLE_COMPONENT,
  320. MSI_ASSEMBLY_MANIFEST_COMPONENT_KEYNAME,
  321. MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME));
  322. //create the folder : %windir%\winsxs\manifest
  323. IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
  324. OPT_CREATEFOLDER,
  325. NUMBER_OF_PARAM_TO_INSERT_TABLE_CREATEFOLDER,
  326. MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME,
  327. MSI_ASSEMBLY_MANIFEST_COMPONENT_KEYNAME));
  328. //
  329. //Enumerate all msi assembly in MsiAssemblyTable
  330. //
  331. IFFAILED_EXIT(MSI_EnumWinFuseAssembly(ENUM_ASSEMBLY_FLAG_CHECK_ASSEMBLY_ONLY, hInstall, CA_DuplicationWin32Assembly_Callback));
  332. Exit:
  333. if (hdb)
  334. MsiCloseHandle(hdb);
  335. return hr;
  336. }
  337. BOOL WINAPI DllMain(
  338. HINSTANCE hinstDLL,
  339. DWORD fdwReason,
  340. LPVOID lpvReserved
  341. )
  342. {
  343. if (fdwReason == DLL_PROCESS_ATTACH)
  344. {
  345. FusionpInitializeHeap(NULL);
  346. }
  347. else if (fdwReason == DLL_PROCESS_DETACH)
  348. {
  349. // NTRAID#NTBUG9 - 589779 - 2002/03/26 - xiaoyuw
  350. // FusionpUninitializeHeap should be called when dll is detached
  351. FusionpUninitializeHeap();
  352. }
  353. return TRUE;
  354. }