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
12 #define REG_BLOCK_SIZE 4096
13 #define REG_HEAP_BLOCK_DATA_OFFSET 32
14 #define REG_HEAP_ID 0x6e696268
15 #define REG_INIT_BLOCK_LIST_SIZE 32
16 #define REG_INIT_HASH_TABLE_SIZE 3
17 #define REG_EXTEND_HASH_TABLE_SIZE 4
18 #define REG_VALUE_LIST_BLOCK_MULTIPLE 4
19 #define REG_KEY_BLOCK_ID 0x6b6e
20 #define REG_HASH_TABLE_BLOCK_ID 0x666c
21 #define REG_VALUE_BLOCK_ID 0x6b76
22 #define REG_KEY_BLOCK_TYPE 0x20
23 #define REG_ROOT_KEY_BLOCK_TYPE 0x2c
26 extern PREGISTRY_FILE CmiVolatileFile
;
28 void CmiCreateDefaultHeaderBlock(PHEADER_BLOCK HeaderBlock
)
30 RtlZeroMemory(HeaderBlock
, sizeof(HEADER_BLOCK
));
31 HeaderBlock
->BlockId
= 0x66676572;
32 HeaderBlock
->DateModified
.dwLowDateTime
= 0;
33 HeaderBlock
->DateModified
.dwHighDateTime
= 0;
34 HeaderBlock
->Version
= 1;
35 HeaderBlock
->Unused3
= 3;
36 HeaderBlock
->Unused5
= 1;
37 HeaderBlock
->RootKeyBlock
= 0;
38 HeaderBlock
->BlockSize
= REG_BLOCK_SIZE
;
39 HeaderBlock
->Unused6
= 1;
40 HeaderBlock
->Checksum
= 0;
43 void CmiCreateDefaultHeapBlock(PHEAP_BLOCK HeapBlock
)
45 RtlZeroMemory(HeapBlock
, sizeof(HEAP_BLOCK
));
46 HeapBlock
->BlockId
= REG_HEAP_ID
;
47 HeapBlock
->DateModified
.dwLowDateTime
= 0;
48 HeapBlock
->DateModified
.dwHighDateTime
= 0;
49 HeapBlock
->BlockSize
= REG_BLOCK_SIZE
;
52 void CmiCreateDefaultRootKeyBlock(PKEY_BLOCK RootKeyBlock
)
54 RtlZeroMemory(RootKeyBlock
, sizeof(KEY_BLOCK
));
55 RootKeyBlock
->SubBlockSize
=-sizeof(KEY_BLOCK
);
56 RootKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
57 RootKeyBlock
->Type
= REG_ROOT_KEY_BLOCK_TYPE
;
58 ZwQuerySystemTime((PTIME
) &RootKeyBlock
->LastWriteTime
);
59 RootKeyBlock
->ParentKeyOffset
= 0;
60 RootKeyBlock
->NumberOfSubKeys
= 0;
61 RootKeyBlock
->HashTableOffset
= -1;
62 RootKeyBlock
->NumberOfValues
= 0;
63 RootKeyBlock
->ValuesOffset
= -1;
64 RootKeyBlock
->SecurityKeyOffset
= 0;
65 RootKeyBlock
->ClassNameOffset
= -1;
66 RootKeyBlock
->NameSize
= 0;
67 RootKeyBlock
->ClassSize
= 0;
70 NTSTATUS
CmiCreateNewRegFile( HANDLE FileHandle
)
73 PHEADER_BLOCK HeaderBlock
;
74 PHEAP_BLOCK HeapBlock
;
75 PKEY_BLOCK RootKeyBlock
;
76 PFREE_SUB_BLOCK FreeSubBlock
;
78 IO_STATUS_BLOCK IoStatusBlock
;
81 tBuf
= (char*) ExAllocatePool(NonPagedPool
, 2*REG_BLOCK_SIZE
);
83 return STATUS_INSUFFICIENT_RESOURCES
;
85 HeaderBlock
= (PHEADER_BLOCK
)tBuf
;
86 HeapBlock
= (PHEAP_BLOCK
) (tBuf
+REG_BLOCK_SIZE
);
87 RootKeyBlock
= (PKEY_BLOCK
) (tBuf
+REG_BLOCK_SIZE
+REG_HEAP_BLOCK_DATA_OFFSET
);
88 FreeSubBlock
= (PFREE_SUB_BLOCK
) (tBuf
+REG_BLOCK_SIZE
+REG_HEAP_BLOCK_DATA_OFFSET
+sizeof(KEY_BLOCK
));
90 CmiCreateDefaultHeaderBlock(HeaderBlock
);
91 CmiCreateDefaultHeapBlock(HeapBlock
);
92 CmiCreateDefaultRootKeyBlock(RootKeyBlock
);
94 HeapBlock
->BlockOffset
= 0; //First block.
95 HeaderBlock
->RootKeyBlock
= REG_HEAP_BLOCK_DATA_OFFSET
; //Offset to root key block.
96 //The rest of the block is free
97 FreeSubBlock
->SubBlockSize
= REG_BLOCK_SIZE
-(REG_HEAP_BLOCK_DATA_OFFSET
+sizeof(KEY_BLOCK
));
99 Status
= ZwWriteFile( FileHandle
, NULL
, NULL
, NULL
,
100 &IoStatusBlock
, tBuf
, 2*REG_BLOCK_SIZE
, 0, NULL
);
107 CmiCreateRegistry(PWSTR Filename
)
109 PREGISTRY_FILE RegistryFile
;
111 PKEY_BLOCK RootKeyBlock
;
113 LARGE_INTEGER fileOffset
;
114 PFREE_SUB_BLOCK FreeBlock
;
117 BLOCK_OFFSET BlockOffset
;
118 DPRINT1("CmiCreateRegistry() Filename '%S'\n", Filename
);
119 RegistryFile
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_FILE
));
121 if (RegistryFile
== NULL
)
124 if (Filename
!= NULL
)
126 UNICODE_STRING TmpFileName
;
127 OBJECT_ATTRIBUTES ObjectAttributes
;
129 FILE_STANDARD_INFORMATION fsi
;
130 IO_STATUS_BLOCK IoSB
;
132 /* Duplicate Filename */
133 RegistryFile
->Filename
= ExAllocatePool(NonPagedPool
, MAX_PATH
);
134 wcscpy(RegistryFile
->Filename
, Filename
);
136 RtlInitUnicodeString (&TmpFileName
, Filename
);
137 InitializeObjectAttributes(&ObjectAttributes
,
143 Status
= NtCreateFile( &FileHandle
,
148 FILE_ATTRIBUTE_NORMAL
,
151 FILE_NON_DIRECTORY_FILE
,
155 /* FIXME: create directory if IoSB.Status == STATUS_OBJECT_PATH_NOT_FOUND */
156 if( !NT_SUCCESS(Status
) )
158 ExFreePool(RegistryFile
->Filename
);
159 RegistryFile
->Filename
= NULL
;
162 /*if file did not exist*/
163 if( IoSB
.Information
== FILE_CREATED
){
164 Status
= CmiCreateNewRegFile( FileHandle
);
165 if( !NT_SUCCESS(Status
) )
167 ExFreePool(RegistryFile
->Filename
);
168 RegistryFile
->Filename
= NULL
;
173 RegistryFile
->HeaderBlock
= (PHEADER_BLOCK
)
174 ExAllocatePool(NonPagedPool
, sizeof(HEADER_BLOCK
));
176 fileOffset
.u
.HighPart
= 0;
177 fileOffset
.u
.LowPart
= 0;
178 Status
= ZwReadFile(FileHandle
,
180 RegistryFile
->HeaderBlock
,
181 sizeof(HEADER_BLOCK
),
183 if (!NT_SUCCESS(Status
))
185 ExFreePool(RegistryFile
->Filename
);
186 RegistryFile
->Filename
= NULL
;
190 Status
= ZwQueryInformationFile(FileHandle
,&IoSB
,&fsi
191 ,sizeof(fsi
),FileStandardInformation
);
192 if (!NT_SUCCESS(Status
))
194 ExFreePool(RegistryFile
->Filename
);
195 RegistryFile
->Filename
= NULL
;
198 RegistryFile
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
199 RegistryFile
->BlockListSize
= RegistryFile
->FileSize
/ 4096 -1;
200 // RegistryFile->NumberOfBlocks = RegistryFile->BlockListSize;
201 RegistryFile
->BlockList
= ExAllocatePool(NonPagedPool
,
202 sizeof(PHEAP_BLOCK
*) * (RegistryFile
->BlockListSize
));
204 fileOffset
.u
.HighPart
= 0;
205 fileOffset
.u
.LowPart
= 4096;
206 RegistryFile
->BlockList
[0]
207 = ExAllocatePool(NonPagedPool
,RegistryFile
->FileSize
-4096);
208 if (RegistryFile
->BlockList
[0] == NULL
)
210 // Status = STATUS_INSUFFICIENT_RESOURCES;
211 DPRINT1("error allocating %d bytes for registry\n"
212 ,RegistryFile
->FileSize
-4096);
216 Status
= ZwReadFile(FileHandle
,
218 RegistryFile
->BlockList
[0],
219 RegistryFile
->FileSize
-4096,
222 if (!NT_SUCCESS(Status
))
224 DPRINT1("error %x reading registry file at offset %x\n"
225 ,Status
,fileOffset
.u
.LowPart
);
228 RegistryFile
->FreeListSize
= 0;
229 RegistryFile
->FreeListMax
= 0;
230 RegistryFile
->FreeList
= NULL
;
231 for(i
=0 ; i
<RegistryFile
->BlockListSize
; i
++)
233 tmpHeap
= (PHEAP_BLOCK
)(((char *)RegistryFile
->BlockList
[0])+BlockOffset
);
234 if (tmpHeap
->BlockId
!= REG_HEAP_ID
)
236 DPRINT1("bad BlockId %x,offset %x\n",tmpHeap
->BlockId
,fileOffset
.u
.LowPart
);
238 RegistryFile
->BlockList
[i
]
240 if (tmpHeap
->BlockSize
>4096)
242 for(j
=1;j
<tmpHeap
->BlockSize
/4096;j
++)
243 RegistryFile
->BlockList
[i
+j
] = RegistryFile
->BlockList
[i
];
246 /* search free blocks and add to list */
247 FreeOffset
=REG_HEAP_BLOCK_DATA_OFFSET
;
248 while(FreeOffset
< tmpHeap
->BlockSize
)
250 FreeBlock
= (PFREE_SUB_BLOCK
)((char *)RegistryFile
->BlockList
[i
]
252 if ( FreeBlock
->SubBlockSize
>0)
254 CmiAddFree(RegistryFile
,FreeBlock
255 ,RegistryFile
->BlockList
[i
]->BlockOffset
+FreeOffset
);
256 FreeOffset
+= FreeBlock
->SubBlockSize
;
259 FreeOffset
-= FreeBlock
->SubBlockSize
;
261 BlockOffset
+= tmpHeap
->BlockSize
;
263 Status
= ObReferenceObjectByHandle(FileHandle
,
267 (PVOID
*)&RegistryFile
->FileObject
,
272 RegistryFile
->Filename
= NULL
;
273 RegistryFile
->FileObject
= NULL
;
275 RegistryFile
->HeaderBlock
= (PHEADER_BLOCK
)
276 ExAllocatePool(NonPagedPool
, sizeof(HEADER_BLOCK
));
277 CmiCreateDefaultHeaderBlock(RegistryFile
->HeaderBlock
);
279 RootKeyBlock
= (PKEY_BLOCK
) ExAllocatePool(NonPagedPool
, sizeof(KEY_BLOCK
));
280 CmiCreateDefaultRootKeyBlock(RootKeyBlock
);
282 RegistryFile
->HeaderBlock
->RootKeyBlock
= (BLOCK_OFFSET
) RootKeyBlock
;
284 KeInitializeSemaphore(&RegistryFile
->RegSem
, 1, 1);
290 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile
,
294 PHASH_TABLE_BLOCK HashBlock
;
295 PKEY_BLOCK CurSubKeyBlock
;
298 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
303 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
305 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
307 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
308 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
309 if (MaxName
< CurSubKeyBlock
->NameSize
)
311 MaxName
= CurSubKeyBlock
->NameSize
;
313 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
317 CmiReleaseBlock(RegistryFile
, HashBlock
);
323 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile
,
327 PHASH_TABLE_BLOCK HashBlock
;
328 PKEY_BLOCK CurSubKeyBlock
;
331 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
336 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
338 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
340 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
341 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
342 if (MaxClass
< CurSubKeyBlock
->ClassSize
)
344 MaxClass
= CurSubKeyBlock
->ClassSize
;
346 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
350 CmiReleaseBlock(RegistryFile
, HashBlock
);
356 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile
,
359 ULONG Idx
, MaxValueName
;
360 PVALUE_LIST_BLOCK ValueListBlock
;
361 PVALUE_BLOCK CurValueBlock
;
363 ValueListBlock
= CmiGetBlock(RegistryFile
,
364 KeyBlock
->ValuesOffset
,NULL
);
366 if (ValueListBlock
== 0)
370 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
372 CurValueBlock
= CmiGetBlock(RegistryFile
,
373 ValueListBlock
->Values
[Idx
],NULL
);
374 if (CurValueBlock
!= NULL
&&
375 MaxValueName
< CurValueBlock
->NameSize
)
377 MaxValueName
= CurValueBlock
->NameSize
;
379 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
382 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
388 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile
,
391 ULONG Idx
, MaxValueData
;
392 PVALUE_LIST_BLOCK ValueListBlock
;
393 PVALUE_BLOCK CurValueBlock
;
395 ValueListBlock
= CmiGetBlock(RegistryFile
,
396 KeyBlock
->ValuesOffset
,NULL
);
398 if (ValueListBlock
== 0)
402 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
404 CurValueBlock
= CmiGetBlock(RegistryFile
,
405 ValueListBlock
->Values
[Idx
],NULL
);
406 if (CurValueBlock
!= NULL
&&
407 MaxValueData
< (CurValueBlock
->DataSize
& LONG_MAX
) )
409 MaxValueData
= CurValueBlock
->DataSize
& LONG_MAX
;
411 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
414 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
420 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile
,
421 IN PKEY_BLOCK KeyBlock
,
422 OUT PKEY_BLOCK
*SubKeyBlock
,
423 OUT BLOCK_OFFSET
*BlockOffset
,
425 IN ACCESS_MASK DesiredAccess
,
429 PHASH_TABLE_BLOCK HashBlock
;
430 PKEY_BLOCK CurSubKeyBlock
;
431 WORD KeyLength
= strlen(KeyName
);
433 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
435 if (HashBlock
== NULL
)
437 return STATUS_SUCCESS
;
439 // for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
440 for (Idx
= 0; Idx
< KeyBlock
->NumberOfSubKeys
441 && Idx
< HashBlock
->HashTableSize
; Idx
++)
443 if (Attributes
& OBJ_CASE_INSENSITIVE
)
445 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0 &&
446 HashBlock
->Table
[Idx
].KeyOffset
!= -1 &&
447 !_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[Idx
].HashValue
, 4))
449 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
450 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
451 if ( CurSubKeyBlock
->NameSize
== KeyLength
452 && !_strnicmp(KeyName
, CurSubKeyBlock
->Name
, KeyLength
))
454 *SubKeyBlock
= CurSubKeyBlock
;
455 *BlockOffset
= HashBlock
->Table
[Idx
].KeyOffset
;
460 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
466 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0 &&
467 HashBlock
->Table
[Idx
].KeyOffset
!= -1 &&
468 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[Idx
].HashValue
, 4))
470 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
471 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
472 if ( CurSubKeyBlock
->NameSize
== KeyLength
473 && !_strnicmp(KeyName
, CurSubKeyBlock
->Name
, KeyLength
))
475 *SubKeyBlock
= CurSubKeyBlock
;
476 *BlockOffset
= HashBlock
->Table
[Idx
].KeyOffset
;
481 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
487 CmiReleaseBlock(RegistryFile
, HashBlock
);
489 return STATUS_SUCCESS
;
493 CmiAddSubKey(PREGISTRY_FILE RegistryFile
,
497 USHORT NewSubKeyNameSize
,
499 PUNICODE_STRING Class
,
502 PKEY_BLOCK KeyBlock
= Parent
->KeyBlock
;
504 PHASH_TABLE_BLOCK HashBlock
, NewHashBlock
;
505 PKEY_BLOCK NewKeyBlock
;
506 BLOCK_OFFSET NKBOffset
;
510 if (NewSubKeyName
[0] == L
'\\')
513 NameSize
= NewSubKeyNameSize
/2-1;
516 NameSize
= NewSubKeyNameSize
/2;
517 Status
= STATUS_SUCCESS
;
519 NewBlockSize
= sizeof(KEY_BLOCK
) + NameSize
;
520 Status
= CmiAllocateBlock(RegistryFile
, (PVOID
) &NewKeyBlock
521 , NewBlockSize
,&NKBOffset
);
522 if (NewKeyBlock
== NULL
)
524 Status
= STATUS_INSUFFICIENT_RESOURCES
;
528 NewKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
529 NewKeyBlock
->Type
= REG_KEY_BLOCK_TYPE
;
530 ZwQuerySystemTime((PTIME
) &NewKeyBlock
->LastWriteTime
);
531 NewKeyBlock
->ParentKeyOffset
= -1;
532 NewKeyBlock
->NumberOfSubKeys
= 0;
533 NewKeyBlock
->HashTableOffset
= -1;
534 NewKeyBlock
->NumberOfValues
= 0;
535 NewKeyBlock
->ValuesOffset
= -1;
536 NewKeyBlock
->SecurityKeyOffset
= -1;
537 NewKeyBlock
->NameSize
= NameSize
;
538 wcstombs(NewKeyBlock
->Name
,NewSubKeyName
,NameSize
);
539 NewKeyBlock
->ClassNameOffset
= -1;
543 NewKeyBlock
->ClassSize
= Class
->Length
+sizeof(WCHAR
);
544 Status
= CmiAllocateBlock(RegistryFile
546 ,NewKeyBlock
->ClassSize
547 ,&NewKeyBlock
->ClassNameOffset
);
548 wcsncpy((PWSTR
)pClass
->Data
,Class
->Buffer
,Class
->Length
);
549 ( (PWSTR
)(pClass
->Data
))[Class
->Length
]=0;
553 if (!NT_SUCCESS(Status
))
557 SubKey
->KeyBlock
= NewKeyBlock
;
558 SubKey
->BlockOffset
= NKBOffset
;
559 /* don't modify hash table if key is volatile and parent is not */
560 if (RegistryFile
== CmiVolatileFile
&& Parent
->RegistryFile
!= RegistryFile
)
564 if (KeyBlock
->HashTableOffset
== -1)
566 Status
= CmiAllocateHashTableBlock(RegistryFile
,
568 &KeyBlock
->HashTableOffset
,
569 REG_INIT_HASH_TABLE_SIZE
);
570 if (!NT_SUCCESS(Status
))
577 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
578 if (KeyBlock
->NumberOfSubKeys
+ 1 >= HashBlock
->HashTableSize
)
580 BLOCK_OFFSET HTOffset
;
582 /* Reallocate the hash table block */
583 Status
= CmiAllocateHashTableBlock(RegistryFile
,
586 HashBlock
->HashTableSize
+
587 REG_EXTEND_HASH_TABLE_SIZE
);
588 if (!NT_SUCCESS(Status
))
592 RtlZeroMemory(&NewHashBlock
->Table
[0],
593 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
594 RtlCopyMemory(&NewHashBlock
->Table
[0],
595 &HashBlock
->Table
[0],
596 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
597 CmiDestroyBlock(RegistryFile
, HashBlock
598 , KeyBlock
->HashTableOffset
);
599 KeyBlock
->HashTableOffset
= HTOffset
;
600 HashBlock
= NewHashBlock
;
603 Status
= CmiAddKeyToHashTable(RegistryFile
, HashBlock
, NewKeyBlock
,NKBOffset
);
604 if (NT_SUCCESS(Status
))
606 KeyBlock
->NumberOfSubKeys
++;
613 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile
,
614 IN PKEY_BLOCK KeyBlock
,
616 OUT PVALUE_BLOCK
*ValueBlock
,
617 OUT BLOCK_OFFSET
*VBOffset
)
620 PVALUE_LIST_BLOCK ValueListBlock
;
621 PVALUE_BLOCK CurValueBlock
;
622 ValueListBlock
= CmiGetBlock(RegistryFile
,
623 KeyBlock
->ValuesOffset
,NULL
);
625 if (ValueListBlock
== NULL
)
627 return STATUS_SUCCESS
;
629 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
631 CurValueBlock
= CmiGetBlock(RegistryFile
,
632 ValueListBlock
->Values
[Idx
],NULL
);
633 /* FIXME : perhaps we must not ignore case if NtCreateKey has not been */
634 /* called with OBJ_CASE_INSENSITIVE flag ? */
635 if (CurValueBlock
!= NULL
&&
636 CurValueBlock
->NameSize
== strlen(ValueName
) &&
637 !_strnicmp(CurValueBlock
->Name
, ValueName
,strlen(ValueName
)))
639 *ValueBlock
= CurValueBlock
;
640 if(VBOffset
) *VBOffset
= ValueListBlock
->Values
[Idx
];
643 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
646 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
648 return STATUS_SUCCESS
;
653 CmiGetValueFromKeyByIndex(IN PREGISTRY_FILE RegistryFile
,
654 IN PKEY_BLOCK KeyBlock
,
656 OUT PVALUE_BLOCK
*ValueBlock
)
658 PVALUE_LIST_BLOCK ValueListBlock
;
659 PVALUE_BLOCK CurValueBlock
;
660 ValueListBlock
= CmiGetBlock(RegistryFile
,
661 KeyBlock
->ValuesOffset
,NULL
);
663 if (ValueListBlock
== NULL
)
665 return STATUS_NO_MORE_ENTRIES
;
667 if (Index
>= KeyBlock
->NumberOfValues
)
669 return STATUS_NO_MORE_ENTRIES
;
671 CurValueBlock
= CmiGetBlock(RegistryFile
,
672 ValueListBlock
->Values
[Index
],NULL
);
673 if (CurValueBlock
!= NULL
)
675 *ValueBlock
= CurValueBlock
;
677 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
678 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
680 return STATUS_SUCCESS
;
684 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile
,
685 IN PKEY_BLOCK KeyBlock
,
686 IN PCHAR ValueNameBuf
,
687 OUT PVALUE_BLOCK
*pValueBlock
,
688 OUT BLOCK_OFFSET
*pVBOffset
)
691 PVALUE_LIST_BLOCK ValueListBlock
, NewValueListBlock
;
692 BLOCK_OFFSET VBOffset
;
693 BLOCK_OFFSET VLBOffset
;
694 PVALUE_BLOCK NewValueBlock
;
696 Status
= CmiAllocateValueBlock(RegistryFile
,
701 if (!NT_SUCCESS(Status
))
705 ValueListBlock
= CmiGetBlock(RegistryFile
,
706 KeyBlock
->ValuesOffset
,NULL
);
707 if (ValueListBlock
== NULL
)
709 Status
= CmiAllocateBlock(RegistryFile
,
710 (PVOID
) &ValueListBlock
,
711 sizeof(BLOCK_OFFSET
) * 3,
713 if (!NT_SUCCESS(Status
))
715 CmiDestroyValueBlock(RegistryFile
,
716 NewValueBlock
,VBOffset
);
719 KeyBlock
->ValuesOffset
= VLBOffset
;
721 else if ( KeyBlock
->NumberOfValues
722 >= -(ValueListBlock
->SubBlockSize
-4)/sizeof(BLOCK_OFFSET
))
724 Status
= CmiAllocateBlock(RegistryFile
,
725 (PVOID
) &NewValueListBlock
,
726 sizeof(BLOCK_OFFSET
) *
727 (KeyBlock
->NumberOfValues
+
728 REG_VALUE_LIST_BLOCK_MULTIPLE
),&VLBOffset
);
729 if (!NT_SUCCESS(Status
))
731 CmiDestroyValueBlock(RegistryFile
,
732 NewValueBlock
,VBOffset
);
735 RtlCopyMemory(&NewValueListBlock
->Values
[0],
736 &ValueListBlock
->Values
[0],
737 sizeof(BLOCK_OFFSET
) * KeyBlock
->NumberOfValues
);
738 CmiDestroyBlock(RegistryFile
, ValueListBlock
,KeyBlock
->ValuesOffset
);
739 KeyBlock
->ValuesOffset
= VLBOffset
;
740 ValueListBlock
= NewValueListBlock
;
742 ValueListBlock
->Values
[KeyBlock
->NumberOfValues
] = VBOffset
;
743 KeyBlock
->NumberOfValues
++;
744 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
745 CmiReleaseBlock(RegistryFile
, NewValueBlock
);
746 *pValueBlock
= NewValueBlock
;
748 return STATUS_SUCCESS
;
752 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile
,
753 IN PKEY_BLOCK KeyBlock
,
757 PVALUE_LIST_BLOCK ValueListBlock
;
758 PVALUE_BLOCK CurValueBlock
;
761 ValueListBlock
= CmiGetBlock(RegistryFile
,
762 KeyBlock
->ValuesOffset
,NULL
);
763 if (ValueListBlock
== 0)
765 return STATUS_SUCCESS
;
767 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
769 CurValueBlock
= CmiGetBlock(RegistryFile
,
770 ValueListBlock
->Values
[Idx
],&pHeap
);
771 if (CurValueBlock
!= NULL
&&
772 CurValueBlock
->NameSize
== strlen(ValueName
) &&
773 !memcmp(CurValueBlock
->Name
, ValueName
,strlen(ValueName
)))
775 if (KeyBlock
->NumberOfValues
- 1 < Idx
)
777 RtlCopyMemory(&ValueListBlock
->Values
[Idx
],
778 &ValueListBlock
->Values
[Idx
+ 1],
779 sizeof(BLOCK_OFFSET
) *
780 (KeyBlock
->NumberOfValues
- 1 - Idx
));
784 RtlZeroMemory(&ValueListBlock
->Values
[Idx
],
785 sizeof(BLOCK_OFFSET
));
787 KeyBlock
->NumberOfValues
-= 1;
788 CmiDestroyValueBlock(RegistryFile
, CurValueBlock
, ValueListBlock
->Values
[Idx
]);
789 /* update time of heap */
790 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
794 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
797 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
799 return STATUS_SUCCESS
;
803 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile
,
804 OUT PHASH_TABLE_BLOCK
*HashBlock
,
805 OUT BLOCK_OFFSET
*HBOffset
,
806 IN ULONG HashTableSize
)
810 PHASH_TABLE_BLOCK NewHashBlock
;
812 Status
= STATUS_SUCCESS
;
814 NewHashSize
= sizeof(HASH_TABLE_BLOCK
) +
815 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
816 Status
= CmiAllocateBlock(RegistryFile
,
817 (PVOID
*)&NewHashBlock
,
818 NewHashSize
,HBOffset
);
819 if (NewHashBlock
== NULL
|| !NT_SUCCESS(Status
) )
821 Status
= STATUS_INSUFFICIENT_RESOURCES
;
825 NewHashBlock
->SubBlockId
= REG_HASH_TABLE_BLOCK_ID
;
826 NewHashBlock
->HashTableSize
= HashTableSize
;
827 *HashBlock
= NewHashBlock
;
834 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile
,
835 PHASH_TABLE_BLOCK HashBlock
,
839 BLOCK_OFFSET KeyOffset
;
841 if( HashBlock
== NULL
)
843 if (RegistryFile
->Filename
== NULL
)
845 KeyBlock
= (PKEY_BLOCK
) HashBlock
->Table
[Index
].KeyOffset
;
849 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
850 KeyBlock
= CmiGetBlock(RegistryFile
,KeyOffset
,NULL
);
852 CmiLockBlock(RegistryFile
, KeyBlock
);
858 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile
,
859 PHASH_TABLE_BLOCK HashBlock
,
860 PKEY_BLOCK NewKeyBlock
,
861 BLOCK_OFFSET NKBOffset
)
865 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
867 if (HashBlock
->Table
[i
].KeyOffset
== 0)
869 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
870 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
,
873 return STATUS_SUCCESS
;
876 return STATUS_UNSUCCESSFUL
;
880 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile
,
881 PVALUE_BLOCK
*ValueBlock
,
882 BLOCK_OFFSET
*VBOffset
,
883 IN PCHAR ValueNameBuf
)
887 PVALUE_BLOCK NewValueBlock
;
889 Status
= STATUS_SUCCESS
;
891 NewValueSize
= sizeof(VALUE_BLOCK
) + strlen(ValueNameBuf
);
892 Status
= CmiAllocateBlock(RegistryFile
,
893 (PVOID
*)&NewValueBlock
,
894 NewValueSize
,VBOffset
);
895 if (NewValueBlock
== NULL
|| !NT_SUCCESS(Status
))
897 Status
= STATUS_INSUFFICIENT_RESOURCES
;
901 NewValueBlock
->SubBlockId
= REG_VALUE_BLOCK_ID
;
902 NewValueBlock
->NameSize
= strlen(ValueNameBuf
);
903 memcpy(NewValueBlock
->Name
, ValueNameBuf
,strlen(ValueNameBuf
));
904 NewValueBlock
->DataType
= 0;
905 NewValueBlock
->DataSize
= 0;
906 NewValueBlock
->DataOffset
= 0xffffffff;
907 *ValueBlock
= NewValueBlock
;
914 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile
,
915 PVALUE_BLOCK ValueBlock
, BLOCK_OFFSET VBOffset
)
921 /* first, release datas : */
922 if (ValueBlock
->DataSize
>0)
924 pBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
,&pHeap
);
925 Status
= CmiDestroyBlock(RegistryFile
, pBlock
, ValueBlock
->DataOffset
);
926 if (!NT_SUCCESS(Status
))
930 /* update time of heap */
931 if(RegistryFile
->Filename
)
932 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
935 Status
= CmiDestroyBlock(RegistryFile
, ValueBlock
, VBOffset
);
936 /* update time of heap */
937 if(RegistryFile
->Filename
&& CmiGetBlock(RegistryFile
, VBOffset
,&pHeap
))
938 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
943 CmiAddHeap(PREGISTRY_FILE RegistryFile
,PVOID
*NewBlock
,BLOCK_OFFSET
*NewBlockOffset
)
946 PHEAP_BLOCK
* tmpBlockList
;
947 PFREE_SUB_BLOCK tmpBlock
;
948 tmpHeap
=ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
949 tmpHeap
->BlockId
= REG_HEAP_ID
;
950 tmpHeap
->BlockOffset
= RegistryFile
->FileSize
- REG_BLOCK_SIZE
;
951 RegistryFile
->FileSize
+= REG_BLOCK_SIZE
;
952 tmpHeap
->BlockSize
= REG_BLOCK_SIZE
;
953 tmpHeap
->Unused1
= 0;
954 ZwQuerySystemTime((PTIME
) &tmpHeap
->DateModified
);
955 tmpHeap
->Unused2
= 0;
956 /* increase size of list of blocks */
957 tmpBlockList
=ExAllocatePool(NonPagedPool
,
958 sizeof(PHEAP_BLOCK
*) * (RegistryFile
->BlockListSize
+1));
959 if (tmpBlockList
== NULL
)
962 return(STATUS_INSUFFICIENT_RESOURCES
);
964 if(RegistryFile
->BlockListSize
> 0)
966 memcpy(tmpBlockList
,RegistryFile
->BlockList
,
967 sizeof(PHEAP_BLOCK
*)*(RegistryFile
->BlockListSize
));
968 ExFreePool(RegistryFile
->BlockList
);
970 RegistryFile
->BlockList
= tmpBlockList
;
971 RegistryFile
->BlockList
[RegistryFile
->BlockListSize
++] = tmpHeap
;
972 /* initialize a free block in this heap : */
973 tmpBlock
= (PFREE_SUB_BLOCK
)((char *) tmpHeap
+ REG_HEAP_BLOCK_DATA_OFFSET
);
974 tmpBlock
-> SubBlockSize
= (REG_BLOCK_SIZE
- REG_HEAP_BLOCK_DATA_OFFSET
) ;
975 *NewBlock
= (PVOID
)tmpBlock
;
977 *NewBlockOffset
= tmpHeap
->BlockOffset
+ REG_HEAP_BLOCK_DATA_OFFSET
;
978 /* FIXME : set first dword to block_offset of another free bloc */
979 return STATUS_SUCCESS
;
983 CmiAllocateBlock(PREGISTRY_FILE RegistryFile
,
986 BLOCK_OFFSET
* pBlockOffset
)
989 PFREE_SUB_BLOCK NewBlock
;
992 Status
= STATUS_SUCCESS
;
993 /* round to 16 bytes multiple */
994 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
996 /* Handle volatile files first */
997 if (RegistryFile
->Filename
== NULL
)
999 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
1000 if (NewBlock
== NULL
)
1002 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1006 RtlZeroMemory(NewBlock
, BlockSize
);
1007 NewBlock
->SubBlockSize
= BlockSize
;
1008 CmiLockBlock(RegistryFile
, NewBlock
);
1010 if (pBlockOffset
) *pBlockOffset
= (BLOCK_OFFSET
)NewBlock
;
1016 /* first search in free blocks */
1018 for (i
=0 ; i
<RegistryFile
->FreeListSize
; i
++)
1020 if(RegistryFile
->FreeList
[i
]->SubBlockSize
>=BlockSize
)
1022 NewBlock
= RegistryFile
->FreeList
[i
];
1024 *pBlockOffset
= RegistryFile
->FreeListOffset
[i
];
1025 /* update time of heap */
1026 if(RegistryFile
->Filename
1027 && CmiGetBlock(RegistryFile
, RegistryFile
->FreeListOffset
[i
],&pHeap
))
1028 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
1029 if( (i
+1) <RegistryFile
->FreeListSize
)
1031 memmove( &RegistryFile
->FreeList
[i
]
1032 ,&RegistryFile
->FreeList
[i
+1]
1033 ,sizeof(RegistryFile
->FreeList
[0])
1034 *(RegistryFile
->FreeListSize
-i
-1));
1035 memmove( &RegistryFile
->FreeListOffset
[i
]
1036 ,&RegistryFile
->FreeListOffset
[i
+1]
1037 ,sizeof(RegistryFile
->FreeListOffset
[0])
1038 *(RegistryFile
->FreeListSize
-i
-1));
1040 RegistryFile
->FreeListSize
--;
1044 /* need to extend hive file : */
1045 if (NewBlock
== NULL
)
1047 /* add a new block : */
1048 Status
= CmiAddHeap(RegistryFile
, (PVOID
*)&NewBlock
, pBlockOffset
);
1050 if (NT_SUCCESS(Status
))
1053 /* split the block in two parts */
1054 if(NewBlock
->SubBlockSize
> BlockSize
)
1056 NewBlock
= (PFREE_SUB_BLOCK
)((char *)NewBlock
+BlockSize
);
1057 NewBlock
->SubBlockSize
=((PFREE_SUB_BLOCK
) (*Block
))->SubBlockSize
-BlockSize
;
1058 CmiAddFree(RegistryFile
,NewBlock
,*pBlockOffset
+BlockSize
);
1060 else if(NewBlock
->SubBlockSize
< BlockSize
)
1061 return STATUS_UNSUCCESSFUL
;
1062 RtlZeroMemory(*Block
, BlockSize
);
1063 ((PFREE_SUB_BLOCK
)(*Block
)) ->SubBlockSize
= - BlockSize
;
1064 CmiLockBlock(RegistryFile
, *Block
);
1071 CmiDestroyBlock(PREGISTRY_FILE RegistryFile
,
1072 PVOID Block
,BLOCK_OFFSET Offset
)
1077 Status
= STATUS_SUCCESS
;
1079 if (RegistryFile
->Filename
== NULL
)
1081 CmiReleaseBlock(RegistryFile
, Block
);
1086 PFREE_SUB_BLOCK pFree
= Block
;
1087 if (pFree
->SubBlockSize
<0)
1088 pFree
->SubBlockSize
= -pFree
->SubBlockSize
;
1089 CmiAddFree(RegistryFile
,Block
,Offset
);
1090 CmiReleaseBlock(RegistryFile
, Block
);
1091 /* update time of heap */
1092 if(RegistryFile
->Filename
&& CmiGetBlock(RegistryFile
, Offset
,&pHeap
))
1093 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
1094 /* FIXME : set first dword to block_offset of another free bloc ? */
1095 /* FIXME : concatenate with previous and next block if free */
1102 CmiAddFree(PREGISTRY_FILE RegistryFile
,
1103 PFREE_SUB_BLOCK FreeBlock
,BLOCK_OFFSET FreeOffset
)
1105 PFREE_SUB_BLOCK
*tmpList
;
1106 BLOCK_OFFSET
*tmpListOffset
;
1107 int minInd
,maxInd
,medInd
;
1108 if( (RegistryFile
->FreeListSize
+1) > RegistryFile
->FreeListMax
)
1110 tmpList
=ExAllocatePool(PagedPool
1111 ,sizeof(PFREE_SUB_BLOCK
)*(RegistryFile
->FreeListMax
+32));
1112 if (tmpList
== NULL
)
1113 return STATUS_INSUFFICIENT_RESOURCES
;
1114 tmpListOffset
=ExAllocatePool(PagedPool
1115 ,sizeof(BLOCK_OFFSET
*)*(RegistryFile
->FreeListMax
+32));
1116 if (tmpListOffset
== NULL
)
1117 return STATUS_INSUFFICIENT_RESOURCES
;
1118 if (RegistryFile
->FreeListMax
)
1120 memcpy(tmpList
,RegistryFile
->FreeList
1121 ,sizeof(PFREE_SUB_BLOCK
)*(RegistryFile
->FreeListMax
));
1122 memcpy(tmpListOffset
,RegistryFile
->FreeListOffset
1123 ,sizeof(BLOCK_OFFSET
*)*(RegistryFile
->FreeListMax
));
1124 ExFreePool(RegistryFile
->FreeList
);
1125 ExFreePool(RegistryFile
->FreeListOffset
);
1127 RegistryFile
->FreeList
= tmpList
;
1128 RegistryFile
->FreeListOffset
= tmpListOffset
;
1129 RegistryFile
->FreeListMax
+=32;
1131 /* add new offset to free list, maintening list in ascending order */
1132 if ( RegistryFile
->FreeListSize
==0
1133 || RegistryFile
->FreeListOffset
[RegistryFile
->FreeListSize
-1] < FreeOffset
)
1135 /* add to end of list : */
1136 RegistryFile
->FreeList
[RegistryFile
->FreeListSize
] = FreeBlock
;
1137 RegistryFile
->FreeListOffset
[RegistryFile
->FreeListSize
++] = FreeOffset
;
1139 else if (RegistryFile
->FreeListOffset
[0] > FreeOffset
)
1141 /* add to begin of list : */
1142 memmove( &RegistryFile
->FreeList
[1],&RegistryFile
->FreeList
[0]
1143 ,sizeof(RegistryFile
->FreeList
[0])*RegistryFile
->FreeListSize
);
1144 memmove( &RegistryFile
->FreeListOffset
[1],&RegistryFile
->FreeListOffset
[0]
1145 ,sizeof(RegistryFile
->FreeListOffset
[0])*RegistryFile
->FreeListSize
);
1146 RegistryFile
->FreeList
[0] = FreeBlock
;
1147 RegistryFile
->FreeListOffset
[0] = FreeOffset
;
1148 RegistryFile
->FreeListSize
++;
1152 /* search where to insert : */
1154 maxInd
=RegistryFile
->FreeListSize
-1;
1155 while( (maxInd
-minInd
) >1)
1157 medInd
=(minInd
+maxInd
)/2;
1158 if (RegistryFile
->FreeListOffset
[medInd
] > FreeOffset
)
1163 /* insert before maxInd : */
1164 memmove( &RegistryFile
->FreeList
[maxInd
+1],&RegistryFile
->FreeList
[maxInd
]
1165 ,sizeof(RegistryFile
->FreeList
[0])
1166 *(RegistryFile
->FreeListSize
-minInd
));
1167 memmove( &RegistryFile
->FreeListOffset
[maxInd
+1]
1168 , &RegistryFile
->FreeListOffset
[maxInd
]
1169 , sizeof(RegistryFile
->FreeListOffset
[0])
1170 *(RegistryFile
->FreeListSize
-minInd
));
1171 RegistryFile
->FreeList
[maxInd
] = FreeBlock
;
1172 RegistryFile
->FreeListOffset
[maxInd
] = FreeOffset
;
1173 RegistryFile
->FreeListSize
++;
1175 return STATUS_SUCCESS
;
1179 CmiGetBlock(PREGISTRY_FILE RegistryFile
,
1180 BLOCK_OFFSET BlockOffset
,
1181 OUT PHEAP_BLOCK
* ppHeap
)
1183 if( BlockOffset
== 0 || BlockOffset
== -1) return NULL
;
1185 if (RegistryFile
->Filename
== NULL
)
1187 return (PVOID
)BlockOffset
;
1192 pHeap
= RegistryFile
->BlockList
[BlockOffset
/4096];
1193 if(ppHeap
) *ppHeap
= pHeap
;
1194 return ((char *)pHeap
1195 +(BlockOffset
- pHeap
->BlockOffset
));
1200 CmiLockBlock(PREGISTRY_FILE RegistryFile
,
1203 if (RegistryFile
->Filename
!= NULL
)
1205 /* FIXME : implement */
1210 CmiReleaseBlock(PREGISTRY_FILE RegistryFile
,
1213 if (RegistryFile
->Filename
!= NULL
)
1215 /* FIXME : implement */