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
;
119 RegistryFile
= ExAllocatePool(NonPagedPool
, sizeof(REGISTRY_FILE
));
120 if (Filename
!= NULL
)
122 UNICODE_STRING TmpFileName
;
123 OBJECT_ATTRIBUTES ObjectAttributes
;
125 FILE_STANDARD_INFORMATION fsi
;
126 IO_STATUS_BLOCK IoSB
;
128 /* Duplicate Filename */
129 RegistryFile
->Filename
= ExAllocatePool(NonPagedPool
, MAX_PATH
);
130 wcscpy(RegistryFile
->Filename
, Filename
);
132 RtlInitUnicodeString (&TmpFileName
, Filename
);
133 InitializeObjectAttributes(&ObjectAttributes
,
139 Status
= NtCreateFile( &FileHandle
,
144 FILE_ATTRIBUTE_NORMAL
,
147 FILE_NON_DIRECTORY_FILE
,
151 /* FIXME: create directory if IoSB.Status == STATUS_OBJECT_PATH_NOT_FOUND */
152 if( !NT_SUCCESS(Status
) )
154 ExFreePool(RegistryFile
->Filename
);
155 RegistryFile
->Filename
= NULL
;
158 /*if file did not exist*/
159 if( IoSB
.Information
== FILE_CREATED
){
160 Status
= CmiCreateNewRegFile( FileHandle
);
161 if( !NT_SUCCESS(Status
) )
163 ExFreePool(RegistryFile
->Filename
);
164 RegistryFile
->Filename
= NULL
;
169 RegistryFile
->HeaderBlock
= (PHEADER_BLOCK
)
170 ExAllocatePool(NonPagedPool
, sizeof(HEADER_BLOCK
));
172 fileOffset
.u
.HighPart
= 0;
173 fileOffset
.u
.LowPart
= 0;
174 Status
= ZwReadFile(FileHandle
,
176 RegistryFile
->HeaderBlock
,
177 sizeof(HEADER_BLOCK
),
179 ZwQueryInformationFile(FileHandle
,&IoSB
,&fsi
180 ,sizeof(fsi
),FileStandardInformation
);
181 RegistryFile
->FileSize
= fsi
.EndOfFile
.u
.LowPart
;
182 RegistryFile
->BlockListSize
= RegistryFile
->FileSize
/ 4096 -1;
183 // RegistryFile->NumberOfBlocks = RegistryFile->BlockListSize;
184 RegistryFile
->BlockList
= ExAllocatePool(NonPagedPool
,
185 sizeof(PHEAP_BLOCK
*) * (RegistryFile
->BlockListSize
));
187 fileOffset
.u
.HighPart
= 0;
188 fileOffset
.u
.LowPart
= 4096;
189 RegistryFile
->BlockList
[0]
190 = ExAllocatePool(NonPagedPool
,RegistryFile
->FileSize
-4096);
191 if (RegistryFile
->BlockList
[0] == NULL
)
193 // Status = STATUS_INSUFFICIENT_RESOURCES;
194 DPRINT1("error allocating %d bytes for registry\n"
195 ,RegistryFile
->FileSize
-4096);
199 Status
= ZwReadFile(FileHandle
,
201 RegistryFile
->BlockList
[0],
202 RegistryFile
->FileSize
-4096,
205 if (!NT_SUCCESS(Status
))
207 DPRINT1("error %x reading registry file at offset %x\n"
208 ,Status
,fileOffset
.u
.LowPart
);
211 RegistryFile
->FreeListSize
= 0;
212 RegistryFile
->FreeListMax
= 0;
213 RegistryFile
->FreeList
= NULL
;
214 for(i
=0 ; i
<RegistryFile
->BlockListSize
; i
++)
216 tmpHeap
= (PHEAP_BLOCK
)(((char *)RegistryFile
->BlockList
[0])+BlockOffset
);
217 if (tmpHeap
->BlockId
!= REG_HEAP_ID
)
219 DPRINT1("bad BlockId %x,offset %x\n",tmpHeap
->BlockId
,fileOffset
.u
.LowPart
);
221 RegistryFile
->BlockList
[i
]
223 if (tmpHeap
->BlockSize
>4096)
225 for(j
=1;j
<tmpHeap
->BlockSize
/4096;j
++)
226 RegistryFile
->BlockList
[i
+j
] = RegistryFile
->BlockList
[i
];
229 /* search free blocks and add to list */
230 FreeOffset
=REG_HEAP_BLOCK_DATA_OFFSET
;
231 while(FreeOffset
< tmpHeap
->BlockSize
)
233 FreeBlock
= (PFREE_SUB_BLOCK
)((char *)RegistryFile
->BlockList
[i
]
235 if ( FreeBlock
->SubBlockSize
>0)
237 CmiAddFree(RegistryFile
,FreeBlock
238 ,RegistryFile
->BlockList
[i
]->BlockOffset
+FreeOffset
);
239 FreeOffset
+= FreeBlock
->SubBlockSize
;
242 FreeOffset
-= FreeBlock
->SubBlockSize
;
244 BlockOffset
+= tmpHeap
->BlockSize
;
246 Status
= ObReferenceObjectByHandle(FileHandle
,
250 (PVOID
*)&RegistryFile
->FileObject
,
255 RegistryFile
->Filename
= NULL
;
256 RegistryFile
->FileObject
= NULL
;
258 RegistryFile
->HeaderBlock
= (PHEADER_BLOCK
)
259 ExAllocatePool(NonPagedPool
, sizeof(HEADER_BLOCK
));
260 CmiCreateDefaultHeaderBlock(RegistryFile
->HeaderBlock
);
262 RootKeyBlock
= (PKEY_BLOCK
) ExAllocatePool(NonPagedPool
, sizeof(KEY_BLOCK
));
263 CmiCreateDefaultRootKeyBlock(RootKeyBlock
);
265 RegistryFile
->HeaderBlock
->RootKeyBlock
= (BLOCK_OFFSET
) RootKeyBlock
;
267 KeInitializeSemaphore(&RegistryFile
->RegSem
, 1, 1);
273 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile
,
277 PHASH_TABLE_BLOCK HashBlock
;
278 PKEY_BLOCK CurSubKeyBlock
;
281 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
286 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
288 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
290 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
291 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
292 if (MaxName
< CurSubKeyBlock
->NameSize
)
294 MaxName
= CurSubKeyBlock
->NameSize
;
296 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
300 CmiReleaseBlock(RegistryFile
, HashBlock
);
306 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile
,
310 PHASH_TABLE_BLOCK HashBlock
;
311 PKEY_BLOCK CurSubKeyBlock
;
314 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
319 for (Idx
= 0; Idx
< HashBlock
->HashTableSize
; Idx
++)
321 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0)
323 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
324 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
325 if (MaxClass
< CurSubKeyBlock
->ClassSize
)
327 MaxClass
= CurSubKeyBlock
->ClassSize
;
329 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
333 CmiReleaseBlock(RegistryFile
, HashBlock
);
339 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile
,
342 ULONG Idx
, MaxValueName
;
343 PVALUE_LIST_BLOCK ValueListBlock
;
344 PVALUE_BLOCK CurValueBlock
;
346 ValueListBlock
= CmiGetBlock(RegistryFile
,
347 KeyBlock
->ValuesOffset
,NULL
);
349 if (ValueListBlock
== 0)
353 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
355 CurValueBlock
= CmiGetBlock(RegistryFile
,
356 ValueListBlock
->Values
[Idx
],NULL
);
357 if (CurValueBlock
!= NULL
&&
358 MaxValueName
< CurValueBlock
->NameSize
)
360 MaxValueName
= CurValueBlock
->NameSize
;
362 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
365 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
371 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile
,
374 ULONG Idx
, MaxValueData
;
375 PVALUE_LIST_BLOCK ValueListBlock
;
376 PVALUE_BLOCK CurValueBlock
;
378 ValueListBlock
= CmiGetBlock(RegistryFile
,
379 KeyBlock
->ValuesOffset
,NULL
);
381 if (ValueListBlock
== 0)
385 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
387 CurValueBlock
= CmiGetBlock(RegistryFile
,
388 ValueListBlock
->Values
[Idx
],NULL
);
389 if (CurValueBlock
!= NULL
&&
390 MaxValueData
< (CurValueBlock
->DataSize
& LONG_MAX
) )
392 MaxValueData
= CurValueBlock
->DataSize
& LONG_MAX
;
394 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
397 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
403 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile
,
404 IN PKEY_BLOCK KeyBlock
,
405 OUT PKEY_BLOCK
*SubKeyBlock
,
406 OUT BLOCK_OFFSET
*BlockOffset
,
408 IN ACCESS_MASK DesiredAccess
,
412 PHASH_TABLE_BLOCK HashBlock
;
413 PKEY_BLOCK CurSubKeyBlock
;
414 WORD KeyLength
= strlen(KeyName
);
416 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
418 if (HashBlock
== NULL
)
420 return STATUS_SUCCESS
;
422 // for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
423 for (Idx
= 0; Idx
< KeyBlock
->NumberOfSubKeys
424 && Idx
< HashBlock
->HashTableSize
; Idx
++)
426 if (Attributes
& OBJ_CASE_INSENSITIVE
)
428 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0 &&
429 HashBlock
->Table
[Idx
].KeyOffset
!= -1 &&
430 !_strnicmp(KeyName
, (PCHAR
) &HashBlock
->Table
[Idx
].HashValue
, 4))
432 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
433 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
434 if ( CurSubKeyBlock
->NameSize
== KeyLength
435 && !_strnicmp(KeyName
, CurSubKeyBlock
->Name
, KeyLength
))
437 *SubKeyBlock
= CurSubKeyBlock
;
438 *BlockOffset
= HashBlock
->Table
[Idx
].KeyOffset
;
443 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
449 if (HashBlock
->Table
[Idx
].KeyOffset
!= 0 &&
450 HashBlock
->Table
[Idx
].KeyOffset
!= -1 &&
451 !strncmp(KeyName
, (PCHAR
) &HashBlock
->Table
[Idx
].HashValue
, 4))
453 CurSubKeyBlock
= CmiGetBlock(RegistryFile
,
454 HashBlock
->Table
[Idx
].KeyOffset
,NULL
);
455 if ( CurSubKeyBlock
->NameSize
== KeyLength
456 && !_strnicmp(KeyName
, CurSubKeyBlock
->Name
, KeyLength
))
458 *SubKeyBlock
= CurSubKeyBlock
;
459 *BlockOffset
= HashBlock
->Table
[Idx
].KeyOffset
;
464 CmiReleaseBlock(RegistryFile
, CurSubKeyBlock
);
470 CmiReleaseBlock(RegistryFile
, HashBlock
);
472 return STATUS_SUCCESS
;
476 CmiAddSubKey(PREGISTRY_FILE RegistryFile
,
480 USHORT NewSubKeyNameSize
,
482 PUNICODE_STRING Class
,
485 PKEY_BLOCK KeyBlock
= Parent
->KeyBlock
;
487 PHASH_TABLE_BLOCK HashBlock
, NewHashBlock
;
488 PKEY_BLOCK NewKeyBlock
;
489 BLOCK_OFFSET NKBOffset
;
493 if (NewSubKeyName
[0] == L
'\\')
496 NameSize
= NewSubKeyNameSize
/2-1;
499 NameSize
= NewSubKeyNameSize
/2;
500 Status
= STATUS_SUCCESS
;
502 NewBlockSize
= sizeof(KEY_BLOCK
) + NameSize
;
503 Status
= CmiAllocateBlock(RegistryFile
, (PVOID
) &NewKeyBlock
504 , NewBlockSize
,&NKBOffset
);
505 if (NewKeyBlock
== NULL
)
507 Status
= STATUS_INSUFFICIENT_RESOURCES
;
511 NewKeyBlock
->SubBlockId
= REG_KEY_BLOCK_ID
;
512 NewKeyBlock
->Type
= REG_KEY_BLOCK_TYPE
;
513 ZwQuerySystemTime((PTIME
) &NewKeyBlock
->LastWriteTime
);
514 NewKeyBlock
->ParentKeyOffset
= -1;
515 NewKeyBlock
->NumberOfSubKeys
= 0;
516 NewKeyBlock
->HashTableOffset
= -1;
517 NewKeyBlock
->NumberOfValues
= 0;
518 NewKeyBlock
->ValuesOffset
= -1;
519 NewKeyBlock
->SecurityKeyOffset
= -1;
520 NewKeyBlock
->NameSize
= NameSize
;
521 wcstombs(NewKeyBlock
->Name
,NewSubKeyName
,NameSize
);
522 NewKeyBlock
->ClassNameOffset
= -1;
526 NewKeyBlock
->ClassSize
= Class
->Length
+sizeof(WCHAR
);
527 Status
= CmiAllocateBlock(RegistryFile
529 ,NewKeyBlock
->ClassSize
530 ,&NewKeyBlock
->ClassNameOffset
);
531 wcsncpy((PWSTR
)pClass
->Data
,Class
->Buffer
,Class
->Length
);
532 ( (PWSTR
)(pClass
->Data
))[Class
->Length
]=0;
536 if (!NT_SUCCESS(Status
))
540 SubKey
->KeyBlock
= NewKeyBlock
;
541 SubKey
->BlockOffset
= NKBOffset
;
542 /* don't modify hash table if key is volatile and parent is not */
543 if (RegistryFile
== CmiVolatileFile
&& Parent
->RegistryFile
!= RegistryFile
)
547 if (KeyBlock
->HashTableOffset
== -1)
549 Status
= CmiAllocateHashTableBlock(RegistryFile
,
551 &KeyBlock
->HashTableOffset
,
552 REG_INIT_HASH_TABLE_SIZE
);
553 if (!NT_SUCCESS(Status
))
560 HashBlock
= CmiGetBlock(RegistryFile
, KeyBlock
->HashTableOffset
,NULL
);
561 if (KeyBlock
->NumberOfSubKeys
+ 1 >= HashBlock
->HashTableSize
)
563 BLOCK_OFFSET HTOffset
;
565 /* Reallocate the hash table block */
566 Status
= CmiAllocateHashTableBlock(RegistryFile
,
569 HashBlock
->HashTableSize
+
570 REG_EXTEND_HASH_TABLE_SIZE
);
571 if (!NT_SUCCESS(Status
))
575 RtlZeroMemory(&NewHashBlock
->Table
[0],
576 sizeof(NewHashBlock
->Table
[0]) * NewHashBlock
->HashTableSize
);
577 RtlCopyMemory(&NewHashBlock
->Table
[0],
578 &HashBlock
->Table
[0],
579 sizeof(NewHashBlock
->Table
[0]) * HashBlock
->HashTableSize
);
580 CmiDestroyBlock(RegistryFile
, HashBlock
581 , KeyBlock
->HashTableOffset
);
582 KeyBlock
->HashTableOffset
= HTOffset
;
583 HashBlock
= NewHashBlock
;
586 Status
= CmiAddKeyToHashTable(RegistryFile
, HashBlock
, NewKeyBlock
,NKBOffset
);
587 if (NT_SUCCESS(Status
))
589 KeyBlock
->NumberOfSubKeys
++;
596 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile
,
597 IN PKEY_BLOCK KeyBlock
,
599 OUT PVALUE_BLOCK
*ValueBlock
,
600 OUT BLOCK_OFFSET
*VBOffset
)
603 PVALUE_LIST_BLOCK ValueListBlock
;
604 PVALUE_BLOCK CurValueBlock
;
605 ValueListBlock
= CmiGetBlock(RegistryFile
,
606 KeyBlock
->ValuesOffset
,NULL
);
608 if (ValueListBlock
== NULL
)
610 return STATUS_SUCCESS
;
612 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
614 CurValueBlock
= CmiGetBlock(RegistryFile
,
615 ValueListBlock
->Values
[Idx
],NULL
);
616 /* FIXME : perhaps we must not ignore case if NtCreateKey has not been */
617 /* called with OBJ_CASE_INSENSITIVE flag ? */
618 if (CurValueBlock
!= NULL
&&
619 CurValueBlock
->NameSize
== strlen(ValueName
) &&
620 !_strnicmp(CurValueBlock
->Name
, ValueName
,strlen(ValueName
)))
622 *ValueBlock
= CurValueBlock
;
623 if(VBOffset
) *VBOffset
= ValueListBlock
->Values
[Idx
];
626 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
629 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
631 return STATUS_SUCCESS
;
636 CmiGetValueFromKeyByIndex(IN PREGISTRY_FILE RegistryFile
,
637 IN PKEY_BLOCK KeyBlock
,
639 OUT PVALUE_BLOCK
*ValueBlock
)
641 PVALUE_LIST_BLOCK ValueListBlock
;
642 PVALUE_BLOCK CurValueBlock
;
643 ValueListBlock
= CmiGetBlock(RegistryFile
,
644 KeyBlock
->ValuesOffset
,NULL
);
646 if (ValueListBlock
== NULL
)
648 return STATUS_NO_MORE_ENTRIES
;
650 if (Index
>= KeyBlock
->NumberOfValues
)
652 return STATUS_NO_MORE_ENTRIES
;
654 CurValueBlock
= CmiGetBlock(RegistryFile
,
655 ValueListBlock
->Values
[Index
],NULL
);
656 if (CurValueBlock
!= NULL
)
658 *ValueBlock
= CurValueBlock
;
660 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
661 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
663 return STATUS_SUCCESS
;
667 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile
,
668 IN PKEY_BLOCK KeyBlock
,
669 IN PCHAR ValueNameBuf
,
670 OUT PVALUE_BLOCK
*pValueBlock
,
671 OUT BLOCK_OFFSET
*pVBOffset
)
674 PVALUE_LIST_BLOCK ValueListBlock
, NewValueListBlock
;
675 BLOCK_OFFSET VBOffset
;
676 BLOCK_OFFSET VLBOffset
;
677 PVALUE_BLOCK NewValueBlock
;
679 Status
= CmiAllocateValueBlock(RegistryFile
,
684 if (!NT_SUCCESS(Status
))
688 ValueListBlock
= CmiGetBlock(RegistryFile
,
689 KeyBlock
->ValuesOffset
,NULL
);
690 if (ValueListBlock
== NULL
)
692 Status
= CmiAllocateBlock(RegistryFile
,
693 (PVOID
) &ValueListBlock
,
694 sizeof(BLOCK_OFFSET
) * 3,
696 if (!NT_SUCCESS(Status
))
698 CmiDestroyValueBlock(RegistryFile
,
699 NewValueBlock
,VBOffset
);
702 KeyBlock
->ValuesOffset
= VLBOffset
;
704 else if ( KeyBlock
->NumberOfValues
705 >= -(ValueListBlock
->SubBlockSize
-4)/sizeof(BLOCK_OFFSET
))
707 Status
= CmiAllocateBlock(RegistryFile
,
708 (PVOID
) &NewValueListBlock
,
709 sizeof(BLOCK_OFFSET
) *
710 (KeyBlock
->NumberOfValues
+
711 REG_VALUE_LIST_BLOCK_MULTIPLE
),&VLBOffset
);
712 if (!NT_SUCCESS(Status
))
714 CmiDestroyValueBlock(RegistryFile
,
715 NewValueBlock
,VBOffset
);
718 RtlCopyMemory(&NewValueListBlock
->Values
[0],
719 &ValueListBlock
->Values
[0],
720 sizeof(BLOCK_OFFSET
) * KeyBlock
->NumberOfValues
);
721 CmiDestroyBlock(RegistryFile
, ValueListBlock
,KeyBlock
->ValuesOffset
);
722 KeyBlock
->ValuesOffset
= VLBOffset
;
723 ValueListBlock
= NewValueListBlock
;
725 ValueListBlock
->Values
[KeyBlock
->NumberOfValues
] = VBOffset
;
726 KeyBlock
->NumberOfValues
++;
727 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
728 CmiReleaseBlock(RegistryFile
, NewValueBlock
);
729 *pValueBlock
= NewValueBlock
;
731 return STATUS_SUCCESS
;
735 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile
,
736 IN PKEY_BLOCK KeyBlock
,
740 PVALUE_LIST_BLOCK ValueListBlock
;
741 PVALUE_BLOCK CurValueBlock
;
744 ValueListBlock
= CmiGetBlock(RegistryFile
,
745 KeyBlock
->ValuesOffset
,NULL
);
746 if (ValueListBlock
== 0)
748 return STATUS_SUCCESS
;
750 for (Idx
= 0; Idx
< KeyBlock
->NumberOfValues
; Idx
++)
752 CurValueBlock
= CmiGetBlock(RegistryFile
,
753 ValueListBlock
->Values
[Idx
],&pHeap
);
754 if (CurValueBlock
!= NULL
&&
755 CurValueBlock
->NameSize
== strlen(ValueName
) &&
756 !memcmp(CurValueBlock
->Name
, ValueName
,strlen(ValueName
)))
758 if (KeyBlock
->NumberOfValues
- 1 < Idx
)
760 RtlCopyMemory(&ValueListBlock
->Values
[Idx
],
761 &ValueListBlock
->Values
[Idx
+ 1],
762 sizeof(BLOCK_OFFSET
) *
763 (KeyBlock
->NumberOfValues
- 1 - Idx
));
767 RtlZeroMemory(&ValueListBlock
->Values
[Idx
],
768 sizeof(BLOCK_OFFSET
));
770 KeyBlock
->NumberOfValues
-= 1;
771 CmiDestroyValueBlock(RegistryFile
, CurValueBlock
, ValueListBlock
->Values
[Idx
]);
772 /* update time of heap */
773 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
777 CmiReleaseBlock(RegistryFile
, CurValueBlock
);
780 CmiReleaseBlock(RegistryFile
, ValueListBlock
);
782 return STATUS_SUCCESS
;
786 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile
,
787 OUT PHASH_TABLE_BLOCK
*HashBlock
,
788 OUT BLOCK_OFFSET
*HBOffset
,
789 IN ULONG HashTableSize
)
793 PHASH_TABLE_BLOCK NewHashBlock
;
795 Status
= STATUS_SUCCESS
;
797 NewHashSize
= sizeof(HASH_TABLE_BLOCK
) +
798 (HashTableSize
- 1) * sizeof(HASH_RECORD
);
799 Status
= CmiAllocateBlock(RegistryFile
,
800 (PVOID
*)&NewHashBlock
,
801 NewHashSize
,HBOffset
);
802 if (NewHashBlock
== NULL
|| !NT_SUCCESS(Status
) )
804 Status
= STATUS_INSUFFICIENT_RESOURCES
;
808 NewHashBlock
->SubBlockId
= REG_HASH_TABLE_BLOCK_ID
;
809 NewHashBlock
->HashTableSize
= HashTableSize
;
810 *HashBlock
= NewHashBlock
;
817 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile
,
818 PHASH_TABLE_BLOCK HashBlock
,
822 BLOCK_OFFSET KeyOffset
;
824 if( HashBlock
== NULL
)
826 if (RegistryFile
->Filename
== NULL
)
828 KeyBlock
= (PKEY_BLOCK
) HashBlock
->Table
[Index
].KeyOffset
;
832 KeyOffset
= HashBlock
->Table
[Index
].KeyOffset
;
833 KeyBlock
= CmiGetBlock(RegistryFile
,KeyOffset
,NULL
);
835 CmiLockBlock(RegistryFile
, KeyBlock
);
841 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile
,
842 PHASH_TABLE_BLOCK HashBlock
,
843 PKEY_BLOCK NewKeyBlock
,
844 BLOCK_OFFSET NKBOffset
)
848 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
850 if (HashBlock
->Table
[i
].KeyOffset
== 0)
852 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
853 RtlCopyMemory(&HashBlock
->Table
[i
].HashValue
,
856 return STATUS_SUCCESS
;
859 return STATUS_UNSUCCESSFUL
;
863 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile
,
864 PVALUE_BLOCK
*ValueBlock
,
865 BLOCK_OFFSET
*VBOffset
,
866 IN PCHAR ValueNameBuf
)
870 PVALUE_BLOCK NewValueBlock
;
872 Status
= STATUS_SUCCESS
;
874 NewValueSize
= sizeof(VALUE_BLOCK
) + strlen(ValueNameBuf
);
875 Status
= CmiAllocateBlock(RegistryFile
,
876 (PVOID
*)&NewValueBlock
,
877 NewValueSize
,VBOffset
);
878 if (NewValueBlock
== NULL
|| !NT_SUCCESS(Status
))
880 Status
= STATUS_INSUFFICIENT_RESOURCES
;
884 NewValueBlock
->SubBlockId
= REG_VALUE_BLOCK_ID
;
885 NewValueBlock
->NameSize
= strlen(ValueNameBuf
);
886 memcpy(NewValueBlock
->Name
, ValueNameBuf
,strlen(ValueNameBuf
));
887 NewValueBlock
->DataType
= 0;
888 NewValueBlock
->DataSize
= 0;
889 NewValueBlock
->DataOffset
= 0xffffffff;
890 *ValueBlock
= NewValueBlock
;
897 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile
,
898 PVALUE_BLOCK ValueBlock
, BLOCK_OFFSET VBOffset
)
904 /* first, release datas : */
905 if (ValueBlock
->DataSize
>0)
907 pBlock
= CmiGetBlock(RegistryFile
, ValueBlock
->DataOffset
,&pHeap
);
908 Status
= CmiDestroyBlock(RegistryFile
, pBlock
, ValueBlock
->DataOffset
);
909 if (!NT_SUCCESS(Status
))
913 /* update time of heap */
914 if(RegistryFile
->Filename
)
915 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
918 Status
= CmiDestroyBlock(RegistryFile
, ValueBlock
, VBOffset
);
919 /* update time of heap */
920 if(RegistryFile
->Filename
&& CmiGetBlock(RegistryFile
, VBOffset
,&pHeap
))
921 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
926 CmiAddHeap(PREGISTRY_FILE RegistryFile
,PVOID
*NewBlock
,BLOCK_OFFSET
*NewBlockOffset
)
929 PHEAP_BLOCK
* tmpBlockList
;
930 PFREE_SUB_BLOCK tmpBlock
;
931 tmpHeap
=ExAllocatePool(PagedPool
, REG_BLOCK_SIZE
);
932 tmpHeap
->BlockId
= REG_HEAP_ID
;
933 tmpHeap
->BlockOffset
= RegistryFile
->FileSize
- REG_BLOCK_SIZE
;
934 RegistryFile
->FileSize
+= REG_BLOCK_SIZE
;
935 tmpHeap
->BlockSize
= REG_BLOCK_SIZE
;
936 tmpHeap
->Unused1
= 0;
937 ZwQuerySystemTime((PTIME
) &tmpHeap
->DateModified
);
938 tmpHeap
->Unused2
= 0;
939 /* increase size of list of blocks */
940 tmpBlockList
=ExAllocatePool(NonPagedPool
,
941 sizeof(PHEAP_BLOCK
*) * (RegistryFile
->BlockListSize
+1));
942 if (tmpBlockList
== NULL
)
945 return(STATUS_INSUFFICIENT_RESOURCES
);
947 if(RegistryFile
->BlockListSize
> 0)
949 memcpy(tmpBlockList
,RegistryFile
->BlockList
,
950 sizeof(PHEAP_BLOCK
*)*(RegistryFile
->BlockListSize
));
951 ExFreePool(RegistryFile
->BlockList
);
953 RegistryFile
->BlockList
= tmpBlockList
;
954 RegistryFile
->BlockList
[RegistryFile
->BlockListSize
++] = tmpHeap
;
955 /* initialize a free block in this heap : */
956 tmpBlock
= (PFREE_SUB_BLOCK
)((char *) tmpHeap
+ REG_HEAP_BLOCK_DATA_OFFSET
);
957 tmpBlock
-> SubBlockSize
= (REG_BLOCK_SIZE
- REG_HEAP_BLOCK_DATA_OFFSET
) ;
958 *NewBlock
= (PVOID
)tmpBlock
;
960 *NewBlockOffset
= tmpHeap
->BlockOffset
+ REG_HEAP_BLOCK_DATA_OFFSET
;
961 /* FIXME : set first dword to block_offset of another free bloc */
962 return STATUS_SUCCESS
;
966 CmiAllocateBlock(PREGISTRY_FILE RegistryFile
,
969 BLOCK_OFFSET
* pBlockOffset
)
972 PFREE_SUB_BLOCK NewBlock
;
975 Status
= STATUS_SUCCESS
;
976 /* round to 16 bytes multiple */
977 BlockSize
= (BlockSize
+ sizeof(DWORD
) + 15) & 0xfffffff0;
979 /* Handle volatile files first */
980 if (RegistryFile
->Filename
== NULL
)
982 NewBlock
= ExAllocatePool(NonPagedPool
, BlockSize
);
983 if (NewBlock
== NULL
)
985 Status
= STATUS_INSUFFICIENT_RESOURCES
;
989 RtlZeroMemory(NewBlock
, BlockSize
);
990 NewBlock
->SubBlockSize
= BlockSize
;
991 CmiLockBlock(RegistryFile
, NewBlock
);
993 if (pBlockOffset
) *pBlockOffset
= (BLOCK_OFFSET
)NewBlock
;
999 /* first search in free blocks */
1001 for (i
=0 ; i
<RegistryFile
->FreeListSize
; i
++)
1003 if(RegistryFile
->FreeList
[i
]->SubBlockSize
>=BlockSize
)
1005 NewBlock
= RegistryFile
->FreeList
[i
];
1007 *pBlockOffset
= RegistryFile
->FreeListOffset
[i
];
1008 /* update time of heap */
1009 if(RegistryFile
->Filename
1010 && CmiGetBlock(RegistryFile
, RegistryFile
->FreeListOffset
[i
],&pHeap
))
1011 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
1012 if( (i
+1) <RegistryFile
->FreeListSize
)
1014 memmove( &RegistryFile
->FreeList
[i
]
1015 ,&RegistryFile
->FreeList
[i
+1]
1016 ,sizeof(RegistryFile
->FreeList
[0])
1017 *(RegistryFile
->FreeListSize
-i
-1));
1018 memmove( &RegistryFile
->FreeListOffset
[i
]
1019 ,&RegistryFile
->FreeListOffset
[i
+1]
1020 ,sizeof(RegistryFile
->FreeListOffset
[0])
1021 *(RegistryFile
->FreeListSize
-i
-1));
1023 RegistryFile
->FreeListSize
--;
1027 /* need to extend hive file : */
1028 if (NewBlock
== NULL
)
1030 /* add a new block : */
1031 Status
= CmiAddHeap(RegistryFile
, (PVOID
*)&NewBlock
, pBlockOffset
);
1033 if (NT_SUCCESS(Status
))
1036 /* split the block in two parts */
1037 if(NewBlock
->SubBlockSize
> BlockSize
)
1039 NewBlock
= (PFREE_SUB_BLOCK
)((char *)NewBlock
+BlockSize
);
1040 NewBlock
->SubBlockSize
=((PFREE_SUB_BLOCK
) (*Block
))->SubBlockSize
-BlockSize
;
1041 CmiAddFree(RegistryFile
,NewBlock
,*pBlockOffset
+BlockSize
);
1043 else if(NewBlock
->SubBlockSize
< BlockSize
)
1044 return STATUS_UNSUCCESSFUL
;
1045 RtlZeroMemory(*Block
, BlockSize
);
1046 ((PFREE_SUB_BLOCK
)(*Block
)) ->SubBlockSize
= - BlockSize
;
1047 CmiLockBlock(RegistryFile
, *Block
);
1054 CmiDestroyBlock(PREGISTRY_FILE RegistryFile
,
1055 PVOID Block
,BLOCK_OFFSET Offset
)
1060 Status
= STATUS_SUCCESS
;
1062 if (RegistryFile
->Filename
== NULL
)
1064 CmiReleaseBlock(RegistryFile
, Block
);
1069 PFREE_SUB_BLOCK pFree
= Block
;
1070 if (pFree
->SubBlockSize
<0)
1071 pFree
->SubBlockSize
= -pFree
->SubBlockSize
;
1072 CmiAddFree(RegistryFile
,Block
,Offset
);
1073 CmiReleaseBlock(RegistryFile
, Block
);
1074 /* update time of heap */
1075 if(RegistryFile
->Filename
&& CmiGetBlock(RegistryFile
, Offset
,&pHeap
))
1076 ZwQuerySystemTime((PTIME
) &pHeap
->DateModified
);
1077 /* FIXME : set first dword to block_offset of another free bloc ? */
1078 /* FIXME : concatenate with previous and next block if free */
1085 CmiAddFree(PREGISTRY_FILE RegistryFile
,
1086 PFREE_SUB_BLOCK FreeBlock
,BLOCK_OFFSET FreeOffset
)
1088 PFREE_SUB_BLOCK
*tmpList
;
1089 BLOCK_OFFSET
*tmpListOffset
;
1090 int minInd
,maxInd
,medInd
;
1091 if( (RegistryFile
->FreeListSize
+1) > RegistryFile
->FreeListMax
)
1093 tmpList
=ExAllocatePool(PagedPool
1094 ,sizeof(PFREE_SUB_BLOCK
)*(RegistryFile
->FreeListMax
+32));
1095 if (tmpList
== NULL
)
1096 return STATUS_INSUFFICIENT_RESOURCES
;
1097 tmpListOffset
=ExAllocatePool(PagedPool
1098 ,sizeof(BLOCK_OFFSET
*)*(RegistryFile
->FreeListMax
+32));
1099 if (tmpListOffset
== NULL
)
1100 return STATUS_INSUFFICIENT_RESOURCES
;
1101 if (RegistryFile
->FreeListMax
)
1103 memcpy(tmpList
,RegistryFile
->FreeList
1104 ,sizeof(PFREE_SUB_BLOCK
)*(RegistryFile
->FreeListMax
));
1105 memcpy(tmpListOffset
,RegistryFile
->FreeListOffset
1106 ,sizeof(BLOCK_OFFSET
*)*(RegistryFile
->FreeListMax
));
1107 ExFreePool(RegistryFile
->FreeList
);
1108 ExFreePool(RegistryFile
->FreeListOffset
);
1110 RegistryFile
->FreeList
= tmpList
;
1111 RegistryFile
->FreeListOffset
= tmpListOffset
;
1112 RegistryFile
->FreeListMax
+=32;
1114 /* add new offset to free list, maintening list in ascending order */
1115 if ( RegistryFile
->FreeListSize
==0
1116 || RegistryFile
->FreeListOffset
[RegistryFile
->FreeListSize
-1] < FreeOffset
)
1118 /* add to end of list : */
1119 RegistryFile
->FreeList
[RegistryFile
->FreeListSize
] = FreeBlock
;
1120 RegistryFile
->FreeListOffset
[RegistryFile
->FreeListSize
++] = FreeOffset
;
1122 else if (RegistryFile
->FreeListOffset
[0] > FreeOffset
)
1124 /* add to begin of list : */
1125 memmove( &RegistryFile
->FreeList
[1],&RegistryFile
->FreeList
[0]
1126 ,sizeof(RegistryFile
->FreeList
[0])*RegistryFile
->FreeListSize
);
1127 memmove( &RegistryFile
->FreeListOffset
[1],&RegistryFile
->FreeListOffset
[0]
1128 ,sizeof(RegistryFile
->FreeListOffset
[0])*RegistryFile
->FreeListSize
);
1129 RegistryFile
->FreeList
[0] = FreeBlock
;
1130 RegistryFile
->FreeListOffset
[0] = FreeOffset
;
1131 RegistryFile
->FreeListSize
++;
1135 /* search where to insert : */
1137 maxInd
=RegistryFile
->FreeListSize
-1;
1138 while( (maxInd
-minInd
) >1)
1140 medInd
=(minInd
+maxInd
)/2;
1141 if (RegistryFile
->FreeListOffset
[medInd
] > FreeOffset
)
1146 /* insert before maxInd : */
1147 memmove( &RegistryFile
->FreeList
[maxInd
+1],&RegistryFile
->FreeList
[maxInd
]
1148 ,sizeof(RegistryFile
->FreeList
[0])
1149 *(RegistryFile
->FreeListSize
-minInd
));
1150 memmove( &RegistryFile
->FreeListOffset
[maxInd
+1]
1151 , &RegistryFile
->FreeListOffset
[maxInd
]
1152 , sizeof(RegistryFile
->FreeListOffset
[0])
1153 *(RegistryFile
->FreeListSize
-minInd
));
1154 RegistryFile
->FreeList
[maxInd
] = FreeBlock
;
1155 RegistryFile
->FreeListOffset
[maxInd
] = FreeOffset
;
1156 RegistryFile
->FreeListSize
++;
1158 return STATUS_SUCCESS
;
1162 CmiGetBlock(PREGISTRY_FILE RegistryFile
,
1163 BLOCK_OFFSET BlockOffset
,
1164 OUT PHEAP_BLOCK
* ppHeap
)
1166 if( BlockOffset
== 0 || BlockOffset
== -1) return NULL
;
1168 if (RegistryFile
->Filename
== NULL
)
1170 return (PVOID
)BlockOffset
;
1175 pHeap
= RegistryFile
->BlockList
[BlockOffset
/4096];
1176 if(ppHeap
) *ppHeap
= pHeap
;
1177 return ((char *)pHeap
1178 +(BlockOffset
- pHeap
->BlockOffset
));
1183 CmiLockBlock(PREGISTRY_FILE RegistryFile
,
1186 if (RegistryFile
->Filename
!= NULL
)
1188 /* FIXME : implement */
1193 CmiReleaseBlock(PREGISTRY_FILE RegistryFile
,
1196 if (RegistryFile
->Filename
!= NULL
)
1198 /* FIXME : implement */