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