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