1 /*
2 * PROJECT: Registry manipulation library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * COPYRIGHT: Copyright 2005 Filip Navara <navaraf@reactos.org>
5 * Copyright 2001 - 2005 Eric Kohl
6 */
7
8 #include "cmlib.h"
9 #define NDEBUG
10 #include <debug.h>
11
12 /* DECLARATIONS *************************************************************/
13
14 #if !defined(CMLIB_HOST) && !defined(_BLDR_)
15 VOID
16 NTAPI
17 CmpLazyFlush(VOID);
18 #endif
19
20 /* FUNCTIONS *****************************************************************/
21
22 static __inline PHCELL CMAPI
HvpGetCellHeader(PHHIVE RegistryHive,HCELL_INDEX CellIndex)23 HvpGetCellHeader(
24 PHHIVE RegistryHive,
25 HCELL_INDEX CellIndex)
26 {
27 PVOID Block;
28
29 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive 0x%p, CellIndex 0x%x\n",
30 __FUNCTION__, RegistryHive, CellIndex);
31
32 ASSERT(CellIndex != HCELL_NIL);
33 if (!RegistryHive->Flat)
34 {
35 ULONG CellType = HvGetCellType(CellIndex);
36 ULONG CellBlock = HvGetCellBlock(CellIndex);
37 ULONG CellOffset = (CellIndex & HCELL_OFFSET_MASK) >> HCELL_OFFSET_SHIFT;
38
39 ASSERT(CellBlock < RegistryHive->Storage[CellType].Length);
40 Block = (PVOID)RegistryHive->Storage[CellType].BlockList[CellBlock].BlockAddress;
41 ASSERT(Block != NULL);
42 return (PHCELL)((ULONG_PTR)Block + CellOffset);
43 }
44 else
45 {
46 ASSERT(HvGetCellType(CellIndex) == Stable);
47 return (PHCELL)((ULONG_PTR)RegistryHive->BaseBlock + HBLOCK_SIZE +
48 CellIndex);
49 }
50 }
51
52 BOOLEAN CMAPI
HvIsCellAllocated(IN PHHIVE RegistryHive,IN HCELL_INDEX CellIndex)53 HvIsCellAllocated(IN PHHIVE RegistryHive,
54 IN HCELL_INDEX CellIndex)
55 {
56 ULONG Type, Block;
57
58 /* If it's a flat hive, the cell is always allocated */
59 if (RegistryHive->Flat)
60 return TRUE;
61
62 /* Otherwise, get the type and make sure it's valid */
63 Type = HvGetCellType(CellIndex);
64 Block = HvGetCellBlock(CellIndex);
65 if (Block >= RegistryHive->Storage[Type].Length)
66 return FALSE;
67
68 /* Try to get the cell block */
69 if (RegistryHive->Storage[Type].BlockList[Block].BlockAddress)
70 return TRUE;
71
72 /* No valid block, fail */
73 return FALSE;
74 }
75
76 PCELL_DATA CMAPI
HvpGetCellData(_In_ PHHIVE Hive,_In_ HCELL_INDEX CellIndex)77 HvpGetCellData(
78 _In_ PHHIVE Hive,
79 _In_ HCELL_INDEX CellIndex)
80 {
81 return (PCELL_DATA)(HvpGetCellHeader(Hive, CellIndex) + 1);
82 }
83
84 static __inline LONG CMAPI
HvpGetCellFullSize(PHHIVE RegistryHive,PVOID Cell)85 HvpGetCellFullSize(
86 PHHIVE RegistryHive,
87 PVOID Cell)
88 {
89 UNREFERENCED_PARAMETER(RegistryHive);
90 return ((PHCELL)Cell - 1)->Size;
91 }
92
93 LONG CMAPI
HvGetCellSize(IN PHHIVE Hive,IN PVOID Address)94 HvGetCellSize(IN PHHIVE Hive,
95 IN PVOID Address)
96 {
97 PHCELL CellHeader;
98 LONG Size;
99
100 UNREFERENCED_PARAMETER(Hive);
101
102 CellHeader = (PHCELL)Address - 1;
103 Size = CellHeader->Size * -1;
104 Size -= sizeof(HCELL);
105 return Size;
106 }
107
108 BOOLEAN CMAPI
HvMarkCellDirty(PHHIVE RegistryHive,HCELL_INDEX CellIndex,BOOLEAN HoldingLock)109 HvMarkCellDirty(
110 PHHIVE RegistryHive,
111 HCELL_INDEX CellIndex,
112 BOOLEAN HoldingLock)
113 {
114 ULONG CellBlock;
115 ULONG CellLastBlock;
116
117 ASSERT(RegistryHive->ReadOnly == FALSE);
118
119 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive 0x%p, CellIndex 0x%x, HoldingLock %u\n",
120 __FUNCTION__, RegistryHive, CellIndex, HoldingLock);
121
122 if (HvGetCellType(CellIndex) != Stable)
123 return TRUE;
124
125 CellBlock = HvGetCellBlock(CellIndex);
126 CellLastBlock = HvGetCellBlock(CellIndex + HBLOCK_SIZE - 1);
127
128 RtlSetBits(&RegistryHive->DirtyVector,
129 CellBlock, CellLastBlock - CellBlock);
130 RegistryHive->DirtyCount++;
131
132 /*
133 * FIXME: Querying a lazy flush operation is needed to
134 * ensure that the dirty data is being flushed to disk
135 * accordingly. However, this operation has to be done
136 * in a helper like HvMarkDirty that marks specific parts
137 * of the hive as dirty. Since we do not have such kind
138 * of helper we have to perform an eventual lazy flush
139 * when marking cells as dirty here for the moment being,
140 * so that not only we flush dirty data but also write
141 * logs.
142 */
143 #if !defined(CMLIB_HOST) && !defined(_BLDR_)
144 if (!(RegistryHive->HiveFlags & HIVE_NOLAZYFLUSH))
145 {
146 CmpLazyFlush();
147 }
148 #endif
149 return TRUE;
150 }
151
152 BOOLEAN CMAPI
HvIsCellDirty(IN PHHIVE Hive,IN HCELL_INDEX Cell)153 HvIsCellDirty(IN PHHIVE Hive,
154 IN HCELL_INDEX Cell)
155 {
156 BOOLEAN IsDirty = FALSE;
157
158 /* Sanity checks */
159 ASSERT(Hive->ReadOnly == FALSE);
160
161 /* Volatile cells are always "dirty" */
162 if (HvGetCellType(Cell) == Volatile)
163 return TRUE;
164
165 /* Check if the dirty bit is set */
166 if (RtlCheckBit(&Hive->DirtyVector, Cell / HBLOCK_SIZE))
167 IsDirty = TRUE;
168
169 /* Return result as boolean*/
170 return IsDirty;
171 }
172
173 static __inline ULONG CMAPI
HvpComputeFreeListIndex(ULONG Size)174 HvpComputeFreeListIndex(
175 ULONG Size)
176 {
177 ULONG Index;
178 static CCHAR FindFirstSet[128] = {
179 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
180 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
181 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
182 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
183 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
184 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
185 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
186 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
187
188 ASSERT(Size >= (1 << 3));
189 Index = (Size >> 3) - 1;
190 if (Index >= 16)
191 {
192 if (Index > 127)
193 Index = 23;
194 else
195 Index = FindFirstSet[Index] + 16;
196 }
197
198 return Index;
199 }
200
201 static NTSTATUS CMAPI
HvpAddFree(PHHIVE RegistryHive,PHCELL FreeBlock,HCELL_INDEX FreeIndex)202 HvpAddFree(
203 PHHIVE RegistryHive,
204 PHCELL FreeBlock,
205 HCELL_INDEX FreeIndex)
206 {
207 PHCELL_INDEX FreeBlockData;
208 HSTORAGE_TYPE Storage;
209 ULONG Index;
210
211 ASSERT(RegistryHive != NULL);
212 ASSERT(FreeBlock != NULL);
213
214 Storage = HvGetCellType(FreeIndex);
215 Index = HvpComputeFreeListIndex((ULONG)FreeBlock->Size);
216
217 FreeBlockData = (PHCELL_INDEX)(FreeBlock + 1);
218 *FreeBlockData = RegistryHive->Storage[Storage].FreeDisplay[Index];
219 RegistryHive->Storage[Storage].FreeDisplay[Index] = FreeIndex;
220
221 /* FIXME: Eventually get rid of free bins. */
222
223 return STATUS_SUCCESS;
224 }
225
226 static VOID CMAPI
HvpRemoveFree(PHHIVE RegistryHive,PHCELL CellBlock,HCELL_INDEX CellIndex)227 HvpRemoveFree(
228 PHHIVE RegistryHive,
229 PHCELL CellBlock,
230 HCELL_INDEX CellIndex)
231 {
232 PHCELL_INDEX FreeCellData;
233 PHCELL_INDEX pFreeCellOffset;
234 HSTORAGE_TYPE Storage;
235 ULONG Index, FreeListIndex;
236
237 ASSERT(RegistryHive->ReadOnly == FALSE);
238
239 Storage = HvGetCellType(CellIndex);
240 Index = HvpComputeFreeListIndex((ULONG)CellBlock->Size);
241
242 pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index];
243 while (*pFreeCellOffset != HCELL_NIL)
244 {
245 FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
246 if (*pFreeCellOffset == CellIndex)
247 {
248 *pFreeCellOffset = *FreeCellData;
249 return;
250 }
251 pFreeCellOffset = FreeCellData;
252 }
253
254 /* Something bad happened, print a useful trace info and bugcheck */
255 CMLTRACE(CMLIB_HCELL_DEBUG, "-- beginning of HvpRemoveFree trace --\n");
256 CMLTRACE(CMLIB_HCELL_DEBUG, "block we are about to free: %08x\n", CellIndex);
257 CMLTRACE(CMLIB_HCELL_DEBUG, "chosen free list index: %u\n", Index);
258 for (FreeListIndex = 0; FreeListIndex < 24; FreeListIndex++)
259 {
260 CMLTRACE(CMLIB_HCELL_DEBUG, "free list [%u]: ", FreeListIndex);
261 pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[FreeListIndex];
262 while (*pFreeCellOffset != HCELL_NIL)
263 {
264 CMLTRACE(CMLIB_HCELL_DEBUG, "%08x ", *pFreeCellOffset);
265 FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
266 pFreeCellOffset = FreeCellData;
267 }
268 CMLTRACE(CMLIB_HCELL_DEBUG, "\n");
269 }
270 CMLTRACE(CMLIB_HCELL_DEBUG, "-- end of HvpRemoveFree trace --\n");
271
272 ASSERT(FALSE);
273 }
274
275 static HCELL_INDEX CMAPI
HvpFindFree(PHHIVE RegistryHive,ULONG Size,HSTORAGE_TYPE Storage)276 HvpFindFree(
277 PHHIVE RegistryHive,
278 ULONG Size,
279 HSTORAGE_TYPE Storage)
280 {
281 PHCELL_INDEX FreeCellData;
282 HCELL_INDEX FreeCellOffset;
283 PHCELL_INDEX pFreeCellOffset;
284 ULONG Index;
285
286 for (Index = HvpComputeFreeListIndex(Size); Index < 24; Index++)
287 {
288 pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index];
289 while (*pFreeCellOffset != HCELL_NIL)
290 {
291 FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
292 if ((ULONG)HvpGetCellFullSize(RegistryHive, FreeCellData) >= Size)
293 {
294 FreeCellOffset = *pFreeCellOffset;
295 *pFreeCellOffset = *FreeCellData;
296 return FreeCellOffset;
297 }
298 pFreeCellOffset = FreeCellData;
299 }
300 }
301
302 return HCELL_NIL;
303 }
304
305 NTSTATUS CMAPI
HvpCreateHiveFreeCellList(PHHIVE Hive)306 HvpCreateHiveFreeCellList(
307 PHHIVE Hive)
308 {
309 HCELL_INDEX BlockOffset;
310 PHCELL FreeBlock;
311 ULONG BlockIndex;
312 ULONG FreeOffset;
313 PHBIN Bin;
314 NTSTATUS Status;
315 ULONG Index;
316
317 /* Initialize the free cell list */
318 for (Index = 0; Index < 24; Index++)
319 {
320 Hive->Storage[Stable].FreeDisplay[Index] = HCELL_NIL;
321 Hive->Storage[Volatile].FreeDisplay[Index] = HCELL_NIL;
322 }
323
324 BlockOffset = 0;
325 BlockIndex = 0;
326 while (BlockIndex < Hive->Storage[Stable].Length)
327 {
328 Bin = (PHBIN)Hive->Storage[Stable].BlockList[BlockIndex].BinAddress;
329
330 /* Search free blocks and add to list */
331 FreeOffset = sizeof(HBIN);
332 while (FreeOffset < Bin->Size)
333 {
334 FreeBlock = (PHCELL)((ULONG_PTR)Bin + FreeOffset);
335 if (FreeBlock->Size > 0)
336 {
337 Status = HvpAddFree(Hive, FreeBlock, Bin->FileOffset + FreeOffset);
338 if (!NT_SUCCESS(Status))
339 return Status;
340
341 FreeOffset += FreeBlock->Size;
342 }
343 else
344 {
345 FreeOffset -= FreeBlock->Size;
346 }
347 }
348
349 BlockIndex += Bin->Size / HBLOCK_SIZE;
350 BlockOffset += Bin->Size;
351 }
352
353 return STATUS_SUCCESS;
354 }
355
356 HCELL_INDEX CMAPI
HvAllocateCell(PHHIVE RegistryHive,ULONG Size,HSTORAGE_TYPE Storage,HCELL_INDEX Vicinity)357 HvAllocateCell(
358 PHHIVE RegistryHive,
359 ULONG Size,
360 HSTORAGE_TYPE Storage,
361 HCELL_INDEX Vicinity)
362 {
363 PHCELL FreeCell;
364 HCELL_INDEX FreeCellOffset;
365 PHCELL NewCell;
366 PHBIN Bin;
367
368 ASSERT(RegistryHive->ReadOnly == FALSE);
369
370 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive 0x%p, Size 0x%x, %s, Vicinity 0x%x\n",
371 __FUNCTION__, RegistryHive, Size, (Storage == 0) ? "Stable" : "Volatile", Vicinity);
372
373 /* Round to 16 bytes multiple. */
374 Size = ROUND_UP(Size + sizeof(HCELL), 16);
375
376 /* First search in free blocks. */
377 FreeCellOffset = HvpFindFree(RegistryHive, Size, Storage);
378
379 /* If no free cell was found we need to extend the hive file. */
380 if (FreeCellOffset == HCELL_NIL)
381 {
382 Bin = HvpAddBin(RegistryHive, Size, Storage);
383 if (Bin == NULL)
384 return HCELL_NIL;
385 FreeCellOffset = Bin->FileOffset + sizeof(HBIN);
386 FreeCellOffset |= Storage << HCELL_TYPE_SHIFT;
387 }
388
389 FreeCell = HvpGetCellHeader(RegistryHive, FreeCellOffset);
390
391 /* Split the block in two parts */
392
393 /* The free block that is created has to be at least
394 sizeof(HCELL) + sizeof(HCELL_INDEX) big, so that free
395 cell list code can work. Moreover we round cell sizes
396 to 16 bytes, so creating a smaller block would result in
397 a cell that would never be allocated. */
398 if ((ULONG)FreeCell->Size > Size + 16)
399 {
400 NewCell = (PHCELL)((ULONG_PTR)FreeCell + Size);
401 NewCell->Size = FreeCell->Size - Size;
402 FreeCell->Size = Size;
403 HvpAddFree(RegistryHive, NewCell, FreeCellOffset + Size);
404 if (Storage == Stable)
405 HvMarkCellDirty(RegistryHive, FreeCellOffset + Size, FALSE);
406 }
407
408 if (Storage == Stable)
409 HvMarkCellDirty(RegistryHive, FreeCellOffset, FALSE);
410
411 FreeCell->Size = -FreeCell->Size;
412 RtlZeroMemory(FreeCell + 1, Size - sizeof(HCELL));
413
414 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - CellIndex 0x%x\n",
415 __FUNCTION__, FreeCellOffset);
416
417 return FreeCellOffset;
418 }
419
420 HCELL_INDEX CMAPI
HvReallocateCell(PHHIVE RegistryHive,HCELL_INDEX CellIndex,ULONG Size)421 HvReallocateCell(
422 PHHIVE RegistryHive,
423 HCELL_INDEX CellIndex,
424 ULONG Size)
425 {
426 PVOID OldCell;
427 PVOID NewCell;
428 LONG OldCellSize;
429 HCELL_INDEX NewCellIndex;
430 HSTORAGE_TYPE Storage;
431
432 ASSERT(CellIndex != HCELL_NIL);
433
434 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive 0x%p, CellIndex 0x%x, Size 0x%x\n",
435 __FUNCTION__, RegistryHive, CellIndex, Size);
436
437 Storage = HvGetCellType(CellIndex);
438
439 OldCell = HvGetCell(RegistryHive, CellIndex);
440 OldCellSize = HvGetCellSize(RegistryHive, OldCell);
441 ASSERT(OldCellSize > 0);
442
443 /*
444 * If new data size is larger than the current, destroy current
445 * data block and allocate a new one.
446 *
447 * FIXME: Merge with adjacent free cell if possible.
448 * FIXME: Implement shrinking.
449 */
450 if (Size > (ULONG)OldCellSize)
451 {
452 NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage, HCELL_NIL);
453 if (NewCellIndex == HCELL_NIL)
454 return HCELL_NIL;
455
456 NewCell = HvGetCell(RegistryHive, NewCellIndex);
457 RtlCopyMemory(NewCell, OldCell, (SIZE_T)OldCellSize);
458
459 HvFreeCell(RegistryHive, CellIndex);
460
461 return NewCellIndex;
462 }
463
464 return CellIndex;
465 }
466
467 VOID CMAPI
HvFreeCell(PHHIVE RegistryHive,HCELL_INDEX CellIndex)468 HvFreeCell(
469 PHHIVE RegistryHive,
470 HCELL_INDEX CellIndex)
471 {
472 PHCELL Free;
473 PHCELL Neighbor;
474 PHBIN Bin;
475 ULONG CellType;
476 ULONG CellBlock;
477
478 ASSERT(RegistryHive->ReadOnly == FALSE);
479
480 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive 0x%p, CellIndex 0x%x\n",
481 __FUNCTION__, RegistryHive, CellIndex);
482
483 Free = HvpGetCellHeader(RegistryHive, CellIndex);
484
485 ASSERT(Free->Size < 0);
486
487 Free->Size = -Free->Size;
488
489 CellType = HvGetCellType(CellIndex);
490 CellBlock = HvGetCellBlock(CellIndex);
491
492 /* FIXME: Merge free blocks */
493 Bin = (PHBIN)RegistryHive->Storage[CellType].BlockList[CellBlock].BinAddress;
494
495 if ((CellIndex & ~HCELL_TYPE_MASK) + Free->Size <
496 Bin->FileOffset + Bin->Size)
497 {
498 Neighbor = (PHCELL)((ULONG_PTR)Free + Free->Size);
499 if (Neighbor->Size > 0)
500 {
501 HvpRemoveFree(RegistryHive, Neighbor,
502 ((HCELL_INDEX)((ULONG_PTR)Neighbor - (ULONG_PTR)Bin +
503 Bin->FileOffset)) | (CellIndex & HCELL_TYPE_MASK));
504 Free->Size += Neighbor->Size;
505 }
506 }
507
508 Neighbor = (PHCELL)(Bin + 1);
509 while (Neighbor < Free)
510 {
511 if (Neighbor->Size > 0)
512 {
513 if ((ULONG_PTR)Neighbor + Neighbor->Size == (ULONG_PTR)Free)
514 {
515 HCELL_INDEX NeighborCellIndex =
516 ((HCELL_INDEX)((ULONG_PTR)Neighbor - (ULONG_PTR)Bin +
517 Bin->FileOffset)) | (CellIndex & HCELL_TYPE_MASK);
518
519 if (HvpComputeFreeListIndex(Neighbor->Size) !=
520 HvpComputeFreeListIndex(Neighbor->Size + Free->Size))
521 {
522 HvpRemoveFree(RegistryHive, Neighbor, NeighborCellIndex);
523 Neighbor->Size += Free->Size;
524 HvpAddFree(RegistryHive, Neighbor, NeighborCellIndex);
525 }
526 else
527 Neighbor->Size += Free->Size;
528
529 if (CellType == Stable)
530 HvMarkCellDirty(RegistryHive, NeighborCellIndex, FALSE);
531
532 return;
533 }
534 Neighbor = (PHCELL)((ULONG_PTR)Neighbor + Neighbor->Size);
535 }
536 else
537 {
538 Neighbor = (PHCELL)((ULONG_PTR)Neighbor - Neighbor->Size);
539 }
540 }
541
542 /* Add block to the list of free blocks */
543 HvpAddFree(RegistryHive, Free, CellIndex);
544
545 if (CellType == Stable)
546 HvMarkCellDirty(RegistryHive, CellIndex, FALSE);
547 }
548
549
550 #define CELL_REF_INCREMENT 10
551
552 BOOLEAN
553 CMAPI
HvTrackCellRef(IN OUT PHV_TRACK_CELL_REF CellRef,IN PHHIVE Hive,IN HCELL_INDEX Cell)554 HvTrackCellRef(
555 IN OUT PHV_TRACK_CELL_REF CellRef,
556 IN PHHIVE Hive,
557 IN HCELL_INDEX Cell)
558 {
559 PHV_HIVE_CELL_PAIR NewCellArray;
560
561 PAGED_CODE();
562
563 /* Sanity checks */
564 ASSERT(CellRef);
565 ASSERT(Hive);
566 ASSERT(Cell != HCELL_NIL);
567
568 /* NOTE: The hive cell is already referenced! */
569
570 /* Less than 4? Use the static array */
571 if (CellRef->StaticCount < STATIC_CELL_PAIR_COUNT)
572 {
573 /* Add the reference */
574 CellRef->StaticArray[CellRef->StaticCount].Hive = Hive;
575 CellRef->StaticArray[CellRef->StaticCount].Cell = Cell;
576 CellRef->StaticCount++;
577 return TRUE;
578 }
579
580 DPRINT("HvTrackCellRef: Static array full, use dynamic array.\n");
581
582 /* Sanity checks */
583 if (CellRef->Max == 0)
584 {
585 /* The dynamic array must not have been allocated already */
586 ASSERT(CellRef->CellArray == NULL);
587 ASSERT(CellRef->Count == 0);
588 }
589 else
590 {
591 /* The dynamic array must be allocated */
592 ASSERT(CellRef->CellArray);
593 }
594 ASSERT(CellRef->Count <= CellRef->Max);
595
596 if (CellRef->Count == CellRef->Max)
597 {
598 /* Allocate a new reference table */
599 NewCellArray = CmpAllocate((CellRef->Max + CELL_REF_INCREMENT) * sizeof(HV_HIVE_CELL_PAIR),
600 TRUE,
601 TAG_CM);
602 if (!NewCellArray)
603 {
604 DPRINT1("HvTrackCellRef: Cannot reallocate the reference table.\n");
605 /* We failed, dereference the hive cell */
606 HvReleaseCell(Hive, Cell);
607 return FALSE;
608 }
609
610 /* Free the old reference table and use the new one */
611 if (CellRef->CellArray)
612 {
613 /* Copy the handles from the old table to the new one */
614 RtlCopyMemory(NewCellArray,
615 CellRef->CellArray,
616 CellRef->Max * sizeof(HV_HIVE_CELL_PAIR));
617 CmpFree(CellRef->CellArray, 0); // TAG_CM
618 }
619 CellRef->CellArray = NewCellArray;
620 CellRef->Max += CELL_REF_INCREMENT;
621 }
622
623 // ASSERT(CellRef->Count < CellRef->Max);
624
625 /* Add the reference */
626 CellRef->CellArray[CellRef->Count].Hive = Hive;
627 CellRef->CellArray[CellRef->Count].Cell = Cell;
628 CellRef->Count++;
629 return TRUE;
630 }
631
632 VOID
633 CMAPI
HvReleaseFreeCellRefArray(IN OUT PHV_TRACK_CELL_REF CellRef)634 HvReleaseFreeCellRefArray(
635 IN OUT PHV_TRACK_CELL_REF CellRef)
636 {
637 ULONG i;
638
639 PAGED_CODE();
640
641 ASSERT(CellRef);
642
643 /* Any references in the static array? */
644 if (CellRef->StaticCount > 0)
645 {
646 /* Sanity check */
647 ASSERT(CellRef->StaticCount <= STATIC_CELL_PAIR_COUNT);
648
649 /* Loop over them and release them */
650 for (i = 0; i < CellRef->StaticCount; i++)
651 {
652 HvReleaseCell(CellRef->StaticArray[i].Hive,
653 CellRef->StaticArray[i].Cell);
654 }
655
656 /* We can reuse the static array */
657 CellRef->StaticCount = 0;
658 }
659
660 /* Any references in the dynamic array? */
661 if (CellRef->Count > 0)
662 {
663 /* Sanity checks */
664 ASSERT(CellRef->Count <= CellRef->Max);
665 ASSERT(CellRef->CellArray);
666
667 /* Loop over them and release them */
668 for (i = 0; i < CellRef->Count; i++)
669 {
670 HvReleaseCell(CellRef->CellArray[i].Hive,
671 CellRef->CellArray[i].Cell);
672 }
673
674 /* We can reuse the dynamic array */
675 CmpFree(CellRef->CellArray, 0); // TAG_CM
676 CellRef->CellArray = NULL;
677 CellRef->Count = CellRef->Max = 0;
678 }
679 }
680