Windows檔案系統過濾驅動開發教程 5.綁定FS CDO,檔案系統辨識器,裝置擴充
上一節講到我們打算綁定一個剛剛被啟用的FS CDO.前邊說過簡單的調用wd_dev_attach可以很容易的綁定這個裝置。但是,並不是每次my_fs_notify調用發現有新的fs啟用,我就直接綁定它。
首先判斷是否我需要關心的檔案系統類型。我用下面的函數來擷取裝置類型。
// ------------------wdf.h中的內容-------------------
_inline wd_dev_type wd_dev_get_type(in wd_dev *dev)
{
return dev->DeviceType;
}
檔案系統的CDO的裝置類型有下邊的幾種可能,你的過濾驅動可能只對其中某些感興趣。
enum {
wd_dev_disk_fs = FILE_DEVICE_DISK_FILE_SYSTEM,
wd_dev_cdrom_fs = FILE_DEVICE_CD_ROM_FILE_SYSTEM,
wd_dev_network_fs = FILE_DEVICE_NETWORK_FILE_SYSTEM
};
你應該自己寫一個函數來判斷該fs是否你所關心的。
// -------------一個函數,判斷是否我所關心的fs---------------
wd_bool my_care(wd_ulong type)
{
return (((type) == wd_dev_disk_fs) ||
((type) == wd_dev_cdrom_fs) ||
((type) == wd_dev_network_fs));
}
下一個問題是我打算跳過檔案系統辨識器。檔案系統辨識器是檔案系統驅動的一個很小的替身。為了避免沒有使用到的檔案系統驅動佔據核心記憶體,windows 系統不載入這些大驅動,而代替以該檔案系統驅動對應的檔案系統辨識器。當新的實體儲存體媒介進入系統,io管理器會依次的嘗試各種檔案系統對它進行“識 別”。識別成功,立刻載入真正的檔案系統驅動,對應的檔案系統辨識器則被卸載掉。對我們來說,檔案系統辨識器的控制裝置看起來就像一個檔案系統控制裝置。 但我們不打算綁定它。
分辨的方法是通過驅動的名字。凡是檔案系統辨識器的驅動對象的名字(注意是DriverObject而不是DeviceObject!)都為“\FileSystem\Fs_Rec”.
//-------------------用這些代碼來跳過檔案系統辨識器----------------------
wd_wchar name_buf[wd_dev_name_max_len];
wd_ustr name,tmp;
wd_ustr_init_em(&name,name_buf,wd_dev_name_max_len);
wd_ustr_init(&tmp,L"\\FileSystem\\Fs_Rec");
// 我不綁定辨識器。所以如果是辨識器,我直接返回成功。查看是否是識別
// 器的辦法是看是否是\FileSystem\Fs_Rec的裝置。
wd_obj_get_name(wd_dev_drv(fs_dev),&name);
if(wd_ustr_cmp(&name,&tmp,wd_true) == 0)
{
wd_printf0("attach fs dev:is a recogonizer.\r\n");
return wd_stat_suc;
}
wd_printf0("attach fs dev: not a recogonizer.\r\n");
接下來我將要產生我的裝置。這裡要提到裝置擴充的概念。裝置對象是一個資料結構,為了表示不同的裝置,裡邊將有一片自訂的空間,用來給你記錄這個裝置的特有資訊。我們為我們所產生的裝置確定裝置擴充如下:
// 檔案過濾系統驅動的裝置擴充
typedef struct _my_dev_ext
{
// 我們綁定的檔案系統驅動
wd_dev * attached_to;
// 上邊這個裝置的裝置名稱。
wd_ustr dev_name;
// 這是上邊的unicode字串的緩衝區
wd_wchar name_buf[wd_dev_name_max_len];
} my_dev_ext;
之所以如此簡單,是因為我們現在還沒有多少東西要記錄。只要記得自己綁定在哪個裝置上就好了。如果以後需要更多的資訊,再增加不遲。擴充空間的大小是在 wdf_dev_create(也就是這個裝置產生)的時候指定的。得到裝置對象指標後,我用下面這個函數來擷取裝置擴充指標:
// --------------wdf.h中的內容------------------
_inline wd_void * wd_dev_ext(wd_dev *dev)
{
return (dev->DeviceExtension);
}
產生裝置後,為了讓系統看起來,你的裝置和原來的裝置沒什麼區別,你必須設定一些該裝置的標誌位與你所連結的裝置相同。
_inline wd_void wd_dev_copy_flag(wd_dev *new_dev,
wd_dev *old_dev)
{
if(old_dev->Flags & DO_BUFFERED_IO)
new_dev->Flags &= DO_BUFFERED_IO;
if(old_dev->Flags & DO_DIRECT_IO)
new_dev->Flags &= DO_DIRECT_IO;
if (old_dev->Characteristics & FILE_DEVICE_SECURE_OPEN)
new_dev->Characteristics &= FILE_DEVICE_SECURE_OPEN;
}
DO_BUFFERED_IO,DO_DIRECT_IO這兩個標誌的意義在於外部向這些裝置發送讀寫請求的時候,所用的緩衝地址將有所不同。這點以後在 過濾檔案讀寫的時候再討論。現在一切事情都搞完,你應該去掉你的新裝置上的DO_DEVICE_INITIALIZING標誌,以表明的的裝置已經完全可 以用了。
// --------------wdf.h中的內容------------------
_inline wd_void wd_dev_clr_init_flag(wd_dev *dev)
{
dev->Flags &= ~DO_DEVICE_INITIALIZING;
}
現在我寫一個函數來完成以上的這個過程。你只要在上一節中提示的位置調用這個函數,就完成對檔案系統控制裝置的綁定了。
//-----------綁定一個檔案系統驅動裝置-------------------------
wd_stat my_attach_fs_dev(wd_dev *fs_dev)
{
wd_wchar name_buf[wd_dev_name_max_len];
wd_ustr name,tmp;
wd_dev *new_dev;
wd_stat status;
my_dev_ext *ext;
wd_ustr_init_em(&name,name_buf,wd_dev_name_max_len);
wd_ustr_init(&tmp,L"\\FileSystem\\Fs_Rec");
// 如果不是我關心的類型,我直接返回成功
if(!my_care(wd_dev_get_type(fs_dev)))
{
wd_printf0(("attach fs dev:not a cared type.\r\n"));
return wd_stat_suc;
}
wd_printf0("attach fs dev: is my cared type.\r\n");
// 我不綁定辨識器。所以如果是辨識器,我直接返回成功。查看是否是識別
// 器的辦法是看是否是\FileSystem\Fs_Rec的裝置。
wd_obj_get_name(wd_dev_drv(fs_dev),&name);
if(wd_ustr_cmp(&name,&tmp,wd_true) == 0)
{
wd_printf0("attach fs dev:is a recogonizer.\r\n");
return wd_stat_suc;
}
wd_printf0("attach fs dev: not a recogonizer.\r\n");
// 現在來產生一個裝置用來綁定
status = wd_dev_create(g_drv,sizeof(my_dev_ext),NULL,
wd_dev_get_type(fs_dev),
0,wd_false,&new_dev);
if(!wd_suc(status))
{
wd_printf0("attach fs dev: dev create failed.\r\n");
return status;
}
wd_printf0("attach fs dev: create dev success.\r\n");
// 接著設定裝置的各種標誌與之要綁定的標誌一致
wd_dev_copy_flag(new_dev,fs_dev);
ext = (my_dev_ext *)wd_dev_ext(new_dev);
wd_printf0("begin to attach.\r\n");
status = wd_dev_attach(new_dev,fs_dev,&ext->attached_to);
wd_printf0("attach over.status = %8x\r\n",status);
if(!wd_suc(status))
{
wd_printf0("attach fs dev: dev attach failed.\r\n");
UNREFERENCED_PARAMETER(new_dev);
wd_dev_del(new_dev);
return status;
}
wd_printf0("attach fs dev: attach %wZ succeed.\r\n",&name);
wd_ustr_init_em(&ext->dev_name,ext->name_buf,wd_dev_name_max_len);
wd_ustr_copy(&ext->dev_name,&name);
wd_dev_clr_init_flag(new_dev);
return status;
}