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