2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/device.c
5 * PURPOSE: Device Object Management, including Notifications and Queues.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
12 /* INCLUDES *******************************************************************/
18 /* GLOBALS ********************************************************************/
20 ULONG IopDeviceObjectNumber
= 0;
21 LIST_ENTRY ShutdownListHead
, LastChanceShutdownListHead
;
22 KSPIN_LOCK ShutdownListLock
;
23 extern LIST_ENTRY IopDiskFileSystemQueueHead
;
24 extern LIST_ENTRY IopCdRomFileSystemQueueHead
;
25 extern LIST_ENTRY IopTapeFileSystemQueueHead
;
26 extern ERESOURCE IopDatabaseResource
;
30 /* PRIVATE FUNCTIONS **********************************************************/
34 IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver
)
36 PDEVICE_OBJECT DeviceObject
;
39 /* Set the driver as initialized */
40 Driver
->Flags
|= DRVO_INITIALIZED
;
41 DeviceObject
= Driver
->DeviceObject
;
44 /* Set every device as initialized too */
45 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
46 DeviceObject
= DeviceObject
->NextDevice
;
52 IopDeleteDevice(IN PVOID ObjectBody
)
54 PDEVICE_OBJECT DeviceObject
= ObjectBody
;
55 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
58 /* Cleanup and free the device node */
60 IopFreeDeviceNode(DeviceNode
);
62 /* Dereference the driver object, referenced in IoCreateDevice */
63 if (DeviceObject
->DriverObject
)
64 ObDereferenceObject(DeviceObject
->DriverObject
);
70 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
71 IN PDEVICE_OBJECT TargetDevice
,
72 OUT PDEVICE_OBJECT
*AttachedToDeviceObject OPTIONAL
)
74 PDEVICE_OBJECT AttachedDevice
;
75 PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension
;
77 /* Get the Attached Device and source extension */
78 AttachedDevice
= IoGetAttachedDevice(TargetDevice
);
79 SourceDeviceExtension
= IoGetDevObjExtension(SourceDevice
);
80 ASSERT(SourceDeviceExtension
->AttachedTo
== NULL
);
82 /* Make sure that it's in a correct state */
83 if ((AttachedDevice
->Flags
& DO_DEVICE_INITIALIZING
) ||
84 (IoGetDevObjExtension(AttachedDevice
)->ExtensionFlags
&
88 DOE_REMOVE_PROCESSED
)))
90 /* Device was unloading or being removed */
91 AttachedDevice
= NULL
;
95 /* Update atached device fields */
96 AttachedDevice
->AttachedDevice
= SourceDevice
;
97 AttachedDevice
->Spare1
++;
99 /* Update the source with the attached data */
100 SourceDevice
->StackSize
= AttachedDevice
->StackSize
+ 1;
101 SourceDevice
->AlignmentRequirement
= AttachedDevice
->
102 AlignmentRequirement
;
103 SourceDevice
->SectorSize
= AttachedDevice
->SectorSize
;
105 /* Check for pending start flag */
106 if (IoGetDevObjExtension(AttachedDevice
)->ExtensionFlags
&
110 IoGetDevObjExtension(SourceDevice
)->ExtensionFlags
|=
114 /* Set the attachment in the device extension */
115 SourceDeviceExtension
->AttachedTo
= AttachedDevice
;
118 /* Return the attached device */
119 if (AttachedToDeviceObject
) *AttachedToDeviceObject
= AttachedDevice
;
120 return AttachedDevice
;
125 IoShutdownPnpDevices(VOID
)
127 /* This routine is only used by Driver Verifier to validate shutdown */
133 IoShutdownSystem(IN ULONG Phase
)
135 PLIST_ENTRY ListEntry
;
136 PDEVICE_OBJECT DeviceObject
;
137 PSHUTDOWN_ENTRY ShutdownEntry
;
138 IO_STATUS_BLOCK StatusBlock
;
143 /* Initialize an event to wait on */
144 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
150 IoShutdownPnpDevices();
152 /* Loop first-chance shutdown notifications */
153 ListEntry
= ExInterlockedRemoveHeadList(&ShutdownListHead
,
157 /* Get the shutdown entry */
158 ShutdownEntry
= CONTAINING_RECORD(ListEntry
,
162 /* Get the attached device */
163 DeviceObject
= IoGetAttachedDevice(ShutdownEntry
->DeviceObject
);
165 /* Build the shutdown IRP and call the driver */
166 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
175 Status
= IoCallDriver(DeviceObject
, Irp
);
176 if (Status
== STATUS_PENDING
)
178 /* Wait on the driver */
179 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
183 /* Remove the flag */
184 ShutdownEntry
->DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
186 /* Get rid of our reference to it */
187 ObDereferenceObject(ShutdownEntry
->DeviceObject
);
189 /* Free the shutdown entry and reset the event */
190 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
191 KeClearEvent(&Event
);
193 /* Go to the next entry */
194 ListEntry
= ExInterlockedRemoveHeadList(&ShutdownListHead
,
200 /* Acquire resource forever */
201 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
203 /* Shutdown disk file systems */
204 IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead
);
206 /* Shutdown cdrom file systems */
207 IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead
);
209 /* Shutdown tape filesystems */
210 IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead
);
212 /* Loop last-chance shutdown notifications */
213 ListEntry
= ExInterlockedRemoveHeadList(&LastChanceShutdownListHead
,
217 /* Get the shutdown entry */
218 ShutdownEntry
= CONTAINING_RECORD(ListEntry
,
222 /* Get the attached device */
223 DeviceObject
= IoGetAttachedDevice(ShutdownEntry
->DeviceObject
);
225 /* Build the shutdown IRP and call the driver */
226 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
235 Status
= IoCallDriver(DeviceObject
, Irp
);
236 if (Status
== STATUS_PENDING
)
238 /* Wait on the driver */
239 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
243 /* Remove the flag */
244 ShutdownEntry
->DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
246 /* Get rid of our reference to it */
247 ObDereferenceObject(ShutdownEntry
->DeviceObject
);
249 /* Free the shutdown entry and reset the event */
250 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
251 KeClearEvent(&Event
);
253 /* Go to the next entry */
254 ListEntry
= ExInterlockedRemoveHeadList(&LastChanceShutdownListHead
,
263 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
264 IN ACCESS_MASK DesiredAccess
,
265 OUT PFILE_OBJECT
*FileObject
,
266 OUT PDEVICE_OBJECT
*DeviceObject
,
269 OBJECT_ATTRIBUTES ObjectAttributes
;
270 IO_STATUS_BLOCK StatusBlock
;
271 PFILE_OBJECT LocalFileObject
;
275 /* Open the Device */
276 InitializeObjectAttributes(&ObjectAttributes
,
281 Status
= ZwOpenFile(&FileHandle
,
286 FILE_NON_DIRECTORY_FILE
| AttachFlag
);
287 if (!NT_SUCCESS(Status
)) return Status
;
289 /* Get File Object */
290 Status
= ObReferenceObjectByHandle(FileHandle
,
294 (PVOID
*)&LocalFileObject
,
296 if (NT_SUCCESS(Status
))
298 /* Return the requested data */
299 *DeviceObject
= IoGetRelatedDeviceObject(LocalFileObject
);
300 *FileObject
= LocalFileObject
;
303 /* Close the handle */
311 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject
)
313 PDEVICE_OBJECT LowestDevice
;
314 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
316 /* Get the current device and its extension */
317 LowestDevice
= DeviceObject
;
318 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
320 /* Keep looping as long as we're attached */
321 while (DeviceExtension
->AttachedTo
)
323 /* Get the lowest device and its extension */
324 LowestDevice
= DeviceExtension
->AttachedTo
;
325 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
328 /* Return the lowest device */
334 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject
,
335 IN PDEVICE_OBJECT DeviceObject
,
336 IN IOP_DEVICE_LIST_OPERATION Type
)
338 PDEVICE_OBJECT Previous
;
341 /* Lock the Device list while we edit it */
342 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
344 /* Check the type of operation */
345 if (Type
== IopRemove
)
347 /* Get the current device and check if it's the current one */
348 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
349 if (Previous
== DeviceObject
)
351 /* It is, simply unlink this one directly */
352 DeviceObject
->DriverObject
->DeviceObject
=
353 DeviceObject
->NextDevice
;
357 /* It's not, so loop until we find the device */
358 while (Previous
->NextDevice
!= DeviceObject
)
360 /* Not this one, keep moving */
361 if (!Previous
->NextDevice
)
363 DPRINT1("Failed to remove PDO %p (not found)\n",
367 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
370 Previous
= Previous
->NextDevice
;
373 /* We found it, now unlink us */
374 Previous
->NextDevice
= DeviceObject
->NextDevice
;
379 /* Link the device object and the driver object */
380 DeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
381 DriverObject
->DeviceObject
= DeviceObject
;
384 /* Release the device list lock */
385 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
390 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject
)
392 PDRIVER_OBJECT DriverObject
= DeviceObject
->DriverObject
;
393 PEXTENDED_DEVOBJ_EXTENSION ThisExtension
= IoGetDevObjExtension(DeviceObject
);
395 /* Check if deletion is pending */
396 if (ThisExtension
->ExtensionFlags
& DOE_DELETE_PENDING
)
398 if (DeviceObject
->AttachedDevice
)
400 DPRINT("Device object is in the middle of a device stack\n");
404 if (DeviceObject
->ReferenceCount
)
406 DPRINT("Device object still has %d references\n", DeviceObject
->ReferenceCount
);
410 /* Check if we have a Security Descriptor */
411 if (DeviceObject
->SecurityDescriptor
)
414 ObDereferenceSecurityDescriptor(DeviceObject
->SecurityDescriptor
, 1);
417 /* Remove the device from the list */
418 IopEditDeviceList(DeviceObject
->DriverObject
, DeviceObject
, IopRemove
);
420 /* Dereference the keep-alive */
421 ObDereferenceObject(DeviceObject
);
424 /* We can't unload a non-PnP driver here */
425 if (DriverObject
->Flags
& DRVO_LEGACY_DRIVER
)
427 DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
431 /* Return if we've already called unload (maybe we're in it?) */
432 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) return;
434 /* We can't unload unless there's an unload handler */
435 if (!DriverObject
->DriverUnload
)
437 DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
441 /* Bail if there are still devices present */
442 if (DriverObject
->DeviceObject
)
444 DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
448 DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject
->DriverName
);
450 /* Set the unload invoked flag */
451 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
454 DriverObject
->DriverUnload(DriverObject
);
456 /* Make object temporary so it can be deleted */
457 ObMakeTemporaryObject(DriverObject
);
462 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject
,
463 IN BOOLEAN ForceUnload
)
466 ASSERT(DeviceObject
->ReferenceCount
);
468 /* Dereference the device */
469 InterlockedDecrement(&DeviceObject
->ReferenceCount
);
472 * Check if we can unload it and it's safe to unload (or if we're forcing
473 * an unload, which is OK too).
475 ASSERT(!ForceUnload
);
476 if (!(DeviceObject
->ReferenceCount
) &&
477 (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
& DOE_DELETE_PENDING
))
480 IopUnloadDevice(DeviceObject
);
486 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
487 IN BOOLEAN Cancelable
,
490 PKDEVICE_QUEUE_ENTRY Entry
;
494 /* Acquire the cancel lock if this is cancelable */
495 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
497 /* Clear the current IRP */
498 DeviceObject
->CurrentIrp
= NULL
;
500 /* Remove an entry from the queue */
501 Entry
= KeRemoveByKeyDeviceQueue(&DeviceObject
->DeviceQueue
, Key
);
504 /* Get the IRP and set it */
505 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
506 DeviceObject
->CurrentIrp
= Irp
;
508 /* Check if this is a cancelable packet */
511 /* Check if the caller requested no cancellation */
512 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
515 /* He did, so remove the cancel routine */
516 Irp
->CancelRoutine
= NULL
;
519 /* Release the cancel lock */
520 IoReleaseCancelSpinLock(OldIrql
);
523 /* Call the Start I/O Routine */
524 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
528 /* Otherwise, release the cancel lock if we had acquired it */
529 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
535 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
536 IN BOOLEAN Cancelable
)
538 PKDEVICE_QUEUE_ENTRY Entry
;
542 /* Acquire the cancel lock if this is cancelable */
543 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
545 /* Clear the current IRP */
546 DeviceObject
->CurrentIrp
= NULL
;
548 /* Remove an entry from the queue */
549 Entry
= KeRemoveDeviceQueue(&DeviceObject
->DeviceQueue
);
552 /* Get the IRP and set it */
553 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
554 DeviceObject
->CurrentIrp
= Irp
;
556 /* Check if this is a cancelable packet */
559 /* Check if the caller requested no cancellation */
560 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
563 /* He did, so remove the cancel routine */
564 Irp
->CancelRoutine
= NULL
;
567 /* Release the cancel lock */
568 IoReleaseCancelSpinLock(OldIrql
);
571 /* Call the Start I/O Routine */
572 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
576 /* Otherwise, release the cancel lock if we had acquired it */
577 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
583 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject
,
587 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
588 ULONG CurrentKey
= Key
;
589 ULONG CurrentFlags
= Flags
;
591 /* Get the device extension and start the packet loop */
592 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
595 /* Increase the count */
596 if (InterlockedIncrement(&DeviceExtension
->StartIoCount
) > 1)
599 * We've already called the routine once...
600 * All we have to do is save the key and add the new flags
602 DeviceExtension
->StartIoFlags
|= CurrentFlags
;
603 DeviceExtension
->StartIoKey
= CurrentKey
;
607 /* Mask out the current packet flags and key */
608 DeviceExtension
->StartIoFlags
&= ~(DOE_SIO_WITH_KEY
|
611 DeviceExtension
->StartIoKey
= 0;
613 /* Check if this is a packet start with key */
614 if (Flags
& DOE_SIO_WITH_KEY
)
616 /* Start the packet with a key */
617 IopStartNextPacketByKey(DeviceObject
,
618 (Flags
& DOE_SIO_CANCELABLE
) ?
622 else if (Flags
& DOE_SIO_NO_KEY
)
624 /* Start the packet */
625 IopStartNextPacket(DeviceObject
,
626 (Flags
& DOE_SIO_CANCELABLE
) ?
631 /* Decrease the Start I/O count and check if it's 0 now */
632 if (!InterlockedDecrement(&DeviceExtension
->StartIoCount
))
634 /* Get the current active key and flags */
635 CurrentKey
= DeviceExtension
->StartIoKey
;
636 CurrentFlags
= DeviceExtension
->StartIoFlags
& (DOE_SIO_WITH_KEY
|
640 /* Check if we should still loop */
641 if (!(CurrentFlags
& (DOE_SIO_WITH_KEY
| DOE_SIO_NO_KEY
))) break;
645 /* There are still Start I/Os active, so quit this loop */
653 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
654 OUT PDEVICE_NODE
*DeviceNode
)
657 IO_STACK_LOCATION Stack
= {0};
658 PDEVICE_RELATIONS DeviceRelations
;
659 PDEVICE_OBJECT DeviceObject
= NULL
;
663 /* Get DeviceObject related to given FileObject */
664 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
665 if (!DeviceObject
) return STATUS_NO_SUCH_DEVICE
;
667 /* Define input parameters */
668 Stack
.MajorFunction
= IRP_MJ_PNP
;
669 Stack
.MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
670 Stack
.Parameters
.QueryDeviceRelations
.Type
= TargetDeviceRelation
;
671 Stack
.FileObject
= FileObject
;
673 /* Call the driver to query all relations (IRP_MJ_PNP) */
674 Status
= IopSynchronousCall(DeviceObject
,
676 (PVOID
)&DeviceRelations
);
677 if (!NT_SUCCESS(Status
)) return Status
;
679 /* Make sure it's not NULL and contains only one object */
680 ASSERT(DeviceRelations
);
681 ASSERT(DeviceRelations
->Count
== 1);
683 /* Finally get the device node */
684 *DeviceNode
= IopGetDeviceNode(DeviceRelations
->Objects
[0]);
685 if (!*DeviceNode
) Status
= STATUS_NO_SUCH_DEVICE
;
687 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
688 ExFreePool(DeviceRelations
);
695 IopVerifyDeviceObjectOnStack(IN PDEVICE_OBJECT BaseDeviceObject
,
696 IN PDEVICE_OBJECT TopDeviceObjectHint
)
700 PDEVICE_OBJECT LoopObject
;
702 ASSERT(BaseDeviceObject
!= NULL
);
705 /* Simply loop on the device stack and try to find our hint */
706 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
707 for (LoopObject
= BaseDeviceObject
; ; LoopObject
= LoopObject
->AttachedDevice
)
709 /* It was found, it's a success */
710 if (LoopObject
== TopDeviceObjectHint
)
716 /* End of the stack, that's a failure - default */
717 if (LoopObject
== NULL
)
722 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
729 IopCreateSecurityDescriptorPerType(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
731 OUT PULONG OutputFlags
)
736 /* Select the DACL the caller wants */
739 case RestrictedPublic
:
740 Dacl
= SePublicDefaultDacl
;
743 case UnrestrictedPublic
:
744 Dacl
= SePublicDefaultUnrestrictedDacl
;
747 case RestrictedPublicOpen
:
748 Dacl
= SePublicOpenDacl
;
751 case UnrestrictedPublicOpen
:
752 Dacl
= SePublicOpenUnrestrictedDacl
;
756 Dacl
= SeSystemDefaultDacl
;
761 return STATUS_INVALID_PARAMETER
;
764 /* Create the SD and set the DACL caller wanted */
765 Status
= RtlCreateSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
766 ASSERT(NT_SUCCESS(Status
));
767 Status
= RtlSetDaclSecurityDescriptor(SecurityDescriptor
, TRUE
, Dacl
, FALSE
);
770 if (OutputFlags
) *OutputFlags
|= DACL_SET
;
778 IopCreateDefaultDeviceSecurityDescriptor(IN DEVICE_TYPE DeviceType
,
779 IN ULONG DeviceCharacteristics
,
780 IN BOOLEAN HasDeviceName
,
781 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
782 OUT PACL
* OutputDacl
,
783 OUT PULONG OutputFlags
)
788 PACCESS_ALLOWED_ACE Ace
;
789 BOOLEAN AdminsSet
, WorldSet
;
793 /* Zero our output vars */
794 if (OutputFlags
) *OutputFlags
= 0;
798 /* For FSD, easy use SePublicDefaultUnrestrictedDacl */
799 if (DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
||
800 DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
||
801 DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
||
802 DeviceType
== FILE_DEVICE_FILE_SYSTEM
)
804 Status
= IopCreateSecurityDescriptorPerType(SecurityDescriptor
,
809 /* For storage devices with a name and floppy attribute,
810 * use SePublicOpenUnrestrictedDacl
812 else if ((DeviceType
!= FILE_DEVICE_VIRTUAL_DISK
&&
813 DeviceType
!= FILE_DEVICE_MASS_STORAGE
&&
814 DeviceType
!= FILE_DEVICE_CD_ROM
&&
815 DeviceType
!= FILE_DEVICE_DISK
&&
816 DeviceType
!= FILE_DEVICE_DFS_FILE_SYSTEM
&&
817 DeviceType
!= FILE_DEVICE_NETWORK
&&
818 DeviceType
!= FILE_DEVICE_NETWORK_FILE_SYSTEM
) ||
819 (HasDeviceName
&& BooleanFlagOn(DeviceCharacteristics
, FILE_FLOPPY_DISKETTE
)))
821 Status
= IopCreateSecurityDescriptorPerType(SecurityDescriptor
,
822 UnrestrictedPublicOpen
,
828 * We will rely on SePublicDefaultUnrestrictedDacl as well
830 Dacl
= ExAllocatePoolWithTag(PagedPool
, SePublicDefaultUnrestrictedDacl
->AclSize
, 'eSoI');
837 RtlCopyMemory(Dacl
, SePublicDefaultUnrestrictedDacl
, SePublicDefaultUnrestrictedDacl
->AclSize
);
839 /* Now, browse the DACL to make sure we have everything we want in them,
840 * including permissions
845 while (NT_SUCCESS(RtlGetAce(Dacl
, AceId
, (PVOID
*)&Ace
)))
847 /* Admins must acess and in RWX, set it */
848 if (RtlEqualSid(SeAliasAdminsSid
, &Ace
->SidStart
))
850 SetFlag(Ace
->Mask
, (GENERIC_READ
| GENERIC_WRITE
| GENERIC_EXECUTE
));
854 /* World can read a CD_ROM device */
855 if (DeviceType
== FILE_DEVICE_CD_ROM
&& RtlEqualSid(SeWorldSid
, &Ace
->SidStart
))
857 SetFlag(Ace
->Mask
, GENERIC_READ
);
864 /* AdminSid was present and set (otherwise, we have big trouble) */
867 /* If CD_ROM device, we've set world permissions */
868 if (DeviceType
== FILE_DEVICE_CD_ROM
) ASSERT(WorldSet
);
870 /* Now our DACL is correct, setup the security descriptor */
871 RtlCreateSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
872 RtlSetDaclSecurityDescriptor(SecurityDescriptor
, TRUE
, Dacl
, FALSE
);
875 if (OutputFlags
) *OutputFlags
|= DACL_SET
;
877 /* Return DACL to allow later freeing */
879 Status
= STATUS_SUCCESS
;
882 /* Only return SD if we succeed */
883 if (!NT_SUCCESS(Status
))
888 return SecurityDescriptor
;
891 /* PUBLIC FUNCTIONS ***********************************************************/
896 * Layers a device over the highest device in a device stack.
900 * Device to be attached.
903 * Name of the target device.
906 * Caller storage for the device attached to.
913 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
914 PUNICODE_STRING TargetDeviceName
,
915 PDEVICE_OBJECT
*AttachedDevice
)
918 PFILE_OBJECT FileObject
= NULL
;
919 PDEVICE_OBJECT TargetDevice
= NULL
;
921 /* Call the helper routine for an attach operation */
922 Status
= IopGetDeviceObjectPointer(TargetDeviceName
,
923 FILE_READ_ATTRIBUTES
,
926 IO_ATTACH_DEVICE_API
);
927 if (!NT_SUCCESS(Status
)) return Status
;
929 /* Attach the device */
930 Status
= IoAttachDeviceToDeviceStackSafe(SourceDevice
,
935 ObDereferenceObject(FileObject
);
940 * IoAttachDeviceByPointer
947 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
948 IN PDEVICE_OBJECT TargetDevice
)
950 PDEVICE_OBJECT AttachedDevice
;
951 NTSTATUS Status
= STATUS_SUCCESS
;
954 AttachedDevice
= IoAttachDeviceToDeviceStack(SourceDevice
, TargetDevice
);
955 if (!AttachedDevice
) Status
= STATUS_NO_SUCH_DEVICE
;
957 /* Return the status */
966 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice
,
967 IN PDEVICE_OBJECT TargetDevice
)
969 /* Attach it safely */
970 return IopAttachDeviceToDeviceStackSafe(SourceDevice
,
980 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
981 IN PDEVICE_OBJECT TargetDevice
,
982 IN OUT PDEVICE_OBJECT
*AttachedToDeviceObject
)
984 /* Call the internal function */
985 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice
,
987 AttachedToDeviceObject
))
990 return STATUS_NO_SUCH_DEVICE
;
994 return STATUS_SUCCESS
;
1000 * Allocates memory for and intializes a device object for use for
1005 * Driver object passed by IO Manager when the driver was loaded.
1007 * DeviceExtensionSize
1008 * Number of bytes for the device extension.
1011 * Unicode name of device.
1014 * Device type of the new device.
1016 * DeviceCharacteristics
1017 * Bit mask of device characteristics.
1020 * TRUE if only one thread can access the device at a time.
1023 * On successful return this parameter is filled by pointer to
1024 * allocated device object.
1031 IoCreateDevice(IN PDRIVER_OBJECT DriverObject
,
1032 IN ULONG DeviceExtensionSize
,
1033 IN PUNICODE_STRING DeviceName
,
1034 IN DEVICE_TYPE DeviceType
,
1035 IN ULONG DeviceCharacteristics
,
1036 IN BOOLEAN Exclusive
,
1037 OUT PDEVICE_OBJECT
*DeviceObject
)
1039 WCHAR AutoNameBuffer
[20];
1040 UNICODE_STRING AutoName
;
1041 PDEVICE_OBJECT CreatedDeviceObject
;
1042 PDEVOBJ_EXTENSION DeviceObjectExtension
;
1043 OBJECT_ATTRIBUTES ObjectAttributes
;
1045 ULONG AlignedDeviceExtensionSize
;
1049 SECURITY_DESCRIPTOR SecurityDescriptor
, *ReturnedSD
;
1052 /* Check if we have to generate a name */
1053 if (DeviceCharacteristics
& FILE_AUTOGENERATED_DEVICE_NAME
)
1056 swprintf(AutoNameBuffer
,
1058 InterlockedIncrementUL(&IopDeviceObjectNumber
));
1060 /* Initialize the name */
1061 RtlInitUnicodeString(&AutoName
, AutoNameBuffer
);
1062 DeviceName
= &AutoName
;
1065 /* Get the security descriptor */
1066 ReturnedSD
= IopCreateDefaultDeviceSecurityDescriptor(DeviceType
,
1067 DeviceCharacteristics
,
1069 &SecurityDescriptor
,
1073 /* Initialize the Object Attributes */
1074 InitializeObjectAttributes(&ObjectAttributes
,
1080 /* Honor exclusive flag */
1081 if (Exclusive
) ObjectAttributes
.Attributes
|= OBJ_EXCLUSIVE
;
1083 /* Create a permanent object for named devices */
1084 if (DeviceName
) ObjectAttributes
.Attributes
|= OBJ_PERMANENT
;
1086 /* Align the Extension Size to 8-bytes */
1087 AlignedDeviceExtensionSize
= (DeviceExtensionSize
+ 7) &~ 7;
1090 TotalSize
= AlignedDeviceExtensionSize
+
1091 sizeof(DEVICE_OBJECT
) +
1092 sizeof(EXTENDED_DEVOBJ_EXTENSION
);
1094 /* Create the Device Object */
1095 *DeviceObject
= NULL
;
1096 Status
= ObCreateObject(KernelMode
,
1104 (PVOID
*)&CreatedDeviceObject
);
1105 if (!NT_SUCCESS(Status
))
1107 if (Dacl
!= NULL
) ExFreePoolWithTag(Dacl
, 'eSoI');
1112 /* Clear the whole Object and extension so we don't null stuff manually */
1113 RtlZeroMemory(CreatedDeviceObject
, TotalSize
);
1116 * Setup the Type and Size. Note that we don't use the aligned size,
1117 * because that's only padding for the DevObjExt and not part of the Object.
1119 CreatedDeviceObject
->Type
= IO_TYPE_DEVICE
;
1120 CreatedDeviceObject
->Size
= sizeof(DEVICE_OBJECT
) + (USHORT
)DeviceExtensionSize
;
1122 /* The kernel extension is after the driver internal extension */
1123 DeviceObjectExtension
= (PDEVOBJ_EXTENSION
)
1124 ((ULONG_PTR
)(CreatedDeviceObject
+ 1) +
1125 AlignedDeviceExtensionSize
);
1127 /* Set the Type and Size. Question: why is Size 0 on Windows? */
1128 DeviceObjectExtension
->Type
= IO_TYPE_DEVICE_OBJECT_EXTENSION
;
1129 DeviceObjectExtension
->Size
= 0;
1131 /* Initialize with Power Manager */
1132 PoInitializeDeviceObject(DeviceObjectExtension
);
1134 /* Link the Object and Extension */
1135 DeviceObjectExtension
->DeviceObject
= CreatedDeviceObject
;
1136 CreatedDeviceObject
->DeviceObjectExtension
= DeviceObjectExtension
;
1138 /* Set Device Object Data */
1139 CreatedDeviceObject
->DeviceType
= DeviceType
;
1140 CreatedDeviceObject
->Characteristics
= DeviceCharacteristics
;
1141 CreatedDeviceObject
->DeviceExtension
= DeviceExtensionSize
?
1142 CreatedDeviceObject
+ 1 :
1144 CreatedDeviceObject
->StackSize
= 1;
1145 CreatedDeviceObject
->AlignmentRequirement
= 0;
1148 CreatedDeviceObject
->Flags
= DO_DEVICE_INITIALIZING
;
1149 if (Exclusive
) CreatedDeviceObject
->Flags
|= DO_EXCLUSIVE
;
1150 if (DeviceName
) CreatedDeviceObject
->Flags
|= DO_DEVICE_HAS_NAME
;
1152 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
1153 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
1154 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_VIRTUAL_DISK
) ||
1155 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
) ||
1156 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
))
1159 Status
= IopCreateVpb(CreatedDeviceObject
);
1160 if (!NT_SUCCESS(Status
))
1162 if (Dacl
!= NULL
) ExFreePoolWithTag(Dacl
, 'eSoI');
1164 /* Dereference the device object and fail */
1165 ObDereferenceObject(CreatedDeviceObject
);
1169 /* Initialize Lock Event */
1170 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
1171 SynchronizationEvent
,
1175 /* Set the right Sector Size */
1178 /* All disk systems */
1179 case FILE_DEVICE_DISK_FILE_SYSTEM
:
1180 case FILE_DEVICE_DISK
:
1181 case FILE_DEVICE_VIRTUAL_DISK
:
1183 /* The default is 512 bytes */
1184 CreatedDeviceObject
->SectorSize
= 512;
1187 /* CD-ROM file systems */
1188 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
1190 /* The default is 2048 bytes */
1191 CreatedDeviceObject
->SectorSize
= 2048;
1194 /* Create the Device Queue */
1195 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
1196 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
) ||
1197 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
1198 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
) ||
1199 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
))
1201 /* Simple FS Devices, they don't need a real Device Queue */
1202 InitializeListHead(&CreatedDeviceObject
->Queue
.ListEntry
);
1206 /* An actual Device, initialize its DQ */
1207 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
1210 /* Insert the Object */
1211 Status
= ObInsertObject(CreatedDeviceObject
,
1213 FILE_READ_DATA
| FILE_WRITE_DATA
,
1215 (PVOID
*)&CreatedDeviceObject
,
1217 if (!NT_SUCCESS(Status
))
1219 if (Dacl
!= NULL
) ExFreePoolWithTag(Dacl
, 'eSoI');
1224 /* Now do the final linking */
1225 ObReferenceObject(DriverObject
);
1226 ASSERT((DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) == 0);
1227 CreatedDeviceObject
->DriverObject
= DriverObject
;
1228 IopEditDeviceList(DriverObject
, CreatedDeviceObject
, IopAdd
);
1230 /* Link with the power manager */
1231 if (CreatedDeviceObject
->Vpb
) PoVolumeDevice(CreatedDeviceObject
);
1233 /* Close the temporary handle and return to caller */
1234 ObCloseHandle(TempHandle
, KernelMode
);
1235 *DeviceObject
= CreatedDeviceObject
;
1237 if (Dacl
!= NULL
) ExFreePoolWithTag(Dacl
, 'eSoI');
1239 return STATUS_SUCCESS
;
1250 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject
)
1254 /* Check if the device is registered for shutdown notifications */
1255 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
1257 /* Call the shutdown notifications */
1258 IoUnregisterShutdownNotification(DeviceObject
);
1261 /* Check if it has a timer */
1262 Timer
= DeviceObject
->Timer
;
1265 /* Remove it and free it */
1266 IopRemoveTimerFromTimerList(Timer
);
1267 ExFreePoolWithTag(Timer
, TAG_IO_TIMER
);
1270 /* Check if the device has a name */
1271 if (DeviceObject
->Flags
& DO_DEVICE_HAS_NAME
)
1273 /* It does, make it temporary so we can remove it */
1274 ObMakeTemporaryObject(DeviceObject
);
1277 /* Set the pending delete flag */
1278 IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
|= DOE_DELETE_PENDING
;
1280 /* Unlink with the power manager */
1281 if (DeviceObject
->Vpb
) PoRemoveVolumeDevice(DeviceObject
);
1283 /* Check if the device object can be unloaded */
1284 if (!DeviceObject
->ReferenceCount
) IopUnloadDevice(DeviceObject
);
1295 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice
)
1297 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1300 DeviceExtension
= IoGetDevObjExtension(TargetDevice
->AttachedDevice
);
1301 ASSERT(DeviceExtension
->AttachedTo
== TargetDevice
);
1303 /* Remove the attachment */
1304 DeviceExtension
->AttachedTo
= NULL
;
1305 TargetDevice
->AttachedDevice
= NULL
;
1307 /* Check if it's ok to delete this device */
1308 if ((IoGetDevObjExtension(TargetDevice
)->ExtensionFlags
& DOE_DELETE_PENDING
) &&
1309 !(TargetDevice
->ReferenceCount
))
1312 IopUnloadDevice(TargetDevice
);
1321 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject
,
1322 IN PDEVICE_OBJECT
*DeviceObjectList
,
1323 IN ULONG DeviceObjectListSize
,
1324 OUT PULONG ActualNumberDeviceObjects
)
1326 ULONG ActualDevices
= 1;
1327 PDEVICE_OBJECT CurrentDevice
= DriverObject
->DeviceObject
;
1330 /* Lock the Device list while we enumerate it */
1331 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
1333 /* Find out how many devices we'll enumerate */
1334 while ((CurrentDevice
= CurrentDevice
->NextDevice
)) ActualDevices
++;
1336 /* Go back to the first */
1337 CurrentDevice
= DriverObject
->DeviceObject
;
1339 /* Start by at least returning this */
1340 *ActualNumberDeviceObjects
= ActualDevices
;
1342 /* Check if we can support so many */
1343 if ((ActualDevices
* sizeof(PDEVICE_OBJECT
)) > DeviceObjectListSize
)
1345 /* Fail because the buffer was too small */
1346 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
1347 return STATUS_BUFFER_TOO_SMALL
;
1350 /* Check if the caller wanted the device list */
1351 if (DeviceObjectList
)
1353 /* Loop through all the devices */
1354 while (ActualDevices
)
1356 /* Reference each Device */
1357 ObReferenceObject(CurrentDevice
);
1359 /* Add it to the list */
1360 *DeviceObjectList
= CurrentDevice
;
1362 /* Go to the next one */
1363 CurrentDevice
= CurrentDevice
->NextDevice
;
1369 /* Release the device list lock */
1370 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
1372 /* Return the status */
1373 return STATUS_SUCCESS
;
1377 * IoGetAttachedDevice
1384 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
1386 /* Get the last attached device */
1387 while (DeviceObject
->AttachedDevice
)
1389 /* Move to the next one */
1390 DeviceObject
= DeviceObject
->AttachedDevice
;
1394 return DeviceObject
;
1398 * IoGetAttachedDeviceReference
1405 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
1407 /* Reference the Attached Device */
1408 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1409 ObReferenceObject(DeviceObject
);
1410 return DeviceObject
;
1418 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject
)
1420 /* Reference the lowest attached device */
1421 DeviceObject
= IopGetLowestDevice(DeviceObject
);
1422 ObReferenceObject(DeviceObject
);
1423 return DeviceObject
;
1427 * IoGetDeviceObjectPointer
1434 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
1435 IN ACCESS_MASK DesiredAccess
,
1436 OUT PFILE_OBJECT
*FileObject
,
1437 OUT PDEVICE_OBJECT
*DeviceObject
)
1439 /* Call the helper routine for a normal operation */
1440 return IopGetDeviceObjectPointer(ObjectName
,
1452 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject
,
1453 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
1455 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1460 /* Make sure there's a VPB */
1461 if (!FileSystemDeviceObject
->Vpb
) return STATUS_INVALID_PARAMETER
;
1464 IoAcquireVpbSpinLock(&OldIrql
);
1466 /* Get the Device Extension */
1467 DeviceExtension
= IoGetDevObjExtension(FileSystemDeviceObject
);
1469 /* Make sure this one has a VPB too */
1470 Vpb
= DeviceExtension
->Vpb
;
1473 /* Make sure that it's mounted */
1474 if ((Vpb
->ReferenceCount
) &&
1475 (Vpb
->Flags
& VPB_MOUNTED
))
1477 /* Return the Disk Device Object */
1478 *DiskDeviceObject
= Vpb
->RealDevice
;
1480 /* Reference it and return success */
1481 ObReferenceObject(Vpb
->RealDevice
);
1482 Status
= STATUS_SUCCESS
;
1486 /* It's not, so return failure */
1487 Status
= STATUS_VOLUME_DISMOUNTED
;
1493 Status
= STATUS_INVALID_PARAMETER
;
1496 /* Release the lock */
1497 IoReleaseVpbSpinLock(OldIrql
);
1506 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject
)
1508 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1509 PDEVICE_OBJECT LowerDeviceObject
= NULL
;
1511 /* Make sure it's not getting deleted */
1512 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1513 if (!(DeviceExtension
->ExtensionFlags
& (DOE_UNLOAD_PENDING
|
1514 DOE_DELETE_PENDING
|
1515 DOE_REMOVE_PENDING
|
1516 DOE_REMOVE_PROCESSED
)))
1518 /* Get the Lower Device Object */
1519 LowerDeviceObject
= DeviceExtension
->AttachedTo
;
1521 /* Check that we got a valid device object */
1522 if (LowerDeviceObject
)
1524 /* We did so let's reference it */
1525 ObReferenceObject(LowerDeviceObject
);
1530 return LowerDeviceObject
;
1538 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject
)
1540 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
1542 /* Check if we have a VPB with a device object */
1543 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1545 /* Then use the DO from the VPB */
1546 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1547 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1549 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1550 (FileObject
->DeviceObject
->Vpb
) &&
1551 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1553 /* The disk device actually has a VPB, so get the DO from there */
1554 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1558 /* Otherwise, this was a direct open */
1559 DeviceObject
= FileObject
->DeviceObject
;
1563 ASSERT(DeviceObject
!= NULL
);
1565 /* Check if we were attached */
1566 if (DeviceObject
->AttachedDevice
)
1568 /* Check if the file object has an extension present */
1569 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1571 /* Sanity check, direct open files can't have this */
1572 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1574 /* Check if the extension is really present */
1575 if (FileObject
->FileObjectExtension
)
1577 PFILE_OBJECT_EXTENSION FileObjectExtension
;
1579 /* Cast the buffer to something we understand */
1580 FileObjectExtension
= FileObject
->FileObjectExtension
;
1582 /* Check if have a valid replacement top level device */
1583 if (FileObjectExtension
->TopDeviceObjectHint
&&
1584 IopVerifyDeviceObjectOnStack(DeviceObject
,
1585 FileObjectExtension
->TopDeviceObjectHint
))
1587 /* Use this instead of returning the top level device */
1588 return FileObjectExtension
->TopDeviceObjectHint
;
1593 /* Return the highest attached device */
1594 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1597 /* Return the DO we found */
1598 return DeviceObject
;
1606 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
1607 OUT PDEVICE_OBJECT
*DeviceObject
)
1610 PDEVICE_NODE DeviceNode
= NULL
;
1612 /* Call the internal helper function */
1613 Status
= IopGetRelatedTargetDevice(FileObject
, &DeviceNode
);
1614 if (NT_SUCCESS(Status
) && DeviceNode
)
1616 *DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
1626 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
1628 PDEVICE_OBJECT DeviceObject
;
1631 * If the FILE_OBJECT's VPB is defined,
1632 * get the device from it.
1634 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1636 /* Use the VPB's Device Object's */
1637 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1639 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1640 (FileObject
->DeviceObject
->Vpb
) &&
1641 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1643 /* Use the VPB's File System Object */
1644 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1648 /* Use the FO's Device Object */
1649 DeviceObject
= FileObject
->DeviceObject
;
1652 /* Return the device object we found */
1653 ASSERT(DeviceObject
!= NULL
);
1654 return DeviceObject
;
1662 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject
)
1664 PSHUTDOWN_ENTRY Entry
;
1666 /* Allocate the shutdown entry */
1667 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1668 sizeof(SHUTDOWN_ENTRY
),
1669 TAG_SHUTDOWN_ENTRY
);
1670 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1673 Entry
->DeviceObject
= DeviceObject
;
1675 /* Reference it so it doesn't go away */
1676 ObReferenceObject(DeviceObject
);
1678 /* Insert it into the list */
1679 ExInterlockedInsertHeadList(&LastChanceShutdownListHead
,
1680 &Entry
->ShutdownList
,
1683 /* Set the shutdown registered flag */
1684 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1685 return STATUS_SUCCESS
;
1693 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1695 PSHUTDOWN_ENTRY Entry
;
1697 /* Allocate the shutdown entry */
1698 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1699 sizeof(SHUTDOWN_ENTRY
),
1700 TAG_SHUTDOWN_ENTRY
);
1701 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1704 Entry
->DeviceObject
= DeviceObject
;
1706 /* Reference it so it doesn't go away */
1707 ObReferenceObject(DeviceObject
);
1709 /* Insert it into the list */
1710 ExInterlockedInsertHeadList(&ShutdownListHead
,
1711 &Entry
->ShutdownList
,
1714 /* Set the shutdown registered flag */
1715 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1716 return STATUS_SUCCESS
;
1724 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1726 PSHUTDOWN_ENTRY ShutdownEntry
;
1727 PLIST_ENTRY NextEntry
;
1730 /* Remove the flag */
1731 DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
1733 /* Acquire the shutdown lock and loop the shutdown list */
1734 KeAcquireSpinLock(&ShutdownListLock
, &OldIrql
);
1735 NextEntry
= ShutdownListHead
.Flink
;
1736 while (NextEntry
!= &ShutdownListHead
)
1739 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1743 /* Get if the DO matches */
1744 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1746 /* Remove it from the list */
1747 RemoveEntryList(NextEntry
);
1748 NextEntry
= NextEntry
->Blink
;
1750 /* Free the entry */
1751 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1753 /* Get rid of our reference to it */
1754 ObDereferenceObject(DeviceObject
);
1757 /* Go to the next entry */
1758 NextEntry
= NextEntry
->Flink
;
1761 /* Now loop the last chance list */
1762 NextEntry
= LastChanceShutdownListHead
.Flink
;
1763 while (NextEntry
!= &LastChanceShutdownListHead
)
1766 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1770 /* Get if the DO matches */
1771 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1773 /* Remove it from the list */
1774 RemoveEntryList(NextEntry
);
1775 NextEntry
= NextEntry
->Blink
;
1777 /* Free the entry */
1778 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1780 /* Get rid of our reference to it */
1781 ObDereferenceObject(DeviceObject
);
1784 /* Go to the next entry */
1785 NextEntry
= NextEntry
->Flink
;
1788 /* Release the shutdown lock */
1789 KeReleaseSpinLock(&ShutdownListLock
, OldIrql
);
1797 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject
,
1798 IN BOOLEAN DeferredStartIo
,
1799 IN BOOLEAN NonCancelable
)
1801 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1803 /* Get the Device Extension */
1804 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1806 /* Set the flags the caller requested */
1807 DeviceExtension
->StartIoFlags
|= (DeferredStartIo
) ? DOE_SIO_DEFERRED
: 0;
1808 DeviceExtension
->StartIoFlags
|= (NonCancelable
) ? DOE_SIO_NO_CANCEL
: 0;
1816 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
1817 IN BOOLEAN Cancelable
,
1820 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1822 /* Get the Device Extension */
1823 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1825 /* Check if deferred start was requested */
1826 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1828 /* Call our internal function to handle the defered case */
1829 IopStartNextPacketByKeyEx(DeviceObject
,
1832 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1836 /* Call the normal routine */
1837 IopStartNextPacketByKey(DeviceObject
, Cancelable
, Key
);
1846 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
1847 IN BOOLEAN Cancelable
)
1849 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1851 /* Get the Device Extension */
1852 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1854 /* Check if deferred start was requested */
1855 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1857 /* Call our internal function to handle the defered case */
1858 IopStartNextPacketByKeyEx(DeviceObject
,
1861 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1865 /* Call the normal routine */
1866 IopStartNextPacket(DeviceObject
, Cancelable
);
1875 IoStartPacket(IN PDEVICE_OBJECT DeviceObject
,
1878 IN PDRIVER_CANCEL CancelFunction
)
1881 KIRQL OldIrql
, CancelIrql
;
1883 /* Raise to dispatch level */
1884 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1886 /* Check if we should acquire the cancel lock */
1889 /* Acquire and set it */
1890 IoAcquireCancelSpinLock(&CancelIrql
);
1891 Irp
->CancelRoutine
= CancelFunction
;
1894 /* Check if we have a key */
1898 Stat
= KeInsertByKeyDeviceQueue(&DeviceObject
->DeviceQueue
,
1899 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
1904 /* Insert without a key */
1905 Stat
= KeInsertDeviceQueue(&DeviceObject
->DeviceQueue
,
1906 &Irp
->Tail
.Overlay
.DeviceQueueEntry
);
1909 /* Check if this was a first insert */
1913 DeviceObject
->CurrentIrp
= Irp
;
1915 /* Check if this is a cancelable packet */
1918 /* Check if the caller requested no cancellation */
1919 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
1922 /* He did, so remove the cancel routine */
1923 Irp
->CancelRoutine
= NULL
;
1926 /* Release the cancel lock */
1927 IoReleaseCancelSpinLock(CancelIrql
);
1930 /* Call the Start I/O function */
1931 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
1935 /* The packet was inserted... check if we have a cancel function */
1938 /* Check if the IRP got cancelled */
1942 * Set the cancel IRQL, clear the currnet cancel routine and
1945 Irp
->CancelIrql
= CancelIrql
;
1946 Irp
->CancelRoutine
= NULL
;
1947 CancelFunction(DeviceObject
, Irp
);
1951 /* Otherwise, release the lock */
1952 IoReleaseCancelSpinLock(CancelIrql
);
1957 /* Return back to previous IRQL */
1958 KeLowerIrql(OldIrql
);
1961 #if defined (_WIN64)
1964 IoWMIDeviceObjectToProviderId(
1965 IN PDEVICE_OBJECT DeviceObject
)