|
|
/*++
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;
RtlInitUnicodeString(&UnicodeString, szPath);
if (eType == DOS_PATH) { if (!RtlDosPathNameToNtPathName_U(UnicodeString.Buffer, &UnicodeString, NULL, NULL)) { 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; NTSTATUS status;
RtlInitUnicodeString(&UnicodeString, szPath);
if (eType == DOS_PATH) { if (!RtlDosPathNameToNtPathName_U(UnicodeString.Buffer, &UnicodeString, NULL, NULL)) { 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 = (DWORD)(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;
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; }
|