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 );
|
||
}
|