update for HEAD-2003050101
[reactos.git] / ntoskrnl / cm / ntfunc.c
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * FILE:             ntoskrnl/cm/ntfunc.c
5  * PURPOSE:          Ntxxx function for registry access
6  * UPDATE HISTORY:
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ddk/ntddk.h>
12 #include <roscfg.h>
13 #include <internal/ob.h>
14 #include <limits.h>
15 #include <string.h>
16 #include <internal/pool.h>
17 #include <internal/registry.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 #include "cm.h"
23
24
25 /* GLOBALS ******************************************************************/
26
27 extern POBJECT_TYPE  CmiKeyType;
28 extern PREGISTRY_HIVE  CmiVolatileHive;
29
30 static BOOLEAN CmiRegistryInitialized = FALSE;
31
32
33 /* FUNCTIONS ****************************************************************/
34
35 NTSTATUS STDCALL
36 NtCreateKey(OUT PHANDLE KeyHandle,
37             IN ACCESS_MASK DesiredAccess,
38             IN POBJECT_ATTRIBUTES ObjectAttributes,
39             IN ULONG TitleIndex,
40             IN PUNICODE_STRING Class,
41             IN ULONG CreateOptions,
42             OUT PULONG Disposition)
43 {
44   UNICODE_STRING RemainingPath;
45   PKEY_OBJECT KeyObject;
46   NTSTATUS Status;
47   PVOID Object;
48   PWSTR End;
49
50   DPRINT("NtCreateKey (Name %wZ  KeyHandle %x  Root %x)\n",
51          ObjectAttributes->ObjectName,
52          KeyHandle,
53          ObjectAttributes->RootDirectory);
54
55   /* FIXME: check for standard handle prefix and adjust objectAttributes accordingly */
56
57   Status = ObFindObject(ObjectAttributes,
58                         &Object,
59                         &RemainingPath,
60                         CmiKeyType);
61   if (!NT_SUCCESS(Status))
62     {
63       return(Status);
64     }
65
66   DPRINT("RemainingPath %wZ\n", &RemainingPath);
67
68   if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
69     {
70       /* Fail if the key has been deleted */
71       if (((PKEY_OBJECT) Object)->Flags & KO_MARKED_FOR_DELETE)
72         {
73           ObDereferenceObject(Object);
74           return(STATUS_UNSUCCESSFUL);
75         }
76
77       if (Disposition)
78         *Disposition = REG_OPENED_EXISTING_KEY;
79
80       Status = ObCreateHandle(PsGetCurrentProcess(),
81                               Object,
82                               DesiredAccess,
83                               FALSE,
84                               KeyHandle);
85
86       DPRINT("Status %x\n", Status);
87       ObDereferenceObject(Object);
88       return Status;
89     }
90
91   /* If RemainingPath contains \ we must return error
92      because NtCreateKey don't create trees */
93   if (RemainingPath.Buffer[0] == '\\')
94     End = wcschr(RemainingPath.Buffer + 1, '\\');
95   else
96     End = wcschr(RemainingPath.Buffer, '\\');
97
98   if (End != NULL)
99     {
100       ObDereferenceObject(Object);
101       return STATUS_OBJECT_NAME_NOT_FOUND;
102     }
103
104   DPRINT("RemainingPath %S  ParentObject %x\n", RemainingPath.Buffer, Object);
105
106   Status = ObCreateObject(KeyHandle,
107                           DesiredAccess,
108                           NULL,
109                           CmiKeyType,
110                           (PVOID*)&KeyObject);
111   if (!NT_SUCCESS(Status))
112     {
113       return(Status);
114     }
115
116   KeyObject->ParentKey = Object;
117
118   if (CreateOptions & REG_OPTION_VOLATILE)
119     KeyObject->RegistryHive = CmiVolatileHive;
120   else
121     KeyObject->RegistryHive = KeyObject->ParentKey->RegistryHive;
122
123   KeyObject->Flags = 0;
124   KeyObject->NumberOfSubKeys = 0;
125   KeyObject->SizeOfSubKeys = 0;
126   KeyObject->SubKeys = NULL;
127
128   /* Acquire hive lock */
129   ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
130
131   /* add key to subkeys of parent if needed */
132   Status = CmiAddSubKey(KeyObject->RegistryHive,
133                         KeyObject->ParentKey,
134                         KeyObject,
135                         RemainingPath.Buffer,
136                         RemainingPath.Length,
137                         TitleIndex,
138                         Class,
139                         CreateOptions);
140   if (!NT_SUCCESS(Status))
141     {
142       DPRINT("CmiAddSubKey() failed (Status %lx)\n", Status);
143       /* Release hive lock */
144       ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
145       ObDereferenceObject(KeyObject);
146       ObDereferenceObject(Object);
147       return STATUS_UNSUCCESSFUL;
148     }
149
150   KeyObject->Name = KeyObject->KeyCell->Name;
151   KeyObject->NameSize = KeyObject->KeyCell->NameSize;
152
153   if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
154     {
155       KeyObject->KeyCell->ParentKeyOffset = KeyObject->ParentKey->BlockOffset;
156       KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
157     }
158   else
159     {
160       KeyObject->KeyCell->ParentKeyOffset = -1;
161       KeyObject->KeyCell->SecurityKeyOffset = -1;
162       /* This key must remain in memory unless it is deleted
163          or file is unloaded */
164       ObReferenceObjectByPointer(KeyObject,
165                                  STANDARD_RIGHTS_REQUIRED,
166                                  NULL,
167                                  UserMode);
168     }
169
170   CmiAddKeyToList(KeyObject->ParentKey, KeyObject);
171
172   VERIFY_KEY_OBJECT(KeyObject);
173
174   /* Release hive lock */
175   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
176
177   ObDereferenceObject(KeyObject);
178   ObDereferenceObject(Object);
179
180   if (Disposition)
181     *Disposition = REG_CREATED_NEW_KEY;
182
183   CmiSyncHives();
184
185   return Status;
186 }
187
188
189 NTSTATUS STDCALL
190 NtDeleteKey(IN HANDLE KeyHandle)
191 {
192   PKEY_OBJECT KeyObject;
193   NTSTATUS Status;
194
195   DPRINT("KeyHandle %x\n", KeyHandle);
196
197   /* Verify that the handle is valid and is a registry key */
198   Status = ObReferenceObjectByHandle(KeyHandle,
199                                      KEY_WRITE,
200                                      CmiKeyType,
201                                      UserMode,
202                                      (PVOID *)&KeyObject,
203                                      NULL);
204   if (!NT_SUCCESS(Status))
205     {
206       return(Status);
207     }
208
209   /* Acquire hive lock */
210   ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
211
212   VERIFY_KEY_OBJECT(KeyObject);
213
214   /* Check for subkeys */
215   if (KeyObject->NumberOfSubKeys != 0)
216     {
217       Status = STATUS_CANNOT_DELETE;
218     }
219   else
220     {
221       /* Set the marked for delete bit in the key object */
222       KeyObject->Flags |= KO_MARKED_FOR_DELETE;
223       Status = STATUS_SUCCESS;
224     }
225
226   /* Release hive lock */
227   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
228
229   DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
230
231   /* Dereference the object */
232   ObDereferenceObject(KeyObject);
233   if(KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive)
234     ObDereferenceObject(KeyObject);
235
236   DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
237
238   /*
239    * Note:
240    * Hive-Synchronization will not be triggered here. This is done in
241    * CmiObjectDelete() (in regobj.c) after all key-related structures
242    * have been released.
243    */
244
245   return(Status);
246 }
247
248
249 NTSTATUS STDCALL
250 NtEnumerateKey(
251         IN      HANDLE                  KeyHandle,
252         IN      ULONG                     Index,
253         IN      KEY_INFORMATION_CLASS   KeyInformationClass,
254         OUT     PVOID                     KeyInformation,
255         IN      ULONG                     Length,
256         OUT     PULONG                  ResultLength
257         )
258 {
259   NTSTATUS  Status;
260   PKEY_OBJECT  KeyObject;
261   PREGISTRY_HIVE  RegistryHive;
262   PKEY_CELL  KeyCell, SubKeyCell;
263   PHASH_TABLE_CELL  HashTableBlock;
264   PKEY_BASIC_INFORMATION  BasicInformation;
265   PKEY_NODE_INFORMATION  NodeInformation;
266   PKEY_FULL_INFORMATION  FullInformation;
267   PDATA_CELL pClassData;
268
269   DPRINT("KH %x  I %d  KIC %x KI %x  L %d  RL %x\n",
270          KeyHandle,
271          Index,
272          KeyInformationClass,
273          KeyInformation,
274          Length,
275          ResultLength);
276
277   /* Verify that the handle is valid and is a registry key */
278   Status = ObReferenceObjectByHandle(KeyHandle,
279                 KEY_ENUMERATE_SUB_KEYS,
280                 CmiKeyType,
281                 UserMode,
282                 (PVOID *) &KeyObject,
283                 NULL);
284   if (!NT_SUCCESS(Status))
285     {
286       DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
287       return(Status);
288     }
289
290   /* Acquire hive lock */
291   ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
292
293   VERIFY_KEY_OBJECT(KeyObject);
294
295   /* Get pointer to KeyCell */
296   KeyCell = KeyObject->KeyCell;
297   RegistryHive = KeyObject->RegistryHive;
298
299   /* Get pointer to SubKey */
300   if (Index >= KeyCell->NumberOfSubKeys)
301     {
302       if (RegistryHive == CmiVolatileHive)
303         {
304           ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
305           ObDereferenceObject(KeyObject);
306           DPRINT("No more volatile entries\n");
307           return(STATUS_NO_MORE_ENTRIES);
308         }
309       else
310         {
311           ULONG i;
312           PKEY_OBJECT CurKey = NULL;
313
314           /* Search volatile keys */
315           for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
316             {
317               CurKey = KeyObject->SubKeys[i];
318               if (CurKey->RegistryHive == CmiVolatileHive)
319                 {
320                   if (Index-- == KeyObject->NumberOfSubKeys)
321                     break;
322                 }
323             }
324           if (Index >= KeyCell->NumberOfSubKeys)
325             {
326               ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
327               ObDereferenceObject(KeyObject);
328               DPRINT("No more non-volatile entries\n");
329               return(STATUS_NO_MORE_ENTRIES);
330             }
331           SubKeyCell = CurKey->KeyCell;
332         }
333     }
334   else
335     {
336       if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
337         {
338           return(STATUS_NO_MORE_ENTRIES);
339           ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
340           ObDereferenceObject(KeyObject);
341         }
342
343       HashTableBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
344       if (HashTableBlock == NULL)
345         {
346           DPRINT("CmiGetBlock() failed\n");
347           ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
348           ObDereferenceObject(KeyObject);
349           return STATUS_UNSUCCESSFUL;
350         }
351       SubKeyCell = CmiGetKeyFromHashByIndex(RegistryHive,
352                                             HashTableBlock,
353                                             Index);
354     }
355
356   if (SubKeyCell == NULL)
357     {
358       ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
359       ObDereferenceObject(KeyObject);
360       DPRINT("No more entries\n");
361       return(STATUS_NO_MORE_ENTRIES);
362     }
363
364   Status = STATUS_SUCCESS;
365   switch (KeyInformationClass)
366     {
367     case KeyBasicInformation:
368       /* Check size of buffer */
369       *ResultLength = sizeof(KEY_BASIC_INFORMATION) + 
370         (SubKeyCell->NameSize ) * sizeof(WCHAR);
371       if (Length < *ResultLength)
372         {
373           Status = STATUS_BUFFER_OVERFLOW;
374         }
375       else
376         {
377           /* Fill buffer with requested info */
378           BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
379           BasicInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
380           BasicInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
381           BasicInformation->TitleIndex = Index;
382           BasicInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
383           mbstowcs(BasicInformation->Name, 
384             SubKeyCell->Name, 
385             SubKeyCell->NameSize * 2);
386 //          BasicInformation->Name[SubKeyCell->NameSize] = 0;
387         }
388       break;
389       
390     case KeyNodeInformation:
391       /* Check size of buffer */
392       *ResultLength = sizeof(KEY_NODE_INFORMATION) +
393         SubKeyCell->NameSize * sizeof(WCHAR) +
394         SubKeyCell->ClassSize;
395       if (Length < *ResultLength)
396         {
397           Status = STATUS_BUFFER_OVERFLOW;
398         }
399       else
400         {
401           /* Fill buffer with requested info */
402           NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
403           NodeInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
404           NodeInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
405           NodeInformation->TitleIndex = Index;
406           NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + 
407             SubKeyCell->NameSize * sizeof(WCHAR);
408           NodeInformation->ClassLength = SubKeyCell->ClassSize;
409           NodeInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
410           mbstowcs(NodeInformation->Name, 
411             SubKeyCell->Name,
412             SubKeyCell->NameSize * 2);
413 //          NodeInformation->Name[SubKeyCell->NameSize] = 0;
414           if (SubKeyCell->ClassSize != 0)
415             {
416               pClassData=CmiGetBlock(KeyObject->RegistryHive,
417                 SubKeyCell->ClassNameOffset,
418                 NULL);
419               wcsncpy(NodeInformation->Name + SubKeyCell->NameSize ,
420                       (PWCHAR) pClassData->Data,
421                       SubKeyCell->ClassSize);
422             }
423         }
424       break;
425       
426     case KeyFullInformation:
427       /*  check size of buffer  */
428       *ResultLength = sizeof(KEY_FULL_INFORMATION) +
429           SubKeyCell->ClassSize;
430       if (Length < *ResultLength)
431         {
432           Status = STATUS_BUFFER_OVERFLOW;
433         }
434       else
435         {
436           /* fill buffer with requested info  */
437           FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
438           FullInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
439           FullInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
440           FullInformation->TitleIndex = Index;
441           FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - 
442             sizeof(WCHAR);
443           FullInformation->ClassLength = SubKeyCell->ClassSize;
444           FullInformation->SubKeys = SubKeyCell->NumberOfSubKeys;
445           FullInformation->MaxNameLen = 
446             CmiGetMaxNameLength(RegistryHive, SubKeyCell);
447           FullInformation->MaxClassLen = 
448             CmiGetMaxClassLength(RegistryHive, SubKeyCell);
449           FullInformation->Values = SubKeyCell->NumberOfValues;
450           FullInformation->MaxValueNameLen = 
451             CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
452           FullInformation->MaxValueDataLen = 
453             CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
454           if (SubKeyCell->ClassSize != 0)
455             {
456               pClassData = CmiGetBlock(KeyObject->RegistryHive,
457                 SubKeyCell->ClassNameOffset,
458                 NULL);
459               wcsncpy(FullInformation->Class,
460                 (PWCHAR) pClassData->Data,
461                 SubKeyCell->ClassSize);
462             }
463         }
464       break;
465     }
466
467   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
468   ObDereferenceObject(KeyObject);
469
470   DPRINT("Returning status %x\n", Status);
471
472   return(Status);
473 }
474
475
476 NTSTATUS STDCALL
477 NtEnumerateValueKey(IN HANDLE KeyHandle,
478         IN ULONG Index,
479         IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
480         OUT PVOID KeyValueInformation,
481         IN ULONG Length,
482         OUT PULONG ResultLength)
483 {
484   NTSTATUS  Status;
485   PKEY_OBJECT  KeyObject;
486   PREGISTRY_HIVE  RegistryHive;
487   PKEY_CELL  KeyCell;
488   PVALUE_CELL  ValueCell;
489   PDATA_CELL  DataCell;
490   PKEY_VALUE_BASIC_INFORMATION  ValueBasicInformation;
491   PKEY_VALUE_PARTIAL_INFORMATION  ValuePartialInformation;
492   PKEY_VALUE_FULL_INFORMATION  ValueFullInformation;
493
494   DPRINT("KH %x  I %d  KVIC %x  KVI %x  L %d  RL %x\n",
495          KeyHandle,
496          Index,
497          KeyValueInformationClass,
498          KeyValueInformation,
499          Length,
500          ResultLength);
501
502   /*  Verify that the handle is valid and is a registry key  */
503   Status = ObReferenceObjectByHandle(KeyHandle,
504                 KEY_QUERY_VALUE,
505                 CmiKeyType,
506                 UserMode,
507                 (PVOID *) &KeyObject,
508                 NULL);
509
510   if (!NT_SUCCESS(Status))
511     {
512       return Status;
513     }
514
515   /* Acquire hive lock */
516   ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
517
518   VERIFY_KEY_OBJECT(KeyObject);
519
520   /* Get pointer to KeyCell */
521   KeyCell = KeyObject->KeyCell;
522   RegistryHive = KeyObject->RegistryHive;
523
524   /* Get Value block of interest */
525   Status = CmiGetValueFromKeyByIndex(RegistryHive,
526                 KeyCell,
527                 Index,
528                 &ValueCell);
529
530   if (!NT_SUCCESS(Status))
531     {
532       ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
533       ObDereferenceObject(KeyObject);
534       return Status;
535     }
536
537   if (ValueCell != NULL)
538     {
539       switch (KeyValueInformationClass)
540         {
541         case KeyValueBasicInformation:
542           if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
543             {
544               *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + 
545                 (ValueCell->NameSize + 1) * sizeof(WCHAR);
546             }
547           else
548             {
549               *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + 
550                 ValueCell->NameSize + sizeof(WCHAR);
551             }
552           if (Length < *ResultLength)
553             {
554               Status = STATUS_BUFFER_OVERFLOW;
555             }
556           else
557             {
558               ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION) 
559                 KeyValueInformation;
560               ValueBasicInformation->TitleIndex = 0;
561               ValueBasicInformation->Type = ValueCell->DataType;
562               if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
563                 {
564                   ValueBasicInformation->NameLength =
565                     (ValueCell->NameSize + 1) * sizeof(WCHAR);
566                   CmiCopyPackedName(ValueBasicInformation->Name,
567                                     ValueCell->Name,
568                                     ValueCell->NameSize);
569                   ValueBasicInformation->Name[ValueCell->NameSize] = 0;
570                 }
571               else
572                 {
573                   ValueBasicInformation->NameLength =
574                     ValueCell->NameSize + sizeof(WCHAR);
575                   RtlCopyMemory(ValueBasicInformation->Name,
576                                 ValueCell->Name,
577                                 ValueCell->NameSize * sizeof(WCHAR));
578                   ValueBasicInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
579                 }
580             }
581           break;
582
583         case KeyValuePartialInformation:
584           *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 
585             (ValueCell->DataSize & LONG_MAX);
586           if (Length < *ResultLength)
587             {
588               Status = STATUS_BUFFER_OVERFLOW;
589             }
590           else
591             {
592               ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
593                 KeyValueInformation;
594               ValuePartialInformation->TitleIndex = 0;
595               ValuePartialInformation->Type = ValueCell->DataType;
596               ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
597               if(ValueCell->DataSize >0)
598               {
599                 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
600                 RtlCopyMemory(ValuePartialInformation->Data, 
601                   DataCell->Data,
602                   ValueCell->DataSize & LONG_MAX);
603               }
604               else
605               {
606                 RtlCopyMemory(ValuePartialInformation->Data, 
607                   &ValueCell->DataOffset, 
608                   ValueCell->DataSize & LONG_MAX);
609               }
610               DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
611             }
612           break;
613
614         case KeyValueFullInformation:
615           if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
616             {
617               *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
618                 (ValueCell->NameSize + 1) * sizeof(WCHAR) +
619                 (ValueCell->DataSize & LONG_MAX);
620             }
621           else
622             {
623               *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
624                 ValueCell->NameSize + sizeof(WCHAR) +
625                 (ValueCell->DataSize & LONG_MAX);
626             }
627           if (Length < *ResultLength)
628             {
629               Status = STATUS_BUFFER_OVERFLOW;
630             }
631           else
632             {
633               ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION) 
634                 KeyValueInformation;
635               ValueFullInformation->TitleIndex = 0;
636               ValueFullInformation->Type = ValueCell->DataType;
637               if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
638                 {
639                   ValueFullInformation->NameLength =
640                     (ValueCell->NameSize + 1) * sizeof(WCHAR);
641
642                   CmiCopyPackedName(ValueFullInformation->Name,
643                                     ValueCell->Name,
644                                     ValueCell->NameSize);
645                   ValueFullInformation->Name[ValueCell->NameSize] = 0;
646                 }
647               else
648                 {
649                   ValueFullInformation->NameLength =
650                     ValueCell->NameSize + sizeof(WCHAR);
651                   RtlCopyMemory(ValueFullInformation->Name,
652                                 ValueCell->Name,
653                                 ValueCell->NameSize);
654                   ValueFullInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
655                 }
656               ValueFullInformation->DataOffset = 
657                 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
658                 ValueFullInformation->NameLength;
659               ValueFullInformation->DataOffset =
660                 (ValueFullInformation->DataOffset + 3) & 0xfffffffc;
661               ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
662               if (ValueCell->DataSize > 0)
663                 {
664                   DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
665                   RtlCopyMemory((PCHAR) ValueFullInformation
666                     + ValueFullInformation->DataOffset,
667                     DataCell->Data,
668                     ValueCell->DataSize & LONG_MAX);
669                 }
670               else
671                 {
672                   RtlCopyMemory((PCHAR) ValueFullInformation
673                     + ValueFullInformation->DataOffset,
674                     &ValueCell->DataOffset,
675                     ValueCell->DataSize & LONG_MAX);
676                 }
677             }
678           break;
679         }
680     }
681   else
682     {
683       Status = STATUS_UNSUCCESSFUL;
684     }
685
686   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
687   ObDereferenceObject(KeyObject);
688
689   return Status;
690 }
691
692
693 NTSTATUS STDCALL
694 NtFlushKey(IN HANDLE KeyHandle)
695 {
696   NTSTATUS Status;
697   PKEY_OBJECT  KeyObject;
698   PREGISTRY_HIVE  RegistryHive;
699
700   DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle);
701
702   /* Verify that the handle is valid and is a registry key */
703   Status = ObReferenceObjectByHandle(KeyHandle,
704                                      KEY_QUERY_VALUE,
705                                      CmiKeyType,
706                                      UserMode,
707                                      (PVOID *)&KeyObject,
708                                      NULL);
709   if (!NT_SUCCESS(Status))
710     {
711       return(Status);
712     }
713
714   VERIFY_KEY_OBJECT(KeyObject);
715
716   RegistryHive = KeyObject->RegistryHive;
717
718   /* Acquire hive lock */
719   ExAcquireResourceExclusiveLite(&RegistryHive->HiveResource,
720                                  TRUE);
721
722   if (IsVolatileHive(RegistryHive))
723     {
724       Status = STATUS_SUCCESS;
725     }
726   else
727     {
728       /* Flush non-volatile hive */
729       Status = CmiFlushRegistryHive(RegistryHive);
730     }
731
732   ExReleaseResourceLite(&RegistryHive->HiveResource);
733
734   ObDereferenceObject(KeyObject);
735
736   return STATUS_SUCCESS;
737 }
738
739
740 NTSTATUS STDCALL
741 NtOpenKey(OUT PHANDLE KeyHandle,
742           IN ACCESS_MASK DesiredAccess,
743           IN POBJECT_ATTRIBUTES ObjectAttributes)
744 {
745   UNICODE_STRING RemainingPath;
746   NTSTATUS Status;
747   PVOID Object;
748
749   DPRINT("NtOpenFile(KH %x  DA %x  OA %x  OA->ON '%wZ'\n",
750          KeyHandle,
751          DesiredAccess,
752          ObjectAttributes,
753          ObjectAttributes ? ObjectAttributes->ObjectName : NULL);
754
755   RemainingPath.Buffer = NULL;
756   Status = ObFindObject(ObjectAttributes,
757                         &Object,
758                         &RemainingPath,
759                         CmiKeyType);
760   if (!NT_SUCCESS(Status))
761     {
762       return(Status);
763     }
764
765   VERIFY_KEY_OBJECT((PKEY_OBJECT) Object);
766
767   DPRINT("RemainingPath '%wZ'\n", &RemainingPath);
768
769   if ((RemainingPath.Buffer != NULL) && (RemainingPath.Buffer[0] != 0))
770     {
771       ObDereferenceObject(Object);
772       return(STATUS_UNSUCCESSFUL);
773     }
774
775   /* Fail if the key has been deleted */
776   if (((PKEY_OBJECT)Object)->Flags & KO_MARKED_FOR_DELETE)
777     {
778       ObDereferenceObject(Object);
779       return(STATUS_UNSUCCESSFUL);
780     }
781
782   Status = ObCreateHandle(PsGetCurrentProcess(),
783                           Object,
784                           DesiredAccess,
785                           FALSE,
786                           KeyHandle);
787   ObDereferenceObject(Object);
788
789   if (!NT_SUCCESS(Status))
790     {
791       return(Status);
792     }
793
794   return(STATUS_SUCCESS);
795 }
796
797
798 NTSTATUS STDCALL
799 NtQueryKey(IN HANDLE KeyHandle,
800            IN KEY_INFORMATION_CLASS KeyInformationClass,
801            OUT PVOID KeyInformation,
802            IN ULONG Length,
803            OUT PULONG ResultLength)
804 {
805   PKEY_BASIC_INFORMATION BasicInformation;
806   PKEY_NODE_INFORMATION NodeInformation;
807   PKEY_FULL_INFORMATION FullInformation;
808   PREGISTRY_HIVE RegistryHive;
809   PDATA_CELL pClassData;
810   PKEY_OBJECT KeyObject;
811   PKEY_CELL KeyCell;
812   NTSTATUS Status;
813
814   DPRINT("KH %x  KIC %x  KI %x  L %d  RL %x\n",
815          KeyHandle,
816          KeyInformationClass,
817          KeyInformation,
818          Length,
819          ResultLength);
820
821   /* Verify that the handle is valid and is a registry key */
822   Status = ObReferenceObjectByHandle(KeyHandle,
823                 KEY_READ,
824                 CmiKeyType,
825                 UserMode,
826                 (PVOID *) &KeyObject,
827                 NULL);
828   if (!NT_SUCCESS(Status))
829     {
830       return Status;
831     }
832
833   /* Acquire hive lock */
834   ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
835
836   VERIFY_KEY_OBJECT(KeyObject);
837
838   /* Get pointer to KeyCell */
839   KeyCell = KeyObject->KeyCell;
840   RegistryHive = KeyObject->RegistryHive;
841
842   Status = STATUS_SUCCESS;
843   switch (KeyInformationClass)
844     {
845     case KeyBasicInformation:
846       /* Check size of buffer */
847       if (Length < sizeof(KEY_BASIC_INFORMATION) + 
848           KeyObject->NameSize * sizeof(WCHAR))
849         {
850           Status = STATUS_BUFFER_OVERFLOW;
851         }
852       else
853         {
854           /* Fill buffer with requested info */
855           BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
856           BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
857           BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
858           BasicInformation->TitleIndex = 0;
859           BasicInformation->NameLength = (KeyObject->NameSize) * sizeof(WCHAR);
860           mbstowcs(BasicInformation->Name,
861             KeyObject->Name, 
862             KeyObject->NameSize*sizeof(WCHAR));
863           *ResultLength = sizeof(KEY_BASIC_INFORMATION) + 
864             KeyObject->NameSize * sizeof(WCHAR);
865         }
866       break;
867
868     case KeyNodeInformation:
869       /* Check size of buffer */
870       if (Length < sizeof(KEY_NODE_INFORMATION)
871          + KeyObject->NameSize * sizeof(WCHAR)
872          + KeyCell->ClassSize)
873         {
874           Status = STATUS_BUFFER_OVERFLOW;
875         }
876       else
877         {
878           /* Fill buffer with requested info */
879           NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
880           NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
881           NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
882           NodeInformation->TitleIndex = 0;
883           NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + 
884             KeyObject->NameSize * sizeof(WCHAR);
885           NodeInformation->ClassLength = KeyCell->ClassSize;
886           NodeInformation->NameLength = KeyObject->NameSize * sizeof(WCHAR);
887           mbstowcs(NodeInformation->Name,
888             KeyObject->Name,
889             KeyObject->NameSize * sizeof(WCHAR));
890
891           if (KeyCell->ClassSize != 0)
892             {
893               pClassData = CmiGetBlock(KeyObject->RegistryHive,
894                 KeyCell->ClassNameOffset,
895                 NULL);
896               wcsncpy(NodeInformation->Name + KeyObject->NameSize * sizeof(WCHAR),
897                 (PWCHAR)pClassData->Data,
898                 KeyCell->ClassSize);
899             }
900           *ResultLength = sizeof(KEY_NODE_INFORMATION)
901             + KeyObject->NameSize * sizeof(WCHAR)
902             + KeyCell->ClassSize;
903         }
904       break;
905
906     case KeyFullInformation:
907       /* Check size of buffer */
908       if (Length < sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize)
909         {
910           Status = STATUS_BUFFER_OVERFLOW;
911         }
912       else
913         {
914           /* Fill buffer with requested info */
915           FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
916           FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
917           FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
918           FullInformation->TitleIndex = 0;
919           FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
920           FullInformation->ClassLength = KeyCell->ClassSize;
921           FullInformation->SubKeys = KeyCell->NumberOfSubKeys;
922           FullInformation->MaxNameLen =
923             CmiGetMaxNameLength(RegistryHive, KeyCell);
924           FullInformation->MaxClassLen =
925             CmiGetMaxClassLength(RegistryHive, KeyCell);
926           FullInformation->Values = KeyCell->NumberOfValues;
927           FullInformation->MaxValueNameLen =
928             CmiGetMaxValueNameLength(RegistryHive, KeyCell);
929           FullInformation->MaxValueDataLen = 
930             CmiGetMaxValueDataLength(RegistryHive, KeyCell);
931           if (KeyCell->ClassSize != 0)
932             {
933               pClassData=CmiGetBlock(KeyObject->RegistryHive,
934                 KeyCell->ClassNameOffset,
935                 NULL);
936               wcsncpy(FullInformation->Class,
937                 (PWCHAR)pClassData->Data,
938                 KeyCell->ClassSize);
939             }
940           *ResultLength = sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize;
941         }
942       break;
943     }
944
945   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
946   ObDereferenceObject(KeyObject);
947
948   return(Status);
949 }
950
951
952 NTSTATUS STDCALL
953 NtQueryValueKey(IN HANDLE KeyHandle,
954         IN PUNICODE_STRING ValueName,
955         IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
956         OUT PVOID KeyValueInformation,
957         IN ULONG Length,
958         OUT PULONG ResultLength)
959 {
960   NTSTATUS  Status;
961   PKEY_OBJECT  KeyObject;
962   PREGISTRY_HIVE  RegistryHive;
963   PKEY_CELL  KeyCell;
964   PVALUE_CELL  ValueCell;
965   PDATA_CELL  DataCell;
966   PKEY_VALUE_BASIC_INFORMATION  ValueBasicInformation;
967   PKEY_VALUE_PARTIAL_INFORMATION  ValuePartialInformation;
968   PKEY_VALUE_FULL_INFORMATION  ValueFullInformation;
969
970   DPRINT("NtQueryValueKey(KeyHandle %x  ValueName %S  Length %x)\n",
971     KeyHandle, ValueName->Buffer, Length);
972
973   /* Verify that the handle is valid and is a registry key */
974   Status = ObReferenceObjectByHandle(KeyHandle,
975                 KEY_QUERY_VALUE,
976                 CmiKeyType,
977                 UserMode,
978                 (PVOID *)&KeyObject,
979                 NULL);
980
981   if (!NT_SUCCESS(Status))
982     {
983       DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
984       return Status;
985     }
986
987   /* Acquire hive lock */
988   ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
989
990   VERIFY_KEY_OBJECT(KeyObject);
991
992   /* Get pointer to KeyCell */
993   KeyCell = KeyObject->KeyCell;
994   RegistryHive = KeyObject->RegistryHive;
995
996   /* Get Value block of interest */
997   Status = CmiScanKeyForValue(RegistryHive,
998                               KeyCell,
999                               ValueName,
1000                               &ValueCell,
1001                               NULL);
1002   if (!NT_SUCCESS(Status))
1003     {
1004       DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1005       ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1006       ObDereferenceObject(KeyObject);
1007       return(Status);
1008     }
1009   else if (ValueCell != NULL)
1010     {
1011       switch (KeyValueInformationClass)
1012         {
1013         case KeyValueBasicInformation:
1014           if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1015             {
1016               *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + 
1017                 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1018             }
1019           else
1020             {
1021               *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + 
1022                 ValueCell->NameSize + sizeof(WCHAR);
1023             }
1024           if (Length < *ResultLength)
1025             {
1026               Status = STATUS_BUFFER_TOO_SMALL;
1027             }
1028           else
1029             {
1030               ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION) 
1031                 KeyValueInformation;
1032               ValueBasicInformation->TitleIndex = 0;
1033               ValueBasicInformation->Type = ValueCell->DataType;
1034               if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1035                 {
1036                   ValueBasicInformation->NameLength =
1037                     (ValueCell->NameSize + 1) * sizeof(WCHAR);
1038                   CmiCopyPackedName(ValueBasicInformation->Name,
1039                                     ValueCell->Name,
1040                                     ValueCell->NameSize);
1041                   ValueBasicInformation->Name[ValueCell->NameSize] = 0;
1042                 }
1043               else
1044                 {
1045                   ValueBasicInformation->NameLength =
1046                     ValueCell->NameSize + sizeof(WCHAR);
1047                   RtlCopyMemory(ValueBasicInformation->Name,
1048                                 ValueCell->Name,
1049                                 ValueCell->NameSize * sizeof(WCHAR));
1050                   ValueBasicInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
1051                 }
1052             }
1053           break;
1054
1055         case KeyValuePartialInformation:
1056           *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION)
1057             + (ValueCell->DataSize & LONG_MAX);
1058           if (Length < *ResultLength)
1059             {
1060               Status = STATUS_BUFFER_TOO_SMALL;
1061             }
1062           else
1063             {
1064               ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1065                 KeyValueInformation;
1066               ValuePartialInformation->TitleIndex = 0;
1067               ValuePartialInformation->Type = ValueCell->DataType;
1068               ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1069               if (ValueCell->DataSize > 0)
1070                 {
1071                   DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1072                   RtlCopyMemory(ValuePartialInformation->Data,
1073                     DataCell->Data,
1074                     ValueCell->DataSize & LONG_MAX);
1075                 }
1076               else
1077                 {
1078                   RtlCopyMemory(ValuePartialInformation->Data,
1079                     &ValueCell->DataOffset,
1080                     ValueCell->DataSize & LONG_MAX);
1081                 }
1082             }
1083           break;
1084
1085         case KeyValueFullInformation:
1086           if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1087             {
1088               *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
1089                 (ValueCell->NameSize + 1) * sizeof(WCHAR) +
1090                 (ValueCell->DataSize & LONG_MAX);
1091             }
1092           else
1093             {
1094               *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
1095                 ValueCell->NameSize + sizeof(WCHAR) +
1096                 (ValueCell->DataSize & LONG_MAX);
1097             }
1098           if (Length < *ResultLength)
1099             {
1100               Status = STATUS_BUFFER_TOO_SMALL;
1101             }
1102           else
1103             {
1104               ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1105                 KeyValueInformation;
1106               ValueFullInformation->TitleIndex = 0;
1107               ValueFullInformation->Type = ValueCell->DataType;
1108               if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1109                 {
1110                   ValueFullInformation->NameLength =
1111                     (ValueCell->NameSize + 1) * sizeof(WCHAR);
1112                   CmiCopyPackedName(ValueFullInformation->Name,
1113                                     ValueCell->Name,
1114                                     ValueCell->NameSize);
1115                   ValueFullInformation->Name[ValueCell->NameSize] = 0;
1116                 }
1117               else
1118                 {
1119                   ValueFullInformation->NameLength =
1120                     ValueCell->NameSize + sizeof(WCHAR);
1121                   RtlCopyMemory(ValueFullInformation->Name,
1122                                 ValueCell->Name,
1123                                 ValueCell->NameSize);
1124                   ValueFullInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
1125                 }
1126               ValueFullInformation->DataOffset = 
1127                 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
1128                 ValueFullInformation->NameLength;
1129               ValueFullInformation->DataOffset =
1130                 (ValueFullInformation->DataOffset + 3) & 0xfffffffc;
1131               ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1132               if (ValueCell->DataSize > 0)
1133                 {
1134                   DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1135                   RtlCopyMemory((PCHAR) ValueFullInformation
1136                                 + ValueFullInformation->DataOffset,
1137                                 DataCell->Data,
1138                                 ValueCell->DataSize & LONG_MAX);
1139                 }
1140               else
1141                 {
1142                   RtlCopyMemory((PCHAR) ValueFullInformation
1143                                 + ValueFullInformation->DataOffset,
1144                                 &ValueCell->DataOffset,
1145                   ValueCell->DataSize & LONG_MAX);
1146                 }
1147             }
1148           break;
1149         }
1150     }
1151   else
1152     {
1153       Status = STATUS_OBJECT_NAME_NOT_FOUND;
1154     }
1155
1156   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1157   ObDereferenceObject(KeyObject);
1158
1159   return Status;
1160 }
1161
1162
1163 NTSTATUS STDCALL
1164 NtSetValueKey(IN HANDLE KeyHandle,
1165               IN PUNICODE_STRING ValueName,
1166               IN ULONG TitleIndex,
1167               IN ULONG Type,
1168               IN PVOID Data,
1169               IN ULONG DataSize)
1170 {
1171   NTSTATUS  Status;
1172   PKEY_OBJECT  KeyObject;
1173   PREGISTRY_HIVE  RegistryHive;
1174   PKEY_CELL  KeyCell;
1175   PVALUE_CELL  ValueCell;
1176   BLOCK_OFFSET VBOffset;
1177   PDATA_CELL DataCell;
1178   PDATA_CELL NewDataCell;
1179   PHBIN pBin;
1180   ULONG DesiredAccess;
1181
1182   DPRINT("NtSetValueKey(KeyHandle %x  ValueName '%wZ'  Type %d)\n",
1183          KeyHandle, ValueName, Type);
1184
1185   DesiredAccess = KEY_SET_VALUE;
1186   if (Type == REG_LINK)
1187     DesiredAccess |= KEY_CREATE_LINK;
1188
1189   /* Verify that the handle is valid and is a registry key */
1190   Status = ObReferenceObjectByHandle(KeyHandle,
1191                                      DesiredAccess,
1192                                      CmiKeyType,
1193                                      UserMode,
1194                                      (PVOID *)&KeyObject,
1195                                      NULL);
1196   if (!NT_SUCCESS(Status))
1197     return(Status);
1198
1199   /* Acquire hive lock exclucively */
1200   ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1201
1202   VERIFY_KEY_OBJECT(KeyObject);
1203
1204   /* Get pointer to key cell */
1205   KeyCell = KeyObject->KeyCell;
1206   RegistryHive = KeyObject->RegistryHive;
1207   Status = CmiScanKeyForValue(RegistryHive,
1208                               KeyCell,
1209                               ValueName,
1210                               &ValueCell,
1211                               &VBOffset);
1212   if (!NT_SUCCESS(Status))
1213     {
1214       DPRINT("Value not found. Status 0x%X\n", Status);
1215
1216       ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1217       ObDereferenceObject(KeyObject);
1218       return(Status);
1219     }
1220
1221   if (ValueCell == NULL)
1222     {
1223       DPRINT("Allocate new value cell\n");
1224       Status = CmiAddValueToKey(RegistryHive,
1225                                 KeyCell,
1226                                 ValueName,
1227                                 &ValueCell,
1228                                 &VBOffset);
1229       if (NT_SUCCESS(Status))
1230         {
1231           CmiMarkBlockDirty(RegistryHive, VBOffset);
1232         }
1233     }
1234
1235   if (!NT_SUCCESS(Status))
1236     {
1237       DPRINT("Cannot add value. Status 0x%X\n", Status);
1238
1239       ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1240       ObDereferenceObject(KeyObject);
1241       return(Status);
1242     }
1243
1244   DPRINT("DataSize %lu\n", DataSize);
1245   DPRINT("ValueCell %p\n", ValueCell);
1246   DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1247
1248   if (DataSize <= 4)
1249     {
1250       /* If datasize <= 4 then write in valueblock directly */
1251       DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1252       if ((ValueCell->DataSize >= 0) &&
1253           (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1254         {
1255           CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1256         }
1257
1258       RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize);
1259       ValueCell->DataSize = DataSize | 0x80000000;
1260       ValueCell->DataType = Type;
1261       RtlMoveMemory(&ValueCell->DataOffset, Data, DataSize);
1262       CmiMarkBlockDirty(RegistryHive, VBOffset);
1263     }
1264   else if (DataSize <= (ULONG) (ValueCell->DataSize & 0x7fffffff))
1265     {
1266       /* If new data size is <= current then overwrite current data */
1267       DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset,&pBin);
1268       RtlZeroMemory(DataCell->Data, ValueCell->DataSize);
1269       RtlCopyMemory(DataCell->Data, Data, DataSize);
1270       ValueCell->DataSize = DataSize;
1271       ValueCell->DataType = Type;
1272
1273       /* Update time of heap */
1274       if (!IsVolatileHive(RegistryHive))
1275         {
1276           NtQuerySystemTime((PTIME) &pBin->DateModified);
1277         }
1278       CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
1279     }
1280   else
1281     {
1282       /*
1283        * New data size is larger than the current, destroy current
1284        * data block and allocate a new one.
1285        */
1286       BLOCK_OFFSET NewOffset;
1287
1288       DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1289
1290       if ((ValueCell->DataSize >= 0) &&
1291           (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1292         {
1293           CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1294           ValueCell->DataSize = 0;
1295           ValueCell->DataType = 0;
1296           ValueCell->DataOffset = 0xffffffff;
1297         }
1298
1299       Status = CmiAllocateBlock(RegistryHive,
1300                                 (PVOID *)&NewDataCell,
1301                                 DataSize,
1302                                 &NewOffset);
1303       if (!NT_SUCCESS(Status))
1304         {
1305           DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status);
1306
1307           ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1308           ObDereferenceObject(KeyObject);
1309
1310           return(Status);
1311         }
1312
1313       RtlCopyMemory(&NewDataCell->Data[0], Data, DataSize);
1314       ValueCell->DataSize = DataSize;
1315       ValueCell->DataType = Type;
1316       ValueCell->DataOffset = NewOffset;
1317       CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
1318     }
1319
1320   /* Mark link key */
1321   if ((_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0) &&
1322       (Type == REG_LINK))
1323     {
1324       KeyCell->Type = REG_LINK_KEY_CELL_TYPE;
1325       CmiMarkBlockDirty(RegistryHive, KeyObject->BlockOffset);
1326     }
1327
1328   /* Update time of heap */
1329   if (!IsVolatileHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
1330     {
1331       NtQuerySystemTime((PTIME) &pBin->DateModified);
1332     }
1333
1334   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1335   ObDereferenceObject(KeyObject);
1336
1337   CmiSyncHives();
1338
1339   DPRINT("Return Status 0x%X\n", Status);
1340
1341   return(Status);
1342 }
1343
1344
1345 NTSTATUS STDCALL
1346 NtDeleteValueKey(IN HANDLE KeyHandle,
1347                  IN PUNICODE_STRING ValueName)
1348 {
1349   PKEY_OBJECT KeyObject;
1350   NTSTATUS Status;
1351
1352   /* Verify that the handle is valid and is a registry key */
1353   Status = ObReferenceObjectByHandle(KeyHandle,
1354                 KEY_QUERY_VALUE,
1355                 CmiKeyType,
1356                 UserMode,
1357                 (PVOID *)&KeyObject,
1358                 NULL);
1359   if (!NT_SUCCESS(Status))
1360     {
1361       return Status;
1362     }
1363
1364   /* Acquire hive lock */
1365   ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1366
1367   VERIFY_KEY_OBJECT(KeyObject);
1368
1369   Status = CmiDeleteValueFromKey(KeyObject->RegistryHive,
1370                                  KeyObject->KeyCell,
1371                                  KeyObject->BlockOffset,
1372                                  ValueName);
1373
1374   /* Release hive lock */
1375   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1376
1377   ObDereferenceObject(KeyObject);
1378
1379   CmiSyncHives();
1380
1381   return Status;
1382 }
1383
1384 /*
1385  * NOTE:
1386  * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1387  * KeyObjectAttributes->Name specifies the name of the key to load.
1388  */
1389 NTSTATUS STDCALL
1390 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1391           IN POBJECT_ATTRIBUTES FileObjectAttributes)
1392 {
1393   return NtLoadKey2(KeyObjectAttributes, FileObjectAttributes, 0);
1394 }
1395
1396
1397 /*
1398  * NOTE:
1399  * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1400  * KeyObjectAttributes->Name specifies the name of the key to load.
1401  */
1402 NTSTATUS STDCALL
1403 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1404            IN POBJECT_ATTRIBUTES FileObjectAttributes,
1405            IN ULONG Flags)
1406 {
1407   UNIMPLEMENTED;
1408   return STATUS_NOT_IMPLEMENTED;
1409 }
1410
1411
1412 NTSTATUS STDCALL
1413 NtNotifyChangeKey(
1414         IN      HANDLE  KeyHandle,
1415         IN      HANDLE  Event,
1416         IN      PIO_APC_ROUTINE  ApcRoutine  OPTIONAL,
1417         IN      PVOID  ApcContext  OPTIONAL,
1418         OUT     PIO_STATUS_BLOCK  IoStatusBlock,
1419         IN      ULONG  CompletionFilter,
1420         IN      BOOLEAN  Asynchroneous,
1421         OUT     PVOID  ChangeBuffer,
1422         IN      ULONG  Length,
1423         IN      BOOLEAN  WatchSubtree)
1424 {
1425         UNIMPLEMENTED;
1426 }
1427
1428
1429 NTSTATUS STDCALL
1430 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1431                         IN OUT PKEY_VALUE_ENTRY ValueList,
1432                         IN ULONG NumberOfValues,
1433                         OUT PVOID Buffer,
1434                         IN OUT PULONG Length,
1435                         OUT PULONG ReturnLength)
1436 {
1437   PREGISTRY_HIVE RegistryHive;
1438   PVALUE_CELL ValueCell;
1439   PKEY_OBJECT KeyObject;
1440   PDATA_CELL DataCell;
1441   ULONG BufferLength = 0;
1442   PKEY_CELL KeyCell;
1443   NTSTATUS Status;
1444   PUCHAR DataPtr;
1445   ULONG i;
1446
1447   /* Verify that the handle is valid and is a registry key */
1448   Status = ObReferenceObjectByHandle(KeyHandle,
1449                                      KEY_QUERY_VALUE,
1450                                      CmiKeyType,
1451                                      UserMode,
1452                                      (PVOID *) &KeyObject,
1453                                      NULL);
1454   if (!NT_SUCCESS(Status))
1455     {
1456       DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1457       return(Status);
1458     }
1459
1460   /* Acquire hive lock */
1461   ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1462
1463   VERIFY_KEY_OBJECT(KeyObject);
1464
1465   /* Get pointer to KeyCell */
1466   KeyCell = KeyObject->KeyCell;
1467   RegistryHive = KeyObject->RegistryHive;
1468
1469   DataPtr = (PUCHAR) Buffer;
1470
1471   for (i = 0; i < NumberOfValues; i++)
1472     {
1473       DPRINT("ValueName: '%wZ'\n", ValueList[i].ValueName);
1474
1475       /* Get Value block of interest */
1476       Status = CmiScanKeyForValue(RegistryHive,
1477                           KeyCell,
1478                           ValueList[i].ValueName,
1479                           &ValueCell,
1480                           NULL);
1481
1482       if (!NT_SUCCESS(Status))
1483         {
1484           DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1485           break;
1486         }
1487       else if (ValueCell == NULL)
1488         {
1489           Status = STATUS_OBJECT_NAME_NOT_FOUND;
1490           break;
1491         }
1492
1493       BufferLength = (BufferLength + 3) & 0xfffffffc;
1494
1495       if (BufferLength + (ValueCell->DataSize & LONG_MAX) <= *Length)
1496         {
1497           DataPtr = (PUCHAR)(((ULONG)DataPtr + 3) & 0xfffffffc);
1498
1499           ValueList[i].Type = ValueCell->DataType;
1500           ValueList[i].DataLength = ValueCell->DataSize & LONG_MAX;
1501           ValueList[i].DataOffset = (ULONG) DataPtr - (ULONG) Buffer;
1502
1503           if (ValueCell->DataSize > 0)
1504             {
1505               DataCell = CmiGetBlock(RegistryHive,
1506                                      ValueCell->DataOffset,
1507                                      NULL);
1508               RtlCopyMemory(DataPtr,
1509                             DataCell->Data,
1510                             ValueCell->DataSize & LONG_MAX);
1511             }
1512           else
1513             {
1514               RtlCopyMemory(DataPtr,
1515                             &ValueCell->DataOffset,
1516                             ValueCell->DataSize & LONG_MAX);
1517             }
1518
1519           DataPtr += ValueCell->DataSize & LONG_MAX;
1520         }
1521       else
1522         {
1523           Status = STATUS_BUFFER_TOO_SMALL;
1524         }
1525
1526       BufferLength +=  ValueCell->DataSize & LONG_MAX;
1527     }
1528
1529   if (NT_SUCCESS(Status))
1530     *Length = BufferLength;
1531
1532   *ReturnLength = BufferLength;
1533
1534   /* Release hive lock */
1535   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1536
1537   ObDereferenceObject(KeyObject);
1538
1539   DPRINT("Return Status 0x%X\n", Status);
1540
1541   return(Status);
1542 }
1543
1544
1545 NTSTATUS STDCALL
1546 NtReplaceKey(
1547         IN      POBJECT_ATTRIBUTES      ObjectAttributes,
1548         IN      HANDLE  Key,
1549         IN      POBJECT_ATTRIBUTES      ReplacedObjectAttributes
1550         )
1551 {
1552         UNIMPLEMENTED;
1553 }
1554
1555
1556 NTSTATUS STDCALL
1557 NtRestoreKey(
1558         IN      HANDLE  KeyHandle,
1559         IN      HANDLE  FileHandle,
1560         IN      ULONG   RestoreFlags
1561         )
1562 {
1563         UNIMPLEMENTED;
1564 }
1565
1566
1567 NTSTATUS STDCALL
1568 NtSaveKey(
1569         IN      HANDLE  KeyHandle,
1570         IN      HANDLE  FileHandle)
1571 {
1572         UNIMPLEMENTED;
1573 }
1574
1575
1576 NTSTATUS STDCALL
1577 NtSetInformationKey(
1578         IN      HANDLE  KeyHandle,
1579         IN      CINT    KeyInformationClass,
1580         IN      PVOID    KeyInformation,
1581         IN      ULONG    KeyInformationLength)
1582 {
1583   UNIMPLEMENTED;
1584 }
1585
1586
1587 /*
1588  * NOTE:
1589  * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1590  * KeyObjectAttributes->Name specifies the name of the key to unload.
1591  */
1592 NTSTATUS STDCALL
1593 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
1594 {
1595   UNIMPLEMENTED;
1596 }
1597
1598
1599 NTSTATUS STDCALL
1600 NtInitializeRegistry(IN BOOLEAN SetUpBoot)
1601 {
1602   NTSTATUS Status = STATUS_ACCESS_DENIED;
1603
1604   if (CmiRegistryInitialized == FALSE)
1605     {
1606       /* FIXME: save boot log file */
1607
1608       Status = CmiInitHives(SetUpBoot);
1609
1610       CmiRegistryInitialized = TRUE;
1611     }
1612
1613   return(Status);
1614 }
1615
1616 /* EOF */