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