+general captive shutdown
[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;
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    /* FIXME: deadlock loop detection */
199    while ((current_entry = FileSystemListHead.Flink)!=(&FileSystemListHead))
200      {
201         current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
202
203         /* send IRP_MJ_SHUTDOWN */
204         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
205                                            current->DeviceObject,
206                                            NULL,
207                                            0,
208                                            0,
209                                            &Event,
210                                            &IoStatusBlock);
211
212         Status = IoCallDriver(current->DeviceObject,Irp);
213         if (Status==STATUS_PENDING)
214           {
215              KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
216           }
217      }
218
219 #ifndef LIBCAPTIVE
220    /* filesystems cannot be called at DISPATCH_LEVEL */
221    KeReleaseSpinLock(&FileSystemListLock,oldlvl);
222 #endif /* LIBCAPTIVE */
223 }
224
225
226 static NTSTATUS
227 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
228                    PDEVICE_OBJECT DeviceToMount)
229 {
230   IO_STATUS_BLOCK IoStatusBlock;
231   PIO_STACK_LOCATION StackPtr;
232   PKEVENT Event;
233   PIRP Irp;
234   NTSTATUS Status;
235
236   DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
237          DeviceObject,DeviceToMount);
238
239   assert_irql(PASSIVE_LEVEL);
240   Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
241   if (Event == NULL)
242     {
243       return(STATUS_INSUFFICIENT_RESOURCES);
244     }
245   KeInitializeEvent(Event, NotificationEvent, FALSE);
246
247   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
248   if (Irp==NULL)
249     {
250       ExFreePool(Event);
251       return(STATUS_INSUFFICIENT_RESOURCES);
252     }
253
254   Irp->UserIosb = &IoStatusBlock;
255   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
256   Irp->UserEvent = Event;
257   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
258
259   StackPtr = IoGetNextIrpStackLocation(Irp);
260   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
261   StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
262   StackPtr->Flags = 0;
263   StackPtr->Control = 0;
264   StackPtr->DeviceObject = DeviceObject;
265   StackPtr->FileObject = NULL;
266   StackPtr->CompletionRoutine = NULL;
267
268   StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
269   StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
270
271   Status = IoCallDriver(DeviceObject,Irp);
272   if (Status==STATUS_PENDING)
273     {
274       KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
275       Status = IoStatusBlock.Status;
276     }
277
278   ExFreePool(Event);
279
280   return(Status);
281 }
282
283
284 static NTSTATUS
285 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
286 {
287   IO_STATUS_BLOCK IoStatusBlock;
288   PIO_STACK_LOCATION StackPtr;
289   PKEVENT Event;
290   PIRP Irp;
291   NTSTATUS Status;
292
293   DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
294
295   assert_irql(PASSIVE_LEVEL);
296   Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
297   if (Event == NULL)
298     {
299       return(STATUS_INSUFFICIENT_RESOURCES);
300     }
301   KeInitializeEvent(Event, NotificationEvent, FALSE);
302
303   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
304   if (Irp==NULL)
305     {
306       ExFreePool(Event);
307       return(STATUS_INSUFFICIENT_RESOURCES);
308     }
309
310   Irp->UserIosb = &IoStatusBlock;
311   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
312   Irp->UserEvent = Event;
313   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
314
315   StackPtr = IoGetNextIrpStackLocation(Irp);
316   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
317   StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
318   StackPtr->Flags = 0;
319   StackPtr->Control = 0;
320   StackPtr->DeviceObject = DeviceObject;
321   StackPtr->FileObject = NULL;
322   StackPtr->CompletionRoutine = NULL;
323
324   Status = IoCallDriver(DeviceObject,Irp);
325   if (Status==STATUS_PENDING)
326     {
327       KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
328       Status = IoStatusBlock.Status;
329     }
330
331   ExFreePool(Event);
332
333   return(Status);
334 }
335
336
337 NTSTATUS
338 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
339               IN BOOLEAN AllowRawMount)
340 /*
341  * FUNCTION: Mounts a logical volume
342  * ARGUMENTS:
343  *         DeviceObject = Device to mount
344  * RETURNS: Status
345  */
346 {
347   KIRQL oldlvl;
348   PLIST_ENTRY current_entry;
349   FILE_SYSTEM_OBJECT* current;
350   NTSTATUS Status;
351   DEVICE_TYPE MatchingDeviceType;
352
353   assert_irql(PASSIVE_LEVEL);
354
355   DPRINT("IoMountVolume(DeviceObject %x  AllowRawMount %x)\n",
356          DeviceObject, AllowRawMount);
357
358   switch (DeviceObject->DeviceType)
359     {
360       case FILE_DEVICE_DISK:
361       case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
362         MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
363         break;
364
365       case FILE_DEVICE_CD_ROM:
366         MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
367         break;
368
369       case FILE_DEVICE_NETWORK:
370         MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
371         break;
372
373       case FILE_DEVICE_TAPE:
374         MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
375         break;
376
377       default:
378         CPRINT("No matching file system type found for device type: %x\n",
379                DeviceObject->DeviceType);
380         return(STATUS_UNRECOGNIZED_VOLUME);
381     }
382
383   KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
384   current_entry = FileSystemListHead.Flink;
385   while (current_entry!=(&FileSystemListHead))
386     {
387       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
388       if (current->DeviceObject->DeviceType != MatchingDeviceType)
389         {
390           current_entry = current_entry->Flink;
391           continue;
392         }
393       KeReleaseSpinLock(&FileSystemListLock,oldlvl);
394       Status = IopMountFileSystem(current->DeviceObject,
395                                   DeviceObject);
396       KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
397       switch (Status)
398         {
399           case STATUS_FS_DRIVER_REQUIRED:
400             KeReleaseSpinLock(&FileSystemListLock,oldlvl);
401             Status = IopLoadFileSystem(current->DeviceObject);
402             if (!NT_SUCCESS(Status))
403               {
404                 return(Status);
405               }
406             KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
407             current_entry = FileSystemListHead.Flink;
408             continue;
409
410           case STATUS_SUCCESS:
411             DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
412                                        VPB_MOUNTED;
413             KeReleaseSpinLock(&FileSystemListLock,oldlvl);
414             return(STATUS_SUCCESS);
415
416           case STATUS_UNRECOGNIZED_VOLUME:
417           default:
418             current_entry = current_entry->Flink;
419         }
420     }
421   KeReleaseSpinLock(&FileSystemListLock,oldlvl);
422
423   return(STATUS_UNRECOGNIZED_VOLUME);
424 }
425
426 #ifndef LIBCAPTIVE
427
428 /**********************************************************************
429  * NAME                                                 EXPORTED
430  *      IoVerifyVolume
431  *
432  * DESCRIPTION
433  *      Verify the file system type and volume information or mount
434  *      a file system.
435  *
436  * ARGUMENTS
437  *      DeviceObject
438  *              Device to verify or mount
439  *
440  *      AllowRawMount
441  *              ...
442  *
443  * RETURN VALUE
444  *      Status
445  */
446 NTSTATUS STDCALL
447 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
448                IN BOOLEAN AllowRawMount)
449 {
450   IO_STATUS_BLOCK IoStatusBlock;
451   PIO_STACK_LOCATION StackPtr;
452   PKEVENT Event;
453   PIRP Irp;
454   NTSTATUS Status;
455
456   DPRINT("IoVerifyVolume(DeviceObject %x  AllowRawMount %x)\n",
457          DeviceObject, AllowRawMount);
458
459   Status = STATUS_SUCCESS;
460
461   KeWaitForSingleObject(&DeviceObject->DeviceLock,
462                         Executive,
463                         KernelMode,
464                         FALSE,
465                         NULL);
466
467   DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
468
469   if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
470     {
471       /* Issue verify request to the FSD */
472       Event = ExAllocatePool(NonPagedPool,
473                              sizeof(KEVENT));
474       if (Event == NULL)
475         return(STATUS_INSUFFICIENT_RESOURCES);
476
477       KeInitializeEvent(Event,
478                         NotificationEvent,
479                         FALSE);
480
481       Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
482       if (Irp==NULL)
483         {
484           ExFreePool(Event);
485           return(STATUS_INSUFFICIENT_RESOURCES);
486         }
487
488       Irp->UserIosb = &IoStatusBlock;
489       Irp->UserEvent = Event;
490       Irp->Tail.Overlay.Thread = PsGetCurrentThread();
491
492       StackPtr = IoGetNextIrpStackLocation(Irp);
493       StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
494       StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
495       StackPtr->Flags = 0;
496       StackPtr->Control = 0;
497       StackPtr->DeviceObject = DeviceObject;
498       StackPtr->FileObject = NULL;
499       StackPtr->CompletionRoutine = NULL;
500
501       StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
502       StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
503
504       Status = IoCallDriver(DeviceObject,
505                             Irp);
506       if (Status==STATUS_PENDING)
507         {
508           KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
509           Status = IoStatusBlock.Status;
510         }
511       ExFreePool(Event);
512
513       if (NT_SUCCESS(Status))
514         {
515           KeSetEvent(&DeviceObject->DeviceLock,
516                      IO_NO_INCREMENT,
517                      FALSE);
518           return(STATUS_SUCCESS);
519         }
520     }
521
522   if (Status == STATUS_WRONG_VOLUME)
523     {
524       /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
525       DPRINT("Wrong volume!\n");
526
527       DeviceObject->Vpb->DeviceObject = NULL;
528       DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
529     }
530
531   /* Start mount sequence */
532   Status = IoMountVolume(DeviceObject,
533                          AllowRawMount);
534
535   KeSetEvent(&DeviceObject->DeviceLock,
536              IO_NO_INCREMENT,
537              FALSE);
538
539   return(Status);
540 }
541
542
543 PDEVICE_OBJECT STDCALL
544 IoGetDeviceToVerify(IN PETHREAD Thread)
545 /*
546  * FUNCTION: Returns a pointer to the device, representing a removable-media
547  * device, that is the target of the given thread's I/O request
548  */
549 {
550   return(Thread->DeviceToVerify);
551 }
552
553
554 VOID STDCALL
555 IoSetDeviceToVerify(IN PETHREAD Thread,
556                     IN PDEVICE_OBJECT DeviceObject)
557 {
558   Thread->DeviceToVerify = DeviceObject;
559 }
560
561 #endif /* LIBCAPTIVE */
562
563 VOID STDCALL
564 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
565                              IN PDEVICE_OBJECT DeviceObject)
566 {
567   Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
568 }
569
570
571 VOID STDCALL
572 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
573 {
574   PFILE_SYSTEM_OBJECT Fs;
575
576   DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
577
578   Fs = ExAllocatePoolWithTag(NonPagedPool,
579                              sizeof(FILE_SYSTEM_OBJECT),
580                              TAG_FILE_SYSTEM);
581   assert(Fs!=NULL);
582
583   Fs->DeviceObject = DeviceObject;
584   ExInterlockedInsertTailList(&FileSystemListHead,
585                               &Fs->Entry,
586                               &FileSystemListLock);
587 #ifndef LIBCAPTIVE
588   IopNotifyFileSystemChange(DeviceObject,
589                             TRUE);
590 #endif /* LIBCAPTIVE */
591 }
592
593
594 VOID STDCALL
595 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
596 {
597   KIRQL oldlvl;
598   PLIST_ENTRY current_entry;
599   PFILE_SYSTEM_OBJECT current;
600
601   DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
602
603   KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
604   current_entry = FileSystemListHead.Flink;
605   while (current_entry!=(&FileSystemListHead))
606     {
607       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
608       if (current->DeviceObject == DeviceObject)
609         {
610           RemoveEntryList(current_entry);
611           ExFreePool(current);
612           KeReleaseSpinLock(&FileSystemListLock,oldlvl);
613 #ifndef LIBCAPTIVE
614           IopNotifyFileSystemChange(DeviceObject, FALSE);
615 #endif /* LIBCAPTIVE */
616           return;
617         }
618       current_entry = current_entry->Flink;
619     }
620   KeReleaseSpinLock(&FileSystemListLock,oldlvl);
621 }
622
623
624 #ifndef LIBCAPTIVE
625
626 /**********************************************************************
627  * NAME                                                 EXPORTED
628  *      IoGetBaseFileSystemDeviceObject@4
629  *
630  * DESCRIPTION
631  *      Get the DEVICE_OBJECT associated to
632  *      a FILE_OBJECT.
633  *
634  * ARGUMENTS
635  *      FileObject
636  *
637  * RETURN VALUE
638  *
639  * NOTE
640  *      From Bo Branten's ntifs.h v13.
641  */
642 PDEVICE_OBJECT STDCALL
643 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
644 {
645         PDEVICE_OBJECT  DeviceObject = NULL;
646         PVPB            Vpb = NULL;
647
648         /*
649          * If the FILE_OBJECT's VPB is defined,
650          * get the device from it.
651          */
652         if (NULL != (Vpb = FileObject->Vpb)) 
653         {
654                 if (NULL != (DeviceObject = Vpb->DeviceObject))
655                 {
656                         /* Vpb->DeviceObject DEFINED! */
657                         return DeviceObject;
658                 }
659         }
660         /*
661          * If that failed, try the VPB
662          * in the FILE_OBJECT's DeviceObject.
663          */
664         DeviceObject = FileObject->DeviceObject;
665         if (NULL == (Vpb = DeviceObject->Vpb)) 
666         {
667                 /* DeviceObject->Vpb UNDEFINED! */
668                 return DeviceObject;
669         }
670         /*
671          * If that pointer to the VPB is again
672          * undefined, return directly the
673          * device object from the FILE_OBJECT.
674          */
675         return (
676                 (NULL == Vpb->DeviceObject)
677                         ? DeviceObject
678                         : Vpb->DeviceObject
679                 );
680 }
681
682
683 static VOID
684 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
685                           BOOLEAN DriverActive)
686 {
687   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
688   PLIST_ENTRY Entry;
689   KIRQL oldlvl;
690
691   KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
692   Entry = FsChangeNotifyListHead.Flink;
693   while (Entry != &FsChangeNotifyListHead)
694     {
695       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
696
697       (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
698
699       Entry = Entry->Flink;
700     }
701   KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
702 }
703
704
705 NTSTATUS STDCALL
706 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
707                                IN PFSDNOTIFICATIONPROC FSDNotificationProc)
708 {
709   PFS_CHANGE_NOTIFY_ENTRY Entry;
710
711   Entry = ExAllocatePoolWithTag(NonPagedPool,
712                                 sizeof(FS_CHANGE_NOTIFY_ENTRY),
713                                 TAG_FS_CHANGE_NOTIFY);
714   if (Entry == NULL)
715     return(STATUS_INSUFFICIENT_RESOURCES);
716
717   Entry->DriverObject = DriverObject;
718   Entry->FSDNotificationProc = FSDNotificationProc;
719
720   ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
721                               &Entry->FsChangeNotifyList,
722                               &FsChangeNotifyListLock);
723
724   return(STATUS_SUCCESS);
725 }
726
727
728 VOID STDCALL
729 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
730                                  IN PFSDNOTIFICATIONPROC FSDNotificationProc)
731 {
732   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
733   PLIST_ENTRY Entry;
734   KIRQL oldlvl;
735
736   Entry = FsChangeNotifyListHead.Flink;
737   while (Entry != &FsChangeNotifyListHead)
738     {
739       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
740       if (ChangeEntry->DriverObject == DriverObject &&
741           ChangeEntry->FSDNotificationProc == FSDNotificationProc)
742         {
743           KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
744           RemoveEntryList(Entry);
745           KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
746
747           ExFreePool(Entry);
748           return;
749         }
750
751       Entry = Entry->Flink;
752     }
753 }
754
755 #endif /* LIBCAPTIVE */
756
757 /* EOF */