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