• <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>

            小默

            (轉(zhuǎn)載)Windows文件系統(tǒng)過濾驅(qū)動開發(fā)教程 作者,楚狂人自述(1)

            我長期網(wǎng)上為各位項目經(jīng)理充當(dāng)“技術(shù)實現(xiàn)者”的角色。我感覺Windows文件系統(tǒng)驅(qū)動的開發(fā)能找到的資料比較少。為了讓技術(shù)經(jīng)驗不至于遺忘和引起大家交流的興趣我以我的工作經(jīng)驗撰寫本教程。

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

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

            1. 概述,鉆研目的和準(zhǔn)備


            我經(jīng)常在網(wǎng)上碰到同行請求開發(fā)文件系統(tǒng)驅(qū)動。windows的pc機上以過濾驅(qū)動居多。其目的不外乎有以下幾種:

            一是用于防病毒引擎。希望在系統(tǒng)讀寫文件的時候,捕獲讀寫的數(shù)據(jù)內(nèi)容,然后檢測其中是否含有病毒代碼。

            二是用于加密文件系統(tǒng),希望在文件寫過程中對數(shù)據(jù)進行加密,在讀的過程中進行解密。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            如果要調(diào)試代碼,請安裝softice.

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

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

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

            如果準(zhǔn)備好了,我們就可以開始琢磨windows文件系統(tǒng)過濾驅(qū)動的開發(fā)了。



            1.       hello world,驅(qū)動對象與設(shè)備對象

            這里所說的驅(qū)動對象是一種數(shù)據(jù)結(jié)構(gòu),在DDK中名為DRIVER_OBJECT。任何驅(qū)動程序都對應(yīng)一個DRIVER_OBJECT.如何獲得本人所寫的驅(qū)動對應(yīng)的DRIVER_OBJECT呢?驅(qū)動程序的入口函數(shù)為DriverEntry,因此,當(dāng)你寫一個驅(qū)動的開始,你會寫下如下的代碼:

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

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

            DriverObject就是你所寫的驅(qū)動對應(yīng)的DRIVER_OBJECT,是系統(tǒng)在加載你的驅(qū)動時候所分配的。RegisteryPath是專用于你記錄你的驅(qū)動相關(guān)參數(shù)的注冊表路徑。

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

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

            設(shè)備對象則是指DEVICE_OBJECT.下邊簡稱DO.

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

            當(dāng)一個應(yīng)用程序打開文件并讀寫文件的時候,windows系統(tǒng)將這些請求變成irp發(fā)送給文件系統(tǒng)驅(qū)動。

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

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

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

            實際上"C:"是該設(shè)備的符號連接(Symbolic Link)名。而不是真正的設(shè)備名??梢源蜷_Symbolic Links Viewer,能看到:

            C: DeviceHarddiskVolume1

            因此該設(shè)備的設(shè)備名為“DeviceHarddiskVolume1”.

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

            掌握了這些概念的話,我們現(xiàn)在用簡單的代碼來生成我們的CDO,作為我們開發(fā)文件系統(tǒng)驅(qū)動的第一步牛刀小試。

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


            // -----------------wdf_filter.c中的內(nèi)容-------------------------

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

            // 然后我生成控制設(shè)備,雖然現(xiàn)在我的控制設(shè)備什么都不干
            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)
            {
            // 這種情況發(fā)生于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;
            }

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

            #define DriverEntry wd_main

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

            // ----------------------wdf.h中的內(nèi)容------------------------------
            #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

            // 設(shè)備、驅(qū)動對象類型
            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
            };

            // 狀態(tài)相關(guān)的類型和宏
            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這個文件我僅僅節(jié)選了需要的部分。以上您已經(jīng)擁有了一個簡單的“驅(qū)動”的完整的代碼。它甚至可以編譯,安裝(請修改sfilter.inf文件,其方法不過是將多處sfilter改為"our_fs_filter",希望這個過程中您不會出現(xiàn)問題)。然后把wdf.h和wdf_filter.c放在您新建立的目錄下,這個目錄下還應(yīng)該有另兩個文件。一個是Makefile,請從sfilter目錄下拷貝。另一個是SOURCES,請輸入如下內(nèi)容:
            TARGETNAME=our_fs_filter
            TARGETPATH=obj
            TARGETTYPE=DRIVER
            DRIVERTYPE=FS
            BROWSER_INFO=1
            SOURCES=wdf_filter.c

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

            這個驅(qū)動不起任何作用,但是你已經(jīng)成功的完成了"hello world".



            2.       分發(fā)例程,fast io

            上一節(jié)僅僅生成了控制設(shè)備對象。但是不要忘記,驅(qū)動開發(fā)的主要工作是撰寫分發(fā)例程(dispatch functions.).接上一接,我們已經(jīng)知道自己的DriverObject保存在上文代碼的driver中?,F(xiàn)在我寫如下一個函數(shù)來指定一個默認的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);

            就為這個驅(qū)動指定了一個默認的Dispatch Function.所有的irp請求,都會被發(fā)送到這個函數(shù)。但是,我可能不希望這個函數(shù)處理過于復(fù)雜,而希望把一些常見的請求獨立出來,如Read,Write,Create,Close,那我又寫了幾個函數(shù)專門用來設(shè)置這幾個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多代碼,其實就是在設(shè)置driver->MajorFunction這個數(shù)組而已。因此在wd_main對dispatch functions的設(shè)置,就變成了下邊這樣的:

            // 開始設(shè)置幾個分發(fā)例程
            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);

            下面的任務(wù)都在寫my_xxx系列的這些函數(shù)了。但是對于這個DriverObject的設(shè)置,還并不是僅僅這么簡單。

            由于你的驅(qū)動將要綁定到文件系統(tǒng)驅(qū)動的上邊,文件系統(tǒng)除了處理正常的IRP之外,還要處理所謂的FastIo.FastIo是Cache Manager調(diào)用所引發(fā)的一種沒有irp的請求。換句話說,除了正常的Dispatch Functions之外,你還得為DriverObject撰寫另一組Fast Io Functions.這組函數(shù)的指針在driver->FastIoDispatch.我不知道這個指針留空會不會導(dǎo)致系統(tǒng)崩潰。在這里本來是沒有空間的,所以為了保存這一組指針,你必須自己分配空間。

            下面是我常用的內(nèi)存分配函數(shù)。

            //-----------------wdf.h中的代碼----------------------
            // 最簡單的分配內(nèi)存的函數(shù),可以指定分頁非分頁
            _inline wd_pvoid wd_malloc(wd_bool paged,wd_size size)
            {
            if(paged)
            return ExAllocatePool(PagedPool,size);
            else
            return ExAllocatePool(NonPagedPool,size);
            }

            // 釋放內(nèi)存
            _inline wd_void wd_free(wd_pvoid point)
            {
            ExFreePool(point);
            }

            _inline wd_void wd_memzero(
            wd_pvoid point,
            wd_size size)
            {
            RtlZeroMemory(point,size);
            }

            有了上邊的基礎(chǔ),我就可以自己寫一個初始化FastIoDispatch指針的函數(shù)。

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

            這個函數(shù)為FastIoDispacth指針分配足夠的空間并填寫它的大小。下面是再寫一系列的函數(shù)來設(shè)置這個函數(shù)指針數(shù)組。實際上,F(xiàn)astIo接口函數(shù)實在太多了,所以我僅僅寫出這些設(shè)置函數(shù)的幾個作為例子:
            //-----------------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;
            }

            ...

            好,如果你堅持讀到了這里,應(yīng)該表示祝賀了。我們回顧一下,wd_main中,應(yīng)該做哪些工作。

            a.生成一個控制設(shè)備。當(dāng)然此前你必須給控制設(shè)置指定名稱。

            b.設(shè)置Dispatch Functions.

            c.設(shè)置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;

            // 然后我生成控制設(shè)備,雖然現(xiàn)在我的控制設(shè)備什么都不干
            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)
            {
            // 這種情況發(fā)生于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");

            // 開始設(shè)置幾個分發(fā)例程
            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處理函數(shù)
            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;
            }

            // 下面指定的這些函數(shù)都定義在wdf_filter_fio.h中,其實這些函數(shù)都統(tǒng)
            // 一的返回了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函數(shù)個數(shù)數(shù)量不明,我只覺得很多。因此不打算全部羅列,以"..."敷衍之。某些讀者可能會認為這些代碼無法調(diào)試安裝。其實您可以參考sfilter中的示例自己完成這些代碼。

            使用Fast I/O

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

            Windows NT內(nèi)核模式開發(fā)的標(biāo)準(zhǔn)做法是采用IRP作為基本的與驅(qū)動程序通信的手段,它的優(yōu)點是IRP封裝了上下文所需的詳細操作并且允許從驅(qū)動程序的眾多操作細節(jié)中分離出來。

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

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

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

            原理

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

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

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

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



            I/O管理器和Fast I/O

            I/O管理器在必要的時候負責(zé)調(diào)用Fast I/O接口。Fast I/O調(diào)用返回TRUE或FALSE表示Fast I/O操作是否完成。如果Fast I/O沒有被完成或無效,則會產(chǎn)生一個IPR并發(fā)送到上層驅(qū)動,但是FAST_IO_DISPATCH結(jié)構(gòu)中最近的三個接口卻不是這樣的,它們?yōu)镮/O管理員提供了不同的服務(wù),接下來我們將討論它們。

            FastIoCheckIfPossible

            這是在FAST_IO_DISPATCH結(jié)構(gòu)中第一個調(diào)用的,僅被用來作為一般的文件系統(tǒng)庫操作(以FsRtl開頭的函數(shù))。原型如下:
            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
            );
            這個函數(shù)被FsRtl庫中提供的通用的Fast I/O函數(shù)調(diào)用,僅用在讀寫操作中,以獲取使用了通用文件緩存管理系統(tǒng)中的讀和寫是否能在文件緩存中被響應(yīng)(由參數(shù)CheckForReadOperation的值決定)。注意,除了這個函數(shù)沒有分配任何數(shù)據(jù)空間外其它參數(shù)和讀寫的Fast I/O接口參數(shù)相似。

            FastIoRead and FastIoWrite

            當(dāng)對一個已經(jīng)分配了有效數(shù)據(jù)緩存的文件進行讀請求時,這個函數(shù)被I/O管理器調(dià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
            );
            正如前面所講的,基本的調(diào)用參數(shù)和FastIoCheckIfPossible相似,就是多了一個必要的數(shù)據(jù)緩存參數(shù)。要保證所有Fast I/O調(diào)用接口的參數(shù)有效,例如上面的Buffer指針,必需是有效的并且在讀線程的上下文中能使用此指針。

            Fast I/O函數(shù)可以完成以下兩件事情之一:第一,當(dāng)操作完成時設(shè)置IoStatus的返回值并給I/O管理器返回TRUE,這時I/O管理器會完成對應(yīng)的I/O操作。第二,直接返回FALSE給I/O管理器使其構(gòu)造一個IRP從而調(diào)用標(biāo)準(zhǔn)的分派例程。

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

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

            以上任何一種情況出現(xiàn)都會導(dǎo)致不良影響。例如,從緩存讀數(shù)據(jù)時,可能要讀的數(shù)據(jù)并不在緩存中,這時會導(dǎo)致一個頁錯誤,從而會請求文件系統(tǒng)來處理這個頁面錯誤。

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



            FastIoQueryBasicInfo and FastIoQueryStandardInfo

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

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

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

            導(dǎo)航

            統(tǒng)計

            留言簿(13)

            隨筆分類(287)

            隨筆檔案(289)

            漏洞

            搜索

            積分與排名

            最新評論

            閱讀排行榜

            久久成人精品| 国内精品久久人妻互换| 久久AAAA片一区二区| 久久精品国产亚洲Aⅴ蜜臀色欲| 久久久久国产视频电影| 久久久久se色偷偷亚洲精品av| 久久精品亚洲中文字幕无码麻豆 | 日本精品久久久久影院日本| 一本久久a久久精品vr综合| 蜜桃麻豆www久久| 一本色道久久99一综合| 精品久久综合1区2区3区激情| 性欧美大战久久久久久久久| 国产精品九九久久免费视频| 久久精品九九亚洲精品| 色8激情欧美成人久久综合电| 久久九九有精品国产23百花影院| 久久夜色精品国产噜噜亚洲a| 久久精品国产99久久丝袜| 久久成人国产精品| 日日噜噜夜夜狠狠久久丁香五月| 久久黄色视频| 久久久久人妻精品一区三寸蜜桃| 久久精品国产福利国产秒| 久久综合给合久久狠狠狠97色69| 久久91精品国产91| 久久精品亚洲乱码伦伦中文| 青青草原综合久久| 久久综合久久综合久久| 久久亚洲欧美日本精品| 狠狠干狠狠久久| 久久99免费视频| 亚洲国产二区三区久久| 国产69精品久久久久9999| 青青草原综合久久| 国产视频久久| 亚洲国产精品狼友中文久久久| 欧美日韩精品久久久久| 综合久久精品色| 人妻无码αv中文字幕久久| 久久久精品国产sm调教网站|