一、何謂文件系統過濾驅動?
文件系統過濾驅動是一種可選的,為文件系統提供具有附加值功能的驅動程序。文件系統過濾驅動是一種核心模式組件,它作為Windows NT執行體的一部分運行。
文件系統過濾驅動可以過濾一個或多個文件系統或文件系統卷的I/O操作。按不同的種類劃分,文件系統過濾驅動可以分成日志記錄、系統監測、數據修改或事件預防幾類。通常,以文件系統過濾驅動為核心的應用程序有防毒軟件、加密程序、分級存儲管理系統等。
二、文件系統過濾驅動並不是設備驅動
設備驅動是用來控制特定硬件I/O設備的軟件組件。例如:DVD存儲設備驅動是一個DVD驅動。
相反,文件系統過濾驅動與一個或多個文件系統協同工作來處理文件I/O操作。這些操作包括:創建、打開、關閉、枚舉文件和目錄;獲取和設置文件、目錄、卷的相關信息;向文件中讀取或寫入數據。另外,文件系統過濾驅動必須支持文件系統特定的功能,例如緩存、鎖定、稀疏文件、磁盤配額、壓縮、安全、可恢復性、還原點和卷裝載等。
下面兩部分詳細的闡述了文件系統過濾驅動和設備驅動之間的相似點與不同點。
三、安裝文件系統過濾驅動 對於Windows XP和後續操作系統來說,可以通過INI文件或安裝應用程序來安裝文件系統過濾驅動(對於Windows 2000和更早的操作系統,過濾驅動通常通過服務控制管理器Service Control Manager來進行安裝)。
四、初始化文件系統過濾驅動與設備驅動類似,文件系統過濾驅動也使用DriverEntry例程進行初始化工作。
在驅動程序加載後,加載驅動相同的組件將通過調用驅動程序的 DriverEntry例程來對驅動程序進行初始化工作。對於文件系統過濾驅動來說,加載和初始化過濾驅動的系統組件為I/O管理器。
DriverEntry例程運行於系統線程上下文中,其IRQL = PASSIVE_LEVEL。本例程可分頁,詳細信息參見MmLockPagableCodeSection。
DriverEntry例程定義如下:
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
本例程有兩個輸入參數。第一個參數,DriverObject為系統在文件系統過濾驅動加載時所創建的驅動對象;第二個參數,RegistryPath為包含驅動程序注冊鍵路徑的Unicode字符串。
文件系統過濾驅動按如下順序執行DriverEntry例程:
01、創建控制設備對象:
文件系統過濾驅動的DriverEntry例程通常以創建控制設備對象作為該例程的起始。創建控制設備對象的目的在於允許應用程序即使在過濾驅動加載到文件系統或卷設備對象之前也能夠直接與過濾驅動進行通信。
注意:文件系統也會創建控制設備對象。當文件系統過濾驅動將其自身附加到文件系統之上時(而不是附加到某一特定文件系統卷),過濾驅動同樣將其自身附加到文件系統的控制設備對象之上。
pan>在FileSpy驅動范例中,控制設備對象按如下方式創建:
RtlInitUnicodeString(&nameString, FILESPY_FULLDEVICE_NAME);
status = IoCreateDevice(
DriverObject, //DriverObject
0, //DeviceExtensionSize
&nameString, //DeviceName
FILE_DEVICE_DISK_FILE_SYSTEM, //DeviceType
FILE_DEVICE_SECURE_OPEN, //DeviceCharacteristics
pan>
FALSE, //Exclusive
&gControlDeviceObject); //DeviceObject
RtlInitUnicodeString(&linkString, FILESPY_DOSDEVICE_NAME);
status = IoCreateSymbolicLink(&linkString, &nameString);
與文件系統不同,文件系統過濾驅動並不是一定要為其控制設備對象命名。如果傳遞給
DeviceName參數一個非空
(Non-NULL)值,該值將作為控制設備對象的名稱。接下來,在前面的代碼范例中DriverEntry可以調用IoCreateSymbolicLink例程來將該對象的核心模式名稱與應用程序可見的用戶模式名稱關聯到一起(同樣可以通過調用IoRegisterDeviceInterface來使設備對象對應用程序可見)。
注意:由於控制設備對象是唯一不會附加到設備堆棧中的設備對象,因此控制設備對象是唯一的可安全命名的設備對象。由此,是否為文件系統過濾驅動的控制設備對象是否命名是可選的。
注意:文件系統的控制設備對象必須命名。過濾設備對象從不命名。
參數DeviceType代表某種設備類型,其可能的取值均以常量形式定義在ntifs.h中,例如: FILE_DEVICE_DISK_FILE_SYSTEM。
如果向DeviceName傳遞了一個非空值(Non-NULL),DeviceCharacteristics標識必須包括 FILE_DEVICE_SECURE_OPEN。該標識指示I/O管理器對所有發送到控制設備對象的Open請求進行安全檢測。
文件系統過濾驅動在分派例程中識別其自身控制設備對象的有效方式為將設備指針與前期存儲的全局控制設備對象指針進行比較。因此FileSpy驅動范例將 IoCreateDevice所返回的設備對象指針存儲到了全局變量gControlDeviceObject中。
02、注冊IRP分派例程: 過濾驅動DriverEntry例程中的DriverObject參數提供了一個指向過濾驅動的驅動對象的指針。為了注冊I/O請求包(IRP)的分派例程,必須為主功能碼注冊分派例程的入口點。
例如:FileSpy驅動范例按下列方式設置分派例程入口點:
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = SpyDispatch;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = SpyCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SpyClose;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = SpyFsControl;
注意:在上面的For循環為每個IRP主功能碼分派例程都分派了默認的分派例程。這是一個比較好的做法,因為,默認情況下,I/O管理器完成未知IRP並返回STATUS_INVALID_DEVICE_REQUEST。文件系統過濾驅動在這種方式下不會拒絕未知的IRP,這些請求將發送給低層驅動。由於這個原因,默認分派例程僅向下層傳遞IRP。
03、注冊Fast I/O分派例程: 過濾驅動DriverEntry例程的DriverObject參數提供了指向過濾驅動驅動對象的指針。
-SIZE: 10pt">為了注冊文件系統過濾驅動的Fast I/O分派例程,必須分配並初始化Fast I/O分派表,向該表中存儲Fast I/O分派例程,然後將該分派表的地址存儲到驅動對象的FastIoDispatch成員中。
例如:FileSpy驅動范例按下述方式為Fast I/O分派例程設置入口點:
RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
fastIoDispatch->FastIoCheckIfPossible = SpyFastIoCheckIfPossible;
fastIoDispatch->FastIoRead = SpyFastIoRead;
fastIoDispatch->FastIoWrite = SpyFastIoWrite;
fastIoDispatch->FastIoQueryBasicInfo = SpyFastIoQueryBasicInfo;
fastIoDispatch->FastIoQueryStandardInfo = SpyFastIoQueryStandardInfo;
fastIoDispatch->FastIoLock = SpyFastIoLock;
fastIoDispatch->FastIoUnlockSingle = SpyFastIoUnlockSingle;
fastIoDispatch->FastIoUnlockAll = SpyFastIoUnlockAll;
fastIoDispatch->FastIoUnlockAllByKey = SpyFastIoUnlockAllByKey;
fastIoDispatch->FastIoDeviceControl = SpyFastIoDeviceControl;
fastIoDispatch->FastIoDetachDevice = SpyFastIoDetachDevice;
fastIoDispatch->FastIoQueryNetworkOpenInfo = SpyFastIoQueryNetworkOpenInfo;
fastIoDispatch->MdlRead = SpyFastIoMdlRead;
NT-SIZE: 9pt">fastIoDispatch->MdlReadComplete = SpyFastIoMdlReadComplete;
fastIoDispatch->PrepareMdlWrite = SpyFastIoPrepareMdlWrite;
fastIoDispatch->MdlWriteComplete = SpyFastIoMdlWriteComplete;
fastIoDispatch->FastIoReadCompressed = SpyFastIoReadCompressed;
fastIoDispatch->FastIoWriteCompressed = SpyFastIoWriteCompressed;
fastIoDispatch->MdlReadCompleteCompressed = SpyFastIoMdlReadCompleteCompressed;
fastIoDispatch->MdlWriteCompleteCompressed = SpyFastIoMdlWriteCompleteCompressed;
fastIoDispatch->FastIoQueryOpen = SpyFastIoQueryOpen;
DriverObject->FastIoDispatch = fastIoDispatch;
04、注冊FsFilter回調例程: FsFilter通知回調例程在下層文件系統執行某些操作之前或之後調用。如果需要獲取更多有關於FsFilter回調例程相關信息,可參見FsRtlRegisterFileSystemFilterCallbacks例程
為了注冊FsFilter的通知回調例程必須分配並初始化FS_FILTER_CALLBACKS結構體,然後向該結構體中促出FsFilter回調例程,並將存儲有Callbacks parameter到FsRtlRegisterFileSystemFilterCallbacks中。
E: 10pt">例如:FileSpy驅動范例按如下方式注冊FsFilter回調。
fsFilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS);
fsFilterCallbacks.PreAcquireForSectionSynchronization = SpyPreFsFilterOperation;
fsFilterCallbacks.PostAcquireForSectionSynchronization = SpyPostFsFilterOperation;
fsFilterCallbacks.PreReleaseForSectionSynchronization = SpyPreFsFilterOperation;
fsFilterCallbacks.PostReleaseForSectionSynchronization = SpyPostFsFilterOperation;
fsFilterCallbacks.PreAcquireForCcFlush = SpyPreFsFilterOperation;
fsFilterCallbacks.PostAcquireForCcFlush = SpyPostFsFilterOperation;
fsFilterCallbacks.PreReleaseForCcFlush = SpyPreFsFilterOperation;
fsFilterCallbacks.PostReleaseForCcFlush = SpyPostFsFilterOperation;
fsFilterCallbacks.PreAcquireForModifIEdPageWriter = SpyPreFsFilterOperation;
fsFilterCallbacks.PostAcquireForModifIEdPageWriter = SpyPostFsFilterOperation;
fsFilterCallbacks.PreReleaseForModifIEdPageWriter = SpyPreFsFilterOperation;
fsFilterCallbacks.PostReleaseForModifIEdPageWriter = SpyPostFsFilterOperation;
status = FsRtlRegisterFileSystemFilterCallbacks(DriverObject, &fsFilterCallbacks);
05、執行其它必要的初始化工作: 在注冊完IRP和Fast I/O分派例程之後,
文件系統過濾驅動的DriverEntry例程需要初始化其它該驅動所需的全局變量和數據結構。
06、注冊回調例程【可選】:
過濾驅動可以通過調用IoRegisterFsRegistrationChange例程來注冊用來偵聽在文件系統調用 IoRegisterFileSystem或IoUnregisterFileSystem注冊或卸載自身時所觸發事件的回調例程。過濾驅動通過注冊這個回調函數來發覺新的文件系統加載事件,然後,過濾驅動將自身附加到這個新的文件系統之上。
注意:文件系統過濾驅動不可能調用IoRegisterFileSystem或IoUnregisterFileSystem例程。這兩個例程都是專為文件系統提供服務的。
過濾驅動並不是在調用IoRegisterFsRegistrationChange時加載到卷之上,它必須在偵測到卷以後才能進行加載(例如,通過一個用戶模式應用程序)。注意:過濾驅動使用該例程來獲得在卷裝在後立即附加到該卷之上的能力。使用該例程時,並不能保證過濾驅動將直接附加到卷設備對象之上。其余部分未翻譯,如下: But it does ensure that such a filter attaches before (and thus below) any filter that instead waits for a command from a user-mode application, because filters can attach only at the top of the current file system volume device stack.
07、存儲注冊表路徑字符串拷貝【可選】:
注意:本步驟是過濾驅動在執行DriverEntry例程之後,需要使用注冊表路徑時所必須的。
其余部分未翻譯,如下:Save a copy of the RegistryPath string that was passed as input to DriverEntry. This parameter points to a counted Unicode string that specifIEs a path to the driver's registry key,
\Registry\Machine\System\CurrentControlSet\Services\DriverName, where
DriverName is the name of the driver. If the RegistryPath string will be needed later, DriverEntry must save a copy of it, not just a pointer to it, because the pointer is no longer valid after the DriverEntry routine returns.
08、返回狀態:
文件系統過濾驅動的DriverEntry例程通常會返回STATUS_SUCCESS。然而,如果驅動初始化失敗,DriverEntry會向返回一個適當的狀態值。
如果DriverEntry例程返回了一個指示未成功的狀態值,系統將卸載該驅動。因此,DriverEntry例程必須在返回錯誤代碼之前釋放那些自己所分配的內存和所獲取的諸如設備對象之類系統資源。
五、附加過濾驅動到文件系統或卷之上文件系統過濾驅動將其自身附加到一個或多個已裝載卷之上,並過濾發送給這些卷的I/O操作。下面將以Windows Driver Kit (WDK)中的范例來說明通常會采用的兩種方式:
· 文件系統過濾驅動可以附加到終端用戶指定需要過濾的卷,比如鍵入卷的驅動符。
用戶命令將傳遞給過濾驅動一個私有的IRP_MJ_DEVICE_CONTROL請求。FileSpy驅動范例在全局變量gFileSpyAttachMode設置為FILESPY_ATTACH_ON_DEMAND時,采用這種方式(默認情況下, gFileSpyAttachMode將設置為FILESPY_ATTACH_ALL_VOLUMES)。
· 文件系統過濾驅動可以附加到一個或多個文件系統驅動之上,監聽 IRP_MJ_FILE_SYSTEM_CONTROL、IRP_MN_MOUNT_VOLUME請求,並附加到文件系統所裝載的卷之上。SFilter 就驅動范例使用這種方式。FileSpy驅動范例在全局變量gFileSpyAttachMode被設置為 FILESPY_ATTACH_ALL_VOLUMES(默認值)采取這種方式。
注意:通常需要假定卷和文件系統驅動的關系為一對多,而不是一對一。這是由於某些高級存儲功能,例如動態卷和卷裝載點等所造成的。
注意:不要將定文件系統會一直以同步方式處理IRP_MN_MOUNT_VOLUME請求。例如,輔助存儲器可能異步的進行裝載。因此,過濾驅動需要在Mount Completion例程中傳遞PendingReturned標識。如果需要獲取更多信息,可查閱DDK在線文檔的
“PendingReturned Flag”部分。
文件系統過濾驅動可以附加並過濾文件系統卷。但是它們無法直接附加到諸如磁盤驅動或分區等存儲設備之上,同樣他們也無法附加到單獨的目錄或文件之上。
如果需要獲取更多信息,可參見下面章節:
01、創建過濾設備對象 調用IoCreateDevice例程來創建用來附加到卷或文件系統堆棧上的過濾設備對象,在FileSpy范例中,以下述方式進行該工作:
status = IoCreateDevice(
gFileSpyDriverObject, //DriverObject
sizeof(FILESPY_DEVICE_EXTENSION), //DeviceExtensionSize
NULL, //DeviceName
DeviceObject->DeviceType, //DeviceType
0, //DeviceCharacteristics
FALSE, //Exclusive
&newDeviceObject); //DeviceObject
在上面的代碼片段中,DeviceObject為指向過濾驅動所需要附加到的目標設備的設備對象,而newDeviceObject為指向過濾驅動自身的設備對象的指針。
為了為過濾設備對象的設備擴展數據結構體分配存儲空間,因此需要將DeviceExtensionSize參數設置為10pt">sizeof (FILESPY_DEVICE_EXTENSION)。新創建的過濾設備對象的設備擴展成員將設置為指向該數據結構的指針。文件系統過濾驅動通常為每個過濾設備對象定義並分配設備擴展。設備擴展的數量和結構均由驅動指定。然而,在MS Windows XP以及後續操作系統之上,過濾驅動所定義的設備擴展結構DEVICE_EXTENSION至少需要包含下述成員:PDEVICE_OBJECT AttachedToDeviceObject。
在上面調用IoCreateDevice時,由於過濾設備對象並沒有命名,因此將DeviceName參數設置為NULL。由於過濾設備對象需要附加到文件系統或卷設備堆棧之上,因此,為過濾設備對象分配一個名字將造成系統安全漏洞。
DeviceType參數必須始終設置為過濾設備對象所附加到的目標(文件系統或過濾)設備對象。按照此方法傳遞設備類型是非常重要的,這是因為它將由I/O Manager使用,並傳回給應用程序。
注意:文件系統和文件系統過濾驅動從來不會將DeviceType參數設置為FILE_DEVICE_FILE_SYSTEM。該值並不是一個有效參數值(FILE_DEVICE_FILE_SYSTEM常量僅在定義FSCTL時使用)。
DeviceType參數非常重要的其它原因是,許多過濾驅動僅僅附加到某些特定的文件系統之上。例如,一個特殊的過濾驅動將會附加到本地磁盤文件系統之上,而並不附加到CD-ROM文件系統或遠程文件系統之上。這些過濾驅動測試最文件系統或卷設備堆棧中最高層設備對象的DeviceType參數。在大多數情況下,最高層設備對象為一個過濾設備對象。
文章整理:<strong>這就是為什麼過濾驅動的Device Type參數需要同下層文件系統或卷設備對象的該參數一致的原因。
02、將過濾設備對象附加到目標設備對象之上 通過調用IoAttachDeviceToDeviceStackSafe來將過濾設備對象附加到目標文件系統或卷的過濾設備堆棧之中。
devExt = filespyDeviceObject->DeviceExtension;
status = IoAttachDeviceToDeviceStackSafe(
filespyDeviceObject, //SourceDevice
DeviceObject, //TargetDevice
&devext->AttachedToDeviceObject); //AttachedToDeviceObject
注意:在有其它過濾驅動已經附加到目標設備對象之上時,AttachedToDeviceObject輸出參數接收到的設備對象指針可以與TargeDevice不同。
通過名稱附加到文件系統之上
每種文件系統需要創建一個或多個已命名控制設備對象。如果需要直接附加到文件系統之上,文件系統過濾驅動需要傳遞給 IoGetDeviceObjectPointer傳遞該特定文件系統控制設備對象的名稱來獲取該設備對象的指針。下列代碼范例顯示了如何獲取RAW文件系統的兩個控制設備對象中的一個的方法:
RtlInitUnicodeString(&nameString, L"\\Device\\RawDisk");
status = IoGetDeviceObjectPointer(
&nameString, //ObjectName
FILE_READ_ATTRIBUTES, //DesiredAccess
&fileObject, //FileObject
&rawDeviceObject); //DeviceObject
if (NT_SUCCESS(status)) {
ObDereferenceObject(fileObject);
}
如果調用IoGetDeviceObjectPointer成功,文件系統過濾驅動調用IoAttachDeviceToDeviceStackSafe方法來附加到前述方法返回的控制設備對象之上。
注意:除了控制設備對象指針(rawDeviceObject)以外,IoGetDeviceObjectPointer還會返回一個指向向用戶模式應用表現該控制設備對象的文件對象的指針(fileObject)。在上述代碼范例中,並不需要文件對象,因此通過調用ObDereferenceObject關閉了該文件對象。
下面沒有翻譯:It is important to note that decrementing the reference count on the file object returned by IoGetDeviceObjectPointer causes the reference count on the device object to be decremented as well. Thus the fileObject and rawDeviceObject pointers should both be considered invalid after the above call to ObDereferenceObject, unless the reference count on the device object is incremented by an additional call to ObReferenceObject before ObDereferenceObject is called for the file object.
03、傳遞DO_BUFFERED_IO和DO_DIRECT_IO標識 在過濾設備對象成功的附加到文件系統或卷之上以後,
下面沒有翻譯:always be sure to set or clear the DO_BUFFERED_IO and DO_DIRECT_IO flags as needed so that they match the values of the next-lower device object on the driver stack. (For more information about these flags, see Methods for Accessing Data Buffers.) In the FileSpy sample, this is done as follows:
if (FlagOn( DeviceObject->Flags, DO_BUFFERED_IO ))
{
SetFlag( filespyDeviceObject->Flags, DO_BUFFERED_IO );
}
if (FlagOn( DeviceObject->Flags, DO_DIRECT_IO ))
{
SetFlag( filespyDeviceObject->Flags, DO_DIRECT_IO );
}
在上述代碼片段中,DeviceObject為一個過濾設備對象附加到的設備對象的指針, filespyDeviceObject為指向過濾設備對象自身的指針。
04、傳遞FILE_DEVICE_SECURE_OPEN標識 在過濾設備對象成功附加到文件系統(並非卷)設備對象之上以後,
下面沒有翻譯:always be sure to set the FILE_DEVICE_SECURE_OPEN flag on the filter device object as needed to so that it matches the value of the next-lower device object on the driver stack. (For more information about this flag, see Specifying Device Characteristics in the Kernel Architecture Design Guide and DEVICE_OBJECT in the Kernel Reference.)在FileSpy驅動范例中,實現方式如下:
if (FlagOn( DeviceObject->Characteristics, FILE_DEVICE_SECURE_OPEN ))
{
SetFlag( filespyDeviceObject->Characteristics, FILE_DEVICE_SECURE_OPEN );
}
在上述代碼片段中,DeviceObject>為一個過濾設備對象附加到的設備對象的指針, filespyDeviceObject為指向過濾設備對象自身的指針。
05、清除DO_DEVICE_INITIALIZING標記: 在過濾設備對象附加到文件系統或卷之上以後,,需要確保清除過濾設備對象的DO_DEVICE_INITIALIZING標識。在FileSpy驅動范例中,以如下方式實現:
ClearFlag(NewDeviceObject->Flags, DO_DEVICE_INITIALIZING);
在過濾設備對象創建以後,IoCreateDevice為設備對象設置DO_DEVICE_INITIALIZING標識。在過濾驅動成功進行附加以後,這個標識必須被清除掉。
注意:如果本標識沒有被清除,其它過濾驅動將無法再次附加到該過濾鏈中,因為,此時調用IoAttachDeviceToDeviceStackSafe將失敗。
注意:在DriverEntry例程中創建的設備對象,並不需要必須清除DO_DEVICE_INITIALIZING標識,這是因為這個工作將會由I/O管理器自動完成。然而,如果創建了其它設備對象,則需要進行該清除工作。 1、文件系統過濾驅動同設備驅動的相似點:
下列部分描述了Windows操作系統中文件系統過濾驅動和設備驅動之間的相似點:
(t">1)、類似的結構 類似於設備驅動,文件系統過濾驅動有著屬於自己的DriverEntry、Dispatch和I/O組件例程。文件系統過濾驅動同設備驅動一樣調用許多相同的系統核心例程,它們都會過濾發送給它們所關聯的設備的I/O請求。
(2)、類似的功能: 文件系統過濾驅動和設備驅動都是I/O子系統的組成部分,因此它們都接收和作用於I/O請求包(IRP)。
類似於設備驅動,文件系統過濾驅動同樣可以創建它們自己的IRP並將該IRP發送到低層驅動。
這兩種驅動均可以通過注冊回調函數來接收多種系統事件的通知。
(3)、其它類似點: 同設備驅動類似,文件系統過濾驅動可以接收傳入的I/O控制碼(IOCTLs)。而且,文件系統過濾驅動還可以接收和定義
文件系統控制碼(FSCTLs>)。
同設備驅動類似,文件系統過濾驅動可以被配置為在系統引導過程中加載或者在系統啟動過程完成後加載。
2、文件系統過濾驅動同設備驅動之間的不同點: 下例部分描述了文件系統過濾驅動同設備驅動之間的不同點:
(1)、無需電源管理 由於文件系統過濾驅動並不是真正的設備驅動,而且它們不需要直接控制硬件設備,因此它們並不接收IRP_MJ_POWER請求。(電源管理IRP將直接發送到存儲設備堆棧中。但是,在非常罕見的情況下,文件系統過濾驅動有可能會影響到電源管理。)由此,文件系統過濾驅動並不注冊IRP_MJ_POWER相關例程,它們也不會調用PoXxx例程。
(2)、非WDM 文件系統過濾驅動並不是WDM驅動程序,WDM驅動模型僅適用於設備驅動。
(3)、沒有AddDevice</span>或StartIo例程 由於文件系統過濾驅動並不是設備驅動,而且它們並不直接控制硬件設備,因此它們沒有AddDevice或StartIo例程。
(4)、創建不同的設備對象 雖然文件系統過濾驅動和設備驅動均需要創建設備對象,但是它們所創建的設備對象的種類和數量都是不同的。
設備驅動創建物理和功能設備對象來描述設備。即插即用(PnP)管理器將構建一個設備樹來存放所有由設備驅動所創建的設備對象。文件系統過濾驅動所創建的設備對象,並不包含在這個設備樹中。
文件系統過濾驅動並不創建物理或功能設備對象,它們創建控制設備對象和過濾設備對象。控制設備對象對系統和用戶模式應用程序提供過濾驅動的描繪。過濾設備對象執行對指定文件系統或卷的實際過濾工作。文件系統過濾驅動通常創建一個控制設備對象和多個過濾設備對象。
(5)、其它不同點: 由於文件系統過濾驅動並不是設備驅動,因此他們將不會執行
直接內存訪問(DMA)。
與設備過濾驅動不同,設備過濾驅動可以附加到目標設備功能驅動的上層和下層,文件系統過濾驅動僅能附加到目標文件系統驅動的上層。因此在設備驅動隊列中,文件系統僅能進行上層過濾而無法進行下層過濾。