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