2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regfile.c
5 * PURPOSE: Registry file manipulation routines
11 #include <internal/ob.h>
14 #include <internal/pool.h>
15 #include <internal/registry.h>
18 #include <internal/debug.h>
23 #define REG_BLOCK_SIZE 4096
24 #define REG_HEAP_BLOCK_DATA_OFFSET 32
25 #define REG_HEAP_ID 0x6e696268
26 #define REG_INIT_BLOCK_LIST_SIZE 32
27 #define REG_INIT_HASH_TABLE_SIZE 3
28 #define REG_EXTEND_HASH_TABLE_SIZE 4
29 #define REG_VALUE_LIST_BLOCK_MULTIPLE 4
30 #define REG_KEY_BLOCK_ID 0x6b6e
31 #define REG_HASH_TABLE_BLOCK_ID 0x666c
32 #define REG_VALUE_BLOCK_ID 0x6b76
33 #define REG_KEY_BLOCK_TYPE 0x20
34 #define REG_ROOT_KEY_BLOCK_TYPE 0x2c
37 extern PREGISTRY_FILE CmiVolatileFile
;
39 void CmiCreateDefaultHeaderBlock(PHEADER_BLOCK HeaderBlock
)
41 RtlZeroMemory(HeaderBlock
, sizeof(HEADER_BLOCK
));
42 HeaderBlock
->BlockId
= 0x66676572;
43 HeaderBlock
->DateModified
.dwLowDateTime
= 0;
44 HeaderBlock
->DateModified
.dwHighDateTime
= 0;
45 HeaderBlock
->Version
= 1;
46 HeaderBlock
->Unused3
= 3;
47 HeaderBlock
->Unused5
= 1;
48 HeaderBlock
->RootKeyBlock
= 0;
49 HeaderBlock
->BlockSize
= REG_BLOCK_SIZE
;
50 HeaderBlock
->Unused6
= 1;
51 HeaderBlock
->Checksum
= 0;
54 void CmiCreateDefaultHeapBlock(PHEAP_BLOCK HeapBlock
)
56 RtlZeroMemory(HeapBlock
, sizeof(HEAP_BLOCK
));
57 HeapBlock
->BlockId
= REG_HEAP_ID
;
58 HeapBlock
->DateModified
.dwLowDateTime
= 0;
59 HeapBlock
->DateModified
.dwHighDateTime
= 0;
60 HeapBlock
->BlockSize
= REG_BLOCK_SIZE
;
63 void CmiCreateDefaultRootKeyBlock(PKEY_BLOCK RootKeyBlock
)
65 RtlZeroMemory(RootKeyBlock
, sizeof(KEY_BLOCK
));
66 RootKeyBlock
->SubBlockSize
=-sizeof(KEY_BLOCK
);
67 RootKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
68 RootKeyBlock
->Type
= REG_ROOT_KEY_BLOCK_TYPE
;
69 ZwQuerySystemTime((PTIME
) &RootKeyBlock
->LastWriteTime
);
70 RootKeyBlock
->ParentKeyOffset
= 0;
71 RootKeyBlock
->NumberOfSubKeys
= 0;
72 RootKeyBlock
->HashTableOffset
= -1;
73 RootKeyBlock
->NumberOfValues
= 0;
74 RootKeyBlock
->ValuesOffset
= -1;
75 RootKeyBlock
->SecurityKeyOffset
= 0;
76 RootKeyBlock
->ClassNameOffset
= -1;
77 RootKeyBlock
->NameSize
= 0;
78 RootKeyBlock
->ClassSize
= 0;
81 NTSTATUS
CmiCreateNewRegFile( HANDLE FileHandle
)
84 PHEADER_BLOCK HeaderBlock
;
85 PHEAP_BLOCK HeapBlock
;
86 PKEY_BLOCK RootKeyBlock
;
87 PFREE_SUB_BLOCK FreeSubBlock
;
89 IO_STATUS_BLOCK IoStatusBlock
;
92 tBuf
= (char*) ExAllocatePool(NonPagedPool
, 2*REG_BLOCK_SIZE
);
94 return STATUS_INSUFFICIENT_RESOURCES
;
96 HeaderBlock
= (PHEADER_BLOCK
)tBuf
;
97 HeapBlock
= (PHEAP_BLOCK
) (tBuf
+REG_BLOCK_SIZE
);
98 RootKeyBlock
= (PKEY_BLOCK
) (tBuf
+REG_BLOCK_SIZE
+REG_HEAP_BLOCK_DATA_OFFSET
);
99 FreeSubBlock
= (PFREE_SUB_BLOCK
) (tBuf
+REG_BLOCK_SIZE
+REG_HEAP_BLOCK_DATA_OFFSET
+sizeof(KEY_BLOCK
));
101 CmiCreateDefaultHeaderBlock(HeaderBlock
);
102 CmiCreateDefaultHeapBlock(HeapBlock
);
103 CmiCreateDefaultRootKeyBlock(RootKeyBlock
);
105 HeapBlock
->BlockOffset
= 0; //First block.
106 HeaderBlock
->RootKeyBlock
= REG_HEAP_BLOCK_DATA_OFFSET
; //Offset to root key block.
107 //The rest of the block is free
108 FreeSubBlock
->SubBlockSize
= REG_BLOCK_SIZE
-(REG_HEAP_BLOCK_DATA_OFFSET
+sizeof(KEY_BLOCK
));
110 Status
= ZwWriteFile( FileHandle
, NULL
, NULL
, NULL
,
111 &IoStatusBlock
, tBuf
, 2*REG_BLOCK_SIZE
, 0, NULL
);
118 CmiCreateRegistry(PWSTR Filename
)
120 PREGISTRY_FILE RegistryFile
;
122 PKEY_BLOCK RootKeyBlock
;
124 LARGE_INTEGER fileOffset
;
125 PFREE_SUB_BLOCK FreeBlock
;
128 BLOCK_OFFSET BlockOffset
;
129 DPRINT("CmiCreateRegistry() Filename '%S'\n", Filename
);
130 RegistryFile
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_FILE
));
132 if (RegistryFile
== NULL
)
135 if (Filename
!= NULL
)
137 UNICODE_STRING TmpFileName
;
138 OBJECT_ATTRIBUTES ObjectAttributes
;
140 FILE_STANDARD_INFORMATION fsi
;
141 IO_STATUS_BLOCK IoSB
;
143 /* Duplicate Filename */
144 RegistryFile
->Filename
= ExAllocatePool(NonPagedPool
, MAX_PATH
);
145 wcscpy(RegistryFile
->Filename
, Filename
);
147 RtlInitUnicodeString (&TmpFileName
, Filename
);
148 InitializeObjectAttributes(&ObjectAttributes
,
154 Status
= NtCreateFile( &FileHandle
,
159 FILE_ATTRIBUTE_NORMAL
,
162 FILE_NON_DIRECTORY_FILE
,
166 /* FIXME: create directory if IoSB.Status == STATUS_OBJECT_PATH_NOT_FOUND */
167 if( !NT_SUCCESS(Status
) )
169 ExFreePool(RegistryFile
->Filename
);
170 RegistryFile
->Filename
= NULL
;
173 /*if file did not exist*/
174 if( IoSB
.Information
== FILE_CREATED
){
175 Status
= CmiCreateNewRegFile( FileHandle
);
176 if( !NT_SUCCESS(Status
) )
178 ExFreePool(RegistryFile
->Filename
);
179 RegistryFile
->Filename
= NULL
;
184 RegistryFile
->HeaderBlock
= (PHEADER_BLOCK
)
185 ExAllocatePool(NonPagedPool
, sizeof(HEADER_BLOCK
));
187 fileOffset
.u
.HighPart
= 0;
188 fileOffset
.u
.LowPart
= 0;
189 Status
= ZwReadFile(FileHandle
,
191 RegistryFile
->HeaderBlock
,
192 sizeof(HEADER_BLOCK
),
194 if (!NT_SUCCESS(Status
))
196 ExFreePool(RegistryFile
->Filename
);
197 RegistryFile
->Filename
= NULL
;
201 Status
= ZwQueryInformationFile(FileHandle
,&IoSB
,&fsi
202 ,sizeof(fsi
),FileStandardInformation
);
203 if (!NT_SUCCESS(Status
))
205 ExFreePool(RegistryFile
->Filename
);
206 RegistryFile
->Filename
= NULL
;
209 RegistryFile
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
210 RegistryFile
->BlockListSize
= RegistryFile
->FileSize
/ 4096 -1;
211 // RegistryFile->NumberOfBlocks = RegistryFile->BlockListSize;
212 RegistryFile
->BlockList
= ExAllocatePool(NonPagedPool
,
213 sizeof(PHEAP_BLOCK
*) * (RegistryFile
->BlockListSize
));
215 fileOffset
.u
.HighPart
= 0;
216 fileOffset
.u
.LowPart
= 4096;
217 RegistryFile
->BlockList
[0]
218 = ExAllocatePool(NonPagedPool
,RegistryFile
->FileSize
-4096);
219 if (RegistryFile
->BlockList
[0] == NULL
)
221 // Status = STATUS_INSUFFICIENT_RESOURCES;
222 DPRINT("error allocating %d bytes for registry\n"
223 ,RegistryFile
->FileSize
-4096);
227 Status
= ZwReadFile(FileHandle
,
229 RegistryFile
->BlockList
[0],
230 RegistryFile
->FileSize
-4096,
233 if (!NT_SUCCESS(Status
))
235 DPRINT("error %x reading registry file at offset %x\n"
236 ,Status
,fileOffset
.u
.LowPart
);
239 RegistryFile
->FreeListSize
= 0;
240 RegistryFile
->FreeListMax
= 0;
241 RegistryFile
->FreeList
= NULL
;
242 for(i
=0 ; i
<RegistryFile
->BlockListSize
; i
++)
244 tmpHeap
= (PHEAP_BLOCK
)(((char *)RegistryFile
->BlockList
[0])+BlockOffset
);
245 if (tmpHeap
->BlockId
!= REG_HEAP_ID
)
247 DPRINT("bad BlockId %x,offset %x\n",tmpHeap
->BlockId
,fileOffset
.u
.LowPart
);
249 RegistryFile
->BlockList
[i
]
251 if (tmpHeap
->BlockSize
>4096)
253 for(j
=1;j
<tmpHeap
->BlockSize
/4096;j
++)
254 RegistryFile
->BlockList
[i
+j
] = RegistryFile
->BlockList
[i
];
257 /* search free blocks and add to list */
258 FreeOffset
=REG_HEAP_BLOCK_DATA_OFFSET
;
259 while(FreeOffset
< tmpHeap
->BlockSize
)
261 FreeBlock
= (PFREE_SUB_BLOCK
)((char *)RegistryFile
->BlockList
[i
]
263 if ( FreeBlock
->SubBlockSize
>0)
265 CmiAddFree(RegistryFile
,FreeBlock
266 ,RegistryFile
->BlockList
[i
]->BlockOffset
+FreeOffset
);
267 FreeOffset
+= FreeBlock
->SubBlockSize
;
270 FreeOffset
-= FreeBlock
->SubBlockSize
;
272 BlockOffset
+= tmpHeap
->BlockSize
;
274 Status
= ObReferenceObjectByHandle(FileHandle
,
278 (PVOID
*)&RegistryFile
->FileObject
,
283 RegistryFile
->Filename
= NULL
;
284 RegistryFile
->FileObject
= NULL
;
286 RegistryFile
->HeaderBlock
= (PHEADER_BLOCK
)
287 ExAllocatePool(NonPagedPool
, sizeof(HEADER_BLOCK
));
288 CmiCreateDefaultHeaderBlock(RegistryFile
->HeaderBlock
);
290 RootKeyBlock
= (PKEY_BLOCK
) ExAllocatePool(NonPagedPool
, sizeof(KEY_BLOCK
));
291 CmiCreateDefaultRootKeyBlock(RootKeyBlock
);
293 RegistryFile
->HeaderBlock
->RootKeyBlock
= (BLOCK_OFFSET
) RootKeyBlock
;
295 KeInitializeSemaphore(&RegistryFile
->RegSem
, 1, 1);
301 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile
,
305 PHASH_TABLE_BLOCK HashBlock
;
306 PKEY_BLOCK CurSubKeyBlock
;
309 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
314 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
316 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
318 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
319 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
320 if (MaxName
< CurSubKeyBlock
->NameSize
)
322 MaxName
= CurSubKeyBlock
->NameSize
;
324 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
328 CmiReleaseBlock(RegistryFile
, HashBlock
);
334 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile
,
338 PHASH_TABLE_BLOCK HashBlock
;
339 PKEY_BLOCK CurSubKeyBlock
;
342 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
347 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
349 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
351 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
352 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
353 if (MaxClass
< CurSubKeyBlock
->ClassSize
)
355 MaxClass
= CurSubKeyBlock
->ClassSize
;
357 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
361 CmiReleaseBlock(RegistryFile
, HashBlock
);
367 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile
,
370 ULONG Idx
, MaxValueName
;
371 PVALUE_LIST_BLOCK ValueListBlock
;
372 PVALUE_BLOCK CurValueBlock
;
374 ValueListBlock
= CmiGetBlock(RegistryFile
,
375 KeyBlock
->ValuesOffset
,NULL
);
377 if (ValueListBlock
== 0)
381 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
383 CurValueBlock
= CmiGetBlock(RegistryFile
,
384 ValueListBlock
->Values
[Idx
],NULL
);
385 if (CurValueBlock
!= NULL
&&
386 MaxValueName
< CurValueBlock
->NameSize
)
388 MaxValueName
= CurValueBlock
->NameSize
;
390 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
393 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
399 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile
,
402 ULONG Idx
, MaxValueData
;
403 PVALUE_LIST_BLOCK ValueListBlock
;
404 PVALUE_BLOCK CurValueBlock
;
406 ValueListBlock
= CmiGetBlock(RegistryFile
,
407 KeyBlock
->ValuesOffset
,NULL
);
409 if (ValueListBlock
== 0)
413 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
415 CurValueBlock
= CmiGetBlock(RegistryFile
,
416 ValueListBlock
->Values
[Idx
],NULL
);
417 if (CurValueBlock
!= NULL
&&
418 MaxValueData
< (CurValueBlock
->DataSize
& LONG_MAX
) )
420 MaxValueData
= CurValueBlock
->DataSize
& LONG_MAX
;
422 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
425 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
431 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile
,
432 IN PKEY_BLOCK KeyBlock
,
433 OUT PKEY_BLOCK
*SubKeyBlock
,
434 OUT BLOCK_OFFSET
*BlockOffset
,
436 IN ACCESS_MASK DesiredAccess
,
440 PHASH_TABLE_BLOCK HashBlock
;
441 PKEY_BLOCK CurSubKeyBlock
;
442 WORD KeyLength
= strlen(KeyName
);
444 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
446 if (HashBlock
== NULL
)
448 return STATUS_SUCCESS
;
450 // for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
451 for (Idx
= 0; Idx
< KeyBlock
->NumberOfSubKeys
452 && Idx
< HashBlock
->HashTableSize
; Idx
++)
454 if (Attributes
& OBJ_CASE_INSENSITIVE
)
456 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0 &&
457 HashBlock
->Table
[Idx
].KeyOffset
!= -1 &&
458 !_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[Idx
].HashValue
, 4))
460 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
461 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
462 if ( CurSubKeyBlock
->NameSize
== KeyLength
463 && !_strnicmp(KeyName
, CurSubKeyBlock
->Name
, KeyLength
))
465 *SubKeyBlock
= CurSubKeyBlock
;
466 *BlockOffset
= HashBlock
->Table
[Idx
].KeyOffset
;
471 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
477 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0 &&
478 HashBlock
->Table
[Idx
].KeyOffset
!= -1 &&
479 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[Idx
].HashValue
, 4))
481 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
482 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
483 if ( CurSubKeyBlock
->NameSize
== KeyLength
484 && !_strnicmp(KeyName
, CurSubKeyBlock
->Name
, KeyLength
))
486 *SubKeyBlock
= CurSubKeyBlock
;
487 *BlockOffset
= HashBlock
->Table
[Idx
].KeyOffset
;
492 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
498 CmiReleaseBlock(RegistryFile
, HashBlock
);
500 return STATUS_SUCCESS
;
504 CmiAddSubKey(PREGISTRY_FILE RegistryFile
,
508 USHORT NewSubKeyNameSize
,
510 PUNICODE_STRING Class
,
513 PKEY_BLOCK KeyBlock
= Parent
->KeyBlock
;
515 PHASH_TABLE_BLOCK HashBlock
, NewHashBlock
;
516 PKEY_BLOCK NewKeyBlock
;
517 BLOCK_OFFSET NKBOffset
;
521 if (NewSubKeyName
[0] == L
'\\')
524 NameSize
= NewSubKeyNameSize
/2-1;
527 NameSize
= NewSubKeyNameSize
/2;
528 Status
= STATUS_SUCCESS
;
530 NewBlockSize
= sizeof(KEY_BLOCK
) + NameSize
;
531 Status
= CmiAllocateBlock(RegistryFile
, (PVOID
) &NewKeyBlock
532 , NewBlockSize
,&NKBOffset
);
533 if (NewKeyBlock
== NULL
)
535 Status
= STATUS_INSUFFICIENT_RESOURCES
;
539 NewKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
540 NewKeyBlock
->Type
= REG_KEY_BLOCK_TYPE
;
541 ZwQuerySystemTime((PTIME
) &NewKeyBlock
->LastWriteTime
);
542 NewKeyBlock
->ParentKeyOffset
= -1;
543 NewKeyBlock
->NumberOfSubKeys
= 0;
544 NewKeyBlock
->HashTableOffset
= -1;
545 NewKeyBlock
->NumberOfValues
= 0;
546 NewKeyBlock
->ValuesOffset
= -1;
547 NewKeyBlock
->SecurityKeyOffset
= -1;
548 NewKeyBlock
->NameSize
= NameSize
;
549 wcstombs(NewKeyBlock
->Name
,NewSubKeyName
,NameSize
);
550 NewKeyBlock
->ClassNameOffset
= -1;
554 NewKeyBlock
->ClassSize
= Class
->Length
+sizeof(WCHAR
);
555 Status
= CmiAllocateBlock(RegistryFile
557 ,NewKeyBlock
->ClassSize
558 ,&NewKeyBlock
->ClassNameOffset
);
559 wcsncpy((PWSTR
)pClass
->Data
,Class
->Buffer
,Class
->Length
);
560 ( (PWSTR
)(pClass
->Data
))[Class
->Length
]=0;
564 if (!NT_SUCCESS(Status
))
568 SubKey
->KeyBlock
= NewKeyBlock
;
569 SubKey
->BlockOffset
= NKBOffset
;
570 /* don't modify hash table if key is volatile and parent is not */
571 if (RegistryFile
== CmiVolatileFile
&& Parent
->RegistryFile
!= RegistryFile
)
575 if (KeyBlock
->HashTableOffset
== -1)
577 Status
= CmiAllocateHashTableBlock(RegistryFile
,
579 &KeyBlock
->HashTableOffset
,
580 REG_INIT_HASH_TABLE_SIZE
);
581 if (!NT_SUCCESS(Status
))
588 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
589 if (KeyBlock
->NumberOfSubKeys
+ 1 >= HashBlock
->HashTableSize
)
591 BLOCK_OFFSET HTOffset
;
593 /* Reallocate the hash table block */
594 Status
= CmiAllocateHashTableBlock(RegistryFile
,
597 HashBlock
->HashTableSize
+
598 REG_EXTEND_HASH_TABLE_SIZE
);
599 if (!NT_SUCCESS(Status
))
603 RtlZeroMemory(&NewHashBlock
->Table
[0],
604 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
605 RtlCopyMemory(&NewHashBlock
->Table
[0],
606 &HashBlock
->Table
[0],
607 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
608 CmiDestroyBlock(RegistryFile
, HashBlock
609 , KeyBlock
->HashTableOffset
);
610 KeyBlock
->HashTableOffset
= HTOffset
;
611 HashBlock
= NewHashBlock
;
614 Status
= CmiAddKeyToHashTable(RegistryFile
, HashBlock
, NewKeyBlock
,NKBOffset
);
615 if (NT_SUCCESS(Status
))
617 KeyBlock
->NumberOfSubKeys
++;
624 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile
,
625 IN PKEY_BLOCK KeyBlock
,
627 OUT PVALUE_BLOCK
*ValueBlock
,
628 OUT BLOCK_OFFSET
*VBOffset
)
632 PVALUE_LIST_BLOCK ValueListBlock
;
633 PVALUE_BLOCK CurValueBlock
;
635 ValueListBlock
= CmiGetBlock(RegistryFile
,
636 KeyBlock
->ValuesOffset
,NULL
);
638 if (ValueListBlock
== NULL
)
640 DPRINT("ValueListBlock is NULL\n");
641 return STATUS_SUCCESS
;
643 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
645 CurValueBlock
= CmiGetBlock(RegistryFile
,
646 ValueListBlock
->Values
[Idx
],NULL
);
647 /* FIXME : perhaps we must not ignore case if NtCreateKey has not been */
648 /* called with OBJ_CASE_INSENSITIVE flag ? */
649 Length
= strlen(ValueName
);
650 if ((CurValueBlock
!= NULL
) &&
651 (CurValueBlock
->NameSize
== Length
) &&
652 (_strnicmp(CurValueBlock
->Name
, ValueName
, Length
) == 0))
654 *ValueBlock
= CurValueBlock
;
655 if(VBOffset
) *VBOffset
= ValueListBlock
->Values
[Idx
];
656 DPRINT("Found value %s\n", ValueName
);
659 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
662 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
664 return STATUS_SUCCESS
;
669 CmiGetValueFromKeyByIndex(IN PREGISTRY_FILE RegistryFile
,
670 IN PKEY_BLOCK KeyBlock
,
672 OUT PVALUE_BLOCK
*ValueBlock
)
674 PVALUE_LIST_BLOCK ValueListBlock
;
675 PVALUE_BLOCK CurValueBlock
;
677 ValueListBlock
= CmiGetBlock(RegistryFile
,
678 KeyBlock
->ValuesOffset
,NULL
);
680 if (ValueListBlock
== NULL
)
682 return STATUS_NO_MORE_ENTRIES
;
684 if (Index
>= KeyBlock
->NumberOfValues
)
686 return STATUS_NO_MORE_ENTRIES
;
688 CurValueBlock
= CmiGetBlock(RegistryFile
,
689 ValueListBlock
->Values
[Index
],NULL
);
690 if (CurValueBlock
!= NULL
)
692 *ValueBlock
= CurValueBlock
;
694 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
695 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
697 return STATUS_SUCCESS
;
701 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile
,
702 IN PKEY_BLOCK KeyBlock
,
703 IN PCHAR ValueNameBuf
,
704 OUT PVALUE_BLOCK
*pValueBlock
,
705 OUT BLOCK_OFFSET
*pVBOffset
)
708 PVALUE_LIST_BLOCK ValueListBlock
, NewValueListBlock
;
709 BLOCK_OFFSET VBOffset
;
710 BLOCK_OFFSET VLBOffset
;
711 PVALUE_BLOCK NewValueBlock
;
713 Status
= CmiAllocateValueBlock(RegistryFile
,
718 if (!NT_SUCCESS(Status
))
722 ValueListBlock
= CmiGetBlock(RegistryFile
,
723 KeyBlock
->ValuesOffset
,NULL
);
724 if (ValueListBlock
== NULL
)
726 Status
= CmiAllocateBlock(RegistryFile
,
727 (PVOID
) &ValueListBlock
,
728 sizeof(BLOCK_OFFSET
) * 3,
730 if (!NT_SUCCESS(Status
))
732 CmiDestroyValueBlock(RegistryFile
,
733 NewValueBlock
,VBOffset
);
736 KeyBlock
->ValuesOffset
= VLBOffset
;
738 else if (KeyBlock
->NumberOfValues
739 >= ((LONG
)(ValueListBlock
->SubBlockSize
-4))/(LONG
)sizeof(BLOCK_OFFSET
))
740 // >= -(ValueListBlock->SubBlockSize-4)/sizeof(BLOCK_OFFSET))
743 Status
= CmiAllocateBlock(RegistryFile
,
744 (PVOID
) &NewValueListBlock
,
745 sizeof(BLOCK_OFFSET
) *
746 (KeyBlock
->NumberOfValues
+
747 REG_VALUE_LIST_BLOCK_MULTIPLE
),
749 if (!NT_SUCCESS(Status
))
751 CmiDestroyValueBlock(RegistryFile
,
756 RtlCopyMemory(&NewValueListBlock
->Values
[0],
757 &ValueListBlock
->Values
[0],
758 sizeof(BLOCK_OFFSET
) * KeyBlock
->NumberOfValues
);
759 CmiDestroyBlock(RegistryFile
, ValueListBlock
,KeyBlock
->ValuesOffset
);
760 KeyBlock
->ValuesOffset
= VLBOffset
;
761 ValueListBlock
= NewValueListBlock
;
763 DPRINT1("KeyBlock->NumberOfValues %d, ValueListBlock->SubBlockSize %d (%d %x)\n",
764 KeyBlock
->NumberOfValues
, ValueListBlock
->SubBlockSize
,
765 -(ValueListBlock
->SubBlockSize
-4)/sizeof(BLOCK_OFFSET
),
766 -(ValueListBlock
->SubBlockSize
-4)/sizeof(BLOCK_OFFSET
));
767 ValueListBlock
->Values
[KeyBlock
->NumberOfValues
] = VBOffset
;
768 KeyBlock
->NumberOfValues
++;
769 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
770 CmiReleaseBlock(RegistryFile
, NewValueBlock
);
771 *pValueBlock
= NewValueBlock
;
773 return(STATUS_SUCCESS
);
777 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile
,
778 IN PKEY_BLOCK KeyBlock
,
782 PVALUE_LIST_BLOCK ValueListBlock
;
783 PVALUE_BLOCK CurValueBlock
;
786 ValueListBlock
= CmiGetBlock(RegistryFile
,
787 KeyBlock
->ValuesOffset
,NULL
);
788 if (ValueListBlock
== 0)
790 return STATUS_SUCCESS
;
792 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
794 CurValueBlock
= CmiGetBlock(RegistryFile
,
795 ValueListBlock
->Values
[Idx
],&pHeap
);
796 if (CurValueBlock
!= NULL
&&
797 CurValueBlock
->NameSize
== strlen(ValueName
) &&
798 !memcmp(CurValueBlock
->Name
, ValueName
,strlen(ValueName
)))
800 if (KeyBlock
->NumberOfValues
- 1 < Idx
)
802 RtlCopyMemory(&ValueListBlock
->Values
[Idx
],
803 &ValueListBlock
->Values
[Idx
+ 1],
804 sizeof(BLOCK_OFFSET
) *
805 (KeyBlock
->NumberOfValues
- 1 - Idx
));
809 RtlZeroMemory(&ValueListBlock
->Values
[Idx
],
810 sizeof(BLOCK_OFFSET
));
812 KeyBlock
->NumberOfValues
-= 1;
813 CmiDestroyValueBlock(RegistryFile
, CurValueBlock
, ValueListBlock
->Values
[Idx
]);
814 /* update time of heap */
815 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
819 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
822 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
824 return STATUS_SUCCESS
;
828 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile
,
829 OUT PHASH_TABLE_BLOCK
*HashBlock
,
830 OUT BLOCK_OFFSET
*HBOffset
,
831 IN ULONG HashTableSize
)
835 PHASH_TABLE_BLOCK NewHashBlock
;
837 Status
= STATUS_SUCCESS
;
839 NewHashSize
= sizeof(HASH_TABLE_BLOCK
) +
840 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
841 Status
= CmiAllocateBlock(RegistryFile
,
842 (PVOID
*)&NewHashBlock
,
843 NewHashSize
,HBOffset
);
844 if (NewHashBlock
== NULL
|| !NT_SUCCESS(Status
) )
846 Status
= STATUS_INSUFFICIENT_RESOURCES
;
850 NewHashBlock
->SubBlockId
= REG_HASH_TABLE_BLOCK_ID
;
851 NewHashBlock
->HashTableSize
= HashTableSize
;
852 *HashBlock
= NewHashBlock
;
859 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile
,
860 PHASH_TABLE_BLOCK HashBlock
,
864 BLOCK_OFFSET KeyOffset
;
866 if( HashBlock
== NULL
)
868 if (RegistryFile
->Filename
== NULL
)
870 KeyBlock
= (PKEY_BLOCK
) HashBlock
->Table
[Index
].KeyOffset
;
874 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
875 KeyBlock
= CmiGetBlock(RegistryFile
,KeyOffset
,NULL
);
877 CmiLockBlock(RegistryFile
, KeyBlock
);
883 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile
,
884 PHASH_TABLE_BLOCK HashBlock
,
885 PKEY_BLOCK NewKeyBlock
,
886 BLOCK_OFFSET NKBOffset
)
890 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
892 if (HashBlock
->Table
[i
].KeyOffset
== 0)
894 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
895 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
,
898 return STATUS_SUCCESS
;
901 return STATUS_UNSUCCESSFUL
;
905 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile
,
906 PVALUE_BLOCK
*ValueBlock
,
907 BLOCK_OFFSET
*VBOffset
,
908 IN PCHAR ValueNameBuf
)
912 PVALUE_BLOCK NewValueBlock
;
914 Status
= STATUS_SUCCESS
;
916 NewValueSize
= sizeof(VALUE_BLOCK
) + strlen(ValueNameBuf
);
917 Status
= CmiAllocateBlock(RegistryFile
,
918 (PVOID
*)&NewValueBlock
,
919 NewValueSize
,VBOffset
);
920 if (NewValueBlock
== NULL
|| !NT_SUCCESS(Status
))
922 Status
= STATUS_INSUFFICIENT_RESOURCES
;
926 NewValueBlock
->SubBlockId
= REG_VALUE_BLOCK_ID
;
927 NewValueBlock
->NameSize
= strlen(ValueNameBuf
);
928 memcpy(NewValueBlock
->Name
, ValueNameBuf
,strlen(ValueNameBuf
));
929 NewValueBlock
->DataType
= 0;
930 NewValueBlock
->DataSize
= 0;
931 NewValueBlock
->DataOffset
= 0xffffffff;
932 *ValueBlock
= NewValueBlock
;
939 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile
,
940 PVALUE_BLOCK ValueBlock
, BLOCK_OFFSET VBOffset
)
946 /* first, release datas : */
947 if (ValueBlock
->DataSize
>0)
949 pBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
,&pHeap
);
950 Status
= CmiDestroyBlock(RegistryFile
, pBlock
, ValueBlock
->DataOffset
);
951 if (!NT_SUCCESS(Status
))
955 /* update time of heap */
956 if(RegistryFile
->Filename
)
957 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
960 Status
= CmiDestroyBlock(RegistryFile
, ValueBlock
, VBOffset
);
961 /* update time of heap */
962 if(RegistryFile
->Filename
&& CmiGetBlock(RegistryFile
, VBOffset
,&pHeap
))
963 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
968 CmiAddHeap(PREGISTRY_FILE RegistryFile
,PVOID
*NewBlock
,BLOCK_OFFSET
*NewBlockOffset
)
971 PHEAP_BLOCK
* tmpBlockList
;
972 PFREE_SUB_BLOCK tmpBlock
;
973 tmpHeap
=ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
974 tmpHeap
->BlockId
= REG_HEAP_ID
;
975 tmpHeap
->BlockOffset
= RegistryFile
->FileSize
- REG_BLOCK_SIZE
;
976 RegistryFile
->FileSize
+= REG_BLOCK_SIZE
;
977 tmpHeap
->BlockSize
= REG_BLOCK_SIZE
;
978 tmpHeap
->Unused1
= 0;
979 ZwQuerySystemTime((PTIME
) &tmpHeap
->DateModified
);
980 tmpHeap
->Unused2
= 0;
981 /* increase size of list of blocks */
982 tmpBlockList
=ExAllocatePool(NonPagedPool
,
983 sizeof(PHEAP_BLOCK
*) * (RegistryFile
->BlockListSize
+1));
984 if (tmpBlockList
== NULL
)
987 return(STATUS_INSUFFICIENT_RESOURCES
);
989 if(RegistryFile
->BlockListSize
> 0)
991 memcpy(tmpBlockList
,RegistryFile
->BlockList
,
992 sizeof(PHEAP_BLOCK
*)*(RegistryFile
->BlockListSize
));
993 ExFreePool(RegistryFile
->BlockList
);
995 RegistryFile
->BlockList
= tmpBlockList
;
996 RegistryFile
->BlockList
[RegistryFile
->BlockListSize
++] = tmpHeap
;
997 /* initialize a free block in this heap : */
998 tmpBlock
= (PFREE_SUB_BLOCK
)((char *) tmpHeap
+ REG_HEAP_BLOCK_DATA_OFFSET
);
999 tmpBlock
-> SubBlockSize
= (REG_BLOCK_SIZE
- REG_HEAP_BLOCK_DATA_OFFSET
) ;
1000 *NewBlock
= (PVOID
)tmpBlock
;
1002 *NewBlockOffset
= tmpHeap
->BlockOffset
+ REG_HEAP_BLOCK_DATA_OFFSET
;
1003 /* FIXME : set first dword to block_offset of another free bloc */
1004 return STATUS_SUCCESS
;
1008 CmiAllocateBlock(PREGISTRY_FILE RegistryFile
,
1011 BLOCK_OFFSET
* pBlockOffset
)
1014 PFREE_SUB_BLOCK NewBlock
;
1017 Status
= STATUS_SUCCESS
;
1018 /* round to 16 bytes multiple */
1019 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
1021 /* Handle volatile files first */
1022 if (RegistryFile
->Filename
== NULL
)
1024 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
1025 if (NewBlock
== NULL
)
1027 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1031 RtlZeroMemory(NewBlock
, BlockSize
);
1032 NewBlock
->SubBlockSize
= BlockSize
;
1033 CmiLockBlock(RegistryFile
, NewBlock
);
1035 if (pBlockOffset
) *pBlockOffset
= (BLOCK_OFFSET
)NewBlock
;
1041 /* first search in free blocks */
1043 for (i
=0 ; i
<RegistryFile
->FreeListSize
; i
++)
1045 if(RegistryFile
->FreeList
[i
]->SubBlockSize
>=BlockSize
)
1047 NewBlock
= RegistryFile
->FreeList
[i
];
1049 *pBlockOffset
= RegistryFile
->FreeListOffset
[i
];
1050 /* update time of heap */
1051 if(RegistryFile
->Filename
1052 && CmiGetBlock(RegistryFile
, RegistryFile
->FreeListOffset
[i
],&pHeap
))
1053 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
1054 if( (i
+1) <RegistryFile
->FreeListSize
)
1056 memmove( &RegistryFile
->FreeList
[i
]
1057 ,&RegistryFile
->FreeList
[i
+1]
1058 ,sizeof(RegistryFile
->FreeList
[0])
1059 *(RegistryFile
->FreeListSize
-i
-1));
1060 memmove( &RegistryFile
->FreeListOffset
[i
]
1061 ,&RegistryFile
->FreeListOffset
[i
+1]
1062 ,sizeof(RegistryFile
->FreeListOffset
[0])
1063 *(RegistryFile
->FreeListSize
-i
-1));
1065 RegistryFile
->FreeListSize
--;
1069 /* need to extend hive file : */
1070 if (NewBlock
== NULL
)
1072 /* add a new block : */
1073 Status
= CmiAddHeap(RegistryFile
, (PVOID
*)&NewBlock
, pBlockOffset
);
1075 if (NT_SUCCESS(Status
))
1078 /* split the block in two parts */
1079 if(NewBlock
->SubBlockSize
> BlockSize
)
1081 NewBlock
= (PFREE_SUB_BLOCK
)((char *)NewBlock
+BlockSize
);
1082 NewBlock
->SubBlockSize
=((PFREE_SUB_BLOCK
) (*Block
))->SubBlockSize
-BlockSize
;
1083 CmiAddFree(RegistryFile
,NewBlock
,*pBlockOffset
+BlockSize
);
1085 else if(NewBlock
->SubBlockSize
< BlockSize
)
1086 return STATUS_UNSUCCESSFUL
;
1087 RtlZeroMemory(*Block
, BlockSize
);
1088 ((PFREE_SUB_BLOCK
)(*Block
)) ->SubBlockSize
= - BlockSize
;
1089 CmiLockBlock(RegistryFile
, *Block
);
1096 CmiDestroyBlock(PREGISTRY_FILE RegistryFile
,
1097 PVOID Block
,BLOCK_OFFSET Offset
)
1102 Status
= STATUS_SUCCESS
;
1104 if (RegistryFile
->Filename
== NULL
)
1106 CmiReleaseBlock(RegistryFile
, Block
);
1111 PFREE_SUB_BLOCK pFree
= Block
;
1113 if (pFree
->SubBlockSize
<0)
1114 pFree
->SubBlockSize
= -pFree
->SubBlockSize
;
1115 CmiAddFree(RegistryFile
,Block
,Offset
);
1116 CmiReleaseBlock(RegistryFile
, Block
);
1117 /* update time of heap */
1118 if(RegistryFile
->Filename
&& CmiGetBlock(RegistryFile
, Offset
,&pHeap
))
1119 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
1120 /* FIXME : set first dword to block_offset of another free block ? */
1121 /* FIXME : concatenate with previous and next block if free */
1128 CmiAddFree(PREGISTRY_FILE RegistryFile
,
1129 PFREE_SUB_BLOCK FreeBlock
,BLOCK_OFFSET FreeOffset
)
1131 PFREE_SUB_BLOCK
*tmpList
;
1132 BLOCK_OFFSET
*tmpListOffset
;
1133 int minInd
,maxInd
,medInd
;
1134 if( (RegistryFile
->FreeListSize
+1) > RegistryFile
->FreeListMax
)
1136 tmpList
=ExAllocatePool(PagedPool
1137 ,sizeof(PFREE_SUB_BLOCK
)*(RegistryFile
->FreeListMax
+32));
1138 if (tmpList
== NULL
)
1139 return STATUS_INSUFFICIENT_RESOURCES
;
1140 tmpListOffset
=ExAllocatePool(PagedPool
1141 ,sizeof(BLOCK_OFFSET
*)*(RegistryFile
->FreeListMax
+32));
1142 if (tmpListOffset
== NULL
)
1143 return STATUS_INSUFFICIENT_RESOURCES
;
1144 if (RegistryFile
->FreeListMax
)
1146 memcpy(tmpList
,RegistryFile
->FreeList
1147 ,sizeof(PFREE_SUB_BLOCK
)*(RegistryFile
->FreeListMax
));
1148 memcpy(tmpListOffset
,RegistryFile
->FreeListOffset
1149 ,sizeof(BLOCK_OFFSET
*)*(RegistryFile
->FreeListMax
));
1150 ExFreePool(RegistryFile
->FreeList
);
1151 ExFreePool(RegistryFile
->FreeListOffset
);
1153 RegistryFile
->FreeList
= tmpList
;
1154 RegistryFile
->FreeListOffset
= tmpListOffset
;
1155 RegistryFile
->FreeListMax
+=32;
1157 /* add new offset to free list, maintening list in ascending order */
1158 if ( RegistryFile
->FreeListSize
==0
1159 || RegistryFile
->FreeListOffset
[RegistryFile
->FreeListSize
-1] < FreeOffset
)
1161 /* add to end of list : */
1162 RegistryFile
->FreeList
[RegistryFile
->FreeListSize
] = FreeBlock
;
1163 RegistryFile
->FreeListOffset
[RegistryFile
->FreeListSize
++] = FreeOffset
;
1165 else if (RegistryFile
->FreeListOffset
[0] > FreeOffset
)
1167 /* add to begin of list : */
1168 memmove( &RegistryFile
->FreeList
[1],&RegistryFile
->FreeList
[0]
1169 ,sizeof(RegistryFile
->FreeList
[0])*RegistryFile
->FreeListSize
);
1170 memmove( &RegistryFile
->FreeListOffset
[1],&RegistryFile
->FreeListOffset
[0]
1171 ,sizeof(RegistryFile
->FreeListOffset
[0])*RegistryFile
->FreeListSize
);
1172 RegistryFile
->FreeList
[0] = FreeBlock
;
1173 RegistryFile
->FreeListOffset
[0] = FreeOffset
;
1174 RegistryFile
->FreeListSize
++;
1178 /* search where to insert : */
1180 maxInd
=RegistryFile
->FreeListSize
-1;
1181 while( (maxInd
-minInd
) >1)
1183 medInd
=(minInd
+maxInd
)/2;
1184 if (RegistryFile
->FreeListOffset
[medInd
] > FreeOffset
)
1189 /* insert before maxInd : */
1190 memmove( &RegistryFile
->FreeList
[maxInd
+1],&RegistryFile
->FreeList
[maxInd
]
1191 ,sizeof(RegistryFile
->FreeList
[0])
1192 *(RegistryFile
->FreeListSize
-minInd
));
1193 memmove( &RegistryFile
->FreeListOffset
[maxInd
+1]
1194 , &RegistryFile
->FreeListOffset
[maxInd
]
1195 , sizeof(RegistryFile
->FreeListOffset
[0])
1196 *(RegistryFile
->FreeListSize
-minInd
));
1197 RegistryFile
->FreeList
[maxInd
] = FreeBlock
;
1198 RegistryFile
->FreeListOffset
[maxInd
] = FreeOffset
;
1199 RegistryFile
->FreeListSize
++;
1201 return STATUS_SUCCESS
;
1205 CmiGetBlock(PREGISTRY_FILE RegistryFile
,
1206 BLOCK_OFFSET BlockOffset
,
1207 OUT PHEAP_BLOCK
* ppHeap
)
1209 if( BlockOffset
== 0 || BlockOffset
== -1)
1212 if (RegistryFile
->Filename
== NULL
)
1214 return (PVOID
)BlockOffset
;
1220 pHeap
= RegistryFile
->BlockList
[BlockOffset
/4096];
1221 if(ppHeap
) *ppHeap
= pHeap
;
1222 return ((char *)pHeap
1223 +(BlockOffset
- pHeap
->BlockOffset
));
1228 CmiLockBlock(PREGISTRY_FILE RegistryFile
,
1231 if (RegistryFile
->Filename
!= NULL
)
1233 /* FIXME : implement */
1238 CmiReleaseBlock(PREGISTRY_FILE RegistryFile
,
1241 if (RegistryFile
->Filename
!= NULL
)
1243 /* FIXME : implement */