天天看點

讀懂常見IRP:IRP_MJ_CLEANUP/IRP_MJ_CLOSE/IRP_MJ_CREATE

IRP_MJ_CLEANUP 保持程序定義上下文資訊的驅動器,必須在DispatchCleanup中包含cleanup請求。 何時發送: 收到IRP_MJ_CLEANUP意味着請求的目标裝置與目标檔案的句柄相關(也可能因為io請求後沒有釋放) 入參: 無 出參: 無 操作: 該IRP在關閉 file object 句柄的程序上下文中發送。是以,驅動器應該釋放程序上下文中所指定的資源,比如之前驅動器鎖定或映射的user memory等。 如果驅動器的 device objects 狀态是exclusive,則該device是獨占性的,一次隻能為一個線程服務。驅動器必須結束目前目标 device object 隊列中的所有IRP,并設定其I/O status block為STATUS_CANCELLED。 另外,驅動器隻是需要取消并結束與待釋放的file object句柄相關的IRP隊列成員。(指向file object的指針位于驅動器IRP IO_STACK_LOCATION的FileObject成員中。)取消隊列中的IRP後,驅動器結束了clear up IRP操作,并将自身的I/O status block置為STATUS_SUCCESS。 //------------------------------------------------------------------------------------------ IRP_MJ_CLOSE 驅動器必須在DispatchClose中包含關閉請求和驅動器的可能發生的異常,因為該驅動器隻能通過關閉系統來解除安裝裝置,保持了系統分頁檔案的的磁盤驅動器就屬于這類驅動器。具有該類特性驅動器支援動态解除安裝。 何時發送: 收到IRP_MJ_CLOSE請求意味着與目标device object相關的file object句柄已經關閉或釋放。所有的外部I/O請求都已結束或取消。 入參: 無 出參: 無 操作: 很少有裝置會設定IRP的status block為STATUS_SUCCESS結束關閉請求。驅動器如何處理關閉請求取決于其設計。通常,驅動器在收到IRP_MJ_CREATE後會 undo自己的操作結果。device object為exclusive的驅動器,比如串行驅動器,在收到該請求後也可能會reset硬體。 IRP_MJ_CLOSE不是在關閉了file object句柄的程序上下文中發送的。如果驅動器必須釋放程序指定的資源,比如驅動器之前鎖定或映射的user memeory等,就會對IRP_MJ_CLEANUP請求做同樣的響應。 //------------------------------------------------------------------------------------------  IRP_MJ_CREATE kernel-mode驅動器必須在DispatchCreate或DispatchCreateClose中提出建立請求。 何時發送: 收到該請求意味着user-mode保護的子系統(可能代表的是某個應用程式),請求一個file object句柄,該局并代表特定的目标device object,或者是較進階别的驅動器正在連接配接器device object到目标device object。 入參: 無 出參: 無 操作: 與IRP_MJ_CLOSE類似,對IRP_MJ_CREATE的相應取決與驅動器的設計,很少有驅動器會設定IRP的I/O status block為STATUS_SUCCESS。帶有pageable-image單元的驅動器,像系統串行驅動器,會通過映射自身的page-out代碼, 來為那些嘗試打開裝置進行I/O操作的user-mode線程提供資源。 //------------------------------------------------------------------------------------------  IRP_MJ_DIRECTORY_CONTROL 何時發送: IRP_MJ_DIRECTORY_CONTROL請求是由I/O管理器和其他作業系統元件(比如kernel-mode驅動器)發送的。當user- mode程式調用ReadDirectoryChangesW、FindNextVolumeMountPoint或者kernal-mode componenet調用ZwQueryDirectoryFile時,會發送該請求。 操作:檔案系統驅動器 檔案系統驅動器通過檢查監控程式code來判斷判斷執行哪一個目錄控制操作。有效的監控程式codes: IRP_MN_NOTIFY_CHANGE_DIRECTORY 請求告知目錄變更。通常檔案系統驅動器會将此IRP放到私有的隊列中,而不是立即進行滿足該請求。 當目錄發生變更時,檔案系統驅動器執行通知目錄變更操作,出隊,結束該IRP。 IRP_MN_QUERY_DIRECTORY 目錄查詢請求。消息類型因檔案系統而異,通常包括以下幾種: FileBothDirectoryInformation FileDirectoryInformation FileFullDirectoryInformation FileIdBothDirectoryInformation FileIdFullDirectoryInformation FileNamesInformation FileObjectIdInformation FileReparsePointInformation 注意:FileQuotaInformation類已不再使用,用IRP_MJ_QUERY_QUOTA代替。 執行之後,結束IRP。 操作:檔案系統過濾驅動器 過濾驅動器将該IRP向棧上的下一層驅動器傳遞。 //------------------------------------------------------------------------------------------ IRP_MJ_QUERY_INFORMATION 何時發送: IRP_MJ_QUERY_INFORMATION請求的發送和IRP_MJ_DIRECTORY_CONTROL類似,是由I/O管理器和其他作業系統 元件(比如kernel-mode驅動器)發送的。調用GetFileInformationByHandle或 ZwQueryInformationFile時發送。 操作:檔案系統驅動器 檔案系統驅動器提取file object資訊并進行解析,由此判斷使用者是打開一個檔案還是打開一個目錄,這樣,驅動器處理查詢并結束IRP。如果不能對資訊進行提取解析,驅動器結束IRP,不處理查詢。 可供查詢的檔案和目錄資訊因檔案系統而異,通常包括如下幾種:

