🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #273

Re: Hard Drive Access

#273
From: Bruce Larrabee
Date: Sun, 25 May 2008 14:34
1324 lines
50851 bytes
    Hi Jeff,

    Here's some samples from the filemon.exe program's
    source code (filemon.exe is a precursor to the more
    versatile (and contemporary...) program you refer to
    I assume you are referring to Process Monitor?
    (Procmon.exe) not performance monitor...

    Here are some sample functions related to your needs:

    The last three look particularly interesting... :)

    If you have any questions you can email me
    (bruce_l @ westbrookent . com) or you post
    here...

This function comes from the source for the windows executable
version of file monitor, filemon.exe:

/************************************************************
  *
  *   FUNCTION:  HookDrives
  *
  *   PURPOSE:   Hook the currently selected drives,
  *              updating menu checks
  *
  ************************************************************/

DWORD HookDrives( HMENU DriveMenu, DWORD MaxDriveSet, DWORD CurDriveSet )
{
     DWORD nb;
     DWORD drive;

     // Tell device driver which drives to monitor

     if(!DeviceIoControl(

        SysHandle,
        IOCTL_FILEMON_SETDRIVES,
        &CurDriveSet, sizeof CurDriveSet,
        &CurDriveSet, sizeof CurDriveSet,

        &nb, NULL
     ))
     {
        return 0;
     }

     // Update menu items

     for( drive = 0; drive < 32; ++drive )
     {
        if ( MaxDriveSet & (1<<drive) )
        {
            if ( CurDriveSet & (1<<drive) )
            {
                CheckMenuItem( DriveMenu, IDC_DRIVE+drive, MF_BYCOMMAND|MF_CHECKED );
            }
            else
            {
                CheckMenuItem( DriveMenu, IDC_DRIVE+drive, MF_BYCOMMAND|MF_UNCHECKED );
            }
        }
     }

     return CurDriveSet;
}

This code is from the source code for the 'vxd' version of file monitor:

//----------------------------------------------------------------------
//                     H O O K   R O U T I N E
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//
// FilemonHookProc
//
// All (most) IFS functions come through this routine for us to look
// at.
//
//----------------------------------------------------------------------

int _cdecl FilemonHookProc( pIFSFunc pfn, int fn, int Drive, int ResType, int CodePage, pioreq pir)
{
     int                retval;
     char               fullpathname[MAXPATHLEN];
     char               processname[64];
     char               data[MAXPATHLEN];
     char               drivestring[4];
     ifsreq             origifsr;
     pioreq             origir;
     _WIN32_FIND_DATA   *finddata;
     struct srch_entry  *search;
     BOOLEAN            log;
     _QWORD             result;
     DWORD              timelo, timehi;
     DWORD              timelo1, timehi1;
     DWORD              dostime, dosdate;
     DWORD              datetimelo, datetimehi;
     int                i, j;

     //
     // Inititlize default data.
     //
     data[0] = 0;

     //
     // Save original iorequest because some entries get modified.
     //
     origir = (pioreq) &origifsr;
     memcpy( &origifsr, pir, sizeof( ifsreq ));

     //
     // Get the current process name.
     //
     FilemonGetProcess( processname );

     //
     // Get the time
     //
     VTD_Get_Real_Time( &timehi, &timelo );
     datetimehi = IFSMgr_Get_DOSTime( &datetimelo );
     dostime = VTD_Get_Date_And_Time( &dosdate );
     datetimelo = dostime - ((datetimehi >> 11)& 0x1F)*60*60*1000 -
             ((datetimehi >> 5) & 0x3F)*60*1000 -
             ((datetimehi & 0x1F)*2000);

     //
     // Special case for close call, since after the file's closed
     // we can't query its name
     //
     if( fn == IFSFN_CLOSE ) {

         FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );
     }

     //
     // Call the previous hooker first, to get the return code.
     //
     retval = (*PrevIFSHookProc)(pfn, fn, Drive, ResType, CodePage, pir);

     //
     // Now extract parameters based on the function type.
     //
     dprintf("%d: %d\n", fn, pir->ir_fh );
     switch( fn ) {

     case IFSFN_OPEN:

         FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );

         TIME_DIFF();
         sprintf(data,"");
         if( origir->ir_options & ACTION_CREATENEW ) strcat(data,"CREATENEW ");
         if( origir->ir_options & ACTION_OPENEXISTING ) strcat(data,"OPENEXISTING ");
         if( origir->ir_options & ACTION_REPLACEEXISTING ) strcat(data,"REPLACEEXISTING ");
         switch (origir->ir_flags & ACCESS_MODE_MASK) {

         case ACCESS_READONLY:
             strcat(data,"READONLY ");
             break;
         case ACCESS_WRITEONLY:
             strcat(data,"WRITEONLY ");
             break;
         case ACCESS_READWRITE:
             strcat(data,"READWRITE ");
             break;
         case ACCESS_EXECUTE:
             strcat(data,"EXECUTE ");
             break;
         default:
             break;
         }
         switch (origir->ir_flags & SHARE_MODE_MASK) {
         case SHARE_COMPATIBILITY:
             strcat(data,"COMPATIBILITY ");
             break;
         case SHARE_DENYREADWRITE:
             strcat(data,"DENYREADWRITE ");
             break;
         case SHARE_DENYWRITE:
             strcat(data,"DENYWRITE ");
             break;
         case SHARE_DENYREAD:
             strcat(data,"DENYREAD ");
             break;
         case SHARE_DENYNONE:
             strcat(data,"DENYNONE ");
             break;
         default:
             break;
         }
         LogRecord( timelo, datetimelo, datetimehi, "%s\tOpen\t%s\t%s\t%s",
                    processname, fullpathname,
                    data, ErrorString( retval ));
         FilemonLogHash( Drive, pir->ir_fh, fullpathname );
         break;

     case IFSFN_READ:
     case IFSFN_WRITE:
         FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );
         if( ((fn == IFSFN_READ && FilterDef.logreads ) ||
              (fn == IFSFN_WRITE && FilterDef.logwrites )) ) {

             TIME_DIFF();
             sprintf( data, "Offset: %ld Length: %ld", origir->ir_pos, origir->ir_length );
             LogRecord( timelo, datetimelo, datetimehi, "%s\t%s\t%s\t%s\t%s",
                        processname, fn == IFSFN_READ? "Read" : "Write",
                        fullpathname,
                        data, ErrorString( retval ));
         }
         break;

     case IFSFN_CLOSE:
         if( FilterDef.logreads ) {

             TIME_DIFF();
             switch( origir->ir_flags ) {
             case CLOSE_HANDLE:      sprintf(data, "CLOSE_HANDLE");      break;
             case CLOSE_FOR_PROCESS: sprintf(data, "CLOSE_FOR_PROCESS"); break;
             case CLOSE_FINAL:       sprintf(data, "CLOSE_FINAL");       break;
             default: sprintf(data,"0x%02X",origir->ir_flags);            break;
             }
             LogRecord( timelo, datetimelo, datetimehi, "%s\tClose\t%s\t%s\t%s", processname,
                        fullpathname, data, ErrorString( retval ));
         }
         if( origir->ir_flags == CLOSE_FINAL ) FilemonFreeHashEntry( Drive, origir->ir_fh);
         break;

     case IFSFN_DIR:

         //
         // This works around a special case I've seen when hiting the "browse" button in the
         // "have disk" dialog of the hardware wizard
         //
         if( origir->ir_flags != 0xFF ) {

             FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );

         } else {

             sprintf( fullpathname, "%c:", Drive+'A'-1);
         }
         TIME_DIFF();
         log = FALSE;
         switch( origir->ir_flags ) {
         case CREATE_DIR:
             sprintf(data, "CREATE");
             if( FilterDef.logwrites ) log = TRUE;
             break;
         case DELETE_DIR:
             sprintf(data,"DELETE");
             if( FilterDef.logwrites ) log = TRUE;
             break;
         case CHECK_DIR:
             sprintf(data,"CHECK");
             if( FilterDef.logreads ) log = TRUE;
             break;
         default:
             sprintf(data,"QUERY");
             if( FilterDef.logreads ) log = TRUE;
             break;
         }
         if( log ) {
             LogRecord( timelo, datetimelo, datetimehi, "%s\tDirectory\t%s\t%s\t%s",
                        processname,
                        fullpathname,
                        data, ErrorString( retval ));
         }
         break;

     case IFSFN_SEEK:
         FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );
         if( FilterDef.logreads) {

             TIME_DIFF();
             sprintf(data, "%s Offset: %ld / New offset: %ld",
                     origir->ir_flags == FILE_BEGIN ? "Beginning" : "End",
                     origir->ir_pos, origir->ir_pos );
             LogRecord( timelo, datetimelo, datetimehi, "%s\tSeek\t%s\t%s\t%s",
                        processname, fullpathname,
                        data, ErrorString( retval ));
         }
         break;

     case IFSFN_COMMIT:
         FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );
         if( FilterDef.logwrites) {

             TIME_DIFF();
             sprintf(data, "%s", origir->ir_options == FILE_COMMIT_ASYNC ?
                     "ASYNC" : "NOACCESSUPDATE" );
             LogRecord( timelo, datetimelo, datetimehi, "%s\tCommit\t%s\t%s\t%s",
                        processname, fullpathname,
                        data, ErrorString( retval ));
         }
         break;

     case IFSFN_FILELOCKS:
         FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );
         if( FilterDef.logreads) {

             TIME_DIFF();
             sprintf(data, "Offset: %ld Length:%ld", origir->ir_pos, origir->ir_locklen );
             LogRecord( timelo, datetimelo, datetimehi, "%s\t%s\t%s\t%s\t%s",
                        processname, origir->ir_flags == LOCK_REGION ? "Lock" : "Unlock",
                        fullpathname,
                        data, ErrorString( retval ));
         }
         break;

     case IFSFN_FINDOPEN:
         if( FilterDef.logreads) {	

             FilemonConvertPath( CONVERT_FINDOPEN, Drive, origir, CodePage, fullpathname );
             TIME_DIFF();
             if( !retval ) {

                 finddata = (_WIN32_FIND_DATA *) origir->ir_data;
                 UniToBCS( data, finddata->cFileName, wstrlen(finddata->cFileName), MAXPATHLEN-1, BCS_WANSI, &result );
                 data[ result.ddLower ] = 0;
             }
             LogRecord( timelo, datetimelo, datetimehi, "%s\tFindOpen\t%s\t%s\t%s",
                        processname, fullpathname,
                        data, ErrorString( retval ));
         }
         FilemonLogHash( Drive, pir->ir_fh, fullpathname );
         break;

     case IFSFN_FINDNEXT:
         FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );
         if( FilterDef.logreads) {	

             TIME_DIFF();
             if( !retval ) {
                 finddata = (_WIN32_FIND_DATA *) origir->ir_data;
                 UniToBCS( data, finddata->cFileName, wstrlen(finddata->cFileName), MAXPATHLEN-1, BCS_WANSI, &result );
                 data[ result.ddLower ] = 0;
             }

             LogRecord( timelo, datetimelo, datetimehi, "%s\tFindNext\t%s\t%s\t%s",
                        processname, fullpathname,
                        data, ErrorString( retval ));
         }
         break;

     case IFSFN_FINDCLOSE:
         FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );
         if( FilterDef.logreads) {	

             TIME_DIFF();
             LogRecord( timelo, datetimelo, datetimehi, "%s\tFindClose\t%s\t\t%s",
                        processname, fullpathname,
                        ErrorString( retval ));
         }
         FilemonFreeHashEntry( Drive, origir->ir_fh );
         break;

     case IFSFN_FILEATTRIB:
         if( FilterDef.logreads) {

             FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );
             TIME_DIFF();
             switch(origir->ir_flags ) {
             case GET_ATTRIBUTES:
                 sprintf(data,"GetAttributes");
                 break;
             case SET_ATTRIBUTES:
                 sprintf(data, "SetAttributes" );
                 break;
             case GET_ATTRIB_COMP_FILESIZE:
                 sprintf(data, "GET_ATTRIB_COMP_FILESIZE" );
                 break;
             case SET_ATTRIB_MODIFY_DATETIME:
                 sprintf(data, "SET_ATTRIB_MODIFY_DATETIME");
                 break;
             case SET_ATTRIB_LAST_ACCESS_DATETIME:
                 sprintf(data, "SET_ATTRIB_LAST_ACCESS_DATETIME");
                 break;
             case GET_ATTRIB_LAST_ACCESS_DATETIME:
                 sprintf(data, "GET_ATTRIB_LAST_ACCESS_DATETIME");
                 break;
             case SET_ATTRIB_CREATION_DATETIME:
                 sprintf(data, "SET_ATTRIB_CREATION_DATETIME");
                 break;
             case GET_ATTRIB_CREATION_DATETIME:
                 sprintf(data, "GET_ATTRIB_CREATION_DATETIME");
                 break;
             }
             LogRecord( timelo, datetimelo, datetimehi, "%s\tAttributes\t%s\t%s\t%s",
                        processname, fullpathname,
                        data, ErrorString( retval ));
         }
         break;

     case IFSFN_FILETIMES:
         FilemonGetFullPath( origir->ir_fh, fullpathname, Drive, ResType, CodePage, origir );
         if( FilterDef.logreads) {	

             TIME_DIFF();
             switch( origir->ir_flags ) {
             case GET_MODIFY_DATETIME:
                 sprintf(data, "Get Modify");
                 break;
             case SET_MODIFY_DATETIME:
                 sprintf(data, "Set Modify");
                 break;
             case GET_LAST_ACCESS_DATETIME:
                 sprintf(data, "Get Access");
                 break;
             case SET_LAST_ACCESS_DATETIME:
                 sprintf(data, "Set Access");
                 break;
             case GET_CREATION_DATETIME:
                 sprintf(data, "Get Creation");
                 break;
             case SET_CREATION_DATETIME:
                 sprintf(data, "Set Creation");
                 break;
             }
             LogRecord( timelo, datetimelo, datetimehi, "%s\tAttributes\t%s\t%s\t%s",
                        processname, fullpathname,
                        data, ErrorString( retval ));
         }
         break;

     case IFSFN_FLUSH:
         if( FilterDef.logwrites) {

             TIME_DIFF();
             LogRecord( timelo, datetimelo, datetimehi, "%s\tFlushVolume\t\t\t%s",
                        processname, ErrorString( retval ));
         }
         break;

     case IFSFN_DELETE:
         if( FilterDef.logwrites) {

             FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );
             TIME_DIFF();
             LogRecord( timelo, datetimelo, datetimehi, "%s\tDelete\t%s\t\t%s",
                        processname, fullpathname, ErrorString( retval ));
         }
         FilemonFreeHashEntry( Drive, origir->ir_fh );
         break;

     case IFSFN_SEARCH:
         if( FilterDef.logreads ) {

             if( origir->ir_flags == SEARCH_FIRST )
                 FilemonConvertPath( CONVERT_STANDARD, Drive, origir, CodePage, fullpathname );
             else
                 sprintf(fullpathname, "SearchNext" );
             TIME_DIFF();
             if( !retval ) {
                 j = 0;
                 if( origir->ir_attr & FILE_ATTRIBUTE_LABEL ) {
                     sprintf(data, "VolumeLabel: " );
                     j = strlen( data );
                 }
                 search = (struct srch_entry *) origir->ir_data;
                 for( i = 0; i < 13; i++ )
                     if( search->se_name[i] != ' ' ) data[j++] = search->se_name[i];
                 data[j] = 0;
             }
             LogRecord( timelo, datetimelo, datetimehi, "%s\tSearch\t%s\t%s\t%s",
                        processname, fullpathname, data, ErrorString( retval ));
         }
         break;

     case IFSFN_GETDISKINFO:

         if( FilterDef.logreads ) {

             TIME_DIFF();
             if( !retval ) sprintf(data, "Free Space");
             drivestring[0] = Drive+'A'-1;
             drivestring[1] = ':';
             drivestring[2] = 0;
             LogRecord( timelo, datetimelo, datetimehi, "%s\tGetDiskInfo\t%s\t%s\t%s",
                        processname, drivestring, data, ErrorString( retval ));
         }
         break;

     case IFSFN_RENAME:
         if( FilterDef.logwrites) {

             FilemonConvertPath( CONVERT_RENAME_SOURCE, Drive, origir, CodePage, fullpathname );
             TIME_DIFF();
             LogRecord( timelo, datetimelo, datetimehi, "%s\tRename\t%s\t%s\t%s",
                        processname, fullpathname,
                        FilemonConvertPath( CONVERT_RENAME_TARGET, Drive, origir, CodePage, data ),
                        ErrorString( retval ));		
         }
         break;
     case IFSFN_IOCTL16DRIVE:
         if( FilterDef.logreads || FilterDef.logwrites) {

             TIME_DIFF();
             sprintf(data, "Subfunction: %02Xh", origir->ir_flags );
             drivestring[0] = Drive+'A'-1;
             drivestring[1] = ':';
             drivestring[2] = 0;
             LogRecord( timelo, datetimelo, datetimehi, "%s\tIoctl\t%s\t%s\t%s",
                        processname, drivestring, data, ErrorString( retval ));
         }
         break;
     }
     dprintf("==>%d\n", fn );
     return retval;
}



//----------------------------------------------------------------------
//
// OnSysDynamicDeviceInit
//
// Dynamic init. Install a file system filter hook.
//
//----------------------------------------------------------------------

BOOL OnSysDynamicDeviceInit( VOID)
{
     int i;
     MEMHANDLE hLog;

     //
     // Initialize the locks.
     //
     LogMutex = Create_Semaphore(1);
     HashMutex  = Create_Semaphore(1);
     FilterMutex  = Create_Semaphore(1);

     //
     // Zero hash table.
     //
     for(i = 0; i < NUMHASH; i++ ) HashTable[i] = NULL;

     //
     // Allocate the initial output buffer.
     //
     PageAllocate(LOGBUFPAGES, PG_SYS, 0, 0, 0, 0, NULL, PAGELOCKED,
                  (PMEMHANDLE) &hLog, (PVOID) &Log );
     Log->Handle = hLog;
     Log->Len = 0;
     Log->Next = NULL;
     NumLog = 1;

     //
     // Hook IFS functions.
     //
     PrevIFSHookProc = IFSMgr_InstallFileSystemApiHook(FilemonHookProc);
     return TRUE;
}

//----------------------------------------------------------------------
//
// OnSysDynamicDeviceExit
//
// Dynamic exit. Unhook everything.
//
//----------------------------------------------------------------------

