1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/io/iomgr/volume.c 5 * PURPOSE: Volume and File System I/O Support 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Herv� Poussineau (hpoussin@reactos.org) 8 * Eric Kohl 9 * Pierre Schweitzer (pierre.schweitzer@reactos.org) 10 */ 11 12 /* INCLUDES *****************************************************************/ 13 14 #include <ntoskrnl.h> 15 #define NDEBUG 16 #include <debug.h> 17 18 /* GLOBALS ******************************************************************/ 19 20 ERESOURCE IopDatabaseResource; 21 LIST_ENTRY IopDiskFileSystemQueueHead, IopNetworkFileSystemQueueHead; 22 LIST_ENTRY IopCdRomFileSystemQueueHead, IopTapeFileSystemQueueHead; 23 LIST_ENTRY IopFsNotifyChangeQueueHead; 24 ULONG IopFsRegistrationOps; 25 26 /* PRIVATE FUNCTIONS *********************************************************/ 27 28 /* 29 * @halfplemented 30 */ 31 VOID 32 NTAPI 33 IopDecrementDeviceObjectRef(IN PDEVICE_OBJECT DeviceObject, 34 IN BOOLEAN UnloadIfUnused) 35 { 36 KIRQL OldIrql; 37 38 /* Acquire lock */ 39 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); 40 ASSERT(DeviceObject->ReferenceCount > 0); 41 42 if (--DeviceObject->ReferenceCount > 0) 43 { 44 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 45 return; 46 } 47 48 /* Release lock */ 49 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 50 51 /* Here, DO is not referenced any longer, check if we have to unload it */ 52 if (UnloadIfUnused || IoGetDevObjExtension(DeviceObject)->ExtensionFlags & 53 (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING)) 54 { 55 /* Unload the driver */ 56 IopUnloadDevice(DeviceObject); 57 } 58 } 59 60 /* 61 * @implemented 62 */ 63 VOID 64 NTAPI 65 IopDecrementDeviceObjectHandleCount(IN PDEVICE_OBJECT DeviceObject) 66 { 67 /* Just decrease reference count */ 68 IopDecrementDeviceObjectRef(DeviceObject, FALSE); 69 } 70 71 /* 72 * @implemented 73 */ 74 PVPB 75 NTAPI 76 IopCheckVpbMounted(IN POPEN_PACKET OpenPacket, 77 IN PDEVICE_OBJECT DeviceObject, 78 IN PUNICODE_STRING RemainingName, 79 OUT PNTSTATUS Status) 80 { 81 BOOLEAN Alertable, Raw; 82 KIRQL OldIrql; 83 PVPB Vpb = NULL; 84 85 /* Lock the VPBs */ 86 IoAcquireVpbSpinLock(&OldIrql); 87 88 /* Set VPB mount settings */ 89 Raw = !RemainingName->Length && !OpenPacket->RelatedFileObject; 90 Alertable = (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) ? 91 TRUE: FALSE; 92 93 /* Start looping until the VPB is mounted */ 94 while (!(DeviceObject->Vpb->Flags & VPB_MOUNTED)) 95 { 96 /* Release the lock */ 97 IoReleaseVpbSpinLock(OldIrql); 98 99 /* Mount the volume */ 100 *Status = IopMountVolume(DeviceObject, 101 Raw, 102 FALSE, 103 Alertable, 104 &Vpb); 105 106 /* Check if we failed or if we were alerted */ 107 if (!(NT_SUCCESS(*Status)) || 108 (*Status == STATUS_USER_APC) || 109 (*Status == STATUS_ALERTED)) 110 { 111 /* Dereference the device, since IopParseDevice referenced it */ 112 IopDereferenceDeviceObject(DeviceObject, FALSE); 113 114 /* Check if it was a total failure */ 115 if (!NT_SUCCESS(*Status)) return NULL; 116 117 /* Otherwise we were alerted */ 118 *Status = STATUS_WRONG_VOLUME; 119 return NULL; 120 } 121 /* 122 * In case IopMountVolume returns a valid VPB 123 * Then, the volume is mounted, return it 124 */ 125 else if (Vpb != NULL) 126 { 127 return Vpb; 128 } 129 130 /* Re-acquire the lock */ 131 IoAcquireVpbSpinLock(&OldIrql); 132 } 133 134 /* Make sure the VPB isn't locked */ 135 Vpb = DeviceObject->Vpb; 136 if (Vpb->Flags & VPB_LOCKED) 137 { 138 /* We're locked, so fail */ 139 *Status = STATUS_ACCESS_DENIED; 140 Vpb = NULL; 141 } 142 else 143 { 144 /* Success! Reference the VPB */ 145 Vpb->ReferenceCount++; 146 } 147 148 /* Release the lock and return the VPB */ 149 IoReleaseVpbSpinLock(OldIrql); 150 return Vpb; 151 } 152 153 /* 154 * @implemented 155 */ 156 NTSTATUS 157 NTAPI 158 IopCreateVpb(IN PDEVICE_OBJECT DeviceObject) 159 { 160 PVPB Vpb; 161 162 /* Allocate the Vpb */ 163 Vpb = ExAllocatePoolWithTag(NonPagedPool, 164 sizeof(VPB), 165 TAG_VPB); 166 if (!Vpb) return STATUS_INSUFFICIENT_RESOURCES; 167 168 /* Clear it so we don't waste time manually */ 169 RtlZeroMemory(Vpb, sizeof(VPB)); 170 171 /* Set the Header and Device Field */ 172 Vpb->Type = IO_TYPE_VPB; 173 Vpb->Size = sizeof(VPB); 174 Vpb->RealDevice = DeviceObject; 175 176 /* Link it to the Device Object */ 177 DeviceObject->Vpb = Vpb; 178 return STATUS_SUCCESS; 179 } 180 181 /* 182 * @implemented 183 */ 184 VOID 185 NTAPI 186 IopDereferenceVpbAndFree(IN PVPB Vpb) 187 { 188 KIRQL OldIrql; 189 190 /* Lock the VPBs and decrease references */ 191 IoAcquireVpbSpinLock(&OldIrql); 192 Vpb->ReferenceCount--; 193 194 /* Check if we're out of references */ 195 if (!Vpb->ReferenceCount && Vpb->RealDevice->Vpb == Vpb && 196 !(Vpb->Flags & VPB_PERSISTENT)) 197 { 198 /* Release VPB lock */ 199 IoReleaseVpbSpinLock(OldIrql); 200 201 /* And free VPB */ 202 ExFreePoolWithTag(Vpb, TAG_VPB); 203 } 204 else 205 { 206 /* Release VPB lock */ 207 IoReleaseVpbSpinLock(OldIrql); 208 } 209 } 210 211 /* 212 * @implemented 213 */ 214 BOOLEAN 215 NTAPI 216 IopReferenceVerifyVpb(IN PDEVICE_OBJECT DeviceObject, 217 OUT PDEVICE_OBJECT *FileSystemObject, 218 OUT PVPB *Vpb) 219 { 220 KIRQL OldIrql; 221 PVPB LocalVpb; 222 BOOLEAN Result = FALSE; 223 224 /* Lock the VPBs and assume failure */ 225 IoAcquireVpbSpinLock(&OldIrql); 226 *Vpb = NULL; 227 *FileSystemObject = NULL; 228 229 /* Get the VPB and make sure it's mounted */ 230 LocalVpb = DeviceObject->Vpb; 231 if ((LocalVpb) && (LocalVpb->Flags & VPB_MOUNTED)) 232 { 233 /* Return it */ 234 *Vpb = LocalVpb; 235 *FileSystemObject = LocalVpb->DeviceObject; 236 237 /* Reference it */ 238 LocalVpb->ReferenceCount++; 239 Result = TRUE; 240 } 241 242 /* Release the VPB lock and return status */ 243 IoReleaseVpbSpinLock(OldIrql); 244 return Result; 245 } 246 247 PVPB 248 NTAPI 249 IopMountInitializeVpb(IN PDEVICE_OBJECT DeviceObject, 250 IN PDEVICE_OBJECT AttachedDeviceObject, 251 IN BOOLEAN Raw) 252 { 253 KIRQL OldIrql; 254 PVPB Vpb; 255 256 /* Lock the VPBs */ 257 IoAcquireVpbSpinLock(&OldIrql); 258 Vpb = DeviceObject->Vpb; 259 260 /* Set the VPB as mounted and possibly raw */ 261 Vpb->Flags |= VPB_MOUNTED | (Raw ? VPB_RAW_MOUNT : 0); 262 263 /* Set the stack size */ 264 Vpb->DeviceObject->StackSize = AttachedDeviceObject->StackSize; 265 266 /* Add one for the FS Driver */ 267 Vpb->DeviceObject->StackSize++; 268 269 /* Set the VPB in the device extension */ 270 IoGetDevObjExtension(Vpb->DeviceObject)->Vpb = Vpb; 271 272 /* Reference it */ 273 Vpb->ReferenceCount++; 274 275 /* Release the VPB lock and return it */ 276 IoReleaseVpbSpinLock(OldIrql); 277 return Vpb; 278 } 279 280 /* 281 * @implemented 282 */ 283 FORCEINLINE 284 VOID 285 IopNotifyFileSystemChange(IN PDEVICE_OBJECT DeviceObject, 286 IN BOOLEAN DriverActive) 287 { 288 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry; 289 PLIST_ENTRY ListEntry; 290 291 /* Loop the list */ 292 ListEntry = IopFsNotifyChangeQueueHead.Flink; 293 while (ListEntry != &IopFsNotifyChangeQueueHead) 294 { 295 /* Get the entry */ 296 ChangeEntry = CONTAINING_RECORD(ListEntry, 297 FS_CHANGE_NOTIFY_ENTRY, 298 FsChangeNotifyList); 299 300 /* Call the notification procedure */ 301 ChangeEntry->FSDNotificationProc(DeviceObject, DriverActive); 302 303 /* Go to the next entry */ 304 ListEntry = ListEntry->Flink; 305 } 306 } 307 308 /* 309 * @implemented 310 */ 311 ULONG 312 FASTCALL 313 IopInterlockedIncrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue, 314 IN PULONG Ulong) 315 { 316 KIRQL Irql; 317 ULONG OldValue; 318 319 Irql = KeAcquireQueuedSpinLock(Queue); 320 OldValue = (*Ulong)++; 321 KeReleaseQueuedSpinLock(Queue, Irql); 322 323 return OldValue; 324 } 325 326 /* 327 * @implemented 328 */ 329 ULONG 330 FASTCALL 331 IopInterlockedDecrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue, 332 IN PULONG Ulong) 333 { 334 KIRQL Irql; 335 ULONG OldValue; 336 337 Irql = KeAcquireQueuedSpinLock(Queue); 338 OldValue = (*Ulong)--; 339 KeReleaseQueuedSpinLock(Queue, Irql); 340 341 return OldValue; 342 } 343 344 /* 345 * @implemented 346 */ 347 VOID 348 NTAPI 349 IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead) 350 { 351 PLIST_ENTRY ListEntry; 352 PDEVICE_OBJECT DeviceObject; 353 IO_STATUS_BLOCK StatusBlock; 354 PIRP Irp; 355 KEVENT Event; 356 NTSTATUS Status; 357 358 KeInitializeEvent(&Event, NotificationEvent, FALSE); 359 360 /* Get the first entry and start looping */ 361 ListEntry = ListHead->Flink; 362 while (ListEntry != ListHead) 363 { 364 /* Get the device object */ 365 DeviceObject = CONTAINING_RECORD(ListEntry, 366 DEVICE_OBJECT, 367 Queue.ListEntry); 368 369 /* Go to the next entry */ 370 ListEntry = ListEntry->Flink; 371 372 /* Get the attached device */ 373 DeviceObject = IoGetAttachedDevice(DeviceObject); 374 375 ObReferenceObject(DeviceObject); 376 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 377 378 /* Build the shutdown IRP and call the driver */ 379 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, 380 DeviceObject, 381 NULL, 382 0, 383 NULL, 384 &Event, 385 &StatusBlock); 386 if (Irp) 387 { 388 Status = IoCallDriver(DeviceObject, Irp); 389 if (Status == STATUS_PENDING) 390 { 391 /* Wait on the driver */ 392 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 393 } 394 } 395 396 /* Reset the event */ 397 KeClearEvent(&Event); 398 399 IopDecrementDeviceObjectRef(DeviceObject, FALSE); 400 ObDereferenceObject(DeviceObject); 401 } 402 } 403 404 /* 405 * @implemented 406 */ 407 VOID 408 NTAPI 409 IopLoadFileSystemDriver(IN PDEVICE_OBJECT DeviceObject) 410 { 411 IO_STATUS_BLOCK IoStatusBlock; 412 PIO_STACK_LOCATION StackPtr; 413 KEVENT Event; 414 PIRP Irp; 415 NTSTATUS Status; 416 PDEVICE_OBJECT AttachedDeviceObject = DeviceObject; 417 PAGED_CODE(); 418 419 /* Loop as long as we're attached */ 420 while (AttachedDeviceObject->AttachedDevice) 421 { 422 /* Get the attached device object */ 423 AttachedDeviceObject = AttachedDeviceObject->AttachedDevice; 424 } 425 426 /* Initialize the event and build the IRP */ 427 KeInitializeEvent(&Event, NotificationEvent, FALSE); 428 Irp = IoBuildDeviceIoControlRequest(IRP_MJ_DEVICE_CONTROL, 429 AttachedDeviceObject, 430 NULL, 431 0, 432 NULL, 433 0, 434 FALSE, 435 &Event, 436 &IoStatusBlock); 437 if (Irp) 438 { 439 /* Set the major and minor functions */ 440 StackPtr = IoGetNextIrpStackLocation(Irp); 441 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; 442 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM; 443 444 /* Call the driver */ 445 Status = IoCallDriver(AttachedDeviceObject, Irp); 446 if (Status == STATUS_PENDING) 447 { 448 /* Wait on it */ 449 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 450 } 451 } 452 453 /* Dereference DO - FsRec? - Comment out call, since it breaks up 2nd stage boot, needs more research. */ 454 // IopDecrementDeviceObjectRef(AttachedDeviceObject, TRUE); 455 } 456 457 /* 458 * @implemented 459 */ 460 NTSTATUS 461 NTAPI 462 IopMountVolume(IN PDEVICE_OBJECT DeviceObject, 463 IN BOOLEAN AllowRawMount, 464 IN BOOLEAN DeviceIsLocked, 465 IN BOOLEAN Alertable, 466 OUT PVPB *Vpb) 467 { 468 KEVENT Event; 469 NTSTATUS Status; 470 IO_STATUS_BLOCK IoStatusBlock; 471 PIRP Irp; 472 PIO_STACK_LOCATION StackPtr; 473 PLIST_ENTRY FsList, ListEntry; 474 LIST_ENTRY LocalList; 475 PDEVICE_OBJECT AttachedDeviceObject = DeviceObject; 476 PDEVICE_OBJECT FileSystemDeviceObject, ParentFsDeviceObject; 477 ULONG FsStackOverhead, RegistrationOps; 478 PAGED_CODE(); 479 480 /* Check if the device isn't already locked */ 481 if (!DeviceIsLocked) 482 { 483 /* Lock it ourselves */ 484 Status = KeWaitForSingleObject(&DeviceObject->DeviceLock, 485 Executive, 486 KeGetPreviousMode(), 487 Alertable, 488 NULL); 489 if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC)) 490 { 491 /* Don't mount if we were interrupted */ 492 return Status; 493 } 494 } 495 496 /* Acquire the FS Lock*/ 497 KeEnterCriticalRegion(); 498 ExAcquireResourceSharedLite(&IopDatabaseResource, TRUE); 499 500 /* Make sure we weren't already mounted */ 501 if (!(DeviceObject->Vpb->Flags & (VPB_MOUNTED | VPB_REMOVE_PENDING))) 502 { 503 /* Initialize the event to wait on */ 504 KeInitializeEvent(&Event, NotificationEvent, FALSE); 505 506 /* Remove the verify flag and get the actual device to mount */ 507 DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 508 while (AttachedDeviceObject->AttachedDevice) 509 { 510 /* Get the next one */ 511 AttachedDeviceObject = AttachedDeviceObject->AttachedDevice; 512 } 513 514 /* Reference it */ 515 ObReferenceObject(AttachedDeviceObject); 516 517 /* For a mount operation, this can only be a Disk, CD-ROM or tape */ 518 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) || 519 (DeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK)) 520 { 521 /* Use the disk list */ 522 FsList = &IopDiskFileSystemQueueHead; 523 } 524 else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM) 525 { 526 /* Use the CD-ROM list */ 527 FsList = &IopCdRomFileSystemQueueHead; 528 } 529 else 530 { 531 /* It's gotta be a tape... */ 532 FsList = &IopTapeFileSystemQueueHead; 533 } 534 535 /* Now loop the fs list until one of the file systems accepts us */ 536 Status = STATUS_UNSUCCESSFUL; 537 ListEntry = FsList->Flink; 538 while ((ListEntry != FsList) && !(NT_SUCCESS(Status))) 539 { 540 /* 541 * If we're not allowed to mount this volume and this is our last 542 * (but not only) chance to mount it... 543 */ 544 if (!(AllowRawMount) && 545 (ListEntry->Flink == FsList) && 546 (ListEntry != FsList->Flink)) 547 { 548 /* Then fail this mount request */ 549 break; 550 } 551 552 /* 553 * Also check if this is a raw mount and there are other file 554 * systems on the list. 555 */ 556 if ((DeviceObject->Vpb->Flags & VPB_RAW_MOUNT) && 557 (ListEntry->Flink != FsList)) 558 { 559 /* Then skip this entry */ 560 ListEntry = ListEntry->Flink; 561 continue; 562 } 563 564 /* Get the Device Object for this FS */ 565 FileSystemDeviceObject = CONTAINING_RECORD(ListEntry, 566 DEVICE_OBJECT, 567 Queue.ListEntry); 568 ParentFsDeviceObject = FileSystemDeviceObject; 569 570 /* 571 * If this file system device is attached to some other device, 572 * then we must make sure to increase the stack size for the IRP. 573 * The default is +1, for the FS device itself. 574 */ 575 FsStackOverhead = 1; 576 while (FileSystemDeviceObject->AttachedDevice) 577 { 578 /* Get the next attached device and increase overhead */ 579 FileSystemDeviceObject = FileSystemDeviceObject-> 580 AttachedDevice; 581 FsStackOverhead++; 582 } 583 584 /* Clear the event */ 585 KeClearEvent(&Event); 586 587 /* Allocate the IRP */ 588 Irp = IoAllocateIrp(AttachedDeviceObject->StackSize + 589 (UCHAR)FsStackOverhead, 590 TRUE); 591 if (!Irp) 592 { 593 /* Fail */ 594 Status = STATUS_INSUFFICIENT_RESOURCES; 595 break; 596 } 597 598 /* Setup the IRP */ 599 Irp->UserIosb = &IoStatusBlock; 600 Irp->UserEvent = &Event; 601 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 602 Irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO; 603 Irp->RequestorMode = KernelMode; 604 605 /* Get the I/O Stack location and set it up */ 606 StackPtr = IoGetNextIrpStackLocation(Irp); 607 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; 608 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME; 609 StackPtr->Flags = AllowRawMount; 610 StackPtr->Parameters.MountVolume.Vpb = DeviceObject->Vpb; 611 StackPtr->Parameters.MountVolume.DeviceObject = 612 AttachedDeviceObject; 613 614 /* Save registration operations */ 615 RegistrationOps = IopFsRegistrationOps; 616 617 /* Release locks */ 618 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 619 ExReleaseResourceLite(&IopDatabaseResource); 620 621 /* Call the driver */ 622 Status = IoCallDriver(FileSystemDeviceObject, Irp); 623 if (Status == STATUS_PENDING) 624 { 625 /* Wait on it */ 626 KeWaitForSingleObject(&Event, 627 Executive, 628 KernelMode, 629 FALSE, 630 NULL); 631 Status = IoStatusBlock.Status; 632 } 633 634 ExAcquireResourceSharedLite(&IopDatabaseResource, TRUE); 635 IopInterlockedDecrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 636 637 /* Check if mounting was successful */ 638 if (NT_SUCCESS(Status)) 639 { 640 /* Mount the VPB */ 641 *Vpb = IopMountInitializeVpb(DeviceObject, 642 AttachedDeviceObject, 643 (DeviceObject->Vpb->Flags & 644 VPB_RAW_MOUNT)); 645 } 646 else 647 { 648 /* Check if we failed because of the user */ 649 if ((IoIsErrorUserInduced(Status)) && 650 (IoStatusBlock.Information == 1)) 651 { 652 /* Break out and fail */ 653 break; 654 } 655 656 /* If there were registration operations in the meanwhile */ 657 if (RegistrationOps != IopFsRegistrationOps) 658 { 659 /* We need to setup a local list to pickup where we left */ 660 LocalList.Flink = FsList->Flink; 661 ListEntry = &LocalList; 662 663 Status = STATUS_UNRECOGNIZED_VOLUME; 664 } 665 666 /* Otherwise, check if we need to load the FS driver */ 667 if (Status == STATUS_FS_DRIVER_REQUIRED) 668 { 669 /* We need to release the lock */ 670 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 671 ExReleaseResourceLite(&IopDatabaseResource); 672 673 /* Release the device lock if we're holding it */ 674 if (!DeviceIsLocked) 675 { 676 KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE); 677 } 678 679 /* Leave critical section */ 680 KeLeaveCriticalRegion(); 681 682 /* Load the FS */ 683 IopLoadFileSystemDriver(ParentFsDeviceObject); 684 685 /* Check if the device isn't already locked */ 686 if (!DeviceIsLocked) 687 { 688 /* Lock it ourselves */ 689 Status = KeWaitForSingleObject(&DeviceObject-> 690 DeviceLock, 691 Executive, 692 KeGetPreviousMode(), 693 Alertable, 694 NULL); 695 if ((Status == STATUS_ALERTED) || 696 (Status == STATUS_USER_APC)) 697 { 698 /* Don't mount if we were interrupted */ 699 ObDereferenceObject(AttachedDeviceObject); 700 return Status; 701 } 702 } 703 704 /* Reacquire the lock */ 705 KeEnterCriticalRegion(); 706 ExAcquireResourceSharedLite(&IopDatabaseResource, TRUE); 707 708 /* When we released the lock, make sure nobody beat us */ 709 if (DeviceObject->Vpb->Flags & VPB_MOUNTED) 710 { 711 /* Someone did, break out */ 712 Status = STATUS_SUCCESS; 713 break; 714 } 715 716 /* Start over by setting a failure */ 717 Status = STATUS_UNRECOGNIZED_VOLUME; 718 719 /* We need to setup a local list to pickup where we left */ 720 LocalList.Flink = FsList->Flink; 721 ListEntry = &LocalList; 722 } 723 724 /* 725 * Check if we failed with any other error then an unrecognized 726 * volume, and if this request doesn't allow mounting the raw 727 * file system. 728 */ 729 if (!(AllowRawMount) && 730 (Status != STATUS_UNRECOGNIZED_VOLUME) && 731 (FsRtlIsTotalDeviceFailure(Status))) 732 { 733 /* Break out and give up */ 734 break; 735 } 736 } 737 738 /* Go to the next FS entry */ 739 ListEntry = ListEntry->Flink; 740 } 741 742 /* Dereference the device if we failed */ 743 if (!NT_SUCCESS(Status)) ObDereferenceObject(AttachedDeviceObject); 744 } 745 else if (DeviceObject->Vpb->Flags & VPB_REMOVE_PENDING) 746 { 747 /* Someone wants to remove us */ 748 Status = STATUS_DEVICE_DOES_NOT_EXIST; 749 } 750 else 751 { 752 /* Someone already mounted us */ 753 Status = STATUS_SUCCESS; 754 } 755 756 /* Release the FS lock */ 757 ExReleaseResourceLite(&IopDatabaseResource); 758 KeLeaveCriticalRegion(); 759 760 /* Release the device lock if we're holding it */ 761 if (!DeviceIsLocked) KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE); 762 763 /* Check if we failed to mount the boot partition */ 764 if ((!NT_SUCCESS(Status)) && 765 (DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION) && 766 ExpInitializationPhase < 2) 767 { 768 /* Bugcheck the system */ 769 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE, 770 (ULONG_PTR)DeviceObject, 771 Status, 772 0, 773 0); 774 } 775 776 /* Return the mount status */ 777 return Status; 778 } 779 780 /* 781 * @implemented 782 */ 783 VOID 784 NTAPI 785 IopNotifyAlreadyRegisteredFileSystems(IN PLIST_ENTRY ListHead, 786 IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine, 787 BOOLEAN SkipRawFs) 788 { 789 PLIST_ENTRY ListEntry; 790 PDEVICE_OBJECT DeviceObject; 791 792 /* Browse the whole list */ 793 ListEntry = ListHead->Flink; 794 while (ListEntry != ListHead) 795 { 796 /* Check if we reached rawfs and if we have to skip it */ 797 if (ListEntry->Flink == ListHead && SkipRawFs) 798 { 799 return; 800 } 801 802 /* Otherwise, get DO and notify */ 803 DeviceObject = CONTAINING_RECORD(ListEntry, 804 DEVICE_OBJECT, 805 Queue.ListEntry); 806 807 DriverNotificationRoutine(DeviceObject, TRUE); 808 809 /* Go to the next entry */ 810 ListEntry = ListEntry->Flink; 811 } 812 } 813 814 /* PUBLIC FUNCTIONS **********************************************************/ 815 816 /* 817 * @implemented 818 */ 819 NTSTATUS 820 NTAPI 821 IoEnumerateRegisteredFiltersList(OUT PDRIVER_OBJECT *DriverObjectList, 822 IN ULONG DriverObjectListSize, 823 OUT PULONG ActualNumberDriverObjects) 824 { 825 PLIST_ENTRY ListEntry; 826 NTSTATUS Status = STATUS_SUCCESS; 827 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry; 828 ULONG ListSize = 0, MaximumSize = DriverObjectListSize / sizeof(PDRIVER_OBJECT); 829 830 /* Acquire the FS lock */ 831 KeEnterCriticalRegion(); 832 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 833 834 /* Browse the whole list */ 835 ListEntry = IopFsNotifyChangeQueueHead.Flink; 836 while (ListEntry != &IopFsNotifyChangeQueueHead) 837 { 838 ChangeEntry = CONTAINING_RECORD(ListEntry, 839 FS_CHANGE_NOTIFY_ENTRY, 840 FsChangeNotifyList); 841 842 /* If buffer is still big enough */ 843 if (ListSize < MaximumSize) 844 { 845 /* Reference the driver object */ 846 ObReferenceObject(ChangeEntry->DriverObject); 847 /* And pass it to the caller */ 848 DriverObjectList[ListSize] = ChangeEntry->DriverObject; 849 } 850 else 851 { 852 Status = STATUS_BUFFER_TOO_SMALL; 853 } 854 855 /* Increase size counter */ 856 ListSize++; 857 858 /* Go to the next entry */ 859 ListEntry = ListEntry->Flink; 860 } 861 862 /* Return list size */ 863 *ActualNumberDriverObjects = ListSize; 864 865 /* Release the FS lock */ 866 ExReleaseResourceLite(&IopDatabaseResource); 867 KeLeaveCriticalRegion(); 868 869 return Status; 870 } 871 872 /* 873 * @implemented 874 */ 875 NTSTATUS 876 NTAPI 877 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject, 878 IN BOOLEAN AllowRawMount) 879 { 880 IO_STATUS_BLOCK IoStatusBlock; 881 PIO_STACK_LOCATION StackPtr; 882 KEVENT Event; 883 PIRP Irp; 884 NTSTATUS Status, VpbStatus; 885 PDEVICE_OBJECT FileSystemDeviceObject; 886 PVPB Vpb, NewVpb; 887 //BOOLEAN WasNotMounted = TRUE; 888 889 /* Wait on the device lock */ 890 Status = KeWaitForSingleObject(&DeviceObject->DeviceLock, 891 Executive, 892 KernelMode, 893 FALSE, 894 NULL); 895 ASSERT(Status == STATUS_SUCCESS); 896 897 /* Reference the VPB */ 898 if (IopReferenceVerifyVpb(DeviceObject, &FileSystemDeviceObject, &Vpb)) 899 { 900 /* Initialize the event */ 901 KeInitializeEvent(&Event, NotificationEvent, FALSE); 902 903 /* Find the actual File System DO */ 904 //WasNotMounted = FALSE; 905 FileSystemDeviceObject = DeviceObject->Vpb->DeviceObject; 906 while (FileSystemDeviceObject->AttachedDevice) 907 { 908 /* Go to the next one */ 909 FileSystemDeviceObject = FileSystemDeviceObject->AttachedDevice; 910 } 911 912 /* Allocate the IRP */ 913 Irp = IoAllocateIrp(FileSystemDeviceObject->StackSize, FALSE); 914 if (!Irp) 915 { 916 Status = STATUS_INSUFFICIENT_RESOURCES; 917 goto Release; 918 } 919 920 /* Set it up */ 921 Irp->UserIosb = &IoStatusBlock; 922 Irp->UserEvent = &Event; 923 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 924 Irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO; 925 Irp->RequestorMode = KernelMode; 926 927 /* Get the I/O Stack location and set it */ 928 StackPtr = IoGetNextIrpStackLocation(Irp); 929 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; 930 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME; 931 StackPtr->Flags = AllowRawMount ? SL_ALLOW_RAW_MOUNT : 0; 932 StackPtr->Parameters.VerifyVolume.Vpb = Vpb; 933 StackPtr->Parameters.VerifyVolume.DeviceObject = 934 DeviceObject->Vpb->DeviceObject; 935 936 /* Call the driver */ 937 Status = IoCallDriver(FileSystemDeviceObject, Irp); 938 if (Status == STATUS_PENDING) 939 { 940 /* Wait on it */ 941 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 942 Status = IoStatusBlock.Status; 943 } 944 945 /* Dereference the VPB */ 946 IopDereferenceVpbAndFree(Vpb); 947 } 948 949 /* Check if we had the wrong volume or didn't mount at all */ 950 if (Status == STATUS_WRONG_VOLUME) 951 { 952 /* Create a VPB */ 953 VpbStatus = IopCreateVpb(DeviceObject); 954 if (NT_SUCCESS(VpbStatus)) 955 { 956 PoVolumeDevice(DeviceObject); 957 958 /* Mount it */ 959 VpbStatus = IopMountVolume(DeviceObject, 960 AllowRawMount, 961 TRUE, 962 FALSE, 963 &NewVpb); 964 965 /* If we got a new VPB, dereference it */ 966 if (NewVpb) 967 { 968 IopInterlockedDecrementUlong(LockQueueIoVpbLock, &NewVpb->ReferenceCount); 969 } 970 } 971 972 /* If we failed, remove the verify flag */ 973 if (!NT_SUCCESS(VpbStatus)) DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 974 } 975 976 Release: 977 /* Signal the device lock and return */ 978 KeSetEvent(&DeviceObject->DeviceLock, IO_NO_INCREMENT, FALSE); 979 return Status; 980 } 981 982 /* 983 * @implemented 984 */ 985 VOID 986 NTAPI 987 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject) 988 { 989 PLIST_ENTRY FsList = NULL; 990 PAGED_CODE(); 991 992 /* Acquire the FS lock */ 993 KeEnterCriticalRegion(); 994 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 995 996 /* Check what kind of FS this is */ 997 if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) 998 { 999 /* Use the disk list */ 1000 FsList = &IopDiskFileSystemQueueHead; 1001 } 1002 else if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) 1003 { 1004 /* Use the network device list */ 1005 FsList = &IopNetworkFileSystemQueueHead; 1006 } 1007 else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) 1008 { 1009 /* Use the CD-ROM list */ 1010 FsList = &IopCdRomFileSystemQueueHead; 1011 } 1012 else if (DeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) 1013 { 1014 /* Use the tape list */ 1015 FsList = &IopTapeFileSystemQueueHead; 1016 } 1017 1018 /* Make sure that we have a valid list */ 1019 if (FsList) 1020 { 1021 /* Check if we should insert it at the top or bottom of the list */ 1022 if (DeviceObject->Flags & DO_LOW_PRIORITY_FILESYSTEM) 1023 { 1024 /* At the bottom */ 1025 InsertTailList(FsList->Blink, &DeviceObject->Queue.ListEntry); 1026 } 1027 else 1028 { 1029 /* On top */ 1030 InsertHeadList(FsList, &DeviceObject->Queue.ListEntry); 1031 } 1032 } 1033 1034 /* Update operations counter */ 1035 IopFsRegistrationOps++; 1036 1037 /* Clear the initializing flag */ 1038 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1039 1040 /* Notify file systems of the addition */ 1041 IopNotifyFileSystemChange(DeviceObject, TRUE); 1042 1043 /* Release the FS Lock */ 1044 ExReleaseResourceLite(&IopDatabaseResource); 1045 KeLeaveCriticalRegion(); 1046 1047 /* Ensure driver won't be unloaded */ 1048 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 1049 } 1050 1051 /* 1052 * @implemented 1053 */ 1054 VOID 1055 NTAPI 1056 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject) 1057 { 1058 PAGED_CODE(); 1059 1060 /* Acquire the FS lock */ 1061 KeEnterCriticalRegion(); 1062 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 1063 1064 /* Simply remove the entry - if queued */ 1065 if (DeviceObject->Queue.ListEntry.Flink) 1066 { 1067 RemoveEntryList(&DeviceObject->Queue.ListEntry); 1068 } 1069 1070 /* And notify all registered file systems */ 1071 IopNotifyFileSystemChange(DeviceObject, FALSE); 1072 1073 /* Update operations counter */ 1074 IopFsRegistrationOps++; 1075 1076 /* Then release the lock */ 1077 ExReleaseResourceLite(&IopDatabaseResource); 1078 KeLeaveCriticalRegion(); 1079 1080 /* Decrease reference count to allow unload */ 1081 IopInterlockedDecrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 1082 } 1083 1084 /* 1085 * @implemented 1086 */ 1087 NTSTATUS 1088 NTAPI 1089 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject, 1090 IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine) 1091 { 1092 PFS_CHANGE_NOTIFY_ENTRY Entry; 1093 PAGED_CODE(); 1094 1095 /* Acquire the list lock */ 1096 KeEnterCriticalRegion(); 1097 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 1098 1099 /* Check if that driver is already registered (successive calls) 1100 * See MSDN note: http://msdn.microsoft.com/en-us/library/ff548499%28v=vs.85%29.aspx 1101 */ 1102 if (!IsListEmpty(&IopFsNotifyChangeQueueHead)) 1103 { 1104 Entry = CONTAINING_RECORD(IopFsNotifyChangeQueueHead.Blink, 1105 FS_CHANGE_NOTIFY_ENTRY, 1106 FsChangeNotifyList); 1107 1108 if (Entry->DriverObject == DriverObject && 1109 Entry->FSDNotificationProc == DriverNotificationRoutine) 1110 { 1111 /* Release the lock */ 1112 ExReleaseResourceLite(&IopDatabaseResource); 1113 1114 return STATUS_DEVICE_ALREADY_ATTACHED; 1115 } 1116 } 1117 1118 /* Allocate a notification entry */ 1119 Entry = ExAllocatePoolWithTag(PagedPool, 1120 sizeof(FS_CHANGE_NOTIFY_ENTRY), 1121 TAG_FS_CHANGE_NOTIFY); 1122 if (!Entry) 1123 { 1124 /* Release the lock */ 1125 ExReleaseResourceLite(&IopDatabaseResource); 1126 1127 return STATUS_INSUFFICIENT_RESOURCES; 1128 } 1129 1130 /* Save the driver object and notification routine */ 1131 Entry->DriverObject = DriverObject; 1132 Entry->FSDNotificationProc = DriverNotificationRoutine; 1133 1134 /* Insert it into the notification list */ 1135 InsertTailList(&IopFsNotifyChangeQueueHead, &Entry->FsChangeNotifyList); 1136 1137 /* Start notifying all already present FS */ 1138 IopNotifyAlreadyRegisteredFileSystems(&IopNetworkFileSystemQueueHead, DriverNotificationRoutine, FALSE); 1139 IopNotifyAlreadyRegisteredFileSystems(&IopCdRomFileSystemQueueHead, DriverNotificationRoutine, TRUE); 1140 IopNotifyAlreadyRegisteredFileSystems(&IopDiskFileSystemQueueHead, DriverNotificationRoutine, TRUE); 1141 IopNotifyAlreadyRegisteredFileSystems(&IopTapeFileSystemQueueHead, DriverNotificationRoutine, TRUE); 1142 1143 /* Release the lock */ 1144 ExReleaseResourceLite(&IopDatabaseResource); 1145 KeLeaveCriticalRegion(); 1146 1147 /* Reference the driver */ 1148 ObReferenceObject(DriverObject); 1149 return STATUS_SUCCESS; 1150 } 1151 1152 /* 1153 * @implemented 1154 */ 1155 VOID 1156 NTAPI 1157 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject, 1158 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc) 1159 { 1160 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry; 1161 PLIST_ENTRY NextEntry; 1162 PAGED_CODE(); 1163 1164 /* Acquire the list lock */ 1165 KeEnterCriticalRegion(); 1166 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 1167 1168 /* Loop the list */ 1169 NextEntry = IopFsNotifyChangeQueueHead.Flink; 1170 while (NextEntry != &IopFsNotifyChangeQueueHead) 1171 { 1172 /* Get the entry */ 1173 ChangeEntry = CONTAINING_RECORD(NextEntry, 1174 FS_CHANGE_NOTIFY_ENTRY, 1175 FsChangeNotifyList); 1176 1177 /* Check if it matches this de-registration */ 1178 if ((ChangeEntry->DriverObject == DriverObject) && 1179 (ChangeEntry->FSDNotificationProc == FSDNotificationProc)) 1180 { 1181 /* It does, remove it from the list */ 1182 RemoveEntryList(&ChangeEntry->FsChangeNotifyList); 1183 ExFreePoolWithTag(ChangeEntry, TAG_FS_CHANGE_NOTIFY); 1184 break; 1185 } 1186 1187 /* Go to the next entry */ 1188 NextEntry = NextEntry->Flink; 1189 } 1190 1191 /* Release the lock and dereference the driver */ 1192 ExReleaseResourceLite(&IopDatabaseResource); 1193 KeLeaveCriticalRegion(); 1194 1195 /* Dereference the driver */ 1196 ObDereferenceObject(DriverObject); 1197 } 1198 1199 /* 1200 * @implemented 1201 */ 1202 VOID 1203 NTAPI 1204 IoAcquireVpbSpinLock(OUT PKIRQL Irql) 1205 { 1206 /* Simply acquire the lock */ 1207 *Irql = KeAcquireQueuedSpinLock(LockQueueIoVpbLock); 1208 } 1209 1210 /* 1211 * @implemented 1212 */ 1213 VOID 1214 NTAPI 1215 IoReleaseVpbSpinLock(IN KIRQL Irql) 1216 { 1217 /* Just release the lock */ 1218 KeReleaseQueuedSpinLock(LockQueueIoVpbLock, Irql); 1219 } 1220 1221 /* 1222 * @implemented 1223 */ 1224 NTSTATUS 1225 NTAPI 1226 IoSetSystemPartition(IN PUNICODE_STRING VolumeNameString) 1227 { 1228 NTSTATUS Status; 1229 HANDLE RootHandle, KeyHandle; 1230 UNICODE_STRING HKLMSystem, KeyString; 1231 WCHAR Buffer[sizeof(L"SystemPartition") / sizeof(WCHAR)]; 1232 1233 RtlInitUnicodeString(&HKLMSystem, L"\\REGISTRY\\MACHINE\\SYSTEM"); 1234 1235 /* Open registry to save data (HKLM\SYSTEM) */ 1236 Status = IopOpenRegistryKeyEx(&RootHandle, 0, &HKLMSystem, KEY_ALL_ACCESS); 1237 if (!NT_SUCCESS(Status)) 1238 { 1239 return Status; 1240 } 1241 1242 /* Create or open Setup subkey */ 1243 KeyString.Buffer = Buffer; 1244 KeyString.Length = sizeof(L"Setup") - sizeof(UNICODE_NULL); 1245 KeyString.MaximumLength = sizeof(L"Setup"); 1246 RtlCopyMemory(Buffer, L"Setup", sizeof(L"Setup")); 1247 Status = IopCreateRegistryKeyEx(&KeyHandle, 1248 RootHandle, 1249 &KeyString, 1250 KEY_ALL_ACCESS, 1251 REG_OPTION_NON_VOLATILE, 1252 NULL); 1253 ZwClose(RootHandle); 1254 if (!NT_SUCCESS(Status)) 1255 { 1256 return Status; 1257 } 1258 1259 /* Store caller value */ 1260 KeyString.Length = sizeof(L"SystemPartition") - sizeof(UNICODE_NULL); 1261 KeyString.MaximumLength = sizeof(L"SystemPartition"); 1262 RtlCopyMemory(Buffer, L"SystemPartition", sizeof(L"SystemPartition")); 1263 Status = ZwSetValueKey(KeyHandle, 1264 &KeyString, 1265 0, 1266 REG_SZ, 1267 VolumeNameString->Buffer, 1268 VolumeNameString->Length + sizeof(UNICODE_NULL)); 1269 ZwClose(KeyHandle); 1270 1271 return Status; 1272 } 1273 1274 /* 1275 * @implemented 1276 */ 1277 NTSTATUS 1278 NTAPI 1279 IoVolumeDeviceToDosName(IN PVOID VolumeDeviceObject, 1280 OUT PUNICODE_STRING DosName) 1281 { 1282 PIRP Irp; 1283 ULONG Length; 1284 KEVENT Event; 1285 NTSTATUS Status; 1286 PFILE_OBJECT FileObject; 1287 PDEVICE_OBJECT DeviceObject; 1288 IO_STATUS_BLOCK IoStatusBlock; 1289 UNICODE_STRING MountMgrDevice; 1290 MOUNTMGR_VOLUME_PATHS VolumePath; 1291 PMOUNTMGR_VOLUME_PATHS VolumePathPtr; 1292 /* 1293 * This variable with be required to query device name. 1294 * It's based on MOUNTDEV_NAME (mountmgr.h). 1295 * Doing it that way will prevent dyn memory allocation. 1296 * Device name won't be longer. 1297 */ 1298 struct 1299 { 1300 USHORT NameLength; 1301 WCHAR DeviceName[256]; 1302 } DeviceName; 1303 1304 PAGED_CODE(); 1305 1306 /* First step, getting device name */ 1307 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1308 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 1309 VolumeDeviceObject, NULL, 0, 1310 &DeviceName, sizeof(DeviceName), 1311 FALSE, &Event, &IoStatusBlock); 1312 if (!Irp) 1313 { 1314 return STATUS_INSUFFICIENT_RESOURCES; 1315 } 1316 1317 Status = IoCallDriver(VolumeDeviceObject, Irp); 1318 if (Status == STATUS_PENDING) 1319 { 1320 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1321 Status = IoStatusBlock.Status; 1322 } 1323 1324 if (!NT_SUCCESS(Status)) 1325 { 1326 return Status; 1327 } 1328 1329 /* Now that we have the device name, we can query the MountMgr 1330 * So, get its device object first. 1331 */ 1332 RtlInitUnicodeString(&MountMgrDevice, MOUNTMGR_DEVICE_NAME); 1333 Status = IoGetDeviceObjectPointer(&MountMgrDevice, FILE_READ_ATTRIBUTES, 1334 &FileObject, &DeviceObject); 1335 if (!NT_SUCCESS(Status)) 1336 { 1337 return Status; 1338 } 1339 1340 /* Then, use the proper IOCTL to query the DOS name */ 1341 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1342 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, 1343 DeviceObject, &DeviceName, sizeof(DeviceName), 1344 &VolumePath, sizeof(VolumePath), 1345 FALSE, &Event, &IoStatusBlock); 1346 if (!Irp) 1347 { 1348 Status = STATUS_INSUFFICIENT_RESOURCES; 1349 goto DereferenceFO; 1350 } 1351 1352 Status = IoCallDriver(DeviceObject, Irp); 1353 if (Status == STATUS_PENDING) 1354 { 1355 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1356 Status = IoStatusBlock.Status; 1357 } 1358 1359 /* Only tolerated failure here is buffer too small, which is 1360 * expected. 1361 */ 1362 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 1363 { 1364 goto DereferenceFO; 1365 } 1366 1367 /* Compute needed size to store DOS name. 1368 * Even if MOUNTMGR_VOLUME_PATHS allows bigger 1369 * name lengths than MAXUSHORT, we can't use 1370 * them, because we have to return this in an UNICODE_STRING 1371 * that stores length on USHORT. 1372 */ 1373 Length = VolumePath.MultiSzLength + sizeof(VolumePath); 1374 if (Length > MAXUSHORT) 1375 { 1376 Status = STATUS_INVALID_BUFFER_SIZE; 1377 goto DereferenceFO; 1378 } 1379 1380 /* Reallocate memory, even in case of success, because 1381 * that's the buffer that will be returned to caller 1382 */ 1383 VolumePathPtr = ExAllocatePoolWithTag(PagedPool, Length, 'D2d '); 1384 if (!VolumePathPtr) 1385 { 1386 Status = STATUS_INSUFFICIENT_RESOURCES; 1387 goto DereferenceFO; 1388 } 1389 1390 /* Requery DOS path with proper size */ 1391 KeInitializeEvent(&Event, NotificationEvent, FALSE); 1392 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, 1393 DeviceObject, &DeviceName, sizeof(DeviceName), 1394 VolumePathPtr, Length, 1395 FALSE, &Event, &IoStatusBlock); 1396 if (!Irp) 1397 { 1398 Status = STATUS_INSUFFICIENT_RESOURCES; 1399 goto ReleaseMemory; 1400 } 1401 1402 Status = IoCallDriver(DeviceObject, Irp); 1403 if (Status == STATUS_PENDING) 1404 { 1405 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1406 Status = IoStatusBlock.Status; 1407 } 1408 1409 if (!NT_SUCCESS(Status)) 1410 { 1411 goto ReleaseMemory; 1412 } 1413 1414 /* Set output string */ 1415 DosName->Length = (USHORT)VolumePathPtr->MultiSzLength; 1416 DosName->MaximumLength = (USHORT)VolumePathPtr->MultiSzLength + sizeof(UNICODE_NULL); 1417 /* Our MOUNTMGR_VOLUME_PATHS will be used as output buffer */ 1418 DosName->Buffer = (PWSTR)VolumePathPtr; 1419 /* Move name at the begin, RtlMoveMemory is OK with overlapping */ 1420 RtlMoveMemory(DosName->Buffer, VolumePathPtr->MultiSz, VolumePathPtr->MultiSzLength); 1421 DosName->Buffer[DosName->Length / sizeof(WCHAR)] = UNICODE_NULL; 1422 1423 /* DON'T release buffer, just dereference FO, and return success */ 1424 Status = STATUS_SUCCESS; 1425 goto DereferenceFO; 1426 1427 ReleaseMemory: 1428 ExFreePoolWithTag(VolumePathPtr, 'D2d '); 1429 1430 DereferenceFO: 1431 ObDereferenceObject(FileObject); 1432 1433 return Status; 1434 } 1435 1436 /* EOF */ 1437