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.

1467 lines
48 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: selfupdate.cpp
  8. //
  9. // Desc: This file contains all the functions necessary for self-update
  10. //--------------------------------------------------------------------------
  11. #include "pch.h"
  12. #include <osdet.h>
  13. #include <muiutil.h>
  14. #define TCHAR_SCTRUCTURE_DELIMITER _T('|')
  15. struct AU_FILEINCAB
  16. {
  17. TCHAR szFilePath[MAX_PATH + 1];
  18. TCHAR szNewFilePath[MAX_PATH + 1];
  19. TCHAR szBackupFilePath[MAX_PATH + 1];
  20. TCHAR szExtractFilePath[MAX_PATH + 1];
  21. BOOL fCreatedBackup;
  22. BOOL fFileExists;
  23. AU_FILEINCAB *pNextFileInCab;
  24. };
  25. struct AU_COMPONENT : AU_FILEINCAB
  26. {
  27. TCHAR *pszSectionName;
  28. TCHAR szFileName[_MAX_FNAME + 1];
  29. TCHAR szCabName[_MAX_FNAME + 1];
  30. TCHAR szCabPath[MAX_PATH + 1];
  31. CHAR a_szCabPath[MAX_PATH + 1];
  32. TCHAR szInfName[_MAX_FNAME + 1];
  33. CHAR a_szInfName[_MAX_FNAME + 1];
  34. DWORD dwUpdateMS;
  35. DWORD dwUpdateLS;
  36. BOOL fDoUpgrade;
  37. BOOL fNeedToCheckMui;
  38. BOOL fMuiFile;
  39. BOOL fHasHelpfile;
  40. AU_COMPONENT *pNext;
  41. };
  42. // AU_UPDATE_VERSION should be updated when incompatible changes are made to the
  43. // self update mechanism required AU to go to a new directory for update info.
  44. const TCHAR IDENT_TXT[] = _T("iuident.txt");
  45. const TCHAR WUAUCOMP_CAB[] = _T("wuaucomp.cab");
  46. const TCHAR WUAUCOMP_CIF[] = _T("wuaucomp.cif");
  47. const TCHAR WUAUENG_DLL[] = TEXT("wuaueng.dll");
  48. const TCHAR AU_KEY_FILE_NAME[] = TEXT("file");
  49. const TCHAR AU_KEY_FILE_VERSION[] = TEXT("version");
  50. const TCHAR AU_KEY_CAB_NAME[] = TEXT("cab");
  51. const TCHAR AU_KEY_INF_NAME[] = TEXT("inf");
  52. const TCHAR AU_KEY_RESMOD_NAME[] = TEXT("resmodule");
  53. const TCHAR AU_KEY_HELPFILE[] = TEXT("helpfile");
  54. const DWORD MAX_SECTION = 30;
  55. // main selfupdate keys
  56. const TCHAR IDENT_SERVERURLEX[] = _T("ServerUrlEx");
  57. const TCHAR IDENT_STRUCTUREKEYEX[] = _T("StructureKeyEx");
  58. const TCHAR INIVALUE_NOTFOUND[] = _T("??");
  59. BOOL fConvertVersionStrToDwords(LPTSTR pszVer, LPDWORD pdwVer, LPDWORD pdwBuild);
  60. HRESULT InstallUpdatedComponents(LPCTSTR pszSelfUpdateUrl,
  61. LPCTSTR pszMuiUpdateUrl,
  62. LPCTSTR pszIdentTxt,
  63. LPCTSTR pszFileCacheDir,
  64. LPCTSTR pszCif,
  65. BOOL *pfInstalledWUAUENG);
  66. BOOL ReplaceFileInPath(LPCTSTR pszPath, LPCTSTR szNewFile, LPTSTR pszNewPathBuf, DWORD cchNewPathBuf);
  67. BOOL MyGetPrivateProfileString( IN LPCWSTR lpAppName,
  68. IN LPCWSTR lpKeyName,
  69. OUT LPWSTR lpReturnedString,
  70. IN DWORD nSize,
  71. IN LPCWSTR lpFileName,
  72. IN LPCTSTR lpDefault=_T(""));
  73. inline BOOL fNewerFile(DWORD dwUpdateMS, DWORD dwUpdateLS, DWORD dwExistingMS, DWORD dwExistingLS)
  74. {
  75. return (dwUpdateMS > dwExistingMS) ||
  76. ((dwUpdateMS == dwExistingMS) && (dwUpdateLS > dwExistingLS));
  77. }
  78. inline HRESULT vAU_W2A(LPCWSTR lpWideCharStr, LPSTR lpMultiByteStr, int cbMultiByte)
  79. {
  80. if ( 0 != WideCharToMultiByte(CP_ACP, 0, lpWideCharStr, -1, lpMultiByteStr, cbMultiByte, NULL, NULL))
  81. {
  82. return S_OK;
  83. }
  84. else
  85. {
  86. return HRESULT_FROM_WIN32(GetLastError());
  87. }
  88. }
  89. HRESULT SelfUpdate(void)
  90. {
  91. HRESULT hr;
  92. BOOL fInstalledWUAUENG = FALSE;
  93. DEBUGMSG("------------------------SELFUPDATE BEGINS---------------------------");
  94. if( FAILED(hr = CheckForUpdatedComponents(&fInstalledWUAUENG)) )
  95. {
  96. goto lCleanUp;
  97. }
  98. if ( fInstalledWUAUENG )
  99. {
  100. DEBUGMSG("SELFUPDATE installed new wuaueng");
  101. hr = S_FALSE;
  102. goto lCleanUp;
  103. }
  104. lCleanUp:
  105. return hr;
  106. }
  107. /////////////////////////////////////////////////////////////////////////////////////////
  108. //
  109. // CleanFileCache()
  110. //
  111. //////////////////////////////////////////////////////////////////////////////////////////
  112. BOOL CleanFileCache(LPCTSTR pszFileCacheDir)
  113. {
  114. BOOL fRet = TRUE;
  115. TCHAR szFileCacheDir[MAX_PATH + 1];
  116. TCHAR szFilePath[MAX_PATH + 1];
  117. WIN32_FIND_DATA fd;
  118. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  119. if (FAILED(StringCchCopyEx(szFileCacheDir, ARRAYSIZE(szFileCacheDir), pszFileCacheDir, NULL, NULL, MISTSAFE_STRING_FLAGS)))
  120. {
  121. fRet = FALSE;
  122. goto done;
  123. }
  124. if (FAILED(PathCchAppend(szFileCacheDir, ARRAYSIZE(szFileCacheDir), TEXT("*.*"))))
  125. {
  126. fRet = FALSE;
  127. goto done;
  128. }
  129. // Find the first file
  130. hFindFile = FindFirstFile(szFileCacheDir, &fd);
  131. if ( INVALID_HANDLE_VALUE == hFindFile )
  132. {
  133. goto done;
  134. }
  135. do
  136. {
  137. if ( !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
  138. {
  139. // Make file path
  140. if (FAILED(StringCchCopyEx(szFilePath, ARRAYSIZE(szFilePath), pszFileCacheDir, NULL, NULL, MISTSAFE_STRING_FLAGS)) ||
  141. FAILED(PathCchAppend(szFilePath, ARRAYSIZE(szFilePath), fd.cFileName)) ||
  142. !SetFileAttributes(szFilePath, FILE_ATTRIBUTE_NORMAL) ||
  143. !DeleteFile(szFilePath))
  144. {
  145. fRet = FALSE;
  146. DEBUGMSG("Couldn't delete file %S", szFilePath);
  147. }
  148. }
  149. }
  150. while ( FindNextFile(hFindFile, &fd) );// Find the next entry
  151. done:
  152. if ( INVALID_HANDLE_VALUE != hFindFile )
  153. {
  154. FindClose(hFindFile);
  155. }
  156. return fRet;
  157. }
  158. //////////////////////////////////////////////////////////////////////
  159. //
  160. // GetSelfUpdateUrl()
  161. //
  162. // Should be like:
  163. //
  164. // http://windowsupdate.microsoft.com/selfupdate/x86/XP/en
  165. ////////////////////////////////////////////////////////////////////////
  166. HRESULT GetSelfUpdateUrl(LPCTSTR ptszName,
  167. LPCTSTR ptszBaseUrl,
  168. LPCTSTR pszIdentTxt,
  169. LPTSTR pszSelfUpdateUrl,
  170. DWORD cchSelfUpdateUrl,
  171. LPTSTR pszMuiUpdateUrl,
  172. DWORD cchMuiUpdateUrl)
  173. {
  174. LOG_Block("GetSelfUpdateUrl");
  175. HRESULT hr;
  176. TCHAR tszKey[MAX_SECTION]; // at least MAX_ISO_CODE_LENGTH
  177. TCHAR tszValue[MAX_PATH];
  178. BOOL fLangField;
  179. if (FAILED(hr = StringCchCopyEx(tszKey, ARRAYSIZE(tszKey), ptszName, NULL, NULL, MISTSAFE_STRING_FLAGS)) ||
  180. FAILED(hr = StringCchCatEx(tszKey, ARRAYSIZE(tszKey), _T("SelfUpdate"), NULL, NULL, MISTSAFE_STRING_FLAGS)))
  181. {
  182. goto lFinish;
  183. }
  184. if (NULL == ptszBaseUrl)
  185. {
  186. // Get SelfUpdate Server URL
  187. if (MyGetPrivateProfileString(
  188. tszKey,
  189. IDENT_SERVERURLEX,
  190. pszSelfUpdateUrl,
  191. cchSelfUpdateUrl,
  192. pszIdentTxt) == FALSE)
  193. {
  194. // no URL specified in iuident..
  195. hr = E_FAIL;
  196. goto lFinish;
  197. }
  198. else
  199. {
  200. if (FAILED(hr = StringCchCopyEx(pszMuiUpdateUrl, cchMuiUpdateUrl, pszSelfUpdateUrl, NULL, NULL, MISTSAFE_STRING_FLAGS)))
  201. goto lFinish;
  202. }
  203. }
  204. else
  205. {
  206. if (FAILED(hr = StringCchCopyEx(pszSelfUpdateUrl, cchSelfUpdateUrl, ptszBaseUrl, NULL, NULL, MISTSAFE_STRING_FLAGS)) ||
  207. FAILED(hr = StringCchCopyEx(pszMuiUpdateUrl, cchMuiUpdateUrl, ptszBaseUrl, NULL, NULL, MISTSAFE_STRING_FLAGS)))
  208. {
  209. goto lFinish;
  210. }
  211. // Remove trailing _T('/') if present
  212. int nBaseUrlLen = lstrlen(pszSelfUpdateUrl);
  213. if(nBaseUrlLen <= 0)
  214. {
  215. hr = E_FAIL;
  216. goto lFinish;
  217. }
  218. if (_T('/') == pszSelfUpdateUrl[nBaseUrlLen-1])
  219. {
  220. pszSelfUpdateUrl[nBaseUrlLen-1] = _T('\0');
  221. pszMuiUpdateUrl[nBaseUrlLen-1] = _T('\0');
  222. }
  223. }
  224. TCHAR tszStructure[MAX_PATH];
  225. if (!MyGetPrivateProfileString(
  226. tszKey,
  227. IDENT_STRUCTUREKEYEX,
  228. tszStructure,
  229. ARRAYSIZE(tszStructure),
  230. pszIdentTxt))
  231. {
  232. // no STRUCTYREKEY specified in iuident..
  233. hr = E_FAIL;
  234. goto lFinish;
  235. }
  236. // Parse the SelfUpdate Structure Key for Value Names to Read
  237. LPTSTR ptszWalk = tszStructure;
  238. while (_T('\0') != ptszWalk[0])
  239. {
  240. LPTSTR ptszDelim;
  241. fLangField = FALSE;
  242. if (NULL != (ptszDelim = StrChr(ptszWalk, TCHAR_SCTRUCTURE_DELIMITER)))
  243. {
  244. *ptszDelim = _T('\0');
  245. }
  246. if (_T('/') == ptszWalk[0])
  247. {
  248. if (FAILED(hr = StringCchCopyEx(tszValue, ARRAYSIZE(tszValue), ptszWalk, NULL, NULL, MISTSAFE_STRING_FLAGS)))
  249. {
  250. goto lFinish;
  251. }
  252. }
  253. else
  254. {
  255. int nPrefixLength = lstrlen(ptszName);
  256. LPCTSTR ptszToken = ptszWalk;
  257. if (0 == StrCmpNI(ptszWalk, ptszName, nPrefixLength))
  258. {
  259. ptszToken += nPrefixLength;
  260. }
  261. if (0 == StrCmpI(ptszToken, IDENT_ARCH))
  262. {
  263. if (!MyGetPrivateProfileString(
  264. ptszWalk,
  265. #ifdef _IA64_
  266. IDENT_IA64,
  267. #else
  268. IDENT_X86,
  269. #endif
  270. tszValue,
  271. ARRAYSIZE(tszValue),
  272. pszIdentTxt))
  273. {
  274. // insufficient buffer
  275. hr = E_FAIL;
  276. goto lFinish;
  277. }
  278. }
  279. else if (0 == StrCmpI(ptszToken, IDENT_OS))
  280. {
  281. if (FAILED(hr = StringCchCopyEx(tszKey, ARRAYSIZE(tszKey), ptszWalk, NULL, NULL, MISTSAFE_STRING_FLAGS)) ||
  282. FAILED(hr = StringCchCatEx(tszKey, ARRAYSIZE(tszKey), _T("NT"), NULL, NULL, MISTSAFE_STRING_FLAGS)))
  283. {
  284. goto lFinish;
  285. }
  286. if (S_OK != GetINIValueByOSVer(
  287. pszIdentTxt,
  288. tszKey,
  289. tszValue,
  290. ARRAYSIZE(tszValue)))
  291. {
  292. hr = E_FAIL;
  293. goto lFinish;
  294. }
  295. }
  296. else if (0 == StrCmpI(ptszToken, IDENT_LANG))
  297. {
  298. fLangField = TRUE;
  299. // Get the Current Locale String
  300. (void) LookupLocaleString(tszKey, ARRAYSIZE(tszKey), FALSE);
  301. if (0 == StrCmp(tszKey, _T("Error")))
  302. {
  303. DEBUGMSG("GetSelfUpdateUrl() call to LookupLocaleString() failed.");
  304. hr = E_FAIL;
  305. goto lFinish;
  306. }
  307. if (!MyGetPrivateProfileString(
  308. ptszWalk,
  309. tszKey,
  310. tszValue,
  311. ARRAYSIZE(tszValue),
  312. pszIdentTxt,INIVALUE_NOTFOUND))
  313. {
  314. hr = E_FAIL;
  315. goto lFinish;
  316. }
  317. if (0 == StrCmp(tszValue, INIVALUE_NOTFOUND))
  318. {
  319. LPTSTR ptszDash = StrChr(tszKey, _T('-'));
  320. if (NULL != ptszDash)
  321. {
  322. *ptszDash = _T('\0');
  323. if (!MyGetPrivateProfileString(
  324. ptszWalk,
  325. tszKey,
  326. tszValue,
  327. ARRAYSIZE(tszValue),
  328. pszIdentTxt))
  329. {
  330. hr = E_FAIL;
  331. goto lFinish;
  332. }
  333. }
  334. else
  335. {
  336. tszValue[0] = _T('\0');
  337. }
  338. }
  339. }
  340. else
  341. {
  342. LOG_Internet(_T("Found Unrecognized Token in SelfUpdate Structure String: Token was: %s"), ptszWalk);
  343. tszValue[0] = _T('\0'); // ignore the unrecognized token
  344. }
  345. }
  346. if (_T('\0') != tszValue[0])
  347. {
  348. LPCTSTR ptszMuiCopy;
  349. if (FAILED(hr = StringCchCatEx(pszSelfUpdateUrl, cchSelfUpdateUrl, tszValue, NULL, NULL, MISTSAFE_STRING_FLAGS)))
  350. goto lFinish;
  351. if (fLangField)
  352. ptszMuiCopy = MUI_WEBSUBPATH;
  353. else
  354. ptszMuiCopy = tszValue;
  355. if (FAILED(hr = StringCchCatEx(pszMuiUpdateUrl, cchMuiUpdateUrl, ptszMuiCopy, NULL, NULL, MISTSAFE_STRING_FLAGS)))
  356. goto lFinish;
  357. }
  358. if (NULL == ptszDelim)
  359. {
  360. break;
  361. }
  362. ptszWalk = ptszDelim + 1; // skip the previous token, and go to the next one in the string.
  363. *ptszDelim = TCHAR_SCTRUCTURE_DELIMITER;
  364. }
  365. DEBUGMSG("GetSelfUpdateUrl() Self Update URL is %S", pszSelfUpdateUrl);
  366. DEBUGMSG("GetSelfUpdateUrl() MUI Update URL is %S", pszMuiUpdateUrl);
  367. hr = S_OK;
  368. lFinish:
  369. if (FAILED(hr))
  370. {
  371. if (cchMuiUpdateUrl > 0)
  372. *pszMuiUpdateUrl = _T('\0');
  373. if (cchSelfUpdateUrl > 0)
  374. *pszSelfUpdateUrl = _T('\0');
  375. }
  376. return hr;
  377. }
  378. ////////////////////////////////////////////////////////////////////////////////////////
  379. //
  380. // CheckForUpdatedComponents
  381. //
  382. ////////////////////////////////////////////////////////////////////////////////////////
  383. HRESULT CheckForUpdatedComponents(BOOL *pfInstalledWUAUENG)
  384. {
  385. HRESULT hr;
  386. LPCTSTR ptszIdentServerUrl = NULL;
  387. LPTSTR ptszSelfUpdateUrl = NULL;
  388. LPTSTR ptszMuiUpdateUrl = NULL;
  389. if (NULL != (ptszSelfUpdateUrl = (LPTSTR) malloc(sizeof(TCHAR) * INTERNET_MAX_URL_LENGTH)) &&
  390. NULL != (ptszMuiUpdateUrl = (LPTSTR) malloc(sizeof(TCHAR) * INTERNET_MAX_URL_LENGTH)) &&
  391. NULL != (ptszIdentServerUrl = gpState->GetIdentServerURL()))
  392. {
  393. TCHAR szFileCacheDir[MAX_PATH+1];
  394. if ( FAILED(hr = MakeTempDownloadDir(szFileCacheDir, ARRAYSIZE(szFileCacheDir))) ||
  395. !CleanFileCache(szFileCacheDir) )
  396. {
  397. DEBUGMSG("Couldn't fully clean file cache %S", szFileCacheDir);
  398. hr = FAILED(hr) ? hr : E_FAIL;
  399. goto done;
  400. }
  401. BOOL fInCorpWU = gpState->fInCorpWU();
  402. if (IsConnected(ptszIdentServerUrl, !fInCorpWU))
  403. {
  404. DWORD dwFlags = 0;
  405. if (fInCorpWU)
  406. {
  407. dwFlags |= WUDF_DONTALLOWPROXY;
  408. }
  409. if (SUCCEEDED(hr = DownloadIUIdent(
  410. ghServiceFinished,
  411. ptszIdentServerUrl,
  412. szFileCacheDir,
  413. dwFlags)))
  414. {
  415. TCHAR tszIdentTxt[MAX_PATH];
  416. gPingStatus.ReadLiveServerUrlFromIdent();
  417. hr = PathCchCombine(tszIdentTxt, ARRAYSIZE(tszIdentTxt),
  418. szFileCacheDir, IDENT_TXT);
  419. if (FAILED(hr))
  420. goto done;
  421. if (SUCCEEDED(hr = GetSelfUpdateUrl(
  422. _T("AU"),
  423. gpState->GetSelfUpdateServerURLOverride(),
  424. tszIdentTxt,
  425. ptszSelfUpdateUrl,
  426. INTERNET_MAX_URL_LENGTH,
  427. ptszMuiUpdateUrl,
  428. INTERNET_MAX_URL_LENGTH)) &&
  429. SUCCEEDED(hr = DownloadCab(
  430. ghServiceFinished,
  431. WUAUCOMP_CAB,
  432. ptszSelfUpdateUrl,
  433. szFileCacheDir,
  434. dwFlags)))
  435. {
  436. TCHAR szWuaucompCif[MAX_PATH+1];
  437. if (SUCCEEDED(hr = PathCchCombine(szWuaucompCif, ARRAYSIZE(szWuaucompCif), szFileCacheDir, WUAUCOMP_CIF)))
  438. {
  439. // install any updated components
  440. hr = InstallUpdatedComponents(
  441. ptszSelfUpdateUrl,
  442. ptszMuiUpdateUrl,
  443. tszIdentTxt,
  444. szFileCacheDir,
  445. szWuaucompCif,
  446. pfInstalledWUAUENG);
  447. #ifdef DBG
  448. if (FAILED(hr))
  449. {
  450. DEBUGMSG("InstallUpdatedComponents failed");
  451. }
  452. #endif
  453. }
  454. }
  455. }
  456. }
  457. else
  458. {
  459. DEBUGMSG("SelfUpdate: No connection found.");
  460. hr = E_FAIL;
  461. }
  462. }
  463. else
  464. {
  465. hr = E_OUTOFMEMORY;
  466. }
  467. done:
  468. SafeFree(ptszSelfUpdateUrl);
  469. SafeFree(ptszMuiUpdateUrl);
  470. return hr;
  471. }
  472. /////////////////////////////////////////////////////////////////////////////////////////
  473. //
  474. // SfcMoveFileEx
  475. //
  476. //////////////////////////////////////////////////////////////////////////////////////////
  477. BOOL SfcMoveFileEx( IN LPCTSTR lpExistingFileName,
  478. IN LPCTSTR lpNewFileName,
  479. IN LPCTSTR lpSfcProtectedFile,
  480. IN HANDLE SfcRpcHandle)
  481. {
  482. BOOL fRet = TRUE;
  483. if ( SfcIsFileProtected(SfcRpcHandle, lpSfcProtectedFile) &&
  484. (ERROR_SUCCESS != SfcFileException(SfcRpcHandle,
  485. lpSfcProtectedFile,
  486. SFC_ACTION_RENAMED_OLD_NAME)) )
  487. {
  488. fRet = FALSE;
  489. goto done;
  490. }
  491. fRet = MoveFileEx(lpExistingFileName, lpNewFileName, MOVEFILE_REPLACE_EXISTING);
  492. done:
  493. if ( !fRet )
  494. {
  495. DEBUGMSG("Could not rename %S --> %S", lpExistingFileName, lpNewFileName);
  496. }
  497. return fRet;
  498. }
  499. /////////////////////////////////////////////////////////////////////////////////////////
  500. //
  501. // Function BuildPaths()
  502. //
  503. //////////////////////////////////////////////////////////////////////////////////////////
  504. HRESULT BuildPaths(AU_FILEINCAB *paufic, LPCTSTR pszFileName, LPCTSTR pszBasePath, LPCTSTR pszExtractBase,
  505. AU_LANG *paul)
  506. {
  507. HRESULT hr = S_OK;
  508. if (paufic == NULL || pszFileName == NULL || pszExtractBase == NULL)
  509. {
  510. hr = E_INVALIDARG;
  511. goto done;
  512. }
  513. if (pszBasePath != NULL)
  514. {
  515. // build the full file path
  516. hr = PathCchCombine(paufic->szFilePath, ARRAYSIZE(paufic->szFilePath),
  517. pszBasePath, pszFileName);
  518. if (FAILED(hr))
  519. goto done;
  520. paufic->fFileExists = fFileExists(paufic->szFilePath);
  521. }
  522. // file path we'll temporarily copy the original file to
  523. if (ReplaceFileExtension(paufic->szFilePath, _T(".bak"),
  524. paufic->szBackupFilePath,
  525. ARRAYSIZE(paufic->szBackupFilePath)) == FALSE)
  526. {
  527. hr = E_FAIL;
  528. goto done;
  529. }
  530. // file path we'll temporarily expand the new file to
  531. if (ReplaceFileExtension(paufic->szFilePath, _T(".new"),
  532. paufic->szNewFilePath,
  533. ARRAYSIZE(paufic->szNewFilePath)) == FALSE)
  534. {
  535. hr = E_FAIL;
  536. goto done;
  537. }
  538. if (ReplaceFileInPath(pszExtractBase, pszFileName,
  539. paufic->szExtractFilePath,
  540. ARRAYSIZE(paufic->szExtractFilePath)) == FALSE)
  541. {
  542. hr = E_FAIL;
  543. goto done;
  544. }
  545. // if we are processing a language file, append the language name to
  546. // the end of the extraction path to avoid collisions in this directory.
  547. if (paul != NULL)
  548. {
  549. hr = StringCchCatEx(paufic->szExtractFilePath,
  550. ARRAYSIZE(paufic->szExtractFilePath),
  551. paul->szAUName,
  552. NULL, NULL, MISTSAFE_STRING_FLAGS);
  553. if (FAILED(hr))
  554. goto done;
  555. }
  556. done:
  557. return hr;
  558. }
  559. /////////////////////////////////////////////////////////////////////////////////////////
  560. //
  561. // Function ProcessFile()
  562. //
  563. //////////////////////////////////////////////////////////////////////////////////////////
  564. HRESULT ProcessFile(AU_COMPONENT *paucParent, AU_COMPONENT *paucCurr, LPCTSTR pszBasePath,
  565. AU_LANG *paul, LPCTSTR pszCif)
  566. {
  567. USES_IU_CONVERSION;
  568. HRESULT hr = NOERROR;
  569. LPCTSTR pszIniFileVerToUse;
  570. DWORD dwExistingMS = 0, dwExistingLS = 0;
  571. TCHAR szValue[64], szIniFileVer[32];
  572. BOOL fRet;
  573. int cch, cchLang;
  574. // validate params
  575. if (paucCurr == NULL || pszBasePath == NULL || pszCif == NULL ||
  576. ((paucParent == NULL) != (paul == NULL)))
  577. {
  578. hr = E_INVALIDARG;
  579. goto done;
  580. }
  581. // build the full file path
  582. hr = PathCchCombine(paucCurr->szFilePath, ARRAYSIZE(paucCurr->szFilePath),
  583. pszBasePath, paucCurr->szFileName);
  584. if (FAILED(hr))
  585. goto done;
  586. // get the version of the file we should have
  587. if (paul != NULL)
  588. {
  589. hr = StringCchPrintfEx(szIniFileVer, ARRAYSIZE(szIniFileVer),
  590. NULL, NULL, MISTSAFE_STRING_FLAGS,
  591. _T("%s%s"), AU_KEY_FILE_VERSION, paul->szAUName);
  592. if (FAILED(hr))
  593. goto done;
  594. pszIniFileVerToUse = szIniFileVer;
  595. }
  596. else
  597. {
  598. pszIniFileVerToUse = AU_KEY_FILE_VERSION;
  599. }
  600. fRet = MyGetPrivateProfileString(paucCurr->pszSectionName,
  601. pszIniFileVerToUse,
  602. szValue, ARRAYSIZE(szValue),
  603. pszCif);
  604. if (fRet)
  605. {
  606. fRet = fConvertVersionStrToDwords(szValue, &paucCurr->dwUpdateMS,
  607. &paucCurr->dwUpdateLS);
  608. }
  609. // if we couldn't find the version string in the ini file, get it from the
  610. // parent AU_COMPONENT
  611. else if (paucParent != NULL)
  612. {
  613. paucCurr->dwUpdateMS = paucParent->dwUpdateMS;
  614. paucCurr->dwUpdateLS = paucParent->dwUpdateLS;
  615. fRet = TRUE;
  616. }
  617. if (fRet == FALSE)
  618. {
  619. hr = E_FAIL;
  620. goto done;
  621. }
  622. // see if we need to replace the file
  623. paucCurr->fFileExists = fFileExists(paucCurr->szFilePath);
  624. if (paucCurr->fFileExists)
  625. {
  626. LPSTR pszPathForVer;
  627. // if the file exists, then check for the version
  628. pszPathForVer = T2A(paucCurr->szFilePath);
  629. if (pszPathForVer == NULL)
  630. {
  631. hr = E_OUTOFMEMORY;
  632. goto done;
  633. }
  634. // this function will never return a failure code. Intstead, check if
  635. // both return values are 0
  636. hr = GetVersionFromFileEx(pszPathForVer, &dwExistingMS, &dwExistingLS,
  637. TRUE);
  638. if (FAILED(hr) || (dwExistingMS == 0 && dwExistingLS == 0))
  639. {
  640. hr = E_FAIL;
  641. goto done;
  642. }
  643. paucCurr->fDoUpgrade = fNewerFile(paucCurr->dwUpdateMS,
  644. paucCurr->dwUpdateLS,
  645. dwExistingMS,
  646. dwExistingLS);
  647. }
  648. else
  649. {
  650. // if the file doesn't exist, obviously gotta replace it
  651. paucCurr->fDoUpgrade = TRUE;
  652. }
  653. // if we don't need to update the file and it's not a parent file with
  654. // resources, then can just bail at this point.
  655. if (paucCurr->fDoUpgrade == FALSE)
  656. {
  657. if (paul != NULL ||
  658. (paul == NULL && paucCurr->fNeedToCheckMui == FALSE))
  659. {
  660. hr = S_FALSE;
  661. goto done;
  662. }
  663. }
  664. else
  665. {
  666. DEBUGMSG("PASS 1 -- newer file in section %S", paucCurr->pszSectionName);
  667. }
  668. // get the cab and inf name. For non-MUI files, we fetch this out of the ini.
  669. if (paul == NULL)
  670. {
  671. if (MyGetPrivateProfileString(paucCurr->pszSectionName,
  672. AU_KEY_CAB_NAME,
  673. paucCurr->szCabName,
  674. ARRAYSIZE(paucCurr->szCabName),
  675. pszCif) == FALSE)
  676. {
  677. hr = E_FAIL;
  678. goto done;
  679. }
  680. // if there is no inf, "" is value of field, so we're ok ignoring a
  681. // failure here
  682. MyGetPrivateProfileString(paucCurr->pszSectionName,
  683. AU_KEY_INF_NAME,
  684. paucCurr->szInfName,
  685. ARRAYSIZE(paucCurr->szInfName),
  686. pszCif);
  687. }
  688. // for MUI files, we base it on the name of the cab from the parent file.
  689. else
  690. {
  691. LPTSTR pszExt;
  692. DWORD cchExt, cchName;
  693. // make sure the buffer is big enuf
  694. cch = lstrlen(paucParent->szCabName);
  695. cchLang = lstrlen(paul->szAUName);
  696. if (cch + cchLang >= ARRAYSIZE(paucCurr->szCabName))
  697. {
  698. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  699. goto done;
  700. }
  701. hr = StringCchCopyEx(paucCurr->szCabName, ARRAYSIZE(paucCurr->szCabName),
  702. paucParent->szCabName,
  703. NULL, NULL, MISTSAFE_STRING_FLAGS);
  704. if (FAILED(hr))
  705. goto done;
  706. // paucCurr->szCabName
  707. for (pszExt = paucCurr->szCabName + cch, cchExt = 0;
  708. pszExt > paucCurr->szCabName && *pszExt != _T('\\') && *pszExt != _T('.');
  709. pszExt--, cchExt++);
  710. // if we hit a backslash or the beginning of the string, then move the
  711. // extension pointer to the NULL terminator.
  712. if (*pszExt == _T('\\') || pszExt <= paucCurr->szCabName)
  713. {
  714. pszExt = paucCurr->szCabName + cch;
  715. cchExt = 0;
  716. }
  717. cchName = (DWORD)(pszExt - paucCurr->szCabName);
  718. // append the language to where the extension (if any) currently exists
  719. hr = StringCchCopyEx(pszExt, ARRAYSIZE(paucCurr->szCabName) - cchName,
  720. paul->szAUName,
  721. NULL, NULL, MISTSAFE_STRING_FLAGS);
  722. if (FAILED(hr))
  723. goto done;
  724. // if there is an extension, copy it over from the original string in
  725. // the parent AU_COMPONENT
  726. if (cchExt > 0)
  727. {
  728. hr = StringCchCopyEx(&paucCurr->szCabName[cchName + cchLang],
  729. ARRAYSIZE(paucCurr->szCabName) - cchName - cchLang,
  730. &paucParent->szCabName[cchName],
  731. NULL, NULL, MISTSAFE_STRING_FLAGS);
  732. if (FAILED(hr))
  733. goto done;
  734. }
  735. }
  736. if (ReplaceFileInPath(pszCif, paucCurr->szCabName,
  737. paucCurr->szCabPath,
  738. ARRAYSIZE(paucCurr->szCabPath)) == FALSE)
  739. {
  740. hr = E_FAIL;
  741. goto done;
  742. }
  743. hr = BuildPaths(paucCurr, paucCurr->szFileName, NULL, pszCif, paul);
  744. if (FAILED(hr))
  745. goto done;
  746. done:
  747. return hr;
  748. }
  749. /////////////////////////////////////////////////////////////////////////////////////////
  750. //
  751. // Function InstallUpdatedComponents()
  752. //
  753. //////////////////////////////////////////////////////////////////////////////////////////
  754. HRESULT InstallUpdatedComponents(LPCTSTR pszSelfUpdateUrl,
  755. LPCTSTR pszMuiUpdateUrl,
  756. LPCTSTR pszIdentTxt,
  757. LPCTSTR pszFileCacheDir,
  758. LPCTSTR pszCif,
  759. BOOL *pfInstalledWUAUENG)
  760. {
  761. USES_IU_CONVERSION;
  762. AU_COMPONENT *paucRoot = NULL;
  763. AU_COMPONENT *paucCurr = NULL;
  764. AU_COMPONENT *paucParent = NULL;
  765. AU_COMPONENT *paucMui = NULL;
  766. AU_FILEINCAB *paufic = NULL;
  767. HRESULT hr = S_OK;
  768. HANDLE SfcRpcHandle = NULL;
  769. LPTSTR pszSection = NULL;
  770. TCHAR szSectionNames[1024];
  771. TCHAR szSysDir[MAX_PATH + 1];
  772. TCHAR szSrcPath[MAX_PATH + 1];
  773. TCHAR szHelpFile[_MAX_FNAME + 1];
  774. DWORD cchSectionNames, cch;
  775. BOOL fFailedInstall = FALSE;
  776. // MUI stuff
  777. AU_LANGLIST aull;
  778. DWORD cchMuiDir = 0, cchMuiDirAvail = 0;
  779. DWORD cchHelpMuiDir = 0, cchHelpMuiDirAvail = 0;
  780. TCHAR szMuiDir[MAX_PATH + 1];
  781. TCHAR szHelpMuiDir[MAX_PATH + 1];
  782. ZeroMemory(&aull, sizeof(aull));
  783. aull.pszIdentFile = pszIdentTxt;
  784. szMuiDir[0] = _T('\0');
  785. szHelpMuiDir[0] = _T('\0');
  786. *pfInstalledWUAUENG = FALSE;
  787. SfcRpcHandle = SfcConnectToServer(NULL);
  788. if (NULL == SfcRpcHandle)
  789. {
  790. hr = E_FAIL;
  791. goto done;
  792. }
  793. // determine how many components there are to update.
  794. cchSectionNames = GetPrivateProfileSectionNames(szSectionNames,
  795. ARRAYSIZE(szSectionNames),
  796. pszCif);
  797. if ((ARRAYSIZE(szSectionNames) - 2) == cchSectionNames)
  798. {
  799. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  800. goto done;
  801. }
  802. cchMuiDir = ARRAYSIZE(szMuiDir);
  803. cchHelpMuiDir = ARRAYSIZE(szHelpMuiDir);
  804. hr = GetMuiLangList(&aull, szMuiDir, &cchMuiDir, szHelpMuiDir, &cchHelpMuiDir);
  805. if (FAILED(hr))
  806. goto done;
  807. cchMuiDirAvail = ARRAYSIZE(szMuiDir) - cchMuiDir;
  808. cchHelpMuiDirAvail = ARRAYSIZE(szHelpMuiDir) - cchHelpMuiDir;
  809. cch = GetSystemDirectory(szSysDir, ARRAYSIZE(szSysDir));
  810. if (cch == 0 || cch >= ARRAYSIZE(szSysDir))
  811. {
  812. hr = HRESULT_FROM_WIN32(GetLastError());
  813. goto done;
  814. }
  815. // PASS 1: figure out which files to upgrade
  816. for (pszSection = szSectionNames;
  817. *pszSection != _T('\0');
  818. pszSection += lstrlen(pszSection) + 1)
  819. {
  820. szHelpFile[0] = _T('\0');
  821. // if we didn't need to upgrade the parent file from the previous pass
  822. // then we don't need to alloc a new blob- just reuse the one from the
  823. // previous pass. To signal this, we'll set paucParent to NULL if we
  824. // add it to the linked list- note this covers us for the first time
  825. // thru the loop cuz we initialize paucParent to NULL.
  826. if (paucParent == NULL)
  827. {
  828. paucParent = (AU_COMPONENT *)malloc(sizeof(AU_COMPONENT));
  829. if (paucParent == NULL)
  830. {
  831. hr = E_OUTOFMEMORY;
  832. goto done;
  833. }
  834. }
  835. ZeroMemory(paucParent, sizeof(AU_COMPONENT));
  836. paucParent->fMuiFile = FALSE;
  837. DEBUGMSG("PASS 1 -- section %S", pszSection);
  838. paucParent->pszSectionName = pszSection;
  839. if (MyGetPrivateProfileString(paucParent->pszSectionName,
  840. AU_KEY_FILE_NAME,
  841. paucParent->szFileName,
  842. ARRAYSIZE(paucParent->szFileName),
  843. pszCif) == FALSE)
  844. {
  845. hr = E_FAIL;
  846. goto done;
  847. }
  848. if (aull.cLangs > 0)
  849. {
  850. UINT uiHasResources;
  851. // see if we need to test for MUI file updates
  852. uiHasResources = GetPrivateProfileInt(paucParent->pszSectionName,
  853. AU_KEY_RESMOD_NAME,
  854. 0,
  855. pszCif);
  856. // if we do have resources, then check if we also have a helpfile
  857. if (uiHasResources == 1)
  858. {
  859. paucParent->fNeedToCheckMui = TRUE;
  860. if (MyGetPrivateProfileString(paucParent->pszSectionName,
  861. AU_KEY_HELPFILE,
  862. szHelpFile, ARRAYSIZE(szHelpFile),
  863. pszCif) == FALSE)
  864. {
  865. szHelpFile[0] = _T('\0');
  866. }
  867. }
  868. else
  869. {
  870. paucParent->fNeedToCheckMui = FALSE;
  871. }
  872. }
  873. else
  874. {
  875. paucParent->fNeedToCheckMui = FALSE;
  876. }
  877. hr = ProcessFile(NULL, paucParent, szSysDir, NULL, pszCif);
  878. if (FAILED(hr))
  879. goto done;
  880. if (paucParent->fNeedToCheckMui)
  881. {
  882. DWORD iLang;
  883. DWORD cchParentFile;
  884. cchParentFile = lstrlen(paucParent->szFileName);
  885. if (cchParentFile + ARRAYSIZE(MUI_EXT) > ARRAYSIZE(paucParent->szFileName))
  886. {
  887. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  888. goto done;
  889. }
  890. for (iLang = 0; iLang < aull.cLangs; iLang++)
  891. {
  892. // if we didn't need to upgrade the file from the previous
  893. // pass then we don't need to alloc a new blob- just reuse
  894. // the one from the previous pass.
  895. if (paucMui == NULL)
  896. {
  897. paucMui = (AU_COMPONENT *)malloc(sizeof(AU_COMPONENT));
  898. if (paucMui == NULL)
  899. {
  900. hr = E_OUTOFMEMORY;
  901. goto done;
  902. }
  903. }
  904. ZeroMemory(paucMui, sizeof(AU_COMPONENT));
  905. paucMui->pszSectionName = paucParent->pszSectionName;
  906. paucMui->fMuiFile = TRUE;
  907. // ProcessFile does not expect a trailing backslash, so be sure
  908. // not to add one. Note that we've checked the size of the
  909. // buffer against the largest possible string it will contain
  910. // above, so this should not fail.
  911. // The directory is build with the MUI langauge name (4 hex chars)
  912. hr = StringCchCopyEx(&szMuiDir[cchMuiDir], cchMuiDirAvail,
  913. aull.rgpaulLangs[iLang]->szMuiName,
  914. NULL, NULL, MISTSAFE_STRING_FLAGS);
  915. if (FAILED(hr))
  916. goto done;
  917. // the filename for a language is the same as the parent file with
  918. // a ".mui" added to the end
  919. hr = StringCchCopyEx(paucMui->szFileName, ARRAYSIZE(paucMui->szFileName),
  920. paucParent->szFileName,
  921. NULL, NULL, MISTSAFE_STRING_FLAGS);
  922. if (FAILED(hr))
  923. goto done;
  924. hr = StringCchCopyEx(&paucMui->szFileName[cchParentFile],
  925. ARRAYSIZE(paucMui->szFileName) - cchParentFile,
  926. MUI_EXT,
  927. NULL, NULL, MISTSAFE_STRING_FLAGS);
  928. if (FAILED(hr))
  929. goto done;
  930. hr = ProcessFile(paucParent, paucMui,
  931. szMuiDir,
  932. aull.rgpaulLangs[iLang],
  933. pszCif);
  934. if (FAILED(hr))
  935. goto done;
  936. // Clean up for the next language
  937. szMuiDir[cchMuiDir] = _T('\0');
  938. // don't need to update the file
  939. if (paucMui->fDoUpgrade == FALSE)
  940. continue;
  941. if (szHelpFile[0] != _T('\0'))
  942. {
  943. paucMui->pNextFileInCab = (AU_FILEINCAB *)malloc(sizeof(AU_FILEINCAB));
  944. if (paucMui->pNextFileInCab == NULL)
  945. {
  946. hr = E_OUTOFMEMORY;
  947. goto done;
  948. }
  949. ZeroMemory(paucMui->pNextFileInCab, sizeof(AU_FILEINCAB));
  950. hr = StringCchCopyEx(&szHelpMuiDir[cchHelpMuiDir], cchHelpMuiDirAvail,
  951. aull.rgpaulLangs[iLang]->szMuiName,
  952. NULL, NULL, MISTSAFE_STRING_FLAGS);
  953. if (FAILED(hr))
  954. goto done;
  955. hr = BuildPaths(paucMui->pNextFileInCab,
  956. szHelpFile, szHelpMuiDir,
  957. pszCif,
  958. aull.rgpaulLangs[iLang]);
  959. if (FAILED(hr))
  960. goto done;
  961. }
  962. // we do need to update the file, so add it to our list of files
  963. // to update
  964. paucMui->pNext = paucRoot;
  965. paucRoot = paucMui;
  966. paucMui = NULL;
  967. }
  968. }
  969. // if we need to update the parent file, add it to our list of files to
  970. // update
  971. if (paucParent->fDoUpgrade)
  972. {
  973. paucParent->pNext = paucRoot;
  974. paucRoot = paucParent;
  975. paucParent = NULL;
  976. }
  977. }
  978. // short cut the rest of the function if we have no work to do
  979. hr = S_OK;
  980. if (paucRoot == NULL)
  981. goto done;
  982. // PASS 2: bring down the required cabs
  983. DWORD dwFlags = 0;
  984. if (gpState->fInCorpWU())
  985. {
  986. dwFlags |= WUDF_DONTALLOWPROXY;
  987. }
  988. for (paucCurr = paucRoot; paucCurr != NULL; paucCurr = paucCurr->pNext)
  989. {
  990. LPCTSTR pszDownloadUrl;
  991. pszDownloadUrl = (paucCurr->fMuiFile) ? pszMuiUpdateUrl : pszSelfUpdateUrl;
  992. DEBUGMSG("PASS 2 -- downloading %S", paucCurr->szCabName);
  993. // We have to install so bring down the full cab
  994. hr = DownloadCab(ghServiceFinished,
  995. paucCurr->szCabName,
  996. pszDownloadUrl,
  997. pszFileCacheDir,
  998. dwFlags);
  999. if (FAILED(hr))
  1000. {
  1001. DEBUGMSG("Failed to download %S (%#lx)", paucCurr->szCabName, hr);
  1002. goto done;
  1003. }
  1004. //Verify that the extracted file is a binary and it's subsystem matches that of the OS
  1005. if (FAILED(hr = IsBinaryCompatible(paucCurr->szExtractFilePath)))
  1006. {
  1007. DEBUGMSG("%S is not a valid binary file (error %#lx)", paucCurr->szExtractFilePath, hr);
  1008. goto done;
  1009. }
  1010. // Check version number against cif
  1011. DWORD dwNewMS, dwNewLS;
  1012. LPSTR pszTmp;
  1013. pszTmp = T2A(paucCurr->szExtractFilePath);
  1014. if (pszTmp == NULL)
  1015. {
  1016. hr = E_OUTOFMEMORY;
  1017. goto done;
  1018. }
  1019. // this function will never return a failure code. Intstead, check if
  1020. // both return values are 0
  1021. hr = GetVersionFromFileEx(pszTmp, &dwNewMS, &dwNewLS, TRUE /* get version */);
  1022. if (FAILED(hr) || (dwNewMS == 0 && dwNewLS == 0))
  1023. {
  1024. DEBUGMSG("Failed to get version info from %S (%#lx)", paucCurr->szExtractFilePath, hr);
  1025. goto done;
  1026. }
  1027. if (paucCurr->dwUpdateMS != dwNewMS ||
  1028. paucCurr->dwUpdateLS != dwNewLS)
  1029. {
  1030. hr = HRESULT_FROM_WIN32(ERROR_INSTALL_PACKAGE_VERSION);
  1031. DEBUGMSG("Version mismatch for %S - %d.%d.%d.%d vs %d.%d.%d.%d",
  1032. paucCurr->szExtractFilePath,
  1033. HIWORD(paucCurr->dwUpdateMS),
  1034. LOWORD(paucCurr->dwUpdateMS),
  1035. HIWORD(paucCurr->dwUpdateLS),
  1036. LOWORD(paucCurr->dwUpdateLS),
  1037. HIWORD(dwNewMS),
  1038. LOWORD(dwNewMS),
  1039. HIWORD(dwNewLS),
  1040. LOWORD(dwNewLS));
  1041. goto done;
  1042. }
  1043. }
  1044. hr = StringCchCopyEx(szSrcPath, ARRAYSIZE(szSrcPath), pszCif,
  1045. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1046. if (FAILED(hr))
  1047. goto done;
  1048. PathRemoveFileSpec(szSrcPath);
  1049. // PASS 3: Copy files to *.new in destination directory.
  1050. for (paucCurr = paucRoot; paucCurr != NULL; paucCurr = paucCurr->pNext)
  1051. {
  1052. if (FAILED(hr = vAU_W2A(paucCurr->szCabPath,
  1053. paucCurr->a_szCabPath,
  1054. sizeof(paucCurr->a_szCabPath))))
  1055. {
  1056. fFailedInstall = TRUE;
  1057. goto done;
  1058. }
  1059. // copy all the files to their new locations
  1060. for (paufic = paucCurr; paufic != NULL; paufic = paufic->pNextFileInCab)
  1061. {
  1062. DEBUGMSG("PASS 3 -- copying %S --> %S",
  1063. paufic->szExtractFilePath,
  1064. paufic->szNewFilePath);
  1065. if ( !CopyFile(paufic->szExtractFilePath, paufic->szNewFilePath, FALSE) )
  1066. {
  1067. fFailedInstall = TRUE;
  1068. hr = E_FAIL;
  1069. goto done;
  1070. }
  1071. }
  1072. // this comparison is sufficient because we don't care if we replaced a
  1073. // MUI lang pack for wuaueng.dll. The reason is that the service runs
  1074. // as local system, which always uses the native language (and the
  1075. // service doesn't pop up UI anyway)
  1076. // we do, however, need to check for a winhttp update
  1077. if (StrCmpI(WUAUENG_DLL, paucCurr->szFileName) == 0 ||
  1078. StrCmpI(c_szWinHttpDll, paucCurr->szFileName) == 0)
  1079. {
  1080. *pfInstalledWUAUENG = TRUE;
  1081. }
  1082. }
  1083. // PASS 4: Move the <file>.new into its proper location
  1084. for (paucCurr = paucRoot; paucCurr != NULL; paucCurr = paucCurr->pNext)
  1085. {
  1086. // copy all the files to their new locations
  1087. for (paufic = paucCurr; paufic != NULL; paufic = paufic->pNextFileInCab)
  1088. {
  1089. if ( paufic->fFileExists )
  1090. {
  1091. DEBUGMSG("PASS 4 -- renaming %S --> %S", paufic->szFilePath, paufic->szBackupFilePath);
  1092. if ( !SfcMoveFileEx(paufic->szFilePath, paufic->szBackupFilePath,
  1093. paufic->szFilePath, SfcRpcHandle) )
  1094. {
  1095. fFailedInstall = TRUE;
  1096. hr = E_FAIL;
  1097. goto done;
  1098. }
  1099. paufic->fCreatedBackup = TRUE;
  1100. }
  1101. DEBUGMSG("PASS 4 -- renaming %S --> %S", paufic->szNewFilePath, paufic->szFilePath);
  1102. if (!MoveFileEx(paufic->szNewFilePath, paufic->szFilePath, MOVEFILE_REPLACE_EXISTING))
  1103. {
  1104. fFailedInstall = TRUE;
  1105. hr = E_FAIL;
  1106. goto done;
  1107. }
  1108. }
  1109. }
  1110. // PASS 5: Run any .inf file.
  1111. for (paucCurr = paucRoot; paucCurr != NULL; paucCurr = paucCurr->pNext)
  1112. {
  1113. if (paucCurr->szInfName[0] != _T('\0'))
  1114. {
  1115. DEBUGMSG("PASS 5A -- executing inf %S", paucCurr->szInfName);
  1116. CABINFO cabinfo;
  1117. HRESULT hr2;
  1118. cabinfo.pszCab = paucCurr->a_szCabPath;
  1119. cabinfo.pszInf = paucCurr->a_szInfName;
  1120. if (FAILED( hr2 = vAU_W2A(paucCurr->szInfName, paucCurr->a_szInfName, sizeof(paucCurr->a_szInfName)))
  1121. || FAILED(hr2 = vAU_W2A(szSrcPath, cabinfo.szSrcPath, sizeof(cabinfo.szSrcPath))))
  1122. {
  1123. DEBUGMSG("vAU_W2A failed: %#lx", hr2);
  1124. if (SUCCEEDED(hr))
  1125. {
  1126. hr = hr2;
  1127. fFailedInstall = TRUE;
  1128. }
  1129. // don't delete the backup file. Need to restore it afterwards.
  1130. continue;
  1131. }
  1132. cabinfo.pszSection = "DefaultInstall";
  1133. cabinfo.dwFlags = ALINF_QUIET;
  1134. if ( FAILED(hr2 = ExecuteCab(NULL, &cabinfo, NULL)) )
  1135. {
  1136. DEBUGMSG("ExecuteCab failed on %s (%#lx)", paucCurr->a_szInfName, hr2);
  1137. if (SUCCEEDED(hr))
  1138. {
  1139. hr = hr2;
  1140. fFailedInstall = TRUE;
  1141. }
  1142. // don't delete the backup file. Need to restore it afterwards.
  1143. continue;
  1144. }
  1145. }
  1146. for (paufic = paucCurr; paufic != NULL; paufic = paufic->pNextFileInCab)
  1147. {
  1148. // delete the backup file corresponding to the .inf which was successfully installed
  1149. if (paufic->fCreatedBackup &&
  1150. StrCmpI(WUAUENG_DLL, paucCurr->szFileName) != 0)
  1151. {
  1152. DEBUGMSG("PASS 5B - deleting bak file %S", paufic->szBackupFilePath);
  1153. if ( DeleteFile(paufic->szBackupFilePath) )
  1154. {
  1155. paufic->fCreatedBackup = FALSE;
  1156. }
  1157. #ifdef DBG
  1158. else
  1159. {
  1160. DEBUGMSG("Could not delete %S (error %d)", paufic->szBackupFilePath, GetLastError());
  1161. }
  1162. #endif
  1163. }
  1164. }
  1165. }
  1166. done:
  1167. // if we failed an install, revert all the prior installs
  1168. if ( fFailedInstall )
  1169. {
  1170. for (paucCurr = paucRoot; paucCurr != NULL; paucCurr = paucCurr->pNext)
  1171. {
  1172. for(paufic = paucCurr; paufic != NULL; paufic = paufic->pNextFileInCab)
  1173. {
  1174. if (paufic->fCreatedBackup)
  1175. {
  1176. DEBUGMSG("Reverting %S --> %S", paufic->szBackupFilePath, paufic->szFilePath);
  1177. MoveFileEx(paufic->szBackupFilePath, paufic->szFilePath, MOVEFILE_REPLACE_EXISTING);
  1178. }
  1179. }
  1180. }
  1181. }
  1182. if (paucParent != NULL)
  1183. free(paucParent);
  1184. if (paucMui != NULL)
  1185. {
  1186. while (paucMui->pNextFileInCab != NULL)
  1187. {
  1188. paufic = paucMui->pNextFileInCab;
  1189. paucMui->pNextFileInCab = paucMui->pNextFileInCab->pNextFileInCab;
  1190. free(paufic);
  1191. }
  1192. free(paucMui);
  1193. }
  1194. // cleanup the linked list of files
  1195. while(paucRoot != NULL)
  1196. {
  1197. paucCurr = paucRoot;
  1198. paucRoot = paucCurr->pNext;
  1199. while (paucCurr->pNextFileInCab != NULL)
  1200. {
  1201. paufic = paucCurr->pNextFileInCab;
  1202. paucCurr->pNextFileInCab = paucCurr->pNextFileInCab->pNextFileInCab;
  1203. free(paufic);
  1204. }
  1205. free(paucCurr);
  1206. }
  1207. // cleanup the MUI stuff
  1208. CleanupMuiLangList(&aull);
  1209. if ( NULL != SfcRpcHandle )
  1210. {
  1211. SfcClose(SfcRpcHandle);
  1212. }
  1213. return hr;
  1214. }
  1215. ////////////////////////////////////////////////////////////////////////////
  1216. //
  1217. // fConvertDotVersionStrToDwords
  1218. //
  1219. ////////////////////////////////////////////////////////////////////////////
  1220. BOOL fConvertVersionStrToDwords(LPTSTR pszVer, LPDWORD pdwMS, LPDWORD pdwLS)
  1221. {
  1222. DWORD grVerFields[4] = {0,0,0,0};
  1223. TCHAR *pch = pszVer;
  1224. int i;
  1225. // _ttol will stop when it hits a non-numeric character, so we're
  1226. // safe calling it this way
  1227. grVerFields[0] = _ttol(pch);
  1228. for (i = 1; i < 4; i++)
  1229. {
  1230. while (*pch != _T('\0') && _istdigit(*pch))
  1231. pch++;
  1232. if (*pch == _T('\0'))
  1233. break;
  1234. pch++;
  1235. // _ttol will stop when it hits a non-numeric character, so we're
  1236. // safe calling it this way
  1237. grVerFields[i] = _ttol(pch);
  1238. }
  1239. *pdwMS = (grVerFields[0] << 16) + grVerFields[1];
  1240. *pdwLS = (grVerFields[2] << 16) + grVerFields[3];
  1241. return true;
  1242. }
  1243. ////////////////////////////////////////////////////////////////////////////
  1244. //
  1245. // MyGetPrivateProfileString
  1246. //
  1247. // Same as normal call but if buffer is too small or default string is returned
  1248. // then function returns FALSE.
  1249. ////////////////////////////////////////////////////////////////////////////
  1250. BOOL MyGetPrivateProfileString( IN LPCTSTR lpAppName,
  1251. IN LPCTSTR lpKeyName,
  1252. OUT LPTSTR lpReturnedString,
  1253. IN DWORD nSize,
  1254. IN LPCTSTR lpFileName,
  1255. IN LPCTSTR lpDefault)
  1256. {
  1257. BOOL fRet = TRUE;
  1258. if (NULL == lpAppName || NULL == lpKeyName || NULL == lpDefault || NULL == lpReturnedString)
  1259. {
  1260. return FALSE;
  1261. }
  1262. DWORD dwRet = GetPrivateProfileString(lpAppName,
  1263. lpKeyName,
  1264. lpDefault,
  1265. lpReturnedString,
  1266. nSize,
  1267. lpFileName);
  1268. if ( ((nSize - 1) == dwRet) || (_T('\0') == *lpReturnedString) )
  1269. {
  1270. fRet = FALSE;
  1271. }
  1272. return fRet;
  1273. }