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