home *** CD-ROM | disk | FTP | other *** search
- /*
- * M S P T B L . C
- *
- * Functions to manage a hierarchy and contents tables cached on disk.
- *
- * Copyright 1992-1995 Microsoft Corporation. All Rights Reserved.
- */
-
- #include "msp.h"
-
- static SCODE ScCreateFile(LPTSTR szFile, ULONG ulAccess, ULONG ulShare,
- ULONG ulCreate, HANDLE * lphFile);
- static HRESULT HrOpenTblFileRetry(LPTSTR szFile, ULONG ulAccess, ULONG ulShare,
- ULONG ulCreate, HANDLE * lphFile);
- static HRESULT HrNewCounts(PIFLD pifld, LPTABLEDATA lptbl);
- static HRESULT HrReadBytes(HANDLE hFile, LPVOID lpBuffer, ULONG cbToRead,
- BOOL * pfEOF);
- static HRESULT HrWriteBytes(HANDLE hFile, LPVOID lpBuffer, ULONG cbToWrite);
- static HRESULT HrWriteRow(HANDLE hFile, LPSRow prw);
- static VOID TranslateFileError(BOOL fSuccess, ULONG cbIn, ULONG cbOut,
- BOOL * pfEOF, SCODE * pscFile);
- static HRESULT HrGetTime(LPSRow prw, FILETIME * pfiletime);
- static HRESULT HrRemoveBadTableRows(LPTABLEDATA lptbl, PIFLD pifldParent,
- PIMS pims, BOOL * pfTableChanged);
- static HRESULT HrAddMissingTableRows(LPTABLEDATA lptbl, PIFLD pifld,
- LPSTR szTemplate, LPSPropTagArray ptaga, BOOL * pfTableChanged);
-
-
-
- /* format of a row of table data on disk (DRW) */
- typedef struct _DRW
- {
- ULONG cbRow;
- SRow rw;
- BYTE ab[MAPI_DIM];
- } DRW, *PDRW;
-
- #define CbNewDRW(_cb) (offsetof(DRW,ab) + (_cb))
- #define CbDRW(_pdrw) (offsetof(DRW,ab) + (UINT)((_pdrw)->cbRow))
-
-
- /****************************************************************************
- * ScCreateFile
- *
- * Purpose Open or create a file
- *
- * Parameters
- * szFile name of the file
- * ulAccess read/write access desired see CreateFile
- * ulShare sharing desired see CreateFile
- * ulCreate creation disposition see CreateFile
- * lphFile returns handle of open file, undefined if call fails
- *
- */
- static SCODE
- ScCreateFile(LPTSTR szFile, ULONG ulAccess, ULONG ulShare,
- ULONG ulCreate, HANDLE * lphFile)
- {
- HANDLE hFile;
- SCODE sc = S_OK;
-
- hFile = CreateFile(szFile, ulAccess, ulShare, NULL,
- ulCreate, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
-
- if (hFile == INVALID_HANDLE_VALUE)
- {
- switch (GetLastError())
- {
- case ERROR_FILE_NOT_FOUND:
- sc = MAPI_E_NOT_FOUND;
- break;
-
- case ERROR_SHARING_VIOLATION:
- case ERROR_LOCK_VIOLATION:
- sc = MAPI_E_BUSY;
- break;
-
- default:
- sc = MAPI_E_NO_ACCESS;
- break;
- }
- }
- else
- {
- AssertSz(!IsBadWritePtr(lphFile, sizeof(HANDLE)), "Bad parameter"
- " (lphFile) given to ScCreateFile");
-
- *lphFile = hFile;
- }
-
- DebugTraceSc(ScCreateFile, sc);
- return sc;
- }
-
- /*
- * HrOpenTblFileRetry
- *
- * Purpose Open or create a file, but retry if it is busy
- *
- * Parameters
- * szFile name of the file
- * ulAccess read/write access desired see CreateFile
- * ulShare sharing desired see CreateFile
- * ulCreate creation disposition see CreateFile
- * lphFile returns handle of open file, undefined if call fails
- *
- */
- static HRESULT HrOpenTblFileRetry(LPTSTR szFile, ULONG ulAccess, ULONG ulShare,
- ULONG ulCreate, HANDLE * lphFile)
- {
- UINT iRetry;
- SCODE sc = S_OK;
- HANDLE hFile;
-
- iRetry = 0;
- while (TRUE)
- {
- sc = ScCreateFile(szFile, ulAccess, ulShare, ulCreate, &hFile);
-
- if (sc != MAPI_E_BUSY || ++iRetry >= NUM_RETRIES)
- break;
-
- Sleep(500);
- }
-
- if (sc == S_OK)
- *lphFile = hFile;
-
- #ifdef DEBUG
- if (iRetry >= NUM_RETRIES)
- TraceSz("HrOpenTblFileRetry: Failing open. Too many tries.");
- #endif
-
- DebugTraceSc(HrOpenTblFileRetry, sc);
- return ResultFromScode(sc);
- }
-
- /*
- * HrWriteCounts
- *
- * Purpose
- * This function writes the counts of messages and unread messages
- * in a folder to the folder's property file. After the code
- * validates what the counts should be, this function writes the
- * counts so that they are correct.
- *
- * Parameters
- * pifld: A pointer to the folder object to update.
- * ulMsgs: The number of messages in the folder.
- * ulUnread: The number of unread messages in the folder.
- *
- */
- static HRESULT HrWriteCounts(PIFLD pifld, ULONG ulMsgs, ULONG ulUnread)
- {
- HRESULT hr;
- LPMESSAGE lpmsg = NULL;
- PLMR plmr = &pifld->pims->lmr;
- ULONG ulMsgsCopy = ulMsgs; /* workaround - MS C code-gen bug */
-
- hr = HrOpenPropertyMessageRetry(pifld->peid, pifld->pims, TRUE, &lpmsg);
- if (hr != hrSuccess)
- goto exit;
-
- hr = HrSetOneROProp(lpmsg, plmr, PR_CONTENT_COUNT, &ulMsgsCopy);
- if (hr != hrSuccess)
- goto exit;
-
- hr = HrSetOneROProp(lpmsg, plmr, PR_CONTENT_UNREAD, &ulUnread);
- if (hr != hrSuccess)
- goto exit;
-
- hr = lpmsg->lpVtbl->SaveChanges(lpmsg, FORCE_SAVE);
-
- exit:
- UlRelease(lpmsg);
-
- DebugTraceResult(HrWriteCounts, hr);
- return hr;
- }
-
- /*
- * HrNewCounts
- *
- * Purpose Make the contents count and unread count of the folder in pifld
- * agree with the data in the contents table lptbl
- *
- * Parameters
- * pifld the folder
- * lptbl the table
- */
- static HRESULT HrNewCounts(PIFLD pifld, LPTABLEDATA lptbl)
- {
- HRESULT hr = hrSuccess;
- ULONG cMessages = 0;
- ULONG cUnread = 0;
- LPSRow lpsRow = NULL;
- ULONG ulRow = 0;
- PLMR plmr = &pifld->pims->lmr;
- LPMESSAGE lpmsg = NULL;
-
- /* check each row in the table to see if the message has been read */
-
- while (TRUE)
- {
- LPSPropValue pval;
- LPSPropValue pvalMax;
-
- hr = lptbl->lpVtbl->HrEnumRow(lptbl, ulRow++, &lpsRow);
- if (hr != hrSuccess)
- goto exit;
-
- if (lpsRow == NULL)
- break;
-
- cMessages++;
-
- pval = lpsRow->lpProps;
- pvalMax = pval + lpsRow->cValues;
-
- /* check PR_MESSAGE_FLAGS to see if this message is unread */
- while (pval < pvalMax)
- {
- if (pval->ulPropTag == PR_MESSAGE_FLAGS)
- {
- if (!(pval->Value.l & MSGFLAG_READ))
- cUnread++;
- break;
- }
- pval++;
- }
-
- LMFree(&pifld->pims->lmr, lpsRow);
- lpsRow = NULL;
- }
-
- hr = HrWriteCounts(pifld, cMessages, cUnread);
-
- exit:
- LMFree(&pifld->pims->lmr, lpsRow);
-
- DebugTraceResult(HrNewCounts, hr);
- return hr;
- }
-
- /**********************************************************************
- * HrGetTableName
- *
- * Purpose
- * Given an open object and the kind of table
- * returns the full path name of the file that caches that table's data.
- * Must be freed with FreeNull.
- *
- * Parameters
- * pobj object whose table is needed
- * szEIDPath EID path (may be NULL)
- * szFileName Name of the file that holds the table.
- * lppszTable pointer to storage for the path name of the table file
- */
- HRESULT HrGetTableName(POBJ pobj, LPSTR szEIDPath, LPSTR szFileName,
- LPSTR *pszTable)
- {
- LPTSTR szDir = NULL; /* Full Path name of directory containing table */
- HRESULT hr = hrSuccess;
- PIMS pims = pobj->pims;
-
- Assert(!IsBadWritePtr(pszTable, sizeof(LPTSTR)));
-
- hr = HrFullPathName(pims->szStorePath, szEIDPath, NULL, &szDir);
- if (hr != hrSuccess)
- goto exit;
-
- /* get memory to hold the filename that contains the table. */
- /* Add 1 char for the backslash before the filename. */
-
- hr = HrAlloc(CCH_NAME * sizeof(TCHAR)
- + ((lstrlen(szDir) + 1) * sizeof(TCHAR)), (PPV) pszTable);
- if (hr != hrSuccess)
- goto exit;
-
- lstrcpy(*pszTable, szDir);
- lstrcat(*pszTable, "\\");
- lstrcat(*pszTable, szFileName);
-
- exit:
- FreeNull(szDir);
- DebugTraceResult(HrGetTableName, hr);
- return hr;
- }
-
- /**********************************************************************
- * HrReadBytes
- *
- * Read a number of bytes from a file into a buffer, checking for errors and
- * end-of-file.
- *
- * Parameters:
- *
- * hFile: File handle to read from.
- * lpBuffer: Pointer to a buffer to read into. The buffer should be big
- * enough to hold the incoming data.
- * cbToRead: The number of bytes to read. Should be <= UINT_MAX.
- * pfEOF: A pointer to the location to return a boolean specifying
- * whether the read encountered an end-of-file. If it did, the
- * buffer will return with no data in it. This pointer may be NULL,
- * in which case end-of-file will be treated as an error.
- *
- * Returns:
- * HRESULT (either a file read error, or MAPI_E_CALL_FAILED when either
- * EOF is encountered and pfEOF is NULL, or when the number of
- * bytes read is less than the number requested).
- */
- static HRESULT HrReadBytes(HANDLE hFile, LPVOID lpBuffer, ULONG cbToRead,
- BOOL *pfEOF)
- {
- SCODE sc = S_OK;
- ULONG cbRead = 0;
- BOOL fSuccess;
-
- AssertSz(cbToRead <= UINT_MAX && !IsBadWritePtr(lpBuffer, (UINT) cbToRead),
- "Bad buffer");
-
- fSuccess = ReadFile(hFile, lpBuffer, cbToRead, &cbRead, NULL);
-
- TranslateFileError(fSuccess, cbToRead, cbRead, pfEOF, &sc);
-
- DebugTraceSc(HrReadBytes, sc);
- return ResultFromScode(sc);
- }
-
- /**********************************************************************
- * HrWriteBytes
- *
- * Write a number of bytes from a buffer into a file, checking for errors.
- *
- * Parameters:
- *
- * hFile: File handle to write into.
- * lpBuffer: Pointer to a buffer containing the data to write.
- * cbToRead: The number of bytes to write. Should be <= UINT_MAX.
- *
- * Returns:
- * HRESULT (either a file write error, or MAPI_E_CALL_FAILED when the
- * number of bytes written is less than the number requested).
- */
- static HRESULT HrWriteBytes(HANDLE hFile, LPVOID lpBuffer, ULONG cbToWrite)
- {
- SCODE sc = S_OK;
- ULONG cbWritten = 0;
- BOOL fSuccess;
-
- AssertSz(cbToWrite <= UINT_MAX && !IsBadReadPtr(lpBuffer, (UINT) cbToWrite),
- "Bad buffer");
-
- fSuccess = WriteFile(hFile, lpBuffer, cbToWrite, &cbWritten, NULL);
-
- TranslateFileError(fSuccess, cbToWrite, cbWritten, NULL, &sc);
-
- DebugTraceSc(HrWriteBytes, sc);
- return ResultFromScode(sc);
- }
-
- /**********************************************************************
- * TranslateFileError
- *
- * Checks for errors from a windows ReadFile or WriteFile call, translating
- * windows error codes to MAPI errors, and, if requested, checking for end-of-
- * file. Also checks to make sure the number of bytes read or written equals
- * the number given as input.
- *
- * Parameters:
- *
- * fSuccess: The return value from ReadFile or WriteFile.
- * cbIn: The number of bytes given as input to ReadFile or WriteFile.
- * cbOut: The number of bytes returned from ReadFile or WriteFile.
- * pfEOF: A pointer to the location to return a BOOL specifying
- * whether cbOut was 0 and fSuccess was TRUE. This condition
- * indicates end-of-file when reading, and should not be treated
- * as an error. The pointer may be NULL, in which case, this
- * condition is treated as an error, and *psc is returned with
- * MAPI_E_CALL_FAILED.
- * psc: A pointer to the location to return an SCODE indicating
- * the success or failure of the ReadFile or WriteFile.
- *
- * Returns: VOID
- */
- static VOID TranslateFileError(BOOL fSuccess, ULONG cbIn, ULONG cbOut,
- BOOL *pfEOF, SCODE *pscFile)
- {
- SCODE sc = S_OK;
- BOOL fEOF = FALSE;
- BOOL fCheckEOF = (pfEOF != NULL);
-
- if (!fSuccess)
- {
- DWORD dwError = GetLastError();
-
- if (dwError != 0)
-
- switch (dwError)
- {
- case 0:
- TraceSz("SampleMS: ScTranslateFileError found unexpected "
- "success\n");
- break;
-
- case ERROR_SHARING_VIOLATION:
- case ERROR_LOCK_VIOLATION:
- sc = MAPI_E_BUSY;
- break;
-
- case ERROR_FILE_NOT_FOUND:
- sc = MAPI_E_NOT_FOUND;
- break;
-
- case ERROR_TOO_MANY_OPEN_FILES:
- sc = MAPI_E_NOT_ENOUGH_RESOURCES;
- break;
-
- case ERROR_ACCESS_DENIED:
- case ERROR_INVALID_ACCESS:
- case ERROR_INVALID_DRIVE:
- sc = MAPI_E_NO_ACCESS;
- break;
-
- default:
- sc = MAPI_E_CALL_FAILED;
- break;
- }
- }
- else if (cbOut != cbIn)
- {
- sc = MAPI_E_CALL_FAILED;
-
- /* If the caller wants to discriminate end-of-file from other */
- /* errors, and the file call returned zero bytes, return EOF, */
- /* and don't return an error. */
-
- if (fCheckEOF && cbOut == 0)
- {
- sc = S_OK;
- fEOF = TRUE;
- }
- }
-
- AssertSz(!IsBadWritePtr(pscFile, sizeof(SCODE)), "Bad parameter (pscFile) "
- "given to TranslateFileError");
-
- *pscFile = sc;
-
- if (pfEOF)
- {
- AssertSz(!IsBadWritePtr(pfEOF, sizeof(BOOL)), "Bad parameter (pfEOF) "
- "given to TranslateFileError");
- *pfEOF = fEOF;
- }
-
- return;
- }
-
- /*
- * HrWriteRow
- *
- * Purpose
- * Writes one row of data to the file handle given.
- *
- * Arguments
- * hFile: File handle to update.
- * prw: Pointer to the row to write.
- *
- * RETURNS: HRESULT
- */
- static HRESULT HrWriteRow(HANDLE hFile, LPSRow prw)
- {
- HRESULT hr = hrSuccess;
- SCODE sc;
- ULONG cb;
- PDRW pdrw = NULL;
-
- sc = ScCountProps((UINT) prw->cValues, prw->lpProps, &cb);
- if (sc != S_OK)
- {
- hr = ResultFromScode(sc);
- goto exit;
- }
-
- /* Allocate space for the disk row */
- hr = HrAlloc(CbNewDRW(cb), &pdrw);
- if (hr != hrSuccess)
- goto exit;
-
- /* fill in the disk row structure */
-
- pdrw->cbRow = cb;
- pdrw->rw.cValues = prw->cValues;
-
- /* The lpProps field of the row we write should be point at the */
- /* row we are writing (i.e., pdrw->ab). We will use that pointer */
- /* value when we read the data off disk to fixup the pointers via */
- /* ScRelocProps. */
- pdrw->rw.lpProps = (LPSPropValue) pdrw->ab;
-
- sc = ScCopyProps((UINT) prw->cValues, prw->lpProps, &(pdrw->ab), NULL);
- if (sc != S_OK)
- {
- hr = ResultFromScode(sc);
- goto exit;
- }
-
- /* write the row */
- hr = HrWriteBytes(hFile, pdrw, CbDRW(pdrw));
- if (hr != hrSuccess)
- goto exit;
-
- exit:
- FreeNull(pdrw);
-
- DebugTraceResult(HrWriteRow, hr);
- return hr;
- }
-
- /*************************************************************************
- * HrWriteTableOnDisk
- *
- * Purpose
- * write the table in lptbl to the disk image of lpvObjects table
- * of type ulType
- *
- * lptbl Table to be written
- * pobj object whose table is to be written
- * szEIDPath Pathname of the EID of the folder, or NULL
- * szFileName Name of the file that holds this table type.
- *
- */
- HRESULT HrWriteTableOnDisk(LPTABLEDATA lptbl, POBJ pobj, LPSTR szEIDPath,
- LPSTR szFileName)
- {
- LPTSTR szFile = NULL;
- HANDLE hFile = INVALID_HANDLE_VALUE; /* handle to open file */
- LPSRow lpsRow = NULL; /* next row to be written */
- ULONG ulRowNumber; /* number of the row being written */
- HRESULT hr = hrSuccess;
- PLMR plmr = &pobj->pims->lmr;
-
- /* get the name of the file holding the table */
- hr = HrGetTableName(pobj, szEIDPath, szFileName, &szFile);
- if (hr != hrSuccess)
- goto exit;
-
- /* open the file with exclusive access */
-
- hr = HrOpenTblFileRetry(szFile, GENERIC_WRITE, 0L, CREATE_ALWAYS, &hFile);
- if (hr != hrSuccess)
- goto exit;
-
- /* write the table data to the file */
- ulRowNumber = 0;
- while (TRUE)
- {
- hr = lptbl->lpVtbl->HrEnumRow(lptbl, ulRowNumber, &lpsRow);
- if (hr != hrSuccess)
- goto exit;
- if (lpsRow == NULL)
- break;
-
- hr = HrWriteRow(hFile, lpsRow);
- if (hr != hrSuccess)
- goto exit;
-
- LMFree(plmr, lpsRow);
- lpsRow = NULL;
- ulRowNumber++;
- }
-
- exit:
- AssertSz(GetScode(hr) != MAPI_W_ERRORS_RETURNED,
- "Unexpected warning return");
-
- /* Set the end of file marker, in case we shrank the file. */
- if (hr == hrSuccess && SetEndOfFile(hFile) == FALSE)
- hr = ResultFromScode(MAPI_E_DISK_ERROR);
-
- if (hFile != INVALID_HANDLE_VALUE)
- CloseHandle(hFile);
-
- /* erase the file if in error */
- if (hr != hrSuccess && szFile)
- DeleteFile(szFile);
-
- FreeNull(szFile);
- LMFree(plmr, lpsRow);
-
- DebugTraceResult(HrWriteTableOnDisk, hr);
- return hr;
- }
-
- /*************************************************************************
- * HrReadTableFromDisk
- *
- * Purpose
- * Read a table from this disk cache into the table lptbl
- *
- * lptbl the table to be built
- * pobj object whose table is to be read
- * szEIDPath Pathname of the EID of the folder, or NULL
- * cCols Number of columns in this type of table
- * szFileName Name of the file that holds this table type.
- */
- HRESULT HrReadTableFromDisk(LPTABLEDATA lptbl, POBJ pobj, LPSTR szEIDPath,
- ULONG cCols, LPSTR szFileName)
- {
- HRESULT hr;
- PLMR plmr;
- BOOL fBadTableData = FALSE;
- LPTSTR szFile = NULL;
- HANDLE hFile = INVALID_HANDLE_VALUE;
- PDRW pdrw = NULL;
-
- plmr = &pobj->pims->lmr;
-
- /* get the name of the file holding the table */
- hr = HrGetTableName(pobj, szEIDPath, szFileName, &szFile);
- if (hr != hrSuccess)
- goto exit;
-
- /* open the file */
- hr = HrOpenTblFileRetry(szFile, GENERIC_READ, FILE_SHARE_READ,
- OPEN_ALWAYS, &hFile);
- if (hr != hrSuccess)
- {
- /* If the file wasn't found, then simply leave the table empty, */
- /* and return success. */
-
- if (GetScode(hr) == MAPI_E_NOT_FOUND)
- hr = hrSuccess;
-
- goto exit;
- }
-
- while (TRUE)
- {
- BOOL fEOF;
- DRW drwTemp;
- ULONG cbOut;
- SCODE sc;
-
- /* Read the beginning of the disk row. */
- hr = HrReadBytes(hFile, &drwTemp, CbNewDRW(0), &fEOF);
- if (hr != hrSuccess)
- goto exit;
-
- if (fEOF)
- break;
-
- /* Sanity check for bad data. */
- /* Note that the number of columns in the disk version of the */
- /* table can be less than the number of columns in the in-memory */
- /* table due to properties that were missing from the message */
- /* when it was written to disk. */
-
- if ( drwTemp.rw.cValues > cCols
- || drwTemp.rw.cValues == 0
- || drwTemp.cbRow < drwTemp.rw.cValues * sizeof(SPropValue))
- {
- hr = ResultFromScode(MAPI_E_CORRUPT_DATA);
- fBadTableData = TRUE;
- goto exit;
- }
-
- hr = HrAlloc(CbNewDRW(drwTemp.cbRow), &pdrw);
- if (hr != hrSuccess)
- goto exit;
-
- memcpy(pdrw, &drwTemp, CbNewDRW(0));
-
- /* read the rest of the row */
- hr = HrReadBytes(hFile, &pdrw->ab, pdrw->cbRow, NULL);
- if (hr != hrSuccess)
- {
- fBadTableData = TRUE;
- goto exit;
- }
-
- sc = ScRelocProps((UINT) pdrw->rw.cValues, (LPSPropValue) pdrw->ab,
- pdrw->rw.lpProps, &pdrw->ab, &cbOut);
- if (sc != S_OK || cbOut != pdrw->cbRow)
- {
- hr = ResultFromScode(MAPI_E_CORRUPT_DATA);
- fBadTableData = TRUE;
- goto exit;
- }
-
- pdrw->rw.lpProps = (LPSPropValue) pdrw->ab;
-
- /* add this row to the table */
- hr = lptbl->lpVtbl->HrModifyRow(lptbl, &pdrw->rw);
- if (hr != hrSuccess)
- goto exit;
-
- FreeNull(pdrw);
- pdrw = NULL;
- }
-
- exit:
- if (hFile != INVALID_HANDLE_VALUE)
- CloseHandle(hFile);
-
- /* erase the file if it is bogus. We will regenerate it if we can. */
- if (fBadTableData)
- DeleteFile(szFile);
-
- FreeNull(szFile);
- FreeNull(pdrw);
-
- DebugTraceResult(HrReadTableFromDisk, hr);
- return hr;
- }
-
- /************************************************************************
- * HrGetTime
- *
- * Purpose return the value of PR_LAST_MODIFICATION_TIME from the properties
- * in the given property array
- *
- * Parameters
- * prw pointer to the table row to search
- * pfiletime pointer to last modification time
- */
- static HRESULT HrGetTime(LPSRow prw, FILETIME *pfiletime)
- {
- LPSPropValue pvalT;
- LPSPropValue pvalMax;
- SCODE sc = MAPI_E_NOT_FOUND;
-
- Assert(!IsBadReadPtr(prw, sizeof(SRow)));
- Assert(prw->cValues <= UINT_MAX / sizeof(SPropValue));
- Assert(!IsBadReadPtr(prw->lpProps, ((UINT) prw->cValues) * sizeof(SPropValue)));
- Assert(!IsBadWritePtr(pfiletime, sizeof(FILETIME)));
-
- pvalT = prw->lpProps;
- pvalMax = pvalT + prw->cValues;
-
- while (pvalT < pvalMax)
- {
- if (pvalT->ulPropTag == PR_LAST_MODIFICATION_TIME)
- {
- sc = S_OK;
- *pfiletime = pvalT->Value.ft;
- break;
- }
- pvalT++;
- }
-
- DebugTraceSc(HrGetTime, sc);
- return ResultFromScode(sc);
- }
-
- /*************************************************************************
- * HrSyncOutgoingTable
- *
- * Purpose
- * Verifies that every table row in memory actually corresponds to
- * a message on disk. If bad rows are found, removes them and
- * rewrites the disk version of the table data. Note that this code
- * does not verify that the message on disk actually is in the queue,
- * nor does it check for messages that are somehow missing from the table.
- *
- * lptbl pointer to the outgoing table data object.
- * pims a pointer to the message store object.
- *
- */
- HRESULT HrSyncOutgoingTable(LPTABLEDATA lptbl, PIMS pims)
- {
- HRESULT hr;
- BOOL fRowsRemoved;
-
- hr = HrRemoveBadTableRows(lptbl, NULL, pims, &fRowsRemoved);
-
- if (hr == hrSuccess && fRowsRemoved)
- hr = HrWriteTableOnDisk(lptbl, (POBJ) pims, NULL, szOutgoingFileName);
-
- DebugTraceResult(HrSyncOutgoingTable, hr);
- return hr;
- }
-
- /*************************************************************************
- * HrSyncContentsTable
- *
- * Purpose
- * Verifies that the table in memory agrees with what's on disk.
- * If discrepancies are found, fixes them, and rewrites the disk
- * version of the table data.
- *
- * pifld the parent folder of the contents table.
- * fWriteTable if TRUE, write the disk version of the table if the
- * in-memory table is out of sync.
- *
- */
- HRESULT HrSyncContentsTable(PIFLD pifld, BOOL fWriteTable)
- {
- HRESULT hr;
- BOOL fRowsRemoved;
- BOOL fRowsAdded;
- LPTABLEDATA lptbl;
-
- lptbl = pifld->lptblContents;
-
- hr = HrRemoveBadTableRows(lptbl, pifld, pifld->pims, &fRowsRemoved);
- if (hr != hrSuccess)
- goto exit;
-
- hr = HrAddMissingTableRows(lptbl, pifld, szMessageTemplate,
- (LPSPropTagArray) &sPropTagsContents, &fRowsAdded);
- if (hr != hrSuccess)
- goto exit;
-
- /* update folder's content count and unread count if */
- /* the table was out of ssync */
-
- if (fRowsRemoved || fRowsAdded)
- {
- hr = HrNewCounts(pifld, lptbl);
- if (hr != hrSuccess)
- goto exit;
-
- if (fWriteTable)
- {
- hr = HrWriteTableOnDisk(lptbl, (POBJ) pifld, pifld->peid->szPath,
- szContentsFileName);
- if (hr != hrSuccess)
- goto exit;
- }
- }
- else
- {
- /* If there aren't any rows in the table, we still need to
- * update the folder's count of messages, because the counts
- * may not be zero, even though there aren't any messages on disk.
- */
- LPSRow lpSRow = NULL;
-
- hr = lptbl->lpVtbl->HrEnumRow(lptbl, 0, &lpSRow);
- if (hr != hrSuccess)
- goto exit;
-
- if (lpSRow == NULL)
- hr = HrWriteCounts(pifld, 0, 0);
-
- LMFree(&pifld->pims->lmr, lpSRow);
- }
-
- exit:
- DebugTraceResult(HrSyncContentsTable, hr);
- return hr;
- }
-
- /*************************************************************************
- * HrRemoveBadTableRows
- *
- * Purpose
- * Verifies that every row in the table given has a corresponding
- * file on disk. If the file on disk does not exist, the routine
- * removes the row from the table.
- *
- * lptbl pointer to table
- * pifldParent the folder that all objects should be in. May be NULL.
- * pims the message store object
- * pfTableChanged Pointer to a location to return a BOOL that, when TRUE,
- * indicates that a bad row was found, and the table was changed
- *
- */
- static HRESULT HrRemoveBadTableRows(LPTABLEDATA lptbl, PIFLD pifldParent,
- PIMS pims, BOOL *pfTableChanged)
- {
- HRESULT hr = hrSuccess;
- LPSRow lpSRow = NULL;
- BOOL fTableChanged = FALSE; /* TRUE if lptbl was changed */
- ULONG iRow = 0;
-
- while (TRUE)
- {
- LPSTR szPath;
- BOOL fIsParent = TRUE;
- PEID peid;
-
- hr = lptbl->lpVtbl->HrEnumRow(lptbl, iRow++, &lpSRow);
-
- if (hr != hrSuccess || lpSRow == NULL)
- break;
-
- peid = (PEID) lpSRow->lpProps->Value.bin.lpb;
-
- /* If the caller gave us a parent folder, verify that the message */
- /* is in that folder. For example, if the caller is checking the */
- /* contents table, we can check that all messages are in the folder */
- /* they should be, but for the outgoing queue table, we can't. */
-
- if (pifldParent)
- {
- hr = HrIsParent(pifldParent->peid, peid, &fIsParent);
- if (hr != hrSuccess)
- goto exit;
- }
-
- hr = HrFullPathName(pims->szStorePath, peid->szPath, NULL, &szPath);
- if (hr != hrSuccess)
- goto exit;
-
- /* Delete the row if it no longer exists on disk */
- /* or isn't in the correct folder */
- if ((GetFileAttributes(szPath) == -1) || !fIsParent)
- {
- HRESULT hrT;
-
- hrT = lptbl->lpVtbl->HrDeleteRow(lptbl, lpSRow->lpProps);
-
- if (hrT != hrSuccess)
- {
- TraceSz1("SampleMS: HrSyncTableWithDisk: error %s "
- "deleting out-of-date table entry\n",
- SzDecodeScode(GetScode(hrT)));
- }
-
- fTableChanged = TRUE;
- }
-
- LMFree(&pims->lmr, lpSRow);
- lpSRow = NULL;
- FreeNull(szPath);
- }
-
- AssertSz(!IsBadWritePtr(pfTableChanged, sizeof(BOOL)), "Bad parameter"
- " (pfTableChanged) given to HrRemoveBadTableRows");
- *pfTableChanged = fTableChanged;
-
- exit:
- LMFree(&pims->lmr, lpSRow);
- DebugTraceResult(HrRemoveBadTableRows, hr);
- return hr;
- }
-
- /*************************************************************************
- * HrAddMissingTableRows
- *
- * Purpose
- * Searches a folder for objects of the specified type, and verifies
- * that each object exists in the table given, and is up-to-date.
- * If the object does not exist or is out-of-date, the routine
- * adds or updates the table row with current information from the object.
- * This routine only works for contents tables currently.
- *
- * lptbl pointer to table
- * pifld the folder that all objects should be in.
- * szTemplate type of files to search for for this table type
- * ptaga list of proptags for this type of table
- * pfTableChanged Pointer to a location to return a BOOL that, when TRUE,
- * indicates that the table was changed to match the disk
- *
- */
- static HRESULT HrAddMissingTableRows(LPTABLEDATA lptbl, PIFLD pifld,
- LPSTR szTemplate, LPSPropTagArray ptaga, BOOL * pfTableChanged)
- {
- HRESULT hr;
- WIN32_FIND_DATA ffd;
- HANDLE hFindFile = INVALID_HANDLE_VALUE;
- ULONG ulOffset;
- LPTSTR szFile = NULL; /* full path name of next file in the table */
- PEID peid = NULL;
- BOOL fTableChanged = FALSE;
- LPSRow lpSRow = NULL;
- SPropValue pvInstKey;
- PLMR plmr = &pifld->pims->lmr;
-
- /* for each file of the right kind ( message or folder ) on disk */
- /* make sure its entry in the cache is up to date */
-
- pvInstKey.ulPropTag = PR_INSTANCE_KEY;
-
- /* get the next file */
- hr = HrFindFirstID(pifld, szTemplate, &ulOffset, &szFile, &hFindFile,
- &ffd, &peid);
-
- while (hr == hrSuccess)
- {
- FILETIME ftTableTime; /* modify time of szFile in lptbl */
-
- /* get its row in the table */
- pvInstKey.Value.bin.cb = CbEID(peid);
- pvInstKey.Value.bin.lpb = (LPBYTE) peid;
-
- hr = lptbl->lpVtbl->HrQueryRow(lptbl, &pvInstKey, &lpSRow, NULL);
-
- if (GetScode(hr) == MAPI_E_NOT_ENOUGH_MEMORY)
- goto exit;
-
- /* update the row if necessary */
- /* store in ftTableTime, the modify time of this object */
- /* as stored in the lptbl */
- if (hr == hrSuccess && lpSRow)
- hr = HrGetTime(lpSRow, &ftTableTime);
-
- if (hr != hrSuccess
- || lpSRow == NULL
- || CompareFileTime(&ftTableTime, &(ffd.ftLastWriteTime)) == -1)
- {
- fTableChanged = TRUE;
-
- HrUpdateRow(pifld->pims, lptbl, peid, ptaga, &(ffd.ftLastWriteTime),
- MAPI_MESSAGE);
- }
-
- LMFree(plmr, peid);
- peid = NULL;
- LMFree(plmr, lpSRow);
- lpSRow = NULL;
-
- hr = HrFindNextID(pifld, ulOffset, szFile, hFindFile, &ffd, &peid);
- }
-
- if (GetScode(hr) == MAPI_E_NOT_FOUND)
- hr = hrSuccess;
-
- if (hr == hrSuccess)
- {
- AssertSz(!IsBadWritePtr(pfTableChanged, sizeof(BOOL)), "Bad parameter"
- " (pfTableChanged) given to HrAddMissingTableRows");
- *pfTableChanged = fTableChanged;
- }
-
- exit:
- CloseIDSearch(&hFindFile, &szFile);
- LMFree(plmr, lpSRow);
- LMFree(plmr, peid);
-
- DebugTraceResult(HrAddMissingTableRows, hr);
- return hr;
- }
-
-