test: cmparse.c File Reference

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# cmparse.c File Reference

`#include "cmp.h"`

Go to the source code of this file.

## Classes

struct | _CM_HASH_ENTRY

## Defines

#define | CM_HASH_STACK_SIZE 30
#define | CmpStepThroughExit(h, c, n)
#define | CMP_PARSE_GOTO_NONE 0
#define | CMP_PARSE_GOTO_CREATE 1
#define | CMP_PARSE_GOTO_RETURN 2
#define | CMP_PARSE_GOTO_RETURN2 3

## Typedefs

typedef _CM_HASH_ENTRY | CM_HASH_ENTRY
typedef _CM_HASH_ENTRY * | PCM_HASH_ENTRY

## Functions

ULONG | CmpComputeHashValue (IN PCM_HASH_ENTRY HashStack, IN OUT ULONG *TotalSubkeys, IN ULONG BaseConvKey, IN PUNICODE_STRING RemainingName)
NTSTATUS | CmpCacheLookup (IN PCM_HASH_ENTRY HashStack, IN ULONG TotalRemainingSubkeys, OUT ULONG *MatchRemainSubkeyLevel, IN OUT PCM_KEY_CONTROL_BLOCK *Kcb, OUT PUNICODE_STRING RemainingName, OUT PHHIVE *Hive, OUT HCELL_INDEX *Cell)
VOID | CmpCacheAdd (IN PCM_HASH_ENTRY LastHashEntry, IN ULONG Count)
PCM_KEY_CONTROL_BLOCK | CmpAddInfoAfterParseFailure (PHHIVE Hive, HCELL_INDEX Cell, PCM_KEY_NODE Node, PCM_KEY_CONTROL_BLOCK kcb, PUNICODE_STRING NodeName)
BOOLEAN | CmpGetSymbolicLink (IN PHHIVE Hive, IN PCM_KEY_NODE Node, IN OUT PUNICODE_STRING ObjectName, IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb, IN PUNICODE_STRING RemainingName)
NTSTATUS | CmpDoOpen (IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PCM_KEY_NODE Node, IN PACCESS_STATE AccessState, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN PCM_PARSE_CONTEXT Context, IN BOOLEAN CompleteKeyCached, IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb, IN PUNICODE_STRING KeyName, OUT PVOID *Object)
NTSTATUS | CmpCreateLinkNode (IN PHHIVE Hive, IN HCELL_INDEX Cell, IN PACCESS_STATE AccessState, IN UNICODE_STRING Name, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN PCM_PARSE_CONTEXT Context, IN PCM_KEY_CONTROL_BLOCK ParentKcb, OUT PVOID *Object)
NTSTATUS | CmpParseKey (IN PVOID ParseObject, IN PVOID ObjectType, IN OUT PACCESS_STATE AccessState, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN OUT PUNICODE_STRING CompleteName, IN OUT PUNICODE_STRING RemainingName, IN OUT PVOID Context OPTIONAL, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, OUT PVOID *Object)
BOOLEAN | CmpGetNextName (IN OUT PUNICODE_STRING RemainingName, OUT PUNICODE_STRING NextName, OUT PBOOLEAN Last)

## Variables

ULONG | CmpCacheOnFlag = CM_CACHE_FAKE_KEY
PCMHIVE | CmpMasterHive
BOOLEAN | CmpNoMasterCreates
PCM_KEY_CONTROL_BLOCK | CmpKeyControlBlockRoot
UNICODE_STRING | CmSymbolicLinkValueName

## Define Documentation

#define CM_HASH_STACK_SIZE 30

| Definition at line 30 of file cmparse.c. Referenced by CmpComputeHashValue(), and CmpParseKey().

#define CMP_PARSE_GOTO_CREATE 1

| Definition at line 139 of file cmparse.c. Referenced by CmpParseKey().

#define CMP_PARSE_GOTO_NONE 0

| Definition at line 138 of file cmparse.c. Referenced by CmpParseKey().

#define CMP_PARSE_GOTO_RETURN 2

| Definition at line 140 of file cmparse.c. Referenced by CmpParseKey().

#define CMP_PARSE_GOTO_RETURN2 3

| Definition at line 141 of file cmparse.c. Referenced by CmpParseKey().

#define CmpStepThroughExit | ( | h,
|  | c,
|  | n |  | ) |

Value:

    if ((n)->Flags & KEY_HIVE_EXIT) {           \
        (h)=(n)->ChildHiveReference.KeyHive;    \
        (c)=(n)->ChildHiveReference.KeyCell;    \
        (n)=(PCM_KEY_NODE)HvGetCell((h),(c));   \
    }

Definition at line 131 of file cmparse.c.

Referenced by CmpParseKey().

## Typedef Documentation

typedef struct _CM_HASH_ENTRY CM_HASH_ENTRY

typedef struct _CM_HASH_ENTRY * PCM_HASH_ENTRY

## Function Documentation

PCM_KEY_CONTROL_BLOCK CmpAddInfoAfterParseFailure | ( | PHHIVE | Hive,
|  | HCELL_INDEX | Cell,
|  | PCM_KEY_NODE | Node,
|  | PCM_KEY_CONTROL_BLOCK | kcb,
|  | PUNICODE_STRING | NodeName
| ) |

Definition at line 2056 of file cmparse.c.

References Cell, CM_CACHE_FAKE_KEY, CM_KCB_NO_SUBKEY, CM_KCB_SUBKEY_HINT, CM_KCB_SUBKEY_ONE, CM_KEY_FAST_LEAF, CM_MAX_CACHE_HINT_SIZE, CM_SUBKEY_HINT_LENGTH, CmpCacheOnFlag, CmpCreateKeyControlBlock(), CmpDereferenceKeyControlBlock(), ExAllocatePoolWithTag, ExFreePoolWithTag, FALSE, Hive, HvGetCell, Index, kcb(), _CM_KEY_FAST_INDEX::List, LOCK_KCB_TREE, _CM_INDEX::NameHint, PagedPool, PROTECTED_POOL, Size, Stable, _HHIVE::StorageTypeCount, _CM_KEY_NODE::SubKeyCounts, _CM_KEY_NODE::SubKeyLists, TRUE, UNLOCK_KCB_TREE, UseFastIndex, USHORT, and Volatile.

Referenced by CmpParseKey().

    02065                    :
    02066
    02067     This routine builds up further information in the cache when parse
    02068     fails.  The additional information can be
    02069     1. The key is has no subkey (CM_KCB_NO_SUBKEY).
    02070     2. The key has a few subkeys, then build the index hint in the cache.
    02071     3. If lookup failed even we have index hint cached, then create a fake key so
    02072        we do not fail again.   This is very usful for lookup failure under keys like
    02073        \registry\machine\software\classes\clsid, which have 1500+ subkeys and lots of
    02074        them have the smae first four chars.
    02075
    02076        NOTE. Currently we are not seeing too many fake keys being created.
    02077        We need to monitor this periodly and work out a way to work around if
    02078        we do create too many fake keys.
    02079        One solution is to use hash value for index hint (We can do it in the cache only
    02080        if we need to be backward comparible).
    02081
    02082 Arguments:
    02083
    02084     Hive - Supplies Hive that holds the key we are creating a KCB for.
    02085
    02086     Cell - Supplies Cell that contains the key we are creating a KCB for.
    02087
    02088     Node - Supplies pointer to key node.
    02089
    02090     KeyName - The KeyName.
    02091
    02092 Return Value:
    02093
    02094     The KCB that CmpParse need to dereference at the end.
    02095 --*/
    02096 {
    02097
    02098     ULONG TotalSubKeyCounts;
    02099     BOOLEAN CreateFakeKcb = FALSE;
    02100     BOOLEAN HintCached;
    02101     PCM_KEY_CONTROL_BLOCK ParentKcb;
    02102     USHORT i,j,k;
    02103
    02104     if (!UseFastIndex(Hive)) {
    02105         //
    02106         // Older version of hive, do not bother to cache hint.
    02107         //
    02108         return (kcb);
    02109     }
    02110
    02111     TotalSubKeyCounts = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
    02112
    02113     if (TotalSubKeyCounts == 0) {
    02114         LOCK_KCB_TREE();
    02115         kcb->ExtFlags |= CM_KCB_NO_SUBKEY;
    02116         UNLOCK_KCB_TREE();
    02117     } else if (TotalSubKeyCounts == 1) {
    02118         LOCK_KCB_TREE();
    02119         if (!(kcb->ExtFlags & CM_KCB_SUBKEY_ONE)) {
    02120             //
    02121             // Build the subkey hint to avoid unnecessary lookups in the index leaf
    02122             //
    02123             PCM_KEY_INDEX   Index;
    02124             PCM_INDEX       Hint;
    02125
    02126             if (Node->SubKeyCounts[Stable] == 1) {
    02127                 Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Stable]);
    02128             } else {
    02129                 Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Volatile]);
    02130             }
    02131
    02132             if (Index->Signature == CM_KEY_FAST_LEAF) {
    02133                 PCM_KEY_FAST_INDEX FastIndex;
    02134                 FastIndex = (PCM_KEY_FAST_INDEX)Index;
    02135                 Hint = &FastIndex->List[0];
    02136
    02137                 for (k=0; k<CM_SUBKEY_HINT_LENGTH; k++) {
    02138                     kcb->NameHint[k] = Hint->NameHint[k];
    02139                 }
    02140
    02141                 kcb->ExtFlags |= CM_KCB_SUBKEY_ONE;
    02142             }
    02143         } else {
    02144             //
    02145             // The name hint does not prevent from this look up
    02146             // Create the fake Kcb.
    02147             //
    02148             CreateFakeKcb = TRUE;
    02149         }
    02150         UNLOCK_KCB_TREE();
    02151     } else if (TotalSubKeyCounts < CM_MAX_CACHE_HINT_SIZE) {
    02152         LOCK_KCB_TREE();
    02153         if (!(kcb->ExtFlags & CM_KCB_SUBKEY_HINT)) {
    02154             //
    02155             // Build the index leaf info in the parent KCB
    02156             // How to sync the cache with the registry data is a problem to be resolved.
    02157             //
    02158             ULONG Size;
    02159             PCM_KEY_INDEX   Index;
    02160             PCM_INDEX       Hint;
    02161             PCM_KEY_FAST_INDEX FastIndex;
    02162             UCHAR           *NameHint;
    02163
    02164             Size = sizeof(ULONG) * (Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile] + 1);
    02165
    02166             kcb->IndexHint = ExAllocatePoolWithTag(PagedPool,
    02167                                                    Size,
    02168                                                    CM_CACHE_INDEX_TAG | PROTECTED_POOL);
    02169
    02170             HintCached = TRUE;
    02171             if (kcb->IndexHint) {
    02172                 kcb->IndexHint->Count = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
    02173
    02174                 NameHint = &(kcb->IndexHint->NameHint[0]);
    02175
    02176                 for (i = 0; i < Hive->StorageTypeCount; i++) {
    02177                     if(Node->SubKeyCounts[i]) {
    02178                         Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[i]);
    02179                         for (j=0; j<Node->SubKeyCounts[i]; j++) {
    02180                             if (Index->Signature == CM_KEY_FAST_LEAF) {
    02181                                 FastIndex = (PCM_KEY_FAST_INDEX)Index;
    02182                                 Hint = &FastIndex->List[j];
    02183
    02184                                 for (k=0; k<CM_SUBKEY_HINT_LENGTH; k++) {
    02185                                     NameHint[k] = Hint->NameHint[k];
    02186                                 }
    02187                             } else {
    02188                                 HintCached = FALSE;
    02189                                 break;
    02190                             }
    02191                             NameHint += CM_SUBKEY_HINT_LENGTH;
    02192                         }
    02193                     }
    02194                 }
    02195
    02196                 if (HintCached) {
    02197                     kcb->ExtFlags |= CM_KCB_SUBKEY_HINT;
    02198                 } else {
    02199                     //
    02200                     // Do not have a FAST_LEAF, free the allocation.
    02201                     //
    02202                     ExFreePoolWithTag(kcb->IndexHint, CM_CACHE_INDEX_TAG | PROTECTED_POOL);
    02203                 }
    02204             }
    02205         } else {
    02206             //
    02207             // The name hint does not prevent from this look up
    02208             // Create the fake Kcb.
    02209             //
    02210             CreateFakeKcb = TRUE;
    02211         }
    02212         UNLOCK_KCB_TREE();
    02213     } else {
    02214         CreateFakeKcb = TRUE;
    02215     }
    02216
    02217     ParentKcb = kcb;
    02218
    02219     if (CreateFakeKcb && (CmpCacheOnFlag & CM_CACHE_FAKE_KEY)) {
    02220         //
    02221         // It has more than a few children but not the one we are interested.
    02222         // Create a kcb for this non-existing key so we do not try to find it
    02223         // again. Use the cell and node from the parent.
    02224         //
    02225         // Before we create a new one. Dereference the current kcb.
    02226         //
    02227         // CmpCacheOnFlag is for us to turn it on/off easily.
    02228         //
    02229
    02230         kcb = CmpCreateKeyControlBlock(Hive,
    02231                                        Cell,
    02232                                        Node,
    02233                                        ParentKcb,
    02234                                        TRUE,
    02235                                        NodeName);
    02236
    02237         if (kcb) {
    02238             CmpDereferenceKeyControlBlock(ParentKcb);
    02239             ParentKcb = kcb;
    02240         }
    02241     }
    02242
    02243     return (ParentKcb);
    02244 }
    }

