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