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 = (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 */ 1973