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

來源:互聯網
上載者:User
Windows檔案系統過濾驅動開發教程 6.IRP的傳遞,File System Control Dispatch

我們現在不得不開始寫dispatch functions.因為你的裝置已經綁定到檔案系統控制裝置上去了。windows發給檔案系統的請求發給你的驅動。如果你不能做恰當的處理,你的系統的就會崩潰。

最簡單的處理方式是把請求不加改變的傳遞到我們所連結的裝置上去。如何獲得我們所連結的裝置?上一節已經把該裝置記錄在我們的裝置擴充裡。

//------------我用這個函數快速得到我所連結的裝置-----------
// 得到連結的裝置
_inline wd_dev *my_dev_attached(wd_dev *dev)
{
return ((wdff_dev_ext *)wd_dev_ext(dev))->attached_to;
}

如何傳遞請求?使用IoCallDriver,該調用的第一個參數是裝置對象指標,第二個參數是IRP指標。

一個IRP擁有一組IO_STACK_LOCATION.前面說過IRP在一個裝置棧中傳遞。IO_STACK_LOCATION是和這個裝置棧對應的。 用於儲存IRP請求在當前裝置棧位置中的部分參數。如果我要把請求往下個裝置傳遞,那麼我應該把當前IO_STATCK_LOCATION複製到下一個。

我寫了一些函數來處理IO_STACK_LOCATION,另外wd_irp_call用來封裝IoCallDriver的功能。

//---------------------wdf.h中的內容----------------------------
typdef wd_irpsp PIO_STACK_LOCAION;

_inline wd_irpsp *wd_cur_io_stack(wd_irp *irp)
{
return IoGetCurrentIrpStackLocation(irp);
}

_inline wd_void wd_skip_io_stack(wd_pirp irp)
{
IoSkipCurrentIrpStackLocation(irp);
}

_inline wd_void wd_copy_io_stack(wd_irp *irp)
{
IoCopyCurrentIrpStackLocationToNext(irp);
}

_inline wd_stat wd_irp_call(wd_dev *dev,wd_pirp irp)
{
return IoCallDriver(dev,irp);
}

有了上邊這些,我現在可以寫一個預設的Dispatch Functions.

// 預設的處理很簡單,忽略當前調用棧,直接發送給綁定裝置
wd_stat my_disp_default(in wd_dev *dev,in wd_pirp irp)
{
wd_dev *attached_dev;
if(!is_my_dev(dev))
return wd_irp_failed(irp,wd_stat_invalid_dev_req);
if(is_my_cdo(dev))
return wd_irp_failed(irp,wd_stat_invalid_dev_req);
attached_dev = my_dev_attached(dev);
if(!attached_dev)
return wd_irp_failed(irp,wd_stat_invalid_dev_req);
wd_skip_io_stack(irp);
return wd_irp_call(attached_dev,irp);
}

上邊有一個函數is_my_dev來判斷是否我的裝置。這個判斷過程很簡單。通過dev可以得到DriverObject指標,判斷一下是否我自己的驅動 即可。is_my_cdo()來判斷這個裝置是否是我的控制裝置,不要忘記在wd_main()中我們首先產生了一個本驅動的控制裝置。實際這個控制裝置 還不做任何事情,所以對它發生的任何請求也是非法的。返回錯誤即可。wd_irp_failed這個函數立刻讓一個irp失敗。其內容如下:

// 這個函數可以立刻失敗掉一個irp
_inline wd_stat wd_irp_failed(wd_pirp irp,wd_stat status_error)
{
irp->IoStatus.Status = status_error;
irp->IoStatus.Information = 0;
return wd_irp_over(irp);
}

如此一來,本不改發到我的驅動的irp,就立刻返回錯誤非法請求。但是實際上這種情況是很少發生的。

如果你現在想要你的驅動立刻運行,讓所有的dispacth functions都調用my_disp_default.這個驅動已經可以繫結檔案系統的控制裝置,並輸出一些調試資訊。但是還沒有綁定Volume.所以並不能直接監控檔案讀寫。

