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 來分配內存,但是在後續中,使用了許多接口,並且較爲複雜,鑑於實際應用性不強,本人目前感覺學習意義不大,所以停止對該章的學習。
明日計劃
從明天開始慢慢啃文件系統的過濾與監控吧,似乎還挺有意思的。