FileAllInformation

FileAttributeTagInformation

FileBasicInformation

FileCompressionInformation

FileEaInformation

FileInternalInformation

FileNameInformation

FileNetworkOpenInformation

FilePositionInformation

FileStandardInformation

FileStreamInformation
           

ZwQueryInformationFile支援FileAccessInformation, FileAlignmentInformation, 和 FileModeInformation 類型,而無需向檔案系統發送IRP_MJ_QUERY_INFORMATION請求,因為他們與檔案系統無關。 操作:檔案系統過濾驅動器 過濾驅動器将該IRP向棧上的下一層驅動器傳遞。 //------------------------------------------------------------------------------------------ IRP_MJ_QUERY_VOLUME_INFORMATION 何時發送: IRP_MJ_QUERY_VOLUME_INFORMATION請求由I/O管理器發送。當user-mode程式調用GetDiskFreeSpace或GetFileType時會發送該請求。 操作:檔案系統驅動器 檔案系統驅動器通過對file object進行提取和解碼,判斷目标device object是不是該檔案系統的control device object。如果是,并且請求的是打開volume(或者打開volume上的object),檔案系統驅動器會處理請求并結束IRP。如果不是,檔案 系統驅動器查詢失敗,結束IRP。 可供查詢的volume資訊類型因檔案系統而異,通常有如下幾種類型: FileFsAttributeInformation FileFsDeviceInformation FileFsSizeInformation FileFsVolumeInformation 操作:檔案系統過濾驅動器 過濾驅動器将該IRP向棧上的下一層驅動器傳遞。 //------------------------------------------------------------------------------------------ IRP_MJ_READ 向系統傳遞資料的驅動器必須在DispatchRead或DispatchReadWrite中包含read請求,在此類驅動器上分層的higher-level驅動器也必須這樣做。 何時發送: 在完成create請求的之後的時間域内發送。 可能由包含file object句柄(代表請求過從從該device傳遞資料的目标device object)的user-mode程式或win32元件發送。也可能由建立和設定read IRP的higher-level驅動器發送。 入參: IRP中的驅動器I/O stack位置訓示Parameters.Read.Length.傳送多少byte資料。 有些驅動器通過Parameters.Read.Key對在device queue或驅動器管理的IRP内部隊列中對read請求進行排序。有的驅動器通過Parameters.Read.ByteOffset(訓示傳送操作的offset)進行排序。 出參: 根據驅動器對device object Flag的是DO_BUFFERED_IO還是DO_DIRECT_IO,采用不同的方法傳遞資料: The buffer at Irp->AssociatedIrp.SystemBuffer if the driver uses buffered I/O The buffer described by the MDL at Irp->MdlAddress if the underlying device driver uses direct I/O (DMA or PIO) 操作: 接收到read請求之後,higher-level驅動器會通過為next-lower驅動器設定IRP中的I/O stack位置,或者為lower驅動器建立并設定附加的IRP。可以調用IoSetCompletionRoutine設定 IoCompletion(在IRP輸入中是可選的,但在driver-created IRP是必須的)。 接收到該請求之後,驅動器将器device傳送給系統memory。結束IRP的過程中,驅動器将設定I/O stack block為傳遞的byte數量。 //------------------------------------------------------------------------------------------ IRP_MJ_SET_INFORMATION 何時發送: IRP_MJ_SET_INFORMATION請求的發送和IRP_MJ_QUERY_INFORMATION、 IRP_MJ_DIRECTORY_CONTROL類似,是由I/O管理器和其他作業系統元件(比如kernel-mode驅動器)發送的。調用 SetEndOfFile或ZwSetInformationFile時發送。 操作:檔案系統驅動器 檔案系統驅動器提取file object資訊并進行解析,由此判斷使用者是打開一個檔案還是打開一個目錄,這樣,驅動器處理查詢并結束IRP。

