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.

591 lines
18 KiB

  1. // ===========================================================================
  2. // File: CSETUP.CXX
  3. // CSetup class implementation
  4. //
  5. #include <cdlpch.h>
  6. #include "verp.h"
  7. #include <advpub.h>
  8. #include "advpkp.h"
  9. extern CRunSetupHook g_RunSetupHook;
  10. extern BOOL g_bRunOnWin95;
  11. inline
  12. DWORD Win32ErrorFromHResult( HRESULT hr)
  13. {
  14. // BUGBUG: assert failed?
  15. //BUGBUG: assert win32 facility?
  16. return (DWORD)(hr & 0x0000ffff);
  17. }
  18. DWORD GetFullPathNameA_Wrap(
  19. LPCSTR lpFileName, // file name
  20. DWORD nBufferLength, // size of path buffer
  21. LPSTR lpBuffer, // path buffer
  22. LPSTR *lpFilePart // address of file name in path
  23. );
  24. // ---------------------------------------------------------------------------
  25. // %%Function: CSetup::CSetup
  26. //
  27. // Csetup obj: zero or more associated with every CDownload obj
  28. // Some CDownload's may have no CSetup (eg. INF file)
  29. // ---------------------------------------------------------------------------
  30. CSetup::CSetup(LPCSTR pSrcFileName, LPCSTR pBaseFileName, FILEXTN extn,
  31. LPCSTR pDestDir, HRESULT *phr, DESTINATION_DIR dest)
  32. {
  33. DEBUG_ENTER((DBG_DOWNLOAD,
  34. None,
  35. "CSetup::CSetup",
  36. "this=%#x, %.80q, %.80q, %#x, %.80q, %#x, %#x",
  37. this, pSrcFileName, pBaseFileName, extn, pDestDir, phr, dest
  38. ));
  39. m_pSetupnext = NULL;
  40. m_extn = extn;
  41. m_dest = dest;
  42. m_flags = 0;
  43. m_advcopyflags = 0; // flags for AdvInstallFile
  44. m_state = INSTALL_INIT;
  45. m_pExistDir = NULL;
  46. if (pDestDir) {
  47. m_pExistDir = new char [lstrlen(pDestDir)+1];
  48. if (m_pExistDir)
  49. lstrcpy((char *)m_pExistDir, pDestDir);
  50. else
  51. *phr = E_OUTOFMEMORY;
  52. }
  53. Assert(pBaseFileName);
  54. if (pBaseFileName) {
  55. m_pBaseFileName = new char [lstrlen(pBaseFileName)+1];
  56. if (m_pBaseFileName)
  57. lstrcpy(m_pBaseFileName, pBaseFileName);
  58. else
  59. *phr = E_OUTOFMEMORY;
  60. }
  61. if (pSrcFileName) {
  62. m_pSrcFileName = new char [lstrlen(pSrcFileName)+1];
  63. if (m_pSrcFileName)
  64. lstrcpy(m_pSrcFileName, pSrcFileName);
  65. else
  66. *phr = E_OUTOFMEMORY;
  67. }
  68. m_bExactVersion = FALSE;
  69. DEBUG_LEAVE(0);
  70. }
  71. // ---------------------------------------------------------------------------
  72. // %%Function: CSetup::~CSetup
  73. // ---------------------------------------------------------------------------
  74. CSetup::~CSetup()
  75. {
  76. DEBUG_ENTER((DBG_DOWNLOAD,
  77. None,
  78. "CSetup::~CSetup",
  79. "this=%#x",
  80. this
  81. ));
  82. if (m_pSrcFileName)
  83. delete (LPSTR)m_pSrcFileName;
  84. if (m_pBaseFileName)
  85. delete (LPSTR)m_pBaseFileName;
  86. if (m_pExistDir)
  87. delete (LPSTR)m_pExistDir;
  88. DEBUG_LEAVE(0);
  89. }
  90. // ---------------------------------------------------------------------------
  91. // %%Function: CSetup::SetSrcFileName
  92. // ---------------------------------------------------------------------------
  93. HRESULT CSetup::SetSrcFileName(LPCSTR pSrcFileName)
  94. {
  95. DEBUG_ENTER((DBG_DOWNLOAD,
  96. Hresult,
  97. "CSetup::SetSrcFileName",
  98. "this=%#x, %.80q",
  99. this, pSrcFileName
  100. ));
  101. if (m_pSrcFileName) {
  102. SAFEDELETE(m_pSrcFileName);
  103. }
  104. ASSERT(pSrcFileName);
  105. ASSERT(pSrcFileName[0] != '\0');
  106. HRESULT hr = S_OK;
  107. if (pSrcFileName) {
  108. m_pSrcFileName = new char [lstrlen(pSrcFileName)+1];
  109. if (m_pSrcFileName)
  110. lstrcpy(m_pSrcFileName, pSrcFileName);
  111. else
  112. hr = E_OUTOFMEMORY;
  113. } else {
  114. hr = E_INVALIDARG;
  115. }
  116. DEBUG_LEAVE(hr);
  117. return hr;
  118. }
  119. // ---------------------------------------------------------------------------
  120. // %%Function: CSetup::CheckForNameCollisions
  121. // This checks if the given cache dir has name collision for this file
  122. // ---------------------------------------------------------------------------
  123. HRESULT CSetup::CheckForNameCollision(CCodeDownload *pcdl, LPCSTR szCacheDir)
  124. {
  125. DEBUG_ENTER((DBG_DOWNLOAD,
  126. Hresult,
  127. "CSetup::CheckForNameCollision",
  128. "this=%#x, %#x, %.80q",
  129. this, pcdl, szCacheDir
  130. ));
  131. HRESULT hr = S_OK;
  132. char szDest[MAX_PATH];
  133. // INFs don't matter for name collisions or prev version exists
  134. // the way to handle this is to doc that evryone should choose
  135. // same name INFs as their primary OCX. This way the INF and OCX will
  136. // reside in the same dir (szCacheDir) and the primary OCX will handle
  137. // name collisions and be located in a non-conflicting dir.
  138. // So, INFs will always be overwritten. If someone defies convention
  139. // we might end up losing an INF, so we have to gerbage collect the
  140. // OCX to recover space on disk.
  141. if ( (m_extn == FILEXTN_INF) || (m_extn == FILEXTN_OSD))
  142. goto Exit;
  143. if (m_pExistDir) // if a previous version exists and this is a
  144. goto Exit; // and this is a overwrite all OK (no accidental
  145. // name collision issues
  146. // we don't care now if the dest is either Windows or System dir
  147. // This case will be tackled in CSetup::DoSetup after we have established
  148. // a non-colliding OCXCACHE dir for m_dest == LDID_OCXCACHE case
  149. // to put rest of this OCX files in
  150. if ((m_dest == LDID_SYS) || (m_dest == LDID_WIN))
  151. goto Exit;
  152. if (lstrlen(m_pBaseFileName) + lstrlen(szCacheDir) + 1 > MAX_PATH) {
  153. // Fatal! The length of the filepath is beyond MAX_PATH.
  154. hr = E_UNEXPECTED;
  155. goto Exit;
  156. }
  157. lstrcpy(szDest, szCacheDir);
  158. lstrcat(szDest, "\\");
  159. lstrcat(szDest, m_pBaseFileName);
  160. if (GetFileAttributes(szDest) != -1) { // file exists?
  161. if (!IsEqualGUID(pcdl->GetClsid() , CLSID_NULL)) {
  162. hr = S_FALSE; // report name conflict
  163. goto Exit;
  164. }
  165. // check if that file implements the main clsid
  166. HRESULT hr1 = CheckFileImplementsCLSID(szDest, pcdl->GetClsid());
  167. if (FAILED(hr1))
  168. hr = S_FALSE; // report name conflict
  169. }
  170. Exit:
  171. DEBUG_LEAVE(hr);
  172. return hr;
  173. }
  174. // ---------------------------------------------------------------------------
  175. // %%Function: CSetup::InstallFile
  176. // ---------------------------------------------------------------------------
  177. HRESULT CSetup::InstallFile(CCodeDownload *pcdl, LPSTR szDest, int iLen, LPWSTR szStatusText,
  178. LPUINT pcbStatusText)
  179. {
  180. DEBUG_ENTER((DBG_DOWNLOAD,
  181. Hresult,
  182. "CSetup::InstallFile",
  183. "this=%#x, %#x, %.80q, %.80wq, %#x",
  184. this, pcdl, szDest, szStatusText, pcbStatusText
  185. ));
  186. char *pSrcBaseName;
  187. char pSrcDir[MAX_PATH];
  188. HWND hWnd = pcdl->GetClientBinding()->GetHWND();
  189. HRESULT hr = S_OK;
  190. char szDestDir[MAX_PATH];
  191. char szDestDirShort[MAX_PATH];
  192. DWORD dwMachineType = 0;
  193. SetState(INSTALL_COPY);
  194. GetDestDir(pcdl, szDestDir, sizeof(szDestDir));
  195. if (g_bRunOnWin95) {
  196. if (!GetShortPathName(szDestDir, szDestDirShort, MAX_PATH)) {
  197. hr = HRESULT_FROM_WIN32(GetLastError());
  198. goto Exit;
  199. }
  200. lstrcpy(szDestDir, szDestDirShort);
  201. }
  202. StrNCpy(szDest, szDestDir, iLen);
  203. StrCatBuff(szDest, "\\", iLen);
  204. StrCatBuff(szDest, m_pBaseFileName, iLen);
  205. //may be MAX_PATH (instead of *pcbStatusText, which in the only case this is called is = INTERNET_MAX_URL_LENGTH + 2*MAX_PATH)
  206. *pcbStatusText = MultiByteToWideChar(CP_ACP, 0, szDest, -1, szStatusText,
  207. MAX_PATH);
  208. pcdl->GetClientBSC()->OnProgress( INSTALL_COPY, INSTALL_PHASES,
  209. BINDSTATUS_INSTALLINGCOMPONENTS, szStatusText);
  210. // get src dir + srcbasename out of src filename
  211. if (!GetFullPathNameA_Wrap(m_pSrcFileName, MAX_PATH,
  212. pSrcDir, &pSrcBaseName)) {
  213. hr = HRESULT_FROM_WIN32(GetLastError());
  214. goto Exit;
  215. }
  216. // Installed catalog => this setup might be for a SFP-protected file.
  217. // So check if this file is protected, and if it is
  218. if (g_bNT5OrGreater && pcdl->IsCatalogInstalled())
  219. {
  220. LPSTR pszFile;
  221. DWORD cbLen = lstrlen(szDestDir) + lstrlen(m_pBaseFileName);
  222. pszFile = new CHAR[cbLen+2];
  223. BOOL bRet;
  224. if (pszFile)
  225. {
  226. lstrcpy(pszFile, szDestDir);
  227. lstrcat(pszFile, "\\");
  228. lstrcat(pszFile, m_pBaseFileName);
  229. bRet = pcdl->IsFileProtected(pszFile);
  230. delete [] pszFile;
  231. if (bRet && FAILED(pcdl->VerifyFileAgainstSystemCatalog(pSrcDir, NULL, NULL)))
  232. {
  233. hr = INET_E_CANNOT_REPLACE_SFP_FILE;
  234. goto Exit;
  235. }
  236. }
  237. }
  238. Assert(pSrcDir != pSrcBaseName);
  239. Assert(pSrcBaseName);
  240. *(pSrcBaseName-1) = '\0'; // make a dir out of pSrcDir
  241. // sniff machine type of PE
  242. hr = IsCompatibleFile(m_pSrcFileName, &dwMachineType);
  243. if (hr == HRESULT_FROM_WIN32(ERROR_EXE_MACHINE_TYPE_MISMATCH)) {
  244. // if its of wrong CPU flavor fail and clean up the OCX
  245. pcdl->CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_INCOMPATIBLE_BINARY, m_pSrcFileName);
  246. goto Exit;
  247. }
  248. #ifdef WX86
  249. if (g_fWx86Present && dwMachineType == IMAGE_FILE_MACHINE_I386) {
  250. //
  251. // From here on out, all other binaries downloaded must also be i386
  252. //
  253. hr = pcdl->GetMultiArch()->RequireAlternateArch();
  254. if (FAILED(hr)) {
  255. //
  256. // We're in the middle of downloading an Alpha piece, and we ended
  257. // up finding an x86-only piece. Fail the download.
  258. //
  259. pcdl->CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_INCOMPATIBLE_BINARY, m_pSrcFileName);
  260. goto Exit;
  261. }
  262. }
  263. if (pcdl->GetMultiArch()->GetRequiredArch() == PROCESSOR_ARCHITECTURE_INTEL) {
  264. //
  265. // Use x86 advpack.dll to install
  266. //
  267. hr = g_RunSetupHook.AdvInstallFileX86(hWnd, pSrcDir, pSrcBaseName,
  268. szDestDir, m_pBaseFileName,
  269. m_advcopyflags, 0);
  270. } else {
  271. //
  272. // Use native advpack.dll to install
  273. //
  274. hr = g_RunSetupHook.AdvInstallFile(hWnd, pSrcDir, pSrcBaseName,
  275. szDestDir, m_pBaseFileName,
  276. m_advcopyflags, 0);
  277. }
  278. #else
  279. DEBUG_ENTER((DBG_DOWNLOAD,
  280. Hresult,
  281. "g_RunSetupHook.AdvInstallFile",
  282. "%#x, %.80q, %.80q, %.80q, %.80q, %x",
  283. hWnd, pSrcDir, pSrcBaseName, szDestDir, m_pBaseFileName, m_advcopyflags
  284. ));
  285. hr = g_RunSetupHook.AdvInstallFile(hWnd, pSrcDir, pSrcBaseName,
  286. szDestDir, m_pBaseFileName,
  287. m_advcopyflags, 0);
  288. DEBUG_LEAVE(hr);
  289. #endif
  290. if (FAILED(hr)) {
  291. goto Exit;
  292. }
  293. // if error_success_reboot_required
  294. // then preserve this and return for overall download
  295. // if overall download fails beyond this point then, we should raise the
  296. // CIP and then fail with the subsequent error.
  297. if (hr == ERROR_SUCCESS_REBOOT_REQUIRED) {
  298. pcdl->SetRebootRequired();
  299. }
  300. Exit:
  301. DEBUG_LEAVE(hr);
  302. return hr;
  303. }
  304. // ---------------------------------------------------------------------------
  305. // %%Function: CSetup::GetDestDir
  306. // ---------------------------------------------------------------------------
  307. HRESULT CSetup::GetDestDir(CCodeDownload *pcdl, LPSTR szDestDir, int iLen)
  308. {
  309. DEBUG_ENTER((DBG_DOWNLOAD,
  310. Hresult,
  311. "CSetup::GetDestDir",
  312. "this=%#x, %#x, %.80q",
  313. this, pcdl, szDestDir
  314. ));
  315. if (!m_pExistDir) {
  316. // no existing version of file on client machine
  317. // if no suggested dest dir was specified move to ocxcachedir
  318. switch (m_dest) {
  319. case LDID_SYS:
  320. #ifdef WX86
  321. if (pcdl->GetMultiArch()->GetRequiredArch() == PROCESSOR_ARCHITECTURE_INTEL) {
  322. // An x86 control is downloading. Tell GetSystemDirectory
  323. // to return the sys32x86 dir instead of system32
  324. NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = TRUE;
  325. }
  326. #endif
  327. GetSystemDirectory(szDestDir, MAX_PATH);
  328. break;
  329. case LDID_WIN:
  330. GetWindowsDirectory(szDestDir, MAX_PATH);
  331. break;
  332. case LDID_OCXCACHE:
  333. Assert(pcdl->GetCacheDir());
  334. StrNCpy(szDestDir, pcdl->GetCacheDir(), iLen);
  335. break;
  336. }
  337. } else {
  338. StrNCpy(szDestDir, m_pExistDir, iLen);
  339. }
  340. DEBUG_LEAVE(S_OK);
  341. return S_OK;
  342. }
  343. // ---------------------------------------------------------------------------
  344. // %%Function: CSetup::DoSetup
  345. // The main action item for CSetup
  346. // installs file in proper dest dir (if null) defaults to ocxcache dir
  347. // It then registers the file if registerable
  348. // ---------------------------------------------------------------------------
  349. HRESULT CSetup::DoSetup(CCodeDownload *pcdl, CDownload *pdl)
  350. {
  351. DEBUG_ENTER((DBG_DOWNLOAD,
  352. Hresult,
  353. "CSetup::DoSetup",
  354. "this=%#x, %#x, %#x",
  355. this, pcdl, pdl
  356. ));
  357. char szDest[MAX_PATH];
  358. BOOL bModuleUsage = TRUE;
  359. // url + filename + other parts of msg
  360. WCHAR szStatusText[INTERNET_MAX_URL_LENGTH+MAX_PATH+MAX_PATH];
  361. IBindStatusCallback* pClientBSC = pcdl->GetClientBSC();
  362. HRESULT hr = S_OK;
  363. UINT nStatusText = 0;
  364. BOOL bReboot = FALSE;
  365. // side-effect of below: changes szStatusText, nStatusText and
  366. // fills in szDest to be destination file
  367. hr = InstallFile(pcdl, szDest, sizeof(szDest), szStatusText, &nStatusText);
  368. if (hr == ERROR_SUCCESS_REBOOT_REQUIRED) {
  369. bReboot = TRUE;
  370. hr = S_OK;
  371. pcdl->CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_FILE_INUSE, szDest);
  372. }
  373. if (hr != S_OK) // skip or abort?
  374. goto Exit;
  375. SetState(INSTALL_REGISTER);
  376. if ((m_extn == FILEXTN_INF) || (m_extn == FILEXTN_OSD)) {
  377. // nothing to register!
  378. // but, remember the name of the installed INF/OSD
  379. // to store away in registry.
  380. hr = pcdl->SetManifest(m_extn, szDest);
  381. goto Exit;
  382. }
  383. pClientBSC->OnProgress( INSTALL_REGISTER, INSTALL_PHASES, BINDSTATUS_INSTALLINGCOMPONENTS, szStatusText);
  384. // document one thing and do something else!
  385. // if its not an EXE try to self register no matter what?!
  386. // unless overriden not to.
  387. if (m_extn == FILEXTN_EXE) {
  388. BOOL bLocalServer = (UserOverrideRegisterServer() && WantsRegisterServer()) || (!UserOverrideRegisterServer() && SupportsSelfRegister(szDest));
  389. if ( bLocalServer ||
  390. ((pdl->GetExtn() != FILEXTN_CAB) && !UserOverrideRegisterServer())){
  391. pcdl->CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_DLL_REGISTERED, szDest);
  392. hr = pcdl->InstallOCX(szDest, m_extn, bLocalServer);
  393. // if we executed an EXE that was not a local server it is
  394. // probably just a setup EXE that needs to be cleaned up when
  395. // done. So we don't do ModuleUsage for those.
  396. if (!bLocalServer)
  397. bModuleUsage = FALSE;
  398. }
  399. } else {
  400. if (!UserOverrideRegisterServer() || WantsRegisterServer()) {
  401. if (!bReboot) {
  402. hr = pcdl->InstallOCX(szDest, m_extn, FALSE);
  403. } else {
  404. // we are going to reboot the machine to install the new
  405. // version of the OCX. So, no point trying to register it here
  406. // instead we will make it register on the next reboot
  407. // and proceed here as if it succeded.
  408. // what could be broken here is that if we proceed and
  409. // some other setup required this OCX to be registered
  410. // then it will fail
  411. // the work around is for those guys have interdependent
  412. // registerations to install using a custom EXE that will
  413. // force the user to reboot.
  414. if (IsRegisterableDLL(m_pSrcFileName) == S_OK) {
  415. hr = pcdl->DelayRegisterOCX(szDest, m_extn);
  416. pcdl->CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_DLL_REGISTERED, szDest);
  417. }
  418. }
  419. }
  420. }
  421. if (FAILED(hr)) {
  422. if (!m_pExistDir)
  423. DeleteFile(szDest);
  424. } else {
  425. // make sure we have a ref count for the code downloader in
  426. // shareddlls as well as mark us as a client in the usage section
  427. // if there is no prev version we are upgrading over
  428. // mark us as the owner
  429. if (bModuleUsage) {
  430. if (m_bExactVersion) {
  431. // Need to do this because in a exact version scenario,
  432. // we may have upgraded/downgraded in which case m_pExistDir
  433. // is non-NULL. We want us to be listed as our own owner
  434. // instead of "Unknown Owner" so OCCache can remove us later.
  435. hr = pcdl->QueueModuleUsage(szDest, MU_OWNER);
  436. if (FAILED(hr)) {
  437. goto Exit;
  438. }
  439. }
  440. else {
  441. if (FAILED((hr= pcdl->QueueModuleUsage(szDest,
  442. (m_pExistDir)?MU_CLIENT:MU_OWNER))))
  443. goto Exit;
  444. }
  445. }
  446. }
  447. Exit:
  448. if (FAILED(hr)) {
  449. pcdl->CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_DOSETUP_FAILED, hr, m_pBaseFileName, m_pExistDir, m_dest);
  450. } else {
  451. pcdl->CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_SETUP_COMPLETE, m_pBaseFileName, m_pExistDir, m_dest);
  452. }
  453. SetState(INSTALL_DONE);
  454. DEBUG_LEAVE(hr);
  455. return hr;
  456. }