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