Added some error checks.
[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 DPRINT1("CmiCreateRegistry() Filename '%S'\n", Filename);
119 RegistryFile = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_FILE));
120 CHECKPOINT1;
121 if (RegistryFile == NULL)
122 return NULL;
123 CHECKPOINT1;
124 if (Filename != NULL)
125 {
126 UNICODE_STRING TmpFileName;
127 OBJECT_ATTRIBUTES ObjectAttributes;
128 NTSTATUS Status;
129 FILE_STANDARD_INFORMATION fsi;
130 IO_STATUS_BLOCK IoSB;
131
132 /* Duplicate Filename */
133 RegistryFile->Filename = ExAllocatePool(NonPagedPool, MAX_PATH);
134 wcscpy(RegistryFile->Filename , Filename);
135
136 RtlInitUnicodeString (&TmpFileName, Filename);
137 InitializeObjectAttributes(&ObjectAttributes,
138 &TmpFileName,
139 0,
140 NULL,
141 NULL);
142
143 Status = NtCreateFile( &FileHandle,
144 FILE_ALL_ACCESS,
145 &ObjectAttributes,
146 &IoSB,
147 NULL,
148 FILE_ATTRIBUTE_NORMAL,
149 0,
150 FILE_OPEN_IF,
151 FILE_NON_DIRECTORY_FILE,
152 NULL,
153 0 );
154
155 /* FIXME: create directory if IoSB.Status == STATUS_OBJECT_PATH_NOT_FOUND */
156 if( !NT_SUCCESS(Status) )
157 {
158 ExFreePool(RegistryFile->Filename);
159 RegistryFile->Filename = NULL;
160 return NULL;
161 }
162 /*if file did not exist*/
163 if( IoSB.Information == FILE_CREATED ){
164 Status = CmiCreateNewRegFile( FileHandle );
165 if( !NT_SUCCESS(Status) )
166 {
167 ExFreePool(RegistryFile->Filename);
168 RegistryFile->Filename = NULL;
169 return NULL;
170 }
171 }
172
173 RegistryFile->HeaderBlock = (PHEADER_BLOCK)
174 ExAllocatePool(NonPagedPool, sizeof(HEADER_BLOCK));
175
176 fileOffset.u.HighPart = 0;
177 fileOffset.u.LowPart = 0;
178 Status = ZwReadFile(FileHandle,
179 0, 0, 0, 0,
180 RegistryFile->HeaderBlock,
181 sizeof(HEADER_BLOCK),
182 &fileOffset, 0);
183 if (!NT_SUCCESS(Status))
184 {
185 ExFreePool(RegistryFile->Filename);
186 RegistryFile->Filename = NULL;
187 return NULL;
188 }
189
190 Status = ZwQueryInformationFile(FileHandle,&IoSB,&fsi
191 ,sizeof(fsi),FileStandardInformation);
192 if (!NT_SUCCESS(Status))
193 {
194 ExFreePool(RegistryFile->Filename);
195 RegistryFile->Filename = NULL;
196 return NULL;
197 }
198 RegistryFile->FileSize = fsi.EndOfFile.u.LowPart;
199 RegistryFile->BlockListSize = RegistryFile->FileSize / 4096 -1;
200 // RegistryFile->NumberOfBlocks = RegistryFile->BlockListSize;
201 RegistryFile->BlockList = ExAllocatePool(NonPagedPool,
202 sizeof(PHEAP_BLOCK *) * (RegistryFile->BlockListSize ));
203 BlockOffset=0;
204 fileOffset.u.HighPart = 0;
205 fileOffset.u.LowPart = 4096;
206 RegistryFile->BlockList [0]
207 = ExAllocatePool(NonPagedPool,RegistryFile->FileSize-4096);
208 if (RegistryFile->BlockList[0] == NULL)
209 {
210 // Status = STATUS_INSUFFICIENT_RESOURCES;
211 DPRINT1("error allocating %d bytes for registry\n"
212 ,RegistryFile->FileSize-4096);
213 ZwClose(FileHandle);
214 return NULL;
215 }
216 Status = ZwReadFile(FileHandle,
217 0, 0, 0, 0,
218 RegistryFile->BlockList [0],
219 RegistryFile->FileSize-4096,
220 &fileOffset, 0);
221 ZwClose(FileHandle);
222 if (!NT_SUCCESS(Status))
223 {
224 DPRINT1("error %x reading registry file at offset %x\n"
225 ,Status,fileOffset.u.LowPart);
226 return NULL;
227 }
228 RegistryFile->FreeListSize = 0;
229 RegistryFile->FreeListMax = 0;
230 RegistryFile->FreeList = NULL;
231 for(i=0 ; i <RegistryFile->BlockListSize; i++)
232 {
233 tmpHeap = (PHEAP_BLOCK)(((char *)RegistryFile->BlockList [0])+BlockOffset);
234 if (tmpHeap->BlockId != REG_HEAP_ID )
235 {
236 DPRINT1("bad BlockId %x,offset %x\n",tmpHeap->BlockId,fileOffset.u.LowPart);
237 }
238 RegistryFile->BlockList [i]
239 = tmpHeap;
240 if (tmpHeap->BlockSize >4096)
241 {
242 for(j=1;j<tmpHeap->BlockSize/4096;j++)
243 RegistryFile->BlockList[i+j] = RegistryFile->BlockList[i];
244 i = i+j-1;
245 }
246 /* search free blocks and add to list */
247 FreeOffset=REG_HEAP_BLOCK_DATA_OFFSET;
248 while(FreeOffset < tmpHeap->BlockSize)
249 {
250 FreeBlock = (PFREE_SUB_BLOCK)((char *)RegistryFile->BlockList[i]
251 +FreeOffset);
252 if ( FreeBlock->SubBlockSize>0)
253 {
254 CmiAddFree(RegistryFile,FreeBlock
255 ,RegistryFile->BlockList[i]->BlockOffset+FreeOffset);
256 FreeOffset += FreeBlock->SubBlockSize;
257 }
258 else
259 FreeOffset -= FreeBlock->SubBlockSize;
260 }
261 BlockOffset += tmpHeap->BlockSize;
262 }
263 Status = ObReferenceObjectByHandle(FileHandle,
264 FILE_ALL_ACCESS,
265 IoFileObjectType,
266 UserMode,
267 (PVOID*)&RegistryFile->FileObject,
268 NULL);
269 }
270 else
271 {
272 RegistryFile->Filename = NULL;
273 RegistryFile->FileObject = NULL;
274
275 RegistryFile->HeaderBlock = (PHEADER_BLOCK)
276 ExAllocatePool(NonPagedPool, sizeof(HEADER_BLOCK));
277 CmiCreateDefaultHeaderBlock(RegistryFile->HeaderBlock);
278
279 RootKeyBlock = (PKEY_BLOCK) ExAllocatePool(NonPagedPool, sizeof(KEY_BLOCK));
280 CmiCreateDefaultRootKeyBlock(RootKeyBlock);
281
282 RegistryFile->HeaderBlock->RootKeyBlock = (BLOCK_OFFSET) RootKeyBlock;
283 }
284 KeInitializeSemaphore(&RegistryFile->RegSem, 1, 1);
285
286 return RegistryFile;
287 }
288
289 ULONG
290 CmiGetMaxNameLength(PREGISTRY_FILE RegistryFile,
291 PKEY_BLOCK KeyBlock)
292 {
293 ULONG Idx, MaxName;
294 PHASH_TABLE_BLOCK HashBlock;
295 PKEY_BLOCK CurSubKeyBlock;
296
297 MaxName = 0;
298 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
299 if (HashBlock == 0)
300 {
301 return 0;
302 }
303 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
304 {
305 if (HashBlock->Table[Idx].KeyOffset != 0)
306 {
307 CurSubKeyBlock = CmiGetBlock(RegistryFile,
308 HashBlock->Table[Idx].KeyOffset,NULL);
309 if (MaxName < CurSubKeyBlock->NameSize)
310 {
311 MaxName = CurSubKeyBlock->NameSize;
312 }
313 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
314 }
315 }
316
317 CmiReleaseBlock(RegistryFile, HashBlock);
318
319 return MaxName;
320 }
321
322 ULONG
323 CmiGetMaxClassLength(PREGISTRY_FILE RegistryFile,
324 PKEY_BLOCK KeyBlock)
325 {
326 ULONG Idx, MaxClass;
327 PHASH_TABLE_BLOCK HashBlock;
328 PKEY_BLOCK CurSubKeyBlock;
329
330 MaxClass = 0;
331 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
332 if (HashBlock == 0)
333 {
334 return 0;
335 }
336 for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
337 {
338 if (HashBlock->Table[Idx].KeyOffset != 0)
339 {
340 CurSubKeyBlock = CmiGetBlock(RegistryFile,
341 HashBlock->Table[Idx].KeyOffset,NULL);
342 if (MaxClass < CurSubKeyBlock->ClassSize)
343 {
344 MaxClass = CurSubKeyBlock->ClassSize;
345 }
346 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
347 }
348 }
349
350 CmiReleaseBlock(RegistryFile, HashBlock);
351
352 return MaxClass;
353 }
354
355 ULONG
356 CmiGetMaxValueNameLength(PREGISTRY_FILE RegistryFile,
357 PKEY_BLOCK KeyBlock)
358 {
359 ULONG Idx, MaxValueName;
360 PVALUE_LIST_BLOCK ValueListBlock;
361 PVALUE_BLOCK CurValueBlock;
362
363 ValueListBlock = CmiGetBlock(RegistryFile,
364 KeyBlock->ValuesOffset,NULL);
365 MaxValueName = 0;
366 if (ValueListBlock == 0)
367 {
368 return 0;
369 }
370 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
371 {
372 CurValueBlock = CmiGetBlock(RegistryFile,
373 ValueListBlock->Values[Idx],NULL);
374 if (CurValueBlock != NULL &&
375 MaxValueName < CurValueBlock->NameSize)
376 {
377 MaxValueName = CurValueBlock->NameSize;
378 }
379 CmiReleaseBlock(RegistryFile, CurValueBlock);
380 }
381
382 CmiReleaseBlock(RegistryFile, ValueListBlock);
383
384 return MaxValueName;
385 }
386
387 ULONG
388 CmiGetMaxValueDataLength(PREGISTRY_FILE RegistryFile,
389 PKEY_BLOCK KeyBlock)
390 {
391 ULONG Idx, MaxValueData;
392 PVALUE_LIST_BLOCK ValueListBlock;
393 PVALUE_BLOCK CurValueBlock;
394
395 ValueListBlock = CmiGetBlock(RegistryFile,
396 KeyBlock->ValuesOffset,NULL);
397 MaxValueData = 0;
398 if (ValueListBlock == 0)
399 {
400 return 0;
401 }
402 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
403 {
404 CurValueBlock = CmiGetBlock(RegistryFile,
405 ValueListBlock->Values[Idx],NULL);
406 if (CurValueBlock != NULL &&
407 MaxValueData < (CurValueBlock->DataSize & LONG_MAX) )
408 {
409 MaxValueData = CurValueBlock->DataSize & LONG_MAX;
410 }
411 CmiReleaseBlock(RegistryFile, CurValueBlock);
412 }
413
414 CmiReleaseBlock(RegistryFile, ValueListBlock);
415
416 return MaxValueData;
417 }
418
419 NTSTATUS
420 CmiScanForSubKey(IN PREGISTRY_FILE RegistryFile,
421 IN PKEY_BLOCK KeyBlock,
422 OUT PKEY_BLOCK *SubKeyBlock,
423 OUT BLOCK_OFFSET *BlockOffset,
424 IN PCHAR KeyName,
425 IN ACCESS_MASK DesiredAccess,
426 IN ULONG Attributes)
427 {
428 ULONG Idx;
429 PHASH_TABLE_BLOCK HashBlock;
430 PKEY_BLOCK CurSubKeyBlock;
431 WORD KeyLength = strlen(KeyName);
432
433 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
434 *SubKeyBlock = NULL;
435 if (HashBlock == NULL)
436 {
437 return STATUS_SUCCESS;
438 }
439 // for (Idx = 0; Idx < HashBlock->HashTableSize; Idx++)
440 for (Idx = 0; Idx < KeyBlock->NumberOfSubKeys
441 && Idx < HashBlock->HashTableSize; Idx++)
442 {
443 if (Attributes & OBJ_CASE_INSENSITIVE)
444 {
445 if (HashBlock->Table[Idx].KeyOffset != 0 &&
446 HashBlock->Table[Idx].KeyOffset != -1 &&
447 !_strnicmp(KeyName, (PCHAR) &HashBlock->Table[Idx].HashValue, 4))
448 {
449 CurSubKeyBlock = CmiGetBlock(RegistryFile,
450 HashBlock->Table[Idx].KeyOffset,NULL);
451 if ( CurSubKeyBlock->NameSize == KeyLength
452 && !_strnicmp(KeyName, CurSubKeyBlock->Name, KeyLength))
453 {
454 *SubKeyBlock = CurSubKeyBlock;
455 *BlockOffset = HashBlock->Table[Idx].KeyOffset;
456 break;
457 }
458 else
459 {
460 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
461 }
462 }
463 }
464 else
465 {
466 if (HashBlock->Table[Idx].KeyOffset != 0 &&
467 HashBlock->Table[Idx].KeyOffset != -1 &&
468 !strncmp(KeyName, (PCHAR) &HashBlock->Table[Idx].HashValue, 4))
469 {
470 CurSubKeyBlock = CmiGetBlock(RegistryFile,
471 HashBlock->Table[Idx].KeyOffset,NULL);
472 if ( CurSubKeyBlock->NameSize == KeyLength
473 && !_strnicmp(KeyName, CurSubKeyBlock->Name, KeyLength))
474 {
475 *SubKeyBlock = CurSubKeyBlock;
476 *BlockOffset = HashBlock->Table[Idx].KeyOffset;
477 break;
478 }
479 else
480 {
481 CmiReleaseBlock(RegistryFile, CurSubKeyBlock);
482 }
483 }
484 }
485 }
486
487 CmiReleaseBlock(RegistryFile, HashBlock);
488
489 return STATUS_SUCCESS;
490 }
491
492 NTSTATUS
493 CmiAddSubKey(PREGISTRY_FILE RegistryFile,
494 PKEY_OBJECT Parent,
495 PKEY_OBJECT SubKey,
496 PWSTR NewSubKeyName,
497 USHORT NewSubKeyNameSize,
498 ULONG TitleIndex,
499 PUNICODE_STRING Class,
500 ULONG CreateOptions)
501 {
502 PKEY_BLOCK KeyBlock = Parent->KeyBlock;
503 NTSTATUS Status;
504 PHASH_TABLE_BLOCK HashBlock, NewHashBlock;
505 PKEY_BLOCK NewKeyBlock;
506 BLOCK_OFFSET NKBOffset;
507 ULONG NewBlockSize;
508 USHORT NameSize;
509
510 if (NewSubKeyName[0] == L'\\')
511 {
512 NewSubKeyName++;
513 NameSize = NewSubKeyNameSize/2-1;
514 }
515 else
516 NameSize = NewSubKeyNameSize/2;
517 Status = STATUS_SUCCESS;
518
519 NewBlockSize = sizeof(KEY_BLOCK) + NameSize;
520 Status = CmiAllocateBlock(RegistryFile, (PVOID) &NewKeyBlock
521 , NewBlockSize,&NKBOffset);
522 if (NewKeyBlock == NULL)
523 {
524 Status = STATUS_INSUFFICIENT_RESOURCES;
525 }
526 else
527 {
528 NewKeyBlock->SubBlockId = REG_KEY_BLOCK_ID;
529 NewKeyBlock->Type = REG_KEY_BLOCK_TYPE;
530 ZwQuerySystemTime((PTIME) &NewKeyBlock->LastWriteTime);
531 NewKeyBlock->ParentKeyOffset = -1;
532 NewKeyBlock->NumberOfSubKeys = 0;
533 NewKeyBlock->HashTableOffset = -1;
534 NewKeyBlock->NumberOfValues = 0;
535 NewKeyBlock->ValuesOffset = -1;
536 NewKeyBlock->SecurityKeyOffset = -1;
537 NewKeyBlock->NameSize = NameSize;
538 wcstombs(NewKeyBlock->Name,NewSubKeyName,NameSize);
539 NewKeyBlock->ClassNameOffset = -1;
540 if (Class)
541 {
542 PDATA_BLOCK pClass;
543 NewKeyBlock->ClassSize = Class->Length+sizeof(WCHAR);
544 Status = CmiAllocateBlock(RegistryFile
545 ,(PVOID)&pClass
546 ,NewKeyBlock->ClassSize
547 ,&NewKeyBlock->ClassNameOffset );
548 wcsncpy((PWSTR)pClass->Data,Class->Buffer,Class->Length);
549 ( (PWSTR)(pClass->Data))[Class->Length]=0;
550 }
551 }
552
553 if (!NT_SUCCESS(Status))
554 {
555 return Status;
556 }
557 SubKey->KeyBlock = NewKeyBlock;
558 SubKey->BlockOffset = NKBOffset;
559 /* don't modify hash table if key is volatile and parent is not */
560 if (RegistryFile == CmiVolatileFile && Parent->RegistryFile != RegistryFile)
561 {
562 return Status;
563 }
564 if (KeyBlock->HashTableOffset == -1)
565 {
566 Status = CmiAllocateHashTableBlock(RegistryFile,
567 &HashBlock,
568 &KeyBlock->HashTableOffset,
569 REG_INIT_HASH_TABLE_SIZE);
570 if (!NT_SUCCESS(Status))
571 {
572 return Status;
573 }
574 }
575 else
576 {
577 HashBlock = CmiGetBlock(RegistryFile, KeyBlock->HashTableOffset,NULL);
578 if (KeyBlock->NumberOfSubKeys + 1 >= HashBlock->HashTableSize)
579 {
580 BLOCK_OFFSET HTOffset;
581
582 /* Reallocate the hash table block */
583 Status = CmiAllocateHashTableBlock(RegistryFile,
584 &NewHashBlock,
585 &HTOffset,
586 HashBlock->HashTableSize +
587 REG_EXTEND_HASH_TABLE_SIZE);
588 if (!NT_SUCCESS(Status))
589 {
590 return Status;
591 }
592 RtlZeroMemory(&NewHashBlock->Table[0],
593 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
594 RtlCopyMemory(&NewHashBlock->Table[0],
595 &HashBlock->Table[0],
596 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
597 CmiDestroyBlock(RegistryFile, HashBlock
598 , KeyBlock->HashTableOffset);
599 KeyBlock->HashTableOffset = HTOffset;
600 HashBlock = NewHashBlock;
601 }
602 }
603 Status = CmiAddKeyToHashTable(RegistryFile, HashBlock, NewKeyBlock,NKBOffset);
604 if (NT_SUCCESS(Status))
605 {
606 KeyBlock->NumberOfSubKeys++;
607 }
608
609 return Status;
610 }
611
612 NTSTATUS
613 CmiScanKeyForValue(IN PREGISTRY_FILE RegistryFile,
614 IN PKEY_BLOCK KeyBlock,
615 IN PCHAR ValueName,
616 OUT PVALUE_BLOCK *ValueBlock,
617 OUT BLOCK_OFFSET *VBOffset)
618 {
619 ULONG Idx;
620 PVALUE_LIST_BLOCK ValueListBlock;
621 PVALUE_BLOCK CurValueBlock;
622 ValueListBlock = CmiGetBlock(RegistryFile,
623 KeyBlock->ValuesOffset,NULL);
624 *ValueBlock = NULL;
625 if (ValueListBlock == NULL)
626 {
627 return STATUS_SUCCESS;
628 }
629 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
630 {
631 CurValueBlock = CmiGetBlock(RegistryFile,
632 ValueListBlock->Values[Idx],NULL);
633 /* FIXME : perhaps we must not ignore case if NtCreateKey has not been */
634 /* called with OBJ_CASE_INSENSITIVE flag ? */
635 if (CurValueBlock != NULL &&
636 CurValueBlock->NameSize == strlen(ValueName) &&
637 !_strnicmp(CurValueBlock->Name, ValueName,strlen(ValueName)))
638 {
639 *ValueBlock = CurValueBlock;
640 if(VBOffset) *VBOffset = ValueListBlock->Values[Idx];
641 break;
642 }
643 CmiReleaseBlock(RegistryFile, CurValueBlock);
644 }
645
646 CmiReleaseBlock(RegistryFile, ValueListBlock);
647
648 return STATUS_SUCCESS;
649 }
650
651
652 NTSTATUS
653 CmiGetValueFromKeyByIndex(IN PREGISTRY_FILE RegistryFile,
654 IN PKEY_BLOCK KeyBlock,
655 IN ULONG Index,
656 OUT PVALUE_BLOCK *ValueBlock)
657 {
658 PVALUE_LIST_BLOCK ValueListBlock;
659 PVALUE_BLOCK CurValueBlock;
660 ValueListBlock = CmiGetBlock(RegistryFile,
661 KeyBlock->ValuesOffset,NULL);
662 *ValueBlock = NULL;
663 if (ValueListBlock == NULL)
664 {
665 return STATUS_NO_MORE_ENTRIES;
666 }
667 if (Index >= KeyBlock->NumberOfValues)
668 {
669 return STATUS_NO_MORE_ENTRIES;
670 }
671 CurValueBlock = CmiGetBlock(RegistryFile,
672 ValueListBlock->Values[Index],NULL);
673 if (CurValueBlock != NULL)
674 {
675 *ValueBlock = CurValueBlock;
676 }
677 CmiReleaseBlock(RegistryFile, CurValueBlock);
678 CmiReleaseBlock(RegistryFile, ValueListBlock);
679
680 return STATUS_SUCCESS;
681 }
682
683 NTSTATUS
684 CmiAddValueToKey(IN PREGISTRY_FILE RegistryFile,
685 IN PKEY_BLOCK KeyBlock,
686 IN PCHAR ValueNameBuf,
687 OUT PVALUE_BLOCK *pValueBlock,
688 OUT BLOCK_OFFSET *pVBOffset)
689 {
690 NTSTATUS Status;
691 PVALUE_LIST_BLOCK ValueListBlock, NewValueListBlock;
692 BLOCK_OFFSET VBOffset;
693 BLOCK_OFFSET VLBOffset;
694 PVALUE_BLOCK NewValueBlock;
695
696 Status = CmiAllocateValueBlock(RegistryFile,
697 &NewValueBlock,
698 &VBOffset,
699 ValueNameBuf);
700 *pVBOffset=VBOffset;
701 if (!NT_SUCCESS(Status))
702 {
703 return Status;
704 }
705 ValueListBlock = CmiGetBlock(RegistryFile,
706 KeyBlock->ValuesOffset,NULL);
707 if (ValueListBlock == NULL)
708 {
709 Status = CmiAllocateBlock(RegistryFile,
710 (PVOID) &ValueListBlock,
711 sizeof(BLOCK_OFFSET) * 3,
712 &VLBOffset);
713 if (!NT_SUCCESS(Status))
714 {
715 CmiDestroyValueBlock(RegistryFile,
716 NewValueBlock,VBOffset);
717 return Status;
718 }
719 KeyBlock->ValuesOffset = VLBOffset;
720 }
721 else if ( KeyBlock->NumberOfValues
722 >= -(ValueListBlock->SubBlockSize-4)/sizeof(BLOCK_OFFSET))
723 {
724 Status = CmiAllocateBlock(RegistryFile,
725 (PVOID) &NewValueListBlock,
726 sizeof(BLOCK_OFFSET) *
727 (KeyBlock->NumberOfValues +
728 REG_VALUE_LIST_BLOCK_MULTIPLE),&VLBOffset);
729 if (!NT_SUCCESS(Status))
730 {
731 CmiDestroyValueBlock(RegistryFile,
732 NewValueBlock,VBOffset);
733 return Status;
734 }
735 RtlCopyMemory(&NewValueListBlock->Values[0],
736 &ValueListBlock->Values[0],
737 sizeof(BLOCK_OFFSET) * KeyBlock->NumberOfValues);
738 CmiDestroyBlock(RegistryFile, ValueListBlock,KeyBlock->ValuesOffset);
739 KeyBlock->ValuesOffset = VLBOffset;
740 ValueListBlock = NewValueListBlock;
741 }
742 ValueListBlock->Values[KeyBlock->NumberOfValues] = VBOffset;
743 KeyBlock->NumberOfValues++;
744 CmiReleaseBlock(RegistryFile, ValueListBlock);
745 CmiReleaseBlock(RegistryFile, NewValueBlock);
746 *pValueBlock = NewValueBlock;
747
748 return STATUS_SUCCESS;
749 }
750
751 NTSTATUS
752 CmiDeleteValueFromKey(IN PREGISTRY_FILE RegistryFile,
753 IN PKEY_BLOCK KeyBlock,
754 IN PCHAR ValueName)
755 {
756 ULONG Idx;
757 PVALUE_LIST_BLOCK ValueListBlock;
758 PVALUE_BLOCK CurValueBlock;
759 PHEAP_BLOCK pHeap;
760
761 ValueListBlock = CmiGetBlock(RegistryFile,
762 KeyBlock->ValuesOffset,NULL);
763 if (ValueListBlock == 0)
764 {
765 return STATUS_SUCCESS;
766 }
767 for (Idx = 0; Idx < KeyBlock->NumberOfValues; Idx++)
768 {
769 CurValueBlock = CmiGetBlock(RegistryFile,
770 ValueListBlock->Values[Idx],&pHeap);
771 if (CurValueBlock != NULL &&
772 CurValueBlock->NameSize == strlen(ValueName) &&
773 !memcmp(CurValueBlock->Name, ValueName,strlen(ValueName)))
774 {
775 if (KeyBlock->NumberOfValues - 1 < Idx)
776 {
777 RtlCopyMemory(&ValueListBlock->Values[Idx],
778 &ValueListBlock->Values[Idx + 1],
779 sizeof(BLOCK_OFFSET) *
780 (KeyBlock->NumberOfValues - 1 - Idx));
781 }
782 else
783 {
784 RtlZeroMemory(&ValueListBlock->Values[Idx],
785 sizeof(BLOCK_OFFSET));
786 }
787 KeyBlock->NumberOfValues -= 1;
788 CmiDestroyValueBlock(RegistryFile, CurValueBlock, ValueListBlock->Values[Idx]);
789 /* update time of heap */
790 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
791
792 break;
793 }
794 CmiReleaseBlock(RegistryFile, CurValueBlock);
795 }
796
797 CmiReleaseBlock(RegistryFile, ValueListBlock);
798
799 return STATUS_SUCCESS;
800 }
801
802 NTSTATUS
803 CmiAllocateHashTableBlock(IN PREGISTRY_FILE RegistryFile,
804 OUT PHASH_TABLE_BLOCK *HashBlock,
805 OUT BLOCK_OFFSET *HBOffset,
806 IN ULONG HashTableSize)
807 {
808 NTSTATUS Status;
809 ULONG NewHashSize;
810 PHASH_TABLE_BLOCK NewHashBlock;
811
812 Status = STATUS_SUCCESS;
813 *HashBlock = NULL;
814 NewHashSize = sizeof(HASH_TABLE_BLOCK) +
815 (HashTableSize - 1) * sizeof(HASH_RECORD);
816 Status = CmiAllocateBlock(RegistryFile,
817 (PVOID*)&NewHashBlock,
818 NewHashSize,HBOffset);
819 if (NewHashBlock == NULL || !NT_SUCCESS(Status) )
820 {
821 Status = STATUS_INSUFFICIENT_RESOURCES;
822 }
823 else
824 {
825 NewHashBlock->SubBlockId = REG_HASH_TABLE_BLOCK_ID;
826 NewHashBlock->HashTableSize = HashTableSize;
827 *HashBlock = NewHashBlock;
828 }
829
830 return Status;
831 }
832
833 PKEY_BLOCK
834 CmiGetKeyFromHashByIndex(PREGISTRY_FILE RegistryFile,
835 PHASH_TABLE_BLOCK HashBlock,
836 ULONG Index)
837 {
838 PKEY_BLOCK KeyBlock;
839 BLOCK_OFFSET KeyOffset;
840
841 if( HashBlock == NULL)
842 return NULL;
843 if (RegistryFile->Filename == NULL)
844 {
845 KeyBlock = (PKEY_BLOCK) HashBlock->Table[Index].KeyOffset;
846 }
847 else
848 {
849 KeyOffset = HashBlock->Table[Index].KeyOffset;
850 KeyBlock = CmiGetBlock(RegistryFile,KeyOffset,NULL);
851 }
852 CmiLockBlock(RegistryFile, KeyBlock);
853
854 return KeyBlock;
855 }
856
857 NTSTATUS
858 CmiAddKeyToHashTable(PREGISTRY_FILE RegistryFile,
859 PHASH_TABLE_BLOCK HashBlock,
860 PKEY_BLOCK NewKeyBlock,
861 BLOCK_OFFSET NKBOffset)
862 {
863 ULONG i;
864
865 for (i = 0; i < HashBlock->HashTableSize; i++)
866 {
867 if (HashBlock->Table[i].KeyOffset == 0)
868 {
869 HashBlock->Table[i].KeyOffset = NKBOffset;
870 RtlCopyMemory(&HashBlock->Table[i].HashValue,
871 NewKeyBlock->Name,
872 4);
873 return STATUS_SUCCESS;
874 }
875 }
876 return STATUS_UNSUCCESSFUL;
877 }
878
879 NTSTATUS
880 CmiAllocateValueBlock(PREGISTRY_FILE RegistryFile,
881 PVALUE_BLOCK *ValueBlock,
882 BLOCK_OFFSET *VBOffset,
883 IN PCHAR ValueNameBuf)
884 {
885 NTSTATUS Status;
886 ULONG NewValueSize;
887 PVALUE_BLOCK NewValueBlock;
888
889 Status = STATUS_SUCCESS;
890
891 NewValueSize = sizeof(VALUE_BLOCK) + strlen(ValueNameBuf);
892 Status = CmiAllocateBlock(RegistryFile,
893 (PVOID*)&NewValueBlock,
894 NewValueSize,VBOffset);
895 if (NewValueBlock == NULL || !NT_SUCCESS(Status))
896 {
897 Status = STATUS_INSUFFICIENT_RESOURCES;
898 }
899 else
900 {
901 NewValueBlock->SubBlockId = REG_VALUE_BLOCK_ID;
902 NewValueBlock->NameSize = strlen(ValueNameBuf);
903 memcpy(NewValueBlock->Name, ValueNameBuf,strlen(ValueNameBuf));
904 NewValueBlock->DataType = 0;
905 NewValueBlock->DataSize = 0;
906 NewValueBlock->DataOffset = 0xffffffff;
907 *ValueBlock = NewValueBlock;
908 }
909
910 return Status;
911 }
912
913 NTSTATUS
914 CmiDestroyValueBlock(PREGISTRY_FILE RegistryFile,
915 PVALUE_BLOCK ValueBlock, BLOCK_OFFSET VBOffset)
916 {
917 NTSTATUS Status;
918 PHEAP_BLOCK pHeap;
919 PVOID pBlock;
920
921 /* first, release datas : */
922 if (ValueBlock->DataSize >0)
923 {
924 pBlock = CmiGetBlock(RegistryFile, ValueBlock->DataOffset,&pHeap);
925 Status = CmiDestroyBlock(RegistryFile, pBlock, ValueBlock->DataOffset);
926 if (!NT_SUCCESS(Status))
927 {
928 return Status;
929 }
930 /* update time of heap */
931 if(RegistryFile->Filename)
932 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
933 }
934
935 Status = CmiDestroyBlock(RegistryFile, ValueBlock, VBOffset);
936 /* update time of heap */
937 if(RegistryFile->Filename && CmiGetBlock(RegistryFile, VBOffset,&pHeap))
938 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
939 return Status;
940 }
941
942 NTSTATUS
943 CmiAddHeap(PREGISTRY_FILE RegistryFile,PVOID *NewBlock,BLOCK_OFFSET *NewBlockOffset)
944 {
945 PHEAP_BLOCK tmpHeap;
946 PHEAP_BLOCK * tmpBlockList;
947 PFREE_SUB_BLOCK tmpBlock;
948 tmpHeap=ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
949 tmpHeap->BlockId = REG_HEAP_ID;
950 tmpHeap->BlockOffset = RegistryFile->FileSize - REG_BLOCK_SIZE;
951 RegistryFile->FileSize += REG_BLOCK_SIZE;
952 tmpHeap->BlockSize = REG_BLOCK_SIZE;
953 tmpHeap->Unused1 = 0;
954 ZwQuerySystemTime((PTIME) &tmpHeap->DateModified);
955 tmpHeap->Unused2 = 0;
956 /* increase size of list of blocks */
957 tmpBlockList=ExAllocatePool(NonPagedPool,
958 sizeof(PHEAP_BLOCK *) * (RegistryFile->BlockListSize +1));
959 if (tmpBlockList == NULL)
960 {
961 KeBugCheck(0);
962 return(STATUS_INSUFFICIENT_RESOURCES);
963 }
964 if(RegistryFile->BlockListSize > 0)
965 {
966 memcpy(tmpBlockList,RegistryFile->BlockList,
967 sizeof(PHEAP_BLOCK *)*(RegistryFile->BlockListSize ));
968 ExFreePool(RegistryFile->BlockList);
969 }
970 RegistryFile->BlockList = tmpBlockList;
971 RegistryFile->BlockList [RegistryFile->BlockListSize++] = tmpHeap;
972 /* initialize a free block in this heap : */
973 tmpBlock = (PFREE_SUB_BLOCK)((char *) tmpHeap + REG_HEAP_BLOCK_DATA_OFFSET);
974 tmpBlock-> SubBlockSize = (REG_BLOCK_SIZE - REG_HEAP_BLOCK_DATA_OFFSET) ;
975 *NewBlock = (PVOID)tmpBlock;
976 if (NewBlockOffset)
977 *NewBlockOffset = tmpHeap->BlockOffset + REG_HEAP_BLOCK_DATA_OFFSET;
978 /* FIXME : set first dword to block_offset of another free bloc */
979 return STATUS_SUCCESS;
980 }
981
982 NTSTATUS
983 CmiAllocateBlock(PREGISTRY_FILE RegistryFile,
984 PVOID *Block,
985 LONG BlockSize,
986 BLOCK_OFFSET * pBlockOffset)
987 {
988 NTSTATUS Status;
989 PFREE_SUB_BLOCK NewBlock;
990 PHEAP_BLOCK pHeap;
991
992 Status = STATUS_SUCCESS;
993 /* round to 16 bytes multiple */
994 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
995
996 /* Handle volatile files first */
997 if (RegistryFile->Filename == NULL)
998 {
999 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
1000 if (NewBlock == NULL)
1001 {
1002 Status = STATUS_INSUFFICIENT_RESOURCES;
1003 }
1004 else
1005 {
1006 RtlZeroMemory(NewBlock, BlockSize);
1007 NewBlock->SubBlockSize = BlockSize;
1008 CmiLockBlock(RegistryFile, NewBlock);
1009 *Block = NewBlock;
1010 if (pBlockOffset) *pBlockOffset = (BLOCK_OFFSET)NewBlock;
1011 }
1012 }
1013 else
1014 {
1015 int i;
1016 /* first search in free blocks */
1017 NewBlock = NULL;
1018 for (i=0 ; i<RegistryFile->FreeListSize ; i++)
1019 {
1020 if(RegistryFile->FreeList[i]->SubBlockSize >=BlockSize)
1021 {
1022 NewBlock = RegistryFile->FreeList[i];
1023 if(pBlockOffset)
1024 *pBlockOffset = RegistryFile->FreeListOffset[i];
1025 /* update time of heap */
1026 if(RegistryFile->Filename
1027 && CmiGetBlock(RegistryFile, RegistryFile->FreeListOffset[i],&pHeap))
1028 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
1029 if( (i+1) <RegistryFile->FreeListSize)
1030 {
1031 memmove( &RegistryFile->FreeList[i]
1032 ,&RegistryFile->FreeList[i+1]
1033 ,sizeof(RegistryFile->FreeList[0])
1034 *(RegistryFile->FreeListSize-i-1));
1035 memmove( &RegistryFile->FreeListOffset[i]
1036 ,&RegistryFile->FreeListOffset[i+1]
1037 ,sizeof(RegistryFile->FreeListOffset[0])
1038 *(RegistryFile->FreeListSize-i-1));
1039 }
1040 RegistryFile->FreeListSize--;
1041 break;
1042 }
1043 }
1044 /* need to extend hive file : */
1045 if (NewBlock == NULL)
1046 {
1047 /* add a new block : */
1048 Status = CmiAddHeap(RegistryFile, (PVOID *)&NewBlock , pBlockOffset);
1049 }
1050 if (NT_SUCCESS(Status))
1051 {
1052 *Block = NewBlock;
1053 /* split the block in two parts */
1054 if(NewBlock->SubBlockSize > BlockSize)
1055 {
1056 NewBlock = (PFREE_SUB_BLOCK)((char *)NewBlock+BlockSize);
1057 NewBlock->SubBlockSize=((PFREE_SUB_BLOCK) (*Block))->SubBlockSize-BlockSize;
1058 CmiAddFree(RegistryFile,NewBlock,*pBlockOffset+BlockSize);
1059 }
1060 else if(NewBlock->SubBlockSize < BlockSize)
1061 return STATUS_UNSUCCESSFUL;
1062 RtlZeroMemory(*Block, BlockSize);
1063 ((PFREE_SUB_BLOCK)(*Block)) ->SubBlockSize = - BlockSize;
1064 CmiLockBlock(RegistryFile, *Block);
1065 }
1066 }
1067 return Status;
1068 }
1069
1070 NTSTATUS
1071 CmiDestroyBlock(PREGISTRY_FILE RegistryFile,
1072 PVOID Block,BLOCK_OFFSET Offset)
1073 {
1074 NTSTATUS Status;
1075 PHEAP_BLOCK pHeap;
1076
1077 Status = STATUS_SUCCESS;
1078
1079 if (RegistryFile->Filename == NULL)
1080 {
1081 CmiReleaseBlock(RegistryFile, Block);
1082 ExFreePool(Block);
1083 }
1084 else
1085 {
1086 PFREE_SUB_BLOCK pFree = Block;
1087 if (pFree->SubBlockSize <0)
1088 pFree->SubBlockSize = -pFree->SubBlockSize;
1089 CmiAddFree(RegistryFile,Block,Offset);
1090 CmiReleaseBlock(RegistryFile, Block);
1091 /* update time of heap */
1092 if(RegistryFile->Filename && CmiGetBlock(RegistryFile, Offset,&pHeap))
1093 ZwQuerySystemTime((PTIME) &pHeap->DateModified);
1094 /* FIXME : set first dword to block_offset of another free bloc ? */
1095 /* FIXME : concatenate with previous and next block if free */
1096 }
1097
1098 return Status;
1099 }
1100
1101 NTSTATUS
1102 CmiAddFree(PREGISTRY_FILE RegistryFile,
1103 PFREE_SUB_BLOCK FreeBlock,BLOCK_OFFSET FreeOffset)
1104 {
1105 PFREE_SUB_BLOCK *tmpList;
1106 BLOCK_OFFSET *tmpListOffset;
1107 int minInd,maxInd,medInd;
1108 if( (RegistryFile->FreeListSize+1) > RegistryFile->FreeListMax)
1109 {
1110 tmpList=ExAllocatePool(PagedPool
1111 ,sizeof(PFREE_SUB_BLOCK)*(RegistryFile->FreeListMax+32));
1112 if (tmpList == NULL)
1113 return STATUS_INSUFFICIENT_RESOURCES;
1114 tmpListOffset=ExAllocatePool(PagedPool
1115 ,sizeof(BLOCK_OFFSET *)*(RegistryFile->FreeListMax+32));
1116 if (tmpListOffset == NULL)
1117 return STATUS_INSUFFICIENT_RESOURCES;
1118 if (RegistryFile->FreeListMax)
1119 {
1120 memcpy(tmpList,RegistryFile->FreeList
1121 ,sizeof(PFREE_SUB_BLOCK)*(RegistryFile->FreeListMax));
1122 memcpy(tmpListOffset,RegistryFile->FreeListOffset
1123 ,sizeof(BLOCK_OFFSET *)*(RegistryFile->FreeListMax));
1124 ExFreePool(RegistryFile->FreeList);
1125 ExFreePool(RegistryFile->FreeListOffset);
1126 }
1127 RegistryFile->FreeList = tmpList;
1128 RegistryFile->FreeListOffset = tmpListOffset;
1129 RegistryFile->FreeListMax +=32;
1130 }
1131 /* add new offset to free list, maintening list in ascending order */
1132 if ( RegistryFile->FreeListSize==0
1133 || RegistryFile->FreeListOffset[RegistryFile->FreeListSize-1] < FreeOffset)
1134 {
1135 /* add to end of list : */
1136 RegistryFile->FreeList[RegistryFile->FreeListSize] = FreeBlock;
1137 RegistryFile->FreeListOffset[RegistryFile->FreeListSize ++] = FreeOffset;
1138 }
1139 else if (RegistryFile->FreeListOffset[0] > FreeOffset)
1140 {
1141 /* add to begin of list : */
1142 memmove( &RegistryFile->FreeList[1],&RegistryFile->FreeList[0]
1143 ,sizeof(RegistryFile->FreeList[0])*RegistryFile->FreeListSize);
1144 memmove( &RegistryFile->FreeListOffset[1],&RegistryFile->FreeListOffset[0]
1145 ,sizeof(RegistryFile->FreeListOffset[0])*RegistryFile->FreeListSize);
1146 RegistryFile->FreeList[0] = FreeBlock;
1147 RegistryFile->FreeListOffset[0] = FreeOffset;
1148 RegistryFile->FreeListSize ++;
1149 }
1150 else
1151 {
1152 /* search where to insert : */
1153 minInd=0;
1154 maxInd=RegistryFile->FreeListSize-1;
1155 while( (maxInd-minInd) >1)
1156 {
1157 medInd=(minInd+maxInd)/2;
1158 if (RegistryFile->FreeListOffset[medInd] > FreeOffset)
1159 maxInd=medInd;
1160 else
1161 minInd=medInd;
1162 }
1163 /* insert before maxInd : */
1164 memmove( &RegistryFile->FreeList[maxInd+1],&RegistryFile->FreeList[maxInd]
1165 ,sizeof(RegistryFile->FreeList[0])
1166 *(RegistryFile->FreeListSize-minInd));
1167 memmove( &RegistryFile->FreeListOffset[maxInd+1]
1168 , &RegistryFile->FreeListOffset[maxInd]
1169 , sizeof(RegistryFile->FreeListOffset[0])
1170 *(RegistryFile->FreeListSize-minInd));
1171 RegistryFile->FreeList[maxInd] = FreeBlock;
1172 RegistryFile->FreeListOffset[maxInd] = FreeOffset;
1173 RegistryFile->FreeListSize ++;
1174 }
1175 return STATUS_SUCCESS;
1176 }
1177
1178 PVOID
1179 CmiGetBlock(PREGISTRY_FILE RegistryFile,
1180 BLOCK_OFFSET BlockOffset,
1181 OUT PHEAP_BLOCK * ppHeap)
1182 {
1183 if( BlockOffset == 0 || BlockOffset == -1) return NULL;
1184
1185 if (RegistryFile->Filename == NULL)
1186 {
1187 return (PVOID)BlockOffset;
1188 }
1189 else
1190 {
1191 PHEAP_BLOCK pHeap;
1192 pHeap = RegistryFile->BlockList[BlockOffset/4096];
1193 if(ppHeap) *ppHeap = pHeap;
1194 return ((char *)pHeap
1195 +(BlockOffset - pHeap->BlockOffset));
1196 }
1197 }
1198
1199 void
1200 CmiLockBlock(PREGISTRY_FILE RegistryFile,
1201 PVOID Block)
1202 {
1203 if (RegistryFile->Filename != NULL)
1204 {
1205 /* FIXME : implement */
1206 }
1207 }
1208
1209 void
1210 CmiReleaseBlock(PREGISTRY_FILE RegistryFile,
1211 PVOID Block)
1212 {
1213 if (RegistryFile->Filename != NULL)
1214 {
1215 /* FIXME : implement */
1216 }
1217 }