可供設定的檔案、目錄屬性資訊如下:

FileBasicInformation

FileDispositionInformation

FileLinkInformation (for file systems that allow cycles to be created in the directory hierarchy) FilePositionInformation

FileRenameInformation



檔案專有屬性:

FileAllocationInformation

FileEndOfFileInformation

FileLinkInformation (for file systems, such as NTFS, that do not allow cycles to be created in the directory hierarchy)

FileValidDataLengthInformation
           

操作:檔案系統過濾驅動器 過濾驅動器将該IRP向棧上的下一層驅動器傳遞。 //------------------------------------------------------------------------------------------ IRP_MJ_SET_INFORMATION* IRP_MJ_SET_INFORMATION (Serial) 何時發送: client通過set information請求改變串行裝置上打開的檔案結尾位置時發送。 //------------------------------------------------------------------------------------------ IRP_MJ_WRITE 向系統傳遞資料的驅動器必須在DispatchWrite或DispatchReadWrite中包含write請求,在此類驅動器上分層的higher-level驅動器也必須這樣做。 何時發送: 成功結束creat請求的時間域内。 可能由包含file object句柄(代表請求過從從該device傳遞資料的目标device object)的user-mode程式或win32元件發送。也可能由建立和設定write IRP的higher-level驅動器發送。 入參: IRP中的驅動器I/O stack位置訓示Parameters.Write.Length.傳送多少byte資料。 有些驅動器通過Parameters.Write.Key對在device queue或驅動器管理的IRP内部隊列中對write請求進行排序。有的驅動器通過Parameters.write.ByteOffset(訓示傳送操作的offset)進行排序。 根據驅動器對device object Flag的是DO_BUFFERED_IO還是DO_DIRECT_IO,采用不同的方法傳遞資料: The buffer at Irp->AssociatedIrp.SystemBuffer, if the driver uses buffered I/O The buffer described by the MDL at Irp->MdlAddress, if the underlying device driver uses direct I/O (DMA or PIO) 出參: 無 操作: 接收到write請求之後,higher-level驅動器會通過為next-lower驅動器設定IRP中的I/O stack位置,或者為lower驅動器建立并設定附加的IRP。可以調用IoSetCompletionRoutine設定 IoCompletion(在IRP輸入中是可選的,但在driver-created IRP是必須的)。之後,驅動器通過IoCallDriver傳遞請求給next-lower驅動器。 接收到該請求之後,驅動器将資料從系統memory傳遞到自身的device。結束IRP的過程中,驅動器将設定I/O stack block為傳遞的byte數量。 //------------------------------------------------------------------------------------------ IRP_MJ_WRITE* 分段寫入,提供Offset,每次寫入65536位元組。