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.

467 lines
16 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. catest.cpp
  5. Abstract:
  6. Test Function calls for ca_policy
  7. Function:
  8. This tool would generate a new msi for the package which contains a Fusion-Win32 Policy, which fails on XP Client.
  9. The user need generate a new msi on one local drive based the original msi. The difference between these two msi would
  10. include :
  11. (1) add entry of SourceDir into Property Table : SourceDir = CDROM\Source
  12. (2) add entry of ResolveSource into InstallExecuteSequence Table
  13. (3) change Component::Condition to be FALSE for Fusion-Win32-Policy component
  14. (4) Add CustomAction:
  15. a. add ca_policy.dll into Binary Table
  16. b. add Fusion_Win32_Policy_Installation action into Custom Action Table
  17. c. add Fusion_Win32_Policy_Installation action into InstallExecuteSequence Table
  18. Author:
  19. Xiaoyu Wu(xiaoyuw) 01-Aug-2001
  20. --*/
  21. #include "stdinc.h"
  22. #include "macros.h"
  23. #include "fusionbuffer.h"
  24. #include "msi.h"
  25. #include "msiquery.h"
  26. #define CA_TEST_NEWMSI_EXTENSION L".new.msi"
  27. #define CA_TEST_NEWMSI_TEMPLATE L"%ProgramFiles%\\msmgen\\templates\\ca_msi.msi"
  28. #define CA_TEST_BINARY_NAME L"FusionWin32Policy_CustomAction_DLL"
  29. #define CA_TEST_BINARY_VALUE L"%ProgramFiles%\\msmgen\\ca_policy\\ca_pol.dll"
  30. #define CA_TEST_CUSTOMACTION_ACTION L"FusionWin32Policy_CustomAction_Action"
  31. #define CA_TEST_CUSTOMACTION_TARGET L"CustomAction_SxsPolicy"
  32. #define CA_TEST_WIN32_POLICY L"win32-policy"
  33. #define CA_TEST_CUSTOMACTION_TYPE 1
  34. #define CA_TEST_RESOLVE_SOURCE_SEQUENCE_NUM 850
  35. #define CA_TEST_INSERT_BINARY 0
  36. #define CA_TEST_INSERT_CUSTOMACTION 1
  37. #define CA_TEST_INSERT_INSTALL_EXECUTION_SEQUENCE 2
  38. #define CA_TEST_INSERT_PROPERTY 3
  39. #define CA_TEST_DEFAULT_CA_SEQUENCE_NUMBER 1450
  40. static PCWSTR sqlInsert[]=
  41. {
  42. L"INSERT INTO Binary(Name, Data) VALUES (?, ?)",
  43. L"INSERT INTO CustomAction(Action, Type, Source,Target) VALUES (?, ?, ?, ?)",
  44. L"INSERT INTO InstallExecuteSequence(Action, Condition, Sequence) VALUES(?, NULL, ?)",
  45. L"INSERT INTO Property(Property, Value) VALUES(?, ?)"
  46. };
  47. static PCWSTR sqlQuery[]=
  48. {
  49. L"SELECT `Component_`,`Value` FROM `MsiAssemblyName` WHERE `Name`='type'", // check whether it is a policy file
  50. L"SELECT `Attributes` FROM `MsiAssembly` WHERE `Component_`='%s'", // check whether it is a win32 assembly
  51. };
  52. static WCHAR sqlUpdate[]= L"UPDATE `%s` SET `%s` = '%s' WHERE `%s`='%s'";
  53. #define CA_TEST_QUERY_MSIASSEMBLYNAME 0
  54. #define CA_TEST_QUERY_MSIASSEMBLY 1
  55. typedef struct _CA_TEST_PACKAGE_INFO
  56. {
  57. CSmallStringBuffer m_sbSourcePath; // fully-qualified filename of the msi file
  58. CSmallStringBuffer m_sbDestinationMsi; // fullpath of new file msi
  59. DWORD m_cchSourceMsi;
  60. DWORD m_cchSourcePath;
  61. MSIHANDLE m_hdb;
  62. BOOL m_fFusionWin32Policy;
  63. UINT m_iCAInstallSequenceNum;
  64. }CA_TEST_PACKAGE_INFO;
  65. CA_TEST_PACKAGE_INFO ginfo;
  66. //
  67. // (1)the user must specify msi(could be non-fully-qualified filename) by using "-msi"
  68. // (2)user could set the destination of new msi, it could be a path or a fully-qualified filename
  69. // if no dest is specified, it would try to generate the msi on the same place of original msi, with a name
  70. // like oldname_new.msi
  71. //
  72. void PrintUsage(WCHAR * exe)
  73. {
  74. fprintf(stderr, "Usage: %S <options> \n",exe);
  75. fprintf(stderr, "Generate a new msi for an assembly\n");
  76. fprintf(stderr, "[-dest full-path]\n");
  77. fprintf(stderr, "-ca sequNum\n"); // the sequence must be after CostFinalize
  78. fprintf(stderr, "-msi msi_filename\n");
  79. return;
  80. }
  81. HRESULT ParseInputParameter(wchar_t *exe, int argc, wchar_t** argv, CA_TEST_PACKAGE_INFO &info)
  82. {
  83. ULONG i = 0 ;
  84. DWORD nRet;
  85. PWSTR psz = NULL;
  86. WCHAR buf[MAX_PATH];
  87. HRESULT hr = S_OK;
  88. info.m_cchSourceMsi = 0;
  89. info.m_cchSourcePath = 0;
  90. info.m_fFusionWin32Policy = FALSE;
  91. info.m_hdb = NULL;
  92. info.m_iCAInstallSequenceNum = 0;
  93. while (i < argc)
  94. {
  95. if (argv[i][0] != L'-')
  96. goto Invalid_Param;
  97. if (wcscmp(argv[i], L"-msi") == 0 )
  98. {
  99. i ++;
  100. psz = argv[i];
  101. nRet = GetFullPathNameW(psz, NUMBER_OF(buf), buf, NULL);
  102. if ((nRet == 0 ) || (nRet >NUMBER_OF(buf)))
  103. SET_HRERR_AND_EXIT(::GetLastError());
  104. psz = wcsrchr(buf, L'\\');
  105. ASSERT_NTC(psz != NULL);
  106. psz ++; // skip "\"
  107. info.m_cchSourcePath = ((ULONG)psz - (ULONG)buf)/sizeof(WCHAR);
  108. IFFALSE_EXIT(info.m_sbSourcePath.Win32Assign(buf, wcslen(buf)));
  109. info.m_cchSourceMsi = info.m_sbSourcePath.Cch();
  110. }else if (wcscmp(argv[i], L"-dest") == 0 )
  111. {
  112. i ++;
  113. psz = argv[i];
  114. nRet = GetFullPathNameW(psz, NUMBER_OF(buf), buf, NULL);
  115. if ((nRet == 0 ) || (nRet >NUMBER_OF(buf)))
  116. SET_HRERR_AND_EXIT(::GetLastError());
  117. IFFALSE_EXIT(info.m_sbDestinationMsi.Win32Assign(buf, wcslen(buf)));
  118. }
  119. else if (wcscmp(argv[i], L"-ca") == 0 )
  120. {
  121. i ++;
  122. psz = argv[i];
  123. info.m_iCAInstallSequenceNum = _wtoi(psz);
  124. }else
  125. goto Invalid_Param;
  126. i ++;
  127. } // end of while
  128. if (info.m_sbSourcePath.Cch() == 0)
  129. goto Invalid_Param;
  130. if (info.m_iCAInstallSequenceNum == 0)
  131. info.m_iCAInstallSequenceNum = CA_TEST_DEFAULT_CA_SEQUENCE_NUMBER;
  132. if (info.m_sbDestinationMsi.Cch() == 0)
  133. IFFALSE_EXIT(info.m_sbDestinationMsi.Win32Assign(info.m_sbSourcePath, info.m_cchSourcePath));
  134. nRet = ::GetFileAttributesW(info.m_sbDestinationMsi);
  135. if ((nRet != DWORD(-1)) && (nRet & FILE_ATTRIBUTE_DIRECTORY))
  136. {
  137. //
  138. // if the name of new msi does not specified, use the original msi filename
  139. //
  140. IFFALSE_EXIT(info.m_sbDestinationMsi.Win32EnsureTrailingPathSeparator());
  141. IFFALSE_EXIT(info.m_sbDestinationMsi.Win32Append(info.m_sbSourcePath + info.m_cchSourcePath,
  142. info.m_cchSourceMsi - info.m_cchSourcePath));
  143. IFFALSE_EXIT(info.m_sbDestinationMsi.Win32Append(CA_TEST_NEWMSI_EXTENSION, NUMBER_OF(CA_TEST_NEWMSI_EXTENSION) - 1));
  144. }
  145. goto Exit;
  146. Invalid_Param:
  147. hr = E_INVALIDARG;
  148. PrintUsage(exe);
  149. Exit:
  150. return hr;
  151. }
  152. //
  153. // change Component::Condition of Fusion Win32 policy to be FALSE
  154. //
  155. HRESULT UpdateComponentTable(CA_TEST_PACKAGE_INFO & info)
  156. {
  157. WCHAR szbuf[128];
  158. UINT iValue;
  159. WCHAR tmp[256];
  160. PMSIHANDLE hView = NULL;
  161. PMSIHANDLE hRecord = NULL;
  162. HRESULT hr = S_OK;
  163. UINT iRet;
  164. DWORD cchbuf;
  165. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info.m_hdb, sqlQuery[CA_TEST_QUERY_MSIASSEMBLYNAME], &hView));
  166. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
  167. for (;;)
  168. {
  169. iRet = MsiViewFetch(hView, &hRecord);
  170. if (iRet == ERROR_NO_MORE_ITEMS)
  171. break;
  172. if (iRet != ERROR_SUCCESS )
  173. SET_HRERR_AND_EXIT(iRet);
  174. //
  175. // check whether it is policy : Note that the value of attribute is case-insensitive...
  176. //
  177. cchbuf = NUMBER_OF(szbuf);
  178. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 2, szbuf, &cchbuf));
  179. if (_wcsicmp(szbuf, CA_TEST_WIN32_POLICY) != 0)
  180. continue;
  181. //
  182. // get ComponentID
  183. //
  184. cchbuf = NUMBER_OF(szbuf);
  185. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetString(hRecord, 1, szbuf, &cchbuf));
  186. {
  187. //
  188. // check whether this a win32 Assembly
  189. //
  190. PMSIHANDLE hView = NULL;
  191. PMSIHANDLE hRecord = NULL;
  192. swprintf(tmp, sqlQuery[CA_TEST_QUERY_MSIASSEMBLY], szbuf);
  193. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info.m_hdb, tmp, &hView));
  194. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
  195. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiViewFetch(hView, &hRecord)); // this call should succeed otherwise fail
  196. iValue = MsiRecordGetInteger(hRecord, 1);
  197. MsiCloseHandle(hRecord);
  198. }
  199. if (iValue != 1)
  200. continue;
  201. {
  202. //
  203. // update Component__Condtion to be FALSE
  204. //
  205. PMSIHANDLE hView = NULL;
  206. PMSIHANDLE hRecord = NULL;
  207. swprintf(tmp, sqlUpdate, L"Component", L"Condition", L"FALSE", L"Component", szbuf);
  208. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info.m_hdb, tmp, &hView));
  209. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
  210. MsiCloseHandle(hRecord);
  211. if (info.m_fFusionWin32Policy == FALSE)
  212. info.m_fFusionWin32Policy = TRUE;
  213. }
  214. } // end of for MsiFetchRecord
  215. Exit:
  216. return hr;
  217. }
  218. HRESULT ImportTablesIfNeeded(CA_TEST_PACKAGE_INFO & info)
  219. {
  220. ASSERT_NTC(info.m_fFusionWin32Policy == TRUE);
  221. WCHAR buf[MAX_PATH];
  222. UINT iRet;
  223. HRESULT hr = S_OK;
  224. PMSIHANDLE hDatabase = NULL;
  225. iRet = ExpandEnvironmentStringsW(CA_TEST_NEWMSI_TEMPLATE, buf, NUMBER_OF(buf));
  226. if ((iRet == 0) || (iRet > NUMBER_OF(buf)))
  227. SET_HRERR_AND_EXIT(::GetLastError());
  228. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiOpenDatabaseW(buf, (LPCWSTR)MSIDBOPEN_READONLY, &hDatabase));
  229. ASSERT_NTC(info.m_hdb != NULL);
  230. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiDatabaseMerge(info.m_hdb, hDatabase, NULL));
  231. Exit:
  232. if (hDatabase != NULL)
  233. {
  234. MsiCloseHandle(hDatabase);
  235. }
  236. return hr;
  237. }
  238. //
  239. // add ca_policy to CustomAction
  240. //
  241. HRESULT AddEntryIntoDB(CA_TEST_PACKAGE_INFO & info)
  242. {
  243. PMSIHANDLE hRecord = NULL;
  244. PMSIHANDLE hView = NULL;
  245. WCHAR tmp[256];
  246. HRESULT hr = S_OK;
  247. UINT iRet;
  248. CSmallStringBuffer buf;
  249. //
  250. // Insert BinaryTable
  251. //
  252. hRecord = MsiCreateRecord(2);
  253. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetStringW(hRecord, 1, CA_TEST_BINARY_NAME));
  254. iRet = ExpandEnvironmentStringsW(CA_TEST_BINARY_VALUE, tmp, NUMBER_OF(tmp));
  255. if ((iRet == 0) || (iRet > NUMBER_OF(tmp)))
  256. SET_HRERR_AND_EXIT(::GetLastError());
  257. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetStreamW(hRecord, 2, tmp));
  258. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info.m_hdb, sqlInsert[CA_TEST_INSERT_BINARY], &hView));
  259. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, hRecord));
  260. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hView));
  261. hView = NULL;
  262. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hRecord));
  263. hRecord = NULL;
  264. //
  265. // insert CustionAction Table
  266. //
  267. hRecord = MsiCreateRecord(4);
  268. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetStringW(hRecord, 1, CA_TEST_CUSTOMACTION_ACTION));
  269. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetInteger(hRecord, 2, CA_TEST_CUSTOMACTION_TYPE));
  270. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetStringW(hRecord, 3, CA_TEST_BINARY_NAME));
  271. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetStringW(hRecord, 4, CA_TEST_CUSTOMACTION_TARGET));
  272. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info.m_hdb, sqlInsert[CA_TEST_INSERT_CUSTOMACTION], &hView));
  273. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, hRecord));
  274. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hView));
  275. hView = NULL;
  276. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hRecord));
  277. hRecord = NULL;
  278. //
  279. // insert myAction into CA_TEST_INSERT_INSTALL_EXECUTION_SEQUENCE
  280. //
  281. hRecord = MsiCreateRecord(2);
  282. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetStringW(hRecord, 1, CA_TEST_CUSTOMACTION_ACTION));
  283. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetInteger(hRecord, 2, info.m_iCAInstallSequenceNum));
  284. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info.m_hdb, sqlInsert[CA_TEST_INSERT_INSTALL_EXECUTION_SEQUENCE], &hView));
  285. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, hRecord));
  286. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hView));
  287. hView = NULL;
  288. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hRecord));
  289. hRecord = NULL;
  290. //
  291. // insert PropertyTable about SourceDir
  292. //
  293. hRecord = MsiCreateRecord(2);
  294. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetStringW(hRecord, 1, L"SourceDir"));
  295. IFFALSE_EXIT(buf.Win32Assign(info.m_sbSourcePath, info.m_cchSourcePath));
  296. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetStringW(hRecord, 2, buf));
  297. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info.m_hdb, sqlInsert[CA_TEST_INSERT_PROPERTY], &hView));
  298. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, hRecord));
  299. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hView));
  300. hView = NULL;
  301. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hRecord));
  302. hRecord = NULL;
  303. //
  304. // insert ResolveSource into CA_TEST_INSERT_INSTALL_EXECUTION_SEQUENCE
  305. //
  306. hRecord = MsiCreateRecord(2);
  307. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetStringW(hRecord, 1, L"ResolveSource"));
  308. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordSetInteger(hRecord, 2, CA_TEST_RESOLVE_SOURCE_SEQUENCE_NUM));
  309. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info.m_hdb, sqlInsert[CA_TEST_INSERT_INSTALL_EXECUTION_SEQUENCE], &hView));
  310. IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, hRecord));
  311. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hView));
  312. hView = NULL;
  313. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiCloseHandle(hRecord));
  314. hRecord = NULL;
  315. Exit:
  316. if (hView != NULL)
  317. MsiCloseHandle(hView);
  318. if (hRecord != NULL)
  319. MsiCloseHandle(hRecord);
  320. return hr;
  321. }
  322. HRESULT GenerateTestMsiForFusionPolicyInstallOnXPClient(CA_TEST_PACKAGE_INFO & info)
  323. {
  324. ASSERT_NTC(info.m_sbSourcePath.Cch() != 0);
  325. ASSERT_NTC(info.m_sbDestinationMsi.Cch() != 0);
  326. ASSERT_NTC(info.m_cchSourceMsi != 0);
  327. ASSERT_NTC(info.m_cchSourcePath != 0);
  328. ASSERT_NTC(info.m_iCAInstallSequenceNum != 0);
  329. HRESULT hr = S_OK;
  330. IFFALSE_EXIT(CopyFileW(info.m_sbSourcePath, info.m_sbDestinationMsi, FALSE));
  331. IFFALSE_EXIT(SetFileAttributesW(info.m_sbDestinationMsi, FILE_ATTRIBUTE_NORMAL));
  332. IF_NOTSUCCESS_SET_HRERR_EXIT(MsiOpenDatabaseW(info.m_sbDestinationMsi, (LPCWSTR)MSIDBOPEN_DIRECT, &info.m_hdb));
  333. IFFAILED_EXIT(UpdateComponentTable(info));
  334. if (info.m_fFusionWin32Policy == TRUE)
  335. {
  336. IFFAILED_EXIT(ImportTablesIfNeeded(info));
  337. IFFAILED_EXIT(AddEntryIntoDB(info));
  338. }else
  339. {
  340. printf("This package does contain FusionWin32 Policy, use the original msi for installation!");
  341. }
  342. Exit:
  343. if (info.m_hdb != NULL)
  344. {
  345. if ( SUCCEEDED(hr))
  346. MsiDatabaseCommit(info.m_hdb);
  347. MsiCloseHandle(info.m_hdb);
  348. }
  349. return hr;
  350. }
  351. extern "C" int __cdecl wmain(int argc, wchar_t** argv)
  352. {
  353. HRESULT hr = S_OK;
  354. if ((argc < 3) && ((argc % 2) != 1))
  355. {
  356. PrintUsage(argv[0]);
  357. hr = E_INVALIDARG;
  358. goto Exit;
  359. }
  360. //
  361. // set SourcePath and Destination Path of the package
  362. //
  363. IFFAILED_EXIT(ParseInputParameter(argv[0], argc-1 , argv+1, ginfo));
  364. //
  365. // - CustomAction table : one entry for CA
  366. // - Binary table : containing the binary stream of this dll
  367. // - InstallExecuteSequence : add one entry for CA
  368. // - add SourceDir into Property Table
  369. // - add ResolveSource into InstallExecuteSequence Table
  370. //
  371. IFFAILED_EXIT(GenerateTestMsiForFusionPolicyInstallOnXPClient(ginfo));
  372. #ifdef CA_TEST_TEST
  373. //
  374. // install this msi
  375. //
  376. if (ginfo.m_fFusionWin32Policy)
  377. MsiInstallProduct(ginfo.m_sbDestinationMsi, NULL);
  378. #endif
  379. Exit:
  380. return hr;
  381. }