|
|
////////////////////////////////////////////////////////////////////////////////
///
///
/// MPSMisc.C
///
/// Microsoft Property Store - WAB Dll - miscellaneous helper functions
///
/// binSearchStr
/// binSearchEID
/// LoadIndex
/// SizeOfSinglePropData
/// SizeOfMultiPropData
/// UnlockFileAccess
/// LockFileAccess
/// LocalFreePropArray
/// FreePcontentlist
/// ReadRecordWithoutLocking
/// GetWABBackupFileName
/// CopySrcFileToDestFile
/// bIsValidRecord
/// TagWABFileError
/// ReloadMPSWabFileInfo
///
/// CreateMPSWabFile
/// CompressFile
/// HrDoQuickWABIntegrityCheck
/// HrResetWABFileContents
/// HrRestoreFromBackup
/// HrDoDetailedWABIntegrityCheck
/////////////////////////////////////////////////////////////////////////////////
#include "_apipch.h"
extern BOOL fTrace; // Set TRUE if you want debug traces
extern BOOL fDebugTrap; // Set TRUE to get int3's
extern TCHAR szDebugOutputFile[MAX_PATH]; // the name of the debug output file
extern BOOL SubstringSearch(LPTSTR pszTarget, LPTSTR pszSearch);
BOOL CopySrcFileToDestFile(HANDLE hSrc, ULONG ulSrcStartOffset, HANDLE hDest,ULONG ulDestStartOffset);
//$$////////////////////////////////////////////////////////////////////////////
//
// Gets us a WAB specific temp file name to play with
//
//
////////////////////////////////////////////////////////////////////////////////
void GetWABTempFileName(LPTSTR szFileName) { TCHAR szBuf[MAX_PATH]; TCHAR szBufPath[MAX_PATH]; szBufPath[0]='\0'; GetTempPath(MAX_PATH,szBufPath); LoadString(hinstMapiX, IDS_WAB_TEMP_FILE_PREFIX, szBuf, CharSizeOf(szBuf)); GetTempFileName(szBufPath, /* dir. for temp. files */ szBuf, //"MPS", /* temp. filename prefix */
0, /* create unique name w/ sys. time */ (LPTSTR) szFileName); /* buffer for name */
return; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// BOOL binSearchStr - binary search routine for scanning string indexes
//
// IN struct _tagIndexOffset * Index - Index Array to Search in
// IN LPTSTR lpszValue - value to search for
// IN ULONG nArraySize - number of elements in array
// OUT ULONG lpulMatchIndex - array index of matched item
//
// Returns:
// Nothing found: FALSE - lpulMatchIndex contains array position at which this entry
// this entry would hypothetically exist, were it a part of the array
// Match found: TRUE - lpulMatchIndex contains array position of matched entry
//
// Comments:
// Algorithm from "Data Structures" by Reingold & Hansen, pg. 278.
//
////////////////////////////////////////////////////////////////////////////////////
BOOL BinSearchStr( IN struct _tagMPSWabIndexEntryDataString * lpIndexStr, IN LPTSTR lpszValue, //used for searching strings
IN ULONG nArraySize, OUT ULONG * lpulMatchIndex) { LONG low = 0; LONG high = nArraySize - 1; LONG mid = (low + high) / 2; int comp = 0; BOOL bRet = FALSE;
*lpulMatchIndex = 0;
if (nArraySize == 0) return FALSE;
while (low <= high && ! bRet) { mid = (low + high) / 2; comp = lstrcmpi(lpIndexStr[mid].szIndex, lpszValue); if (comp < 0) { low = mid + 1; } else if (comp > 0) { high = mid - 1; } else { bRet = TRUE; } }
// Calculate found or insert position
(ULONG)*lpulMatchIndex = bRet ? mid : low;
// DebugTrace(TEXT("\tBinSearchSTR: Exit\n"));
return bRet; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// BOOL binSearchEID - binary search routine for scanning EntryID index
//
// IN lpIndexEID - Index Array to Search in
// IN LPTSTR dwValue - value to search for
// IN ULONG nArraySize - number of elements in array
// OUT ULONG lpulMatchIndex - array index of matched item
//
// Returns:
// Nothing found: FALSE - lpulMatchIndex contains array position at which this entry
// this entry would hypothetically exist, were it a part of the array
// Match found: TRUE - lpulMatchIndex contains array position of matched entry
//
////////////////////////////////////////////////////////////////////////////////////
BOOL BinSearchEID( IN struct _tagMPSWabIndexEntryDataEntryID * lpIndexEID, IN DWORD dwValue, //used for comparing DWORDs
IN ULONG nArraySize, OUT ULONG * lpulMatchIndex) { LONG low = 0; LONG high = nArraySize - 1; LONG mid = (low + high) / 2; BOOL bRet = FALSE;
*lpulMatchIndex = 0;
// The special cases for this algorithm are
// nArraySize == 0
if (nArraySize == 0) return FALSE;
while (low <= high && ! bRet) { mid = (low + high) / 2;
if (lpIndexEID[mid].dwEntryID < dwValue) low = mid+1; else if (lpIndexEID[mid].dwEntryID > dwValue) high = mid - 1; else //equal
bRet = TRUE; }
// Calculate found or insert position
(ULONG)*lpulMatchIndex = bRet ? mid : low;
return bRet; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// CreateMPSWabFile
//
// Internal function for creating the MPS Wab File - called from several places
//
// IN ulcMaxEntries - this number determines how much space we put aside for
// the indexes when we create the file. From time to time
// we will need to grow the file so we can call this CreateFile
// function to create the new file with the new size...
//
////////////////////////////////////////////////////////////////////////////////////
BOOL CreateMPSWabFile(IN struct _tagMPSWabFileHeader * lpMPSWabFileHeader, IN LPTSTR lpszFileName, IN ULONG ulcMaxEntries, IN ULONG ulNamedPropSize) {
HRESULT hr = E_FAIL; HANDLE hMPSWabFile = NULL; DWORD dwNumofBytesWritten; LPVOID lpszBuffer = NULL; int i = 0;
DebugTrace(TEXT("\tCreateMPSWabFile: Entry\n"));
//
// Create the file - its assumed that calling function has worked out all the
// logic for whether or not old file should be left alone or not.
//
hMPSWabFile = CreateFile( lpszFileName, GENERIC_WRITE, 0, (LPSECURITY_ATTRIBUTES) NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);
if (hMPSWabFile == INVALID_HANDLE_VALUE) { DebugPrintError(( TEXT("Could not create file.\nExiting ...\n"))); goto out; }
lpMPSWabFileHeader->ulModificationCount = 0; lpMPSWabFileHeader->MPSWabGuid = MPSWab_GUID; lpMPSWabFileHeader->ulcNumEntries = 0; lpMPSWabFileHeader->ulcMaxNumEntries = ulcMaxEntries; lpMPSWabFileHeader->ulFlags = WAB_CLEAR; lpMPSWabFileHeader->ulReserved1 = 0; lpMPSWabFileHeader->ulReserved2 = 0; lpMPSWabFileHeader->ulReserved3 = 0; lpMPSWabFileHeader->ulReserved4 = 0; lpMPSWabFileHeader->dwNextEntryID = 1;
// We will squeeze in the space to save the named property data betweeen th
// File header and the First Index
lpMPSWabFileHeader->NamedPropData.ulOffset = sizeof(MPSWab_FILE_HEADER); lpMPSWabFileHeader->NamedPropData.UtilizedBlockSize = 0; lpMPSWabFileHeader->NamedPropData.ulcNumEntries = 0; lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize = ulNamedPropSize;
// its important that this order matches TEXT("enum _IndexType") in mpswab.h
// or we'll have major read-write problems
for(i=0;i<indexMax;i++) {
lpMPSWabFileHeader->IndexData[i].UtilizedBlockSize = 0; lpMPSWabFileHeader->IndexData[i].ulcNumEntries = 0; if(i==indexEntryID) { lpMPSWabFileHeader->IndexData[i].ulOffset = lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize + lpMPSWabFileHeader->NamedPropData.ulOffset; lpMPSWabFileHeader->IndexData[i].AllocatedBlockSize = ulcMaxEntries * sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID); } else { lpMPSWabFileHeader->IndexData[i].ulOffset = lpMPSWabFileHeader->IndexData[i-1].ulOffset + lpMPSWabFileHeader->IndexData[i-1].AllocatedBlockSize; lpMPSWabFileHeader->IndexData[i].AllocatedBlockSize = ulcMaxEntries * sizeof(MPSWab_INDEX_ENTRY_DATA_STRING); } }
//Now we write this dummy structure to the file
if(!WriteFile( hMPSWabFile, (LPCVOID) lpMPSWabFileHeader, (DWORD) sizeof(MPSWab_FILE_HEADER), &dwNumofBytesWritten, NULL)) { DebugPrintError(( TEXT("Writing FileHeader failed.\n"))); goto out; }
//Assuming that the entryid index is always smaller than the display name index
// allocate enough empty space for a display name index and
lpszBuffer = LocalAlloc(LMEM_ZEROINIT, lpMPSWabFileHeader->IndexData[indexDisplayName].AllocatedBlockSize); if(!lpszBuffer) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
// Write the dummy blank Named Prop data into the file
// (this ensures that there are all zeros in the blank space)
// Assumes that the NamedPropData will be less than the index space
if(!WriteFile( hMPSWabFile, (LPCVOID) lpszBuffer, (DWORD) lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize, &dwNumofBytesWritten, NULL)) { DebugPrintError(( TEXT("Writing Index No. %d failed.\n"),i)); goto out; }
for (i=0;i<indexMax;i++) { if(!WriteFile( hMPSWabFile, (LPCVOID) lpszBuffer, (DWORD) lpMPSWabFileHeader->IndexData[i].AllocatedBlockSize, &dwNumofBytesWritten, NULL)) { DebugPrintError(( TEXT("Writing Index No. %d failed.\n"),i)); goto out; } }
LocalFreeAndNull(&lpszBuffer);
IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);) hMPSWabFile = NULL;
hr = S_OK;
out: LocalFreeAndNull(&lpszBuffer);
DebugTrace(TEXT("\tCreateMPSWabFile: Exit\n"));
return( (FAILED(hr)) ? FALSE : TRUE);
}
//$$//////////////////////////////////////////////////////////////////////////////////
//
// LoadIndex - Only one of the string indexes is loaded at any given time
// If we need some other index in memory, we have to reload it from the file ...
//
// This assumes that the ulcNumEntries and UtilizedBlockData for each index in the file header is up to date
// because that value is used to allocate memory for the index
//
// We use this function as a generic load index function too
//
//
////////////////////////////////////////////////////////////////////////////////////
BOOL LoadIndex( IN struct _tagMPSWabFileInfo * lpMPSWabFileInfo, IN ULONG nIndexType, IN HANDLE hMPSWabFile) { BOOL bRet = FALSE; DWORD dwNumofBytes = 0;
// DebugTrace(TEXT("\tLoadIndex: Entry\n"));
if (!lpMPSWabFileInfo) goto out;
if (lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries==0) //assumes this is an accurate value
{ LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexEID); LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexStr);
bRet = TRUE; goto out; }
//otherwise we have to reload the index from file
//
//First free the existing index
//
if (nIndexType == indexEntryID) { LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexEID); } else { LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexStr); }
//Load the index into memory
if(0xFFFFFFFF == SetFilePointer ( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].ulOffset, NULL, FILE_BEGIN)) { DebugPrintError(( TEXT("SetFilePointer Failed\n"))); goto out; }
if (nIndexType == indexEntryID) { lpMPSWabFileInfo->lpMPSWabIndexEID = LocalAlloc(LMEM_ZEROINIT, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].UtilizedBlockSize); if(!(lpMPSWabFileInfo->lpMPSWabIndexEID)) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; } if(!ReadFile( hMPSWabFile, (LPVOID) lpMPSWabFileInfo->lpMPSWabIndexEID, (DWORD) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].UtilizedBlockSize, &dwNumofBytes, NULL)) { DebugPrintError(( TEXT("Reading Index failed.\n"))); goto out; } } else { lpMPSWabFileInfo->lpMPSWabIndexStr = LocalAlloc(LMEM_ZEROINIT, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].UtilizedBlockSize); if(!(lpMPSWabFileInfo->lpMPSWabIndexStr)) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; } if(!ReadFile( hMPSWabFile, (LPVOID) lpMPSWabFileInfo->lpMPSWabIndexStr, (DWORD) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].UtilizedBlockSize, &dwNumofBytes, NULL)) { DebugPrintError(( TEXT("Reading Index failed.\n"))); goto out; } }
if (nIndexType != indexEntryID) lpMPSWabFileInfo->nCurrentlyLoadedStrIndexType = nIndexType;
bRet = TRUE;
out:
// DebugTrace(TEXT( TEXT("\tLoadIndex: Exit\n")));
return bRet; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// SizeOfSinglePropData - returns the number of bytes of data in a given SPropValue ...
//
//
////////////////////////////////////////////////////////////////////////////////////
ULONG SizeOfSinglePropData(SPropValue Prop) {
ULONG i = 0; ULONG ulDataSize = 0;
switch(PROP_TYPE(Prop.ulPropTag)) { case PT_I2: ulDataSize = sizeof(short int); break; case PT_LONG: ulDataSize = sizeof(LONG); break; case PT_R4: ulDataSize = sizeof(float); break; case PT_DOUBLE: ulDataSize = sizeof(double); break; case PT_BOOLEAN: ulDataSize = sizeof(unsigned short int); break; case PT_CURRENCY: ulDataSize = sizeof(CURRENCY); break; case PT_APPTIME: ulDataSize = sizeof(double); break; case PT_SYSTIME: ulDataSize = sizeof(FILETIME); break; case PT_STRING8: ulDataSize = lstrlenA(Prop.Value.lpszA)+1; break; case PT_UNICODE: ulDataSize = sizeof(TCHAR)*(lstrlenW(Prop.Value.lpszW)+1); break; case PT_BINARY: ulDataSize = Prop.Value.bin.cb; break; case PT_CLSID: ulDataSize = sizeof(GUID); break; case PT_I8: ulDataSize = sizeof(LARGE_INTEGER); break; case PT_ERROR: ulDataSize = sizeof(SCODE); break; case PT_NULL: ulDataSize = sizeof(LONG); break; }
return ulDataSize;
}
//$$//////////////////////////////////////////////////////////////////////////////////
//
// SizeOfMultiPropData - returns the number of bytes of data in a given SPropValue ...
//
//
////////////////////////////////////////////////////////////////////////////////////
ULONG SizeOfMultiPropData(SPropValue Prop) {
ULONG i = 0; ULONG ulDataSize = 0;
switch(PROP_TYPE(Prop.ulPropTag)) { case PT_MV_I2: ulDataSize = sizeof(short int) * Prop.Value.MVi.cValues; break; case PT_MV_LONG: ulDataSize = sizeof(LONG) * Prop.Value.MVl.cValues; break; case PT_MV_R4: ulDataSize = sizeof(float) * Prop.Value.MVflt.cValues; break; case PT_MV_DOUBLE: ulDataSize = sizeof(double) * Prop.Value.MVdbl.cValues; break; case PT_MV_CURRENCY: ulDataSize = sizeof(CURRENCY) * Prop.Value.MVcur.cValues; break; case PT_MV_APPTIME: ulDataSize = sizeof(double) * Prop.Value.MVat.cValues; break; case PT_MV_SYSTIME: ulDataSize = sizeof(FILETIME) * Prop.Value.MVft.cValues; break; case PT_MV_BINARY: ulDataSize = 0; // Note this data size includes, for each array entry, the sizeof(ULONG) that
// contains the actual datasize (i.e cb)
for(i=0;i<Prop.Value.MVbin.cValues;i++) { ulDataSize += sizeof(ULONG) + Prop.Value.MVbin.lpbin[i].cb; } break; case PT_MV_STRING8: ulDataSize = 0; DebugTrace(TEXT("where the heck are we getting ANSI data from\n")); // Note this data size includes, for each array entry, the sizeof(ULONG) that
// contains the actual datasize (i.e cb)
for(i=0;i<Prop.Value.MVszA.cValues;i++) { // Note the strlen is incremented by '+1' to include the terminating NULL for
// each string
ulDataSize += sizeof(ULONG) + lstrlenA(Prop.Value.MVszA.lppszA[i])+1; } break; case PT_MV_UNICODE: ulDataSize = 0; // Note this data size includes, for each array entry, the sizeof(ULONG) that
// contains the actual datasize (i.e cb)
for(i=0;i<Prop.Value.MVszW.cValues;i++) { // Note the strlen is incremented by '+1' to include the terminating NULL for
// each string
ulDataSize += sizeof(ULONG) + sizeof(TCHAR)*(lstrlenW(Prop.Value.MVszW.lppszW[i])+1); } break; case PT_MV_CLSID: ulDataSize = sizeof(GUID) * Prop.Value.MVguid.cValues; break; case PT_MV_I8: ulDataSize = sizeof(LARGE_INTEGER) * Prop.Value.MVli.cValues; break; }
return ulDataSize;
}
//$$//////////////////////////////////////////////////////////////////////////////////
//
// ReloadMPSWabFileInfo - Reloads the MPSWabFileHeader and reloads the
// memory indexes. This is a performance hit but cant be helped since it
// is the most reliable way to ensure we are working with the latest
// valid information
//
// Thus a write by one program cannot mess up the read by another program
//
////////////////////////////////////////////////////////////////////////////////////
BOOL ReloadMPSWabFileInfo( IN struct _tagMPSWabFileInfo * lpMPSWabFileInfo, IN HANDLE hMPSWabFile) { BOOL bRet = TRUE; ULONG i = 0; DWORD dwNumofBytes = 0;
if(!ReadDataFromWABFile(hMPSWabFile, 0, (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries != lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries) lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
for(i=indexDisplayName;i<indexMax;i++) { if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries > lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries) lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED; }
if(lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) { if(!WriteFile( hMPSWabFile, (LPCVOID) lpMPSWabFileInfo->lpMPSWabFileHeader, (DWORD) sizeof(MPSWab_FILE_HEADER), &dwNumofBytes, NULL)) { DebugPrintError(( TEXT("Writing FileHeader failed.\n"))); goto out; }
}
//
// Get the Entry iD index
//
if (!LoadIndex( IN lpMPSWabFileInfo, IN indexEntryID, IN hMPSWabFile) ) { DebugPrintError(( TEXT("Error Loading EntryID Index!\n"))); goto out; }
//
// Get the current string index
//
if (!LoadIndex( IN lpMPSWabFileInfo, IN lpMPSWabFileInfo->nCurrentlyLoadedStrIndexType, IN hMPSWabFile) ) { DebugPrintError(( TEXT("Error Loading String Index!\n"))); goto out; }
bRet = TRUE;
out:
return bRet;
}
//$$//////////////////////////////////////////////////////////////////////////////////
//
// UnlockFileAccess - UnLocks Exclusive Access to the property store
//
////////////////////////////////////////////////////////////////////////////////////
BOOL UnLockFileAccess(LPMPSWab_FILE_INFO lpMPSWabFileInfo) { BOOL bRet = FALSE;
//DebugTrace(TEXT( TEXT("\t\tUnlockFileAccess\n")));
if(lpMPSWabFileInfo) { bRet = ReleaseMutex(lpMPSWabFileInfo->hDataAccessMutex); }
return bRet; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// LockFileAccess - Gives exclusive access to the Property Store
//
////////////////////////////////////////////////////////////////////////////////////
BOOL LockFileAccess(LPMPSWab_FILE_INFO lpMPSWabFileInfo) { BOOL bRet = FALSE; DWORD dwWait = 0;
//DebugTrace(TEXT( TEXT("\t\tLockFileAccess\n")));
if(lpMPSWabFileInfo) { dwWait = WaitForSingleObject(lpMPSWabFileInfo->hDataAccessMutex,MAX_LOCK_FILE_TIMEOUT);
if ((dwWait == WAIT_TIMEOUT) || (dwWait == WAIT_FAILED)) { DebugPrintError(( TEXT("Thread:%x\tWaitForSingleObject failed.\n"),GetCurrentThreadId())); bRet = FALSE; } else bRet = TRUE; }
return(bRet);
}
//$$//////////////////////////////////////////////////////////////////////////////////
//
// CompressFile - Creates a compressed version of the property store
// file that removes all the invlaid records.
//
// The compressiong function is very similar to creating a backup and hence
// the exported Backup function calls CompressFile. The difference being that
// in Backup, a new file is created with a new name and in CompressFile, the
// newfile is renamed to the property store
//
// Similarly, growing the file is very similar and the internal call to Growing
// the file calls CompressFile too
//
//
// IN lpMPSWabFileInfo
// IN lpsznewFileName - supplied by backup. if NULL, means that CompressFile
// should rename the new file as the property store
// IN BOOL bGrowFile - if specified, the new file is created with space for
// an additional MAX_INITIAL_INDEX_ENTRIES
// IN ULONG ulFlags - there are 2 things that can grow here - the index size and
// the named property storage size. Hence we have the following flags
// one or more of which can be used simultaneously
// AB_GROW_INDEX | AB_GROW_NAMEDPROP
//
// Returns
// Success: TRUE
// Failure: FALSE
//
////////////////////////////////////////////////////////////////////////////////////
BOOL CompressFile( IN struct _tagMPSWabFileInfo * lpMPSWabFileInfo, IN HANDLE hMPSWabFile, IN LPTSTR lpszFileName, IN BOOL bGrowFile, IN ULONG ulFlags) { BOOL bRet = FALSE; BOOL bBackup = FALSE; BOOL bRFileLocked = FALSE; BOOL bWFileLocked = FALSE; HANDLE hTempFile = NULL; struct _tagMPSWabFileHeader NewFileHeader = {0}; ULONG ulNewFileMaxEntries = 0; ULONG ulNamedPropSize = 0; DWORD dwNumofBytes = 0; struct _tagMPSWabIndexEntryDataString * lpIndexStr = NULL; struct _tagMPSWabIndexEntryDataEntryID NewMPSWabIndexEID; ULONG ulNewRecordOffset = 0; ULONG ulNewEIDIndexElementOffset = 0; ULONG i = 0; LPULONG lpPropTagArray = NULL; struct _tagMPSWabRecordHeader RecordHeader; LPVOID lpRecordData = NULL;
ULONG ulBytesLeftToCopy = 0; ULONG ulChunkSize = 8192; //copy 8k at a time
LPVOID lpv = NULL; TCHAR szFileName[MAX_PATH];
ULONG ulFileSize = 0;
DebugTrace(TEXT("----Thread:%x\tCompressFile: Entry\n"),GetCurrentThreadId());
// if this is a backup operation we first backup to a temp file and
// then rename the temp file to the backup - this way if the process
// fails we dont lose our last made backup ...
if (lpszFileName != NULL) { if (!lstrcmpi(lpszFileName,lpMPSWabFileInfo->lpszMPSWabFileName)) { DebugPrintError(( TEXT("Cannot backup a file over itself. Please specify new backup file name."))); goto out; } bBackup = TRUE; } else bBackup = FALSE;
GetWABTempFileName(szFileName);
// Find the least multiple of MAX_INITIAL_INDEX_ENTRIES that can accomodate the
// existing entries in the file and set ulNewFilMaxEntries to that number
ulNewFileMaxEntries = 0;
{ int j=0; for( j = (lpMPSWabFileInfo->lpMPSWabFileHeader->ulcMaxNumEntries/MAX_INITIAL_INDEX_ENTRIES);j >= 0; j--) { if (lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries >= (ULONG) j*MAX_INITIAL_INDEX_ENTRIES) { ulNewFileMaxEntries = (j+1)*MAX_INITIAL_INDEX_ENTRIES; break; } }
if (ulNewFileMaxEntries == 0) //this shouldnt happen
ulNewFileMaxEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->ulcMaxNumEntries;
ulNamedPropSize = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize; }
if (bGrowFile) { if(ulFlags & AB_GROW_INDEX) ulNewFileMaxEntries += MAX_INITIAL_INDEX_ENTRIES;
if(ulFlags & AB_GROW_NAMEDPROP) ulNamedPropSize += NAMEDPROP_STORE_INCREMENT_SIZE; }
if (!CreateMPSWabFile( IN &NewFileHeader, IN szFileName, IN ulNewFileMaxEntries, IN ulNamedPropSize)) { DebugPrintError(( TEXT("Could Not Create File %s!\n"),szFileName)); goto out; }
if (hMPSWabFile == INVALID_HANDLE_VALUE) { DebugPrintError(( TEXT("Could not open file.\nExiting ...\n"))); goto out; }
hTempFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, (HANDLE) NULL);
if (hTempFile == INVALID_HANDLE_VALUE) { DebugPrintError(( TEXT("Could not open file.\nExiting ...\n"))); goto out; }
ulFileSize = GetFileSize(hMPSWabFile, NULL);
NewFileHeader.ulcNumEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries; NewFileHeader.ulModificationCount = 0; NewFileHeader.dwNextEntryID = lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID; NewFileHeader.ulFlags = lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags;
NewFileHeader.NamedPropData.UtilizedBlockSize = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.UtilizedBlockSize; NewFileHeader.NamedPropData.ulcNumEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulcNumEntries;
NewFileHeader.ulReserved1 = lpMPSWabFileInfo->lpMPSWabFileHeader->ulReserved1; NewFileHeader.ulReserved2 = lpMPSWabFileInfo->lpMPSWabFileHeader->ulReserved2; NewFileHeader.ulReserved3 = lpMPSWabFileInfo->lpMPSWabFileHeader->ulReserved3; NewFileHeader.ulReserved4 = lpMPSWabFileInfo->lpMPSWabFileHeader->ulReserved4;
for(i=indexEntryID; i<indexMax; i++) { NewFileHeader.IndexData[i].UtilizedBlockSize = lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].UtilizedBlockSize; NewFileHeader.IndexData[i].ulcNumEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries; }
// write the header info
//
if(!WriteDataToWABFile( hTempFile, 0, (LPVOID) &NewFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
//
// Copy over Named Prop Data
//
{ lpv = NULL; lpv = LocalAlloc(LMEM_ZEROINIT, NewFileHeader.NamedPropData.UtilizedBlockSize); if(!lpv) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; }
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulOffset, NULL, FILE_BEGIN)) { DebugPrintError(( TEXT("SetFilePointer Failed\n"))); goto out; }
if (0xFFFFFFFF == SetFilePointer ( hTempFile, NewFileHeader.NamedPropData.ulOffset, NULL, FILE_BEGIN) ) { DebugPrintError(( TEXT("SetFilePointer Failed\n"))); goto out; }
if(!ReadFile(hMPSWabFile, (LPVOID) lpv, (DWORD) NewFileHeader.NamedPropData.UtilizedBlockSize, &dwNumofBytes, NULL) ) { DebugPrintError(( TEXT("read file failed.\n"))); goto out; }
if(!WriteFile( hTempFile, (LPCVOID) lpv, (DWORD) NewFileHeader.NamedPropData.UtilizedBlockSize, &dwNumofBytes, NULL)) { DebugPrintError(( TEXT("write file failed.\n"))); goto out; }
LocalFreeAndNull(&lpv);
} // Copy over named prop data
//
// Then copy over the string indexes
//
for(i=indexDisplayName; i<indexMax;i++) { LocalFreeAndNull(&lpIndexStr);
lpIndexStr = LocalAlloc(LMEM_ZEROINIT, NewFileHeader.IndexData[i].UtilizedBlockSize); if(!lpIndexStr) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; }
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulOffset, NULL, FILE_BEGIN)) { DebugPrintError(( TEXT("SetFilePointer Failed\n"))); goto out; }
if (0xFFFFFFFF == SetFilePointer ( hTempFile, NewFileHeader.IndexData[i].ulOffset, NULL, FILE_BEGIN) ) { DebugPrintError(( TEXT("SetFilePointer Failed\n"))); goto out; }
if(!ReadFile(hMPSWabFile, (LPVOID) lpIndexStr, (DWORD) NewFileHeader.IndexData[i].UtilizedBlockSize, &dwNumofBytes, NULL) ) { DebugPrintError(( TEXT("read file failed.\n"))); goto out; }
if(!WriteFile( hTempFile, (LPCVOID) lpIndexStr, (DWORD) NewFileHeader.IndexData[i].UtilizedBlockSize, &dwNumofBytes, NULL)) { DebugPrintError(( TEXT("write file failed.\n"))); goto out; }
LocalFreeAndNull(&lpIndexStr); }
//
// now load the entryid index from the old file
//
if (!LoadIndex( IN lpMPSWabFileInfo, IN indexEntryID, IN hMPSWabFile) ) { DebugPrintError(( TEXT("Error Loading EntryID Index!\n"))); goto out; }
ulNewRecordOffset = NewFileHeader.IndexData[indexMax - 1].ulOffset + NewFileHeader.IndexData[indexMax - 1].AllocatedBlockSize; ulNewEIDIndexElementOffset = NewFileHeader.IndexData[indexEntryID].ulOffset;
//
// Walk through the old file entry ID index reading the
// valid records one by one and writing them to the new file. Also write the
// new record offset and the new EID entry into the new file (so that if we
// crash we have as up to date data in the new file as possible
//
for(i=0;i<NewFileHeader.IndexData[indexEntryID].ulcNumEntries;i++) { NewMPSWabIndexEID.dwEntryID = lpMPSWabFileInfo->lpMPSWabIndexEID[i].dwEntryID; NewMPSWabIndexEID.ulOffset = ulNewRecordOffset;
if(!ReadDataFromWABFile(hMPSWabFile, lpMPSWabFileInfo->lpMPSWabIndexEID[i].ulOffset, (LPVOID) &RecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
// if for some reason this was an invalid record .. skip it and go to next
if(!bIsValidRecord( RecordHeader, lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID, lpMPSWabFileInfo->lpMPSWabIndexEID[i].ulOffset, ulFileSize)) continue;
LocalFreeAndNull(&lpPropTagArray);
lpPropTagArray = LocalAlloc(LMEM_ZEROINIT, RecordHeader.ulPropTagArraySize); if(!lpPropTagArray) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; }
if(!ReadFile( hMPSWabFile, (LPVOID) lpPropTagArray, (DWORD) RecordHeader.ulPropTagArraySize, &dwNumofBytes, NULL)) { DebugPrintError(( TEXT("read file failed.\n"))); goto out; }
LocalFreeAndNull(&lpRecordData);
lpRecordData = LocalAlloc(LMEM_ZEROINIT, RecordHeader.ulRecordDataSize); if(!lpRecordData) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; }
if(!ReadFile( hMPSWabFile, (LPVOID) lpRecordData, (DWORD) RecordHeader.ulRecordDataSize, &dwNumofBytes, NULL)) { DebugPrintError(( TEXT("read file failed.\n"))); goto out; }
if(!WriteDataToWABFile(hTempFile, ulNewRecordOffset, (LPVOID) &RecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
// assumes that file pointer will be at the correct spot
if(!WriteFile( hTempFile, (LPCVOID) lpPropTagArray, (DWORD) RecordHeader.ulPropTagArraySize, &dwNumofBytes, NULL)) { DebugPrintError(( TEXT("write file failed.\n"))); goto out; }
// assumes that file pointer will be at the correct spot
if(!WriteFile( hTempFile, (LPCVOID) lpRecordData, (DWORD) RecordHeader.ulRecordDataSize, &dwNumofBytes, NULL)) { DebugPrintError(( TEXT("write file failed.\n"))); goto out; }
ulNewRecordOffset += sizeof(MPSWab_RECORD_HEADER) + RecordHeader.ulPropTagArraySize + RecordHeader.ulRecordDataSize;
LocalFreeAndNull(&lpPropTagArray); LocalFreeAndNull(&lpRecordData);
//
// Write the new entryID index element
//
if(!WriteDataToWABFile( hTempFile, ulNewEIDIndexElementOffset, (LPVOID) &NewMPSWabIndexEID, sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID))) goto out;
ulNewEIDIndexElementOffset += sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID);
// loop for next record
}
//
// At this point in the process we have successfuly copied over all the
// records from the old file to the new file
//
// If this is a backup operation - we delete the old backup and copy the new temp file
// as the new backup ...
//
// If this is not a backup operation, we want to basically delete the old file
// and rename the new temp file as the property store ..
//
// However, if we release our access to the property store, there is no gaurentee that
// some other process will not grab up exclusive access to the store and we will fail in
// our attempt to gain control and modify ...
//
// Hence the options are
// (a) give up control and then hope we can regain control before someone else does something
// to the file
// (b) copy in the new file contents and overwrite the existing file contents - this is going
// to be slower than rewriting the file but it will give us exclusive control on the
// modifications and makes the process much more robust ...
//
if (!bBackup) // Not a backup operation
{ //
// Save the header in the new file
//
if(!WriteDataToWABFile( hTempFile, 0, (LPVOID) &NewFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
//
// Copy the New file into this WAB file thus replacing the old contents
// and hope this never fails
//
if(!CopySrcFileToDestFile(hTempFile, 0, hMPSWabFile, 0)) { DebugPrintError(( TEXT("Unable to copy files\n"))); goto out; }
//
// Reload this so we have the new fileheader info in our structures
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugPrintError(( TEXT("Reading file info failed.\n"))); goto out; }
//
// Thats it .. we can close the files and party on ..
//
} else { //this is a backup operation ...
// Close the temp file
if (hTempFile) { IF_WIN32(CloseHandle(hTempFile);) IF_WIN16(CloseFile(hTempFile);) hTempFile = NULL; }
if(!CopyFile( szFileName, lpszFileName, FALSE)) { DebugPrintError(( TEXT("CopyFile %s to %s failed: %d\n"),szFileName,lpszFileName, GetLastError())); goto out; } }
bRet = TRUE;
out:
if (hTempFile) IF_WIN32(CloseHandle(hTempFile);) IF_WIN16(CloseFile(hTempFile);)
if( szFileName != NULL) DeleteFile(szFileName);
LocalFreeAndNull(&lpv);
LocalFreeAndNull(&lpPropTagArray);
LocalFreeAndNull(&lpRecordData);
DebugTrace(TEXT("----Thread:%x\tCompressFile: Exit\n"),GetCurrentThreadId());
return bRet; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// ReadRecordWithoutLocking
//
// IN lpMPSWabFileInfo
// IN dwEntryID - EntryID of record to read
// OUT ulcPropCount - number of props returned
// OUT lpPropArray - Array of Property values
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT ReadRecordWithoutLocking( IN HANDLE hMPSWabFile, IN struct _tagMPSWabFileInfo * lpMPSWabFileInfo, IN DWORD dwEntryID, OUT LPULONG lpulcPropCount, OUT LPPROPERTY_ARRAY * lppPropArray) { HRESULT hr = E_FAIL; ULONG ulRecordOffset = 0; BOOL bErrorDetected = FALSE; ULONG nIndexPos = 0; ULONG ulObjType = 0;
*lpulcPropCount = 0; *lppPropArray = NULL;
//
// First check if this is a valid entryID
//
if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID, IN dwEntryID, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, OUT &nIndexPos)) { DebugPrintError(( TEXT("Specified EntryID doesnt exist!\n"))); hr = MAPI_E_INVALID_ENTRYID; goto out; }
//if entryid exists, we can start reading the record
ulRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset;
hr = HrGetPropArrayFromFileRecord(hMPSWabFile, ulRecordOffset, &bErrorDetected, &ulObjType, NULL, lpulcPropCount, lppPropArray);
if(!HR_FAILED(hr)) { // reset the backward compatibility thing-um-a-jig we did between
// MAPI_ABCONT and MAPI_MAILUSER
if(ulObjType == RECORD_CONTAINER) SetContainerObjectType(*lpulcPropCount, *lppPropArray, FALSE); }
out:
//a little cleanup on failure
if (FAILED(hr)) { if(bErrorDetected) { TagWABFileError(lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile); }
if ((*lppPropArray) && (*lpulcPropCount > 0)) { LocalFreePropArray(NULL, *lpulcPropCount, lppPropArray); *lppPropArray = NULL; } }
return(hr); }
//$$//////////////////////////////////////////////////////////////////////////////
//
// GetWABBackupFileName - derives the backup file name from the WAB file by changing
// the extension from WAB to BWB
//
// lpszWabFileName - WAB file name
// lpszBackupFileName - Backup File name - points to a preallocated buffer big enough to
// hold the backup file name
//
// This generates a backup name in which the last character is turned into a ~
////////////////////////////////////////////////////////////////////////////////////
void GetWABBackupFileName(LPTSTR lpszWab, LPTSTR lpszBackup, ULONG cchBackup) { ULONG nLen;
if(!lpszWab || !lpszBackup) goto out;
nLen = lstrlen(lpszWab);
// if((nLen < 4) || (lpszWab[nLen-4] != '.'))
// goto out;
StrCpyN(lpszBackup,lpszWab, cchBackup);
lpszBackup[nLen-1]='\0';
StrCpyN(lpszBackup,TEXT("~"), cchBackup);
out:
return; }
//$$//////////////////////////////////////////////////////////////////////////////
//
// HrDoQuickWABIntegrityCheck - does a quick integrity check of the WAB indexes
// Verifies that:
//
// - Indexes contain the correct number of entries which is equal to or less than
// the max number of entries
// - Indexes dont contain duplicate entry-ids
// - Indexes point to valid and existing data ...
//
// If there are problems, this function attempts to fix them - if it cant fix them
// we fail and caller should call HrDoDetailedWABIntegrityCheck which will rebuild
// the indexes from the actual WAB data.
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrDoQuickWABIntegrityCheck(LPMPSWab_FILE_INFO lpMPSWabFileInfo, HANDLE hMPSWabFile) { HRESULT hr = E_FAIL; BOOL bError = FALSE; ULONG ulcNumWABEntries = 0,ulcNumIndexEntries = 0; LPMPSWab_FILE_HEADER lpMPSWabFileHeader = NULL; MPSWab_RECORD_HEADER MPSWabRecordHeader = {0}; ULONG i=0,j=0; DWORD dwNumofBytes = 0; ULONG ulFileSize = GetFileSize(hMPSWabFile,NULL);
lpMPSWabFileHeader = lpMPSWabFileInfo->lpMPSWabFileHeader; ulcNumWABEntries = lpMPSWabFileHeader->ulcNumEntries;
//
// First check the EntryID index
//
if (!LoadIndex( IN lpMPSWabFileInfo, IN indexEntryID, IN hMPSWabFile) ) { DebugPrintError(( TEXT("Error Loading Index!\n"))); goto out; }
ulcNumIndexEntries = lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries;
if(ulcNumIndexEntries != ulcNumWABEntries) { hr = MAPI_E_INVALID_ENTRYID; DebugPrintError(( TEXT("EntryID index has incorrect number of elements\n"))); goto out; }
if(ulcNumIndexEntries > 0) { for(i=0;i<ulcNumIndexEntries-1;i++) { // Since this is a sorted array, the indexes will be in sorted order
// So we just compare one with the next
if(lpMPSWabFileInfo->lpMPSWabIndexEID[i].dwEntryID == lpMPSWabFileInfo->lpMPSWabIndexEID[i+1].dwEntryID) { hr = MAPI_E_INVALID_ENTRYID; DebugPrintError(( TEXT("EntryID index has duplicate elements\n"))); goto out; } } }
/*
// This is painfully slowing things down
// Comment out for now
//
// Now we walk through the index and verify that each entry is a valid entry ....
for(i=0;i<ulcNumIndexEntries;i++) { ULONG ulOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[i].ulOffset;
MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
if(!ReadDataFromWABFile(hMPSWabFile, ulOffset, (LPVOID) &MPSWabRecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
if(!bIsValidRecord( MPSWabRecordHeader, lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID, ulOffset, ulFileSize)) { DebugPrintError(( TEXT("Index points to an invalid record\n"))); hr = MAPI_E_INVALID_ENTRYID; goto out; }
} */
// if we're here, then the entry id index checks out ok ...
//
// Check out the other indexes also ... we will start backwards since we want to fix potential
// problems in the First/Last name indexes before we do the more stringent display name case
//
for(j=indexMax-1;j>=indexDisplayName;j--) { if (!LoadIndex( IN lpMPSWabFileInfo, IN j, IN hMPSWabFile) ) { DebugPrintError(( TEXT("Error Loading Index!\n"))); goto out; }
ulcNumIndexEntries = lpMPSWabFileHeader->IndexData[j].ulcNumEntries;
if(j == indexDisplayName) { if(ulcNumIndexEntries != ulcNumWABEntries) { DebugPrintError(( TEXT("Display Name index has incorrect number of elements\n"))); goto out; } } else if(ulcNumIndexEntries > ulcNumWABEntries) { bError = TRUE; goto endloop; }
if(ulcNumIndexEntries > 0) { for(i=0;i<ulcNumIndexEntries-1;i++) { // Since this is a sorted array, the indexes will be in sorted order
// So we just compare one with the next
if(lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID == lpMPSWabFileInfo->lpMPSWabIndexStr[i+1].dwEntryID) { DebugPrintError(( TEXT("String index has duplicate elements\n"))); if(j == indexDisplayName) goto out; else { bError = TRUE; goto endloop; } } } }
// Now we walk through the index and verify that each entry is a valid entry ....
for(i=0;i<ulcNumIndexEntries;i++) { DWORD dwEntryID = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID; ULONG nIndexPos;
// All we need to do is to check that the entry id exists in the EntryID index since we
// have already verified the entryid index
if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID, IN dwEntryID, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, //IndexEntries,
OUT &nIndexPos)) { DebugPrintError(( TEXT("Specified EntryID: %d doesnt exist!\n"),dwEntryID)); hr = MAPI_E_NOT_FOUND; if(j == indexDisplayName) goto out; else { bError = TRUE; goto endloop; } }
}
endloop: if(bError && ( (j==indexFirstName) || (j==indexLastName) )) { // if the problem is in the first/last indexes, we can reset these indexes safely
//Assert(FALSE);
ulcNumIndexEntries = 0; lpMPSWabFileHeader->IndexData[j].ulcNumEntries = 0; lpMPSWabFileHeader->IndexData[j].ulcNumEntries = 0;
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
}
}
hr = hrSuccess;
out:
return hr; }
//$$///////////////////////////////////////////////////////////////////////////////////////////
//
// CopySrcFileToDestFile - replaces contents of Dest file with contents of source file
// starting at the ulsrcStartOffset and ulDestStartOffset respectively
// hSrc, hDest - handles to already open files
// ulSrcStartOffset - start copying from this offset
// ulDestStartOffset - start copying to this offset
//
//////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CopySrcFileToDestFile(HANDLE hSrc, ULONG ulSrcStartOffset, HANDLE hDest,ULONG ulDestStartOffset) { BOOL bRet = FALSE; ULONG ulBytesLeftToCopy = 0; DWORD dwNumofBytes = 0; ULONG ulChunkSize = 8192; //size of block of bytes to copy from one file into the other
LPVOID lpv = NULL;
// copy contents of hSrc into hDest
//
// Set the hDest File to 0 length
//
if (0xFFFFFFFF == SetFilePointer ( hDest, ulDestStartOffset, NULL, FILE_BEGIN)) { DebugPrintError(( TEXT("SetFilePointer Failed\n"))); goto out; }
//
// Set end of file to the current file pointer position to discard everything
// in the file after this point
//
if (!SetEndOfFile(hDest)) { DebugPrintError(( TEXT("SetEndofFile Failed\n"))); goto out; }
//
// Go to beginning of the source File
//
if (0xFFFFFFFF == SetFilePointer( hSrc, ulSrcStartOffset, NULL, FILE_BEGIN)) { DebugPrintError(( TEXT("SetFilePointer Failed\n"))); goto out; }
//
// figure out how many bytes to read ...
//
ulBytesLeftToCopy = GetFileSize(hSrc, NULL);
if (0xFFFFFFFF == ulBytesLeftToCopy) { DebugPrintError(( TEXT("GetFileSize Failed: %d\n"),GetLastError())); goto out; }
if(ulSrcStartOffset > ulBytesLeftToCopy) { DebugPrintError(( TEXT("Error in File Sizes\n"))); goto out; }
ulBytesLeftToCopy -= ulSrcStartOffset;
lpv = LocalAlloc(LMEM_ZEROINIT, ulChunkSize);
if(!lpv) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; }
//
// Loop copying bytes from one file to the other
while(ulBytesLeftToCopy > 0) { if (ulBytesLeftToCopy < ulChunkSize) ulChunkSize = ulBytesLeftToCopy;
if(!ReadFile(hSrc,(LPVOID) lpv,(DWORD) ulChunkSize,&dwNumofBytes,NULL)) { DebugPrintError(( TEXT("Read file failed.\n"))); goto out; }
if (dwNumofBytes != ulChunkSize) { DebugPrintError(( TEXT("Read file failed.\n"))); goto out; }
if(!WriteFile(hDest,(LPVOID) lpv,(DWORD) ulChunkSize,&dwNumofBytes,NULL)) { DebugPrintError(( TEXT("Write file failed.\n"))); goto out; }
if (dwNumofBytes != ulChunkSize) { DebugPrintError(( TEXT("Write file failed.\n"))); goto out; }
ulBytesLeftToCopy -= ulChunkSize;
}
bRet = TRUE;
out:
LocalFreeAndNull(&lpv);
return bRet; }
//$$//////////////////////////////////////////////////////////////////////////////
//
// HrResetWABFileContents - This is called as a last ditch error recovery attempt at
// deleting the file and reseting its contents in the event that a recovery from
// backup also failed...
//
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrResetWABFileContents(LPMPSWab_FILE_INFO lpMPSWabFileInfo, HANDLE hMPSWabFile) { HRESULT hr = E_FAIL; TCHAR szFileName[MAX_PATH]; MPSWab_FILE_HEADER NewFileHeader; HANDLE hTempFile = NULL;
DebugTrace(TEXT("#####HrResetWABFileContents Entry\n"));
// Get a temporary file name ...
GetWABTempFileName(szFileName);
if (!CreateMPSWabFile( IN &NewFileHeader, IN szFileName, IN MAX_INITIAL_INDEX_ENTRIES, IN NAMEDPROP_STORE_SIZE)) { DebugTrace(TEXT("Could Not Create File %s!\n"),szFileName); goto out; }
hTempFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, (HANDLE) NULL);
if (hTempFile == INVALID_HANDLE_VALUE) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
if(!CopySrcFileToDestFile(hTempFile, 0, hMPSWabFile, 0)) { DebugTrace(TEXT("Unable to copy files\n")); goto out; }
//
// Reload this so we have the new fileheader info in our structures
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
hr = hrSuccess;
out:
if(HR_FAILED(hr)) { // This is totally unexpected and basically we couldnt even fix the file so tell
// the user to restart the application - meanwhile we will delete the file
ShowMessageBox(NULL, idsWABUnexpectedError, MB_ICONHAND | MB_OK); // Hope that no one comes and locks this file between the next 2 calls
IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);) hMPSWabFile = NULL; DeleteFile(lpMPSWabFileInfo->lpszMPSWabFileName); }
if(hTempFile) IF_WIN32(CloseHandle(hTempFile);) IF_WIN16(CloseFile(hTempFile);)
DebugTrace(TEXT("#####HrResetWABFileContents Exit\n"));
return hr;
}
//$$//////////////////////////////////////////////////////////////////////////////
//
// HrRestoreFromBackup - attempts to replace WAB file contents from contents of
// Backup file
//
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrRestoreFromBackup(LPMPSWab_FILE_INFO lpMPSWabFileInfo, HANDLE hMPSWabFile) { HRESULT hr = E_FAIL; HANDLE hBackupFile = NULL; TCHAR szBackupFileName[MAX_PATH]; HCURSOR hOldCursor = SetCursor(LoadCursor(NULL,IDC_WAIT));
// Steps to this process are:
// - Open Backup File
// - Reset contents of WABFile
// - Copy Backup into WAB
// - Close BackupFile
// - Reload WAB Indexes
DebugTrace(TEXT("+++++HrRestoreFromBackup Entry\n"));
// Get the backup file name
szBackupFileName[0]='\0'; GetWABBackupFileName(lpMPSWabFileInfo->lpszMPSWabFileName, szBackupFileName, ARRAYSIZE(szBackupFileName));
hBackupFile = CreateFile( szBackupFileName, GENERIC_READ, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, //FILE_FLAG_RANDOM_ACCESS,
(HANDLE) NULL);
if (hBackupFile == INVALID_HANDLE_VALUE) { DebugTrace(TEXT("Could not open backup file.\nExiting ...\n")); hr = MAPI_E_DISK_ERROR; goto out; }
if(!CopySrcFileToDestFile(hBackupFile, 0, hMPSWabFile, 0)) { DebugTrace(TEXT("Unable to copy files\n")); goto out; }
//
// Reload this so we have the new fileheader info in our structures
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
hr = hrSuccess;
out:
// close the backup file
if(hBackupFile) IF_WIN32(CloseHandle(hBackupFile);) IF_WIN16(CloseFile(hBackupFile);)
SetCursor(hOldCursor);
DebugTrace(TEXT("+++++HrRestoreFromBackup Exit\n"));
return hr; }
//$$//////////////////////////////////////////////////////////////////////////////
//
// HrDoDetailedWABIntegrityCheck - does a thorough integrity check
// This is triggered only when an index error was detected or if a write
// transaction failed.
//
// - We step through all the records validating them and their size data
// - From each valid record we create the sorted entryid index
// - From the sorted entryid index we read the records and create the
// - display name index and reset the first last name indexes for now
//
// This function should not fail but should try to recover from errors
// If this function fails we need to break out the backup of the wab file
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrDoDetailedWABIntegrityCheck(LPMPSWab_FILE_INFO lpMPSWabFileInfo, HANDLE hMPSWabFile) { HRESULT hr = E_FAIL; BOOL bEID = FALSE; ULONG ulcNumWABEntries = 0,ulcNumIndexEntries = 0; MPSWab_FILE_HEADER MPSWabFileHeader = {0}; MPSWab_FILE_HEADER NewMPSWabFileHeader = {0}; MPSWab_RECORD_HEADER MPSWabRecordHeader = {0}; ULONG i=0,j=0; DWORD dwNumofBytes = 0; DWORD dwEntryID = 0; ULONG ulcPropCount = 0; LPSPropValue lpPropArray = NULL;
ULONG ulRecordOffset = 0; ULONG ulFileSize = 0; ULONG ulcWABEntryCount = 0; ULONG nIndexPos = 0;
MPSWab_INDEX_ENTRY_DATA_ENTRYID MPSWabIndexEID = {0}; LPMPSWab_INDEX_ENTRY_DATA_ENTRYID lpIndexEID = NULL;
MPSWab_INDEX_ENTRY_DATA_STRING MPSWabIndexString = {0}; LPMPSWab_INDEX_ENTRY_DATA_STRING lpIndexString = NULL;
LPVOID lpTmp = NULL;
HCURSOR hOldCur = SetCursor(LoadCursor(NULL,IDC_WAIT));
DebugTrace(TEXT("---DoDetailedWABIntegrityCheck Entry\n")); //
// We will go with the assumption that this WAB is currently a proper wab file
// otherwise OpenPropertyStore would have failed while opening it.
//
// Consequently, we should be able to read the header of the file
// update the file header
if(!ReadDataFromWABFile(hMPSWabFile, 0, (LPVOID) &MPSWabFileHeader, (DWORD) sizeof(MPSWab_FILE_HEADER))) goto out;
// We are going to reset the file header for now so that if this process fails,
// this file will think that there is nothing in the file rather than crashing
NewMPSWabFileHeader = MPSWabFileHeader; NewMPSWabFileHeader.ulModificationCount = 0; NewMPSWabFileHeader.ulcNumEntries = 0;
for(i=0;i<indexMax;i++) { if(i != indexDisplayName)// Temp Temp TBD TBD
{ NewMPSWabFileHeader.IndexData[i].UtilizedBlockSize = 0; NewMPSWabFileHeader.IndexData[i].ulcNumEntries = 0; } }
//
// Write this NewMPSWabFileHeader to the file
//
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) &NewMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
ulFileSize = GetFileSize(hMPSWabFile, NULL);
if(ulFileSize == 0xFFFFFFFF) { DebugTrace(TEXT("Error retrieving file size: %d"),GetLastError()); hr = MAPI_E_DISK_ERROR; goto out; } //
// Allocate some working space
//
lpIndexEID = LocalAlloc(LMEM_ZEROINIT, MPSWabFileHeader.IndexData[indexEntryID].AllocatedBlockSize); if(!lpIndexEID) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } lpTmp = LocalAlloc(LMEM_ZEROINIT, MPSWabFileHeader.IndexData[indexEntryID].AllocatedBlockSize); if(!lpTmp) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
//
// Now start reading the records 1 by one
//
ulRecordOffset = MPSWabFileHeader.IndexData[indexMax-1].ulOffset + MPSWabFileHeader.IndexData[indexMax-1].AllocatedBlockSize;
ulcWABEntryCount = 0;
while(ulRecordOffset < ulFileSize) { if(!ReadDataFromWABFile(hMPSWabFile, ulRecordOffset, (LPVOID) &MPSWabRecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
//
// if this is an invalid record ignore it
//
if( (MPSWabRecordHeader.bValidRecord != FALSE) && (!bIsValidRecord( MPSWabRecordHeader, lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID, ulRecordOffset, ulFileSize))) { DebugTrace(TEXT("Something seriously screwed up in the file\n")); hr = MAPI_E_CORRUPT_DATA; goto out; } else if(MPSWabRecordHeader.bValidRecord == FALSE) { // if this is a deleted obsolete record, ignore it
ulRecordOffset += sizeof(MPSWab_RECORD_HEADER) + MPSWabRecordHeader.ulPropTagArraySize + MPSWabRecordHeader.ulRecordDataSize; continue; }
//
// We have a live one ... create an entryid index structure for this
//
MPSWabIndexEID.dwEntryID = MPSWabRecordHeader.dwEntryID; MPSWabIndexEID.ulOffset = ulRecordOffset;
//
// We are creating a shadow index in memory in the lpIndexEID block
// We then write this index into the file ..
//
//
// Find the position in the index where this entry will go
//
bEID = BinSearchEID(lpIndexEID, MPSWabIndexEID.dwEntryID, ulcWABEntryCount, &nIndexPos);
if(bEID) { //
// This means that the entryid exists in the index which is messed up
// since we dont support duplicate entryids ...
// In this case, just ignore this entry and continue
ulRecordOffset += sizeof(MPSWab_RECORD_HEADER) + MPSWabRecordHeader.ulPropTagArraySize + MPSWabRecordHeader.ulRecordDataSize; continue; }
if(nIndexPos != ulcWABEntryCount) { CopyMemory( lpTmp, &(lpIndexEID[nIndexPos]), sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID) * (ulcWABEntryCount - nIndexPos)); }
CopyMemory( &(lpIndexEID[nIndexPos]), &(MPSWabIndexEID), sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID));
if(nIndexPos != ulcWABEntryCount) { CopyMemory( &(lpIndexEID[nIndexPos+1]), lpTmp, sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID) * (ulcWABEntryCount - nIndexPos)); }
ulcWABEntryCount++;
// Write this entry id index from memory to file
//
if(!WriteDataToWABFile( hMPSWabFile, MPSWabFileHeader.IndexData[indexEntryID].ulOffset, (LPVOID) lpIndexEID, sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)*ulcWABEntryCount)) goto out;
NewMPSWabFileHeader.ulcNumEntries = ulcWABEntryCount; NewMPSWabFileHeader.IndexData[indexEntryID].UtilizedBlockSize = sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)*ulcWABEntryCount; NewMPSWabFileHeader.IndexData[indexEntryID].ulcNumEntries = ulcWABEntryCount;
//
// Write this NewMPSWabFileHeader to the file
//
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) &NewMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
// go onto next record
ulRecordOffset += sizeof(MPSWab_RECORD_HEADER) + MPSWabRecordHeader.ulPropTagArraySize + MPSWabRecordHeader.ulRecordDataSize;
} // while loop
// Now we have the correct entryid index,
// we want to build the display name index from scratch ...
LocalFreeAndNull(&lpTmp);
lpTmp = LocalAlloc( LMEM_ZEROINIT, MPSWabFileHeader.IndexData[indexDisplayName].AllocatedBlockSize); if(!lpTmp) { DebugTrace(TEXT("LocalAlloc failed\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
lpIndexString = LocalAlloc( LMEM_ZEROINIT, MPSWabFileHeader.IndexData[indexDisplayName].AllocatedBlockSize); if(!lpIndexString) { DebugTrace(TEXT("LocalAlloc failed\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
//
// Get the Entry iD index
//
if (!LoadIndex( IN lpMPSWabFileInfo, IN indexEntryID, IN hMPSWabFile) ) { DebugTrace(TEXT("Error Loading EntryID Index!\n")); goto out; }
if(!ReadDataFromWABFile(hMPSWabFile, 0, (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader, (DWORD) sizeof(MPSWab_FILE_HEADER))) goto out;
for(i=0;i<ulcWABEntryCount;i++) { DWORD dwEntryID = lpIndexEID[i].dwEntryID; ULONG j = 0; LPTSTR lpszDisplayName = NULL;
hr = ReadRecordWithoutLocking( hMPSWabFile, lpMPSWabFileInfo, dwEntryID, &ulcPropCount, &lpPropArray);
if (HR_FAILED(hr)) { // Since there are a lot of implicit expectations in the WAB that the
// EntryID and DisplayName indexes should have a one to one correspondence,
// we cant really have an entry in the EntryID index and not have it in
// the display name index. Hence an error in reading the record is serious
// and we should either
// - remove the corresponding entry from the EID index; or
// - fail and restore from backup;
// For the time being we will do (a)
hr = MAPI_E_CORRUPT_DATA; goto out; }
//reset hr
hr = E_FAIL;
for(j=0;j<ulcPropCount;j++) { if (lpPropArray[j].ulPropTag == PR_DISPLAY_NAME) { lpszDisplayName = lpPropArray[j].Value.LPSZ; break; } }
if(!lpszDisplayName) { //we should remove this index from the EID index since this record
//seems to have some errors <TBD>
hr = MAPI_E_CORRUPT_DATA; goto out; } else { // We have a display name so create an index and write it to file ..
ULONG nLen = TruncatePos(lpszDisplayName, MAX_INDEX_STRING-1); CopyMemory(MPSWabIndexString.szIndex,lpszDisplayName,sizeof(TCHAR)*nLen); MPSWabIndexString.szIndex[nLen]='\0';
MPSWabIndexString.dwEntryID = dwEntryID;
//
// We are cerating a shadow index in memory in the lpIndexEID block
// We then write this index into the file ..
//
//
// Find the position in the index where this entry will go
//
bEID = BinSearchStr(lpIndexString, MPSWabIndexString.szIndex, i, &nIndexPos);
if(nIndexPos != i) { CopyMemory( lpTmp, &(lpIndexString[nIndexPos]), sizeof(MPSWab_INDEX_ENTRY_DATA_STRING) * (i - nIndexPos)); }
CopyMemory( &(lpIndexString[nIndexPos]), &(MPSWabIndexString), sizeof(MPSWab_INDEX_ENTRY_DATA_STRING));
if(nIndexPos != i) { CopyMemory( &(lpIndexString[nIndexPos+1]), lpTmp, sizeof(MPSWab_INDEX_ENTRY_DATA_STRING) * (i - nIndexPos)); }
if(!WriteDataToWABFile( hMPSWabFile, MPSWabFileHeader.IndexData[indexDisplayName].ulOffset, (LPVOID) lpIndexString, sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(i+1))) goto out;
NewMPSWabFileHeader.IndexData[indexDisplayName].UtilizedBlockSize = sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(i+1); NewMPSWabFileHeader.IndexData[indexDisplayName].ulcNumEntries = (i+1);
//
// Write this NewMPSWabFileHeader to the file
//
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) &NewMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
}
LocalFreePropArray(NULL, ulcPropCount,&lpPropArray);
lpPropArray = NULL; ulcPropCount = 0;
} //for loop
// check that we have the correct number of entries in the both indexes
//
if (NewMPSWabFileHeader.IndexData[indexDisplayName].ulcNumEntries != NewMPSWabFileHeader.ulcNumEntries) { // If the 2 indexes dont contain the same number of elements, something failed above
// Big problem ... cant recover
hr = MAPI_E_CORRUPT_DATA; goto out; }
//
// Clear out the error tag from the File Header so we dont keep falling back
// into this function ...
//
NewMPSWabFileHeader.ulFlags = WAB_CLEAR;
//
// Write this NewMPSWabFileHeader to the file
//
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) &NewMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
hr = hrSuccess;
out: LocalFreeAndNull(&lpTmp);
LocalFreeAndNull(&lpIndexEID);
LocalFreeAndNull(&lpIndexString);
LocalFreePropArray(NULL, ulcPropCount,&lpPropArray);
// fix the return error code
switch(hr) { case MAPI_E_NOT_ENOUGH_MEMORY: case MAPI_E_DISK_ERROR: case S_OK: break; default: hr = MAPI_E_CORRUPT_DATA; break; }
DebugTrace(TEXT("---DoDetailedWABIntegrityCheck Exit: %x\n"),hr);
SetCursor(hOldCur);
return hr; }
//$$////////////////////////////////////////////////////////////////////////////////
//
// bIsValidRecord - This function looks at the Record Header components to determine if
// the record is valid or not
//
// It follows some very simple rules that can detect record header corruptions
//
// dwNextEntryID value will not be used if it is 0xFFFFFFFF
////////////////////////////////////////////////////////////////////////////////////////
BOOL bIsValidRecord(MPSWab_RECORD_HEADER rh, DWORD dwNextEntryID, ULONG ulRecordOffset, ULONG ulFileSize) { BOOL bRet = FALSE;
// is this tagged as an invalid record (or something else)
if ((rh.bValidRecord == FALSE) && (rh.bValidRecord != TRUE)) goto out;
// is this entry id value acceptable and correct
if(dwNextEntryID != 0xFFFFFFFF) { if (rh.dwEntryID > dwNextEntryID) goto out; }
// are the offsets in the header correct
if (rh.ulPropTagArraySize != rh.ulcPropCount * sizeof(ULONG)) goto out;
if (rh.ulRecordDataOffset != rh.ulPropTagArraySize) goto out;
if (rh.ulPropTagArrayOffset != 32) /***TBD - this is dependent on the struct elements***/ goto out;
if (ulRecordOffset + rh.ulRecordDataOffset + rh.ulRecordDataSize > ulFileSize) goto out;
bRet = TRUE;
out:
if(!bRet) DebugTrace(TEXT("\n@@@@@@@@@@\n@@@Invalid Record Detected\n@@@@@@@@@@\n"));
return bRet; }
//$$////////////////////////////////////////////////////////////////////////
//
// TagWABFileError -
//
// If an error is detected while reading a files contents, we can tag the error
// in the file so that the next access will attempt to fix it
//
////////////////////////////////////////////////////////////////////////////
BOOL TagWABFileError( LPMPSWab_FILE_HEADER lpMPSWabFileHeader, HANDLE hMPSWabFile) { BOOL bRet = FALSE; DWORD dwNumofBytes = 0;
if(!lpMPSWabFileHeader || !hMPSWabFile) { DebugTrace(TEXT("Invalid Parameter\n")); goto out; }
lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
// update the file header
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) lpMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
bRet = TRUE;
out: return bRet; }
/*
- - SetNextEntryID - sets the next entryid to use in a file. Called durimg migration * */ void SetNextEntryID(HANDLE hPropertyStoreTemp, DWORD dwEID) { MPSWab_FILE_HEADER WABHeader = {0}; HANDLE hWABFile = NULL; LPMPSWab_FILE_INFO lpMPSWabFI = hPropertyStoreTemp;
// First read the header from the existing file
if(!HR_FAILED(OpenWABFile(lpMPSWabFI->lpszMPSWabFileName, NULL, &hWABFile))) { if(!ReadDataFromWABFile(hWABFile, 0, (LPVOID) &WABHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
WABHeader.dwNextEntryID = dwEID;
if(!WriteDataToWABFile(hWABFile, 0, (LPVOID) &WABHeader, sizeof(MPSWab_FILE_HEADER))) goto out; } out: if ((hWABFile != NULL) && (hWABFile != INVALID_HANDLE_VALUE)) CloseHandle(hWABFile);
return; }
enum WABVersion { W05 =0, W2, W3, W4, };
//$$////////////////////////////////////////////////////////////////////////////
//
// HrMigrateFromOldWABtoNew - Migrates older versions of the wab into current ones
//
// IN hMPSWabFile
// IN lpMPSWabFileInfo
// hWnd .. used for displaying a "Please wait" dialog
// returns:
// E_FAIL or S_OK
// MAPI_E_CORRUPT_DATA if GUID is unrecognizable
//
////////////////////////////////////////////////////////////////////////////////
HRESULT HrMigrateFromOldWABtoNew(HWND hWnd, HANDLE hMPSWabFile, LPMPSWab_FILE_INFO lpMPSWabFileInfo, GUID WabGUID) { HRESULT hr = E_FAIL; int WABVersion; HANDLE hTempFile = NULL; MPSWab_FILE_HEADER NewFileHeader = {0}; ULONG ulcMaxEntries = 0; MPSWab_FILE_HEADER_W2 MPSWabFileHeaderW2 = {0}; MPSWab_FILE_HEADER MPSWabFileHeader = {0}; TCHAR szFileName[MAX_PATH]; ULONG ulAdditionalRecordOffset=0; LPVOID lpv = NULL; LPMPSWab_INDEX_ENTRY_DATA_ENTRYID lpeid = NULL; ULONG i = 0; DWORD dwOldEID = 0, dwNextEID = 0;
HCURSOR hOldC = SetCursor(LoadCursor(NULL, IDC_WAIT));
if (IsEqualGUID(&WabGUID,&MPSWab_OldBeta1_GUID)) { WABVersion = W05; } else if (IsEqualGUID(&WabGUID,&MPSWab_W2_GUID)) { WABVersion = W2; } else if (IsEqualGUID(&WabGUID,&MPSWab_GUID_V4)) { WABVersion = W4; }
// For WABVersion 1 and 2, we will read in the file header and
// save it to the new file. We will then read in the records one by
// one and write them to the file through the interface retaining the
// old entryid. Version 1 and 2 did not have named prop support and also
// had lesser numbers of indices. The individual record layour was the same as before
// WABVersion 4 is the conversion from the ANSI store to the Unicode store ..
// We can copy the file header and the named prop info as it is but we'll need
// to read the records one by one, convert them to Unicode and then write it to the
// new file so that all the indexes etc are rebuild correctly ...
//
// As long as all the entryids are retained, the relationship between the address
// book data elements is the same.
// Get a temp file name
szFileName[0]='\0'; GetWABTempFileName(szFileName);
if(WABVersion <= W2) { // First read the header from the existing file
if(!ReadDataFromWABFile(hMPSWabFile, 0, (LPVOID) &MPSWabFileHeaderW2, sizeof(MPSWab_FILE_HEADER_W2))) goto out;
// Create a new Temp WAB File
if (!CreateMPSWabFile( IN &NewFileHeader, IN szFileName, IN MPSWabFileHeaderW2.ulcMaxNumEntries, IN NAMEDPROP_STORE_SIZE)) { DebugTrace(TEXT("Error creating new file\n")); goto out; }
//Update header information
NewFileHeader.ulModificationCount = MPSWabFileHeaderW2.ulModificationCount; dwNextEID = NewFileHeader.dwNextEntryID = MPSWabFileHeaderW2.dwNextEntryID; NewFileHeader.ulcNumEntries = MPSWabFileHeaderW2.ulcNumEntries; NewFileHeader.ulFlags = MPSWabFileHeaderW2.ulFlags; NewFileHeader.ulReserved1 = MPSWabFileHeaderW2.ulReserved; } else { // First read the header from the existing file
if(!ReadDataFromWABFile(hMPSWabFile, 0, (LPVOID) &MPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
// Create a new Temp WAB File
if (!CreateMPSWabFile( IN &NewFileHeader, IN szFileName, IN MPSWabFileHeader.ulcMaxNumEntries, IN MPSWabFileHeader.NamedPropData.AllocatedBlockSize)) { DebugTrace(TEXT("Error creating new file\n")); goto out; } //Update header information
dwOldEID = dwNextEID = NewFileHeader.dwNextEntryID = MPSWabFileHeader.dwNextEntryID; }
{ // Update the file header info from current file to the new file
// now we open the new temp file and get a handle to it
hTempFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, (HANDLE) NULL); if (hTempFile == INVALID_HANDLE_VALUE) { DebugTrace(TEXT("Could not open Temp file.\nExiting ...\n")); goto out; }
if(WABVersion == W4) { DWORD dwNP = MPSWabFileHeader.NamedPropData.AllocatedBlockSize; LPBYTE lpNP = LocalAlloc(LMEM_ZEROINIT, dwNP); LPGUID_NAMED_PROPS lpgnp = NULL;
if(lpNP) { if(!ReadDataFromWABFile(hMPSWabFile, MPSWabFileHeader.NamedPropData.ulOffset, (LPVOID) lpNP, dwNP)) goto out;
if(GetNamedPropsFromBuffer(lpNP, MPSWabFileHeader.NamedPropData.ulcNumEntries, TRUE, &lpgnp)) { LocalFreeAndNull(&lpNP); if(SetNamedPropsToBuffer( MPSWabFileHeader.NamedPropData.ulcNumEntries, lpgnp, &dwNP, &lpNP)) { if(!WriteDataToWABFile(hTempFile, NewFileHeader.NamedPropData.ulOffset, (LPVOID) lpNP, dwNP)) goto out; LocalFreeAndNull(&lpNP); }
NewFileHeader.NamedPropData.UtilizedBlockSize = MPSWabFileHeader.NamedPropData.UtilizedBlockSize; NewFileHeader.NamedPropData.ulcNumEntries = MPSWabFileHeader.NamedPropData.ulcNumEntries;
if(lpgnp) FreeGuidnamedprops(MPSWabFileHeader.NamedPropData.ulcNumEntries, lpgnp); }
}
}
//Save this fileheader information
if(!WriteDataToWABFile(hTempFile, 0, (LPVOID) &NewFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
CloseHandle(hTempFile); hTempFile = NULL; }
{ HANDLE hPropertyStoreTemp = NULL; ULONG ulOldRecordOffset = 0; ULONG ulWABFileSize = GetFileSize(hMPSWabFile,NULL); LPSPropValue lpPropArray = NULL; ULONG ulcValues = 0;
hr = OpenPropertyStore( szFileName, AB_OPEN_EXISTING | AB_DONT_RESTORE, NULL, &hPropertyStoreTemp); if(HR_FAILED(hr)) { DebugTrace(TEXT("Could not open Temp PropStore\n")); goto endW05; }
// Get the start of the record data from this file
if(WABVersion <= W2) { ulOldRecordOffset = MPSWabFileHeaderW2.IndexData[indexFirstName].ulOffset + MPSWabFileHeaderW2.IndexData[indexFirstName].AllocatedBlockSize; } else { ulOldRecordOffset = MPSWabFileHeader.IndexData[indexAlias].ulOffset + MPSWabFileHeader.IndexData[indexAlias].AllocatedBlockSize; }
// walk the file record by record
while (ulOldRecordOffset < ulWABFileSize) { ULONG ulRecordSize = 0; ULONG ulObjType = 0;
//Read the record prop array from the old WAB file
hr = HrGetPropArrayFromFileRecord(hMPSWabFile, ulOldRecordOffset, NULL, &ulObjType, &ulRecordSize, &ulcValues, &lpPropArray);
if(ulRecordSize == 0) { // If this happens we will get caught in a loop
// Better to exit.
DebugTrace(TEXT("Zero-lengthrecord found\n")); goto endW05; }
if(!HR_FAILED(hr)) { LPSBinary lpsbEID = NULL; ULONG i = 0, iEID = 0; DWORD dwEID = 0;
// The above PropArray has a PR_ENTRY_ID that has a value
// from the old store. We want to retain this entryid value
for(i=0;i<ulcValues;i++) { if(lpPropArray[i].ulPropTag == PR_ENTRYID) { lpsbEID = &lpPropArray[i].Value.bin; iEID = i; break; } }
// However, when we save this entry to the new store, the new
// store does not have an index and so the entryid will be rejected and
// a new one assigned .. so to trick the WAB into reusing the entryid, we will
// just set the entryid in the file header as the next one to use ..
{ AssertSz(lpsbEID->cb == SIZEOF_WAB_ENTRYID, TEXT("Entryid has unknown size!"));
CopyMemory(&dwEID, lpsbEID->lpb, sizeof(DWORD));
if(dwNextEID <= dwEID) dwNextEID = dwEID + 1;
SetNextEntryID(hPropertyStoreTemp, dwEID);
//lpPropArray[iEID].ulPropTag = PR_NULL;
//lpsbEID->cb = 0;
//LocalFreeAndNull(&lpsbEID->lpb);
//lpsbEID = NULL;
}
// Convert any A props read in into W props
ConvertAPropsToWCLocalAlloc(lpPropArray, ulcValues);
// We have a valid record (otherwise ignore it)
hr = WriteRecord(IN hPropertyStoreTemp, NULL, &lpsbEID, 0, ulObjType, ulcValues, lpPropArray); if(HR_FAILED(hr)) { DebugTrace(TEXT("WriteRecord failed\n")); goto endW05; }
//if(lpsbEID)
// FreeEntryIDs(NULL, 1, lpsbEID);
}
ulOldRecordOffset += ulRecordSize;
LocalFreePropArray(NULL, ulcValues, &lpPropArray);
}
if(hr == MAPI_E_INVALID_OBJECT) hr = S_OK;
// Just in case the Next Entryid value has changed (for whatever reason)(though this shouldnt happen)
// update the value in the file ..
if(dwOldEID != dwNextEID) SetNextEntryID(hPropertyStoreTemp, dwNextEID);
endW05: LocalFreePropArray(NULL, ulcValues, &lpPropArray);
if(hPropertyStoreTemp) ClosePropertyStore(hPropertyStoreTemp, AB_DONT_BACKUP);
if(!HR_FAILED(hr)) { hr = E_FAIL;
hTempFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, (HANDLE) NULL); if (hTempFile == INVALID_HANDLE_VALUE) { DebugTrace(TEXT("Could not open Temp file.\nExiting ...\n")); goto out; }
if(!CopySrcFileToDestFile(hTempFile, 0, hMPSWabFile, 0)) { DebugTrace(TEXT("Could not copy file\n")); goto out; }
hr = S_OK; } }
out: LocalFreeAndNull(&lpv);
LocalFreeAndNull(&lpeid);
if(hTempFile) IF_WIN32(CloseHandle(hTempFile);) IF_WIN16(CloseFile(hTempFile);)
if(lstrlen(szFileName)) DeleteFile(szFileName);
if(hOldC) SetCursor(hOldC);
return hr; }
//$$////////////////////////////////////////////////////////////////////////////
//
// HrVerifyWABVersionAndUpdate - Looks at the WAB File version and migrates
// older versions into newer versions
//
// IN hMPSWabFile
// IN lpMPSWabFileInfo
// hWnd - used for displaying some kind of dialog if necessary
//
// BUG 16681:
// In randomly occuring cases, the wab file seems to get totally wiped and turned
// into 0's ... In such events, we will rename the file and try again .. we
// indicate this condition to the OpenPropertyStore function by returning
// MAPI_E_VERSION ..
//
// returns:
// E_FAIL or S_OK
// MAPI_E_CORRUPT_DATA if GUID is unrecognizable
//
////////////////////////////////////////////////////////////////////////////////
HRESULT HrVerifyWABVersionAndUpdate(HWND hWnd, HANDLE hMPSWabFile, LPMPSWab_FILE_INFO lpMPSWabFileInfo) { GUID TmpGuid = {0}; HRESULT hr = E_FAIL; DWORD dwNumofBytes = 0;
// First read the GUID from the file
//
if(!ReadDataFromWABFile(hMPSWabFile, 0, (LPVOID) &TmpGuid, (DWORD) sizeof(GUID))) goto out;
//
// Check if this is a Microsoft Property Store by looking for MPSWab GUID in header
// (If this was an old file it should have been updated above)(If not, we should
// avoid an error and go ahead and open it)
// However if the guids dont match, we cant tell if this is a WAB file or not
// because it could also be a valid corrupt wab file ... so when the guids dont
// match, we will assume that the file is a corrupt wab file.
//
if ( (!IsEqualGUID(&TmpGuid,&MPSWab_GUID)) && (!IsEqualGUID(&TmpGuid,&MPSWab_GUID_V4)) && (!IsEqualGUID(&TmpGuid,&MPSWab_W2_GUID)) && (!IsEqualGUID(&TmpGuid,&MPSWab_OldBeta1_GUID)) ) { DebugTrace(TEXT("%s is not a Microsoft Property Store File. GUIDS don't match\n"),lpMPSWabFileInfo->lpszMPSWabFileName); hr = MAPI_E_INVALID_OBJECT;
//Bug 16681:
//Check the special condition where everything is all zero's
{ if ( (TmpGuid.Data1 == 0) && (TmpGuid.Data2 == 0) && (TmpGuid.Data3 == 0) && (lstrlen((LPTSTR)TmpGuid.Data4) == 0) ) { hr = MAPI_E_VERSION; } }
goto out; }
//
// If this is an older version of the file, update it to a more current
// store format.
//
if ( (IsEqualGUID(&TmpGuid,&MPSWab_GUID_V4)) || (IsEqualGUID(&TmpGuid,&MPSWab_OldBeta1_GUID)) || (IsEqualGUID(&TmpGuid,&MPSWab_W2_GUID)) ) { // We will basically scavenge the old file for records out of the
// file (ignoring the indexes so we can avoid all errors)
// and put them in a new prop store file which we will then
// populate with the old records and finally use to replace the
// current file - very similar to how CompressFile works
DebugTrace(TEXT("Old WAB File Found. Migrating to new ...\n")); hr = HrMigrateFromOldWABtoNew( hWnd, hMPSWabFile, lpMPSWabFileInfo, TmpGuid); if(HR_FAILED(hr)) { DebugTrace(TEXT("MPSWabUpdateAndVerifyOldWAB: %x\n")); goto out; } }
//reset hr
hr = E_FAIL;
lpMPSWabFileInfo->nCurrentlyLoadedStrIndexType = indexDisplayName;
// Reload whatever new info we added as a result of the above.
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
hr = S_OK;
out: return hr; }
//$$////////////////////////////////////////////////////////////////////////////////
//
// HrGetBufferFromPropArray - translates a prop array into a flat buffer.
// The format of the data in the buffer is the same as
// the format of data in the .wab file
//
//
// Params:
// ulcPropCount- # of props in array
// lpPropArray - prop array
// lpcbBuf - size of returned buffer
// lppBuf - returned buffer
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrGetBufferFromPropArray( ULONG ulcPropCount, LPSPropValue lpPropArray, ULONG * lpcbBuf, LPBYTE * lppBuf) { HRESULT hr = E_FAIL; LPULONG lpulrgPropDataSize = NULL; ULONG ulRecordDataSize = 0; LPBYTE lp = NULL; LPBYTE szBuf = NULL; ULONG i=0,j=0,k=0;
if(!lpcbBuf || !lppBuf) goto out;
*lpcbBuf = 0; *lppBuf = NULL;
// _DebugProperties(lpPropArray, ulcPropCount, TEXT("GetBufferFromPropArray"));
//
// We will go through the given data and determine how much space we need for each
// property. lpulrgPropDataSize is an array of ULONGs in which we store the calculated sizes
// temporarily.
//
lpulrgPropDataSize = LocalAlloc(LMEM_ZEROINIT, ulcPropCount * sizeof(ULONG));
if (!lpulrgPropDataSize) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
//
// Get an estimate of how big the data portion of this record will be ...
// We need this estimate to allocate a block of memory into which we will
// write the data and then blt the block into the file
//
for(i=0;i<ulcPropCount;i++) { // This is the eventual data format:
//
// If (SingleValued)
// <PropTag><DataSize><Data>
// else
// <MultiPropTag><cValues><DataSize><data>
// unless PropType is MV_BINARY or MV_TSTRING in which case we need a
// more flexible data storage
// <MultiPropTag><cValues><DataSize>
// <cb/strlen><Data>
// <cb/strlen><Data> ...
//
ulRecordDataSize += sizeof(ULONG); // holds <PropTag>
if ((lpPropArray[i].ulPropTag & MV_FLAG)) { //
// multi-valued
//
lpulrgPropDataSize[i] = SizeOfMultiPropData(lpPropArray[i]); //Data
ulRecordDataSize += sizeof(ULONG); // holds <CValues>
} else { //
// single-valued
//
lpulrgPropDataSize[i] = SizeOfSinglePropData(lpPropArray[i]); //Data
} ulRecordDataSize += sizeof(ULONG) // holds <DataSize>
+ lpulrgPropDataSize[i]; //holds <Data>
}
lp = LocalAlloc(LMEM_ZEROINIT, ulRecordDataSize);
if (!lp) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
szBuf = lp;
for (i = 0; i<ulcPropCount; i++) { //
// copy the prop tag
//
CopyMemory(szBuf,&lpPropArray[i].ulPropTag, sizeof(ULONG)); szBuf += sizeof(ULONG);
//
// difference between handling of multivalued and singlevalued
//
if (!(lpPropArray[i].ulPropTag & MV_FLAG)) { // Single Valued
//
// Record the size of data
//
CopyMemory(szBuf,&lpulrgPropDataSize[i], sizeof(ULONG)); szBuf += sizeof(ULONG);
////DebugTrace(TEXT("%x: "),lpPropArray[i].ulPropTag);
switch(PROP_TYPE(lpPropArray[i].ulPropTag)) { case(PT_STRING8): //
// Record the data ...
//
CopyMemory(szBuf,lpPropArray[i].Value.lpszA, lpulrgPropDataSize[i]); ////DebugTrace(TEXT("%s\n"),lpPropArray[i].Value.LPSZ);
break;
case(PT_UNICODE): //
// Record the data ...
//
CopyMemory(szBuf,lpPropArray[i].Value.lpszW, lpulrgPropDataSize[i]); ////DebugTrace(TEXT("%s\n"),lpPropArray[i].Value.LPSZ);
break;
case(PT_CLSID): //
// Record the data ...
//
CopyMemory(szBuf,lpPropArray[i].Value.lpguid, lpulrgPropDataSize[i]); ////DebugTrace(TEXT("%x-%x-%x-%x\n"),lpPropArray[i].Value.lpguid->Data1,lpPropArray[i].Value.lpguid->Data2,lpPropArray[i].Value.lpguid->Data3,lpPropArray[i].Value.lpguid->Data4);
break;
case(PT_BINARY): //
// Record the data ...
//
CopyMemory(szBuf,lpPropArray[i].Value.bin.lpb, lpulrgPropDataSize[i]); break;
case(PT_SHORT): //Record the data ...
CopyMemory(szBuf,&lpPropArray[i].Value.i, lpulrgPropDataSize[i]); ////DebugTrace(TEXT("%d\n"),lpPropArray[i].Value.i);
break;
case(PT_LONG): case(PT_R4): case(PT_DOUBLE): case(PT_BOOLEAN): case(PT_APPTIME): case(PT_CURRENCY): //Record the data ...
CopyMemory(szBuf,&lpPropArray[i].Value.i, lpulrgPropDataSize[i]); ////DebugTrace(TEXT("%d\n"),lpPropArray[i].Value.l);
break;
case(PT_SYSTIME): //Record the data ...
CopyMemory(szBuf,&lpPropArray[i].Value.ft, lpulrgPropDataSize[i]); ////DebugTrace(TEXT("%d,%d\n"),lpPropArray[i].Value.ft.dwLowDateTime,lpPropArray[i].Value.ft.dwHighDateTime);
break;
default: DebugTrace(TEXT("Unknown PropTag !!\n")); break;
} szBuf += lpulrgPropDataSize[i];
} else { //multivalued
//copy the # of multi-values
CopyMemory(szBuf,&lpPropArray[i].Value.MVi.cValues, sizeof(ULONG)); szBuf += sizeof(ULONG);
//Record the size of data
CopyMemory(szBuf,&lpulrgPropDataSize[i], sizeof(ULONG)); szBuf += sizeof(ULONG);
////DebugTrace(TEXT("%x: MV_PROP\n"),lpPropArray[i].ulPropTag);
switch(PROP_TYPE(lpPropArray[i].ulPropTag)) { case(PT_MV_I2): case(PT_MV_LONG): case(PT_MV_R4): case(PT_MV_DOUBLE): case(PT_MV_CURRENCY): case(PT_MV_APPTIME): case(PT_MV_SYSTIME): CopyMemory(szBuf,lpPropArray[i].Value.MVft.lpft, lpulrgPropDataSize[i]); szBuf += lpulrgPropDataSize[i]; break;
case(PT_MV_I8): CopyMemory(szBuf,lpPropArray[i].Value.MVli.lpli, lpulrgPropDataSize[i]); szBuf += lpulrgPropDataSize[i]; break;
case(PT_MV_BINARY): for (j=0;j<lpPropArray[i].Value.MVbin.cValues;j++) { CopyMemory(szBuf,&lpPropArray[i].Value.MVbin.lpbin[j].cb, sizeof(ULONG)); szBuf += sizeof(ULONG); CopyMemory(szBuf,lpPropArray[i].Value.MVbin.lpbin[j].lpb, lpPropArray[i].Value.MVbin.lpbin[j].cb); szBuf += lpPropArray[i].Value.MVbin.lpbin[j].cb; } break;
case(PT_MV_STRING8): for (j=0;j<lpPropArray[i].Value.MVszA.cValues;j++) { ULONG nLen; nLen = lstrlenA(lpPropArray[i].Value.MVszA.lppszA[j])+1; CopyMemory(szBuf,&nLen, sizeof(ULONG)); szBuf += sizeof(ULONG); CopyMemory(szBuf,lpPropArray[i].Value.MVszA.lppszA[j], nLen); szBuf += nLen; } break;
case(PT_MV_UNICODE): for (j=0;j<lpPropArray[i].Value.MVszW.cValues;j++) { ULONG nLen; nLen = sizeof(TCHAR)*(lstrlenW(lpPropArray[i].Value.MVszW.lppszW[j])+1); CopyMemory(szBuf,&nLen, sizeof(ULONG)); szBuf += sizeof(ULONG); CopyMemory(szBuf,lpPropArray[i].Value.MVszW.lppszW[j], nLen); szBuf += nLen; } break;
case(PT_MV_CLSID): CopyMemory(szBuf,lpPropArray[i].Value.MVguid.lpguid, lpulrgPropDataSize[i]); szBuf += lpulrgPropDataSize[i]; break;
} //switch
} //if
} //for
*lpcbBuf = ulRecordDataSize; *lppBuf = lp; hr = S_OK;
out: LocalFreeAndNull(&lpulrgPropDataSize); return hr; }
//$$////////////////////////////////////////////////////////////////////////////////
//
// HrGetPropArrayFromBuffer - translates a buffer (from file or memory) into
// a prop array. The format of the data in the buffer is the same as
// the format of data in the .wab file
//
//
// Params: char * szBuf- buffer to interpret
// cbBuf - sizeof buffer
// ulcPropCount- # of props in buffer
// lppPropArray - returned prop array
//
// ulcNumExtraProps - an extra number of props to add to the PropArray
// during allocation. These blank props are later used for
// extending the prop array easily ..
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrGetPropArrayFromBuffer( LPBYTE szBuf, ULONG cbBuf, ULONG ulcPropCount, ULONG ulcNumExtraProps, LPSPropValue * lppPropArray) { HRESULT hr = S_OK; LPBYTE lp = NULL; ULONG i = 0,j=0, k=0; DWORD cbBufLeft = cbBuf;
if(!lppPropArray) { hr = MAPI_E_INVALID_PARAMETER; goto out; }
*lppPropArray = NULL;
*lppPropArray = LocalAlloc(LMEM_ZEROINIT, (ulcPropCount+ulcNumExtraProps) * sizeof(SPropValue));
if (!(*lppPropArray)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
for(i=0;i<(ulcPropCount+ulcNumExtraProps);i++) (*lppPropArray)[i].ulPropTag = PR_NULL;
lp = szBuf;
for(i=0;i<ulcPropCount;i++) { ULONG ulDataSize = 0; ULONG ulcValues = 0;
// Copy PropTag
CopyMemory(&((*lppPropArray)[i].ulPropTag),lp,sizeof(ULONG)); lp+=sizeof(ULONG);
AssertSz((*lppPropArray)[i].ulPropTag, TEXT("Null PropertyTag"));
if(ulDataSize > cbBuf) { hr = MAPI_E_CORRUPT_DATA; goto out; }
if (((*lppPropArray)[i].ulPropTag & MV_FLAG)) { //multi-valued
//DebugTrace(TEXT("MV_PROP\n"));
//Copy cValues
CopyMemory(&ulcValues,lp,sizeof(ULONG)); lp+=sizeof(ULONG);
//Copy DataSize
CopyMemory(&ulDataSize,lp,sizeof(ULONG)); lp+=sizeof(ULONG);
switch(PROP_TYPE((*lppPropArray)[i].ulPropTag)) { case(PT_MV_I2): case(PT_MV_LONG): case(PT_MV_R4): case(PT_MV_DOUBLE): case(PT_MV_CURRENCY): case(PT_MV_APPTIME): case(PT_MV_SYSTIME): case(PT_MV_CLSID): case(PT_MV_I8): (*lppPropArray)[i].Value.MVi.lpi = LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!((*lppPropArray)[i].Value.MVi.lpi)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } (*lppPropArray)[i].Value.MVi.cValues = ulcValues; CopyMemory((*lppPropArray)[i].Value.MVi.lpi, lp, ulDataSize); lp += ulDataSize; break;
case(PT_MV_BINARY): (*lppPropArray)[i].Value.MVbin.lpbin = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(SBinary)); if (!((*lppPropArray)[i].Value.MVbin.lpbin)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } (*lppPropArray)[i].Value.MVbin.cValues = ulcValues; for (j=0;j<ulcValues;j++) { ULONG nLen; CopyMemory(&nLen, lp, sizeof(ULONG)); lp += sizeof(ULONG); (*lppPropArray)[i].Value.MVbin.lpbin[j].cb = nLen; (*lppPropArray)[i].Value.MVbin.lpbin[j].lpb = LocalAlloc(LMEM_ZEROINIT, nLen); if (!((*lppPropArray)[i].Value.MVbin.lpbin[j].lpb)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory((*lppPropArray)[i].Value.MVbin.lpbin[j].lpb, lp, nLen); lp += nLen; } // hack: we want to upgrade the old WAB_FOLDER_PARENT_OLDPROP props to a new WAB_FOLDER_PARENT
// This is the best place to do it and the check only happens on contacts with MV_BINARY props
if((*lppPropArray)[i].ulPropTag == PR_WAB_FOLDER_PARENT_OLDPROP && PR_WAB_FOLDER_PARENT) (*lppPropArray)[i].ulPropTag = PR_WAB_FOLDER_PARENT; break;
case(PT_MV_STRING8): (*lppPropArray)[i].Value.MVszA.lppszA = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(LPSTR)); if (!((*lppPropArray)[i].Value.MVszA.lppszA)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } for (j=0;j<ulcValues;j++) { ULONG nLen; CopyMemory(&nLen, lp, sizeof(ULONG)); lp += sizeof(ULONG); (*lppPropArray)[i].Value.MVszA.lppszA[j] = LocalAlloc(LMEM_ZEROINIT, nLen); if (!((*lppPropArray)[i].Value.MVszA.lppszA[j])) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory((*lppPropArray)[i].Value.MVszA.lppszA[j], lp, nLen); lp += nLen; } (*lppPropArray)[i].Value.MVszA.cValues = ulcValues; break;
case(PT_MV_UNICODE): (*lppPropArray)[i].Value.MVszW.lppszW = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(LPTSTR)); if (!((*lppPropArray)[i].Value.MVszW.lppszW)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } for (j=0;j<ulcValues;j++) { ULONG nLen; CopyMemory(&nLen, lp, sizeof(ULONG)); lp += sizeof(ULONG); (*lppPropArray)[i].Value.MVszW.lppszW[j] = LocalAlloc(LMEM_ZEROINIT, nLen); if (!((*lppPropArray)[i].Value.MVszW.lppszW[j])) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory((*lppPropArray)[i].Value.MVszW.lppszW[j], lp, nLen); lp += nLen; } (*lppPropArray)[i].Value.MVszW.cValues = ulcValues; break;
default: DebugTrace(TEXT("Unknown Prop Type\n")); break; } } else { //Single Valued
CopyMemory(&ulDataSize,lp,sizeof(ULONG)); lp+=sizeof(ULONG);
if(ulDataSize > cbBuf) { hr = MAPI_E_CORRUPT_DATA; goto out; }
switch(PROP_TYPE((*lppPropArray)[i].ulPropTag)) { case(PT_CLSID): (*lppPropArray)[i].Value.lpguid = (LPGUID) LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!((*lppPropArray)[i].Value.lpguid)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory((*lppPropArray)[i].Value.lpguid, lp, ulDataSize); lp += ulDataSize; break;
case(PT_STRING8): (*lppPropArray)[i].Value.lpszA = (LPSTR) LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!((*lppPropArray)[i].Value.lpszA)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory((*lppPropArray)[i].Value.lpszA, lp, ulDataSize); lp += ulDataSize; break;
case(PT_UNICODE): (*lppPropArray)[i].Value.lpszW = (LPTSTR) LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!((*lppPropArray)[i].Value.lpszW)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory((*lppPropArray)[i].Value.lpszW, lp, ulDataSize); lp += ulDataSize; break;
case(PT_BINARY): (*lppPropArray)[i].Value.bin.lpb = LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!((*lppPropArray)[i].Value.bin.lpb)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } (*lppPropArray)[i].Value.bin.cb = ulDataSize; CopyMemory((*lppPropArray)[i].Value.bin.lpb, lp, ulDataSize); lp += ulDataSize; break;
case(PT_SHORT): CopyMemory(&((*lppPropArray)[i].Value.i),lp,ulDataSize); lp += ulDataSize; break;
case(PT_LONG): CopyMemory(&((*lppPropArray)[i].Value.l),lp,ulDataSize); lp += ulDataSize; break;
case(PT_R4): CopyMemory(&((*lppPropArray)[i].Value.flt),lp,ulDataSize); lp += ulDataSize; break;
case(PT_DOUBLE): case(PT_APPTIME): CopyMemory(&((*lppPropArray)[i].Value.dbl),lp,ulDataSize); lp += ulDataSize; break;
case(PT_BOOLEAN): CopyMemory(&((*lppPropArray)[i].Value.b),lp,ulDataSize); lp += ulDataSize; break;
case(PT_SYSTIME): CopyMemory(&((*lppPropArray)[i].Value.ft),lp,ulDataSize); lp += ulDataSize; break;
case(PT_CURRENCY): CopyMemory(&((*lppPropArray)[i].Value.cur),lp,ulDataSize); lp += ulDataSize; break;
default: DebugTrace(TEXT("Unknown Prop Type\n")); CopyMemory(&((*lppPropArray)[i].Value.i),lp,ulDataSize); lp += ulDataSize; break; }
} }
hr = S_OK;
out:
if (FAILED(hr)) { if ((*lppPropArray) && (ulcPropCount > 0)) { LocalFreePropArray(NULL, ulcPropCount, lppPropArray); *lppPropArray = NULL; } }
// _DebugProperties(*lppPropArray, ulcPropCount, TEXT("GetPropArrayFromBuffer"));
return hr;
}
//$$////////////////////////////////////////////////////////////////////////////////
//
// HrGetPropArrayFromFileRecord - goes into a file, reads the record at the
// given offset, and turns the record data into a lpPropArray
//
// IN
// hFile - the WAB file to read from
// ulOffset - the record offset within the file
//
// OUT
// ulcValues - # of props in the prop array
// lpPropArray - the prop array from the record
//
// Returns
// E_FAIL, S_OK,
// MAPI_E_INVALID_OBJECT
// MAPI_E_CORRUPT_DATA
// MAPI_E_NOT_ENOUGH_MEMORY
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrGetPropArrayFromFileRecord(HANDLE hMPSWabFile, ULONG ulRecordOffset, BOOL * lpbErrorDetected, ULONG * lpulObjType, ULONG * lpulRecordSize, ULONG * lpulcPropCount, LPSPropValue * lppPropArray) { HRESULT hr = S_OK; MPSWab_RECORD_HEADER MPSWabRecordHeader = {0}; DWORD dwNumofBytes = 0; LPBYTE szBuf = NULL; LPBYTE lp = NULL; ULONG i = 0,j=0, k=0; ULONG nIndexPos = 0; BOOL bErrorDetected = FALSE;
if(!ReadDataFromWABFile(hMPSWabFile, ulRecordOffset, (LPVOID) &MPSWabRecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
// Its important that we get the record size first because a
// calling client may depend on the size to move to the
// next record if they want to skip invalid ones.
if(lpulRecordSize) { *lpulRecordSize = sizeof(MPSWab_RECORD_HEADER) + MPSWabRecordHeader.ulPropTagArraySize + MPSWabRecordHeader.ulRecordDataSize; }
if(lpulObjType) { *lpulObjType = MPSWabRecordHeader.ulObjType; }
if(!bIsValidRecord( MPSWabRecordHeader, 0xFFFFFFFF, ulRecordOffset, GetFileSize(hMPSWabFile,NULL))) { //this should never happen but who knows
DebugTrace(TEXT("Error: Obtained an invalid record ...\n")); hr = MAPI_E_INVALID_OBJECT; goto out; }
szBuf = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulRecordDataSize); if (!szBuf) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
// Set File Pointer to beginning of Data Section
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, MPSWabRecordHeader.ulPropTagArraySize, NULL, FILE_CURRENT)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
//Read in the data
// Read record header
if(!ReadFile( hMPSWabFile, (LPVOID) szBuf, (DWORD) MPSWabRecordHeader.ulRecordDataSize, &dwNumofBytes, NULL)) { DebugTrace(TEXT("Reading Record Header failed.\n")); goto out; }
if(HR_FAILED(hr = HrGetPropArrayFromBuffer( szBuf, MPSWabRecordHeader.ulRecordDataSize, MPSWabRecordHeader.ulcPropCount, 0, lppPropArray) )) { goto out; }
*lpulcPropCount = MPSWabRecordHeader.ulcPropCount;
hr = S_OK;
out:
// if this is a container, make sure its object type is correct
if(!HR_FAILED(hr) && MPSWabRecordHeader.ulObjType == RECORD_CONTAINER) SetContainerObjectType(*lpulcPropCount, *lppPropArray, FALSE);
if(hr == MAPI_E_CORRUPT_DATA) bErrorDetected = TRUE;
if (lpbErrorDetected) *lpbErrorDetected = bErrorDetected;
LocalFreeAndNull(&szBuf);
return hr; }
//$$////////////////////////////////////////////////////////////////////////////
//
// Space saver function for writing data to the file
//
////////////////////////////////////////////////////////////////////////////////
BOOL WriteDataToWABFile(HANDLE hMPSWabFile, ULONG ulOffset, LPVOID lpData, ULONG ulDataSize) { DWORD dwNumofBytes = 0;
if (0xFFFFFFFF != SetFilePointer ( hMPSWabFile, ulOffset, NULL, FILE_BEGIN)) { return WriteFile( hMPSWabFile, lpData, (DWORD) ulDataSize, &dwNumofBytes, NULL); }
return FALSE; }
//$$////////////////////////////////////////////////////////////////////////////////
//
// Space saver function for reading data from the file
//
////////////////////////////////////////////////////////////////////////////////////
BOOL ReadDataFromWABFile(HANDLE hMPSWabFile, ULONG ulOffset, LPVOID lpData, ULONG ulDataSize) { DWORD dwNumofBytes = 0;
if (0xFFFFFFFF != SetFilePointer ( hMPSWabFile, ulOffset, NULL, FILE_BEGIN)) { return ReadFile(hMPSWabFile, lpData, (DWORD) ulDataSize, &dwNumofBytes, NULL); }
return FALSE; }
//$$****************************************************************************
//
// FreeGuidnamedprops - frees a GUID_NAMED_PROPS array
//
// ulcGUIDCount - number of elements in the lpgnp array
// lpgnp - arry of GUID_NAMED_PROPS
//****************************************************************************//
void FreeGuidnamedprops(ULONG ulcGUIDCount, LPGUID_NAMED_PROPS lpgnp) { ULONG i=0,j=0;
if(lpgnp) { // for(i=ulcGUIDCount;i>0;--i)
for (i = 0; i < ulcGUIDCount; i++) { if(lpgnp[i].lpnm) { // for(j=lpgnp[i].cValues;j>0;--j)
for (j = 0; j < lpgnp[i].cValues; j++) { LocalFreeAndNull(&lpgnp[i].lpnm[j].lpsz); } LocalFreeAndNull(&lpgnp[i].lpnm); } LocalFreeAndNull(&lpgnp[i].lpGUID); } LocalFreeAndNull(&lpgnp); } return; }
//$$////////////////////////////////////////////////////////////////////////////////////////////////
//
// OpenWABFile - Opens the WAB file. If file is missing, restores from backup. If backup is missing
// creates a new file
//
// hWndParent - parent for opening message boxes - no message boxesif null
// lphMPSWabFile - returned file pointer
//
////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT OpenWABFile(LPTSTR lpszFileName, HWND hWndParent, HANDLE * lphMPSWabFile) { HANDLE hMPSWabFile = NULL; TCHAR szBackupFileName[MAX_PATH]; WIN32_FIND_DATA wfd = {0}; HANDLE hff = NULL; HRESULT hr = E_FAIL; DWORD dwErr = 0;
hMPSWabFile = CreateFile( lpszFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, (HANDLE) NULL);
if(hMPSWabFile != INVALID_HANDLE_VALUE) { hr = S_OK; goto out; }
// Something happened find out what..
dwErr = GetLastError();
if(dwErr == ERROR_ACCESS_DENIED) { hr = MAPI_E_NO_ACCESS; goto out; }
if(dwErr != ERROR_FILE_NOT_FOUND) { hr = E_FAIL; goto out; }
// Get the backup file name
szBackupFileName[0]='\0'; GetWABBackupFileName(lpszFileName, szBackupFileName, ARRAYSIZE(szBackupFileName));
hff = FindFirstFile(szBackupFileName,&wfd);
if(hff != INVALID_HANDLE_VALUE) { // we found the backup file
// copy it into the wab file name
CopyFile(szBackupFileName, lpszFileName, FALSE);
hMPSWabFile = CreateFile( lpszFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, (HANDLE) NULL);
if(hMPSWabFile != INVALID_HANDLE_VALUE) { hr = S_OK; goto out; }
}
// if we're still here .. nothing worked .. so create a new file
{ MPSWab_FILE_HEADER MPSWabFileHeader;
if(CreateMPSWabFile(IN &MPSWabFileHeader, lpszFileName, MAX_INITIAL_INDEX_ENTRIES, NAMEDPROP_STORE_SIZE)) { hMPSWabFile = CreateFile( lpszFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, (HANDLE) NULL);
if(hMPSWabFile != INVALID_HANDLE_VALUE) hr = S_OK; } }
out: *lphMPSWabFile = hMPSWabFile;
if(hff) FindClose(hff);
return hr; }
//$$/////////////////////////////////////////////////////////////////////////////////
//
//
// nCountSubStrings - counts space-delimted substrings in a given string
//
//
/////////////////////////////////////////////////////////////////////////////////////
int nCountSubStrings(LPTSTR lpszSearchStr) { int nSubStr = 0; LPTSTR lpTemp = lpszSearchStr; LPTSTR lpStart = lpszSearchStr;
if (!lpszSearchStr) goto out;
if (!lstrlen(lpszSearchStr)) goto out;
TrimSpaces(lpszSearchStr);
// Count the spaces
while(*lpTemp) { if (IsSpace(lpTemp) && ! IsSpace(CharNext(lpTemp))) { nSubStr++; } lpTemp = CharNext(lpTemp); }
// Number of substrings is 1 more than number of spaces
nSubStr++;
out: return nSubStr; }
#define DONTFIND 0
#define DOFIND 1
#define NOTFOUND 0
#define FOUND 1
extern BOOL SubstringSearchEx(LPTSTR pszTarget, LPTSTR pszSearch, LCID lcid); extern int my_atoi(LPTSTR lpsz); //$$////////////////////////////////////////////////////////////////////////////////
//
// HrDoLocalWABSearch
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrDoLocalWABSearch( IN HANDLE hPropertyStore, IN LPSBinary lpsbCont, //container entryid for Outlook stores
IN LDAP_SEARCH_PARAMS LDAPsp, OUT LPULONG lpulFoundCount, OUT LPSBinary * lprgsbEntryIDs ) {
int bFindName = DONTFIND; int bFindEmail = DONTFIND; int bFindAddress = DONTFIND; int bFindPhone = DONTFIND; int bFindOther = DONTFIND;
LCID lcid = 0; int nUseLCID = 0; TCHAR szUseLCID[2];
int bFoundName = NOTFOUND; int bFoundEmail = NOTFOUND; int bFoundAddress = NOTFOUND; int bFoundPhone = NOTFOUND; int bFoundOther = NOTFOUND;
ULONG nSubStr[ldspMAX]; LPTSTR * lppszSubStr[ldspMAX];
HRESULT hr = E_FAIL; SPropertyRestriction PropRes; ULONG ulPropCount = 0; ULONG ulEIDCount = 0; LPSBinary rgsbEntryIDs = NULL;
LPSPropValue lpPropArray = NULL; ULONG ulcPropCount = 0;
ULONG i,j,k; ULONG ulFoundIndex = 0; BOOL bFileLocked = FALSE; BOOL bFound = FALSE;
LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore; HANDLE hMPSWabFile = NULL;
LPPTGDATA lpPTGData=GetThreadStoragePointer(); ULONG cchSize;
if(!lpulFoundCount || !lprgsbEntryIDs) goto out;
*lpulFoundCount = 0; *lprgsbEntryIDs = NULL;
LoadString(hinstMapiX, idsUseLCID, szUseLCID, CharSizeOf(szUseLCID)); nUseLCID = my_atoi(szUseLCID); if(nUseLCID) lcid = GetUserDefaultLCID();
if(lstrlen(LDAPsp.szData[ldspDisplayName])) bFindName = DOFIND; if(lstrlen(LDAPsp.szData[ldspEmail])) bFindEmail = DOFIND; if(lstrlen(LDAPsp.szData[ldspAddress])) bFindAddress = DOFIND; if(lstrlen(LDAPsp.szData[ldspPhone])) bFindPhone = DOFIND; if(lstrlen(LDAPsp.szData[ldspOther])) bFindOther = DOFIND;
if (bFindName +bFindEmail +bFindPhone +bFindAddress +bFindOther == 0) goto out;
for(i=0;i<ldspMAX;i++) {
nSubStr[i] = (ULONG) nCountSubStrings(LDAPsp.szData[i]);
if(!nSubStr[i]) { lppszSubStr[i] = NULL; continue; }
lppszSubStr[i] = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * nSubStr[i]); if(!lppszSubStr[i]) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
{ // Fill in the substrings
ULONG nIndex = 0; LPTSTR lpTemp = NULL; LPTSTR lpStart = NULL; TCHAR szBuf[MAX_UI_STR];
StrCpyN(szBuf, LDAPsp.szData[i], ARRAYSIZE(szBuf)); lpTemp = szBuf; lpStart = szBuf;
// Bug 2558 - filter out commas from display name
if(i == ldspDisplayName) { while(lpTemp && *lpTemp) { if(*lpTemp == ',') *lpTemp = ' '; lpTemp++; } lpTemp = szBuf; }
while(*lpTemp) { if (IsSpace(lpTemp) && ! IsSpace(CharNext(lpTemp))) { LPTSTR lpNextString = CharNext(lpTemp); *lpTemp = '\0'; lpTemp = lpNextString;
cchSize = lstrlen(lpStart)+1; lppszSubStr[i][nIndex] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize); if(!lppszSubStr[i][nIndex]) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } StrCpyN(lppszSubStr[i][nIndex], lpStart, cchSize); lpStart = lpTemp; nIndex++; } else lpTemp = CharNext(lpTemp); }
if(nIndex==nSubStr[i]-1) { //we're off by one
cchSize = lstrlen(lpStart)+1; lppszSubStr[i][nIndex] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize); if(!lppszSubStr[i][nIndex]) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } StrCpyN(lppszSubStr[i][nIndex], lpStart, cchSize); }
for(j=0;j<nSubStr[i];j++) TrimSpaces(lppszSubStr[i][j]);
} } // for i ...
if(!pt_bIsWABOpenExSession) { // Lock the file
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; } }
// Get an index of all entries in the WAB
PropRes.ulPropTag = PR_DISPLAY_NAME; PropRes.relop = RELOP_EQ; PropRes.lpProp = NULL;
hr = FindRecords( IN hPropertyStore, IN lpsbCont, IN AB_MATCH_PROP_ONLY, FALSE, &PropRes, &ulEIDCount, &rgsbEntryIDs);
ulFoundIndex = 0;
if(!pt_bIsWABOpenExSession) { hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; } }
for(i=0;i<ulEIDCount;i++) { if(!pt_bIsWABOpenExSession) { DWORD dwEID = 0; CopyMemory(&dwEID, rgsbEntryIDs[i].lpb, rgsbEntryIDs[i].cb); hr = ReadRecordWithoutLocking( hMPSWabFile, lpMPSWabFileInfo, dwEID, &ulcPropCount, &lpPropArray); } else { hr = ReadRecord(hPropertyStore, &rgsbEntryIDs[i], 0, &ulcPropCount, &lpPropArray); }
if(HR_FAILED(hr)) goto endloop;
bFoundName = NOTFOUND; bFoundEmail = NOTFOUND; bFoundAddress = NOTFOUND; bFoundPhone = NOTFOUND; bFoundOther = NOTFOUND;
for(j=0;j<ulcPropCount;j++) { switch(lpPropArray[j].ulPropTag) { case PR_DISPLAY_NAME: case PR_GIVEN_NAME: case PR_SURNAME: case PR_NICKNAME: case PR_MIDDLE_NAME: case PR_COMPANY_NAME: if(bFindName == DONTFIND) continue; if(bFoundName == FOUND) continue; bFound = TRUE; for(k=0;k<nSubStr[ldspDisplayName];k++) { if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspDisplayName][k],lcid)) { bFound = FALSE; break; } } if(bFound) { bFoundName = FOUND; continue; } break;
case PR_EMAIL_ADDRESS: case PR_ADDRTYPE: if(bFindEmail == DONTFIND) continue; if(bFoundEmail == FOUND) continue; bFound = TRUE; for(k=0;k<nSubStr[ldspEmail];k++) { if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspEmail][k],lcid)) { bFound = FALSE; break; } } if(bFound) { bFoundEmail = FOUND; continue; } break;
case PR_HOME_ADDRESS_STREET: case PR_HOME_ADDRESS_CITY: case PR_HOME_ADDRESS_POSTAL_CODE: case PR_HOME_ADDRESS_STATE_OR_PROVINCE: case PR_HOME_ADDRESS_COUNTRY: case PR_BUSINESS_ADDRESS_STREET: case PR_BUSINESS_ADDRESS_CITY: case PR_BUSINESS_ADDRESS_POSTAL_CODE: case PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE: case PR_BUSINESS_ADDRESS_COUNTRY: if(bFindAddress == DONTFIND) continue; if(bFoundAddress == FOUND) continue; bFound = TRUE; for(k=0;k<nSubStr[ldspAddress];k++) { if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspAddress][k],lcid)) { bFound = FALSE; break; } } if(bFound) { bFoundAddress = FOUND; continue; } break;
case PR_HOME_TELEPHONE_NUMBER: case PR_HOME_FAX_NUMBER: case PR_CELLULAR_TELEPHONE_NUMBER: case PR_BUSINESS_TELEPHONE_NUMBER: case PR_BUSINESS_FAX_NUMBER: case PR_PAGER_TELEPHONE_NUMBER: if(bFindPhone == DONTFIND) continue; if(bFoundPhone == FOUND) continue; bFound = TRUE; for(k=0;k<nSubStr[ldspPhone];k++) { if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspPhone][k],lcid)) { bFound = FALSE; break; } } if(bFound) { bFoundPhone = FOUND; continue; } break; case PR_TITLE: case PR_DEPARTMENT_NAME: case PR_OFFICE_LOCATION: case PR_COMMENT: case PR_BUSINESS_HOME_PAGE: case PR_PERSONAL_HOME_PAGE: if(bFindOther == DONTFIND) continue; if(bFoundOther == FOUND) continue; bFound = TRUE; for(k=0;k<nSubStr[ldspOther];k++) { if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspOther][k],lcid)) { bFound = FALSE; break; } } if(bFound) { bFoundOther = FOUND; continue; } break; } //switch
}// for j
if ((bFindName +bFindEmail +bFindPhone +bFindAddress +bFindOther) != (bFoundName+bFoundEmail+bFoundPhone+bFoundAddress+bFoundOther)) goto endloop;
// doublecheck that we didnt get a container entry here
for(j=0;j<ulcPropCount;j++) { if( lpPropArray[j].ulPropTag == PR_OBJECT_TYPE) { if(lpPropArray[j].Value.l == MAPI_ABCONT) goto endloop; break; } }
// match!
CopyMemory(rgsbEntryIDs[ulFoundIndex].lpb, rgsbEntryIDs[i].lpb, rgsbEntryIDs[i].cb); ulFoundIndex++;
endloop: if(ulcPropCount && lpPropArray) { ReadRecordFreePropArray(hPropertyStore, ulcPropCount, &lpPropArray); lpPropArray = NULL; } } // for i
if(ulFoundIndex) { *lpulFoundCount = ulFoundIndex; *lprgsbEntryIDs = rgsbEntryIDs; }
hr = S_OK;
out:
ReadRecordFreePropArray(hPropertyStore, ulcPropCount, &lpPropArray);
for(i=0;i<ldspMAX;i++) { if(lppszSubStr[i]) { for(j=0;j<nSubStr[i];j++) LocalFree(lppszSubStr[i][j]); LocalFree(lppszSubStr[i]); } }
if(!*lpulFoundCount || !*lprgsbEntryIDs) { if(rgsbEntryIDs) FreeEntryIDs(hPropertyStore, ulEIDCount, rgsbEntryIDs); } else if(ulFoundIndex && (ulFoundIndex < ulEIDCount) && !pt_bIsWABOpenExSession) { // We will leak anything we are not using here so clear up before exiting
// Do this only if this is a WAB session because then that memory was LocalAlloced
// and can be partially freed up here
for(i=ulFoundIndex;i<ulEIDCount;i++) { if(rgsbEntryIDs[i].lpb) LocalFree(rgsbEntryIDs[i].lpb); } }
if(!pt_bIsWABOpenExSession) { if(hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);) }
if(!pt_bIsWABOpenExSession && bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
return hr; }
//$$
//
// Determines if the disk on which WAB resides has free space or not..
// Free space is defined as space being equal too or more than the size
// of the current WAB file. If the available space is less than the size
// of the WAB file, this function will return false ...
//
BOOL WABHasFreeDiskSpace(LPTSTR lpszName, HANDLE hFile) { TCHAR szBuf[MAX_PATH]; DWORD dwWABSize=0; DWORDLONG dwDiskFreeSpace = 0; DWORD SectorsPerCluster=0; DWORD BytesPerSector=0; DWORD NumberOfFreeClusters=0; DWORD TotalNumberOfClusters=0; BOOL bRet = TRUE;
szBuf[0]='\0'; StrCpyN(szBuf, lpszName, ARRAYSIZE(szBuf)); TrimSpaces(szBuf); if(lstrlen(szBuf)) { dwWABSize = GetFileSize(hFile, NULL);
{ LPTSTR lpszFirst = szBuf; LPTSTR lpszSecond = CharNext(szBuf); LPTSTR lpRoot = NULL; LPTSTR lpTemp; ULONG ulCount = 0;
if(*lpszFirst == '\\' && *lpszSecond == '\\') { // This looks like a network share ..
// There doesnt seem to be any way to determine disk space
// on a network share .. so we will try to copy the wab
// file into a tmp file and delete the tmp file. If this operation
// succeeds we have plenty of disk space. If it fails we dont have any
// space
TCHAR szTmp[MAX_PATH]; StrCpyN(szTmp, szBuf, ARRAYSIZE(szTmp));
// our temp file name is the wab file name with a - instead of the last char
lpTemp = szTmp; while(*lpTemp) lpTemp = CharNext(lpTemp); lpTemp = CharPrev(szTmp, lpTemp); if(*lpTemp != '-') *lpTemp = '-'; else *lpTemp = '_';
if(!CopyFile(szBuf, szTmp, FALSE)) { bRet = FALSE; } else DeleteFile(szTmp); /***
lpTemp = CharNext(lpszSecond); while(*lpTemp) { if(*lpTemp == '\\') { ulCount++; if (ulCount == 1) { //lpTemp=CharNext(lpTemp);
*lpTemp = '\0'; break; } } lpTemp = CharNext(lpTemp); } ***/ } else { if(*lpszSecond == ':') { lpTemp = CharNext(lpszSecond); if(*lpTemp != '\\') *lpTemp = '\0'; else { lpTemp = CharNext(lpTemp); *lpTemp = '\0'; } } else { *lpszFirst = '\0'; } if(lstrlen(szBuf)) lpRoot = szBuf; if( GetDiskFreeSpace(lpRoot, &SectorsPerCluster, // address of sectors per cluster
&BytesPerSector, // address of bytes per sector
&NumberOfFreeClusters, // address of number of free clusters
&TotalNumberOfClusters // address of total number of clusters
) ) { dwDiskFreeSpace = BytesPerSector * SectorsPerCluster * NumberOfFreeClusters;
if(dwDiskFreeSpace < ((DWORDLONG) dwWABSize) ) bRet = FALSE; } else { DebugTrace(TEXT("GetDiskFreeSpace failed: %d\n"),GetLastError()); } } }
}
return bRet; }
|