對於一個繫結檔案系統控制裝置的裝置來說,其他的請求直接調用上邊的預設處理就可以了。重點需要注意的是上邊曾經掛接IRP_MJ_FILE_SYSTEM_CONTROL的dispatch處理的函數my_disp_file_sys_ctl().

IRP_MJ_FILE_SYSTEM_CONTROL這個東西是IRP的主功能號。每個主功能號下一般都有次功能號。這兩個東西標示一個IRP的功能。

主功能號和次功能號是IO_STACK_LOCATION的開頭兩位元組。

//----------------我重新定義的次功能號-------------------
enum {
wd_irp_mn_mount = IRP_MN_MOUNT_VOLUME,
wd_irp_mn_load_filesys = IRP_MN_LOAD_FILE_SYSTEM,
wd_irp_mn_user_req = IRP_MN_USER_FS_REQUEST
};
enum {
wdf_fsctl_dismount = FSCTL_DISMOUNT_VOLUME
};

要得到功能號,要先得到當前的IO_STACK_LOCATION,這個上邊已經有函數wd_cur_io_stack,相信這個不能難倒你。

當有Volumne被Mount或者dismount,你寫的my_disp_file_sys_ctl()就被調用。具體的判斷方法,就見如下的代碼了:

// 可以看到分發函數中其他的函數處理都很簡單,但是file_sys_ctl的
// 處理會比較複雜。我們已經在notify函數中綁定了檔案系統驅動的控
// 制對象。當檔案系統得到實際的介質的時候,會產生新的裝置對象,
// 這種裝置稱為卷(Volume),而這種裝置是在file_sys中的mount中生
// 成的,而且也是unmount中登出掉的。我們捕獲這樣的操作之後,就必
// 鬚生成我們的裝置對象,綁定在這樣的“卷”上,才能綁定對這個卷
// 上的檔案的操作。
wd_stat my_disp_file_sys_ctl(in wd_dev *dev,in wd_pirp irp)
{
wd_dev *attached_dev;
wd_io_stack *stack = wd_cur_io_stack(irp);
if(!is_my_dev(dev))
return wd_irp_failed(irp,wd_stat_invalid_dev_req);
switch(wd_irpsp_minor(stack))
{
case wd_irp_mn_mount:
// 在這裡,一個Volume正在Mount
return my_fsctl_mount(dev,irp);
case wd_irp_mn_load_filesys:
return my_fsctl_load_fs(dev,irp);
case wd_irp_mn_user_req:
{
switch(wd_irpsp_fs_ctl_code(stack))
{
case wdf_fsctl_dismount:
// 在這裡,一個Volume正dismount
return my_fsctl_dismount(dev,irp);
}
}
}
wd_skip_io_stack(irp);
attached_dev = my_dev_attached(dev);
return wd_irp_call(attached_dev,irp);
}

你發現你又得開始寫兩個新的函數,my_fsctl_mount()和my_fsctl_dismount(),來處理卷的Mount和Dismount.顯然,你應該在其中產生裝置或者刪除,綁定或者解除綁定。很快,你就能完全監控所有的卷了。

這樣做是動態監控所有的卷的完美的解決方案。

如果是在xp以上,有一個調用可以獲得一個檔案系統上已經被Mount的卷。但是2000下不能使用。所以我們沒有使用那個方法。何況僅僅得到已經Mount的卷也不是我想要的。

這裡另外還有一個my_fsctl_load_fs函數。發生於IRP_MN_LOAD_FILESYS。這個功能碼我只做一點點解釋:當一個檔案辨識器(見上文)決定載入真正的檔案系統的時候,會產生一個這樣的irp。

你現在可以修改你的驅動,使插入拔出u盤的時候,在Volume載入卸載時候輸出調試資訊。回首一下我們的脈絡:

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

b.設定Dispatch Functions.

c.設定Fast Io Functions.

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

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

f.編寫預設的dispatch functions.

e.處理IRP_MJ_FILE_SYSTEM_CONTROL,在其中監控Volumne的Mount和Dismount.

f.下一步自然是綁定Volumne了,請聽下回分解。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.