mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 21:42:57 +00:00
- Move NtCreateKey to regobj.c, delete ntfunc.c, now all those routines exist solely for creating keys.
- Move NtOpenKey to ntapi.c and rewrite it to use the new parse routine. It's now 6 lines of code instead of 80. - Fix a bug in CmpDereferenceNameCnotrolBlockWithLock. - Fix bugs during reference and dereference of KCB. - Fix KCB structure. - CmpDelayDerefKCBWorker is now called, don't make it assert anymore, just print out that it's not completed. - Remove debug output from new parse routine, since it's now called for each key open. - Add one more case to handle: opening the root \REGISTRY node. - Don't dereference KCBs in the parse routine anymore: we have some bugs related to this and it would make ReactOS crash. svn path=/trunk/; revision=31094
This commit is contained in:
parent
f7d91421f8
commit
60fad32ecf
8 changed files with 310 additions and 397 deletions
|
@ -1,289 +0,0 @@
|
||||||
/*
|
|
||||||
* PROJECT: ReactOS Kernel
|
|
||||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
|
||||||
* FILE: ntoskrnl/cm/ntfunc.c
|
|
||||||
* PURPOSE: Ntxxx function for registry access
|
|
||||||
*
|
|
||||||
* PROGRAMMERS: Hartmut Birr
|
|
||||||
* Casper Hornstrup
|
|
||||||
* Alex Ionescu
|
|
||||||
* Rex Jolliff
|
|
||||||
* Eric Kohl
|
|
||||||
* Filip Navara
|
|
||||||
* Thomas Weidenmueller
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
|
||||||
#define NDEBUG
|
|
||||||
#include <internal/debug.h>
|
|
||||||
|
|
||||||
#include "cm.h"
|
|
||||||
|
|
||||||
/* GLOBALS ******************************************************************/
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
|
||||||
CmpCreateHandle(PVOID ObjectBody,
|
|
||||||
ACCESS_MASK GrantedAccess,
|
|
||||||
ULONG HandleAttributes,
|
|
||||||
PHANDLE HandleReturn);
|
|
||||||
|
|
||||||
/* FUNCTIONS ****************************************************************/
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
|
||||||
NtCreateKey(OUT PHANDLE KeyHandle,
|
|
||||||
IN ACCESS_MASK DesiredAccess,
|
|
||||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
||||||
IN ULONG TitleIndex,
|
|
||||||
IN PUNICODE_STRING Class,
|
|
||||||
IN ULONG CreateOptions,
|
|
||||||
OUT PULONG Disposition)
|
|
||||||
{
|
|
||||||
UNICODE_STRING RemainingPath = {0}, ReturnedPath = {0};
|
|
||||||
ULONG LocalDisposition;
|
|
||||||
PCM_KEY_BODY KeyObject, Parent;
|
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
|
||||||
UNICODE_STRING ObjectName;
|
|
||||||
OBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
|
||||||
ULONG i;
|
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
||||||
HANDLE hKey;
|
|
||||||
PCM_KEY_NODE Node, ParentNode;
|
|
||||||
CM_PARSE_CONTEXT ParseContext = {0};
|
|
||||||
PAGED_CODE();
|
|
||||||
|
|
||||||
/* Setup the parse context */
|
|
||||||
ParseContext.CreateOperation = TRUE;
|
|
||||||
ParseContext.CreateOptions = CreateOptions;
|
|
||||||
if (Class) ParseContext.Class = *Class;
|
|
||||||
|
|
||||||
/* Capture all the info */
|
|
||||||
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
|
||||||
PreviousMode,
|
|
||||||
FALSE,
|
|
||||||
&ObjectCreateInfo,
|
|
||||||
&ObjectName);
|
|
||||||
if (!NT_SUCCESS(Status)) return Status;
|
|
||||||
|
|
||||||
/* Find the key object */
|
|
||||||
Status = CmFindObject(&ObjectCreateInfo,
|
|
||||||
&ObjectName,
|
|
||||||
(PVOID*)&Parent,
|
|
||||||
&ReturnedPath,
|
|
||||||
CmpKeyObjectType,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status)) goto Cleanup;
|
|
||||||
|
|
||||||
/* Check if we found the entire path */
|
|
||||||
RemainingPath = ReturnedPath;
|
|
||||||
if (!RemainingPath.Length)
|
|
||||||
{
|
|
||||||
/* Check if the parent has been deleted */
|
|
||||||
if (Parent->KeyControlBlock->Delete)
|
|
||||||
{
|
|
||||||
/* Fail */
|
|
||||||
DPRINT1("Object marked for delete!\n");
|
|
||||||
Status = STATUS_UNSUCCESSFUL;
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a new handle to the parent */
|
|
||||||
Status = CmpCreateHandle(Parent,
|
|
||||||
DesiredAccess,
|
|
||||||
ObjectCreateInfo.Attributes,
|
|
||||||
&hKey);
|
|
||||||
if (!NT_SUCCESS(Status)) goto Cleanup;
|
|
||||||
|
|
||||||
/* Tell the caller we did this */
|
|
||||||
LocalDisposition = REG_OPENED_EXISTING_KEY;
|
|
||||||
goto SuccessReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loop every leading slash */
|
|
||||||
while ((RemainingPath.Length) &&
|
|
||||||
(*RemainingPath.Buffer == OBJ_NAME_PATH_SEPARATOR))
|
|
||||||
{
|
|
||||||
/* And remove it */
|
|
||||||
RemainingPath.Length -= sizeof(WCHAR);
|
|
||||||
RemainingPath.MaximumLength -= sizeof(WCHAR);
|
|
||||||
RemainingPath.Buffer++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loop every terminating slash */
|
|
||||||
while ((RemainingPath.Length) &&
|
|
||||||
(RemainingPath.Buffer[(RemainingPath.Length / sizeof(WCHAR)) - 1] ==
|
|
||||||
OBJ_NAME_PATH_SEPARATOR))
|
|
||||||
{
|
|
||||||
/* And remove it */
|
|
||||||
RemainingPath.Length -= sizeof(WCHAR);
|
|
||||||
RemainingPath.MaximumLength -= sizeof(WCHAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now loop the entire path */
|
|
||||||
for (i = 0; i < RemainingPath.Length / sizeof(WCHAR); i++)
|
|
||||||
{
|
|
||||||
/* And check if we found slahes */
|
|
||||||
if (RemainingPath.Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
|
|
||||||
{
|
|
||||||
/* We don't create trees -- parent key doesn't exist, so fail */
|
|
||||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now check if we're left with no name by this point */
|
|
||||||
if (!(RemainingPath.Length) || (RemainingPath.Buffer[0] == UNICODE_NULL))
|
|
||||||
{
|
|
||||||
/* Then fail since we can't do anything */
|
|
||||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lock the registry */
|
|
||||||
CmpLockRegistry();
|
|
||||||
|
|
||||||
/* Create the key */
|
|
||||||
Status = CmpDoCreate(Parent->KeyControlBlock->KeyHive,
|
|
||||||
Parent->KeyControlBlock->KeyCell,
|
|
||||||
NULL,
|
|
||||||
&RemainingPath,
|
|
||||||
KernelMode,
|
|
||||||
&ParseContext,
|
|
||||||
Parent->KeyControlBlock,
|
|
||||||
(PVOID*)&KeyObject);
|
|
||||||
if (!NT_SUCCESS(Status)) goto Cleanup;
|
|
||||||
|
|
||||||
/* If we got here, this is a new key */
|
|
||||||
LocalDisposition = REG_CREATED_NEW_KEY;
|
|
||||||
|
|
||||||
/* Get the parent node and the child node */
|
|
||||||
ParentNode = (PCM_KEY_NODE)HvGetCell(KeyObject->KeyControlBlock->ParentKcb->KeyHive,
|
|
||||||
KeyObject->KeyControlBlock->ParentKcb->KeyCell);
|
|
||||||
Node = (PCM_KEY_NODE)HvGetCell(KeyObject->KeyControlBlock->KeyHive,
|
|
||||||
KeyObject->KeyControlBlock->KeyCell);
|
|
||||||
|
|
||||||
/* Inherit some information */
|
|
||||||
Node->Parent = KeyObject->KeyControlBlock->ParentKcb->KeyCell;
|
|
||||||
Node->Security = ParentNode->Security;
|
|
||||||
KeyObject->KeyControlBlock->ValueCache.ValueList = Node->ValueList.List;
|
|
||||||
KeyObject->KeyControlBlock->ValueCache.Count = Node->ValueList.Count;
|
|
||||||
|
|
||||||
/* Link child to parent */
|
|
||||||
InsertTailList(&Parent->KeyControlBlock->KeyBodyListHead, &KeyObject->KeyBodyList);
|
|
||||||
|
|
||||||
/* Create the actual handle to the object */
|
|
||||||
Status = CmpCreateHandle(KeyObject,
|
|
||||||
DesiredAccess,
|
|
||||||
ObjectCreateInfo.Attributes,
|
|
||||||
&hKey);
|
|
||||||
|
|
||||||
/* Free the create information */
|
|
||||||
ObpFreeAndReleaseCapturedAttributes(OBJECT_TO_OBJECT_HEADER(KeyObject)->ObjectCreateInfo);
|
|
||||||
OBJECT_TO_OBJECT_HEADER(KeyObject)->ObjectCreateInfo = NULL;
|
|
||||||
if (!NT_SUCCESS(Status)) goto Cleanup;
|
|
||||||
|
|
||||||
/* Add the keep-alive reference */
|
|
||||||
ObReferenceObject(KeyObject);
|
|
||||||
|
|
||||||
/* Unlock registry */
|
|
||||||
CmpUnlockRegistry();
|
|
||||||
|
|
||||||
/* Force a lazy flush */
|
|
||||||
CmpLazyFlush();
|
|
||||||
|
|
||||||
SuccessReturn:
|
|
||||||
/* Return data to user */
|
|
||||||
*KeyHandle = hKey;
|
|
||||||
if (Disposition) *Disposition = LocalDisposition;
|
|
||||||
|
|
||||||
Cleanup:
|
|
||||||
/* Cleanup */
|
|
||||||
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
|
||||||
if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
|
|
||||||
RtlFreeUnicodeString(&ReturnedPath);
|
|
||||||
if (Parent) ObDereferenceObject(Parent);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
|
||||||
NtOpenKey(OUT PHANDLE KeyHandle,
|
|
||||||
IN ACCESS_MASK DesiredAccess,
|
|
||||||
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
|
||||||
{
|
|
||||||
UNICODE_STRING RemainingPath = {0};
|
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
||||||
PCM_KEY_BODY Object = NULL;
|
|
||||||
HANDLE hKey = NULL;
|
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
|
||||||
UNICODE_STRING ObjectName;
|
|
||||||
OBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
|
||||||
PAGED_CODE();
|
|
||||||
|
|
||||||
/* Capture all the info */
|
|
||||||
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
|
||||||
PreviousMode,
|
|
||||||
FALSE,
|
|
||||||
&ObjectCreateInfo,
|
|
||||||
&ObjectName);
|
|
||||||
if (!NT_SUCCESS(Status)) return Status;
|
|
||||||
|
|
||||||
/* Loop every terminating slash */
|
|
||||||
while ((ObjectName.Length) &&
|
|
||||||
(ObjectName.Buffer[(ObjectName.Length / sizeof(WCHAR)) - 1] ==
|
|
||||||
OBJ_NAME_PATH_SEPARATOR))
|
|
||||||
{
|
|
||||||
/* And remove it */
|
|
||||||
ObjectName.Length -= sizeof(WCHAR);
|
|
||||||
ObjectName.MaximumLength -= sizeof(WCHAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the key */
|
|
||||||
Status = CmFindObject(&ObjectCreateInfo,
|
|
||||||
&ObjectName,
|
|
||||||
(PVOID*)&Object,
|
|
||||||
&RemainingPath,
|
|
||||||
CmpKeyObjectType,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status)) goto openkey_cleanup;
|
|
||||||
|
|
||||||
/* Make sure we don't have any remaining path */
|
|
||||||
if ((RemainingPath.Buffer) && (RemainingPath.Buffer[0] != UNICODE_NULL))
|
|
||||||
{
|
|
||||||
/* Fail */
|
|
||||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
||||||
goto openkey_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the key has been deleted */
|
|
||||||
if (Object->KeyControlBlock->Delete)
|
|
||||||
{
|
|
||||||
/* Fail */
|
|
||||||
Status = STATUS_UNSUCCESSFUL;
|
|
||||||
goto openkey_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the actual handle */
|
|
||||||
Status = CmpCreateHandle(Object,
|
|
||||||
DesiredAccess,
|
|
||||||
ObjectCreateInfo.Attributes,
|
|
||||||
&hKey);
|
|
||||||
|
|
||||||
openkey_cleanup:
|
|
||||||
/* Cleanup */
|
|
||||||
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
|
||||||
if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
|
|
||||||
RtlFreeUnicodeString(&RemainingPath);
|
|
||||||
if (Object) ObDereferenceObject(Object);
|
|
||||||
|
|
||||||
/* Return information and status to user */
|
|
||||||
*KeyHandle = hKey;
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* EOF */
|
|
|
@ -875,4 +875,181 @@ CmiGetLinkTarget(PCMHIVE RegistryHive,
|
||||||
return(STATUS_SUCCESS);
|
return(STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
NtCreateKey(OUT PHANDLE KeyHandle,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
|
IN ULONG TitleIndex,
|
||||||
|
IN PUNICODE_STRING Class,
|
||||||
|
IN ULONG CreateOptions,
|
||||||
|
OUT PULONG Disposition)
|
||||||
|
{
|
||||||
|
UNICODE_STRING RemainingPath = {0}, ReturnedPath = {0};
|
||||||
|
ULONG LocalDisposition;
|
||||||
|
PCM_KEY_BODY KeyObject, Parent;
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
UNICODE_STRING ObjectName;
|
||||||
|
OBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
||||||
|
ULONG i;
|
||||||
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
HANDLE hKey;
|
||||||
|
PCM_KEY_NODE Node, ParentNode;
|
||||||
|
CM_PARSE_CONTEXT ParseContext = {0};
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Setup the parse context */
|
||||||
|
ParseContext.CreateOperation = TRUE;
|
||||||
|
ParseContext.CreateOptions = CreateOptions;
|
||||||
|
if (Class) ParseContext.Class = *Class;
|
||||||
|
|
||||||
|
/* Capture all the info */
|
||||||
|
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
||||||
|
PreviousMode,
|
||||||
|
FALSE,
|
||||||
|
&ObjectCreateInfo,
|
||||||
|
&ObjectName);
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
|
/* Find the key object */
|
||||||
|
Status = CmFindObject(&ObjectCreateInfo,
|
||||||
|
&ObjectName,
|
||||||
|
(PVOID*)&Parent,
|
||||||
|
&ReturnedPath,
|
||||||
|
CmpKeyObjectType,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
if (!NT_SUCCESS(Status)) goto Cleanup;
|
||||||
|
|
||||||
|
/* Check if we found the entire path */
|
||||||
|
RemainingPath = ReturnedPath;
|
||||||
|
if (!RemainingPath.Length)
|
||||||
|
{
|
||||||
|
/* Check if the parent has been deleted */
|
||||||
|
if (Parent->KeyControlBlock->Delete)
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
DPRINT1("Object marked for delete!\n");
|
||||||
|
Status = STATUS_UNSUCCESSFUL;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new handle to the parent */
|
||||||
|
Status = CmpCreateHandle(Parent,
|
||||||
|
DesiredAccess,
|
||||||
|
ObjectCreateInfo.Attributes,
|
||||||
|
&hKey);
|
||||||
|
if (!NT_SUCCESS(Status)) goto Cleanup;
|
||||||
|
|
||||||
|
/* Tell the caller we did this */
|
||||||
|
LocalDisposition = REG_OPENED_EXISTING_KEY;
|
||||||
|
goto SuccessReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop every leading slash */
|
||||||
|
while ((RemainingPath.Length) &&
|
||||||
|
(*RemainingPath.Buffer == OBJ_NAME_PATH_SEPARATOR))
|
||||||
|
{
|
||||||
|
/* And remove it */
|
||||||
|
RemainingPath.Length -= sizeof(WCHAR);
|
||||||
|
RemainingPath.MaximumLength -= sizeof(WCHAR);
|
||||||
|
RemainingPath.Buffer++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop every terminating slash */
|
||||||
|
while ((RemainingPath.Length) &&
|
||||||
|
(RemainingPath.Buffer[(RemainingPath.Length / sizeof(WCHAR)) - 1] ==
|
||||||
|
OBJ_NAME_PATH_SEPARATOR))
|
||||||
|
{
|
||||||
|
/* And remove it */
|
||||||
|
RemainingPath.Length -= sizeof(WCHAR);
|
||||||
|
RemainingPath.MaximumLength -= sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now loop the entire path */
|
||||||
|
for (i = 0; i < RemainingPath.Length / sizeof(WCHAR); i++)
|
||||||
|
{
|
||||||
|
/* And check if we found slahes */
|
||||||
|
if (RemainingPath.Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
|
||||||
|
{
|
||||||
|
/* We don't create trees -- parent key doesn't exist, so fail */
|
||||||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now check if we're left with no name by this point */
|
||||||
|
if (!(RemainingPath.Length) || (RemainingPath.Buffer[0] == UNICODE_NULL))
|
||||||
|
{
|
||||||
|
/* Then fail since we can't do anything */
|
||||||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock the registry */
|
||||||
|
CmpLockRegistry();
|
||||||
|
|
||||||
|
/* Create the key */
|
||||||
|
Status = CmpDoCreate(Parent->KeyControlBlock->KeyHive,
|
||||||
|
Parent->KeyControlBlock->KeyCell,
|
||||||
|
NULL,
|
||||||
|
&RemainingPath,
|
||||||
|
KernelMode,
|
||||||
|
&ParseContext,
|
||||||
|
Parent->KeyControlBlock,
|
||||||
|
(PVOID*)&KeyObject);
|
||||||
|
if (!NT_SUCCESS(Status)) goto Cleanup;
|
||||||
|
|
||||||
|
/* If we got here, this is a new key */
|
||||||
|
LocalDisposition = REG_CREATED_NEW_KEY;
|
||||||
|
|
||||||
|
/* Get the parent node and the child node */
|
||||||
|
ParentNode = (PCM_KEY_NODE)HvGetCell(KeyObject->KeyControlBlock->ParentKcb->KeyHive,
|
||||||
|
KeyObject->KeyControlBlock->ParentKcb->KeyCell);
|
||||||
|
Node = (PCM_KEY_NODE)HvGetCell(KeyObject->KeyControlBlock->KeyHive,
|
||||||
|
KeyObject->KeyControlBlock->KeyCell);
|
||||||
|
|
||||||
|
/* Inherit some information */
|
||||||
|
Node->Parent = KeyObject->KeyControlBlock->ParentKcb->KeyCell;
|
||||||
|
Node->Security = ParentNode->Security;
|
||||||
|
KeyObject->KeyControlBlock->ValueCache.ValueList = Node->ValueList.List;
|
||||||
|
KeyObject->KeyControlBlock->ValueCache.Count = Node->ValueList.Count;
|
||||||
|
|
||||||
|
/* Link child to parent */
|
||||||
|
InsertTailList(&Parent->KeyControlBlock->KeyBodyListHead, &KeyObject->KeyBodyList);
|
||||||
|
|
||||||
|
/* Create the actual handle to the object */
|
||||||
|
Status = CmpCreateHandle(KeyObject,
|
||||||
|
DesiredAccess,
|
||||||
|
ObjectCreateInfo.Attributes,
|
||||||
|
&hKey);
|
||||||
|
|
||||||
|
/* Free the create information */
|
||||||
|
ObpFreeAndReleaseCapturedAttributes(OBJECT_TO_OBJECT_HEADER(KeyObject)->ObjectCreateInfo);
|
||||||
|
OBJECT_TO_OBJECT_HEADER(KeyObject)->ObjectCreateInfo = NULL;
|
||||||
|
if (!NT_SUCCESS(Status)) goto Cleanup;
|
||||||
|
|
||||||
|
/* Add the keep-alive reference */
|
||||||
|
ObReferenceObject(KeyObject);
|
||||||
|
|
||||||
|
/* Unlock registry */
|
||||||
|
CmpUnlockRegistry();
|
||||||
|
|
||||||
|
/* Force a lazy flush */
|
||||||
|
CmpLazyFlush();
|
||||||
|
|
||||||
|
SuccessReturn:
|
||||||
|
/* Return data to user */
|
||||||
|
*KeyHandle = hKey;
|
||||||
|
if (Disposition) *Disposition = LocalDisposition;
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
/* Cleanup */
|
||||||
|
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
||||||
|
if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
|
||||||
|
RtlFreeUnicodeString(&ReturnedPath);
|
||||||
|
if (Parent) ObDereferenceObject(Parent);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -231,11 +231,14 @@ typedef struct _CM_KEY_CONTROL_BLOCK
|
||||||
{
|
{
|
||||||
USHORT RefCount;
|
USHORT RefCount;
|
||||||
USHORT Flags;
|
USHORT Flags;
|
||||||
|
struct
|
||||||
|
{
|
||||||
ULONG ExtFlags:8;
|
ULONG ExtFlags:8;
|
||||||
ULONG PrivateAlloc:1;
|
ULONG PrivateAlloc:1;
|
||||||
ULONG Delete:1;
|
ULONG Delete:1;
|
||||||
ULONG DelayedCloseIndex:12;
|
ULONG DelayedCloseIndex:12;
|
||||||
ULONG TotalLevels:10;
|
ULONG TotalLevels:10;
|
||||||
|
};
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
CM_KEY_HASH KeyHash;
|
CM_KEY_HASH KeyHash;
|
||||||
|
@ -251,9 +254,12 @@ typedef struct _CM_KEY_CONTROL_BLOCK
|
||||||
PCM_NAME_CONTROL_BLOCK NameBlock;
|
PCM_NAME_CONTROL_BLOCK NameBlock;
|
||||||
PCM_KEY_SECURITY_CACHE CachedSecurity;
|
PCM_KEY_SECURITY_CACHE CachedSecurity;
|
||||||
CACHED_CHILD_LIST ValueCache;
|
CACHED_CHILD_LIST ValueCache;
|
||||||
|
union
|
||||||
|
{
|
||||||
PCM_INDEX_HINT_BLOCK IndexHint;
|
PCM_INDEX_HINT_BLOCK IndexHint;
|
||||||
ULONG HashKey;
|
ULONG HashKey;
|
||||||
ULONG SubKeyCount;
|
ULONG SubKeyCount;
|
||||||
|
};
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
LIST_ENTRY KeyBodyListHead;
|
LIST_ENTRY KeyBodyListHead;
|
||||||
|
|
|
@ -107,6 +107,8 @@ CmpDelayDerefKCBWorker(IN PVOID Context)
|
||||||
ASSERT(CmpDelayDerefKCBWorkItemActive);
|
ASSERT(CmpDelayDerefKCBWorkItemActive);
|
||||||
|
|
||||||
/* FIXME: TODO */
|
/* FIXME: TODO */
|
||||||
|
DPRINT1("CmpDelayDerefKCBWorker has work to do!\n");
|
||||||
|
return;
|
||||||
ASSERT(FALSE);
|
ASSERT(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,3 +309,4 @@ CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -312,9 +312,10 @@ NTAPI
|
||||||
CmpDereferenceNameControlBlockWithLock(IN PCM_NAME_CONTROL_BLOCK Ncb)
|
CmpDereferenceNameControlBlockWithLock(IN PCM_NAME_CONTROL_BLOCK Ncb)
|
||||||
{
|
{
|
||||||
PCM_NAME_HASH Current, *Next;
|
PCM_NAME_HASH Current, *Next;
|
||||||
|
ULONG ConvKey = Ncb->ConvKey;
|
||||||
|
|
||||||
/* Lock the NCB */
|
/* Lock the NCB */
|
||||||
CmpAcquireNcbLockExclusive(Ncb);
|
CmpAcquireNcbLockExclusiveByKey(ConvKey);
|
||||||
|
|
||||||
/* Decrease the reference count */
|
/* Decrease the reference count */
|
||||||
if (!(--Ncb->RefCount))
|
if (!(--Ncb->RefCount))
|
||||||
|
@ -342,7 +343,7 @@ CmpDereferenceNameControlBlockWithLock(IN PCM_NAME_CONTROL_BLOCK Ncb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release the lock */
|
/* Release the lock */
|
||||||
CmpReleaseNcbLock(Ncb);
|
CmpReleaseNcbLockByKey(ConvKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
|
@ -387,7 +388,7 @@ CmpReferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Increase the reference count */
|
/* Increase the reference count */
|
||||||
if (InterlockedIncrement((PLONG)&Kcb->RefCount) == 0)
|
if ((InterlockedIncrement((PLONG)&Kcb->RefCount) & 0xFFFF) == 0)
|
||||||
{
|
{
|
||||||
/* We've overflown to 64K references, bail out */
|
/* We've overflown to 64K references, bail out */
|
||||||
InterlockedDecrement((PLONG)&Kcb->RefCount);
|
InterlockedDecrement((PLONG)&Kcb->RefCount);
|
||||||
|
@ -512,8 +513,8 @@ CmpDereferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
OldRefCount = *(PLONG)&Kcb->RefCount;
|
OldRefCount = *(PLONG)&Kcb->RefCount;
|
||||||
NewRefCount = OldRefCount - 1;
|
NewRefCount = OldRefCount - 1;
|
||||||
|
|
||||||
/* Check if we still have refenreces */
|
/* Check if we still have references */
|
||||||
if( (NewRefCount & 0xffff) > 0)
|
if( (NewRefCount & 0xFFFF) > 0)
|
||||||
{
|
{
|
||||||
/* Do the dereference */
|
/* Do the dereference */
|
||||||
if (InterlockedCompareExchange((PLONG)&Kcb->RefCount,
|
if (InterlockedCompareExchange((PLONG)&Kcb->RefCount,
|
||||||
|
@ -544,7 +545,7 @@ CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
|
||||||
(CmpTestRegistryLockExclusive() == TRUE));
|
(CmpTestRegistryLockExclusive() == TRUE));
|
||||||
|
|
||||||
/* Check if this is the last reference */
|
/* Check if this is the last reference */
|
||||||
if (InterlockedDecrement((PLONG)&Kcb->RefCount) == 0)
|
if ((InterlockedDecrement((PLONG)&Kcb->RefCount) & 0xFFFF) == 0)
|
||||||
{
|
{
|
||||||
/* Check if we should do a direct delete */
|
/* Check if we should do a direct delete */
|
||||||
if (((CmpHoldLazyFlush) &&
|
if (((CmpHoldLazyFlush) &&
|
||||||
|
@ -821,3 +822,4 @@ EnlistKeyBodyWithKCB(IN PCM_KEY_BODY KeyBody,
|
||||||
/* FIXME: Implement once we don't link parents to children anymore */
|
/* FIXME: Implement once we don't link parents to children anymore */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -782,7 +782,7 @@ CmpCreateLinkNode(IN PHHIVE Hive,
|
||||||
/* Release it */
|
/* Release it */
|
||||||
HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
|
HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);
|
||||||
|
|
||||||
/* Set the parent adn flags */
|
/* Set the parent and flags */
|
||||||
KeyNode->Parent = LinkCell;
|
KeyNode->Parent = LinkCell;
|
||||||
KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
|
KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
|
||||||
|
|
||||||
|
@ -977,7 +977,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
PULONG LockedKcbs = NULL;
|
PULONG LockedKcbs = NULL;
|
||||||
BOOLEAN Result, Last;
|
BOOLEAN Result, Last;
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
DPRINT1("New style parse routine called: %wZ %wZ!\n", CompleteName, RemainingName);
|
|
||||||
|
|
||||||
/* Loop path separators at the end */
|
/* Loop path separators at the end */
|
||||||
while ((RemainingName->Length) &&
|
while ((RemainingName->Length) &&
|
||||||
|
@ -1003,7 +1002,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
|
|
||||||
/* Grab the KCB */
|
/* Grab the KCB */
|
||||||
Kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock;
|
Kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock;
|
||||||
DPRINT1("KCB Parse: %p\n", Kcb);
|
|
||||||
|
|
||||||
/* Lookup in the cache */
|
/* Lookup in the cache */
|
||||||
Status = CmpBuildHashStackAndLookupCache(ParseObject,
|
Status = CmpBuildHashStackAndLookupCache(ParseObject,
|
||||||
|
@ -1019,9 +1017,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
|
|
||||||
/* This is now the parent */
|
/* This is now the parent */
|
||||||
ParentKcb = Kcb;
|
ParentKcb = Kcb;
|
||||||
DPRINT1("ParentKcb Parse: %p\n", ParentKcb);
|
|
||||||
DPRINT1("Hive Parse: %p\n", Hive);
|
|
||||||
DPRINT1("Cell Parse: %p\n", Cell);
|
|
||||||
|
|
||||||
/* Check if everything was found cached */
|
/* Check if everything was found cached */
|
||||||
if (!TotalRemainingSubkeys) ASSERTMSG("Caching not implemented", FALSE);
|
if (!TotalRemainingSubkeys) ASSERTMSG("Caching not implemented", FALSE);
|
||||||
|
@ -1032,9 +1027,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
/* Check if this is a symlink */
|
/* Check if this is a symlink */
|
||||||
if (Kcb->Flags & KEY_SYM_LINK)
|
if (Kcb->Flags & KEY_SYM_LINK)
|
||||||
{
|
{
|
||||||
DPRINT1("Parsing sym link: %lx %lx %lx\n", Kcb->Flags, Status,
|
|
||||||
CompleteName);
|
|
||||||
|
|
||||||
/* Get the next name */
|
/* Get the next name */
|
||||||
Result = CmpGetNextName(&Current, &NextName, &Last);
|
Result = CmpGetNextName(&Current, &NextName, &Last);
|
||||||
Current.Buffer = NextName.Buffer;
|
Current.Buffer = NextName.Buffer;
|
||||||
|
@ -1072,10 +1064,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not implemented */
|
|
||||||
DPRINT1("Parsing sym link: %lx %wZ %wZ\n", Status,
|
|
||||||
CompleteName, &Current);
|
|
||||||
|
|
||||||
/* We're done */
|
/* We're done */
|
||||||
goto Quickie;
|
goto Quickie;
|
||||||
}
|
}
|
||||||
|
@ -1083,7 +1071,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
/* Get the key node */
|
/* Get the key node */
|
||||||
Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
|
Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
|
||||||
if (!Node) return STATUS_INSUFFICIENT_RESOURCES;
|
if (!Node) return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
DPRINT1("Node Parse: %p\n", Node);
|
|
||||||
|
|
||||||
/* Start parsing */
|
/* Start parsing */
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
Status = STATUS_NOT_IMPLEMENTED;
|
||||||
|
@ -1091,7 +1078,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
{
|
{
|
||||||
/* Get the next component */
|
/* Get the next component */
|
||||||
Result = CmpGetNextName(&Current, &NextName, &Last);
|
Result = CmpGetNextName(&Current, &NextName, &Last);
|
||||||
DPRINT1("Result Parse: %p\n", Result);
|
|
||||||
if ((Result) && (NextName.Length))
|
if ((Result) && (NextName.Length))
|
||||||
{
|
{
|
||||||
/* See if this is a sym link */
|
/* See if this is a sym link */
|
||||||
|
@ -1099,13 +1085,11 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
{
|
{
|
||||||
/* Find the subkey */
|
/* Find the subkey */
|
||||||
NextCell = CmpFindSubKeyByName(Hive, Node, &NextName);
|
NextCell = CmpFindSubKeyByName(Hive, Node, &NextName);
|
||||||
DPRINT1("NextCell Parse: %lx %wZ\n", NextCell, &NextName);
|
|
||||||
if (NextCell != HCELL_NIL)
|
if (NextCell != HCELL_NIL)
|
||||||
{
|
{
|
||||||
/* Get the new node */
|
/* Get the new node */
|
||||||
Cell = NextCell;
|
Cell = NextCell;
|
||||||
Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
|
Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
|
||||||
DPRINT1("Node Parse: %p\n", Node);
|
|
||||||
if (!Node) ASSERT(FALSE);
|
if (!Node) ASSERT(FALSE);
|
||||||
|
|
||||||
/* Check if this was the last key */
|
/* Check if this was the last key */
|
||||||
|
@ -1115,13 +1099,11 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
if (Node->Flags & KEY_HIVE_EXIT)
|
if (Node->Flags & KEY_HIVE_EXIT)
|
||||||
{
|
{
|
||||||
/* Handle it */
|
/* Handle it */
|
||||||
DPRINT1("Exit node\n");
|
|
||||||
CmpHandleExitNode(&Hive,
|
CmpHandleExitNode(&Hive,
|
||||||
&Cell,
|
&Cell,
|
||||||
&Node,
|
&Node,
|
||||||
&HiveToRelease,
|
&HiveToRelease,
|
||||||
&CellToRelease);
|
&CellToRelease);
|
||||||
DPRINT1("Node Parse: %p\n", Node);
|
|
||||||
if (!Node) ASSERT(FALSE);
|
if (!Node) ASSERT(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1139,9 +1121,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
Object);
|
Object);
|
||||||
if (Status == STATUS_REPARSE)
|
if (Status == STATUS_REPARSE)
|
||||||
{
|
{
|
||||||
DPRINT1("Parsing sym link: %lx %lx\n", Status,
|
|
||||||
CompleteName);
|
|
||||||
|
|
||||||
/* Parse the symlink */
|
/* Parse the symlink */
|
||||||
if (!CmpGetSymbolicLink(Hive,
|
if (!CmpGetSymbolicLink(Hive,
|
||||||
CompleteName,
|
CompleteName,
|
||||||
|
@ -1151,15 +1130,9 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
/* Symlink parse failed */
|
/* Symlink parse failed */
|
||||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not implemented */
|
|
||||||
DPRINT1("Parsing sym link: %lx %wZ\n", Status,
|
|
||||||
CompleteName);
|
|
||||||
while (TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We are done */
|
/* We are done */
|
||||||
DPRINT1("Open of last key\n");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1167,13 +1140,11 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
if (Node->Flags & KEY_HIVE_EXIT)
|
if (Node->Flags & KEY_HIVE_EXIT)
|
||||||
{
|
{
|
||||||
/* Handle it */
|
/* Handle it */
|
||||||
DPRINT1("Exit node: %lx\n", Node->Flags);
|
|
||||||
CmpHandleExitNode(&Hive,
|
CmpHandleExitNode(&Hive,
|
||||||
&Cell,
|
&Cell,
|
||||||
&Node,
|
&Node,
|
||||||
&HiveToRelease,
|
&HiveToRelease,
|
||||||
&CellToRelease);
|
&CellToRelease);
|
||||||
DPRINT1("Node Parse: %p\n", Node);
|
|
||||||
if (!Node) ASSERT(FALSE);
|
if (!Node) ASSERT(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1185,10 +1156,9 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
0,
|
0,
|
||||||
&NextName);
|
&NextName);
|
||||||
if (!Kcb) ASSERT(FALSE);
|
if (!Kcb) ASSERT(FALSE);
|
||||||
DPRINT1("Kcb Parse: %p\n", Kcb);
|
|
||||||
|
|
||||||
/* Dereference the parent and set the new one */
|
/* Dereference the parent and set the new one */
|
||||||
CmpDereferenceKeyControlBlock(ParentKcb);
|
//CmpDereferenceKeyControlBlock(ParentKcb);
|
||||||
ParentKcb = Kcb;
|
ParentKcb = Kcb;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1211,7 +1181,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
ParseContext,
|
ParseContext,
|
||||||
ParentKcb,
|
ParentKcb,
|
||||||
Object);
|
Object);
|
||||||
DPRINT1("Link created: %lx\n", Status);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1242,9 +1211,6 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DPRINT1("Parsing sym link: %lx %lx\n", Status,
|
|
||||||
CompleteName);
|
|
||||||
|
|
||||||
/* Save the next name */
|
/* Save the next name */
|
||||||
Current.Buffer = NextName.Buffer;
|
Current.Buffer = NextName.Buffer;
|
||||||
|
|
||||||
|
@ -1281,19 +1247,46 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not implemented */
|
|
||||||
DPRINT1("Parsing sym link: %lx %wZ %wZ\n", Status,
|
|
||||||
CompleteName, &Current);
|
|
||||||
|
|
||||||
/* We're done */
|
/* We're done */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((Result) && (Last))
|
else if ((Result) && (Last))
|
||||||
{
|
{
|
||||||
/* Opening root: unexpected */
|
/* Opening the root. Is this an exit node? */
|
||||||
DPRINT1("Unexpected: Opening root\n");
|
if (Node->Flags & KEY_HIVE_EXIT)
|
||||||
while (TRUE);
|
{
|
||||||
|
/* Handle it */
|
||||||
|
CmpHandleExitNode(&Hive,
|
||||||
|
&Cell,
|
||||||
|
&Node,
|
||||||
|
&HiveToRelease,
|
||||||
|
&CellToRelease);
|
||||||
|
if (!Node) ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: This hack seems required? */
|
||||||
|
RtlInitUnicodeString(&NextName, L"\\REGISTRY");
|
||||||
|
|
||||||
|
/* Do the open */
|
||||||
|
Status = CmpDoOpen(Hive,
|
||||||
|
Cell,
|
||||||
|
Node,
|
||||||
|
AccessState,
|
||||||
|
AccessMode,
|
||||||
|
Attributes,
|
||||||
|
ParseContext,
|
||||||
|
0,
|
||||||
|
&Kcb,
|
||||||
|
&NextName,
|
||||||
|
Object);
|
||||||
|
if (Status == STATUS_REPARSE)
|
||||||
|
{
|
||||||
|
/* Nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're done */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1305,7 +1298,7 @@ CmpParseKey2(IN PVOID ParseObject,
|
||||||
|
|
||||||
/* Dereference the parent if it exists */
|
/* Dereference the parent if it exists */
|
||||||
Quickie:
|
Quickie:
|
||||||
if (ParentKcb) CmpDereferenceKeyControlBlock(ParentKcb);
|
//if (ParentKcb) CmpDereferenceKeyControlBlock(ParentKcb);
|
||||||
|
|
||||||
/* Unlock the registry */
|
/* Unlock the registry */
|
||||||
CmpUnlockRegistry();
|
CmpUnlockRegistry();
|
||||||
|
|
|
@ -18,6 +18,25 @@ BOOLEAN CmFirstTime = TRUE;
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
NtOpenKey(OUT PHANDLE KeyHandle,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
||||||
|
{
|
||||||
|
CM_PARSE_CONTEXT ParseContext = {0};
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Just let the object manager handle this */
|
||||||
|
return ObOpenObjectByName(ObjectAttributes,
|
||||||
|
CmpKeyObjectType,
|
||||||
|
ExGetPreviousMode(),
|
||||||
|
NULL,
|
||||||
|
DesiredAccess,
|
||||||
|
&ParseContext,
|
||||||
|
KeyHandle);
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
NtDeleteKey(IN HANDLE KeyHandle)
|
NtDeleteKey(IN HANDLE KeyHandle)
|
||||||
|
@ -470,28 +489,12 @@ NtFlushKey(IN HANDLE KeyHandle)
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
|
||||||
NtCompactKeys(IN ULONG Count,
|
|
||||||
IN PHANDLE KeyArray)
|
|
||||||
{
|
|
||||||
UNIMPLEMENTED;
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
|
||||||
NtCompressKey(IN HANDLE Key)
|
|
||||||
{
|
|
||||||
UNIMPLEMENTED;
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
IN POBJECT_ATTRIBUTES FileObjectAttributes)
|
IN POBJECT_ATTRIBUTES FileObjectAttributes)
|
||||||
{
|
{
|
||||||
|
/* Call the newer API */
|
||||||
return NtLoadKey2(KeyObjectAttributes, FileObjectAttributes, 0);
|
return NtLoadKey2(KeyObjectAttributes, FileObjectAttributes, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,6 +504,7 @@ NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
IN POBJECT_ATTRIBUTES FileObjectAttributes,
|
IN POBJECT_ATTRIBUTES FileObjectAttributes,
|
||||||
IN ULONG Flags)
|
IN ULONG Flags)
|
||||||
{
|
{
|
||||||
|
/* Call the newer API */
|
||||||
return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL);
|
return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,6 +559,34 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
NtNotifyChangeKey(IN HANDLE KeyHandle,
|
||||||
|
IN HANDLE Event,
|
||||||
|
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
||||||
|
IN PVOID ApcContext OPTIONAL,
|
||||||
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
IN ULONG CompletionFilter,
|
||||||
|
IN BOOLEAN WatchTree,
|
||||||
|
OUT PVOID Buffer,
|
||||||
|
IN ULONG Length,
|
||||||
|
IN BOOLEAN Asynchronous)
|
||||||
|
{
|
||||||
|
/* Call the newer API */
|
||||||
|
return NtNotifyChangeMultipleKeys(KeyHandle,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
Event,
|
||||||
|
ApcRoutine,
|
||||||
|
ApcContext,
|
||||||
|
IoStatusBlock,
|
||||||
|
CompletionFilter,
|
||||||
|
WatchTree,
|
||||||
|
Buffer,
|
||||||
|
Length,
|
||||||
|
Asynchronous);
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
NtInitializeRegistry(IN USHORT Flag)
|
NtInitializeRegistry(IN USHORT Flag)
|
||||||
|
@ -617,6 +649,23 @@ NtInitializeRegistry(IN USHORT Flag)
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
NtCompactKeys(IN ULONG Count,
|
||||||
|
IN PHANDLE KeyArray)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
NtCompressKey(IN HANDLE Key)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
NtLockProductActivationKeys(IN PULONG pPrivateVer,
|
NtLockProductActivationKeys(IN PULONG pPrivateVer,
|
||||||
|
@ -653,33 +702,6 @@ NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
|
||||||
NtNotifyChangeKey(IN HANDLE KeyHandle,
|
|
||||||
IN HANDLE Event,
|
|
||||||
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
|
||||||
IN PVOID ApcContext OPTIONAL,
|
|
||||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
|
||||||
IN ULONG CompletionFilter,
|
|
||||||
IN BOOLEAN WatchTree,
|
|
||||||
OUT PVOID Buffer,
|
|
||||||
IN ULONG Length,
|
|
||||||
IN BOOLEAN Asynchronous)
|
|
||||||
{
|
|
||||||
return NtNotifyChangeMultipleKeys(KeyHandle,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
Event,
|
|
||||||
ApcRoutine,
|
|
||||||
ApcContext,
|
|
||||||
IoStatusBlock,
|
|
||||||
CompletionFilter,
|
|
||||||
WatchTree,
|
|
||||||
Buffer,
|
|
||||||
Length,
|
|
||||||
Asynchronous);
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
NtQueryMultipleValueKey(IN HANDLE KeyHandle,
|
NtQueryMultipleValueKey(IN HANDLE KeyHandle,
|
||||||
|
|
|
@ -139,7 +139,6 @@
|
||||||
<file>ntapi.c</file>
|
<file>ntapi.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
<directory name="cm">
|
<directory name="cm">
|
||||||
<file>ntfunc.c</file>
|
|
||||||
<file>regobj.c</file>
|
<file>regobj.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
<directory name="dbgk">
|
<directory name="dbgk">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue