//////////////////////////////////////////////////////////////////////////////// /// /// /// 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;iIndexData[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;iIndexData[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;ilpMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out; if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries != lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries) lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED; for(i=indexDisplayName;ilpMPSWabFileHeader->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; ilpMPSWabFileHeader->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; ilpMPSWabFileHeader->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;ilpMPSWabIndexEID[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;ilpMPSWabIndexEID[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;ilpMPSWabIndexEID[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;ilpMPSWabIndexStr[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;ilpMPSWabIndexStr[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;ilpMPSWabFileHeader->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 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;icb == 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 // else // // unless PropType is MV_BINARY or MV_TSTRING in which case we need a // more flexible data storage // // // ... // ulRecordDataSize += sizeof(ULONG); // holds if ((lpPropArray[i].ulPropTag & MV_FLAG)) { // // multi-valued // lpulrgPropDataSize[i] = SizeOfMultiPropData(lpPropArray[i]); //Data ulRecordDataSize += sizeof(ULONG); // holds } else { // // single-valued // lpulrgPropDataSize[i] = SizeOfSinglePropData(lpPropArray[i]); //Data } ulRecordDataSize += sizeof(ULONG) // holds + lpulrgPropDataSize[i]; //holds } 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; iData1,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 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 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;ilpszMPSWabFileName, NULL, &hMPSWabFile); if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; } } for(i=0;i