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.

455 lines
16 KiB

  1. #include "stdinc.h"
  2. #include "st.h"
  3. #include "msiinstall.h"
  4. CDeque<MSIINSTALLTEST_THREAD_PROC_DATA, offsetof(MSIINSTALLTEST_THREAD_PROC_DATA, Linkage)> g_MSIInstallTest;
  5. #define DATA_DIRECTORY_NAME L"msiinstall"
  6. #define SLASH_DATA_DIRECTORY_SLASH_STAR L"\\" DATA_DIRECTORY_NAME L"\\*"
  7. #define SLASH_DATA_DIRECTORY_SLASH L"\\" DATA_DIRECTORY_NAME L"\\"
  8. #define INI_FILE L"msiinstall.ini"
  9. #define SLASH_INI_FILE L"\\msiinstall.ini"
  10. BOOL InitializeMSIInstallTest()
  11. {
  12. BOOL fSuccess = FALSE;
  13. FN_TRACE_WIN32(fSuccess);
  14. CFindFile hFind;
  15. WIN32_FIND_DATAW wfd;
  16. CStringBuffer TempDirectory;
  17. CDequeIterator<MSIINSTALLTEST_THREAD_PROC_DATA, offsetof(MSIINSTALLTEST_THREAD_PROC_DATA, Linkage)> iter(&g_MSIInstallTest);
  18. CStringBuffer IniFilePath;
  19. WCHAR buf[MAX_PATH];
  20. DWORD bufSize = NUMBER_OF(buf);
  21. WCHAR FileKey[10]; // at most, there are 10^10 files in the assembly, including manifest
  22. DWORD rSize;
  23. STRINGBUFFER_LINKAGE * pTinyStringBuffer = NULL;
  24. MSIINSTALLTEST_THREAD_PROC_DATA *pData = NULL;
  25. if (!TempDirectory.Win32Assign(BaseDirectory))
  26. goto Exit;
  27. if (!TempDirectory.Win32AppendPathElement(DATA_DIRECTORY_NAME, NUMBER_OF(DATA_DIRECTORY_NAME) - 1))
  28. goto Exit;
  29. if ((wfd.dwFileAttributes = ::GetFileAttributesW(TempDirectory)) == 0xffffffff
  30. && (wfd.dwFileAttributes = ::FusionpGetLastWin32Error()) == ERROR_FILE_NOT_FOUND)
  31. {
  32. printf("no %ls tests, skipping\n", DATA_DIRECTORY_NAME);
  33. FN_SUCCESSFUL_EXIT();
  34. }
  35. if (!TempDirectory.Win32AppendPathElement(L"*", 1))
  36. goto Exit;
  37. hFind = ::FindFirstFileW(TempDirectory, &wfd);
  38. if (hFind == INVALID_HANDLE_VALUE)
  39. {
  40. ::ReportFailure("Failed to find any files matching \"%ls\"\n", static_cast<PCWSTR>(TempDirectory));
  41. goto Exit;
  42. }
  43. for (;;)
  44. {
  45. CSmallStringBuffer TempString;
  46. CSmallStringBuffer BaseDirectory2;
  47. if (FusionpIsDotOrDotDot(wfd.cFileName))
  48. goto Skip;
  49. if (!BaseDirectory2.Win32Assign(BaseDirectory))
  50. goto Exit;
  51. if (!BaseDirectory2.Win32AppendPathElement(DATA_DIRECTORY_NAME, NUMBER_OF(DATA_DIRECTORY_NAME) - 1))
  52. goto Exit;
  53. if (!BaseDirectory2.Win32AppendPathElement(wfd.cFileName, wcslen(wfd.cFileName)))
  54. goto Exit;
  55. if ((pData = new MSIINSTALLTEST_THREAD_PROC_DATA) == NULL)
  56. {
  57. ::FusionpSetLastWin32Error(ERROR_OUTOFMEMORY);
  58. ::ReportFailure("Failed to allocate MSIINSTALLTEST_THREAD_PROC_DATA\n");
  59. goto Exit;
  60. }
  61. if (!IniFilePath.Win32Assign(BaseDirectory2))
  62. goto Exit;
  63. if (!IniFilePath.Win32AppendPathElement(INI_FILE, NUMBER_OF(INI_FILE) - 1))
  64. goto Exit;
  65. if (GetFileAttributesW(IniFilePath) == DWORD(-1))
  66. {
  67. ::ReportFailure("Failed to find msiinstall.ini from %s.\n", IniFilePath);
  68. goto Exit;
  69. }
  70. //
  71. // get manifest filename
  72. //
  73. rSize = GetPrivateProfileStringW(L"general", L"manifest", L"", buf, bufSize, IniFilePath);
  74. if ((rSize == bufSize - 1) || (rSize == 0))
  75. {
  76. ::ReportFailure("manifest filename in %s is erroneous, either too long or empty\n", IniFilePath);
  77. goto Exit;
  78. }
  79. IFW32FALSE_EXIT(pData->ManifestFileName.Win32Assign(buf, rSize));
  80. //
  81. // get AssemblyNamefromDarwin
  82. //
  83. rSize = GetPrivateProfileStringW(L"general", L"AssemblyNameFromDarwin", L"", buf, bufSize, IniFilePath);
  84. if ((rSize == bufSize - 1) || (rSize == 0))
  85. {
  86. ::ReportFailure("assemblyname from darwin in %s is erroneous, either too long or empty\n", IniFilePath);
  87. goto Exit;
  88. }
  89. IFW32FALSE_EXIT(pData->AssemblyNameFromDarwin.Win32Assign(buf, rSize));
  90. //
  91. // get the SourceFile directory from ini or use the current directory
  92. //
  93. rSize = GetPrivateProfileStringW(L"general", L"AssemblySourceFileDirectory", L"", buf, bufSize, IniFilePath);
  94. if (rSize == bufSize - 1)
  95. goto Exit;
  96. if (rSize != 0)
  97. IFW32FALSE_EXIT(pData->AssemblySourceDirectory.Win32Assign(buf, rSize));
  98. else
  99. IFW32FALSE_EXIT(pData->AssemblySourceDirectory.Win32Assign(BaseDirectory2));
  100. for (DWORD i=0;;i++)
  101. {
  102. swprintf(FileKey, L"%1d", i); // make FileKey in WSTR
  103. rSize = GetPrivateProfileStringW(L"files", FileKey, L"", buf, bufSize, IniFilePath);
  104. if (rSize == bufSize - 1)// the value string in .ini is too long
  105. goto Exit;
  106. if ( rSize == 0 ) // get all
  107. break;
  108. pTinyStringBuffer = new STRINGBUFFER_LINKAGE;
  109. if (pTinyStringBuffer == NULL)
  110. {
  111. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  112. goto Exit;
  113. }
  114. IFW32FALSE_EXIT(pTinyStringBuffer->Str.Win32Assign(buf, rSize));
  115. pData->FileNameOfAssemblyList.AddToTail(pTinyStringBuffer);
  116. pTinyStringBuffer = NULL;
  117. }
  118. g_MSIInstallTest.AddToTail(pData);
  119. pData = NULL;
  120. Skip:
  121. if (!::FindNextFileW(hFind, &wfd))
  122. {
  123. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  124. {
  125. ::ReportFailure("Error iterating over assemblies\n");
  126. goto Exit;
  127. }
  128. break;
  129. }
  130. }
  131. for (iter.Reset(); iter.More(); iter.Next())
  132. {
  133. if (!iter->Thread.Win32CreateThread(&MSIInstallTestThreadProc, iter.Current()))
  134. {
  135. ::ReportFailure("Error launching install thread\n");
  136. goto Exit;
  137. }
  138. TotalThreads += 1;
  139. }
  140. fSuccess = TRUE;
  141. Exit:
  142. if (pData)
  143. delete pData;
  144. if (pTinyStringBuffer != NULL)
  145. delete pTinyStringBuffer;
  146. return fSuccess;
  147. }
  148. void RequestShutdownMSIInstallTestThreads()
  149. {
  150. CDequeIterator<MSIINSTALLTEST_THREAD_PROC_DATA, offsetof(MSIINSTALLTEST_THREAD_PROC_DATA, Linkage)> iter(&g_MSIInstallTest);
  151. for (iter.Reset(); iter.More(); iter.Next())
  152. {
  153. iter->Stop = true;
  154. }
  155. }
  156. void WaitForMSIInstallTestThreads()
  157. {
  158. CDequeIterator<MSIINSTALLTEST_THREAD_PROC_DATA, offsetof(MSIINSTALLTEST_THREAD_PROC_DATA, Linkage)> iter(&g_MSIInstallTest);
  159. for (iter.Reset(); iter.More(); iter.Next())
  160. {
  161. DWORD WaitResult = ::WaitForSingleObject(iter->Thread, INFINITE);
  162. switch (WaitResult)
  163. {
  164. case WAIT_OBJECT_0:
  165. break;
  166. case WAIT_FAILED:
  167. ::ReportFailure("MSIInstall :: Failed to WaitForSingleObject.\n");
  168. break;
  169. default:
  170. ::FusionpSetLastWin32Error(WaitResult);
  171. ::ReportFailure("MSIInstall :: Failed to WaitForSingleObject.\n");
  172. break;
  173. }
  174. iter->Thread.Win32Close();
  175. }
  176. }
  177. void CleanupMSIInstallTest()
  178. {
  179. g_MSIInstallTest.ClearAndDeleteAll();
  180. }
  181. HRESULT Helper_WriteStream(CSmallStringBuffer * pFileNameBuf,
  182. IStream *pStream)
  183. {
  184. HRESULT hr = NOERROR;
  185. LPBYTE pBuf[0x4000];
  186. DWORD cbBuf = 0x4000;
  187. DWORD dwWritten = 0;
  188. DWORD cbRead = 0;
  189. HANDLE hf = INVALID_HANDLE_VALUE;
  190. hf = ::CreateFileW(static_cast<PCWSTR>(*pFileNameBuf), GENERIC_READ, FILE_SHARE_READ,
  191. NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  192. if (hf == INVALID_HANDLE_VALUE){
  193. hr = HRESULT_FROM_WIN32 (GetLastError());
  194. goto Exit;
  195. }
  196. while (::ReadFile(hf, pBuf, cbBuf, &cbRead, NULL) && cbRead){
  197. hr = pStream->Write(pBuf, cbRead, &dwWritten);
  198. if (FAILED(hr))
  199. goto Exit;
  200. }
  201. if (! SUCCEEDED(hr = pStream->Commit(0)))
  202. goto Exit;
  203. CloseHandle(hf);
  204. Exit:
  205. return hr;
  206. }
  207. DWORD
  208. WINAPI
  209. MSIInstallTestThreadProc(
  210. LPVOID pvData
  211. )
  212. {
  213. DWORD dwReturnValue = ERROR_INTERNAL_ERROR;
  214. DWORD WaitResult = 0;
  215. MSIINSTALLTEST_THREAD_PROC_DATA *pData = reinterpret_cast<MSIINSTALLTEST_THREAD_PROC_DATA*>(pvData);
  216. IAssemblyCache * pAsmCache = NULL;
  217. SIZE_T nPathLen = pData->AssemblySourceDirectory.Cch();
  218. IAssemblyCacheItem * pCacheItem = NULL;
  219. IStream * pStream = NULL;
  220. IAssemblyName * pAssemblyName = NULL;
  221. WCHAR buf[MAX_PATH];
  222. DWORD bufSize = MAX_PATH;
  223. HRESULT hr;
  224. InterlockedIncrement(&ThreadsWaiting);
  225. WaitResult = WaitForSingleObject(ResumeThreadsEvent, INFINITE);
  226. switch (WaitResult)
  227. {
  228. case WAIT_OBJECT_0:
  229. break;
  230. case WAIT_FAILED:
  231. dwReturnValue = ::FusionpGetLastWin32Error();
  232. ::ReportFailure("Failed to WaitForSingleObject.\n");
  233. goto Exit;
  234. default:
  235. dwReturnValue = WaitResult;
  236. ::FusionpSetLastWin32Error(WaitResult);
  237. ::ReportFailure("Failed to WaitForSingleObject.\n");
  238. goto Exit;
  239. }
  240. if (CreateAssemblyCache(&pAsmCache, 0) != S_OK)
  241. {
  242. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) failed CreateAssemblyCache with gle %lu \n",
  243. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  244. pData->AssemblySourceDirectory,
  245. pData->ManifestFileName,
  246. ::FusionpGetLastWin32Error());
  247. goto Exit;
  248. }
  249. while (!pData->Stop)
  250. {
  251. //Create AssemblyCache and AssemblyCacheItem
  252. if ((hr = pAsmCache->CreateAssemblyCacheItem(0, NULL, &pCacheItem, NULL)) != S_OK)
  253. {
  254. ::FusionpSetLastErrorFromHRESULT(hr);
  255. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) failed CreateAssemblyCacheItem with gle %lu \n",
  256. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  257. pData->AssemblySourceDirectory,
  258. pData->ManifestFileName,
  259. ::FusionpGetLastWin32Error());
  260. goto Exit;
  261. }
  262. //
  263. // create manifests for assembly item
  264. //
  265. if ((hr = pCacheItem->CreateStream(0, pData->ManifestFileName, STREAM_FORMAT_WIN32_MANIFEST, 0, &pStream, NULL)) != S_OK)
  266. {
  267. ::FusionpSetLastErrorFromHRESULT(hr);
  268. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) failed CreateStream for manifest with gle %lu \n",
  269. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  270. pData->AssemblySourceDirectory,
  271. pData->ManifestFileName,
  272. ::FusionpGetLastWin32Error());
  273. goto Exit;
  274. }
  275. pData->AssemblySourceDirectory.Left(nPathLen);
  276. if (! pData->AssemblySourceDirectory.Win32AppendPathElement(pData->ManifestFileName))
  277. {
  278. goto Exit;
  279. }
  280. if ( (hr = Helper_WriteStream(&pData->AssemblySourceDirectory, pStream)) != S_OK)
  281. {
  282. ::FusionpSetLastErrorFromHRESULT(hr);
  283. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) failed WriteStream for manifest with gle %lu \n",
  284. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  285. pData->AssemblySourceDirectory,
  286. pData->ManifestFileName,
  287. ::FusionpGetLastWin32Error());
  288. goto Exit;
  289. }
  290. pStream->Release();
  291. CDequeIterator<STRINGBUFFER_LINKAGE, offsetof(STRINGBUFFER_LINKAGE, Linkage)> iter(&pData->FileNameOfAssemblyList);
  292. for (iter.Reset(); iter.More(); iter.Next())
  293. {
  294. if ((hr = pCacheItem->CreateStream(0, iter.Current()->Str, STREAM_FORMAT_WIN32_MODULE, 0, &pStream, NULL)) != S_OK)
  295. {
  296. ::FusionpSetLastErrorFromHRESULT(hr);
  297. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) failed CreateStream for module \"%ls\" with gle %lu \n",
  298. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  299. pData->AssemblySourceDirectory,
  300. pData->ManifestFileName,
  301. iter->Str,
  302. ::FusionpGetLastWin32Error());
  303. goto Exit;
  304. }
  305. pData->AssemblySourceDirectory.Left(nPathLen);
  306. if (! pData->AssemblySourceDirectory.Win32AppendPathElement(iter.Current()->Str))
  307. goto Exit;
  308. if ( (hr = Helper_WriteStream(&pData->AssemblySourceDirectory, pStream)) != S_OK)
  309. {
  310. ::FusionpSetLastErrorFromHRESULT(hr);
  311. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) failed CreateStream for module \"%ls\" with gle %lu \n",
  312. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  313. pData->AssemblySourceDirectory,
  314. pData->ManifestFileName,
  315. iter->Str,
  316. ::FusionpGetLastWin32Error());
  317. goto Exit;
  318. }
  319. pStream->Release();
  320. }
  321. if ((hr = pCacheItem->Commit(0, NULL)) != S_OK)
  322. {
  323. ::FusionpSetLastErrorFromHRESULT(hr);
  324. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) failed Commit AssemblyCacheItem with gle %lu \n",
  325. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  326. pData->AssemblySourceDirectory,
  327. pData->ManifestFileName,
  328. ::FusionpGetLastWin32Error());
  329. goto Exit;
  330. }
  331. // uninstall the same assembly using CAssemblyName and CAssemblyCache->UninstallAssembly
  332. if ( (hr = CreateAssemblyNameObject(&pAssemblyName, pData->AssemblyNameFromDarwin, CANOF_PARSE_DISPLAY_NAME,NULL)) != S_OK)
  333. {
  334. ::FusionpSetLastErrorFromHRESULT(hr);
  335. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) failed CreateAssemblyName for %s with gle %lu \n",
  336. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  337. pData->AssemblySourceDirectory,
  338. pData->ManifestFileName,
  339. pData->AssemblyNameFromDarwin,
  340. ::FusionpGetLastWin32Error());
  341. goto Exit;
  342. }
  343. if ( (hr = pAssemblyName->GetDisplayName(buf, &bufSize, 0)) != S_OK)
  344. {
  345. ::FusionpSetLastErrorFromHRESULT(hr);
  346. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) failed IsAssemblyInstalled for %s with gle %lu \n",
  347. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  348. pData->AssemblySourceDirectory,
  349. pData->ManifestFileName,
  350. pData->AssemblyNameFromDarwin,
  351. ::FusionpGetLastWin32Error());
  352. goto Exit;
  353. }
  354. if ( wcscmp(pData->AssemblyNameFromDarwin, buf) != 0)
  355. {
  356. goto Exit;
  357. }
  358. if ((hr = pAsmCache->UninstallAssembly(0, buf, NULL, NULL)) != S_OK)
  359. {
  360. ::FusionpSetLastErrorFromHRESULT(hr);
  361. ::ReportFailure("[%lx.%lx] MSIInstall(\"%ls\", 0x%lx) Cache->UninstallAssemblyfailed for %s with gle %lu \n",
  362. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(),
  363. pData->AssemblySourceDirectory,
  364. pData->ManifestFileName,
  365. buf,
  366. ::FusionpGetLastWin32Error());
  367. goto Exit;
  368. }
  369. ::WaitForSingleObject(StopEvent, pData->Sleep);
  370. }
  371. dwReturnValue = ERROR_SUCCESS;
  372. goto Cleanup;
  373. Exit:
  374. dwReturnValue = ::FusionpGetLastWin32Error();
  375. Cleanup:
  376. if (pAsmCache)
  377. pAsmCache->Release();
  378. if (pCacheItem)
  379. pCacheItem->Release();
  380. if (pStream)
  381. pStream->Release();
  382. if (pAssemblyName)
  383. pAssemblyName->Release();
  384. return dwReturnValue;
  385. }