3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/fs/notify.c
6 * PURPOSE: No purpose listed.
8 * PROGRAMMERS: Gunnar Dalsnes
14 #include <internal/debug.h>
17 PAGED_LOOKASIDE_LIST NotifyEntryLookaside
;
19 typedef struct _NOTIFY_ENTRY
22 PSTRING FullDirectoryName
;
24 BOOLEAN PendingChanges
;
25 ULONG CompletionFilter
;
28 PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback
;
29 PSECURITY_SUBJECT_CONTEXT SubjectContext
;
32 BOOLEAN BufferExhausted
;
33 PVOID Buffer
; /* Buffer == NULL equals IgnoreBuffer == TRUE */
35 ULONG NextEntryOffset
;
36 PFILE_NOTIFY_INFORMATION PrevEntry
;
37 } NOTIFY_ENTRY
, *PNOTIFY_ENTRY
;
40 /**********************************************************************
42 * FsRtlpInitNotifyImplementation
47 FsRtlpInitNotifyImplementation(VOID
)
49 ExInitializePagedLookasideList( &NotifyEntryLookaside
,
72 if (Path
->Length
== 1) return FALSE
;
74 if (*(WCHAR
*)Path
->Buffer
== '\\') return TRUE
;
80 /**********************************************************************
82 * FsRtlpNotifyCancelRoutine
88 FsRtlpNotifyCancelRoutine(
89 IN PDEVICE_OBJECT DeviceObject
,
95 //don't need this since we have our own sync. protecting irp cancellation
96 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
98 Lock
= (PFAST_MUTEX
)Irp
->Tail
.Overlay
.DriverContext
[3];
100 ExAcquireFastMutex(Lock
);
102 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
104 ExReleaseFastMutex(Lock
);
106 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
107 Irp
->IoStatus
.Information
= 0;
109 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
118 FsRtlpFindNotifyEntry(
119 PLIST_ENTRY NotifyList
,
123 PNOTIFY_ENTRY NotifyEntry
;
125 LIST_FOR_EACH(NotifyEntry
, NotifyList
, NOTIFY_ENTRY
, ListEntry
)
127 if (NotifyEntry
->FsContext
== FsContext
)
136 /**********************************************************************
138 * FsRtlNotifyChangeDirectory@28
150 FsRtlNotifyChangeDirectory (
151 IN PNOTIFY_SYNC NotifySync
,
153 IN PSTRING FullDirectoryName
,
154 IN PLIST_ENTRY NotifyList
,
155 IN BOOLEAN WatchTree
,
156 IN ULONG CompletionFilter
,
160 FsRtlNotifyFullChangeDirectory (
166 TRUE
, /* IgnoreBuffer */
176 /**********************************************************************
178 * FsRtlNotifyCleanup@12
181 * Called by FSD when all handles to FileObject (identified by FsContext) are closed
192 IN PNOTIFY_SYNC NotifySync
,
193 IN PLIST_ENTRY NotifyList
,
197 PNOTIFY_ENTRY NotifyEntry
;
198 LIST_ENTRY CompletedListHead
;
199 PLIST_ENTRY TmpEntry
;
202 InitializeListHead(&CompletedListHead
);
204 ExAcquireFastMutex((PFAST_MUTEX
)NotifySync
);
206 NotifyEntry
= FsRtlpFindNotifyEntry(NotifyList
, FsContext
);
210 /* free buffered changes */
211 if (NotifyEntry
->Buffer
)
213 ExFreePool(NotifyEntry
->Buffer
);
216 /* cancel(?) pending irps */
217 while (!IsListEmpty(&NotifyEntry
->IrpQueue
))
219 TmpEntry
= RemoveHeadList(&NotifyEntry
->IrpQueue
);
220 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
222 /* irp cancelation bolilerplate */
223 if (!IoSetCancelRoutine(Irp
, NULL
))
225 //The cancel routine will be called. When we release the lock it will complete the irp.
226 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
230 Irp
->IoStatus
.Status
= STATUS_NOTIFY_CLEANUP
; /* FIXME: correct status? */
231 Irp
->IoStatus
.Information
= 0;
233 /* avoid holding lock while completing irp */
234 InsertTailList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
237 /* Unlink and free the NotifyStruct */
238 RemoveEntryList(&NotifyEntry
->ListEntry
);
239 ExFreeToPagedLookasideList(&NotifyEntryLookaside
, NotifyEntry
);
242 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
244 /* complete defered irps */
245 while (!IsListEmpty(&CompletedListHead
))
247 TmpEntry
= RemoveHeadList(&CompletedListHead
);
248 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
249 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
260 FsRtlNotifyFilterChangeDirectory (
261 IN PNOTIFY_SYNC NotifySync
,
262 IN PLIST_ENTRY NotifyList
,
264 IN PSTRING FullDirectoryName
,
265 IN BOOLEAN WatchTree
,
266 IN BOOLEAN IgnoreBuffer
,
267 IN ULONG CompletionFilter
,
269 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL
,
270 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL
,
271 IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL
282 FsRtlNotifyFilterReportChange (
283 IN PNOTIFY_SYNC NotifySync
,
284 IN PLIST_ENTRY NotifyList
,
285 IN PSTRING FullTargetName
,
286 IN USHORT TargetNameOffset
,
287 IN PSTRING StreamName OPTIONAL
,
288 IN PSTRING NormalizedParentName OPTIONAL
,
289 IN ULONG FilterMatch
,
291 IN PVOID TargetContext
,
292 IN PVOID FilterContext
303 FsRtlpWatchedDirectoryWasDeleted(
304 IN PNOTIFY_SYNC NotifySync
,
305 IN PLIST_ENTRY NotifyList
,
309 LIST_ENTRY CompletedListHead
;
310 PLIST_ENTRY TmpEntry
;
311 PNOTIFY_ENTRY NotifyEntry
, tmp
;
314 InitializeListHead(&CompletedListHead
);
316 ExAcquireFastMutex((PFAST_MUTEX
)NotifySync
);
318 LIST_FOR_EACH_SAFE(NotifyEntry
, tmp
, NotifyList
, NOTIFY_ENTRY
, ListEntry
)
320 if (NotifyEntry
->Fcb
== Fcb
)
322 RemoveEntryList(&NotifyEntry
->ListEntry
);
324 /* free buffered changes */
325 if (NotifyEntry
->Buffer
)
327 ExFreePool(NotifyEntry
->Buffer
);
330 /* cleanup pending irps */
331 while (!IsListEmpty(&NotifyEntry
->IrpQueue
))
333 TmpEntry
= RemoveHeadList(&NotifyEntry
->IrpQueue
);
334 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
336 /* irp cancelation bolilerplate */
337 if (!IoSetCancelRoutine(Irp
, NULL
))
339 //The cancel routine will be called. When we release the lock it will complete the irp.
340 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
344 Irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
345 Irp
->IoStatus
.Information
= 0;
347 /* avoid holding lock while completing irp */
348 InsertTailList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
353 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
355 /* complete defered irps */
356 while (!IsListEmpty(&CompletedListHead
))
358 TmpEntry
= RemoveHeadList(&CompletedListHead
);
359 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
360 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
370 /**********************************************************************
372 * FsRtlNotifyFullChangeDirectory@40
384 FsRtlNotifyFullChangeDirectory (
385 IN PNOTIFY_SYNC NotifySync
,
386 IN PLIST_ENTRY NotifyList
,
388 IN PSTRING FullDirectoryName
,
389 IN BOOLEAN WatchTree
,
390 IN BOOLEAN IgnoreBuffer
,
391 IN ULONG CompletionFilter
,
393 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL
,
394 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL
397 PIO_STACK_LOCATION IrpStack
;
398 PNOTIFY_ENTRY NotifyEntry
;
403 /* all other params are ignored if NotifyIrp == NULL */
404 FsRtlpWatchedDirectoryWasDeleted(NotifySync
, NotifyList
, FsContext
);
408 DPRINT("FullDirectoryName: %wZ\n", FullDirectoryName
);
410 ExAcquireFastMutex((PFAST_MUTEX
)NotifySync
);
412 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
413 if (IrpStack
->FileObject
->Flags
& FO_CLEANUP_COMPLETE
)
415 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
417 Irp
->IoStatus
.Information
= 0;
418 Irp
->IoStatus
.Status
= STATUS_NOTIFY_CLEANUP
;
419 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
423 IrpBuffLen
= IrpStack
->Parameters
.NotifyDirectory
.Length
;
425 NotifyEntry
= FsRtlpFindNotifyEntry(NotifyList
, FsContext
);
429 /* No NotifyStruct for this FileObject existed */
431 /* The first request for this FileObject set the standards.
432 * For subsequent requests, these params will be ignored.
433 * Ref: Windows NT File System Internals page 516
436 NotifyEntry
= ExAllocateFromPagedLookasideList(&NotifyEntryLookaside
);
438 RtlZeroMemory(NotifyEntry
, sizeof(NOTIFY_ENTRY
));
440 NotifyEntry
->FsContext
= FsContext
;
441 NotifyEntry
->FullDirectoryName
= FullDirectoryName
;
442 NotifyEntry
->WatchTree
= WatchTree
;
443 NotifyEntry
->CompletionFilter
= CompletionFilter
;
444 NotifyEntry
->TraverseCallback
= TraverseCallback
;
445 NotifyEntry
->SubjectContext
= SubjectContext
;
446 NotifyEntry
->Fcb
= IrpStack
->FileObject
->FsContext
;
447 NotifyEntry
->Unicode
= FsRtlpIsUnicodePath(FullDirectoryName
);
450 if (IrpBuffLen
&& !IgnoreBuffer
)
454 NotifyEntry
->Buffer
= ExAllocatePoolWithQuotaTag(
460 NotifyEntry
->BufferSize
= IrpBuffLen
;
464 /* ExAllocatePoolWithQuotaTag raised exception but we dont care.
465 The impl. doesnt require a buffer, so well continue as usual.
471 InitializeListHead(&NotifyEntry
->IrpQueue
);
473 InsertTailList(NotifyList
, &NotifyEntry
->ListEntry
);
478 if (!NotifyEntry
->PendingChanges
)
480 /* No changes are pending. Queue the irp */
482 /* Irp cancelation boilerplate */
484 /* save NotifySych for use in the cancel routine */
485 Irp
->Tail
.Overlay
.DriverContext
[3] = NotifySync
;
487 IoSetCancelRoutine(Irp
, FsRtlpNotifyCancelRoutine
);
488 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
491 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
493 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
494 Irp
->IoStatus
.Information
= 0;
496 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
500 IoMarkIrpPending(Irp
);
502 //FIXME: any point in setting irp status/information before queueing?
503 Irp
->IoStatus
.Status
= STATUS_PENDING
;
505 InsertTailList(&NotifyEntry
->IrpQueue
, &Irp
->Tail
.Overlay
.ListEntry
);
507 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
512 /* Pending changes exist */
514 if (NotifyEntry
->Buffer
== NULL
||
515 NotifyEntry
->BufferExhausted
||
516 IrpBuffLen
< NotifyEntry
->NextEntryOffset
)
519 Can't return detailed changes to user cause:
521 -Buffer were overflowed, OR
522 -Current irp buff was not large enough
525 Irp
->IoStatus
.Information
= 0;
526 Irp
->IoStatus
.Status
= STATUS_NOTIFY_ENUM_DIR
;
531 PVOID Adr
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, LowPagePriority
);
535 memcpy(Adr
, NotifyEntry
->Buffer
, NotifyEntry
->NextEntryOffset
);
536 Irp
->IoStatus
.Information
= NotifyEntry
->NextEntryOffset
;
540 Irp
->IoStatus
.Information
= 0;
543 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
547 NotifyEntry
->PrevEntry
= NULL
;
548 NotifyEntry
->NextEntryOffset
= 0;
549 NotifyEntry
->BufferExhausted
= FALSE
;
551 NotifyEntry
->PendingChanges
= FALSE
;
553 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
555 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
557 /* caller must return STATUS_PENDING */
565 FsRtlpGetNextIrp(PNOTIFY_ENTRY NotifyEntry
)
568 PLIST_ENTRY TmpEntry
;
570 /* Loop to get a non-canceled irp */
571 while (!IsListEmpty(&NotifyEntry
->IrpQueue
))
573 /* If we have queued irp(s) we can't possibly have pending changes too */
574 ASSERT(!NotifyEntry
->PendingChanges
);
576 TmpEntry
= RemoveHeadList(&NotifyEntry
->IrpQueue
);
577 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
579 /* irp cancelation bolilerplate */
580 if (!IoSetCancelRoutine(Irp
, NULL
))
582 //The cancel routine will be called. When we release the lock it will complete the irp.
583 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
587 /* Finally we got a non-canceled irp */
599 PFILE_NOTIFY_INFORMATION CurrentEntry
,
601 PSTRING RelativeName
,
605 /* Buffer size is allready probed, so just copy the data */
609 memcpy(CurrentEntry
->FileName
, RelativeName
->Buffer
, RelativeName
->Length
);
612 CurrentEntry
->FileName
[RelativeName
->Length
/sizeof(WCHAR
)] = ':';
613 memcpy(&CurrentEntry
->FileName
[(RelativeName
->Length
/sizeof(WCHAR
))+1],
620 //FIXME: convert to unicode etc.
621 DPRINT1("FIXME: ansi strings in notify impl. not supported yet\n");
626 /**********************************************************************
628 * FsRtlNotifyFullReportChange@36
640 FsRtlNotifyFullReportChange (
641 IN PNOTIFY_SYNC NotifySync
,
642 IN PLIST_ENTRY NotifyList
,
643 IN PSTRING FullTargetName
, /* can include short names! */
644 IN USHORT TargetNameOffset
, /* in bytes */
645 IN PSTRING StreamName OPTIONAL
,
646 IN PSTRING NormalizedParentName OPTIONAL
, /* same as FullTargetName, but with long names */
647 IN ULONG FilterMatch
,
649 IN PVOID TargetContext
654 PNOTIFY_ENTRY NotifyEntry
, tmp
;
655 PLIST_ENTRY EnumEntry
;
657 LIST_ENTRY CompletedListHead
;
660 PFILE_NOTIFY_INFORMATION CurrentEntry
;
662 InitializeListHead(&CompletedListHead
);
664 DPRINT("FullTargetName: %wZ\n", FullTargetName
);
667 I think FullTargetName can include/be a short file name! What the heck do i do with this?
668 Dont think this apply to FsRtlNotifyFullChangeDirectory's FullDirectoryName.
674 ExAcquireFastMutex((PFAST_MUTEX
)NotifySync
);
676 LIST_FOR_EACH_SAFE(NotifyEntry
, tmp
, NotifyList
, NOTIFY_ENTRY
, ListEntry
)
678 ASSERT(NotifyEntry
->Unicode
== FsRtlpIsUnicodePath(FullTargetName
));
680 /* rule out some easy cases */
681 /* FIXME: short vs. long names??? lower case/upper case/mixed case? */
682 if (!(FilterMatch
& NotifyEntry
->CompletionFilter
)) continue;
684 FullDirLen
= TargetNameOffset
- (NotifyEntry
->Unicode
? sizeof(WCHAR
) : sizeof(char));
687 /* special case for root dir */
688 FullDirLen
= (NotifyEntry
->Unicode
? sizeof(WCHAR
) : sizeof(char));
691 if (FullDirLen
< NotifyEntry
->FullDirectoryName
->Length
) continue;
693 if (!NotifyEntry
->WatchTree
&& FullDirLen
!= NotifyEntry
->FullDirectoryName
->Length
) continue;
695 DPRINT("NotifyEntry->FullDirectoryName: %wZ\n", NotifyEntry
->FullDirectoryName
);
697 /* FIXME: short vs. long names??? lower case/upper case/mixed case? */
698 if (memcmp(NotifyEntry
->FullDirectoryName
->Buffer
,
699 FullTargetName
->Buffer
,
700 NotifyEntry
->FullDirectoryName
->Length
) != 0) continue;
703 if (NotifyEntry
->WatchTree
&&
704 NotifyEntry
->TraverseCallback
&&
705 FullDirLen
!= NotifyEntry
->FullDirectoryName
->Length
)
707 /* change happend in a subdir. ask caller if we are allowed in here */
708 NTSTATUS Status
= NotifyEntry
->TraverseCallback(NotifyEntry
->FsContext
,
710 NotifyEntry
->SubjectContext
);
712 if (!NT_SUCCESS(Status
)) continue;
715 FIXME: notify-dir impl. should release and free the SubjectContext
719 DPRINT("Found match\n");
721 /* Found a valid change */
723 RelativeName
.Buffer
= FullTargetName
->Buffer
+ TargetNameOffset
;
724 RelativeName
.MaximumLength
=
725 RelativeName
.Length
=
726 FullTargetName
->Length
- TargetNameOffset
;
728 DPRINT("RelativeName: %wZ\n",&RelativeName
);
730 /* calculate unicode bytes of relative-name + stream-name */
731 if (NotifyEntry
->Unicode
)
733 NameLenU
= RelativeName
.Length
+ (StreamName
? (StreamName
->Length
+ sizeof(WCHAR
)) : 0);
737 NameLenU
= RelativeName
.Length
* sizeof(WCHAR
) +
738 (StreamName
? ((StreamName
->Length
* sizeof(WCHAR
)) + sizeof(WCHAR
)) : 0);
741 RecordLen
= FIELD_OFFSET(FILE_NOTIFY_INFORMATION
, FileName
) + NameLenU
;
743 if ((Irp
= FsRtlpGetNextIrp(NotifyEntry
)))
745 PIO_STACK_LOCATION IrpStack
;
748 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
749 IrpBuffLen
= IrpStack
->Parameters
.NotifyDirectory
.Length
;
751 DPRINT("Got pending irp\n");
753 ASSERT(!NotifyEntry
->PendingChanges
);
755 if (NotifyEntry
->Buffer
== NULL
|| /* aka. IgnoreBuffer */
756 RecordLen
> IrpBuffLen
)
758 /* ignore buffer / buffer not large enough */
759 Irp
->IoStatus
.Status
= STATUS_NOTIFY_ENUM_DIR
;
760 Irp
->IoStatus
.Information
= 0;
764 CurrentEntry
= (PFILE_NOTIFY_INFORMATION
)
765 MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, LowPagePriority
);
769 CurrentEntry
->Action
= Action
;
770 CurrentEntry
->FileNameLength
= NameLenU
;
771 CurrentEntry
->NextEntryOffset
= 0;
775 NotifyEntry
->Unicode
,
780 Irp
->IoStatus
.Information
= RecordLen
;
784 Irp
->IoStatus
.Information
= 0;
788 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
791 /* avoid holding lock while completing irp */
792 InsertTailList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
798 NotifyEntry
->PendingChanges
= TRUE
;
800 if (NotifyEntry
->Buffer
== NULL
|| NotifyEntry
->BufferExhausted
) continue;
802 if (RecordLen
> NotifyEntry
->BufferSize
- NotifyEntry
->NextEntryOffset
)
804 /* overflow. drop these changes and stop buffering any other changes too */
805 NotifyEntry
->BufferExhausted
= TRUE
;
809 /* The buffer has enough room for the changes.
810 * Copy data to buffer.
813 CurrentEntry
= (PFILE_NOTIFY_INFORMATION
)NotifyEntry
->Buffer
;
815 CurrentEntry
->Action
= Action
;
816 CurrentEntry
->FileNameLength
= NameLenU
;
817 CurrentEntry
->NextEntryOffset
= 0;
819 FsRtlpCopyName(CurrentEntry
,
820 NotifyEntry
->Unicode
,
825 if (NotifyEntry
->PrevEntry
)
827 NotifyEntry
->PrevEntry
->NextEntryOffset
= (char*)CurrentEntry
- (char*)NotifyEntry
->PrevEntry
;
829 NotifyEntry
->PrevEntry
= CurrentEntry
;
830 NotifyEntry
->NextEntryOffset
+= RecordLen
;
834 // UNICODE_STRING TmpStr;
835 // TmpStr.Buffer = BufferedChange->RelativeName;
836 // TmpStr.MaximumLength = TmpStr.Length = BufferedChange->NameLen;
837 // DPRINT("BufferedChange->RelativeName: %wZ\n", &TmpStr);
844 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
846 /* complete defered irps */
847 while (!IsListEmpty(&CompletedListHead
))
849 EnumEntry
= RemoveHeadList(&CompletedListHead
);
850 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
852 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
858 /**********************************************************************
860 * FsRtlNotifyInitializeSync@4
872 FsRtlNotifyInitializeSync (
873 IN PNOTIFY_SYNC
*NotifySync
876 *NotifySync
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FAST_MUTEX
), FSRTL_NOTIFY_TAG
);
877 ExInitializeFastMutex((PFAST_MUTEX
)*NotifySync
);
881 /**********************************************************************
883 * FsRtlNotifyReportChange@20
895 FsRtlNotifyReportChange (
896 IN PNOTIFY_SYNC NotifySync
,
897 IN PLIST_ENTRY NotifyList
,
898 IN PSTRING FullTargetName
,
899 IN PUSHORT FileNamePartLength
,
903 FsRtlNotifyFullReportChange (
907 (FullTargetName
->Length
- *FileNamePartLength
),
917 /**********************************************************************
919 * FsRtlNotifyUninitializeSync@4
922 * Uninitialize a NOTIFY_SYNC object.
925 * NotifySync is the address of a pointer
926 * to a PNOTIFY_SYNC object previously initialized by
927 * FsRtlNotifyInitializeSync().
936 FsRtlNotifyUninitializeSync (
937 IN PNOTIFY_SYNC
*NotifySync
940 ExFreePool (*NotifySync
);
943 /**********************************************************************
945 * FsRtlNotifyVolumeEvent@8
948 * NOTE: Only present in NT 5+.
958 FsRtlNotifyVolumeEvent (
959 IN PFILE_OBJECT FileObject
,
963 return STATUS_NOT_IMPLEMENTED
;
972 FsRtlRegisterFileSystemFilterCallbacks(IN PDRIVER_OBJECT FilterDriverObject
,
973 IN PFS_FILTER_CALLBACKS Callbacks
)
976 return STATUS_NOT_IMPLEMENTED
;