VOID CmpCacheAdd | ( | IN PCM_HASH_ENTRY | LastHashEntry,
|  | IN ULONG | Count
| ) |

NTSTATUS CmpCacheLookup | ( | IN PCM_HASH_ENTRY | HashStack,
|  | IN ULONG | TotalRemainingSubkeys,
|  | OUT ULONG * | MatchRemainSubkeyLevel,
|  | IN OUT PCM_KEY_CONTROL_BLOCK * | Kcb,
|  | OUT PUNICODE_STRING | RemainingName,
|  | OUT PHHIVE * | Hive,
|  | OUT HCELL_INDEX * | Cell
| ) |

Definition at line 1853 of file cmparse.c.

References ASSERT, ASSERT_KEY_HASH, Cell, CM_KCB_KEY_NON_EXIST, CmpCacheTable, CmpCleanUpKcbCacheWithLock(), CmpCompareCompressedName(), CmpReferenceKeyControlBlock(), CmpRemoveFromDelayedClose(), CmpRemoveKeyControlBlock(), _CM_NAME_CONTROL_BLOCK::Compressed, _CM_KEY_CONTROL_BLOCK::ConvKey, FALSE, GET_HASH_ENTRY, Hive, KeyName, _CM_NAME_CONTROL_BLOCK::Name, _CM_KEY_CONTROL_BLOCK::NameBlock, _CM_NAME_CONTROL_BLOCK::NameLength, _CM_KEY_HASH::NextHash, NTSTATUS(), _CM_KEY_CONTROL_BLOCK::ParentKcb, RtlCompareUnicodeString(), _CM_KEY_CONTROL_BLOCK::TotalLevels, and TRUE.

