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.

331 lines
12 KiB

  1. #include "stdinc.h"
  2. #include "st.h"
  3. #include "install.h"
  4. CDeque<INSTALL_THREAD_PROC_DATA, offsetof(INSTALL_THREAD_PROC_DATA, Linkage)> g_Installs;
  5. #define DATA_DIRECTORY_NAME L"assemblies"
  6. #define SLASH_INI_FILE L"\\assembly.ini"
  7. #define INI_FILE L"assembly.ini"
  8. BOOL InitializeInstall()
  9. {
  10. FN_PROLOG_WIN32
  11. CFindFile hFind;
  12. WIN32_FIND_DATAW wfd;
  13. CStringBuffer TempDirectory;
  14. CDequeIterator<INSTALL_THREAD_PROC_DATA, offsetof(INSTALL_THREAD_PROC_DATA, Linkage)> iter(&g_Installs);
  15. CStringBuffer IniFileName;
  16. CStringBuffer BaseDirectory2;
  17. if (!BaseDirectory2.Win32Assign(BaseDirectory))
  18. goto Exit;
  19. if (!BaseDirectory2.Win32AppendPathElement(DATA_DIRECTORY_NAME, NUMBER_OF(DATA_DIRECTORY_NAME) - 1))
  20. goto Exit;
  21. if (!TempDirectory.Win32Assign(BaseDirectory2))
  22. if ((wfd.dwFileAttributes = ::GetFileAttributesW(TempDirectory)) == 0xffffffff
  23. && (wfd.dwFileAttributes = ::FusionpGetLastWin32Error()) == ERROR_FILE_NOT_FOUND)
  24. {
  25. printf("no %ls tests, skipping\n", DATA_DIRECTORY_NAME);
  26. FN_SUCCESSFUL_EXIT();
  27. }
  28. if (!TempDirectory.Win32AppendPathElement(L"*", 1))
  29. goto Exit;
  30. hFind = ::FindFirstFileW(TempDirectory, &wfd);
  31. if (hFind == INVALID_HANDLE_VALUE)
  32. {
  33. ::ReportFailure("Failed to find any files matching \"%ls\"\n", static_cast<PCWSTR>(TempDirectory));
  34. goto Exit;
  35. }
  36. for (;;)
  37. {
  38. DWORD dwTemp;
  39. WCHAR rgwchGuid[64];
  40. WCHAR rgwchKey[MAX_PATH];
  41. WCHAR rgwchData[MAX_PATH];
  42. INSTALL_THREAD_PROC_DATA *pData = NULL;
  43. struct
  44. {
  45. SXS_MANIFEST_INFORMATION_BASIC mib;
  46. WCHAR rgwchBuffer[65535]; // big frame but what the heck
  47. } ManifestInformation;
  48. if (FusionpIsDotOrDotDot(wfd.cFileName))
  49. goto Skip;
  50. if (!IniFileName.Win32Assign(BaseDirectory2))
  51. goto Exit;
  52. if (!TempDirectory.Win32AppendPathElement(DATA_DIRECTORY_NAME, NUMBER_OF(DATA_DIRECTORY_NAME) - 1))
  53. goto Exit;
  54. if (!IniFileName.Win32AppendPathElement(wfd.cFileName, wcslen(wfd.cFileName)))
  55. goto Exit;
  56. if ((pData = new INSTALL_THREAD_PROC_DATA) == NULL)
  57. {
  58. ::FusionpSetLastWin32Error(ERROR_OUTOFMEMORY);
  59. ::ReportFailure("Failed to allocate INSTALL_THREAD_PROC_DATA\n");
  60. goto Exit;
  61. }
  62. if (!pData->ManifestPath.Win32Append(IniFileName))
  63. goto Exit;
  64. if (!pData->ManifestPath.Win32Append(L"\\", 1))
  65. goto Exit;
  66. if (!IniFileName.Win32AppendPathElement(INI_FILE, NUMBER_OF(INI_FILE) - 1))
  67. goto Exit;
  68. if (!SxStressToolGetStringSetting(0, IniFileName, L"assembly", L"manifest", L"assembly.manifest", pData->ManifestPath, NULL))
  69. goto Exit;
  70. if (!::SxsQueryManifestInformation(
  71. 0,
  72. pData->ManifestPath,
  73. SXS_QUERY_MANIFEST_INFORMATION_INFOCLASS_BASIC,
  74. SXS_QUERY_MANIFEST_INFORMATION_INFOCLASS_BASIC_FLAG_OMIT_SHORTNAME,
  75. sizeof(ManifestInformation),
  76. &ManifestInformation,
  77. NULL))
  78. {
  79. ::ReportFailure("Unable to query manifest information for manifest \"%ls\"\n", static_cast<PCWSTR>(pData->ManifestPath));
  80. goto Exit;
  81. }
  82. dwTemp = ::GetPrivateProfileStringW(L"reference", L"guid", L"", rgwchGuid, NUMBER_OF(rgwchGuid), IniFileName);
  83. if (dwTemp == (NUMBER_OF(rgwchGuid) - 1))
  84. {
  85. ::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
  86. ::ReportFailure("Enormous guid in \"%ls\"; section \"reference\", key \"guid\" (does not fit in %Iu characters).\n",
  87. static_cast<PCWSTR>(IniFileName), NUMBER_OF(rgwchGuid));
  88. goto Exit;
  89. }
  90. dwTemp = ::GetPrivateProfileStringW(L"reference", L"key", L"", rgwchKey, NUMBER_OF(rgwchKey), IniFileName);
  91. if (dwTemp == (NUMBER_OF(rgwchKey) - 1))
  92. {
  93. ::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
  94. ::ReportFailure("Enormous value in \"%ls\"; section \"reference\", key \"key\" (does not fit in %Iu characters).\n",
  95. static_cast<PCWSTR>(IniFileName), NUMBER_OF(rgwchKey));
  96. goto Exit;
  97. }
  98. dwTemp = ::GetPrivateProfileStringW(L"reference", L"data", L"", rgwchData, NUMBER_OF(rgwchData), IniFileName);
  99. if (dwTemp == (NUMBER_OF(rgwchData) - 1))
  100. {
  101. ::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
  102. ::ReportFailure("Enourmous value in \"%ls\"; section \"reference\", key \"data\" (does not fit in %Iu characters).\n",
  103. static_cast<PCWSTR>(IniFileName), NUMBER_OF(rgwchData));
  104. goto Exit;
  105. }
  106. pData->AfterInstallSleep = static_cast<DWORD>(::GetPrivateProfileIntW(L"assembly", L"AfterInstallSleepMS", 500, IniFileName));
  107. pData->AfterUninstallSleep = static_cast<DWORD>(::GetPrivateProfileIntW(L"assembly", L"AfterUninstallSleepMS", 500, IniFileName));
  108. pData->Install = (::GetPrivateProfileIntW(L"assembly", L"install", 1, IniFileName) != 0);
  109. pData->Uninstall = (::GetPrivateProfileIntW(L"assembly", L"uninstall", 1, IniFileName) != 0);
  110. if (!pData->Identity.Win32Assign(ManifestInformation.mib.lpIdentity, wcslen(ManifestInformation.mib.lpIdentity)))
  111. {
  112. ::FusionpSetLastWin32Error(ERROR_OUTOFMEMORY);
  113. ::ReportFailure("Error allocating installation identify string\n");
  114. goto Exit;
  115. }
  116. if (rgwchGuid[0] != L'\0')
  117. {
  118. HRESULT hr;
  119. if (FAILED(hr = ::CLSIDFromString(rgwchGuid, &pData->InstallationReference.guidScheme)))
  120. {
  121. ::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
  122. ::ReportFailure("CLSIDFromString() on [reference]/guid value in \"%ls\" failed with HRESULT 0x%08lx\n", static_cast<PCWSTR>(IniFileName), hr);
  123. goto Exit;
  124. }
  125. pData->InstallationReferencePtr = &pData->InstallationReference;
  126. }
  127. if (rgwchKey[0] != L'\0')
  128. {
  129. if (!pData->InstallationReference_Identifier.Win32Assign(rgwchKey, wcslen(rgwchKey)))
  130. {
  131. ::FusionpSetLastWin32Error(ERROR_OUTOFMEMORY);
  132. ::ReportFailure("Unable to allocate installation reference non-canonical data buffer\n");
  133. goto Exit;
  134. }
  135. pData->InstallationReference.lpIdentifier = pData->InstallationReference_Identifier;
  136. }
  137. if (rgwchData[0] != L'\0')
  138. {
  139. if (!pData->InstallationReference_NonCanonicalData.Win32Assign(rgwchData, wcslen(rgwchData)))
  140. {
  141. ::FusionpSetLastWin32Error(ERROR_OUTOFMEMORY);
  142. ::ReportFailure("Unable to allocate installation reference non-canonical data buffer\n");
  143. goto Exit;
  144. }
  145. pData->InstallationReference.lpNonCanonicalData = pData->InstallationReference_NonCanonicalData;
  146. }
  147. g_Installs.AddToTail(pData);
  148. Skip:
  149. if (!::FindNextFileW(hFind, &wfd))
  150. {
  151. if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES)
  152. {
  153. ::ReportFailure("Error iterating over assemblies\n");
  154. goto Exit;
  155. }
  156. break;
  157. }
  158. }
  159. for (iter.Reset(); iter.More(); iter.Next())
  160. {
  161. if (!iter->Thread.Win32CreateThread(&InstallThreadProc, iter.Current()))
  162. {
  163. ::ReportFailure("Error launching install thread\n");
  164. goto Exit;
  165. }
  166. TotalThreads += 1;
  167. }
  168. FN_EPILOG
  169. }
  170. void RequestShutdownInstallThreads()
  171. {
  172. CDequeIterator<INSTALL_THREAD_PROC_DATA, offsetof(INSTALL_THREAD_PROC_DATA, Linkage)> iter(&g_Installs);
  173. for (iter.Reset(); iter.More(); iter.Next())
  174. {
  175. iter->Stop = true;
  176. }
  177. }
  178. void WaitForInstallThreads()
  179. {
  180. CDequeIterator<INSTALL_THREAD_PROC_DATA, offsetof(INSTALL_THREAD_PROC_DATA, Linkage)> iter(&g_Installs);
  181. for (iter.Reset(); iter.More(); iter.Next())
  182. {
  183. DWORD WaitResult = ::WaitForSingleObject(iter->Thread, INFINITE);
  184. switch (WaitResult)
  185. {
  186. case WAIT_OBJECT_0:
  187. break;
  188. case WAIT_FAILED:
  189. ::ReportFailure("Failed to WaitForSingleObject.\n");
  190. break;
  191. default:
  192. ::FusionpSetLastWin32Error(WaitResult);
  193. ::ReportFailure("Failed to WaitForSingleObject.\n");
  194. break;
  195. }
  196. iter->Thread.Win32Close();
  197. }
  198. }
  199. void CleanupInstall()
  200. {
  201. g_Installs.ClearAndDeleteAll();
  202. }
  203. DWORD
  204. WINAPI
  205. InstallThreadProc(
  206. LPVOID pvData
  207. )
  208. {
  209. INSTALL_THREAD_PROC_DATA *pData = reinterpret_cast<INSTALL_THREAD_PROC_DATA *>(pvData);
  210. DWORD dwReturnValue = ERROR_INTERNAL_ERROR;
  211. SXS_INSTALLW Install = { sizeof(SXS_INSTALLW) };
  212. SXS_UNINSTALLW Uninstall = { sizeof(SXS_UNINSTALLW) };
  213. DWORD WaitResult = 0;
  214. if ((Install.lpReference = pData->InstallationReferencePtr) != NULL)
  215. Install.dwFlags |= SXS_INSTALL_FLAG_REFERENCE_VALID;
  216. Install.lpManifestPath = pData->ManifestPath;
  217. Uninstall.lpAssemblyIdentity = pData->Identity;
  218. if ((Uninstall.lpInstallReference = pData->InstallationReferencePtr) != NULL)
  219. Uninstall.dwFlags |= SXS_UNINSTALL_FLAG_REFERENCE_VALID;
  220. InterlockedIncrement(&ThreadsWaiting);
  221. WaitResult = WaitForSingleObject(ResumeThreadsEvent, INFINITE);
  222. switch (WaitResult)
  223. {
  224. case WAIT_OBJECT_0:
  225. break;
  226. case WAIT_FAILED:
  227. dwReturnValue = ::FusionpGetLastWin32Error();
  228. ::ReportFailure("Failed to WaitForSingleObject.\n");
  229. goto Exit;
  230. default:
  231. dwReturnValue = WaitResult;
  232. ::FusionpSetLastWin32Error(WaitResult);
  233. ::ReportFailure("Failed to WaitForSingleObject.\n");
  234. goto Exit;
  235. }
  236. for (;;)
  237. {
  238. DWORD dwUninstallDisposition;
  239. if (pData->Install)
  240. {
  241. if (!::SxsInstallW(&Install))
  242. {
  243. dwReturnValue = ::FusionpGetLastWin32Error();
  244. ::ReportFailure("Failed to install \"%ls\"\n", static_cast<PCWSTR>(pData->ManifestPath));
  245. goto Exit;
  246. }
  247. printf("[%lx.%lx] Manifest \"%ls\" installed\n",
  248. SxStressToolGetCurrentProcessId(),
  249. SxStressToolGetCurrentThreadId(),
  250. static_cast<PCWSTR>(pData->ManifestPath)
  251. );
  252. ::WaitForSingleObject(StopEvent, pData->AfterInstallSleep);
  253. }
  254. if (pData->Stop)
  255. break;
  256. if (pData->Uninstall)
  257. {
  258. if (!::SxsUninstallW(&Uninstall, &dwUninstallDisposition))
  259. {
  260. dwReturnValue = ::FusionpGetLastWin32Error();
  261. ::ReportFailure("Failed to uninstall \"%ls\"\n", static_cast<PCWSTR>(pData->ManifestPath));
  262. goto Exit;
  263. }
  264. printf("[%lx.%lx] Manifest \"%ls\" uninstalled; disposition = %lu\n",
  265. SxStressToolGetCurrentProcessId(),
  266. SxStressToolGetCurrentThreadId(),
  267. static_cast<PCWSTR>(pData->ManifestPath),
  268. dwUninstallDisposition
  269. );
  270. ::WaitForSingleObject(StopEvent, pData->AfterUninstallSleep);
  271. }
  272. if (pData->Stop)
  273. break;
  274. }
  275. dwReturnValue = ERROR_SUCCESS;
  276. Exit:
  277. printf("[%lx.%lx] install(%ls) thread exiting %lu\n",
  278. SxStressToolGetCurrentProcessId(), SxStressToolGetCurrentThreadId(), static_cast<PCWSTR>(pData->ManifestPath), dwReturnValue);
  279. return dwReturnValue;
  280. }