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