写驱动啊,我给你一个显成的代码吧!<br>// 司马华鹏<br>//======================================================================<br>//<br>// FILEMON.c - main module for VxD FILEMON<br>//<br>// Copyright (C) 1996-2000 Mark Russinovich and Bryce Cogswell<br>//<br>//======================================================================<br>#define DEVICE_MAIN<br>#include <vtoolsc.h><br>#include "../exe/ioctlcmd.h"<br>#include "filemon.h"<br>#undef DEVICE_MAIN<br><br>//----------------------------------------------------------------------<br>// G L O B A L D A T A <br>//----------------------------------------------------------------------<br><br>//<br>// Indicates if the GUI wants activity to be logged<br>//<br>BOOLEAN FilterOn = FALSE;<br><br>//<br>// Global filter (sent to us by the GUI)<br>//<br>FILTER FilterDef;<br><br>//<br>// Array of process and path filters <br>//<br>ULONG NumIncludeFilters = 0;<br>PCHAR IncludeFilters[MAXFILTERS];<br>ULONG NumExcludeFilters = 0;<br>PCHAR ExcludeFilters[MAXFILTERS];<br><br>//<br>// Real service pointers with the hook thunks<br>//<br>ppIFSFileHookFunc PrevIFSHookProc;<br><br>//<br>// Hash table data <br>//<br>PHASH_ENTRY HashTable[NUMHASH];<br><br>//<br>// Buffer data<br>//<br>PLOG_BUF Log = NULL;<br>ULONG Sequence = 0;<br><br>//<br>// Maximum amount of buffers we will grab for buffered unread data<br>//<br>ULONG NumLog = 0;<br>ULONG MaxLog = 5;<br><br>//<br>// Semaphore for critical sections<br>//<br>SEMHANDLE LogMutex, HashMutex, FilterMutex;<br><br>//<br>// Unknown error string<br>//<br>CHAR errstring[32];<br><br>//----------------------------------------------------------------------<br>// F O R W A R D S<br>//----------------------------------------------------------------------<br><br>BOOLEAN<br>ApplyFilters(<br> PCHAR Text<br> );<br><br>//----------------------------------------------------------------------<br>// V X D C O N T R O L<br>//----------------------------------------------------------------------<br><br>//<br>// Device declaration<br>//<br>Declare_Virtual_Device(FILEMON)<br><br>//<br>// Message handlers - we only care about dynamic loading and unloading<br>//<br>DefineControlHandler(SYS_DYNAMIC_DEVICE_INIT, OnSysDynamicDeviceInit);<br>DefineControlHandler(SYS_DYNAMIC_DEVICE_EXIT, OnSysDynamicDeviceExit);<br>DefineControlHandler(W32_DEVICEIOCONTROL, OnW32Deviceiocontrol);<br><br><br>//----------------------------------------------------------------------<br>// <br>// ControlDispatcher<br>//<br>// Multiplexes incoming VxD messages from Windows to their handlers.<br>//<br>//----------------------------------------------------------------------<br>BOOL <br>__cdecl ControlDispatcher(<br> DWORD dwControlMessage,<br> DWORD EBX,<br> DWORD EDX,<br> DWORD ESI,<br> DWORD EDI,<br> DWORD ECX<br> )<br>{<br> START_CONTROL_DISPATCH<br><br> ON_W32_DEVICEIOCONTROL(OnW32Deviceiocontrol);<br> ON_SYS_DYNAMIC_DEVICE_INIT(OnSysDynamicDeviceInit);<br> ON_SYS_DYNAMIC_DEVICE_EXIT(OnSysDynamicDeviceExit);<br><br> END_CONTROL_DISPATCH<br><br> return TRUE;<br>}<br><br>//----------------------------------------------------------------------<br>// P A T T E R N M A T C H I N G R O U T I N E S<br>//----------------------------------------------------------------------<br><br><br>//----------------------------------------------------------------------<br>//<br>// MatchOkay<br>//<br>// Only thing left after compare is more mask. This routine makes<br>// sure that its a valid wild card ending so that its really a match.<br>//<br>//----------------------------------------------------------------------<br>BOOLEAN <br>MatchOkay( <br> PCHAR Pattern <br> )<br>{<br> //<br> // If pattern isn't empty, it must be a wildcard<br> //<br> if( *Pattern && *Pattern != '*' ) {<br> <br> return FALSE;<br> }<br><br> //<br> // Matched<br> //<br> return TRUE;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// MatchWithPattern<br>//<br>// Performs nifty wildcard comparison.<br>//<br>//----------------------------------------------------------------------<br>BOOLEAN <br>MatchWithPattern( <br> PCHAR Pattern, <br> PCHAR Name <br> )<br>{<br> CHAR upcase;<br><br> //<br> // End of pattern?<br> //<br> if( !*Pattern ) {<br><br> return FALSE;<br> }<br><br> //<br> // If we hit a wild card, do recursion<br> //<br> if( *Pattern == '*' ) {<br><br> Pattern++;<br><br> while( *Name && *Pattern ) {<br><br> if( *Name >= 'a' && *Name <= 'z' )<br> upcase = *Name - 'a' + 'A';<br> else<br> upcase = *Name;<br><br> //<br> // See if this substring matches<br> //<br> if( *Pattern == upcase || *Name == '*' ) {<br><br> if( MatchWithPattern( Pattern+1, Name+1 )) {<br><br> return TRUE;<br> }<br> }<br><br> //<br> // Try the next substring<br> //<br> Name++;<br> }<br><br> //<br> // See if match condition was met<br> //<br> return MatchOkay( Pattern );<br> } <br><br> //<br> // Do straight compare until we hit a wild card<br> //<br> while( *Name && *Pattern != '*' ) {<br><br> if( *Name >= 'a' && *Name <= 'z' )<br> upcase = *Name - 'a' + 'A';<br> else<br> upcase = *Name;<br><br> if( *Pattern == upcase ) {<br><br> Pattern++;<br> Name++;<br><br> } else {<br><br> return FALSE;<br> }<br> }<br><br> //<br> // If not done, recurse<br> //<br> if( *Name ) {<br><br> return MatchWithPattern( Pattern, Name );<br> }<br><br> //<br> // Make sure its a match<br> //<br> return MatchOkay( Pattern );<br>}<br><br>//----------------------------------------------------------------------<br>// B U F F E R M A N A G E M E N T<br>//----------------------------------------------------------------------<br><br>//----------------------------------------------------------------------<br>//<br>// FilemonFreeLog<br>//<br>// Frees all the data output buffers that we have currently allocated.<br>//<br>//----------------------------------------------------------------------<br>VOID <br>FilemonFreeLog(<br> VOID <br> )<br>{<br> PLOG_BUF prev;<br> <br> //<br> // Just traverse the list of allocated output buffers<br> //<br> while( Log ) {<br><br> prev = Log->Next;<br> PageFree( Log->Handle, 0 );<br> Log = prev;<br> }<br>} <br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonNewLog<br>//<br>// Called when the current buffer has filled up. This moves us to the<br>// pre-allocated buffer and then allocates another buffer.<br>//<br>// Returns FALSE if another thread is already allocating a buffer.<br>//<br>//----------------------------------------------------------------------<br>BOOLEAN <br>FilemonNewLog( VOID <br> )<br>{<br> PLOG_BUF prev = Log, newLog;<br> static busyAllocating = FALSE;<br> MEMHANDLE hNewLog;<br><br> //<br> // If we have maxed out or haven't accessed the current Log<br> // just return.<br> //<br> if( MaxLog == NumLog ) {<br><br> Log->Len = 0;<br> return TRUE; <br> }<br><br> //<br> // If the output buffer we currently are using is empty, just<br> // use it, or if we are busy already allocating a buffer, return<br> //<br> if( !Log->Len || busyAllocating ) {<br><br> return !busyAllocating;<br> }<br><br> //<br> // Allocate a new output buffer. Release lock to prevent deadlock<br> // on reentrance (allocating memory can result in file I/O)<br> //<br> busyAllocating = TRUE;<br> dprintf("Pageallocate: num:%d/n", NumLog );<br> Signal_Semaphore( LogMutex );<br><br> PageAllocate(LOGBUFPAGES, PG_SYS, 0, 0, 0, 0, NULL, PAGELOCKED, <br> (PMEMHANDLE) &hNewLog, (PVOID) &newLog );<br><br> Wait_Semaphore( LogMutex, BLOCK_SVC_INTS );<br> dprintf("Pageallocate done: num:%d/n", NumLog );<br> busyAllocating = FALSE;<br><br> if( newLog ) { <br><br> //<br> // Allocation was successful so add the buffer to the list<br> // of allocated buffers and increment the buffer count.<br> //<br> Log = newLog;<br> Log->Handle = hNewLog;<br> Log->Len = 0;<br> Log->Next = prev;<br> NumLog++;<br><br> } else {<br><br> //<br> // The allocation failed - just reuse the current buffer<br> //<br> Log->Len = 0;<br> }<br> return TRUE;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonOldestLog<br>//<br>// Goes through the linked list of storage buffers and returns the <br>// oldest one.<br>//<br>//----------------------------------------------------------------------<br>PLOG_BUF <br>FilemonOldestLog( <br> VOID<br> )<br>{<br> PLOG_BUF ptr = Log, prev = NULL;<br><br> //<br> // Traverse the list<br> // <br> while ( ptr->Next ) {<br><br> ptr = (prev = ptr)->Next;<br> }<br><br> //<br> // Remove the buffer from the list<br> //<br> if ( prev ) {<br><br> prev->Next = NULL; <br> }<br> NumLog--;<br> return ptr;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonResetLog<br>//<br>// When a GUI is no longer communicating with us, but we can't unload,<br>// we reset the storage buffers.<br>//<br>//----------------------------------------------------------------------<br>VOID <br>FilemonResetLog(<br> VOID<br> )<br>{<br> PLOG_BUF current, next;<br><br> //<br> // Traverse the list of output buffers<br> //<br> current = Log->Next;<br> while( current ) {<br><br> //<br> // Free the buffer<br> //<br> next = current->Next;<br> PageFree( current->Handle, 0 );<br> current = next;<br> }<br><br> // <br> // Move the output pointer in the buffer that's being kept<br> // the start of the buffer.<br> // <br> Log->Len = 0;<br> Log->Next = NULL;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// LogRecord<br>//<br>// Add a new string to Log, if it fits.<br>//<br>//----------------------------------------------------------------------<br>VOID <br>LogRecord( <br> ULONG time, <br> ULONG datetimelo,<br> ULONG datetimehi,<br> const char *format, <br> ... <br> )<br>{ <br> PENTRY Entry;<br> ULONG len;<br> va_list arg_ptr;<br> static CHAR text[MAXPATHLEN*3];<br><br> //<br> // If no filtering is desired, don't bother<br> //<br> if( !FilterOn ) {<br> <br> return;<br> }<br><br> //<br> // Lock the output buffer.<br> //<br> Wait_Semaphore( LogMutex, BLOCK_SVC_INTS );<br><br> //<br> // Vsprintf to determine length of the buffer<br> //<br> _asm cld;<br> va_start( arg_ptr, format );<br> len = vsprintf( text, format, arg_ptr );<br> va_end( arg_ptr );<br><br> //<br> // Only log it if the text passes the filters<br> //<br> if( ApplyFilters( text )) {<br><br> //<br> // If the current output buffer is near capacity, move to a new<br> // output buffer<br> //<br> if( (ULONG) (Log->Len + len + sizeof(ENTRY) +1) >= LOGBUFSIZE ) {<br><br> if( !FilemonNewLog() ) {<br> <br> //<br> // Just return if a thread is in the process<br> // of allocating a buffer.<br> //<br> Signal_Semaphore( LogMutex );<br> return;<br> }<br> } <br><br> //<br> // Extract the sequence number and Log it<br> //<br> Entry = (void *)(Log->Data+Log->Len);<br> Entry->seq = Sequence++;<br> Entry->perftime.u.LowPart = time;<br> Entry->perftime.u.HighPart = 0;<br> Entry->datetime.u.HighPart = datetimehi;<br> Entry->datetime.u.LowPart = datetimelo;<br> _asm cld;<br> memcpy( Entry->text, text, len + 1 );<br> <br> //<br> // Log the length of the string, plus 1 for the terminating<br> // NULL <br> // <br> Log->Len += (Entry->text - (PCHAR) Entry) + len + 1;<br> }<br> <br> //<br> // Release the output buffer lock<br> //<br> Signal_Semaphore( LogMutex );<br>}<br><br>//----------------------------------------------------------------------<br>// H A S H T A B L E M A N A G E M E N T<br>//----------------------------------------------------------------------<br><br>//----------------------------------------------------------------------<br>//<br>// FilemonHashCleanup<br>//<br>// Called when we are unloading to free any memory that we have <br>// in our possession.<br>//<br>//----------------------------------------------------------------------<br>VOID <br>FilemonHashCleanup(<br> VOID<br> )<br>{<br> PHASH_ENTRY hashEntry, nextEntry;<br> ULONG i;<br> <br> //<br> // Free the hash table entries<br> //<br> for( i = 0; i < NUMHASH; i++ ) {<br><br> hashEntry = HashTable;<br> while( hashEntry ) {<br> nextEntry = hashEntry->Next;<br> HeapFree( hashEntry, 0 );<br> hashEntry = nextEntry;<br> }<br> }<br>}<br><br>//----------------------------------------------------------------------<br>//<br>// FilemonLogHash<br>//<br>// Logs the key and associated fullpath in the hash table.<br>//<br>//----------------------------------------------------------------------<br>VOID<br>FilemonLogHash( <br> int Drive, <br> fh_t Filenumber, <br> PCHAR Fullname <br> )<br>{<br> PHASH_ENTRY newEntry;<br><br> //<br> // Allocate a new entry<br> //<br> newEntry = HeapAllocate( sizeof(HASH_ENTRY) + strlen(Fullname)+1, 0 );<br> if( !newEntry ) return;<br><br> //<br> // Initialize the new entry.<br> //<br> newEntry->filenumber = Filenumber;<br> newEntry->drive = Drive & 0xFF;<br> strcpy( newEntry->FullName, Fullname );<br><br> //<br> // Lock the hash table and insert the new entry.<br> //<br> Wait_Semaphore( HashMutex, BLOCK_SVC_INTS );<br> newEntry->Next = HashTable[ HASHOBJECT(Filenumber) ];<br> HashTable[ HASHOBJECT(Filenumber) ] = newEntry; <br> Signal_Semaphore( HashMutex );<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonFreeHashEntry<br>//<br>// When we see a file close, we can free the string we had associated<br>// with the fileobject being closed since we know it won't be used<br>// again.<br>//<br>//----------------------------------------------------------------------<br>VOID <br>FilemonFreeHashEntry( <br> int Drive, <br> fh_t Filenumber <br> )<br>{<br> PHASH_ENTRY hashEntry, prevEntry;<br><br> Wait_Semaphore( HashMutex, BLOCK_SVC_INTS );<br><br> //<br> // Look-up the entry.<br> //<br> hashEntry = HashTable[ HASHOBJECT( Filenumber ) ];<br> prevEntry = NULL;<br><br> while( hashEntry && <br> hashEntry->filenumber != Filenumber && <br> hashEntry->drive != (Drive & 0xFF)) {<br><br> prevEntry = hashEntry;<br> hashEntry = hashEntry->Next;<br> }<br><br> // <br> // If we fall of the hash list without finding what we're looking<br> // for, just return.<br> //<br> if( !hashEntry ) {<br><br> Signal_Semaphore( HashMutex );<br> return;<br> }<br><br> //<br> // Got it! Remove it from the list<br> //<br> if( prevEntry ) {<br><br> prevEntry->Next = hashEntry->Next;<br> } else {<br><br> HashTable[ HASHOBJECT( Filenumber )] = hashEntry->Next;<br> }<br><br> //<br> // Free the memory associated with the name of the free entry.<br> //<br> HeapFree( hashEntry, 0 );<br> Signal_Semaphore( HashMutex );<br>}<br><br>//----------------------------------------------------------------------<br>// F I L T E R A N D P R O C E S S N A M E R O U T I N E S<br>//----------------------------------------------------------------------<br><br>//----------------------------------------------------------------------<br>//<br>// ErrorString<br>//<br>// Returns the string form of an error code.<br>//<br>//----------------------------------------------------------------------<br>PCHAR <br>ErrorString( <br> DWORD retval <br> )<br>{<br> switch( retval ) {<br> case ERROR_INVALID_FUNCTION:<br> return "INVALIDFUNC"; <br> case ERROR_SUCCESS:<br> return "SUCCESS";<br> case ERROR_OUTOFMEMORY:<br> return "OUTOFMEM";<br> case ERROR_ACCESS_DENIED:<br> return "ACCDENIED";<br> case ERROR_PATH_NOT_FOUND:<br> return "NOTFOUND";<br> case ERROR_TOO_MANY_OPEN_FILES:<br> return "TOOMANYOPEN";<br> case ERROR_FILE_NOT_FOUND:<br> return "NOTFOUND";<br> case ERROR_NO_MORE_ITEMS:<br> return "NOMORE";<br> case ERROR_GEN_FAILURE:<br> return "GENFAILURE";<br> case ERROR_MORE_DATA:<br> return "MOREDATA";<br> case ERROR_INVALID_DRIVE:<br> return "INVALIDDRIVE";<br> case ERROR_NOT_SAME_DEVICE:<br> return "DIFFERENTDEVICE";<br> case ERROR_WRITE_PROTECT:<br> return "WRITEPROTECTED";<br> case ERROR_SHARING_VIOLATION:<br> return "SHARING";<br> case ERROR_BAD_UNIT:<br> return "BADUNIT";<br> case ERROR_NOT_READY:<br> return "NOTREADY";<br> case ERROR_NO_MORE_FILES:<br> return "NOMORE";<br> case ERROR_BAD_COMMAND:<br> return "BADCOMMAND";<br> case ERROR_INVALID_HANDLE:<br> return "INVALIDHANDLE";<br> case ERROR_DEV_NOT_EXIST:<br> return "DEVDOESNOTEXIST";<br> default:<br> sprintf(errstring, "0x%x", retval );<br> return errstring;<br> }<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonFreeFilters<br>//<br>// Fress storage we allocated for filter strings.<br>//<br>//----------------------------------------------------------------------<br>VOID <br>FilemonFreeFilters(<br> VOID<br> )<br>{<br> ULONG i;<br><br> for( i = 0; i < NumIncludeFilters; i++ ) {<br><br> HeapFree( IncludeFilters, 0 );<br> }<br> for( i = 0; i < NumExcludeFilters; i++ ) {<br><br> HeapFree( ExcludeFilters, 0 );<br> }<br> NumIncludeFilters = 0;<br> NumExcludeFilters = 0;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// MakeFilterArray<br>//<br>// Takes a filter string and splits into components (a component<br>// is seperated with a ';')<br>//<br>//----------------------------------------------------------------------<br>VOID <br>MakeFilterArray( <br> PCHAR FilterString,<br> PCHAR FilterArray[],<br> PULONG NumFilters <br> )<br>{<br> PCHAR filterStart;<br> ULONG filterLength;<br> CHAR saveChar;<br><br> //<br> // Scan through the process filters<br> //<br> filterStart = FilterString;<br> while( *filterStart ) {<br><br> filterLength = 0;<br> while( filterStart[filterLength] &&<br> filterStart[filterLength] != ';' ) {<br><br> filterLength++;<br> }<br><br> //<br> // Ignore zero-length components<br> //<br> if( filterLength ) {<br><br> //<br> // Conservatively allocate so that we can prepend and append<br> // wildcards<br> //<br> FilterArray[ *NumFilters ] = <br> HeapAllocate( filterLength + 1 + 2* sizeof('*'), 0 );<br><br> if( FilterArray[ *NumFilters ]) {<br><br> saveChar = *(filterStart + filterLength );<br> *(filterStart + filterLength) = 0;<br> sprintf( FilterArray[ *NumFilters ], "%s%s%s",<br> *filterStart == '*' ? "" : "*",<br> filterStart,<br> *(filterStart + filterLength - 1 ) == '*' ? "" : "*" );<br> *(filterStart + filterLength) = saveChar;<br> (*NumFilters)++;<br> }<br> }<br> <br> //<br> // Are we done?<br> //<br> if( !filterStart[filterLength] ) break;<br><br> //<br> // Move to the next component (skip over ';')<br> //<br> filterStart += filterLength + 1;<br> }<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonUpdateFilters<br>//<br>// Takes a new filter specification and updates the filter<br>// arrays with them.<br>//<br>//----------------------------------------------------------------------<br>VOID <br>FilemonUpdateFilters(<br> VOID<br> )<br>{<br> //<br> // Free old filters (if any)<br> //<br> Wait_Semaphore( FilterMutex, BLOCK_SVC_INTS );<br> FilemonFreeFilters();<br><br> //<br> // Create new filter arrays<br> //<br> MakeFilterArray( FilterDef.includefilter,<br> IncludeFilters, &NumIncludeFilters );<br> MakeFilterArray( FilterDef.excludefilter,<br> ExcludeFilters, &NumExcludeFilters );<br> Signal_Semaphore( FilterMutex );<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// wstrlen<br>//<br>// Determine the length of a wide-character string.<br>//<br>//----------------------------------------------------------------------<br>int <br>wstrlen( <br> unsigned short *unistring <br> )<br>{<br> int i = 0;<br> int len = 0;<br> <br> while( unistring[i++] != 0 ) len+=2;<br> return len;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilmonGetProcess<br>//<br>// Retrieves the process name.<br>//<br>//----------------------------------------------------------------------<br>PCHAR<br>FilemonGetProcess( <br> PCHAR ProcessName <br> )<br>{<br> PVOID CurProc;<br> PVOID ring3proc;<br> char *name;<br> ULONG i;<br><br> //<br> // Get the ring0 process pointer.<br> //<br> CurProc = VWIN32_GetCurrentProcessHandle();<br> <br> //<br> // Now, map the ring3 PCB <br> //<br> ring3proc = (PVOID) SelectorMapFlat( Get_Sys_VM_Handle(), <br> (DWORD) (*(PDWORD) ((char *) CurProc + 0x38)) | 0x7, 0 );<br><br> if( ring3proc == (PVOID) -1 ) {<br> strcpy( ProcessName, "???");<br> } else {<br><br> //<br> // copy out the process name (max 8 characters)<br> //<br> name = ((char *)ring3proc) + 0xF2;<br> if( name[0] >= 'A' && name[0] < 'z' ) {<br><br> strcpy( ProcessName, name );<br> ProcessName[8] = 0;<br> } else {<br><br> strcpy( ProcessName, "???" );<br> }<br> }<br> return ProcessName;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// ApplyFilters<br>//<br>// If the name matches the exclusion mask, we do not log it. Else if<br>// it doesn't match the inclusion mask we do not log it. <br>//<br>//----------------------------------------------------------------------<br>BOOLEAN<br>ApplyFilters( <br> PCHAR Text<br> )<br>{<br> ULONG i;<br><br> // <br> // If it matches the exclusion string, do not log it<br> //<br> Wait_Semaphore( FilterMutex, BLOCK_SVC_INTS );<br> for( i = 0; i < NumExcludeFilters; i++ ) {<br><br> if( MatchWithPattern( ExcludeFilters, Text ) ) {<br><br> Signal_Semaphore( FilterMutex );<br> return FALSE;<br> }<br> }<br> <br> //<br> // If it matches an include filter then log it<br> //<br> for( i = 0; i < NumIncludeFilters; i++ ) {<br><br> if( MatchWithPattern( IncludeFilters, Text )) {<br><br> Signal_Semaphore( FilterMutex );<br> return TRUE;<br> }<br> }<br><br> //<br> // It didn't match any include filters so don't log<br> //<br> Signal_Semaphore( FilterMutex );<br> return FALSE;<br>}<br><br>//----------------------------------------------------------------------<br>// P A T H P A R S I N G<br>//----------------------------------------------------------------------<br><br>//----------------------------------------------------------------------<br>//<br>// FilemonConvertUnparsedPath<br>//<br>// Converts an unparsed unicode path to ANSI. This is only used for<br>// UNC paths except for the special cases of renames and findopens.<br>//<br>//----------------------------------------------------------------------<br>VOID<br>FilemonConvertUnparsedPath(<br> pioreq pir,<br> PCHAR fullpathname<br> )<br>{<br> _QWORD result;<br><br> UniToBCS( fullpathname, pir->ir_upath, wstrlen( pir->ir_upath ),<br> MAXPATHLEN, BCS_WANSI, &result );<br> fullpathname[ result.ddLower ] = 0;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonConvertParsedPath<br>// <br>// Converts a parsed unicode path to ANSI.<br>//<br>//----------------------------------------------------------------------<br>VOID<br>FilemonConvertParsedPath(<br> int drive,<br> path_t ppath,<br> int codepage,<br> PCHAR fullpathname <br> )<br>{<br> int i = 0;<br> _QWORD result;<br><br> if( drive != 0xFF ) {<br><br> //<br> // Its a volume-based path<br> // <br> fullpathname[0] = drive+'A'-1;<br> fullpathname[1] = ':';<br> i = 2;<br> }<br> fullpathname = 0;<br> UniToBCSPath( &fullpathname, ppath->pp_elements, <br> MAXPATHLEN-1, codepage, &result );<br> fullpathname[ i + result.ddLower ] = 0;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonConvertMixedPath<br>//<br>// This converts a mix of unparsed and parsed paths to ANSI. The <br>// unparsed path is used for server/share, whereas the parsed<br>// path is used for the directory/file. Only UNC rename and findopen <br>// use this.<br>// <br>//----------------------------------------------------------------------<br>VOID<br>FilemonConvertMixedPath(<br> pioreq pir,<br> path_t ppath,<br> int codepage,<br> PCHAR fullpathname<br> )<br>{<br> int i, slashes;<br> _QWORD result;<br><br> UniToBCS( fullpathname, pir->ir_upath, wstrlen( pir->ir_upath ), MAXPATHLEN-1,<br> codepage, &result );<br> fullpathname[ result.ddLower ] = 0;<br><br> slashes = 0;<br> for( i = 0; i < result.ddLower; i++ ) {<br> <br> //<br> // We find the 4th slash: //Server/share/...<br> //<br> if( fullpathname == '//' && ++slashes == 4 ) break;<br> }<br> if( slashes == 4 ) {<br><br> FilemonConvertParsedPath( 0xFF, ppath, codepage, &fullpathname);<br> }<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonConvertPath<br>//<br>// Converts a unicode path name to ANSI.<br>//<br>//----------------------------------------------------------------------<br>PCHAR <br>FilemonConvertPath( <br> CONVERT_TYPE converttype,<br> int drive, <br> pioreq pir,<br> int codepage,<br> PCHAR fullpathname <br> )<br>{<br> if( drive != 0xFF ) {<br><br> //<br> // Its a volume-based path<br> // <br> switch( converttype ) {<br> case CONVERT_RENAME_TARGET:<br> FilemonConvertParsedPath( drive, pir->ir_ppath2, codepage, fullpathname );<br> break;<br><br> default:<br> FilemonConvertParsedPath( drive, pir->ir_ppath, codepage, fullpathname );<br> break;<br> }<br><br> } else {<br> <br> //<br> // Its a UNC path. The parsed path doesn't include the<br> // server/share, so we get that from the unparsed path.<br> //<br> switch( converttype ) {<br> case CONVERT_STANDARD:<br> FilemonConvertUnparsedPath( pir, fullpathname );<br> break;<br><br> case CONVERT_FINDOPEN:<br> case CONVERT_RENAME_SOURCE:<br> FilemonConvertMixedPath( pir, pir->ir_ppath, codepage, fullpathname );<br> break;<br><br> case CONVERT_RENAME_TARGET:<br> FilemonConvertMixedPath( pir, pir->ir_ppath2, codepage, fullpathname );<br> break;<br> }<br> }<br> return fullpathname;<br>}<br><br><br>//----------------------------------------------------------------------<br>//<br>// FilemonGetFullPath<br>//<br>// Returns the full pathname of a file, if we can obtain one, else<br>// returns a handle.<br>//<br>//----------------------------------------------------------------------<br>PCHAR <br>FilemonGetFullPath( <br> fh_t filenumber, <br> PCHAR fullname,<br> int Drive, <br> int ResType, <br> int CodePage, <br> pioreq pir <br> )<br>{<br> PHASH_ENTRY hashEntry;<br> pIFSFunc enumFunc;<br> ifsreq ifsr;<br> path_t uniFullName;<br> int retval;<br><br> //<br> // See if we find the key in the hash table.<br> //<br> Wait_Semaphore( HashMutex, BLOCK_SVC_INTS );<br><br> hashEntry = HashTable[ HASHOBJECT( filenumber ) ];<br><br> while( hashEntry && <br> hashEntry->filenumber != filenumber &&<br> hashEntry->drive != (Drive & 0xFF)) {<br><br> hashEntry = hashEntry->Next;<br> }<br><br> Signal_Semaphore( HashMutex );<br><br> fullname[0] = 0;<br> if( hashEntry ) {<br><br> strcpy( fullname, hashEntry->FullName );<br><br> } else {<br><br> //<br> // File name isn't in the table, so ask the<br> // underlying file system<br> //<br> sprintf( fullname, "0x%X", filenumber );<br><br> uniFullName = IFSMgr_GetHeap( MAXPATHLEN * sizeof(WCHAR) + sizeof( path_t));<br> if( uniFullName ) {<br> <br> //<br> // Send a query file name request<br> //<br> memcpy( &ifsr, pir, sizeof( ifsreq ));<br> ifsr.ifsir.ir_flags = ENUMH_GETFILENAME;<br> ifsr.ifsir.ir_ppath = uniFullName;<br> enumFunc = ifsr.ifs_hndl->hf_misc->hm_func[HM_ENUMHANDLE];<br><br> retval = (*PrevIFSHookProc)(enumFunc, IFSFN_ENUMHANDLE, <br> Drive, ResType, CodePage, <br> (pioreq) &ifsr);<br><br> if( retval == ERROR_SUCCESS ) {<br> <br> FilemonConvertParsedPath( Drive, uniFullName, CodePage, fullname );<br> FilemonLogHash( Drive, filenumber, fullname );<br> }<br> IFSMgr_RetHeap( (void *) uniFullName );<br> } <br> }<br> return fullname;<br>}<br><br><br>//----------------------------------------------------------------------<br>// H O O K R O U T I N E<br>//----------------------------------------------------------------------<br><br>//----------------------------------------------------------------------<br>//<br>// FilemonHookProc<br>//<br>// All (most) IFS functions come through this routine for us to look<br>// at.<br>//<br>//----------------------------------------------------------------------<br>#pragma optimize("", off)<br>int <br>_cdecl <br>FilemonHookProc(<br> pIFSFunc pfn, <br> int fn, <br> int Drive, <br> int ResType,<br> int CodePage,<br> pioreq pir<br> )<br>{<br> int retval;<br> char fullpathname[MAXPATHLEN];<br> char processname[64];<br> char data[MAXPATHLEN];<br> char drivestring[4];<br> ifsreq origifsr;<br> pioreq origir;<br> _WIN32_FIND_DATA *finddata;<br> struct srch_entry *search;<br> BOOLEAN log;<br> _QWORD result;<br> DWORD timelo, timehi;<br> DWORD timelo1, timehi1;<br> DWORD dostime, dosdate;<br> DWORD datetimelo, datetimehi;<br> int i, j;<br><br> // <br> // Inititlize default data.<br> //<br> data[0] = 0;<br><br> //<br> // Save original iorequest because some entries get modified.<br> //<br> origir = (pioreq) &origifsr;<br> memcpy( &origifsr, pir, sizeof( ifsreq ));<br><br> //<br> // Get the current process name.<br> //<br> FilemonGetProcess( processname );<br><br> //<br> // Get the time<br> //<br> VTD_Get_Real_Time( &timehi, &timelo );<br> datetimehi = IFSMgr_Get_DOSTime( &datetimelo );<br> dostime = VTD_Get_Date_And_Time( &dosdate );<br> datetimelo = dostime - ((datetimehi >> 11)& 0x1F)*60*60*1000 - <br> ((datetimehi >> 5) & 0x3F)*60*1000 - <br> ((datetimehi & 0x1F)*2000);<br><br> //<br> // Special case for close call, since after the file's closed <br> // we can't query its name<br> //<br> if( fn == IFSFN_CLOSE ) {<br><br> FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );<br> }<br><br> //<br> // Call the previous hooker first, to get the return code.<br> //<br> retval = (*PrevIFSHookProc)(pfn, fn, Drive, ResType, CodePage, pir);<br><br> //<br> // Now extract parameters based on the function type.<br> //<br> dprintf("%d: %d/n", fn, pir->ir_fh ); <br> switch( fn ) {<br><br> case IFSFN_OPEN:<br><br> FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );<br><br> TIME_DIFF();<br> sprintf(data,"");<br> if( origir->ir_options & ACTION_CREATENEW ) strcat(data,"CREATENEW ");<br> if( origir->ir_options & ACTION_OPENEXISTING ) strcat(data,"OPENEXISTING ");<br> if( origir->ir_options & ACTION_REPLACEEXISTING ) strcat(data,"REPLACEEXISTING ");<br> switch (origir->ir_flags & ACCESS_MODE_MASK) {<br><br> case ACCESS_READONLY:<br> strcat(data,"READONLY ");<br> break;<br> case ACCESS_WRITEONLY:<br> strcat(data,"WRITEONLY ");<br> break;<br> case ACCESS_READWRITE:<br> strcat(data,"READWRITE ");<br> break;<br> case ACCESS_EXECUTE:<br> strcat(data,"EXECUTE ");<br> break;<br> default:<br> break;<br> }<br> switch (origir->ir_flags & SHARE_MODE_MASK) {<br> case SHARE_COMPATIBILITY:<br> strcat(data,"COMPATIBILITY ");<br> break;<br> case SHARE_DENYREADWRITE:<br> strcat(data,"DENYREADWRITE ");<br> break;<br> case SHARE_DENYWRITE:<br> strcat(data,"DENYWRITE ");<br> break;<br> case SHARE_DENYREAD:<br> strcat(data,"DENYREAD ");<br> break;<br> case SHARE_DENYNONE:<br> strcat(data,"DENYNONE ");<br> break;<br> default:<br> break;<br> }<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tOpen/t%s/t%s/t%s", <br> processname, fullpathname,<br> data, ErrorString( retval ));<br> FilemonLogHash( Drive, pir->ir_fh, fullpathname );<br> break;<br><br> case IFSFN_READ:<br> case IFSFN_WRITE:<br> FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );<br> if( ((fn == IFSFN_READ && FilterDef.logreads ) ||<br> (fn == IFSFN_WRITE && FilterDef.logwrites )) ) {<br><br> TIME_DIFF();<br> sprintf( data, "Offset: %ld Length: %ld", origir->ir_pos, origir->ir_length );<br> LogRecord( timelo, datetimelo, datetimehi, "%s/t%s/t%s/t%s/t%s", <br> processname, fn == IFSFN_READ? "Read" : "Write", <br> fullpathname,<br> data, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_CLOSE:<br> if( FilterDef.logreads ) {<br><br> TIME_DIFF();<br> switch( origir->ir_flags ) {<br> case CLOSE_HANDLE: sprintf(data, "CLOSE_HANDLE"); break;<br> case CLOSE_FOR_PROCESS: sprintf(data, "CLOSE_FOR_PROCESS"); break;<br> case CLOSE_FINAL: sprintf(data, "CLOSE_FINAL"); break;<br> default: sprintf(data,"0x%02X",origir->ir_flags); break;<br> }<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tClose/t%s/t%s/t%s", processname, <br> fullpathname, data, ErrorString( retval ));<br> }<br> if( origir->ir_flags == CLOSE_FINAL ) FilemonFreeHashEntry( Drive, origir->ir_fh);<br> break;<br><br> case IFSFN_DIR:<br><br> //<br> // This works around a special case I've seen when hiting the "browse" button in the <br> // "have disk" dialog of the hardware wizard<br> //<br> if( origir->ir_flags != 0xFF ) {<br><br> FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );<br><br> } else {<br><br> sprintf( fullpathname, "%c:", Drive+'A'-1);<br> }<br> TIME_DIFF();<br> log = FALSE;<br> switch( origir->ir_flags ) {<br> case CREATE_DIR:<br> sprintf(data, "CREATE");<br> if( FilterDef.logwrites ) log = TRUE;<br> break;<br> case DELETE_DIR:<br> sprintf(data,"DELETE");<br> if( FilterDef.logwrites ) log = TRUE;<br> break;<br> case CHECK_DIR:<br> sprintf(data,"CHECK");<br> if( FilterDef.logreads ) log = TRUE;<br> break;<br> default:<br> sprintf(data,"QUERY");<br> if( FilterDef.logreads ) log = TRUE;<br> break;<br> }<br> if( log ) {<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tDirectory/t%s/t%s/t%s", <br> processname, <br> fullpathname,<br> data, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_SEEK:<br> FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );<br> if( FilterDef.logreads) {<br><br> TIME_DIFF();<br> sprintf(data, "%s Offset: %ld / New offset: %ld",<br> origir->ir_flags == FILE_BEGIN ? "Beginning" : "End",<br> origir->ir_pos, origir->ir_pos ); <br> LogRecord( timelo, datetimelo, datetimehi, "%s/tSeek/t%s/t%s/t%s", <br> processname, fullpathname,<br> data, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_COMMIT:<br> FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );<br> if( FilterDef.logwrites) {<br><br> TIME_DIFF();<br> sprintf(data, "%s", origir->ir_options == FILE_COMMIT_ASYNC ? <br> "ASYNC" : "NOACCESSUPDATE" );<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tCommit/t%s/t%s/t%s", <br> processname, fullpathname,<br> data, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_FILELOCKS:<br> FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );<br> if( FilterDef.logreads) {<br><br> TIME_DIFF();<br> sprintf(data, "Offset: %ld Length:%ld", origir->ir_pos, origir->ir_locklen );<br> LogRecord( timelo, datetimelo, datetimehi, "%s/t%s/t%s/t%s/t%s", <br> processname, origir->ir_flags == LOCK_REGION ? "Lock" : "Unlock",<br> fullpathname,<br> data, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_FINDOPEN:<br> if( FilterDef.logreads) { <br><br> FilemonConvertPath( CONVERT_FINDOPEN, Drive, origir, CodePage, fullpathname );<br> TIME_DIFF();<br> if( !retval ) {<br><br> finddata = (_WIN32_FIND_DATA *) origir->ir_data;<br> UniToBCS( data, finddata->cFileName, wstrlen(finddata->cFileName), MAXPATHLEN-1, BCS_WANSI, &result );<br> data[ result.ddLower ] = 0;<br> }<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tFindOpen/t%s/t%s/t%s", <br> processname, fullpathname,<br> data, ErrorString( retval ));<br> }<br> FilemonLogHash( Drive, pir->ir_fh, fullpathname );<br> break;<br><br> case IFSFN_FINDNEXT:<br> FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );<br> if( FilterDef.logreads) { <br><br> TIME_DIFF();<br> if( !retval ) {<br> finddata = (_WIN32_FIND_DATA *) origir->ir_data;<br> UniToBCS( data, finddata->cFileName, wstrlen(finddata->cFileName), MAXPATHLEN-1, BCS_WANSI, &result );<br> data[ result.ddLower ] = 0;<br> }<br><br> LogRecord( timelo, datetimelo, datetimehi, "%s/tFindNext/t%s/t%s/t%s", <br> processname, fullpathname,<br> data, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_FINDCLOSE:<br> FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );<br> if( FilterDef.logreads) { <br><br> TIME_DIFF();<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tFindClose/t%s/t/t%s", <br> processname, fullpathname,<br> ErrorString( retval ));<br> }<br> FilemonFreeHashEntry( Drive, origir->ir_fh );<br> break;<br><br> case IFSFN_FILEATTRIB:<br> if( FilterDef.logreads) { <br><br> FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );<br> TIME_DIFF();<br> switch(origir->ir_flags ) {<br> case GET_ATTRIBUTES:<br> sprintf(data,"GetAttributes");<br> break;<br> case SET_ATTRIBUTES:<br> sprintf(data, "SetAttributes" );<br> break;<br> case GET_ATTRIB_COMP_FILESIZE:<br> sprintf(data, "GET_ATTRIB_COMP_FILESIZE" );<br> break;<br> case SET_ATTRIB_MODIFY_DATETIME:<br> sprintf(data, "SET_ATTRIB_MODIFY_DATETIME");<br> break;<br> case SET_ATTRIB_LAST_ACCESS_DATETIME:<br> sprintf(data, "SET_ATTRIB_LAST_ACCESS_DATETIME");<br> break;<br> case GET_ATTRIB_LAST_ACCESS_DATETIME:<br> sprintf(data, "GET_ATTRIB_LAST_ACCESS_DATETIME");<br> break;<br> case SET_ATTRIB_CREATION_DATETIME:<br> sprintf(data, "SET_ATTRIB_CREATION_DATETIME");<br> break;<br> case GET_ATTRIB_CREATION_DATETIME:<br> sprintf(data, "GET_ATTRIB_CREATION_DATETIME");<br> break;<br> }<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tAttributes/t%s/t%s/t%s", <br> processname, fullpathname,<br> data, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_FILETIMES:<br> FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );<br> if( FilterDef.logreads) { <br><br> TIME_DIFF();<br> switch( origir->ir_flags ) {<br> case GET_MODIFY_DATETIME:<br> sprintf(data, "Get Modify");<br> break;<br> case SET_MODIFY_DATETIME:<br> sprintf(data, "Set Modify");<br> break;<br> case GET_LAST_ACCESS_DATETIME:<br> sprintf(data, "Get Access");<br> break;<br> case SET_LAST_ACCESS_DATETIME:<br> sprintf(data, "Set Access");<br> break;<br> case GET_CREATION_DATETIME:<br> sprintf(data, "Get Creation");<br> break;<br> case SET_CREATION_DATETIME:<br> sprintf(data, "Set Creation");<br> break;<br> }<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tAttributes/t%s/t%s/t%s", <br> processname, fullpathname,<br> data, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_FLUSH:<br> if( FilterDef.logwrites) {<br><br> TIME_DIFF();<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tFlushVolume/t/t/t%s",<br> processname, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_DELETE:<br> if( FilterDef.logwrites) { <br><br> FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );<br> TIME_DIFF();<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tDelete/t%s/t/t%s", <br> processname, fullpathname, ErrorString( retval ));<br> }<br> FilemonFreeHashEntry( Drive, origir->ir_fh );<br> break;<br><br> case IFSFN_SEARCH:<br> if( FilterDef.logreads ) {<br><br> if( origir->ir_flags == SEARCH_FIRST ) <br> FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );<br> else<br> sprintf(fullpathname, "SearchNext" );<br> TIME_DIFF();<br> if( !retval ) {<br> j = 0;<br> if( origir->ir_attr & FILE_ATTRIBUTE_LABEL ) {<br> sprintf(data, "VolumeLabel: " );<br> j = strlen( data );<br> }<br> search = (struct srch_entry *) origir->ir_data;<br> for( i = 0; i < 13; i++ ) <br> if( search->se_name != ' ' ) data[j++] = search->se_name;<br> data[j] = 0;<br> }<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tSearch/t%s/t%s/t%s", <br> processname, fullpathname, data, ErrorString( retval )); <br> }<br> break;<br> <br> case IFSFN_GETDISKINFO:<br><br> if( FilterDef.logreads ) {<br><br> TIME_DIFF();<br> if( !retval ) sprintf(data, "Free Space");<br> drivestring[0] = Drive+'A'-1;<br> drivestring[1] = ':';<br> drivestring[2] = 0;<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tGetDiskInfo/t%s/t%s/t%s",<br> processname, drivestring, data, ErrorString( retval ));<br> }<br> break;<br><br> case IFSFN_RENAME:<br> if( FilterDef.logwrites) { <br><br> FilemonConvertPath( CONVERT_RENAME_SOURCE, Drive, origir, CodePage, fullpathname );<br> TIME_DIFF();<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tRename/t%s/t%s/t%s",<br> processname, fullpathname,<br> FilemonConvertPath( CONVERT_RENAME_TARGET, Drive, origir, CodePage, data ),<br> ErrorString( retval )); <br> }<br> break;<br> case IFSFN_IOCTL16DRIVE:<br> if( FilterDef.logreads || FilterDef.logwrites) {<br><br> TIME_DIFF();<br> sprintf(data, "Subfunction: %02Xh", origir->ir_flags );<br> drivestring[0] = Drive+'A'-1;<br> drivestring[1] = ':';<br> drivestring[2] = 0;<br> LogRecord( timelo, datetimelo, datetimehi, "%s/tIoctl/t%s/t%s/t%s",<br> processname, drivestring, data, ErrorString( retval ));<br> }<br> break;<br> }<br> dprintf("==>%d/n", fn );<br> return retval;<br>}<br>#pragma optimize("", on)<br><br>//----------------------------------------------------------------------<br>//<br>// OnSysDynamicDeviceInit<br>//<br>// Dynamic init. Install a file system filter hook.<br>//<br>//----------------------------------------------------------------------<br>BOOL <br>OnSysDynamicDeviceInit(<br> VOID<br> )<br>{<br> int i;<br> MEMHANDLE hLog;<br><br> //<br> // Initialize the locks.<br> //<br> LogMutex = Create_Semaphore(1);<br> HashMutex = Create_Semaphore(1);<br> FilterMutex = Create_Semaphore(1);<br><br> // <br> // Zero hash table.<br> //<br> for(i = 0; i < NUMHASH; i++ ) HashTable = NULL;<br><br> //<br> // Allocate the initial output buffer.<br> //<br> PageAllocate(LOGBUFPAGES, PG_SYS, 0, 0, 0, 0, NULL, PAGELOCKED, <br> (PMEMHANDLE) &hLog, (PVOID) &Log );<br> Log->Handle = hLog;<br> Log->Len = 0;<br> Log->Next = NULL;<br> NumLog = 1;<br><br> //<br> // Hook IFS functions.<br> //<br> PrevIFSHookProc = IFSMgr_InstallFileSystemApiHook(FilemonHookProc);<br> return TRUE;<br>}<br><br>//----------------------------------------------------------------------<br>//<br>// OnSysDynamicDeviceExit<br>//<br>// Dynamic exit. Unhook everything.<br>//<br>//----------------------------------------------------------------------<br>BOOL <br>OnSysDynamicDeviceExit(<br> VOID<br> )<br>{<br> //<br> // Unhook IFS functions.<br> //<br> IFSMgr_RemoveFileSystemApiHook(FilemonHookProc);<br><br> //<br> // Free all memory.<br> //<br> FilemonHashCleanup();<br> FilemonFreeLog();<br> FilemonFreeFilters();<br> return TRUE;<br>}<br><br>//----------------------------------------------------------------------<br>//<br>// OnW32Deviceiocontrol<br>//<br>// Interface with the GUI.<br>//<br>//----------------------------------------------------------------------<br>DWORD <br>OnW32Deviceiocontrol(<br> PIOCTLPARAMS p<br> )<br>{<br> PLOG_BUF old;<br><br> switch( p->dioc_IOCtlCode ) {<br> case 0:<br> return ERROR_SUCCESS;<br><br> case IOCTL_FILEMON_ZEROSTATS:<br><br> Wait_Semaphore( LogMutex, BLOCK_SVC_INTS );<br> while ( Log->Next ) {<br> <br> //<br> // Release the next entry.<br> //<br> old = Log->Next;<br> Log->Next = old->Next;<br> Signal_Semaphore( LogMutex );<br> PageFree( old->Handle, 0 );<br> Wait_Semaphore( LogMutex, BLOCK_SVC_INTS );<br> NumLog--;<br> }<br> Log->Len = 0;<br> Signal_Semaphore( LogMutex );<br> Sequence = 0;<br> return ERROR_SUCCESS;<br><br> case IOCTL_FILEMON_GETSTATS:<br><br> //<br> // Copy buffer into user space.<br> Wait_Semaphore( LogMutex, BLOCK_SVC_INTS );<br> if ( LOGBUFSIZE > p->dioc_cbOutBuf ) {<br><br> //<br> // Buffer is too small. Return error.<br> //<br> Signal_Semaphore( LogMutex );<br> return ERROR_INSUFFICIENT_BUFFER;<br><br> } else if ( Log->Len || Log->Next ) {<br><br> //<br> // Switch to a new buffer.<br> //<br> FilemonNewLog();<br><br> //<br> // Fetch the oldest buffer to give to caller.<br> //<br> old = FilemonOldestLog();<br> Signal_Semaphore( LogMutex );<br><br> //<br> // Copy it into the caller's buffer.<br> //<br> memcpy( p->dioc_OutBuf, old->Data, old->Len );<br><br> //<br> // Return length of copied info.<br> //<br> *p->dioc_bytesret = old->Len;<br><br> // <br> // Deallocate the buffer.<br> //<br> PageFree( old->Handle, 0 );<br><br> } else {<br><br> //<br> // There is no unread data.<br> //<br> Signal_Semaphore( LogMutex );<br> *p->dioc_bytesret = 0;<br> }<br> return ERROR_SUCCESS;<br><br> case IOCTL_FILEMON_STOPFILTER:<br><br> FilterOn = FALSE;<br> return ERROR_SUCCESS;<br><br> case IOCTL_FILEMON_STARTFILTER:<br><br> FilterOn = TRUE;<br> return ERROR_SUCCESS;<br><br> case IOCTL_FILEMON_SETFILTER:<br><br> FilterDef = * (PFILTER) p->dioc_InBuf;<br> FilemonUpdateFilters();<br> return ERROR_SUCCESS;<br><br> default:<br> return ERROR_INVALID_FUNCTION;<br> }<br>}<br>