reactos/ntoskrnl/io/iomgr/device.c
Joachim Henze 688875e411 [0.4.7][CDFS_NEW/NTOSKRNL/NDK] Switch from our old CDFS to MS-PL CDFS_NEW
The main motivation to switch to that newer driver is, that our old one
simply can not read all isos. Especially complex ones made trouble and were
only shown as empty in explorer.
It is still possible to build and use the old driver when needed, only thing
that needs to be done for that is to revert 0.4.8-dev-164-g ec6b3ecbe4

Porting back the state up to 0.4.8-release-100-g8f947b5 implies:

Fixing the following JIRA-IDs (or avoid introducing them):
CORE-18029 "Mute noisy DPRINT 'SectionObject has ImageSection'"
CORE-17405 "Fix a macro-copy-paste and shrink the binary size"
CORE-15659 "Unable to build the gcc Release version in Windows using RosBE 2.1.6 (module cdfs fails)"
CORE-14315 "CDFS_NEW assertion during first stage setup due to new CcPerformReadAhead"
CORE-14128 "Avast! Free Antivirus 7.0 hangs the system when trying to detect a newly created virus"
CORE-14067 "CDFS_NEW assertions and exceptions"
CORE-14003 "Shutting down LiveCD asserts since introduction of MS PL CDFS_NEW"
CORE-13184 "Restore ability to install from disk-image"

by picking the following commits:
0.4.8-release-100-g 8f947b5322 [NTOSKRNL] Mute noisy DPRINT 'SectionObject has ImageSection' CORE-18029
0.4.8-release-80-g eb1ea19588 [CDFS_NEW] == 0.4.15-dev-1456-g 889eab7 CORE-17405
0.4.8-release-62-g 8c07aad4a8 [CDFS_NEW/XDK] == 0.4.11-dev-39-g a2f9762 + 0.4.11-dev-40-g 6d7ec8c CORE-14067
0.4.8-release-3-g 5d976d04e8 [CDFS_NEW] == 0.4.12-dev-431-g bccad87f3c + 0.4.12-dev-432-g 3463b2db9f CORE-15659
0.4.8-RC-3-g 51f9494d48 [CDFS_NEW] superseded later by the proper fix 0.4.8-release-62-g 8c07aad4a8 CORE-14067
0.4.8-dev-1069-g a5e89014dc [CDFS_NEW] CORE-14315
0.4.8-dev-475-g a59d4674de [NTOSKRNL] io/iomgr/device.c (forgotten assert) CORE-14128
0.4.8-dev-221-g 9d67a24799 [CDFS_NEW]
0.4.8-dev-220-g 67a7e45e35 [CDFS_NEW/DOC]
0.4.8-dev-219-g 6a3bbf24e0 [CDFS_NEW]
0.4.8-dev-218-g ec26cde4a1 [CDFS_NEW]
0.4.8-dev-217-g bc2378a356 [CDFS_NEW]
0.4.8-dev-216-g 5429771b99 [CDFS_NEW]
0.4.8-dev-215-g fd34548263 [CDFS_NEW] Sync with MS-PL driver
0.4.8-dev-164-g ec6b3ecbe4 [FILESYSTEMS] switch from CDFS to CDFS_NEW in CMakeLists.txt
0.4.8-dev-160-g 2b217e4ecf [NTOSKRNL] Mute spam CcSetReadAheadGranularity()
0.4.8-dev-159-g 64cb138a67 [NTOSKRNL] Mute spam CcPurgeCacheSection()
0.4.8-dev-150-g f723d230a0 [CDFS_NEW]
0.4.8-dev-133-g faee3753ea [CDFS_NEW] CORE-14003
0.4.8-dev-132-g 1d777ffab5 [NTOSKRNL] iofunc.c CORE-14003
0.4.8-dev-131-g c3d5a3f2bd [NTOSKRNL] iofunc.c CORE-14003
0.4.8-dev-130-g 3b64f7f8fb [NTOSKRNL] ob/obref.c & co CORE-14003
0.4.8-dev-129-g 7eefe70294 [NTOSKRNL] io/iomgr.c & co CORE-14003
0.4.8-dev-127-g 5f255827d3 [CDFS_NEW]
0.4.8-dev-126-g 1bef48796e [NTOSKRNL] just a comment, superseded later
0.4.8-dev-125-g cbf0430b56 [CDFS_NEW]
0.4.8-dev-123-g f88fe43abd [NTOSKRNL] io/iomgr/device.c (forbidden DPRINT)
0.4.8-dev-122-g 6c73385625 [CDFS_NEW] CORE-13184
0.4.8-dev-97-g 94298313c0 [CDFS_NEW]
0.4.8-dev-95-g e88eeb21af [CDFS_NEW/NTOSKRNL] CcWaitForCurrentLazyWriterActivity() stub return Success
0.4.8-dev-94-g 03d5be6437 [CDFS_NEW]
0.4.8-dev-93-g fa1c60db50 [CDFS_NEW]
0.4.8-dev-92-g 8b2fd60829 [CDFS_NEW]
0.4.8-dev-91-g e4da7ecc50 [CDFS_NEW]
0.4.8-dev-90-g 7b19676e2b [CDFS_NEW]
0.4.8-dev-89-g 3d4b8783fd [CDFS_NEW]
0.4.8-dev-88-g 818025ecc8 [CDFS_NEW]
0.4.8-dev-87-g 2639dd6736 [CDFS_NEW]
0.4.8-dev-86-g 755bdb5d0b [CDFS_NEW]
0.4.8-dev-85-g 3cbcb1bade [CDFS_NEW]

