[CMAKE]
[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 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, IoInitFileSystemImplementation)
19 #pragma alloc_text(INIT, IoInitVpbImplementation)
20 #endif
21
22 /* GLOBALS ******************************************************************/
23
24 ERESOURCE FileSystemListLock;
25 LIST_ENTRY IopDiskFsListHead, IopNetworkFsListHead;
26 LIST_ENTRY IopCdRomFsListHead, IopTapeFsListHead;
27 KGUARDED_MUTEX FsChangeNotifyListLock;
28 LIST_ENTRY FsChangeNotifyListHead;
29
30 /* PRIVATE FUNCTIONS *********************************************************/
31
32 PVPB
33 NTAPI
34 IopCheckVpbMounted(IN POPEN_PACKET OpenPacket,
35 IN PDEVICE_OBJECT DeviceObject,
36 IN PUNICODE_STRING RemainingName,
37 OUT PNTSTATUS Status)
38 {
39 BOOLEAN Alertable, Raw;
40 KIRQL OldIrql;
41 PVPB Vpb = NULL;
42
43 /* Lock the VPBs */
44 IoAcquireVpbSpinLock(&OldIrql);
45
46 /* Set VPB mount settings */
47 Raw = !RemainingName->Length && !OpenPacket->RelatedFileObject;
48 Alertable = (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) ?
49 TRUE: FALSE;
50
51 /* Start looping until the VPB is mounted */
52 while (!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
53 {
54 /* Release the lock */
55 IoReleaseVpbSpinLock(OldIrql);
56
57 /* Mount the volume */
58 *Status = IopMountVolume(DeviceObject,
59 Raw,
60 FALSE,
61 Alertable,
62 &Vpb);
63
64 /* Check if we failed or if we were alerted */
65 if (!(NT_SUCCESS(*Status)) ||
66 (*Status == STATUS_USER_APC) ||
67 (*Status == STATUS_ALERTED))
68 {
69 /* Dereference the device, since IopParseDevice referenced it */
70 IopDereferenceDeviceObject(DeviceObject, FALSE);
71
72 /* Check if it was a total failure */
73 if (!NT_SUCCESS(*Status)) return NULL;
74
75 /* Otherwise we were alerted */
76 *Status = STATUS_WRONG_VOLUME;
77 return NULL;
78 }
79
80 /* Re-acquire the lock */
81 IoAcquireVpbSpinLock(&OldIrql);
82 }
83
84 /* Make sure the VPB isn't locked */
85 Vpb = DeviceObject->Vpb;
86 if (Vpb->Flags & VPB_LOCKED)
87 {
88 /* We're locked, so fail */
89 *Status = STATUS_ACCESS_DENIED;
90 Vpb = NULL;
91 }
92 else
93 {
94 /* Success! Reference the VPB */
95 Vpb->ReferenceCount++;
96 }
97
98 /* Release the lock and return the VPB */
99 IoReleaseVpbSpinLock(OldIrql);
100 return Vpb;
101 }
102
103 NTSTATUS
104 NTAPI
105 IopCreateVpb(IN PDEVICE_OBJECT DeviceObject)
106 {
107 PVPB Vpb;
108
109 /* Allocate the Vpb */
110 Vpb = ExAllocatePoolWithTag(NonPagedPool,
111 sizeof(VPB),
112 TAG_VPB);
113 if (!Vpb) return STATUS_UNSUCCESSFUL;
114
115 /* Clear it so we don't waste time manually */
116 RtlZeroMemory(Vpb, sizeof(VPB));
117
118 /* Set the Header and Device Field */
119 Vpb->Type = IO_TYPE_VPB;
120 Vpb->Size = sizeof(VPB);
121 Vpb->RealDevice = DeviceObject;
122
123 /* Link it to the Device Object */
124 DeviceObject->Vpb = Vpb;
125 return STATUS_SUCCESS;
126 }
127
128 VOID
129 NTAPI
130 IopDereferenceVpb(IN PVPB Vpb)
131 {
132 KIRQL OldIrql;
133
134 /* Lock the VPBs and decrease references */
135 IoAcquireVpbSpinLock(&OldIrql);
136 Vpb->ReferenceCount--;
137
138 /* Check if we're out of references */
139 if (!Vpb->ReferenceCount)
140 {
141 /* FIXME: IMPLEMENT CLEANUP! */
142 ASSERT(FALSE);
143 }
144
145 /* Release VPB lock */
146 IoReleaseVpbSpinLock(OldIrql);
147 }
148
149 BOOLEAN
150 NTAPI
151 IopReferenceVpbForVerify(IN PDEVICE_OBJECT DeviceObject,
152 OUT PDEVICE_OBJECT *FileSystemObject,
153 OUT PVPB *Vpb)
154 {
155 KIRQL OldIrql;
156 PVPB LocalVpb;
157 BOOLEAN Result = FALSE;
158
159 /* Lock the VPBs and assume failure */
160 IoAcquireVpbSpinLock(&OldIrql);
161 *Vpb = NULL;
162 *FileSystemObject = NULL;
163
164 /* Get the VPB and make sure it's mounted */
165 LocalVpb = DeviceObject->Vpb;
166 if ((LocalVpb) && (LocalVpb->Flags & VPB_MOUNTED))
167 {
168 /* Return it */
169 *Vpb = LocalVpb;
170 *FileSystemObject = LocalVpb->DeviceObject;
171
172 /* Reference it */
173 LocalVpb->ReferenceCount++;
174 Result = TRUE;
175 }
176
177 /* Release the VPB lock and return status */
178 IoReleaseVpbSpinLock(OldIrql);
179 return Result;
180 }
181
182 PVPB
183 NTAPI
184 IopInitializeVpbForMount(IN PDEVICE_OBJECT DeviceObject,
185 IN PDEVICE_OBJECT AttachedDeviceObject,
186 IN BOOLEAN Raw)
187 {
188 KIRQL OldIrql;
189 PVPB Vpb;
190
191 /* Lock the VPBs */
192 IoAcquireVpbSpinLock(&OldIrql);
193 Vpb = DeviceObject->Vpb;
194
195 /* Set the VPB as mounted and possibly raw */
196 Vpb->Flags |= VPB_MOUNTED | (Raw ? VPB_RAW_MOUNT : 0);
197
198 /* Set the stack size */
199 Vpb->DeviceObject->StackSize = AttachedDeviceObject->StackSize;
200
201 /* Add one for the FS Driver */
202 Vpb->DeviceObject->StackSize++;
203
204 /* Set the VPB in the device extension */
205 IoGetDevObjExtension(Vpb->DeviceObject)->Vpb = Vpb;
206
207 /* Reference it */
208 Vpb->ReferenceCount++;
209
210 /* Release the VPB lock and return it */
211 IoReleaseVpbSpinLock(OldIrql);
212 return Vpb;
213 }
214
215 VOID
216 NTAPI
217 IopNotifyFileSystemChange(IN PDEVICE_OBJECT DeviceObject,
218 IN BOOLEAN DriverActive)
219 {
220 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
221 PLIST_ENTRY ListEntry;
222
223 /* Acquire the notification lock */
224 KeAcquireGuardedMutex(&FsChangeNotifyListLock);
225
226 /* Loop the list */
227 ListEntry = FsChangeNotifyListHead.Flink;
228 while (ListEntry != &FsChangeNotifyListHead)
229 {
230 /* Get the entry */
231 ChangeEntry = CONTAINING_RECORD(ListEntry,
232 FS_CHANGE_NOTIFY_ENTRY,
233 FsChangeNotifyList);
234
235 /* Call the notification procedure */
236 ChangeEntry->FSDNotificationProc(DeviceObject, DriverActive);
237
238 /* Go to the next entry */
239 ListEntry = ListEntry->Flink;
240 }
241
242 /* Release the lock */
243 KeReleaseGuardedMutex(&FsChangeNotifyListLock);
244 }
245
246 VOID
247 NTAPI
248 IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead)
249 {
250 PLIST_ENTRY ListEntry;
251 PDEVICE_OBJECT DeviceObject;
252 IO_STATUS_BLOCK StatusBlock;
253 PIRP Irp;
254 KEVENT Event;
255 NTSTATUS Status;
256
257 /* Lock the FS List and initialize an event to wait on */
258 KeEnterCriticalRegion();
259 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
260 KeInitializeEvent(&Event, NotificationEvent, FALSE);
261
262 /* Get the first entry and start looping */
263 ListEntry = ListHead->Flink;
264 while (ListEntry != ListHead)
265 {
266 /* Get the device object */
267 DeviceObject = CONTAINING_RECORD(ListEntry,
268 DEVICE_OBJECT,
269 Queue.ListEntry);
270
271 /* Check if we're attached */
272 if (DeviceObject->AttachedDevice)
273 {
274 /* Get the attached device */
275 DeviceObject = IoGetAttachedDevice(DeviceObject);
276 }
277
278 /* Build the shutdown IRP and call the driver */
279 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
280 DeviceObject,
281 NULL,
282 0,
283 NULL,
284 &Event,
285 &StatusBlock);
286 Status = IoCallDriver(DeviceObject, Irp);
287 if (Status == STATUS_PENDING)
288 {
289 /* Wait on the driver */
290 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
291 }
292
293 /* Reset the event */
294 KeClearEvent(&Event);
295
296 /* Go to the next entry */
297 ListEntry = ListEntry->Flink;
298 }
299
300 /* Release the lock */
301 ExReleaseResourceLite(&FileSystemListLock);
302 KeLeaveCriticalRegion();
303 }
304
305 VOID
306 NTAPI
307 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
308 {
309 IO_STATUS_BLOCK IoStatusBlock;
310 PIO_STACK_LOCATION StackPtr;
311 KEVENT Event;
312 PIRP Irp;
313 NTSTATUS Status;
314 PDEVICE_OBJECT AttachedDeviceObject = DeviceObject;
315 PAGED_CODE();
316
317 /* Loop as long as we're attached */
318 while (AttachedDeviceObject->AttachedDevice)
319 {
320 /* Get the attached device object */
321 AttachedDeviceObject = AttachedDeviceObject->AttachedDevice;
322 }
323
324 /* Initialize the event and build the IRP */
325 KeInitializeEvent(&Event, NotificationEvent, FALSE);
326 Irp = IoBuildDeviceIoControlRequest(IRP_MJ_DEVICE_CONTROL,
327 AttachedDeviceObject,
328 NULL,
329 0,
330 NULL,
331 0,
332 FALSE,
333 &Event,
334 &IoStatusBlock);
335 if (Irp)
336 {
337 /* Set the major and minor functions */
338 StackPtr = IoGetNextIrpStackLocation(Irp);
339 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
340 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
341
342 /* Call the driver */
343 Status = IoCallDriver(AttachedDeviceObject, Irp);
344 if (Status == STATUS_PENDING)
345 {
346 /* Wait on it */
347 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
348 }
349 }
350 }
351
352 NTSTATUS
353 NTAPI
354 IopMountVolume(IN PDEVICE_OBJECT DeviceObject,
355 IN BOOLEAN AllowRawMount,
356 IN BOOLEAN DeviceIsLocked,
357 IN BOOLEAN Alertable,
358 OUT PVPB *Vpb)
359 {
360 KEVENT Event;
361 NTSTATUS Status;
362 IO_STATUS_BLOCK IoStatusBlock;
363 PIRP Irp;
364 PIO_STACK_LOCATION StackPtr;
365 PLIST_ENTRY FsList, ListEntry;
366 LIST_ENTRY LocalList;
367 PDEVICE_OBJECT AttachedDeviceObject = DeviceObject;
368 PDEVICE_OBJECT FileSystemDeviceObject, ParentFsDeviceObject;
369 ULONG FsStackOverhead;
370 PAGED_CODE();
371
372 /* Check if the device isn't already locked */
373 if (!DeviceIsLocked)
374 {
375 /* Lock it ourselves */
376 Status = KeWaitForSingleObject(&DeviceObject->DeviceLock,
377 Executive,
378 KeGetPreviousMode(),
379 Alertable,
380 NULL);
381 if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
382 {
383 /* Don't mount if we were interrupted */
384 return Status;
385 }
386 }
387
388 /* Acquire the FS Lock*/
389 KeEnterCriticalRegion();
390 ExAcquireResourceSharedLite(&FileSystemListLock, TRUE);
391
392 /* Make sure we weren't already mounted */
393 if (!(DeviceObject->Vpb->Flags & (VPB_MOUNTED | VPB_REMOVE_PENDING)))
394 {
395 /* Initialize the event to wait on */
396 KeInitializeEvent(&Event, NotificationEvent, FALSE);
397
398 /* Remove the verify flag and get the actual device to mount */
399 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
400 while (AttachedDeviceObject->AttachedDevice)
401 {
402 /* Get the next one */
403 AttachedDeviceObject = AttachedDeviceObject->AttachedDevice;
404 }
405
406 /* Reference it */
407 ObReferenceObject(AttachedDeviceObject);
408
409 /* For a mount operation, this can only be a Disk, CD-ROM or tape */
410 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) ||
411 (DeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK))
412 {
413 /* Use the disk list */
414 FsList = &IopDiskFsListHead;
415 }
416 else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM)
417 {
418 /* Use the CD-ROM list */
419 FsList = &IopCdRomFsListHead;
420 }
421 else
422 {
423 /* It's gotta be a tape... */
424 FsList = &IopTapeFsListHead;
425 }
426
427 /* Now loop the fs list until one of the file systems accepts us */
428 Status = STATUS_UNSUCCESSFUL;
429 ListEntry = FsList->Flink;
430 while ((ListEntry != FsList) && !(NT_SUCCESS(Status)))
431 {
432 /*
433 * If we're not allowed to mount this volume and this is our last
434 * (but not only) chance to mount it...
435 */
436 if (!(AllowRawMount) &&
437 (ListEntry->Flink == FsList) &&
438 (ListEntry != FsList->Flink))
439 {
440 /* Then fail this mount request */
441 break;
442 }
443
444 /*
445 * Also check if this is a raw mount and there are other file
446 * systems on the list.
447 */
448 if ((DeviceObject->Vpb->Flags & VPB_RAW_MOUNT) &&
449 (ListEntry->Flink != FsList))
450 {
451 /* Then skip this entry */
452 continue;
453 }
454
455 /* Get the Device Object for this FS */
456 FileSystemDeviceObject = CONTAINING_RECORD(ListEntry,
457 DEVICE_OBJECT,
458 Queue.ListEntry);
459 ParentFsDeviceObject = FileSystemDeviceObject;
460
461 /*
462 * If this file system device is attached to some other device,
463 * then we must make sure to increase the stack size for the IRP.
464 * The default is +1, for the FS device itself.
465 */
466 FsStackOverhead = 1;
467 while (FileSystemDeviceObject->AttachedDevice)
468 {
469 /* Get the next attached device and increase overhead */
470 FileSystemDeviceObject = FileSystemDeviceObject->
471 AttachedDevice;
472 FsStackOverhead++;
473 }
474
475 /* Clear the event */
476 KeClearEvent(&Event);
477
478 /* Allocate the IRP */
479 Irp = IoAllocateIrp(AttachedDeviceObject->StackSize +
480 (UCHAR)FsStackOverhead,
481 TRUE);
482 if (!Irp)
483 {
484 /* Fail */
485 Status = STATUS_INSUFFICIENT_RESOURCES;
486 break;
487 }
488
489 /* Setup the IRP */
490 Irp->UserIosb = &IoStatusBlock;
491 Irp->UserEvent = &Event;
492 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
493 Irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO;
494 Irp->RequestorMode = KernelMode;
495
496 /* Get the I/O Stack location and set it up */
497 StackPtr = IoGetNextIrpStackLocation(Irp);
498 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
499 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
500 StackPtr->Flags = AllowRawMount;
501 StackPtr->Parameters.MountVolume.Vpb = DeviceObject->Vpb;
502 StackPtr->Parameters.MountVolume.DeviceObject =
503 AttachedDeviceObject;
504
505 /* Call the driver */
506 Status = IoCallDriver(FileSystemDeviceObject, Irp);
507 if (Status == STATUS_PENDING)
508 {
509 /* Wait on it */
510 KeWaitForSingleObject(&Event,
511 Executive,
512 KernelMode,
513 FALSE,
514 NULL);
515 Status = IoStatusBlock.Status;
516 }
517
518 /* Check if mounting was successful */
519 if (NT_SUCCESS(Status))
520 {
521 /* Mount the VPB */
522 *Vpb = IopInitializeVpbForMount(DeviceObject,
523 AttachedDeviceObject,
524 (DeviceObject->Vpb->Flags &
525 VPB_RAW_MOUNT));
526 }
527 else
528 {
529 /* Check if we failed because of the user */
530 if ((IoIsErrorUserInduced(Status)) &&
531 (IoStatusBlock.Information == 1))
532 {
533 /* Break out and fail */
534 break;
535 }
536
537 /* Otherwise, check if we need to load the FS driver */
538 if (Status == STATUS_FS_DRIVER_REQUIRED)
539 {
540 /* We need to release the lock */
541 ExReleaseResourceLite(&FileSystemListLock);
542
543 /* Release the device lock if we're holding it */
544 if (!DeviceIsLocked)
545 {
546 KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE);
547 }
548
549 /* Load the FS */
550 IopLoadFileSystem(ParentFsDeviceObject);
551
552 /* Check if the device isn't already locked */
553 if (!DeviceIsLocked)
554 {
555 /* Lock it ourselves */
556 Status = KeWaitForSingleObject(&DeviceObject->
557 DeviceLock,
558 Executive,
559 KeGetPreviousMode(),
560 Alertable,
561 NULL);
562 if ((Status == STATUS_ALERTED) ||
563 (Status == STATUS_USER_APC))
564 {
565 /* Don't mount if we were interrupted */
566 ObDereferenceObject(AttachedDeviceObject);
567 return Status;
568 }
569 }
570
571 /* Reacquire the lock */
572 ExAcquireResourceSharedLite(&FileSystemListLock, TRUE);
573
574 /* When we released the lock, make sure nobody beat us */
575 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
576 {
577 /* Someone did, break out */
578 Status = STATUS_SUCCESS;
579 break;
580 }
581
582 /* Start over by setting a failure */
583 Status = STATUS_UNRECOGNIZED_VOLUME;
584
585 /* We need to setup a local list to pickup where we left */
586 LocalList.Flink = FsList->Flink;
587 ListEntry = &LocalList;
588 }
589
590 /*
591 * Check if we failed with any other error then an unrecognized
592 * volume, and if this request doesn't allow mounting the raw
593 * file system.
594 */
595 if (!(AllowRawMount) &&
596 (Status != STATUS_UNRECOGNIZED_VOLUME) &&
597 (FsRtlIsTotalDeviceFailure(Status)))
598 {
599 /* Break out and give up */
600 break;
601 }
602 }
603
604 /* Go to the next FS entry */
605 ListEntry = ListEntry->Flink;
606 }
607
608 /* Dereference the device if we failed */
609 if (!NT_SUCCESS(Status)) ObDereferenceObject(AttachedDeviceObject);
610 }
611 else if (DeviceObject->Vpb->Flags & VPB_REMOVE_PENDING)
612 {
613 /* Someone wants to remove us */
614 Status = STATUS_DEVICE_DOES_NOT_EXIST;
615 }
616 else
617 {
618 /* Someone already mounted us */
619 Status = STATUS_SUCCESS;
620 }
621
622 /* Release the FS lock */
623 ExReleaseResourceLite(&FileSystemListLock);
624 KeLeaveCriticalRegion();
625
626 /* Release the device lock if we're holding it */
627 if (!DeviceIsLocked) KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE);
628
629 /* Check if we failed to mount the boot partition */
630 if ((!NT_SUCCESS(Status)) &&
631 (DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION))
632 {
633 /* Bugcheck the system */
634 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE,
635 (ULONG_PTR)DeviceObject,
636 Status,
637 0,
638 0);
639 }
640
641 /* Return the mount status */
642 return Status;
643 }
644
645 /* PUBLIC FUNCTIONS **********************************************************/
646
647 /*
648 * @unimplemented
649 */
650 NTSTATUS
651 NTAPI
652 IoEnumerateRegisteredFiltersList(IN PDRIVER_OBJECT *DriverObjectList,
653 IN ULONG DriverObjectListSize,
654 OUT PULONG ActualNumberDriverObjects)
655 {
656 UNIMPLEMENTED;
657 return STATUS_UNSUCCESSFUL;
658 }
659
660 /*
661 * @implemented
662 */
663 NTSTATUS
664 NTAPI
665 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
666 IN BOOLEAN AllowRawMount)
667 {
668 IO_STATUS_BLOCK IoStatusBlock;
669 PIO_STACK_LOCATION StackPtr;
670 KEVENT Event;
671 PIRP Irp;
672 NTSTATUS Status = STATUS_SUCCESS, VpbStatus;
673 PDEVICE_OBJECT FileSystemDeviceObject;
674 PVPB Vpb, NewVpb;
675 BOOLEAN WasNotMounted = TRUE;
676
677 /* Wait on the device lock */
678 KeWaitForSingleObject(&DeviceObject->DeviceLock,
679 Executive,
680 KernelMode,
681 FALSE,
682 NULL);
683
684 /* Reference the VPB */
685 if (IopReferenceVpbForVerify(DeviceObject, &FileSystemDeviceObject, &Vpb))
686 {
687 /* Initialize the event */
688 KeInitializeEvent(&Event, NotificationEvent, FALSE);
689
690 /* Find the actual File System DO */
691 WasNotMounted = FALSE;
692 FileSystemDeviceObject = DeviceObject->Vpb->DeviceObject;
693 while (FileSystemDeviceObject->AttachedDevice)
694 {
695 /* Go to the next one */
696 FileSystemDeviceObject = FileSystemDeviceObject->AttachedDevice;
697 }
698
699 /* Allocate the IRP */
700 Irp = IoAllocateIrp(FileSystemDeviceObject->StackSize, FALSE);
701 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
702
703 /* Set it up */
704 Irp->UserIosb = &IoStatusBlock;
705 Irp->UserEvent = &Event;
706 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
707 Irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO;
708 Irp->RequestorMode = KernelMode;
709
710 /* Get the I/O Stack location and set it */
711 StackPtr = IoGetNextIrpStackLocation(Irp);
712 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
713 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
714 StackPtr->Flags = AllowRawMount ? SL_ALLOW_RAW_MOUNT : 0;
715 StackPtr->Parameters.VerifyVolume.Vpb = Vpb;
716 StackPtr->Parameters.VerifyVolume.DeviceObject =
717 DeviceObject->Vpb->DeviceObject;
718
719 /* Call the driver */
720 Status = IoCallDriver(FileSystemDeviceObject, Irp);
721 if (Status == STATUS_PENDING)
722 {
723 /* Wait on it */
724 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
725 Status = IoStatusBlock.Status;
726 }
727
728 /* Dereference the VPB */
729 IopDereferenceVpb(Vpb);
730 }
731
732 /* Check if we had the wrong volume or didn't mount at all */
733 if ((Status == STATUS_WRONG_VOLUME) || (WasNotMounted))
734 {
735 /* Create a VPB */
736 VpbStatus = IopCreateVpb(DeviceObject);
737 if (NT_SUCCESS(VpbStatus))
738 {
739 /* Mount it */
740 VpbStatus = IopMountVolume(DeviceObject,
741 AllowRawMount,
742 TRUE,
743 FALSE,
744 &NewVpb);
745 }
746
747 /* If we failed, remove the verify flag */
748 if (!NT_SUCCESS(VpbStatus)) DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
749 }
750
751 /* Signal the device lock and return */
752 KeSetEvent(&DeviceObject->DeviceLock, IO_NO_INCREMENT, FALSE);
753 return Status;
754 }
755
756 /*
757 * @implemented
758 */
759 VOID
760 NTAPI
761 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
762 {
763 PLIST_ENTRY FsList = NULL;
764 PAGED_CODE();
765
766 /* Acquire the FS lock */
767 KeEnterCriticalRegion();
768 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
769
770 /* Check what kind of FS this is */
771 if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM)
772 {
773 /* Use the disk list */
774 FsList = &IopDiskFsListHead;
775 }
776 else if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
777 {
778 /* Use the network device list */
779 FsList = &IopNetworkFsListHead;
780 }
781 else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)
782 {
783 /* Use the CD-ROM list */
784 FsList = &IopCdRomFsListHead;
785 }
786 else if (DeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM)
787 {
788 /* Use the tape list */
789 FsList = &IopTapeFsListHead;
790 }
791
792 /* Make sure that we have a valid list */
793 if (FsList)
794 {
795 /* Check if we should insert it at the top or bottom of the list */
796 if (DeviceObject->Flags & DO_LOW_PRIORITY_FILESYSTEM)
797 {
798 /* At the bottom */
799 InsertTailList(FsList->Blink, &DeviceObject->Queue.ListEntry);
800 }
801 else
802 {
803 /* On top */
804 InsertHeadList(FsList, &DeviceObject->Queue.ListEntry);
805 }
806 }
807
808 /* Clear the initializing flag */
809 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
810
811 /* Release the FS Lock */
812 ExReleaseResourceLite(&FileSystemListLock);
813 KeLeaveCriticalRegion();
814
815 /* Notify file systems of the addition */
816 IopNotifyFileSystemChange(DeviceObject, TRUE);
817 }
818
819 /*
820 * @implemented
821 */
822 VOID
823 NTAPI
824 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
825 {
826 PAGED_CODE();
827
828 /* Acquire the FS lock */
829 KeEnterCriticalRegion();
830 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
831
832 /* Simply remove the entry */
833 RemoveEntryList(&DeviceObject->Queue.ListEntry);
834
835 /* And notify all registered file systems */
836 IopNotifyFileSystemChange(DeviceObject, FALSE);
837
838 /* Then release the lock */
839 ExReleaseResourceLite(&FileSystemListLock);
840 KeLeaveCriticalRegion();
841 }
842
843 /*
844 * @implemented
845 */
846 NTSTATUS
847 NTAPI
848 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
849 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc)
850 {
851 PFS_CHANGE_NOTIFY_ENTRY Entry;
852 PAGED_CODE();
853
854 /* Allocate a notification entry */
855 Entry = ExAllocatePoolWithTag(PagedPool,
856 sizeof(FS_CHANGE_NOTIFY_ENTRY),
857 TAG_FS_CHANGE_NOTIFY);
858 if (!Entry) return(STATUS_INSUFFICIENT_RESOURCES);
859
860 /* Save the driver object and notification routine */
861 Entry->DriverObject = DriverObject;
862 Entry->FSDNotificationProc = FSDNotificationProc;
863
864 /* Insert it into the notification list */
865 KeAcquireGuardedMutex(&FsChangeNotifyListLock);
866 InsertTailList(&FsChangeNotifyListHead, &Entry->FsChangeNotifyList);
867 KeReleaseGuardedMutex(&FsChangeNotifyListLock);
868
869 /* Reference the driver */
870 ObReferenceObject(DriverObject);
871 return STATUS_SUCCESS;
872 }
873
874 /*
875 * @implemented
876 */
877 VOID
878 NTAPI
879 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
880 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc)
881 {
882 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
883 PLIST_ENTRY NextEntry;
884 PAGED_CODE();
885
886 /* Acquire the list lock */
887 KeAcquireGuardedMutex(&FsChangeNotifyListLock);
888
889 /* Loop the list */
890 NextEntry = FsChangeNotifyListHead.Flink;
891 while (NextEntry != &FsChangeNotifyListHead)
892 {
893 /* Get the entry */
894 ChangeEntry = CONTAINING_RECORD(NextEntry,
895 FS_CHANGE_NOTIFY_ENTRY,
896 FsChangeNotifyList);
897
898 /* Check if it matches this de-registration */
899 if ((ChangeEntry->DriverObject == DriverObject) &&
900 (ChangeEntry->FSDNotificationProc == FSDNotificationProc))
901 {
902 /* It does, remove it from the list */
903 RemoveEntryList(&ChangeEntry->FsChangeNotifyList);
904 ExFreePoolWithTag(ChangeEntry, TAG_FS_CHANGE_NOTIFY);
905 break;
906 }
907
908 /* Go to the next entry */
909 NextEntry = NextEntry->Flink;
910 }
911
912 /* Release the lock and dereference the driver */
913 KeReleaseGuardedMutex(&FsChangeNotifyListLock);
914 ObDereferenceObject(DriverObject);
915 }
916
917 /*
918 * @implemented
919 */
920 VOID
921 NTAPI
922 IoAcquireVpbSpinLock(OUT PKIRQL Irql)
923 {
924 /* Simply acquire the lock */
925 *Irql = KeAcquireQueuedSpinLock(LockQueueIoVpbLock);
926 }
927
928 /*
929 * @implemented
930 */
931 VOID
932 NTAPI
933 IoReleaseVpbSpinLock(IN KIRQL Irql)
934 {
935 /* Just release the lock */
936 KeReleaseQueuedSpinLock(LockQueueIoVpbLock, Irql);
937 }
938
939 /*
940 * @unimplemented
941 */
942 NTSTATUS
943 NTAPI
944 IoSetSystemPartition(IN PUNICODE_STRING VolumeNameString)
945 {
946 UNIMPLEMENTED;
947 return STATUS_NOT_IMPLEMENTED;
948 }
949
950 /*
951 * @unimplemented
952 */
953 NTSTATUS
954 NTAPI
955 IoVolumeDeviceToDosName(IN PVOID VolumeDeviceObject,
956 OUT PUNICODE_STRING DosName)
957 {
958 UNIMPLEMENTED;
959 return STATUS_NOT_IMPLEMENTED;
960 }
961
962 /* EOF */