strip whitespace from end of lines
[reactos.git] / reactos / 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 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
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 PDRIVER_FS_NOTIFICATION 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 KGUARDED_MUTEX 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 PIO_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 = 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 KeInitializeGuardedMutex(&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 ExFreePoolWithTag(current, TAG_FILE_SYSTEM);
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
713 KeAcquireGuardedMutex(&FsChangeNotifyListLock);
714 Entry = FsChangeNotifyListHead.Flink;
715 while (Entry != &FsChangeNotifyListHead)
716 {
717 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
718
719 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
720
721 Entry = Entry->Flink;
722 }
723 KeReleaseGuardedMutex(&FsChangeNotifyListLock);
724 }
725
726
727 /*
728 * @implemented
729 */
730 NTSTATUS STDCALL
731 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
732 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc)
733 {
734 PFS_CHANGE_NOTIFY_ENTRY Entry;
735
736 Entry = ExAllocatePoolWithTag(NonPagedPool,
737 sizeof(FS_CHANGE_NOTIFY_ENTRY),
738 TAG_FS_CHANGE_NOTIFY);
739 if (Entry == NULL)
740 return(STATUS_INSUFFICIENT_RESOURCES);
741
742 Entry->DriverObject = DriverObject;
743 Entry->FSDNotificationProc = FSDNotificationProc;
744
745 KeAcquireGuardedMutex(&FsChangeNotifyListLock);
746 InsertHeadList(&FsChangeNotifyListHead,
747 &Entry->FsChangeNotifyList);
748 KeReleaseGuardedMutex(&FsChangeNotifyListLock);
749
750 return(STATUS_SUCCESS);
751 }
752
753
754 /*
755 * @implemented
756 */
757 VOID STDCALL
758 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
759 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc)
760 {
761 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
762 PLIST_ENTRY Entry;
763
764 Entry = FsChangeNotifyListHead.Flink;
765 while (Entry != &FsChangeNotifyListHead)
766 {
767 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
768 if (ChangeEntry->DriverObject == DriverObject &&
769 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
770 {
771 KeAcquireGuardedMutex(&FsChangeNotifyListLock);
772 RemoveEntryList(Entry);
773 KeReleaseGuardedMutex(&FsChangeNotifyListLock);
774
775 ExFreePoolWithTag(Entry, TAG_FS_CHANGE_NOTIFY);
776 return;
777 }
778
779 Entry = Entry->Flink;
780 }
781 }
782
783 /* EOF */