and mute spam in opcode INSTEAD of picking:
0.4.8-dev-165-g 2284a457a3 [NTOSKRNL] oplock.c Fixup
0.4.8-dev-163-g d3d5853956 [NTOSKRNL] oplock.c Implement oplock-support
0.4.12-dev-232-g f488102c86 [CDFS] was also left out for now

I am aware, that the backport introduces white-space-glitches within CDFS_NEW.
I decided to live with them in favor of better sync to master and newer releases.
2022-01-27 21:11:23 +01:00

1744 lines
51 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/io/iomgr/device.c
* PURPOSE: Device Object Management, including Notifications and Queues.
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Filip Navara (navaraf@reactos.org)
* Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
ULONG IopDeviceObjectNumber = 0;
LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead;
KSPIN_LOCK ShutdownListLock;
extern LIST_ENTRY IopDiskFileSystemQueueHead;
extern LIST_ENTRY IopCdRomFileSystemQueueHead;
extern LIST_ENTRY IopTapeFileSystemQueueHead;
extern ERESOURCE IopDatabaseResource;
/* PRIVATE FUNCTIONS **********************************************************/
VOID
NTAPI
IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver)
{
PDEVICE_OBJECT DeviceObject;
PAGED_CODE();
/* Set the driver as initialized */
Driver->Flags |= DRVO_INITIALIZED;
DeviceObject = Driver->DeviceObject;
while (DeviceObject)
{
/* Set every device as initialized too */
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
DeviceObject = DeviceObject->NextDevice;
}
}
VOID
NTAPI
IopDeleteDevice(IN PVOID ObjectBody)
{
PDEVICE_OBJECT DeviceObject = ObjectBody;
PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
PAGED_CODE();
/* Cleanup and free the device node */
if (DeviceNode)
IopFreeDeviceNode(DeviceNode);
/* Dereference the driver object, referenced in IoCreateDevice */
if (DeviceObject->DriverObject)
ObDereferenceObject(DeviceObject->DriverObject);
}
PDEVICE_OBJECT
NTAPI
IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice,
OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL)
{
PDEVICE_OBJECT AttachedDevice;
PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension;
/* Get the Attached Device and source extension */
AttachedDevice = IoGetAttachedDevice(TargetDevice);
SourceDeviceExtension = IoGetDevObjExtension(SourceDevice);
ASSERT(SourceDeviceExtension->AttachedTo == NULL);
/* Make sure that it's in a correct state */
if ((AttachedDevice->Flags & DO_DEVICE_INITIALIZING) ||
(IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
(DOE_UNLOAD_PENDING |
DOE_DELETE_PENDING |
DOE_REMOVE_PENDING |
DOE_REMOVE_PROCESSED)))
{
/* Device was unloading or being removed */
AttachedDevice = NULL;
}
else
{
/* Update atached device fields */
AttachedDevice->AttachedDevice = SourceDevice;
AttachedDevice->Spare1++;
/* Update the source with the attached data */
SourceDevice->StackSize = AttachedDevice->StackSize + 1;
SourceDevice->AlignmentRequirement = AttachedDevice->
AlignmentRequirement;
SourceDevice->SectorSize = AttachedDevice->SectorSize;
/* Check for pending start flag */
if (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
DOE_START_PENDING)
{
/* Propagate */
IoGetDevObjExtension(SourceDevice)->ExtensionFlags |=
DOE_START_PENDING;
}
/* Set the attachment in the device extension */
SourceDeviceExtension->AttachedTo = AttachedDevice;
}
/* Return the attached device */
if (AttachedToDeviceObject) *AttachedToDeviceObject = AttachedDevice;
return AttachedDevice;
}
VOID
NTAPI
IoShutdownPnpDevices(VOID)
{
/* This routine is only used by Driver Verifier to validate shutdown */
return;
}
VOID
NTAPI
IoShutdownSystem(IN ULONG Phase)
{
PLIST_ENTRY ListEntry;
PDEVICE_OBJECT DeviceObject;
PSHUTDOWN_ENTRY ShutdownEntry;
IO_STATUS_BLOCK StatusBlock;
PIRP Irp;
KEVENT Event;
NTSTATUS Status;
/* Initialize an event to wait on */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* What phase? */
if (Phase == 0)
{
/* Shutdown PnP */
IoShutdownPnpDevices();
/* Loop first-chance shutdown notifications */
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
&ShutdownListLock);
while (ListEntry)
{
/* Get the shutdown entry */
ShutdownEntry = CONTAINING_RECORD(ListEntry,
SHUTDOWN_ENTRY,
ShutdownList);
/* Get the attached device */
DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
/* Build the shutdown IRP and call the driver */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
DeviceObject,
NULL,
0,
NULL,
&Event,
&StatusBlock);
if (Irp)
{
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait on the driver */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
}
}
/* Remove the flag */
ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
/* Get rid of our reference to it */
ObDereferenceObject(ShutdownEntry->DeviceObject);
/* Free the shutdown entry and reset the event */
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
KeClearEvent(&Event);
/* Go to the next entry */
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
&ShutdownListLock);
}
}
else if (Phase == 1)
{
/* Acquire resource forever */
ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE);
/* Shutdown disk file systems */
IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead);
/* Shutdown cdrom file systems */
IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead);
/* Shutdown tape filesystems */
IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead);
/* Loop last-chance shutdown notifications */
ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
&ShutdownListLock);
while (ListEntry)
{
/* Get the shutdown entry */
ShutdownEntry = CONTAINING_RECORD(ListEntry,
SHUTDOWN_ENTRY,
ShutdownList);
/* Get the attached device */
DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
/* Build the shutdown IRP and call the driver */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
DeviceObject,
NULL,
0,
NULL,
&Event,
&StatusBlock);
if (Irp)
{
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait on the driver */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
}
}
/* Remove the flag */
ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
/* Get rid of our reference to it */
ObDereferenceObject(ShutdownEntry->DeviceObject);
/* Free the shutdown entry and reset the event */
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
KeClearEvent(&Event);
/* Go to the next entry */
ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
&ShutdownListLock);
}
}
}
NTSTATUS
NTAPI
IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
IN ACCESS_MASK DesiredAccess,
OUT PFILE_OBJECT *FileObject,
OUT PDEVICE_OBJECT *DeviceObject,
IN ULONG AttachFlag)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK StatusBlock;
PFILE_OBJECT LocalFileObject;
HANDLE FileHandle;
NTSTATUS Status;
/* Open the Device */
InitializeObjectAttributes(&ObjectAttributes,
ObjectName,
OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = ZwOpenFile(&FileHandle,
DesiredAccess,
&ObjectAttributes,
&StatusBlock,
0,
FILE_NON_DIRECTORY_FILE | AttachFlag);
if (!NT_SUCCESS(Status)) return Status;
/* Get File Object */
Status = ObReferenceObjectByHandle(FileHandle,
0,
IoFileObjectType,
KernelMode,
(PVOID*)&LocalFileObject,
NULL);
if (NT_SUCCESS(Status))
{
/* Return the requested data */
*DeviceObject = IoGetRelatedDeviceObject(LocalFileObject);
*FileObject = LocalFileObject;
}
/* Close the handle */
ZwClose(FileHandle);
return Status;
}
PDEVICE_OBJECT
NTAPI
IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject)
{
PDEVICE_OBJECT LowestDevice;
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
/* Get the current device and its extension */
LowestDevice = DeviceObject;
DeviceExtension = IoGetDevObjExtension(LowestDevice);
/* Keep looping as long as we're attached */
while (DeviceExtension->AttachedTo)
{
/* Get the lowest device and its extension */
LowestDevice = DeviceExtension->AttachedTo;
DeviceExtension = IoGetDevObjExtension(LowestDevice);
}
/* Return the lowest device */
return LowestDevice;
}
VOID
NTAPI
IopEditDeviceList(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject,
IN IOP_DEVICE_LIST_OPERATION Type)
{
PDEVICE_OBJECT Previous;
KIRQL OldIrql;
/* Lock the Device list while we edit it */
OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
/* Check the type of operation */
if (Type == IopRemove)
{
/* Get the current device and check if it's the current one */
Previous = DeviceObject->DriverObject->DeviceObject;
if (Previous == DeviceObject)
{
/* It is, simply unlink this one directly */
DeviceObject->DriverObject->DeviceObject =
DeviceObject->NextDevice;
}
else
{
/* It's not, so loop until we find the device */
while (Previous->NextDevice != DeviceObject)
{
/* Not this one, keep moving */
if (!Previous->NextDevice)
{
DPRINT1("Failed to remove PDO %p (not found)\n",
DeviceObject);
ASSERT(FALSE);
KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
return;
}
Previous = Previous->NextDevice;
}
/* We found it, now unlink us */
Previous->NextDevice = DeviceObject->NextDevice;
}
}
else
{
/* Link the device object and the driver object */
DeviceObject->NextDevice = DriverObject->DeviceObject;
DriverObject->DeviceObject = DeviceObject;
}
/* Release the device list lock */
KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
}
VOID
NTAPI
IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject)
{
PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject;
PEXTENDED_DEVOBJ_EXTENSION ThisExtension = IoGetDevObjExtension(DeviceObject);
/* Check if deletion is pending */
if (ThisExtension->ExtensionFlags & DOE_DELETE_PENDING)
{
if (DeviceObject->AttachedDevice)
{
DPRINT("Device object is in the middle of a device stack\n");
return;
}
if (DeviceObject->ReferenceCount)
{
DPRINT("Device object still has %d references\n", DeviceObject->ReferenceCount);
return;
}
/* Check if we have a Security Descriptor */
if (DeviceObject->SecurityDescriptor)
{
/* Dereference it */
ObDereferenceSecurityDescriptor(DeviceObject->SecurityDescriptor, 1);
}
/* Remove the device from the list */
IopEditDeviceList(DeviceObject->DriverObject, DeviceObject, IopRemove);
/* Dereference the keep-alive */
ObDereferenceObject(DeviceObject);
}
/* We can't unload a non-PnP driver here */
if (DriverObject->Flags & DRVO_LEGACY_DRIVER)
{
DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
return;
}
/* Return if we've already called unload (maybe we're in it?) */
if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) return;
/* We can't unload unless there's an unload handler */
if (!DriverObject->DriverUnload)
{
DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
return;
}
/* Bail if there are still devices present */
if (DriverObject->DeviceObject)
{
DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
return;
}
DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject->DriverName);
/* Set the unload invoked flag */
DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
/* Unload it */
DriverObject->DriverUnload(DriverObject);
/* Make object temporary so it can be deleted */
ObMakeTemporaryObject(DriverObject);
}
VOID
NTAPI
IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN ForceUnload)
{
/* Sanity check */
ASSERT(DeviceObject->ReferenceCount);
/* Dereference the device */
InterlockedDecrement(&DeviceObject->ReferenceCount);
/*
* Check if we can unload it and it's safe to unload (or if we're forcing
* an unload, which is OK too).
*/
ASSERT(!ForceUnload);
if (!(DeviceObject->ReferenceCount) &&
(IoGetDevObjExtension(DeviceObject)->ExtensionFlags & DOE_DELETE_PENDING))
{
/* Unload it */
IopUnloadDevice(DeviceObject);
}
}
VOID
NTAPI
IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN Cancelable,
IN ULONG Key)
{
PKDEVICE_QUEUE_ENTRY Entry;
PIRP Irp;
KIRQL OldIrql;
/* Acquire the cancel lock if this is cancelable */
if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
/* Clear the current IRP */
DeviceObject->CurrentIrp = NULL;
/* Remove an entry from the queue */
Entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue, Key);
if (Entry)
{
/* Get the IRP and set it */
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
DeviceObject->CurrentIrp = Irp;
/* Check if this is a cancelable packet */
if (Cancelable)
{
/* Check if the caller requested no cancellation */
if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
DOE_SIO_NO_CANCEL)
{
/* He did, so remove the cancel routine */
Irp->CancelRoutine = NULL;
}
/* Release the cancel lock */
IoReleaseCancelSpinLock(OldIrql);
}
/* Call the Start I/O Routine */
DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
}
else
{
/* Otherwise, release the cancel lock if we had acquired it */
if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
}
}
VOID
NTAPI
IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN Cancelable)
{
PKDEVICE_QUEUE_ENTRY Entry;
PIRP Irp;
KIRQL OldIrql;
/* Acquire the cancel lock if this is cancelable */
if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
/* Clear the current IRP */
DeviceObject->CurrentIrp = NULL;
/* Remove an entry from the queue */
Entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue);
if (Entry)
{
/* Get the IRP and set it */
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
DeviceObject->CurrentIrp = Irp;
/* Check if this is a cancelable packet */
if (Cancelable)
{
/* Check if the caller requested no cancellation */
if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
DOE_SIO_NO_CANCEL)
{
/* He did, so remove the cancel routine */
Irp->CancelRoutine = NULL;
}
/* Release the cancel lock */
IoReleaseCancelSpinLock(OldIrql);
}
/* Call the Start I/O Routine */
DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
}
else
{
/* Otherwise, release the cancel lock if we had acquired it */
if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
}
}
VOID
NTAPI
IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject,
IN ULONG Key,
IN ULONG Flags)
{
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
ULONG CurrentKey = Key;
ULONG CurrentFlags = Flags;
/* Get the device extension and start the packet loop */
DeviceExtension = IoGetDevObjExtension(DeviceObject);
while (TRUE)
{
/* Increase the count */
if (InterlockedIncrement(&DeviceExtension->StartIoCount) > 1)
{
/*
* We've already called the routine once...
* All we have to do is save the key and add the new flags
*/
DeviceExtension->StartIoFlags |= CurrentFlags;
DeviceExtension->StartIoKey = CurrentKey;
}
else
{
/* Mask out the current packet flags and key */
DeviceExtension->StartIoFlags &= ~(DOE_SIO_WITH_KEY |
DOE_SIO_NO_KEY |
DOE_SIO_CANCELABLE);
DeviceExtension->StartIoKey = 0;
/* Check if this is a packet start with key */
if (Flags & DOE_SIO_WITH_KEY)
{
/* Start the packet with a key */
IopStartNextPacketByKey(DeviceObject,
(Flags & DOE_SIO_CANCELABLE) ?
TRUE : FALSE,
CurrentKey);
}
else if (Flags & DOE_SIO_NO_KEY)
{
/* Start the packet */
IopStartNextPacket(DeviceObject,
(Flags & DOE_SIO_CANCELABLE) ?
TRUE : FALSE);
}
}
/* Decrease the Start I/O count and check if it's 0 now */
if (!InterlockedDecrement(&DeviceExtension->StartIoCount))
{
/* Get the current active key and flags */
CurrentKey = DeviceExtension->StartIoKey;
CurrentFlags = DeviceExtension->StartIoFlags & (DOE_SIO_WITH_KEY |
DOE_SIO_NO_KEY |
DOE_SIO_CANCELABLE);
/* Check if we should still loop */
if (!(CurrentFlags & (DOE_SIO_WITH_KEY | DOE_SIO_NO_KEY))) break;
}
else
{
/* There are still Start I/Os active, so quit this loop */
break;
}
}
}
NTSTATUS
NTAPI
IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
OUT PDEVICE_NODE *DeviceNode)
{
NTSTATUS Status;
IO_STACK_LOCATION Stack = {0};
PDEVICE_RELATIONS DeviceRelations;
PDEVICE_OBJECT DeviceObject = NULL;
ASSERT(FileObject);
/* Get DeviceObject related to given FileObject */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
if (!DeviceObject) return STATUS_NO_SUCH_DEVICE;
/* Define input parameters */
Stack.MajorFunction = IRP_MJ_PNP;
Stack.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
Stack.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
Stack.FileObject = FileObject;
/* Call the driver to query all relations (IRP_MJ_PNP) */
Status = IopSynchronousCall(DeviceObject,
&Stack,
(PVOID)&DeviceRelations);
if (!NT_SUCCESS(Status)) return Status;
/* Make sure it's not NULL and contains only one object */
ASSERT(DeviceRelations);
ASSERT(DeviceRelations->Count == 1);
/* Finally get the device node */
*DeviceNode = IopGetDeviceNode(DeviceRelations->Objects[0]);
if (!*DeviceNode) Status = STATUS_NO_SUCH_DEVICE;
/* Free the DEVICE_RELATIONS structure, it's not needed anymore */
ExFreePool(DeviceRelations);
return Status;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* IoAttachDevice
*
* Layers a device over the highest device in a device stack.
*
* Parameters
* SourceDevice
* Device to be attached.
*
* TargetDevice
* Name of the target device.
*
* AttachedDevice
* Caller storage for the device attached to.
*
* Status
* @implemented
*/
NTSTATUS
NTAPI
IoAttachDevice(PDEVICE_OBJECT SourceDevice,
PUNICODE_STRING TargetDeviceName,
PDEVICE_OBJECT *AttachedDevice)
{
NTSTATUS Status;
PFILE_OBJECT FileObject = NULL;
PDEVICE_OBJECT TargetDevice = NULL;
/* Call the helper routine for an attach operation */
Status = IopGetDeviceObjectPointer(TargetDeviceName,
FILE_READ_ATTRIBUTES,
&FileObject,
&TargetDevice,
IO_ATTACH_DEVICE_API);
if (!NT_SUCCESS(Status)) return Status;
/* Attach the device */
Status = IoAttachDeviceToDeviceStackSafe(SourceDevice,
TargetDevice,
AttachedDevice);
/* Dereference it */
ObDereferenceObject(FileObject);
return Status;
}
/*
* IoAttachDeviceByPointer
*
* Status
* @implemented
*/
NTSTATUS
NTAPI
IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice)
{
PDEVICE_OBJECT AttachedDevice;
NTSTATUS Status = STATUS_SUCCESS;
/* Do the Attach */
AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice);
if (!AttachedDevice) Status = STATUS_NO_SUCH_DEVICE;
/* Return the status */
return Status;
}
/*
* @implemented
*/
PDEVICE_OBJECT
NTAPI
IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice)
{
/* Attach it safely */
return IopAttachDeviceToDeviceStackSafe(SourceDevice,
TargetDevice,
NULL);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice,
IN OUT PDEVICE_OBJECT *AttachedToDeviceObject)
{
/* Call the internal function */
if (!IopAttachDeviceToDeviceStackSafe(SourceDevice,
TargetDevice,
AttachedToDeviceObject))
{
/* Nothing found */
return STATUS_NO_SUCH_DEVICE;
}
/* Success! */
return STATUS_SUCCESS;
}
/*
* IoCreateDevice
*
* Allocates memory for and intializes a device object for use for
* a driver.
*
* Parameters
* DriverObject
* Driver object passed by IO Manager when the driver was loaded.
*
* DeviceExtensionSize
* Number of bytes for the device extension.
*
* DeviceName
* Unicode name of device.
*
* DeviceType
* Device type of the new device.
*
* DeviceCharacteristics
* Bit mask of device characteristics.
*
* Exclusive
* TRUE if only one thread can access the device at a time.
*
* DeviceObject
* On successful return this parameter is filled by pointer to
* allocated device object.
*
* Status
* @implemented
*/
NTSTATUS
NTAPI
IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject)
{
WCHAR AutoNameBuffer[20];
UNICODE_STRING AutoName;
PDEVICE_OBJECT CreatedDeviceObject;
PDEVOBJ_EXTENSION DeviceObjectExtension;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
ULONG AlignedDeviceExtensionSize;
ULONG TotalSize;
HANDLE TempHandle;
PAGED_CODE();
/* Check if we have to generate a name */
if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME)
{
/* Generate it */
swprintf(AutoNameBuffer,
L"\\Device\\%08lx",
InterlockedIncrementUL(&IopDeviceObjectNumber));
/* Initialize the name */
RtlInitUnicodeString(&AutoName, AutoNameBuffer);
DeviceName = &AutoName;
}
/* Initialize the Object Attributes */
InitializeObjectAttributes(&ObjectAttributes,
DeviceName,
OBJ_KERNEL_HANDLE,
NULL,
SePublicOpenUnrestrictedSd);
/* Honor exclusive flag */
if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE;
/* Create a permanent object for named devices */
if (DeviceName) ObjectAttributes.Attributes |= OBJ_PERMANENT;
/* Align the Extension Size to 8-bytes */
AlignedDeviceExtensionSize = (DeviceExtensionSize + 7) &~ 7;
/* Total Size */
TotalSize = AlignedDeviceExtensionSize +
sizeof(DEVICE_OBJECT) +
sizeof(EXTENDED_DEVOBJ_EXTENSION);
/* Create the Device Object */
*DeviceObject = NULL;
Status = ObCreateObject(KernelMode,
IoDeviceObjectType,
&ObjectAttributes,
KernelMode,
NULL,
TotalSize,
0,
0,
(PVOID*)&CreatedDeviceObject);
if (!NT_SUCCESS(Status)) return Status;
/* Clear the whole Object and extension so we don't null stuff manually */
RtlZeroMemory(CreatedDeviceObject, TotalSize);
/*
* Setup the Type and Size. Note that we don't use the aligned size,
* because that's only padding for the DevObjExt and not part of the Object.
*/
CreatedDeviceObject->Type = IO_TYPE_DEVICE;
CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize;
/* The kernel extension is after the driver internal extension */
DeviceObjectExtension = (PDEVOBJ_EXTENSION)
((ULONG_PTR)(CreatedDeviceObject + 1) +
AlignedDeviceExtensionSize);
/* Set the Type and Size. Question: why is Size 0 on Windows? */
DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
DeviceObjectExtension->Size = 0;
/* Initialize with Power Manager */
PoInitializeDeviceObject(DeviceObjectExtension);
/* Link the Object and Extension */
DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
/* Set Device Object Data */
CreatedDeviceObject->DeviceType = DeviceType;
CreatedDeviceObject->Characteristics = DeviceCharacteristics;
CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ?
CreatedDeviceObject + 1 :
NULL;
CreatedDeviceObject->StackSize = 1;
CreatedDeviceObject->AlignmentRequirement = 0;
/* Set the Flags */
CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING;
if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE;
if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME;
/* Attach a Vpb for Disks and Tapes, and create the Device Lock */
if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE))
{
/* Create Vpb */
Status = IopCreateVpb(CreatedDeviceObject);
if (!NT_SUCCESS(Status))
{
/* Dereference the device object and fail */
ObDereferenceObject(CreatedDeviceObject);
return Status;
}
/* Initialize Lock Event */
KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
SynchronizationEvent,
TRUE);
}
/* Set the right Sector Size */
switch (DeviceType)
{
/* All disk systems */
case FILE_DEVICE_DISK_FILE_SYSTEM:
case FILE_DEVICE_DISK:
case FILE_DEVICE_VIRTUAL_DISK:
/* The default is 512 bytes */
CreatedDeviceObject->SectorSize = 512;
break;
/* CD-ROM file systems */
case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
/* The default is 2048 bytes */
CreatedDeviceObject->SectorSize = 2048;
}
/* Create the Device Queue */
if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM))
{
/* Simple FS Devices, they don't need a real Device Queue */
InitializeListHead(&CreatedDeviceObject->Queue.ListEntry);
}
else
{
/* An actual Device, initialize its DQ */
KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
}
/* Insert the Object */
Status = ObInsertObject(CreatedDeviceObject,
NULL,
FILE_READ_DATA | FILE_WRITE_DATA,
1,
(PVOID*)&CreatedDeviceObject,
&TempHandle);
if (!NT_SUCCESS(Status)) return Status;
/* Now do the final linking */
ObReferenceObject(DriverObject);
ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
CreatedDeviceObject->DriverObject = DriverObject;
IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
/* Link with the power manager */
if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
/* Close the temporary handle and return to caller */
ObCloseHandle(TempHandle, KernelMode);
*DeviceObject = CreatedDeviceObject;
return STATUS_SUCCESS;
}
/*
* IoDeleteDevice
*
* Status
* @implemented
*/
VOID
NTAPI
IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)
{
PIO_TIMER Timer;
/* Check if the device is registered for shutdown notifications */
if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
{
/* Call the shutdown notifications */
IoUnregisterShutdownNotification(DeviceObject);
}
/* Check if it has a timer */
Timer = DeviceObject->Timer;
if (Timer)
{
/* Remove it and free it */
IopRemoveTimerFromTimerList(Timer);
ExFreePoolWithTag(Timer, TAG_IO_TIMER);
}
/* Check if the device has a name */
if (DeviceObject->Flags & DO_DEVICE_HAS_NAME)
{
/* It does, make it temporary so we can remove it */
ObMakeTemporaryObject(DeviceObject);
}
/* Set the pending delete flag */
IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING;
/* Unlink with the power manager */
if (DeviceObject->Vpb) PoRemoveVolumeDevice(DeviceObject);
/* Check if the device object can be unloaded */
if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject);
}
/*
* IoDetachDevice
*
* Status
* @implemented
*/
VOID
NTAPI
IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
{
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
/* Sanity check */
DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice);
ASSERT(DeviceExtension->AttachedTo == TargetDevice);
/* Remove the attachment */
DeviceExtension->AttachedTo = NULL;
TargetDevice->AttachedDevice = NULL;
/* Check if it's ok to delete this device */
if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) &&
!(TargetDevice->ReferenceCount))
{
/* It is, do it */
IopUnloadDevice(TargetDevice);
}
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT *DeviceObjectList,
IN ULONG DeviceObjectListSize,
OUT PULONG ActualNumberDeviceObjects)
{
ULONG ActualDevices = 1;
PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject;
KIRQL OldIrql;
/* Lock the Device list while we enumerate it */
OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
/* Find out how many devices we'll enumerate */
while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++;
/* Go back to the first */
CurrentDevice = DriverObject->DeviceObject;
/* Start by at least returning this */
*ActualNumberDeviceObjects = ActualDevices;
/* Check if we can support so many */
if ((ActualDevices * sizeof(PDEVICE_OBJECT)) > DeviceObjectListSize)
{
/* Fail because the buffer was too small */
KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
return STATUS_BUFFER_TOO_SMALL;
}
/* Check if the caller wanted the device list */
if (DeviceObjectList)
{
/* Loop through all the devices */
while (ActualDevices)
{
/* Reference each Device */
ObReferenceObject(CurrentDevice);
/* Add it to the list */
*DeviceObjectList = CurrentDevice;
/* Go to the next one */
CurrentDevice = CurrentDevice->NextDevice;
ActualDevices--;
DeviceObjectList++;
}
}
/* Release the device list lock */
KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
/* Return the status */
return STATUS_SUCCESS;
}
/*
* IoGetAttachedDevice
*
* Status
* @implemented
*/
PDEVICE_OBJECT
NTAPI
IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
{
/* Get the last attached device */
while (DeviceObject->AttachedDevice)
{
/* Move to the next one */
DeviceObject = DeviceObject->AttachedDevice;
}
/* Return it */
return DeviceObject;
}
/*
* IoGetAttachedDeviceReference
*
* Status
* @implemented
*/
PDEVICE_OBJECT
NTAPI
IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
{
/* Reference the Attached Device */
DeviceObject = IoGetAttachedDevice(DeviceObject);
ObReferenceObject(DeviceObject);
return DeviceObject;
}
/*
* @implemented
*/
PDEVICE_OBJECT
NTAPI
IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject)
{
/* Reference the lowest attached device */
DeviceObject = IopGetLowestDevice(DeviceObject);
ObReferenceObject(DeviceObject);
return DeviceObject;
}
/*
* IoGetDeviceObjectPointer
*
* Status
* @implemented
*/
NTSTATUS
NTAPI
IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
IN ACCESS_MASK DesiredAccess,
OUT PFILE_OBJECT *FileObject,
OUT PDEVICE_OBJECT *DeviceObject)
{
/* Call the helper routine for a normal operation */
return IopGetDeviceObjectPointer(ObjectName,
DesiredAccess,
FileObject,
DeviceObject,
0);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject,
OUT PDEVICE_OBJECT *DiskDeviceObject)
{
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
PVPB Vpb;
KIRQL OldIrql;
NTSTATUS Status;
/* Make sure there's a VPB */
if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER;
/* Acquire it */
IoAcquireVpbSpinLock(&OldIrql);
/* Get the Device Extension */
DeviceExtension = IoGetDevObjExtension(FileSystemDeviceObject);
/* Make sure this one has a VPB too */
Vpb = DeviceExtension->Vpb;
if (Vpb)
{
/* Make sure that it's mounted */
if ((Vpb->ReferenceCount) &&
(Vpb->Flags & VPB_MOUNTED))
{
/* Return the Disk Device Object */
*DiskDeviceObject = Vpb->RealDevice;
/* Reference it and return success */
ObReferenceObject(Vpb->RealDevice);
Status = STATUS_SUCCESS;
}
else
{
/* It's not, so return failure */
Status = STATUS_VOLUME_DISMOUNTED;
}
}
else
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
/* Release the lock */
IoReleaseVpbSpinLock(OldIrql);
return Status;
}
/*
* @implemented
*/
PDEVICE_OBJECT
NTAPI
IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)
{
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
PDEVICE_OBJECT LowerDeviceObject = NULL;
/* Make sure it's not getting deleted */
DeviceExtension = IoGetDevObjExtension(DeviceObject);
if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING |
DOE_DELETE_PENDING |
DOE_REMOVE_PENDING |
DOE_REMOVE_PROCESSED)))
{
/* Get the Lower Device Object */
LowerDeviceObject = DeviceExtension->AttachedTo;
/* Check that we got a valid device object */
if (LowerDeviceObject)
{
/* We did so let's reference it */
ObReferenceObject(LowerDeviceObject);
}
}
/* Return it */
return LowerDeviceObject;
}
/*
* @implemented
*/
PDEVICE_OBJECT
NTAPI
IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject)
{
PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
/* Check if we have a VPB with a device object */
if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
{
/* Then use the DO from the VPB */
ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
DeviceObject = FileObject->Vpb->DeviceObject;
}
else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
(FileObject->DeviceObject->Vpb) &&
(FileObject->DeviceObject->Vpb->DeviceObject))
{
/* The disk device actually has a VPB, so get the DO from there */
DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
}
else
{
/* Otherwise, this was a direct open */
DeviceObject = FileObject->DeviceObject;
}
/* Sanity check */
ASSERT(DeviceObject != NULL);
/* Check if we were attached */
if (DeviceObject->AttachedDevice)
{
/* Check if the file object has an extension present */
if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
{
/* Sanity check, direct open files can't have this */
ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
/* Check if the extension is really present */
if (FileObject->FileObjectExtension)
{
PFILE_OBJECT_EXTENSION FileObjectExtension;
/* Cast the buffer to something we understand */
FileObjectExtension = FileObject->FileObjectExtension;
/* Check if have a replacement top level device */
if (FileObjectExtension->TopDeviceObjectHint)
{
/* Use this instead of returning the top level device */
return FileObjectExtension->TopDeviceObjectHint;
}
}
}
/* Return the highest attached device */
DeviceObject = IoGetAttachedDevice(DeviceObject);
}
/* Return the DO we found */
return DeviceObject;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
OUT PDEVICE_OBJECT *DeviceObject)
{
NTSTATUS Status;
PDEVICE_NODE DeviceNode = NULL;
/* Call the internal helper function */
Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode);
if (NT_SUCCESS(Status) && DeviceNode)
{
*DeviceObject = DeviceNode->PhysicalDeviceObject;
}
return Status;
}
/*
* @implemented
*/
PDEVICE_OBJECT
NTAPI
IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
{
PDEVICE_OBJECT DeviceObject;
/*
* If the FILE_OBJECT's VPB is defined,
* get the device from it.
*/
if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
{
/* Use the VPB's Device Object's */
DeviceObject = FileObject->Vpb->DeviceObject;
}
else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
(FileObject->DeviceObject->Vpb) &&
(FileObject->DeviceObject->Vpb->DeviceObject))
{
/* Use the VPB's File System Object */
DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
}
else
{
/* Use the FO's Device Object */
DeviceObject = FileObject->DeviceObject;
}
/* Return the device object we found */
ASSERT(DeviceObject != NULL);
return DeviceObject;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
{
PSHUTDOWN_ENTRY Entry;
/* Allocate the shutdown entry */
Entry = ExAllocatePoolWithTag(NonPagedPool,
sizeof(SHUTDOWN_ENTRY),
TAG_SHUTDOWN_ENTRY);
if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
/* Set the DO */
Entry->DeviceObject = DeviceObject;
/* Reference it so it doesn't go away */
ObReferenceObject(DeviceObject);
/* Insert it into the list */
ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
&Entry->ShutdownList,
&ShutdownListLock);
/* Set the shutdown registered flag */
DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
{
PSHUTDOWN_ENTRY Entry;
/* Allocate the shutdown entry */
Entry = ExAllocatePoolWithTag(NonPagedPool,
sizeof(SHUTDOWN_ENTRY),
TAG_SHUTDOWN_ENTRY);
if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
/* Set the DO */
Entry->DeviceObject = DeviceObject;
/* Reference it so it doesn't go away */
ObReferenceObject(DeviceObject);
/* Insert it into the list */
ExInterlockedInsertHeadList(&ShutdownListHead,
&Entry->ShutdownList,
&ShutdownListLock);
/* Set the shutdown registered flag */
DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
NTAPI
IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
{
PSHUTDOWN_ENTRY ShutdownEntry;
PLIST_ENTRY NextEntry;
KIRQL OldIrql;
/* Remove the flag */
DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
/* Acquire the shutdown lock and loop the shutdown list */
KeAcquireSpinLock(&ShutdownListLock, &OldIrql);
NextEntry = ShutdownListHead.Flink;
while (NextEntry != &ShutdownListHead)
{
/* Get the entry */
ShutdownEntry = CONTAINING_RECORD(NextEntry,
SHUTDOWN_ENTRY,
ShutdownList);
/* Get if the DO matches */
if (ShutdownEntry->DeviceObject == DeviceObject)
{
/* Remove it from the list */
RemoveEntryList(NextEntry);
NextEntry = NextEntry->Blink;
/* Free the entry */
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
/* Get rid of our reference to it */
ObDereferenceObject(DeviceObject);
}
/* Go to the next entry */
NextEntry = NextEntry->Flink;
}
/* Now loop the last chance list */
NextEntry = LastChanceShutdownListHead.Flink;
while (NextEntry != &LastChanceShutdownListHead)
{
/* Get the entry */
ShutdownEntry = CONTAINING_RECORD(NextEntry,
SHUTDOWN_ENTRY,
ShutdownList);
/* Get if the DO matches */
if (ShutdownEntry->DeviceObject == DeviceObject)
{
/* Remove it from the list */
RemoveEntryList(NextEntry);
NextEntry = NextEntry->Blink;
/* Free the entry */
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
/* Get rid of our reference to it */
ObDereferenceObject(DeviceObject);
}
/* Go to the next entry */
NextEntry = NextEntry->Flink;
}
/* Release the shutdown lock */
KeReleaseSpinLock(&ShutdownListLock, OldIrql);
}
/*
* @implemented
*/
VOID
NTAPI
IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN DeferredStartIo,
IN BOOLEAN NonCancelable)
{
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
/* Get the Device Extension */
DeviceExtension = IoGetDevObjExtension(DeviceObject);
/* Set the flags the caller requested */
DeviceExtension->StartIoFlags |= (DeferredStartIo) ? DOE_SIO_DEFERRED : 0;
DeviceExtension->StartIoFlags |= (NonCancelable) ? DOE_SIO_NO_CANCEL : 0;
}
/*
* @implemented
*/
VOID
NTAPI
IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN Cancelable,
IN ULONG Key)
{
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
/* Get the Device Extension */
DeviceExtension = IoGetDevObjExtension(DeviceObject);
/* Check if deferred start was requested */
if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
{
/* Call our internal function to handle the defered case */
IopStartNextPacketByKeyEx(DeviceObject,
Key,
DOE_SIO_WITH_KEY |
(Cancelable ? DOE_SIO_CANCELABLE : 0));
}
else
{
/* Call the normal routine */
IopStartNextPacketByKey(DeviceObject, Cancelable, Key);
}
}
/*
* @implemented
*/
VOID
NTAPI
IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN Cancelable)
{
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
/* Get the Device Extension */
DeviceExtension = IoGetDevObjExtension(DeviceObject);
/* Check if deferred start was requested */
if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
{
/* Call our internal function to handle the defered case */
IopStartNextPacketByKeyEx(DeviceObject,
0,
DOE_SIO_NO_KEY |
(Cancelable ? DOE_SIO_CANCELABLE : 0));
}
else
{
/* Call the normal routine */
IopStartNextPacket(DeviceObject, Cancelable);
}
}
/*
* @implemented
*/
VOID
NTAPI
IoStartPacket(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PULONG Key,
IN PDRIVER_CANCEL CancelFunction)
{
BOOLEAN Stat;
KIRQL OldIrql, CancelIrql;
/* Raise to dispatch level */
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
/* Check if we should acquire the cancel lock */
if (CancelFunction)
{
/* Acquire and set it */
IoAcquireCancelSpinLock(&CancelIrql);
Irp->CancelRoutine = CancelFunction;
}
/* Check if we have a key */
if (Key)
{
/* Insert by key */
Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry,
*Key);
}
else
{
/* Insert without a key */
Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry);
}
/* Check if this was a first insert */
if (!Stat)
{
/* Set the IRP */
DeviceObject->CurrentIrp = Irp;
/* Check if this is a cancelable packet */
if (CancelFunction)
{
/* Check if the caller requested no cancellation */
if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
DOE_SIO_NO_CANCEL)
{
/* He did, so remove the cancel routine */
Irp->CancelRoutine = NULL;
}
/* Release the cancel lock */
IoReleaseCancelSpinLock(CancelIrql);
}
/* Call the Start I/O function */
DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
}
else
{
/* The packet was inserted... check if we have a cancel function */
if (CancelFunction)
{
/* Check if the IRP got cancelled */
if (Irp->Cancel)
{
/*
* Set the cancel IRQL, clear the currnet cancel routine and
* call ours
*/
Irp->CancelIrql = CancelIrql;
Irp->CancelRoutine = NULL;
CancelFunction(DeviceObject, Irp);
}
else
{
/* Otherwise, release the lock */
IoReleaseCancelSpinLock(CancelIrql);
}
}
}
/* Return back to previous IRQL */
KeLowerIrql(OldIrql);
}
#if defined (_WIN64)
ULONG
NTAPI
IoWMIDeviceObjectToProviderId(
IN PDEVICE_OBJECT DeviceObject)
{
UNIMPLEMENTED;
return 0;
}
#endif
/* EOF */