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 DPRINT1("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 DPRINT1("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 DPRINT1("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 DPRINT1("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
)
631 PVALUE_LIST_BLOCK ValueListBlock
;
632 PVALUE_BLOCK CurValueBlock
;
633 ValueListBlock
= CmiGetBlock(RegistryFile
,
634 KeyBlock
->ValuesOffset
,NULL
);
636 if (ValueListBlock
== NULL
)
638 return STATUS_SUCCESS
;
640 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
642 CurValueBlock
= CmiGetBlock(RegistryFile
,
643 ValueListBlock
->Values
[Idx
],NULL
);
644 /* FIXME : perhaps we must not ignore case if NtCreateKey has not been */
645 /* called with OBJ_CASE_INSENSITIVE flag ? */
646 if (CurValueBlock
!= NULL
&&
647 CurValueBlock
->NameSize
== strlen(ValueName
) &&
648 !_strnicmp(CurValueBlock
->Name
, ValueName
,strlen(ValueName
)))
650 *ValueBlock
= CurValueBlock
;
651 if(VBOffset
) *VBOffset
= ValueListBlock
->Values
[Idx
];
654 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
657 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
659 return STATUS_SUCCESS
;
664 CmiGetValueFromKeyByIndex(IN PREGISTRY_FILE RegistryFile
,
665 IN PKEY_BLOCK KeyBlock
,
667 OUT PVALUE_BLOCK
*ValueBlock
)
669 PVALUE_LIST_BLOCK ValueListBlock
;
670 PVALUE_BLOCK CurValueBlock
;
671 ValueListBlock
= CmiGetBlock(RegistryFile
,
672 KeyBlock
->ValuesOffset
,NULL
);
674 if (ValueListBlock
== NULL
)
676 return STATUS_NO_MORE_ENTRIES
;
678 if (Index
>= KeyBlock
->NumberOfValues
)
680 return STATUS_NO_MORE_ENTRIES
;
682 CurValueBlock
= CmiGetBlock(RegistryFile
,
683 ValueListBlock
->Values
[Index
],NULL
);
684 if (CurValueBlock
!= NULL
)
686 *ValueBlock
= CurValueBlock
;
688 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
689 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
691 return STATUS_SUCCESS
;
695 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile
,
696 IN PKEY_BLOCK KeyBlock
,
697 IN PCHAR ValueNameBuf
,
698 OUT PVALUE_BLOCK
*pValueBlock
,
699 OUT BLOCK_OFFSET
*pVBOffset
)
702 PVALUE_LIST_BLOCK ValueListBlock
, NewValueListBlock
;
703 BLOCK_OFFSET VBOffset
;
704 BLOCK_OFFSET VLBOffset
;
705 PVALUE_BLOCK NewValueBlock
;
707 Status
= CmiAllocateValueBlock(RegistryFile
,
712 if (!NT_SUCCESS(Status
))
716 ValueListBlock
= CmiGetBlock(RegistryFile
,
717 KeyBlock
->ValuesOffset
,NULL
);
718 if (ValueListBlock
== NULL
)
720 Status
= CmiAllocateBlock(RegistryFile
,
721 (PVOID
) &ValueListBlock
,
722 sizeof(BLOCK_OFFSET
) * 3,
724 if (!NT_SUCCESS(Status
))
726 CmiDestroyValueBlock(RegistryFile
,
727 NewValueBlock
,VBOffset
);
730 KeyBlock
->ValuesOffset
= VLBOffset
;
732 else if ( KeyBlock
->NumberOfValues
733 >= -(ValueListBlock
->SubBlockSize
-4)/sizeof(BLOCK_OFFSET
))
735 Status
= CmiAllocateBlock(RegistryFile
,
736 (PVOID
) &NewValueListBlock
,
737 sizeof(BLOCK_OFFSET
) *
738 (KeyBlock
->NumberOfValues
+
739 REG_VALUE_LIST_BLOCK_MULTIPLE
),&VLBOffset
);
740 if (!NT_SUCCESS(Status
))
742 CmiDestroyValueBlock(RegistryFile
,
743 NewValueBlock
,VBOffset
);
746 RtlCopyMemory(&NewValueListBlock
->Values
[0],
747 &ValueListBlock
->Values
[0],
748 sizeof(BLOCK_OFFSET
) * KeyBlock
->NumberOfValues
);
749 CmiDestroyBlock(RegistryFile
, ValueListBlock
,KeyBlock
->ValuesOffset
);
750 KeyBlock
->ValuesOffset
= VLBOffset
;
751 ValueListBlock
= NewValueListBlock
;
753 ValueListBlock
->Values
[KeyBlock
->NumberOfValues
] = VBOffset
;
754 KeyBlock
->NumberOfValues
++;
755 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
756 CmiReleaseBlock(RegistryFile
, NewValueBlock
);
757 *pValueBlock
= NewValueBlock
;
759 return STATUS_SUCCESS
;
763 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile
,
764 IN PKEY_BLOCK KeyBlock
,
768 PVALUE_LIST_BLOCK ValueListBlock
;
769 PVALUE_BLOCK CurValueBlock
;
772 ValueListBlock
= CmiGetBlock(RegistryFile
,
773 KeyBlock
->ValuesOffset
,NULL
);
774 if (ValueListBlock
== 0)
776 return STATUS_SUCCESS
;
778 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
780 CurValueBlock
= CmiGetBlock(RegistryFile
,
781 ValueListBlock
->Values
[Idx
],&pHeap
);
782 if (CurValueBlock
!= NULL
&&
783 CurValueBlock
->NameSize
== strlen(ValueName
) &&
784 !memcmp(CurValueBlock
->Name
, ValueName
,strlen(ValueName
)))
786 if (KeyBlock
->NumberOfValues
- 1 < Idx
)
788 RtlCopyMemory(&ValueListBlock
->Values
[Idx
],
789 &ValueListBlock
->Values
[Idx
+ 1],
790 sizeof(BLOCK_OFFSET
) *
791 (KeyBlock
->NumberOfValues
- 1 - Idx
));
795 RtlZeroMemory(&ValueListBlock
->Values
[Idx
],
796 sizeof(BLOCK_OFFSET
));
798 KeyBlock
->NumberOfValues
-= 1;
799 CmiDestroyValueBlock(RegistryFile
, CurValueBlock
, ValueListBlock
->Values
[Idx
]);
800 /* update time of heap */
801 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
805 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
808 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
810 return STATUS_SUCCESS
;
814 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile
,
815 OUT PHASH_TABLE_BLOCK
*HashBlock
,
816 OUT BLOCK_OFFSET
*HBOffset
,
817 IN ULONG HashTableSize
)
821 PHASH_TABLE_BLOCK NewHashBlock
;
823 Status
= STATUS_SUCCESS
;
825 NewHashSize
= sizeof(HASH_TABLE_BLOCK
) +
826 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
827 Status
= CmiAllocateBlock(RegistryFile
,
828 (PVOID
*)&NewHashBlock
,
829 NewHashSize
,HBOffset
);
830 if (NewHashBlock
== NULL
|| !NT_SUCCESS(Status
) )
832 Status
= STATUS_INSUFFICIENT_RESOURCES
;
836 NewHashBlock
->SubBlockId
= REG_HASH_TABLE_BLOCK_ID
;
837 NewHashBlock
->HashTableSize
= HashTableSize
;
838 *HashBlock
= NewHashBlock
;
845 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile
,
846 PHASH_TABLE_BLOCK HashBlock
,
850 BLOCK_OFFSET KeyOffset
;
852 if( HashBlock
== NULL
)
854 if (RegistryFile
->Filename
== NULL
)
856 KeyBlock
= (PKEY_BLOCK
) HashBlock
->Table
[Index
].KeyOffset
;
860 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
861 KeyBlock
= CmiGetBlock(RegistryFile
,KeyOffset
,NULL
);
863 CmiLockBlock(RegistryFile
, KeyBlock
);
869 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile
,
870 PHASH_TABLE_BLOCK HashBlock
,
871 PKEY_BLOCK NewKeyBlock
,
872 BLOCK_OFFSET NKBOffset
)
876 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
878 if (HashBlock
->Table
[i
].KeyOffset
== 0)
880 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
881 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
,
884 return STATUS_SUCCESS
;
887 return STATUS_UNSUCCESSFUL
;
891 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile
,
892 PVALUE_BLOCK
*ValueBlock
,
893 BLOCK_OFFSET
*VBOffset
,
894 IN PCHAR ValueNameBuf
)
898 PVALUE_BLOCK NewValueBlock
;
900 Status
= STATUS_SUCCESS
;
902 NewValueSize
= sizeof(VALUE_BLOCK
) + strlen(ValueNameBuf
);
903 Status
= CmiAllocateBlock(RegistryFile
,
904 (PVOID
*)&NewValueBlock
,
905 NewValueSize
,VBOffset
);
906 if (NewValueBlock
== NULL
|| !NT_SUCCESS(Status
))
908 Status
= STATUS_INSUFFICIENT_RESOURCES
;
912 NewValueBlock
->SubBlockId
= REG_VALUE_BLOCK_ID
;
913 NewValueBlock
->NameSize
= strlen(ValueNameBuf
);
914 memcpy(NewValueBlock
->Name
, ValueNameBuf
,strlen(ValueNameBuf
));
915 NewValueBlock
->DataType
= 0;
916 NewValueBlock
->DataSize
= 0;
917 NewValueBlock
->DataOffset
= 0xffffffff;
918 *ValueBlock
= NewValueBlock
;
925 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile
,
926 PVALUE_BLOCK ValueBlock
, BLOCK_OFFSET VBOffset
)
932 /* first, release datas : */
933 if (ValueBlock
->DataSize
>0)
935 pBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
,&pHeap
);
936 Status
= CmiDestroyBlock(RegistryFile
, pBlock
, ValueBlock
->DataOffset
);
937 if (!NT_SUCCESS(Status
))
941 /* update time of heap */
942 if(RegistryFile
->Filename
)
943 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
946 Status
= CmiDestroyBlock(RegistryFile
, ValueBlock
, VBOffset
);
947 /* update time of heap */
948 if(RegistryFile
->Filename
&& CmiGetBlock(RegistryFile
, VBOffset
,&pHeap
))
949 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
954 CmiAddHeap(PREGISTRY_FILE RegistryFile
,PVOID
*NewBlock
,BLOCK_OFFSET
*NewBlockOffset
)
957 PHEAP_BLOCK
* tmpBlockList
;
958 PFREE_SUB_BLOCK tmpBlock
;
959 tmpHeap
=ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
960 tmpHeap
->BlockId
= REG_HEAP_ID
;
961 tmpHeap
->BlockOffset
= RegistryFile
->FileSize
- REG_BLOCK_SIZE
;
962 RegistryFile
->FileSize
+= REG_BLOCK_SIZE
;
963 tmpHeap
->BlockSize
= REG_BLOCK_SIZE
;
964 tmpHeap
->Unused1
= 0;
965 ZwQuerySystemTime((PTIME
) &tmpHeap
->DateModified
);
966 tmpHeap
->Unused2
= 0;
967 /* increase size of list of blocks */
968 tmpBlockList
=ExAllocatePool(NonPagedPool
,
969 sizeof(PHEAP_BLOCK
*) * (RegistryFile
->BlockListSize
+1));
970 if (tmpBlockList
== NULL
)
973 return(STATUS_INSUFFICIENT_RESOURCES
);
975 if(RegistryFile
->BlockListSize
> 0)
977 memcpy(tmpBlockList
,RegistryFile
->BlockList
,
978 sizeof(PHEAP_BLOCK
*)*(RegistryFile
->BlockListSize
));
979 ExFreePool(RegistryFile
->BlockList
);
981 RegistryFile
->BlockList
= tmpBlockList
;
982 RegistryFile
->BlockList
[RegistryFile
->BlockListSize
++] = tmpHeap
;
983 /* initialize a free block in this heap : */
984 tmpBlock
= (PFREE_SUB_BLOCK
)((char *) tmpHeap
+ REG_HEAP_BLOCK_DATA_OFFSET
);
985 tmpBlock
-> SubBlockSize
= (REG_BLOCK_SIZE
- REG_HEAP_BLOCK_DATA_OFFSET
) ;
986 *NewBlock
= (PVOID
)tmpBlock
;
988 *NewBlockOffset
= tmpHeap
->BlockOffset
+ REG_HEAP_BLOCK_DATA_OFFSET
;
989 /* FIXME : set first dword to block_offset of another free bloc */
990 return STATUS_SUCCESS
;
994 CmiAllocateBlock(PREGISTRY_FILE RegistryFile
,
997 BLOCK_OFFSET
* pBlockOffset
)
1000 PFREE_SUB_BLOCK NewBlock
;
1003 Status
= STATUS_SUCCESS
;
1004 /* round to 16 bytes multiple */
1005 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
1007 /* Handle volatile files first */
1008 if (RegistryFile
->Filename
== NULL
)
1010 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
1011 if (NewBlock
== NULL
)
1013 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1017 RtlZeroMemory(NewBlock
, BlockSize
);
1018 NewBlock
->SubBlockSize
= BlockSize
;
1019 CmiLockBlock(RegistryFile
, NewBlock
);
1021 if (pBlockOffset
) *pBlockOffset
= (BLOCK_OFFSET
)NewBlock
;
1027 /* first search in free blocks */
1029 for (i
=0 ; i
<RegistryFile
->FreeListSize
; i
++)
1031 if(RegistryFile
->FreeList
[i
]->SubBlockSize
>=BlockSize
)
1033 NewBlock
= RegistryFile
->FreeList
[i
];
1035 *pBlockOffset
= RegistryFile
->FreeListOffset
[i
];
1036 /* update time of heap */
1037 if(RegistryFile
->Filename
1038 && CmiGetBlock(RegistryFile
, RegistryFile
->FreeListOffset
[i
],&pHeap
))
1039 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
1040 if( (i
+1) <RegistryFile
->FreeListSize
)
1042 memmove( &RegistryFile
->FreeList
[i
]
1043 ,&RegistryFile
->FreeList
[i
+1]
1044 ,sizeof(RegistryFile
->FreeList
[0])
1045 *(RegistryFile
->FreeListSize
-i
-1));
1046 memmove( &RegistryFile
->FreeListOffset
[i
]
1047 ,&RegistryFile
->FreeListOffset
[i
+1]
1048 ,sizeof(RegistryFile
->FreeListOffset
[0])
1049 *(RegistryFile
->FreeListSize
-i
-1));
1051 RegistryFile
->FreeListSize
--;
1055 /* need to extend hive file : */
1056 if (NewBlock
== NULL
)
1058 /* add a new block : */
1059 Status
= CmiAddHeap(RegistryFile
, (PVOID
*)&NewBlock
, pBlockOffset
);
1061 if (NT_SUCCESS(Status
))
1064 /* split the block in two parts */
1065 if(NewBlock
->SubBlockSize
> BlockSize
)
1067 NewBlock
= (PFREE_SUB_BLOCK
)((char *)NewBlock
+BlockSize
);
1068 NewBlock
->SubBlockSize
=((PFREE_SUB_BLOCK
) (*Block
))->SubBlockSize
-BlockSize
;
1069 CmiAddFree(RegistryFile
,NewBlock
,*pBlockOffset
+BlockSize
);
1071 else if(NewBlock
->SubBlockSize
< BlockSize
)
1072 return STATUS_UNSUCCESSFUL
;
1073 RtlZeroMemory(*Block
, BlockSize
);
1074 ((PFREE_SUB_BLOCK
)(*Block
)) ->SubBlockSize
= - BlockSize
;
1075 CmiLockBlock(RegistryFile
, *Block
);
1082 CmiDestroyBlock(PREGISTRY_FILE RegistryFile
,
1083 PVOID Block
,BLOCK_OFFSET Offset
)
1088 Status
= STATUS_SUCCESS
;
1090 if (RegistryFile
->Filename
== NULL
)
1092 CmiReleaseBlock(RegistryFile
, Block
);
1097 PFREE_SUB_BLOCK pFree
= Block
;
1098 if (pFree
->SubBlockSize
<0)
1099 pFree
->SubBlockSize
= -pFree
->SubBlockSize
;
1100 CmiAddFree(RegistryFile
,Block
,Offset
);
1101 CmiReleaseBlock(RegistryFile
, Block
);
1102 /* update time of heap */
1103 if(RegistryFile
->Filename
&& CmiGetBlock(RegistryFile
, Offset
,&pHeap
))
1104 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
1105 /* FIXME : set first dword to block_offset of another free bloc ? */
1106 /* FIXME : concatenate with previous and next block if free */
1113 CmiAddFree(PREGISTRY_FILE RegistryFile
,
1114 PFREE_SUB_BLOCK FreeBlock
,BLOCK_OFFSET FreeOffset
)
1116 PFREE_SUB_BLOCK
*tmpList
;
1117 BLOCK_OFFSET
*tmpListOffset
;
1118 int minInd
,maxInd
,medInd
;
1119 if( (RegistryFile
->FreeListSize
+1) > RegistryFile
->FreeListMax
)
1121 tmpList
=ExAllocatePool(PagedPool
1122 ,sizeof(PFREE_SUB_BLOCK
)*(RegistryFile
->FreeListMax
+32));
1123 if (tmpList
== NULL
)
1124 return STATUS_INSUFFICIENT_RESOURCES
;
1125 tmpListOffset
=ExAllocatePool(PagedPool
1126 ,sizeof(BLOCK_OFFSET
*)*(RegistryFile
->FreeListMax
+32));
1127 if (tmpListOffset
== NULL
)
1128 return STATUS_INSUFFICIENT_RESOURCES
;
1129 if (RegistryFile
->FreeListMax
)
1131 memcpy(tmpList
,RegistryFile
->FreeList
1132 ,sizeof(PFREE_SUB_BLOCK
)*(RegistryFile
->FreeListMax
));
1133 memcpy(tmpListOffset
,RegistryFile
->FreeListOffset
1134 ,sizeof(BLOCK_OFFSET
*)*(RegistryFile
->FreeListMax
));
1135 ExFreePool(RegistryFile
->FreeList
);
1136 ExFreePool(RegistryFile
->FreeListOffset
);
1138 RegistryFile
->FreeList
= tmpList
;
1139 RegistryFile
->FreeListOffset
= tmpListOffset
;
1140 RegistryFile
->FreeListMax
+=32;
1142 /* add new offset to free list, maintening list in ascending order */
1143 if ( RegistryFile
->FreeListSize
==0
1144 || RegistryFile
->FreeListOffset
[RegistryFile
->FreeListSize
-1] < FreeOffset
)
1146 /* add to end of list : */
1147 RegistryFile
->FreeList
[RegistryFile
->FreeListSize
] = FreeBlock
;
1148 RegistryFile
->FreeListOffset
[RegistryFile
->FreeListSize
++] = FreeOffset
;
1150 else if (RegistryFile
->FreeListOffset
[0] > FreeOffset
)
1152 /* add to begin of list : */
1153 memmove( &RegistryFile
->FreeList
[1],&RegistryFile
->FreeList
[0]
1154 ,sizeof(RegistryFile
->FreeList
[0])*RegistryFile
->FreeListSize
);
1155 memmove( &RegistryFile
->FreeListOffset
[1],&RegistryFile
->FreeListOffset
[0]
1156 ,sizeof(RegistryFile
->FreeListOffset
[0])*RegistryFile
->FreeListSize
);
1157 RegistryFile
->FreeList
[0] = FreeBlock
;
1158 RegistryFile
->FreeListOffset
[0] = FreeOffset
;
1159 RegistryFile
->FreeListSize
++;
1163 /* search where to insert : */
1165 maxInd
=RegistryFile
->FreeListSize
-1;
1166 while( (maxInd
-minInd
) >1)
1168 medInd
=(minInd
+maxInd
)/2;
1169 if (RegistryFile
->FreeListOffset
[medInd
] > FreeOffset
)
1174 /* insert before maxInd : */
1175 memmove( &RegistryFile
->FreeList
[maxInd
+1],&RegistryFile
->FreeList
[maxInd
]
1176 ,sizeof(RegistryFile
->FreeList
[0])
1177 *(RegistryFile
->FreeListSize
-minInd
));
1178 memmove( &RegistryFile
->FreeListOffset
[maxInd
+1]
1179 , &RegistryFile
->FreeListOffset
[maxInd
]
1180 , sizeof(RegistryFile
->FreeListOffset
[0])
1181 *(RegistryFile
->FreeListSize
-minInd
));
1182 RegistryFile
->FreeList
[maxInd
] = FreeBlock
;
1183 RegistryFile
->FreeListOffset
[maxInd
] = FreeOffset
;
1184 RegistryFile
->FreeListSize
++;
1186 return STATUS_SUCCESS
;
1190 CmiGetBlock(PREGISTRY_FILE RegistryFile
,
1191 BLOCK_OFFSET BlockOffset
,
1192 OUT PHEAP_BLOCK
* ppHeap
)
1194 if( BlockOffset
== 0 || BlockOffset
== -1) return NULL
;
1196 if (RegistryFile
->Filename
== NULL
)
1198 return (PVOID
)BlockOffset
;
1203 pHeap
= RegistryFile
->BlockList
[BlockOffset
/4096];
1204 if(ppHeap
) *ppHeap
= pHeap
;
1205 return ((char *)pHeap
1206 +(BlockOffset
- pHeap
->BlockOffset
));
1211 CmiLockBlock(PREGISTRY_FILE RegistryFile
,
1214 if (RegistryFile
->Filename
!= NULL
)
1216 /* FIXME : implement */
1221 CmiReleaseBlock(PREGISTRY_FILE RegistryFile
,
1224 if (RegistryFile
->Filename
!= NULL
)
1226 /* FIXME : implement */