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