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

805 lines
20 KiB
C

/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
ntKMode.c
Abstract:
This module implements low level primitives for kernel mode implementation.
Author:
VadimB created sometime in 2000
Revision History:
--*/
#include "sdbp.h"
#ifdef KERNEL_MODE
extern TAG g_rgDirectoryTags[];
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, SdbTagIDToTagRef)
#pragma alloc_text(PAGE, SdbTagRefToTagID)
#pragma alloc_text(PAGE, SdbInitDatabaseInMemory)
#pragma alloc_text(PAGE, SdbpOpenAndMapFile)
#pragma alloc_text(PAGE, SdbpUnmapAndCloseFile)
#pragma alloc_text(PAGE, SdbpUpcaseUnicodeStringToMultiByteN)
#pragma alloc_text(PAGE, SdbpQueryFileDirectoryAttributesNT)
#pragma alloc_text(PAGE, SdbpDoesFileExists_U)
#pragma alloc_text(PAGE, SdbGetFileInfo)
#pragma alloc_text(PAGE, DuplicateUnicodeString)
#pragma alloc_text(PAGE, SdbpCreateUnicodeString)
#pragma alloc_text(PAGE, SdbpGetFileDirectoryAttributesNT)
#endif
BOOL
SdbTagIDToTagRef(
IN HSDB hSDB,
IN PDB pdb, // PDB the TAGID is from
IN TAGID tiWhich, // TAGID to convert
OUT TAGREF* ptrWhich // converted TAGREF
)
/*++
Return: TRUE if a TAGREF was found, FALSE otherwise.
Desc: Converts a PDB and TAGID into a TAGREF, by packing the high bits of the
TAGREF with a constant that tells us which PDB, and the low bits with
the TAGID.
--*/
{
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
BOOL bReturn = FALSE;
//
// In kernel mode we only support sysmain db
//
*ptrWhich = tiWhich | PDB_MAIN;
bReturn = TRUE;
if (!bReturn) {
DBGPRINT((sdlError, "SdbTagIDToTagRef", "Bad PDB.\n"));
*ptrWhich = TAGREF_NULL;
}
return bReturn;
}
BOOL
SdbTagRefToTagID(
IN HSDB hSDB,
IN TAGREF trWhich, // TAGREF to convert
OUT PDB* ppdb, // PDB the TAGREF is from
OUT TAGID* ptiWhich // TAGID within that PDB
)
/*++
Return: TRUE if the TAGREF is valid and was converted, FALSE otherwise.
Desc: Converts a TAGREF type to a TAGID and a PDB. This manages the interface
between NTDLL, which knows nothing of PDBs, and the shimdb, which manages
three separate PDBs. The TAGREF incorporates the TAGID and a constant
that tells us which PDB the TAGID is from. In this way, the NTDLL client
doesn't need to know which DB the info is coming from.
--*/
{
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
BOOL bReturn = TRUE;
TAGID tiWhich = TAGID_NULL;
PDB pdb = NULL;
DWORD dwMask;
dwMask = trWhich & TAGREF_STRIP_PDB;
if (dwMask != PDB_MAIN) {
goto cleanup;
}
tiWhich = trWhich & TAGREF_STRIP_TAGID;
pdb = pSdbContext->pdbMain;
//
// See that we double-check here
//
if (pdb == NULL && tiWhich != TAGID_NULL) {
DBGPRINT((sdlError, "SdbTagRefToTagID", "PDB dereferenced by this TAGREF is NULL\n"));
bReturn = FALSE;
}
cleanup:
if (ppdb != NULL) {
*ppdb = pdb;
}
if (ptiWhich != NULL) {
*ptiWhich = tiWhich;
}
return bReturn;
}
HSDB
SdbInitDatabaseInMemory(
IN LPVOID pDatabaseImage,
IN DWORD dwImageSize
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
PSDBCONTEXT pContext;
//
// Initialize the context.
//
pContext = (PSDBCONTEXT)SdbAlloc(sizeof(SDBCONTEXT));
if (pContext == NULL) {
DBGPRINT((sdlError,
"SdbInitDatabaseInMemory",
"Failed to allocate %d bytes for HSDB\n",
sizeof(SDBCONTEXT)));
return NULL;
}
//
// Now open the database.
//
pContext->pdbMain = SdbpOpenDatabaseInMemory(pDatabaseImage, dwImageSize);
if (pContext->pdbMain == NULL) {
DBGPRINT((sdlError,
"SdbInitDatabaseInMemory",
"Unable to open main database at 0x%x size 0x%x\n",
pDatabaseImage,
dwImageSize));
goto ErrHandle;
}
return (HSDB)pContext;
ErrHandle:
if (pContext != NULL) {
if (pContext->pdbMain != NULL) {
SdbCloseDatabaseRead(pContext->pdbMain);
}
SdbFree(pContext);
}
return NULL;
}
//
// Open and map File
//
BOOL
SdbpOpenAndMapFile(
IN LPCWSTR szPath, // pointer to the fully-qualified filename
OUT PIMAGEFILEDATA pImageData, // pointer to IMAGEFILEDATA that receives
// image-related information
IN PATH_TYPE ePathType // ignored
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Opens a file and maps it into memory.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING ustrFileName;
HANDLE hSection = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
IO_STATUS_BLOCK IoStatusBlock;
SIZE_T ViewSize = 0;
PVOID pBase = NULL;
DWORD dwFlags = 0;
FILE_STANDARD_INFORMATION StandardInfo;
if (pImageData->dwFlags & IMAGEFILEDATA_PBASEVALID) {
//
// special case, only headers are valid in our assumption
//
return TRUE;
}
//
// Initialize return data
//
if (pImageData->dwFlags & IMAGEFILEDATA_HANDLEVALID) {
hFile = pImageData->hFile;
if (hFile != INVALID_HANDLE_VALUE) {
dwFlags |= IMAGEFILEDATA_NOFILECLOSE;
}
}
RtlZeroMemory(pImageData, sizeof(*pImageData));
pImageData->hFile = INVALID_HANDLE_VALUE;
if (hFile == INVALID_HANDLE_VALUE) {
//
// Open the file
//
RtlInitUnicodeString(&ustrFileName, szPath);
InitializeObjectAttributes(&ObjectAttributes,
&ustrFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwCreateFile(&hFile,
GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE,
NULL,
0);
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbpOpenAndMapFile",
"ZwCreateFile failed status 0x%x\n",
Status));
return FALSE;
}
}
//
// Query file size
//
Status = ZwQueryInformationFile(hFile,
&IoStatusBlock,
&StandardInfo,
sizeof(StandardInfo),
FileStandardInformation);
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbpOpenAndMapFile",
"ZwQueryInformationFile (EOF) failed Status 0x%x\n",
Status));
if (!(dwFlags & IMAGEFILEDATA_NOFILECLOSE)) {
ZwClose(hFile);
}
return FALSE;
}
InitializeObjectAttributes(&ObjectAttributes,
NULL,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwCreateSection(&hSection,
STANDARD_RIGHTS_REQUIRED |
SECTION_QUERY |
SECTION_MAP_READ,
&ObjectAttributes,
NULL,
PAGE_READONLY,
SEC_COMMIT,
hFile);
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbpOpenAndMapFile",
"ZwOpenSectionFailed status 0x%x\n",
Status));
if (!(dwFlags & IMAGEFILEDATA_NOFILECLOSE)) {
ZwClose(hFile);
}
return FALSE;
}
Status = ZwMapViewOfSection(hSection,
NtCurrentProcess(),
&pBase,
0L,
0L,
NULL,
&ViewSize,
ViewUnmap,
0L,
PAGE_READONLY);
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbpMapFile",
"NtMapViewOfSection failed Status 0x%x\n",
Status));
ZwClose(hSection);
if (!(dwFlags & IMAGEFILEDATA_NOFILECLOSE)) {
ZwClose(hFile);
}
return FALSE;
}
pImageData->hFile = hFile;
pImageData->dwFlags = dwFlags;
pImageData->hSection = hSection;
pImageData->pBase = pBase;
pImageData->ViewSize = ViewSize;
pImageData->FileSize = StandardInfo.EndOfFile.QuadPart;
return TRUE;
}
BOOL
SdbpUnmapAndCloseFile(
IN PIMAGEFILEDATA pImageData // pointer to IMAGEFILEDATE - image-related information
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Closes and unmaps an opened file.
--*/
{
BOOL bSuccess = TRUE;
NTSTATUS Status;
if (pImageData->dwFlags & IMAGEFILEDATA_PBASEVALID) { // externally supplied pointer
RtlZeroMemory(pImageData, sizeof(*pImageData));
return TRUE;
}
if (pImageData->pBase != NULL) {
Status = ZwUnmapViewOfSection(NtCurrentProcess(), pImageData->pBase);
if (!NT_SUCCESS(Status)) {
bSuccess = FALSE;
DBGPRINT((sdlError,
"SdbpCloseAndUnmapFile",
"ZwUnmapViewOfSection failed Status 0x%x\n",
Status));
}
pImageData->pBase = NULL;
}
if (pImageData->hSection != NULL) {
Status = ZwClose(pImageData->hSection);
if (!NT_SUCCESS(Status)) {
bSuccess = FALSE;
DBGPRINT((sdlError,
"SdbpCloseAndUnmapFile",
"ZwClose on section failed Status 0x%x\n",
Status));
}
pImageData->hSection = NULL;
}
if (pImageData->dwFlags & IMAGEFILEDATA_NOFILECLOSE) {
pImageData->hFile = INVALID_HANDLE_VALUE;
} else {
if (pImageData->hFile != INVALID_HANDLE_VALUE) {
Status = ZwClose(pImageData->hFile);
if (!NT_SUCCESS(Status)) {
bSuccess = FALSE;
DBGPRINT((sdlError,
"SdbpCloseAndUnmapFile",
"ZwClose on file failed Status 0x%x\n",
Status));
}
pImageData->hFile = INVALID_HANDLE_VALUE;
}
}
return bSuccess;
}
NTSTATUS
SdbpUpcaseUnicodeStringToMultiByteN(
OUT LPSTR lpszDest, // dest buffer
IN DWORD dwSize, // size in characters, excluding unicode_null
IN LPCWSTR lpszSrc // source
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Convert up to dwSize characters from Unicode to ANSI.
--*/
{
ANSI_STRING strDest;
UNICODE_STRING ustrSource;
NTSTATUS Status;
UNICODE_STRING ustrUpcaseSource = { 0 };
USHORT DestBufSize = (USHORT)dwSize * sizeof(WCHAR);
RtlInitUnicodeString(&ustrSource, lpszSrc);
STACK_ALLOC(ustrUpcaseSource.Buffer, ustrSource.MaximumLength);
if (ustrUpcaseSource.Buffer == NULL) {
DBGPRINT((sdlError,
"SdbpUnicodeToMultiByteN",
"Failed to allocate %d bytes on the stack\n",
(DWORD)ustrSource.MaximumLength));
return STATUS_NO_MEMORY;
}
ustrUpcaseSource.MaximumLength = ustrSource.MaximumLength;
ustrUpcaseSource.Length = 0;
Status = RtlUpcaseUnicodeString(&ustrUpcaseSource, &ustrSource, FALSE);
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbpUnicodeToMultiByteN",
"RtlUpcaseUnicodeString failed Status 0x%x\n",
Status));
goto Done;
}
if (ustrUpcaseSource.Length > DestBufSize) {
ustrUpcaseSource.Length = DestBufSize;
}
strDest.Buffer = lpszDest;
strDest.MaximumLength = DestBufSize + sizeof(UNICODE_NULL);
strDest.Length = 0;
Status = RtlUnicodeStringToAnsiString(&strDest, &ustrUpcaseSource, FALSE);
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbpUnicodeToMultiByteN",
"RtlUnicodeStringToAnsiString failed Status 0x%x\n",
Status));
}
Done:
if (ustrUpcaseSource.Buffer != NULL) {
STACK_FREE(ustrUpcaseSource.Buffer);
}
return Status;
}
BOOL
SdbpQueryFileDirectoryAttributesNT(
PIMAGEFILEDATA pImageData,
PFILEDIRECTORYATTRIBUTES pFileDirectoryAttributes
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: BUGBUG: ?
--*/
{
LARGE_INTEGER liFileSize;
liFileSize.QuadPart = pImageData->FileSize;
pFileDirectoryAttributes->dwFlags |= FDA_FILESIZE;
pFileDirectoryAttributes->dwFileSizeHigh = liFileSize.HighPart;
pFileDirectoryAttributes->dwFileSizeLow = liFileSize.LowPart;
return TRUE;
}
BOOL
SdbpDoesFileExists_U(
LPCWSTR pwszPath
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: BUGBUG: ?
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING ustrFileName;
HANDLE hFile;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
RtlInitUnicodeString(&ustrFileName, pwszPath);
InitializeObjectAttributes(&ObjectAttributes,
&ustrFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwCreateFile(&hFile,
STANDARD_RIGHTS_REQUIRED |
FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatusBlock,
NULL, // AllocationSize
FILE_ATTRIBUTE_NORMAL, // FileAttributes
FILE_SHARE_READ, // Share Access
FILE_OPEN, // Create Disposition
FILE_NON_DIRECTORY_FILE | // Create Options
FILE_SYNCHRONOUS_IO_NONALERT,
NULL, // EaBuffer
0); // EaLength
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbpDoesFileExists_U",
"Failed to create file. Status 0x%x\n",
Status));
return FALSE;
}
ZwClose(hFile);
return TRUE;
}
PVOID
SdbGetFileInfo(
IN HSDB hSDB,
IN LPCWSTR pwszFilePath,
IN HANDLE hFile, // handle for the file in question
IN LPVOID pImageBase, // image base for this file
IN DWORD dwImageSize,
IN BOOL bNoCache
)
/*++
Return: BUGBUG: ?
Desc: Create and link a new entry in a file attribute cache.
--*/
{
PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
LPCWSTR FullPath = pwszFilePath;
NTSTATUS Status;
PFILEINFO pFileInfo = NULL;
UNICODE_STRING FullPathU;
if (!bNoCache) {
pFileInfo = FindFileInfo(pContext, FullPath);
}
if (pFileInfo == NULL) {
if (hFile != INVALID_HANDLE_VALUE || pImageBase != NULL || SdbpDoesFileExists_U(FullPath)) {
RtlInitUnicodeString(&FullPathU, FullPath);
pFileInfo = CreateFileInfo(pContext,
FullPathU.Buffer,
FullPathU.Length / sizeof(WCHAR),
hFile,
pImageBase,
dwImageSize,
bNoCache);
}
}
return (PVOID)pFileInfo;
}
WCHAR*
DuplicateUnicodeString(
PUNICODE_STRING pStr,
PUSHORT pLength // pLength is an allocated length
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
WCHAR* pBuffer = NULL;
USHORT Length = 0;
if (pStr != NULL && pStr->Length > 0) {
Length = pStr->Length + sizeof(UNICODE_NULL);
pBuffer = (WCHAR*)SdbAlloc(Length);
if (pBuffer == NULL) {
DBGPRINT((sdlError,
"DuplicateUnicodeString",
"Failed to allocate %d bytes\n",
Length));
return NULL;
}
RtlMoveMemory(pBuffer, pStr->Buffer, pStr->Length);
pBuffer[pStr->Length/sizeof(WCHAR)] = UNICODE_NULL;
}
if (pLength != NULL) {
*pLength = Length;
}
return pBuffer;
}
BOOL
SdbpCreateUnicodeString(
PUNICODE_STRING pStr,
LPCWSTR lpwsz
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
USHORT Length;
UNICODE_STRING ustrSrc;
RtlZeroMemory(pStr, sizeof(*pStr));
RtlInitUnicodeString(&ustrSrc, lpwsz);
pStr->Buffer = DuplicateUnicodeString(&ustrSrc, &Length);
pStr->Length = ustrSrc.Length;
pStr->MaximumLength = Length;
return pStr->Buffer != NULL;
}
BOOL
SdbpGetFileDirectoryAttributesNT(
OUT PFILEINFO pFileInfo,
IN PIMAGEFILEDATA pImageData
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: This function retrieves the header attributes for the
specified file.
--*/
{
BOOL bSuccess = FALSE;
FILEDIRECTORYATTRIBUTES fda;
int i;
bSuccess = SdbpQueryFileDirectoryAttributesNT(pImageData, &fda);
if (!bSuccess) {
DBGPRINT((sdlInfo,
"SdbpGetFileDirectoryAttributesNT",
"No file directory attributes available.\n"));
goto Done;
}
if (fda.dwFlags & FDA_FILESIZE) {
assert(fda.dwFileSizeHigh == 0);
SdbpSetAttribute(pFileInfo, TAG_SIZE, &fda.dwFileSizeLow);
}
Done:
if (!bSuccess) {
for (i = 0; g_rgDirectoryTags[i] != 0; ++i) {
SdbpSetAttribute(pFileInfo, g_rgDirectoryTags[i], NULL);
}
}
return bSuccess;
}
#ifdef _DEBUG_SPEW
extern DBGLEVELINFO g_rgDbgLevelInfo[];
extern PCH g_szDbgLevelUser;
#endif // _DEBUG_SPEW
int __cdecl
ShimDbgPrint(
int iLevel,
PCH pszFunctionName,
PCH Format,
...
)
{
int nch = 0;
#ifdef _DEBUG_SPEW
PCH pszFormat = NULL;
va_list arglist;
ULONG Level = 0;
int i;
CHAR szPrefix[64];
PCH pchBuffer = szPrefix;
PCH pchLevel = NULL;
PREPARE_FORMAT(pszFormat, Format);
if (pszFormat == NULL) {
//
// Can't convert format for debug output
//
return 0;
}
//
// Do we have a comment for this debug level? if so, print it
//
for (i = 0; i < DEBUG_LEVELS; ++i) {
if (g_rgDbgLevelInfo[i].iLevel == iLevel) {
pchLevel = (PCH)g_rgDbgLevelInfo[i].szStrTag;
break;
}
}
if (pchLevel == NULL) {
pchLevel = g_szDbgLevelUser;
}
nch = sprintf(pchBuffer, "[%-4hs]", pchLevel);
pchBuffer += nch;
if (pszFunctionName) {
//
// Single-byte char going into UNICODE buffer
//
nch = sprintf(pchBuffer, "[%-30hs] ", pszFunctionName);
pchBuffer += nch;
}
switch (iLevel) {
case sdlError:
Level = (1 << DPFLTR_ERROR_LEVEL) | DPFLTR_MASK;
break;
case sdlWarning:
Level = (1 << DPFLTR_WARNING_LEVEL) | DPFLTR_MASK;
break;
case sdlInfo:
Level = (1 << DPFLTR_TRACE_LEVEL) | DPFLTR_MASK;
break;
}
va_start(arglist, Format);
nch = (int)vDbgPrintExWithPrefix(szPrefix,
DPFLTR_NTOSPNP_ID,
Level,
pszFormat,
arglist);
va_end(arglist);
STACK_FREE(pszFormat);
#endif // _DEBUG_SPEW
return nch;
}
#endif // KERNEL_MODE