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

1234 lines
30 KiB
C

/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
write.c
Abstract:
This module implements low level primitives that are win32 compatible.
Author:
dmunsil created sometime in 1999
Revision History:
--*/
#include "sdbp.h"
#define ALLOCATION_INCREMENT 65536 // 64K bytes
BOOL
SdbpWriteBufferedData(
PDB pdb,
DWORD dwOffset,
const PVOID pBuffer,
DWORD dwSize)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Appends the specified buffer to the mapped view of the db.
--*/
{
if (!pdb->bWrite) {
DBGPRINT((sdlError, "SdbpWriteBufferedData", "Invalid parameter.\n"));
return FALSE;
}
//
// Reallocate the buffer if necessary
//
if (dwOffset + dwSize > pdb->dwAllocatedSize) {
DWORD dwNewAllocation;
PVOID* pNewBase;
dwNewAllocation = dwOffset + dwSize + ALLOCATION_INCREMENT;
pNewBase = SdbAlloc(dwNewAllocation);
if (pNewBase == NULL) {
DBGPRINT((sdlError,
"SdbpWriteBufferedData",
"Failed to allocate %d bytes.\n",
dwNewAllocation));
return FALSE;
}
if (pdb->pBase) {
memcpy(pNewBase, pdb->pBase, pdb->dwAllocatedSize);
SdbFree(pdb->pBase);
}
pdb->pBase = pNewBase;
pdb->dwAllocatedSize = dwNewAllocation;
}
//
// Copy in the new bytes.
//
memcpy((PBYTE)pdb->pBase + dwOffset, pBuffer, dwSize);
//
// Adjust the size.
//
if (dwOffset + dwSize > pdb->dwSize) {
pdb->dwSize = dwOffset + dwSize;
}
return TRUE;
}
HANDLE
SdbpCreateFile(
IN LPCWSTR szPath, // the full path to the database file to be created
IN PATH_TYPE eType // DOS_PATH for the popular DOS paths or NT_PATH for
// nt internal paths.
)
/*++
Return: The handle to the created file or INVALID_HANDLE_VALUE if it fails.
Desc: Creates a file with the path specified.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING UnicodeString;
HANDLE hFile = INVALID_HANDLE_VALUE;
HRESULT status;
RTL_RELATIVE_NAME RelativeName;
RtlInitUnicodeString(&UnicodeString, szPath);
if (eType == DOS_PATH) {
if (!RtlDosPathNameToNtPathName_U(UnicodeString.Buffer,
&UnicodeString,
NULL,
&RelativeName)) {
DBGPRINT((sdlError,
"SdbpCreateFile",
"Failed to convert DOS path \"%s\"\n",
szPath));
return INVALID_HANDLE_VALUE;
}
}
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
status = NtCreateFile(&hFile,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OVERWRITE_IF,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (eType == DOS_PATH) {
RtlFreeUnicodeString(&UnicodeString);
}
if (!NT_SUCCESS(status)) {
DBGPRINT((sdlError,
"SdbpCreateFile",
"Failed to create the file \"%s\". Status 0x%x\n",
szPath,
status));
return INVALID_HANDLE_VALUE;
}
return hFile;
}
void
SdbpDeleteFile(
IN LPCWSTR szPath, // the full path to the database file to be deleted.
IN PATH_TYPE eType // DOS_PATH for the popular DOS paths or NT_PATH for
// nt internal paths.
)
/*++
Return: ?
Desc: ?.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
RTL_RELATIVE_NAME RelativeName;
NTSTATUS status;
RtlInitUnicodeString(&UnicodeString, szPath);
if (eType == DOS_PATH) {
if (!RtlDosPathNameToNtPathName_U(UnicodeString.Buffer,
&UnicodeString,
NULL,
&RelativeName)) {
DBGPRINT((sdlError,
"SdbpDeleteFile",
"Failed to convert DOS path \"%s\"\n",
szPath));
return;
}
}
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
status = NtDeleteFile(&ObjectAttributes);
if (DOS_PATH == eType) {
RtlFreeUnicodeString(&UnicodeString);
}
if (!NT_SUCCESS(status)) {
DBGPRINT((sdlError,
"SdbpDeleteFile",
"Failed to delete the file \"%s\". Status 0x%x\n",
szPath,
status));
}
}
PDB
SdbCreateDatabase(
IN LPCWSTR szPath,
IN PATH_TYPE eType
)
/*++
Return: A pointer to the created database.
Desc: Self explanatory.
--*/
{
HANDLE hFile;
DB_HEADER DBHeader;
PDB pdb;
SYSTEMTIME time;
hFile = SdbpCreateFile(szPath, eType);
if (hFile == INVALID_HANDLE_VALUE) {
DBGPRINT((sdlError, "SdbCreateDatabase", "Failed to create the database.\n"));
return NULL;
}
pdb = SdbAlloc(sizeof(DB));
if (pdb == NULL) {
DBGPRINT((sdlError,
"SdbCreateDatabase",
"Failed to allocate %d bytes.\n",
sizeof(DB)));
goto err1;
}
ZeroMemory(pdb, sizeof(DB));
pdb->hFile = hFile;
pdb->bWrite = TRUE;
//
// Create the initial header
//
DBHeader.dwMagic = SHIMDB_MAGIC;
DBHeader.dwMajorVersion = SHIMDB_MAJOR_VERSION;
SdbpGetCurrentTime(&time);
DBHeader.dwMinorVersion = time.wDay + time.wMonth * 100 + (time.wYear - 2000) * 10000;
if (!SdbpWriteBufferedData(pdb, 0, &DBHeader, sizeof(DB_HEADER))) {
DBGPRINT((sdlError,
"SdbCreateDatabase",
"Failed to write the header to disk.\n"));
goto err2;
}
return pdb;
err2:
SdbFree(pdb);
err1:
SdbpCloseFile(hFile);
return NULL;
}
//
// WRITE functions
//
TAGID
SdbBeginWriteListTag(
IN PDB pdb,
IN TAG tTag
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
TAGID tiReturn;
assert(pdb);
//
// The tagid is just the file offset to the tag
//
tiReturn = pdb->dwSize;
if (GETTAGTYPE(tTag) != TAG_TYPE_LIST) {
DBGPRINT((sdlError, "SdbBeginWriteListTag", "This is not a list tag.\n"));
return TAGID_NULL;
}
if (!SdbpWriteTagData(pdb, tTag, NULL, TAG_SIZE_UNFINISHED)) {
DBGPRINT((sdlError, "SdbBeginWriteListTag", "Failed to write the data.\n"));
return TAGID_NULL;
}
return tiReturn;
}
BOOL
SdbEndWriteListTag(
IN PDB pdb,
IN TAGID tiList
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
DWORD dwSize;
DWORD i;
assert(pdb);
if (GETTAGTYPE(SdbGetTagFromTagID(pdb, tiList)) != TAG_TYPE_LIST) {
DBGPRINT((sdlError, "SdbEndWriteListTag", "This is not a list tag.\n"));
return FALSE;
}
//
// The size of this tag is the offset from the beginning to the end of the
// file, minus the tag and size itself.
//
dwSize = pdb->dwSize - tiList - sizeof(TAG) - sizeof(DWORD);
if (!SdbpWriteBufferedData(pdb, tiList + sizeof(TAG), &dwSize, sizeof(DWORD))) {
DBGPRINT((sdlError, "SdbEndWriteListTag", "Failed to write the data.\n"));
return FALSE;
}
//
// Check if we need to add index entries
//
for (i = 0; i < pdb->dwIndexes; i++) {
//
// Is there an index of this type, that is currently active?
//
if (pdb->aIndexes[i].tWhich == SdbGetTagFromTagID(pdb, tiList) &&
pdb->aIndexes[i].bActive) {
//
// We have an index on this tag, check for a key.
//
TAGID tiKey;
INDEX_RECORD IndexRecord;
BOOL bWrite = TRUE; // this is the variable that determines
// whether we actually write an index entry,
// used for "uniqueKey" indexes
PINDEX_INFO pIndex = &pdb->aIndexes[i];
//
// Find the key value and fill out INDEX_RECORD structure.
//
tiKey = SdbFindFirstTag(pdb, tiList, pIndex->tKey);
//
// If we don't have a key, that's OK. This tag will get indexed with key 0
//
if (tiKey) {
IndexRecord.ullKey = SdbpTagToKey(pdb, tiKey);
} else {
IndexRecord.ullKey = (ULONGLONG)0;
}
IndexRecord.tiRef = tiList;
//
// If the index is of "UniqueKey" type we don't write anything at
// this time, we just collect the info and write it all out at the end.
//
if (pIndex->bUniqueKey) {
//
// Use the buffer
//
// has the last written key been the same as this one?
//
if (pIndex->ullLastKey == IndexRecord.ullKey) {
bWrite = FALSE;
} else {
//
// Actually write the key, store the buffer
//
pIndex->ullLastKey = IndexRecord.ullKey;
}
}
if (bWrite) {
//
// Check for walking off the end of the index
//
if (pIndex->dwIndexEntry == pIndex->dwIndexEnd) {
DBGPRINT((sdlError,
"SdbEndWriteListTag",
"Too many index entries for tag %04x, key %04x.\n",
pdb->aIndexes[i].tWhich,
pdb->aIndexes[i].tKey));
return FALSE;
}
//
// Stick in the new entry, and increment
//
SdbpWriteBufferedData(pdb,
pIndex->dwIndexEntry,
&IndexRecord,
sizeof(INDEX_RECORD));
pIndex->dwIndexEntry += sizeof(INDEX_RECORD);
}
}
}
return TRUE;
}
BOOL
SdbWriteNULLTag(
IN PDB pdb,
IN TAG tTag
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
assert(pdb);
if (GETTAGTYPE(tTag) != TAG_TYPE_NULL) {
return FALSE;
}
if (!SdbpWriteTagData(pdb, tTag, NULL, 0)) {
return FALSE;
}
return TRUE;
}
#define WRITETYPEDTAG(ttype, type) \
{ \
assert(pdb); \
\
if (GETTAGTYPE(tTag) != ttype) { \
return FALSE; \
} \
\
if (!SdbpWriteTagData(pdb, tTag, &xData, sizeof(type))) { \
return FALSE; \
} \
\
return TRUE; \
}
BOOL SdbWriteBYTETag(PDB pdb, TAG tTag, BYTE xData)
{
WRITETYPEDTAG(TAG_TYPE_BYTE, BYTE);
}
BOOL SdbWriteWORDTag(PDB pdb, TAG tTag, WORD xData)
{
WRITETYPEDTAG(TAG_TYPE_WORD, WORD);
}
BOOL SdbWriteDWORDTag(PDB pdb, TAG tTag, DWORD xData)
{
WRITETYPEDTAG(TAG_TYPE_DWORD, DWORD);
}
BOOL SdbWriteQWORDTag(PDB pdb, TAG tTag, ULONGLONG xData)
{
WRITETYPEDTAG(TAG_TYPE_QWORD, ULONGLONG);
}
BOOL
SdbWriteStringTag(
IN PDB pdb,
IN TAG tTag,
IN LPCWSTR pwszData
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
TAG_TYPE ttThis;
assert(pdb);
ttThis = GETTAGTYPE(tTag);
//
// It must be either a STRING type, in which case we
// write it directly, or a STRINGREF, in which case we
// put it in the string table and add a string table reference
// in place here.
//
if (ttThis == TAG_TYPE_STRINGREF) {
STRINGREF srThis;
srThis = SdbpAddStringToTable(pdb, pwszData);
if (srThis == STRINGREF_NULL) {
return FALSE;
}
return SdbWriteStringRefTag(pdb, tTag, srThis);
} else if (ttThis == TAG_TYPE_STRING) {
return SdbWriteStringTagDirect(pdb, tTag, pwszData);
}
return FALSE;
}
BOOL
SdbWriteBinaryTag(
IN PDB pdb,
IN TAG tTag,
IN PBYTE pBuffer,
IN DWORD dwSize
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
assert(pdb);
if (GETTAGTYPE(tTag) != TAG_TYPE_BINARY) {
return FALSE;
}
if (!SdbpWriteTagData(pdb, tTag, pBuffer, dwSize)) {
return FALSE;
}
return TRUE;
}
BOOL
SdbWriteBinaryTagFromFile(
IN PDB pdb,
IN TAG tTag,
IN LPCWSTR pwszPath
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
HANDLE hTempFile;
DWORD dwSize;
BOOL bSuccess = FALSE;
PBYTE pBuffer;
LARGE_INTEGER liOffset;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS status;
assert(pdb && pwszPath);
hTempFile = SdbpOpenFile(pwszPath, DOS_PATH);
if (hTempFile == INVALID_HANDLE_VALUE) {
return FALSE;
}
dwSize = SdbpGetFileSize(hTempFile);
pBuffer = SdbAlloc(dwSize);
if (pBuffer == NULL) {
bSuccess = FALSE;
goto err1;
}
liOffset.LowPart = 0;
liOffset.HighPart = 0;
status = NtReadFile(hTempFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
pBuffer,
dwSize,
&liOffset,
NULL);
if (!NT_SUCCESS(status)) {
DBGPRINT((sdlError,
"SdbWriteBinaryTagFromFile",
"Failed to read data. Status: 0x%x.\n",
status));
goto err2;
}
bSuccess = SdbWriteBinaryTag(pdb, tTag, pBuffer, dwSize);
err2:
SdbFree(pBuffer);
err1:
SdbpCloseFile(hTempFile);
return bSuccess;
}
BOOL
SdbpWriteTagData(
PDB pdb,
TAG tTag,
const PVOID pBuffer,
DWORD dwSize
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
BYTE bPadding = 0xDB;
assert(pdb);
//
// Write the tag.
//
if (!SdbpWriteBufferedData(pdb, pdb->dwSize, &tTag, sizeof(TAG))) {
return FALSE;
}
//
// Write the size.
//
if (GETTAGTYPE(tTag) >= TAG_TYPE_LIST) {
if (!SdbpWriteBufferedData(pdb, pdb->dwSize, &dwSize, sizeof(DWORD))) {
return FALSE;
}
}
//
// Write the data.
//
if (pBuffer) {
if (!SdbpWriteBufferedData(pdb, pdb->dwSize, pBuffer, dwSize)) {
return FALSE;
}
//
// Align the tag.
//
if (dwSize & 1) {
if (!SdbpWriteBufferedData(pdb, pdb->dwSize, &bPadding, 1)) {
DBGPRINT((sdlError, "SdbpWriteTagData", "Failed to write padding data 1 byte\n"));
return FALSE;
}
}
}
return TRUE;
}
BOOL
SdbWriteStringRefTag(
IN PDB pdb,
IN TAG tTag,
IN STRINGREF srData
)
{
assert(pdb);
if (GETTAGTYPE(tTag) != TAG_TYPE_STRINGREF) {
return FALSE;
}
if (!SdbpWriteTagData(pdb, tTag, &srData, sizeof(srData))) {
return FALSE;
}
return TRUE;
}
BOOL
SdbWriteStringTagDirect(
IN PDB pdb,
IN TAG tTag,
IN LPCWSTR pwszData
)
{
DWORD dwSize;
assert(pdb && pwszData);
dwSize = (wcslen(pwszData) + 1) * sizeof(WCHAR);
if (GETTAGTYPE(tTag) != TAG_TYPE_STRING) {
return FALSE;
}
if (!SdbpWriteTagData(pdb, tTag, (const PVOID)pwszData, dwSize)) {
return FALSE;
}
return TRUE;
}
void
SdbCloseDatabase(
IN PDB pdb // IN - DB to close
)
/*++
Params: described above.
Return: void.
Desc: Closes a database and frees all memory and file handles associated with it.
--*/
{
assert(pdb != NULL);
// copy the string table and indexes onto the end of the file
if (pdb->bWrite && pdb->pdbStringTable != NULL) {
TAGID tiString;
tiString = SdbFindFirstTag(pdb->pdbStringTable, TAGID_ROOT, TAG_STRINGTABLE_ITEM);
if (tiString != TAGID_NULL) {
TAGID tiTable;
tiTable = SdbBeginWriteListTag(pdb, TAG_STRINGTABLE);
while (tiString != TAGID_NULL) {
TCHAR* pszTemp;
pszTemp = SdbGetStringTagPtr(pdb->pdbStringTable, tiString);
if (pszTemp == NULL) {
DBGPRINT((sdlWarning,
"SdbCloseDatabase",
"Failed to read a string.\n"));
break;
}
if (!SdbWriteStringTagDirect(pdb, TAG_STRINGTABLE_ITEM, pszTemp)) {
DBGPRINT((sdlError,
"SdbCloseDatabase",
"Failed to write stringtable item\n"));
break;
}
tiString = SdbFindNextTag(pdb->pdbStringTable, TAGID_ROOT, tiString);
}
if (!SdbEndWriteListTag(pdb, tiTable)) {
DBGPRINT((sdlError,
"SdbCloseDatabase",
"Failed to write end list tag for the string table\n"));
goto err1;
}
}
}
//
// Now sort all the indexes if necessary.
//
if (pdb->bWrite) {
DWORD i;
for (i = 0; i < pdb->dwIndexes; ++i) {
if (!SdbpSortIndex(pdb, pdb->aIndexes[i].tiIndex)) {
DBGPRINT((sdlError,
"SdbCloseDatabase",
"Failed to sort index.\n"));
goto err1;
}
}
}
err1:
if (pdb->pdbStringTable != NULL) {
SdbCloseDatabase(pdb->pdbStringTable);
pdb->pdbStringTable = NULL;
//
// Delete the file
//
if (pdb->ustrTempStringtable.Buffer) {
SdbpDeleteFile(pdb->ustrTempStringtable.Buffer, DOS_PATH);
}
FREE_TEMP_STRINGTABLE(pdb);
}
//
// The string hash is used when writing to the database for the purpose of
// caching the string table.
//
if (pdb->pStringHash != NULL) {
HashFree(pdb->pStringHash);
pdb->pStringHash = NULL;
}
if (pdb->pBase != NULL) {
if (pdb->bWrite) {
LARGE_INTEGER liOffset;
IO_STATUS_BLOCK IoStatusBlock;
HRESULT status;
liOffset.LowPart = 0;
liOffset.HighPart = 0;
//
// Flush the buffer to disk.
//
status = NtWriteFile(pdb->hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
pdb->pBase,
pdb->dwSize,
&liOffset,
NULL);
if (!NT_SUCCESS(status)) {
DBGPRINT((sdlError, "SdbCloseDatabase", "Failed to write the sdb.\n"));
}
SdbFree(pdb->pBase);
pdb->pBase = NULL;
// BUGBUG: should we call SdbpUnmapAndCloseDB in this case ?
} else {
SdbpUnmapAndCloseDB(pdb);
}
}
if (pdb->hFile != INVALID_HANDLE_VALUE) {
SdbpCloseFile(pdb->hFile);
pdb->hFile = INVALID_HANDLE_VALUE;
}
SdbFree(pdb);
}
//
// INDEX functions (used during write)
//
BOOL
SdbDeclareIndex(
IN PDB pdb,
IN TAG tWhich,
IN TAG tKey,
IN DWORD dwEntries,
IN BOOL bUniqueKey,
OUT INDEXID* piiIndex
)
{
BOOL bReturn = FALSE;
DWORD dwSize = 0;
TAGID tiIndex = TAGID_NULL;
PVOID pFiller = NULL;
TAGID tiIndexBits = TAGID_NULL;
DWORD dwFlags = 0;
if (bUniqueKey) {
// this is a special unique-key index which we will write out
dwFlags |= SHIMDB_INDEX_UNIQUE_KEY;
}
if (GETTAGTYPE(tWhich) != TAG_TYPE_LIST) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Illegal to index non-LIST tag.\n"));
goto err1;
}
if (GETTAGTYPE(tKey) == TAG_TYPE_LIST) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Illegal to use LIST type as a key.\n"));
goto err1;
}
if (!pdb->bWritingIndexes) {
if (pdb->dwSize != sizeof(DB_HEADER)) {
DBGPRINT((sdlError,
"SdbDeclareIndex",
"Began declaring indexes after writing other data.\n"));
goto err1;
}
pdb->bWritingIndexes = TRUE;
pdb->tiIndexes = SdbBeginWriteListTag(pdb, TAG_INDEXES);
if (!pdb->tiIndexes) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Error beginning TAG_INDEXES.\n"));
goto err1;
}
}
if (pdb->dwIndexes == MAX_INDEXES) {
DBGPRINT((sdlError,
"SdbDeclareIndex",
"Hit limit of %d indexes. Increase MAX_INDEXES and recompile.\n",
MAX_INDEXES));
goto err1;
}
tiIndex = SdbBeginWriteListTag(pdb, TAG_INDEX);
if (!tiIndex) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Error beginning TAG_INDEX.\n"));
goto err1;
}
if (!SdbWriteWORDTag(pdb, TAG_INDEX_TAG, tWhich)) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Error writing TAG_INDEX_TAG.\n"));
goto err1;
}
if (!SdbWriteWORDTag(pdb, TAG_INDEX_KEY, tKey)) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Error writing TAG_INDEX_KEY.\n"));
goto err1;
}
if (dwFlags && !SdbWriteDWORDTag(pdb, TAG_INDEX_FLAGS, dwFlags)) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Error writing TAG_INDEX_FLAGS.\n"));
goto err1;
}
//
// allocate and write out space-filler garbage, which
// will be filled in with the real index later.
//
dwSize = dwEntries * sizeof(INDEX_RECORD);
pFiller = SdbAlloc(dwSize);
if (!pFiller) {
goto err1;
}
tiIndexBits = pdb->dwSize;
if (!SdbWriteBinaryTag(pdb, TAG_INDEX_BITS, pFiller, dwSize)) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Error writing TAG_INDEX_BITS.\n"));
goto err1;
}
SdbFree(pFiller);
pFiller = NULL;
if (!SdbEndWriteListTag(pdb, tiIndex)) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Error ending TAG_INDEX.\n"));
goto err1;
}
pdb->aIndexes[pdb->dwIndexes].tWhich = tWhich;
pdb->aIndexes[pdb->dwIndexes].tKey = tKey;
pdb->aIndexes[pdb->dwIndexes].tiIndex = tiIndexBits;
pdb->aIndexes[pdb->dwIndexes].dwIndexEntry = tiIndexBits + sizeof(TAG) + sizeof(DWORD);
pdb->aIndexes[pdb->dwIndexes].dwIndexEnd = pdb->aIndexes[pdb->dwIndexes].dwIndexEntry + dwSize;
pdb->aIndexes[pdb->dwIndexes].ullLastKey = 0;
pdb->aIndexes[pdb->dwIndexes].bUniqueKey = bUniqueKey;
*piiIndex = pdb->dwIndexes;
pdb->dwIndexes++;
bReturn = TRUE;
err1:
if (pFiller) {
SdbFree(pFiller);
pFiller = NULL;
}
return bReturn;
}
BOOL
SdbCommitIndexes(
IN PDB pdb
)
{
pdb->bWritingIndexes = FALSE;
if (!SdbEndWriteListTag(pdb, pdb->tiIndexes)) {
DBGPRINT((sdlError, "SdbDeclareIndex", "Error ending TAG_INDEXES.\n"));
return FALSE;
}
return TRUE;
}
BOOL
SdbStartIndexing(
IN PDB pdb,
IN INDEXID iiWhich
)
{
if (iiWhich >= pdb->dwIndexes) {
return FALSE;
}
pdb->aIndexes[iiWhich].bActive = TRUE;
return TRUE;
}
BOOL
SdbStopIndexing(
IN PDB pdb,
IN INDEXID iiWhich
)
{
if (iiWhich >= pdb->dwIndexes) {
return FALSE;
}
pdb->aIndexes[iiWhich].bActive = FALSE;
return TRUE;
}
int __cdecl
CompareIndexRecords(
const void* p1,
const void* p2
)
/*++
Params: BUGBUG: comments ?
Return: TRUE if successful, FALSE otherwise.
Desc: Callback used by qsort.
--*/
{
ULONGLONG ullKey1;
ULONGLONG ullKey2;
ullKey1 = ((INDEX_RECORD UNALIGNED*)p1)->ullKey;
ullKey2 = ((INDEX_RECORD UNALIGNED*)p2)->ullKey;
if (ullKey1 == ullKey2) {
TAGID ti1, ti2;
//
// Secondary sort on TAGID, so we'll always walk
// the exe records from the beginning to the end, and
// take advantage of cache read-ahead
//
ti1 = ((INDEX_RECORD UNALIGNED*)p1)->tiRef;
ti2 = ((INDEX_RECORD UNALIGNED*)p2)->tiRef;
if (ti1 == ti2) {
return 0;
} else if (ti1 < ti2) {
return -1;
} else {
return 1;
}
} else if (ullKey1 < ullKey2) {
return -1;
} else {
return 1;
}
}
BOOL
SdbpSortIndex(
PDB pdb,
TAGID tiIndexBits
)
/*++
Params: BUGBUG: comments ?
Return: TRUE if successful, FALSE otherwise.
Desc: Sorts an index.
--*/
{
INDEX_RECORD* pIndexRecords = NULL;
DWORD dwRecords = 0;
if (SdbGetTagFromTagID(pdb, tiIndexBits) != TAG_INDEX_BITS) {
DBGPRINT((sdlError, "SdbpSortIndex", "Not an index.\n"));
return FALSE;
}
pIndexRecords = SdbpGetMappedTagData(pdb, tiIndexBits);
if (pIndexRecords == NULL) {
DBGPRINT((sdlError,
"SdbpSortIndex",
"Index referenced by 0x%x is not valid\n",
tiIndexBits));
return FALSE;
}
dwRecords = SdbGetTagDataSize(pdb, tiIndexBits) / sizeof(INDEX_RECORD);
qsort(pIndexRecords, dwRecords, sizeof(INDEX_RECORD), CompareIndexRecords);
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
//
// String writing routine
//
STRINGREF
SdbpAddStringToTable(
PDB pdb,
LPCTSTR szData)
{
STRINGREF srReturn = STRINGREF_NULL;
BOOL bSuccess;
TAGID tiTemp;
assert(pdb);
//
// Add a string table if one doesn't exist
//
if (!pdb->pdbStringTable) {
DWORD dwLength;
TCHAR szBuffer[MAX_PATH];
TCHAR szTempFile[MAX_PATH];
//
// Create temp string table db
//
dwLength = GetTempPath(CHARCOUNT(szBuffer), szBuffer);
if (!dwLength || dwLength > CHARCOUNT(szBuffer)) {
DBGPRINT((sdlError,
"SdbpAddStringToTable",
"Error Gettting temp path 0x%lx\n",
GetLastError()));
goto err1;
}
//
// We got the directory, generate the file now
//
dwLength = GetTempFileName(szBuffer, TEXT("SDB"), 0, szTempFile);
if (!dwLength) {
DBGPRINT((sdlError,
"SdbpAddStringToTable",
"Error Gettting temp filename 0x%lx\n",
GetLastError()));
goto err1;
}
//
// If we are successful, we'd have a string table file now.
//
pdb->pdbStringTable = SdbCreateDatabase(szTempFile, DOS_PATH);
if (!pdb->pdbStringTable) {
goto err1;
}
//
// success !!! set the name of the file into the pdb so we could remove it later
//
if (!COPY_TEMP_STRINGTABLE(pdb, szTempFile)) {
DBGPRINT((sdlError,
"SdbpAddStringToTable",
"Error copying string table temp filename\n"));
goto err1;
}
}
if (!pdb->pStringHash) {
pdb->pStringHash = HashCreate();
if (pdb->pStringHash == NULL) {
DBGPRINT((sdlError,
"SdbpAddStringToTable",
"Error creating hash table\n"));
goto err1;
}
}
srReturn = HashFindString((PSTRHASH)pdb->pStringHash, szData);
if (!srReturn) {
//
// A stringref is the offset from the beginning of the string table to
// the string tag itself. We have to adjust for the header of the temporary
// DB, and the tag and size that will be written later.
//
srReturn = pdb->pdbStringTable->dwSize - sizeof (DB_HEADER) + sizeof(TAG) + sizeof(DWORD);
bSuccess = SdbWriteStringTagDirect(pdb->pdbStringTable, TAG_STRINGTABLE_ITEM, szData);
if (!bSuccess) {
DBGPRINT((sdlError,
"SdbpAddStringToTable",
"Failed to write stringtableitem into the string table\n"));
srReturn = STRINGREF_NULL;
}
HashAddString((PSTRHASH)pdb->pStringHash, szData, srReturn);
}
err1:
return srReturn;
}