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

cmapi.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1991 Microsoft Corporation 00004 00005 Module Name: 00006 00007 cmapi.c 00008 00009 Abstract: 00010 00011 This module contains CM level entry points for the registry. 00012 00013 Author: 00014 00015 Bryan M. Willman (bryanwi) 30-Aug-1991 00016 00017 Revision History: 00018 00019 --*/ 00020 00021 #include "cmp.h" 00022 00023 00024 00025 extern BOOLEAN CmpNoWrite; 00026 00027 extern LIST_ENTRY CmpHiveListHead; 00028 00029 extern BOOLEAN CmpProfileLoaded; 00030 extern BOOLEAN CmpWasSetupBoot; 00031 00032 extern PUCHAR CmpStashBuffer; 00033 extern ULONG CmpStashBufferSize; 00034 00035 extern UNICODE_STRING CmSymbolicLinkValueName; 00036 00037 extern ULONG CmpGlobalQuotaAllowed; 00038 extern ULONG CmpGlobalQuotaWarning; 00039 00040 // 00041 // procedures private to this file 00042 // 00043 NTSTATUS 00044 CmpSetValueKeyExisting( 00045 IN PHHIVE Hive, 00046 IN HCELL_INDEX OldChild, 00047 IN PCELL_DATA Value, 00048 IN ULONG Type, 00049 IN PVOID Data, 00050 IN ULONG DataSize, 00051 IN ULONG StorageType, 00052 IN ULONG TempData 00053 ); 00054 00055 00056 NTSTATUS 00057 CmpSetValueKeyNew( 00058 IN PHHIVE Hive, 00059 IN PCM_KEY_NODE Parent, 00060 IN PUNICODE_STRING ValueName, 00061 IN ULONG Type, 00062 IN PVOID Data, 00063 IN ULONG DataSize, 00064 IN ULONG StorageType, 00065 IN ULONG TempData 00066 ); 00067 00068 #ifdef ALLOC_PRAGMA 00069 #pragma alloc_text(PAGE,CmDeleteValueKey) 00070 #pragma alloc_text(PAGE,CmEnumerateKey) 00071 #pragma alloc_text(PAGE,CmEnumerateValueKey) 00072 #pragma alloc_text(PAGE,CmFlushKey) 00073 #pragma alloc_text(PAGE,CmQueryKey) 00074 #pragma alloc_text(PAGE,CmQueryValueKey) 00075 #pragma alloc_text(PAGE,CmQueryMultipleValueKey) 00076 #pragma alloc_text(PAGE,CmSetValueKey) 00077 #pragma alloc_text(PAGE,CmpSetValueKeyExisting) 00078 #pragma alloc_text(PAGE,CmpSetValueKeyNew) 00079 #pragma alloc_text(PAGE,CmSetLastWriteTimeKey) 00080 #pragma alloc_text(PAGE,CmLoadKey) 00081 #pragma alloc_text(PAGE,CmUnloadKey) 00082 #pragma alloc_text(PAGE,CmpDoFlushAll) 00083 #pragma alloc_text(PAGE,CmReplaceKey) 00084 00085 #ifdef _WRITE_PROTECTED_REGISTRY_POOL 00086 #pragma alloc_text(PAGE,CmpMarkAllBinsReadOnly) 00087 #endif 00088 00089 #endif 00090 00091 NTSTATUS 00092 CmDeleteValueKey( 00093 IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, 00094 IN UNICODE_STRING ValueName // RAW 00095 ) 00096 /*++ 00097 00098 Routine Description: 00099 00100 One of the value entries of a registry key may be removed with this call. 00101 00102 The value entry with ValueName matching ValueName is removed from the key. 00103 If no such entry exists, an error is returned. 00104 00105 Arguments: 00106 00107 KeyControlBlock - pointer to kcb for key to operate on 00108 00109 ValueName - The name of the value to be deleted. NULL is a legal name. 00110 00111 Return Value: 00112 00113 NTSTATUS - Result code from call, among the following: 00114 00115 <TBS> 00116 00117 --*/ 00118 { 00119 NTSTATUS status; 00120 PCM_KEY_NODE pcell; 00121 PCHILD_LIST plist; 00122 PCELL_DATA targetaddress; 00123 ULONG targetindex; 00124 ULONG newcount; 00125 HCELL_INDEX newcell; 00126 HCELL_INDEX ChildCell; 00127 PHHIVE Hive; 00128 HCELL_INDEX Cell; 00129 ULONG realsize; 00130 LARGE_INTEGER systemtime; 00131 00132 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmDeleteValueKey\n")); 00133 00134 CmpLockRegistryExclusive(); 00135 00136 try { 00137 // 00138 // no edits, not even this one, on keys marked for deletion 00139 // 00140 if (KeyControlBlock->Delete) { 00141 return STATUS_KEY_DELETED; 00142 } 00143 00144 Hive = KeyControlBlock->KeyHive; 00145 Cell = KeyControlBlock->KeyCell; 00146 pcell = KeyControlBlock->KeyNode; 00147 00148 // Mark the hive as read only 00149 CmpMarkAllBinsReadOnly(Hive); 00150 00151 status = STATUS_OBJECT_NAME_NOT_FOUND; 00152 00153 plist = &(pcell->ValueList); 00154 ChildCell = HCELL_NIL; 00155 00156 if (plist->Count != 0) { 00157 00158 // 00159 // The parent has at least one value, map in the list of 00160 // values and call CmpFindChildInList 00161 // 00162 00163 // 00164 // plist -> the CHILD_LIST structure 00165 // pchild -> the child node structure being examined 00166 // 00167 00168 ChildCell = CmpFindNameInList(Hive, 00169 plist, 00170 &ValueName, 00171 &targetaddress, 00172 &targetindex); 00173 00174 if (ChildCell != HCELL_NIL) { 00175 00176 // 00177 // 1. the desired target was found 00178 // 2. ChildCell is it's HCELL_INDEX 00179 // 3. targetaddress points to it 00180 // 4. targetindex is it's index 00181 // 00182 00183 // 00184 // attempt to mark all relevent cells dirty 00185 // 00186 if (!(HvMarkCellDirty(Hive, Cell) && 00187 HvMarkCellDirty(Hive, pcell->ValueList.List) && 00188 HvMarkCellDirty(Hive, ChildCell))) 00189 00190 { 00191 // Mark the hive as read only 00192 CmpMarkAllBinsReadOnly(Hive); 00193 00194 return STATUS_NO_LOG_SPACE; 00195 } 00196 00197 if (!CmpIsHKeyValueSmall(realsize,targetaddress->u.KeyValue.DataLength)) { 00198 00199 if (!HvMarkCellDirty(Hive, targetaddress->u.KeyValue.Data)) { 00200 00201 // Mark the hive as read only 00202 CmpMarkAllBinsReadOnly(Hive); 00203 00204 return(STATUS_NO_LOG_SPACE); 00205 } 00206 } 00207 00208 newcount = plist->Count - 1; 00209 00210 if (newcount > 0) { 00211 PCELL_DATA pvector; 00212 00213 // 00214 // more than one entry list, squeeze 00215 // 00216 pvector = HvGetCell(Hive, plist->List); 00217 for ( ; targetindex < newcount; targetindex++) { 00218 pvector->u.KeyList[ targetindex ] = 00219 pvector->u.KeyList[ targetindex+1 ]; 00220 } 00221 00222 newcell = HvReallocateCell( 00223 Hive, 00224 plist->List, 00225 newcount * sizeof(HCELL_INDEX) 00226 ); 00227 ASSERT(newcell != HCELL_NIL); 00228 plist->List = newcell; 00229 00230 } else { 00231 00232 // 00233 // list is empty, free it 00234 // 00235 HvFreeCell(Hive, plist->List); 00236 } 00237 plist->Count = newcount; 00238 CmpFreeValue(Hive, ChildCell); 00239 00240 KeQuerySystemTime(&systemtime); 00241 pcell->LastWriteTime = systemtime; 00242 00243 if (pcell->ValueList.Count == 0) { 00244 pcell->MaxValueNameLen = 0; 00245 pcell->MaxValueDataLen = 0; 00246 } 00247 00248 // 00249 // We are changing the KCB cache. Since the registry is locked exclusively, 00250 // we do not need a KCB lock. 00251 // 00252 ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); 00253 00254 // 00255 // Invalidate the cache 00256 // 00257 CmpCleanUpKcbValueCache(KeyControlBlock); 00258 00259 KeyControlBlock->ValueCache.Count = plist->Count; 00260 KeyControlBlock->ValueCache.ValueList = (ULONG_PTR) plist->List; 00261 00262 CmpReportNotify( 00263 KeyControlBlock, 00264 KeyControlBlock->KeyHive, 00265 KeyControlBlock->KeyCell, 00266 REG_NOTIFY_CHANGE_LAST_SET 00267 ); 00268 status = STATUS_SUCCESS; 00269 } else { 00270 status = STATUS_OBJECT_NAME_NOT_FOUND; 00271 } 00272 } 00273 } finally { 00274 CmpUnlockRegistry(); 00275 } 00276 00277 // Mark the hive as read only 00278 CmpMarkAllBinsReadOnly(Hive); 00279 00280 return status; 00281 } 00282 00283 00284 NTSTATUS 00285 CmEnumerateKey( 00286 IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, 00287 IN ULONG Index, 00288 IN KEY_INFORMATION_CLASS KeyInformationClass, 00289 IN PVOID KeyInformation, 00290 IN ULONG Length, 00291 IN PULONG ResultLength 00292 ) 00293 /*++ 00294 00295 Routine Description: 00296 00297 Enumerate sub keys, return data on Index'th entry. 00298 00299 CmEnumerateKey returns the name of the Index'th sub key of the open 00300 key specified. The value STATUS_NO_MORE_ENTRIES will be 00301 returned if value of Index is larger than the number of sub keys. 00302 00303 Note that Index is simply a way to select among child keys. Two calls 00304 to CmEnumerateKey with the same Index are NOT guaranteed to return 00305 the same results. 00306 00307 If KeyInformation is not long enough to hold all requested data, 00308 STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be 00309 set to the number of bytes actually required. 00310 00311 Arguments: 00312 00313 KeyControlBlock - pointer to the KCB that describes the key 00314 00315 Index - Specifies the (0-based) number of the sub key to be returned. 00316 00317 KeyInformationClass - Specifies the type of information returned in 00318 Buffer. One of the following types: 00319 00320 KeyBasicInformation - return last write time, title index, and name. 00321 (see KEY_BASIC_INFORMATION structure) 00322 00323 KeyNodeInformation - return last write time, title index, name, class. 00324 (see KEY_NODE_INFORMATION structure) 00325 00326 KeyInformation -Supplies pointer to buffer to receive the data. 00327 00328 Length - Length of KeyInformation in bytes. 00329 00330 ResultLength - Number of bytes actually written into KeyInformation. 00331 00332 Return Value: 00333 00334 NTSTATUS - Result code from call, among the following: 00335 00336 <TBS> 00337 00338 --*/ 00339 { 00340 NTSTATUS status; 00341 HCELL_INDEX childcell; 00342 PHHIVE Hive; 00343 HCELL_INDEX Cell; 00344 PCM_KEY_NODE Node; 00345 00346 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmEnumerateKey\n")); 00347 00348 00349 CmpLockRegistry(); 00350 00351 if (KeyControlBlock->Delete) { 00352 CmpUnlockRegistry(); 00353 return STATUS_KEY_DELETED; 00354 } 00355 00356 Hive = KeyControlBlock->KeyHive; 00357 Cell = KeyControlBlock->KeyCell; 00358 00359 // Mark the hive as read only 00360 CmpMarkAllBinsReadOnly(Hive); 00361 00362 // 00363 // fetch the child of interest 00364 // 00365 00366 childcell = CmpFindSubKeyByNumber(Hive, KeyControlBlock->KeyNode, Index); 00367 if (childcell == HCELL_NIL) { 00368 // 00369 // no such child, clean up and return error 00370 // 00371 00372 CmpUnlockRegistry(); 00373 00374 // Mark the hive as read only 00375 CmpMarkAllBinsReadOnly(Hive); 00376 00377 return STATUS_NO_MORE_ENTRIES; 00378 } 00379 00380 Node = (PCM_KEY_NODE)HvGetCell(Hive,childcell); 00381 00382 try { 00383 00384 // 00385 // call a worker to perform data transfer 00386 // 00387 00388 status = CmpQueryKeyData(Hive, 00389 Node, 00390 KeyInformationClass, 00391 KeyInformation, 00392 Length, 00393 ResultLength); 00394 00395 } except (EXCEPTION_EXECUTE_HANDLER) { 00396 CmpUnlockRegistry(); 00397 status = GetExceptionCode(); 00398 00399 // Mark the hive as read only 00400 CmpMarkAllBinsReadOnly(Hive); 00401 00402 return status; 00403 } 00404 00405 CmpUnlockRegistry(); 00406 00407 // Mark the hive as read only 00408 CmpMarkAllBinsReadOnly(Hive); 00409 00410 return status; 00411 } 00412 00413 00414 00415 NTSTATUS 00416 CmEnumerateValueKey( 00417 IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, 00418 IN ULONG Index, 00419 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 00420 IN PVOID KeyValueInformation, 00421 IN ULONG Length, 00422 IN PULONG ResultLength 00423 ) 00424 /*++ 00425 00426 Routine Description: 00427 00428 The value entries of an open key may be enumerated. 00429 00430 CmEnumerateValueKey returns the name of the Index'th value 00431 entry of the open key specified by KeyHandle. The value 00432 STATUS_NO_MORE_ENTRIES will be returned if value of Index is 00433 larger than the number of sub keys. 00434 00435 Note that Index is simply a way to select among value 00436 entries. Two calls to NtEnumerateValueKey with the same Index 00437 are NOT guaranteed to return the same results. 00438 00439 If KeyValueInformation is not long enough to hold all requested data, 00440 STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be 00441 set to the number of bytes actually required. 00442 00443 Arguments: 00444 00445 KeyControlBlock - pointer to the KCB that describes the key 00446 00447 Index - Specifies the (0-based) number of the sub key to be returned. 00448 00449 KeyValueInformationClass - Specifies the type of information returned 00450 in Buffer. One of the following types: 00451 00452 KeyValueBasicInformation - return time of last write, 00453 title index, and name. (See KEY_VALUE_BASIC_INFORMATION) 00454 00455 KeyValueFullInformation - return time of last write, 00456 title index, name, class. (See KEY_VALUE_FULL_INFORMATION) 00457 00458 KeyValueInformation -Supplies pointer to buffer to receive the data. 00459 00460 Length - Length of KeyValueInformation in bytes. 00461 00462 ResultLength - Number of bytes actually written into KeyValueInformation. 00463 00464 Return Value: 00465 00466 NTSTATUS - Result code from call, among the following: 00467 00468 <TBS> 00469 00470 --*/ 00471 { 00472 NTSTATUS status; 00473 PHHIVE Hive; 00474 PCM_KEY_NODE Node; 00475 PCELL_DATA ChildList; 00476 PCM_KEY_VALUE ValueData; 00477 BOOLEAN IndexCached; 00478 BOOLEAN ValueCached; 00479 PPCM_CACHED_VALUE ContainingList; 00480 00481 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmEnumerateValueKey\n")); 00482 00483 00484 // 00485 // lock the parent cell 00486 // 00487 00488 CmpLockRegistry(); 00489 00490 if (KeyControlBlock->Delete) { 00491 CmpUnlockRegistry(); 00492 return STATUS_KEY_DELETED; 00493 } 00494 Hive = KeyControlBlock->KeyHive; 00495 Node = KeyControlBlock->KeyNode; 00496 00497 // 00498 // fetch the child of interest 00499 // 00500 // 00501 // Do it using the cache 00502 // 00503 if (Index >= KeyControlBlock->ValueCache.Count) { 00504 // 00505 // No such child, clean up and return error. 00506 // 00507 CmpUnlockRegistry(); 00508 return(STATUS_NO_MORE_ENTRIES); 00509 } 00510 00511 // Mark the hive as read only 00512 CmpMarkAllBinsReadOnly(Hive); 00513 00514 LOCK_KCB_TREE(); 00515 if (KeyControlBlock->ExtFlags & CM_KCB_SYM_LINK_FOUND) { 00516 // 00517 // The value list is now set to the KCB for symbolic link, 00518 // Clean it up and set the value right before we do the query. 00519 // 00520 CmpDereferenceKeyControlBlockWithLock(KeyControlBlock->ValueCache.RealKcb); 00521 KeyControlBlock->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND; 00522 00523 KeyControlBlock->ValueCache.Count = KeyControlBlock->KeyNode->ValueList.Count; 00524 KeyControlBlock->ValueCache.ValueList = (ULONG_PTR) KeyControlBlock->KeyNode->ValueList.List; 00525 } 00526 00527 ChildList = CmpGetValueListFromCache(Hive, &(KeyControlBlock->ValueCache), &IndexCached); 00528 ValueData = CmpGetValueKeyFromCache(Hive, ChildList, Index, &ContainingList, IndexCached, &ValueCached); 00529 00530 try { 00531 00532 // Trying to catch the BAD guy who writes over our pool. 00533 CmpMakeValueCacheReadWrite(ValueCached,CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList)); 00534 00535 // 00536 // call a worker to perform data transfer 00537 // 00538 status = CmpQueryKeyValueData(Hive, 00539 ContainingList, 00540 ValueData, 00541 ValueCached, 00542 KeyValueInformationClass, 00543 KeyValueInformation, 00544 Length, 00545 ResultLength); 00546 00547 // Trying to catch the BAD guy who writes over our pool. 00548 CmpMakeValueCacheReadOnly(ValueCached,CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList)); 00549 } finally { 00550 00551 UNLOCK_KCB_TREE(); 00552 CmpUnlockRegistry(); 00553 } 00554 00555 // Mark the hive as read only 00556 CmpMarkAllBinsReadOnly(Hive); 00557 00558 return status; 00559 } 00560 00561 00562 00563 NTSTATUS 00564 CmFlushKey( 00565 IN PHHIVE Hive, 00566 IN HCELL_INDEX Cell 00567 ) 00568 /*++ 00569 00570 Routine Description: 00571 00572 Forces changes made to a key to disk. 00573 00574 CmFlushKey will not return to its caller until any changed data 00575 associated with the key has been written out. 00576 00577 WARNING: CmFlushKey will flush the entire registry tree, and thus will 00578 burn cycles and I/O. 00579 00580 Arguments: 00581 00582 Hive - supplies a pointer to the hive control structure for the hive 00583 00584 Cell - supplies index of node to whose sub keys are to be found 00585 00586 Return Value: 00587 00588 NTSTATUS - Result code from call, among the following: 00589 00590 <TBS> 00591 00592 --*/ 00593 { 00594 PCMHIVE CmHive; 00595 NTSTATUS status = STATUS_SUCCESS; 00596 extern PCMHIVE CmpMasterHive; 00597 00598 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmFlushKey\n")); 00599 00600 // 00601 // If writes are not working, lie and say we succeeded, will 00602 // clean up in a short time. Only early system init code 00603 // will ever know the difference. 00604 // 00605 if (CmpNoWrite) { 00606 return STATUS_SUCCESS; 00607 } 00608 00609 00610 // Mark the hive as read only 00611 CmpMarkAllBinsReadOnly(Hive); 00612 00613 CmHive = CONTAINING_RECORD(Hive, CMHIVE, Hive); 00614 00615 // 00616 // Don't flush the master hive. If somebody asks for a flushkey on 00617 // the master hive, do a CmpDoFlushAll instead. CmpDoFlushAll flushes 00618 // every hive except the master hive, which is what they REALLY want. 00619 // 00620 if (CmHive == CmpMasterHive) { 00621 CmpDoFlushAll(); 00622 } else { 00623 DCmCheckRegistry(CONTAINING_RECORD(Hive, CMHIVE, Hive)); 00624 00625 CmLockHive (CmHive); 00626 00627 if (! HvSyncHive(Hive)) { 00628 00629 status = STATUS_REGISTRY_IO_FAILED; 00630 00631 CMLOG(CML_MAJOR, CMS_IO_ERROR) { 00632 KdPrint(("CmFlushKey: HvSyncHive failed\n")); 00633 } 00634 } 00635 00636 CmUnlockHive (CmHive); 00637 } 00638 00639 // Mark the hive as read only 00640 CmpMarkAllBinsReadOnly(Hive); 00641 00642 return status; 00643 } 00644 00645 00646 NTSTATUS 00647 CmQueryKey( 00648 IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, 00649 IN KEY_INFORMATION_CLASS KeyInformationClass, 00650 IN PVOID KeyInformation, 00651 IN ULONG Length, 00652 IN PULONG ResultLength 00653 ) 00654 /*++ 00655 00656 Routine Description: 00657 00658 Data about the class of a key, and the numbers and sizes of its 00659 children and value entries may be queried with CmQueryKey. 00660 00661 NOTE: The returned lengths are guaranteed to be at least as 00662 long as the described values, but may be longer in 00663 some circumstances. 00664 00665 Arguments: 00666 00667 KeyControlBlock - pointer to the KCB that describes the key 00668 00669 KeyInformationClass - Specifies the type of information 00670 returned in Buffer. One of the following types: 00671 00672 KeyBasicInformation - return last write time, title index, and name. 00673 (See KEY_BASIC_INFORMATION) 00674 00675 KeyNodeInformation - return last write time, title index, name, class. 00676 (See KEY_NODE_INFORMATION) 00677 00678 KeyFullInformation - return all data except for name and security. 00679 (See KEY_FULL_INFORMATION) 00680 00681 KeyInformation -Supplies pointer to buffer to receive the data. 00682 00683 Length - Length of KeyInformation in bytes. 00684 00685 ResultLength - Number of bytes actually written into KeyInformation. 00686 00687 Return Value: 00688 00689 NTSTATUS - Result code from call, among the following: 00690 00691 <TBS> 00692 00693 --*/ 00694 { 00695 NTSTATUS status; 00696 00697 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmQueryKey\n")); 00698 00699 00700 00701 CmpLockRegistry(); 00702 00703 // Mark the hive as read only 00704 CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive); 00705 00706 try { 00707 00708 // 00709 // request for the FULL path of the key 00710 // 00711 if( KeyInformationClass == KeyNameInformation ) { 00712 if (KeyControlBlock->Delete ) { 00713 // 00714 // special case: return key deleted status, but still fill the full name of the key. 00715 // 00716 status = STATUS_KEY_DELETED; 00717 } else { 00718 status = STATUS_SUCCESS; 00719 } 00720 00721 if( KeyControlBlock->NameBlock ) { 00722 00723 PUNICODE_STRING Name; 00724 Name = CmpConstructName(KeyControlBlock); 00725 if (Name == NULL) { 00726 status = STATUS_INSUFFICIENT_RESOURCES; 00727 } else { 00728 ULONG requiredlength; 00729 ULONG minimumlength; 00730 USHORT NameLength; 00731 LONG leftlength; 00732 PKEY_INFORMATION pbuffer = (PKEY_INFORMATION)KeyInformation; 00733 00734 NameLength = Name->Length; 00735 00736 requiredlength = FIELD_OFFSET(KEY_NAME_INFORMATION, Name) + NameLength; 00737 00738 minimumlength = FIELD_OFFSET(KEY_NAME_INFORMATION, Name); 00739 00740 *ResultLength = requiredlength; 00741 if (Length < minimumlength) { 00742 00743 status = STATUS_BUFFER_TOO_SMALL; 00744 00745 } else { 00746 // 00747 // Fill in the length of the name 00748 // 00749 pbuffer->KeyNameInformation.NameLength = NameLength; 00750 00751 // 00752 // Now copy the full name into the user buffer, if enough space 00753 // 00754 leftlength = Length - minimumlength; 00755 requiredlength = NameLength; 00756 if (leftlength < (LONG)requiredlength) { 00757 requiredlength = leftlength; 00758 status = STATUS_BUFFER_OVERFLOW; 00759 } 00760 00761 // 00762 // If not enough space, copy how much we can and return overflow 00763 // 00764 RtlCopyMemory( 00765 &(pbuffer->KeyNameInformation.Name[0]), 00766 Name->Buffer, 00767 requiredlength 00768 ); 00769 } 00770 00771 ExFreePoolWithTag(Name, CM_NAME_TAG | PROTECTED_POOL); 00772 } 00773 } 00774 } else if(KeyControlBlock->Delete ) { 00775 // 00776 // key already deleted 00777 // 00778 status = STATUS_KEY_DELETED; 00779 } else { 00780 // 00781 // call a worker to perform data transfer 00782 // 00783 00784 status = CmpQueryKeyData(KeyControlBlock->KeyHive, 00785 KeyControlBlock->KeyNode, 00786 KeyInformationClass, 00787 KeyInformation, 00788 Length, 00789 ResultLength); 00790 } 00791 00792 } finally { 00793 CmpUnlockRegistry(); 00794 } 00795 00796 // Mark the hive as read only 00797 CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive); 00798 00799 return status; 00800 } 00801 00802 00803 NTSTATUS 00804 CmQueryValueKey( 00805 IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, 00806 IN UNICODE_STRING ValueName, 00807 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 00808 IN PVOID KeyValueInformation, 00809 IN ULONG Length, 00810 IN PULONG ResultLength 00811 ) 00812 /*++ 00813 00814 Routine Description: 00815 00816 The ValueName, TitleIndex, Type, and Data for any one of a key's 00817 value entries may be queried with CmQueryValueKey. 00818 00819 If KeyValueInformation is not long enough to hold all requested data, 00820 STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be 00821 set to the number of bytes actually required. 00822 00823 Arguments: 00824 00825 KeyControlBlock - pointer to the KCB that describes the key 00826 00827 ValueName - The name of the value entry to return data for. 00828 00829 KeyValueInformationClass - Specifies the type of information 00830 returned in KeyValueInformation. One of the following types: 00831 00832 KeyValueBasicInformation - return time of last write, title 00833 index, and name. (See KEY_VALUE_BASIC_INFORMATION) 00834 00835 KeyValueFullInformation - return time of last write, title 00836 index, name, class. (See KEY_VALUE_FULL_INFORMATION) 00837 00838 KeyValueInformation -Supplies pointer to buffer to receive the data. 00839 00840 Length - Length of KeyValueInformation in bytes. 00841 00842 ResultLength - Number of bytes actually written into KeyValueInformation. 00843 00844 Return Value: 00845 00846 NTSTATUS - Result code from call, among the following: 00847 00848 <TBS> 00849 00850 --*/ 00851 { 00852 NTSTATUS status; 00853 HCELL_INDEX childcell; 00854 PHCELL_INDEX childindex; 00855 HCELL_INDEX Cell; 00856 PCM_KEY_VALUE ValueData; 00857 ULONG Index; 00858 BOOLEAN ValueCached; 00859 PPCM_CACHED_VALUE ContainingList; 00860 00861 PAGED_CODE(); 00862 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmQueryValueKey\n")); 00863 00864 00865 CmpLockRegistry(); 00866 00867 if (KeyControlBlock->Delete) { 00868 CmpUnlockRegistry(); 00869 return STATUS_KEY_DELETED; 00870 } 00871 00872 // Mark the hive as read only 00873 CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive); 00874 00875 LOCK_KCB_TREE(); 00876 00877 if (KeyControlBlock->ExtFlags & CM_KCB_SYM_LINK_FOUND) { 00878 // 00879 // The value list is now set to the KCB for symbolic link, 00880 // Clean it up and set the value right before we do the query. 00881 // 00882 CmpDereferenceKeyControlBlockWithLock(KeyControlBlock->ValueCache.RealKcb); 00883 KeyControlBlock->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND; 00884 00885 KeyControlBlock->ValueCache.Count = KeyControlBlock->KeyNode->ValueList.Count; 00886 KeyControlBlock->ValueCache.ValueList = (ULONG_PTR) KeyControlBlock->KeyNode->ValueList.List; 00887 } 00888 00889 00890 try { 00891 // 00892 // Find the data 00893 // 00894 00895 ValueData = CmpFindValueByNameFromCache(KeyControlBlock->KeyHive, 00896 &(KeyControlBlock->ValueCache), 00897 &ValueName, 00898 &ContainingList, 00899 &Index, 00900 &ValueCached 00901 ); 00902 if (ValueData) { 00903 00904 // Trying to catch the BAD guy who writes over our pool. 00905 CmpMakeValueCacheReadWrite(ValueCached,CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList)); 00906 00907 // 00908 // call a worker to perform data transfer 00909 // 00910 00911 status = CmpQueryKeyValueData(KeyControlBlock->KeyHive, 00912 ContainingList, 00913 ValueData, 00914 ValueCached, 00915 KeyValueInformationClass, 00916 KeyValueInformation, 00917 Length, 00918 ResultLength); 00919 00920 // Trying to catch the BAD guy who writes over our pool. 00921 CmpMakeValueCacheReadOnly(ValueCached,CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList)); 00922 00923 } else { 00924 status = STATUS_OBJECT_NAME_NOT_FOUND; 00925 } 00926 00927 } finally { 00928 UNLOCK_KCB_TREE(); 00929 CmpUnlockRegistry(); 00930 } 00931 00932 // Mark the hive as read only 00933 CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive); 00934 00935 return status; 00936 } 00937 00938 00939 NTSTATUS 00940 CmQueryMultipleValueKey( 00941 IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, 00942 IN PKEY_VALUE_ENTRY ValueEntries, 00943 IN ULONG EntryCount, 00944 IN PVOID ValueBuffer, 00945 IN OUT PULONG BufferLength, 00946 IN OPTIONAL PULONG ResultLength 00947 ) 00948 /*++ 00949 00950 Routine Description: 00951 00952 Multiple values of any key may be queried atomically with 00953 this api. 00954 00955 Arguments: 00956 00957 KeyControlBlock - Supplies the key to be queried. 00958 00959 ValueEntries - Returns an array of KEY_VALUE_ENTRY structures, one for each value. 00960 00961 EntryCount - Supplies the number of entries in the ValueNames and ValueEntries arrays 00962 00963 ValueBuffer - Returns the value data for each value. 00964 00965 BufferLength - Supplies the length of the ValueBuffer array in bytes. 00966 Returns the length of the ValueBuffer array that was filled in. 00967 00968 ResultLength - if present, Returns the length in bytes of the ValueBuffer 00969 array required to return the requested values of this key. 00970 00971 Return Value: 00972 00973 NTSTATUS 00974 00975 --*/ 00976 00977 { 00978 PHHIVE Hive; 00979 NTSTATUS Status; 00980 ULONG i; 00981 UNICODE_STRING CurrentName; 00982 HCELL_INDEX ValueCell; 00983 PCM_KEY_VALUE ValueNode; 00984 ULONG RequiredLength = 0; 00985 ULONG UsedLength = 0; 00986 ULONG DataLength; 00987 BOOLEAN BufferFull = FALSE; 00988 BOOLEAN Small; 00989 PUCHAR Data; 00990 KPROCESSOR_MODE PreviousMode; 00991 00992 PAGED_CODE(); 00993 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmQueryMultipleValueKey\n")); 00994 00995 00996 CmpLockRegistry(); 00997 if (KeyControlBlock->Delete) { 00998 CmpUnlockRegistry(); 00999 return STATUS_KEY_DELETED; 01000 } 01001 Hive = KeyControlBlock->KeyHive; 01002 Status = STATUS_SUCCESS; 01003 01004 // Mark the hive as read only 01005 CmpMarkAllBinsReadOnly(Hive); 01006 01007 PreviousMode = KeGetPreviousMode(); 01008 try { 01009 for (i=0; i < EntryCount; i++) { 01010 // 01011 // find the data 01012 // 01013 if (PreviousMode == UserMode) { 01014 CurrentName = ProbeAndReadUnicodeString(ValueEntries[i].ValueName); 01015 ProbeForRead(CurrentName.Buffer,CurrentName.Length,sizeof(WCHAR)); 01016 } else { 01017 CurrentName = *(ValueEntries[i].ValueName); 01018 } 01019 ValueCell = CmpFindValueByName(Hive, 01020 KeyControlBlock->KeyNode, 01021 &CurrentName); 01022 if (ValueCell != HCELL_NIL) { 01023 01024 ValueNode = (PCM_KEY_VALUE)HvGetCell(Hive, ValueCell); 01025 Small = CmpIsHKeyValueSmall(DataLength, ValueNode->DataLength); 01026 01027 // 01028 // Round up UsedLength and RequiredLength to a ULONG boundary 01029 // 01030 UsedLength = (UsedLength + sizeof(ULONG)-1) & ~(sizeof(ULONG)-1); 01031 RequiredLength = (RequiredLength + sizeof(ULONG)-1) & ~(sizeof(ULONG)-1); 01032 01033 // 01034 // If there is enough room for this data value in the buffer, 01035 // fill it in now. Otherwise, mark the buffer as full. We must 01036 // keep iterating through the values in order to determine the 01037 // RequiredLength. 01038 // 01039 if ((UsedLength + DataLength <= *BufferLength) && 01040 (!BufferFull)) { 01041 if (DataLength > 0) { 01042 if (Small) { 01043 Data = (PUCHAR)&ValueNode->Data; 01044 } else { 01045 Data = (PUCHAR)HvGetCell(Hive, ValueNode->Data); 01046 } 01047 RtlCopyMemory((PUCHAR)ValueBuffer + UsedLength, 01048 Data, 01049 DataLength); 01050 } 01051 ValueEntries[i].Type = ValueNode->Type; 01052 ValueEntries[i].DataLength = DataLength; 01053 ValueEntries[i].DataOffset = UsedLength; 01054 UsedLength += DataLength; 01055 } else { 01056 BufferFull = TRUE; 01057 Status = STATUS_BUFFER_OVERFLOW; 01058 } 01059 RequiredLength += DataLength; 01060 01061 } else { 01062 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01063 break; 01064 } 01065 } 01066 01067 if (NT_SUCCESS(Status) || 01068 (Status == STATUS_BUFFER_OVERFLOW)) { 01069 *BufferLength = UsedLength; 01070 if (ARGUMENT_PRESENT(ResultLength)) { 01071 *ResultLength = RequiredLength; 01072 } 01073 } 01074 01075 } finally { 01076 CmpUnlockRegistry(); 01077 } 01078 01079 // Mark the hive as read only 01080 CmpMarkAllBinsReadOnly(Hive); 01081 01082 return Status; 01083 } 01084 01085 01086 NTSTATUS 01087 CmSetValueKey( 01088 IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, 01089 IN PUNICODE_STRING ValueName, 01090 IN ULONG Type, 01091 IN PVOID Data, 01092 IN ULONG DataSize 01093 ) 01094 /*++ 01095 01096 Routine Description: 01097 01098 A value entry may be created or replaced with CmSetValueKey. 01099 01100 If a value entry with a Value ID (i.e. name) matching the 01101 one specified by ValueName exists, it is deleted and replaced 01102 with the one specified. If no such value entry exists, a new 01103 one is created. NULL is a legal Value ID. While Value IDs must 01104 be unique within any given key, the same Value ID may appear 01105 in many different keys. 01106 01107 Arguments: 01108 01109 KeyControlBlock - pointer to kcb for the key to operate on 01110 01111 ValueName - The unique (relative to the containing key) name 01112 of the value entry. May be NULL. 01113 01114 Type - The integer type number of the value entry. 01115 01116 Data - Pointer to buffer with actual data for the value entry. 01117 01118 DataSize - Size of Data buffer. 01119 01120 01121 Return Value: 01122 01123 NTSTATUS - Result code from call, among the following: 01124 01125 <TBS> 01126 01127 --*/ 01128 { 01129 NTSTATUS status; 01130 PCM_KEY_NODE parent; 01131 HCELL_INDEX oldchild; 01132 ULONG count; 01133 PHHIVE Hive; 01134 HCELL_INDEX Cell; 01135 ULONG StorageType; 01136 ULONG TempData; 01137 BOOLEAN found; 01138 PCELL_DATA pdata; 01139 LARGE_INTEGER systemtime; 01140 ULONG compareSize,mustChange=FALSE; 01141 01142 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmSetValueKey\n")); 01143 01144 CmpLockRegistry(); 01145 ASSERT(sizeof(ULONG) == CM_KEY_VALUE_SMALL); 01146 01147 // Mark the hive as read only 01148 CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive); 01149 01150 while (TRUE) { 01151 // 01152 // Check that we are not being asked to add a value to a key 01153 // that has been deleted 01154 // 01155 if (KeyControlBlock->Delete == TRUE) { 01156 status = STATUS_KEY_DELETED; 01157 goto Exit; 01158 } 01159 01160 // 01161 // Check to see if this is a symbolic link node. If so caller 01162 // is only allowed to create/change the SymbolicLinkValue 01163 // value name 01164 // 01165 01166 if (KeyControlBlock->KeyNode->Flags & KEY_SYM_LINK && 01167 (Type != REG_LINK || 01168 ValueName == NULL || 01169 !RtlEqualUnicodeString(&CmSymbolicLinkValueName, ValueName, TRUE))) 01170 { 01171 // 01172 // Disallow attempts to manipulate any value names under a symbolic link 01173 // except for the "SymbolicLinkValue" value name or type other than REG_LINK 01174 // 01175 01176 // Mark the hive as read only 01177 CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive); 01178 01179 status = STATUS_ACCESS_DENIED; 01180 goto Exit; 01181 } 01182 01183 // 01184 // get reference to parent key, 01185 // 01186 Hive = KeyControlBlock->KeyHive; 01187 Cell = KeyControlBlock->KeyCell; 01188 parent = KeyControlBlock->KeyNode; 01189 01190 // 01191 // try to find an existing value entry by the same name 01192 // 01193 count = parent->ValueList.Count; 01194 found = FALSE; 01195 01196 if (count > 0) { 01197 oldchild = CmpFindNameInList(Hive, 01198 &parent->ValueList, 01199 ValueName, 01200 &pdata, 01201 NULL); 01202 01203 if (oldchild != HCELL_NIL) { 01204 found = TRUE; 01205 } 01206 } 01207 // 01208 // Performance Hack: 01209 // If a Set is asking us to set a key to the current value (IE does this a lot) 01210 // drop it (and, therefore, the last modified time) on the floor, but return success 01211 // this stops the page from being dirtied, and us having to flush the registry. 01212 // 01213 // 01214 if (mustChange == TRUE) { 01215 break; //while 01216 } 01217 if ((found) && 01218 (Type == pdata->u.KeyValue.Type)) { 01219 01220 PCELL_DATA pcmpdata; 01221 01222 if (DataSize == (pdata->u.KeyValue.DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE)) { 01223 01224 if (DataSize > 0) { 01225 // 01226 //check for small values 01227 // 01228 if (DataSize <= CM_KEY_VALUE_SMALL ) { 01229 pcmpdata = (PCELL_DATA)&pdata->u.KeyValue.Data; 01230 } else { 01231 pcmpdata = HvGetCell(Hive, pdata->u.KeyValue.Data); 01232 } 01233 01234 try { 01235 compareSize = (ULONG)RtlCompareMemory ((PVOID)pcmpdata,Data,(DataSize & ~CM_KEY_VALUE_SPECIAL_SIZE)); 01236 } except (EXCEPTION_EXECUTE_HANDLER) { 01237 01238 CMLOG(CML_API, CMS_EXCEPTION) { 01239 KdPrint(("!!CmSetValueKey: code:%08lx\n", GetExceptionCode())); 01240 } 01241 status = GetExceptionCode(); 01242 goto Exit; 01243 } 01244 }else { 01245 compareSize = 0; 01246 } 01247 01248 if (compareSize == DataSize) { 01249 status = STATUS_SUCCESS; 01250 goto Exit; 01251 } 01252 } 01253 01254 } 01255 01256 // 01257 // To Get here, we must either be changing a value, or setting a new one 01258 // 01259 mustChange=TRUE; 01260 // 01261 // We're going through these gyrations so that if someone does come in and try and delete the 01262 // key we're setting we're safe. Once we know we have to change the key, take the 01263 // Exclusive (write) lock then restart 01264 // 01265 // 01266 CmpUnlockRegistry(); 01267 CmpLockRegistryExclusive(); 01268 01269 }// while 01270 01271 // It's a different or new value, mark it dirty, since we'll 01272 // at least set its time stamp 01273 01274 if (! HvMarkCellDirty(Hive, Cell)) { 01275 status = STATUS_NO_LOG_SPACE; 01276 goto Exit; 01277 } 01278 01279 StorageType = HvGetCellType(Cell); 01280 01281 // 01282 // stash small data if relevent 01283 // 01284 TempData = 0; 01285 if ((DataSize <= CM_KEY_VALUE_SMALL) && 01286 (DataSize > 0)) 01287 { 01288 try { 01289 RtlMoveMemory( // yes, move memory, could be 1 byte 01290 &TempData, // at the end of a page. 01291 Data, 01292 DataSize 01293 ); 01294 } except (EXCEPTION_EXECUTE_HANDLER) { 01295 CMLOG(CML_API, CMS_EXCEPTION) { 01296 KdPrint(("!!CmSetValueKey: code:%08lx\n", GetExceptionCode())); 01297 } 01298 status = GetExceptionCode(); 01299 goto Exit; 01300 } 01301 } 01302 01303 if (found) { 01304 01305 // 01306 // ----- Existing Value Entry Path ----- 01307 // 01308 01309 // 01310 // An existing value entry of the specified name exists, 01311 // set our data into it. 01312 // 01313 status = CmpSetValueKeyExisting(Hive, 01314 oldchild, 01315 pdata, 01316 Type, 01317 Data, 01318 DataSize, 01319 StorageType, 01320 TempData); 01321 01322 } else { 01323 01324 // 01325 // ----- New Value Entry Path ----- 01326 // 01327 01328 // 01329 // Either there are no existing value entries, or the one 01330 // specified is not in the list. In either case, create and 01331 // fill a new one, and add it to the list 01332 // 01333 status = CmpSetValueKeyNew(Hive, 01334 parent, 01335 ValueName, 01336 Type, 01337 Data, 01338 DataSize, 01339 StorageType, 01340 TempData); 01341 } 01342 01343 if (NT_SUCCESS(status)) { 01344 01345 if (parent->MaxValueNameLen < ValueName->Length) { 01346 parent->MaxValueNameLen = ValueName->Length; 01347 } 01348 01349 if (parent->MaxValueDataLen < DataSize) { 01350 parent->MaxValueDataLen = DataSize; 01351 } 01352 01353 KeQuerySystemTime(&systemtime); 01354 parent->LastWriteTime = systemtime; 01355 01356 // 01357 // Update the cache, no need for KCB lock as the registry is locked exclusively. 01358 // 01359 ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); 01360 01361 CmpCleanUpKcbValueCache(KeyControlBlock); 01362 01363 KeyControlBlock->ValueCache.Count = parent->ValueList.Count; 01364 KeyControlBlock->ValueCache.ValueList = (ULONG_PTR) parent->ValueList.List; 01365 01366 CmpReportNotify(KeyControlBlock, 01367 KeyControlBlock->KeyHive, 01368 KeyControlBlock->KeyCell, 01369 REG_NOTIFY_CHANGE_LAST_SET); 01370 } 01371 01372 Exit: 01373 CmpUnlockRegistry(); 01374 01375 // Mark the hive as read only 01376 CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive); 01377 01378 return status; 01379 } 01380 01381 01382 NTSTATUS 01383 CmpSetValueKeyExisting( 01384 IN PHHIVE Hive, 01385 IN HCELL_INDEX OldChild, 01386 IN PCELL_DATA pvalue, 01387 IN ULONG Type, 01388 IN PVOID Data, 01389 IN ULONG DataSize, 01390 IN ULONG StorageType, 01391 IN ULONG TempData 01392 ) 01393 /*++ 01394 01395 Routine Description: 01396 01397 Helper for CmSetValueKey, implements the case where the value entry 01398 being set already exists. 01399 01400 Arguments: 01401 01402 Hive - hive of interest 01403 01404 OldChild - hcell_index of the value entry body to which we are to 01405 set new data 01406 01407 Type - The integer type number of the value entry. 01408 01409 Data - Pointer to buffer with actual data for the value entry. 01410 01411 DataSize - Size of Data buffer. 01412 01413 StorageType - stable or volatile 01414 01415 TempData - small values are passed here 01416 01417 Return Value: 01418 01419 STATUS_SUCCESS if it worked, appropriate status code if it did not 01420 01421 --*/ 01422 { 01423 HCELL_INDEX DataCell; 01424 PCELL_DATA pdata; 01425 HCELL_INDEX NewCell; 01426 ULONG realsize; 01427 BOOLEAN small; 01428 PUCHAR StashBuffer; 01429 ULONG BufferSize; 01430 01431 ASSERT_CM_LOCK_OWNED(); 01432 01433 01434 // 01435 // value entry by the specified name already exists 01436 // oldchild is hcell_index of its value entry body 01437 // which we will always edit, so mark it dirty 01438 // 01439 if (! HvMarkCellDirty(Hive, OldChild)) { 01440 return STATUS_NO_LOG_SPACE; 01441 } 01442 01443 small = CmpIsHKeyValueSmall(realsize, pvalue->u.KeyValue.DataLength); 01444 01445 if (DataSize <= CM_KEY_VALUE_SMALL) { // small 01446 01447 // 01448 // We are storing a small datum, TempData has data. 01449 // 01450 if ((! small) && (realsize > 0)) 01451 { 01452 // 01453 // value entry has existing external data to free 01454 // 01455 if (! HvMarkCellDirty(Hive, pvalue->u.KeyValue.Data)) { 01456 return STATUS_NO_LOG_SPACE; 01457 } 01458 HvFreeCell(Hive, pvalue->u.KeyValue.Data); 01459 } 01460 01461 // 01462 // write our new small data into value entry body 01463 // 01464 pvalue->u.KeyValue.DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; 01465 pvalue->u.KeyValue.Data = TempData; 01466 pvalue->u.KeyValue.Type = Type; 01467 01468 return STATUS_SUCCESS; 01469 01470 } else { // large 01471 01472 // 01473 // We are storing a "large" datum 01474 // 01475 01476 // 01477 // See if we can write data on top of existing cell 01478 // 01479 if ((! small) && (realsize > 0)) { 01480 01481 DataCell = pvalue->u.KeyValue.Data; 01482 ASSERT(DataCell != HCELL_NIL); 01483 pdata = HvGetCell(Hive, DataCell); 01484 01485 ASSERT(HvGetCellSize(Hive, pdata) > 0); 01486 01487 if (DataSize <= (ULONG)(HvGetCellSize(Hive, pdata))) { 01488 01489 // 01490 // The existing data cell is big enough to hold the 01491 // new data. Attempt to copy to stash buffer. if 01492 // we succeed we can copy directly onto the old cell. 01493 // if we fail, we must allocate and fill a new cell, 01494 // and replace the old one with it. 01495 // 01496 if (! HvMarkCellDirty(Hive, DataCell)) { 01497 return STATUS_NO_LOG_SPACE; 01498 } 01499 01500 StashBuffer = NULL; 01501 if (DataSize <= CmpStashBufferSize) { 01502 01503 StashBuffer = CmpStashBuffer; 01504 01505 } else if (DataSize <= CM_MAX_STASH) { 01506 01507 // 01508 // Try to allocate a bigger stash buffer. If it works, keep it and 01509 // free the old one. This prevents pool from becoming too fragmented 01510 // if somebody (like SAM) is repeatedly setting very large values 01511 // 01512 BufferSize = ((DataSize + PAGE_SIZE) & ~(PAGE_SIZE-1)); 01513 01514 StashBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, 'bSmC'); 01515 if (StashBuffer != NULL) { 01516 ExFreePool(CmpStashBuffer); 01517 CmpStashBuffer = StashBuffer; 01518 CmpStashBufferSize = BufferSize; 01519 } 01520 } 01521 01522 if (StashBuffer != NULL) { 01523 // 01524 // We have a stash buffer 01525 // 01526 try { 01527 01528 RtlCopyMemory( 01529 StashBuffer, 01530 Data, 01531 DataSize 01532 ); 01533 01534 } except (EXCEPTION_EXECUTE_HANDLER) { 01535 CMLOG(CML_API, CMS_EXCEPTION) { 01536 KdPrint(("!!CmSetValueKey: code:%08lx\n", GetExceptionCode())); 01537 } 01538 return GetExceptionCode(); 01539 } 01540 01541 01542 // 01543 // We have filled the stash buffer, copy data and finish 01544 // 01545 RtlCopyMemory( 01546 pdata, 01547 StashBuffer, 01548 DataSize 01549 ); 01550 01551 ASSERT(StashBuffer != NULL); 01552 01553 pvalue->u.KeyValue.DataLength = DataSize; 01554 pvalue->u.KeyValue.Type = Type; 01555 01556 return STATUS_SUCCESS; 01557 01558 } // else stashbuffer == null 01559 } // else existing cell is too small 01560 } // else there is no existing cell 01561 } // new cell needed (always large) 01562 01563 // 01564 // Either the existing cell is not large enough, or does 01565 // not exist, or we couldn't stash successfully. 01566 // 01567 // Allocate and fill a new cell. Free the old one. Store 01568 // the new's index into the value entry body. 01569 // 01570 NewCell = HvAllocateCell(Hive, DataSize, StorageType); 01571 01572 if (NewCell == HCELL_NIL) { 01573 return STATUS_INSUFFICIENT_RESOURCES; 01574 } 01575 01576 // 01577 // fill the new data cell 01578 // 01579 pdata = HvGetCell(Hive, NewCell); 01580 try { 01581 01582 RtlMoveMemory( 01583 pdata, 01584 Data, 01585 DataSize 01586 ); 01587 01588 } except (EXCEPTION_EXECUTE_HANDLER) { 01589 CMLOG(CML_API, CMS_EXCEPTION) { 01590 KdPrint(("!!CmSetValueKey: code:%08lx\n", GetExceptionCode())); 01591 } 01592 HvFreeCell(Hive, NewCell); 01593 return GetExceptionCode(); 01594 } 01595 01596 // 01597 // free the old data cell 01598 // 01599 if ((! small) && (realsize > 0)) { 01600 ASSERT(pvalue->u.KeyValue.Data != HCELL_NIL); 01601 if (! HvMarkCellDirty(Hive, pvalue->u.KeyValue.Data)) { 01602 HvFreeCell(Hive, NewCell); 01603 return STATUS_NO_LOG_SPACE; 01604 } 01605 HvFreeCell(Hive, pvalue->u.KeyValue.Data); 01606 } 01607 01608 // 01609 // set body 01610 // 01611 pvalue->u.KeyValue.DataLength = DataSize; 01612 pvalue->u.KeyValue.Data = NewCell; 01613 pvalue->u.KeyValue.Type = Type; 01614 01615 return STATUS_SUCCESS; 01616 } 01617 01618 NTSTATUS 01619 CmpSetValueKeyNew( 01620 IN PHHIVE Hive, 01621 IN PCM_KEY_NODE Parent, 01622 IN PUNICODE_STRING ValueName, 01623 IN ULONG Type, 01624 IN PVOID Data, 01625 IN ULONG DataSize, 01626 IN ULONG StorageType, 01627 IN ULONG TempData 01628 ) 01629 /*++ 01630 01631 Routine Description: 01632 01633 Helper for CmSetValueKey, implements the case where the value entry 01634 being set does not exist. Will create new value entry and data, 01635 place in list (which may be created) 01636 01637 Arguments: 01638 01639 Hive - hive of interest 01640 01641 Parent - pointer to key node value entry is for 01642 01643 ValueName - The unique (relative to the containing key) name 01644 of the value entry. May be NULL. 01645 01646 TitleIndex - Supplies the title index for ValueName. The title 01647 index specifies the index of the localized alias for the ValueName. 01648 01649 Type - The integer type number of the value entry. 01650 01651 Data - Pointer to buffer with actual data for the value entry. 01652 01653 DataSize - Size of Data buffer. 01654 01655 StorageType - stable or volatile 01656 01657 TempData - small data values passed here 01658 01659 01660 Return Value: 01661 01662 STATUS_SUCCESS if it worked, appropriate status code if it did not 01663 01664 --*/ 01665 { 01666 PCELL_DATA pvalue; 01667 HCELL_INDEX ValueCell; 01668 HCELL_INDEX DataCell; 01669 PCELL_DATA pdata; 01670 ULONG count; 01671 HCELL_INDEX NewCell; 01672 ULONG AllocateSize; 01673 01674 // 01675 // Either Count == 0 (no list) or our entry is simply not in 01676 // the list. Create a new value entry body, and data. Add to list. 01677 // (May create the list.) 01678 // 01679 if (Parent->ValueList.Count != 0) { 01680 ASSERT(Parent->ValueList.List != HCELL_NIL); 01681 if (! HvMarkCellDirty(Hive, Parent->ValueList.List)) { 01682 return STATUS_NO_LOG_SPACE; 01683 } 01684 } 01685 01686 // 01687 // allocate the body of the value entry, and the data 01688 // 01689 ValueCell = HvAllocateCell( 01690 Hive, 01691 CmpHKeyValueSize(Hive, ValueName), 01692 StorageType 01693 ); 01694 01695 if (ValueCell == HCELL_NIL) { 01696 return STATUS_INSUFFICIENT_RESOURCES; 01697 } 01698 01699 DataCell = HCELL_NIL; 01700 if (DataSize > CM_KEY_VALUE_SMALL) { 01701 DataCell = HvAllocateCell(Hive, DataSize, StorageType); 01702 if (DataCell == HCELL_NIL) { 01703 HvFreeCell(Hive, ValueCell); 01704 return STATUS_INSUFFICIENT_RESOURCES; 01705 } 01706 } 01707 01708 // 01709 // map in the body, and fill in its fixed portion 01710 // 01711 pvalue = HvGetCell(Hive, ValueCell); 01712 pvalue->u.KeyValue.Signature = CM_KEY_VALUE_SIGNATURE; 01713 01714 // 01715 // fill in the variable portions of the new value entry, name and 01716 // and data are copied from caller space, could fault. 01717 // 01718 try { 01719 01720 // 01721 // fill in the name 01722 // 01723 pvalue->u.KeyValue.NameLength = CmpCopyName(Hive, 01724 pvalue->u.KeyValue.Name, 01725 ValueName); 01726 } except (EXCEPTION_EXECUTE_HANDLER) { 01727 CMLOG(CML_API, CMS_EXCEPTION) { 01728 KdPrint(("!!CmSetValueKey: code:%08lx\n", GetExceptionCode())); 01729 } 01730 01731 // 01732 // We have bombed out loading user data, clean up and exit. 01733 // 01734 if (DataCell != HCELL_NIL) { 01735 HvFreeCell(Hive, DataCell); 01736 } 01737 HvFreeCell(Hive, ValueCell); 01738 return GetExceptionCode(); 01739 } 01740 01741 if (pvalue->u.KeyValue.NameLength < ValueName->Length) { 01742 pvalue->u.KeyValue.Flags = VALUE_COMP_NAME; 01743 } else { 01744 pvalue->u.KeyValue.Flags = 0; 01745 } 01746 01747 // 01748 // fill in the data 01749 // 01750 if (DataSize > CM_KEY_VALUE_SMALL) { 01751 pdata = HvGetCell(Hive, DataCell); 01752 01753 try { 01754 01755 RtlMoveMemory(pdata, Data, DataSize); 01756 01757 } except (EXCEPTION_EXECUTE_HANDLER) { 01758 CMLOG(CML_API, CMS_EXCEPTION) { 01759 KdPrint(("!!CmSetValueKey: code:%08lx\n", GetExceptionCode())); 01760 } 01761 01762 // 01763 // We have bombed out loading user data, clean up and exit. 01764 // 01765 if (DataCell != HCELL_NIL) { 01766 HvFreeCell(Hive, DataCell); 01767 } 01768 HvFreeCell(Hive, ValueCell); 01769 return GetExceptionCode(); 01770 } 01771 01772 pvalue->u.KeyValue.DataLength = DataSize; 01773 pvalue->u.KeyValue.Data = DataCell; 01774 01775 } else { 01776 pvalue->u.KeyValue.DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; 01777 pvalue->u.KeyValue.Data = TempData; 01778 } 01779 01780 // 01781 // either add ourselves to list, or make new one with us in it. 01782 // 01783 count = Parent->ValueList.Count; 01784 count++; 01785 if (count > 1) { 01786 01787 if (count < CM_MAX_REASONABLE_VALUES) { 01788 01789 // 01790 // A reasonable number of values, allocate just enough 01791 // space. 01792 // 01793 01794 AllocateSize = count * sizeof(HCELL_INDEX); 01795 } else { 01796 01797 // 01798 // An excessive number of values, pad the allocation out 01799 // to avoid fragmentation. (if there's this many values, 01800 // there'll probably be more pretty soon) 01801 // 01802 AllocateSize = ROUND_UP(count, CM_MAX_REASONABLE_VALUES) * sizeof(HCELL_INDEX); 01803 if (AllocateSize > HBLOCK_SIZE) { 01804 AllocateSize = ROUND_UP(AllocateSize, HBLOCK_SIZE); 01805 } 01806 } 01807 NewCell = HvReallocateCell( 01808 Hive, 01809 Parent->ValueList.List, 01810 AllocateSize 01811 ); 01812 } else { 01813 NewCell = HvAllocateCell(Hive, sizeof(HCELL_INDEX), StorageType); 01814 } 01815 01816 // 01817 // put ourselves on the list 01818 // 01819 if (NewCell != HCELL_NIL) { 01820 Parent->ValueList.List = NewCell; 01821 pdata = HvGetCell(Hive, NewCell); 01822 01823 pdata->u.KeyList[count-1] = ValueCell; 01824 Parent->ValueList.Count = count; 01825 pvalue->u.KeyValue.Type = Type; 01826 01827 return STATUS_SUCCESS; 01828 01829 } else { 01830 // out of space, free all allocated stuff 01831 if (DataCell != HCELL_NIL) { 01832 HvFreeCell(Hive, DataCell); 01833 } 01834 HvFreeCell(Hive, ValueCell); 01835 return STATUS_INSUFFICIENT_RESOURCES; 01836 } 01837 } 01838 01839 01840 NTSTATUS 01841 CmSetLastWriteTimeKey( 01842 IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, 01843 IN PLARGE_INTEGER LastWriteTime 01844 ) 01845 /*++ 01846 01847 Routine Description: 01848 01849 The LastWriteTime associated with a key node can be set with 01850 CmSetLastWriteTimeKey 01851 01852 Arguments: 01853 01854 KeyControlBlock - pointer to kcb for the key to operate on 01855 01856 LastWriteTime - new time for key 01857 01858 Return Value: 01859 01860 NTSTATUS - Result code from call, among the following: 01861 01862 <TBS> 01863 01864 --*/ 01865 { 01866 PCM_KEY_NODE parent; 01867 PHHIVE Hive; 01868 HCELL_INDEX Cell; 01869 NTSTATUS status = STATUS_SUCCESS; 01870 01871 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmSetLastWriteTimeKey\n")); 01872 01873 CmpLockRegistryExclusive(); 01874 01875 // 01876 // Check that we are not being asked to modify a key 01877 // that has been deleted 01878 // 01879 if (KeyControlBlock->Delete == TRUE) { 01880 status = STATUS_KEY_DELETED; 01881 goto Exit; 01882 } 01883 01884 Hive = KeyControlBlock->KeyHive; 01885 Cell = KeyControlBlock->KeyCell; 01886 parent = KeyControlBlock->KeyNode; 01887 if (! HvMarkCellDirty(Hive, Cell)) { 01888 status = STATUS_NO_LOG_SPACE; 01889 goto Exit; 01890 } 01891 01892 parent->LastWriteTime = *LastWriteTime; 01893 01894 Exit: 01895 CmpUnlockRegistry(); 01896 return status; 01897 } 01898 01899 01900 NTSTATUS 01901 CmLoadKey( 01902 IN POBJECT_ATTRIBUTES TargetKey, 01903 IN POBJECT_ATTRIBUTES SourceFile, 01904 IN ULONG Flags 01905 ) 01906 01907 /*++ 01908 01909 Routine Description: 01910 01911 A hive (file in the format created by NtSaveKey) may be linked 01912 into the active registry with this call. UNLIKE NtRestoreKey, 01913 the file specified to NtLoadKey will become the actual backing 01914 store of part of the registry (that is, it will NOT be copied.) 01915 01916 The file may have an associated .log file. 01917 01918 If the hive file is marked as needing a .log file, and one is 01919 not present, the call will fail. 01920 01921 The name specified by SourceFile must be such that ".log" can 01922 be appended to it to generate the name of the log file. Thus, 01923 on FAT file systems, the hive file may not have an extension. 01924 01925 This call is used by logon to make the user's profile available 01926 in the registry. It is not intended for use doing backup, 01927 restore, etc. Use NtRestoreKey for that. 01928 01929 N.B. This routine assumes that the object attributes for the file 01930 to be opened have been captured into kernel space so that 01931 they can safely be passed to the worker thread to open the file 01932 and do the actual I/O. 01933 01934 Arguments: 01935 01936 TargetKey - specifies the path to a key to link the hive to. 01937 path must be of the form "\registry\user<username>" 01938 01939 SourceFile - specifies a file. while file could be remote, 01940 that is strongly discouraged. 01941 01942 Flags - specifies any flags that should be used for the load operation. 01943 The only valid flag is REG_NO_LAZY_FLUSH. 01944 01945 Return Value: 01946 01947 NTSTATUS - values TBS. 01948 01949 --*/ 01950 { 01951 PCMHIVE NewHive; 01952 NTSTATUS Status; 01953 BOOLEAN Allocate; 01954 REGISTRY_COMMAND Command; 01955 SECURITY_QUALITY_OF_SERVICE ServiceQos; 01956 SECURITY_CLIENT_CONTEXT ClientSecurityContext; 01957 01958 01959 // 01960 // Obtain the security context here so we can use it 01961 // later to impersonate the user, which we will do 01962 // if we cannot access the file as SYSTEM. This 01963 // usually occurs if the file is on a remote machine. 01964 // 01965 ServiceQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); 01966 ServiceQos.ImpersonationLevel = SecurityImpersonation; 01967 ServiceQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; 01968 ServiceQos.EffectiveOnly = TRUE; 01969 Status = SeCreateClientSecurity(CONTAINING_RECORD(KeGetCurrentThread(),ETHREAD,Tcb), 01970 &ServiceQos, 01971 FALSE, 01972 &ClientSecurityContext); 01973 if (!NT_SUCCESS(Status)) { 01974 return(Status); 01975 } 01976 01977 // 01978 // Do not lock the registry; Instead set the RegistryLockAquired member 01979 // of REGISTRY_COMMAND so CmpWorker can lock it after opening the hive files 01980 // 01981 //CmpLockRegistryExclusive(); 01982 // 01983 01984 Command.RegistryLockAquired = FALSE; 01985 Command.Command = REG_CMD_HIVE_OPEN; 01986 Command.Allocate = TRUE; 01987 Command.FileAttributes = SourceFile; 01988 Command.ImpersonationContext = &ClientSecurityContext; 01989 01990 CmpWorker(&Command); 01991 Status = Command.Status; 01992 01993 SeDeleteClientSecurity( &ClientSecurityContext ); 01994 01995 NewHive = Command.CmHive; 01996 Allocate = Command.Allocate; 01997 01998 if (!NT_SUCCESS(Status)) { 01999 if( Command.RegistryLockAquired ) { 02000 // if CmpWorker has locked the registry, unlock it now. 02001 CmpUnlockRegistry(); 02002 } 02003 return(Status); 02004 } else { 02005 // 02006 // if we got here, CmpWorker should have locked the registry exclusive. 02007 // 02008 ASSERT( Command.RegistryLockAquired ); 02009 } 02010 02011 // 02012 // if this is a NO_LAZY_FLUSH hive, set the appropriate bit. 02013 // 02014 if (Flags & REG_NO_LAZY_FLUSH) { 02015 NewHive->Hive.HiveFlags |= HIVE_NOLAZYFLUSH; 02016 } 02017 02018 // 02019 // We now have a succesfully loaded and initialized CmHive, so we 02020 // just need to link that into the appropriate spot in the master hive. 02021 // 02022 Status = CmpLinkHiveToMaster(TargetKey->ObjectName, 02023 TargetKey->RootDirectory, 02024 NewHive, 02025 Allocate, 02026 TargetKey->SecurityDescriptor); 02027 02028 Command.CmHive = NewHive; 02029 if (NT_SUCCESS(Status)) { 02030 // 02031 // add new hive to hivelist 02032 // 02033 Command.Command = REG_CMD_ADD_HIVE_LIST; 02034 02035 } else { 02036 // 02037 // Close the files we've opened. 02038 // 02039 Command.Command = REG_CMD_HIVE_CLOSE; 02040 } 02041 CmpWorker(&Command); 02042 02043 // 02044 // We've given user chance to log on, so turn on quota 02045 // 02046 if ((CmpProfileLoaded == FALSE) && 02047 (CmpWasSetupBoot == FALSE)) { 02048 CmpProfileLoaded = TRUE; 02049 CmpSetGlobalQuotaAllowed(); 02050 } 02051 02052 CmpUnlockRegistry(); 02053 return(Status); 02054 } 02055 02056 #if DBG 02057 ULONG 02058 CmpUnloadKeyWorker( 02059 PCM_KEY_CONTROL_BLOCK Current, 02060 PVOID Context1, 02061 PVOID Context2 02062 ) 02063 { 02064 PUNICODE_STRING ConstructedName; 02065 if (Current->KeyHive == Context1) { 02066 ConstructedName = CmpConstructName(Current); 02067 02068 if (ConstructedName) { 02069 KdPrint(("%wZ\n", ConstructedName)); 02070 ExFreePoolWithTag(ConstructedName, CM_NAME_TAG | PROTECTED_POOL); 02071 } 02072 } 02073 return KCB_WORKER_CONTINUE; // always keep searching 02074 } 02075 #endif 02076 02077 02078 NTSTATUS 02079 CmUnloadKey( 02080 IN PHHIVE Hive, 02081 IN HCELL_INDEX Cell, 02082 IN PCM_KEY_CONTROL_BLOCK Kcb 02083 ) 02084 02085 /*++ 02086 02087 Routine Description: 02088 02089 Unlinks a hive from its location in the registry, closes its file 02090 handles, and deallocates all its memory. 02091 02092 There must be no key control blocks currently referencing the hive 02093 to be unloaded. 02094 02095 Arguments: 02096 02097 Hive - Supplies a pointer to the hive control structure for the 02098 hive to be unloaded 02099 02100 Cell - supplies the HCELL_INDEX for the root cell of the hive. 02101 02102 Kcb - Supplies the key control block 02103 02104 Return Value: 02105 02106 NTSTATUS 02107 02108 --*/ 02109 02110 { 02111 PCMHIVE CmHive; 02112 REGISTRY_COMMAND Command; 02113 BOOLEAN Success; 02114 02115 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmUnloadKey\n")); 02116 02117 CmpLockRegistryExclusive(); 02118 02119 // 02120 // Make sure the cell passed in is the root cell of the hive. 02121 // 02122 if (Cell != Hive->BaseBlock->RootCell) { 02123 CmpUnlockRegistry(); 02124 return(STATUS_INVALID_PARAMETER); 02125 } 02126 02127 // 02128 // Make sure there are no open references to key control blocks 02129 // for this hive. If there are none, then we can unload the hive. 02130 // 02131 02132 CmHive = CONTAINING_RECORD(Hive, CMHIVE, Hive); 02133 if ((CmpSearchForOpenSubKeys(Kcb,SearchIfExist) != 0) || (Kcb->RefCount != 1)) { 02134 #if DBG 02135 KdPrint(("List of keys open against hive unload was attempted on:\n")); 02136 CmpSearchKeyControlBlockTree( 02137 CmpUnloadKeyWorker, 02138 Hive, 02139 NULL 02140 ); 02141 #endif 02142 CmpUnlockRegistry(); 02143 return(STATUS_CANNOT_DELETE); 02144 } 02145 02146 // 02147 // Flush any dirty data to disk. If this fails, too bad. 02148 // 02149 Command.Command = REG_CMD_FLUSH_KEY; 02150 Command.Hive = Hive; 02151 Command.Cell = Cell; 02152 CmpWorker(&Command); 02153 02154 // 02155 // Remove the hive from the HiveFileList 02156 // 02157 Command.Command = REG_CMD_REMOVE_HIVE_LIST; 02158 Command.CmHive = (PCMHIVE)Hive; 02159 CmpWorker(&Command); 02160 02161 // 02162 // Unlink from master hive, remove from list 02163 // 02164 Success = CmpDestroyHive(Hive, Cell); 02165 02166 CmpUnlockRegistry(); 02167 02168 if (Success) { 02169 HvFreeHive(Hive); 02170 02171 // 02172 // Close the hive files 02173 // 02174 Command.Command = REG_CMD_HIVE_CLOSE; 02175 Command.CmHive = CmHive; 02176 CmpWorker(&Command); 02177 02178 // 02179 // free the cm level structure 02180 // 02181 ASSERT( CmHive->HiveLock ); 02182 ExFreePool(CmHive->HiveLock); 02183 CmpFree(CmHive, sizeof(CMHIVE)); 02184 02185 return(STATUS_SUCCESS); 02186 } else { 02187 return(STATUS_INSUFFICIENT_RESOURCES); 02188 } 02189 02190 } 02191 02192 02193 02194 BOOLEAN 02195 CmpDoFlushAll( 02196 VOID 02197 ) 02198 /*++ 02199 02200 Routine Description: 02201 02202 Flush all hives. 02203 02204 Runs in the context of the CmpWorkerThread. 02205 02206 Runs down list of Hives and applies HvSyncHive to them. 02207 02208 NOTE: Hives which are marked as HV_NOLAZYFLUSH are *NOT* flushed 02209 by this call. You must call HvSyncHive explicitly to flush 02210 a hive marked as HV_NOLAZYFLUSH. 02211 02212 Arguments: 02213 02214 Return Value: 02215 02216 NONE 02217 02218 --*/ 02219 { 02220 NTSTATUS Status; 02221 PLIST_ENTRY p; 02222 PCMHIVE h; 02223 BOOLEAN Result = TRUE; 02224 /* 02225 ULONG rc; 02226 */ 02227 extern PCMHIVE CmpMasterHive; 02228 02229 // 02230 // If writes are not working, lie and say we succeeded, will 02231 // clean up in a short time. Only early system init code 02232 // will ever know the difference. 02233 // 02234 if (CmpNoWrite) { 02235 return TRUE; 02236 } 02237 02238 // 02239 // traverse list of hives, sync each one 02240 // 02241 p = CmpHiveListHead.Flink; 02242 while (p != &CmpHiveListHead) { 02243 02244 h = CONTAINING_RECORD(p, CMHIVE, HiveList); 02245 02246 /* 02247 #if DBG 02248 if (h!=CmpMasterHive) { 02249 rc = CmCheckRegistry(h, FALSE); 02250 02251 if (rc!=0) { 02252 KdPrint(("CmpDoFlushAll: corrupt hive, rc = %08lx\n",rc)); 02253 DbgBreakPoint(); 02254 } 02255 } 02256 #endif 02257 */ 02258 if (!(h->Hive.HiveFlags & HIVE_NOLAZYFLUSH)) { 02259 02260 // 02261 //Lock the hive before we flush it. 02262 //-- since we now allow multiple readers 02263 // during a flush (a flush is considered a read) 02264 // we have to force a serialization on the vector table 02265 // 02266 CmLockHive (h); 02267 02268 Status = HvSyncHive((PHHIVE)h); 02269 02270 if( !NT_SUCCESS( Status ) ) { 02271 Result = FALSE; 02272 } 02273 CmUnlockHive (h); 02274 // 02275 // WARNNOTE - the above means that a lazy flush or 02276 // or shutdown flush did not work. we don't 02277 // know why. there is noone to report an error 02278 // to, so continue on and hope for the best. 02279 // (in theory, worst that can happen is user changes 02280 // are lost.) 02281 // 02282 } 02283 02284 02285 p = p->Flink; 02286 } 02287 02288 return Result; 02289 } 02290 02291 02292 NTSTATUS 02293 CmReplaceKey( 02294 IN PHHIVE Hive, 02295 IN HCELL_INDEX Cell, 02296 IN PUNICODE_STRING NewHiveName, 02297 IN PUNICODE_STRING OldFileName 02298 ) 02299 02300 /*++ 02301 02302 Routine Description: 02303 02304 Renames the hive file for a running system and replaces it with a new 02305 file. The new file is not actually used until the next boot. 02306 02307 Arguments: 02308 02309 Hive - Supplies a hive control structure for the hive to be replaced. 02310 02311 Cell - Supplies the HCELL_INDEX of the root cell of the hive to be 02312 replaced. 02313 02314 NewHiveName - Supplies the name of the file which is to be installed 02315 as the new hive. 02316 02317 OldFileName - Supplies the name of the file which the existing hive 02318 file is to be renamed to. 02319 02320 Return Value: 02321 02322 NTSTATUS 02323 02324 --*/ 02325 02326 { 02327 REGISTRY_COMMAND Command; 02328 CHAR ObjectInfoBuffer[512]; 02329 NTSTATUS Status; 02330 OBJECT_ATTRIBUTES Attributes; 02331 PCMHIVE NewHive; 02332 POBJECT_NAME_INFORMATION NameInfo; 02333 ULONG OldQuotaAllowed; 02334 ULONG OldQuotaWarning; 02335 02336 CmpLockRegistryExclusive(); 02337 02338 if (Hive->HiveFlags & HIVE_HAS_BEEN_REPLACED) { 02339 CmpUnlockRegistry(); 02340 return STATUS_FILE_RENAMED; 02341 } 02342 02343 // 02344 // temporarily disable registry quota as we will be giving this memory back immediately! 02345 // 02346 OldQuotaAllowed = CmpGlobalQuotaAllowed; 02347 OldQuotaWarning = CmpGlobalQuotaWarning; 02348 CmpGlobalQuotaAllowed = CM_WRAP_LIMIT; 02349 CmpGlobalQuotaWarning = CM_WRAP_LIMIT; 02350 02351 // 02352 // First open the new hive file and check to make sure it is valid. 02353 // 02354 InitializeObjectAttributes(&Attributes, 02355 NewHiveName, 02356 OBJ_CASE_INSENSITIVE, 02357 NULL, 02358 NULL); 02359 02360 Command.RegistryLockAquired = TRUE; 02361 Command.Command = REG_CMD_HIVE_OPEN; 02362 Command.FileAttributes = &Attributes; 02363 Command.Allocate = FALSE; 02364 Command.ImpersonationContext = NULL; 02365 CmpWorker(&Command); 02366 Status = Command.Status; 02367 if (!NT_SUCCESS(Status)) { 02368 goto ErrorExit; 02369 } 02370 ASSERT(Command.Allocate == FALSE); 02371 02372 NewHive = Command.CmHive; 02373 02374 // 02375 // The new hive exists, and is consistent, and we have it open. 02376 // Now rename the current hive file. 02377 // 02378 Command.Command = REG_CMD_RENAME_HIVE; 02379 Command.NewName = OldFileName; 02380 Command.OldName = (POBJECT_NAME_INFORMATION)ObjectInfoBuffer; 02381 Command.NameInfoLength = sizeof(ObjectInfoBuffer); 02382 Command.CmHive = CONTAINING_RECORD(Hive, CMHIVE, Hive); 02383 CmpWorker(&Command); 02384 Status = Command.Status; 02385 if (!NT_SUCCESS(Status)) { 02386 // 02387 // rename failed, close the files associated with the new hive 02388 // 02389 Command.CmHive = NewHive; 02390 Command.Command = REG_CMD_HIVE_CLOSE; 02391 CmpWorker(&Command); 02392 goto ErrorExit; 02393 } 02394 02395 // 02396 // The existing hive was successfully renamed, so try to rename the 02397 // new file to what the old hive file was named. (which was returned 02398 // into ObjectInfoBuffer by the worker thread) 02399 // 02400 Hive->HiveFlags |= HIVE_HAS_BEEN_REPLACED; 02401 NameInfo = (POBJECT_NAME_INFORMATION)ObjectInfoBuffer; 02402 Command.Command = REG_CMD_RENAME_HIVE; 02403 Command.NewName = &NameInfo->Name; 02404 Command.OldName = NULL; 02405 Command.NameInfoLength = 0; 02406 Command.CmHive = NewHive; 02407 CmpWorker(&Command); 02408 Status = Command.Status; 02409 if (!NT_SUCCESS(Status)) { 02410 02411 // 02412 // Close the handles to the new hive 02413 // 02414 Command.Command = REG_CMD_HIVE_CLOSE; 02415 Command.CmHive = NewHive; 02416 CmpWorker(&Command); 02417 02418 // 02419 // We are in trouble now. We have renamed the existing hive file, 02420 // but we couldn't rename the new hive file! Try to rename the 02421 // existing hive file back to where it was. 02422 // 02423 Command.Command = REG_CMD_RENAME_HIVE; 02424 Command.NewName = &NameInfo->Name; 02425 Command.OldName = NULL; 02426 Command.NameInfoLength = 0; 02427 Command.CmHive = CONTAINING_RECORD(Hive, CMHIVE, Hive); 02428 CmpWorker(&Command); 02429 if (!NT_SUCCESS(Command.Status)) { 02430 CMLOG(CML_BUGCHECK, CMS_SAVRES) { 02431 KdPrint(("CmReplaceKey: renamed existing hive file, but couldn't\n")); 02432 KdPrint((" rename new hive file (%08lx) ",Status)); 02433 KdPrint((" or replace old hive file (%08lx)!\n",Command.Status)); 02434 } 02435 02436 // 02437 // WARNNOTE: 02438 // To get into this state, the user must have relevent 02439 // privileges, deliberately screw with system in an attempt 02440 // to defeat it, AND get it done in a narrow timing window. 02441 // 02442 // Further, if it's a user profile, the system will 02443 // still come up. 02444 // 02445 // Therefore, return an error code and go on. 02446 // 02447 02448 Status = STATUS_REGISTRY_CORRUPT; 02449 02450 } 02451 } 02452 02453 // 02454 // All of the renaming is done. However, we are holding an in-memory 02455 // image of the new hive. Release it, since it will not actually 02456 // be used until next boot. 02457 // 02458 // Do not close the open file handles to the new hive, we need to 02459 // keep it locked exclusively until the system is rebooted to prevent 02460 // people from mucking with it. 02461 // 02462 RemoveEntryList(&(NewHive->HiveList)); 02463 02464 HvFreeHive((PHHIVE)NewHive); 02465 02466 ASSERT( NewHive->HiveLock ); 02467 ExFreePool(NewHive->HiveLock); 02468 CmpFree(NewHive, sizeof(CMHIVE)); 02469 02470 ErrorExit: 02471 // 02472 // Set global quota back to what it was. 02473 // 02474 CmpGlobalQuotaAllowed = OldQuotaAllowed; 02475 CmpGlobalQuotaWarning = OldQuotaWarning; 02476 02477 CmpUnlockRegistry(); 02478 return(Status); 02479 } 02480 02481 #ifdef _WRITE_PROTECTED_REGISTRY_POOL 02482 02483 VOID 02484 CmpMarkAllBinsReadOnly( 02485 PHHIVE Hive 02486 ) 02487 /*++ 02488 02489 Routine Description: 02490 02491 Marks the memory allocated for all the stable bins in this hive as read only. 02492 02493 Arguments: 02494 02495 Hive - supplies a pointer to the hive control structure for the 02496 hive of interest 02497 02498 Return Value: 02499 02500 NONE (It should work!) 02501 02502 --*/ 02503 { 02504 PHMAP_ENTRY t; 02505 PHBIN Bin; 02506 HCELL_INDEX p; 02507 ULONG Length; 02508 02509 // 02510 // we are only interested in the stable storage 02511 // 02512 Length = Hive->Storage[Stable].Length; 02513 02514 p = 0; 02515 02516 // 02517 // for each bin in the space 02518 // 02519 while (p < Length) { 02520 t = HvpGetCellMap(Hive, p); 02521 VALIDATE_CELL_MAP(__LINE__,t,Hive,p); 02522 02523 Bin = (PHBIN)((t->BinAddress) & HMAP_BASE); 02524 02525 if (t->BinAddress & HMAP_NEWALLOC) { 02526 02527 // 02528 // Mark it as read Only 02529 // 02530 HvpChangeBinAllocation(Bin,TRUE); 02531 } 02532 02533 // next one, please 02534 p = (ULONG)p + Bin->Size; 02535 02536 } 02537 02538 } 02539 02540 #endif 02541

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