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 (FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName) + DriveLetterTarget->DeviceNameLength > 641 Stack->Parameters.DeviceIoControl.InputBufferLength) 642 { 643 return STATUS_INVALID_PARAMETER; 644 } 645 646 /* Call the worker */ 647 DeviceName.Buffer = DriveLetterTarget->DeviceName; 648 DeviceName.Length = 649 DeviceName.MaximumLength = DriveLetterTarget->DeviceNameLength; 650 651 Status = MountMgrNextDriveLetterWorker(DeviceExtension, &DeviceName, 652 &DriveLetterInformation); 653 if (NT_SUCCESS(Status)) 654 { 655 *(PMOUNTMGR_DRIVE_LETTER_INFORMATION)Irp->AssociatedIrp.SystemBuffer = 656 DriveLetterInformation; 657 Irp->IoStatus.Information = sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION); 658 } 659 660 return Status; 661 } 662 663 /* 664 * @implemented 665 */ 666 NTSTATUS 667 NTAPI 668 MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName, 669 IN ULONG ValueType, 670 IN PVOID ValueData, 671 IN ULONG ValueLength, 672 IN PVOID Context, 673 IN PVOID EntryContext) 674 { 675 UNICODE_STRING ValueString; 676 PUNICODE_STRING SystemVolumeName; 677 678 UNREFERENCED_PARAMETER(ValueName); 679 UNREFERENCED_PARAMETER(ValueLength); 680 UNREFERENCED_PARAMETER(EntryContext); 681 682 if (ValueType != REG_SZ) 683 { 684 return STATUS_SUCCESS; 685 } 686 687 RtlInitUnicodeString(&ValueString, ValueData); 688 SystemVolumeName = Context; 689 690 /* Return a string containing system volume name */ 691 SystemVolumeName->Length = ValueString.Length; 692 SystemVolumeName->MaximumLength = ValueString.Length + sizeof(WCHAR); 693 SystemVolumeName->Buffer = AllocatePool(SystemVolumeName->MaximumLength); 694 if (SystemVolumeName->Buffer) 695 { 696 RtlCopyMemory(SystemVolumeName->Buffer, ValueData, ValueString.Length); 697 SystemVolumeName->Buffer[ValueString.Length / sizeof(WCHAR)] = UNICODE_NULL; 698 } 699 700 return STATUS_SUCCESS; 701 702 } 703 704 /* 705 * @implemented 706 */ 707 NTSTATUS 708 MountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName) 709 { 710 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 711 712 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 713 QueryTable[0].QueryRoutine = MountMgrQuerySystemVolumeNameQueryRoutine; 714 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; 715 QueryTable[0].Name = L"SystemPartition"; 716 717 SystemVolumeName->Buffer = NULL; 718 719 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 720 L"\\Registry\\Machine\\System\\Setup", 721 QueryTable, 722 SystemVolumeName, 723 NULL); 724 725 if (SystemVolumeName->Buffer) 726 { 727 return STATUS_SUCCESS; 728 } 729 730 return STATUS_UNSUCCESSFUL; 731 } 732 733 /* 734 * @implemented 735 */ 736 VOID 737 MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension) 738 { 739 NTSTATUS Status; 740 PLIST_ENTRY NextEntry; 741 UNICODE_STRING SystemVolumeName; 742 PDEVICE_INFORMATION DeviceInformation; 743 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation; 744 745 /* First, get system volume name */ 746 Status = MountMgrQuerySystemVolumeName(&SystemVolumeName); 747 748 /* If there are no device, it's all done */ 749 if (IsListEmpty(&(DeviceExtension->DeviceListHead))) 750 { 751 if (NT_SUCCESS(Status)) 752 { 753 FreePool(SystemVolumeName.Buffer); 754 } 755 756 return; 757 } 758 759 /* Now, for all the devices... */ 760 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 761 NextEntry != &(DeviceExtension->DeviceListHead); 762 NextEntry = NextEntry->Flink) 763 { 764 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 765 766 /* If the device doesn't have a letter assigned, do it! */ 767 if (!DeviceInformation->LetterAssigned) 768 { 769 MountMgrNextDriveLetterWorker(DeviceExtension, 770 &(DeviceInformation->DeviceName), 771 &DriveLetterInformation); 772 } 773 774 /* If it's the system volume */ 775 if (NT_SUCCESS(Status) && RtlEqualUnicodeString(&SystemVolumeName, &(DeviceInformation->DeviceName), TRUE)) 776 { 777 /* Keep track of it */ 778 DeviceExtension->DriveLetterData = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + 779 sizeof(MOUNTDEV_UNIQUE_ID)); 780 if (DeviceExtension->DriveLetterData) 781 { 782 RtlCopyMemory(DeviceExtension->DriveLetterData, 783 DeviceInformation->UniqueId, 784 DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 785 } 786 787 /* Ensure it gets mounted if automount is disabled */ 788 if (DeviceExtension->NoAutoMount) 789 { 790 /* Temporarily re-enable automount for the 791 * worker to mount and set a drive letter */ 792 DeviceExtension->NoAutoMount = FALSE; 793 794 MountMgrNextDriveLetterWorker(DeviceExtension, 795 &(DeviceInformation->DeviceName), 796 &DriveLetterInformation); 797 798 /* And re-disable automount */ 799 DeviceExtension->NoAutoMount = TRUE; 800 } 801 } 802 } 803 804 if (NT_SUCCESS(Status)) 805 { 806 FreePool(SystemVolumeName.Buffer); 807 } 808 } 809 810 /* 811 * @implemented 812 */ 813 NTSTATUS 814 MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension, 815 IN PIRP Irp) 816 { 817 NTSTATUS Status; 818 ULONG DevicesFound; 819 PIO_STACK_LOCATION Stack; 820 PLIST_ENTRY SymlinksEntry; 821 UNICODE_STRING SymbolicName; 822 PMOUNTMGR_TARGET_NAME Target; 823 PMOUNTMGR_VOLUME_PATHS Output; 824 PWSTR DeviceString, OldBuffer; 825 USHORT DeviceLength, OldLength; 826 PDEVICE_INFORMATION DeviceInformation; 827 PSYMLINK_INFORMATION SymlinkInformation; 828 PASSOCIATED_DEVICE_ENTRY AssociatedDevice; 829 830 Stack = IoGetCurrentIrpStackLocation(Irp); 831 832 /* Validate input size */ 833 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) 834 { 835 return STATUS_INVALID_PARAMETER; 836 } 837 838 /* Ensure we have received UNICODE_STRING */ 839 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; 840 if (Target->DeviceNameLength & 1) 841 { 842 return STATUS_INVALID_PARAMETER; 843 } 844 845 /* Validate the entry structure size */ 846 if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength > 847 Stack->Parameters.DeviceIoControl.InputBufferLength) 848 { 849 return STATUS_INVALID_PARAMETER; 850 } 851 852 /* Ensure we can at least return needed size */ 853 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz)) 854 { 855 return STATUS_INVALID_PARAMETER; 856 } 857 858 /* Construct string for query */ 859 SymbolicName.Length = 860 SymbolicName.MaximumLength = Target->DeviceNameLength; 861 SymbolicName.Buffer = Target->DeviceName; 862 863 /* Find device with our info */ 864 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation); 865 if (!NT_SUCCESS(Status)) 866 { 867 return Status; 868 } 869 870 DeviceLength = 0; 871 DeviceString = NULL; 872 DevicesFound = 0; 873 874 /* Try to find associated device info */ 875 while (TRUE) 876 { 877 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink; 878 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead); 879 SymlinksEntry = SymlinksEntry->Flink) 880 { 881 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 882 883 /* Try to find with drive letter */ 884 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online) 885 { 886 break; 887 } 888 } 889 890 /* If we've found a device via drive letter, do default processing */ 891 if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead)) 892 break; 893 894 /* If it doesn't have an associated device, go to fallback method */ 895 if (IsListEmpty(&DeviceInformation->AssociatedDevicesHead)) 896 goto TryWithVolumeName; 897 898 /* Create a string with the information about the device */ 899 AssociatedDevice = CONTAINING_RECORD(&(DeviceInformation->AssociatedDevicesHead), ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 900 OldLength = DeviceLength; 901 OldBuffer = DeviceString; 902 DeviceLength += AssociatedDevice->String.Length; 903 DeviceString = AllocatePool(DeviceLength); 904 if (!DeviceString) 905 { 906 if (OldBuffer) 907 { 908 FreePool(OldBuffer); 909 } 910 911 return STATUS_INSUFFICIENT_RESOURCES; 912 } 913 914 /* Store our info and previous if any */ 915 RtlCopyMemory(DeviceString, AssociatedDevice->String.Buffer, AssociatedDevice->String.Length); 916 if (OldBuffer) 917 { 918 RtlCopyMemory(&DeviceString[AssociatedDevice->String.Length / sizeof(WCHAR)], OldBuffer, OldLength); 919 FreePool(OldBuffer); 920 } 921 922 /* Count and continue looking */ 923 ++DevicesFound; 924 DeviceInformation = AssociatedDevice->DeviceInformation; 925 926 /* If too many devices, try another way */ 927 if (DevicesFound > MAX_DEVICES) /* 1000 */ 928 { 929 goto TryWithVolumeName; 930 } 931 } 932 933 /* Reallocate our string, so that we can prepend disk letter */ 934 OldBuffer = DeviceString; 935 OldLength = DeviceLength; 936 DeviceLength += 2 * sizeof(WCHAR); 937 DeviceString = AllocatePool(DeviceLength); 938 if (!DeviceString) 939 { 940 if (OldBuffer) 941 { 942 FreePool(OldBuffer); 943 } 944 945 return STATUS_INSUFFICIENT_RESOURCES; 946 } 947 948 /* Get the letter */ 949 DeviceString[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION]; 950 DeviceString[1] = L':'; 951 952 /* And copy the rest */ 953 if (OldBuffer) 954 { 955 RtlCopyMemory(&DeviceString[2], OldBuffer, OldLength); 956 FreePool(OldBuffer); 957 } 958 959 TryWithVolumeName: 960 /* If we didn't find anything, try differently */ 961 if (DeviceLength < 2 * sizeof(WCHAR) || DeviceString[1] != L':') 962 { 963 if (DeviceString) 964 { 965 FreePool(DeviceString); 966 DeviceString = NULL; 967 DeviceLength = 0; 968 } 969 970 /* Try to find a volume name matching */ 971 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink; 972 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead); 973 SymlinksEntry = SymlinksEntry->Flink) 974 { 975 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 976 977 if (MOUNTMGR_IS_VOLUME_NAME(&SymlinkInformation->Name)) 978 { 979 break; 980 } 981 } 982 983 /* If found copy */ 984 if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead)) 985 { 986 DeviceLength = SymlinkInformation->Name.Length; 987 DeviceString = AllocatePool(DeviceLength); 988 if (!DeviceString) 989 { 990 return STATUS_INSUFFICIENT_RESOURCES; 991 } 992 993 RtlCopyMemory(DeviceString, SymlinkInformation->Name.Buffer, DeviceLength); 994 /* Ensure we are in the Win32 namespace; [1] can be '?' */ 995 DeviceString[1] = L'\\'; 996 } 997 } 998 999 /* If we didn't find something, fail */ 1000 if (!DeviceString) 1001 return STATUS_NOT_FOUND; 1002 1003 /* Get the output buffer */ 1004 Output = (PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer; 1005 1006 /* At least, we will return our length */ 1007 Output->MultiSzLength = DeviceLength + 2 * sizeof(UNICODE_NULL); 1008 Irp->IoStatus.Information = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz) + Output->MultiSzLength; 1009 1010 /* If we have enough room for copying the string */ 1011 if (Irp->IoStatus.Information <= Stack->Parameters.DeviceIoControl.OutputBufferLength) 1012 { 1013 /* Copy it */ 1014 if (DeviceLength) 1015 { 1016 RtlCopyMemory(Output->MultiSz, DeviceString, DeviceLength); 1017 } 1018 1019 /* And double-NUL at its end - this is needed in case of 1020 * multiple paths which are separated by a single NUL */ 1021 FreePool(DeviceString); 1022 Output->MultiSz[DeviceLength / sizeof(WCHAR)] = UNICODE_NULL; 1023 Output->MultiSz[DeviceLength / sizeof(WCHAR) + 1] = UNICODE_NULL; 1024 1025 return STATUS_SUCCESS; 1026 } 1027 else 1028 { 1029 /* Just return the size needed and leave */ 1030 FreePool(DeviceString); 1031 Irp->IoStatus.Information = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz); 1032 return STATUS_BUFFER_OVERFLOW; 1033 } 1034 } 1035 1036 /* 1037 * @implemented 1038 */ 1039 NTSTATUS 1040 MountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry, 1041 IN PDEVICE_INFORMATION DeviceInformation, 1042 OUT PBOOLEAN Invalid) 1043 { 1044 HANDLE Handle; 1045 NTSTATUS Status; 1046 PLIST_ENTRY SymlinksEntry; 1047 IO_STATUS_BLOCK IoStatusBlock; 1048 PREPARSE_DATA_BUFFER ReparseData; 1049 OBJECT_ATTRIBUTES ObjectAttributes; 1050 UNICODE_STRING FullName, SubstituteName; 1051 PSYMLINK_INFORMATION SymlinkInformation; 1052 1053 /* Initialize & allocate a string big enough to contain our complete mount point name */ 1054 FullName.Length = 0; 1055 FullName.MaximumLength = AssociatedDeviceEntry->String.Length 1056 + AssociatedDeviceEntry->DeviceInformation->DeviceName.Length 1057 + sizeof(WCHAR) 1058 + sizeof(UNICODE_NULL); 1059 FullName.Buffer = AllocatePool(FullName.MaximumLength); 1060 if (!FullName.Buffer) 1061 { 1062 return STATUS_INSUFFICIENT_RESOURCES; 1063 } 1064 1065 /* Create the path */ 1066 RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->DeviceInformation->DeviceName); 1067 FullName.Buffer[FullName.Length / sizeof(WCHAR)] = L'\\'; 1068 RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->String); 1069 FullName.Buffer[FullName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1070 1071 /* Open it to query the reparse point */ 1072 InitializeObjectAttributes(&ObjectAttributes, 1073 &FullName, 1074 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1075 NULL, 1076 NULL); 1077 Status = ZwOpenFile(&Handle, 1078 SYNCHRONIZE | FILE_READ_ATTRIBUTES, 1079 &ObjectAttributes, &IoStatusBlock, 1080 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1081 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT); 1082 FreePool(FullName.Buffer); 1083 1084 if (!NT_SUCCESS(Status)) 1085 { 1086 *Invalid = TRUE; 1087 return STATUS_SUCCESS; 1088 } 1089 1090 /* Allocate a buffer big enough to read reparse data */ 1091 ReparseData = AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 1092 if (ReparseData == NULL) 1093 { 1094 ZwClose(Handle); 1095 return STATUS_INSUFFICIENT_RESOURCES; 1096 } 1097 1098 /* Query reparse data */ 1099 Status = ZwFsControlFile(Handle, 1100 NULL, NULL, NULL, 1101 &IoStatusBlock, 1102 FSCTL_GET_REPARSE_POINT, 1103 NULL, 0, 1104 ReparseData, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 1105 ZwClose(Handle); 1106 1107 if (!NT_SUCCESS(Status)) 1108 { 1109 FreePool(ReparseData); 1110 *Invalid = TRUE; 1111 return STATUS_SUCCESS; 1112 } 1113 1114 /* Create a string with the substitute name */ 1115 SubstituteName.Length = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength; 1116 SubstituteName.MaximumLength = SubstituteName.Length; 1117 SubstituteName.Buffer = (PWSTR)((ULONG_PTR)ReparseData->SymbolicLinkReparseBuffer.PathBuffer + ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset); 1118 1119 /* If that's a volume name that matches our associated device, that's a success! */ 1120 if (MOUNTMGR_IS_VOLUME_NAME(&SubstituteName)) 1121 { 1122 if (SubstituteName.Length == 98 && SubstituteName.Buffer[1] == L'?') 1123 { 1124 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink; 1125 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead); 1126 SymlinksEntry = SymlinksEntry->Flink) 1127 { 1128 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 1129 1130 if (RtlEqualUnicodeString(&SubstituteName, &SymlinkInformation->Name, TRUE)) 1131 { 1132 FreePool(ReparseData); 1133 return STATUS_SUCCESS; 1134 } 1135 } 1136 } 1137 } 1138 1139 FreePool(ReparseData); 1140 *Invalid = TRUE; 1141 return STATUS_SUCCESS; 1142 } 1143 1144 /* 1145 * @implemented 1146 */ 1147 NTSTATUS 1148 MountMgrQueryVolumePaths(IN PDEVICE_EXTENSION DeviceExtension, 1149 IN PDEVICE_INFORMATION DeviceInformation, 1150 IN PLIST_ENTRY DeviceInfoList, 1151 OUT PMOUNTMGR_VOLUME_PATHS * VolumePaths, 1152 OUT PDEVICE_INFORMATION *FailedDevice) 1153 { 1154 ULONG Written; 1155 NTSTATUS Status; 1156 PLIST_ENTRY Entry; 1157 PSYMLINK_INFORMATION SymlinkInformation; 1158 PDEVICE_INFORMATION_ENTRY DeviceInfoEntry; 1159 PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry; 1160 PMOUNTMGR_VOLUME_PATHS * Paths = NULL, * CurrentPath; 1161 ULONG OutputPathLength, NumberOfPaths, ReturnedPaths; 1162 1163 /* We return at least null char */ 1164 OutputPathLength = sizeof(UNICODE_NULL); 1165 1166 for (Entry = DeviceInformation->SymbolicLinksListHead.Flink; 1167 Entry != &(DeviceInformation->SymbolicLinksListHead); 1168 Entry = Entry->Flink) 1169 { 1170 SymlinkInformation = CONTAINING_RECORD(Entry, SYMLINK_INFORMATION, SymbolicLinksListEntry); 1171 1172 /* Try to find the drive letter (ie, DOS device) */ 1173 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online) 1174 { 1175 /* We'll return the letter */ 1176 OutputPathLength = 4 * sizeof(WCHAR); 1177 break; 1178 } 1179 } 1180 1181 /* We didn't find any */ 1182 if (Entry == &(DeviceInformation->SymbolicLinksListHead)) 1183 { 1184 SymlinkInformation = NULL; 1185 } 1186 1187 /* Do we have any device info to return? */ 1188 for (Entry = DeviceInfoList->Flink; Entry != DeviceInfoList; Entry = Entry->Flink) 1189 { 1190 DeviceInfoEntry = CONTAINING_RECORD(Entry, DEVICE_INFORMATION_ENTRY, DeviceInformationEntry); 1191 1192 /* Matching current device */ 1193 if (DeviceInfoEntry->DeviceInformation == DeviceInformation) 1194 { 1195 /* Allocate the output buffer */ 1196 *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength); 1197 if (*VolumePaths == NULL) 1198 { 1199 return STATUS_INSUFFICIENT_RESOURCES; 1200 } 1201 1202 /* Set size */ 1203 (*VolumePaths)->MultiSzLength = OutputPathLength; 1204 /* If we have a drive letter, return it */ 1205 if (SymlinkInformation != NULL) 1206 { 1207 (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION]; 1208 (*VolumePaths)->MultiSz[1] = L':'; 1209 (*VolumePaths)->MultiSz[2] = UNICODE_NULL; 1210 (*VolumePaths)->MultiSz[3] = UNICODE_NULL; 1211 } 1212 else 1213 { 1214 (*VolumePaths)->MultiSz[0] = UNICODE_NULL; 1215 } 1216 1217 return STATUS_SUCCESS; 1218 } 1219 } 1220 1221 /* Allocate a new device entry */ 1222 DeviceInfoEntry = AllocatePool(sizeof(DEVICE_INFORMATION_ENTRY)); 1223 if (DeviceInfoEntry == NULL) 1224 { 1225 return STATUS_INSUFFICIENT_RESOURCES; 1226 } 1227 1228 /* Add it to the list */ 1229 DeviceInfoEntry->DeviceInformation = DeviceInformation; 1230 InsertTailList(DeviceInfoList, &DeviceInfoEntry->DeviceInformationEntry); 1231 1232 NumberOfPaths = 0; 1233 /* Count the amount of devices we will have to handle */ 1234 if (!IsListEmpty(&DeviceInformation->AssociatedDevicesHead)) 1235 { 1236 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink; 1237 Entry != &DeviceInformation->AssociatedDevicesHead; 1238 Entry = Entry->Flink) 1239 { 1240 ++NumberOfPaths; 1241 } 1242 1243 ASSERT(NumberOfPaths != 0); 1244 /* And allocate a big enough buffer */ 1245 Paths = AllocatePool(NumberOfPaths * sizeof(PMOUNTMGR_VOLUME_PATHS)); 1246 if (Paths == NULL) 1247 { 1248 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1249 FreePool(DeviceInfoEntry); 1250 return STATUS_INSUFFICIENT_RESOURCES; 1251 } 1252 } 1253 1254 /* Start the hot loop to gather all the paths and be able to compute total output length! */ 1255 ReturnedPaths = 0; 1256 CurrentPath = Paths; 1257 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink; 1258 Entry != &DeviceInformation->AssociatedDevicesHead; 1259 Entry = Entry->Flink) 1260 { 1261 USHORT InnerStrings; 1262 BOOLEAN Invalid = FALSE; 1263 1264 AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 1265 1266 /* Validate the fact its a mount point by query reparse data */ 1267 Status = MountMgrValidateBackPointer(AssociatedDeviceEntry, DeviceInformation, &Invalid); 1268 1269 /* If we found an invalid device, that's a failure */ 1270 if (Invalid) 1271 { 1272 *FailedDevice = AssociatedDeviceEntry->DeviceInformation; 1273 Status = STATUS_UNSUCCESSFUL; 1274 } 1275 1276 /* Check whether we failed, if so, bail out */ 1277 if (!NT_SUCCESS(Status)) 1278 { 1279 ULONG i; 1280 1281 for (i = 0; i < ReturnedPaths; ++i) 1282 { 1283 FreePool(Paths[i]); 1284 } 1285 1286 if (Paths != NULL) 1287 { 1288 FreePool(Paths); 1289 } 1290 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1291 FreePool(DeviceInfoEntry); 1292 return Status; 1293 } 1294 1295 /* Query associated paths (hello ourselves :-)) */ 1296 Status = MountMgrQueryVolumePaths(DeviceExtension, 1297 AssociatedDeviceEntry->DeviceInformation, 1298 DeviceInfoList, 1299 CurrentPath, 1300 FailedDevice); 1301 if (!NT_SUCCESS(Status)) 1302 { 1303 ULONG i; 1304 1305 for (i = 0; i < ReturnedPaths; ++i) 1306 { 1307 FreePool(Paths[i]); 1308 } 1309 1310 if (Paths != NULL) 1311 { 1312 FreePool(Paths); 1313 } 1314 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1315 FreePool(DeviceInfoEntry); 1316 return Status; 1317 } 1318 1319 /* Count the number of strings we have in the multi string buffer */ 1320 InnerStrings = 0; 1321 if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL)) 1322 { 1323 ULONG i; 1324 PWSTR MultiSz = (*CurrentPath)->MultiSz; 1325 1326 for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR); ++i, ++MultiSz) 1327 { 1328 if (*MultiSz == UNICODE_NULL) 1329 { 1330 ++InnerStrings; 1331 } 1332 } 1333 } 1334 1335 /* We returned one more path (ie, one more allocated buffer) */ 1336 ++ReturnedPaths; 1337 /* Move the next pointer to use in the array */ 1338 ++CurrentPath; 1339 /* Multiply String.Length by the number of found paths, we always add it after a path */ 1340 OutputPathLength += (*CurrentPath)->MultiSzLength + InnerStrings * AssociatedDeviceEntry->String.Length - sizeof(UNICODE_NULL); 1341 } 1342 1343 /* Allocate the output buffer */ 1344 *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength); 1345 if (*VolumePaths == NULL) 1346 { 1347 ULONG i; 1348 1349 for (i = 0; i < ReturnedPaths; ++i) 1350 { 1351 FreePool(Paths[i]); 1352 } 1353 1354 if (Paths != NULL) 1355 { 1356 FreePool(Paths); 1357 } 1358 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1359 FreePool(DeviceInfoEntry); 1360 return STATUS_INSUFFICIENT_RESOURCES; 1361 } 1362 1363 Written = 0; 1364 /* If we had found a DOS letter, that's the first thing we return */ 1365 (*VolumePaths)->MultiSzLength = OutputPathLength; 1366 if (SymlinkInformation != NULL) 1367 { 1368 (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION]; 1369 (*VolumePaths)->MultiSz[1] = L':'; 1370 (*VolumePaths)->MultiSz[2] = UNICODE_NULL; 1371 Written = 3; 1372 } 1373 1374 /* Now, browse again all our paths to return them */ 1375 CurrentPath = Paths; 1376 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink; 1377 Entry != &DeviceInformation->AssociatedDevicesHead; 1378 Entry = Entry->Flink) 1379 { 1380 AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 1381 1382 /* If we had a path... */ 1383 if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL)) 1384 { 1385 ULONG i, Offset; 1386 PWSTR MultiSz; 1387 1388 /* This offset is used to "jump" into MultiSz, so, start with the string begin (ie, skip MultiSzLength) */ 1389 Offset = sizeof(ULONG); 1390 /* Browse every single letter, and skip last UNICODE_NULL */ 1391 for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR) - 1; ++i) 1392 { 1393 /* Get the letter */ 1394 MultiSz = (PWSTR)((ULONG_PTR)(*CurrentPath) + Offset); 1395 /* If it was part of the path, just return it */ 1396 if (*MultiSz != UNICODE_NULL) 1397 { 1398 (*VolumePaths)->MultiSz[Written] = *MultiSz; 1399 } 1400 else 1401 { 1402 /* Otherwise, as planed, return our whole associated device name */ 1403 RtlCopyMemory(&(*VolumePaths)->MultiSz[Written], 1404 AssociatedDeviceEntry->String.Buffer, 1405 AssociatedDeviceEntry->String.Length); 1406 Written += AssociatedDeviceEntry->String.Length / sizeof(WCHAR); 1407 /* And don't forget to nullify */ 1408 (*VolumePaths)->MultiSz[Written] = UNICODE_NULL; 1409 } 1410 1411 /* We at least return a letter or a null char */ 1412 ++Written; 1413 /* Move to the next letter */ 1414 Offset += sizeof(WCHAR); 1415 } 1416 } 1417 1418 FreePool(*CurrentPath); 1419 ++CurrentPath; 1420 } 1421 1422 /* MultiSz: don't forget last null char */ 1423 (*VolumePaths)->MultiSz[Written] = UNICODE_NULL; 1424 /* Cleanup everything and return success! */ 1425 if (Paths != NULL) 1426 { 1427 FreePool(Paths); 1428 } 1429 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); 1430 FreePool(DeviceInfoEntry); 1431 return STATUS_SUCCESS; 1432 } 1433 1434 /* 1435 * @implemented 1436 */ 1437 NTSTATUS 1438 MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension, 1439 IN PIRP Irp) 1440 { 1441 NTSTATUS Status; 1442 PLIST_ENTRY Entry; 1443 LIST_ENTRY Devices; 1444 BOOLEAN NeedNotification; 1445 PIO_STACK_LOCATION Stack; 1446 UNICODE_STRING SymbolicName; 1447 ULONG Attempts, OutputLength; 1448 PMOUNTMGR_TARGET_NAME Target; 1449 PMOUNTMGR_VOLUME_PATHS Paths, Output; 1450 RECONCILE_WORK_ITEM_CONTEXT ReconcileContext; 1451 PDEVICE_INFORMATION DeviceInformation, ListDeviceInfo, FailedDevice; 1452 1453 Stack = IoGetCurrentIrpStackLocation(Irp); 1454 1455 /* Validate input size */ 1456 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) 1457 { 1458 return STATUS_INVALID_PARAMETER; 1459 } 1460 1461 /* Ensure we have received UNICODE_STRING */ 1462 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; 1463 if (Target->DeviceNameLength & 1) 1464 { 1465 return STATUS_INVALID_PARAMETER; 1466 } 1467 1468 /* Validate the entry structure size */ 1469 if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength > 1470 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 < FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz)) 1477 { 1478 return STATUS_INVALID_PARAMETER; 1479 } 1480 1481 /* Construct string for query */ 1482 SymbolicName.Length = 1483 SymbolicName.MaximumLength = Target->DeviceNameLength; 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 the 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 = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz) + Output->MultiSzLength; 1568 1569 /* If it cannot fit, just return the size needed and leave */ 1570 if (OutputLength > Stack->Parameters.DeviceIoControl.OutputBufferLength) 1571 { 1572 Irp->IoStatus.Information = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz); 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 (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength > 1607 Stack->Parameters.DeviceIoControl.InputBufferLength) 1608 { 1609 return STATUS_INVALID_PARAMETER; 1610 } 1611 1612 SymbolicName.Length = 1613 SymbolicName.MaximumLength = Target->DeviceNameLength; 1614 SymbolicName.Buffer = Target->DeviceName; 1615 1616 /* Find the associated device */ 1617 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation); 1618 if (!NT_SUCCESS(Status)) 1619 { 1620 return Status; 1621 } 1622 1623 /* Mark we want to keep links */ 1624 DeviceInformation->KeepLinks = TRUE; 1625 1626 return STATUS_SUCCESS; 1627 } 1628 1629 /* 1630 * @implemented 1631 */ 1632 NTSTATUS 1633 MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension, 1634 IN PIRP Irp) 1635 { 1636 NTSTATUS Status; 1637 BOOLEAN OldState; 1638 PIO_STACK_LOCATION Stack; 1639 UNICODE_STRING SymbolicName; 1640 PMOUNTMGR_TARGET_NAME Target; 1641 1642 Stack = IoGetCurrentIrpStackLocation(Irp); 1643 1644 /* Validate input */ 1645 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) 1646 { 1647 return STATUS_INVALID_PARAMETER; 1648 } 1649 1650 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; 1651 if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength > 1652 Stack->Parameters.DeviceIoControl.InputBufferLength) 1653 { 1654 return STATUS_INVALID_PARAMETER; 1655 } 1656 1657 SymbolicName.Length = 1658 SymbolicName.MaximumLength = Target->DeviceNameLength; 1659 SymbolicName.Buffer = Target->DeviceName; 1660 1661 /* Disable hard errors */ 1662 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread()); 1663 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE); 1664 1665 /* Call real worker */ 1666 Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE); 1667 1668 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState); 1669 1670 return Status; 1671 } 1672 1673 /* 1674 * @implemented 1675 */ 1676 NTSTATUS 1677 MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension, 1678 IN PIRP Irp) 1679 { 1680 NTSTATUS Status; 1681 PIO_STACK_LOCATION Stack; 1682 PMOUNTDEV_UNIQUE_ID UniqueId; 1683 PMOUNTMGR_MOUNT_POINT MountPoint; 1684 UNICODE_STRING SymbolicName, DeviceName; 1685 1686 Stack = IoGetCurrentIrpStackLocation(Irp); 1687 1688 /* Validate input... */ 1689 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT)) 1690 { 1691 return STATUS_INVALID_PARAMETER; 1692 } 1693 1694 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer; 1695 if (!MountPoint->SymbolicLinkNameLength) 1696 { 1697 MountPoint->SymbolicLinkNameOffset = 0; 1698 } 1699 1700 if (!MountPoint->UniqueIdLength) 1701 { 1702 MountPoint->UniqueIdOffset = 0; 1703 } 1704 1705 if (!MountPoint->DeviceNameLength) 1706 { 1707 MountPoint->DeviceNameOffset = 0; 1708 } 1709 1710 /* Addresses can't be odd */ 1711 if ((MountPoint->SymbolicLinkNameOffset & 1) || 1712 (MountPoint->SymbolicLinkNameLength & 1)) 1713 { 1714 return STATUS_INVALID_PARAMETER; 1715 } 1716 1717 if ((MountPoint->UniqueIdOffset & 1) || 1718 (MountPoint->UniqueIdLength & 1)) 1719 { 1720 return STATUS_INVALID_PARAMETER; 1721 } 1722 1723 if ((MountPoint->DeviceNameOffset & 1) || 1724 (MountPoint->DeviceNameLength & 1)) 1725 { 1726 return STATUS_INVALID_PARAMETER; 1727 } 1728 1729 /* We can't go beyond */ 1730 if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength + 1731 MountPoint->DeviceNameLength) > Stack->Parameters.DeviceIoControl.InputBufferLength) 1732 { 1733 return STATUS_INVALID_PARAMETER; 1734 } 1735 1736 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS)) 1737 { 1738 return STATUS_INVALID_PARAMETER; 1739 } 1740 1741 /* If caller provided a Symlink, use it */ 1742 if (MountPoint->SymbolicLinkNameLength != 0) 1743 { 1744 if (MountPoint->SymbolicLinkNameLength > MAXSHORT) 1745 { 1746 return STATUS_INVALID_PARAMETER; 1747 } 1748 1749 SymbolicName.Length = MountPoint->SymbolicLinkNameLength; 1750 SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR); 1751 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength); 1752 if (!SymbolicName.Buffer) 1753 { 1754 return STATUS_INSUFFICIENT_RESOURCES; 1755 } 1756 1757 RtlCopyMemory(SymbolicName.Buffer, 1758 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset), 1759 SymbolicName.Length); 1760 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1761 1762 /* Query links using it */ 1763 Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp); 1764 FreePool(SymbolicName.Buffer); 1765 } 1766 /* If user provided an unique ID */ 1767 else if (MountPoint->UniqueIdLength != 0) 1768 { 1769 UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 1770 if (!UniqueId) 1771 { 1772 return STATUS_INSUFFICIENT_RESOURCES; 1773 } 1774 1775 UniqueId->UniqueIdLength = MountPoint->UniqueIdLength; 1776 RtlCopyMemory(UniqueId->UniqueId, 1777 (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset), 1778 MountPoint->UniqueIdLength); 1779 1780 /* Query links using it */ 1781 Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL); 1782 FreePool(UniqueId); 1783 } 1784 /* If caller provided a device name */ 1785 else if (MountPoint->DeviceNameLength != 0) 1786 { 1787 if (MountPoint->DeviceNameLength > MAXSHORT) 1788 { 1789 return STATUS_INVALID_PARAMETER; 1790 } 1791 1792 DeviceName.Length = MountPoint->DeviceNameLength; 1793 DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR); 1794 DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength); 1795 if (!DeviceName.Buffer) 1796 { 1797 return STATUS_INSUFFICIENT_RESOURCES; 1798 } 1799 1800 RtlCopyMemory(DeviceName.Buffer, 1801 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->DeviceNameOffset), 1802 DeviceName.Length); 1803 DeviceName.Buffer[DeviceName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1804 1805 /* Query links using it */ 1806 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, &DeviceName); 1807 FreePool(DeviceName.Buffer); 1808 } 1809 else 1810 { 1811 /* Otherwise, query all links */ 1812 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, NULL); 1813 } 1814 1815 return Status; 1816 } 1817 1818 /* 1819 * @implemented 1820 */ 1821 NTSTATUS 1822 MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension, 1823 IN PIRP Irp) 1824 { 1825 ULONG Link; 1826 NTSTATUS Status; 1827 BOOLEAN CreateNoDrive; 1828 PIO_STACK_LOCATION Stack; 1829 PMOUNTDEV_UNIQUE_ID UniqueId; 1830 PMOUNTMGR_MOUNT_POINT MountPoint; 1831 PMOUNTMGR_MOUNT_POINTS MountPoints; 1832 UNICODE_STRING SymbolicName, DeviceName; 1833 1834 Stack = IoGetCurrentIrpStackLocation(Irp); 1835 1836 /* Validate input */ 1837 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT)) 1838 { 1839 return STATUS_INVALID_PARAMETER; 1840 } 1841 1842 /* Query points */ 1843 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer; 1844 CreateNoDrive = (MountPoint->SymbolicLinkNameOffset && MountPoint->SymbolicLinkNameLength); 1845 1846 Status = MountMgrQueryPoints(DeviceExtension, Irp); 1847 if (!NT_SUCCESS(Status)) 1848 { 1849 return Status; 1850 } 1851 1852 /* For all the points matching the request */ 1853 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer; 1854 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++) 1855 { 1856 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength; 1857 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR); 1858 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength); 1859 if (!SymbolicName.Buffer) 1860 { 1861 return STATUS_INSUFFICIENT_RESOURCES; 1862 } 1863 1864 RtlCopyMemory(SymbolicName.Buffer, 1865 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset), 1866 SymbolicName.Length); 1867 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1868 1869 /* Create a no drive entry for the drive letters */ 1870 if (CreateNoDrive && IsDriveLetter(&SymbolicName)) 1871 { 1872 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 1873 if (UniqueId) 1874 { 1875 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength; 1876 RtlCopyMemory(UniqueId->UniqueId, 1877 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset), 1878 MountPoints->MountPoints[Link].UniqueIdLength); 1879 1880 CreateNoDriveLetterEntry(UniqueId); 1881 FreePool(UniqueId); 1882 } 1883 } 1884 1885 /* If there are no link any more, and no need to create a no drive entry */ 1886 if (Link == 0 && !CreateNoDrive) 1887 { 1888 /* Then, delete everything */ 1889 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength); 1890 if (UniqueId) 1891 { 1892 RtlCopyMemory(UniqueId, 1893 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset), 1894 MountPoints->MountPoints[Link].UniqueIdLength); 1895 1896 DeleteNoDriveLetterEntry(UniqueId); 1897 FreePool(UniqueId); 1898 } 1899 } 1900 1901 /* Delete all the information about the mount point */ 1902 GlobalDeleteSymbolicLink(&SymbolicName); 1903 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, FALSE); 1904 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer); 1905 FreePool(SymbolicName.Buffer); 1906 1907 /* Notify the change */ 1908 DeviceName.Length = DeviceName.MaximumLength = 1909 MountPoints->MountPoints[Link].DeviceNameLength; 1910 DeviceName.Buffer = (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].DeviceNameOffset); 1911 MountMgrNotifyNameChange(DeviceExtension, &DeviceName, TRUE); 1912 } 1913 1914 MountMgrNotify(DeviceExtension); 1915 1916 return Status; 1917 } 1918 1919 /* 1920 * @implemented 1921 */ 1922 NTSTATUS 1923 MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension, 1924 IN PIRP Irp) 1925 { 1926 ULONG Link; 1927 NTSTATUS Status; 1928 UNICODE_STRING SymbolicName; 1929 PMOUNTDEV_UNIQUE_ID UniqueId; 1930 PMOUNTMGR_MOUNT_POINTS MountPoints; 1931 1932 /* Query points */ 1933 Status = MountMgrQueryPoints(DeviceExtension, Irp); 1934 if (!NT_SUCCESS(Status)) 1935 { 1936 return Status; 1937 } 1938 1939 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer; 1940 if (MountPoints->NumberOfMountPoints == 0) 1941 { 1942 return Status; 1943 } 1944 1945 /* For all the mount points */ 1946 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++) 1947 { 1948 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength; 1949 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR); 1950 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength); 1951 if (!SymbolicName.Buffer) 1952 { 1953 return STATUS_INSUFFICIENT_RESOURCES; 1954 } 1955 1956 RtlCopyMemory(SymbolicName.Buffer, 1957 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset), 1958 SymbolicName.Length); 1959 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; 1960 1961 /* If the only mount point is a drive letter, then create a no letter drive entry */ 1962 if (MountPoints->NumberOfMountPoints == 1 && IsDriveLetter(&SymbolicName)) 1963 { 1964 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 1965 if (UniqueId) 1966 { 1967 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength; 1968 RtlCopyMemory(UniqueId->UniqueId, 1969 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset), 1970 MountPoints->MountPoints[Link].UniqueIdLength); 1971 1972 CreateNoDriveLetterEntry(UniqueId); 1973 FreePool(UniqueId); 1974 } 1975 } 1976 1977 /* Simply delete mount point from DB */ 1978 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, TRUE); 1979 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer); 1980 FreePool(SymbolicName.Buffer); 1981 } 1982 1983 return Status; 1984 } 1985 1986 /* 1987 * @implemented 1988 */ 1989 NTSTATUS 1990 MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension, 1991 IN PIRP Irp, 1992 IN NTSTATUS LockStatus, 1993 OUT PUNICODE_STRING SourceDeviceName, 1994 OUT PUNICODE_STRING SourceSymbolicName, 1995 OUT PUNICODE_STRING TargetVolumeName) 1996 { 1997 HANDLE Handle; 1998 NTSTATUS Status; 1999 PFILE_OBJECT FileObject; 2000 PIO_STACK_LOCATION Stack; 2001 ULONG Length, SavedLength; 2002 BOOLEAN FOReferenced = FALSE; 2003 IO_STATUS_BLOCK IoStatusBlock; 2004 OBJECT_ATTRIBUTES ObjectAttributes; 2005 PDEVICE_INFORMATION DeviceInformation; 2006 OBJECT_NAME_INFORMATION ObjectNameInfo; 2007 FILE_FS_DEVICE_INFORMATION FsDeviceInfo; 2008 PFILE_NAME_INFORMATION FileNameInfo = NULL; 2009 PMOUNTMGR_VOLUME_MOUNT_POINT VolumeMountPoint; 2010 POBJECT_NAME_INFORMATION ObjectNameInfoPtr = NULL; 2011 UNICODE_STRING SourceVolumeName, TargetDeviceName; 2012 2013 Stack = IoGetCurrentIrpStackLocation(Irp); 2014 2015 /* Validate input */ 2016 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_VOLUME_MOUNT_POINT)) 2017 { 2018 return STATUS_INVALID_PARAMETER; 2019 } 2020 2021 VolumeMountPoint = (PMOUNTMGR_VOLUME_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer; 2022 2023 if (((ULONG)VolumeMountPoint->SourceVolumeNameLength + VolumeMountPoint->TargetVolumeNameLength) < 2024 Stack->Parameters.DeviceIoControl.InputBufferLength) 2025 { 2026 return STATUS_INVALID_PARAMETER; 2027 } 2028 2029 /* Get source volume name */ 2030 SourceVolumeName.Length = 2031 SourceVolumeName.MaximumLength = VolumeMountPoint->SourceVolumeNameLength; 2032 SourceVolumeName.Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset); 2033 2034 InitializeObjectAttributes(&ObjectAttributes, 2035 &SourceVolumeName, 2036 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 2037 NULL, 2038 NULL); 2039 2040 /* Open it */ 2041 Status = ZwOpenFile(&Handle, 2042 SYNCHRONIZE | FILE_READ_ATTRIBUTES, 2043 &ObjectAttributes, 2044 &IoStatusBlock, 2045 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2046 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT); 2047 if (!NT_SUCCESS(Status)) 2048 { 2049 return Status; 2050 } 2051 2052 TargetDeviceName.Buffer = NULL; 2053 2054 /* Query its attributes */ 2055 Status = ZwQueryVolumeInformationFile(Handle, 2056 &IoStatusBlock, 2057 &FsDeviceInfo, 2058 sizeof(FsDeviceInfo), 2059 FileFsDeviceInformation); 2060 if (!NT_SUCCESS(Status)) 2061 { 2062 goto Cleanup; 2063 } 2064 2065 if (FsDeviceInfo.DeviceType != FILE_DEVICE_DISK && FsDeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK) 2066 { 2067 goto Cleanup; 2068 } 2069 2070 if (FsDeviceInfo.Characteristics != (FILE_REMOTE_DEVICE | FILE_REMOVABLE_MEDIA)) 2071 { 2072 goto Cleanup; 2073 } 2074 2075 /* Reference it */ 2076 Status = ObReferenceObjectByHandle(Handle, 0, *IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL); 2077 if (!NT_SUCCESS(Status)) 2078 { 2079 goto Cleanup; 2080 } 2081 FOReferenced = TRUE; 2082 2083 /* Get file name */ 2084 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION)); 2085 if (!FileNameInfo) 2086 { 2087 Status = STATUS_INSUFFICIENT_RESOURCES; 2088 goto Cleanup; 2089 } 2090 2091 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo, 2092 sizeof(FILE_NAME_INFORMATION), 2093 FileNameInformation); 2094 if (Status == STATUS_BUFFER_OVERFLOW) 2095 { 2096 /* Now we have real length, use it */ 2097 Length = FileNameInfo->FileNameLength; 2098 FreePool(FileNameInfo); 2099 2100 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + Length); 2101 if (!FileNameInfo) 2102 { 2103 Status = STATUS_INSUFFICIENT_RESOURCES; 2104 goto Cleanup; 2105 } 2106 2107 /* Really query file name */ 2108 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo, 2109 sizeof(FILE_NAME_INFORMATION) + Length, 2110 FileNameInformation); 2111 } 2112 2113 if (!NT_SUCCESS(Status)) 2114 { 2115 goto Cleanup; 2116 } 2117 2118 /* Get symbolic name */ 2119 ObjectNameInfoPtr = &ObjectNameInfo; 2120 SavedLength = sizeof(OBJECT_NAME_INFORMATION); 2121 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, sizeof(OBJECT_NAME_INFORMATION), &Length); 2122 if (Status == STATUS_INFO_LENGTH_MISMATCH) 2123 { 2124 /* Once again, with proper size, it works better */ 2125 ObjectNameInfoPtr = AllocatePool(Length); 2126 if (!ObjectNameInfoPtr) 2127 { 2128 Status = STATUS_INSUFFICIENT_RESOURCES; 2129 goto Cleanup; 2130 } 2131 2132 SavedLength = Length; 2133 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, SavedLength, &Length); 2134 } 2135 2136 if (!NT_SUCCESS(Status)) 2137 { 2138 goto Cleanup; 2139 } 2140 2141 /* Now, query the device name */ 2142 Status = QueryDeviceInformation(&ObjectNameInfoPtr->Name, SourceDeviceName, 2143 NULL, NULL, NULL, NULL, NULL, NULL); 2144 if (!NT_SUCCESS(Status)) 2145 { 2146 goto Cleanup; 2147 } 2148 2149 /* For target volume name, use input */ 2150 TargetVolumeName->Length = 2151 TargetVolumeName->MaximumLength = VolumeMountPoint->TargetVolumeNameLength; 2152 TargetVolumeName->Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset); 2153 2154 /* Query its device name */ 2155 Status = QueryDeviceInformation(TargetVolumeName, &TargetDeviceName, 2156 NULL, NULL, NULL, NULL, NULL, NULL); 2157 if (!NT_SUCCESS(Status)) 2158 { 2159 goto Cleanup; 2160 } 2161 2162 /* Return symbolic name */ 2163 SourceSymbolicName->Length = 2164 SourceSymbolicName->MaximumLength = (USHORT)FileNameInfo->FileNameLength; 2165 SourceSymbolicName->Buffer = (PWSTR)FileNameInfo; 2166 /* memmove allows memory overlap */ 2167 RtlMoveMemory(SourceSymbolicName->Buffer, FileNameInfo->FileName, SourceSymbolicName->Length); 2168 FileNameInfo = NULL; 2169 2170 /* Notify the change */ 2171 MountMgrNotify(DeviceExtension); 2172 MountMgrNotifyNameChange(DeviceExtension, &TargetDeviceName, TRUE); 2173 2174 /* If we are locked, sync databases if possible */ 2175 if (NT_SUCCESS(LockStatus)) 2176 { 2177 Status = FindDeviceInfo(DeviceExtension, SourceDeviceName, FALSE, &DeviceInformation); 2178 if (NT_SUCCESS(Status)) 2179 { 2180 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation); 2181 } 2182 else 2183 { 2184 Status = STATUS_PENDING; 2185 } 2186 } 2187 2188 Cleanup: 2189 if (TargetDeviceName.Buffer) 2190 { 2191 FreePool(TargetDeviceName.Buffer); 2192 } 2193 2194 if (ObjectNameInfoPtr && ObjectNameInfoPtr != &ObjectNameInfo) 2195 { 2196 FreePool(ObjectNameInfoPtr); 2197 } 2198 2199 if (FileNameInfo) 2200 { 2201 FreePool(FileNameInfo); 2202 } 2203 2204 if (FOReferenced) 2205 { 2206 ObDereferenceObject(FileObject); 2207 } 2208 2209 return Status; 2210 } 2211 2212 /* 2213 * @implemented 2214 */ 2215 NTSTATUS 2216 MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension, 2217 IN PIRP Irp, 2218 IN NTSTATUS LockStatus) 2219 { 2220 LONG Offset; 2221 BOOLEAN Found; 2222 NTSTATUS Status; 2223 HANDLE RemoteDatabase; 2224 PMOUNTDEV_UNIQUE_ID UniqueId; 2225 PDATABASE_ENTRY DatabaseEntry; 2226 PASSOCIATED_DEVICE_ENTRY AssociatedEntry; 2227 PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation; 2228 UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName; 2229 2230 /* Initialize string */ 2231 LinkTarget.Length = 0; 2232 LinkTarget.MaximumLength = 0xC8; 2233 LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength); 2234 if (LinkTarget.Buffer == NULL) 2235 { 2236 return STATUS_INSUFFICIENT_RESOURCES; 2237 } 2238 2239 /* If the mount point was created, then, it changed! 2240 * Also use it to query some information 2241 */ 2242 Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName); 2243 /* Pending means DB are under synchronization, bail out */ 2244 if (Status == STATUS_PENDING) 2245 { 2246 FreePool(LinkTarget.Buffer); 2247 FreePool(SourceDeviceName.Buffer); 2248 FreePool(SourceSymbolicName.Buffer); 2249 return STATUS_SUCCESS; 2250 } 2251 else if (!NT_SUCCESS(Status)) 2252 { 2253 FreePool(LinkTarget.Buffer); 2254 return Status; 2255 } 2256 2257 /* Query the device information */ 2258 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); 2259 if (!NT_SUCCESS(Status)) 2260 { 2261 /* If it failed, first try to get volume name */ 2262 Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName); 2263 if (!NT_SUCCESS(Status)) 2264 { 2265 /* Then, try to read the symlink */ 2266 Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget); 2267 if (!NT_SUCCESS(Status)) 2268 { 2269 FreePool(LinkTarget.Buffer); 2270 FreePool(SourceDeviceName.Buffer); 2271 FreePool(SourceSymbolicName.Buffer); 2272 return Status; 2273 } 2274 } 2275 else 2276 { 2277 FreePool(VolumeName.Buffer); 2278 } 2279 2280 FreePool(SourceDeviceName.Buffer); 2281 2282 SourceDeviceName.Length = LinkTarget.Length; 2283 SourceDeviceName.MaximumLength = LinkTarget.MaximumLength; 2284 SourceDeviceName.Buffer = LinkTarget.Buffer; 2285 2286 /* Now that we have the correct source, reattempt to query information */ 2287 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); 2288 if (!NT_SUCCESS(Status)) 2289 { 2290 FreePool(SourceDeviceName.Buffer); 2291 FreePool(SourceSymbolicName.Buffer); 2292 return Status; 2293 } 2294 } 2295 2296 FreePool(SourceDeviceName.Buffer); 2297 2298 /* Get information about target device */ 2299 Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation); 2300 if (!NT_SUCCESS(Status)) 2301 { 2302 FreePool(SourceSymbolicName.Buffer); 2303 return Status; 2304 } 2305 2306 /* Notify if not disabled */ 2307 if (!TargetDeviceInformation->SkipNotifications) 2308 { 2309 PostOnlineNotification(DeviceExtension, &TargetDeviceInformation->SymbolicName); 2310 } 2311 2312 /* Open the remote database */ 2313 RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE); 2314 if (RemoteDatabase == 0) 2315 { 2316 FreePool(SourceSymbolicName.Buffer); 2317 return STATUS_INSUFFICIENT_RESOURCES; 2318 } 2319 2320 /* Browse all the entries */ 2321 Offset = 0; 2322 Found = FALSE; 2323 for (;;) 2324 { 2325 DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset); 2326 if (DatabaseEntry == NULL) 2327 { 2328 break; 2329 } 2330 2331 /* Try to find ourselves */ 2332 DbName.MaximumLength = DatabaseEntry->SymbolicNameLength; 2333 DbName.Length = DbName.MaximumLength; 2334 DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset); 2335 if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE)) 2336 { 2337 /* Reference ourselves and update the entry */ 2338 ++DatabaseEntry->EntryReferences; 2339 Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry); 2340 FreePool(DatabaseEntry); 2341 Found = TRUE; 2342 break; 2343 } 2344 2345 Offset += DatabaseEntry->EntrySize; 2346 FreePool(DatabaseEntry); 2347 } 2348 2349 /* We couldn't find ourselves, we'll have to add ourselves */ 2350 if (!Found) 2351 { 2352 ULONG EntrySize; 2353 PUNIQUE_ID_REPLICATE UniqueIdReplicate; 2354 2355 /* Query the device unique ID */ 2356 Status = QueryDeviceInformation(&TargetVolumeName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL); 2357 if (!NT_SUCCESS(Status)) 2358 { 2359 FreePool(SourceSymbolicName.Buffer); 2360 CloseRemoteDatabase(RemoteDatabase); 2361 return Status; 2362 } 2363 2364 /* Allocate a database entry */ 2365 EntrySize = UniqueId->UniqueIdLength + TargetVolumeName.Length + sizeof(DATABASE_ENTRY); 2366 DatabaseEntry = AllocatePool(EntrySize); 2367 if (DatabaseEntry == NULL) 2368 { 2369 FreePool(UniqueId); 2370 FreePool(SourceSymbolicName.Buffer); 2371 CloseRemoteDatabase(RemoteDatabase); 2372 return STATUS_INSUFFICIENT_RESOURCES; 2373 } 2374 2375 /* Fill it in */ 2376 DatabaseEntry->EntrySize = EntrySize; 2377 DatabaseEntry->EntryReferences = 1; 2378 DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY); 2379 DatabaseEntry->SymbolicNameLength = TargetVolumeName.Length; 2380 DatabaseEntry->UniqueIdOffset = TargetVolumeName.Length + sizeof(DATABASE_ENTRY); 2381 DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength; 2382 RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + sizeof(DATABASE_ENTRY)), TargetVolumeName.Buffer, DatabaseEntry->SymbolicNameLength); 2383 RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength); 2384 2385 /* And write it down */ 2386 Status = AddRemoteDatabaseEntry(RemoteDatabase, DatabaseEntry); 2387 FreePool(DatabaseEntry); 2388 if (!NT_SUCCESS(Status)) 2389 { 2390 FreePool(UniqueId); 2391 FreePool(SourceSymbolicName.Buffer); 2392 CloseRemoteDatabase(RemoteDatabase); 2393 return Status; 2394 } 2395 2396 /* And now, allocate an Unique ID item */ 2397 UniqueIdReplicate = AllocatePool(sizeof(UNIQUE_ID_REPLICATE)); 2398 if (UniqueIdReplicate == NULL) 2399 { 2400 FreePool(UniqueId); 2401 FreePool(SourceSymbolicName.Buffer); 2402 CloseRemoteDatabase(RemoteDatabase); 2403 return Status; 2404 } 2405 2406 /* To associate it with the device */ 2407 UniqueIdReplicate->UniqueId = UniqueId; 2408 InsertTailList(&DeviceInformation->ReplicatedUniqueIdsListHead, &UniqueIdReplicate->ReplicatedUniqueIdsListEntry); 2409 } 2410 2411 /* We're done with the remote database */ 2412 CloseRemoteDatabase(RemoteDatabase); 2413 2414 /* Check we were find writing the entry */ 2415 if (!NT_SUCCESS(Status)) 2416 { 2417 FreePool(SourceSymbolicName.Buffer); 2418 return Status; 2419 } 2420 2421 /* This is the end, allocate an associated entry */ 2422 AssociatedEntry = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY)); 2423 if (AssociatedEntry == NULL) 2424 { 2425 FreePool(SourceSymbolicName.Buffer); 2426 return STATUS_INSUFFICIENT_RESOURCES; 2427 } 2428 2429 /* Initialize its source name string */ 2430 AssociatedEntry->String.Length = SourceSymbolicName.Length; 2431 AssociatedEntry->String.MaximumLength = AssociatedEntry->String.Length + sizeof(UNICODE_NULL); 2432 AssociatedEntry->String.Buffer = AllocatePool(AssociatedEntry->String.MaximumLength); 2433 if (AssociatedEntry->String.Buffer == NULL) 2434 { 2435 FreePool(AssociatedEntry); 2436 FreePool(SourceSymbolicName.Buffer); 2437 return STATUS_INSUFFICIENT_RESOURCES; 2438 } 2439 2440 /* Copy data & insert in list */ 2441 RtlCopyMemory(AssociatedEntry->String.Buffer, SourceSymbolicName.Buffer, SourceSymbolicName.Length); 2442 AssociatedEntry->String.Buffer[SourceSymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; 2443 AssociatedEntry->DeviceInformation = DeviceInformation; 2444 InsertTailList(&TargetDeviceInformation->AssociatedDevicesHead, &AssociatedEntry->AssociatedDevicesEntry); 2445 2446 /* We're done! */ 2447 FreePool(SourceSymbolicName.Buffer); 2448 return STATUS_SUCCESS; 2449 } 2450 2451 /* 2452 * @implemented 2453 */ 2454 NTSTATUS 2455 MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension, 2456 IN PIRP Irp, 2457 IN NTSTATUS LockStatus) 2458 { 2459 LONG Offset; 2460 NTSTATUS Status; 2461 PLIST_ENTRY Entry; 2462 HANDLE RemoteDatabase; 2463 PDATABASE_ENTRY DatabaseEntry; 2464 PUNIQUE_ID_REPLICATE UniqueIdReplicate; 2465 PASSOCIATED_DEVICE_ENTRY AssociatedEntry; 2466 PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation; 2467 UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName; 2468 2469 /* Initialize string */ 2470 LinkTarget.Length = 0; 2471 LinkTarget.MaximumLength = 0xC8; 2472 LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength); 2473 if (LinkTarget.Buffer == NULL) 2474 { 2475 return STATUS_INSUFFICIENT_RESOURCES; 2476 } 2477 2478 /* If the mount point was deleted, then, it changed! 2479 * Also use it to query some information 2480 */ 2481 Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName); 2482 /* Pending means DB are under synchronization, bail out */ 2483 if (Status == STATUS_PENDING) 2484 { 2485 FreePool(LinkTarget.Buffer); 2486 FreePool(SourceDeviceName.Buffer); 2487 FreePool(SourceSymbolicName.Buffer); 2488 return STATUS_SUCCESS; 2489 } 2490 else if (!NT_SUCCESS(Status)) 2491 { 2492 FreePool(LinkTarget.Buffer); 2493 return Status; 2494 } 2495 2496 /* Query the device information */ 2497 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); 2498 if (!NT_SUCCESS(Status)) 2499 { 2500 /* If it failed, first try to get volume name */ 2501 Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName); 2502 if (!NT_SUCCESS(Status)) 2503 { 2504 /* Then, try to read the symlink */ 2505 Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget); 2506 if (!NT_SUCCESS(Status)) 2507 { 2508 FreePool(LinkTarget.Buffer); 2509 FreePool(SourceDeviceName.Buffer); 2510 FreePool(SourceSymbolicName.Buffer); 2511 return Status; 2512 } 2513 } 2514 else 2515 { 2516 FreePool(VolumeName.Buffer); 2517 } 2518 2519 FreePool(SourceDeviceName.Buffer); 2520 2521 SourceDeviceName.Length = LinkTarget.Length; 2522 SourceDeviceName.MaximumLength = LinkTarget.MaximumLength; 2523 SourceDeviceName.Buffer = LinkTarget.Buffer; 2524 2525 /* Now that we have the correct source, reattempt to query information */ 2526 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); 2527 if (!NT_SUCCESS(Status)) 2528 { 2529 FreePool(SourceDeviceName.Buffer); 2530 FreePool(SourceSymbolicName.Buffer); 2531 return Status; 2532 } 2533 } 2534 2535 FreePool(SourceDeviceName.Buffer); 2536 2537 /* Get information about target device */ 2538 Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation); 2539 if (!NT_SUCCESS(Status)) 2540 { 2541 FreePool(SourceSymbolicName.Buffer); 2542 return Status; 2543 } 2544 2545 /* Open the remote database */ 2546 RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE); 2547 if (RemoteDatabase == 0) 2548 { 2549 FreePool(SourceSymbolicName.Buffer); 2550 return STATUS_INSUFFICIENT_RESOURCES; 2551 } 2552 2553 /* Browse all the entries */ 2554 Offset = 0; 2555 for (;;) 2556 { 2557 DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset); 2558 if (DatabaseEntry == NULL) 2559 { 2560 /* We didn't find ourselves, that's infortunate! */ 2561 FreePool(SourceSymbolicName.Buffer); 2562 CloseRemoteDatabase(RemoteDatabase); 2563 return STATUS_INVALID_PARAMETER; 2564 } 2565 2566 /* Try to find ourselves */ 2567 DbName.MaximumLength = DatabaseEntry->SymbolicNameLength; 2568 DbName.Length = DbName.MaximumLength; 2569 DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset); 2570 if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE)) 2571 { 2572 break; 2573 } 2574 2575 Offset += DatabaseEntry->EntrySize; 2576 FreePool(DatabaseEntry); 2577 } 2578 2579 /* Dereference ourselves */ 2580 DatabaseEntry->EntryReferences--; 2581 if (DatabaseEntry->EntryReferences == 0) 2582 { 2583 /* If we're still referenced, just update the entry */ 2584 Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry); 2585 } 2586 else 2587 { 2588 /* Otherwise, delete the entry */ 2589 Status = DeleteRemoteDatabaseEntry(RemoteDatabase, Offset); 2590 if (!NT_SUCCESS(Status)) 2591 { 2592 FreePool(DatabaseEntry); 2593 FreePool(SourceSymbolicName.Buffer); 2594 CloseRemoteDatabase(RemoteDatabase); 2595 return Status; 2596 } 2597 2598 /* Also, delete our unique ID replicated record */ 2599 for (Entry = DeviceInformation->ReplicatedUniqueIdsListHead.Flink; 2600 Entry != &DeviceInformation->ReplicatedUniqueIdsListHead; 2601 Entry = Entry->Flink) 2602 { 2603 UniqueIdReplicate = CONTAINING_RECORD(Entry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry); 2604 2605 if (UniqueIdReplicate->UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength && 2606 RtlCompareMemory(UniqueIdReplicate->UniqueId->UniqueId, 2607 (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), 2608 DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength) 2609 { 2610 break; 2611 } 2612 } 2613 2614 /* It has to exist! */ 2615 if (Entry == &DeviceInformation->ReplicatedUniqueIdsListHead) 2616 { 2617 FreePool(DatabaseEntry); 2618 FreePool(SourceSymbolicName.Buffer); 2619 CloseRemoteDatabase(RemoteDatabase); 2620 return STATUS_UNSUCCESSFUL; 2621 } 2622 2623 /* Remove it and free it */ 2624 RemoveEntryList(&UniqueIdReplicate->ReplicatedUniqueIdsListEntry); 2625 FreePool(UniqueIdReplicate->UniqueId); 2626 FreePool(UniqueIdReplicate); 2627 } 2628 2629 /* We're done with the remote database */ 2630 FreePool(DatabaseEntry); 2631 CloseRemoteDatabase(RemoteDatabase); 2632 2633 /* Check write operation succeed */ 2634 if (!NT_SUCCESS(Status)) 2635 { 2636 FreePool(SourceSymbolicName.Buffer); 2637 return Status; 2638 } 2639 2640 /* Try to find our associated device entry */ 2641 for (Entry = TargetDeviceInformation->AssociatedDevicesHead.Flink; 2642 Entry != &TargetDeviceInformation->AssociatedDevicesHead; 2643 Entry = Entry->Flink) 2644 { 2645 AssociatedEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); 2646 2647 /* If found, delete it */ 2648 if (AssociatedEntry->DeviceInformation == DeviceInformation && 2649 RtlEqualUnicodeString(&AssociatedEntry->String, &SourceSymbolicName, TRUE)) 2650 { 2651 RemoveEntryList(&AssociatedEntry->AssociatedDevicesEntry); 2652 FreePool(AssociatedEntry->String.Buffer); 2653 FreePool(AssociatedEntry); 2654 break; 2655 } 2656 } 2657 2658 /* We're done! */ 2659 FreePool(SourceSymbolicName.Buffer); 2660 return STATUS_SUCCESS; 2661 } 2662 2663 /* 2664 * @implemented 2665 */ 2666 NTSTATUS 2667 NTAPI 2668 MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject, 2669 IN PIRP Irp) 2670 { 2671 PIO_STACK_LOCATION Stack; 2672 NTSTATUS Status, LockStatus; 2673 PDEVICE_EXTENSION DeviceExtension; 2674 2675 Stack = IoGetCurrentIrpStackLocation(Irp); 2676 DeviceExtension = DeviceObject->DeviceExtension; 2677 2678 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 2679 2680 switch (Stack->Parameters.DeviceIoControl.IoControlCode) 2681 { 2682 case IOCTL_MOUNTMGR_CREATE_POINT: 2683 Status = MountMgrCreatePoint(DeviceExtension, Irp); 2684 break; 2685 2686 case IOCTL_MOUNTMGR_DELETE_POINTS: 2687 Status = MountMgrDeletePoints(DeviceExtension, Irp); 2688 break; 2689 2690 case IOCTL_MOUNTMGR_QUERY_POINTS: 2691 Status = MountMgrQueryPoints(DeviceExtension, Irp); 2692 break; 2693 2694 case IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY: 2695 Status = MountMgrDeletePointsDbOnly(DeviceExtension, Irp); 2696 break; 2697 2698 case IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER: 2699 Status = MountMgrNextDriveLetter(DeviceExtension, Irp); 2700 break; 2701 2702 case IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS: 2703 // NOTE: On Win7+, this is handled during driver re-initialization. 2704 DeviceExtension->AutomaticDriveLetter = TRUE; 2705 MountMgrAssignDriveLetters(DeviceExtension); 2706 ReconcileAllDatabasesWithMaster(DeviceExtension); 2707 WaitForOnlinesToComplete(DeviceExtension); 2708 Status = STATUS_SUCCESS; 2709 break; 2710 2711 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED: 2712 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 2713 2714 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension); 2715 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 2716 Status = MountMgrVolumeMountPointCreated(DeviceExtension, Irp, LockStatus); 2717 if (NT_SUCCESS(LockStatus)) 2718 { 2719 ReleaseRemoteDatabaseSemaphore(DeviceExtension); 2720 } 2721 2722 break; 2723 2724 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED: 2725 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 2726 2727 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension); 2728 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 2729 Status = MountMgrVolumeMountPointDeleted(DeviceExtension, Irp, LockStatus); 2730 if (NT_SUCCESS(LockStatus)) 2731 { 2732 ReleaseRemoteDatabaseSemaphore(DeviceExtension); 2733 } 2734 2735 break; 2736 2737 case IOCTL_MOUNTMGR_CHANGE_NOTIFY: 2738 Status = MountMgrChangeNotify(DeviceExtension, Irp); 2739 break; 2740 2741 case IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE: 2742 Status = MountMgrKeepLinksWhenOffline(DeviceExtension, Irp); 2743 break; 2744 2745 case IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES: 2746 Status = MountMgrCheckUnprocessedVolumes(DeviceExtension, Irp); 2747 goto Complete; 2748 2749 case IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION: 2750 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 2751 Status = MountMgrVolumeArrivalNotification(DeviceExtension, Irp); 2752 goto Complete; 2753 2754 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH: 2755 Status = MountMgrQueryDosVolumePath(DeviceExtension, Irp); 2756 break; 2757 2758 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS: 2759 Status = MountMgrQueryDosVolumePaths(DeviceExtension, Irp); 2760 break; 2761 2762 case IOCTL_MOUNTMGR_SCRUB_REGISTRY: 2763 Status = MountMgrScrubRegistry(DeviceExtension); 2764 break; 2765 2766 case IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT: 2767 Status = MountMgrQueryAutoMount(DeviceExtension, Irp); 2768 break; 2769 2770 case IOCTL_MOUNTMGR_SET_AUTO_MOUNT: 2771 Status = MountMgrSetAutoMount(DeviceExtension, Irp); 2772 break; 2773 2774 default: 2775 Status = STATUS_INVALID_DEVICE_REQUEST; 2776 } 2777 2778 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 2779 2780 if (Status != STATUS_PENDING) 2781 { 2782 goto Complete; 2783 } 2784 2785 return Status; 2786 2787 Complete: 2788 Irp->IoStatus.Status = Status; 2789 IoCompleteRequest(Irp, IO_NO_INCREMENT); 2790 2791 return Status; 2792 } 2793