preliminary implementation of boot hive import. exposes memory problem in registry...
[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 <ddk/ntddk.h>
10 #include <internal/config.h>
11 #include <internal/ob.h>
12 #include <limits.h>
13 #include <string.h>
14 #include <internal/pool.h>
15 #include <internal/registry.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 #include "cm.h"
21
22
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
35
36
37 extern PREGISTRY_FILE CmiVolatileFile;
38
39 void CmiCreateDefaultHeaderBlock(PHEADER_BLOCK HeaderBlock)
40 {
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;
52 }
53
54 void CmiCreateDefaultHeapBlock(PHEAP_BLOCK HeapBlock)
55 {
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;
61 }
62
63 void CmiCreateDefaultRootKeyBlock(PKEY_BLOCK RootKeyBlock)
64 {
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;
79 }
80
81 NTSTATUS CmiCreateNewRegFile( HANDLE FileHandle )
82 {
83 NTSTATUS Status;
84 PHEADER_BLOCK HeaderBlock;
85 PHEAP_BLOCK HeapBlock;
86 PKEY_BLOCK RootKeyBlock;
87 PFREE_SUB_BLOCK FreeSubBlock;
88
89 IO_STATUS_BLOCK IoStatusBlock;
90 char* tBuf;
91
92 tBuf = (char*) ExAllocatePool(NonPagedPool, 2*REG_BLOCK_SIZE);
93 if( tBuf == NULL )
94 return STATUS_INSUFFICIENT_RESOURCES;
95
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));
100
101 CmiCreateDefaultHeaderBlock(HeaderBlock);
102 CmiCreateDefaultHeapBlock(HeapBlock);
103 CmiCreateDefaultRootKeyBlock(RootKeyBlock);
104
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));
109
110 Status = ZwWriteFile( FileHandle, NULL, NULL, NULL,
111 &IoStatusBlock, tBuf, 2*REG_BLOCK_SIZE, 0, NULL );
112
113 ExFreePool( tBuf );
114 return Status;
115 }
116
117 PREGISTRY_FILE
118 CmiCreateRegistry(PWSTR Filename)
119 {
120 PREGISTRY_FILE RegistryFile;
121 HANDLE FileHandle;
122 PKEY_BLOCK RootKeyBlock;
123 PHEAP_BLOCK tmpHeap;
124 LARGE_INTEGER fileOffset;
125 PFREE_SUB_BLOCK FreeBlock;
126 DWORD FreeOffset;
127 int i, j;
128 BLOCK_OFFSET BlockOffset;
129 DPRINT1("CmiCreateRegistry() Filename '%S'\n", Filename);
130 RegistryFile = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_FILE));
131 CHECKPOINT1;
132 if (RegistryFile == NULL)
133 return NULL;
134 CHECKPOINT1;
135 if (Filename != NULL)
136 {
137 UNICODE_STRING TmpFileName;
138 OBJECT_ATTRIBUTES ObjectAttributes;
139 NTSTATUS Status;
140 FILE_STANDARD_INFORMATION fsi;
141 IO_STATUS_BLOCK IoSB;
142
143 /* Duplicate Filename */
144 RegistryFile->Filename = ExAllocatePool(NonPagedPool, MAX_PATH);
145 wcscpy(RegistryFile->Filename , Filename);
146
147 RtlInitUnicodeString (&TmpFileName, Filename);
148 InitializeObjectAttributes(&ObjectAttributes,
149 &TmpFileName,
150 0,
151 NULL,
152 NULL);
153
154 Status = NtCreateFile( &FileHandle,
155 FILE_ALL_ACCESS,
156 &ObjectAttributes,
157 &IoSB,
158 NULL,
159 FILE_ATTRIBUTE_NORMAL,
160 0,
161 FILE_OPEN_IF,
162 FILE_NON_DIRECTORY_FILE,
163 NULL,
164 0 );
165
166 /* FIXME: create directory if IoSB.Status == STATUS_OBJECT_PATH_NOT_FOUND */
167 if( !NT_SUCCESS(Status) )
168 {
169 ExFreePool(RegistryFile->Filename);
170 RegistryFile->Filename = NULL;
171 return NULL;
172 }
173 /*if file did not exist*/
174 if( IoSB.Information == FILE_CREATED ){
175 Status = CmiCreateNewRegFile( FileHandle );
176 if( !NT_SUCCESS(Status) )
177 {
178 ExFreePool(RegistryFile->Filename);
179 RegistryFile->Filename = NULL;
180 return NULL;
181 }
182 }
183
184 RegistryFile->HeaderBlock = (PHEADER_BLOCK)
185 ExAllocatePool(NonPagedPool, sizeof(HEADER_BLOCK));
186
187 fileOffset.u.HighPart = 0;
188 fileOffset.u.LowPart = 0;
189 Status = ZwReadFile(FileHandle,
190 0, 0, 0, 0,
191 RegistryFile->HeaderBlock,
192 sizeof(HEADER_BLOCK),
193 &fileOffset, 0);
194 if (!NT_SUCCESS(Status))
195 {
196 ExFreePool(RegistryFile->Filename);
197 RegistryFile->Filename = NULL;
198 return NULL;
199 }
200
201 Status = ZwQueryInformationFile(FileHandle,&IoSB,&fsi
202 ,sizeof(fsi),FileStandardInformation);
203 if (!NT_SUCCESS(Status))
204 {
205 ExFreePool(RegistryFile->Filename);
206 RegistryFile->Filename = NULL;
207 return NULL;
208 }
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 ));
214 BlockOffset=0;
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)
220 {
221 // Status = STATUS_INSUFFICIENT_RESOURCES;
222 DPRINT1("error allocating %d bytes for registry\n"
223 ,RegistryFile->FileSize-4096);
224 ZwClose(FileHandle);
225 return NULL;
226 }
227 Status = ZwReadFile(FileHandle,
228 0, 0, 0, 0,
229 RegistryFile->BlockList [0],
230 RegistryFile->FileSize-4096,
231 &fileOffset, 0);
232 ZwClose(FileHandle);
233 if (!NT_SUCCESS(Status))
234 {
235 DPRINT1("error %x reading registry file at offset %x\n"
236 ,Status,fileOffset.u.LowPart);
237 return NULL;
238 }
239 RegistryFile->FreeListSize = 0;
240 RegistryFile->FreeListMax = 0;
241 RegistryFile->FreeList = NULL;
242 for(i=0 ; i <RegistryFile->BlockListSize; i++)
243 {
244 tmpHeap = (PHEAP_BLOCK)(((char *)RegistryFile->BlockList [0])+BlockOffset);
245 if (tmpHeap->BlockId != REG_HEAP_ID )
246 {
247 DPRINT1("bad BlockId %x,offset %x\n",tmpHeap->BlockId,fileOffset.u.LowPart);
248 }
249 RegistryFile->BlockList [i]
250 = tmpHeap;
251 if (tmpHeap->BlockSize >4096)
252 {
253 for(j=1;j<tmpHeap->BlockSize/4096;j++)
254 RegistryFile->BlockList[i+j] = RegistryFile->BlockList[i];
255 i = i+j-1;
256 }
257 /* search free blocks and add to list */
258 FreeOffset=REG_HEAP_BLOCK_DATA_OFFSET;
259 while(FreeOffset < tmpHeap->BlockSize)
260 {
261 FreeBlock = (PFREE_SUB_BLOCK)((char *)RegistryFile->BlockList[i]
262 +FreeOffset);
263 if ( FreeBlock->SubBlockSize>0)
264 {
265 CmiAddFree(RegistryFile,FreeBlock
266 ,RegistryFile->BlockList[i]->BlockOffset+FreeOffset);
267 FreeOffset += FreeBlock->SubBlockSize;
268 }
269 else
270 FreeOffset -= FreeBlock->SubBlockSize;
271 }
272 BlockOffset += tmpHeap->BlockSize;
273 }
274 Status = ObReferenceObjectByHandle(FileHandle,
275 FILE_ALL_ACCESS,
276 IoFileObjectType,
277 UserMode,
278 (PVOID*)&RegistryFile->FileObject,
279 NULL);
280 }
281 else
282 {
283 RegistryFile->Filename = NULL;
284 RegistryFile->FileObject = NULL;
285
286 RegistryFile->HeaderBlock = (PHEADER_BLOCK)
287 ExAllocatePool(NonPagedPool, sizeof(HEADER_BLOCK));
288 CmiCreateDefaultHeaderBlock(RegistryFile->HeaderBlock);
289
290 RootKeyBlock = (PKEY_BLOCK) ExAllocatePool(NonPagedPool, sizeof(KEY_BLOCK));
291 CmiCreateDefaultRootKeyBlock(RootKeyBlock);
292
293 RegistryFile->HeaderBlock->RootKeyBlock = (BLOCK_OFFSET) RootKeyBlock;
294 }
295 KeInitializeSemaphore(&RegistryFile->RegSem, 1, 1);
296
297 return RegistryFile;
298 }
299
300 ULONG
301 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile,
302 PKEY_BLOCK KeyBlock)
303 {
304 ULONG Idx, MaxName;
305 PHASH_TABLE_BLOCK HashBlock;
306 PKEY_BLOCK CurSubKeyBlock;
307
308 MaxName = 0;
309 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
310 if (HashBlock == 0)
311 {
312 return 0;
313 }
314 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
315 {
316 if (HashBlock->Table[Idx].KeyOffset != 0)
317 {
318 CurSubKeyBlock = CmiGetBlock(RegistryFile,
319 HashBlock->Table[Idx].KeyOffset,NULL);
320 if (MaxName < CurSubKeyBlock->NameSize)
321 {
322 MaxName = CurSubKeyBlock->NameSize;
323 }
324 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
325 }
326 }
327
328 CmiReleaseBlock(RegistryFile, HashBlock);
329
330 return MaxName;
331 }
332
333 ULONG
334 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile,
335 PKEY_BLOCK KeyBlock)
336 {
337 ULONG Idx, MaxClass;
338 PHASH_TABLE_BLOCK HashBlock;
339 PKEY_BLOCK CurSubKeyBlock;
340
341 MaxClass = 0;
342 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
343 if (HashBlock == 0)
344 {
345 return 0;
346 }
347 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
348 {
349 if (HashBlock->Table[Idx].KeyOffset != 0)
350 {
351 CurSubKeyBlock = CmiGetBlock(RegistryFile,
352 HashBlock->Table[Idx].KeyOffset,NULL);
353 if (MaxClass < CurSubKeyBlock->ClassSize)
354 {
355 MaxClass = CurSubKeyBlock->ClassSize;
356 }
357 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
358 }
359 }
360
361 CmiReleaseBlock(RegistryFile, HashBlock);
362
363 return MaxClass;
364 }
365
366 ULONG
367 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile,
368 PKEY_BLOCK KeyBlock)
369 {
370 ULONG Idx, MaxValueName;
371 PVALUE_LIST_BLOCK ValueListBlock;
372 PVALUE_BLOCK CurValueBlock;
373
374 ValueListBlock = CmiGetBlock(RegistryFile,
375 KeyBlock->ValuesOffset,NULL);
376 MaxValueName = 0;
377 if (ValueListBlock == 0)
378 {
379 return 0;
380 }
381 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
382 {
383 CurValueBlock = CmiGetBlock(RegistryFile,
384 ValueListBlock->Values[Idx],NULL);
385 if (CurValueBlock != NULL &&
386 MaxValueName < CurValueBlock->NameSize)
387 {
388 MaxValueName = CurValueBlock->NameSize;
389 }
390 CmiReleaseBlock(RegistryFile, CurValueBlock);
391 }
392
393 CmiReleaseBlock(RegistryFile, ValueListBlock);
394
395 return MaxValueName;
396 }
397
398 ULONG
399 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile,
400 PKEY_BLOCK KeyBlock)
401 {
402 ULONG Idx, MaxValueData;
403 PVALUE_LIST_BLOCK ValueListBlock;
404 PVALUE_BLOCK CurValueBlock;
405
406 ValueListBlock = CmiGetBlock(RegistryFile,
407 KeyBlock->ValuesOffset,NULL);
408 MaxValueData = 0;
409 if (ValueListBlock == 0)
410 {
411 return 0;
412 }
413 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
414 {
415 CurValueBlock = CmiGetBlock(RegistryFile,
416 ValueListBlock->Values[Idx],NULL);
417 if (CurValueBlock != NULL &&
418 MaxValueData < (CurValueBlock->DataSize & LONG_MAX) )
419 {
420 MaxValueData = CurValueBlock->DataSize & LONG_MAX;
421 }
422 CmiReleaseBlock(RegistryFile, CurValueBlock);
423 }
424
425 CmiReleaseBlock(RegistryFile, ValueListBlock);
426
427 return MaxValueData;
428 }
429
430 NTSTATUS
431 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile,
432 IN PKEY_BLOCK KeyBlock,
433 OUT PKEY_BLOCK *SubKeyBlock,
434 OUT BLOCK_OFFSET *BlockOffset,
435 IN PCHAR KeyName,
436 IN ACCESS_MASK DesiredAccess,
437 IN ULONG Attributes)
438 {
439 ULONG Idx;
440 PHASH_TABLE_BLOCK HashBlock;
441 PKEY_BLOCK CurSubKeyBlock;
442 WORD KeyLength = strlen(KeyName);
443
444 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
445 *SubKeyBlock = NULL;
446 if (HashBlock == NULL)
447 {
448 return STATUS_SUCCESS;
449 }
450 // for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
451 for (Idx = 0; Idx < KeyBlock->NumberOfSubKeys
452 && Idx < HashBlock->HashTableSize; Idx++)
453 {
454 if (Attributes & OBJ_CASE_INSENSITIVE)
455 {
456 if (HashBlock->Table[Idx].KeyOffset != 0 &&
457 HashBlock->Table[Idx].KeyOffset != -1 &&
458 !_strnicmp(KeyName, (PCHAR) &HashBlock->Table[Idx].HashValue, 4))
459 {
460 CurSubKeyBlock = CmiGetBlock(RegistryFile,
461 HashBlock->Table[Idx].KeyOffset,NULL);
462 if ( CurSubKeyBlock->NameSize == KeyLength
463 && !_strnicmp(KeyName, CurSubKeyBlock->Name, KeyLength))
464 {
465 *SubKeyBlock = CurSubKeyBlock;
466 *BlockOffset = HashBlock->Table[Idx].KeyOffset;
467 break;
468 }
469 else
470 {
471 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
472 }
473 }
474 }
475 else
476 {
477 if (HashBlock->Table[Idx].KeyOffset != 0 &&
478 HashBlock->Table[Idx].KeyOffset != -1 &&
479 !strncmp(KeyName, (PCHAR) &HashBlock->Table[Idx].HashValue, 4))
480 {
481 CurSubKeyBlock = CmiGetBlock(RegistryFile,
482 HashBlock->Table[Idx].KeyOffset,NULL);
483 if ( CurSubKeyBlock->NameSize == KeyLength
484 && !_strnicmp(KeyName, CurSubKeyBlock->Name, KeyLength))
485 {
486 *SubKeyBlock = CurSubKeyBlock;
487 *BlockOffset = HashBlock->Table[Idx].KeyOffset;
488 break;
489 }
490 else
491 {
492 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
493 }
494 }
495 }
496 }
497
498 CmiReleaseBlock(RegistryFile, HashBlock);
499
500 return STATUS_SUCCESS;
501 }
502
503 NTSTATUS
504 CmiAddSubKey(PREGISTRY_FILE RegistryFile,
505 PKEY_OBJECT Parent,
506 PKEY_OBJECT SubKey,
507 PWSTR NewSubKeyName,
508 USHORT NewSubKeyNameSize,
509 ULONG TitleIndex,
510 PUNICODE_STRING Class,
511 ULONG CreateOptions)
512 {
513 PKEY_BLOCK KeyBlock = Parent->KeyBlock;
514 NTSTATUS Status;
515 PHASH_TABLE_BLOCK HashBlock, NewHashBlock;
516 PKEY_BLOCK NewKeyBlock;
517 BLOCK_OFFSET NKBOffset;
518 ULONG NewBlockSize;
519 USHORT NameSize;
520
521 if (NewSubKeyName[0] == L'\\')
522 {
523 NewSubKeyName++;
524 NameSize = NewSubKeyNameSize/2-1;
525 }
526 else
527 NameSize = NewSubKeyNameSize/2;
528 Status = STATUS_SUCCESS;
529
530 NewBlockSize = sizeof(KEY_BLOCK) + NameSize;
531 Status = CmiAllocateBlock(RegistryFile, (PVOID) &NewKeyBlock
532 , NewBlockSize,&NKBOffset);
533 if (NewKeyBlock == NULL)
534 {
535 Status = STATUS_INSUFFICIENT_RESOURCES;
536 }
537 else
538 {
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;
551 if (Class)
552 {
553 PDATA_BLOCK pClass;
554 NewKeyBlock->ClassSize = Class->Length+sizeof(WCHAR);
555 Status = CmiAllocateBlock(RegistryFile
556 ,(PVOID)&pClass
557 ,NewKeyBlock->ClassSize
558 ,&NewKeyBlock->ClassNameOffset );
559 wcsncpy((PWSTR)pClass->Data,Class->Buffer,Class->Length);
560 ( (PWSTR)(pClass->Data))[Class->Length]=0;
561 }
562 }
563
564 if (!NT_SUCCESS(Status))
565 {
566 return Status;
567 }
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)
572 {
573 return Status;
574 }
575 if (KeyBlock->HashTableOffset == -1)
576 {
577 Status = CmiAllocateHashTableBlock(RegistryFile,
578 &HashBlock,
579 &KeyBlock->HashTableOffset,
580 REG_INIT_HASH_TABLE_SIZE);
581 if (!NT_SUCCESS(Status))
582 {
583 return Status;
584 }
585 }
586 else
587 {
588 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
589 if (KeyBlock->NumberOfSubKeys + 1 >= HashBlock->HashTableSize)
590 {
591 BLOCK_OFFSET HTOffset;
592
593 /* Reallocate the hash table block */
594 Status = CmiAllocateHashTableBlock(RegistryFile,
595 &NewHashBlock,
596 &HTOffset,
597 HashBlock->HashTableSize +
598 REG_EXTEND_HASH_TABLE_SIZE);
599 if (!NT_SUCCESS(Status))
600 {
601 return Status;
602 }
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;
612 }
613 }
614 Status = CmiAddKeyToHashTable(RegistryFile, HashBlock, NewKeyBlock,NKBOffset);
615 if (NT_SUCCESS(Status))
616 {
617 KeyBlock->NumberOfSubKeys++;
618 }
619
620 return Status;
621 }
622
623 NTSTATUS
624 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile,
625 IN PKEY_BLOCK KeyBlock,
626 IN PCHAR ValueName,
627 OUT PVALUE_BLOCK *ValueBlock,
628 OUT BLOCK_OFFSET *VBOffset)
629 {
630 ULONG Idx;
631 PVALUE_LIST_BLOCK ValueListBlock;
632 PVALUE_BLOCK CurValueBlock;
633 ValueListBlock = CmiGetBlock(RegistryFile,
634 KeyBlock->ValuesOffset,NULL);
635 *ValueBlock = NULL;
636 if (ValueListBlock == NULL)
637 {
638 return STATUS_SUCCESS;
639 }
640 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
641 {
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)))
649 {
650 *ValueBlock = CurValueBlock;
651 if(VBOffset) *VBOffset = ValueListBlock->Values[Idx];
652 break;
653 }
654 CmiReleaseBlock(RegistryFile, CurValueBlock);
655 }
656
657 CmiReleaseBlock(RegistryFile, ValueListBlock);
658
659 return STATUS_SUCCESS;
660 }
661
662
663 NTSTATUS
664 CmiGetValueFromKeyByIndex(IN PREGISTRY_FILE RegistryFile,
665 IN PKEY_BLOCK KeyBlock,
666 IN ULONG Index,
667 OUT PVALUE_BLOCK *ValueBlock)
668 {
669 PVALUE_LIST_BLOCK ValueListBlock;
670 PVALUE_BLOCK CurValueBlock;
671 ValueListBlock = CmiGetBlock(RegistryFile,
672 KeyBlock->ValuesOffset,NULL);
673 *ValueBlock = NULL;
674 if (ValueListBlock == NULL)
675 {
676 return STATUS_NO_MORE_ENTRIES;
677 }
678 if (Index >= KeyBlock->NumberOfValues)
679 {
680 return STATUS_NO_MORE_ENTRIES;
681 }
682 CurValueBlock = CmiGetBlock(RegistryFile,
683 ValueListBlock->Values[Index],NULL);
684 if (CurValueBlock != NULL)
685 {
686 *ValueBlock = CurValueBlock;
687 }
688 CmiReleaseBlock(RegistryFile, CurValueBlock);
689 CmiReleaseBlock(RegistryFile, ValueListBlock);
690
691 return STATUS_SUCCESS;
692 }
693
694 NTSTATUS
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)
700 {
701 NTSTATUS Status;
702 PVALUE_LIST_BLOCK ValueListBlock, NewValueListBlock;
703 BLOCK_OFFSET VBOffset;
704 BLOCK_OFFSET VLBOffset;
705 PVALUE_BLOCK NewValueBlock;
706
707 Status = CmiAllocateValueBlock(RegistryFile,
708 &NewValueBlock,
709 &VBOffset,
710 ValueNameBuf);
711 *pVBOffset=VBOffset;
712 if (!NT_SUCCESS(Status))
713 {
714 return Status;
715 }
716 ValueListBlock = CmiGetBlock(RegistryFile,
717 KeyBlock->ValuesOffset,NULL);
718 if (ValueListBlock == NULL)
719 {
720 Status = CmiAllocateBlock(RegistryFile,
721 (PVOID) &ValueListBlock,
722 sizeof(BLOCK_OFFSET) * 3,
723 &VLBOffset);
724 if (!NT_SUCCESS(Status))
725 {
726 CmiDestroyValueBlock(RegistryFile,
727 NewValueBlock,VBOffset);
728 return Status;
729 }
730 KeyBlock->ValuesOffset = VLBOffset;
731 }
732 else if ( KeyBlock->NumberOfValues
733 >= -(ValueListBlock->SubBlockSize-4)/sizeof(BLOCK_OFFSET))
734 {
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))
741 {
742 CmiDestroyValueBlock(RegistryFile,
743 NewValueBlock,VBOffset);
744 return Status;
745 }
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;
752 }
753 ValueListBlock->Values[KeyBlock->NumberOfValues] = VBOffset;
754 KeyBlock->NumberOfValues++;
755 CmiReleaseBlock(RegistryFile, ValueListBlock);
756 CmiReleaseBlock(RegistryFile, NewValueBlock);
757 *pValueBlock = NewValueBlock;
758
759 return STATUS_SUCCESS;
760 }
761
762 NTSTATUS
763 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile,
764 IN PKEY_BLOCK KeyBlock,
765 IN PCHAR ValueName)
766 {
767 ULONG Idx;
768 PVALUE_LIST_BLOCK ValueListBlock;
769 PVALUE_BLOCK CurValueBlock;
770 PHEAP_BLOCK pHeap;
771
772 ValueListBlock = CmiGetBlock(RegistryFile,
773 KeyBlock->ValuesOffset,NULL);
774 if (ValueListBlock == 0)
775 {
776 return STATUS_SUCCESS;
777 }
778 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
779 {
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)))
785 {
786 if (KeyBlock->NumberOfValues - 1 < Idx)
787 {
788 RtlCopyMemory(&ValueListBlock->Values[Idx],
789 &ValueListBlock->Values[Idx + 1],
790 sizeof(BLOCK_OFFSET) *
791 (KeyBlock->NumberOfValues - 1 - Idx));
792 }
793 else
794 {
795 RtlZeroMemory(&ValueListBlock->Values[Idx],
796 sizeof(BLOCK_OFFSET));
797 }
798 KeyBlock->NumberOfValues -= 1;
799 CmiDestroyValueBlock(RegistryFile, CurValueBlock, ValueListBlock->Values[Idx]);
800 /* update time of heap */
801 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
802
803 break;
804 }
805 CmiReleaseBlock(RegistryFile, CurValueBlock);
806 }
807
808 CmiReleaseBlock(RegistryFile, ValueListBlock);
809
810 return STATUS_SUCCESS;
811 }
812
813 NTSTATUS
814 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile,
815 OUT PHASH_TABLE_BLOCK *HashBlock,
816 OUT BLOCK_OFFSET *HBOffset,
817 IN ULONG HashTableSize)
818 {
819 NTSTATUS Status;
820 ULONG NewHashSize;
821 PHASH_TABLE_BLOCK NewHashBlock;
822
823 Status = STATUS_SUCCESS;
824 *HashBlock = NULL;
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) )
831 {
832 Status = STATUS_INSUFFICIENT_RESOURCES;
833 }
834 else
835 {
836 NewHashBlock->SubBlockId = REG_HASH_TABLE_BLOCK_ID;
837 NewHashBlock->HashTableSize = HashTableSize;
838 *HashBlock = NewHashBlock;
839 }
840
841 return Status;
842 }
843
844 PKEY_BLOCK
845 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile,
846 PHASH_TABLE_BLOCK HashBlock,
847 ULONG Index)
848 {
849 PKEY_BLOCK KeyBlock;
850 BLOCK_OFFSET KeyOffset;
851
852 if( HashBlock == NULL)
853 return NULL;
854 if (RegistryFile->Filename == NULL)
855 {
856 KeyBlock = (PKEY_BLOCK) HashBlock->Table[Index].KeyOffset;
857 }
858 else
859 {
860 KeyOffset = HashBlock->Table[Index].KeyOffset;
861 KeyBlock = CmiGetBlock(RegistryFile,KeyOffset,NULL);
862 }
863 CmiLockBlock(RegistryFile, KeyBlock);
864
865 return KeyBlock;
866 }
867
868 NTSTATUS
869 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile,
870 PHASH_TABLE_BLOCK HashBlock,
871 PKEY_BLOCK NewKeyBlock,
872 BLOCK_OFFSET NKBOffset)
873 {
874 ULONG i;
875
876 for (i = 0; i < HashBlock->HashTableSize; i++)
877 {
878 if (HashBlock->Table[i].KeyOffset == 0)
879 {
880 HashBlock->Table[i].KeyOffset = NKBOffset;
881 RtlCopyMemory(&HashBlock->Table[i].HashValue,
882 NewKeyBlock->Name,
883 4);
884 return STATUS_SUCCESS;
885 }
886 }
887 return STATUS_UNSUCCESSFUL;
888 }
889
890 NTSTATUS
891 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile,
892 PVALUE_BLOCK *ValueBlock,
893 BLOCK_OFFSET *VBOffset,
894 IN PCHAR ValueNameBuf)
895 {
896 NTSTATUS Status;
897 ULONG NewValueSize;
898 PVALUE_BLOCK NewValueBlock;
899
900 Status = STATUS_SUCCESS;
901
902 NewValueSize = sizeof(VALUE_BLOCK) + strlen(ValueNameBuf);
903 Status = CmiAllocateBlock(RegistryFile,
904 (PVOID*)&NewValueBlock,
905 NewValueSize,VBOffset);
906 if (NewValueBlock == NULL || !NT_SUCCESS(Status))
907 {
908 Status = STATUS_INSUFFICIENT_RESOURCES;
909 }
910 else
911 {
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;
919 }
920
921 return Status;
922 }
923
924 NTSTATUS
925 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile,
926 PVALUE_BLOCK ValueBlock, BLOCK_OFFSET VBOffset)
927 {
928 NTSTATUS Status;
929 PHEAP_BLOCK pHeap;
930 PVOID pBlock;
931
932 /* first, release datas : */
933 if (ValueBlock->DataSize >0)
934 {
935 pBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset,&pHeap);
936 Status = CmiDestroyBlock(RegistryFile, pBlock, ValueBlock->DataOffset);
937 if (!NT_SUCCESS(Status))
938 {
939 return Status;
940 }
941 /* update time of heap */
942 if(RegistryFile->Filename)
943 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
944 }
945
946 Status = CmiDestroyBlock(RegistryFile, ValueBlock, VBOffset);
947 /* update time of heap */
948 if(RegistryFile->Filename && CmiGetBlock(RegistryFile, VBOffset,&pHeap))
949 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
950 return Status;
951 }
952
953 NTSTATUS
954 CmiAddHeap(PREGISTRY_FILE RegistryFile,PVOID *NewBlock,BLOCK_OFFSET *NewBlockOffset)
955 {
956 PHEAP_BLOCK tmpHeap;
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)
971 {
972 KeBugCheck(0);
973 return(STATUS_INSUFFICIENT_RESOURCES);
974 }
975 if(RegistryFile->BlockListSize > 0)
976 {
977 memcpy(tmpBlockList,RegistryFile->BlockList,
978 sizeof(PHEAP_BLOCK *)*(RegistryFile->BlockListSize ));
979 ExFreePool(RegistryFile->BlockList);
980 }
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;
987 if (NewBlockOffset)
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;
991 }
992
993 NTSTATUS
994 CmiAllocateBlock(PREGISTRY_FILE RegistryFile,
995 PVOID *Block,
996 LONG BlockSize,
997 BLOCK_OFFSET * pBlockOffset)
998 {
999 NTSTATUS Status;
1000 PFREE_SUB_BLOCK NewBlock;
1001 PHEAP_BLOCK pHeap;
1002
1003 Status = STATUS_SUCCESS;
1004 /* round to 16 bytes multiple */
1005 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
1006
1007 /* Handle volatile files first */
1008 if (RegistryFile->Filename == NULL)
1009 {
1010 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
1011 if (NewBlock == NULL)
1012 {
1013 Status = STATUS_INSUFFICIENT_RESOURCES;
1014 }
1015 else
1016 {
1017 RtlZeroMemory(NewBlock, BlockSize);
1018 NewBlock->SubBlockSize = BlockSize;
1019 CmiLockBlock(RegistryFile, NewBlock);
1020 *Block = NewBlock;
1021 if (pBlockOffset) *pBlockOffset = (BLOCK_OFFSET)NewBlock;
1022 }
1023 }
1024 else
1025 {
1026 int i;
1027 /* first search in free blocks */
1028 NewBlock = NULL;
1029 for (i=0 ; i<RegistryFile->FreeListSize ; i++)
1030 {
1031 if(RegistryFile->FreeList[i]->SubBlockSize >=BlockSize)
1032 {
1033 NewBlock = RegistryFile->FreeList[i];
1034 if(pBlockOffset)
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)
1041 {
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));
1050 }
1051 RegistryFile->FreeListSize--;
1052 break;
1053 }
1054 }
1055 /* need to extend hive file : */
1056 if (NewBlock == NULL)
1057 {
1058 /* add a new block : */
1059 Status = CmiAddHeap(RegistryFile, (PVOID *)&NewBlock , pBlockOffset);
1060 }
1061 if (NT_SUCCESS(Status))
1062 {
1063 *Block = NewBlock;
1064 /* split the block in two parts */
1065 if(NewBlock->SubBlockSize > BlockSize)
1066 {
1067 NewBlock = (PFREE_SUB_BLOCK)((char *)NewBlock+BlockSize);
1068 NewBlock->SubBlockSize=((PFREE_SUB_BLOCK) (*Block))->SubBlockSize-BlockSize;
1069 CmiAddFree(RegistryFile,NewBlock,*pBlockOffset+BlockSize);
1070 }
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);
1076 }
1077 }
1078 return Status;
1079 }
1080
1081 NTSTATUS
1082 CmiDestroyBlock(PREGISTRY_FILE RegistryFile,
1083 PVOID Block,BLOCK_OFFSET Offset)
1084 {
1085 NTSTATUS Status;
1086 PHEAP_BLOCK pHeap;
1087
1088 Status = STATUS_SUCCESS;
1089
1090 if (RegistryFile->Filename == NULL)
1091 {
1092 CmiReleaseBlock(RegistryFile, Block);
1093 ExFreePool(Block);
1094 }
1095 else
1096 {
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 */
1107 }
1108
1109 return Status;
1110 }
1111
1112 NTSTATUS
1113 CmiAddFree(PREGISTRY_FILE RegistryFile,
1114 PFREE_SUB_BLOCK FreeBlock,BLOCK_OFFSET FreeOffset)
1115 {
1116 PFREE_SUB_BLOCK *tmpList;
1117 BLOCK_OFFSET *tmpListOffset;
1118 int minInd,maxInd,medInd;
1119 if( (RegistryFile->FreeListSize+1) > RegistryFile->FreeListMax)
1120 {
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)
1130 {
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);
1137 }
1138 RegistryFile->FreeList = tmpList;
1139 RegistryFile->FreeListOffset = tmpListOffset;
1140 RegistryFile->FreeListMax +=32;
1141 }
1142 /* add new offset to free list, maintening list in ascending order */
1143 if ( RegistryFile->FreeListSize==0
1144 || RegistryFile->FreeListOffset[RegistryFile->FreeListSize-1] < FreeOffset)
1145 {
1146 /* add to end of list : */
1147 RegistryFile->FreeList[RegistryFile->FreeListSize] = FreeBlock;
1148 RegistryFile->FreeListOffset[RegistryFile->FreeListSize ++] = FreeOffset;
1149 }
1150 else if (RegistryFile->FreeListOffset[0] > FreeOffset)
1151 {
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 ++;
1160 }
1161 else
1162 {
1163 /* search where to insert : */
1164 minInd=0;
1165 maxInd=RegistryFile->FreeListSize-1;
1166 while( (maxInd-minInd) >1)
1167 {
1168 medInd=(minInd+maxInd)/2;
1169 if (RegistryFile->FreeListOffset[medInd] > FreeOffset)
1170 maxInd=medInd;
1171 else
1172 minInd=medInd;
1173 }
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 ++;
1185 }
1186 return STATUS_SUCCESS;
1187 }
1188
1189 PVOID
1190 CmiGetBlock(PREGISTRY_FILE RegistryFile,
1191 BLOCK_OFFSET BlockOffset,
1192 OUT PHEAP_BLOCK * ppHeap)
1193 {
1194 if( BlockOffset == 0 || BlockOffset == -1) return NULL;
1195
1196 if (RegistryFile->Filename == NULL)
1197 {
1198 return (PVOID)BlockOffset;
1199 }
1200 else
1201 {
1202 PHEAP_BLOCK pHeap;
1203 pHeap = RegistryFile->BlockList[BlockOffset/4096];
1204 if(ppHeap) *ppHeap = pHeap;
1205 return ((char *)pHeap
1206 +(BlockOffset - pHeap->BlockOffset));
1207 }
1208 }
1209
1210 void
1211 CmiLockBlock(PREGISTRY_FILE RegistryFile,
1212 PVOID Block)
1213 {
1214 if (RegistryFile->Filename != NULL)
1215 {
1216 /* FIXME : implement */
1217 }
1218 }
1219
1220 void
1221 CmiReleaseBlock(PREGISTRY_FILE RegistryFile,
1222 PVOID Block)
1223 {
1224 if (RegistryFile->Filename != NULL)
1225 {
1226 /* FIXME : implement */
1227 }
1228 }