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
IopDecrementDeviceObjectRef(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN UnloadIfUnused)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
IopDecrementDeviceObjectHandleCount(IN PDEVICE_OBJECT DeviceObject)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
IopCheckVpbMounted(IN POPEN_PACKET OpenPacket,IN PDEVICE_OBJECT DeviceObject,IN PUNICODE_STRING RemainingName,OUT PNTSTATUS Status)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
IopCreateVpb(IN PDEVICE_OBJECT DeviceObject)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
IopDereferenceVpbAndFree(IN PVPB Vpb)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
IopReferenceVerifyVpb(IN PDEVICE_OBJECT DeviceObject,OUT PDEVICE_OBJECT * FileSystemObject,OUT PVPB * Vpb)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
IopMountInitializeVpb(IN PDEVICE_OBJECT DeviceObject,IN PDEVICE_OBJECT AttachedDeviceObject,IN BOOLEAN Raw)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
IopNotifyFileSystemChange(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN DriverActive)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
IopInterlockedIncrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue,IN PULONG Ulong)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
IopInterlockedDecrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue,IN PULONG Ulong)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
IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead)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
IopLoadFileSystemDriver(IN PDEVICE_OBJECT DeviceObject)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
IopMountVolume(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN AllowRawMount,IN BOOLEAN DeviceIsLocked,IN BOOLEAN Alertable,OUT PVPB * Vpb)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
IopNotifyAlreadyRegisteredFileSystems(IN PLIST_ENTRY ListHead,IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine,BOOLEAN SkipRawFs)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
IoEnumerateRegisteredFiltersList(OUT PDRIVER_OBJECT * DriverObjectList,IN ULONG DriverObjectListSize,OUT PULONG ActualNumberDriverObjects)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
IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,IN BOOLEAN AllowRawMount)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
IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)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
IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)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
IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine)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
IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,IN PDRIVER_FS_NOTIFICATION FSDNotificationProc)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
IoAcquireVpbSpinLock(OUT PKIRQL Irql)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
IoReleaseVpbSpinLock(IN KIRQL Irql)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
IoSetSystemPartition(IN PUNICODE_STRING VolumeNameString)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
IoVolumeDeviceToDosName(IN PVOID VolumeDeviceObject,OUT PUNICODE_STRING DosName)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