/*++

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    cmdata.h

Abstract:

    This module contains data structures used by the 
    configuration manager.

--*/

#ifndef __CM_DATA__
#define __CM_DATA__

// \nt\private\ntos\inc\hivedata.h
#include "hivedata.h"


//
// Limits on lengths of names, all in BYTES, all INCLUDING nulls.
//

#define MAX_KEY_PATH_LENGTH         65535       
#define MAX_FRIENDLY_NAME_LENGTH    160         // allow for 80  unicode chars in FriendlyNames


//
// ----- Control structures, object manager structures ------
//


//
// CM_KEY_CONTROL_BLOCK
//
// One key control block exists for each open key.  All of the key objects
// (open instances) for the key refer to the key control block.
//


typedef ULONG HASH_VALUE;

typedef struct _CM_KEY_HASH {
    ULONG   ConvKey;
    struct _CM_KEY_HASH *NextHash;
    PHHIVE     KeyHive;                         // Hive containing CM_KEY_NODE
    HCELL_INDEX KeyCell;                        // Cell containing CM_KEY_NODE
} CM_KEY_HASH, *PCM_KEY_HASH;

typedef struct _CM_NAME_HASH {
    ULONG   ConvKey;
    struct _CM_NAME_HASH *NextHash;
    USHORT  NameLength;      // Length of string value
    WCHAR   Name[1] ;        // The actual string value
} CM_NAME_HASH, *PCM_NAME_HASH;

typedef struct _CM_KEY_HASH_TABLE_ENTRY {
    EX_PUSH_LOCK    Lock;
    PKTHREAD        Owner;      // exclusive owner so we don't do unnecessary reacquires.
    PCM_KEY_HASH    Entry;
} CM_KEY_HASH_TABLE_ENTRY, *PCM_KEY_HASH_TABLE_ENTRY;

typedef struct _CM_NAME_HASH_TABLE_ENTRY {
    EX_PUSH_LOCK    Lock;
    PCM_NAME_HASH   Entry;
} CM_NAME_HASH_TABLE_ENTRY, *PCM_NAME_HASH_TABLE_ENTRY;

#ifdef CM_DEBUG_KCB
#define KCB_SIGNATURE 'bKmC'

#define SET_KCB_SIGNATURE(_kcb_,_sig_) (_kcb_)->Signature = (_sig_)
#define ASSERT_KCB(_kcb_) ASSERT((_kcb_)->Signature == KCB_SIGNATURE)
#define ASSERT_KEY_HASH(_keyhash_) ASSERT_KCB(CONTAINING_RECORD((_keyhash_), CM_KEY_CONTROL_BLOCK, KeyHash))
#else
#define SET_KCB_SIGNATURE(_kcb_,_sig_)
#define ASSERT_KCB(_kcb_)
#define ASSERT_KEY_HASH(_keyhash_)
#endif



