|
|
//=======================================================================
//
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
//
// File: fileutil.cpp
//
// Description:
//
// IU file utility library
//
//=======================================================================
#include <windows.h>
#include <tchar.h>
#include <stringutil.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <memutil.h>
#include <fileutil.h>
#include <platform.h>
#include <logging.h>
#include <iucommon.h>
#include <advpub.h>
#include <wincrypt.h>
#include <mscat.h>
#include "mistsafe.h"
#include "wusafefn.h"
const TCHAR REGKEY_WINDOWSUPDATE[] = _T("\\WindowsUpdate\\"); const TCHAR REGKEY_INDUSTRYUPDATE[] = _T("\\WindowsUpdate\\V4\\"); const TCHAR REGKEY_WINCURDIR[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"); const TCHAR REGKEY_PROGFILES[] = _T(":\\Program Files"); const TCHAR REGKEY_PROGFILESDIR[] = _T("ProgramFilesDir");
const TCHAR REGKEY_IUCTL[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\IUControl"); const TCHAR REGVAL_ISBETA[] = _T("IsBeta");
const TCHAR IDENT_IUSERVERCACHE[] = _T("IUServerCache"); const TCHAR IDENT_DEFAULTQUERYSERVERINDEX[] = _T("DefaultQueryServerIndex"); const TCHAR IDENT_BETAQUERYSERVERINDEX[] = _T("BetaQueryServerIndex"); const TCHAR IDENT_QUERYSERVERINDEX[] = _T("QueryServerIndex");
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#define IfNullReturnNull(ptr) if (NULL == ptr) return NULL;
#define InitString(lpStr) if (NULL != lpStr) lpStr[0] = TCHAR_EOS
typedef BOOL (WINAPI * PFN_GetDiskFreeSpaceEx) ( LPCTSTR lpDirectoryName, // directory name
PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
);
//---------------------------------------------------------------------
// CreateNestedDirectory
// Creates the full path of the directory (nested directories)
//---------------------------------------------------------------------
#pragma warning( disable : 4706 ) // Ignore warning C4706: assignment within conditional expression
BOOL CreateNestedDirectory(LPCTSTR pszDir) { BOOL bRc; TCHAR szPath[MAX_PATH]; HRESULT hr=S_OK;
if (NULL == pszDir || MAX_PATH < (lstrlen(pszDir) + 1)) { return FALSE; }
//
// make a local copy and remove final slash
//
hr=StringCchCopyEx(szPath,ARRAYSIZE(szPath),pszDir,NULL,NULL,MISTSAFE_STRING_FLAGS); if(FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); return FALSE; }
int iLast = lstrlen(szPath) - 1; if (0 > iLast) // Prefix
iLast = 0; if (szPath[iLast] == '\\') szPath[iLast] = 0;
//
// check to see if directory already exists
//
DWORD dwAttr = GetFileAttributes(szPath);
if (dwAttr != 0xFFFFFFFF) { if ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0) return TRUE; }
//
// create it
//
TCHAR* p = szPath; if (p[1] == ':') p += 2; else { // Check if the path is a UNC, need to skip past the UNC Server\Share specification to get to
// real path
if (p[0] == '\\' && p[1] == '\\') { p += 2; // skip to the beginning of the share declaration
p = _tcschr(p, '\\'); if (NULL == p) { return FALSE; // invalid UNC
} p++; // look for a trailing '\', if it exists then we want to further check for any nested levels,
// otherwise the path as is should be valid.
p = _tcschr(p, '\\'); if (NULL == p) { // UNC is valid base share name, assume its valid
return TRUE; } else { // look for any further levels, if they exist then pass through to the rest of the directory
// creator
p++; if (NULL == p) { // UNC is valid base share name, but had a trailing slash, not a problem, assume its valid
return TRUE; } // if we haven't exited then there are remaining levels, don't reset our current pointer in the string
// and let the rest of the nested directory creation work.
} } } if (*p == '\\') p++; while (p = _tcschr(p, '\\')) // Ignore warning C4706: assignment within conditional expression
{ *p = 0; bRc = CreateDirectory(szPath, NULL); *p = '\\'; p++; if (!bRc) { if (GetLastError() != ERROR_ALREADY_EXISTS) { return FALSE; } } }
bRc = CreateDirectory(szPath, NULL); if ( !bRc ) { if (GetLastError() != ERROR_ALREADY_EXISTS) { return FALSE; } }
return TRUE; } #pragma warning( default : 4706 )
//-----------------------------------------------------------------------------------
// GetIndustryUpdateDirectory
// This function returns the location of the IndustryUpdate directory. All local
// files are stored in this directory. The pszPath parameter needs to be at least
// MAX_PATH.
//-----------------------------------------------------------------------------------
void GetIndustryUpdateDirectory(LPTSTR pszPath) { /*
HRESULT hr=S_OK;
LOG_Block("GetIndustryUpdateDirectory");
if (NULL == pszPath) { LOG_ErrorMsg(E_INVALIDARG); return; }
static TCHAR szCachePath[MAX_PATH] = {'\0'};
if (szCachePath[0] == '\0') { HKEY hkey;
pszPath[0] = '\0'; if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_WINCURDIR, &hkey) == ERROR_SUCCESS) { DWORD cbPath = MAX_PATH * sizeof(TCHAR); RegQueryValueEx(hkey, REGKEY_PROGFILESDIR, NULL, NULL, (LPBYTE)pszPath, &cbPath); RegCloseKey(hkey); } if (pszPath[0] == '\0') { TCHAR szWinDir[MAX_PATH]; if (! GetWindowsDirectory(szWinDir, ARRAYSIZE(szWinDir))) { //if GetWinDir fails, assume C:
CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szWinDir,ARRAYSIZE(szWinDir),_T("C"),NULL,NULL,MISTSAFE_STRING_FLAGS)); } pszPath[0] = szWinDir[0]; pszPath[1] = '\0'; //It is assumed that the pszPath will be of the size MAX_PATH
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_PROGFILES,NULL,NULL,MISTSAFE_STRING_FLAGS));
}
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_INDUSTRYUPDATE,NULL,NULL,MISTSAFE_STRING_FLAGS)); CreateNestedDirectory(pszPath);
//
// save it in the cache (lstrcpy -> lstrcpyn to shut Prefix up, although this
// would always be safe given the constants used).
//
lstrcpyn(szCachePath, pszPath, MAX_PATH); } else { //It is assumed that the pszPath will be of the size MAX_PATH
CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(pszPath,MAX_PATH,szCachePath,NULL,NULL,MISTSAFE_STRING_FLAGS)); }
CleanUp: return; */ (void) GetWUDirectory(pszPath, MAX_PATH, TRUE);
}
//-----------------------------------------------------------------------------------
// GetWindowsUpdateV3Directory - used for V3 history migration
// This function returns the location of the WindowsUpdate(V3) directory. All V3
// local files are stored in this directory. The pszPath parameter needs to be
// at least MAX_PATH. The directory is created if not found
//-----------------------------------------------------------------------------------
void GetWindowsUpdateV3Directory(LPTSTR pszPath) { LOG_Block("GetWindowsUpdateV3Directory");
HRESULT hr=S_OK; if (NULL == pszPath) { LOG_ErrorMsg(E_INVALIDARG); return; }
static TCHAR szWUCachePath[MAX_PATH] = {'\0'};
if (szWUCachePath[0] == '\0') { HKEY hkey;
pszPath[0] = '\0'; if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_WINCURDIR, &hkey) == ERROR_SUCCESS) { DWORD cbPath = MAX_PATH * sizeof(TCHAR); RegQueryValueEx(hkey, REGKEY_PROGFILESDIR, NULL, NULL, (LPBYTE)pszPath, &cbPath); RegCloseKey(hkey); } if (pszPath[0] == '\0') { TCHAR szWinDir[MAX_PATH]; if (! GetWindowsDirectory(szWinDir, ARRAYSIZE(szWinDir))) { //if GetWinDir fails, assume C:
CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szWinDir,ARRAYSIZE(szWinDir),_T("C"),NULL,NULL,MISTSAFE_STRING_FLAGS)); } pszPath[0] = szWinDir[0]; pszPath[1] = '\0'; CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_PROGFILES,NULL,NULL,MISTSAFE_STRING_FLAGS)); }
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_WINDOWSUPDATE,NULL,NULL,MISTSAFE_STRING_FLAGS)); CreateNestedDirectory(pszPath);
//
// save it in the cache (lstrcpy -> lstrcpyn to shut Prefix up, although this
// would always be safe given the constants used).
//
lstrcpyn(szWUCachePath, pszPath, MAX_PATH); } else { CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(pszPath,MAX_PATH,szWUCachePath,NULL,NULL,MISTSAFE_STRING_FLAGS));
}
CleanUp: return;
}
// ----------------------------------------------------------------------
//
// Public function MySplitPath() - same as CRT _tsplitpath()
// to break a path into pieces
//
// Input:
// see below
//
// Return:
// Returns the address of the last occurrence of the character in
// the string if successful, or NULL otherwise.
//
// Algorithm:
// C:\mydir\...\mysubdir\myfile.ext
// _________| _________| |____
// | | |
// start of dir start of filename start of extension
//
// ----------------------------------------------------------------------
void MySplitPath( LPCTSTR lpcszPath, // original path
LPTSTR lpszDrive, // point to buffer to receive drive letter
LPTSTR lpszDir, // point to buffer to receive directory
LPTSTR lpszFName, // point to buffer to receive file name
LPTSTR lpszExt // point to buffer to receive extension
) { LPCTSTR lpFirstSlash, lpLastSlash, lpPeriod; LPCTSTR lpStart = lpcszPath;
int nPathLen = lstrlen(lpcszPath); int nExtLen;
//
// initialize pass in vars
//
InitString(lpszDrive); InitString(lpszDir); InitString(lpszFName); InitString(lpszExt); if (0 == nPathLen || TCHAR_DOT == lpcszPath[0]) { //
// not a valid path
//
return; }
lpFirstSlash = MyStrChr(lpcszPath, TCHAR_BACKSLASH); lpLastSlash = MyStrRChr(lpcszPath, NULL, TCHAR_BACKSLASH); lpPeriod = MyStrRChr(lpcszPath, NULL, TCHAR_DOT);
nExtLen = lstrlen(lpPeriod); if (NULL != lpPeriod && NULL != lpszExt) { //
// found a period from right, and
// we have buffer to output extension
//
if(FAILED(StringCchCopyEx(lpszExt,nExtLen+1,lpPeriod,NULL,NULL,MISTSAFE_STRING_FLAGS))) return;
}
//
// process drive
//
if (nPathLen > 2 && TCHAR_COLON == lpcszPath[1]) { lpStart = lpcszPath + 2; if (NULL != lpszDir) { lstrcpyn(lpszDrive, lpcszPath, 3); } }
if (NULL == lpFirstSlash) { //
// no backslash, assume this is file name only
//
if (NULL != lpszFName) { lstrcpyn(lpszFName, lpStart, lstrlen(lpStart) - nExtLen + 1); } } else { //
// find directory if not empty
//
//if (lpLastSlash != lpFirstSlash && NULL != lpszDir)
if (NULL != lpszDir) { lstrcpyn(lpszDir, lpFirstSlash, (int)(lpLastSlash - lpFirstSlash + 2)); }
//
// find file name
//
if (NULL != lpszFName) { lstrcpyn(lpszFName, lpLastSlash + 1, lstrlen(lpLastSlash) - nExtLen ); } } }
// **********************************************************************************
//
// File version related declarations
//
// **********************************************************************************
// ----------------------------------------------------------------------------------
//
// public function to retrieve file version
//
// ----------------------------------------------------------------------------------
BOOL GetFileVersion(LPCTSTR lpsFile, LPFILE_VERSION lpstVersion) { LOG_Block("GetFileVersion()");
DWORD dwVerInfoSize; DWORD dwHandle; DWORD dwVerNumber; LPVOID lpBuffer = NULL; UINT uiSize = 0; VS_FIXEDFILEINFO* lpVSFixedFileInfo;
USES_MY_MEMORY;
if (NULL != lpstVersion) { //
// if this pointer not null, we always try to initialize
// this structure to 0, in order to reduce the change of
// programming error, no matter the file exists or not.
//
ZeroMemory(lpstVersion, sizeof(FILE_VERSION)); } if (NULL == lpsFile || NULL == lpstVersion) { LOG_ErrorMsg(E_INVALIDARG); return FALSE; }
//
// 506212 IU - FRE log reports incorrect version data for iuengine.dll
//
if (FALSE == FileExists(lpsFile)) { //
// GetFileVersionInfoSize() returns 0 but sets last error to 0 (or
// doesn't set) if file doesn't exist on Win2K.
//
LOG_Out(_T("File \"%s\" doesn't exist, returning FALSE"), lpsFile); return FALSE; } dwVerInfoSize = GetFileVersionInfoSize((LPTSTR)lpsFile, &dwHandle); if (0 == dwVerInfoSize) { DWORD dwErr = GetLastError(); if (0 == dwErr) { LOG_Error(_T("File %s does not have version data. Use 0.0.0.0"), lpsFile); lpstVersion->Major = 0x0; lpstVersion->Minor = 0x0; lpstVersion->Build = 0x0; lpstVersion->Ext = 0x0; return TRUE; } else { LOG_ErrorMsg(dwErr); return FALSE; } }
if (NULL == (lpBuffer = (LPVOID) MemAlloc(dwVerInfoSize))) { LOG_Error(_T("Failed to allocate memory to get version info")); return FALSE; }
if (!GetFileVersionInfo((LPTSTR)lpsFile, dwHandle, dwVerInfoSize, lpBuffer)) { LOG_ErrorMsg(GetLastError()); return FALSE; }
//
// Get the value for Translation
//
if (!VerQueryValue(lpBuffer, _T("\\"), (LPVOID*)&lpVSFixedFileInfo, &uiSize) && (uiSize) && NULL != lpVSFixedFileInfo) { LOG_ErrorMsg(GetLastError()); return FALSE; }
dwVerNumber = lpVSFixedFileInfo->dwFileVersionMS; lpstVersion->Major = HIWORD(dwVerNumber); lpstVersion->Minor = LOWORD(dwVerNumber);
dwVerNumber = lpVSFixedFileInfo->dwFileVersionLS; lpstVersion->Build = HIWORD(dwVerNumber); lpstVersion->Ext = LOWORD(dwVerNumber);
LOG_Out(_T("File %s found version %d.%d.%d.%d"), lpsFile, lpstVersion->Major, lpstVersion->Minor, lpstVersion->Build, lpstVersion->Ext);
return TRUE; }
// ----------------------------------------------------------------------------------
//
// public functions to compare file versions
//
// return:
// -1: if file ver of 1st parameter < file ver of 2nd parameter
// 0: if file ver of 1st parameter = file ver of 2nd parameter
// +1: if file ver of 1st parameter > file ver of 2nd parameter
//
// ----------------------------------------------------------------------------------
int CompareFileVersion(const FILE_VERSION stVersion1, const FILE_VERSION stVersion2) {
if ((short)stVersion1.Major < 0 || (short)stVersion2.Major < 0) { //
// two empty version structure to compare, we call it equal
//
return 0; }
if (stVersion1.Major != stVersion2.Major) { //
// major diff, then we know the answer
//
return (stVersion1.Major < stVersion2.Major) ? -1 : 1; } else { if ((short)stVersion1.Minor < 0 || (short)stVersion2.Minor < 0) { //
// if any minor missing, they equal
//
return 0; }
if (stVersion1.Minor != stVersion2.Minor) { //
// minor diff, then we know the answer
//
return (stVersion1.Minor < stVersion2.Minor) ? -1 : 1; } else { if ((short)stVersion1.Build < 0 || (short)stVersion2.Build < 0) { //
// if any build is missing, they equal
//
return 0; }
if (stVersion1.Build != stVersion2.Build) { //
// if build diff then we are done
//
return (stVersion1.Build < stVersion2.Build) ? -1 : 1; } else { if ((short)stVersion1.Ext < 0 || (short)stVersion2.Ext < 0 || stVersion1.Ext == stVersion2.Ext) { //
// if any ext is missing, or they equal, we are done
//
return 0; } else { return (stVersion1.Ext < stVersion2.Ext) ? -1 : 1; } } } } }
HRESULT CompareFileVersion(LPCTSTR lpsFile1, LPCTSTR lpsFile2, int *pCompareResult) {
LOG_Block("CompareFileVersion(File, File)");
FILE_VERSION stVer1 = {-1,-1,-1,-1}, stVer2 = {-1,-1,-1,-1}; if (NULL == lpsFile1 || NULL == lpsFile2) { LOG_ErrorMsg(E_INVALIDARG); return E_INVALIDARG; }
if (!GetFileVersion(lpsFile1, &stVer1)) { return E_INVALIDARG; } if (!GetFileVersion(lpsFile2, &stVer2)) { return E_INVALIDARG; }
*pCompareResult = CompareFileVersion(stVer1, stVer2); return S_OK; }
HRESULT CompareFileVersion(LPCTSTR lpsFile, FILE_VERSION stVersion, int *pCompareResult) { LOG_Block("CompareFileVersion(FILE, VER)"); FILE_VERSION stVer = {0};
if (NULL == lpsFile) { LOG_Error(_T("NULL file pointer passed in. Function returns 0")); return E_INVALIDARG; }
if (!GetFileVersion(lpsFile, &stVer)) { return E_INVALIDARG; }
*pCompareResult = CompareFileVersion(stVer, stVersion); return S_OK; }
// ----------------------------------------------------------------------------------
//
// publif function to convert a string type functoin to FILE_VERSION type
//
// ----------------------------------------------------------------------------------
BOOL ConvertStringVerToFileVer(LPCSTR lpsVer, LPFILE_VERSION lpstVer) { LOG_Block("ConvertStringVerToFileVer()");
WORD n = -1; char c; BOOL fHasNumber = FALSE;
#if defined(DBG) // full logging for checked builds
USES_IU_CONVERSION; #endif
if (NULL == lpsVer || NULL == lpstVer) { LOG_ErrorMsg(E_INVALIDARG); return FALSE; }
#if defined(DBG) // full logging for checked builds
LOG_Out(_T("String version = %s"), A2T(const_cast<LPSTR>(lpsVer))); #endif
lpstVer->Major = lpstVer->Minor = lpstVer->Build = lpstVer->Ext = -1;
c = *lpsVer;
//
// get first number
//
n = 0; while (c != '\0' && '0' <= c && c <= '9') { n = n * 10 + (int)(c - '0'); c = *++lpsVer; fHasNumber = TRUE; } if (fHasNumber) { lpstVer->Major = n; } else { return TRUE; }
//
// skip delimiter
//
while (c != '\0' && ('0' > c || c > '9')) { c = *++lpsVer; }
//
// get 2nd number
//
n = 0; fHasNumber = FALSE; while (c != '\0' && '0' <= c && c <= '9') { n = n * 10 + (int)(c - '0'); c = *++lpsVer; fHasNumber = TRUE; } if (fHasNumber) { lpstVer->Minor = n; } else { return TRUE; }
//
// skip delimiter
//
while (c != '\0' && ('0' > c || c > '9')) { c = *++lpsVer; }
//
// get 3rd number
//
n = 0; fHasNumber = FALSE; while (c != '\0' && '0' <= c && c <= '9') { n = n * 10 + (int)(c - '0'); c = *++lpsVer; fHasNumber = TRUE; } if (fHasNumber) { lpstVer->Build = n; } else { return TRUE; }
//
// skip delimiter
//
while (c != '\0' && ('0' > c || c > '9')) { c = *++lpsVer; }
//
// get 4th number
//
n = 0; fHasNumber = FALSE; while (c != '\0' && '0' <= c && c <= '9') { n = n * 10 + (int)(c - '0'); c = *++lpsVer; fHasNumber = TRUE; } if (fHasNumber) { lpstVer->Ext = n; }
return TRUE; }
// ----------------------------------------------------------------------------------
//
// publif function to convert a FILE_VERSION to a string
//
// ----------------------------------------------------------------------------------
BOOL ConvertFileVerToStringVer( FILE_VERSION stVer, // version to convert
char chDel, // delimiter to use
LPSTR lpsBuffer, // buffer of string
int ccBufSize // size of buffer
) { //
// declare max buffer that wsprintf can use
//
char szBuf[1024];
HRESULT hr=S_OK;
hr=StringCchPrintfExA( szBuf,ARRAYSIZE(szBuf), NULL,NULL,MISTSAFE_STRING_FLAGS, "%d%c%d%c%d%c", stVer.Major, chDel, stVer.Minor, chDel, stVer.Build, chDel, stVer.Ext, chDel ); if(FAILED(hr)) { goto ErrorExit; }
hr=StringCchCopyExA(lpsBuffer,ccBufSize,szBuf,NULL,NULL,MISTSAFE_STRING_FLAGS); if(FAILED(hr)) { goto ErrorExit; }
return TRUE;
ErrorExit: lpsBuffer[0] = '\0'; return FALSE;
}
// ----------------------------------------------------------------------------------
//
// public function to check if a file exists
//
// ----------------------------------------------------------------------------------
BOOL FileExists( LPCTSTR lpsFile // file with path to check
) { LOG_Block("FileExists"); DWORD dwAttr; BOOL rc;
if (NULL == lpsFile || _T('\0') == *lpsFile) { LOG_ErrorMsg(E_INVALIDARG); return FALSE; }
dwAttr = GetFileAttributes(lpsFile);
if (-1 == dwAttr) { LOG_InfoMsg(GetLastError()); rc = FALSE; }
else { rc = (0x0 == (FILE_ATTRIBUTE_DIRECTORY & dwAttr)); }
return rc; }
// ----------------------------------------------------------------------------------
//
// publif function to retrieve the creation time of a file in ISO 8601 format
// without zone info
//
// if buffer too small, call GetLastError();
//
// ----------------------------------------------------------------------------------
BOOL GetFileTimeStamp(LPCTSTR lpsFile, LPTSTR lpsTimeStamp, int iBufSize) { BOOL fRet = FALSE; HANDLE hFile; SYSTEMTIME tm; WIN32_FILE_ATTRIBUTE_DATA fileData; HRESULT hr=S_OK;
if (0 != GetFileAttributesEx(lpsFile, GetFileExInfoStandard, &fileData) && 0 != FileTimeToSystemTime((const FILETIME*)&(fileData.ftCreationTime), &tm)) { //
// the output of this systemtime, according to ISA 8601 format, will be
// like yyyy-mm-ddThh:mm:ss format, so it is 20 chars incl terminator
//
if (iBufSize < 20) { SetLastError(ERROR_BUFFER_OVERFLOW); return fRet; } hr=StringCchPrintfEx(lpsTimeStamp,iBufSize,NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%4d-%02d-%02dT%02d:%02d:%02d"), tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond);
if(FAILED(hr)) { fRet=FALSE; SetLastError(HRESULT_CODE(hr)); } else fRet = TRUE;
} return fRet; }
// ----------------------------------------------------------------------------------
//
// publif function to find the free disk space in KB
//
//
// ----------------------------------------------------------------------------------
HRESULT GetFreeDiskSpace(TCHAR tcDriveLetter, int *piKBytes) { HRESULT hr = E_INVALIDARG; BOOL fResult; TCHAR szDrive[4];
if (!(_T('A') <= tcDriveLetter && tcDriveLetter <= _T('Z') || _T('a') <= tcDriveLetter && tcDriveLetter <= _T('z'))) { return hr; }
hr=StringCchPrintfEx(szDrive,ARRAYSIZE(szDrive),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("%c:\\"), tcDriveLetter);
if(FAILED(hr)) return hr;
PFN_GetDiskFreeSpaceEx pGetDiskFreeSpaceEx = (PFN_GetDiskFreeSpaceEx) GetProcAddress( GetModuleHandle(_T("kernel32.dll")), #ifdef UNICODE
"GetDiskFreeSpaceExW"); #else
"GetDiskFreeSpaceExA"); #endif
if (pGetDiskFreeSpaceEx) { LARGE_INTEGER i64FreeBytesToCaller, i64TotalBytes;
fResult = pGetDiskFreeSpaceEx (szDrive, (PULARGE_INTEGER)&i64FreeBytesToCaller, (PULARGE_INTEGER)&i64TotalBytes, (PULARGE_INTEGER)NULL); *piKBytes = (int) (i64FreeBytesToCaller.QuadPart / 1024); }
else { DWORD dwSectPerClust = 0x0, dwBytesPerSect = 0x0, dwFreeClusters = 0x0, dwTotalClusters = 0x0;
fResult = GetDiskFreeSpace (szDrive, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters); *piKBytes = (int) ((float)(((int)dwFreeClusters) * ((int)dwSectPerClust)) / 1024.0 * (int)dwBytesPerSect); }
return (fResult) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
}
HRESULT GetFreeDiskSpace(LPCTSTR pszUNC, int *piKBytes) { HRESULT hr = E_INVALIDARG; BOOL fResult;
PFN_GetDiskFreeSpaceEx pGetDiskFreeSpaceEx = (PFN_GetDiskFreeSpaceEx) GetProcAddress( GetModuleHandle(_T("kernel32.dll")), #ifdef UNICODE
"GetDiskFreeSpaceExW"); #else
"GetDiskFreeSpaceExA"); #endif
if (pGetDiskFreeSpaceEx) { LARGE_INTEGER i64FreeBytesToCaller, i64TotalBytes;
fResult = pGetDiskFreeSpaceEx (pszUNC, (PULARGE_INTEGER)&i64FreeBytesToCaller, (PULARGE_INTEGER)&i64TotalBytes, (PULARGE_INTEGER)NULL); *piKBytes = (int) (i64FreeBytesToCaller.QuadPart / 1024); }
else { DWORD dwSectPerClust = 0x0, dwBytesPerSect = 0x0, dwFreeClusters = 0x0, dwTotalClusters = 0x0;
fResult = GetDiskFreeSpace (pszUNC, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters); *piKBytes = (int) ((float)(((int)dwFreeClusters) * ((int)dwSectPerClust)) / 1024.0 * (int)dwBytesPerSect); }
return (fResult) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
}
// ----------------------------------------------------------------------------------
//
// publif function to expand the file path
//
// Assumption: lpszFilePath points to allocated buffer of MAX_PATH.
// if the expanded path is longer than MAX_PATH, error returned.
//
// ----------------------------------------------------------------------------------
HRESULT ExpandFilePath(LPCTSTR lpszFilePath, LPTSTR lpszDestination, UINT cChars) { HRESULT hr = S_OK; LPTSTR lpEnvExpanded; LPTSTR lp2ndPercentChar = NULL; LPTSTR lpSearchStart;
USES_MY_MEMORY;
if (NULL == (lpEnvExpanded = (LPTSTR) MemAlloc((cChars + 1) * sizeof(TCHAR)))) { return E_OUTOFMEMORY; }
//
// first, let's substitute the system defined variables
//
if (0 == ExpandEnvironmentStrings(lpszFilePath, lpEnvExpanded, cChars)) { hr = HRESULT_FROM_WIN32(GetLastError()); }
//
// then handle pre-defined variables that we need to recognize
// these include all CSIDL definitions inside shlobj.h for SHGetFolderPath() API
//
const int C_NAME_LEN = 32;
struct _CSIDL_NAME { long CSIDL_Id; TCHAR CSIDL_Str[C_NAME_LEN]; }; const _CSIDL_NAME C_CSIDL_NAMES[] = { {CSIDL_ADMINTOOLS , _T("CSIDL_ADMINTOOLS")}, {CSIDL_ALTSTARTUP , _T("CSIDL_ALTSTARTUP")}, {CSIDL_APPDATA , _T("CSIDL_APPDATA")}, {CSIDL_BITBUCKET , _T("CSIDL_BITBUCKET")}, {CSIDL_COMMON_ADMINTOOLS , _T("CSIDL_COMMON_ADMINTOOLS")}, {CSIDL_COMMON_ALTSTARTUP , _T("CSIDL_COMMON_ALTSTARTUP")}, {CSIDL_COMMON_APPDATA , _T("CSIDL_COMMON_APPDATA")}, {CSIDL_COMMON_DESKTOPDIRECTORY , _T("CSIDL_COMMON_DESKTOPDIRECTORY")}, {CSIDL_COMMON_DOCUMENTS , _T("CSIDL_COMMON_DOCUMENTS")}, {CSIDL_COMMON_FAVORITES , _T("CSIDL_COMMON_FAVORITES")}, {CSIDL_COMMON_PROGRAMS , _T("CSIDL_COMMON_PROGRAMS")}, {CSIDL_COMMON_STARTMENU , _T("CSIDL_COMMON_STARTMENU")}, {CSIDL_COMMON_STARTUP , _T("CSIDL_COMMON_STARTUP")}, {CSIDL_COMMON_TEMPLATES , _T("CSIDL_COMMON_TEMPLATES")}, {CSIDL_CONTROLS , _T("CSIDL_CONTROLS")}, {CSIDL_COOKIES , _T("CSIDL_COOKIES")}, {CSIDL_DESKTOP , _T("CSIDL_DESKTOP")}, {CSIDL_DESKTOPDIRECTORY , _T("CSIDL_DESKTOPDIRECTORY")}, {CSIDL_DRIVES , _T("CSIDL_DRIVES")}, {CSIDL_FAVORITES , _T("CSIDL_FAVORITES")}, {CSIDL_FONTS , _T("CSIDL_FONTS")}, {CSIDL_HISTORY , _T("CSIDL_HISTORY")}, {CSIDL_INTERNET , _T("CSIDL_INTERNET")}, {CSIDL_INTERNET_CACHE , _T("CSIDL_INTERNET_CACHE")}, {CSIDL_LOCAL_APPDATA , _T("CSIDL_LOCAL_APPDATA")}, {CSIDL_MYPICTURES , _T("CSIDL_MYPICTURES")}, {CSIDL_NETHOOD , _T("CSIDL_NETHOOD")}, {CSIDL_NETWORK , _T("CSIDL_NETWORK")}, {CSIDL_PERSONAL , _T("CSIDL_PERSONAL")}, {CSIDL_PRINTERS , _T("CSIDL_PRINTERS")}, {CSIDL_PRINTHOOD , _T("CSIDL_PRINTHOOD")}, {CSIDL_PROFILE , _T("CSIDL_PROFILE")}, {CSIDL_PROGRAM_FILES , _T("CSIDL_PROGRAM_FILES")}, {CSIDL_PROGRAM_FILES_COMMON , _T("CSIDL_PROGRAM_FILES_COMMON")}, {CSIDL_PROGRAMS , _T("CSIDL_PROGRAMS")}, {CSIDL_RECENT , _T("CSIDL_RECENT")}, {CSIDL_SENDTO , _T("CSIDL_SENDTO")}, {CSIDL_STARTMENU , _T("CSIDL_STARTMENU")}, {CSIDL_STARTUP , _T("CSIDL_STARTUP")}, {CSIDL_SYSTEM , _T("CSIDL_SYSTEM")}, {CSIDL_TEMPLATES , _T("CSIDL_TEMPLATES")}, {CSIDL_WINDOWS , _T("CSIDL_WINDOWS")} };
//
// see if this path has any of these variables
//
lpSearchStart = lpEnvExpanded + 1;
if (SUCCEEDED(hr) && _T('%') == *lpEnvExpanded && NULL != (lp2ndPercentChar = StrChr(lpSearchStart, _T('%')))) { //
// copy the variable name to passed in buffer
//
lstrcpyn(lpszDestination, lpSearchStart, (int)(lp2ndPercentChar - lpSearchStart + 1)); // skip the 1st % char
lp2ndPercentChar++; // move to begining of rest of path
//
// find out what this variable is
//
for (int i = 0; i < sizeof(C_CSIDL_NAMES)/sizeof(C_CSIDL_NAMES[0]); i++) { if (lstrcmpi(lpszDestination, C_CSIDL_NAMES[i].CSIDL_Str) == 0) { //
// found the matching variable!
//
if (S_OK == (hr = SHGetFolderPath(NULL, C_CSIDL_NAMES[i].CSIDL_Id, NULL, SHGFP_TYPE_CURRENT, lpszDestination))) { //
// ensure buffer big enough
//
if (lstrlen(lp2ndPercentChar) + lstrlen(lpszDestination) + sizeof(TCHAR) >= cChars) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); }
//
// append the rest of them - shouldn't be any of
// these variables in the rest of string, since this
// kind variable alaways starts at the beginning of
// a path
//
if(SUCCEEDED(hr)) hr=PathCchAppend(lpszDestination,MAX_PATH,lp2ndPercentChar);
if (SUCCEEDED(hr)) { return hr; }
}
//
// we found the matching variable, but couldn't get the
// string replaced.
//
break; } }
//
// didn't find it.
//
}
//
// didn't find it, or failed.
//
if (FAILED(hr)) { *lpszDestination = _T('\0'); } else { lstrcpyn(lpszDestination, lpEnvExpanded, cChars); }
return hr; }
//----------------------------------------------------------------------
//
// function to validate the folder to make sure
// user has required priviledge
//
// folder will be verified exist. then required priviledge will be checked.
//
// ASSUMPTION: lpszFolder not exceeding MAX_PATH long!!!
//
//----------------------------------------------------------------------
DWORD ValidateFolder(LPTSTR lpszFolder, BOOL fCheckForWrite) { LOG_Block("ValidateFolder");
DWORD dwErr = ERROR_SUCCESS; HRESULT hr=S_OK; //
// first, check if the folder exist
//
dwErr = GetFileAttributes(lpszFolder);
if (-1 == dwErr) { dwErr = GetLastError(); LOG_ErrorMsg(dwErr); return dwErr; }
//
// make sure it's a directory
//
if ((FILE_ATTRIBUTE_DIRECTORY & dwErr) == 0) { dwErr = ERROR_PATH_NOT_FOUND; LOG_ErrorMsg(dwErr); return dwErr; }
if (fCheckForWrite) { TCHAR szFile[MAX_PATH], szFileName[40]; SYSTEMTIME tm; HANDLE hFile;
//
// create a random file name
//
hr=StringCchCopyEx(szFile,ARRAYSIZE(szFile),lpszFolder,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr)) { dwErr = HRESULT_CODE(hr);; LOG_ErrorMsg(dwErr); return dwErr; }
GetLocalTime(&tm);
hr=StringCchPrintfEx( szFileName, ARRAYSIZE(szFileName), NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%08x%08x%02hd%02hd%02hd%02hd%02hd%03hd%08x"), GetCurrentProcessId(), GetCurrentThreadId(), tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond, tm.wMilliseconds, GetTickCount()); if(FAILED(hr)) { dwErr = HRESULT_CODE(hr);; LOG_ErrorMsg(dwErr); return dwErr; }
hr=PathCchAppend(szFile,ARRAYSIZE(szFile),szFileName); if(FAILED(hr)) { dwErr = HRESULT_CODE(hr);; LOG_ErrorMsg(dwErr); return dwErr; }
//
// try to write file
//
hFile = CreateFile(szFile, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
if (INVALID_HANDLE_VALUE == hFile) { dwErr = GetLastError(); LOG_ErrorMsg(dwErr); return dwErr; }
CloseHandle(hFile); }
return ERROR_SUCCESS; }
//----------------------------------------------------------------------
//
// function to get a QueryServer from the Ident File for a Given ClientName
// This also looks in the registry for the IsBeta regkey indicating Beta
// functionlality
//
// Returns:
// S_OK : we successfully got QueryServer for this Client
// S_FALSE : we did NOT find a QueryServer for this Client (pszQueryServer will be a null string)
// E_INVALIDARG : parameters were incorrect
//----------------------------------------------------------------------
HRESULT GetClientQueryServer(LPCTSTR pszClientName, LPTSTR pszQueryServer, UINT cChars) { HKEY hkey; BOOL fBeta = FALSE; int iIndex; TCHAR szQueryServerKeyName[128]; TCHAR szIUDir[MAX_PATH]; TCHAR szIdentFile[MAX_PATH]; DWORD dwValue = 0; DWORD dwLength = sizeof(dwValue); HRESULT hr=S_OK;
LOG_Block("GetClientQueryServer");
if ((NULL == pszClientName) || (NULL == pszQueryServer) || (0 == cChars)) { LOG_ErrorMsg(E_INVALIDARG); return E_INVALIDARG; }
// Check IUControl Reg Key for Beta Mode
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, &hkey)) { if (ERROR_SUCCESS == RegQueryValueEx(hkey, REGVAL_ISBETA, NULL, NULL, (LPBYTE)&dwValue, &dwLength)) { if (1 == dwValue) { fBeta = TRUE; } } RegCloseKey(hkey); }
GetIndustryUpdateDirectory(szIUDir); hr=PathCchCombine (szIdentFile,ARRAYSIZE(szIdentFile),szIUDir,IDENTTXT); if(FAILED(hr)) { LOG_ErrorMsg(hr); return hr; }
// Form the KeyName for the QueryServer Index
hr=StringCchPrintfEx(szQueryServerKeyName,ARRAYSIZE(szQueryServerKeyName),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("%s%s"), pszClientName, fBeta ? IDENT_BETAQUERYSERVERINDEX : IDENT_QUERYSERVERINDEX);
if(FAILED(hr)) { LOG_ErrorMsg(hr); return hr; }
iIndex = GetPrivateProfileInt(IDENT_IUSERVERCACHE, szQueryServerKeyName, 0, szIdentFile); if (0 == iIndex) { iIndex = GetPrivateProfileInt(IDENT_IUSERVERCACHE, IDENT_DEFAULTQUERYSERVERINDEX, 0, szIdentFile); if (0 == iIndex) { return S_FALSE; } }
// Form the KeyName for the Specified QueryServer based on the Index
hr=StringCchPrintfEx(szQueryServerKeyName,ARRAYSIZE(szQueryServerKeyName),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("Server%d"), iIndex); if(FAILED(hr)) { LOG_ErrorMsg(hr); return hr; }
GetPrivateProfileString(IDENT_IUSERVERCACHE, szQueryServerKeyName, _T(""), pszQueryServer, cChars, szIdentFile); if ('\0' == *pszQueryServer) { return S_FALSE; } else { return S_OK; } }
HRESULT DecompressFolderCabs(LPCTSTR pszDecompressPath) { HRESULT hr = S_FALSE; // default is not an Error, but if there are no cabs we return S_FALSE
TCHAR szSearchInfo[MAX_PATH]; TCHAR szCabPath[MAX_PATH]; LPTSTR pszCabList = NULL; LPTSTR pszWritePosition = NULL; LONG lCabCount = 0;
WIN32_FIND_DATA fd; HANDLE hFind; BOOL fMore = TRUE; BOOL fRet = TRUE;
USES_IU_CONVERSION;
hr=PathCchCombine (szSearchInfo,ARRAYSIZE(szSearchInfo),pszDecompressPath, _T("*.cab"));
if(FAILED(hr)) { return hr; }
hFind = FindFirstFile(szSearchInfo, &fd); if (hFind != INVALID_HANDLE_VALUE) { while (fMore) { if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { lCabCount++; } fMore = FindNextFile(hFind, &fd); } FindClose(hFind);
pszCabList = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PATH * sizeof(TCHAR) * lCabCount)); if (NULL == pszCabList) { hr = E_OUTOFMEMORY; return hr; }
pszWritePosition = pszCabList;
hFind = FindFirstFile(szSearchInfo, &fd); fMore = (INVALID_HANDLE_VALUE != hFind);
DWORD dwRemLength=lCabCount*MAX_PATH;
while (fMore) { if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { hr=PathCchCombine(szCabPath,ARRAYSIZE(szCabPath),pszDecompressPath, fd.cFileName); if(FAILED(hr)) { SafeHeapFree(pszCabList); return hr; } hr=StringCchCatEx(pszWritePosition,dwRemLength,szCabPath,NULL,NULL,MISTSAFE_STRING_FLAGS); if(FAILED(hr)) { SafeHeapFree(pszCabList); return hr;
} dwRemLength=dwRemLength- ( lstrlen(pszWritePosition)+ 2 * (sizeof(TCHAR)) ); pszWritePosition += lstrlen(pszWritePosition) + 2 * (sizeof(TCHAR));
} fMore = FindNextFile(hFind, &fd); } FindClose(hFind);
pszWritePosition = pszCabList; for (LONG lCnt = 0; lCnt < lCabCount; lCnt++) { fRet = IUExtractFiles(pszWritePosition, pszDecompressPath); if (!fRet) { break; } pszWritePosition += lstrlen(pszWritePosition) + 2 * (sizeof(TCHAR)); }
SafeHeapFree(pszCabList); if (!fRet) { hr = E_FAIL; // one of the cabs had an error decompressing
} else { hr = S_OK; } } return hr; }
//Extracts a cab file to the specified destination. Optionally we can pass in a colon seperated list of files to extract
BOOL IUExtractFiles(LPCTSTR pszCabFile, LPCTSTR pszDecompressFolder, LPCTSTR pszFileNames) { HRESULT hr = S_OK; #ifdef UNICODE
char szCabFile[MAX_PATH]; char szDecompressFolder[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, pszCabFile, -1, szCabFile, sizeof(szCabFile), NULL, NULL); WideCharToMultiByte(CP_ACP, 0, pszDecompressFolder, -1, szDecompressFolder, sizeof(szDecompressFolder), NULL, NULL); char *pszFiles = NULL; if(pszFileNames != NULL) { pszFiles = (char*)malloc(lstrlen(pszFileNames)+1); if (pszFiles == NULL) { return FALSE; } WideCharToMultiByte(CP_ACP, 0, pszFileNames, -1, pszFiles, lstrlen(pszFileNames)+1, NULL, NULL); } hr = ExtractFiles(szCabFile, szDecompressFolder, 0, pszFiles, 0, 0); free(pszFiles); #else
hr = ExtractFiles(pszCabFile, pszDecompressFolder, 0, pszFileNames, 0, 0); #endif
return SUCCEEDED(hr); }
/////////////////////////////////////////////////////////////////////////////
//
// ReplaceFileExtension
//
/////////////////////////////////////////////////////////////////////////////
BOOL ReplaceFileExtension( LPCTSTR pszPath, LPCTSTR pszNewExt, LPTSTR pszNewPathBuf, DWORD cchNewPathBuf) { LPCTSTR psz; HRESULT hr; DWORD cchPath, cchExt, cch;
if (pszPath == NULL || *pszPath == _T('\0')) return FALSE;
cchPath = lstrlen(pszPath);
// note that only a '>' comparison is needed since the file extension
// should never start at the 1st char in the path.
for (psz = pszPath + cchPath; psz > pszPath && *psz != _T('\\') && *psz != _T('.'); psz--); if (*psz == _T('\\')) psz = pszPath + cchPath; else if (psz == pszPath) return FALSE;
// ok, so now psz points to the place where the new extension is going to
// go. Make sure our buffer is big enough.
cchPath = (DWORD)(psz - pszPath); cchExt = lstrlen(pszNewExt); if (cchPath + cchExt >= cchNewPathBuf) return FALSE;
// yay. we got a big enuf buffer.
hr = StringCchCopyEx(pszNewPathBuf, cchNewPathBuf, pszPath, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) return FALSE; hr = StringCchCopyEx(pszNewPathBuf + cchPath, cchNewPathBuf - cchPath, pszNewExt, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) return FALSE;
return TRUE; }
/////////////////////////////////////////////////////////////////////////////
//
// ReplaceFileInPath
//
/////////////////////////////////////////////////////////////////////////////
BOOL ReplaceFileInPath(LPCTSTR pszPath, LPCTSTR pszNewFile, LPTSTR pszNewPathBuf, DWORD cchNewPathBuf) { LPCTSTR psz; HRESULT hr; DWORD cchPath, cchFile, cch;
if (pszPath == NULL || *pszPath == _T('\0')) return FALSE;
cchPath = lstrlen(pszPath);
// note that only the '>=' comparison is safe cuz we check if pszPath is
// NULL above, so there should always be at least one value < pszPath
for (psz = pszPath + cchPath; psz >= pszPath && *psz != _T('\\'); psz--);
// either way we break out of the loop, gotta increment the pointer to
// be either the first char in the string or the first char after the
// last backslash
psz++;
// ok, so now psz points to the place where the new filename is going to
// go. Make sure our buffer is big enough.
cchPath = (DWORD)(psz - pszPath); cchFile = lstrlen(pszNewFile); if (cchPath + cchFile >= cchNewPathBuf) return FALSE; // yay. we got a big enuf buffer.
if (cchPath > 0) { hr = StringCchCopyEx(pszNewPathBuf, cchNewPathBuf, pszPath, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) return FALSE; } hr = StringCchCopyEx(pszNewPathBuf + cchPath, cchNewPathBuf - cchPath, pszNewFile, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) return FALSE;
return TRUE; }
// ----------------------------------------------------------------------------------
//
// VerifyFileCRC : This function takes a File Path, calculates the hash on this file
// and compares it to the passed in Hash (pCRC).
// Returns:
// S_OK: CRC's Match
// ERROR_CRC (HRESULT_FROM_WIN32(ERROR_CRC): if the CRC's do not match
// Otherwise an HRESULT Error Code
//
// ----------------------------------------------------------------------------------
HRESULT VerifyFileCRC(LPCTSTR pszFileToVerify, LPCTSTR pszHash) { HRESULT hr = S_OK; TCHAR szCompareCRC[CRC_HASH_STRING_LENGTH]; // Validate Parameters
if ((NULL == pszFileToVerify) || (NULL == pszHash)) return E_INVALIDARG;
hr = CalculateFileCRC(pszFileToVerify, szCompareCRC, ARRAYSIZE(szCompareCRC)); if (FAILED(hr)) return hr;
// Now we need to Compare the Calculated CRC with the Passed in CRC
if (0 == lstrcmpi(szCompareCRC, pszHash)) return S_OK; // CRC's Match
else return HRESULT_FROM_WIN32(ERROR_CRC); // CRC's do not match
}
// ----------------------------------------------------------------------------------
//
// CalculateFileCRC : This function takes a File Path, calculates a CRC from the file
// converts it to a string and returns it in the supplied TCHAR buffer
//
// ----------------------------------------------------------------------------------
typedef BOOL (WINAPI * PFN_CryptCATAdminCalcHashFromFileHandle)(HANDLE hFile, DWORD *pcbHash, BYTE *pbHash, DWORD dwFlags);
HRESULT CalculateFileCRC(LPCTSTR pszFileToHash, LPTSTR pszHash, int cchBuf) { HANDLE hFile; HRESULT hr = S_OK; DWORD cbHash = CRC_HASH_SIZE; BYTE bHashBytes[CRC_HASH_SIZE]; BYTE b;
// Validate Parameters
if ((NULL == pszFileToHash) || (NULL == pszHash) || (cchBuf < CRC_HASH_STRING_LENGTH)) return E_INVALIDARG;
hFile = CreateFile(pszFileToHash, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { HMODULE hWinTrust = LoadLibraryFromSystemDir(_T("wintrust.dll")); if (NULL == hWinTrust) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { PFN_CryptCATAdminCalcHashFromFileHandle fpnCryptCATAdminCalcHashFromFileHandle = NULL; fpnCryptCATAdminCalcHashFromFileHandle = (PFN_CryptCATAdminCalcHashFromFileHandle) GetProcAddress(hWinTrust, "CryptCATAdminCalcHashFromFileHandle"); if (NULL == fpnCryptCATAdminCalcHashFromFileHandle) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { if (!fpnCryptCATAdminCalcHashFromFileHandle(hFile, &cbHash, bHashBytes, 0)) { hr = HRESULT_FROM_WIN32(GetLastError()); } fpnCryptCATAdminCalcHashFromFileHandle = NULL; } FreeLibrary(hWinTrust); } CloseHandle(hFile); } else { hr = HRESULT_FROM_WIN32(GetLastError()); }
if (FAILED(hr)) return hr;
LPTSTR p = pszHash;
// Now we have the Calculated CRC of the File, we need to convert it to a String and Return it. The following
// loop will go through each byte in the array and convert it to a Hex Character in the supplied TCHAR buffer
for (int i = 0; i < CRC_HASH_SIZE; i++) { b = bHashBytes[i] >> 4; if (b <= 9) *p = '0' + (TCHAR)b; else *p = 'A' + (TCHAR)(b - 10); p++;
b = bHashBytes[i] & 0x0F; if (b <= 9) *p = '0' + (TCHAR)b; else *p = 'A' + (TCHAR)(b - 10); p++; } *p = _T('\0'); return hr; }
|