Renamed pseudo target 'floppy' to 'install'
[reactos.git] / reactos / ntoskrnl / cm / registry.c
1 /* $Id: registry.c,v 1.25 2000/08/11 12:39:25 ekohl 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"\\SystemRoot\\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 {
1226 UNIMPLEMENTED;
1227 }
1228
1229
1230 NTSTATUS
1231 STDCALL
1232 NtReplaceKey (
1233 IN POBJECT_ATTRIBUTES ObjectAttributes,
1234 IN HANDLE Key,
1235 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
1236 )
1237 {
1238 UNIMPLEMENTED;
1239 }
1240
1241
1242 NTSTATUS
1243 STDCALL
1244 NtRestoreKey (
1245 IN HANDLE KeyHandle,
1246 IN HANDLE FileHandle,
1247 IN ULONG RestoreFlags
1248 )
1249 {
1250 UNIMPLEMENTED;
1251 }
1252
1253
1254 NTSTATUS
1255 STDCALL
1256 NtSaveKey (
1257 IN HANDLE KeyHandle,
1258 IN HANDLE FileHandle
1259 )
1260 {
1261 UNIMPLEMENTED;
1262 }
1263
1264
1265 NTSTATUS
1266 STDCALL
1267 NtSetInformationKey (
1268 IN HANDLE KeyHandle,
1269 IN CINT KeyInformationClass,
1270 IN PVOID KeyInformation,
1271 IN ULONG KeyInformationLength
1272 )
1273 {
1274 UNIMPLEMENTED;
1275 }
1276
1277
1278 NTSTATUS
1279 STDCALL
1280 NtUnloadKey (
1281 HANDLE KeyHandle
1282 )
1283 {
1284 UNIMPLEMENTED;
1285 }
1286
1287
1288 NTSTATUS
1289 STDCALL
1290 NtInitializeRegistry (
1291 BOOLEAN SetUpBoot
1292 )
1293 {
1294 UNIMPLEMENTED;
1295 }
1296
1297
1298 NTSTATUS
1299 STDCALL
1300 RtlCheckRegistryKey (
1301 IN ULONG RelativeTo,
1302 IN PWSTR Path
1303 )
1304 {
1305 UNIMPLEMENTED;
1306 }
1307
1308
1309 NTSTATUS
1310 STDCALL
1311 RtlCreateRegistryKey (
1312 IN ULONG RelativeTo,
1313 IN PWSTR Path
1314 )
1315 {
1316 UNIMPLEMENTED;
1317 }
1318
1319
1320 NTSTATUS
1321 STDCALL
1322 RtlDeleteRegistryValue (
1323 IN ULONG RelativeTo,
1324 IN PWSTR Path,
1325 IN PWSTR ValueName
1326 )
1327 {
1328 UNIMPLEMENTED;
1329 }
1330
1331
1332 NTSTATUS
1333 STDCALL
1334 RtlQueryRegistryValues (
1335 IN ULONG RelativeTo,
1336 IN PWSTR Path,
1337 IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
1338 IN PVOID Context,
1339 IN PVOID Environment
1340 )
1341 {
1342 UNIMPLEMENTED;
1343 }
1344
1345
1346 NTSTATUS
1347 STDCALL
1348 RtlWriteRegistryValue (
1349 IN ULONG RelativeTo,
1350 IN PWSTR Path,
1351 IN PWSTR ValueName,
1352 IN ULONG ValueType,
1353 IN PVOID ValueData,
1354 IN ULONG ValueLength
1355 )
1356 {
1357 UNIMPLEMENTED;
1358 }
1359
1360 /* ------------------------------------------ Private Implementation */
1361
1362
1363 #if PROTO_REG
1364 //static PVOID
1365 //CmiObjectParse(PVOID ParsedObject, PWSTR *Path)
1366 static NTSTATUS CmiObjectParse(PVOID ParsedObject,
1367 PVOID *NextObject,
1368 PUNICODE_STRING FullPath,
1369 PWSTR *Path)
1370 {
1371 NTSTATUS Status;
1372 /* FIXME: this should be allocated based on the largest subkey name */
1373 WCHAR CurKeyName[260];
1374 PWSTR Remainder, NextSlash;
1375 PREGISTRY_FILE RegistryFile;
1376 PKEY_OBJECT NewKeyObject;
1377 HANDLE KeyHandle;
1378 PKEY_BLOCK CurKeyBlock, SubKeyBlock;
1379
1380 Status = STATUS_SUCCESS;
1381
1382 /* FIXME: it should probably get this from ParsedObject */
1383 RegistryFile = CmiVolatileFile;
1384
1385 /* Scan key object list for key already open */
1386 NewKeyObject = CmiScanKeyList((*Path) + 1);
1387 if (NewKeyObject != NULL)
1388 {
1389 /* Return reference if found */
1390 ObReferenceObjectByPointer(NewKeyObject,
1391 STANDARD_RIGHTS_REQUIRED,
1392 NULL,
1393 UserMode);
1394 *Path = NULL;
1395
1396 // return NewKeyObject;
1397 //FIXME
1398 return Status;
1399 }
1400
1401 CurKeyBlock = CmiGetKeyBlock(RegistryFile,
1402 RegistryFile->HeaderBlock->RootKeyBlock);
1403
1404 /* Loop through each key level and find the needed subkey */
1405 Remainder = (*Path) + 1;
1406 while (NT_SUCCESS(Status) && *Remainder != 0)
1407 {
1408 NextSlash = wcschr(Remainder, L'\\');
1409
1410 /* Copy just the current subkey name to a buffer */
1411 if (NextSlash != NULL)
1412 {
1413 wcsncpy(CurKeyName, Remainder, NextSlash - Remainder);
1414 CurKeyName[NextSlash - Remainder] = 0;
1415 }
1416 else
1417 {
1418 wcscpy(CurKeyName, Remainder);
1419 }
1420
1421 /* Verify existance of CurKeyName */
1422 Status = CmiScanForSubKey(RegistryFile,
1423 CurKeyBlock,
1424 &SubKeyBlock,
1425 CurKeyName,
1426 STANDARD_RIGHTS_REQUIRED);
1427 if (!NT_SUCCESS(Status))
1428 {
1429 continue;
1430 }
1431 if (SubKeyBlock == NULL)
1432 {
1433 Status = STATUS_UNSUCCESSFUL;
1434 continue;
1435 }
1436 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1437 CurKeyBlock = SubKeyBlock;
1438
1439 if (NextSlash != NULL)
1440 {
1441 Remainder = NextSlash + 1;
1442 }
1443 else
1444 {
1445 Remainder = NULL;
1446 }
1447 }
1448
1449 /* Create new key object and put into linked list */
1450 NewKeyObject = ObCreateObject(&KeyHandle,
1451 STANDARD_RIGHTS_REQUIRED,
1452 NULL,
1453 CmiKeyType);
1454 if (NewKeyObject == NULL)
1455 {
1456 //FIXME : return the good error code
1457 return STATUS_UNSUCCESSFUL;
1458 }
1459 NewKeyObject->Flags = 0;
1460 NewKeyObject->Name = ExAllocatePool(NonPagedPool,
1461 wcslen(*Path) * sizeof(WCHAR));
1462 wcscpy(NewKeyObject->Name, (*Path) + 1);
1463 NewKeyObject->KeyBlock = CurKeyBlock;
1464 NewKeyObject->RegistryFile = RegistryFile;
1465 CmiAddKeyToList(NewKeyObject);
1466 *Path = (Remainder != NULL) ? Remainder - 1 : NULL;
1467
1468 NextObject = (PVOID)NewKeyObject;
1469 return STATUS_SUCCESS;
1470 }
1471
1472 static VOID
1473 CmiObjectDelete(PVOID DeletedObject)
1474 {
1475 PKEY_OBJECT KeyObject;
1476
1477 KeyObject = (PKEY_OBJECT) DeletedObject;
1478 if (KeyObject->Flags & KO_MARKED_FOR_DELETE)
1479 {
1480 CmiDestroyKeyBlock(KeyObject->RegistryFile,
1481 KeyObject->KeyBlock);
1482 }
1483 else
1484 {
1485 CmiReleaseBlock(KeyObject->RegistryFile,
1486 KeyObject->KeyBlock);
1487 }
1488 ExFreePool(KeyObject->Name);
1489 CmiRemoveKeyFromList(KeyObject);
1490 }
1491
1492 static NTSTATUS
1493 CmiBuildKeyPath(PWSTR *KeyPath, POBJECT_ATTRIBUTES ObjectAttributes)
1494 {
1495 NTSTATUS Status;
1496 ULONG KeyNameSize;
1497 PWSTR KeyNameBuf;
1498 PVOID ObjectBody;
1499 PKEY_OBJECT KeyObject;
1500 POBJECT_HEADER ObjectHeader;
1501
1502 /* FIXME: Verify ObjectAttributes is in \\Registry space and compute size for path */
1503 KeyNameSize = 0;
1504 ObjectHeader = 0;
1505 if (ObjectAttributes->RootDirectory != NULL)
1506 {
1507 /* FIXME: determine type of object for RootDirectory */
1508 Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
1509 KEY_READ,
1510 NULL,
1511 UserMode,
1512 (PVOID *)&ObjectBody,
1513 NULL);
1514 if (!NT_SUCCESS(Status))
1515 {
1516 return Status;
1517 }
1518 ObjectHeader = BODY_TO_HEADER(ObjectBody);
1519
1520 if (ObjectHeader->ObjectType != CmiKeyType)
1521 {
1522 /* Fail if RootDirectory != '\\' */
1523 if (ObjectBody == NameSpaceRoot)
1524 {
1525 /* Check for 'Registry' in ObjectName, fail if missing */
1526 if (wcsncmp(ObjectAttributes->ObjectName->Buffer,
1527 REG_ROOT_KEY_NAME + 1,
1528 wcslen(REG_ROOT_KEY_NAME + 1)) != 0 ||
1529 ObjectAttributes->ObjectName->Buffer[wcslen(REG_ROOT_KEY_NAME + 1)] != L'\\')
1530 {
1531 ObDereferenceObject(ObjectBody);
1532
1533 return STATUS_OBJECT_PATH_INVALID;
1534 }
1535
1536 /* Compute size of registry portion of path to KeyNameSize */
1537 KeyNameSize = (ObjectAttributes->ObjectName->Length -
1538 (wcslen(REG_ROOT_KEY_NAME + 1) + 1))
1539 * sizeof(WCHAR);
1540 }
1541 else if (!wcscmp(ObjectHeader->Name.Buffer,
1542 REG_ROOT_KEY_NAME + 1))
1543 {
1544 /* Add size of ObjectName to KeyNameSize */
1545 KeyNameSize = ObjectAttributes->ObjectName->Length;
1546 }
1547 else
1548 {
1549 ObDereferenceObject(ObjectBody);
1550
1551 return STATUS_OBJECT_PATH_INVALID;
1552 }
1553 }
1554 else
1555 {
1556 KeyObject = (PKEY_OBJECT) ObjectBody;
1557
1558 /* Add size of Name from RootDirectory object to KeyNameSize */
1559 KeyNameSize = wcslen(KeyObject->Name) * sizeof(WCHAR);
1560
1561 /* Add 1 to KeyNamesize for '\\' */
1562 KeyNameSize += sizeof(WCHAR);
1563
1564 /* Add size of ObjectName to KeyNameSize */
1565 KeyNameSize += ObjectAttributes->ObjectName->Length * sizeof(WCHAR);
1566 }
1567 }
1568 else
1569 {
1570 /* Check for \\Registry and fail if missing */
1571 if (wcsncmp(ObjectAttributes->ObjectName->Buffer,
1572 REG_ROOT_KEY_NAME,
1573 wcslen(REG_ROOT_KEY_NAME)) != 0 ||
1574 ObjectAttributes->ObjectName->Buffer[wcslen(REG_ROOT_KEY_NAME)] != L'\\')
1575 {
1576 return STATUS_OBJECT_PATH_INVALID;
1577 }
1578
1579 /* Compute size of registry portion of path to KeyNameSize */
1580 KeyNameSize = (ObjectAttributes->ObjectName->Length -
1581 (wcslen(REG_ROOT_KEY_NAME) + 1)) * sizeof(WCHAR);
1582 }
1583
1584 KeyNameBuf = ExAllocatePool(NonPagedPool, KeyNameSize + sizeof(WCHAR));
1585
1586 /* Construct relative pathname */
1587 KeyNameBuf[0] = 0;
1588 if (ObjectAttributes->RootDirectory != NULL)
1589 {
1590 if (ObjectHeader->ObjectType != CmiKeyType)
1591 {
1592 /* Fail if RootDirectory != '\\' */
1593 if (ObjectBody == NameSpaceRoot)
1594 {
1595 /* Copy remainder of ObjectName after 'Registry' */
1596 wcscpy(KeyNameBuf, ObjectAttributes->ObjectName->Buffer + wcslen(REG_ROOT_KEY_NAME + 1));
1597 }
1598 else
1599 {
1600 /* Copy all of ObjectName */
1601 wcscpy(KeyNameBuf, ObjectAttributes->ObjectName->Buffer);
1602 }
1603 }
1604 else
1605 {
1606 KeyObject = (PKEY_OBJECT) ObjectBody;
1607
1608 /* Copy Name from RootDirectory object to KeyNameBuf */
1609 wcscpy(KeyNameBuf, KeyObject->Name);
1610
1611 /* Append '\\' onto KeyNameBuf */
1612 wcscat(KeyNameBuf, L"\\");
1613
1614 /* Append ObjectName onto KeyNameBuf */
1615 wcscat(KeyNameBuf, ObjectAttributes->ObjectName->Buffer);
1616 }
1617 }
1618 else
1619 {
1620 /* Copy registry portion of path into KeyNameBuf */
1621 wcscpy(KeyNameBuf, ObjectAttributes->ObjectName->Buffer +
1622 (wcslen(REG_ROOT_KEY_NAME) + 1));
1623 }
1624
1625 *KeyPath = KeyNameBuf;
1626 return STATUS_SUCCESS;
1627 }
1628
1629 static VOID
1630 CmiAddKeyToList(PKEY_OBJECT NewKey)
1631 {
1632 KIRQL OldIrql;
1633
1634 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
1635 NewKey->NextKey = CmiKeyList;
1636 CmiKeyList = NewKey;
1637 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
1638 }
1639
1640 static VOID
1641 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove)
1642 {
1643 KIRQL OldIrql;
1644 PKEY_OBJECT CurKey;
1645
1646 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
1647 if (CmiKeyList == KeyToRemove)
1648 {
1649 CmiKeyList = CmiKeyList->NextKey;
1650 }
1651 else
1652 {
1653 CurKey = CmiKeyList;
1654 while (CurKey != NULL && CurKey->NextKey != KeyToRemove)
1655 {
1656 CurKey = CurKey->NextKey;
1657 }
1658 if (CurKey != NULL)
1659 {
1660 CurKey->NextKey = KeyToRemove->NextKey;
1661 }
1662 }
1663 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
1664 }
1665
1666 static PKEY_OBJECT
1667 CmiScanKeyList(PWSTR KeyName)
1668 {
1669 KIRQL OldIrql;
1670 PKEY_OBJECT CurKey;
1671
1672 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
1673 CurKey = CmiKeyList;
1674 while (CurKey != NULL && wcscmp(KeyName, CurKey->Name) != 0)
1675 {
1676 CurKey = CurKey->NextKey;
1677 }
1678 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
1679
1680 return CurKey;
1681 }
1682
1683 static PREGISTRY_FILE
1684 CmiCreateRegistry(PWSTR Filename)
1685 {
1686 PREGISTRY_FILE RegistryFile;
1687 PKEY_BLOCK RootKeyBlock;
1688
1689 RegistryFile = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_FILE));
1690 if (Filename != NULL)
1691 {
1692 UNIMPLEMENTED;
1693 /* FIXME: Duplicate Filename */
1694 /* FIXME: if file does not exist, create new file */
1695 /* FIXME: else attempt to map the file */
1696 }
1697 else
1698 {
1699 RegistryFile->Filename = NULL;
1700 RegistryFile->FileHandle = NULL;
1701
1702 RegistryFile->HeaderBlock = (PHEADER_BLOCK)
1703 ExAllocatePool(NonPagedPool, sizeof(HEADER_BLOCK));
1704 RtlZeroMemory(RegistryFile->HeaderBlock, sizeof(HEADER_BLOCK));
1705 RegistryFile->HeaderBlock->BlockId = 0x66676572;
1706 RegistryFile->HeaderBlock->DateModified.QuadPart = 0;
1707 RegistryFile->HeaderBlock->Unused2 = 1;
1708 RegistryFile->HeaderBlock->Unused3 = 3;
1709 RegistryFile->HeaderBlock->Unused5 = 1;
1710 RegistryFile->HeaderBlock->RootKeyBlock = 0;
1711 RegistryFile->HeaderBlock->BlockSize = REG_BLOCK_SIZE;
1712 RegistryFile->HeaderBlock->Unused6 = 1;
1713 RegistryFile->HeaderBlock->Checksum = 0;
1714 RootKeyBlock = (PKEY_BLOCK)
1715 ExAllocatePool(NonPagedPool, sizeof(KEY_BLOCK));
1716 RtlZeroMemory(RootKeyBlock, sizeof(KEY_BLOCK));
1717 RootKeyBlock->SubBlockId = REG_KEY_BLOCK_ID;
1718 RootKeyBlock->Type = REG_ROOT_KEY_BLOCK_TYPE;
1719 ZwQuerySystemTime((PTIME) &RootKeyBlock->LastWriteTime);
1720 RootKeyBlock->ParentKeyOffset = 0;
1721 RootKeyBlock->NumberOfSubKeys = 0;
1722 RootKeyBlock->HashTableOffset = 0;
1723 RootKeyBlock->NumberOfValues = 0;
1724 RootKeyBlock->ValuesOffset = 0;
1725 RootKeyBlock->SecurityKeyOffset = 0;
1726 RootKeyBlock->ClassNameOffset = sizeof(KEY_BLOCK);
1727 RootKeyBlock->NameSize = 0;
1728 RootKeyBlock->ClassSize = 0;
1729 RootKeyBlock->Name[0] = 0;
1730 RegistryFile->HeaderBlock->RootKeyBlock = (BLOCK_OFFSET) RootKeyBlock;
1731 }
1732
1733 return RegistryFile;
1734 }
1735
1736 static NTSTATUS
1737 CmiCreateKey(IN PREGISTRY_FILE RegistryFile,
1738 IN PWSTR KeyNameBuf,
1739 OUT PKEY_BLOCK *KeyBlock,
1740 IN ACCESS_MASK DesiredAccess,
1741 IN ULONG TitleIndex,
1742 IN PUNICODE_STRING Class,
1743 IN ULONG CreateOptions,
1744 OUT PULONG Disposition)
1745 {
1746 /* FIXME: this should be allocated based on the largest subkey name */
1747 NTSTATUS Status;
1748 WCHAR CurKeyName[256];
1749 PWSTR ClassName;
1750 PWSTR Remainder, NextSlash;
1751 PKEY_BLOCK CurKeyBlock, SubKeyBlock;
1752
1753 /* FIXME: Should handle search by Class/TitleIndex */
1754
1755 CHECKPOINT;
1756 /* Loop through each key level and find or build the needed subkey */
1757 Status = STATUS_SUCCESS;
1758 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1759 CurKeyBlock = CmiGetKeyBlock(RegistryFile,
1760 RegistryFile->HeaderBlock->RootKeyBlock);
1761 CHECKPOINT;
1762 Remainder = KeyNameBuf;
1763 while (NT_SUCCESS(Status) &&
1764 (NextSlash = wcschr(Remainder, L'\\')) != NULL)
1765 {
1766 /* Copy just the current subkey name to a buffer */
1767 wcsncpy(CurKeyName, Remainder, NextSlash - Remainder);
1768 CurKeyName[NextSlash - Remainder] = 0;
1769
1770 /* Verify existance of/Create CurKeyName */
1771 CHECKPOINT;
1772 Status = CmiScanForSubKey(RegistryFile,
1773 CurKeyBlock,
1774 &SubKeyBlock,
1775 CurKeyName,
1776 DesiredAccess);
1777 if (!NT_SUCCESS(Status))
1778 {
1779 continue;
1780 }
1781 if (SubKeyBlock == NULL)
1782 {
1783 Status = CmiAddSubKey(RegistryFile,
1784 CurKeyBlock,
1785 &SubKeyBlock,
1786 CurKeyName,
1787 0,
1788 NULL,
1789 0);
1790 if (!NT_SUCCESS(Status))
1791 {
1792 continue;
1793 }
1794 }
1795 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1796 CurKeyBlock = SubKeyBlock;
1797
1798 Remainder = NextSlash + 1;
1799 }
1800 CHECKPOINT;
1801 if (NT_SUCCESS(Status))
1802 {
1803 CHECKPOINT;
1804 Status = CmiScanForSubKey(RegistryFile,
1805 CurKeyBlock,
1806 &SubKeyBlock,
1807 CurKeyName,
1808 DesiredAccess);
1809 if (NT_SUCCESS(Status))
1810 {
1811 if (SubKeyBlock == NULL)
1812 {
1813 if (Class != NULL)
1814 {
1815 ClassName = ExAllocatePool(NonPagedPool, Class->Length + 1);
1816 wcsncpy(ClassName, Class->Buffer, Class->Length);
1817 ClassName[Class->Length] = 0;
1818 }
1819 else
1820 {
1821 ClassName = 0;
1822 }
1823 Status = CmiAddSubKey(RegistryFile,
1824 CurKeyBlock,
1825 &SubKeyBlock,
1826 Remainder,
1827 TitleIndex,
1828 ClassName,
1829 CreateOptions);
1830 if (ClassName != NULL)
1831 {
1832 ExFreePool(ClassName);
1833 }
1834 if (NT_SUCCESS(Status) && Disposition != NULL)
1835 {
1836 *Disposition = REG_CREATED_NEW_KEY;
1837 }
1838 }
1839 else if (Disposition != NULL)
1840 {
1841 *Disposition = REG_OPENED_EXISTING_KEY;
1842 }
1843 }
1844 *KeyBlock = SubKeyBlock;
1845 }
1846 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1847
1848 return Status;
1849 }
1850
1851 static NTSTATUS
1852 CmiFindKey(IN PREGISTRY_FILE RegistryFile,
1853 IN PWSTR KeyNameBuf,
1854 OUT PKEY_BLOCK *KeyBlock,
1855 IN ACCESS_MASK DesiredAccess,
1856 IN ULONG TitleIndex,
1857 IN PUNICODE_STRING Class)
1858 {
1859 /* FIXME: this should be allocated based on the largest subkey name */
1860 NTSTATUS Status;
1861 WCHAR CurKeyName[256];
1862 PWSTR Remainder, NextSlash;
1863 PKEY_BLOCK CurKeyBlock, SubKeyBlock;
1864
1865 /* FIXME: Should handle search by Class/TitleIndex */
1866
1867 /* Loop through each key level and find the needed subkey */
1868 Status = STATUS_SUCCESS;
1869 /* FIXME: this access of RootKeyBlock should be guarded by spinlock */
1870 CurKeyBlock = CmiGetKeyBlock(RegistryFile, RegistryFile->HeaderBlock->RootKeyBlock);
1871 Remainder = KeyNameBuf;
1872 while (NT_SUCCESS(Status) &&
1873 (NextSlash = wcschr(Remainder, L'\\')) != NULL)
1874 {
1875 /* Copy just the current subkey name to a buffer */
1876 wcsncpy(CurKeyName, Remainder, NextSlash - Remainder);
1877 CurKeyName[NextSlash - Remainder] = 0;
1878
1879 /* Verify existance of CurKeyName */
1880 Status = CmiScanForSubKey(RegistryFile,
1881 CurKeyBlock,
1882 &SubKeyBlock,
1883 CurKeyName,
1884 DesiredAccess);
1885 if (!NT_SUCCESS(Status))
1886 {
1887 continue;
1888 }
1889 if (SubKeyBlock == NULL)
1890 {
1891 Status = STATUS_UNSUCCESSFUL;
1892 continue;
1893 }
1894 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1895 CurKeyBlock = SubKeyBlock;
1896
1897 Remainder = NextSlash + 1;
1898 }
1899 if (NT_SUCCESS(Status))
1900 {
1901 Status = CmiScanForSubKey(RegistryFile,
1902 CurKeyBlock,
1903 &SubKeyBlock,
1904 CurKeyName,
1905 DesiredAccess);
1906 if (NT_SUCCESS(Status))
1907 {
1908 if (SubKeyBlock == NULL)
1909 {
1910 Status = STATUS_UNSUCCESSFUL;
1911 }
1912 else
1913 {
1914 *KeyBlock = SubKeyBlock;
1915 }
1916 }
1917 }
1918 CmiReleaseBlock(RegistryFile, CurKeyBlock);
1919
1920 return Status;
1921 }
1922
1923 static ULONG
1924 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile,
1925 PKEY_BLOCK KeyBlock)
1926 {
1927 ULONG Idx, MaxName;
1928 PHASH_TABLE_BLOCK HashBlock;
1929 PKEY_BLOCK CurSubKeyBlock;
1930
1931 MaxName = 0;
1932 HashBlock = CmiGetHashTableBlock(RegistryFile, KeyBlock->HashTableOffset);
1933 if (HashBlock == 0)
1934 {
1935 return 0;
1936 }
1937 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
1938 {
1939 if (HashBlock->Table[Idx].KeyOffset != 0)
1940 {
1941 CurSubKeyBlock = CmiGetKeyBlock(RegistryFile,
1942 HashBlock->Table[Idx].KeyOffset);
1943 if (MaxName < CurSubKeyBlock->NameSize)
1944 {
1945 MaxName = CurSubKeyBlock->NameSize;
1946 }
1947 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
1948 }
1949 }
1950
1951 CmiReleaseBlock(RegistryFile, HashBlock);
1952
1953 return MaxName;
1954 }
1955
1956 static ULONG
1957 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile,
1958 PKEY_BLOCK KeyBlock)
1959 {
1960 ULONG Idx, MaxClass;
1961 PHASH_TABLE_BLOCK HashBlock;
1962 PKEY_BLOCK CurSubKeyBlock;
1963
1964 MaxClass = 0;
1965 HashBlock = CmiGetHashTableBlock(RegistryFile, KeyBlock->HashTableOffset);
1966 if (HashBlock == 0)
1967 {
1968 return 0;
1969 }
1970 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
1971 {
1972 if (HashBlock->Table[Idx].KeyOffset != 0)
1973 {
1974 CurSubKeyBlock = CmiGetKeyBlock(RegistryFile,
1975 HashBlock->Table[Idx].KeyOffset);
1976 if (MaxClass < CurSubKeyBlock->ClassSize)
1977 {
1978 MaxClass = CurSubKeyBlock->ClassSize;
1979 }
1980 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
1981 }
1982 }
1983
1984 CmiReleaseBlock(RegistryFile, HashBlock);
1985
1986 return MaxClass;
1987 }
1988
1989 static ULONG
1990 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile,
1991 PKEY_BLOCK KeyBlock)
1992 {
1993 ULONG Idx, MaxValueName;
1994 PVALUE_LIST_BLOCK ValueListBlock;
1995 PVALUE_BLOCK CurValueBlock;
1996
1997 ValueListBlock = CmiGetBlock(RegistryFile,
1998 KeyBlock->ValuesOffset);
1999 MaxValueName = 0;
2000 if (ValueListBlock == 0)
2001 {
2002 return 0;
2003 }
2004 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
2005 {
2006 CurValueBlock = CmiGetBlock(RegistryFile,
2007 ValueListBlock->Values[Idx]);
2008 if (CurValueBlock != NULL &&
2009 MaxValueName < CurValueBlock->NameSize)
2010 {
2011 MaxValueName = CurValueBlock->NameSize;
2012 }
2013 CmiReleaseBlock(RegistryFile, CurValueBlock);
2014 }
2015
2016 CmiReleaseBlock(RegistryFile, ValueListBlock);
2017
2018 return MaxValueName;
2019 }
2020
2021 static ULONG
2022 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile,
2023 PKEY_BLOCK KeyBlock)
2024 {
2025 ULONG Idx, MaxValueData;
2026 PVALUE_LIST_BLOCK ValueListBlock;
2027 PVALUE_BLOCK CurValueBlock;
2028
2029 ValueListBlock = CmiGetBlock(RegistryFile,
2030 KeyBlock->ValuesOffset);
2031 MaxValueData = 0;
2032 if (ValueListBlock == 0)
2033 {
2034 return 0;
2035 }
2036 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
2037 {
2038 CurValueBlock = CmiGetBlock(RegistryFile,
2039 ValueListBlock->Values[Idx]);
2040 if (CurValueBlock != NULL &&
2041 MaxValueData < CurValueBlock->DataSize)
2042 {
2043 MaxValueData = CurValueBlock->DataSize;
2044 }
2045 CmiReleaseBlock(RegistryFile, CurValueBlock);
2046 }
2047
2048 CmiReleaseBlock(RegistryFile, ValueListBlock);
2049
2050 return MaxValueData;
2051 }
2052
2053 static NTSTATUS
2054 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile,
2055 IN PKEY_BLOCK KeyBlock,
2056 OUT PKEY_BLOCK *SubKeyBlock,
2057 IN PWSTR KeyName,
2058 IN ACCESS_MASK DesiredAccess)
2059 {
2060 ULONG Idx;
2061 PHASH_TABLE_BLOCK HashBlock;
2062 PKEY_BLOCK CurSubKeyBlock;
2063
2064 HashBlock = CmiGetHashTableBlock(RegistryFile, KeyBlock->HashTableOffset);
2065 *SubKeyBlock = NULL;
2066 if (HashBlock == 0)
2067 {
2068 return STATUS_SUCCESS;
2069 }
2070 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
2071 {
2072 if (HashBlock->Table[Idx].KeyOffset != 0 &&
2073 !wcsncmp(KeyName, (PWSTR) &HashBlock->Table[Idx].HashValue, 4))
2074 {
2075 CurSubKeyBlock = CmiGetKeyBlock(RegistryFile,
2076 HashBlock->Table[Idx].KeyOffset);
2077 if (!wcscmp(KeyName, CurSubKeyBlock->Name))
2078 {
2079 *SubKeyBlock = CurSubKeyBlock;
2080 break;
2081 }
2082 else
2083 {
2084 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
2085 }
2086 }
2087 }
2088
2089 CmiReleaseBlock(RegistryFile, HashBlock);
2090
2091 return STATUS_SUCCESS;
2092 }
2093
2094 static NTSTATUS
2095 CmiAddSubKey(PREGISTRY_FILE RegistryFile,
2096 PKEY_BLOCK KeyBlock,
2097 PKEY_BLOCK *SubKeyBlock,
2098 PWSTR NewSubKeyName,
2099 ULONG TitleIndex,
2100 PWSTR Class,
2101 ULONG CreateOptions)
2102 {
2103 NTSTATUS Status;
2104 PHASH_TABLE_BLOCK HashBlock, NewHashBlock;
2105 PKEY_BLOCK NewKeyBlock;
2106
2107 Status = CmiAllocateKeyBlock(RegistryFile,
2108 &NewKeyBlock,
2109 NewSubKeyName,
2110 TitleIndex,
2111 Class,
2112 CreateOptions);
2113 if (!NT_SUCCESS(Status))
2114 {
2115 return Status;
2116 }
2117 if (KeyBlock->HashTableOffset == 0)
2118 {
2119 Status = CmiAllocateHashTableBlock(RegistryFile,
2120 &HashBlock,
2121 REG_INIT_HASH_TABLE_SIZE);
2122 if (!NT_SUCCESS(Status))
2123 {
2124 return Status;
2125 }
2126 KeyBlock->HashTableOffset = CmiGetBlockOffset(RegistryFile, HashBlock);
2127 }
2128 else
2129 {
2130 HashBlock = CmiGetHashTableBlock(RegistryFile, KeyBlock->HashTableOffset);
2131 if (KeyBlock->NumberOfSubKeys + 1 >= HashBlock->HashTableSize)
2132 {
2133
2134 /* FIXME: All Subkeys will need to be rehashed here! */
2135
2136 /* Reallocate the hash table block */
2137 Status = CmiAllocateHashTableBlock(RegistryFile,
2138 &NewHashBlock,
2139 HashBlock->HashTableSize +
2140 REG_EXTEND_HASH_TABLE_SIZE);
2141 if (!NT_SUCCESS(Status))
2142 {
2143 return Status;
2144 }
2145 RtlZeroMemory(&NewHashBlock->Table[0],
2146 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2147 RtlCopyMemory(&NewHashBlock->Table[0],
2148 &HashBlock->Table[0],
2149 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2150 KeyBlock->HashTableOffset = CmiGetBlockOffset(RegistryFile, NewHashBlock);
2151 CmiDestroyHashTableBlock(RegistryFile, HashBlock);
2152 HashBlock = NewHashBlock;
2153 }
2154 }
2155 Status = CmiAddKeyToHashTable(RegistryFile, HashBlock, NewKeyBlock);
2156 if (NT_SUCCESS(Status))
2157 {
2158 KeyBlock->NumberOfSubKeys++;
2159 *SubKeyBlock = NewKeyBlock;
2160 }
2161 CmiReleaseBlock(RegistryFile, HashBlock);
2162
2163 return Status;
2164 }
2165
2166 static NTSTATUS
2167 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile,
2168 IN PKEY_BLOCK KeyBlock,
2169 IN PWSTR ValueName,
2170 OUT PVALUE_BLOCK *ValueBlock)
2171 {
2172 ULONG Idx;
2173 PVALUE_LIST_BLOCK ValueListBlock;
2174 PVALUE_BLOCK CurValueBlock;
2175
2176 ValueListBlock = CmiGetBlock(RegistryFile,
2177 KeyBlock->ValuesOffset);
2178 *ValueBlock = NULL;
2179 if (ValueListBlock == 0)
2180 {
2181 return STATUS_SUCCESS;
2182 }
2183 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
2184 {
2185 CurValueBlock = CmiGetBlock(RegistryFile,
2186 ValueListBlock->Values[Idx]);
2187 if (CurValueBlock != NULL &&
2188 !wcscmp(CurValueBlock->Name, ValueName))
2189 {
2190 *ValueBlock = CurValueBlock;
2191 break;
2192 }
2193 CmiReleaseBlock(RegistryFile, CurValueBlock);
2194 }
2195
2196 CmiReleaseBlock(RegistryFile, ValueListBlock);
2197
2198 return STATUS_SUCCESS;
2199 }
2200
2201 static NTSTATUS
2202 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile,
2203 IN PKEY_BLOCK KeyBlock,
2204 IN PWSTR ValueNameBuf,
2205 IN ULONG Type,
2206 IN PVOID Data,
2207 IN ULONG DataSize)
2208 {
2209 NTSTATUS Status;
2210 PVALUE_LIST_BLOCK ValueListBlock, NewValueListBlock;
2211 PVALUE_BLOCK ValueBlock;
2212
2213 Status = CmiAllocateValueBlock(RegistryFile,
2214 &ValueBlock,
2215 ValueNameBuf,
2216 Type,
2217 Data,
2218 DataSize);
2219 if (!NT_SUCCESS(Status))
2220 {
2221 return Status;
2222 }
2223 ValueListBlock = CmiGetBlock(RegistryFile,
2224 KeyBlock->ValuesOffset);
2225 if (ValueListBlock == NULL)
2226 {
2227 Status = CmiAllocateBlock(RegistryFile,
2228 (PVOID) &ValueListBlock,
2229 sizeof(BLOCK_OFFSET) *
2230 REG_VALUE_LIST_BLOCK_MULTIPLE);
2231 if (!NT_SUCCESS(Status))
2232 {
2233 CmiDestroyValueBlock(RegistryFile,
2234 ValueBlock);
2235 return Status;
2236 }
2237 }
2238 else if (KeyBlock->NumberOfValues % REG_VALUE_LIST_BLOCK_MULTIPLE)
2239 {
2240 Status = CmiAllocateBlock(RegistryFile,
2241 (PVOID) &NewValueListBlock,
2242 sizeof(BLOCK_OFFSET) *
2243 (KeyBlock->NumberOfValues +
2244 REG_VALUE_LIST_BLOCK_MULTIPLE));
2245 if (!NT_SUCCESS(Status))
2246 {
2247 CmiDestroyValueBlock(RegistryFile,
2248 ValueBlock);
2249 return Status;
2250 }
2251 RtlCopyMemory(NewValueListBlock,
2252 ValueListBlock,
2253 sizeof(BLOCK_OFFSET) * KeyBlock->NumberOfValues);
2254 KeyBlock->ValuesOffset = CmiGetBlockOffset(RegistryFile,
2255 NewValueListBlock);
2256 CmiDestroyBlock(RegistryFile, ValueListBlock);
2257 ValueListBlock = NewValueListBlock;
2258 }
2259 ValueListBlock->Values[KeyBlock->NumberOfValues] =
2260 CmiGetBlockOffset(RegistryFile, ValueBlock);
2261 KeyBlock->NumberOfValues++;
2262 CmiReleaseBlock(RegistryFile, ValueBlock);
2263 CmiReleaseBlock(RegistryFile, ValueListBlock);
2264
2265 return STATUS_SUCCESS;
2266 }
2267
2268 static NTSTATUS
2269 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile,
2270 IN PKEY_BLOCK KeyBlock,
2271 IN PWSTR ValueName)
2272 {
2273 ULONG Idx;
2274 PVALUE_LIST_BLOCK ValueListBlock;
2275 PVALUE_BLOCK CurValueBlock;
2276
2277 ValueListBlock = CmiGetBlock(RegistryFile,
2278 KeyBlock->ValuesOffset);
2279 if (ValueListBlock == 0)
2280 {
2281 return STATUS_SUCCESS;
2282 }
2283 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
2284 {
2285 CurValueBlock = CmiGetBlock(RegistryFile,
2286 ValueListBlock->Values[Idx]);
2287 if (CurValueBlock != NULL &&
2288 !wcscmp(CurValueBlock->Name, ValueName))
2289 {
2290 if (KeyBlock->NumberOfValues - 1 < Idx)
2291 {
2292 RtlCopyMemory(&ValueListBlock->Values[Idx],
2293 &ValueListBlock->Values[Idx + 1],
2294 sizeof(BLOCK_OFFSET) *
2295 (KeyBlock->NumberOfValues - 1 - Idx));
2296 }
2297 else
2298 {
2299 RtlZeroMemory(&ValueListBlock->Values[Idx],
2300 sizeof(BLOCK_OFFSET));
2301 }
2302 KeyBlock->NumberOfValues -= 1;
2303 CmiDestroyValueBlock(RegistryFile, CurValueBlock);
2304
2305 break;
2306 }
2307 CmiReleaseBlock(RegistryFile, CurValueBlock);
2308 }
2309
2310 CmiReleaseBlock(RegistryFile, ValueListBlock);
2311
2312 return STATUS_SUCCESS;
2313 }
2314
2315 static NTSTATUS
2316 CmiAllocateKeyBlock(IN PREGISTRY_FILE RegistryFile,
2317 OUT PKEY_BLOCK *KeyBlock,
2318 IN PWSTR KeyName,
2319 IN ULONG TitleIndex,
2320 IN PWSTR Class,
2321 IN ULONG CreateOptions)
2322 {
2323 NTSTATUS Status;
2324 ULONG NewKeySize;
2325 PKEY_BLOCK NewKeyBlock;
2326
2327 Status = STATUS_SUCCESS;
2328
2329 /* Handle volatile files first */
2330 if (RegistryFile->Filename == NULL)
2331 {
2332 NewKeySize = sizeof(KEY_BLOCK) +
2333 (wcslen(KeyName) + 1) * sizeof(WCHAR) +
2334 (Class != NULL ? (wcslen(Class) + 1) * sizeof(WCHAR) : 0);
2335 NewKeyBlock = ExAllocatePool(NonPagedPool, NewKeySize);
2336 if (NewKeyBlock == NULL)
2337 {
2338 Status = STATUS_INSUFFICIENT_RESOURCES;
2339 }
2340 else
2341 {
2342 RtlZeroMemory(NewKeyBlock, NewKeySize);
2343 NewKeyBlock->SubBlockId = REG_KEY_BLOCK_ID;
2344 NewKeyBlock->Type = REG_KEY_BLOCK_TYPE;
2345 ZwQuerySystemTime((PTIME) &NewKeyBlock->LastWriteTime);
2346 NewKeyBlock->ParentKeyOffset = 0;
2347 NewKeyBlock->NumberOfSubKeys = 0;
2348 NewKeyBlock->HashTableOffset = 0;
2349 NewKeyBlock->NumberOfValues = 0;
2350 NewKeyBlock->ValuesOffset = 0;
2351 NewKeyBlock->SecurityKeyOffset = 0;
2352 NewKeyBlock->ClassNameOffset = sizeof(KEY_BLOCK) + wcslen(KeyName);
2353 NewKeyBlock->NameSize = wcslen(KeyName);
2354 NewKeyBlock->ClassSize = (Class != NULL) ? wcslen(Class) : 0;
2355 wcscpy(NewKeyBlock->Name, KeyName);
2356 if (Class != NULL)
2357 {
2358 wcscpy(&NewKeyBlock->Name[wcslen(KeyName) + 1], Class);
2359 }
2360 CmiLockBlock(RegistryFile, NewKeyBlock);
2361 *KeyBlock = NewKeyBlock;
2362 }
2363 }
2364 else
2365 {
2366 UNIMPLEMENTED;
2367 }
2368
2369 return Status;
2370 }
2371
2372 static PKEY_BLOCK
2373 CmiGetKeyBlock(PREGISTRY_FILE RegistryFile,
2374 BLOCK_OFFSET KeyBlockOffset)
2375 {
2376 PKEY_BLOCK KeyBlock;
2377
2378 if (RegistryFile->Filename == NULL)
2379 {
2380 CmiLockBlock(RegistryFile, (PVOID) KeyBlockOffset);
2381
2382 KeyBlock = (PKEY_BLOCK) KeyBlockOffset;
2383 }
2384 else
2385 {
2386 UNIMPLEMENTED;
2387 }
2388
2389 return KeyBlock;
2390 }
2391
2392 static NTSTATUS
2393 CmiDestroyKeyBlock(PREGISTRY_FILE RegistryFile,
2394 PKEY_BLOCK KeyBlock)
2395 {
2396 NTSTATUS Status;
2397
2398 Status = STATUS_SUCCESS;
2399
2400 if (RegistryFile->Filename == NULL)
2401 {
2402 CmiReleaseBlock(RegistryFile, KeyBlock);
2403 ExFreePool(KeyBlock);
2404 }
2405 else
2406 {
2407 UNIMPLEMENTED;
2408 }
2409
2410 return Status;
2411 }
2412
2413 static NTSTATUS
2414 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile,
2415 OUT PHASH_TABLE_BLOCK *HashBlock,
2416 IN ULONG HashTableSize)
2417 {
2418 NTSTATUS Status;
2419 ULONG NewHashSize;
2420 PHASH_TABLE_BLOCK NewHashBlock;
2421
2422 Status = STATUS_SUCCESS;
2423
2424 /* Handle volatile files first */
2425 if (RegistryFile->Filename == NULL)
2426 {
2427 NewHashSize = sizeof(HASH_TABLE_BLOCK) +
2428 (HashTableSize - 1) * sizeof(HASH_RECORD);
2429 NewHashBlock = ExAllocatePool(NonPagedPool, NewHashSize);
2430 if (NewHashBlock == NULL)
2431 {
2432 Status = STATUS_INSUFFICIENT_RESOURCES;
2433 }
2434 else
2435 {
2436 RtlZeroMemory(NewHashBlock, NewHashSize);
2437 NewHashBlock->SubBlockId = REG_HASH_TABLE_BLOCK_ID;
2438 NewHashBlock->HashTableSize = HashTableSize;
2439 CmiLockBlock(RegistryFile, NewHashBlock);
2440 *HashBlock = NewHashBlock;
2441 }
2442 }
2443 else
2444 {
2445 UNIMPLEMENTED;
2446 }
2447
2448 return Status;
2449 }
2450
2451 static PHASH_TABLE_BLOCK
2452 CmiGetHashTableBlock(PREGISTRY_FILE RegistryFile,
2453 BLOCK_OFFSET HashBlockOffset)
2454 {
2455 PHASH_TABLE_BLOCK HashBlock;
2456
2457 if (RegistryFile->Filename == NULL)
2458 {
2459 CmiLockBlock(RegistryFile, (PVOID) HashBlockOffset);
2460
2461 HashBlock = (PHASH_TABLE_BLOCK) HashBlockOffset;
2462 }
2463 else
2464 {
2465 UNIMPLEMENTED;
2466 }
2467
2468 return HashBlock;
2469 }
2470
2471 static PKEY_BLOCK
2472 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile,
2473 PHASH_TABLE_BLOCK HashBlock,
2474 ULONG Index)
2475 {
2476 PKEY_BLOCK KeyBlock;
2477
2478 if (RegistryFile->Filename == NULL)
2479 {
2480 KeyBlock = (PKEY_BLOCK) HashBlock->Table[Index].KeyOffset;
2481 CmiLockBlock(RegistryFile, KeyBlock);
2482 }
2483 else
2484 {
2485 UNIMPLEMENTED;
2486 }
2487
2488 return KeyBlock;
2489 }
2490
2491 static NTSTATUS
2492 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile,
2493 PHASH_TABLE_BLOCK HashBlock,
2494 PKEY_BLOCK NewKeyBlock)
2495 {
2496 HashBlock->Table[HashBlock->HashTableSize].KeyOffset =
2497 CmiGetBlockOffset(RegistryFile, NewKeyBlock);
2498 RtlCopyMemory(&HashBlock->Table[HashBlock->HashTableSize].HashValue,
2499 NewKeyBlock->Name,
2500 4);
2501 HashBlock->HashTableSize++;
2502
2503 return STATUS_SUCCESS;
2504 }
2505
2506 static NTSTATUS
2507 CmiDestroyHashTableBlock(PREGISTRY_FILE RegistryFile,
2508 PHASH_TABLE_BLOCK HashBlock)
2509 {
2510 NTSTATUS Status;
2511
2512 Status = STATUS_SUCCESS;
2513
2514 if (RegistryFile->Filename == NULL)
2515 {
2516 CmiReleaseBlock(RegistryFile, HashBlock);
2517 ExFreePool(HashBlock);
2518 }
2519 else
2520 {
2521 Status = STATUS_NOT_IMPLEMENTED;
2522 }
2523
2524 return Status;
2525 }
2526
2527 static NTSTATUS
2528 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile,
2529 PVALUE_BLOCK *ValueBlock,
2530 IN PWSTR ValueNameBuf,
2531 IN ULONG Type,
2532 IN PVOID Data,
2533 IN ULONG DataSize)
2534 {
2535 NTSTATUS Status;
2536 ULONG NewValueSize;
2537 PVALUE_BLOCK NewValueBlock;
2538 PVOID DataBlock;
2539
2540 Status = STATUS_SUCCESS;
2541
2542 /* Handle volatile files first */
2543 if (RegistryFile->Filename == NULL)
2544 {
2545 NewValueSize = sizeof(VALUE_BLOCK) + wcslen(ValueNameBuf);
2546 NewValueBlock = ExAllocatePool(NonPagedPool, NewValueSize);
2547 if (NewValueBlock == NULL)
2548 {
2549 Status = STATUS_INSUFFICIENT_RESOURCES;
2550 }
2551 else
2552 {
2553 RtlZeroMemory(NewValueBlock, NewValueSize);
2554 NewValueBlock->SubBlockId = REG_VALUE_BLOCK_ID;
2555 NewValueBlock->NameSize = wcslen(ValueNameBuf);
2556 wcscpy(NewValueBlock->Name, ValueNameBuf);
2557 NewValueBlock->DataType = Type;
2558 NewValueBlock->DataSize = DataSize;
2559 Status = CmiAllocateBlock(RegistryFile,
2560 &DataBlock,
2561 DataSize);
2562 if (!NT_SUCCESS(Status))
2563 {
2564 ExFreePool(NewValueBlock);
2565 }
2566 else
2567 {
2568 RtlCopyMemory(DataBlock, Data, DataSize);
2569 NewValueBlock->DataOffset = CmiGetBlockOffset(RegistryFile,
2570 DataBlock);
2571 CmiLockBlock(RegistryFile, NewValueBlock);
2572 CmiReleaseBlock(RegistryFile, DataBlock);
2573 *ValueBlock = NewValueBlock;
2574 }
2575 }
2576 }
2577 else
2578 {
2579 Status = STATUS_NOT_IMPLEMENTED;
2580 }
2581
2582 return Status;
2583 }
2584
2585 static NTSTATUS
2586 CmiReplaceValueData(IN PREGISTRY_FILE RegistryFile,
2587 IN PVALUE_BLOCK ValueBlock,
2588 IN ULONG Type,
2589 IN PVOID Data,
2590 IN ULONG DataSize)
2591 {
2592 NTSTATUS Status;
2593 PVOID DataBlock, NewDataBlock;
2594
2595 Status = STATUS_SUCCESS;
2596
2597 /* If new data size is <= current then overwrite current data */
2598 if (DataSize <= ValueBlock->DataSize)
2599 {
2600 DataBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset);
2601 RtlCopyMemory(DataBlock, Data, DataSize);
2602 ValueBlock->DataSize = DataSize;
2603 ValueBlock->DataType = Type;
2604 CmiReleaseBlock(RegistryFile, DataBlock);
2605 }
2606 else
2607 {
2608 /* Destroy current data block and allocate a new one */
2609 DataBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset);
2610 Status = CmiAllocateBlock(RegistryFile,
2611 &NewDataBlock,
2612 DataSize);
2613 RtlCopyMemory(NewDataBlock, Data, DataSize);
2614 ValueBlock->DataOffset = CmiGetBlockOffset(RegistryFile, DataBlock);
2615 ValueBlock->DataSize = DataSize;
2616 ValueBlock->DataType = Type;
2617 CmiReleaseBlock(RegistryFile, NewDataBlock);
2618 CmiDestroyBlock(RegistryFile, DataBlock);
2619 }
2620
2621 return Status;
2622 }
2623
2624 static NTSTATUS
2625 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile,
2626 PVALUE_BLOCK ValueBlock)
2627 {
2628 NTSTATUS Status;
2629
2630 Status = CmiDestroyBlock(RegistryFile,
2631 CmiGetBlock(RegistryFile,
2632 ValueBlock->DataOffset));
2633 if (!NT_SUCCESS(Status))
2634 {
2635 return Status;
2636 }
2637 return CmiDestroyBlock(RegistryFile, ValueBlock);
2638 }
2639
2640 static NTSTATUS
2641 CmiAllocateBlock(PREGISTRY_FILE RegistryFile,
2642 PVOID *Block,
2643 ULONG BlockSize)
2644 {
2645 NTSTATUS Status;
2646 PVOID NewBlock;
2647
2648 Status = STATUS_SUCCESS;
2649
2650 /* Handle volatile files first */
2651 if (RegistryFile->Filename == NULL)
2652 {
2653 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
2654 if (NewBlock == NULL)
2655 {
2656 Status = STATUS_INSUFFICIENT_RESOURCES;
2657 }
2658 else
2659 {
2660 RtlZeroMemory(NewBlock, BlockSize);
2661 CmiLockBlock(RegistryFile, NewBlock);
2662 *Block = NewBlock;
2663 }
2664 }
2665 else
2666 {
2667 Status = STATUS_NOT_IMPLEMENTED;
2668 }
2669
2670 return Status;
2671 }
2672
2673 static NTSTATUS
2674 CmiDestroyBlock(PREGISTRY_FILE RegistryFile,
2675 PVOID Block)
2676 {
2677 NTSTATUS Status;
2678
2679 Status = STATUS_SUCCESS;
2680
2681 if (RegistryFile->Filename == NULL)
2682 {
2683 CmiReleaseBlock(RegistryFile, Block);
2684 ExFreePool(Block);
2685 }
2686 else
2687 {
2688 Status = STATUS_NOT_IMPLEMENTED;
2689 }
2690
2691 return Status;
2692 }
2693
2694 static PVOID
2695 CmiGetBlock(PREGISTRY_FILE RegistryFile,
2696 BLOCK_OFFSET BlockOffset)
2697 {
2698 PVOID Block;
2699
2700 Block = NULL;
2701 if (RegistryFile->Filename == NULL)
2702 {
2703 CmiLockBlock(RegistryFile, (PVOID) BlockOffset);
2704
2705 Block = (PVOID) BlockOffset;
2706 }
2707 else
2708 {
2709 UNIMPLEMENTED;
2710 }
2711
2712 return Block;
2713 }
2714
2715 static BLOCK_OFFSET
2716 CmiGetBlockOffset(PREGISTRY_FILE RegistryFile,
2717 PVOID Block)
2718 {
2719 BLOCK_OFFSET BlockOffset;
2720
2721 if (RegistryFile->Filename == NULL)
2722 {
2723 BlockOffset = (BLOCK_OFFSET) Block;
2724 }
2725 else
2726 {
2727 UNIMPLEMENTED;
2728 }
2729
2730 return BlockOffset;
2731 }
2732
2733 static VOID
2734 CmiLockBlock(PREGISTRY_FILE RegistryFile,
2735 PVOID Block)
2736 {
2737 if (RegistryFile->Filename != NULL)
2738 {
2739 UNIMPLEMENTED;
2740 }
2741 }
2742
2743 static VOID
2744 CmiReleaseBlock(PREGISTRY_FILE RegistryFile,
2745 PVOID Block)
2746 {
2747 if (RegistryFile->Filename != NULL)
2748 {
2749 UNIMPLEMENTED;
2750 }
2751 }
2752
2753 #endif
2754
2755 /* EOF */