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)
9 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
12 /* INCLUDES *****************************************************************/
18 #if defined (ALLOC_PRAGMA)
19 #pragma alloc_text(INIT, IoInitFileSystemImplementation)
20 #pragma alloc_text(INIT, IoInitVpbImplementation)
23 /* GLOBALS ******************************************************************/
25 ERESOURCE IopDatabaseResource
;
26 LIST_ENTRY IopDiskFileSystemQueueHead
, IopNetworkFileSystemQueueHead
;
27 LIST_ENTRY IopCdRomFileSystemQueueHead
, IopTapeFileSystemQueueHead
;
28 LIST_ENTRY IopFsNotifyChangeQueueHead
;
29 ULONG IopFsRegistrationOps
;
31 /* PRIVATE FUNCTIONS *********************************************************/
38 IopDecrementDeviceObjectRef(IN PDEVICE_OBJECT DeviceObject
,
39 IN BOOLEAN UnloadIfUnused
)
44 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
45 ASSERT(DeviceObject
->ReferenceCount
> 0);
47 if (--DeviceObject
->ReferenceCount
> 0)
49 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
54 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
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
))
60 /* Unload the driver */
61 IopUnloadDevice(DeviceObject
);
70 IopDecrementDeviceObjectHandleCount(IN PDEVICE_OBJECT DeviceObject
)
72 /* Just decrease reference count */
73 IopDecrementDeviceObjectRef(DeviceObject
, FALSE
);
81 IopCheckVpbMounted(IN POPEN_PACKET OpenPacket
,
82 IN PDEVICE_OBJECT DeviceObject
,
83 IN PUNICODE_STRING RemainingName
,
86 BOOLEAN Alertable
, Raw
;
91 IoAcquireVpbSpinLock(&OldIrql
);
93 /* Set VPB mount settings */
94 Raw
= !RemainingName
->Length
&& !OpenPacket
->RelatedFileObject
;
95 Alertable
= (OpenPacket
->CreateOptions
& FILE_SYNCHRONOUS_IO_ALERT
) ?
98 /* Start looping until the VPB is mounted */
99 while (!(DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
))
101 /* Release the lock */
102 IoReleaseVpbSpinLock(OldIrql
);
104 /* Mount the volume */
105 *Status
= IopMountVolume(DeviceObject
,
111 /* Check if we failed or if we were alerted */
112 if (!(NT_SUCCESS(*Status
)) ||
113 (*Status
== STATUS_USER_APC
) ||
114 (*Status
== STATUS_ALERTED
))
116 /* Dereference the device, since IopParseDevice referenced it */
117 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
119 /* Check if it was a total failure */
120 if (!NT_SUCCESS(*Status
)) return NULL
;
122 /* Otherwise we were alerted */
123 *Status
= STATUS_WRONG_VOLUME
;
127 /* Re-acquire the lock */
128 IoAcquireVpbSpinLock(&OldIrql
);
131 /* Make sure the VPB isn't locked */
132 Vpb
= DeviceObject
->Vpb
;
133 if (Vpb
->Flags
& VPB_LOCKED
)
135 /* We're locked, so fail */
136 *Status
= STATUS_ACCESS_DENIED
;
141 /* Success! Reference the VPB */
142 Vpb
->ReferenceCount
++;
145 /* Release the lock and return the VPB */
146 IoReleaseVpbSpinLock(OldIrql
);
155 IopCreateVpb(IN PDEVICE_OBJECT DeviceObject
)
159 /* Allocate the Vpb */
160 Vpb
= ExAllocatePoolWithTag(NonPagedPool
,
163 if (!Vpb
) return STATUS_INSUFFICIENT_RESOURCES
;
165 /* Clear it so we don't waste time manually */
166 RtlZeroMemory(Vpb
, sizeof(VPB
));
168 /* Set the Header and Device Field */
169 Vpb
->Type
= IO_TYPE_VPB
;
170 Vpb
->Size
= sizeof(VPB
);
171 Vpb
->RealDevice
= DeviceObject
;
173 /* Link it to the Device Object */
174 DeviceObject
->Vpb
= Vpb
;
175 return STATUS_SUCCESS
;
183 IopDereferenceVpbAndFree(IN PVPB Vpb
)
187 /* Lock the VPBs and decrease references */
188 IoAcquireVpbSpinLock(&OldIrql
);
189 Vpb
->ReferenceCount
--;
191 /* Check if we're out of references */
192 if (!Vpb
->ReferenceCount
&& Vpb
->RealDevice
->Vpb
== Vpb
&&
193 !(Vpb
->Flags
& VPB_PERSISTENT
))
195 /* Release VPB lock */
196 IoReleaseVpbSpinLock(OldIrql
);
199 ExFreePoolWithTag(Vpb
, TAG_VPB
);
203 /* Release VPB lock */
204 IoReleaseVpbSpinLock(OldIrql
);
213 IopReferenceVerifyVpb(IN PDEVICE_OBJECT DeviceObject
,
214 OUT PDEVICE_OBJECT
*FileSystemObject
,
219 BOOLEAN Result
= FALSE
;
221 /* Lock the VPBs and assume failure */
222 IoAcquireVpbSpinLock(&OldIrql
);
224 *FileSystemObject
= NULL
;
226 /* Get the VPB and make sure it's mounted */
227 LocalVpb
= DeviceObject
->Vpb
;
228 if ((LocalVpb
) && (LocalVpb
->Flags
& VPB_MOUNTED
))
232 *FileSystemObject
= LocalVpb
->DeviceObject
;
235 LocalVpb
->ReferenceCount
++;
239 /* Release the VPB lock and return status */
240 IoReleaseVpbSpinLock(OldIrql
);
246 IopMountInitializeVpb(IN PDEVICE_OBJECT DeviceObject
,
247 IN PDEVICE_OBJECT AttachedDeviceObject
,
254 IoAcquireVpbSpinLock(&OldIrql
);
255 Vpb
= DeviceObject
->Vpb
;
257 /* Set the VPB as mounted and possibly raw */
258 Vpb
->Flags
|= VPB_MOUNTED
| (Raw
? VPB_RAW_MOUNT
: 0);
260 /* Set the stack size */
261 Vpb
->DeviceObject
->StackSize
= AttachedDeviceObject
->StackSize
;
263 /* Add one for the FS Driver */
264 Vpb
->DeviceObject
->StackSize
++;
266 /* Set the VPB in the device extension */
267 IoGetDevObjExtension(Vpb
->DeviceObject
)->Vpb
= Vpb
;
270 Vpb
->ReferenceCount
++;
272 /* Release the VPB lock and return it */
273 IoReleaseVpbSpinLock(OldIrql
);
282 IopNotifyFileSystemChange(IN PDEVICE_OBJECT DeviceObject
,
283 IN BOOLEAN DriverActive
)
285 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
286 PLIST_ENTRY ListEntry
;
289 ListEntry
= IopFsNotifyChangeQueueHead
.Flink
;
290 while (ListEntry
!= &IopFsNotifyChangeQueueHead
)
293 ChangeEntry
= CONTAINING_RECORD(ListEntry
,
294 FS_CHANGE_NOTIFY_ENTRY
,
297 /* Call the notification procedure */
298 ChangeEntry
->FSDNotificationProc(DeviceObject
, DriverActive
);
300 /* Go to the next entry */
301 ListEntry
= ListEntry
->Flink
;
310 IopInterlockedIncrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue
,
316 Irql
= KeAcquireQueuedSpinLock(Queue
);
317 OldValue
= (*Ulong
)++;
318 KeReleaseQueuedSpinLock(Queue
, Irql
);
328 IopInterlockedDecrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue
,
334 Irql
= KeAcquireQueuedSpinLock(Queue
);
335 OldValue
= (*Ulong
)--;
336 KeReleaseQueuedSpinLock(Queue
, Irql
);
346 IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead
)
348 PLIST_ENTRY ListEntry
;
349 PDEVICE_OBJECT DeviceObject
;
350 IO_STATUS_BLOCK StatusBlock
;
355 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
357 /* Get the first entry and start looping */
358 ListEntry
= ListHead
->Flink
;
359 while (ListEntry
!= ListHead
)
361 /* Get the device object */
362 DeviceObject
= CONTAINING_RECORD(ListEntry
,
366 /* Get the attached device */
367 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
369 ObReferenceObject(DeviceObject
);
370 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
372 /* Build the shutdown IRP and call the driver */
373 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
382 Status
= IoCallDriver(DeviceObject
, Irp
);
383 if (Status
== STATUS_PENDING
)
385 /* Wait on the driver */
386 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
390 /* Reset the event */
391 KeClearEvent(&Event
);
393 IopDecrementDeviceObjectRef(DeviceObject
, FALSE
);
394 ObDereferenceObject(DeviceObject
);
396 /* Go to the next entry */
397 ListEntry
= ListEntry
->Flink
;
406 IopLoadFileSystemDriver(IN PDEVICE_OBJECT DeviceObject
)
408 IO_STATUS_BLOCK IoStatusBlock
;
409 PIO_STACK_LOCATION StackPtr
;
413 PDEVICE_OBJECT AttachedDeviceObject
= DeviceObject
;
416 /* Loop as long as we're attached */
417 while (AttachedDeviceObject
->AttachedDevice
)
419 /* Get the attached device object */
420 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
423 /* Initialize the event and build the IRP */
424 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
425 Irp
= IoBuildDeviceIoControlRequest(IRP_MJ_DEVICE_CONTROL
,
426 AttachedDeviceObject
,
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
;
441 /* Call the driver */
442 Status
= IoCallDriver(AttachedDeviceObject
, Irp
);
443 if (Status
== STATUS_PENDING
)
446 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
450 /* Dereference DO - FsRec? - Comment out call, since it breaks up 2nd stage boot, needs more research. */
451 // IopDecrementDeviceObjectRef(AttachedDeviceObject, TRUE);
459 IopMountVolume(IN PDEVICE_OBJECT DeviceObject
,
460 IN BOOLEAN AllowRawMount
,
461 IN BOOLEAN DeviceIsLocked
,
462 IN BOOLEAN Alertable
,
467 IO_STATUS_BLOCK IoStatusBlock
;
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
;
477 /* Check if the device isn't already locked */
480 /* Lock it ourselves */
481 Status
= KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
486 if ((Status
== STATUS_ALERTED
) || (Status
== STATUS_USER_APC
))
488 /* Don't mount if we were interrupted */
493 /* Acquire the FS Lock*/
494 KeEnterCriticalRegion();
495 ExAcquireResourceSharedLite(&IopDatabaseResource
, TRUE
);
497 /* Make sure we weren't already mounted */
498 if (!(DeviceObject
->Vpb
->Flags
& (VPB_MOUNTED
| VPB_REMOVE_PENDING
)))
500 /* Initialize the event to wait on */
501 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
503 /* Remove the verify flag and get the actual device to mount */
504 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
505 while (AttachedDeviceObject
->AttachedDevice
)
507 /* Get the next one */
508 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
512 ObReferenceObject(AttachedDeviceObject
);
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
))
518 /* Use the disk list */
519 FsList
= &IopDiskFileSystemQueueHead
;
521 else if (DeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
)
523 /* Use the CD-ROM list */
524 FsList
= &IopCdRomFileSystemQueueHead
;
528 /* It's gotta be a tape... */
529 FsList
= &IopTapeFileSystemQueueHead
;
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
)))
538 * If we're not allowed to mount this volume and this is our last
539 * (but not only) chance to mount it...
541 if (!(AllowRawMount
) &&
542 (ListEntry
->Flink
== FsList
) &&
543 (ListEntry
!= FsList
->Flink
))
545 /* Then fail this mount request */
550 * Also check if this is a raw mount and there are other file
551 * systems on the list.
553 if ((DeviceObject
->Vpb
->Flags
& VPB_RAW_MOUNT
) &&
554 (ListEntry
->Flink
!= FsList
))
556 /* Then skip this entry */
560 /* Get the Device Object for this FS */
561 FileSystemDeviceObject
= CONTAINING_RECORD(ListEntry
,
564 ParentFsDeviceObject
= FileSystemDeviceObject
;
567 * If this file system device is attached to some other device,
568 * then we must make sure to increase the stack size for the IRP.
569 * The default is +1, for the FS device itself.
572 while (FileSystemDeviceObject
->AttachedDevice
)
574 /* Get the next attached device and increase overhead */
575 FileSystemDeviceObject
= FileSystemDeviceObject
->
580 /* Clear the event */
581 KeClearEvent(&Event
);
583 /* Allocate the IRP */
584 Irp
= IoAllocateIrp(AttachedDeviceObject
->StackSize
+
585 (UCHAR
)FsStackOverhead
,
590 Status
= STATUS_INSUFFICIENT_RESOURCES
;
595 Irp
->UserIosb
= &IoStatusBlock
;
596 Irp
->UserEvent
= &Event
;
597 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
598 Irp
->Flags
= IRP_MOUNT_COMPLETION
| IRP_SYNCHRONOUS_PAGING_IO
;
599 Irp
->RequestorMode
= KernelMode
;
601 /* Get the I/O Stack location and set it up */
602 StackPtr
= IoGetNextIrpStackLocation(Irp
);
603 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
604 StackPtr
->MinorFunction
= IRP_MN_MOUNT_VOLUME
;
605 StackPtr
->Flags
= AllowRawMount
;
606 StackPtr
->Parameters
.MountVolume
.Vpb
= DeviceObject
->Vpb
;
607 StackPtr
->Parameters
.MountVolume
.DeviceObject
=
608 AttachedDeviceObject
;
610 /* Save registration operations */
611 RegistrationOps
= IopFsRegistrationOps
;
614 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
615 ExReleaseResourceLite(&IopDatabaseResource
);
617 /* Call the driver */
618 Status
= IoCallDriver(FileSystemDeviceObject
, Irp
);
619 if (Status
== STATUS_PENDING
)
622 KeWaitForSingleObject(&Event
,
627 Status
= IoStatusBlock
.Status
;
630 ExAcquireResourceSharedLite(&IopDatabaseResource
, TRUE
);
631 IopInterlockedDecrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
633 /* Check if mounting was successful */
634 if (NT_SUCCESS(Status
))
637 *Vpb
= IopMountInitializeVpb(DeviceObject
,
638 AttachedDeviceObject
,
639 (DeviceObject
->Vpb
->Flags
&
644 /* Check if we failed because of the user */
645 if ((IoIsErrorUserInduced(Status
)) &&
646 (IoStatusBlock
.Information
== 1))
648 /* Break out and fail */
652 /* If there were registration operations in the meanwhile */
653 if (RegistrationOps
!= IopFsRegistrationOps
)
655 /* We need to setup a local list to pickup where we left */
656 LocalList
.Flink
= FsList
->Flink
;
657 ListEntry
= &LocalList
;
659 Status
= STATUS_UNRECOGNIZED_VOLUME
;
662 /* Otherwise, check if we need to load the FS driver */
663 if (Status
== STATUS_FS_DRIVER_REQUIRED
)
665 /* We need to release the lock */
666 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
667 ExReleaseResourceLite(&IopDatabaseResource
);
669 /* Release the device lock if we're holding it */
672 KeSetEvent(&DeviceObject
->DeviceLock
, 0, FALSE
);
675 /* Leave critical section */
676 KeLeaveCriticalRegion();
679 IopLoadFileSystemDriver(ParentFsDeviceObject
);
681 /* Check if the device isn't already locked */
684 /* Lock it ourselves */
685 Status
= KeWaitForSingleObject(&DeviceObject
->
691 if ((Status
== STATUS_ALERTED
) ||
692 (Status
== STATUS_USER_APC
))
694 /* Don't mount if we were interrupted */
695 ObDereferenceObject(AttachedDeviceObject
);
700 /* Reacquire the lock */
701 KeEnterCriticalRegion();
702 ExAcquireResourceSharedLite(&IopDatabaseResource
, TRUE
);
704 /* When we released the lock, make sure nobody beat us */
705 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
)
707 /* Someone did, break out */
708 Status
= STATUS_SUCCESS
;
712 /* Start over by setting a failure */
713 Status
= STATUS_UNRECOGNIZED_VOLUME
;
715 /* We need to setup a local list to pickup where we left */
716 LocalList
.Flink
= FsList
->Flink
;
717 ListEntry
= &LocalList
;
721 * Check if we failed with any other error then an unrecognized
722 * volume, and if this request doesn't allow mounting the raw
725 if (!(AllowRawMount
) &&
726 (Status
!= STATUS_UNRECOGNIZED_VOLUME
) &&
727 (FsRtlIsTotalDeviceFailure(Status
)))
729 /* Break out and give up */
734 /* Go to the next FS entry */
735 ListEntry
= ListEntry
->Flink
;
738 /* Dereference the device if we failed */
739 if (!NT_SUCCESS(Status
)) ObDereferenceObject(AttachedDeviceObject
);
741 else if (DeviceObject
->Vpb
->Flags
& VPB_REMOVE_PENDING
)
743 /* Someone wants to remove us */
744 Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
748 /* Someone already mounted us */
749 Status
= STATUS_SUCCESS
;
752 /* Release the FS lock */
753 ExReleaseResourceLite(&IopDatabaseResource
);
754 KeLeaveCriticalRegion();
756 /* Release the device lock if we're holding it */
757 if (!DeviceIsLocked
) KeSetEvent(&DeviceObject
->DeviceLock
, 0, FALSE
);
759 /* Check if we failed to mount the boot partition */
760 if ((!NT_SUCCESS(Status
)) &&
761 (DeviceObject
->Flags
& DO_SYSTEM_BOOT_PARTITION
) &&
762 ExpInitializationPhase
< 2)
764 /* Bugcheck the system */
765 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE
,
766 (ULONG_PTR
)DeviceObject
,
772 /* Return the mount status */
781 IopNotifyAlreadyRegisteredFileSystems(IN PLIST_ENTRY ListHead
,
782 IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine
,
785 PLIST_ENTRY ListEntry
;
786 PDEVICE_OBJECT DeviceObject
;
788 /* Browse the whole list */
789 ListEntry
= ListHead
->Flink
;
790 while (ListEntry
!= ListHead
)
792 /* Check if we reached rawfs and if we have to skip it */
793 if (ListEntry
->Flink
== ListHead
&& SkipRawFs
)
798 /* Otherwise, get DO and notify */
799 DeviceObject
= CONTAINING_RECORD(ListEntry
,
803 DriverNotificationRoutine(DeviceObject
, TRUE
);
805 /* Go to the next entry */
806 ListEntry
= ListEntry
->Flink
;
810 /* PUBLIC FUNCTIONS **********************************************************/
817 IoEnumerateRegisteredFiltersList(OUT PDRIVER_OBJECT
*DriverObjectList
,
818 IN ULONG DriverObjectListSize
,
819 OUT PULONG ActualNumberDriverObjects
)
821 PLIST_ENTRY ListEntry
;
822 NTSTATUS Status
= STATUS_SUCCESS
;
823 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
824 ULONG ListSize
= 0, MaximumSize
= DriverObjectListSize
/ sizeof(PDRIVER_OBJECT
);
826 /* Acquire the FS lock */
827 KeEnterCriticalRegion();
828 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
830 /* Browse the whole list */
831 ListEntry
= IopFsNotifyChangeQueueHead
.Flink
;
832 while (ListEntry
!= &IopFsNotifyChangeQueueHead
)
834 ChangeEntry
= CONTAINING_RECORD(ListEntry
,
835 FS_CHANGE_NOTIFY_ENTRY
,
838 /* If buffer is still big enough */
839 if (ListSize
< MaximumSize
)
841 /* Reference the driver object */
842 ObReferenceObject(ChangeEntry
->DriverObject
);
843 /* And pass it to the caller */
844 DriverObjectList
[ListSize
] = ChangeEntry
->DriverObject
;
848 Status
= STATUS_BUFFER_TOO_SMALL
;
851 /* Increase size counter */
854 /* Go to the next entry */
855 ListEntry
= ListEntry
->Flink
;
858 /* Return list size */
859 *ActualNumberDriverObjects
= ListSize
;
861 /* Release the FS lock */
862 ExReleaseResourceLite(&IopDatabaseResource
);
863 KeLeaveCriticalRegion();
873 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject
,
874 IN BOOLEAN AllowRawMount
)
876 IO_STATUS_BLOCK IoStatusBlock
;
877 PIO_STACK_LOCATION StackPtr
;
880 NTSTATUS Status
, VpbStatus
;
881 PDEVICE_OBJECT FileSystemDeviceObject
;
883 //BOOLEAN WasNotMounted = TRUE;
885 /* Wait on the device lock */
886 Status
= KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
891 ASSERT(Status
== STATUS_SUCCESS
);
893 /* Reference the VPB */
894 if (IopReferenceVerifyVpb(DeviceObject
, &FileSystemDeviceObject
, &Vpb
))
896 /* Initialize the event */
897 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
899 /* Find the actual File System DO */
900 //WasNotMounted = FALSE;
901 FileSystemDeviceObject
= DeviceObject
->Vpb
->DeviceObject
;
902 while (FileSystemDeviceObject
->AttachedDevice
)
904 /* Go to the next one */
905 FileSystemDeviceObject
= FileSystemDeviceObject
->AttachedDevice
;
908 /* Allocate the IRP */
909 Irp
= IoAllocateIrp(FileSystemDeviceObject
->StackSize
, FALSE
);
912 Status
= STATUS_INSUFFICIENT_RESOURCES
;
917 Irp
->UserIosb
= &IoStatusBlock
;
918 Irp
->UserEvent
= &Event
;
919 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
920 Irp
->Flags
= IRP_MOUNT_COMPLETION
| IRP_SYNCHRONOUS_PAGING_IO
;
921 Irp
->RequestorMode
= KernelMode
;
923 /* Get the I/O Stack location and set it */
924 StackPtr
= IoGetNextIrpStackLocation(Irp
);
925 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
926 StackPtr
->MinorFunction
= IRP_MN_VERIFY_VOLUME
;
927 StackPtr
->Flags
= AllowRawMount
? SL_ALLOW_RAW_MOUNT
: 0;
928 StackPtr
->Parameters
.VerifyVolume
.Vpb
= Vpb
;
929 StackPtr
->Parameters
.VerifyVolume
.DeviceObject
=
930 DeviceObject
->Vpb
->DeviceObject
;
932 /* Call the driver */
933 Status
= IoCallDriver(FileSystemDeviceObject
, Irp
);
934 if (Status
== STATUS_PENDING
)
937 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
938 Status
= IoStatusBlock
.Status
;
941 /* Dereference the VPB */
942 IopDereferenceVpbAndFree(Vpb
);
945 /* Check if we had the wrong volume or didn't mount at all */
946 if (Status
== STATUS_WRONG_VOLUME
)
949 VpbStatus
= IopCreateVpb(DeviceObject
);
950 if (NT_SUCCESS(VpbStatus
))
952 PoVolumeDevice(DeviceObject
);
955 VpbStatus
= IopMountVolume(DeviceObject
,
961 /* If we got a new VPB, dereference it */
964 IopInterlockedDecrementUlong(LockQueueIoVpbLock
, &NewVpb
->ReferenceCount
);
968 /* If we failed, remove the verify flag */
969 if (!NT_SUCCESS(VpbStatus
)) DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
973 /* Signal the device lock and return */
974 KeSetEvent(&DeviceObject
->DeviceLock
, IO_NO_INCREMENT
, FALSE
);
983 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
985 PLIST_ENTRY FsList
= NULL
;
988 /* Acquire the FS lock */
989 KeEnterCriticalRegion();
990 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
992 /* Check what kind of FS this is */
993 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
)
995 /* Use the disk list */
996 FsList
= &IopDiskFileSystemQueueHead
;
998 else if (DeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
)
1000 /* Use the network device list */
1001 FsList
= &IopNetworkFileSystemQueueHead
;
1003 else if (DeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
)
1005 /* Use the CD-ROM list */
1006 FsList
= &IopCdRomFileSystemQueueHead
;
1008 else if (DeviceObject
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
)
1010 /* Use the tape list */
1011 FsList
= &IopTapeFileSystemQueueHead
;
1014 /* Make sure that we have a valid list */
1017 /* Check if we should insert it at the top or bottom of the list */
1018 if (DeviceObject
->Flags
& DO_LOW_PRIORITY_FILESYSTEM
)
1021 InsertTailList(FsList
->Blink
, &DeviceObject
->Queue
.ListEntry
);
1026 InsertHeadList(FsList
, &DeviceObject
->Queue
.ListEntry
);
1030 /* Update operations counter */
1031 IopFsRegistrationOps
++;
1033 /* Clear the initializing flag */
1034 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1036 /* Notify file systems of the addition */
1037 IopNotifyFileSystemChange(DeviceObject
, TRUE
);
1039 /* Release the FS Lock */
1040 ExReleaseResourceLite(&IopDatabaseResource
);
1041 KeLeaveCriticalRegion();
1043 /* Ensure driver won't be unloaded */
1044 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
1052 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
1056 /* Acquire the FS lock */
1057 KeEnterCriticalRegion();
1058 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
1060 /* Simply remove the entry - if queued */
1061 if (DeviceObject
->Queue
.ListEntry
.Flink
)
1063 RemoveEntryList(&DeviceObject
->Queue
.ListEntry
);
1066 /* And notify all registered file systems */
1067 IopNotifyFileSystemChange(DeviceObject
, FALSE
);
1069 /* Update operations counter */
1070 IopFsRegistrationOps
++;
1072 /* Then release the lock */
1073 ExReleaseResourceLite(&IopDatabaseResource
);
1074 KeLeaveCriticalRegion();
1076 /* Decrease reference count to allow unload */
1077 IopInterlockedDecrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
1085 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
1086 IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine
)
1088 PFS_CHANGE_NOTIFY_ENTRY Entry
;
1091 /* Acquire the list lock */
1092 KeEnterCriticalRegion();
1093 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
1095 /* Check if that driver is already registered (successive calls)
1096 * See MSDN note: http://msdn.microsoft.com/en-us/library/ff548499%28v=vs.85%29.aspx
1098 if (!IsListEmpty(&IopFsNotifyChangeQueueHead
))
1100 Entry
= CONTAINING_RECORD(IopFsNotifyChangeQueueHead
.Blink
,
1101 FS_CHANGE_NOTIFY_ENTRY
,
1102 FsChangeNotifyList
);
1104 if (Entry
->DriverObject
== DriverObject
&&
1105 Entry
->FSDNotificationProc
== DriverNotificationRoutine
)
1107 /* Release the lock */
1108 ExReleaseResourceLite(&IopDatabaseResource
);
1110 return STATUS_DEVICE_ALREADY_ATTACHED
;
1114 /* Allocate a notification entry */
1115 Entry
= ExAllocatePoolWithTag(PagedPool
,
1116 sizeof(FS_CHANGE_NOTIFY_ENTRY
),
1117 TAG_FS_CHANGE_NOTIFY
);
1120 /* Release the lock */
1121 ExReleaseResourceLite(&IopDatabaseResource
);
1123 return STATUS_INSUFFICIENT_RESOURCES
;
1126 /* Save the driver object and notification routine */
1127 Entry
->DriverObject
= DriverObject
;
1128 Entry
->FSDNotificationProc
= DriverNotificationRoutine
;
1130 /* Insert it into the notification list */
1131 InsertTailList(&IopFsNotifyChangeQueueHead
, &Entry
->FsChangeNotifyList
);
1133 /* Start notifying all already present FS */
1134 IopNotifyAlreadyRegisteredFileSystems(&IopNetworkFileSystemQueueHead
, DriverNotificationRoutine
, FALSE
);
1135 IopNotifyAlreadyRegisteredFileSystems(&IopCdRomFileSystemQueueHead
, DriverNotificationRoutine
, TRUE
);
1136 IopNotifyAlreadyRegisteredFileSystems(&IopDiskFileSystemQueueHead
, DriverNotificationRoutine
, TRUE
);
1137 IopNotifyAlreadyRegisteredFileSystems(&IopTapeFileSystemQueueHead
, DriverNotificationRoutine
, TRUE
);
1139 /* Release the lock */
1140 ExReleaseResourceLite(&IopDatabaseResource
);
1141 KeLeaveCriticalRegion();
1143 /* Reference the driver */
1144 ObReferenceObject(DriverObject
);
1145 return STATUS_SUCCESS
;
1153 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
1154 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
1156 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
1157 PLIST_ENTRY NextEntry
;
1160 /* Acquire the list lock */
1161 KeEnterCriticalRegion();
1162 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
1165 NextEntry
= IopFsNotifyChangeQueueHead
.Flink
;
1166 while (NextEntry
!= &IopFsNotifyChangeQueueHead
)
1169 ChangeEntry
= CONTAINING_RECORD(NextEntry
,
1170 FS_CHANGE_NOTIFY_ENTRY
,
1171 FsChangeNotifyList
);
1173 /* Check if it matches this de-registration */
1174 if ((ChangeEntry
->DriverObject
== DriverObject
) &&
1175 (ChangeEntry
->FSDNotificationProc
== FSDNotificationProc
))
1177 /* It does, remove it from the list */
1178 RemoveEntryList(&ChangeEntry
->FsChangeNotifyList
);
1179 ExFreePoolWithTag(ChangeEntry
, TAG_FS_CHANGE_NOTIFY
);
1183 /* Go to the next entry */
1184 NextEntry
= NextEntry
->Flink
;
1187 /* Release the lock and dereference the driver */
1188 ExReleaseResourceLite(&IopDatabaseResource
);
1189 KeLeaveCriticalRegion();
1191 /* Dereference the driver */
1192 ObDereferenceObject(DriverObject
);
1200 IoAcquireVpbSpinLock(OUT PKIRQL Irql
)
1202 /* Simply acquire the lock */
1203 *Irql
= KeAcquireQueuedSpinLock(LockQueueIoVpbLock
);
1211 IoReleaseVpbSpinLock(IN KIRQL Irql
)
1213 /* Just release the lock */
1214 KeReleaseQueuedSpinLock(LockQueueIoVpbLock
, Irql
);
1222 IoSetSystemPartition(IN PUNICODE_STRING VolumeNameString
)
1225 HANDLE RootHandle
, KeyHandle
;
1226 UNICODE_STRING HKLMSystem
, KeyString
;
1227 WCHAR Buffer
[sizeof(L
"SystemPartition") / sizeof(WCHAR
)];
1229 RtlInitUnicodeString(&HKLMSystem
, L
"\\REGISTRY\\MACHINE\\SYSTEM");
1231 /* Open registry to save data (HKLM\SYSTEM) */
1232 Status
= IopOpenRegistryKeyEx(&RootHandle
, 0, &HKLMSystem
, KEY_ALL_ACCESS
);
1233 if (!NT_SUCCESS(Status
))
1238 /* Create or open Setup subkey */
1239 KeyString
.Buffer
= Buffer
;
1240 KeyString
.Length
= sizeof(L
"Setup") - sizeof(UNICODE_NULL
);
1241 KeyString
.MaximumLength
= sizeof(L
"Setup");
1242 RtlCopyMemory(Buffer
, L
"Setup", sizeof(L
"Setup"));
1243 Status
= IopCreateRegistryKeyEx(&KeyHandle
,
1247 REG_OPTION_NON_VOLATILE
,
1249 ZwClose(RootHandle
);
1250 if (!NT_SUCCESS(Status
))
1255 /* Store caller value */
1256 KeyString
.Length
= sizeof(L
"SystemPartition") - sizeof(UNICODE_NULL
);
1257 KeyString
.MaximumLength
= sizeof(L
"SystemPartition");
1258 RtlCopyMemory(Buffer
, L
"SystemPartition", sizeof(L
"SystemPartition"));
1259 Status
= ZwSetValueKey(KeyHandle
,
1263 VolumeNameString
->Buffer
,
1264 VolumeNameString
->Length
+ sizeof(UNICODE_NULL
));
1275 IoVolumeDeviceToDosName(IN PVOID VolumeDeviceObject
,
1276 OUT PUNICODE_STRING DosName
)
1282 PFILE_OBJECT FileObject
;
1283 PDEVICE_OBJECT DeviceObject
;
1284 IO_STATUS_BLOCK IoStatusBlock
;
1285 UNICODE_STRING MountMgrDevice
;
1286 MOUNTMGR_VOLUME_PATHS VolumePath
;
1287 PMOUNTMGR_VOLUME_PATHS VolumePathPtr
;
1289 * This variable with be required to query device name.
1290 * It's based on MOUNTDEV_NAME (mountmgr.h).
1291 * Doing it that way will prevent dyn memory allocation.
1292 * Device name won't be longer.
1297 WCHAR DeviceName
[256];
1302 /* First step, getting device name */
1303 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1304 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
1305 VolumeDeviceObject
, NULL
, 0,
1306 &DeviceName
, sizeof(DeviceName
),
1307 FALSE
, &Event
, &IoStatusBlock
);
1310 return STATUS_INSUFFICIENT_RESOURCES
;
1313 Status
= IoCallDriver(VolumeDeviceObject
, Irp
);
1314 if (Status
== STATUS_PENDING
)
1316 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1317 Status
= IoStatusBlock
.Status
;
1320 if (!NT_SUCCESS(Status
))
1325 /* Now that we have the device name, we can query the MountMgr
1326 * So, get its device object first.
1328 RtlInitUnicodeString(&MountMgrDevice
, MOUNTMGR_DEVICE_NAME
);
1329 Status
= IoGetDeviceObjectPointer(&MountMgrDevice
, FILE_READ_ATTRIBUTES
,
1330 &FileObject
, &DeviceObject
);
1331 if (!NT_SUCCESS(Status
))
1336 /* Then, use the proper IOCTL to query the DOS name */
1337 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1338 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
,
1339 DeviceObject
, &DeviceName
, sizeof(DeviceName
),
1340 &VolumePath
, sizeof(VolumePath
),
1341 FALSE
, &Event
, &IoStatusBlock
);
1344 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1348 Status
= IoCallDriver(VolumeDeviceObject
, Irp
);
1349 if (Status
== STATUS_PENDING
)
1351 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1352 Status
= IoStatusBlock
.Status
;
1355 /* Only tolerated failure here is buffer too small, which is
1358 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
1363 /* Compute needed size to store DOS name.
1364 * Even if MOUNTMGR_VOLUME_PATHS allows bigger
1365 * name lengths than MAXUSHORT, we can't use
1366 * them, because we have to return this in an UNICODE_STRING
1367 * that stores length on USHORT.
1369 Length
= VolumePath
.MultiSzLength
+ sizeof(VolumePath
);
1370 if (Length
> MAXUSHORT
)
1372 Status
= STATUS_INVALID_BUFFER_SIZE
;
1376 /* Reallocate memory, even in case of success, because
1377 * that's the buffer that will be returned to caller
1379 VolumePathPtr
= ExAllocatePoolWithTag(PagedPool
, Length
, 'D2d ');
1382 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1386 /* Requery DOS path with proper size */
1387 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1388 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
,
1389 DeviceObject
, &DeviceName
, sizeof(DeviceName
),
1390 VolumePathPtr
, Length
,
1391 FALSE
, &Event
, &IoStatusBlock
);
1394 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1398 Status
= IoCallDriver(VolumeDeviceObject
, Irp
);
1399 if (Status
== STATUS_PENDING
)
1401 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1402 Status
= IoStatusBlock
.Status
;
1405 if (!NT_SUCCESS(Status
))
1410 /* Set output string */
1411 DosName
->Length
= (USHORT
)VolumePathPtr
->MultiSzLength
;
1412 DosName
->MaximumLength
= (USHORT
)VolumePathPtr
->MultiSzLength
+ sizeof(UNICODE_NULL
);
1413 /* Our MOUNTMGR_VOLUME_PATHS will be used as output buffer */
1414 DosName
->Buffer
= (PWSTR
)VolumePathPtr
;
1415 /* Move name at the begin, RtlMoveMemory is OK with overlapping */
1416 RtlMoveMemory(DosName
->Buffer
, VolumePathPtr
->MultiSz
, VolumePathPtr
->MultiSzLength
);
1417 DosName
->Buffer
[DosName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1419 /* DON'T release buffer, just dereference FO, and return success */
1420 Status
= STATUS_SUCCESS
;
1424 ExFreePoolWithTag(VolumePathPtr
, 'D2d ');
1427 ObDereferenceObject(FileObject
);