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