1 /* 2 * ReactOS kernel 3 * Copyright (C) 2011 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 18 * 19 * COPYRIGHT: See COPYING in the top level directory 20 * PROJECT: ReactOS kernel 21 * FILE: drivers/filesystem/mountmgr/mountmgr.c 22 * PURPOSE: Mount Manager 23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org) 24 * Alex Ionescu (alex.ionescu@reactos.org) 25 */ 26 27 #include "mntmgr.h" 28 29 #define NDEBUG 30 #include <debug.h> 31 32 #if defined(ALLOC_PRAGMA) 33 #pragma alloc_text(INIT, MountmgrReadNoAutoMount) 34 #pragma alloc_text(INIT, DriverEntry) 35 #endif 36 37 /* FIXME */ 38 GUID MountedDevicesGuid = {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}}; 39 40 PDEVICE_OBJECT gdeviceObject; 41 KEVENT UnloadEvent; 42 LONG Unloading; 43 44 static const WCHAR Cunc[] = L"\\??\\C:"; 45 #define Cunc_LETTER_POSITION 4 46 47 /* 48 * @implemented 49 */ 50 BOOLEAN 51 IsOffline(PUNICODE_STRING SymbolicName) 52 { 53 NTSTATUS Status; 54 ULONG IsOffline, Default; 55 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 56 57 /* Prepare to look in the registry to see if 58 * given volume is offline 59 */ 60 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 61 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 62 QueryTable[0].Name = SymbolicName->Buffer; 63 QueryTable[0].EntryContext = &IsOffline; 64 QueryTable[0].DefaultType = REG_DWORD; 65 QueryTable[0].DefaultLength = sizeof(ULONG); 66 QueryTable[0].DefaultData = &Default; 67 68 Default = 0; 69 70 /* Query status */ 71 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 72 OfflinePath, 73 QueryTable, 74 NULL, 75 NULL); 76 if (!NT_SUCCESS(Status)) 77 { 78 IsOffline = 0; 79 } 80 81 return (IsOffline != 0); 82 } 83 84 /* 85 * @implemented 86 */ 87 BOOLEAN 88 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation) 89 { 90 PLIST_ENTRY NextEntry; 91 PSYMLINK_INFORMATION SymlinkInfo; 92 93 /* Browse all the symlinks to check if there is at least a drive letter */ 94 for (NextEntry = DeviceInformation->SymbolicLinksListHead.Flink; 95 NextEntry != &DeviceInformation->SymbolicLinksListHead; 96 NextEntry = NextEntry->Flink) 97 { 98 SymlinkInfo = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 99 100 if (IsDriveLetter(&SymlinkInfo->Name) && SymlinkInfo->Online) 101 { 102 return TRUE; 103 } 104 } 105 106 return FALSE; 107 } 108 109 /* 110 * @implemented 111 */ 112 NTSTATUS 113 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter, 114 IN PUNICODE_STRING DeviceName, 115 IN UCHAR Letter, 116 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL) 117 { 118 NTSTATUS Status = STATUS_UNSUCCESSFUL; 119 120 /* Allocate a big enough buffer to contain the symbolic link */ 121 DriveLetter->MaximumLength = DosDevices.Length + 3 * sizeof(WCHAR); 122 DriveLetter->Buffer = AllocatePool(DriveLetter->MaximumLength); 123 if (!DriveLetter->Buffer) 124 { 125 return STATUS_INSUFFICIENT_RESOURCES; 126 } 127 128 /* Copy prefix */ 129 RtlCopyUnicodeString(DriveLetter, &DosDevices); 130 131 /* Update string to reflect real contents */ 132 DriveLetter->Length = DosDevices.Length + 2 * sizeof(WCHAR); 133 DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR) + 2] = UNICODE_NULL; 134 DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR) + 1] = L':'; 135 136 /* If caller wants a no drive entry */ 137 if (Letter == (UCHAR)-1) 138 { 139 /* Then, create a no letter entry */ 140 CreateNoDriveLetterEntry(UniqueId); 141 FreePool(DriveLetter->Buffer); 142 return STATUS_UNSUCCESSFUL; 143 } 144 else if (Letter) 145 { 146 /* Use the letter given by the caller */ 147 DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR)] = (WCHAR)Letter; 148 Status = GlobalCreateSymbolicLink(DriveLetter, DeviceName); 149 if (NT_SUCCESS(Status)) 150 { 151 return Status; 152 } 153 } 154 155 /* If caller didn't provide a letter, let's find one for him */ 156 157 if (RtlPrefixUnicodeString(&DeviceFloppy, DeviceName, TRUE)) 158 { 159 /* If the device is a floppy, start with letter A */ 160 Letter = 'A'; 161 } 162 else if (RtlPrefixUnicodeString(&DeviceCdRom, DeviceName, TRUE)) 163 { 164 /* If the device is a CD-ROM, start with letter D */ 165 Letter = 'D'; 166 } 167 else 168 { 169 /* Finally, if it's a disk, use C */ 170 Letter = 'C'; 171 } 172 173 /* Try to affect a letter (up to Z, ofc) until it's possible */ 174 for (; Letter <= 'Z'; Letter++) 175 { 176 DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR)] = (WCHAR)Letter; 177 Status = GlobalCreateSymbolicLink(DriveLetter, DeviceName); 178 if (NT_SUCCESS(Status)) 179 { 180 DPRINT("Assigned drive %c: to %wZ\n", Letter, DeviceName); 181 return Status; 182 } 183 } 184 185 /* We failed to allocate a letter */ 186 FreePool(DriveLetter->Buffer); 187 DPRINT("Failed to create a drive letter for %wZ\n", DeviceName); 188 return Status; 189 } 190 191 /* 192 * @implemented 193 */ 194 NTSTATUS 195 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName, 196 OUT PUNICODE_STRING DeviceName OPTIONAL, 197 OUT PMOUNTDEV_UNIQUE_ID * UniqueId OPTIONAL, 198 OUT PBOOLEAN Removable OPTIONAL, 199 OUT PBOOLEAN GptDriveLetter OPTIONAL, 200 OUT PBOOLEAN HasGuid OPTIONAL, 201 IN OUT LPGUID StableGuid OPTIONAL, 202 OUT PBOOLEAN Valid OPTIONAL) 203 { 204 PIRP Irp; 205 USHORT Size; 206 KEVENT Event; 207 BOOLEAN IsRemovable; 208 PMOUNTDEV_NAME Name; 209 PMOUNTDEV_UNIQUE_ID Id; 210 PFILE_OBJECT FileObject; 211 PIO_STACK_LOCATION Stack; 212 NTSTATUS Status, IntStatus; 213 PDEVICE_OBJECT DeviceObject; 214 IO_STATUS_BLOCK IoStatusBlock; 215 PARTITION_INFORMATION_EX PartitionInfo; 216 STORAGE_DEVICE_NUMBER StorageDeviceNumber; 217 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes; 218 219 /* Get device associated with the symbolic name */ 220 Status = IoGetDeviceObjectPointer(SymbolicName, 221 FILE_READ_ATTRIBUTES, 222 &FileObject, 223 &DeviceObject); 224 if (!NT_SUCCESS(Status)) 225 { 226 return Status; 227 } 228 229 /* The associate FO can't have a file name */ 230 if (FileObject->FileName.Length) 231 { 232 ObDereferenceObject(FileObject); 233 return STATUS_OBJECT_NAME_NOT_FOUND; 234 } 235 236 /* Check if it's removable & return to the user (if asked to) */ 237 IsRemovable = (FileObject->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA); 238 if (Removable) 239 { 240 *Removable = IsRemovable; 241 } 242 243 /* Get the attached device */ 244 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 245 246 /* If we've been asked for a GPT drive letter */ 247 if (GptDriveLetter) 248 { 249 /* Consider it has one */ 250 *GptDriveLetter = TRUE; 251 252 if (!IsRemovable) 253 { 254 /* Query the GPT attributes */ 255 KeInitializeEvent(&Event, NotificationEvent, FALSE); 256 Irp = IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES, 257 DeviceObject, 258 NULL, 259 0, 260 &GptAttributes, 261 sizeof(GptAttributes), 262 FALSE, 263 &Event, 264 &IoStatusBlock); 265 if (!Irp) 266 { 267 ObDereferenceObject(DeviceObject); 268 ObDereferenceObject(FileObject); 269 return STATUS_INSUFFICIENT_RESOURCES; 270 } 271 272 Status = IoCallDriver(DeviceObject, Irp); 273 if (Status == STATUS_PENDING) 274 { 275 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 276 Status = IoStatusBlock.Status; 277 } 278 279 /* In case of failure, don't fail, that's no vital */ 280 if (!NT_SUCCESS(Status)) 281 { 282 Status = STATUS_SUCCESS; 283 } 284 /* Check if it has a drive letter */ 285 else if (GptAttributes.GptAttributes & GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER) 286 { 287 *GptDriveLetter = FALSE; 288 } 289 } 290 } 291 292 /* If caller wants to know if there's valid contents */ 293 if (Valid) 294 { 295 /* Suppose it's not OK */ 296 *Valid = FALSE; 297 298 if (!IsRemovable) 299 { 300 /* Query partitions information */ 301 KeInitializeEvent(&Event, NotificationEvent, FALSE); 302 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX, 303 DeviceObject, 304 NULL, 305 0, 306 &PartitionInfo, 307 sizeof(PartitionInfo), 308 FALSE, 309 &Event, 310 &IoStatusBlock); 311 if (!Irp) 312 { 313 ObDereferenceObject(DeviceObject); 314 ObDereferenceObject(FileObject); 315 return STATUS_INSUFFICIENT_RESOURCES; 316 } 317 318 Status = IoCallDriver(DeviceObject, Irp); 319 if (Status == STATUS_PENDING) 320 { 321 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 322 Status = IoStatusBlock.Status; 323 } 324 325 /* Once again here, failure isn't major */ 326 if (!NT_SUCCESS(Status)) 327 { 328 Status = STATUS_SUCCESS; 329 } 330 /* Verify we know something in */ 331 else if (PartitionInfo.PartitionStyle == PARTITION_STYLE_MBR && 332 IsRecognizedPartition(PartitionInfo.Mbr.PartitionType)) 333 { 334 *Valid = TRUE; 335 } 336 337 /* It looks correct, ensure it is & query device number */ 338 if (*Valid) 339 { 340 KeInitializeEvent(&Event, NotificationEvent, FALSE); 341 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER, 342 DeviceObject, 343 NULL, 344 0, 345 &StorageDeviceNumber, 346 sizeof(StorageDeviceNumber), 347 FALSE, 348 &Event, 349 &IoStatusBlock); 350 if (!Irp) 351 { 352 ObDereferenceObject(DeviceObject); 353 ObDereferenceObject(FileObject); 354 return STATUS_INSUFFICIENT_RESOURCES; 355 } 356 357 Status = IoCallDriver(DeviceObject, Irp); 358 if (Status == STATUS_PENDING) 359 { 360 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 361 Status = IoStatusBlock.Status; 362 } 363 364 if (!NT_SUCCESS(Status)) 365 { 366 Status = STATUS_SUCCESS; 367 } 368 else 369 { 370 *Valid = FALSE; 371 } 372 } 373 } 374 } 375 376 /* If caller needs device name */ 377 if (DeviceName) 378 { 379 /* Allocate a buffer just to request length */ 380 Name = AllocatePool(sizeof(MOUNTDEV_NAME)); 381 if (!Name) 382 { 383 ObDereferenceObject(DeviceObject); 384 ObDereferenceObject(FileObject); 385 return STATUS_INSUFFICIENT_RESOURCES; 386 } 387 388 /* Query device name */ 389 KeInitializeEvent(&Event, NotificationEvent, FALSE); 390 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 391 DeviceObject, 392 NULL, 393 0, 394 Name, 395 sizeof(MOUNTDEV_NAME), 396 FALSE, 397 &Event, 398 &IoStatusBlock); 399 if (!Irp) 400 { 401 FreePool(Name); 402 ObDereferenceObject(DeviceObject); 403 ObDereferenceObject(FileObject); 404 return STATUS_INSUFFICIENT_RESOURCES; 405 } 406 407 Stack = IoGetNextIrpStackLocation(Irp); 408 Stack->FileObject = FileObject; 409 410 Status = IoCallDriver(DeviceObject, Irp); 411 if (Status == STATUS_PENDING) 412 { 413 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 414 Status = IoStatusBlock.Status; 415 } 416 417 /* Now, we've got the correct length */ 418 if (Status == STATUS_BUFFER_OVERFLOW) 419 { 420 Size = Name->NameLength + sizeof(MOUNTDEV_NAME); 421 422 FreePool(Name); 423 424 /* Allocate proper size */ 425 Name = AllocatePool(Size); 426 if (!Name) 427 { 428 ObDereferenceObject(DeviceObject); 429 ObDereferenceObject(FileObject); 430 return STATUS_INSUFFICIENT_RESOURCES; 431 } 432 433 /* And query name (for real that time) */ 434 KeInitializeEvent(&Event, NotificationEvent, FALSE); 435 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 436 DeviceObject, 437 NULL, 438 0, 439 Name, 440 Size, 441 FALSE, 442 &Event, 443 &IoStatusBlock); 444 if (!Irp) 445 { 446 FreePool(Name); 447 ObDereferenceObject(DeviceObject); 448 ObDereferenceObject(FileObject); 449 return STATUS_INSUFFICIENT_RESOURCES; 450 } 451 452 Stack = IoGetNextIrpStackLocation(Irp); 453 Stack->FileObject = FileObject; 454 455 Status = IoCallDriver(DeviceObject, Irp); 456 if (Status == STATUS_PENDING) 457 { 458 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 459 Status = IoStatusBlock.Status; 460 } 461 } 462 463 if (NT_SUCCESS(Status)) 464 { 465 /* Copy back found name to the caller */ 466 DeviceName->Length = Name->NameLength; 467 DeviceName->MaximumLength = Name->NameLength + sizeof(WCHAR); 468 DeviceName->Buffer = AllocatePool(DeviceName->MaximumLength); 469 if (!DeviceName->Buffer) 470 { 471 Status = STATUS_INSUFFICIENT_RESOURCES; 472 } 473 else 474 { 475 RtlCopyMemory(DeviceName->Buffer, Name->Name, Name->NameLength); 476 DeviceName->Buffer[Name->NameLength / sizeof(WCHAR)] = UNICODE_NULL; 477 } 478 } 479 480 FreePool(Name); 481 } 482 483 if (!NT_SUCCESS(Status)) 484 { 485 ObDereferenceObject(DeviceObject); 486 ObDereferenceObject(FileObject); 487 return Status; 488 } 489 490 /* If caller wants device unique ID */ 491 if (UniqueId) 492 { 493 /* Prepare buffer to probe length */ 494 Id = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID)); 495 if (!Id) 496 { 497 ObDereferenceObject(DeviceObject); 498 ObDereferenceObject(FileObject); 499 return STATUS_INSUFFICIENT_RESOURCES; 500 } 501 502 /* Query unique ID length */ 503 KeInitializeEvent(&Event, NotificationEvent, FALSE); 504 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID, 505 DeviceObject, 506 NULL, 507 0, 508 Id, 509 sizeof(MOUNTDEV_UNIQUE_ID), 510 FALSE, 511 &Event, 512 &IoStatusBlock); 513 if (!Irp) 514 { 515 FreePool(Id); 516 ObDereferenceObject(DeviceObject); 517 ObDereferenceObject(FileObject); 518 return STATUS_INSUFFICIENT_RESOURCES; 519 } 520 521 Stack = IoGetNextIrpStackLocation(Irp); 522 Stack->FileObject = FileObject; 523 524 Status = IoCallDriver(DeviceObject, Irp); 525 if (Status == STATUS_PENDING) 526 { 527 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 528 Status = IoStatusBlock.Status; 529 } 530 531 /* Retry with appropriate length */ 532 if (Status == STATUS_BUFFER_OVERFLOW) 533 { 534 Size = Id->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID); 535 536 FreePool(Id); 537 538 /* Allocate the correct buffer */ 539 Id = AllocatePool(Size); 540 if (!Id) 541 { 542 ObDereferenceObject(DeviceObject); 543 ObDereferenceObject(FileObject); 544 return STATUS_INSUFFICIENT_RESOURCES; 545 } 546 547 /* Query unique ID */ 548 KeInitializeEvent(&Event, NotificationEvent, FALSE); 549 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID, 550 DeviceObject, 551 NULL, 552 0, 553 Id, 554 Size, 555 FALSE, 556 &Event, 557 &IoStatusBlock); 558 if (!Irp) 559 { 560 FreePool(Id); 561 ObDereferenceObject(DeviceObject); 562 ObDereferenceObject(FileObject); 563 return STATUS_INSUFFICIENT_RESOURCES; 564 } 565 566 Stack = IoGetNextIrpStackLocation(Irp); 567 Stack->FileObject = FileObject; 568 569 Status = IoCallDriver(DeviceObject, Irp); 570 if (Status == STATUS_PENDING) 571 { 572 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 573 Status = IoStatusBlock.Status; 574 } 575 } 576 577 /* Hands back unique ID */ 578 if (NT_SUCCESS(Status)) 579 { 580 *UniqueId = Id; 581 } 582 else 583 { 584 /* In case of failure, also free the rest */ 585 FreePool(Id); 586 if (DeviceName->Length) 587 { 588 FreePool(DeviceName->Buffer); 589 } 590 591 ObDereferenceObject(DeviceObject); 592 ObDereferenceObject(FileObject); 593 594 return Status; 595 } 596 } 597 598 /* If user wants to know about GUID */ 599 if (HasGuid) 600 { 601 /* Query device stable GUID */ 602 KeInitializeEvent(&Event, NotificationEvent, FALSE); 603 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID, 604 DeviceObject, 605 NULL, 606 0, 607 StableGuid, 608 sizeof(GUID), 609 FALSE, 610 &Event, 611 &IoStatusBlock); 612 if (!Irp) 613 { 614 ObDereferenceObject(DeviceObject); 615 ObDereferenceObject(FileObject); 616 return STATUS_INSUFFICIENT_RESOURCES; 617 } 618 619 Stack = IoGetNextIrpStackLocation(Irp); 620 Stack->FileObject = FileObject; 621 622 IntStatus = IoCallDriver(DeviceObject, Irp); 623 if (IntStatus == STATUS_PENDING) 624 { 625 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 626 IntStatus = IoStatusBlock.Status; 627 } 628 629 *HasGuid = NT_SUCCESS(IntStatus); 630 } 631 632 ObDereferenceObject(DeviceObject); 633 ObDereferenceObject(FileObject); 634 return Status; 635 } 636 637 /* 638 * @implemented 639 */ 640 NTSTATUS 641 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension, 642 IN PUNICODE_STRING SymbolicName, 643 IN BOOLEAN DeviceNameGiven, 644 OUT PDEVICE_INFORMATION * DeviceInformation) 645 { 646 NTSTATUS Status; 647 PLIST_ENTRY NextEntry; 648 UNICODE_STRING DeviceName; 649 PDEVICE_INFORMATION DeviceInfo = NULL; 650 651 /* If a device name was given, use it */ 652 if (DeviceNameGiven) 653 { 654 DeviceName.Length = SymbolicName->Length; 655 DeviceName.Buffer = SymbolicName->Buffer; 656 } 657 else 658 { 659 /* Otherwise, query it */ 660 Status = QueryDeviceInformation(SymbolicName, 661 &DeviceName, 662 NULL, NULL, 663 NULL, NULL, 664 NULL, NULL); 665 if (!NT_SUCCESS(Status)) 666 { 667 return Status; 668 } 669 } 670 671 /* Look for device information matching devive */ 672 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 673 NextEntry != &(DeviceExtension->DeviceListHead); 674 NextEntry = NextEntry->Flink) 675 { 676 DeviceInfo = CONTAINING_RECORD(NextEntry, 677 DEVICE_INFORMATION, 678 DeviceListEntry); 679 680 if (RtlEqualUnicodeString(&DeviceName, &(DeviceInfo->DeviceName), TRUE)) 681 { 682 break; 683 } 684 } 685 686 /* Release our buffer if required */ 687 if (!DeviceNameGiven) 688 { 689 FreePool(DeviceName.Buffer); 690 } 691 692 /* Return found information */ 693 if (NextEntry == &(DeviceExtension->DeviceListHead)) 694 { 695 return STATUS_OBJECT_NAME_NOT_FOUND; 696 } 697 698 *DeviceInformation = DeviceInfo; 699 return STATUS_SUCCESS; 700 } 701 702 /* 703 * @implemented 704 */ 705 VOID 706 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation) 707 { 708 FreePool(DeviceInformation->SymbolicName.Buffer); 709 FreePool(DeviceInformation); 710 } 711 712 /* 713 * @implemented 714 */ 715 VOID 716 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation) 717 { 718 PLIST_ENTRY NextEntry; 719 PSYMLINK_INFORMATION SymLink; 720 PUNIQUE_ID_REPLICATE UniqueId; 721 PASSOCIATED_DEVICE_ENTRY AssociatedDevice; 722 723 /* Purge symbolic links list */ 724 while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead))) 725 { 726 NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead)); 727 SymLink = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 728 729 GlobalDeleteSymbolicLink(&(SymLink->Name)); 730 FreePool(SymLink->Name.Buffer); 731 } 732 733 /* Purge replicated unique IDs list */ 734 while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead))) 735 { 736 NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead)); 737 UniqueId = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry); 738 739 FreePool(UniqueId->UniqueId); 740 FreePool(UniqueId); 741 } 742 743 while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead))) 744 { 745 NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead)); 746 AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 747 748 FreePool(AssociatedDevice->String.Buffer); 749 FreePool(AssociatedDevice); 750 } 751 752 /* Free the rest of the buffers */ 753 FreePool(DeviceInformation->SymbolicName.Buffer); 754 if (DeviceInformation->KeepLinks) 755 { 756 FreePool(DeviceInformation->UniqueId); 757 } 758 FreePool(DeviceInformation->DeviceName.Buffer); 759 760 /* Finally, stop waiting for notifications for this device */ 761 if (DeviceInformation->TargetDeviceNotificationEntry) 762 { 763 IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry); 764 } 765 } 766 767 /* 768 * @implemented 769 */ 770 VOID 771 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation) 772 { 773 PLIST_ENTRY NextEntry; 774 PSYMLINK_INFORMATION SymlinkInformation; 775 776 /* For all the saved links */ 777 while (!IsListEmpty(&(SavedLinkInformation->SymbolicLinksListHead))) 778 { 779 NextEntry = RemoveHeadList(&(SavedLinkInformation->SymbolicLinksListHead)); 780 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 781 782 /* Remove from system & free */ 783 GlobalDeleteSymbolicLink(&(SymlinkInformation->Name)); 784 FreePool(SymlinkInformation->Name.Buffer); 785 FreePool(SymlinkInformation); 786 } 787 788 /* And free unique ID & entry */ 789 FreePool(SavedLinkInformation->UniqueId); 790 FreePool(SavedLinkInformation); 791 } 792 793 794 /* 795 * @implemented 796 */ 797 VOID 798 NTAPI 799 MountMgrUnload(IN struct _DRIVER_OBJECT *DriverObject) 800 { 801 PLIST_ENTRY NextEntry; 802 PUNIQUE_ID_WORK_ITEM WorkItem; 803 PDEVICE_EXTENSION DeviceExtension; 804 PDEVICE_INFORMATION DeviceInformation; 805 PSAVED_LINK_INFORMATION SavedLinkInformation; 806 807 UNREFERENCED_PARAMETER(DriverObject); 808 809 /* Don't get notification any longer */ 810 IoUnregisterShutdownNotification(gdeviceObject); 811 812 /* Free registry buffer */ 813 DeviceExtension = gdeviceObject->DeviceExtension; 814 if (DeviceExtension->RegistryPath.Buffer) 815 { 816 FreePool(DeviceExtension->RegistryPath.Buffer); 817 DeviceExtension->RegistryPath.Buffer = NULL; 818 } 819 820 InterlockedExchange(&Unloading, TRUE); 821 822 KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE); 823 824 /* Wait for workers to finish */ 825 if (InterlockedIncrement(&DeviceExtension->WorkerReferences) > 0) 826 { 827 KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore), 828 IO_NO_INCREMENT, 1, FALSE); 829 830 KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL); 831 } 832 else 833 { 834 InterlockedDecrement(&(DeviceExtension->WorkerReferences)); 835 } 836 837 /* Don't get any notification any longer² */ 838 IoUnregisterPlugPlayNotification(DeviceExtension->NotificationEntry); 839 840 /* Acquire the driver exclusively */ 841 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, 842 FALSE, NULL); 843 844 /* Clear offline devices list */ 845 while (!IsListEmpty(&(DeviceExtension->OfflineDeviceListHead))) 846 { 847 NextEntry = RemoveHeadList(&(DeviceExtension->OfflineDeviceListHead)); 848 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 849 MountMgrFreeDeadDeviceInfo(DeviceInformation); 850 } 851 852 /* Clear saved links list */ 853 while (!IsListEmpty(&(DeviceExtension->SavedLinksListHead))) 854 { 855 NextEntry = RemoveHeadList(&(DeviceExtension->SavedLinksListHead)); 856 SavedLinkInformation = CONTAINING_RECORD(NextEntry, SAVED_LINK_INFORMATION, SavedLinksListEntry); 857 MountMgrFreeSavedLink(SavedLinkInformation); 858 } 859 860 /* Clear workers list */ 861 while (!IsListEmpty(&(DeviceExtension->UniqueIdWorkerItemListHead))) 862 { 863 NextEntry = RemoveHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead)); 864 WorkItem = CONTAINING_RECORD(NextEntry, UNIQUE_ID_WORK_ITEM, UniqueIdWorkerItemListEntry); 865 866 KeClearEvent(&UnloadEvent); 867 WorkItem->Event = &UnloadEvent; 868 869 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 870 1, FALSE); 871 872 IoCancelIrp(WorkItem->Irp); 873 KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL); 874 875 IoFreeIrp(WorkItem->Irp); 876 FreePool(WorkItem->DeviceName.Buffer); 877 FreePool(WorkItem->IrpBuffer); 878 FreePool(WorkItem); 879 880 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, 881 FALSE, NULL); 882 } 883 884 /* If we have drive letter data, release */ 885 if (DeviceExtension->DriveLetterData) 886 { 887 FreePool(DeviceExtension->DriveLetterData); 888 DeviceExtension->DriveLetterData = NULL; 889 } 890 891 /* Release driver & quit */ 892 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 893 894 GlobalDeleteSymbolicLink(&DosDevicesMount); 895 IoDeleteDevice(gdeviceObject); 896 } 897 898 /* 899 * @implemented 900 */ 901 CODE_SEG("INIT") 902 BOOLEAN 903 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath) 904 { 905 NTSTATUS Status; 906 ULONG Result, Default = 0; 907 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 908 909 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 910 911 /* Simply read data from register */ 912 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 913 QueryTable[0].Name = L"NoAutoMount"; 914 QueryTable[0].EntryContext = &Result; 915 QueryTable[0].DefaultType = REG_NONE; 916 QueryTable[0].DefaultData = &Default; 917 QueryTable[0].DefaultLength = sizeof(ULONG); 918 919 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 920 RegistryPath->Buffer, 921 QueryTable, 922 NULL, 923 NULL); 924 if (!NT_SUCCESS(Status)) 925 { 926 return (Default != 0); 927 } 928 929 return (Result != 0); 930 } 931 932 /* 933 * @implemented 934 */ 935 NTSTATUS 936 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension, 937 IN PUNICODE_STRING SymbolicName, 938 IN BOOLEAN ManuallyRegistered) 939 { 940 WCHAR Letter; 941 GUID StableGuid; 942 HANDLE LinkHandle; 943 ULONG SymLinkCount, i; 944 PLIST_ENTRY NextEntry; 945 PUNICODE_STRING SymLinks; 946 NTSTATUS Status, IntStatus; 947 OBJECT_ATTRIBUTES ObjectAttributes; 948 PSYMLINK_INFORMATION SymlinkInformation; 949 PMOUNTDEV_UNIQUE_ID UniqueId, NewUniqueId; 950 PSAVED_LINK_INFORMATION SavedLinkInformation; 951 PDEVICE_INFORMATION DeviceInformation, CurrentDevice; 952 WCHAR CSymLinkBuffer[RTL_NUMBER_OF(Cunc)], LinkTargetBuffer[MAX_PATH]; 953 UNICODE_STRING TargetDeviceName, SuggestedLinkName, DeviceName, VolumeName, DriveLetter, LinkTarget, CSymLink; 954 BOOLEAN HasGuid, HasGptDriveLetter, Valid, UseOnlyIfThereAreNoOtherLinks, IsDrvLetter, IsOff, IsVolumeName, LinkError; 955 956 /* New device = new structure to represent it */ 957 DeviceInformation = AllocatePool(sizeof(DEVICE_INFORMATION)); 958 if (!DeviceInformation) 959 { 960 return STATUS_INSUFFICIENT_RESOURCES; 961 } 962 963 /* Initialise device structure */ 964 RtlZeroMemory(DeviceInformation, sizeof(DEVICE_INFORMATION)); 965 InitializeListHead(&(DeviceInformation->SymbolicLinksListHead)); 966 InitializeListHead(&(DeviceInformation->ReplicatedUniqueIdsListHead)); 967 InitializeListHead(&(DeviceInformation->AssociatedDevicesHead)); 968 DeviceInformation->SymbolicName.Length = SymbolicName->Length; 969 DeviceInformation->SymbolicName.MaximumLength = SymbolicName->Length + sizeof(UNICODE_NULL); 970 DeviceInformation->SymbolicName.Buffer = AllocatePool(DeviceInformation->SymbolicName.MaximumLength); 971 if (!DeviceInformation->SymbolicName.Buffer) 972 { 973 FreePool(DeviceInformation); 974 return STATUS_INSUFFICIENT_RESOURCES; 975 } 976 977 /* Copy symbolic name */ 978 RtlCopyMemory(DeviceInformation->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length); 979 DeviceInformation->SymbolicName.Buffer[DeviceInformation->SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; 980 DeviceInformation->ManuallyRegistered = ManuallyRegistered; 981 DeviceInformation->DeviceExtension = DeviceExtension; 982 983 /* Query as much data as possible about device */ 984 Status = QueryDeviceInformation(SymbolicName, 985 &TargetDeviceName, 986 &UniqueId, 987 &(DeviceInformation->Removable), 988 &HasGptDriveLetter, 989 &HasGuid, 990 &StableGuid, 991 &Valid); 992 if (!NT_SUCCESS(Status)) 993 { 994 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 995 996 for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink; 997 NextEntry != &(DeviceExtension->OfflineDeviceListHead); 998 NextEntry = NextEntry->Flink) 999 { 1000 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 1001 1002 if (RtlEqualUnicodeString(&(DeviceInformation->SymbolicName), &(CurrentDevice->SymbolicName), TRUE)) 1003 { 1004 break; 1005 } 1006 } 1007 1008 if (NextEntry != &(DeviceExtension->OfflineDeviceListHead)) 1009 { 1010 MountMgrFreeDeadDeviceInfo(DeviceInformation); 1011 } 1012 else 1013 { 1014 InsertTailList(&(DeviceExtension->OfflineDeviceListHead), &(DeviceInformation->DeviceListEntry)); 1015 } 1016 1017 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 1018 1019 return Status; 1020 } 1021 1022 /* Save gathered data */ 1023 DeviceInformation->UniqueId = UniqueId; 1024 DeviceInformation->DeviceName = TargetDeviceName; 1025 DeviceInformation->KeepLinks = FALSE; 1026 1027 /* If we found system partition, mark it */ 1028 if (DeviceExtension->DriveLetterData && UniqueId->UniqueIdLength == DeviceExtension->DriveLetterData->UniqueIdLength) 1029 { 1030 if (RtlCompareMemory(UniqueId->UniqueId, DeviceExtension->DriveLetterData->UniqueId, UniqueId->UniqueIdLength) 1031 == UniqueId->UniqueIdLength) 1032 { 1033 IoSetSystemPartition(&TargetDeviceName); 1034 } 1035 } 1036 1037 /* Check suggested link name */ 1038 Status = QuerySuggestedLinkName(&(DeviceInformation->SymbolicName), 1039 &SuggestedLinkName, 1040 &UseOnlyIfThereAreNoOtherLinks); 1041 if (!NT_SUCCESS(Status)) 1042 { 1043 SuggestedLinkName.Buffer = NULL; 1044 } 1045 1046 /* If it's OK, set it and save its letter (if any) */ 1047 if (SuggestedLinkName.Buffer && IsDriveLetter(&SuggestedLinkName)) 1048 { 1049 DeviceInformation->SuggestedDriveLetter = (UCHAR)SuggestedLinkName.Buffer[LETTER_POSITION]; 1050 } 1051 1052 /* Acquire driver exclusively */ 1053 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 1054 1055 /* Check if we already have device in to prevent double registration */ 1056 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 1057 NextEntry != &(DeviceExtension->DeviceListHead); 1058 NextEntry = NextEntry->Flink) 1059 { 1060 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 1061 1062 if (RtlEqualUnicodeString(&(CurrentDevice->DeviceName), &TargetDeviceName, TRUE)) 1063 { 1064 break; 1065 } 1066 } 1067 1068 /* If we found it, clear ours, and return success, all correct */ 1069 if (NextEntry != &(DeviceExtension->DeviceListHead)) 1070 { 1071 if (SuggestedLinkName.Buffer) 1072 { 1073 FreePool(SuggestedLinkName.Buffer); 1074 } 1075 1076 FreePool(UniqueId); 1077 FreePool(TargetDeviceName.Buffer); 1078 FreePool(DeviceInformation->DeviceName.Buffer); 1079 FreePool(DeviceInformation); 1080 1081 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 1082 1083 return STATUS_SUCCESS; 1084 } 1085 1086 /* Check if there are symlinks associated with our device in registry */ 1087 Status = QuerySymbolicLinkNamesFromStorage(DeviceExtension, 1088 DeviceInformation, 1089 (SuggestedLinkName.Buffer) ? &SuggestedLinkName : NULL, 1090 UseOnlyIfThereAreNoOtherLinks, 1091 &SymLinks, 1092 &SymLinkCount, 1093 HasGuid, 1094 &StableGuid); 1095 1096 /* If our device is a CD-ROM */ 1097 if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE)) 1098 { 1099 LinkTarget.Length = 0; 1100 LinkTarget.MaximumLength = sizeof(LinkTargetBuffer); 1101 LinkTarget.Buffer = LinkTargetBuffer; 1102 1103 RtlCopyMemory(CSymLinkBuffer, Cunc, sizeof(Cunc)); 1104 RtlInitUnicodeString(&CSymLink, CSymLinkBuffer); 1105 1106 /* Start checking all letters that could have been associated */ 1107 for (Letter = L'D'; Letter <= L'Z'; Letter++) 1108 { 1109 CSymLink.Buffer[Cunc_LETTER_POSITION] = Letter; 1110 1111 InitializeObjectAttributes(&ObjectAttributes, 1112 &CSymLink, 1113 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 1114 NULL, 1115 NULL); 1116 1117 /* Try to open the associated symlink */ 1118 Status = ZwOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes); 1119 if (!NT_SUCCESS(Status)) 1120 { 1121 continue; 1122 } 1123 1124 /* And query its target */ 1125 Status = ZwQuerySymbolicLinkObject(LinkHandle, &LinkTarget, NULL); 1126 ZwClose(LinkHandle); 1127 1128 if (!NT_SUCCESS(Status)) 1129 { 1130 continue; 1131 } 1132 1133 IntStatus = STATUS_UNSUCCESSFUL; 1134 if (!RtlEqualUnicodeString(&LinkTarget, &DeviceInformation->DeviceName, FALSE)) 1135 { 1136 continue; 1137 } 1138 1139 /* This link is matching our device, whereas it's not supposed to have any 1140 * symlink associated. 1141 * Delete it 1142 */ 1143 if (!SymLinkCount) 1144 { 1145 IoDeleteSymbolicLink(&CSymLink); 1146 continue; 1147 } 1148 1149 /* Now, for all the symlinks, check for ours */ 1150 for (i = 0; i < SymLinkCount; i++) 1151 { 1152 if (IsDriveLetter(&(SymLinks[i]))) 1153 { 1154 /* If it exists, that's correct */ 1155 if (SymLinks[i].Buffer[LETTER_POSITION] == Letter) 1156 { 1157 IntStatus = STATUS_SUCCESS; 1158 } 1159 } 1160 } 1161 1162 /* Useless link, delete it */ 1163 if (IntStatus == STATUS_UNSUCCESSFUL) 1164 { 1165 IoDeleteSymbolicLink(&CSymLink); 1166 } 1167 } 1168 } 1169 1170 /* Suggested name is no longer required */ 1171 if (SuggestedLinkName.Buffer) 1172 { 1173 FreePool(SuggestedLinkName.Buffer); 1174 } 1175 1176 /* If if failed, ensure we don't take symlinks into account */ 1177 if (!NT_SUCCESS(Status)) 1178 { 1179 SymLinks = NULL; 1180 SymLinkCount = 0; 1181 } 1182 1183 /* Now we queried them, remove the symlinks */ 1184 SavedLinkInformation = RemoveSavedLinks(DeviceExtension, UniqueId); 1185 1186 IsDrvLetter = FALSE; 1187 IsOff = FALSE; 1188 IsVolumeName = FALSE; 1189 /* For all the symlinks */ 1190 for (i = 0; i < SymLinkCount; i++) 1191 { 1192 /* Check if our device is a volume */ 1193 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks[i]))) 1194 { 1195 IsVolumeName = TRUE; 1196 } 1197 /* If it has a drive letter */ 1198 else if (IsDriveLetter(&(SymLinks[i]))) 1199 { 1200 if (IsDrvLetter) 1201 { 1202 DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId); 1203 continue; 1204 } 1205 else 1206 { 1207 IsDrvLetter = TRUE; 1208 } 1209 } 1210 1211 /* And recreate the symlink to our device */ 1212 Status = GlobalCreateSymbolicLink(&(SymLinks[i]), &TargetDeviceName); 1213 if (!NT_SUCCESS(Status)) 1214 { 1215 LinkError = TRUE; 1216 1217 if ((SavedLinkInformation && !RedirectSavedLink(SavedLinkInformation, &(SymLinks[i]), &TargetDeviceName)) || 1218 !SavedLinkInformation) 1219 { 1220 Status = QueryDeviceInformation(&(SymLinks[i]), &DeviceName, NULL, NULL, NULL, NULL, NULL, NULL); 1221 if (NT_SUCCESS(Status)) 1222 { 1223 LinkError = RtlEqualUnicodeString(&TargetDeviceName, &DeviceName, TRUE); 1224 FreePool(DeviceName.Buffer); 1225 } 1226 1227 if (!LinkError) 1228 { 1229 if (IsDriveLetter(&(SymLinks[i]))) 1230 { 1231 IsDrvLetter = FALSE; 1232 DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId); 1233 } 1234 1235 FreePool(SymLinks[i].Buffer); 1236 continue; 1237 } 1238 } 1239 } 1240 1241 /* Check if was offline */ 1242 if (IsOffline(&(SymLinks[i]))) 1243 { 1244 IsOff = TRUE; 1245 } 1246 1247 /* Finally, associate this symlink with the device */ 1248 SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION)); 1249 if (!SymlinkInformation) 1250 { 1251 GlobalDeleteSymbolicLink(&(SymLinks[i])); 1252 FreePool(SymLinks[i].Buffer); 1253 continue; 1254 } 1255 1256 SymlinkInformation->Name = SymLinks[i]; 1257 SymlinkInformation->Online = TRUE; 1258 1259 InsertTailList(&(DeviceInformation->SymbolicLinksListHead), 1260 &(SymlinkInformation->SymbolicLinksListEntry)); 1261 } 1262 1263 /* Now, for all the recreated symlinks, notify their recreation */ 1264 for (NextEntry = DeviceInformation->SymbolicLinksListHead.Flink; 1265 NextEntry != &(DeviceInformation->SymbolicLinksListHead); 1266 NextEntry = NextEntry->Flink) 1267 { 1268 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 1269 1270 SendLinkCreated(&(SymlinkInformation->Name)); 1271 } 1272 1273 /* If we had saved links, it's time to free them */ 1274 if (SavedLinkInformation) 1275 { 1276 MountMgrFreeSavedLink(SavedLinkInformation); 1277 } 1278 1279 /* If our device doesn't have a volume name */ 1280 if (!IsVolumeName) 1281 { 1282 /* It's time to create one */ 1283 Status = CreateNewVolumeName(&VolumeName, NULL); 1284 if (NT_SUCCESS(Status)) 1285 { 1286 /* Write it to global database */ 1287 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, 1288 DatabasePath, 1289 VolumeName.Buffer, 1290 REG_BINARY, 1291 UniqueId->UniqueId, 1292 UniqueId->UniqueIdLength); 1293 1294 /* And create the symlink */ 1295 GlobalCreateSymbolicLink(&VolumeName, &TargetDeviceName); 1296 1297 SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION)); 1298 if (!SymlinkInformation) 1299 { 1300 FreePool(VolumeName.Buffer); 1301 } 1302 /* Finally, associate it with the device and notify creation */ 1303 else 1304 { 1305 SymlinkInformation->Name = VolumeName; 1306 SymlinkInformation->Online = TRUE; 1307 InsertTailList(&(DeviceInformation->SymbolicLinksListHead), 1308 &(SymlinkInformation->SymbolicLinksListEntry)); 1309 1310 SendLinkCreated(&VolumeName); 1311 } 1312 } 1313 } 1314 1315 /* If we found a drive letter, then, ignore the suggested one */ 1316 if (IsDrvLetter) 1317 { 1318 DeviceInformation->SuggestedDriveLetter = 0; 1319 } 1320 /* Else, it's time to set up one */ 1321 else if ((DeviceExtension->NoAutoMount || DeviceInformation->Removable) && 1322 DeviceExtension->AutomaticDriveLetter && 1323 (HasGptDriveLetter || DeviceInformation->SuggestedDriveLetter) && 1324 !HasNoDriveLetterEntry(UniqueId)) 1325 { 1326 /* Create a new drive letter */ 1327 Status = CreateNewDriveLetterName(&DriveLetter, &TargetDeviceName, 1328 DeviceInformation->SuggestedDriveLetter, 1329 NULL); 1330 if (!NT_SUCCESS(Status)) 1331 { 1332 CreateNoDriveLetterEntry(UniqueId); 1333 } 1334 else 1335 { 1336 /* Save it to global database */ 1337 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, 1338 DatabasePath, 1339 DriveLetter.Buffer, 1340 REG_BINARY, 1341 UniqueId->UniqueId, 1342 UniqueId->UniqueIdLength); 1343 1344 /* Associate it with the device and notify creation */ 1345 SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION)); 1346 if (!SymlinkInformation) 1347 { 1348 FreePool(DriveLetter.Buffer); 1349 } 1350 else 1351 { 1352 SymlinkInformation->Name = DriveLetter; 1353 SymlinkInformation->Online = TRUE; 1354 InsertTailList(&(DeviceInformation->SymbolicLinksListHead), 1355 &(SymlinkInformation->SymbolicLinksListEntry)); 1356 1357 SendLinkCreated(&DriveLetter); 1358 } 1359 } 1360 } 1361 1362 /* If that's a PnP device, register for notifications */ 1363 if (!ManuallyRegistered) 1364 { 1365 RegisterForTargetDeviceNotification(DeviceExtension, DeviceInformation); 1366 } 1367 1368 /* Finally, insert the device into our devices list */ 1369 InsertTailList(&(DeviceExtension->DeviceListHead), &(DeviceInformation->DeviceListEntry)); 1370 1371 /* Copy device unique ID */ 1372 NewUniqueId = AllocatePool(UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 1373 if (NewUniqueId) 1374 { 1375 NewUniqueId->UniqueIdLength = UniqueId->UniqueIdLength; 1376 RtlCopyMemory(NewUniqueId->UniqueId, UniqueId->UniqueId, UniqueId->UniqueIdLength); 1377 } 1378 1379 /* If device's offline or valid, skip its notifications */ 1380 if (IsOff || Valid) 1381 { 1382 DeviceInformation->SkipNotifications = TRUE; 1383 } 1384 1385 /* In case device is valid and is set to no automount, 1386 * set it offline. 1387 */ 1388 if (DeviceExtension->NoAutoMount || IsDrvLetter) 1389 { 1390 IsOff = !DeviceInformation->SkipNotifications; 1391 } 1392 else 1393 { 1394 IsOff = FALSE; 1395 } 1396 1397 /* Finally, release the exclusive lock */ 1398 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 1399 1400 /* If device is not offline, notify its arrival */ 1401 if (!IsOff) 1402 { 1403 SendOnlineNotification(SymbolicName); 1404 } 1405 1406 /* If we had symlinks (from storage), free them */ 1407 if (SymLinks) 1408 { 1409 FreePool(SymLinks); 1410 } 1411 1412 /* Notify about unique id change */ 1413 if (NewUniqueId) 1414 { 1415 IssueUniqueIdChangeNotify(DeviceExtension, SymbolicName, NewUniqueId); 1416 FreePool(NewUniqueId); 1417 } 1418 1419 /* If this drive was set to have a drive letter automatically 1420 * Now it's back, local databases sync will be required 1421 */ 1422 if (DeviceExtension->AutomaticDriveLetter) 1423 { 1424 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 1425 1426 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation); 1427 1428 NextEntry = DeviceExtension->DeviceListHead.Flink; 1429 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 1430 while (CurrentDevice != DeviceInformation) 1431 { 1432 if (!CurrentDevice->NoDatabase) 1433 { 1434 ReconcileThisDatabaseWithMaster(DeviceExtension, CurrentDevice); 1435 } 1436 1437 NextEntry = NextEntry->Flink; 1438 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 1439 } 1440 1441 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 1442 } 1443 1444 return STATUS_SUCCESS; 1445 } 1446 1447 /* 1448 * @implemented 1449 */ 1450 VOID 1451 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension, 1452 IN PUNICODE_STRING DeviceName) 1453 { 1454 PLIST_ENTRY NextEntry, DeviceEntry; 1455 PUNIQUE_ID_REPLICATE UniqueIdReplicate; 1456 PSYMLINK_INFORMATION SymlinkInformation; 1457 PASSOCIATED_DEVICE_ENTRY AssociatedDevice; 1458 PSAVED_LINK_INFORMATION SavedLinkInformation = NULL; 1459 PDEVICE_INFORMATION DeviceInformation, CurrentDevice; 1460 1461 /* Acquire device exclusively */ 1462 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 1463 1464 /* Look for the leaving device */ 1465 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 1466 NextEntry != &(DeviceExtension->DeviceListHead); 1467 NextEntry = NextEntry->Flink) 1468 { 1469 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 1470 1471 if (!RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE)) 1472 { 1473 break; 1474 } 1475 } 1476 1477 /* If we found it */ 1478 if (NextEntry != &(DeviceExtension->DeviceListHead)) 1479 { 1480 /* If it's asked to keep links, then, prepare to save them */ 1481 if (DeviceInformation->KeepLinks) 1482 { 1483 SavedLinkInformation = AllocatePool(sizeof(SAVED_LINK_INFORMATION)); 1484 if (!SavedLinkInformation) 1485 { 1486 DeviceInformation->KeepLinks = FALSE; 1487 } 1488 } 1489 1490 /* If it's possible (and asked), start to save them */ 1491 if (DeviceInformation->KeepLinks) 1492 { 1493 InsertTailList(&(DeviceExtension->SavedLinksListHead), &(SavedLinkInformation->SavedLinksListEntry)); 1494 InitializeListHead(&(SavedLinkInformation->SymbolicLinksListHead)); 1495 SavedLinkInformation->UniqueId = DeviceInformation->UniqueId; 1496 } 1497 1498 /* For all the symlinks */ 1499 while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead))) 1500 { 1501 NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead)); 1502 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 1503 1504 /* If we have to, save the link */ 1505 if (DeviceInformation->KeepLinks) 1506 { 1507 InsertTailList(&(SavedLinkInformation->SymbolicLinksListHead), &(SymlinkInformation->SymbolicLinksListEntry)); 1508 } 1509 /* Otherwise, just release it */ 1510 else 1511 { 1512 GlobalDeleteSymbolicLink(&(SymlinkInformation->Name)); 1513 FreePool(SymlinkInformation->Name.Buffer); 1514 FreePool(SymlinkInformation); 1515 } 1516 } 1517 1518 /* Free all the replicated unique IDs */ 1519 while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead))) 1520 { 1521 NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead)); 1522 UniqueIdReplicate = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry); 1523 1524 1525 FreePool(UniqueIdReplicate->UniqueId); 1526 FreePool(UniqueIdReplicate); 1527 } 1528 1529 while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead))) 1530 { 1531 NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead)); 1532 AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 1533 1534 DeviceInformation->NoDatabase = TRUE; 1535 FreePool(AssociatedDevice->String.Buffer); 1536 FreePool(AssociatedDevice); 1537 } 1538 1539 /* Remove device from the device list */ 1540 RemoveEntryList(&(DeviceInformation->DeviceListEntry)); 1541 1542 /* If there are still devices, check if some were associated with ours */ 1543 if (!IsListEmpty(&(DeviceInformation->DeviceListEntry))) 1544 { 1545 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 1546 NextEntry != &(DeviceExtension->DeviceListHead); 1547 NextEntry = NextEntry->Flink) 1548 { 1549 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 1550 1551 /* And then, remove them */ 1552 DeviceEntry = CurrentDevice->AssociatedDevicesHead.Flink; 1553 while (DeviceEntry != &(CurrentDevice->AssociatedDevicesHead)) 1554 { 1555 AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 1556 DeviceEntry = DeviceEntry->Flink; 1557 1558 if (AssociatedDevice->DeviceInformation != DeviceInformation) 1559 { 1560 continue; 1561 } 1562 1563 RemoveEntryList(&(AssociatedDevice->AssociatedDevicesEntry)); 1564 FreePool(AssociatedDevice->String.Buffer); 1565 FreePool(AssociatedDevice); 1566 } 1567 } 1568 } 1569 1570 /* Finally, clean up device name, symbolic name */ 1571 FreePool(DeviceInformation->SymbolicName.Buffer); 1572 if (!DeviceInformation->KeepLinks) 1573 { 1574 FreePool(DeviceInformation->UniqueId); 1575 } 1576 FreePool(DeviceInformation->DeviceName.Buffer); 1577 1578 /* Unregister notifications */ 1579 if (DeviceInformation->TargetDeviceNotificationEntry) 1580 { 1581 IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry); 1582 } 1583 1584 /* And leave */ 1585 FreePool(DeviceInformation); 1586 } 1587 else 1588 { 1589 /* We didn't find device, perhaps because it was offline */ 1590 for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink; 1591 NextEntry != &(DeviceExtension->OfflineDeviceListHead); 1592 NextEntry = NextEntry->Flink) 1593 { 1594 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 1595 1596 /* It was, remove it */ 1597 if (RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE) == 0) 1598 { 1599 RemoveEntryList(&(DeviceInformation->DeviceListEntry)); 1600 MountMgrFreeDeadDeviceInfo(DeviceInformation); 1601 break; 1602 } 1603 } 1604 } 1605 1606 /* Release driver */ 1607 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 1608 } 1609 1610 /* 1611 * @implemented 1612 */ 1613 NTSTATUS 1614 NTAPI 1615 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure, 1616 IN PVOID Context) 1617 { 1618 BOOLEAN OldState; 1619 PDEVICE_EXTENSION DeviceExtension; 1620 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification; 1621 1622 /* Notification for a device arrived */ 1623 /* Disable hard errors */ 1624 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread()); 1625 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE); 1626 1627 DeviceExtension = Context; 1628 Notification = NotificationStructure; 1629 1630 /* Dispatch according to the event */ 1631 if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_ARRIVAL)) 1632 { 1633 MountMgrMountedDeviceArrival(DeviceExtension, Notification->SymbolicLinkName, FALSE); 1634 } 1635 else if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_REMOVAL)) 1636 { 1637 MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName); 1638 } 1639 1640 /* Reset hard errors */ 1641 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState); 1642 1643 return STATUS_SUCCESS; 1644 } 1645 1646 /* 1647 * @implemented 1648 */ 1649 NTSTATUS 1650 NTAPI 1651 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject, 1652 IN PIRP Irp) 1653 { 1654 PIO_STACK_LOCATION Stack; 1655 NTSTATUS Status = STATUS_SUCCESS; 1656 1657 UNREFERENCED_PARAMETER(DeviceObject); 1658 1659 Stack = IoGetCurrentIrpStackLocation(Irp); 1660 1661 /* Allow driver opening for communication 1662 * as long as it's not taken for a directory 1663 */ 1664 if (Stack->MajorFunction == IRP_MJ_CREATE && 1665 Stack->Parameters.Create.Options & FILE_DIRECTORY_FILE) 1666 { 1667 Status = STATUS_NOT_A_DIRECTORY; 1668 } 1669 1670 Irp->IoStatus.Status = Status; 1671 Irp->IoStatus.Information = 0; 1672 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1673 return Status; 1674 } 1675 1676 /* 1677 * @implemented 1678 */ 1679 VOID 1680 NTAPI 1681 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject, 1682 IN PIRP Irp) 1683 { 1684 UNREFERENCED_PARAMETER(DeviceObject); 1685 1686 RemoveEntryList(&(Irp->Tail.Overlay.ListEntry)); 1687 1688 IoReleaseCancelSpinLock(Irp->CancelIrql); 1689 1690 Irp->IoStatus.Information = 0; 1691 Irp->IoStatus.Status = STATUS_CANCELLED; 1692 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1693 } 1694 1695 /* 1696 * @implemented 1697 */ 1698 NTSTATUS 1699 NTAPI 1700 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject, 1701 IN PIRP Irp) 1702 { 1703 PIRP ListIrp; 1704 KIRQL OldIrql; 1705 PLIST_ENTRY NextEntry; 1706 PFILE_OBJECT FileObject; 1707 PIO_STACK_LOCATION Stack; 1708 PDEVICE_EXTENSION DeviceExtension; 1709 1710 DeviceExtension = DeviceObject->DeviceExtension; 1711 Stack = IoGetCurrentIrpStackLocation(Irp); 1712 FileObject = Stack->FileObject; 1713 1714 IoAcquireCancelSpinLock(&OldIrql); 1715 1716 /* If IRP list if empty, it's OK */ 1717 if (IsListEmpty(&(DeviceExtension->IrpListHead))) 1718 { 1719 IoReleaseCancelSpinLock(OldIrql); 1720 1721 Irp->IoStatus.Status = STATUS_SUCCESS; 1722 Irp->IoStatus.Information = 0; 1723 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1724 1725 return STATUS_SUCCESS; 1726 } 1727 1728 /* Otherwise, cancel all the IRPs */ 1729 NextEntry = DeviceExtension->IrpListHead.Flink; 1730 do 1731 { 1732 ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); 1733 if (IoGetCurrentIrpStackLocation(ListIrp)->FileObject == FileObject) 1734 { 1735 ListIrp->Cancel = TRUE; 1736 ListIrp->CancelIrql = OldIrql; 1737 ListIrp->CancelRoutine = NULL; 1738 MountMgrCancel(DeviceObject, ListIrp); 1739 1740 IoAcquireCancelSpinLock(&OldIrql); 1741 } 1742 1743 NextEntry = NextEntry->Flink; 1744 } 1745 while (NextEntry != &(DeviceExtension->IrpListHead)); 1746 1747 IoReleaseCancelSpinLock(OldIrql); 1748 1749 Irp->IoStatus.Status = STATUS_SUCCESS; 1750 Irp->IoStatus.Information = 0; 1751 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1752 1753 return STATUS_SUCCESS; 1754 } 1755 1756 /* 1757 * @implemented 1758 */ 1759 NTSTATUS 1760 NTAPI 1761 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject, 1762 IN PIRP Irp) 1763 { 1764 PDEVICE_EXTENSION DeviceExtension; 1765 1766 DeviceExtension = DeviceObject->DeviceExtension; 1767 1768 InterlockedExchange(&Unloading, TRUE); 1769 1770 KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE); 1771 1772 /* Wait for workers */ 1773 if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)) > 0) 1774 { 1775 KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore), 1776 IO_NO_INCREMENT, 1777 1, 1778 FALSE); 1779 KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL); 1780 } 1781 else 1782 { 1783 InterlockedDecrement(&(DeviceExtension->WorkerReferences)); 1784 } 1785 1786 Irp->IoStatus.Status = STATUS_SUCCESS; 1787 Irp->IoStatus.Information = 0; 1788 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1789 1790 return STATUS_SUCCESS; 1791 } 1792 1793 /* FUNCTIONS ****************************************************************/ 1794 1795 CODE_SEG("INIT") 1796 NTSTATUS 1797 NTAPI 1798 DriverEntry(IN PDRIVER_OBJECT DriverObject, 1799 IN PUNICODE_STRING RegistryPath) 1800 { 1801 NTSTATUS Status; 1802 PDEVICE_OBJECT DeviceObject; 1803 PDEVICE_EXTENSION DeviceExtension; 1804 1805 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, DatabasePath); 1806 1807 Status = IoCreateDevice(DriverObject, 1808 sizeof(DEVICE_EXTENSION), 1809 &DeviceMount, 1810 FILE_DEVICE_NETWORK, 1811 FILE_DEVICE_SECURE_OPEN, 1812 FALSE, 1813 &DeviceObject); 1814 if (!NT_SUCCESS(Status)) 1815 { 1816 return Status; 1817 } 1818 1819 DriverObject->DriverUnload = MountMgrUnload; 1820 1821 DeviceExtension = DeviceObject->DeviceExtension; 1822 RtlZeroMemory(DeviceExtension, sizeof(DEVICE_EXTENSION)); 1823 DeviceExtension->DeviceObject = DeviceObject; 1824 DeviceExtension->DriverObject = DriverObject; 1825 1826 InitializeListHead(&(DeviceExtension->DeviceListHead)); 1827 InitializeListHead(&(DeviceExtension->OfflineDeviceListHead)); 1828 1829 KeInitializeSemaphore(&(DeviceExtension->DeviceLock), 1, 1); 1830 KeInitializeSemaphore(&(DeviceExtension->RemoteDatabaseLock), 1, 1); 1831 1832 InitializeListHead(&(DeviceExtension->IrpListHead)); 1833 DeviceExtension->EpicNumber = 1; 1834 1835 InitializeListHead(&(DeviceExtension->SavedLinksListHead)); 1836 1837 InitializeListHead(&(DeviceExtension->WorkerQueueListHead)); 1838 KeInitializeSemaphore(&(DeviceExtension->WorkerSemaphore), 0, MAXLONG); 1839 DeviceExtension->WorkerReferences = -1; 1840 KeInitializeSpinLock(&(DeviceExtension->WorkerLock)); 1841 1842 InitializeListHead(&(DeviceExtension->UniqueIdWorkerItemListHead)); 1843 InitializeListHead(&(DeviceExtension->OnlineNotificationListHead)); 1844 DeviceExtension->OnlineNotificationCount = 1; 1845 1846 DeviceExtension->RegistryPath.Length = RegistryPath->Length; 1847 DeviceExtension->RegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR); 1848 DeviceExtension->RegistryPath.Buffer = AllocatePool(DeviceExtension->RegistryPath.MaximumLength); 1849 if (!DeviceExtension->RegistryPath.Buffer) 1850 { 1851 IoDeleteDevice(DeviceObject); 1852 return STATUS_INSUFFICIENT_RESOURCES; 1853 } 1854 1855 RtlCopyUnicodeString(&(DeviceExtension->RegistryPath), RegistryPath); 1856 1857 DeviceExtension->NoAutoMount = MountmgrReadNoAutoMount(&(DeviceExtension->RegistryPath)); 1858 1859 GlobalCreateSymbolicLink(&DosDevicesMount, &DeviceMount); 1860 1861 /* Register for device arrival & removal. Ask to be notified for already 1862 * present devices 1863 */ 1864 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, 1865 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 1866 &MountedDevicesGuid, 1867 DriverObject, 1868 MountMgrMountedDeviceNotification, 1869 DeviceExtension, 1870 &(DeviceExtension->NotificationEntry)); 1871 1872 if (!NT_SUCCESS(Status)) 1873 { 1874 IoDeleteDevice(DeviceObject); 1875 return Status; 1876 } 1877 1878 DriverObject->MajorFunction[IRP_MJ_CREATE] = 1879 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MountMgrCreateClose; 1880 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MountMgrDeviceControl; 1881 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MountMgrCleanup; 1882 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = MountMgrShutdown; 1883 1884 gdeviceObject = DeviceObject; 1885 1886 Status = IoRegisterShutdownNotification(DeviceObject); 1887 if (!NT_SUCCESS(Status)) 1888 { 1889 IoDeleteDevice(DeviceObject); 1890 } 1891 1892 return Status; 1893 } 1894