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

來源:互聯網
上載者:User
Windows檔案系統過濾驅動開發教程

注: 有任何問題與建議請加QQ16191935,郵箱MFC_Tan_Wen@163.com

工作忙,好久沒有來過了,請大家諒解。

10 自己發送Irp完成讀請求

關於這個有一篇文檔解釋得很詳細,不過我認為樣本的代碼有點太簡略了,這篇文檔在IFS所附帶的OSR文檔中,請自己尋找。

為何要自己發送Irp?在一個檔案過濾驅動中,如果你打算讀寫檔案,可以試用ZwReadFile.但是這有一些問題。Zw系列的Native API使

用控制代碼。而控制代碼是有線程環境限制的。此外也有中斷層級的限制。再說,Zw系列函數來讀寫檔案,最終還是要發出Irp,又會被自己的過濾驅動

捕獲到。結果帶來判斷上的困難。對資源也是浪費。那麼最應該的辦法是什麼呢?當然是直接對卷裝置發Irp了。

但是Irp是非常複雜的資料結構,而且又被微軟所構造的很多未空開的組件所處理。所以自己發irp並不是一件簡單的事情。

比較萬能的方法是IoAllocateIrp,分配後自己逐個填寫。問題是細節實在太多,很多無文檔可尋。有興趣的應該看看我上邊所提及的

那篇文章“Rolling Your Own”。

有意思的是這篇文章後來提到了捷徑,就是利用三個函數:

IoBuildAsynchronousFsdRequest(...)
IoBuildSynchronousFsdRequest(...)
IoBuildDeviceIoControlRequest(...)

於是我參考了他這方面的範例程式碼,發現運行良好,程式也很簡單。建議怕深入研究的選手就可以使用我下邊提供的方法了。

首先的建議是使用IoBuildAsynchronousFsdRequest(),而不要使用同步的那個。使用非同步Irp使irp和線程無關。而你的過濾驅動一

般很難把握當前線程(如果你開一個系統線程來專門讀取檔案那例外)。此時,你可以輕鬆的在Irp的完成函數中刪除你分配過的Irp,避免去追

究和線程相關的事情。

但是這個方法有局限性。文檔指出,這個方法僅僅能用於IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_FLUSH_BUFFERS,和IRP_MJ_SHUTDOWN.

剛好我這裡僅僅要求完成檔案讀。

用Irp完成檔案讀需要一個FILE_OBJECT.FileObject是比Zw系列所用的控制代碼更好的東西。因為這個FileObject是和線程無關的。你可以

放心的在未知的線程中使用他。

自己要獲得一個FILE_OBJECT必須自己發送IRP_MJ_CREATE的IRP.這又不是一件輕鬆的事情。不過我跳過了這個問題。因為我是檔案系

統過濾驅動,所以我從上面發來的IRP中得到FILE_OBJECT,然後再構造自己的IRP使用這個FILE_OBJECT,我發現運行很好。

但是又出現一個問題,如果IRP的irp->Flags中有IRP_PAGING(或者說是Cache管理器所發來的IRP)標記,則其FileObject我獲得並使

用後,老是返回錯誤。閱讀網上的經驗表明,帶有IRP_PAGINGE的FileObject不可以使用.於是我避免使用這時的FileObject.我總是使用不帶

IRP_PAGING的Irp(認為是使用者程式發來的讀請求)的FileObject。

好,現在廢話很多了,現在來看看構造irp的代碼:

_inline wd_irp *wd_irp_fsd_read_alloc(wd_dev *dev,
wd_void *buf,
wd_ulong length,
wd_lgint *offset,
wd_io_stat_block *io_stat)
{
return IoBuildAsynchronousFsdRequest(IRP_MJ_READ,dev,
buf,length,
offset,
io_stat);
}

io_stat我不知道是做何用,我一般填寫NULL.類型是PIO_STATUS_BLOCK.buf則是緩衝。在Irp中被用做UserBuffer接收資料。offset是

這次讀的位移量。

以上函數構造一個讀irp.請注意,此時您還沒有設定FileObject.實際上我是這樣發出請求的:

irp = wd_irp_fsd_read_alloc(dev,buf,len,&start,NULL);
if(irp == NULL)
return;
irpsp = wd_irp_next_sp(irp);
wd_irpsp_file_set(irpsp,file);
wd_irp_comp(irp,my_req_comp,context);

請注意wd_irp_next_sp,我是得到了這個irp的下一個IO_STACK_LOCATION,然後我設定了FileObject.接下來應該設定了完成後,我就

可以發送請求了!請求發送完畢後,一旦系統完成請求就會調用你的my_req_comp.

再看看my_req_comp如何收場:

wd_stat my_req_comp(in wd_dev *dev,
in wd_irp *irp,
in wd_void *context)
{

// 請注意,無論成功還是失敗,我都得在這裡徹底銷毀irp
wd_irp_send_by_myself_free(irp);

// 返回這個,僅僅是因為irp我已經銷毀,不想讓系統再次銷毀它而已。
return wd_stat_more_processing;
}

wd_stat_more_prcessing就是STATUS_MORE_PROCESSING_REQUIRED。之所以返回這個,是因為我已經把irp給刪除了。我不想windows系

統再對這個irp做什麼。所以乾脆說我還要繼續處理,這樣避免了io管理器再去動用這個irp的可能。

最後是那個irp刪除函數的代碼:

_inline wd_void wd_irp_send_by_myself_free(wd_irp *irp)
{
if (irp->MdlAddress)
{
MmUnmapLockedPages(MmGetSystemAddressForMdl(irp->MdlAddress),
irp->MdlAddress);
MmUnlockPages(irp->MdlAddress);
IoFreeMdl(irp->MdlAddress);
}
IoFreeIrp(irp);
};

因為我自己沒有分配過MdlAddress下去過。所以如果下邊返回了MDL,我得附帶清理它。

好了,祝願你心情愉快。如果你何我一樣懶惰的話,不妨就用上邊的簡單方法自己發irp來讀檔案了。

相關文章

聯繫我們

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