FILEMON.C
上传用户:hmgghm
上传日期:2007-01-07
资源大小:335k
文件大小:162k
源码类别:

文件操作

开发平台:

Visual C++

  1. //======================================================================
  2. // 
  3. // Filemon.c
  4. //
  5. // Copyright (C) 1996-1998 Mark Russinovich and Bryce Cogswell
  6. //
  7. // Implements the equivalent of Windows 95 IFSMgr_FileSystemApiHook.
  8. //
  9. // Note: the reason that we use NonPagedPool even though the driver
  10. // only accesses allocated buffer at PASSIVE_LEVEL, is that touching
  11. // a paged pool buffer can generate a page fault, and if the paging
  12. // file is on a drive that filemon is monitoring filemon would be
  13. // reentered to handle the page fault. We want to avoid that and so
  14. // we only use nonpaged pool.
  15. //
  16. //======================================================================
  17. #include "ntddk.h"
  18. #include "stdarg.h"
  19. #include "stdio.h"
  20. #include "..guiioctlcmd.h"
  21. #include "filemon.h"
  22. #include "winioctl.h"
  23. //----------------------------------------------------------------------
  24. //                           DEFINES
  25. //----------------------------------------------------------------------
  26. //
  27. // Print macro that only turns on when debugging is on
  28. //
  29. #if DBG
  30. #define DbgPrint(arg) DbgPrint arg
  31. #else
  32. #define DbgPrint(arg) 
  33. #endif
  34. //
  35. // The name of the System process, in which context we're called in our 
  36. // DriverEntry
  37. //
  38. #define SYSNAME    "System"
  39. //----------------------------------------------------------------------
  40. //                          TYPEDEFS
  41. //----------------------------------------------------------------------
  42. // 
  43. // Directory control structure
  44. //
  45. typedef struct {
  46.     ULONG Length;
  47.     PUNICODE_STRING FileName;
  48.     FILE_INFORMATION_CLASS FileInformationClass;
  49.     ULONG FileIndex;
  50. } QUERY_DIRECTORY, *PQUERY_DIRECTORY;
  51. //
  52. // Lock control data structure
  53. //
  54. typedef struct {
  55.     PLARGE_INTEGER Length;
  56.     ULONG Key;
  57.     LARGE_INTEGER ByteOffset;
  58. } LOCK_CONTROL, *PLOCK_CONTROL;
  59. //
  60. // File name information 
  61. //
  62. typedef struct _FILE_NAME_INFORMATION {
  63.     ULONG FileNameLength;
  64.     WCHAR FileName[1];
  65. } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
  66. //----------------------------------------------------------------------
  67. //                         FORWARD DEFINES
  68. //---------------------------------------------------------------------- 
  69. //
  70. // These are prototypes for Filemon's Fast I/O hooks. The originals 
  71. // prototypes can be found in NTDDK.H
  72. // 
  73. BOOLEAN  FilemonFastIoCheckifPossible( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, 
  74.                                        IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN BOOLEAN CheckForReadOperation,
  75.                                        OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  76. BOOLEAN  FilemonFastIoRead( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, 
  77.                             IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, OUT PVOID Buffer,
  78.                             OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  79. BOOLEAN  FilemonFastIoWrite( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, 
  80.                              IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN PVOID Buffer,
  81.                              OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  82. BOOLEAN  FilemonFastIoQueryBasicInfo( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, 
  83.                                       OUT PFILE_BASIC_INFORMATION Buffer,
  84.                                       OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  85. BOOLEAN  FilemonFastIoQueryStandardInfo( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, 
  86.                                          OUT PFILE_STANDARD_INFORMATION Buffer,
  87.                                          OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  88. BOOLEAN  FilemonFastIoLock( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset,
  89.                             IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key,
  90.                             BOOLEAN FailImmediately, BOOLEAN ExclusiveLock,
  91.                             OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  92. BOOLEAN  FilemonFastIoUnlockSingle( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset,
  93.                                     IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key,
  94.                                     OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  95. BOOLEAN  FilemonFastIoUnlockAll( IN PFILE_OBJECT FileObject, PEPROCESS ProcessId,
  96.                                  OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  97. BOOLEAN  FilemonFastIoUnlockAllByKey( IN PFILE_OBJECT FileObject, PEPROCESS ProcessId, ULONG Key,
  98.                                       OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  99. BOOLEAN  FilemonFastIoDeviceControl( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait,
  100.                                      IN PVOID InputBuffer, IN ULONG InputBufferLength, 
  101.                                      OUT PVOID OutbufBuffer, IN ULONG OutputBufferLength, IN ULONG IoControlCode,
  102.                                      OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject );
  103. VOID     FilemonFastIoAcquireFile( PFILE_OBJECT FileObject );
  104. VOID     FilemonFastIoReleaseFile( PFILE_OBJECT FileObject );
  105. VOID     FilemonFastIoDetachDevice( PDEVICE_OBJECT SourceDevice, PDEVICE_OBJECT TargetDevice );
  106. //
  107. // These are new NT 4.0 Fast I/O calls
  108. //
  109. BOOLEAN  FilemonFastIoQueryNetworkOpenInfo(IN PFILE_OBJECT FileObject,
  110.                                            IN BOOLEAN Wait, OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer,
  111.                                            OUT struct _IO_STATUS_BLOCK *IoStatus, IN PDEVICE_OBJECT DeviceObject );
  112. NTSTATUS FilemonFastIoAcquireForModWrite( IN PFILE_OBJECT FileObject,
  113.                                           IN PLARGE_INTEGER EndingOffset, OUT struct _ERESOURCE **ResourceToRelease,
  114.                                           IN PDEVICE_OBJECT DeviceObject );
  115. BOOLEAN  FilemonFastIoMdlRead( IN PFILE_OBJECT FileObject,
  116.                                IN PLARGE_INTEGER FileOffset, IN ULONG Length,
  117.                                IN ULONG LockKey, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus,
  118.                                IN PDEVICE_OBJECT DeviceObject );
  119. BOOLEAN  FilemonFastIoMdlReadComplete( IN PFILE_OBJECT FileObject,
  120.                                        IN PMDL MdlChain, IN PDEVICE_OBJECT DeviceObject );
  121. BOOLEAN  FilemonFastIoPrepareMdlWrite( IN PFILE_OBJECT FileObject,
  122.                                        IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey,
  123.                                        OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus,
  124.                                        IN PDEVICE_OBJECT DeviceObject );
  125. BOOLEAN  FilemonFastIoMdlWriteComplete( IN PFILE_OBJECT FileObject,
  126.                                         IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain,
  127.                                         IN PDEVICE_OBJECT DeviceObject );
  128. BOOLEAN  FilemonFastIoReadCompressed( IN PFILE_OBJECT FileObject,
  129.                                       IN PLARGE_INTEGER FileOffset, IN ULONG Length,
  130.                                       IN ULONG LockKey, OUT PVOID Buffer, OUT PMDL *MdlChain,
  131.                                       OUT PIO_STATUS_BLOCK IoStatus,
  132.                                       OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
  133.                                       IN ULONG CompressedDataInfoLength, IN PDEVICE_OBJECT DeviceObject );
  134. BOOLEAN  FilemonFastIoWriteCompressed( IN PFILE_OBJECT FileObject,
  135.                                        IN PLARGE_INTEGER FileOffset, IN ULONG Length,
  136.                                        IN ULONG LockKey, IN PVOID Buffer, OUT PMDL *MdlChain,
  137.                                        OUT PIO_STATUS_BLOCK IoStatus,
  138.                                        IN struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
  139.                                        IN ULONG CompressedDataInfoLength, IN PDEVICE_OBJECT DeviceObject );
  140. BOOLEAN  FilemonFastIoMdlReadCompleteCompressed( IN PFILE_OBJECT FileObject,
  141.                                                  IN PMDL MdlChain, IN PDEVICE_OBJECT DeviceObject );
  142. BOOLEAN  FilemonFastIoMdlWriteCompleteCompressed( IN PFILE_OBJECT FileObject,
  143.                                                   IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain,
  144.                                                   IN PDEVICE_OBJECT DeviceObject );
  145. BOOLEAN  FilemonFastIoQueryOpen( IN struct _IRP *Irp,
  146.                                  OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation,
  147.                                  IN PDEVICE_OBJECT DeviceObject );
  148. NTSTATUS FilemonFastIoReleaseForModWrite( IN PFILE_OBJECT FileObject,
  149.                                           IN struct _ERESOURCE *ResourceToRelease, IN PDEVICE_OBJECT DeviceObject );
  150. NTSTATUS FilemonFastIoAcquireForCcFlush( IN PFILE_OBJECT FileObject,
  151.                                          IN PDEVICE_OBJECT DeviceObject );
  152. NTSTATUS FilemonFastIoReleaseForCcFlush( IN PFILE_OBJECT FileObject,
  153.                                          IN PDEVICE_OBJECT DeviceObject );
  154. //----------------------------------------------------------------------
  155. //                         GLOBALS
  156. //---------------------------------------------------------------------- 
  157. //
  158. // This is Filemon's user-inteface device object. It is addressed
  159. // by calls from the GUI including CreateFile and DeviceIoControl
  160. //
  161. PDEVICE_OBJECT      GUIDevice;
  162. //
  163. // This is our Driver Object
  164. //
  165. PDRIVER_OBJECT      FilemonDriver;
  166. //
  167. // Indicates if the GUI wants activity to be logged
  168. //
  169. BOOLEAN             FilterOn = FALSE;
  170. //
  171. // Global filter (sent to us by the GUI)
  172. //
  173. FILTER              FilterDef;
  174. //
  175. // This lock protects access to the filter array
  176. //
  177. ERESOURCE           FilterResource;
  178. //
  179. // Array of process and path filters 
  180. //
  181. //
  182. // Array of process and path filters 
  183. //
  184. ULONG               NumIncludeFilters = 0;
  185. PCHAR               IncludeFilters[MAXFILTERS];
  186. ULONG               NumExcludeFilters = 0;
  187. PCHAR               ExcludeFilters[MAXFILTERS];
  188. //
  189. // Which type of timing are we doing (told to us by GUI)
  190. //
  191. BOOLEAN             TimeIsDuration;
  192. //
  193. // Once a load is initiated, this flag prevents the processing of
  194. // further IRPs. This is required because an unload can only take
  195. // place if there are any IRP's for which an IoCompletion has
  196. // been registered that has not actually completed.
  197. //
  198. BOOLEAN             UnloadInProgress = FALSE;
  199. //
  200. // This is the offset into a KPEB of the current process name. This is determined
  201. // dynamically by scanning the process block belonging to the GUI for the name
  202. // of the system process, in who's context we execute in DriverEntry
  203. //
  204. ULONG               ProcessNameOffset;
  205. //
  206. // This variable keeps track of the outstanding IRPs (ones for which
  207. // a completion routine has been registered, but that have not yet
  208. // passed through the completion routine), which is used in 
  209. // the unload determination logic. The CountMutex protects data
  210. // races on updating the count.
  211. //
  212. ULONG               OutstandingIRPCount = 0;
  213. KSPIN_LOCK          CountMutex;
  214. //
  215. // Table of our hook devices for each drive letter. This makes it
  216. // easy to look up the device object that was created to hook a 
  217. // particular drive.
  218. //
  219. PDEVICE_OBJECT      LDriveDevices[26];
  220. //
  221. // This table keeps track of which drives are controlled by common
  222. // network redirectors (unhooking one results in all of the group
  223. // being unhooked). Each device object that is hooked is assigned
  224. // a unique identifier. Network devices are used to represent 
  225. // multiple logical drives, so the drive map entries for network
  226. // drive handled by the same network device object have the
  227. // same identifier.
  228. //
  229. int                 LDriveMap[26];
  230. int                 LDriveGroup = 0;
  231. //
  232. // The special file system hook devices
  233. //
  234. PDEVICE_OBJECT      NamedPipeHookDevice = NULL;
  235. PDEVICE_OBJECT      MailSlotHookDevice = NULL;
  236. //
  237. // Hash table for keeping names around. This is necessary because 
  238. // at any time the name information in the fileobjects that we
  239. // see can be deallocated and reused. If we want to print accurate
  240. // names, we need to keep them around ourselves. 
  241. //
  242. PHASH_ENTRY         HashTable[NUMHASH];
  243. //
  244. // Reader/Writer lock to protect hash table.
  245. //
  246. ERESOURCE         HashResource;
  247. //
  248. // The current output buffer
  249. //
  250. PSTORE_BUF          Store = NULL;
  251. //
  252. // Each IRP is given a sequence number. This allows the return status
  253. // of an IRP, which is obtained in the completion routine, to be 
  254. // associated with the IRPs parameters that were extracted in the Dispatch
  255. // routine.
  256. //
  257. ULONG               Sequence = 0;
  258. //
  259. // This mutex protects the output buffer
  260. //
  261. FAST_MUTEX          StoreMutex;
  262. //
  263. // Filemon keeps track of the number of distinct output buffers that
  264. // have been allocated, but not yet uploaded to the GUI, and caps
  265. // the amount of memory (which is in non-paged pool) it takes at
  266. // 1MB.
  267. //
  268. ULONG               NumStore = 0;
  269. ULONG               MaxStore = 1000000/MAX_STORE;
  270. //
  271. // Free hash list. Note: we don't use lookaside lists since
  272. // we want to be able to run on NT 3.51 - lookasides were
  273. // introduced in NT 4.0
  274. //
  275. PHASH_ENTRY         FreeHashList = NULL;
  276. //
  277. // These are the text representations of the classes of IRP_MJ_SET/GET_INFORMATION
  278. // calls
  279. //
  280. CHAR    *FileInformation[] = {
  281.     "",
  282.     "FileDirectoryInformation",
  283.     "FileFullDirectoryInformation",
  284.     "FileBothDirectoryInformation",
  285.     "FileBasicInformation",
  286.     "FileStandardInformation",
  287.     "FileInternalInformation",
  288.     "FileEaInformation",
  289.     "FileAccessInformation",
  290.     "FileNameInformation",
  291.     "FileRenameInformation",
  292.     "FileLinkInformation",
  293.     "FileNamesInformation",
  294.     "FileDispositionInformation",
  295.     "FilePositionInformation",
  296.     "FileFullEaInformation",
  297.     "FileModeInformation",
  298.     "FileAlignmentInformation",
  299.     "FileAllInformation",
  300.     "FileAllocationInformation",
  301.     "FileEndOfFileInformation",
  302.     "FileAlternateNameInformation",
  303.     "FileStreamInformation",
  304.     "FilePipeInformation",
  305.     "FilePipeLocalInformation",
  306.     "FilePipeRemoteInformation",
  307.     "FileMailslotQueryInformation",
  308.     "FileMailslotSetInformation",
  309.     "FileCompressionInformation",
  310.     "FileCopyOnWriteInformation",
  311.     "FileCompletionInformation",
  312.     "FileMoveClusterInformation",
  313.     "FileOleClassIdInformation",
  314.     "FileOleStateBitsInformation",
  315.     "FileNetworkOpenInformation",
  316.     "FileObjectIdInformation",
  317.     "FileOleAllInformation",
  318.     "FileOleDirectoryInformation",
  319.     "FileContentIndexInformation",
  320.     "FileInheritContentIndexInformation",
  321.     "FileOleInformation",
  322.     "FileMaximumInformation",
  323. };
  324. //
  325. // These are textual representations of the IRP_MJ_SET/GET_VOLUME_INFORMATION
  326. // classes
  327. //
  328. CHAR *VolumeInformation[] = {
  329.     "",
  330.     "FileFsVolumeInformation",
  331.     "FileFsLabelInformation",
  332.     "FileFsSizeInformation",
  333.     "FileFsDeviceInformation",
  334.     "FileFsAttributeInformation",
  335.     "FileFsQuotaQueryInformation",
  336.     "FileFsQuotaSetInformation",
  337.     "FileFsControlQueryInformation",
  338.     "FileFsControlSetInformation",
  339.     "FileFsMaximumInformation",
  340. };
  341.     
  342. //
  343. // This Filemon's Fast I/O dispatch table. Note that NT assumes that
  344. // file system drivers support some Fast I/O calls, so this table must
  345. // be present for an file system filter driver
  346. //
  347. FAST_IO_DISPATCH    FastIOHook = {
  348.     sizeof(FAST_IO_DISPATCH), 
  349.     FilemonFastIoCheckifPossible,
  350.     FilemonFastIoRead,
  351.     FilemonFastIoWrite,
  352.     FilemonFastIoQueryBasicInfo,
  353.     FilemonFastIoQueryStandardInfo,
  354.     FilemonFastIoLock,
  355.     FilemonFastIoUnlockSingle,
  356.     FilemonFastIoUnlockAll,
  357.     FilemonFastIoUnlockAllByKey,
  358.     FilemonFastIoDeviceControl,
  359.     FilemonFastIoAcquireFile,
  360.     FilemonFastIoReleaseFile,
  361.     FilemonFastIoDetachDevice,
  362.     //
  363.     // new for NT 4.0
  364.     //
  365.     FilemonFastIoQueryNetworkOpenInfo,
  366.     FilemonFastIoAcquireForModWrite,
  367.     FilemonFastIoMdlRead,
  368.     FilemonFastIoMdlReadComplete,
  369.     FilemonFastIoPrepareMdlWrite,
  370.     FilemonFastIoMdlWriteComplete,
  371.     FilemonFastIoReadCompressed,
  372.     FilemonFastIoWriteCompressed,
  373.     FilemonFastIoMdlReadCompleteCompressed,
  374.     FilemonFastIoMdlWriteCompleteCompressed,
  375.     FilemonFastIoQueryOpen,
  376.     FilemonFastIoReleaseForModWrite,
  377.     FilemonFastIoAcquireForCcFlush,
  378.     FilemonFastIoReleaseForCcFlush
  379. };
  380. //----------------------------------------------------------------------
  381. //      P A T T E R N   M A T C H I N G   R O U T I N E S
  382. //----------------------------------------------------------------------
  383. //----------------------------------------------------------------------
  384. //
  385. // MatchOkay
  386. //
  387. // Only thing left after compare is more mask. This routine makes
  388. // sure that its a valid wild card ending so that its really a match.
  389. //
  390. //----------------------------------------------------------------------
  391. BOOLEAN MatchOkay( PCHAR Pattern )
  392. {
  393.     //
  394.     // If pattern isn't empty, it must be a wildcard
  395.     //
  396.     if( *Pattern && *Pattern != '*' ) {
  397.  
  398.         return FALSE;
  399.     }
  400.     //
  401.     // Matched
  402.     //
  403.     return TRUE;
  404. }
  405. //----------------------------------------------------------------------
  406. //
  407. // MatchWithPattern
  408. //
  409. // Performs nifty wildcard comparison.
  410. //
  411. //----------------------------------------------------------------------
  412. BOOLEAN MatchWithPattern( PCHAR Pattern, PCHAR Name )
  413. {
  414.     CHAR   upcase;
  415.     //
  416.     // End of pattern?
  417.     //
  418.     if( !*Pattern ) {
  419.         return FALSE;
  420.     }
  421.     //
  422.     // If we hit a wild card, do recursion
  423.     //
  424.     if( *Pattern == '*' ) {
  425.         Pattern++;
  426.         while( *Name && *Pattern ) {
  427.             if( *Name >= 'a' && *Name <= 'z' )
  428.                 upcase = *Name - 'a' + 'A';
  429.             else
  430.                 upcase = *Name;
  431.             //
  432.             // See if this substring matches
  433.             //
  434.             if( *Pattern == upcase || *Name == '*' ) {
  435.                 if( MatchWithPattern( Pattern+1, Name+1 )) {
  436.                     return TRUE;
  437.                 }
  438.             }
  439.             //
  440.             // Try the next substring
  441.             //
  442.             Name++;
  443.         }
  444.         //
  445.         // See if match condition was met
  446.         //
  447.         return MatchOkay( Pattern );
  448.     } 
  449.     //
  450.     // Do straight compare until we hit a wild card
  451.     //
  452.     while( *Name && *Pattern != '*' ) {
  453.         if( *Name >= 'a' && *Name <= 'z' )
  454.             upcase = *Name - 'a' + 'A';
  455.         else
  456.             upcase = *Name;
  457.         if( *Pattern == upcase ) {
  458.             Pattern++;
  459.             Name++;
  460.         } else {
  461.             return FALSE;
  462.         }
  463.     }
  464.     //
  465.     // If not done, recurse
  466.     //
  467.     if( *Name ) {
  468.         return MatchWithPattern( Pattern, Name );
  469.     }
  470.     //
  471.     // Make sure its a match
  472.     //
  473.     return MatchOkay( Pattern );
  474. }
  475. //----------------------------------------------------------------------
  476. //            B U F F E R   M A N A G E M E N T
  477. //----------------------------------------------------------------------
  478. //----------------------------------------------------------------------
  479. //
  480. // FilemonFreeStore
  481. //
  482. // Frees all the data output buffers that we have currently allocated.
  483. //
  484. //----------------------------------------------------------------------
  485. VOID FilemonFreeStore()
  486. {
  487.     PSTORE_BUF  prev;
  488.     
  489.     //
  490.     // Just traverse the list of allocated output buffers
  491.     //
  492.     while( Store ) {
  493.         prev = Store->Next;
  494.         ExFreePool( Store );
  495.         Store = prev;
  496.     }
  497. }   
  498. //----------------------------------------------------------------------
  499. //
  500. // FilemonNewStore
  501. //
  502. // Called when the current buffer has filled up. This allocates a new
  503. // buffer and stick it at the head (newest) entry of our buffer list.
  504. //
  505. //----------------------------------------------------------------------
  506. void FilemonNewStore( void )
  507. {
  508.     PSTORE_BUF prev = Store, newstore;
  509.     //
  510.     // If we've already allocated the allowed number of buffers, just
  511.     // reuse the current one. This will result in output records being
  512.     // lost, but it takes ALOT of file system activity to cause this.
  513.     //
  514.     if( MaxStore == NumStore ) {
  515.         Store->Len = 0;
  516.         return; 
  517.     }
  518.     //
  519.     // If the output buffer we currently are using is empty, just
  520.     // use it.
  521.     //
  522.     if( !Store->Len ) 
  523.         return;
  524.     //
  525.     // Allocate a new output buffer
  526.     //
  527.     newstore = ExAllocatePool( NonPagedPool, sizeof(*Store) );
  528.     if( newstore ) { 
  529.         //
  530.         // Allocation was successful so add the buffer to the list
  531.         // of allocated buffers and increment the buffer count.
  532.         //
  533.         Store   = newstore;
  534.         Store->Len  = 0;
  535.         Store->Next = prev;
  536.         NumStore++;
  537.     } else {
  538.         //
  539.         // The allocation failed - just reuse the current buffer
  540.         //
  541.         Store->Len = 0;
  542.     }
  543. }
  544. //----------------------------------------------------------------------
  545. //
  546. // FilemonOldestStore
  547. //
  548. // Traverse the list of allocated buffers to find the last one, which
  549. // will be the oldest (as we want to return the oldest data to the GUI
  550. // first).
  551. //
  552. //----------------------------------------------------------------------
  553. PSTORE_BUF FilemonOldestStore( void )
  554. {
  555.     PSTORE_BUF  ptr = Store, prev = NULL;
  556.     //
  557.     // Traverse the list
  558.     //    
  559.     while ( ptr->Next ) {
  560.         ptr = (prev = ptr)->Next;
  561.     }
  562.     //
  563.     // Remove the buffer from the list
  564.     //
  565.     if ( prev ) {
  566.         prev->Next = NULL;    
  567.         NumStore--;
  568.     }
  569.     return ptr;
  570. }
  571. //----------------------------------------------------------------------
  572. //
  573. // FilemonResetStore
  574. //
  575. // When a GUI instance has close communication (exited), but the driver
  576. // can't unload due to oustdanding IRPs, all the output buffers except
  577. // one are all deallocated so that the memory footprint is shrunk as much 
  578. // as possible.
  579. //
  580. //----------------------------------------------------------------------
  581. VOID FilemonResetStore()
  582. {
  583.     PSTORE_BUF  current, next;
  584.     ExAcquireFastMutex( &StoreMutex );
  585.     //
  586.     // Traverse the list of output buffers
  587.     //
  588.     current = Store->Next;
  589.     while( current ) {
  590.         //
  591.         // Free the buffer
  592.         //
  593.         next = current->Next;
  594.         ExFreePool( current );
  595.         current = next;
  596.     }
  597.     // 
  598.     // Move the output pointer in the buffer that's being kept
  599.     // the start of the buffer.
  600.     // 
  601.     NumStore = 1;
  602.     Store->Len = 0;
  603.     Store->Next = NULL;
  604.     ExReleaseFastMutex( &StoreMutex );    
  605. }
  606. //----------------------------------------------------------------------
  607. //
  608. // MyInterlockedIncrement
  609. //
  610. // On 3.51 InterlockedIncrement doesn't return the udpates value(!).
  611. //
  612. //----------------------------------------------------------------------
  613. __inline ULONG MyInterlockedIncrement( PULONG Number )
  614. {
  615.     if( *NtBuildNumber < NT4FINAL ) {
  616.         //
  617.         // Just use the count spin lock
  618.         //
  619.         return ExInterlockedAddUlong( Number, 1, &CountMutex );
  620.     } else {
  621.         return InterlockedIncrement( Number );
  622.     }
  623. }
  624. //----------------------------------------------------------------------
  625. //
  626. // UpdateStore
  627. //
  628. // This "printfs" a string into an output buffer.
  629. //
  630. //----------------------------------------------------------------------
  631. void UpdateStore( ULONG seq, PLARGE_INTEGER time, const CHAR * format, ... ) 
  632. {   
  633.     PENTRY             Entry;
  634.     int                len;
  635.     va_list            arg_ptr;
  636.     static CHAR        text[MAXPATHLEN];
  637.     //
  638.     // If no GUI is there to receive the output or if no filtering is desired, don't bother
  639.     //     
  640.     if( !FilterOn ) {
  641.      
  642.         return;
  643.     }
  644.     // 
  645.     // Lock the output buffer and Store.
  646.     // 
  647.     ExAcquireFastMutex( &StoreMutex );
  648.     //
  649.     // Send text out as debug output  This is x86 specific.
  650.     //      
  651. #define A (&format)
  652.     DbgPrint(( (char *)format, A[1], A[2], A[3], A[4], A[5], A[6] ));
  653.     DbgPrint(( "n" ));
  654. #undef A
  655.     //
  656.     // Vsprintf to determine the length of the buffer
  657.     //
  658.     va_start( arg_ptr, format );
  659.     len = vsprintf( text, format, arg_ptr );
  660.     va_end( arg_ptr );
  661.     
  662.     //
  663.     // ULONG align for Alpha
  664.     //
  665.     len += 4; len &=  0xFFFFFFFC; // +1 to include null terminator and +3 to allign on 32 bit
  666.     //
  667.     // If the current output buffer is near capacity, move to a new 
  668.     // output buffer
  669.     //
  670.     if ( Store->Len + len + sizeof(ENTRY) +1 >= MAX_STORE ) {
  671.         FilemonNewStore();
  672.     }
  673.     //
  674.     // Extract the sequence number and store it
  675.     //
  676.     Entry = (void *)(Store->Data+Store->Len);
  677.     Entry->seq = seq;
  678.     Entry->time = *time;
  679.     memcpy( Entry->text, text, len );
  680.  
  681.     //
  682.     // Store the length of the string, plus 1 for the terminating
  683.     // NULL  
  684.     //   
  685.     Store->Len += (Entry->text - (PCHAR) Entry ) + len;
  686.     //
  687.     // Release the output buffer lock
  688.     //
  689.     ExReleaseFastMutex( &StoreMutex );
  690. }
  691. //----------------------------------------------------------------------
  692. //       H A S H   T A B L E   M A N A G E M E N T
  693. //----------------------------------------------------------------------
  694. //----------------------------------------------------------------------
  695. //
  696. // FilemonHashCleanup
  697. //
  698. // Called when we are unloading to free any memory that we have 
  699. // in our possession.
  700. //
  701. //----------------------------------------------------------------------
  702. VOID FilemonHashCleanup()
  703. {
  704.     PHASH_ENTRY hashEntry, nextEntry;
  705.     ULONG     i;
  706.     ExAcquireResourceExclusiveLite( &HashResource, TRUE );
  707.     //
  708.     // First, free the hash table entries
  709.     //
  710.     for( i = 0; i < NUMHASH; i++ ) {
  711.         hashEntry = HashTable[i];
  712.         while( hashEntry ) {
  713.             nextEntry = hashEntry->Next;
  714.             ExFreePool( hashEntry->FullPathName );
  715.             ExFreePool( hashEntry );
  716.             hashEntry = nextEntry;
  717.         }
  718.         HashTable[i] = NULL;
  719.     }
  720.     hashEntry = FreeHashList;
  721.     while( hashEntry ) {
  722.         nextEntry = hashEntry->Next;
  723.         ExFreePool( hashEntry );
  724.         hashEntry = nextEntry;
  725.     }
  726.     FreeHashList = NULL;
  727.     ExReleaseResourceLite( &HashResource );
  728. }
  729. //----------------------------------------------------------------------
  730. //
  731. // FilemonFreeHashEntry
  732. //
  733. // When we see a file close, we can free the string we had associated
  734. // with the fileobject being closed since we know it won't be used
  735. // again.
  736. //
  737. //----------------------------------------------------------------------
  738. VOID FilemonFreeHashEntry( PFILE_OBJECT fileObject )
  739. {
  740.     PHASH_ENTRY hashEntry, prevEntry;
  741.     ExAcquireResourceExclusiveLite( &HashResource, TRUE );
  742.     //
  743.     // Look-up the entry
  744.     //
  745.     hashEntry = HashTable[ HASHOBJECT( fileObject ) ];
  746.     prevEntry = NULL;
  747.     while( hashEntry && hashEntry->FileObject != fileObject ) {
  748.         prevEntry = hashEntry;
  749.         hashEntry = hashEntry->Next;
  750.     }
  751.  
  752.     //  
  753.     // If we fall of the hash list without finding what we're looking
  754.     // for, just return.
  755.     //
  756.     if( !hashEntry ) {
  757.         ExReleaseResourceLite( &HashResource );
  758.         return;
  759.     }
  760.     //
  761.     // Got it! Remove it from the list
  762.     //
  763.     if( prevEntry ) {
  764.         prevEntry->Next = hashEntry->Next;
  765.     } else {
  766.         HashTable[ HASHOBJECT( fileObject )] = hashEntry->Next;
  767.     }
  768.     //
  769.     // Free the memory associated with the name of the free entry.
  770.     //
  771.     ExFreePool( hashEntry->FullPathName );
  772.     hashEntry->Next = FreeHashList;
  773.     FreeHashList = hashEntry;
  774.     ExReleaseResourceLite( &HashResource );
  775. }
  776. //----------------------------------------------------------------------
  777. //       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
  778. //----------------------------------------------------------------------
  779. //----------------------------------------------------------------------
  780. //
  781. // FilemonFreeFilters
  782. //
  783. // Fress storage we allocated for filter strings.
  784. //
  785. //----------------------------------------------------------------------
  786. VOID FilemonFreeFilters()
  787. {
  788.     ULONG   i;
  789.     for( i = 0; i < NumIncludeFilters; i++ ) {
  790.         ExFreePool( IncludeFilters[i] );
  791.     }
  792.     for( i = 0; i < NumExcludeFilters; i++ ) {
  793.         ExFreePool( ExcludeFilters[i] );
  794.     }
  795.     NumIncludeFilters = 0;
  796.     NumExcludeFilters = 0;
  797. }
  798. //----------------------------------------------------------------------
  799. //
  800. // MakeFilterArray
  801. //
  802. // Takes a filter string and splits into components (a component
  803. // is seperated with a ';')
  804. //
  805. //----------------------------------------------------------------------
  806. VOID MakeFilterArray( PCHAR FilterString,
  807.                       PCHAR FilterArray[],
  808.                       PULONG NumFilters )
  809. {
  810.     PCHAR filterStart;
  811.     ULONG filterLength;
  812.     //
  813.     // Scan through the process filters
  814.     //
  815.     filterStart = FilterString;
  816.     while( *filterStart ) {
  817.         filterLength = 0;
  818.         while( filterStart[filterLength] &&
  819.                filterStart[filterLength] != ';' ) {
  820.             filterLength++;
  821.         }
  822.         //
  823.         // Ignore zero-length components
  824.         //
  825.         if( filterLength ) {
  826.             FilterArray[ *NumFilters ] = 
  827.                 ExAllocatePool( NonPagedPool, filterLength + 1  );
  828.             strncpy( FilterArray[ *NumFilters ],
  829.                      filterStart, filterLength );
  830.             FilterArray[ *NumFilters ][filterLength] = 0;
  831.             (*NumFilters)++;
  832.         }
  833.     
  834.         //
  835.         // Are we done?
  836.         //
  837.         if( !filterStart[filterLength] ) break;
  838.         //
  839.         // Move to the next component (skip over ';')
  840.         //
  841.         filterStart += filterLength + 1;
  842.     }
  843. }
  844. //----------------------------------------------------------------------
  845. //
  846. // FilemonUpdateFilters
  847. //
  848. // Takes a new filter specification and updates the filter
  849. // arrays with them.
  850. //
  851. //----------------------------------------------------------------------
  852. VOID FilemonUpdateFilters()
  853. {
  854.     //
  855.     // Free old filters (if any)
  856.     //
  857.     ExAcquireResourceExclusiveLite( &FilterResource, TRUE );
  858.     FilemonFreeFilters();
  859.     //
  860.     // Create new filter arrays
  861.     //
  862.     MakeFilterArray( FilterDef.includefilter,
  863.                      IncludeFilters, &NumIncludeFilters );
  864.     MakeFilterArray( FilterDef.excludefilter,
  865.                      ExcludeFilters, &NumExcludeFilters );
  866.     ExReleaseResourceLite( &FilterResource );
  867. }
  868. //----------------------------------------------------------------------
  869. //
  870. // ApplyNameFilter
  871. //
  872. // If the name matches the exclusion mask, we do not log it. Else if
  873. // it doesn't match the inclusion mask we do not log it. 
  874. //
  875. //----------------------------------------------------------------------
  876. FILTERSTATUS ApplyNameFilter( PCHAR fullname )
  877. {
  878.     ULONG i;
  879.     //
  880.     // If no GUI or no filename return FALSE
  881.     //
  882.     if ( !fullname ) return FILTERFAIL;
  883.     //   
  884.     // If it matches the exclusion string, do not log it
  885.     //
  886.     ExAcquireResourceSharedLite( &FilterResource, TRUE );
  887.     for( i = 0; i < NumExcludeFilters; i++ ) {
  888.         if( MatchWithPattern( ExcludeFilters[i], fullname ) ) {
  889.             ExReleaseResourceLite( &FilterResource );
  890.             return FILTERFAIL;
  891.         }
  892.     }
  893.  
  894.     //
  895.     // If it matches an include filter then log it
  896.     //
  897.     for( i = 0; i < NumIncludeFilters; i++ ) {
  898.         if( MatchWithPattern( IncludeFilters[i], fullname )) {
  899.             ExReleaseResourceLite( &FilterResource );
  900.             return FILTERPASS;
  901.         }
  902.     }
  903.     //
  904.     // It didn't match any include filters so don't log
  905.     //
  906.     ExReleaseResourceLite( &FilterResource );
  907.     return FILTERNOMATCH;
  908. }
  909. //----------------------------------------------------------------------
  910. //
  911. // FilemonQueryFileNameComplete
  912. //
  913. // This routine is used to handle I/O completion for our self-generated
  914. // IRP that is used to query a file's name.
  915. //
  916. //----------------------------------------------------------------------
  917. NTSTATUS FilemonQueryFileNameComplete(PDEVICE_OBJECT DeviceObject,
  918.                                     PIRP Irp,
  919.                                     PVOID Context)
  920. {
  921.     //
  922.     // Copy the status information back into the "user" IOSB.
  923.     //
  924.     *Irp->UserIosb = Irp->IoStatus;
  925.     if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
  926.         DbgPrint(("   ERROR ON IRP: %xn", Irp->IoStatus.Status ));
  927.     }
  928.     
  929.     //
  930.     // Set the user event - wakes up the mainline code doing this.
  931.     //
  932.     KeSetEvent(Irp->UserEvent, 0, FALSE);
  933.     
  934.     //
  935.     // Free the IRP now that we are done with it.
  936.     //
  937.     IoFreeIrp(Irp);
  938.     
  939.     //
  940.     // We return STATUS_MORE_PROCESSING_REQUIRED because this "magic" return value
  941.     // tells the I/O Manager that additional processing will be done by this driver
  942.     // to the IRP - in fact, it might (as it is in this case) already BE done - and
  943.     // the IRP cannot be completed.
  944.     //
  945.     return STATUS_MORE_PROCESSING_REQUIRED;
  946. }
  947. //----------------------------------------------------------------------
  948. //
  949. // FilemonQueryFileName
  950. //
  951. // This function retrieves the "standard" information for the
  952. // underlying file system, asking for the filename in particular.
  953. //
  954. //----------------------------------------------------------------------
  955. BOOLEAN FilemonQueryFileName( PDEVICE_OBJECT DeviceObject, 
  956.                               PFILE_OBJECT FileObject,
  957.                               PFILE_NAME_INFORMATION FileName, ULONG FileNameLength )
  958. {
  959.     PIRP irp;
  960.     KEVENT event;
  961.     IO_STATUS_BLOCK IoStatusBlock;
  962.     PIO_STACK_LOCATION ioStackLocation;
  963.     DbgPrint(("Getting file name for %xn", FileObject));
  964.     //
  965.     // Initialize the event
  966.     //
  967.     KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  968.     //
  969.     // Allocate an irp for this request.  This could also come from a 
  970.     // private pool, for instance.
  971.     //
  972.     irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  973.     if (!irp) {
  974.         //
  975.         // Failure!
  976.         //
  977.         return FALSE;
  978.     }
  979.   
  980.     //
  981.     // Build the IRP's main body
  982.     //  
  983.     irp->AssociatedIrp.SystemBuffer = FileName;
  984.     irp->UserEvent = &event;
  985.     irp->UserIosb = &IoStatusBlock;
  986.     irp->Tail.Overlay.Thread = PsGetCurrentThread();
  987.     irp->Tail.Overlay.OriginalFileObject = FileObject;
  988.     irp->RequestorMode = KernelMode;
  989.     irp->Flags = 0;
  990.     //
  991.     // Set up the I/O stack location.
  992.     //
  993.     ioStackLocation = IoGetNextIrpStackLocation(irp);
  994.     ioStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION;
  995.     ioStackLocation->DeviceObject = DeviceObject;
  996.     ioStackLocation->FileObject = FileObject;
  997.     ioStackLocation->Parameters.QueryFile.Length = FileNameLength;
  998.     ioStackLocation->Parameters.QueryFile.FileInformationClass = FileNameInformation;
  999.     //
  1000.     // Set the completion routine.
  1001.     //
  1002.     IoSetCompletionRoutine(irp, FilemonQueryFileNameComplete, 0, TRUE, TRUE, TRUE);
  1003.     //
  1004.     // Send it to the FSD
  1005.     //
  1006.     (void) IoCallDriver(DeviceObject, irp);
  1007.     //
  1008.     // Wait for the I/O
  1009.     //
  1010.     KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
  1011.     //
  1012.     // Done!
  1013.     //
  1014.     return( NT_SUCCESS( IoStatusBlock.Status ));
  1015. }
  1016. //----------------------------------------------------------------------
  1017. //
  1018. // FilemonGetFullPath
  1019. //
  1020. // Takes a fileobject and filename and returns a canonical path,
  1021. // nicely formatted, in fullpathname.
  1022. //
  1023. //----------------------------------------------------------------------
  1024. VOID FilemonGetFullPath( BOOLEAN createPath, 
  1025.                          PFILE_OBJECT fileObject, PHOOK_EXTENSION hookExt, 
  1026.                          PCHAR fullPathName )
  1027. {
  1028.     ULONG               pathLen, prefixLen, slashes;
  1029.     PCHAR               pathOffset, ptr;
  1030.     PFILE_OBJECT        relatedFileObject;
  1031.     PHASH_ENTRY         hashEntry, newEntry;
  1032.     ANSI_STRING         componentName;
  1033.     PFILE_NAME_INFORMATION fileNameInfo;
  1034.     UNICODE_STRING      fullUniName;
  1035.     //
  1036.     // Only do this if a GUI is active and filtering is on
  1037.     //
  1038.     if( !FilterOn || !hookExt || !fullPathName) {
  1039.      
  1040.         fullPathName[0] = 0;
  1041.         return;
  1042.     }
  1043.     //
  1044.     // First, lookup the object in the hash table to see if a name 
  1045.     // has already been generated for it
  1046.     //
  1047.     ExAcquireResourceSharedLite( &HashResource, TRUE );
  1048.     hashEntry = HashTable[ HASHOBJECT( fileObject ) ];
  1049.     while( hashEntry && hashEntry->FileObject != fileObject )  {
  1050.         hashEntry = hashEntry->Next;
  1051.     }
  1052.     //
  1053.     // Did we find an entry?
  1054.     //
  1055.     if( hashEntry ) {
  1056.         //
  1057.         // Yes, so get the name from the entry.
  1058.         //
  1059.         strcpy( fullPathName, hashEntry->FullPathName );
  1060.         ExReleaseResourceLite( &HashResource );
  1061.         return;
  1062.     }
  1063.     ExReleaseResourceLite( &HashResource );
  1064.     //
  1065.     // We didn't find the name in the hash table, so we have to attempt
  1066.     // to construct it from the file objects.  Note that we won't always
  1067.     // be able to successfully do this, because the file system may
  1068.     // deallocate the name in the file object at its discretion. 
  1069.     //
  1070.     //
  1071.     // Is it DASD (Volume) I/O?
  1072.     //
  1073.     if( !fileObject || !fileObject->FileName.Length || fileObject->FileName.Length > 2*MAXPATHLEN ) {
  1074.         if( hookExt->Type == NPFS )      strcpy( fullPathName, NAMED_PIPE_PREFIX );
  1075.         else if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );
  1076.         else                             sprintf( fullPathName, "%C: DASD", hookExt->LogicalDrive );
  1077.         return;
  1078.     }
  1079.     //
  1080.     // Calculate prefix length
  1081.     //
  1082.     switch( hookExt->Type ) {
  1083.     case NPFS: 
  1084.         prefixLen = NAMED_PIPE_PREFIX_LENGTH;
  1085.         break;
  1086.     case MSFS: 
  1087.         prefixLen = MAIL_SLOT_PREFIX_LENGTH;
  1088.         break;
  1089.     default: 
  1090.         if( fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
  1091.             prefixLen = 0;
  1092.         } else {
  1093.             prefixLen = 2; // "C:"
  1094.         }
  1095.         break;
  1096.     }
  1097.     //
  1098.     // Okay, now we have to construct the name. If we're in the Create path,
  1099.     // we can use the file objects. Otherwise we'll just query the file's name
  1100.     //
  1101.     if( createPath ) {
  1102.         //
  1103.         // Clear out any existing name association
  1104.         //
  1105.         FilemonFreeHashEntry( fileObject );        
  1106.     
  1107.         //
  1108.         // Create the full path name. First, calculate the length taking into 
  1109.         // account space for seperators and the leading drive letter plus ':'
  1110.         //
  1111.         pathLen = fileObject->FileName.Length/2 + prefixLen;
  1112.         relatedFileObject = fileObject->RelatedFileObject;
  1113.     
  1114.         //
  1115.         // Only look at related file object if this is a relative name
  1116.         //
  1117.         if( fileObject->FileName.Buffer[0] != L'\' )  {
  1118.             while( relatedFileObject ) {
  1119.         
  1120.                 // 
  1121.                 // If its too long, just stop.
  1122.                 // 
  1123.                 if( pathLen + relatedFileObject->FileName.Length/2+1 >= MAXPATHLEN ) {
  1124.  
  1125.                     break;
  1126.                 }
  1127.                 pathLen += relatedFileObject->FileName.Length/2+1;
  1128.                 relatedFileObject = relatedFileObject->RelatedFileObject;
  1129.             }
  1130.         }
  1131.         //
  1132.         // Add the drive letter first at the front of the name
  1133.         //
  1134.         if( hookExt->Type == NPFS )      strcpy( fullPathName, NAMED_PIPE_PREFIX );
  1135.         else if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );
  1136.         else if( fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
  1137.             sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
  1138.         }
  1139.     
  1140.         //
  1141.         // Now, start at the end and work back to the beginning of the path
  1142.         //
  1143.         fullPathName[ pathLen ] = 0;
  1144.         pathOffset = fullPathName + pathLen - fileObject->FileName.Length/2;
  1145.             
  1146.         RtlUnicodeStringToAnsiString( &componentName, &fileObject->FileName, TRUE );    
  1147.         strncpy( pathOffset, componentName.Buffer, componentName.Length + 1 );
  1148.         RtlFreeAnsiString( &componentName );
  1149.         relatedFileObject = fileObject->RelatedFileObject;
  1150.     
  1151.         if( fileObject->FileName.Buffer[0] != L'\' )  {
  1152.             while( relatedFileObject ) {
  1153.                 *(pathOffset - 1) = '\';
  1154.                 pathOffset -= relatedFileObject->FileName.Length/2 + 1;
  1155.                 //
  1156.                 // Bail when we've maxed the string.
  1157.                 //
  1158.                 if( pathOffset <= fullPathName ) {
  1159.                     break;
  1160.                 }
  1161.                 RtlUnicodeStringToAnsiString( &componentName, 
  1162.                                               &relatedFileObject->FileName, TRUE );
  1163.                 strncpy( pathOffset, componentName.Buffer,
  1164.                          componentName.Length );
  1165.                 RtlFreeAnsiString( &componentName );
  1166.                 relatedFileObject = relatedFileObject->RelatedFileObject;
  1167.             }
  1168.         }  
  1169.         //
  1170.         // If we added two '' to the front because there was a relative file object
  1171.         // that specified the root directory, remove one
  1172.         //
  1173.         if( pathLen > 3 && fullPathName[2] == '\' && fullPathName[3] == '\' )  {
  1174.         
  1175.             strcpy( fullPathName + 2, fullPathName + 3 );
  1176.         }
  1177.     } else {
  1178.         //
  1179.         // Ask the file system for the name of the file, which its required to be
  1180.         // able to provide for the Win32 filename query function. We could use the
  1181.         // undocumented ObQueryNameString, but then we'd have to worry about
  1182.         // re-entrancy issues, since that call generates the IRP that we create
  1183.         // manually here. Since we send the IRP to the FSD below us, we don't need
  1184.         // to worry about seeing the IRP in our dispatch entry point.
  1185.         //
  1186.         fileNameInfo = (PFILE_NAME_INFORMATION) ExAllocatePool( NonPagedPool, MAXPATHLEN*2 );
  1187.         if( fileNameInfo && 
  1188.             FilemonQueryFileName(hookExt->FileSystem, fileObject, fileNameInfo, 
  1189.                                  (MAXPATHLEN-3)*2 + 4 )) {
  1190.             fullUniName.Length = (SHORT) fileNameInfo->FileNameLength;
  1191.             fullUniName.Buffer = fileNameInfo->FileName;
  1192.             RtlUnicodeStringToAnsiString( &componentName, &fullUniName, TRUE ); 
  1193.             fullPathName[ componentName.Length + prefixLen ] = 0;
  1194.             if( hookExt->Type == NPFS ) {
  1195.                 strcpy( fullPathName, NAMED_PIPE_PREFIX );
  1196.                 memcpy( &fullPathName[NAMED_PIPE_PREFIX_LENGTH], componentName.Buffer, componentName.Length );
  1197.             } else if( hookExt->Type == MSFS ) {
  1198.                 strcpy( fullPathName, MAIL_SLOT_PREFIX );
  1199.                 memcpy( &fullPathName[MAIL_SLOT_PREFIX_LENGTH], componentName.Buffer, componentName.Length );
  1200.             } else if( fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
  1201.                 memcpy( fullPathName, componentName.Buffer, componentName.Length );
  1202.                 
  1203.             } else {
  1204.                 sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
  1205.                 memcpy( &fullPathName[2], componentName.Buffer, componentName.Length );
  1206.             }            
  1207.             RtlFreeAnsiString( &componentName );
  1208.         } else {
  1209.             if( hookExt->Type == NPFS ) {
  1210.                 strcpy( fullPathName, NAMED_PIPE_PREFIX "\???" );
  1211.             } else if( hookExt->Type == MSFS ) {
  1212.                 strcpy( fullPathName, MAIL_SLOT_PREFIX "\???" );
  1213.             } else {
  1214.                 sprintf( fullPathName, "%C: ???", hookExt->LogicalDrive );
  1215.             }
  1216.         }
  1217.         ExFreePool( fileNameInfo );
  1218.         pathLen = strlen( fullPathName );
  1219.     }
  1220.     //
  1221.     // Network redirector names already specify a share name, that we have to strip
  1222.     // 
  1223.     //     X:computersharerealpath
  1224.     //
  1225.     // And we want to present:
  1226.     //
  1227.     //     X:realpath
  1228.     //
  1229.     // to the user.
  1230.     //
  1231.     if( fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM ) {
  1232.         //
  1233.         // Skip the share name 
  1234.         //
  1235.         if( fullPathName[2] == ':' ) {
  1236.             strcpy( fullPathName, &fullPathName[1] );
  1237.             
  1238.             slashes = 0;
  1239.             ptr = &fullPathName[3];
  1240.             while( *ptr && slashes != 2 ) {
  1241.                 if( *ptr == '\' ) slashes++;
  1242.                 ptr++;
  1243.             }
  1244.             strcpy( &fullPathName[3], ptr );
  1245.         } else {
  1246.             //
  1247.             // Its a UNC path
  1248.             //
  1249.         }
  1250.     }
  1251.     // 
  1252.     // Now that we have a name associated with the file object, put the
  1253.     // association in a hash table
  1254.     //
  1255.     ExAcquireResourceExclusiveLite( &HashResource, TRUE );
  1256.     //
  1257.     // Allocate a hash entry
  1258.     //
  1259.     if( FreeHashList ) {
  1260.         
  1261.         newEntry = FreeHashList;
  1262.         FreeHashList = newEntry->Next;
  1263.     } else {
  1264.         newEntry = ExAllocatePool( NonPagedPool, sizeof(HASH_ENTRY ));
  1265.     }
  1266.     //
  1267.     // If no memory for a new entry, oh well.
  1268.     //
  1269.     if( newEntry ) {
  1270.         //
  1271.         // Fill in the new entry and put it in the hash table
  1272.         //
  1273.         newEntry->FileObject  = fileObject;
  1274.         newEntry->FullPathName = ExAllocatePool( NonPagedPool, strlen(fullPathName)+1);
  1275.         //
  1276.         // Make sure there was memory for the name
  1277.         //
  1278.         if( !newEntry->FullPathName ) {
  1279.             newEntry->Next = FreeHashList;
  1280.             FreeHashList   = newEntry;
  1281.         } else {
  1282.             strcpy( newEntry->FullPathName, fullPathName );
  1283.             newEntry->Next = HashTable[ HASHOBJECT(fileObject) ];
  1284.             HashTable[ HASHOBJECT(fileObject) ] = newEntry;
  1285.         }
  1286.     }
  1287.     ExReleaseResourceLite( &HashResource );
  1288. }
  1289. //----------------------------------------------------------------------
  1290. //
  1291. // FilemonGetProcessNameOffset
  1292. //
  1293. // In an effort to remain version-independent, rather than using a
  1294. // hard-coded into the KPEB (Kernel Process Environment Block), we
  1295. // scan the KPEB looking for the name, which should match that
  1296. // of the system process. This is because we are in the system process'
  1297. // context in DriverEntry, where this is called.
  1298. //
  1299. //----------------------------------------------------------------------
  1300. ULONG FilemonGetProcessNameOffset()
  1301. {
  1302.     PEPROCESS       curproc;
  1303.     int             i;
  1304.     curproc = PsGetCurrentProcess();
  1305.     //
  1306.     // Scan for 12KB, hoping the KPEB never grows that big!
  1307.     //
  1308.     for( i = 0; i < 3*PAGE_SIZE; i++ ) {
  1309.      
  1310.         if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) )) {
  1311.             return i;
  1312.         }
  1313.     }
  1314.     //
  1315.     // Name not found - oh, well
  1316.     //
  1317.     return 0;
  1318. }
  1319. //----------------------------------------------------------------------
  1320. //
  1321. // FilemonGetProcess
  1322. //
  1323. // Uses undocumented data structure offsets to obtain the name of the
  1324. // currently executing process.
  1325. //
  1326. //----------------------------------------------------------------------
  1327. FILTERSTATUS FilemonGetProcess( PCHAR Name )
  1328. {
  1329.     PEPROCESS       curproc;
  1330.     char            *nameptr;
  1331.     ULONG           i;
  1332.     //
  1333.     // We only do this if we determined the process name offset
  1334.     //
  1335.     if( ProcessNameOffset ) {
  1336.       
  1337.         //
  1338.         // Get a pointer to the current process block
  1339.         //
  1340.         curproc = PsGetCurrentProcess();
  1341.         //
  1342.         // Dig into it to extract the name 
  1343.         //
  1344.         nameptr   = (PCHAR) curproc + ProcessNameOffset;
  1345.          
  1346.         strncpy( Name, nameptr, NT_PROCNAMELEN );
  1347.         //
  1348.         // Terminate in case process name overflowed
  1349.         //
  1350.         Name[NT_PROCNAMELEN] = 0;
  1351.     } else {
  1352.         strcpy( Name, "???" );
  1353.     }
  1354.     //
  1355.     // Apply process name filters
  1356.     //
  1357.     ExAcquireResourceSharedLite( &FilterResource, TRUE );
  1358.     for( i = 0; i < NumExcludeFilters; i++ ) {
  1359.         if( MatchWithPattern( ExcludeFilters[i], Name )) {
  1360.             ExReleaseResourceLite( &FilterResource );
  1361.             return FILTERFAIL;
  1362.         }
  1363.     }
  1364.     for( i = 0; i < NumIncludeFilters; i++ ) {
  1365.         if( MatchWithPattern( IncludeFilters[i], Name ) ) {
  1366.             ExReleaseResourceLite( &FilterResource );
  1367.             return FILTERPASS;
  1368.         }
  1369.     }
  1370.     ExReleaseResourceLite( &FilterResource );
  1371.     return FILTERNOMATCH;
  1372. }
  1373. //----------------------------------------------------------------------
  1374. //
  1375. // ApplyFilters
  1376. //
  1377. // Gets the process name and then performs filtering logic.
  1378. //
  1379. //----------------------------------------------------------------------
  1380. BOOLEAN ApplyFilters( PCHAR ProcessName, PCHAR FullName )
  1381. {
  1382.     FILTERSTATUS   filterStatus, nameFilterStatus;
  1383.     //
  1384.     // If there's no name, bail
  1385.     //
  1386.     if( !ProcessName || !FullName ) return FALSE;
  1387.     //
  1388.     // Try the process filter
  1389.     //
  1390.     filterStatus = FilemonGetProcess( ProcessName );
  1391.     if( filterStatus == FILTERPASS ||
  1392.         filterStatus == FILTERNOMATCH ) {
  1393.         //
  1394.         // Try the path filter
  1395.         //
  1396.         nameFilterStatus = ApplyNameFilter( FullName );
  1397.         if( (filterStatus == FILTERPASS && nameFilterStatus != FILTERFAIL) ||
  1398.             nameFilterStatus == FILTERPASS ) {
  1399.             
  1400.             return TRUE;
  1401.         }
  1402.     } 
  1403.     return FALSE;
  1404. }
  1405. //----------------------------------------------------------------------
  1406. //          H O O K / U N H O O K   R O U T I N E S
  1407. //----------------------------------------------------------------------
  1408. //----------------------------------------------------------------------
  1409. //
  1410. // HookSpecialFs
  1411. //
  1412. // Hook the named pipe or mail slot file system.
  1413. //
  1414. //----------------------------------------------------------------------
  1415. BOOLEAN HookSpecialFs( IN PDRIVER_OBJECT DriverObject, 
  1416.                        FILE_SYSTEM_TYPE FsType )
  1417. {
  1418.     IO_STATUS_BLOCK     ioStatus;
  1419.     HANDLE              ntFileHandle;   
  1420.     OBJECT_ATTRIBUTES   objectAttributes;
  1421.     PDEVICE_OBJECT      fileSysDevice;
  1422.     PDEVICE_OBJECT      hookDevice;
  1423.     UNICODE_STRING      fileNameUnicodeString;
  1424.     WCHAR               npfsFilename[] = L"\Device\NamedPipe";
  1425.     WCHAR               msfsFilename[] = L"\Device\MailSlot";
  1426.     NTSTATUS            ntStatus;
  1427.     ULONG               i;
  1428.     PFILE_OBJECT        fileObject;
  1429.     PHOOK_EXTENSION     hookExtension;
  1430.     //
  1431.     // If we've already hooked it, just return success
  1432.     //
  1433.     if( FsType == NPFS && NamedPipeHookDevice ) return TRUE;
  1434.     if( FsType == MSFS && MailSlotHookDevice ) return TRUE;
  1435.     
  1436.     //
  1437.     // We have to figure out what device to hook - first open the volume's 
  1438.     // root directory
  1439.     //
  1440.     if( FsType == NPFS ) RtlInitUnicodeString( &fileNameUnicodeString, npfsFilename );
  1441.     else                 RtlInitUnicodeString( &fileNameUnicodeString, msfsFilename );
  1442.     InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString, 
  1443.                                 OBJ_CASE_INSENSITIVE, NULL, NULL );
  1444.     ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS, 
  1445.                              &objectAttributes, &ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, 
  1446.                              FILE_OPEN, 
  1447.                              FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, 
  1448.                              NULL, 0 );
  1449.     if( !NT_SUCCESS( ntStatus ) ) {
  1450.         DbgPrint(("Filemon: Could not open %sn", FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));
  1451.         return FALSE;
  1452.     }
  1453.     DbgPrint(("Filemon:  opened the root directory!!! handle: %xn", ntFileHandle));   
  1454.     //
  1455.     // Got the file handle, so now look-up the file-object it refers to
  1456.     //
  1457.     ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA, 
  1458.                                           NULL, KernelMode, &fileObject, NULL );
  1459.     if( !NT_SUCCESS( ntStatus )) {
  1460.         DbgPrint(("Filemon: Could not get fileobject from %s handle: %xn", 
  1461.                   FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));
  1462.         ZwClose( ntFileHandle );
  1463.         return FALSE;
  1464.     }
  1465.     //  
  1466.     // Next, find out what device is associated with the file object by getting its related
  1467.     // device object
  1468.     //
  1469.     fileSysDevice = IoGetRelatedDeviceObject( fileObject );
  1470.     if ( ! fileSysDevice ) {
  1471.         DbgPrint(("Filemon: Could not get related device object for %s: %xn", 
  1472.                   FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));
  1473.         ObDereferenceObject( fileObject );
  1474.         ZwClose( ntFileHandle );
  1475.         return FALSE;
  1476.     }
  1477.     //
  1478.     // The file system's device hasn't been hooked already, so make a hooking device
  1479.     //  object that will be attached to it.
  1480.     //
  1481.     ntStatus = IoCreateDevice( DriverObject,
  1482.                                sizeof(HOOK_EXTENSION),
  1483.                                NULL,
  1484.                                fileSysDevice->DeviceType,
  1485.                                0,
  1486.                                FALSE,
  1487.                                &hookDevice );
  1488.     if ( !NT_SUCCESS(ntStatus) ) {
  1489.         DbgPrint(("Filemon: failed to create associated device %s: %xn", 
  1490.                   FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));
  1491.         ObDereferenceObject( fileObject );
  1492.         ZwClose( ntFileHandle );
  1493.         return FALSE;
  1494.     }
  1495.     //
  1496.     // Clear the device's init flag as per NT DDK KB article on creating device 
  1497.     // objects from a dispatch routine
  1498.     //
  1499.     hookDevice->Flags &= ~DO_DEVICE_INITIALIZING;
  1500.     //
  1501.     // Setup the device extensions. The drive letter and file system object are stored
  1502.     // in the extension.
  1503.     //
  1504.     hookExtension = hookDevice->DeviceExtension;
  1505.     hookExtension->LogicalDrive = '\';
  1506.     hookExtension->FileSystem   = fileSysDevice;
  1507.     hookExtension->Type = FsType;
  1508.     //
  1509.     // Finally, attach to the device. The second we're successfully attached, we may 
  1510.     // start receiving IRPs targetted at the device we've hooked.
  1511.     //
  1512.     ntStatus = IoAttachDeviceByPointer( hookDevice, fileSysDevice );
  1513.     if ( !NT_SUCCESS(ntStatus) )  {
  1514.         //
  1515.         // Couldn' attach for some reason
  1516.         //
  1517.         DbgPrint(("Filemon: Connect with Filesystem failed: %s (%x) =>%xn", 
  1518.                   FsType == NPFS ? "NPFS" : "MSFS", fileSysDevice, ntStatus ));
  1519.         //
  1520.         // Derefence the object and get out
  1521.         //
  1522.         ObDereferenceObject( fileObject );
  1523.         ZwClose( ntFileHandle );
  1524.         return FALSE;
  1525.     } else {
  1526.         DbgPrint(("Filemon: Successfully connected to Filesystem device %sn",
  1527.                   FsType == NPFS ? "NPFS" : "MSFS" ));
  1528.     }
  1529.     
  1530.     //
  1531.     // Close the file and update the hooked drive list by entering a
  1532.     // pointer to the hook device object in it.
  1533.     //
  1534.     ObDereferenceObject( fileObject );
  1535.     ZwClose( ntFileHandle );
  1536.     if( FsType == NPFS ) NamedPipeHookDevice = hookDevice;
  1537.     else                 MailSlotHookDevice  = hookDevice;
  1538.     return TRUE;
  1539. }
  1540. //----------------------------------------------------------------------
  1541. //
  1542. // UnhookSpecialFs
  1543. //
  1544. // Unhook the named pipe file or mail slot system.
  1545. //
  1546. //----------------------------------------------------------------------
  1547. VOID UnhookSpecialFs( FILE_SYSTEM_TYPE FsType )
  1548. {
  1549.     PHOOK_EXTENSION   hookExt;
  1550.     if( FsType == NPFS && NamedPipeHookDevice ) {
  1551.         
  1552.         hookExt = NamedPipeHookDevice->DeviceExtension;
  1553.         IoDetachDevice( hookExt->FileSystem );
  1554.         IoDeleteDevice( NamedPipeHookDevice );
  1555.         NamedPipeHookDevice = NULL;
  1556.     } else if( FsType == MSFS && MailSlotHookDevice ) {
  1557.         hookExt = MailSlotHookDevice->DeviceExtension;
  1558.         IoDetachDevice( hookExt->FileSystem );
  1559.         IoDeleteDevice( MailSlotHookDevice );
  1560.         MailSlotHookDevice = NULL;
  1561.     }
  1562. }
  1563. //----------------------------------------------------------------------
  1564. //
  1565. // HookDrive
  1566. //
  1567. // Hook the drive specified by determining which device object to 
  1568. // attach to. The algorithm used here is similar to the one used
  1569. // internally by NT to determine which device object a file system request
  1570. // is directed at.
  1571. //
  1572. //----------------------------------------------------------------------
  1573. BOOLEAN HookDrive( IN char Drive, IN PDRIVER_OBJECT DriverObject )
  1574. {
  1575.     IO_STATUS_BLOCK     ioStatus;
  1576.     HANDLE              ntFileHandle;   
  1577.     OBJECT_ATTRIBUTES   objectAttributes;
  1578.     PDEVICE_OBJECT      fileSysDevice;
  1579.     PDEVICE_OBJECT      hookDevice;
  1580.     UNICODE_STRING      fileNameUnicodeString;
  1581.     WCHAR               filename[] = L"\DosDevices\A:\";
  1582.     NTSTATUS            ntStatus;
  1583.     ULONG               i;
  1584.     PFILE_OBJECT        fileObject;
  1585.     PHOOK_EXTENSION     hookExtension;
  1586.     
  1587.     //
  1588.     // Translate the drive letter to a 0-based integer
  1589.     //
  1590.     if ( Drive >= 'a' && Drive <= 'z' ) {
  1591.         Drive -= 'a';
  1592.     } else {
  1593.         Drive -= 'A';
  1594.     }
  1595.     //
  1596.     // Is it a legal drive letter?
  1597.     //
  1598.     if ( (unsigned char) Drive >= 26 )  {
  1599.         return FALSE;
  1600.     }
  1601.     //
  1602.     // Has this drive already been hooked?
  1603.     //
  1604.     if ( LDriveDevices[Drive] == NULL )  {
  1605.         //
  1606.         // Frob the name to make it refer to the drive specified in the input 
  1607.         // parameter.
  1608.         //
  1609.         filename[12] = 'A'+Drive;
  1610.         //
  1611.         // We have to figure out what device to hook - first open the volume's 
  1612.         // root directory
  1613.         //
  1614.         RtlInitUnicodeString( &fileNameUnicodeString, filename );
  1615.         InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString, 
  1616.                                     OBJ_CASE_INSENSITIVE, NULL, NULL );
  1617.         ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS, 
  1618.                                  &objectAttributes, &ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, 
  1619.                                  FILE_OPEN, 
  1620.                                  FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, 
  1621.                                  NULL, 0 );
  1622.         if( !NT_SUCCESS( ntStatus ) ) {
  1623.             DbgPrint(("Filemon: Could not open drive %c: %xn", 'A'+Drive, ntStatus ));
  1624.             return FALSE;
  1625.         }
  1626.         DbgPrint(("Filemon:  opened the root directory!!! handle: %xn", ntFileHandle));   
  1627.         //
  1628.         // Got the file handle, so now look-up the file-object it refers to
  1629.         //
  1630.         ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA, 
  1631.                                               NULL, KernelMode, &fileObject, NULL );
  1632.         if( !NT_SUCCESS( ntStatus )) {
  1633.             DbgPrint(("Filemon: Could not get fileobject from handle: %cn", 'A'+Drive ));
  1634.             ZwClose( ntFileHandle );
  1635.             return FALSE;
  1636.         }
  1637.         //  
  1638.         // Next, find out what device is associated with the file object by getting its related
  1639.         // device object
  1640.         //
  1641.         fileSysDevice = IoGetRelatedDeviceObject( fileObject );
  1642.         if ( ! fileSysDevice ) {
  1643.             DbgPrint(("Filemon: Could not get related device object: %cn", 'A'+Drive ));
  1644.             ObDereferenceObject( fileObject );
  1645.             ZwClose( ntFileHandle );
  1646.             return FALSE;
  1647.         }
  1648.         //  
  1649.         // Check the device list to see if we've already attached to this particular device. 
  1650.         // This can happen when more than one drive letter is being handled by the same network
  1651.         // redirecter
  1652.         //  
  1653.         for( i = 0; i < 26; i++ ) {
  1654.             if( LDriveDevices[i] == fileSysDevice ) {
  1655.                 //
  1656.                 // If we're already watching it, associate this drive letter
  1657.                 // with the others that are handled by the same network driver. This
  1658.                 // enables us to intelligently update the hooking menus when the user
  1659.                 // specifies that one of the group should not be watched -we mark all
  1660.                 // of the related drives as unwatched as well
  1661.                 //
  1662.                 ObDereferenceObject( fileObject );
  1663.                 ZwClose( ntFileHandle );
  1664.                 LDriveMap[ Drive ]     = LDriveMap[i];
  1665.                 LDriveDevices[ Drive ] = fileSysDevice;
  1666.                 return TRUE;
  1667.             }
  1668.         }
  1669.         //
  1670.         // The file system's device hasn't been hooked already, so make a hooking device
  1671.         //  object that will be attached to it.
  1672.         //
  1673.         ntStatus = IoCreateDevice( DriverObject,
  1674.                                    sizeof(HOOK_EXTENSION),
  1675.                                    NULL,
  1676.                                    fileSysDevice->DeviceType,
  1677.                                    0,
  1678.                                    FALSE,
  1679.                                    &hookDevice );
  1680.         if ( !NT_SUCCESS(ntStatus) ) {
  1681.             DbgPrint(("Filemon: failed to create associated device: %cn", 'A'+Drive ));   
  1682.             ObDereferenceObject( fileObject );
  1683.             ZwClose( ntFileHandle );
  1684.             return FALSE;
  1685.         }
  1686.         //
  1687.         // Clear the device's init flag as per NT DDK KB article on creating device 
  1688.         // objects from a dispatch routine
  1689.         //
  1690.         hookDevice->Flags &= ~DO_DEVICE_INITIALIZING;
  1691.         //
  1692.         // Setup the device extensions. The drive letter and file system object are stored
  1693.         // in the extension.
  1694.         //
  1695.         hookExtension = hookDevice->DeviceExtension;
  1696.         hookExtension->LogicalDrive = 'A'+Drive;
  1697.         hookExtension->FileSystem   = fileSysDevice;
  1698.         hookExtension->Type         = STANDARD;
  1699.         //
  1700.         // Finally, attach to the device. The second we're successfully attached, we may 
  1701.         // start receiving IRPs targetted at the device we've hooked.
  1702.         //
  1703.         ntStatus = IoAttachDeviceByPointer( hookDevice, fileSysDevice );
  1704.         if ( !NT_SUCCESS(ntStatus) )  {
  1705.             //
  1706.             // Couldn' attach for some reason
  1707.             //
  1708.             DbgPrint(("Filemon: Connect with Filesystem failed: %c (%x) =>%xn", 
  1709.                       'A'+Drive, fileSysDevice, ntStatus ));
  1710.             //
  1711.             // Derefence the object and get out
  1712.             //
  1713.             ObDereferenceObject( fileObject );
  1714.             ZwClose( ntFileHandle );
  1715.             return FALSE;
  1716.         } else {
  1717.             // 
  1718.             // Make a new drive group for the device,l if it does not have one 
  1719.             // already
  1720.             // 
  1721.             DbgPrint(("Filemon: Successfully connected to Filesystem device %cn", 'A'+Drive ));
  1722.             if( !LDriveMap[ Drive ] ) {
  1723.                 LDriveMap[ Drive ] = ++LDriveGroup;
  1724.             }
  1725.         }
  1726.     
  1727.         //
  1728.         // Close the file and update the hooked drive list by entering a
  1729.         // pointer to the hook device object in it.
  1730.         //
  1731.         ObDereferenceObject( fileObject );
  1732.         ZwClose( ntFileHandle );
  1733.         LDriveDevices[Drive] = hookDevice;
  1734.     }
  1735.     return TRUE;
  1736. }
  1737. //----------------------------------------------------------------------
  1738. //
  1739. // UnhookDrive
  1740. //
  1741. // Unhook a previously hooked drive.
  1742. //
  1743. //----------------------------------------------------------------------
  1744. BOOLEAN UnhookDrive( IN char Drive )
  1745. {
  1746.     PHOOK_EXTENSION hookExt;
  1747.     //
  1748.     // Translate the drive letter to a 0-based integer
  1749.     //
  1750.     if ( Drive >= 'a' && Drive <= 'z' ) {
  1751.         Drive -= 'a';
  1752.     } else {
  1753.         Drive -= 'A';
  1754.     }
  1755.     //
  1756.     // If the drive has been hooked, unhook it and delete the hook
  1757.     // device object
  1758.     //
  1759.     if ( LDriveDevices[Drive] )  {
  1760.         hookExt = LDriveDevices[Drive]->DeviceExtension;
  1761.         IoDetachDevice( hookExt->FileSystem );
  1762.         IoDeleteDevice( LDriveDevices[Drive] );
  1763.         LDriveDevices[Drive] = NULL;
  1764.     }
  1765.     return TRUE;
  1766. }
  1767. //----------------------------------------------------------------------
  1768. //
  1769. // HookDriveSet
  1770. //
  1771. // Hook/Unhook a set of drives specified by user. Return the set 
  1772. // that is currently hooked.
  1773. //
  1774. //----------------------------------------------------------------------
  1775. ULONG HookDriveSet( IN ULONG DriveSet, IN PDRIVER_OBJECT DriverObject )
  1776. {
  1777.     ULONG drive, i;
  1778.     ULONG bit;
  1779.     //
  1780.     // Scan the drive table, looking for hits on the DriveSet bitmask
  1781.     //
  1782.     for ( drive = 0; drive < 26; ++drive )  {
  1783.         bit = 1 << drive;
  1784.         //
  1785.         // Are we suppoed to hook this drive?
  1786.         //
  1787.         if ( bit & DriveSet )  {
  1788.             //
  1789.             // Try to hook drive 
  1790.             //
  1791.             if ( ! HookDrive( (char)('A'+drive), DriverObject ) ) {
  1792.              
  1793.                 //
  1794.                 // Remove from drive set if can't be hooked
  1795.                 //
  1796.                 DriveSet &= ~bit;
  1797.             } else {
  1798.                 //
  1799.                 // hook drives in same drive group      
  1800.                 //
  1801.                 for( i = 0; i < 26; i++ ) {
  1802.                     if( LDriveMap[i] == LDriveMap[ drive ] &&
  1803.                         !LDriveDevices[i] ) {
  1804.                         DriveSet |= ( 1<<i );
  1805.                         LDriveDevices[i] = LDriveDevices[drive];
  1806.                     }
  1807.                 }
  1808.             }
  1809.         } else {
  1810.             //
  1811.             // Try to unhook drive 
  1812.             //
  1813.             if ( ! UnhookDrive( (char)('A'+drive) ) )  {
  1814.                 //
  1815.                 // Unhook failed, leave the drive marked as hooked
  1816.                 //
  1817.                 DriveSet |= bit;    
  1818.             } else {
  1819.                 // 
  1820.                 // Unhook worked. Mark all drives in same group as
  1821.                 // unhooked
  1822.                 //
  1823.                 for( i = 0; i< 26; i++ ) {
  1824.                     if( LDriveMap[i] == LDriveMap[ drive ] && 
  1825.                         LDriveDevices[i] ) {
  1826.                         DriveSet &= ~(1 << i); 
  1827.                         LDriveDevices[i] = NULL;
  1828.                     }
  1829.                 }
  1830.             }
  1831.         }
  1832.     }
  1833.     //
  1834.     // Return set of drives currently hooked
  1835.     //
  1836.     return DriveSet;
  1837. }
  1838. //----------------------------------------------------------------------
  1839. //
  1840. // ControlCodeString
  1841. //
  1842. // Takes a control code and sees if we know what it is.
  1843. //
  1844. //----------------------------------------------------------------------
  1845. PCHAR ControlCodeString( PIO_STACK_LOCATION IrpSp,
  1846.                          ULONG ControlCode, PCHAR Buffer, 
  1847.                          PCHAR Other )
  1848. {
  1849.     Other[0] = 0;
  1850.     switch( ControlCode ) {
  1851.     case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  1852.         strcpy( Buffer, "FSCTL_REQUEST_OPLOCK_LEVEL_1" );
  1853.         break;
  1854.     case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  1855.         strcpy( Buffer, "FSCTL_REQUEST_OPLOCK_LEVEL_2" );
  1856.         break;
  1857.     case FSCTL_REQUEST_BATCH_OPLOCK:
  1858.         strcpy( Buffer, "FSCTL_REQUEST_BATCH_OPLOCK" );
  1859.         break;        
  1860.     case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  1861.         strcpy( Buffer, "FSCTL_OPLOCK_BREAK_ACKNOWLEDGE" );
  1862.         break;
  1863.     case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
  1864.         strcpy( Buffer, "FSCTL_OPBATCH_ACK_CLOSE_PENDING" );
  1865.         break;
  1866.     case FSCTL_OPLOCK_BREAK_NOTIFY:
  1867.         strcpy( Buffer, "FSCTL_OPLOCK_BREAK_NOTIFY" );
  1868.         break;
  1869.     case FSCTL_LOCK_VOLUME:
  1870.         strcpy( Buffer, "FSCTL_LOCK_VOLUME" );
  1871.         break;
  1872.     case FSCTL_UNLOCK_VOLUME:
  1873.         strcpy( Buffer, "FSCTL_UNLOCK_VOLUME" );
  1874.         break;
  1875.     case FSCTL_DISMOUNT_VOLUME:
  1876.         strcpy( Buffer, "FSCTL_DISMOUNT_VOLUME" );
  1877.         break;
  1878.     case FSCTL_IS_VOLUME_MOUNTED:
  1879.         strcpy( Buffer, "FSCTL_IS_VOLUME_MOUNTED" );
  1880.         break;
  1881.     case FSCTL_IS_PATHNAME_VALID:
  1882.         strcpy( Buffer, "FSCTL_IS_PATHNAME_VALID" );
  1883.         break;
  1884.     case FSCTL_MARK_VOLUME_DIRTY:
  1885.         strcpy( Buffer, "FSCTL_MARK_VOLUME_DIRTY" );
  1886.         break;
  1887.     case FSCTL_QUERY_RETRIEVAL_POINTERS:
  1888.         strcpy( Buffer, "FSCTL_QUERY_RETRIEVAL_POINTERS" );
  1889.         break;
  1890.     case FSCTL_GET_COMPRESSION:
  1891.         strcpy( Buffer, "FSCTL_GET_COMPRESSION" );
  1892.         break;
  1893.     case FSCTL_SET_COMPRESSION:
  1894.         strcpy( Buffer, "FSCTL_SET_COMPRESSION" );
  1895.         break;
  1896.     case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  1897.         strcpy( Buffer, "FSCTL_OPLOCK_BREAK_ACK_NO_2" );
  1898.         break;
  1899.     case FSCTL_QUERY_FAT_BPB:
  1900.         strcpy( Buffer, "FSCTL_QUERY_FAT_BPB" );
  1901.         break;
  1902.     case FSCTL_REQUEST_FILTER_OPLOCK:
  1903.         strcpy( Buffer, "FSCTL_REQUEST_FILTER_OPLOCK" );
  1904.         break;
  1905.     case FSCTL_FILESYSTEM_GET_STATISTICS:
  1906.         strcpy( Buffer, "FSCTL_FILESYSTEM_GET_STATISTICS" );
  1907.         break;
  1908.     case FSCTL_GET_NTFS_VOLUME_DATA:
  1909.         strcpy( Buffer, "FSCTL_GET_NTFS_VOLUME_DATA" );
  1910.         break;
  1911.     case FSCTL_GET_NTFS_FILE_RECORD:
  1912.         strcpy( Buffer, "FSCTL_GET_NTFS_FILE_RECORD" );
  1913.         break;
  1914.     case FSCTL_GET_VOLUME_BITMAP:
  1915.         strcpy( Buffer, "FSCTL_GET_VOLUME_BITMAP" );
  1916.         break;
  1917.     case FSCTL_GET_RETRIEVAL_POINTERS:
  1918.         strcpy( Buffer, "FSCTL_GET_RETRIEVAL_POINTERS" );
  1919.         break;
  1920.     case FSCTL_MOVE_FILE:
  1921.         strcpy( Buffer, "FSCTL_MOVE_FILE" );
  1922.         break;
  1923.     case FSCTL_IS_VOLUME_DIRTY:
  1924.         strcpy( Buffer, "FSCTL_IS_VOLUME_DIRTY" );
  1925.         break;
  1926.     case FSCTL_ALLOW_EXTENDED_DASD_IO:
  1927.         strcpy( Buffer, "FSCTL_ALLOW_EXTENDED_DASD_IO" );
  1928.         break;
  1929.         //
  1930.         // *** new to Win2K (NT 5.0)
  1931.         //
  1932.     case FSCTL_READ_PROPERTY_DATA:
  1933.         strcpy( Buffer, "FSCTL_READ_PROPERTY_DATA" );
  1934.         break;
  1935.     case FSCTL_WRITE_PROPERTY_DATA:
  1936.         strcpy( Buffer, "FSCTL_WRITE_PROPERTY_DATA" );
  1937.         break;
  1938.     case FSCTL_FIND_FILES_BY_SID:
  1939.         strcpy( Buffer, "FSCTL_FIND_FILES_BY_SID" );
  1940.         break;
  1941.     case FSCTL_DUMP_PROPERTY_DATA:
  1942.         strcpy( Buffer, "FSCTL_DUMP_PROPERTY_DATA" );
  1943.         break;
  1944.     case FSCTL_SET_OBJECT_ID:
  1945.         strcpy( Buffer, "FSCTL_SET_OBJECT_ID" );
  1946.         break;
  1947.     case FSCTL_GET_OBJECT_ID:
  1948.         strcpy( Buffer, "FSCTL_GET_OBJECT_ID" );
  1949.         break;
  1950.     case FSCTL_DELETE_OBJECT_ID:
  1951.         strcpy( Buffer, "FSCTL_DELETE_OBJECT_ID" );
  1952.         break;
  1953.     case FSCTL_SET_REPARSE_POINT:
  1954.         strcpy( Buffer, "FSCTL_SET_REPARSE_POINT" );
  1955.         break;
  1956.     case FSCTL_GET_REPARSE_POINT:
  1957.         strcpy( Buffer, "FSCTL_GET_REPARSE_POINT" );
  1958.         break;
  1959.     case FSCTL_DELETE_REPARSE_POINT:
  1960.         strcpy( Buffer, "FSCTL_DELETE_REPARSE_POINT" );
  1961.         break;
  1962.     case FSCTL_ENUM_USN_DATA:
  1963.         strcpy( Buffer, "FSCTL_ENUM_USN_DATA" );
  1964.         break;
  1965.     case FSCTL_SECURITY_ID_CHECK:
  1966.         strcpy( Buffer, "FSCTL_SECURITY_ID_CHECK" );
  1967.         break;
  1968.     case FSCTL_READ_USN_JOURNAL:
  1969.         strcpy( Buffer, "FSCTL_READ_USN_JOURNAL" );
  1970.         break;
  1971.     case FSCTL_SET_OBJECT_ID_EXTENDED:
  1972.         strcpy( Buffer, "FSCTL_SET_OBJECT_ID_EXTENDED" );
  1973.         break;
  1974.     case FSCTL_CREATE_OR_GET_OBJECT_ID:
  1975.         strcpy( Buffer, "FSCTL_CREATE_OR_GET_OBJECT_ID" );
  1976.         break;
  1977.     case FSCTL_SET_SPARSE:
  1978.         strcpy( Buffer, "FSCTL_SET_SPARSE" );
  1979.         break;
  1980.     case FSCTL_SET_ZERO_DATA:
  1981.         strcpy( Buffer, "FSCTL_SET_ZERO_DATA" );
  1982.         break;
  1983.     case FSCTL_QUERY_ALLOCATED_RANGES:
  1984.         strcpy( Buffer, "FSCTL_QUERY_ALLOCATED_RANGES" );
  1985.         break;
  1986.     case FSCTL_ENABLE_UPGRADE:
  1987.         strcpy( Buffer, "FSCTL_ENABLE_UPGRADE" );
  1988.         break;
  1989.     case FSCTL_SET_ENCRYPTION:
  1990.         strcpy( Buffer, "FSCTL_SET_ENCRYPTION" );
  1991.         break;
  1992.     case FSCTL_ENCRYPTION_FSCTL_IO:
  1993.         strcpy( Buffer, "FSCTL_ENCRYPTION_FSCTL_IO" );
  1994.         break;
  1995.     case FSCTL_WRITE_RAW_ENCRYPTED:
  1996.         strcpy( Buffer, "FSCTL_WRITE_RAW_ENCRYPTED" );
  1997.         break;
  1998.     case FSCTL_READ_RAW_ENCRYPTED:
  1999.         strcpy( Buffer, "FSCTL_READ_RAW_ENCRYPTED" );
  2000.         break;
  2001.     case FSCTL_CREATE_USN_JOURNAL:
  2002.         strcpy( Buffer, "FSCTL_CREATE_USN_JOURNAL" );
  2003.         break;
  2004.     case FSCTL_READ_FILE_USN_DATA:
  2005.         strcpy( Buffer, "FSCTL_READ_FILE_USN_DATA" );
  2006.         break;
  2007.     case FSCTL_WRITE_USN_CLOSE_RECORD:
  2008.         strcpy( Buffer, "FSCTL_WRITE_USN_CLOSE_RECORD" );
  2009.         break;
  2010.     case FSCTL_EXTEND_VOLUME:
  2011.         strcpy( Buffer, "FSCTL_EXTEND_VOLUME" );
  2012.         break;
  2013.         //
  2014.         // Named pipe file system controls 
  2015.         // (these are all undocumented)
  2016.         //
  2017.     case FSCTL_PIPE_DISCONNECT:
  2018.         strcpy( Buffer, "FSCTL_PIPE_DISCONNECT" );
  2019.         break;
  2020.     case FSCTL_PIPE_ASSIGN_EVENT:
  2021.         strcpy( Buffer, "FSCTL_PIPE_ASSIGN_EVENT" );
  2022.         break;
  2023.     case FSCTL_PIPE_QUERY_EVENT:
  2024.         strcpy( Buffer, "FSCTL_PIPE_QUERY_EVENT" );
  2025.         break;
  2026.     case FSCTL_PIPE_LISTEN:
  2027.         strcpy( Buffer, "FSCTL_PIPE_LISTEN" );
  2028.         break;
  2029.     case FSCTL_PIPE_IMPERSONATE:
  2030.         strcpy( Buffer, "FSCTL_PIPE_IMPERSONATE" );
  2031.         break;
  2032.     case FSCTL_PIPE_WAIT:
  2033.         strcpy( Buffer, "FSCTL_PIPE_WAIT" );
  2034.         break;
  2035.     case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
  2036.         strcpy( Buffer, "FSCTL_QUERY_CLIENT_PROCESS" );
  2037.         break;
  2038.     case FSCTL_PIPE_SET_CLIENT_PROCESS:
  2039.         strcpy( Buffer, "FSCTL_PIPE_SET_CLIENT_PROCESS");
  2040.         break;
  2041.     case FSCTL_PIPE_PEEK:
  2042.         strcpy( Buffer, "FSCTL_PIPE_PEEK" );
  2043.         break;
  2044.     case FSCTL_PIPE_INTERNAL_READ:
  2045.         strcpy( Buffer, "FSCTL_PIPE_INTERNAL_READ" );
  2046.         sprintf( Other, "ReadLen: %d", 
  2047.                 IrpSp->Parameters.DeviceIoControl.InputBufferLength );
  2048.         break;
  2049.     case FSCTL_PIPE_INTERNAL_WRITE:
  2050.         strcpy( Buffer, "FSCTL_PIPE_INTERNAL_WRITE" );
  2051.         sprintf( Other, "WriteLen: %d", 
  2052.                 IrpSp->Parameters.DeviceIoControl.InputBufferLength );
  2053.         break;
  2054.     case FSCTL_PIPE_TRANSCEIVE:
  2055.         strcpy( Buffer, "FSCTL_PIPE_TRANSCEIVE" );
  2056.         sprintf( Other, "WriteLen: %d ReadLen: %d",
  2057.                  IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  2058.                  IrpSp->Parameters.DeviceIoControl.OutputBufferLength );
  2059.         break;
  2060.     case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
  2061.         strcpy( Buffer, "FSCTL_PIPE_INTERNAL_TRANSCEIVE" );
  2062.         sprintf( Other, "WriteLen: %d ReadLen: %d",
  2063.                  IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  2064.                  IrpSp->Parameters.DeviceIoControl.OutputBufferLength );
  2065.         break;        
  2066.         //
  2067.         // Mail slot file system controls
  2068.         // (these are all undocumented)
  2069.         //
  2070.     case FSCTL_MAILSLOT_PEEK:
  2071.         strcpy( Buffer, "FSCTL_MAILSLOT_PEEK" );
  2072.         break;
  2073.     default:
  2074.         sprintf( Buffer, "IOCTL: 0x%X", ControlCode );
  2075.         break;
  2076.     }
  2077.     return Buffer;
  2078. }
  2079. //----------------------------------------------------------------------
  2080. //
  2081. // ErrorString
  2082. //
  2083. // Returns string representing the passed error condition.
  2084. //
  2085. //----------------------------------------------------------------------
  2086. PCHAR ErrorString( NTSTATUS RetStat, PCHAR Buffer ) 
  2087. {
  2088.     switch( RetStat ) {
  2089.     case STATUS_SUCCESS:
  2090.         strcpy( Buffer, "SUCCESS" );
  2091.         break;
  2092.     case STATUS_CRC_ERROR:
  2093.         strcpy( Buffer, "CRC ERROR" );
  2094.         break;
  2095.     case STATUS_NOT_IMPLEMENTED:
  2096.         strcpy( Buffer, "NOT IMPLEMENTED" );
  2097.         break;
  2098.     case STATUS_EAS_NOT_SUPPORTED:
  2099.         strcpy( Buffer, "EAS NOT SUPPORTED" );
  2100.         break;
  2101.     case STATUS_EA_TOO_LARGE:
  2102.         strcpy( Buffer, "EA TOO LARGE");
  2103.         break;
  2104.     case STATUS_NONEXISTENT_EA_ENTRY:
  2105.         strcpy( Buffer, "NONEXISTENT EA ENTRY");
  2106.         break;
  2107.     case STATUS_BAD_NETWORK_NAME:
  2108.         strcpy( Buffer, "BAD NETWORK NAME" );
  2109.         break;
  2110.     case STATUS_NOTIFY_ENUM_DIR:
  2111.         strcpy( Buffer, "NOTIFY ENUM DIR" );
  2112.         break;
  2113.     case STATUS_FILE_CORRUPT_ERROR:
  2114.         strcpy( Buffer, "FILE CORRUPT" );
  2115.         break;
  2116.     case STATUS_DISK_CORRUPT_ERROR:
  2117.         strcpy( Buffer, "DISK CORRUPT" );
  2118.         break;
  2119.     case STATUS_RANGE_NOT_LOCKED:
  2120.         strcpy( Buffer, "RANGE NOT LOCKED" );
  2121.         break;
  2122.     case STATUS_FILE_CLOSED:
  2123.         strcpy( Buffer, "FILE CLOSED" );
  2124.         break;
  2125.     case STATUS_IN_PAGE_ERROR:
  2126.         strcpy( Buffer, "IN PAGE ERROR" );
  2127.         break;
  2128.     case STATUS_CANCELLED:
  2129.         strcpy( Buffer, "CANCELLED" );
  2130.         break;
  2131.     case STATUS_QUOTA_EXCEEDED:
  2132.         strcpy( Buffer, "QUOTA EXCEEDED" );
  2133.         break;
  2134.     case STATUS_NOT_SUPPORTED:
  2135.         strcpy( Buffer, "NOT SUPPORTED" );
  2136.         break;
  2137.     case STATUS_NO_MORE_FILES:
  2138.         strcpy( Buffer, "NO MORE FILES" );
  2139.         break;
  2140.     case STATUS_OBJECT_NAME_INVALID:
  2141.         strcpy( Buffer, "NAME INVALID" );
  2142.         break;
  2143.     case STATUS_OBJECT_NAME_NOT_FOUND:
  2144.         strcpy( Buffer, "FILE NOT FOUND" );
  2145.         break;
  2146.     case STATUS_NOT_A_DIRECTORY: