青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

小默

(轉載)Windows文件系統過濾驅動開發教程 作者,楚狂人自述(1)

我長期網上為各位項目經理充當“技術實現者”的角色。我感覺Windows文件系統驅動的開發能找到的資料比較少。為了讓技術經驗不至于遺忘和引起大家交流的興趣我以我的工作經驗撰寫本教程。

我的理解未必正確,有錯誤的地方望多多指教。有問題歡迎與我聯系。我們也樂于接受各種驅動項目的開發。郵箱為MFC_Tan_Wen@163.com,QQ為16191935。

對于這本教程,您可以免費獲得并隨意修改,向任何網站轉貼。但是不得剽竊任何內容作為任何贏利出版物的全部或者部分。

1. 概述,鉆研目的和準備


我經常在網上碰到同行請求開發文件系統驅動。windows的pc機上以過濾驅動居多。其目的不外乎有以下幾種:

一是用于防病毒引擎。希望在系統讀寫文件的時候,捕獲讀寫的數據內容,然后檢測其中是否含有病毒代碼。

二是用于加密文件系統,希望在文件寫過程中對數據進行加密,在讀的過程中進行解密。

三是設計透明的文件系統加速。讀寫磁盤的時候,合適的cache算法是可以大大提高磁盤的工作效率。windows本身的cache算法未必適合一些特殊的讀寫

磁盤操作(如流媒體服務器上讀流媒體文件)。設計自己的cache算法的效果,我已在工作中有所感受。

如果你剛好有以上此類的要求,你可以閱讀本教程。

文件系統驅動是windows系統中最復雜的驅動種類之一。不能對ifsddk中的幫助抱太多希望,以我的經驗看來,文件系統相關的ddk幫助極其簡略,很多重要的部分僅僅輕描淡寫的帶過。如果安裝了ifsddk,應該閱讀srcfilesysOSR_docs下的文檔。而不僅僅是ddk幫助。

文件系統驅動開發方面的書籍很少。中文資料我僅僅見過侯捷翻譯過的一本驅動開發的書上有兩三章涉及,也僅僅是只能用于9x的vxd驅動。NT文件系統我見過一本英文書。我都不記得這兩本書的書名了。

如果您打算開發9x或者nt文件系統驅動,建議你去網上下載上文提及的書。那兩本書都有免費的電子版本下載。如果你打算開發Windows2000WindowsXPWindow2003的文件系統驅動,你可以閱讀本教程。雖然本教程僅僅講述文件系統過濾驅動。但是如果您要開發一個全新的文件系統驅動的話,本教程依然對你有很大的幫助。

學習文件系統驅動開發之前,應該在機器上安裝ifsddk。ddk版本越高級,其中頭文件中提供的系統調用也越多。經常有人詢問如xpddk編譯的驅動能不能在2000上運行等等的問題。我想可以這樣解釋:高級版本的ddk應該總是可以編譯低級驅動的代碼,而且得到的二進制版本也總是可以在低級系統上運行。但是反過來就未必可以了。如果在高級系統上編寫用于低級系統上的驅動,要非常認真的注意僅僅調用低級系統上有的系統調用。

ifsddk可以在某些ftp上免費下載。

我的使用的是ifs ddk for xp,但是我實際用來開發的兩臺機器有一臺是windows 2000,另一臺是windows 2003.我盡量使我編譯出來的驅動,可以在2000xp2003三種系統上都通過測試。

安裝配置ddk和在vc中開發驅動的方法網上有很多的介紹。ifsddk安裝之后,src目錄下的filesys目錄下有文件系統驅動的示例。閱讀這些代碼你就可以快速的學會文件系統驅動開發。

filter目錄下的sfilter是一個文件系統過濾驅動的例子。另一個filespy完全是用這個例子的代碼加工得更復雜而已。

如何用ddk編譯這個例子請自己查看相關的資料。

文件系統過濾驅動編譯出來后你得到的是一個擴展名為sys的文件。同時你需要寫一個.inf文件來實現這個驅動的安裝。我這里不討論.inf文件的細節,你可以直接用sfilter目錄下的inf文件修改。

對inf文件點鼠標右鍵彈出菜單選擇“安裝”,即可安裝這個過濾驅動。但是必須重新啟動系統才生效。

如果重啟后藍屏無法啟動,可以用其他方式引導系統后到system32drivers目錄下刪除你的.sys文件再重啟即可。我嘗試這種情況下用安全模式結果還是藍屏。所以我后來不得不在機器上裝了兩個2000系統。雙系統情況下,一個系統崩潰了用另一個系統啟動,刪除原來的驅動即可。

如果要調試代碼,請安裝softice.

打開sfilter目錄下的文件sources(這個文件沒有擴展名),加入一行
BROWSER_INFO=1

然后打開Symbol Loader,File->Open選中你編譯出來的xxx.sys,Modul->Load,Modul->Translate,然后就可以調試了。

打開softice,輸入file *就可以看見代碼。

如果準備好了,我們就可以開始琢磨windows文件系統過濾驅動的開發了。



1.       hello world,驅動對象與設備對象

這里所說的驅動對象是一種數據結構,在DDK中名為DRIVER_OBJECT。任何驅動程序都對應一個DRIVER_OBJECT.如何獲得本人所寫的驅動對應的DRIVER_OBJECT呢?驅動程序的入口函數為DriverEntry,因此,當你寫一個驅動的開始,你會寫下如下的代碼:

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
{
}

這個函數就相當與喜歡c語言的你所常用的main().IN是無意義的宏,僅僅表明后邊的參數是一種輸入,而對應的OUT則代表這個參數是一種返回。這里沒有使用引用,因此如果想在參數中返回結果,一律傳入指針。

DriverObject就是你所寫的驅動對應的DRIVER_OBJECT,是系統在加載你的驅動時候所分配的。RegisteryPath是專用于你記錄你的驅動相關參數的注冊表路徑。

DriverObject重要之處,在于它擁有一組函數指針,稱為dispatch functions.

開發驅動的主要任務就是親手撰寫這些dispatch functions.當系統用到你的驅動,會向你的DO發送IRP(這是windows所有驅動的共同工作方式)。你的任務是在dispatch function中處理這些請求。你可以讓irp失敗,也可以成功返回,也可以修改這些irp,甚至可以自己發出irp。

設備對象則是指DEVICE_OBJECT.下邊簡稱DO.

但是實際上每個irp都是針對DO發出的。只有針對由該驅動所生成的DO的IRP,
才會發給該驅動來處理。

當一個應用程序打開文件并讀寫文件的時候,windows系統將這些請求變成irp發送給文件系統驅動。

文件系統過濾驅動將可以過濾這些irp.這樣,你就擁有了捕獲和改變文件系統操作的能力。

象Fat32,NTFS這樣的文件系統(File System,簡稱FS),可能生成好幾種設備。首先文件系統驅動本身往往生成一個控制設備(CDO).這個設備的主要任務是修改整個驅動的內部配置。因此一個Driver只對應一個CDO.

另一種設備是被這個文件系統Mount的Volume。一個FS可能有多個Volume,也可能一個都沒有。解釋一下,如果你有C:,D:,E:,F:四個分區。C:,D:為NTFS,E:,F:為Fat32.那么C:,D:則是Fat的兩個Volume設備對象.

實際上"C:"是該設備的符號連接(Symbolic Link)名。而不是真正的設備名。可以打開Symbolic Links Viewer,能看到:

C: DeviceHarddiskVolume1

因此該設備的設備名為“DeviceHarddiskVolume1”.

這里也看出來,文件系統驅動是針對每個Volume來生成一個DeviceObject,而不是針對每個文件的。實際上對文件的讀寫的irp,都發到Volume設備對象上去了。并不會生成一個“文件設備對象”。

掌握了這些概念的話,我們現在用簡單的代碼來生成我們的CDO,作為我們開發文件系統驅動的第一步牛刀小試。

我不喜歡用微軟風格的代碼。太長而且難看。我對大部分數據結構和函數進行了重定義。為此我寫了一個名為wdf.h的頭文件幫助我轉換。有興趣的讀者可以發郵件向索取這個文件。沒有也沒有關系,我總是會寫出wd_xxx系列的東西在DDK中的原形。


// -----------------wdf_filter.c中的內容-------------------------

#include "wdf.h"

wd_stat wdff_cdo_create(in wd_drv *driver,
in wd_size exten_len,
in wd_ustr *name,
out wd_dev **device)
{
return wd_dev_create(
driver,
exten_len,
name,
wd_dev_disk_fs,
wdf_dev_secure_open,
wd_false,
device);
}

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_filter");
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_filter");
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");
return status;
}

為了讓代碼看起來象上邊的那樣,我不得不做了很多轉換。如

#define DriverEntry wd_main

一種爽的感覺,終于可以在寫看起來更象是main()的函數中工作了。 wd_dev_create 這個函數內部調用的是IoCreateDevice.而wd_suc實際上是SUCCESS()這樣的宏。

// ----------------------wdf.h中的內容------------------------------
#include "ntifs.h"

#define in IN
#define out OUT
#define optional OPTIONAL
#define wd_ustr UNICODE_STRING
#define wdp_ustr PUNICODE_STRING
#define wd_main DriverEntry

// 設備、驅動對象類型
typedef DRIVER_OBJECT wd_drv;
typedef DEVICE_OBJECT wd_dev;
typedef DRIVER_OBJECT wd_pdrv;
typedef PDEVICE_OBJECT wd_pdev;

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
};

// 狀態相關的類型和宏
typedef NTSTATUS wd_stat;

enum {
wd_stat_suc = STATUS_SUCCESS,
wd_stat_path_not_found = STATUS_OBJECT_PATH_NOT_FOUND,
wd_stat_insufficient_res = STATUS_INSUFFICIENT_RESOURCES,
wd_stat_invalid_dev_req = STATUS_INVALID_DEVICE_REQUEST,
wd_stat_no_such_dev = STATUS_NO_SUCH_DEVICE,
wd_stat_image_already_loaded = STATUS_IMAGE_ALREADY_LOADED,
wd_stat_more_processing = STATUS_MORE_PROCESSING_REQUIRED,
wd_stat_pending = STATUS_PENDING
};

_inline wd_bool wd_suc(wd_stat state)
{
return NT_SUCCESS(state);
}

#define wd_printf0 DbgPrint

_inline wd_void wd_ustr_init(in out wd_ustr* str,
in const wd_wchar* chars)
{
RtlInitUnicodeString(str,chars);
};

_inline wd_void wd_ustr_init_em(
in out wd_ustr*str,
in wd_wchar *chars,
in wd_size size)
{
RtlInitEmptyUnicodeString(str,chars,size);
};


wdf.h這個文件我僅僅節選了需要的部分。以上您已經擁有了一個簡單的“驅動”的完整的代碼。它甚至可以編譯,安裝(請修改sfilter.inf文件,其方法不過是將多處sfilter改為"our_fs_filter",希望這個過程中您不會出現問題)。然后把wdf.h和wdf_filter.c放在您新建立的目錄下,這個目錄下還應該有另兩個文件。一個是Makefile,請從sfilter目錄下拷貝。另一個是SOURCES,請輸入如下內容:
TARGETNAME=our_fs_filter
TARGETPATH=obj
TARGETTYPE=DRIVER
DRIVERTYPE=FS
BROWSER_INFO=1
SOURCES=wdf_filter.c

使用ddk編譯之后您將得到our_fs_filter.sys.把這個文件與前所描述的inf文件同一目錄,按上節所敘述方法安裝。

這個驅動不起任何作用,但是你已經成功的完成了"hello world".



2.       分發例程,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 = 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中的示例自己完成這些代碼。

使用Fast I/O

在這里我們將講述Fast I/O的基本原理,簡單描述各種各樣的Fast I/O調用,以及得出如何使用此接口來提高程序性能的建議性結論。

Windows NT內核模式開發的標準做法是采用IRP作為基本的與驅動程序通信的手段,它的優點是IRP封裝了上下文所需的詳細操作并且允許從驅動程序的眾多操作細節中分離出來。

這個方法在windos NT的分層設備體系中非常通用,有相當多的上層操作請求需要快速響應,在這種情況下,上層操作生成IRP決定了整個操作的成本并會導致系統性能的下降。鑒于此,NT系統引入的Fast I/O的概念。這種方法被用在文件系統驅動,如NTFS,HPFS,FAT和CDFS以及被WinSock使用的傳輸驅動AFD。

