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 #define FSRTL_NOTIFY_TAG TAG('N','O','T','I')
21 typedef struct _NOTIFY_ENTRY
24 PSTRING FullDirectoryName
;
26 BOOLEAN PendingChanges
;
27 ULONG CompletionFilter
;
30 PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback
;
31 PSECURITY_SUBJECT_CONTEXT SubjectContext
;
34 BOOLEAN BufferExhausted
;
35 PVOID Buffer
; /* Buffer == NULL equals IgnoreBuffer == TRUE */
37 ULONG NextEntryOffset
;
38 PFILE_NOTIFY_INFORMATION PrevEntry
;
39 } NOTIFY_ENTRY
, *PNOTIFY_ENTRY
;
42 /**********************************************************************
44 * FsRtlpInitNotifyImplementation
49 FsRtlpInitNotifyImplementation(VOID
)
51 ExInitializePagedLookasideList( &NotifyEntryLookaside
,
74 if (Path
->Length
== 1) return FALSE
;
76 if (*(WCHAR
*)Path
->Buffer
== '\\') return TRUE
;
82 /**********************************************************************
84 * FsRtlpNotifyCancelRoutine
90 FsRtlpNotifyCancelRoutine(
91 IN PDEVICE_OBJECT DeviceObject
,
97 //don't need this since we have our own sync. protecting irp cancellation
98 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
100 Lock
= (PFAST_MUTEX
)Irp
->Tail
.Overlay
.DriverContext
[3];
102 ExAcquireFastMutex(Lock
);
104 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
106 ExReleaseFastMutex(Lock
);
108 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
109 Irp
->IoStatus
.Information
= 0;
111 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
120 FsRtlpFindNotifyEntry(
121 PLIST_ENTRY NotifyList
,
125 PLIST_ENTRY EnumEntry
;
126 PNOTIFY_ENTRY NotifyEntry
;
128 LIST_FOR_EACH(EnumEntry
, NotifyList
)
130 NotifyEntry
= CONTAINING_RECORD(EnumEntry
, NOTIFY_ENTRY
, ListEntry
);
132 if (NotifyEntry
->FsContext
== FsContext
)
141 /**********************************************************************
143 * FsRtlNotifyChangeDirectory@28
155 FsRtlNotifyChangeDirectory (
156 IN PNOTIFY_SYNC NotifySync
,
158 IN PSTRING FullDirectoryName
,
159 IN PLIST_ENTRY NotifyList
,
160 IN BOOLEAN WatchTree
,
161 IN ULONG CompletionFilter
,
165 FsRtlNotifyFullChangeDirectory (
171 TRUE
, /* IgnoreBuffer */
181 /**********************************************************************
183 * FsRtlNotifyCleanup@12
186 * Called by FSD when all handles to FileObject (identified by FsContext) are closed
197 IN PNOTIFY_SYNC NotifySync
,
198 IN PLIST_ENTRY NotifyList
,
202 PNOTIFY_ENTRY NotifyEntry
;
203 LIST_ENTRY CompletedListHead
;
204 PLIST_ENTRY TmpEntry
;
207 InitializeListHead(&CompletedListHead
);
209 ExAcquireFastMutex((PFAST_MUTEX
)NotifySync
);
211 NotifyEntry
= FsRtlpFindNotifyEntry(NotifyList
, FsContext
);
215 /* free buffered changes */
216 if (NotifyEntry
->Buffer
)
218 ExFreePool(NotifyEntry
->Buffer
);
221 /* cancel(?) pending irps */
222 while (!IsListEmpty(&NotifyEntry
->IrpQueue
))
224 TmpEntry
= RemoveHeadList(&NotifyEntry
->IrpQueue
);
225 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
227 /* irp cancelation bolilerplate */
228 if (!IoSetCancelRoutine(Irp
, NULL
))
230 //The cancel routine will be called. When we release the lock it will complete the irp.
231 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
235 Irp
->IoStatus
.Status
= STATUS_NOTIFY_CLEANUP
; /* FIXME: correct status? */
236 Irp
->IoStatus
.Information
= 0;
238 /* avoid holding lock while completing irp */
239 InsertTailList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
242 /* Unlink and free the NotifyStruct */
243 RemoveEntryList(&NotifyEntry
->ListEntry
);
244 ExFreeToPagedLookasideList(&NotifyEntryLookaside
, NotifyEntry
);
247 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
249 /* complete defered irps */
250 while (!IsListEmpty(&CompletedListHead
))
252 TmpEntry
= RemoveHeadList(&CompletedListHead
);
253 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
254 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
265 FsRtlNotifyFilterChangeDirectory (
266 IN PNOTIFY_SYNC NotifySync
,
267 IN PLIST_ENTRY NotifyList
,
269 IN PSTRING FullDirectoryName
,
270 IN BOOLEAN WatchTree
,
271 IN BOOLEAN IgnoreBuffer
,
272 IN ULONG CompletionFilter
,
274 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL
,
275 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL
,
276 IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL
287 FsRtlNotifyFilterReportChange (
288 IN PNOTIFY_SYNC NotifySync
,
289 IN PLIST_ENTRY NotifyList
,
290 IN PSTRING FullTargetName
,
291 IN USHORT TargetNameOffset
,
292 IN PSTRING StreamName OPTIONAL
,
293 IN PSTRING NormalizedParentName OPTIONAL
,
294 IN ULONG FilterMatch
,
296 IN PVOID TargetContext
,
297 IN PVOID FilterContext
308 FsRtlpWatchedDirectoryWasDeleted(
309 IN PNOTIFY_SYNC NotifySync
,
310 IN PLIST_ENTRY NotifyList
,
314 LIST_ENTRY CompletedListHead
;
315 PLIST_ENTRY EnumEntry
, TmpEntry
;
316 PNOTIFY_ENTRY NotifyEntry
;
319 InitializeListHead(&CompletedListHead
);
321 ExAcquireFastMutex((PFAST_MUTEX
)NotifySync
);
323 LIST_FOR_EACH_SAFE(EnumEntry
, NotifyList
, NotifyEntry
, NOTIFY_ENTRY
, ListEntry
)
325 if (NotifyEntry
->Fcb
== Fcb
)
327 RemoveEntryList(&NotifyEntry
->ListEntry
);
329 /* free buffered changes */
330 if (NotifyEntry
->Buffer
)
332 ExFreePool(NotifyEntry
->Buffer
);
335 /* cleanup pending irps */
336 while (!IsListEmpty(&NotifyEntry
->IrpQueue
))
338 TmpEntry
= RemoveHeadList(&NotifyEntry
->IrpQueue
);
339 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
341 /* irp cancelation bolilerplate */
342 if (!IoSetCancelRoutine(Irp
, NULL
))
344 //The cancel routine will be called. When we release the lock it will complete the irp.
345 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
349 Irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
350 Irp
->IoStatus
.Information
= 0;
352 /* avoid holding lock while completing irp */
353 InsertTailList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
358 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
360 /* complete defered irps */
361 while (!IsListEmpty(&CompletedListHead
))
363 TmpEntry
= RemoveHeadList(&CompletedListHead
);
364 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
365 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
375 /**********************************************************************
377 * FsRtlNotifyFullChangeDirectory@40
389 FsRtlNotifyFullChangeDirectory (
390 IN PNOTIFY_SYNC NotifySync
,
391 IN PLIST_ENTRY NotifyList
,
393 IN PSTRING FullDirectoryName
,
394 IN BOOLEAN WatchTree
,
395 IN BOOLEAN IgnoreBuffer
,
396 IN ULONG CompletionFilter
,
398 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL
,
399 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL
402 PIO_STACK_LOCATION IrpStack
;
403 PNOTIFY_ENTRY NotifyEntry
;
408 /* all other params are ignored if NotifyIrp == NULL */
409 FsRtlpWatchedDirectoryWasDeleted(NotifySync
, NotifyList
, FsContext
);
413 DPRINT("FullDirectoryName: %wZ\n", FullDirectoryName
);
415 ExAcquireFastMutex((PFAST_MUTEX
)NotifySync
);
417 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
418 if (IrpStack
->FileObject
->Flags
& FO_CLEANUP_COMPLETE
)
420 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
422 Irp
->IoStatus
.Information
= 0;
423 Irp
->IoStatus
.Status
= STATUS_NOTIFY_CLEANUP
;
424 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
428 IrpBuffLen
= IrpStack
->Parameters
.NotifyDirectory
.Length
;
430 NotifyEntry
= FsRtlpFindNotifyEntry(NotifyList
, FsContext
);
434 /* No NotifyStruct for this FileObject existed */
436 /* The first request for this FileObject set the standards.
437 * For subsequent requests, these params will be ignored.
438 * Ref: Windows NT File System Internals page 516
441 NotifyEntry
= ExAllocateFromPagedLookasideList(&NotifyEntryLookaside
);
443 RtlZeroMemory(NotifyEntry
, sizeof(NOTIFY_ENTRY
));
445 NotifyEntry
->FsContext
= FsContext
;
446 NotifyEntry
->FullDirectoryName
= FullDirectoryName
;
447 NotifyEntry
->WatchTree
= WatchTree
;
448 NotifyEntry
->CompletionFilter
= CompletionFilter
;
449 NotifyEntry
->TraverseCallback
= TraverseCallback
;
450 NotifyEntry
->SubjectContext
= SubjectContext
;
451 NotifyEntry
->Fcb
= IrpStack
->FileObject
->FsContext
;
452 NotifyEntry
->Unicode
= FsRtlpIsUnicodePath(FullDirectoryName
);
455 if (IrpBuffLen
&& !IgnoreBuffer
)
459 NotifyEntry
->Buffer
= ExAllocatePoolWithQuotaTag(
465 NotifyEntry
->BufferSize
= IrpBuffLen
;
469 /* ExAllocatePoolWithQuotaTag raised exception but we dont care.
470 The impl. doesnt require a buffer, so well continue as usual.
476 InitializeListHead(&NotifyEntry
->IrpQueue
);
478 InsertTailList(NotifyList
, &NotifyEntry
->ListEntry
);
483 if (!NotifyEntry
->PendingChanges
)
485 /* No changes are pending. Queue the irp */
487 /* Irp cancelation boilerplate */
489 /* save NotifySych for use in the cancel routine */
490 Irp
->Tail
.Overlay
.DriverContext
[3] = NotifySync
;
492 IoSetCancelRoutine(Irp
, FsRtlpNotifyCancelRoutine
);
493 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
496 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
498 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
499 Irp
->IoStatus
.Information
= 0;
501 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
505 IoMarkIrpPending(Irp
);
507 //FIXME: any point in setting irp status/information before queueing?
508 Irp
->IoStatus
.Status
= STATUS_PENDING
;
510 InsertTailList(&NotifyEntry
->IrpQueue
, &Irp
->Tail
.Overlay
.ListEntry
);
512 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
517 /* Pending changes exist */
519 if (NotifyEntry
->Buffer
== NULL
||
520 NotifyEntry
->BufferExhausted
||
521 IrpBuffLen
< NotifyEntry
->NextEntryOffset
)
524 Can't return detailed changes to user cause:
526 -Buffer were overflowed, OR
527 -Current irp buff was not large enough
530 Irp
->IoStatus
.Information
= 0;
531 Irp
->IoStatus
.Status
= STATUS_NOTIFY_ENUM_DIR
;
536 PVOID Adr
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, LowPagePriority
);
540 memcpy(Adr
, NotifyEntry
->Buffer
, NotifyEntry
->NextEntryOffset
);
541 Irp
->IoStatus
.Information
= NotifyEntry
->NextEntryOffset
;
545 Irp
->IoStatus
.Information
= 0;
548 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
552 NotifyEntry
->PrevEntry
= NULL
;
553 NotifyEntry
->NextEntryOffset
= 0;
554 NotifyEntry
->BufferExhausted
= FALSE
;
556 NotifyEntry
->PendingChanges
= FALSE
;
558 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
560 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
562 /* caller must return STATUS_PENDING */
570 FsRtlpGetNextIrp(PNOTIFY_ENTRY NotifyEntry
)
573 PLIST_ENTRY TmpEntry
;
575 /* Loop to get a non-canceled irp */
576 while (!IsListEmpty(&NotifyEntry
->IrpQueue
))
578 /* If we have queued irp(s) we can't possibly have pending changes too */
579 ASSERT(!NotifyEntry
->PendingChanges
);
581 TmpEntry
= RemoveHeadList(&NotifyEntry
->IrpQueue
);
582 Irp
= CONTAINING_RECORD(TmpEntry
, IRP
, Tail
.Overlay
.ListEntry
);
584 /* irp cancelation bolilerplate */
585 if (!IoSetCancelRoutine(Irp
, NULL
))
587 //The cancel routine will be called. When we release the lock it will complete the irp.
588 InitializeListHead(&Irp
->Tail
.Overlay
.ListEntry
);
592 /* Finally we got a non-canceled irp */
604 PFILE_NOTIFY_INFORMATION CurrentEntry
,
606 PSTRING RelativeName
,
610 /* Buffer size is allready probed, so just copy the data */
614 memcpy(CurrentEntry
->Name
, RelativeName
->Buffer
, RelativeName
->Length
);
617 CurrentEntry
->Name
[RelativeName
->Length
/sizeof(WCHAR
)] = ':';
618 memcpy(&CurrentEntry
->Name
[(RelativeName
->Length
/sizeof(WCHAR
))+1],
625 //FIXME: convert to unicode etc.
626 DPRINT1("FIXME: ansi strings in notify impl. not supported yet\n");
631 /**********************************************************************
633 * FsRtlNotifyFullReportChange@36
645 FsRtlNotifyFullReportChange (
646 IN PNOTIFY_SYNC NotifySync
,
647 IN PLIST_ENTRY NotifyList
,
648 IN PSTRING FullTargetName
, /* can include short names! */
649 IN USHORT TargetNameOffset
, /* in bytes */
650 IN PSTRING StreamName OPTIONAL
,
651 IN PSTRING NormalizedParentName OPTIONAL
, /* same as FullTargetName, but with long names */
652 IN ULONG FilterMatch
,
654 IN PVOID TargetContext
659 PLIST_ENTRY EnumEntry
;
660 PNOTIFY_ENTRY NotifyEntry
;
662 LIST_ENTRY CompletedListHead
;
665 PFILE_NOTIFY_INFORMATION CurrentEntry
;
667 InitializeListHead(&CompletedListHead
);
669 DPRINT("FullTargetName: %wZ\n", FullTargetName
);
672 I think FullTargetName can include/be a short file name! What the heck do i do with this?
673 Dont think this apply to FsRtlNotifyFullChangeDirectory's FullDirectoryName.
679 ExAcquireFastMutex((PFAST_MUTEX
)NotifySync
);
681 LIST_FOR_EACH_SAFE(EnumEntry
, NotifyList
, NotifyEntry
, NOTIFY_ENTRY
, ListEntry
)
683 ASSERT(NotifyEntry
->Unicode
== FsRtlpIsUnicodePath(FullTargetName
));
685 /* rule out some easy cases */
686 /* FIXME: short vs. long names??? lower case/upper case/mixed case? */
687 if (!(FilterMatch
& NotifyEntry
->CompletionFilter
)) continue;
689 FullDirLen
= TargetNameOffset
- (NotifyEntry
->Unicode
? sizeof(WCHAR
) : sizeof(char));
692 /* special case for root dir */
693 FullDirLen
= (NotifyEntry
->Unicode
? sizeof(WCHAR
) : sizeof(char));
696 if (FullDirLen
< NotifyEntry
->FullDirectoryName
->Length
) continue;
698 if (!NotifyEntry
->WatchTree
&& FullDirLen
!= NotifyEntry
->FullDirectoryName
->Length
) continue;
700 DPRINT("NotifyEntry->FullDirectoryName: %wZ\n", NotifyEntry
->FullDirectoryName
);
702 /* FIXME: short vs. long names??? lower case/upper case/mixed case? */
703 if (memcmp(NotifyEntry
->FullDirectoryName
->Buffer
,
704 FullTargetName
->Buffer
,
705 NotifyEntry
->FullDirectoryName
->Length
) != 0) continue;
708 if (NotifyEntry
->WatchTree
&&
709 NotifyEntry
->TraverseCallback
&&
710 FullDirLen
!= NotifyEntry
->FullDirectoryName
->Length
)
712 /* change happend in a subdir. ask caller if we are allowed in here */
713 NTSTATUS Status
= NotifyEntry
->TraverseCallback(NotifyEntry
->FsContext
,
715 NotifyEntry
->SubjectContext
);
717 if (!NT_SUCCESS(Status
)) continue;
720 FIXME: notify-dir impl. should release and free the SubjectContext
724 DPRINT("Found match\n");
726 /* Found a valid change */
728 RelativeName
.Buffer
= FullTargetName
->Buffer
+ TargetNameOffset
;
729 RelativeName
.MaximumLength
=
730 RelativeName
.Length
=
731 FullTargetName
->Length
- TargetNameOffset
;
733 DPRINT("RelativeName: %wZ\n",&RelativeName
);
735 /* calculate unicode bytes of relative-name + stream-name */
736 if (NotifyEntry
->Unicode
)
738 NameLenU
= RelativeName
.Length
+ (StreamName
? (StreamName
->Length
+ sizeof(WCHAR
)) : 0);
742 NameLenU
= RelativeName
.Length
* sizeof(WCHAR
) +
743 (StreamName
? ((StreamName
->Length
* sizeof(WCHAR
)) + sizeof(WCHAR
)) : 0);
746 RecordLen
= FIELD_OFFSET(FILE_NOTIFY_INFORMATION
, Name
) + NameLenU
;
748 if ((Irp
= FsRtlpGetNextIrp(NotifyEntry
)))
750 PIO_STACK_LOCATION IrpStack
;
753 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
754 IrpBuffLen
= IrpStack
->Parameters
.NotifyDirectory
.Length
;
756 DPRINT("Got pending irp\n");
758 ASSERT(!NotifyEntry
->PendingChanges
);
760 if (NotifyEntry
->Buffer
== NULL
|| /* aka. IgnoreBuffer */
761 RecordLen
> IrpBuffLen
)
763 /* ignore buffer / buffer not large enough */
764 Irp
->IoStatus
.Status
= STATUS_NOTIFY_ENUM_DIR
;
765 Irp
->IoStatus
.Information
= 0;
769 CurrentEntry
= (PFILE_NOTIFY_INFORMATION
)
770 MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, LowPagePriority
);
774 CurrentEntry
->Action
= Action
;
775 CurrentEntry
->NameLength
= NameLenU
;
776 CurrentEntry
->NextEntryOffset
= 0;
780 NotifyEntry
->Unicode
,
785 Irp
->IoStatus
.Information
= RecordLen
;
789 Irp
->IoStatus
.Information
= 0;
793 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
796 /* avoid holding lock while completing irp */
797 InsertTailList(&CompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
803 NotifyEntry
->PendingChanges
= TRUE
;
805 if (NotifyEntry
->Buffer
== NULL
|| NotifyEntry
->BufferExhausted
) continue;
807 if (RecordLen
> NotifyEntry
->BufferSize
- NotifyEntry
->NextEntryOffset
)
809 /* overflow. drop these changes and stop buffering any other changes too */
810 NotifyEntry
->BufferExhausted
= TRUE
;
814 /* The buffer has enough room for the changes.
815 * Copy data to buffer.
818 CurrentEntry
= (PFILE_NOTIFY_INFORMATION
)NotifyEntry
->Buffer
;
820 CurrentEntry
->Action
= Action
;
821 CurrentEntry
->NameLength
= NameLenU
;
822 CurrentEntry
->NextEntryOffset
= 0;
824 FsRtlpCopyName(CurrentEntry
,
825 NotifyEntry
->Unicode
,
830 if (NotifyEntry
->PrevEntry
)
832 NotifyEntry
->PrevEntry
->NextEntryOffset
= (char*)CurrentEntry
- (char*)NotifyEntry
->PrevEntry
;
834 NotifyEntry
->PrevEntry
= CurrentEntry
;
835 NotifyEntry
->NextEntryOffset
+= RecordLen
;
839 // UNICODE_STRING TmpStr;
840 // TmpStr.Buffer = BufferedChange->RelativeName;
841 // TmpStr.MaximumLength = TmpStr.Length = BufferedChange->NameLen;
842 // DPRINT("BufferedChange->RelativeName: %wZ\n", &TmpStr);
849 ExReleaseFastMutex((PFAST_MUTEX
)NotifySync
);
851 /* complete defered irps */
852 while (!IsListEmpty(&CompletedListHead
))
854 EnumEntry
= RemoveHeadList(&CompletedListHead
);
855 Irp
= CONTAINING_RECORD(EnumEntry
, IRP
, Tail
.Overlay
.ListEntry
);
857 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
863 /**********************************************************************
865 * FsRtlNotifyInitializeSync@4
877 FsRtlNotifyInitializeSync (
878 IN PNOTIFY_SYNC
*NotifySync
881 *NotifySync
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FAST_MUTEX
), FSRTL_NOTIFY_TAG
);
882 ExInitializeFastMutex((PFAST_MUTEX
)*NotifySync
);
886 /**********************************************************************
888 * FsRtlNotifyReportChange@20
900 FsRtlNotifyReportChange (
901 IN PNOTIFY_SYNC NotifySync
,
902 IN PLIST_ENTRY NotifyList
,
903 IN PSTRING FullTargetName
,
904 IN PUSHORT FileNamePartLength
,
908 FsRtlNotifyFullReportChange (
912 (FullTargetName
->Length
- *FileNamePartLength
),
922 /**********************************************************************
924 * FsRtlNotifyUninitializeSync@4
927 * Uninitialize a NOTIFY_SYNC object.
930 * NotifySync is the address of a pointer
931 * to a PNOTIFY_SYNC object previously initialized by
932 * FsRtlNotifyInitializeSync().
941 FsRtlNotifyUninitializeSync (
942 IN PNOTIFY_SYNC NotifySync
945 ExFreePool (NotifySync
);
948 /**********************************************************************
950 * FsRtlNotifyVolumeEvent@8
953 * NOTE: Only present in NT 5+.
963 FsRtlNotifyVolumeEvent (
964 IN PFILE_OBJECT FileObject
,
968 return STATUS_NOT_IMPLEMENTED
;
977 FsRtlRegisterFileSystemFilterCallbacks(IN PDRIVER_OBJECT FilterDriverObject
,
978 IN PFS_FILTER_CALLBACKS Callbacks
)
981 return STATUS_NOT_IMPLEMENTED
;