//
// The registry is a large data structure that has had poor locality.
// To improve performance without changing the on disk structure, we
// cache the frequently used registry data to minimize reference on
// registry data.
//
// A KCB (Key Control Block) is the core structure for registry cache.
// It uses HashValue for quick cache lookup and contains the most
// frequently used data in a key node.
//
// It contains the most frequently used data in a key node:
// Security, Flags, and Value index.
//
// A KCB may also contains additional information
// (which are cached lazily) about its subkeys, value nodes and values' data.
//
// The subkey information is distinquished by ExtFlags.  See CM_KCB_* below.
// The value nodes and data are distinguished by a bit in the variable.
// See CMP_IS_CELL_CACHED.
//
// Caches for value data will be created during query process, the cached
// structure is shown as the following picture.  The structure is almost
// the same as the registry structure
// except they are pointers to the allocation instead of offset index on hive.
//
// To minimize the name string storage space KCB's,  we do not store the complete
// path name of the key in the kcb, instead, we implemented the tree structure
// (like the registry hive structure) to share name prefix.
// Also, knowing that there are lots of keys sharing same names,
// we create NameBlock structure so KCB's of same names
// can share the NameBlock.  NameBlock is compressed.
//
// Meanings when the following bits are set in ExtFlags:
// 1. The following bits are used for Parse and are for
//    non-symbolic keys.  Also, at most one bit can be set at any given time.
//    CM_KCB_KEY_NON_EXIST : This key is a fake key (no such key in the hive).
//    CM_KCB_NO_SUBKEY     : This key is has no subkey.
//    CM_KCB_SUBKEY_ONE    : This key has only one subkey and IndexHint is
//                           the first four characters of this subkey.
//    CM_KCB_SUBKEY_HINT   : This key has the first four characters of all
//                           its subkeys (buffer pointed by IndexHint).
//
// 2. CM_KCB_SYM_LINK_FOUND: This bit is only for symbolic keys.  It
//                           indicates that the symbolic link has been
//                           resolved and the KCB for the link is pointed to
//                           by ValueCache.RealKcb.
//                           In this case, the Value Index of this key is no longer
//                           available in the KCB.  (We hardly query the value
//                           of a symbolic link key other than finding the path
//                           of the real key anyway).
//
// 3. CM_KCB_NO_DELAY_CLOSE: This bit is only used for non-symbolic keys and is
//                           independent of bits on item 1. When set, it indicates that
//                           key should not be kept in delay close when the reference
//                           count goes to zero.
//                           This is for the case when a key has no open handles but
//                           still has subkeys in the cache.
//                           When its last subkey is kicked out of cache, we do not
//                           want to keep this key around.
//                           This is done so CmpSearchForOpenSubKeysInCachen can clean
//                           up the cache properly before a key can be unloaded.
//
//
//   KCB
//   +-------------------+
//   | ...               |      (Typical case)
//   +-------------------+      Value Index
//   | ValueCache        |  +-->+---------+         Value Key (with small data)
//   +  +----------------+  |   |        o--------->+-----------+
//   |  | ValueList     o---+   +---------+         | ....      |
//   |  +---- Union -----|      |         |         +-----------+
//   |  | RealKcb       o---+   +---------+         | Data (S)  |
//   |  +----------------|  |   |         |         +-----------+
//   |                   |  |   +---------+
//   |                   |  |   |         |
//   |                   |  |   +---------+         Value Key (with large data)
//   |                   |  |   |        o--------->+-----------+
//   |                   |  |   +---------+         | ...       |
//   |                   |  |   |         |         +-----------+
//   |                   |  |   +---------+         | Data (L) o------+
//   |                   |  |                       +-----------+     |
//   |                   |  |                       |           | <---+ (Append at the end of Value Node)
//   |                   |  |                       |           |
//   |                   |  |                       |           |
//   |                   |  |                       +-----------+
//   |                   |  |
//   |                   |  |   KCB (Symbolic link key, CM_KCB_SYM_LINK_FOUND set).
//   |                   |  +-->+---------+
//   |                   |      |         |
//   |                   |      |         |
//   |                   |      |         |
//   |                   |      |         |
//   |                   |      |         |
//   |                   |      +---------+
//   |                   |
//   | ...               |
//   +-------------------+      Index Hint
//   | IndexHint        o------>+---------+
//   +-------------------+      | 4 char  |
//   |                   |      +---------+
//   |                   |      | 4 char  |
//   +-------------------+      +---------+
//   |                   |      (CM_KCB_SUBKEY_HINT)
//   |                   |
//   |                   |
//   +-------------------+                 Name Block
//   | NameBlock        o----------------->+----------+
//   +-------------------+                 |          |
//                                         +----------+
//
//
// The TotalLevels is used for quick comparison for notification and cache lookup.
//
// *** MP Synchronization ***
// The KCB lock is held for any write to KCB unless the registry is locked exclusively.
// KCB is also locked while reading fields that can be modified by another thread
// during a read operation, i.e., when the registry lock is held shared.
//
// The fields are the follows: ExtFlags, ValueCache, IndexInfo, IndexHint, or NameHint.
//
// Reading of other entries in the KCB does not need to hold the KCB lock since
// these entries will not change for any registry read operation.  When there
// are changes to these entries, registry must be locked exclusively.
//
// NOTE: the KCB size is 56 bytes now, plus the pool header of 8 bytes,
//       it fits into a 64byte allocation.  Think carefully if you want to
//       enlarge the data structure.  Also, watch it if the pool allocation code changes.
//
//       The RefCount in KCB is the number of open handles plus the number of cached subkeys.
//       We can change this by having a RefCount and a CachedSubKeyCount.  To not grow the
//       structure size, we can merge the boolean Delete into ExtFlags.

