散分300:庆祝文件过滤驱动开发包完成 (300分)

  • 主题发起人 主题发起人 爱元元的哥哥
  • 开始时间 开始时间
祝贺!学习
 
在没有资料参考的情况下写出一个驱动来是非常不容易的;
对某些高手来说或许很简单,不过你有没有想过你自己第一次写驱动的艰苦历程啊!
我很菜,可是这些还是懂的^0^
别忘了给我分啊!老大
 
我不要分,我要你的那些资料,整理出来后一定告诉兄弟一声。
 
贴一个文件驱动重要的Fast IO的资料
Fast I/O
1996-1997 OSR Open Systems Resources, Inc.

This article has been updated since its original date of publication.
The standarddo
gma for Windows NT kernel mode development is that NT uses the I/O Request Packet (IRP) as the basis of communications with drivers – the advantage of the I/O Request packet is that it encapsulates the context needed for a particular operation and allows abstraction of the driver away from many of the details common to drivers.
While this approach is very general and extensible – allowing for the cleanly layered Windows NT device architecture, there is a fair amount of overhead involved for operations where the request can be satisfied quickly. In that instance, the overhead associated with creating an IRP cando
minate the cost of the entire operation – slowing the systemdo
wn in performance critical areas. Because of this, the NT team introduced the concept of fast I/O. This approach to I/O is used by some file system drivers, such as NTFS, HPFS, FAT, and CDFS as well as the AFD transport driver which is used by WinSock.
Any driver can register a set of fast I/O entry points but their use is often extremely limited – requiring that just the right conditions be met before a particular fast I/O entry point will even be called. For example, both the read and write fast I/O entry points are only called when information about the particular file is being maintained by the cache manager in Windows NT. We will describe these restrictions later in this article.
Of course the most frustrating aspect of fast I/O for Windows NT is the total lack of availabledo
cumentation – even the file system development kitdo
es not provide a description of how fast I/O works or how to use it. In this article we will provide the rationale for fast I/O, a brief description of the various fast I/O calls, and conclude with some suggestions on how to use this interface to improve performance for your project.
Rationale
The rationale for providing Fast I/O seems to be one of convenience – many I/O operations are repeatedly performed against the same data. For example, like most modern operating systems, Windows NT integrates file system caching with the virtual memory system – using the system memory as a giant cache for file system information. Such systems are extremely efficient and boost both the actual and perceived performance of the system.
A second reason for this integration is Windows NT’s support for memory-mapped files. Supporting both read/write access and memory mapped file access to the same data, requires either a high cost (and hence low performance) cache consistency scheme or the scheme used by NT – where all data is stored in the virtual memory system. This ensures that data is always consistent – even between two programs accessing the same data using different access techniques.
This tight integration means that both read and write operations can often be satisfied from this cached data. In the search for performance, then
, this fact can be exploited for read and write by simply calling a specialized routine which moves data from the VM cache into the user’s memory, or vice versa. This eliminates the need to allocate an I/O request packet since the operation can be satisfied synchronously and need not call into lower drivers. It is this fundamental model which is realized by the fast I/O operations.
Once these fast I/O entry points have been created to provide added performance for read and write, it is only a small additional step to adding other commonly performed operations to the list as well – and over time, this list has grown to its current (as of NT 3.51) list of thirteen entry points. As we describe each of these entry points, it will become obvious that most of them really are geared specifically towards supporting file systems and fast I/O. These entries are contained in the FAST_IO_DISPATCH structure as described in ntddk.h. The first element of this structure describes the size of the structure, providing a straight-forward mechanism for adding new elements to this data structure in the future in a compatible fashion.
The I/O Manager and Fast I/O
The I/O Manager is responsible for calling the fast I/O entry points, as necessary. The model it uses is actually straight-forward for almost all the calls – the fast I/O entry points return either TRUE or FALSE indicating whether or not the fast I/O operation was completed. If it was not completed, or if fast I/O wasn’t available, an IRP is created and sent to the top level driver. The last three entry points in the FAST_IO_DISPATCH structure actuallydo
not fit this model, however. Rather they provide slightly different services for the I/O manager. We will discuss them later in this article.
FastIoCheckIfPossible
The first call in the FAST_IO_DISPATCH structure is only used by file systems as part of the common file system runtime library (the FsRtl routines).. The prototype for this routine is:
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
);
This routine is only used for read and write operations. As such, it is called by the generic fast I/O routines provided in the FsRtl library to allow the specific file system to ascertain if a read or write (depending upon the value of the Boolean CheckForReadOperation parameter) can be satisfied from the file cache, while using a generic implementation of managing the file system cache. Note that the parameters to this call are extremely similar to those for the read and write fast I/O entry points – except that this routinedo
es not have any data buffer associated with it.
FastIoRead and FastIoWrite
This routine is called by the I/O manager whenever a read request is made for a file which has valid cached data associated with it. The prototype for this routine is:
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
);
As we noted previously, the basic parameters to this call are extremely similar to those used by FastIoCheckIfPossible, with this call having the necessary data buffer. All of these entry points are guaranteed that the passed in parameters have been validated so that, for instance, the buffer pointer is valid and available for reading in the calling thread’s context.
The fast I/O routine cando
one of two things: it can complete the operation, set the IoStatus field to indicate the result codes for the operation and return TRUE to the I/O manager. If that is the case, the I/O manager will complete the I/O operation. Alternatively, the routine can return FALSE, in which case the I/O manager will simply create an IRP and call the standard dispatch entry point.
Note that returning TRUEdo
esn’t always guarantee the data has been transferred. For example, a read which starts past the end of file causes the IoStatus.Results field to be set to STATUS_END_OF_FILE, with no data copied. A read which crosses over the end of file will cause a TRUE to be returned, again with STATUS_END_OF_FILE set in the Results field, but this time with all remaining data in the file copied to the buffer.
Similarly, returning FALSEdo
esn’t always guarantee that some data has not been transferred. While less likely, it is possible for some data to be successfully copied but then
to experience an I/O error, or to have the memory of the buffer become inaccessible.
In either case a number of secondary effects can occur. For example, while reading from the cache, it is possible that some of the data being read is not currently resident. This will result in a page fault which will result in a call back into the file system to satisfy the page fault.
The only difference for the write case is that the Buffer argument is IN rather than OUT. The basic processing model is very similar. Of course, some error conditions are different – the media could be full, new pages may need to be allocated, etc.
FastIoQueryBasicInfo and FastIoQueryStandardInfo
These operations provide support for the standard NtQueryInformationFile API operation, while FastIoQueryBasicInfo is also used for certain operations associated with NtCreateFile. The basic information includes information about when the file was created, when it was last accessed, when it was last modified, and any special attributes of the file – such as being a hidden file, a directory, or other appropriate attributes. The standard information includes information about the allocation size being used for the file, the current size of the file, the number of hard links to the file, an indication if deletion has been requested for the file, and an indicator if this particular file is a directory.
Because this information is often cached in memory, it is a perfect candidate for fast I/O operations. Indeed, many standard utilities probe this information on a routine basis, which means that enhancing the performance of these operations will substantially increased the perceived performance of utilities, such as the File Manager (winfile.exe).
The two fast I/O routines have the same interface:
typedef BOOLEAN (*PFAST_IO_QUERY_BASIC_INFO) (
IN struct _FILE_OBJECT *FileObject,
IN BOOLEAN Wait,
OUT PFILE_BASIC_INFORMATION Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
The Wait parameter indicates if the caller is willing to block waiting for the requisite information. If this is set to FALSE then
the call must either complete without waiting, or must return FALSE – in which case a normal IRP can be created, including the necessary context for the full operation. Interestingly enough, it appears that in NT 3.51 neither of these entry points are called with Wait set to FALSE. Of course, this might change in future versions of NT.
Once invoked, these routines typically look at information they stored for the file when the FileObject was first opened. This information can also be reconstructed "on the fly" – for example, the last access time is set to the current system time by some file systems drivers. Of course, setting these values is determined by the file system implementation.
FastIoLock, FastIoUnlockSingle, FastIoUnlockAll, and FastIoUnlockAllByKey
These entry points are used to control lock state associated with a particular file. The locking being controlled by these calls is byte range locking against a single file. Thus, more than one byte range of a file can be locked. While not required, standard NT file systems utilize the services of the file system runtime package (the FsRtl routines) which provides a common code base for verifying that a requested lock can be granted and storing information about the lock ranges presently held on the file. Lock state can be controlled via the NT API calls NtLockFile as well as NtUnlockFile.
Locks in Windows NT are one of two types – either exclusive locks, meaning the locked byte range is locked for modification, or shared locks, meaning the locked byte range is locked for reads. Multiple shared locks can be granted against overlapping byte ranges, and each is then
stored until it is later released. Various pieces of information are stored about each lock so it can be acquired for rapid access later.
The interface for FastIoLock is:
typedef BOOLEAN (*PFAST_IO_LOCK) (
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN PLARGE_INTEGER Length,
PEPROCESS ProcessId,
ULONG Key,
BOOLEAN FailImmediately,
BOOLEAN ExclusiveLock,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
Thus, the FileOffest and Length parameters correspond to the byte range being locked by the caller. The ProcessId provides information to identify the process which took out the lock – allowing cleanup later, for instance, when that process exits. The Key parameter provides an opaque value which can be used to associate multiple locks together for rapid access via the FastIoUnlockAllByKey call, for example. FailImmediately indicates if the call should block until the lock is available, or should immediately return failure. For the FsRtl routine, FailImmediately is ignored – if the lock is not available, FALSE is returned to the caller. The ExclusiveLock parameter indicates if this lock request is for exclusive (write) access or shared (read) access.
The FastUnlockSingle routine is used to release the byte range locking on a portion of the file. The prototype for this call is:
typedef BOOLEAN (*PFAST_IO_UNLOCK_SINGLE) (
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN PLARGE_INTEGER Length,
PEPROCESS ProcessId,
ULONG Key,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
For most file systems, unless the file has associated Op Locks, this operation always returns TRUE, since even if the byte lock range is not accessible the operation has been completed (albeit with an error status). Since making the same call with an IRP would generate the same result, processing is completed at this stage.
For this unlock operation to succeed, the FileOffset, Length, ProcessId, and Key must all match an existing byte range lock. Otherwise, the operation should complete with the error STATUS_RANGE_NOT_LOCKED set in the IoStatus block which will then
be returned to the caller. The FastIoUnlockAll routine is used to release all byte range locks associated with a particular file being held by a particular process. The prototype for this function is:
typedef BOOLEAN (*PFAST_IO_UNLOCK_ALL) (
IN struct _FILE_OBJECT *FileObject,
PEPROCESS ProcessId,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
In this case, the fast I/O routine searches the available list of locks for the particular file and deletes any lock, whether exclusive or share, which is associated with the given ProcessId. This is used by the system when NtCloseFile is called, either because a program closed it or because a process was deleted.
The FastIoUnlockAllByKey operation is used to delete a set of byte range locks which have been logically associated by the caller using a particular key value. The prototype for this routine is:
typedef BOOLEAN (*PFAST_IO_UNLOCK_ALL_BY_KEY) (
IN struct _FILE_OBJECT *FileObject,
PVOID ProcessId,
ULONG Key,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
This call is provided for the benefit of file servers such as SRV. The I/O Manager in NT 3.51do
es not appear to make any use of this call. This key allows a file server to associate a file lock with some remote client. Since it may represent many such remote clients, the use of the ProcessId alone is not sufficient. Similarly, since there are multiple file servers, the use of the Key alone might cause the erroneous release of file locks for some other file server. Combining the two ensures correct operation and allows for remote system locking.
FastIoDeviceControl
This entry point is used for supporting the native NtDeviceIoControlFile call which is used essentially to implement private communications channels to kernel resident drivers. As with the other Fast I/O routines, this routine returns TRUE if the operation was completed, and FALSE otherwise. For the FALSE case, the I/O Manager creates an IRP and calls the dispatch entry point for the driver in question.
The prototype for FastIoDeviceControl is:
typedef BOOLEAN (*PFAST_IO_DEVICE_CONTROL) (
IN struct _FILE_OBJECT *FileObject,
IN BOOLEAN Wait,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength,
IN ULONG IoControlCode,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
Wait indicates if the caller is willing to wait for the operation to complete, although the Fast I/O routine may return FALSE even if Wait is set to TRUE. The InputBuffer points to an optional and potentially validated caller provided buffer which is considered "optional" from the perspective of this interface, although the implementation of the Fast I/O routine can return TRUE and indicate an error (e.g., STATUS_INVALID_PARAMETER) if the InputBuffer is missing or of the wrong length. The OutputBuffer points to memory which maybe validated, depending upon the access type for the IoControlCode value. If IoControlCode indicates an access type of 3, the OutputBuffer is not validated and the Fast I/O routine is responsible for its validation. Otherwise, the buffer is validated prior to calling the Fast I/O routine. This approach is identical to that used for the normal IRP_MJ_DEVICE_CONTROL dispatch entry point.
The implementation of this Fast I/O routine is dependent entirely upon the IoControlCode value passed to the FastIoDeviceControl routine. Typically, this entry point is associated with those kernel mode drivers which implement a rich private communications interface. Thus, none of the NT native file systems actually implement this entry point, but the WinSock support driver AFD uses this interface heavily for communications to the underlying transport drivers.
Thus, the actual model for these communications is dependent entirely upon the driver implementation of the Fast I/O routines.
AcquireFileForNtCreateSection and ReleaseFileForNtCreateSection
These two routinesdo
not fit the pattern established by the other entries in the Fast I/O dispatch table. Rather, they appear to have been used to resolve certain locking issues surrounding the HPFS file system (as of the four native NT file systems, only HPFS actually uses these entries). The prototype for these two calls is identical and quite simple:
typedef VOID (*PFAST_IO_ACQUIRE_FILE) (
IN struct _FILE_OBJECT *FileObject
);
The AcquireFileForNtCreateSection call is made prior to mapping in pages from a file stored within the file system to ensure that any driver-specific locking has beendo
ne. The ReleaseFileForNtCreateSection call is made to release the locks acquired earlier for the file mapping operation.
As it turns out, if these entry points are not provided, the I/O Manager utilizes a default mechanism for ensuring proper synchronization for the file mapping operations.
FastIoDetachDevice
This last routine is a most curious one. The ntddk.h filedo
es provide a hint as to the purpose of this call – namely, it is called when a device object is about to be deleted. We found this call is extremely useful when developing filter drivers for file systems, since the device objects of removable file systems are destroyed whenever the underlying media is changed. Sometimes this occurs immediately, but it can occur at almost any time after the media has been removed, depending upon what portions of the system are still caching information.
The prototype of this call is:
typedef VOID (*PFAST_IO_DETACH_DEVICE) (
IN struct _DEVICE_OBJECT *SourceDevice,
IN struct _DEVICE_OBJECT *TargetDevice
);
In our experience, a filter driver for removable media file systems must be able to handle this call as the system will halt otherwise.
[Note that the fast I/O calls beyond this point were not described in the original article.]
FastIoQueryNetworkOpenInfo
A common operation for the LanManager (CIFS) file server is to open a file and retrieve both its standard and basic attributes. This information is then
combined and sent to the remote client (the LanManager/CIFS redirector) so that it can be presented to the remote application programs.
Prior to NT 4.0, SRV was required to pass an IRP to the underlying file system multiple times to extract the same information. begin
ning with NT 4.0 a new information type, identified by the FileNetworkOpenInformation file information type, was added to the file systems interface so that a network file server, such as SRV, could extract this information in a single operation. To further speed this process, a corresponding fast I/O entry point was also added. The prototype for this is:
typedef BOOLEAN (*PFAST_IO_QUERY_NETWORK_OPEN_INFO) (
IN struct _FILE_OBJECT *FileObject,
IN BOOLEAN Wait,
OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer,
OUT struct _IO_STATUS_BLOCK *IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
As with the other fast I/O routines, the FileObject represents the file on which the caller is acting. The Wait parameter indicates if the caller is willing to block. If Wait is FALSE this routine should not block. The caller can then
use the standard IRP path to obtain this information from the file system. The Buffer argument points to the location where the data should be copied, and the IoStatus block points to the standard I/O status information. Finally, the DeviceObject represents the file system instance being queried.
Since this is used by SRV, this is only implemented by physical file systems.
FastIoAcquireForModWrite
This call was added to allow an alternate mechanism for locking the file prior to the Modified Page Writer in the memory manager actually performing I/O. This function is entirely optional - but if youdo
not implement it, the File System Runtime Library will us the ERESOURCE pointers in the common header of the file object to ensure correct synchronization (so your file system must be using the standard NT locking model.)
typedef NTSTATUS (*PFAST_IO_ACQUIRE_FOR_MOD_WRITE) (
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER EndingOffset,
OUT struct _ERESOURCE **ResourceToRelease,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject identifies the specific file to be locked, the EndingOffset indicates the highest byte in the file that the Modified Page Writer is going to write. You can use this information in your file system to synchronize anyone attempting to truncate the file during this operation. The ResourceToRelease is an optional parameter your FSD can return. If you return anything except a PERESOURCE you must also implement the complimentary entry point (FastIoReleaseForModWrite) which is described later in this article. The DeviceObject represents the file system instance.
FastIoMdlRead
This call was added to allow optimal performance for SRV (or other kernel resident services.) Prior versions of Windows NT allowed SRV to retrieve MDLs into the cache directly, but only when using the IRP path. This new entry point now provides a direct function call method for SRV to achieve the same results.
typedef BOOLEAN (*PFAST_IO_MDL_READ) (
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject uniquely identifies the file being read, while the FileOffset and Length arguments identify the region of the file being read. The LockKey is used to perform the correct mandatory byte range locking checks, as this read is an "application level" read. The MdlChain is one (or more) MDLs describing the cache buffer. The IoStatus block indicates the completion status of the read operation (since this may require the data be read from disk.) The DeviceObject represents the file system instance.
Typically, this is implemented by file systems either using support routines from the FsRtl package or by calling CcMdlRead direcly.
FastIoMdlReadComplete
This call is used by SRV (or other kernel-resident services) to release an MDL previously acquired via a call to FastIoMdlRead.
typedef BOOLEAN (*PFAST_IO_MDL_READ_COMPLETE) (
IN struct _FILE_OBJECT *FileObject,
IN PMDL MdlChain,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject identifies the file for which the MDL is being released. The MdlChain is the chain returned from a previous call to FastIoMdlRead. The DeviceObject represents the file system instance.
Typically, this is implemented by file systems either using support routines from the FsRtl package or by calling CcMdlReadComplete.
File System Filter Driver Writers beware! CcMdlReadComplete calls this entry point and ignores the return value (as of NT 4.0 SP3) which will cause memory loss when filtering any file system which uses CcMdlReadComplete (and both FAT and NTFS work in this fashion.)
FastIoPrepareMdlWrite
This entry point is used by SRV (or other kernel-resident services) to obtain a pointer to a range of memory within the cache which can be written to directly. This avoids the "memory copy" limitations inherent in providing buffers (as application programsdo
.)
typedef BOOLEAN (*PFAST_IO_PREPARE_MDL_WRITE) (
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject uniquely identifies the file being written, while the FileOffset and Length arguments identify the region of the file being written. The LockKey is used to perform the correct mandatory byte range locking checks, as this write is an "application level" write. The MdlChain is one (or more) MDLs describing the cache buffer. The IoStatus block indicates the completion status of the write operation (since this may require that some data be read from disk.) The DeviceObject represents the file system instance.
Typically, this is implemented by file systems either using support routines from the FsRtl package or by calling CcMdlWrite direcly.
FastIoMdlWriteComplete
This call is used by SRV (or other kernel-resident services) to release an MDL previously acquired via a call to FastIoMdlRead.
typedef BOOLEAN (*PFAST_IO_MDL_WRITE_COMPLETE) (
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN PMDL MdlChain,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject identifies the file for which the MDL is being released. The MdlChain is the chain returned from a previous call to FastIoMdlRead. The DeviceObject represents the file system instance.
Typically, this is implemented by file systems either using support routines from the FsRtl package or by calling CcMdlReadComplete.
File System Filter Driver Writers beware! CcMdlWriteComplete calls this entry point and ignores the return value (as of NT 4.0 SP3) which will cause data and memory loss when filtering any file system which uses CcMdlReadComplete (and both FAT and NTFS work in this fashion at present.)
FastIoReadCompressed
This call was added to allow SRV (or other kernel-resident services) to fetch data in compressed format from the underlying file system. This can only be used for files that are compressed using the standard Windows NT compression libraries (such as "LZW1".) This routine can be used to either copy the data to a buffer provided by the caller, or it can return the data in a fashion described as an MDL.
typedef BOOLEAN (*PFAST_IO_READ_COMPRESSED) (
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PVOID Buffer,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
IN ULONG CompressedDataInfoLength,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject uniquely identifies the file being read, while the FileOffset and Length arguments identify the region of the file being read. The LockKey is used to perform the correct mandatory byte range locking checks, as this read is an "application level" read. The Buffer argument is an (optional) buffer into which the compressed data is to be copied. The MdlChain (also optional) is a pointer which will be set to point to one (or more) MDLs describing the cache buffer. The IoStatus block indicates the completion status of the read operation (since this may require the data be read from disk.) The CompressedDataInfo and CompressedDataInfoLength identify the buffer provided where the compression information for the block being read is copied. The DeviceObject represents the file system instance.
FastIoWriteCompressed
This call was added to allow SRV (or other kernel-resident services) to store data in compressed format in the underlying file system. This can only be used for files that are compressed using the standard Windows NT compression libraries (such as "LZW1".)
typedef BOOLEAN (*PFAST_IO_WRITE_COMPRESSED) (
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
IN PVOID Buffer,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
IN ULONG CompressedDataInfoLength,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject uniquely identifies the file being written, while the FileOffset and Length arguments identify the region of the file being modified. The LockKey is used to perform the correct mandatory byte range locking checks, as this write is an "application level" write. The MdlChain is a pointer which will be set to point to one (or more) MDLs describing the cache buffer. The IoStatus block indicates the completion status of the read operation (since this may require the data be read from disk.) The CompressedDataInfo and CompressedDataInfoLength identify the buffer provided where the compression information for the block being read is copied. The DeviceObject represents the file system instance.
FastIoMdlReadCompleteCompressed
This call is used by SRV (or other kernel-resident services) to release an MDL previously acquired via a call to FastIoMdlReadCompressed.
typedef BOOLEAN (*PFAST_IO_MDL_READ_COMPLETE_COMPRESSED) (
IN struct _FILE_OBJECT *FileObject,
IN PMDL MdlChain,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject identifies the file for which the MDL is being released. The MdlChain is the chain returned from a previous call to FastIoMdlReadCompressed. The DeviceObject represents the file system instance.
FastIoMdlWriteCompleteCompressed
This call is used by SRV (or other kernel-resident services) to release an MDL previously acquired via a call to FastIoMdlWriteCompressed.
typedef BOOLEAN (*PFAST_IO_MDL_WRITE_COMPLETE_COMPRESSED) (
IN struct _FILE_OBJECT *FileObject,
IN PLARGE_INTEGER FileOffset,
IN PMDL MdlChain,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject identifies the file for which the MDL is being released. The MdlChain is the chain returned from a previous call to FastIoMdlWriteCompressed. The DeviceObject represents the file system instance.
FastIoQueryOpen
This routine is used by SRV (or other kernel-resident services) to open a file, retrieve its "network information" and close the file - all in a single operation. The Irp passed into this routine is an IRP_MJ_CREATE request with the necessary information for the underlying file system to actually retrieve the files information.
typedef BOOLEAN (*PFAST_IO_QUERY_OPEN) (
IN struct _IRP *Irp,
OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation,
IN struct _DEVICE_OBJECT *DeviceObject
);
The Irp argument identifies the file being opened (it is a fully constructed IRP_MJ_CREATE request.) The NetworkInformation argument points to a buffer where the file system should store the requisite information. The DeviceObject represents the file system instance.
FastIoReleaseForModWrite
This routine is used by the FsRtl package to release any resources previously acquired by a call to FastIoAcquireForModWrite (described previously.)
typedef NTSTATUS (*PFAST_IO_RELEASE_FOR_MOD_WRITE) (
IN struct _FILE_OBJECT *FileObject,
IN struct _ERESOURCE *ResourceToRelease,
IN struct _DEVICE_OBJECT *DeviceObject
);
If FastIoReleaseForModWrite returns a PERESOURCE it is not necessary for a file system to implement this entry point. However, if the file system is utilizing a more complex synchronization model, or wishes for some other reason to be called to release the file, this routine can be implemented.
The FileObject identifies the specific file being released. The ResourceToRelease corresponds to the value returned from a previous call to FastIoAcquireForModWrite. The DeviceObject represents the file system instance.
FastIoAcquireForCcFlush
This routine is used by the FsRtl package to acquire any file system resources necessary prior to the Lazy Writer in the cache manager writing dirty data back to the file system. If this entry point is not implemented by the file system, the FsRtl routine uses the information in the common header (FileObject->FsContext) to lock the PERESOURCEs to which it points.
typedef NTSTATUS (*PFAST_IO_ACQUIRE_FOR_CCFLUSH) (
IN struct _FILE_OBJECT *FileObject,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject represents the specific file being flushed. The DeviceObject represents the file system instance.
FastIoReleaseForCcFlush
This routine is used by the FsRtl package to release any file system resources acquired via a previous call to FastIoAcquireForCcFlush. If this entry point is not implemented by the file system, the FsRtl routine uses the information in the common header (FileObject->FsContext) to unlock the PERESOURCEs to which it points.
typedef NTSTATUS (*PFAST_IO_RELEASE_FOR_CCFLUSH) (
IN struct _FILE_OBJECT *FileObject,
IN struct _DEVICE_OBJECT *DeviceObject
);
The FileObject represents the specific file being flushed. The DeviceObject represents the file system instance.
Uses for Fast I/O
For most Windows NT drivers, there will never be any need to use these fast I/O entry points. The I/O managerdo
es not require them and will create IRPs for most of these I/O operations (with AcquireFileForNtCreateSection, ReleaseFileForNtCreateSection, and FastIoDetachDevice being the exceptions). However, for file system drivers, these calls are an important part of enhancing the performance of the file system.
Similarly, for anyone attempting to develop their own TDI, they could use a driver much like AFD to provide the interface (via the IOCTL control channel) between user-mode access packages and the kernel mode TDI interface. Again, while this is not required for correct performance, itdo
es seem to be a feature which could be added when enhancing performance of the system.
A third category of drivers would be those kernel mode drivers which combine some of the features of file systems and network communications. For example, NPFS the Named Pipe File System, uses fast I/O to provide a performance tuned communications channel.
Finally, the fourth use we have found for Fast I/O is in the development of file system filter drivers – where they are virtually required. As it turns out, if the underlying device has a particular Fast I/O entry point, the filtering driver must also have that Fast I/O entry point – otherwise it will cause the system to crash under certain circumstances.
NT Insider 1996 On-line Articles
 
我入门的代码FileMon——一个文件监视驱动
代码很长,我分开贴
//======================================================================
//
// Filemon.c
//
// Sysinternals - www.sysinternals.com
// Copyright (C) 1996-2001 Mark Russinovich and Bryce Cogswell
//
// Passthrough file system filter device driver.
//
// Notes: The reason that we use NonPagedPool even though the driver
// only accesses allocated buffer at PASSIVE_LEVEL, is that touching
// a paged pool buffer can generate a page fault, and if the paging
// file is on a drive that filemon is monitoring filemon would be
// reentered to handle the page fault. We want to avoid that and so
// we only use nonpaged pool.
//
//======================================================================
#include "ntddk.h"
#include "stdarg.h"
#include "stdio.h"
#include "../exe/ioctlcmd.h"
#include "filemon.h"

//----------------------------------------------------------------------
// F O R W A R D D E C L A R A T I O N S
//----------------------------------------------------------------------
//
// These are prototypes for Filemon's Fast I/O hooks. The originals
// prototypes can be found in NTDDK.H
//
BOOLEAN
FilemonFastIoCheckifPossible(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
IN ULONG LockKey,
IN BOOLEAN CheckForReadOperation,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoRead(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
IN ULONG LockKey,
OUT PVOID Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoWrite(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
IN ULONG LockKey,
IN PVOID Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoQueryBasicInfo(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
OUT PFILE_BASIC_INFORMATION Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoQueryStandardInfo(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
OUT PFILE_STANDARD_INFORMATION Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoLock(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN PLARGE_INTEGER Length,
PEPROCESS ProcessId,
ULONG Key,
BOOLEAN FailImmediately,
BOOLEAN ExclusiveLock,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoUnlockSingle(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN PLARGE_INTEGER Length,
PEPROCESS ProcessId,
ULONG Key,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoUnlockAll(
IN PFILE_OBJECT FileObject,
PEPROCESS ProcessId,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoUnlockAllByKey(
IN PFILE_OBJECT FileObject,
PEPROCESS ProcessId, ULONG Key,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoDeviceControl(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutbufBuffer,
IN ULONG OutputBufferLength,
IN ULONG IoControlCode,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
VOID
FilemonFastIoAcquireFile(
PFILE_OBJECT FileObject
);
VOID
FilemonFastIoReleaseFile(
PFILE_OBJECT FileObject
);
VOID
FilemonFastIoDetachDevice(
PDEVICE_OBJECT SourceDevice,
PDEVICE_OBJECT TargetDevice
);
//
// These are new NT 4.0 Fast I/O calls
//
BOOLEAN
FilemonFastIoQueryNetworkOpenInfo(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer,
OUT struct _IO_STATUS_BLOCK *IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
FilemonFastIoAcquireForModWrite(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER EndingOffset,
OUT struct _ERESOURCE **ResourceToRelease,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoMdlRead(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoMdlReadComplete(
IN PFILE_OBJECT FileObject,
IN PMDL MdlChain,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoPrepareMdlWrite(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoMdlWriteComplete(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN PMDL MdlChain,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoReadCompressed(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PVOID Buffer,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
IN ULONG CompressedDataInfoLength,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoWriteCompressed(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
IN PVOID Buffer,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
IN ULONG CompressedDataInfoLength,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoMdlReadCompleteCompressed(
IN PFILE_OBJECT FileObject,
IN PMDL MdlChain,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoMdlWriteCompleteCompressed(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN PMDL MdlChain,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
FilemonFastIoQueryOpen(
IN struct _IRP *Irp,
OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation,
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
FilemonFastIoReleaseForModWrite(
IN PFILE_OBJECT FileObject,
IN struct _ERESOURCE *ResourceToRelease,
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
FilemonFastIoAcquireForCcFlush(
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
FilemonFastIoReleaseForCcFlush(
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject
);
BOOLEAN
ApplyFilters(
PCHAR Text
);
//
// Unload routine (debug builds only)
//
VOID
FilemonUnload(
IN PDRIVER_OBJECT DriverObject
);
//----------------------------------------------------------------------
// G L O B A L S
//----------------------------------------------------------------------
//
// This is our Driver Object
//
PDRIVER_OBJECT FilemonDriver;
//
// Indicates if the GUI wants activity to be logged
//
BOOLEAN FilterOn = FALSE;
//
// Global filter (sent to us by the GUI)
//
FILTER FilterDef;
//
// This lock protects access to the filter array
//
ERESOURCE FilterResource;
//
// Array of process and path filters
//
ULONG NumIncludeFilters = 0;
PCHAR IncludeFilters[MAXFILTERS];
ULONG NumExcludeFilters = 0;
PCHAR ExcludeFilters[MAXFILTERS];
//
// Once a load is initiated, this flag prevents the processing of
// further IRPs. This is required because an unload can only take
// place if there are any IRP's for which an IoCompletion has
// been registered that has not actually completed.
//
BOOLEAN UnloadInProgress = FALSE;
//
// This is the offset into a KPEB of the current process name. This is determined
// dynamically by scanning the process block belonging to the GUI for the name
// of the system process, in who's context we execute in DriverEntry
//
ULONG ProcessNameOffset;
//
// This variable keeps track of the outstanding IRPs (ones for which
// a completion routine has been registered, but that have not yet
// passed through the completion routine), which is used in
// the unload determination logic. The CountMutex protects data
// races on updating the count.
//
#if DBG
ULONG OutstandingIRPCount = 0;
#endif // DBG
KSPIN_LOCK CountMutex;
//
// Table of our hook devices for each drive letter. This makes it
// easy to look up the device object that was created to hook a
// particular drive.
//
PDEVICE_OBJECT DriveHookDevices[26];
//
// Current bitmask of hooked drives
//
ULONG CurrentDriveSet = 0;
//
// The special file system hook devices
//
PDEVICE_OBJECT NamedPipeHookDevice = NULL;
PDEVICE_OBJECT MailSlotHookDevice = NULL;
//
// Hash table for keeping names around. This is necessary because
// at any time the name information in the fileobjects that we
// see can be deallocated and reused. If we want to print accurate
// names, we need to keep them around ourselves.
//
PHASH_ENTRY HashTable[NUMHASH];
//
// Reader/Writer lock to protect hash table.
//
ERESOURCE HashResource;
//
// The current output buffer
//
PLOG_BUF CurrentLog = NULL;
//
// Each IRP is given a sequence number. This allows the return status
// of an IRP, which is obtained in the completion routine, to be
// associated with the IRPs parameters that were extracted in the Dispatch
// routine.
//
ULONG Sequence = 0;
//
// This mutex protects the output buffer
//
FAST_MUTEX LogMutex;
//
// Filemon keeps track of the number of distinct output buffers that
// have been allocated, but not yet uploaded to the GUI, and caps
// the amount of memory (which is in non-paged pool) it takes at
// 1MB.
//
ULONG NumLog = 0;
ULONG MaxLog = (1024*1024)/LOGBUFSIZE;
//
// Full path name lookaside for dispatch entry
//
NPAGED_LOOKASIDE_LIST FullPathLookaside;
//
// We use this string for a path name when we're out of resources
//
CHAR InsufficientResources[] = "<INSUFFICIENT MEMORY>";
//
// These are the text representations of the classes of IRP_MJ_SET/GET_INFORMATION
// calls
//
CHAR *FileInformation[] = {
"",
"FileDirectoryInformation",
"FileFullDirectoryInformation",
"FileBothDirectoryInformation",
"FileBasicInformation",
"FileStandardInformation",
"FileInternalInformation",
"FileEaInformation",
"FileAccessInformation",
"FileNameInformation",
"FileRenameInformation",
"FileLinkInformation",
"FileNamesInformation",
"FileDispositionInformation",
"FilePositionInformation",
"FileFullEaInformation",
"FileModeInformation",
"FileAlignmentInformation",
"FileAllInformation",
"FileAllocationInformation",
"FileEndOfFileInformation",
"FileAlternateNameInformation",
"FileStreamInformation",
"FilePipeInformation",
"FilePipeLocalInformation",
"FilePipeRemoteInformation",
"FileMailslotQueryInformation",
"FileMailslotSetInformation",
"FileCompressionInformation",
"FileCopyOnWriteInformation",
"FileCompletionInformation",
"FileMoveClusterInformation",
"FileOleClassIdInformation",
"FileOleStateBitsInformation",
"FileNetworkOpenInformation",
"FileObjectIdInformation",
"FileOleAllInformation",
"FileOleDirectoryInformation",
"FileContentIndexInformation",
"FileInheritContentIndexInformation",
"FileOleInformation",
"FileMaximumInformation",
};

//
// These are textual representations of the IRP_MJ_SET/GET_VOLUME_INFORMATION
// classes
//
CHAR *VolumeInformation[] = {
"",
"FileFsVolumeInformation",
"FileFsLabelInformation",
"FileFsSizeInformation",
"FileFsDeviceInformation",
"FileFsAttributeInformation",
"FileFsQuotaQueryInformation",
"FileFsQuotaSetInformation",
"FileFsControlQueryInformation",
"FileFsControlSetInformation",
"FileFsMaximumInformation",
};

//
// These are Win2K Plug-and-Play minor IRP codes
//
CHAR *PnpMinorCode[] = {
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
"IRP_MN_REMOVE_DEVICE",
"IRP_MN_CANCEL_REMOVE_DEVICE",
"IRP_MN_STOP_DEVICE",
"IRP_MN_QUERY_STOP_DEVICE",
"IRP_MN_CANCEL_STOP_DEVICE",
"IRP_MN_QUERY_DEVICE_RELATIONS",
"IRP_MN_QUERY_INTERFACE",
"IRP_MN_QUERY_CAPABILITIES",
"IRP_MN_QUERY_RESOURCES",
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
"IRP_MN_SET_LOCK",
"IRP_MN_QUERY_ID",
"IRP_MN_QUERY_PNP_DEVICE_STATE",
"IRP_MN_QUERY_BUS_INFORMATION",
"IRP_MN_DEVICE_USAGE_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL",
"IRP_MN_QUERY_LEGACY_BUS_INFORMATION",
};
#define MAX_NTFS_METADATA_FILE 11
CHAR *NtfsMetadataFileNames[] = {
"$Mft",
"$MftMirr",
"$LogFile",
"$Volume",
"$AttrDef",
"$Root",
"$Bitmap",
"$Boot",
"$BadClus",
"$Secure",
"$UpCase",
"$Extend"
};


//
// This Filemon's Fast I/O dispatch table. Note that NT assumes that
// file system drivers support some Fast I/O calls, so this table must
// be present for an file system filter driver
//
FAST_IO_DISPATCH FastIOHook = {
sizeof(FAST_IO_DISPATCH),
FilemonFastIoCheckifPossible,
FilemonFastIoRead,
FilemonFastIoWrite,
FilemonFastIoQueryBasicInfo,
FilemonFastIoQueryStandardInfo,
FilemonFastIoLock,
FilemonFastIoUnlockSingle,
FilemonFastIoUnlockAll,
FilemonFastIoUnlockAllByKey,
FilemonFastIoDeviceControl,
FilemonFastIoAcquireFile,
FilemonFastIoReleaseFile,
FilemonFastIoDetachDevice,
//
// new for NT 4.0
//
FilemonFastIoQueryNetworkOpenInfo,
FilemonFastIoAcquireForModWrite,
FilemonFastIoMdlRead,
FilemonFastIoMdlReadComplete,
FilemonFastIoPrepareMdlWrite,
FilemonFastIoMdlWriteComplete,
FilemonFastIoReadCompressed,
FilemonFastIoWriteCompressed,
FilemonFastIoMdlReadCompleteCompressed,
FilemonFastIoMdlWriteCompleteCompressed,
FilemonFastIoQueryOpen,
FilemonFastIoReleaseForModWrite,
FilemonFastIoAcquireForCcFlush,
FilemonFastIoReleaseForCcFlush
};
//----------------------------------------------------------------------
// P A T T E R N M A T C H I N G R O U T I N E S
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//
// MatchOkay
//
// Only thing left after compare is more mask. This routine makes
// sure that its a valid wild card ending so that its really a match.
//
//----------------------------------------------------------------------
BOOLEAN
MatchOkay(
PCHAR Pattern
)
{
//
// If pattern isn't empty, it must be a wildcard
//
if( *Pattern &amp;&amp;
*Pattern != '*' ) {

return FALSE;
}
//
// Matched
//
return TRUE;
}

//----------------------------------------------------------------------
//
// MatchWithPattern
//
// Performs nifty wildcard comparison.
//
//----------------------------------------------------------------------
BOOLEAN
MatchWithPattern(
PCHAR Pattern,
PCHAR Name
)
{
char matchchar;
//
// End of pattern?
//
if( !*Pattern ) {
return FALSE;
}
//
// If we hit a wild card,do
recursion
//
if( *Pattern == '*' ) {
Pattern++;
while( *Name &amp;&amp;
*Pattern ) {
matchchar = *Name;
if( matchchar >= 'a' &amp;&amp;
matchchar <= 'z' ) {
matchchar -= 'a' - 'A';
}
//
// See if this substring matches
//
if( *Pattern == matchchar ) {
if( MatchWithPattern( Pattern+1, Name+1 )) {
return TRUE;
}
}
//
// Try the next substring
//
Name++;
}
//
// See if match condition was met
//
return MatchOkay( Pattern );
}
//
//do
straight compare until we hit a wild card
//
while( *Name &amp;&amp;
*Pattern != '*' ) {
matchchar = *Name;
if( matchchar >= 'a' &amp;&amp;
matchchar <= 'z' ) {
matchchar -= 'a' - 'A';
}
if( *Pattern == matchchar ) {
Pattern++;
Name++;
} else
{
return FALSE;
}
}
//
// If notdo
ne, recurse
//
if( *Name ) {
return MatchWithPattern( Pattern, Name );
}
//
// Make sure its a match
//
return MatchOkay( Pattern );
}
//----------------------------------------------------------------------
// B U F F E R M A N A G E M E N T
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//
// FilemonFreeLog
//
// Frees all the data output buffers that we have currently allocated.
//
//----------------------------------------------------------------------
VOID
FilemonFreeLog(
VOID
)
{
PLOG_BUF prev;

//
// Just traverse the list of allocated output buffers
//
while( CurrentLog ) {
prev = CurrentLog->Next;
ExFreePool( CurrentLog );
CurrentLog = prev;
}
}

//----------------------------------------------------------------------
//
// FilemonAllocateLog
//
// Called when the current buffer has filled up. This allocates a new
// buffer and stick it at the head (newest) entry of our buffer list.
//
//----------------------------------------------------------------------
void
FilemonAllocateLog(
VOID
)
{
PLOG_BUF prev = CurrentLog, newLog;
//
// If we've already allocated the allowed number of buffers, just
// reuse the current one. This will result in output records being
// lost, but it takes ALOT of file system activity to cause this.
//
if( MaxLog == NumLog ) {
DbgPrint(("Filemon ***** Dropping records at sequence number %d/n", Sequence ));
CurrentLog->Len = 0;
return;
}
DbgPrint(("FilemonAllocateLog: num: %d max: %d/n", NumLog, MaxLog ));
//
// If the output buffer we currently are using is empty, just
// use it.
//
if( !CurrentLog->Len ) {
return;
}
//
// Allocate a new output buffer
//
newLog = ExAllocatePool( NonPagedPool, sizeof(*CurrentLog) );
if( newLog ) {
//
// Allocation was successful so add the buffer to the list
// of allocated buffers and increment the buffer count.
//
CurrentLog = newLog;
CurrentLog->Len = 0;
CurrentLog->Next = prev;
NumLog++;
} else
{
//
// The allocation failed - just reuse the current buffer
//
CurrentLog->Len = 0;
}
}

//----------------------------------------------------------------------
//
// FilemonGetOldestLog
//
// Traverse the list of allocated buffers to find the last one, which
// will be the oldest (as we want to return the oldest data to the GUI
// first).
//
//----------------------------------------------------------------------
PLOG_BUF
FilemonGetOldestLog(
VOID
)
{
PLOG_BUF ptr = CurrentLog, prev = NULL;
//
// Traverse the list
//
while( ptr->Next ) {
ptr = (prev = ptr)->Next;
}
//
// Remove the buffer from the list
//
if( prev ) {
prev->Next = NULL;

NumLog--;
}
return ptr;
}

//----------------------------------------------------------------------
//
// FilemonResetLog
//
// When a GUI instance has close communication (exited), but the driver
// can't unload due to oustdanding IRPs, all the output buffers except
// one are all deallocated so that the memory footprint is shrunk as much
// as possible.
//
//----------------------------------------------------------------------
VOID
FilemonResetLog(
VOID
)
{
PLOG_BUF current, next;
ExAcquireFastMutex( &amp;LogMutex );
//
// Traverse the list of output buffers
//
current = CurrentLog->Next;
while( current ) {
//
// Free the buffer
//
next = current->Next;
ExFreePool( current );
current = next;
}
//
// Move the output pointer in the buffer that's being kept
// the start of the buffer.
//
NumLog = 1;
CurrentLog->Len = 0;
CurrentLog->Next = NULL;
ExReleaseFastMutex( &amp;LogMutex );

}

//----------------------------------------------------------------------
//
// LogRecord
//
// This "printfs" a string into an output buffer.
//
//----------------------------------------------------------------------
BOOLEAN
LogRecord(
BOOLEAN ProcessFilters,
PULONG SeqNum,
PLARGE_INTEGER dateTime,
PLARGE_INTEGER perfTime,
const CHAR * format,
...
)
{
PENTRY Entry;
int len;
ULONG recordSequence;
va_list arg_ptr;
static CHAR text[MAXPATHLEN];
BOOLEAN passedFilters = FALSE;
//
// If no GUI is there to receive the output or if no filtering is desired,do
n't bother
//
if( !FilterOn ) {

return FALSE;
}
//
// Lock the output buffer and Log.
//
ExAcquireFastMutex( &amp;LogMutex );
//
// Send text out as debug output This is x86 specific.
//
#define A (&amp;format)
DbgPrint(( (char *)format, A[1], A[2], A[3], A[4], A[5], A[6] ));
DbgPrint(( "/n" ));
#undef A
//
// Vsprintf to determine the length of the buffer
//
va_start( arg_ptr, format );
len = vsprintf( text, format, arg_ptr );
va_end( arg_ptr );
//
// ULONG align for Alpha
//
len += 4;
len &amp;= 0xFFFFFFFC;

//
// Only log it if it passes the filters. Note that IRP completion
// passes a false for ProcessFilters because if we've logged
// the initial action, we have to go ahead and log the completion.
//
passedFilters = !ProcessFilters || ApplyFilters( text );
if( passedFilters ) {
//
// Assign a sequence number if we weren't passed one
//
if( !SeqNum || (SeqNum &amp;&amp;
*SeqNum == (ULONG) -1))
{
recordSequence = InterlockedIncrement( &amp;Sequence );
if( SeqNum ) *SeqNum = recordSequence;
} else
{
recordSequence = *SeqNum;
}
//
// If the current output buffer is near capacity, move to a new
// output buffer
//
if( CurrentLog->Len + len + sizeof(ENTRY) +1 >= LOGBUFSIZE )
{
FilemonAllocateLog();
}
//
// Log the entry
//
Entry = (void *)(CurrentLog->Data+CurrentLog->Len);
Entry->seq = recordSequence;
Entry->datetime.QuadPart = 0;
Entry->perftime.QuadPart = 0;
if( dateTime ) Entry->datetime = *dateTime;
if( perfTime ) Entry->perftime = *perfTime;
memcpy( Entry->text, text, len );

//
// Log the length of the string, plus 1 for the terminating
// NULL
//
CurrentLog->Len += ((ULONG) (Entry->text - (PCHAR) Entry )) + len;
}
//
// Release the output buffer lock
//
ExReleaseFastMutex( &amp;LogMutex );
return passedFilters;
}
//----------------------------------------------------------------------
// H A S H T A B L E M A N A G E M E N T
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//
// FilemonHashCleanup
//
// Called when we are unloading to free any memory that we have
// in our possession.
//
//----------------------------------------------------------------------
VOID
FilemonHashCleanup(
VOID
)
{
PHASH_ENTRY hashEntry, nextEntry;
ULONG i;
// 进入临界区域
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite( &amp;HashResource, TRUE );
//
// Free the hash table entries
//
for( i = 0;
i < NUMHASH;
i++ ) {
hashEntry = HashTable;
while( hashEntry )
{
nextEntry = hashEntry->Next;
ExFreePool( hashEntry );
hashEntry = nextEntry;
}
HashTable = NULL;
}
ExReleaseResourceLite( &amp;HashResource );
// 退出临界区域
KeLeaveCriticalRegion();
}

//----------------------------------------------------------------------
//
// FilemonFreeHashEntry
//
// When we see a file close, we can free the string we had associated
// with the fileobject being closed since we know it won't be used
// again.
//
//----------------------------------------------------------------------
VOID
FilemonFreeHashEntry(
PFILE_OBJECT fileObject
)
{
PHASH_ENTRY hashEntry, prevEntry;
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite( &amp;HashResource, TRUE );
//
// Look-up the entry
//
hashEntry = HashTable[ HASHOBJECT( fileObject ) ];
prevEntry = NULL;
while( hashEntry &amp;&amp;
hashEntry->FileObject != fileObject ) {
prevEntry = hashEntry;
hashEntry = hashEntry->Next;
}

//
// If we fall of the hash list without finding what we're looking
// for, just return.
//
if( !hashEntry ) {
ExReleaseResourceLite( &amp;HashResource );
KeLeaveCriticalRegion();
return;
}
//
// Got it! Remove it from the list
//
if( prevEntry ) {
prevEntry->Next = hashEntry->Next;
} else
{
HashTable[ HASHOBJECT( fileObject )] = hashEntry->Next;
}
//
// Free the entry's memory
//
ExFreePool( hashEntry );
ExReleaseResourceLite( &amp;HashResource );
KeLeaveCriticalRegion();
}
//----------------------------------------------------------------------
// P A T H A N D P R O C E S S N A M E R O U T I N E S
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//
// FilemonFreeFilters
//
// Fress storage we allocated for filter strings.
//
//----------------------------------------------------------------------
VOID
FilemonFreeFilters(
VOID
)
{
ULONG i;
for( i = 0;
i < NumIncludeFilters;
i++ ) {
ExFreePool( IncludeFilters );
}
for( i = 0;
i < NumExcludeFilters;
i++ ) {
ExFreePool( ExcludeFilters );
}
NumIncludeFilters = 0;
NumExcludeFilters = 0;
}

//----------------------------------------------------------------------
//
// MakeFilterArray
//
// Takes a filter string and splits into components (a component
// is seperated with a ';')
//
//----------------------------------------------------------------------
VOID
MakeFilterArray(
PCHAR FilterString,
PCHAR FilterArray[],
PULONG NumFilters
)
{
PCHAR filterStart;
ULONG filterLength;
CHAR saveChar;
//
// Scan through the process filters
//
filterStart = FilterString;
while( *filterStart ) {
filterLength = 0;
while( filterStart[filterLength] &amp;&amp;
filterStart[filterLength] != ';' ) {
filterLength++;
}
//
// Ignore zero-length components
//
if( filterLength ) {
//
// Conservatively allocate so that we can prepend and append
// wildcards
//
FilterArray[ *NumFilters ] =
ExAllocatePool( PagedPool, filterLength + 1 + 2*sizeof('*') );

//
// Only fill this in if there's enough memory
//
if( FilterArray[ *NumFilters] ) {
saveChar = *(filterStart + filterLength );
*(filterStart + filterLength) = 0;
sprintf( FilterArray[ *NumFilters ], "%s%s%s",
*filterStart == '*' ? "" : "*",
filterStart,
*(filterStart + filterLength - 1 ) == '*' ? "" : "*" );
*(filterStart + filterLength) = saveChar;
(*NumFilters)++;
}
}

//
// Are wedo
ne?
//
if( !filterStart[filterLength] ) break;
//
// Move to the next component (skip over ';')
//
filterStart += filterLength + 1;
}
}

//----------------------------------------------------------------------
//
// FilemonUpdateFilters
//
// Takes a new filter specification and updates the filter
// arrays with them.
//
//----------------------------------------------------------------------
VOID
FilemonUpdateFilters(
VOID
)
{
//
// Free old filters (if any)
//
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite( &amp;FilterResource, TRUE );
FilemonFreeFilters();
//
// Create new filter arrays
//
MakeFilterArray( FilterDef.includefilter,
IncludeFilters, &amp;NumIncludeFilters );
MakeFilterArray( FilterDef.excludefilter,
ExcludeFilters, &amp;NumExcludeFilters );
ExReleaseResourceLite( &amp;FilterResource );
KeLeaveCriticalRegion();
}

//----------------------------------------------------------------------
//
// ApplyFilters
//
// If the name matches the exclusion mask, wedo
not log it. else
if
// itdo
esn't match the inclusion mask wedo
not log it.
//
//----------------------------------------------------------------------
BOOLEAN
ApplyFilters(
PCHAR Text
)
{
ULONG i;
//
// If no GUI or no filename return FALSE
//
if( !Text ) return FALSE;
//
// If it matches the exclusion string,do
not log it
//
KeEnterCriticalRegion();
ExAcquireResourceSharedLite( &amp;FilterResource, TRUE );
for( i = 0;
i < NumExcludeFilters;
i++ ) {
if( MatchWithPattern( ExcludeFilters, Text ) ) {
ExReleaseResourceLite( &amp;FilterResource );
KeLeaveCriticalRegion();
return FALSE;
}
}

//
// If it matches an include filter then
log it
//
for( i = 0;
i < NumIncludeFilters;
i++ ) {
if( MatchWithPattern( IncludeFilters, Text )) {
ExReleaseResourceLite( &amp;FilterResource );
KeLeaveCriticalRegion();
return TRUE;
}
}
//
// It didn't match any include filters sodo
n't log
//
ExReleaseResourceLite( &amp;FilterResource );
KeLeaveCriticalRegion();
return FALSE;
}

//----------------------------------------------------------------------
//
// FilemonQueryFileComplete
//
// This routine is used to handle I/O completion for our self-generated
// IRP that is used to query a file's name or number.
//
//----------------------------------------------------------------------
NTSTATUS
FilemonQueryFileComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
//
// Copy the status information back into the "user" IOSB.
//
*Irp->UserIosb = Irp->IoStatus;
if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
DbgPrint((" ERROR ON IRP: %x/n", Irp->IoStatus.Status ));
}

//
// Set the user event - wakes up the mainline codedo
ing this.
//
KeSetEvent(Irp->UserEvent, 0, FALSE);

//
// Free the IRP now that we aredo
ne with it.
//
IoFreeIrp(Irp);

//
// We return STATUS_MORE_PROCESSING_REQUIRED because this "magic" return value
// tells the I/O Manager that additional processing will bedo
ne by this driver
// to the IRP - in fact, it might (as it is in this case) already BEdo
ne - and
// the IRP cannot be completed.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}

//----------------------------------------------------------------------
//
// FilemonQueryFile
//
// This function retrieves the "standard" information for the
// underlying file system, asking for the filename in particular.
//
//----------------------------------------------------------------------
BOOLEAN
FilemonQueryFile(
PDEVICE_OBJECT DeviceObject,
PFILE_OBJECT FileObject,
FILE_INFORMATION_CLASS FileInformationClass,
PVOID FileQueryBuffer,
ULONG FileQueryBufferLength
)
{
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION ioStackLocation;
DbgPrint(("Getting file name for %x/n", FileObject));
//
// Initialize the event
//
KeInitializeEvent(&amp;event, SynchronizationEvent, FALSE);
//
// Allocate an irp for this request. This could also come from a
// private pool, for instance.
//
irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if(!irp) {
//
// Failure!
//
return FALSE;
}

//
// Build the IRP's main body
//
irp->AssociatedIrp.SystemBuffer = FileQueryBuffer;
irp->UserEvent = &amp;event;
irp->UserIosb = &amp;IoStatusBlock;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject = FileObject;
irp->RequestorMode = KernelMode;
irp->Flags = 0;
//
// Set up the I/O stack location.
//
ioStackLocation = IoGetNextIrpStackLocation(irp);
ioStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION;
ioStackLocation->DeviceObject = DeviceObject;
ioStackLocation->FileObject = FileObject;
ioStackLocation->Parameters.QueryFile.Length = FileQueryBufferLength;
ioStackLocation->Parameters.QueryFile.FileInformationClass = FileInformationClass;
//
// Set the completion routine.
//
IoSetCompletionRoutine(irp, FilemonQueryFileComplete, 0, TRUE, TRUE, TRUE);
//FSD
// Send it to the
//
(void) IoCallDriver(DeviceObject, irp);
//
// Wait for the I/O
//
KeWaitForSingleObject(&amp;event, Executive, KernelMode, TRUE, 0);
//
//do
ne! Note that since our completion routine frees the IRP we cannot
// touch the IRP now.
//
return NT_SUCCESS( IoStatusBlock.Status );
}

//----------------------------------------------------------------------
//
// FilemonGetFullPath
//
// Takes a fileobject and filename and returns a canonical path,
// nicely formatted, in fullpathname.
//
//----------------------------------------------------------------------
VOID
FilemonGetFullPath(
BOOLEAN createPath,
PFILE_OBJECT fileObject,
PHOOK_EXTENSION hookExt,
PCHAR fullPathName
)
{
ULONG pathLen, prefixLen, slashes;
PCHAR pathOffset, ptr;
BOOLEAN gotPath;
PFILE_OBJECT relatedFileObject;
PHASH_ENTRY hashEntry, newEntry;
ANSI_STRING fileName;
ANSI_STRING relatedName;
PFILE_NAME_INFORMATION fileNameInfo;
FILE_INTERNAL_INFORMATION fileInternalInfo;
UNICODE_STRING fullUniName;
ULONGLONG mftIndex;
//
// Onlydo
this if a GUI is active and filtering is on
//
if( fullPathName ) fullPathName[0] = 0;
if( !FilterOn || !hookExt || !hookExt->Hooked || !fullPathName) {

return;
}
//
// Lookup the object in the hash table to see if a name
// has already been generated for it
//
KeEnterCriticalRegion();
ExAcquireResourceSharedLite( &amp;HashResource, TRUE );
hashEntry = HashTable[ HASHOBJECT( fileObject ) ];
while( hashEntry &amp;&amp;
hashEntry->FileObject != fileObject ) {
hashEntry = hashEntry->Next;
}
//
// Did we find an entry?
//
if( hashEntry ) {
//
// Yes, so get the name from the entry.
//
strcpy( fullPathName, hashEntry->FullPathName );
ExReleaseResourceLite( &amp;HashResource );
KeLeaveCriticalRegion();
return;
}
ExReleaseResourceLite( &amp;HashResource );
KeLeaveCriticalRegion();
//
// We didn't find the name in the hash table so let's either ask
// the file system for it or construct it from the file objects.
//
//
// Calculate prefix length
//
switch( hookExt->Type ) {
case NPFS:
prefixLen = NAMED_PIPE_PREFIX_LENGTH;
break;
case MSFS:
prefixLen = MAIL_SLOT_PREFIX_LENGTH;
break;
default:
if( !fileObject ||
fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
prefixLen = 0;
} else
{
prefixLen = 2;
// "C:"
}
break;
}
//
// If there's no file object, we can't even ask for a name.
//
if( !fileObject ) {
if( hookExt->Type == NPFS ) strcpy( fullPathName, NAMED_PIPE_PREFIX );
else
if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );
else
sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
return;
}
//
// Initialize variables
//
fileName.Buffer = NULL;
relatedName.Buffer = NULL;
gotPath = FALSE;
//
// Check for special case first: NTFS volume and a file object
// with no name. It might be a metadata file that we "know" the name of. This
// special case also stops us from querying NTFS for the name of a metadata
// file on versions of NTFS prior to Whistler, which is a good thing since
// that causes hangs and crashes. On Whistler metadata files have file names.
//
if( !fileObject->FileName.Buffer &amp;&amp;
hookExt->FsAttributes &amp;&amp;
!memcmp( hookExt->FsAttributes->FileSystemName, L"NTFS", sizeof(L"NTFS")-sizeof(WCHAR))) {
//
// The only file that is opened without a name is a volume
//
if( createPath ) {
sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
//
// Return right here without inserting this into the hash table, since this might
// be the cleanup path of a metadata file and we can retrieve the metada's index
// at a later point.
//
return;
} else
if( FilemonQueryFile( hookExt->FileSystem, fileObject, FileInternalInformation,
&amp;fileInternalInfo, sizeof( fileInternalInfo ))) {

//
// Use the name in the metadata name index
//
mftIndex = fileInternalInfo.IndexNumber.QuadPart &amp;
~0xF0000000;
if( mftIndex <= MAX_NTFS_METADATA_FILE ) {
sprintf( fullPathName, "%C://%s", hookExt->LogicalDrive, NtfsMetadataFileNames[ mftIndex ] );
gotPath = TRUE;
}
}
}
//
// If we are not in the create path, we can ask the file system for the name. If we
// are in the create path, we can't ask the file system for the name of the file object, since
// the file system driver hasn't even seen the file object yet.
//
if( !gotPath &amp;&amp;
!createPath ) {
//
// Ask the file system for the name of the file, which its required to be
// able to provide for the Win32 filename query function. We could use the
// undocumented ObQueryNameString, but then
we'd have to worry about
// re-entrancy issues, since that call generates the IRP that we create
// manually here. Since we send the IRP to the FSD below us, wedo
n't need
// to worry about seeing the IRP in our dispatch entry point. This can fail
// in some cases, so we fall back on constructing the name ourselves if
// we have to.
//
fileNameInfo = (PFILE_NAME_INFORMATION) ExAllocatePool( NonPagedPool,
MAXPATHLEN*sizeof(WCHAR) );
if( fileNameInfo &amp;&amp;
FilemonQueryFile(hookExt->FileSystem, fileObject, FileNameInformation,
fileNameInfo, (MAXPATHLEN - prefixLen - 1)*sizeof(WCHAR) )) {
fullUniName.Length = (SHORT) fileNameInfo->FileNameLength;
fullUniName.Buffer = fileNameInfo->FileName;
if( NT_SUCCESS( RtlUnicodeStringToAnsiString( &amp;fileName, &amp;fullUniName, TRUE ))) {
fullPathName[ fileName.Length + prefixLen ] = 0;
if( hookExt->Type == NPFS ) {

strcpy( fullPathName, NAMED_PIPE_PREFIX );
} else
if( hookExt->Type == MSFS ) {
strcpy( fullPathName, MAIL_SLOT_PREFIX );
} else
if( fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
} else
{

//
// No prefix for network devices
//
}
memcpy( &amp;fullPathName[prefixLen], fileName.Buffer, fileName.Length );
gotPath = TRUE;
RtlFreeAnsiString( &amp;fileName );
fileName.Buffer = NULL;
}
}
if( fileNameInfo ) ExFreePool( fileNameInfo );
}
//
// If wedo
n't have a name yet then
we are in the create path, or we failed
// when we asked the file system for the name. In that case we'll go ahead
// and construct the name based on file object names.
//
if( !gotPath ) {
//
// If there is no file name at this point, just return "DEVICE" to indicate
// raw access to a device
//
if( !fileObject->FileName.Buffer ) {
if( hookExt->Type == NPFS ) strcpy( fullPathName, NAMED_PIPE_PREFIX );
else
if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );
else
sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
return;
}

//
// Create the full path name. First, calculate the length taking into
// account space for seperators and the leading prefix
//
if( !NT_SUCCESS( RtlUnicodeStringToAnsiString( &amp;fileName, &amp;fileObject->FileName, TRUE ))) {
if( hookExt->Type == NPFS ) sprintf( fullPathName, "%s: <Out of Memory>", NAMED_PIPE_PREFIX );
else
if( hookExt->Type == MSFS ) sprintf( fullPathName, "%s: <Out of Memory>", MAIL_SLOT_PREFIX );
else
sprintf( fullPathName, "%C: <Out of Memory>", hookExt->LogicalDrive );
return;
}
pathLen = fileName.Length + prefixLen;
relatedFileObject = fileObject->RelatedFileObject;

//
// Only look at related file object if this is a relative name
//
if( fileObject->FileName.Buffer[0] != L'//' &amp;&amp;
relatedFileObject &amp;&amp;
relatedFileObject->FileName.Length ) {

if( !NT_SUCCESS( RtlUnicodeStringToAnsiString( &amp;relatedName, &amp;relatedFileObject->FileName, TRUE ))) {
if( hookExt->Type == NPFS ) sprintf( fullPathName, "%s: <Out of Memory>", NAMED_PIPE_PREFIX );
else
if( hookExt->Type == MSFS ) sprintf( fullPathName, "%s: <Out of Memory>", MAIL_SLOT_PREFIX );
else
sprintf( fullPathName, "%C: <Out of Memory>", hookExt->LogicalDrive );
RtlFreeAnsiString( &amp;fileName );
return;
}
pathLen += relatedName.Length+1;
}
//
// Add the drive letter first at the front of the name
//
if( hookExt->Type == NPFS ) strcpy( fullPathName, NAMED_PIPE_PREFIX );
else
if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );
else
if( fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
}
//
// If the name is too long, quit now
//
if( pathLen >= MAXPATHLEN ) {

strcat( fullPathName, " <Name Too Long>" );
} else
{

//
// Now we can build the path name
//
fullPathName[ pathLen ] = 0;

pathOffset = fullPathName + pathLen - fileName.Length;
memcpy( pathOffset, fileName.Buffer, fileName.Length + 1 );

if( fileObject->FileName.Buffer[0] != L'//' &amp;&amp;
relatedFileObject &amp;&amp;
relatedFileObject->FileName.Length ) {
//
// Copy the component, adding a slash separator
//
*(pathOffset - 1) = '//';
pathOffset -= relatedName.Length + 1;

memcpy( pathOffset, relatedName.Buffer, relatedName.Length );
//
// If we've got to slashes at the front zap one
//
if( pathLen > 3 &amp;&amp;
fullPathName[2] == '//' &amp;&amp;
fullPathName[3] == '//' ) {

strcpy( fullPathName + 2, fullPathName + 3 );
}
}
}
}
if( fileName.Buffer ) RtlFreeAnsiString( &amp;fileName );
if( relatedName.Buffer ) RtlFreeAnsiString( &amp;relatedName );
//
// Network redirector names already specify a share name that we
// have to strip:
//
// /X:/computer/share/realpath
//
// And we want to present:
//
// X:/realpath
//
// to the user.
//
if( fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM &amp;&amp;
strlen( fullPathName ) >= strlen("//X://") ) {
//
// If this is Win2k the name is specified like this:
//
// /;X:0/computer/share/realpath
//
// so we have to handle that case as well
//
if( fullPathName[1] == ';' ) {

//
// Win2K-style name. Grab the drive letter
// and skip over the share
//
fullPathName[0] = fullPathName[2];
fullPathName[1] = ':';
fullPathName[2] = '//';
//
// The third slash after the drive is the
// start of the real path (we start scanning
// at the ':' since wedo
n't want to make assumptions
// about the length of the number).
//
slashes = 0;
ptr = &amp;fullPathName[3];
while( *ptr &amp;&amp;
slashes != 3 ) {

if( *ptr == '//' ) slashes++;
ptr++;
}
strcpy( &amp;fullPathName[3], ptr );
} else
if( fullPathName[2] == ':' ) {
//
// NT 4-style name. Skip the share name
//
fullPathName[0] = fullPathName[1];
fullPathName[1] = ':';
fullPathName[2] = '//';

//
// The second slash after the drive's slash (x:/)
// is the start of the real path
//
slashes = 0;
ptr = &amp;fullPathName[3];
while( *ptr &amp;&amp;
slashes != 3 ) {

if( *ptr == '//' ) slashes++;
ptr++;
}
strcpy( &amp;fullPathName[3], ptr );
} else
{
//
// Its a UNC path, so add a leading slash
//
RtlMoveMemory( &amp;fullPathName[1], fullPathName, strlen( fullPathName ) + 1);
fullPathName[0] = '//';
}
}
//
// Allocate a hash entry
//
newEntry = ExAllocatePool( NonPagedPool,
sizeof(HASH_ENTRY ) + strlen( fullPathName ) + 1);
//
// If no memory for a new entry, oh well.
//
if( newEntry ) {
//
// Fill in the new entry
//
newEntry->FileObject = fileObject;
strcpy( newEntry->FullPathName, fullPathName );
//
// Put it in the hash table
//
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite( &amp;HashResource, TRUE );
newEntry->Next = HashTable[ HASHOBJECT(fileObject) ];
HashTable[ HASHOBJECT(fileObject) ] = newEntry;
ExReleaseResourceLite( &amp;HashResource );
KeLeaveCriticalRegion();
}
}

//----------------------------------------------------------------------
//
// FilemonGetProcessNameOffset
//
// In an effort to remain version-independent, rather than using a
// hard-coded into the KPEB (Kernel Process Environment Block), we
// scan the KPEB looking for the name, which should match that
// of the system process. This is because we are in the system process'
// context in DriverEntry, where this is called.
//
//----------------------------------------------------------------------
ULONG
FilemonGetProcessNameOffset(
VOID
)
{
PEPROCESS curproc;
int i;
curproc = PsGetCurrentProcess();
//
// Scan for 12KB, hoping the KPEB never grows that big!
//
for( i = 0;
i < 3*PAGE_SIZE;
i++ ) {

if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) )) {
return i;
}
}
//
// Name not found - oh, well
//
return 0;
}

//----------------------------------------------------------------------
//
// FilemonGetProcess
//
// Uses undocumented data structure offsets to obtain the name of the
// currently executing process.
//
//----------------------------------------------------------------------
PCHAR
FilemonGetProcess(
PCHAR ProcessName
)
{
PEPROCESS curproc;
char *nameptr;
ULONG i;
//
// We onlydo
this if we determined the process name offset
//
if( ProcessNameOffset ) {

//
// Get a pointer to the current process block
//
curproc = PsGetCurrentProcess();
//
// Dig into it to extract the name. Make sure to leave enough room
// in the buffer for the appended process ID.
//
nameptr = (PCHAR) curproc + ProcessNameOffset;

strncpy( ProcessName, nameptr, NT_PROCNAMELEN-1 );
ProcessName[NT_PROCNAMELEN-1] = 0;
#if defined(_IA64_)
sprintf( ProcessName + strlen(ProcessName), ":%I64d", PsGetCurrentProcessId());
#else
sprintf( ProcessName + strlen(ProcessName), ":%d", PsGetCurrentProcessId());
#endif
} else
{
strcpy( ProcessName, "???" );
}
return ProcessName;
}

//----------------------------------------------------------------------
// H O O K / U N H O O K R O U T I N E S
//----------------------------------------------------------------------
#if DBG
//----------------------------------------------------------------------
//
// UnloadDetach
//
// Detaches from all devices for an unload
//
//----------------------------------------------------------------------
VOID
UnloadDetach(
VOID
)
{
ULONG drive, i;
PDEVICE_OBJECT device;
PHOOK_EXTENSION hookExt;

//
// Detach from file system devices
//
for( drive = 0;
drive < 26;
drive++ ) {
if( DriveHookDevices[drive] ) {
device = DriveHookDevices[drive];
hookExt = device->DeviceExtension;
IoDetachDevice( hookExt->FileSystem );
IoDeleteDevice( device );
for( i =0;
i < 26;
i++ ) {
if( DriveHookDevices == device ) {
DriveHookDevices = NULL;
}
}
}
}
//
// Detach from special devices
//
if( NamedPipeHookDevice ) {
IoDetachDevice( NamedPipeHookDevice );
IoDeleteDevice( NamedPipeHookDevice );
}
if( MailSlotHookDevice ) {
IoDetachDevice( MailSlotHookDevice );
IoDeleteDevice( MailSlotHookDevice );
}
}
#endif // DBG
//----------------------------------------------------------------------
//
// HookSpecialFs
//
// Hook the named pipe or mail slot file system.
//
//----------------------------------------------------------------------
BOOLEAN
HookSpecialFs(
IN PDRIVER_OBJECT DriverObject,
FILE_SYSTEM_TYPE FsType
)
{
IO_STATUS_BLOCK ioStatus;
HANDLE ntFileHandle;

OBJECT_ATTRIBUTES objectAttributes;
PDEVICE_OBJECT fileSysDevice;
PDEVICE_OBJECT topAttachDevice;
PDEVICE_OBJECT hookDevice;
UNICODE_STRING fileNameUnicodeString;
WCHAR npfsFilename[] = L"//Device//NamedPipe";
WCHAR msfsFilename[] = L"//Device//MailSlot";
NTSTATUS ntStatus;
ULONG i;
PFILE_OBJECT fileObject;
PHOOK_EXTENSION hookExtension;
//
// If we've already hooked it, just return success
//
if( FsType == NPFS &amp;&amp;
NamedPipeHookDevice ) return TRUE;
if( FsType == MSFS &amp;&amp;
MailSlotHookDevice ) return TRUE;

//
// We have to figure out what device to hook - first open the volume's
// root directory
//
if( FsType == NPFS ) RtlInitUnicodeString( &amp;fileNameUnicodeString, npfsFilename );
else
RtlInitUnicodeString( &amp;fileNameUnicodeString, msfsFilename );
InitializeObjectAttributes( &amp;objectAttributes, &amp;fileNameUnicodeString,
OBJ_CASE_INSENSITIVE, NULL, NULL );
ntStatus = ZwCreateFile( &amp;ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS,
&amp;objectAttributes, &amp;ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE,
NULL, 0 );
if( !NT_SUCCESS( ntStatus ) ) {
DbgPrint(("Filemon: Could not open %s/n", FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));
return FALSE;
}
DbgPrint(("Filemon: opened the root directory!!! handle: %x/n", ntFileHandle));

//
// Got the file handle, so now look-up the file-object it refers to
//
ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA,
NULL, KernelMode, &amp;fileObject, NULL );
if( !NT_SUCCESS( ntStatus )) {
DbgPrint(("Filemon: Could not get fileobject from %s handle: %x/n",
FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));
ZwClose( ntFileHandle );
return FALSE;
}
//
// Next, find out what device is associated with the file object by getting its related
// device object
//
fileSysDevice = IoGetRelatedDeviceObject( fileObject );
if( ! fileSysDevice ) {
DbgPrint(("Filemon: Could not get related device object for %s: %x/n",
FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
}
//
// The file system's device hasn't been hooked already, so make a hooking device
// object that will be attached to it.
//
ntStatus = IoCreateDevice( DriverObject,
sizeof(HOOK_EXTENSION),
NULL,
fileSysDevice->DeviceType,
0,
FALSE,
&amp;hookDevice );
if( !NT_SUCCESS(ntStatus) ) {
DbgPrint(("Filemon: failed to create associated device %s: %x/n",
FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
}
//
// Clear the device's init flag as per NT DDK KB article on creating device
// objects from a dispatch routine
//
hookDevice->Flags &amp;= ~DO_DEVICE_INITIALIZING;
//
// Finally, attach to the device. The second we're successfully attached, we may
// start receiving IRPs targetted at the device we've hooked.
//
topAttachDevice = IoAttachDeviceToDeviceStack( hookDevice, fileSysDevice );
if( !topAttachDevice ) {
//
// Couldn' attach for some reason
//
DbgPrint(("Filemon: Connect with Filesystem failed: %s (%x) =>%x/n",
FsType == NPFS ? "NPFS" : "MSFS", fileSysDevice, ntStatus ));
//
// Derefence the object and get out
//
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
} else
{
DbgPrint(("Filemon: Successfully connected to Filesystem device %s/n",
FsType == NPFS ? "NPFS" : "MSFS" ));
}
//
// Setup the device extensions. The drive letter and file system object are stored
// in the extension.
//
hookExtension = hookDevice->DeviceExtension;
hookExtension->LogicalDrive = '//';
hookExtension->FileSystem = topAttachDevice;
hookExtension->Hooked = TRUE;
hookExtension->Type = FsType;

//
// Close the file and update the hooked drive list by entering a
// pointer to the hook device object in it.
//
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
if( FsType == NPFS ) NamedPipeHookDevice = hookDevice;
else
MailSlotHookDevice = hookDevice;
return TRUE;
}

//----------------------------------------------------------------------
//
// UnhookSpecialFs
//
// Unhook the named pipe file or mail slot system.
//
//----------------------------------------------------------------------
VOID
UnhookSpecialFs(
FILE_SYSTEM_TYPE FsType
)
{
PHOOK_EXTENSION hookExt;
if( FsType == NPFS &amp;&amp;
NamedPipeHookDevice ) {

hookExt = NamedPipeHookDevice->DeviceExtension;
hookExt->Hooked = FALSE;
NamedPipeHookDevice = NULL;
} else
if( FsType == MSFS &amp;&amp;
MailSlotHookDevice ) {
hookExt = MailSlotHookDevice->DeviceExtension;
hookExt->Hooked = FALSE;
MailSlotHookDevice = NULL;
}
}
 
接上
//----------------------------------------------------------------------
//
// HookDrive
//
// Hook the drive specified by determining which device object to
// attach to. The algorithm used here is similar to the one used
// internally by NT to determine which device object a file system request
// is directed at.
//
//----------------------------------------------------------------------
BOOLEAN
HookDrive(
IN ULONG Drive,
IN PDRIVER_OBJECT DriverObject
)
{
IO_STATUS_BLOCK ioStatus;
HANDLE ntFileHandle;

OBJECT_ATTRIBUTES objectAttributes;
PDEVICE_OBJECT fileSysDevice;
PDEVICE_OBJECT hookDevice;
UNICODE_STRING fileNameUnicodeString;
PFILE_FS_ATTRIBUTE_INFORMATION fileFsAttributes;
ULONG fileFsAttributesSize;
WCHAR filename[] = L"//DosDevices//A://";
NTSTATUS ntStatus;
ULONG i;
PFILE_OBJECT fileObject;
PHOOK_EXTENSION hookExtension;

//
// Is it a legal drive letter?
//
if( Drive >= 26 ) {
return FALSE;
}
//
// Has this drive already been hooked?
//
if( DriveHookDevices[Drive] == NULL ) {
//
// Frob the name to make it refer to the drive specified in the input
// parameter.
//
filename[12] = (CHAR) ('A'+Drive);
//
// We have to figure out what device to hook - first open the volume's
// root directory
//
RtlInitUnicodeString( &amp;fileNameUnicodeString, filename );
InitializeObjectAttributes( &amp;objectAttributes, &amp;fileNameUnicodeString,
OBJ_CASE_INSENSITIVE, NULL, NULL );
ntStatus = ZwCreateFile( &amp;ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS,
&amp;objectAttributes, &amp;ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE,
NULL, 0 );
if( !NT_SUCCESS( ntStatus ) ) {
DbgPrint(("Filemon: Could not open drive %c: %x/n", 'A'+Drive, ntStatus ));
return FALSE;
}
DbgPrint(("Filemon: opened the root directory!!! handle: %x/n", ntFileHandle));

//
// Got the file handle, so now look-up the file-object it refers to
//
ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA,
NULL, KernelMode, &amp;fileObject, NULL );
if( !NT_SUCCESS( ntStatus )) {
DbgPrint(("Filemon: Could not get fileobject from handle: %c/n", 'A'+Drive ));
ZwClose( ntFileHandle );
return FALSE;
}
//
// Next, find out what device is associated with the file object by getting its related
// device object
//
fileSysDevice = IoGetRelatedDeviceObject( fileObject );
if( ! fileSysDevice ) {
DbgPrint(("Filemon: Could not get related device object: %c/n", 'A'+Drive ));
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
}
//
// Check the device list to see if we've already attached to this particular device.
// This can happen when more than one drive letter is being handled by the same network
// redirecter
//
for( i = 0;
i < 26;
i++ ) {
if( DriveHookDevices == fileSysDevice ) {
//
// If we're already watching it, associate this drive letter
// with the others that are handled by the same network driver. This
// enables us to intelligently update the hooking menus when the user
// specifies that one of the group should not be watched -we mark all
// of the related drives as unwatched as well
//
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
DriveHookDevices[ Drive ] = fileSysDevice;
return TRUE;
}
}
//
// The file system's device hasn't been hooked already, so make a hooking device
// object that will be attached to it.
//
ntStatus = IoCreateDevice( DriverObject,
sizeof(HOOK_EXTENSION),
NULL,
fileSysDevice->DeviceType,
0,
FALSE,
&amp;hookDevice );
if( !NT_SUCCESS(ntStatus) ) {
DbgPrint(("Filemon: failed to create associated device: %c/n", 'A'+Drive ));

ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
}
//
// Clear the device's init flag as per NT DDK KB article on creating device
// objects from a dispatch routine
//
hookDevice->Flags &amp;= ~DO_DEVICE_INITIALIZING;
//
// Setup the device extensions. The drive letter and file system object are stored
// in the extension.
//
hookExtension = hookDevice->DeviceExtension;
hookExtension->LogicalDrive = 'A'+Drive;
hookExtension->FileSystem = fileSysDevice;
hookExtension->Hooked = TRUE;
hookExtension->Type = STANDARD;
//
// Finally, attach to the device. The second we're successfully attached, we may
// start receiving IRPs targetted at the device we've hooked.
//
ntStatus = IoAttachDeviceByPointer( hookDevice, fileSysDevice );
if( !NT_SUCCESS(ntStatus) ) {
//
// Couldn' attach for some reason
//
DbgPrint(("Filemon: Connect with Filesystem failed: %c (%x) =>%x/n",
'A'+Drive, fileSysDevice, ntStatus ));
//
// Derefence the object and get out
//
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
return FALSE;
} else
{
//
// Make a new drive group for the device,l if itdo
es not have one
// already
//
DbgPrint(("Filemon: Successfully connected to Filesystem device %c/n", 'A'+Drive ));
}
//
// Determine if this is a NTFS drive
//
fileFsAttributesSize = sizeof( FILE_FS_ATTRIBUTE_INFORMATION) + MAXPATHLEN;
hookExtension->FsAttributes = (PFILE_FS_ATTRIBUTE_INFORMATION) ExAllocatePool( NonPagedPool,
fileFsAttributesSize );
if( hookExtension->FsAttributes &amp;&amp;
!NT_SUCCESS( IoQueryVolumeInformation( fileObject, FileFsAttributeInformation,
fileFsAttributesSize, hookExtension->FsAttributes,
&amp;fileFsAttributesSize ))) {
//
// On failure, we justdo
n't have attributes for this file system
//
ExFreePool( hookExtension->FsAttributes );
hookExtension->FsAttributes = NULL;
}
//
// Close the file and update the hooked drive list by entering a
// pointer to the hook device object in it.
//
ObDereferenceObject( fileObject );
ZwClose( ntFileHandle );
DriveHookDevices[Drive] = hookDevice;

} else
{
hookExtension = DriveHookDevices[Drive]->DeviceExtension;
hookExtension->Hooked = TRUE;
}
return TRUE;
}

//----------------------------------------------------------------------
//
// UnhookDrive
//
// Unhook a previously hooked drive.
//
//----------------------------------------------------------------------
VOID
UnhookDrive(
IN ULONG Drive
)
{
PHOOK_EXTENSION hookExt;
//
// If the drive has been hooked, unhook it and delete the hook
// device object
//
if( DriveHookDevices[Drive] ) {
hookExt = DriveHookDevices[Drive]->DeviceExtension;
hookExt->Hooked = FALSE;
}
}

//----------------------------------------------------------------------
//
// HookDriveSet
//
// Hook/Unhook a set of drives specified by user. Return the set
// that is currently hooked.
//
//----------------------------------------------------------------------
ULONG
HookDriveSet(
IN ULONG DriveSet,
IN PDRIVER_OBJECT DriverObject
)
{
PHOOK_EXTENSION hookExt;
ULONG drive, i;
ULONG bit;
//
// Scan the drive table, looking for hits on the DriveSet bitmask
//
for ( drive = 0;
drive < 26;
++drive ) {
bit = 1 << drive;
//
// Are we supposed to hook this drive?
//
if( (bit &amp;
DriveSet) &amp;&amp;
!(bit &amp;
CurrentDriveSet) ) {
//
// Try to hook drive
//
if( !HookDrive( drive, DriverObject ) ) {

//
// Remove from drive set if can't be hooked
//
DriveSet &amp;= ~bit;
} else
{
//
// hook drives in same drive group
//
for( i = 0;
i < 26;
i++ ) {
if( DriveHookDevices == DriveHookDevices[ drive ] ) {
DriveSet |= ( 1<<i );
}
}
}
} else
if( !(bit &amp;
DriveSet) &amp;&amp;
(bit &amp;
CurrentDriveSet) ) {
//
// Unhook this drive and all in the group
//
for( i = 0;
i< 26;
i++ ) {
if( DriveHookDevices == DriveHookDevices[ drive ] ) {
UnhookDrive( i );
DriveSet &amp;= ~(1 << i);
}
}
}
}
//
// Return set of drives currently hooked
//
CurrentDriveSet = DriveSet;
return DriveSet;
}
//----------------------------------------------------------------------
//
// ControlCodeString
//
// Takes a control code and sees if we know what it is.
//
//----------------------------------------------------------------------
PCHAR
ControlCodeString(
PIO_STACK_LOCATION IrpSp,
ULONG ControlCode,
PCHAR Buffer,
PCHAR Other
)
{
Other[0] = 0;
switch( ControlCode ) {
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
strcpy( Buffer, "FSCTL_REQUEST_OPLOCK_LEVEL_1" );
break;
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
strcpy( Buffer, "FSCTL_REQUEST_OPLOCK_LEVEL_2" );
break;
case FSCTL_REQUEST_BATCH_OPLOCK:
strcpy( Buffer, "FSCTL_REQUEST_BATCH_OPLOCK" );
break;

case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
strcpy( Buffer, "FSCTL_OPLOCK_BREAK_ACKNOWLEDGE" );
break;
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
strcpy( Buffer, "FSCTL_OPBATCH_ACK_CLOSE_PENDING" );
break;
case FSCTL_OPLOCK_BREAK_NOTIFY:
strcpy( Buffer, "FSCTL_OPLOCK_BREAK_NOTIFY" );
break;
case FSCTL_LOCK_VOLUME:
strcpy( Buffer, "FSCTL_LOCK_VOLUME" );
break;
case FSCTL_UNLOCK_VOLUME:
strcpy( Buffer, "FSCTL_UNLOCK_VOLUME" );
break;
case FSCTL_DISMOUNT_VOLUME:
strcpy( Buffer, "FSCTL_DISMOUNT_VOLUME" );
break;
case FSCTL_IS_VOLUME_MOUNTED:
strcpy( Buffer, "FSCTL_IS_VOLUME_MOUNTED" );
break;
case FSCTL_IS_PATHNAME_VALID:
strcpy( Buffer, "FSCTL_IS_PATHNAME_VALID" );
break;
case FSCTL_MARK_VOLUME_DIRTY:
strcpy( Buffer, "FSCTL_MARK_VOLUME_DIRTY" );
break;
case FSCTL_QUERY_RETRIEVAL_POINTERS:
strcpy( Buffer, "FSCTL_QUERY_RETRIEVAL_POINTERS" );
break;
case FSCTL_GET_COMPRESSION:
strcpy( Buffer, "FSCTL_GET_COMPRESSION" );
break;
case FSCTL_SET_COMPRESSION:
strcpy( Buffer, "FSCTL_SET_COMPRESSION" );
break;
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
strcpy( Buffer, "FSCTL_OPLOCK_BREAK_ACK_NO_2" );
break;
case FSCTL_QUERY_FAT_BPB:
strcpy( Buffer, "FSCTL_QUERY_FAT_BPB" );
break;
case FSCTL_REQUEST_FILTER_OPLOCK:
strcpy( Buffer, "FSCTL_REQUEST_FILTER_OPLOCK" );
break;
case FSCTL_FILESYSTEM_GET_STATISTICS:
strcpy( Buffer, "FSCTL_FILESYSTEM_GET_STATISTICS" );
break;
case FSCTL_GET_NTFS_VOLUME_DATA:
strcpy( Buffer, "FSCTL_GET_NTFS_VOLUME_DATA" );
break;
case FSCTL_GET_NTFS_FILE_RECORD:
strcpy( Buffer, "FSCTL_GET_NTFS_FILE_RECORD" );
break;
case FSCTL_GET_VOLUME_BITMAP:
strcpy( Buffer, "FSCTL_GET_VOLUME_BITMAP" );
break;
case FSCTL_GET_RETRIEVAL_POINTERS:
strcpy( Buffer, "FSCTL_GET_RETRIEVAL_POINTERS" );
break;
case FSCTL_MOVE_FILE:
strcpy( Buffer, "FSCTL_MOVE_FILE" );
break;
case FSCTL_IS_VOLUME_DIRTY:
strcpy( Buffer, "FSCTL_IS_VOLUME_DIRTY" );
break;
case FSCTL_ALLOW_EXTENDED_DASD_IO:
strcpy( Buffer, "FSCTL_ALLOW_EXTENDED_DASD_IO" );
break;
//
// *** new to Win2K (NT 5.0)
//
case FSCTL_READ_PROPERTY_DATA:
strcpy( Buffer, "FSCTL_READ_PROPERTY_DATA" );
break;
case FSCTL_WRITE_PROPERTY_DATA:
strcpy( Buffer, "FSCTL_WRITE_PROPERTY_DATA" );
break;
case FSCTL_FIND_FILES_BY_SID:
strcpy( Buffer, "FSCTL_FIND_FILES_BY_SID" );
break;
case FSCTL_DUMP_PROPERTY_DATA:
strcpy( Buffer, "FSCTL_DUMP_PROPERTY_DATA" );
break;
case FSCTL_SET_OBJECT_ID:
strcpy( Buffer, "FSCTL_SET_OBJECT_ID" );
break;
case FSCTL_GET_OBJECT_ID:
strcpy( Buffer, "FSCTL_GET_OBJECT_ID" );
break;
case FSCTL_DELETE_OBJECT_ID:
strcpy( Buffer, "FSCTL_DELETE_OBJECT_ID" );
break;
case FSCTL_SET_REPARSE_POINT:
strcpy( Buffer, "FSCTL_SET_REPARSE_POINT" );
break;
case FSCTL_GET_REPARSE_POINT:
strcpy( Buffer, "FSCTL_GET_REPARSE_POINT" );
break;
case FSCTL_DELETE_REPARSE_POINT:
strcpy( Buffer, "FSCTL_DELETE_REPARSE_POINT" );
break;
case FSCTL_ENUM_USN_DATA:
strcpy( Buffer, "FSCTL_ENUM_USN_DATA" );
break;
case FSCTL_SECURITY_ID_CHECK:
strcpy( Buffer, "FSCTL_SECURITY_ID_CHECK" );
break;
case FSCTL_READ_USN_JOURNAL:
strcpy( Buffer, "FSCTL_READ_USN_JOURNAL" );
break;
case FSCTL_SET_OBJECT_ID_EXTENDED:
strcpy( Buffer, "FSCTL_SET_OBJECT_ID_EXTENDED" );
break;
case FSCTL_CREATE_OR_GET_OBJECT_ID:
strcpy( Buffer, "FSCTL_CREATE_OR_GET_OBJECT_ID" );
break;
case FSCTL_SET_SPARSE:
strcpy( Buffer, "FSCTL_SET_SPARSE" );
break;
case FSCTL_SET_ZERO_DATA:
strcpy( Buffer, "FSCTL_SET_ZERO_DATA" );
break;
case FSCTL_QUERY_ALLOCATED_RANGES:
strcpy( Buffer, "FSCTL_QUERY_ALLOCATED_RANGES" );
break;
case FSCTL_ENABLE_UPGRADE:
strcpy( Buffer, "FSCTL_ENABLE_UPGRADE" );
break;
case FSCTL_SET_ENCRYPTION:
strcpy( Buffer, "FSCTL_SET_ENCRYPTION" );
break;
case FSCTL_ENCRYPTION_FSCTL_IO:
strcpy( Buffer, "FSCTL_ENCRYPTION_FSCTL_IO" );
break;
case FSCTL_WRITE_RAW_ENCRYPTED:
strcpy( Buffer, "FSCTL_WRITE_RAW_ENCRYPTED" );
break;
case FSCTL_READ_RAW_ENCRYPTED:
strcpy( Buffer, "FSCTL_READ_RAW_ENCRYPTED" );
break;
case FSCTL_CREATE_USN_JOURNAL:
strcpy( Buffer, "FSCTL_CREATE_USN_JOURNAL" );
break;
case FSCTL_READ_FILE_USN_DATA:
strcpy( Buffer, "FSCTL_READ_FILE_USN_DATA" );
break;
case FSCTL_WRITE_USN_CLOSE_RECORD:
strcpy( Buffer, "FSCTL_WRITE_USN_CLOSE_RECORD" );
break;
case FSCTL_EXTEND_VOLUME:
strcpy( Buffer, "FSCTL_EXTEND_VOLUME" );
break;
//
// Named pipe file system controls
// (these are all undocumented)
//
case FSCTL_PIPE_DISCONNECT:
strcpy( Buffer, "FSCTL_PIPE_DISCONNECT" );
break;
case FSCTL_PIPE_ASSIGN_EVENT:
strcpy( Buffer, "FSCTL_PIPE_ASSIGN_EVENT" );
break;
case FSCTL_PIPE_QUERY_EVENT:
strcpy( Buffer, "FSCTL_PIPE_QUERY_EVENT" );
break;
case FSCTL_PIPE_LISTEN:
strcpy( Buffer, "FSCTL_PIPE_LISTEN" );
break;
case FSCTL_PIPE_IMPERSONATE:
strcpy( Buffer, "FSCTL_PIPE_IMPERSONATE" );
break;
case FSCTL_PIPE_WAIT:
strcpy( Buffer, "FSCTL_PIPE_WAIT" );
break;
case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
strcpy( Buffer, "FSCTL_QUERY_CLIENT_PROCESS" );
break;
case FSCTL_PIPE_SET_CLIENT_PROCESS:
strcpy( Buffer, "FSCTL_PIPE_SET_CLIENT_PROCESS");
break;
case FSCTL_PIPE_PEEK:
strcpy( Buffer, "FSCTL_PIPE_PEEK" );
break;
case FSCTL_PIPE_INTERNAL_READ:
strcpy( Buffer, "FSCTL_PIPE_INTERNAL_READ" );
sprintf( Other, "ReadLen: %d",
IrpSp->Parameters.DeviceIoControl.InputBufferLength );
break;
case FSCTL_PIPE_INTERNAL_WRITE:
strcpy( Buffer, "FSCTL_PIPE_INTERNAL_WRITE" );
sprintf( Other, "WriteLen: %d",
IrpSp->Parameters.DeviceIoControl.InputBufferLength );
break;
case FSCTL_PIPE_TRANSCEIVE:
strcpy( Buffer, "FSCTL_PIPE_TRANSCEIVE" );
sprintf( Other, "WriteLen: %d ReadLen: %d",
IrpSp->Parameters.DeviceIoControl.InputBufferLength,
IrpSp->Parameters.DeviceIoControl.OutputBufferLength );
break;
case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
strcpy( Buffer, "FSCTL_PIPE_INTERNAL_TRANSCEIVE" );
sprintf( Other, "WriteLen: %d ReadLen: %d",
IrpSp->Parameters.DeviceIoControl.InputBufferLength,
IrpSp->Parameters.DeviceIoControl.OutputBufferLength );
break;

//
// Mail slot file system controls
// (these are all undocumented)
//
case FSCTL_MAILSLOT_PEEK:
strcpy( Buffer, "FSCTL_MAILSLOT_PEEK" );
break;
//
// Undocumented network redirector controls
//
case FSCTL_NETWORK_GET_CONNECTION_INFO:
strcpy( Buffer, "FSCTL_NETWORK_GET_CONNECTION_INFO" );
break;
case FSCTL_NETWORK_ENUMERATE_CONNECTIONS:
strcpy( Buffer, "FSCTL_NETWORK_ENUMERATE_CONNECTIONS");
break;
case FSCTL_NETWORK_DELETE_CONNECTION:
strcpy( Buffer, "FSCTL_NETWORK_DELETE_CONNECTION" );
break;
case FSCTL_NETWORK_SET_CONFIGURATION_INFO:
strcpy( Buffer, "FSCTL_NETWORK_SET_CONFIGURATION_INFO" );
break;
case FSCTL_NETWORK_GET_CONFIGURATION_INFO:
strcpy( Buffer, "FSCTL_NETWORK_GET_CONFIGURATION_INFO" );
break;
case FSCTL_NETWORK_GET_STATISTICS:
strcpy( Buffer, "FSCTL_NETWORK_GET_STATISTICS" );
break;
case FSCTL_NETWORK_SET_DOMAIN_NAME:
strcpy( Buffer, "FSCTL_NETWORK_SET_DOMAIN_NAME" );
break;
case FSCTL_NETWORK_REMOTE_BOOT_INIT_SCRT:
strcpy( Buffer, "FSCTL_NETWORK_REMOTE_BOOT_INIT_SCRT" );
break;
default:
sprintf( Buffer, "IOCTL: 0x%X", ControlCode );
break;
}
return Buffer;
}

//----------------------------------------------------------------------
//
// ErrorString
//
// Returns string representing the passed error condition.
//
//----------------------------------------------------------------------
PCHAR
ErrorString(
NTSTATUS RetStat,
PCHAR Buffer
)
{
switch( RetStat ) {
case STATUS_SUCCESS:
strcpy( Buffer, "SUCCESS" );
break;
case STATUS_CRC_ERROR:
strcpy( Buffer, "CRC ERROR" );
break;
case STATUS_NOT_IMPLEMENTED:
strcpy( Buffer, "NOT IMPLEMENTED" );
break;
case STATUS_EAS_NOT_SUPPORTED:
strcpy( Buffer, "EAS NOT SUPPORTED" );
break;
case STATUS_EA_TOO_LARGE:
strcpy( Buffer, "EA TOO LARGE");
break;
case STATUS_NONEXISTENT_EA_ENTRY:
strcpy( Buffer, "NONEXISTENT EA ENTRY");
break;
case STATUS_BAD_NETWORK_NAME:
strcpy( Buffer, "BAD NETWORK NAME" );
break;
case STATUS_NOTIFY_ENUM_DIR:
strcpy( Buffer, "NOTIFY ENUM DIR" );
break;
case STATUS_FILE_CORRUPT_ERROR:
strcpy( Buffer, "FILE CORRUPT" );
break;
case STATUS_DISK_CORRUPT_ERROR:
strcpy( Buffer, "DISK CORRUPT" );
break;
case STATUS_RANGE_NOT_LOCKED:
strcpy( Buffer, "RANGE NOT LOCKED" );
break;
case STATUS_FILE_CLOSED:
strcpy( Buffer, "FILE CLOSED" );
break;
case STATUS_IN_PAGE_ERROR:
strcpy( Buffer, "IN PAGE ERROR" );
break;
case STATUS_CANCELLED:
strcpy( Buffer, "CANCELLED" );
break;
case STATUS_QUOTA_EXCEEDED:
strcpy( Buffer, "QUOTA EXCEEDED" );
break;
case STATUS_NOT_SUPPORTED:
strcpy( Buffer, "NOT SUPPORTED" );
break;
case STATUS_NO_MORE_FILES:
strcpy( Buffer, "NO MORE FILES" );
break;
case STATUS_BUFFER_TOO_SMALL:
strcpy( Buffer, "BUFFER TOO SMALL" );
break;
case STATUS_OBJECT_NAME_INVALID:
strcpy( Buffer, "NAME INVALID" );
break;
case STATUS_OBJECT_NAME_NOT_FOUND:
strcpy( Buffer, "FILE NOT FOUND" );
break;
case STATUS_NOT_A_DIRECTORY:
strcpy( Buffer, "NOT A DIRECTORY" );
break;
case STATUS_NO_SUCH_FILE:
strcpy( Buffer, "NO SUCH FILE" );
break;
case STATUS_OBJECT_NAME_COLLISION:
strcpy( Buffer, "NAME COLLISION" );
break;
case STATUS_NONEXISTENT_SECTOR:
strcpy( Buffer, "NONEXISTENT SECTOR" );
break;
case STATUS_BAD_NETWORK_PATH:
strcpy( Buffer, "BAD NETWORK PATH" );
break;
case STATUS_OBJECT_PATH_NOT_FOUND:
strcpy( Buffer, "PATH NOT FOUND" );
break;
case STATUS_NO_SUCH_DEVICE:
strcpy( Buffer, "INVALID PARAMETER" );
break;
case STATUS_END_OF_FILE:
strcpy( Buffer, "END OF FILE" );
break;
case STATUS_NOTIFY_CLEANUP:
strcpy( Buffer, "NOTIFY CLEANUP" );
break;
case STATUS_BUFFER_OVERFLOW:
strcpy( Buffer, "BUFFER OVERFLOW" );
break;
case STATUS_NO_MORE_ENTRIES:
strcpy( Buffer, "NO MORE ENTRIES" );
break;
case STATUS_ACCESS_DENIED:
strcpy( Buffer, "ACCESS DENIED" );
break;
case STATUS_SHARING_VIOLATION:
strcpy( Buffer, "SHARING VIOLATION" );
break;

case STATUS_INVALID_PARAMETER:
strcpy( Buffer, "INVALID PARAMETER" );
break;

case STATUS_OPLOCK_BREAK_IN_PROGRESS:
strcpy( Buffer, "OPLOCK BREAK" );
break;

case STATUS_OPLOCK_NOT_GRANTED:
strcpy( Buffer, "OPLOCK NOT GRANTED" );
break;
case STATUS_FILE_LOCK_CONFLICT:
strcpy( Buffer, "FILE LOCK CONFLICT" );
break;
case STATUS_PENDING:
strcpy( Buffer, "PENDING" );
break;

case STATUS_REPARSE:
strcpy( Buffer, "REPARSE" );
break;

case STATUS_MORE_ENTRIES:
strcpy( Buffer, "MORE" );
break;

case STATUS_DELETE_PENDING:
strcpy( Buffer, "DELETE PEND" );
break;

case STATUS_CANNOT_DELETE:
strcpy( Buffer, "CANNOT DELETE" );
break;

case STATUS_LOCK_NOT_GRANTED:
strcpy( Buffer, "NOT GRANTED" );
break;

case STATUS_FILE_IS_A_DIRECTORY:
strcpy( Buffer, "IS DIRECTORY" );
break;
case STATUS_ALREADY_COMMITTED:
strcpy( Buffer, "ALREADY COMMITTED" );
break;
case STATUS_INVALID_EA_FLAG:
strcpy( Buffer, "INVALID EA FLAG" );
break;
case STATUS_INVALID_INFO_CLASS:
strcpy( Buffer, "INVALID INFO CLASS" );
break;
case STATUS_INVALID_HANDLE:
strcpy( Buffer, "INVALID HANDLE" );
break;
case STATUS_INVALID_DEVICE_REQUEST:
strcpy( Buffer, "INVALID DEVICE REQUEST" );
break;
case STATUS_WRONG_VOLUME:
strcpy( Buffer, "WRONG VOLUME" );
break;
case STATUS_UNEXPECTED_NETWORK_ERROR:
strcpy( Buffer, "NETWORK ERROR" );
break;
case STATUS_DFS_UNAVAILABLE:
strcpy( Buffer, "DFS UNAVAILABLE" );
break;
case STATUS_LOG_FILE_FULL:
strcpy( Buffer, "LOG FILE FULL" );
break;
case STATUS_INVALID_DEVICE_STATE:
strcpy( Buffer, "INVALID DEVICE STATE" );
break;
case STATUS_NO_MEDIA_IN_DEVICE:
strcpy( Buffer, "NO MEDIA");
break;
case STATUS_DISK_FULL:
strcpy( Buffer, "DISK FULL");
break;
case STATUS_DIRECTORY_NOT_EMPTY:
strcpy( Buffer, "NOT EMPTY");
break;
//
// Named pipe errors
//
case STATUS_INSTANCE_NOT_AVAILABLE:
strcpy( Buffer, "INSTANCE NOT AVAILABLE" );
break;
case STATUS_PIPE_NOT_AVAILABLE:
strcpy( Buffer, "PIPE NOT AVAILABLE" );
break;
case STATUS_INVALID_PIPE_STATE:
strcpy( Buffer, "INVALID PIPE STATE" );
break;
case STATUS_PIPE_BUSY:
strcpy( Buffer, "PIPE BUSY" );
break;
case STATUS_PIPE_DISCONNECTED:
strcpy( Buffer, "PIPE DISCONNECTED" );
break;
case STATUS_PIPE_CLOSING:
strcpy( Buffer, "PIPE CLOSING" );
break;
case STATUS_PIPE_CONNECTED:
strcpy( Buffer, "PIPE CONNECTED" );
break;
case STATUS_PIPE_LISTENING:
strcpy( Buffer, "PIPE LISTENING" );
break;
case STATUS_INVALID_READ_MODE:
strcpy( Buffer, "INVALID READ MODE" );
break;
case STATUS_PIPE_EMPTY:
strcpy( Buffer, "PIPE EMPTY" );
break;
case STATUS_PIPE_BROKEN:
strcpy( Buffer, "PIPE BROKEN" );
break;
case STATUS_IO_TIMEOUT:
strcpy( Buffer, "IO TIMEOUT" );
break;
default:
sprintf( Buffer, "* 0x%X", RetStat );
break;
}
return Buffer;
}
//----------------------------------------------------------------------
//
// CreateOptionsString
//
// Takes the options mask and returns a string that represents
// the settings.
//
//----------------------------------------------------------------------
PCHAR
CreateOptionsString(
ULONG Options,
PCHAR Buffer
)
{
ULONG disposition;
Buffer[0] = 0;
disposition = (Options >> 24) &amp;
0xFF;

switch( disposition ) {
case FILE_SUPERSEDE:
strcat( Buffer, "Supersede " );
break;
case FILE_CREATE:
strcat( Buffer, "Create " );
break;
case FILE_OPEN_IF:
strcat( Buffer, "OpenIf " );
break;
case FILE_OPEN:
strcat( Buffer, "Open " );
break;
case FILE_OVERWRITE:
strcat( Buffer, "Overwrite " );
break;
case FILE_OVERWRITE_IF:
strcat( Buffer, "OverwriteIf " );
break;
}
if( Options &amp;
FILE_DIRECTORY_FILE )
strcat( Buffer, "Directory " );
if( Options &amp;
FILE_WRITE_THROUGH )
strcat( Buffer, "WriteThrough " );
if( Options &amp;
FILE_SEQUENTIAL_ONLY )
strcat( Buffer, "Sequential " );
if( Options &amp;
FILE_NO_INTERMEDIATE_BUFFERING )
strcat( Buffer, "NoBuffer" );
if( Options &amp;
FILE_OPEN_BY_FILE_ID )
strcat( Buffer, "ByID");
return Buffer;
}
//----------------------------------------------------------------------
//
// CreateAttributesString
//
// Take attributes and return a string that represents them.
// 获取文件的属性,并使用字符显示出来
//
//----------------------------------------------------------------------
PCHAR
CreateAttributesString(
USHORT Attributes,
PCHAR Buffer
)
{
Buffer[0] = 0;
if( !Attributes ) {
strcat( Buffer, "Any" );
return Buffer;
}
if( Attributes &amp;
FILE_ATTRIBUTE_COMPRESSED) strcat( Buffer, "C" );
if( Attributes &amp;
FILE_ATTRIBUTE_TEMPORARY) strcat( Buffer, "T" );
if( Attributes &amp;
FILE_ATTRIBUTE_DIRECTORY) strcat( Buffer, "D" );
if( Attributes &amp;
FILE_ATTRIBUTE_READONLY) strcat( Buffer, "R" );
if( Attributes &amp;
FILE_ATTRIBUTE_HIDDEN ) strcat( Buffer, "H" );
if( Attributes &amp;
FILE_ATTRIBUTE_SYSTEM ) strcat( Buffer, "S" );
if( Attributes &amp;
FILE_ATTRIBUTE_ARCHIVE ) strcat( Buffer, "A" );
if( Attributes &amp;
FILE_ATTRIBUTE_NORMAL ) strcat( Buffer, "N" );
return Buffer;
}

//----------------------------------------------------------------------
// F A S T I O R O U T I N E S
//
// NOTE: There is no need for us to worry about accessing fastio
// parameters within try/except because the I/O manager has either
// probed the validity of the arguments or calls within its own
// try/except block (itdo
esn't trust us anyway :-) ).
//
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//
// FilemonFastIoCheckIfPossible
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoCheckifPossible(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
IN ULONG LockKey,
IN BOOLEAN CheckForReadOperation,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoCheckIfPossible ) ) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoCheckIfPossible(
FileObject, FileOffset, Length,
Wait, LockKey, CheckForReadOperation, IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_CHECK_IF_POSSIBLE/t%s/t%s Offset: %d Length: %d/t%s",
FilemonGetProcess( name ),fullPathName,
CheckForReadOperation ? "Read:" : "Write:",
FileOffset->LowPart, Length,
retval?"SUCCESS":"FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoRead
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoRead(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
IN ULONG LockKey,
OUT PVOID Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoRead ) ) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoRead(
FileObject, FileOffset, Length,
Wait, LockKey, Buffer, IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_READ/t%s/tOffset: %d Length: %ld/t%s",
FilemonGetProcess( name ), fullPathName,
FileOffset->LowPart, Length,
retval?ErrorString( IoStatus->Status, errorBuf):"FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoWrite
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoWrite(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
IN ULONG LockKey,
IN PVOID Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoWrite )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoWrite(
FileObject, FileOffset, Length, Wait, LockKey,
Buffer, IoStatus, hookExt->FileSystem );
if( FilterDef.logwrites &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_WRITE/t%s/tOffset: %d Length: %d/t%s",
FilemonGetProcess( name ), fullPathName,
FileOffset->LowPart, Length,
retval?ErrorString( IoStatus->Status, errorBuf ):"FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoQueryBasicinfo
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoQueryBasicInfo(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
OUT PFILE_BASIC_INFORMATION Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
CHAR attributeString[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoQueryBasicInfo ) ) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(
FileObject, Wait, Buffer, IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
if( retval ) {
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_QUERY_BASIC_INFO/t%s/tAttributes: %s/t%s",
FilemonGetProcess( name ), fullPathName,
NT_SUCCESS(IoStatus->Status) ?
CreateAttributesString((USHORT)((PFILE_BASIC_INFORMATION) Buffer)->FileAttributes,
attributeString ) :
"Error",
retval?ErrorString( IoStatus->Status, errorBuf ):"FAILURE" );
} else
{
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_QUERY_BASIC_INFO/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName, retval?"SUCCESS":"FAILURE" );
}
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoQueryStandardInfo
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoQueryStandardInfo(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
OUT PFILE_STANDARD_INFORMATION Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoQueryStandardInfo ) ) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoQueryStandardInfo(
FileObject, Wait, Buffer, IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
if( retval ) {
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_QUERY_STANDARD_INFO/t%s/tSize: %d/t%s",
FilemonGetProcess( name ), fullPathName,
((PFILE_STANDARD_INFORMATION) Buffer)->EndOfFile.LowPart,
retval?"SUCCESS":"FAILURE" );
} else
{
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_QUERY_STANDARD_INFO/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName,
retval?ErrorString( IoStatus->Status, errorBuf ):"FAILURE" );
}
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoLock
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoLock(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN PLARGE_INTEGER Length,
PEPROCESS ProcessId,
ULONG Key,
BOOLEAN FailImmediately,
BOOLEAN ExclusiveLock,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoLock )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoLock(
FileObject, FileOffset, Length, ProcessId, Key, FailImmediately,
ExclusiveLock, IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_LOCK/t%s/tExcl: %s Offset: %d Length: %d/t%s",
FilemonGetProcess( name ), fullPathName,
ExclusiveLock ? "Yes":"No", FileOffset ? FileOffset->LowPart : 0,
Length ? Length->LowPart : 0, retval?ErrorString( IoStatus->Status, errorBuf ):"FAILURE" );
}
FREEPATHNAME();
}
return retval;
}
 
怎么这么长啊
不过还是要感谢
爱元元的哥哥
up
 
接上
//----------------------------------------------------------------------
//
// FilemonFastIoUnlockSingle
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoUnlockSingle(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN PLARGE_INTEGER Length,
PEPROCESS ProcessId,
ULONG Key,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;


if( FASTIOPRESENT( hookExt, FastIoUnlockSingle )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoUnlockSingle(
FileObject, FileOffset, Length, ProcessId, Key,
IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_UNLOCK/t%s/tOffset: %d Length: %d/t%s",
FilemonGetProcess( name ), fullPathName,
FileOffset? FileOffset->LowPart : 0, Length ? Length->LowPart : 0,
retval?ErrorString( IoStatus->Status, errorBuf ):"FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoUnlockAll
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoUnlockAll(
IN PFILE_OBJECT FileObject,
PEPROCESS ProcessId,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT(hookExt, FastIoUnlockAll ) ) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoUnlockAll(
FileObject, ProcessId, IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_UNLOCK_ALL/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName,
retval?ErrorString( IoStatus->Status, errorBuf ):"FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoUnlockAllByKey
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoUnlockAllByKey(
IN PFILE_OBJECT FileObject,
PEPROCESS ProcessId,
ULONG Key,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoUnlockAllByKey )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoUnlockAllByKey(
FileObject, ProcessId, Key, IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_UNLOCK_ALL_BY_KEY/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName,
retval?ErrorString( IoStatus->Status, errorBuf):"FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoQueryNetworkOpenInfo
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoQueryNetworkOpenInfo(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoQueryNetworkOpenInfo )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoQueryNetworkOpenInfo(
FileObject, Wait, Buffer, IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_QUERY_NETWORK_OPEN_INFO/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName,
retval ? ErrorString( IoStatus->Status, errorBuf ): "FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoAcquireForModWrite
//
//----------------------------------------------------------------------
NTSTATUS
FilemonFastIoAcquireForModWrite(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER EndingOffset,
OUT struct _ERESOURCE **ResourceToRelease,
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS retval = STATUS_NOT_IMPLEMENTED;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, errval[ERRORLEN], name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, AcquireForModWrite )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->AcquireForModWrite(
FileObject, EndingOffset, ResourceToRelease, hookExt->FileSystem );
if( FilterDef.logwrites &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_ACQUIRE_FOR_MOD_WRITE/t%s/tEndOffset: %d/t%s",
FilemonGetProcess( name ), fullPathName, EndingOffset,
ErrorString( retval, errval ) );
}
FREEPATHNAME();
}
return retval;
}
//----------------------------------------------------------------------
//
// FilemonFastIoMdlRead
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoMdlRead(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, MdlRead )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->MdlRead(
FileObject, FileOffset, Length, LockKey, MdlChain,
IoStatus, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_MDL_READ/t%s/tOffset: %d Length: %d/t%s",
FilemonGetProcess( name ), fullPathName,
FileOffset->LowPart, Length,
retval ? ErrorString( IoStatus->Status, errorBuf ): "FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoMdlReadComplete
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoMdlReadComplete(
IN PFILE_OBJECT FileObject,
IN PMDL MdlChain,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, MdlReadComplete )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = (BOOLEAN) hookExt->FileSystem->DriverObject->FastIoDispatch->MdlReadComplete( FileObject,
MdlChain, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_MDL_READ_COMPLETE/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName, "OK" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoPrepareMdlWrite
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoPrepareMdlWrite(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
IoStatus->Status = STATUS_NOT_IMPLEMENTED;
IoStatus->Information = 0;
if( FASTIOPRESENT( hookExt, PrepareMdlWrite )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->PrepareMdlWrite(
FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus,
hookExt->FileSystem );
if( FilterDef.logwrites &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_PREPARE_MDL_WRITE/t%s/tOffset: %d Length: %d/t%s",
FilemonGetProcess( name ), fullPathName,
FileOffset->LowPart, Length,
retval ? ErrorString( IoStatus->Status, errorBuf ): "FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoMdlWriteComplete
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoMdlWriteComplete(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN PMDL MdlChain,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;

if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, MdlWriteComplete )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->MdlWriteComplete(
FileObject, FileOffset, MdlChain, hookExt->FileSystem );
if( FilterDef.logwrites &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_MDL_WRITE_COMPLETE/t%s/tOffset: %d/tOK",
FilemonGetProcess( name ), fullPathName, FileOffset->LowPart );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoReadCompressed
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoReadCompressed(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PVOID Buffer,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
IN ULONG CompressedDataInfoLength,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoReadCompressed )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoReadCompressed(
FileObject, FileOffset, Length, LockKey, Buffer, MdlChain, IoStatus,
CompressedDataInfo, CompressedDataInfoLength, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_READ_COMPRESSED/t%s/tOffset: %d Length: %d/t%s",
FilemonGetProcess( name ), fullPathName,
FileOffset->LowPart, Length,
retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoWriteCompressed
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoWriteCompressed(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PVOID Buffer,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
IN ULONG CompressedDataInfoLength,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoWriteCompressed )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoWriteCompressed(
FileObject, FileOffset, Length, LockKey, Buffer, MdlChain, IoStatus,
CompressedDataInfo, CompressedDataInfoLength, hookExt->FileSystem );
if( FilterDef.logwrites &amp;&amp;
hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_WRITE_COMPRESSED/t%s/tOffset: %d Length: %d/t%s",
FilemonGetProcess( name ), fullPathName,
FileOffset->LowPart, Length,
retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoMdlReadCompleteCompressed
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoMdlReadCompleteCompressed(
IN PFILE_OBJECT FileObject,
IN PMDL MdlChain,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, MdlReadCompleteCompressed )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->MdlReadCompleteCompressed(
FileObject, MdlChain, hookExt->FileSystem );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_MDL_READ_COMPLETE_COMPRESSED/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName, "OK" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoMdlWriteCompleteCompressed
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoMdlWriteCompleteCompressed(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN PMDL MdlChain,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;

if( FASTIOPRESENT( hookExt, MdlWriteCompleteCompressed )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->MdlWriteCompleteCompressed(
FileObject, FileOffset, MdlChain, hookExt->FileSystem );
if( FilterDef.logwrites &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_MDL_WRITE_COMPLETE_COMPRESSED/t%s/tOffset: %d/t%s",
FilemonGetProcess( name ), fullPathName, FileOffset->LowPart, "OK" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoQueryOpen
//
// This call actually passes an IRP!
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoQueryOpen(
IN PIRP Irp,
OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
PHOOK_EXTENSION hookExt;
PFILE_OBJECT FileObject;
CHAR *fullPathName, name[PROCNAMELEN];
PIO_STACK_LOCATION currentIrpStack;
PIO_STACK_LOCATION nextIrpStack;
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return FALSE;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoQueryOpen )) {
currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
nextIrpStack = IoGetNextIrpStackLocation(Irp);
FileObject = currentIrpStack->FileObject;
//
// copy parametersdo
wn to next level in the stack
//
*nextIrpStack = *currentIrpStack;
nextIrpStack->DeviceObject = hookExt->FileSystem;
IoSetNextIrpStackLocation( Irp );
//
// Get path and timestamp
//
GETPATHNAME(TRUE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoQueryOpen(
Irp, NetworkInformation, hookExt->FileSystem );
//
// Reset the stack location because pre-NT 5.0 checked builds complain
//
Irp->CurrentLocation++;
Irp->Tail.Overlay.CurrentStackLocation++;
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_QUERY_OPEN/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName, retval ? "SUCCESS" : "FAILURE" );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoReleaseForModWrite
//
//----------------------------------------------------------------------
NTSTATUS
FilemonFastIoReleaseForModWrite(
IN PFILE_OBJECT FileObject,
IN struct _ERESOURCE *ResourceToRelease,
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS retval = STATUS_NOT_IMPLEMENTED;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, errval[ERRORLEN], name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;

if( !DeviceObject ) return STATUS_NOT_IMPLEMENTED;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, ReleaseForModWrite )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->ReleaseForModWrite(
FileObject, ResourceToRelease, hookExt->FileSystem );
if( FilterDef.logwrites &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_RELEASE_FOR_MOD_WRITE/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName, ErrorString( retval, errval ));
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoAcquireForCcFlush
//
//----------------------------------------------------------------------
NTSTATUS
FilemonFastIoAcquireForCcFlush(
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS retval = STATUS_NOT_IMPLEMENTED;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, errval[ERRORLEN], name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return STATUS_NOT_IMPLEMENTED;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, AcquireForCcFlush )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->AcquireForCcFlush(
FileObject, hookExt->FileSystem );
if( FilterDef.logwrites &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_ACQUIRE_FOR_CC_FLUSH/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName, ErrorString( retval, errval));
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoReleaseForCcFlush
//
//----------------------------------------------------------------------
NTSTATUS
FilemonFastIoReleaseForCcFlush(
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS retval = STATUS_NOT_IMPLEMENTED;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, errval[ERRORLEN], name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
if( !DeviceObject ) return STATUS_NOT_IMPLEMENTED;
hookExt = DeviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, ReleaseForCcFlush )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->ReleaseForCcFlush(
FileObject, hookExt->FileSystem );
if( FilterDef.logwrites &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL,
&amp;dateTime, &amp;timeResult,
"%s/tFASTIO_RELEASE_FOR_CC_FLUSH/t%s/t/t%s",
FilemonGetProcess( name ), fullPathName, ErrorString( retval, errval) );
}
FREEPATHNAME();
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoDeviceControl
//
//----------------------------------------------------------------------
BOOLEAN
FilemonFastIoDeviceControl(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength,
IN ULONG IoControlCode,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN retval = FALSE;
BOOLEAN logMutexReleased;
PHOOK_EXTENSION hookExt;
PLOG_BUF oldLog, savedCurrentLog;
CHAR fullPathName[MAXPATHLEN], name[PROCNAMELEN], errorBuf[ERRORLEN];
KIRQL oldirql;
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
hookExt = DeviceObject->DeviceExtension;
if( hookExt->Type == GUIINTERFACE ) {
//
// Its a message from our GUI!
//
IoStatus->Status = STATUS_SUCCESS;
// Assume success
IoStatus->Information = 0;
// Assume nothing returned
switch ( IoControlCode ) {
case IOCTL_FILEMON_VERSION:
//
// Version #
//
if( OutputBufferLength >= sizeof(ULONG)) {
*(ULONG *)OutputBuffer = FILEMONVERSION;
IoStatus->Information = sizeof(ULONG);
} else
{
IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case IOCTL_FILEMON_SETDRIVES:
//
// Hook and/or unhook drives
//
DbgPrint (("Filemon: set drives/n"));
if( InputBufferLength >= sizeof(ULONG) &amp;&amp;
OutputBufferLength >= sizeof(ULONG)) {
*(ULONG *)OutputBuffer = HookDriveSet( *(ULONG *)InputBuffer, DeviceObject->DriverObject );
IoStatus->Information = sizeof(ULONG);
} else
{
IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case IOCTL_FILEMON_HOOKSPECIAL:
if( InputBufferLength >= sizeof(FILE_SYSTEM_TYPE )) {
if( !HookSpecialFs( DeviceObject->DriverObject, *(PFILE_SYSTEM_TYPE) InputBuffer )) {

IoStatus->Status = STATUS_UNSUCCESSFUL;
}
} else
{
IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case IOCTL_FILEMON_UNHOOKSPECIAL:
if( InputBufferLength >= sizeof(FILE_SYSTEM_TYPE )) {
UnhookSpecialFs( *(PFILE_SYSTEM_TYPE) InputBuffer );
} else
{
IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case IOCTL_FILEMON_STOPFILTER:

//
// Turn off logging
//
DbgPrint(("Filemon: stop logging/n"));
FilterOn = FALSE;
break;
case IOCTL_FILEMON_STARTFILTER:

//
// Turn on logging
//
DbgPrint(("Filemon: start logging/n"));
FilterOn = TRUE;
break;
case IOCTL_FILEMON_SETFILTER:

//
// Gui is updating the filter functions
//
DbgPrint(("Filemon: set filter/n"));
if( InputBufferLength >= sizeof(FILTER) ) {
FilterDef = *(PFILTER) InputBuffer;
FilemonUpdateFilters();
} else
{
IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case IOCTL_FILEMON_UNLOADQUERY:
#if DBG
//
// Is it possible to unload?
//
KeAcquireSpinLock( &amp;CountMutex, &amp;oldirql );
IoStatus->Information = OutstandingIRPCount;
//
// Any outstanding Irps?
//
if( !OutstandingIRPCount ) {
//
// Nope, sodo
n't process anymore
//
UnloadInProgress = TRUE;
KeReleaseSpinLock( &amp;CountMutex, oldirql );
//
// Stop capturing drives
//
HookDriveSet( 0, DeviceObject->DriverObject );
UnhookSpecialFs( NPFS );
UnhookSpecialFs( MSFS );
//
// Detach from all devices
//
UnloadDetach();
} else
{
KeReleaseSpinLock( &amp;CountMutex, oldirql );
}
#else
// DBG
IoStatus->Information = 1;
#endif // DBG
break;
case IOCTL_FILEMON_ZEROSTATS:
//
// Reset all output buffers
//
DbgPrint (("Filemon: zero stats/n"));
ExAcquireFastMutex( &amp;LogMutex );
while( CurrentLog->Next ) {
//
// Free all but the first output buffer
//
oldLog = CurrentLog->Next;
CurrentLog->Next = oldLog->Next;
ExFreePool( oldLog );
NumLog--;
}

//
// Set the output pointer to the start of the output buffer
//
CurrentLog->Len = 0;
Sequence = 0;
ExReleaseFastMutex( &amp;LogMutex );
break;
case IOCTL_FILEMON_GETSTATS:
//
// Copy the oldest output buffer to the caller
//
DbgPrint (("Filemon: get stats/n"));
//
// If the output buffer is too large to fit into the caller's buffer
//
if( LOGBUFSIZE > OutputBufferLength ) {
IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
return FALSE;
}
//
// Probe the output buffer
//
try {
ProbeForWrite( OutputBuffer,
OutputBufferLength,
sizeof( UCHAR ));
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoStatus->Status = STATUS_INVALID_PARAMETER;
return FALSE;
}
//
// We're okay, lock the buffer pool
//
ExAcquireFastMutex( &amp;LogMutex );
if( CurrentLog->Len || CurrentLog->Next ) {
//
// Start output to a new output buffer
//
FilemonAllocateLog();
//
// Fetch the oldest to give to user
//
oldLog = FilemonGetOldestLog();
if( oldLog != CurrentLog ) {
logMutexReleased = TRUE;
ExReleaseFastMutex( &amp;LogMutex );
} else
{
logMutexReleased = FALSE;
}
//
// Copy it to the caller's buffer
//
memcpy( OutputBuffer, oldLog->Data, oldLog->Len );
//
// Return length of copied info
//
IoStatus->Information = oldLog->Len;
//
// Deallocate buffer - unless its the last one
//
if( logMutexReleased ) {

ExFreePool( oldLog );
} else
{
CurrentLog->Len = 0;
ExReleaseFastMutex( &amp;LogMutex );

}
} else
{
//
// There is no unread data
//
ExReleaseFastMutex( &amp;LogMutex );
IoStatus->Information = 0;
}
break;

default:
//
// Unknown control
//
DbgPrint (("Filemon: unknown IRP_MJ_DEVICE_CONTROL/n"));
IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
retval = TRUE;
} else
{
//
// Its a call for a file system, so pass it through
//
if( FASTIOPRESENT( hookExt, FastIoDeviceControl ) ) {

FilemonGetFullPath( FALSE, FileObject, hookExt, fullPathName );
TIMESTAMPSTART();
retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoDeviceControl(
FileObject, Wait, InputBuffer, InputBufferLength, OutputBuffer,
OutputBufferLength, IoControlCode, IoStatus, hookExt->FileSystem );
if(hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL, &amp;dateTime, &amp;timeResult,
"%s/tFASTIO_DEVICE_CONTROL/t%s/tIOCTL: 0x%X/t%s",
FilemonGetProcess( name ), fullPathName,
IoControlCode,
retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );
}
}
}
return retval;
}

//----------------------------------------------------------------------
//
// FilemonFastIoAcquireFile
//
//----------------------------------------------------------------------
VOID
FilemonFastIoAcquireFile(
PFILE_OBJECT FileObject
)
{
PDEVICE_OBJECT deviceObject, checkDevice;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
//
// We've got to locate our own device object
//
checkDevice = FileObject->DeviceObject->Vpb->DeviceObject;
while( checkDevice ) {
if( checkDevice->DriverObject == FilemonDriver ) {

//
// Found it
//
deviceObject = checkDevice;
hookExt = deviceObject->DeviceExtension;
if( FASTIOPRESENT( hookExt, AcquireFileForNtCreateSection )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
hookExt->FileSystem->DriverObject->FastIoDispatch->AcquireFileForNtCreateSection(
FileObject );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL, &amp;dateTime, &amp;timeResult,
"%s/tFASTIO_ACQUIRE_FILE/t%s/t/tOK", FilemonGetProcess( name ),
fullPathName );
}
FREEPATHNAME();
}
return;
}
checkDevice = checkDevice->AttachedDevice;
}
}

//----------------------------------------------------------------------
//
// FilemonFastIoReleaseFile
//
//----------------------------------------------------------------------
VOID
FilemonFastIoReleaseFile(
PFILE_OBJECT FileObject
)
{
PDEVICE_OBJECT deviceObject, checkDevice;
PHOOK_EXTENSION hookExt;
CHAR *fullPathName, name[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
//
// We've got to locate our own device object
//
checkDevice = FileObject->DeviceObject->Vpb->DeviceObject;
while( checkDevice ) {
if( checkDevice->DriverObject == FilemonDriver ) {

deviceObject = IoGetRelatedDeviceObject( FileObject );
hookExt = deviceObject->DeviceExtension;

if( FASTIOPRESENT( hookExt, ReleaseFileForNtCreateSection )) {
GETPATHNAME(FALSE);
TIMESTAMPSTART();
hookExt->FileSystem->DriverObject->FastIoDispatch->ReleaseFileForNtCreateSection( FileObject );
if( FilterDef.logreads &amp;&amp;
hookExt->Hooked) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL, &amp;dateTime, &amp;timeResult,
"%s/tFASTIO_RELEASE_FILE/t%s/t/tOK", FilemonGetProcess( name ),
fullPathName );
}
FREEPATHNAME();
}
return;
}
checkDevice = checkDevice->AttachedDevice;
}
}

//----------------------------------------------------------------------
//
// FilemonFastIoDetachDevice
//
// We get this call when a device that we have hooked is being deleted.
// This happens when, for example, a floppy is formatted. We have
// to detach from it and delete our device. We should notify the GUI
// that the hook state has changed, but its not worth the trouble.
//
//----------------------------------------------------------------------
VOID
FilemonFastIoDetachDevice(
PDEVICE_OBJECT SourceDevice,
PDEVICE_OBJECT TargetDevice
)
{
PHOOK_EXTENSION hookExt;
ULONG i;
CHAR name[PROCNAMELEN], drive[PROCNAMELEN];
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
LARGE_INTEGER dateTime;
//
// See if a device (like a floppy) is being removed out from under us. If so,
// we have to detach from it before it disappears
//
for( i = 0;
i < 26;
i++ ) {
if( SourceDevice == DriveHookDevices ) {
//
// We've hooked it, so we must detach
//
hookExt = SourceDevice->DeviceExtension;
DbgPrint(("Filemon: Detaching from drive: %c/n",
hookExt->LogicalDrive ));
TIMESTAMPSTART();
sprintf( drive, "%c:", hookExt->LogicalDrive );
if( hookExt->Hooked ) {
TIMESTAMPSTOP();
LogRecord( TRUE, NULL, &amp;dateTime, &amp;timeResult,
"%s/tFASTIO_DETACH_DEVICE/t%s/t/tOK",
FilemonGetProcess( name ), drive );
}
IoDetachDevice( TargetDevice );
IoDeleteDevice( SourceDevice );
DriveHookDevices = NULL;
return;
}
}
//
// It wasn't for us, so pass it on.
//
hookExt = SourceDevice->DeviceExtension;
if( FASTIOPRESENT( hookExt, FastIoDetachDevice )) {
hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoDetachDevice(
SourceDevice, TargetDevice );
}
}

//----------------------------------------------------------------------
// D I S P A T C H A N D H O O K E N T R Y P O I N T S
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//
// FilemonHookDoneWork
//
// Worker routine that simply calls update Log. Since we want
// to avoid using spin locks in order to improve SMP performance
// we need todo
everything at passive. When our completion routine
// is called at dispatch, we queue the update off to a worker thread.
//
//----------------------------------------------------------------------
VOID
FilemonHookDoneWork(
PVOID Context
)
{
PFILEMON_WORK filemonWork = (PFILEMON_WORK) Context;
DbgPrint(("HookWorkRoutine/n"));
LogRecord( FALSE, &amp;filemonWork->Sequence,
NULL,
&amp;filemonWork->TimeResult,
filemonWork->ErrString );
ExFreePool( filemonWork );
}

//----------------------------------------------------------------------
//
// FilemonHookDone
//
// Gets control after a filesystem operation has completed so that
// we can get return status information about it.
//
//----------------------------------------------------------------------
NTSTATUS
FilemonHookDone(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PIO_STACK_LOCATION IrpSp;
#if defined(_IA64_)
ULONG seqNum = (ULONG) ((ULONG_PTR)Context);
#else
ULONG seqNum = (ULONG) Context;
#endif
CHAR errval[ERRORLEN], errString[ERRORLEN];
KIRQL oldirql;
LARGE_INTEGER timeStampStart, timeStampComplete, timeResult;
PFILEMON_WORK filemonWorkContext;
//
// A request completed - look at the result
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );

//
// Log the return status in the output buffer. Tag it with the
// sequence number so that the GUI can match it with the IRP input information.
//
if( FilterOn ) {
//
// Quick, get the completion time
//
timeStampStart = IrpSp->Parameters.Read.ByteOffset;
timeStampComplete = KeQueryPerformanceCounter(NULL);
timeResult.QuadPart = timeStampComplete.QuadPart - timeStampStart.QuadPart;
//
// Queue off to a worker thread if we have to
//
if( KeGetCurrentIrql() == DISPATCH_LEVEL ) {
filemonWorkContext = ExAllocatePool( NonPagedPool, sizeof(FILEMON_WORK));
if( filemonWorkContext ) {
filemonWorkContext->Sequence = seqNum;
filemonWorkContext->TimeResult = timeResult;
sprintf( filemonWorkContext->ErrString, "/t/t/t/t%s",
ErrorString( Irp->IoStatus.Status, errval ));
ExInitializeWorkItem( &amp;filemonWorkContext->WorkItem,
FilemonHookDoneWork, filemonWorkContext );
ExQueueWorkItem( &amp;filemonWorkContext->WorkItem, CriticalWorkQueue );
}
} else
{
sprintf( errString, "/t/t/t/t%s", ErrorString( Irp->IoStatus.Status, errval ));
LogRecord( FALSE, &amp;seqNum, NULL, &amp;timeResult, errString );
}
}
#if DBG
//
// We have finished processing an IRP so decrement oustanding IRP count
//
KeAcquireSpinLock( &amp;CountMutex, &amp;oldirql );
OutstandingIRPCount--;
DbgPrint(("-%d: %x/n", OutstandingIRPCount, Irp ));;
if( !OutstandingIRPCount ) FilemonDriver->DriverUnload = FilemonUnload;
KeReleaseSpinLock( &amp;CountMutex, oldirql );
#endif
//
// Now we have to mark Irp as pending if necessary
//
if( Irp->PendingReturned ) {
IoMarkIrpPending( Irp );
}
return Irp->IoStatus.Status;
}

//----------------------------------------------------------------------
//
// FilemonHookRoutine
//
// This routine is the main hook routine where we figure out what
// calls are being sent to the file system.
//
//----------------------------------------------------------------------
NTSTATUS
FilemonHookRoutine(
PDEVICE_OBJECT HookDevice,
IN PIRP Irp
)
{
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
PMOVE_FILE_DATA moveFile;
PQUERY_DIRECTORY queryDirectory;
PFILE_OBJECT FileObject;
PHOOK_EXTENSION hookExt;
LARGE_INTEGER dateTime;
LARGE_INTEGER perfTime;
PCHAR fullPathName = NULL;
BOOLEAN hookCompletion, createPath;
CHAR controlCodeBuffer[ERRORLEN];
CHAR attributeString[ERRORLEN];
CHAR optionString[ERRORLEN];
CHAR name[PROCNAMELEN];
ULONG i;
ANSI_STRING directoryFilter;
PCHAR queryFilter;
ULONG seqNum;
KIRQL oldirql;
//
// Extract the file object from the IRP
//
FileObject = currentIrpStack->FileObject;
//
// Point at the device extension, which contains information on which
// file system this IRP is headed for
//
hookExt = HookDevice->DeviceExtension;
//
// We note open cases so that when we query the file name
// wedo
n't ask the file system for the name (since it won't
// have seen the file object yet).
//
if( currentIrpStack->MajorFunction == IRP_MJ_CREATE ||
currentIrpStack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE ||
currentIrpStack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ) {
//
// Clear any existing fileobject/name association stored in the
// hash table
//
FilemonFreeHashEntry( FileObject );
createPath = TRUE;
} else
if( currentIrpStack->MajorFunction == IRP_MJ_CLOSE ) {
//
// We treat close as a special case of create for name querying
// since calling into NTFS during a close can result in a deadlock.
//
createPath = TRUE;
} else
if( currentIrpStack->MajorFunction == IRP_MJ_CLEANUP &amp;&amp;
FileObject->Flags &amp;
FO_STREAM_FILE ) {
//
// Treat cleanup of stream file objects as special create case, because
// querying them causes NTFS to screwup on NT 4
//
createPath = TRUE;
} else
{
createPath = FALSE;
}
//
// Allocate a buffer and get the name only if we have to
//
if( FilterOn &amp;&amp;
hookExt->Hooked ) {
GETPATHNAME( createPath );
}
//
// Only log it if it passes the filter
//
if( hookExt->Hooked &amp;&amp;
fullPathName ) {
//
// If measuring absolute time go and get the timestamp.
//
KeQuerySystemTime( &amp;dateTime );
perfTime = KeQueryPerformanceCounter( NULL );
//
// We want to watch this IRP complete
//
seqNum = (ULONG) -1;
hookCompletion = FALSE;
//
// Determine what function we're dealing with
//
FilemonGetProcess( name );
switch( currentIrpStack->MajorFunction ) {
case IRP_MJ_CREATE:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_CREATE/t%s/tAttributes: %s Options: %s",
name, fullPathName,
CreateAttributesString( currentIrpStack->Parameters.Create.FileAttributes,
attributeString ),
CreateOptionsString( currentIrpStack->Parameters.Create.Options,
optionString ));

//
// If its an open-by-id we free the hash entry now so that on the next access to
// the file we'll pick up the file's real name.
//
if( currentIrpStack->Parameters.Create.Options &amp;
FILE_OPEN_BY_FILE_ID ) {
FilemonFreeHashEntry( FileObject );
}
break;
case IRP_MJ_CREATE_NAMED_PIPE:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_CREATE_NAMED_PIPE/t%s/tAttributes: %s Options: %s",
name, fullPathName,
CreateAttributesString( currentIrpStack->Parameters.Create.FileAttributes,
attributeString ),
CreateOptionsString( currentIrpStack->Parameters.Create.Options,
optionString ));
break;
case IRP_MJ_CREATE_MAILSLOT:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_CREATE_MAILSLOT/t%s/tAttributes: %s Options: %s",
name, fullPathName,
CreateAttributesString( currentIrpStack->Parameters.Create.FileAttributes,
attributeString ),
CreateOptionsString( currentIrpStack->Parameters.Create.Options,
optionString ));
break;
case IRP_MJ_READ:
if( FilterDef.logreads ) {
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_READ%c/t%s/tOffset: %d Length: %d",
name,
(Irp->Flags &amp;
IRP_PAGING_IO) ||
(Irp->Flags &amp;
IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',
fullPathName,
currentIrpStack->Parameters.Read.ByteOffset.LowPart,
currentIrpStack->Parameters.Read.Length );
}
break;
case IRP_MJ_WRITE:
if( FilterDef.logwrites ) {
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_WRITE%c/t%s/tOffset: %d Length: %d",
name,
(Irp->Flags &amp;
IRP_PAGING_IO) ||
(Irp->Flags &amp;
IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',
fullPathName,
currentIrpStack->Parameters.Write.ByteOffset.LowPart,
currentIrpStack->Parameters.Write.Length );
}
break;
case IRP_MJ_CLOSE:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_CLOSE%c/t%s/t",
name,
(Irp->Flags &amp;
IRP_PAGING_IO) ||
(Irp->Flags &amp;
IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',
fullPathName );
//
// This fileobject/name association can be discarded now.
//
FilemonFreeHashEntry( FileObject );
break;
case IRP_MJ_FLUSH_BUFFERS:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_FLUSH/t%s/t", name, fullPathName );
break;
case IRP_MJ_QUERY_INFORMATION:

hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_QUERY_INFORMATION/t%s/t%s",
name, fullPathName,
FileInformation[currentIrpStack->Parameters.QueryFile.FileInformationClass] );
break;
case IRP_MJ_SET_INFORMATION:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_SET_INFORMATION%c/t%s/t%s",
name,
(Irp->Flags &amp;
IRP_PAGING_IO) ||
(Irp->Flags &amp;
IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',
fullPathName,
FileInformation[currentIrpStack->Parameters.SetFile.FileInformationClass] );
//
// If its a rename, cleanup the name association.
//
if( currentIrpStack->Parameters.SetFile.FileInformationClass ==
FileRenameInformation ) {
FilemonFreeHashEntry( FileObject );
}
break;
case IRP_MJ_QUERY_EA:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_QUERY_EA/t%s/t", name, fullPathName );
break;
case IRP_MJ_SET_EA:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_SET_EA/t%s/t", name, fullPathName );
break;
case IRP_MJ_QUERY_VOLUME_INFORMATION:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_QUERY_VOLUME_INFORMATION/t%s/t%s",
name, fullPathName,
VolumeInformation[currentIrpStack->Parameters.QueryVolume.FsInformationClass] );
break;
case IRP_MJ_SET_VOLUME_INFORMATION:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_SET_VOLUME_INFORMATION/t%s/t%s",
name, fullPathName,
VolumeInformation[currentIrpStack->Parameters.QueryVolume.FsInformationClass] );
break;
case IRP_MJ_DIRECTORY_CONTROL:
switch( currentIrpStack->MinorFunction ) {
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_DIRECTORY_CONTROL/t%s/tChange Notify",
name, fullPathName );
break;
case IRP_MN_QUERY_DIRECTORY:
queryDirectory = (PQUERY_DIRECTORY)&amp;currentIrpStack->Parameters;
queryFilter = NULL;
if( queryDirectory->FileName ) {
if( NT_SUCCESS( RtlUnicodeStringToAnsiString( &amp;directoryFilter,
queryDirectory->FileName, TRUE ))) {

queryFilter = ExAllocatePool( PagedPool, directoryFilter.Length + 1 );
if( queryFilter ) {
memcpy( queryFilter, directoryFilter.Buffer, directoryFilter.Length );
queryFilter[ directoryFilter.Length ] = 0;
//
// Massagedo
S-internal wildcards
//
for( i = 0;
i < strlen( queryFilter );
i++ ) {
if( queryFilter == '<' ) queryFilter = '*';
else
if( queryFilter == '>' ) queryFilter = '?';
}
}
RtlFreeAnsiString( &amp;directoryFilter );
}
}
if( queryFilter ) {
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_DIRECTORY_CONTROL/t%s/t%s: %s",
name, fullPathName,
FileInformation[queryDirectory->FileInformationClass],
queryFilter );
ExFreePool( queryFilter );
} else
{
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_DIRECTORY_CONTROL/t%s/t%s",
name, fullPathName,
FileInformation[queryDirectory->FileInformationClass] );
}
break;
default:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_DIRECTORY_CONTROL/t%s/t",
name, fullPathName );
break;
}
break;
case IRP_MJ_FILE_SYSTEM_CONTROL:
switch( currentIrpStack->Parameters.DeviceIoControl.IoControlCode ) {
case FSCTL_MOVE_FILE:
moveFile = (PMOVE_FILE_DATA) Irp->AssociatedIrp.SystemBuffer;
sprintf( optionString, "Vcn: %d Len: %d Target: %d",
moveFile->StartingVcn.LowPart,
moveFile->ClusterCount,
moveFile->StartingLcn.LowPart );
ObReferenceObjectByHandle( moveFile->FileHandle, 0, NULL, KernelMode, &amp;FileObject, NULL );
FilemonGetFullPath( FALSE, FileObject, hookExt, fullPathName );
ObDereferenceObject( FileObject );
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tFSCTL_MOVE_FILE/t%s/t%s",
name, fullPathName, optionString );
break;
default:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/t%s/t%s/t%s",
name,
ControlCodeString( currentIrpStack,
currentIrpStack->Parameters.DeviceIoControl.IoControlCode,
controlCodeBuffer, optionString ),
fullPathName, optionString );
}
break;
case IRP_MJ_SHUTDOWN:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_SHUTDOWN/t/t", name );
break;
case IRP_MJ_LOCK_CONTROL:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_LOCK_CONTROL/t%s/tOffset: %d Length: %d",
name, fullPathName,
((PLOCK_CONTROL)&amp;currentIrpStack->Parameters)->ByteOffset.LowPart,
((PLOCK_CONTROL)&amp;currentIrpStack->Parameters)->Length ?
((PLOCK_CONTROL)&amp;currentIrpStack->Parameters)->Length->LowPart : 0 );
break;
case IRP_MJ_CLEANUP:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_CLEANUP/t%s/t", name, fullPathName );
break;
case IRP_MJ_DEVICE_CONTROL:

hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_DEVICE_CONTROL/t%s/tIOCTL: 0x%X", name,
fullPathName, currentIrpStack->Parameters.DeviceIoControl.IoControlCode );
break;
case IRP_MJ_QUERY_SECURITY:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_QUERY_SECURITY/t%s/t",
name, fullPathName );
break;
case IRP_MJ_SET_SECURITY:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_SET_SECURITY/t%s/t",
name, fullPathName );
break;
case IRP_MJ_POWER:

hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_POWER/t%s/tMinor: %x",
name, fullPathName,
currentIrpStack->MinorFunction );
break;
case IRP_MJ_PNP:

hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/tIRP_MJ_PNP/t%s/t%s",
name, fullPathName,
currentIrpStack->MinorFunction <= IRP_MN_QUERY_LEGACY_BUS_INFORMATION ?
PnpMinorCode[currentIrpStack->MinorFunction] : "New minor code" );
break;
default:
hookCompletion = LogRecord( TRUE, &amp;seqNum, &amp;dateTime, NULL,
"%s/t*UNKNOWN* 0x%X/t/t", name, currentIrpStack->MajorFunction );
break;
}
} else
{
//
// Wedo
n't care about this IRP's completion
//
hookCompletion = FALSE;
//
//do
name processing for the sake of keeping the hash table current
//
switch( currentIrpStack->MajorFunction ) {
case IRP_MJ_CLOSE:
//
// This fileobject/name association can be discarded now.
//
FilemonFreeHashEntry( FileObject );
break;
}
}
//
// Free the buffer if we have one
//
if( fullPathName &amp;&amp;
fullPathName != InsufficientResources ) {
ExFreeToNPagedLookasideList( &amp;FullPathLookaside, fullPathName );
}
//
// Copy parametersdo
wn to next level in the stack for the driver below us
//
*nextIrpStack = *currentIrpStack;
#if DBG
//
// If an unload isn't in progress, we should register a completion callback
// so that the IRP's return status can be examined.
//
KeAcquireSpinLock( &amp;CountMutex, &amp;oldirql );
#endif
if( !UnloadInProgress &amp;&amp;
hookCompletion ) {
#if DBG
//
// Increment the outstanding IRP count since this IRP will be headed
// for our completion routine
//
FilemonDriver->DriverUnload = NULL;
OutstandingIRPCount++;
DbgPrint(("+%d: %x/n", OutstandingIRPCount, Irp ));;
#endif // DBG
//
// Grab the time stamp and Log it in the current stack location. This
// is legal since the stack location is ours, and we'redo
ne looking at
// the parameters. This makes it easy to pass this to the completion routine. The
// DiskPerf example in the NT DDK uses this trick.
//
currentIrpStack->Parameters.Read.ByteOffset = perfTime;
#if defined(_IA64_)
IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) (ULONG_PTR) seqNum, TRUE, TRUE, TRUE );
#else
IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) seqNum, TRUE, TRUE, TRUE );
#endif
} else
{
//
// Set no completion routine
//
IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, FALSE, FALSE, FALSE );
}
#if DBG
KeReleaseSpinLock( &amp;CountMutex, oldirql );
#endif
//
// Return the results of the call to the caller
//
return IoCallDriver( hookExt->FileSystem, Irp );
}

//----------------------------------------------------------------------
//
// FilemonDeviceRoutine
//
// In this routine we handle requests to our own device. The only
// requests we care about handling explicitely are IOCTL commands that
// we will get from the GUI. We also expect to get Create and Close
// commands when the GUI opens and closes communications with us.
//
//----------------------------------------------------------------------
NTSTATUS
FilemonDeviceRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irpStack;
PVOID inputBuffer;
PVOID outputBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
//
// Go ahead and set the request up as successful
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
//
// Get the pointer to the input/output buffer and its length
//
inputBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBuffer = Irp->AssociatedIrp.SystemBuffer;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
DbgPrint(("Filemon: IRP_MJ_CREATE/n"));
//
// Start the sequence number at 0
//
Sequence = 0;
break;
case IRP_MJ_CLOSE:
DbgPrint(("Filemon: IRP_MJ_CLOSE/n"));
//
// A GUI is closing communication
//
FilterOn = FALSE;
//
// If the GUI has no more references to us, reset the output
// buffers and hash table.
//
FilemonResetLog();
FilemonHashCleanup();
//
// Stop capturing drives
//
HookDriveSet( 0, DeviceObject->DriverObject );
UnhookSpecialFs( NPFS );
UnhookSpecialFs( MSFS );
break;
case IRP_MJ_DEVICE_CONTROL:
//
// This path will never execute because we have registered a
// fast I/O path for device control. That means that the fast I/O entry
// point will ALWAYS be called for Device Control operations
//
DbgPrint (("Filemon: IRP_MJ_DEVICE_CONTROL/n"));
//
// Get output buffer if its passed as an MDL
//
if( Irp->MdlAddress ) {
outputBuffer = MmGetSystemAddressForMdl( Irp->MdlAddress );
}
//
// Its a request from the GUI. Simply call our fast handler.
//
FilemonFastIoDeviceControl( irpStack->FileObject, TRUE,
inputBuffer, inputBufferLength,
outputBuffer, outputBufferLength,
ioControlCode, &amp;Irp->IoStatus, DeviceObject );
break;
}
//
// Complete the IRP
//
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_SUCCESS;

}

//----------------------------------------------------------------------
//
// FilemonDispatch
//
// Based on which device the Irp is destined for we call either the
// filesystem filter function, or our own device handling routine.
//
//----------------------------------------------------------------------
NTSTATUS
FilemonDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
//
// Determine if its a request from the GUI to us, or one that is
// directed at a file system driver that we've hooked
//
if( ((PHOOK_EXTENSION) DeviceObject->DeviceExtension)->Type == GUIINTERFACE ) {
return FilemonDeviceRoutine( DeviceObject, Irp );
} else
{
return FilemonHookRoutine( DeviceObject, Irp );
}
}

//----------------------------------------------------------------------
//
// FilemonUnload
//
// Our job isdo
ne - time to leave. Note that this function is
// only called when debugging is on, since in reality it is not safe
// to detach filter devices or unload a filter driver.
//
//----------------------------------------------------------------------
VOID
FilemonUnload(
IN PDRIVER_OBJECT DriverObject
)
{
WCHAR deviceLinkBuffer[] = L"//DosDevices//Filemon";
UNICODE_STRING deviceLinkUnicodeString;
//
// Delete the symbolic link for our GUI device
//
RtlInitUnicodeString( &amp;deviceLinkUnicodeString, deviceLinkBuffer );
IoDeleteSymbolicLink( &amp;deviceLinkUnicodeString );
DbgPrint(("Filemon.SYS: unloading/n"));
//
// The only device object left should be the GUI device, since
// we delete devices in our unload check.
//
IoDeleteDevice( DriverObject->DeviceObject );
DbgPrint(("Filemon.SYS: deleted devices/n"));
//
// Now we can free any memory that is allocated
//
FilemonFreeFilters();
FilemonHashCleanup();
FilemonFreeLog();
ExDeleteNPagedLookasideList( &amp;FullPathLookaside );
//
// Delete the resources
//
ExDeleteResourceLite( &amp;FilterResource );
ExDeleteResourceLite( &amp;HashResource );
DbgPrint(("Filemon.SYS: freed memory/n"));
}

//----------------------------------------------------------------------
//
// DriverEntry
//
// Installable driver initialization. Here we just set ourselves up.
// 驱动入口
//
//----------------------------------------------------------------------
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS ntStatus; // 返回的状态
PDEVICE_OBJECT guiDevice;
WCHAR deviceNameBuffer[] = L"//Device//Filemon";
UNICODE_STRING deviceNameUnicodeString;
WCHAR deviceLinkBuffer[] = L"//DosDevices//Filemon";
UNICODE_STRING deviceLinkUnicodeString;
ULONG i;
DbgPrint (("Filemon.SYS: entering DriverEntry/n"));

//
// 这个是最基础的对象
//
FilemonDriver = DriverObject;
//
// 设置驱动的名称
//
RtlInitUnicodeString (&amp;deviceNameUnicodeString,
deviceNameBuffer );
//
// Create the device used for GUI communications
//
ntStatus = IoCreateDevice ( DriverObject,
sizeof(HOOK_EXTENSION),
&amp;deviceNameUnicodeString,
FILE_DEVICE_FILEMON,
0,
TRUE,
&amp;guiDevice );
//
// If successful, make a symbolic link that allows for the device
// object's access from Win32 programs
//
if(NT_SUCCESS(ntStatus)) {
//
// Mark this as our GUI device
//
((PHOOK_EXTENSION) guiDevice->DeviceExtension)->Type = GUIINTERFACE;
//
// Create a symbolic link that the GUI can specify to gain access
// to this driver/device
//
RtlInitUnicodeString (&amp;deviceLinkUnicodeString,
deviceLinkBuffer );
ntStatus = IoCreateSymbolicLink (&amp;deviceLinkUnicodeString,
&amp;deviceNameUnicodeString );
if(!NT_SUCCESS(ntStatus)) {
DbgPrint (("Filemon.SYS: IoCreateSymbolicLink failed/n"));
IoDeleteDevice( guiDevice );
return ntStatus;

}
//
// Create dispatch points for all routines that must be handled.
// All entry points are registered since we might filter a
// file system that processes all of them.
//
for( i = 0;
i <= IRP_MJ_MAXIMUM_FUNCTION;
i++ ) {
DriverObject->MajorFunction = FilemonDispatch;
}
#if DBG
//
// Driver unload is only set if we are debugging Filemon. This is
// because unloading a filter is not really safe - threads could
// be in our fastio routines (or about to enter them), for example,
// and there is no way to tell. When debugging, we can risk the
// occasional unload crash as a trade-off for not having to
// reboot as often.
//
// DriverObject->DriverUnload = FilemonUnload;
#endif // DBG
//
// Set up the Fast I/O dispatch table
//
DriverObject->FastIoDispatch = &amp;FastIOHook;
} else
{
//
// If something went wrong, cleanup the device object anddo
n't load
//
DbgPrint(("Filemon: Failed to create our device!/n"));
return ntStatus;
}
//
// Initialize the name hash table
//
for(i = 0;
i < NUMHASH;
i++ ) HashTable = NULL;
//
// Find the process name offset
//
ProcessNameOffset = FilemonGetProcessNameOffset(); // 进程偏移量
//
// Initialize the synchronization objects
//
#if DBG
KeInitializeSpinLock( &amp;CountMutex );
#endif
ExInitializeFastMutex( &amp;LogMutex );
ExInitializeResourceLite( &amp;FilterResource );
ExInitializeResourceLite( &amp;HashResource );
//
// Initialize a lookaside for file names
//
ExInitializeNPagedLookasideList( &amp;FullPathLookaside, NULL, NULL,
0, MAXPATHLEN, 'mliF', 256 );
//
// Allocate the first output buffer
//
CurrentLog = ExAllocatePool( NonPagedPool, sizeof(*CurrentLog) );
// 申请输出缓冲区
if( !CurrentLog ) {
//
// Oops - we can'tdo
anything without at least one buffer
//
IoDeleteSymbolicLink( &amp;deviceLinkUnicodeString );
IoDeleteDevice( guiDevice );
return STATUS_INSUFFICIENT_RESOURCES;
// 资源不足错误
}
//
// Set the buffer pointer to the start of the buffer just allocated
//
CurrentLog->Len = 0;
CurrentLog->Next = NULL;
NumLog = 1;
return STATUS_SUCCESS;
}
 
这些是入门的资料,我都已经翻译成为汉语,因为版权属于公司,我不能在此公开。
如果Driver同志做过类似的东西,欢迎和我讨论。
这个开发包在国际上售价为799美金,呵呵。
马上微软的新的文件系统要出来,过期就要作废的了!
 
也算我一份吧
 
好东西,我也来学学习
 
about File monitor, there are a lots of free code that are written by c++,
I knew a delphi component called Alfa File Monitor, it is not free.
how mach are you going to sale?
 
我发现我又一次走近了巨人的肩膀,真历害! up一下,哈哈,又有分了.[:)][^]
 
晕了 晕了 这么长 还是给点分吧!
 
唉!原来 元元她哥这么厉害,原来的时候还以为只是和我们差不多的水平,现在明白了
差距怎么这么大呢????
 
收下再说[:D]
 
[:D]謝謝了!找個時間看一下,會不會,我看了不知會不會走火入MO。。[:D]
 
厉害,脑袋都看大了
 
UP
太好了 !
 
后退
顶部