+IopMountFileSystem()
[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 #ifndef LIBCAPTIVE
178
179 VOID
180 IoShutdownRegisteredFileSystems(VOID)
181 {
182    KIRQL oldlvl;
183    PLIST_ENTRY current_entry;
184    FILE_SYSTEM_OBJECT* current;
185    PIRP Irp;
186    KEVENT Event;
187    IO_STATUS_BLOCK IoStatusBlock;
188    NTSTATUS Status;
189
190    DPRINT("IoShutdownRegisteredFileSystems()\n");
191
192    KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
193    KeInitializeEvent(&Event,NotificationEvent,FALSE);
194
195    current_entry = FileSystemListHead.Flink;
196    while (current_entry!=(&FileSystemListHead))
197      {
198         current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
199
200         /* send IRP_MJ_SHUTDOWN */
201         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
202                                            current->DeviceObject,
203                                            NULL,
204                                            0,
205                                            0,
206                                            &Event,
207                                            &IoStatusBlock);
208
209         Status = IoCallDriver(current->DeviceObject,Irp);
210         if (Status==STATUS_PENDING)
211           {
212              KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
213           }
214
215         current_entry = current_entry->Flink;
216      }
217
218    KeReleaseSpinLock(&FileSystemListLock,oldlvl);
219 }
220
221 #endif /* LIBCAPTIVE */
222
223 #ifndef LIBCAPTIVE
224 static
225 #endif /* LIBCAPTIVE */
226 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 #ifndef LIBCAPTIVE
284
285 static NTSTATUS
286 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
287 {
288   IO_STATUS_BLOCK IoStatusBlock;
289   PIO_STACK_LOCATION StackPtr;
290   PKEVENT Event;
291   PIRP Irp;
292   NTSTATUS Status;
293
294   DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
295
296   assert_irql(PASSIVE_LEVEL);
297   Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
298   if (Event == NULL)
299     {
300       return(STATUS_INSUFFICIENT_RESOURCES);
301     }
302   KeInitializeEvent(Event, NotificationEvent, FALSE);
303
304   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
305   if (Irp==NULL)
306     {
307       ExFreePool(Event);
308       return(STATUS_INSUFFICIENT_RESOURCES);
309     }
310
311   Irp->UserIosb = &IoStatusBlock;
312   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
313   Irp->UserEvent = Event;
314   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
315
316   StackPtr = IoGetNextIrpStackLocation(Irp);
317   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
318   StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
319   StackPtr->Flags = 0;
320   StackPtr->Control = 0;
321   StackPtr->DeviceObject = DeviceObject;
322   StackPtr->FileObject = NULL;
323   StackPtr->CompletionRoutine = NULL;
324
325   Status = IoCallDriver(DeviceObject,Irp);
326   if (Status==STATUS_PENDING)
327     {
328       KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
329       Status = IoStatusBlock.Status;
330     }
331
332   ExFreePool(Event);
333
334   return(Status);
335 }
336
337
338 NTSTATUS
339 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
340               IN BOOLEAN AllowRawMount)
341 /*
342  * FUNCTION: Mounts a logical volume
343  * ARGUMENTS:
344  *         DeviceObject = Device to mount
345  * RETURNS: Status
346  */
347 {
348   KIRQL oldlvl;
349   PLIST_ENTRY current_entry;
350   FILE_SYSTEM_OBJECT* current;
351   NTSTATUS Status;
352   DEVICE_TYPE MatchingDeviceType;
353
354   assert_irql(PASSIVE_LEVEL);
355
356   DPRINT("IoMountVolume(DeviceObject %x  AllowRawMount %x)\n",
357          DeviceObject, AllowRawMount);
358
359   switch (DeviceObject->DeviceType)
360     {
361       case FILE_DEVICE_DISK:
362       case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
363         MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
364         break;
365
366       case FILE_DEVICE_CD_ROM:
367         MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
368         break;
369
370       case FILE_DEVICE_NETWORK:
371         MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
372         break;
373
374       case FILE_DEVICE_TAPE:
375         MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
376         break;
377
378       default:
379         CPRINT("No matching file system type found for device type: %x\n",
380                DeviceObject->DeviceType);
381         return(STATUS_UNRECOGNIZED_VOLUME);
382     }
383
384   KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
385   current_entry = FileSystemListHead.Flink;
386   while (current_entry!=(&FileSystemListHead))
387     {
388       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
389       if (current->DeviceObject->DeviceType != MatchingDeviceType)
390         {
391           current_entry = current_entry->Flink;
392           continue;
393         }
394       KeReleaseSpinLock(&FileSystemListLock,oldlvl);
395       Status = IopMountFileSystem(current->DeviceObject,
396                                   DeviceObject);
397       KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
398       switch (Status)
399         {
400           case STATUS_FS_DRIVER_REQUIRED:
401             KeReleaseSpinLock(&FileSystemListLock,oldlvl);
402             Status = IopLoadFileSystem(current->DeviceObject);
403             if (!NT_SUCCESS(Status))
404               {
405                 return(Status);
406               }
407             KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
408             current_entry = FileSystemListHead.Flink;
409             continue;
410
411           case STATUS_SUCCESS:
412             DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
413                                        VPB_MOUNTED;
414             KeReleaseSpinLock(&FileSystemListLock,oldlvl);
415             return(STATUS_SUCCESS);
416
417           case STATUS_UNRECOGNIZED_VOLUME:
418           default:
419             current_entry = current_entry->Flink;
420         }
421     }
422   KeReleaseSpinLock(&FileSystemListLock,oldlvl);
423
424   return(STATUS_UNRECOGNIZED_VOLUME);
425 }
426
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
562 VOID STDCALL
563 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
564                              IN PDEVICE_OBJECT DeviceObject)
565 {
566   Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
567 }
568
569 #endif /* LIBCAPTIVE */
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 #ifndef LIBCAPTIVE
594
595 VOID STDCALL
596 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
597 {
598   KIRQL oldlvl;
599   PLIST_ENTRY current_entry;
600   PFILE_SYSTEM_OBJECT current;
601
602   DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
603
604   KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
605   current_entry = FileSystemListHead.Flink;
606   while (current_entry!=(&FileSystemListHead))
607     {
608       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
609       if (current->DeviceObject == DeviceObject)
610         {
611           RemoveEntryList(current_entry);
612           ExFreePool(current);
613           KeReleaseSpinLock(&FileSystemListLock,oldlvl);
614           IopNotifyFileSystemChange(DeviceObject, FALSE);
615           return;
616         }
617       current_entry = current_entry->Flink;
618     }
619   KeReleaseSpinLock(&FileSystemListLock,oldlvl);
620 }
621
622
623 /**********************************************************************
624  * NAME                                                 EXPORTED
625  *      IoGetBaseFileSystemDeviceObject@4
626  *
627  * DESCRIPTION
628  *      Get the DEVICE_OBJECT associated to
629  *      a FILE_OBJECT.
630  *
631  * ARGUMENTS
632  *      FileObject
633  *
634  * RETURN VALUE
635  *
636  * NOTE
637  *      From Bo Branten's ntifs.h v13.
638  */
639 PDEVICE_OBJECT STDCALL
640 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
641 {
642         PDEVICE_OBJECT  DeviceObject = NULL;
643         PVPB            Vpb = NULL;
644
645         /*
646          * If the FILE_OBJECT's VPB is defined,
647          * get the device from it.
648          */
649         if (NULL != (Vpb = FileObject->Vpb)) 
650         {
651                 if (NULL != (DeviceObject = Vpb->DeviceObject))
652                 {
653                         /* Vpb->DeviceObject DEFINED! */
654                         return DeviceObject;
655                 }
656         }
657         /*
658          * If that failed, try the VPB
659          * in the FILE_OBJECT's DeviceObject.
660          */
661         DeviceObject = FileObject->DeviceObject;
662         if (NULL == (Vpb = DeviceObject->Vpb)) 
663         {
664                 /* DeviceObject->Vpb UNDEFINED! */
665                 return DeviceObject;
666         }
667         /*
668          * If that pointer to the VPB is again
669          * undefined, return directly the
670          * device object from the FILE_OBJECT.
671          */
672         return (
673                 (NULL == Vpb->DeviceObject)
674                         ? DeviceObject
675                         : Vpb->DeviceObject
676                 );
677 }
678
679
680 static VOID
681 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
682                           BOOLEAN DriverActive)
683 {
684   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
685   PLIST_ENTRY Entry;
686   KIRQL oldlvl;
687
688   KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
689   Entry = FsChangeNotifyListHead.Flink;
690   while (Entry != &FsChangeNotifyListHead)
691     {
692       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
693
694       (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
695
696       Entry = Entry->Flink;
697     }
698   KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
699 }
700
701
702 NTSTATUS STDCALL
703 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
704                                IN PFSDNOTIFICATIONPROC FSDNotificationProc)
705 {
706   PFS_CHANGE_NOTIFY_ENTRY Entry;
707
708   Entry = ExAllocatePoolWithTag(NonPagedPool,
709                                 sizeof(FS_CHANGE_NOTIFY_ENTRY),
710                                 TAG_FS_CHANGE_NOTIFY);
711   if (Entry == NULL)
712     return(STATUS_INSUFFICIENT_RESOURCES);
713
714   Entry->DriverObject = DriverObject;
715   Entry->FSDNotificationProc = FSDNotificationProc;
716
717   ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
718                               &Entry->FsChangeNotifyList,
719                               &FsChangeNotifyListLock);
720
721   return(STATUS_SUCCESS);
722 }
723
724
725 VOID STDCALL
726 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
727                                  IN PFSDNOTIFICATIONPROC FSDNotificationProc)
728 {
729   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
730   PLIST_ENTRY Entry;
731   KIRQL oldlvl;
732
733   Entry = FsChangeNotifyListHead.Flink;
734   while (Entry != &FsChangeNotifyListHead)
735     {
736       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
737       if (ChangeEntry->DriverObject == DriverObject &&
738           ChangeEntry->FSDNotificationProc == FSDNotificationProc)
739         {
740           KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
741           RemoveEntryList(Entry);
742           KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
743
744           ExFreePool(Entry);
745           return;
746         }
747
748       Entry = Entry->Flink;
749     }
750 }
751
752 #endif /* LIBCAPTIVE */
753
754 /* EOF */