ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cmapi.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.