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