BOOL OnSysDynamicDeviceExit( VOID)
{
     //
     // Unhook IFS functions.
     //
     IFSMgr_RemoveFileSystemApiHook(FilemonHookProc);

     //
     // Free all memory.
     //
     FilemonHashCleanup();
     FilemonFreeLog();
     FilemonFreeFilters();
     return TRUE;
}

//----------------------------------------------------------------------

This code is from the file monitor 'sys' version source code:


//----------------------------------------------------------------------
//
// HookDrive
//
// Hook the drive specified by determining which device object to
// attach to. The algorithm used here is similar to the one used
// internally by NT to determine which device object a file system request
// is directed at.
//
//----------------------------------------------------------------------

BOOLEAN HookDrive( IN ULONG Drive, IN PDRIVER_OBJECT DriverObject)
{
     IO_STATUS_BLOCK     ioStatus;
     HANDLE              ntFileHandle;
     OBJECT_ATTRIBUTES   objectAttributes;
     PDEVICE_OBJECT      fileSysDevice;
     PDEVICE_OBJECT      hookDevice;
     UNICODE_STRING      fileNameUnicodeString;
     PFILE_FS_ATTRIBUTE_INFORMATION fileFsAttributes;
     ULONG               fileFsAttributesSize;
     WCHAR               filename[] = L"\\DosDevices\\A:\\";
     NTSTATUS            ntStatus;
     ULONG               i;
     PFILE_OBJECT        fileObject;
     PHOOK_EXTENSION     hookExtension;

     //
     // Is it a legal drive letter?
     //
     if( Drive >= 26 )  {

         return FALSE;
     }

     //
     // Has this drive already been hooked?
     //
     if( DriveHookDevices[Drive] == NULL )  {

         //
         // Frob the name to make it refer to the drive specified in the input
         // parameter.
         //
         filename[12] = (CHAR) ('A'+Drive);

         //
         // We have to figure out what device to hook - first open the volume's
         // root directory
         //
         RtlInitUnicodeString( &fileNameUnicodeString, filename );
         InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString,
                                     OBJ_CASE_INSENSITIVE, NULL, NULL );
         ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS,
                                  &objectAttributes, &ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
                                  FILE_OPEN,
                                  FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE,
                                  NULL, 0 );
         if( !NT_SUCCESS( ntStatus ) ) {

             DbgPrint(("Filemon: Could not open drive %c: %x\n", 'A'+Drive, ntStatus ));
             return FALSE;
         }

         DbgPrint(("Filemon:  opened the root directory!!! handle: %x\n", ntFileHandle));

         //
         // Got the file handle, so now look-up the file-object it refers to
         //
         ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA,
                                               NULL, KernelMode, &fileObject, NULL );
         if( !NT_SUCCESS( ntStatus )) {

             DbgPrint(("Filemon: Could not get fileobject from handle: %c\n", 'A'+Drive ));
             ZwClose( ntFileHandle );
             return FALSE;
         }

         //
         // Next, find out what device is associated with the file object by getting its related
         // device object
         //
         fileSysDevice = IoGetRelatedDeviceObject( fileObject );

         if( ! fileSysDevice ) {

             DbgPrint(("Filemon: Could not get related device object: %c\n", 'A'+Drive ));
             ObDereferenceObject( fileObject );
             ZwClose( ntFileHandle );
             return FALSE;
         }

         //
         // Check the device list to see if we've already attached to this particular device.
         // This can happen when more than one drive letter is being handled by the same network
         // redirecter
         //
         for( i = 0; i < 26; i++ ) {

             if( DriveHookDevices[i] == fileSysDevice ) {

                 //
                 // If we're already watching it, associate this drive letter
                 // with the others that are handled by the same network driver. This
                 // enables us to intelligently update the hooking menus when the user
                 // specifies that one of the group should not be watched -we mark all
                 // of the related drives as unwatched as well
                 //
                 ObDereferenceObject( fileObject );
                 ZwClose( ntFileHandle );
                 DriveHookDevices[ Drive ] = fileSysDevice;
                 return TRUE;
             }
         }

         //
         // The file system's device hasn't been hooked already, so make a hooking device
         //  object that will be attached to it.
         //
         ntStatus = IoCreateDevice( DriverObject,
                                    sizeof(HOOK_EXTENSION),
                                    NULL,
                                    fileSysDevice->DeviceType,
                                    0,
                                    FALSE,
                                    &hookDevice );
         if( !NT_SUCCESS(ntStatus) ) {

             DbgPrint(("Filemon: failed to create associated device: %c\n", 'A'+Drive ));

             ObDereferenceObject( fileObject );
             ZwClose( ntFileHandle );

             return FALSE;
         }

         //
         // Clear the device's init flag as per NT DDK KB article on creating device
         // objects from a dispatch routine
         //
         hookDevice->Flags &= ~DO_DEVICE_INITIALIZING;

         //
         // Setup the device extensions. The drive letter and file system object are stored
         // in the extension.
         //
         hookExtension = hookDevice->DeviceExtension;
         hookExtension->LogicalDrive = 'A'+Drive;
         hookExtension->FileSystem   = fileSysDevice;
         hookExtension->Hooked       = TRUE;
         hookExtension->Type         = STANDARD;

         //
         // Finally, attach to the device. The second we're successfully attached, we may
         // start receiving IRPs targetted at the device we've hooked.
         //
         ntStatus = IoAttachDeviceByPointer( hookDevice, fileSysDevice );
         if( !NT_SUCCESS(ntStatus) )  {

             //
             // Couldn' attach for some reason
             //
             DbgPrint(("Filemon: Connect with Filesystem failed: %c (%x) =>%x\n",
                       'A'+Drive, fileSysDevice, ntStatus ));

             //
             // Derefence the object and get out
             //
             ObDereferenceObject( fileObject );
             ZwClose( ntFileHandle );

             return FALSE;

         } else {

             //
             // Make a new drive group for the device,l if it does not have one
             // already
             //
             DbgPrint(("Filemon: Successfully connected to Filesystem device %c\n", 'A'+Drive ));
         }

         //
         // Determine if this is a NTFS drive
         //
         fileFsAttributesSize = sizeof( FILE_FS_ATTRIBUTE_INFORMATION) + MAXPATHLEN;
         hookExtension->FsAttributes = (PFILE_FS_ATTRIBUTE_INFORMATION) ExAllocatePool( NonPagedPool,
                                                                                        fileFsAttributesSize );
         if( hookExtension->FsAttributes &&
             !NT_SUCCESS( IoQueryVolumeInformation( fileObject, FileFsAttributeInformation,
                                                    fileFsAttributesSize, hookExtension->FsAttributes,
                                                    &fileFsAttributesSize ))) {

             //
             // On failure, we just don't have attributes for this file system
             //
             ExFreePool( hookExtension->FsAttributes );
             hookExtension->FsAttributes = NULL;
         }

         //
         // Close the file and update the hooked drive list by entering a
         // pointer to the hook device object in it.
         //
         ObDereferenceObject( fileObject );

         ZwClose( ntFileHandle );

         DriveHookDevices[Drive] = hookDevice;

     } else {

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


//----------------------------------------------------------------------
//
// UnhookDrive
//
// Unhook a previously hooked drive.
//
//----------------------------------------------------------------------

VOID UnhookDrive( IN ULONG Drive)
{
     PHOOK_EXTENSION hookExt;

     //
     // If the drive has been hooked, unhook it and delete the hook
     // device object
     //
     if( DriveHookDevices[Drive] )  {

         hookExt = DriveHookDevices[Drive]->DeviceExtension;
         hookExt->Hooked = FALSE;
     }
}

//----------------------------------------------------------------------
//
// FilemonHookRoutine
//
// This routine is the main hook routine where we figure out what
// calls are being sent to the file system.
//
//----------------------------------------------------------------------

NTSTATUS FilemonHookRoutine( PDEVICE_OBJECT HookDevice, IN PIRP Irp)
{
     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
     PIO_STACK_LOCATION  nextIrpStack    = IoGetNextIrpStackLocation(Irp);
     PMOVE_FILE_DATA     moveFile;
     PQUERY_DIRECTORY    queryDirectory;
     PFILE_OBJECT        FileObject;
     PHOOK_EXTENSION     hookExt;
     LARGE_INTEGER       dateTime;
     LARGE_INTEGER       perfTime;
     PCHAR               fullPathName = NULL;
     BOOLEAN             hookCompletion, createPath;
     CHAR                controlCodeBuffer[ERRORLEN];
     CHAR                attributeString[ERRORLEN];
     CHAR                optionString[ERRORLEN];
     CHAR                name[PROCNAMELEN];
     ULONG               i;
     ANSI_STRING         directoryFilter;
     PCHAR               queryFilter;
     ULONG               seqNum;
     KIRQL               oldirql;

     //
     // Extract the file object from the IRP
     //
     FileObject = currentIrpStack->FileObject;

     //
     // Point at the device extension, which contains information on which
     // file system this IRP is headed for
     //
     hookExt = HookDevice->DeviceExtension;

     //
     // We note open cases so that when we query the file name
     // we don't ask the file system for the name (since it won't
     // have seen the file object yet).
     //
     if( currentIrpStack->MajorFunction == IRP_MJ_CREATE ||
         currentIrpStack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE ||
         currentIrpStack->MajorFunction == IRP_MJ_CREATE_MAILSLOT ) {

         //
         // Clear any existing fileobject/name association stored in the
         // hash table
         //
         FilemonFreeHashEntry( FileObject );
         createPath = TRUE;

     } else if( currentIrpStack->MajorFunction == IRP_MJ_CLOSE ) {

         //
         // We treat close as a special case of create for name querying
         // since calling into NTFS during a close can result in a deadlock.
         //
         createPath = TRUE;

     } else if( currentIrpStack->MajorFunction == IRP_MJ_CLEANUP &&
                FileObject->Flags & FO_STREAM_FILE ) {

         //
         // Treat cleanup of stream file objects as special create case, because
         // querying them causes NTFS to screwup on NT 4
         //
         createPath = TRUE;

     } else {

         createPath = FALSE;
     }

     //
     // Allocate a buffer and get the name only if we have to
     //
     if( FilterOn && hookExt->Hooked ) {

         GETPATHNAME( createPath );
     }

     //
     // Only log it if it passes the filter
     //
     if( hookExt->Hooked && fullPathName ) {

         //
         // If measuring absolute time go and get the timestamp.
         //
         KeQuerySystemTime( &dateTime );
         perfTime = KeQueryPerformanceCounter( NULL );

         //
         // We want to watch this IRP complete
         //
         seqNum = (ULONG) -1;
         hookCompletion = FALSE;

         //
         // Determine what function we're dealing with
         //
         FilemonGetProcess( name );
         switch( currentIrpStack->MajorFunction ) {

         case IRP_MJ_CREATE:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_CREATE\t%s\tAttributes: %s Options: %s",
                                        name, fullPathName,
                                        CreateAttributesString( currentIrpStack->Parameters.Create.FileAttributes,
                                                                attributeString ),
                                        CreateOptionsString( currentIrpStack->Parameters.Create.Options,
                                                             optionString ));

             //
             // If its an open-by-id we free the hash entry now so that on the next access to
             // the file we'll pick up the file's real name.
             //
             if( currentIrpStack->Parameters.Create.Options & FILE_OPEN_BY_FILE_ID ) {

                 FilemonFreeHashEntry( FileObject );
             }
             break;

         case IRP_MJ_CREATE_NAMED_PIPE:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_CREATE_NAMED_PIPE\t%s\tAttributes: %s Options: %s",
                                        name, fullPathName,
                                        CreateAttributesString( currentIrpStack->Parameters.Create.FileAttributes,
                                                                attributeString ),
                                        CreateOptionsString( currentIrpStack->Parameters.Create.Options,
                                                             optionString ));
             break;

         case IRP_MJ_CREATE_MAILSLOT:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_CREATE_MAILSLOT\t%s\tAttributes: %s Options: %s",
                                        name, fullPathName,
                                        CreateAttributesString( currentIrpStack->Parameters.Create.FileAttributes,
                                                                attributeString ),
                                        CreateOptionsString( currentIrpStack->Parameters.Create.Options,
                                                             optionString ));
             break;

         case IRP_MJ_READ:

             if( FilterDef.logreads ) {
                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                            "%s\tIRP_MJ_READ%c\t%s\tOffset: %d Length: %d",
                                            name,
                                            (Irp->Flags & IRP_PAGING_IO) ||
                                                   (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',
                                            fullPathName,
                                            currentIrpStack->Parameters.Read.ByteOffset.LowPart,
                                            currentIrpStack->Parameters.Read.Length );
             }
             break;

         case IRP_MJ_WRITE:

             if( FilterDef.logwrites ) {
                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                            "%s\tIRP_MJ_WRITE%c\t%s\tOffset: %d Length: %d",
                                            name,
                                            (Irp->Flags & IRP_PAGING_IO) ||
                                                   (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',
                                            fullPathName,
                                            currentIrpStack->Parameters.Write.ByteOffset.LowPart,
                                            currentIrpStack->Parameters.Write.Length );
             }
             break;

         case IRP_MJ_CLOSE:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_CLOSE%c\t%s\t",
                                        name,
                                        (Irp->Flags & IRP_PAGING_IO) ||
                                               (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',
                                        fullPathName );

             //
             // This fileobject/name association can be discarded now.
             //
             FilemonFreeHashEntry( FileObject );
             break;

         case IRP_MJ_FLUSH_BUFFERS:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_FLUSH\t%s\t", name, fullPathName );
             break;

         case IRP_MJ_QUERY_INFORMATION:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_QUERY_INFORMATION\t%s\t%s",
                                        name, fullPathName,
                                        FileInformation[currentIrpStack->Parameters.QueryFile.FileInformationClass] );
             break;

         case IRP_MJ_SET_INFORMATION:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_SET_INFORMATION%c\t%s\t%s",
                                        name,
                                        (Irp->Flags & IRP_PAGING_IO) ||
                                              (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',
                                        fullPathName,
                                        FileInformation[currentIrpStack->Parameters.SetFile.FileInformationClass] );

             //
             // If its a rename, cleanup the name association.
             //
             if( currentIrpStack->Parameters.SetFile.FileInformationClass ==
                 FileRenameInformation ) {

                 FilemonFreeHashEntry( FileObject );
             }
             break;

         case IRP_MJ_QUERY_EA:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_QUERY_EA\t%s\t", name, fullPathName );
             break;

         case IRP_MJ_SET_EA:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_SET_EA\t%s\t", name, fullPathName );
             break;

         case IRP_MJ_QUERY_VOLUME_INFORMATION:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_QUERY_VOLUME_INFORMATION\t%s\t%s",
                                        name, fullPathName,
                                        VolumeInformation[currentIrpStack->Parameters.QueryVolume.FsInformationClass] );
             break;

         case IRP_MJ_SET_VOLUME_INFORMATION:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_SET_VOLUME_INFORMATION\t%s\t%s",
                                        name, fullPathName,
                                        VolumeInformation[currentIrpStack->Parameters.QueryVolume.FsInformationClass] );
             break;

         case IRP_MJ_DIRECTORY_CONTROL:

             switch( currentIrpStack->MinorFunction ) {
             case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                            "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\tChange Notify",
                                            name, fullPathName );
                 break;
             case IRP_MN_QUERY_DIRECTORY:
                 queryDirectory = (PQUERY_DIRECTORY)&currentIrpStack->Parameters;
                 queryFilter = NULL;
                 if( queryDirectory->FileName ) {

                     if( NT_SUCCESS( RtlUnicodeStringToAnsiString( &directoryFilter,
                                                                   queryDirectory->FileName, TRUE ))) {

                         queryFilter = ExAllocatePool( PagedPool, directoryFilter.Length + 1 );
                         if( queryFilter ) {

                             memcpy( queryFilter, directoryFilter.Buffer, directoryFilter.Length );
                             queryFilter[ directoryFilter.Length ] = 0;

                             //
                             // Massage DOS-internal wildcards
                             //
                             for( i = 0; i < strlen( queryFilter ); i++ ) {
                                 if( queryFilter[i] == '<' ) queryFilter[i] = '*';
                                 else if( queryFilter[i] == '>' ) queryFilter[i] = '?';
                             }
                         }
                         RtlFreeAnsiString( &directoryFilter );
                     }
                 }
                 if( queryFilter ) {

                     hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                                "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\t%s: %s",
                                                name, fullPathName,
                                                FileInformation[queryDirectory->FileInformationClass],
                                                queryFilter );
                     ExFreePool( queryFilter );

                 } else {

                     hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                                "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\t%s",
                                                name, fullPathName,
                                                FileInformation[queryDirectory->FileInformationClass] );
                 }
                 break;
             default:
                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                            "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\t",
                                            name, fullPathName );
                 break;
             }
             break;

         case IRP_MJ_FILE_SYSTEM_CONTROL:

             switch( currentIrpStack->Parameters.DeviceIoControl.IoControlCode ) {
             case FSCTL_MOVE_FILE:
                 moveFile = (PMOVE_FILE_DATA) Irp->AssociatedIrp.SystemBuffer;
                 sprintf( optionString, "Vcn: %d Len: %d Target: %d",
                          moveFile->StartingVcn.LowPart,
                          moveFile->ClusterCount,
                          moveFile->StartingLcn.LowPart );
                 ObReferenceObjectByHandle( moveFile->FileHandle, 0, NULL, KernelMode, &FileObject, NULL );
                 FilemonGetFullPath( FALSE, FileObject, hookExt, fullPathName );
                 ObDereferenceObject( FileObject );
                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                             "%s\tFSCTL_MOVE_FILE\t%s\t%s",
                                             name, fullPathName, optionString );
                 break;
             default:
                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                             "%s\t%s\t%s\t%s",
                                             name,
                                             ControlCodeString( currentIrpStack,
                                                                currentIrpStack->Parameters.DeviceIoControl.IoControlCode,
                                                                controlCodeBuffer, optionString ),
                                             fullPathName, optionString );
             }
             break;

         case IRP_MJ_SHUTDOWN:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_SHUTDOWN\t\t", name );
             break;

         case IRP_MJ_LOCK_CONTROL:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_LOCK_CONTROL\t%s\tOffset: %d Length: %d",
                                        name, fullPathName,
                                        ((PLOCK_CONTROL)&currentIrpStack->Parameters)->ByteOffset.LowPart,
                                        ((PLOCK_CONTROL)&currentIrpStack->Parameters)->Length ?
                                        ((PLOCK_CONTROL)&currentIrpStack->Parameters)->Length->LowPart : 0 );
             break;

         case IRP_MJ_CLEANUP:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_CLEANUP\t%s\t", name, fullPathName );
             break;

         case IRP_MJ_DEVICE_CONTROL:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_DEVICE_CONTROL\t%s\tIOCTL: 0x%X", name,
                                        fullPathName, currentIrpStack->Parameters.DeviceIoControl.IoControlCode );
             break;

         case IRP_MJ_QUERY_SECURITY:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_QUERY_SECURITY\t%s\t",
                                        name, fullPathName );
             break;

         case IRP_MJ_SET_SECURITY:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_SET_SECURITY\t%s\t",
                                        name, fullPathName );
             break;

         case IRP_MJ_POWER:

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

         case IRP_MJ_PNP:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\tIRP_MJ_PNP\t%s\t%s",
                                        name, fullPathName,
                                        currentIrpStack->MinorFunction <= IRP_MN_QUERY_LEGACY_BUS_INFORMATION ?
                                        PnpMinorCode[currentIrpStack->MinorFunction] : "New minor code" );
             break;

         default:

             hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,
                                        "%s\t*UNKNOWN* 0x%X\t\t", name, currentIrpStack->MajorFunction );
             break;
         }

     } else {

         //
         // We don't care about this IRP's completion
         //
         hookCompletion = FALSE;

         //
         // Do name processing for the sake of keeping the hash table current
         //
         switch( currentIrpStack->MajorFunction ) {
         case IRP_MJ_CLOSE:

             //
             // This fileobject/name association can be discarded now.
             //
             FilemonFreeHashEntry( FileObject );
             break;
         }
     }

     //
     // Free the buffer if we have one
     //
     if( fullPathName && fullPathName != InsufficientResources ) {

         ExFreeToNPagedLookasideList( &FullPathLookaside, fullPathName );
     }

     //
     // Copy parameters down to next level in the stack for the driver below us
     //
     *nextIrpStack = *currentIrpStack;

