windows-nt/Source/XPSP1/NT/windows/appcompat/sdbapi/dbaccessplus.c
2020-09-26 16:20:57 +08:00

1277 lines
34 KiB
C

/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
dbaccessplus.c
Abstract:
This module implements APIs to access the shim database.
Author:
clupu created sometime in 2001
Revision History:
several people contributed (vadimb, dmunsil, ...)
--*/
#include "sdbp.h"
//
// This file is not included for KERNEL_MODE
//
//
// SdbInitDatabase is not used in Kernel mode. SdbInitDatabaseInMemory is used instead
//
HSDB
SdbInitDatabase(
IN DWORD dwFlags, // flags that tell how the database should be
// initialized.
IN LPCTSTR pszDatabasePath // the OPTIONAL full path to the database to be used.
)
/*++
Return: A handle to the database.
Desc: This is the first API someone needs to call to initiate comunication
with the database. Should be paired with a call to SdbReleaseDatabase
when finished.
HID_DATABASE_FULLPATH indicates that pszDatabasePath points to the full path of the
main database, when this flag is not present and pszDatabasePath
is not NULL we treat it as the directory where sysmain.sdb and
systest.sdb are to be found
HID_DOS_PATHS indicates the format of the pszDatabasePath: when this flag is
present, we treat it as being in dos c:\blah\blah format, when
it's not present - we treat pszDatabasePath as being in nt format
e.g. "\SystemRoot\Apppatch"
HID_NO_DATABASE indicates that no database will be open at this time
(pszDatabasePath is simply ignored, along with all
the other flags)
In addition to the flags above you can specify the type of the database that needs to be
opened via the SDB_DATABASE_MAIN_* flags such as:
SDB_DATABASE_MAIN_SHIM - sysmain.sdb
SDB_DATABASE_MAIN_MSI - msimain.sdb
SDB_DATABASE_MAIN_DRIVERS - drvmain.sdb
This feature is not present on downlevel platforms.
When any of the database type flags are provided, pszDatabasePath should be set to NULL
--*/
{
TCHAR wszWinDir[MAX_PATH] = TEXT("");
TCHAR wszShimDB[MAX_PATH] = TEXT("");
BOOL bReturn = FALSE;
PSDBCONTEXT pContext;
DWORD dwFlagOpen = 0;
//
// Allocate the HSDB handle.
//
pContext = (PSDBCONTEXT)SdbAlloc(sizeof(SDBCONTEXT));
if (pContext == NULL) {
DBGPRINT((sdlError, "SdbInitDatabase", "Failed to allocate %d bytes for HSDB\n",
sizeof(SDBCONTEXT)));
return NULL;
}
//
// See if we need to open db...
//
if (dwFlags & HID_NO_DATABASE) {
DBGPRINT((sdlInfo, "SdbInitDatabase", "No database is open\n"));
goto InitDone;
}
//
// Determine which flag to use with the OPEN call
//
dwFlagOpen = (dwFlags & HID_DOS_PATHS) ? DOS_PATH : NT_PATH;
//
// Open the main database and do this under a try/except so we don't screw
// our caller if the database is corrupt.
//
__try {
if (dwFlags & HID_DATABASE_FULLPATH) {
// we better have the ptr
if (pszDatabasePath == NULL) {
DBGPRINT((sdlError, "SdbInitDatabase",
"Database not specified with the database path flag\n"));
goto errHandle;
}
_tcscpy(wszShimDB, pszDatabasePath);
} else {
//
// we do not have a database path
// see if we have a database type to open as a "main" db
//
#ifndef WIN32A_MODE
//
// This code works only on UNICODE
//
if (dwFlags & HID_DATABASE_TYPE_MASK) {
DWORD dwDatabaseType = dwFlags;
DWORD dwLen;
dwLen = SdbpGetStandardDatabasePath(dwDatabaseType,
dwFlags,
wszShimDB,
CHARCOUNT(wszShimDB));
if (dwLen > CHARCOUNT(wszShimDB)) {
DBGPRINT((sdlError,
"SdbInitDatabase",
"Cannot get standard database path\n"));
goto errHandle;
}
} else
#endif // WIN32A_MODE
{
if (pszDatabasePath != NULL) {
int nLen;
_tcscpy(wszShimDB, pszDatabasePath);
nLen = _tcslen(wszShimDB);
if (nLen > 0 && TEXT('\\') == wszShimDB[nLen-1]) {
wszShimDB[nLen-1] = TEXT('\0');
}
} else { // standard database path
if (dwFlags & HID_DOS_PATHS) {
SdbpGetAppPatchDir(wszShimDB);
} else {
_tcscpy(wszShimDB, TEXT("\\SystemRoot\\AppPatch"));
}
}
_tcscat(wszShimDB, TEXT("\\sysmain.sdb"));
}
}
pContext->pdbMain = SdbOpenDatabase(wszShimDB, dwFlagOpen);
} __except(SHIM_EXCEPT_HANDLER) {
pContext->pdbMain = NULL;
}
if (pContext->pdbMain == NULL) {
DBGPRINT((sdlError, "SdbInitDatabase", "Unable to open main database sysmain.sdb.\n"));
goto errHandle;
}
if (dwFlags & HID_DATABASE_FULLPATH) {
// we are done, no test db
goto InitDone;
}
//
// Now try to open the systest.sdb if it exists.
//
__try {
if (NULL != pszDatabasePath) {
int nLen;
_tcscpy(wszShimDB, pszDatabasePath);
nLen = _tcslen(wszShimDB);
if (nLen > 0 && TEXT('\\') == wszShimDB[nLen-1]) {
wszShimDB[nLen-1] = TEXT('\0');
}
} else { // standard database path
if (dwFlags & HID_DOS_PATHS) {
SdbpGetAppPatchDir(wszShimDB);
} else {
_tcscpy(wszShimDB, TEXT("\\SystemRoot\\AppPatch"));
}
}
_tcscat(wszShimDB, TEXT("\\systest.sdb"));
pContext->pdbTest = SdbOpenDatabase(wszShimDB, dwFlagOpen);
} __except(SHIM_EXCEPT_HANDLER) {
pContext->pdbTest = NULL;
}
if (pContext->pdbTest == NULL) {
DBGPRINT((sdlInfo, "SdbInitDatabase", "No systest.sdb found.\n"));
}
InitDone:
//
// Initialize new members (local db support)
//
if (pContext->pdbMain) {
pContext->rgSDB[0].pdb = pContext->pdbMain;
pContext->rgSDB[0].dwFlags = SDBENTRY_VALID_ENTRY|SDBENTRY_VALID_GUID;
RtlCopyMemory(&pContext->rgSDB[0].guidDB, &GUID_SYSMAIN_SDB, sizeof(GUID));
SDBCUSTOM_SET_MASK(pContext, SDB_MASK_TO_INDEX(PDB_MAIN));
}
if (pContext->pdbTest) {
pContext->rgSDB[1].pdb = pContext->pdbTest;
pContext->rgSDB[1].dwFlags = SDBENTRY_VALID_ENTRY|SDBENTRY_VALID_GUID;
RtlCopyMemory(&pContext->rgSDB[1].guidDB, &GUID_SYSTEST_SDB, sizeof(GUID));
SDBCUSTOM_SET_MASK(pContext, SDB_MASK_TO_INDEX(PDB_TEST));
}
//
// Initialize architecture
//
pContext->dwRuntimePlatform = SdbpGetProcessorArchitecture();
//
// Initialize OS SKU and SP
//
SdbpGetOSSKU(&pContext->dwOSSKU, &pContext->dwSPMask);
#ifndef WIN32A_MODE
//
// Finally, initialize the pipe
//
pContext->hPipe = SdbpOpenDebugPipe();
#endif // WIN32A_MODE
return (HSDB)pContext;
errHandle:
//
// Cleanup on failure.
//
if (pContext != NULL) {
if (pContext->pdbMain != NULL) {
SdbCloseDatabaseRead(pContext->pdbMain);
}
if (pContext->pdbTest != NULL) {
SdbCloseDatabaseRead(pContext->pdbTest);
}
SdbFree(pContext);
}
return NULL;
}
BOOL
SdbpOpenAndMapFile(
IN LPCTSTR szPath, // Filename
OUT PIMAGEFILEDATA pImageData, // pointer to the structure to be filled
IN PATH_TYPE ePathType // path type, only DOS_PATH is supported on win32
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Opens a file and maps it into memory.
--*/
{
HANDLE hFile;
DWORD dwFlags = 0;
if (pImageData->dwFlags & IMAGEFILEDATA_PBASEVALID) {
//
// special case, only headers are valid in our assumption
//
return TRUE;
}
if (pImageData->dwFlags & IMAGEFILEDATA_HANDLEVALID) {
hFile = pImageData->hFile;
dwFlags |= IMAGEFILEDATA_NOFILECLOSE;
} else {
hFile = SdbpOpenFile(szPath, ePathType);
}
if (hFile == INVALID_HANDLE_VALUE) {
return FALSE;
}
if (!SdbpMapFile(hFile, pImageData)) {
if (!(dwFlags & IMAGEFILEDATA_NOFILECLOSE)) {
SdbpCloseFile(hFile);
}
return FALSE;
}
pImageData->dwFlags = dwFlags;
return TRUE;
}
BOOL
SdbpUnmapAndCloseFile(
IN PIMAGEFILEDATA pImageData
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
HANDLE hFile;
BOOL bSuccess;
if (pImageData->dwFlags & IMAGEFILEDATA_PBASEVALID) { // externally supplied pointer
RtlZeroMemory(pImageData, sizeof(*pImageData));
return TRUE;
}
hFile = pImageData->hFile;
bSuccess = SdbpUnmapFile(pImageData);
if (hFile != INVALID_HANDLE_VALUE) {
if (pImageData->dwFlags & IMAGEFILEDATA_NOFILECLOSE) {
pImageData->hFile = INVALID_HANDLE_VALUE;
} else {
SdbpCloseFile(hFile);
}
}
return bSuccess;
}
BOOL
SdbpCleanupLocalDatabaseSupport(
IN HSDB hSDB
)
{
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
DWORD dwIndex;
DWORD dwMask;
//
// Ee start with entry 2 -- to include local sdbs
//
if (pSdbContext->dwDatabaseMask & SDB_CUSTOM_MASK) {
for (dwIndex = 3; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
dwMask = 1 << dwIndex;
if (pSdbContext->dwDatabaseMask & dwMask) {
SdbCloseLocalDatabaseEx(hSDB, NULL, dwIndex);
}
}
}
//
// Always check for entry 2 (local sdb)
//
if (pSdbContext->pdbLocal != NULL) {
SdbCloseLocalDatabaseEx(hSDB, NULL, SDB_MASK_TO_INDEX(PDB_LOCAL));
}
return TRUE;
}
BOOL
SdbpIsLocalTempPDB(
IN HSDB hSDB,
IN PDB pdb
)
{
PSDBENTRY pEntry = SDBGETLOCALENTRY(hSDB);
if (pEntry->dwFlags & SDBENTRY_VALID_ENTRY) {
return pdb == pEntry->pdb;
}
return FALSE;
}
BOOL
SdbpIsMainPDB(
IN HSDB hSDB,
IN PDB pdb
)
{
DWORD dwIndex;
if (!SdbpFindLocalDatabaseByPDB(hSDB, pdb, FALSE, &dwIndex)) {
return FALSE;
}
return (dwIndex == SDB_MASK_TO_INDEX(PDB_MAIN) || dwIndex == SDB_MASK_TO_INDEX(PDB_TEST));
}
BOOL
SdbpFindLocalDatabaseByPDB(
IN HSDB hSDB,
IN PDB pdb,
IN BOOL bExcludeLocalDB, // exclude local db entry?
OUT LPDWORD pdwIndex
)
{
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
DWORD dwIndex;
PSDBENTRY pEntry;
BOOL bSuccess = FALSE;
for (dwIndex = 0; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
if (bExcludeLocalDB && dwIndex == SDB_MASK_TO_INDEX(PDB_LOCAL)) {
continue;
}
if (!SDBCUSTOM_CHECK_INDEX(hSDB, dwIndex)) {
continue;
}
pEntry = &pSdbContext->rgSDB[dwIndex];
if ((pEntry->dwFlags & SDBENTRY_VALID_ENTRY) && (pdb == pEntry->pdb)) {
bSuccess = TRUE;
break;
}
}
if (bSuccess && pdwIndex != NULL) {
*pdwIndex = dwIndex;
}
return bSuccess;
}
BOOL
SdbpFindLocalDatabaseByGUID(
IN HSDB hSDB,
IN GUID* pGuidDB,
IN BOOL bExcludeLocalDB,
OUT LPDWORD pdwIndex // this index (if valid) will work as an initial point for comparison
)
{
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
PSDBENTRY pEntry;
DWORD dwIndex;
for (dwIndex = 0; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
if (bExcludeLocalDB && dwIndex == SDB_MASK_TO_INDEX(PDB_LOCAL)) {
continue;
}
if (!SDBCUSTOM_CHECK_INDEX(hSDB, dwIndex)) {
continue;
}
pEntry = SDBGETENTRY(hSDB, dwIndex);
if (!(pEntry->dwFlags & SDBENTRY_VALID_GUID)) {
//
// if this happens to be a valid database -- get it's guid
//
if ((pEntry->dwFlags & SDBENTRY_VALID_ENTRY) && (pEntry->pdb != NULL)) {
//
// retrieve guid
//
GUID guidDB;
if (SdbGetDatabaseGUID(hSDB, pEntry->pdb, &guidDB)) {
pEntry->guidDB = guidDB;
pEntry->dwFlags |= SDBENTRY_VALID_GUID;
goto checkEntry;
}
}
continue;
}
checkEntry:
if (RtlEqualMemory(&pEntry->guidDB, pGuidDB, sizeof(GUID))) {
if (pdwIndex) {
*pdwIndex = dwIndex;
}
return TRUE;
}
}
return FALSE;
}
DWORD
SdbpFindFreeLocalEntry(
IN HSDB hSDB
)
{
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
DWORD dwIndex;
for (dwIndex = 3; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
if (SDBCUSTOM_CHECK_INDEX(hSDB, dwIndex)) {
continue;
}
if (!(pSdbContext->rgSDB[dwIndex].dwFlags & (SDBENTRY_VALID_ENTRY | SDBENTRY_VALID_GUID))) {
return dwIndex;
}
}
//
// We have no entry
//
return SDBENTRY_INVALID_INDEX;
}
/*++
returns SDBENTRY_INVALID_INDEX if none could be found
if success, returns an index where the local db entry was found
--*/
DWORD
SdbpRetainLocalDBEntry(
IN HSDB hSDB,
OUT PDB* ppPDB OPTIONAL // optional pointer to the pdb
)
{
DWORD dwIndex = SDBENTRY_INVALID_INDEX;
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
PSDBENTRY pEntry;
PSDBENTRY pEntryLocal = SDBGETLOCALENTRY(hSDB);
GUID guidDB;
if (pEntryLocal->pdb == NULL || !(pEntryLocal->dwFlags & SDBENTRY_VALID_ENTRY)) {
return SDBENTRY_INVALID_INDEX;
}
//
// Recycling could be done here so that we reuse custom db entries which
// may have been opened already (for instance set by __COMPAT_LAYER)
//
if (SdbGetDatabaseGUID(hSDB, pEntryLocal->pdb, &guidDB) &&
SdbpFindLocalDatabaseByGUID(hSDB, &guidDB, TRUE, &dwIndex) &&
dwIndex != SDBENTRY_INVALID_INDEX) {
//
// Close the local db
//
SdbCloseLocalDatabase(hSDB);
pEntry = SDBGETENTRY(hSDB, dwIndex);
pSdbContext->pdbLocal = pEntry->pdb;
if (ppPDB != NULL) {
*ppPDB = pEntry->pdb;
}
return dwIndex;
}
//
// An attempt to recycle has failed -- allocate new entry
//
dwIndex = SdbpFindFreeLocalEntry(hSDB);
if (dwIndex != SDBENTRY_INVALID_INDEX) {
//
// We have found an empty slot, relocate
//
pEntry = SDBGETENTRY(hSDB, dwIndex);
RtlCopyMemory(pEntry, pEntryLocal, sizeof(SDBENTRY));
RtlZeroMemory(pEntryLocal, sizeof(SDBENTRY));
SDBCUSTOM_SET_MASK(hSDB, dwIndex);
if (ppPDB != NULL) {
*ppPDB = pEntry->pdb;
}
//
// Note that pdbLocal is still valid, we never close this handle manually though
//
}
return dwIndex;
}
BOOL
SdbCloseLocalDatabaseEx(
IN HSDB hSDB,
IN PDB pdb,
IN DWORD dwIndex
)
{
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
PSDBENTRY pEntry;
DWORD dwMask;
if (pdb != NULL) {
if (!SdbpFindLocalDatabaseByPDB(hSDB, pdb, FALSE, &dwIndex)) {
return FALSE;
}
}
dwMask = 1 << dwIndex;
if (dwIndex >= ARRAYSIZE(pSdbContext->rgSDB) || !(pSdbContext->dwDatabaseMask & dwMask)) {
return FALSE;
}
pEntry = &pSdbContext->rgSDB[dwIndex];
if (pEntry->dwFlags & SDBENTRY_VALID_ENTRY) {
if (pEntry->pdb) {
SdbCloseDatabaseRead(pEntry->pdb);
}
}
RtlZeroMemory(pEntry, sizeof(*pEntry));
SDBCUSTOM_CLEAR_MASK(hSDB, dwIndex);
if (dwIndex == SDB_MASK_TO_INDEX(PDB_LOCAL)) {
pSdbContext->pdbLocal = NULL;
}
return TRUE;
}
BOOL
SdbOpenLocalDatabaseEx(
IN HSDB hSDB,
IN LPCVOID pDatabaseID,
IN DWORD dwFlags,
OUT PDB* pPDB OPTIONAL,
IN OUT LPDWORD pdwLocalDBMask OPTIONAL // local db mask for tagref
)
{
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
PDB pdb;
DWORD dwOpenFlags = DOS_PATH;
TCHAR szDatabasePath[MAX_PATH];
LPTSTR pszDatabasePath;
GUID guidDB;
GUID* pGuidDB;
DWORD dwDatabaseType = 0;
DWORD dwCount;
BOOL bSuccess = FALSE;
DWORD dwIndex;
PSDBENTRY pEntry;
if (!(SDBCUSTOM_FLAGS(dwFlags) & SDBCUSTOM_USE_INDEX)) {
//
// Find free local sdb entry
//
dwIndex = SdbpFindFreeLocalEntry(hSDB);
if (dwIndex == SDBENTRY_INVALID_INDEX) {
DBGPRINT((sdlError,
"SdbOpenLocalDatabaseEx",
"No more free entries in local db table\n"));
goto cleanup;
}
pEntry = &pSdbContext->rgSDB[dwIndex];
} else {
dwIndex = *pdwLocalDBMask;
if (dwIndex & TAGREF_STRIP_PDB) {
dwIndex = SDB_MASK_TO_INDEX(dwIndex);
}
if (dwIndex >= ARRAYSIZE(pSdbContext->rgSDB)) {
DBGPRINT((sdlError,
"SdbOpenLocalDatabaseEx",
"Bad index 0x%lx\n",
dwIndex));
goto cleanup;
}
if (dwIndex < 2) {
DBGPRINT((sdlWarning,
"SdbOpenLocalDatabaseEx",
"Unusual use of SdbOpenLocalDatabaseEx index 0x%lx\n",
dwIndex));
}
pEntry = &pSdbContext->rgSDB[dwIndex];
SdbCloseLocalDatabaseEx(hSDB, NULL, dwIndex);
}
switch (SDBCUSTOM_TYPE(dwFlags)) {
case SDBCUSTOM_PATH:
if (SDBCUSTOM_PATH_NT & SDBCUSTOM_FLAGS(dwFlags)) {
dwOpenFlags = NT_PATH;
}
pszDatabasePath = (LPTSTR)pDatabaseID;
pGuidDB = NULL;
break;
case SDBCUSTOM_GUID:
if (SDBCUSTOM_GUID_STRING & SDBCUSTOM_FLAGS(dwFlags)) {
if (!SdbGUIDFromString((LPCTSTR)pDatabaseID, &guidDB)) {
DBGPRINT((sdlError,
"SdbOpenLocalDatabaseEx",
"Cannot convert \"%s\" to guid\n",
(LPCTSTR)pDatabaseID));
goto cleanup;
}
pGuidDB = &guidDB;
} else {
pGuidDB = (GUID*)pDatabaseID;
}
dwCount = SdbResolveDatabase(pGuidDB,
&dwDatabaseType,
szDatabasePath,
CHARCOUNT(szDatabasePath));
if (dwCount == 0 || dwCount >= CHARCOUNT(szDatabasePath)) {
DBGPRINT((sdlError,
"SdbOpenLocalDatabaseEx",
"Cannot resolve database, the path length is 0x%lx\n",
dwCount));
goto cleanup;
}
pszDatabasePath = szDatabasePath;
break;
default:
DBGPRINT((sdlError, "SdbOpenLocalDatabaseEx", "Bad flags 0x%lx\n", dwFlags));
goto cleanup;
break;
}
pdb = SdbOpenDatabase(pszDatabasePath, dwOpenFlags);
if (pdb == NULL) {
//
// dbgprint not needed here
//
goto cleanup;
}
pSdbContext->rgSDB[dwIndex].pdb = pdb;
pSdbContext->rgSDB[dwIndex].dwFlags = SDBENTRY_VALID_ENTRY;
SDBCUSTOM_SET_MASK(pSdbContext, dwIndex);
if (pGuidDB != NULL) {
RtlCopyMemory(&pSdbContext->rgSDB[dwIndex].guidDB, pGuidDB, sizeof(GUID));
pSdbContext->rgSDB[dwIndex].dwFlags |= SDBENTRY_VALID_GUID;
} else {
RtlZeroMemory(&pSdbContext->rgSDB[dwIndex].guidDB, sizeof(GUID));
}
bSuccess = TRUE;
cleanup:
if (bSuccess) {
if (dwIndex == SDB_MASK_TO_INDEX(PDB_LOCAL)) {
pSdbContext->pdbLocal = pdb;
}
if (pdwLocalDBMask != NULL) {
*pdwLocalDBMask = SDB_INDEX_TO_MASK(dwIndex);
}
if (pPDB != NULL) {
*pPDB = pdb;
}
}
return bSuccess;
}
BOOL
SdbOpenLocalDatabase(
IN HSDB hSDB, // handle to the database channel
IN LPCTSTR pszLocalDatabase // full DOS path to the local database to open.
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Opens a local database.
--*/
{
DWORD dwIndex = PDB_LOCAL;
BOOL bSuccess;
bSuccess = SdbOpenLocalDatabaseEx(hSDB,
pszLocalDatabase,
(SDBCUSTOM_PATH_DOS | SDBCUSTOM_USE_INDEX),
NULL,
&dwIndex);
return bSuccess;
}
BOOL
SdbCloseLocalDatabase(
IN HSDB hSDB // handle to the database channel
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Closes the local database.
--*/
{
return SdbCloseLocalDatabaseEx(hSDB, NULL, SDB_MASK_TO_INDEX(PDB_LOCAL));
}
TAGREF
SdbGetItemFromItemRef(
IN HSDB hSDB, // handle to the database channel
IN TAGREF trItemRef, // TAGREF of a DLL_REF record
IN TAG tagItemKey, // key that has the name of the item (TAG_NAME)
IN TAG tagItemTAGID, // tag that points to the location of the desired item by it's tagid
IN TAG tagItem // what to look for under Library
)
/*++
Return: TAGREF of a DLL record that matches the DLL_REF.
Desc: Given a TAGREF that points to a *tag*_REF type tag, searches through
the various databases for the matching tag (generally located
under the LIBRARY tag in gpdbMain).
if bAllowNonMain is specified then the library section is looked up
in the same database where trItemRef was found. This is used with
MSI transforms - to locate and extract them from custom databases.
This flag IS NOT used for other components - such as patches and
shim dlls. This is ensured through the macros -
SdbGetShimFromShimRef(hSDB, trShimRef)
and
SdbGetPatchFromPatchRef(hSDB, trPatchRef)
Both of these macros call this function with bAllowNonMain set to FALSE
--*/
{
PSDBCONTEXT pDbContext = (PSDBCONTEXT)hSDB;
TAGID tiItemRef = TAGID_NULL;
PDB pdbItemRef = NULL;
TAGREF trReturn = TAGREF_NULL;
TAGID tiReturn = TAGID_NULL;
TAGID tiDatabase = TAGID_NULL;
TAGID tiLibrary = TAGID_NULL;
TAGID tiItemTagID = TAGID_NULL;
TAGID tiItemName;
LPTSTR szItemName = NULL;
try {
//
// Find first which database contains the reference TAGREF.
//
if (!SdbTagRefToTagID(pDbContext, trItemRef, &pdbItemRef, &tiItemRef)){
DBGPRINT((sdlError, "SdbGetItemFromItemRef", "Can't convert tag ref.\n"));
goto out;
}
//
// First check if there's a TAG_item_TAGID that tells us exactly
// where the item is within the current database.
//
tiItemTagID = SdbFindFirstTag(pdbItemRef, tiItemRef, tagItemTAGID);
if (tiItemTagID != TAGID_NULL) {
tiReturn = (TAGID)SdbReadDWORDTag(pdbItemRef, tiItemTagID, 0);
if (tiReturn != TAGID_NULL) {
goto out;
}
}
if (pdbItemRef == pDbContext->pdbMain) {
goto checkMainDatabase;
}
//
// Then check for the item in the LIBRARY section of the
// current database.
//
tiDatabase = SdbFindFirstTag(pdbItemRef, TAGID_ROOT, TAG_DATABASE);
if (!tiDatabase) {
DBGPRINT((sdlError,
"SdbGetItemFromItemRef",
"Can't find DATABASE tag in db.\n"));
goto checkMainDatabase;
}
tiLibrary = SdbFindFirstTag(pdbItemRef, tiDatabase, TAG_LIBRARY);
if (!tiLibrary) {
//
// This library doesn't have a LIBRARY section. That's ok, go check
// sysmain.sdb.
//
goto checkMainDatabase;
}
//
// We need to search by name.
//
tiItemName = SdbFindFirstTag(pdbItemRef, tiItemRef, tagItemKey);
if (!tiItemName) {
goto out;
}
szItemName = SdbGetStringTagPtr(pdbItemRef, tiItemName);
if (!szItemName) {
goto out;
}
tiReturn = SdbFindFirstNamedTag(pdbItemRef,
tiLibrary,
tagItem,
tagItemKey,
szItemName);
if (tiReturn != TAGID_NULL) {
goto out;
}
checkMainDatabase:
tiDatabase = SdbFindFirstTag(pDbContext->pdbMain, TAGID_ROOT, TAG_DATABASE);
if (!tiDatabase) {
DBGPRINT((sdlError,
"SdbGetItemFromItemRef",
"Can't find DATABASE tag in main db.\n"));
goto out;
}
tiLibrary = SdbFindFirstTag(pDbContext->pdbMain, tiDatabase, TAG_LIBRARY);
if (!tiLibrary) {
DBGPRINT((sdlError,
"SdbGetItemFromItemRef",
"Can't find LIBRARY tag in main db.\n"));
goto out;
}
//
// We need to search by name.
//
if (szItemName == NULL) {
tiItemName = SdbFindFirstTag(pdbItemRef, tiItemRef, tagItemKey);
if (!tiItemName) {
goto out;
}
szItemName = SdbGetStringTagPtr(pdbItemRef, tiItemName);
if (!szItemName) {
goto out;
}
}
tiReturn = SdbFindFirstNamedTag(pDbContext->pdbMain,
tiLibrary,
tagItem,
tagItemKey,
szItemName);
pdbItemRef = pDbContext->pdbMain;
} except (SHIM_EXCEPT_HANDLER) {
tiReturn = TAGID_NULL;
trReturn = TAGREF_NULL;
}
out:
if (tiReturn) {
assert(pdbItemRef != NULL);
if (!SdbTagIDToTagRef(pDbContext, pdbItemRef, tiReturn, &trReturn)) {
trReturn = TAGREF_NULL;
}
}
if (trReturn == TAGREF_NULL) {
DBGPRINT((sdlError,
"SdbGetItemFromItemRef",
"Can't find tag for tag ref 0x%x.\n", trItemRef));
}
return trReturn;
}
TAGID
SdbpGetLibraryFile(
IN PDB pdb, // handle to the database channel
IN LPCTSTR szDllName // the name of the DLL
)
/*++
Return: The TAGID of the DLL used by the specified shim.
Desc: This function gets the TAGID of the DLL with the specified name.
--*/
{
TAGID tiDatabase;
TAGID tiLibrary;
TAGID tiDll = TAG_NULL;
tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
if (!tiDatabase) {
DBGPRINT((sdlError, "SdbpGetLibraryFile", "Can't find DATABASE tag in main db.\n"));
goto out;
}
tiLibrary = SdbFindFirstTag(pdb, tiDatabase, TAG_LIBRARY);
if (!tiLibrary) {
DBGPRINT((sdlError, "SdbpGetLibraryFile", "Can't find LIBRARY tag in main db.\n"));
goto out;
}
tiDll = SdbFindFirstNamedTag(pdb, tiLibrary, TAG_FILE, TAG_NAME, szDllName);
if (!tiDll) {
DBGPRINT((sdlError,
"SdbpGetLibraryFile", "Can't find FILE \"%s\" in main db library.\n",
szDllName));
goto out;
}
out:
return tiDll;
}
BOOL
SdbGetDllPath(
IN HSDB hSDB, // handle to the database channel
IN TAGREF trShimRef, // SHIM_REF to use to search for the DLL
OUT LPTSTR pwszBuffer // Buffer to fill with the path to the DLL containing
// the specified shim.
)
/*++
Return: TRUE if the DLL was found, FALSE otherwise.
Desc: Hunts for the DLL file on disk, first in the same
directory as the EXE (if there was a local database opened), then
in the %windir%\AppPatch directory.
Always fills in a DOS_PATH type path (UNC or 'x:').
--*/
{
BOOL bReturn = FALSE;
HANDLE hFile = INVALID_HANDLE_VALUE;
PBYTE pBuffer = NULL;
DWORD dwSize;
TAGREF trShim;
TAGREF trDll;
TAGREF trDllBits;
TAGREF trName;
TCHAR szFile[2 * MAX_PATH];
TCHAR szName[MAX_PATH];
assert(pwszBuffer);
try {
//
// Initialize the return buffer.
//
pwszBuffer[0] = _T('\0');
SdbpGetAppPatchDir(szFile);
_tcscat(szFile, _T("\\"));
//
// Look for the SHIM record in the LIBRARY section.
//
trShim = SdbGetShimFromShimRef(hSDB, trShimRef);
if (trShim == TAGREF_NULL) {
//
// No SHIM in LIBRARY. Error out.
//
DBGPRINT((sdlError, "SdbGetDllPath", "No SHIM in LIBRARY.\n"));
goto out;
}
//
// Get the name of the file that contains this shim.
//
trName = SdbFindFirstTagRef(hSDB, trShim, TAG_DLLFILE);
if (trName == TAGREF_NULL) {
//
// Nope, and we need one. Error out.
//
DBGPRINT((sdlError, "SdbGetDllPath", "No DLLFILE for the SHIM in LIBRARY.\n"));
goto out;
}
if (!SdbReadStringTagRef(hSDB, trName, szName, MAX_PATH)) {
DBGPRINT((sdlError, "SdbGetDllPath", "Can't read DLL name.\n"));
goto out;
}
//
// Check if the file is already on the disk.
// Look in %windir%\AppPatch directory for the DLL.
//
_tcscat(szFile, szName);
_tcscpy(pwszBuffer, szFile);
DBGPRINT((sdlInfo, "SdbGetDllPath", "Opening file \"%s\".\n", szFile));
hFile = SdbpOpenFile(szFile, DOS_PATH);
if (hFile != INVALID_HANDLE_VALUE) {
bReturn = TRUE;
goto out;
}
out:
;
} except (SHIM_EXCEPT_HANDLER) {
bReturn = FALSE;
}
if (hFile != INVALID_HANDLE_VALUE) {
SdbpCloseFile(hFile);
}
if (pBuffer != NULL) {
SdbFree(pBuffer);
}
if (bReturn) {
DBGPRINT((sdlInfo, "SdbGetDllPath", "Using DLL \"%s\".\n", szFile));
}
return bReturn;
}
BOOL
SdbReadPatchBits(
IN HSDB hSDB, // handle to the database channel
IN TAGREF trPatchRef, // PATCH_REF to use to find the PATCH
OUT PVOID pBuffer, // buffer to fill with bits
OUT LPDWORD lpdwBufferSize // size of passed-in buffer
)
/*++
Return: Returns TRUE on success, FALSE on failure.
Desc: Looks for the patch, first on disk, then in the DB, and fills
pBuffer with the bits. If the size specified in lpdwBufferSize is
less than the size of the patch this function will return in
lpdwBufferSize the size required. In that case pBuffer is ignored
and can be NULL.
--*/
{
BOOL bReturn = FALSE;
TAGID tiPatchRef = TAGID_NULL;
PDB pdb = NULL;
LPTSTR szName = NULL;
TAGREF trPatch = TAGREF_NULL;
TAGREF trPatchBits = TAGREF_NULL;
TAGID tiName = TAGID_NULL;
DWORD dwSize;
try {
if (!SdbTagRefToTagID(hSDB, trPatchRef, &pdb, &tiPatchRef)) {
DBGPRINT((sdlError, "SdbReadPatchBits", "Can't convert tag ref.\n"));
goto out;
}
tiName = SdbFindFirstTag(pdb, tiPatchRef, TAG_NAME);
if (!tiName) {
DBGPRINT((sdlError, "SdbReadPatchBits", "Can't find the name tag.\n"));
goto out;
}
szName = SdbGetStringTagPtr(pdb, tiName);
if (!szName) {
DBGPRINT((sdlError, "SdbReadPatchBits", "Can't read the name of the patch.\n"));
goto out;
}
//
// Look in the main database for the patch bits.
//
trPatch = SdbGetPatchFromPatchRef(hSDB, trPatchRef);
if (!trPatch) {
DBGPRINT((sdlError, "SdbReadPatchBits", "Can't get the patch tag.\n"));
goto out;
}
trPatchBits = SdbFindFirstTagRef(hSDB, trPatch, TAG_PATCH_BITS);
if (!trPatchBits) {
DBGPRINT((sdlError, "SdbReadPatchBits", "Can't get the patch bits tag.\n"));
goto out;
}
dwSize = SdbpGetTagRefDataSize(hSDB, trPatchBits);
if (dwSize == 0) {
DBGPRINT((sdlError, "SdbReadPatchBits", "Corrupt database. Zero sized patch.\n"));
goto out;
}
//
// Check for buffer size.
//
if (dwSize > *lpdwBufferSize) {
*lpdwBufferSize = dwSize;
goto out;
}
//
// Read the bits if the buffer is big enough.
//
*lpdwBufferSize = dwSize;
if (!SdbpReadBinaryTagRef(hSDB, trPatchBits, pBuffer, dwSize)) {
DBGPRINT((sdlError, "SdbReadPatchBits", "Cannot get the patch bits.\n"));
goto out;
}
bReturn = TRUE;
} except (SHIM_EXCEPT_HANDLER) {
bReturn = FALSE;
}
out:
return bReturn;
}