//
// As of Windows XP, the Name in the NameBlock is Always UpperCase
//
typedef struct _CM_NAME_CONTROL_BLOCK {
    BOOLEAN     Compressed;       // Flags to indicate which extension we have.
    USHORT      RefCount;
    union {
        CM_NAME_HASH             NameHash;
        struct {
            ULONG   ConvKey;
            struct _CM_KEY_HASH *NextHash;
            USHORT  NameLength;      // Length of string value
            WCHAR   Name[1] ;      // The actual string value
        };
    };
} CM_NAME_CONTROL_BLOCK, *PCM_NAME_CONTROL_BLOCK;

typedef struct _CM_INDEX_HINT_BLOCK {
    ULONG   Count;
    ULONG   HashKey[1];        // hash key of name

} CM_INDEX_HINT_BLOCK, *PCM_INDEX_HINT_BLOCK;

typedef struct _CACHED_CHILD_LIST {
    ULONG       Count;                  // 0 for empty list
    union {
        ULONG_PTR   ValueList;
        struct _CM_KEY_CONTROL_BLOCK *RealKcb;
    };
} CACHED_CHILD_LIST, *PCACHED_CHILD_LIST;

//
// Define the HINT Length used
//
#define CM_SUBKEY_HINT_LENGTH   4
#define CM_MAX_CACHE_HINT_SIZE 14

//
// ----- Structures used to implement registry hierarchy -----
//

typedef enum _NODE_TYPE {
    KeyBodyNode,
    KeyValueNode
} NODE_TYPE;


typedef enum _CMP_COPY_TYPE {
    Copy,
    Sync,
    Merge
} CMP_COPY_TYPE;

typedef enum _SUBKEY_SEARCH_TYPE {
    SearchIfExist,
    SearchAndDeref,
    SearchAndCount,
    SearchAndRehash,
	SearchAndTagNoDelayClose
} SUBKEY_SEARCH_TYPE;

//
// ChildList
//
//      NOTE:   CHILD_LIST structures are normally referred to
//              with HCELL_INDEX, not PCHILD_LIST vars.
//

typedef struct _CHILD_LIST {
    ULONG       Count;                  // 0 for empty list
    HCELL_INDEX List;
} CHILD_LIST, *PCHILD_LIST;

//
// CM_KEY_REFERENCE
//

typedef struct  _CM_KEY_REFERENCE {
    HCELL_INDEX KeyCell;
    PHHIVE      KeyHive;
} CM_KEY_REFERENCE , *PCM_KEY_REFERENCE;

