7d17ce955164202de286e03961482b706602193a
[reactos.git] / ntoskrnl / io / iomgr / device.c
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
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
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
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
125 IoShutdownPnpDevices(VOID)
126 {
127 /* This routine is only used by Driver Verifier to validate shutdown */
128 return;
129 }
130
131 VOID
132 NTAPI
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
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
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
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
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
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
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
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
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
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
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
729 IopCreateSecurityDescriptorPerType(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
730 IN ULONG 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
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
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
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
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
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
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 = (DeviceExtensionSize + 7) &~ 7;
1088
1089 /* Total Size */
1090 TotalSize = AlignedDeviceExtensionSize +
1091 sizeof(DEVICE_OBJECT) +
1092 sizeof(EXTENDED_DEVOBJ_EXTENSION);
1093
1094 /* Create the Device Object */
1095 *DeviceObject = NULL;
1096 Status = ObCreateObject(KernelMode,
1097 IoDeviceObjectType,
1098 &ObjectAttributes,
1099 KernelMode,
1100 NULL,
1101 TotalSize,
1102 0,
1103 0,
1104 (PVOID*)&CreatedDeviceObject);
1105 if (!NT_SUCCESS(Status))
1106 {
1107 if (Dacl != NULL) ExFreePoolWithTag(Dacl, 'eSoI');
1108
1109 return Status;
1110 }
1111
1112 /* Clear the whole Object and extension so we don't null stuff manually */
1113 RtlZeroMemory(CreatedDeviceObject, TotalSize);
1114
1115 /*
1116 * Setup the Type and Size. Note that we don't use the aligned size,
1117 * because that's only padding for the DevObjExt and not part of the Object.
1118 */
1119 CreatedDeviceObject->Type = IO_TYPE_DEVICE;
1120 CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize;
1121
1122 /* The kernel extension is after the driver internal extension */
1123 DeviceObjectExtension = (PDEVOBJ_EXTENSION)
1124 ((ULONG_PTR)(CreatedDeviceObject + 1) +
1125 AlignedDeviceExtensionSize);
1126
1127 /* Set the Type and Size. Question: why is Size 0 on Windows? */
1128 DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
1129 DeviceObjectExtension->Size = 0;
1130
1131 /* Initialize with Power Manager */
1132 PoInitializeDeviceObject(DeviceObjectExtension);
1133
1134 /* Link the Object and Extension */
1135 DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
1136 CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
1137
1138 /* Set Device Object Data */
1139 CreatedDeviceObject->DeviceType = DeviceType;
1140 CreatedDeviceObject->Characteristics = DeviceCharacteristics;
1141 CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ?
1142 CreatedDeviceObject + 1 :
1143 NULL;
1144 CreatedDeviceObject->StackSize = 1;
1145 CreatedDeviceObject->AlignmentRequirement = 0;
1146
1147 /* Set the Flags */
1148 CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING;
1149 if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE;
1150 if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME;
1151
1152 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
1153 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
1154 (CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) ||
1155 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) ||
1156 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE))
1157 {
1158 /* Create Vpb */
1159 Status = IopCreateVpb(CreatedDeviceObject);
1160 if (!NT_SUCCESS(Status))
1161 {
1162 if (Dacl != NULL) ExFreePoolWithTag(Dacl, 'eSoI');
1163
1164 /* Dereference the device object and fail */
1165 ObDereferenceObject(CreatedDeviceObject);
1166 return Status;
1167 }
1168
1169 /* Initialize Lock Event */
1170 KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
1171 SynchronizationEvent,
1172 TRUE);
1173 }
1174
1175 /* Set the right Sector Size */
1176 switch (DeviceType)
1177 {
1178 /* All disk systems */
1179 case FILE_DEVICE_DISK_FILE_SYSTEM:
1180 case FILE_DEVICE_DISK:
1181 case FILE_DEVICE_VIRTUAL_DISK:
1182
1183 /* The default is 512 bytes */
1184 CreatedDeviceObject->SectorSize = 512;
1185 break;
1186
1187 /* CD-ROM file systems */
1188 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
1189
1190 /* The default is 2048 bytes */
1191 CreatedDeviceObject->SectorSize = 2048;
1192 }
1193
1194 /* Create the Device Queue */
1195 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
1196 (CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) ||
1197 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
1198 (CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) ||
1199 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM))
1200 {
1201 /* Simple FS Devices, they don't need a real Device Queue */
1202 InitializeListHead(&CreatedDeviceObject->Queue.ListEntry);
1203 }
1204 else
1205 {
1206 /* An actual Device, initialize its DQ */
1207 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
1208 }
1209
1210 /* Insert the Object */
1211 Status = ObInsertObject(CreatedDeviceObject,
1212 NULL,
1213 FILE_READ_DATA | FILE_WRITE_DATA,
1214 1,
1215 (PVOID*)&CreatedDeviceObject,
1216 &TempHandle);
1217 if (!NT_SUCCESS(Status))
1218 {
1219 if (Dacl != NULL) ExFreePoolWithTag(Dacl, 'eSoI');
1220
1221 return Status;
1222 }
1223
1224 /* Now do the final linking */
1225 ObReferenceObject(DriverObject);
1226 ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
1227 CreatedDeviceObject->DriverObject = DriverObject;
1228 IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
1229
1230 /* Link with the power manager */
1231 if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
1232
1233 /* Close the temporary handle and return to caller */
1234 ObCloseHandle(TempHandle, KernelMode);
1235 *DeviceObject = CreatedDeviceObject;
1236
1237 if (Dacl != NULL) ExFreePoolWithTag(Dacl, 'eSoI');
1238
1239 return STATUS_SUCCESS;
1240 }
1241
1242 /*
1243 * IoDeleteDevice
1244 *
1245 * Status
1246 * @implemented
1247 */
1248 VOID
1249 NTAPI
1250 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)
1251 {
1252 PIO_TIMER Timer;
1253
1254 /* Check if the device is registered for shutdown notifications */
1255 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
1256 {
1257 /* Call the shutdown notifications */
1258 IoUnregisterShutdownNotification(DeviceObject);
1259 }
1260
1261 /* Check if it has a timer */
1262 Timer = DeviceObject->Timer;
1263 if (Timer)
1264 {
1265 /* Remove it and free it */
1266 IopRemoveTimerFromTimerList(Timer);
1267 ExFreePoolWithTag(Timer, TAG_IO_TIMER);
1268 }
1269
1270 /* Check if the device has a name */
1271 if (DeviceObject->Flags & DO_DEVICE_HAS_NAME)
1272 {
1273 /* It does, make it temporary so we can remove it */
1274 ObMakeTemporaryObject(DeviceObject);
1275 }
1276
1277 /* Set the pending delete flag */
1278 IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING;
1279
1280 /* Unlink with the power manager */
1281 if (DeviceObject->Vpb) PoRemoveVolumeDevice(DeviceObject);
1282
1283 /* Check if the device object can be unloaded */
1284 if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject);
1285 }
1286
1287 /*
1288 * IoDetachDevice
1289 *
1290 * Status
1291 * @implemented
1292 */
1293 VOID
1294 NTAPI
1295 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
1296 {
1297 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1298
1299 /* Sanity check */
1300 DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice);
1301 ASSERT(DeviceExtension->AttachedTo == TargetDevice);
1302
1303 /* Remove the attachment */
1304 DeviceExtension->AttachedTo = NULL;
1305 TargetDevice->AttachedDevice = NULL;
1306
1307 /* Check if it's ok to delete this device */
1308 if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) &&
1309 !(TargetDevice->ReferenceCount))
1310 {
1311 /* It is, do it */
1312 IopUnloadDevice(TargetDevice);
1313 }
1314 }
1315
1316 /*
1317 * @implemented
1318 */
1319 NTSTATUS
1320 NTAPI
1321 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject,
1322 IN PDEVICE_OBJECT *DeviceObjectList,
1323 IN ULONG DeviceObjectListSize,
1324 OUT PULONG ActualNumberDeviceObjects)
1325 {
1326 ULONG ActualDevices = 1;
1327 PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject;
1328 KIRQL OldIrql;
1329
1330 /* Lock the Device list while we enumerate it */
1331 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1332
1333 /* Find out how many devices we'll enumerate */
1334 while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++;
1335
1336 /* Go back to the first */
1337 CurrentDevice = DriverObject->DeviceObject;
1338
1339 /* Start by at least returning this */
1340 *ActualNumberDeviceObjects = ActualDevices;
1341
1342 /* Check if we can support so many */
1343 if ((ActualDevices * sizeof(PDEVICE_OBJECT)) > DeviceObjectListSize)
1344 {
1345 /* Fail because the buffer was too small */
1346 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1347 return STATUS_BUFFER_TOO_SMALL;
1348 }
1349
1350 /* Check if the caller wanted the device list */
1351 if (DeviceObjectList)
1352 {
1353 /* Loop through all the devices */
1354 while (ActualDevices)
1355 {
1356 /* Reference each Device */
1357 ObReferenceObject(CurrentDevice);
1358
1359 /* Add it to the list */
1360 *DeviceObjectList = CurrentDevice;
1361
1362 /* Go to the next one */
1363 CurrentDevice = CurrentDevice->NextDevice;
1364 ActualDevices--;
1365 DeviceObjectList++;
1366 }
1367 }
1368
1369 /* Release the device list lock */
1370 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1371
1372 /* Return the status */
1373 return STATUS_SUCCESS;
1374 }
1375
1376 /*
1377 * IoGetAttachedDevice
1378 *
1379 * Status
1380 * @implemented
1381 */
1382 PDEVICE_OBJECT
1383 NTAPI
1384 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
1385 {
1386 /* Get the last attached device */
1387 while (DeviceObject->AttachedDevice)
1388 {
1389 /* Move to the next one */
1390 DeviceObject = DeviceObject->AttachedDevice;
1391 }
1392
1393 /* Return it */
1394 return DeviceObject;
1395 }
1396
1397 /*
1398 * IoGetAttachedDeviceReference
1399 *
1400 * Status
1401 * @implemented
1402 */
1403 PDEVICE_OBJECT
1404 NTAPI
1405 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
1406 {
1407 /* Reference the Attached Device */
1408 DeviceObject = IoGetAttachedDevice(DeviceObject);
1409 ObReferenceObject(DeviceObject);
1410 return DeviceObject;
1411 }
1412
1413 /*
1414 * @implemented
1415 */
1416 PDEVICE_OBJECT
1417 NTAPI
1418 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject)
1419 {
1420 /* Reference the lowest attached device */
1421 DeviceObject = IopGetLowestDevice(DeviceObject);
1422 ObReferenceObject(DeviceObject);
1423 return DeviceObject;
1424 }
1425
1426 /*
1427 * IoGetDeviceObjectPointer
1428 *
1429 * Status
1430 * @implemented
1431 */
1432 NTSTATUS
1433 NTAPI
1434 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
1435 IN ACCESS_MASK DesiredAccess,
1436 OUT PFILE_OBJECT *FileObject,
1437 OUT PDEVICE_OBJECT *DeviceObject)
1438 {
1439 /* Call the helper routine for a normal operation */
1440 return IopGetDeviceObjectPointer(ObjectName,
1441 DesiredAccess,
1442 FileObject,
1443 DeviceObject,
1444 0);
1445 }
1446
1447 /*
1448 * @implemented
1449 */
1450 NTSTATUS
1451 NTAPI
1452 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject,
1453 OUT PDEVICE_OBJECT *DiskDeviceObject)
1454 {
1455 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1456 PVPB Vpb;
1457 KIRQL OldIrql;
1458 NTSTATUS Status;
1459
1460 /* Make sure there's a VPB */
1461 if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER;
1462
1463 /* Acquire it */
1464 IoAcquireVpbSpinLock(&OldIrql);
1465
1466 /* Get the Device Extension */
1467 DeviceExtension = IoGetDevObjExtension(FileSystemDeviceObject);
1468
1469 /* Make sure this one has a VPB too */
1470 Vpb = DeviceExtension->Vpb;
1471 if (Vpb)
1472 {
1473 /* Make sure that it's mounted */
1474 if ((Vpb->ReferenceCount) &&
1475 (Vpb->Flags & VPB_MOUNTED))
1476 {
1477 /* Return the Disk Device Object */
1478 *DiskDeviceObject = Vpb->RealDevice;
1479
1480 /* Reference it and return success */
1481 ObReferenceObject(Vpb->RealDevice);
1482 Status = STATUS_SUCCESS;
1483 }
1484 else
1485 {
1486 /* It's not, so return failure */
1487 Status = STATUS_VOLUME_DISMOUNTED;
1488 }
1489 }
1490 else
1491 {
1492 /* Fail */
1493 Status = STATUS_INVALID_PARAMETER;
1494 }
1495
1496 /* Release the lock */
1497 IoReleaseVpbSpinLock(OldIrql);
1498 return Status;
1499 }
1500
1501 /*
1502 * @implemented
1503 */
1504 PDEVICE_OBJECT
1505 NTAPI
1506 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)
1507 {
1508 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1509 PDEVICE_OBJECT LowerDeviceObject = NULL;
1510
1511 /* Make sure it's not getting deleted */
1512 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1513 if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING |
1514 DOE_DELETE_PENDING |
1515 DOE_REMOVE_PENDING |
1516 DOE_REMOVE_PROCESSED)))
1517 {
1518 /* Get the Lower Device Object */
1519 LowerDeviceObject = DeviceExtension->AttachedTo;
1520
1521 /* Check that we got a valid device object */
1522 if (LowerDeviceObject)
1523 {
1524 /* We did so let's reference it */
1525 ObReferenceObject(LowerDeviceObject);
1526 }
1527 }
1528
1529 /* Return it */
1530 return LowerDeviceObject;
1531 }
1532
1533 /*
1534 * @implemented
1535 */
1536 PDEVICE_OBJECT
1537 NTAPI
1538 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject)
1539 {
1540 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
1541
1542 /* Check if we have a VPB with a device object */
1543 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
1544 {
1545 /* Then use the DO from the VPB */
1546 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
1547 DeviceObject = FileObject->Vpb->DeviceObject;
1548 }
1549 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
1550 (FileObject->DeviceObject->Vpb) &&
1551 (FileObject->DeviceObject->Vpb->DeviceObject))
1552 {
1553 /* The disk device actually has a VPB, so get the DO from there */
1554 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
1555 }
1556 else
1557 {
1558 /* Otherwise, this was a direct open */
1559 DeviceObject = FileObject->DeviceObject;
1560 }
1561
1562 /* Sanity check */
1563 ASSERT(DeviceObject != NULL);
1564
1565 /* Check if we were attached */
1566 if (DeviceObject->AttachedDevice)
1567 {
1568 /* Check if the file object has an extension present */
1569 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1570 {
1571 /* Sanity check, direct open files can't have this */
1572 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
1573
1574 /* Check if the extension is really present */
1575 if (FileObject->FileObjectExtension)
1576 {
1577 PFILE_OBJECT_EXTENSION FileObjectExtension;
1578
1579 /* Cast the buffer to something we understand */
1580 FileObjectExtension = FileObject->FileObjectExtension;
1581
1582 /* Check if have a valid replacement top level device */
1583 if (FileObjectExtension->TopDeviceObjectHint &&
1584 IopVerifyDeviceObjectOnStack(DeviceObject,
1585 FileObjectExtension->TopDeviceObjectHint))
1586 {
1587 /* Use this instead of returning the top level device */
1588 return FileObjectExtension->TopDeviceObjectHint;
1589 }
1590 }
1591 }
1592
1593 /* Return the highest attached device */
1594 DeviceObject = IoGetAttachedDevice(DeviceObject);
1595 }
1596
1597 /* Return the DO we found */
1598 return DeviceObject;
1599 }
1600
1601 /*
1602 * @implemented
1603 */
1604 NTSTATUS
1605 NTAPI
1606 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
1607 OUT PDEVICE_OBJECT *DeviceObject)
1608 {
1609 NTSTATUS Status;
1610 PDEVICE_NODE DeviceNode = NULL;
1611
1612 /* Call the internal helper function */
1613 Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode);
1614 if (NT_SUCCESS(Status) && DeviceNode)
1615 {
1616 *DeviceObject = DeviceNode->PhysicalDeviceObject;
1617 }
1618 return Status;
1619 }
1620
1621 /*
1622 * @implemented
1623 */
1624 PDEVICE_OBJECT
1625 NTAPI
1626 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
1627 {
1628 PDEVICE_OBJECT DeviceObject;
1629
1630 /*
1631 * If the FILE_OBJECT's VPB is defined,
1632 * get the device from it.
1633 */
1634 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
1635 {
1636 /* Use the VPB's Device Object's */
1637 DeviceObject = FileObject->Vpb->DeviceObject;
1638 }
1639 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
1640 (FileObject->DeviceObject->Vpb) &&
1641 (FileObject->DeviceObject->Vpb->DeviceObject))
1642 {
1643 /* Use the VPB's File System Object */
1644 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
1645 }
1646 else
1647 {
1648 /* Use the FO's Device Object */
1649 DeviceObject = FileObject->DeviceObject;
1650 }
1651
1652 /* Return the device object we found */
1653 ASSERT(DeviceObject != NULL);
1654 return DeviceObject;
1655 }
1656
1657 /*
1658 * @implemented
1659 */
1660 NTSTATUS
1661 NTAPI
1662 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
1663 {
1664 PSHUTDOWN_ENTRY Entry;
1665
1666 /* Allocate the shutdown entry */
1667 Entry = ExAllocatePoolWithTag(NonPagedPool,
1668 sizeof(SHUTDOWN_ENTRY),
1669 TAG_SHUTDOWN_ENTRY);
1670 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
1671
1672 /* Set the DO */
1673 Entry->DeviceObject = DeviceObject;
1674
1675 /* Reference it so it doesn't go away */
1676 ObReferenceObject(DeviceObject);
1677
1678 /* Insert it into the list */
1679 ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
1680 &Entry->ShutdownList,
1681 &ShutdownListLock);
1682
1683 /* Set the shutdown registered flag */
1684 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
1685 return STATUS_SUCCESS;
1686 }
1687
1688 /*
1689 * @implemented
1690 */
1691 NTSTATUS
1692 NTAPI
1693 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
1694 {
1695 PSHUTDOWN_ENTRY Entry;
1696
1697 /* Allocate the shutdown entry */
1698 Entry = ExAllocatePoolWithTag(NonPagedPool,
1699 sizeof(SHUTDOWN_ENTRY),
1700 TAG_SHUTDOWN_ENTRY);
1701 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
1702
1703 /* Set the DO */
1704 Entry->DeviceObject = DeviceObject;
1705
1706 /* Reference it so it doesn't go away */
1707 ObReferenceObject(DeviceObject);
1708
1709 /* Insert it into the list */
1710 ExInterlockedInsertHeadList(&ShutdownListHead,
1711 &Entry->ShutdownList,
1712 &ShutdownListLock);
1713
1714 /* Set the shutdown registered flag */
1715 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
1716 return STATUS_SUCCESS;
1717 }
1718
1719 /*
1720 * @implemented
1721 */
1722 VOID
1723 NTAPI
1724 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
1725 {
1726 PSHUTDOWN_ENTRY ShutdownEntry;
1727 PLIST_ENTRY NextEntry;
1728 KIRQL OldIrql;
1729
1730 /* Remove the flag */
1731 DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
1732
1733 /* Acquire the shutdown lock and loop the shutdown list */
1734 KeAcquireSpinLock(&ShutdownListLock, &OldIrql);
1735 NextEntry = ShutdownListHead.Flink;
1736 while (NextEntry != &ShutdownListHead)
1737 {
1738 /* Get the entry */
1739 ShutdownEntry = CONTAINING_RECORD(NextEntry,
1740 SHUTDOWN_ENTRY,
1741 ShutdownList);
1742
1743 /* Get if the DO matches */
1744 if (ShutdownEntry->DeviceObject == DeviceObject)
1745 {
1746 /* Remove it from the list */
1747 RemoveEntryList(NextEntry);
1748 NextEntry = NextEntry->Blink;
1749
1750 /* Free the entry */
1751 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
1752
1753 /* Get rid of our reference to it */
1754 ObDereferenceObject(DeviceObject);
1755 }
1756
1757 /* Go to the next entry */
1758 NextEntry = NextEntry->Flink;
1759 }
1760
1761 /* Now loop the last chance list */
1762 NextEntry = LastChanceShutdownListHead.Flink;
1763 while (NextEntry != &LastChanceShutdownListHead)
1764 {
1765 /* Get the entry */
1766 ShutdownEntry = CONTAINING_RECORD(NextEntry,
1767 SHUTDOWN_ENTRY,
1768 ShutdownList);
1769
1770 /* Get if the DO matches */
1771 if (ShutdownEntry->DeviceObject == DeviceObject)
1772 {
1773 /* Remove it from the list */
1774 RemoveEntryList(NextEntry);
1775 NextEntry = NextEntry->Blink;
1776
1777 /* Free the entry */
1778 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
1779
1780 /* Get rid of our reference to it */
1781 ObDereferenceObject(DeviceObject);
1782 }
1783
1784 /* Go to the next entry */
1785 NextEntry = NextEntry->Flink;
1786 }
1787
1788 /* Release the shutdown lock */
1789 KeReleaseSpinLock(&ShutdownListLock, OldIrql);
1790 }
1791
1792 /*
1793 * @implemented
1794 */
1795 VOID
1796 NTAPI
1797 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject,
1798 IN BOOLEAN DeferredStartIo,
1799 IN BOOLEAN NonCancelable)
1800 {
1801 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1802
1803 /* Get the Device Extension */
1804 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1805
1806 /* Set the flags the caller requested */
1807 DeviceExtension->StartIoFlags |= (DeferredStartIo) ? DOE_SIO_DEFERRED : 0;
1808 DeviceExtension->StartIoFlags |= (NonCancelable) ? DOE_SIO_NO_CANCEL : 0;
1809 }
1810
1811 /*
1812 * @implemented
1813 */
1814 VOID
1815 NTAPI
1816 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
1817 IN BOOLEAN Cancelable,
1818 IN ULONG Key)
1819 {
1820 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1821
1822 /* Get the Device Extension */
1823 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1824
1825 /* Check if deferred start was requested */
1826 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
1827 {
1828 /* Call our internal function to handle the defered case */
1829 IopStartNextPacketByKeyEx(DeviceObject,
1830 Key,
1831 DOE_SIO_WITH_KEY |
1832 (Cancelable ? DOE_SIO_CANCELABLE : 0));
1833 }
1834 else
1835 {
1836 /* Call the normal routine */
1837 IopStartNextPacketByKey(DeviceObject, Cancelable, Key);
1838 }
1839 }
1840
1841 /*
1842 * @implemented
1843 */
1844 VOID
1845 NTAPI
1846 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
1847 IN BOOLEAN Cancelable)
1848 {
1849 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1850
1851 /* Get the Device Extension */
1852 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1853
1854 /* Check if deferred start was requested */
1855 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
1856 {
1857 /* Call our internal function to handle the defered case */
1858 IopStartNextPacketByKeyEx(DeviceObject,
1859 0,
1860 DOE_SIO_NO_KEY |
1861 (Cancelable ? DOE_SIO_CANCELABLE : 0));
1862 }
1863 else
1864 {
1865 /* Call the normal routine */
1866 IopStartNextPacket(DeviceObject, Cancelable);
1867 }
1868 }
1869
1870 /*
1871 * @implemented
1872 */
1873 VOID
1874 NTAPI
1875 IoStartPacket(IN PDEVICE_OBJECT DeviceObject,
1876 IN PIRP Irp,
1877 IN PULONG Key,
1878 IN PDRIVER_CANCEL CancelFunction)
1879 {
1880 BOOLEAN Stat;
1881 KIRQL OldIrql, CancelIrql;
1882
1883 /* Raise to dispatch level */
1884 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1885
1886 /* Check if we should acquire the cancel lock */
1887 if (CancelFunction)
1888 {
1889 /* Acquire and set it */
1890 IoAcquireCancelSpinLock(&CancelIrql);
1891 Irp->CancelRoutine = CancelFunction;
1892 }
1893
1894 /* Check if we have a key */
1895 if (Key)
1896 {
1897 /* Insert by key */
1898 Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue,
1899 &Irp->Tail.Overlay.DeviceQueueEntry,
1900 *Key);
1901 }
1902 else
1903 {
1904 /* Insert without a key */
1905 Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue,
1906 &Irp->Tail.Overlay.DeviceQueueEntry);
1907 }
1908
1909 /* Check if this was a first insert */
1910 if (!Stat)
1911 {
1912 /* Set the IRP */
1913 DeviceObject->CurrentIrp = Irp;
1914
1915 /* Check if this is a cancelable packet */
1916 if (CancelFunction)
1917 {
1918 /* Check if the caller requested no cancellation */
1919 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
1920 DOE_SIO_NO_CANCEL)
1921 {
1922 /* He did, so remove the cancel routine */
1923 Irp->CancelRoutine = NULL;
1924 }
1925
1926 /* Release the cancel lock */
1927 IoReleaseCancelSpinLock(CancelIrql);
1928 }
1929
1930 /* Call the Start I/O function */
1931 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
1932 }
1933 else
1934 {
1935 /* The packet was inserted... check if we have a cancel function */
1936 if (CancelFunction)
1937 {
1938 /* Check if the IRP got cancelled */
1939 if (Irp->Cancel)
1940 {
1941 /*
1942 * Set the cancel IRQL, clear the currnet cancel routine and
1943 * call ours
1944 */
1945 Irp->CancelIrql = CancelIrql;
1946 Irp->CancelRoutine = NULL;
1947 CancelFunction(DeviceObject, Irp);
1948 }
1949 else
1950 {
1951 /* Otherwise, release the lock */
1952 IoReleaseCancelSpinLock(CancelIrql);
1953 }
1954 }
1955 }
1956
1957 /* Return back to previous IRQL */
1958 KeLowerIrql(OldIrql);
1959 }
1960
1961 #if defined (_WIN64)
1962 ULONG
1963 NTAPI
1964 IoWMIDeviceObjectToProviderId(
1965 IN PDEVICE_OBJECT DeviceObject)
1966 {
1967 UNIMPLEMENTED;
1968 return 0;
1969 }
1970 #endif
1971
1972 /* EOF */