From Eugene Ingerman:
[reactos.git] / reactos / ntoskrnl / cm / regfile.c
1 /*
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
6 * UPDATE HISTORY:
7 */
8
9 #include "cm.h"
10
11
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
24
25
26 extern PREGISTRY_FILE CmiVolatileFile;
27
28 void CmiCreateDefaultHeaderBlock(PHEADER_BLOCK HeaderBlock)
29 {
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;
41 }
42
43 void CmiCreateDefaultHeapBlock(PHEAP_BLOCK HeapBlock)
44 {
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;
50 }
51
52 void CmiCreateDefaultRootKeyBlock(PKEY_BLOCK RootKeyBlock)
53 {
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;
68 }
69
70 NTSTATUS CmiCreateNewRegFile( HANDLE FileHandle )
71 {
72 NTSTATUS Status;
73 PHEADER_BLOCK HeaderBlock;
74 PHEAP_BLOCK HeapBlock;
75 PKEY_BLOCK RootKeyBlock;
76 PFREE_SUB_BLOCK FreeSubBlock;
77
78 IO_STATUS_BLOCK IoStatusBlock;
79 char* tBuf;
80
81 tBuf = (char*) ExAllocatePool(NonPagedPool, 2*REG_BLOCK_SIZE);
82 if( tBuf == NULL )
83 return STATUS_INSUFFICIENT_RESOURCES;
84
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));
89
90 CmiCreateDefaultHeaderBlock(HeaderBlock);
91 CmiCreateDefaultHeapBlock(HeapBlock);
92 CmiCreateDefaultRootKeyBlock(RootKeyBlock);
93
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));
98
99 Status = ZwWriteFile( FileHandle, NULL, NULL, NULL,
100 &IoStatusBlock, tBuf, 2*REG_BLOCK_SIZE, 0, NULL );
101
102 ExFreePool( tBuf );
103 return Status;
104 }
105
106 PREGISTRY_FILE
107 CmiCreateRegistry(PWSTR Filename)
108 {
109 PREGISTRY_FILE RegistryFile;
110 HANDLE FileHandle;
111 PKEY_BLOCK RootKeyBlock;
112 PHEAP_BLOCK tmpHeap;
113 LARGE_INTEGER fileOffset;
114 PFREE_SUB_BLOCK FreeBlock;
115 DWORD FreeOffset;
116 int i, j;
117 BLOCK_OFFSET BlockOffset;
118
119 RegistryFile = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_FILE));
120 if (Filename != NULL)
121 {
122 UNICODE_STRING TmpFileName;
123 OBJECT_ATTRIBUTES ObjectAttributes;
124 NTSTATUS Status;
125 FILE_STANDARD_INFORMATION fsi;
126 IO_STATUS_BLOCK IoSB;
127
128 /* Duplicate Filename */
129 RegistryFile->Filename = ExAllocatePool(NonPagedPool, MAX_PATH);
130 wcscpy(RegistryFile->Filename , Filename);
131
132 RtlInitUnicodeString (&TmpFileName, Filename);
133 InitializeObjectAttributes(&ObjectAttributes,
134 &TmpFileName,
135 0,
136 NULL,
137 NULL);
138
139 Status = NtCreateFile( &FileHandle,
140 FILE_ALL_ACCESS,
141 &ObjectAttributes,
142 &IoSB,
143 NULL,
144 FILE_ATTRIBUTE_NORMAL,
145 0,
146 FILE_OPEN_IF,
147 FILE_NON_DIRECTORY_FILE,
148 NULL,
149 0 );
150
151 /* FIXME: create directory if IoSB.Status == STATUS_OBJECT_PATH_NOT_FOUND */
152 if( !NT_SUCCESS(Status) )
153 {
154 ExFreePool(RegistryFile->Filename);
155 RegistryFile->Filename = NULL;
156 return NULL;
157 }
158 /*if file did not exist*/
159 if( IoSB.Information == FILE_CREATED ){
160 Status = CmiCreateNewRegFile( FileHandle );
161 if( !NT_SUCCESS(Status) )
162 {
163 ExFreePool(RegistryFile->Filename);
164 RegistryFile->Filename = NULL;
165 return NULL;
166 }
167 }
168
169 RegistryFile->HeaderBlock = (PHEADER_BLOCK)
170 ExAllocatePool(NonPagedPool, sizeof(HEADER_BLOCK));
171
172 fileOffset.u.HighPart = 0;
173 fileOffset.u.LowPart = 0;
174 Status = ZwReadFile(FileHandle,
175 0, 0, 0, 0,
176 RegistryFile->HeaderBlock,
177 sizeof(HEADER_BLOCK),
178 &fileOffset, 0);
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 ));
186 BlockOffset=0;
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)
192 {
193 // Status = STATUS_INSUFFICIENT_RESOURCES;
194 DPRINT1("error allocating %d bytes for registry\n"
195 ,RegistryFile->FileSize-4096);
196 ZwClose(FileHandle);
197 return NULL;
198 }
199 Status = ZwReadFile(FileHandle,
200 0, 0, 0, 0,
201 RegistryFile->BlockList [0],
202 RegistryFile->FileSize-4096,
203 &fileOffset, 0);
204 ZwClose(FileHandle);
205 if (!NT_SUCCESS(Status))
206 {
207 DPRINT1("error %x reading registry file at offset %x\n"
208 ,Status,fileOffset.u.LowPart);
209 return NULL;
210 }
211 RegistryFile->FreeListSize = 0;
212 RegistryFile->FreeListMax = 0;
213 RegistryFile->FreeList = NULL;
214 for(i=0 ; i <RegistryFile->BlockListSize; i++)
215 {
216 tmpHeap = (PHEAP_BLOCK)(((char *)RegistryFile->BlockList [0])+BlockOffset);
217 if (tmpHeap->BlockId != REG_HEAP_ID )
218 {
219 DPRINT1("bad BlockId %x,offset %x\n",tmpHeap->BlockId,fileOffset.u.LowPart);
220 }
221 RegistryFile->BlockList [i]
222 = tmpHeap;
223 if (tmpHeap->BlockSize >4096)
224 {
225 for(j=1;j<tmpHeap->BlockSize/4096;j++)
226 RegistryFile->BlockList[i+j] = RegistryFile->BlockList[i];
227 i = i+j-1;
228 }
229 /* search free blocks and add to list */
230 FreeOffset=REG_HEAP_BLOCK_DATA_OFFSET;
231 while(FreeOffset < tmpHeap->BlockSize)
232 {
233 FreeBlock = (PFREE_SUB_BLOCK)((char *)RegistryFile->BlockList[i]
234 +FreeOffset);
235 if ( FreeBlock->SubBlockSize>0)
236 {
237 CmiAddFree(RegistryFile,FreeBlock
238 ,RegistryFile->BlockList[i]->BlockOffset+FreeOffset);
239 FreeOffset += FreeBlock->SubBlockSize;
240 }
241 else
242 FreeOffset -= FreeBlock->SubBlockSize;
243 }
244 BlockOffset += tmpHeap->BlockSize;
245 }
246 Status = ObReferenceObjectByHandle(FileHandle,
247 FILE_ALL_ACCESS,
248 IoFileObjectType,
249 UserMode,
250 (PVOID*)&RegistryFile->FileObject,
251 NULL);
252 }
253 else
254 {
255 RegistryFile->Filename = NULL;
256 RegistryFile->FileObject = NULL;
257
258 RegistryFile->HeaderBlock = (PHEADER_BLOCK)
259 ExAllocatePool(NonPagedPool, sizeof(HEADER_BLOCK));
260 CmiCreateDefaultHeaderBlock(RegistryFile->HeaderBlock);
261
262 RootKeyBlock = (PKEY_BLOCK) ExAllocatePool(NonPagedPool, sizeof(KEY_BLOCK));
263 CmiCreateDefaultRootKeyBlock(RootKeyBlock);
264
265 RegistryFile->HeaderBlock->RootKeyBlock = (BLOCK_OFFSET) RootKeyBlock;
266 }
267 KeInitializeSemaphore(&RegistryFile->RegSem, 1, 1);
268
269 return RegistryFile;
270 }
271
272 ULONG
273 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile,
274 PKEY_BLOCK KeyBlock)
275 {
276 ULONG Idx, MaxName;
277 PHASH_TABLE_BLOCK HashBlock;
278 PKEY_BLOCK CurSubKeyBlock;
279
280 MaxName = 0;
281 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
282 if (HashBlock == 0)
283 {
284 return 0;
285 }
286 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
287 {
288 if (HashBlock->Table[Idx].KeyOffset != 0)
289 {
290 CurSubKeyBlock = CmiGetBlock(RegistryFile,
291 HashBlock->Table[Idx].KeyOffset,NULL);
292 if (MaxName < CurSubKeyBlock->NameSize)
293 {
294 MaxName = CurSubKeyBlock->NameSize;
295 }
296 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
297 }
298 }
299
300 CmiReleaseBlock(RegistryFile, HashBlock);
301
302 return MaxName;
303 }
304
305 ULONG
306 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile,
307 PKEY_BLOCK KeyBlock)
308 {
309 ULONG Idx, MaxClass;
310 PHASH_TABLE_BLOCK HashBlock;
311 PKEY_BLOCK CurSubKeyBlock;
312
313 MaxClass = 0;
314 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
315 if (HashBlock == 0)
316 {
317 return 0;
318 }
319 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
320 {
321 if (HashBlock->Table[Idx].KeyOffset != 0)
322 {
323 CurSubKeyBlock = CmiGetBlock(RegistryFile,
324 HashBlock->Table[Idx].KeyOffset,NULL);
325 if (MaxClass < CurSubKeyBlock->ClassSize)
326 {
327 MaxClass = CurSubKeyBlock->ClassSize;
328 }
329 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
330 }
331 }
332
333 CmiReleaseBlock(RegistryFile, HashBlock);
334
335 return MaxClass;
336 }
337
338 ULONG
339 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile,
340 PKEY_BLOCK KeyBlock)
341 {
342 ULONG Idx, MaxValueName;
343 PVALUE_LIST_BLOCK ValueListBlock;
344 PVALUE_BLOCK CurValueBlock;
345
346 ValueListBlock = CmiGetBlock(RegistryFile,
347 KeyBlock->ValuesOffset,NULL);
348 MaxValueName = 0;
349 if (ValueListBlock == 0)
350 {
351 return 0;
352 }
353 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
354 {
355 CurValueBlock = CmiGetBlock(RegistryFile,
356 ValueListBlock->Values[Idx],NULL);
357 if (CurValueBlock != NULL &&
358 MaxValueName < CurValueBlock->NameSize)
359 {
360 MaxValueName = CurValueBlock->NameSize;
361 }
362 CmiReleaseBlock(RegistryFile, CurValueBlock);
363 }
364
365 CmiReleaseBlock(RegistryFile, ValueListBlock);
366
367 return MaxValueName;
368 }
369
370 ULONG
371 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile,
372 PKEY_BLOCK KeyBlock)
373 {
374 ULONG Idx, MaxValueData;
375 PVALUE_LIST_BLOCK ValueListBlock;
376 PVALUE_BLOCK CurValueBlock;
377
378 ValueListBlock = CmiGetBlock(RegistryFile,
379 KeyBlock->ValuesOffset,NULL);
380 MaxValueData = 0;
381 if (ValueListBlock == 0)
382 {
383 return 0;
384 }
385 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
386 {
387 CurValueBlock = CmiGetBlock(RegistryFile,
388 ValueListBlock->Values[Idx],NULL);
389 if (CurValueBlock != NULL &&
390 MaxValueData < (CurValueBlock->DataSize & LONG_MAX) )
391 {
392 MaxValueData = CurValueBlock->DataSize & LONG_MAX;
393 }
394 CmiReleaseBlock(RegistryFile, CurValueBlock);
395 }
396
397 CmiReleaseBlock(RegistryFile, ValueListBlock);
398
399 return MaxValueData;
400 }
401
402 NTSTATUS
403 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile,
404 IN PKEY_BLOCK KeyBlock,
405 OUT PKEY_BLOCK *SubKeyBlock,
406 OUT BLOCK_OFFSET *BlockOffset,
407 IN PCHAR KeyName,
408 IN ACCESS_MASK DesiredAccess,
409 IN ULONG Attributes)
410 {
411 ULONG Idx;
412 PHASH_TABLE_BLOCK HashBlock;
413 PKEY_BLOCK CurSubKeyBlock;
414 WORD KeyLength = strlen(KeyName);
415
416 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
417 *SubKeyBlock = NULL;
418 if (HashBlock == NULL)
419 {
420 return STATUS_SUCCESS;
421 }
422 // for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
423 for (Idx = 0; Idx < KeyBlock->NumberOfSubKeys
424 && Idx < HashBlock->HashTableSize; Idx++)
425 {
426 if (Attributes & OBJ_CASE_INSENSITIVE)
427 {
428 if (HashBlock->Table[Idx].KeyOffset != 0 &&
429 HashBlock->Table[Idx].KeyOffset != -1 &&
430 !_strnicmp(KeyName, (PCHAR) &HashBlock->Table[Idx].HashValue, 4))
431 {
432 CurSubKeyBlock = CmiGetBlock(RegistryFile,
433 HashBlock->Table[Idx].KeyOffset,NULL);
434 if ( CurSubKeyBlock->NameSize == KeyLength
435 && !_strnicmp(KeyName, CurSubKeyBlock->Name, KeyLength))
436 {
437 *SubKeyBlock = CurSubKeyBlock;
438 *BlockOffset = HashBlock->Table[Idx].KeyOffset;
439 break;
440 }
441 else
442 {
443 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
444 }
445 }
446 }
447 else
448 {
449 if (HashBlock->Table[Idx].KeyOffset != 0 &&
450 HashBlock->Table[Idx].KeyOffset != -1 &&
451 !strncmp(KeyName, (PCHAR) &HashBlock->Table[Idx].HashValue, 4))
452 {
453 CurSubKeyBlock = CmiGetBlock(RegistryFile,
454 HashBlock->Table[Idx].KeyOffset,NULL);
455 if ( CurSubKeyBlock->NameSize == KeyLength
456 && !_strnicmp(KeyName, CurSubKeyBlock->Name, KeyLength))
457 {
458 *SubKeyBlock = CurSubKeyBlock;
459 *BlockOffset = HashBlock->Table[Idx].KeyOffset;
460 break;
461 }
462 else
463 {
464 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
465 }
466 }
467 }
468 }
469
470 CmiReleaseBlock(RegistryFile, HashBlock);
471
472 return STATUS_SUCCESS;
473 }
474
475 NTSTATUS
476 CmiAddSubKey(PREGISTRY_FILE RegistryFile,
477 PKEY_OBJECT Parent,
478 PKEY_OBJECT SubKey,
479 PWSTR NewSubKeyName,
480 USHORT NewSubKeyNameSize,
481 ULONG TitleIndex,
482 PUNICODE_STRING Class,
483 ULONG CreateOptions)
484 {
485 PKEY_BLOCK KeyBlock = Parent->KeyBlock;
486 NTSTATUS Status;
487 PHASH_TABLE_BLOCK HashBlock, NewHashBlock;
488 PKEY_BLOCK NewKeyBlock;
489 BLOCK_OFFSET NKBOffset;
490 ULONG NewBlockSize;
491 USHORT NameSize;
492
493 if (NewSubKeyName[0] == L'\\')
494 {
495 NewSubKeyName++;
496 NameSize = NewSubKeyNameSize/2-1;
497 }
498 else
499 NameSize = NewSubKeyNameSize/2;
500 Status = STATUS_SUCCESS;
501
502 NewBlockSize = sizeof(KEY_BLOCK) + NameSize;
503 Status = CmiAllocateBlock(RegistryFile, (PVOID) &NewKeyBlock
504 , NewBlockSize,&NKBOffset);
505 if (NewKeyBlock == NULL)
506 {
507 Status = STATUS_INSUFFICIENT_RESOURCES;
508 }
509 else
510 {
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;
523 if (Class)
524 {
525 PDATA_BLOCK pClass;
526 NewKeyBlock->ClassSize = Class->Length+sizeof(WCHAR);
527 Status = CmiAllocateBlock(RegistryFile
528 ,(PVOID)&pClass
529 ,NewKeyBlock->ClassSize
530 ,&NewKeyBlock->ClassNameOffset );
531 wcsncpy((PWSTR)pClass->Data,Class->Buffer,Class->Length);
532 ( (PWSTR)(pClass->Data))[Class->Length]=0;
533 }
534 }
535
536 if (!NT_SUCCESS(Status))
537 {
538 return Status;
539 }
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)
544 {
545 return Status;
546 }
547 if (KeyBlock->HashTableOffset == -1)
548 {
549 Status = CmiAllocateHashTableBlock(RegistryFile,
550 &HashBlock,
551 &KeyBlock->HashTableOffset,
552 REG_INIT_HASH_TABLE_SIZE);
553 if (!NT_SUCCESS(Status))
554 {
555 return Status;
556 }
557 }
558 else
559 {
560 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
561 if (KeyBlock->NumberOfSubKeys + 1 >= HashBlock->HashTableSize)
562 {
563 BLOCK_OFFSET HTOffset;
564
565 /* Reallocate the hash table block */
566 Status = CmiAllocateHashTableBlock(RegistryFile,
567 &NewHashBlock,
568 &HTOffset,
569 HashBlock->HashTableSize +
570 REG_EXTEND_HASH_TABLE_SIZE);
571 if (!NT_SUCCESS(Status))
572 {
573 return Status;
574 }
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;
584 }
585 }
586 Status = CmiAddKeyToHashTable(RegistryFile, HashBlock, NewKeyBlock,NKBOffset);
587 if (NT_SUCCESS(Status))
588 {
589 KeyBlock->NumberOfSubKeys++;
590 }
591
592 return Status;
593 }
594
595 NTSTATUS
596 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile,
597 IN PKEY_BLOCK KeyBlock,
598 IN PCHAR ValueName,
599 OUT PVALUE_BLOCK *ValueBlock,
600 OUT BLOCK_OFFSET *VBOffset)
601 {
602 ULONG Idx;
603 PVALUE_LIST_BLOCK ValueListBlock;
604 PVALUE_BLOCK CurValueBlock;
605 ValueListBlock = CmiGetBlock(RegistryFile,
606 KeyBlock->ValuesOffset,NULL);
607 *ValueBlock = NULL;
608 if (ValueListBlock == NULL)
609 {
610 return STATUS_SUCCESS;
611 }
612 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
613 {
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)))
621 {
622 *ValueBlock = CurValueBlock;
623 if(VBOffset) *VBOffset = ValueListBlock->Values[Idx];
624 break;
625 }
626 CmiReleaseBlock(RegistryFile, CurValueBlock);
627 }
628
629 CmiReleaseBlock(RegistryFile, ValueListBlock);
630
631 return STATUS_SUCCESS;
632 }
633
634
635 NTSTATUS
636 CmiGetValueFromKeyByIndex(IN PREGISTRY_FILE RegistryFile,
637 IN PKEY_BLOCK KeyBlock,
638 IN ULONG Index,
639 OUT PVALUE_BLOCK *ValueBlock)
640 {
641 PVALUE_LIST_BLOCK ValueListBlock;
642 PVALUE_BLOCK CurValueBlock;
643 ValueListBlock = CmiGetBlock(RegistryFile,
644 KeyBlock->ValuesOffset,NULL);
645 *ValueBlock = NULL;
646 if (ValueListBlock == NULL)
647 {
648 return STATUS_NO_MORE_ENTRIES;
649 }
650 if (Index >= KeyBlock->NumberOfValues)
651 {
652 return STATUS_NO_MORE_ENTRIES;
653 }
654 CurValueBlock = CmiGetBlock(RegistryFile,
655 ValueListBlock->Values[Index],NULL);
656 if (CurValueBlock != NULL)
657 {
658 *ValueBlock = CurValueBlock;
659 }
660 CmiReleaseBlock(RegistryFile, CurValueBlock);
661 CmiReleaseBlock(RegistryFile, ValueListBlock);
662
663 return STATUS_SUCCESS;
664 }
665
666 NTSTATUS
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)
672 {
673 NTSTATUS Status;
674 PVALUE_LIST_BLOCK ValueListBlock, NewValueListBlock;
675 BLOCK_OFFSET VBOffset;
676 BLOCK_OFFSET VLBOffset;
677 PVALUE_BLOCK NewValueBlock;
678
679 Status = CmiAllocateValueBlock(RegistryFile,
680 &NewValueBlock,
681 &VBOffset,
682 ValueNameBuf);
683 *pVBOffset=VBOffset;
684 if (!NT_SUCCESS(Status))
685 {
686 return Status;
687 }
688 ValueListBlock = CmiGetBlock(RegistryFile,
689 KeyBlock->ValuesOffset,NULL);
690 if (ValueListBlock == NULL)
691 {
692 Status = CmiAllocateBlock(RegistryFile,
693 (PVOID) &ValueListBlock,
694 sizeof(BLOCK_OFFSET) * 3,
695 &VLBOffset);
696 if (!NT_SUCCESS(Status))
697 {
698 CmiDestroyValueBlock(RegistryFile,
699 NewValueBlock,VBOffset);
700 return Status;
701 }
702 KeyBlock->ValuesOffset = VLBOffset;
703 }
704 else if ( KeyBlock->NumberOfValues
705 >= -(ValueListBlock->SubBlockSize-4)/sizeof(BLOCK_OFFSET))
706 {
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))
713 {
714 CmiDestroyValueBlock(RegistryFile,
715 NewValueBlock,VBOffset);
716 return Status;
717 }
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;
724 }
725 ValueListBlock->Values[KeyBlock->NumberOfValues] = VBOffset;
726 KeyBlock->NumberOfValues++;
727 CmiReleaseBlock(RegistryFile, ValueListBlock);
728 CmiReleaseBlock(RegistryFile, NewValueBlock);
729 *pValueBlock = NewValueBlock;
730
731 return STATUS_SUCCESS;
732 }
733
734 NTSTATUS
735 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile,
736 IN PKEY_BLOCK KeyBlock,
737 IN PCHAR ValueName)
738 {
739 ULONG Idx;
740 PVALUE_LIST_BLOCK ValueListBlock;
741 PVALUE_BLOCK CurValueBlock;
742 PHEAP_BLOCK pHeap;
743
744 ValueListBlock = CmiGetBlock(RegistryFile,
745 KeyBlock->ValuesOffset,NULL);
746 if (ValueListBlock == 0)
747 {
748 return STATUS_SUCCESS;
749 }
750 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
751 {
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)))
757 {
758 if (KeyBlock->NumberOfValues - 1 < Idx)
759 {
760 RtlCopyMemory(&ValueListBlock->Values[Idx],
761 &ValueListBlock->Values[Idx + 1],
762 sizeof(BLOCK_OFFSET) *
763 (KeyBlock->NumberOfValues - 1 - Idx));
764 }
765 else
766 {
767 RtlZeroMemory(&ValueListBlock->Values[Idx],
768 sizeof(BLOCK_OFFSET));
769 }
770 KeyBlock->NumberOfValues -= 1;
771 CmiDestroyValueBlock(RegistryFile, CurValueBlock, ValueListBlock->Values[Idx]);
772 /* update time of heap */
773 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
774
775 break;
776 }
777 CmiReleaseBlock(RegistryFile, CurValueBlock);
778 }
779
780 CmiReleaseBlock(RegistryFile, ValueListBlock);
781
782 return STATUS_SUCCESS;
783 }
784
785 NTSTATUS
786 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile,
787 OUT PHASH_TABLE_BLOCK *HashBlock,
788 OUT BLOCK_OFFSET *HBOffset,
789 IN ULONG HashTableSize)
790 {
791 NTSTATUS Status;
792 ULONG NewHashSize;
793 PHASH_TABLE_BLOCK NewHashBlock;
794
795 Status = STATUS_SUCCESS;
796 *HashBlock = NULL;
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) )
803 {
804 Status = STATUS_INSUFFICIENT_RESOURCES;
805 }
806 else
807 {
808 NewHashBlock->SubBlockId = REG_HASH_TABLE_BLOCK_ID;
809 NewHashBlock->HashTableSize = HashTableSize;
810 *HashBlock = NewHashBlock;
811 }
812
813 return Status;
814 }
815
816 PKEY_BLOCK
817 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile,
818 PHASH_TABLE_BLOCK HashBlock,
819 ULONG Index)
820 {
821 PKEY_BLOCK KeyBlock;
822 BLOCK_OFFSET KeyOffset;
823
824 if( HashBlock == NULL)
825 return NULL;
826 if (RegistryFile->Filename == NULL)
827 {
828 KeyBlock = (PKEY_BLOCK) HashBlock->Table[Index].KeyOffset;
829 }
830 else
831 {
832 KeyOffset = HashBlock->Table[Index].KeyOffset;
833 KeyBlock = CmiGetBlock(RegistryFile,KeyOffset,NULL);
834 }
835 CmiLockBlock(RegistryFile, KeyBlock);
836
837 return KeyBlock;
838 }
839
840 NTSTATUS
841 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile,
842 PHASH_TABLE_BLOCK HashBlock,
843 PKEY_BLOCK NewKeyBlock,
844 BLOCK_OFFSET NKBOffset)
845 {
846 ULONG i;
847
848 for (i = 0; i < HashBlock->HashTableSize; i++)
849 {
850 if (HashBlock->Table[i].KeyOffset == 0)
851 {
852 HashBlock->Table[i].KeyOffset = NKBOffset;
853 RtlCopyMemory(&HashBlock->Table[i].HashValue,
854 NewKeyBlock->Name,
855 4);
856 return STATUS_SUCCESS;
857 }
858 }
859 return STATUS_UNSUCCESSFUL;
860 }
861
862 NTSTATUS
863 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile,
864 PVALUE_BLOCK *ValueBlock,
865 BLOCK_OFFSET *VBOffset,
866 IN PCHAR ValueNameBuf)
867 {
868 NTSTATUS Status;
869 ULONG NewValueSize;
870 PVALUE_BLOCK NewValueBlock;
871
872 Status = STATUS_SUCCESS;
873
874 NewValueSize = sizeof(VALUE_BLOCK) + strlen(ValueNameBuf);
875 Status = CmiAllocateBlock(RegistryFile,
876 (PVOID*)&NewValueBlock,
877 NewValueSize,VBOffset);
878 if (NewValueBlock == NULL || !NT_SUCCESS(Status))
879 {
880 Status = STATUS_INSUFFICIENT_RESOURCES;
881 }
882 else
883 {
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;
891 }
892
893 return Status;
894 }
895
896 NTSTATUS
897 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile,
898 PVALUE_BLOCK ValueBlock, BLOCK_OFFSET VBOffset)
899 {
900 NTSTATUS Status;
901 PHEAP_BLOCK pHeap;
902 PVOID pBlock;
903
904 /* first, release datas : */
905 if (ValueBlock->DataSize >0)
906 {
907 pBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset,&pHeap);
908 Status = CmiDestroyBlock(RegistryFile, pBlock, ValueBlock->DataOffset);
909 if (!NT_SUCCESS(Status))
910 {
911 return Status;
912 }
913 /* update time of heap */
914 if(RegistryFile->Filename)
915 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
916 }
917
918 Status = CmiDestroyBlock(RegistryFile, ValueBlock, VBOffset);
919 /* update time of heap */
920 if(RegistryFile->Filename && CmiGetBlock(RegistryFile, VBOffset,&pHeap))
921 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
922 return Status;
923 }
924
925 NTSTATUS
926 CmiAddHeap(PREGISTRY_FILE RegistryFile,PVOID *NewBlock,BLOCK_OFFSET *NewBlockOffset)
927 {
928 PHEAP_BLOCK tmpHeap;
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)
943 {
944 KeBugCheck(0);
945 return(STATUS_INSUFFICIENT_RESOURCES);
946 }
947 if(RegistryFile->BlockListSize > 0)
948 {
949 memcpy(tmpBlockList,RegistryFile->BlockList,
950 sizeof(PHEAP_BLOCK *)*(RegistryFile->BlockListSize ));
951 ExFreePool(RegistryFile->BlockList);
952 }
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;
959 if (NewBlockOffset)
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;
963 }
964
965 NTSTATUS
966 CmiAllocateBlock(PREGISTRY_FILE RegistryFile,
967 PVOID *Block,
968 LONG BlockSize,
969 BLOCK_OFFSET * pBlockOffset)
970 {
971 NTSTATUS Status;
972 PFREE_SUB_BLOCK NewBlock;
973 PHEAP_BLOCK pHeap;
974
975 Status = STATUS_SUCCESS;
976 /* round to 16 bytes multiple */
977 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
978
979 /* Handle volatile files first */
980 if (RegistryFile->Filename == NULL)
981 {
982 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
983 if (NewBlock == NULL)
984 {
985 Status = STATUS_INSUFFICIENT_RESOURCES;
986 }
987 else
988 {
989 RtlZeroMemory(NewBlock, BlockSize);
990 NewBlock->SubBlockSize = BlockSize;
991 CmiLockBlock(RegistryFile, NewBlock);
992 *Block = NewBlock;
993 if (pBlockOffset) *pBlockOffset = (BLOCK_OFFSET)NewBlock;
994 }
995 }
996 else
997 {
998 int i;
999 /* first search in free blocks */
1000 NewBlock = NULL;
1001 for (i=0 ; i<RegistryFile->FreeListSize ; i++)
1002 {
1003 if(RegistryFile->FreeList[i]->SubBlockSize >=BlockSize)
1004 {
1005 NewBlock = RegistryFile->FreeList[i];
1006 if(pBlockOffset)
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)
1013 {
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));
1022 }
1023 RegistryFile->FreeListSize--;
1024 break;
1025 }
1026 }
1027 /* need to extend hive file : */
1028 if (NewBlock == NULL)
1029 {
1030 /* add a new block : */
1031 Status = CmiAddHeap(RegistryFile, (PVOID *)&NewBlock , pBlockOffset);
1032 }
1033 if (NT_SUCCESS(Status))
1034 {
1035 *Block = NewBlock;
1036 /* split the block in two parts */
1037 if(NewBlock->SubBlockSize > BlockSize)
1038 {
1039 NewBlock = (PFREE_SUB_BLOCK)((char *)NewBlock+BlockSize);
1040 NewBlock->SubBlockSize=((PFREE_SUB_BLOCK) (*Block))->SubBlockSize-BlockSize;
1041 CmiAddFree(RegistryFile,NewBlock,*pBlockOffset+BlockSize);
1042 }
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);
1048 }
1049 }
1050 return Status;
1051 }
1052
1053 NTSTATUS
1054 CmiDestroyBlock(PREGISTRY_FILE RegistryFile,
1055 PVOID Block,BLOCK_OFFSET Offset)
1056 {
1057 NTSTATUS Status;
1058 PHEAP_BLOCK pHeap;
1059
1060 Status = STATUS_SUCCESS;
1061
1062 if (RegistryFile->Filename == NULL)
1063 {
1064 CmiReleaseBlock(RegistryFile, Block);
1065 ExFreePool(Block);
1066 }
1067 else
1068 {
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 */
1079 }
1080
1081 return Status;
1082 }
1083
1084 NTSTATUS
1085 CmiAddFree(PREGISTRY_FILE RegistryFile,
1086 PFREE_SUB_BLOCK FreeBlock,BLOCK_OFFSET FreeOffset)
1087 {
1088 PFREE_SUB_BLOCK *tmpList;
1089 BLOCK_OFFSET *tmpListOffset;
1090 int minInd,maxInd,medInd;
1091 if( (RegistryFile->FreeListSize+1) > RegistryFile->FreeListMax)
1092 {
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)
1102 {
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);
1109 }
1110 RegistryFile->FreeList = tmpList;
1111 RegistryFile->FreeListOffset = tmpListOffset;
1112 RegistryFile->FreeListMax +=32;
1113 }
1114 /* add new offset to free list, maintening list in ascending order */
1115 if ( RegistryFile->FreeListSize==0
1116 || RegistryFile->FreeListOffset[RegistryFile->FreeListSize-1] < FreeOffset)
1117 {
1118 /* add to end of list : */
1119 RegistryFile->FreeList[RegistryFile->FreeListSize] = FreeBlock;
1120 RegistryFile->FreeListOffset[RegistryFile->FreeListSize ++] = FreeOffset;
1121 }
1122 else if (RegistryFile->FreeListOffset[0] > FreeOffset)
1123 {
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 ++;
1132 }
1133 else
1134 {
1135 /* search where to insert : */
1136 minInd=0;
1137 maxInd=RegistryFile->FreeListSize-1;
1138 while( (maxInd-minInd) >1)
1139 {
1140 medInd=(minInd+maxInd)/2;
1141 if (RegistryFile->FreeListOffset[medInd] > FreeOffset)
1142 maxInd=medInd;
1143 else
1144 minInd=medInd;
1145 }
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 ++;
1157 }
1158 return STATUS_SUCCESS;
1159 }
1160
1161 PVOID
1162 CmiGetBlock(PREGISTRY_FILE RegistryFile,
1163 BLOCK_OFFSET BlockOffset,
1164 OUT PHEAP_BLOCK * ppHeap)
1165 {
1166 if( BlockOffset == 0 || BlockOffset == -1) return NULL;
1167
1168 if (RegistryFile->Filename == NULL)
1169 {
1170 return (PVOID)BlockOffset;
1171 }
1172 else
1173 {
1174 PHEAP_BLOCK pHeap;
1175 pHeap = RegistryFile->BlockList[BlockOffset/4096];
1176 if(ppHeap) *ppHeap = pHeap;
1177 return ((char *)pHeap
1178 +(BlockOffset - pHeap->BlockOffset));
1179 }
1180 }
1181
1182 void
1183 CmiLockBlock(PREGISTRY_FILE RegistryFile,
1184 PVOID Block)
1185 {
1186 if (RegistryFile->Filename != NULL)
1187 {
1188 /* FIXME : implement */
1189 }
1190 }
1191
1192 void
1193 CmiReleaseBlock(PREGISTRY_FILE RegistryFile,
1194 PVOID Block)
1195 {
1196 if (RegistryFile->Filename != NULL)
1197 {
1198 /* FIXME : implement */
1199 }
1200 }