#if DBG
     //
     // If an unload isn't in progress, we should register a completion callback
     // so that the IRP's return status can be examined.
     //
     KeAcquireSpinLock( &CountMutex, &oldirql );
#endif

     if( !UnloadInProgress && hookCompletion ) {

#if DBG
         //
         // Increment the outstanding IRP count since this IRP will be headed
         // for our completion routine
         //
         FilemonDriver->DriverUnload = NULL;
         OutstandingIRPCount++;
         DbgPrint(("+%d: %x\n", OutstandingIRPCount, Irp ));;
#endif // DBG
         //
         // Grab the time stamp and Log it in the current stack location. This
         // is legal since the stack location is ours, and we're done looking at
         // the parameters. This makes it easy to pass this to the completion routine. The
         // DiskPerf example in the NT DDK uses this trick.
         //
         currentIrpStack->Parameters.Read.ByteOffset = perfTime;
#if defined(_IA64_)
         IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) (ULONG_PTR) seqNum, TRUE, TRUE, TRUE );
#else
         IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) seqNum, TRUE, TRUE, TRUE );
#endif

     } else {

         //
         // Set no completion routine
         //
         IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, FALSE, FALSE, FALSE );
     }
#if DBG
     KeReleaseSpinLock( &CountMutex, oldirql );
#endif

     //
     // Return the results of the call to the caller
     //
     return IoCallDriver( hookExt->FileSystem, Irp );
}


//----------------------------------------------------------------------
Technical Details
Message-ID: <483978fa@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!feeder.news-service.com!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail
References: <483726af$1@newsgroups.borland.com>

Show Full Headers
Complete Article Headers
X-Google-Thread: 10cc67,c374cfd4b7ac43da
X-Google-Attributes: gid10cc67,domainid0,public,usenet
X-Google-Language: ENGLISH,ASCII-7-bit
Date: Sun, 25 May 2008 07:34:25 -0700
From: Bruce Larrabee <bruce_l@westbrookent.com>
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)
X-Accept-Language: en-us, en
MIME-Version: 1.0
Newsgroups: borland.public.cppbuilder.nativeapi
Subject: Re: Hard Drive Access
References: <483726af$1@newsgroups.borland.com>
In-Reply-To: <483726af$1@newsgroups.borland.com>
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
NNTP-Posting-Host: 208.100.240.149
Message-ID: <483978fa@newsgroups.borland.com>
X-Trace: newsgroups.borland.com 1211726074 208.100.240.149 (25 May 2008 07:34:34 -0700)
Lines: 1325
Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!feeder.news-service.com!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail