xref: /reactos/ntoskrnl/io/iomgr/device.c (revision 93e72ed3)
1 /*
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)
9  *                  Pierre Schweitzer
10  */
11 
12 /* INCLUDES *******************************************************************/
13 
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <debug.h>
17 
18 /* GLOBALS ********************************************************************/
19 
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;
27 
28 #define DACL_SET 4
29 
30 /* PRIVATE FUNCTIONS **********************************************************/
31 
32 VOID
33 NTAPI
IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver)34 IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver)
35 {
36     PDEVICE_OBJECT DeviceObject;
37     PAGED_CODE();
38 
39     /* Set the driver as initialized */
40     Driver->Flags |= DRVO_INITIALIZED;
41     DeviceObject = Driver->DeviceObject;
42     while (DeviceObject)
43     {
44         /* Set every device as initialized too */
45         DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
46         DeviceObject = DeviceObject->NextDevice;
47     }
48 }
49 
50 VOID
51 NTAPI
IopDeleteDevice(IN PVOID ObjectBody)52 IopDeleteDevice(IN PVOID ObjectBody)
53 {
54     PDEVICE_OBJECT DeviceObject = ObjectBody;
55     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
56     PAGED_CODE();
57 
58     /* Cleanup and free the device node */
59     if (DeviceNode)
60         IopFreeDeviceNode(DeviceNode);
61 
62     /* Dereference the driver object, referenced in IoCreateDevice */
63     if (DeviceObject->DriverObject)
64         ObDereferenceObject(DeviceObject->DriverObject);
65 }
66 
67 
68 PDEVICE_OBJECT
69 NTAPI
IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,IN PDEVICE_OBJECT TargetDevice,OUT PDEVICE_OBJECT * AttachedToDeviceObject OPTIONAL)70 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
71                                  IN PDEVICE_OBJECT TargetDevice,
72                                  OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL)
73 {
74     PDEVICE_OBJECT AttachedDevice;
75     PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension;
76 
77     /* Get the Attached Device and source extension */
78     AttachedDevice = IoGetAttachedDevice(TargetDevice);
79     SourceDeviceExtension = IoGetDevObjExtension(SourceDevice);
80     ASSERT(SourceDeviceExtension->AttachedTo == NULL);
81 
82     /* Make sure that it's in a correct state */
83     if ((AttachedDevice->Flags & DO_DEVICE_INITIALIZING) ||
84         (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
85          (DOE_UNLOAD_PENDING |
86           DOE_DELETE_PENDING |
87           DOE_REMOVE_PENDING |
88           DOE_REMOVE_PROCESSED)))
89     {
90         /* Device was unloading or being removed */
91         AttachedDevice = NULL;
92     }
93     else
94     {
95         /* Update atached device fields */
96         AttachedDevice->AttachedDevice = SourceDevice;
97         AttachedDevice->Spare1++;
98 
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;
104 
105         /* Check for pending start flag */
106         if (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
107             DOE_START_PENDING)
108         {
109             /* Propagate */
110             IoGetDevObjExtension(SourceDevice)->ExtensionFlags |=
111                 DOE_START_PENDING;
112         }
113 
114         /* Set the attachment in the device extension */
115         SourceDeviceExtension->AttachedTo = AttachedDevice;
116     }
117 
118     /* Return the attached device */
119     if (AttachedToDeviceObject) *AttachedToDeviceObject = AttachedDevice;
120     return AttachedDevice;
121 }
122 
123 VOID
124 NTAPI
IoShutdownPnpDevices(VOID)125 IoShutdownPnpDevices(VOID)
126 {
127     /* This routine is only used by Driver Verifier to validate shutdown */
128     return;
129 }
130 
131 VOID
132 NTAPI
IoShutdownSystem(IN ULONG Phase)133 IoShutdownSystem(IN ULONG Phase)
134 {
135     PLIST_ENTRY ListEntry;
136     PDEVICE_OBJECT DeviceObject;
137     PSHUTDOWN_ENTRY ShutdownEntry;
138     IO_STATUS_BLOCK StatusBlock;
139     PIRP Irp;
140     KEVENT Event;
141     NTSTATUS Status;
142 
143     /* Initialize an event to wait on */
144     KeInitializeEvent(&Event, NotificationEvent, FALSE);
145 
146     /* What phase? */
147     if (Phase == 0)
148     {
149         /* Shutdown PnP */
150         IoShutdownPnpDevices();
151 
152         /* Loop first-chance shutdown notifications */
153         ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
154                                                 &ShutdownListLock);
155         while (ListEntry)
156         {
157             /* Get the shutdown entry */
158             ShutdownEntry = CONTAINING_RECORD(ListEntry,
159                                               SHUTDOWN_ENTRY,
160                                               ShutdownList);
161 
162             /* Get the attached device */
163             DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
164 
165             /* Build the shutdown IRP and call the driver */
166             Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
167                                                DeviceObject,
168                                                NULL,
169                                                0,
170                                                NULL,
171                                                &Event,
172                                                &StatusBlock);
173             if (Irp)
174             {
175                 Status = IoCallDriver(DeviceObject, Irp);
176                 if (Status == STATUS_PENDING)
177                 {
178                     /* Wait on the driver */
179                     KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
180                 }
181             }
182 
183             /* Remove the flag */
184             ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
185 
186             /* Get rid of our reference to it */
187             ObDereferenceObject(ShutdownEntry->DeviceObject);
188 
189             /* Free the shutdown entry and reset the event */
190             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
191             KeClearEvent(&Event);
192 
193             /* Go to the next entry */
194             ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
195                                                     &ShutdownListLock);
196          }
197     }
198     else if (Phase == 1)
199     {
200         /* Acquire resource forever */
201         ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE);
202 
203         /* Shutdown disk file systems */
204         IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead);
205 
206         /* Shutdown cdrom file systems */
207         IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead);
208 
209         /* Shutdown tape filesystems */
210         IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead);
211 
212         /* Loop last-chance shutdown notifications */
213         ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
214                                                 &ShutdownListLock);
215         while (ListEntry)
216         {
217             /* Get the shutdown entry */
218             ShutdownEntry = CONTAINING_RECORD(ListEntry,
219                                               SHUTDOWN_ENTRY,
220                                               ShutdownList);
221 
222             /* Get the attached device */
223             DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
224 
225             /* Build the shutdown IRP and call the driver */
226             Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
227                                                DeviceObject,
228                                                NULL,
229                                                0,
230                                                NULL,
231                                                &Event,
232                                                &StatusBlock);
233             if (Irp)
234             {
235                 Status = IoCallDriver(DeviceObject, Irp);
236                 if (Status == STATUS_PENDING)
237                 {
238                     /* Wait on the driver */
239                     KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
240                 }
241             }
242 
243             /* Remove the flag */
244             ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
245 
246             /* Get rid of our reference to it */
247             ObDereferenceObject(ShutdownEntry->DeviceObject);
248 
249             /* Free the shutdown entry and reset the event */
250             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
251             KeClearEvent(&Event);
252 
253             /* Go to the next entry */
254             ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
255                                                     &ShutdownListLock);
256          }
257 
258     }
259 }
260 
261 NTSTATUS
262 NTAPI
IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,IN ACCESS_MASK DesiredAccess,OUT PFILE_OBJECT * FileObject,OUT PDEVICE_OBJECT * DeviceObject,IN ULONG AttachFlag)263 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
264                           IN ACCESS_MASK DesiredAccess,
265                           OUT PFILE_OBJECT *FileObject,
266                           OUT PDEVICE_OBJECT *DeviceObject,
267                           IN ULONG AttachFlag)
268 {
269     OBJECT_ATTRIBUTES ObjectAttributes;
270     IO_STATUS_BLOCK StatusBlock;
271     PFILE_OBJECT LocalFileObject;
272     HANDLE FileHandle;
273     NTSTATUS Status;
274 
275     /* Open the Device */
276     InitializeObjectAttributes(&ObjectAttributes,
277                                ObjectName,
278                                OBJ_KERNEL_HANDLE,
279                                NULL,
280                                NULL);
281     Status = ZwOpenFile(&FileHandle,
282                         DesiredAccess,
283                         &ObjectAttributes,
284                         &StatusBlock,
285                         0,
286                         FILE_NON_DIRECTORY_FILE | AttachFlag);
287     if (!NT_SUCCESS(Status)) return Status;
288 
289     /* Get File Object */
290     Status = ObReferenceObjectByHandle(FileHandle,
291                                        0,
292                                        IoFileObjectType,
293                                        KernelMode,
294                                        (PVOID*)&LocalFileObject,
295                                        NULL);
296     if (NT_SUCCESS(Status))
297     {
298         /* Return the requested data */
299         *DeviceObject = IoGetRelatedDeviceObject(LocalFileObject);
300         *FileObject = LocalFileObject;
301     }
302 
303     /* Close the handle */
304     ZwClose(FileHandle);
305 
306     return Status;
307 }
308 
309 PDEVICE_OBJECT
310 NTAPI
IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject)311 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject)
312 {
313     PDEVICE_OBJECT LowestDevice;
314     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
315 
316     /* Get the current device and its extension */
317     LowestDevice = DeviceObject;
318     DeviceExtension = IoGetDevObjExtension(LowestDevice);
319 
320     /* Keep looping as long as we're attached */
321     while (DeviceExtension->AttachedTo)
322     {
323         /* Get the lowest device and its extension */
324         LowestDevice = DeviceExtension->AttachedTo;
325         DeviceExtension = IoGetDevObjExtension(LowestDevice);
326     }
327 
328     /* Return the lowest device */
329     return LowestDevice;
330 }
331 
332 VOID
333 NTAPI
IopEditDeviceList(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT DeviceObject,IN IOP_DEVICE_LIST_OPERATION Type)334 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject,
335                   IN PDEVICE_OBJECT DeviceObject,
336                   IN IOP_DEVICE_LIST_OPERATION Type)
337 {
338     PDEVICE_OBJECT Previous;
339     KIRQL OldIrql;
340 
341     /* Lock the Device list while we edit it */
342     OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
343 
344     /* Check the type of operation */
345     if (Type == IopRemove)
346     {
347         /* Get the current device and check if it's the current one */
348         Previous = DeviceObject->DriverObject->DeviceObject;
349         if (Previous == DeviceObject)
350         {
351             /* It is, simply unlink this one directly */
352             DeviceObject->DriverObject->DeviceObject =
353                 DeviceObject->NextDevice;
354         }
355         else
356         {
357             /* It's not, so loop until we find the device */
358             while (Previous->NextDevice != DeviceObject)
359             {
360                 /* Not this one, keep moving */
361                 if (!Previous->NextDevice)
362                 {
363                     DPRINT1("Failed to remove PDO %p (not found)\n",
364                             DeviceObject);
365 
366                     ASSERT(FALSE);
367                     KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
368                     return;
369                 }
370                 Previous = Previous->NextDevice;
371             }
372 
373             /* We found it, now unlink us */
374             Previous->NextDevice = DeviceObject->NextDevice;
375         }
376     }
377     else
378     {
379         /* Link the device object and the driver object */
380         DeviceObject->NextDevice = DriverObject->DeviceObject;
381         DriverObject->DeviceObject = DeviceObject;
382     }
383 
384     /* Release the device list lock */
385     KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
386 }
387 
388 VOID
389 NTAPI
IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject)390 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject)
391 {
392     PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject;
393     PEXTENDED_DEVOBJ_EXTENSION ThisExtension = IoGetDevObjExtension(DeviceObject);
394 
395     /* Check if deletion is pending */
396     if (ThisExtension->ExtensionFlags & DOE_DELETE_PENDING)
397     {
398         if (DeviceObject->AttachedDevice)
399         {
400             DPRINT("Device object is in the middle of a device stack\n");
401             return;
402         }
403 
404         if (DeviceObject->ReferenceCount)
405         {
406             DPRINT("Device object still has %d references\n", DeviceObject->ReferenceCount);
407             return;
408         }
409 
410         /* Check if we have a Security Descriptor */
411         if (DeviceObject->SecurityDescriptor)
412         {
413             /* Dereference it */
414             ObDereferenceSecurityDescriptor(DeviceObject->SecurityDescriptor, 1);
415         }
416 
417         /* Remove the device from the list */
418         IopEditDeviceList(DeviceObject->DriverObject, DeviceObject, IopRemove);
419 
420         /* Dereference the keep-alive */
421         ObDereferenceObject(DeviceObject);
422     }
423 
424     /* We can't unload a non-PnP driver here */
425     if (DriverObject->Flags & DRVO_LEGACY_DRIVER)
426     {
427         DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
428         return;
429     }
430 
431     /* Return if we've already called unload (maybe we're in it?) */
432     if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) return;
433 
434     /* We can't unload unless there's an unload handler */
435     if (!DriverObject->DriverUnload)
436     {
437         DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
438         return;
439     }
440 
441     /* Bail if there are still devices present */
442     if (DriverObject->DeviceObject)
443     {
444         DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
445         return;
446     }
447 
448     DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject->DriverName);
449 
450     /* Set the unload invoked flag */
451     DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
452 
453     /* Unload it */
454     DriverObject->DriverUnload(DriverObject);
455 
456     /* Make object temporary so it can be deleted */
457     ObMakeTemporaryObject(DriverObject);
458 }
459 
460 VOID
461 NTAPI
IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN ForceUnload)462 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject,
463                            IN BOOLEAN ForceUnload)
464 {
465     /* Sanity check */
466     ASSERT(DeviceObject->ReferenceCount);
467 
468     /* Dereference the device */
469     InterlockedDecrement(&DeviceObject->ReferenceCount);
470 
471     /*
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).
474      */
475     ASSERT(!ForceUnload);
476     if (!(DeviceObject->ReferenceCount) &&
477         (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & DOE_DELETE_PENDING))
478     {
479         /* Unload it */
480         IopUnloadDevice(DeviceObject);
481     }
482 }
483 
484 VOID
485 NTAPI
IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN Cancelable,IN ULONG Key)486 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
487                         IN BOOLEAN Cancelable,
488                         IN ULONG Key)
489 {
490     PKDEVICE_QUEUE_ENTRY Entry;
491     PIRP Irp;
492     KIRQL OldIrql;
493 
494     /* Acquire the cancel lock if this is cancelable */
495     if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
496 
497     /* Clear the current IRP */
498     DeviceObject->CurrentIrp = NULL;
499 
500     /* Remove an entry from the queue */
501     Entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue, Key);
502     if (Entry)
503     {
504         /* Get the IRP and set it */
505         Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
506         DeviceObject->CurrentIrp = Irp;
507 
508         /* Check if this is a cancelable packet */
509         if (Cancelable)
510         {
511             /* Check if the caller requested no cancellation */
512             if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
513                 DOE_SIO_NO_CANCEL)
514             {
515                 /* He did, so remove the cancel routine */
516                 Irp->CancelRoutine = NULL;
517             }
518 
519             /* Release the cancel lock */
520             IoReleaseCancelSpinLock(OldIrql);
521         }
522 
523         /* Call the Start I/O Routine */
524         DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
525     }
526     else
527     {
528         /* Otherwise, release the cancel lock if we had acquired it */
529         if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
530     }
531 }
532 
533 VOID
534 NTAPI
IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN Cancelable)535 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
536                    IN BOOLEAN Cancelable)
537 {
538     PKDEVICE_QUEUE_ENTRY Entry;
539     PIRP Irp;
540     KIRQL OldIrql;
541 
542     /* Acquire the cancel lock if this is cancelable */
543     if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
544 
545     /* Clear the current IRP */
546     DeviceObject->CurrentIrp = NULL;
547 
548     /* Remove an entry from the queue */
549     Entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue);
550     if (Entry)
551     {
552         /* Get the IRP and set it */
553         Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
554         DeviceObject->CurrentIrp = Irp;
555 
556         /* Check if this is a cancelable packet */
557         if (Cancelable)
558         {
559             /* Check if the caller requested no cancellation */
560             if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
561                 DOE_SIO_NO_CANCEL)
562             {
563                 /* He did, so remove the cancel routine */
564                 Irp->CancelRoutine = NULL;
565             }
566 
567             /* Release the cancel lock */
568             IoReleaseCancelSpinLock(OldIrql);
569         }
570 
571         /* Call the Start I/O Routine */
572         DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
573     }
574     else
575     {
576         /* Otherwise, release the cancel lock if we had acquired it */
577         if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
578     }
579 }
580 
581 VOID
582 NTAPI
IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject,IN ULONG Key,IN ULONG Flags)583 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject,
584                           IN ULONG Key,
585                           IN ULONG Flags)
586 {
587     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
588     ULONG CurrentKey = Key;
589     ULONG CurrentFlags = Flags;
590 
591     /* Get the device extension and start the packet loop */
592     DeviceExtension = IoGetDevObjExtension(DeviceObject);
593     while (TRUE)
594     {
595         /* Increase the count */
596         if (InterlockedIncrement(&DeviceExtension->StartIoCount) > 1)
597         {
598             /*
599              * We've already called the routine once...
600              * All we have to do is save the key and add the new flags
601              */
602             DeviceExtension->StartIoFlags |= CurrentFlags;
603             DeviceExtension->StartIoKey = CurrentKey;
604         }
605         else
606         {
607             /* Mask out the current packet flags and key */
608             DeviceExtension->StartIoFlags &= ~(DOE_SIO_WITH_KEY |
609                                                DOE_SIO_NO_KEY |
610                                                DOE_SIO_CANCELABLE);
611             DeviceExtension->StartIoKey = 0;
612 
613             /* Check if this is a packet start with key */
614             if (Flags & DOE_SIO_WITH_KEY)
615             {
616                 /* Start the packet with a key */
617                 IopStartNextPacketByKey(DeviceObject,
618                                         (Flags & DOE_SIO_CANCELABLE) ?
619                                         TRUE : FALSE,
620                                         CurrentKey);
621             }
622             else if (Flags & DOE_SIO_NO_KEY)
623             {
624                 /* Start the packet */
625                 IopStartNextPacket(DeviceObject,
626                                    (Flags & DOE_SIO_CANCELABLE) ?
627                                    TRUE : FALSE);
628             }
629         }
630 
631         /* Decrease the Start I/O count and check if it's 0 now */
632         if (!InterlockedDecrement(&DeviceExtension->StartIoCount))
633         {
634             /* Get the current active key and flags */
635             CurrentKey = DeviceExtension->StartIoKey;
636             CurrentFlags = DeviceExtension->StartIoFlags & (DOE_SIO_WITH_KEY |
637                                                             DOE_SIO_NO_KEY |
638                                                             DOE_SIO_CANCELABLE);
639 
640             /* Check if we should still loop */
641             if (!(CurrentFlags & (DOE_SIO_WITH_KEY | DOE_SIO_NO_KEY))) break;
642         }
643         else
644         {
645             /* There are still Start I/Os active, so quit this loop */
646             break;
647         }
648     }
649 }
650 
651 NTSTATUS
652 NTAPI
IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,OUT PDEVICE_NODE * DeviceNode)653 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
654                           OUT PDEVICE_NODE *DeviceNode)
655 {
656     NTSTATUS Status;
657     IO_STACK_LOCATION Stack = {0};
658     PDEVICE_RELATIONS DeviceRelations;
659     PDEVICE_OBJECT DeviceObject = NULL;
660 
661     ASSERT(FileObject);
662 
663     /* Get DeviceObject related to given FileObject */
664     DeviceObject = IoGetRelatedDeviceObject(FileObject);
665     if (!DeviceObject) return STATUS_NO_SUCH_DEVICE;
666 
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;
672 
673     /* Call the driver to query all relations (IRP_MJ_PNP) */
674     Status = IopSynchronousCall(DeviceObject,
675                                 &Stack,
676                                 (PVOID)&DeviceRelations);
677     if (!NT_SUCCESS(Status)) return Status;
678 
679     /* Make sure it's not NULL and contains only one object */
680     ASSERT(DeviceRelations);
681     ASSERT(DeviceRelations->Count == 1);
682 
683     /* Finally get the device node */
684     *DeviceNode = IopGetDeviceNode(DeviceRelations->Objects[0]);
685     if (!*DeviceNode) Status = STATUS_NO_SUCH_DEVICE;
686 
687     /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
688     ExFreePool(DeviceRelations);
689 
690     return Status;
691 }
692 
693 BOOLEAN
694 NTAPI
IopVerifyDeviceObjectOnStack(IN PDEVICE_OBJECT BaseDeviceObject,IN PDEVICE_OBJECT TopDeviceObjectHint)695 IopVerifyDeviceObjectOnStack(IN PDEVICE_OBJECT BaseDeviceObject,
696                              IN PDEVICE_OBJECT TopDeviceObjectHint)
697 {
698     KIRQL OldIrql;
699     BOOLEAN Result;
700     PDEVICE_OBJECT LoopObject;
701 
702     ASSERT(BaseDeviceObject != NULL);
703 
704     Result = FALSE;
705     /* Simply loop on the device stack and try to find our hint */
706     OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
707     for (LoopObject = BaseDeviceObject; ; LoopObject = LoopObject->AttachedDevice)
708     {
709         /* It was found, it's a success */
710         if (LoopObject == TopDeviceObjectHint)
711         {
712             Result = TRUE;
713             break;
714         }
715 
716         /* End of the stack, that's a failure - default */
717         if (LoopObject == NULL)
718         {
719             break;
720         }
721     }
722     KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
723 
724     return Result;
725 }
726 
727 NTSTATUS
728 NTAPI
IopCreateSecurityDescriptorPerType(IN PSECURITY_DESCRIPTOR SecurityDescriptor,IN SECURITY_DESCRIPTOR_TYPE Type,OUT PULONG OutputFlags)729 IopCreateSecurityDescriptorPerType(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
730                                    IN SECURITY_DESCRIPTOR_TYPE Type,
731                                    OUT PULONG OutputFlags)
732 {
733     PACL Dacl;
734     NTSTATUS Status;
735 
736     /* Select the DACL the caller wants */
737     switch (Type)
738     {
739         case RestrictedPublic:
740             Dacl = SePublicDefaultDacl;
741             break;
742 
743         case UnrestrictedPublic:
744             Dacl = SePublicDefaultUnrestrictedDacl;
745             break;
746 
747         case RestrictedPublicOpen:
748             Dacl = SePublicOpenDacl;
749             break;
750 
751         case UnrestrictedPublicOpen:
752             Dacl = SePublicOpenUnrestrictedDacl;
753             break;
754 
755         case SystemDefault:
756             Dacl = SeSystemDefaultDacl;
757             break;
758 
759         default:
760             ASSERT(FALSE);
761             return STATUS_INVALID_PARAMETER;
762     }
763 
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);
768 
769     /* We've set DACL */
770     if (OutputFlags) *OutputFlags |= DACL_SET;
771 
772     /* Done */
773     return Status;
774 }
775 
776 PSECURITY_DESCRIPTOR
777 NTAPI
IopCreateDefaultDeviceSecurityDescriptor(IN DEVICE_TYPE DeviceType,IN ULONG DeviceCharacteristics,IN BOOLEAN HasDeviceName,IN PSECURITY_DESCRIPTOR SecurityDescriptor,OUT PACL * OutputDacl,OUT PULONG OutputFlags)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)
784 {
785     PACL Dacl;
786     ULONG AceId;
787     NTSTATUS Status;
788     PACCESS_ALLOWED_ACE Ace;
789     BOOLEAN AdminsSet, WorldSet;
790 
791     PAGED_CODE();
792 
793     /* Zero our output vars */
794     if (OutputFlags) *OutputFlags = 0;
795 
796     *OutputDacl = NULL;
797 
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)
803     {
804         Status = IopCreateSecurityDescriptorPerType(SecurityDescriptor,
805                                                     UnrestrictedPublic,
806                                                     OutputFlags);
807         goto Quit;
808     }
809     /* For storage devices with a name and floppy attribute,
810      * use SePublicOpenUnrestrictedDacl
811      */
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)))
820     {
821         Status = IopCreateSecurityDescriptorPerType(SecurityDescriptor,
822                                                     UnrestrictedPublicOpen,
823                                                     OutputFlags);
824         goto Quit;
825     }
826 
827     /* The rest...
828      * We will rely on SePublicDefaultUnrestrictedDacl as well
829      */
830     Dacl = ExAllocatePoolWithTag(PagedPool, SePublicDefaultUnrestrictedDacl->AclSize, 'eSoI');
831     if (Dacl == NULL)
832     {
833         return NULL;
834     }
835 
836     /* Copy our DACL */
837     RtlCopyMemory(Dacl, SePublicDefaultUnrestrictedDacl, SePublicDefaultUnrestrictedDacl->AclSize);
838 
839     /* Now, browse the DACL to make sure we have everything we want in them,
840      * including permissions
841      */
842     AceId = 0;
843     AdminsSet = FALSE;
844     WorldSet = FALSE;
845     while (NT_SUCCESS(RtlGetAce(Dacl, AceId, (PVOID *)&Ace)))
846     {
847         /* Admins must acess and in RWX, set it */
848         if (RtlEqualSid(SeAliasAdminsSid, &Ace->SidStart))
849         {
850             SetFlag(Ace->Mask, (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE));
851             AdminsSet = TRUE;
852         }
853 
854         /* World can read a CD_ROM device */
855         if (DeviceType == FILE_DEVICE_CD_ROM && RtlEqualSid(SeWorldSid, &Ace->SidStart))
856         {
857             SetFlag(Ace->Mask, GENERIC_READ);
858             WorldSet = TRUE;
859         }
860 
861         ++AceId;
862     }
863 
864     /* AdminSid was present and set (otherwise, we have big trouble) */
865     ASSERT(AdminsSet);
866 
867     /* If CD_ROM device, we've set world permissions */
868     if (DeviceType == FILE_DEVICE_CD_ROM) ASSERT(WorldSet);
869 
870     /* Now our DACL is correct, setup the security descriptor */
871     RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
872     RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Dacl, FALSE);
873 
874     /* We've set DACL */
875     if (OutputFlags) *OutputFlags |= DACL_SET;
876 
877     /* Return DACL to allow later freeing */
878     *OutputDacl = Dacl;
879     Status = STATUS_SUCCESS;
880 
881 Quit:
882     /* Only return SD if we succeed */
883     if (!NT_SUCCESS(Status))
884     {
885         return NULL;
886     }
887 
888     return SecurityDescriptor;
889 }
890 
891 /* PUBLIC FUNCTIONS ***********************************************************/
892 
893 /*
894  * IoAttachDevice
895  *
896  * Layers a device over the highest device in a device stack.
897  *
898  * Parameters
899  *    SourceDevice
900  *       Device to be attached.
901  *
902  *    TargetDevice
903  *       Name of the target device.
904  *
905  *    AttachedDevice
906  *       Caller storage for the device attached to.
907  *
908  * Status
909  *    @implemented
910  */
911 NTSTATUS
912 NTAPI
IoAttachDevice(PDEVICE_OBJECT SourceDevice,PUNICODE_STRING TargetDeviceName,PDEVICE_OBJECT * AttachedDevice)913 IoAttachDevice(PDEVICE_OBJECT SourceDevice,
914                PUNICODE_STRING TargetDeviceName,
915                PDEVICE_OBJECT *AttachedDevice)
916 {
917     NTSTATUS Status;
918     PFILE_OBJECT FileObject = NULL;
919     PDEVICE_OBJECT TargetDevice = NULL;
920 
921     /* Call the helper routine for an attach operation */
922     Status = IopGetDeviceObjectPointer(TargetDeviceName,
923                                        FILE_READ_ATTRIBUTES,
924                                        &FileObject,
925                                        &TargetDevice,
926                                        IO_ATTACH_DEVICE_API);
927     if (!NT_SUCCESS(Status)) return Status;
928 
929     /* Attach the device */
930     Status = IoAttachDeviceToDeviceStackSafe(SourceDevice,
931                                              TargetDevice,
932                                              AttachedDevice);
933 
934     /* Dereference it */
935     ObDereferenceObject(FileObject);
936     return Status;
937 }
938 
939 /*
940  * IoAttachDeviceByPointer
941  *
942  * Status
943  *    @implemented
944  */
945 NTSTATUS
946 NTAPI
IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,IN PDEVICE_OBJECT TargetDevice)947 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,
948                         IN PDEVICE_OBJECT TargetDevice)
949 {
950     PDEVICE_OBJECT AttachedDevice;
951     NTSTATUS Status = STATUS_SUCCESS;
952 
953     /* Do the Attach */
954     AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice);
955     if (!AttachedDevice) Status = STATUS_NO_SUCH_DEVICE;
956 
957     /* Return the status */
958     return Status;
959 }
960 
961 /*
962  * @implemented
963  */
964 PDEVICE_OBJECT
965 NTAPI
IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice,IN PDEVICE_OBJECT TargetDevice)966 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice,
967                             IN PDEVICE_OBJECT TargetDevice)
968 {
969     /* Attach it safely */
970     return IopAttachDeviceToDeviceStackSafe(SourceDevice,
971                                             TargetDevice,
972                                             NULL);
973 }
974 
975 /*
976  * @implemented
977  */
978 NTSTATUS
979 NTAPI
IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,IN PDEVICE_OBJECT TargetDevice,IN OUT PDEVICE_OBJECT * AttachedToDeviceObject)980 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
981                                 IN PDEVICE_OBJECT TargetDevice,
982                                 IN OUT PDEVICE_OBJECT *AttachedToDeviceObject)
983 {
984     /* Call the internal function */
985     if (!IopAttachDeviceToDeviceStackSafe(SourceDevice,
986                                           TargetDevice,
987                                           AttachedToDeviceObject))
988     {
989         /* Nothing found */
990         return STATUS_NO_SUCH_DEVICE;
991     }
992 
993     /* Success! */
994     return STATUS_SUCCESS;
995 }
996 
997 /*
998  * IoCreateDevice
999  *
1000  * Allocates memory for and intializes a device object for use for
1001  * a driver.
1002  *
1003  * Parameters
1004  *    DriverObject
1005  *       Driver object passed by IO Manager when the driver was loaded.
1006  *
1007  *    DeviceExtensionSize
1008  *       Number of bytes for the device extension.
1009  *
1010  *    DeviceName
1011  *       Unicode name of device.
1012  *
1013  *    DeviceType
1014  *       Device type of the new device.
1015  *
1016  *    DeviceCharacteristics
1017  *       Bit mask of device characteristics.
1018  *
1019  *    Exclusive
1020  *       TRUE if only one thread can access the device at a time.
1021  *
1022  *    DeviceObject
1023  *       On successful return this parameter is filled by pointer to
1024  *       allocated device object.
1025  *
1026  * Status
1027  *    @implemented
1028  */
1029 NTSTATUS
1030 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)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)
1038 {
1039     WCHAR AutoNameBuffer[20];
1040     UNICODE_STRING AutoName;
1041     PDEVICE_OBJECT CreatedDeviceObject;
1042     PDEVOBJ_EXTENSION DeviceObjectExtension;
1043     OBJECT_ATTRIBUTES ObjectAttributes;
1044     NTSTATUS Status;
1045     ULONG AlignedDeviceExtensionSize;
1046     ULONG TotalSize;
1047     HANDLE TempHandle;
1048     PACL Dacl;
1049     SECURITY_DESCRIPTOR SecurityDescriptor, *ReturnedSD;
1050     PAGED_CODE();
1051 
1052     /* Check if we have to generate a name */
1053     if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME)
1054     {
1055         /* Generate it */
1056         swprintf(AutoNameBuffer,
1057                  L"\\Device\\%08lx",
1058                  InterlockedIncrementUL(&IopDeviceObjectNumber));
1059 
1060         /* Initialize the name */
1061         RtlInitUnicodeString(&AutoName, AutoNameBuffer);
1062         DeviceName = &AutoName;
1063     }
1064 
1065     /* Get the security descriptor */
1066     ReturnedSD = IopCreateDefaultDeviceSecurityDescriptor(DeviceType,
1067                                                           DeviceCharacteristics,
1068                                                           DeviceName != NULL,
1069                                                           &SecurityDescriptor,
1070                                                           &Dacl,
1071                                                           NULL);
1072 
1073     /* Initialize the Object Attributes */
1074     InitializeObjectAttributes(&ObjectAttributes,
1075                                DeviceName,
1076                                OBJ_KERNEL_HANDLE,
1077                                NULL,
1078                                ReturnedSD);
1079 
1080     /* Honor exclusive flag */
1081     if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE;
1082 
1083     /* Create a permanent object for named devices */
1084     if (DeviceName) ObjectAttributes.Attributes |= OBJ_PERMANENT;
1085 
1086     /* Align the Extension Size to 8-bytes */
1087     AlignedDeviceExtensionSize = ALIGN_UP_BY(DeviceExtensionSize,
1088                                              MEMORY_ALLOCATION_ALIGNMENT);
1089 
1090     /* Total Size */
1091     TotalSize = AlignedDeviceExtensionSize +
1092                 sizeof(DEVICE_OBJECT) +
1093                 sizeof(EXTENDED_DEVOBJ_EXTENSION);
1094 
1095     /* Create the Device Object */
1096     *DeviceObject = NULL;
1097     Status = ObCreateObject(KernelMode,
1098                             IoDeviceObjectType,
1099                             &ObjectAttributes,
1100                             KernelMode,
1101                             NULL,
1102                             TotalSize,
1103                             0,
1104                             0,
1105                             (PVOID*)&CreatedDeviceObject);
1106     if (!NT_SUCCESS(Status))
1107     {
1108         if (Dacl != NULL) ExFreePoolWithTag(Dacl, 'eSoI');
1109 
1110         return Status;
1111     }
1112 
1113     /* Clear the whole Object and extension so we don't null stuff manually */
1114     RtlZeroMemory(CreatedDeviceObject, TotalSize);
1115 
1116     /*
1117      * Setup the Type and Size. Note that we don't use the aligned size,
1118      * because that's only padding for the DevObjExt and not part of the Object.
1119      */
1120     CreatedDeviceObject->Type = IO_TYPE_DEVICE;
1121     CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize;
1122 
1123     /* The kernel extension is after the driver internal extension */
1124     DeviceObjectExtension = (PDEVOBJ_EXTENSION)
1125                             ((ULONG_PTR)(CreatedDeviceObject + 1) +
1126                              AlignedDeviceExtensionSize);
1127 
1128     /* Set the Type and Size. Question: why is Size 0 on Windows? */
1129     DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
1130     DeviceObjectExtension->Size = 0;
1131 
1132     /* Initialize with Power Manager */
1133     PoInitializeDeviceObject(DeviceObjectExtension);
1134 
1135     /* Link the Object and Extension */
1136     DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
1137     CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
1138 
1139     /* Set Device Object Data */
1140     CreatedDeviceObject->DeviceType = DeviceType;
1141     CreatedDeviceObject->Characteristics = DeviceCharacteristics;
1142     CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ?
1143                                            CreatedDeviceObject + 1 :
1144                                            NULL;
1145     CreatedDeviceObject->StackSize = 1;
1146     CreatedDeviceObject->AlignmentRequirement = 0;
1147 
1148     /* Set the Flags */
1149     CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING;
1150     if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE;
1151     if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME;
1152 
1153     /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
1154     if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
1155         (CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) ||
1156         (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) ||
1157         (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE))
1158     {
1159         /* Create Vpb */
1160         Status = IopCreateVpb(CreatedDeviceObject);
1161         if (!NT_SUCCESS(Status))
1162         {
1163             if (Dacl != NULL) ExFreePoolWithTag(Dacl, 'eSoI');
1164 
1165             /* Dereference the device object and fail */
1166             ObDereferenceObject(CreatedDeviceObject);
1167             return Status;
1168         }
1169 
1170         /* Initialize Lock Event */
1171         KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
1172                           SynchronizationEvent,
1173                           TRUE);
1174     }
1175 
1176     /* Set the right Sector Size */
1177     switch (DeviceType)
1178     {
1179         /* All disk systems */
1180         case FILE_DEVICE_DISK_FILE_SYSTEM:
1181         case FILE_DEVICE_DISK:
1182         case FILE_DEVICE_VIRTUAL_DISK:
1183 
1184             /* The default is 512 bytes */
1185             CreatedDeviceObject->SectorSize  = 512;
1186             break;
1187 
1188         /* CD-ROM file systems */
1189         case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
1190 
1191             /* The default is 2048 bytes */
1192             CreatedDeviceObject->SectorSize = 2048;
1193     }
1194 
1195     /* Create the Device Queue */
1196     if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
1197         (CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) ||
1198         (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
1199         (CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) ||
1200         (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM))
1201     {
1202         /* Simple FS Devices, they don't need a real Device Queue */
1203         InitializeListHead(&CreatedDeviceObject->Queue.ListEntry);
1204     }
1205     else
1206     {
1207         /* An actual Device, initialize its DQ */
1208         KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
1209     }
1210 
1211     /* Insert the Object */
1212     Status = ObInsertObject(CreatedDeviceObject,
1213                             NULL,
1214                             FILE_READ_DATA | FILE_WRITE_DATA,
1215                             1,
1216                             (PVOID*)&CreatedDeviceObject,
1217                             &TempHandle);
1218     if (!NT_SUCCESS(Status))
1219     {
1220         if (Dacl != NULL) ExFreePoolWithTag(Dacl, 'eSoI');
1221 
1222         return Status;
1223     }
1224 
1225     /* Now do the final linking */
1226     ObReferenceObject(DriverObject);
1227     ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
1228     CreatedDeviceObject->DriverObject = DriverObject;
1229     IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
1230 
1231     /* Link with the power manager */
1232     if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
1233 
1234     /* Close the temporary handle and return to caller */
1235     ObCloseHandle(TempHandle, KernelMode);
1236     *DeviceObject = CreatedDeviceObject;
1237 
1238     if (Dacl != NULL) ExFreePoolWithTag(Dacl, 'eSoI');
1239 
1240     return STATUS_SUCCESS;
1241 }
1242 
1243 /*
1244  * IoDeleteDevice
1245  *
1246  * Status
1247  *    @implemented
1248  */
1249 VOID
1250 NTAPI
IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)1251 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)
1252 {
1253     PIO_TIMER Timer;
1254 
1255     /* Check if the device is registered for shutdown notifications */
1256     if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
1257     {
1258         /* Call the shutdown notifications */
1259         IoUnregisterShutdownNotification(DeviceObject);
1260     }
1261 
1262     /* Check if it has a timer */
1263     Timer = DeviceObject->Timer;
1264     if (Timer)
1265     {
1266         /* Remove it and free it */
1267         IopRemoveTimerFromTimerList(Timer);
1268         ExFreePoolWithTag(Timer, TAG_IO_TIMER);
1269     }
1270 
1271     /* Check if the device has a name */
1272     if (DeviceObject->Flags & DO_DEVICE_HAS_NAME)
1273     {
1274         /* It does, make it temporary so we can remove it */
1275         ObMakeTemporaryObject(DeviceObject);
1276     }
1277 
1278     /* Set the pending delete flag */
1279     IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING;
1280 
1281     /* Unlink with the power manager */
1282     if (DeviceObject->Vpb) PoRemoveVolumeDevice(DeviceObject);
1283 
1284     /* Check if the device object can be unloaded */
1285     if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject);
1286 }
1287 
1288 /*
1289  * IoDetachDevice
1290  *
1291  * Status
1292  *    @implemented
1293  */
1294 VOID
1295 NTAPI
IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)1296 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
1297 {
1298     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1299 
1300     /* Sanity check */
1301     DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice);
1302     ASSERT(DeviceExtension->AttachedTo == TargetDevice);
1303 
1304     /* Remove the attachment */
1305     DeviceExtension->AttachedTo = NULL;
1306     TargetDevice->AttachedDevice = NULL;
1307 
1308     /* Check if it's ok to delete this device */
1309     if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) &&
1310         !(TargetDevice->ReferenceCount))
1311     {
1312         /* It is, do it */
1313         IopUnloadDevice(TargetDevice);
1314     }
1315 }
1316 
1317 /*
1318  * @implemented
1319  */
1320 NTSTATUS
1321 NTAPI
IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT * DeviceObjectList,IN ULONG DeviceObjectListSize,OUT PULONG ActualNumberDeviceObjects)1322 IoEnumerateDeviceObjectList(IN  PDRIVER_OBJECT DriverObject,
1323                             IN  PDEVICE_OBJECT *DeviceObjectList,
1324                             IN  ULONG DeviceObjectListSize,
1325                             OUT PULONG ActualNumberDeviceObjects)
1326 {
1327     ULONG ActualDevices = 1;
1328     PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject;
1329     KIRQL OldIrql;
1330 
1331     /* Lock the Device list while we enumerate it */
1332     OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1333 
1334     /* Find out how many devices we'll enumerate */
1335     while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++;
1336 
1337     /* Go back to the first */
1338     CurrentDevice = DriverObject->DeviceObject;
1339 
1340     /* Start by at least returning this */
1341     *ActualNumberDeviceObjects = ActualDevices;
1342 
1343     /* Check if we can support so many */
1344     if ((ActualDevices * sizeof(PDEVICE_OBJECT)) > DeviceObjectListSize)
1345     {
1346         /* Fail because the buffer was too small */
1347         KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1348         return STATUS_BUFFER_TOO_SMALL;
1349     }
1350 
1351     /* Check if the caller wanted the device list */
1352     if (DeviceObjectList)
1353     {
1354         /* Loop through all the devices */
1355         while (ActualDevices)
1356         {
1357             /* Reference each Device */
1358             ObReferenceObject(CurrentDevice);
1359 
1360             /* Add it to the list */
1361             *DeviceObjectList = CurrentDevice;
1362 
1363             /* Go to the next one */
1364             CurrentDevice = CurrentDevice->NextDevice;
1365             ActualDevices--;
1366             DeviceObjectList++;
1367         }
1368     }
1369 
1370     /* Release the device list lock */
1371     KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1372 
1373     /* Return the status */
1374     return STATUS_SUCCESS;
1375 }
1376 
1377 /*
1378  * IoGetAttachedDevice
1379  *
1380  * Status
1381  *    @implemented
1382  */
1383 PDEVICE_OBJECT
1384 NTAPI
IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)1385 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
1386 {
1387     /* Get the last attached device */
1388     while (DeviceObject->AttachedDevice)
1389     {
1390         /* Move to the next one */
1391         DeviceObject = DeviceObject->AttachedDevice;
1392     }
1393 
1394     /* Return it */
1395     return DeviceObject;
1396 }
1397 
1398 /*
1399  * IoGetAttachedDeviceReference
1400  *
1401  * Status
1402  *    @implemented
1403  */
1404 PDEVICE_OBJECT
1405 NTAPI
IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)1406 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
1407 {
1408     /* Reference the Attached Device */
1409     DeviceObject = IoGetAttachedDevice(DeviceObject);
1410     ObReferenceObject(DeviceObject);
1411     return DeviceObject;
1412 }
1413 
1414 /*
1415  * @implemented
1416  */
1417 PDEVICE_OBJECT
1418 NTAPI
IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject)1419 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject)
1420 {
1421     /* Reference the lowest attached device */
1422     DeviceObject = IopGetLowestDevice(DeviceObject);
1423     ObReferenceObject(DeviceObject);
1424     return DeviceObject;
1425 }
1426 
1427 /*
1428  * IoGetDeviceObjectPointer
1429  *
1430  * Status
1431  *    @implemented
1432  */
1433 NTSTATUS
1434 NTAPI
IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,IN ACCESS_MASK DesiredAccess,OUT PFILE_OBJECT * FileObject,OUT PDEVICE_OBJECT * DeviceObject)1435 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
1436                          IN ACCESS_MASK DesiredAccess,
1437                          OUT PFILE_OBJECT *FileObject,
1438                          OUT PDEVICE_OBJECT *DeviceObject)
1439 {
1440     /* Call the helper routine for a normal operation */
1441     return IopGetDeviceObjectPointer(ObjectName,
1442                                      DesiredAccess,
1443                                      FileObject,
1444                                      DeviceObject,
1445                                      0);
1446 }
1447 
1448 /*
1449  * @implemented
1450  */
1451 NTSTATUS
1452 NTAPI
IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject,OUT PDEVICE_OBJECT * DiskDeviceObject)1453 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject,
1454                       OUT PDEVICE_OBJECT *DiskDeviceObject)
1455 {
1456     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1457     PVPB Vpb;
1458     KIRQL OldIrql;
1459     NTSTATUS Status;
1460 
1461     /* Make sure there's a VPB */
1462     if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER;
1463 
1464     /* Acquire it */
1465     IoAcquireVpbSpinLock(&OldIrql);
1466 
1467     /* Get the Device Extension */
1468     DeviceExtension = IoGetDevObjExtension(FileSystemDeviceObject);
1469 
1470     /* Make sure this one has a VPB too */
1471     Vpb = DeviceExtension->Vpb;
1472     if (Vpb)
1473     {
1474         /* Make sure that it's mounted */
1475         if ((Vpb->ReferenceCount) &&
1476             (Vpb->Flags & VPB_MOUNTED))
1477         {
1478             /* Return the Disk Device Object */
1479             *DiskDeviceObject = Vpb->RealDevice;
1480 
1481             /* Reference it and return success */
1482             ObReferenceObject(Vpb->RealDevice);
1483             Status = STATUS_SUCCESS;
1484         }
1485         else
1486         {
1487             /* It's not, so return failure */
1488             Status = STATUS_VOLUME_DISMOUNTED;
1489         }
1490     }
1491     else
1492     {
1493         /* Fail */
1494         Status = STATUS_INVALID_PARAMETER;
1495     }
1496 
1497     /* Release the lock */
1498     IoReleaseVpbSpinLock(OldIrql);
1499     return Status;
1500 }
1501 
1502 /*
1503  * @implemented
1504  */
1505 PDEVICE_OBJECT
1506 NTAPI
IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)1507 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)
1508 {
1509     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1510     PDEVICE_OBJECT LowerDeviceObject = NULL;
1511 
1512     /* Make sure it's not getting deleted */
1513     DeviceExtension = IoGetDevObjExtension(DeviceObject);
1514     if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING |
1515                                            DOE_DELETE_PENDING |
1516                                            DOE_REMOVE_PENDING |
1517                                            DOE_REMOVE_PROCESSED)))
1518     {
1519         /* Get the Lower Device Object */
1520         LowerDeviceObject = DeviceExtension->AttachedTo;
1521 
1522         /* Check that we got a valid device object */
1523         if (LowerDeviceObject)
1524         {
1525             /* We did so let's reference it */
1526             ObReferenceObject(LowerDeviceObject);
1527         }
1528     }
1529 
1530     /* Return it */
1531     return LowerDeviceObject;
1532 }
1533 
1534 /*
1535  * @implemented
1536  */
1537 PDEVICE_OBJECT
1538 NTAPI
IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject)1539 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject)
1540 {
1541     PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
1542 
1543     /* Check if we have a VPB with a device object */
1544     if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
1545     {
1546         /* Then use the DO from the VPB */
1547         ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
1548         DeviceObject = FileObject->Vpb->DeviceObject;
1549     }
1550     else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
1551               (FileObject->DeviceObject->Vpb) &&
1552               (FileObject->DeviceObject->Vpb->DeviceObject))
1553     {
1554         /* The disk device actually has a VPB, so get the DO from there */
1555         DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
1556     }
1557     else
1558     {
1559         /* Otherwise, this was a direct open */
1560         DeviceObject = FileObject->DeviceObject;
1561     }
1562 
1563     /* Sanity check */
1564     ASSERT(DeviceObject != NULL);
1565 
1566     /* Check if we were attached */
1567     if (DeviceObject->AttachedDevice)
1568     {
1569         /* Check if the file object has an extension present */
1570         if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1571         {
1572             /* Sanity check, direct open files can't have this */
1573             ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
1574 
1575             /* Check if the extension is really present */
1576             if (FileObject->FileObjectExtension)
1577             {
1578                 PFILE_OBJECT_EXTENSION FileObjectExtension;
1579 
1580                 /* Cast the buffer to something we understand */
1581                 FileObjectExtension = FileObject->FileObjectExtension;
1582 
1583                 /* Check if have a valid replacement top level device */
1584                 if (FileObjectExtension->TopDeviceObjectHint &&
1585                     IopVerifyDeviceObjectOnStack(DeviceObject,
1586                                                  FileObjectExtension->TopDeviceObjectHint))
1587                 {
1588                     /* Use this instead of returning the top level device */
1589                     return FileObjectExtension->TopDeviceObjectHint;
1590                 }
1591             }
1592         }
1593 
1594         /* Return the highest attached device */
1595         DeviceObject = IoGetAttachedDevice(DeviceObject);
1596     }
1597 
1598     /* Return the DO we found */
1599     return DeviceObject;
1600 }
1601 
1602 /*
1603  * @implemented
1604  */
1605 NTSTATUS
1606 NTAPI
IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,OUT PDEVICE_OBJECT * DeviceObject)1607 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
1608                          OUT PDEVICE_OBJECT *DeviceObject)
1609 {
1610     NTSTATUS Status;
1611     PDEVICE_NODE DeviceNode = NULL;
1612 
1613     /* Call the internal helper function */
1614     Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode);
1615     if (NT_SUCCESS(Status) && DeviceNode)
1616     {
1617         *DeviceObject = DeviceNode->PhysicalDeviceObject;
1618     }
1619     return Status;
1620 }
1621 
1622 /*
1623  * @implemented
1624  */
1625 PDEVICE_OBJECT
1626 NTAPI
IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)1627 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
1628 {
1629     PDEVICE_OBJECT DeviceObject;
1630 
1631     /*
1632     * If the FILE_OBJECT's VPB is defined,
1633     * get the device from it.
1634     */
1635     if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
1636     {
1637         /* Use the VPB's Device Object's */
1638         DeviceObject = FileObject->Vpb->DeviceObject;
1639     }
1640     else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
1641              (FileObject->DeviceObject->Vpb) &&
1642              (FileObject->DeviceObject->Vpb->DeviceObject))
1643     {
1644         /* Use the VPB's File System Object */
1645         DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
1646     }
1647     else
1648     {
1649         /* Use the FO's Device Object */
1650         DeviceObject = FileObject->DeviceObject;
1651     }
1652 
1653     /* Return the device object we found */
1654     ASSERT(DeviceObject != NULL);
1655     return DeviceObject;
1656 }
1657 
1658 /*
1659  * @implemented
1660  */
1661 NTSTATUS
1662 NTAPI
IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)1663 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
1664 {
1665     PSHUTDOWN_ENTRY Entry;
1666 
1667     /* Allocate the shutdown entry */
1668     Entry = ExAllocatePoolWithTag(NonPagedPool,
1669                                   sizeof(SHUTDOWN_ENTRY),
1670                                   TAG_SHUTDOWN_ENTRY);
1671     if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
1672 
1673     /* Set the DO */
1674     Entry->DeviceObject = DeviceObject;
1675 
1676     /* Reference it so it doesn't go away */
1677     ObReferenceObject(DeviceObject);
1678 
1679     /* Insert it into the list */
1680     ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
1681                                 &Entry->ShutdownList,
1682                                 &ShutdownListLock);
1683 
1684     /* Set the shutdown registered flag */
1685     DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
1686     return STATUS_SUCCESS;
1687 }
1688 
1689 /*
1690  * @implemented
1691  */
1692 NTSTATUS
1693 NTAPI
IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)1694 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
1695 {
1696     PSHUTDOWN_ENTRY Entry;
1697 
1698     /* Allocate the shutdown entry */
1699     Entry = ExAllocatePoolWithTag(NonPagedPool,
1700                                   sizeof(SHUTDOWN_ENTRY),
1701                                   TAG_SHUTDOWN_ENTRY);
1702     if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
1703 
1704     /* Set the DO */
1705     Entry->DeviceObject = DeviceObject;
1706 
1707     /* Reference it so it doesn't go away */
1708     ObReferenceObject(DeviceObject);
1709 
1710     /* Insert it into the list */
1711     ExInterlockedInsertHeadList(&ShutdownListHead,
1712                                 &Entry->ShutdownList,
1713                                 &ShutdownListLock);
1714 
1715     /* Set the shutdown registered flag */
1716     DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
1717     return STATUS_SUCCESS;
1718 }
1719 
1720 /*
1721  * @implemented
1722  */
1723 VOID
1724 NTAPI
IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)1725 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
1726 {
1727     PSHUTDOWN_ENTRY ShutdownEntry;
1728     PLIST_ENTRY NextEntry;
1729     KIRQL OldIrql;
1730 
1731     /* Remove the flag */
1732     DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
1733 
1734     /* Acquire the shutdown lock and loop the shutdown list */
1735     KeAcquireSpinLock(&ShutdownListLock, &OldIrql);
1736     NextEntry = ShutdownListHead.Flink;
1737     while (NextEntry != &ShutdownListHead)
1738     {
1739         /* Get the entry */
1740         ShutdownEntry = CONTAINING_RECORD(NextEntry,
1741                                           SHUTDOWN_ENTRY,
1742                                           ShutdownList);
1743 
1744         /* Get if the DO matches */
1745         if (ShutdownEntry->DeviceObject == DeviceObject)
1746         {
1747             /* Remove it from the list */
1748             RemoveEntryList(NextEntry);
1749             NextEntry = NextEntry->Blink;
1750 
1751             /* Free the entry */
1752             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
1753 
1754             /* Get rid of our reference to it */
1755             ObDereferenceObject(DeviceObject);
1756         }
1757 
1758         /* Go to the next entry */
1759         NextEntry = NextEntry->Flink;
1760     }
1761 
1762     /* Now loop the last chance list */
1763     NextEntry = LastChanceShutdownListHead.Flink;
1764     while (NextEntry != &LastChanceShutdownListHead)
1765     {
1766         /* Get the entry */
1767         ShutdownEntry = CONTAINING_RECORD(NextEntry,
1768                                           SHUTDOWN_ENTRY,
1769                                           ShutdownList);
1770 
1771         /* Get if the DO matches */
1772         if (ShutdownEntry->DeviceObject == DeviceObject)
1773         {
1774             /* Remove it from the list */
1775             RemoveEntryList(NextEntry);
1776             NextEntry = NextEntry->Blink;
1777 
1778             /* Free the entry */
1779             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
1780 
1781             /* Get rid of our reference to it */
1782             ObDereferenceObject(DeviceObject);
1783         }
1784 
1785         /* Go to the next entry */
1786         NextEntry = NextEntry->Flink;
1787     }
1788 
1789     /* Release the shutdown lock */
1790     KeReleaseSpinLock(&ShutdownListLock, OldIrql);
1791 }
1792 
1793 /*
1794  * @implemented
1795  */
1796 VOID
1797 NTAPI
IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN DeferredStartIo,IN BOOLEAN NonCancelable)1798 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject,
1799                        IN BOOLEAN DeferredStartIo,
1800                        IN BOOLEAN NonCancelable)
1801 {
1802     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1803 
1804     /* Get the Device Extension */
1805     DeviceExtension = IoGetDevObjExtension(DeviceObject);
1806 
1807     /* Set the flags the caller requested */
1808     DeviceExtension->StartIoFlags |= (DeferredStartIo) ? DOE_SIO_DEFERRED : 0;
1809     DeviceExtension->StartIoFlags |= (NonCancelable) ? DOE_SIO_NO_CANCEL : 0;
1810 }
1811 
1812 /*
1813  * @implemented
1814  */
1815 VOID
1816 NTAPI
IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN Cancelable,IN ULONG Key)1817 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
1818                        IN BOOLEAN Cancelable,
1819                        IN ULONG Key)
1820 {
1821     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1822 
1823     /* Get the Device Extension */
1824     DeviceExtension = IoGetDevObjExtension(DeviceObject);
1825 
1826     /* Check if deferred start was requested */
1827     if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
1828     {
1829         /* Call our internal function to handle the defered case */
1830         IopStartNextPacketByKeyEx(DeviceObject,
1831                                   Key,
1832                                   DOE_SIO_WITH_KEY |
1833                                   (Cancelable ? DOE_SIO_CANCELABLE : 0));
1834     }
1835     else
1836     {
1837         /* Call the normal routine */
1838         IopStartNextPacketByKey(DeviceObject, Cancelable, Key);
1839     }
1840 }
1841 
1842 /*
1843  * @implemented
1844  */
1845 VOID
1846 NTAPI
IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN Cancelable)1847 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
1848                   IN BOOLEAN Cancelable)
1849 {
1850     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1851 
1852     /* Get the Device Extension */
1853     DeviceExtension = IoGetDevObjExtension(DeviceObject);
1854 
1855     /* Check if deferred start was requested */
1856     if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
1857     {
1858         /* Call our internal function to handle the defered case */
1859         IopStartNextPacketByKeyEx(DeviceObject,
1860                                   0,
1861                                   DOE_SIO_NO_KEY |
1862                                   (Cancelable ? DOE_SIO_CANCELABLE : 0));
1863     }
1864     else
1865     {
1866         /* Call the normal routine */
1867         IopStartNextPacket(DeviceObject, Cancelable);
1868     }
1869 }
1870 
1871 /*
1872  * @implemented
1873  */
1874 VOID
1875 NTAPI
IoStartPacket(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PULONG Key,IN PDRIVER_CANCEL CancelFunction)1876 IoStartPacket(IN PDEVICE_OBJECT DeviceObject,
1877               IN PIRP Irp,
1878               IN PULONG Key,
1879               IN PDRIVER_CANCEL CancelFunction)
1880 {
1881     BOOLEAN Stat;
1882     KIRQL OldIrql, CancelIrql;
1883 
1884     /* Raise to dispatch level */
1885     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1886 
1887     /* Check if we should acquire the cancel lock */
1888     if (CancelFunction)
1889     {
1890         /* Acquire and set it */
1891         IoAcquireCancelSpinLock(&CancelIrql);
1892         Irp->CancelRoutine = CancelFunction;
1893     }
1894 
1895     /* Check if we have a key */
1896     if (Key)
1897     {
1898         /* Insert by key */
1899         Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue,
1900                                         &Irp->Tail.Overlay.DeviceQueueEntry,
1901                                         *Key);
1902     }
1903     else
1904     {
1905         /* Insert without a key */
1906         Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue,
1907                                    &Irp->Tail.Overlay.DeviceQueueEntry);
1908     }
1909 
1910     /* Check if this was a first insert */
1911     if (!Stat)
1912     {
1913         /* Set the IRP */
1914         DeviceObject->CurrentIrp = Irp;
1915 
1916         /* Check if this is a cancelable packet */
1917         if (CancelFunction)
1918         {
1919             /* Check if the caller requested no cancellation */
1920             if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
1921                 DOE_SIO_NO_CANCEL)
1922             {
1923                 /* He did, so remove the cancel routine */
1924                 Irp->CancelRoutine = NULL;
1925             }
1926 
1927             /* Release the cancel lock */
1928             IoReleaseCancelSpinLock(CancelIrql);
1929         }
1930 
1931         /* Call the Start I/O function */
1932         DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
1933     }
1934     else
1935     {
1936         /* The packet was inserted... check if we have a cancel function */
1937         if (CancelFunction)
1938         {
1939             /* Check if the IRP got cancelled */
1940             if (Irp->Cancel)
1941             {
1942                 /*
1943                  * Set the cancel IRQL, clear the currnet cancel routine and
1944                  * call ours
1945                  */
1946                 Irp->CancelIrql = CancelIrql;
1947                 Irp->CancelRoutine = NULL;
1948                 CancelFunction(DeviceObject, Irp);
1949             }
1950             else
1951             {
1952                 /* Otherwise, release the lock */
1953                 IoReleaseCancelSpinLock(CancelIrql);
1954             }
1955         }
1956     }
1957 
1958     /* Return back to previous IRQL */
1959     KeLowerIrql(OldIrql);
1960 }
1961 
1962 #if defined (_WIN64)
1963 ULONG
1964 NTAPI
IoWMIDeviceObjectToProviderId(IN PDEVICE_OBJECT DeviceObject)1965 IoWMIDeviceObjectToProviderId(
1966     IN PDEVICE_OBJECT DeviceObject)
1967 {
1968     UNIMPLEMENTED;
1969     return 0;
1970 }
1971 #endif
1972 
1973 /* EOF */
1974