Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencmapi.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/config/cmapi.c 00005 * PURPOSE: Configuration Manager - Internal Registry APIs 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Eric Kohl 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include "ntoskrnl.h" 00013 #define NDEBUG 00014 #include "debug.h" 00015 00016 /* FUNCTIONS *****************************************************************/ 00017 00018 BOOLEAN 00019 NTAPI 00020 CmpIsHiveAlreadyLoaded(IN HANDLE KeyHandle, 00021 IN POBJECT_ATTRIBUTES SourceFile, 00022 OUT PCMHIVE *CmHive) 00023 { 00024 NTSTATUS Status; 00025 PCM_KEY_BODY KeyBody; 00026 PCMHIVE Hive; 00027 BOOLEAN Loaded = FALSE; 00028 PAGED_CODE(); 00029 00030 /* Sanity check */ 00031 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); 00032 00033 /* Reference the handle */ 00034 Status = ObReferenceObjectByHandle(KeyHandle, 00035 0, 00036 CmpKeyObjectType, 00037 KernelMode, 00038 (PVOID)&KeyBody, 00039 NULL); 00040 if (!NT_SUCCESS(Status)) return Loaded; 00041 00042 /* Don't touch deleted KCBs */ 00043 if (KeyBody->KeyControlBlock->Delete) return Loaded; 00044 00045 Hive = CONTAINING_RECORD(KeyBody->KeyControlBlock->KeyHive, CMHIVE, Hive); 00046 00047 /* Must be the root key */ 00048 if (!(KeyBody->KeyControlBlock->Flags & KEY_HIVE_ENTRY) || 00049 !(Hive->FileUserName.Buffer)) 00050 { 00051 /* It isn't */ 00052 ObDereferenceObject(KeyBody); 00053 return Loaded; 00054 } 00055 00056 /* Now compare the name of the file */ 00057 if (!RtlCompareUnicodeString(&Hive->FileUserName, 00058 SourceFile->ObjectName, 00059 TRUE)) 00060 { 00061 /* Same file found */ 00062 Loaded = TRUE; 00063 *CmHive = Hive; 00064 00065 /* If the hive is frozen, not sure what to do */ 00066 if (Hive->Frozen) 00067 { 00068 /* FIXME: TODO */ 00069 DPRINT1("ERROR: Hive is frozen\n"); 00070 while (TRUE); 00071 } 00072 } 00073 00074 /* Dereference and return result */ 00075 ObDereferenceObject(KeyBody); 00076 return Loaded; 00077 } 00078 00079 BOOLEAN 00080 NTAPI 00081 CmpDoFlushAll(IN BOOLEAN ForceFlush) 00082 { 00083 PLIST_ENTRY NextEntry; 00084 PCMHIVE Hive; 00085 NTSTATUS Status; 00086 BOOLEAN Result = TRUE; 00087 00088 /* Make sure that the registry isn't read-only now */ 00089 if (CmpNoWrite) return TRUE; 00090 00091 /* Otherwise, acquire the hive list lock and disable force flush */ 00092 CmpForceForceFlush = FALSE; 00093 ExAcquirePushLockShared(&CmpHiveListHeadLock); 00094 00095 /* Loop the hive list */ 00096 NextEntry = CmpHiveListHead.Flink; 00097 while (NextEntry != &CmpHiveListHead) 00098 { 00099 /* Get the hive */ 00100 Hive = CONTAINING_RECORD(NextEntry, CMHIVE, HiveList); 00101 if (!(Hive->Hive.HiveFlags & HIVE_NOLAZYFLUSH)) 00102 { 00103 /* Acquire the flusher lock */ 00104 CmpLockHiveFlusherExclusive(Hive); 00105 00106 /* Check for illegal state */ 00107 if ((ForceFlush) && (Hive->UseCount)) 00108 { 00109 /* Registry needs to be locked down */ 00110 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); 00111 DPRINT1("FIXME: Hive is damaged and needs fixup\n"); 00112 while (TRUE); 00113 } 00114 00115 /* Only sync if we are forced to or if it won't cause a hive shrink */ 00116 if ((ForceFlush) || (!HvHiveWillShrink(&Hive->Hive))) 00117 { 00118 /* Do the sync */ 00119 Status = HvSyncHive(&Hive->Hive); 00120 00121 /* If something failed - set the flag and continue looping */ 00122 if (!NT_SUCCESS(Status)) Result = FALSE; 00123 } 00124 else 00125 { 00126 /* We won't flush if the hive might shrink */ 00127 Result = FALSE; 00128 CmpForceForceFlush = TRUE; 00129 } 00130 00131 /* Release the flusher lock */ 00132 CmpUnlockHiveFlusher(Hive); 00133 } 00134 00135 /* Try the next entry */ 00136 NextEntry = NextEntry->Flink; 00137 } 00138 00139 /* Release lock and return */ 00140 ExReleasePushLock(&CmpHiveListHeadLock); 00141 return Result; 00142 } 00143 00144 NTSTATUS 00145 NTAPI 00146 CmpSetValueKeyNew(IN PHHIVE Hive, 00147 IN PCM_KEY_NODE Parent, 00148 IN PUNICODE_STRING ValueName, 00149 IN ULONG Index, 00150 IN ULONG Type, 00151 IN PVOID Data, 00152 IN ULONG DataSize, 00153 IN ULONG StorageType, 00154 IN ULONG SmallData) 00155 { 00156 PCELL_DATA CellData; 00157 HCELL_INDEX ValueCell; 00158 NTSTATUS Status; 00159 00160 /* Check if we already have a value list */ 00161 if (Parent->ValueList.Count) 00162 { 00163 /* Then make sure it's valid and dirty it */ 00164 ASSERT(Parent->ValueList.List != HCELL_NIL); 00165 if (!HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE)) 00166 { 00167 /* Fail if we're out of space for log changes */ 00168 return STATUS_NO_LOG_SPACE; 00169 } 00170 } 00171 00172 /* Allocate a value cell */ 00173 ValueCell = HvAllocateCell(Hive, 00174 FIELD_OFFSET(CM_KEY_VALUE, Name) + 00175 CmpNameSize(Hive, ValueName), 00176 StorageType, 00177 HCELL_NIL); 00178 if (ValueCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; 00179 00180 /* Get the actual data for it */ 00181 CellData = HvGetCell(Hive, ValueCell); 00182 if (!CellData) ASSERT(FALSE); 00183 00184 /* Now we can release it, make sure it's also dirty */ 00185 HvReleaseCell(Hive, ValueCell); 00186 ASSERT(HvIsCellDirty(Hive, ValueCell)); 00187 00188 /* Set it up and copy the name */ 00189 CellData->u.KeyValue.Signature = CM_KEY_VALUE_SIGNATURE; 00190 _SEH2_TRY 00191 { 00192 /* This can crash since the name is coming from user-mode */ 00193 CellData->u.KeyValue.NameLength = CmpCopyName(Hive, 00194 CellData->u.KeyValue.Name, 00195 ValueName); 00196 } 00197 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00198 { 00199 /* Fail */ 00200 DPRINT1("Invalid user data!\n"); 00201 HvFreeCell(Hive, ValueCell); 00202 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00203 } 00204 _SEH2_END; 00205 00206 /* Check for compressed name */ 00207 if (CellData->u.KeyValue.NameLength < ValueName->Length) 00208 { 00209 /* This is a compressed name */ 00210 CellData->u.KeyValue.Flags = VALUE_COMP_NAME; 00211 } 00212 else 00213 { 00214 /* No flags to set */ 00215 CellData->u.KeyValue.Flags = 0; 00216 } 00217 00218 /* Check if this is a normal key */ 00219 if (DataSize > CM_KEY_VALUE_SMALL) 00220 { 00221 /* Build a data cell for it */ 00222 Status = CmpSetValueDataNew(Hive, 00223 Data, 00224 DataSize, 00225 StorageType, 00226 ValueCell, 00227 &CellData->u.KeyValue.Data); 00228 if (!NT_SUCCESS(Status)) 00229 { 00230 /* We failed, free the cell */ 00231 HvFreeCell(Hive, ValueCell); 00232 return Status; 00233 } 00234 00235 /* Otherwise, set the data length, and make sure the data is dirty */ 00236 CellData->u.KeyValue.DataLength = DataSize; 00237 ASSERT(HvIsCellDirty(Hive, CellData->u.KeyValue.Data)); 00238 } 00239 else 00240 { 00241 /* This is a small key, set the data directly inside */ 00242 CellData->u.KeyValue.DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; 00243 CellData->u.KeyValue.Data = SmallData; 00244 } 00245 00246 /* Set the type now */ 00247 CellData->u.KeyValue.Type = Type; 00248 00249 /* Add this value cell to the child list */ 00250 Status = CmpAddValueToList(Hive, 00251 ValueCell, 00252 Index, 00253 StorageType, 00254 &Parent->ValueList); 00255 00256 /* If we failed, free the entire cell, including the data */ 00257 if (!NT_SUCCESS(Status)) 00258 { 00259 /* Overwrite the status with a known one */ 00260 CmpFreeValue(Hive, ValueCell); 00261 Status = STATUS_INSUFFICIENT_RESOURCES; 00262 } 00263 00264 /* Return Status */ 00265 return Status; 00266 } 00267 00268 NTSTATUS 00269 NTAPI 00270 CmpSetValueKeyExisting(IN PHHIVE Hive, 00271 IN HCELL_INDEX OldChild, 00272 IN PCM_KEY_VALUE Value, 00273 IN ULONG Type, 00274 IN PVOID Data, 00275 IN ULONG DataSize, 00276 IN ULONG StorageType, 00277 IN ULONG TempData) 00278 { 00279 HCELL_INDEX DataCell, NewCell; 00280 PCELL_DATA CellData; 00281 ULONG Length; 00282 BOOLEAN WasSmall, IsSmall; 00283 00284 /* Registry writes must be blocked */ 00285 CMP_ASSERT_FLUSH_LOCK(Hive); 00286 00287 /* Mark the old child cell dirty */ 00288 if (!HvMarkCellDirty(Hive, OldChild, FALSE)) return STATUS_NO_LOG_SPACE; 00289 00290 /* See if this is a small or normal key */ 00291 WasSmall = CmpIsKeyValueSmall(&Length, Value->DataLength); 00292 00293 /* See if our new data can fit in a small key */ 00294 IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE; 00295 00296 /* Big keys are unsupported */ 00297 ASSERT_VALUE_BIG(Hive, Length); 00298 ASSERT_VALUE_BIG(Hive, DataSize); 00299 00300 /* Mark the old value dirty */ 00301 if (!CmpMarkValueDataDirty(Hive, Value)) return STATUS_NO_LOG_SPACE; 00302 00303 /* Check if we have a small key */ 00304 if (IsSmall) 00305 { 00306 /* Check if we had a normal key with some data in it */ 00307 if (!(WasSmall) && (Length > 0)) 00308 { 00309 /* Free the previous data */ 00310 CmpFreeValueData(Hive, Value->Data, Length); 00311 } 00312 00313 /* Write our data directly */ 00314 Value->DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; 00315 Value->Data = TempData; 00316 Value->Type = Type; 00317 return STATUS_SUCCESS; 00318 } 00319 00320 /* We have a normal key. Was the old cell also normal and had data? */ 00321 if (!(WasSmall) && (Length > 0)) 00322 { 00323 /* Get the current data cell and actual data inside it */ 00324 DataCell = Value->Data; 00325 ASSERT(DataCell != HCELL_NIL); 00326 CellData = HvGetCell(Hive, DataCell); 00327 if (!CellData) return STATUS_INSUFFICIENT_RESOURCES; 00328 00329 /* Immediately release the cell */ 00330 HvReleaseCell(Hive, DataCell); 00331 00332 /* Make sure that the data cell actually has a size */ 00333 ASSERT(HvGetCellSize(Hive, CellData) > 0); 00334 00335 /* Check if the previous data cell could fit our new data */ 00336 if (DataSize <= (ULONG)(HvGetCellSize(Hive, CellData))) 00337 { 00338 /* Re-use it then */ 00339 NewCell = DataCell; 00340 } 00341 else 00342 { 00343 /* Otherwise, re-allocate the current data cell */ 00344 NewCell = HvReallocateCell(Hive, DataCell, DataSize); 00345 if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; 00346 } 00347 } 00348 else 00349 { 00350 /* This was a small key, or a key with no data, allocate a cell */ 00351 NewCell = HvAllocateCell(Hive, DataSize, StorageType, HCELL_NIL); 00352 if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; 00353 } 00354 00355 /* Now get the actual data for our data cell */ 00356 CellData = HvGetCell(Hive, NewCell); 00357 if (!CellData) ASSERT(FALSE); 00358 00359 /* Release it immediately */ 00360 HvReleaseCell(Hive, NewCell); 00361 00362 /* Copy our data into the data cell's buffer, and set up the value */ 00363 RtlCopyMemory(CellData, Data, DataSize); 00364 Value->Data = NewCell; 00365 Value->DataLength = DataSize; 00366 Value->Type = Type; 00367 00368 /* Return success */ 00369 ASSERT(HvIsCellDirty(Hive, NewCell)); 00370 return STATUS_SUCCESS; 00371 } 00372 00373 NTSTATUS 00374 NTAPI 00375 CmpQueryKeyData(IN PHHIVE Hive, 00376 IN PCM_KEY_NODE Node, 00377 IN KEY_INFORMATION_CLASS KeyInformationClass, 00378 IN OUT PVOID KeyInformation, 00379 IN ULONG Length, 00380 IN OUT PULONG ResultLength) 00381 { 00382 NTSTATUS Status; 00383 ULONG Size, SizeLeft, MinimumSize; 00384 PKEY_INFORMATION Info = (PKEY_INFORMATION)KeyInformation; 00385 USHORT NameLength; 00386 00387 /* Check if the value is compressed */ 00388 if (Node->Flags & KEY_COMP_NAME) 00389 { 00390 /* Get the compressed name size */ 00391 NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength); 00392 } 00393 else 00394 { 00395 /* Get the real size */ 00396 NameLength = Node->NameLength; 00397 } 00398 00399 /* Check what kind of information is being requested */ 00400 switch (KeyInformationClass) 00401 { 00402 /* Basic information */ 00403 case KeyBasicInformation: 00404 00405 /* This is the size we need */ 00406 Size = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + NameLength; 00407 00408 /* And this is the minimum we can work with */ 00409 MinimumSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name); 00410 00411 /* Let the caller know and assume success */ 00412 *ResultLength = Size; 00413 Status = STATUS_SUCCESS; 00414 00415 /* Check if the bufer we got is too small */ 00416 if (Length < MinimumSize) 00417 { 00418 /* Let the caller know and fail */ 00419 Status = STATUS_BUFFER_TOO_SMALL; 00420 break; 00421 } 00422 00423 /* Copy the basic information */ 00424 Info->KeyBasicInformation.LastWriteTime = Node->LastWriteTime; 00425 Info->KeyBasicInformation.TitleIndex = 0; 00426 Info->KeyBasicInformation.NameLength = NameLength; 00427 00428 /* Only the name is left */ 00429 SizeLeft = Length - MinimumSize; 00430 Size = NameLength; 00431 00432 /* Check if we don't have enough space for the name */ 00433 if (SizeLeft < Size) 00434 { 00435 /* Truncate the name we'll return, and tell the caller */ 00436 Size = SizeLeft; 00437 Status = STATUS_BUFFER_OVERFLOW; 00438 } 00439 00440 /* Check if this is a compressed key */ 00441 if (Node->Flags & KEY_COMP_NAME) 00442 { 00443 /* Copy the compressed name */ 00444 CmpCopyCompressedName(Info->KeyBasicInformation.Name, 00445 SizeLeft, 00446 Node->Name, 00447 Node->NameLength); 00448 } 00449 else 00450 { 00451 /* Otherwise, copy the raw name */ 00452 RtlCopyMemory(Info->KeyBasicInformation.Name, 00453 Node->Name, 00454 Size); 00455 } 00456 break; 00457 00458 /* Node information */ 00459 case KeyNodeInformation: 00460 00461 /* Calculate the size we need */ 00462 Size = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) + 00463 NameLength + 00464 Node->ClassLength; 00465 00466 /* And the minimum size we can support */ 00467 MinimumSize = FIELD_OFFSET(KEY_NODE_INFORMATION, Name); 00468 00469 /* Return the size to the caller and assume succes */ 00470 *ResultLength = Size; 00471 Status = STATUS_SUCCESS; 00472 00473 /* Check if the caller's buffer is too small */ 00474 if (Length < MinimumSize) 00475 { 00476 /* Let them know, and fail */ 00477 Status = STATUS_BUFFER_TOO_SMALL; 00478 break; 00479 } 00480 00481 /* Copy the basic information */ 00482 Info->KeyNodeInformation.LastWriteTime = Node->LastWriteTime; 00483 Info->KeyNodeInformation.TitleIndex = 0; 00484 Info->KeyNodeInformation.ClassLength = Node->ClassLength; 00485 Info->KeyNodeInformation.NameLength = NameLength; 00486 00487 /* Now the name is left */ 00488 SizeLeft = Length - MinimumSize; 00489 Size = NameLength; 00490 00491 /* Check if the name can fit entirely */ 00492 if (SizeLeft < Size) 00493 { 00494 /* It can't, we'll have to truncate. Tell the caller */ 00495 Size = SizeLeft; 00496 Status = STATUS_BUFFER_OVERFLOW; 00497 } 00498 00499 /* Check if the key node name is compressed */ 00500 if (Node->Flags & KEY_COMP_NAME) 00501 { 00502 /* Copy the compressed name */ 00503 CmpCopyCompressedName(Info->KeyNodeInformation.Name, 00504 SizeLeft, 00505 Node->Name, 00506 Node->NameLength); 00507 } 00508 else 00509 { 00510 /* It isn't, so copy the raw name */ 00511 RtlCopyMemory(Info->KeyNodeInformation.Name, 00512 Node->Name, 00513 Size); 00514 } 00515 00516 /* Check if the node has a class */ 00517 if (Node->ClassLength > 0) 00518 { 00519 /* It does. We don't support these yet */ 00520 ASSERTMSG("Classes not supported\n", FALSE); 00521 } 00522 else 00523 { 00524 /* It doesn't, so set offset to -1, not 0! */ 00525 Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF; 00526 } 00527 break; 00528 00529 /* Full information requsted */ 00530 case KeyFullInformation: 00531 00532 /* This is the size we need */ 00533 Size = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + 00534 Node->ClassLength; 00535 00536 /* This is what we can work with */ 00537 MinimumSize = FIELD_OFFSET(KEY_FULL_INFORMATION, Class); 00538 00539 /* Return it to caller and assume success */ 00540 *ResultLength = Size; 00541 Status = STATUS_SUCCESS; 00542 00543 /* Check if the caller's buffer is to small */ 00544 if (Length < MinimumSize) 00545 { 00546 /* Let them know and fail */ 00547 Status = STATUS_BUFFER_TOO_SMALL; 00548 break; 00549 } 00550 00551 /* Now copy all the basic information */ 00552 Info->KeyFullInformation.LastWriteTime = Node->LastWriteTime; 00553 Info->KeyFullInformation.TitleIndex = 0; 00554 Info->KeyFullInformation.ClassLength = Node->ClassLength; 00555 Info->KeyFullInformation.SubKeys = Node->SubKeyCounts[Stable] + 00556 Node->SubKeyCounts[Volatile]; 00557 Info->KeyFullInformation.Values = Node->ValueList.Count; 00558 Info->KeyFullInformation.MaxNameLen = Node->MaxNameLen; 00559 Info->KeyFullInformation.MaxClassLen = Node->MaxClassLen; 00560 Info->KeyFullInformation.MaxValueNameLen = Node->MaxValueNameLen; 00561 Info->KeyFullInformation.MaxValueDataLen = Node->MaxValueDataLen; 00562 00563 /* Check if we have a class */ 00564 if (Node->ClassLength > 0) 00565 { 00566 /* We do, but we currently don't support this */ 00567 ASSERTMSG("Classes not supported\n", FALSE); 00568 } 00569 else 00570 { 00571 /* We don't have a class, so set offset to -1, not 0! */ 00572 Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF; 00573 } 00574 break; 00575 00576 /* Any other class that got sent here is invalid! */ 00577 default: 00578 00579 /* Set failure code */ 00580 Status = STATUS_INVALID_PARAMETER; 00581 break; 00582 } 00583 00584 /* Return status */ 00585 return Status; 00586 } 00587 00588 NTSTATUS 00589 NTAPI 00590 CmSetValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, 00591 IN PUNICODE_STRING ValueName, 00592 IN ULONG Type, 00593 IN PVOID Data, 00594 IN ULONG DataLength) 00595 { 00596 PHHIVE Hive = NULL; 00597 PCM_KEY_NODE Parent; 00598 PCM_KEY_VALUE Value = NULL; 00599 HCELL_INDEX CurrentChild, Cell; 00600 NTSTATUS Status; 00601 BOOLEAN Found, Result; 00602 ULONG Count, ChildIndex, SmallData, Storage; 00603 VALUE_SEARCH_RETURN_TYPE SearchResult; 00604 BOOLEAN FirstTry = TRUE, FlusherLocked = FALSE; 00605 HCELL_INDEX ParentCell = HCELL_NIL, ChildCell = HCELL_NIL; 00606 00607 /* Acquire hive and KCB lock */ 00608 CmpLockRegistry(); 00609 CmpAcquireKcbLockShared(Kcb); 00610 00611 /* Sanity check */ 00612 ASSERT(sizeof(ULONG) == CM_KEY_VALUE_SMALL); 00613 00614 /* Don't touch deleted KCBs */ 00615 DoAgain: 00616 if (Kcb->Delete) 00617 { 00618 /* Fail */ 00619 Status = STATUS_KEY_DELETED; 00620 goto Quickie; 00621 } 00622 00623 /* Don't let anyone mess with symlinks */ 00624 if ((Kcb->Flags & KEY_SYM_LINK) && 00625 ((Type != REG_LINK) || 00626 !(ValueName) || 00627 !(RtlEqualUnicodeString(&CmSymbolicLinkValueName, ValueName, TRUE)))) 00628 { 00629 /* Invalid modification of a symlink key */ 00630 Status = STATUS_ACCESS_DENIED; 00631 goto Quickie; 00632 } 00633 00634 /* Check if this is the first attempt */ 00635 if (FirstTry) 00636 { 00637 /* Search for the value in the cache */ 00638 SearchResult = CmpCompareNewValueDataAgainstKCBCache(Kcb, 00639 ValueName, 00640 Type, 00641 Data, 00642 DataLength); 00643 if (SearchResult == SearchNeedExclusiveLock) 00644 { 00645 /* Try again with the exclusive lock */ 00646 CmpConvertKcbSharedToExclusive(Kcb); 00647 goto DoAgain; 00648 } 00649 else if (SearchResult == SearchSuccess) 00650 { 00651 /* We don't actually need to do anything! */ 00652 Status = STATUS_SUCCESS; 00653 goto Quickie; 00654 } 00655 00656 /* We need the exclusive KCB lock now */ 00657 if (!(CmpIsKcbLockedExclusive(Kcb)) && 00658 !(CmpTryToConvertKcbSharedToExclusive(Kcb))) 00659 { 00660 /* Acquire exclusive lock */ 00661 CmpConvertKcbSharedToExclusive(Kcb); 00662 } 00663 00664 /* Cache lookup failed, so don't try it next time */ 00665 FirstTry = FALSE; 00666 00667 /* Now grab the flush lock since the key will be modified */ 00668 ASSERT(FlusherLocked == FALSE); 00669 CmpLockHiveFlusherShared((PCMHIVE)Kcb->KeyHive); 00670 FlusherLocked = TRUE; 00671 goto DoAgain; 00672 } 00673 else 00674 { 00675 /* Get pointer to key cell */ 00676 Hive = Kcb->KeyHive; 00677 Cell = Kcb->KeyCell; 00678 00679 /* Get the parent */ 00680 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell); 00681 ASSERT(Parent); 00682 ParentCell = Cell; 00683 00684 /* Prepare to scan the key node */ 00685 Count = Parent->ValueList.Count; 00686 Found = FALSE; 00687 if (Count > 0) 00688 { 00689 /* Try to find the existing name */ 00690 Result = CmpFindNameInList(Hive, 00691 &Parent->ValueList, 00692 ValueName, 00693 &ChildIndex, 00694 &CurrentChild); 00695 if (!Result) 00696 { 00697 /* Fail */ 00698 Status = STATUS_INSUFFICIENT_RESOURCES; 00699 goto Quickie; 00700 } 00701 00702 /* Check if we found something */ 00703 if (CurrentChild != HCELL_NIL) 00704 { 00705 /* Release existing child */ 00706 if (ChildCell != HCELL_NIL) 00707 { 00708 HvReleaseCell(Hive, ChildCell); 00709 ChildCell = HCELL_NIL; 00710 } 00711 00712 /* Get its value */ 00713 Value = (PCM_KEY_VALUE)HvGetCell(Hive, CurrentChild); 00714 if (!Value) 00715 { 00716 /* Fail */ 00717 Status = STATUS_INSUFFICIENT_RESOURCES; 00718 goto Quickie; 00719 } 00720 00721 /* Remember that we found it */ 00722 ChildCell = CurrentChild; 00723 Found = TRUE; 00724 } 00725 } 00726 else 00727 { 00728 /* No child list, we'll need to add it */ 00729 ChildIndex = 0; 00730 } 00731 } 00732 00733 /* Should only get here on the second pass */ 00734 ASSERT(FirstTry == FALSE); 00735 00736 /* The KCB must be locked exclusive at this point */ 00737 CMP_ASSERT_KCB_LOCK(Kcb); 00738 00739 /* Mark the cell dirty */ 00740 if (!HvMarkCellDirty(Hive, Cell, FALSE)) 00741 { 00742 /* Not enough log space, fail */ 00743 Status = STATUS_NO_LOG_SPACE; 00744 goto Quickie; 00745 } 00746 00747 /* Get the storage type */ 00748 Storage = HvGetCellType(Cell); 00749 00750 /* Check if this is small data */ 00751 SmallData = 0; 00752 if ((DataLength <= CM_KEY_VALUE_SMALL) && (DataLength > 0)) 00753 { 00754 /* Need SEH because user data may be invalid */ 00755 _SEH2_TRY 00756 { 00757 /* Copy it */ 00758 RtlCopyMemory(&SmallData, Data, DataLength); 00759 } 00760 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00761 { 00762 /* Return failure code */ 00763 Status = _SEH2_GetExceptionCode(); 00764 _SEH2_YIELD(goto Quickie); 00765 } 00766 _SEH2_END; 00767 } 00768 00769 /* Check if we didn't find a matching key */ 00770 if (!Found) 00771 { 00772 /* Call the internal routine */ 00773 Status = CmpSetValueKeyNew(Hive, 00774 Parent, 00775 ValueName, 00776 ChildIndex, 00777 Type, 00778 Data, 00779 DataLength, 00780 Storage, 00781 SmallData); 00782 } 00783 else 00784 { 00785 /* Call the internal routine */ 00786 Status = CmpSetValueKeyExisting(Hive, 00787 CurrentChild, 00788 Value, 00789 Type, 00790 Data, 00791 DataLength, 00792 Storage, 00793 SmallData); 00794 } 00795 00796 /* Check for success */ 00797 if (NT_SUCCESS(Status)) 00798 { 00799 /* Check if the maximum value name length changed */ 00800 ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen); 00801 if (Parent->MaxValueNameLen < ValueName->Length) 00802 { 00803 /* Set the new values */ 00804 Parent->MaxValueNameLen = ValueName->Length; 00805 Kcb->KcbMaxValueNameLen = ValueName->Length; 00806 } 00807 00808 /* Check if the maximum data length changed */ 00809 ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen); 00810 if (Parent->MaxValueDataLen < DataLength) 00811 { 00812 /* Update it */ 00813 Parent->MaxValueDataLen = DataLength; 00814 Kcb->KcbMaxValueDataLen = Parent->MaxValueDataLen; 00815 } 00816 00817 /* Save the write time */ 00818 KeQuerySystemTime(&Parent->LastWriteTime); 00819 Kcb->KcbLastWriteTime = Parent->LastWriteTime; 00820 00821 /* Check if the cell is cached */ 00822 if ((Found) && (CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList))) 00823 { 00824 /* Shouldn't happen */ 00825 ASSERT(FALSE); 00826 } 00827 else 00828 { 00829 /* Cleanup the value cache */ 00830 CmpCleanUpKcbValueCache(Kcb); 00831 00832 /* Sanity checks */ 00833 ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList))); 00834 ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)); 00835 00836 /* Set the value cache */ 00837 Kcb->ValueCache.Count = Parent->ValueList.Count; 00838 Kcb->ValueCache.ValueList = Parent->ValueList.List; 00839 } 00840 00841 /* Notify registered callbacks */ 00842 CmpReportNotify(Kcb, 00843 Hive, 00844 Kcb->KeyCell, 00845 REG_NOTIFY_CHANGE_LAST_SET); 00846 } 00847 00848 /* Release the cells */ 00849 Quickie: 00850 if ((ParentCell != HCELL_NIL) && (Hive)) HvReleaseCell(Hive, ParentCell); 00851 if ((ChildCell != HCELL_NIL) && (Hive)) HvReleaseCell(Hive, ChildCell); 00852 00853 /* Release the locks */ 00854 if (FlusherLocked) CmpUnlockHiveFlusher((PCMHIVE)Hive); 00855 CmpReleaseKcbLock(Kcb); 00856 CmpUnlockRegistry(); 00857 return Status; 00858 } 00859 00860 NTSTATUS 00861 NTAPI 00862 CmDeleteValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, 00863 IN UNICODE_STRING ValueName) 00864 { 00865 NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND; 00866 PHHIVE Hive; 00867 PCM_KEY_NODE Parent; 00868 HCELL_INDEX ChildCell, Cell; 00869 PCHILD_LIST ChildList; 00870 PCM_KEY_VALUE Value = NULL; 00871 ULONG ChildIndex; 00872 BOOLEAN Result; 00873 00874 /* Acquire hive lock */ 00875 CmpLockRegistry(); 00876 00877 /* Lock KCB exclusively */ 00878 CmpAcquireKcbLockExclusive(Kcb); 00879 00880 /* Don't touch deleted keys */ 00881 if (Kcb->Delete) 00882 { 00883 /* Undo everything */ 00884 CmpReleaseKcbLock(Kcb); 00885 CmpUnlockRegistry(); 00886 return STATUS_KEY_DELETED; 00887 } 00888 00889 /* Get the hive and the cell index */ 00890 Hive = Kcb->KeyHive; 00891 Cell = Kcb->KeyCell; 00892 00893 /* Lock flushes */ 00894 CmpLockHiveFlusherShared((PCMHIVE)Hive); 00895 00896 /* Get the parent key node */ 00897 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell); 00898 ASSERT(Parent); 00899 00900 /* Get the value list and check if it has any entries */ 00901 ChildList = &Parent->ValueList; 00902 if (ChildList->Count) 00903 { 00904 /* Try to find this value */ 00905 Result = CmpFindNameInList(Hive, 00906 ChildList, 00907 &ValueName, 00908 &ChildIndex, 00909 &ChildCell); 00910 if (!Result) 00911 { 00912 /* Fail */ 00913 Status = STATUS_INSUFFICIENT_RESOURCES; 00914 goto Quickie; 00915 } 00916 00917 /* Value not found, return error */ 00918 if (ChildCell == HCELL_NIL) goto Quickie; 00919 00920 /* We found the value, mark all relevant cells dirty */ 00921 if (!((HvMarkCellDirty(Hive, Cell, FALSE)) && 00922 (HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE)) && 00923 (HvMarkCellDirty(Hive, ChildCell, FALSE)))) 00924 { 00925 /* Not enough log space, fail */ 00926 Status = STATUS_NO_LOG_SPACE; 00927 goto Quickie; 00928 } 00929 00930 /* Get the key value */ 00931 Value = (PCM_KEY_VALUE)HvGetCell(Hive,ChildCell); 00932 ASSERT(Value); 00933 00934 /* Mark it and all related data as dirty */ 00935 if (!CmpMarkValueDataDirty(Hive, Value)) 00936 { 00937 /* Not enough log space, fail */ 00938 Status = STATUS_NO_LOG_SPACE; 00939 goto Quickie; 00940 } 00941 00942 /* Ssanity checks */ 00943 ASSERT(HvIsCellDirty(Hive, Parent->ValueList.List)); 00944 ASSERT(HvIsCellDirty(Hive, ChildCell)); 00945 00946 /* Remove the value from the child list */ 00947 Status = CmpRemoveValueFromList(Hive, ChildIndex, ChildList); 00948 if (!NT_SUCCESS(Status)) 00949 { 00950 /* Set known error */ 00951 Status = STATUS_INSUFFICIENT_RESOURCES; 00952 goto Quickie; 00953 } 00954 00955 /* Remove the value and its data itself */ 00956 if (!CmpFreeValue(Hive, ChildCell)) 00957 { 00958 /* Failed to free the value, fail */ 00959 Status = STATUS_INSUFFICIENT_RESOURCES; 00960 goto Quickie; 00961 } 00962 00963 /* Set the last write time */ 00964 KeQuerySystemTime(&Parent->LastWriteTime); 00965 Kcb->KcbLastWriteTime = Parent->LastWriteTime; 00966 00967 /* Sanity check */ 00968 ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen); 00969 ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen); 00970 ASSERT(HvIsCellDirty(Hive, Cell)); 00971 00972 /* Check if the value list is empty now */ 00973 if (!Parent->ValueList.Count) 00974 { 00975 /* Then clear key node data */ 00976 Parent->MaxValueNameLen = 0; 00977 Parent->MaxValueDataLen = 0; 00978 Kcb->KcbMaxValueNameLen = 0; 00979 Kcb->KcbMaxValueDataLen = 0; 00980 } 00981 00982 /* Cleanup the value cache */ 00983 CmpCleanUpKcbValueCache(Kcb); 00984 00985 /* Sanity checks */ 00986 ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList))); 00987 ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)); 00988 00989 /* Set the value cache */ 00990 Kcb->ValueCache.Count = ChildList->Count; 00991 Kcb->ValueCache.ValueList = ChildList->List; 00992 00993 /* Notify registered callbacks */ 00994 CmpReportNotify(Kcb, Hive, Cell, REG_NOTIFY_CHANGE_LAST_SET); 00995 00996 /* Change default Status to success */ 00997 Status = STATUS_SUCCESS; 00998 } 00999 01000 Quickie: 01001 /* Release the parent cell, if any */ 01002 if (Parent) HvReleaseCell(Hive, Cell); 01003 01004 /* Check if we had a value */ 01005 if (Value) 01006 { 01007 /* Release the child cell */ 01008 ASSERT(ChildCell != HCELL_NIL); 01009 HvReleaseCell(Hive, ChildCell); 01010 } 01011 01012 /* Release locks */ 01013 CmpUnlockHiveFlusher((PCMHIVE)Hive); 01014 CmpReleaseKcbLock(Kcb); 01015 CmpUnlockRegistry(); 01016 return Status; 01017 } 01018 01019 NTSTATUS 01020 NTAPI 01021 CmQueryValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, 01022 IN UNICODE_STRING ValueName, 01023 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 01024 IN PVOID KeyValueInformation, 01025 IN ULONG Length, 01026 IN PULONG ResultLength) 01027 { 01028 NTSTATUS Status; 01029 PCM_KEY_VALUE ValueData; 01030 ULONG Index; 01031 BOOLEAN ValueCached = FALSE; 01032 PCM_CACHED_VALUE *CachedValue; 01033 HCELL_INDEX CellToRelease; 01034 VALUE_SEARCH_RETURN_TYPE Result; 01035 PHHIVE Hive; 01036 PAGED_CODE(); 01037 01038 /* Acquire hive lock */ 01039 CmpLockRegistry(); 01040 01041 /* Lock the KCB shared */ 01042 CmpAcquireKcbLockShared(Kcb); 01043 01044 /* Don't touch deleted keys */ 01045 DoAgain: 01046 if (Kcb->Delete) 01047 { 01048 /* Undo everything */ 01049 CmpReleaseKcbLock(Kcb); 01050 CmpUnlockRegistry(); 01051 return STATUS_KEY_DELETED; 01052 } 01053 01054 /* We don't deal with this yet */ 01055 if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) 01056 { 01057 /* Shouldn't happen */ 01058 ASSERT(FALSE); 01059 } 01060 01061 /* Get the hive */ 01062 Hive = Kcb->KeyHive; 01063 01064 /* Find the key value */ 01065 Result = CmpFindValueByNameFromCache(Kcb, 01066 &ValueName, 01067 &CachedValue, 01068 &Index, 01069 &ValueData, 01070 &ValueCached, 01071 &CellToRelease); 01072 if (Result == SearchNeedExclusiveLock) 01073 { 01074 /* Check if we need an exclusive lock */ 01075 ASSERT(CellToRelease == HCELL_NIL); 01076 ASSERT(ValueData == NULL); 01077 01078 /* Try with exclusive KCB lock */ 01079 CmpConvertKcbSharedToExclusive(Kcb); 01080 goto DoAgain; 01081 } 01082 01083 if (Result == SearchSuccess) 01084 { 01085 /* Sanity check */ 01086 ASSERT(ValueData != NULL); 01087 01088 /* User data, protect against exceptions */ 01089 _SEH2_TRY 01090 { 01091 /* Query the information requested */ 01092 Result = CmpQueryKeyValueData(Kcb, 01093 CachedValue, 01094 ValueData, 01095 ValueCached, 01096 KeyValueInformationClass, 01097 KeyValueInformation, 01098 Length, 01099 ResultLength, 01100 &Status); 01101 if (Result == SearchNeedExclusiveLock) 01102 { 01103 /* Release the value cell */ 01104 if (CellToRelease != HCELL_NIL) 01105 { 01106 HvReleaseCell(Hive, CellToRelease); 01107 CellToRelease = HCELL_NIL; 01108 } 01109 01110 /* Try with exclusive KCB lock */ 01111 CmpConvertKcbSharedToExclusive(Kcb); 01112 goto DoAgain; 01113 } 01114 } 01115 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01116 { 01117 Status = _SEH2_GetExceptionCode(); 01118 } 01119 _SEH2_END; 01120 } 01121 else 01122 { 01123 /* Failed to find the value */ 01124 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01125 } 01126 01127 /* If we have a cell to release, do so */ 01128 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); 01129 01130 /* Release locks */ 01131 CmpReleaseKcbLock(Kcb); 01132 CmpUnlockRegistry(); 01133 return Status; 01134 } 01135 01136 NTSTATUS 01137 NTAPI 01138 CmEnumerateValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, 01139 IN ULONG Index, 01140 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 01141 IN PVOID KeyValueInformation, 01142 IN ULONG Length, 01143 IN PULONG ResultLength) 01144 { 01145 NTSTATUS Status; 01146 PHHIVE Hive; 01147 PCM_KEY_NODE Parent; 01148 HCELL_INDEX CellToRelease = HCELL_NIL, CellToRelease2 = HCELL_NIL; 01149 VALUE_SEARCH_RETURN_TYPE Result; 01150 BOOLEAN IndexIsCached, ValueIsCached = FALSE; 01151 PCELL_DATA CellData; 01152 PCM_CACHED_VALUE *CachedValue; 01153 PCM_KEY_VALUE ValueData = NULL; 01154 PAGED_CODE(); 01155 01156 /* Acquire hive lock */ 01157 CmpLockRegistry(); 01158 01159 /* Lock the KCB shared */ 01160 CmpAcquireKcbLockShared(Kcb); 01161 01162 /* Don't touch deleted keys */ 01163 DoAgain: 01164 if (Kcb->Delete) 01165 { 01166 /* Undo everything */ 01167 CmpReleaseKcbLock(Kcb); 01168 CmpUnlockRegistry(); 01169 return STATUS_KEY_DELETED; 01170 } 01171 01172 /* Get the hive and parent */ 01173 Hive = Kcb->KeyHive; 01174 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); 01175 ASSERT(Parent); 01176 01177 /* FIXME: Lack of cache? */ 01178 if (Kcb->ValueCache.Count != Parent->ValueList.Count) 01179 { 01180 DPRINT1("HACK: Overriding value cache count\n"); 01181 Kcb->ValueCache.Count = Parent->ValueList.Count; 01182 } 01183 01184 /* Make sure the index is valid */ 01185 if (Index >= Kcb->ValueCache.Count) 01186 { 01187 /* Release the cell and fail */ 01188 HvReleaseCell(Hive, Kcb->KeyCell); 01189 Status = STATUS_NO_MORE_ENTRIES; 01190 goto Quickie; 01191 } 01192 01193 /* We don't deal with this yet */ 01194 if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) 01195 { 01196 /* Shouldn't happen */ 01197 ASSERT(FALSE); 01198 } 01199 01200 /* Find the value list */ 01201 Result = CmpGetValueListFromCache(Kcb, 01202 &CellData, 01203 &IndexIsCached, 01204 &CellToRelease); 01205 if (Result == SearchNeedExclusiveLock) 01206 { 01207 /* Check if we need an exclusive lock */ 01208 ASSERT(CellToRelease == HCELL_NIL); 01209 HvReleaseCell(Hive, Kcb->KeyCell); 01210 01211 /* Try with exclusive KCB lock */ 01212 CmpConvertKcbSharedToExclusive(Kcb); 01213 goto DoAgain; 01214 } 01215 else if (Result != SearchSuccess) 01216 { 01217 /* Sanity check */ 01218 ASSERT(CellData == NULL); 01219 01220 /* Release the cell and fail */ 01221 Status = STATUS_INSUFFICIENT_RESOURCES; 01222 goto Quickie; 01223 } 01224 01225 /* Now get the key value */ 01226 Result = CmpGetValueKeyFromCache(Kcb, 01227 CellData, 01228 Index, 01229 &CachedValue, 01230 &ValueData, 01231 IndexIsCached, 01232 &ValueIsCached, 01233 &CellToRelease2); 01234 if (Result == SearchNeedExclusiveLock) 01235 { 01236 /* Cleanup state */ 01237 ASSERT(CellToRelease2 == HCELL_NIL); 01238 if (CellToRelease) 01239 { 01240 HvReleaseCell(Hive, CellToRelease); 01241 CellToRelease = HCELL_NIL; 01242 } 01243 HvReleaseCell(Hive, Kcb->KeyCell); 01244 01245 /* Try with exclusive KCB lock */ 01246 CmpConvertKcbSharedToExclusive(Kcb); 01247 goto DoAgain; 01248 } 01249 else if (Result != SearchSuccess) 01250 { 01251 /* Sanity check */ 01252 ASSERT(ValueData == NULL); 01253 01254 /* Release the cells and fail */ 01255 Status = STATUS_INSUFFICIENT_RESOURCES; 01256 goto Quickie; 01257 } 01258 01259 /* User data, need SEH */ 01260 _SEH2_TRY 01261 { 01262 /* Query the information requested */ 01263 Result = CmpQueryKeyValueData(Kcb, 01264 CachedValue, 01265 ValueData, 01266 ValueIsCached, 01267 KeyValueInformationClass, 01268 KeyValueInformation, 01269 Length, 01270 ResultLength, 01271 &Status); 01272 if (Result == SearchNeedExclusiveLock) 01273 { 01274 /* Cleanup state */ 01275 if (CellToRelease2) HvReleaseCell(Hive, CellToRelease2); 01276 HvReleaseCell(Hive, Kcb->KeyCell); 01277 if (CellToRelease) HvReleaseCell(Hive, CellToRelease); 01278 01279 /* Try with exclusive KCB lock */ 01280 CmpConvertKcbSharedToExclusive(Kcb); 01281 goto DoAgain; 01282 } 01283 } 01284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01285 { 01286 /* Get exception code */ 01287 Status = _SEH2_GetExceptionCode(); 01288 } 01289 _SEH2_END; 01290 01291 Quickie: 01292 /* If we have a cell to release, do so */ 01293 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); 01294 01295 /* Release the parent cell */ 01296 HvReleaseCell(Hive, Kcb->KeyCell); 01297 01298 /* If we have a cell to release, do so */ 01299 if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2); 01300 01301 /* Release locks */ 01302 CmpReleaseKcbLock(Kcb); 01303 CmpUnlockRegistry(); 01304 return Status; 01305 } 01306 01307 NTSTATUS 01308 NTAPI 01309 CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb, 01310 IN KEY_INFORMATION_CLASS KeyInformationClass, 01311 IN PVOID KeyInformation, 01312 IN ULONG Length, 01313 IN PULONG ResultLength) 01314 { 01315 NTSTATUS Status; 01316 PHHIVE Hive; 01317 PCM_KEY_NODE Parent; 01318 HV_TRACK_CELL_REF CellReferences = {0}; 01319 01320 /* Acquire hive lock */ 01321 CmpLockRegistry(); 01322 01323 /* Lock KCB shared */ 01324 CmpAcquireKcbLockShared(Kcb); 01325 01326 /* Don't touch deleted keys */ 01327 if (Kcb->Delete) 01328 { 01329 /* Fail */ 01330 Status = STATUS_KEY_DELETED; 01331 goto Quickie; 01332 } 01333 01334 /* Check what class we got */ 01335 switch (KeyInformationClass) 01336 { 01337 /* Typical information */ 01338 case KeyFullInformation: 01339 case KeyBasicInformation: 01340 case KeyNodeInformation: 01341 01342 /* Get the hive and parent */ 01343 Hive = Kcb->KeyHive; 01344 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); 01345 ASSERT(Parent); 01346 01347 /* Track cell references */ 01348 if (!HvTrackCellRef(&CellReferences, Hive, Kcb->KeyCell)) 01349 { 01350 /* Not enough memory to track references */ 01351 Status = STATUS_INSUFFICIENT_RESOURCES; 01352 } 01353 else 01354 { 01355 /* Call the internal API */ 01356 Status = CmpQueryKeyData(Hive, 01357 Parent, 01358 KeyInformationClass, 01359 KeyInformation, 01360 Length, 01361 ResultLength); 01362 } 01363 break; 01364 01365 /* Unsupported classes for now */ 01366 case KeyNameInformation: 01367 case KeyCachedInformation: 01368 case KeyFlagsInformation: 01369 01370 /* Print message and fail */ 01371 DPRINT1("Unsupported class: %d!\n", KeyInformationClass); 01372 Status = STATUS_NOT_IMPLEMENTED; 01373 break; 01374 01375 /* Illegal classes */ 01376 default: 01377 01378 /* Print message and fail */ 01379 DPRINT1("Unsupported class: %d!\n", KeyInformationClass); 01380 Status = STATUS_INVALID_INFO_CLASS; 01381 break; 01382 } 01383 01384 Quickie: 01385 /* Release references */ 01386 HvReleaseFreeCellRefArray(&CellReferences); 01387 01388 /* Release locks */ 01389 CmpReleaseKcbLock(Kcb); 01390 CmpUnlockRegistry(); 01391 return Status; 01392 } 01393 01394 NTSTATUS 01395 NTAPI 01396 CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb, 01397 IN ULONG Index, 01398 IN KEY_INFORMATION_CLASS KeyInformationClass, 01399 IN PVOID KeyInformation, 01400 IN ULONG Length, 01401 IN PULONG ResultLength) 01402 { 01403 NTSTATUS Status; 01404 PHHIVE Hive; 01405 PCM_KEY_NODE Parent, Child; 01406 HCELL_INDEX ChildCell; 01407 HV_TRACK_CELL_REF CellReferences = {0}; 01408 01409 /* Acquire hive lock */ 01410 CmpLockRegistry(); 01411 01412 /* Lock the KCB shared */ 01413 CmpAcquireKcbLockShared(Kcb); 01414 01415 /* Don't touch deleted keys */ 01416 if (Kcb->Delete) 01417 { 01418 /* Undo everything */ 01419 Status = STATUS_KEY_DELETED; 01420 goto Quickie; 01421 } 01422 01423 /* Get the hive and parent */ 01424 Hive = Kcb->KeyHive; 01425 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); 01426 ASSERT(Parent); 01427 01428 /* Get the child cell */ 01429 ChildCell = CmpFindSubKeyByNumber(Hive, Parent, Index); 01430 01431 /* Release the parent cell */ 01432 HvReleaseCell(Hive, Kcb->KeyCell); 01433 01434 /* Check if we found the child */ 01435 if (ChildCell == HCELL_NIL) 01436 { 01437 /* We didn't, fail */ 01438 Status = STATUS_NO_MORE_ENTRIES; 01439 goto Quickie; 01440 } 01441 01442 /* Now get the actual child node */ 01443 Child = (PCM_KEY_NODE)HvGetCell(Hive, ChildCell); 01444 ASSERT(Child); 01445 01446 /* Track references */ 01447 if (!HvTrackCellRef(&CellReferences, Hive, ChildCell)) 01448 { 01449 /* Can't allocate memory for tracking */ 01450 Status = STATUS_INSUFFICIENT_RESOURCES; 01451 goto Quickie; 01452 } 01453 01454 /* Data can be user-mode, use SEH */ 01455 _SEH2_TRY 01456 { 01457 /* Query the data requested */ 01458 Status = CmpQueryKeyData(Hive, 01459 Child, 01460 KeyInformationClass, 01461 KeyInformation, 01462 Length, 01463 ResultLength); 01464 } 01465 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01466 { 01467 /* Fail with exception code */ 01468 Status = _SEH2_GetExceptionCode(); 01469 _SEH2_YIELD(goto Quickie); 01470 } 01471 _SEH2_END; 01472 01473 Quickie: 01474 /* Release references */ 01475 HvReleaseFreeCellRefArray(&CellReferences); 01476 01477 /* Release locks */ 01478 CmpReleaseKcbLock(Kcb); 01479 CmpUnlockRegistry(); 01480 return Status; 01481 } 01482 01483 NTSTATUS 01484 NTAPI 01485 CmDeleteKey(IN PCM_KEY_BODY KeyBody) 01486 { 01487 NTSTATUS Status; 01488 PHHIVE Hive; 01489 PCM_KEY_NODE Node, Parent; 01490 HCELL_INDEX Cell, ParentCell; 01491 PCM_KEY_CONTROL_BLOCK Kcb; 01492 01493 /* Acquire hive lock */ 01494 CmpLockRegistry(); 01495 01496 /* Get the kcb */ 01497 Kcb = KeyBody->KeyControlBlock; 01498 01499 /* Don't allow deleting the root */ 01500 if (!Kcb->ParentKcb) 01501 { 01502 /* Fail */ 01503 CmpUnlockRegistry(); 01504 return STATUS_CANNOT_DELETE; 01505 } 01506 01507 /* Lock parent and child */ 01508 CmpAcquireTwoKcbLocksExclusiveByKey(Kcb->ConvKey, Kcb->ParentKcb->ConvKey); 01509 01510 /* Check if we're already being deleted */ 01511 if (Kcb->Delete) 01512 { 01513 /* Don't do it twice */ 01514 Status = STATUS_SUCCESS; 01515 goto Quickie2; 01516 } 01517 01518 /* Get the hive and node */ 01519 Hive = Kcb->KeyHive; 01520 Cell = Kcb->KeyCell; 01521 01522 /* Lock flushes */ 01523 CmpLockHiveFlusherShared((PCMHIVE)Hive); 01524 01525 /* Get the key node */ 01526 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); 01527 ASSERT(Node); 01528 01529 /* Sanity check */ 01530 ASSERT(Node->Flags == Kcb->Flags); 01531 01532 /* Check if we don't have any children */ 01533 if (!(Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile]) && 01534 !(Node->Flags & KEY_NO_DELETE)) 01535 { 01536 /* Send notification to registered callbacks */ 01537 CmpReportNotify(Kcb, Hive, Cell, REG_NOTIFY_CHANGE_NAME); 01538 01539 /* Get the parent and free the cell */ 01540 ParentCell = Node->Parent; 01541 Status = CmpFreeKeyByCell(Hive, Cell, TRUE); 01542 if (NT_SUCCESS(Status)) 01543 { 01544 /* Flush any notifications */ 01545 CmpFlushNotifiesOnKeyBodyList(Kcb, FALSE); 01546 01547 /* Clean up information we have on the subkey */ 01548 CmpCleanUpSubKeyInfo(Kcb->ParentKcb); 01549 01550 /* Get the parent node */ 01551 Parent = (PCM_KEY_NODE)HvGetCell(Hive, ParentCell); 01552 if (Parent) 01553 { 01554 /* Update the maximum name length */ 01555 Kcb->ParentKcb->KcbMaxNameLen = (USHORT)Parent->MaxNameLen; 01556 01557 /* Make sure we're dirty */ 01558 ASSERT(HvIsCellDirty(Hive, ParentCell)); 01559 01560 /* Update the write time */ 01561 KeQuerySystemTime(&Parent->LastWriteTime); 01562 Kcb->ParentKcb->KcbLastWriteTime = Parent->LastWriteTime; 01563 01564 /* Release the cell */ 01565 HvReleaseCell(Hive, ParentCell); 01566 } 01567 01568 /* Set the KCB in delete mode and remove it */ 01569 Kcb->Delete = TRUE; 01570 CmpRemoveKeyControlBlock(Kcb); 01571 01572 /* Clear the cell */ 01573 Kcb->KeyCell = HCELL_NIL; 01574 } 01575 } 01576 else 01577 { 01578 /* Fail */ 01579 Status = STATUS_CANNOT_DELETE; 01580 } 01581 01582 /* Release the cell */ 01583 HvReleaseCell(Hive, Cell); 01584 01585 /* Release flush lock */ 01586 CmpUnlockHiveFlusher((PCMHIVE)Hive); 01587 01588 /* Release the KCB locks */ 01589 Quickie2: 01590 CmpReleaseTwoKcbLockByKey(Kcb->ConvKey, Kcb->ParentKcb->ConvKey); 01591 01592 /* Release hive lock */ 01593 CmpUnlockRegistry(); 01594 return Status; 01595 } 01596 01597 NTSTATUS 01598 NTAPI 01599 CmFlushKey(IN PCM_KEY_CONTROL_BLOCK Kcb, 01600 IN BOOLEAN ExclusiveLock) 01601 { 01602 PCMHIVE CmHive; 01603 NTSTATUS Status = STATUS_SUCCESS; 01604 PHHIVE Hive; 01605 01606 /* Ignore flushes until we're ready */ 01607 if (CmpNoWrite) return STATUS_SUCCESS; 01608 01609 /* Get the hives */ 01610 Hive = Kcb->KeyHive; 01611 CmHive = (PCMHIVE)Hive; 01612 01613 /* Check if this is the master hive */ 01614 if (CmHive == CmiVolatileHive) 01615 { 01616 /* Flush all the hives instead */ 01617 CmpDoFlushAll(FALSE); 01618 } 01619 else 01620 { 01621 /* Don't touch the hive */ 01622 CmpLockHiveFlusherExclusive(CmHive); 01623 ASSERT(CmHive->ViewLock); 01624 KeAcquireGuardedMutex(CmHive->ViewLock); 01625 CmHive->ViewLockOwner = KeGetCurrentThread(); 01626 01627 /* Will the hive shrink? */ 01628 if (HvHiveWillShrink(Hive)) 01629 { 01630 /* I don't believe the current Hv does shrinking */ 01631 ASSERT(FALSE); 01632 } 01633 else 01634 { 01635 /* Now we can release views */ 01636 ASSERT(CmHive->ViewLock); 01637 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK_OR_LOADING(CmHive); 01638 ASSERT(KeGetCurrentThread() == CmHive->ViewLockOwner); 01639 KeReleaseGuardedMutex(CmHive->ViewLock); 01640 } 01641 01642 /* Flush only this hive */ 01643 if (!HvSyncHive(Hive)) 01644 { 01645 /* Fail */ 01646 Status = STATUS_REGISTRY_IO_FAILED; 01647 } 01648 01649 /* Release the flush lock */ 01650 CmpUnlockHiveFlusher((PCMHIVE)Hive); 01651 } 01652 01653 /* Return the status */ 01654 return Status; 01655 } 01656 01657 NTSTATUS 01658 NTAPI 01659 CmLoadKey(IN POBJECT_ATTRIBUTES TargetKey, 01660 IN POBJECT_ATTRIBUTES SourceFile, 01661 IN ULONG Flags, 01662 IN PCM_KEY_BODY KeyBody) 01663 { 01664 SECURITY_QUALITY_OF_SERVICE ServiceQos; 01665 SECURITY_CLIENT_CONTEXT ClientSecurityContext; 01666 HANDLE KeyHandle; 01667 BOOLEAN Allocate = TRUE; 01668 PCMHIVE CmHive, LoadedHive; 01669 NTSTATUS Status; 01670 CM_PARSE_CONTEXT ParseContext; 01671 01672 /* Check if we have a trust key */ 01673 if (KeyBody) 01674 { 01675 /* Fail */ 01676 DPRINT1("Trusted classes not yet supported\n"); 01677 return STATUS_NOT_IMPLEMENTED; 01678 } 01679 01680 /* Build a service QoS for a security context */ 01681 ServiceQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); 01682 ServiceQos.ImpersonationLevel = SecurityImpersonation; 01683 ServiceQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; 01684 ServiceQos.EffectiveOnly = TRUE; 01685 Status = SeCreateClientSecurity(PsGetCurrentThread(), 01686 &ServiceQos, 01687 FALSE, 01688 &ClientSecurityContext); 01689 if (!NT_SUCCESS(Status)) 01690 { 01691 /* Fail */ 01692 DPRINT1("Security context failed\n"); 01693 return Status; 01694 } 01695 01696 /* Open the target key */ 01697 #if 0 01698 Status = ZwOpenKey(&KeyHandle, KEY_READ, TargetKey); 01699 #else 01700 RtlZeroMemory(&ParseContext, sizeof(ParseContext)); 01701 ParseContext.CreateOperation = FALSE; 01702 Status = ObOpenObjectByName(TargetKey, 01703 CmpKeyObjectType, 01704 KernelMode, 01705 NULL, 01706 KEY_READ, 01707 &ParseContext, 01708 &KeyHandle); 01709 #endif 01710 if (!NT_SUCCESS(Status)) KeyHandle = NULL; 01711 01712 /* Open the hive */ 01713 Status = CmpCmdHiveOpen(SourceFile, 01714 &ClientSecurityContext, 01715 &Allocate, 01716 &CmHive, 01717 0); 01718 01719 /* Get rid of the security context */ 01720 SeDeleteClientSecurity(&ClientSecurityContext); 01721 01722 /* See if we failed */ 01723 if (!NT_SUCCESS(Status)) 01724 { 01725 /* See if the target already existed */ 01726 if (KeyHandle) 01727 { 01728 /* Lock the registry */ 01729 CmpLockRegistryExclusive(); 01730 01731 /* Check if we are already loaded */ 01732 if (CmpIsHiveAlreadyLoaded(KeyHandle, SourceFile, &LoadedHive)) 01733 { 01734 /* That's okay then */ 01735 ASSERT(LoadedHive); 01736 Status = STATUS_SUCCESS; 01737 } 01738 01739 /* Release the registry */ 01740 CmpUnlockRegistry(); 01741 } 01742 01743 /* Close the key handle if we had one */ 01744 if (KeyHandle) ZwClose(KeyHandle); 01745 return Status; 01746 } 01747 01748 /* Lock the registry shared */ 01749 CmpLockRegistry(); 01750 01751 /* Lock loading */ 01752 ExAcquirePushLockExclusive(&CmpLoadHiveLock); 01753 01754 /* Lock the hive to this thread */ 01755 CmHive->Hive.HiveFlags |= HIVE_IS_UNLOADING; 01756 CmHive->CreatorOwner = KeGetCurrentThread(); 01757 01758 /* Set flag */ 01759 if (Flags & REG_NO_LAZY_FLUSH) CmHive->Hive.HiveFlags |= HIVE_NOLAZYFLUSH; 01760 01761 /* Link the hive */ 01762 Status = CmpLinkHiveToMaster(TargetKey->ObjectName, 01763 TargetKey->RootDirectory, 01764 CmHive, 01765 Allocate, 01766 TargetKey->SecurityDescriptor); 01767 if (NT_SUCCESS(Status)) 01768 { 01769 /* Add to HiveList key */ 01770 CmpAddToHiveFileList(CmHive); 01771 01772 /* Sync the hive if necessary */ 01773 if (Allocate) 01774 { 01775 /* Sync it under the flusher lock */ 01776 CmpLockHiveFlusherExclusive(CmHive); 01777 HvSyncHive(&CmHive->Hive); 01778 CmpUnlockHiveFlusher(CmHive); 01779 } 01780 01781 /* Release the hive */ 01782 CmHive->Hive.HiveFlags &= ~HIVE_IS_UNLOADING; 01783 CmHive->CreatorOwner = NULL; 01784 01785 /* Allow loads */ 01786 ExReleasePushLock(&CmpLoadHiveLock); 01787 } 01788 else 01789 { 01790 DPRINT1("CmpLinkHiveToMaster failed, Status %lx\n", Status); 01791 /* FIXME: TODO */ 01792 ASSERT(FALSE); 01793 } 01794 01795 /* Is this first profile load? */ 01796 if (!(CmpProfileLoaded) && !(CmpWasSetupBoot)) 01797 { 01798 /* User is now logged on, set quotas */ 01799 CmpProfileLoaded = TRUE; 01800 CmpSetGlobalQuotaAllowed(); 01801 } 01802 01803 /* Unlock the registry */ 01804 CmpUnlockRegistry(); 01805 01806 /* Close handle and return */ 01807 if (KeyHandle) ZwClose(KeyHandle); 01808 return Status; 01809 } 01810 01811 NTSTATUS 01812 NTAPI 01813 CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb, 01814 IN ULONG Flags) 01815 { 01816 UNIMPLEMENTED; 01817 return STATUS_NOT_IMPLEMENTED; 01818 } 01819 01820 ULONG 01821 NTAPI 01822 CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb, 01823 IN BOOLEAN RemoveEmptyCacheEntries) 01824 { 01825 PCM_KEY_HASH Entry; 01826 PCM_KEY_CONTROL_BLOCK CachedKcb; 01827 PCM_KEY_CONTROL_BLOCK ParentKcb; 01828 ULONG ParentKeyCount; 01829 ULONG i, j; 01830 ULONG SubKeys = 0; 01831 01832 DPRINT("CmCountOpenSubKeys() called\n"); 01833 01834 /* The root key is the only referenced key. There are no refereced sub keys. */ 01835 if (RootKcb->RefCount == 1) 01836 { 01837 DPRINT("open sub keys: 0\n"); 01838 return 0; 01839 } 01840 01841 /* Enumerate all hash lists */ 01842 for (i = 0; i < CmpHashTableSize; i++) 01843 { 01844 /* Get the first cache entry */ 01845 Entry = CmpCacheTable[i].Entry; 01846 01847 /* Enumerate all cache entries */ 01848 while (Entry) 01849 { 01850 /* Get the KCB of the current cache entry */ 01851 CachedKcb = CONTAINING_RECORD(Entry, CM_KEY_CONTROL_BLOCK, KeyHash); 01852 01853 /* Check keys only that are subkeys to our root key */ 01854 if (CachedKcb->TotalLevels > RootKcb->TotalLevels) 01855 { 01856 /* Calculate the number of parent keys to the root key */ 01857 ParentKeyCount = CachedKcb->TotalLevels - RootKcb->TotalLevels; 01858 01859 /* Find a parent key that could be the root key */ 01860 ParentKcb = CachedKcb; 01861 for (j = 0; j < ParentKeyCount; j++) 01862 { 01863 ParentKcb = ParentKcb->ParentKcb; 01864 } 01865 01866 /* Check whether the parent is the root key */ 01867 if (ParentKcb == RootKcb) 01868 { 01869 DPRINT("Found a sub key \n"); 01870 DPRINT("RefCount = %u\n", CachedKcb->RefCount); 01871 01872 if (CachedKcb->RefCount > 0) 01873 { 01874 /* Count the current hash entry if it is in use */ 01875 SubKeys++; 01876 } 01877 else if ((CachedKcb->RefCount == 0) && (RemoveEmptyCacheEntries == TRUE)) 01878 { 01879 /* Remove the current key from the delayed close list */ 01880 CmpRemoveFromDelayedClose(CachedKcb); 01881 01882 /* Remove the current cache entry */ 01883 CmpCleanUpKcbCacheWithLock(CachedKcb, TRUE); 01884 01885 /* Restart, because the hash list has changed */ 01886 Entry = CmpCacheTable[i].Entry; 01887 continue; 01888 } 01889 } 01890 } 01891 01892 /* Get the next cache entry */ 01893 Entry = Entry->NextHash; 01894 } 01895 } 01896 01897 DPRINT("open sub keys: %u\n", SubKeys); 01898 01899 return SubKeys; 01900 } Generated on Fri May 25 2012 04:35:29 for ReactOS by
1.7.6.1
|