Source code of Windows XP (NT5)
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.

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