/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: PpHandle.c Abstract: This module implements handle location code for the Plug and Play subsystem. Author: Adrian J. Oney - April 4, 2001 Revision History: --*/ #include "pnpmgrp.h" #include "pihandle.h" #pragma hdrstop #ifdef ALLOC_PRAGMA //#pragma alloc_text(NONPAGE, PpHandleEnumerateHandlesAgainstPdoStack) #pragma alloc_text(PAGE, PiHandleEnumerateHandlesAgainstDeviceObject) #pragma alloc_text(PAGE, PiHandleProcessWalkWorker) #endif LOGICAL PpHandleEnumerateHandlesAgainstPdoStack( IN PDEVICE_OBJECT PhysicalDeviceObject, IN PHANDLE_ENUMERATION_CALLBACK HandleEnumCallBack, IN PVOID Context ) /*++ Routine Description: This routine walks every device object in the WDM device stack along with all filesystem device objects on the other side of a VPB. If any handles are opened against such device objects, the specified callback is invoked. Arguments: PhysicalDeviceObject - Supplies a pointer to the device object at the bottom of the WDM device stack. HandleEnumCallBack - Pointer the callback function. Context - Pointer to information to be passed into the callback function. Return Value: TRUE if the enumeration was halted, FALSE otherwise. --*/ { PDEVICE_OBJECT currentDevObj, nextDevObj, vpbObj, vpbBottomObj; LOGICAL stopEnum; KIRQL oldIrql; PVPB vpb; // // Preinit // stopEnum = FALSE; // // Start with the device object at the bottom of the stack // currentDevObj = PhysicalDeviceObject; ObReferenceObject(currentDevObj); do { // // Dump any handles opened directly against the specified device object // stopEnum = PiHandleEnumerateHandlesAgainstDeviceObject( currentDevObj, HandleEnumCallBack, Context ); if (stopEnum) { ObDereferenceObject(currentDevObj); break; } // // Look for a VPB // IoAcquireVpbSpinLock(&oldIrql); vpb = currentDevObj->Vpb; vpbObj = NULL; if (vpb) { vpbObj = vpb->DeviceObject; if (vpbObj) { ObReferenceObject(vpbObj); } } IoReleaseVpbSpinLock(oldIrql); // // If we have a vpb object, dump any handles queued against it. // if (vpbObj) { vpbBottomObj = IoGetDeviceAttachmentBaseRef(vpbObj); stopEnum = PiHandleEnumerateHandlesAgainstDeviceObject( vpbBottomObj, HandleEnumCallBack, Context ); ObDereferenceObject(vpbBottomObj); ObDereferenceObject(vpbObj); if (stopEnum) { ObDereferenceObject(currentDevObj); break; } } // // Advance to the next DO. // oldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); nextDevObj = currentDevObj->AttachedDevice; if (nextDevObj) { ObReferenceObject(nextDevObj); } KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, oldIrql); // // Drop ref on old DO. // ObDereferenceObject(currentDevObj); // // Loop. // currentDevObj = nextDevObj; } while (currentDevObj); return stopEnum; } LOGICAL PiHandleEnumerateHandlesAgainstDeviceObject( IN PDEVICE_OBJECT DeviceObject, IN PHANDLE_ENUMERATION_CALLBACK HandleEnumCallBack, IN PVOID Context ) /*++ Routine Description: This routine walks the handle table for each process in the system looking for handles opened against the passed in device object. Arguments: PhysicalDeviceObject - Supplies a pointer to the device object at the bottom of the WDM device stack. HandleEnumCallBack - Pointer the callback function. Context - Pointer to information to be passed into the callback function. Return Value: TRUE if the enumeration was halted, FALSE otherwise. --*/ { PEPROCESS process; PHANDLE_TABLE objectTable; HANDLE_ENUM_CONTEXT handleEnumContext; LOGICAL stopEnum = FALSE; for(process = PsGetNextProcess(NULL); process != NULL; process = PsGetNextProcess(process)) { objectTable = ObReferenceProcessHandleTable(process); if (objectTable) { handleEnumContext.DeviceObject = DeviceObject; handleEnumContext.Process = process; handleEnumContext.CallBack = HandleEnumCallBack; handleEnumContext.Context = Context; stopEnum = (LOGICAL) ExEnumHandleTable( objectTable, PiHandleProcessWalkWorker, (PVOID) &handleEnumContext, NULL ); ObDereferenceProcessHandleTable(process); if (stopEnum) { PsQuitNextProcess(process); break; } } } return stopEnum; } BOOLEAN PiHandleProcessWalkWorker( IN PHANDLE_TABLE_ENTRY ObjectTableEntry, IN HANDLE HandleId, IN PHANDLE_ENUM_CONTEXT EnumContext ) /*++ Routine Description: This routine gets called back for each handle in a given process. It examines each handle to see if it is a file object opened against the device object we are looking for. Arguments: ObjectTableEntry - Points to the handle table entry of interest. HandleId - Supplies the handle. EnumContext - Context passed in for the enumeration. Return Value: TRUE if the enumeration should be stopped, FALSE otherwise. --*/ { PDEVICE_OBJECT deviceObject; POBJECT_HEADER objectHeader; PFILE_OBJECT fileObject; objectHeader = OBJECT_FROM_EX_TABLE_ENTRY(ObjectTableEntry); if (objectHeader->Type != IoFileObjectType) { // // Not a file object // return FALSE; } fileObject = (PFILE_OBJECT) &objectHeader->Body; deviceObject = IoGetBaseFileSystemDeviceObject( fileObject ); if (deviceObject != EnumContext->DeviceObject) { // // Not our device object // return FALSE; } // // Found one, invoke the callback! // return (BOOLEAN) EnumContext->CallBack( EnumContext->DeviceObject, EnumContext->Process, fileObject, HandleId, EnumContext->Context ); }