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