Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhivecell.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: registry manipulation library 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * COPYRIGHT: Copyright 2005 Filip Navara <navaraf@reactos.org> 00005 * Copyright 2001 - 2005 Eric Kohl 00006 */ 00007 00008 #include "cmlib.h" 00009 #define NDEBUG 00010 #include <debug.h> 00011 00012 static __inline PHCELL CMAPI 00013 HvpGetCellHeader( 00014 PHHIVE RegistryHive, 00015 HCELL_INDEX CellIndex) 00016 { 00017 PVOID Block; 00018 00019 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx\n", 00020 __FUNCTION__, RegistryHive, CellIndex); 00021 00022 ASSERT(CellIndex != HCELL_NIL); 00023 if (!RegistryHive->Flat) 00024 { 00025 ULONG CellType; 00026 ULONG CellBlock; 00027 ULONG CellOffset; 00028 00029 CellType = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT; 00030 CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT; 00031 CellOffset = (CellIndex & HCELL_OFFSET_MASK) >> HCELL_OFFSET_SHIFT; 00032 ASSERT(CellBlock < RegistryHive->Storage[CellType].Length); 00033 Block = (PVOID)RegistryHive->Storage[CellType].BlockList[CellBlock].BlockAddress; 00034 ASSERT(Block != NULL); 00035 return (PVOID)((ULONG_PTR)Block + CellOffset); 00036 } 00037 else 00038 { 00039 ASSERT((CellIndex & HCELL_TYPE_MASK) == Stable); 00040 return (PVOID)((ULONG_PTR)RegistryHive->BaseBlock + HV_BLOCK_SIZE + 00041 CellIndex); 00042 } 00043 } 00044 00045 BOOLEAN CMAPI 00046 HvIsCellAllocated(IN PHHIVE RegistryHive, 00047 IN HCELL_INDEX CellIndex) 00048 { 00049 ULONG Type, Block; 00050 00051 /* If it's a flat hive, the cell is always allocated */ 00052 if (RegistryHive->Flat) 00053 return TRUE; 00054 00055 /* Otherwise, get the type and make sure it's valid */ 00056 Type = HvGetCellType(CellIndex); 00057 Block = HvGetCellBlock(CellIndex); 00058 if (Block >= RegistryHive->Storage[Type].Length) 00059 return FALSE; 00060 00061 /* Try to get the cell block */ 00062 if (RegistryHive->Storage[Type].BlockList[Block].BlockAddress) 00063 return TRUE; 00064 00065 /* No valid block, fail */ 00066 return FALSE; 00067 } 00068 00069 PVOID CMAPI 00070 HvGetCell( 00071 PHHIVE RegistryHive, 00072 HCELL_INDEX CellIndex) 00073 { 00074 return (PVOID)(HvpGetCellHeader(RegistryHive, CellIndex) + 1); 00075 } 00076 00077 static __inline LONG CMAPI 00078 HvpGetCellFullSize( 00079 PHHIVE RegistryHive, 00080 PVOID Cell) 00081 { 00082 UNREFERENCED_PARAMETER(RegistryHive); 00083 return ((PHCELL)Cell - 1)->Size; 00084 } 00085 00086 LONG CMAPI 00087 HvGetCellSize(IN PHHIVE Hive, 00088 IN PVOID Address) 00089 { 00090 PHCELL CellHeader; 00091 LONG Size; 00092 00093 UNREFERENCED_PARAMETER(Hive); 00094 00095 CellHeader = (PHCELL)Address - 1; 00096 Size = CellHeader->Size * -1; 00097 Size -= sizeof(HCELL); 00098 return Size; 00099 } 00100 00101 BOOLEAN CMAPI 00102 HvMarkCellDirty( 00103 PHHIVE RegistryHive, 00104 HCELL_INDEX CellIndex, 00105 BOOLEAN HoldingLock) 00106 { 00107 ULONG CellBlock; 00108 ULONG CellLastBlock; 00109 00110 ASSERT(RegistryHive->ReadOnly == FALSE); 00111 00112 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx, HoldingLock %b\n", 00113 __FUNCTION__, RegistryHive, CellIndex, HoldingLock); 00114 00115 if ((CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT != Stable) 00116 return TRUE; 00117 00118 CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT; 00119 CellLastBlock = ((CellIndex + HV_BLOCK_SIZE - 1) & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT; 00120 00121 RtlSetBits(&RegistryHive->DirtyVector, 00122 CellBlock, CellLastBlock - CellBlock); 00123 return TRUE; 00124 } 00125 00126 BOOLEAN CMAPI 00127 HvIsCellDirty(IN PHHIVE Hive, 00128 IN HCELL_INDEX Cell) 00129 { 00130 BOOLEAN IsDirty = FALSE; 00131 00132 /* Sanity checks */ 00133 ASSERT(Hive->ReadOnly == FALSE); 00134 00135 /* Volatile cells are always "dirty" */ 00136 if (HvGetCellType(Cell) == Volatile) 00137 return TRUE; 00138 00139 /* Check if the dirty bit is set */ 00140 if (RtlCheckBit(&Hive->DirtyVector, Cell / HV_BLOCK_SIZE)) 00141 IsDirty = TRUE; 00142 00143 /* Return result as boolean*/ 00144 return IsDirty; 00145 } 00146 00147 static __inline ULONG CMAPI 00148 HvpComputeFreeListIndex( 00149 ULONG Size) 00150 { 00151 ULONG Index; 00152 static CCHAR FindFirstSet[256] = { 00153 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 00154 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 00155 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 00156 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 00157 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 00158 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 00159 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 00160 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 00161 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 00162 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 00163 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 00164 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 00165 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 00166 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 00167 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 00168 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; 00169 00170 Index = (Size >> 3) - 1; 00171 if (Index >= 16) 00172 { 00173 if (Index > 255) 00174 Index = 23; 00175 else 00176 Index = FindFirstSet[Index] + 7; 00177 } 00178 00179 return Index; 00180 } 00181 00182 static NTSTATUS CMAPI 00183 HvpAddFree( 00184 PHHIVE RegistryHive, 00185 PHCELL FreeBlock, 00186 HCELL_INDEX FreeIndex) 00187 { 00188 PHCELL_INDEX FreeBlockData; 00189 HSTORAGE_TYPE Storage; 00190 ULONG Index; 00191 00192 ASSERT(RegistryHive != NULL); 00193 ASSERT(FreeBlock != NULL); 00194 00195 Storage = (FreeIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT; 00196 Index = HvpComputeFreeListIndex((ULONG)FreeBlock->Size); 00197 00198 FreeBlockData = (PHCELL_INDEX)(FreeBlock + 1); 00199 *FreeBlockData = RegistryHive->Storage[Storage].FreeDisplay[Index]; 00200 RegistryHive->Storage[Storage].FreeDisplay[Index] = FreeIndex; 00201 00202 /* FIXME: Eventually get rid of free bins. */ 00203 00204 return STATUS_SUCCESS; 00205 } 00206 00207 static VOID CMAPI 00208 HvpRemoveFree( 00209 PHHIVE RegistryHive, 00210 PHCELL CellBlock, 00211 HCELL_INDEX CellIndex) 00212 { 00213 PHCELL_INDEX FreeCellData; 00214 PHCELL_INDEX pFreeCellOffset; 00215 HSTORAGE_TYPE Storage; 00216 ULONG Index, FreeListIndex; 00217 00218 ASSERT(RegistryHive->ReadOnly == FALSE); 00219 00220 Storage = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT; 00221 Index = HvpComputeFreeListIndex((ULONG)CellBlock->Size); 00222 00223 pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index]; 00224 while (*pFreeCellOffset != HCELL_NIL) 00225 { 00226 FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset); 00227 if (*pFreeCellOffset == CellIndex) 00228 { 00229 *pFreeCellOffset = *FreeCellData; 00230 return; 00231 } 00232 pFreeCellOffset = FreeCellData; 00233 } 00234 00235 /* Something bad happened, print a useful trace info and bugcheck */ 00236 CMLTRACE(CMLIB_HCELL_DEBUG, "-- beginning of HvpRemoveFree trace --\n"); 00237 CMLTRACE(CMLIB_HCELL_DEBUG, "block we are about to free: %08x\n", CellIndex); 00238 CMLTRACE(CMLIB_HCELL_DEBUG, "chosen free list index: %d\n", Index); 00239 for (FreeListIndex = 0; FreeListIndex < 24; FreeListIndex++) 00240 { 00241 CMLTRACE(CMLIB_HCELL_DEBUG, "free list [%d]: ", FreeListIndex); 00242 pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[FreeListIndex]; 00243 while (*pFreeCellOffset != HCELL_NIL) 00244 { 00245 CMLTRACE(CMLIB_HCELL_DEBUG, "%08x ", *pFreeCellOffset); 00246 FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset); 00247 pFreeCellOffset = FreeCellData; 00248 } 00249 CMLTRACE(CMLIB_HCELL_DEBUG, "\n"); 00250 } 00251 CMLTRACE(CMLIB_HCELL_DEBUG, "-- end of HvpRemoveFree trace --\n"); 00252 00253 ASSERT(FALSE); 00254 } 00255 00256 static HCELL_INDEX CMAPI 00257 HvpFindFree( 00258 PHHIVE RegistryHive, 00259 ULONG Size, 00260 HSTORAGE_TYPE Storage) 00261 { 00262 PHCELL_INDEX FreeCellData; 00263 HCELL_INDEX FreeCellOffset; 00264 PHCELL_INDEX pFreeCellOffset; 00265 ULONG Index; 00266 00267 for (Index = HvpComputeFreeListIndex(Size); Index < 24; Index++) 00268 { 00269 pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index]; 00270 while (*pFreeCellOffset != HCELL_NIL) 00271 { 00272 FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset); 00273 if ((ULONG)HvpGetCellFullSize(RegistryHive, FreeCellData) >= Size) 00274 { 00275 FreeCellOffset = *pFreeCellOffset; 00276 *pFreeCellOffset = *FreeCellData; 00277 return FreeCellOffset; 00278 } 00279 pFreeCellOffset = FreeCellData; 00280 } 00281 } 00282 00283 return HCELL_NIL; 00284 } 00285 00286 NTSTATUS CMAPI 00287 HvpCreateHiveFreeCellList( 00288 PHHIVE Hive) 00289 { 00290 HCELL_INDEX BlockOffset; 00291 PHCELL FreeBlock; 00292 ULONG BlockIndex; 00293 ULONG FreeOffset; 00294 PHBIN Bin; 00295 NTSTATUS Status; 00296 ULONG Index; 00297 00298 /* Initialize the free cell list */ 00299 for (Index = 0; Index < 24; Index++) 00300 { 00301 Hive->Storage[Stable].FreeDisplay[Index] = HCELL_NIL; 00302 Hive->Storage[Volatile].FreeDisplay[Index] = HCELL_NIL; 00303 } 00304 00305 BlockOffset = 0; 00306 BlockIndex = 0; 00307 while (BlockIndex < Hive->Storage[Stable].Length) 00308 { 00309 Bin = (PHBIN)Hive->Storage[Stable].BlockList[BlockIndex].BinAddress; 00310 00311 /* Search free blocks and add to list */ 00312 FreeOffset = sizeof(HBIN); 00313 while (FreeOffset < Bin->Size) 00314 { 00315 FreeBlock = (PHCELL)((ULONG_PTR)Bin + FreeOffset); 00316 if (FreeBlock->Size > 0) 00317 { 00318 Status = HvpAddFree(Hive, FreeBlock, Bin->FileOffset + FreeOffset); 00319 if (!NT_SUCCESS(Status)) 00320 return Status; 00321 00322 FreeOffset += FreeBlock->Size; 00323 } 00324 else 00325 { 00326 FreeOffset -= FreeBlock->Size; 00327 } 00328 } 00329 00330 BlockIndex += Bin->Size / HV_BLOCK_SIZE; 00331 BlockOffset += Bin->Size; 00332 } 00333 00334 return STATUS_SUCCESS; 00335 } 00336 00337 HCELL_INDEX CMAPI 00338 HvAllocateCell( 00339 PHHIVE RegistryHive, 00340 ULONG Size, 00341 HSTORAGE_TYPE Storage, 00342 HCELL_INDEX Vicinity) 00343 { 00344 PHCELL FreeCell; 00345 HCELL_INDEX FreeCellOffset; 00346 PHCELL NewCell; 00347 PHBIN Bin; 00348 00349 ASSERT(RegistryHive->ReadOnly == FALSE); 00350 00351 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, Size %x, %s, Vicinity %08lx\n", 00352 __FUNCTION__, RegistryHive, Size, (Storage == 0) ? "Stable" : "Volatile", Vicinity); 00353 00354 /* Round to 16 bytes multiple. */ 00355 Size = ROUND_UP(Size + sizeof(HCELL), 16); 00356 00357 /* First search in free blocks. */ 00358 FreeCellOffset = HvpFindFree(RegistryHive, Size, Storage); 00359 00360 /* If no free cell was found we need to extend the hive file. */ 00361 if (FreeCellOffset == HCELL_NIL) 00362 { 00363 Bin = HvpAddBin(RegistryHive, Size, Storage); 00364 if (Bin == NULL) 00365 return HCELL_NIL; 00366 FreeCellOffset = Bin->FileOffset + sizeof(HBIN); 00367 FreeCellOffset |= Storage << HCELL_TYPE_SHIFT; 00368 } 00369 00370 FreeCell = HvpGetCellHeader(RegistryHive, FreeCellOffset); 00371 00372 /* Split the block in two parts */ 00373 00374 /* The free block that is created has to be at least 00375 sizeof(HCELL) + sizeof(HCELL_INDEX) big, so that free 00376 cell list code can work. Moreover we round cell sizes 00377 to 16 bytes, so creating a smaller block would result in 00378 a cell that would never be allocated. */ 00379 if ((ULONG)FreeCell->Size > Size + 16) 00380 { 00381 NewCell = (PHCELL)((ULONG_PTR)FreeCell + Size); 00382 NewCell->Size = FreeCell->Size - Size; 00383 FreeCell->Size = Size; 00384 HvpAddFree(RegistryHive, NewCell, FreeCellOffset + Size); 00385 if (Storage == Stable) 00386 HvMarkCellDirty(RegistryHive, FreeCellOffset + Size, FALSE); 00387 } 00388 00389 if (Storage == Stable) 00390 HvMarkCellDirty(RegistryHive, FreeCellOffset, FALSE); 00391 FreeCell->Size = -FreeCell->Size; 00392 RtlZeroMemory(FreeCell + 1, Size - sizeof(HCELL)); 00393 00394 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - CellIndex %08lx\n", 00395 __FUNCTION__, FreeCellOffset); 00396 00397 return FreeCellOffset; 00398 } 00399 00400 HCELL_INDEX CMAPI 00401 HvReallocateCell( 00402 PHHIVE RegistryHive, 00403 HCELL_INDEX CellIndex, 00404 ULONG Size) 00405 { 00406 PVOID OldCell; 00407 PVOID NewCell; 00408 LONG OldCellSize; 00409 HCELL_INDEX NewCellIndex; 00410 HSTORAGE_TYPE Storage; 00411 00412 ASSERT(CellIndex != HCELL_NIL); 00413 00414 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx, Size %x\n", 00415 __FUNCTION__, RegistryHive, CellIndex, Size); 00416 00417 Storage = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT; 00418 00419 OldCell = HvGetCell(RegistryHive, CellIndex); 00420 OldCellSize = HvGetCellSize(RegistryHive, OldCell); 00421 ASSERT(OldCellSize > 0); 00422 00423 /* 00424 * If new data size is larger than the current, destroy current 00425 * data block and allocate a new one. 00426 * 00427 * FIXME: Merge with adjacent free cell if possible. 00428 * FIXME: Implement shrinking. 00429 */ 00430 if (Size > (ULONG)OldCellSize) 00431 { 00432 NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage, HCELL_NIL); 00433 if (NewCellIndex == HCELL_NIL) 00434 return HCELL_NIL; 00435 00436 NewCell = HvGetCell(RegistryHive, NewCellIndex); 00437 RtlCopyMemory(NewCell, OldCell, (SIZE_T)OldCellSize); 00438 00439 HvFreeCell(RegistryHive, CellIndex); 00440 00441 return NewCellIndex; 00442 } 00443 00444 return CellIndex; 00445 } 00446 00447 VOID CMAPI 00448 HvFreeCell( 00449 PHHIVE RegistryHive, 00450 HCELL_INDEX CellIndex) 00451 { 00452 PHCELL Free; 00453 PHCELL Neighbor; 00454 PHBIN Bin; 00455 ULONG CellType; 00456 ULONG CellBlock; 00457 00458 ASSERT(RegistryHive->ReadOnly == FALSE); 00459 00460 CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx\n", 00461 __FUNCTION__, RegistryHive, CellIndex); 00462 00463 Free = HvpGetCellHeader(RegistryHive, CellIndex); 00464 00465 ASSERT(Free->Size < 0); 00466 00467 Free->Size = -Free->Size; 00468 00469 CellType = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT; 00470 CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT; 00471 00472 /* FIXME: Merge free blocks */ 00473 Bin = (PHBIN)RegistryHive->Storage[CellType].BlockList[CellBlock].BinAddress; 00474 00475 if ((CellIndex & ~HCELL_TYPE_MASK) + Free->Size < 00476 Bin->FileOffset + Bin->Size) 00477 { 00478 Neighbor = (PHCELL)((ULONG_PTR)Free + Free->Size); 00479 if (Neighbor->Size > 0) 00480 { 00481 HvpRemoveFree(RegistryHive, Neighbor, 00482 ((HCELL_INDEX)((ULONG_PTR)Neighbor - (ULONG_PTR)Bin + 00483 Bin->FileOffset)) | (CellIndex & HCELL_TYPE_MASK)); 00484 Free->Size += Neighbor->Size; 00485 } 00486 } 00487 00488 Neighbor = (PHCELL)(Bin + 1); 00489 while (Neighbor < Free) 00490 { 00491 if (Neighbor->Size > 0) 00492 { 00493 if ((ULONG_PTR)Neighbor + Neighbor->Size == (ULONG_PTR)Free) 00494 { 00495 HCELL_INDEX NeighborCellIndex = 00496 (HCELL_INDEX)((ULONG_PTR)Neighbor - (ULONG_PTR)Bin + 00497 Bin->FileOffset) | (CellIndex & HCELL_TYPE_MASK); 00498 00499 if (HvpComputeFreeListIndex(Neighbor->Size) != 00500 HvpComputeFreeListIndex(Neighbor->Size + Free->Size)) 00501 { 00502 HvpRemoveFree(RegistryHive, Neighbor, NeighborCellIndex); 00503 Neighbor->Size += Free->Size; 00504 HvpAddFree(RegistryHive, Neighbor, NeighborCellIndex); 00505 } 00506 else 00507 Neighbor->Size += Free->Size; 00508 00509 if (CellType == Stable) 00510 HvMarkCellDirty(RegistryHive, NeighborCellIndex, FALSE); 00511 00512 return; 00513 } 00514 Neighbor = (PHCELL)((ULONG_PTR)Neighbor + Neighbor->Size); 00515 } 00516 else 00517 { 00518 Neighbor = (PHCELL)((ULONG_PTR)Neighbor - Neighbor->Size); 00519 } 00520 } 00521 00522 /* Add block to the list of free blocks */ 00523 HvpAddFree(RegistryHive, Free, CellIndex); 00524 00525 if (CellType == Stable) 00526 HvMarkCellDirty(RegistryHive, CellIndex, FALSE); 00527 } 00528 00529 BOOLEAN 00530 CMAPI 00531 HvTrackCellRef(PHV_TRACK_CELL_REF CellRef, 00532 PHHIVE Hive, 00533 HCELL_INDEX Cell) 00534 { 00535 /* Sanity checks */ 00536 ASSERT(CellRef); 00537 ASSERT(Hive ); 00538 ASSERT(Cell != HCELL_NIL); 00539 00540 /* Less than 4? */ 00541 if (CellRef->StaticCount < STATIC_CELL_PAIR_COUNT) 00542 { 00543 /* Add reference */ 00544 CellRef->StaticArray[CellRef->StaticCount].Hive = Hive; 00545 CellRef->StaticArray[CellRef->StaticCount].Cell = Cell; 00546 CellRef->StaticCount++; 00547 return TRUE; 00548 } 00549 00550 /* FIXME: TODO */ 00551 DPRINT1("ERROR: Too many references\n"); 00552 while (TRUE); 00553 return FALSE; 00554 } 00555 00556 VOID 00557 CMAPI 00558 HvReleaseFreeCellRefArray(PHV_TRACK_CELL_REF CellRef) 00559 { 00560 ULONG i; 00561 ASSERT(CellRef); 00562 00563 /* Any references? */ 00564 if (CellRef->StaticCount > 0) 00565 { 00566 /* Sanity check */ 00567 ASSERT(CellRef->StaticCount <= STATIC_CELL_PAIR_COUNT); 00568 00569 /* Loop them */ 00570 for (i = 0; i < CellRef->StaticCount;i++) 00571 { 00572 /* Release them */ 00573 HvReleaseCell(CellRef->StaticArray[i].Hive, 00574 CellRef->StaticArray[i].Cell); 00575 } 00576 00577 /* Free again */ 00578 CellRef->StaticCount = 0; 00579 } 00580 } Generated on Sat May 26 2012 04:34:52 for ReactOS by
1.7.6.1
|