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