//
// ----- CM_KEY_INDEX -----
//
// A leaf index may be one of two types. The "old" CM_KEY_INDEX type is used for
// hives circa NT3.1, 3.5, and 3.51. NT4.0 introduces the newer CM_KEY_FAST_INDEX
// which is used for all leaf indexes that have less than CM_MAX_FAST_INDEX leaves.
//
// The main advantage of the fast index is that the first four characters of the
// names are stored within the index itself. This almost always saves us from having
// to fault in a number of unnecessary pages when searching for a given key.
//
// The main disadvantage is that each subkey requires twice as much storage. One dword
// for the HCELL_INDEX and one dword to hold the first four characters of the subkey
// name. If one of the first four characters in the subkey name is a unicode character
// where the high byte is non-zero, the actual subkey must be examined to determine the
// name.
//
// Hive version 1 & 2 do not support the fast index. Version 3 adds support for the
// fast index. All hives that are newly created on a V3-capable system are therefore
// unreadable on V1 & 2 systems.
//
// N.B. There is code in cmindex.c that relies on the Signature and Count fields of
//      CM_KEY_INDEX and CM_KEY_FAST_INDEX being at the same offset in the structure!

#define INVALID_INDEX           0x80000000  // index is not valid

#define UseFastIndex(Hive)      ((Hive)->Version >= 3)
#define UseHashIndex(Hive)      ((Hive)->Version >= HSYS_WHISTLER)

#define CM_KEY_INDEX_ROOT       0x6972      // ir
#define CM_KEY_INDEX_LEAF       0x696c      // il
#define CM_KEY_FAST_LEAF        0x666c      // fl
#define CM_KEY_HASH_LEAF        0x686c      // hl

typedef struct _CM_INDEX {
    HCELL_INDEX Cell;
    union {
        UCHAR       NameHint[4];    // upcased first four chars of name 
        ULONG       HashKey;        // hash key of name
    };
} CM_INDEX, *PCM_INDEX;

typedef struct _CM_KEY_FAST_INDEX {
    USHORT      Signature;              // also type selector
    USHORT      Count;
    CM_INDEX    List[1];                // Variable sized array
} CM_KEY_FAST_INDEX, *PCM_KEY_FAST_INDEX;

typedef struct _CM_KEY_INDEX {
    USHORT      Signature;              // also type selector
    USHORT      Count;
    HCELL_INDEX List[1];                // Variable sized array
} CM_KEY_INDEX, *PCM_KEY_INDEX;

//
// Allow index to grow to size that will cause allocation of exactly
// one logical block.  Works out to be 1013 entries.
//
#define CM_MAX_INDEX                                                        \
 ( (HBLOCK_SIZE-                                                             \
    (sizeof(HBIN)+FIELD_OFFSET(HCELL,u)+FIELD_OFFSET(CM_KEY_INDEX,List))) /  \
    sizeof(HCELL_INDEX) )

#define CM_MAX_LEAF_SIZE ((sizeof(HCELL_INDEX)*CM_MAX_INDEX) + \
                          (FIELD_OFFSET(CM_KEY_INDEX, List)))

//
// Allow index to grow to size that will cause allocation of exactly
// one logical block.  Works out to be approx. 500 entries.
//
#define CM_MAX_FAST_INDEX                                                    \
 ( (HBLOCK_SIZE-                                                             \
    (sizeof(HBIN)+FIELD_OFFSET(HCELL,u)+FIELD_OFFSET(CM_KEY_FAST_INDEX,List))) /  \
    sizeof(CM_INDEX) )

#define CM_MAX_FAST_LEAF_SIZE ((sizeof(CM_INDEX)*CM_MAX_FAST_INDEX) + \
                          (FIELD_OFFSET(CM_KEY_FAST_INDEX, List)))



//
// ----- CM_KEY_NODE -----
//

#define CM_KEY_NODE_SIGNATURE     0x6b6e           // "kn"
#define CM_LINK_NODE_SIGNATURE     0x6b6c          // "kl"

#define KEY_VOLATILE        0x0001      // This key (and all its children)
                                        // is volatile.

#define KEY_HIVE_EXIT       0x0002      // This key marks a boundary to another
                                        // hive (sort of a link).  The null
                                        // value entry contains the hive
                                        // and hive index of the root of the
                                        // child hive.

#define KEY_HIVE_ENTRY      0x0004      // This key is the root of a particular
                                        // hive.

