|
|
/*++
Copyright (c) 1996, 1997 Microsoft Corporation
Module Name:
catdbsvc.cpp
Abstract:
This module contains routines associated with the service side of the catalog database
Author:
Reid Kuhn (reidk) 19-Nov-97
--*/
/*
This comment section gives a picture of an example catalog database, with example catalog files added and the resulting database tables. The database schema can be seen clearly by looking at the picture of the database tables. This comment section also contains psuedo code for the add catalog algorithm.
Catalogs added to the catalog database are stored in the FILE SYSTEM --------------------------------------------------------------------
-------- -------- -------- -------- -------- -------- Catname: | CatA | | CatB | | CatC | | CatD | | CatE | | CatF | -------- -------- -------- -------- -------- -------- HashList: | 111 | | 111 | | 444 | | 333 | | 333 | | 555 | | 222 | | 222 | | | | | | 555 | | | | 333 | | | | | | | | | | | -------- -------- -------- -------- -------- --------
Resulting Database Tables (above catalogs where added in order) --------------------------------------------------------------------
HashCatNameTable ---------------------------------- | HashCol | CatNameListCol | |-----------|--------------------| | 111 | CatA - CatB | | 222 | CatA - CatB | | 333 | CatA - CatD - CatE | | 444 | CatC | | 555 | CatE - CatF | ----------------------------------
CatNameBuddyTable --------------------------------------------- | CatNameCol | BuddyListCol | --------------------------------------------- | CatA | CatB - CatD - CatE | | CatB | CatA | | CatD | CatA - CatB - CatE | | CatE | CatA - CatB - CatD - CatF | | CatF | CatE - CatA - CatB - CatD | ---------------------------------------------
Add Catalog Algorithm ---------------------
AddCat(<CatToAdd>) { For each hash <i> contained in catalog <CatToAdd> { if (<i> is not contained in HashCol of HashCatNameTable) { add row to HashCatNameTable with <i> in HashCol and <CatToAdd> in CatNameListCol } else { create row in CatNameBuddyTable with <CatToAdd> in CatNameCol
for each CatName <CatNameIn-CatNameListCol> contained in <i>'s CatNameListCol { if (<CatNameIn-CatNameListCol> is not contained in CatNameCol of CatNameBuddyTable { create row in CatNameBuddyTable with <CatNameIn-CatNameListCol> in CatNameCol }
add <CatNameIn-CatNameListCol> to <CatToAdd>'s BuddyListCol
for each CatName <CatNameIn-BuddyListCol> contained in <CatNameIn-CatNameListCol>'s BuddyListCol - (may be empty) { add <CatNameIn-BuddyListCol> to <CatToAdd>'s BuddyListCol }
add <CatToAdd> to <CatNameIn-CatNameListCol>'s BuddyListCol }
add <CatToAdd> to <i>'s CatNameListCol } } }
*/
#include <windows.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <dbgdef.h>
#include <esent.h>
#include <assert.h>
#include <stdio.h>
#include "catdb.h" // header file generated by MIDL compiler
#include "dbutils.h"
#include "voidlist.h"
#include "catutil.h"
#include "resource.h"
#include "errlog.h"
#include "mscat.h"
#include "keysvr.h"
#include "cryptmsg.h"
#define CATDB_MAX_CATNAME_LENGTH 255
#define WSZ_REG_TEMP_FILES_KEY L"Software\\Microsoft\\Cryptography\\CatDBTempFiles"
#define WSZ_REG_CATALOGDB_VALUES L"Software\\Microsoft\\Cryptography\\CatalogDB"
#define WSZ_REG_CALLBACK_TIMER L"CallbackTime"
#define WSZ_REG_DATABASE_TIMEOUT L"DatabaseTimeout"
#define SZ_CATALOG_FILE_BASE_DIRECTORY "CatRoot"
#define WSZ_CATALOG_FILE_BASE_DIRECTORY L"CatRoot"
#define SZ_DATABASE_FILE_BASE_DIRECTORY "CatRoot2"
#define WSZ_DATABASE_FILE_BASE_DIRECTORY L"CatRoot2"
#define SZ_DBFILE_NAME "catdb"
#define WSZ_DBFILE_NAME L"catdb"
#define SZ_CATALOG_DATABASE "Catalog Database"
#define WSZ_TIME_STAMP_FILE L"TimeStamp"
#define CATDBSVC_LOGERR_LASTERR() ErrLog_LogError(NULL, \
ERRLOG_CLIENT_ID_CATDBSCV, \ __LINE__, \ 0, \ FALSE, \ FALSE);
#define CATDBSVC_SETERR_LOG_RETURN(x, y) SetLastError(x); \
ErrLog_LogError(NULL, \ ERRLOG_CLIENT_ID_CATDBSCV, \ __LINE__, \ 0, \ FALSE, \ FALSE); \ goto y;
#define CATDBSVC_LOGERR(x) ErrLog_LogError(NULL, \
ERRLOG_CLIENT_ID_CATDBSCV, \ __LINE__, \ x, \ FALSE, \ FALSE);
#define CATDBSVC_LOGWARN(x) ErrLog_LogError(NULL, \
ERRLOG_CLIENT_ID_CATDBSCV, \ __LINE__, \ x, \ TRUE, \ FALSE);
#define ALLOCATION_BLOCK_SIZE 8
typedef struct _JET_DB_STRUCT { LPSTR pszDBFileName;
JET_SESID JetSesID; JET_DBID JetDBID;
// Hash-CatName Table
JET_TABLEID JetHashCatNameTableID; JET_COLUMNID JetHashCatNameTable_HashColumnID; JET_COLUMNID JetHashCatNameTable_CatNameColumnID;
// CatName Buddy Table
JET_TABLEID JetCatNameBuddyTableID; JET_COLUMNID JetCatNameBuddyTable_CatNameColumnID; JET_COLUMNID JetCatNameBuddyTable_BuddyColumnID;
} JET_DB_STRUCT, *PJET_DB_STRUCT;
typedef struct _CATALOG_DIR_CACHE_STRUCT { JET_DB_STRUCT JetDBStruct; LPWSTR pwszSubSysGUID; HANDLE hDBNotInUse; BOOL fReadOnly; DWORD dwTimeLastTouched;
} CATALOG_DIR_CACHE_STRUCT, *PCATALOG_DIR_CACHE_STRUCT;
typedef struct _NOTIFICATION_STRUCT { DWORD ProcessID; HANDLE hClientProcess; HANDLE hRegisterWaitFor; HANDLE hNotificationHandle; HANDLE hDuplicatedNotificationHandle; LONG lNotificationID;
} NOTIFICATION_STRUCT, *PNOTIFICATION_STRUCT;
//
// Global variables
//
extern HINSTANCE g_hInst; BOOL g_fDBSvcInitialized = FALSE; CRITICAL_SECTION g_CatDBAddDeleteCS; CRITICAL_SECTION g_CatDBRegisterNotifyCS; CRITICAL_SECTION g_CatDirCashCS; CRITICAL_SECTION g_CatClientCountCS; CRITICAL_SECTION g_InitializeJetCS; CRITICAL_SECTION g_WaitOrTimerCallbackCS; LONG g_lOpenedDBCount = 0; BOOL g_fJetInitialized = FALSE; JET_INSTANCE g_JetInstance = 0; NOTIFICATION_STRUCT *g_rgNotificationStructs = NULL; DWORD g_NumNotificationStructs = 0; LIST g_CatalogDBCacheList; HANDLE g_hCatalogCacheCallbackEvent = NULL; BOOL g_fShuttingDown = FALSE; DWORD g_dwClientCount = 0; LONG g_lNotificationID = 0; LPWSTR g_pwszCatalogFileBaseDirectory = NULL; LPWSTR g_pwszDatabaseFileBaseDirectory = NULL; DWORD g_dwCatalogDatabaseCacheTimeout = (1000 * 60); // default one minute
DWORD g_dwCatalogDatabaseCacheCallbackTime= (1000 * 60 * 5); // default five minutes
HANDLE g_hRegisterWaitForServiceShutdown = NULL; HANDLE g_hNotFrozen = NULL;
//
// Forward declarations
//
//
// General supporting DB file functions
//
BOOL _CatDBClientEnter(void);
void _CatDBClientExit(void);
void _CatDBTouchTimeStampFile( LPCWSTR pwszSubSysGUID);
BOOL _CatDBInitializeJet( BOOL fInRecursiveCall);
BOOL _CatDBTermJet();
BOOL _CatDBAcquireOpenDatabaseFromCache( PJET_DB_STRUCT *ppJetDBStruct, LPCWSTR pwszSubSysGUID, BOOL fReadOnly, BOOL fInRecursiveCall );
BOOL _CatDBReleaseDatabaseToCache( PJET_DB_STRUCT pJetDBStruct );
BOOL _CatDBCloseCachedDatabases( BOOL fForceClose);
VOID CALLBACK _CatDBWaitOrTimerCallback( PVOID lpParameter, BOOLEAN fTimedOut );
//
// Supporting functions for s_SSCatDBAddCatalog
//
DWORD _CatDBAddCatalog( handle_t h, DWORD dwFlags, LPCWSTR pwszSubSysGUID, LPCWSTR pwszCatalogFile, LPCWSTR pwszCatName, BOOL fInRecursiveCall, LPWSTR __RPC_FAR *ppwszCatalogNameUsed);
BOOL _CatDBAddCatalogEntriesToDatabase( PJET_DB_STRUCT pJetDBStruct, PCCTL_CONTEXT pCTLContext, LPWSTR pwszNewCatalogName );
BOOL _CatDBAddHashCatNamePair( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName );
BOOL _CatDBAddNewRowToHashCatNameTable( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName );
BOOL _CatDBAddValueToExistingHashCatNameRow( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName );
BOOL _CatDBCatnameAlreadyInHashesListOfCats( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName );
BOOL _CatDBAddNewRowToCatNameBuddyTableIfNotExists( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatBaseName );
BOOL _CatDBAddNewRowToCatNameBuddyTable( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatBaseName );
BOOL _CatDBAddNameToBuddyList( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszNameToAdd, LPWSTR pwszListToAddTo );
BOOL _CatDBAddWholeBuddyList( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszBuddyToAddTo, LPWSTR pwszBuddyListName );
BOOL _CatDBMoveInUseFileToTempLocation( LPWSTR pwszFile );
void _CatDBCleanupTempFiles();
//
// Supporting functions for s_SSCatDBDeleteCatalog
//
BOOL _CatDBDeleteCatalogEntriesFromDatabase( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatalogName );
BOOL _CatDBRemoveCatNameFromHashesListOfCatNames( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName );
BOOL _CatDBRemoveCatNameFromMultiValuedColumn( PJET_DB_STRUCT pJetDBStruct, JET_TABLEID jetTableID, JET_COLUMNID jetColumnID, LPWSTR pwszCatBaseName );
BOOL _CatDBRemoveCatNameFromCatNameTable( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatBaseName );
BOOL _CatDBRemoveCatNameFromBuddyTable( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatBaseName );
//
// Supporting functions for s_SSCatDBEnumCatalogs
//
BOOL _CatDBAddCatNameAndCatNamesBuddyListToReturnCatNames( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatName, DWORD __RPC_FAR *pdwNumCatalogNames, LPWSTR __RPC_FAR *__RPC_FAR *pppwszCatalogNames, BOOL fRecursiveCall);
BOOL _CatDBAddCatNameToReturnBuddyListIfNotExist( LPWSTR pwszBuddy, DWORD __RPC_FAR *pdwNumCatalogNames, LPWSTR __RPC_FAR *__RPC_FAR *pppwszCatalogNames );
//
// More general supporting functions
//
JET_ERR _CatDBSeekInCatNameBuddyTable( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszBuddyRow );
JET_ERR _CatDBSeekInHashCatNameTable( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob );
void _CatDBNotifyClients(void);
void _CatDBCleanupClientNotifications(void);
LPWSTR _CatDBCreateNewCatalogFileName( LPCWSTR pwszCatalogFileDir, LPCWSTR pwszCatName, BOOL *pfFileAlreadyExists );
BOOL _CatDBFindAndDecodeHashInCatEntry( PCTL_ENTRY pctlEntry, SPC_INDIRECT_DATA_CONTENT **ppIndirectData );
DWORD _CatDBMapJetError( JET_ERR jerr);
BOOL _CatDBJET_errFailure( JET_ERR jerr);
BOOL _CatDBInitJetDatabaseParams( JET_INSTANCE *pJetInstance);
BOOL _CatDBAttachAndOpenDatabase( JET_DB_STRUCT *pJetDBStruct, BOOL fReadOnly);
BOOL _CatDBCloseDatabaseFile( PJET_DB_STRUCT pJetDBStruct, BOOL fDetach);
BOOL _CatDBCatalogFileAlreadyInstalled( LPCWSTR pwszCatalogToBeAdded, LPCWSTR pwszExistingCatalog);
#define LOGEVENT_STRING_PARAMTYPE 1
#define LOGEVENT_INT_PARAMTYPE 2
#define LOGEVENT_NONE_PARAMTYPE 3
//
// VSS Writer prototypes
//
VOID _SystemWriterInit( BOOL fUnInit);
//
// Use these for memory that is transferred across an LRPC call
//
extern "C" { extern void __RPC_FAR * __RPC_API midl_user_allocate(size_t len); extern void __RPC_API midl_user_free(void __RPC_FAR * ptr); extern void __RPC_FAR * __RPC_API midl_user_reallocate(void __RPC_FAR * ptr, size_t len); }
//
// general allocation routines
//
void * _CatDBAlloc(size_t len) { void *temp;
temp = LocalAlloc(LMEM_ZEROINIT, len);
if (temp == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); }
return(temp); }
void * _CatDBReAlloc(void *p, size_t len) { void *temp;
temp = LocalReAlloc(p, len, LMEM_MOVEABLE | LMEM_ZEROINIT);
if (temp == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); }
return(temp); }
void _CatDBFree(void *p) { if (p != NULL) { LocalFree(p); } }
LPSTR _CatDBGetCatrootDirA() { LPSTR pszTempPath = NULL; char szDefaultSystemDir[MAX_PATH + 1]; DWORD dwLength;
//
// Get System default directory
//
szDefaultSystemDir[0] = NULL; if (0 == GetSystemDirectoryA(&szDefaultSystemDir[0], MAX_PATH)) { CATDBSVC_LOGERR_LASTERR() return (NULL); }
//
// Calculate length
//
dwLength = strlen(szDefaultSystemDir) + strlen(SZ_DATABASE_FILE_BASE_DIRECTORY) + 3;
//
// Allocate space for the full path
//
if (NULL == (pszTempPath = (LPSTR) malloc(sizeof(char) * dwLength))) { CATDBSVC_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) return (NULL); }
//
// Make the path
//
strcpy(pszTempPath, szDefaultSystemDir); if ((pszTempPath[0]) && (pszTempPath[strlen(&pszTempPath[0]) - 1] != '\\')) { strcat(pszTempPath, "\\"); }
strcat(pszTempPath, SZ_DATABASE_FILE_BASE_DIRECTORY); strcat(pszTempPath, "\\");
ErrorMemory:
return (pszTempPath); }
LPWSTR _CatDBGetCatrootDirW( BOOL fCatroot2) { LPWSTR pwszTempPath = NULL; WCHAR wszDefaultSystemDir[MAX_PATH + 1]; DWORD dwLength;
//
// Get System default directory
//
wszDefaultSystemDir[0] = NULL; if (0 == GetSystemDirectoryW(&wszDefaultSystemDir[0], MAX_PATH)) { CATDBSVC_LOGERR_LASTERR() return (NULL); }
//
// Calculate length
//
dwLength = wcslen(wszDefaultSystemDir) + 3; if (fCatroot2) { dwLength += wcslen(WSZ_DATABASE_FILE_BASE_DIRECTORY); } else { dwLength += wcslen(WSZ_CATALOG_FILE_BASE_DIRECTORY); }
//
// Allocate space for the full path
//
if (NULL == (pwszTempPath = (LPWSTR) malloc(sizeof(WCHAR) * dwLength))) { CATDBSVC_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) return (NULL); }
//
// Make the path
//
wcscpy(pwszTempPath, wszDefaultSystemDir); if ((pwszTempPath[0]) && (pwszTempPath[wcslen(&pwszTempPath[0]) - 1] != L'\\')) { wcscat(pwszTempPath, L"\\"); }
if (fCatroot2) { wcscat(pwszTempPath, WSZ_DATABASE_FILE_BASE_DIRECTORY); } else { wcscat(pwszTempPath, WSZ_CATALOG_FILE_BASE_DIRECTORY); }
wcscat(pwszTempPath, L"\\");
ErrorMemory:
return (pwszTempPath); }
LPWSTR _CatDBCreatePath( IN LPCWSTR pwsz1, IN LPCWSTR pwsz2) { LPWSTR pwszTemp = NULL; int nTotalLen = 0; int nLenStr1 = 0;
//
// Calculate the length of the resultant string as the sum of the length
// of psz1, a '\', the length of psz2, and a NULL char
//
nLenStr1 = wcslen(pwsz1); nTotalLen = nLenStr1 + wcslen(pwsz2) + 2;
//
// Allocate the string and copy pwsz1 into the buffer
//
if (NULL == (pwszTemp = (LPWSTR) malloc(sizeof(WCHAR) * nTotalLen))) { CATDBSVC_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorReturn) }
wcscpy(pwszTemp, pwsz1);
//
// Add the extra '\' if needed
//
if (pwsz1[nLenStr1 - 1] != L'\\') { wcscat(pwszTemp, L"\\"); }
//
// Tack on psz2
//
wcscat(pwszTemp, pwsz2);
CommonReturn:
return (pwszTemp);
ErrorReturn:
goto CommonReturn; }
BOOL _CatDBDVerifyGUIDString( IN LPCWSTR pwszDatabaseGUID) { LPCWSTR pszCompareString = L"{00000000-0000-0000-0000-000000000000}"; DWORD i;
if (wcslen(pwszDatabaseGUID) != wcslen(pszCompareString)) { return (FALSE); }
for (i=0; i<wcslen(pszCompareString); i++) { if (pszCompareString[i] == L'0') { if (!((pwszDatabaseGUID[i] >= '0') && (pwszDatabaseGUID[i] <= '9') || (pwszDatabaseGUID[i] >= 'a') && (pwszDatabaseGUID[i] <= 'f') || (pwszDatabaseGUID[i] >= 'A') && (pwszDatabaseGUID[i] <= 'F'))) { return (FALSE); } } else { if (pszCompareString[i] != pwszDatabaseGUID[i]) { return (FALSE); } } }
return (TRUE); }
BOOL _CatDBFileNameOK( IN LPCWSTR pwszFileName) { if (pwszFileName == NULL) { return (TRUE); }
if (wcslen(pwszFileName) > 28) { return (FALSE); }
return (TRUE); }
BOOL _CatDBDeleteFiles( IN LPCWSTR pwszPath, IN LPCWSTR pwszSearch) { BOOL fRet = TRUE; HANDLE hFindHandle = INVALID_HANDLE_VALUE; WIN32_FIND_DATAW FindData; DWORD dwErr; LPWSTR pwszDelete = NULL;
//
// Do the initial find
//
hFindHandle = FindFirstFileW(pwszSearch, &FindData); if (hFindHandle == INVALID_HANDLE_VALUE) { //
// See if a real error occurred, or just no files
//
dwErr = GetLastError(); if ((dwErr == ERROR_NO_MORE_FILES) || (dwErr == ERROR_FILE_NOT_FOUND)) { //
// There are no files of this type to delete
//
return (TRUE); } else { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } }
while (1) { //
// Only care about files
//
if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { pwszDelete = _CatDBCreatePath(pwszPath, FindData.cFileName);
if (pwszDelete == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (!DeleteFileW(pwszDelete)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
free(pwszDelete); pwszDelete = NULL; }
//
// Get next file
//
if (!FindNextFileW(hFindHandle, &FindData)) { if (GetLastError() == ERROR_NO_MORE_FILES) { break; } else { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } } }
CommonReturn:
if (pwszDelete != NULL) { free(pwszDelete); }
return (fRet);
ErrorReturn:
fRet = FALSE; goto CommonReturn; }
BOOL _CatDBDeleteJetFiles() { BOOL fRet = TRUE; LPWSTR pwszCatroot2 = NULL; LPWSTR pwszDelete = NULL; LPWSTR pwszSearch = NULL; LPWSTR pwszPathName = NULL; HANDLE hFindHandle = INVALID_HANDLE_VALUE; WIN32_FIND_DATAW FindData; DWORD dwErr;
//
// Get the directory where the jet files live
//
pwszCatroot2 = _CatDBGetCatrootDirW(TRUE);
if (pwszCatroot2 == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// build the search string for jet log files and delete them
// (there are two forms of log files).
//
pwszDelete = _CatDBCreatePath(pwszCatroot2, L"edb*.log");
if (pwszDelete == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (!_CatDBDeleteFiles(pwszCatroot2, pwszDelete)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
free(pwszDelete); pwszDelete = NULL;
pwszDelete = _CatDBCreatePath(pwszCatroot2, L"res*.log");
if (pwszDelete == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (!_CatDBDeleteFiles(pwszCatroot2, pwszDelete)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
free(pwszDelete); pwszDelete = NULL;
//
// Delete the "catdb" and "timestamp" files in each directory
//
//
// Build a search string for catdb directories
//
pwszSearch = _CatDBCreatePath(pwszCatroot2, L"{????????????????????????????????????}");
if (pwszSearch == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Do the initial find
//
hFindHandle = FindFirstFileW(pwszSearch, &FindData); if (hFindHandle == INVALID_HANDLE_VALUE) { //
// See if a real error occurred, or just no directories
//
dwErr = GetLastError(); if ((dwErr == ERROR_NO_MORE_FILES) || (dwErr == ERROR_PATH_NOT_FOUND) || (dwErr == ERROR_FILE_NOT_FOUND)) { //
// There are no directories of this form
//
goto CommonReturn; } else { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } }
while (1) { //
// Only care about directories
//
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { pwszPathName = _CatDBCreatePath(pwszCatroot2, FindData.cFileName);
if (pwszPathName == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Delete the "catdb" file
//
pwszDelete = _CatDBCreatePath(pwszPathName, WSZ_DBFILE_NAME);
if (pwszDelete == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
DeleteFileW(pwszDelete);
free(pwszDelete); pwszDelete = NULL;
//
// Delete the "timestamp" file
//
pwszDelete = _CatDBCreatePath(pwszPathName, WSZ_TIME_STAMP_FILE);
if (pwszDelete == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
DeleteFileW(pwszDelete);
free(pwszDelete); pwszDelete = NULL;
free(pwszPathName); pwszPathName = NULL; }
//
// Get next file
//
if (!FindNextFileW(hFindHandle, &FindData)) { if (GetLastError() == ERROR_NO_MORE_FILES) { break; } else { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } } }
CommonReturn:
if (pwszCatroot2 != NULL) { free(pwszCatroot2); }
if (pwszDelete != NULL) { free(pwszDelete); }
if (pwszSearch != NULL) { free(pwszSearch); }
if (pwszPathName != NULL) { free(pwszPathName); }
return (fRet);
ErrorReturn:
fRet = FALSE; goto CommonReturn; }
BOOL _CatDBRebuildDB( LPCWSTR pwszPathName, LPCWSTR pwszDatabaseGUID) { BOOL fRet = TRUE; LPWSTR pwszSearch = NULL; LPWSTR pwszCatalog = NULL; HANDLE hFindHandle = INVALID_HANDLE_VALUE; WIN32_FIND_DATAW FindData; DWORD dwErr; LPWSTR __RPC_FAR pwszCatalogNameUsed = NULL; WCHAR wszTempFile[MAX_PATH]; JET_DB_STRUCT *pJetDBStruct = NULL;
//
// First, just make sure the database gets created by doing
// an open and close
//
if (!_CatDBAcquireOpenDatabaseFromCache( &pJetDBStruct, pwszDatabaseGUID, FALSE, TRUE)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
_CatDBReleaseDatabaseToCache(pJetDBStruct);
//
// Find all catalogs in direcotry and add each one
//
//
// Build a search string for catalog files
//
pwszSearch = _CatDBCreatePath(pwszPathName, L"*.cat");
if (pwszSearch == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Do the initial find
//
hFindHandle = FindFirstFileW(pwszSearch, &FindData); if (hFindHandle == INVALID_HANDLE_VALUE) { //
// See if a real error occurred, or just no directories
//
dwErr = GetLastError(); if ((dwErr == ERROR_NO_MORE_FILES) || (dwErr == ERROR_FILE_NOT_FOUND)) { //
// There are no files of this form
//
goto CommonReturn; } else { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } }
//
// Get a temporary file name which will be used to when adding each catalog
//
if (0 == GetTempFileNameW( g_pwszCatalogFileBaseDirectory, L"TMP", 0, wszTempFile)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// GetTempFileName actually creates the file, so delete it
//
DeleteFileW(wszTempFile);
while (1) { //
// Only care about files
//
if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { pwszCatalog = _CatDBCreatePath(pwszPathName, FindData.cFileName);
if (pwszCatalog == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Copy the catalog file to a temporary location and add it from there
//
if (!CopyFileW(pwszCatalog, wszTempFile, TRUE)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
_CatDBAddCatalog( NULL, 0, pwszDatabaseGUID, wszTempFile, FindData.cFileName, TRUE, &pwszCatalogNameUsed);
DeleteFileW(wszTempFile);
if (pwszCatalogNameUsed != NULL) { MIDL_user_free(pwszCatalogNameUsed); pwszCatalogNameUsed = NULL; }
free(pwszCatalog); pwszCatalog = NULL; }
//
// Get next file
//
if (!FindNextFileW(hFindHandle, &FindData)) { if (GetLastError() == ERROR_NO_MORE_FILES) { break; } else { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } } }
CommonReturn:
if (pwszSearch != NULL) { free(pwszSearch); }
if (pwszCatalog != NULL) { free(pwszCatalog); }
return (fRet);
ErrorReturn:
fRet = FALSE; goto CommonReturn; }
BOOL _CatDBRebuildAllDBs() { BOOL fRet = TRUE; LPWSTR pwszCatroot = NULL; LPWSTR pwszSearch = NULL; LPWSTR pwszPathName = NULL; HANDLE hFindHandle = INVALID_HANDLE_VALUE; WIN32_FIND_DATAW FindData; DWORD dwErr;
//
// Get the directory where the catalog files live
//
pwszCatroot = _CatDBGetCatrootDirW(FALSE);
if (pwszCatroot == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Build a search string for the catalog directories
//
pwszSearch = _CatDBCreatePath(pwszCatroot, L"{????????????????????????????????????}");
if (pwszSearch == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Do the initial find
//
hFindHandle = FindFirstFileW(pwszSearch, &FindData); if (hFindHandle == INVALID_HANDLE_VALUE) { //
// See if a real error occurred, or just no directories
//
dwErr = GetLastError(); if ((dwErr == ERROR_NO_MORE_FILES) || (dwErr == ERROR_PATH_NOT_FOUND) || (dwErr == ERROR_FILE_NOT_FOUND)) { //
// There are no directories of this form
//
goto CommonReturn; } else { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } }
while (1) { //
// Only care about directories
//
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { pwszPathName = _CatDBCreatePath(pwszCatroot, FindData.cFileName);
if (pwszPathName == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (!_CatDBRebuildDB(pwszPathName, FindData.cFileName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
free(pwszPathName); pwszPathName = NULL; }
//
// Get next file
//
if (!FindNextFileW(hFindHandle, &FindData)) { if (GetLastError() == ERROR_NO_MORE_FILES) { break; } else { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } } }
CommonReturn:
if (pwszCatroot != NULL) { free(pwszCatroot); }
if (pwszSearch != NULL) { free(pwszSearch); }
if (pwszPathName != NULL) { free(pwszPathName); }
return (fRet);
ErrorReturn:
fRet = FALSE; goto CommonReturn; }
/////////////////////////////////////////////////////////////////////////////////////////
//
// LPC-exposed functions
//
// these functions return a DWORD equivalent to GetLastError(). The client side stub
// code will check if the return code is not ERROR_SUCCESS, and if this is the case,
// the client stub will return FALSE and SetLastError() to this DWORD.
//
/////////////////////////////////////////////////////////////////////////////////////////
DWORD _CatDBAddCatalog( handle_t h, DWORD dwFlags, LPCWSTR pwszSubSysGUID, LPCWSTR pwszCatalogFile, LPCWSTR pwszCatName, BOOL fInRecursiveCall, LPWSTR __RPC_FAR *ppwszCatalogNameUsed) { DWORD dwRet = ERROR_SUCCESS; RPC_STATUS RpcStatus; LPWSTR pwszCatalogFileDir = NULL; BOOL fImpersonating = FALSE; JET_DB_STRUCT *pJetDBStruct = NULL; BOOL fCatalogDatabaseAcquiredFromCache = FALSE; PCCTL_CONTEXT pCTLContext = NULL; LPWSTR pwszNewCatalogName = NULL; HANDLE hMappedFile = NULL; BYTE *pbMappedFile = NULL; BOOL fTransactionBegun = FALSE; BOOL fFileAlreadyExists = FALSE; WCHAR wszTempFile[MAX_PATH]; JET_ERR jerr; BOOL fTempFileCreated = FALSE;
//
// Initialize out param
//
*ppwszCatalogNameUsed = NULL;
//
// Only allow one add or delete at a time
//
EnterCriticalSection(&g_CatDBAddDeleteCS);
//
// Impersonate client if needed
//
if (h != NULL) { if (RPC_S_OK != (RpcStatus = RpcImpersonateClient(h))) { CATDBSVC_SETERR_LOG_RETURN(RpcStatus, ErrorImpersonateClient); }
fImpersonating = TRUE; }
//
// Create the path to the catalog files
//
if (NULL == (pwszCatalogFileDir = _CATDBConstructWSTRPath( g_pwszCatalogFileBaseDirectory, pwszSubSysGUID))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Get the fully qualified path name of the new catalog file
//
if (NULL == (pwszNewCatalogName = _CatDBCreateNewCatalogFileName( pwszCatalogFileDir, pwszCatName, &fFileAlreadyExists))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (NULL == (*ppwszCatalogNameUsed = (LPWSTR) midl_user_allocate((wcslen(pwszNewCatalogName) + 1) * sizeof(WCHAR)))) { CATDBSVC_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } wcscpy(*ppwszCatalogNameUsed, pwszNewCatalogName);
//
// Open a CTL context on the catalog being added
//
if (!CatUtil_CreateCTLContextFromFileName( pwszCatalogFile, &hMappedFile, &pbMappedFile, &pCTLContext, FALSE)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// If we are replacing an existing catalog, save a copy of the old one
// in case the commit fails
//
if (fFileAlreadyExists) { if (0 == GetTempFileNameW( g_pwszCatalogFileBaseDirectory, L"TMP", 0, wszTempFile)) { //
// If the entries couldn't be deleted because the user doesn't
// have write rights, then do a check to see if the catalog
// they are trying to add already exists, if it does, then
// retrun ERROR_ALREADY_EXISTS instead of ACCESS_DENIED
//
if (GetLastError() == ERROR_ACCESS_DENIED) { if (_CatDBCatalogFileAlreadyInstalled( pwszCatalogFile, pwszNewCatalogName)) { SetLastError(ERROR_ALREADY_EXISTS); goto ErrorReturn; } } else { CATDBSVC_LOGERR_LASTERR() goto ErrorGetTempFileName; } }
//
// Copy the old catalog file to a temporary location
//
if (!CopyFileW(pwszNewCatalogName, wszTempFile, FALSE)) { CATDBSVC_LOGERR_LASTERR() goto ErrorCopyFile; } fTempFileCreated = TRUE; }
//
// Open the database file
//
if (!_CatDBAcquireOpenDatabaseFromCache( &pJetDBStruct, pwszSubSysGUID, FALSE, fInRecursiveCall)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } fCatalogDatabaseAcquiredFromCache = TRUE;
//
// Start transaction
//
if (_CatDBJET_errFailure(jerr = JetBeginTransaction(pJetDBStruct->JetSesID))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetBeginTransaction) } fTransactionBegun = TRUE;
if (fFileAlreadyExists) { if (!_CatDBDeleteCatalogEntriesFromDatabase( pJetDBStruct, pwszNewCatalogName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } }
//
// Add the new DB entries
//
if (!_CatDBAddCatalogEntriesToDatabase( pJetDBStruct, pCTLContext, pwszNewCatalogName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Don't need the CTL context anymore
//
CertFreeCTLContext(pCTLContext); pCTLContext = NULL; UnmapViewOfFile(pbMappedFile); pbMappedFile = NULL; CloseHandle(hMappedFile); hMappedFile = NULL;
//
// Now, copy the new catalog file to its location
//
if (!CopyFileW(pwszCatalogFile, pwszNewCatalogName, FALSE)) { if (!fFileAlreadyExists) { CATDBSVC_LOGERR_LASTERR() goto ErrorCopyFile; }
//
// Since that failed, try renaming the destination file, and then re-copy.
// BTW, the above copy will fail if another client already has the
// destination file memory mapped in their catalog cache.
//
if (!_CatDBMoveInUseFileToTempLocation(pwszNewCatalogName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Now, retry the copy... this better work!
//
if (!CopyFileW(pwszCatalogFile, pwszNewCatalogName, FALSE)) { CATDBSVC_LOGERR_LASTERR() goto ErrorCopyFile; } } SetFileAttributesW(pwszNewCatalogName, FILE_ATTRIBUTE_SYSTEM);
//
// At this stage do the commit.
//
if (_CatDBJET_errFailure(jerr = JetCommitTransaction( pJetDBStruct->JetSesID, 0))) { //
// Since there was an error doing the commit, copy back the original
// catalog file
//
if (0 == CopyFileW(wszTempFile, pwszNewCatalogName, FALSE)) { // THE ABOVE COPY FAILED... THE DATABASE IS NOW INCONSISTENT!!!!!
CATDBSVC_LOGERR_LASTERR() } else { SetFileAttributesW(pwszNewCatalogName, FILE_ATTRIBUTE_SYSTEM); }
CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetCommitTransaction) } fTransactionBegun = FALSE;
_CatDBTouchTimeStampFile(pwszSubSysGUID);
//
// Release DB back to the cache
//
_CatDBReleaseDatabaseToCache(pJetDBStruct);
//
// Notify client of changes
//
_CatDBNotifyClients();
CommonReturn:
if (fTempFileCreated) { DeleteFileW(wszTempFile); }
if (pwszNewCatalogName != NULL) { _CatDBFree(pwszNewCatalogName); }
if (pwszCatalogFileDir != NULL) { _CatDBFree(pwszCatalogFileDir); }
if (pCTLContext != NULL) { CertFreeCTLContext(pCTLContext); }
if (pbMappedFile != NULL) { UnmapViewOfFile(pbMappedFile); }
if (hMappedFile != NULL) { CloseHandle(hMappedFile); }
if (fImpersonating) { if (RPC_S_OK != (RpcStatus = RpcRevertToSelf())) { MyLogErrorMessage((DWORD) RpcStatus, MSG_KEYSVC_REVERT_TO_SELF_FAILED); } }
LeaveCriticalSection(&g_CatDBAddDeleteCS);
return dwRet;
ErrorReturn:
dwRet = GetLastError();
if (0 == dwRet) { dwRet = (DWORD) E_UNEXPECTED; }
if (fTransactionBegun) { JetRollback(pJetDBStruct->JetSesID, 0); }
if (fCatalogDatabaseAcquiredFromCache) { _CatDBReleaseDatabaseToCache(pJetDBStruct); }
if (*ppwszCatalogNameUsed != NULL) { midl_user_free(*ppwszCatalogNameUsed); *ppwszCatalogNameUsed = NULL; }
goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorImpersonateClient) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetBeginTransaction) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetCommitTransaction) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorMemory) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorCopyFile) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorGetTempFileName) }
DWORD s_SSCatDBAddCatalog( /* [in] */ handle_t h, /* [in] */ DWORD dwFlags, /* [in] */ LPCWSTR pwszSubSysGUID, /* [in] */ LPCWSTR pwszCatalogFile, /* [unique][in] */ LPCWSTR pwszCatName, /* [out] */ LPWSTR __RPC_FAR *ppwszCatalogNameUsed) { DWORD dwRet;
if (!_CatDBClientEnter()) { CATDBSVC_LOGERR_LASTERR() return (GetLastError()); }
//
// Check input params
//
if ((h == NULL) || (!_CatDBDVerifyGUIDString(pwszSubSysGUID)) || (!_CatDBFileNameOK(pwszCatName))) { CATDBSVC_SETERR_LOG_RETURN(ERROR_BAD_ARGUMENTS, ErrorReturn) }
dwRet = _CatDBAddCatalog( h, dwFlags, pwszSubSysGUID, pwszCatalogFile, pwszCatName, FALSE, ppwszCatalogNameUsed);
_CatDBClientExit();
CommonReturn:
return (dwRet);
ErrorReturn:
dwRet = GetLastError(); goto CommonReturn; }
DWORD s_SSCatDBDeleteCatalog( /* [in] */ handle_t h, /* [in] */ DWORD dwFlags, /* [in] */ LPCWSTR pwszSubSysGUID, /* [in] */ LPCWSTR pwszCatalogFile) { DWORD dwRet = 0; RPC_STATUS RpcStatus; BOOL fImpersonating = FALSE; JET_DB_STRUCT *pJetDBStruct = NULL; BOOL fCatalogDatabaseAcquiredFromCache = FALSE; JET_ERR jerr; LPWSTR pwszCatalogFileFullPath = NULL; BOOL fTransactionBegun = FALSE; LPWSTR pwszCatalogFileDir = NULL;
if (!_CatDBClientEnter()) { CATDBSVC_LOGERR_LASTERR() return (GetLastError()); }
//
// Check input params
//
if ((h == NULL) || (!_CatDBDVerifyGUIDString(pwszSubSysGUID))) { return (ERROR_BAD_ARGUMENTS); }
//
// Only allow one add or delete at a time
//
EnterCriticalSection(&g_CatDBAddDeleteCS);
//
// Impersonate client
//
if (RPC_S_OK != (RpcStatus = RpcImpersonateClient(h))) { CATDBSVC_SETERR_LOG_RETURN(RpcStatus, ErrorImpersonateClient) } fImpersonating = TRUE;
//
// Create the path to the catalog files
//
if (NULL == (pwszCatalogFileDir = _CATDBConstructWSTRPath( g_pwszCatalogFileBaseDirectory, pwszSubSysGUID))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Construct full path to catalog being deleted
//
if (NULL == (pwszCatalogFileFullPath = _CATDBConstructWSTRPath(pwszCatalogFileDir, pwszCatalogFile))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Open the database file
//
if (!_CatDBAcquireOpenDatabaseFromCache( &pJetDBStruct, pwszSubSysGUID, FALSE, FALSE)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } fCatalogDatabaseAcquiredFromCache = TRUE;
//
// Start transaction
//
if (_CatDBJET_errFailure(jerr = JetBeginTransaction(pJetDBStruct->JetSesID))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetBeginTransaction) } fTransactionBegun = TRUE;
//
// Delete the entries of the catalog file from the DB
//
if (!_CatDBDeleteCatalogEntriesFromDatabase( pJetDBStruct, pwszCatalogFileFullPath)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// At this stage do the commit.
//
if (_CatDBJET_errFailure(jerr = JetCommitTransaction( pJetDBStruct->JetSesID, 0))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetCommitTransaction) } fTransactionBegun = FALSE;
if (!DeleteFileW(pwszCatalogFileFullPath)) { //
// Maybe the delete failed since the file doesn't even exist
//
if (GetLastError() != ERROR_FILE_NOT_FOUND) { //
// If the delete failed for a reason other than NOT_FOUND
// then another client is probably already accessing the file,
// so just copy it to a temp location and log it for deletion
//
if (!_CatDBMoveInUseFileToTempLocation(pwszCatalogFileFullPath)) { CATDBSVC_LOGERR_LASTERR()
//
// Don't return an error, since this isn't fatal
//
} } }
//
// Release DB back to the cache
//
_CatDBReleaseDatabaseToCache(pJetDBStruct);
//
// Notify client of changes
//
_CatDBNotifyClients();
_CatDBTouchTimeStampFile(pwszSubSysGUID);
CommonReturn:
if (pwszCatalogFileFullPath != NULL) { _CatDBFree(pwszCatalogFileFullPath); }
if (pwszCatalogFileDir != NULL) { _CatDBFree(pwszCatalogFileDir); }
if(fImpersonating) { if (RPC_S_OK != (RpcStatus = RpcRevertToSelf())) { MyLogErrorMessage((DWORD) RpcStatus, MSG_KEYSVC_REVERT_TO_SELF_FAILED); } }
LeaveCriticalSection(&g_CatDBAddDeleteCS);
_CatDBClientExit();
return dwRet;
ErrorReturn:
dwRet = GetLastError();
if (0 == dwRet) { dwRet = (DWORD) E_UNEXPECTED; }
if (fTransactionBegun) { JetRollback(pJetDBStruct->JetSesID, 0); }
if (fCatalogDatabaseAcquiredFromCache) { _CatDBReleaseDatabaseToCache(pJetDBStruct); }
goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorImpersonateClient) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetBeginTransaction) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetCommitTransaction) }
DWORD s_SSCatDBEnumCatalogs( /* [in] */ handle_t h, /* [in] */ DWORD dwFlags, /* [in] */ LPCWSTR pwszSubSysGUID, /* [in] */ DWORD cbHash, /* [size_is][in] */ BYTE __RPC_FAR *pbHash, /* [out] */ DWORD __RPC_FAR *pdwNumCatalogNames, /* [size_is][size_is][out] */ LPWSTR __RPC_FAR *__RPC_FAR *pppwszCatalogNames) { DWORD dwRet = ERROR_SUCCESS; JET_DB_STRUCT *pJetDBStruct; JET_ERR jerr; BOOL fCatalogDatabaseAcquiredFromCache = FALSE; CRYPT_HASH_BLOB HashBlob; JET_RETINFO JetRetInfo; WCHAR wszCatalogName[CATDB_MAX_CATNAME_LENGTH]; DWORD dwLength; DWORD i;
if (!_CatDBClientEnter()) { CATDBSVC_LOGERR_LASTERR() return (GetLastError()); }
if ((h == NULL) || (!_CatDBDVerifyGUIDString(pwszSubSysGUID))) { CATDBSVC_SETERR_LOG_RETURN(ERROR_BAD_ARGUMENTS, ErrorInvalidArg) }
//
// Init out vars
//
*pdwNumCatalogNames = 0; *pppwszCatalogNames = NULL;
//
// Open the database file
//
if (!_CatDBAcquireOpenDatabaseFromCache( &pJetDBStruct, pwszSubSysGUID, TRUE, FALSE)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } fCatalogDatabaseAcquiredFromCache = TRUE;
//
// Try to find the hash
//
HashBlob.pbData = pbHash; HashBlob.cbData = cbHash; jerr = _CatDBSeekInHashCatNameTable(pJetDBStruct, &HashBlob);
if (jerr == JET_errSuccess) { //
// Add all names from the Hashes CatNameList, plus all the buddys
// of those CatNames
//
// NOTE: the order in which the CatNames are added to the list results in
// only the first CatName of the list being guaranteed to contain the
// hash... all other CatNames may or may not contain the hash. This
// is OK because the client side code only assumes the first CatName
// contains the hash, and then explicitly searches all others for the hash.
//
memset(&JetRetInfo, 0, sizeof(JetRetInfo)); JetRetInfo.cbStruct = sizeof(JetRetInfo); JetRetInfo.itagSequence = 1; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo);
while (jerr == JET_errSuccess) { if (!_CatDBAddCatNameAndCatNamesBuddyListToReturnCatNames( pJetDBStruct, wszCatalogName, pdwNumCatalogNames, pppwszCatalogNames, FALSE)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Setup for next loop
//
JetRetInfo.itagSequence++; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo); }
//
// Check to see if a real error occurred and not just a JET_wrnColumnNull
//
if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } } else if ((jerr != JET_errRecordNotFound) && _CatDBJET_errFailure(jerr)) { //
// Some real error occurred
//
CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
if (fCatalogDatabaseAcquiredFromCache) { _CatDBReleaseDatabaseToCache(pJetDBStruct); }
_CatDBClientExit();
return dwRet;
ErrorReturn:
dwRet = GetLastError();
if (0 == dwRet) { dwRet = (DWORD) E_UNEXPECTED; }
for (i=0; i<(*pdwNumCatalogNames); i++) { midl_user_free((*pppwszCatalogNames)[i]); }
if ((*pppwszCatalogNames) != NULL) { midl_user_free(*pppwszCatalogNames); *pppwszCatalogNames = NULL; } *pdwNumCatalogNames = 0;
goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorInvalidArg) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBProcessExitCallback
//
//---------------------------------------------------------------------------------------
VOID CALLBACK _CatDBProcessExitCallback( PVOID lpParameter, BOOLEAN TimerOrWaitFired) { LONG lNotificationID = PtrToLong(lpParameter); DWORD i;
EnterCriticalSection(&g_CatDBRegisterNotifyCS);
//
// Search through the array to make sure the handle wasn't already unregistered
//
i = 0; while ( (i < g_NumNotificationStructs) && (g_rgNotificationStructs[i].lNotificationID != lNotificationID)) { i++; }
//
// If it was found, then clean it up.
//
if (i < g_NumNotificationStructs) { g_rgNotificationStructs[i].ProcessID = 0;
CloseHandle(g_rgNotificationStructs[i].hClientProcess); g_rgNotificationStructs[i].hClientProcess = NULL;
UnregisterWait(g_rgNotificationStructs[i].hRegisterWaitFor); g_rgNotificationStructs[i].hRegisterWaitFor = NULL;
g_rgNotificationStructs[i].hNotificationHandle = INVALID_HANDLE_VALUE;
CloseHandle(g_rgNotificationStructs[i].hDuplicatedNotificationHandle); g_rgNotificationStructs[i].hDuplicatedNotificationHandle = INVALID_HANDLE_VALUE;
g_rgNotificationStructs[i].lNotificationID = 0; }
LeaveCriticalSection(&g_CatDBRegisterNotifyCS); }
DWORD s_SSCatDBRegisterForChangeNotification( /* [in] */ handle_t h, /* [in] */ DWORD_PTR EventHandle, /* [in] */ DWORD dwFlags, /* [in] */ LPCWSTR pwszSubSysGUID, /* [in] */ BOOL fUnRegister) { DWORD dwRet = ERROR_SUCCESS; RPC_STATUS RpcStatus; HANDLE hDuplicate = INVALID_HANDLE_VALUE; DWORD i, j; HANDLE hWaitForToUnregister = NULL; HANDLE hClientProcess = NULL; LONG lLocalNotificationID = 0; BOOL fCSEntered = FALSE; DWORD dwPID = 0; NOTIFICATION_STRUCT *rghTemp;
if (!_CatDBClientEnter()) { CATDBSVC_LOGERR_LASTERR() return (GetLastError()); }
if ((h == NULL) || (!_CatDBDVerifyGUIDString(pwszSubSysGUID))) { return (ERROR_BAD_ARGUMENTS); }
if (RPC_S_OK != (RpcStatus = I_RpcBindingInqLocalClientPID(h, &dwPID))) { CATDBSVC_LOGERR(RpcStatus) return (ERROR_BAD_ARGUMENTS); }
//
// NOTE: this is a implementation that just notifies
// all clients when an add/delete catalog occurs... regardless
// of what catalog sub-system has been modified and what sub-system
// the client is operating in. Because of this implementation
// pwszCatalogDir is NOT USED. If this changes, the client side code
// will also need to change. See the NOTE in the
// _CatAdminRegisterForChangeNotification() function of catadnew.cpp
//
EnterCriticalSection(&g_CatDBRegisterNotifyCS); fCSEntered = TRUE;
//
// First check to see whether we are registering or unregestering
//
if (!fUnRegister) { //
// Make sure we can get a slot to add the handle to
//
i = 0; while ( (i < g_NumNotificationStructs) && (g_rgNotificationStructs[i].hClientProcess != NULL)) { i++; }
//
// If no space, allocate more
//
if (i >= g_NumNotificationStructs) { if (g_NumNotificationStructs == 0) { //
// None allocated yet, so allocate and initialize
//
if (NULL == (g_rgNotificationStructs = (NOTIFICATION_STRUCT *) _CatDBAlloc(sizeof(NOTIFICATION_STRUCT) * ALLOCATION_BLOCK_SIZE))) { CATDBSVC_LOGERR_LASTERR() goto ErrorMemory; }
g_NumNotificationStructs = ALLOCATION_BLOCK_SIZE;
for (j = 0; j < g_NumNotificationStructs; j++) { g_rgNotificationStructs[j].ProcessID = 0;
g_rgNotificationStructs[j].hClientProcess = NULL;
g_rgNotificationStructs[j].hRegisterWaitFor = NULL;
g_rgNotificationStructs[j].hNotificationHandle = INVALID_HANDLE_VALUE;
g_rgNotificationStructs[j].hDuplicatedNotificationHandle = INVALID_HANDLE_VALUE;
g_rgNotificationStructs[j].lNotificationID = 0; }
// set i so it can just be used as open slot
i = 0; } else { rghTemp = g_rgNotificationStructs;
if (NULL == (g_rgNotificationStructs = (NOTIFICATION_STRUCT *) _CatDBReAlloc(g_rgNotificationStructs, sizeof(NOTIFICATION_STRUCT) * (g_NumNotificationStructs + ALLOCATION_BLOCK_SIZE)))) { g_rgNotificationStructs = rghTemp; CATDBSVC_LOGERR_LASTERR() goto ErrorMemory; }
for ( j = g_NumNotificationStructs; j < (g_NumNotificationStructs + ALLOCATION_BLOCK_SIZE); j++) { g_rgNotificationStructs[j].ProcessID = 0;
g_rgNotificationStructs[j].hClientProcess = NULL;
g_rgNotificationStructs[j].hRegisterWaitFor = NULL;
g_rgNotificationStructs[j].hNotificationHandle = INVALID_HANDLE_VALUE;
g_rgNotificationStructs[j].hDuplicatedNotificationHandle = INVALID_HANDLE_VALUE;
g_rgNotificationStructs[j].lNotificationID = 0; }
// set i so it can just be used as open slot
i = g_NumNotificationStructs;
g_NumNotificationStructs += ALLOCATION_BLOCK_SIZE; } }
//
// Open the process' handle that is registering a notification since we need
// the process handle to duplicate the event handle that they want signaled,
// plus, we wait on it in case of process exit
//
if (NULL == (hClientProcess = OpenProcess( PROCESS_DUP_HANDLE | SYNCHRONIZE, FALSE, dwPID))) { CATDBSVC_LOGERR_LASTERR() goto ErrorOpenProcess; }
//
// Duplicate the handle
//
if (0 == (DuplicateHandle( hClientProcess, (HANDLE) EventHandle, GetCurrentProcess(), &hDuplicate, EVENT_MODIFY_STATE, //0,
FALSE, 0))) //DUPLICATE_SAME_ACCESS)))
{ CATDBSVC_LOGERR_LASTERR() goto ErrorDuplicateHandle; }
//
// Register a callback in case the process exits without unregistering
//
lLocalNotificationID = InterlockedIncrement(&g_lNotificationID);
if (!RegisterWaitForSingleObject( &(g_rgNotificationStructs[i].hRegisterWaitFor), hClientProcess, _CatDBProcessExitCallback, ULongToPtr(lLocalNotificationID), // use ULongToPtr instead of LongToPtr because
// ULongToPtr zero extends instead of sign extends
INFINITE, WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) {
CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
g_rgNotificationStructs[i].ProcessID = dwPID;
g_rgNotificationStructs[i].hClientProcess = hClientProcess; hClientProcess = NULL;
g_rgNotificationStructs[i].hNotificationHandle = (HANDLE) EventHandle;
g_rgNotificationStructs[i].hDuplicatedNotificationHandle = hDuplicate; hDuplicate = INVALID_HANDLE_VALUE;
g_rgNotificationStructs[i].lNotificationID = lLocalNotificationID; } else { //
// Search through the array to find the handle being unregisterd
//
i = 0; while (i < g_NumNotificationStructs) { //
// Match client based on ProcessID And EventHandle which is a unique pair
//
if ((g_rgNotificationStructs[i].hNotificationHandle == (HANDLE) EventHandle) && (g_rgNotificationStructs[i].ProcessID == dwPID)) { break; }
i++; }
//
// Make sure we found the handle
//
if (i < g_NumNotificationStructs) { g_rgNotificationStructs[i].ProcessID = 0;
hWaitForToUnregister = g_rgNotificationStructs[i].hRegisterWaitFor; g_rgNotificationStructs[i].hRegisterWaitFor = NULL;
hClientProcess = g_rgNotificationStructs[i].hClientProcess; g_rgNotificationStructs[i].hClientProcess = NULL;
g_rgNotificationStructs[i].hNotificationHandle = INVALID_HANDLE_VALUE;
CloseHandle(g_rgNotificationStructs[i].hDuplicatedNotificationHandle); g_rgNotificationStructs[i].hDuplicatedNotificationHandle = INVALID_HANDLE_VALUE;
g_rgNotificationStructs[i].lNotificationID = 0;
//
// Leave the RegisterNotitifyCS before calling UnregisterWait()
//
LeaveCriticalSection(&g_CatDBRegisterNotifyCS); fCSEntered = FALSE;
UnregisterWaitEx(hWaitForToUnregister, INVALID_HANDLE_VALUE); CloseHandle(hClientProcess); hClientProcess = NULL; } }
CommonReturn:
if (fCSEntered) { LeaveCriticalSection(&g_CatDBRegisterNotifyCS); }
if (hClientProcess != NULL) { CloseHandle(hClientProcess); }
if (hDuplicate != INVALID_HANDLE_VALUE) { CloseHandle(hDuplicate); }
_CatDBClientExit();
return dwRet;
ErrorReturn:
dwRet = GetLastError();
if (0 == dwRet) { dwRet = (DWORD) E_UNEXPECTED; }
goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorMemory) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorOpenProcess) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorDuplicateHandle) }
#define CATDB_RETRY_PAUSE_COUNT 10
#define CATDB_PAUSE_RETRY_INTERNVAL 1000
DWORD s_SSCatDBPauseResumeService( /* [in] */ handle_t h, /* [in] */ DWORD dwFlags, /* [in] */ BOOL fResume) { return (ERROR_CALL_NOT_IMPLEMENTED); }
/////////////////////////////////////////////////////////////////////////////////////////
//
// Supporting functions
//
/////////////////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------------------------
//
// _CatDBServiceInit
//
//---------------------------------------------------------------------------------------
BOOL _CatDBServiceInit(BOOL fUnInit) { BOOL fRet = TRUE; DWORD dwErr = 0; HKEY hKey; DWORD dwDisposition; WCHAR wszDefaultSystemDir[MAX_PATH + 1]; DWORD dwType; DWORD dwValue = 0; DWORD cbSize; DWORD NumCritSecsInitialized = 0; PVOID pvoid = NULL;
if (fUnInit && g_fDBSvcInitialized) { EnterCriticalSection(&g_CatDirCashCS); g_fShuttingDown = TRUE; LeaveCriticalSection(&g_CatDirCashCS);
//
// Close down the VSS writer object
//
_SystemWriterInit(TRUE);
_CatDBCleanupClientNotifications();
//
// Wait for the registered callback to be completed
//
pvoid = InterlockedExchangePointer( &g_hRegisterWaitForServiceShutdown, NULL);
if (pvoid != NULL) { UnregisterWaitEx((HANDLE) pvoid, INVALID_HANDLE_VALUE); }
CloseHandle(g_hCatalogCacheCallbackEvent); g_hCatalogCacheCallbackEvent = NULL;
//
// Cleanup the cached catalog dirs
//
if (!_CatDBCloseCachedDatabases(TRUE)) { CATDBSVC_LOGERR_LASTERR() //
// Nothing we can do but log an error
//
}
_CatDBTermJet();
CloseHandle(g_hNotFrozen); g_hNotFrozen = NULL;
if (g_pwszCatalogFileBaseDirectory != NULL) { _CatDBFree(g_pwszCatalogFileBaseDirectory); g_pwszCatalogFileBaseDirectory = NULL; }
if (g_pwszDatabaseFileBaseDirectory != NULL) { _CatDBFree(g_pwszDatabaseFileBaseDirectory); g_pwszDatabaseFileBaseDirectory = NULL; }
DeleteCriticalSection(&g_CatDBAddDeleteCS); DeleteCriticalSection(&g_CatDBRegisterNotifyCS); DeleteCriticalSection(&g_CatDirCashCS); DeleteCriticalSection(&g_CatClientCountCS); DeleteCriticalSection(&g_InitializeJetCS); DeleteCriticalSection(&g_WaitOrTimerCallbackCS);
g_fDBSvcInitialized = FALSE; } else if (!fUnInit) { g_fShuttingDown = FALSE;
__try { InitializeCriticalSection(&g_CatDBAddDeleteCS); NumCritSecsInitialized++; InitializeCriticalSection(&g_CatDBRegisterNotifyCS); NumCritSecsInitialized++; InitializeCriticalSection(&g_CatDirCashCS); NumCritSecsInitialized++; InitializeCriticalSection(&g_CatClientCountCS); NumCritSecsInitialized++; InitializeCriticalSection(&g_InitializeJetCS); NumCritSecsInitialized++; InitializeCriticalSection(&g_WaitOrTimerCallbackCS); NumCritSecsInitialized++; } __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(GetExceptionCode()); CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Get System default directory
//
wszDefaultSystemDir[0] = NULL; if (0 == GetSystemDirectoryW(wszDefaultSystemDir, MAX_PATH)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Create default dirs for catalog files and CatDB files
//
if (NULL == (g_pwszCatalogFileBaseDirectory = _CATDBConstructWSTRPath( wszDefaultSystemDir, WSZ_CATALOG_FILE_BASE_DIRECTORY))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (NULL == (g_pwszDatabaseFileBaseDirectory = _CATDBConstructWSTRPath( wszDefaultSystemDir, WSZ_DATABASE_FILE_BASE_DIRECTORY))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Get values to be used for timer callback, and database cache timeout
//
if (RegCreateKeyExW( HKEY_LOCAL_MACHINE, WSZ_REG_CATALOGDB_VALUES, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS) { cbSize = sizeof(DWORD);
if (RegQueryValueExW( hKey, WSZ_REG_DATABASE_TIMEOUT, NULL, &dwType, (BYTE *) &dwValue, &cbSize) == ERROR_SUCCESS) { g_dwCatalogDatabaseCacheTimeout = dwValue; }
dwValue = 0; cbSize = sizeof(DWORD);
if (RegQueryValueExW( hKey, WSZ_REG_CALLBACK_TIMER, NULL, &dwType, (BYTE *) &dwValue, &cbSize) == ERROR_SUCCESS) { g_dwCatalogDatabaseCacheCallbackTime = dwValue; }
RegCloseKey(hKey); }
//
// Create the event to be used in the call to RegisterWaitForSingleObject
//
if (NULL == (g_hCatalogCacheCallbackEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Create the g_hNotFrozen event (initially set to indicate not frozen)
//
if (NULL == (g_hNotFrozen = CreateEvent(NULL, TRUE, TRUE, NULL))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
LIST_Initialize(&g_CatalogDBCacheList);
//
// Startup the VSS writer object
//
// Note: This will spin off a thread to do the actual initialization of
// the vss writer object, which depends on services like COM+ and VSS.
//
_SystemWriterInit(FALSE);
g_fDBSvcInitialized = TRUE; }
CommonReturn:
return fRet;
ErrorReturn:
dwErr = GetLastError();
if (NumCritSecsInitialized >= 1) { DeleteCriticalSection(&g_CatDBAddDeleteCS); }
if (NumCritSecsInitialized >= 2) { DeleteCriticalSection(&g_CatDBRegisterNotifyCS); }
if (NumCritSecsInitialized >= 3) { DeleteCriticalSection(&g_CatDirCashCS); } if (NumCritSecsInitialized >= 4) { DeleteCriticalSection(&g_CatClientCountCS); }
if (NumCritSecsInitialized >= 5) { DeleteCriticalSection(&g_InitializeJetCS); }
if (NumCritSecsInitialized >= 6) { DeleteCriticalSection(&g_WaitOrTimerCallbackCS); }
if (g_pwszCatalogFileBaseDirectory != NULL) { _CatDBFree(g_pwszCatalogFileBaseDirectory); }
if (g_pwszDatabaseFileBaseDirectory != NULL) { _CatDBFree(g_pwszDatabaseFileBaseDirectory); }
if (g_hCatalogCacheCallbackEvent != NULL) { CloseHandle(g_hCatalogCacheCallbackEvent); g_hCatalogCacheCallbackEvent = NULL; }
if (g_hNotFrozen != NULL) { CloseHandle(g_hNotFrozen); g_hNotFrozen = NULL; }
SetLastError(dwErr);
fRet = FALSE; goto CommonReturn; }
//---------------------------------------------------------------------------------------
//
// _CatDBClientEnter
//
//---------------------------------------------------------------------------------------
BOOL _CatDBClientEnter(void) { BOOL fRet = TRUE;
EnterCriticalSection(&g_CatClientCountCS); g_dwClientCount++; LeaveCriticalSection(&g_CatClientCountCS);
return fRet; }
//---------------------------------------------------------------------------------------
//
// _CatDBClientExit
//
//---------------------------------------------------------------------------------------
void _CatDBClientExit(void) { EnterCriticalSection(&g_CatClientCountCS); g_dwClientCount--; LeaveCriticalSection(&g_CatClientCountCS); }
//---------------------------------------------------------------------------------------
//
// _CatDBTouchTimeStampFile
//
//---------------------------------------------------------------------------------------
void _CatDBTouchTimeStampFile( LPCWSTR pwszSubSysGUID) { LPWSTR pwsz = NULL;
if (NULL != (pwsz = _CATDBConstructWSTRPath( g_pwszDatabaseFileBaseDirectory, pwszSubSysGUID))) { TimeStampFile_Touch(pwsz); _CatDBFree(pwsz); } else { CATDBSVC_LOGERR_LASTERR() } }
//---------------------------------------------------------------------------------------
//
// _CatDBInitializeJet
//
//---------------------------------------------------------------------------------------
BOOL _CatDBInitializeJet( BOOL fInRecursiveCall) { BOOL fRet = TRUE; JET_ERR jerr;
EnterCriticalSection(&g_InitializeJetCS);
if (g_fJetInitialized) { goto CommonReturn; }
//
// Create a jet instance so multiple jet users can co-exist
// in the same process
//
jerr = JetCreateInstance(&g_JetInstance, SZ_CATALOG_DATABASE); if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(jerr, ErrorReturn) }
//
// Initialize Jets parameters
//
if (!_CatDBInitJetDatabaseParams(&g_JetInstance)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Jet will start up at this point
//
jerr = JetInit(&g_JetInstance);
//
// Check for specific JET errors, if we got one of those errors then
// the DB is corrupt in some way and we need to try and cleanup the
// catroot2 dir, and rebuild the DB.
//
// Of course we should only do this if we are not already recursing
//
if (!fInRecursiveCall && ((jerr == JET_errMissingLogFile) || (jerr == JET_errLogFileCorrupt) || (jerr == JET_errReadVerifyFailure) || (jerr == JET_errPageNotInitialized))) { CATDBSVC_LOGERR(jerr)
assert(0);
JetTerm(g_JetInstance); g_JetInstance = 0;
//
// Cleanup the catroot 2 directory and then rebuild the DB
//
if (_CatDBDeleteJetFiles() && _CatDBRebuildAllDBs()) { jerr = JET_errSuccess; } }
if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(jerr, ErrorReturn) }
g_fJetInitialized = TRUE;
CommonReturn:
LeaveCriticalSection(&g_InitializeJetCS);
return (fRet);
ErrorReturn:
if (g_JetInstance != 0) { JetTerm(g_JetInstance); g_JetInstance = 0; }
fRet = FALSE; goto CommonReturn; }
//---------------------------------------------------------------------------------------
//
// _CatDBTermJet
//
//---------------------------------------------------------------------------------------
BOOL _CatDBTermJet() { BOOL fRet = TRUE; JET_ERR jerr;
EnterCriticalSection(&g_InitializeJetCS);
if (!g_fJetInitialized || (g_lOpenedDBCount != 0)) { goto CommonReturn; }
//
// Shut Jet down!!
//
jerr = JetTerm(g_JetInstance); g_JetInstance = 0; g_fJetInitialized = FALSE;
if (_CatDBJET_errFailure(jerr)) { SetLastError(jerr); CATDBSVC_LOGERR(jerr) }
CommonReturn:
LeaveCriticalSection(&g_InitializeJetCS);
return (fRet); }
//---------------------------------------------------------------------------------------
//
// _CatDBAcquireOpenDatabaseFromCache
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAcquireOpenDatabaseFromCache( PJET_DB_STRUCT *ppJetDBStruct, LPCWSTR pwszSubSysGUID, BOOL fReadOnly, BOOL fInRecursiveCall) { BOOL fRet = TRUE; JET_ERR jerr; LPSTR pszDatabaseFileDir = NULL; LPSTR pszSubSysGUID = NULL; LPSTR pszTemp = NULL; BOOL fJetSessionBegun = FALSE; BOOL fJetDBFileOpen = FALSE; BOOL fCSEntered = FALSE; PJET_DB_STRUCT pJetDBStruct = NULL; LIST_NODE *pListNode = NULL; CATALOG_DIR_CACHE_STRUCT *pCatDirCacheStruct = NULL; CATALOG_DIR_CACHE_STRUCT *pNewCatDirCacheStruct = NULL; DWORD dwErr = 0; PVOID pvoid = NULL; HANDLE hTemp = NULL;
//
// check to see if we are shutting down, if so, get out
//
EnterCriticalSection(&g_CatDirCashCS); fCSEntered = TRUE; if (g_fShuttingDown) { CATDBSVC_SETERR_LOG_RETURN(ERROR_CAN_NOT_COMPLETE, ErrorReturn) } LeaveCriticalSection(&g_CatDirCashCS); fCSEntered = FALSE;
//
// Wait here if we're currently frozen
//
WaitForSingleObject(g_hNotFrozen,INFINITE);
//
// Do this here to ensure that JetTerm isn't called after the
// initialize below is called. This reference will be removed
// if an actuall cached DB is used.
//
InterlockedIncrement(&g_lOpenedDBCount);
//
// Make sure Jet is initialized
//
if (!_CatDBInitializeJet(fInRecursiveCall)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// First check to see if there is a cached session available
//
EnterCriticalSection(&g_CatDirCashCS); fCSEntered = TRUE;
pListNode = LIST_GetFirst(&g_CatalogDBCacheList);
while (pListNode != NULL) { pCatDirCacheStruct = (CATALOG_DIR_CACHE_STRUCT *) LIST_GetElement(pListNode);
if ((WaitForSingleObject(pCatDirCacheStruct->hDBNotInUse, 0) == WAIT_OBJECT_0) && (_wcsicmp(pCatDirCacheStruct->pwszSubSysGUID, pwszSubSysGUID) == 0)) /*&&
(pCatDirCacheStruct->fReadOnly == fReadOnly))*/ { break; }
pListNode = LIST_GetNext(pListNode); }
if (pListNode != NULL) { //
// Using a cached DB, which already has a ref count, so get rid of the
// one added at the beginning of the function
//
InterlockedDecrement(&g_lOpenedDBCount);
ResetEvent(pCatDirCacheStruct->hDBNotInUse); pCatDirCacheStruct->dwTimeLastTouched = GetTickCount(); *ppJetDBStruct = &(pCatDirCacheStruct->JetDBStruct); goto CommonReturn; }
//
// There are either no cached DBs for this dir, or they are already in use...
// So open a new instance
//
if (NULL == (pNewCatDirCacheStruct = (CATALOG_DIR_CACHE_STRUCT *) _CatDBAlloc(sizeof(CATALOG_DIR_CACHE_STRUCT)))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
memset(&(pNewCatDirCacheStruct->JetDBStruct), 0, sizeof(JET_DB_STRUCT)); pNewCatDirCacheStruct->hDBNotInUse = NULL; pNewCatDirCacheStruct->pwszSubSysGUID = NULL; pNewCatDirCacheStruct->dwTimeLastTouched = GetTickCount(); pNewCatDirCacheStruct->fReadOnly = fReadOnly;
//
// Create the DBNotInUse event for this new instance (initially clear to indicate in use)
//
pNewCatDirCacheStruct->hDBNotInUse = CreateEvent(NULL, TRUE, FALSE, NULL); if (pNewCatDirCacheStruct->hDBNotInUse == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Make a copy of the catalog database GUID
//
if (NULL == (pNewCatDirCacheStruct->pwszSubSysGUID = (LPWSTR) _CatDBAlloc((wcslen(pwszSubSysGUID) + 1) * sizeof(WCHAR)))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } wcscpy(pNewCatDirCacheStruct->pwszSubSysGUID, pwszSubSysGUID);
pJetDBStruct = &(pNewCatDirCacheStruct->JetDBStruct);
//
// Begin a session
//
if (_CatDBJET_errFailure(jerr = JetBeginSession( g_JetInstance, &(pJetDBStruct->JetSesID), NULL, NULL))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } fJetSessionBegun = TRUE;
//
// Get the fully qualified name of the database file
//
pszDatabaseFileDir = _CatDBConvertWszToSz(g_pwszDatabaseFileBaseDirectory); if (pszDatabaseFileDir == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
pszSubSysGUID = _CatDBConvertWszToSz(pwszSubSysGUID); if (pszSubSysGUID == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (NULL == (pszTemp = _CATDBConstructPath(pszDatabaseFileDir, pszSubSysGUID))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (NULL == (pJetDBStruct->pszDBFileName = _CATDBConstructPath(pszTemp, SZ_DBFILE_NAME))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Open the DB file... create it if it doesn't already exist
//
if (!_CatDBAttachAndOpenDatabase(pJetDBStruct, fReadOnly)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } fJetDBFileOpen = TRUE;
//
// Register the global close callback for cached DBs
//
if (!RegisterWaitForSingleObject( &hTemp, g_hCatalogCacheCallbackEvent, _CatDBWaitOrTimerCallback, NULL, // Context
g_dwCatalogDatabaseCacheCallbackTime, WT_EXECUTEDEFAULT)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
pvoid = InterlockedExchangePointer( &g_hRegisterWaitForServiceShutdown, hTemp);
//
// Add the opened database to the cache list
//
if (!LIST_AddTail(&g_CatalogDBCacheList, pNewCatDirCacheStruct)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
*ppJetDBStruct = &(pNewCatDirCacheStruct->JetDBStruct);
CommonReturn:
if (fCSEntered) { LeaveCriticalSection(&g_CatDirCashCS); }
//
// If there was already a callback registered, then unregister the one that was
// previously registered
//
if (pvoid != NULL) { UnregisterWaitEx((HANDLE) pvoid, INVALID_HANDLE_VALUE); }
if (pszDatabaseFileDir != NULL) { _CatDBFree(pszDatabaseFileDir); }
if (pszSubSysGUID != NULL) { _CatDBFree(pszSubSysGUID); }
if (pszTemp != NULL) { _CatDBFree(pszTemp); }
return fRet;
ErrorReturn:
dwErr = GetLastError();
if (fJetDBFileOpen) { JetCloseDatabase(pJetDBStruct->JetSesID, pJetDBStruct->JetDBID, 0); }
if (fJetSessionBegun) { JetEndSession(pJetDBStruct->JetSesID, 0); }
if (pNewCatDirCacheStruct != NULL) { if (pNewCatDirCacheStruct->hDBNotInUse) { CloseHandle(pNewCatDirCacheStruct->hDBNotInUse); }
if (pNewCatDirCacheStruct->JetDBStruct.pszDBFileName != NULL) { _CatDBFree(pNewCatDirCacheStruct->JetDBStruct.pszDBFileName); }
if (pNewCatDirCacheStruct->pwszSubSysGUID != NULL) { _CatDBFree(pNewCatDirCacheStruct->pwszSubSysGUID); }
_CatDBFree(pNewCatDirCacheStruct); }
InterlockedDecrement(&g_lOpenedDBCount);
SetLastError(dwErr);
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBReleaseDatabaseToCache
//
//---------------------------------------------------------------------------------------
BOOL _CatDBReleaseDatabaseToCache( PJET_DB_STRUCT pJetDBStruct) { //
// This cast works because the JET_DB_STRUCT is the first member of the
// CATALOG_DIR_CACHE_STRUCT
//
CATALOG_DIR_CACHE_STRUCT *pCatDirCacheStruct = (CATALOG_DIR_CACHE_STRUCT *) pJetDBStruct;
pCatDirCacheStruct->dwTimeLastTouched = GetTickCount(); SetEvent(pCatDirCacheStruct->hDBNotInUse);
return TRUE; }
//---------------------------------------------------------------------------------------
//
// _CatDBInstanceCount
//
//---------------------------------------------------------------------------------------
DWORD _CatDBInstanceCount( PWSTR pwszSubSysGUID) { DWORD dwResult = 0; LIST_NODE *pListNode = NULL; CATALOG_DIR_CACHE_STRUCT *pCatDirCacheStruct = NULL;
if (pwszSubSysGUID) { pListNode = LIST_GetFirst(&g_CatalogDBCacheList);
while (pListNode != NULL) { pCatDirCacheStruct = (CATALOG_DIR_CACHE_STRUCT *) LIST_GetElement(pListNode);
if (_wcsicmp(pCatDirCacheStruct->pwszSubSysGUID, pwszSubSysGUID) == 0) { ++dwResult; }
pListNode = LIST_GetNext(pListNode); } }
return dwResult; }
//---------------------------------------------------------------------------------------
//
// _CatDBCloseCachedDatabases
//
//---------------------------------------------------------------------------------------
BOOL _CatDBCloseCachedDatabases( BOOL fForceClose) { BOOL fRet = TRUE; BOOL fDatabaseFoundThatIsInUse = FALSE; BOOL fCloseFailed = FALSE; LIST_NODE *pListNode = NULL; CATALOG_DIR_CACHE_STRUCT *pCatDirCacheStruct = NULL; PVOID pvoid = NULL; DWORD dwWaitResult; BOOL fDetach;
EnterCriticalSection(&g_CatDirCashCS);
//
// Cycle through all open DBs and close them
//
pListNode = LIST_GetFirst(&g_CatalogDBCacheList);
while (pListNode != NULL) { pCatDirCacheStruct = (CATALOG_DIR_CACHE_STRUCT *) LIST_GetElement(pListNode);
//
// Is the instance currently in use?
// If a close is being forced, wait for the instance to be released
//
if (fForceClose) { dwWaitResult = WaitForSingleObject(pCatDirCacheStruct->hDBNotInUse, INFINITE); } else { dwWaitResult = WaitForSingleObject(pCatDirCacheStruct->hDBNotInUse, 0); }
//
// If the database is not in use AND
// a DB close is being forced by caller OR the DB hasn't been used in a while
// then close it
//
if ((dwWaitResult == WAIT_OBJECT_0) && (fForceClose || ((GetTickCount() - pCatDirCacheStruct->dwTimeLastTouched) > g_dwCatalogDatabaseCacheTimeout))) { //
// Only detach if we are closing the last instance
//
fDetach = (_CatDBInstanceCount(pCatDirCacheStruct->pwszSubSysGUID) == 1);
if (!_CatDBCloseDatabaseFile(&(pCatDirCacheStruct->JetDBStruct), fDetach)) { fCloseFailed = TRUE; CATDBSVC_LOGERR_LASTERR() } else { //
// Decrement the open DB count and check to see if there are anymore
// DBs open, if that was the last one, then terminate Jet
//
if (0 == InterlockedDecrement(&g_lOpenedDBCount)) { _CatDBTermJet(); } }
CloseHandle(pCatDirCacheStruct->hDBNotInUse);
_CatDBFree(pCatDirCacheStruct->JetDBStruct.pszDBFileName); _CatDBFree(pCatDirCacheStruct->pwszSubSysGUID);
pListNode = LIST_GetNext(pListNode); LIST_RemoveElement(&g_CatalogDBCacheList, pCatDirCacheStruct); _CatDBFree(pCatDirCacheStruct);
} else { fDatabaseFoundThatIsInUse = TRUE; pListNode = LIST_GetNext(pListNode); } }
if (fDatabaseFoundThatIsInUse || fCloseFailed) { fRet = FALSE; }
LeaveCriticalSection(&g_CatDirCashCS);
return fRet; }
//---------------------------------------------------------------------------------------
//
// _CatDBWaitOrTimerCallback
//
//---------------------------------------------------------------------------------------
VOID CALLBACK _CatDBWaitOrTimerCallback( PVOID lpParameter, BOOLEAN fTimedOut) { BOOL fClosed = FALSE; PVOID pvoid = NULL;
//
// Make sure only one thread executes the callback at a time
//
EnterCriticalSection(&g_WaitOrTimerCallbackCS);
//
// If we are being called because we timed out (the event wasn't set), that
// means we should close the database if possible... otherwise, the event
// was set because we are shutting down, so don't do anything and just let the
// shutdown-cleanup code handle it.
//
if (fTimedOut) { //
// If the close succeeds that means there are no DBs still in use, so we should
// unregister the callback
//
fClosed = _CatDBCloseCachedDatabases(FALSE);
//
// Since we have a thread, try to clean up the temp files
//
_CatDBCleanupTempFiles(); }
//
// if there does not need to be another callback then unregister
//
if (fClosed) { pvoid = InterlockedExchangePointer( &g_hRegisterWaitForServiceShutdown, NULL); if (pvoid != NULL) { UnregisterWait((HANDLE) pvoid); } }
LeaveCriticalSection(&g_WaitOrTimerCallbackCS); }
//---------------------------------------------------------------------------------------
//
// _CatDBAddCatalogEntriesToDatabase
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddCatalogEntriesToDatabase( PJET_DB_STRUCT pJetDBStruct, PCCTL_CONTEXT pCTLContext, LPWSTR pwszNewCatalogName) { BOOL fRet = TRUE; WCHAR *pwszCatBaseName; DWORD i; CRYPT_DATA_BLOB CryptDataBlob; SPC_INDIRECT_DATA_CONTENT *pIndirectData = NULL;
CryptDataBlob.pbData = NULL;
//
// Extract the base name from the full path name
//
if (NULL == (pwszCatBaseName = wcsrchr(pwszNewCatalogName, L'\\'))) { pwszCatBaseName = wcsrchr(pwszNewCatalogName, L':'); }
if (pwszCatBaseName != NULL) { pwszCatBaseName++; } else { pwszCatBaseName = pwszNewCatalogName; }
//
// Loop for each hash in the catalog file
//
for (i=0; i<pCTLContext->pCtlInfo->cCTLEntry; i++) { if (!_CatDBFindAndDecodeHashInCatEntry( &(pCTLContext->pCtlInfo->rgCTLEntry[i]), &pIndirectData)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (!_CatDBAddHashCatNamePair( pJetDBStruct, &(pIndirectData->Digest), pwszCatBaseName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
_CatDBFree(pIndirectData); pIndirectData = NULL; }
CommonReturn:
return fRet;
ErrorReturn:
if (pIndirectData != NULL) { _CatDBFree(pIndirectData); }
fRet = FALSE; goto CommonReturn; }
//---------------------------------------------------------------------------------------
//
// _CatDBAddHashCatNamePair
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddHashCatNamePair( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName) { BOOL fRet = TRUE; JET_ERR jerr;
//
// First, try to find the hash in the HashCatName table.
//
jerr = _CatDBSeekInHashCatNameTable(pJetDBStruct, pHashBlob);
if (jerr == JET_errRecordNotFound) { //
// not found
//
if (!_CatDBAddNewRowToHashCatNameTable( pJetDBStruct, pHashBlob, pwszCatBaseName)) { goto ErrorReturn; } } else if (jerr == JET_errSuccess) { //
// found
//
if (!_CatDBAddValueToExistingHashCatNameRow( pJetDBStruct, pHashBlob, pwszCatBaseName)) { goto ErrorReturn; } } else if (_CatDBJET_errFailure(jerr)) { //
// error
//
CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBAddNewRowToHashCatNameTable
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddNewRowToHashCatNameTable( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName) { BOOL fRet = TRUE; JET_ERR jerr; JET_SETINFO JetSetInfo;
//
// Create the new row, and insert the values
//
if (_CatDBJET_errFailure(jerr = JetPrepareUpdate( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, JET_prepInsert))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
// hash
if (_CatDBJET_errFailure(jerr = JetSetColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_HashColumnID, pHashBlob->pbData, pHashBlob->cbData, 0, NULL))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
// catname
memset(&JetSetInfo, 0, sizeof(JetSetInfo)); JetSetInfo.cbStruct = sizeof(JetSetInfo); JetSetInfo.itagSequence = 1; if (_CatDBJET_errFailure(jerr = JetSetColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, (BYTE const *) pwszCatBaseName, (wcslen(pwszCatBaseName) + 1) * sizeof(WCHAR), 0, &JetSetInfo))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetUpdate( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, NULL, 0, NULL))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBAddValueToExistingHashCatNameRow
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddValueToExistingHashCatNameRow( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName) { BOOL fRet = TRUE; JET_ERR jerr; JET_SETINFO JetSetInfo; WCHAR wszCatalogName[CATDB_MAX_CATNAME_LENGTH]; DWORD dwLength; JET_RETINFO JetRetInfo;
//
// Make sure we are not here because a single hash is in the same catalog twice...
//
//
if (_CatDBCatnameAlreadyInHashesListOfCats( pJetDBStruct, pHashBlob, pwszCatBaseName)) { goto CommonReturn; }
//
// Create a row in the CatNameBuddy Table for the current catalog if it
// doesn't already exist
//
if (!_CatDBAddNewRowToCatNameBuddyTableIfNotExists( pJetDBStruct, pwszCatBaseName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Get each catalog name in the current hashes CatNameList and add it to the
// current catalogs buddy list
//
memset(&JetRetInfo, 0, sizeof(JetRetInfo)); JetRetInfo.cbStruct = sizeof(JetRetInfo); JetRetInfo.itagSequence = 1; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo);
while (jerr == JET_errSuccess) { if (!_CatDBAddNewRowToCatNameBuddyTableIfNotExists( pJetDBStruct, wszCatalogName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Add the buddy that was found to the current catalogs buddy list
//
if (!_CatDBAddNameToBuddyList( pJetDBStruct, wszCatalogName, pwszCatBaseName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Add the buddys of the buddy that was found, to current catalogs buddy list
//
if (!_CatDBAddWholeBuddyList( pJetDBStruct, pwszCatBaseName, wszCatalogName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Add the current catalog to the buddy list of the buddy that was found
//
if (!_CatDBAddNameToBuddyList( pJetDBStruct, pwszCatBaseName, wszCatalogName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Setup for next loop
//
JetRetInfo.itagSequence++; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo); }
//
// Check to see if a real error occurred and not just a JET_wrnColumnNull
//
if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
//
// Add the current catalog to the CatNameList of the current hash
//
if (_CatDBJET_errFailure(jerr = JetPrepareUpdate( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, JET_prepReplace))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
memset(&JetSetInfo, 0, sizeof(JetSetInfo)); JetSetInfo.cbStruct = sizeof(JetSetInfo); JetSetInfo.itagSequence = 0; // insert into next open position
if (_CatDBJET_errFailure(jerr = JetSetColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, (BYTE const *) pwszCatBaseName, (wcslen(pwszCatBaseName) + 1) * sizeof(WCHAR), 0, &JetSetInfo))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetUpdate( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, NULL, 0, NULL))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBCatnameAlreadyInHashesListOfCats
//
//---------------------------------------------------------------------------------------
BOOL _CatDBCatnameAlreadyInHashesListOfCats( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName) { JET_ERR jerr; WCHAR wszCatalogName[CATDB_MAX_CATNAME_LENGTH]; DWORD dwLength; JET_RETINFO JetRetInfo;
//
// Get each catalog name in the current hashes CatNameList see if it is the same
// as pwszCatBaseName
//
memset(&JetRetInfo, 0, sizeof(JetRetInfo)); JetRetInfo.cbStruct = sizeof(JetRetInfo); JetRetInfo.itagSequence = 1; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo);
while (jerr == JET_errSuccess) { if (_wcsicmp(wszCatalogName, pwszCatBaseName) == 0) { //
// Duplicate found
//
return TRUE; }
//
// Setup for next loop
//
JetRetInfo.itagSequence++; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo); }
//
// No duplicates were found
//
return FALSE; }
//---------------------------------------------------------------------------------------
//
// _CatDBAddNewRowToCatNameBuddyTableIfNotExists
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddNewRowToCatNameBuddyTableIfNotExists( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatBaseName) { BOOL fRet = TRUE; JET_ERR jerr;
//
// Try to find the CatName in the CatNameBuddy table.
//
jerr = _CatDBSeekInCatNameBuddyTable(pJetDBStruct, pwszCatBaseName); if (jerr == JET_errRecordNotFound) { //
// not found, so add the row
//
if (!_CatDBAddNewRowToCatNameBuddyTable(pJetDBStruct, pwszCatBaseName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } } else if (_CatDBJET_errFailure(jerr)) { //
// error
//
CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } // else, it was found, so just return successfully
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBAddNewRowToCatNameBuddyTable
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddNewRowToCatNameBuddyTable( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatBaseName) { BOOL fRet = TRUE; JET_ERR jerr; JET_SETINFO JetSetInfo;
//
// Create the new row, and insert the values
//
if (_CatDBJET_errFailure(jerr = JetPrepareUpdate( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, JET_prepInsert))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
// catname
if (_CatDBJET_errFailure(jerr = JetSetColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, pJetDBStruct->JetCatNameBuddyTable_CatNameColumnID, (BYTE const *) pwszCatBaseName, (wcslen(pwszCatBaseName) + 1) * sizeof(WCHAR), 0, NULL))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetUpdate( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, NULL, 0, NULL))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBAddNameToBuddyList
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddNameToBuddyList( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszNameToAdd, LPWSTR pwszListToAddTo) { BOOL fRet = TRUE; JET_ERR jerr; JET_SETINFO JetSetInfo; JET_RETINFO JetRetInfo; WCHAR wszCatalogName[CATDB_MAX_CATNAME_LENGTH]; DWORD dwLength;
//
// Don't add the same name to itself
//
if (_wcsicmp(pwszNameToAdd, pwszListToAddTo) == 0) { goto CommonReturn; }
//
// seek to the pwszListToAddTo row in the CatNameBuddy table
//
jerr = _CatDBSeekInCatNameBuddyTable(pJetDBStruct, pwszListToAddTo); if (jerr == JET_errRecordNotFound) { //
// this bad, since we know the row should exist
//
CATDBSVC_SETERR_LOG_RETURN(JET_errRecordNotFound, ErrorJetDatabase) } else if (_CatDBJET_errFailure(jerr)) { //
// error
//
CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
//
// Check to see if the buddy being added is already there.
//
memset(&JetRetInfo, 0, sizeof(JetRetInfo)); JetRetInfo.cbStruct = sizeof(JetRetInfo); JetRetInfo.itagSequence = 1; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, pJetDBStruct->JetCatNameBuddyTable_BuddyColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo);
while (jerr == JET_errSuccess) { //
// Compare to see if this is the name we are supposed to add,
// if so, we are done, so get out
//
if (_wcsicmp(pwszNameToAdd, wszCatalogName) == 0) { goto CommonReturn; }
//
// Setup for next loop
//
JetRetInfo.itagSequence++; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, pJetDBStruct->JetCatNameBuddyTable_BuddyColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo); }
//
// Check to see if a real error occurred and not just a JET_wrnColumnNull
//
if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
//
// Prepare, then insert the new buddy name into the list
//
if (_CatDBJET_errFailure(jerr = JetPrepareUpdate( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, JET_prepReplace))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
memset(&JetSetInfo, 0, sizeof(JetSetInfo)); JetSetInfo.cbStruct = sizeof(JetSetInfo); JetSetInfo.itagSequence = 0; // insert in next open position
if (_CatDBJET_errFailure(jerr = JetSetColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, pJetDBStruct->JetCatNameBuddyTable_BuddyColumnID, (BYTE const *) pwszNameToAdd, (wcslen(pwszNameToAdd) + 1) * sizeof(WCHAR), 0, &JetSetInfo))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetUpdate( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, NULL, 0, NULL))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBAddWholeBuddyList
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddWholeBuddyList( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszBuddyToAddTo, LPWSTR pwszBuddyListName) { BOOL fRet = TRUE; JET_ERR jerr; JET_RETINFO JetRetInfo; WCHAR wszCatalogName[CATDB_MAX_CATNAME_LENGTH]; DWORD dwLength;
//
// seek to the pwszBuddyListName row in the CatNameBuddy table
//
jerr = _CatDBSeekInCatNameBuddyTable(pJetDBStruct, pwszBuddyListName); if (jerr == JET_errRecordNotFound) { //
// this bad, since we know the row should exist
//
CATDBSVC_SETERR_LOG_RETURN(JET_errRecordNotFound, ErrorJetDatabase) } else if (_CatDBJET_errFailure(jerr)) { //
// error
//
CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
//
// Get each buddy in the list and add it to pwszBuddyToAddTo's buddy list
//
memset(&JetRetInfo, 0, sizeof(JetRetInfo)); JetRetInfo.cbStruct = sizeof(JetRetInfo); JetRetInfo.itagSequence = 1; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, pJetDBStruct->JetCatNameBuddyTable_BuddyColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo);
while (jerr == JET_errSuccess) { //
// Add the buddy that was found to the current catalogs buddy list
//
if (!_CatDBAddNameToBuddyList( pJetDBStruct, wszCatalogName, pwszBuddyToAddTo)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// setup for next loop
//
//
// NOTE - we have to re-seek since the cursor was reset in
// the _CatDBAddNameToBuddyList call
//
jerr = _CatDBSeekInCatNameBuddyTable(pJetDBStruct, pwszBuddyListName); if (jerr == JET_errRecordNotFound) { //
// this bad, since we know the row should exist
//
CATDBSVC_SETERR_LOG_RETURN(JET_errRecordNotFound, ErrorJetDatabase) } else if (jerr != JET_errSuccess) { //
// error
//
CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
JetRetInfo.itagSequence++; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, pJetDBStruct->JetCatNameBuddyTable_BuddyColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo); }
//
// Check to see if a real error occurred and not just a JET_wrnColumnNull
//
if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBMoveInUseFileToTempLocation
//
//---------------------------------------------------------------------------------------
BOOL _CatDBMoveInUseFileToTempLocation( LPWSTR pwszFile ) { BOOL fRet = TRUE; WCHAR wszTempFile[MAX_PATH]; HKEY hKey = NULL; HKEY hKey2 = NULL; DWORD dwDisposition; DWORD i;
//
// Get the temp file name that the file will be renamed to
//
if (0 == GetTempFileNameW( g_pwszCatalogFileBaseDirectory, L"TMP", 0, wszTempFile)) { CATDBSVC_LOGERR_LASTERR() goto ErrorGetTempFileName; }
//
// Move the file to a temporary location
//
if (!MoveFileExW(pwszFile, wszTempFile, MOVEFILE_REPLACE_EXISTING)) { DeleteFileW(wszTempFile); CATDBSVC_LOGERR_LASTERR() goto ErrorMoveFile; }
//
// The moved copy is still being accessed, so log the name of the file
// to make sure it gets cleaned up later.
//
if (RegCreateKeyExW( HKEY_LOCAL_MACHINE, WSZ_REG_TEMP_FILES_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS) { //
// convert all '\\' to '*'
//
for (i=0; i<wcslen(wszTempFile); i++) { if (wszTempFile[i] == L'\\') { wszTempFile[i] = L'*'; } }
if (RegCreateKeyW( hKey, wszTempFile, &hKey2) == ERROR_SUCCESS) { RegCloseKey(hKey2); } }
CommonReturn:
if (hKey != NULL) { RegCloseKey(hKey); }
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorGetTempFileName) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorMoveFile) }
//---------------------------------------------------------------------------------------
//
// _CatDBCleanupTempFiles
//
//---------------------------------------------------------------------------------------
void _CatDBCleanupTempFiles() { HKEY hKey = NULL; HKEY hKey2 = NULL; DWORD dwIndex = 0; DWORD dwRet = 0; DWORD dwDisposition; WCHAR wszFileToDelete[MAX_PATH + 1]; DWORD i;
//
// Open the key that contains all the tempfile name keys
//
if (RegCreateKeyExW( HKEY_LOCAL_MACHINE, WSZ_REG_TEMP_FILES_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS) { //
// Query to see how many keys there are
//
if (RegQueryInfoKey( hKey, NULL, NULL, NULL, &dwIndex, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { dwIndex--;
//
// Enumerate through all the keys and try to delete the
// corresponding temp files
//
while (RegEnumKeyW( hKey, dwIndex, wszFileToDelete, MAX_PATH + 1) == ERROR_SUCCESS) { //
// Delete the key first
//
RegDeleteKey(hKey, wszFileToDelete);
//
// convert all '*' back to '\\'
//
for (i=0; i<wcslen(wszFileToDelete); i++) { if (wszFileToDelete[i] == L'*') { wszFileToDelete[i] = L'\\'; } }
//
// If the delete fails for any reason other than file not found
// add the key back to try and delete it later.
//
if ((DeleteFileW(wszFileToDelete) == 0) && (GetLastError() != ERROR_FILE_NOT_FOUND)) { //
// convert all '\\' back to '*' and then add the reg key back
//
for (i=0; i<wcslen(wszFileToDelete); i++) { if (wszFileToDelete[i] == L'\\') { wszFileToDelete[i] = L'*'; } }
if (RegCreateKeyW( hKey, wszFileToDelete, &hKey2) == ERROR_SUCCESS) { RegCloseKey(hKey2); } }
dwIndex--; } }
RegCloseKey(hKey); } }
//---------------------------------------------------------------------------------------
//
// _CatDBDeleteCatalogEntriesFromDatabase
//
//---------------------------------------------------------------------------------------
BOOL _CatDBDeleteCatalogEntriesFromDatabase( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatalogName) { BOOL fRet = TRUE; PCCTL_CONTEXT pCTLContext = NULL; HANDLE hMappedFile = NULL; BYTE *pbMappedFile = NULL; WCHAR *pwszCatBaseName; DWORD i; SPC_INDIRECT_DATA_CONTENT *pIndirectData = NULL; BOOL fDeleteUsingName = TRUE; DWORD dwErr = 0;
//
// Extract the base name from the full path name
//
if (NULL == (pwszCatBaseName = wcsrchr(pwszCatalogName, L'\\'))) { pwszCatBaseName = wcsrchr(pwszCatalogName, L':'); }
if (pwszCatBaseName != NULL) { pwszCatBaseName++; } else { pwszCatBaseName = pwszCatalogName; }
//
// Open a CTL context on the catalog file whose entries are being deleted
//
if (CatUtil_CreateCTLContextFromFileName( pwszCatalogName, &hMappedFile, &pbMappedFile, &pCTLContext, FALSE)) { //
// Since we can create a CTL context on the catalog, first try to
// delete without walking the whole HashCatnameTable, which we will
// have to do if we delete using the catalog name only
//
fDeleteUsingName = FALSE;
//
// Loop for each hash in the catalog file
//
for (i=0; i<pCTLContext->pCtlInfo->cCTLEntry; i++) { if (!_CatDBFindAndDecodeHashInCatEntry( &(pCTLContext->pCtlInfo->rgCTLEntry[i]), &pIndirectData)) { //
// Since this failed, fallback and try to delete the catalog
// from the DB using the catalogs name only
//
fDeleteUsingName = TRUE; break; }
if (!_CatDBRemoveCatNameFromHashesListOfCatNames( pJetDBStruct, &(pIndirectData->Digest), pwszCatBaseName)) { //
// Since this failed, fallback and try to delete the catalog
// from the DB using the catalogs name only
//
fDeleteUsingName = TRUE; break; }
_CatDBFree(pIndirectData); pIndirectData = NULL; } }
if (fDeleteUsingName) { //
// Since that failed, the catalog is most likely corrupt, so just use
// the catalog name to delete its entries from the HashCatName table
//
if (!_CatDBRemoveCatNameFromCatNameTable( pJetDBStruct, pwszCatBaseName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } }
//
// Delete all occurences of CatName from buddy table
//
if (!_CatDBRemoveCatNameFromBuddyTable( pJetDBStruct, pwszCatBaseName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
CommonReturn:
dwErr = GetLastError();
if (pIndirectData != NULL) { _CatDBFree(pIndirectData); }
if (pCTLContext != NULL) { CertFreeCTLContext(pCTLContext); } if (pbMappedFile != NULL) { UnmapViewOfFile(pbMappedFile); }
if (hMappedFile != NULL) { CloseHandle(hMappedFile); }
SetLastError(dwErr);
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn; }
//---------------------------------------------------------------------------------------
//
// _CatDBRemoveCatNameFromHashesListOfCatNames
//
//---------------------------------------------------------------------------------------
BOOL _CatDBRemoveCatNameFromHashesListOfCatNames( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob, LPWSTR pwszCatBaseName) { BOOL fRet = TRUE; JET_ERR jerr;
//
// First, try to find the hash in the HashCatName table.
//
jerr = _CatDBSeekInHashCatNameTable(pJetDBStruct, pHashBlob);
if (jerr == JET_errRecordNotFound) { //
// Not found, this is OK since a single catalog may contain the same hash
// twice, in which case by the second time the hash is being looked for
// the row may already be gone.
//
goto CommonReturn; } else if (jerr == JET_errSuccess) { //
// found
//
if (!_CatDBRemoveCatNameFromMultiValuedColumn( pJetDBStruct, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, pwszCatBaseName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } } else if (_CatDBJET_errFailure(jerr)) { //
// error
//
CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBRemoveCatNameFromMultiValuedColumn
//
//---------------------------------------------------------------------------------------
BOOL _CatDBRemoveCatNameFromMultiValuedColumn( PJET_DB_STRUCT pJetDBStruct, JET_TABLEID jetTableID, JET_COLUMNID jetColumnID, LPWSTR pwszCatBaseName) { BOOL fRet = TRUE; JET_ERR jerr; JET_SETINFO JetSetInfo; WCHAR wszCatalogName[CATDB_MAX_CATNAME_LENGTH]; DWORD dwLength; JET_RETINFO JetRetInfo; BOOL fDeleteRow = FALSE; unsigned long iValueToDelete = 0;
//
// Search for the CatName in the current row
//
memset(&JetRetInfo, 0, sizeof(JetRetInfo)); JetRetInfo.cbStruct = sizeof(JetRetInfo); JetRetInfo.itagSequence = 1; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, jetTableID, jetColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo);
while (jerr == JET_errSuccess) { //
// See if this is the one
//
if (0 == _wcsicmp(pwszCatBaseName, wszCatalogName)) { iValueToDelete = JetRetInfo.itagSequence;
if (JetRetInfo.itagSequence == 1) { //
// If this CatName is the only one in the row, then
// set a flag to just delete the row
//
JetRetInfo.itagSequence = 2; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, jetTableID, jetColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo);
if (jerr == JET_wrnColumnNull) { jerr = JET_errSuccess; fDeleteRow = TRUE; } } break; }
//
// Setup for next loop
//
JetRetInfo.itagSequence++; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, jetTableID, jetColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo); }
//
// Make sure the CatName was found
//
if (jerr == JET_wrnColumnNull) { //
// Not found, this is OK
//
goto CommonReturn;
} else if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
//
// If this CatName is the only one in the row, then just delete the row,
// otherwise, remove it from the multi-valued column
//
if (fDeleteRow) { if (_CatDBJET_errFailure(jerr = JetDelete( pJetDBStruct->JetSesID, jetTableID))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } } else { //
// Remove the CatName from the current row
//
if (_CatDBJET_errFailure(jerr = JetPrepareUpdate( pJetDBStruct->JetSesID, jetTableID, JET_prepReplace))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
memset(&JetSetInfo, 0, sizeof(JetSetInfo)); JetSetInfo.cbStruct = sizeof(JetSetInfo); JetSetInfo.itagSequence = iValueToDelete; if (_CatDBJET_errFailure(jerr = JetSetColumn( pJetDBStruct->JetSesID, jetTableID, jetColumnID, NULL, 0, 0, &JetSetInfo))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetUpdate( pJetDBStruct->JetSesID, jetTableID, NULL, 0, NULL))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBRemoveCatNameFromCatNameTable
//
//---------------------------------------------------------------------------------------
BOOL _CatDBRemoveCatNameFromCatNameTable( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatBaseName) { BOOL fRet = TRUE; JET_ERR jerr;
//
// Delete this CatName from every row that contains it
//
jerr = JetMove( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, JET_MoveFirst, 0);
while (jerr == JET_errSuccess) { if (!_CatDBRemoveCatNameFromMultiValuedColumn( pJetDBStruct, pJetDBStruct->JetHashCatNameTableID, pJetDBStruct->JetHashCatNameTable_CatNameColumnID, pwszCatBaseName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Setup for next loop
//
jerr = JetMove( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, JET_MoveNext, 0); }
//
// See if this was a real error, or just no more records
//
if ((jerr != JET_errNoCurrentRecord) && _CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBRemoveCatNameFromBuddyTable
//
//---------------------------------------------------------------------------------------
BOOL _CatDBRemoveCatNameFromBuddyTable( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatBaseName) { BOOL fRet = TRUE; JET_ERR jerr;
//
// First, delete this CatName's buddy list
//
jerr = _CatDBSeekInCatNameBuddyTable(pJetDBStruct, pwszCatBaseName);
if (jerr == JET_errSuccess) { if (_CatDBJET_errFailure(jerr = JetDelete( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } }
//
// Second, delete this CatName from everyone elses buddy list
//
jerr = JetMove( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, JET_MoveFirst, 0);
while (jerr == JET_errSuccess) { if (!_CatDBRemoveCatNameFromMultiValuedColumn( pJetDBStruct, pJetDBStruct->JetCatNameBuddyTableID, pJetDBStruct->JetCatNameBuddyTable_BuddyColumnID, pwszCatBaseName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Setup for next loop
//
jerr = JetMove( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, JET_MoveNext, 0); }
//
// See if this was a real error, or just no more records
//
if ((jerr != JET_errNoCurrentRecord) && _CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBAddCatNameAndCatNamesBuddyListToReturnCatNames
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddCatNameAndCatNamesBuddyListToReturnCatNames( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszCatName, DWORD __RPC_FAR *pdwNumCatalogNames, LPWSTR __RPC_FAR *__RPC_FAR *pppwszCatalogNames, BOOL fRecursiveCall) { BOOL fRet = TRUE; JET_ERR jerr; JET_RETINFO JetRetInfo; WCHAR wszCatalogName[CATDB_MAX_CATNAME_LENGTH]; DWORD dwLength;
//
// First add the original catname
//
if (!_CatDBAddCatNameToReturnBuddyListIfNotExist( pwszCatName, pdwNumCatalogNames, pppwszCatalogNames)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Seek to the catname's buddy list
//
jerr = _CatDBSeekInCatNameBuddyTable(pJetDBStruct, pwszCatName);
if (jerr == JET_errSuccess) { //
// Add all the catname's buddies, and catname's buddies' buddies (only do one recursion)
//
memset(&JetRetInfo, 0, sizeof(JetRetInfo)); JetRetInfo.cbStruct = sizeof(JetRetInfo); JetRetInfo.itagSequence = 1; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, pJetDBStruct->JetCatNameBuddyTable_BuddyColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo);
while (jerr == JET_errSuccess) { if (fRecursiveCall) { if (!_CatDBAddCatNameToReturnBuddyListIfNotExist( wszCatalogName, pdwNumCatalogNames, pppwszCatalogNames)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } } else { //
// Recurse to get the buddies' buddies
//
if (!_CatDBAddCatNameAndCatNamesBuddyListToReturnCatNames( pJetDBStruct, wszCatalogName, pdwNumCatalogNames, pppwszCatalogNames, TRUE)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } }
//
// Re-seek to the catname's buddy list, since it could have moved in the
// recursive call to this function
//
jerr = _CatDBSeekInCatNameBuddyTable(pJetDBStruct, pwszCatName); if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
//
// Setup for next loop
//
JetRetInfo.itagSequence++; jerr = JetRetrieveColumn( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, pJetDBStruct->JetCatNameBuddyTable_BuddyColumnID, wszCatalogName, CATDB_MAX_CATNAME_LENGTH, &dwLength, JET_bitRetrieveCopy, &JetRetInfo); }
//
// Check to see if a real error occurred and not just a JET_wrnColumnNull
//
if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBAddCatNameToReturnBuddyListIfNotExist
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAddCatNameToReturnBuddyListIfNotExist( LPWSTR pwszBuddy, DWORD __RPC_FAR *pdwNumCatalogNames, LPWSTR __RPC_FAR *__RPC_FAR *pppwszCatalogNames) { BOOL fRet = TRUE; DWORD i; BOOL fAlreadyExists = FALSE; LPWSTR *rgTemp = NULL;
//
// First, see if the name already exists in the list
//
for (i=0; i<(*pdwNumCatalogNames); i++) { if (_wcsicmp((*pppwszCatalogNames)[i], pwszBuddy) == 0) { fAlreadyExists = TRUE; break; } }
//
// Add it if it doesn't already exist
//
if (!fAlreadyExists) { //
// Allocate a new slot in the array of buddy names
//
if ((*pdwNumCatalogNames) == 0) { *pppwszCatalogNames = (LPWSTR __RPC_FAR *) midl_user_allocate(sizeof(LPWSTR)); } else { rgTemp = *pppwszCatalogNames; *pppwszCatalogNames = (LPWSTR __RPC_FAR *) midl_user_reallocate( *pppwszCatalogNames, ((*pdwNumCatalogNames) + 1) * sizeof(LPWSTR)); }
//
// Make sure allocation worked
//
if ((*pppwszCatalogNames) == NULL) { *pppwszCatalogNames = rgTemp; CATDBSVC_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) }
(*pppwszCatalogNames)[(*pdwNumCatalogNames)] = (LPWSTR) midl_user_allocate((wcslen(pwszBuddy) + 1) * sizeof(WCHAR));
if ((*pppwszCatalogNames)[(*pdwNumCatalogNames)] == NULL) { CATDBSVC_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } wcscpy((*pppwszCatalogNames)[(*pdwNumCatalogNames)], pwszBuddy); (*pdwNumCatalogNames)++; }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorMemory) }
//---------------------------------------------------------------------------------------
//
// _CatDBSeekInCatNameBuddyTable
//
//---------------------------------------------------------------------------------------
JET_ERR _CatDBSeekInCatNameBuddyTable( PJET_DB_STRUCT pJetDBStruct, LPWSTR pwszBuddyRow) { JET_ERR jerr;
if (_CatDBJET_errFailure(jerr = JetMakeKey( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, (BYTE const *) pwszBuddyRow, (wcslen(pwszBuddyRow) + 1) * sizeof(WCHAR), JET_bitNewKey))) { return jerr; }
jerr = JetSeek( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, JET_bitSeekEQ);
return jerr; }
//---------------------------------------------------------------------------------------
//
// _CatDBSeekInHashCatNameTable
//
//---------------------------------------------------------------------------------------
JET_ERR _CatDBSeekInHashCatNameTable( PJET_DB_STRUCT pJetDBStruct, PCRYPT_DATA_BLOB pHashBlob) { JET_ERR jerr;
if (_CatDBJET_errFailure(jerr = JetMakeKey( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, pHashBlob->pbData, pHashBlob->cbData, JET_bitNewKey))) { return jerr; }
jerr = JetSeek( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, JET_bitSeekEQ);
return jerr; }
//---------------------------------------------------------------------------------------
//
// _CatDBNotifyClients
//
//---------------------------------------------------------------------------------------
void _CatDBNotifyClients(void) { DWORD i = 0;
EnterCriticalSection(&g_CatDBRegisterNotifyCS);
while (i < g_NumNotificationStructs) { if (g_rgNotificationStructs[i].hDuplicatedNotificationHandle != INVALID_HANDLE_VALUE) { SetEvent(g_rgNotificationStructs[i].hDuplicatedNotificationHandle); } i++; }
LeaveCriticalSection(&g_CatDBRegisterNotifyCS); }
//---------------------------------------------------------------------------------------
//
// _CatDBCleanupClientNotifications
//
//---------------------------------------------------------------------------------------
void _CatDBCleanupClientNotifications(void) { DWORD i = 0; HANDLE *rgUnregisterHandles = NULL; HANDLE *rgProcessHandles = NULL; int nHandleIndex = -1;
EnterCriticalSection(&g_CatDBRegisterNotifyCS);
rgUnregisterHandles = (HANDLE *) _CatDBAlloc(sizeof(HANDLE) * g_NumNotificationStructs); rgProcessHandles = (HANDLE *) _CatDBAlloc(sizeof(HANDLE) * g_NumNotificationStructs); if ((rgUnregisterHandles == NULL) || (rgProcessHandles == NULL)) { goto Return; }
for (i=0; i<g_NumNotificationStructs; i++) { if (g_rgNotificationStructs[i].hDuplicatedNotificationHandle != INVALID_HANDLE_VALUE) { nHandleIndex++;
g_rgNotificationStructs[i].ProcessID = 0;
rgUnregisterHandles[nHandleIndex] = g_rgNotificationStructs[i].hRegisterWaitFor; g_rgNotificationStructs[i].hRegisterWaitFor = NULL;
rgProcessHandles[nHandleIndex] = g_rgNotificationStructs[i].hClientProcess; g_rgNotificationStructs[i].hClientProcess = NULL;
g_rgNotificationStructs[i].hNotificationHandle = INVALID_HANDLE_VALUE;
CloseHandle(g_rgNotificationStructs[i].hDuplicatedNotificationHandle); g_rgNotificationStructs[i].hDuplicatedNotificationHandle = INVALID_HANDLE_VALUE;
g_rgNotificationStructs[i].lNotificationID = 0; } }
Return:
LeaveCriticalSection(&g_CatDBRegisterNotifyCS);
while (nHandleIndex >= 0) { UnregisterWaitEx(rgUnregisterHandles[nHandleIndex], INVALID_HANDLE_VALUE); CloseHandle(rgProcessHandles[nHandleIndex]);
nHandleIndex--; }
if (rgUnregisterHandles != NULL) { _CatDBFree(rgUnregisterHandles); }
if (rgProcessHandles != NULL) { _CatDBFree(rgProcessHandles); } }
//---------------------------------------------------------------------------------------
//
// _CatDBCreateNewCatalogFileName
//
//---------------------------------------------------------------------------------------
#define SZ_UNIQUE_CAT_FILENAME_FORMAT L"%X.CAT"
#define MAX_UNIQUE_CAT_FILES 0xffffffff
LPWSTR _CatDBCreateNewCatalogFileName( LPCWSTR pwszCatalogFileDir, LPCWSTR pwszCatName, BOOL *pfFileAlreadyExists) { LPWSTR pwszFullyQualifiedCatName = NULL; WCHAR pwszTempBaseName[56]; BOOL fUniqueFileNameFound; DWORD dw; HANDLE hTestFile = INVALID_HANDLE_VALUE; DWORD dwLastErr = 0;
if (pwszCatName != NULL) { //
// The caller specified the cat name to use, so just concatenate the
// the path and the name
//
if (NULL == (pwszFullyQualifiedCatName = _CATDBConstructWSTRPath( pwszCatalogFileDir, pwszCatName))) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// See if this file already exists by trying to create the file
//
hTestFile = CreateFileW( pwszFullyQualifiedCatName, GENERIC_WRITE | GENERIC_READ, 0, // dwShareMode
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // hTemplateFile
dwLastErr = GetLastError();
if ((hTestFile == INVALID_HANDLE_VALUE) && ( (dwLastErr == ERROR_FILE_NOT_FOUND) || (dwLastErr == ERROR_PATH_NOT_FOUND) || (dwLastErr == ERROR_BAD_NETPATH))) { *pfFileAlreadyExists = FALSE; } else if (hTestFile == INVALID_HANDLE_VALUE) { *pfFileAlreadyExists = TRUE; } else { *pfFileAlreadyExists = TRUE; CloseHandle(hTestFile); } } else { *pfFileAlreadyExists = FALSE;
//
// Create a unique name for the directory in question
//
fUniqueFileNameFound = FALSE; dw = 1;
while ((!fUniqueFileNameFound) && (dw != 0)) // (dw == 0) after rollover.
{ wsprintfW(pwszTempBaseName, SZ_UNIQUE_CAT_FILENAME_FORMAT, dw); if (NULL == (pwszFullyQualifiedCatName = _CATDBConstructWSTRPath( pwszCatalogFileDir, pwszTempBaseName)))
if (pwszFullyQualifiedCatName == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// See if this is a unique file name by trying to create the file
//
hTestFile = CreateFileW( pwszFullyQualifiedCatName, GENERIC_WRITE | GENERIC_READ, 0, // dwShareMode
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // hTemplateFile
if (hTestFile == INVALID_HANDLE_VALUE) { fUniqueFileNameFound = TRUE; } else { CloseHandle(hTestFile);
//
// Setup for next iteration
//
_CatDBFree(pwszFullyQualifiedCatName); pwszFullyQualifiedCatName = NULL; dw++; } } }
CommonReturn:
return pwszFullyQualifiedCatName;
ErrorReturn:
if (pwszFullyQualifiedCatName != NULL) { _CatDBFree(pwszFullyQualifiedCatName); } pwszFullyQualifiedCatName = NULL;
goto CommonReturn; }
//---------------------------------------------------------------------------------------
//
// _CatDBFindAndDecodeHashInCatEntry
//
//---------------------------------------------------------------------------------------
BOOL _CatDBFindAndDecodeHashInCatEntry( PCTL_ENTRY pctlEntry, SPC_INDIRECT_DATA_CONTENT **ppIndirectData) { BOOL fRet = TRUE; DWORD i; DWORD cbIndirectData = 0;
*ppIndirectData = NULL;
//
// Search for the hash in the attributes
//
for (i=0; i<pctlEntry->cAttribute; i++) { if (strcmp(pctlEntry->rgAttribute[i].pszObjId, SPC_INDIRECT_DATA_OBJID) == 0) { break; } }
//
// Make sure the hash was found
//
if (i >= pctlEntry->cAttribute) { CATDBSVC_LOGERR_LASTERR() goto ErrorInvalidCatalogFormat; }
//
// decode the indirect data
//
if (!CryptDecodeObject( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, SPC_INDIRECT_DATA_CONTENT_STRUCT, pctlEntry->rgAttribute[i].rgValue[0].pbData, pctlEntry->rgAttribute[i].rgValue[0].cbData, 0, NULL, &cbIndirectData)) { CATDBSVC_LOGERR_LASTERR() goto ErrorCryptDecodeObject; }
if (NULL == (*ppIndirectData = (SPC_INDIRECT_DATA_CONTENT *) _CatDBAlloc(cbIndirectData))) { CATDBSVC_LOGERR_LASTERR() goto ErrorMemory; }
if (!CryptDecodeObject( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, SPC_INDIRECT_DATA_CONTENT_STRUCT, pctlEntry->rgAttribute[i].rgValue[0].pbData, pctlEntry->rgAttribute[i].rgValue[0].cbData, 0, *ppIndirectData, &cbIndirectData)) { CATDBSVC_LOGERR_LASTERR() goto ErrorCryptDecodeObject; }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorInvalidCatalogFormat) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorCryptDecodeObject) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorMemory) }
#define SZ_HASH_CATNAME_TABLE "HashCatNameTable"
#define SZ_HASH_CATNAME_TABLE_HASHCOL "HashCatNameTable_HashCol"
#define SZ_HASH_CATNAME_TABLE_CATNAMECOL "HashCatNameTable_CatNameCol"
#define SZ_HASH_CATNAME_TABLE_INDEX "HashCatNameTable_Index"
#define SZ_HASH_CATNAME_TABLE_INDEX_DEF "+HashCatNameTable_HashCol\0"
#define SZ_CATNAME_BUDDY_TABLE "CatNameBuddyTable"
#define SZ_CATNAME_BUDDY_TABLE_CATNAMECOL "CatNameBuddyTable_CatNameCol"
#define SZ_CATNAME_BUDDY_TABLE_BUDDYCOL "CatNameBuddyTable_BuddyCol"
#define SZ_CATNAME_BUDDY_TABLE_INDEX "CatNameBuddyTable_Index"
#define SZ_CATNAME_BUDDY_TABLE_INDEX_DEF "+CatNameBuddyTable_CatNameCol\0"
//---------------------------------------------------------------------------------------
//
// _CatDBInitJetDatabaseParams
//
//---------------------------------------------------------------------------------------
typedef struct _DBJETPARAM { DWORD paramid; DWORD lParam; char *pszParam; } DBJETPARAM;
DBJETPARAM g_rgJetParams[] = {
#define JP_LOGPATH 0
{ JET_paramLogFilePath, 0, NULL},
#define JP_SYSTEMPATH 1
{ JET_paramSystemPath, 0, NULL},
#define JP_TEMPPATH 2
{ JET_paramTempPath, 0, NULL},
{ JET_paramEventSource, 0, "Catalog Database"},
{ JET_paramMaxVerPages, 1024, NULL},
#if !defined(_M_IA64) && !defined(_M_AXP64)
//{ JET_paramEventLogCache, 32768, NULL},
#endif
{ JET_paramCircularLog, 1, NULL},
{ JET_paramNoInformationEvent, 1, NULL},
{ JET_paramAccessDeniedRetryPeriod, 1000, NULL} }; #define CDBPARAM (sizeof(g_rgJetParams)/sizeof(g_rgJetParams[0]))
BOOL _CatDBInitJetDatabaseParams( JET_INSTANCE *pJetInstance) { BOOL fRet = TRUE; JET_ERR jerr; LPSTR pszTempPath = NULL;
DBJETPARAM const *pjp;
//
// Create a temp path for cat db
//
if (NULL == (pszTempPath = _CatDBGetCatrootDirA())) { CATDBSVC_LOGERR_LASTERR() goto ErrorGetSystemDirectory; }
//
// Initialize the Jet Parameters
//
g_rgJetParams[JP_LOGPATH].pszParam = pszTempPath; g_rgJetParams[JP_SYSTEMPATH].pszParam = pszTempPath; g_rgJetParams[JP_TEMPPATH].pszParam = pszTempPath;
for (pjp = g_rgJetParams; pjp < &g_rgJetParams[CDBPARAM]; pjp++) { if (_CatDBJET_errFailure(jerr = JetSetSystemParameter( pJetInstance, 0, pjp->paramid, pjp->lParam, pjp->pszParam))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } }
CommonReturn:
if (pszTempPath != NULL) { free(pszTempPath); }
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorGetSystemDirectory) }
//---------------------------------------------------------------------------------------
//
// _CatDBGetColumnIDs
//
//---------------------------------------------------------------------------------------
BOOL _CatDBGetColumnIDs( PJET_DB_STRUCT pJetDBStruct) { BOOL fRet = TRUE; JET_ERR jerr; JET_COLUMNDEF JetColumnDef; BOOL fHashCatNameTableOpen = FALSE; BOOL fCatNameBuddyTableOpen = FALSE; DWORD dwErr = 0;
//
// Hash-CatName table and columns
//
if (_CatDBJET_errFailure(jerr = JetOpenTable( pJetDBStruct->JetSesID, pJetDBStruct->JetDBID, SZ_HASH_CATNAME_TABLE, NULL, 0, 0, &(pJetDBStruct->JetHashCatNameTableID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } fHashCatNameTableOpen = TRUE;
if (_CatDBJET_errFailure(jerr = JetGetColumnInfo( pJetDBStruct->JetSesID, pJetDBStruct->JetDBID, SZ_HASH_CATNAME_TABLE, SZ_HASH_CATNAME_TABLE_HASHCOL, &JetColumnDef, sizeof(JetColumnDef), JET_ColInfo))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } pJetDBStruct->JetHashCatNameTable_HashColumnID = JetColumnDef.columnid;
if (_CatDBJET_errFailure(jerr = JetGetColumnInfo( pJetDBStruct->JetSesID, pJetDBStruct->JetDBID, SZ_HASH_CATNAME_TABLE, SZ_HASH_CATNAME_TABLE_CATNAMECOL, &JetColumnDef, sizeof(JetColumnDef), JET_ColInfo))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } pJetDBStruct->JetHashCatNameTable_CatNameColumnID = JetColumnDef.columnid;
//
// CatNameBuddy table and columns
//
if (_CatDBJET_errFailure(jerr = JetOpenTable( pJetDBStruct->JetSesID, pJetDBStruct->JetDBID, SZ_CATNAME_BUDDY_TABLE, NULL, 0, 0, &(pJetDBStruct->JetCatNameBuddyTableID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } fCatNameBuddyTableOpen = TRUE;
if (_CatDBJET_errFailure(jerr = JetGetColumnInfo( pJetDBStruct->JetSesID, pJetDBStruct->JetDBID, SZ_CATNAME_BUDDY_TABLE, SZ_CATNAME_BUDDY_TABLE_CATNAMECOL, &JetColumnDef, sizeof(JetColumnDef), JET_ColInfo))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } pJetDBStruct->JetCatNameBuddyTable_CatNameColumnID = JetColumnDef.columnid;
if (_CatDBJET_errFailure(jerr = JetGetColumnInfo( pJetDBStruct->JetSesID, pJetDBStruct->JetDBID, SZ_CATNAME_BUDDY_TABLE, SZ_CATNAME_BUDDY_TABLE_BUDDYCOL, &JetColumnDef, sizeof(JetColumnDef), JET_ColInfo))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } pJetDBStruct->JetCatNameBuddyTable_BuddyColumnID = JetColumnDef.columnid;
CommonReturn:
return fRet;
ErrorReturn:
dwErr = GetLastError();
if (fHashCatNameTableOpen) { JetCloseTable(pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID); }
if (fCatNameBuddyTableOpen) { JetCloseTable(pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID); }
SetLastError(dwErr);
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBCreateDBFile
//
//---------------------------------------------------------------------------------------
BOOL _CatDBCreateDBFile( PJET_DB_STRUCT pJetDBStruct, LPSTR pszDBFileName) { BOOL fRet = TRUE; JET_ERR jerr; JET_COLUMNDEF JetColumnDef; BOOL fDBFileOpen = FALSE; BOOL fDBFileCreated = FALSE; BOOL fTransactionBegun = FALSE; DWORD dwErr = 0; JET_DBID LocalJetDBID = 0; JET_TABLEID LocalJetHashCatNameTableID = 0; JET_COLUMNID LocalJetHashCatNameTable_HashColumnID = 0; JET_COLUMNID LocalJetHashCatNameTable_CatNameColumnID = 0; JET_TABLEID LocalJetCatNameBuddyTableID = 0; JET_COLUMNID LocalJetCatNameBuddyTable_CatNameColumnID = 0; JET_COLUMNID LocalJetCatNameBuddyTable_BuddyColumnID = 0;
//
// Create the actual db file
//
if (_CatDBJET_errFailure(jerr = JetCreateDatabase( pJetDBStruct->JetSesID, pszDBFileName, NULL, &(LocalJetDBID), 0))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } fDBFileCreated = TRUE; fDBFileOpen = TRUE;
if (_CatDBJET_errFailure(jerr = JetCloseDatabase( pJetDBStruct->JetSesID, LocalJetDBID, 0))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } fDBFileOpen = FALSE;
if (_CatDBJET_errFailure(jerr = JetOpenDatabase( pJetDBStruct->JetSesID, pszDBFileName, NULL, &(LocalJetDBID), 0))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } fDBFileOpen = TRUE;
//
// Add the whole schema to the db file (tables, columns, indexes)
//
if (_CatDBJET_errFailure(jerr = JetBeginTransaction(pJetDBStruct->JetSesID))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } fTransactionBegun = TRUE;
//
// Create the hash-catname table, columns, and indexes
//
if (_CatDBJET_errFailure(jerr = JetCreateTable( pJetDBStruct->JetSesID, LocalJetDBID, SZ_HASH_CATNAME_TABLE, 4, 100, &(LocalJetHashCatNameTableID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetCloseTable( pJetDBStruct->JetSesID, LocalJetHashCatNameTableID))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetOpenTable( pJetDBStruct->JetSesID, LocalJetDBID, SZ_HASH_CATNAME_TABLE, NULL, 0, 0, &(LocalJetHashCatNameTableID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
// Hash column
memset(&JetColumnDef, 0, sizeof(JetColumnDef)); JetColumnDef.cbStruct = sizeof(JetColumnDef); JetColumnDef.langid = 0x409; JetColumnDef.wCountry = 1; JetColumnDef.coltyp = JET_coltypBinary; JetColumnDef.grbit = JET_bitColumnNotNULL;
if (_CatDBJET_errFailure(jerr = JetAddColumn( pJetDBStruct->JetSesID, LocalJetHashCatNameTableID, SZ_HASH_CATNAME_TABLE_HASHCOL, &JetColumnDef, NULL, 0, &(LocalJetHashCatNameTable_HashColumnID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
// CatName column
memset(&JetColumnDef, 0, sizeof(JetColumnDef)); JetColumnDef.cbStruct = sizeof(JetColumnDef); JetColumnDef.cp = 1200; // unicode (1200) instead of Ascii (1252)
JetColumnDef.langid = 0x409; JetColumnDef.wCountry = 1; JetColumnDef.coltyp = JET_coltypText; JetColumnDef.cbMax = 255; JetColumnDef.grbit = JET_bitColumnMultiValued | JET_bitColumnTagged;
if (_CatDBJET_errFailure(jerr = JetAddColumn( pJetDBStruct->JetSesID, LocalJetHashCatNameTableID, SZ_HASH_CATNAME_TABLE_CATNAMECOL, &JetColumnDef, NULL, 0, &(LocalJetHashCatNameTable_CatNameColumnID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
// Hash-CatName table index
if (_CatDBJET_errFailure(jerr = JetCreateIndex( pJetDBStruct->JetSesID, LocalJetHashCatNameTableID, SZ_HASH_CATNAME_TABLE_INDEX, JET_bitIndexPrimary, SZ_HASH_CATNAME_TABLE_INDEX_DEF, strlen(SZ_HASH_CATNAME_TABLE_INDEX_DEF) + 2, 80))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
//
// Create the CatName-Buddy table, columns, and indexes
//
if (_CatDBJET_errFailure(jerr = JetCreateTable( pJetDBStruct->JetSesID, LocalJetDBID, SZ_CATNAME_BUDDY_TABLE, 4, 100, &(LocalJetCatNameBuddyTableID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetCloseTable( pJetDBStruct->JetSesID, LocalJetCatNameBuddyTableID))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetOpenTable( pJetDBStruct->JetSesID, LocalJetDBID, SZ_CATNAME_BUDDY_TABLE, NULL, 0, 0, &(LocalJetCatNameBuddyTableID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
// CatName column
memset(&JetColumnDef, 0, sizeof(JetColumnDef)); JetColumnDef.cbStruct = sizeof(JetColumnDef); JetColumnDef.cp = 1200; // unicode (1200) instead of Ascii (1252)
JetColumnDef.langid = 0x409; JetColumnDef.wCountry = 1; JetColumnDef.coltyp = JET_coltypText; JetColumnDef.cbMax = 255; JetColumnDef.grbit = JET_bitColumnNotNULL;
if (_CatDBJET_errFailure(jerr = JetAddColumn( pJetDBStruct->JetSesID, LocalJetCatNameBuddyTableID, SZ_CATNAME_BUDDY_TABLE_CATNAMECOL, &JetColumnDef, NULL, 0, &(LocalJetCatNameBuddyTable_CatNameColumnID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
// Buddy column
memset(&JetColumnDef, 0, sizeof(JetColumnDef)); JetColumnDef.cbStruct = sizeof(JetColumnDef); JetColumnDef.cp = 1200; // unicode (1200) instead of Ascii (1252)
JetColumnDef.langid = 0x409; JetColumnDef.wCountry = 1; JetColumnDef.coltyp = JET_coltypText; JetColumnDef.cbMax = 255; JetColumnDef.grbit = JET_bitColumnMultiValued | JET_bitColumnTagged;
if (_CatDBJET_errFailure(jerr = JetAddColumn( pJetDBStruct->JetSesID, LocalJetCatNameBuddyTableID, SZ_CATNAME_BUDDY_TABLE_BUDDYCOL, &JetColumnDef, NULL, 0, &(LocalJetCatNameBuddyTable_BuddyColumnID)))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
// CatName-Buddy table index
if (_CatDBJET_errFailure(jerr = JetCreateIndex( pJetDBStruct->JetSesID, LocalJetCatNameBuddyTableID, SZ_CATNAME_BUDDY_TABLE_INDEX, JET_bitIndexPrimary, SZ_CATNAME_BUDDY_TABLE_INDEX_DEF, strlen(SZ_CATNAME_BUDDY_TABLE_INDEX_DEF) + 2, 80))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
//
// Now that all the schema has been successfully added, COMMIT
//
if (_CatDBJET_errFailure(jerr = JetCommitTransaction( pJetDBStruct->JetSesID, 0))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetCloseDatabase( pJetDBStruct->JetSesID, LocalJetDBID, 0))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
dwErr = GetLastError();
if (fTransactionBegun) { JetRollback(pJetDBStruct->JetSesID, 0); }
if (fDBFileOpen) { JetCloseDatabase( pJetDBStruct->JetSesID, LocalJetDBID, 0); }
if (fDBFileCreated) { DeleteFileA(pszDBFileName); }
SetLastError(dwErr);
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBAttachAndOpenDatabase
//
//---------------------------------------------------------------------------------------
BOOL _CatDBAttachAndOpenDatabase( JET_DB_STRUCT *pJetDBStruct, BOOL fReadOnly) { BOOL fRet = TRUE; JET_ERR jerr; BOOL fJetDBFileOpen = FALSE; DWORD dwErr = 0;
//
// Try to attach the existing database, if it doesn't already exist,
// then create it
//
jerr = JetAttachDatabase( pJetDBStruct->JetSesID, pJetDBStruct->pszDBFileName, 0); //fReadOnly ? JET_bitDbReadOnly : 0);
if (jerr == JET_errFileNotFound) { //
// The DB file doesn't exist yet, so create it
//
if (!_CatDBCreateDBFile( pJetDBStruct, pJetDBStruct->pszDBFileName)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; } } else if (_CatDBJET_errFailure(jerr)) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetOpenDatabase( pJetDBStruct->JetSesID, pJetDBStruct->pszDBFileName, NULL, &(pJetDBStruct->JetDBID), 0))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } fJetDBFileOpen = TRUE;
if (!_CatDBGetColumnIDs(pJetDBStruct)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Set the current indexes for both tables so all seeks work
//
if (_CatDBJET_errFailure(jerr = JetSetCurrentIndex( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID, NULL))) // NULL == primary index
{ CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetSetCurrentIndex( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID, NULL))) // NULL == primary index
{ CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } CommonReturn:
return fRet;
ErrorReturn:
dwErr = GetLastError();
if (fJetDBFileOpen) { JetCloseDatabase(pJetDBStruct->JetSesID, pJetDBStruct->JetDBID, 0); }
SetLastError(dwErr);
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBCloseDatabaseFile
//
//---------------------------------------------------------------------------------------
BOOL _CatDBCloseDatabaseFile( PJET_DB_STRUCT pJetDBStruct, BOOL fDetach) { BOOL fRet = TRUE; JET_ERR jerr;
if (_CatDBJET_errFailure(jerr = JetCloseTable( pJetDBStruct->JetSesID, pJetDBStruct->JetHashCatNameTableID))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetCloseTable( pJetDBStruct->JetSesID, pJetDBStruct->JetCatNameBuddyTableID))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (_CatDBJET_errFailure(jerr = JetCloseDatabase( pJetDBStruct->JetSesID, pJetDBStruct->JetDBID, 0))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
if (fDetach) { if (_CatDBJET_errFailure(jerr = JetDetachDatabase( pJetDBStruct->JetSesID, pJetDBStruct->pszDBFileName))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) } }
if (_CatDBJET_errFailure(jerr = JetEndSession( pJetDBStruct->JetSesID, 0))) { CATDBSVC_SETERR_LOG_RETURN(_CatDBMapJetError(jerr), ErrorJetDatabase) }
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE; goto CommonReturn;
TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorJetDatabase) }
//---------------------------------------------------------------------------------------
//
// _CatDBCatalogFileAlreadyInstalled
//
//---------------------------------------------------------------------------------------
BOOL _CatDBCatalogFileAlreadyInstalled( LPCWSTR pwszCatalogToBeAdded, LPCWSTR pwszExistingCatalog) { BOOL fRet = TRUE; HANDLE h1 = NULL; HANDLE h2 = NULL; BYTE rgbHash1[20]; BYTE rgbHash2[20]; DWORD cbHash1 = 20; DWORD cbHash2 = 20;
//
// Open both files
//
h1 = CreateFileW( pwszCatalogToBeAdded, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // hTemplateFile
if (h1 == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
h2 = CreateFileW( pwszExistingCatalog, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // hTemplateFile
if (h1 == NULL) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Get the hash for each file
//
if (!CryptCATAdminCalcHashFromFileHandle( h1, &cbHash1, rgbHash1, 0)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
if (!CryptCATAdminCalcHashFromFileHandle( h2, &cbHash2, rgbHash2, 0)) { CATDBSVC_LOGERR_LASTERR() goto ErrorReturn; }
//
// Compare the hashes to see if they are the same
//
if (memcmp(rgbHash1, rgbHash2, 20) == 0) { fRet = TRUE; }
Return:
if (h1 != NULL) { CloseHandle(h1); }
if (h2 != NULL) { CloseHandle(h2); }
return fRet;
ErrorReturn:
fRet = FALSE; goto Return; }
//---------------------------------------------------------------------------------------
//
// _CatDBFreeze
//
//---------------------------------------------------------------------------------------
BOOL _CatDBFreeze() { //
// Freeze all incomming requests
//
ResetEvent(g_hNotFrozen);
//
// Close all open instances of all databased (which also detaches automatically)
//
if (!_CatDBCloseCachedDatabases(TRUE)) { CATDBSVC_LOGERR_LASTERR() return FALSE; }
return TRUE; }
//---------------------------------------------------------------------------------------
//
// _CatDBThaw
//
//---------------------------------------------------------------------------------------
VOID _CatDBThaw() { //
// Unfreeze all incomming requests
//
SetEvent(g_hNotFrozen); }
//---------------------------------------------------------------------------------------
//
// _CatDBJET_errFailure
//
//---------------------------------------------------------------------------------------
BOOL _CatDBJET_errFailure( JET_ERR jerr) { if (jerr == JET_errSuccess) { return FALSE; } else if (jerr & 0x80000000) { //
// Jet errors are negative numbers, jet warnings are positive
//
return TRUE; } else { CATDBSVC_LOGWARN(_CatDBMapJetError(jerr)) return FALSE; } }
//---------------------------------------------------------------------------------------
//
// _CatDBMapJetError
//
//---------------------------------------------------------------------------------------
DWORD _CatDBMapJetError(JET_ERR jerr) { // FIX FIX
return jerr;//ERROR_DATABASE_FAILURE;
}
|