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 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 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 = 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1965 IoWMIDeviceObjectToProviderId( 1966 IN PDEVICE_OBJECT DeviceObject) 1967 { 1968 UNIMPLEMENTED; 1969 return 0; 1970 } 1971 #endif 1972 1973 /* EOF */ 1974