668 lines
17 KiB
C
668 lines
17 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
cmsubs2.c
|
||
|
||
Abstract:
|
||
|
||
This module various support routines for the configuration manager.
|
||
|
||
The routines in this module are independent enough to be linked into
|
||
any other program. The routines in cmsubs.c are not.
|
||
|
||
Author:
|
||
|
||
Bryan M. Willman (bryanwi) 12-Sep-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "cmp.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,CmpFreeValue)
|
||
#pragma alloc_text(PAGE,CmpQueryKeyData)
|
||
#pragma alloc_text(PAGE,CmpQueryKeyValueData)
|
||
#endif
|
||
|
||
//
|
||
// Define alignment macro.
|
||
//
|
||
|
||
#define ALIGN_OFFSET(Offset) (ULONG) \
|
||
((((ULONG)(Offset) + sizeof(ULONG)-1)) & (~(sizeof(ULONG) - 1)))
|
||
|
||
|
||
VOID
|
||
CmpFreeValue(
|
||
PHHIVE Hive,
|
||
HCELL_INDEX Cell
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free the value entry Hive.Cell refers to, including
|
||
its name and data cells.
|
||
|
||
Arguments:
|
||
|
||
Hive - supplies a pointer to the hive control structure for the hive
|
||
|
||
Cell - supplies index of value to delete
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Result code from call, among the following:
|
||
|
||
<TBS>
|
||
|
||
--*/
|
||
{
|
||
PCELL_DATA value;
|
||
ULONG realsize;
|
||
BOOLEAN small;
|
||
|
||
//
|
||
// map in the cell
|
||
//
|
||
value = HvGetCell(Hive, Cell);
|
||
|
||
//
|
||
// free data if present
|
||
//
|
||
small = CmpIsHKeyValueSmall(realsize, value->u.KeyValue.DataLength);
|
||
if ((! small) && (realsize > 0))
|
||
{
|
||
HvFreeCell(Hive, value->u.KeyValue.Data);
|
||
}
|
||
|
||
//
|
||
// free the cell itself
|
||
//
|
||
HvFreeCell(Hive, Cell);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// Data transfer workers
|
||
//
|
||
|
||
NTSTATUS
|
||
CmpQueryKeyData(
|
||
PHHIVE Hive,
|
||
PCM_KEY_NODE Node,
|
||
KEY_INFORMATION_CLASS KeyInformationClass,
|
||
PVOID KeyInformation,
|
||
ULONG Length,
|
||
PULONG ResultLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Do the actual copy of data for a key into caller's buffer.
|
||
|
||
If KeyInformation is not long enough to hold all requested data,
|
||
STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
|
||
set to the number of bytes actually required.
|
||
|
||
Arguments:
|
||
|
||
Hive - supplies a pointer to the hive control structure for the hive
|
||
|
||
Node - Supplies pointer to node whose subkeys are to be found
|
||
|
||
KeyInformationClass - Specifies the type of information returned in
|
||
Buffer. One of the following types:
|
||
|
||
KeyBasicInformation - return last write time, title index, and name.
|
||
(see KEY_BASIC_INFORMATION structure)
|
||
|
||
KeyNodeInformation - return last write time, title index, name, class.
|
||
(see KEY_NODE_INFORMATION structure)
|
||
|
||
KeyInformation -Supplies pointer to buffer to receive the data.
|
||
|
||
Length - Length of KeyInformation in bytes.
|
||
|
||
ResultLength - Number of bytes actually written into KeyInformation.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Result code from call, among the following:
|
||
|
||
<TBS>
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PCELL_DATA pclass;
|
||
ULONG requiredlength;
|
||
LONG leftlength;
|
||
ULONG offset;
|
||
ULONG minimumlength;
|
||
PKEY_INFORMATION pbuffer;
|
||
USHORT NameLength;
|
||
|
||
pbuffer = (PKEY_INFORMATION)KeyInformation;
|
||
NameLength = CmpHKeyNameLen(Node);
|
||
|
||
switch (KeyInformationClass) {
|
||
|
||
case KeyBasicInformation:
|
||
|
||
//
|
||
// LastWriteTime, TitleIndex, NameLength, Name
|
||
|
||
requiredlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) +
|
||
NameLength;
|
||
|
||
minimumlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name);
|
||
|
||
*ResultLength = requiredlength;
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
if (Length < minimumlength) {
|
||
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else {
|
||
|
||
pbuffer->KeyBasicInformation.LastWriteTime =
|
||
Node->LastWriteTime;
|
||
|
||
pbuffer->KeyBasicInformation.TitleIndex = 0;
|
||
|
||
pbuffer->KeyBasicInformation.NameLength =
|
||
NameLength;
|
||
|
||
leftlength = Length - minimumlength;
|
||
|
||
requiredlength = NameLength;
|
||
|
||
if (leftlength < (LONG)requiredlength) {
|
||
requiredlength = leftlength;
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
if (Node->Flags & KEY_COMP_NAME) {
|
||
CmpCopyCompressedName(pbuffer->KeyBasicInformation.Name,
|
||
leftlength,
|
||
Node->Name,
|
||
Node->NameLength);
|
||
} else {
|
||
RtlCopyMemory(
|
||
&(pbuffer->KeyBasicInformation.Name[0]),
|
||
&(Node->Name[0]),
|
||
requiredlength
|
||
);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
|
||
case KeyNodeInformation:
|
||
|
||
//
|
||
// LastWriteTime, TitleIndex, ClassOffset, ClassLength
|
||
// NameLength, Name, Class
|
||
//
|
||
requiredlength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) +
|
||
NameLength +
|
||
Node->ClassLength;
|
||
|
||
minimumlength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name);
|
||
|
||
*ResultLength = requiredlength;
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
if (Length < minimumlength) {
|
||
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else {
|
||
|
||
pbuffer->KeyNodeInformation.LastWriteTime =
|
||
Node->LastWriteTime;
|
||
|
||
pbuffer->KeyNodeInformation.TitleIndex = 0;
|
||
|
||
pbuffer->KeyNodeInformation.ClassLength =
|
||
Node->ClassLength;
|
||
|
||
pbuffer->KeyNodeInformation.NameLength =
|
||
NameLength;
|
||
|
||
leftlength = Length - minimumlength;
|
||
requiredlength = NameLength;
|
||
|
||
if (leftlength < (LONG)requiredlength) {
|
||
requiredlength = leftlength;
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
if (Node->Flags & KEY_COMP_NAME) {
|
||
CmpCopyCompressedName(pbuffer->KeyNodeInformation.Name,
|
||
leftlength,
|
||
Node->Name,
|
||
Node->NameLength);
|
||
} else {
|
||
RtlCopyMemory(
|
||
&(pbuffer->KeyNodeInformation.Name[0]),
|
||
&(Node->Name[0]),
|
||
requiredlength
|
||
);
|
||
}
|
||
|
||
if (Node->ClassLength > 0) {
|
||
|
||
offset = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) +
|
||
NameLength;
|
||
offset = ALIGN_OFFSET(offset);
|
||
|
||
pbuffer->KeyNodeInformation.ClassOffset = offset;
|
||
|
||
pclass = HvGetCell(Hive, Node->u1.s1.Class);
|
||
|
||
pbuffer = (PKEY_INFORMATION)((PUCHAR)pbuffer + offset);
|
||
|
||
leftlength = (((LONG)Length - (LONG)offset) < 0) ?
|
||
0 :
|
||
Length - offset;
|
||
|
||
requiredlength = Node->ClassLength;
|
||
|
||
if (leftlength < (LONG)requiredlength) {
|
||
requiredlength = leftlength;
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
RtlMoveMemory(
|
||
pbuffer,
|
||
pclass,
|
||
requiredlength
|
||
);
|
||
|
||
} else {
|
||
pbuffer->KeyNodeInformation.ClassOffset = (ULONG)-1;
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
|
||
case KeyFullInformation:
|
||
|
||
//
|
||
// LastWriteTime, TitleIndex, ClassOffset, ClassLength,
|
||
// SubKeys, MaxNameLen, MaxClassLen, Values, MaxValueNameLen,
|
||
// MaxValueDataLen, Class
|
||
//
|
||
requiredlength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) +
|
||
Node->ClassLength;
|
||
|
||
minimumlength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
|
||
|
||
*ResultLength = requiredlength;
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
if (Length < minimumlength) {
|
||
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else {
|
||
|
||
pbuffer->KeyFullInformation.LastWriteTime =
|
||
Node->LastWriteTime;
|
||
|
||
pbuffer->KeyFullInformation.TitleIndex = 0;
|
||
|
||
pbuffer->KeyFullInformation.ClassLength =
|
||
Node->ClassLength;
|
||
|
||
if (Node->ClassLength > 0) {
|
||
|
||
pbuffer->KeyFullInformation.ClassOffset =
|
||
FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
|
||
|
||
pclass = HvGetCell(Hive, Node->u1.s1.Class);
|
||
|
||
leftlength = Length - minimumlength;
|
||
requiredlength = Node->ClassLength;
|
||
|
||
if (leftlength < (LONG)requiredlength) {
|
||
requiredlength = leftlength;
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
RtlMoveMemory(
|
||
&(pbuffer->KeyFullInformation.Class[0]),
|
||
pclass,
|
||
requiredlength
|
||
);
|
||
|
||
} else {
|
||
pbuffer->KeyFullInformation.ClassOffset = (ULONG)-1;
|
||
}
|
||
|
||
pbuffer->KeyFullInformation.SubKeys =
|
||
Node->SubKeyCounts[Stable] +
|
||
Node->SubKeyCounts[Volatile];
|
||
|
||
pbuffer->KeyFullInformation.Values =
|
||
Node->ValueList.Count;
|
||
|
||
pbuffer->KeyFullInformation.MaxNameLen =
|
||
Node->MaxNameLen;
|
||
|
||
pbuffer->KeyFullInformation.MaxClassLen =
|
||
Node->MaxClassLen;
|
||
|
||
pbuffer->KeyFullInformation.MaxValueNameLen =
|
||
Node->MaxValueNameLen;
|
||
|
||
pbuffer->KeyFullInformation.MaxValueDataLen =
|
||
Node->MaxValueDataLen;
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
|
||
default:
|
||
status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
CmpQueryKeyValueData(
|
||
PHHIVE Hive,
|
||
HCELL_INDEX Cell,
|
||
KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
||
PVOID KeyValueInformation,
|
||
ULONG Length,
|
||
PULONG ResultLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Do the actual copy of data for a key value into caller's buffer.
|
||
|
||
If KeyValueInformation is not long enough to hold all requested data,
|
||
STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
|
||
set to the number of bytes actually required.
|
||
|
||
Arguments:
|
||
|
||
Hive - supplies a pointer to the hive control structure for the hive
|
||
|
||
Cell - supplies index of node to whose sub keys are to be found
|
||
|
||
KeyValueInformationClass - Specifies the type of information returned in
|
||
KeyValueInformation. One of the following types:
|
||
|
||
KeyValueInformation -Supplies pointer to buffer to receive the data.
|
||
|
||
Length - Length of KeyInformation in bytes.
|
||
|
||
ResultLength - Number of bytes actually written into KeyInformation.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Result code from call, among the following:
|
||
|
||
<TBS>
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PKEY_VALUE_INFORMATION pbuffer;
|
||
PCELL_DATA pcell;
|
||
LONG leftlength;
|
||
ULONG requiredlength;
|
||
ULONG minimumlength;
|
||
ULONG offset;
|
||
ULONG base;
|
||
ULONG realsize;
|
||
PUCHAR datapointer;
|
||
BOOLEAN small;
|
||
USHORT NameLength;
|
||
|
||
|
||
pbuffer = (PKEY_VALUE_INFORMATION)KeyValueInformation;
|
||
pcell = HvGetCell(Hive, Cell);
|
||
NameLength = CmpValueNameLen(&pcell->u.KeyValue);
|
||
|
||
switch (KeyValueInformationClass) {
|
||
|
||
case KeyValueBasicInformation:
|
||
|
||
//
|
||
// TitleIndex, Type, NameLength, Name
|
||
//
|
||
requiredlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) +
|
||
NameLength;
|
||
|
||
minimumlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);
|
||
|
||
*ResultLength = requiredlength;
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
if (Length < minimumlength) {
|
||
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else {
|
||
|
||
pbuffer->KeyValueBasicInformation.TitleIndex = 0;
|
||
|
||
pbuffer->KeyValueBasicInformation.Type =
|
||
pcell->u.KeyValue.Type;
|
||
|
||
pbuffer->KeyValueBasicInformation.NameLength =
|
||
NameLength;
|
||
|
||
leftlength = Length - minimumlength;
|
||
requiredlength = NameLength;
|
||
|
||
if (leftlength < (LONG)requiredlength) {
|
||
requiredlength = leftlength;
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
|
||
CmpCopyCompressedName(pbuffer->KeyValueBasicInformation.Name,
|
||
requiredlength,
|
||
pcell->u.KeyValue.Name,
|
||
pcell->u.KeyValue.NameLength);
|
||
} else {
|
||
RtlCopyMemory(&(pbuffer->KeyValueBasicInformation.Name[0]),
|
||
&(pcell->u.KeyValue.Name[0]),
|
||
requiredlength);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
|
||
|
||
case KeyValueFullInformation:
|
||
|
||
//
|
||
// TitleIndex, Type, DataOffset, DataLength, NameLength,
|
||
// Name, Data
|
||
//
|
||
small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
|
||
requiredlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) +
|
||
NameLength +
|
||
realsize;
|
||
|
||
if (realsize > 0) {
|
||
base = requiredlength - realsize;
|
||
offset = ALIGN_OFFSET(base);
|
||
if (offset > base) {
|
||
requiredlength += (offset - base);
|
||
}
|
||
}
|
||
|
||
minimumlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
|
||
|
||
*ResultLength = requiredlength;
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
if (Length < minimumlength) {
|
||
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else {
|
||
|
||
pbuffer->KeyValueFullInformation.TitleIndex = 0;
|
||
|
||
pbuffer->KeyValueFullInformation.Type =
|
||
pcell->u.KeyValue.Type;
|
||
|
||
pbuffer->KeyValueFullInformation.DataLength =
|
||
realsize;
|
||
|
||
pbuffer->KeyValueFullInformation.NameLength =
|
||
NameLength;
|
||
|
||
leftlength = Length - minimumlength;
|
||
requiredlength = NameLength;
|
||
|
||
if (leftlength < (LONG)requiredlength) {
|
||
requiredlength = leftlength;
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
|
||
CmpCopyCompressedName(pbuffer->KeyValueFullInformation.Name,
|
||
requiredlength,
|
||
pcell->u.KeyValue.Name,
|
||
pcell->u.KeyValue.NameLength);
|
||
} else {
|
||
RtlMoveMemory(
|
||
&(pbuffer->KeyValueFullInformation.Name[0]),
|
||
&(pcell->u.KeyValue.Name[0]),
|
||
requiredlength
|
||
);
|
||
}
|
||
|
||
if (realsize > 0) {
|
||
|
||
if (small == TRUE) {
|
||
datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
|
||
} else {
|
||
datapointer = (PUCHAR)HvGetCell(Hive, pcell->u.KeyValue.Data);
|
||
}
|
||
|
||
pbuffer->KeyValueFullInformation.DataOffset = offset;
|
||
|
||
leftlength = (((LONG)Length - (LONG)offset) < 0) ?
|
||
0 :
|
||
Length - offset;
|
||
|
||
requiredlength = realsize;
|
||
|
||
if (leftlength < (LONG)requiredlength) {
|
||
requiredlength = leftlength;
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
|
||
|
||
RtlMoveMemory(
|
||
((PUCHAR)pbuffer + offset),
|
||
datapointer,
|
||
requiredlength
|
||
);
|
||
|
||
} else {
|
||
pbuffer->KeyValueFullInformation.DataOffset = (ULONG)-1;
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
|
||
case KeyValuePartialInformation:
|
||
|
||
//
|
||
// TitleIndex, Type, DataLength, Data
|
||
//
|
||
small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
|
||
requiredlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
|
||
realsize;
|
||
|
||
minimumlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
||
|
||
*ResultLength = requiredlength;
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
if (Length < minimumlength) {
|
||
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else {
|
||
|
||
pbuffer->KeyValuePartialInformation.TitleIndex = 0;
|
||
|
||
pbuffer->KeyValuePartialInformation.Type =
|
||
pcell->u.KeyValue.Type;
|
||
|
||
pbuffer->KeyValuePartialInformation.DataLength =
|
||
realsize;
|
||
|
||
leftlength = Length - minimumlength;
|
||
requiredlength = realsize;
|
||
|
||
if (leftlength < (LONG)requiredlength) {
|
||
requiredlength = leftlength;
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
if (realsize > 0) {
|
||
|
||
if (small == TRUE) {
|
||
datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
|
||
} else {
|
||
datapointer = (PUCHAR)HvGetCell(Hive, pcell->u.KeyValue.Data);
|
||
}
|
||
|
||
ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
|
||
|
||
RtlMoveMemory(
|
||
(PUCHAR)&(pbuffer->KeyValuePartialInformation.Data[0]),
|
||
datapointer,
|
||
requiredlength
|
||
);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
return status;
|
||
}
|