ReactOS 0.4.15-dev-7934-g1dc8d80
notify.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/notify.c
5 * PURPOSE: Change Notifications and Sync for File System Drivers
6 * PROGRAMMERS: Pierre Schweitzer
7 */
8
9/* INCLUDES ******************************************************************/
10
11#include <ntoskrnl.h>
12#define NDEBUG
13#include <debug.h>
14
15/* INLINED FUNCTIONS *********************************************************/
16
17/*
18 * @implemented
19 */
21VOID
23{
24 ULONG_PTR CurrentThread = (ULONG_PTR)KeGetCurrentThread();
25
26 /* Only acquire fast mutex if it's not already acquired by the current thread */
27 if (RealNotifySync->OwningThread != CurrentThread)
28 {
29 ExAcquireFastMutexUnsafe(&(RealNotifySync->FastMutex));
30 RealNotifySync->OwningThread = CurrentThread;
31 }
32 /* Whatever the case, keep trace of the attempt to acquire fast mutex */
33 RealNotifySync->OwnerCount++;
34}
35
36/*
37 * @implemented
38 */
40VOID
42{
43 RealNotifySync->OwnerCount--;
44 /* Release the fast mutex only if no other instance needs it */
45 if (!RealNotifySync->OwnerCount)
46 {
47 ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex));
48 RealNotifySync->OwningThread = (ULONG_PTR)0;
49 }
50}
51
52#define FsRtlNotifyGetLastPartOffset(FullLen, TargLen, Type, Chr) \
53 for (FullPosition = 0; FullPosition < FullLen; ++FullPosition) \
54 if (((Type)NotifyChange->FullDirectoryName->Buffer)[FullPosition] == Chr) \
55 ++FullNumberOfParts; \
56 for (LastPartOffset = 0; LastPartOffset < TargLen; ++LastPartOffset) { \
57 if ( ((Type)TargetDirectory.Buffer)[LastPartOffset] == Chr) { \
58 ++TargetNumberOfParts; \
59 if (TargetNumberOfParts == FullNumberOfParts) \
60 break; \
61 } \
62 }
63
64/* PRIVATE FUNCTIONS *********************************************************/
65
66VOID
69
72 IN PNOTIFY_CHANGE NotifyChange OPTIONAL);
73
74/*
75 * @implemented
76 */
77VOID
80 IN PIRP Irp)
81{
86 PNOTIFY_CHANGE NotifyChange;
87 PREAL_NOTIFY_SYNC RealNotifySync;
88 BOOLEAN PoolQuotaCharged;
90
91 /* Get the NOTIFY_CHANGE struct and reset it */
92 NotifyChange = (PNOTIFY_CHANGE)Irp->IoStatus.Information;
93 Irp->IoStatus.Information = 0;
94 /* Reset the cancel routine */
96 /* And release lock */
97 IoReleaseCancelSpinLock(Irp->CancelIrql);
98 /* Get REAL_NOTIFY_SYNC struct */
99 RealNotifySync = NotifyChange->NotifySync;
100
101 FsRtlNotifyAcquireFastMutex(RealNotifySync);
102
104 {
105 /* Remove the IRP from the notifications list and mark it pending */
106 RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
108
109 /* Now, the tricky part - let's find a buffer big enough to hold the return data */
110 if (NotifyChange->Buffer && NotifyChange->AllocatedBuffer == NULL &&
111 ((Irp->MdlAddress && MmGetSystemAddressForMdl(Irp->MdlAddress) == NotifyChange->Buffer) ||
112 NotifyChange->Buffer == Irp->AssociatedIrp.SystemBuffer))
113 {
114 /* Assume we didn't find any */
115 Buffer = NULL;
116 BufferLength = 0;
117
118 /* If we don't have IRPs, check if current buffer is big enough */
119 if (IsListEmpty(&NotifyChange->NotifyIrps))
120 {
121 if (NotifyChange->BufferLength >= NotifyChange->DataLength)
122 {
123 BufferLength = NotifyChange->BufferLength;
124 }
125 }
126 else
127 {
128 /* Otherwise, try to look at next IRP available */
129 NotifyIrp = CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, IRP, Tail.Overlay.ListEntry);
131
132 /* If its buffer is big enough, get it */
133 if (Stack->Parameters.NotifyDirectory.Length >= NotifyChange->BufferLength)
134 {
135 /* Is it MDL? */
136 if (NotifyIrp->AssociatedIrp.SystemBuffer == NULL)
137 {
138 if (NotifyIrp->MdlAddress != NULL)
139 {
141 }
142 }
143 else
144 {
145 Buffer = NotifyIrp->AssociatedIrp.MasterIrp;
146 }
147
148 /* Backup our accepted buffer length */
149 BufferLength = Stack->Parameters.NotifyDirectory.Length;
150 if (BufferLength > NotifyChange->BufferLength)
151 {
152 BufferLength = NotifyChange->BufferLength;
153 }
154 }
155 }
156
157 /* At that point, we *may* have a buffer */
158
159 /* If it has null length, then note that we won't use it */
160 if (BufferLength == 0)
161 {
162 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
163 }
164 else
165 {
166 /* If we have a buffer length, but no buffer then allocate one */
167 if (Buffer == NULL)
168 {
169 /* Assume we haven't charged quotas */
170 PoolQuotaCharged = FALSE;
171
173 {
174 /* Charge quotas */
176 PoolQuotaCharged = TRUE;
177
178 /* Allocate buffer */
180 NotifyChange->AllocatedBuffer = Buffer;
181
182 /* Copy data in that buffer */
183 RtlCopyMemory(Buffer, NotifyChange->Buffer, NotifyChange->DataLength);
184 NotifyChange->ThisBufferLength = BufferLength;
185 NotifyChange->Buffer = Buffer;
186 }
188 {
189 /* Something went wrong, have we charged quotas? */
190 if (PoolQuotaCharged)
191 {
192 /* We did, return quotas */
194 }
195
196 /* And notify immediately */
197 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
198 }
199 _SEH2_END;
200 }
201 }
202
203 /* If we have to notify immediately, ensure that any buffer is 0-ed out */
204 if (NotifyChange->Flags & NOTIFY_IMMEDIATELY)
205 {
206 NotifyChange->Buffer = 0;
207 NotifyChange->AllocatedBuffer = 0;
208 NotifyChange->LastEntry = 0;
209 NotifyChange->DataLength = 0;
210 NotifyChange->ThisBufferLength = 0;
211 }
212 }
213
214 /* It's now time to complete - data are ready */
215
216 /* Set appropriate status and complete */
217 Irp->IoStatus.Status = STATUS_CANCELLED;
219
220 /* If that notification isn't referenced any longer, drop it */
221 if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount)))
222 {
223 /* If it had an allocated buffer, delete */
224 if (NotifyChange->AllocatedBuffer)
225 {
228 }
229
230 /* In case of full name, remember subject context for later deletion */
231 if (NotifyChange->FullDirectoryName)
232 {
233 SubjectContext = NotifyChange->SubjectContext;
234 }
235
236 /* We mustn't have ANY change left anymore */
237 ASSERT(NotifyChange->NotifyList.Flink == NULL);
238 ExFreePoolWithTag(NotifyChange, 0);
239 }
240 }
242 {
243 FsRtlNotifyReleaseFastMutex(RealNotifySync);
244
245 /* If the subject security context was captured, release and free it */
246 if (SubjectContext)
247 {
250 }
251 }
252 _SEH2_END;
253}
254
255/*
256 * @implemented
257 */
258VOID
261{
262 PLIST_ENTRY NextEntry;
263 PNOTIFY_CHANGE NotifyChange;
264
266 {
267 /* Browse the notifications list to find the matching entry */
268 for (NextEntry = NotifyList->Flink;
269 NextEntry != NotifyList;
270 NextEntry = NextEntry->Flink)
271 {
272 NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
273 /* If the current record matches with the given context, it's the good one */
274 if (NotifyChange->FsContext == FsContext && !IsListEmpty(&(NotifyChange->NotifyIrps)))
275 {
277 }
278 }
279 }
280}
281
282/*
283 *@implemented
284 */
288{
289 PLIST_ENTRY NextEntry;
290 PNOTIFY_CHANGE NotifyChange;
291
293 {
294 /* Browse the notifications list to find the matching entry */
295 for (NextEntry = NotifyList->Flink;
296 NextEntry != NotifyList;
297 NextEntry = NextEntry->Flink)
298 {
299 NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
300 /* If the current record matches with the given context, it's the good one */
301 if (NotifyChange->FsContext == FsContext)
302 {
303 return NotifyChange;
304 }
305 }
306 }
307 return NULL;
308}
309
310/*
311 * @implemented
312 */
313VOID
315 IN PNOTIFY_CHANGE NotifyChange,
318 IN BOOLEAN SkipCompletion)
319{
322
323 PAGED_CODE();
324
325 /* Check if we need to complete */
326 if (!FsRtlNotifySetCancelRoutine(Irp, NotifyChange) && SkipCompletion)
327 {
328 return;
329 }
330
331 /* No succes => no data to return just complete */
332 if (Status != STATUS_SUCCESS)
333 {
334 goto Completion;
335 }
336
337 /* Ensure there's something to return */
339 if (!DataLength || Stack->Parameters.NotifyDirectory.Length < DataLength)
340 {
342 goto Completion;
343 }
344
345 /* Ensture there's a buffer where to find data */
346 if (!NotifyChange->AllocatedBuffer)
347 {
348 Irp->IoStatus.Information = DataLength;
349 NotifyChange->Buffer = NULL;
350 goto Completion;
351 }
352
353 /* Now, browse all the way to return data
354 * and find the one that will work. We will
355 * return data whatever happens
356 */
357 if (Irp->AssociatedIrp.SystemBuffer)
358 {
359 Buffer = Irp->AssociatedIrp.SystemBuffer;
360 goto CopyAndComplete;
361 }
362
363 if (Irp->MdlAddress)
364 {
365 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
366 goto CopyAndComplete;
367 }
368
369 if (!(Stack->Control & SL_PENDING_RETURNED))
370 {
371 Buffer = Irp->UserBuffer;
372 goto CopyAndComplete;
373 }
374
376 Irp->AssociatedIrp.SystemBuffer = NotifyChange->AllocatedBuffer;
377 /* Nothing to copy */
378 goto ReleaseAndComplete;
379
380CopyAndComplete:
382 {
383 RtlCopyMemory(Buffer, NotifyChange->AllocatedBuffer, DataLength);
384 }
386 {
387 /* Do nothing */
388 }
389 _SEH2_END;
390
391ReleaseAndComplete:
392 PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
393
394 /* Release buffer UNLESS it's used */
395 if (NotifyChange->AllocatedBuffer != Irp->AssociatedIrp.SystemBuffer &&
396 NotifyChange->AllocatedBuffer)
397 {
398 ExFreePoolWithTag(NotifyChange->AllocatedBuffer, 0);
399 }
400
401 /* Prepare for return */
402 NotifyChange->AllocatedBuffer = 0;
403 NotifyChange->ThisBufferLength = 0;
404 Irp->IoStatus.Information = DataLength;
405 NotifyChange->Buffer = NULL;
406
407 /* Finally complete */
408Completion:
410 Irp->IoStatus.Status = Status;
412}
413
414/*
415 * @implemented
416 */
417VOID
420{
421 PIRP Irp;
423 PLIST_ENTRY NextEntry;
424
425 DataLength = NotifyChange->DataLength;
426
427 NotifyChange->Flags &= (NOTIFY_IMMEDIATELY | WATCH_TREE);
428 NotifyChange->DataLength = 0;
429 NotifyChange->LastEntry = 0;
430
431 while (!IsListEmpty(&(NotifyChange->NotifyIrps)))
432 {
433 /* We take the first entry */
434 NextEntry = RemoveHeadList(&(NotifyChange->NotifyIrps));
435 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
436 /* We complete it */
438 /* If we're notifying success, just notify first one */
439 if (Status == STATUS_SUCCESS)
440 break;
441 }
442}
443
444/*
445 * @implemented
446 */
449 IN PNOTIFY_CHANGE NotifyChange OPTIONAL)
450{
452
453 /* Acquire cancel lock */
454 IoAcquireCancelSpinLock(&Irp->CancelIrql);
455
456 /* If NotifyChange was given */
457 if (NotifyChange)
458 {
459 /* First get cancel routine */
461 Irp->IoStatus.Information = 0;
462 /* Release cancel lock */
463 IoReleaseCancelSpinLock(Irp->CancelIrql);
464 /* If there was a cancel routine */
465 if (CancelRoutine)
466 {
467 /* Decrease reference count */
468 InterlockedDecrement((PLONG)&NotifyChange->ReferenceCount);
469 /* Notify that we removed cancel routine */
470 return TRUE;
471 }
472 }
473 else
474 {
475 /* If IRP is cancel, call FsRtl cancel routine */
476 if (Irp->Cancel)
477 {
479 }
480 else
481 {
482 /* Otherwise, define FsRtl cancel routine as IRP cancel routine */
484 /* Release lock */
485 IoReleaseCancelSpinLock(Irp->CancelIrql);
486 }
487 }
488
489 /* Return that we didn't removed cancel routine */
490 return FALSE;
491}
492
493/*
494 * @implemented
495 */
499 IN PSTRING ParentName,
502 IN BOOLEAN IsUnicode,
504{
505 /* Unless there's an issue with buffers, there's no reason to fail */
506 BOOLEAN Succeed = TRUE;
507 ULONG AlreadyWritten = 0, ResultSize;
508
509 PAGED_CODE();
510
511 /* Update user buffer with the change that occured
512 * First copy parent name if any
513 * Then copy target name, there's always one
514 * And finally, copy stream name if any
515 * If these names aren't unicode, then convert first
516 */
518 {
519 OutputBuffer->NextEntryOffset = 0;
520 OutputBuffer->Action = Action;
522 if (IsUnicode)
523 {
524 if (ParentName->Length)
525 {
526 RtlCopyMemory(OutputBuffer->FileName, ParentName->Buffer, ParentName->Length);
527 OutputBuffer->FileName[ParentName->Length / sizeof(WCHAR)] = L'\\';
528 AlreadyWritten = ParentName->Length + sizeof(WCHAR);
529 }
530 RtlCopyMemory((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten),
531 TargetName->Buffer, TargetName->Length);
532 if (StreamName)
533 {
534 AlreadyWritten += TargetName->Length;
535 OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = L':';
536 RtlCopyMemory((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten + sizeof(WCHAR)),
537 StreamName->Buffer, StreamName->Length);
538 }
539 }
540 else
541 {
542 if (!ParentName->Length)
543 {
545 RtlCopyMemory(OutputBuffer->FileName, StreamName->Buffer, StreamName->Length);
546 }
547 else
548 {
549 RtlOemToUnicodeN(OutputBuffer->FileName, OutputBuffer->FileNameLength,
550 &ResultSize, ParentName->Buffer,
551 ParentName->Length);
552 OutputBuffer->FileName[ResultSize / sizeof(WCHAR)] = L'\\';
553 AlreadyWritten = ResultSize + sizeof(WCHAR);
554
555 RtlOemToUnicodeN((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten),
556 OutputBuffer->FileNameLength, &ResultSize,
557 TargetName->Buffer, TargetName->Length);
558
559 if (StreamName)
560 {
561 AlreadyWritten += ResultSize;
562 OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = L':';
563 RtlOemToUnicodeN((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten + sizeof(WCHAR)),
564 OutputBuffer->FileNameLength, &ResultSize,
565 StreamName->Buffer, StreamName->Length);
566 }
567 }
568 }
569 }
571 {
572 Succeed = FALSE;
573 }
574 _SEH2_END;
575
576 return Succeed;
577}
578
579/* PUBLIC FUNCTIONS **********************************************************/
580
581/*++
582 * @name FsRtlNotifyChangeDirectory
583 * @implemented
584 *
585 * Lets FSD know if changes occures in the specified directory.
586 * Directory will be reenumerated.
587 *
588 * @param NotifySync
589 * Synchronization object pointer
590 *
591 * @param FsContext
592 * Used to identify the notify structure
593 *
594 * @param FullDirectoryName
595 * String (A or W) containing the full directory name
596 *
597 * @param NotifyList
598 * Notify list pointer (to head)
599 *
600 * @param WatchTree
601 * True to notify changes in subdirectories too
602 *
603 * @param CompletionFilter
604 * Used to define types of changes to notify
605 *
606 * @param NotifyIrp
607 * IRP pointer to complete notify operation. It can be null
608 *
609 * @return None
610 *
611 * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
612 *
613 *--*/
614VOID
615NTAPI
623{
626 FsContext,
628 WatchTree,
629 TRUE,
631 NotifyIrp,
632 NULL,
633 NULL,
634 NULL);
635}
636
637/*++
638 * @name FsRtlNotifyCleanup
639 * @implemented
640 *
641 * Called by FSD when all handles to FileObject (identified by FsContext) are closed
642 *
643 * @param NotifySync
644 * Synchronization object pointer
645 *
646 * @param NotifyList
647 * Notify list pointer (to head)
648 *
649 * @param FsContext
650 * Used to identify the notify structure
651 *
652 * @return None
653 *
654 * @remarks None
655 *
656 *--*/
657VOID
658NTAPI
662{
663 PNOTIFY_CHANGE NotifyChange;
664 PREAL_NOTIFY_SYNC RealNotifySync;
666
667 /* Get real structure hidden behind the opaque pointer */
668 RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
669
670 /* Acquire the fast mutex */
671 FsRtlNotifyAcquireFastMutex(RealNotifySync);
672
674 {
675 /* Find if there's a matching notification with the FsContext */
677 if (NotifyChange)
678 {
679 /* Mark it as to know that cleanup is in process */
680 NotifyChange->Flags |= CLEANUP_IN_PROCESS;
681
682 /* If there are pending IRPs, complete them using the STATUS_NOTIFY_CLEANUP status */
683 if (!IsListEmpty(&NotifyChange->NotifyIrps))
684 {
686 }
687
688 /* Decrease reference number and if 0 is reached, it's time to do complete cleanup */
689 if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount)))
690 {
691 /* Remove it from the notifications list */
692 RemoveEntryList(&NotifyChange->NotifyList);
693
694 /* In case there was an allocated buffer, free it */
695 if (NotifyChange->AllocatedBuffer)
696 {
698 ExFreePool(NotifyChange->AllocatedBuffer);
699 }
700
701 /* In case there the string was set, get the captured subject security context */
702 if (NotifyChange->FullDirectoryName)
703 {
704 SubjectContext = NotifyChange->SubjectContext;
705 }
706
707 /* Finally, free the notification, as it's not needed anymore */
708 ExFreePoolWithTag(NotifyChange, 'NrSF');
709 }
710 }
711 }
713 {
714 /* Release fast mutex */
715 FsRtlNotifyReleaseFastMutex(RealNotifySync);
716
717 /* If the subject security context was captured, release and free it */
718 if (SubjectContext)
719 {
722 }
723 }
724 _SEH2_END;
725}
726
727/*++
728 * @name FsRtlNotifyFilterChangeDirectory
729 * @implemented
730 *
731 * FILLME
732 *
733 * @param NotifySync
734 * FILLME
735 *
736 * @param NotifyList
737 * FILLME
738 *
739 * @param FsContext
740 * FILLME
741 *
742 * @param FullDirectoryName
743 * FILLME
744 *
745 * @param WatchTree
746 * FILLME
747 *
748 * @param IgnoreBuffer
749 * FILLME
750 *
751 * @param CompletionFilter
752 * FILLME
753 *
754 * @param NotifyIrp
755 * FILLME
756 *
757 * @param TraverseCallback
758 * FILLME
759 *
760 * @param SubjectContext
761 * FILLME
762 *
763 * @param FilterCallback
764 * FILLME
765 *
766 * @return None
767 *
768 * @remarks None
769 *
770 *--*/
771VOID
772NTAPI
784{
785 ULONG SavedLength;
787 PNOTIFY_CHANGE NotifyChange = NULL;
788 PREAL_NOTIFY_SYNC RealNotifySync;
789
790 PAGED_CODE();
791
792 DPRINT("FsRtlNotifyFilterChangeDirectory(): %p, %p, %p, %wZ, %u, %u, %u, %p, %p, %p, %p\n",
795
796 /* Get real structure hidden behind the opaque pointer */
797 RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
798
799 /* Acquire the fast mutex */
800 FsRtlNotifyAcquireFastMutex(RealNotifySync);
801
803 {
804 /* If we have no IRP, FSD is performing a cleanup */
805 if (!NotifyIrp)
806 {
807 /* So, we delete */
810 }
811
812 NotifyIrp->IoStatus.Status = STATUS_SUCCESS;
813 NotifyIrp->IoStatus.Information = (ULONG_PTR)NULL;
814
816 /* If FileObject's been cleaned up, just return */
817 if (Stack->FileObject->Flags & FO_CLEANUP_COMPLETE)
818 {
820 NotifyIrp->IoStatus.Status = STATUS_NOTIFY_CLEANUP;
823 }
824
825 /* Try to find a matching notification has been already registered */
827 if (NotifyChange)
828 {
829 /* If it's been found, and is cleaned up, immediatly complete */
830 if (NotifyChange->Flags & CLEANUP_IN_PROCESS)
831 {
833 NotifyIrp->IoStatus.Status = STATUS_NOTIFY_CLEANUP;
835 }
836 /* Or if it's about to be deleted, complete */
837 else if (NotifyChange->Flags & DELETE_IN_PROCESS)
838 {
840 NotifyIrp->IoStatus.Status = STATUS_DELETE_PENDING;
842 }
843 /* Complete now if asked to (and not asked to notify later on) */
844 if ((NotifyChange->Flags & NOTIFY_IMMEDIATELY) && !(NotifyChange->Flags & NOTIFY_LATER))
845 {
846 NotifyChange->Flags &= ~NOTIFY_IMMEDIATELY;
848 NotifyIrp->IoStatus.Status = STATUS_NOTIFY_ENUM_DIR;
850 }
851 /* If no data yet, or asked to notify later on, handle */
852 else if (NotifyChange->DataLength == 0 || (NotifyChange->Flags & NOTIFY_LATER))
853 {
854 goto HandleIRP;
855 }
856 /* Else, just complete with we have */
857 else
858 {
859 SavedLength = NotifyChange->DataLength;
860 NotifyChange->DataLength = 0;
861 FsRtlNotifyCompleteIrp(NotifyIrp, NotifyChange, SavedLength, STATUS_SUCCESS, FALSE);
862 }
863
865 }
866
867 /* Allocate new notification */
869 sizeof(NOTIFY_CHANGE), 'NrSF');
870 RtlZeroMemory(NotifyChange, sizeof(NOTIFY_CHANGE));
871
872 /* Set basic information */
873 NotifyChange->NotifySync = NotifySync;
874 NotifyChange->FsContext = FsContext;
875 NotifyChange->StreamID = Stack->FileObject->FsContext;
876 NotifyChange->TraverseCallback = TraverseCallback;
877 NotifyChange->SubjectContext = SubjectContext;
878 NotifyChange->FullDirectoryName = FullDirectoryName;
879 NotifyChange->FilterCallback = FilterCallback;
880 InitializeListHead(&(NotifyChange->NotifyIrps));
881
882 /* Keep trace of WatchTree */
883 if (WatchTree)
884 {
885 NotifyChange->Flags |= WATCH_TREE;
886 }
887
888 /* If string is empty, faulty to ANSI */
889 if (FullDirectoryName->Length == 0)
890 {
891 NotifyChange->CharacterSize = sizeof(CHAR);
892 }
893 else
894 {
895 /* If it can't contain WCHAR, it's ANSI */
896 if (FullDirectoryName->Length < sizeof(WCHAR) || ((CHAR*)FullDirectoryName->Buffer)[1] != 0)
897 {
898 NotifyChange->CharacterSize = sizeof(CHAR);
899 }
900 else
901 {
902 NotifyChange->CharacterSize = sizeof(WCHAR);
903 }
904
905 /* Now, check is user is willing to watch root */
906 if (FullDirectoryName->Length == NotifyChange->CharacterSize)
907 {
908 NotifyChange->Flags |= WATCH_ROOT;
909 }
910 }
911
912 NotifyChange->CompletionFilter = CompletionFilter;
913
914 /* In case we have not to ignore buffer , keep its length */
915 if (!IgnoreBuffer)
916 {
917 NotifyChange->BufferLength = Stack->Parameters.NotifyDirectory.Length;
918 }
919
920 NotifyChange->OwningProcess = NotifyIrp->Tail.Overlay.Thread->ThreadsProcess;
921
922 /* Insert the notification into the notification list */
923 InsertTailList(NotifyList, &(NotifyChange->NotifyList));
924
925 NotifyChange->ReferenceCount = 1;
926
927HandleIRP:
928 /* Associate the notification to the IRP */
929 NotifyIrp->IoStatus.Information = (ULONG_PTR)NotifyChange;
930 /* The IRP is pending */
932 /* Insert the IRP in the IRP list */
933 InsertTailList(&(NotifyChange->NotifyIrps), &(NotifyIrp->Tail.Overlay.ListEntry));
934 /* Increment reference count */
935 InterlockedIncrement((PLONG)&(NotifyChange->ReferenceCount));
936 /* Set cancel routine to FsRtl one */
938 }
940 {
941 /* Release fast mutex */
942 FsRtlNotifyReleaseFastMutex(RealNotifySync);
943
944 /* If the subject security context was captured and there's no notify */
945 if (SubjectContext && (!NotifyChange || NotifyChange->FullDirectoryName))
946 {
949 }
950 }
951 _SEH2_END;
952}
953
954/*++
955 * @name FsRtlNotifyFilterReportChange
956 * @implemented
957 *
958 * FILLME
959 *
960 * @param NotifySync
961 * FILLME
962 *
963 * @param NotifyList
964 * FILLME
965 *
966 * @param FullTargetName
967 * FILLME
968 *
969 * @param TargetNameOffset
970 * FILLME
971 *
972 * @param StreamName
973 * FILLME
974 *
975 * @param NormalizedParentName
976 * FILLME
977 *
978 * @param FilterMatch
979 * FILLME
980 *
981 * @param Action
982 * FILLME
983 *
984 * @param TargetContext
985 * FILLME
986 *
987 * @param FilterContext
988 * FILLME
989 *
990 * @return None
991 *
992 * @remarks None
993 *
994 *--*/
995VOID
996NTAPI
1004 IN ULONG Action,
1007{
1008 PIRP Irp;
1010 USHORT FullPosition;
1011 PLIST_ENTRY NextEntry;
1013 PNOTIFY_CHANGE NotifyChange;
1014 PREAL_NOTIFY_SYNC RealNotifySync;
1015 PFILE_NOTIFY_INFORMATION FileNotifyInfo;
1016 BOOLEAN IsStream, IsParent, PoolQuotaCharged;
1017 STRING TargetDirectory, TargetName, ParentName, IntNormalizedParentName;
1018 ULONG NumberOfBytes, TargetNumberOfParts, FullNumberOfParts, LastPartOffset, ParentNameOffset, ParentNameLength;
1019 ULONG DataLength, AlignedDataLength;
1020
1021 TargetDirectory.Length = 0;
1022 TargetDirectory.MaximumLength = 0;
1023 TargetDirectory.Buffer = NULL;
1024 TargetName.Length = 0;
1025 TargetName.MaximumLength = 0;
1026 TargetName.Buffer = NULL;
1027 ParentName.Length = 0;
1028 ParentName.MaximumLength = 0;
1029 ParentName.Buffer = NULL;
1030 IsStream = FALSE;
1031
1032 PAGED_CODE();
1033
1034 DPRINT("FsRtlNotifyFilterReportChange(%p, %p, %p, %u, %p, %p, %p, %x, %x, %p, %p)\n",
1037
1038 /* We need offset in name */
1040 {
1041 return;
1042 }
1043
1044 /* Get real structure hidden behind the opaque pointer */
1045 RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
1046 /* Acquire lock - will be released in finally block */
1047 FsRtlNotifyAcquireFastMutex(RealNotifySync);
1048 _SEH2_TRY
1049 {
1050 /* Browse all the registered notifications we have */
1051 for (NextEntry = NotifyList->Flink; NextEntry != NotifyList;
1052 NextEntry = NextEntry->Flink)
1053 {
1054 /* Try to find an entry matching our change */
1055 NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
1056 if (FullTargetName != NULL)
1057 {
1058 ASSERT(NotifyChange->FullDirectoryName != NULL);
1059 if (!NotifyChange->FullDirectoryName->Length)
1060 {
1061 continue;
1062 }
1063
1064 if (!(FilterMatch & NotifyChange->CompletionFilter))
1065 {
1066 continue;
1067 }
1068
1069 /* If no normalized name provided, construct it from full target name */
1071 {
1072 IntNormalizedParentName.Buffer = FullTargetName->Buffer;
1073 if (TargetNameOffset != NotifyChange->CharacterSize)
1074 {
1075 IntNormalizedParentName.MaximumLength =
1076 IntNormalizedParentName.Length = TargetNameOffset - NotifyChange->CharacterSize;
1077 }
1078 else
1079 {
1080 IntNormalizedParentName.MaximumLength =
1081 IntNormalizedParentName.Length = TargetNameOffset;
1082 }
1083 NormalizedParentName = &IntNormalizedParentName;
1084 }
1085
1086 /* heh? Watched directory bigger than changed file? */
1087 if (NormalizedParentName->Length < NotifyChange->FullDirectoryName->Length)
1088 {
1089 continue;
1090 }
1091
1092 /* Same len => parent */
1093 if (NormalizedParentName->Length == NotifyChange->FullDirectoryName->Length)
1094 {
1095 IsParent = TRUE;
1096 }
1097 /* If not, then, we have to be watching the tree, otherwise we don't have to report such changes */
1098 else if (!(NotifyChange->Flags & WATCH_TREE))
1099 {
1100 continue;
1101 }
1102 /* And finally, we've to check we're properly \-terminated */
1103 else
1104 {
1105 if (!(NotifyChange->Flags & WATCH_ROOT))
1106 {
1107 if (NotifyChange->CharacterSize == sizeof(CHAR))
1108 {
1109 if (((PSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length] != '\\')
1110 {
1111 continue;
1112 }
1113 }
1114 else
1115 {
1116 if (((PWSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length / sizeof (WCHAR)] != L'\\')
1117 {
1118 continue;
1119 }
1120 }
1121 }
1122
1123 IsParent = FALSE;
1124 }
1125
1126 /* If len matches, then check that both name are equal */
1127 if (!RtlEqualMemory(NormalizedParentName->Buffer, NotifyChange->FullDirectoryName->Buffer,
1128 NotifyChange->FullDirectoryName->Length))
1129 {
1130 continue;
1131 }
1132
1133 /* Call traverse callback (only if we have to traverse ;-)) */
1134 if (!IsParent
1135 && NotifyChange->TraverseCallback != NULL
1136 && !NotifyChange->TraverseCallback(NotifyChange->FsContext,
1138 NotifyChange->SubjectContext))
1139 {
1140 continue;
1141 }
1142
1143 /* And then, filter callback if provided */
1144 if (NotifyChange->FilterCallback != NULL
1145 && FilterContext != NULL
1146 && !NotifyChange->FilterCallback(NotifyChange->FsContext, FilterContext))
1147 {
1148 continue;
1149 }
1150 }
1151 /* We have a stream! */
1152 else
1153 {
1154 ASSERT(NotifyChange->FullDirectoryName == NULL);
1155 if (TargetContext != NotifyChange->SubjectContext)
1156 {
1157 continue;
1158 }
1159
1160 ParentName.Buffer = NULL;
1161 ParentName.Length = 0;
1162 IsStream = TRUE;
1163 IsParent = FALSE;
1164 }
1165
1166 /* If we don't have to notify immediately, prepare for output */
1167 if (!(NotifyChange->Flags & NOTIFY_IMMEDIATELY))
1168 {
1169 /* If we have something to output... */
1170 if (NotifyChange->BufferLength)
1171 {
1172 /* Get size of the output */
1173 NumberOfBytes = 0;
1174 Irp = NULL;
1175 if (!NotifyChange->ThisBufferLength)
1176 {
1177 if (IsListEmpty(&NotifyChange->NotifyIrps))
1178 {
1179 NumberOfBytes = NotifyChange->BufferLength;
1180 }
1181 else
1182 {
1183 Irp = CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, IRP, Tail.Overlay.ListEntry);
1185 NumberOfBytes = Stack->Parameters.NotifyDirectory.Length;
1186 }
1187 }
1188 else
1189 {
1190 NumberOfBytes = NotifyChange->ThisBufferLength;
1191 }
1192
1193 /* If we're matching parent, we don't care about parent (redundant) */
1194 if (IsParent)
1195 {
1196 ParentName.Length = 0;
1197 }
1198 else
1199 {
1200 /* If we don't deal with streams, some more work is required */
1201 if (!IsStream)
1202 {
1203 if (NotifyChange->Flags & WATCH_ROOT ||
1204 (NormalizedParentName->Buffer != FullTargetName->Buffer))
1205 {
1206 /* Construct TargetDirectory if we don't have it yet */
1207 if (TargetDirectory.Buffer == NULL)
1208 {
1209 TargetDirectory.Buffer = FullTargetName->Buffer;
1210 TargetDirectory.Length = TargetNameOffset;
1211 if (TargetNameOffset != NotifyChange->CharacterSize)
1212 {
1213 TargetDirectory.Length = TargetNameOffset - NotifyChange->CharacterSize;
1214 }
1215 TargetDirectory.MaximumLength = TargetDirectory.Length;
1216 }
1217 /* Now, we start looking for matching parts (unless we watch root) */
1218 TargetNumberOfParts = 0;
1219 if (!(NotifyChange->Flags & WATCH_ROOT))
1220 {
1221 FullNumberOfParts = 1;
1222 if (NotifyChange->CharacterSize == sizeof(CHAR))
1223 {
1225 TargetDirectory.Length, PSTR, '\\');
1226 }
1227 else
1228 {
1230 TargetDirectory.Length / sizeof(WCHAR), PWSTR, L'\\');
1231 LastPartOffset *= NotifyChange->CharacterSize;
1232 }
1233 }
1234
1235 /* Then, we can construct proper parent name */
1236 ParentNameOffset = NotifyChange->CharacterSize + LastPartOffset;
1237 ParentName.Buffer = &TargetDirectory.Buffer[ParentNameOffset];
1238 ParentNameLength = TargetDirectory.Length;
1239 }
1240 else
1241 {
1242 /* Construct parent name even for streams */
1243 ParentName.Buffer = &NormalizedParentName->Buffer[NotifyChange->FullDirectoryName->Length] + NotifyChange->CharacterSize;
1244 ParentNameLength = NormalizedParentName->Length - NotifyChange->FullDirectoryName->Length;
1245 ParentNameOffset = NotifyChange->CharacterSize;
1246 }
1247 ParentNameLength -= ParentNameOffset;
1248 ParentName.Length = ParentNameLength;
1249 ParentName.MaximumLength = ParentNameLength;
1250 }
1251 }
1252
1253 /* Start to count amount of data to write, we've first the structure itself */
1255
1256 /* If stream, we'll just append stream name */
1257 if (IsStream)
1258 {
1260 DataLength += StreamName->Length;
1261 }
1262 else
1263 {
1264 /* If not parent, we've to append parent name */
1265 if (!IsParent)
1266 {
1267 if (NotifyChange->CharacterSize == sizeof(CHAR))
1268 {
1270 }
1271 else
1272 {
1273 DataLength += ParentName.Length;
1274 }
1275 DataLength += sizeof(WCHAR);
1276 }
1277
1278 /* Look for target name & construct it, if required */
1279 if (TargetName.Buffer == NULL)
1280 {
1281 TargetName.Buffer = &FullTargetName->Buffer[TargetNameOffset];
1282 TargetName.Length =
1283 TargetName.MaximumLength = FullTargetName->Length - TargetNameOffset;
1284 }
1285
1286 /* Then, we will append it as well */
1287 if (NotifyChange->CharacterSize == sizeof(CHAR))
1288 {
1290 }
1291 else
1292 {
1293 DataLength += TargetName.Length;
1294 }
1295
1296 /* If we also had a stream name, then we can append it as well */
1297 if (StreamName != NULL)
1298 {
1299 if (NotifyChange->CharacterSize == sizeof(WCHAR))
1300 {
1301 DataLength += StreamName->Length + sizeof(WCHAR);
1302 }
1303 else
1304 {
1306 }
1307 }
1308 }
1309
1310 /* Get the position where we can put our data (aligned!) */
1311 AlignedDataLength = ROUND_UP(NotifyChange->DataLength, sizeof(ULONG));
1312 /* If it's higher than buffer length, then, bail out without outputing */
1313 if (DataLength > NumberOfBytes || AlignedDataLength + DataLength > NumberOfBytes)
1314 {
1315 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
1316 }
1317 else
1318 {
1320 FileNotifyInfo = NULL;
1321 /* If we already had a buffer, update last entry position */
1322 if (NotifyChange->Buffer != NULL)
1323 {
1324 FileNotifyInfo = (PVOID)((ULONG_PTR)NotifyChange->Buffer + NotifyChange->LastEntry);
1325 FileNotifyInfo->NextEntryOffset = AlignedDataLength - NotifyChange->LastEntry;
1326 NotifyChange->LastEntry = AlignedDataLength;
1327 /* And get our output buffer */
1328 OutputBuffer = (PVOID)((ULONG_PTR)NotifyChange->Buffer + AlignedDataLength);
1329 }
1330 /* If we hadn't buffer, try to find one */
1331 else if (Irp != NULL)
1332 {
1333 if (Irp->AssociatedIrp.SystemBuffer != NULL)
1334 {
1335 OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
1336 }
1337 else if (Irp->MdlAddress != NULL)
1338 {
1340 }
1341
1342 NotifyChange->Buffer = OutputBuffer;
1343 NotifyChange->ThisBufferLength = NumberOfBytes;
1344 }
1345
1346 /* If we couldn't find one, then allocate one */
1347 if (NotifyChange->Buffer == NULL)
1348 {
1349 /* Assign the length buffer */
1350 NotifyChange->ThisBufferLength = NumberOfBytes;
1351
1352 /* Assume we have not charged quotas */
1353 PoolQuotaCharged = FALSE;
1354 _SEH2_TRY
1355 {
1356 /* And charge quotas */
1357 PsChargePoolQuota(NotifyChange->OwningProcess, PagedPool, NotifyChange->ThisBufferLength);
1358 PoolQuotaCharged = TRUE;
1361 NotifyChange->Buffer = OutputBuffer;
1362 NotifyChange->AllocatedBuffer = OutputBuffer;
1363 }
1364 /* If something went wrong during allocation, notify immediately instead of outputing */
1366 {
1367 if (PoolQuotaCharged)
1368 {
1369 PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
1370 }
1371 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
1372 }
1373 _SEH2_END;
1374 }
1375
1376 /* Finally, if we have a buffer, fill it in! */
1377 if (OutputBuffer != NULL)
1378 {
1380 Action, &ParentName, &TargetName,
1381 StreamName, NotifyChange->CharacterSize == sizeof(WCHAR),
1382 DataLength))
1383 {
1384 NotifyChange->DataLength = DataLength + AlignedDataLength;
1385 }
1386 /* If it failed, notify immediately */
1387 else
1388 {
1389 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
1390 }
1391 }
1392 }
1393
1394 /* If we have to notify right now (something went wrong?) */
1395 if (NotifyChange->Flags & NOTIFY_IMMEDIATELY)
1396 {
1397 /* Ensure that all our buffers are NULL */
1398 if (NotifyChange->Buffer != NULL)
1399 {
1400 if (NotifyChange->AllocatedBuffer != NULL)
1401 {
1402 PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
1404 }
1405
1406 NotifyChange->Buffer = NULL;
1407 NotifyChange->AllocatedBuffer = NULL;
1408 NotifyChange->LastEntry = 0;
1409 NotifyChange->DataLength = 0;
1410 NotifyChange->ThisBufferLength = 0;
1411 }
1412 }
1413 }
1414 }
1415
1416 /* If asking for old name in case of a rename, notify later on,
1417 * so that we can wait for new name.
1418 * http://msdn.microsoft.com/en-us/library/dn392331.aspx
1419 */
1421 {
1422 NotifyChange->Flags |= NOTIFY_LATER;
1423 }
1424 else
1425 {
1426 NotifyChange->Flags &= ~NOTIFY_LATER;
1427 if (!IsListEmpty(&NotifyChange->NotifyIrps))
1428 {
1430 }
1431 }
1432 }
1433 }
1435 {
1436 FsRtlNotifyReleaseFastMutex(RealNotifySync);
1437 }
1438 _SEH2_END;
1439}
1440
1441/*++
1442 * @name FsRtlNotifyFullChangeDirectory
1443 * @implemented
1444 *
1445 * Lets FSD know if changes occures in the specified directory.
1446 *
1447 * @param NotifySync
1448 * Synchronization object pointer
1449 *
1450 * @param NotifyList
1451 * Notify list pointer (to head)
1452 *
1453 * @param FsContext
1454 * Used to identify the notify structure
1455 *
1456 * @param FullDirectoryName
1457 * String (A or W) containing the full directory name
1458 *
1459 * @param WatchTree
1460 * True to notify changes in subdirectories too
1461 *
1462 * @param IgnoreBuffer
1463 * True to reenumerate directory. It's ignored it NotifyIrp is null
1464 *
1465 * @param CompletionFilter
1466 * Used to define types of changes to notify
1467 *
1468 * @param NotifyIrp
1469 * IRP pointer to complete notify operation. It can be null
1470 *
1471 * @param TraverseCallback
1472 * Pointer to a callback function. It's called each time a change is
1473 * done in a subdirectory of the main directory. It's ignored it NotifyIrp
1474 * is null
1475 *
1476 * @param SubjectContext
1477 * Pointer to pass to SubjectContext member of TraverseCallback.
1478 * It's freed after use. It's ignored it NotifyIrp is null
1479 *
1480 * @return None
1481 *
1482 * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
1483 *
1484 *--*/
1485VOID
1486NTAPI
1497{
1499 NotifyList,
1500 FsContext,
1502 WatchTree,
1505 NotifyIrp,
1508 NULL);
1509}
1510
1511/*++
1512 * @name FsRtlNotifyFullReportChange
1513 * @implemented
1514 *
1515 * Complets the pending notify IRPs.
1516 *
1517 * @param NotifySync
1518 * Synchronization object pointer
1519 *
1520 * @param NotifyList
1521 * Notify list pointer (to head)
1522 *
1523 * @param FullTargetName
1524 * String (A or W) containing the full directory name that changed
1525 *
1526 * @param TargetNameOffset
1527 * Offset, in FullTargetName, of the final component that is in the changed directory
1528 *
1529 * @param StreamName
1530 * String (A or W) containing a stream name
1531 *
1532 * @param NormalizedParentName
1533 * String (A or W) containing the full directory name that changed with long names
1534 *
1535 * @param FilterMatch
1536 * Flags that will be compared to the completion filter
1537 *
1538 * @param Action
1539 * Action code to store in user's buffer
1540 *
1541 * @param TargetContext
1542 * Pointer to a callback function. It's called each time a change is
1543 * done in a subdirectory of the main directory.
1544 *
1545 * @return None
1546 *
1547 * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
1548 *
1549 *--*/
1550VOID
1551NTAPI
1559 IN ULONG Action,
1561{
1563 NotifyList,
1566 StreamName,
1569 Action,
1571 NULL);
1572}
1573
1574/*++
1575 * @name FsRtlNotifyInitializeSync
1576 * @implemented
1577 *
1578 * Allocates the internal structure associated with notifications.
1579 *
1580 * @param NotifySync
1581 * Opaque pointer. It will receive the address of the allocated internal structure.
1582 *
1583 * @return None
1584 *
1585 * @remarks This function raise an exception in case of a failure.
1586 *
1587 *--*/
1588VOID
1589NTAPI
1591{
1592 PREAL_NOTIFY_SYNC RealNotifySync;
1593
1594 *NotifySync = NULL;
1595
1597 sizeof(REAL_NOTIFY_SYNC), 'SNSF');
1598 ExInitializeFastMutex(&(RealNotifySync->FastMutex));
1599 RealNotifySync->OwningThread = 0;
1600 RealNotifySync->OwnerCount = 0;
1601
1602 *NotifySync = RealNotifySync;
1603}
1604
1605/*++
1606 * @name FsRtlNotifyReportChange
1607 * @implemented
1608 *
1609 * Complets the pending notify IRPs.
1610 *
1611 * @param NotifySync
1612 * Synchronization object pointer
1613 *
1614 * @param NotifyList
1615 * Notify list pointer (to head)
1616 *
1617 * @param FullTargetName
1618 * String (A or W) containing the full directory name that changed
1619 *
1620 * @param FileNamePartLength
1621 * Length of the final component that is in the changed directory
1622 *
1623 * @param FilterMatch
1624 * Flags that will be compared to the completion filter
1625 *
1626 * @return None
1627 *
1628 * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
1629 *
1630 *--*/
1631VOID
1632NTAPI
1636 IN PUSHORT FileNamePartLength,
1638{
1640 NotifyList,
1642 FullTargetName->Length - *FileNamePartLength,
1643 NULL,
1644 NULL,
1646 0,
1647 NULL,
1648 NULL);
1649}
1650
1651/*++
1652 * @name FsRtlNotifyUninitializeSync
1653 * @implemented
1654 *
1655 * Uninitialize a NOTIFY_SYNC object
1656 *
1657 * @param NotifySync
1658 * Address of a pointer to a PNOTIFY_SYNC object previously
1659 * initialized by FsRtlNotifyInitializeSync()
1660 *
1661 * @return None
1662 *
1663 * @remarks None
1664 *
1665 *--*/
1666VOID
1667NTAPI
1669{
1670 if (*NotifySync)
1671 {
1672 ExFreePoolWithTag(*NotifySync, 'SNSF');
1673 *NotifySync = NULL;
1674 }
1675}
1676
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
#define PAGED_CODE()
unsigned char BOOLEAN
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
#define CHAR(Char)
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1444
Definition: bufpool.h:45
_In_ PIRP Irp
Definition: csq.h:116
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ULONG_PTR
Definition: config.h:101
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define NonPagedPool
Definition: env_spec_w32.h:307
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define PagedPool
Definition: env_spec_w32.h:308
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
#define _SEH2_FINALLY
Definition: filesup.c:21
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define _SEH2_LEAVE
Definition: filesup.c:20
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_ PFLT_CALLBACK_DATA _In_opt_ PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback
Definition: fltkernel.h:2245
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_ PFLT_CALLBACK_DATA _In_opt_ PCHECK_FOR_TRAVERSE_ACCESS _In_opt_ PSECURITY_SUBJECT_CONTEXT _In_opt_ PFILTER_REPORT_CHANGE FilterCallback
Definition: fltkernel.h:2247
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING FullDirectoryName
Definition: fltkernel.h:2240
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG CompletionFilter
Definition: fltkernel.h:2243
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN WatchTree
Definition: fltkernel.h:2241
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN IgnoreBuffer
Definition: fltkernel.h:2242
_Inout_ PLIST_ENTRY NotifyList
Definition: fltkernel.h:2238
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_ PFLT_CALLBACK_DATA _In_opt_ PCHECK_FOR_TRAVERSE_ACCESS _In_opt_ PSECURITY_SUBJECT_CONTEXT SubjectContext
Definition: fltkernel.h:2246
_Inout_ PLIST_ENTRY _In_ PVOID FsContext
Definition: fltkernel.h:2239
std::wstring STRING
Definition: fontsub.cpp:33
#define WATCH_TREE
Definition: fsrtl.h:55
#define DELETE_IN_PROCESS
Definition: fsrtl.h:60
#define WATCH_ROOT
Definition: fsrtl.h:59
#define NOTIFY_LATER
Definition: fsrtl.h:58
#define CLEANUP_IN_PROCESS
Definition: fsrtl.h:57
#define NOTIFY_IMMEDIATELY
Definition: fsrtl.h:56
struct _REAL_NOTIFY_SYNC * PREAL_NOTIFY_SYNC
struct _NOTIFY_CHANGE * PNOTIFY_CHANGE
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING _In_ ULONG _In_ ULONG _In_opt_ PVOID TargetContext
Definition: fsrtlfuncs.h:745
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT TargetNameOffset
Definition: fsrtlfuncs.h:740
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING NormalizedParentName
Definition: fsrtlfuncs.h:742
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING _In_ ULONG _In_ ULONG _In_opt_ PVOID _In_opt_ PVOID FilterContext
Definition: fsrtlfuncs.h:746
_In_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_opt_ PIRP NotifyIrp
Definition: fsrtlfuncs.h:728
_In_ PLIST_ENTRY _In_ PSTRING FullTargetName
Definition: fsrtlfuncs.h:739
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING StreamName
Definition: fsrtlfuncs.h:741
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING _In_ ULONG FilterMatch
Definition: fsrtlfuncs.h:743
BOOLEAN(NTAPI * PCHECK_FOR_TRAVERSE_ACCESS)(_In_ PVOID NotifyContext, _In_opt_ PVOID TargetContext, _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
Definition: fsrtltypes.h:291
BOOLEAN(NTAPI * PFILTER_REPORT_CHANGE)(_In_ PVOID NotifyContext, _In_ PVOID FilterContext)
Definition: fsrtltypes.h:297
Status
Definition: gdiplustypes.h:25
#define KeGetCurrentThread
Definition: hal.h:55
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
IoMarkIrpPending(Irp)
IoSetCancelRoutine(Irp, CancelRoutine)
#define RtlEqualMemory(a, b, c)
Definition: kdvm.h:18
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
_Use_decl_annotations_ NTSTATUS NTAPI RtlOemToUnicodeN(_Out_ PWCHAR UnicodeString, _In_ ULONG UnicodeSize, _Out_opt_ PULONG ResultSize, _In_ PCCH OemString, _In_ ULONG OemSize)
Definition: nlsboot.c:282
VOID FASTCALL ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:86
VOID FASTCALL ExAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:75
VOID NTAPI FsRtlCancelNotify(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: notify.c:79
VOID NTAPI FsRtlNotifyFullReportChange(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PSTRING FullTargetName, IN USHORT TargetNameOffset, IN PSTRING StreamName OPTIONAL, IN PSTRING NormalizedParentName OPTIONAL, IN ULONG FilterMatch, IN ULONG Action, IN PVOID TargetContext)
Definition: notify.c:1552
VOID NTAPI FsRtlNotifyUninitializeSync(IN PNOTIFY_SYNC *NotifySync)
Definition: notify.c:1668
BOOLEAN FsRtlNotifySetCancelRoutine(IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange OPTIONAL)
Definition: notify.c:448
VOID NTAPI FsRtlNotifyCleanup(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:659
VOID FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange, IN NTSTATUS Status)
Definition: notify.c:418
VOID FsRtlNotifyCompleteIrp(IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange, IN ULONG DataLength, IN NTSTATUS Status, IN BOOLEAN SkipCompletion)
Definition: notify.c:314
VOID NTAPI FsRtlNotifyChangeDirectory(IN PNOTIFY_SYNC NotifySync, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN PLIST_ENTRY NotifyList, IN BOOLEAN WatchTree, IN ULONG CompletionFilter, IN PIRP NotifyIrp)
Definition: notify.c:616
FORCEINLINE VOID FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
Definition: notify.c:41
VOID FsRtlCheckNotifyForDelete(IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:259
VOID NTAPI FsRtlNotifyFilterChangeDirectory(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN BOOLEAN WatchTree, IN BOOLEAN IgnoreBuffer, IN ULONG CompletionFilter, IN PIRP NotifyIrp, IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL, IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL)
Definition: notify.c:773
PNOTIFY_CHANGE FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:286
BOOLEAN FsRtlNotifyUpdateBuffer(OUT PFILE_NOTIFY_INFORMATION OutputBuffer, IN ULONG Action, IN PSTRING ParentName, IN PSTRING TargetName, IN PSTRING StreamName, IN BOOLEAN IsUnicode, IN ULONG DataLength)
Definition: notify.c:497
FORCEINLINE VOID FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
Definition: notify.c:22
VOID NTAPI FsRtlNotifyInitializeSync(IN PNOTIFY_SYNC *NotifySync)
Definition: notify.c:1590
VOID NTAPI FsRtlNotifyReportChange(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PSTRING FullTargetName, IN PUSHORT FileNamePartLength, IN ULONG FilterMatch)
Definition: notify.c:1633
#define FsRtlNotifyGetLastPartOffset(FullLen, TargLen, Type, Chr)
Definition: notify.c:52
VOID NTAPI FsRtlNotifyFilterReportChange(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PSTRING FullTargetName, IN USHORT TargetNameOffset, IN PSTRING StreamName OPTIONAL, IN PSTRING NormalizedParentName OPTIONAL, IN ULONG FilterMatch, IN ULONG Action, IN PVOID TargetContext, IN PVOID FilterContext)
Definition: notify.c:997
VOID NTAPI FsRtlNotifyFullChangeDirectory(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN BOOLEAN WatchTree, IN BOOLEAN IgnoreBuffer, IN ULONG CompletionFilter, IN PIRP NotifyIrp, IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL)
Definition: notify.c:1487
#define IoCompleteRequest
Definition: irp.c:1240
VOID NTAPI IoReleaseCancelSpinLock(IN KIRQL Irql)
Definition: util.c:150
VOID NTAPI IoAcquireCancelSpinLock(OUT PKIRQL Irql)
Definition: util.c:56
#define STATUS_DELETE_PENDING
Definition: ntstatus.h:322
#define STATUS_NOTIFY_CLEANUP
Definition: ntstatus.h:90
#define STATUS_NOTIFY_ENUM_DIR
Definition: ntstatus.h:91
#define L(x)
Definition: ntvdm.h:50
unsigned short USHORT
Definition: pedump.c:61
static PCWSTR TargetName
Definition: ping.c:67
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_VOLATILE
Definition: pseh2_64.h:163
VOID NTAPI PsReturnProcessPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Returns the paged pool quota that the process was taking up.
Definition: quota.c:965
VOID NTAPI PsChargePoolQuota(_In_ PEPROCESS Process, _In_ POOL_TYPE PoolType, _In_ SIZE_T Amount)
Charges the pool quota of a given process. The kind of pool quota to charge is determined by the Pool...
Definition: quota.c:775
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
PSTRING FullDirectoryName
Definition: fsrtl.h:82
ULONG BufferLength
Definition: fsrtl.h:91
PVOID Buffer
Definition: fsrtl.h:90
PVOID FsContext
Definition: fsrtl.h:78
PVOID AllocatedBuffer
Definition: fsrtl.h:89
USHORT Flags
Definition: fsrtl.h:86
LIST_ENTRY NotifyIrps
Definition: fsrtl.h:84
ULONG CompletionFilter
Definition: fsrtl.h:88
PSECURITY_SUBJECT_CONTEXT SubjectContext
Definition: fsrtl.h:81
PEPROCESS OwningProcess
Definition: fsrtl.h:96
ULONG DataLength
Definition: fsrtl.h:93
ULONG LastEntry
Definition: fsrtl.h:94
ULONG ReferenceCount
Definition: fsrtl.h:95
PREAL_NOTIFY_SYNC NotifySync
Definition: fsrtl.h:77
PVOID StreamID
Definition: fsrtl.h:79
UCHAR CharacterSize
Definition: fsrtl.h:87
LIST_ENTRY NotifyList
Definition: fsrtl.h:83
ULONG ThisBufferLength
Definition: fsrtl.h:92
PFILTER_REPORT_CHANGE FilterCallback
Definition: fsrtl.h:85
PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback
Definition: fsrtl.h:80
ULONG_PTR OwningThread
Definition: fsrtl.h:68
ULONG OwnerCount
Definition: fsrtl.h:69
FAST_MUTEX FastMutex
Definition: fsrtl.h:67
unsigned short Length
Definition: sprintf.c:451
void * Buffer
Definition: sprintf.c:453
VOID NTAPI SeReleaseSubjectContext(_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
Releases both the primary and client tokens of a security subject context.
Definition: subject.c:171
#define TAG_FS_NOTIFICATIONS
Definition: tag.h:68
uint16_t * PWSTR
Definition: typedefs.h:56
char * PSTR
Definition: typedefs.h:51
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
uint16_t * PUSHORT
Definition: typedefs.h:56
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
int32_t * PLONG
Definition: typedefs.h:58
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3771
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR OutputBuffer
Definition: wdfiotarget.h:863
_In_ WDFIOTARGET _In_ _Strict_type_match_ WDF_IO_TARGET_SENT_IO_ACTION Action
Definition: wdfiotarget.h:510
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
#define FORCEINLINE
Definition: wdftypes.h:67
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
_In_opt_ PDRIVER_CANCEL CancelRoutine
Definition: iofuncs.h:2744
#define SL_PENDING_RETURNED
Definition: iotypes.h:3325
#define IRP_DEALLOCATE_BUFFER
#define FILE_ACTION_RENAMED_OLD_NAME
DRIVER_CANCEL * PDRIVER_CANCEL
Definition: iotypes.h:2759
#define FO_CLEANUP_COMPLETE
Definition: iotypes.h:1790
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
#define IRP_BUFFERED_IO
#define IRP_SYNCHRONOUS_PAGING_IO
#define POOL_RAISE_IF_ALLOCATION_FAILURE
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _Inout_ PLARGE_INTEGER NumberOfBytes
Definition: iotypes.h:1036
#define MmGetSystemAddressForMdl(Mdl)
#define RtlOemStringToCountedUnicodeSize(STRING)
__wchar_t WCHAR
Definition: xmlstorage.h:180
char CHAR
Definition: xmlstorage.h:175