FILEMON.C
资源名称:filesrc.zip [点击查看]
上传用户:hmgghm
上传日期:2007-01-07
资源大小:335k
文件大小:162k
源码类别:
文件操作
开发平台:
Visual C++
- //======================================================================
- //
- // Filemon.c
- //
- // Copyright (C) 1996-1998 Mark Russinovich and Bryce Cogswell
- //
- // Implements the equivalent of Windows 95 IFSMgr_FileSystemApiHook.
- //
- // Note: 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 "..guiioctlcmd.h"
- #include "filemon.h"
- #include "winioctl.h"
- //----------------------------------------------------------------------
- // DEFINES
- //----------------------------------------------------------------------
- //
- // Print macro that only turns on when debugging is on
- //
- #if DBG
- #define DbgPrint(arg) DbgPrint arg
- #else
- #define DbgPrint(arg)
- #endif
- //
- // The name of the System process, in which context we're called in our
- // DriverEntry
- //
- #define SYSNAME "System"
- //----------------------------------------------------------------------
- // TYPEDEFS
- //----------------------------------------------------------------------
- //
- // Directory control structure
- //
- typedef struct {
- ULONG Length;
- PUNICODE_STRING FileName;
- FILE_INFORMATION_CLASS FileInformationClass;
- ULONG FileIndex;
- } QUERY_DIRECTORY, *PQUERY_DIRECTORY;
- //
- // Lock control data structure
- //
- typedef struct {
- PLARGE_INTEGER Length;
- ULONG Key;
- LARGE_INTEGER ByteOffset;
- } LOCK_CONTROL, *PLOCK_CONTROL;
- //
- // File name information
- //
- typedef struct _FILE_NAME_INFORMATION {
- ULONG FileNameLength;
- WCHAR FileName[1];
- } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
- //----------------------------------------------------------------------
- // FORWARD DEFINES
- //----------------------------------------------------------------------
- //
- // 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 );
- //----------------------------------------------------------------------
- // GLOBALS
- //----------------------------------------------------------------------
- //
- // This is Filemon's user-inteface device object. It is addressed
- // by calls from the GUI including CreateFile and DeviceIoControl
- //
- PDEVICE_OBJECT GUIDevice;
- //
- // 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
- //
- //
- // Array of process and path filters
- //
- ULONG NumIncludeFilters = 0;
- PCHAR IncludeFilters[MAXFILTERS];
- ULONG NumExcludeFilters = 0;
- PCHAR ExcludeFilters[MAXFILTERS];
- //
- // Which type of timing are we doing (told to us by GUI)
- //
- BOOLEAN TimeIsDuration;
- //
- // 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.
- //
- ULONG OutstandingIRPCount = 0;
- 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 LDriveDevices[26];
- //
- // This table keeps track of which drives are controlled by common
- // network redirectors (unhooking one results in all of the group
- // being unhooked). Each device object that is hooked is assigned
- // a unique identifier. Network devices are used to represent
- // multiple logical drives, so the drive map entries for network
- // drive handled by the same network device object have the
- // same identifier.
- //
- int LDriveMap[26];
- int LDriveGroup = 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
- //
- PSTORE_BUF Store = 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 StoreMutex;
- //
- // 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 NumStore = 0;
- ULONG MaxStore = 1000000/MAX_STORE;
- //
- // Free hash list. Note: we don't use lookaside lists since
- // we want to be able to run on NT 3.51 - lookasides were
- // introduced in NT 4.0
- //
- PHASH_ENTRY FreeHashList = NULL;
- //
- // 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",
- };
- //
- // 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 upcase;
- //
- // End of pattern?
- //
- if( !*Pattern ) {
- return FALSE;
- }
- //
- // If we hit a wild card, do recursion
- //
- if( *Pattern == '*' ) {
- Pattern++;
- while( *Name && *Pattern ) {
- if( *Name >= 'a' && *Name <= 'z' )
- upcase = *Name - 'a' + 'A';
- else
- upcase = *Name;
- //
- // See if this substring matches
- //
- if( *Pattern == upcase || *Name == '*' ) {
- 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 != '*' ) {
- if( *Name >= 'a' && *Name <= 'z' )
- upcase = *Name - 'a' + 'A';
- else
- upcase = *Name;
- if( *Pattern == upcase ) {
- 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
- //----------------------------------------------------------------------
- //----------------------------------------------------------------------
- //
- // FilemonFreeStore
- //
- // Frees all the data output buffers that we have currently allocated.
- //
- //----------------------------------------------------------------------
- VOID FilemonFreeStore()
- {
- PSTORE_BUF prev;
- //
- // Just traverse the list of allocated output buffers
- //
- while( Store ) {
- prev = Store->Next;
- ExFreePool( Store );
- Store = prev;
- }
- }
- //----------------------------------------------------------------------
- //
- // FilemonNewStore
- //
- // 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 FilemonNewStore( void )
- {
- PSTORE_BUF prev = Store, newstore;
- //
- // 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( MaxStore == NumStore ) {
- Store->Len = 0;
- return;
- }
- //
- // If the output buffer we currently are using is empty, just
- // use it.
- //
- if( !Store->Len )
- return;
- //
- // Allocate a new output buffer
- //
- newstore = ExAllocatePool( NonPagedPool, sizeof(*Store) );
- if( newstore ) {
- //
- // Allocation was successful so add the buffer to the list
- // of allocated buffers and increment the buffer count.
- //
- Store = newstore;
- Store->Len = 0;
- Store->Next = prev;
- NumStore++;
- } else {
- //
- // The allocation failed - just reuse the current buffer
- //
- Store->Len = 0;
- }
- }
- //----------------------------------------------------------------------
- //
- // FilemonOldestStore
- //
- // 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).
- //
- //----------------------------------------------------------------------
- PSTORE_BUF FilemonOldestStore( void )
- {
- PSTORE_BUF ptr = Store, prev = NULL;
- //
- // Traverse the list
- //
- while ( ptr->Next ) {
- ptr = (prev = ptr)->Next;
- }
- //
- // Remove the buffer from the list
- //
- if ( prev ) {
- prev->Next = NULL;
- NumStore--;
- }
- return ptr;
- }
- //----------------------------------------------------------------------
- //
- // FilemonResetStore
- //
- // 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 FilemonResetStore()
- {
- PSTORE_BUF current, next;
- ExAcquireFastMutex( &StoreMutex );
- //
- // Traverse the list of output buffers
- //
- current = Store->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.
- //
- NumStore = 1;
- Store->Len = 0;
- Store->Next = NULL;
- ExReleaseFastMutex( &StoreMutex );
- }
- //----------------------------------------------------------------------
- //
- // MyInterlockedIncrement
- //
- // On 3.51 InterlockedIncrement doesn't return the udpates value(!).
- //
- //----------------------------------------------------------------------
- __inline ULONG MyInterlockedIncrement( PULONG Number )
- {
- if( *NtBuildNumber < NT4FINAL ) {
- //
- // Just use the count spin lock
- //
- return ExInterlockedAddUlong( Number, 1, &CountMutex );
- } else {
- return InterlockedIncrement( Number );
- }
- }
- //----------------------------------------------------------------------
- //
- // UpdateStore
- //
- // This "printfs" a string into an output buffer.
- //
- //----------------------------------------------------------------------
- void UpdateStore( ULONG seq, PLARGE_INTEGER time, const CHAR * format, ... )
- {
- PENTRY Entry;
- int len;
- va_list arg_ptr;
- static CHAR text[MAXPATHLEN];
- //
- // If no GUI is there to receive the output or if no filtering is desired, don't bother
- //
- if( !FilterOn ) {
- return;
- }
- //
- // Lock the output buffer and Store.
- //
- ExAcquireFastMutex( &StoreMutex );
- //
- // 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; // +1 to include null terminator and +3 to allign on 32 bit
- //
- // If the current output buffer is near capacity, move to a new
- // output buffer
- //
- if ( Store->Len + len + sizeof(ENTRY) +1 >= MAX_STORE ) {
- FilemonNewStore();
- }
- //
- // Extract the sequence number and store it
- //
- Entry = (void *)(Store->Data+Store->Len);
- Entry->seq = seq;
- Entry->time = *time;
- memcpy( Entry->text, text, len );
- //
- // Store the length of the string, plus 1 for the terminating
- // NULL
- //
- Store->Len += (Entry->text - (PCHAR) Entry ) + len;
- //
- // Release the output buffer lock
- //
- ExReleaseFastMutex( &StoreMutex );
- }
- //----------------------------------------------------------------------
- // 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()
- {
- PHASH_ENTRY hashEntry, nextEntry;
- ULONG i;
- ExAcquireResourceExclusiveLite( &HashResource, TRUE );
- //
- // First, free the hash table entries
- //
- for( i = 0; i < NUMHASH; i++ ) {
- hashEntry = HashTable[i];
- while( hashEntry ) {
- nextEntry = hashEntry->Next;
- ExFreePool( hashEntry->FullPathName );
- ExFreePool( hashEntry );
- hashEntry = nextEntry;
- }
- HashTable[i] = NULL;
- }
- hashEntry = FreeHashList;
- while( hashEntry ) {
- nextEntry = hashEntry->Next;
- ExFreePool( hashEntry );
- hashEntry = nextEntry;
- }
- FreeHashList = NULL;
- ExReleaseResourceLite( &HashResource );
- }
- //----------------------------------------------------------------------
- //
- // 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;
- 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 );
- return;
- }
- //
- // Got it! Remove it from the list
- //
- if( prevEntry ) {
- prevEntry->Next = hashEntry->Next;
- } else {
- HashTable[ HASHOBJECT( fileObject )] = hashEntry->Next;
- }
- //
- // Free the memory associated with the name of the free entry.
- //
- ExFreePool( hashEntry->FullPathName );
- hashEntry->Next = FreeHashList;
- FreeHashList = hashEntry;
- ExReleaseResourceLite( &HashResource );
- }
- //----------------------------------------------------------------------
- // 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()
- {
- 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;
- //
- // Scan through the process filters
- //
- filterStart = FilterString;
- while( *filterStart ) {
- filterLength = 0;
- while( filterStart[filterLength] &&
- filterStart[filterLength] != ';' ) {
- filterLength++;
- }
- //
- // Ignore zero-length components
- //
- if( filterLength ) {
- FilterArray[ *NumFilters ] =
- ExAllocatePool( NonPagedPool, filterLength + 1 );
- strncpy( FilterArray[ *NumFilters ],
- filterStart, filterLength );
- FilterArray[ *NumFilters ][filterLength] = 0;
- (*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()
- {
- //
- // Free old filters (if any)
- //
- ExAcquireResourceExclusiveLite( &FilterResource, TRUE );
- FilemonFreeFilters();
- //
- // Create new filter arrays
- //
- MakeFilterArray( FilterDef.includefilter,
- IncludeFilters, &NumIncludeFilters );
- MakeFilterArray( FilterDef.excludefilter,
- ExcludeFilters, &NumExcludeFilters );
- ExReleaseResourceLite( &FilterResource );
- }
- //----------------------------------------------------------------------
- //
- // ApplyNameFilter
- //
- // 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.
- //
- //----------------------------------------------------------------------
- FILTERSTATUS ApplyNameFilter( PCHAR fullname )
- {
- ULONG i;
- //
- // If no GUI or no filename return FALSE
- //
- if ( !fullname ) return FILTERFAIL;
- //
- // If it matches the exclusion string, do not log it
- //
- ExAcquireResourceSharedLite( &FilterResource, TRUE );
- for( i = 0; i < NumExcludeFilters; i++ ) {
- if( MatchWithPattern( ExcludeFilters[i], fullname ) ) {
- ExReleaseResourceLite( &FilterResource );
- return FILTERFAIL;
- }
- }
- //
- // If it matches an include filter then log it
- //
- for( i = 0; i < NumIncludeFilters; i++ ) {
- if( MatchWithPattern( IncludeFilters[i], fullname )) {
- ExReleaseResourceLite( &FilterResource );
- return FILTERPASS;
- }
- }
- //
- // It didn't match any include filters so don't log
- //
- ExReleaseResourceLite( &FilterResource );
- return FILTERNOMATCH;
- }
- //----------------------------------------------------------------------
- //
- // FilemonQueryFileNameComplete
- //
- // This routine is used to handle I/O completion for our self-generated
- // IRP that is used to query a file's name.
- //
- //----------------------------------------------------------------------
- NTSTATUS FilemonQueryFileNameComplete(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: %xn", 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;
- }
- //----------------------------------------------------------------------
- //
- // FilemonQueryFileName
- //
- // This function retrieves the "standard" information for the
- // underlying file system, asking for the filename in particular.
- //
- //----------------------------------------------------------------------
- BOOLEAN FilemonQueryFileName( PDEVICE_OBJECT DeviceObject,
- PFILE_OBJECT FileObject,
- PFILE_NAME_INFORMATION FileName, ULONG FileNameLength )
- {
- PIRP irp;
- KEVENT event;
- IO_STATUS_BLOCK IoStatusBlock;
- PIO_STACK_LOCATION ioStackLocation;
- DbgPrint(("Getting file name for %xn", 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 = FileName;
- 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 = FileNameLength;
- ioStackLocation->Parameters.QueryFile.FileInformationClass = FileNameInformation;
- //
- // Set the completion routine.
- //
- IoSetCompletionRoutine(irp, FilemonQueryFileNameComplete, 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!
- //
- 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;
- PFILE_OBJECT relatedFileObject;
- PHASH_ENTRY hashEntry, newEntry;
- ANSI_STRING componentName;
- PFILE_NAME_INFORMATION fileNameInfo;
- UNICODE_STRING fullUniName;
- //
- // Only do this if a GUI is active and filtering is on
- //
- if( !FilterOn || !hookExt || !fullPathName) {
- fullPathName[0] = 0;
- return;
- }
- //
- // First, lookup the object in the hash table to see if a name
- // has already been generated for it
- //
- 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 );
- return;
- }
- ExReleaseResourceLite( &HashResource );
- //
- // We didn't find the name in the hash table, so we have to attempt
- // to construct it from the file objects. Note that we won't always
- // be able to successfully do this, because the file system may
- // deallocate the name in the file object at its discretion.
- //
- //
- // Is it DASD (Volume) I/O?
- //
- if( !fileObject || !fileObject->FileName.Length || fileObject->FileName.Length > 2*MAXPATHLEN ) {
- if( hookExt->Type == NPFS ) strcpy( fullPathName, NAMED_PIPE_PREFIX );
- else if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );
- else sprintf( fullPathName, "%C: DASD", hookExt->LogicalDrive );
- return;
- }
- //
- // 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->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
- prefixLen = 0;
- } else {
- prefixLen = 2; // "C:"
- }
- break;
- }
- //
- // Okay, now we have to construct the name. If we're in the Create path,
- // we can use the file objects. Otherwise we'll just query the file's name
- //
- if( createPath ) {
- //
- // Clear out any existing name association
- //
- FilemonFreeHashEntry( fileObject );
- //
- // Create the full path name. First, calculate the length taking into
- // account space for seperators and the leading drive letter plus ':'
- //
- pathLen = fileObject->FileName.Length/2 + prefixLen;
- relatedFileObject = fileObject->RelatedFileObject;
- //
- // Only look at related file object if this is a relative name
- //
- if( fileObject->FileName.Buffer[0] != L'\' ) {
- while( relatedFileObject ) {
- //
- // If its too long, just stop.
- //
- if( pathLen + relatedFileObject->FileName.Length/2+1 >= MAXPATHLEN ) {
- break;
- }
- pathLen += relatedFileObject->FileName.Length/2+1;
- relatedFileObject = relatedFileObject->RelatedFileObject;
- }
- }
- //
- // 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 );
- }
- //
- // Now, start at the end and work back to the beginning of the path
- //
- fullPathName[ pathLen ] = 0;
- pathOffset = fullPathName + pathLen - fileObject->FileName.Length/2;
- RtlUnicodeStringToAnsiString( &componentName, &fileObject->FileName, TRUE );
- strncpy( pathOffset, componentName.Buffer, componentName.Length + 1 );
- RtlFreeAnsiString( &componentName );
- relatedFileObject = fileObject->RelatedFileObject;
- if( fileObject->FileName.Buffer[0] != L'\' ) {
- while( relatedFileObject ) {
- *(pathOffset - 1) = '\';
- pathOffset -= relatedFileObject->FileName.Length/2 + 1;
- //
- // Bail when we've maxed the string.
- //
- if( pathOffset <= fullPathName ) {
- break;
- }
- RtlUnicodeStringToAnsiString( &componentName,
- &relatedFileObject->FileName, TRUE );
- strncpy( pathOffset, componentName.Buffer,
- componentName.Length );
- RtlFreeAnsiString( &componentName );
- relatedFileObject = relatedFileObject->RelatedFileObject;
- }
- }
- //
- // If we added two '' to the front because there was a relative file object
- // that specified the root directory, remove one
- //
- if( pathLen > 3 && fullPathName[2] == '\' && fullPathName[3] == '\' ) {
- strcpy( fullPathName + 2, fullPathName + 3 );
- }
- } else {
- //
- // 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.
- //
- fileNameInfo = (PFILE_NAME_INFORMATION) ExAllocatePool( NonPagedPool, MAXPATHLEN*2 );
- if( fileNameInfo &&
- FilemonQueryFileName(hookExt->FileSystem, fileObject, fileNameInfo,
- (MAXPATHLEN-3)*2 + 4 )) {
- fullUniName.Length = (SHORT) fileNameInfo->FileNameLength;
- fullUniName.Buffer = fileNameInfo->FileName;
- RtlUnicodeStringToAnsiString( &componentName, &fullUniName, TRUE );
- fullPathName[ componentName.Length + prefixLen ] = 0;
- if( hookExt->Type == NPFS ) {
- strcpy( fullPathName, NAMED_PIPE_PREFIX );
- memcpy( &fullPathName[NAMED_PIPE_PREFIX_LENGTH], componentName.Buffer, componentName.Length );
- } else if( hookExt->Type == MSFS ) {
- strcpy( fullPathName, MAIL_SLOT_PREFIX );
- memcpy( &fullPathName[MAIL_SLOT_PREFIX_LENGTH], componentName.Buffer, componentName.Length );
- } else if( fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
- memcpy( fullPathName, componentName.Buffer, componentName.Length );
- } else {
- sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
- memcpy( &fullPathName[2], componentName.Buffer, componentName.Length );
- }
- RtlFreeAnsiString( &componentName );
- } else {
- 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 );
- }
- }
- ExFreePool( fileNameInfo );
- pathLen = strlen( fullPathName );
- }
- //
- // Network redirector names already specify a share name, that we have to strip
- //
- // X:computersharerealpath
- //
- // And we want to present:
- //
- // X:realpath
- //
- // to the user.
- //
- if( fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
- //
- // Skip the share name
- //
- if( fullPathName[2] == ':' ) {
- strcpy( fullPathName, &fullPathName[1] );
- slashes = 0;
- ptr = &fullPathName[3];
- while( *ptr && slashes != 2 ) {
- if( *ptr == '\' ) slashes++;
- ptr++;
- }
- strcpy( &fullPathName[3], ptr );
- } else {
- //
- // Its a UNC path
- //
- }
- }
- //
- // Now that we have a name associated with the file object, put the
- // association in a hash table
- //
- ExAcquireResourceExclusiveLite( &HashResource, TRUE );
- //
- // Allocate a hash entry
- //
- if( FreeHashList ) {
- newEntry = FreeHashList;
- FreeHashList = newEntry->Next;
- } else {
- newEntry = ExAllocatePool( NonPagedPool, sizeof(HASH_ENTRY ));
- }
- //
- // If no memory for a new entry, oh well.
- //
- if( newEntry ) {
- //
- // Fill in the new entry and put it in the hash table
- //
- newEntry->FileObject = fileObject;
- newEntry->FullPathName = ExAllocatePool( NonPagedPool, strlen(fullPathName)+1);
- //
- // Make sure there was memory for the name
- //
- if( !newEntry->FullPathName ) {
- newEntry->Next = FreeHashList;
- FreeHashList = newEntry;
- } else {
- strcpy( newEntry->FullPathName, fullPathName );
- newEntry->Next = HashTable[ HASHOBJECT(fileObject) ];
- HashTable[ HASHOBJECT(fileObject) ] = newEntry;
- }
- }
- ExReleaseResourceLite( &HashResource );
- }
- //----------------------------------------------------------------------
- //
- // 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()
- {
- 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.
- //
- //----------------------------------------------------------------------
- FILTERSTATUS FilemonGetProcess( PCHAR Name )
- {
- 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
- //
- nameptr = (PCHAR) curproc + ProcessNameOffset;
- strncpy( Name, nameptr, NT_PROCNAMELEN );
- //
- // Terminate in case process name overflowed
- //
- Name[NT_PROCNAMELEN] = 0;
- } else {
- strcpy( Name, "???" );
- }
- //
- // Apply process name filters
- //
- ExAcquireResourceSharedLite( &FilterResource, TRUE );
- for( i = 0; i < NumExcludeFilters; i++ ) {
- if( MatchWithPattern( ExcludeFilters[i], Name )) {
- ExReleaseResourceLite( &FilterResource );
- return FILTERFAIL;
- }
- }
- for( i = 0; i < NumIncludeFilters; i++ ) {
- if( MatchWithPattern( IncludeFilters[i], Name ) ) {
- ExReleaseResourceLite( &FilterResource );
- return FILTERPASS;
- }
- }
- ExReleaseResourceLite( &FilterResource );
- return FILTERNOMATCH;
- }
- //----------------------------------------------------------------------
- //
- // ApplyFilters
- //
- // Gets the process name and then performs filtering logic.
- //
- //----------------------------------------------------------------------
- BOOLEAN ApplyFilters( PCHAR ProcessName, PCHAR FullName )
- {
- FILTERSTATUS filterStatus, nameFilterStatus;
- //
- // If there's no name, bail
- //
- if( !ProcessName || !FullName ) return FALSE;
- //
- // Try the process filter
- //
- filterStatus = FilemonGetProcess( ProcessName );
- if( filterStatus == FILTERPASS ||
- filterStatus == FILTERNOMATCH ) {
- //
- // Try the path filter
- //
- nameFilterStatus = ApplyNameFilter( FullName );
- if( (filterStatus == FILTERPASS && nameFilterStatus != FILTERFAIL) ||
- nameFilterStatus == FILTERPASS ) {
- return TRUE;
- }
- }
- return FALSE;
- }
- //----------------------------------------------------------------------
- // H O O K / U N H O O K R O U T I N E S
- //----------------------------------------------------------------------
- //----------------------------------------------------------------------
- //
- // 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 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 %sn", FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));
- return FALSE;
- }
- DbgPrint(("Filemon: opened the root directory!!! handle: %xn", 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: %xn",
- 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: %xn",
- 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: %xn",
- 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;
- //
- // Setup the device extensions. The drive letter and file system object are stored
- // in the extension.
- //
- hookExtension = hookDevice->DeviceExtension;
- hookExtension->LogicalDrive = '\';
- hookExtension->FileSystem = fileSysDevice;
- hookExtension->Type = FsType;
- //
- // 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: %s (%x) =>%xn",
- 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 %sn",
- FsType == NPFS ? "NPFS" : "MSFS" ));
- }
- //
- // 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;
- IoDetachDevice( hookExt->FileSystem );
- IoDeleteDevice( NamedPipeHookDevice );
- NamedPipeHookDevice = NULL;
- } else if( FsType == MSFS && MailSlotHookDevice ) {
- hookExt = MailSlotHookDevice->DeviceExtension;
- IoDetachDevice( hookExt->FileSystem );
- IoDeleteDevice( MailSlotHookDevice );
- 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 char Drive, IN PDRIVER_OBJECT DriverObject )
- {
- IO_STATUS_BLOCK ioStatus;
- HANDLE ntFileHandle;
- OBJECT_ATTRIBUTES objectAttributes;
- PDEVICE_OBJECT fileSysDevice;
- PDEVICE_OBJECT hookDevice;
- UNICODE_STRING fileNameUnicodeString;
- WCHAR filename[] = L"\DosDevices\A:\";
- NTSTATUS ntStatus;
- ULONG i;
- PFILE_OBJECT fileObject;
- PHOOK_EXTENSION hookExtension;
- //
- // Translate the drive letter to a 0-based integer
- //
- if ( Drive >= 'a' && Drive <= 'z' ) {
- Drive -= 'a';
- } else {
- Drive -= 'A';
- }
- //
- // Is it a legal drive letter?
- //
- if ( (unsigned char) Drive >= 26 ) {
- return FALSE;
- }
- //
- // Has this drive already been hooked?
- //
- if ( LDriveDevices[Drive] == NULL ) {
- //
- // Frob the name to make it refer to the drive specified in the input
- // parameter.
- //
- filename[12] = '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: %xn", 'A'+Drive, ntStatus ));
- return FALSE;
- }
- DbgPrint(("Filemon: opened the root directory!!! handle: %xn", 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: %cn", '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: %cn", '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( LDriveDevices[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 );
- LDriveMap[ Drive ] = LDriveMap[i];
- LDriveDevices[ 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: %cn", '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->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) =>%xn",
- '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 %cn", 'A'+Drive ));
- if( !LDriveMap[ Drive ] ) {
- LDriveMap[ Drive ] = ++LDriveGroup;
- }
- }
- //
- // Close the file and update the hooked drive list by entering a
- // pointer to the hook device object in it.
- //
- ObDereferenceObject( fileObject );
- ZwClose( ntFileHandle );
- LDriveDevices[Drive] = hookDevice;
- }
- return TRUE;
- }
- //----------------------------------------------------------------------
- //
- // UnhookDrive
- //
- // Unhook a previously hooked drive.
- //
- //----------------------------------------------------------------------
- BOOLEAN UnhookDrive( IN char Drive )
- {
- PHOOK_EXTENSION hookExt;
- //
- // Translate the drive letter to a 0-based integer
- //
- if ( Drive >= 'a' && Drive <= 'z' ) {
- Drive -= 'a';
- } else {
- Drive -= 'A';
- }
- //
- // If the drive has been hooked, unhook it and delete the hook
- // device object
- //
- if ( LDriveDevices[Drive] ) {
- hookExt = LDriveDevices[Drive]->DeviceExtension;
- IoDetachDevice( hookExt->FileSystem );
- IoDeleteDevice( LDriveDevices[Drive] );
- LDriveDevices[Drive] = NULL;
- }
- return TRUE;
- }
- //----------------------------------------------------------------------
- //
- // 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 )
- {
- 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 suppoed to hook this drive?
- //
- if ( bit & DriveSet ) {
- //
- // Try to hook drive
- //
- if ( ! HookDrive( (char)('A'+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( LDriveMap[i] == LDriveMap[ drive ] &&
- !LDriveDevices[i] ) {
- DriveSet |= ( 1<<i );
- LDriveDevices[i] = LDriveDevices[drive];
- }
- }
- }
- } else {
- //
- // Try to unhook drive
- //
- if ( ! UnhookDrive( (char)('A'+drive) ) ) {
- //
- // Unhook failed, leave the drive marked as hooked
- //
- DriveSet |= bit;
- } else {
- //
- // Unhook worked. Mark all drives in same group as
- // unhooked
- //
- for( i = 0; i< 26; i++ ) {
- if( LDriveMap[i] == LDriveMap[ drive ] &&
- LDriveDevices[i] ) {
- DriveSet &= ~(1 << i);
- LDriveDevices[i] = NULL;
- }
- }
- }
- }
- }
- //
- // Return set of drives currently hooked
- //
- 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;
- 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_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: