1 /* 2 * ReactOS kernel 3 * Copyright (C) 2011-2012 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/device.c 22 * PURPOSE: Mount Manager - Device Control 23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org) 24 */ 25 26 #include "mntmgr.h" 27 28 #define MAX_DEVICES 0x3E8 /* Matches 1000 devices */ 29 30 #define NDEBUG 31 #include <debug.h> 32 33 /* 34 * @implemented 35 */ 36 NTSTATUS 37 MountMgrChangeNotify(IN PDEVICE_EXTENSION DeviceExtension, 38 IN PIRP Irp) 39 { 40 KIRQL OldIrql; 41 NTSTATUS Status; 42 PIO_STACK_LOCATION Stack; 43 PMOUNTMGR_CHANGE_NOTIFY_INFO ChangeNotify; 44 45 /* Get the I/O buffer */ 46 Stack = IoGetCurrentIrpStackLocation(Irp); 47 ChangeNotify = (PMOUNTMGR_CHANGE_NOTIFY_INFO)Irp->AssociatedIrp.SystemBuffer; 48 49 /* Validate it */ 50 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO) || 51 Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO)) 52 { 53 return STATUS_INVALID_PARAMETER; 54 } 55 56 /* If epic number doesn't match, just return now one */ 57 if (DeviceExtension->EpicNumber != ChangeNotify->EpicNumber) 58 { 59 ChangeNotify->EpicNumber = DeviceExtension->EpicNumber; 60 Irp->IoStatus.Information = sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO); 61 return STATUS_SUCCESS; 62 } 63 64 /* If IRP is to be canceled, forget about that */ 65 IoAcquireCancelSpinLock(&OldIrql); 66 if (Irp->Cancel) 67 { 68 Status = STATUS_CANCELLED; 69 } 70 /* Otherwise queue the IRP to be notified with the next epic number change */ 71 else 72 { 73 InsertTailList(&(DeviceExtension->IrpListHead), &(Irp->Tail.Overlay.ListEntry)); 74 IoMarkIrpPending(Irp); 75 IoSetCancelRoutine(Irp, MountMgrCancel); 76 Status = STATUS_PENDING; 77 } 78 IoReleaseCancelSpinLock(OldIrql); 79 80 return Status; 81 } 82 83 /* 84 * @implemented 85 */ 86 NTSTATUS 87 MountmgrWriteNoAutoMount(IN PDEVICE_EXTENSION DeviceExtension) 88 { 89 ULONG Value = DeviceExtension->NoAutoMount; 90 91 return RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, 92 DeviceExtension->RegistryPath.Buffer, 93 L"NoAutoMount", 94 REG_DWORD, 95 &Value, 96 sizeof(Value)); 97 } 98 99 /* 100 * @implemented 101 */ 102 NTSTATUS 103 MountMgrSetAutoMount(IN PDEVICE_EXTENSION DeviceExtension, 104 IN PIRP Irp) 105 { 106 PIO_STACK_LOCATION Stack; 107 PMOUNTMGR_SET_AUTO_MOUNT SetState; 108 109 Stack = IoGetCurrentIrpStackLocation(Irp); 110 111 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_SET_AUTO_MOUNT)) 112 { 113 Irp->IoStatus.Information = 0; 114 return STATUS_INVALID_PARAMETER; 115 } 116 117 /* Change the state only if there is a real difference 118 * with the user-provided NewState (normalized) */ 119 SetState = (PMOUNTMGR_SET_AUTO_MOUNT)Irp->AssociatedIrp.SystemBuffer; 120 if ((SetState->NewState != Enabled) == DeviceExtension->NoAutoMount) 121 { 122 Irp->IoStatus.Information = 0; 123 return STATUS_SUCCESS; 124 } 125 126 /* Set new state */ 127 DeviceExtension->NoAutoMount = (SetState->NewState != Enabled); 128 Irp->IoStatus.Information = 0; 129 return MountmgrWriteNoAutoMount(DeviceExtension); 130 } 131 132 /* 133 * @implemented 134 */ 135 NTSTATUS 136 MountMgrQueryAutoMount(IN PDEVICE_EXTENSION DeviceExtension, 137 IN PIRP Irp) 138 { 139 PIO_STACK_LOCATION Stack; 140 PMOUNTMGR_QUERY_AUTO_MOUNT QueryState; 141 142 Stack = IoGetCurrentIrpStackLocation(Irp); 143 144 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_QUERY_AUTO_MOUNT)) 145 { 146 Irp->IoStatus.Information = 0; 147 return STATUS_INVALID_PARAMETER; 148 } 149 150 QueryState = (PMOUNTMGR_QUERY_AUTO_MOUNT)Irp->AssociatedIrp.SystemBuffer; 151 QueryState->CurrentState = !DeviceExtension->NoAutoMount; 152 Irp->IoStatus.Information = sizeof(MOUNTMGR_QUERY_AUTO_MOUNT); 153 154 return STATUS_SUCCESS; 155 } 156 157 /* 158 * @implemented 159 */ 160 NTSTATUS 161 NTAPI 162 ScrubRegistryRoutine(IN PWSTR ValueName, 163 IN ULONG ValueType, 164 IN PVOID ValueData, 165 IN ULONG ValueLength, 166 IN PVOID Context, 167 IN PVOID EntryContext) 168 { 169 NTSTATUS Status; 170 PLIST_ENTRY NextEntry; 171 PDEVICE_INFORMATION DeviceInfo; 172 PBOOLEAN Continue = EntryContext; 173 PDEVICE_EXTENSION DeviceExtension = Context; 174 175 if (ValueType != REG_BINARY) 176 { 177 return STATUS_SUCCESS; 178 } 179 180 /* Delete values for devices that don't have the matching unique ID */ 181 if (!IsListEmpty(&(DeviceExtension->DeviceListHead))) 182 { 183 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 184 NextEntry != &(DeviceExtension->DeviceListHead); 185 NextEntry = NextEntry->Flink) 186 { 187 DeviceInfo = CONTAINING_RECORD(NextEntry, 188 DEVICE_INFORMATION, 189 DeviceListEntry); 190 191 if (!DeviceInfo->UniqueId || DeviceInfo->UniqueId->UniqueIdLength != ValueLength) 192 { 193 continue; 194 } 195 196 if (RtlCompareMemory(DeviceInfo->UniqueId->UniqueId, ValueData, ValueLength) == ValueLength) 197 { 198 return STATUS_SUCCESS; 199 } 200 } 201 } 202 203 /* Wrong unique ID, scrub it */ 204 Status = RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, 205 DatabasePath, 206 ValueName); 207 if (!NT_SUCCESS(Status)) 208 { 209 *Continue = TRUE; 210 return STATUS_UNSUCCESSFUL; 211 } 212 213 *Continue = FALSE; 214 return Status; 215 } 216 217 /* 218 * @implemented 219 */ 220 NTSTATUS 221 MountMgrScrubRegistry(IN PDEVICE_EXTENSION DeviceExtension) 222 { 223 NTSTATUS Status; 224 BOOLEAN Continue; 225 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 226 227 do 228 { 229 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 230 QueryTable[0].QueryRoutine = ScrubRegistryRoutine; 231 QueryTable[0].EntryContext = &Continue; 232 Continue = FALSE; 233 234 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 235 DatabasePath, 236 QueryTable, 237 DeviceExtension, 238 NULL); 239 } 240 while (Continue); 241 242 return Status; 243 } 244 245 /* 246 * @implemented 247 */ 248 NTSTATUS 249 MountMgrCreatePoint(IN PDEVICE_EXTENSION DeviceExtension, 250 IN PIRP Irp) 251 { 252 ULONG MaxLength; 253 PIO_STACK_LOCATION Stack; 254 PMOUNTMGR_CREATE_POINT_INPUT Point; 255 UNICODE_STRING DeviceName, SymbolicName; 256 257 Stack = IoGetCurrentIrpStackLocation(Irp); 258 259 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_CREATE_POINT_INPUT)) 260 { 261 return STATUS_INVALID_PARAMETER; 262 } 263 264 Point = (PMOUNTMGR_CREATE_POINT_INPUT)Irp->AssociatedIrp.SystemBuffer; 265 266 MaxLength = MAX((Point->DeviceNameOffset + Point->DeviceNameLength), 267 (Point->SymbolicLinkNameLength + Point->SymbolicLinkNameOffset)); 268 if (MaxLength > Stack->Parameters.DeviceIoControl.InputBufferLength) 269 { 270 return STATUS_INVALID_PARAMETER; 271 } 272 273 /* Get all the strings and call the worker */ 274 SymbolicName.Length = Point->SymbolicLinkNameLength; 275 SymbolicName.MaximumLength = Point->SymbolicLinkNameLength; 276 DeviceName.Length = Point->DeviceNameLength; 277 DeviceName.MaximumLength = Point->DeviceNameLength; 278 SymbolicName.Buffer = (PVOID)((ULONG_PTR)Point + Point->SymbolicLinkNameOffset); 279 DeviceName.Buffer = (PVOID)((ULONG_PTR)Point + Point->DeviceNameOffset); 280 281 return MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &DeviceName); 282 } 283 284 /* 285 * @implemented 286 */ 287 NTSTATUS 288 MountMgrCheckUnprocessedVolumes(IN PDEVICE_EXTENSION DeviceExtension, 289 IN PIRP Irp) 290 { 291 PLIST_ENTRY NextEntry; 292 PDEVICE_INFORMATION DeviceInformation; 293 NTSTATUS ArrivalStatus, Status = STATUS_SUCCESS; 294 295 UNREFERENCED_PARAMETER(Irp); 296 297 /* No offline volumes, nothing more to do */ 298 if (IsListEmpty(&(DeviceExtension->OfflineDeviceListHead))) 299 { 300 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 301 return STATUS_SUCCESS; 302 } 303 304 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 305 306 /* Reactivate all the offline volumes */ 307 while (!IsListEmpty(&(DeviceExtension->OfflineDeviceListHead))) 308 { 309 NextEntry = RemoveHeadList(&(DeviceExtension->OfflineDeviceListHead)); 310 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 311 312 ArrivalStatus = MountMgrMountedDeviceArrival(DeviceExtension, 313 &(DeviceInformation->SymbolicName), 314 DeviceInformation->ManuallyRegistered); 315 /* Then, remove them dead information */ 316 MountMgrFreeDeadDeviceInfo(DeviceInformation); 317 318 if (NT_SUCCESS(Status)) 319 { 320 Status = ArrivalStatus; 321 } 322 } 323 324 return Status; 325 } 326 327 /* 328 * @implemented 329 */ 330 BOOLEAN 331 IsFtVolume(IN PUNICODE_STRING SymbolicName) 332 { 333 NTSTATUS Status; 334 PFILE_OBJECT FileObject; 335 PARTITION_INFORMATION PartitionInfo; 336 PDEVICE_OBJECT DeviceObject, FileDeviceObject; 337 338 /* Get device object */ 339 Status = IoGetDeviceObjectPointer(SymbolicName, 340 FILE_READ_ATTRIBUTES, 341 &FileObject, 342 &DeviceObject); 343 if (!NT_SUCCESS(Status)) 344 return FALSE; 345 346 /* Get attached device */ 347 FileDeviceObject = FileObject->DeviceObject; 348 DeviceObject = IoGetAttachedDeviceReference(FileDeviceObject); 349 350 /* FT volume can't be removable */ 351 if (FileDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) 352 { 353 ObDereferenceObject(DeviceObject); 354 ObDereferenceObject(FileObject); 355 return FALSE; 356 } 357 358 ObDereferenceObject(FileObject); 359 360 /* Get partition information */ 361 Status = MountMgrSendSyncDeviceIoCtl(IOCTL_DISK_GET_PARTITION_INFO, 362 DeviceObject, 363 NULL, 364 0, 365 &PartitionInfo, 366 sizeof(PartitionInfo), 367 NULL); 368 369 ObDereferenceObject(DeviceObject); 370 if (!NT_SUCCESS(Status)) 371 return FALSE; 372 373 /* Check if this is a FT volume */ 374 return IsFTPartition(PartitionInfo.PartitionType); 375 } 376 377 /* 378 * @implemented 379 */ 380 VOID 381 ProcessSuggestedDriveLetters(IN PDEVICE_EXTENSION DeviceExtension) 382 { 383 WCHAR NameBuffer[DRIVE_LETTER_LENGTH / sizeof(WCHAR)]; 384 PLIST_ENTRY NextEntry; 385 UNICODE_STRING SymbolicName; 386 PDEVICE_INFORMATION DeviceInformation; 387 388 /* No devices? Nothing to do! */ 389 if (IsListEmpty(&(DeviceExtension->DeviceListHead))) 390 { 391 return; 392 } 393 394 /* For all the devices */ 395 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 396 NextEntry != &(DeviceExtension->DeviceListHead); 397 NextEntry = NextEntry->Flink) 398 { 399 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 400 401 /* If no drive letter */ 402 if (DeviceInformation->SuggestedDriveLetter == (UCHAR)-1) 403 { 404 /* Ensure it has no entry yet */ 405 if (!HasDriveLetter(DeviceInformation) && 406 !HasNoDriveLetterEntry(DeviceInformation->UniqueId)) 407 { 408 /* And create one */ 409 CreateNoDriveLetterEntry(DeviceInformation->UniqueId); 410 } 411 412 DeviceInformation->SuggestedDriveLetter = 0; 413 } 414 /* Suggested letter & no entry */ 415 else if (DeviceInformation->SuggestedDriveLetter && 416 !HasNoDriveLetterEntry(DeviceInformation->UniqueId)) 417 { 418 /* Just create a mount point */ 419 SymbolicName.Buffer = NameBuffer; 420 RtlCopyMemory(NameBuffer, DosDevices.Buffer, DosDevices.Length); 421 NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter; 422 NameBuffer[COLON_POSITION] = L':'; 423 SymbolicName.Length = 424 SymbolicName.MaximumLength = DRIVE_LETTER_LENGTH; 425 426 MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &(DeviceInformation->DeviceName)); 427 } 428 } 429 } 430 431 /* 432 * @implemented 433 */ 434 NTSTATUS 435 MountMgrNextDriveLetterWorker(IN PDEVICE_EXTENSION DeviceExtension, 436 IN PUNICODE_STRING DeviceName, 437 OUT PMOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInfo) 438 { 439 NTSTATUS Status; 440 UCHAR DriveLetter; 441 PLIST_ENTRY NextEntry; 442 PMOUNTDEV_UNIQUE_ID UniqueId; 443 BOOLEAN Removable, GptDriveLetter; 444 PDEVICE_INFORMATION DeviceInformation; 445 WCHAR NameBuffer[DRIVE_LETTER_LENGTH]; 446 PSYMLINK_INFORMATION SymlinkInformation; 447 UNICODE_STRING TargetDeviceName, SymbolicName; 448 449 /* First, process suggested letters */ 450 if (!DeviceExtension->ProcessedSuggestions) 451 { 452 ProcessSuggestedDriveLetters(DeviceExtension); 453 DeviceExtension->ProcessedSuggestions = TRUE; 454 } 455 456 /* Then, get information about the device */ 457 Status = QueryDeviceInformation(DeviceName, &TargetDeviceName, NULL, &Removable, &GptDriveLetter, NULL, NULL, NULL); 458 if (!NT_SUCCESS(Status)) 459 { 460 return Status; 461 } 462 463 /* Ensure we have such device */ 464 NextEntry = DeviceExtension->DeviceListHead.Flink; 465 while (NextEntry != &(DeviceExtension->DeviceListHead)) 466 { 467 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 468 469 if (RtlCompareUnicodeString(&(DeviceInformation->DeviceName), &TargetDeviceName, TRUE) == 0) 470 { 471 break; 472 } 473 474 NextEntry = NextEntry->Flink; 475 } 476 477 if (NextEntry == &(DeviceExtension->DeviceListHead)) 478 { 479 FreePool(TargetDeviceName.Buffer); 480 return STATUS_OBJECT_NAME_NOT_FOUND; 481 } 482 483 /* Now, assume we will assign a letter */ 484 DeviceInformation->LetterAssigned = 485 DriveLetterInfo->DriveLetterWasAssigned = TRUE; 486 487 /* Browse all the symlinks to check if there is already a drive letter */ 488 NextEntry = DeviceInformation->SymbolicLinksListHead.Flink; 489 while (NextEntry != &(DeviceInformation->SymbolicLinksListHead)) 490 { 491 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 492 493 /* If this is a drive letter and it is online, forget about new drive letter */ 494 if (IsDriveLetter(&(SymlinkInformation->Name)) && SymlinkInformation->Online) 495 { 496 DriveLetterInfo->DriveLetterWasAssigned = FALSE; 497 DriveLetterInfo->CurrentDriveLetter = (CHAR)SymlinkInformation->Name.Buffer[LETTER_POSITION]; 498 break; 499 } 500 501 NextEntry = NextEntry->Flink; 502 } 503 504 /* If we didn't find a drive letter online, ensure this is not 505 * a no-drive entry by querying GPT attributes & database */ 506 if (NextEntry == &(DeviceInformation->SymbolicLinksListHead)) 507 { 508 if (!GptDriveLetter || HasNoDriveLetterEntry(DeviceInformation->UniqueId)) 509 { 510 DriveLetterInfo->DriveLetterWasAssigned = FALSE; 511 DriveLetterInfo->CurrentDriveLetter = 0; 512 goto Release; 513 } 514 } 515 516 /* If automount is disabled, and the device is not removable 517 * but needs a drive letter, don't assign one and bail out */ 518 if (DeviceExtension->NoAutoMount && !Removable) 519 { 520 if (DriveLetterInfo->DriveLetterWasAssigned) 521 { 522 DriveLetterInfo->DriveLetterWasAssigned = FALSE; 523 DriveLetterInfo->CurrentDriveLetter = 0; 524 goto Release; 525 } 526 } 527 528 /* Stop now if we don't need to assign the drive a letter */ 529 if (!DriveLetterInfo->DriveLetterWasAssigned) 530 goto Release; 531 532 /* Now everything is fine, begin drive letter assignment */ 533 534 if (RtlPrefixUnicodeString(&DeviceFloppy, &TargetDeviceName, TRUE)) 535 { 536 /* If the device is a floppy, start with letter A */ 537 DriveLetter = 'A'; 538 } 539 else if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE)) 540 { 541 /* If the device is a CD-ROM, start with letter D */ 542 DriveLetter = 'D'; 543 } 544 else 545 { 546 /* Finally, if it's a disk, use C */ 547 DriveLetter = 'C'; 548 } 549 550 /* We cannot set NO drive letter */ 551 ASSERT(DeviceInformation->SuggestedDriveLetter != (UCHAR)-1); 552 553 /* If we don't have suggested letter but it's a FT volume, fail */ 554 if (!DeviceInformation->SuggestedDriveLetter && IsFtVolume(&(DeviceInformation->DeviceName))) 555 { 556 DriveLetterInfo->DriveLetterWasAssigned = FALSE; 557 DriveLetterInfo->CurrentDriveLetter = 0; 558 goto Release; 559 } 560 561 /* Prepare buffer */ 562 RtlCopyMemory(NameBuffer, DosDevices.Buffer, DosDevices.Length); 563 NameBuffer[COLON_POSITION] = L':'; 564 SymbolicName.Buffer = NameBuffer; 565 SymbolicName.Length = 566 SymbolicName.MaximumLength = DRIVE_LETTER_LENGTH; 567 568 /* It's all prepared, create mount point */ 569 if (DeviceInformation->SuggestedDriveLetter) 570 { 571 DriveLetterInfo->CurrentDriveLetter = DeviceInformation->SuggestedDriveLetter; 572 NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter; 573 574 Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName); 575 if (NT_SUCCESS(Status)) 576 { 577 goto Release; 578 } 579 } 580 581 /* It failed with this letter... Try another one! */ 582 for (DriveLetterInfo->CurrentDriveLetter = DriveLetter; 583 DriveLetterInfo->CurrentDriveLetter <= L'Z'; 584 DriveLetterInfo->CurrentDriveLetter++) 585 { 586 NameBuffer[LETTER_POSITION] = DriveLetterInfo->CurrentDriveLetter; 587 588 Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName); 589 if (NT_SUCCESS(Status)) 590 { 591 break; 592 } 593 } 594 595 /* We failed setting a letter */ 596 if (DriveLetterInfo->CurrentDriveLetter > L'Z') 597 { 598 DriveLetterInfo->DriveLetterWasAssigned = FALSE; 599 DriveLetterInfo->CurrentDriveLetter = 0; 600 601 /* Try at least to add a no drive letter entry */ 602 Status = QueryDeviceInformation(&TargetDeviceName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL); 603 if (NT_SUCCESS(Status)) 604 { 605 CreateNoDriveLetterEntry(UniqueId); 606 FreePool(UniqueId); 607 } 608 } 609 610 Release: 611 FreePool(TargetDeviceName.Buffer); 612 613 return STATUS_SUCCESS; 614 } 615 616 617 /* 618 * @implemented 619 */ 620 NTSTATUS 621 MountMgrNextDriveLetter(IN PDEVICE_EXTENSION DeviceExtension, 622 IN PIRP Irp) 623 { 624 NTSTATUS Status; 625 PIO_STACK_LOCATION Stack; 626 UNICODE_STRING DeviceName; 627 PMOUNTMGR_DRIVE_LETTER_TARGET DriveLetterTarget; 628 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation; 629 630 Stack = IoGetCurrentIrpStackLocation(Irp); 631 632 /* Validate input */ 633 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) || 634 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION)) 635 { 636 return STATUS_INVALID_PARAMETER; 637 } 638 639 DriveLetterTarget = (PMOUNTMGR_DRIVE_LETTER_TARGET)Irp->AssociatedIrp.SystemBuffer; 640 if (DriveLetterTarget->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength) 641 { 642 return STATUS_INVALID_PARAMETER; 643 } 644 645 /* Call the worker */ 646 DeviceName.Buffer = DriveLetterTarget->DeviceName; 647 DeviceName.Length = 648 DeviceName.MaximumLength = DriveLetterTarget->DeviceNameLength; 649 650 Status = MountMgrNextDriveLetterWorker(DeviceExtension, &DeviceName, 651 &DriveLetterInformation); 652 if (NT_SUCCESS(Status)) 653 { 654 *(PMOUNTMGR_DRIVE_LETTER_INFORMATION)Irp->AssociatedIrp.SystemBuffer = 655 DriveLetterInformation; 656 Irp->IoStatus.Information = sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION); 657 } 658 659 return Status; 660 } 661 662 /* 663 * @implemented 664 */ 665 NTSTATUS 666 NTAPI 667 MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName, 668 IN ULONG ValueType, 669 IN PVOID ValueData, 670 IN ULONG ValueLength, 671 IN PVOID Context, 672 IN PVOID EntryContext) 673 { 674 UNICODE_STRING ValueString; 675 PUNICODE_STRING SystemVolumeName; 676 677 UNREFERENCED_PARAMETER(ValueName); 678 UNREFERENCED_PARAMETER(ValueLength); 679 UNREFERENCED_PARAMETER(EntryContext); 680 681 if (ValueType != REG_SZ) 682 { 683 return STATUS_SUCCESS; 684 } 685 686 RtlInitUnicodeString(&ValueString, ValueData); 687 SystemVolumeName = Context; 688 689 /* Return a string containing system volume name */ 690 SystemVolumeName->Length = ValueString.Length; 691 SystemVolumeName->MaximumLength = ValueString.Length + sizeof(WCHAR); 692 SystemVolumeName->Buffer = AllocatePool(SystemVolumeName->MaximumLength); 693 if (SystemVolumeName->Buffer) 694 { 695 RtlCopyMemory(SystemVolumeName->Buffer, ValueData, ValueString.Length); 696 SystemVolumeName->Buffer[ValueString.Length / sizeof(WCHAR)] = UNICODE_NULL; 697 } 698 699 return STATUS_SUCCESS; 700 701 } 702 703 /* 704 * @implemented 705 */ 706 NTSTATUS 707 MountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName) 708 { 709 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 710 711 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 712 QueryTable[0].QueryRoutine = MountMgrQuerySystemVolumeNameQueryRoutine; 713 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; 714 QueryTable[0].Name = L"SystemPartition"; 715 716 SystemVolumeName->Buffer = NULL; 717 718 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 719 L"\\Registry\\Machine\\System\\Setup", 720 QueryTable, 721 SystemVolumeName, 722 NULL); 723 724 if (SystemVolumeName->Buffer) 725 { 726 return STATUS_SUCCESS; 727 } 728 729 return STATUS_UNSUCCESSFUL; 730 } 731 732 /* 733 * @implemented 734 */ 735 VOID 736 MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension) 737 { 738 NTSTATUS Status; 739 PLIST_ENTRY NextEntry; 740 UNICODE_STRING SystemVolumeName; 741 PDEVICE_INFORMATION DeviceInformation; 742 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation; 743 744 /* First, get system volume name */ 745 Status = MountMgrQuerySystemVolumeName(&SystemVolumeName); 746 747 /* If there are no device, it's all done */ 748 if (IsListEmpty(&(DeviceExtension->DeviceListHead))) 749 { 750 if (NT_SUCCESS(Status)) 751 { 752 FreePool(SystemVolumeName.Buffer); 753 } 754 755 return; 756 } 757 758 /* Now, for all the devices... */ 759 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 760 NextEntry != &(DeviceExtension->DeviceListHead); 761 NextEntry = NextEntry->Flink) 762 { 763 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 764 765 /* If the device doesn't have a letter assigned, do it! */ 766 if (!DeviceInformation->LetterAssigned) 767 { 768 MountMgrNextDriveLetterWorker(DeviceExtension, 769 &(DeviceInformation->DeviceName), 770 &DriveLetterInformation); 771 } 772 773 /* If it's the system volume */ 774 if (NT_SUCCESS(Status) && RtlEqualUnicodeString(&SystemVolumeName, &(DeviceInformation->DeviceName), TRUE)) 775 { 776 /* Keep track of it */ 777 DeviceExtension->DriveLetterData = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + 778 sizeof(MOUNTDEV_UNIQUE_ID)); 779 if (DeviceExtension->DriveLetterData) 780 { 781 RtlCopyMemory(DeviceExtension->DriveLetterData, 782 DeviceInformation->UniqueId, 783 DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 784 } 785 786 /* Ensure it gets mounted if automount is disabled */ 787 if (DeviceExtension->NoAutoMount) 788 { 789 /* Temporarily re-enable automount for the 790 * worker to mount and set a drive letter */ 791 DeviceExtension->NoAutoMount = FALSE; 792 793 MountMgrNextDriveLetterWorker(DeviceExtension, 794 &(DeviceInformation->DeviceName), 795 &DriveLetterInformation); 796 797 /* And re-disable automount */ 798 DeviceExtension->NoAutoMount = TRUE; 799 } 800 } 801 } 802 803 if (NT_SUCCESS(Status)) 804 { 805 FreePool(SystemVolumeName.Buffer); 806 } 807 } 808 809 /* 810 * @implemented 811 */ 812 NTSTATUS 813 MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension, 814 IN PIRP Irp) 815 { 816 NTSTATUS Status; 817 ULONG DevicesFound; 818 PIO_STACK_LOCATION Stack; 819 PLIST_ENTRY SymlinksEntry; 820 UNICODE_STRING SymbolicName; 821 PMOUNTMGR_TARGET_NAME Target; 822 PWSTR DeviceString, OldBuffer; 823 USHORT DeviceLength, OldLength; 824 PDEVICE_INFORMATION DeviceInformation; 825 PSYMLINK_INFORMATION SymlinkInformation; 826 PASSOCIATED_DEVICE_ENTRY AssociatedDevice; 827 828 Stack = IoGetCurrentIrpStackLocation(Irp); 829 830 /* Validate input size */ 831 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) 832 { 833 return STATUS_INVALID_PARAMETER; 834 } 835 836 /* Ensure we have received UNICODE_STRING */ 837 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; 838 if (Target->DeviceNameLength & 1) 839 { 840 return STATUS_INVALID_PARAMETER; 841 } 842 843 /* Validate the entry structure size */ 844 if ((FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceNameLength) + Target->DeviceNameLength) > 845 Stack->Parameters.DeviceIoControl.InputBufferLength) 846 { 847 return STATUS_INVALID_PARAMETER; 848 } 849 850 /* Ensure we can at least return needed size */ 851 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) 852 { 853 return STATUS_INVALID_PARAMETER; 854 } 855 856 /* Construct string for query */ 857 SymbolicName.Length = Target->DeviceNameLength; 858 SymbolicName.MaximumLength = Target->DeviceNameLength; 859 SymbolicName.Buffer = Target->DeviceName; 860 861 /* Find device with our info */ 862 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation); 863 if (!NT_SUCCESS(Status)) 864 { 865 return Status; 866 } 867 868 DeviceLength = 0; 869 DeviceString = NULL; 870 DevicesFound = 0; 871 872 /* Try to find associated device info */ 873 while (TRUE) 874 { 875 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink; 876 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead); 877 SymlinksEntry = SymlinksEntry->Flink) 878 { 879 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 880 881 /* Try to find with drive letter */ 882 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online) 883 { 884 break; 885 } 886 } 887 888 /* We didn't find, break */ 889 if (SymlinksEntry == &(DeviceInformation->SymbolicLinksListHead)) 890 { 891 return STATUS_NOT_FOUND; 892 } 893 894 /* It doesn't have associated device, go to fallback method */ 895 if (IsListEmpty(&DeviceInformation->AssociatedDevicesHead)) 896 { 897 goto TryWithVolumeName; 898 } 899 900 /* Create a string with the information about the device */ 901 AssociatedDevice = CONTAINING_RECORD(&(DeviceInformation->SymbolicLinksListHead), ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 902 OldLength = DeviceLength; 903 OldBuffer = DeviceString; 904 DeviceLength += AssociatedDevice->String.Length; 905 DeviceString = AllocatePool(DeviceLength); 906 if (!DeviceString) 907 { 908 if (OldBuffer) 909 { 910 FreePool(OldBuffer); 911 } 912 913 return STATUS_INSUFFICIENT_RESOURCES; 914 } 915 916 /* Store our info and previous if any */ 917 RtlCopyMemory(DeviceString, AssociatedDevice->String.Buffer, AssociatedDevice->String.Length); 918 if (OldBuffer) 919 { 920 RtlCopyMemory(&DeviceString[AssociatedDevice->String.Length / sizeof(WCHAR)], OldBuffer, OldLength); 921 FreePool(OldBuffer); 922 } 923 924 /* Count and continue looking */ 925 ++DevicesFound; 926 DeviceInformation = AssociatedDevice->DeviceInformation; 927 928 /* If too many devices, try another way */ 929 if (DevicesFound > MAX_DEVICES) /* 1000 */ 930 { 931 goto TryWithVolumeName; 932 } 933 } 934 935 /* Reallocate our string, so that we can prepend disk letter */ 936 OldBuffer = DeviceString; 937 OldLength = DeviceLength; 938 DeviceLength += 2 * sizeof(WCHAR); 939 DeviceString = AllocatePool(DeviceLength); 940 if (!DeviceString) 941 { 942 if (OldBuffer) 943 { 944 FreePool(OldBuffer); 945 } 946 947 return STATUS_INSUFFICIENT_RESOURCES; 948 } 949 950 /* Get the letter */ 951 DeviceString[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION]; 952 DeviceString[1] = L':'; 953 954 /* And copy the rest */ 955 if (OldBuffer) 956 { 957 RtlCopyMemory(&DeviceString[2], OldBuffer, OldLength); 958 FreePool(OldBuffer); 959 } 960 961 TryWithVolumeName: 962 /* If we didn't find anything, try differently */ 963 if (DeviceLength < 2 * sizeof(WCHAR) || DeviceString[1] != L':') 964 { 965 if (DeviceString) 966 { 967 FreePool(DeviceString); 968 DeviceLength = 0; 969 } 970 971 /* Try to find a volume name matching */ 972 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink; 973 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead); 974 SymlinksEntry = SymlinksEntry->Flink) 975 { 976 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 977 978 if (MOUNTMGR_IS_VOLUME_NAME(&SymlinkInformation->Name)) 979 { 980 break; 981 } 982 } 983 984 /* If found copy */ 985 if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead)) 986 { 987 DeviceLength = SymlinkInformation->Name.Length; 988 DeviceString = AllocatePool(DeviceLength); 989 if (!DeviceString) 990 { 991 return STATUS_INSUFFICIENT_RESOURCES; 992 } 993 994 RtlCopyMemory(DeviceString, SymlinkInformation->Name.Buffer, DeviceLength); 995 /* Ensure we are in the right namespace; [1] can be ? */ 996 DeviceString[1] = L'\\'; 997 } 998 } 999 1000 /* If we found something */ 1001 if (DeviceString) 1002 { 1003 /* At least, we will return our length */ 1004 ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSzLength = DeviceLength; 1005 /* MOUNTMGR_VOLUME_PATHS is a string + a ULONG */ 1006 Irp->IoStatus.Information = DeviceLength + sizeof(ULONG); 1007 1008 /* If we have enough room for copying the string */ 1009 if (sizeof(ULONG) + DeviceLength <= Stack->Parameters.DeviceIoControl.OutputBufferLength) 1010 { 1011 /* Copy it */ 1012 if (DeviceLength) 1013 { 1014 RtlCopyMemory(((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz, DeviceString, DeviceLength); 1015 } 1016 1017 /* And double zero at its end - this is needed in case of multiple paths which are separated by a single 0 */ 1018 FreePool(DeviceString); 1019 ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz[DeviceLength / sizeof(WCHAR)] = 0; 1020 ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz[DeviceLength / sizeof(WCHAR) + 1] = 0; 1021 1022 return STATUS_SUCCESS; 1023 } 1024 else 1025 { 1026 /* Just return appropriate size and leave */ 1027 FreePool(DeviceString); 1028 Irp->IoStatus.Information = sizeof(ULONG); 1029 return STATUS_BUFFER_OVERFLOW; 1030 } 1031 } 1032 1033 /* Fail */ 1034 return STATUS_NOT_FOUND; 1035 } 1036 1037 /* 1038 * @implemented 1039 */ 1040 NTSTATUS 1041 MountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry, 1042 IN PDEVICE_INFORMATION DeviceInformation, 1043 OUT PBOOLEAN Invalid) 1044 { 1045 HANDLE Handle; 1046 NTSTATUS Status; 1047 PLIST_ENTRY SymlinksEntry; 1048 IO_STATUS_BLOCK IoStatusBlock; 1049 PREPARSE_DATA_BUFFER ReparseData; 1050 OBJECT_ATTRIBUTES ObjectAttributes; 1051 UNICODE_STRING FullName, SubstituteName; 1052 PSYMLINK_INFORMATION SymlinkInformation; 1053 1054 /* Initialize & allocate a string big enough to contain our complete mount point name */ 1055 FullName.Length = 0; 1056 FullName.MaximumLength = AssociatedDeviceEntry->String.Length 1057 + AssociatedDeviceEntry->DeviceInformation->DeviceName.Length 1058 + sizeof(WCHAR) 1059 + sizeof(UNICODE_NULL); 1060 FullName.Buffer = AllocatePool(FullName.MaximumLength); 1061 if (!FullName.Buffer) 1062 { 1063 return STATUS_INSUFFICIENT_RESOURCES; 1064 } 1065 1066 /* Create the path */ 1067 RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->DeviceInformation->DeviceName); 1068 FullName.Buffer[FullName.Length / sizeof(WCHAR)] = L'\\'; 1069 RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->String); 1070 FullName.Buffer[FullName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1071 1072 /* Open it to query the reparse point */ 1073 InitializeObjectAttributes(&ObjectAttributes, 1074 &FullName, 1075 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1076 NULL, 1077 NULL); 1078 Status = ZwOpenFile(&Handle, 1079 SYNCHRONIZE | FILE_READ_ATTRIBUTES, 1080 &ObjectAttributes, &IoStatusBlock, 1081 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1082 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT); 1083 FreePool(FullName.Buffer); 1084 1085 if (!NT_SUCCESS(Status)) 1086 { 1087 *Invalid = TRUE; 1088 return STATUS_SUCCESS; 1089 } 1090 1091 /* Allocate a buffer big enough to read reparse data */ 1092 ReparseData = AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 1093 if (ReparseData == NULL) 1094 { 1095 ZwClose(Handle); 1096 return STATUS_INSUFFICIENT_RESOURCES; 1097 } 1098 1099 /* Query reparse data */ 1100 Status = ZwFsControlFile(Handle, 1101 NULL, NULL, NULL, 1102 &IoStatusBlock, 1103 FSCTL_GET_REPARSE_POINT, 1104 NULL, 0, 1105 ReparseData, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 1106 ZwClose(Handle); 1107 1108 if (!NT_SUCCESS(Status)) 1109 { 1110 FreePool(ReparseData); 1111 *Invalid = TRUE; 1112 return STATUS_SUCCESS; 1113 } 1114 1115 /* Create a string with the substitute name */ 1116 SubstituteName.Length = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength; 1117 SubstituteName.MaximumLength = SubstituteName.Length; 1118 SubstituteName.Buffer = (PWSTR)((ULONG_PTR)ReparseData->SymbolicLinkReparseBuffer.PathBuffer + ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset); 1119 1120 /* If that's a volume name that matches our associated device, that's a success! */ 1121 if (MOUNTMGR_IS_VOLUME_NAME(&SubstituteName)) 1122 { 1123 if (SubstituteName.Length == 98 && SubstituteName.Buffer[1] == L'?') 1124 { 1125 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink; 1126 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead); 1127 SymlinksEntry = SymlinksEntry->Flink) 1128 { 1129 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 1130 1131 if (RtlEqualUnicodeString(&SubstituteName, &SymlinkInformation->Name, TRUE)) 1132 { 1133 FreePool(ReparseData); 1134 return STATUS_SUCCESS; 1135 } 1136 } 1137 } 1138 } 1139 1140 FreePool(ReparseData); 1141 *Invalid = TRUE; 1142 return STATUS_SUCCESS; 1143 } 1144 1145 /* 1146 * @implemented 1147 */ 1148 NTSTATUS 1149 MountMgrQueryVolumePaths(IN PDEVICE_EXTENSION DeviceExtension, 1150 IN PDEVICE_INFORMATION DeviceInformation, 1151 IN PLIST_ENTRY DeviceInfoList, 1152 OUT PMOUNTMGR_VOLUME_PATHS * VolumePaths, 1153 OUT PDEVICE_INFORMATION *FailedDevice) 1154 { 1155 ULONG Written; 1156 NTSTATUS Status; 1157 PLIST_ENTRY Entry; 1158 PSYMLINK_INFORMATION SymlinkInformation; 1159 PDEVICE_INFORMATION_ENTRY DeviceInfoEntry; 1160 PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry; 1161 PMOUNTMGR_VOLUME_PATHS * Paths = NULL, * CurrentPath; 1162 ULONG OutputPathLength, NumberOfPaths, ReturnedPaths; 1163 1164 /* We return at least null char */ 1165 OutputPathLength = sizeof(UNICODE_NULL); 1166 1167 for (Entry = DeviceInformation->SymbolicLinksListHead.Flink; 1168 Entry != &(DeviceInformation->SymbolicLinksListHead); 1169 Entry = Entry->Flink) 1170 { 1171 SymlinkInformation = CONTAINING_RECORD(Entry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 1172 1173 /* Try to find the drive letter (ie, DOS device) */ 1174 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online) 1175 { 1176 /* We'll return the letter */ 1177 OutputPathLength = 4 * sizeof(WCHAR); 1178 break; 1179 } 1180 } 1181 1182 /* We didn't find any */ 1183 if (Entry == &(DeviceInformation->SymbolicLinksListHead)) 1184 { 1185 SymlinkInformation = NULL; 1186 } 1187 1188 /* Do we have any device info to return? */ 1189 for (Entry = DeviceInfoList->Flink; Entry != DeviceInfoList; Entry = Entry->Flink) 1190 { 1191 DeviceInfoEntry = CONTAINING_RECORD(Entry, DEVICE_INFORMATION_ENTRY, DeviceInformationEntry); 1192 1193 /* Matching current device */ 1194 if (DeviceInfoEntry->DeviceInformation == DeviceInformation) 1195 { 1196 /* Allocate the output buffer */ 1197 *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength); 1198 if (*VolumePaths == NULL) 1199 { 1200 return STATUS_INSUFFICIENT_RESOURCES; 1201 } 1202 1203 /* Set size */ 1204 (*VolumePaths)->MultiSzLength = OutputPathLength; 1205 /* If we have a drive letter, return it */ 1206 if (SymlinkInformation != NULL) 1207 { 1208 (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION]; 1209 (*VolumePaths)->MultiSz[1] = L':'; 1210 (*VolumePaths)->MultiSz[2] = UNICODE_NULL; 1211 (*VolumePaths)->MultiSz[3] = UNICODE_NULL; 1212 } 1213 else 1214 { 1215 (*VolumePaths)->MultiSz[0] = UNICODE_NULL; 1216 } 1217 1218 return STATUS_SUCCESS; 1219 } 1220 } 1221 1222 /* Allocate a new device entry */ 1223 DeviceInfoEntry = AllocatePool(sizeof(DEVICE_INFORMATION_ENTRY)); 1224 if (DeviceInfoEntry == NULL) 1225 { 1226 return STATUS_INSUFFICIENT_RESOURCES; 1227 } 1228 1229 /* Add it to the list */ 1230 DeviceInfoEntry->DeviceInformation = DeviceInformation; 1231 InsertTailList(DeviceInfoList, &DeviceInfoEntry->DeviceInformationEntry); 1232 1233 NumberOfPaths = 0; 1234 /* Count the amount of devices we will have to handle */ 1235 if (!IsListEmpty(&DeviceInformation->AssociatedDevicesHead)) 1236 { 1237 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink; 1238 Entry != &DeviceInformation->AssociatedDevicesHead; 1239 Entry = Entry->Flink) 1240 { 1241 ++NumberOfPaths; 1242 } 1243 1244 ASSERT(NumberOfPaths != 0); 1245 /* And allocate a big enough buffer */ 1246 Paths = AllocatePool(NumberOfPaths * sizeof(PMOUNTMGR_VOLUME_PATHS)); 1247 if (Paths == NULL) 1248 { 1249 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1250 FreePool(DeviceInfoEntry); 1251 return STATUS_INSUFFICIENT_RESOURCES; 1252 } 1253 } 1254 1255 /* Start the hot loop to gather all the paths and be able to compute total output length! */ 1256 ReturnedPaths = 0; 1257 CurrentPath = Paths; 1258 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink; 1259 Entry != &DeviceInformation->AssociatedDevicesHead; 1260 Entry = Entry->Flink) 1261 { 1262 USHORT InnerStrings; 1263 BOOLEAN Invalid = FALSE; 1264 1265 AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 1266 1267 /* Validate the fact its a mount point by query reparse data */ 1268 Status = MountMgrValidateBackPointer(AssociatedDeviceEntry, DeviceInformation, &Invalid); 1269 1270 /* If we found an invalid device, that's a failure */ 1271 if (Invalid) 1272 { 1273 *FailedDevice = AssociatedDeviceEntry->DeviceInformation; 1274 Status = STATUS_UNSUCCESSFUL; 1275 } 1276 1277 /* Check whether we failed, if so, bail out */ 1278 if (!NT_SUCCESS(Status)) 1279 { 1280 ULONG i; 1281 1282 for (i = 0; i < ReturnedPaths; ++i) 1283 { 1284 FreePool(Paths[i]); 1285 } 1286 1287 if (Paths != NULL) 1288 { 1289 FreePool(Paths); 1290 } 1291 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1292 FreePool(DeviceInfoEntry); 1293 return Status; 1294 } 1295 1296 /* Query associated paths (hello ourselves :-)) */ 1297 Status = MountMgrQueryVolumePaths(DeviceExtension, 1298 AssociatedDeviceEntry->DeviceInformation, 1299 DeviceInfoList, 1300 CurrentPath, 1301 FailedDevice); 1302 if (!NT_SUCCESS(Status)) 1303 { 1304 ULONG i; 1305 1306 for (i = 0; i < ReturnedPaths; ++i) 1307 { 1308 FreePool(Paths[i]); 1309 } 1310 1311 if (Paths != NULL) 1312 { 1313 FreePool(Paths); 1314 } 1315 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1316 FreePool(DeviceInfoEntry); 1317 return Status; 1318 } 1319 1320 /* Count the number of strings we have in the multi string buffer */ 1321 InnerStrings = 0; 1322 if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL)) 1323 { 1324 ULONG i; 1325 PWSTR MultiSz = (*CurrentPath)->MultiSz; 1326 1327 for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR); ++i, ++MultiSz) 1328 { 1329 if (*MultiSz == UNICODE_NULL) 1330 { 1331 ++InnerStrings; 1332 } 1333 } 1334 } 1335 1336 /* We returned one more path (ie, one more allocated buffer) */ 1337 ++ReturnedPaths; 1338 /* Move the next pointer to use in the array */ 1339 ++CurrentPath; 1340 /* Multiply String.Length by the number of found paths, we always add it after a path */ 1341 OutputPathLength += (*CurrentPath)->MultiSzLength + InnerStrings * AssociatedDeviceEntry->String.Length - sizeof(UNICODE_NULL); 1342 } 1343 1344 /* Allocate the output buffer */ 1345 *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength); 1346 if (*VolumePaths == NULL) 1347 { 1348 ULONG i; 1349 1350 for (i = 0; i < ReturnedPaths; ++i) 1351 { 1352 FreePool(Paths[i]); 1353 } 1354 1355 if (Paths != NULL) 1356 { 1357 FreePool(Paths); 1358 } 1359 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1360 FreePool(DeviceInfoEntry); 1361 return STATUS_INSUFFICIENT_RESOURCES; 1362 } 1363 1364 Written = 0; 1365 /* If we had found a DOS letter, that's the first thing we return */ 1366 (*VolumePaths)->MultiSzLength = OutputPathLength; 1367 if (SymlinkInformation != NULL) 1368 { 1369 (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION]; 1370 (*VolumePaths)->MultiSz[1] = L':'; 1371 (*VolumePaths)->MultiSz[2] = UNICODE_NULL; 1372 Written = 3; 1373 } 1374 1375 /* Now, browse again all our paths to return them */ 1376 CurrentPath = Paths; 1377 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink; 1378 Entry != &DeviceInformation->AssociatedDevicesHead; 1379 Entry = Entry->Flink) 1380 { 1381 AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 1382 1383 /* If we had a path... */ 1384 if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL)) 1385 { 1386 ULONG i, Offset; 1387 PWSTR MultiSz; 1388 1389 /* This offset is used to "jump" into MultiSz, so, start with the string begin (ie, skip MultiSzLength) */ 1390 Offset = sizeof(ULONG); 1391 /* Browse every single letter, and skip last UNICODE_NULL */ 1392 for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR) - 1; ++i) 1393 { 1394 /* Get the letter */ 1395 MultiSz = (PWSTR)((ULONG_PTR)(*CurrentPath) + Offset); 1396 /* If it was part of the path, just return it */ 1397 if (*MultiSz != UNICODE_NULL) 1398 { 1399 (*VolumePaths)->MultiSz[Written] = *MultiSz; 1400 } 1401 else 1402 { 1403 /* Otherwise, as planed, return our whole associated device name */ 1404 RtlCopyMemory(&(*VolumePaths)->MultiSz[Written], 1405 AssociatedDeviceEntry->String.Buffer, 1406 AssociatedDeviceEntry->String.Length); 1407 Written += AssociatedDeviceEntry->String.Length / sizeof(WCHAR); 1408 /* And don't forget to nullify */ 1409 (*VolumePaths)->MultiSz[Written] = UNICODE_NULL; 1410 } 1411 1412 /* We at least return a letter or a null char */ 1413 ++Written; 1414 /* Move to the next letter */ 1415 Offset += sizeof(WCHAR); 1416 } 1417 } 1418 1419 FreePool(*CurrentPath); 1420 ++CurrentPath; 1421 } 1422 1423 /* MultiSz: don't forget last null char */ 1424 (*VolumePaths)->MultiSz[Written] = UNICODE_NULL; 1425 /* Cleanup everything and return success! */ 1426 if (Paths != NULL) 1427 { 1428 FreePool(Paths); 1429 } 1430 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1431 FreePool(DeviceInfoEntry); 1432 return STATUS_SUCCESS; 1433 } 1434 1435 /* 1436 * @implemented 1437 */ 1438 NTSTATUS 1439 MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension, 1440 IN PIRP Irp) 1441 { 1442 NTSTATUS Status; 1443 PLIST_ENTRY Entry; 1444 LIST_ENTRY Devices; 1445 BOOLEAN NeedNotification; 1446 PIO_STACK_LOCATION Stack; 1447 UNICODE_STRING SymbolicName; 1448 ULONG Attempts, OutputLength; 1449 PMOUNTMGR_TARGET_NAME Target; 1450 PMOUNTMGR_VOLUME_PATHS Paths, Output; 1451 RECONCILE_WORK_ITEM_CONTEXT ReconcileContext; 1452 PDEVICE_INFORMATION DeviceInformation, ListDeviceInfo, FailedDevice; 1453 1454 Stack = IoGetCurrentIrpStackLocation(Irp); 1455 1456 /* Validate input size */ 1457 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) 1458 { 1459 return STATUS_INVALID_PARAMETER; 1460 } 1461 1462 /* Ensure we have received UNICODE_STRING */ 1463 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; 1464 if (Target->DeviceNameLength & 1) 1465 { 1466 return STATUS_INVALID_PARAMETER; 1467 } 1468 1469 /* Validate the entry structure size */ 1470 if (Target->DeviceNameLength + FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) > Stack->Parameters.DeviceIoControl.InputBufferLength) 1471 { 1472 return STATUS_INVALID_PARAMETER; 1473 } 1474 1475 /* Ensure we can at least return needed size */ 1476 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) 1477 { 1478 return STATUS_INVALID_PARAMETER; 1479 } 1480 1481 /* Construct string for query */ 1482 SymbolicName.Length = Target->DeviceNameLength; 1483 SymbolicName.MaximumLength = Target->DeviceNameLength + sizeof(UNICODE_NULL); 1484 SymbolicName.Buffer = Target->DeviceName; 1485 1486 /* Find device with our info */ 1487 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation); 1488 if (!NT_SUCCESS(Status)) 1489 { 1490 return Status; 1491 } 1492 1493 NeedNotification = FALSE; 1494 Attempts = 0; 1495 for (;;) 1496 { 1497 FailedDevice = NULL; 1498 InitializeListHead(&Devices); 1499 1500 /* Query paths */ 1501 Status = MountMgrQueryVolumePaths(DeviceExtension, DeviceInformation, &Devices, &Paths, &FailedDevice); 1502 if (NT_SUCCESS(Status)) 1503 { 1504 break; 1505 } 1506 1507 /* If it failed for generic reason (memory, whatever), bail out (ie, FailedDevice not set) */ 1508 if (FailedDevice == NULL) 1509 { 1510 return Status; 1511 } 1512 1513 /* If PnP, let's notify in case of success */ 1514 if (!DeviceInformation->ManuallyRegistered) 1515 { 1516 NeedNotification = TRUE; 1517 } 1518 1519 /* Reconcile database */ 1520 ReconcileContext.DeviceExtension = DeviceExtension; 1521 ReconcileContext.DeviceInformation = FailedDevice; 1522 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE); 1523 ReconcileThisDatabaseWithMasterWorker(&ReconcileContext); 1524 KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL); 1525 1526 /* Look for our device, to check it's online */ 1527 for (Entry = DeviceExtension->DeviceListHead.Flink; 1528 Entry != &DeviceExtension->DeviceListHead; 1529 Entry = Entry->Flink) 1530 { 1531 ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry); 1532 /* It's online, it's OK! */ 1533 if (ListDeviceInfo == DeviceInformation) 1534 { 1535 break; 1536 } 1537 } 1538 1539 /* It's not online, it's not good */ 1540 if (Entry == &DeviceExtension->DeviceListHead) 1541 { 1542 return STATUS_OBJECT_NAME_NOT_FOUND; 1543 } 1544 1545 /* Increase attempts count */ 1546 ++Attempts; 1547 /* Don't look forever and fail if we get out of attempts */ 1548 if (Attempts >= 1000) 1549 { 1550 return Status; 1551 } 1552 } 1553 1554 /* We need to notify? Go ahead */ 1555 if (NeedNotification) 1556 { 1557 MountMgrNotifyNameChange(DeviceExtension, &SymbolicName, FALSE); 1558 } 1559 1560 /* Get output buffer */ 1561 Output = (PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer; 1562 1563 /* Set required size */ 1564 Output->MultiSzLength = Paths->MultiSzLength; 1565 1566 /* Compute total length */ 1567 OutputLength = Output->MultiSzLength + sizeof(ULONG); 1568 1569 /* If it cannot fit, just return need size and quit */ 1570 if (OutputLength > Stack->Parameters.DeviceIoControl.OutputBufferLength) 1571 { 1572 Irp->IoStatus.Information = sizeof(ULONG); 1573 FreePool(Paths); 1574 return STATUS_BUFFER_OVERFLOW; 1575 } 1576 1577 /* Copy data and quit */ 1578 Irp->IoStatus.Information = OutputLength; 1579 RtlCopyMemory(Output->MultiSz, Paths->MultiSz, Output->MultiSzLength); 1580 FreePool(Paths); 1581 return STATUS_SUCCESS; 1582 } 1583 1584 /* 1585 * @implemented 1586 */ 1587 NTSTATUS 1588 MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension, 1589 IN PIRP Irp) 1590 { 1591 NTSTATUS Status; 1592 PIO_STACK_LOCATION Stack; 1593 UNICODE_STRING SymbolicName; 1594 PMOUNTMGR_TARGET_NAME Target; 1595 PDEVICE_INFORMATION DeviceInformation; 1596 1597 Stack = IoGetCurrentIrpStackLocation(Irp); 1598 1599 /* Validate input */ 1600 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) 1601 { 1602 return STATUS_INVALID_PARAMETER; 1603 } 1604 1605 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; 1606 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength) 1607 { 1608 return STATUS_INVALID_PARAMETER; 1609 } 1610 1611 SymbolicName.Length = 1612 SymbolicName.MaximumLength = Target->DeviceNameLength; 1613 SymbolicName.Buffer = Target->DeviceName; 1614 1615 /* Find the associated device */ 1616 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation); 1617 if (!NT_SUCCESS(Status)) 1618 { 1619 return Status; 1620 } 1621 1622 /* Mark we want to keep links */ 1623 DeviceInformation->KeepLinks = TRUE; 1624 1625 return STATUS_SUCCESS; 1626 } 1627 1628 /* 1629 * @implemented 1630 */ 1631 NTSTATUS 1632 MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension, 1633 IN PIRP Irp) 1634 { 1635 NTSTATUS Status; 1636 BOOLEAN OldState; 1637 PIO_STACK_LOCATION Stack; 1638 UNICODE_STRING SymbolicName; 1639 PMOUNTMGR_TARGET_NAME Target; 1640 1641 Stack = IoGetCurrentIrpStackLocation(Irp); 1642 1643 /* Validate input */ 1644 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) 1645 { 1646 return STATUS_INVALID_PARAMETER; 1647 } 1648 1649 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; 1650 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength) 1651 { 1652 return STATUS_INVALID_PARAMETER; 1653 } 1654 1655 SymbolicName.Length = 1656 SymbolicName.MaximumLength = Target->DeviceNameLength; 1657 SymbolicName.Buffer = Target->DeviceName; 1658 1659 /* Disable hard errors */ 1660 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread()); 1661 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE); 1662 1663 /* Call real worker */ 1664 Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE); 1665 1666 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState); 1667 1668 return Status; 1669 } 1670 1671 /* 1672 * @implemented 1673 */ 1674 NTSTATUS 1675 MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension, 1676 IN PIRP Irp) 1677 { 1678 NTSTATUS Status; 1679 PIO_STACK_LOCATION Stack; 1680 PMOUNTDEV_UNIQUE_ID UniqueId; 1681 PMOUNTMGR_MOUNT_POINT MountPoint; 1682 UNICODE_STRING SymbolicName, DeviceName; 1683 1684 Stack = IoGetCurrentIrpStackLocation(Irp); 1685 1686 /* Validate input... */ 1687 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT)) 1688 { 1689 return STATUS_INVALID_PARAMETER; 1690 } 1691 1692 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer; 1693 if (!MountPoint->SymbolicLinkNameLength) 1694 { 1695 MountPoint->SymbolicLinkNameOffset = 0; 1696 } 1697 1698 if (!MountPoint->UniqueIdLength) 1699 { 1700 MountPoint->UniqueIdOffset = 0; 1701 } 1702 1703 if (!MountPoint->DeviceNameLength) 1704 { 1705 MountPoint->DeviceNameOffset = 0; 1706 } 1707 1708 /* Addresses can't be odd */ 1709 if ((MountPoint->SymbolicLinkNameOffset & 1) || 1710 (MountPoint->SymbolicLinkNameLength & 1)) 1711 { 1712 return STATUS_INVALID_PARAMETER; 1713 } 1714 1715 if ((MountPoint->UniqueIdOffset & 1) || 1716 (MountPoint->UniqueIdLength & 1)) 1717 { 1718 return STATUS_INVALID_PARAMETER; 1719 } 1720 1721 if ((MountPoint->DeviceNameOffset & 1) || 1722 (MountPoint->DeviceNameLength & 1)) 1723 { 1724 return STATUS_INVALID_PARAMETER; 1725 } 1726 1727 /* We can't go beyond */ 1728 if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength + 1729 MountPoint->DeviceNameLength) > Stack->Parameters.DeviceIoControl.InputBufferLength) 1730 { 1731 return STATUS_INVALID_PARAMETER; 1732 } 1733 1734 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS)) 1735 { 1736 return STATUS_INVALID_PARAMETER; 1737 } 1738 1739 /* If caller provided a Symlink, use it */ 1740 if (MountPoint->SymbolicLinkNameLength != 0) 1741 { 1742 if (MountPoint->SymbolicLinkNameLength > MAXSHORT) 1743 { 1744 return STATUS_INVALID_PARAMETER; 1745 } 1746 1747 SymbolicName.Length = MountPoint->SymbolicLinkNameLength; 1748 SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR); 1749 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength); 1750 if (!SymbolicName.Buffer) 1751 { 1752 return STATUS_INSUFFICIENT_RESOURCES; 1753 } 1754 1755 RtlCopyMemory(SymbolicName.Buffer, 1756 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset), 1757 SymbolicName.Length); 1758 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1759 1760 /* Query links using it */ 1761 Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp); 1762 FreePool(SymbolicName.Buffer); 1763 } 1764 /* If user provided an unique ID */ 1765 else if (MountPoint->UniqueIdLength != 0) 1766 { 1767 UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 1768 if (!UniqueId) 1769 { 1770 return STATUS_INSUFFICIENT_RESOURCES; 1771 } 1772 1773 UniqueId->UniqueIdLength = MountPoint->UniqueIdLength; 1774 RtlCopyMemory(UniqueId->UniqueId, 1775 (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset), 1776 MountPoint->UniqueIdLength); 1777 1778 /* Query links using it */ 1779 Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL); 1780 FreePool(UniqueId); 1781 } 1782 /* If caller provided a device name */ 1783 else if (MountPoint->DeviceNameLength != 0) 1784 { 1785 if (MountPoint->DeviceNameLength > MAXSHORT) 1786 { 1787 return STATUS_INVALID_PARAMETER; 1788 } 1789 1790 DeviceName.Length = MountPoint->DeviceNameLength; 1791 DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR); 1792 DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength); 1793 if (!DeviceName.Buffer) 1794 { 1795 return STATUS_INSUFFICIENT_RESOURCES; 1796 } 1797 1798 RtlCopyMemory(DeviceName.Buffer, 1799 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->DeviceNameOffset), 1800 DeviceName.Length); 1801 DeviceName.Buffer[DeviceName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1802 1803 /* Query links using it */ 1804 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, &DeviceName); 1805 FreePool(DeviceName.Buffer); 1806 } 1807 else 1808 { 1809 /* Otherwise, query all links */ 1810 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, NULL); 1811 } 1812 1813 return Status; 1814 } 1815 1816 /* 1817 * @implemented 1818 */ 1819 NTSTATUS 1820 MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension, 1821 IN PIRP Irp) 1822 { 1823 ULONG Link; 1824 NTSTATUS Status; 1825 BOOLEAN CreateNoDrive; 1826 PIO_STACK_LOCATION Stack; 1827 PMOUNTDEV_UNIQUE_ID UniqueId; 1828 PMOUNTMGR_MOUNT_POINT MountPoint; 1829 PMOUNTMGR_MOUNT_POINTS MountPoints; 1830 UNICODE_STRING SymbolicName, DeviceName; 1831 1832 Stack = IoGetCurrentIrpStackLocation(Irp); 1833 1834 /* Validate input */ 1835 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT)) 1836 { 1837 return STATUS_INVALID_PARAMETER; 1838 } 1839 1840 /* Query points */ 1841 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer; 1842 CreateNoDrive = (MountPoint->SymbolicLinkNameOffset && MountPoint->SymbolicLinkNameLength); 1843 1844 Status = MountMgrQueryPoints(DeviceExtension, Irp); 1845 if (!NT_SUCCESS(Status)) 1846 { 1847 return Status; 1848 } 1849 1850 /* For all the points matching the request */ 1851 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer; 1852 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++) 1853 { 1854 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength; 1855 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR); 1856 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength); 1857 if (!SymbolicName.Buffer) 1858 { 1859 return STATUS_INSUFFICIENT_RESOURCES; 1860 } 1861 1862 RtlCopyMemory(SymbolicName.Buffer, 1863 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset), 1864 SymbolicName.Length); 1865 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1866 1867 /* Create a no drive entry for the drive letters */ 1868 if (CreateNoDrive && IsDriveLetter(&SymbolicName)) 1869 { 1870 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 1871 if (UniqueId) 1872 { 1873 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength; 1874 RtlCopyMemory(UniqueId->UniqueId, 1875 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset), 1876 MountPoints->MountPoints[Link].UniqueIdLength); 1877 1878 CreateNoDriveLetterEntry(UniqueId); 1879 FreePool(UniqueId); 1880 } 1881 } 1882 1883 /* If there are no link any more, and no need to create a no drive entry */ 1884 if (Link == 0 && !CreateNoDrive) 1885 { 1886 /* Then, delete everything */ 1887 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength); 1888 if (UniqueId) 1889 { 1890 RtlCopyMemory(UniqueId, 1891 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset), 1892 MountPoints->MountPoints[Link].UniqueIdLength); 1893 1894 DeleteNoDriveLetterEntry(UniqueId); 1895 FreePool(UniqueId); 1896 } 1897 } 1898 1899 /* Delete all the information about the mount point */ 1900 GlobalDeleteSymbolicLink(&SymbolicName); 1901 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, FALSE); 1902 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer); 1903 FreePool(SymbolicName.Buffer); 1904 1905 /* Notify the change */ 1906 DeviceName.Length = DeviceName.MaximumLength = 1907 MountPoints->MountPoints[Link].DeviceNameLength; 1908 DeviceName.Buffer = (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].DeviceNameOffset); 1909 MountMgrNotifyNameChange(DeviceExtension, &DeviceName, TRUE); 1910 } 1911 1912 MountMgrNotify(DeviceExtension); 1913 1914 return Status; 1915 } 1916 1917 /* 1918 * @implemented 1919 */ 1920 NTSTATUS 1921 MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension, 1922 IN PIRP Irp) 1923 { 1924 ULONG Link; 1925 NTSTATUS Status; 1926 UNICODE_STRING SymbolicName; 1927 PMOUNTDEV_UNIQUE_ID UniqueId; 1928 PMOUNTMGR_MOUNT_POINTS MountPoints; 1929 1930 /* Query points */ 1931 Status = MountMgrQueryPoints(DeviceExtension, Irp); 1932 if (!NT_SUCCESS(Status)) 1933 { 1934 return Status; 1935 } 1936 1937 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer; 1938 if (MountPoints->NumberOfMountPoints == 0) 1939 { 1940 return Status; 1941 } 1942 1943 /* For all the mount points */ 1944 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++) 1945 { 1946 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength; 1947 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR); 1948 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength); 1949 if (!SymbolicName.Buffer) 1950 { 1951 return STATUS_INSUFFICIENT_RESOURCES; 1952 } 1953 1954 RtlCopyMemory(SymbolicName.Buffer, 1955 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset), 1956 SymbolicName.Length); 1957 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1958 1959 /* If the only mount point is a drive letter, then create a no letter drive entry */ 1960 if (MountPoints->NumberOfMountPoints == 1 && IsDriveLetter(&SymbolicName)) 1961 { 1962 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 1963 if (UniqueId) 1964 { 1965 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength; 1966 RtlCopyMemory(UniqueId->UniqueId, 1967 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset), 1968 MountPoints->MountPoints[Link].UniqueIdLength); 1969 1970 CreateNoDriveLetterEntry(UniqueId); 1971 FreePool(UniqueId); 1972 } 1973 } 1974 1975 /* Simply delete mount point from DB */ 1976 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, TRUE); 1977 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer); 1978 FreePool(SymbolicName.Buffer); 1979 } 1980 1981 return Status; 1982 } 1983 1984 /* 1985 * @implemented 1986 */ 1987 NTSTATUS 1988 MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension, 1989 IN PIRP Irp, 1990 IN NTSTATUS LockStatus, 1991 OUT PUNICODE_STRING SourceDeviceName, 1992 OUT PUNICODE_STRING SourceSymbolicName, 1993 OUT PUNICODE_STRING TargetVolumeName) 1994 { 1995 HANDLE Handle; 1996 NTSTATUS Status; 1997 PFILE_OBJECT FileObject; 1998 PIO_STACK_LOCATION Stack; 1999 ULONG Length, SavedLength; 2000 BOOLEAN FOReferenced = FALSE; 2001 IO_STATUS_BLOCK IoStatusBlock; 2002 OBJECT_ATTRIBUTES ObjectAttributes; 2003 PDEVICE_INFORMATION DeviceInformation; 2004 OBJECT_NAME_INFORMATION ObjectNameInfo; 2005 FILE_FS_DEVICE_INFORMATION FsDeviceInfo; 2006 PFILE_NAME_INFORMATION FileNameInfo = NULL; 2007 PMOUNTMGR_VOLUME_MOUNT_POINT VolumeMountPoint; 2008 POBJECT_NAME_INFORMATION ObjectNameInfoPtr = NULL; 2009 UNICODE_STRING SourceVolumeName, TargetDeviceName; 2010 2011 Stack = IoGetCurrentIrpStackLocation(Irp); 2012 2013 /* Validate input */ 2014 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_VOLUME_MOUNT_POINT)) 2015 { 2016 return STATUS_INVALID_PARAMETER; 2017 } 2018 2019 VolumeMountPoint = (PMOUNTMGR_VOLUME_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer; 2020 2021 if (((ULONG)VolumeMountPoint->SourceVolumeNameLength + VolumeMountPoint->TargetVolumeNameLength) < 2022 Stack->Parameters.DeviceIoControl.InputBufferLength) 2023 { 2024 return STATUS_INVALID_PARAMETER; 2025 } 2026 2027 /* Get source volume name */ 2028 SourceVolumeName.Length = 2029 SourceVolumeName.MaximumLength = VolumeMountPoint->SourceVolumeNameLength; 2030 SourceVolumeName.Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset); 2031 2032 InitializeObjectAttributes(&ObjectAttributes, 2033 &SourceVolumeName, 2034 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 2035 NULL, 2036 NULL); 2037 2038 /* Open it */ 2039 Status = ZwOpenFile(&Handle, 2040 SYNCHRONIZE | FILE_READ_ATTRIBUTES, 2041 &ObjectAttributes, 2042 &IoStatusBlock, 2043 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2044 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT); 2045 if (!NT_SUCCESS(Status)) 2046 { 2047 return Status; 2048 } 2049 2050 TargetDeviceName.Buffer = NULL; 2051 2052 /* Query its attributes */ 2053 Status = ZwQueryVolumeInformationFile(Handle, 2054 &IoStatusBlock, 2055 &FsDeviceInfo, 2056 sizeof(FsDeviceInfo), 2057 FileFsDeviceInformation); 2058 if (!NT_SUCCESS(Status)) 2059 { 2060 goto Cleanup; 2061 } 2062 2063 if (FsDeviceInfo.DeviceType != FILE_DEVICE_DISK && FsDeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK) 2064 { 2065 goto Cleanup; 2066 } 2067 2068 if (FsDeviceInfo.Characteristics != (FILE_REMOTE_DEVICE | FILE_REMOVABLE_MEDIA)) 2069 { 2070 goto Cleanup; 2071 } 2072 2073 /* Reference it */ 2074 Status = ObReferenceObjectByHandle(Handle, 0, *IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL); 2075 if (!NT_SUCCESS(Status)) 2076 { 2077 goto Cleanup; 2078 } 2079 FOReferenced = TRUE; 2080 2081 /* Get file name */ 2082 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION)); 2083 if (!FileNameInfo) 2084 { 2085 Status = STATUS_INSUFFICIENT_RESOURCES; 2086 goto Cleanup; 2087 } 2088 2089 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo, 2090 sizeof(FILE_NAME_INFORMATION), 2091 FileNameInformation); 2092 if (Status == STATUS_BUFFER_OVERFLOW) 2093 { 2094 /* Now we have real length, use it */ 2095 Length = FileNameInfo->FileNameLength; 2096 FreePool(FileNameInfo); 2097 2098 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + Length); 2099 if (!FileNameInfo) 2100 { 2101 Status = STATUS_INSUFFICIENT_RESOURCES; 2102 goto Cleanup; 2103 } 2104 2105 /* Really query file name */ 2106 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo, 2107 sizeof(FILE_NAME_INFORMATION) + Length, 2108 FileNameInformation); 2109 } 2110 2111 if (!NT_SUCCESS(Status)) 2112 { 2113 goto Cleanup; 2114 } 2115 2116 /* Get symbolic name */ 2117 ObjectNameInfoPtr = &ObjectNameInfo; 2118 SavedLength = sizeof(OBJECT_NAME_INFORMATION); 2119 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, sizeof(OBJECT_NAME_INFORMATION), &Length); 2120 if (Status == STATUS_INFO_LENGTH_MISMATCH) 2121 { 2122 /* Once again, with proper size, it works better */ 2123 ObjectNameInfoPtr = AllocatePool(Length); 2124 if (!ObjectNameInfoPtr) 2125 { 2126 Status = STATUS_INSUFFICIENT_RESOURCES; 2127 goto Cleanup; 2128 } 2129 2130 SavedLength = Length; 2131 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, SavedLength, &Length); 2132 } 2133 2134 if (!NT_SUCCESS(Status)) 2135 { 2136 goto Cleanup; 2137 } 2138 2139 /* Now, query the device name */ 2140 Status = QueryDeviceInformation(&ObjectNameInfoPtr->Name, SourceDeviceName, 2141 NULL, NULL, NULL, NULL, NULL, NULL); 2142 if (!NT_SUCCESS(Status)) 2143 { 2144 goto Cleanup; 2145 } 2146 2147 /* For target volume name, use input */ 2148 TargetVolumeName->Length = 2149 TargetVolumeName->MaximumLength = VolumeMountPoint->TargetVolumeNameLength; 2150 TargetVolumeName->Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset); 2151 2152 /* Query its device name */ 2153 Status = QueryDeviceInformation(TargetVolumeName, &TargetDeviceName, 2154 NULL, NULL, NULL, NULL, NULL, NULL); 2155 if (!NT_SUCCESS(Status)) 2156 { 2157 goto Cleanup; 2158 } 2159 2160 /* Return symbolic name */ 2161 SourceSymbolicName->Length = 2162 SourceSymbolicName->MaximumLength = (USHORT)FileNameInfo->FileNameLength; 2163 SourceSymbolicName->Buffer = (PWSTR)FileNameInfo; 2164 /* memmove allows memory overlap */ 2165 RtlMoveMemory(SourceSymbolicName->Buffer, FileNameInfo->FileName, SourceSymbolicName->Length); 2166 FileNameInfo = NULL; 2167 2168 /* Notify the change */ 2169 MountMgrNotify(DeviceExtension); 2170 MountMgrNotifyNameChange(DeviceExtension, &TargetDeviceName, TRUE); 2171 2172 /* If we are locked, sync databases if possible */ 2173 if (NT_SUCCESS(LockStatus)) 2174 { 2175 Status = FindDeviceInfo(DeviceExtension, SourceDeviceName, FALSE, &DeviceInformation); 2176 if (NT_SUCCESS(Status)) 2177 { 2178 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation); 2179 } 2180 else 2181 { 2182 Status = STATUS_PENDING; 2183 } 2184 } 2185 2186 Cleanup: 2187 if (TargetDeviceName.Buffer) 2188 { 2189 FreePool(TargetDeviceName.Buffer); 2190 } 2191 2192 if (ObjectNameInfoPtr && ObjectNameInfoPtr != &ObjectNameInfo) 2193 { 2194 FreePool(ObjectNameInfoPtr); 2195 } 2196 2197 if (FileNameInfo) 2198 { 2199 FreePool(FileNameInfo); 2200 } 2201 2202 if (FOReferenced) 2203 { 2204 ObDereferenceObject(FileObject); 2205 } 2206 2207 return Status; 2208 } 2209 2210 /* 2211 * @implemented 2212 */ 2213 NTSTATUS 2214 MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension, 2215 IN PIRP Irp, 2216 IN NTSTATUS LockStatus) 2217 { 2218 LONG Offset; 2219 BOOLEAN Found; 2220 NTSTATUS Status; 2221 HANDLE RemoteDatabase; 2222 PMOUNTDEV_UNIQUE_ID UniqueId; 2223 PDATABASE_ENTRY DatabaseEntry; 2224 PASSOCIATED_DEVICE_ENTRY AssociatedEntry; 2225 PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation; 2226 UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName; 2227 2228 /* Initialize string */ 2229 LinkTarget.Length = 0; 2230 LinkTarget.MaximumLength = 0xC8; 2231 LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength); 2232 if (LinkTarget.Buffer == NULL) 2233 { 2234 return STATUS_INSUFFICIENT_RESOURCES; 2235 } 2236 2237 /* If the mount point was created, then, it changed! 2238 * Also use it to query some information 2239 */ 2240 Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName); 2241 /* Pending means DB are under synchronization, bail out */ 2242 if (Status == STATUS_PENDING) 2243 { 2244 FreePool(LinkTarget.Buffer); 2245 FreePool(SourceDeviceName.Buffer); 2246 FreePool(SourceSymbolicName.Buffer); 2247 return STATUS_SUCCESS; 2248 } 2249 else if (!NT_SUCCESS(Status)) 2250 { 2251 FreePool(LinkTarget.Buffer); 2252 return Status; 2253 } 2254 2255 /* Query the device information */ 2256 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); 2257 if (!NT_SUCCESS(Status)) 2258 { 2259 /* If it failed, first try to get volume name */ 2260 Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName); 2261 if (!NT_SUCCESS(Status)) 2262 { 2263 /* Then, try to read the symlink */ 2264 Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget); 2265 if (!NT_SUCCESS(Status)) 2266 { 2267 FreePool(LinkTarget.Buffer); 2268 FreePool(SourceDeviceName.Buffer); 2269 FreePool(SourceSymbolicName.Buffer); 2270 return Status; 2271 } 2272 } 2273 else 2274 { 2275 FreePool(VolumeName.Buffer); 2276 } 2277 2278 FreePool(SourceDeviceName.Buffer); 2279 2280 SourceDeviceName.Length = LinkTarget.Length; 2281 SourceDeviceName.MaximumLength = LinkTarget.MaximumLength; 2282 SourceDeviceName.Buffer = LinkTarget.Buffer; 2283 2284 /* Now that we have the correct source, reattempt to query information */ 2285 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); 2286 if (!NT_SUCCESS(Status)) 2287 { 2288 FreePool(SourceDeviceName.Buffer); 2289 FreePool(SourceSymbolicName.Buffer); 2290 return Status; 2291 } 2292 } 2293 2294 FreePool(SourceDeviceName.Buffer); 2295 2296 /* Get information about target device */ 2297 Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation); 2298 if (!NT_SUCCESS(Status)) 2299 { 2300 FreePool(SourceSymbolicName.Buffer); 2301 return Status; 2302 } 2303 2304 /* Notify if not disabled */ 2305 if (!TargetDeviceInformation->SkipNotifications) 2306 { 2307 PostOnlineNotification(DeviceExtension, &TargetDeviceInformation->SymbolicName); 2308 } 2309 2310 /* Open the remote database */ 2311 RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE); 2312 if (RemoteDatabase == 0) 2313 { 2314 FreePool(SourceSymbolicName.Buffer); 2315 return STATUS_INSUFFICIENT_RESOURCES; 2316 } 2317 2318 /* Browse all the entries */ 2319 Offset = 0; 2320 Found = FALSE; 2321 for (;;) 2322 { 2323 DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset); 2324 if (DatabaseEntry == NULL) 2325 { 2326 break; 2327 } 2328 2329 /* Try to find ourselves */ 2330 DbName.MaximumLength = DatabaseEntry->SymbolicNameLength; 2331 DbName.Length = DbName.MaximumLength; 2332 DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset); 2333 if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE)) 2334 { 2335 /* Reference ourselves and update the entry */ 2336 ++DatabaseEntry->EntryReferences; 2337 Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry); 2338 FreePool(DatabaseEntry); 2339 Found = TRUE; 2340 break; 2341 } 2342 2343 Offset += DatabaseEntry->EntrySize; 2344 FreePool(DatabaseEntry); 2345 } 2346 2347 /* We couldn't find ourselves, we'll have to add ourselves */ 2348 if (!Found) 2349 { 2350 ULONG EntrySize; 2351 PUNIQUE_ID_REPLICATE UniqueIdReplicate; 2352 2353 /* Query the device unique ID */ 2354 Status = QueryDeviceInformation(&TargetVolumeName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL); 2355 if (!NT_SUCCESS(Status)) 2356 { 2357 FreePool(SourceSymbolicName.Buffer); 2358 CloseRemoteDatabase(RemoteDatabase); 2359 return Status; 2360 } 2361 2362 /* Allocate a database entry */ 2363 EntrySize = UniqueId->UniqueIdLength + TargetVolumeName.Length + sizeof(DATABASE_ENTRY); 2364 DatabaseEntry = AllocatePool(EntrySize); 2365 if (DatabaseEntry == NULL) 2366 { 2367 FreePool(UniqueId); 2368 FreePool(SourceSymbolicName.Buffer); 2369 CloseRemoteDatabase(RemoteDatabase); 2370 return STATUS_INSUFFICIENT_RESOURCES; 2371 } 2372 2373 /* Fill it in */ 2374 DatabaseEntry->EntrySize = EntrySize; 2375 DatabaseEntry->EntryReferences = 1; 2376 DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY); 2377 DatabaseEntry->SymbolicNameLength = TargetVolumeName.Length; 2378 DatabaseEntry->UniqueIdOffset = TargetVolumeName.Length + sizeof(DATABASE_ENTRY); 2379 DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength; 2380 RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + sizeof(DATABASE_ENTRY)), TargetVolumeName.Buffer, DatabaseEntry->SymbolicNameLength); 2381 RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength); 2382 2383 /* And write it down */ 2384 Status = AddRemoteDatabaseEntry(RemoteDatabase, DatabaseEntry); 2385 FreePool(DatabaseEntry); 2386 if (!NT_SUCCESS(Status)) 2387 { 2388 FreePool(UniqueId); 2389 FreePool(SourceSymbolicName.Buffer); 2390 CloseRemoteDatabase(RemoteDatabase); 2391 return Status; 2392 } 2393 2394 /* And now, allocate an Unique ID item */ 2395 UniqueIdReplicate = AllocatePool(sizeof(UNIQUE_ID_REPLICATE)); 2396 if (UniqueIdReplicate == NULL) 2397 { 2398 FreePool(UniqueId); 2399 FreePool(SourceSymbolicName.Buffer); 2400 CloseRemoteDatabase(RemoteDatabase); 2401 return Status; 2402 } 2403 2404 /* To associate it with the device */ 2405 UniqueIdReplicate->UniqueId = UniqueId; 2406 InsertTailList(&DeviceInformation->ReplicatedUniqueIdsListHead, &UniqueIdReplicate->ReplicatedUniqueIdsListEntry); 2407 } 2408 2409 /* We're done with the remote database */ 2410 CloseRemoteDatabase(RemoteDatabase); 2411 2412 /* Check we were find writing the entry */ 2413 if (!NT_SUCCESS(Status)) 2414 { 2415 FreePool(SourceSymbolicName.Buffer); 2416 return Status; 2417 } 2418 2419 /* This is the end, allocate an associated entry */ 2420 AssociatedEntry = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY)); 2421 if (AssociatedEntry == NULL) 2422 { 2423 FreePool(SourceSymbolicName.Buffer); 2424 return STATUS_INSUFFICIENT_RESOURCES; 2425 } 2426 2427 /* Initialize its source name string */ 2428 AssociatedEntry->String.Length = SourceSymbolicName.Length; 2429 AssociatedEntry->String.MaximumLength = AssociatedEntry->String.Length + sizeof(UNICODE_NULL); 2430 AssociatedEntry->String.Buffer = AllocatePool(AssociatedEntry->String.MaximumLength); 2431 if (AssociatedEntry->String.Buffer == NULL) 2432 { 2433 FreePool(AssociatedEntry); 2434 FreePool(SourceSymbolicName.Buffer); 2435 return STATUS_INSUFFICIENT_RESOURCES; 2436 } 2437 2438 /* Copy data & insert in list */ 2439 RtlCopyMemory(AssociatedEntry->String.Buffer, SourceSymbolicName.Buffer, SourceSymbolicName.Length); 2440 AssociatedEntry->String.Buffer[SourceSymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; 2441 AssociatedEntry->DeviceInformation = DeviceInformation; 2442 InsertTailList(&TargetDeviceInformation->AssociatedDevicesHead, &AssociatedEntry->AssociatedDevicesEntry); 2443 2444 /* We're done! */ 2445 FreePool(SourceSymbolicName.Buffer); 2446 return STATUS_SUCCESS; 2447 } 2448 2449 /* 2450 * @implemented 2451 */ 2452 NTSTATUS 2453 MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension, 2454 IN PIRP Irp, 2455 IN NTSTATUS LockStatus) 2456 { 2457 LONG Offset; 2458 NTSTATUS Status; 2459 PLIST_ENTRY Entry; 2460 HANDLE RemoteDatabase; 2461 PDATABASE_ENTRY DatabaseEntry; 2462 PUNIQUE_ID_REPLICATE UniqueIdReplicate; 2463 PASSOCIATED_DEVICE_ENTRY AssociatedEntry; 2464 PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation; 2465 UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName; 2466 2467 /* Initialize string */ 2468 LinkTarget.Length = 0; 2469 LinkTarget.MaximumLength = 0xC8; 2470 LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength); 2471 if (LinkTarget.Buffer == NULL) 2472 { 2473 return STATUS_INSUFFICIENT_RESOURCES; 2474 } 2475 2476 /* If the mount point was deleted, then, it changed! 2477 * Also use it to query some information 2478 */ 2479 Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName); 2480 /* Pending means DB are under synchronization, bail out */ 2481 if (Status == STATUS_PENDING) 2482 { 2483 FreePool(LinkTarget.Buffer); 2484 FreePool(SourceDeviceName.Buffer); 2485 FreePool(SourceSymbolicName.Buffer); 2486 return STATUS_SUCCESS; 2487 } 2488 else if (!NT_SUCCESS(Status)) 2489 { 2490 FreePool(LinkTarget.Buffer); 2491 return Status; 2492 } 2493 2494 /* Query the device information */ 2495 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); 2496 if (!NT_SUCCESS(Status)) 2497 { 2498 /* If it failed, first try to get volume name */ 2499 Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName); 2500 if (!NT_SUCCESS(Status)) 2501 { 2502 /* Then, try to read the symlink */ 2503 Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget); 2504 if (!NT_SUCCESS(Status)) 2505 { 2506 FreePool(LinkTarget.Buffer); 2507 FreePool(SourceDeviceName.Buffer); 2508 FreePool(SourceSymbolicName.Buffer); 2509 return Status; 2510 } 2511 } 2512 else 2513 { 2514 FreePool(VolumeName.Buffer); 2515 } 2516 2517 FreePool(SourceDeviceName.Buffer); 2518 2519 SourceDeviceName.Length = LinkTarget.Length; 2520 SourceDeviceName.MaximumLength = LinkTarget.MaximumLength; 2521 SourceDeviceName.Buffer = LinkTarget.Buffer; 2522 2523 /* Now that we have the correct source, reattempt to query information */ 2524 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); 2525 if (!NT_SUCCESS(Status)) 2526 { 2527 FreePool(SourceDeviceName.Buffer); 2528 FreePool(SourceSymbolicName.Buffer); 2529 return Status; 2530 } 2531 } 2532 2533 FreePool(SourceDeviceName.Buffer); 2534 2535 /* Get information about target device */ 2536 Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation); 2537 if (!NT_SUCCESS(Status)) 2538 { 2539 FreePool(SourceSymbolicName.Buffer); 2540 return Status; 2541 } 2542 2543 /* Open the remote database */ 2544 RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE); 2545 if (RemoteDatabase == 0) 2546 { 2547 FreePool(SourceSymbolicName.Buffer); 2548 return STATUS_INSUFFICIENT_RESOURCES; 2549 } 2550 2551 /* Browse all the entries */ 2552 Offset = 0; 2553 for (;;) 2554 { 2555 DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset); 2556 if (DatabaseEntry == NULL) 2557 { 2558 /* We didn't find ourselves, that's infortunate! */ 2559 FreePool(SourceSymbolicName.Buffer); 2560 CloseRemoteDatabase(RemoteDatabase); 2561 return STATUS_INVALID_PARAMETER; 2562 } 2563 2564 /* Try to find ourselves */ 2565 DbName.MaximumLength = DatabaseEntry->SymbolicNameLength; 2566 DbName.Length = DbName.MaximumLength; 2567 DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset); 2568 if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE)) 2569 { 2570 break; 2571 } 2572 2573 Offset += DatabaseEntry->EntrySize; 2574 FreePool(DatabaseEntry); 2575 } 2576 2577 /* Dereference ourselves */ 2578 DatabaseEntry->EntryReferences--; 2579 if (DatabaseEntry->EntryReferences == 0) 2580 { 2581 /* If we're still referenced, just update the entry */ 2582 Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry); 2583 } 2584 else 2585 { 2586 /* Otherwise, delete the entry */ 2587 Status = DeleteRemoteDatabaseEntry(RemoteDatabase, Offset); 2588 if (!NT_SUCCESS(Status)) 2589 { 2590 FreePool(DatabaseEntry); 2591 FreePool(SourceSymbolicName.Buffer); 2592 CloseRemoteDatabase(RemoteDatabase); 2593 return Status; 2594 } 2595 2596 /* Also, delete our unique ID replicated record */ 2597 for (Entry = DeviceInformation->ReplicatedUniqueIdsListHead.Flink; 2598 Entry != &DeviceInformation->ReplicatedUniqueIdsListHead; 2599 Entry = Entry->Flink) 2600 { 2601 UniqueIdReplicate = CONTAINING_RECORD(Entry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry); 2602 2603 if (UniqueIdReplicate->UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength && 2604 RtlCompareMemory(UniqueIdReplicate->UniqueId->UniqueId, 2605 (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), 2606 DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength) 2607 { 2608 break; 2609 } 2610 } 2611 2612 /* It has to exist! */ 2613 if (Entry == &DeviceInformation->ReplicatedUniqueIdsListHead) 2614 { 2615 FreePool(DatabaseEntry); 2616 FreePool(SourceSymbolicName.Buffer); 2617 CloseRemoteDatabase(RemoteDatabase); 2618 return STATUS_UNSUCCESSFUL; 2619 } 2620 2621 /* Remove it and free it */ 2622 RemoveEntryList(&UniqueIdReplicate->ReplicatedUniqueIdsListEntry); 2623 FreePool(UniqueIdReplicate->UniqueId); 2624 FreePool(UniqueIdReplicate); 2625 } 2626 2627 /* We're done with the remote database */ 2628 FreePool(DatabaseEntry); 2629 CloseRemoteDatabase(RemoteDatabase); 2630 2631 /* Check write operation succeed */ 2632 if (!NT_SUCCESS(Status)) 2633 { 2634 FreePool(SourceSymbolicName.Buffer); 2635 return Status; 2636 } 2637 2638 /* Try to find our associated device entry */ 2639 for (Entry = TargetDeviceInformation->AssociatedDevicesHead.Flink; 2640 Entry != &TargetDeviceInformation->AssociatedDevicesHead; 2641 Entry = Entry->Flink) 2642 { 2643 AssociatedEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 2644 2645 /* If found, delete it */ 2646 if (AssociatedEntry->DeviceInformation == DeviceInformation && 2647 RtlEqualUnicodeString(&AssociatedEntry->String, &SourceSymbolicName, TRUE)) 2648 { 2649 RemoveEntryList(&AssociatedEntry->AssociatedDevicesEntry); 2650 FreePool(AssociatedEntry->String.Buffer); 2651 FreePool(AssociatedEntry); 2652 break; 2653 } 2654 } 2655 2656 /* We're done! */ 2657 FreePool(SourceSymbolicName.Buffer); 2658 return STATUS_SUCCESS; 2659 } 2660 2661 /* 2662 * @implemented 2663 */ 2664 NTSTATUS 2665 NTAPI 2666 MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject, 2667 IN PIRP Irp) 2668 { 2669 PIO_STACK_LOCATION Stack; 2670 NTSTATUS Status, LockStatus; 2671 PDEVICE_EXTENSION DeviceExtension; 2672 2673 Stack = IoGetCurrentIrpStackLocation(Irp); 2674 DeviceExtension = DeviceObject->DeviceExtension; 2675 2676 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 2677 2678 switch (Stack->Parameters.DeviceIoControl.IoControlCode) 2679 { 2680 case IOCTL_MOUNTMGR_CREATE_POINT: 2681 Status = MountMgrCreatePoint(DeviceExtension, Irp); 2682 break; 2683 2684 case IOCTL_MOUNTMGR_DELETE_POINTS: 2685 Status = MountMgrDeletePoints(DeviceExtension, Irp); 2686 break; 2687 2688 case IOCTL_MOUNTMGR_QUERY_POINTS: 2689 Status = MountMgrQueryPoints(DeviceExtension, Irp); 2690 break; 2691 2692 case IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY: 2693 Status = MountMgrDeletePointsDbOnly(DeviceExtension, Irp); 2694 break; 2695 2696 case IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER: 2697 Status = MountMgrNextDriveLetter(DeviceExtension, Irp); 2698 break; 2699 2700 case IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS: 2701 // NOTE: On Win7+, this is handled during driver re-initialization. 2702 DeviceExtension->AutomaticDriveLetter = TRUE; 2703 MountMgrAssignDriveLetters(DeviceExtension); 2704 ReconcileAllDatabasesWithMaster(DeviceExtension); 2705 WaitForOnlinesToComplete(DeviceExtension); 2706 Status = STATUS_SUCCESS; 2707 break; 2708 2709 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED: 2710 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 2711 2712 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension); 2713 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 2714 Status = MountMgrVolumeMountPointCreated(DeviceExtension, Irp, LockStatus); 2715 if (NT_SUCCESS(LockStatus)) 2716 { 2717 ReleaseRemoteDatabaseSemaphore(DeviceExtension); 2718 } 2719 2720 break; 2721 2722 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED: 2723 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 2724 2725 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension); 2726 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 2727 Status = MountMgrVolumeMountPointDeleted(DeviceExtension, Irp, LockStatus); 2728 if (NT_SUCCESS(LockStatus)) 2729 { 2730 ReleaseRemoteDatabaseSemaphore(DeviceExtension); 2731 } 2732 2733 break; 2734 2735 case IOCTL_MOUNTMGR_CHANGE_NOTIFY: 2736 Status = MountMgrChangeNotify(DeviceExtension, Irp); 2737 break; 2738 2739 case IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE: 2740 Status = MountMgrKeepLinksWhenOffline(DeviceExtension, Irp); 2741 break; 2742 2743 case IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES: 2744 Status = MountMgrCheckUnprocessedVolumes(DeviceExtension, Irp); 2745 goto Complete; 2746 2747 case IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION: 2748 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 2749 Status = MountMgrVolumeArrivalNotification(DeviceExtension, Irp); 2750 goto Complete; 2751 2752 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH: 2753 Status = MountMgrQueryDosVolumePath(DeviceExtension, Irp); 2754 break; 2755 2756 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS: 2757 Status = MountMgrQueryDosVolumePaths(DeviceExtension, Irp); 2758 break; 2759 2760 case IOCTL_MOUNTMGR_SCRUB_REGISTRY: 2761 Status = MountMgrScrubRegistry(DeviceExtension); 2762 break; 2763 2764 case IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT: 2765 Status = MountMgrQueryAutoMount(DeviceExtension, Irp); 2766 break; 2767 2768 case IOCTL_MOUNTMGR_SET_AUTO_MOUNT: 2769 Status = MountMgrSetAutoMount(DeviceExtension, Irp); 2770 break; 2771 2772 default: 2773 Status = STATUS_INVALID_DEVICE_REQUEST; 2774 } 2775 2776 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 2777 2778 if (Status != STATUS_PENDING) 2779 { 2780 goto Complete; 2781 } 2782 2783 return Status; 2784 2785 Complete: 2786 Irp->IoStatus.Status = Status; 2787 IoCompleteRequest(Irp, IO_NO_INCREMENT); 2788 2789 return Status; 2790 } 2791