223f1595e0d7c1f86dadc292033c5d50e4502776
[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 ERESOURCE 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   ExInitializeResourceLite(&FileSystemListLock);
170
171 #ifndef LIBCAPTIVE
172   InitializeListHead(&FsChangeNotifyListHead);
173   KeInitializeSpinLock(&FsChangeNotifyListLock);
174 #endif /* LIBCAPTIVE */
175 }
176
177
178 VOID
179 IoShutdownRegisteredFileSystems(VOID)
180 {
181   PLIST_ENTRY current_entry;
182   FILE_SYSTEM_OBJECT* current,*current_last=NULL;
183   PIRP Irp;
184   KEVENT Event;
185   IO_STATUS_BLOCK IoStatusBlock;
186   NTSTATUS Status;
187
188   DPRINT("IoShutdownRegisteredFileSystems()\n");
189
190   KeInitializeEvent(&Event,
191                     NotificationEvent,
192                     FALSE);
193
194 restart:
195   ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
196
197   /* 'current' will get IoDeleteDevice()ed by IRP_MJ_SHUTDOWN! */
198   if ((current_entry = FileSystemListHead.Flink)!=(&FileSystemListHead))
199     {
200       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
201       if (current==current_last)
202         {
203           /* At least ntfs.sys-NT5.1sp1 appears to not to unregister itself.
204            * It does not import symbol IoUnregisterFileSystem() at all!
205            * BTW also ext2fsd.sys<=v0.10A also forgets to call IoUnregisterFileSystem().
206            */
207           DPRINT("IoShutdownRegisteredFileSystems(): WARNING: filesystem forgot to call IoUnregisterFileSystem() !!!\n");
208           /* IoUnregisterFileSystem() acquires the lock exclusively. */
209           ExReleaseResourceLite(&FileSystemListLock);
210           IoUnregisterFileSystem(current->DeviceObject);
211           /* Reacquire 'FileSystemListLock'. */
212           goto restart;
213         }
214       current_last=current;
215
216       /* IoUnregisterFileSystem() acquires the lock exclusively. */
217       ExReleaseResourceLite(&FileSystemListLock);
218
219       /* send IRP_MJ_SHUTDOWN */
220       Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
221                                          current->DeviceObject,
222                                          NULL,
223                                          0,
224                                          0,
225                                          &Event,
226                                          &IoStatusBlock);
227
228       Status = IoCallDriver(current->DeviceObject,Irp);
229       if (Status==STATUS_PENDING)
230         {
231           KeWaitForSingleObject(&Event,
232                                 Executive,
233                                 KernelMode,
234                                 FALSE,
235                                 NULL);
236         }
237
238       /* Reacquire 'FileSystemListLock'. */
239       goto restart;
240     }
241
242   ExReleaseResourceLite(&FileSystemListLock);
243 }
244
245
246 static NTSTATUS
247 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
248                    PDEVICE_OBJECT DeviceToMount)
249 {
250   IO_STATUS_BLOCK IoStatusBlock;
251   PIO_STACK_LOCATION StackPtr;
252   KEVENT Event;
253   PIRP Irp;
254   NTSTATUS Status;
255
256   DPRINT("IopMountFileSystem(DeviceObject %x, DeviceToMount %x)\n",
257          DeviceObject,DeviceToMount);
258
259   assert_irql(PASSIVE_LEVEL);
260
261   KeInitializeEvent(&Event, NotificationEvent, FALSE);
262   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
263   if (Irp==NULL)
264     {
265       return(STATUS_INSUFFICIENT_RESOURCES);
266     }
267
268   Irp->UserIosb = &IoStatusBlock;
269   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
270   Irp->UserEvent = &Event;
271   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
272
273   StackPtr = IoGetNextIrpStackLocation(Irp);
274   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
275   StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
276   StackPtr->Flags = 0;
277   StackPtr->Control = 0;
278   StackPtr->DeviceObject = DeviceObject;
279   StackPtr->FileObject = NULL;
280   StackPtr->CompletionRoutine = NULL;
281
282   StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
283   StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
284
285   Status = IoCallDriver(DeviceObject,Irp);
286   if (Status==STATUS_PENDING)
287     {
288       KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
289       Status = IoStatusBlock.Status;
290     }
291
292   return(Status);
293 }
294
295
296 static NTSTATUS
297 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
298 {
299   IO_STATUS_BLOCK IoStatusBlock;
300   PIO_STACK_LOCATION StackPtr;
301   KEVENT Event;
302   PIRP Irp;
303   NTSTATUS Status;
304
305   DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
306
307   assert_irql(PASSIVE_LEVEL);
308
309   KeInitializeEvent(&Event, NotificationEvent, FALSE);
310   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
311   if (Irp==NULL)
312     {
313       return(STATUS_INSUFFICIENT_RESOURCES);
314     }
315
316   Irp->UserIosb = &IoStatusBlock;
317   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
318   Irp->UserEvent = &Event;
319   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
320
321   StackPtr = IoGetNextIrpStackLocation(Irp);
322   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
323   StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
324   StackPtr->Flags = 0;
325   StackPtr->Control = 0;
326   StackPtr->DeviceObject = DeviceObject;
327   StackPtr->FileObject = NULL;
328   StackPtr->CompletionRoutine = NULL;
329
330   Status = IoCallDriver(DeviceObject,Irp);
331   if (Status==STATUS_PENDING)
332     {
333       KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
334       Status = IoStatusBlock.Status;
335     }
336
337   return(Status);
338 }
339
340
341 NTSTATUS
342 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
343               IN BOOLEAN AllowRawMount)
344 /*
345  * FUNCTION: Mounts a logical volume
346  * ARGUMENTS:
347  *         DeviceObject = Device to mount
348  * RETURNS: Status
349  */
350 {
351   PLIST_ENTRY current_entry;
352   FILE_SYSTEM_OBJECT* current;
353   NTSTATUS Status;
354   DEVICE_TYPE MatchingDeviceType;
355   PDEVICE_OBJECT DevObject;
356
357   assert_irql(PASSIVE_LEVEL);
358
359   DPRINT("IoMountVolume(DeviceObject %x  AllowRawMount %x)\n",
360          DeviceObject, AllowRawMount);
361
362   switch (DeviceObject->DeviceType)
363     {
364       case FILE_DEVICE_DISK:
365       case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
366         MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
367         break;
368
369       case FILE_DEVICE_CD_ROM:
370         MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
371         break;
372
373       case FILE_DEVICE_NETWORK:
374         MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
375         break;
376
377       case FILE_DEVICE_TAPE:
378         MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
379         break;
380
381       default:
382         CPRINT("No matching file system type found for device type: %x\n",
383                DeviceObject->DeviceType);
384         return(STATUS_UNRECOGNIZED_VOLUME);
385     }
386
387   ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
388   current_entry = FileSystemListHead.Flink;
389   while (current_entry!=(&FileSystemListHead))
390     {
391       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
392       if (current->DeviceObject->DeviceType != MatchingDeviceType)
393         {
394           current_entry = current_entry->Flink;
395           continue;
396         }
397       Status = IopMountFileSystem(current->DeviceObject,
398                                   DeviceObject);
399       switch (Status)
400         {
401           case STATUS_FS_DRIVER_REQUIRED:
402             DevObject = current->DeviceObject;
403             ExReleaseResourceLite(&FileSystemListLock);
404             Status = IopLoadFileSystem(DevObject);
405             if (!NT_SUCCESS(Status))
406               {
407                 return(Status);
408               }
409             ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
410             current_entry = FileSystemListHead.Flink;
411             continue;
412
413           case STATUS_SUCCESS:
414             DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
415                                        VPB_MOUNTED;
416             ExReleaseResourceLite(&FileSystemListLock);
417             return(STATUS_SUCCESS);
418
419           case STATUS_UNRECOGNIZED_VOLUME:
420           default:
421             current_entry = current_entry->Flink;
422         }
423     }
424   ExReleaseResourceLite(&FileSystemListLock);
425
426   return(STATUS_UNRECOGNIZED_VOLUME);
427 }
428
429 #ifndef LIBCAPTIVE
430
431 /**********************************************************************
432  * NAME                                                 EXPORTED
433  *      IoVerifyVolume
434  *
435  * DESCRIPTION
436  *      Verify the file system type and volume information or mount
437  *      a file system.
438  *
439  * ARGUMENTS
440  *      DeviceObject
441  *              Device to verify or mount
442  *
443  *      AllowRawMount
444  *              ...
445  *
446  * RETURN VALUE
447  *      Status
448  */
449 NTSTATUS STDCALL
450 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
451                IN BOOLEAN AllowRawMount)
452 {
453   IO_STATUS_BLOCK IoStatusBlock;
454   PIO_STACK_LOCATION StackPtr;
455   KEVENT Event;
456   PIRP Irp;
457   NTSTATUS Status;
458
459   DPRINT("IoVerifyVolume(DeviceObject %x  AllowRawMount %x)\n",
460          DeviceObject, AllowRawMount);
461
462   Status = STATUS_SUCCESS;
463
464   KeWaitForSingleObject(&DeviceObject->DeviceLock,
465                         Executive,
466                         KernelMode,
467                         FALSE,
468                         NULL);
469
470   DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
471
472   if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
473     {
474       /* Issue verify request to the FSD */
475
476       KeInitializeEvent(&Event,
477                         NotificationEvent,
478                         FALSE);
479
480       Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
481       if (Irp==NULL)
482         {
483           return(STATUS_INSUFFICIENT_RESOURCES);
484         }
485
486       Irp->UserIosb = &IoStatusBlock;
487       Irp->UserEvent = &Event;
488       Irp->Tail.Overlay.Thread = PsGetCurrentThread();
489
490       StackPtr = IoGetNextIrpStackLocation(Irp);
491       StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
492       StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
493       StackPtr->Flags = 0;
494       StackPtr->Control = 0;
495       StackPtr->DeviceObject = DeviceObject;
496       StackPtr->FileObject = NULL;
497       StackPtr->CompletionRoutine = NULL;
498
499       StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
500       StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
501
502       Status = IoCallDriver(DeviceObject,
503                             Irp);
504       if (Status==STATUS_PENDING)
505         {
506           KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
507           Status = IoStatusBlock.Status;
508         }
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 #endif /* LIBCAPTIVE */
559
560 VOID STDCALL
561 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
562                              IN PDEVICE_OBJECT DeviceObject)
563 {
564   Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
565 }
566
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   ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
582
583   InsertTailList(&FileSystemListHead,
584                  &Fs->Entry);
585
586   ExReleaseResourceLite(&FileSystemListLock);
587
588 #ifndef LIBCAPTIVE
589   IopNotifyFileSystemChange(DeviceObject,
590                             TRUE);
591 #endif /* LIBCAPTIVE */
592 }
593
594
595 VOID STDCALL
596 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
597 {
598   PLIST_ENTRY current_entry;
599   PFILE_SYSTEM_OBJECT current;
600
601   DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
602
603   ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
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           ExReleaseResourceLite(&FileSystemListLock);
613 #ifndef LIBCAPTIVE
614           IopNotifyFileSystemChange(DeviceObject, FALSE);
615 #endif /* LIBCAPTIVE */
616           return;
617         }
618       current_entry = current_entry->Flink;
619     }
620   ExReleaseResourceLite(&FileSystemListLock);
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 */