#define KEY_NO_DELETE       0x0008      // This key cannot be deleted, period.

#define KEY_SYM_LINK        0x0010      // This key is really a symbolic link.
#define KEY_COMP_NAME       0x0020      // The name for this key is stored in a
                                        // compressed form.
#define KEY_PREDEF_HANDLE   0x0040      // There is no real key backing this,
                                        // return the predefined handle.
                                        // Predefined handles are stashed in
                                        // ValueList.Count.

#define KEY_USER_FLAGS_CLEAR_MASK   0x0FFF  // used to clear the user defined flags

#define KEY_USER_FLAGS_VALID_MASK   0x000F  // we only allow 4 bits for the user defined flags
                                            // (this is just for the time being) - we may extend 
                                            // this as we see fit)

#define KEY_USER_FLAGS_SHIFT        12      // shift count (to be updated if we change the number of flags)

#define KEY_BREAK_ON_OPEN		    0x8000  // used to determine if we need to break to dbg

#pragma pack(4)
typedef struct _CM_KEY_NODE {
    USHORT      Signature;
    USHORT      Flags;                      // first 4 bits are User defined flags !!!!
    LARGE_INTEGER LastWriteTime;
    ULONG       Spare;                      // not used, yet
    HCELL_INDEX Parent;
    ULONG       SubKeyCounts[HTYPE_COUNT];  // Stable and Volatile
    union {
        struct {
            HCELL_INDEX SubKeyLists[HTYPE_COUNT];   // Stable and Volatile
            CHILD_LIST  ValueList;
        };
        CM_KEY_REFERENCE    ChildHiveReference;
    };

    HCELL_INDEX Security;
    HCELL_INDEX Class;
    ULONG       MaxNameLen;
    ULONG       MaxClassLen;
    ULONG       MaxValueNameLen;
    ULONG       MaxValueDataLen;

    ULONG       WorkVar;                // WARNING: This DWORD is used
                                        //          by the system at run
                                        //          time, do attempt to
                                        //          store user data in it.

    USHORT      NameLength;
    USHORT      ClassLength;
    WCHAR       Name[1];                // Variable sized array
} CM_KEY_NODE, *PCM_KEY_NODE;
#pragma pack()

//
// ----- CM_KEY_VALUE -----
//

#define CM_KEY_VALUE_SIGNATURE      0x6b76                      // "kv"

#define CM_KEY_VALUE_SPECIAL_SIZE   0x80000000                  // 2 gig

#define CM_KEY_VALUE_SMALL          4


#define CM_KEY_VALUE_BIG            0x3fd8 // 16K ; Only new hive formats will have this
//
//  The above comes from this:
// (0x4000 - sizeof(HBIN) - ROUND_UP(FIELD_OFFSET(HCELL, u.NewCell.u.UserData),8) ) 
//


#define VALUE_COMP_NAME             0x0001                      // The name for this value is stored in a
                                                                // compressed form.
typedef struct _CM_KEY_VALUE {
    USHORT      Signature;
    USHORT      NameLength;
    ULONG       DataLength;
    HCELL_INDEX Data;
    ULONG       Type;
    USHORT      Flags;                      // Used to be TitleIndex
    USHORT      Spare;                      // Used to be TitleIndex
    WCHAR       Name[1];                    // Variable sized array
} CM_KEY_VALUE, *PCM_KEY_VALUE;

//
// realsize is set to real size, returns TRUE if small, else FALSE
//
#define CmpIsHKeyValueSmall(realsize, size)                     \
        ((size >= CM_KEY_VALUE_SPECIAL_SIZE) ?                  \
        ((realsize) = size - CM_KEY_VALUE_SPECIAL_SIZE, TRUE) : \
        ((realsize) = size, FALSE))

#define CmpIsHKeyValueBig(Hive,size)   ( (Hive->Version >= HSYS_WHISTLER_BETA1) && ((size) < CM_KEY_VALUE_SPECIAL_SIZE) && ((size) > CM_KEY_VALUE_BIG ) )

