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