You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4430 lines
144 KiB
4430 lines
144 KiB
////////////////////////////////////////////////////////////////////////////////
|
|
///
|
|
///
|
|
/// 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;
|
|
}
|
|
|