#define  ASSERT_KEY_VALUE(Value) ASSERT( (Value)->Signature == CM_KEY_VALUE_SIGNATURE )
//
// ----- CM_BIG_DATA ------
//

#define CM_BIG_DATA_SIGNATURE      0x6264                      // "bd"

typedef struct _CM_BIG_DATA {
    USHORT      Signature;
    USHORT      Count;              // 0 for empty list; this shouldn't happen
    HCELL_INDEX List;               // HCELL_NIL for empty list; this shouldn't happen
} CM_BIG_DATA, *PCM_BIG_DATA;

#define ASSERT_BIG_DATA(BigData) ASSERT( ((BigData)->Signature == CM_BIG_DATA_SIGNATURE) && ((BigData)->Count > 0 ) && ((BigData)->List != HCELL_NIL) );

//
// ----- CM_KEY_SECURITY -----
//

#define CM_KEY_SECURITY_SIGNATURE 0x6b73              // "ks"

typedef struct _CM_KEY_SECURITY {
    USHORT                  Signature;
    USHORT                  Reserved;
    HCELL_INDEX             Flink;
    HCELL_INDEX             Blink;
    ULONG                   ReferenceCount;
    ULONG                   DescriptorLength;
    SECURITY_DESCRIPTOR_RELATIVE     Descriptor;         // Variable length
} CM_KEY_SECURITY, *PCM_KEY_SECURITY;

//
// ----- CM_KEY_SECURITY_CACHE ----
//

typedef struct _CM_KEY_SECURITY_CACHE {
    HCELL_INDEX                     Cell;                   // security cellindex (inside the hive)
    ULONG                           ConvKey;                
    LIST_ENTRY                      List;
    ULONG                           DescriptorLength;
    SECURITY_DESCRIPTOR_RELATIVE    Descriptor;         // Variable length
} CM_KEY_SECURITY_CACHE, *PCM_KEY_SECURITY_CACHE;

typedef struct _CM_KEY_SECURITY_CACHE_ENTRY {
    HCELL_INDEX             Cell;                   // security cellindex (inside the hive) - 
                                                    // this is to avoid touching the Security pages 
                                                    // at lookup operations                                                        

    PCM_KEY_SECURITY_CACHE  CachedSecurity;               // actual security cell (cached)
} CM_KEY_SECURITY_CACHE_ENTRY, *PCM_KEY_SECURITY_CACHE_ENTRY;



//
// ----- CELL_DATA -----
//
// Union of types of data that could be in a cell
//

typedef struct _CELL_DATA {
    union _u {
        CM_KEY_NODE      KeyNode;
        CM_KEY_VALUE     KeyValue;
        CM_KEY_SECURITY  KeySecurity;    // Variable security descriptor length
        CM_KEY_INDEX     KeyIndex;       // Variable sized structure
        CM_BIG_DATA      ValueData;      // This is only for big cells; a list of cells 
                                         // all of the length CM_KEY_VALUE_BIG
        HCELL_INDEX      KeyList[1];     // Variable sized array
        WCHAR            KeyString[1];   // Variable sized array
    } u;
} CELL_DATA, *PCELL_DATA;


//
// Unions for KEY_INFORMATION, KEY_VALUE_INFORMATION
//

typedef union _KEY_INFORMATION {
    KEY_BASIC_INFORMATION   KeyBasicInformation;
    KEY_NODE_INFORMATION    KeyNodeInformation;
    KEY_FULL_INFORMATION    KeyFullInformation;
    KEY_NAME_INFORMATION    KeyNameInformation;
    KEY_CACHED_INFORMATION  KeyCachedInformation;
    KEY_FLAGS_INFORMATION   KeyFlagsInformation;
} KEY_INFORMATION, *PKEY_INFORMATION;

