99c18646ec0af1b91c71fcce3b1fa3769c0110f5
[reactos.git] / reactos / ntoskrnl / cm / registry.c
1 /* $Id: registry.c,v 1.24 2000/08/11 08:17:41 jean Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/registry.c
6 * PURPOSE: Registry functions
7 * PROGRAMMERS: Rex Jolliff
8 * Matt Pyne
9 * UPDATE HISTORY:
10 * Created 22/05/98
11 */
12
13 #undef WIN32_LEAN_AND_MEAN
14 #include <defines.h>
15 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
17 #include <wchar.h>
18
19 //#define NDEBUG
20 #include <internal/debug.h>
21
22 #define PROTO_REG 1 /* Comment out to disable */
23
24 /* ----------------------------------------------------- Typedefs */
25
26 #define ULONG_MAX 0x7fffffff
27
28 #define REG_BLOCK_SIZE 4096
29 #define REG_HEAP_BLOCK_DATA_OFFSET 32
30 #define REG_INIT_BLOCK_LIST_SIZE 32
31 #define REG_INIT_HASH_TABLE_SIZE 32
32 #define REG_EXTEND_HASH_TABLE_SIZE 32
33 #define REG_VALUE_LIST_BLOCK_MULTIPLE 32
34 #define REG_KEY_BLOCK_ID 0x6b6e
35 #define REG_HASH_TABLE_BLOCK_ID 0x666c
36 #define REG_VALUE_BLOCK_ID 0x6b76
37 #define REG_KEY_BLOCK_TYPE 0x20
38 #define REG_ROOT_KEY_BLOCK_TYPE 0x2c
39
40 #define REG_ROOT_KEY_NAME L"\\Registry"
41 #define SYSTEM_REG_FILE L"\\SystemDir\\System32\\Config\\SYSTEM.DAT"
42
43
44 // BLOCK_OFFSET = offset in file after header block
45 typedef DWORD BLOCK_OFFSET;
46
47 typedef struct _HEADER_BLOCK
48 {
49 DWORD BlockId;
50 DWORD Unused1;
51 DWORD Unused2;
52 LARGE_INTEGER DateModified;
53 DWORD Unused3;
54 DWORD Unused4;
55 DWORD Unused5;
56 DWORD Unused6;
57 BLOCK_OFFSET RootKeyBlock;
58 DWORD BlockSize;
59 DWORD Unused7;
60 DWORD Unused8[115];
61 DWORD Checksum;
62 } HEADER_BLOCK, *PHEADER_BLOCK;
63
64 typedef struct _HEAP_BLOCK
65 {
66 DWORD BlockId;
67 BLOCK_OFFSET BlockOffset;
68 DWORD BlockSize;
69 } HEAP_BLOCK, *PHEAP_BLOCK;
70
71 // each sub_block begin with this struct :
72 // in a free subblock, higher bit of SubBlockSize is set
73 typedef struct _FREE_SUB_BLOCK
74 {
75 DWORD SubBlockSize;
76 } FREE_SUB_BLOCK, *PFREE_SUB_BLOCK;
77
78 typedef struct _KEY_BLOCK
79 {
80 WORD SubBlockId;
81 WORD Type;
82 LARGE_INTEGER LastWriteTime;
83 DWORD UnUsed1;
84 BLOCK_OFFSET ParentKeyOffset;
85 DWORD NumberOfSubKeys;
86 DWORD UnUsed2;
87 BLOCK_OFFSET HashTableOffset;
88 DWORD UnUsed3;
89 DWORD NumberOfValues;
90 BLOCK_OFFSET ValuesOffset;
91 BLOCK_OFFSET SecurityKeyOffset;
92 BLOCK_OFFSET ClassNameOffset;
93 DWORD Unused4[5];
94 WORD NameSize;
95 WORD ClassSize;
96 WCHAR Name[0];
97 } KEY_BLOCK, *PKEY_BLOCK;
98
99 // hash record :
100 // HashValue=four letters of value's name
101 typedef struct _HASH_RECORD
102 {
103 BLOCK_OFFSET KeyOffset;
104 ULONG HashValue;
105 } HASH_RECORD, *PHASH_RECORD;
106
107 typedef struct _HASH_TABLE_BLOCK
108 {
109 WORD SubBlockId;
110 WORD HashTableSize;
111 HASH_RECORD Table[0];
112 } HASH_TABLE_BLOCK, *PHASH_TABLE_BLOCK;
113
114 typedef struct _VALUE_LIST_BLOCK
115 {
116 BLOCK_OFFSET Values[0];
117 } VALUE_LIST_BLOCK, *PVALUE_LIST_BLOCK;
118
119 typedef struct _VALUE_BLOCK
120 {
121 WORD SubBlockId; // "kv"
122 WORD NameSize; // length of Name
123 DWORD DataSize; // length of datas in the subblock pinted by DataOffset
124 BLOCK_OFFSET DataOffset; // datas are here if DataSize <=4
125 DWORD DataType;
126 WORD Flags;
127 WORD Unused1;
128 WCHAR Name[0];
129 } VALUE_BLOCK, *PVALUE_BLOCK;
130
131 typedef struct _IN_MEMORY_BLOCK
132 {
133 DWORD FileOffset;
134 DWORD BlockSize;
135 PVOID *Data;
136 } IN_MEMORY_BLOCK, *PIN_MEMORY_BLOCK;
137
138 typedef struct _REGISTRY_FILE
139 {
140 PWSTR Filename;
141 HANDLE FileHandle;
142 PHEADER_BLOCK HeaderBlock;
143 ULONG NumberOfBlocks;
144 ULONG BlockListSize;
145 PIN_MEMORY_BLOCK *BlockList;
146
147 NTSTATUS (*Extend)(ULONG NewSize);
148 PVOID (*Flush)(VOID);
149 } REGISTRY_FILE, *PREGISTRY_FILE;
150
151 /* Type defining the Object Manager Key Object */
152 typedef struct _KEY_OBJECT
153 {
154 CSHORT Type;
155 CSHORT Size;
156
157 ULONG Flags;
158 WCHAR *Name;
159 PREGISTRY_FILE RegistryFile;
160 PKEY_BLOCK KeyBlock;
161 struct _KEY_OBJECT *NextKey;
162 } KEY_OBJECT, *PKEY_OBJECT;
163
164 #define KO_MARKED_FOR_DELETE 0x00000001
165
166 /* ------------------------------------------------- File Statics */
167
168 #if PROTO_REG
169 static POBJECT_TYPE CmiKeyType = NULL;
170 static PREGISTRY_FILE CmiVolatileFile = NULL;
171 static PKEY_OBJECT CmiKeyList = NULL;
172 static KSPIN_LOCK CmiKeyListLock;
173 static PREGISTRY_FILE CmiSystemFile = NULL;
174 #endif
175
176 /* ----------------------------------------- Forward Declarations */
177
178 #if PROTO_REG
179 //static PVOID CmiObjectParse(PVOID ParsedObject, PWSTR *Path);
180 static NTSTATUS CmiObjectParse(PVOID ParsedObject,
181 PVOID *NextObject,
182 PUNICODE_STRING FullPath,
183 PWSTR *Path);
184
185 static VOID CmiObjectDelete(PVOID DeletedObject);
186 static NTSTATUS CmiBuildKeyPath(PWSTR *KeyPath,
187 POBJECT_ATTRIBUTES ObjectAttributes);
188 static VOID CmiAddKeyToList(PKEY_OBJECT NewKey);
189 static VOID CmiRemoveKeyFromList(PKEY_OBJECT NewKey);
190 static PKEY_OBJECT CmiScanKeyList(PWSTR KeyNameBuf);
191 static PREGISTRY_FILE CmiCreateRegistry(PWSTR Filename);
192 static NTSTATUS CmiCreateKey(IN PREGISTRY_FILE RegistryFile,
193 IN PWSTR KeyNameBuf,
194 OUT PKEY_BLOCK *KeyBlock,
195 IN ACCESS_MASK DesiredAccess,
196 IN ULONG TitleIndex,
197 IN PUNICODE_STRING Class,
198 IN ULONG CreateOptions,
199 OUT PULONG Disposition);
200 static NTSTATUS CmiFindKey(IN PREGISTRY_FILE RegistryFile,
201 IN PWSTR KeyNameBuf,
202 OUT PKEY_BLOCK *KeyBlock,
203 IN ACCESS_MASK DesiredAccess,
204 IN ULONG TitleIndex,
205 IN PUNICODE_STRING Class);
206 static ULONG CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile,
207 PKEY_BLOCK KeyBlock);
208 static ULONG CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile,
209 PKEY_BLOCK KeyBlock);
210 static ULONG CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile,
211 PKEY_BLOCK KeyBlock);
212 static ULONG CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile,
213 PKEY_BLOCK KeyBlock);
214 static NTSTATUS CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile,
215 IN PKEY_BLOCK KeyBlock,
216 OUT PKEY_BLOCK *SubKeyBlock,
217 IN PWSTR KeyName,
218 IN ACCESS_MASK DesiredAccess);
219 static NTSTATUS CmiAddSubKey(IN PREGISTRY_FILE RegistryFile,
220 IN PKEY_BLOCK CurKeyBlock,
221 OUT PKEY_BLOCK *SubKeyBlock,
222 IN PWSTR NewSubKeyName,
223 IN ULONG TitleIndex,
224 IN PWSTR Class,
225 IN ULONG CreateOptions);
226 static NTSTATUS CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile,
227 IN PKEY_BLOCK KeyBlock,
228 IN PWSTR ValueName,
229 OUT PVALUE_BLOCK *ValueBlock);
230 static NTSTATUS CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile,
231 IN PKEY_BLOCK KeyBlock,
232 IN PWSTR ValueNameBuf,
233 IN ULONG Type,
234 IN PVOID Data,
235 IN ULONG DataSize);
236 static NTSTATUS CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile,
237 IN PKEY_BLOCK KeyBlock,
238 IN PWSTR ValueName);
239 static NTSTATUS CmiAllocateKeyBlock(IN PREGISTRY_FILE RegistryFile,
240 OUT PKEY_BLOCK *KeyBlock,
241 IN PWSTR NewSubKeyName,
242 IN ULONG TitleIndex,
243 IN PWSTR Class,
244 IN ULONG CreateOptions);
245 static PKEY_BLOCK CmiGetKeyBlock(PREGISTRY_FILE RegistryFile,
246 BLOCK_OFFSET KeyBlockOffset);
247 static NTSTATUS CmiDestroyKeyBlock(PREGISTRY_FILE RegistryFile,
248 PKEY_BLOCK KeyBlock);
249 static NTSTATUS CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile,
250 OUT PHASH_TABLE_BLOCK *HashBlock,
251 IN ULONG HashTableSize);
252 static PHASH_TABLE_BLOCK CmiGetHashTableBlock(PREGISTRY_FILE RegistryFile,
253 BLOCK_OFFSET HashBlockOffset);
254 static PKEY_BLOCK CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile,
255 PHASH_TABLE_BLOCK HashBlock,
256 ULONG Index);
257 static NTSTATUS CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile,
258 PHASH_TABLE_BLOCK HashBlock,
259 PKEY_BLOCK NewKeyBlock);
260 static NTSTATUS CmiDestroyHashTableBlock(PREGISTRY_FILE RegistryFile,
261 PHASH_TABLE_BLOCK HashBlock);
262 static NTSTATUS CmiAllocateValueBlock(IN PREGISTRY_FILE RegistryFile,
263 OUT PVALUE_BLOCK *ValueBlock,
264 IN PWSTR ValueNameBuf,
265 IN ULONG Type,
266 IN PVOID Data,
267 IN ULONG DataSize);
268 static NTSTATUS CmiReplaceValueData(IN PREGISTRY_FILE RegistryFile,
269 IN PVALUE_BLOCK ValueBlock,
270 IN ULONG Type,
271 IN PVOID Data,
272 IN ULONG DataSize);
273 static NTSTATUS CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile,
274 PVALUE_BLOCK ValueBlock);
275 static NTSTATUS CmiAllocateBlock(PREGISTRY_FILE RegistryFile,
276 PVOID *Block,
277 ULONG BlockSize);
278 static NTSTATUS CmiDestroyBlock(PREGISTRY_FILE RegistryFile,
279 PVOID Block);
280 static PVOID CmiGetBlock(PREGISTRY_FILE RegistryFile,
281 BLOCK_OFFSET BlockOffset);
282 static BLOCK_OFFSET CmiGetBlockOffset(PREGISTRY_FILE RegistryFile,
283 PVOID Block);
284 static VOID CmiLockBlock(PREGISTRY_FILE RegistryFile,
285 PVOID Block);
286 static VOID CmiReleaseBlock(PREGISTRY_FILE RegistryFile,
287 PVOID Block);
288
289 #endif
290
291 /* --------------------------------------------- Public Interface */
292
293 VOID
294 CmInitializeRegistry(VOID)
295 {
296 #if PROTO_REG
297 NTSTATUS Status;
298 HANDLE RootKeyHandle;
299 UNICODE_STRING RootKeyName;
300 OBJECT_ATTRIBUTES ObjectAttributes;
301 PKEY_BLOCK KeyBlock;
302
303 /* Initialize the Key object type */
304 CmiKeyType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
305 CmiKeyType->TotalObjects = 0;
306 CmiKeyType->TotalHandles = 0;
307 CmiKeyType->MaxObjects = ULONG_MAX;
308 CmiKeyType->MaxHandles = ULONG_MAX;
309 CmiKeyType->PagedPoolCharge = 0;
310 CmiKeyType->NonpagedPoolCharge = sizeof(KEY_OBJECT);
311 CmiKeyType->Dump = NULL;
312 CmiKeyType->Open = NULL;
313 CmiKeyType->Close = NULL;
314 CmiKeyType->Delete = CmiObjectDelete;
315 CmiKeyType->Parse = CmiObjectParse;
316 CmiKeyType->Security = NULL;
317 CmiKeyType->QueryName = NULL;
318 CmiKeyType->OkayToClose = NULL;
319 RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
320
321 /* Build the Root Key Object */
322 /* FIXME: This should be split into two objects, 1 system and 1 user */
323 RtlInitUnicodeString(&RootKeyName, REG_ROOT_KEY_NAME);
324 InitializeObjectAttributes(&ObjectAttributes, &RootKeyName, 0, NULL, NULL);
325 ObCreateObject(&RootKeyHandle,
326 STANDARD_RIGHTS_REQUIRED,
327 &ObjectAttributes,
328 CmiKeyType);
329
330 KeInitializeSpinLock(&CmiKeyListLock);
331
332 /* Build volitile registry store */
333 CHECKPOINT;
334 CmiVolatileFile = CmiCreateRegistry(NULL);
335
336 /* Build system registry store */
337 CHECKPOINT;
338 CmiSystemFile = NULL; // CmiCreateRegistry(SYSTEM_REG_FILE);
339
340 /* Create initial predefined symbolic links */
341 /* HKEY_LOCAL_MACHINE */
342 CHECKPOINT;
343 Status = CmiCreateKey(CmiVolatileFile,
344 L"Machine",
345 &KeyBlock,
346 KEY_ALL_ACCESS,
347 0,
348 NULL,
349 REG_OPTION_VOLATILE,
350 0);
351 if (!NT_SUCCESS(Status))
352 {
353 return;
354 }
355 CHECKPOINT;
356 CmiReleaseBlock(CmiVolatileFile, KeyBlock);
357
358 /* HKEY_USERS */
359 CHECKPOINT;
360 Status = CmiCreateKey(CmiVolatileFile,
361 L"Users",
362 &KeyBlock,
363 KEY_ALL_ACCESS,
364 0,
365 NULL,
366 REG_OPTION_VOLATILE,
367 0);
368 if (!NT_SUCCESS(Status))
369 {
370 return;
371 }
372 CHECKPOINT;
373 CmiReleaseBlock(CmiVolatileFile, KeyBlock);
374
375 /* FIXME: create remaining structure needed for default handles */
376 /* FIXME: load volatile registry data from ROSDTECT */
377
378 #endif
379 }
380
381 VOID
382 CmImportHive(PCHAR Chunk)
383 {
384 /* FIXME: implemement this */
385 return;
386 }
387
388 NTSTATUS
389 STDCALL
390 NtCreateKey (
391 OUT PHANDLE KeyHandle,
392 IN ACCESS_MASK DesiredAccess,
393 IN POBJECT_ATTRIBUTES ObjectAttributes,
394 IN ULONG TitleIndex,
395 IN PUNICODE_STRING Class,
396 IN ULONG CreateOptions,
397 OUT PULONG Disposition
398 )
399 {
400 #if PROTO_REG
401 PWSTR KeyNameBuf;
402 NTSTATUS Status;
403 PKEY_OBJECT CurKey, NewKey;
404 PREGISTRY_FILE FileToUse;
405 PKEY_BLOCK KeyBlock;
406
407 assert(ObjectAttributes != NULL);
408
409 FileToUse = (CreateOptions & REG_OPTION_VOLATILE) ?
410 CmiVolatileFile : CmiSystemFile;
411
412 /* Construct the complete registry relative pathname */
413 Status = CmiBuildKeyPath(&KeyNameBuf, ObjectAttributes);
414 if (!NT_SUCCESS(Status))
415 {
416 return Status;
417 }
418
419 /* Scan the key list to see if key already open */
420 CurKey = CmiScanKeyList(KeyNameBuf);
421 if (CurKey != NULL)
422 {
423 /* Unmark the key if the key has been marked for Delete */
424 if (CurKey->Flags & KO_MARKED_FOR_DELETE)
425 {
426 CurKey->Flags &= ~KO_MARKED_FOR_DELETE;
427 }
428
429 /* If so, return a reference to it */
430 Status = ObCreateHandle(PsGetCurrentProcess(),
431 CurKey,
432 DesiredAccess,
433 FALSE,
434 KeyHandle);
435 ExFreePool(KeyNameBuf);
436
437 return Status;
438 }
439
440 /* Create or open the key in the registry file */
441 Status = CmiCreateKey(FileToUse,
442 KeyNameBuf,
443 &KeyBlock,
444 DesiredAccess,
445 TitleIndex,
446 Class,
447 CreateOptions,
448 Disposition);
449 if (!NT_SUCCESS(Status))
450 {
451 ExFreePool(KeyNameBuf);
452
453 return Status;
454 }
455
456 /* Create new key object and put into linked list */
457 NewKey = ObCreateObject(KeyHandle,
458 DesiredAccess,
459 NULL,
460 CmiKeyType);
461 if (NewKey == NULL)
462 {
463 return STATUS_UNSUCCESSFUL;
464 }
465 NewKey->Flags = 0;
466 NewKey->Name = KeyNameBuf;
467 NewKey->KeyBlock = KeyBlock;
468 NewKey->RegistryFile = FileToUse;
469 CmiAddKeyToList(NewKey);
470 Status = ObCreateHandle(PsGetCurrentProcess(),
471 CurKey,
472 DesiredAccess,
473 FALSE,
474 KeyHandle);
475
476 return Status;
477 #else
478 UNIMPLEMENTED;
479 #endif
480 }
481
482
483 NTSTATUS
484 STDCALL
485 NtDeleteKey (
486 IN HANDLE KeyHandle
487 )
488 {
489 #ifdef PROTO_REG
490 NTSTATUS Status;
491 PKEY_OBJECT KeyObject;
492
493 /* Verify that the handle is valid and is a registry key */
494 Status = ObReferenceObjectByHandle(KeyHandle,
495 KEY_WRITE,
496 CmiKeyType,
497 UserMode,
498 (PVOID *)&KeyObject,
499 NULL);
500 if (!NT_SUCCESS(Status))
501 {
502 return Status;
503 }
504
505 /* Set the marked for delete bit in the key object */
506 KeyObject->Flags |= KO_MARKED_FOR_DELETE;
507
508 /* Dereference the object */
509 ObDeleteHandle(PsGetCurrentProcess(),KeyHandle);
510 /* FIXME: I think that ObDeleteHandle should dereference the object */
511 ObDereferenceObject(KeyObject);
512
513 return STATUS_SUCCESS;
514 #else
515 UNIMPLEMENTED;
516 #endif
517 }
518
519
520 NTSTATUS
521 STDCALL
522 NtEnumerateKey (
523 IN HANDLE KeyHandle,
524 IN ULONG Index,
525 IN KEY_INFORMATION_CLASS KeyInformationClass,
526 OUT PVOID KeyInformation,
527 IN ULONG Length,
528 OUT PULONG ResultLength
529 )
530 {
531 #ifdef PROTO_REG
532 NTSTATUS Status;
533 PKEY_OBJECT KeyObject;
534 PREGISTRY_FILE RegistryFile;
535 PKEY_BLOCK KeyBlock, SubKeyBlock;
536 PHASH_TABLE_BLOCK HashTableBlock;
537 PKEY_BASIC_INFORMATION BasicInformation;
538 PKEY_NODE_INFORMATION NodeInformation;
539 PKEY_FULL_INFORMATION FullInformation;
540
541 /* Verify that the handle is valid and is a registry key */
542 Status = ObReferenceObjectByHandle(KeyHandle,
543 KEY_ENUMERATE_SUB_KEYS,
544 CmiKeyType,
545 UserMode,
546 (PVOID *)&KeyObject,
547 NULL);
548 if (!NT_SUCCESS(Status))
549 {
550 return Status;
551 }
552
553 /* Get pointer to KeyBlock */
554 KeyBlock = KeyObject->KeyBlock;
555 RegistryFile = KeyObject->RegistryFile;
556
557 /* Get pointer to SubKey */
558 HashTableBlock = CmiGetHashTableBlock(RegistryFile, KeyBlock->HashTableOffset);
559 SubKeyBlock = CmiGetKeyFromHashByIndex(RegistryFile,
560 HashTableBlock,
561 Index);
562 if (SubKeyBlock == NULL)
563 {
564 return STATUS_NO_MORE_ENTRIES;
565 }
566
567 Status = STATUS_SUCCESS;
568 switch (KeyInformationClass)
569 {
570 case KeyBasicInformation:
571 /* Check size of buffer */
572 if (Length < sizeof(KEY_BASIC_INFORMATION) +
573 SubKeyBlock->NameSize * sizeof(WCHAR))
574 {
575 Status = STATUS_BUFFER_OVERFLOW;
576 }
577 else
578 {
579 /* Fill buffer with requested info */
580 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
581 BasicInformation->LastWriteTime = SubKeyBlock->LastWriteTime;
582 BasicInformation->TitleIndex = Index;
583 BasicInformation->NameLength = SubKeyBlock->NameSize;
584 wcsncpy(BasicInformation->Name,
585 SubKeyBlock->Name,
586 SubKeyBlock->NameSize);
587 BasicInformation->Name[SubKeyBlock->NameSize] = 0;
588 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
589 SubKeyBlock->NameSize * sizeof(WCHAR);
590 }
591 break;
592
593 case KeyNodeInformation:
594 /* Check size of buffer */
595 if (Length < sizeof(KEY_NODE_INFORMATION) +
596 SubKeyBlock->NameSize * sizeof(WCHAR) +
597 (SubKeyBlock->ClassSize + 1) * sizeof(WCHAR))
598 {
599 Status = STATUS_BUFFER_OVERFLOW;
600 }
601 else
602 {
603 /* Fill buffer with requested info */
604 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
605 NodeInformation->LastWriteTime = SubKeyBlock->LastWriteTime;
606 NodeInformation->TitleIndex = Index;
607 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
608 SubKeyBlock->NameSize * sizeof(WCHAR);
609 NodeInformation->ClassLength = SubKeyBlock->ClassSize;
610 NodeInformation->NameLength = SubKeyBlock->NameSize;
611 wcsncpy(NodeInformation->Name,
612 SubKeyBlock->Name,
613 SubKeyBlock->NameSize);
614 NodeInformation->Name[SubKeyBlock->NameSize] = 0;
615 if (SubKeyBlock->ClassSize != 0)
616 {
617 wcsncpy(NodeInformation->Name + SubKeyBlock->NameSize + 1,
618 &SubKeyBlock->Name[SubKeyBlock->NameSize + 1],
619 SubKeyBlock->ClassSize);
620 NodeInformation->
621 Name[SubKeyBlock->NameSize + 1 + SubKeyBlock->ClassSize] = 0;
622 }
623 *ResultLength = sizeof(KEY_NODE_INFORMATION) +
624 SubKeyBlock->NameSize * sizeof(WCHAR) +
625 (SubKeyBlock->ClassSize + 1) * sizeof(WCHAR);
626 }
627 break;
628
629 case KeyFullInformation:
630 /* FIXME: check size of buffer */
631 if (Length < sizeof(KEY_FULL_INFORMATION) +
632 SubKeyBlock->ClassSize * sizeof(WCHAR))
633 {
634 Status = STATUS_BUFFER_OVERFLOW;
635 }
636 else
637 {
638 /* FIXME: fill buffer with requested info */
639 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
640 FullInformation->LastWriteTime = SubKeyBlock->LastWriteTime;
641 FullInformation->TitleIndex = Index;
642 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) -
643 sizeof(WCHAR);
644 FullInformation->ClassLength = SubKeyBlock->ClassSize;
645 FullInformation->SubKeys = SubKeyBlock->NumberOfSubKeys;
646 FullInformation->MaxNameLen =
647 CmiGetMaxNameLength(RegistryFile, SubKeyBlock);
648 FullInformation->MaxClassLen =
649 CmiGetMaxClassLength(RegistryFile, SubKeyBlock);
650 FullInformation->Values = SubKeyBlock->NumberOfValues;
651 FullInformation->MaxValueNameLen =
652 CmiGetMaxValueNameLength(RegistryFile, SubKeyBlock);
653 FullInformation->MaxValueDataLen =
654 CmiGetMaxValueDataLength(RegistryFile, SubKeyBlock);
655 wcsncpy(FullInformation->Class,
656 &SubKeyBlock->Name[SubKeyBlock->NameSize + 1],
657 SubKeyBlock->ClassSize);
658 FullInformation->Class[SubKeyBlock->ClassSize] = 0;
659 *ResultLength = sizeof(KEY_FULL_INFORMATION) +
660 SubKeyBlock->ClassSize * sizeof(WCHAR);
661 }
662 break;
663 }
664 CmiReleaseBlock(RegistryFile, SubKeyBlock);
665
666 return Status;
667 #else
668 UNIMPLEMENTED;
669 #endif
670 }
671
672
673 NTSTATUS
674 STDCALL
675 NtEnumerateValueKey (
676 IN HANDLE KeyHandle,
677 IN ULONG Index,
678 IN KEY_VALUE_INFORMATION_CLASS KeyInformationClass,
679 OUT PVOID KeyInformation,
680 IN ULONG Length,
681 OUT PULONG ResultLength
682 )
683 {
684 #ifdef PROTO_REG
685 UNIMPLEMENTED;
686 #else
687 UNIMPLEMENTED;
688 #endif
689 }
690
691
692 NTSTATUS
693 STDCALL
694 NtFlushKey (
695 IN HANDLE KeyHandle
696 )
697 {
698 #ifdef PROTO_REG
699 return STATUS_SUCCESS;
700 #else
701 UNIMPLEMENTED;
702 #endif
703 }
704
705
706 NTSTATUS
707 STDCALL
708 NtOpenKey (
709 OUT PHANDLE KeyHandle,
710 IN ACCESS_MASK DesiredAccess,
711 IN POBJECT_ATTRIBUTES ObjectAttributes
712 )
713 {
714 #ifdef PROTO_REG
715 NTSTATUS Status;
716 PWSTR KeyNameBuf;
717 PREGISTRY_FILE FileToUse;
718 PKEY_BLOCK KeyBlock;
719 PKEY_OBJECT CurKey, NewKey;
720
721 /* Construct the complete registry relative pathname */
722 Status = CmiBuildKeyPath(&KeyNameBuf, ObjectAttributes);
723 if (!NT_SUCCESS(Status))
724 {
725 return Status;
726 }
727
728 /* Scan the key list to see if key already open */
729 CurKey = CmiScanKeyList(KeyNameBuf);
730 if (CurKey != NULL)
731 {
732 /* Fail if the key has been deleted */
733 if (CurKey->Flags & KO_MARKED_FOR_DELETE)
734 {
735 ExFreePool(KeyNameBuf);
736
737 return STATUS_UNSUCCESSFUL;
738 }
739
740 /* If so, return a reference to it */
741 Status = ObCreateHandle(PsGetCurrentProcess(),
742 CurKey,
743 DesiredAccess,
744 FALSE,
745 KeyHandle);
746 ExFreePool(KeyNameBuf);
747
748 return Status;
749 }
750
751 /* Open the key in the registry file */
752 FileToUse = CmiSystemFile;
753 Status = CmiFindKey(FileToUse,
754 KeyNameBuf,
755 &KeyBlock,
756 DesiredAccess,
757 0,
758 NULL);
759 if (!NT_SUCCESS(Status))
760 {
761 FileToUse = CmiVolatileFile;
762 Status = CmiFindKey(FileToUse,
763 KeyNameBuf,
764 &KeyBlock,
765 DesiredAccess,
766 0,
767 NULL);
768 if (!NT_SUCCESS(Status))
769 {
770 ExFreePool(KeyNameBuf);
771
772 return Status;
773 }
774 }
775
776 /* Create new key object and put into linked list */
777 NewKey = ObCreateObject(KeyHandle,
778 DesiredAccess,
779 NULL,
780 CmiKeyType);
781 if (NewKey == NULL)
782 {
783 return STATUS_UNSUCCESSFUL;
784 }
785 NewKey->Flags = 0;
786 NewKey->Name = KeyNameBuf;
787 NewKey->RegistryFile = FileToUse;
788 NewKey->KeyBlock = KeyBlock;
789 CmiAddKeyToList(NewKey);
790 Status = ObCreateHandle(PsGetCurrentProcess(),
791 CurKey,
792 DesiredAccess,
793 FALSE,
794 KeyHandle);
795
796 return Status;
797 #else
798 UNIMPLEMENTED;
799 #endif
800 }
801
802
803 NTSTATUS
804 STDCALL
805 NtQueryKey (
806 IN HANDLE KeyHandle,
807 IN KEY_INFORMATION_CLASS KeyInformationClass,
808 OUT PVOID KeyInformation,
809 IN ULONG Length,
810 OUT PULONG ResultLength
811 )
812 {
813 #ifdef PROTO_REG
814 NTSTATUS Status;
815 PKEY_OBJECT KeyObject;
816 PREGISTRY_FILE RegistryFile;
817 PKEY_BLOCK KeyBlock;
818 PKEY_BASIC_INFORMATION BasicInformation;
819 PKEY_NODE_INFORMATION NodeInformation;
820 PKEY_FULL_INFORMATION FullInformation;
821
822 /* Verify that the handle is valid and is a registry key */
823 Status = ObReferenceObjectByHandle(KeyHandle,
824 KEY_READ,
825 CmiKeyType,
826 UserMode,
827 (PVOID *)&KeyObject,
828 NULL);
829 if (!NT_SUCCESS(Status))
830 {
831 return Status;
832 }
833
834 /* Get pointer to KeyBlock */
835 KeyBlock = KeyObject->KeyBlock;
836 RegistryFile = KeyObject->RegistryFile;
837
838 Status = STATUS_SUCCESS;
839 switch (KeyInformationClass)
840 {
841 case KeyBasicInformation:
842 /* Check size of buffer */
843 if (Length < sizeof(KEY_BASIC_INFORMATION) +
844 KeyBlock->NameSize * sizeof(WCHAR))
845 {
846 Status = STATUS_BUFFER_OVERFLOW;
847 }
848 else
849 {
850 /* Fill buffer with requested info */
851 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
852 BasicInformation->LastWriteTime = KeyBlock->LastWriteTime;
853 BasicInformation->TitleIndex = 0;
854 BasicInformation->NameLength = KeyBlock->NameSize;
855 wcsncpy(BasicInformation->Name,
856 KeyBlock->Name,
857 KeyBlock->NameSize);
858 BasicInformation->Name[KeyBlock->NameSize] = 0;
859 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
860 KeyBlock->NameSize * sizeof(WCHAR);
861 }
862 break;
863
864 case KeyNodeInformation:
865 /* Check size of buffer */
866 if (Length < sizeof(KEY_NODE_INFORMATION) +
867 KeyBlock->NameSize * sizeof(WCHAR) +
868 (KeyBlock->ClassSize + 1) * sizeof(WCHAR))
869 {
870 Status = STATUS_BUFFER_OVERFLOW;
871 }
872 else
873 {
874 /* Fill buffer with requested info */
875 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
876 NodeInformation->LastWriteTime = KeyBlock->LastWriteTime;
877 NodeInformation->TitleIndex = 0;
878 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
879 KeyBlock->NameSize * sizeof(WCHAR);
880 NodeInformation->ClassLength = KeyBlock->ClassSize;
881 NodeInformation->NameLength = KeyBlock->NameSize;
882 wcsncpy(NodeInformation->Name,
883 KeyBlock->Name,
884 KeyBlock->NameSize);
885 NodeInformation->Name[KeyBlock->NameSize] = 0;
886 if (KeyBlock->ClassSize != 0)
887 {
888 wcsncpy(NodeInformation->Name + KeyBlock->NameSize + 1,
889 &KeyBlock->Name[KeyBlock->NameSize + 1],
890 KeyBlock->ClassSize);
891 NodeInformation->
892 Name[KeyBlock->NameSize + 1 + KeyBlock->ClassSize] = 0;
893 }
894 *ResultLength = sizeof(KEY_NODE_INFORMATION) +
895 KeyBlock->NameSize * sizeof(WCHAR) +
896 (KeyBlock->ClassSize + 1) * sizeof(WCHAR);
897 }
898 break;
899
900 case KeyFullInformation:
901 /* Check size of buffer */
902 if (Length < sizeof(KEY_FULL_INFORMATION) +
903 KeyBlock->ClassSize * sizeof(WCHAR))
904 {
905 Status = STATUS_BUFFER_OVERFLOW;
906 }
907 else
908 {
909 /* Fill buffer with requested info */
910 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
911 FullInformation->LastWriteTime = KeyBlock->LastWriteTime;
912 FullInformation->TitleIndex = 0;
913 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) -
914 sizeof(WCHAR);
915 FullInformation->ClassLength = KeyBlock->ClassSize;
916 FullInformation->SubKeys = KeyBlock->NumberOfSubKeys;
917 FullInformation->MaxNameLen =
918 CmiGetMaxNameLength(RegistryFile, KeyBlock);
919 FullInformation->MaxClassLen =
920 CmiGetMaxClassLength(RegistryFile, KeyBlock);
921 FullInformation->Values = KeyBlock->NumberOfValues;
922 FullInformation->MaxValueNameLen =
923 CmiGetMaxValueNameLength(RegistryFile, KeyBlock);
924 FullInformation->MaxValueDataLen =
925 CmiGetMaxValueDataLength(RegistryFile, KeyBlock);
926 wcsncpy(FullInformation->Class,
927 &KeyBlock->Name[KeyBlock->NameSize + 1],
928 KeyBlock->ClassSize);
929 FullInformation->Class[KeyBlock->ClassSize] = 0;
930 *ResultLength = sizeof(KEY_FULL_INFORMATION) +
931 KeyBlock->ClassSize * sizeof(WCHAR);
932 }
933 break;
934 }
935
936 return Status;
937 #else
938 UNIMPLEMENTED;
939 #endif
940 }
941
942
943 NTSTATUS
944 STDCALL
945 NtQueryValueKey (
946 IN HANDLE KeyHandle,
947 IN PUNICODE_STRING ValueName,
948 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
949 OUT PVOID KeyValueInformation,
950 IN ULONG Length,
951 OUT PULONG ResultLength
952 )
953 {
954 #ifdef PROTO_REG
955 NTSTATUS Status;
956 PKEY_OBJECT KeyObject;
957 PREGISTRY_FILE RegistryFile;
958 PKEY_BLOCK KeyBlock;
959 PVALUE_BLOCK ValueBlock;
960 PVOID DataBlock;
961 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
962 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
963 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
964
965 /* Verify that the handle is valid and is a registry key */
966 Status = ObReferenceObjectByHandle(KeyHandle,
967 KEY_QUERY_VALUE,
968 CmiKeyType,
969 UserMode,
970 (PVOID *)&KeyObject,
971 NULL);
972 if (!NT_SUCCESS(Status))
973 {
974 return Status;
975 }
976
977 /* Get pointer to KeyBlock */
978 KeyBlock = KeyObject->KeyBlock;
979 RegistryFile = KeyObject->RegistryFile;
980
981 /* Get Value block of interest */
982 Status = CmiScanKeyForValue(RegistryFile,
983 KeyBlock,
984 ValueName->Buffer,
985 &ValueBlock);
986 if (!NT_SUCCESS(Status))
987 {
988 return Status;
989 }
990 else if (ValueBlock != NULL)
991 {
992 switch (KeyValueInformationClass)
993 {
994 case KeyValueBasicInformation:
995 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
996 ValueBlock->NameSize * sizeof(WCHAR);
997 if (Length < *ResultLength)
998 {
999 Status = STATUS_BUFFER_OVERFLOW;
1000 }
1001 else
1002 {
1003 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1004 KeyValueInformation;
1005 ValueBasicInformation->TitleIndex = 0;
1006 ValueBasicInformation->Type = ValueBlock->DataType;
1007 ValueBasicInformation->NameLength = ValueBlock->NameSize;
1008 wcscpy(ValueBasicInformation->Name, ValueBlock->Name);
1009 }
1010 break;
1011
1012 case KeyValuePartialInformation:
1013 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
1014 ValueBlock->DataSize;
1015 if (Length < *ResultLength)
1016 {
1017 Status = STATUS_BUFFER_OVERFLOW;
1018 }
1019 else
1020 {
1021 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1022 KeyValueInformation;
1023 ValuePartialInformation->TitleIndex = 0;
1024 ValuePartialInformation->Type = ValueBlock->DataType;
1025 ValuePartialInformation->DataLength = ValueBlock->DataSize;
1026 DataBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset);
1027 RtlCopyMemory(ValuePartialInformation->Data,
1028 DataBlock,
1029 ValueBlock->DataSize);
1030 CmiReleaseBlock(RegistryFile, DataBlock);
1031 }
1032 break;
1033
1034 case KeyValueFullInformation:
1035 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
1036 ValueBlock->NameSize * sizeof(WCHAR) + ValueBlock->DataSize;
1037 if (Length < *ResultLength)
1038 {
1039 Status = STATUS_BUFFER_OVERFLOW;
1040 }
1041 else
1042 {
1043 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1044 KeyValueInformation;
1045 ValueFullInformation->TitleIndex = 0;
1046 ValueFullInformation->Type = ValueBlock->DataType;
1047 ValueFullInformation->DataOffset =
1048 sizeof(KEY_VALUE_FULL_INFORMATION) +
1049 ValueBlock->NameSize * sizeof(WCHAR);
1050 ValueFullInformation->DataLength = ValueBlock->DataSize;
1051 ValueFullInformation->NameLength = ValueBlock->NameSize;
1052 wcscpy(ValueFullInformation->Name, ValueBlock->Name);
1053 DataBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset);
1054 RtlCopyMemory(&ValueFullInformation->Name[ValueBlock->NameSize + 1],
1055 DataBlock,
1056 ValueBlock->DataSize);
1057 CmiReleaseBlock(RegistryFile, DataBlock);
1058 }
1059 break;
1060 }
1061 }
1062 else
1063 {
1064 Status = STATUS_UNSUCCESSFUL;
1065 }
1066
1067 return Status;
1068 #else
1069 UNIMPLEMENTED;
1070 #endif
1071 }
1072
1073
1074 NTSTATUS
1075 STDCALL
1076 NtSetValueKey (
1077 IN HANDLE KeyHandle,
1078 IN PUNICODE_STRING ValueName,
1079 IN ULONG TitleIndex,
1080 IN ULONG Type,
1081 IN PVOID Data,
1082 IN ULONG DataSize
1083 )
1084 {
1085 #ifdef PROTO_REG
1086 NTSTATUS Status;
1087 PKEY_OBJECT KeyObject;
1088 PREGISTRY_FILE RegistryFile;
1089 PKEY_BLOCK KeyBlock;
1090 PVALUE_BLOCK ValueBlock;
1091
1092 /* Verify that the handle is valid and is a registry key */
1093 Status = ObReferenceObjectByHandle(KeyHandle,
1094 KEY_QUERY_VALUE,
1095 CmiKeyType,
1096 UserMode,
1097 (PVOID *)&KeyObject,
1098 NULL);
1099 if (!NT_SUCCESS(Status))
1100 {
1101 return Status;
1102 }
1103
1104 /* Get pointer to KeyBlock */
1105 KeyBlock = KeyObject->KeyBlock;
1106 RegistryFile = KeyObject->RegistryFile;
1107 Status = CmiScanKeyForValue(RegistryFile,
1108 KeyBlock,
1109 ValueName->Buffer,
1110 &ValueBlock);
1111 if (!NT_SUCCESS(Status))
1112 {
1113 return Status;
1114 }
1115 if (ValueBlock == NULL)
1116 {
1117 Status = CmiAddValueToKey(RegistryFile,
1118 KeyBlock,
1119 ValueName->Buffer,
1120 Type,
1121 Data,
1122 DataSize);
1123 }
1124 else
1125 {
1126 Status = CmiReplaceValueData(RegistryFile,
1127 ValueBlock,
1128 Type,
1129 Data,
1130 DataSize);
1131 }
1132
1133 return Status;
1134 #else
1135 UNIMPLEMENTED;
1136 #endif
1137 }
1138
1139 NTSTATUS
1140 STDCALL
1141 NtDeleteValueKey (
1142 IN HANDLE KeyHandle,
1143 IN PUNICODE_STRING ValueName
1144 )
1145 {
1146 #ifdef PROTO_REG
1147 NTSTATUS Status;
1148 PKEY_OBJECT KeyObject;
1149 PREGISTRY_FILE RegistryFile;
1150 PKEY_BLOCK KeyBlock;
1151
1152 /* Verify that the handle is valid and is a registry key */
1153 Status = ObReferenceObjectByHandle(KeyHandle,
1154 KEY_QUERY_VALUE,
1155 CmiKeyType,
1156 UserMode,
1157 (PVOID *)&KeyObject,
1158 NULL);
1159 if (!NT_SUCCESS(Status))
1160 {
1161 return Status;
1162 }
1163
1164 /* Get pointer to KeyBlock */
1165 KeyBlock = KeyObject->KeyBlock;
1166 RegistryFile = KeyObject->RegistryFile;
1167 Status = CmiDeleteValueFromKey(RegistryFile,
1168 KeyBlock,
1169 ValueName->Buffer);
1170
1171 return Status;
1172 #else
1173 UNIMPLEMENTED;
1174 #endif
1175 }
1176
1177 NTSTATUS
1178 STDCALL
1179 NtLoadKey (
1180 PHANDLE KeyHandle,
1181 OBJECT_ATTRIBUTES ObjectAttributes
1182 )
1183 {
1184 UNIMPLEMENTED;
1185 }
1186
1187
1188 NTSTATUS
1189 STDCALL
1190 NtLoadKey2(VOID)
1191 {
1192 UNIMPLEMENTED;
1193 }
1194
1195
1196 NTSTATUS
1197 STDCALL
1198 NtNotifyChangeKey (
1199 IN HANDLE KeyHandle,
1200 IN HANDLE Event,
1201 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1202 IN PVOID ApcContext OPTIONAL,
1203 OUT PIO_STATUS_BLOCK IoStatusBlock,
1204 IN ULONG CompletionFilter,
1205 IN BOOLEAN Asynchroneous,
1206 OUT PVOID ChangeBuffer,
1207 IN ULONG Length,
1208 IN BOOLEAN WatchSubtree
1209 )
1210 {
1211 UNIMPLEMENTED;
1212 }
1213
1214
1215 NTSTATUS
1216 STDCALL
1217 NtQueryMultipleValueKey (
1218 IN HANDLE KeyHandle,
1219 IN PWVALENT ListOfValuesToQuery,
1220 IN ULONG NumberOfItems,
1221 OUT PVOID MultipleValueInformation,
1222 IN ULONG Length,
1223 OUT PULONG ReturnLength)
1224 {
1225 UNIMPLEMENTED;
1226 }
1227
1228
1229 NTSTATUS
1230 STDCALL
1231 NtReplaceKey (
1232 IN POBJECT_ATTRIBUTES ObjectAttributes,
1233 IN HANDLE Key,
1234 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
1235 )
1236 {
1237 UNIMPLEMENTED;
1238 }
1239
1240
1241 NTSTATUS
1242 STDCALL
1243 NtRestoreKey (
1244 IN HANDLE KeyHandle,
1245 IN HANDLE FileHandle,
1246 IN ULONG RestoreFlags
1247 )
1248 {
1249 UNIMPLEMENTED;
1250 }
1251
1252
1253 NTSTATUS
1254 STDCALL
1255 NtSaveKey (
1256 IN HANDLE KeyHandle,
1257 IN HANDLE FileHandle
1258 )
1259 {
1260 UNIMPLEMENTED;
1261 }
1262
1263
1264 NTSTATUS
1265 STDCALL
1266 NtSetInformationKey (
1267 IN HANDLE KeyHandle,
1268 IN CINT KeyInformationClass,
1269 IN PVOID KeyInformation,
1270 IN ULONG KeyInformationLength
1271 )
1272 {
1273 UNIMPLEMENTED;
1274 }
1275
1276
1277 NTSTATUS
1278 STDCALL
1279 NtUnloadKey (
1280 HANDLE KeyHandle
1281 )
1282 {
1283 UNIMPLEMENTED;
1284 }
1285
1286
1287 NTSTATUS
1288 STDCALL
1289 NtInitializeRegistry (
1290 BOOLEAN SetUpBoot
1291 )
1292 {
1293 UNIMPLEMENTED;
1294 }
1295
1296
1297 NTSTATUS
1298 STDCALL
1299 RtlCheckRegistryKey (
1300 ULONG RelativeTo,
1301 PWSTR Path
1302 )
1303 {
1304 UNIMPLEMENTED;
1305 }
1306
1307
1308 NTSTATUS
1309 STDCALL
1310 RtlCreateRegistryKey (
1311 IN ULONG RelativeTo,
1312 IN PWSTR Path
1313 )
1314 {
1315 UNIMPLEMENTED;
1316 }
1317
1318
1319 NTSTATUS
1320 STDCALL
1321 RtlDeleteRegistryValue (
1322 IN ULONG RelativeTo,
1323 IN PWSTR Path,
1324 IN PWSTR ValueName
1325 )
1326 {
1327 UNIMPLEMENTED;
1328 }
1329
1330
1331 NTSTATUS
1332 STDCALL
1333 RtlQueryRegistryValues (
1334 IN ULONG RelativeTo,
1335 IN PWSTR Path,
1336 PRTL_QUERY_REGISTRY_TABLE QueryTable,
1337 PVOID Context,
1338 PVOID Environment
1339 )
1340 {
1341 UNIMPLEMENTED;
1342 }
1343
1344
1345 NTSTATUS
1346 STDCALL
1347 RtlWriteRegistryValue (
1348 ULONG RelativeTo,
1349 PWSTR Path,
1350 PWSTR ValueName,
1351 ULONG ValueType,
1352 PVOID ValueData,
1353 ULONG ValueLength
1354 )
1355 {
1356 UNIMPLEMENTED;
1357 }
1358
1359 /* ------------------------------------------ Private Implementation */
1360
1361
1362 #if PROTO_REG
1363 //static PVOID
1364 //CmiObjectParse(PVOID ParsedObject, PWSTR *Path)
1365 static NTSTATUS CmiObjectParse(PVOID ParsedObject,
1366 PVOID *NextObject,
1367 PUNICODE_STRING FullPath,
1368 PWSTR *Path)
1369 {
1370 NTSTATUS Status;
1371 /* FIXME: this should be allocated based on the largest subkey name */
1372 WCHAR CurKeyName[260];
1373 PWSTR Remainder, NextSlash;
1374 PREGISTRY_FILE RegistryFile;
1375 PKEY_OBJECT NewKeyObject;
1376 HANDLE KeyHandle;
1377 PKEY_BLOCK CurKeyBlock, SubKeyBlock;
1378
1379 Status = STATUS_SUCCESS;
1380
1381 /* FIXME: it should probably get this from ParsedObject */
1382 RegistryFile = CmiVolatileFile;
1383
1384 /* Scan key object list for key already open */
1385 NewKeyObject = CmiScanKeyList((*Path) + 1);
1386 if (NewKeyObject != NULL)
1387 {
1388 /* Return reference if found */
1389 ObReferenceObjectByPointer(NewKeyObject,
1390 STANDARD_RIGHTS_REQUIRED,
1391 NULL,
1392 UserMode);
1393 *Path = NULL;
1394
1395 // return NewKeyObject;
1396 //FIXME
1397 return Status;
1398 }
1399
1400 CurKeyBlock = CmiGetKeyBlock(RegistryFile,
1401 RegistryFile->HeaderBlock->RootKeyBlock);
1402
1403 /* Loop through each key level and find the needed subkey */
1404 Remainder = (*Path) + 1;
1405 while (NT_SUCCESS(Status) && *Remainder != 0)
1406 {
1407 NextSlash = wcschr(Remainder, L'\\');
1408
1409 /* Copy just the current subkey name to a buffer */
1410 if (NextSlash != NULL)
1411 {
1412 wcsncpy(CurKeyName, Remainder, NextSlash - Remainder);
1413 CurKeyName[NextSlash - Remainder] = 0;
1414 }
1415 else
1416 {
1417 wcscpy(CurKeyName, Remainder);
1418 }
1419
1420 /* Verify existance of CurKeyName */
1421 Status = CmiScanForSubKey(RegistryFile,
1422 CurKeyBlock,
1423 &SubKeyBlock,
1424 CurKeyName,
1425 STANDARD_RIGHTS_REQUIRED);
1426 if (!NT_SUCCESS(Status))
1427 {
1428 continue;
1429 }
1430 if (SubKeyBlock == NULL)
1431 {
1432 Status = STATUS_UNSUCCESSFUL;
1433 continue;
1434 }
1435 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1436 CurKeyBlock = SubKeyBlock;
1437
1438 if (NextSlash != NULL)
1439 {
1440 Remainder = NextSlash + 1;
1441 }
1442 else
1443 {
1444 Remainder = NULL;
1445 }
1446 }
1447
1448 /* Create new key object and put into linked list */
1449 NewKeyObject = ObCreateObject(&KeyHandle,
1450 STANDARD_RIGHTS_REQUIRED,
1451 NULL,
1452 CmiKeyType);
1453 if (NewKeyObject == NULL)
1454 {
1455 //FIXME : return the good error code
1456 return STATUS_UNSUCCESSFUL;
1457 }
1458 NewKeyObject->Flags = 0;
1459 NewKeyObject->Name = ExAllocatePool(NonPagedPool,
1460 wcslen(*Path) * sizeof(WCHAR));
1461 wcscpy(NewKeyObject->Name, (*Path) + 1);
1462 NewKeyObject->KeyBlock = CurKeyBlock;
1463 NewKeyObject->RegistryFile = RegistryFile;
1464 CmiAddKeyToList(NewKeyObject);
1465 *Path = (Remainder != NULL) ? Remainder - 1 : NULL;
1466
1467 NextObject = (PVOID)NewKeyObject;
1468 return STATUS_SUCCESS;
1469 }
1470
1471 static VOID
1472 CmiObjectDelete(PVOID DeletedObject)
1473 {
1474 PKEY_OBJECT KeyObject;
1475
1476 KeyObject = (PKEY_OBJECT) DeletedObject;
1477 if (KeyObject->Flags & KO_MARKED_FOR_DELETE)
1478 {
1479 CmiDestroyKeyBlock(KeyObject->RegistryFile,
1480 KeyObject->KeyBlock);
1481 }
1482 else
1483 {
1484 CmiReleaseBlock(KeyObject->RegistryFile,
1485 KeyObject->KeyBlock);
1486 }
1487 ExFreePool(KeyObject->Name);
1488 CmiRemoveKeyFromList(KeyObject);
1489 }
1490
1491 static NTSTATUS
1492 CmiBuildKeyPath(PWSTR *KeyPath, POBJECT_ATTRIBUTES ObjectAttributes)
1493 {
1494 NTSTATUS Status;
1495 ULONG KeyNameSize;
1496 PWSTR KeyNameBuf;
1497 PVOID ObjectBody;
1498 PKEY_OBJECT KeyObject;
1499 POBJECT_HEADER ObjectHeader;
1500
1501 /* FIXME: Verify ObjectAttributes is in \\Registry space and compute size for path */
1502 KeyNameSize = 0;
1503 ObjectHeader = 0;
1504 if (ObjectAttributes->RootDirectory != NULL)
1505 {
1506 /* FIXME: determine type of object for RootDirectory */
1507 Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
1508 KEY_READ,
1509 NULL,
1510 UserMode,
1511 (PVOID *)&ObjectBody,
1512 NULL);
1513 if (!NT_SUCCESS(Status))
1514 {
1515 return Status;
1516 }
1517 ObjectHeader = BODY_TO_HEADER(ObjectBody);
1518
1519 if (ObjectHeader->ObjectType != CmiKeyType)
1520 {
1521 /* Fail if RootDirectory != '\\' */
1522 if (ObjectBody == NameSpaceRoot)
1523 {
1524 /* Check for 'Registry' in ObjectName, fail if missing */
1525 if (wcsncmp(ObjectAttributes->ObjectName->Buffer,
1526 REG_ROOT_KEY_NAME + 1,
1527 wcslen(REG_ROOT_KEY_NAME + 1)) != 0 ||
1528 ObjectAttributes->ObjectName->Buffer[wcslen(REG_ROOT_KEY_NAME + 1)] != L'\\')
1529 {
1530 ObDereferenceObject(ObjectBody);
1531
1532 return STATUS_OBJECT_PATH_INVALID;
1533 }
1534
1535 /* Compute size of registry portion of path to KeyNameSize */
1536 KeyNameSize = (ObjectAttributes->ObjectName->Length -
1537 (wcslen(REG_ROOT_KEY_NAME + 1) + 1))
1538 * sizeof(WCHAR);
1539 }
1540 else if (!wcscmp(ObjectHeader->Name.Buffer,
1541 REG_ROOT_KEY_NAME + 1))
1542 {
1543 /* Add size of ObjectName to KeyNameSize */
1544 KeyNameSize = ObjectAttributes->ObjectName->Length;
1545 }
1546 else
1547 {
1548 ObDereferenceObject(ObjectBody);
1549
1550 return STATUS_OBJECT_PATH_INVALID;
1551 }
1552 }
1553 else
1554 {
1555 KeyObject = (PKEY_OBJECT) ObjectBody;
1556
1557 /* Add size of Name from RootDirectory object to KeyNameSize */
1558 KeyNameSize = wcslen(KeyObject->Name) * sizeof(WCHAR);
1559
1560 /* Add 1 to KeyNamesize for '\\' */
1561 KeyNameSize += sizeof(WCHAR);
1562
1563 /* Add size of ObjectName to KeyNameSize */
1564 KeyNameSize += ObjectAttributes->ObjectName->Length * sizeof(WCHAR);
1565 }
1566 }
1567 else
1568 {
1569 /* Check for \\Registry and fail if missing */
1570 if (wcsncmp(ObjectAttributes->ObjectName->Buffer,
1571 REG_ROOT_KEY_NAME,
1572 wcslen(REG_ROOT_KEY_NAME)) != 0 ||
1573 ObjectAttributes->ObjectName->Buffer[wcslen(REG_ROOT_KEY_NAME)] != L'\\')
1574 {
1575 return STATUS_OBJECT_PATH_INVALID;
1576 }
1577
1578 /* Compute size of registry portion of path to KeyNameSize */
1579 KeyNameSize = (ObjectAttributes->ObjectName->Length -
1580 (wcslen(REG_ROOT_KEY_NAME) + 1)) * sizeof(WCHAR);
1581 }
1582
1583 KeyNameBuf = ExAllocatePool(NonPagedPool, KeyNameSize + sizeof(WCHAR));
1584
1585 /* Construct relative pathname */
1586 KeyNameBuf[0] = 0;
1587 if (ObjectAttributes->RootDirectory != NULL)
1588 {
1589 if (ObjectHeader->ObjectType != CmiKeyType)
1590 {
1591 /* Fail if RootDirectory != '\\' */
1592 if (ObjectBody == NameSpaceRoot)
1593 {
1594 /* Copy remainder of ObjectName after 'Registry' */
1595 wcscpy(KeyNameBuf, ObjectAttributes->ObjectName->Buffer + wcslen(REG_ROOT_KEY_NAME + 1));
1596 }
1597 else
1598 {
1599 /* Copy all of ObjectName */
1600 wcscpy(KeyNameBuf, ObjectAttributes->ObjectName->Buffer);
1601 }
1602 }
1603 else
1604 {
1605 KeyObject = (PKEY_OBJECT) ObjectBody;
1606
1607 /* Copy Name from RootDirectory object to KeyNameBuf */
1608 wcscpy(KeyNameBuf, KeyObject->Name);
1609
1610 /* Append '\\' onto KeyNameBuf */
1611 wcscat(KeyNameBuf, L"\\");
1612
1613 /* Append ObjectName onto KeyNameBuf */
1614 wcscat(KeyNameBuf, ObjectAttributes->ObjectName->Buffer);
1615 }
1616 }
1617 else
1618 {
1619 /* Copy registry portion of path into KeyNameBuf */
1620 wcscpy(KeyNameBuf, ObjectAttributes->ObjectName->Buffer +
1621 (wcslen(REG_ROOT_KEY_NAME) + 1));
1622 }
1623
1624 *KeyPath = KeyNameBuf;
1625 return STATUS_SUCCESS;
1626 }
1627
1628 static VOID
1629 CmiAddKeyToList(PKEY_OBJECT NewKey)
1630 {
1631 KIRQL OldIrql;
1632
1633 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
1634 NewKey->NextKey = CmiKeyList;
1635 CmiKeyList = NewKey;
1636 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
1637 }
1638
1639 static VOID
1640 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove)
1641 {
1642 KIRQL OldIrql;
1643 PKEY_OBJECT CurKey;
1644
1645 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
1646 if (CmiKeyList == KeyToRemove)
1647 {
1648 CmiKeyList = CmiKeyList->NextKey;
1649 }
1650 else
1651 {
1652 CurKey = CmiKeyList;
1653 while (CurKey != NULL && CurKey->NextKey != KeyToRemove)
1654 {
1655 CurKey = CurKey->NextKey;
1656 }
1657 if (CurKey != NULL)
1658 {
1659 CurKey->NextKey = KeyToRemove->NextKey;
1660 }
1661 }
1662 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
1663 }
1664
1665 static PKEY_OBJECT
1666 CmiScanKeyList(PWSTR KeyName)
1667 {
1668 KIRQL OldIrql;
1669 PKEY_OBJECT CurKey;
1670
1671 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
1672 CurKey = CmiKeyList;
1673 while (CurKey != NULL && wcscmp(KeyName, CurKey->Name) != 0)
1674 {
1675 CurKey = CurKey->NextKey;
1676 }
1677 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
1678
1679 return CurKey;
1680 }
1681
1682 static PREGISTRY_FILE
1683 CmiCreateRegistry(PWSTR Filename)
1684 {
1685 PREGISTRY_FILE RegistryFile;
1686 PKEY_BLOCK RootKeyBlock;
1687
1688 RegistryFile = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_FILE));
1689 if (Filename != NULL)
1690 {
1691 UNIMPLEMENTED;
1692 /* FIXME: Duplicate Filename */
1693 /* FIXME: if file does not exist, create new file */
1694 /* FIXME: else attempt to map the file */
1695 }
1696 else
1697 {
1698 RegistryFile->Filename = NULL;
1699 RegistryFile->FileHandle = NULL;
1700
1701 RegistryFile->HeaderBlock = (PHEADER_BLOCK)
1702 ExAllocatePool(NonPagedPool, sizeof(HEADER_BLOCK));
1703 RtlZeroMemory(RegistryFile->HeaderBlock, sizeof(HEADER_BLOCK));
1704 RegistryFile->HeaderBlock->BlockId = 0x66676572;
1705 RegistryFile->HeaderBlock->DateModified.QuadPart = 0;
1706 RegistryFile->HeaderBlock->Unused2 = 1;
1707 RegistryFile->HeaderBlock->Unused3 = 3;
1708 RegistryFile->HeaderBlock->Unused5 = 1;
1709 RegistryFile->HeaderBlock->RootKeyBlock = 0;
1710 RegistryFile->HeaderBlock->BlockSize = REG_BLOCK_SIZE;
1711 RegistryFile->HeaderBlock->Unused6 = 1;
1712 RegistryFile->HeaderBlock->Checksum = 0;
1713 RootKeyBlock = (PKEY_BLOCK)
1714 ExAllocatePool(NonPagedPool, sizeof(KEY_BLOCK));
1715 RtlZeroMemory(RootKeyBlock, sizeof(KEY_BLOCK));
1716 RootKeyBlock->SubBlockId = REG_KEY_BLOCK_ID;
1717 RootKeyBlock->Type = REG_ROOT_KEY_BLOCK_TYPE;
1718 ZwQuerySystemTime((PTIME) &RootKeyBlock->LastWriteTime);
1719 RootKeyBlock->ParentKeyOffset = 0;
1720 RootKeyBlock->NumberOfSubKeys = 0;
1721 RootKeyBlock->HashTableOffset = 0;
1722 RootKeyBlock->NumberOfValues = 0;
1723 RootKeyBlock->ValuesOffset = 0;
1724 RootKeyBlock->SecurityKeyOffset = 0;
1725 RootKeyBlock->ClassNameOffset = sizeof(KEY_BLOCK);
1726 RootKeyBlock->NameSize = 0;
1727 RootKeyBlock->ClassSize = 0;
1728 RootKeyBlock->Name[0] = 0;
1729 RegistryFile->HeaderBlock->RootKeyBlock = (BLOCK_OFFSET) RootKeyBlock;
1730 }
1731
1732 return RegistryFile;
1733 }
1734
1735 static NTSTATUS
1736 CmiCreateKey(IN PREGISTRY_FILE RegistryFile,
1737 IN PWSTR KeyNameBuf,
1738 OUT PKEY_BLOCK *KeyBlock,
1739 IN ACCESS_MASK DesiredAccess,
1740 IN ULONG TitleIndex,
1741 IN PUNICODE_STRING Class,
1742 IN ULONG CreateOptions,
1743 OUT PULONG Disposition)
1744 {
1745 /* FIXME: this should be allocated based on the largest subkey name */
1746 NTSTATUS Status;
1747 WCHAR CurKeyName[256];
1748 PWSTR ClassName;
1749 PWSTR Remainder, NextSlash;
1750 PKEY_BLOCK CurKeyBlock, SubKeyBlock;
1751
1752 /* FIXME: Should handle search by Class/TitleIndex */
1753
1754 CHECKPOINT;
1755 /* Loop through each key level and find or build the needed subkey */
1756 Status = STATUS_SUCCESS;
1757 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1758 CurKeyBlock = CmiGetKeyBlock(RegistryFile,
1759 RegistryFile->HeaderBlock->RootKeyBlock);
1760 CHECKPOINT;
1761 Remainder = KeyNameBuf;
1762 while (NT_SUCCESS(Status) &&
1763 (NextSlash = wcschr(Remainder, L'\\')) != NULL)
1764 {
1765 /* Copy just the current subkey name to a buffer */
1766 wcsncpy(CurKeyName, Remainder, NextSlash - Remainder);
1767 CurKeyName[NextSlash - Remainder] = 0;
1768
1769 /* Verify existance of/Create CurKeyName */
1770 CHECKPOINT;
1771 Status = CmiScanForSubKey(RegistryFile,
1772 CurKeyBlock,
1773 &SubKeyBlock,
1774 CurKeyName,
1775 DesiredAccess);
1776 if (!NT_SUCCESS(Status))
1777 {
1778 continue;
1779 }
1780 if (SubKeyBlock == NULL)
1781 {
1782 Status = CmiAddSubKey(RegistryFile,
1783 CurKeyBlock,
1784 &SubKeyBlock,
1785 CurKeyName,
1786 0,
1787 NULL,
1788 0);
1789 if (!NT_SUCCESS(Status))
1790 {
1791 continue;
1792 }
1793 }
1794 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1795 CurKeyBlock = SubKeyBlock;
1796
1797 Remainder = NextSlash + 1;
1798 }
1799 CHECKPOINT;
1800 if (NT_SUCCESS(Status))
1801 {
1802 CHECKPOINT;
1803 Status = CmiScanForSubKey(RegistryFile,
1804 CurKeyBlock,
1805 &SubKeyBlock,
1806 CurKeyName,
1807 DesiredAccess);
1808 if (NT_SUCCESS(Status))
1809 {
1810 if (SubKeyBlock == NULL)
1811 {
1812 if (Class != NULL)
1813 {
1814 ClassName = ExAllocatePool(NonPagedPool, Class->Length + 1);
1815 wcsncpy(ClassName, Class->Buffer, Class->Length);
1816 ClassName[Class->Length] = 0;
1817 }
1818 else
1819 {
1820 ClassName = 0;
1821 }
1822 Status = CmiAddSubKey(RegistryFile,
1823 CurKeyBlock,
1824 &SubKeyBlock,
1825 Remainder,
1826 TitleIndex,
1827 ClassName,
1828 CreateOptions);
1829 if (ClassName != NULL)
1830 {
1831 ExFreePool(ClassName);
1832 }
1833 if (NT_SUCCESS(Status) && Disposition != NULL)
1834 {
1835 *Disposition = REG_CREATED_NEW_KEY;
1836 }
1837 }
1838 else if (Disposition != NULL)
1839 {
1840 *Disposition = REG_OPENED_EXISTING_KEY;
1841 }
1842 }
1843 *KeyBlock = SubKeyBlock;
1844 }
1845 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1846
1847 return Status;
1848 }
1849
1850 static NTSTATUS
1851 CmiFindKey(IN PREGISTRY_FILE RegistryFile,
1852 IN PWSTR KeyNameBuf,
1853 OUT PKEY_BLOCK *KeyBlock,
1854 IN ACCESS_MASK DesiredAccess,
1855 IN ULONG TitleIndex,
1856 IN PUNICODE_STRING Class)
1857 {
1858 /* FIXME: this should be allocated based on the largest subkey name */
1859 NTSTATUS Status;
1860 WCHAR CurKeyName[256];
1861 PWSTR Remainder, NextSlash;
1862 PKEY_BLOCK CurKeyBlock, SubKeyBlock;
1863
1864 /* FIXME: Should handle search by Class/TitleIndex */
1865
1866 /* Loop through each key level and find the needed subkey */
1867 Status = STATUS_SUCCESS;
1868 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1869 CurKeyBlock = CmiGetKeyBlock(RegistryFile, RegistryFile->HeaderBlock->RootKeyBlock);
1870 Remainder = KeyNameBuf;
1871 while (NT_SUCCESS(Status) &&
1872 (NextSlash = wcschr(Remainder, L'\\')) != NULL)
1873 {
1874 /* Copy just the current subkey name to a buffer */
1875 wcsncpy(CurKeyName, Remainder, NextSlash - Remainder);
1876 CurKeyName[NextSlash - Remainder] = 0;
1877
1878 /* Verify existance of CurKeyName */
1879 Status = CmiScanForSubKey(RegistryFile,
1880 CurKeyBlock,
1881 &SubKeyBlock,
1882 CurKeyName,
1883 DesiredAccess);
1884 if (!NT_SUCCESS(Status))
1885 {
1886 continue;
1887 }
1888 if (SubKeyBlock == NULL)
1889 {
1890 Status = STATUS_UNSUCCESSFUL;
1891 continue;
1892 }
1893 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1894 CurKeyBlock = SubKeyBlock;
1895
1896 Remainder = NextSlash + 1;
1897 }
1898 if (NT_SUCCESS(Status))
1899 {
1900 Status = CmiScanForSubKey(RegistryFile,
1901 CurKeyBlock,
1902 &SubKeyBlock,
1903 CurKeyName,
1904 DesiredAccess);
1905 if (NT_SUCCESS(Status))
1906 {
1907 if (SubKeyBlock == NULL)
1908 {
1909 Status = STATUS_UNSUCCESSFUL;
1910 }
1911 else
1912 {
1913 *KeyBlock = SubKeyBlock;
1914 }
1915 }
1916 }
1917 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1918
1919 return Status;
1920 }
1921
1922 static ULONG
1923 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile,
1924 PKEY_BLOCK KeyBlock)
1925 {
1926 ULONG Idx, MaxName;
1927 PHASH_TABLE_BLOCK HashBlock;
1928 PKEY_BLOCK CurSubKeyBlock;
1929
1930 MaxName = 0;
1931 HashBlock = CmiGetHashTableBlock(RegistryFile, KeyBlock->HashTableOffset);
1932 if (HashBlock == 0)
1933 {
1934 return 0;
1935 }
1936 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
1937 {
1938 if (HashBlock->Table[Idx].KeyOffset != 0)
1939 {
1940 CurSubKeyBlock = CmiGetKeyBlock(RegistryFile,
1941 HashBlock->Table[Idx].KeyOffset);
1942 if (MaxName < CurSubKeyBlock->NameSize)
1943 {
1944 MaxName = CurSubKeyBlock->NameSize;
1945 }
1946 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
1947 }
1948 }
1949
1950 CmiReleaseBlock(RegistryFile, HashBlock);
1951
1952 return MaxName;
1953 }
1954
1955 static ULONG
1956 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile,
1957 PKEY_BLOCK KeyBlock)
1958 {
1959 ULONG Idx, MaxClass;
1960 PHASH_TABLE_BLOCK HashBlock;
1961 PKEY_BLOCK CurSubKeyBlock;
1962
1963 MaxClass = 0;
1964 HashBlock = CmiGetHashTableBlock(RegistryFile, KeyBlock->HashTableOffset);
1965 if (HashBlock == 0)
1966 {
1967 return 0;
1968 }
1969 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
1970 {
1971 if (HashBlock->Table[Idx].KeyOffset != 0)
1972 {
1973 CurSubKeyBlock = CmiGetKeyBlock(RegistryFile,
1974 HashBlock->Table[Idx].KeyOffset);
1975 if (MaxClass < CurSubKeyBlock->ClassSize)
1976 {
1977 MaxClass = CurSubKeyBlock->ClassSize;
1978 }
1979 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
1980 }
1981 }
1982
1983 CmiReleaseBlock(RegistryFile, HashBlock);
1984
1985 return MaxClass;
1986 }
1987
1988 static ULONG
1989 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile,
1990 PKEY_BLOCK KeyBlock)
1991 {
1992 ULONG Idx, MaxValueName;
1993 PVALUE_LIST_BLOCK ValueListBlock;
1994 PVALUE_BLOCK CurValueBlock;
1995
1996 ValueListBlock = CmiGetBlock(RegistryFile,
1997 KeyBlock->ValuesOffset);
1998 MaxValueName = 0;
1999 if (ValueListBlock == 0)
2000 {
2001 return 0;
2002 }
2003 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
2004 {
2005 CurValueBlock = CmiGetBlock(RegistryFile,
2006 ValueListBlock->Values[Idx]);
2007 if (CurValueBlock != NULL &&
2008 MaxValueName < CurValueBlock->NameSize)
2009 {
2010 MaxValueName = CurValueBlock->NameSize;
2011 }
2012 CmiReleaseBlock(RegistryFile, CurValueBlock);
2013 }
2014
2015 CmiReleaseBlock(RegistryFile, ValueListBlock);
2016
2017 return MaxValueName;
2018 }
2019
2020 static ULONG
2021 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile,
2022 PKEY_BLOCK KeyBlock)
2023 {
2024 ULONG Idx, MaxValueData;
2025 PVALUE_LIST_BLOCK ValueListBlock;
2026 PVALUE_BLOCK CurValueBlock;
2027
2028 ValueListBlock = CmiGetBlock(RegistryFile,
2029 KeyBlock->ValuesOffset);
2030 MaxValueData = 0;
2031 if (ValueListBlock == 0)
2032 {
2033 return 0;
2034 }
2035 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
2036 {
2037 CurValueBlock = CmiGetBlock(RegistryFile,
2038 ValueListBlock->Values[Idx]);
2039 if (CurValueBlock != NULL &&
2040 MaxValueData < CurValueBlock->DataSize)
2041 {
2042 MaxValueData = CurValueBlock->DataSize;
2043 }
2044 CmiReleaseBlock(RegistryFile, CurValueBlock);
2045 }
2046
2047 CmiReleaseBlock(RegistryFile, ValueListBlock);
2048
2049 return MaxValueData;
2050 }
2051
2052 static NTSTATUS
2053 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile,
2054 IN PKEY_BLOCK KeyBlock,
2055 OUT PKEY_BLOCK *SubKeyBlock,
2056 IN PWSTR KeyName,
2057 IN ACCESS_MASK DesiredAccess)
2058 {
2059 ULONG Idx;
2060 PHASH_TABLE_BLOCK HashBlock;
2061 PKEY_BLOCK CurSubKeyBlock;
2062
2063 HashBlock = CmiGetHashTableBlock(RegistryFile, KeyBlock->HashTableOffset);
2064 *SubKeyBlock = NULL;
2065 if (HashBlock == 0)
2066 {
2067 return STATUS_SUCCESS;
2068 }
2069 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
2070 {
2071 if (HashBlock->Table[Idx].KeyOffset != 0 &&
2072 !wcsncmp(KeyName, (PWSTR) &HashBlock->Table[Idx].HashValue, 4))
2073 {
2074 CurSubKeyBlock = CmiGetKeyBlock(RegistryFile,
2075 HashBlock->Table[Idx].KeyOffset);
2076 if (!wcscmp(KeyName, CurSubKeyBlock->Name))
2077 {
2078 *SubKeyBlock = CurSubKeyBlock;
2079 break;
2080 }
2081 else
2082 {
2083 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
2084 }
2085 }
2086 }
2087
2088 CmiReleaseBlock(RegistryFile, HashBlock);
2089
2090 return STATUS_SUCCESS;
2091 }
2092
2093 static NTSTATUS
2094 CmiAddSubKey(PREGISTRY_FILE RegistryFile,
2095 PKEY_BLOCK KeyBlock,
2096 PKEY_BLOCK *SubKeyBlock,
2097 PWSTR NewSubKeyName,
2098 ULONG TitleIndex,
2099 PWSTR Class,
2100 ULONG CreateOptions)
2101 {
2102 NTSTATUS Status;
2103 PHASH_TABLE_BLOCK HashBlock, NewHashBlock;
2104 PKEY_BLOCK NewKeyBlock;
2105
2106 Status = CmiAllocateKeyBlock(RegistryFile,
2107 &NewKeyBlock,
2108 NewSubKeyName,
2109 TitleIndex,
2110 Class,
2111 CreateOptions);
2112 if (!NT_SUCCESS(Status))
2113 {
2114 return Status;
2115 }
2116 if (KeyBlock->HashTableOffset == 0)
2117 {
2118 Status = CmiAllocateHashTableBlock(RegistryFile,
2119 &HashBlock,
2120 REG_INIT_HASH_TABLE_SIZE);
2121 if (!NT_SUCCESS(Status))
2122 {
2123 return Status;
2124 }
2125 KeyBlock->HashTableOffset = CmiGetBlockOffset(RegistryFile, HashBlock);
2126 }
2127 else
2128 {
2129 HashBlock = CmiGetHashTableBlock(RegistryFile, KeyBlock->HashTableOffset);
2130 if (KeyBlock->NumberOfSubKeys + 1 >= HashBlock->HashTableSize)
2131 {
2132
2133 /* FIXME: All Subkeys will need to be rehashed here! */
2134
2135 /* Reallocate the hash table block */
2136 Status = CmiAllocateHashTableBlock(RegistryFile,
2137 &NewHashBlock,
2138 HashBlock->HashTableSize +
2139 REG_EXTEND_HASH_TABLE_SIZE);
2140 if (!NT_SUCCESS(Status))
2141 {
2142 return Status;
2143 }
2144 RtlZeroMemory(&NewHashBlock->Table[0],
2145 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2146 RtlCopyMemory(&NewHashBlock->Table[0],
2147 &HashBlock->Table[0],
2148 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2149 KeyBlock->HashTableOffset = CmiGetBlockOffset(RegistryFile, NewHashBlock);
2150 CmiDestroyHashTableBlock(RegistryFile, HashBlock);
2151 HashBlock = NewHashBlock;
2152 }
2153 }
2154 Status = CmiAddKeyToHashTable(RegistryFile, HashBlock, NewKeyBlock);
2155 if (NT_SUCCESS(Status))
2156 {
2157 KeyBlock->NumberOfSubKeys++;
2158 *SubKeyBlock = NewKeyBlock;
2159 }
2160 CmiReleaseBlock(RegistryFile, HashBlock);
2161
2162 return Status;
2163 }
2164
2165 static NTSTATUS
2166 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile,
2167 IN PKEY_BLOCK KeyBlock,
2168 IN PWSTR ValueName,
2169 OUT PVALUE_BLOCK *ValueBlock)
2170 {
2171 ULONG Idx;
2172 PVALUE_LIST_BLOCK ValueListBlock;
2173 PVALUE_BLOCK CurValueBlock;
2174
2175 ValueListBlock = CmiGetBlock(RegistryFile,
2176 KeyBlock->ValuesOffset);
2177 *ValueBlock = NULL;
2178 if (ValueListBlock == 0)
2179 {
2180 return STATUS_SUCCESS;
2181 }
2182 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
2183 {
2184 CurValueBlock = CmiGetBlock(RegistryFile,
2185 ValueListBlock->Values[Idx]);
2186 if (CurValueBlock != NULL &&
2187 !wcscmp(CurValueBlock->Name, ValueName))
2188 {
2189 *ValueBlock = CurValueBlock;
2190 break;
2191 }
2192 CmiReleaseBlock(RegistryFile, CurValueBlock);
2193 }
2194
2195 CmiReleaseBlock(RegistryFile, ValueListBlock);
2196
2197 return STATUS_SUCCESS;
2198 }
2199
2200 static NTSTATUS
2201 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile,
2202 IN PKEY_BLOCK KeyBlock,
2203 IN PWSTR ValueNameBuf,
2204 IN ULONG Type,
2205 IN PVOID Data,
2206 IN ULONG DataSize)
2207 {
2208 NTSTATUS Status;
2209 PVALUE_LIST_BLOCK ValueListBlock, NewValueListBlock;
2210 PVALUE_BLOCK ValueBlock;
2211
2212 Status = CmiAllocateValueBlock(RegistryFile,
2213 &ValueBlock,
2214 ValueNameBuf,
2215 Type,
2216 Data,
2217 DataSize);
2218 if (!NT_SUCCESS(Status))
2219 {
2220 return Status;
2221 }
2222 ValueListBlock = CmiGetBlock(RegistryFile,
2223 KeyBlock->ValuesOffset);
2224 if (ValueListBlock == NULL)
2225 {
2226 Status = CmiAllocateBlock(RegistryFile,
2227 (PVOID) &ValueListBlock,
2228 sizeof(BLOCK_OFFSET) *
2229 REG_VALUE_LIST_BLOCK_MULTIPLE);
2230 if (!NT_SUCCESS(Status))
2231 {
2232 CmiDestroyValueBlock(RegistryFile,
2233 ValueBlock);
2234 return Status;
2235 }
2236 }
2237 else if (KeyBlock->NumberOfValues % REG_VALUE_LIST_BLOCK_MULTIPLE)
2238 {
2239 Status = CmiAllocateBlock(RegistryFile,
2240 (PVOID) &NewValueListBlock,
2241 sizeof(BLOCK_OFFSET) *
2242 (KeyBlock->NumberOfValues +
2243 REG_VALUE_LIST_BLOCK_MULTIPLE));
2244 if (!NT_SUCCESS(Status))
2245 {
2246 CmiDestroyValueBlock(RegistryFile,
2247 ValueBlock);
2248 return Status;
2249 }
2250 RtlCopyMemory(NewValueListBlock,
2251 ValueListBlock,
2252 sizeof(BLOCK_OFFSET) * KeyBlock->NumberOfValues);
2253 KeyBlock->ValuesOffset = CmiGetBlockOffset(RegistryFile,
2254 NewValueListBlock);
2255 CmiDestroyBlock(RegistryFile, ValueListBlock);
2256 ValueListBlock = NewValueListBlock;
2257 }
2258 ValueListBlock->Values[KeyBlock->NumberOfValues] =
2259 CmiGetBlockOffset(RegistryFile, ValueBlock);
2260 KeyBlock->NumberOfValues++;
2261 CmiReleaseBlock(RegistryFile, ValueBlock);
2262 CmiReleaseBlock(RegistryFile, ValueListBlock);
2263
2264 return STATUS_SUCCESS;
2265 }
2266
2267 static NTSTATUS
2268 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile,
2269 IN PKEY_BLOCK KeyBlock,
2270 IN PWSTR ValueName)
2271 {
2272 ULONG Idx;
2273 PVALUE_LIST_BLOCK ValueListBlock;
2274 PVALUE_BLOCK CurValueBlock;
2275
2276 ValueListBlock = CmiGetBlock(RegistryFile,
2277 KeyBlock->ValuesOffset);
2278 if (ValueListBlock == 0)
2279 {
2280 return STATUS_SUCCESS;
2281 }
2282 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
2283 {
2284 CurValueBlock = CmiGetBlock(RegistryFile,
2285 ValueListBlock->Values[Idx]);
2286 if (CurValueBlock != NULL &&
2287 !wcscmp(CurValueBlock->Name, ValueName))
2288 {
2289 if (KeyBlock->NumberOfValues - 1 < Idx)
2290 {
2291 RtlCopyMemory(&ValueListBlock->Values[Idx],
2292 &ValueListBlock->Values[Idx + 1],
2293 sizeof(BLOCK_OFFSET) *
2294 (KeyBlock->NumberOfValues - 1 - Idx));
2295 }
2296 else
2297 {
2298 RtlZeroMemory(&ValueListBlock->Values[Idx],
2299 sizeof(BLOCK_OFFSET));
2300 }
2301 KeyBlock->NumberOfValues -= 1;
2302 CmiDestroyValueBlock(RegistryFile, CurValueBlock);
2303
2304 break;
2305 }
2306 CmiReleaseBlock(RegistryFile, CurValueBlock);
2307 }
2308
2309 CmiReleaseBlock(RegistryFile, ValueListBlock);
2310
2311 return STATUS_SUCCESS;
2312 }
2313
2314 static NTSTATUS
2315 CmiAllocateKeyBlock(IN PREGISTRY_FILE RegistryFile,
2316 OUT PKEY_BLOCK *KeyBlock,
2317 IN PWSTR KeyName,
2318 IN ULONG TitleIndex,
2319 IN PWSTR Class,
2320 IN ULONG CreateOptions)
2321 {
2322 NTSTATUS Status;
2323 ULONG NewKeySize;
2324 PKEY_BLOCK NewKeyBlock;
2325
2326 Status = STATUS_SUCCESS;
2327
2328 /* Handle volatile files first */
2329 if (RegistryFile->Filename == NULL)
2330 {
2331 NewKeySize = sizeof(KEY_BLOCK) +
2332 (wcslen(KeyName) + 1) * sizeof(WCHAR) +
2333 (Class != NULL ? (wcslen(Class) + 1) * sizeof(WCHAR) : 0);
2334 NewKeyBlock = ExAllocatePool(NonPagedPool, NewKeySize);
2335 if (NewKeyBlock == NULL)
2336 {
2337 Status = STATUS_INSUFFICIENT_RESOURCES;
2338 }
2339 else
2340 {
2341 RtlZeroMemory(NewKeyBlock, NewKeySize);
2342 NewKeyBlock->SubBlockId = REG_KEY_BLOCK_ID;
2343 NewKeyBlock->Type = REG_KEY_BLOCK_TYPE;
2344 ZwQuerySystemTime((PTIME) &NewKeyBlock->LastWriteTime);
2345 NewKeyBlock->ParentKeyOffset = 0;
2346 NewKeyBlock->NumberOfSubKeys = 0;
2347 NewKeyBlock->HashTableOffset = 0;
2348 NewKeyBlock->NumberOfValues = 0;
2349 NewKeyBlock->ValuesOffset = 0;
2350 NewKeyBlock->SecurityKeyOffset = 0;
2351 NewKeyBlock->ClassNameOffset = sizeof(KEY_BLOCK) + wcslen(KeyName);
2352 NewKeyBlock->NameSize = wcslen(KeyName);
2353 NewKeyBlock->ClassSize = (Class != NULL) ? wcslen(Class) : 0;
2354 wcscpy(NewKeyBlock->Name, KeyName);
2355 if (Class != NULL)
2356 {
2357 wcscpy(&NewKeyBlock->Name[wcslen(KeyName) + 1], Class);
2358 }
2359 CmiLockBlock(RegistryFile, NewKeyBlock);
2360 *KeyBlock = NewKeyBlock;
2361 }
2362 }
2363 else
2364 {
2365 UNIMPLEMENTED;
2366 }
2367
2368 return Status;
2369 }
2370
2371 static PKEY_BLOCK
2372 CmiGetKeyBlock(PREGISTRY_FILE RegistryFile,
2373 BLOCK_OFFSET KeyBlockOffset)
2374 {
2375 PKEY_BLOCK KeyBlock;
2376
2377 if (RegistryFile->Filename == NULL)
2378 {
2379 CmiLockBlock(RegistryFile, (PVOID) KeyBlockOffset);
2380
2381 KeyBlock = (PKEY_BLOCK) KeyBlockOffset;
2382 }
2383 else
2384 {
2385 UNIMPLEMENTED;
2386 }
2387
2388 return KeyBlock;
2389 }
2390
2391 static NTSTATUS
2392 CmiDestroyKeyBlock(PREGISTRY_FILE RegistryFile,
2393 PKEY_BLOCK KeyBlock)
2394 {
2395 NTSTATUS Status;
2396
2397 Status = STATUS_SUCCESS;
2398
2399 if (RegistryFile->Filename == NULL)
2400 {
2401 CmiReleaseBlock(RegistryFile, KeyBlock);
2402 ExFreePool(KeyBlock);
2403 }
2404 else
2405 {
2406 UNIMPLEMENTED;
2407 }
2408
2409 return Status;
2410 }
2411
2412 static NTSTATUS
2413 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile,
2414 OUT PHASH_TABLE_BLOCK *HashBlock,
2415 IN ULONG HashTableSize)
2416 {
2417 NTSTATUS Status;
2418 ULONG NewHashSize;
2419 PHASH_TABLE_BLOCK NewHashBlock;
2420
2421 Status = STATUS_SUCCESS;
2422
2423 /* Handle volatile files first */
2424 if (RegistryFile->Filename == NULL)
2425 {
2426 NewHashSize = sizeof(HASH_TABLE_BLOCK) +
2427 (HashTableSize - 1) * sizeof(HASH_RECORD);
2428 NewHashBlock = ExAllocatePool(NonPagedPool, NewHashSize);
2429 if (NewHashBlock == NULL)
2430 {
2431 Status = STATUS_INSUFFICIENT_RESOURCES;
2432 }
2433 else
2434 {
2435 RtlZeroMemory(NewHashBlock, NewHashSize);
2436 NewHashBlock->SubBlockId = REG_HASH_TABLE_BLOCK_ID;
2437 NewHashBlock->HashTableSize = HashTableSize;
2438 CmiLockBlock(RegistryFile, NewHashBlock);
2439 *HashBlock = NewHashBlock;
2440 }
2441 }
2442 else
2443 {
2444 UNIMPLEMENTED;
2445 }
2446
2447 return Status;
2448 }
2449
2450 static PHASH_TABLE_BLOCK
2451 CmiGetHashTableBlock(PREGISTRY_FILE RegistryFile,
2452 BLOCK_OFFSET HashBlockOffset)
2453 {
2454 PHASH_TABLE_BLOCK HashBlock;
2455
2456 if (RegistryFile->Filename == NULL)
2457 {
2458 CmiLockBlock(RegistryFile, (PVOID) HashBlockOffset);
2459
2460 HashBlock = (PHASH_TABLE_BLOCK) HashBlockOffset;
2461 }
2462 else
2463 {
2464 UNIMPLEMENTED;
2465 }
2466
2467 return HashBlock;
2468 }
2469
2470 static PKEY_BLOCK
2471 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile,
2472 PHASH_TABLE_BLOCK HashBlock,
2473 ULONG Index)
2474 {
2475 PKEY_BLOCK KeyBlock;
2476
2477 if (RegistryFile->Filename == NULL)
2478 {
2479 KeyBlock = (PKEY_BLOCK) HashBlock->Table[Index].KeyOffset;
2480 CmiLockBlock(RegistryFile, KeyBlock);
2481 }
2482 else
2483 {
2484 UNIMPLEMENTED;
2485 }
2486
2487 return KeyBlock;
2488 }
2489
2490 static NTSTATUS
2491 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile,
2492 PHASH_TABLE_BLOCK HashBlock,
2493 PKEY_BLOCK NewKeyBlock)
2494 {
2495 HashBlock->Table[HashBlock->HashTableSize].KeyOffset =
2496 CmiGetBlockOffset(RegistryFile, NewKeyBlock);
2497 RtlCopyMemory(&HashBlock->Table[HashBlock->HashTableSize].HashValue,
2498 NewKeyBlock->Name,
2499 4);
2500 HashBlock->HashTableSize++;
2501
2502 return STATUS_SUCCESS;
2503 }
2504
2505 static NTSTATUS
2506 CmiDestroyHashTableBlock(PREGISTRY_FILE RegistryFile,
2507 PHASH_TABLE_BLOCK HashBlock)
2508 {
2509 NTSTATUS Status;
2510
2511 Status = STATUS_SUCCESS;
2512
2513 if (RegistryFile->Filename == NULL)
2514 {
2515 CmiReleaseBlock(RegistryFile, HashBlock);
2516 ExFreePool(HashBlock);
2517 }
2518 else
2519 {
2520 Status = STATUS_NOT_IMPLEMENTED;
2521 }
2522
2523 return Status;
2524 }
2525
2526 static NTSTATUS
2527 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile,
2528 PVALUE_BLOCK *ValueBlock,
2529 IN PWSTR ValueNameBuf,
2530 IN ULONG Type,
2531 IN PVOID Data,
2532 IN ULONG DataSize)
2533 {
2534 NTSTATUS Status;
2535 ULONG NewValueSize;
2536 PVALUE_BLOCK NewValueBlock;
2537 PVOID DataBlock;
2538
2539 Status = STATUS_SUCCESS;
2540
2541 /* Handle volatile files first */
2542 if (RegistryFile->Filename == NULL)
2543 {
2544 NewValueSize = sizeof(VALUE_BLOCK) + wcslen(ValueNameBuf);
2545 NewValueBlock = ExAllocatePool(NonPagedPool, NewValueSize);
2546 if (NewValueBlock == NULL)
2547 {
2548 Status = STATUS_INSUFFICIENT_RESOURCES;
2549 }
2550 else
2551 {
2552 RtlZeroMemory(NewValueBlock, NewValueSize);
2553 NewValueBlock->SubBlockId = REG_VALUE_BLOCK_ID;
2554 NewValueBlock->NameSize = wcslen(ValueNameBuf);
2555 wcscpy(NewValueBlock->Name, ValueNameBuf);
2556 NewValueBlock->DataType = Type;
2557 NewValueBlock->DataSize = DataSize;
2558 Status = CmiAllocateBlock(RegistryFile,
2559 &DataBlock,
2560 DataSize);
2561 if (!NT_SUCCESS(Status))
2562 {
2563 ExFreePool(NewValueBlock);
2564 }
2565 else
2566 {
2567 RtlCopyMemory(DataBlock, Data, DataSize);
2568 NewValueBlock->DataOffset = CmiGetBlockOffset(RegistryFile,
2569 DataBlock);
2570 CmiLockBlock(RegistryFile, NewValueBlock);
2571 CmiReleaseBlock(RegistryFile, DataBlock);
2572 *ValueBlock = NewValueBlock;
2573 }
2574 }
2575 }
2576 else
2577 {
2578 Status = STATUS_NOT_IMPLEMENTED;
2579 }
2580
2581 return Status;
2582 }
2583
2584 static NTSTATUS
2585 CmiReplaceValueData(IN PREGISTRY_FILE RegistryFile,
2586 IN PVALUE_BLOCK ValueBlock,
2587 IN ULONG Type,
2588 IN PVOID Data,
2589 IN ULONG DataSize)
2590 {
2591 NTSTATUS Status;
2592 PVOID DataBlock, NewDataBlock;
2593
2594 Status = STATUS_SUCCESS;
2595
2596 /* If new data size is <= current then overwrite current data */
2597 if (DataSize <= ValueBlock->DataSize)
2598 {
2599 DataBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset);
2600 RtlCopyMemory(DataBlock, Data, DataSize);
2601 ValueBlock->DataSize = DataSize;
2602 ValueBlock->DataType = Type;
2603 CmiReleaseBlock(RegistryFile, DataBlock);
2604 }
2605 else
2606 {
2607 /* Destroy current data block and allocate a new one */
2608 DataBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset);
2609 Status = CmiAllocateBlock(RegistryFile,
2610 &NewDataBlock,
2611 DataSize);
2612 RtlCopyMemory(NewDataBlock, Data, DataSize);
2613 ValueBlock->DataOffset = CmiGetBlockOffset(RegistryFile, DataBlock);
2614 ValueBlock->DataSize = DataSize;
2615 ValueBlock->DataType = Type;
2616 CmiReleaseBlock(RegistryFile, NewDataBlock);
2617 CmiDestroyBlock(RegistryFile, DataBlock);
2618 }
2619
2620 return Status;
2621 }
2622
2623 static NTSTATUS
2624 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile,
2625 PVALUE_BLOCK ValueBlock)
2626 {
2627 NTSTATUS Status;
2628
2629 Status = CmiDestroyBlock(RegistryFile,
2630 CmiGetBlock(RegistryFile,
2631 ValueBlock->DataOffset));
2632 if (!NT_SUCCESS(Status))
2633 {
2634 return Status;
2635 }
2636 return CmiDestroyBlock(RegistryFile, ValueBlock);
2637 }
2638
2639 static NTSTATUS
2640 CmiAllocateBlock(PREGISTRY_FILE RegistryFile,
2641 PVOID *Block,
2642 ULONG BlockSize)
2643 {
2644 NTSTATUS Status;
2645 PVOID NewBlock;
2646
2647 Status = STATUS_SUCCESS;
2648
2649 /* Handle volatile files first */
2650 if (RegistryFile->Filename == NULL)
2651 {
2652 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
2653 if (NewBlock == NULL)
2654 {
2655 Status = STATUS_INSUFFICIENT_RESOURCES;
2656 }
2657 else
2658 {
2659 RtlZeroMemory(NewBlock, BlockSize);
2660 CmiLockBlock(RegistryFile, NewBlock);
2661 *Block = NewBlock;
2662 }
2663 }
2664 else
2665 {
2666 Status = STATUS_NOT_IMPLEMENTED;
2667 }
2668
2669 return Status;
2670 }
2671
2672 static NTSTATUS
2673 CmiDestroyBlock(PREGISTRY_FILE RegistryFile,
2674 PVOID Block)
2675 {
2676 NTSTATUS Status;
2677
2678 Status = STATUS_SUCCESS;
2679
2680 if (RegistryFile->Filename == NULL)
2681 {
2682 CmiReleaseBlock(RegistryFile, Block);
2683 ExFreePool(Block);
2684 }
2685 else
2686 {
2687 Status = STATUS_NOT_IMPLEMENTED;
2688 }
2689
2690 return Status;
2691 }
2692
2693 static PVOID
2694 CmiGetBlock(PREGISTRY_FILE RegistryFile,
2695 BLOCK_OFFSET BlockOffset)
2696 {
2697 PVOID Block;
2698
2699 Block = NULL;
2700 if (RegistryFile->Filename == NULL)
2701 {
2702 CmiLockBlock(RegistryFile, (PVOID) BlockOffset);
2703
2704 Block = (PVOID) BlockOffset;
2705 }
2706 else
2707 {
2708 UNIMPLEMENTED;
2709 }
2710
2711 return Block;
2712 }
2713
2714 static BLOCK_OFFSET
2715 CmiGetBlockOffset(PREGISTRY_FILE RegistryFile,
2716 PVOID Block)
2717 {
2718 BLOCK_OFFSET BlockOffset;
2719
2720 if (RegistryFile->Filename == NULL)
2721 {
2722 BlockOffset = (BLOCK_OFFSET) Block;
2723 }
2724 else
2725 {
2726 UNIMPLEMENTED;
2727 }
2728
2729 return BlockOffset;
2730 }
2731
2732 static VOID
2733 CmiLockBlock(PREGISTRY_FILE RegistryFile,
2734 PVOID Block)
2735 {
2736 if (RegistryFile->Filename != NULL)
2737 {
2738 UNIMPLEMENTED;
2739 }
2740 }
2741
2742 static VOID
2743 CmiReleaseBlock(PREGISTRY_FILE RegistryFile,
2744 PVOID Block)
2745 {
2746 if (RegistryFile->Filename != NULL)
2747 {
2748 UNIMPLEMENTED;
2749 }
2750 }
2751
2752 #endif
2753
2754 /* EOF */