Referenced by CmpParseKey().

    01864                    :
    01865
    01866     This routine Search the cache to find the matching path in the Cache.
    01867
    01868 Arguments:
    01869
    01870     HashStack - Array that has the hash value of each level.
    01871
    01872     TotalRemainingSubkeys - Total Subkey counts from base.
    01873
    01874     MatchRemainSubkeyLevel - Number of Levels in RemaingName
    01875                              that matches. (0 if not found)
    01876
    01877     kcb - Pointer to the kcb of the basename.
    01878           Will be changed to the kcb for the new basename.
    01879
    01880     RemainingName - Returns remaining name
    01881
    01882     Hive - Returns the hive of the cache entry found (if any)
    01883
    01884     Cell - Returns the cell of the cache entry found (if any)
    01885
    01886 Return Value:
    01887
    01888     Status
    01889
    01890 --*/
    01891
    01892 {
    01893     LONG i;
    01894     LONG j;
    01895     NTSTATUS status = STATUS_SUCCESS;
    01896     ULONG CurrentLevel;
    01897     PCM_KEY_HASH Current;
    01898     PCM_KEY_CONTROL_BLOCK BaseKcb;
    01899     PCM_KEY_CONTROL_BLOCK CurrentKcb;
    01900     PCM_KEY_CONTROL_BLOCK ParentKcb;
    01901     BOOLEAN Found = FALSE;
    01902
    01903     BaseKcb = *Kcb;
    01904     CurrentLevel = TotalRemainingSubkeys + BaseKcb->TotalLevels + 1;
    01905
    01906     for(i = TotalRemainingSubkeys-1; i>=0; i--) {
    01907         //
    01908         // Try to find the longest path in the cache.
    01909         //
    01910         // First, find the kcb that match the hash value.
    01911         //
    01912
    01913         CurrentLevel--;
    01914
    01915         Current = GET_HASH_ENTRY(CmpCacheTable, HashStack[i].ConvKey);
    01916
    01917         while (Current) {
    01918             ASSERT_KEY_HASH(Current);
    01919
    01920             //
    01921             // Check against both the ConvKey and total levels;
    01922             //
    01923             CurrentKcb = (CONTAINING_RECORD(Current, CM_KEY_CONTROL_BLOCK, KeyHash));
    01924
    01925             if (CurrentKcb->TotalLevels == CurrentLevel) {
    01926                 //
    01927                 // The total subkey levels match.
    01928                 // Iterate through the kcb path and compare each subkey.
    01929                 //
    01930                 Found = TRUE;
    01931                 ParentKcb = CurrentKcb;
    01932                 for (j=i; j>=0; j--) {
    01933                     if (HashStack[j].ConvKey == ParentKcb->ConvKey) {
    01934                         //
    01935                         // Convkey matches, compare the string
    01936                         //
    01937                         LONG Result;
    01938                         UNICODE_STRING  TmpNodeName;
    01939
    01940                         if (ParentKcb->NameBlock->Compressed) {
    01941                                Result = CmpCompareCompressedName(&(HashStack[j].KeyName),
    01942                                                                  ParentKcb->NameBlock->Name,
    01943                                                                  ParentKcb->NameBlock->NameLength);
    01944                         } else {
    01945                                TmpNodeName.Buffer = ParentKcb->NameBlock->Name;
    01946                                TmpNodeName.Length = ParentKcb->NameBlock->NameLength;
    01947                                TmpNodeName.MaximumLength = ParentKcb->NameBlock->NameLength;
    01948
    01949                                Result = RtlCompareUnicodeString (&(HashStack[j].KeyName),
    01950                                                                  &TmpNodeName,
    01951                                                                  TRUE);
    01952                         }
    01953
    01954                         if (Result) {
    01955                             Found = FALSE;
    01956                             break;
    01957                         }
    01958                         ParentKcb = ParentKcb->ParentKcb;
    01959                     } else {
    01960                         Found = FALSE;
    01961                         break;
    01962                     }
    01963                 }
    01964                 if (Found) {
    01965                     //
    01966                     // All remaining key matches.  Now compare the BaseKcb.
    01967                     //
    01968                     if (BaseKcb == ParentKcb) {
    01969                         if (CurrentKcb->ParentKcb->Delete) {
    01970                             //
    01971                             // The parentkcb is marked deleted.
    01972                             // So this must be a fake key created when the parent still existed.
    01973                             // Otherwise it cannot be in the cache
    01974                             //
    01975                             ASSERT (CurrentKcb->ExtFlags & CM_KCB_KEY_NON_EXIST);
    01976
    01977                             //
    01978                             // It is possible that the parent key was deleted but now recreated.
    01979                             // In that case this fake key is not longer valid for the ParentKcb is bad.
    01980                             // We must now remove this fake key out of cache so, if this is a
    01981                             // create operation, we do get hit this kcb in CmpCreateKeyControlBlock.
    01982                             //
    01983                             if (CurrentKcb->RefCount == 0) {
    01984                                 //
    01985                                 // No one is holding this fake kcb, just delete it.
    01986                                 //
    01987                                 CmpRemoveFromDelayedClose(CurrentKcb);
    01988                                 CmpCleanUpKcbCacheWithLock(CurrentKcb);
    01989                             } else {
    01990                                 //
    01991                                 // Someone is still holding this fake kcb,
    01992                                 // Mark it as delete and remove it out of cache.
    01993                                 //
    01994                                 CurrentKcb->Delete = TRUE;
    01995                                 CmpRemoveKeyControlBlock(CurrentKcb);
    01996                             }
    01997                             Found = FALSE;
    01998                             break;
    01999                         }
    02000
    02001
    02002                         //
    02003                         // We have a match, update the RemainingName.
    02004                         //
    02005
    02006                         //
    02007                         // Skip the leading OBJ_NAME_PATH_SEPARATOR
    02008                         //
    02009                         while ((RemainingName->Length > 0) &&
    02010                                (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) {
    02011                             RemainingName->Buffer++;
    02012                             RemainingName->Length -= sizeof(WCHAR);
    02013                         }
    02014
    02015                         //
    02016                         // Skip all subkeys plus OBJ_NAME_PATH_SEPARATOR
    02017                         //
    02018                         for(j=0; j<=i; j++) {
    02019                             RemainingName->Buffer += HashStack[j].KeyName.Length/sizeof(WCHAR) + 1;
    02020                             RemainingName->Length -= HashStack[j].KeyName.Length + sizeof(WCHAR);
    02021                         }
    02022
    02023                         //
    02024                         // Update the KCB, Hive and Cell.
    02025                         //
    02026                         *Kcb = CurrentKcb;
    02027                         *Hive = CurrentKcb->KeyHive;
    02028                         *Cell = CurrentKcb->KeyCell;
    02029                         break;
    02030                     } else {
    02031                         Found = FALSE;
    02032                     }
    02033                 }
    02034             }
    02035             Current = Current->NextHash;
    02036         }
    02037
    02038         if (Found) {
    02039             break;
    02040         }
    02041     }
    02042     //
    02043     // Now the kcb will be used in the parse routine.
    02044     // Increase its reference count.
    02045     // Make sure we remember to dereference it at the parse routine.
    02046     //
    02047     if (!CmpReferenceKeyControlBlock(*Kcb)) {
    02048         status = STATUS_INSUFFICIENT_RESOURCES;
    02049     }
    02050     *MatchRemainSubkeyLevel = i+1;
    02051     return status;
    02052 }

ULONG CmpComputeHashValue | ( | IN PCM_HASH_ENTRY | HashStack,
|  | IN OUT ULONG * | TotalSubkeys,
|  | IN ULONG | BaseConvKey,
|  | IN PUNICODE_STRING | RemainingName
| ) |

Definition at line 1737 of file cmparse.c.

References CM_HASH_STACK_SIZE, RtlUpcaseUnicodeChar(), and USHORT.

Referenced by CmpParseKey().

    01746                    :
    01747
    01748     This routine parses the complete path of a request registry key and calculate
    01749     the hash value at each level.
    01750
    01751 Arguments:
    01752
    01753     HashStack - Array for filling the hash value of each level.
    01754
    01755     TotalSubkeys - a pointer to fill the total number of subkeys
    01756
    01757     BaseConvKey - Supplies the convkey for the base key.
    01758
    01759     RemainingName - supplies pointer to a unicode_string for RemainingName.
    01760
    01761 Return Value:
    01762
    01763     Number of Levels in RemainingName
    01764
    01765 --*/
    01766
    01767 {
    01768     ULONG  TotalRemainingSubkeys=0;
    01769     ULONG  TotalKeys=0;
    01770     ULONG  ConvKey=BaseConvKey;
    01771     USHORT  Cnt;
    01772     WCHAR *Cp;
    01773     WCHAR *Begin;
    01774     USHORT Length;
    01775
    01776     if (RemainingName->Length) {
    01777         Cp = RemainingName->Buffer;
    01778         Cnt = RemainingName->Length;
    01779
    01780         //Skip the leading OBJ_NAME_PATH_SEPARATOR
    01781
    01782         while (*Cp == OBJ_NAME_PATH_SEPARATOR) {
    01783             Cp++;
    01784             Cnt -= sizeof(WCHAR);
    01785         }
    01786         Begin = Cp;
    01787         Length = 0;
    01788
    01789         HashStack[TotalRemainingSubkeys].KeyName.Buffer = Cp;
    01790
    01791         while (Cnt){
    01792             if ( *Cp == OBJ_NAME_PATH_SEPARATOR ) {
    01793                 if (TotalRemainingSubkeys < CM_HASH_STACK_SIZE) {
    01794                     HashStack[TotalRemainingSubkeys].ConvKey = ConvKey;
    01795                     //
    01796                     // Due to the changes in KCB structure, we now only have the subkey name
    01797                     // in the kcb (not the full path).  Change the name in the stack to store
    01798                     // the parse element (each subkey) only.
    01799                     //
    01800                     HashStack[TotalRemainingSubkeys].KeyName.Length = Length;
    01801                     Length = 0;
    01802                     TotalRemainingSubkeys++;
    01803                 }
    01804
    01805                 TotalKeys++;
    01806
    01807                 //
    01808                 // Now skip over leading path separators
    01809                 // Just in case someone has a RemainingName '..A\\\\B..'
    01810                 //
    01811                 //
    01812                 // We are stripping all OBJ_NAME_PATH_SEPARATOR (The origainl code keep the first one).
    01813                 // so the KeyName.Buffer is set properly.
    01814                 //
    01815                 while(*Cp == OBJ_NAME_PATH_SEPARATOR){
    01816                     Cp++;
    01817                     Cnt -= sizeof(WCHAR);
    01818                 }
    01819                 HashStack[TotalRemainingSubkeys].KeyName.Buffer = Cp;
    01820
    01821             } else {
    01822                 ConvKey = 37 * ConvKey + (ULONG) RtlUpcaseUnicodeChar(*Cp);
    01823                 //
    01824                 // We are stripping all OBJ_NAME_PATH_SEPARATOR in the above code,
    01825                 // we should only move to the next char in the else case.
    01826                 //
    01827                 Cp++;
    01828                 Cnt -= sizeof(WCHAR);
    01829                 Length += sizeof(WCHAR);
    01830
    01831             }
    01832
    01833
    01834         }
    01835
    01836         //
    01837         // Since we have stripped off all trailing path separators in CmpParseKey routine,
    01838         // the last char will not be OBJ_NAME_PATH_SEPARATOR.
    01839         //
    01840         if (TotalRemainingSubkeys < CM_HASH_STACK_SIZE) {
    01841             HashStack[TotalRemainingSubkeys].ConvKey = ConvKey;
    01842             HashStack[TotalRemainingSubkeys].KeyName.Length = Length;
    01843             TotalRemainingSubkeys++;
    01844         }
    01845         TotalKeys++;
    01846
    01847         (*TotalSubkeys) = TotalKeys;
    01848     }
    01849
    01850     return(TotalRemainingSubkeys);
    01851 }
    NTSTATUS

NTSTATUS CmpCreateLinkNode | ( | IN PHHIVE | Hive,
|  | IN HCELL_INDEX | Cell,
|  | IN PACCESS_STATE | AccessState,
|  | IN UNICODE_STRING | Name,
|  | IN KPROCESSOR_MODE | AccessMode,
|  | IN ULONG | Attributes,
|  | IN PCM_PARSE_CONTEXT | Context,
|  | IN PCM_KEY_CONTROL_BLOCK | ParentKcb,
|  | OUT PVOID * | Object
| ) |

Definition at line 1252 of file cmparse.c.

References ASSERT_CM_LOCK_OWNED_EXCLUSIVE, Cell, _CM_KEY_NODE::ChildHiveReference, _CM_KEY_NODE::ClassLength, CM_LINK_NODE_SIGNATURE, CML_FLOW, CML_MAJOR, CMLOG, CmpAddSubKey(), CmpCleanUpSubKeyInfo(), CmpCopyName(), CmpDoCreateChild(), CmpDoOpen(), CmpHKeyNodeSize, CmpMasterHive, CMS_PARSE, _CHILD_LIST::Count, FALSE, _CM_KEY_NODE::Flags, HCELL_INDEX, HCELL_NIL, _CMHIVE::Hive, Hive, HvAllocateCell(), HvFreeCell(), HvGetCell, kcb(), KeQuerySystemTime(), KEY_COMP_NAME, KEY_HIVE_ENTRY, KEY_HIVE_EXIT, KEY_NO_DELETE, _CM_KEY_REFERENCE::KeyCell, _CM_KEY_BODY::KeyControlBlock, _CM_KEY_REFERENCE::KeyHive, _CELL_DATA::_u::KeyNode, _CM_KEY_NODE::LastWriteTime, _CHILD_LIST::List, _CM_KEY_NODE::MaxClassLen, _CM_KEY_NODE::MaxNameLen, _CM_KEY_NODE::Name, Name, _CM_KEY_NODE::NameLength, NT_SUCCESS, NTSTATUS(), NULL, _CM_KEY_NODE::Parent, _CM_KEY_CONTROL_BLOCK::ParentKcb, _CM_KEY_NODE::Signature, Stable, Status, _CM_KEY_NODE::SubKeyCounts, _CM_KEY_NODE::SubKeyLists, _CELL_DATA::u, _CM_KEY_NODE::ValueList, and Volatile.

Referenced by CmpParseKey().

    01265                    :
    01266
    01267     Perform the creation of a link node.  Allocate all components,
    01268     and attach to parent key.  Calls CmpDoCreate or CmpDoOpen to
    01269     create or open the root node of the hive as appropriate.
    01270
    01271     Note that you can only create link nodes in the master hive.
    01272
    01273 Arguments:
    01274
    01275     Hive - supplies a pointer to the hive control structure for the hive
    01276
    01277     Cell - supplies index of node to create child under
    01278
    01279     Name - supplies pointer to a UNICODE string which is the name of
    01280             the child to be created.
    01281
    01282     AccessMode - Access mode of the original caller.
    01283
    01284     Attributes - Attributes to be applied to the object.
    01285
    01286     Context - pointer to CM_PARSE_CONTEXT structure passed through
    01287                 the object manager
    01288
    01289     BaseName - Name of object create is relative to
    01290
    01291     KeyName - Relative name (to BaseName)
    01292
    01293     Object - The address of a variable to receive the created key object, if
    01294              any.
    01295
    01296 Return Value:
    01297
    01298     NTSTATUS
    01299
    01300 --*/
    01301 {
    01302     NTSTATUS Status;
    01303     PCELL_DATA Parent;
    01304     PCELL_DATA Link;
    01305     PCELL_DATA CellData;
    01306     HCELL_INDEX LinkCell;
    01307     HCELL_INDEX KeyCell;
    01308     HCELL_INDEX ChildCell;
    01309     PCM_KEY_CONTROL_BLOCK kcb = ParentKcb;
    01310     PCM_KEY_BODY KeyBody;
    01311     LARGE_INTEGER systemtime;
    01312
    01313     CMLOG(CML_FLOW, CMS_PARSE) {
    01314         KdPrint(("CmpCreateLinkNode:\n"));
    01315     }
    01316
    01317     if (Hive != &CmpMasterHive->Hive) {
    01318         CMLOG(CML_MAJOR, CMS_PARSE) {
    01319             KdPrint(("CmpCreateLinkNode: attempt to create link node in\n"));
    01320             KdPrint(("    non-master hive %08lx\n", Hive));
    01321         }
    01322         return(STATUS_ACCESS_DENIED);
    01323     }
    01324
    01325     //
    01326     // Allocate link node
    01327     //
    01328     // Link nodes are always in the master hive, so their storage type is
    01329     // mostly irrelevent.
    01330     //
    01331     LinkCell = HvAllocateCell(Hive,  CmpHKeyNodeSize(Hive, &Name), Stable);
    01332     if (LinkCell == HCELL_NIL) {
    01333         return STATUS_INSUFFICIENT_RESOURCES;
    01334     }
    01335
    01336     KeyCell = Context->ChildHive.KeyCell;
    01337
    01338     if (KeyCell != HCELL_NIL) {
    01339
    01340         //
    01341         // This hive already exists, so we just need to open the root node.
    01342         //
    01343         ChildCell=KeyCell;
    01344
    01345         //
    01346         // The root cell in the hive does not has the Name buffer
    01347         // space reseverd.  This is why we need to pass in the Name for creating KCB
    01348         // instead of using the name in the keynode.
    01349         //
    01350         CellData = HvGetCell(Context->ChildHive.KeyHive, ChildCell);
    01351         CellData->u.KeyNode.Parent = LinkCell;
    01352         CellData->u.KeyNode.Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
    01353         Status = CmpDoOpen( Context->ChildHive.KeyHive,
    01354                             KeyCell,
    01355                             (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive,KeyCell),
    01356                             AccessState,
    01357                             AccessMode,
    01358                             Attributes,
    01359                             NULL,
    01360                             FALSE,
    01361                             &kcb,
    01362                             &Name,
    01363                             Object );
    01364     } else {
    01365
    01366         //
    01367         // This is a newly created hive, so we must allocate and initialize
    01368         // the root node.
    01369         //
    01370
    01371         Status = CmpDoCreateChild( Context->ChildHive.KeyHive,
    01372                                    Cell,
    01373                                    NULL,
    01374                                    AccessState,
    01375                                    &Name,
    01376                                    AccessMode,
    01377                                    Context,
    01378                                    ParentKcb,
    01379                                    KEY_HIVE_ENTRY | KEY_NO_DELETE,
    01380                                    &ChildCell,
    01381                                    Object );
    01382
    01383         if (NT_SUCCESS(Status)) {
    01384
    01385             //
    01386             // Initialize hive root cell pointer.
    01387             //
    01388
    01389             Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell;
    01390         }
    01391
    01392     }
    01393     if (NT_SUCCESS(Status)) {
    01394
    01395         //
    01396         // Initialize parent and flags.  Note that we do this whether the
    01397         // root has been created or opened, because we are not guaranteed
    01398         // that the link node is always the same cell in the master hive.
    01399         //
    01400         CellData = HvGetCell(Context->ChildHive.KeyHive, ChildCell);
    01401         CellData->u.KeyNode.Parent = LinkCell;
    01402         CellData->u.KeyNode.Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
    01403
    01404         //
    01405         // Initialize special link node flags and data
    01406         //
    01407         Link = HvGetCell(Hive, LinkCell);
    01408         Link->u.KeyNode.Signature = CM_LINK_NODE_SIGNATURE;
    01409         Link->u.KeyNode.Flags = KEY_HIVE_EXIT | KEY_NO_DELETE;
    01410         Link->u.KeyNode.Parent = Cell;
    01411         Link->u.KeyNode.NameLength = CmpCopyName(Hive, Link->u.KeyNode.Name, &Name);
    01412         if (Link->u.KeyNode.NameLength < Name.Length) {
    01413             Link->u.KeyNode.Flags |= KEY_COMP_NAME;
    01414         }
    01415
    01416         KeQuerySystemTime(&systemtime);
    01417         Link->u.KeyNode.LastWriteTime = systemtime;
    01418
    01419         //
    01420         // Zero out unused fields.
    01421         //
    01422         Link->u.KeyNode.SubKeyCounts[Stable] = 0;
    01423         Link->u.KeyNode.SubKeyCounts[Volatile] = 0;
    01424         Link->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL;
    01425         Link->u.KeyNode.SubKeyLists[Volatile] = HCELL_NIL;
    01426         Link->u.KeyNode.ValueList.Count = 0;
    01427         Link->u.KeyNode.ValueList.List = HCELL_NIL;
    01428         Link->u.KeyNode.ClassLength = 0;
    01429
    01430
    01431         //
    01432         // Fill in the link node's pointer to the root node
    01433         //
    01434         Link->u.KeyNode.ChildHiveReference.KeyHive = Context->ChildHive.KeyHive;
    01435         Link->u.KeyNode.ChildHiveReference.KeyCell = ChildCell;
    01436
    01437         //
    01438         // Fill in the parent cell's child list
    01439         //
    01440         if (! CmpAddSubKey(Hive, Cell, LinkCell)) {
    01441             HvFreeCell(Hive, LinkCell);
    01442             return STATUS_INSUFFICIENT_RESOURCES;
    01443         }
    01444
    01445         //
    01446         // Update max keyname and class name length fields
    01447         //
    01448         Parent = HvGetCell(Hive, Cell);
    01449
    01450         //
    01451         // It seem to me that the original code is wrong.
    01452         // Isn't the definition of MaxNameLen just the length of the subkey?
    01453         //
    01454         if (Parent->u.KeyNode.MaxNameLen < Name.Length) {
    01455             Parent->u.KeyNode.MaxNameLen = Name.Length;
    01456         }
    01457
    01458         if (Parent->u.KeyNode.MaxClassLen < Context->Class.Length) {
    01459             Parent->u.KeyNode.MaxClassLen = Context->Class.Length;
    01460         }
    01461
    01462         //
    01463         // If the parent has the subkey info or hint cached, free it.
    01464         //
    01465         ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
    01466         KeyBody = (PCM_KEY_BODY)(*Object);
    01467         CmpCleanUpSubKeyInfo (KeyBody->KeyControlBlock->ParentKcb);
    01468
    01469     } else {
    01470         HvFreeCell(Hive, LinkCell);
    01471     }
    01472     return(Status);
    01473 }

NTSTATUS CmpDoOpen | ( | IN PHHIVE | Hive,
|  | IN HCELL_INDEX | Cell,
|  | IN PCM_KEY_NODE | Node,
|  | IN PACCESS_STATE | AccessState,
|  | IN KPROCESSOR_MODE | AccessMode,
|  | IN ULONG | Attributes,
|  | IN PCM_PARSE_CONTEXT | Context,
|  | IN BOOLEAN | CompleteKeyCached,
|  | IN OUT PCM_KEY_CONTROL_BLOCK * | CachedKcb,
|  | IN PUNICODE_STRING | KeyName,
|  | OUT PVOID * | Object
| ) |

Definition at line 963 of file cmparse.c.

References ASSERT, Cell, CM_KCB_SYM_LINK_FOUND, CML_FLOW, CML_MINOR, CMLOG, CmpCleanUpKcbValueCache(), CmpCreateKeyControlBlock(), CmpDereferenceKeyControlBlock(), CmpKeyObjectType, CmpReferenceKeyControlBlock(), CMS_PARSE, CMS_POOL, ENLIST_KEYBODY_IN_KEYBODY_LIST, FALSE, Hive, kcb(), KEY_BODY_TYPE, KEY_PREDEF_HANDLE, KEY_SYM_LINK, _CM_KEY_BODY::KeyControlBlock, KeyName, KPROCESSOR_MODE, LOCK_KCB_TREE, _CM_KEY_BODY::NotifyBlock, NT_SUCCESS, NTSTATUS(), NULL, ObCheckObjectAccess(), ObCreateObject(), ObDereferenceObject, _CM_KEY_BODY::Process, PsGetCurrentProcess, SeBackupPrivilege, SeRestorePrivilege, SeSinglePrivilegeCheck(), TRUE, _CM_KEY_BODY::Type, and UNLOCK_KCB_TREE.

Referenced by CmpCreateLinkNode(), and CmpParseKey().

    00978                    :
    00979
    00980     Open a registry key, create a keycontrol block.
    00981
    00982 Arguments:
    00983
    00984     Hive - supplies a pointer to the hive control structure for the hive
    00985
    00986     Cell - supplies index of node to delete
    00987
    00988     AccessState - Running security access state information for operation.
    00989
    00990     AccessMode - Access mode of the original caller.
    00991
    00992     Attributes - Attributes to be applied to the object.
    00993
    00994     Context - if create or hive root open, points to a CM_PARSE_CONTEXT
    00995               structure,
    00996               if open, is NULL.
    00997
    00998     CompleteKeyCached - BOOLEAN to indicate it the completekey is cached.
    00999
    01000     CachedKcb - If the completekey is cached, this is the kcb for the destination.
    01001                 If not, this is the parent kcb.
    01002
    01003     KeyName - Relative name (to BaseName)
    01004
    01005     Object - The address of a variable to receive the created key object, if
    01006              any.
    01007
    01008 Return Value:
    01009
    01010     NTSTATUS
    01011
    01012 --*/
    01013 {
    01014     NTSTATUS status;
    01015     PCM_KEY_BODY pbody;
    01016     PCM_KEY_CONTROL_BLOCK kcb;
    01017     KPROCESSOR_MODE   mode;
    01018     BOOLEAN BackupRestore;
    01019
    01020     CMLOG(CML_FLOW, CMS_PARSE) {
    01021         KdPrint(("CmpDoOpen:\n"));
    01022     }
    01023     if (ARGUMENT_PRESENT(Context)) {
    01024
    01025         //
    01026         // It's a create of some sort
    01027         //
    01028         if (Context->CreateLink) {
    01029             //
    01030             // The node already exists as a regular key, so it cannot be
    01031             // turned into a link node.
    01032             //
    01033             return STATUS_ACCESS_DENIED;
    01034
    01035         } else if (Context->CreateOptions & REG_OPTION_CREATE_LINK) {
    01036             //
    01037             // Attempt to create a symbolic link has hit an existing key
    01038             // so return an error
    01039             //
    01040             return STATUS_OBJECT_NAME_COLLISION;
    01041
    01042         } else {
    01043             //
    01044             // Operation is an open, so set Disposition
    01045             //
    01046             Context->Disposition = REG_OPENED_EXISTING_KEY;
    01047         }
    01048     }
    01049
    01050     //
    01051     // Check for symbolic link and caller does not want to open a link
    01052     //
    01053     if (CompleteKeyCached) {
    01054         //
    01055         // The complete key is cached.
    01056         //
    01057         if ((*CachedKcb)->Flags & KEY_SYM_LINK && !(Attributes & OBJ_OPENLINK)) {
    01058             //
    01059             // If the key is a symbolic link, check if the link has been resolved.
    01060             // If the link is resolved, change the kcb to the real KCB.
    01061             // Otherwise, return for reparse.
    01062             //
    01063             LOCK_KCB_TREE();
    01064             if ((*CachedKcb)->ExtFlags & CM_KCB_SYM_LINK_FOUND) {
    01065                 kcb = (*CachedKcb)->ValueCache.RealKcb;
    01066
    01067                 if (kcb->Delete == TRUE) {
    01068                     //
    01069                     // The real key it pointes to had been deleted.
    01070                     // We have no way of knowing if the key has been recreated.
    01071                     // Just clean up the cache and do a reparse.
    01072                     //
    01073                     CmpCleanUpKcbValueCache(*CachedKcb);
    01074                     UNLOCK_KCB_TREE();
    01075                     return(STATUS_REPARSE);
    01076                 }
    01077
    01078                 if (!CmpReferenceKeyControlBlock(kcb)) {
    01079                     UNLOCK_KCB_TREE();
    01080                     return STATUS_INSUFFICIENT_RESOURCES;
    01081                 }
    01082             } else {
    01083                 UNLOCK_KCB_TREE();
    01084                 return(STATUS_REPARSE);
    01085             }
    01086             UNLOCK_KCB_TREE();
    01087         } else {
    01088             //
    01089             // Not a symbolic link, increase the reference Count of Kcb.
    01090             //
    01091             LOCK_KCB_TREE();
    01092             kcb = *CachedKcb;
    01093             if (!CmpReferenceKeyControlBlock(kcb)) {
    01094                 UNLOCK_KCB_TREE();
    01095                 return STATUS_INSUFFICIENT_RESOURCES;
    01096             }
    01097             UNLOCK_KCB_TREE();
    01098         }
    01099     } else {
    01100             //
    01101             // The key is not in cache, the CachedKcb is the parentkcb of this
    01102             // key to be opened.
    01103             //
    01104
    01105         if (Node->Flags & KEY_SYM_LINK && !(Attributes & OBJ_OPENLINK)) {
    01106             //
    01107             // Create a KCB for this symbolic key and put it in delay close.
    01108             //
    01109             kcb = CmpCreateKeyControlBlock(Hive, Cell, Node, *CachedKcb, FALSE, KeyName);
    01110             if (kcb  == NULL) {
    01111                 return STATUS_INSUFFICIENT_RESOURCES;
    01112             }
    01113             CmpDereferenceKeyControlBlock(kcb);
    01114             *CachedKcb = kcb;
    01115             return(STATUS_REPARSE);
    01116         }
    01117
    01118         //
    01119         // If key control block does not exist, and cannot be created, fail,
    01120         // else just increment the ref count (done for us by CreateKeyControlBlock)
    01121         //
    01122         kcb = CmpCreateKeyControlBlock(Hive, Cell, Node, *CachedKcb, FALSE, KeyName);
    01123         if (kcb  == NULL) {
    01124             return STATUS_INSUFFICIENT_RESOURCES;
    01125         }
    01126         ASSERT(kcb->Delete == FALSE);
    01127
    01128         *CachedKcb = kcb;
    01129     }
    01130
    01131     //
    01132     // Allocate the object.
    01133     //
    01134     status = ObCreateObject(AccessMode,
    01135                             CmpKeyObjectType,
    01136                             NULL,
    01137                             AccessMode,
    01138                             NULL,
    01139                             sizeof(CM_KEY_BODY),
    01140                             0,
    01141                             0,
    01142                             Object);
    01143
    01144     if (NT_SUCCESS(status)) {
    01145
    01146         pbody = (PCM_KEY_BODY)(*Object);
    01147
    01148         CMLOG(CML_MINOR, CMS_POOL|CMS_PARSE) {
    01149             KdPrint(("CmpDoOpen: object allocated at:%08lx\n", pbody));
    01150         }
    01151
    01152         //
    01153         // Check for predefined handle
    01154         //
    01155
    01156         pbody = (PCM_KEY_BODY)(*Object);
    01157
    01158         if (kcb->Flags & KEY_PREDEF_HANDLE) {
    01159             pbody->Type = kcb->ValueCache.Count;
    01160             pbody->KeyControlBlock = kcb;
    01161             return(STATUS_PREDEFINED_HANDLE);
    01162         } else {
    01163             //
    01164             // Fill in CM specific fields in the object
    01165             //
    01166             pbody->Type = KEY_BODY_TYPE;
    01167             pbody->KeyControlBlock = kcb;
    01168             pbody->NotifyBlock = NULL;
    01169             pbody->Process = PsGetCurrentProcess();
    01170             ENLIST_KEYBODY_IN_KEYBODY_LIST(pbody);
    01171         }
    01172
    01173     } else {
    01174
    01175         //
    01176         // Failed to create object, so undo key control block work
    01177         //
    01178         CmpDereferenceKeyControlBlock(kcb);
    01179         return status;
    01180     }
    01181
    01182     //
    01183     // Check to make sure the caller can access the key.
    01184     //
    01185     BackupRestore = FALSE;
    01186     if (ARGUMENT_PRESENT(Context)) {
    01187         if (Context->CreateOptions & REG_OPTION_BACKUP_RESTORE) {
    01188             BackupRestore = TRUE;
    01189         }
    01190     }
    01191
    01192     status = STATUS_SUCCESS;
    01193
    01194     if (BackupRestore == TRUE) {
    01195
    01196         //
    01197         // this is an open to support a backup or restore
    01198         // operation, do the special case work
    01199         //
    01200         AccessState->RemainingDesiredAccess = 0;
    01201         AccessState->PreviouslyGrantedAccess = 0;
    01202
    01203         mode = KeGetPreviousMode();
    01204
    01205         if (SeSinglePrivilegeCheck(SeBackupPrivilege, mode)) {
    01206             AccessState->PreviouslyGrantedAccess |=
    01207                 KEY_READ | ACCESS_SYSTEM_SECURITY;
    01208         }
    01209
    01210         if (SeSinglePrivilegeCheck(SeRestorePrivilege, mode)) {
    01211             AccessState->PreviouslyGrantedAccess |=
    01212                 KEY_WRITE | ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER;
    01213         }
    01214
    01215         if (AccessState->PreviouslyGrantedAccess == 0) {
    01216             //
    01217             // relevent privileges not asserted/possessed, so
    01218             // deref (which will cause CmpDeleteKeyObject to clean up)
    01219             // and return an error.
    01220             //
    01221             CMLOG(CML_FLOW, CMS_PARSE) {
    01222                 KdPrint(("CmpDoOpen for backup restore: access denied\n"));
    01223             }
    01224             ObDereferenceObject(*Object);
    01225             return STATUS_ACCESS_DENIED;
    01226         }
    01227
    01228     } else {
    01229
    01230         if (!ObCheckObjectAccess(*Object,
    01231                                   AccessState,
    01232                                   TRUE,         // Type mutex already locked
    01233                                   AccessMode,
    01234                                   &status))
    01235         {
    01236             //
    01237             // Access denied, so deref object, will cause CmpDeleteKeyObject
    01238             // to be called, it will clean up.
    01239             //
    01240             CMLOG(CML_FLOW, CMS_PARSE) {
    01241                 KdPrint(("CmpDoOpen: access denied\n"));
    01242             }
    01243             ObDereferenceObject(*Object);
    01244         }
    01245     }
    01246
    01247     return status;
    01248 }

BOOLEAN CmpGetNextName | ( | IN OUT PUNICODE_STRING | RemainingName,
|  | OUT PUNICODE_STRING | NextName,
|  | OUT PBOOLEAN | Last
| ) |

Definition at line 860 of file cmparse.c.

References FALSE, MAX_KEY_NAME_LENGTH, NULL, TRUE, and USHORT.

Referenced by CmpParseKey(), and CmpWalkPath().

    00867                    :
    00868
    00869     This routine parses off the next component of a registry path, returning
    00870     all of the interesting state about it, including whether it's legal.
    00871
    00872 Arguments:
    00873
    00874     Current - supplies pointer to variable which points to path to parse.
    00875               on input - parsing starts from here
    00876               on output - updated to reflect starting position for next call.
    00877
    00878     NextName - supplies pointer to a unicode_string, which will be set up
    00879                to point into the parse string.
    00880
    00881     Last - supplies a pointer to a boolean - set to TRUE if this is the
    00882            last component of the name being parse, FALSE otherwise.
    00883
    00884 Return Value:
    00885
    00886     TRUE if all is well.
    00887
    00888     FALSE if illegal name (too long component, bad character, etc.)
    00889         (if false, all out parameter values are bogus.)
    00890
    00891 --*/
    00892 {
    00893     BOOLEAN rc = TRUE;
    00894
    00895     //
    00896     // Deal with NULL paths, and pointers to NULL paths
    00897     //
    00898     if ((RemainingName->Buffer == NULL) || (RemainingName->Length == 0)) {
    00899         *Last = TRUE;
    00900         NextName->Buffer = NULL;
    00901         NextName->Length = 0;
    00902         return TRUE;
    00903     }
    00904
    00905     if (*(RemainingName->Buffer) == UNICODE_NULL) {
    00906         *Last = TRUE;
    00907         NextName->Buffer = NULL;
    00908         NextName->Length = 0;
    00909         return TRUE;
    00910     }
    00911
    00912     //
    00913     // Skip over leading path separators
    00914     //
    00915     if (*(RemainingName->Buffer) == OBJ_NAME_PATH_SEPARATOR) {
    00916         RemainingName->Buffer++;
    00917         RemainingName->Length -= sizeof(WCHAR);
    00918         RemainingName->MaximumLength -= sizeof(WCHAR);
    00919     }
    00920
    00921     //
    00922     // Remember where the component starts, and scan to the end
    00923     //
    00924     NextName->Buffer = RemainingName->Buffer;
    00925     while (TRUE) {
    00926         if (RemainingName->Length == 0) {
    00927             break;
    00928         }
    00929         if (*RemainingName->Buffer == OBJ_NAME_PATH_SEPARATOR) {
    00930             break;
    00931         }
    00932
    00933         //
    00934         // NOT at end
    00935         // NOT another path sep
    00936         //
    00937
    00938         RemainingName->Buffer++;
    00939         RemainingName->Length -= sizeof(WCHAR);
    00940         RemainingName->MaximumLength -= sizeof(WCHAR);
    00941     }
    00942
    00943     //
    00944     // Compute component length, return error if it's illegal
    00945     //
    00946     NextName->Length = (USHORT)
    00947         ((PUCHAR)RemainingName->Buffer - (PUCHAR)(NextName->Buffer));
    00948     if (NextName->Length > MAX_KEY_NAME_LENGTH)
    00949     {
    00950         rc = FALSE;
    00951     }
    00952     NextName->MaximumLength = NextName->Length;
    00953
    00954     //
    00955     // Set last, return success
    00956     //
    00957     *Last = (RemainingName->Length == 0);
    00958     return rc;
    00959 }

BOOLEAN CmpGetSymbolicLink | ( | IN PHHIVE | Hive,
|  | IN PCM_KEY_NODE | Node,
|  | IN OUT PUNICODE_STRING | ObjectName,
|  | IN OUT PCM_KEY_CONTROL_BLOCK | SymbolicKcb,
|  | IN PUNICODE_STRING | RemainingName
| ) |

Definition at line 1476 of file cmparse.c.

References ASSERT, CM_KCB_SYM_LINK_FOUND, CML_FLOW, CML_MINOR, CMLOG, CmpCacheTable, CmpCleanUpKcbValueCache(), CmpConstructName(), CmpFindValueByName, CmpHashTableSize, CmpIsHKeyValueSmall, CmpReferenceKeyControlBlock(), CMS_PARSE, CmSymbolicLinkValueName, _CM_KEY_HASH::ConvKey, _CM_KEY_VALUE::Data, _CM_KEY_VALUE::DataLength, ExAllocatePool, ExFreePool(), ExFreePoolWithTag, FALSE, GET_HASH_ENTRY, HCELL_INDEX, HCELL_NIL, Hive, HvGetCell, Index, LOCK_KCB_TREE, _CM_KEY_HASH::NextHash, NT_SUCCESS, NTSTATUS(), NULL, PagedPool, PHCELL_INDEX, PROTECTED_POOL, RtlAppendUnicodeStringToString(), RtlUpcaseUnicodeChar(), Status, _CM_KEY_CONTROL_BLOCK::TotalLevels, TRUE, _CM_KEY_VALUE::Type, UNLOCK_KCB_TREE, and USHORT.

Referenced by CmpParseKey().

    01486                    :
    01487
    01488     This routine extracts the symbolic link name from a key, if it is
    01489     marked as a symbolic link.
    01490
    01491 Arguments:
    01492
    01493     Hive - Supplies the hive of the key.
    01494
    01495     Node - Supplies pointer to the key node
    01496
    01497     ObjectName - Supplies the current ObjectName.
    01498                  Returns the new ObjectName.  If the new name is longer
    01499                  than the maximum length of the current ObjectName, the
    01500                  old buffer will be freed and a new buffer allocated.
    01501
    01502     RemainingName - Supplies the remaining path.  If present, this will be
    01503                 concatenated with the symbolic link to form the new objectname.
    01504
    01505 Return Value:
    01506
    01507     TRUE - symbolic link succesfully found
    01508
    01509     FALSE - Key is not a symbolic link, or an error occurred
    01510
    01511 --*/
    01512
    01513 {
    01514     NTSTATUS Status;
    01515     HCELL_INDEX LinkCell;
    01516     PHCELL_INDEX Index;
    01517     PCM_KEY_VALUE LinkValue;
    01518     PWSTR LinkName;
    01519     PWSTR NewBuffer;
    01520     ULONG Length;
    01521     ULONG ValueLength;
    01522     extern ULONG CmpHashTableSize;
    01523     extern PCM_KEY_HASH *CmpCacheTable;
    01524     PUNICODE_STRING ConstructedName;
    01525     ULONG  ConvKey=0;
    01526     PCM_KEY_HASH KeyHash;
    01527     PCM_KEY_CONTROL_BLOCK RealKcb;
    01528     BOOLEAN KcbFound = FALSE;
    01529     ULONG  Cnt;
    01530     WCHAR *Cp;
    01531     WCHAR *Cp2;
    01532     USHORT TotalLevels;
    01533     BOOLEAN FreeConstructedName = FALSE;
    01534
    01535     LOCK_KCB_TREE();
    01536     if (SymbolicKcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) {
    01537         //
    01538         // First see of the real kab for this symbolic name has been found
    01539         //
    01540         ConstructedName = CmpConstructName(SymbolicKcb->ValueCache.RealKcb);
    01541         if (ConstructedName) {
    01542             FreeConstructedName = TRUE;
    01543             LinkName = ConstructedName->Buffer;
    01544             ValueLength = ConstructedName->Length;
    01545             Length = (USHORT)ValueLength + sizeof(WCHAR);
    01546         }
    01547     }
    01548     UNLOCK_KCB_TREE();
    01549
    01550     if (FreeConstructedName == FALSE) {
    01551         //
    01552         // Find the SymbolicLinkValue value.  This is the name of the symbolic link.
    01553         //
    01554         LinkCell = CmpFindValueByName(Hive,
    01555                                       Node,
    01556                                       &CmSymbolicLinkValueName);
    01557         if (LinkCell == HCELL_NIL) {
    01558             CMLOG(CML_MINOR, CMS_PARSE) {
    01559                 KdPrint(("CmpGetSymbolicLink: couldn't open symbolic link\n"));
    01560             }
    01561             return(FALSE);
    01562         }
    01563
    01564         LinkValue = (PCM_KEY_VALUE)HvGetCell(Hive, LinkCell);
    01565
    01566         if (LinkValue->Type != REG_LINK) {
    01567             CMLOG(CML_MINOR, CMS_PARSE) {
    01568                 KdPrint(("CmpGetSymbolicLink: link value is wrong type: %08lx", LinkValue->Type));
    01569             }
    01570             return(FALSE);
    01571         }
    01572
    01573         LinkName = (PWSTR)HvGetCell(Hive, LinkValue->Data);
    01574
    01575         CmpIsHKeyValueSmall(ValueLength, LinkValue->DataLength);
    01576         Length = (USHORT)ValueLength + sizeof(WCHAR);
    01577
    01578         //
    01579         // Now see if we have this kcb cached.
    01580         //
    01581         Cp = LinkName;
    01582         TotalLevels = 0;
    01583         for (Cnt=0; Cnt<ValueLength; Cnt += sizeof(WCHAR)) {
    01584             if (*Cp != OBJ_NAME_PATH_SEPARATOR) {
    01585                 ConvKey = 37 * ConvKey + (ULONG) RtlUpcaseUnicodeChar(*Cp);
    01586             } else {
    01587                 TotalLevels++;
    01588             }
    01589             ++Cp;
    01590         }
    01591
    01592
    01593         KeyHash = GET_HASH_ENTRY(CmpCacheTable, ConvKey);
    01594
    01595         LOCK_KCB_TREE();
    01596         while (KeyHash) {
    01597             RealKcb =  CONTAINING_RECORD(KeyHash, CM_KEY_CONTROL_BLOCK, KeyHash);
    01598             if ((ConvKey == KeyHash->ConvKey) && (TotalLevels == RealKcb->TotalLevels)) {
    01599                 ConstructedName = CmpConstructName(RealKcb);
    01600                 if (ConstructedName) {
    01601                     FreeConstructedName = TRUE;
    01602                     if (ConstructedName->Length == ValueLength) {
    01603                         KcbFound = TRUE;
    01604                         Cp = LinkName;
    01605                         Cp2 = ConstructedName->Buffer;
    01606                         for (Cnt=0; Cnt<ConstructedName->Length; Cnt += sizeof(WCHAR)) {
    01607                             if (RtlUpcaseUnicodeChar(*Cp) != RtlUpcaseUnicodeChar(*Cp2)) {
    01608                                 KcbFound = FALSE;
    01609                                 break;
    01610                             }
    01611                             ++Cp;
    01612                             ++Cp2;
    01613                         }
    01614                         if (KcbFound) {
    01615                             //
    01616                             // Now the RealKcb is also pointed to by its symbolic link Kcb,
    01617                             // Increase the reference count.
    01618                             // Need to dereference the realkcb when the symbolic kcb is removed.
    01619                             // Do this in CmpCleanUpKcbCacheWithLock();
    01620                             //
    01621                             if (CmpReferenceKeyControlBlock(RealKcb)) {
    01622                                 //
    01623                                 // This symbolic kcb may have value lookup for the path
    01624                                 // Cleanup the value cache.
    01625                                 //
    01626                                 CmpCleanUpKcbValueCache(SymbolicKcb);
    01627
    01628                                 SymbolicKcb->ExtFlags |= CM_KCB_SYM_LINK_FOUND;
    01629                                 SymbolicKcb->ValueCache.RealKcb = RealKcb;
    01630                             } else {
    01631                                 //
    01632                                 // We have maxed out the ref count on the real kcb.
    01633                                 // do not cache the symbolic link.
    01634                                 //
    01635                             }
    01636                             break;
    01637                         }
    01638                     }
    01639                 } else {
    01640                     break;
    01641                 }
    01642             }
    01643             if (FreeConstructedName) {
    01644                 ExFreePoolWithTag(ConstructedName, CM_NAME_TAG | PROTECTED_POOL);
    01645                 FreeConstructedName = FALSE;
    01646             }
    01647             KeyHash = KeyHash->NextHash;
    01648         }
    01649         UNLOCK_KCB_TREE();
    01650     }
    01651
    01652     if (ARGUMENT_PRESENT(RemainingName)) {
    01653         Length += RemainingName->Length + sizeof(WCHAR);
    01654     }
    01655
    01656     //
    01657     // Overflow test: If Length overflows the USHRT_MAX value
    01658     //                cleanup and return FALSE
    01659     //
    01660     if( Length>0xFFFF ) {
    01661         if (FreeConstructedName) {
    01662             ExFreePoolWithTag(ConstructedName, CM_NAME_TAG | PROTECTED_POOL);
    01663             FreeConstructedName = FALSE;
    01664         }
    01665
    01666         return(FALSE);
    01667     }
    01668
    01669         if (Length > ObjectName->MaximumLength) {
    01670         UNICODE_STRING NewObjectName;
    01671
    01672         //
    01673         // The new name is too long to fit in the existing ObjectName buffer,
    01674         // so allocate a new buffer.
    01675         //
    01676         NewBuffer = ExAllocatePool(PagedPool, Length);
    01677         if (NewBuffer == NULL) {
    01678             CMLOG(CML_MINOR, CMS_PARSE) {
    01679                 KdPrint(("CmpGetSymbolicLink: couldn't allocate new name buffer\n"));
    01680             }
    01681             if (FreeConstructedName) {
    01682                 ExFreePoolWithTag(ConstructedName, CM_NAME_TAG | PROTECTED_POOL);
    01683                 FreeConstructedName = FALSE;
    01684             }
    01685             return(FALSE);
    01686         }
    01687
    01688         NewObjectName.Buffer = NewBuffer;
    01689         NewObjectName.MaximumLength = (USHORT)Length;
    01690         NewObjectName.Length = (USHORT)ValueLength;
    01691         RtlCopyMemory(NewBuffer, LinkName, ValueLength);
    01692         CMLOG(CML_FLOW, CMS_PARSE) {
    01693             KdPrint(("CmpGetSymbolicLink: LinkName is %wZ\n", ObjectName));
    01694             if (ARGUMENT_PRESENT(RemainingName)) {
    01695                 KdPrint(("               RemainingName is %wZ\n", RemainingName));
    01696             } else {
    01697                 KdPrint(("               RemainingName is NULL\n"));
    01698             }
    01699         }
    01700
    01701         if (ARGUMENT_PRESENT(RemainingName)) {
    01702             NewBuffer[ ValueLength / sizeof(WCHAR) ] = OBJ_NAME_PATH_SEPARATOR;
    01703             NewObjectName.Length += sizeof(WCHAR);
    01704             Status = RtlAppendUnicodeStringToString(&NewObjectName, RemainingName);
    01705             ASSERT(NT_SUCCESS(Status));
    01706         }
    01707
    01708         ExFreePool(ObjectName->Buffer);
    01709         *ObjectName = NewObjectName;
    01710     } else {
    01711         //
    01712         // The new name will fit within the maximum length of the existing
    01713         // ObjectName, so do the expansion in-place. Note that the remaining
    01714         // name must be moved into its new position first since the symbolic
    01715         // link may or may not overlap it.
    01716         //
    01717         ObjectName->Length = (USHORT)ValueLength;
    01718         if (ARGUMENT_PRESENT(RemainingName)) {
    01719             RtlMoveMemory(&ObjectName->Buffer[(ValueLength / sizeof(WCHAR)) + 1],
    01720                           RemainingName->Buffer,
    01721                           RemainingName->Length);
    01722             ObjectName->Buffer[ValueLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
    01723             ObjectName->Length += RemainingName->Length + sizeof(WCHAR);
    01724         }
    01725         RtlCopyMemory(ObjectName->Buffer, LinkName, ValueLength);
    01726     }
    01727     ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] = UNICODE_NULL;
    01728
    01729     if (FreeConstructedName) {
    01730         ExFreePoolWithTag(ConstructedName, CM_NAME_TAG | PROTECTED_POOL);
    01731     }
    01732     return(TRUE);
    01733 }

NTSTATUS CmpParseKey | ( | IN PVOID | ParseObject,
|  | IN PVOID | ObjectType,
|  | IN OUT PACCESS_STATE | AccessState,
|  | IN KPROCESSOR_MODE | AccessMode,
|  | IN ULONG | Attributes,
|  | IN OUT PUNICODE_STRING | CompleteName,
|  | IN OUT PUNICODE_STRING | RemainingName,
|  | IN OUT PVOID Context | OPTIONAL,
|  | IN PSECURITY_QUALITY_OF_SERVICE SecurityQos | OPTIONAL,
|  | OUT PVOID * | Object
| ) |

Definition at line 145 of file cmparse.c.

References Cell, CM_HASH_STACK_SIZE, CM_KCB_CACHE_MASK, CM_KCB_KEY_NON_EXIST, CM_KCB_NO_SUBKEY, CM_KCB_SUBKEY_ONE, CM_SUBKEY_HINT_LENGTH, CML_FLOW, CML_MAJOR, CML_MINOR, CMLOG, CMP_PARSE_GOTO_CREATE, CMP_PARSE_GOTO_NONE, CMP_PARSE_GOTO_RETURN, CMP_PARSE_GOTO_RETURN2, CmpAddInfoAfterParseFailure(), CmpCacheLookup(), CmpComputeHashValue(), CmpCreateKeyControlBlock(), CmpCreateLinkNode(), CmpDereferenceKeyControlBlock(), CmpDereferenceKeyControlBlockWithLock(), CmpDoCreate(), CmpDoOpen(), CmpFindSubKeyByName(), CmpGetNextName(), CmpGetSymbolicLink(), CmpKeyObjectType, CmpMasterHive, CmpNoMasterCreates, CmpReferenceKeyControlBlock(), CmpRemoveKeyControlBlock(), CmpStepThroughExit, CMS_PARSE, _CM_PARSE_CONTEXT::CreateLink, _CM_PARSE_CONTEXT::Disposition, FALSE, HCELL_INDEX, HCELL_NIL, _CMHIVE::Hive, Hive, HvGetCell, Index, kcb(), KEY_SYM_LINK, _CM_KEY_CONTROL_BLOCK::KeyCell, _CM_KEY_CONTROL_BLOCK::KeyHive, _CM_KEY_CONTROL_BLOCK::KeyNode, LOCK_KCB_TREE, NT_SUCCESS, NTSTATUS(), NULL, PHCELL_INDEX, RtlUpcaseUnicodeChar(), TRUE, UNLOCK_KCB_TREE, and USHORT.

Referenced by CmpCreateObjectTypes().

    00159                    :
    00160
    00161     This routine interfaces to the NT Object Manager.  It is invoked when
    00162     the object system is given the name of an entity to create or open and
    00163     a Key or KeyRoot is encountered in the path.  In practice this means
    00164     that this routine is called for all objects whose names are of the
    00165     form \REGISTRY\...
    00166
    00167     This routine will create a Key object, which is effectively an open
    00168     instance to a registry key node, and return its address
    00169     (for the success case.)
    00170
    00171 Arguments:
    00172
    00173     ParseObject - Pointer to a KeyRoot or Key, thus -> KEY_BODY.
    00174
    00175     ObjectType - Type of the object being opened.
    00176
    00177     AccessState - Running security access state information for operation.
    00178
    00179     AccessMode - Access mode of the original caller.
    00180
    00181     Attributes - Attributes to be applied to the object.
    00182
    00183     CompleteName - Supplies complete name of the object.
    00184
    00185     RemainingName - Remaining name of the object.
    00186
    00187     Context - if create or hive root open, points to a CM_PARSE_CONTEXT
    00188               structure,
    00189               if open, is NULL.
    00190
    00191     SecurityQos - Optional security quality of service indicator.
    00192
    00193     Object - The address of a variable to receive the created key object, if
    00194         any.
    00195
    00196 Return Value:
    00197
    00198     The function return value is one of the following:
    00199
    00200         a)  Success - This indicates that the function succeeded and the object
    00201             parameter contains the address of the created key object.
    00202
    00203         b)  STATUS_REPARSE - This indicates that a symbolic link key was
    00204             found, and the path should be reparsed.
    00205
    00206         c)  Error - This indicates that the file was not found or created and
    00207             no file object was created.
    00208
    00209 --*/
    00210 {
    00211     NTSTATUS    status;
    00212     BOOLEAN     rc;
    00213     PHHIVE      Hive;
    00214     PCM_KEY_NODE Node;
    00215     HCELL_INDEX Cell;
    00216     HCELL_INDEX ParentCell;
    00217     HCELL_INDEX NextCell;
    00218     PHCELL_INDEX Index;
    00219     PCM_PARSE_CONTEXT lcontext;
    00220     UNICODE_STRING Current;
    00221     UNICODE_STRING  NextName;   // Component last returned by CmpGetNextName,
    00222                                 // will always be behind Current.
    00223     BOOLEAN     Last;           // TRUE if component NextName points to
    00224                                 // is the last one in the path.
    00225
    00226     CM_HASH_ENTRY   HashStack[CM_HASH_STACK_SIZE];
    00227     ULONG           TotalRemainingSubkeys;
    00228     ULONG           MatchRemainSubkeyLevel;
    00229     ULONG           TotalSubkeys=0;
    00230     ULONG           SubkeyParsed;
    00231     PCM_KEY_CONTROL_BLOCK   kcb;
    00232     PCM_KEY_HASH PCmpCacheEntry=NULL;
    00233     PCM_KEY_CONTROL_BLOCK   ParentKcb;
    00234     UNICODE_STRING  TmpNodeName;
    00235     ULONG   namelength;
    00236     ULONG   GoToValue = CMP_PARSE_GOTO_NONE;
    00237     BOOLEAN CompleteKeyCached = FALSE;
    00238     USHORT i,j;
    00239     WCHAR *p1;
    00240
    00241     CMLOG(CML_MINOR, CMS_PARSE) {
    00242         KdPrint(("CmpParseKey:\n\t"));
    00243         KdPrint(("CompleteName = '%wZ'\n\t", CompleteName));
    00244         KdPrint(("RemainingName = '%wZ'\n", RemainingName));
    00245     }
    00246
    00247     //
    00248     // Strip off any trailing path separators
    00249     //
    00250     while ((RemainingName->Length > 0) &&
    00251            (RemainingName->Buffer[(RemainingName->Length/sizeof(WCHAR)) - 1] == OBJ_NAME_PATH_SEPARATOR)) {
    00252         RemainingName->Length -= sizeof(WCHAR);
    00253     }
    00254
    00255     Current = *RemainingName;
    00256     if (ObjectType != CmpKeyObjectType) {
    00257         return STATUS_OBJECT_TYPE_MISMATCH;
    00258     }
    00259
    00260     lcontext = (PCM_PARSE_CONTEXT)Context;
    00261
    00262     //
    00263     // Check to make sure the passed in root key is not marked for deletion.
    00264     //
    00265     if (((PCM_KEY_BODY)ParseObject)->KeyControlBlock->Delete == TRUE) {
    00266         return(STATUS_KEY_DELETED);
    00267     }
    00268
    00269     //
    00270     // Fetch the starting Hive.Cell.  Because of the way the parse
    00271     // paths work, this will always be defined.  (ObOpenObjectByName
    00272     // had to bounce off of a KeyObject or KeyRootObject to get here)
    00273     //
    00274     kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock;
    00275     Hive = kcb->KeyHive;
    00276     Cell = kcb->KeyCell;
    00277     Node = kcb->KeyNode;
    00278
    00279     //
    00280     // Compute the hash values of each subkeys
    00281     //
    00282     TotalRemainingSubkeys = CmpComputeHashValue(HashStack,
    00283                                                 &TotalSubkeys,
    00284                                                 kcb->ConvKey,
    00285                                                 &Current);
    00286
    00287
    00288     // Look up from the cache.  kcb will be changed if we find a partial or exact match
    00289     // PCmpCacheEntry, the entry found, will be move to the front of
    00290     // the Cache.
    00291
    00292     LOCK_KCB_TREE();
    00293
    00294     status = CmpCacheLookup(HashStack,
    00295                             TotalRemainingSubkeys,
    00296                             &MatchRemainSubkeyLevel,
    00297                             &kcb,
    00298                             &Current,
    00299                             &Hive,
    00300                             &Cell);
    00301     //
    00302     // The RefCount of kcb was increased in the CmpCacheLookup process,
    00303     // It is to protect it from being kicked out of cache.
    00304     // Make sure we dereference it after we are done.
    00305     //
    00306
    00307     //
    00308     // First make sure it is OK to proceed.
    00309     //
    00310     if (!NT_SUCCESS (status)) {
    00311         UNLOCK_KCB_TREE();
    00312         goto JustReturn;
    00313     }
    00314
    00315     SubkeyParsed = MatchRemainSubkeyLevel;
    00316     ParentKcb = kcb;
    00317
    00318     //
    00319     // First check if there are further information in the cached kcb.
    00320     //
    00321     // The additional information can be
    00322     // 1. This cached key is a fake key (CM_KCB_KEY_NON_EXIST), then either let it be created
    00323     //    or return STATUS_OBJECT_NAME_NOT_FOUND.
    00324     // 2. The cached key is not the destination and it has no subkey (CM_KCB_NO_SUBKEY).
    00325     // 3. The cached key is not the destination and it has
    00326     //    the first four characters of its subkeys.  If the flag is CM_KCB_SUBKEY_ONE, there is only one subkey
    00327     //    and the four char is embedded in the KCB.  If the flag is CM_KCB_SUBKEY_INFO, then there is
    00328     //    an allocation for these info.
    00329     //
    00330     // We do need to lock KCB tree to protect the KCB being modified.  Currently there is not lock contention problem
    00331     // on KCBs, We can change KCB lock to a read-write lock if this becomes a problem.
    00332     //
    00333
    00334     if (kcb->ExtFlags & CM_KCB_CACHE_MASK) {
    00335         if (MatchRemainSubkeyLevel == TotalRemainingSubkeys) {
    00336             //
    00337             // We have found a cache for the complete path,
    00338             //
    00339             if (kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) {
    00340                 //
    00341                 // This key does not exist.
    00342                 //
    00343                 if (ARGUMENT_PRESENT(lcontext)) {
    00344                     ULONG LevelToSkip = TotalRemainingSubkeys-1;
    00345                     ULONG i=0;
    00346                     //
    00347                     // The non-existing key is the desination key and lcontext is present.
    00348                     // delete this fake kcb and let the real one be created.
    00349                     //
    00350                     // Temporarily increase the RefCount of the ParentKcb so it's
    00351                     // not removed while removing the fake and creating the real KCB.
    00352                     //
    00353
    00354                     ParentKcb = kcb->ParentKcb;
    00355
    00356                     if (CmpReferenceKeyControlBlock(ParentKcb)) {
    00357
    00358                         kcb->Delete = TRUE;
    00359                         CmpRemoveKeyControlBlock(kcb);
    00360                         CmpDereferenceKeyControlBlockWithLock(kcb);
    00361
    00362                         //
    00363                         // Update Hive, Cell and Node
    00364                         //
    00365                         Hive = ParentKcb->KeyHive;
    00366                         Cell = ParentKcb->KeyCell;
    00367                         Node = ParentKcb->KeyNode;
    00368
    00369                         //
    00370                         // Now get the child name to be created.
    00371                         //
    00372
    00373                         NextName = *RemainingName;
    00374                         if ((NextName.Buffer == NULL) || (NextName.Length == 0)) {
    00375                             KdPrint(("Something wrong in finding the child name\n"));
    00376                             DbgBreakPoint();
    00377                         }
    00378                         //
    00379                         // Skip over leading path separators
    00380                         //
    00381                         if (*(NextName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
    00382                             NextName.Buffer++;
    00383                             NextName.Length -= sizeof(WCHAR);
    00384                             NextName.MaximumLength -= sizeof(WCHAR);
    00385                         }
    00386
    00387                         while (i < LevelToSkip) {
    00388                             if (*(NextName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
    00389                                 i++;
    00390                             }
    00391                             NextName.Buffer++;
    00392                             NextName.Length -= sizeof(WCHAR);
    00393                             NextName.MaximumLength -= sizeof(WCHAR);
    00394                         }
    00395                         GoToValue = CMP_PARSE_GOTO_CREATE;
    00396                     } else {
    00397                         //
    00398                         // We have maxed the RefCount of ParentKcb; treate it as key cannot be created.
    00399                         // The ParentKcb will not be dereferenced at the end.
    00400                         //
    00401                         status = STATUS_INSUFFICIENT_RESOURCES;
    00402                         GoToValue = CMP_PARSE_GOTO_RETURN2;
    00403                     }
    00404                 } else {
    00405                     status = STATUS_OBJECT_NAME_NOT_FOUND;
    00406                     GoToValue = CMP_PARSE_GOTO_RETURN;
    00407                 }
    00408             }
    00409         } else if (kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) {
    00410             //
    00411             // one subkey (not desination) in the path does not exist. no point to continue.
    00412             //
    00413             status = STATUS_OBJECT_NAME_NOT_FOUND;
    00414             GoToValue = CMP_PARSE_GOTO_RETURN;
    00415         } else if (kcb->ExtFlags & CM_KCB_NO_SUBKEY) {
    00416             //
    00417             // one parent in the path has no subkey. see if it is a create.
    00418             //
    00419             if (((TotalRemainingSubkeys - MatchRemainSubkeyLevel) == 1) && (ARGUMENT_PRESENT(lcontext))) {
    00420                 //
    00421                 // Now we are going to create this subkey.
    00422                 // The kcb cache will be updated in CmpDoCreate routine.
    00423                 //
    00424             } else {
    00425                 status = STATUS_OBJECT_NAME_NOT_FOUND;
    00426                 GoToValue = CMP_PARSE_GOTO_RETURN;
    00427             }
    00428         } else {
    00429             //
    00430             // We have a partial match.  Current is the remaining name to be parsed.
    00431             // The Key has either one or a few subkeys and has index hint. check if it is the candidate.
    00432             //
    00433             ULONG HintLength;
    00434             ULONG HintCounts;
    00435             ULONG CmpCount;
    00436             WCHAR c1;
    00437             WCHAR c2;
    00438             UCHAR *TmpName;
    00439             LONG Result;
    00440             BOOLEAN NoMatch = TRUE;
    00441             //
    00442             // When NoMatch is TRUE, we know for sure there is no subkey that can match.
    00443             // When NoMatch is FALSE, it can we either we found a match or
    00444             // there is not enough information.  Either case, we need to continue
    00445             // the parse.
    00446             //
    00447
    00448             TmpNodeName = Current;
    00449
    00450             rc = CmpGetNextName(&TmpNodeName, &NextName, &Last);
    00451
    00452             if (kcb->ExtFlags & CM_KCB_SUBKEY_ONE) {
    00453                 HintCounts = 1;
    00454                 TmpName = &(kcb->NameHint[0]);
    00455             } else {
    00456                 //
    00457                 // More than one child, the hint info in not inside the kcb but pointed by kcb.
    00458                 //
    00459                 HintCounts = kcb->IndexHint->Count;
    00460                 TmpName = &(kcb->IndexHint->NameHint[0]);
    00461             }
    00462
    00463             //
    00464             // use the hint to predict if there is a possible match
    00465             //
    00466             if (NextName.Length < (sizeof(WCHAR) * CM_SUBKEY_HINT_LENGTH) ) {
    00467                 HintLength = NextName.Length / sizeof(WCHAR);
    00468             } else {
    00469                 HintLength = CM_SUBKEY_HINT_LENGTH;
    00470             }
    00471
    00472             for (CmpCount=0; CmpCount<HintCounts; CmpCount++) {
    00473                 NoMatch = FALSE;
    00474
    00475                 if( TmpName[0] == 0) {
    00476                     //
    00477                     // No hint available; assume the subkey exist and go on with the parse
    00478                     //
    00479                     break;
    00480                 }
    00481
    00482                 for (i=0; i<HintLength; i++) {
    00483                     c1 = NextName.Buffer[i];
    00484                     c2 = (WCHAR) *TmpName;
    00485
    00486                     Result = (LONG)RtlUpcaseUnicodeChar(c1) - (LONG)RtlUpcaseUnicodeChar(c2);
    00487                     if (Result != 0) {
    00488                         NoMatch = TRUE;
    00489                         TmpName += (CM_SUBKEY_HINT_LENGTH-i);
    00490                         break;
    00491                     }
    00492                     TmpName++;
    00493                 }
    00494
    00495                 if (NoMatch == FALSE) {
    00496                     //
    00497                     // There is a match.
    00498                     //
    00499                     break;
    00500                 }
    00501             }
    00502
    00503             if (NoMatch) {
    00504                 if (((TotalRemainingSubkeys - MatchRemainSubkeyLevel) == 1) && (ARGUMENT_PRESENT(lcontext))) {
    00505                     //
    00506                     // No we are going to create this subkey.
    00507                     // The kcb cache will be updated in CmpDoCreate.
    00508                     //
    00509                 } else {
    00510                     status = STATUS_OBJECT_NAME_NOT_FOUND;
    00511                     GoToValue = CMP_PARSE_GOTO_RETURN;
    00512                 }
    00513             }
    00514         }
    00515     }
    00516
    00517     UNLOCK_KCB_TREE();
    00518
    00519
    00520     if (GoToValue == CMP_PARSE_GOTO_CREATE) {
    00521         goto CreateChild;
    00522     } else if (GoToValue == CMP_PARSE_GOTO_RETURN) {
    00523         goto FreeAndReturn;
    00524     } else if (GoToValue == CMP_PARSE_GOTO_RETURN2) {
    00525         goto JustReturn;
    00526     }
    00527
    00528     if (MatchRemainSubkeyLevel) {
    00529         // Found something, update the information to start the search
    00530         // from the new BaseName
    00531
    00532         //
    00533         // Get the Node address from the kcb.
    00534         // (Always try to utilize the KCB to avoid touching the registry data).
    00535         //
    00536         Node = kcb->KeyNode;
    00537
    00538         if (MatchRemainSubkeyLevel == TotalSubkeys) {
    00539             // The complete key has been found in the cache,
    00540             // go directly to the CmpDoOpen.
    00541
    00542             //
    00543             // Found the whole thing cached.
    00544             //
    00545             //
    00546             CompleteKeyCached = TRUE;
    00547             goto Found;
    00548         }
    00549     } else if (TotalRemainingSubkeys == 0) {
    00550         //
    00551         // BUGBUG John Vert (jvert) 10/7/1997
    00552         //
    00553         CompleteKeyCached = TRUE;
    00554         goto Found;
    00555     }
    00556
    00557     //
    00558     // Parse the path.
    00559     //
    00560
    00561     status = STATUS_SUCCESS;
    00562     while (TRUE) {
    00563
    00564         //
    00565         // Parse out next component of name
    00566         //
    00567         rc = CmpGetNextName(&Current, &NextName, &Last);
    00568         if ((NextName.Length > 0) && (rc == TRUE)) {
    00569
    00570             //
    00571             // As we iterate through, we will create a kcb for each subkey parsed.
    00572             //
    00573             // Always use the information in kcb to avoid
    00574             // touching registry data.
    00575             //
    00576             if (!(kcb->KeyNode->Flags & KEY_SYM_LINK)) {
    00577                 //
    00578                 // Got a legal name component, see if we can find a sub key
    00579                 // that actually has such a name.
    00580                 //
    00581                 NextCell = CmpFindSubKeyByName(Hive,
    00582                                                Node,
    00583                                                &NextName);
    00584
    00585                 CMLOG(CML_FLOW, CMS_PARSE) {
    00586                     KdPrint(("CmpParseKey:\n\t"));
    00587                     KdPrint(("NextName = '%wZ'\n\t", &NextName));
    00588                     KdPrint(("NextCell = %08lx  Last = %01lx\n", NextCell, Last));
    00589                 }
    00590                 if (NextCell != HCELL_NIL) {
    00591                     Cell = NextCell;
    00592                     Node = (PCM_KEY_NODE)HvGetCell(Hive,Cell);
    00593                     if (Last == TRUE) {
    00594
    00595 Found:
    00596                         //
    00597                         // We will open the key regardless of whether the
    00598                         // call was open or create, so step through exit
    00599                         // portholes here.
    00600                         //
    00601
    00602                         if (CompleteKeyCached == TRUE) {
    00603                             //
    00604                             // If the key found is already cached,
    00605                             // do not need to StepThroughExit
    00606                             // (no kcb is created using exit node).
    00607                             // This prevents us from touching the key node just for the Flags.
    00608                             //
    00609                         } else {
    00610                             CmpStepThroughExit(Hive, Cell, Node);
    00611                         }
    00612                         //
    00613                         // We have found the entire path, so we want to open
    00614                         // it (for both Open and Create calls).
    00615                         // Hive,Cell -> the key we are supposed to open.
    00616                         //
    00617
    00618                         status = CmpDoOpen(Hive,
    00619                                            Cell,
    00620                                            Node,
    00621                                            AccessState,
    00622                                            AccessMode,
    00623                                            Attributes,
    00624                                            lcontext,
    00625                                            CompleteKeyCached,
    00626                                            &kcb,
    00627                                            &NextName,
    00628                                            Object);
    00629
    00630                         if (status == STATUS_REPARSE) {
    00631                             //
    00632                             // The given key was a symbolic link.  Find the name of
    00633                             // its link, and return STATUS_REPARSE to the Object Manager.
    00634                             //
    00635
    00636                             if (!CmpGetSymbolicLink(Hive,
    00637                                                     Node,
    00638                                                     CompleteName,
    00639                                                     kcb,
    00640                                                     NULL)) {
    00641                                 CMLOG(CML_MAJOR, CMS_PARSE) {
    00642                                     KdPrint(("CmpParseKey: couldn't find symbolic link name\n"));
    00643                                 }
    00644                                 status = STATUS_OBJECT_NAME_NOT_FOUND;
    00645                             }
    00646                         }
    00647
    00648                         break;
    00649                     }
    00650                     // else
    00651                     //   Not at end, so we'll simply iterate and consume
    00652                     //   the next component.
    00653                     //
    00654                     //
    00655                     // Step through exit portholes here.
    00656                     // This ensures that no KCB is created using
    00657                     // the Exit node.
    00658                     //
    00659
    00660                     CmpStepThroughExit(Hive, Cell, Node);
    00661
    00662                     //
    00663                     // Create a kcb for each subkey parsed.
    00664                     //
    00665
    00666                     kcb = CmpCreateKeyControlBlock(Hive,
    00667                                                    Cell,
    00668                                                    Node,
    00669                                                    ParentKcb,
    00670                                                    FALSE,
    00671                                                    &NextName);
    00672
    00673                     if (kcb  == NULL) {
    00674                         status = STATUS_INSUFFICIENT_RESOURCES;
    00675                         goto FreeAndReturn;
    00676                         //
    00677                         // Currently, the kcb has one extra reference conut to be decremented.
    00678                         // So, remember it so we can dereference it properly.
    00679                         //
    00680                     }
    00681                     //
    00682                     // Now we have created a kcb for the next level,
    00683                     // the kcb in the previous level is no longer needed.
    00684                     // Dereference the parent kcb.
    00685                     //
    00686                     CmpDereferenceKeyControlBlock(ParentKcb);
    00687
    00688                     ParentKcb = kcb;
    00689
    00690
    00691                 } else {
    00692                     //
    00693                     // We did not find a key matching the name, but no
    00694                     // unexpected error occured
    00695                     //
    00696
    00697                     if ((Last == TRUE) && (ARGUMENT_PRESENT(lcontext))) {
    00698
    00699 CreateChild:
    00700                         //
    00701                         // Only unfound component is last one, and operation
    00702                         // is a create, so perform the create.
    00703                         //
    00704
    00705                         //
    00706                         // There are two possibilities here.  The normal one
    00707                         // is that we are simply creating a new node.
    00708                         //
    00709                         // The abnormal one is that we are creating a root
    00710                         // node that is linked to the main hive.  In this
    00711                         // case, we must create the link.  Once the link is
    00712                         // created, we can check to see if the root node
    00713                         // exists, then either create it or open it as
    00714                         // necessary.
    00715                         //
    00716                         // CmpCreateLinkNode creates the link, and calls
    00717                         // back to CmpDoCreate or CmpDoOpen to create or open
    00718                         // the root node as appropriate.
    00719                         //
    00720
    00721                         if (lcontext->CreateLink) {
    00722                             status = CmpCreateLinkNode(Hive,
    00723                                                        Cell,
    00724                                                        AccessState,
    00725                                                        NextName,
    00726                                                        AccessMode,
    00727                                                        Attributes,
    00728                                                        lcontext,
    00729                                                        ParentKcb,
    00730                                                        Object);
    00731
    00732                         } else {
    00733
    00734                             if ( (Hive == &(CmpMasterHive->Hive)) &&
    00735                                  (CmpNoMasterCreates == TRUE) ) {
    00736                                 //
    00737                                 // attempting to create a cell in the master
    00738                                 // hive, and not a link, so blow out of here,
    00739                                 // since it wouldn't work anyway.
    00740                                 //
    00741                                 status = STATUS_INVALID_PARAMETER;
    00742                                 break;
    00743                             }
    00744
    00745                             status = CmpDoCreate(Hive,
    00746                                                  Cell,
    00747                                                  AccessState,
    00748                                                  &NextName,
    00749                                                  AccessMode,
    00750                                                  lcontext,
    00751                                                  ParentKcb,
    00752                                                  Object);
    00753                         }
    00754
    00755                         lcontext->Disposition = REG_CREATED_NEW_KEY;
    00756                         break;
    00757
    00758                     } else {
    00759
    00760                         //
    00761                         // Did not find a key to match the component, and
    00762                         // are not at the end of the path.  Thus, open must
    00763                         // fail because the whole path dosn't exist, create must
    00764                         // fail because more than 1 component doesn't exist.
    00765                         //
    00766                         //
    00767                         // We have a lookup failure here, so having additional information
    00768                         // about this kcb may help us not to go through all the code just to fail again.
    00769                         //
    00770                         ParentKcb = CmpAddInfoAfterParseFailure(Hive,
    00771                                                                 Cell,
    00772                                                                 Node,
    00773                                                                 kcb,
    00774                                                                 &NextName
    00775                                                                 );
    00776
    00777                         status = STATUS_OBJECT_NAME_NOT_FOUND;
    00778                         break;
    00779                     }
    00780
    00781                 }
    00782
    00783             } else {
    00784                 //
    00785                 // The given key was a symbolic link.  Find the name of
    00786                 // its link, and return STATUS_REPARSE to the Object Manager.
    00787                 //
    00788                 Current.Buffer = NextName.Buffer;
    00789                 Current.Length += NextName.Length;
    00790                 Current.MaximumLength += NextName.MaximumLength;
    00791                 if (CmpGetSymbolicLink(Hive,
    00792                                        Node,
    00793                                        CompleteName,
    00794                                        kcb,
    00795                                        &Current)) {
    00796
    00797                     status = STATUS_REPARSE;
    00798                     break;
    00799
    00800                 } else {
    00801                     CMLOG(CML_MAJOR, CMS_PARSE) {
    00802                         KdPrint(("CmpParseKey: couldn't find symbolic link name\n"));
    00803                     }
    00804                     status = STATUS_OBJECT_NAME_NOT_FOUND;
    00805                     break;
    00806                 }
    00807             }
    00808
    00809         } else if (rc == TRUE && Last == TRUE) {
    00810             //
    00811             // We will open the \Registry root.
    00812             // Or some strange remaining name that
    00813             // screw up the lookup.
    00814             //
    00815             CmpStepThroughExit(Hive, Cell, Node);
    00816
    00817             //
    00818             // We have found the entire path, so we want to open
    00819             // it (for both Open and Create calls).
    00820             // Hive,Cell -> the key we are supposed to open.
    00821             //
    00822             status = CmpDoOpen(Hive,
    00823                                Cell,
    00824                                Node,
    00825                                AccessState,
    00826                                AccessMode,
    00827                                Attributes,
    00828                                lcontext,
    00829                                TRUE,
    00830                                &kcb,
    00831                                &NextName,
    00832                                Object);
    00833             break;
    00834
    00835         } else {
    00836
    00837             //
    00838             // bogus path -> fail
    00839             //
    00840             status = STATUS_INVALID_PARAMETER;
    00841             break;
    00842         }
    00843
    00844     } // while
    00845
    00846 FreeAndReturn:
    00847     //
    00848     // Now we have to free the last kcb that still has one extra reference count to
    00849     // protect it from being freed.
    00850     //
    00851
    00852     CmpDereferenceKeyControlBlock(ParentKcb);
    00853 JustReturn:
    00854
    00855     return status;
    00856 }

## Variable Documentation

ULONG CmpCacheOnFlag = CM_CACHE_FAKE_KEY

| Definition at line 23 of file cmparse.c. Referenced by CmpAddInfoAfterParseFailure().

PCM_KEY_CONTROL_BLOCK CmpKeyControlBlockRoot

| Definition at line 27 of file cmparse.c.

PCMHIVE CmpMasterHive

| Definition at line 25 of file cmparse.c.

BOOLEAN CmpNoMasterCreates

| Definition at line 26 of file cmparse.c.

UNICODE_STRING CmSymbolicLinkValueName

| Definition at line 28 of file cmparse.c.