Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

6242 lines
132 KiB

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: db.cpp
//
// Contents: Cert Server Database interface implementation
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include "csprop.h"
#include "db.h"
#include "column.h"
#include "row.h"
#include "view.h"
#include "backup.h"
#include "restore.h"
#include "dbw.h"
#define __dwFILE__ __dwFILE_CERTDB_DB_CPP__
#define SEEKPOS_FIRST 0
#define SEEKPOS_LAST 1
#define SEEKPOS_INDEXFIRST 2
#define SEEKPOS_INDEXLAST 3
LONG g_cCertDB = 0;
LONG g_cCertDBTotal = 0;
LONG g_cXactCommit = 0;
LONG g_cXactAbort = 0;
LONG g_cXactTotal = 0;
char *g_pszDBFile = NULL;
typedef struct _DBJETPARM {
DWORD paramid;
DWORD lParam;
char *pszParam;
BOOL fString;
} DBJETPARM;
DBJETPARM g_aParm[] = {
#define JP_LOGPATH 0
{ JET_paramLogFilePath, 0, NULL, TRUE },
#define JP_SYSTEMPATH 1
{ JET_paramSystemPath, 0, NULL, TRUE },
#define JP_TEMPPATH 2
{ JET_paramTempPath, 0, NULL, TRUE },
#define JP_EVENTSOURCE 3
{ JET_paramEventSource, 0, NULL, TRUE },
#define JP_SESSIONMAX 4
{ JET_paramMaxSessions, 0, NULL, FALSE },
#define JP_CACHESIZEMIN 5
{ JET_paramCacheSizeMin, 64, NULL, FALSE },
#define JP_CACHESIZEMAX 6
{ JET_paramCacheSizeMax, 512, NULL, FALSE },
#define JP_VERPAGESMAX 7 // 16k units: 64k per session
{ JET_paramMaxVerPages, 4 * DBSESSIONCOUNTDEFAULT, NULL, FALSE },
{ JET_paramRecovery, 0, "on", TRUE },
{ JET_paramMaxVerPages, 64, NULL, FALSE },
{ JET_paramMaxTemporaryTables, 5, NULL, FALSE },
{ JET_paramLogBuffers, 41, NULL, FALSE },
{ JET_paramLogFileSize, 1024, NULL, FALSE },
{ JET_paramAssertAction, JET_AssertBreak, NULL, FALSE },
{ JET_paramBaseName, 0, szDBBASENAMEPARM, TRUE } // "edb"
};
#define CDBPARM (sizeof(g_aParm)/sizeof(g_aParm[0]))
VOID
DBFreeParms()
{
if (NULL != g_aParm[JP_LOGPATH].pszParam)
{
LocalFree(g_aParm[JP_LOGPATH].pszParam);
g_aParm[JP_LOGPATH].pszParam = NULL;
}
if (NULL != g_aParm[JP_SYSTEMPATH].pszParam)
{
LocalFree(g_aParm[JP_SYSTEMPATH].pszParam);
g_aParm[JP_SYSTEMPATH].pszParam = NULL;
}
if (NULL != g_aParm[JP_TEMPPATH].pszParam)
{
LocalFree(g_aParm[JP_TEMPPATH].pszParam);
g_aParm[JP_TEMPPATH].pszParam = NULL;
}
if (NULL != g_aParm[JP_EVENTSOURCE].pszParam)
{
LocalFree(g_aParm[JP_EVENTSOURCE].pszParam);
g_aParm[JP_EVENTSOURCE].pszParam = NULL;
}
}
HRESULT
DBInitParms(
IN DWORD cSession,
IN BOOL fCircularLogging,
OPTIONAL IN WCHAR const *pwszEventSource,
OPTIONAL IN WCHAR const *pwszLogDir,
OPTIONAL IN WCHAR const *pwszSystemDir,
OPTIONAL IN WCHAR const *pwszTempDir,
OUT JET_INSTANCE *pInstance)
{
HRESULT hr = E_OUTOFMEMORY;
DBJETPARM const *pjp;
WCHAR awc[MAX_PATH];
DWORD dwPerfTweak = 0;
DBFreeParms();
if (NULL != pwszLogDir)
{
wcscpy(awc, pwszLogDir);
wcscat(awc, L"\\");
if (!ConvertWszToSz(&g_aParm[JP_LOGPATH].pszParam, awc, -1))
{
_JumpError(hr, error, "ConvertWszToSz(LogDir)");
}
}
if (NULL != pwszSystemDir)
{
wcscpy(awc, pwszSystemDir);
wcscat(awc, L"\\");
if (!ConvertWszToSz(&g_aParm[JP_SYSTEMPATH].pszParam, awc, -1))
{
_JumpError(hr, error, "ConvertWszToSz(SystemDir)");
}
}
if (NULL != pwszTempDir)
{
wcscpy(awc, pwszTempDir);
wcscat(awc, L"\\");
if (!ConvertWszToSz(&g_aParm[JP_TEMPPATH].pszParam, awc, -1))
{
_JumpError(hr, error, "ConvertWszToSz(TempDir)");
}
}
if (NULL != pwszEventSource)
{
if (!ConvertWszToSz(
&g_aParm[JP_EVENTSOURCE].pszParam,
pwszEventSource,
-1))
{
_JumpError(hr, error, "ConvertWszToSz(EventSource)");
}
}
g_aParm[JP_SESSIONMAX].lParam = cSession + 1;
if (8 * cSession > g_aParm[JP_CACHESIZEMIN].lParam)
{
g_aParm[JP_CACHESIZEMIN].lParam = 8 * cSession;
}
if (8 * 8 * cSession > g_aParm[JP_CACHESIZEMAX].lParam)
{
g_aParm[JP_CACHESIZEMAX].lParam = 8 * 8 * cSession;
}
if (4 * cSession > g_aParm[JP_VERPAGESMAX].lParam)
{
g_aParm[JP_VERPAGESMAX].lParam = 4 * cSession;
}
for (pjp = g_aParm; pjp < &g_aParm[CDBPARM]; pjp++)
{
if (!pjp->fString || NULL != pjp->pszParam)
{
_dbgJetSetSystemParameter(
pInstance,
0,
pjp->paramid,
pjp->lParam,
pjp->pszParam);
}
}
if (fCircularLogging)
{
DBGPRINT((DBG_SS_CERTSRV, "Jet: circular logging enabled\n"));
_dbgJetSetSystemParameter(
pInstance,
0,
JET_paramCircularLog,
TRUE,
NULL);
}
if (S_OK == myGetCertRegDWValue(NULL, NULL, NULL, L"PerfTweak", &dwPerfTweak))
{
if (dwPerfTweak & 0x1)
{
_dbgJetSetSystemParameter(
pInstance,
0,
JET_paramLogBuffers,
480, // should be logfilesize (1024k) - 64k, specified in 512b units
NULL);
}
if (dwPerfTweak & 0x2)
{
_dbgJetSetSystemParameter(
pInstance,
0,
JET_paramCommitDefault,
JET_bitCommitLazyFlush,
NULL);
}
if (dwPerfTweak & 0x4)
{
// real fix is not to set this at all, but setting it to a large number should suffice
_dbgJetSetSystemParameter(
pInstance,
0,
JET_paramCacheSizeMax,
512*100, // 100x the size we usually run with
NULL);
}
if (dwPerfTweak & 0x8)
{
_dbgJetSetSystemParameter(
pInstance,
0,
JET_paramCheckpointDepthMax,
60 * 1024 * 1024, // 60MB -- triple the size we usually run with (20MB)
NULL);
}
if (dwPerfTweak & 0x10)
{
_dbgJetSetSystemParameter(
pInstance,
0,
JET_paramLogFileSize,
16384, // 16x the size we usually run with (1MB)
NULL);
}
if (dwPerfTweak & 0x20)
{
_dbgJetSetSystemParameter(
pInstance,
0,
JET_paramLogBuffers,
256, // usually run with 41
NULL);
}
}
hr = S_OK;
error:
return(hr);
}
#if DBG_CERTSRV
WCHAR const *
wszCSFFlags(
IN LONG Flags)
{
static WCHAR s_awc[256];
wsprintf(s_awc, L"{%x", Flags);
if (CSF_INUSE & Flags) dbgcat(s_awc, L"InUse");
if (CSF_READONLY & Flags) dbgcat(s_awc, L"ReadOnly");
if (CSF_CREATE & Flags) dbgcat(s_awc, L"Create");
if (CSF_VIEW & Flags) dbgcat(s_awc, L"View");
if (CSF_VIEWRESET & Flags) dbgcat(s_awc, L"ViewReset");
wcscat(s_awc, L"}");
CSASSERT(wcslen(s_awc) < ARRAYSIZE(s_awc));
return(s_awc);
}
WCHAR const *
wszCSTFlags(
IN LONG Flags)
{
static WCHAR s_awc[256];
wsprintf(s_awc, L"{%x", Flags);
if (CST_SEEKINDEXRANGE & Flags) dbgcat(s_awc, L"IndexRange");
if (CST_SEEKNOTMOVE & Flags) dbgcat(s_awc, L"SeekNotMove");
if (CST_SEEKUSECURRENT & Flags) dbgcat(s_awc, L"UseCurrent");
if (0 == (CST_SEEKUSECURRENT & Flags)) dbgcat(s_awc, L"SkipCurrent");
if (CST_SEEKASCEND & Flags) dbgcat(s_awc, L"Ascend");
if (0 == (CST_SEEKASCEND & Flags)) dbgcat(s_awc, L"Descend");
wcscat(s_awc, L"}");
CSASSERT(wcslen(s_awc) < ARRAYSIZE(s_awc));
return(s_awc);
}
WCHAR const *
wszTable(
IN DWORD dwTable)
{
WCHAR const *pwsz;
switch (dwTable)
{
case TABLE_REQUESTS:
pwsz = wszREQUESTTABLE;
break;
case TABLE_CERTIFICATES:
pwsz = wszCERTIFICATETABLE;
break;
case TABLE_ATTRIBUTES:
pwsz = wszREQUESTATTRIBUTETABLE;
break;
case TABLE_EXTENSIONS:
pwsz = wszCERTIFICATEEXTENSIONTABLE;
break;
case TABLE_CRLS:
pwsz = wszCRLTABLE;
break;
default:
pwsz = L"???";
break;
}
return(pwsz);
}
WCHAR const *
wszSeekOperator(
IN LONG SeekOperator)
{
WCHAR const *pwsz;
static WCHAR s_wszBuf[20];
switch (CVR_SEEK_MASK & SeekOperator)
{
case CVR_SEEK_NONE: pwsz = L"None"; break;
case CVR_SEEK_EQ: pwsz = L"=="; break;
case CVR_SEEK_LT: pwsz = L"<"; break;
case CVR_SEEK_LE: pwsz = L"<="; break;
case CVR_SEEK_GE: pwsz = L">="; break;
case CVR_SEEK_GT: pwsz = L">"; break;
default:
wsprintf(s_wszBuf, L"???=%x", SeekOperator);
pwsz = s_wszBuf;
break;
}
if (s_wszBuf != pwsz && (CVR_SEEK_NODELTA & SeekOperator))
{
wcscpy(s_wszBuf, pwsz);
wcscat(s_wszBuf, L",NoDelta");
pwsz = s_wszBuf;
}
return(pwsz);
}
WCHAR const *
wszSortOperator(
IN LONG SortOrder)
{
WCHAR const *pwsz;
static WCHAR s_wszBuf[20];
switch (SortOrder)
{
case CVR_SORT_NONE: pwsz = L"None"; break;
case CVR_SORT_ASCEND: pwsz = L"Ascend"; break;
case CVR_SORT_DESCEND: pwsz = L"Descend"; break;
default:
wsprintf(s_wszBuf, L"???=%x", SortOrder);
pwsz = s_wszBuf;
break;
}
return(pwsz);
}
VOID
dbDumpFileTime(
IN DWORD dwSubSystemId,
IN CHAR const *pszPrefix,
IN FILETIME const *pft)
{
HRESULT hr;
WCHAR *pwsz;
hr = myGMTFileTimeToWszLocalTime(pft, TRUE, &pwsz);
if (S_OK == hr)
{
DBGPRINT((dwSubSystemId, "%hs%ws\n", pszPrefix, pwsz));
LocalFree(pwsz);
}
}
VOID
dbDumpValue(
IN DWORD dwSubSystemId,
OPTIONAL IN DBTABLE const *pdt,
IN BYTE const *pbValue,
IN DWORD cbValue)
{
if (NULL != pdt && NULL != pbValue && ISTEXTCOLTYP(pdt->dbcoltyp))
{
cbValue += sizeof(WCHAR);
}
if (JET_coltypDateTime == pdt->dbcoltyp && sizeof(FILETIME) == cbValue)
{
dbDumpFileTime(dwSubSystemId, "", (FILETIME const *) pbValue);
}
DBGDUMPHEX((dwSubSystemId, DH_NOADDRESS, pbValue, cbValue));
}
VOID
CCertDB::DumpRestriction(
IN DWORD dwSubSystemId,
IN LONG i,
IN CERTVIEWRESTRICTION const *pcvr)
{
HRESULT hr;
WCHAR wszColumn[20];
DBTABLE const *pdt;
WCHAR const *pwszTable = L"???";
WCHAR const *pwszCol;
hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
if (S_OK != hr)
{
_PrintError(hr, "_MapPropIdIndex");
wsprintf(wszColumn, L"???=%x", pcvr->ColumnIndex);
pdt = NULL;
pwszCol = wszColumn;
}
else
{
pwszCol = pdt->pwszPropName;
pwszTable = wszTable(pdt->dwTable);
}
DBGPRINT((
dwSubSystemId,
"Restriction[%d]: Col=%ws.%ws\n"
" Seek='%ws' Sort=%ws cb=%x, pb=%x\n",
i,
pwszTable,
pwszCol,
wszSeekOperator(pcvr->SeekOperator),
wszSortOperator(pcvr->SortOrder),
pcvr->cbValue,
pcvr->pbValue));
dbDumpValue(dwSubSystemId, pdt, pcvr->pbValue, pcvr->cbValue);
}
VOID
dbDumpColumn(
IN DWORD dwSubSystemId,
IN DBTABLE const *pdt,
IN BYTE const *pbValue,
IN DWORD cbValue)
{
DBGPRINT((dwSubSystemId, "Column: cb=%x pb=%x\n", cbValue, pbValue));
dbDumpValue(dwSubSystemId, pdt, pbValue, cbValue);
}
DBAUXDATA const *
dbGetAuxTable(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid)
{
DBAUXDATA const *pdbaux;
CSASSERT(IsValidJetTableId(tableid));
if (tableid == pcs->aTable[CSTI_CERTIFICATE].TableId)
{
pdbaux = &g_dbauxCertificates;
}
else if (tableid == pcs->aTable[CSTI_ATTRIBUTE].TableId)
{
pdbaux = &g_dbauxAttributes;
}
else if (tableid == pcs->aTable[CSTI_EXTENSION].TableId)
{
pdbaux = &g_dbauxExtensions;
}
else
{
CSASSERT(tableid == pcs->aTable[CSTI_PRIMARY].TableId);
pdbaux = &g_dbauxRequests;
switch (CSF_TABLEMASK & pcs->SesFlags)
{
case TABLE_CERTIFICATES:
pdbaux = &g_dbauxCertificates;
break;
case TABLE_ATTRIBUTES:
pdbaux = &g_dbauxAttributes;
break;
case TABLE_EXTENSIONS:
pdbaux = &g_dbauxExtensions;
break;
case TABLE_CRLS:
pdbaux = &g_dbauxCRLs;
break;
}
}
return(pdbaux);
}
HRESULT
CCertDB::_DumpRowId(
IN CHAR const *psz,
IN CERTSESSION *pcs,
IN JET_TABLEID tableid)
{
HRESULT hr;
#define DBG_SS_DUMPREQUESTID DBG_SS_CERTDBI
CSASSERT(IsValidJetTableId(tableid));
if (DbgIsSSActive(DBG_SS_DUMPREQUESTID))
{
DWORD cb;
DWORD dwTmp;
DBAUXDATA const *pdbaux = dbGetAuxTable(pcs, tableid);
WCHAR awchr[cwcHRESULTSTRING];
cb = sizeof(dwTmp);
hr = _RetrieveColumn(
pcs,
tableid,
pdbaux->pdtRowId->dbcolumnid,
pdbaux->pdtRowId->dbcoltyp,
&cb,
(BYTE *) &dwTmp);
if (S_OK != hr)
{
DBGPRINT((
DBG_SS_DUMPREQUESTID,
"%hs: %hs.RowId: pcs=%d: %ws\n",
psz,
pdbaux->pszTable,
pcs->RowId,
myHResultToString(awchr, hr)));
_JumpError2(hr, error, "_RetrieveColumn", hr);
}
DBGPRINT((
DBG_SS_DUMPREQUESTID,
"%hs: %hs.RowId: pcs=%d dbcol=%d\n",
psz,
pdbaux->pszTable,
pcs->RowId,
dwTmp));
}
hr = S_OK;
error:
return(hr);
}
HRESULT
CCertDB::_DumpColumn(
IN CHAR const *psz,
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN DBTABLE const *pdt)
{
HRESULT hr;
CSASSERT(IsValidJetTableId(tableid));
CSASSERT(0 != pdt->dbcolumnid);
if (DbgIsSSActive(DBG_SS_CERTDBI))
{
DWORD cb;
BYTE ab[64 * 1024];
DBAUXDATA const *pdbaux = dbGetAuxTable(pcs, tableid);
BOOL fIsText;
cb = sizeof(ab);
hr = _RetrieveColumn(
pcs,
tableid,
pdt->dbcolumnid,
pdt->dbcoltyp,
&cb,
ab);
_JumpIfError(hr, error, "_RetrieveColumn");
fIsText = ISTEXTCOLTYP(pdt->dbcoltyp);
DBGPRINT((
DBG_SS_CERTDBI,
"%hs: _DumpColumn(%hs, %hs): Value:%hs%ws%hs\n",
psz,
pdbaux->pszTable,
pdt->pszFieldName,
fIsText? " '" : "",
fIsText? (WCHAR *) ab : L"",
fIsText? "'" : ""));
dbDumpValue(DBG_SS_CERTDBI, pdt, ab, cb);
}
hr = S_OK;
error:
return(hr);
}
#endif // DBG_CERTSRV
CCertDB::CCertDB()
{
HRESULT hr;
InterlockedIncrement(&g_cCertDB);
InterlockedIncrement(&g_cCertDBTotal);
m_Instance = 0;
m_fDBOpen = FALSE;
m_fDBRestart = FALSE;
m_fPendingShutDown = FALSE;
m_fFoundOldColumns = FALSE;
m_fAddedNewColumns = FALSE;
m_aSession = NULL;
m_cSession = 0;
m_cbPage = 0;
m_cCritSec = 0;
__try
{
InitializeCriticalSection(&m_critsecSession);
m_cCritSec++;
InitializeCriticalSection(&m_critsecAutoIncTables);
m_cCritSec++;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
}
CCertDB::~CCertDB()
{
ShutDown(0);
if (0 < m_cCritSec)
{
DeleteCriticalSection(&m_critsecSession);
if (1 < m_cCritSec)
{
DeleteCriticalSection(&m_critsecAutoIncTables);
}
}
InterlockedDecrement(&g_cCertDB);
}
STDMETHODIMP
CCertDB::Open(
/* [in] */ DWORD Flags,
/* [in] */ DWORD cSession,
/* [in] */ WCHAR const *pwszEventSource,
/* [in] */ WCHAR const *pwszDBFile,
/* [in] */ WCHAR const *pwszLogDir,
/* [in] */ WCHAR const *pwszSystemDir,
/* [in] */ WCHAR const *pwszTempDir)
{
HRESULT hr;
DWORD i;
DBCREATETABLE const *pct;
JET_GRBIT grbit;
DWORD CreateFlags;
CERTSESSION *pcs = NULL;
if (NULL == pwszDBFile ||
NULL == pwszLogDir ||
NULL == pwszSystemDir ||
NULL == pwszTempDir)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
hr = InitGlobalWriterState();
// _JumpIfError(hr, error, "InitGlobalWriterState");
m_fDBOpen = FALSE;
m_fDBRestart = FALSE;
m_fDBReadOnly = (CDBOPEN_READONLY & Flags)? TRUE : FALSE;
CSASSERT(NULL == m_aSession); // code assumes we do not have session
m_cSession = 0;
m_aSession = (CERTSESSION *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
cSession * sizeof(m_aSession[0]));
hr = E_OUTOFMEMORY;
if (NULL == m_aSession)
{
_JumpError(hr, error, "LocalAlloc(m_aSession)");
}
for (i = 0; i < cSession; i++)
{
m_aSession[i].SesId = -1;
m_aSession[i].DBId = -1;
}
if (!ConvertWszToSz(&g_pszDBFile, pwszDBFile, -1))
{
_JumpError(hr, error, "ConvertWszToSz(DBFile)");
}
hr = DBInitParms(
cSession,
(CDBOPEN_CIRCULARLOGGING & Flags)? TRUE : FALSE,
pwszEventSource,
pwszLogDir,
pwszSystemDir,
pwszTempDir,
&m_Instance);
_JumpIfError(hr, error, "DBInitParms");
hr = _dbgJetInit(&m_Instance);
if ((HRESULT) JET_errLogFileSizeMismatchDatabasesConsistent == hr ||
(HRESULT) JET_errLogFileSizeMismatch == hr)
{
_PrintError(hr, "JetInit(old log file size)");
_dbgJetSetSystemParameter(
&m_Instance,
0,
JET_paramLogFileSize,
1000,
NULL);
hr = _dbgJetInit(&m_Instance);
}
_JumpIfError(
hr,
error,
JET_errFileAccessDenied == hr?
"JetInit(Server already running?)" :
"JetInit(JetSetSystemParameter problem?)");
for (i = 0; i < cSession; i++)
{
hr = _dbgJetBeginSession(m_Instance, &m_aSession[i].SesId, NULL, NULL);
_JumpIfError(hr, error, "_dbgJetBeginSession");
m_cSession++;
if (0 == i)
{
CreateFlags = 0;
grbit = m_fDBReadOnly?
JET_bitDbReadOnly : JET_bitDbDeleteCorruptIndexes;
hr = _dbgJetAttachDatabase(
m_aSession[i].SesId,
g_pszDBFile,
grbit);
if ((HRESULT) JET_errFileNotFound == hr &&
(CDBOPEN_CREATEIFNEEDED & Flags))
{
DBGPRINT((DBG_SS_CERTDB, "Creating Database\n"));
CreateFlags |= CF_DATABASE;
}
else
if ((HRESULT) JET_wrnCorruptIndexDeleted == hr)
{
// Rebuild deleted indexes over Unicode columns...
DBGPRINT((DBG_SS_CERTDB, "Creating Database Indexes\n"));
CreateFlags |= CF_MISSINGINDEXES;
}
else
if ((HRESULT) JET_wrnDatabaseAttached != hr)
{
_JumpIfError(hr, error, "JetAttachDatabase");
}
if (m_fDBReadOnly)
{
if (CreateFlags)
{
hr = E_ACCESSDENIED;
_JumpError(hr, error, "ReadOnly");
}
}
else
{
CreateFlags |= CF_MISSINGTABLES | CF_MISSINGCOLUMNS;
hr = _Create(CreateFlags, g_pszDBFile);
_JumpIfError(hr, error, "_Create");
}
}
hr = _dbgJetOpenDatabase(
m_aSession[i].SesId,
g_pszDBFile,
NULL,
&m_aSession[i].DBId,
0);
_JumpIfError(hr, error, "JetOpenDatabase");
}
hr = _AllocateSession(&pcs);
_JumpIfError(hr, error, "_AllocateSession");
for (pct = g_actDataBase; NULL != pct->pszTableName; pct++)
{
hr = _BuildColumnIds(pcs, pct->pszTableName, pct->pdt);
_JumpIfError(hr, error, "_BuildColumnIds");
}
if (!m_fDBReadOnly)
{
for (pct = g_actDataBase; NULL != pct->pszTableName; pct++)
{
hr = _ConvertOldColumnData(
pcs,
pct->pszTableName,
pct->pdbaux,
pct->pdt);
_JumpIfError(hr, error, "_ConvertOldColumnData");
}
}
m_fDBOpen = TRUE;
error:
if (NULL != pcs)
{
ReleaseSession(pcs);
}
hr = myJetHResult(hr);
if (S_OK == hr && m_fDBRestart)
{
hr = S_FALSE; // Restart required for DB changes to take effect.
_PrintError(hr, "m_fDBRestart");
}
return(hr);
}
STDMETHODIMP
CCertDB::ShutDown(
/* [in] */ DWORD dwFlags)
{
HRESULT hr;
DWORD i;
if (CDBSHUTDOWN_PENDING == dwFlags)
{
m_fPendingShutDown = TRUE;
goto error;
}
if (NULL != m_aSession)
{
DBGPRINT((DBG_SS_CERTDB, "Database shutdown...\n"));
for (i = 0; i < m_cSession; i++)
{
hr = _dbgJetEndSession(
m_aSession[i].SesId,
JET_bitForceSessionClosed);
_PrintIfError(hr, "JetEndSession");
}
hr = _dbgJetTerm2(m_Instance, JET_bitTermComplete);
DBGPRINT((DBG_SS_CERTDB, "Database shutdown complete\n"));
LocalFree(m_aSession);
m_aSession = NULL;
}
if (NULL != g_pszDBFile)
{
LocalFree(g_pszDBFile);
g_pszDBFile = NULL;
}
DBFreeParms();
UnInitGlobalWriterState();
error:
return(S_OK);
}
HRESULT
CCertDB::BeginTransaction(
IN CERTSESSION *pcs,
IN BOOL fPrepareUpdate)
{
HRESULT hr;
BOOL fTransacted = FALSE;
DWORD i;
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
if (0 != pcs->cTransact)
{
hr = E_UNEXPECTED;
_JumpError(hr, error, "Nested transaction");
}
CSASSERTTHREAD(pcs);
hr = _dbgJetBeginTransaction(pcs->SesId);
_JumpIfError(hr, error, "JetBeginTransaction");
fTransacted = TRUE;
if (fPrepareUpdate)
{
CSASSERTTHREAD(pcs);
for (i = 0; i < CSTI_MAX; i++)
{
if (IsValidJetTableId(pcs->aTable[i].TableId))
{
hr = _dbgJetPrepareUpdate(
pcs->SesId,
pcs->aTable[i].TableId,
JET_prepReplace);
_JumpIfError(hr, error, "JetPrepareUpdate");
}
}
}
pcs->cTransact++;
InterlockedIncrement(&g_cXactTotal);
hr = S_OK;
error:
if (S_OK != hr && fTransacted)
{
HRESULT hr2;
CSASSERTTHREAD(pcs);
hr2 = _Rollback(pcs);
_PrintIfError(hr2, "_Rollback");
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::CommitTransaction(
IN CERTSESSION *pcs,
IN BOOL fCommit)
{
HRESULT hr;
DWORD i;
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
CSASSERT(0 != pcs->cTransact);
if (fCommit)
{
if (0 == (CSF_DELETE & pcs->SesFlags))
{
for (i = 0; i < CSTI_MAXDIRECT; i++)
{
if (IsValidJetTableId(pcs->aTable[i].TableId))
{
hr = _UpdateTable(pcs, pcs->aTable[i].TableId);
_JumpIfError(hr, error, "_UpdateTable");
}
}
}
CSASSERTTHREAD(pcs);
hr = _dbgJetCommitTransaction(pcs->SesId, 0);
_JumpIfError(hr, error, "JetCommitTransaction");
}
else
{
hr = _Rollback(pcs);
_JumpIfError(hr, error, "_Rollback");
}
pcs->cTransact--;
if (fCommit)
{
InterlockedIncrement(&g_cXactCommit);
}
else
{
InterlockedIncrement(&g_cXactAbort);
}
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_AllocateSession(
OUT CERTSESSION **ppcs)
{
HRESULT hr;
DWORD i;
BOOL fEnterCritSec = FALSE;
CSASSERT(NULL != ppcs);
*ppcs = NULL;
if (0 == m_cCritSec)
{
hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
_JumpError(hr, error, "InitializeCriticalSection failure");
}
EnterCriticalSection(&m_critsecSession);
fEnterCritSec = TRUE;
for (i = 0; 0 != m_aSession[i].SesFlags; i++)
{
if (i + 1 == m_cSession)
{
hr = CERTSRV_E_NO_DB_SESSIONS;
_JumpIfError(hr, error, "no more sessions");
}
}
*ppcs = &m_aSession[i];
CSASSERT(0 == (*ppcs)->RowId);
(*ppcs)->SesFlags = CSF_INUSE;
(*ppcs)->dwThreadId = GetCurrentThreadId();
ZeroMemory((*ppcs)->aTable, sizeof((*ppcs)->aTable));
hr = S_OK;
error:
if (fEnterCritSec)
{
LeaveCriticalSection(&m_critsecSession);
}
return(hr);
}
HRESULT
CCertDB::_OpenTableRow(
IN CERTSESSION *pcs,
IN DBAUXDATA const *pdbaux,
OPTIONAL IN CERTVIEWRESTRICTION const *pcvr,
OUT CERTSESSIONTABLE *pTable,
OUT DWORD *pdwRowIdMismatch)
{
HRESULT hr;
DWORD dwRowId;
DWORD cb;
CSASSERT(NULL == pTable->TableId);
CSASSERT(0 == pTable->TableFlags);
*pdwRowIdMismatch = 0;
if (CSF_CREATE & pcs->SesFlags)
{
CSASSERT(NULL == pcvr);
CSASSERTTHREAD(pcs);
hr = _dbgJetOpenTable(
pcs->SesId,
pcs->DBId,
pdbaux->pszTable,
NULL,
0,
0,
&pTable->TableId);
_JumpIfError(hr, error, "JetOpenTable");
}
else
{
if (NULL == pcvr)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
hr = _OpenTable(pcs, pdbaux, pcvr, pTable);
if (S_FALSE == hr)
{
hr = CERTSRV_E_PROPERTY_EMPTY;
}
_JumpIfError2(hr, error, "_OpenTable", CERTSRV_E_PROPERTY_EMPTY);
}
if (!((CSF_READONLY | CSF_DELETE) & pcs->SesFlags))
{
CSASSERTTHREAD(pcs);
hr = _dbgJetPrepareUpdate(
pcs->SesId,
pTable->TableId,
(CSF_CREATE & pcs->SesFlags)?
JET_prepInsert : JET_prepReplace);
_JumpIfError(hr, error, "JetPrepareUpdate");
}
// Requests table RequestId column is JET_bitColumnAutoincrement.
// Certificates table RequestId column is manually initialized here.
//
// When creating a Certificates table row, the RequestId column must be
// set from pcs->RowId, which must already have been set by first creating
// the Requests table row.
//
// When opening an existing row in either table, just fetch the column.
CSASSERTTHREAD(pcs);
hr = _dbgJetRetrieveColumn(
pcs->SesId,
pTable->TableId,
pdbaux->pdtRowId->dbcolumnid,
&dwRowId,
sizeof(dwRowId),
&cb,
JET_bitRetrieveCopy,
NULL);
if ((HRESULT) JET_wrnColumnNull == hr)
{
hr = CERTSRV_E_PROPERTY_EMPTY;
}
_PrintIfError2(hr, "JetRetrieveColumn", CERTSRV_E_PROPERTY_EMPTY);
if (S_OK != hr || 0 == dwRowId)
{
CSASSERT(CSF_CREATE & pcs->SesFlags);
if (0 == (CSF_CREATE & pcs->SesFlags))
{
if (S_OK == hr)
{
hr = CERTSRV_E_PROPERTY_EMPTY;
}
_JumpError(hr, error, "JetRetrieveColumn");
}
dwRowId = pcs->RowId;
hr = _dbgJetSetColumn(
pcs->SesId,
pTable->TableId,
pdbaux->pdtRowId->dbcolumnid,
&dwRowId,
sizeof(dwRowId),
0,
NULL);
_JumpIfError(hr, error, "JetSetColumn");
}
else if (0 == pcs->RowId)
{
pcs->RowId = dwRowId;
}
DBGPRINT((
DBG_SS_CERTDBI,
"_OpenTableRow:%hs %hs --> RowId=%d(dwRowId(RetrieveColumn)=%d)\n",
(CSF_CREATE & pcs->SesFlags)? " (Create)" : "",
pdbaux->pszTable,
pcs->RowId,
dwRowId));
CSASSERT(0 != pcs->RowId);
if (pcs->RowId > dwRowId)
{
*pdwRowIdMismatch = dwRowId;
hr = CERTSRV_E_PROPERTY_EMPTY;
_JumpError(hr, error, "Missing autoincrement RowId");
}
CSASSERT(pcs->RowId == dwRowId);
error:
if (S_OK != hr)
{
if (IsValidJetTableId(pTable->TableId))
{
HRESULT hr2;
CSASSERTTHREAD(pcs);
hr2 = _dbgJetCloseTable(pcs->SesId, pTable->TableId);
_PrintIfError(hr2, "JetCloseTable");
}
ZeroMemory(pTable, sizeof(*pTable));
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::OpenTables(
IN CERTSESSION *pcs,
OPTIONAL IN CERTVIEWRESTRICTION const *pcvr)
{
HRESULT hr;
BOOL fCertTableFirst = FALSE;
BOOL fCertTableLast = FALSE;
CERTVIEWRESTRICTION cvrRowId;
CERTVIEWRESTRICTION const *pcvrPrimary;
CERTVIEWRESTRICTION const *pcvrCertificates;
BOOL fEnterCritSec = FALSE;
DBAUXDATA const *pdbauxPrimary;
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
pcvrPrimary = pcvr;
pcvrCertificates = NULL;
pdbauxPrimary = &g_dbauxRequests;
if (TABLE_REQCERTS == (CSF_TABLEMASK & pcs->SesFlags))
{
fCertTableLast = TRUE;
if (NULL != pcvr)
{
cvrRowId.SeekOperator = CVR_SEEK_EQ;
cvrRowId.SortOrder = CVR_SORT_ASCEND;
cvrRowId.pbValue = (BYTE *) &pcs->RowId;
cvrRowId.cbValue = sizeof(pcs->RowId);
switch (DTI_TABLEMASK & pcvr->ColumnIndex)
{
case DTI_REQUESTTABLE:
pcvrCertificates = &cvrRowId;
cvrRowId.ColumnIndex = DTI_CERTIFICATETABLE | DTC_REQUESTID;
break;
case DTI_CERTIFICATETABLE:
fCertTableLast = FALSE;
fCertTableFirst = TRUE;
pcvrCertificates = pcvr;
pcvrPrimary = &cvrRowId;
cvrRowId.ColumnIndex = DTI_REQUESTTABLE | DTR_REQUESTID;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "ColumnIndex Table");
}
}
}
else
{
switch (CSF_TABLEMASK & pcs->SesFlags)
{
case TABLE_ATTRIBUTES:
pdbauxPrimary = &g_dbauxAttributes;
break;
case TABLE_EXTENSIONS:
pdbauxPrimary = &g_dbauxExtensions;
break;
case TABLE_CRLS:
pdbauxPrimary = &g_dbauxCRLs;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "bad table");
}
}
if (1 >= m_cCritSec)
{
hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
_JumpError(hr, error, "InitializeCriticalSection failure");
}
EnterCriticalSection(&m_critsecAutoIncTables);
fEnterCritSec = TRUE;
__try
{
DWORD dwRowIdMismatch;
if (fCertTableFirst)
{
hr = _OpenTableRow(
pcs,
&g_dbauxCertificates,
pcvrCertificates,
&pcs->aTable[CSTI_CERTIFICATE],
&dwRowIdMismatch);
_LeaveIfError2(hr, "_OpenTableRow", CERTSRV_E_PROPERTY_EMPTY);
CSASSERT(0 != pcs->RowId);
CSASSERT(IsValidJetTableId(pcs->aTable[CSTI_CERTIFICATE].TableId));
DBGPRINT((
DBG_SS_CERTDBI,
"OpenTables: %hs: %ws\n",
g_dbauxCertificates.pszTable,
wszCSTFlags(pcs->aTable[CSTI_CERTIFICATE].TableFlags)));
}
hr = _OpenTableRow(
pcs,
pdbauxPrimary,
pcvrPrimary,
&pcs->aTable[CSTI_PRIMARY],
&dwRowIdMismatch);
_LeaveIfError2(hr, "_OpenTableRow", CERTSRV_E_PROPERTY_EMPTY);
CSASSERT(0 != pcs->RowId);
CSASSERT(IsValidJetTableId(pcs->aTable[CSTI_PRIMARY].TableId));
DBGPRINT((
DBG_SS_CERTDBI,
"OpenTables: %hs: %ws\n",
g_dbauxRequests.pszTable,
wszCSTFlags(pcs->aTable[CSTI_PRIMARY].TableFlags)));
if (fCertTableLast)
{
while (TRUE)
{
hr = _OpenTableRow(
pcs,
&g_dbauxCertificates,
pcvrCertificates,
&pcs->aTable[CSTI_CERTIFICATE],
&dwRowIdMismatch);
_PrintIfError(hr, "_OpenTableRow");
if (S_OK == hr || 0 == dwRowIdMismatch)
{
break;
}
}
_PrintIfError(hr, "_OpenTableRow");
//_LeaveIfError(hr, "_OpenTableRow");
if (S_OK == hr)
{
CSASSERT(IsValidJetTableId(pcs->aTable[CSTI_CERTIFICATE].TableId));
DBGPRINT((
DBG_SS_CERTDBI,
"OpenTables: %hs: %ws\n",
g_dbauxCertificates.pszTable,
wszCSTFlags(pcs->aTable[CSTI_CERTIFICATE].TableFlags)));
}
hr = S_OK;
}
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
if (S_OK != hr)
{
__try
{
HRESULT hr2;
DWORD i;
for (i = 0; i < CSTI_MAX; i++)
{
if (NULL != pcs)
{
CSASSERTTHREAD(pcs);
if (IsValidJetTableId(pcs->aTable[i].TableId))
{
hr2 = _dbgJetCloseTable(
pcs->SesId,
pcs->aTable[i].TableId);
_PrintIfError(hr2, "JetCloseTable");
}
}
ZeroMemory(&pcs->aTable[i], sizeof(pcs->aTable[i]));
}
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
}
if (fEnterCritSec)
{
LeaveCriticalSection(&m_critsecAutoIncTables);
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::CloseTables(
IN CERTSESSION *pcs)
{
HRESULT hr = S_OK;
HRESULT hr2;
DWORD i;
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
for (i = 0; i < CSTI_MAX; i++)
{
if (IsValidJetTableId(pcs->aTable[i].TableId))
{
hr2 = CloseTable(pcs, pcs->aTable[i].TableId);
_PrintIfError(hr2, "CloseTable");
if (S_OK == hr)
{
hr = hr2;
}
}
}
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::Delete(
IN CERTSESSION *pcs)
{
HRESULT hr = S_OK;
HRESULT hr2;
DWORD i;
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
for (i = 0; i < CSTI_MAXDIRECT; i++)
{
if (IsValidJetTableId(pcs->aTable[i].TableId))
{
hr2 = _dbgJetDelete(pcs->SesId, pcs->aTable[i].TableId);
_PrintIfError(hr2, "JetDelete");
if (S_OK == hr)
{
hr = hr2;
}
}
}
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_UpdateTable(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid)
{
HRESULT hr;
CSASSERT(IsValidJetTableId(tableid));
CSASSERTTHREAD(pcs);
hr = _dbgJetUpdate(pcs->SesId, tableid, NULL, 0, NULL);
_JumpIfError(hr, error, "JetUpdate");
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::CloseTable(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid)
{
HRESULT hr;
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
CSASSERT(IsValidJetTableId(tableid));
CSASSERTTHREAD(pcs);
hr = _dbgJetCloseTable(pcs->SesId, tableid);
_JumpIfError(hr, error, "JetCloseTable");
error:
return(myJetHResult(hr));
}
STDMETHODIMP
CCertDB::OpenRow(
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD RowId,
/* [in] */ WCHAR const *pwszSerialNumberOrCertHash, // OPTIONAL
/* [out] */ ICertDBRow **pprow)
{
HRESULT hr;
ICertDBRow *prow = NULL;
DWORD SesFlags = 0;
BOOL fCreate;
DWORD i;
CERTSESSION *pcs = NULL;
CERTVIEWRESTRICTION cvr;
CERTVIEWRESTRICTION *pcvr;
if (NULL == pprow)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
*pprow = NULL;
switch (PROPTABLE_MASK & dwFlags)
{
case PROPTABLE_REQCERT:
SesFlags |= TABLE_REQCERTS;
cvr.ColumnIndex = DTI_REQUESTTABLE | DTC_REQUESTID;
break;
case PROPTABLE_ATTRIBUTE:
SesFlags |= TABLE_ATTRIBUTES;
cvr.ColumnIndex = DTI_ATTRIBUTETABLE | DTA_REQUESTID;
break;
case PROPTABLE_EXTENSION:
SesFlags |= TABLE_EXTENSIONS;
cvr.ColumnIndex = DTI_EXTENSIONTABLE | DTE_REQUESTID;
break;
case PROPTABLE_CRL:
SesFlags |= TABLE_CRLS;
cvr.ColumnIndex = DTI_CRLTABLE | DTL_ROWID;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "bad table");
}
if ((PROPOPEN_CERTHASH & dwFlags) && NULL == pwszSerialNumberOrCertHash)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "bad PROPOPEN_CERTHASH");
}
if (PROPTABLE_REQCERT != (PROPTABLE_MASK & dwFlags) &&
NULL != pwszSerialNumberOrCertHash)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "bad pwszSerialNumberOrCertHash");
}
if ((PROPOPEN_READONLY | PROPOPEN_DELETE) ==
((PROPOPEN_READONLY | PROPOPEN_DELETE) & dwFlags))
{
hr = E_INVALIDARG;
_JumpError(hr, error, "delete + read-only");
}
if (0 == RowId && NULL == pwszSerialNumberOrCertHash)
{
if ((PROPOPEN_READONLY | PROPOPEN_DELETE) & dwFlags)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "OpenRow: create vs. delete or read-only");
}
SesFlags |= CSF_CREATE;
pcvr = NULL;
}
else
{
cvr.SeekOperator = CVR_SEEK_EQ;
cvr.SortOrder = CVR_SORT_ASCEND;
if (NULL != pwszSerialNumberOrCertHash)
{
cvr.ColumnIndex = (PROPOPEN_CERTHASH & dwFlags)?
(DTI_CERTIFICATETABLE | DTC_CERTIFICATEHASH) :
(DTI_CERTIFICATETABLE | DTC_CERTIFICATESERIALNUMBER);
cvr.cbValue = wcslen(pwszSerialNumberOrCertHash) * sizeof(WCHAR);
cvr.pbValue = (BYTE *) pwszSerialNumberOrCertHash;
}
else
{
cvr.cbValue = sizeof(RowId);
cvr.pbValue = (BYTE *) &RowId;
}
pcvr = &cvr;
}
if (PROPOPEN_READONLY & dwFlags)
{
SesFlags |= CSF_READONLY;
}
else
{
if (PROPOPEN_DELETE & dwFlags)
{
SesFlags |= CSF_DELETE;
}
if (m_fDBReadOnly)
{
hr = E_ACCESSDENIED;
_JumpError(hr, error, "OpenRow: read-only DB");
}
}
prow = new CCertDBRow;
if (NULL == prow)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "new CCertDBRow");
}
hr = _AllocateSession(&pcs);
_JumpIfError(hr, error, "_AllocateSession");
pcs->RowId = RowId;
pcs->SesFlags |= SesFlags;
pcs->prow = prow;
hr = ((CCertDBRow *) prow)->Open(pcs, this, pcvr);
_JumpIfError2(hr, error, "Open", CERTSRV_E_PROPERTY_EMPTY);
*pprow = prow;
prow = NULL;
pcs = NULL;
error:
if (NULL != prow)
{
prow->Release();
}
if (NULL != pcs)
{
ReleaseSession(pcs);
}
return(hr);
}
STDMETHODIMP
CCertDB::OpenView(
/* [in] */ DWORD ccvr,
/* [in] */ CERTVIEWRESTRICTION const *acvr,
/* [in] */ DWORD ccolOut,
/* [in] */ DWORD const *acolOut,
/* [in] */ DWORD const dwFlags,
/* [out] */ IEnumCERTDBRESULTROW **ppenum)
{
HRESULT hr;
IEnumCERTDBRESULTROW *penum = NULL;
BOOL fCreate;
CERTSESSION *pcs;
if ((NULL == acvr && 0 != ccvr) || NULL == acolOut || NULL == ppenum)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
*ppenum = NULL;
penum = new CEnumCERTDBRESULTROW(0 != (CDBOPENVIEW_WORKERTHREAD & dwFlags));
if (NULL == penum)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "new CEnumCERTDBRESULTROW");
}
hr = _AllocateSession(&pcs);
_JumpIfError(hr, error, "_AllocateSession");
pcs->SesFlags |= CSF_READONLY | CSF_VIEW;
pcs->pview = penum;
hr = ((CEnumCERTDBRESULTROW *) penum)->Open(
pcs,
this,
ccvr,
acvr,
ccolOut,
acolOut);
_JumpIfError(hr, error, "Open");
*ppenum = penum;
penum = NULL;
error:
if (NULL != penum)
{
penum->Release();
}
return(hr);
}
HRESULT
CCertDB::OpenBackup(
/* [in] */ LONG grbitJet,
/* [out] */ ICertDBBackup **ppBackup)
{
HRESULT hr;
ICertDBBackup *pBackup = NULL;
CERTSESSION *pcs = NULL;
if (NULL == ppBackup)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
*ppBackup = NULL;
pBackup = new CCertDBBackup;
if (NULL == pBackup)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "new CCertDBBackup");
}
hr = _AllocateSession(&pcs);
_JumpIfError(hr, error, "_AllocateSession");
hr = ((CCertDBBackup *) pBackup)->Open(grbitJet, pcs, this);
_JumpIfError(hr, error, "Open");
*ppBackup = pBackup;
pBackup = NULL;
pcs = NULL;
hr = S_OK;
error:
if (NULL != pBackup)
{
pBackup->Release();
}
if (NULL != pcs)
{
ReleaseSession(pcs);
}
return(hr);
}
HRESULT
CCertDB::ReleaseSession(
IN CERTSESSION *pcs)
{
HRESULT hr = S_OK;
HRESULT hr2;
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
CSASSERT(CSF_INUSE & pcs->SesFlags);
while (0 != pcs->cTransact)
{
CSASSERTTHREAD(pcs);
hr2 = _dbgJetRollback(pcs->SesId, 0);
if (S_OK == hr)
{
hr = hr2;
}
_JumpIfError(hr2, loop, "JetRollback");
DBGPRINT((
(CSF_READONLY & pcs->SesFlags)? DBG_SS_CERTDBI : DBG_SS_CERTDB,
"ReleaseSession: Rollback transaction: %x\n",
pcs->cTransact));
loop:
CSASSERT(0 == pcs->cTransact);
pcs->cTransact--;
InterlockedIncrement(&g_cXactAbort);
}
//EnterCriticalSection(&m_critsecSession);
pcs->RowId = 0;
pcs->prow = NULL;
pcs->SesFlags = 0; // turn off CSF_INUSE -- must be LAST!
//LeaveCriticalSection(&m_critsecSession);
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_Rollback(
IN CERTSESSION *pcs)
{
HRESULT hr = S_OK;
DWORD i;
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
CSASSERT(CSF_INUSE & pcs->SesFlags);
for (i = 0; i < CSTI_MAX; i++)
{
pcs->aTable[i].TableId = 0;
}
CSASSERTTHREAD(pcs);
hr = _dbgJetRollback(pcs->SesId, 0);
_JumpIfError(hr, error, "JetRollback");
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::BackupBegin(
IN LONG grbitJet)
{
HRESULT hr;
hr = _dbgJetBeginExternalBackup(grbitJet);
_JumpIfError(hr, error, "JetBeginExternalBackup");
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_BackupGetFileList(
IN BOOL fDBFiles,
IN OUT DWORD *pcwcList,
OUT WCHAR *pwszzList) // OPTIONAL
{
HRESULT hr;
CHAR buf[12];
CHAR *pszz = buf;
DWORD cbbuf = ARRAYSIZE(buf);
DWORD cbActual;
WCHAR *pwszz = NULL;
DWORD cwc;
WCHAR *pwsz;
DWORD cwcActual;
while (TRUE)
{
if (fDBFiles)
{
hr = _dbgJetGetAttachInfo(pszz, cbbuf, &cbActual);
_JumpIfError(hr, error, "JetGetAttachInfo");
}
else
{
hr = _dbgJetGetLogInfo(pszz, cbbuf, &cbActual);
_JumpIfError(hr, error, "JetGetLogInfo");
}
if (cbbuf >= cbActual)
{
break;
}
CSASSERT(buf == pszz);
pszz = (CHAR *) LocalAlloc(LMEM_FIXED, cbActual);
if (NULL == pszz)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
cbbuf = cbActual;
}
if (!ConvertSzToWsz(&pwszz, pszz, cbActual))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ConvertSzToWsz");
}
pwsz = pwszz;
do
{
cwc = wcslen(pwsz);
pwsz += cwc + 1;
} while (0 != cwc);
cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszz); // includes double trailing L'\0's
if (NULL != pwszzList)
{
CopyMemory(pwszzList, pwszz, min(cwc, *pcwcList) * sizeof(WCHAR));
if (cwc > *pcwcList)
{
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
}
}
*pcwcList = cwc;
_JumpIfError(hr, error, "Buffer Overflow");
error:
if (NULL != pszz && buf != pszz)
{
LocalFree(pszz);
}
if (NULL != pwszz)
{
LocalFree(pwszz);
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::BackupGetDBFileList(
IN OUT DWORD *pcwcList,
OUT WCHAR *pwszzList) // OPTIONAL
{
HRESULT hr;
hr = _BackupGetFileList(TRUE, pcwcList, pwszzList);
_JumpIfError(hr, error, "_BackupGetFileList");
error:
return(hr);
}
HRESULT
CCertDB::BackupGetLogFileList(
IN OUT DWORD *pcwcList,
OUT WCHAR *pwszzList) // OPTIONAL
{
HRESULT hr;
hr = _BackupGetFileList(FALSE, pcwcList, pwszzList);
_JumpIfError(hr, error, "_BackupGetFileList");
error:
return(hr);
}
HRESULT
CCertDB::BackupOpenFile(
IN WCHAR const *pwszFile,
OUT JET_HANDLE *phFileDB,
OPTIONAL OUT ULARGE_INTEGER *pliSize)
{
HRESULT hr;
CHAR *pszFile = NULL;
if (!ConvertWszToSz(&pszFile, pwszFile, -1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ConvertWszToSz(pwszFile)");
}
hr = _dbgJetOpenFile(
pszFile,
phFileDB,
&pliSize->LowPart,
&pliSize->HighPart);
_JumpIfErrorStr(hr, error, "JetOpenFile", pwszFile);
error:
if (NULL != pszFile)
{
LocalFree(pszFile);
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::BackupReadFile(
IN JET_HANDLE hFileDB,
OUT BYTE *pb,
IN DWORD cb,
OUT DWORD *pcb)
{
HRESULT hr;
BYTE *pbAlloc = NULL;
BYTE *pbRead;
if (0 == m_cbPage)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
m_cbPage = si.dwPageSize;
}
if ((m_cbPage - 1) & cb)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "bad read size");
}
pbRead = pb;
// If the caller's buffer is not page aligned, allocate an aligned buffer
// and copy the data.
if ((m_cbPage - 1) & (DWORD_PTR) pb)
{
pbAlloc = (BYTE *) VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_READWRITE);
if (NULL == pbAlloc)
{
hr = myHLastError();
_JumpIfError(hr, error, "VirtualAlloc");
}
pbRead = pbAlloc;
}
hr = _dbgJetReadFile(hFileDB, pbRead, cb, pcb);
_JumpIfError(hr, error, "JetReadFile");
if (NULL != pbAlloc)
{
CopyMemory(pb, pbAlloc, *pcb);
}
error:
if (NULL != pbAlloc)
{
VirtualFree(pbAlloc, 0, MEM_RELEASE);
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::BackupCloseFile(
IN JET_HANDLE hFileDB)
{
HRESULT hr;
hr = _dbgJetCloseFile(hFileDB);
_JumpIfError(hr, error, "JetCloseFile");
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::BackupTruncateLog()
{
HRESULT hr;
hr = _dbgJetTruncateLog();
_JumpIfError(hr, error, "JetTruncateLog");
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::BackupEnd()
{
HRESULT hr;
hr = _dbgJetEndExternalBackup();
_JumpIfError(hr, error, "JetEndExternalBackup");
error:
return(myJetHResult(hr));
}
DBTABLE const *
CCertDB::_MapTable(
IN WCHAR const *pwszPropName,
IN DBTABLE const *pdt)
{
while (NULL != pdt->pwszPropName)
{
if (0 == (DBTF_MISSING & pdt->dwFlags) &&
(0 == lstrcmpi(pwszPropName, pdt->pwszPropName) ||
(NULL != pdt->pwszPropNameObjId &&
0 == lstrcmpi(pwszPropName, pdt->pwszPropNameObjId))))
{
return(pdt);
}
pdt++;
}
return(NULL);
}
HRESULT
CCertDB::_MapPropIdIndex(
IN DWORD ColumnIndex,
OUT DBTABLE const **ppdt,
OPTIONAL OUT DWORD *pType)
{
HRESULT hr;
DBTABLE const *pdt = NULL;
DWORD iCol = DTI_COLUMNMASK & ColumnIndex;
switch (DTI_TABLEMASK & ColumnIndex)
{
case DTI_REQUESTTABLE:
if (DTR_MAX > iCol)
{
pdt = g_adtRequests;
}
break;
case DTI_CERTIFICATETABLE:
if (DTC_MAX > iCol)
{
pdt = g_adtCertificates;
}
break;
case DTI_ATTRIBUTETABLE:
if (DTA_MAX > iCol)
{
pdt = g_adtRequestAttributes;
}
break;
case DTI_EXTENSIONTABLE:
if (DTE_MAX > iCol)
{
pdt = g_adtCertExtensions;
}
break;
case DTI_CRLTABLE:
if (DTL_MAX > iCol)
{
pdt = g_adtCRLs;
}
break;
}
if (NULL == pdt)
{
hr = E_INVALIDARG;
DBGPRINT((
DBG_SS_CERTDB,
"_MapPropIdIndex(%x) -> %x\n",
ColumnIndex,
hr));
_JumpError(hr, error, "column index");
}
pdt += iCol;
if (NULL != pType)
{
switch (pdt->dbcoltyp)
{
case JET_coltypDateTime:
*pType = PROPTYPE_DATE;
break;
case JET_coltypLong:
*pType = PROPTYPE_LONG;
break;
case JET_coltypText:
case JET_coltypLongText:
*pType = PROPTYPE_STRING;
break;
case JET_coltypLongBinary:
default:
*pType = PROPTYPE_BINARY;
break;
}
if (NULL != pdt->pszIndexName &&
0 == (DBTF_INDEXREQUESTID & pdt->dwFlags))
{
*pType |= PROPFLAGS_INDEXED;
}
}
DBGPRINT((
DBG_SS_CERTDBI,
"_MapPropIdIndex(%x) -> %ws.%ws\n",
ColumnIndex,
wszTable(pdt->dwTable),
pdt->pwszPropName));
hr = S_OK;
error:
*ppdt = pdt;
return(hr);
}
HRESULT
CCertDB::MapPropId(
IN WCHAR const *pwszPropName,
IN DWORD dwFlags,
OUT DBTABLE *pdtOut)
{
DBTABLE const *pdt = NULL;
WCHAR wszPrefix[2 * (sizeof(wszPROPSUBJECTDOT) / sizeof(WCHAR))];
DWORD dwTable;
HRESULT hr = S_OK;
DBTABLE const *pdbTable;
WCHAR const *pwszStart;
BOOL fSubject = FALSE;
BOOL fRequest = FALSE;
if (NULL == pwszPropName || NULL == pdtOut)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
dwTable = PROPTABLE_MASK & dwFlags;
CSASSERT(
PROPTABLE_REQUEST == dwTable ||
PROPTABLE_CERTIFICATE == dwTable ||
PROPTABLE_CRL == dwTable);
// Check to see if the request is for L"Subject.".
pwszStart = pwszPropName;
if (PROPTABLE_CRL != dwTable)
{
while (!fSubject)
{
WCHAR const *pwsz;
pwsz = wcschr(pwszStart, L'.');
if (NULL == pwsz ||
pwsz - pwszStart + 2 > sizeof(wszPrefix)/sizeof(WCHAR))
{
pwsz = pwszStart;
break;
}
pwsz++; // skip past L'.'
CopyMemory(
wszPrefix,
pwszStart,
(SAFE_SUBTRACT_POINTERS(pwsz, pwszStart) * sizeof(WCHAR)));
wszPrefix[pwsz - pwszStart] = L'\0';
if (!fSubject)
{
pwszStart = pwsz;
if (0 == lstrcmpi(wszPrefix, wszPROPSUBJECTDOT))
{
fSubject = TRUE;
continue;
}
else
if (!fRequest &&
PROPTABLE_REQUEST == dwTable &&
0 == lstrcmpi(wszPrefix, wszPROPREQUESTDOT))
{
fRequest = TRUE;
continue;
}
}
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "Invalid prefix", pwszPropName);
}
}
pdbTable = NULL;
// Search the requested table for a matching property name or property
// objectid string.
switch (dwTable)
{
case PROPTABLE_REQUEST:
pdbTable = g_adtRequests;
break;
case PROPTABLE_CERTIFICATE:
pdbTable = g_adtCertificates;
break;
case PROPTABLE_CRL:
pdbTable = g_adtCRLs;
break;
}
CSASSERT(NULL != pdbTable);
pdt = _MapTable(pwszStart, pdbTable);
if (NULL == pdt || (fSubject && 0 == (DBTF_SUBJECT & pdt->dwFlags)))
{
hr = CERTSRV_E_PROPERTY_EMPTY;
_JumpErrorStr(
hr,
error,
PROPTABLE_REQUEST == dwTable?
"unknown Request property" :
PROPTABLE_CERTIFICATE == dwTable?
"unknown Certificate property" :
"unknown CRL property",
pwszPropName);
}
*pdtOut = *pdt; // structure copy
hr = S_OK;
error:
return(hr);
}
HRESULT
CCertDB::TestShutDownState()
{
HRESULT hr;
if (m_fPendingShutDown)
{
hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS);
_JumpError(hr, error, "m_fPendingShutDown");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
CCertDB::SetProperty(
IN CERTSESSION *pcs,
IN DBTABLE const *pdt,
IN DWORD cbProp,
IN BYTE const *pbProp) // OPTIONAL
{
HRESULT hr;
JET_TABLEID tableid;
if (NULL == pcs ||
NULL == pdt ||
(NULL == pbProp && !ISTEXTCOLTYP(pdt->dbcoltyp)))
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
DBGPRINT((
DBG_SS_CERTDBI,
"SetProperty for %hs into table %d\n",
pdt->pszFieldName,
pdt->dwTable));
if (ISTEXTCOLTYP(pdt->dbcoltyp))
{
DBGPRINT((DBG_SS_CERTDBI, "SetProperty setting string %ws\n", pbProp));
}
if (JET_coltypDateTime == pdt->dbcoltyp)
{
DBGPRINT((
DBG_SS_CERTDBI,
"SetProperty setting date: %x:%x\n",
((DWORD *) pbProp)[0],
((DWORD *) pbProp)[1]));
}
switch (pdt->dwTable)
{
case TABLE_CRLS:
case TABLE_REQUESTS:
tableid = pcs->aTable[CSTI_PRIMARY].TableId;
break;
case TABLE_CERTIFICATES:
tableid = pcs->aTable[CSTI_CERTIFICATE].TableId;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "unknown table type");
}
CSASSERT(IsValidJetTableId(tableid));
hr = _SetColumn(
pcs->SesId,
tableid,
pdt->dbcolumnid,
cbProp,
pbProp);
_JumpIfErrorStr(hr, error, "_SetColumn", pdt->pwszPropName);
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::GetProperty(
IN CERTSESSION *pcs,
IN DBTABLE const *pdt,
IN OUT DWORD *pcbProp,
OUT BYTE *pbProp) // OPTIONAL
{
HRESULT hr;
JET_COLUMNDEF columndef;
JET_TABLEID tableid;
if (NULL == pcs || NULL == pdt || NULL == pcbProp)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
DBGPRINT((
DBG_SS_CERTDBI,
"GetProperty for %hs from table %d\n",
pdt->pszFieldName,
pdt->dwTable));
if ((CSF_TABLEMASK & pcs->SesFlags) != pdt->dwTable)
{
if (TABLE_REQCERTS != (CSF_TABLEMASK & pcs->SesFlags) ||
(TABLE_REQUESTS != pdt->dwTable &&
TABLE_CERTIFICATES != pdt->dwTable))
{
hr = E_INVALIDARG;
_JumpError(hr, error, "mismatched table");
}
}
if (TABLE_CERTIFICATES == pdt->dwTable)
{
tableid = pcs->aTable[CSTI_CERTIFICATE].TableId;
}
else
{
tableid = pcs->aTable[CSTI_PRIMARY].TableId;
}
CSASSERT(IsValidJetTableId(tableid));
hr = _RetrieveColumn(
pcs,
tableid,
pdt->dbcolumnid,
pdt->dbcoltyp,
pcbProp,
pbProp);
_JumpIfErrorStr3(
hr,
error,
"_RetrieveColumn",
pdt->pwszPropName,
CERTSRV_E_PROPERTY_EMPTY,
HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW));
if (ISTEXTCOLTYP(pdt->dbcoltyp))
{
DBGPRINT((DBG_SS_CERTDBI, "GetProperty returning string %ws\n", pbProp));
}
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::CopyRequestNames(
IN CERTSESSION *pcs)
{
HRESULT hr = S_OK;
DBTABLE dt;
DWORD cbProp;
BYTE *pbProp = NULL;
DWORD i;
BYTE rgbFastBuf[64];
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
for (i = 0; NULL != g_dntr[i].pszFieldName; i++)
{
hr = MapPropId(g_dntr[i].pwszPropName, PROPTABLE_REQUEST, &dt);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = S_OK;
continue; // Optional column doesn't exist
}
_JumpIfError(hr, error, "MapPropId");
// re-point at fastbuf
pbProp = rgbFastBuf;
cbProp = sizeof(rgbFastBuf);
hr = GetProperty(pcs, &dt, &cbProp, pbProp);
if (S_OK != hr)
{
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
{
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = S_OK;
continue;
}
_JumpIfError(hr, error, "GetProperty");
}
CSASSERT (ARRAYSIZE(rgbFastBuf) < cbProp);
DBGPRINT((
DBG_SS_CERTDB,
"FastBuf miss: CopyRequestNames(cbProp=%u)\n",
cbProp));
pbProp = (BYTE *) LocalAlloc(LMEM_FIXED, cbProp);
if (NULL == pbProp)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
hr = GetProperty(pcs, &dt, &cbProp, pbProp);
_JumpIfError(hr, error, "GetProperty");
} // have data in hand
hr = MapPropId(g_dntr[i].pwszPropName, PROPTABLE_CERTIFICATE, &dt);
_JumpIfError(hr, error, "MapPropId");
hr = SetProperty(pcs, &dt, cbProp, pbProp);
_JumpIfError(hr, error, "SetProperty");
if (NULL != pbProp && rgbFastBuf != pbProp)
{
LocalFree(pbProp);
}
pbProp = NULL;
}
error:
if (NULL != pbProp && rgbFastBuf != pbProp)
{
LocalFree(pbProp);
}
return(hr);
}
STDMETHODIMP
CCertDB::EnumCertDBColumn(
/* [in] */ DWORD dwTable,
/* [out] */ IEnumCERTDBCOLUMN **ppenum)
{
HRESULT hr;
IEnumCERTDBCOLUMN *penum = NULL;
if (NULL == ppenum)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
*ppenum = NULL;
penum = new CEnumCERTDBCOLUMN;
if (NULL == penum)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "new CEnumCERTDBCOLUMN");
}
hr = ((CEnumCERTDBCOLUMN *) penum)->Open(dwTable, this);
_JumpIfError(hr, error, "Open");
*ppenum = penum;
hr = S_OK;
error:
if (S_OK != hr && NULL != penum)
{
penum->Release();
}
return(hr);
}
STDMETHODIMP
CCertDB::GetDefaultColumnSet(
/* [in] */ DWORD iColumnSetDefault,
/* [in] */ DWORD cColumnIds,
/* [out] */ DWORD *pcColumnIds,
/* [out, ref] */ DWORD *pColumnIds) // OPTIONAL
{
HRESULT hr;
DWORD *pcol;
DWORD ccol;
if (NULL == pcColumnIds)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
switch (iColumnSetDefault)
{
case CV_COLUMN_LOG_FAILED_DEFAULT:
case CV_COLUMN_QUEUE_DEFAULT:
pcol = g_aColumnViewQueue;
ccol = g_cColumnViewQueue;
break;
case CV_COLUMN_LOG_REVOKED_DEFAULT:
pcol = g_aColumnViewRevoked;
ccol = g_cColumnViewRevoked;
break;
case CV_COLUMN_LOG_DEFAULT:
pcol = g_aColumnViewLog;
ccol = g_cColumnViewLog;
break;
case CV_COLUMN_EXTENSION_DEFAULT:
pcol = g_aColumnViewExtension;
ccol = g_cColumnViewExtension;
break;
case CV_COLUMN_ATTRIBUTE_DEFAULT:
pcol = g_aColumnViewAttribute;
ccol = g_cColumnViewAttribute;
break;
case CV_COLUMN_CRL_DEFAULT:
pcol = g_aColumnViewCRL;
ccol = g_cColumnViewCRL;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "iColumnSetDefault");
}
*pcColumnIds = ccol;
hr = S_OK;
if (NULL != pColumnIds)
{
if (ccol > cColumnIds)
{
ccol = cColumnIds;
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
}
CopyMemory(pColumnIds, pcol, ccol * sizeof(*pColumnIds));
}
error:
return(hr);
}
HRESULT
CCertDB::GetColumnType(
IN LONG ColumnIndex,
OUT DWORD *pType)
{
HRESULT hr;
DBTABLE const *pdt;
if (NULL == pType)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
hr = _MapPropIdIndex(ColumnIndex, &pdt, pType);
_JumpIfError(hr, error, "_MapPropIdIndex");
error:
return(hr);
}
HRESULT
CCertDB::EnumCertDBColumnNext(
IN DWORD dwTable, // CVRC_TABLE_*
IN ULONG ielt,
IN ULONG celt,
OUT CERTDBCOLUMN *rgelt,
OUT ULONG *pielt,
OUT ULONG *pceltFetched)
{
HRESULT hr;
ULONG ieltEnd;
ULONG ieltMax;
ULONG TableIndex;
CERTDBCOLUMN *pelt;
WCHAR const *pwszPrefix;
WCHAR const *pwszDisplayName;
if (NULL == rgelt || NULL == pielt || NULL == pceltFetched)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
switch (dwTable)
{
case CVRC_TABLE_REQCERT:
TableIndex = DTI_REQUESTTABLE;
ieltMax = DTR_MAX + DTC_MAX;
break;
case CVRC_TABLE_EXTENSIONS:
TableIndex = DTI_EXTENSIONTABLE;
ieltMax = DTE_MAX;
break;
case CVRC_TABLE_ATTRIBUTES:
TableIndex = DTI_ATTRIBUTETABLE;
ieltMax = DTA_MAX;
break;
case CVRC_TABLE_CRL:
TableIndex = DTI_CRLTABLE;
ieltMax = DTL_MAX;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "Bad table");
}
if (ieltMax + ielt < celt)
{
celt = ieltMax - ielt;
}
ieltEnd = ielt + celt;
ZeroMemory(rgelt, celt * sizeof(rgelt[0]));
hr = S_OK;
for (pelt = rgelt; pelt < &rgelt[celt]; ielt++, pelt++)
{
DBTABLE const *pdt;
ULONG ieltBase = 0;
if (ieltMax <= ielt)
{
if (pelt == rgelt)
{
hr = S_FALSE;
}
break;
}
pwszPrefix = NULL;
if (CVRC_TABLE_REQCERT == dwTable)
{
if (DTR_MAX > ielt)
{
pwszPrefix = wszPROPREQUESTDOT;
TableIndex = DTI_REQUESTTABLE;
}
else
{
ieltBase = DTR_MAX;
TableIndex = DTI_CERTIFICATETABLE;
}
}
pelt->Index = TableIndex | (ielt - ieltBase);
hr = _MapPropIdIndex(pelt->Index, &pdt, &pelt->Type);
_JumpIfError(hr, error, "_MapPropIdIndex");
pelt->cbMax = pdt->dwcbMax;
hr = _DupString(pwszPrefix, pdt->pwszPropName, &pelt->pwszName);
_JumpIfError(hr, error, "_DupString");
hr = myGetColumnDisplayName(pelt->pwszName, &pwszDisplayName);
_PrintIfError(hr, "myGetColumnDisplayName");
if (S_OK != hr)
{
pwszDisplayName = pelt->pwszName;
}
hr = _DupString(NULL, pwszDisplayName, &pelt->pwszDisplayName);
_JumpIfError(hr, error, "_DupString");
}
*pceltFetched = SAFE_SUBTRACT_POINTERS(pelt, rgelt);
*pielt = ielt;
error:
if (S_OK != hr && S_FALSE != hr)
{
if (NULL != rgelt)
{
for (pelt = rgelt; pelt < &rgelt[celt]; pelt++)
{
if (NULL != pelt->pwszName)
{
CoTaskMemFree(pelt->pwszName);
pelt->pwszName = NULL;
}
if (NULL != pelt->pwszDisplayName)
{
CoTaskMemFree(pelt->pwszDisplayName);
pelt->pwszDisplayName = NULL;
}
}
}
}
return(hr);
}
HRESULT
CCertDB::EnumCertDBResultRowNext(
IN CERTSESSION *pcs,
IN DWORD ccvr,
IN CERTVIEWRESTRICTION const *pcvr,
IN DWORD ccolOut,
IN DWORD const *acolOut,
IN LONG cskip,
IN ULONG celt,
OUT CERTDBRESULTROW *rgelt,
OUT ULONG *pceltFetched,
OUT LONG *pcskipped)
{
HRESULT hr;
DWORD iRow;
CERTDBRESULTROW *pResultRow;
LONG cskipped;
DBGPRINT((
DBG_SS_CERTDBI,
"EnumCertDBResultRowNext called: cskip: %d\n", cskip));
if (NULL == pcvr ||
NULL == acolOut ||
NULL == rgelt ||
NULL == pceltFetched ||
NULL == pcskipped)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
*pcskipped = 0;
hr = S_OK;
for (iRow = 0; iRow < celt; iRow++)
{
hr = TestShutDownState();
_JumpIfError(hr, error, "TestShutDownState");
hr = _GetResultRow(
pcs,
ccvr,
pcvr,
cskip,
ccolOut,
acolOut,
&rgelt[iRow],
&cskipped);
if (S_FALSE == hr)
{
*pcskipped += cskipped;
break;
}
DBGPRINT((
DBG_SS_CERTDBI,
"EnumCertDBResultRowNext: rowid %u\n", rgelt[iRow].rowid));
_JumpIfError(hr, error, "_GetResultRow");
*pcskipped += cskipped;
cskip = 0;
}
*pceltFetched = iRow;
DBGPRINT((
DBG_SS_CERTDBI,
"EnumCertDBResultRowNext: %u rows, hr=%x\n",
*pceltFetched,
hr));
error:
if (S_OK != hr && S_FALSE != hr)
{
ReleaseResultRow(celt, rgelt);
}
return(hr);
}
HRESULT
CCertDB::_CompareColumnValue(
IN CERTSESSION *pcs,
IN CERTVIEWRESTRICTION const *pcvr)
{
HRESULT hr;
JET_TABLEID tableid;
DBTABLE const *pdt;
WCHAR *pwszValue = NULL;
BOOL fMatch;
int r;
BYTE rgbFastBuf[256];
BYTE *pbProp = rgbFastBuf;
DWORD cb = sizeof(rgbFastBuf);
// if SEEK_NONE, short circuit tests
if (CVR_SEEK_NONE == (CVR_SEEK_MASK & pcvr->SeekOperator))
{
return S_OK;
}
hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
_JumpIfError(hr, error, "_MapPropIdIndex");
if (TABLE_CERTIFICATES == pdt->dwTable)
{
tableid = pcs->aTable[CSTI_CERTIFICATE].TableId;
}
else
{
tableid = pcs->aTable[CSTI_PRIMARY].TableId;
}
CSASSERT(IsValidJetTableId(tableid));
hr = _RetrieveColumn(
pcs,
tableid,
pdt->dbcolumnid,
pdt->dbcoltyp,
&cb,
rgbFastBuf);
if (S_OK != hr)
{
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
{
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
_PrintError2(hr, "_RetrieveColumn", hr);
hr = S_FALSE;
}
_JumpError2(hr, error, "_RetrieveColumn", S_FALSE);
}
// buffer not big enough, dyn-alloc
CSASSERT(ARRAYSIZE(rgbFastBuf) < cb);
DBGPRINT((
DBG_SS_CERTDB,
"FastBuf miss: _CompareColumnValue(cbProp=%u)\n",
cb));
pbProp = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == pbProp)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
hr = _RetrieveColumn(
pcs,
tableid,
pdt->dbcolumnid,
pdt->dbcoltyp,
&cb,
pbProp);
_JumpIfError(hr, error, "_RetrieveColumn");
} // we have data in-hand
#if DBG_CERTSRV
DumpRestriction(DBG_SS_CERTDBI, -1, pcvr);
dbDumpColumn(DBG_SS_CERTDBI, pdt, pbProp, cb);
#endif
fMatch = FALSE;
switch (pdt->dbcoltyp)
{
case JET_coltypLong:
if (cb == pcvr->cbValue && sizeof(LONG) == cb)
{
LONG lRestriction;
LONG lColumn;
lRestriction = *(LONG *) pcvr->pbValue;
lColumn = *(LONG *) pbProp;
switch (CVR_SEEK_MASK & pcvr->SeekOperator)
{
case CVR_SEEK_EQ:
fMatch = lColumn == lRestriction;
break;
case CVR_SEEK_LT:
fMatch = lColumn < lRestriction;
break;
case CVR_SEEK_LE:
fMatch = lColumn <= lRestriction;
break;
case CVR_SEEK_GE:
fMatch = lColumn >= lRestriction;
break;
case CVR_SEEK_GT:
fMatch = lColumn > lRestriction;
break;
}
DBGPRINT((
DBG_SS_CERTDBI,
"_CompareColumnValue(lColumn=%x %ws lRestriction=%x) -> fMatch=%x\n",
lColumn,
wszSeekOperator(pcvr->SeekOperator),
lRestriction,
fMatch));
}
break;
case JET_coltypDateTime:
if (cb == pcvr->cbValue && sizeof(FILETIME) == cb)
{
r = CompareFileTime(
(FILETIME *) pcvr->pbValue,
(FILETIME *) pbProp);
switch (CVR_SEEK_MASK & pcvr->SeekOperator)
{
case CVR_SEEK_EQ:
fMatch = 0 == r;
break;
case CVR_SEEK_LT:
fMatch = 0 < r;
break;
case CVR_SEEK_LE:
fMatch = 0 <= r;
break;
case CVR_SEEK_GE:
fMatch = 0 >= r;
break;
case CVR_SEEK_GT:
fMatch = 0 > r;
break;
}
#if DBG_CERTSRV
dbDumpFileTime(
DBG_SS_CERTDBI,
"Column: ",
(FILETIME const *) pbProp);
dbDumpFileTime(
DBG_SS_CERTDBI,
"Restriction: ",
(FILETIME const *) pcvr->pbValue);
#endif
DBGPRINT((
DBG_SS_CERTDBI,
"_CompareColumnValue(ftColumn=%08x:%08x %ws ftRestriction=%08x:%08x) -> r=%d, fMatch=%x\n",
((LARGE_INTEGER *) pbProp)->HighPart,
((LARGE_INTEGER *) pbProp)->LowPart,
wszSeekOperator(pcvr->SeekOperator),
((LARGE_INTEGER *) pcvr->pbValue)->HighPart,
((LARGE_INTEGER *) pcvr->pbValue)->LowPart,
r,
fMatch));
}
break;
case JET_coltypText:
case JET_coltypLongText:
CSASSERT(
(1 + wcslen((WCHAR const *) pcvr->pbValue)) * sizeof(WCHAR) ==
pcvr->cbValue);
CSASSERT(wcslen((WCHAR const *) pbProp) * sizeof(WCHAR) == cb);
r = lstrcmpi((WCHAR const *) pcvr->pbValue, (WCHAR const *) pbProp); //pwszValue
switch (CVR_SEEK_MASK & pcvr->SeekOperator)
{
case CVR_SEEK_EQ:
fMatch = 0 == r;
break;
case CVR_SEEK_LT:
fMatch = 0 < r;
break;
case CVR_SEEK_LE:
fMatch = 0 <= r;
break;
case CVR_SEEK_GE:
fMatch = 0 >= r;
break;
case CVR_SEEK_GT:
fMatch = 0 > r;
break;
}
DBGPRINT((
DBG_SS_CERTDBI,
"_CompareColumnValue(pwszColumn=%ws %ws pwszRestriction=%ws) -> r=%d, fMatch=%x\n",
pbProp, //pwszValue,
wszSeekOperator(pcvr->SeekOperator),
pcvr->pbValue,
r,
fMatch));
break;
case JET_coltypLongBinary:
if (CVR_SEEK_EQ != (CVR_SEEK_MASK & pcvr->SeekOperator))
{
hr = E_INVALIDARG;
_JumpError(hr, error, "Bad dbcoltyp");
}
fMatch = cb == pcvr->cbValue &&
0 == memcmp(pcvr->pbValue, pbProp, cb);
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "Bad dbcoltyp");
}
if (!fMatch)
{
hr = S_FALSE;
_JumpError2(hr, error, "No match", S_FALSE);
}
error:
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
if (NULL != pbProp && rgbFastBuf != pbProp)
{
LocalFree(pbProp);
}
return(hr);
}
HRESULT
CCertDB::_MakeSeekKey(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN DBTABLE const *pdt,
IN BYTE const *pbValue,
IN DWORD cbValue)
{
HRESULT hr;
JET_GRBIT grbitKey = JET_bitNewKey;
CSASSERT(IsValidJetTableId(tableid));
if (DBTF_INDEXREQUESTID & pdt->dwFlags)
{
CSASSERTTHREAD(pcs);
hr = _dbgJetMakeKey(
pcs->SesId,
tableid,
&pcs->RowId,
sizeof(pcs->RowId),
grbitKey);
_JumpIfError(hr, error, "JetMakeKey(RowId)");
DBGPRINT((DBG_SS_CERTDBI, "_MakeSeekKey key(RowId):\n"));
DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, (BYTE *) &pcs->RowId, sizeof(pcs->RowId)));
grbitKey = 0;
}
CSASSERTTHREAD(pcs);
hr = _dbgJetMakeKey(pcs->SesId, tableid, pbValue, cbValue, grbitKey);
_JumpIfErrorStr(hr, error, "JetMakeKey", pdt->pwszPropName);
DBGPRINT((DBG_SS_CERTDBI, "_MakeSeekKey key:\n"));
DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, pbValue, cbValue));
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_SeekTable(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN CERTVIEWRESTRICTION const *pcvr,
IN DBTABLE const *pdt,
IN DWORD dwPosition,
OUT DWORD *pTableFlags
DBGPARM(IN DBAUXDATA const *pdbaux))
{
HRESULT hr;
DBSEEKDATA SeekData;
BYTE *pbValue;
DWORD cbValue;
BYTE abRangeKey[JET_cbKeyMost];
DWORD cbRangeKey;
*pTableFlags = 0;
CSASSERT(IsValidJetTableId(tableid));
hr = _JetSeekFromRestriction(pcvr, dwPosition, &SeekData);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = S_FALSE;
}
_JumpIfError2(hr, error, "_JetSeekFromRestriction", S_FALSE);
cbValue = pcvr->cbValue;
pbValue = pcvr->pbValue;
if (ISTEXTCOLTYP(pdt->dbcoltyp) &&
NULL != pbValue &&
cbValue == -1)
{
cbValue = wcslen((WCHAR const *) pbValue) * sizeof(WCHAR);
}
// If we need to set an index limit, seek to the limit location, and save
// a copy of the key until after the initial record is located.
if (CST_SEEKINDEXRANGE & SeekData.SeekFlags)
{
hr = _MakeSeekKey(pcs, tableid, pdt, pbValue, cbValue);
_JumpIfError(hr, error, "_MakeSeekKey");
CSASSERTTHREAD(pcs);
hr = _dbgJetSeek(pcs->SesId, tableid, SeekData.grbitSeekRange);
if ((HRESULT) JET_errRecordNotFound == hr)
{
// No record exists past the data we're interested in.
// Just use the end of the index as the limit.
_PrintError2(hr, "JetSeek(Range Limit): no key, index end is limit", hr);
SeekData.SeekFlags &= ~CST_SEEKINDEXRANGE;
hr = S_OK;
}
else if ((HRESULT) JET_wrnSeekNotEqual == hr)
{
_PrintError2(hr, "JetSeek(Range): ignoring key not equal", hr);
hr = S_OK; // Ignore inexact match when seeking >= or <=
}
//_JumpIfError2(hr, error, "JetSeek(IndexRange)", S_FALSE);
_JumpIfError(hr, error, "JetSeek(IndexRange)");
}
// If we found a valid key at the limit location, save it now.
if (CST_SEEKINDEXRANGE & SeekData.SeekFlags)
{
CSASSERTTHREAD(pcs);
hr = _dbgJetRetrieveKey(
pcs->SesId,
tableid,
abRangeKey,
ARRAYSIZE(abRangeKey),
&cbRangeKey,
0);
_JumpIfError(hr, error, "JetRetrieveKey");
DBGPRINT((DBG_SS_CERTDBI, "RetrieveKey(Range):\n"));
DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, abRangeKey, cbRangeKey));
}
// Locate the initial record: seek to a key or move to one end of the index
if (CST_SEEKNOTMOVE & SeekData.SeekFlags)
{
hr = _MakeSeekKey(pcs, tableid, pdt, pbValue, cbValue);
_JumpIfError(hr, error, "_MakeSeekKey");
CSASSERTTHREAD(pcs);
hr = _dbgJetSeek(pcs->SesId, tableid, SeekData.grbitInitial);
if ((HRESULT) JET_errRecordNotFound == hr)
{
// Routine GetAttribute/Extension call:
_PrintError2(hr, "JetSeek: Property EMPTY", hr);
hr = S_FALSE;
}
else if ((HRESULT) JET_wrnSeekNotEqual == hr)
{
hr = S_OK; // Ignore inexact match when seeking >= or <=
}
_JumpIfError2(hr, error, "JetSeek(Initial)", S_FALSE);
}
else
{
// grbitInitial is a move count here, not a grbit
CSASSERTTHREAD(pcs);
hr = _dbgJetMove(pcs->SesId, tableid, SeekData.grbitInitial, 0);
if ((HRESULT) JET_errNoCurrentRecord == hr)
{
// Routine Enumerate call:
// _JumpIfError(hr, error, "JetMove: no more elements");
hr = S_FALSE;
}
_JumpIfError2(hr, error, "JetMove(End)", S_FALSE);
// If moving the cursor to the last element, we want to position
// ourselves to step over the end again (skip the last element).
//
// If moving to the first element, we want to position ourselves on the
// first element and use it before stepping
if (SEEKPOS_FIRST == dwPosition || SEEKPOS_INDEXFIRST == dwPosition)
{
SeekData.SeekFlags |= CST_SEEKUSECURRENT;
}
}
// We're done seeking around; set the index limit from the saved key.
if (CST_SEEKINDEXRANGE & SeekData.SeekFlags)
{
CSASSERTTHREAD(pcs);
hr = _dbgJetMakeKey(
pcs->SesId,
tableid,
abRangeKey,
cbRangeKey,
JET_bitNormalizedKey);
_JumpIfError(hr, error, "JetMakeKey");
DBGPRINT((DBG_SS_CERTDBI, "RangeKey:\n"));
DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, abRangeKey, cbRangeKey));
CSASSERTTHREAD(pcs);
hr = _dbgJetSetIndexRange(
pcs->SesId,
tableid,
SeekData.grbitRange);
if ((HRESULT) JET_errNoCurrentRecord == hr)
{
// No records to enumerate:
_PrintError2(hr, "JetSetIndexRange: no records to enumerate", hr);
hr = S_FALSE;
}
_JumpIfError2(hr, error, "JetSetIndexRange", S_FALSE);
}
DBGCODE(_DumpRowId("post-_SeekTable", pcs, tableid));
DBGCODE(_DumpColumn("post-_SeekTable", pcs, tableid, pdt));
*pTableFlags = SeekData.SeekFlags;
error:
if (S_FALSE == hr)
{
DWORD dwPosition2 = dwPosition;
switch (dwPosition)
{
case SEEKPOS_FIRST:
dwPosition2 = SEEKPOS_INDEXFIRST;
break;
case SEEKPOS_LAST:
dwPosition2 = SEEKPOS_INDEXLAST;
break;
}
if (dwPosition2 != dwPosition)
{
hr = _SeekTable(
pcs,
tableid,
pcvr,
pdt,
dwPosition2,
pTableFlags
DBGPARM(pdbaux));
_PrintIfError2(hr, "_SeekTable: recurse on index first/last", S_FALSE);
}
}
#if DBG_CERTSRV
if (S_OK != hr)
{
DumpRestriction(DBG_SS_CERTDBI, 0, pcvr);
}
#endif
return(myJetHResult(hr));
}
HRESULT
CCertDB::_MoveTable(
IN CERTSESSION *pcs,
IN DWORD ccvr,
IN CERTVIEWRESTRICTION const *pcvr,
IN LONG cskip,
OUT LONG *pcskipped)
{
HRESULT hr;
DWORD cb;
DBAUXDATA const *pdbaux;
DBTABLE const *pdt;
DWORD icvr;
DWORD SeekFlags;
LONG lSeek;
LONG skipIncrement;
LONG cskipRemain;
BOOL fHitEnd = FALSE;
LONG cskippeddummy;
CERTSESSIONTABLE *pTable;
CERTSESSIONTABLE *pTable2;
*pcskipped = 0;
DBGPRINT((
DBG_SS_CERTDBI,
"_MoveTable called(ccvr=%d, cskip=%d, flags=%ws)\n",
ccvr,
cskip,
wszCSFFlags(pcs->SesFlags)));
hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
_JumpIfError(hr, error, "_MapPropIdIndex");
pTable = &pcs->aTable[CSTI_PRIMARY];
pTable2 = NULL;
switch (DTI_TABLEMASK & pcvr->ColumnIndex)
{
case DTI_REQUESTTABLE:
pdbaux = &g_dbauxRequests;
pTable2 = &pcs->aTable[CSTI_CERTIFICATE];
break;
case DTI_CERTIFICATETABLE:
pdbaux = &g_dbauxCertificates;
pTable = &pcs->aTable[CSTI_CERTIFICATE];
pTable2 = &pcs->aTable[CSTI_PRIMARY];
break;
case DTI_EXTENSIONTABLE:
pdbaux = &g_dbauxExtensions;
break;
case DTI_ATTRIBUTETABLE:
pdbaux = &g_dbauxAttributes;
break;
case DTI_CRLTABLE:
pdbaux = &g_dbauxCRLs;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "ColumnIndex Table");
}
DBGPRINT((
DBG_SS_CERTDBI,
"_MoveTable(Table=%hs, TableFlags=%ws)\n",
pdbaux->pszTable,
wszCSTFlags(pTable->TableFlags)));
if (NULL != pTable2 && IsValidJetTableId(pTable2->TableId))
{
DBGPRINT((
DBG_SS_CERTDBI,
"_MoveTable(Table2=%hs, TableFlags2=%ws)\n",
&g_dbauxCertificates == pdbaux?
g_dbauxRequests.pszTable :
g_dbauxCertificates.pszTable,
wszCSTFlags(pTable2->TableFlags)));
}
switch (pcvr->SortOrder)
{
case CVR_SORT_DESCEND:
lSeek = JET_MovePrevious;
break;
case CVR_SORT_NONE:
default:
CSASSERT(!"bad pcvr->SortOrder"); // shouldn't get this far
// FALL THROUGH
case CVR_SORT_ASCEND:
lSeek = JET_MoveNext;
break;
}
// Add one to the skip count for the implicit Next operation. Next
// always moves forward one, even when a negative skip count moves
// backward. The net result may be a forward or backward skip.
cskipRemain = cskip + 1;
skipIncrement = 1;
if (0 > cskipRemain)
{
CSASSERT(JET_MoveNext == -1 * JET_MovePrevious);
lSeek *= -1; // Seek in opposite direction
cskipRemain *= -1; // make the skip count positive
skipIncrement = -1;
}
CSASSERT(0 <= cskipRemain);
while (0 != cskipRemain)
{
DBGPRINT((
DBG_SS_CERTDBI,
"_MoveTable loop: ccvr=%d, cskipRemain=%d, lSeek=%d, flags=%ws\n",
ccvr,
cskipRemain,
lSeek,
wszCSFFlags(pcs->SesFlags)));
DBGCODE(_DumpRowId("_MoveTable(loop top)", pcs, pTable->TableId));
if (CSF_VIEW & pcs->SesFlags)
{
hr = TestShutDownState();
_JumpIfError(hr, error, "TestShutDownState");
}
if (CSF_VIEWRESET & pcs->SesFlags)
{
hr = _SeekTable(
pcs,
pTable->TableId,
pcvr,
pdt,
SEEKPOS_FIRST,
&pTable->TableFlags
DBGPARM(pdbaux));
_JumpIfError(hr, error, "_SeekTable");
pcs->SesFlags &= ~CSF_VIEWRESET;
}
if (0 == (CST_SEEKUSECURRENT & pTable->TableFlags))
{
CSASSERTTHREAD(pcs);
hr = _dbgJetMove(pcs->SesId, pTable->TableId, lSeek, 0);
if ((HRESULT) JET_errNoCurrentRecord == hr)
{
_PrintIfError2(hr, "JetMove: no more elements", hr);
if (fHitEnd)
{
// we hit the end trying to backstep! We're done
hr = S_FALSE;
_JumpError(hr, error, "JetMove: db backstep hit beginning");
}
fHitEnd = TRUE;
// NOTE: Tough case
//
// We just hit the end of the database index, which could be a
// virtual end or the real end. To recover, we call _SeekTable
// to position ourselves at the last legal element computed by
// the 1st restriction, then allow this routine to rewind until
// we position ourselves on the very last legal element as
// computed by 2nd through Nth restrictions.
// Routine Seek call to position at end of enumeration
hr = _SeekTable(
pcs,
pTable->TableId,
pcvr,
pdt,
SEEKPOS_LAST, // cursor at end
&pTable->TableFlags
DBGPARM(pdbaux));
_JumpIfError(hr, error, "_SeekTable moving to last elt");
// now fall through, allow other restrictions to test for 1st
// valid element
lSeek *= -1; // Seek in opposite direction
cskipRemain = 1; // one valid element
pcskipped = &cskippeddummy; // stop counting skipped rows
}
_JumpIfError2(hr, error, "JetMove", S_FALSE);
DBGCODE(_DumpRowId("_MoveTable(post-move)", pcs, pTable->TableId));
hr = _CompareColumnValue(pcs, pcvr);
_JumpIfError2(hr, error, "_CompareColumnValue", S_FALSE);
}
pTable->TableFlags &= ~CST_SEEKUSECURRENT;
// Fetch RowId from the first table, form a key for the second
// table and seek to the corresponding record in the second table.
cb = sizeof(pcs->RowId);
hr = _RetrieveColumn(
pcs,
pTable->TableId,
pdbaux->pdtRowId->dbcolumnid,
pdbaux->pdtRowId->dbcoltyp,
&cb,
(BYTE *) &pcs->RowId);
_JumpIfError(hr, error, "_RetrieveColumn");
DBGPRINT((
DBG_SS_CERTDBI,
"_MoveTable(Primary) %hs --> RowId=%d\n",
pdbaux->pszTable,
pcs->RowId));
if (NULL != pTable2 && IsValidJetTableId(pTable2->TableId))
{
CSASSERTTHREAD(pcs);
hr = _dbgJetMakeKey(
pcs->SesId,
pTable2->TableId,
&pcs->RowId,
sizeof(pcs->RowId),
JET_bitNewKey);
_JumpIfError(hr, error, "JetMakeKey");
hr = _dbgJetSeek(pcs->SesId, pTable2->TableId, JET_bitSeekEQ);
if ((HRESULT) JET_errRecordNotFound == hr)
{
// Database is inconsistent
hr = S_FALSE;
}
_JumpIfError2(hr, error, "JetSeek", S_FALSE);
DBGPRINT((
DBG_SS_CERTDBI,
"_MoveTable(Secondary) %hs --> RowId=%d\n",
&g_dbauxCertificates == pdbaux?
g_dbauxRequests.pszTable :
g_dbauxCertificates.pszTable,
pcs->RowId));
}
// Now verify that any addtional restrictions are satisfied
for (icvr = 1; icvr < ccvr; icvr++)
{
#if 0
printf(
"RowId=%u, cvr[%u]: seek=%x, *pb=%x\n",
pcs->RowId,
icvr,
pcvr[icvr].SeekOperator,
*(DWORD *) pcvr[icvr].pbValue);
#endif
hr = _CompareColumnValue(pcs, &pcvr[icvr]);
if (S_FALSE == hr)
{
break; // skip row silently
}
_JumpIfError(hr, error, "_CompareColumnValue");
}
if (icvr >= ccvr)
{
*pcskipped += skipIncrement;
cskipRemain--; // found a matching row
}
} // while (cskipRemain)
error:
// if we nailed the end and rewound, return failure
if (fHitEnd && S_OK == hr)
{
hr = S_FALSE;
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::_GetResultRow(
IN CERTSESSION *pcs,
IN DWORD ccvr,
IN CERTVIEWRESTRICTION const *pcvr,
IN LONG cskip,
IN DWORD ccolOut,
IN DWORD const *acolOut,
OUT CERTDBRESULTROW *pelt,
OUT LONG *pcskipped)
{
HRESULT hr;
DWORD iCol;
BYTE *pbProp = NULL;
BYTE *pbT;
DWORD cbAlloc = 0;
DWORD cbProp;
WCHAR awc[CCH_DBMAXTEXT_LONG];
DBGPRINT((
DBG_SS_CERTDBI,
"_GetResultRow(ccvr=%d, ccolOut=%d, cskip=%d, flags=%ws)\n",
ccvr,
ccolOut,
cskip,
wszCSFFlags(pcs->SesFlags)));
// This may move past the end of the database index entries.
// In that case, we're positioned at the end of the index.
hr = _MoveTable(pcs, ccvr, pcvr, cskip, pcskipped);
_JumpIfError2(hr, error, "_MoveTable", S_FALSE);
DBGPRINT((DBG_SS_CERTDBI, "_GetResultRow: RowId=%d\n", pcs->RowId));
pelt->acol = (CERTDBRESULTCOLUMN *) CoTaskMemAlloc(
ccolOut * sizeof(pelt->acol[0]));
if (NULL == pelt->acol)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "alloc acol");
}
ZeroMemory(pelt->acol, ccolOut * sizeof(pelt->acol[0]));
pelt->rowid = pcs->RowId;
pelt->ccol = ccolOut;
for (iCol = 0; iCol < ccolOut; iCol++)
{
DBTABLE const *pdt;
CERTDBRESULTCOLUMN *pCol;
pCol = &pelt->acol[iCol];
pCol->Index = acolOut[iCol];
hr = _MapPropIdIndex(pCol->Index, &pdt, &pCol->Type);
_JumpIfError(hr, error, "_MapPropIdIndex");
while (TRUE)
{
cbProp = cbAlloc;
hr = GetProperty(pcs, pdt, &cbProp, pbProp);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
break; // leave 0 size, NULL pointer
}
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
{
_JumpIfError(hr, error, "GetProperty");
}
if (cbAlloc >= cbProp)
{
CSASSERT(S_OK == hr);
CSASSERT(0 != cbProp && NULL != pbProp);
break; // property value is in cbProp, pbProp
}
// Property value is too large for the buffer -- grow it
if (NULL == pbProp)
{
pbT = (BYTE *) LocalAlloc(LMEM_FIXED, cbProp);
}
else
{
pbT = (BYTE *) LocalReAlloc(pbProp, cbProp, LMEM_MOVEABLE);
}
if (NULL == pbT)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc/LocalReAlloc property");
}
pbProp = pbT;
cbAlloc = cbProp;
}
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
BYTE const *pb = pbProp;
DWORD cwc;
if (PROPTYPE_STRING == (PROPTYPE_MASK & pCol->Type))
{
CSASSERT( *((WCHAR*) &(pbProp[cbProp])) == L'\0');
cbProp += sizeof(WCHAR); // include NULL term
}
pCol->cbValue = cbProp;
pCol->pbValue = (BYTE *) CoTaskMemAlloc(cbProp);
if (NULL == pCol->pbValue)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "CoTaskMemAlloc");
}
CopyMemory(pCol->pbValue, pb, pCol->cbValue);
}
DBGPRINT((
DBG_SS_CERTDBI,
"_GetResultRow: fetch %ws.%ws: type=%x cb=%x\n",
wszTable(pdt->dwTable),
pdt->pwszPropName,
pCol->Type,
pCol->cbValue));
}
hr = S_OK;
error:
if (NULL != pbProp)
{
LocalFree(pbProp);
}
return(hr);
}
HRESULT
CCertDB::ReleaseResultRow(
IN ULONG celt,
IN OUT CERTDBRESULTROW *rgelt)
{
HRESULT hr;
DWORD iRow;
DWORD iCol;
CERTDBRESULTROW *pResultRow;
if (NULL == rgelt)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
for (iRow = 0; iRow < celt; iRow++)
{
pResultRow = &rgelt[iRow];
if (NULL != pResultRow->acol)
{
for (iCol = 0; iCol < pResultRow->ccol; iCol++)
{
if (NULL != pResultRow->acol[iCol].pbValue)
{
CoTaskMemFree(pResultRow->acol[iCol].pbValue);
pResultRow->acol[iCol].pbValue = NULL;
}
}
CoTaskMemFree(pResultRow->acol);
pResultRow->acol = NULL;
}
pResultRow->ccol = 0;
}
hr = S_OK;
error:
return(hr);
}
HRESULT
CCertDB::EnumerateSetup(
IN CERTSESSION *pcs,
IN OUT DWORD *pFlags,
OUT JET_TABLEID *ptableid)
{
HRESULT hr;
JET_TABLEID tableid = 0;
DBAUXDATA const *pdbaux;
if (NULL == pcs || NULL == ptableid)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
switch (*pFlags)
{
case CIE_TABLE_ATTRIBUTES:
pdbaux = &g_dbauxAttributes;
break;
case CIE_TABLE_EXTENSIONS:
pdbaux = &g_dbauxExtensions;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "*pFlags");
}
CSASSERTTHREAD(pcs);
hr = _dbgJetOpenTable(
pcs->SesId,
pcs->DBId,
pdbaux->pszTable,
NULL,
0,
0,
&tableid);
_JumpIfError(hr, error, "JetOpenTable");
CSASSERTTHREAD(pcs);
hr = _dbgJetSetCurrentIndex2(
pcs->SesId,
tableid,
pdbaux->pszRowIdIndex,
JET_bitMoveFirst);
_JumpIfError(hr, error, "JetSetCurrentIndex2");
CSASSERTTHREAD(pcs);
hr = _dbgJetMakeKey(
pcs->SesId,
tableid,
&pcs->RowId,
sizeof(pcs->RowId),
JET_bitNewKey);
_JumpIfError(hr, error, "JetMakeKey");
*pFlags |= CIE_RESET;
CSASSERT(IsValidJetTableId(tableid));
*ptableid = tableid;
tableid = 0;
error:
if (IsValidJetTableId(tableid))
{
CSASSERTTHREAD(pcs);
_dbgJetCloseTable(pcs->SesId, tableid);
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::_EnumerateMove(
IN CERTSESSION *pcs,
IN OUT DWORD *pFlags,
IN DBAUXDATA const *pdbaux,
IN JET_TABLEID tableid,
IN LONG cskip)
{
HRESULT hr;
DWORD cb;
DWORD RowId;
LONG lSeek;
DBGPRINT((
DBG_SS_CERTDBI,
"_EnumerateMove(cskip=%d, flags=%x%hs)\n",
cskip,
*pFlags,
(CIE_RESET & *pFlags)? " Reset" : ""));
CSASSERT(IsValidJetTableId(tableid));
if (CIE_RESET & *pFlags)
{
CSASSERTTHREAD(pcs);
hr = _dbgJetSeek(pcs->SesId, tableid, JET_bitSeekEQ);
if ((HRESULT) JET_errRecordNotFound == hr)
{
hr = S_FALSE;
}
_JumpIfError2(hr, error, "JetSeek", S_FALSE);
*pFlags &= ~CIE_RESET;
}
else
{
// Add one to the skip count for the implicit Next operation. Next
// always moves forward one, even when a negative skip count moves
// backward. The net result may be a forward or backward skip.
cskip++;
}
if (0 != cskip)
{
lSeek = JET_MoveNext * cskip;
CSASSERT(JET_MoveNext == -1 * JET_MovePrevious);
CSASSERTTHREAD(pcs);
hr = _dbgJetMove(pcs->SesId, tableid, lSeek, 0);
if ((HRESULT) JET_errNoCurrentRecord == hr)
{
hr = S_FALSE;
}
_JumpIfError2(hr, error, "JetMove", S_FALSE);
// Make sure this entry is for the same request:
cb = sizeof(RowId);
hr = _RetrieveColumn(
pcs,
tableid,
pdbaux->pdtRowId->dbcolumnid,
pdbaux->pdtRowId->dbcoltyp,
&cb,
(BYTE *) &RowId);
_JumpIfError(hr, error, "_RetrieveColumn");
if (RowId != pcs->RowId)
{
hr = S_FALSE;
goto error;
}
}
hr = S_OK;
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::EnumerateNext(
IN CERTSESSION *pcs,
IN OUT DWORD *pFlags,
IN JET_TABLEID tableid,
IN LONG cskip,
IN ULONG celt,
OUT CERTDBNAME *rgelt,
OUT ULONG *pceltFetched)
{
HRESULT hr;
DWORD cb;
DWORD cwc;
DWORD RowId;
CERTDBNAME *pelt;
WCHAR wszTmp[MAX_PATH];
DBAUXDATA const *pdbaux;
if (NULL == pcs || NULL == rgelt || NULL == pceltFetched)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
ZeroMemory(rgelt, celt * sizeof(rgelt[0]));
CSASSERT(IsValidJetTableId(tableid));
switch (CIE_TABLE_MASK & *pFlags)
{
case CIE_TABLE_ATTRIBUTES:
pdbaux = &g_dbauxAttributes;
break;
case CIE_TABLE_EXTENSIONS:
pdbaux = &g_dbauxExtensions;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "*pFlags");
}
hr = S_OK;
for (pelt = rgelt; pelt < &rgelt[celt]; pelt++)
{
hr = _EnumerateMove(pcs, pFlags, pdbaux, tableid, cskip);
if (S_FALSE == hr)
{
break;
}
_JumpIfError(hr, error, "_EnumerateMove");
cskip = 0;
cb = sizeof(wszTmp);
hr = _RetrieveColumn(
pcs,
tableid,
pdbaux->pdtName->dbcolumnid,
pdbaux->pdtName->dbcoltyp,
&cb,
(BYTE *) wszTmp);
_JumpIfError(hr, error, "_RetrieveColumn");
CSASSERT(0 == (cb % sizeof(WCHAR))); // integer # of wchars
CSASSERT(L'\0' == wszTmp[cb/sizeof(WCHAR)]); // zero term
hr = _DupString(NULL, wszTmp, &pelt->pwszName);
_JumpIfError(hr, error, "_DupString");
}
*pceltFetched = SAFE_SUBTRACT_POINTERS(pelt, rgelt);
error:
if (S_OK != hr && S_FALSE != hr)
{
if (NULL != rgelt)
{
for (pelt = rgelt; pelt < &rgelt[celt]; pelt++)
{
if (NULL != pelt->pwszName)
{
CoTaskMemFree(pelt->pwszName);
pelt->pwszName = NULL;
}
}
}
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::EnumerateClose(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid)
{
HRESULT hr;
if (NULL == pcs)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
CSASSERT(IsValidJetTableId(tableid));
CSASSERTTHREAD(pcs);
hr = _dbgJetCloseTable(pcs->SesId, tableid);
_JumpIfError(hr, error, "JetCloseTable");
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_BuildColumnIds(
IN CERTSESSION *pcs,
IN CHAR const *pszTableName,
IN DBTABLE *pdt)
{
HRESULT hr;
JET_TABLEID tableid;
JET_COLUMNDEF columndef;
BOOL fOpen = FALSE;
hr = _dbgJetOpenTable(
pcs->SesId,
pcs->DBId,
pszTableName,
NULL,
0,
0,
&tableid);
_JumpIfError(hr, error, "JetOpenTable");
fOpen = TRUE;
CSASSERT(IsValidJetTableId(tableid));
for ( ; NULL != pdt->pwszPropName; pdt++)
{
hr = _dbgJetGetColumnInfo(
pcs->SesId,
pcs->DBId,
pszTableName,
pdt->pszFieldName,
&columndef,
sizeof(columndef),
JET_ColInfo);
if ((HRESULT) JET_errColumnNotFound == hr &&
(DBTF_SOFTFAIL & pdt->dwFlags))
{
pdt->dwFlags |= DBTF_MISSING;
pdt->dbcolumnid = -1;
DBGPRINT((
DBG_SS_CERTDB,
"_BuildColumnIds: %hs.%hs Ignoring missing column\n",
pszTableName,
pdt->pszFieldName));
hr = S_OK;
continue;
}
_JumpIfError(hr, error, "JetGetColumnInfo");
pdt->dbcolumnid = columndef.columnid;
CSASSERT(
pdt->dbcoltyp == columndef.coltyp ||
(ISTEXTCOLTYP(pdt->dbcoltyp) && ISTEXTCOLTYP(columndef.coltyp)));
if (JET_coltypText == pdt->dbcoltyp)
{
CSASSERT(pdt->dwcbMax == pdt->dbcolumnMax);
CSASSERT(0 != pdt->dbcolumnMax);
CSASSERT(CB_DBMAXTEXT_MAXINTERNAL >= pdt->dbcolumnMax);
}
else if (JET_coltypLongText == pdt->dbcoltyp)
{
CSASSERT(pdt->dwcbMax == pdt->dbcolumnMax);
CSASSERT(CB_DBMAXTEXT_MAXINTERNAL < pdt->dbcolumnMax);
}
else if (JET_coltypLongBinary == pdt->dbcoltyp)
{
CSASSERT(pdt->dwcbMax == pdt->dbcolumnMax);
CSASSERT(0 != pdt->dbcolumnMax);
}
else if (JET_coltypDateTime == pdt->dbcoltyp)
{
CSASSERT(sizeof(DATE) == pdt->dwcbMax);
CSASSERT(0 == pdt->dbcolumnMax);
}
else if (JET_coltypLong == pdt->dbcoltyp)
{
CSASSERT(sizeof(LONG) == pdt->dwcbMax);
CSASSERT(0 == pdt->dbcolumnMax);
}
else
{
DBGPRINT((
DBG_SS_CERTDB,
"_BuildColumnIds: %hs.%hs Unknown column type %u\n",
pszTableName,
pdt->pszFieldName,
pdt->dbcoltyp));
CSASSERT(!"Unknown column type");
}
if (pdt->dwcbMax != columndef.cbMax)
{
DBGPRINT((
DBG_SS_CERTDB,
"_BuildColumnIds: %hs.%hs length %u, expected %u\n",
pszTableName,
pdt->pszFieldName,
columndef.cbMax,
pdt->dwcbMax));
// max size can only be increased...
if (pdt->dwcbMax > columndef.cbMax)
{
JET_DDLMAXCOLUMNSIZE jdmcs;
jdmcs.szTable = const_cast<char *>(pszTableName);
jdmcs.szColumn = const_cast<char *>(pdt->pszFieldName);
jdmcs.cbMax = pdt->dwcbMax;
hr = _dbgJetConvertDDL(
pcs->SesId,
pcs->DBId,
opDDLConvIncreaseMaxColumnSize,
&jdmcs,
sizeof(jdmcs));
_PrintIfError(hr, "JetConvertDDL");
if (S_OK == hr)
{
m_fDBRestart = TRUE;
}
}
}
pdt->dbcolumnidOld = -1;
if (chTEXTPREFIX == *pdt->pszFieldName ||
(DBTF_COLUMNRENAMED & pdt->dwFlags))
{
char const *pszFieldName = &pdt->pszFieldName[1];
if (DBTF_COLUMNRENAMED & pdt->dwFlags)
{
pszFieldName += strlen(pszFieldName) + 1;
}
CSASSERT(
chTEXTPREFIX != *pszTableName ||
ISTEXTCOLTYP(columndef.coltyp));
hr = _dbgJetGetColumnInfo(
pcs->SesId,
pcs->DBId,
pszTableName,
pszFieldName,
&columndef,
sizeof(columndef),
JET_ColInfo);
if (S_OK == hr)
{
CSASSERT(
chTEXTPREFIX != *pszTableName ||
ISTEXTCOLTYP(columndef.coltyp));
DBGPRINT((
DBG_SS_CERTDB,
"Found Old Column: %hs.%hs: %x\n",
pszTableName,
pszFieldName,
columndef.columnid));
pdt->dwFlags |= DBTF_OLDCOLUMNID;
pdt->dbcolumnidOld = columndef.columnid;
m_fFoundOldColumns = TRUE;
}
hr = S_OK;
}
}
error:
if (fOpen)
{
HRESULT hr2;
hr2 = _dbgJetCloseTable(pcs->SesId, tableid);
_PrintIfError(hr2, "JetCloseTable");
if (S_OK == hr)
{
hr = hr2;
}
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::_AddKeyLengthColumn(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN DWORD RowId,
IN DBTABLE const *pdtPublicKey,
IN DBTABLE const *pdtPublicKeyAlgorithm,
IN DBTABLE const *pdtPublicKeyParameters,
IN DBTABLE const *pdtPublicKeyLength,
IN DBAUXDATA const *pdbaux,
IN OUT BYTE **ppbBuf,
IN OUT DWORD *pcbBuf)
{
HRESULT hr;
DWORD cb;
DWORD KeyLength;
CERT_PUBLIC_KEY_INFO PublicKeyInfo;
ZeroMemory(&PublicKeyInfo, sizeof(PublicKeyInfo));
DBGPRINT((
DBG_SS_CERTDBI,
"Converting %hs[%d].%hs\n",
pdbaux->pszTable,
RowId,
pdtPublicKeyLength->pszFieldName));
cb = sizeof(KeyLength);
hr = _RetrieveColumn(
pcs,
tableid,
pdtPublicKeyLength->dbcolumnid,
pdtPublicKeyLength->dbcoltyp,
&cb,
(BYTE *) &KeyLength);
if (S_OK == hr)
{
goto error; // already set -- skip this column
}
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_JumpError(hr, error, "_RetrieveColumn");
}
// Fetch the public key algorithm ObjId & copy as ansi to alloc'd memory.
hr = _RetrieveColumnBuffer(
pcs,
tableid,
pdtPublicKeyAlgorithm->dbcolumnid,
pdtPublicKeyAlgorithm->dbcoltyp,
&cb,
ppbBuf,
pcbBuf);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = S_OK;
goto error; // No old data -- skip this column
}
_JumpIfErrorStr(
hr,
error,
"_RetrieveColumnBuffer",
pdtPublicKeyAlgorithm->pwszPropName);
if (!ConvertWszToSz(
&PublicKeyInfo.Algorithm.pszObjId,
(WCHAR const *) *ppbBuf,
-1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ConvertWszToSz(LogDir)");
}
// Fetch the public key algorithm paramaters, and copy to alloc'd memory.
hr = _RetrieveColumnBuffer(
pcs,
tableid,
pdtPublicKeyParameters->dbcolumnid,
pdtPublicKeyParameters->dbcoltyp,
&PublicKeyInfo.Algorithm.Parameters.cbData,
ppbBuf,
pcbBuf);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = S_OK;
goto error; // No old data -- skip this column
}
_JumpIfErrorStr(
hr,
error,
"_RetrieveColumnBuffer",
pdtPublicKeyParameters->pwszPropName);
PublicKeyInfo.Algorithm.Parameters.pbData = (BYTE *) LocalAlloc(
LMEM_FIXED,
PublicKeyInfo.Algorithm.Parameters.cbData);
if (NULL == PublicKeyInfo.Algorithm.Parameters.pbData)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ConvertWszToSz(LogDir)");
}
CopyMemory(
PublicKeyInfo.Algorithm.Parameters.pbData,
*ppbBuf,
PublicKeyInfo.Algorithm.Parameters.cbData);
// Fetch the public key, and leave in dynamic buffer.
hr = _RetrieveColumnBuffer(
pcs,
tableid,
pdtPublicKey->dbcolumnid,
pdtPublicKey->dbcoltyp,
&PublicKeyInfo.PublicKey.cbData,
ppbBuf,
pcbBuf);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = S_OK;
goto error; // No old data -- skip this column
}
_JumpIfErrorStr(
hr,
error,
"_RetrieveColumnBuffer",
pdtPublicKey->pwszPropName);
PublicKeyInfo.PublicKey.pbData = *ppbBuf;
KeyLength = CertGetPublicKeyLength(X509_ASN_ENCODING, &PublicKeyInfo);
// Store the key length in the new column
hr = _SetColumn(
pcs->SesId,
tableid,
pdtPublicKeyLength->dbcolumnid,
sizeof(KeyLength),
(BYTE const *) &KeyLength);
_JumpIfErrorStr(hr, error, "_SetColumn", pdtPublicKeyLength->pwszPropName);
DBGPRINT((
DBG_SS_CERTDB,
"Converted %hs[%d].%hs: %u\n",
pdbaux->pszTable,
RowId,
pdtPublicKeyLength->pszFieldName,
KeyLength));
error:
if (NULL != PublicKeyInfo.Algorithm.pszObjId)
{
LocalFree(PublicKeyInfo.Algorithm.pszObjId);
}
if (NULL != PublicKeyInfo.Algorithm.Parameters.pbData)
{
LocalFree(PublicKeyInfo.Algorithm.Parameters.pbData);
}
return(hr);
}
HRESULT
CCertDB::_AddCallerName(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN DWORD RowId,
IN DBTABLE const *pdtCallerName,
IN DBTABLE const *pdtRequesterName,
IN DBAUXDATA const *pdbaux,
IN OUT BYTE **ppbBuf,
IN OUT DWORD *pcbBuf)
{
HRESULT hr;
DWORD cb;
DBGPRINT((
DBG_SS_CERTDBI,
"Converting %hs[%d].%hs\n",
pdbaux->pszTable,
RowId,
pdtCallerName->pszFieldName));
cb = 0;
hr = _RetrieveColumn(
pcs,
tableid,
pdtCallerName->dbcolumnid,
pdtCallerName->dbcoltyp,
&cb,
NULL);
if (S_OK == hr)
{
goto error; // already set -- skip this column
}
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_JumpError(hr, error, "_RetrieveColumn");
}
// Fetch the ReqesterName
hr = _RetrieveColumnBuffer(
pcs,
tableid,
pdtRequesterName->dbcolumnid,
pdtRequesterName->dbcoltyp,
&cb,
ppbBuf,
pcbBuf);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = S_OK;
goto error; // No old data -- skip this column
}
_JumpIfErrorStr(
hr,
error,
"_RetrieveColumnBuffer",
pdtRequesterName->pwszPropName);
// Store the RequesterName as the CallerName in the new column
hr = _SetColumn(
pcs->SesId,
tableid,
pdtCallerName->dbcolumnid,
cb,
*ppbBuf);
_JumpIfErrorStr(hr, error, "_SetColumn", pdtCallerName->pwszPropName);
DBGPRINT((
DBG_SS_CERTDB,
"Converted %hs[%d].%hs: %ws\n",
pdbaux->pszTable,
RowId,
pdtCallerName->pszFieldName,
*ppbBuf));
error:
return(hr);
}
HRESULT
CCertDB::_ConvertColumnData(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN DWORD RowId,
IN DBTABLE const *pdt,
IN DBAUXDATA const *pdbaux,
IN OUT BYTE **ppbBuf,
IN OUT DWORD *pcbBuf)
{
HRESULT hr;
WCHAR *pwszNew = NULL;
BYTE const *pbNew;
DWORD cb;
DBGPRINT((
DBG_SS_CERTDBI,
"Converting %hs[%d].%hs:\n",
pdbaux->pszTable,
RowId,
pdt->pszFieldName));
// Fetch old column. Grows the buffer if necessary.
hr = _RetrieveColumnBuffer(
pcs,
tableid,
pdt->dbcolumnidOld,
pdt->dbcoltyp,
&cb,
ppbBuf,
pcbBuf);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = S_OK;
goto error; // No old data -- skip this column
}
_JumpIfErrorStr(hr, error, "_RetrieveColumnBuffer", pdt->pwszPropName);
if (DBTF_COLUMNRENAMED & pdt->dwFlags)
{
pbNew = *ppbBuf;
}
else
{
if (!ConvertSzToWsz(&pwszNew, (char *) *ppbBuf, -1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ConvertSzToWsz");
}
pbNew = (BYTE const *) pwszNew;
cb = wcslen(pwszNew) * sizeof(WCHAR);
}
// Store the converted string in the Unicode column
hr = _SetColumn(pcs->SesId, tableid, pdt->dbcolumnid, cb, pbNew);
_JumpIfErrorStr(hr, error, "_SetColumn", pdt->pwszPropName);
if (JET_coltypLong != pdt->dbcoltyp)
{
// Clear out the old column
hr = _SetColumn(pcs->SesId, tableid, pdt->dbcolumnidOld, 0, NULL);
_JumpIfErrorStr(hr, error, "_SetColumn(Clear old)", pdt->pwszPropName);
}
DBGPRINT((
DBG_SS_CERTDB,
"Converted %hs[%d].%hs: %ws\n",
pdbaux->pszTable,
RowId,
pdt->pszFieldName,
ISTEXTCOLTYP(pdt->dbcoltyp)? (WCHAR const *) pbNew : L""));
if (!ISTEXTCOLTYP(pdt->dbcoltyp))
{
DBGDUMPHEX((DBG_SS_CERTDB, DH_NOADDRESS, pbNew, cb));
}
error:
if (NULL != pwszNew)
{
LocalFree(pwszNew);
}
return(hr);
}
DBTABLE *
dbFindColumn(
IN DBTABLE *adt,
IN char const *pszFieldName)
{
DBTABLE *pdt;
DBTABLE *pdtRet = NULL;
for (pdt = adt; NULL != pdt->pwszPropName; pdt++)
{
if (0 == _stricmp(pszFieldName, pdt->pszFieldName))
{
pdtRet = pdt;
break;
}
}
return(pdtRet);
}
HRESULT
CCertDB::_ConvertOldColumnData(
IN CERTSESSION *pcs,
IN CHAR const *pszTableName,
IN DBAUXDATA const *pdbaux,
IN DBTABLE *adt)
{
HRESULT hr;
HRESULT hr2;
JET_TABLEID tableid;
JET_COLUMNDEF columndef;
BOOL fOpen = FALSE;
BOOL fTransacted = FALSE;
DBTABLE *pdt;
DWORD RowId;
DWORD cb;
BYTE *pbBuf = NULL;
DWORD cbBuf = 0;
BOOL fZeroIssuerNameId = FALSE;
DWORD IssuerNameId;
DBTABLE *pdtPublicKeyLength = NULL;
DBTABLE *pdtPublicKey;
DBTABLE *pdtPublicKeyAlgorithm;
DBTABLE *pdtPublicKeyParameters;
DBTABLE *pdtCallerName = NULL;
DBTABLE *pdtRequesterName;
hr = _dbgJetOpenTable(
pcs->SesId,
pcs->DBId,
pszTableName,
NULL,
0,
0,
&tableid);
_JumpIfError(hr, error, "JetOpenTable");
fOpen = TRUE;
// Step through the RowId index for this table.
CSASSERT(IsValidJetTableId(tableid));
hr = _dbgJetSetCurrentIndex2(
pcs->SesId,
tableid,
pdbaux->pszRowIdIndex,
JET_bitMoveFirst);
_JumpIfError(hr, error, "JetSetCurrentIndex2");
if (NULL != pdbaux->pdtIssuerNameId)
{
cb = sizeof(IssuerNameId);
hr = _RetrieveColumn(
pcs,
tableid,
pdbaux->pdtIssuerNameId->dbcolumnid,
pdbaux->pdtIssuerNameId->dbcoltyp,
&cb,
(BYTE *) &IssuerNameId);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
fZeroIssuerNameId = TRUE;
}
else
{
// swallow error if empty database
_PrintIfErrorStr2(
hr,
"_RetrieveColumn",
pdbaux->pdtIssuerNameId->pwszPropName,
myJetHResult(JET_errNoCurrentRecord));
}
}
pdtPublicKeyLength = dbFindColumn(adt, szPUBLICKEYLENGTH);
if (NULL != pdtPublicKeyLength)
{
pdtPublicKey = dbFindColumn(adt, szPUBLICKEY);
pdtPublicKeyAlgorithm = dbFindColumn(adt, szPUBLICKEYALGORITHM);
pdtPublicKeyParameters = dbFindColumn(adt, szPUBLICKEYPARAMS);
if (NULL == pdtPublicKey ||
NULL == pdtPublicKeyAlgorithm ||
NULL == pdtPublicKeyParameters)
{
pdtPublicKeyLength = NULL;
}
else
{
hr = _RetrieveColumn(
pcs,
tableid,
pdtPublicKeyLength->dbcolumnid,
pdtPublicKeyLength->dbcoltyp,
&cb,
NULL);
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
pdtPublicKeyLength = NULL;
}
}
}
pdtCallerName = dbFindColumn(adt, szCALLERNAME);
if (NULL != pdtCallerName)
{
pdtRequesterName = dbFindColumn(adt, szREQUESTERNAME);
if (NULL == pdtRequesterName)
{
pdtCallerName = NULL;
}
else
{
// Update all rows only if the first row's CallerName is empty
// and the first row's RequesterName is NOT empty.
hr = _RetrieveColumn(
pcs,
tableid,
pdtCallerName->dbcolumnid,
pdtCallerName->dbcoltyp,
&cb,
NULL);
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
pdtCallerName = NULL;
}
else
{
hr = _RetrieveColumn(
pcs,
tableid,
pdtRequesterName->dbcolumnid,
pdtRequesterName->dbcoltyp,
&cb,
NULL);
if (S_OK != hr)
{
pdtCallerName = NULL;
}
}
}
}
if (NULL != pdtPublicKeyLength ||
NULL != pdtCallerName ||
m_fFoundOldColumns ||
fZeroIssuerNameId)
{
DBGPRINT((DBG_SS_CERTDB, "Updating %hs table.\n", pdbaux->pszTable));
while (TRUE)
{
// Fetch RowId from the table.
cb = sizeof(pcs->RowId);
hr = _RetrieveColumn(
pcs,
tableid,
pdbaux->pdtRowId->dbcolumnid,
pdbaux->pdtRowId->dbcoltyp,
&cb,
(BYTE *) &RowId);
if (S_OK != hr)
{
if (myJetHResult(JET_errNoCurrentRecord) == hr)
{
hr = S_OK; // Table is empty
break;
}
_JumpError(hr, error, "_RetrieveColumn");
}
hr = _dbgJetBeginTransaction(pcs->SesId);
_JumpIfError(hr, error, "JetBeginTransaction");
fTransacted = TRUE;
// Transact each row.
//
// If fZeroIssuerNameId, set EMPTY IssuerNameId columns to zero.
//
// if the first row's public key length column was empty
// Read the public key column, compute the size and store it
//
// if the first row's CallerName was empty
// Copy RequesterName to CallerName
//
// if m_fFoundOldColumns
// For each text column, do the following:
// Retrieve old string from the old column,
// Convert to Unicode (if old column was Ansi),
// Write the Unicode string to the new column,
// Set the old column to NULL.
hr = _dbgJetPrepareUpdate(
pcs->SesId,
tableid,
JET_prepReplace);
_JumpIfError(hr, error, "JetPrepareUpdate");
if (fZeroIssuerNameId)
{
cb = sizeof(IssuerNameId);
hr = _RetrieveColumn(
pcs,
tableid,
pdbaux->pdtIssuerNameId->dbcolumnid,
pdbaux->pdtIssuerNameId->dbcoltyp,
&cb,
(BYTE *) &IssuerNameId);
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_JumpIfError(hr, error, "_RetrieveColumn");
}
else
{
// Only set EMPTY columns!
IssuerNameId = 0;
hr = _SetColumn(
pcs->SesId,
tableid,
pdbaux->pdtIssuerNameId->dbcolumnid,
sizeof(IssuerNameId),
(BYTE const *) &IssuerNameId);
_JumpIfError(hr, error, "_SetColumn");
}
}
// Convert old columns first.
if (m_fFoundOldColumns)
{
for (pdt = adt; NULL != pdt->pwszPropName; pdt++)
{
if (DBTF_OLDCOLUMNID & pdt->dwFlags)
{
hr = _ConvertColumnData(
pcs,
tableid,
RowId,
pdt,
pdbaux,
&pbBuf,
&cbBuf);
_JumpIfErrorStr(
hr,
error,
"_ConvertColumnData",
pdt->pwszPropName);
}
}
}
// Now compute new columns.
if (NULL != pdtPublicKeyLength)
{
hr = _AddKeyLengthColumn(
pcs,
tableid,
RowId,
pdtPublicKey,
pdtPublicKeyAlgorithm,
pdtPublicKeyParameters,
pdtPublicKeyLength,
pdbaux,
&pbBuf,
&cbBuf);
_JumpIfError(hr, error, "_AddKeyLengthColumn");
}
if (NULL != pdtCallerName)
{
hr = _AddCallerName(
pcs,
tableid,
RowId,
pdtCallerName,
pdtRequesterName,
pdbaux,
&pbBuf,
&cbBuf);
_JumpIfError(hr, error, "_AddCallerName");
}
// Done with this row.
hr = _dbgJetUpdate(pcs->SesId, tableid, NULL, 0, NULL);
_JumpIfError(hr, error, "JetUpdate");
hr = _dbgJetCommitTransaction(pcs->SesId, 0);
_JumpIfError(hr, error, "JetCommitTransaction");
fTransacted = FALSE;
hr = _dbgJetMove(pcs->SesId, tableid, JET_MoveNext, 0);
if ((HRESULT) JET_errNoCurrentRecord == hr)
{
hr = S_OK;
break;
}
}
}
if (m_fFoundOldColumns)
{
hr = _dbgJetBeginTransaction(pcs->SesId);
_JumpIfError(hr, error, "JetBeginTransaction");
fTransacted = TRUE;
for (pdt = adt; NULL != pdt->pwszPropName; pdt++)
{
char const *pszFieldName;
if (0 == (DBTF_OLDCOLUMNID & pdt->dwFlags))
{
continue;
}
pszFieldName = &pdt->pszFieldName[1];
if (DBTF_COLUMNRENAMED & pdt->dwFlags)
{
pszFieldName += strlen(pszFieldName) + 1;
}
DBGPRINT((
DBG_SS_CERTDB,
"Deleting column %hs.%hs\n",
pdbaux->pszTable,
pszFieldName));
hr = _dbgJetDeleteColumn(pcs->SesId, tableid, pszFieldName);
_PrintIfError(hr, "JetDeleteColumn");
if (JET_errColumnInUse == hr)
{
hr = S_OK; // we'll delete the column next time we restart
}
_JumpIfError(hr, error, "JetDeleteColumn");
}
hr = _dbgJetCommitTransaction(pcs->SesId, 0);
_JumpIfError(hr, error, "JetCommitTransaction");
fTransacted = FALSE;
}
hr = S_OK;
error:
if (NULL != pbBuf)
{
LocalFree(pbBuf);
}
if (fTransacted)
{
hr2 = _Rollback(pcs);
_PrintIfError(hr2, "_Rollback");
if (S_OK == hr)
{
hr = hr2;
}
}
if (fOpen)
{
hr2 = _dbgJetCloseTable(pcs->SesId, tableid);
_PrintIfError(hr2, "JetCloseTable");
if (S_OK == hr)
{
hr = hr2;
}
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::_SetColumn(
IN JET_SESID SesId,
IN JET_TABLEID tableid,
IN JET_COLUMNID columnid,
IN DWORD cbProp,
OPTIONAL IN BYTE const *pbProp)
{
HRESULT hr;
CSASSERT(IsValidJetTableId(tableid));
hr = _dbgJetSetColumn(SesId, tableid, columnid, pbProp, cbProp, 0, NULL);
if ((HRESULT) JET_wrnColumnMaxTruncated == hr)
{
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
}
_JumpIfError(hr, error, "JetSetColumn");
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::SetAttribute(
IN CERTSESSION *pcs,
IN WCHAR const *pwszAttributeName,
IN DWORD cbValue,
IN BYTE const *pbValue) // OPTIONAL
{
return(_SetIndirect(
pcs,
&pcs->aTable[CSTI_ATTRIBUTE],
pwszAttributeName,
NULL,
cbValue,
pbValue));
}
HRESULT
CCertDB::GetAttribute(
IN CERTSESSION *pcs,
IN WCHAR const *pwszAttributeName,
IN OUT DWORD *pcbValue,
OUT BYTE *pbValue) // OPTIONAL
{
return(_GetIndirect(
pcs,
&pcs->aTable[CSTI_ATTRIBUTE],
pwszAttributeName,
NULL,
pcbValue,
pbValue));
}
HRESULT
CCertDB::SetExtension(
IN CERTSESSION *pcs,
IN WCHAR const *pwszExtensionName,
IN DWORD dwExtFlags,
IN DWORD cbValue,
IN BYTE const *pbValue) // OPTIONAL
{
return(_SetIndirect(
pcs,
&pcs->aTable[CSTI_EXTENSION],
pwszExtensionName,
&dwExtFlags,
cbValue,
pbValue));
}
HRESULT
CCertDB::GetExtension(
IN CERTSESSION *pcs,
IN WCHAR const *pwszExtensionName,
OUT DWORD *pdwExtFlags,
IN OUT DWORD *pcbValue,
OUT BYTE *pbValue) // OPTIONAL
{
return(_GetIndirect(
pcs,
&pcs->aTable[CSTI_EXTENSION],
pwszExtensionName,
pdwExtFlags,
pcbValue,
pbValue));
}
HRESULT
CCertDB::_JetSeekFromRestriction(
IN CERTVIEWRESTRICTION const *pcvr,
IN DWORD dwPosition,
OUT DBSEEKDATA *pSeekData)
{
HRESULT hr;
BOOL fAscend;
DBSEEKDATA SeekFirst; // seek to first element matching restriction
DBSEEKDATA SeekLast; // seek to last element matching restriction
DBSEEKDATA SeekIndexFirst; // seek to first index element
DBSEEKDATA SeekIndexLast; // seek to last index element
DBSEEKDATA *pSeek;
BOOL fValid;
// SeekLast.SeekFlags: where to seek to retrieve end-of-range key
// SeekLast.grbitSeekRange: where to set the cursor initially: move or seek
// SeekLast.grbitRange: other flags to be ingested while setting range:
// (bitRange UpperLimit, Inclusive)
#if DBG_CERTSRV
DumpRestriction(DBG_SS_CERTDBI, 0, pcvr);
#endif
fAscend = (CVR_SORT_DESCEND != pcvr->SortOrder);
CSASSERT(
CVR_SORT_NONE == pcvr->SortOrder ||
CVR_SORT_ASCEND == pcvr->SortOrder ||
CVR_SORT_DESCEND == pcvr->SortOrder);
ZeroMemory(&SeekFirst, sizeof(SeekFirst));
ZeroMemory(&SeekLast, sizeof(SeekLast));
ZeroMemory(&SeekIndexFirst, sizeof(SeekIndexFirst));
ZeroMemory(&SeekIndexLast, sizeof(SeekIndexLast));
switch (CVR_SEEK_MASK & pcvr->SeekOperator)
{
case CVR_SEEK_EQ:
if (fAscend)
{
SeekFirst.SeekFlags = CST_SEEKUSECURRENT |
CST_SEEKNOTMOVE |
CST_SEEKINDEXRANGE;
SeekFirst.grbitSeekRange = JET_bitSeekEQ;
SeekFirst.grbitInitial = JET_bitSeekEQ;
SeekFirst.grbitRange = JET_bitRangeUpperLimit |
JET_bitRangeInclusive;
SeekLast.SeekFlags = CST_SEEKINDEXRANGE;
SeekLast.grbitSeekRange = JET_bitSeekGT;
SeekLast.grbitInitial = JET_MovePrevious;
SeekLast.grbitRange = JET_bitRangeUpperLimit;
}
else
{
SeekFirst.SeekFlags = CST_SEEKNOTMOVE | CST_SEEKINDEXRANGE;
SeekFirst.grbitSeekRange = JET_bitSeekEQ;
SeekFirst.grbitInitial = JET_bitSeekGT;
SeekFirst.grbitRange = JET_bitRangeInclusive;
SeekLast.SeekFlags = CST_SEEKINDEXRANGE;
SeekLast.grbitSeekRange = JET_bitSeekEQ;
SeekLast.grbitInitial = JET_MovePrevious;
SeekLast.grbitRange = JET_bitRangeInclusive;
}
break;
case CVR_SEEK_LT:
if (fAscend)
{
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
SeekFirst.grbitSeekRange = JET_bitSeekGE;
SeekFirst.grbitInitial = JET_MoveFirst;
SeekFirst.grbitRange = JET_bitRangeUpperLimit;
SeekLast.SeekFlags = CST_SEEKINDEXRANGE;
SeekLast.grbitSeekRange = JET_bitSeekGE;
SeekLast.grbitInitial = JET_MovePrevious;
SeekLast.grbitRange = JET_bitRangeUpperLimit;
}
else
{
SeekFirst.SeekFlags = CST_SEEKNOTMOVE;
SeekFirst.grbitInitial = JET_bitSeekGE;
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
SeekLast.grbitInitial = JET_MoveFirst;
SeekIndexFirst.SeekFlags = CST_SEEKUSECURRENT;
SeekIndexFirst.grbitInitial = JET_MoveLast;
}
break;
case CVR_SEEK_LE:
if (fAscend)
{
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
SeekFirst.grbitSeekRange = JET_bitSeekGT;
SeekFirst.grbitInitial = JET_MoveFirst;
SeekFirst.grbitRange = JET_bitRangeUpperLimit;
SeekLast.SeekFlags = CST_SEEKINDEXRANGE; // !CST_SEEKUSECURRENT
SeekLast.grbitSeekRange = JET_bitSeekGT;
SeekLast.grbitInitial = JET_MovePrevious;
SeekLast.grbitRange = JET_bitRangeUpperLimit;
}
else
{
SeekFirst.SeekFlags = CST_SEEKNOTMOVE;
SeekFirst.grbitInitial = JET_bitSeekGT;
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
SeekLast.grbitInitial = JET_MoveFirst;
SeekIndexFirst.SeekFlags = CST_SEEKUSECURRENT;
SeekIndexFirst.grbitInitial = JET_MoveLast;
}
break;
case CVR_SEEK_GE:
if (fAscend)
{
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKNOTMOVE;
SeekFirst.grbitInitial = JET_bitSeekGE;
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
SeekLast.grbitInitial = JET_MoveLast;
}
else
{
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
SeekFirst.grbitSeekRange = JET_bitSeekLT;
SeekFirst.grbitInitial = JET_MoveLast;
// Implied: SeekFirst.grbitRange = JET_bitRangeLowerLimit;
SeekLast.SeekFlags = CST_SEEKNOTMOVE;
SeekLast.grbitInitial = JET_bitSeekLT;
SeekIndexLast.SeekFlags = CST_SEEKUSECURRENT;
SeekIndexLast.grbitInitial = JET_MoveFirst;
}
break;
case CVR_SEEK_GT:
if (fAscend)
{
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKNOTMOVE;
SeekFirst.grbitInitial = JET_bitSeekGT;
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
SeekLast.grbitInitial = JET_MoveLast;
}
else
{
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
SeekFirst.grbitSeekRange = JET_bitSeekLE;
SeekFirst.grbitInitial = JET_MoveLast;
// Implied: SeekFirst.grbitRange = JET_bitRangeLowerLimit;
SeekLast.SeekFlags = CST_SEEKNOTMOVE;
SeekLast.grbitInitial = JET_bitSeekLE;
SeekIndexLast.SeekFlags = CST_SEEKUSECURRENT;
SeekIndexLast.grbitInitial = JET_MoveFirst;
}
break;
case CVR_SEEK_NONE:
if (fAscend)
{
SeekFirst.SeekFlags = CST_SEEKUSECURRENT;
SeekFirst.grbitInitial = JET_MoveFirst;
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
SeekLast.grbitInitial = JET_MoveLast;
}
else
{
SeekFirst.SeekFlags = CST_SEEKUSECURRENT;
SeekFirst.grbitInitial = JET_MoveLast;
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
SeekLast.grbitInitial = JET_MoveFirst;
}
break;
default:
CSASSERT(!"bad pcvr->SeekOperator"); // shouldn't get this far
hr = E_INVALIDARG;
_JumpError(hr, error, "Seek value");
}
fValid = TRUE;
switch (dwPosition)
{
case SEEKPOS_FIRST:
pSeek = &SeekFirst;
break;
case SEEKPOS_LAST:
pSeek = &SeekLast;
break;
case SEEKPOS_INDEXFIRST:
pSeek = &SeekIndexFirst;
fValid = 0 != pSeek->SeekFlags;
break;
case SEEKPOS_INDEXLAST:
pSeek = &SeekIndexLast;
fValid = 0 != pSeek->SeekFlags;
break;
default:
CSASSERT(!"bad dwPosition"); // shouldn't get this far
hr = E_INVALIDARG;
_JumpError(hr, error, "dwPosition value");
}
if (!fValid)
{
// For this SeekOperator, if seeking to the first or last matching
// restriction failed, there's no point in seeking to the index end.
hr = CERTSRV_E_PROPERTY_EMPTY;
_JumpError2(hr, error, "pSeek->SeekFlags", hr);
}
*pSeekData = *pSeek; // structure copy
if (fAscend)
{
pSeekData->SeekFlags |= CST_SEEKASCEND;
}
hr = S_OK;
DBGPRINT((
DBG_SS_CERTDBI,
"_JetSeekFromRestriction: SeekFlags=%ws, grbitStart=%ws\n",
wszCSTFlags(pSeekData->SeekFlags),
(CST_SEEKNOTMOVE & pSeekData->SeekFlags)?
wszSeekgrbit(pSeekData->grbitInitial) :
wszMovecrow(pSeekData->grbitInitial)));
if (CST_SEEKINDEXRANGE & pSeekData->SeekFlags)
{
DBGPRINT((
DBG_SS_CERTDBI,
"_JetSeekFromRestriction: grbitSeekRange=%ws, grbitRange=%ws\n",
wszSeekgrbit(pSeekData->grbitSeekRange),
wszSetIndexRangegrbit(pSeekData->grbitRange)));
}
error:
return(hr);
}
HRESULT
CCertDB::_OpenTable(
IN CERTSESSION *pcs,
IN DBAUXDATA const *pdbaux,
IN CERTVIEWRESTRICTION const *pcvr,
IN OUT CERTSESSIONTABLE *pTable)
{
HRESULT hr;
DBTABLE const *pdt;
BOOL fOpened = FALSE;
hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
_JumpIfError(hr, error, "_MapPropIdIndex");
if (NULL == pdt->pszIndexName)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "Column not indexed");
}
if (!IsValidJetTableId(pTable->TableId))
{
CSASSERTTHREAD(pcs);
hr = _dbgJetOpenTable(
pcs->SesId,
pcs->DBId,
pdbaux->pszTable,
NULL,
0,
0,
&pTable->TableId);
_JumpIfError(hr, error, "JetOpenTable");
fOpened = TRUE;
// Find RowId and/or Named column.
// It's more efficient to pass NULL for primary index name.
CSASSERTTHREAD(pcs);
hr = _dbgJetSetCurrentIndex2(
pcs->SesId,
pTable->TableId,
(DBTF_INDEXPRIMARY & pdt->dwFlags)?
NULL : pdt->pszIndexName,
JET_bitMoveFirst);
_JumpIfError(hr, error, "JetSetCurrentIndex2");
DBGPRINT((
DBG_SS_CERTDBI,
"_OpenTable Table=%hs, Index=%hs\n",
pdbaux->pszTable,
pdt->pszIndexName));
}
hr = _SeekTable(
pcs,
pTable->TableId,
pcvr,
pdt,
SEEKPOS_FIRST,
&pTable->TableFlags
DBGPARM(pdbaux));
_JumpIfError2(hr, error, "_SeekTable", S_FALSE);
error:
if (S_OK != hr && S_FALSE != hr && fOpened)
{
if (IsValidJetTableId(pTable->TableId))
{
HRESULT hr2;
CSASSERTTHREAD(pcs);
hr2 = _dbgJetCloseTable(pcs->SesId, pTable->TableId);
_PrintIfError(hr2, "JetCloseTable");
}
ZeroMemory(pTable, sizeof(*pTable));
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::_SetIndirect(
IN CERTSESSION *pcs,
IN OUT CERTSESSIONTABLE *pTable,
IN WCHAR const *pwszNameValue,
OPTIONAL IN DWORD const *pdwExtFlags,
IN DWORD cbValue,
OPTIONAL IN BYTE const *pbValue)
{
HRESULT hr;
DBAUXDATA const *pdbaux;
BOOL fExisting = FALSE;
BOOL fDelete;
CERTVIEWRESTRICTION cvr;
if (NULL == pcs || NULL == pwszNameValue)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
fDelete = NULL == pbValue;
if (NULL == pdwExtFlags)
{
pdbaux = &g_dbauxAttributes;
cvr.ColumnIndex = DTI_ATTRIBUTETABLE | DTA_ATTRIBUTENAME;
}
else
{
if (0 != *pdwExtFlags)
{
fDelete = FALSE;
}
pdbaux = &g_dbauxExtensions;
cvr.ColumnIndex = DTI_EXTENSIONTABLE | DTE_EXTENSIONNAME;
}
DBGPRINT((
DBG_SS_CERTDBI,
"IN: _SetIndirect(%hs.%ws) cb = %x%ws\n",
pdbaux->pszTable,
pwszNameValue,
cbValue,
fDelete? L" DELETE" : L""));
cvr.SeekOperator = CVR_SEEK_EQ;
cvr.SortOrder = CVR_SORT_NONE;
cvr.cbValue = wcslen(pwszNameValue) * sizeof(WCHAR);
cvr.pbValue = (BYTE *) pwszNameValue;
hr = _OpenTable(pcs, pdbaux, &cvr, pTable);
if (S_FALSE != hr)
{
_JumpIfError(hr, error, "_OpenTable");
fExisting = TRUE;
}
_PrintIfError2(hr, "_OpenTable", S_FALSE);
if (fDelete)
{
if (fExisting)
{
CSASSERTTHREAD(pcs);
hr = _dbgJetDelete(pcs->SesId, pTable->TableId);
_JumpIfError(hr, error, "JetDelete");
}
}
else
{
CSASSERTTHREAD(pcs);
hr = _dbgJetPrepareUpdate(
pcs->SesId,
pTable->TableId,
!fExisting? JET_prepInsert : JET_prepReplace);
_JumpIfError(hr, error, "JetPrepareUpdate");
if (!fExisting)
{
// No existing row -- insert a new one:
// Set RowId
hr = _SetColumn(
pcs->SesId,
pTable->TableId,
pdbaux->pdtRowId->dbcolumnid,
sizeof(pcs->RowId),
(BYTE const *) &pcs->RowId);
_JumpIfError(hr, error, "_SetColumn");
// Set row's name column
hr = _SetColumn(
pcs->SesId,
pTable->TableId,
pdbaux->pdtName->dbcolumnid,
wcslen(pwszNameValue)*sizeof(WCHAR), //cch,
(BYTE const *) pwszNameValue /*szTmp*/);
_JumpIfError(hr, error, "_SetColumn");
}
if (NULL != pdwExtFlags)
{
// Set or update flags
hr = _SetColumn(
pcs->SesId,
pTable->TableId,
pdbaux->pdtFlags->dbcolumnid,
sizeof(*pdwExtFlags),
(BYTE const *) pdwExtFlags);
_JumpIfError(hr, error, "_SetColumn");
}
// Set or update value
hr = _SetColumn(
pcs->SesId,
pTable->TableId,
pdbaux->pdtValue->dbcolumnid,
cbValue,
pbValue);
_JumpIfError(hr, error, "_SetColumn");
CSASSERTTHREAD(pcs);
hr = _dbgJetUpdate(pcs->SesId, pTable->TableId, NULL, 0, NULL);
_JumpIfError(hr, error, "JetUpdate");
}
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_GetIndirect(
IN CERTSESSION *pcs,
IN OUT CERTSESSIONTABLE *pTable,
IN WCHAR const *pwszNameValue,
OPTIONAL OUT DWORD *pdwExtFlags,
IN OUT DWORD *pcbValue,
OPTIONAL OUT BYTE *pbValue)
{
HRESULT hr;
DBAUXDATA const *pdbaux;
CERTSESSIONTABLE Table;
CERTVIEWRESTRICTION cvr;
if (NULL == pcs || NULL == pwszNameValue || NULL == pcbValue)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
if (NULL == pdwExtFlags)
{
pdbaux = &g_dbauxAttributes;
cvr.ColumnIndex = DTI_ATTRIBUTETABLE | DTA_ATTRIBUTENAME;
}
else
{
pdbaux = &g_dbauxExtensions;
cvr.ColumnIndex = DTI_EXTENSIONTABLE | DTE_EXTENSIONNAME;
}
DBGPRINT((
DBG_SS_CERTDBI,
"IN: _GetIndirect(%hs.%ws) cb = %x\n",
pdbaux->pszTable,
pwszNameValue,
*pcbValue));
cvr.SeekOperator = CVR_SEEK_EQ;
cvr.SortOrder = CVR_SORT_NONE;
cvr.cbValue = wcslen(pwszNameValue) * sizeof(WCHAR);
cvr.pbValue = (BYTE *) pwszNameValue;
hr = _OpenTable(pcs, pdbaux, &cvr, pTable);
if (S_FALSE == hr)
{
hr = CERTSRV_E_PROPERTY_EMPTY;
}
_JumpIfError2(hr, error, "_OpenTable", CERTSRV_E_PROPERTY_EMPTY);
if (NULL != pdwExtFlags)
{
DWORD cb;
// Get flags column
cb = sizeof(*pdwExtFlags);
hr = _RetrieveColumn(
pcs,
pTable->TableId,
pdbaux->pdtFlags->dbcolumnid,
pdbaux->pdtFlags->dbcoltyp,
&cb,
(BYTE *) pdwExtFlags);
_JumpIfError(hr, error, "_RetrieveColumn");
DBGPRINT((
DBG_SS_CERTDBI,
"_GetIndirect(%hs): Flags = %x\n",
pdbaux->pszTable,
*pdwExtFlags));
}
// Get value column
hr = _RetrieveColumn(
pcs,
pTable->TableId,
pdbaux->pdtValue->dbcolumnid,
pdbaux->pdtValue->dbcoltyp,
pcbValue,
pbValue);
if (CERTSRV_E_PROPERTY_EMPTY == hr && NULL != pdwExtFlags)
{
// return zero length property value and S_OK, so the caller can see
// the extension flags.
*pcbValue = 0;
hr = S_OK;
}
_JumpIfError(hr, error, "_RetrieveColumn");
DBGPRINT((
DBG_SS_CERTDBI,
"OUT: _GetIndirect(%hs.%ws) cb = %x\n",
pdbaux->pszTable,
pwszNameValue,
*pcbValue));
error:
return(myJetHResult(hr));
}
#define CB_FETCHDELTA 256
// Fetch a column. Loop if we have to grow the buffer.
HRESULT
CCertDB::_RetrieveColumnBuffer(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN JET_COLUMNID columnid,
IN JET_COLTYP coltyp,
OUT DWORD *pcbProp,
IN OUT BYTE **ppbBuf,
IN OUT DWORD *pcbBuf)
{
HRESULT hr;
BYTE *pbBuf = *ppbBuf;
DWORD cbBuf = *pcbBuf;
DWORD cb;
cb = cbBuf;
while (TRUE)
{
if (NULL == pbBuf)
{
// If cbBuf == 0, allocate CB_FETCHDELTA bytes.
// Otherwise, allocate column size *plus* CB_FETCHDELTA bytes.
// Ensures we make no more than two calls to _RetrieveColumn.
cb += CB_FETCHDELTA;
pbBuf = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == pbBuf)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
DBGPRINT((
DBG_SS_CERTDB,
"Grow buffer: %x --> %x\n", cbBuf, cb));
cbBuf = cb;
}
cb = cbBuf;
hr = _RetrieveColumn(
pcs,
tableid,
columnid,
coltyp,
&cb,
pbBuf);
if (S_OK == hr)
{
*pcbProp = cb;
break; // data fit in the buffer
}
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
{
_JumpError2(hr, error, "_RetrieveColumn", CERTSRV_E_PROPERTY_EMPTY);
}
// Data won't fit. Grow the buffer.
CSASSERT(NULL != pbBuf);
LocalFree(pbBuf);
pbBuf = NULL;
}
CSASSERT(S_OK == hr);
error:
*ppbBuf = pbBuf;
*pcbBuf = cbBuf;
return(hr);
}
HRESULT
CCertDB::_RetrieveColumn(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN JET_COLUMNID columnid,
IN JET_COLTYP coltyp,
IN OUT DWORD *pcbProp,
OPTIONAL OUT BYTE *pbProp)
{
HRESULT hr;
DWORD cbActual;
DWORD cbTotal;
CSASSERT(IsValidJetTableId(tableid));
hr = _dbgJetRetrieveColumn(
pcs->SesId,
tableid,
columnid,
NULL,
0,
&cbActual,
JET_bitRetrieveCopy,
NULL);
if ((HRESULT) JET_wrnColumnNull == hr)
{
// Routine GetProperty call:
// _JumpIfError(hr, error, "JetRetrieveColumn: Property EMPTY");
hr = CERTSRV_E_PROPERTY_EMPTY;
goto error;
}
if ((HRESULT) JET_wrnBufferTruncated != hr)
{
_JumpIfError2(hr, error, "JetRetrieveColumn", JET_errNoCurrentRecord);
}
if (cbActual == 0)
{
hr = CERTSRV_E_PROPERTY_EMPTY;
_JumpError(hr, error, "JetRetrieveColumn: cbActual=0: Property EMPTY");
}
cbTotal = cbActual;
if (ISTEXTCOLTYP(coltyp))
{
DBGPRINT((DBG_SS_CERTDBI, "Size of text %d\n", cbActual));
cbTotal += sizeof(WCHAR);
}
if (NULL == pbProp || cbTotal > *pcbProp)
{
*pcbProp = cbTotal;
hr = S_OK;
if (NULL != pbProp)
{
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
//_PrintError(hr, "output buffer too small");
}
goto error;
}
hr = _dbgJetRetrieveColumn(
pcs->SesId,
tableid,
columnid,
pbProp,
cbActual,
&cbActual,
JET_bitRetrieveCopy,
NULL);
_JumpIfError(hr, error, "JetRetrieveColumn");
*pcbProp = cbActual;
if (ISTEXTCOLTYP(coltyp))
{
*(WCHAR *) &pbProp[cbActual] = L'\0';
}
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_CreateIndex(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN CHAR const *pszIndexName,
IN CHAR const *pchKey,
IN DWORD cbKey,
IN DWORD flags)
{
HRESULT hr;
CSASSERT(IsValidJetTableId(tableid));
hr = _dbgJetCreateIndex(
pcs->SesId,
tableid,
pszIndexName,
flags,
pchKey,
cbKey,
0); // lDensity %, for splits (use default of 80%)
_JumpIfError3(
hr,
error,
"JetCreateIndex",
(HRESULT) JET_errIndexDuplicate,
(HRESULT) JET_errIndexHasPrimary);
DBGPRINT((
DBG_SS_CERTDBI,
"CreateIndex: %x:%hs idx=%hs len=%x flags=%x\n",
tableid,
pszIndexName,
pchKey,
cbKey,
flags));
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_AddColumn(
IN CERTSESSION *pcs,
IN JET_TABLEID tableid,
IN DBTABLE const *pdt)
{
HRESULT hr;
JET_COLUMNDEF columndef;
JET_COLUMNID columnid;
CSASSERT(IsValidJetTableId(tableid));
ZeroMemory(&columndef, sizeof(columndef));
columndef.cbStruct = sizeof(columndef);
columndef.cp = 1200; // unicode (1200) instead of Ascii (1252)
columndef.langid = 0x409;
columndef.wCountry = 1;
columndef.coltyp = pdt->dbcoltyp;
columndef.cbMax = pdt->dbcolumnMax;
columndef.grbit = pdt->dbgrbit;
DBGPRINT((
DBG_SS_CERTDBI,
"AddColumn: %x:%hs coltyp=%x cbMax=%x grbit=%x\n",
tableid,
pdt->pszFieldName,
pdt->dbcoltyp,
pdt->dbcolumnMax,
pdt->dbgrbit));
hr = _dbgJetAddColumn(
pcs->SesId,
tableid,
pdt->pszFieldName,
&columndef,
NULL,
0,
&columnid);
CSASSERT(JET_wrnColumnMaxTruncated != hr);
_JumpIfErrorStr3(
hr,
error,
"JetAddColumn",
pdt->pwszPropName,
(HRESULT) JET_errColumnDuplicate,
(HRESULT) JET_errColumnRedundant);
error:
return(myJetHResult(hr));
}
HRESULT
CCertDB::_CreateTable(
IN DWORD CreateFlags, // CF_*
IN CERTSESSION *pcs,
IN DBCREATETABLE const *pct)
{
HRESULT hr;
JET_TABLEID tableid;
BOOL fTableOpen;
DWORD dwLength;
CHAR achCol[MAX_PATH];
DBTABLE const *pdt;
DBGPRINT((
DBG_SS_CERTDBI,
"_CreateTable(%x, %hs)\n",
CreateFlags,
pct->pszTableName));
fTableOpen = FALSE;
if (CF_MISSINGTABLES & CreateFlags)
{
hr = _dbgJetCreateTable(
pcs->SesId,
pcs->DBId,
pct->pszTableName,
4,
0,
&tableid);
if ((HRESULT) JET_errTableDuplicate != hr)
{
_JumpIfError(hr, error, "JetCreateTable");
if (!(CF_DATABASE & CreateFlags))
{
DBGPRINT((
DBG_SS_CERTDB,
"Created Missing Table: %hs:%x\n",
pct->pszTableName,
tableid));
}
hr = _dbgJetCloseTable(pcs->SesId, tableid);
_JumpIfError(hr, error, "JetCloseTable");
}
}
hr = _dbgJetOpenTable(
pcs->SesId,
pcs->DBId,
pct->pszTableName,
NULL, // pvParameters
0, // cbParameters
JET_bitTableDenyRead, // grbit
&tableid);
_JumpIfError(hr, error, "JetOpenTable");
fTableOpen = TRUE;
CSASSERT(IsValidJetTableId(tableid));
DBGPRINT((DBG_SS_CERTDBI, "OpenTable: %hs: %x\n", pct->pszTableName, tableid));
if (NULL != pct->pdt)
{
HRESULT hrDuplicate;
HRESULT hrRedundant;
HRESULT hrHasPrimary;
if ((CF_DATABASE | CF_MISSINGTABLES | CF_MISSINGCOLUMNS) & CreateFlags)
{
hrDuplicate = myJetHResult(JET_errColumnDuplicate);
hrRedundant = myJetHResult(JET_errColumnRedundant);
for (pdt = pct->pdt; NULL != pdt->pwszPropName; pdt++)
{
hr = _AddColumn(pcs, tableid, pdt);
if (hrDuplicate == hr || hrRedundant == hr)
{
_PrintError2(hr, "_AddColumn", hr);
hr = S_OK;
}
else
if (S_OK == hr && !(CF_DATABASE & CreateFlags))
{
m_fAddedNewColumns = TRUE;
DBGPRINT((
DBG_SS_CERTDB,
"Added Missing Column: %hs.%hs\n",
pct->pszTableName,
pdt->pszFieldName));
}
_JumpIfErrorStr(hr, error, "_AddColumn", pdt->pwszPropName);
}
}
if ((CF_DATABASE | CF_MISSINGTABLES | CF_MISSINGCOLUMNS | CF_MISSINGINDEXES) & CreateFlags)
{
hrDuplicate = myJetHResult(JET_errIndexDuplicate);
hrHasPrimary = myJetHResult(JET_errIndexHasPrimary);
for (pdt = pct->pdt; NULL != pdt->pwszPropName; pdt++)
{
if (NULL != pdt->pszIndexName)
{
DWORD dwCreateIndexFlags = 0;
char *psz = achCol;
if (DBTF_INDEXPRIMARY & pdt->dwFlags)
{
dwCreateIndexFlags |= JET_bitIndexPrimary;
}
if (DBTF_INDEXUNIQUE & pdt->dwFlags)
{
dwCreateIndexFlags |= JET_bitIndexUnique;
}
if (DBTF_INDEXIGNORENULL & pdt->dwFlags)
{
dwCreateIndexFlags |= JET_bitIndexIgnoreNull;
}
if (DBTF_INDEXREQUESTID & pdt->dwFlags)
{
psz += sprintf(psz, "+%hs", szREQUESTID) + 1;
}
psz += sprintf(psz, "+%hs", pdt->pszFieldName) + 1;
*psz++ = '\0'; // double terminate
if (ISTEXTCOLTYP(pdt->dbcoltyp))
{
// if text field, include 2-byte langid
*(WORD UNALIGNED *) psz = (WORD) 0x409;
psz += sizeof(WORD);
*psz++ = '\0'; // double terminate
*psz++ = '\0'; // double terminate
}
hr = _CreateIndex(
pcs,
tableid,
pdt->pszIndexName,
achCol,
SAFE_SUBTRACT_POINTERS(psz, achCol),
dwCreateIndexFlags);
if (hrDuplicate == hr ||
(hrHasPrimary == hr &&
(DBTF_INDEXPRIMARY & pdt->dwFlags)))
{
_PrintError2(hr, "_CreateIndex", hr);
hr = S_OK;
}
else
if (S_OK == hr && !(CF_DATABASE & CreateFlags))
{
DBGPRINT((
DBG_SS_CERTDB,
"Added Missing Index: %hs.%hs\n",
pct->pszTableName,
pdt->pszIndexName));
if (chTEXTPREFIX == *pdt->pszIndexName ||
(DBTF_INDEXRENAMED & pdt->dwFlags))
{
char const *pszIndexName = &pdt->pszIndexName[1];
CSASSERTTHREAD(pcs);
if (DBTF_INDEXRENAMED & pdt->dwFlags)
{
pszIndexName += strlen(pszIndexName) + 1;
}
hr = _dbgJetDeleteIndex(
pcs->SesId,
tableid,
pszIndexName);
_PrintIfError2(hr, "JetDeleteIndex", hr);
if (S_OK == hr)
{
DBGPRINT((
DBG_SS_CERTDB,
"Deleted index %hs.%hs\n",
pct->pszTableName,
pszIndexName));
}
hr = S_OK;
}
}
_JumpIfError(hr, error, "_CreateIndex");
}
}
}
}
error:
if (fTableOpen)
{
HRESULT hr2;
hr2 = _dbgJetCloseTable(pcs->SesId, tableid);
if (S_OK == hr)
{
hr = hr2;
_JumpIfError(hr, error, "JetCloseTable");
}
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::_Create(
IN DWORD CreateFlags, // CF_*
IN CHAR const *pszDataBaseName)
{
HRESULT hr;
DBCREATETABLE const *pct;
CERTSESSION *pcs = NULL;
DBGPRINT((
DBG_SS_CERTDBI,
"_Create(%x, %hs)\n",
CreateFlags,
pszDataBaseName));
hr = _AllocateSession(&pcs);
_JumpIfError(hr, error, "_AllocateSession");
if (CF_DATABASE & CreateFlags)
{
hr = _dbgJetCreateDatabase(
pcs->SesId,
pszDataBaseName,
NULL,
&pcs->DBId,
0);
_JumpIfError(hr, error, "JetCreateDatabase");
hr = _dbgJetCloseDatabase(pcs->SesId, pcs->DBId, 0);
_JumpIfError(hr, error, "JetCloseDatabase");
}
hr = _dbgJetOpenDatabase(
pcs->SesId,
pszDataBaseName,
NULL,
&pcs->DBId,
JET_bitDbExclusive);
_JumpIfError(hr, error, "JetOpenDatabase");
hr = _dbgJetBeginTransaction(pcs->SesId);
_JumpIfError(hr, error, "JetBeginTransaction");
for (pct = g_actDataBase; NULL != pct->pszTableName; pct++)
{
hr = _CreateTable(CreateFlags, pcs, pct);
_JumpIfError(hr, error, "_CreateTable");
}
hr = _dbgJetCommitTransaction(pcs->SesId, 0);
_JumpIfError(hr, error, "JetCommitTransaction");
hr = _dbgJetCloseDatabase(pcs->SesId, pcs->DBId, 0);
_JumpIfError(hr, error, "JetCloseDatabase");
error:
if (NULL != pcs)
{
ReleaseSession(pcs);
}
return(myJetHResult(hr));
}
HRESULT
CCertDB::_DupString(
OPTIONAL IN WCHAR const *pwszPrefix,
IN WCHAR const *pwszIn,
OUT WCHAR **ppwszOut)
{
DWORD cbPrefix;
DWORD cb;
HRESULT hr;
cbPrefix = 0;
if (NULL != pwszPrefix)
{
cbPrefix = wcslen(pwszPrefix) * sizeof(WCHAR);
}
cb = (wcslen(pwszIn) + 1) * sizeof(WCHAR);
*ppwszOut = (WCHAR *) CoTaskMemAlloc(cbPrefix + cb);
if (NULL == *ppwszOut)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "CoTaskMemAlloc");
}
if (NULL != pwszPrefix)
{
CopyMemory(*ppwszOut, pwszPrefix, cbPrefix);
}
CopyMemory((BYTE *) *ppwszOut + cbPrefix, pwszIn, cb);
hr = S_OK;
error:
return(hr);
}