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