10.3.6 bitmap 的作用和分析
在之前我们多次看到了bitmap,但是却一直不知道它是什么,它的作用是干嘛。接下来我们去看,但是具体的bitmap 的实现很复杂,如果没有特殊兴趣的话,可以只看它的接口说明,而不管具体的实现过程。
顾名思义,bitmap就是一个位图。它实际上是一些内存块,这些内存块的每一位用来标识一个磁盘上的最小访问单位,一般情况下是一个扇区。每一位可以被设置或者清除,用来标识这个扇区的两种对应状态。
因为我们要对磁盘进行还原,所以需要将数据存储到其他地方。所以bitmap上的每一位对应一个扇区,有多少个扇区就有多少个位。这个位为0则表示:这个位所对应的扇区的数据没有被存储到其他的地方。这个位为1则表示:这个位对应的扇区的数据被存储到其他地方了。
bitmap的生命周期,为这次保护系统启动直到系统重启。我们在读写数据的时候,根据bitmap的位为0还是1,来判断从哪里读或者写到哪里去。而重启之后,所有的bitmap位都归零,这时无论什么操作都不会到转存处拿数据,也就达到了去保护的功能。
之所以说bitmap是一些内存块而不是一个连续的内存,是因为在涉及bitmap的时候考虑到它所表示的位图可能对应着很大一块磁盘区域,即使是用1位来表示512字节的数据也有可能是很大的一片内存空间。所以在设计bitmap的时候需要按需分配内存。只有在用到的时候才去对应分配,这样就可以达到节约空间的目的。
首先来看bitmap的数据结构。
typedef unsigned char tBitmap;
typedef struct _DP_BITMAP_
{
//这个卷中的每个扇区有多少字节,这同样也说明了bitmap中一个位所对应的字节数
unsigned long sectorSize;
//每个byte里面有几个bit,一般情况下是8
unsigned long byteSize;
//每个块是多大byte,
unsigned long regionSize;
//这个bitmap总共有多少个块
unsigned long regionNumber;
//这个块对应了多少个实际的byte,这个数字应该是sectorSize*byteSize*regionSize
unsigned long regionReferSize;
//这个bitmap对应了多少个实际的byte,这个数字应该是sectorSize*byteSize*regionSize*regionNumber
__int64 bitmapReferSize;
//指向bitmap存储空间的指针
tBitmap** Bitmap;
//用于存取bitmap的锁
void* lockBitmap;
} DP_BITMAP, * PDP_BITMAP;
这里在开头可以看到,将 char 重命名为 tBitmap,然后在最后创建了一个 tBitmap ** Bitmap 的指针元素,实际上等效于 **char ****。这样做,是希望我们将 Bitmap看做一个指针数组。这个数组共有 regionSize个元素,每个元素就是一个指向内存块的指针。这些指针首先指向空的内存块(并不是实际上的,只是指针为空)。看一下初始化bitmap的代码。
NTSTATUS DPBitmapInit(
DP_BITMAP ** bitmap,
unsigned long sectorSize,
unsigned long byteSize,
unsigned long regionSize,
unsigned long regionNumber
)
{
int i = 0;
DP_BITMAP * myBitmap = NULL;
NTSTATUS status = STATUS_SUCCESS;
//检查参数,以免使用了错误的参数导致发生处零错等错误
if (NULL == bitmap || 0 == sectorSize ||
0 == byteSize || 0 == regionSize || 0 == regionNumber)
{
return STATUS_UNSUCCESSFUL;
}
__try
{
//分配一个bitmap结构,这是无论如何都要分配的,这个结构相当于一个bitmap的handle
if (NULL == (myBitmap = (DP_BITMAP*)DPBitmapAlloc(0, sizeof(DP_BITMAP))))
{
status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
//清空结构
memset(myBitmap, 0, sizeof(DP_BITMAP));
//根据参数对结构中的成员进行赋值
myBitmap->sectorSize = sectorSize;
myBitmap->byteSize = byteSize;
myBitmap->regionSize = regionSize;
myBitmap->regionNumber = regionNumber;
myBitmap->regionReferSize = sectorSize * byteSize * regionSize;
myBitmap->bitmapReferSize = (__int64)sectorSize * (__int64)byteSize * (__int64)regionSize * (__int64)regionNumber;
//分配出regionNumber那么多个指向region的指针,这是一个指针数组
if (NULL == (myBitmap->Bitmap = (tBitmap **)DPBitmapAlloc(0, sizeof(tBitmap*) * regionNumber)))
{
status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
//清空指针数组
memset(myBitmap->Bitmap, 0, sizeof(tBitmap*) * regionNumber);
* bitmap = myBitmap;
status = STATUS_SUCCESS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
status = STATUS_UNSUCCESSFUL;
}
if (!NT_SUCCESS(status))
{
if (NULL != myBitmap)
{
DPBitmapFree(myBitmap);
}
* bitmap = NULL;
}
return status;
}
可以看出,这里使用了 DPBitmapAlloc 来分配内存,但是在后续中,使用了许多接口,并且较为复杂,鉴于实际应用性不强,本人目前感觉学习意义不大,所以停止对该章的学习。
明日计划
从明天开始慢慢啃文件系统的过滤与监控吧,似乎还挺有意思的。