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.

1803 lines
46 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: fileutil.cpp
  6. //
  7. // Description:
  8. //
  9. // IU file utility library
  10. //
  11. //=======================================================================
  12. #include <windows.h>
  13. #include <tchar.h>
  14. #include <stringutil.h>
  15. #include <shlobj.h>
  16. #include <shlwapi.h>
  17. #include <memutil.h>
  18. #include <fileutil.h>
  19. #include <platform.h>
  20. #include <logging.h>
  21. #include <iucommon.h>
  22. #include <advpub.h>
  23. #include <wincrypt.h>
  24. #include <mscat.h>
  25. #include "mistsafe.h"
  26. #include "wusafefn.h"
  27. const TCHAR REGKEY_WINDOWSUPDATE[] = _T("\\WindowsUpdate\\");
  28. const TCHAR REGKEY_INDUSTRYUPDATE[] = _T("\\WindowsUpdate\\V4\\");
  29. const TCHAR REGKEY_WINCURDIR[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion");
  30. const TCHAR REGKEY_PROGFILES[] = _T(":\\Program Files");
  31. const TCHAR REGKEY_PROGFILESDIR[] = _T("ProgramFilesDir");
  32. const TCHAR REGKEY_IUCTL[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\IUControl");
  33. const TCHAR REGVAL_ISBETA[] = _T("IsBeta");
  34. const TCHAR IDENT_IUSERVERCACHE[] = _T("IUServerCache");
  35. const TCHAR IDENT_DEFAULTQUERYSERVERINDEX[] = _T("DefaultQueryServerIndex");
  36. const TCHAR IDENT_BETAQUERYSERVERINDEX[] = _T("BetaQueryServerIndex");
  37. const TCHAR IDENT_QUERYSERVERINDEX[] = _T("QueryServerIndex");
  38. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  39. #define IfNullReturnNull(ptr) if (NULL == ptr) return NULL;
  40. #define InitString(lpStr) if (NULL != lpStr) lpStr[0] = TCHAR_EOS
  41. typedef BOOL (WINAPI * PFN_GetDiskFreeSpaceEx) (
  42. LPCTSTR lpDirectoryName, // directory name
  43. PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
  44. PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
  45. PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
  46. );
  47. //---------------------------------------------------------------------
  48. // CreateNestedDirectory
  49. // Creates the full path of the directory (nested directories)
  50. //---------------------------------------------------------------------
  51. #pragma warning( disable : 4706 ) // Ignore warning C4706: assignment within conditional expression
  52. BOOL CreateNestedDirectory(LPCTSTR pszDir)
  53. {
  54. BOOL bRc;
  55. TCHAR szPath[MAX_PATH];
  56. HRESULT hr=S_OK;
  57. if (NULL == pszDir || MAX_PATH < (lstrlen(pszDir) + 1))
  58. {
  59. return FALSE;
  60. }
  61. //
  62. // make a local copy and remove final slash
  63. //
  64. hr=StringCchCopyEx(szPath,ARRAYSIZE(szPath),pszDir,NULL,NULL,MISTSAFE_STRING_FLAGS);
  65. if(FAILED(hr))
  66. {
  67. SetLastError(HRESULT_CODE(hr));
  68. return FALSE;
  69. }
  70. int iLast = lstrlen(szPath) - 1;
  71. if (0 > iLast) // Prefix
  72. iLast = 0;
  73. if (szPath[iLast] == '\\')
  74. szPath[iLast] = 0;
  75. //
  76. // check to see if directory already exists
  77. //
  78. DWORD dwAttr = GetFileAttributes(szPath);
  79. if (dwAttr != 0xFFFFFFFF)
  80. {
  81. if ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0)
  82. return TRUE;
  83. }
  84. //
  85. // create it
  86. //
  87. TCHAR* p = szPath;
  88. if (p[1] == ':')
  89. p += 2;
  90. else
  91. {
  92. // Check if the path is a UNC, need to skip past the UNC Server\Share specification to get to
  93. // real path
  94. if (p[0] == '\\' && p[1] == '\\')
  95. {
  96. p += 2;
  97. // skip to the beginning of the share declaration
  98. p = _tcschr(p, '\\');
  99. if (NULL == p)
  100. {
  101. return FALSE; // invalid UNC
  102. }
  103. p++;
  104. // look for a trailing '\', if it exists then we want to further check for any nested levels,
  105. // otherwise the path as is should be valid.
  106. p = _tcschr(p, '\\');
  107. if (NULL == p)
  108. {
  109. // UNC is valid base share name, assume its valid
  110. return TRUE;
  111. }
  112. else
  113. {
  114. // look for any further levels, if they exist then pass through to the rest of the directory
  115. // creator
  116. p++;
  117. if (NULL == p)
  118. {
  119. // UNC is valid base share name, but had a trailing slash, not a problem, assume its valid
  120. return TRUE;
  121. }
  122. // if we haven't exited then there are remaining levels, don't reset our current pointer in the string
  123. // and let the rest of the nested directory creation work.
  124. }
  125. }
  126. }
  127. if (*p == '\\')
  128. p++;
  129. while (p = _tcschr(p, '\\')) // Ignore warning C4706: assignment within conditional expression
  130. {
  131. *p = 0;
  132. bRc = CreateDirectory(szPath, NULL);
  133. *p = '\\';
  134. p++;
  135. if (!bRc)
  136. {
  137. if (GetLastError() != ERROR_ALREADY_EXISTS)
  138. {
  139. return FALSE;
  140. }
  141. }
  142. }
  143. bRc = CreateDirectory(szPath, NULL);
  144. if ( !bRc )
  145. {
  146. if (GetLastError() != ERROR_ALREADY_EXISTS)
  147. {
  148. return FALSE;
  149. }
  150. }
  151. return TRUE;
  152. }
  153. #pragma warning( default : 4706 )
  154. //-----------------------------------------------------------------------------------
  155. // GetIndustryUpdateDirectory
  156. // This function returns the location of the IndustryUpdate directory. All local
  157. // files are stored in this directory. The pszPath parameter needs to be at least
  158. // MAX_PATH.
  159. //-----------------------------------------------------------------------------------
  160. void GetIndustryUpdateDirectory(LPTSTR pszPath)
  161. {
  162. /*
  163. HRESULT hr=S_OK;
  164. LOG_Block("GetIndustryUpdateDirectory");
  165. if (NULL == pszPath)
  166. {
  167. LOG_ErrorMsg(E_INVALIDARG);
  168. return;
  169. }
  170. static TCHAR szCachePath[MAX_PATH] = {'\0'};
  171. if (szCachePath[0] == '\0')
  172. {
  173. HKEY hkey;
  174. pszPath[0] = '\0';
  175. if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_WINCURDIR, &hkey) == ERROR_SUCCESS)
  176. {
  177. DWORD cbPath = MAX_PATH * sizeof(TCHAR);
  178. RegQueryValueEx(hkey, REGKEY_PROGFILESDIR, NULL, NULL, (LPBYTE)pszPath, &cbPath);
  179. RegCloseKey(hkey);
  180. }
  181. if (pszPath[0] == '\0')
  182. {
  183. TCHAR szWinDir[MAX_PATH];
  184. if (! GetWindowsDirectory(szWinDir, ARRAYSIZE(szWinDir)))
  185. {
  186. //if GetWinDir fails, assume C:
  187. CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szWinDir,ARRAYSIZE(szWinDir),_T("C"),NULL,NULL,MISTSAFE_STRING_FLAGS));
  188. }
  189. pszPath[0] = szWinDir[0];
  190. pszPath[1] = '\0';
  191. //It is assumed that the pszPath will be of the size MAX_PATH
  192. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_PROGFILES,NULL,NULL,MISTSAFE_STRING_FLAGS));
  193. }
  194. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_INDUSTRYUPDATE,NULL,NULL,MISTSAFE_STRING_FLAGS));
  195. CreateNestedDirectory(pszPath);
  196. //
  197. // save it in the cache (lstrcpy -> lstrcpyn to shut Prefix up, although this
  198. // would always be safe given the constants used).
  199. //
  200. lstrcpyn(szCachePath, pszPath, MAX_PATH);
  201. }
  202. else
  203. {
  204. //It is assumed that the pszPath will be of the size MAX_PATH
  205. CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(pszPath,MAX_PATH,szCachePath,NULL,NULL,MISTSAFE_STRING_FLAGS));
  206. }
  207. CleanUp:
  208. return;
  209. */
  210. (void) GetWUDirectory(pszPath, MAX_PATH, TRUE);
  211. }
  212. //-----------------------------------------------------------------------------------
  213. // GetWindowsUpdateV3Directory - used for V3 history migration
  214. // This function returns the location of the WindowsUpdate(V3) directory. All V3
  215. // local files are stored in this directory. The pszPath parameter needs to be
  216. // at least MAX_PATH. The directory is created if not found
  217. //-----------------------------------------------------------------------------------
  218. void GetWindowsUpdateV3Directory(LPTSTR pszPath)
  219. {
  220. LOG_Block("GetWindowsUpdateV3Directory");
  221. HRESULT hr=S_OK;
  222. if (NULL == pszPath)
  223. {
  224. LOG_ErrorMsg(E_INVALIDARG);
  225. return;
  226. }
  227. static TCHAR szWUCachePath[MAX_PATH] = {'\0'};
  228. if (szWUCachePath[0] == '\0')
  229. {
  230. HKEY hkey;
  231. pszPath[0] = '\0';
  232. if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_WINCURDIR, &hkey) == ERROR_SUCCESS)
  233. {
  234. DWORD cbPath = MAX_PATH * sizeof(TCHAR);
  235. RegQueryValueEx(hkey, REGKEY_PROGFILESDIR, NULL, NULL, (LPBYTE)pszPath, &cbPath);
  236. RegCloseKey(hkey);
  237. }
  238. if (pszPath[0] == '\0')
  239. {
  240. TCHAR szWinDir[MAX_PATH];
  241. if (! GetWindowsDirectory(szWinDir, ARRAYSIZE(szWinDir)))
  242. {
  243. //if GetWinDir fails, assume C:
  244. CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szWinDir,ARRAYSIZE(szWinDir),_T("C"),NULL,NULL,MISTSAFE_STRING_FLAGS));
  245. }
  246. pszPath[0] = szWinDir[0];
  247. pszPath[1] = '\0';
  248. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_PROGFILES,NULL,NULL,MISTSAFE_STRING_FLAGS));
  249. }
  250. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_WINDOWSUPDATE,NULL,NULL,MISTSAFE_STRING_FLAGS));
  251. CreateNestedDirectory(pszPath);
  252. //
  253. // save it in the cache (lstrcpy -> lstrcpyn to shut Prefix up, although this
  254. // would always be safe given the constants used).
  255. //
  256. lstrcpyn(szWUCachePath, pszPath, MAX_PATH);
  257. }
  258. else
  259. {
  260. CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(pszPath,MAX_PATH,szWUCachePath,NULL,NULL,MISTSAFE_STRING_FLAGS));
  261. }
  262. CleanUp:
  263. return;
  264. }
  265. // ----------------------------------------------------------------------
  266. //
  267. // Public function MySplitPath() - same as CRT _tsplitpath()
  268. // to break a path into pieces
  269. //
  270. // Input:
  271. // see below
  272. //
  273. // Return:
  274. // Returns the address of the last occurrence of the character in
  275. // the string if successful, or NULL otherwise.
  276. //
  277. // Algorithm:
  278. // C:\mydir\...\mysubdir\myfile.ext
  279. // _________| _________| |____
  280. // | | |
  281. // start of dir start of filename start of extension
  282. //
  283. // ----------------------------------------------------------------------
  284. void MySplitPath(
  285. LPCTSTR lpcszPath, // original path
  286. LPTSTR lpszDrive, // point to buffer to receive drive letter
  287. LPTSTR lpszDir, // point to buffer to receive directory
  288. LPTSTR lpszFName, // point to buffer to receive file name
  289. LPTSTR lpszExt // point to buffer to receive extension
  290. )
  291. {
  292. LPCTSTR lpFirstSlash, lpLastSlash, lpPeriod;
  293. LPCTSTR lpStart = lpcszPath;
  294. int nPathLen = lstrlen(lpcszPath);
  295. int nExtLen;
  296. //
  297. // initialize pass in vars
  298. //
  299. InitString(lpszDrive);
  300. InitString(lpszDir);
  301. InitString(lpszFName);
  302. InitString(lpszExt);
  303. if (0 == nPathLen || TCHAR_DOT == lpcszPath[0])
  304. {
  305. //
  306. // not a valid path
  307. //
  308. return;
  309. }
  310. lpFirstSlash = MyStrChr(lpcszPath, TCHAR_BACKSLASH);
  311. lpLastSlash = MyStrRChr(lpcszPath, NULL, TCHAR_BACKSLASH);
  312. lpPeriod = MyStrRChr(lpcszPath, NULL, TCHAR_DOT);
  313. nExtLen = lstrlen(lpPeriod);
  314. if (NULL != lpPeriod && NULL != lpszExt)
  315. {
  316. //
  317. // found a period from right, and
  318. // we have buffer to output extension
  319. //
  320. if(FAILED(StringCchCopyEx(lpszExt,nExtLen+1,lpPeriod,NULL,NULL,MISTSAFE_STRING_FLAGS)))
  321. return;
  322. }
  323. //
  324. // process drive
  325. //
  326. if (nPathLen > 2 && TCHAR_COLON == lpcszPath[1])
  327. {
  328. lpStart = lpcszPath + 2;
  329. if (NULL != lpszDir)
  330. {
  331. lstrcpyn(lpszDrive, lpcszPath, 3);
  332. }
  333. }
  334. if (NULL == lpFirstSlash)
  335. {
  336. //
  337. // no backslash, assume this is file name only
  338. //
  339. if (NULL != lpszFName)
  340. {
  341. lstrcpyn(lpszFName, lpStart, lstrlen(lpStart) - nExtLen + 1);
  342. }
  343. }
  344. else
  345. {
  346. //
  347. // find directory if not empty
  348. //
  349. //if (lpLastSlash != lpFirstSlash && NULL != lpszDir)
  350. if (NULL != lpszDir)
  351. {
  352. lstrcpyn(lpszDir, lpFirstSlash, (int)(lpLastSlash - lpFirstSlash + 2));
  353. }
  354. //
  355. // find file name
  356. //
  357. if (NULL != lpszFName)
  358. {
  359. lstrcpyn(lpszFName, lpLastSlash + 1, lstrlen(lpLastSlash) - nExtLen );
  360. }
  361. }
  362. }
  363. // **********************************************************************************
  364. //
  365. // File version related declarations
  366. //
  367. // **********************************************************************************
  368. // ----------------------------------------------------------------------------------
  369. //
  370. // public function to retrieve file version
  371. //
  372. // ----------------------------------------------------------------------------------
  373. BOOL GetFileVersion(LPCTSTR lpsFile, LPFILE_VERSION lpstVersion)
  374. {
  375. LOG_Block("GetFileVersion()");
  376. DWORD dwVerInfoSize;
  377. DWORD dwHandle;
  378. DWORD dwVerNumber;
  379. LPVOID lpBuffer = NULL;
  380. UINT uiSize = 0;
  381. VS_FIXEDFILEINFO* lpVSFixedFileInfo;
  382. USES_MY_MEMORY;
  383. if (NULL != lpstVersion)
  384. {
  385. //
  386. // if this pointer not null, we always try to initialize
  387. // this structure to 0, in order to reduce the change of
  388. // programming error, no matter the file exists or not.
  389. //
  390. ZeroMemory(lpstVersion, sizeof(FILE_VERSION));
  391. }
  392. if (NULL == lpsFile || NULL == lpstVersion)
  393. {
  394. LOG_ErrorMsg(E_INVALIDARG);
  395. return FALSE;
  396. }
  397. //
  398. // 506212 IU - FRE log reports incorrect version data for iuengine.dll
  399. //
  400. if (FALSE == FileExists(lpsFile))
  401. {
  402. //
  403. // GetFileVersionInfoSize() returns 0 but sets last error to 0 (or
  404. // doesn't set) if file doesn't exist on Win2K.
  405. //
  406. LOG_Out(_T("File \"%s\" doesn't exist, returning FALSE"), lpsFile);
  407. return FALSE;
  408. }
  409. dwVerInfoSize = GetFileVersionInfoSize((LPTSTR)lpsFile, &dwHandle);
  410. if (0 == dwVerInfoSize)
  411. {
  412. DWORD dwErr = GetLastError();
  413. if (0 == dwErr)
  414. {
  415. LOG_Error(_T("File %s does not have version data. Use 0.0.0.0"), lpsFile);
  416. lpstVersion->Major = 0x0;
  417. lpstVersion->Minor = 0x0;
  418. lpstVersion->Build = 0x0;
  419. lpstVersion->Ext = 0x0;
  420. return TRUE;
  421. }
  422. else
  423. {
  424. LOG_ErrorMsg(dwErr);
  425. return FALSE;
  426. }
  427. }
  428. if (NULL == (lpBuffer = (LPVOID) MemAlloc(dwVerInfoSize)))
  429. {
  430. LOG_Error(_T("Failed to allocate memory to get version info"));
  431. return FALSE;
  432. }
  433. if (!GetFileVersionInfo((LPTSTR)lpsFile, dwHandle, dwVerInfoSize, lpBuffer))
  434. {
  435. LOG_ErrorMsg(GetLastError());
  436. return FALSE;
  437. }
  438. //
  439. // Get the value for Translation
  440. //
  441. if (!VerQueryValue(lpBuffer, _T("\\"), (LPVOID*)&lpVSFixedFileInfo, &uiSize) && (uiSize) && NULL != lpVSFixedFileInfo)
  442. {
  443. LOG_ErrorMsg(GetLastError());
  444. return FALSE;
  445. }
  446. dwVerNumber = lpVSFixedFileInfo->dwFileVersionMS;
  447. lpstVersion->Major = HIWORD(dwVerNumber);
  448. lpstVersion->Minor = LOWORD(dwVerNumber);
  449. dwVerNumber = lpVSFixedFileInfo->dwFileVersionLS;
  450. lpstVersion->Build = HIWORD(dwVerNumber);
  451. lpstVersion->Ext = LOWORD(dwVerNumber);
  452. LOG_Out(_T("File %s found version %d.%d.%d.%d"),
  453. lpsFile,
  454. lpstVersion->Major,
  455. lpstVersion->Minor,
  456. lpstVersion->Build,
  457. lpstVersion->Ext);
  458. return TRUE;
  459. }
  460. // ----------------------------------------------------------------------------------
  461. //
  462. // public functions to compare file versions
  463. //
  464. // return:
  465. // -1: if file ver of 1st parameter < file ver of 2nd parameter
  466. // 0: if file ver of 1st parameter = file ver of 2nd parameter
  467. // +1: if file ver of 1st parameter > file ver of 2nd parameter
  468. //
  469. // ----------------------------------------------------------------------------------
  470. int CompareFileVersion(const FILE_VERSION stVersion1, const FILE_VERSION stVersion2)
  471. {
  472. if ((short)stVersion1.Major < 0 || (short)stVersion2.Major < 0)
  473. {
  474. //
  475. // two empty version structure to compare, we call it equal
  476. //
  477. return 0;
  478. }
  479. if (stVersion1.Major != stVersion2.Major)
  480. {
  481. //
  482. // major diff, then we know the answer
  483. //
  484. return (stVersion1.Major < stVersion2.Major) ? -1 : 1;
  485. }
  486. else
  487. {
  488. if ((short)stVersion1.Minor < 0 || (short)stVersion2.Minor < 0)
  489. {
  490. //
  491. // if any minor missing, they equal
  492. //
  493. return 0;
  494. }
  495. if (stVersion1.Minor != stVersion2.Minor)
  496. {
  497. //
  498. // minor diff, then we know the answer
  499. //
  500. return (stVersion1.Minor < stVersion2.Minor) ? -1 : 1;
  501. }
  502. else
  503. {
  504. if ((short)stVersion1.Build < 0 || (short)stVersion2.Build < 0)
  505. {
  506. //
  507. // if any build is missing, they equal
  508. //
  509. return 0;
  510. }
  511. if (stVersion1.Build != stVersion2.Build)
  512. {
  513. //
  514. // if build diff then we are done
  515. //
  516. return (stVersion1.Build < stVersion2.Build) ? -1 : 1;
  517. }
  518. else
  519. {
  520. if ((short)stVersion1.Ext < 0 || (short)stVersion2.Ext < 0 || stVersion1.Ext == stVersion2.Ext)
  521. {
  522. //
  523. // if any ext is missing, or they equal, we are done
  524. //
  525. return 0;
  526. }
  527. else
  528. {
  529. return (stVersion1.Ext < stVersion2.Ext) ? -1 : 1;
  530. }
  531. }
  532. }
  533. }
  534. }
  535. HRESULT CompareFileVersion(LPCTSTR lpsFile1, LPCTSTR lpsFile2, int *pCompareResult)
  536. {
  537. LOG_Block("CompareFileVersion(File, File)");
  538. FILE_VERSION stVer1 = {-1,-1,-1,-1}, stVer2 = {-1,-1,-1,-1};
  539. if (NULL == lpsFile1 || NULL == lpsFile2)
  540. {
  541. LOG_ErrorMsg(E_INVALIDARG);
  542. return E_INVALIDARG;
  543. }
  544. if (!GetFileVersion(lpsFile1, &stVer1))
  545. {
  546. return E_INVALIDARG;
  547. }
  548. if (!GetFileVersion(lpsFile2, &stVer2))
  549. {
  550. return E_INVALIDARG;
  551. }
  552. *pCompareResult = CompareFileVersion(stVer1, stVer2);
  553. return S_OK;
  554. }
  555. HRESULT CompareFileVersion(LPCTSTR lpsFile, FILE_VERSION stVersion, int *pCompareResult)
  556. {
  557. LOG_Block("CompareFileVersion(FILE, VER)");
  558. FILE_VERSION stVer = {0};
  559. if (NULL == lpsFile)
  560. {
  561. LOG_Error(_T("NULL file pointer passed in. Function returns 0"));
  562. return E_INVALIDARG;
  563. }
  564. if (!GetFileVersion(lpsFile, &stVer))
  565. {
  566. return E_INVALIDARG;
  567. }
  568. *pCompareResult = CompareFileVersion(stVer, stVersion);
  569. return S_OK;
  570. }
  571. // ----------------------------------------------------------------------------------
  572. //
  573. // publif function to convert a string type functoin to FILE_VERSION type
  574. //
  575. // ----------------------------------------------------------------------------------
  576. BOOL ConvertStringVerToFileVer(LPCSTR lpsVer, LPFILE_VERSION lpstVer)
  577. {
  578. LOG_Block("ConvertStringVerToFileVer()");
  579. WORD n = -1;
  580. char c;
  581. BOOL fHasNumber = FALSE;
  582. #if defined(DBG) // full logging for checked builds
  583. USES_IU_CONVERSION;
  584. #endif
  585. if (NULL == lpsVer || NULL == lpstVer)
  586. {
  587. LOG_ErrorMsg(E_INVALIDARG);
  588. return FALSE;
  589. }
  590. #if defined(DBG) // full logging for checked builds
  591. LOG_Out(_T("String version = %s"), A2T(const_cast<LPSTR>(lpsVer)));
  592. #endif
  593. lpstVer->Major = lpstVer->Minor = lpstVer->Build = lpstVer->Ext = -1;
  594. c = *lpsVer;
  595. //
  596. // get first number
  597. //
  598. n = 0;
  599. while (c != '\0' && '0' <= c && c <= '9')
  600. {
  601. n = n * 10 + (int)(c - '0');
  602. c = *++lpsVer;
  603. fHasNumber = TRUE;
  604. }
  605. if (fHasNumber)
  606. {
  607. lpstVer->Major = n;
  608. }
  609. else
  610. {
  611. return TRUE;
  612. }
  613. //
  614. // skip delimiter
  615. //
  616. while (c != '\0' && ('0' > c || c > '9'))
  617. {
  618. c = *++lpsVer;
  619. }
  620. //
  621. // get 2nd number
  622. //
  623. n = 0;
  624. fHasNumber = FALSE;
  625. while (c != '\0' && '0' <= c && c <= '9')
  626. {
  627. n = n * 10 + (int)(c - '0');
  628. c = *++lpsVer;
  629. fHasNumber = TRUE;
  630. }
  631. if (fHasNumber)
  632. {
  633. lpstVer->Minor = n;
  634. }
  635. else
  636. {
  637. return TRUE;
  638. }
  639. //
  640. // skip delimiter
  641. //
  642. while (c != '\0' && ('0' > c || c > '9'))
  643. {
  644. c = *++lpsVer;
  645. }
  646. //
  647. // get 3rd number
  648. //
  649. n = 0;
  650. fHasNumber = FALSE;
  651. while (c != '\0' && '0' <= c && c <= '9')
  652. {
  653. n = n * 10 + (int)(c - '0');
  654. c = *++lpsVer;
  655. fHasNumber = TRUE;
  656. }
  657. if (fHasNumber)
  658. {
  659. lpstVer->Build = n;
  660. }
  661. else
  662. {
  663. return TRUE;
  664. }
  665. //
  666. // skip delimiter
  667. //
  668. while (c != '\0' && ('0' > c || c > '9'))
  669. {
  670. c = *++lpsVer;
  671. }
  672. //
  673. // get 4th number
  674. //
  675. n = 0;
  676. fHasNumber = FALSE;
  677. while (c != '\0' && '0' <= c && c <= '9')
  678. {
  679. n = n * 10 + (int)(c - '0');
  680. c = *++lpsVer;
  681. fHasNumber = TRUE;
  682. }
  683. if (fHasNumber)
  684. {
  685. lpstVer->Ext = n;
  686. }
  687. return TRUE;
  688. }
  689. // ----------------------------------------------------------------------------------
  690. //
  691. // publif function to convert a FILE_VERSION to a string
  692. //
  693. // ----------------------------------------------------------------------------------
  694. BOOL ConvertFileVerToStringVer(
  695. FILE_VERSION stVer, // version to convert
  696. char chDel, // delimiter to use
  697. LPSTR lpsBuffer, // buffer of string
  698. int ccBufSize // size of buffer
  699. )
  700. {
  701. //
  702. // declare max buffer that wsprintf can use
  703. //
  704. char szBuf[1024];
  705. HRESULT hr=S_OK;
  706. hr=StringCchPrintfExA( szBuf,ARRAYSIZE(szBuf),
  707. NULL,NULL,MISTSAFE_STRING_FLAGS,
  708. "%d%c%d%c%d%c",
  709. stVer.Major,
  710. chDel,
  711. stVer.Minor,
  712. chDel,
  713. stVer.Build,
  714. chDel,
  715. stVer.Ext,
  716. chDel
  717. );
  718. if(FAILED(hr))
  719. {
  720. goto ErrorExit;
  721. }
  722. hr=StringCchCopyExA(lpsBuffer,ccBufSize,szBuf,NULL,NULL,MISTSAFE_STRING_FLAGS);
  723. if(FAILED(hr))
  724. {
  725. goto ErrorExit;
  726. }
  727. return TRUE;
  728. ErrorExit:
  729. lpsBuffer[0] = '\0';
  730. return FALSE;
  731. }
  732. // ----------------------------------------------------------------------------------
  733. //
  734. // public function to check if a file exists
  735. //
  736. // ----------------------------------------------------------------------------------
  737. BOOL FileExists(
  738. LPCTSTR lpsFile // file with path to check
  739. )
  740. {
  741. LOG_Block("FileExists");
  742. DWORD dwAttr;
  743. BOOL rc;
  744. if (NULL == lpsFile || _T('\0') == *lpsFile)
  745. {
  746. LOG_ErrorMsg(E_INVALIDARG);
  747. return FALSE;
  748. }
  749. dwAttr = GetFileAttributes(lpsFile);
  750. if (-1 == dwAttr)
  751. {
  752. LOG_InfoMsg(GetLastError());
  753. rc = FALSE;
  754. }
  755. else
  756. {
  757. rc = (0x0 == (FILE_ATTRIBUTE_DIRECTORY & dwAttr));
  758. }
  759. return rc;
  760. }
  761. // ----------------------------------------------------------------------------------
  762. //
  763. // publif function to retrieve the creation time of a file in ISO 8601 format
  764. // without zone info
  765. //
  766. // if buffer too small, call GetLastError();
  767. //
  768. // ----------------------------------------------------------------------------------
  769. BOOL GetFileTimeStamp(LPCTSTR lpsFile, LPTSTR lpsTimeStamp, int iBufSize)
  770. {
  771. BOOL fRet = FALSE;
  772. HANDLE hFile;
  773. SYSTEMTIME tm;
  774. WIN32_FILE_ATTRIBUTE_DATA fileData;
  775. HRESULT hr=S_OK;
  776. if (0 != GetFileAttributesEx(lpsFile, GetFileExInfoStandard, &fileData) &&
  777. 0 != FileTimeToSystemTime((const FILETIME*)&(fileData.ftCreationTime), &tm))
  778. {
  779. //
  780. // the output of this systemtime, according to ISA 8601 format, will be
  781. // like yyyy-mm-ddThh:mm:ss format, so it is 20 chars incl terminator
  782. //
  783. if (iBufSize < 20)
  784. {
  785. SetLastError(ERROR_BUFFER_OVERFLOW);
  786. return fRet;
  787. }
  788. hr=StringCchPrintfEx(lpsTimeStamp,iBufSize,NULL,NULL,MISTSAFE_STRING_FLAGS,
  789. _T("%4d-%02d-%02dT%02d:%02d:%02d"),
  790. tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond);
  791. if(FAILED(hr))
  792. {
  793. fRet=FALSE;
  794. SetLastError(HRESULT_CODE(hr));
  795. }
  796. else
  797. fRet = TRUE;
  798. }
  799. return fRet;
  800. }
  801. // ----------------------------------------------------------------------------------
  802. //
  803. // publif function to find the free disk space in KB
  804. //
  805. //
  806. // ----------------------------------------------------------------------------------
  807. HRESULT GetFreeDiskSpace(TCHAR tcDriveLetter, int *piKBytes)
  808. {
  809. HRESULT hr = E_INVALIDARG;
  810. BOOL fResult;
  811. TCHAR szDrive[4];
  812. if (!(_T('A') <= tcDriveLetter && tcDriveLetter <= _T('Z') ||
  813. _T('a') <= tcDriveLetter && tcDriveLetter <= _T('z')))
  814. {
  815. return hr;
  816. }
  817. hr=StringCchPrintfEx(szDrive,ARRAYSIZE(szDrive),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("%c:\\"), tcDriveLetter);
  818. if(FAILED(hr))
  819. return hr;
  820. PFN_GetDiskFreeSpaceEx pGetDiskFreeSpaceEx =
  821. (PFN_GetDiskFreeSpaceEx)
  822. GetProcAddress( GetModuleHandle(_T("kernel32.dll")),
  823. #ifdef UNICODE
  824. "GetDiskFreeSpaceExW");
  825. #else
  826. "GetDiskFreeSpaceExA");
  827. #endif
  828. if (pGetDiskFreeSpaceEx)
  829. {
  830. LARGE_INTEGER i64FreeBytesToCaller, i64TotalBytes;
  831. fResult = pGetDiskFreeSpaceEx (szDrive,
  832. (PULARGE_INTEGER)&i64FreeBytesToCaller,
  833. (PULARGE_INTEGER)&i64TotalBytes,
  834. (PULARGE_INTEGER)NULL);
  835. *piKBytes = (int) (i64FreeBytesToCaller.QuadPart / 1024);
  836. }
  837. else
  838. {
  839. DWORD dwSectPerClust = 0x0,
  840. dwBytesPerSect = 0x0,
  841. dwFreeClusters = 0x0,
  842. dwTotalClusters = 0x0;
  843. fResult = GetDiskFreeSpace (szDrive,
  844. &dwSectPerClust,
  845. &dwBytesPerSect,
  846. &dwFreeClusters,
  847. &dwTotalClusters);
  848. *piKBytes = (int) ((float)(((int)dwFreeClusters) * ((int)dwSectPerClust)) / 1024.0 * (int)dwBytesPerSect);
  849. }
  850. return (fResult) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
  851. }
  852. HRESULT GetFreeDiskSpace(LPCTSTR pszUNC, int *piKBytes)
  853. {
  854. HRESULT hr = E_INVALIDARG;
  855. BOOL fResult;
  856. PFN_GetDiskFreeSpaceEx pGetDiskFreeSpaceEx =
  857. (PFN_GetDiskFreeSpaceEx)
  858. GetProcAddress( GetModuleHandle(_T("kernel32.dll")),
  859. #ifdef UNICODE
  860. "GetDiskFreeSpaceExW");
  861. #else
  862. "GetDiskFreeSpaceExA");
  863. #endif
  864. if (pGetDiskFreeSpaceEx)
  865. {
  866. LARGE_INTEGER i64FreeBytesToCaller, i64TotalBytes;
  867. fResult = pGetDiskFreeSpaceEx (pszUNC,
  868. (PULARGE_INTEGER)&i64FreeBytesToCaller,
  869. (PULARGE_INTEGER)&i64TotalBytes,
  870. (PULARGE_INTEGER)NULL);
  871. *piKBytes = (int) (i64FreeBytesToCaller.QuadPart / 1024);
  872. }
  873. else
  874. {
  875. DWORD dwSectPerClust = 0x0,
  876. dwBytesPerSect = 0x0,
  877. dwFreeClusters = 0x0,
  878. dwTotalClusters = 0x0;
  879. fResult = GetDiskFreeSpace (pszUNC,
  880. &dwSectPerClust,
  881. &dwBytesPerSect,
  882. &dwFreeClusters,
  883. &dwTotalClusters);
  884. *piKBytes = (int) ((float)(((int)dwFreeClusters) * ((int)dwSectPerClust)) / 1024.0 * (int)dwBytesPerSect);
  885. }
  886. return (fResult) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
  887. }
  888. // ----------------------------------------------------------------------------------
  889. //
  890. // publif function to expand the file path
  891. //
  892. // Assumption: lpszFilePath points to allocated buffer of MAX_PATH.
  893. // if the expanded path is longer than MAX_PATH, error returned.
  894. //
  895. // ----------------------------------------------------------------------------------
  896. HRESULT ExpandFilePath(LPCTSTR lpszFilePath, LPTSTR lpszDestination, UINT cChars)
  897. {
  898. HRESULT hr = S_OK;
  899. LPTSTR lpEnvExpanded;
  900. LPTSTR lp2ndPercentChar = NULL;
  901. LPTSTR lpSearchStart;
  902. USES_MY_MEMORY;
  903. if (NULL == (lpEnvExpanded = (LPTSTR) MemAlloc((cChars + 1) * sizeof(TCHAR))))
  904. {
  905. return E_OUTOFMEMORY;
  906. }
  907. //
  908. // first, let's substitute the system defined variables
  909. //
  910. if (0 == ExpandEnvironmentStrings(lpszFilePath, lpEnvExpanded, cChars))
  911. {
  912. hr = HRESULT_FROM_WIN32(GetLastError());
  913. }
  914. //
  915. // then handle pre-defined variables that we need to recognize
  916. // these include all CSIDL definitions inside shlobj.h for SHGetFolderPath() API
  917. //
  918. const int C_NAME_LEN = 32;
  919. struct _CSIDL_NAME {
  920. long CSIDL_Id;
  921. TCHAR CSIDL_Str[C_NAME_LEN];
  922. };
  923. const _CSIDL_NAME C_CSIDL_NAMES[] = {
  924. {CSIDL_ADMINTOOLS , _T("CSIDL_ADMINTOOLS")},
  925. {CSIDL_ALTSTARTUP , _T("CSIDL_ALTSTARTUP")},
  926. {CSIDL_APPDATA , _T("CSIDL_APPDATA")},
  927. {CSIDL_BITBUCKET , _T("CSIDL_BITBUCKET")},
  928. {CSIDL_COMMON_ADMINTOOLS , _T("CSIDL_COMMON_ADMINTOOLS")},
  929. {CSIDL_COMMON_ALTSTARTUP , _T("CSIDL_COMMON_ALTSTARTUP")},
  930. {CSIDL_COMMON_APPDATA , _T("CSIDL_COMMON_APPDATA")},
  931. {CSIDL_COMMON_DESKTOPDIRECTORY , _T("CSIDL_COMMON_DESKTOPDIRECTORY")},
  932. {CSIDL_COMMON_DOCUMENTS , _T("CSIDL_COMMON_DOCUMENTS")},
  933. {CSIDL_COMMON_FAVORITES , _T("CSIDL_COMMON_FAVORITES")},
  934. {CSIDL_COMMON_PROGRAMS , _T("CSIDL_COMMON_PROGRAMS")},
  935. {CSIDL_COMMON_STARTMENU , _T("CSIDL_COMMON_STARTMENU")},
  936. {CSIDL_COMMON_STARTUP , _T("CSIDL_COMMON_STARTUP")},
  937. {CSIDL_COMMON_TEMPLATES , _T("CSIDL_COMMON_TEMPLATES")},
  938. {CSIDL_CONTROLS , _T("CSIDL_CONTROLS")},
  939. {CSIDL_COOKIES , _T("CSIDL_COOKIES")},
  940. {CSIDL_DESKTOP , _T("CSIDL_DESKTOP")},
  941. {CSIDL_DESKTOPDIRECTORY , _T("CSIDL_DESKTOPDIRECTORY")},
  942. {CSIDL_DRIVES , _T("CSIDL_DRIVES")},
  943. {CSIDL_FAVORITES , _T("CSIDL_FAVORITES")},
  944. {CSIDL_FONTS , _T("CSIDL_FONTS")},
  945. {CSIDL_HISTORY , _T("CSIDL_HISTORY")},
  946. {CSIDL_INTERNET , _T("CSIDL_INTERNET")},
  947. {CSIDL_INTERNET_CACHE , _T("CSIDL_INTERNET_CACHE")},
  948. {CSIDL_LOCAL_APPDATA , _T("CSIDL_LOCAL_APPDATA")},
  949. {CSIDL_MYPICTURES , _T("CSIDL_MYPICTURES")},
  950. {CSIDL_NETHOOD , _T("CSIDL_NETHOOD")},
  951. {CSIDL_NETWORK , _T("CSIDL_NETWORK")},
  952. {CSIDL_PERSONAL , _T("CSIDL_PERSONAL")},
  953. {CSIDL_PRINTERS , _T("CSIDL_PRINTERS")},
  954. {CSIDL_PRINTHOOD , _T("CSIDL_PRINTHOOD")},
  955. {CSIDL_PROFILE , _T("CSIDL_PROFILE")},
  956. {CSIDL_PROGRAM_FILES , _T("CSIDL_PROGRAM_FILES")},
  957. {CSIDL_PROGRAM_FILES_COMMON , _T("CSIDL_PROGRAM_FILES_COMMON")},
  958. {CSIDL_PROGRAMS , _T("CSIDL_PROGRAMS")},
  959. {CSIDL_RECENT , _T("CSIDL_RECENT")},
  960. {CSIDL_SENDTO , _T("CSIDL_SENDTO")},
  961. {CSIDL_STARTMENU , _T("CSIDL_STARTMENU")},
  962. {CSIDL_STARTUP , _T("CSIDL_STARTUP")},
  963. {CSIDL_SYSTEM , _T("CSIDL_SYSTEM")},
  964. {CSIDL_TEMPLATES , _T("CSIDL_TEMPLATES")},
  965. {CSIDL_WINDOWS , _T("CSIDL_WINDOWS")}
  966. };
  967. //
  968. // see if this path has any of these variables
  969. //
  970. lpSearchStart = lpEnvExpanded + 1;
  971. if (SUCCEEDED(hr) && _T('%') == *lpEnvExpanded &&
  972. NULL != (lp2ndPercentChar = StrChr(lpSearchStart, _T('%'))))
  973. {
  974. //
  975. // copy the variable name to passed in buffer
  976. //
  977. lstrcpyn(lpszDestination, lpSearchStart, (int)(lp2ndPercentChar - lpSearchStart + 1)); // skip the 1st % char
  978. lp2ndPercentChar++; // move to begining of rest of path
  979. //
  980. // find out what this variable is
  981. //
  982. for (int i = 0; i < sizeof(C_CSIDL_NAMES)/sizeof(C_CSIDL_NAMES[0]); i++)
  983. {
  984. if (lstrcmpi(lpszDestination, C_CSIDL_NAMES[i].CSIDL_Str) == 0)
  985. {
  986. //
  987. // found the matching variable!
  988. //
  989. if (S_OK == (hr = SHGetFolderPath(NULL, C_CSIDL_NAMES[i].CSIDL_Id, NULL, SHGFP_TYPE_CURRENT, lpszDestination)))
  990. {
  991. //
  992. // ensure buffer big enough
  993. //
  994. if (lstrlen(lp2ndPercentChar) + lstrlen(lpszDestination) + sizeof(TCHAR) >= cChars)
  995. {
  996. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  997. }
  998. //
  999. // append the rest of them - shouldn't be any of
  1000. // these variables in the rest of string, since this
  1001. // kind variable alaways starts at the beginning of
  1002. // a path
  1003. //
  1004. if(SUCCEEDED(hr))
  1005. hr=PathCchAppend(lpszDestination,MAX_PATH,lp2ndPercentChar);
  1006. if (SUCCEEDED(hr))
  1007. {
  1008. return hr;
  1009. }
  1010. }
  1011. //
  1012. // we found the matching variable, but couldn't get the
  1013. // string replaced.
  1014. //
  1015. break;
  1016. }
  1017. }
  1018. //
  1019. // didn't find it.
  1020. //
  1021. }
  1022. //
  1023. // didn't find it, or failed.
  1024. //
  1025. if (FAILED(hr))
  1026. {
  1027. *lpszDestination = _T('\0');
  1028. }
  1029. else
  1030. {
  1031. lstrcpyn(lpszDestination, lpEnvExpanded, cChars);
  1032. }
  1033. return hr;
  1034. }
  1035. //----------------------------------------------------------------------
  1036. //
  1037. // function to validate the folder to make sure
  1038. // user has required priviledge
  1039. //
  1040. // folder will be verified exist. then required priviledge will be checked.
  1041. //
  1042. // ASSUMPTION: lpszFolder not exceeding MAX_PATH long!!!
  1043. //
  1044. //----------------------------------------------------------------------
  1045. DWORD ValidateFolder(LPTSTR lpszFolder, BOOL fCheckForWrite)
  1046. {
  1047. LOG_Block("ValidateFolder");
  1048. DWORD dwErr = ERROR_SUCCESS;
  1049. HRESULT hr=S_OK;
  1050. //
  1051. // first, check if the folder exist
  1052. //
  1053. dwErr = GetFileAttributes(lpszFolder);
  1054. if (-1 == dwErr)
  1055. {
  1056. dwErr = GetLastError();
  1057. LOG_ErrorMsg(dwErr);
  1058. return dwErr;
  1059. }
  1060. //
  1061. // make sure it's a directory
  1062. //
  1063. if ((FILE_ATTRIBUTE_DIRECTORY & dwErr) == 0)
  1064. {
  1065. dwErr = ERROR_PATH_NOT_FOUND;
  1066. LOG_ErrorMsg(dwErr);
  1067. return dwErr;
  1068. }
  1069. if (fCheckForWrite)
  1070. {
  1071. TCHAR szFile[MAX_PATH], szFileName[40];
  1072. SYSTEMTIME tm;
  1073. HANDLE hFile;
  1074. //
  1075. // create a random file name
  1076. //
  1077. hr=StringCchCopyEx(szFile,ARRAYSIZE(szFile),lpszFolder,NULL,NULL,MISTSAFE_STRING_FLAGS);
  1078. if(FAILED(hr))
  1079. {
  1080. dwErr = HRESULT_CODE(hr);;
  1081. LOG_ErrorMsg(dwErr);
  1082. return dwErr;
  1083. }
  1084. GetLocalTime(&tm);
  1085. hr=StringCchPrintfEx( szFileName,
  1086. ARRAYSIZE(szFileName),
  1087. NULL,NULL,MISTSAFE_STRING_FLAGS,
  1088. _T("%08x%08x%02hd%02hd%02hd%02hd%02hd%03hd%08x"),
  1089. GetCurrentProcessId(),
  1090. GetCurrentThreadId(),
  1091. tm.wMonth,
  1092. tm.wDay,
  1093. tm.wHour,
  1094. tm.wMinute,
  1095. tm.wSecond,
  1096. tm.wMilliseconds,
  1097. GetTickCount());
  1098. if(FAILED(hr))
  1099. {
  1100. dwErr = HRESULT_CODE(hr);;
  1101. LOG_ErrorMsg(dwErr);
  1102. return dwErr;
  1103. }
  1104. hr=PathCchAppend(szFile,ARRAYSIZE(szFile),szFileName);
  1105. if(FAILED(hr))
  1106. {
  1107. dwErr = HRESULT_CODE(hr);;
  1108. LOG_ErrorMsg(dwErr);
  1109. return dwErr;
  1110. }
  1111. //
  1112. // try to write file
  1113. //
  1114. hFile = CreateFile(szFile, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
  1115. if (INVALID_HANDLE_VALUE == hFile)
  1116. {
  1117. dwErr = GetLastError();
  1118. LOG_ErrorMsg(dwErr);
  1119. return dwErr;
  1120. }
  1121. CloseHandle(hFile);
  1122. }
  1123. return ERROR_SUCCESS;
  1124. }
  1125. //----------------------------------------------------------------------
  1126. //
  1127. // function to get a QueryServer from the Ident File for a Given ClientName
  1128. // This also looks in the registry for the IsBeta regkey indicating Beta
  1129. // functionlality
  1130. //
  1131. // Returns:
  1132. // S_OK : we successfully got QueryServer for this Client
  1133. // S_FALSE : we did NOT find a QueryServer for this Client (pszQueryServer will be a null string)
  1134. // E_INVALIDARG : parameters were incorrect
  1135. //----------------------------------------------------------------------
  1136. HRESULT GetClientQueryServer(LPCTSTR pszClientName, LPTSTR pszQueryServer, UINT cChars)
  1137. {
  1138. HKEY hkey;
  1139. BOOL fBeta = FALSE;
  1140. int iIndex;
  1141. TCHAR szQueryServerKeyName[128];
  1142. TCHAR szIUDir[MAX_PATH];
  1143. TCHAR szIdentFile[MAX_PATH];
  1144. DWORD dwValue = 0;
  1145. DWORD dwLength = sizeof(dwValue);
  1146. HRESULT hr=S_OK;
  1147. LOG_Block("GetClientQueryServer");
  1148. if ((NULL == pszClientName) || (NULL == pszQueryServer) || (0 == cChars))
  1149. {
  1150. LOG_ErrorMsg(E_INVALIDARG);
  1151. return E_INVALIDARG;
  1152. }
  1153. // Check IUControl Reg Key for Beta Mode
  1154. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, &hkey))
  1155. {
  1156. if (ERROR_SUCCESS == RegQueryValueEx(hkey, REGVAL_ISBETA, NULL, NULL, (LPBYTE)&dwValue, &dwLength))
  1157. {
  1158. if (1 == dwValue)
  1159. {
  1160. fBeta = TRUE;
  1161. }
  1162. }
  1163. RegCloseKey(hkey);
  1164. }
  1165. GetIndustryUpdateDirectory(szIUDir);
  1166. hr=PathCchCombine (szIdentFile,ARRAYSIZE(szIdentFile),szIUDir,IDENTTXT);
  1167. if(FAILED(hr))
  1168. {
  1169. LOG_ErrorMsg(hr);
  1170. return hr;
  1171. }
  1172. // Form the KeyName for the QueryServer Index
  1173. hr=StringCchPrintfEx(szQueryServerKeyName,ARRAYSIZE(szQueryServerKeyName),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("%s%s"), pszClientName, fBeta ? IDENT_BETAQUERYSERVERINDEX : IDENT_QUERYSERVERINDEX);
  1174. if(FAILED(hr))
  1175. {
  1176. LOG_ErrorMsg(hr);
  1177. return hr;
  1178. }
  1179. iIndex = GetPrivateProfileInt(IDENT_IUSERVERCACHE, szQueryServerKeyName, 0, szIdentFile);
  1180. if (0 == iIndex)
  1181. {
  1182. iIndex = GetPrivateProfileInt(IDENT_IUSERVERCACHE, IDENT_DEFAULTQUERYSERVERINDEX, 0, szIdentFile);
  1183. if (0 == iIndex)
  1184. {
  1185. return S_FALSE;
  1186. }
  1187. }
  1188. // Form the KeyName for the Specified QueryServer based on the Index
  1189. hr=StringCchPrintfEx(szQueryServerKeyName,ARRAYSIZE(szQueryServerKeyName),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("Server%d"), iIndex);
  1190. if(FAILED(hr))
  1191. {
  1192. LOG_ErrorMsg(hr);
  1193. return hr;
  1194. }
  1195. GetPrivateProfileString(IDENT_IUSERVERCACHE, szQueryServerKeyName, _T(""), pszQueryServer, cChars, szIdentFile);
  1196. if ('\0' == *pszQueryServer)
  1197. {
  1198. return S_FALSE;
  1199. }
  1200. else
  1201. {
  1202. return S_OK;
  1203. }
  1204. }
  1205. HRESULT DecompressFolderCabs(LPCTSTR pszDecompressPath)
  1206. {
  1207. HRESULT hr = S_FALSE; // default is not an Error, but if there are no cabs we return S_FALSE
  1208. TCHAR szSearchInfo[MAX_PATH];
  1209. TCHAR szCabPath[MAX_PATH];
  1210. LPTSTR pszCabList = NULL;
  1211. LPTSTR pszWritePosition = NULL;
  1212. LONG lCabCount = 0;
  1213. WIN32_FIND_DATA fd;
  1214. HANDLE hFind;
  1215. BOOL fMore = TRUE;
  1216. BOOL fRet = TRUE;
  1217. USES_IU_CONVERSION;
  1218. hr=PathCchCombine (szSearchInfo,ARRAYSIZE(szSearchInfo),pszDecompressPath, _T("*.cab"));
  1219. if(FAILED(hr))
  1220. {
  1221. return hr;
  1222. }
  1223. hFind = FindFirstFile(szSearchInfo, &fd);
  1224. if (hFind != INVALID_HANDLE_VALUE)
  1225. {
  1226. while (fMore)
  1227. {
  1228. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  1229. {
  1230. lCabCount++;
  1231. }
  1232. fMore = FindNextFile(hFind, &fd);
  1233. }
  1234. FindClose(hFind);
  1235. pszCabList = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PATH * sizeof(TCHAR) * lCabCount));
  1236. if (NULL == pszCabList)
  1237. {
  1238. hr = E_OUTOFMEMORY;
  1239. return hr;
  1240. }
  1241. pszWritePosition = pszCabList;
  1242. hFind = FindFirstFile(szSearchInfo, &fd);
  1243. fMore = (INVALID_HANDLE_VALUE != hFind);
  1244. DWORD dwRemLength=lCabCount*MAX_PATH;
  1245. while (fMore)
  1246. {
  1247. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  1248. {
  1249. hr=PathCchCombine(szCabPath,ARRAYSIZE(szCabPath),pszDecompressPath, fd.cFileName);
  1250. if(FAILED(hr))
  1251. {
  1252. SafeHeapFree(pszCabList);
  1253. return hr;
  1254. }
  1255. hr=StringCchCatEx(pszWritePosition,dwRemLength,szCabPath,NULL,NULL,MISTSAFE_STRING_FLAGS);
  1256. if(FAILED(hr))
  1257. {
  1258. SafeHeapFree(pszCabList);
  1259. return hr;
  1260. }
  1261. dwRemLength=dwRemLength- ( lstrlen(pszWritePosition)+ 2 * (sizeof(TCHAR)) );
  1262. pszWritePosition += lstrlen(pszWritePosition) + 2 * (sizeof(TCHAR));
  1263. }
  1264. fMore = FindNextFile(hFind, &fd);
  1265. }
  1266. FindClose(hFind);
  1267. pszWritePosition = pszCabList;
  1268. for (LONG lCnt = 0; lCnt < lCabCount; lCnt++)
  1269. {
  1270. fRet = IUExtractFiles(pszWritePosition, pszDecompressPath);
  1271. if (!fRet)
  1272. {
  1273. break;
  1274. }
  1275. pszWritePosition += lstrlen(pszWritePosition) + 2 * (sizeof(TCHAR));
  1276. }
  1277. SafeHeapFree(pszCabList);
  1278. if (!fRet)
  1279. {
  1280. hr = E_FAIL; // one of the cabs had an error decompressing
  1281. }
  1282. else
  1283. {
  1284. hr = S_OK;
  1285. }
  1286. }
  1287. return hr;
  1288. }
  1289. //Extracts a cab file to the specified destination. Optionally we can pass in a colon seperated list of files to extract
  1290. BOOL IUExtractFiles(LPCTSTR pszCabFile, LPCTSTR pszDecompressFolder, LPCTSTR pszFileNames)
  1291. {
  1292. HRESULT hr = S_OK;
  1293. #ifdef UNICODE
  1294. char szCabFile[MAX_PATH];
  1295. char szDecompressFolder[MAX_PATH];
  1296. WideCharToMultiByte(CP_ACP, 0, pszCabFile, -1, szCabFile, sizeof(szCabFile), NULL, NULL);
  1297. WideCharToMultiByte(CP_ACP, 0, pszDecompressFolder, -1, szDecompressFolder, sizeof(szDecompressFolder), NULL, NULL);
  1298. char *pszFiles = NULL;
  1299. if(pszFileNames != NULL)
  1300. {
  1301. pszFiles = (char*)malloc(lstrlen(pszFileNames)+1);
  1302. if (pszFiles == NULL)
  1303. {
  1304. return FALSE;
  1305. }
  1306. WideCharToMultiByte(CP_ACP, 0, pszFileNames, -1, pszFiles, lstrlen(pszFileNames)+1, NULL, NULL);
  1307. }
  1308. hr = ExtractFiles(szCabFile, szDecompressFolder, 0, pszFiles, 0, 0);
  1309. free(pszFiles);
  1310. #else
  1311. hr = ExtractFiles(pszCabFile, pszDecompressFolder, 0, pszFileNames, 0, 0);
  1312. #endif
  1313. return SUCCEEDED(hr);
  1314. }
  1315. /////////////////////////////////////////////////////////////////////////////
  1316. //
  1317. // ReplaceFileExtension
  1318. //
  1319. /////////////////////////////////////////////////////////////////////////////
  1320. BOOL ReplaceFileExtension( LPCTSTR pszPath,
  1321. LPCTSTR pszNewExt,
  1322. LPTSTR pszNewPathBuf,
  1323. DWORD cchNewPathBuf)
  1324. {
  1325. LPCTSTR psz;
  1326. HRESULT hr;
  1327. DWORD cchPath, cchExt, cch;
  1328. if (pszPath == NULL || *pszPath == _T('\0'))
  1329. return FALSE;
  1330. cchPath = lstrlen(pszPath);
  1331. // note that only a '>' comparison is needed since the file extension
  1332. // should never start at the 1st char in the path.
  1333. for (psz = pszPath + cchPath;
  1334. psz > pszPath && *psz != _T('\\') && *psz != _T('.');
  1335. psz--);
  1336. if (*psz == _T('\\'))
  1337. psz = pszPath + cchPath;
  1338. else if (psz == pszPath)
  1339. return FALSE;
  1340. // ok, so now psz points to the place where the new extension is going to
  1341. // go. Make sure our buffer is big enough.
  1342. cchPath = (DWORD)(psz - pszPath);
  1343. cchExt = lstrlen(pszNewExt);
  1344. if (cchPath + cchExt >= cchNewPathBuf)
  1345. return FALSE;
  1346. // yay. we got a big enuf buffer.
  1347. hr = StringCchCopyEx(pszNewPathBuf, cchNewPathBuf, pszPath,
  1348. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1349. if (FAILED(hr))
  1350. return FALSE;
  1351. hr = StringCchCopyEx(pszNewPathBuf + cchPath, cchNewPathBuf - cchPath, pszNewExt,
  1352. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1353. if (FAILED(hr))
  1354. return FALSE;
  1355. return TRUE;
  1356. }
  1357. /////////////////////////////////////////////////////////////////////////////
  1358. //
  1359. // ReplaceFileInPath
  1360. //
  1361. /////////////////////////////////////////////////////////////////////////////
  1362. BOOL ReplaceFileInPath(LPCTSTR pszPath,
  1363. LPCTSTR pszNewFile,
  1364. LPTSTR pszNewPathBuf,
  1365. DWORD cchNewPathBuf)
  1366. {
  1367. LPCTSTR psz;
  1368. HRESULT hr;
  1369. DWORD cchPath, cchFile, cch;
  1370. if (pszPath == NULL || *pszPath == _T('\0'))
  1371. return FALSE;
  1372. cchPath = lstrlen(pszPath);
  1373. // note that only the '>=' comparison is safe cuz we check if pszPath is
  1374. // NULL above, so there should always be at least one value < pszPath
  1375. for (psz = pszPath + cchPath;
  1376. psz >= pszPath && *psz != _T('\\');
  1377. psz--);
  1378. // either way we break out of the loop, gotta increment the pointer to
  1379. // be either the first char in the string or the first char after the
  1380. // last backslash
  1381. psz++;
  1382. // ok, so now psz points to the place where the new filename is going to
  1383. // go. Make sure our buffer is big enough.
  1384. cchPath = (DWORD)(psz - pszPath);
  1385. cchFile = lstrlen(pszNewFile);
  1386. if (cchPath + cchFile >= cchNewPathBuf)
  1387. return FALSE;
  1388. // yay. we got a big enuf buffer.
  1389. if (cchPath > 0)
  1390. {
  1391. hr = StringCchCopyEx(pszNewPathBuf, cchNewPathBuf, pszPath,
  1392. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1393. if (FAILED(hr))
  1394. return FALSE;
  1395. }
  1396. hr = StringCchCopyEx(pszNewPathBuf + cchPath, cchNewPathBuf - cchPath, pszNewFile,
  1397. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1398. if (FAILED(hr))
  1399. return FALSE;
  1400. return TRUE;
  1401. }
  1402. // ----------------------------------------------------------------------------------
  1403. //
  1404. // VerifyFileCRC : This function takes a File Path, calculates the hash on this file
  1405. // and compares it to the passed in Hash (pCRC).
  1406. // Returns:
  1407. // S_OK: CRC's Match
  1408. // ERROR_CRC (HRESULT_FROM_WIN32(ERROR_CRC): if the CRC's do not match
  1409. // Otherwise an HRESULT Error Code
  1410. //
  1411. // ----------------------------------------------------------------------------------
  1412. HRESULT VerifyFileCRC(LPCTSTR pszFileToVerify, LPCTSTR pszHash)
  1413. {
  1414. HRESULT hr = S_OK;
  1415. TCHAR szCompareCRC[CRC_HASH_STRING_LENGTH];
  1416. // Validate Parameters
  1417. if ((NULL == pszFileToVerify) || (NULL == pszHash))
  1418. return E_INVALIDARG;
  1419. hr = CalculateFileCRC(pszFileToVerify, szCompareCRC, ARRAYSIZE(szCompareCRC));
  1420. if (FAILED(hr))
  1421. return hr;
  1422. // Now we need to Compare the Calculated CRC with the Passed in CRC
  1423. if (0 == lstrcmpi(szCompareCRC, pszHash))
  1424. return S_OK; // CRC's Match
  1425. else
  1426. return HRESULT_FROM_WIN32(ERROR_CRC); // CRC's do not match
  1427. }
  1428. // ----------------------------------------------------------------------------------
  1429. //
  1430. // CalculateFileCRC : This function takes a File Path, calculates a CRC from the file
  1431. // converts it to a string and returns it in the supplied TCHAR buffer
  1432. //
  1433. // ----------------------------------------------------------------------------------
  1434. typedef BOOL (WINAPI * PFN_CryptCATAdminCalcHashFromFileHandle)(HANDLE hFile,
  1435. DWORD *pcbHash,
  1436. BYTE *pbHash,
  1437. DWORD dwFlags);
  1438. HRESULT CalculateFileCRC(LPCTSTR pszFileToHash, LPTSTR pszHash, int cchBuf)
  1439. {
  1440. HANDLE hFile;
  1441. HRESULT hr = S_OK;
  1442. DWORD cbHash = CRC_HASH_SIZE;
  1443. BYTE bHashBytes[CRC_HASH_SIZE];
  1444. BYTE b;
  1445. // Validate Parameters
  1446. if ((NULL == pszFileToHash) || (NULL == pszHash) || (cchBuf < CRC_HASH_STRING_LENGTH))
  1447. return E_INVALIDARG;
  1448. hFile = CreateFile(pszFileToHash, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1449. if (INVALID_HANDLE_VALUE != hFile)
  1450. {
  1451. HMODULE hWinTrust = LoadLibraryFromSystemDir(_T("wintrust.dll"));
  1452. if (NULL == hWinTrust)
  1453. {
  1454. hr = HRESULT_FROM_WIN32(GetLastError());
  1455. }
  1456. else
  1457. {
  1458. PFN_CryptCATAdminCalcHashFromFileHandle fpnCryptCATAdminCalcHashFromFileHandle = NULL;
  1459. fpnCryptCATAdminCalcHashFromFileHandle = (PFN_CryptCATAdminCalcHashFromFileHandle) GetProcAddress(hWinTrust, "CryptCATAdminCalcHashFromFileHandle");
  1460. if (NULL == fpnCryptCATAdminCalcHashFromFileHandle)
  1461. {
  1462. hr = HRESULT_FROM_WIN32(GetLastError());
  1463. }
  1464. else
  1465. {
  1466. if (!fpnCryptCATAdminCalcHashFromFileHandle(hFile, &cbHash, bHashBytes, 0))
  1467. {
  1468. hr = HRESULT_FROM_WIN32(GetLastError());
  1469. }
  1470. fpnCryptCATAdminCalcHashFromFileHandle = NULL;
  1471. }
  1472. FreeLibrary(hWinTrust);
  1473. }
  1474. CloseHandle(hFile);
  1475. }
  1476. else
  1477. {
  1478. hr = HRESULT_FROM_WIN32(GetLastError());
  1479. }
  1480. if (FAILED(hr))
  1481. return hr;
  1482. LPTSTR p = pszHash;
  1483. // Now we have the Calculated CRC of the File, we need to convert it to a String and Return it. The following
  1484. // loop will go through each byte in the array and convert it to a Hex Character in the supplied TCHAR buffer
  1485. for (int i = 0; i < CRC_HASH_SIZE; i++)
  1486. {
  1487. b = bHashBytes[i] >> 4;
  1488. if (b <= 9)
  1489. *p = '0' + (TCHAR)b;
  1490. else
  1491. *p = 'A' + (TCHAR)(b - 10);
  1492. p++;
  1493. b = bHashBytes[i] & 0x0F;
  1494. if (b <= 9)
  1495. *p = '0' + (TCHAR)b;
  1496. else
  1497. *p = 'A' + (TCHAR)(b - 10);
  1498. p++;
  1499. }
  1500. *p = _T('\0');
  1501. return hr;
  1502. }