首先是从空闲CELL中分配一个指定大小的CELL。HvAllocateCell就是做这件事情的。
这个函数有四个参数:
1. RegistryHive HHIVE结构指针
2. Size 需要分配的CELL大小(不包括HCELL结构的大小)
3. Storage 分配的CELL是Stable还是Volatile。
4. Vicinity 这个参数在Freeldr中没有使用
lib/cmlib/hivecell.c
- HCELL_INDEXCMAPIHvAllocateCell(PHHIVERegistryHive,SIZE_TSize,HSTORAGE_TYpestorage,HCELL_INDEXVicinity)
- {
- PHCELLFreeCell;
- HCELL_INDEXFreeCellOffset;
- PHCELLNewCell;
- PHBINBin;
- /*加上HCELL的大小并且按16位向上对齐*/
- Size=ROUND_UP(Size+sizeof(HCELL),16);
- /*从Freedisplay中找到Size大小的空闲CELL,FreeCellOffset是CELL的索引*/
- FreeCellOffset=HvpFindFree(RegistryHive,Size,Storage);
- /*如果没有符合的CELL,需要在末尾增加一个BIN,从新的BIN中分配需要的CELL,FreeCellOffset是CELL索引*/
- if(FreeCellOffset==HCELL_NIL)
- {
- Bin=HvpAddBin(RegistryHive,Storage);
- if(Bin==NULL)
- returnHCELL_NIL;
- FreeCellOffset=Bin->FileOffset+sizeof(HBIN);
- FreeCellOffset|=Storage<<HCELL_TYPE_SHIFT;
- }
- /*根据索引获得HCELL结构*/
- FreeCell=HvpGetCellHeader(RegistryHive,FreeCellOffset);
- /*分配的CELL有可能大于用户请求的长度,如果大于Size+16那么将CELL分解成两个。剩余的空间重新加入Freedisplay中*/
- if((ULONG)FreeCell->Size>Size+16)
- {
- NewCell=(PHCELL)((ULONG_PTR)FreeCell+Size);
- NewCell->Size=FreeCell->Size-Size;
- FreeCell->Size=Size;
- HvpAddFree(RegistryHive,NewCell,FreeCellOffset+Size);
- if(Storage==Stable)
- HvMarkCellDirty(RegistryHive,FreeCellOffset+Size,FALSE);
- }
- /*如果CELL类型是非易失的,需要将对应的DirtyVector置位,这样新增内容最终会被刷新到硬盘*/
- if(Storage==Stable)
- HvMarkCellDirty(RegistryHive,FreeCellOffset,FALSE);
- /*把这个CELL标记成已使用(大小为负)*/
- FreeCell->Size=-FreeCell->Size;
- RtlZeroMemory(FreeCell+1,Size-sizeof(HCELL));
- returnFreeCellOffset;
- }
因为调用者传入的Size不包含HCELL的大小,8行先调整大小并且向上按8字节对其。
因为返回的CELL可能比请求的大,所以21行调用HvpGetCellHeader根据索引获得HCELL指针,如果返回的CELL比请求的大小大16字节以上的话则把CELL分配成两个,剩余的空间重新加入空闲列表Freedisplay(23-31)。
最后如果Storage为Stable时,说明这些信息最终要写入硬盘的HIVE文件,所以要把CELL所在Block的DirtyVetor置位,这样注册表刷新文件时会把这个改变回写到硬盘的HIVE文件中。(33-34)
从Freedisplay中寻找空闲块是HvpFindFree的工作。
这个函数接受大小Size和存储类型Storage,返回找到的CELL的索引,如果没找到返回HCELL_NIL。
HvAllocateCell ->HvpFindFree
lib/cmlib/hivecell.c
- staticHCELL_INDEXCMAPIHvpFindFree(PHHIVERegistryHive,ULONGSize,HSTORAGE_TYpestorage)
- {
- PHCELL_INDEXFreeCellData;
- HCELL_INDEXFreeCellOffset;
- PHCELL_INDEXpFreeCellOffset;
- ULONGIndex;
- /*从Index开始递增搜索比Size大的CELL*/
- for(Index=HvpComputeFreeListIndex(Size);Index<24;Index++)
- {
- pFreeCellOffset=&RegistryHive->Storage[Storage].Freedisplay[Index];
- while(*pFreeCellOffset!=HCELL_NIL)
- {
- /*根据CELL的索引获得HCELL结构*/
- FreeCellData=(PHCELL_INDEX)HvGetCell(RegistryHive,*pFreeCellOffset);
- /*找到了比Size大的CELL,从空闲链里摘除,并返回给用户*/
- if((ULONG)HvpGetCellFullSize(RegistryHive,FreeCellData)>=Size)
- {
- FreeCellOffset=*pFreeCellOffset;
- *pFreeCellOffset=*FreeCellData;
- returnFreeCellOffset;
- }
- pFreeCellOffset=FreeCellData;
- }
- }
- returnHCELL_NIL;
- }
HvAllocateCell ->HvpFindFree ->HvpFindFree
lib/cmlib/hivecell.c
- PVOIDCMAPIHvGetCell(PHHIVERegistryHive,HCELL_INDEXCellIndex)
- {/*HvpGetCellHeader获得HCELL结构,紧跟着HCELL就是CELL内容,返回给用户*/
- return(PVOID)(HvpGetCellHeader(RegistryHive,CellIndex)+1);
- }
HvAllocateCell ->HvpFindFree ->HvpFindFree -> HvpGetCellHeader
lib/cmlib/hivecell.c
- static__inlinePHCELLCMAPIHvpGetCellHeader(PHHIVERegistryHive,HCELL_INDEXCellIndex)
- {
- PVOIDBlock;
- if(!RegistryHive->Flat)
- {
- ULONGCellType;
- ULONGCellBlock;
- ULONGCellOffset;
- CellType=(CellIndex&HCELL_TYPE_MASK)>>HCELL_TYPE_SHIFT;//最高位是CellType(Stable或Volatile)
- CellBlock=(CellIndex&HCELL_BLOCK_MASK)>>HCELL_BLOCK_SHIFT;//Block是4kb,提取出Block的序号
- CellOffset=(CellIndex&HCELL_OFFSET_MASK)>>HCELL_OFFSET_SHIFT;//CELL在Block内的偏移
- //查询对应的BlockList表得到CELL地址
- Block=(PVOID)RegistryHive->Storage[CellType].BlockList[CellBlock].BlockAddress;
- return(PVOID)((ULONG_PTR)Block+CellOffset);
- }
- else
- {
- /*如果HIVE是以Flat模式打开的,将没有意义BlockList。同事BaseBlock指向的内容就是读出的HIVE文件本身。
- 这种模式只能读不能写。*/
- return(PVOID)((ULONG_PTR)RegistryHive->BaseBlock+HV_BLOCK_SIZE+
- CellIndex);
- }
- }
正常情况下Flat为FALSE,所以HvpGetCellHeader将把CellIndex分解为存储类型CellType、CELL所在块编号CellBlock、CELL在块内偏移CellOffset(6-11行)。
这里有个特殊情况,就是HIVE可以以Flat模式初始化。这个模式下HIVE只读,并且没有初始化Storage数组,同事HHIVE.BaseBlock指针直接指向HIVE文件内容,20行处理了这种情况。
到这里我们了解了HvpFindFree、HvGetCell、HvpGetCellHeader三个函数的作用。