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