7d8472adf0c2bda2ed6202074644f8d1e07e06b4
[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 /* GLOBALS ******************************************************************/
39
40 static ERESOURCE FileSystemListLock;
41 static LIST_ENTRY FileSystemListHead;
42
43 #ifndef LIBCAPTIVE
44 static KSPIN_LOCK FsChangeNotifyListLock;
45 static LIST_ENTRY FsChangeNotifyListHead;
46 #endif /* LIBCAPTIVE */
47
48 #define TAG_FILE_SYSTEM       TAG('F', 'S', 'Y', 'S')
49 #ifndef LIBCAPTIVE
50 #define TAG_FS_CHANGE_NOTIFY  TAG('F', 'S', 'C', 'N')
51
52
53 static VOID
54 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
55                           BOOLEAN DriverActive);
56 #endif /* LIBCAPTIVE */
57
58
59 /* FUNCTIONS *****************************************************************/
60
61 #ifndef LIBCAPTIVE
62
63 /*
64  * @implemented
65  */
66 NTSTATUS STDCALL
67 NtFsControlFile (
68         IN      HANDLE                  DeviceHandle,
69         IN      HANDLE                  EventHandle     OPTIONAL, 
70         IN      PIO_APC_ROUTINE         ApcRoutine      OPTIONAL, 
71         IN      PVOID                   ApcContext      OPTIONAL, 
72         OUT     PIO_STATUS_BLOCK        IoStatusBlock, 
73         IN      ULONG                   IoControlCode,
74         IN      PVOID                   InputBuffer, 
75         IN      ULONG                   InputBufferSize,
76         OUT     PVOID                   OutputBuffer,
77         IN      ULONG                   OutputBufferSize
78         )
79 {
80    NTSTATUS Status;
81    PFILE_OBJECT FileObject;
82    PDEVICE_OBJECT DeviceObject;
83    PIRP Irp;
84    PEXTENDED_IO_STACK_LOCATION StackPtr;
85    PKEVENT ptrEvent;
86    IO_STATUS_BLOCK IoSB;
87
88    DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
89           "ApcContext %x IoStatusBlock %x IoControlCode %x "
90           "InputBuffer %x InputBufferSize %x OutputBuffer %x "
91           "OutputBufferSize %x)\n",
92           DeviceHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,
93           IoControlCode,InputBuffer,InputBufferSize,OutputBuffer,
94           OutputBufferSize);
95
96    Status = ObReferenceObjectByHandle(DeviceHandle,
97                                       FILE_READ_DATA | FILE_WRITE_DATA,
98                                       NULL,
99                                       KernelMode,
100                                       (PVOID *) &FileObject,
101                                       NULL);
102    
103    if (!NT_SUCCESS(Status))
104      {
105         return(Status);
106      }
107
108    if (EventHandle != NULL)
109      {
110         Status = ObReferenceObjectByHandle (EventHandle,
111                                             SYNCHRONIZE,
112                                             ExEventObjectType,
113                                             UserMode,
114                                             (PVOID*)&ptrEvent,
115                                             NULL);
116         if (!NT_SUCCESS(Status))
117           {
118             ObDereferenceObject(FileObject);
119             return Status;
120           }
121       }
122     else
123       {
124          KeResetEvent (&FileObject->Event);
125          ptrEvent = &FileObject->Event;
126       }
127
128    
129    DeviceObject = FileObject->DeviceObject;
130
131    Irp = IoBuildDeviceIoControlRequest(IoControlCode,
132                                        DeviceObject,
133                                        InputBuffer,
134                                        InputBufferSize,
135                                        OutputBuffer,
136                                        OutputBufferSize,
137                                        FALSE,
138                                        ptrEvent,
139                                        &IoSB);
140    
141    //trigger FileObject/Event dereferencing
142    Irp->Tail.Overlay.OriginalFileObject = FileObject;
143    
144    Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
145    Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
146
147    StackPtr = (PEXTENDED_IO_STACK_LOCATION) IoGetNextIrpStackLocation(Irp);
148    StackPtr->FileObject = FileObject;
149    StackPtr->DeviceObject = DeviceObject;
150    StackPtr->Parameters.FileSystemControl.InputBufferLength = InputBufferSize;
151    StackPtr->Parameters.FileSystemControl.OutputBufferLength = 
152      OutputBufferSize;
153    StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
154    
155    Status = IoCallDriver(DeviceObject,Irp);
156    if (Status == STATUS_PENDING && !(FileObject->Flags & FO_SYNCHRONOUS_IO))
157      {
158         KeWaitForSingleObject(ptrEvent,Executive,KernelMode,FALSE,NULL);
159         Status = IoSB.Status;
160      }
161    if (IoStatusBlock)
162      {
163         *IoStatusBlock = IoSB;
164      }
165    return(Status);
166 }
167
168 #endif /* LIBCAPTIVE */
169
170 VOID
171 IoInitFileSystemImplementation(VOID)
172 {
173   InitializeListHead(&FileSystemListHead);
174   ExInitializeResourceLite(&FileSystemListLock);
175
176 #ifndef LIBCAPTIVE
177   InitializeListHead(&FsChangeNotifyListHead);
178   KeInitializeSpinLock(&FsChangeNotifyListLock);
179 #endif /* LIBCAPTIVE */
180 }
181
182
183 VOID
184 IoShutdownRegisteredFileSystems(VOID)
185 {
186   PLIST_ENTRY current_entry;
187   FILE_SYSTEM_OBJECT* current,*current_last=NULL;
188   PIRP Irp;
189   KEVENT Event;
190   IO_STATUS_BLOCK IoStatusBlock;
191   NTSTATUS Status;
192
193   DPRINT("IoShutdownRegisteredFileSystems()\n");
194
195   KeInitializeEvent(&Event,
196                     NotificationEvent,
197                     FALSE);
198
199 restart:
200   ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
201
202   /* 'current' will get IoDeleteDevice()ed by IRP_MJ_SHUTDOWN! */
203   if ((current_entry = FileSystemListHead.Flink)!=(&FileSystemListHead))
204     {
205       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
206       if (current==current_last)
207         {
208           /* At least ntfs.sys-NT5.1sp1 appears to not to unregister itself.
209            * It does not import symbol IoUnregisterFileSystem() at all!
210            * BTW also ext2fsd.sys<=v0.10A also forgets to call IoUnregisterFileSystem().
211            */
212           DPRINT("IoShutdownRegisteredFileSystems(): WARNING: filesystem forgot to call IoUnregisterFileSystem() !!!\n");
213           /* IoUnregisterFileSystem() acquires the lock exclusively. */
214           ExReleaseResourceLite(&FileSystemListLock);
215           IoUnregisterFileSystem(current->DeviceObject);
216           /* Reacquire 'FileSystemListLock'. */
217           goto restart;
218         }
219       current_last=current;
220
221       /* IoUnregisterFileSystem() acquires the lock exclusively. */
222       ExReleaseResourceLite(&FileSystemListLock);
223
224       /* send IRP_MJ_SHUTDOWN */
225       Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
226                                          current->DeviceObject,
227                                          NULL,
228                                          0,
229                                          0,
230                                          &Event,
231                                          &IoStatusBlock);
232
233       Status = IoCallDriver(current->DeviceObject,Irp);
234       if (Status==STATUS_PENDING)
235         {
236           KeWaitForSingleObject(&Event,
237                                 Executive,
238                                 KernelMode,
239                                 FALSE,
240                                 NULL);
241         }
242
243       /* Reacquire 'FileSystemListLock'. */
244       goto restart;
245     }
246
247   ExReleaseResourceLite(&FileSystemListLock);
248 }
249
250
251 static NTSTATUS
252 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
253                    PDEVICE_OBJECT DeviceToMount)
254 {
255   IO_STATUS_BLOCK IoStatusBlock;
256   PIO_STACK_LOCATION StackPtr;
257   KEVENT Event;
258   PIRP Irp;
259   NTSTATUS Status;
260
261   DPRINT("IopMountFileSystem(DeviceObject %x, DeviceToMount %x)\n",
262          DeviceObject,DeviceToMount);
263
264   assert_irql(PASSIVE_LEVEL);
265
266   KeInitializeEvent(&Event, NotificationEvent, FALSE);
267   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
268   if (Irp==NULL)
269     {
270       return(STATUS_INSUFFICIENT_RESOURCES);
271     }
272
273   Irp->UserIosb = &IoStatusBlock;
274   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
275   Irp->UserEvent = &Event;
276   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
277
278   StackPtr = IoGetNextIrpStackLocation(Irp);
279   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
280   StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
281   StackPtr->Flags = 0;
282   StackPtr->Control = 0;
283   StackPtr->DeviceObject = DeviceObject;
284   StackPtr->FileObject = NULL;
285   StackPtr->CompletionRoutine = NULL;
286
287   StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
288   StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
289
290   Status = IoCallDriver(DeviceObject,Irp);
291   if (Status==STATUS_PENDING)
292     {
293       KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
294       Status = IoStatusBlock.Status;
295     }
296
297   return(Status);
298 }
299
300
301 static NTSTATUS
302 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
303 {
304   IO_STATUS_BLOCK IoStatusBlock;
305   PIO_STACK_LOCATION StackPtr;
306   KEVENT Event;
307   PIRP Irp;
308   NTSTATUS Status;
309
310   DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
311
312   assert_irql(PASSIVE_LEVEL);
313
314   KeInitializeEvent(&Event, NotificationEvent, FALSE);
315   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
316   if (Irp==NULL)
317     {
318       return(STATUS_INSUFFICIENT_RESOURCES);
319     }
320
321   Irp->UserIosb = &IoStatusBlock;
322   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
323   Irp->UserEvent = &Event;
324   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
325
326   StackPtr = IoGetNextIrpStackLocation(Irp);
327   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
328   StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
329   StackPtr->Flags = 0;
330   StackPtr->Control = 0;
331   StackPtr->DeviceObject = DeviceObject;
332   StackPtr->FileObject = NULL;
333   StackPtr->CompletionRoutine = NULL;
334
335   Status = IoCallDriver(DeviceObject,Irp);
336   if (Status==STATUS_PENDING)
337     {
338       KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
339       Status = IoStatusBlock.Status;
340     }
341
342   return(Status);
343 }
344
345
346 NTSTATUS
347 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
348               IN BOOLEAN AllowRawMount)
349 /*
350  * FUNCTION: Mounts a logical volume
351  * ARGUMENTS:
352  *         DeviceObject = Device to mount
353  * RETURNS: Status
354  */
355 {
356   PLIST_ENTRY current_entry;
357   FILE_SYSTEM_OBJECT* current;
358   NTSTATUS Status;
359   DEVICE_TYPE MatchingDeviceType;
360   PDEVICE_OBJECT DevObject;
361
362   assert_irql(PASSIVE_LEVEL);
363
364   DPRINT("IoMountVolume(DeviceObject %x  AllowRawMount %x)\n",
365          DeviceObject, AllowRawMount);
366
367   switch (DeviceObject->DeviceType)
368     {
369       case FILE_DEVICE_DISK:
370       case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
371         MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
372         break;
373
374       case FILE_DEVICE_CD_ROM:
375         MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
376         break;
377
378       case FILE_DEVICE_NETWORK:
379         MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
380         break;
381
382       case FILE_DEVICE_TAPE:
383         MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
384         break;
385
386       default:
387         CPRINT("No matching file system type found for device type: %x\n",
388                DeviceObject->DeviceType);
389         return(STATUS_UNRECOGNIZED_VOLUME);
390     }
391
392   ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
393   current_entry = FileSystemListHead.Flink;
394   while (current_entry!=(&FileSystemListHead))
395     {
396       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
397       if (current->DeviceObject->DeviceType != MatchingDeviceType)
398         {
399           current_entry = current_entry->Flink;
400           continue;
401         }
402       /* If we are not allowed to mount this volume as a raw filesystem volume
403          then don't try this */
404 #ifndef LIBCAPTIVE
405       if (!AllowRawMount && RawFsIsRawFileSystemDeviceObject(current->DeviceObject))
406         {
407           Status = STATUS_UNRECOGNIZED_VOLUME;
408         }
409       else
410 #endif /* LIBCAPTIVE */
411         {
412           Status = IopMountFileSystem(current->DeviceObject,
413                                   DeviceObject);
414         }
415       switch (Status)
416         {
417           case STATUS_FS_DRIVER_REQUIRED:
418             DevObject = current->DeviceObject;
419             ExReleaseResourceLite(&FileSystemListLock);
420             Status = IopLoadFileSystem(DevObject);
421             if (!NT_SUCCESS(Status))
422               {
423                 return(Status);
424               }
425             ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
426             current_entry = FileSystemListHead.Flink;
427             continue;
428
429           case STATUS_SUCCESS:
430             DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
431                                        VPB_MOUNTED;
432             ExReleaseResourceLite(&FileSystemListLock);
433             return(STATUS_SUCCESS);
434
435           case STATUS_UNRECOGNIZED_VOLUME:
436           default:
437             current_entry = current_entry->Flink;
438         }
439     }
440   ExReleaseResourceLite(&FileSystemListLock);
441
442   return(STATUS_UNRECOGNIZED_VOLUME);
443 }
444
445 #ifndef LIBCAPTIVE
446
447 /**********************************************************************
448  * NAME                                                 EXPORTED
449  *      IoVerifyVolume
450  *
451  * DESCRIPTION
452  *      Verify the file system type and volume information or mount
453  *      a file system.
454  *
455  * ARGUMENTS
456  *      DeviceObject
457  *              Device to verify or mount
458  *
459  *      AllowRawMount
460  *              ...
461  *
462  * RETURN VALUE
463  *      Status
464  *
465  * @implemented
466  */
467 NTSTATUS STDCALL
468 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
469                IN BOOLEAN AllowRawMount)
470 {
471   IO_STATUS_BLOCK IoStatusBlock;
472   PIO_STACK_LOCATION StackPtr;
473   KEVENT Event;
474   PIRP Irp;
475   NTSTATUS Status;
476   PDEVICE_OBJECT DevObject;
477
478   DPRINT("IoVerifyVolume(DeviceObject %x  AllowRawMount %x)\n",
479          DeviceObject, AllowRawMount);
480
481   Status = STATUS_SUCCESS;
482
483   KeWaitForSingleObject(&DeviceObject->DeviceLock,
484                         Executive,
485                         KernelMode,
486                         FALSE,
487                         NULL);
488
489   DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
490
491   if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
492     {
493       /* Issue verify request to the FSD */
494       DevObject = DeviceObject->Vpb->DeviceObject;
495
496       KeInitializeEvent(&Event,
497                         NotificationEvent,
498                         FALSE);
499
500       Irp = IoAllocateIrp(DevObject->StackSize, TRUE);
501       if (Irp==NULL)
502         {
503           return(STATUS_INSUFFICIENT_RESOURCES);
504         }
505
506       Irp->UserIosb = &IoStatusBlock;
507       Irp->UserEvent = &Event;
508       Irp->Tail.Overlay.Thread = PsGetCurrentThread();
509
510       StackPtr = IoGetNextIrpStackLocation(Irp);
511       StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
512       StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
513       StackPtr->Flags = 0;
514       StackPtr->Control = 0;
515       StackPtr->DeviceObject = DevObject;
516       StackPtr->FileObject = NULL;
517       StackPtr->CompletionRoutine = NULL;
518
519       StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
520       StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
521
522       Status = IoCallDriver(DevObject,
523                             Irp);
524       if (Status==STATUS_PENDING)
525         {
526           KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
527           Status = IoStatusBlock.Status;
528         }
529
530       if (NT_SUCCESS(Status))
531         {
532           KeSetEvent(&DeviceObject->DeviceLock,
533                      IO_NO_INCREMENT,
534                      FALSE);
535           return(STATUS_SUCCESS);
536         }
537     }
538
539   if (Status == STATUS_WRONG_VOLUME)
540     {
541       /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
542       DPRINT("Wrong volume!\n");
543
544       DeviceObject->Vpb->DeviceObject = NULL;
545       DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
546     }
547
548   /* Start mount sequence */
549   Status = IoMountVolume(DeviceObject,
550                          AllowRawMount);
551
552   KeSetEvent(&DeviceObject->DeviceLock,
553              IO_NO_INCREMENT,
554              FALSE);
555
556   return(Status);
557 }
558
559
560 /*
561  * @implemented
562  */
563 PDEVICE_OBJECT STDCALL
564 IoGetDeviceToVerify(IN PETHREAD Thread)
565 /*
566  * FUNCTION: Returns a pointer to the device, representing a removable-media
567  * device, that is the target of the given thread's I/O request
568  */
569 {
570   return(Thread->DeviceToVerify);
571 }
572
573
574 /*
575  * @implemented
576  */
577 VOID STDCALL
578 IoSetDeviceToVerify(IN PETHREAD Thread,
579                     IN PDEVICE_OBJECT DeviceObject)
580 {
581   Thread->DeviceToVerify = DeviceObject;
582 }
583
584 #endif /* LIBCAPTIVE */
585
586 /*
587  * @implemented
588  */
589 VOID STDCALL
590 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
591                              IN PDEVICE_OBJECT DeviceObject)
592 {
593   Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
594 }
595
596
597 /*
598  * @implemented
599  */
600 VOID STDCALL
601 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
602 {
603   PFILE_SYSTEM_OBJECT Fs;
604
605   DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
606
607   Fs = ExAllocatePoolWithTag(NonPagedPool,
608                              sizeof(FILE_SYSTEM_OBJECT),
609                              TAG_FILE_SYSTEM);
610   assert(Fs!=NULL);
611
612   Fs->DeviceObject = DeviceObject;
613   ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
614
615   /* The RAW filesystem device objects must be last in the list so the
616      raw filesystem driver is the last filesystem driver asked to mount
617      a volume. It is always the first filesystem driver registered so
618      we use InsertHeadList() here as opposed to the other alternative
619      InsertTailList(). */
620   InsertHeadList(&FileSystemListHead,
621                  &Fs->Entry);
622
623   ExReleaseResourceLite(&FileSystemListLock);
624
625 #ifndef LIBCAPTIVE
626   IopNotifyFileSystemChange(DeviceObject,
627                             TRUE);
628 #endif /* LIBCAPTIVE */
629 }
630
631
632 /*
633  * @implemented
634  */
635 VOID STDCALL
636 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
637 {
638   PLIST_ENTRY current_entry;
639   PFILE_SYSTEM_OBJECT current;
640
641   DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
642
643   ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
644   current_entry = FileSystemListHead.Flink;
645   while (current_entry!=(&FileSystemListHead))
646     {
647       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
648       if (current->DeviceObject == DeviceObject)
649         {
650           RemoveEntryList(current_entry);
651           ExFreePool(current);
652           ExReleaseResourceLite(&FileSystemListLock);
653 #ifndef LIBCAPTIVE
654           IopNotifyFileSystemChange(DeviceObject, FALSE);
655 #endif /* LIBCAPTIVE */
656           return;
657         }
658       current_entry = current_entry->Flink;
659     }
660   ExReleaseResourceLite(&FileSystemListLock);
661 }
662
663
664 #ifndef LIBCAPTIVE
665
666 /**********************************************************************
667  * NAME                                                 EXPORTED
668  *      IoGetBaseFileSystemDeviceObject@4
669  *
670  * DESCRIPTION
671  *      Get the DEVICE_OBJECT associated to
672  *      a FILE_OBJECT.
673  *
674  * ARGUMENTS
675  *      FileObject
676  *
677  * RETURN VALUE
678  *
679  * NOTE
680  *      From Bo Branten's ntifs.h v13.
681  *
682  * @implemented
683  */
684 PDEVICE_OBJECT STDCALL
685 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
686 {
687         PDEVICE_OBJECT  DeviceObject = NULL;
688         PVPB            Vpb = NULL;
689
690         /*
691          * If the FILE_OBJECT's VPB is defined,
692          * get the device from it.
693          */
694         if (NULL != (Vpb = FileObject->Vpb)) 
695         {
696                 if (NULL != (DeviceObject = Vpb->DeviceObject))
697                 {
698                         /* Vpb->DeviceObject DEFINED! */
699                         return DeviceObject;
700                 }
701         }
702         /*
703          * If that failed, try the VPB
704          * in the FILE_OBJECT's DeviceObject.
705          */
706         DeviceObject = FileObject->DeviceObject;
707         if (NULL == (Vpb = DeviceObject->Vpb)) 
708         {
709                 /* DeviceObject->Vpb UNDEFINED! */
710                 return DeviceObject;
711         }
712         /*
713          * If that pointer to the VPB is again
714          * undefined, return directly the
715          * device object from the FILE_OBJECT.
716          */
717         return (
718                 (NULL == Vpb->DeviceObject)
719                         ? DeviceObject
720                         : Vpb->DeviceObject
721                 );
722 }
723
724
725 static VOID
726 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
727                           BOOLEAN DriverActive)
728 {
729   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
730   PLIST_ENTRY Entry;
731   KIRQL oldlvl;
732
733   KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
734   Entry = FsChangeNotifyListHead.Flink;
735   while (Entry != &FsChangeNotifyListHead)
736     {
737       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
738
739       (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
740
741       Entry = Entry->Flink;
742     }
743   KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
744 }
745
746
747 /*
748  * @implemented
749  */
750 NTSTATUS STDCALL
751 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
752                                IN PFSDNOTIFICATIONPROC FSDNotificationProc)
753 {
754   PFS_CHANGE_NOTIFY_ENTRY Entry;
755
756   Entry = ExAllocatePoolWithTag(NonPagedPool,
757                                 sizeof(FS_CHANGE_NOTIFY_ENTRY),
758                                 TAG_FS_CHANGE_NOTIFY);
759   if (Entry == NULL)
760     return(STATUS_INSUFFICIENT_RESOURCES);
761
762   Entry->DriverObject = DriverObject;
763   Entry->FSDNotificationProc = FSDNotificationProc;
764
765   ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
766                               &Entry->FsChangeNotifyList,
767                               &FsChangeNotifyListLock);
768
769   return(STATUS_SUCCESS);
770 }
771
772
773 /*
774  * @implemented
775  */
776 VOID STDCALL
777 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
778                                  IN PFSDNOTIFICATIONPROC FSDNotificationProc)
779 {
780   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
781   PLIST_ENTRY Entry;
782   KIRQL oldlvl;
783
784   Entry = FsChangeNotifyListHead.Flink;
785   while (Entry != &FsChangeNotifyListHead)
786     {
787       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
788       if (ChangeEntry->DriverObject == DriverObject &&
789           ChangeEntry->FSDNotificationProc == FSDNotificationProc)
790         {
791           KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
792           RemoveEntryList(Entry);
793           KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
794
795           ExFreePool(Entry);
796           return;
797         }
798
799       Entry = Entry->Flink;
800     }
801 }
802
803 #endif /* LIBCAPTIVE */
804
805 /* EOF */