Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

525 lines
15 KiB

//+----------------------------------------------------------------------------
//
// Copyright (C) 1992, Microsoft Corporation
//
// File: regsups.c
//
// Contents: Support routines for registry - mainly wrappers for NtAPI.
// The native NT registry API deal with unweildy OBJECT_ATTRIBUTES
// structures to simply name a registry entry, and also deal
// with open-ended structures. This module wraps around the native
// NT api and presents a more logical interface tot the registry.
//
// The routines all have a uniform theme:
//
// o Declare a KEY_XXX (NT defined) structure on the stack,
// with an "arbitrary guess" for size of data.
//
// o Make the NT call.
//
// o If NT call returns STATUS_BUFFER_OVERFLOW, allocate a
// KEY_XXX structure of the correct size from heap, and make
// NT call again.
//
// o If success, copy data to caller's data buffer, and free
// anything we allocated on the heap.
//
// With a generous initial guess for data buffer size, most of
// the time these calls will make a single NT call. Only for
// large data will we pay the overhead of memory allocation.
//
// Classes:
//
// Functions: KRegpAttributes
// KRegpGetValueByName
// KRegpGetKeyInfo
// KRegpEnumKeyValues
// KRegpEnumSubKeys
//
// History: 18 Sep 92 Milans created.
//
//-----------------------------------------------------------------------------
#include "registry.h"
#include "regsups.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, KRegpAttributes )
#pragma alloc_text( PAGE, KRegpGetValueByName )
#pragma alloc_text( PAGE, KRegpGetKeyInfo )
#pragma alloc_text( PAGE, KRegpEnumKeyValues )
#pragma alloc_text( PAGE, KRegpEnumSubKeys )
#endif // ALLOC_PRAGMA
//-----------------------------------------------------------------------------
//
// The NT Reg API uses a few open ended structs for info related calls. This
// defines the max size of our structs.
//
// This is just an "optimization". When the NT API's want an open ended data
// buffer, we will initially supply one of MAX_INFO_LENGTH. If this is not
// sufficient, the NT API will return STATUS_BUFFER_OVERFLOW. At that point,
// we will allocate on the heap the proper size buffer, and call again.
//
//-----------------------------------------------------------------------------
#define MAX_INFO_LENGTH 512 // Maximum length of info bufs
//-----------------------------------------------------------------------------
//
// Struct for Value information (ie, value name, data, etc.)
//
typedef struct tag_KEY_VALUE_INFORMATION {
KEY_VALUE_FULL_INFORMATION vi;
BYTE buffer[MAX_INFO_LENGTH];
} KEY_VALUE_INFORMATION;
#define KEY_VALUE_INFORMATION_LENGTH sizeof(KEY_VALUE_FULL_INFORMATION) + \
MAX_INFO_LENGTH
//-----------------------------------------------------------------------------
//
// Struct for Key information (ie, # of subkeys, # of values, etc.)
//
typedef struct tag_KEY_INFORMATION {
KEY_FULL_INFORMATION ki;
BYTE buffer[MAX_INFO_LENGTH];
} KEY_INFORMATION;
#define KEY_INFORMATION_LENGTH sizeof(KEY_FULL_INFORMATION) + MAX_INFO_LENGTH
//-----------------------------------------------------------------------------
//
// Struct for a particular subkey's information
//
typedef struct tag_KEY_SUBKEY_INFORMATION {
KEY_NODE_INFORMATION ni;
BYTE buffer[MAX_INFO_LENGTH];
} KEY_SUBKEY_INFORMATION;
#define KEY_SUBKEY_INFORMATION_LENGTH sizeof(KEY_NODE_INFORMATION) + \
MAX_INFO_LENGTH
//+----------------------------------------------------------------------------
//
// Function: KRegpAttributes
//
// Synopsis: The NT reg API often calls for an Object Attributes structure
// for things like names etc. This routine bundles a name and its
// parent into such a structure.
//
// Arguments: [hParent] Handle to parent of object
// [wszName] Name of object
//
// Returns: Address of initialized object attributes structure.
//
// Notes: Return value is address to static variable.
//
//-----------------------------------------------------------------------------
OBJECT_ATTRIBUTES *
KRegpAttributes(
IN HANDLE hParent,
IN PWSTR wszName)
{
static OBJECT_ATTRIBUTES objAttributes;
static UNICODE_STRING usName;
RtlInitUnicodeString(&usName, wszName);
InitializeObjectAttributes(
&objAttributes, // Destination
&usName, // Name
OBJ_CASE_INSENSITIVE, // Attributes
hParent, // Parent
NULL); // Security
return(&objAttributes);
}
//+----------------------------------------------------------------------------
//
// Function: KRegpGetValueByName
//
// Synopsis: Given a Value Name, returns the value's data.
//
// Arguments: [hkey] Handle of key
// [wszValueName] Value Name to query
// [pbData] Pointer to data buffer
// [pcbSize] Pointer to ULONG. On entry, it must show size of
// data buffer. On successful exit, it will be set to
// actual length of data retrieved.
//
// Returns: STATUS_BUFFER_TOO_SMALL, Status from NT Reg API.
//
//-----------------------------------------------------------------------------
NTSTATUS
KRegpGetValueByName(
IN HKEY hKey,
IN PWSTR wszValueName,
OUT PBYTE pbData,
IN OUT PULONG pcbSize)
{
KEY_VALUE_INFORMATION viValue, *pviValue;
UNICODE_STRING ustrValueName;
ULONG cbActualLength, cbRequiredSize;
NTSTATUS Status;
RtlInitUnicodeString(&ustrValueName, wszValueName);
pviValue = &viValue;
Status = NtQueryValueKey(
hKey,
&ustrValueName,
KeyValueFullInformation,
(PVOID) pviValue,
KEY_VALUE_INFORMATION_LENGTH,
&cbActualLength
);
if (Status == STATUS_BUFFER_OVERFLOW) {
//
// Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
// Forced to allocate from heap and make call again.
//
pviValue = (KEY_VALUE_INFORMATION *) ExAllocatePoolWithTag(
PagedPool,
cbActualLength,
' sfD');
if (!pviValue) {
return(STATUS_NO_MEMORY);
}
Status = NtQueryValueKey(
hKey,
&ustrValueName,
KeyValueFullInformation,
(PVOID) pviValue,
cbActualLength,
&cbActualLength);
}
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
if (pviValue->vi.Type == REG_SZ) {
cbRequiredSize = pviValue->vi.DataLength + sizeof(UNICODE_NULL);
} else {
cbRequiredSize = pviValue->vi.DataLength;
}
if (cbRequiredSize > *pcbSize) {
Status = STATUS_BUFFER_TOO_SMALL;
goto Cleanup;
}
RtlMoveMemory(pbData, ((BYTE *) pviValue) + pviValue->vi.DataOffset,
pviValue->vi.DataLength);
if (pviValue->vi.Type == REG_SZ) {
((PWSTR) pbData)[cbRequiredSize/sizeof(WCHAR) - 1] = UNICODE_NULL;
}
*pcbSize = cbRequiredSize;
Cleanup:
if (pviValue != &viValue) {
//
// Must have had to allocate from heap, so free the heap
//
DfsFree(pviValue);
}
return(Status);
}
//+----------------------------------------------------------------------------
//
// Function: KRegpGetKeyInfo
//
// Synopsis: Given a key, return the number of subkeys, values, and their
// max sizes.
//
// Arguments: [hkey] Handle to key.
// [pcNumSubKeys] Receives # of subkeys that hkey has
// [pcbMaxSubKeyLength] Receives max length of subkey name
// [pcNumValues] Receives # of values that hkey has
// [pcbMaxValueLength] Receives max length of value name
// [pcbMaxValueData] Receives max length of value data
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS
KRegpGetKeyInfo(
IN HKEY hKey,
OUT PULONG pcNumSubKeys,
OUT PULONG pcbMaxSubKeyLength,
OUT PULONG pcNumValues,
OUT PULONG pcbMaxValueName,
OUT PULONG pcbMaxValueData)
{
KEY_INFORMATION kiInfo, *pkiInfo;
ULONG lActualLength;
NTSTATUS Status;
pkiInfo = &kiInfo;
Status = NtQueryKey(
hKey,
KeyFullInformation,
pkiInfo,
KEY_INFORMATION_LENGTH,
&lActualLength);
if (Status == STATUS_BUFFER_OVERFLOW) {
//
// Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
// Forced to allocate from heap and make call again.
//
pkiInfo = (KEY_INFORMATION *) ExAllocatePoolWithTag(
PagedPool,
lActualLength,
' sfD');
if (!pkiInfo) {
return(STATUS_NO_MEMORY);
}
Status = NtQueryKey(
hKey,
KeyFullInformation,
pkiInfo,
lActualLength,
&lActualLength);
}
if (NT_SUCCESS(Status)) {
*pcNumSubKeys = pkiInfo->ki.SubKeys;
*pcbMaxSubKeyLength = pkiInfo->ki.MaxNameLen;
*pcNumValues = pkiInfo->ki.Values;
*pcbMaxValueName = pkiInfo->ki.MaxValueNameLen;
*pcbMaxValueData = pkiInfo->ki.MaxValueDataLen;
}
if (pkiInfo != &kiInfo) {
DfsFree(pkiInfo);
}
return(Status);
}
//+----------------------------------------------------------------------------
//
// Function: KRegpEnumKeyValues
//
// Synopsis: Given a key, return the name and data of the i'th value, where
// the first value has an index of 0.
//
// Arguments: [hkey] -- Handle to key
// [i] -- Index of value to get
// [wszValueName] -- Pointer to buffer to hold value name.
// [pcbMaxValueName] -- on entry, size in bytes of wszValueName.
// On exit, will hold size of wszValueName.
// [pbData] -- pointer to buffer to hold value data.
// [pcbMaxDataSize] -- on entry, size of pbData. On successful
// return, size of pbData.
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS
KRegpEnumKeyValues(
HKEY hKey,
ULONG iValue,
PWSTR wszValueName,
PULONG pcbMaxValueName,
PBYTE pbData,
PULONG pcbMaxDataSize)
{
KEY_VALUE_INFORMATION viValue, *pviValue;
ULONG dwActualLength;
NTSTATUS Status;
pviValue = &viValue;
Status = NtEnumerateValueKey(
hKey,
iValue,
KeyValueFullInformation,
pviValue,
KEY_VALUE_INFORMATION_LENGTH,
&dwActualLength);
if (Status == STATUS_BUFFER_OVERFLOW) {
//
// Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
// Forced to allocate from heap and make call again.
//
pviValue = (KEY_VALUE_INFORMATION *) ExAllocatePoolWithTag(
PagedPool,
dwActualLength,
' sfD');
if (!pviValue) {
return(STATUS_NO_MEMORY);
}
Status = NtEnumerateValueKey(
hKey,
iValue,
KeyValueFullInformation,
pviValue,
dwActualLength,
&dwActualLength);
}
if (NT_SUCCESS(Status)) {
if ( (*pcbMaxValueName < pviValue->vi.NameLength) ||
(*pcbMaxDataSize < pviValue->vi.DataLength) ) {
Status = STATUS_BUFFER_TOO_SMALL;
goto Cleanup;
}
*pcbMaxValueName = pviValue->vi.NameLength;
RtlMoveMemory(
(BYTE *) wszValueName,
(BYTE *) pviValue->vi.Name,
pviValue->vi.NameLength
);
wszValueName[pviValue->vi.NameLength / sizeof(WCHAR)] = L'\0';
RtlMoveMemory(
pbData,
((BYTE *) &viValue) + pviValue->vi.DataOffset,
pviValue->vi.DataLength
);
*pcbMaxDataSize = pviValue->vi.DataLength;
}
Cleanup:
if (pviValue != &viValue) {
DfsFree(pviValue);
}
return(Status);
}
//+----------------------------------------------------------------------------
//
// Function: KRegpEnumSubKeys
//
// Synopsis: Retrieve the i'th subkey name of a key.
//
// Arguments: [hKey] -- Parent key
// [iSubKey] -- index of the subkey
// [wszSubKeyName] Buffer to hold name of subkey
// [pcbMaxNameSize] On entry, size in bytes of wszSubKeyName
// On exit, size of name.
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS
KRegpEnumSubKeys(
HKEY hKey,
ULONG iSubKey,
PWSTR wszSubKeyName,
PULONG pcbMaxNameSize
)
{
KEY_SUBKEY_INFORMATION si, *psi;
ULONG dwActualLength;
NTSTATUS Status;
psi = &si;
Status = NtEnumerateKey(
hKey,
iSubKey,
KeyNodeInformation,
psi,
KEY_SUBKEY_INFORMATION_LENGTH,
&dwActualLength
);
if (Status == STATUS_BUFFER_OVERFLOW) {
//
// Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
// Forced to allocate from heap and make call again.
//
psi = (KEY_SUBKEY_INFORMATION *) ExAllocatePoolWithTag(
PagedPool,
dwActualLength,
' sfD');
if (!psi) {
return(STATUS_NO_MEMORY);
}
Status = NtEnumerateKey(
hKey,
iSubKey,
KeyNodeInformation,
psi,
dwActualLength,
&dwActualLength
);
}
if (NT_SUCCESS(Status)) {
if (*pcbMaxNameSize < si.ni.NameLength) {
Status = STATUS_BUFFER_TOO_SMALL;
goto Cleanup;
}
RtlMoveMemory(
(BYTE *) wszSubKeyName,
(BYTE *) psi->ni.Name,
psi->ni.NameLength
);
wszSubKeyName[psi->ni.NameLength / sizeof(WCHAR)] = UNICODE_NULL;
*pcbMaxNameSize = psi->ni.NameLength;
}
Cleanup:
if (psi != &si) {
DfsFree(psi);
}
return(Status);
}