typedef union _KEY_VALUE_INFORMATION {
    KEY_VALUE_BASIC_INFORMATION KeyValueBasicInformation;
    KEY_VALUE_FULL_INFORMATION  KeyValueFullInformation;
    KEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInformation;
    KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 KeyValuePartialInformationAlign64;
} KEY_VALUE_INFORMATION, *PKEY_VALUE_INFORMATION;



//
// ----- CACHED_DATA -----
//
// When values are not cached, List in ValueCache is the Hive cell index to the value list.
// When they are cached, List will be pointer to the allocation.  We distinguish them by
// marking the lowest bit in the variable to indicate it is a cached allocation.
//
// Note that the cell index for value list
// is stored in the cached allocation.  It is not used now but may be in further performance
// optimization.
//
// When value key and vaule data are cached, there is only one allocation for both.
// Value data is appended that the end of value key.  DataCacheType indicates
// whether data is cached and ValueKeySize tells how big is the value key (so
// we can calculate the address of cached value data)
//
//

#define CM_CACHE_DATA_NOT_CACHED 0
#define CM_CACHE_DATA_CACHED     1
#define CM_CACHE_DATA_TOO_BIG    2
#define MAXIMUM_CACHED_DATA   2048  // Maximum data size to be cached.

typedef struct _CM_CACHED_VALUE_INDEX {
    HCELL_INDEX CellIndex;
    union {
        CELL_DATA        CellData;
        ULONG_PTR        List[1];
    } Data;
} CM_CACHED_VALUE_INDEX, *PCM_CACHED_VALUE_INDEX; // This is only used as a pointer.

typedef struct _CM_CACHED_VALUE {
    USHORT          DataCacheType;
    USHORT          ValueKeySize;
    ULONG           HashKey;
    CM_KEY_VALUE    KeyValue;
} CM_CACHED_VALUE, *PCM_CACHED_VALUE; // This is only used as a pointer.

typedef PCM_CACHED_VALUE *PPCM_CACHED_VALUE;

#define CMP_CELL_CACHED_MASK  1

#define CMP_IS_CELL_CACHED(Cell) (((ULONG_PTR) (Cell) & CMP_CELL_CACHED_MASK) && ((Cell) != (ULONG_PTR) HCELL_NIL))
#define CMP_GET_CACHED_ADDRESS(Cell) (((ULONG_PTR) (Cell)) & ~CMP_CELL_CACHED_MASK)
#define CMP_GET_CACHED_CELLDATA(Cell) (&(((PCM_CACHED_VALUE_INDEX)(((ULONG_PTR) (Cell)) & ~CMP_CELL_CACHED_MASK))->Data.CellData))
#define CMP_GET_CACHED_KEYVALUE(Cell) (&(((PCM_CACHED_VALUE)(((ULONG_PTR) (Cell)) & ~CMP_CELL_CACHED_MASK))->KeyValue))
#define CMP_GET_CACHED_CELL(Cell) (((PCM_CACHED_ENTRY)(((ULONG_PTR) (Cell)) & ~CMP_CELL_CACHED_MASK))->CellIndex)
#define CMP_MARK_CELL_CACHED(Cell) (((ULONG_PTR) (Cell)) | CMP_CELL_CACHED_MASK)

#define CMP_GET_CACHED_CELL_INDEX(Cell) (PtrToUlong((PVOID) (Cell)))


//
// Bits used in the ExtFlags in KCB.
//

#define CM_KCB_NO_SUBKEY        0x0001      // This key has no subkeys
#define CM_KCB_SUBKEY_ONE       0x0002      // This key has only one subkey and the
                                            // first 4 char
                                            //
#define CM_KCB_SUBKEY_HINT          0x0004
#define CM_KCB_SYM_LINK_FOUND       0x0008
#define CM_KCB_KEY_NON_EXIST        0x0010
#define CM_KCB_NO_DELAY_CLOSE       0x0020
#define CM_KCB_INVALID_CACHED_INFO  0x0040  // info stored in SubKeyCount is not valid, so we shouldn't rely on it

