IopMountFileSystem(): Cosmetic fix of debug message typo
[reactos.git] / ntoskrnl / io / fs.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/io/fs.c
6  * PURPOSE:         Filesystem functions
7  * PROGRAMMER:      David Welch (welch@mcmail.com)
8  * UPDATE HISTORY:
9  *                  Created 22/05/98
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/io.h>
16 #include <internal/ps.h>
17 #include <internal/pool.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22
23 /* TYPES *******************************************************************/
24
25 typedef struct _FILE_SYSTEM_OBJECT
26 {
27   PDEVICE_OBJECT DeviceObject;
28   LIST_ENTRY Entry;
29 } FILE_SYSTEM_OBJECT, *PFILE_SYSTEM_OBJECT;
30
31 typedef struct _FS_CHANGE_NOTIFY_ENTRY
32 {
33   LIST_ENTRY FsChangeNotifyList;
34   PDRIVER_OBJECT DriverObject;
35   PFSDNOTIFICATIONPROC FSDNotificationProc;
36 } FS_CHANGE_NOTIFY_ENTRY, *PFS_CHANGE_NOTIFY_ENTRY;
37
38
39 /* GLOBALS ******************************************************************/
40
41 static KSPIN_LOCK FileSystemListLock;
42 static LIST_ENTRY FileSystemListHead;
43
44 #ifndef LIBCAPTIVE
45 static KSPIN_LOCK FsChangeNotifyListLock;
46 static LIST_ENTRY FsChangeNotifyListHead;
47 #endif /* LIBCAPTIVE */
48
49 #define TAG_FILE_SYSTEM       TAG('F', 'S', 'Y', 'S')
50 #ifndef LIBCAPTIVE
51 #define TAG_FS_CHANGE_NOTIFY  TAG('F', 'S', 'C', 'N')
52
53
54 static VOID
55 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
56                           BOOLEAN DriverActive);
57 #endif /* LIBCAPTIVE */
58
59
60 /* FUNCTIONS *****************************************************************/
61
62 #ifndef LIBCAPTIVE
63
64 NTSTATUS STDCALL
65 NtFsControlFile (
66         IN      HANDLE                  DeviceHandle,
67         IN      HANDLE                  EventHandle     OPTIONAL, 
68         IN      PIO_APC_ROUTINE         ApcRoutine      OPTIONAL, 
69         IN      PVOID                   ApcContext      OPTIONAL, 
70         OUT     PIO_STATUS_BLOCK        IoStatusBlock, 
71         IN      ULONG                   IoControlCode,
72         IN      PVOID                   InputBuffer, 
73         IN      ULONG                   InputBufferSize,
74         OUT     PVOID                   OutputBuffer,
75         IN      ULONG                   OutputBufferSize
76         )
77 {
78    NTSTATUS Status;
79    PFILE_OBJECT FileObject;
80    PDEVICE_OBJECT DeviceObject;
81    PIRP Irp;
82    PIO_STACK_LOCATION StackPtr;
83    PKEVENT ptrEvent;
84    IO_STATUS_BLOCK IoSB;
85
86    DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
87           "ApcContext %x IoStatusBlock %x IoControlCode %x "
88           "InputBuffer %x InputBufferSize %x OutputBuffer %x "
89           "OutputBufferSize %x)\n",
90           DeviceHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,
91           IoControlCode,InputBuffer,InputBufferSize,OutputBuffer,
92           OutputBufferSize);
93
94    Status = ObReferenceObjectByHandle(DeviceHandle,
95                                       FILE_READ_DATA | FILE_WRITE_DATA,
96                                       NULL,
97                                       KernelMode,
98                                       (PVOID *) &FileObject,
99                                       NULL);
100    
101    if (!NT_SUCCESS(Status))
102      {
103         return(Status);
104      }
105
106    if (EventHandle != NULL)
107      {
108         Status = ObReferenceObjectByHandle (EventHandle,
109                                             SYNCHRONIZE,
110                                             ExEventObjectType,
111                                             UserMode,
112                                             (PVOID*)&ptrEvent,
113                                             NULL);
114         if (!NT_SUCCESS(Status))
115           {
116             ObDereferenceObject(FileObject);
117             return Status;
118           }
119       }
120     else
121       {
122          KeResetEvent (&FileObject->Event);
123          ptrEvent = &FileObject->Event;
124       }
125
126    
127    DeviceObject = FileObject->DeviceObject;
128
129    Irp = IoBuildDeviceIoControlRequest(IoControlCode,
130                                        DeviceObject,
131                                        InputBuffer,
132                                        InputBufferSize,
133                                        OutputBuffer,
134                                        OutputBufferSize,
135                                        FALSE,
136                                        ptrEvent,
137                                        &IoSB);
138    
139    Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
140    Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
141
142    StackPtr = IoGetNextIrpStackLocation(Irp);
143    StackPtr->FileObject = FileObject;
144    StackPtr->DeviceObject = DeviceObject;
145    StackPtr->Parameters.FileSystemControl.InputBufferLength = InputBufferSize;
146    StackPtr->Parameters.FileSystemControl.OutputBufferLength = 
147      OutputBufferSize;
148    StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
149    
150    Status = IoCallDriver(DeviceObject,Irp);
151    if (Status == STATUS_PENDING && !(FileObject->Flags & FO_SYNCHRONOUS_IO))
152      {
153         KeWaitForSingleObject(ptrEvent,Executive,KernelMode,FALSE,NULL);
154         Status = IoSB.Status;
155      }
156    if (IoStatusBlock)
157      {
158         *IoStatusBlock = IoSB;
159      }
160    return(Status);
161 }
162
163 #endif /* LIBCAPTIVE */
164
165 VOID
166 IoInitFileSystemImplementation(VOID)
167 {
168   InitializeListHead(&FileSystemListHead);
169   KeInitializeSpinLock(&FileSystemListLock);
170
171 #ifndef LIBCAPTIVE
172   InitializeListHead(&FsChangeNotifyListHead);
173   KeInitializeSpinLock(&FsChangeNotifyListLock);
174 #endif /* LIBCAPTIVE */
175 }
176
177
178 VOID
179 IoShutdownRegisteredFileSystems(VOID)
180 {
181    KIRQL oldlvl;
182    PLIST_ENTRY current_entry;
183    FILE_SYSTEM_OBJECT* current,*current_last=NULL;
184    PIRP Irp;
185    KEVENT Event;
186    IO_STATUS_BLOCK IoStatusBlock;
187    NTSTATUS Status;
188
189    DPRINT("IoShutdownRegisteredFileSystems()\n");
190
191 #ifndef LIBCAPTIVE
192    /* filesystems cannot be called at DISPATCH_LEVEL */
193    KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
194 #endif /* LIBCAPTIVE */
195    KeInitializeEvent(&Event,NotificationEvent,FALSE);
196
197    /* 'current' will get IoDeleteDevice()ed by IRP_MJ_SHUTDOWN! */
198    while ((current_entry = FileSystemListHead.Flink)!=(&FileSystemListHead))
199      {
200         current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
201         if (current==current_last)
202           {
203             /* At least ntfs.sys-NT5.1sp1 appears to not to unregister itself.
204              * It does not import symbol IoUnregisterFileSystem() at all!
205              * BTW also ext2fsd.sys<=v0.10A also forgets to call IoUnregisterFileSystem().
206              */
207             DPRINT("IoShutdownRegisteredFileSystems(): WARNING: filesystem forgot to call IoUnregisterFileSystem() !!!\n");
208             IoUnregisterFileSystem(current->DeviceObject);
209             continue;
210           }
211         current_last=current;
212
213         /* send IRP_MJ_SHUTDOWN */
214         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
215                                            current->DeviceObject,
216                                            NULL,
217                                            0,
218                                            0,
219                                            &Event,
220                                            &IoStatusBlock);
221
222         Status = IoCallDriver(current->DeviceObject,Irp);
223         if (Status==STATUS_PENDING)
224           {
225              KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
226           }
227      }
228
229 #ifndef LIBCAPTIVE
230    /* filesystems cannot be called at DISPATCH_LEVEL */
231    KeReleaseSpinLock(&FileSystemListLock,oldlvl);
232 #endif /* LIBCAPTIVE */
233 }
234
235
236 static NTSTATUS
237 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
238                    PDEVICE_OBJECT DeviceToMount)
239 {
240   IO_STATUS_BLOCK IoStatusBlock;
241   PIO_STACK_LOCATION StackPtr;
242   PKEVENT Event;
243   PIRP Irp;
244   NTSTATUS Status;
245
246   DPRINT("IopMountFileSystem(DeviceObject %x, DeviceToMount %x)\n",
247          DeviceObject,DeviceToMount);
248
249   assert_irql(PASSIVE_LEVEL);
250   Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
251   if (Event == NULL)
252     {
253       return(STATUS_INSUFFICIENT_RESOURCES);
254     }
255   KeInitializeEvent(Event, NotificationEvent, FALSE);
256
257   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
258   if (Irp==NULL)
259     {
260       ExFreePool(Event);
261       return(STATUS_INSUFFICIENT_RESOURCES);
262     }
263
264   Irp->UserIosb = &IoStatusBlock;
265   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
266   Irp->UserEvent = Event;
267   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
268
269   StackPtr = IoGetNextIrpStackLocation(Irp);
270   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
271   StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
272   StackPtr->Flags = 0;
273   StackPtr->Control = 0;
274   StackPtr->DeviceObject = DeviceObject;
275   StackPtr->FileObject = NULL;
276   StackPtr->CompletionRoutine = NULL;
277
278   StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
279   StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
280
281   Status = IoCallDriver(DeviceObject,Irp);
282   if (Status==STATUS_PENDING)
283     {
284       KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
285       Status = IoStatusBlock.Status;
286     }
287
288   ExFreePool(Event);
289
290   return(Status);
291 }
292
293
294 static NTSTATUS
295 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
296 {
297   IO_STATUS_BLOCK IoStatusBlock;
298   PIO_STACK_LOCATION StackPtr;
299   PKEVENT Event;
300   PIRP Irp;
301   NTSTATUS Status;
302
303   DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
304
305   assert_irql(PASSIVE_LEVEL);
306   Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
307   if (Event == NULL)
308     {
309       return(STATUS_INSUFFICIENT_RESOURCES);
310     }
311   KeInitializeEvent(Event, NotificationEvent, FALSE);
312
313   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
314   if (Irp==NULL)
315     {
316       ExFreePool(Event);
317       return(STATUS_INSUFFICIENT_RESOURCES);
318     }
319
320   Irp->UserIosb = &IoStatusBlock;
321   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
322   Irp->UserEvent = Event;
323   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
324
325   StackPtr = IoGetNextIrpStackLocation(Irp);
326   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
327   StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
328   StackPtr->Flags = 0;
329   StackPtr->Control = 0;
330   StackPtr->DeviceObject = DeviceObject;
331   StackPtr->FileObject = NULL;
332   StackPtr->CompletionRoutine = NULL;
333
334   Status = IoCallDriver(DeviceObject,Irp);
335   if (Status==STATUS_PENDING)
336     {
337       KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
338       Status = IoStatusBlock.Status;
339     }
340
341   ExFreePool(Event);
342
343   return(Status);
344 }
345
346
347 NTSTATUS
348 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
349               IN BOOLEAN AllowRawMount)
350 /*
351  * FUNCTION: Mounts a logical volume
352  * ARGUMENTS:
353  *         DeviceObject = Device to mount
354  * RETURNS: Status
355  */
356 {
357   KIRQL oldlvl;
358   PLIST_ENTRY current_entry;
359   FILE_SYSTEM_OBJECT* current;
360   NTSTATUS Status;
361   DEVICE_TYPE MatchingDeviceType;
362
363   assert_irql(PASSIVE_LEVEL);
364
365   DPRINT("IoMountVolume(DeviceObject %x  AllowRawMount %x)\n",
366          DeviceObject, AllowRawMount);
367
368   switch (DeviceObject->DeviceType)
369     {
370       case FILE_DEVICE_DISK:
371       case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
372         MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
373         break;
374
375       case FILE_DEVICE_CD_ROM:
376         MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
377         break;
378
379       case FILE_DEVICE_NETWORK:
380         MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
381         break;
382
383       case FILE_DEVICE_TAPE:
384         MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
385         break;
386
387       default:
388         CPRINT("No matching file system type found for device type: %x\n",
389                DeviceObject->DeviceType);
390         return(STATUS_UNRECOGNIZED_VOLUME);
391     }
392
393   KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
394   current_entry = FileSystemListHead.Flink;
395   while (current_entry!=(&FileSystemListHead))
396     {
397       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
398       if (current->DeviceObject->DeviceType != MatchingDeviceType)
399         {
400           current_entry = current_entry->Flink;
401           continue;
402         }
403       KeReleaseSpinLock(&FileSystemListLock,oldlvl);
404       Status = IopMountFileSystem(current->DeviceObject,
405                                   DeviceObject);
406       KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
407       switch (Status)
408         {
409           case STATUS_FS_DRIVER_REQUIRED:
410             KeReleaseSpinLock(&FileSystemListLock,oldlvl);
411             Status = IopLoadFileSystem(current->DeviceObject);
412             if (!NT_SUCCESS(Status))
413               {
414                 return(Status);
415               }
416             KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
417             current_entry = FileSystemListHead.Flink;
418             continue;
419
420           case STATUS_SUCCESS:
421             DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
422                                        VPB_MOUNTED;
423             KeReleaseSpinLock(&FileSystemListLock,oldlvl);
424             return(STATUS_SUCCESS);
425
426           case STATUS_UNRECOGNIZED_VOLUME:
427           default:
428             current_entry = current_entry->Flink;
429         }
430     }
431   KeReleaseSpinLock(&FileSystemListLock,oldlvl);
432
433   return(STATUS_UNRECOGNIZED_VOLUME);
434 }
435
436 #ifndef LIBCAPTIVE
437
438 /**********************************************************************
439  * NAME                                                 EXPORTED
440  *      IoVerifyVolume
441  *
442  * DESCRIPTION
443  *      Verify the file system type and volume information or mount
444  *      a file system.
445  *
446  * ARGUMENTS
447  *      DeviceObject
448  *              Device to verify or mount
449  *
450  *      AllowRawMount
451  *              ...
452  *
453  * RETURN VALUE
454  *      Status
455  */
456 NTSTATUS STDCALL
457 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
458                IN BOOLEAN AllowRawMount)
459 {
460   IO_STATUS_BLOCK IoStatusBlock;
461   PIO_STACK_LOCATION StackPtr;
462   PKEVENT Event;
463   PIRP Irp;
464   NTSTATUS Status;
465
466   DPRINT("IoVerifyVolume(DeviceObject %x  AllowRawMount %x)\n",
467          DeviceObject, AllowRawMount);
468
469   Status = STATUS_SUCCESS;
470
471   KeWaitForSingleObject(&DeviceObject->DeviceLock,
472                         Executive,
473                         KernelMode,
474                         FALSE,
475                         NULL);
476
477   DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
478
479   if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
480     {
481       /* Issue verify request to the FSD */
482       Event = ExAllocatePool(NonPagedPool,
483                              sizeof(KEVENT));
484       if (Event == NULL)
485         return(STATUS_INSUFFICIENT_RESOURCES);
486
487       KeInitializeEvent(Event,
488                         NotificationEvent,
489                         FALSE);
490
491       Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
492       if (Irp==NULL)
493         {
494           ExFreePool(Event);
495           return(STATUS_INSUFFICIENT_RESOURCES);
496         }
497
498       Irp->UserIosb = &IoStatusBlock;
499       Irp->UserEvent = Event;
500       Irp->Tail.Overlay.Thread = PsGetCurrentThread();
501
502       StackPtr = IoGetNextIrpStackLocation(Irp);
503       StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
504       StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
505       StackPtr->Flags = 0;
506       StackPtr->Control = 0;
507       StackPtr->DeviceObject = DeviceObject;
508       StackPtr->FileObject = NULL;
509       StackPtr->CompletionRoutine = NULL;
510
511       StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
512       StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
513
514       Status = IoCallDriver(DeviceObject,
515                             Irp);
516       if (Status==STATUS_PENDING)
517         {
518           KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
519           Status = IoStatusBlock.Status;
520         }
521       ExFreePool(Event);
522
523       if (NT_SUCCESS(Status))
524         {
525           KeSetEvent(&DeviceObject->DeviceLock,
526                      IO_NO_INCREMENT,
527                      FALSE);
528           return(STATUS_SUCCESS);
529         }
530     }
531
532   if (Status == STATUS_WRONG_VOLUME)
533     {
534       /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
535       DPRINT("Wrong volume!\n");
536
537       DeviceObject->Vpb->DeviceObject = NULL;
538       DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
539     }
540
541   /* Start mount sequence */
542   Status = IoMountVolume(DeviceObject,
543                          AllowRawMount);
544
545   KeSetEvent(&DeviceObject->DeviceLock,
546              IO_NO_INCREMENT,
547              FALSE);
548
549   return(Status);
550 }
551
552
553 PDEVICE_OBJECT STDCALL
554 IoGetDeviceToVerify(IN PETHREAD Thread)
555 /*
556  * FUNCTION: Returns a pointer to the device, representing a removable-media
557  * device, that is the target of the given thread's I/O request
558  */
559 {
560   return(Thread->DeviceToVerify);
561 }
562
563
564 VOID STDCALL
565 IoSetDeviceToVerify(IN PETHREAD Thread,
566                     IN PDEVICE_OBJECT DeviceObject)
567 {
568   Thread->DeviceToVerify = DeviceObject;
569 }
570
571 #endif /* LIBCAPTIVE */
572
573 VOID STDCALL
574 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
575                              IN PDEVICE_OBJECT DeviceObject)
576 {
577   Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
578 }
579
580
581 VOID STDCALL
582 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
583 {
584   PFILE_SYSTEM_OBJECT Fs;
585
586   DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
587
588   Fs = ExAllocatePoolWithTag(NonPagedPool,
589                              sizeof(FILE_SYSTEM_OBJECT),
590                              TAG_FILE_SYSTEM);
591   assert(Fs!=NULL);
592
593   Fs->DeviceObject = DeviceObject;
594   ExInterlockedInsertTailList(&FileSystemListHead,
595                               &Fs->Entry,
596                               &FileSystemListLock);
597 #ifndef LIBCAPTIVE
598   IopNotifyFileSystemChange(DeviceObject,
599                             TRUE);
600 #endif /* LIBCAPTIVE */
601 }
602
603
604 VOID STDCALL
605 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
606 {
607   KIRQL oldlvl;
608   PLIST_ENTRY current_entry;
609   PFILE_SYSTEM_OBJECT current;
610
611   DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
612
613   KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
614   current_entry = FileSystemListHead.Flink;
615   while (current_entry!=(&FileSystemListHead))
616     {
617       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
618       if (current->DeviceObject == DeviceObject)
619         {
620           RemoveEntryList(current_entry);
621           ExFreePool(current);
622           KeReleaseSpinLock(&FileSystemListLock,oldlvl);
623 #ifndef LIBCAPTIVE
624           IopNotifyFileSystemChange(DeviceObject, FALSE);
625 #endif /* LIBCAPTIVE */
626           return;
627         }
628       current_entry = current_entry->Flink;
629     }
630   KeReleaseSpinLock(&FileSystemListLock,oldlvl);
631 }
632
633
634 #ifndef LIBCAPTIVE
635
636 /**********************************************************************
637  * NAME                                                 EXPORTED
638  *      IoGetBaseFileSystemDeviceObject@4
639  *
640  * DESCRIPTION
641  *      Get the DEVICE_OBJECT associated to
642  *      a FILE_OBJECT.
643  *
644  * ARGUMENTS
645  *      FileObject
646  *
647  * RETURN VALUE
648  *
649  * NOTE
650  *      From Bo Branten's ntifs.h v13.
651  */
652 PDEVICE_OBJECT STDCALL
653 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
654 {
655         PDEVICE_OBJECT  DeviceObject = NULL;
656         PVPB            Vpb = NULL;
657
658         /*
659          * If the FILE_OBJECT's VPB is defined,
660          * get the device from it.
661          */
662         if (NULL != (Vpb = FileObject->Vpb)) 
663         {
664                 if (NULL != (DeviceObject = Vpb->DeviceObject))
665                 {
666                         /* Vpb->DeviceObject DEFINED! */
667                         return DeviceObject;
668                 }
669         }
670         /*
671          * If that failed, try the VPB
672          * in the FILE_OBJECT's DeviceObject.
673          */
674         DeviceObject = FileObject->DeviceObject;
675         if (NULL == (Vpb = DeviceObject->Vpb)) 
676         {
677                 /* DeviceObject->Vpb UNDEFINED! */
678                 return DeviceObject;
679         }
680         /*
681          * If that pointer to the VPB is again
682          * undefined, return directly the
683          * device object from the FILE_OBJECT.
684          */
685         return (
686                 (NULL == Vpb->DeviceObject)
687                         ? DeviceObject
688                         : Vpb->DeviceObject
689                 );
690 }
691
692
693 static VOID
694 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
695                           BOOLEAN DriverActive)
696 {
697   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
698   PLIST_ENTRY Entry;
699   KIRQL oldlvl;
700
701   KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
702   Entry = FsChangeNotifyListHead.Flink;
703   while (Entry != &FsChangeNotifyListHead)
704     {
705       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
706
707       (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
708
709       Entry = Entry->Flink;
710     }
711   KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
712 }
713
714
715 NTSTATUS STDCALL
716 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
717                                IN PFSDNOTIFICATIONPROC FSDNotificationProc)
718 {
719   PFS_CHANGE_NOTIFY_ENTRY Entry;
720
721   Entry = ExAllocatePoolWithTag(NonPagedPool,
722                                 sizeof(FS_CHANGE_NOTIFY_ENTRY),
723                                 TAG_FS_CHANGE_NOTIFY);
724   if (Entry == NULL)
725     return(STATUS_INSUFFICIENT_RESOURCES);
726
727   Entry->DriverObject = DriverObject;
728   Entry->FSDNotificationProc = FSDNotificationProc;
729
730   ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
731                               &Entry->FsChangeNotifyList,
732                               &FsChangeNotifyListLock);
733
734   return(STATUS_SUCCESS);
735 }
736
737
738 VOID STDCALL
739 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
740                                  IN PFSDNOTIFICATIONPROC FSDNotificationProc)
741 {
742   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
743   PLIST_ENTRY Entry;
744   KIRQL oldlvl;
745
746   Entry = FsChangeNotifyListHead.Flink;
747   while (Entry != &FsChangeNotifyListHead)
748     {
749       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
750       if (ChangeEntry->DriverObject == DriverObject &&
751           ChangeEntry->FSDNotificationProc == FSDNotificationProc)
752         {
753           KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
754           RemoveEntryList(Entry);
755           KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
756
757           ExFreePool(Entry);
758           return;
759         }
760
761       Entry = Entry->Flink;
762     }
763 }
764
765 #endif /* LIBCAPTIVE */
766
767 /* EOF */