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

cmparse.c

Go to the documentation of this file.
00001 /*++ 00002 Copyright (c) 1991 Microsoft Corporation 00003 00004 Module Name: 00005 00006 cmparse.c 00007 00008 Abstract: 00009 00010 This module contains parse routines for the configuration manager, particularly 00011 the registry. 00012 00013 Author: 00014 00015 Bryan M. Willman (bryanwi) 10-Sep-1991 00016 00017 Revision History: 00018 00019 --*/ 00020 00021 #include "cmp.h" 00022 00023 ULONG CmpCacheOnFlag = CM_CACHE_FAKE_KEY; 00024 00025 extern PCMHIVE CmpMasterHive; 00026 extern BOOLEAN CmpNoMasterCreates; 00027 extern PCM_KEY_CONTROL_BLOCK CmpKeyControlBlockRoot; 00028 extern UNICODE_STRING CmSymbolicLinkValueName; 00029 00030 #define CM_HASH_STACK_SIZE 30 00031 00032 typedef struct _CM_HASH_ENTRY { 00033 ULONG ConvKey; 00034 UNICODE_STRING KeyName; 00035 } CM_HASH_ENTRY, *PCM_HASH_ENTRY; 00036 00037 ULONG 00038 CmpComputeHashValue( 00039 IN PCM_HASH_ENTRY HashStack, 00040 IN OUT ULONG *TotalSubkeys, 00041 IN ULONG BaseConvKey, 00042 IN PUNICODE_STRING RemainingName 00043 ); 00044 00045 NTSTATUS 00046 CmpCacheLookup( 00047 IN PCM_HASH_ENTRY HashStack, 00048 IN ULONG TotalRemainingSubkeys, 00049 OUT ULONG *MatchRemainSubkeyLevel, 00050 IN OUT PCM_KEY_CONTROL_BLOCK *Kcb, 00051 OUT PUNICODE_STRING RemainingName, 00052 OUT PHHIVE *Hive, 00053 OUT HCELL_INDEX *Cell 00054 ); 00055 00056 VOID 00057 CmpCacheAdd( 00058 IN PCM_HASH_ENTRY LastHashEntry, 00059 IN ULONG Count 00060 ); 00061 00062 PCM_KEY_CONTROL_BLOCK 00063 CmpAddInfoAfterParseFailure( 00064 PHHIVE Hive, 00065 HCELL_INDEX Cell, 00066 PCM_KEY_NODE Node, 00067 PCM_KEY_CONTROL_BLOCK kcb, 00068 PUNICODE_STRING NodeName 00069 ); 00070 00071 // 00072 // Prototypes for procedures private to this file 00073 // 00074 00075 BOOLEAN 00076 CmpGetSymbolicLink( 00077 IN PHHIVE Hive, 00078 IN PCM_KEY_NODE Node, 00079 IN OUT PUNICODE_STRING ObjectName, 00080 IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb, 00081 IN PUNICODE_STRING RemainingName 00082 ); 00083 00084 NTSTATUS 00085 CmpDoOpen( 00086 IN PHHIVE Hive, 00087 IN HCELL_INDEX Cell, 00088 IN PCM_KEY_NODE Node, 00089 IN PACCESS_STATE AccessState, 00090 IN KPROCESSOR_MODE AccessMode, 00091 IN ULONG Attributes, 00092 IN PCM_PARSE_CONTEXT Context, 00093 IN BOOLEAN CompleteKeyCached, 00094 IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb, 00095 IN PUNICODE_STRING KeyName, 00096 OUT PVOID *Object 00097 ); 00098 00099 NTSTATUS 00100 CmpCreateLinkNode( 00101 IN PHHIVE Hive, 00102 IN HCELL_INDEX Cell, 00103 IN PACCESS_STATE AccessState, 00104 IN UNICODE_STRING Name, 00105 IN KPROCESSOR_MODE AccessMode, 00106 IN ULONG Attributes, 00107 IN PCM_PARSE_CONTEXT Context, 00108 IN PCM_KEY_CONTROL_BLOCK ParentKcb, 00109 OUT PVOID *Object 00110 ); 00111 00112 #ifdef ALLOC_PRAGMA 00113 #pragma alloc_text(PAGE,CmpParseKey) 00114 #pragma alloc_text(PAGE,CmpGetNextName) 00115 #pragma alloc_text(PAGE,CmpDoOpen) 00116 #pragma alloc_text(PAGE,CmpCreateLinkNode) 00117 #pragma alloc_text(PAGE,CmpGetSymbolicLink) 00118 #pragma alloc_text(PAGE,CmpComputeHashValue) 00119 #pragma alloc_text(PAGE,CmpCacheLookup) 00120 #pragma alloc_text(PAGE,CmpAddInfoAfterParseFailure) 00121 #endif 00122 00123 /* 00124 VOID 00125 CmpStepThroughExit( 00126 IN OUT PHHIVE *Hive, 00127 IN OUT HCELL_INDEX *Cell, 00128 IN OUT PCM_KEY_NODE *pNode 00129 ) 00130 */ 00131 #define CmpStepThroughExit(h,c,n) \ 00132 if ((n)->Flags & KEY_HIVE_EXIT) { \ 00133 (h)=(n)->ChildHiveReference.KeyHive; \ 00134 (c)=(n)->ChildHiveReference.KeyCell; \ 00135 (n)=(PCM_KEY_NODE)HvGetCell((h),(c)); \ 00136 } 00137 00138 #define CMP_PARSE_GOTO_NONE 0 00139 #define CMP_PARSE_GOTO_CREATE 1 00140 #define CMP_PARSE_GOTO_RETURN 2 00141 #define CMP_PARSE_GOTO_RETURN2 3 00142 00143 00144 NTSTATUS 00145 CmpParseKey( 00146 IN PVOID ParseObject, 00147 IN PVOID ObjectType, 00148 IN OUT PACCESS_STATE AccessState, 00149 IN KPROCESSOR_MODE AccessMode, 00150 IN ULONG Attributes, 00151 IN OUT PUNICODE_STRING CompleteName, 00152 IN OUT PUNICODE_STRING RemainingName, 00153 IN OUT PVOID Context OPTIONAL, 00154 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, 00155 OUT PVOID *Object 00156 ) 00157 /*++ 00158 00159 Routine Description: 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 } 00857 00858 00859 BOOLEAN 00860 CmpGetNextName( 00861 IN OUT PUNICODE_STRING RemainingName, 00862 OUT PUNICODE_STRING NextName, 00863 OUT PBOOLEAN Last 00864 ) 00865 /*++ 00866 00867 Routine Description: 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 } 00960 00961 00962 NTSTATUS 00963 CmpDoOpen( 00964 IN PHHIVE Hive, 00965 IN HCELL_INDEX Cell, 00966 IN PCM_KEY_NODE Node, 00967 IN PACCESS_STATE AccessState, 00968 IN KPROCESSOR_MODE AccessMode, 00969 IN ULONG Attributes, 00970 IN PCM_PARSE_CONTEXT Context, 00971 IN BOOLEAN CompleteKeyCached, 00972 IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb, 00973 IN PUNICODE_STRING KeyName, 00974 OUT PVOID *Object 00975 ) 00976 /*++ 00977 00978 Routine Description: 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 } 01249 01250 01251 NTSTATUS 01252 CmpCreateLinkNode( 01253 IN PHHIVE Hive, 01254 IN HCELL_INDEX Cell, 01255 IN PACCESS_STATE AccessState, 01256 IN UNICODE_STRING Name, 01257 IN KPROCESSOR_MODE AccessMode, 01258 IN ULONG Attributes, 01259 IN PCM_PARSE_CONTEXT Context, 01260 IN PCM_KEY_CONTROL_BLOCK ParentKcb, 01261 OUT PVOID *Object 01262 ) 01263 /*++ 01264 01265 Routine Description: 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 } 01474 01475 BOOLEAN 01476 CmpGetSymbolicLink( 01477 IN PHHIVE Hive, 01478 IN PCM_KEY_NODE Node, 01479 IN OUT PUNICODE_STRING ObjectName, 01480 IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb, 01481 IN PUNICODE_STRING RemainingName OPTIONAL 01482 ) 01483 01484 /*++ 01485 01486 Routine Description: 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 } 01734 01735 01736 ULONG 01737 CmpComputeHashValue( 01738 IN PCM_HASH_ENTRY HashStack, 01739 IN OUT ULONG *TotalSubkeys, 01740 IN ULONG BaseConvKey, 01741 IN PUNICODE_STRING RemainingName 01742 ) 01743 01744 /*++ 01745 01746 Routine Description: 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 } 01852 NTSTATUS 01853 CmpCacheLookup( 01854 IN PCM_HASH_ENTRY HashStack, 01855 IN ULONG TotalRemainingSubkeys, 01856 OUT ULONG *MatchRemainSubkeyLevel, 01857 IN OUT PCM_KEY_CONTROL_BLOCK *Kcb, 01858 OUT PUNICODE_STRING RemainingName, 01859 OUT PHHIVE *Hive, 01860 OUT HCELL_INDEX *Cell 01861 ) 01862 /*++ 01863 01864 Routine Description: 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 } 02053 02054 02055 PCM_KEY_CONTROL_BLOCK 02056 CmpAddInfoAfterParseFailure( 02057 PHHIVE Hive, 02058 HCELL_INDEX Cell, 02059 PCM_KEY_NODE Node, 02060 PCM_KEY_CONTROL_BLOCK kcb, 02061 PUNICODE_STRING NodeName 02062 ) 02063 /*++ 02064 02065 Routine Description: 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 }

Generated on Sat May 15 19:39:28 2004 for test by doxygen 1.3.7