任何驅動都可以注冊一系列Fast I/O接口,但使用起來還有很大的限制—在這些接口被調之前需要滿足合適的條件。例如,讀操作和寫操作的Fast I/O接口只有當Windows NT cache管理器保留了文件的信息時才被調用。我們在接下的論述中將會講述這些限制。

當然,Windows NT的Fast I/O最讓人郁悶的是關于它的資料很少,即使文件系統開發包也沒有講述Fast I/O是如何工作和怎樣來使用Fast I/O。

原理

提供了Fast I/O是非常方便的---許多I/O操作可以對相同的數據進行重復操作。例如和許多流行的操作系統一樣,Windows NT用虛擬內存集成了文件系統的緩沖,這樣的系統無論是在使用上還是在感覺上都很有效率。

這種集成的另一原因是Windows NT支持內存映射文件。支持讀寫和內存映射相同的數據要么需要代價很高的cache一致性策略,要么使用NT的策略---將所有數據存儲在虛擬內存中。這樣,即便是兩個程序用不同的技術訪問相同的數據,也確保了數據的一致性。

這種緊密的集成意味著無論是讀還是寫都經常是對cache中的數據來操作。在查找過程中,這種策略用來調用一個特殊的程序,此程序將虛擬機(VM)的cache中的數據移到用戶內存中,反之亦然。這樣就避免了生成IRP,并且不需要請求底層的驅動了。這就是Fast I/O操作的基本功能。

一旦在程序中定義了Fast I/O讀寫接口,那么同時還需要進行一步添加其它的通用Fast I/O操作到Fast I/O鏈中,Fast I/O鏈中有13個接口(在NT3.51中)。在我們接下來要講的各接口過程中,你會明顯地發現各接口是互相關聯的。這些接口包含在FAST_IO_DISPATCH結構中,此結構在ntddk.h中有定義。這個結構的第一個元素表示結構的大小,為以后在結構添加新接口提供了一種向上兼容的機制。



I/O管理器和Fast I/O

I/O管理器在必要的時候負責調用Fast I/O接口。Fast I/O調用返回TRUE或FALSE表示Fast I/O操作是否完成。如果Fast I/O沒有被完成或無效,則會產生一個IPR并發送到上層驅動,但是FAST_IO_DISPATCH結構中最近的三個接口卻不是這樣的,它們為I/O管理員提供了不同的服務,接下來我們將討論它們。

FastIoCheckIfPossible

