Fixed registry bug.
[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 <roscfg.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 DPRINT("CmiCreateRegistry() Filename '%S'\n", Filename);
130 RegistryFile = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_FILE));
131
132 if (RegistryFile == NULL)
133 return NULL;
134
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 DPRINT("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 DPRINT("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 DPRINT("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 Length;
631 ULONG Idx;
632 PVALUE_LIST_BLOCK ValueListBlock;
633 PVALUE_BLOCK CurValueBlock;
634
635 ValueListBlock = CmiGetBlock(RegistryFile,
636 KeyBlock->ValuesOffset,NULL);
637 *ValueBlock = NULL;
638 if (ValueListBlock == NULL)
639 {
640 DPRINT("ValueListBlock is NULL\n");
641 return STATUS_SUCCESS;
642 }
643 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
644 {
645 CurValueBlock = CmiGetBlock(RegistryFile,
646 ValueListBlock->Values[Idx],NULL);
647 /* FIXME : perhaps we must not ignore case if NtCreateKey has not been */
648 /* called with OBJ_CASE_INSENSITIVE flag ? */
649 Length = strlen(ValueName);
650 if ((CurValueBlock != NULL) &&
651 (CurValueBlock->NameSize == Length) &&
652 (_strnicmp(CurValueBlock->Name, ValueName, Length) == 0))
653 {
654 *ValueBlock = CurValueBlock;
655 if(VBOffset) *VBOffset = ValueListBlock->Values[Idx];
656 DPRINT("Found value %s\n", ValueName);
657 break;
658 }
659 CmiReleaseBlock(RegistryFile, CurValueBlock);
660 }
661
662 CmiReleaseBlock(RegistryFile, ValueListBlock);
663
664 return STATUS_SUCCESS;
665 }
666
667
668 NTSTATUS
669 CmiGetValueFromKeyByIndex(IN PREGISTRY_FILE RegistryFile,
670 IN PKEY_BLOCK KeyBlock,
671 IN ULONG Index,
672 OUT PVALUE_BLOCK *ValueBlock)
673 {
674 PVALUE_LIST_BLOCK ValueListBlock;
675 PVALUE_BLOCK CurValueBlock;
676
677 ValueListBlock = CmiGetBlock(RegistryFile,
678 KeyBlock->ValuesOffset,NULL);
679 *ValueBlock = NULL;
680 if (ValueListBlock == NULL)
681 {
682 return STATUS_NO_MORE_ENTRIES;
683 }
684 if (Index >= KeyBlock->NumberOfValues)
685 {
686 return STATUS_NO_MORE_ENTRIES;
687 }
688 CurValueBlock = CmiGetBlock(RegistryFile,
689 ValueListBlock->Values[Index],NULL);
690 if (CurValueBlock != NULL)
691 {
692 *ValueBlock = CurValueBlock;
693 }
694 CmiReleaseBlock(RegistryFile, CurValueBlock);
695 CmiReleaseBlock(RegistryFile, ValueListBlock);
696
697 return STATUS_SUCCESS;
698 }
699
700 NTSTATUS
701 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile,
702 IN PKEY_BLOCK KeyBlock,
703 IN PCHAR ValueNameBuf,
704 OUT PVALUE_BLOCK *pValueBlock,
705 OUT BLOCK_OFFSET *pVBOffset)
706 {
707 NTSTATUS Status;
708 PVALUE_LIST_BLOCK ValueListBlock, NewValueListBlock;
709 BLOCK_OFFSET VBOffset;
710 BLOCK_OFFSET VLBOffset;
711 PVALUE_BLOCK NewValueBlock;
712
713 Status = CmiAllocateValueBlock(RegistryFile,
714 &NewValueBlock,
715 &VBOffset,
716 ValueNameBuf);
717 *pVBOffset=VBOffset;
718 if (!NT_SUCCESS(Status))
719 {
720 return Status;
721 }
722 ValueListBlock = CmiGetBlock(RegistryFile,
723 KeyBlock->ValuesOffset,NULL);
724 if (ValueListBlock == NULL)
725 {
726 Status = CmiAllocateBlock(RegistryFile,
727 (PVOID) &ValueListBlock,
728 sizeof(BLOCK_OFFSET) * 3,
729 &VLBOffset);
730 if (!NT_SUCCESS(Status))
731 {
732 CmiDestroyValueBlock(RegistryFile,
733 NewValueBlock,VBOffset);
734 return Status;
735 }
736 KeyBlock->ValuesOffset = VLBOffset;
737 }
738 else if (KeyBlock->NumberOfValues
739 >= ((LONG)(ValueListBlock->SubBlockSize-4))/(LONG)sizeof(BLOCK_OFFSET))
740 // >= -(ValueListBlock->SubBlockSize-4)/sizeof(BLOCK_OFFSET))
741 {
742 DPRINT1("\n");
743 Status = CmiAllocateBlock(RegistryFile,
744 (PVOID) &NewValueListBlock,
745 sizeof(BLOCK_OFFSET) *
746 (KeyBlock->NumberOfValues +
747 REG_VALUE_LIST_BLOCK_MULTIPLE),
748 &VLBOffset);
749 if (!NT_SUCCESS(Status))
750 {
751 CmiDestroyValueBlock(RegistryFile,
752 NewValueBlock,
753 VBOffset);
754 return(Status);
755 }
756 RtlCopyMemory(&NewValueListBlock->Values[0],
757 &ValueListBlock->Values[0],
758 sizeof(BLOCK_OFFSET) * KeyBlock->NumberOfValues);
759 CmiDestroyBlock(RegistryFile, ValueListBlock,KeyBlock->ValuesOffset);
760 KeyBlock->ValuesOffset = VLBOffset;
761 ValueListBlock = NewValueListBlock;
762 }
763 DPRINT1("KeyBlock->NumberOfValues %d, ValueListBlock->SubBlockSize %d (%d %x)\n",
764 KeyBlock->NumberOfValues, ValueListBlock->SubBlockSize,
765 -(ValueListBlock->SubBlockSize-4)/sizeof(BLOCK_OFFSET),
766 -(ValueListBlock->SubBlockSize-4)/sizeof(BLOCK_OFFSET));
767 ValueListBlock->Values[KeyBlock->NumberOfValues] = VBOffset;
768 KeyBlock->NumberOfValues++;
769 CmiReleaseBlock(RegistryFile, ValueListBlock);
770 CmiReleaseBlock(RegistryFile, NewValueBlock);
771 *pValueBlock = NewValueBlock;
772
773 return(STATUS_SUCCESS);
774 }
775
776 NTSTATUS
777 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile,
778 IN PKEY_BLOCK KeyBlock,
779 IN PCHAR ValueName)
780 {
781 ULONG Idx;
782 PVALUE_LIST_BLOCK ValueListBlock;
783 PVALUE_BLOCK CurValueBlock;
784 PHEAP_BLOCK pHeap;
785
786 ValueListBlock = CmiGetBlock(RegistryFile,
787 KeyBlock->ValuesOffset,NULL);
788 if (ValueListBlock == 0)
789 {
790 return STATUS_SUCCESS;
791 }
792 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
793 {
794 CurValueBlock = CmiGetBlock(RegistryFile,
795 ValueListBlock->Values[Idx],&pHeap);
796 if (CurValueBlock != NULL &&
797 CurValueBlock->NameSize == strlen(ValueName) &&
798 !memcmp(CurValueBlock->Name, ValueName,strlen(ValueName)))
799 {
800 if (KeyBlock->NumberOfValues - 1 < Idx)
801 {
802 RtlCopyMemory(&ValueListBlock->Values[Idx],
803 &ValueListBlock->Values[Idx + 1],
804 sizeof(BLOCK_OFFSET) *
805 (KeyBlock->NumberOfValues - 1 - Idx));
806 }
807 else
808 {
809 RtlZeroMemory(&ValueListBlock->Values[Idx],
810 sizeof(BLOCK_OFFSET));
811 }
812 KeyBlock->NumberOfValues -= 1;
813 CmiDestroyValueBlock(RegistryFile, CurValueBlock, ValueListBlock->Values[Idx]);
814 /* update time of heap */
815 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
816
817 break;
818 }
819 CmiReleaseBlock(RegistryFile, CurValueBlock);
820 }
821
822 CmiReleaseBlock(RegistryFile, ValueListBlock);
823
824 return STATUS_SUCCESS;
825 }
826
827 NTSTATUS
828 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile,
829 OUT PHASH_TABLE_BLOCK *HashBlock,
830 OUT BLOCK_OFFSET *HBOffset,
831 IN ULONG HashTableSize)
832 {
833 NTSTATUS Status;
834 ULONG NewHashSize;
835 PHASH_TABLE_BLOCK NewHashBlock;
836
837 Status = STATUS_SUCCESS;
838 *HashBlock = NULL;
839 NewHashSize = sizeof(HASH_TABLE_BLOCK) +
840 (HashTableSize - 1) * sizeof(HASH_RECORD);
841 Status = CmiAllocateBlock(RegistryFile,
842 (PVOID*)&NewHashBlock,
843 NewHashSize,HBOffset);
844 if (NewHashBlock == NULL || !NT_SUCCESS(Status) )
845 {
846 Status = STATUS_INSUFFICIENT_RESOURCES;
847 }
848 else
849 {
850 NewHashBlock->SubBlockId = REG_HASH_TABLE_BLOCK_ID;
851 NewHashBlock->HashTableSize = HashTableSize;
852 *HashBlock = NewHashBlock;
853 }
854
855 return Status;
856 }
857
858 PKEY_BLOCK
859 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile,
860 PHASH_TABLE_BLOCK HashBlock,
861 ULONG Index)
862 {
863 PKEY_BLOCK KeyBlock;
864 BLOCK_OFFSET KeyOffset;
865
866 if( HashBlock == NULL)
867 return NULL;
868 if (RegistryFile->Filename == NULL)
869 {
870 KeyBlock = (PKEY_BLOCK) HashBlock->Table[Index].KeyOffset;
871 }
872 else
873 {
874 KeyOffset = HashBlock->Table[Index].KeyOffset;
875 KeyBlock = CmiGetBlock(RegistryFile,KeyOffset,NULL);
876 }
877 CmiLockBlock(RegistryFile, KeyBlock);
878
879 return KeyBlock;
880 }
881
882 NTSTATUS
883 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile,
884 PHASH_TABLE_BLOCK HashBlock,
885 PKEY_BLOCK NewKeyBlock,
886 BLOCK_OFFSET NKBOffset)
887 {
888 ULONG i;
889
890 for (i = 0; i < HashBlock->HashTableSize; i++)
891 {
892 if (HashBlock->Table[i].KeyOffset == 0)
893 {
894 HashBlock->Table[i].KeyOffset = NKBOffset;
895 RtlCopyMemory(&HashBlock->Table[i].HashValue,
896 NewKeyBlock->Name,
897 4);
898 return STATUS_SUCCESS;
899 }
900 }
901 return STATUS_UNSUCCESSFUL;
902 }
903
904 NTSTATUS
905 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile,
906 PVALUE_BLOCK *ValueBlock,
907 BLOCK_OFFSET *VBOffset,
908 IN PCHAR ValueNameBuf)
909 {
910 NTSTATUS Status;
911 ULONG NewValueSize;
912 PVALUE_BLOCK NewValueBlock;
913
914 Status = STATUS_SUCCESS;
915
916 NewValueSize = sizeof(VALUE_BLOCK) + strlen(ValueNameBuf);
917 Status = CmiAllocateBlock(RegistryFile,
918 (PVOID*)&NewValueBlock,
919 NewValueSize,VBOffset);
920 if (NewValueBlock == NULL || !NT_SUCCESS(Status))
921 {
922 Status = STATUS_INSUFFICIENT_RESOURCES;
923 }
924 else
925 {
926 NewValueBlock->SubBlockId = REG_VALUE_BLOCK_ID;
927 NewValueBlock->NameSize = strlen(ValueNameBuf);
928 memcpy(NewValueBlock->Name, ValueNameBuf,strlen(ValueNameBuf));
929 NewValueBlock->DataType = 0;
930 NewValueBlock->DataSize = 0;
931 NewValueBlock->DataOffset = 0xffffffff;
932 *ValueBlock = NewValueBlock;
933 }
934
935 return Status;
936 }
937
938 NTSTATUS
939 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile,
940 PVALUE_BLOCK ValueBlock, BLOCK_OFFSET VBOffset)
941 {
942 NTSTATUS Status;
943 PHEAP_BLOCK pHeap;
944 PVOID pBlock;
945
946 /* first, release datas : */
947 if (ValueBlock->DataSize >0)
948 {
949 pBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset,&pHeap);
950 Status = CmiDestroyBlock(RegistryFile, pBlock, ValueBlock->DataOffset);
951 if (!NT_SUCCESS(Status))
952 {
953 return Status;
954 }
955 /* update time of heap */
956 if(RegistryFile->Filename)
957 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
958 }
959
960 Status = CmiDestroyBlock(RegistryFile, ValueBlock, VBOffset);
961 /* update time of heap */
962 if(RegistryFile->Filename && CmiGetBlock(RegistryFile, VBOffset,&pHeap))
963 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
964 return Status;
965 }
966
967 NTSTATUS
968 CmiAddHeap(PREGISTRY_FILE RegistryFile,PVOID *NewBlock,BLOCK_OFFSET *NewBlockOffset)
969 {
970 PHEAP_BLOCK tmpHeap;
971 PHEAP_BLOCK * tmpBlockList;
972 PFREE_SUB_BLOCK tmpBlock;
973 tmpHeap=ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
974 tmpHeap->BlockId = REG_HEAP_ID;
975 tmpHeap->BlockOffset = RegistryFile->FileSize - REG_BLOCK_SIZE;
976 RegistryFile->FileSize += REG_BLOCK_SIZE;
977 tmpHeap->BlockSize = REG_BLOCK_SIZE;
978 tmpHeap->Unused1 = 0;
979 ZwQuerySystemTime((PTIME) &tmpHeap->DateModified);
980 tmpHeap->Unused2 = 0;
981 /* increase size of list of blocks */
982 tmpBlockList=ExAllocatePool(NonPagedPool,
983 sizeof(PHEAP_BLOCK *) * (RegistryFile->BlockListSize +1));
984 if (tmpBlockList == NULL)
985 {
986 KeBugCheck(0);
987 return(STATUS_INSUFFICIENT_RESOURCES);
988 }
989 if(RegistryFile->BlockListSize > 0)
990 {
991 memcpy(tmpBlockList,RegistryFile->BlockList,
992 sizeof(PHEAP_BLOCK *)*(RegistryFile->BlockListSize ));
993 ExFreePool(RegistryFile->BlockList);
994 }
995 RegistryFile->BlockList = tmpBlockList;
996 RegistryFile->BlockList [RegistryFile->BlockListSize++] = tmpHeap;
997 /* initialize a free block in this heap : */
998 tmpBlock = (PFREE_SUB_BLOCK)((char *) tmpHeap + REG_HEAP_BLOCK_DATA_OFFSET);
999 tmpBlock-> SubBlockSize = (REG_BLOCK_SIZE - REG_HEAP_BLOCK_DATA_OFFSET) ;
1000 *NewBlock = (PVOID)tmpBlock;
1001 if (NewBlockOffset)
1002 *NewBlockOffset = tmpHeap->BlockOffset + REG_HEAP_BLOCK_DATA_OFFSET;
1003 /* FIXME : set first dword to block_offset of another free bloc */
1004 return STATUS_SUCCESS;
1005 }
1006
1007 NTSTATUS
1008 CmiAllocateBlock(PREGISTRY_FILE RegistryFile,
1009 PVOID *Block,
1010 LONG BlockSize,
1011 BLOCK_OFFSET * pBlockOffset)
1012 {
1013 NTSTATUS Status;
1014 PFREE_SUB_BLOCK NewBlock;
1015 PHEAP_BLOCK pHeap;
1016
1017 Status = STATUS_SUCCESS;
1018 /* round to 16 bytes multiple */
1019 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
1020
1021 /* Handle volatile files first */
1022 if (RegistryFile->Filename == NULL)
1023 {
1024 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
1025 if (NewBlock == NULL)
1026 {
1027 Status = STATUS_INSUFFICIENT_RESOURCES;
1028 }
1029 else
1030 {
1031 RtlZeroMemory(NewBlock, BlockSize);
1032 NewBlock->SubBlockSize = BlockSize;
1033 CmiLockBlock(RegistryFile, NewBlock);
1034 *Block = NewBlock;
1035 if (pBlockOffset) *pBlockOffset = (BLOCK_OFFSET)NewBlock;
1036 }
1037 }
1038 else
1039 {
1040 int i;
1041 /* first search in free blocks */
1042 NewBlock = NULL;
1043 for (i=0 ; i<RegistryFile->FreeListSize ; i++)
1044 {
1045 if(RegistryFile->FreeList[i]->SubBlockSize >=BlockSize)
1046 {
1047 NewBlock = RegistryFile->FreeList[i];
1048 if(pBlockOffset)
1049 *pBlockOffset = RegistryFile->FreeListOffset[i];
1050 /* update time of heap */
1051 if(RegistryFile->Filename
1052 && CmiGetBlock(RegistryFile, RegistryFile->FreeListOffset[i],&pHeap))
1053 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
1054 if( (i+1) <RegistryFile->FreeListSize)
1055 {
1056 memmove( &RegistryFile->FreeList[i]
1057 ,&RegistryFile->FreeList[i+1]
1058 ,sizeof(RegistryFile->FreeList[0])
1059 *(RegistryFile->FreeListSize-i-1));
1060 memmove( &RegistryFile->FreeListOffset[i]
1061 ,&RegistryFile->FreeListOffset[i+1]
1062 ,sizeof(RegistryFile->FreeListOffset[0])
1063 *(RegistryFile->FreeListSize-i-1));
1064 }
1065 RegistryFile->FreeListSize--;
1066 break;
1067 }
1068 }
1069 /* need to extend hive file : */
1070 if (NewBlock == NULL)
1071 {
1072 /* add a new block : */
1073 Status = CmiAddHeap(RegistryFile, (PVOID *)&NewBlock , pBlockOffset);
1074 }
1075 if (NT_SUCCESS(Status))
1076 {
1077 *Block = NewBlock;
1078 /* split the block in two parts */
1079 if(NewBlock->SubBlockSize > BlockSize)
1080 {
1081 NewBlock = (PFREE_SUB_BLOCK)((char *)NewBlock+BlockSize);
1082 NewBlock->SubBlockSize=((PFREE_SUB_BLOCK) (*Block))->SubBlockSize-BlockSize;
1083 CmiAddFree(RegistryFile,NewBlock,*pBlockOffset+BlockSize);
1084 }
1085 else if(NewBlock->SubBlockSize < BlockSize)
1086 return STATUS_UNSUCCESSFUL;
1087 RtlZeroMemory(*Block, BlockSize);
1088 ((PFREE_SUB_BLOCK)(*Block)) ->SubBlockSize = - BlockSize;
1089 CmiLockBlock(RegistryFile, *Block);
1090 }
1091 }
1092 return Status;
1093 }
1094
1095 NTSTATUS
1096 CmiDestroyBlock(PREGISTRY_FILE RegistryFile,
1097 PVOID Block,BLOCK_OFFSET Offset)
1098 {
1099 NTSTATUS Status;
1100 PHEAP_BLOCK pHeap;
1101
1102 Status = STATUS_SUCCESS;
1103
1104 if (RegistryFile->Filename == NULL)
1105 {
1106 CmiReleaseBlock(RegistryFile, Block);
1107 ExFreePool(Block);
1108 }
1109 else
1110 {
1111 PFREE_SUB_BLOCK pFree = Block;
1112
1113 if (pFree->SubBlockSize <0)
1114 pFree->SubBlockSize = -pFree->SubBlockSize;
1115 CmiAddFree(RegistryFile,Block,Offset);
1116 CmiReleaseBlock(RegistryFile, Block);
1117 /* update time of heap */
1118 if(RegistryFile->Filename && CmiGetBlock(RegistryFile, Offset,&pHeap))
1119 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
1120 /* FIXME : set first dword to block_offset of another free block ? */
1121 /* FIXME : concatenate with previous and next block if free */
1122 }
1123
1124 return Status;
1125 }
1126
1127 NTSTATUS
1128 CmiAddFree(PREGISTRY_FILE RegistryFile,
1129 PFREE_SUB_BLOCK FreeBlock,BLOCK_OFFSET FreeOffset)
1130 {
1131 PFREE_SUB_BLOCK *tmpList;
1132 BLOCK_OFFSET *tmpListOffset;
1133 int minInd,maxInd,medInd;
1134 if( (RegistryFile->FreeListSize+1) > RegistryFile->FreeListMax)
1135 {
1136 tmpList=ExAllocatePool(PagedPool
1137 ,sizeof(PFREE_SUB_BLOCK)*(RegistryFile->FreeListMax+32));
1138 if (tmpList == NULL)
1139 return STATUS_INSUFFICIENT_RESOURCES;
1140 tmpListOffset=ExAllocatePool(PagedPool
1141 ,sizeof(BLOCK_OFFSET *)*(RegistryFile->FreeListMax+32));
1142 if (tmpListOffset == NULL)
1143 return STATUS_INSUFFICIENT_RESOURCES;
1144 if (RegistryFile->FreeListMax)
1145 {
1146 memcpy(tmpList,RegistryFile->FreeList
1147 ,sizeof(PFREE_SUB_BLOCK)*(RegistryFile->FreeListMax));
1148 memcpy(tmpListOffset,RegistryFile->FreeListOffset
1149 ,sizeof(BLOCK_OFFSET *)*(RegistryFile->FreeListMax));
1150 ExFreePool(RegistryFile->FreeList);
1151 ExFreePool(RegistryFile->FreeListOffset);
1152 }
1153 RegistryFile->FreeList = tmpList;
1154 RegistryFile->FreeListOffset = tmpListOffset;
1155 RegistryFile->FreeListMax +=32;
1156 }
1157 /* add new offset to free list, maintening list in ascending order */
1158 if ( RegistryFile->FreeListSize==0
1159 || RegistryFile->FreeListOffset[RegistryFile->FreeListSize-1] < FreeOffset)
1160 {
1161 /* add to end of list : */
1162 RegistryFile->FreeList[RegistryFile->FreeListSize] = FreeBlock;
1163 RegistryFile->FreeListOffset[RegistryFile->FreeListSize ++] = FreeOffset;
1164 }
1165 else if (RegistryFile->FreeListOffset[0] > FreeOffset)
1166 {
1167 /* add to begin of list : */
1168 memmove( &RegistryFile->FreeList[1],&RegistryFile->FreeList[0]
1169 ,sizeof(RegistryFile->FreeList[0])*RegistryFile->FreeListSize);
1170 memmove( &RegistryFile->FreeListOffset[1],&RegistryFile->FreeListOffset[0]
1171 ,sizeof(RegistryFile->FreeListOffset[0])*RegistryFile->FreeListSize);
1172 RegistryFile->FreeList[0] = FreeBlock;
1173 RegistryFile->FreeListOffset[0] = FreeOffset;
1174 RegistryFile->FreeListSize ++;
1175 }
1176 else
1177 {
1178 /* search where to insert : */
1179 minInd=0;
1180 maxInd=RegistryFile->FreeListSize-1;
1181 while( (maxInd-minInd) >1)
1182 {
1183 medInd=(minInd+maxInd)/2;
1184 if (RegistryFile->FreeListOffset[medInd] > FreeOffset)
1185 maxInd=medInd;
1186 else
1187 minInd=medInd;
1188 }
1189 /* insert before maxInd : */
1190 memmove( &RegistryFile->FreeList[maxInd+1],&RegistryFile->FreeList[maxInd]
1191 ,sizeof(RegistryFile->FreeList[0])
1192 *(RegistryFile->FreeListSize-minInd));
1193 memmove( &RegistryFile->FreeListOffset[maxInd+1]
1194 , &RegistryFile->FreeListOffset[maxInd]
1195 , sizeof(RegistryFile->FreeListOffset[0])
1196 *(RegistryFile->FreeListSize-minInd));
1197 RegistryFile->FreeList[maxInd] = FreeBlock;
1198 RegistryFile->FreeListOffset[maxInd] = FreeOffset;
1199 RegistryFile->FreeListSize ++;
1200 }
1201 return STATUS_SUCCESS;
1202 }
1203
1204 PVOID
1205 CmiGetBlock(PREGISTRY_FILE RegistryFile,
1206 BLOCK_OFFSET BlockOffset,
1207 OUT PHEAP_BLOCK * ppHeap)
1208 {
1209 if( BlockOffset == 0 || BlockOffset == -1)
1210 return NULL;
1211
1212 if (RegistryFile->Filename == NULL)
1213 {
1214 return (PVOID)BlockOffset;
1215 }
1216 else
1217 {
1218 PHEAP_BLOCK pHeap;
1219
1220 pHeap = RegistryFile->BlockList[BlockOffset/4096];
1221 if(ppHeap) *ppHeap = pHeap;
1222 return ((char *)pHeap
1223 +(BlockOffset - pHeap->BlockOffset));
1224 }
1225 }
1226
1227 VOID
1228 CmiLockBlock(PREGISTRY_FILE RegistryFile,
1229 PVOID Block)
1230 {
1231 if (RegistryFile->Filename != NULL)
1232 {
1233 /* FIXME : implement */
1234 }
1235 }
1236
1237 VOID
1238 CmiReleaseBlock(PREGISTRY_FILE RegistryFile,
1239 PVOID Block)
1240 {
1241 if (RegistryFile->Filename != NULL)
1242 {
1243 /* FIXME : implement */
1244 }
1245 }