401 lines
12 KiB
C
401 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Regekey.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the server side implementation for the Win32
|
|||
|
Registry API to enumerate keys. That is:
|
|||
|
|
|||
|
- BaseRegEnumKey
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David J. Gilman (davegi) 23-Dec-1991
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
See the Notes in Regkey.c.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <rpc.h>
|
|||
|
#include "regrpc.h"
|
|||
|
#include "localreg.h"
|
|||
|
#include "regclass.h"
|
|||
|
#include "regecls.h"
|
|||
|
#include <malloc.h>
|
|||
|
|
|||
|
#define DEFAULT_KEY_NAME_SIZE 128
|
|||
|
#define DEFAULT_CLASS_SIZE 128
|
|||
|
|
|||
|
|
|||
|
|
|||
|
error_status_t
|
|||
|
BaseRegEnumKey (
|
|||
|
IN HKEY hKey,
|
|||
|
IN DWORD dwIndex,
|
|||
|
OUT PUNICODE_STRING lpName,
|
|||
|
OUT PUNICODE_STRING lpClass OPTIONAL,
|
|||
|
OUT PFILETIME lpftLastWriteTime OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Used to enumerate subkeys of an open key. This function copies the
|
|||
|
dwIndex-th subkey of hKey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - A handle to the open key. The keys returned are relative to
|
|||
|
the key pointed to by this key handle. Any of the predefined reserved
|
|||
|
handles or a previously opened key handle may be used for hKey.
|
|||
|
|
|||
|
dwIndex - The index of the subkey to return. Note that this is for
|
|||
|
convenience, subkeys are not ordered (a new subkey has an arbitrary
|
|||
|
index). Indexes start at 0.
|
|||
|
|
|||
|
lpName - Provides a pointer to a buffer to receive the name of the
|
|||
|
key.
|
|||
|
|
|||
|
lpClass - If present, provides a pointer to a buffer to receive the
|
|||
|
class of the key.
|
|||
|
|
|||
|
lpftLastWriteTime - The time when the value was last written (set or
|
|||
|
created).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns ERROR_SUCCESS (0) for success; error-code for failure.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
This function is guaranteed to operate correctly only if dwIndex
|
|||
|
starts at 0 and is incremented on successive calls without intervening
|
|||
|
calls to other registration APIs that will change the key.
|
|||
|
KEY_ENUMERATE_SUB_KEYS access is required.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG BufferLength;
|
|||
|
KEY_INFORMATION_CLASS KeyInformationClass;
|
|||
|
PVOID KeyInformation;
|
|||
|
ULONG ResultLength;
|
|||
|
BOOL fClassKey;
|
|||
|
|
|||
|
BYTE PrivateKeyInformation[ sizeof( KEY_NODE_INFORMATION ) +
|
|||
|
DEFAULT_KEY_NAME_SIZE +
|
|||
|
DEFAULT_CLASS_SIZE ];
|
|||
|
|
|||
|
ASSERT( lpName != NULL );
|
|||
|
|
|||
|
//
|
|||
|
// Protect ourselves against malicious callers passing NULL
|
|||
|
// pointers.
|
|||
|
//
|
|||
|
if (lpClass == NULL) {
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Call out to Perflib if the HKEY is HKEY_PERFOMANCE_DATA or
|
|||
|
// HKEY_PERFORMANCE_TEXT or HKEY_PERFORMANCE_NLSTEXT
|
|||
|
|
|||
|
if (hKey == HKEY_PERFORMANCE_DATA ||
|
|||
|
hKey == HKEY_PERFORMANCE_TEXT ||
|
|||
|
hKey == HKEY_PERFORMANCE_NLSTEXT ) {
|
|||
|
// if( hKey == HKEY_PERFORMANCE_DATA ) {
|
|||
|
return (error_status_t)PerfRegEnumKey (
|
|||
|
hKey,
|
|||
|
dwIndex,
|
|||
|
lpName,
|
|||
|
NULL,
|
|||
|
lpClass,
|
|||
|
lpftLastWriteTime
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// First we assume that the information we want will fit on
|
|||
|
// PrivateKeyValueInformattion
|
|||
|
//
|
|||
|
|
|||
|
KeyInformationClass = (ARGUMENT_PRESENT( lpClass->Buffer ))?
|
|||
|
KeyNodeInformation :
|
|||
|
KeyBasicInformation;
|
|||
|
|
|||
|
|
|||
|
KeyInformation = PrivateKeyInformation;
|
|||
|
BufferLength = sizeof( PrivateKeyInformation );
|
|||
|
|
|||
|
fClassKey = FALSE;
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// Query for the necessary information about the supplied key.
|
|||
|
//
|
|||
|
|
|||
|
#ifdef LOCAL
|
|||
|
//
|
|||
|
// For hkcr, we need to do special enumeration
|
|||
|
//
|
|||
|
if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
|
|||
|
|
|||
|
Status = EnumTableGetNextEnum( &gClassesEnumTable,
|
|||
|
hKey,
|
|||
|
dwIndex,
|
|||
|
KeyInformationClass,
|
|||
|
KeyInformation,
|
|||
|
BufferLength,
|
|||
|
&ResultLength);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status) || (NT_SUCCESS(Status) && ResultLength)) {
|
|||
|
fClassKey = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif // LOCAL
|
|||
|
|
|||
|
if (!fClassKey) {
|
|||
|
|
|||
|
Status = NtEnumerateKey( hKey,
|
|||
|
dwIndex,
|
|||
|
KeyInformationClass,
|
|||
|
KeyInformation,
|
|||
|
BufferLength,
|
|||
|
&ResultLength
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// A return value of STATUS_BUFFER_TOO_SMALL would mean that there
|
|||
|
// was not enough room for even the fixed portions of the structure.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( Status != STATUS_BUFFER_TOO_SMALL );
|
|||
|
|
|||
|
|
|||
|
if( Status == STATUS_BUFFER_OVERFLOW ) {
|
|||
|
//
|
|||
|
// The buffer defined in the stack wasn't big enough to hold
|
|||
|
// the Key information.
|
|||
|
// If the caller's buffer are big enough to hold the key name
|
|||
|
// and key class, then allocate a new buffer, and call the
|
|||
|
// NT API again.
|
|||
|
//
|
|||
|
if( ( ( KeyInformationClass == KeyBasicInformation ) &&
|
|||
|
( (ULONG)( lpName->MaximumLength ) >=
|
|||
|
(( PKEY_BASIC_INFORMATION )
|
|||
|
KeyInformation )->NameLength + sizeof(UNICODE_NULL)
|
|||
|
)
|
|||
|
) ||
|
|||
|
( ( KeyInformationClass == KeyNodeInformation ) &&
|
|||
|
( (ULONG)(lpName->MaximumLength) >=
|
|||
|
(( PKEY_NODE_INFORMATION )
|
|||
|
KeyInformation )->NameLength + sizeof(UNICODE_NULL)
|
|||
|
) &&
|
|||
|
(
|
|||
|
ARGUMENT_PRESENT( lpClass->Buffer )
|
|||
|
) &&
|
|||
|
(
|
|||
|
(ULONG)(lpClass->MaximumLength) >= (( PKEY_NODE_INFORMATION )
|
|||
|
KeyInformation )->ClassLength + sizeof(UNICODE_NULL)
|
|||
|
)
|
|||
|
)
|
|||
|
) {
|
|||
|
BufferLength = ResultLength;
|
|||
|
|
|||
|
KeyInformation = RtlAllocateHeap( RtlProcessHeap( ), 0,
|
|||
|
BufferLength
|
|||
|
);
|
|||
|
//
|
|||
|
// If the memory allocation fails, return a Registry error.
|
|||
|
//
|
|||
|
|
|||
|
if( ! KeyInformation ) {
|
|||
|
return ERROR_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query for the necessary information about the supplied key.
|
|||
|
// This may or may not include the class depending on lpClass->Buffer
|
|||
|
// as determined above.
|
|||
|
//
|
|||
|
|
|||
|
#ifdef LOCAL
|
|||
|
if (fClassKey) {
|
|||
|
//
|
|||
|
// For hkcr, we need to do special enumeration
|
|||
|
//
|
|||
|
Status = EnumTableGetNextEnum( &gClassesEnumTable,
|
|||
|
hKey,
|
|||
|
dwIndex,
|
|||
|
KeyInformationClass,
|
|||
|
KeyInformation,
|
|||
|
BufferLength,
|
|||
|
&ResultLength);
|
|||
|
|
|||
|
} else
|
|||
|
#endif // LOCAL
|
|||
|
{
|
|||
|
Status = NtEnumerateKey( hKey,
|
|||
|
dwIndex,
|
|||
|
KeyInformationClass,
|
|||
|
KeyInformation,
|
|||
|
BufferLength,
|
|||
|
&ResultLength
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( NT_SUCCESS( Status ) ) {
|
|||
|
//
|
|||
|
// Copy key name
|
|||
|
//
|
|||
|
|
|||
|
if( KeyInformationClass == KeyBasicInformation ) {
|
|||
|
//
|
|||
|
// Return the name length and the name of the key.
|
|||
|
// Note that the NUL byte is included so that RPC copies the
|
|||
|
// correct number of bytes. It is decremented on the client
|
|||
|
// side.
|
|||
|
//
|
|||
|
|
|||
|
if( (ULONG)(lpName->MaximumLength) >=
|
|||
|
(( PKEY_BASIC_INFORMATION )
|
|||
|
KeyInformation )->NameLength + sizeof( UNICODE_NULL ) ) {
|
|||
|
|
|||
|
lpName->Length = ( USHORT )
|
|||
|
(( PKEY_BASIC_INFORMATION )
|
|||
|
KeyInformation )->NameLength;
|
|||
|
|
|||
|
RtlMoveMemory( lpName->Buffer,
|
|||
|
(( PKEY_BASIC_INFORMATION )
|
|||
|
KeyInformation )->Name,
|
|||
|
lpName->Length
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// NUL terminate the value name.
|
|||
|
//
|
|||
|
|
|||
|
lpName->Buffer[ lpName->Length >> 1 ] = UNICODE_NULL;
|
|||
|
lpName->Length += sizeof( UNICODE_NULL );
|
|||
|
|
|||
|
} else {
|
|||
|
Status = STATUS_BUFFER_OVERFLOW;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If requested, return the last write time.
|
|||
|
//
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpftLastWriteTime )) {
|
|||
|
|
|||
|
*lpftLastWriteTime
|
|||
|
= *( PFILETIME )
|
|||
|
&(( PKEY_BASIC_INFORMATION ) KeyInformation )
|
|||
|
->LastWriteTime;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// Return the name length and the name of the key.
|
|||
|
// Note that the NUL byte is included so that RPC copies the
|
|||
|
// correct number of bytes. It is decremented on the client
|
|||
|
// side.
|
|||
|
//
|
|||
|
|
|||
|
if( ( (ULONG)(lpName->MaximumLength) >=
|
|||
|
(( PKEY_NODE_INFORMATION )
|
|||
|
KeyInformation )->NameLength + sizeof( UNICODE_NULL ) ) &&
|
|||
|
( (ULONG)(lpClass->MaximumLength) >=
|
|||
|
(( PKEY_NODE_INFORMATION )
|
|||
|
KeyInformation )->ClassLength + sizeof( UNICODE_NULL) )
|
|||
|
) {
|
|||
|
//
|
|||
|
// Copy the key name
|
|||
|
//
|
|||
|
lpName->Length = ( USHORT )
|
|||
|
(( PKEY_NODE_INFORMATION )
|
|||
|
KeyInformation )->NameLength;
|
|||
|
|
|||
|
RtlMoveMemory( lpName->Buffer,
|
|||
|
(( PKEY_NODE_INFORMATION )
|
|||
|
KeyInformation )->Name,
|
|||
|
lpName->Length
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// NUL terminate the key name.
|
|||
|
//
|
|||
|
|
|||
|
lpName->Buffer[ lpName->Length >> 1 ] = UNICODE_NULL;
|
|||
|
lpName->Length += sizeof( UNICODE_NULL );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Copy the key class
|
|||
|
//
|
|||
|
|
|||
|
lpClass->Length = (USHORT)
|
|||
|
((( PKEY_NODE_INFORMATION ) KeyInformation )->ClassLength );
|
|||
|
|
|||
|
RtlMoveMemory(
|
|||
|
lpClass->Buffer,
|
|||
|
( PBYTE ) KeyInformation
|
|||
|
+ (( PKEY_NODE_INFORMATION ) KeyInformation )->ClassOffset,
|
|||
|
(( PKEY_NODE_INFORMATION ) KeyInformation )->ClassLength
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// NUL terminate the class.
|
|||
|
//
|
|||
|
|
|||
|
lpClass->Buffer[ lpClass->Length >> 1 ] = UNICODE_NULL;
|
|||
|
|
|||
|
lpClass->Length += sizeof( UNICODE_NULL );
|
|||
|
|
|||
|
|
|||
|
} else {
|
|||
|
Status = STATUS_BUFFER_OVERFLOW;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If requested, return the last write time.
|
|||
|
//
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpftLastWriteTime )) {
|
|||
|
|
|||
|
*lpftLastWriteTime
|
|||
|
= *( PFILETIME )
|
|||
|
&(( PKEY_NODE_INFORMATION ) KeyInformation )
|
|||
|
->LastWriteTime;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( KeyInformation != PrivateKeyInformation ) {
|
|||
|
//
|
|||
|
// Free the buffer allocated.
|
|||
|
//
|
|||
|
|
|||
|
RtlFreeHeap( RtlProcessHeap( ), 0, KeyInformation );
|
|||
|
}
|
|||
|
|
|||
|
return (error_status_t)RtlNtStatusToDosError( Status );
|
|||
|
}
|