FileMon.c

http://blog.csdn.net/xiongwjw/article/category/1081656
//====================================================================== 
// 
// 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[] = ""; 
 
// 
// 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 && *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 && *Pattern ) 
        { 
 
            matchchar = *Name; 
            if( matchchar >= 'a' && 
                    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 && *Pattern != '*' ) 
    { 
 
        matchchar = *Name; 
        if( matchchar >= 'a' && 
                matchchar <= 'z' ) 
        { 
 
            matchchar -= 'a' - 'A'; 
        } 
 
        if( *Pattern == matchchar ) 
        { 
            Pattern++; 
            Name++; 
 
        } 
        else 
        { 
 
            return FALSE; 
        } 
    } 
 
    // 
    // If not done, 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( &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( &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, don't bother 
    // 
    if( !FilterOn ) 
    { 
 
        return FALSE; 
    } 
 
    // 
    // Lock the output buffer and Log. 
    // 
    ExAcquireFastMutex( &LogMutex ); 
 
    // 
    // Send text out as debug output  This is x86 specific. 
    // 
#define A (&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 &=  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 && *SeqNum == (ULONG) - 1)) 
        { 
 
            recordSequence = InterlockedIncrement( &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( &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( &HashResource, TRUE ); 
 
    // 
    // Free the hash table entries 
    // 
    for( i = 0; i < NUMHASH; i++ ) 
    { 
 
        hashEntry = HashTable[i]; 
 
        while( hashEntry ) 
        { 
            nextEntry = hashEntry->Next; 
            ExFreePool( hashEntry ); 
            hashEntry = nextEntry; 
        } 
 
        HashTable[i] = NULL; 
    } 
    ExReleaseResourceLite( &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( &HashResource, TRUE ); 
 
    // 
    // Look-up the entry 
    // 
    hashEntry = HashTable[ HASHOBJECT( fileObject ) ]; 
    prevEntry = NULL; 
 
    while( hashEntry && 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( &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( &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[i] ); 
    } 
    for( i = 0; i < NumExcludeFilters; i++ ) 
    { 
 
        ExFreePool( ExcludeFilters[i] ); 
    } 
    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] && 
                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 we done? 
        // 
        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( &FilterResource, TRUE ); 
    FilemonFreeFilters(); 
 
    // 
    // Create new filter arrays 
    // 
    MakeFilterArray( FilterDef.includefilter, 
                     IncludeFilters, &NumIncludeFilters ); 
    MakeFilterArray( FilterDef.excludefilter, 
                     ExcludeFilters, &NumExcludeFilters ); 
    ExReleaseResourceLite( &FilterResource ); 
    KeLeaveCriticalRegion(); 
} 
 
 
//---------------------------------------------------------------------- 
// 
// ApplyFilters 
// 
// If the name matches the exclusion mask, we do not log it. Else if 
// it doesn't match the inclusion mask we do 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( &FilterResource, TRUE ); 
 
    for( i = 0; i < NumExcludeFilters; i++ ) 
    { 
 
        if( MatchWithPattern( ExcludeFilters[i], Text ) ) 
        { 
 
            ExReleaseResourceLite( &FilterResource ); 
            KeLeaveCriticalRegion(); 
            return FALSE; 
        } 
    } 
 
    // 
    // If it matches an include filter then log it 
    // 
    for( i = 0; i < NumIncludeFilters; i++ ) 
    { 
 
        if( MatchWithPattern( IncludeFilters[i], Text )) 
        { 
 
            ExReleaseResourceLite( &FilterResource ); 
            KeLeaveCriticalRegion(); 
            return TRUE; 
        } 
    } 
 
    // 
    // It didn't match any include filters so don't log 
    // 
    ExReleaseResourceLite( &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 code doing this. 
    // 
    KeSetEvent(Irp->UserEvent, 0, FALSE); 
 
    // 
    // Free the IRP now that we are done with it. 
    // 
    IoFreeIrp(Irp); 
 
    // 
    // We return STATUS_MORE_PROCESSING_REQUIRED because this "magic" return value 
    // tells the I/O Manager that additional processing will be done by this driver 
    // to the IRP - in fact, it might (as it is in this case) already BE done - 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(&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 = &event; 
    irp->UserIosb = &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); 
 
    // 
    // Send it to the FSD 
    // 
    (void) IoCallDriver(DeviceObject, irp); 
 
    // 
    // Wait for the I/O 
    // 
    KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0); 
 
    // 
    // Done! 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; 
 
    // 
    // Only do 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( &HashResource, TRUE ); 
 
    hashEntry = HashTable[ HASHOBJECT( fileObject ) ]; 
    while( hashEntry && 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( &HashResource ); 
        KeLeaveCriticalRegion(); 
        return; 
    } 
 
    ExReleaseResourceLite( &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 && hookExt->FsAttributes && 
            !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, 
                                   &fileInternalInfo, sizeof( fileInternalInfo ))) 
        { 
 
            // 
            // Use the name in the metadata name index 
            // 
            mftIndex = fileInternalInfo.IndexNumber.QuadPart & ~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 && !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, we don'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 && 
                FilemonQueryFile(hookExt->FileSystem, fileObject, FileNameInformation, 
                                 fileNameInfo, (MAXPATHLEN - prefixLen - 1)*sizeof(WCHAR) )) 
        { 
 
            fullUniName.Length = (SHORT) fileNameInfo->FileNameLength; 
            fullUniName.Buffer = fileNameInfo->FileName; 
            if( NT_SUCCESS( RtlUnicodeStringToAnsiString( &fileName, &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( &fullPathName[prefixLen], fileName.Buffer, fileName.Length ); 
                gotPath = TRUE; 
                RtlFreeAnsiString( &fileName ); 
                fileName.Buffer = NULL; 
            } 
        } 
        if( fileNameInfo ) ExFreePool( fileNameInfo ); 
    } 
 
    // 
    // If we don'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( &fileName, &fileObject->FileName, TRUE ))) 
        { 
 
            if( hookExt->Type == NPFS )      sprintf( fullPathName, "%s: ", NAMED_PIPE_PREFIX ); 
            else if( hookExt->Type == MSFS ) sprintf( fullPathName, "%s: ", MAIL_SLOT_PREFIX ); 
            else                             sprintf( fullPathName, "%C: ", 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'\\' && 
                relatedFileObject && relatedFileObject->FileName.Length ) 
        { 
 
            if( !NT_SUCCESS( RtlUnicodeStringToAnsiString( &relatedName, &relatedFileObject->FileName, TRUE ))) 
            { 
 
                if( hookExt->Type == NPFS )      sprintf( fullPathName, "%s: ", NAMED_PIPE_PREFIX ); 
                else if( hookExt->Type == MSFS ) sprintf( fullPathName, "%s: ", MAIL_SLOT_PREFIX ); 
                else                             sprintf( fullPathName, "%C: ", hookExt->LogicalDrive ); 
                RtlFreeAnsiString( &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, " " ); 
 
        } 
        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'\\' && 
                    relatedFileObject && 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 && fullPathName[2] == '\\' && fullPathName[3] == '\\' ) 
                { 
 
                    strcpy( fullPathName + 2, fullPathName + 3 ); 
                } 
            } 
        } 
    } 
    if( fileName.Buffer ) RtlFreeAnsiString( &fileName ); 
    if( relatedName.Buffer ) RtlFreeAnsiString( &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 && 
            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 we don't want to make assumptions 
            // about the length of the number). 
            // 
            slashes = 0; 
            ptr = &fullPathName[3]; 
            while( *ptr && slashes != 3 ) 
            { 
 
                if( *ptr == '\\' ) slashes++; 
                ptr++; 
            } 
            strcpy( &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 = &fullPathName[3]; 
            while( *ptr && slashes != 3 ) 
            { 
 
                if( *ptr == '\\' ) slashes++; 
                ptr++; 
            } 
            strcpy( &fullPathName[3], ptr ); 
 
        } 
        else 
        { 
 
            // 
            // Its a UNC path, so add a leading slash 
            // 
            RtlMoveMemory( &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( &HashResource, TRUE ); 
 
        newEntry->Next = HashTable[ HASHOBJECT(fileObject) ]; 
        HashTable[ HASHOBJECT(fileObject) ] = newEntry; 
 
        ExReleaseResourceLite( &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 only do 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[i] == device ) 
                { 
 
                    DriveHookDevices[i] = 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 && NamedPipeHookDevice ) return TRUE; 
    if( FsType == MSFS && MailSlotHookDevice ) return TRUE; 
 
    // 
    // We have to figure out what device to hook - first open the volume's 
    // root directory 
    // 
    if( FsType == NPFS ) RtlInitUnicodeString( &fileNameUnicodeString, npfsFilename ); 
    else                 RtlInitUnicodeString( &fileNameUnicodeString, msfsFilename ); 
    InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString, 
                                OBJ_CASE_INSENSITIVE, NULL, NULL ); 
    ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE | FILE_ANY_ACCESS, 
                             &objectAttributes, &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, &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, 
                               &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 &= ~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 && NamedPipeHookDevice ) 
    { 
 
        hookExt = NamedPipeHookDevice->DeviceExtension; 
        hookExt->Hooked = FALSE; 
        NamedPipeHookDevice = NULL; 
 
    } 
    else if( FsType == MSFS && 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( &fileNameUnicodeString, filename ); 
        InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString, 
                                    OBJ_CASE_INSENSITIVE, NULL, NULL ); 
        ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE | FILE_ANY_ACCESS, 
                                 &objectAttributes, &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, &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[i] == 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, 
                                   &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 &= ~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 it does 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 && 
                !NT_SUCCESS( IoQueryVolumeInformation( fileObject, FileFsAttributeInformation, 
                             fileFsAttributesSize, hookExtension->FsAttributes, 
                             &fileFsAttributesSize ))) 
        { 
 
            // 
            // On failure, we just don'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 & DriveSet) && 
                !(bit & CurrentDriveSet) ) 
        { 
 
            // 
            // Try to hook drive 
            // 
            if( !HookDrive( drive, DriverObject ) ) 
            { 
 
                // 
                // Remove from drive set if can't be hooked 
                // 
                DriveSet &= ~bit; 
 
            } 
            else 
            { 
 
                // 
                // hook drives in same drive group 
                // 
                for( i = 0; i < 26; i++ ) 
                { 
 
                    if( DriveHookDevices[i] == DriveHookDevices[ drive ] ) 
                    { 
 
                        DriveSet |= ( 1 << i ); 
                    } 
                } 
            } 
 
        } 
        else if( !(bit & DriveSet) && 
                 (bit & CurrentDriveSet) ) 
        { 
 
            // 
            // Unhook this drive and all in the group 
            // 
            for( i = 0; i < 26; i++ ) 
            { 
 
                if( DriveHookDevices[i] == DriveHookDevices[ drive ] ) 
                { 
 
                    UnhookDrive( i ); 
                    DriveSet &= ~(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) & 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 & FILE_DIRECTORY_FILE ) 
        strcat( Buffer, "Directory " ); 
    if( Options & FILE_WRITE_THROUGH ) 
        strcat( Buffer, "WriteThrough " ); 
    if( Options & FILE_SEQUENTIAL_ONLY ) 
        strcat( Buffer, "Sequential " ); 
    if( Options & FILE_NO_INTERMEDIATE_BUFFERING ) 
        strcat( Buffer, "NoBuffer" ); 
    if( Options & 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 & FILE_ATTRIBUTE_COMPRESSED) strcat( Buffer, "C" ); 
    if( Attributes & FILE_ATTRIBUTE_TEMPORARY) strcat( Buffer, "T" ); 
    if( Attributes & FILE_ATTRIBUTE_DIRECTORY) strcat( Buffer, "D" ); 
    if( Attributes & FILE_ATTRIBUTE_READONLY) strcat( Buffer, "R" ); 
    if( Attributes & FILE_ATTRIBUTE_HIDDEN )  strcat( Buffer, "H" ); 
    if( Attributes & FILE_ATTRIBUTE_SYSTEM )  strcat( Buffer, "S" ); 
    if( Attributes & FILE_ATTRIBUTE_ARCHIVE ) strcat( Buffer, "A" ); 
    if( Attributes & 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 (it doesn'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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            if( retval ) 
            { 
                LogRecord( TRUE, NULL, 
                           &dateTime, &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, 
                           &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            if( retval ) 
            { 
                LogRecord( TRUE, NULL, 
                           &dateTime, &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, 
                           &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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; 
} 
 
 
//---------------------------------------------------------------------- 
// 
// 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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked ) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 parameters down 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 && hookExt->Hooked) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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 && hookExt->Hooked) 
        { 
 
            TIMESTAMPSTOP(); 
            LogRecord( TRUE, NULL, 
                       &dateTime, &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) && 
                    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( &CountMutex, &oldirql ); 
            IoStatus->Information = OutstandingIRPCount; 
 
            // 
            // Any outstanding Irps? 
            // 
            if( !OutstandingIRPCount ) 
            { 
 
                // 
                // Nope, so don't process anymore 
                // 
                UnloadInProgress = TRUE; 
 
                KeReleaseSpinLock( &CountMutex, oldirql ); 
 
                // 
                // Stop capturing drives 
                // 
                HookDriveSet( 0, DeviceObject->DriverObject ); 
                UnhookSpecialFs( NPFS ); 
                UnhookSpecialFs( MSFS ); 
 
                // 
                // Detach from all devices 
                // 
                UnloadDetach(); 
 
            } 
            else 
            { 
 
                KeReleaseSpinLock( &CountMutex, oldirql ); 
            } 
#else // DBG 
            IoStatus->Information = 1; 
#endif // DBG 
            break; 
 
        case IOCTL_FILEMON_ZEROSTATS: 
 
            // 
            // Reset all output buffers 
            // 
            DbgPrint (("Filemon: zero stats\n")); 
 
            ExAcquireFastMutex( &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( &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( &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( &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( &LogMutex ); 
                } 
 
            } 
            else 
            { 
 
                // 
                // There is no unread data 
                // 
                ExReleaseFastMutex( &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, &dateTime, &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 && hookExt->Hooked) 
                { 
 
                    TIMESTAMPSTOP(); 
                    LogRecord( TRUE, NULL, &dateTime, &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 && hookExt->Hooked) 
                { 
 
                    TIMESTAMPSTOP(); 
                    LogRecord( TRUE, NULL, &dateTime, &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[i] ) 
        { 
 
            // 
            // 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, &dateTime, &timeResult, 
                           "%s\tFASTIO_DETACH_DEVICE\t%s\t\tOK", 
                           FilemonGetProcess( name ), drive ); 
            } 
            IoDetachDevice( TargetDevice ); 
            IoDeleteDevice( SourceDevice ); 
 
            DriveHookDevices[i] = 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 to do 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, &filemonWork->Sequence, 
               NULL, 
               &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( &filemonWorkContext->WorkItem, 
                                      FilemonHookDoneWork, filemonWorkContext ); 
                ExQueueWorkItem( &filemonWorkContext->WorkItem, CriticalWorkQueue ); 
            } 
        } 
        else 
        { 
 
            sprintf( errString, "\t\t\t\t%s", ErrorString( Irp->IoStatus.Status, errval )); 
            LogRecord( FALSE, &seqNum, NULL, &timeResult, errString ); 
        } 
    } 
 
#if DBG 
    // 
    // We have finished processing an IRP so decrement oustanding IRP count 
    // 
    KeAcquireSpinLock( &CountMutex, &oldirql ); 
    OutstandingIRPCount--; 
    DbgPrint(("-%d: %x\n", OutstandingIRPCount, Irp ));; 
    if( !OutstandingIRPCount ) FilemonDriver->DriverUnload = FilemonUnload; 
    KeReleaseSpinLock( &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 
    // we don'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 && 
             FileObject->Flags & 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 && hookExt->Hooked ) 
    { 
 
        GETPATHNAME( createPath ); 
    } 
 
    // 
    // Only log it if it passes the filter 
    // 
    if( hookExt->Hooked && fullPathName ) 
    { 
 
        // 
        // If measuring absolute time go and get the timestamp. 
        // 
        KeQuerySystemTime( &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, &seqNum, &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 & FILE_OPEN_BY_FILE_ID ) 
            { 
 
                FilemonFreeHashEntry( FileObject ); 
            } 
            break; 
 
        case IRP_MJ_CREATE_NAMED_PIPE: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &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, &seqNum, &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, &seqNum, &dateTime, NULL, 
                                            "%s\tIRP_MJ_READ%c\t%s\tOffset: %d Length: %d", 
                                            name, 
                                            (Irp->Flags & IRP_PAGING_IO) || 
                                            (Irp->Flags & 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, &seqNum, &dateTime, NULL, 
                                            "%s\tIRP_MJ_WRITE%c\t%s\tOffset: %d Length: %d", 
                                            name, 
                                            (Irp->Flags & IRP_PAGING_IO) || 
                                            (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ', 
                                            fullPathName, 
                                            currentIrpStack->Parameters.Write.ByteOffset.LowPart, 
                                            currentIrpStack->Parameters.Write.Length ); 
            } 
            break; 
 
        case IRP_MJ_CLOSE: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_CLOSE%c\t%s\t", 
                                        name, 
                                        (Irp->Flags & IRP_PAGING_IO) || 
                                        (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ', 
                                        fullPathName ); 
 
            // 
            // This fileobject/name association can be discarded now. 
            // 
            FilemonFreeHashEntry( FileObject ); 
            break; 
 
        case IRP_MJ_FLUSH_BUFFERS: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_FLUSH\t%s\t", name, fullPathName ); 
            break; 
 
        case IRP_MJ_QUERY_INFORMATION: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &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, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_SET_INFORMATION%c\t%s\t%s", 
                                        name, 
                                        (Irp->Flags & IRP_PAGING_IO) || 
                                        (Irp->Flags & 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, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_QUERY_EA\t%s\t", name, fullPathName ); 
            break; 
 
        case IRP_MJ_SET_EA: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_SET_EA\t%s\t", name, fullPathName ); 
            break; 
 
        case IRP_MJ_QUERY_VOLUME_INFORMATION: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &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, &seqNum, &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, &seqNum, &dateTime, NULL, 
                                            "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\tChange Notify", 
                                            name, fullPathName ); 
                break; 
            case IRP_MN_QUERY_DIRECTORY: 
                queryDirectory = (PQUERY_DIRECTORY)¤tIrpStack->Parameters; 
                queryFilter = NULL; 
                if( queryDirectory->FileName ) 
                { 
 
                    if( NT_SUCCESS( RtlUnicodeStringToAnsiString( &directoryFilter, 
                                    queryDirectory->FileName, TRUE ))) 
                    { 
 
                        queryFilter = ExAllocatePool( PagedPool, directoryFilter.Length + 1 ); 
                        if( queryFilter ) 
                        { 
 
                            memcpy( queryFilter, directoryFilter.Buffer, directoryFilter.Length ); 
                            queryFilter[ directoryFilter.Length ] = 0; 
 
                            // 
                            // Massage DOS-internal wildcards 
                            // 
                            for( i = 0; i < strlen( queryFilter ); i++ ) 
                            { 
                                if( queryFilter[i] == '<' ) queryFilter[i] = '*'; 
                                else if( queryFilter[i] == '>' ) queryFilter[i] = '?'; 
                            } 
                        } 
                        RtlFreeAnsiString( &directoryFilter ); 
                    } 
                } 
                if( queryFilter ) 
                { 
 
                    hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                                "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\t%s: %s", 
                                                name, fullPathName, 
                                                FileInformation[queryDirectory->FileInformationClass], 
                                                queryFilter ); 
                    ExFreePool( queryFilter ); 
 
                } 
                else 
                { 
 
                    hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                                "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\t%s", 
                                                name, fullPathName, 
                                                FileInformation[queryDirectory->FileInformationClass] ); 
                } 
                break; 
            default: 
                hookCompletion = LogRecord( TRUE, &seqNum, &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, &FileObject, NULL ); 
                FilemonGetFullPath( FALSE, FileObject, hookExt, fullPathName ); 
                ObDereferenceObject( FileObject ); 
                hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                            "%s\tFSCTL_MOVE_FILE\t%s\t%s", 
                                            name, fullPathName, optionString ); 
                break; 
            default: 
                hookCompletion = LogRecord( TRUE, &seqNum, &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, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_SHUTDOWN\t\t", name ); 
            break; 
 
        case IRP_MJ_LOCK_CONTROL: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_LOCK_CONTROL\t%s\tOffset: %d Length: %d", 
                                        name, fullPathName, 
                                        ((PLOCK_CONTROL)¤tIrpStack->Parameters)->ByteOffset.LowPart, 
                                        ((PLOCK_CONTROL)¤tIrpStack->Parameters)->Length ? 
                                        ((PLOCK_CONTROL)¤tIrpStack->Parameters)->Length->LowPart : 0 ); 
            break; 
 
        case IRP_MJ_CLEANUP: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_CLEANUP\t%s\t", name, fullPathName ); 
            break; 
 
        case IRP_MJ_DEVICE_CONTROL: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &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, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_QUERY_SECURITY\t%s\t", 
                                        name, fullPathName ); 
            break; 
 
        case IRP_MJ_SET_SECURITY: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_SET_SECURITY\t%s\t", 
                                        name, fullPathName ); 
            break; 
 
        case IRP_MJ_POWER: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL, 
                                        "%s\tIRP_MJ_POWER\t%s\tMinor: %x", 
                                        name, fullPathName, 
                                        currentIrpStack->MinorFunction ); 
            break; 
 
        case IRP_MJ_PNP: 
 
            hookCompletion = LogRecord( TRUE, &seqNum, &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, &seqNum, &dateTime, NULL, 
                                        "%s\t*UNKNOWN* 0x%X\t\t", name, currentIrpStack->MajorFunction ); 
            break; 
        } 
 
    } 
    else 
    { 
 
        // 
        // We don'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 && fullPathName != InsufficientResources ) 
    { 
 
        ExFreeToNPagedLookasideList( &FullPathLookaside, fullPathName ); 
    } 
 
    // 
    // Copy parameters down 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( &CountMutex, &oldirql ); 
#endif 
 
    if( !UnloadInProgress && 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're done 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( &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, &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 is done - 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( &deviceLinkUnicodeString, deviceLinkBuffer ); 
    IoDeleteSymbolicLink( &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( &FullPathLookaside ); 
 
    // 
    // Delete the resources 
    // 
    ExDeleteResourceLite( &FilterResource ); 
    ExDeleteResourceLite( &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; 
 
    // 
    // Setup the device name 
    // 
    RtlInitUnicodeString (&deviceNameUnicodeString, 
                          deviceNameBuffer ); 
 
    // 
    // Create the device used for GUI communications 
    // 
    ntStatus = IoCreateDevice ( DriverObject, 
                                sizeof(HOOK_EXTENSION), 
                                &deviceNameUnicodeString, 
                                FILE_DEVICE_FILEMON, 
                                0, 
                                TRUE, 
                                &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 (&deviceLinkUnicodeString, 
                              deviceLinkBuffer ); 
        ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString, 
                                         &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[i] = 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 = &FastIOHook; 
 
    } 
    else 
    { 
 
        // 
        // If something went wrong, cleanup the device object and don't load 
        // 
        DbgPrint(("Filemon: Failed to create our device!\n")); 
        return ntStatus; 
    } 
 
    // 
    // Initialize the name hash table 
    // 
    for(i = 0; i < NUMHASH; i++ ) HashTable[i] = NULL; 
 
    // 
    // Find the process name offset 
    // 
    ProcessNameOffset = FilemonGetProcessNameOffset(); 
 
    // 
    // Initialize the synchronization objects 
    // 
#if DBG 
    KeInitializeSpinLock( &CountMutex ); 
#endif 
    ExInitializeFastMutex( &LogMutex ); 
    ExInitializeResourceLite( &FilterResource ); 
    ExInitializeResourceLite( &HashResource ); 
 
    // 
    // Initialize a lookaside for file names 
    // 
    ExInitializeNPagedLookasideList( &FullPathLookaside, NULL, NULL, 
                                     0, MAXPATHLEN, 'mliF', 256 ); 
 
    // 
    // Allocate the first output buffer 
    // 
    CurrentLog = ExAllocatePool( NonPagedPool, sizeof(*CurrentLog) ); 
    if( !CurrentLog ) 
    { 
 
        // 
        // Oops - we can't do anything without at least one buffer 
        // 
        IoDeleteSymbolicLink( &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; 
} 



你可能感兴趣的:(C,windows)