847 lines
21 KiB
C
847 lines
21 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
chunkimpl.h
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This routine will manage allocations of chunks of structures. It also
|
|||
|
contains a handy unicode to ansi conversion function
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
16-Jan-1997 AlanWar
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
PENTRYHEADER EtwpAllocEntry(
|
|||
|
PCHUNKINFO ChunkInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will allocate a single structure within a list of chunks
|
|||
|
of structures.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ChunkInfo describes the chunks of structures
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to structure or NULL if one cannot be allocated. Entry returns
|
|||
|
with its refcount set to 1
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PLIST_ENTRY ChunkList, EntryList, FreeEntryHead;
|
|||
|
PCHUNKHEADER Chunk;
|
|||
|
PBYTE EntryPtr;
|
|||
|
ULONG EntryCount, ChunkSize;
|
|||
|
PENTRYHEADER Entry;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
#ifdef HEAPVALIDATION
|
|||
|
EtwpAssert(RtlValidateProcessHeaps());
|
|||
|
#endif
|
|||
|
EtwpEnterCriticalSection();
|
|||
|
ChunkList = ChunkInfo->ChunkHead.Flink;
|
|||
|
|
|||
|
//
|
|||
|
// Loop over all chunks to see if any chunk has a free entry for us
|
|||
|
while(ChunkList != &ChunkInfo->ChunkHead)
|
|||
|
{
|
|||
|
Chunk = CONTAINING_RECORD(ChunkList, CHUNKHEADER, ChunkList);
|
|||
|
if (! IsListEmpty(&Chunk->FreeEntryHead))
|
|||
|
{
|
|||
|
EntryList = RemoveHeadList(&Chunk->FreeEntryHead);
|
|||
|
Chunk->EntriesInUse++;
|
|||
|
EtwpLeaveCriticalSection();
|
|||
|
Entry = (CONTAINING_RECORD(EntryList,
|
|||
|
ENTRYHEADER,
|
|||
|
FreeEntryList));
|
|||
|
EtwpAssert(Entry->Flags & FLAG_ENTRY_ON_FREE_LIST);
|
|||
|
memset(Entry, 0, ChunkInfo->EntrySize);
|
|||
|
Entry->Chunk = Chunk;
|
|||
|
Entry->RefCount = 1;
|
|||
|
Entry->Flags = ChunkInfo->InitialFlags;
|
|||
|
Entry->Signature = ChunkInfo->Signature;
|
|||
|
#if DBG
|
|||
|
InterlockedIncrement(&ChunkInfo->AllocCount);
|
|||
|
#endif
|
|||
|
return(Entry);
|
|||
|
}
|
|||
|
ChunkList = ChunkList->Flink;
|
|||
|
}
|
|||
|
EtwpLeaveCriticalSection();
|
|||
|
|
|||
|
//
|
|||
|
// There are no more free entries in any of the chunks. Allocate a new
|
|||
|
// chunk if we can
|
|||
|
ChunkSize = (ChunkInfo->EntrySize * ChunkInfo->EntriesPerChunk) +
|
|||
|
sizeof(CHUNKHEADER);
|
|||
|
Chunk = (PCHUNKHEADER)EtwpAlloc(ChunkSize);
|
|||
|
if (Chunk != NULL)
|
|||
|
{
|
|||
|
//
|
|||
|
// Initialize the chunk by building the free list of entries within
|
|||
|
// it while also initializing each entry.
|
|||
|
memset(Chunk, 0, ChunkSize);
|
|||
|
|
|||
|
FreeEntryHead = &Chunk->FreeEntryHead;
|
|||
|
InitializeListHead(FreeEntryHead);
|
|||
|
|
|||
|
EntryPtr = (PBYTE)Chunk + sizeof(CHUNKHEADER);
|
|||
|
EntryCount = ChunkInfo->EntriesPerChunk - 1;
|
|||
|
|
|||
|
for (i = 0; i < EntryCount; i++)
|
|||
|
{
|
|||
|
Entry = (PENTRYHEADER)EntryPtr;
|
|||
|
Entry->Chunk = Chunk;
|
|||
|
Entry->Flags = FLAG_ENTRY_ON_FREE_LIST;
|
|||
|
InsertHeadList(FreeEntryHead,
|
|||
|
&((PENTRYHEADER)EntryPtr)->FreeEntryList);
|
|||
|
EntryPtr = EntryPtr + ChunkInfo->EntrySize;
|
|||
|
}
|
|||
|
//
|
|||
|
// EntryPtr now points to the last entry in the chunk which has not
|
|||
|
// been placed on the free list. This will be the entry returned
|
|||
|
// to the caller.
|
|||
|
Entry = (PENTRYHEADER)EntryPtr;
|
|||
|
Entry->Chunk = Chunk;
|
|||
|
Entry->RefCount = 1;
|
|||
|
Entry->Flags = ChunkInfo->InitialFlags;
|
|||
|
Entry->Signature = ChunkInfo->Signature;
|
|||
|
|
|||
|
Chunk->EntriesInUse = 1;
|
|||
|
|
|||
|
//
|
|||
|
// Now place the newly allocated chunk onto the list of chunks
|
|||
|
EtwpEnterCriticalSection();
|
|||
|
InsertHeadList(&ChunkInfo->ChunkHead, &Chunk->ChunkList);
|
|||
|
EtwpLeaveCriticalSection();
|
|||
|
|
|||
|
} else {
|
|||
|
EtwpDebugPrint(("WMI: Could not allocate memory for new chunk %x\n",
|
|||
|
ChunkInfo));
|
|||
|
Entry = NULL;
|
|||
|
}
|
|||
|
return(Entry);
|
|||
|
}
|
|||
|
|
|||
|
void EtwpFreeEntry(
|
|||
|
PCHUNKINFO ChunkInfo,
|
|||
|
PENTRYHEADER Entry
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will free an entry within a chunk and if the chunk has no
|
|||
|
more allocated entries then the chunk will be returned to the pool.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ChunkInfo describes the chunks of structures
|
|||
|
|
|||
|
Entry is the chunk entry to free
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PCHUNKHEADER Chunk;
|
|||
|
|
|||
|
EtwpAssert(Entry != NULL);
|
|||
|
EtwpAssert(! (Entry->Flags & FLAG_ENTRY_ON_FREE_LIST))
|
|||
|
EtwpAssert((Entry->Flags & FLAG_ENTRY_INVALID))
|
|||
|
EtwpAssert(Entry->RefCount == 0);
|
|||
|
EtwpAssert(Entry->Signature == ChunkInfo->Signature);
|
|||
|
|
|||
|
Chunk = Entry->Chunk;
|
|||
|
EtwpAssert(Chunk->EntriesInUse > 0);
|
|||
|
|
|||
|
EtwpEnterCriticalSection();
|
|||
|
if ((--Chunk->EntriesInUse == 0) &&
|
|||
|
(ChunkInfo->ChunkHead.Blink != &Chunk->ChunkList))
|
|||
|
{
|
|||
|
//
|
|||
|
// We return the chunks memory back to the heap if there are no
|
|||
|
// more entries within the chunk in use and the chunk was not the
|
|||
|
// first chunk to be allocated.
|
|||
|
RemoveEntryList(&Chunk->ChunkList);
|
|||
|
EtwpLeaveCriticalSection();
|
|||
|
EtwpFree(Chunk);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// Otherwise just mark the entry as free and put it back on the
|
|||
|
// chunks free list.
|
|||
|
#if DBG
|
|||
|
memset(Entry, 0xCCCCCCCC, ChunkInfo->EntrySize);
|
|||
|
#endif
|
|||
|
Entry->Flags = FLAG_ENTRY_ON_FREE_LIST;
|
|||
|
Entry->Signature = 0;
|
|||
|
InsertTailList(&Chunk->FreeEntryHead, &Entry->FreeEntryList);
|
|||
|
EtwpLeaveCriticalSection();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG EtwpUnreferenceEntry(
|
|||
|
PCHUNKINFO ChunkInfo,
|
|||
|
PENTRYHEADER Entry
|
|||
|
)
|
|||
|
/*+++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will remove a reference count from the entry and if the
|
|||
|
reference count reaches zero then the entry is removed from its active
|
|||
|
list and then cleaned up and finally freed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ChunkInfo points at structure that describes the entry
|
|||
|
|
|||
|
Entry is the entry to unreference
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
New refcount of the entry
|
|||
|
|
|||
|
---*/
|
|||
|
{
|
|||
|
ULONG RefCount;
|
|||
|
|
|||
|
EtwpAssert(Entry != NULL);
|
|||
|
EtwpAssert(Entry->RefCount > 0);
|
|||
|
EtwpAssert(Entry->Signature == ChunkInfo->Signature);
|
|||
|
|
|||
|
EtwpEnterCriticalSection();
|
|||
|
InterlockedDecrement(&Entry->RefCount);
|
|||
|
RefCount = Entry->RefCount;
|
|||
|
|
|||
|
if (RefCount == 0)
|
|||
|
{
|
|||
|
//
|
|||
|
// Entry has reached a ref count of 0 so mark it as invalid and remove
|
|||
|
// it from its active list.
|
|||
|
Entry->Flags |= FLAG_ENTRY_INVALID;
|
|||
|
|
|||
|
if ((Entry->InUseEntryList.Flink != NULL) &&
|
|||
|
(Entry->Flags & FLAG_ENTRY_REMOVE_LIST))
|
|||
|
{
|
|||
|
RemoveEntryList(&Entry->InUseEntryList);
|
|||
|
}
|
|||
|
|
|||
|
EtwpLeaveCriticalSection();
|
|||
|
|
|||
|
if (ChunkInfo->EntryCleanup != NULL)
|
|||
|
{
|
|||
|
//
|
|||
|
// Call cleanup routine to free anything contained by the entry
|
|||
|
(*ChunkInfo->EntryCleanup)(ChunkInfo, Entry);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Place the entry back on its free list
|
|||
|
EtwpFreeEntry(ChunkInfo, Entry);
|
|||
|
} else {
|
|||
|
EtwpLeaveCriticalSection();
|
|||
|
}
|
|||
|
return(RefCount);
|
|||
|
}
|
|||
|
|
|||
|
ULONG AnsiSizeForUnicodeString(
|
|||
|
PWCHAR UnicodeString,
|
|||
|
ULONG *AnsiSizeInBytes
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will return the length needed to represent the unicode
|
|||
|
string as ANSI
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
UnicodeString is the unicode string whose ansi length is returned
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Number of bytes needed to represent unicode string as ANSI
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
EtwpAssert(UnicodeString != NULL);
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
*AnsiSizeInBytes = WideCharToMultiByte(CP_ACP,
|
|||
|
0,
|
|||
|
UnicodeString,
|
|||
|
-1,
|
|||
|
NULL,
|
|||
|
0, NULL, NULL) * sizeof(WCHAR);
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
return(ERROR_NOACCESS);
|
|||
|
}
|
|||
|
return((*AnsiSizeInBytes == 0) ? GetLastError() : ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG UnicodeToAnsi(
|
|||
|
LPCWSTR pszW,
|
|||
|
LPSTR * ppszA,
|
|||
|
ULONG *AnsiSizeInBytes OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Convert Unicode string into its ansi equivalent
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pszW is unicode string to convert
|
|||
|
|
|||
|
*ppszA on entry has a pointer to a ansi string into which the answer
|
|||
|
is written. If NULL on entry then a buffer is allocated and returned
|
|||
|
in it.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Error code
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG cbAnsi, cCharacters;
|
|||
|
ULONG Status;
|
|||
|
ULONG cbAnsiUsed;
|
|||
|
BOOLEAN CallerReturnBuffer = (*ppszA != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// If input is null then just return the same.
|
|||
|
if (pszW == NULL)
|
|||
|
{
|
|||
|
*ppszA = NULL;
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
cCharacters = wcslen(pszW)+1;
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
EtwpDebugPrint(("WMI: Bad pointer %x passed to UnicodeToAnsi\n", pszW));
|
|||
|
return(ERROR_NOACCESS);
|
|||
|
}
|
|||
|
|
|||
|
// Determine number of bytes to be allocated for ANSI string. An
|
|||
|
// ANSI string can have at most 2 bytes per character (for Double
|
|||
|
// Byte Character Strings.)
|
|||
|
cbAnsi = cCharacters*2;
|
|||
|
|
|||
|
// Use of the OLE allocator is not required because the resultant
|
|||
|
// ANSI string will never be passed to another COM component. You
|
|||
|
// can use your own allocator.
|
|||
|
if (*ppszA == NULL)
|
|||
|
{
|
|||
|
*ppszA = (LPSTR) EtwpAlloc(cbAnsi);
|
|||
|
if (NULL == *ppszA)
|
|||
|
{
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Convert to ANSI.
|
|||
|
try
|
|||
|
{
|
|||
|
cbAnsiUsed = WideCharToMultiByte(CP_ACP, 0, pszW, cCharacters, *ppszA,
|
|||
|
cbAnsi, NULL, NULL);
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
if (! CallerReturnBuffer)
|
|||
|
{
|
|||
|
EtwpFree(*ppszA);
|
|||
|
*ppszA = NULL;
|
|||
|
}
|
|||
|
return(ERROR_NOACCESS);
|
|||
|
}
|
|||
|
|
|||
|
if (AnsiSizeInBytes != NULL)
|
|||
|
{
|
|||
|
*AnsiSizeInBytes = cbAnsiUsed;
|
|||
|
}
|
|||
|
if (0 == cbAnsiUsed)
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
if (! CallerReturnBuffer)
|
|||
|
{
|
|||
|
EtwpFree(*ppszA);
|
|||
|
*ppszA = NULL;
|
|||
|
}
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ULONG AnsiToUnicode(
|
|||
|
LPCSTR pszA,
|
|||
|
LPWSTR * ppszW
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Convert Ansi string into its Unicode equivalent
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pszA is ansi string to convert
|
|||
|
|
|||
|
*ppszW on entry has a pointer to a unicode string into which the answer
|
|||
|
is written. If NULL on entry then a buffer is allocated and returned
|
|||
|
in it.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Error code
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG cCharacters;
|
|||
|
ULONG Status;
|
|||
|
ULONG cbUnicodeUsed;
|
|||
|
BOOLEAN CallerReturnBuffer = (*ppszW != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// If input is null then just return the same.
|
|||
|
if (pszA == NULL)
|
|||
|
{
|
|||
|
*ppszW = NULL;
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine the count of characters needed for Unicode string
|
|||
|
try
|
|||
|
{
|
|||
|
cCharacters = MultiByteToWideChar(CP_ACP, 0, pszA, -1, NULL, 0);
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
EtwpDebugPrint(("WMI: Bad pointer %x passed to AnsiToUnicode\n", pszA));
|
|||
|
return(ERROR_NOACCESS);
|
|||
|
}
|
|||
|
|
|||
|
if (cCharacters == 0)
|
|||
|
{
|
|||
|
*ppszW = NULL;
|
|||
|
return(GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
// Use of the OLE allocator is not required because the resultant
|
|||
|
// ANSI string will never be passed to another COM component. You
|
|||
|
// can use your own allocator.
|
|||
|
|
|||
|
if (*ppszW == NULL)
|
|||
|
{
|
|||
|
*ppszW = (LPWSTR) EtwpAlloc(cCharacters * sizeof(WCHAR));
|
|||
|
}
|
|||
|
if (NULL == *ppszW)
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
|
|||
|
// Convert to Unicode
|
|||
|
try
|
|||
|
{
|
|||
|
cbUnicodeUsed = MultiByteToWideChar(CP_ACP, 0, pszA, -1, *ppszW, cCharacters);
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
if (! CallerReturnBuffer)
|
|||
|
{
|
|||
|
EtwpFree(*ppszW);
|
|||
|
*ppszW = NULL;
|
|||
|
}
|
|||
|
return(ERROR_NOACCESS);
|
|||
|
}
|
|||
|
if (0 == cbUnicodeUsed)
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
if (! CallerReturnBuffer)
|
|||
|
{
|
|||
|
EtwpFree(*ppszW);
|
|||
|
*ppszW = NULL;
|
|||
|
}
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ULONG UnicodeSizeForAnsiString(
|
|||
|
LPCSTR pszA,
|
|||
|
ULONG *UnicodeSizeInBytes
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will return the length needed to represent the ansi
|
|||
|
string as UNICODE
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pszA is ansi string to convert
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Error code
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
EtwpAssert(pszA != NULL);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Determine the count of characters needed for Unicode string
|
|||
|
try
|
|||
|
{
|
|||
|
*UnicodeSizeInBytes = MultiByteToWideChar(CP_ACP, 0, pszA, -1, NULL, 0) * sizeof(WCHAR);
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
return(ERROR_NOACCESS);
|
|||
|
}
|
|||
|
|
|||
|
return((*UnicodeSizeInBytes == 0) ? GetLastError() : ERROR_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#if 0 // TODO: Delete me
|
|||
|
ULONG EtwpStaticInstanceNameSize(
|
|||
|
PWMIINSTANCEINFO WmiInstanceInfo
|
|||
|
)
|
|||
|
/*+++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will calculate the size needed to place instance names in
|
|||
|
a WNODE_ALL_DATA
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
WmiInstanceInfo describes to instance set whose instance name size
|
|||
|
is to be calculated
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Size needed to place instance names in a WNODE_ALL_DATA plus 3. The
|
|||
|
extra 3 bytes are added in case the OffsetInstanceNameOffsets need to be
|
|||
|
padded since they must be on a 4 byte boundry.
|
|||
|
|
|||
|
---*/
|
|||
|
{
|
|||
|
ULONG NameSize;
|
|||
|
ULONG i;
|
|||
|
ULONG SuffixLen;
|
|||
|
|
|||
|
//
|
|||
|
// If we already computed this then just return the results
|
|||
|
if (WmiInstanceInfo->InstanceNameSize != 0)
|
|||
|
{
|
|||
|
return(WmiInstanceInfo->InstanceNameSize);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Start with a name size of 3 in case the OffsetInstanceNameOffset will
|
|||
|
// need to be padded so that it starts on a 4 byte boundry.
|
|||
|
NameSize = 3;
|
|||
|
|
|||
|
if (WmiInstanceInfo->Flags & IS_INSTANCE_BASENAME)
|
|||
|
{
|
|||
|
//
|
|||
|
// For static base names we assume that there will never be more than
|
|||
|
// 999999 instances of a guid.
|
|||
|
SuffixLen = MAXBASENAMESUFFIXSIZE * sizeof(WCHAR);
|
|||
|
EtwpAssert((WmiInstanceInfo->BaseIndex + WmiInstanceInfo->InstanceCount) < 999999);
|
|||
|
NameSize += ((wcslen(WmiInstanceInfo->BaseName) * sizeof(WCHAR)) + 2 + SuffixLen + sizeof(ULONG)) * WmiInstanceInfo->InstanceCount;
|
|||
|
} else if (WmiInstanceInfo->Flags & IS_INSTANCE_STATICNAMES)
|
|||
|
{
|
|||
|
//
|
|||
|
// Count up each size of the static instance names in the list
|
|||
|
for (i = 0; i < WmiInstanceInfo->InstanceCount; i++)
|
|||
|
{
|
|||
|
NameSize += (wcslen(WmiInstanceInfo->StaticNamePtr[i]) + 2) * sizeof(WCHAR) + sizeof(ULONG);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
WmiInstanceInfo->InstanceNameSize = NameSize;
|
|||
|
|
|||
|
return(NameSize);
|
|||
|
}
|
|||
|
|
|||
|
void EtwpInsertStaticNames(
|
|||
|
PWNODE_ALL_DATA Wnode,
|
|||
|
ULONG MaxWnodeSize,
|
|||
|
PWMIINSTANCEINFO WmiInstanceInfo
|
|||
|
)
|
|||
|
/*+++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will copy into the WNODE_ALL_DATA instance names for a
|
|||
|
static instance name set. If the Wnode_All_data is too small then it
|
|||
|
is converted to a WNODE_TOO_SMALL
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Wnode points at the WNODE_ALL_DATA
|
|||
|
MaxWnodeSize is the maximum size of the Wnode
|
|||
|
WmiInstanceInfo is the Instance Info
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
---*/
|
|||
|
{
|
|||
|
PWCHAR NamePtr;
|
|||
|
PULONG NameOffsetPtr;
|
|||
|
ULONG InstanceCount;
|
|||
|
ULONG i;
|
|||
|
WCHAR Index[7];
|
|||
|
PWCHAR StaticName;
|
|||
|
ULONG SizeNeeded;
|
|||
|
ULONG NameLen;
|
|||
|
USHORT Len;
|
|||
|
ULONG PaddedBufferSize;
|
|||
|
|
|||
|
if ((WmiInstanceInfo->Flags &
|
|||
|
(IS_INSTANCE_BASENAME | IS_INSTANCE_STATICNAMES)) == 0)
|
|||
|
{
|
|||
|
EtwpDebugPrint(("WMI: Try to setup static names for dynamic guid\n"));
|
|||
|
return;
|
|||
|
}
|
|||
|
InstanceCount = WmiInstanceInfo->InstanceCount;
|
|||
|
|
|||
|
//
|
|||
|
// Pad out the size of the buffer to a 4 byte boundry since the
|
|||
|
// OffsetInstanceNameOffsets must be on a 4 byte boundry
|
|||
|
PaddedBufferSize = (Wnode->WnodeHeader.BufferSize + 3) & ~3;
|
|||
|
|
|||
|
//
|
|||
|
// Compute size needed to write instance names.
|
|||
|
SizeNeeded = (InstanceCount * sizeof(ULONG)) +
|
|||
|
EtwpStaticInstanceNameSize(WmiInstanceInfo) +
|
|||
|
Wnode->WnodeHeader.BufferSize;
|
|||
|
|
|||
|
if (SizeNeeded > MaxWnodeSize)
|
|||
|
{
|
|||
|
//
|
|||
|
// If not enough space left then change into a WNODE_TOO_SMALL
|
|||
|
Wnode->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
|||
|
Wnode->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
|||
|
((PWNODE_TOO_SMALL)Wnode)->SizeNeeded = SizeNeeded;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build the array of offsets to instance names
|
|||
|
NameOffsetPtr = (PULONG)((PBYTE)Wnode + PaddedBufferSize);
|
|||
|
Wnode->OffsetInstanceNameOffsets = (ULONG)((PBYTE)NameOffsetPtr - (PBYTE)Wnode);
|
|||
|
NamePtr = (PWCHAR)(NameOffsetPtr + InstanceCount);
|
|||
|
|
|||
|
|
|||
|
if (WmiInstanceInfo->Flags & IS_INSTANCE_BASENAME)
|
|||
|
{
|
|||
|
if (WmiInstanceInfo->Flags & IS_PDO_INSTANCENAME)
|
|||
|
{
|
|||
|
Wnode->WnodeHeader.Flags |= WNODE_FLAG_PDO_INSTANCE_NAMES;
|
|||
|
}
|
|||
|
|
|||
|
for (i = 0; i < InstanceCount; i++)
|
|||
|
{
|
|||
|
*NameOffsetPtr++ = (ULONG)((PBYTE)NamePtr - (PBYTE)Wnode);
|
|||
|
wcscpy(NamePtr+1,
|
|||
|
WmiInstanceInfo->BaseName);
|
|||
|
swprintf(Index, L"%d", WmiInstanceInfo->BaseIndex+i);
|
|||
|
wcscat(NamePtr+1, Index);
|
|||
|
NameLen = wcslen(NamePtr+1) + 1;
|
|||
|
*NamePtr = (USHORT)NameLen * sizeof(WCHAR);
|
|||
|
NamePtr += NameLen + 1;
|
|||
|
}
|
|||
|
} else if (WmiInstanceInfo->Flags & IS_INSTANCE_STATICNAMES) {
|
|||
|
for (i = 0; i < InstanceCount; i++)
|
|||
|
{
|
|||
|
*NameOffsetPtr++ = (ULONG)((PBYTE)NamePtr - (PBYTE)Wnode);
|
|||
|
StaticName = WmiInstanceInfo->StaticNamePtr[i];
|
|||
|
Len = (wcslen(StaticName)+1) * sizeof(WCHAR);
|
|||
|
*NamePtr++ = Len;
|
|||
|
wcscpy(NamePtr, StaticName);
|
|||
|
NamePtr += Len / sizeof(WCHAR);
|
|||
|
}
|
|||
|
}
|
|||
|
Wnode->WnodeHeader.BufferSize = SizeNeeded;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
#ifdef HEAPVALIDATION
|
|||
|
PVOID EtwpAlloc(
|
|||
|
ULONG Size
|
|||
|
)
|
|||
|
{
|
|||
|
PVOID p;
|
|||
|
|
|||
|
EtwpAssert(RtlValidateProcessHeaps());
|
|||
|
p = RtlAllocateHeap(EtwpProcessHeap, 0, Size);
|
|||
|
|
|||
|
EtwpDebugPrint(("WMI: EtwpAlloc %x (%x)\n", p, Size));
|
|||
|
|
|||
|
return(p);
|
|||
|
}
|
|||
|
|
|||
|
void EtwpFree(
|
|||
|
PVOID p
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
EtwpDebugPrint(("WMI: EtwpFree %x\n", p));
|
|||
|
EtwpAssert(p != NULL);
|
|||
|
|
|||
|
EtwpAssert(RtlValidateProcessHeaps());
|
|||
|
RtlFreeHeap(EtwpProcessHeap, 0, p);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef MEMPHIS
|
|||
|
void __cdecl DebugOut(char *Format, ...)
|
|||
|
{
|
|||
|
char Buffer[1024];
|
|||
|
va_list pArg;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
va_start(pArg, Format);
|
|||
|
i = _vsnprintf(Buffer, sizeof(Buffer), Format, pArg);
|
|||
|
OutputDebugString(Buffer);
|
|||
|
}
|
|||
|
#else
|
|||
|
void __cdecl DebugOut(char *Format, ...)
|
|||
|
{
|
|||
|
char Buffer[1024];
|
|||
|
va_list pArg;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
i = sprintf(Buffer, "[%d] - ", GetTickCount());
|
|||
|
va_start(pArg, Format);
|
|||
|
i = _vsnprintf(&Buffer[i], sizeof(Buffer), Format, pArg);
|
|||
|
DbgPrint(Buffer);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef MEMPHIS
|
|||
|
ULONG EtwpCheckGuidAccess(
|
|||
|
LPGUID Guid,
|
|||
|
ACCESS_MASK DesiredAccess
|
|||
|
)
|
|||
|
{
|
|||
|
HANDLE Handle;
|
|||
|
ULONG Status;
|
|||
|
|
|||
|
Status = EtwpOpenKernelGuid(Guid,
|
|||
|
DesiredAccess,
|
|||
|
&Handle,
|
|||
|
IOCTL_WMI_OPEN_GUID
|
|||
|
);
|
|||
|
|
|||
|
if (Status == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
CloseHandle(Handle);
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
ULONG EtwpBuildGuidObjectAttributes(
|
|||
|
IN LPGUID Guid,
|
|||
|
OUT POBJECT_ATTRIBUTES ObjectAttributes,
|
|||
|
OUT PUNICODE_STRING GuidString,
|
|||
|
OUT PWCHAR GuidObjectName
|
|||
|
)
|
|||
|
{
|
|||
|
WCHAR GuidChar[37];
|
|||
|
|
|||
|
EtwpAssert(Guid != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Build up guid name into the ObjectAttributes
|
|||
|
//
|
|||
|
swprintf(GuidChar, L"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
|||
|
Guid->Data1, Guid->Data2,
|
|||
|
Guid->Data3,
|
|||
|
Guid->Data4[0], Guid->Data4[1],
|
|||
|
Guid->Data4[2], Guid->Data4[3],
|
|||
|
Guid->Data4[4], Guid->Data4[5],
|
|||
|
Guid->Data4[6], Guid->Data4[7]);
|
|||
|
|
|||
|
EtwpAssert(wcslen(GuidChar) == 36);
|
|||
|
|
|||
|
wcscpy(GuidObjectName, WmiGuidObjectDirectory);
|
|||
|
wcscat(GuidObjectName, GuidChar);
|
|||
|
RtlInitUnicodeString(GuidString, GuidObjectName);
|
|||
|
|
|||
|
memset(ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
|
|||
|
ObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES);
|
|||
|
ObjectAttributes->ObjectName = GuidString;
|
|||
|
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
ULONG EtwpOpenKernelGuid(
|
|||
|
LPGUID Guid,
|
|||
|
ACCESS_MASK DesiredAccess,
|
|||
|
PHANDLE Handle,
|
|||
|
ULONG Ioctl
|
|||
|
)
|
|||
|
{
|
|||
|
WMIOPENGUIDBLOCK WmiOpenGuidBlock;
|
|||
|
UNICODE_STRING GuidString;
|
|||
|
ULONG ReturnSize;
|
|||
|
ULONG Status;
|
|||
|
WCHAR GuidObjectName[WmiGuidObjectNameLength+1];
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
|
|||
|
Status = EtwpBuildGuidObjectAttributes(Guid,
|
|||
|
&ObjectAttributes,
|
|||
|
&GuidString,
|
|||
|
GuidObjectName);
|
|||
|
|
|||
|
if (Status == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
WmiOpenGuidBlock.ObjectAttributes = &ObjectAttributes;
|
|||
|
WmiOpenGuidBlock.DesiredAccess = DesiredAccess;
|
|||
|
|
|||
|
Status = EtwpSendWmiKMRequest(NULL,
|
|||
|
Ioctl,
|
|||
|
(PVOID)&WmiOpenGuidBlock,
|
|||
|
sizeof(WMIOPENGUIDBLOCK),
|
|||
|
(PVOID)&WmiOpenGuidBlock,
|
|||
|
sizeof(WMIOPENGUIDBLOCK),
|
|||
|
&ReturnSize,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (Status == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
*Handle = WmiOpenGuidBlock.Handle.Handle;
|
|||
|
} else {
|
|||
|
*Handle = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|