Windows檔案系統過濾驅動開發教程(4)

來源:互聯網
上載者:User
Windows檔案系統過濾驅動開發教程 4.裝置棧,過濾,檔案系統的感知

前邊都在介紹檔案系統驅動的結構,卻還沒講到我們的過濾驅動如何能捕獲所有發給檔案系統驅動的irp,讓我們自己來處理?前面已經解釋過了裝置對象。現在來解釋一下裝置棧。

任何裝置對象都存在於某個裝置棧中。裝置棧自然是一組裝置對象。這些裝置對象是互相關聯的,也就是說,如果得到一個DO指標,你就可以知道它所處的裝置棧。

任何來自應用的請求,最終被windows io mgr翻譯成irp的,總是發送給裝置棧的頂端那個裝置。

原始irp irp irp irp
--------------> ------> -------> ----->
DevTop Dev2 ... DevVolumne ... ???
<-------------- <------ <------- <-----
原始irp(返回) irp irp irp

向右的箭頭表示irp請求的發送過程,向左則是返回。可見irp是從裝置棧的頂端開始,逐步向下發送。DevVolumue表示我們實際要過濾的 Volume裝置,DevTop表示這個裝置棧的頂端。我們只要在這個裝置棧的頂端再綁定一個裝置,那發送給Volume的請求,自然會先發給我們的裝置 來處理。

有一個系統調用可以把我們的裝置綁定到某個裝置的裝置棧的頂端。這個調用是IoAttachDeviceToDeviceStack,這個調用2000以 及以上系統都可以用(所以說到這點,是因為還有一個IoAttachDeviceToDeviceStackSafe,是2000所沒有的。這常常導致你 的filter在2000下不能用。)

我自己寫了一個函數來幫我實現綁定功能:

//----------------------wdf.h中的內容----------------------------------
// 這個常式把源裝置綁定到目標裝置的裝置棧中去,並返回源裝置所直
// 接連結的裝置。注意源裝置未必直接綁定在目標裝置上。它應綁定在
// 目標裝置的裝置棧的頂端。
_inline wd_stat wd_dev_attach(in wd_dev *src,
in wd_dev *dst,
in out wd_dev **attached)
{
*attached = dst;
*attached = IoAttachDeviceToDeviceStack(src,dst);
if(*attached == NULL)
return wd_stat_no_such_dev;
return wd_stat_suc;
}

到這裡,我們已經知道過濾對Volume的請求的辦法。比如“C:”這個裝置,我已經知道符號串連為“C:”,不難得到裝置名稱。得到裝置名稱後,又不難得到 裝置。這時候我們IoCreateDevice()產生一個Device Object,然後調用wd_dev_attach綁定,不是一切ok嗎?所有發給“C:”的irp,就必然先發送給我們的驅動,我們也可以捕獲所有對文 件的操作了!

這確實是很簡單的處理方法。我得到的FileMon的代碼就是這樣處理的,如果不想處理動態Volume,你完全可以這樣做。但是我們這裡有更高的要 求。當你把一個隨身碟插入usb口,一個“J:”之類的Volume動態誕生的時候,我們依然要捕獲這個事件,並產生一個Device來綁定它。

一個新的儲存媒質被系統發現並在檔案系統中產生一個Volume的過程稱為Mounting.其過程開始的時候,FS的CDO將得到一個IRP,其 Major Function Code為IRP_MJ_FILE_SYSTEM_CONTROL,Minor Function Code為IRP_MN_MOUNT。換句話說,如果我們已經產生了一個裝置繫結檔案系統的CDO,那麼我們就可以得到這樣的IRP,在其中知道一個新的 Volume正在Mount.這時候我們可以執行上邊所說的操作。

現在的問題是如何知道系統中有那些檔案系統,還有就是我應該在什麼時候綁定它們的控制裝置。

IoRegisterFsRegistrationChange()是一個非常有用的系統調用。這個調用註冊一個回呼函數。當系統中有任何檔案系統被啟用或者是被登出的時候,你註冊過的回呼函數就會被調用。

//----------------------wdf.h中的內容----------------------------------
wd_stat wdff_reg_notify(
in wd_drv *driver,
in wdff_notify_func func
)
{
return IoRegisterFsRegistrationChange(driver,func);
}

你有必要為此寫一個回呼函數。

//-------------------我的回調處理函數----------------------------------
wd_void my_fs_notify(
in wd_dev *dev,
in wd_bool active)
{
wd_wchar name_buf[wd_dev_name_max_len];
wd_ustr name;
wd_ustr_init_em(&name,name_buf,wd_dev_name_max_len);

// 如果註冊了,就應該得到通知
wd_printf0("notify: a file sys have been acitved!!! \r\n");

// 得到檔案系統對象的名字,然後列印出來
wd_obj_get_name(dev,&name);
wd_printf0("notify : file sys name = %wZ\r\n",&name);

if(active)
{
wd_printf0("notify: try to attach.\r\n");
// ... 請在這裡繫結檔案系統的控制裝置
}
else
{
wd_printf0("notify: unactive.\r\n");
// ...
}
}

應該如何綁定一個檔案系統CDO?我們在下面的章節再詳細描述。

現在我們應該再在wd_main函數中加上下邊的內容:

if(wdff_reg_notify(driver,my_fs_notify) != wd_stat_suc)
{
wd_printf0("error: reg notify failed.\r\n");
wd_fio_disp_release(driver);
wd_dev_del(g_cdo);
g_cdo = wd_null;
return wd_stat_insufficient_res;
};

wd_printf0("success: reg notify ok.\n");

我們再次回顧一下,wd_main中,應該做哪些工作。

a.產生一個控制裝置。當然此前你必須給控制設定指定名稱。

b.設定Dispatch Functions.

c.設定Fast Io Functions.

d.編寫一個my_fs_notify回呼函數,在其中綁定剛啟用的FS CDO.

e.使用wdff_reg_notify調用註冊這個回呼函數。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.