這是在FAST_IO_DISPATCH結構中第一個調用的,僅被用來作為一般的文件系統庫操作(以FsRtl開頭的函數)。原型如下:
typedef BOOLEAN (*PFAST_IO_CHECK_IF_POSSIBLE)(
IN Struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
IN ULONG LockKey,
IN BOOLEAN CheckForReadOperation,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
這個函數被FsRtl庫中提供的通用的Fast I/O函數調用,僅用在讀寫操作中,以獲取使用了通用文件緩存管理系統中的讀和寫是否能在文件緩存中被響應(由參數CheckForReadOperation的值決定)。注意,除了這個函數沒有分配任何數據空間外其它參數和讀寫的Fast I/O接口參數相似。

FastIoRead and FastIoWrite

當對一個已經分配了有效數據緩存的文件進行讀請求時,這個函數被I/O管理器調用。原型如下:
typedef BOOLEAN (*PFAST_IO_READ)(
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
IN ULONG LockKey,
OUT PVOID Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
正如前面所講的,基本的調用參數和FastIoCheckIfPossible相似,就是多了一個必要的數據緩存參數。要保證所有Fast I/O調用接口的參數有效,例如上面的Buffer指針,必需是有效的并且在讀線程的上下文中能使用此指針。

Fast I/O函數可以完成以下兩件事情之一:第一,當操作完成時設置IoStatus的返回值并給I/O管理器返回TRUE,這時I/O管理器會完成對應的I/O操作。第二,直接返回FALSE給I/O管理器使其構造一個IRP從而調用標準的分派例程。

要注意的是返回TRUE并不能保證數據被傳輸了。例如,一個從文件結束處開始的讀請求會設置IoStatus.Results為STATUS_END_OF_FILE,并且沒有數據被復制。但是當一個讀操作讀到了文件的結尾,這時會將IoStatus.Results設置為STATUS_END_OF_FILE,返回TRUE,并且將讀到的數據復制到Buffer里。

同樣,返回FALSE并不能說明所有的數據沒有被處理。例如,當然很少有這種可能,數據已經被成功處理了,但拋出一個I/O錯誤,或者內存不可訪問。

以上任何一種情況出現都會導致不良影響。例如,從緩存讀數據時,可能要讀的數據并不在緩存中,這時會導致一個頁錯誤,從而會請求文件系統來處理這個頁面錯誤。

Fast I/O的寫函數與讀函數不同之處僅僅在于Buffer參數一個是輸入型而不是輸出型的,其它的基本操作很相似。當然,一些錯誤可能不同---介質已經滿,需要分配新頁等等。



FastIoQueryBasicInfo and FastIoQueryStandardInfo

這兩個操作為標準的NtQueryInformationFile API操作提供了支持,而FastIoQueryBasicInfo也經常被用來處理NtCreateFile的特定操作。文件的基本屬性包括創建時間、訪問時間和修改時間,以及隱藏、文件夾或其它屬性等。文件的標準屬性包括文件占用的空間、文件的大小、文件的硬連接號、被請求刪除的標志,是否是文件夾的標識。

由于這些信息經常在緩存中,所以它是FAST I/O操作的最佳候選。其實許多程序用這種方法來獲取文件基本的信息,因為這種方法提高了操作的效率和程序的性能,如文件管理器程序(winfile.exe)。

posted on 2009-12-24 20:49 小默 閱讀(1583) 評論(0)  編輯 收藏 引用 所屬分類: Windows

導航

統計

留言簿(13)

隨筆分類(287)

隨筆檔案(289)

漏洞

搜索

積分與排名

最新評論

閱讀排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            午夜欧美大尺度福利影院在线看| 欧美亚洲一区| 日韩一级二级三级| 久久精品成人一区二区三区| 国产精品激情| 亚洲一区图片| 亚洲一区二区三区色| 欧美另类女人| 亚洲美女黄网| 午夜精品视频在线观看| 国产午夜精品理论片a级大结局 | 在线成人av网站| 久久久久91| 美腿丝袜亚洲色图| 一区二区三区欧美视频| 国产精品国产三级国产专播品爱网 | 亚洲第一页中文字幕| 欧美一区二区三区男人的天堂| 亚洲图片激情小说| 99视频超级精品| 国产精品免费网站在线观看| 欧美理论电影在线播放| 日韩一级免费观看| 99v久久综合狠狠综合久久| 欧美小视频在线| 麻豆成人综合网| 欧美性大战久久久久| 性久久久久久久久| 欧美美女视频| 久久午夜羞羞影院免费观看| av成人免费| 久久精品五月婷婷| 亚洲精品在线观| 亚洲欧美国产77777| 亚洲国产成人精品视频| 一本大道久久a久久综合婷婷| 欧美视频二区36p| 亚洲嫩草精品久久| 久久精品国产精品亚洲精品| 久久―日本道色综合久久| 久久精品一二三| 欧美日韩三级一区二区| 在线亚洲电影| 欧美成人dvd在线视频| 久久丁香综合五月国产三级网站| 欧美日韩国产不卡| 玖玖视频精品| 国产有码在线一区二区视频| 欧美福利电影在线观看| 一区精品久久| 久久女同互慰一区二区三区| 久久国产免费看| 国产精品va在线播放| 欧美一区二区三区视频在线| 国产精品国产精品国产专区不蜜| 亚洲盗摄视频| 亚洲免费成人| 国产欧美精品| 欧美激情第五页| 亚洲欧美日本精品| 欧美电影在线| 亚洲欧美精品一区| 亚洲黄色免费电影| 欧美午夜视频在线| 久久九九精品99国产精品| 午夜精品成人在线视频| 亚洲色在线视频| 美女黄色成人网| 亚洲无线视频| 亚洲免费大片| 91久久国产综合久久蜜月精品| 欧美日韩国产一区二区三区地区| 久久精品色图| 欧美一区二区成人6969| 亚洲视频一区二区在线观看| 欧美国产三区| 欧美护士18xxxxhd| 鲁大师成人一区二区三区| 欧美一区国产一区| 亚洲欧美美女| 欧美自拍丝袜亚洲| 久久精品官网| 久久久夜夜夜| 久久久久久尹人网香蕉| 亚洲欧美国产日韩天堂区| 一本色道久久综合狠狠躁篇的优点 | 国产亚洲福利| 国产美女精品视频| 国产欧美一区二区三区视频| 国产精品视频网| 国产精品视频自拍| 免费一级欧美片在线播放| 亚洲欧美另类在线| 亚洲免费网站| 免费人成网站在线观看欧美高清| 欧美jizz19性欧美| 欧美亚男人的天堂| 国产综合第一页| 日韩一级黄色大片| 香蕉久久国产| 欧美激情欧美狂野欧美精品| 亚洲精品色图| 欧美在线亚洲一区| 欧美freesex8一10精品| 欧美激情亚洲精品| 亚洲另类自拍| 亚洲一区二区免费看| 久久精品国产第一区二区三区最新章节 | 欧美激情一区在线观看| 欧美视频在线不卡| 亚洲三级毛片| 蜜乳av另类精品一区二区| 日韩午夜电影| 欧美成人午夜视频| 国产婷婷色一区二区三区在线| 一区在线观看| 欧美成人在线影院| 久久久久久久久久久久久久一区 | 亚洲一级特黄| 裸体一区二区三区| 国产亚洲视频在线观看| 午夜久久久久| 亚洲一区二区在线| 欧美国产综合一区二区| 午夜影视日本亚洲欧洲精品| 欧美三区在线| 亚洲性xxxx| 午夜视频在线观看一区二区三区 | 国产精品日韩在线一区| 亚洲婷婷免费| 亚洲视频你懂的| 国内精品国产成人| 欧美刺激午夜性久久久久久久| 久久天天狠狠| 新狼窝色av性久久久久久| 亚洲一区二区三区欧美| 久久久精彩视频| 欧美自拍偷拍午夜视频| 一区二区日韩欧美| 国产精品久久久久一区二区三区| 欧美一区二区三区免费视| 久久精品系列| 一本色道**综合亚洲精品蜜桃冫| 99国产精品99久久久久久粉嫩| 欧美日韩在线播放三区四区| 欧美在线亚洲一区| 欧美日韩一本到| 欧美成人激情视频| 国产欧美精品va在线观看| 亚洲电影免费观看高清完整版在线| 欧美精品麻豆| 美女尤物久久精品| 国产精品久久久久9999吃药| 久久综合久久综合这里只有精品| 欧美日韩免费观看一区三区| 久久久久网站| 欧美日韩亚洲系列| 亚洲国产婷婷香蕉久久久久久99| 国产色产综合色产在线视频| 91久久国产自产拍夜夜嗨| 国产一区二区三区电影在线观看| 亚洲精品国产精品乱码不99| 亚洲国产成人av好男人在线观看| 亚洲欧美美女| 新狼窝色av性久久久久久| 国产精品久久网站| 亚洲精品美女| 女女同性女同一区二区三区91| 久久久久久久97| 国内久久视频| 久久综合伊人77777麻豆| 久久久青草婷婷精品综合日韩 | 欧美激情国产日韩精品一区18| 欧美风情在线观看| 亚洲自拍偷拍网址| 国产在线欧美| 欧美精品色综合| 免费不卡在线视频| 激情欧美一区二区三区| 久久九九久精品国产免费直播| 久久久国产精彩视频美女艺术照福利 | 欧美成人精品影院| 亚洲国产精品毛片| 在线亚洲一区| 国产视频久久久久久久| 久久gogo国模啪啪人体图| 欧美国产日韩免费| 欧美中日韩免费视频| 一本色道久久88综合亚洲精品ⅰ| 国产精品xvideos88| 久久亚洲春色中文字幕久久久| 亚洲成色精品| 久久亚洲免费| 久久国产黑丝| 亚洲欧美国产精品va在线观看| 亚洲国产欧美一区二区三区久久| 欧美日韩一级黄| 欧美激情综合色| 嫩草影视亚洲| 免费成年人欧美视频|