#define CM_KCB_CACHE_MASK (CM_KCB_NO_SUBKEY | \
                           CM_KCB_KEY_NON_EXIST | \
                           CM_KCB_SUBKEY_ONE | \
                           CM_KCB_SUBKEY_HINT)

#define CM_KCB_READ_ONLY_KEY        0x0080  // this kcb is read-only all write operations onto it are denied.

#define CMP_LOCK_FREE_KEY_BODY_ARRAY_SIZE                   4

#define CMP_KCB_REAL_NAME_UPCASE                            (PCHAR)1

typedef struct _CM_KEY_CONTROL_BLOCK {
#ifdef CM_DEBUG_KCB
    ULONG                       Signature;
#endif
    USHORT                      RefCount;
    USHORT                      Flags;          // Same Flags as KeyNode

    struct {
        ULONG                   ExtFlags            : 8;  // 00000000 00000000 00000000 ????????  Flags to indicate which extension we have.
        ULONG                   PrivateAlloc        : 1;  // 00000000 00000000 0000000? 00000000  are we allocated from our private pool?
        ULONG                   Delete              : 1;  // 00000000 00000000 000000?0 00000000
        ULONG                   DelayedCloseIndex   : 12; // 00000000 00?????? ??????00 00000000  CmpDelayedCloseSize  means it is 
                                                          //                                      not in the delay close table
        ULONG                   TotalLevels         : 10; // ???????? ??000000 00000000 00000000  max 512
    };

    union {
        CM_KEY_HASH             KeyHash;
        struct {
            ULONG               ConvKey;
            struct _CM_KEY_HASH *NextHash;
            PHHIVE              KeyHive;        // Hive containing CM_KEY_NODE
            HCELL_INDEX         KeyCell;        // Cell containing CM_KEY_NODE
        };
    };

    struct _CM_KEY_CONTROL_BLOCK *ParentKcb;
    PCM_NAME_CONTROL_BLOCK      NameBlock;

    PCM_KEY_SECURITY_CACHE      CachedSecurity; // pointer to cached security
    struct _CACHED_CHILD_LIST   ValueCache;
    union {                                                         // The hint is always stored in uppercase.
        PCM_INDEX_HINT_BLOCK    IndexHint;                          // CM_KCB_SUBKEY_HINT
        ULONG                   HashKey;                            // CM_KCB_SUBKEY_ONE
        ULONG                   SubKeyCount;                        // when none of the  CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT
                                                                    // is set in ExtFlags, we cache here the number of subkeys
                                                                    // (Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile])
    };

    union {
        LIST_ENTRY                  KeyBodyListHead;    // head of the list with all key_nodes using this kcb 
        LIST_ENTRY                  FreeListEntry;      // entry in the free kcbs list inside a page - when we use the private allocator
    };

    struct _CM_KEY_BODY         * KeyBodyArray[CMP_LOCK_FREE_KEY_BODY_ARRAY_SIZE];    // fast path; lock free

    PVOID                       DelayCloseEntry;    // back pointer to delay close table    
    //
    // Bellow is information cached from KEY_NODE for performance reasons.
    // Values here should be IDENTICAL with the ones in the corresponding KEY_NODE
    //
    LARGE_INTEGER               KcbLastWriteTime;  
    USHORT                      KcbMaxNameLen;
    USHORT                      KcbMaxValueNameLen;
    ULONG                       KcbMaxValueDataLen;
#if defined(_WIN64)
    PCHAR                       RealKeyName;            // == 1 means name is uppercase, NULL name not cached yet
#endif

#if DBG
    ULONG                       InDelayClose;
#endif //DBG

} CM_KEY_CONTROL_BLOCK, *PCM_KEY_CONTROL_BLOCK;


#endif //__CM_DATA__

