Windows檔案系統過濾驅動開發教程
3.分發常式,fast io
上一節僅僅產生了控制裝置物件。但是不要忘記,驅動開發的主要工作是撰寫分發常式(dispatch functions.).接上一接,我們已經知道自己的DriverObject儲存在上文代碼的driver中。現在我寫如下一個函數來指定一個預設的 dispatch function給它。
//-----------------wdf.h中的代碼----------------------
typedef PDRIVER_DISPATCH wd_disp_fuc;
_inline wd_void wd_drv_set_dispatch(in wd_drv* driver,
in wd_disp_fuc disp)
{
wd_size i;
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
driver->MajorFunction[i] = disp;
}
在前邊的wd_main中,我只要加
wd_drv_set_dispatch(driver,my_dispatch_func);
就為這個驅動指定了一個預設的Dispatch Function.所有的irp請求,都會被發送到這個函數。但是,我可能不希望這個函數處理過於複雜,而希望把一些常見的請求獨立出來,如Read, Write,Create,Close,那我又寫了幾個函數專門用來設定這幾個Dispatch Functions.
//-----------------wdf.h中的代碼----------------------
_inline wd_void wd_drv_set_read(
in wd_drv* driver,
in wd_disp_fuc read)
{
driver->MajorFunction[IRP_MJ_READ] = read;
}
_inline wd_void wd_drv_set_write(
in wd_drv* driver,
in wd_disp_fuc write)
{
driver->MajorFunction[IRP_MJ_WRITE] = write;
}
wd_void wd_drv_set_create(in wd_drv* driver,
in wd_disp_fuc create)
{
driver->MajorFunction[IRP_MJ_CREATE] = create;
driver->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = create;
driver->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = create;
}
wd_void wd_drv_set_file_sys_control(in wd_drv* driver,
in wd_disp_fuc control)
{
driver->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = control;
}
wd_void wd_drv_set_clean_up(in wd_drv* driver,
in wd_disp_fuc clean_up)
{
driver->MajorFunction[IRP_MJ_CLEANUP] = clean_up;
}
wd_void wd_drv_set_close(in wd_drv* driver,
in wd_disp_fuc close)
{
driver->MajorFunction[IRP_MJ_CLOSE] = close;
}
別看我羅列n多代碼,其實就是在設定driver->MajorFunction這個數組而已。因此在wd_main對dispatch functions的設定,就變成了下邊這樣的:
// 開始設定幾個分發常式
wd_drv_set_dispatch(driver,my_disp_default);
wd_drv_set_create(driver,my_disp_create);
wd_drv_set_clean_up(driver,my_disp_clean_up);
wd_drv_set_file_sys_control(driver,my_disp_file_sys_ctl);
wd_drv_set_close(driver,my_disp_close);
wd_drv_set_read(driver,my_disp_read);
wd_drv_set_write(driver,my_disp_write);
下面的任務都在寫my_xxx系列的這些函數了。但是對於這個DriverObject的設定,還並不是僅僅這麼簡單。
由於你的驅動將要綁定到檔案系統驅動的上邊,檔案系統除了處理正常的IRP之外,還要處理所謂的FastIo.FastIo是Cache Manager調用所引發的一種沒有irp的請求。換句話說,除了正常的Dispatch Functions之外,你還得為DriverObject撰寫另一組Fast Io Functions.這組函數的指標在driver->FastIoDispatch.我不知道這個指標留空會不會導致系統崩潰。在這裡本來是沒有 空間的,所以為了儲存這一組指標,你必須自己分配空間。
下面是我常用的記憶體配置函數。
//-----------------wdf.h中的代碼----------------------
// 最簡單的分配記憶體的函數,可以指定分頁非分頁
_inline wd_pvoid wd_malloc(wd_bool paged,wd_size size)
{
if(paged)
return ExAllocatePool(PagedPool,size);
else
return ExAllocatePool(NonPagedPool,size);
}
// 釋放記憶體
_inline wd_void wd_free(wd_pvoid point)
{
ExFreePool(point);
}
_inline wd_void wd_memzero(
wd_pvoid point,
wd_size size)
{
RtlZeroMemory(point,size);
}
有了上邊的基礎,我就可以自己寫一個初始化FastIoDispatch指標的函數。
//-----------------wdf.h中的代碼----------------------
wd_bool wd_fio_disp_init(wd_drv *driver,wd_ulong size)
{
wd_fio_disp *disp = wd_malloc(wd_false,size);
if(disp == wd_null)
return wd_false;
wd_memzero((wd_pvoid)disp,size);
driver->FastIoDispatch = disp;
driver->FastIoDispatch->SizeOfFastIoDispatch = size;
return wd_true;
}
這個函數為FastIoDispacth指標分配足夠的空間並填寫它的大小。下面是再寫一系列的函數來設定這個函數指標數組。實際上,FastIo介面函數實在太多了,所以我僅僅寫出這些設定函數的幾個作為例子:
//-----------------wdf.h中的代碼----------------------
_inline wd_void wd_fio_disp_set_query_standard(
wd_drv *driver,
wd_fio_query_standard_func func)
{
driver->FastIoDispatch->FastIoQueryStandardInfo = func;
}
_inline wd_void wd_fio_disp_set_io_lock(
wd_drv *driver,
wd_fio_io_lock_func func)
{
driver->FastIoDispatch->FastIoLock = func;
}
_inline wd_void wd_fio_disp_set_io_unlock_s(
wd_drv *driver,
wd_fio_unlock_single_func func)
{
driver->FastIoDispatch->FastIoUnlockSingle = func;
}
...
好,如果你堅持讀到了這裡,應該表示祝賀了。我們回顧一下,wd_main中,應該做哪些工作。
a.產生一個控制裝置。當然此前你必須給控制設定指定名稱。
b.設定Dispatch Functions.
c.設定Fast Io Functions.
// ----------------wd_main 的近況----------------------------
...
wd_dev *g_cdo = NULL;
wd_stat wd_main(in wd_drv* driver,
in wd_ustr* reg_path)
{
wd_ustr name;
wd_stat status = wd_stat_suc;
// 然後我產生控制裝置,雖然現在我的控制裝置什麼都不幹
wd_ustr_init(&name,L\"\\FileSystem\\Filters\\our_fs_filters\");
status = wdff_cdo_create(driver,0,&name,&g_cdo);
if(!wd_suc(status))
{
if(status == wd_stat_path_not_found)
{
// 這種情況發生於FileSystemFilters路徑不存在。這個路徑是
// 在xp上才加上的。所以2000下可能會運行到這裡
wd_ustr_init(&name,L\"\\FileSystem\\our_fs_filters\");
status = wdff_cdo_create(driver,0,&name,&g_cdo);
};
if(!wd_suc(status))
{
wd_printf0(\"error: create cdo failed.rn\");
return status;
}
}
wd_printf0(\"success: create cdo ok.rn\");
// 開始設定幾個分發常式
wd_drv_set_dispatch(driver,my_disp_default);
wd_drv_set_create(driver,my_disp_create);
wd_drv_set_clean_up(driver,my_disp_clean_up);
wd_drv_set_file_sys_control(driver,my_disp_file_sys_ctl);
wd_drv_set_close(driver,my_disp_close);
wd_drv_set_read(driver,my_disp_read);
wd_drv_set_write(driver,my_disp_write);
// 指定fast io處理函數
if(!wd_fio_disp_init(driver,sizeof(wd_fio_disp)))
{
wd_dev_del(g_cdo);
wd_printf0(\"error: fast io disp init failed.rn\");
return wd_stat_insufficient_res;
}
// 下面指定的這些函數都定義在wdf_filter_fio.h中,其實這些函數都統
// 一的返回了false
wd_fio_disp_set_check(
driver,
my_fio_check);
wd_fio_disp_set_read(
driver,
my_fio_read);
wd_fio_disp_set_write(
driver,
my_fio_write);
wd_fio_disp_set_query_basic(
driver,
my_fio_query_basic_info);
...
}
FastIo函數個數數量不明,我只覺得很多。因此不打算全部羅列,以\"...\"敷衍之。某些讀者可能會認為這些代碼無法調試安裝。其實您可以參考sfilter中的樣本自己完成這些代碼。
現在我們的my_xxx系列的函數還沒有開始寫,因此驅動也不能編譯通過。在後邊的內容中再逐步介紹。