ReactOS  0.4.15-dev-4610-g11e0ed3
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  */
21 VOID
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  */
40 VOID
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 
66 VOID
69 
70 BOOLEAN
72  IN PNOTIFY_CHANGE NotifyChange OPTIONAL);
73 
74 /*
75  * @implemented
76  */
77 VOID
78 NTAPI
80  IN PIRP Irp)
81 {
82  PVOID Buffer;
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 
103  _SEH2_TRY
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 
172  _SEH2_TRY
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  {
226  PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
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  */
258 VOID
261 {
262  PLIST_ENTRY NextEntry;
263  PNOTIFY_CHANGE NotifyChange;
264 
265  if (!IsListEmpty(NotifyList))
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 
292  if (!IsListEmpty(NotifyList))
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  */
313 VOID
315  IN PNOTIFY_CHANGE NotifyChange,
318  IN BOOLEAN SkipCompletion)
319 {
320  PVOID Buffer;
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 
380 CopyAndComplete:
381  _SEH2_TRY
382  {
383  RtlCopyMemory(Buffer, NotifyChange->AllocatedBuffer, DataLength);
384  }
386  {
387  /* Do nothing */
388  }
389  _SEH2_END;
390 
391 ReleaseAndComplete:
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 */
408 Completion:
410  Irp->IoStatus.Status = Status;
412 }
413 
414 /*
415  * @implemented
416  */
417 VOID
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 */
437  FsRtlNotifyCompleteIrp(Irp, NotifyChange, DataLength, Status, TRUE);
438  /* If we're notifying success, just notify first one */
439  if (Status == STATUS_SUCCESS)
440  break;
441  }
442 }
443 
444 /*
445  * @implemented
446  */
447 BOOLEAN
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  */
496 BOOLEAN
498  IN ULONG Action,
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  */
517  _SEH2_TRY
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  *--*/
614 VOID
615 NTAPI
622  IN PIRP NotifyIrp)
623 {
625  NotifyList,
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  *--*/
657 VOID
658 NTAPI
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 
673  _SEH2_TRY
674  {
675  /* Find if there's a matching notification with the FsContext */
676  NotifyChange = FsRtlIsNotifyOnList(NotifyList, 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  {
697  PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
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  *--*/
771 VOID
772 NTAPI
780  IN PIRP NotifyIrp,
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 
802  _SEH2_TRY
803  {
804  /* If we have no IRP, FSD is performing a cleanup */
805  if (!NotifyIrp)
806  {
807  /* So, we delete */
809  _SEH2_LEAVE;
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;
822  _SEH2_LEAVE;
823  }
824 
825  /* Try to find a matching notification has been already registered */
826  NotifyChange = FsRtlIsNotifyOnList(NotifyList, FsContext);
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 
864  _SEH2_LEAVE;
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 
927 HandleIRP:
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  *--*/
995 VOID
996 NTAPI
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 */
1070  if (NormalizedParentName == NULL)
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,
1137  TargetContext,
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  {
1259  ASSERT(StreamName != NULL);
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  {
1319  OutputBuffer = NULL;
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  {
1339  OutputBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
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  *--*/
1485 VOID
1486 NTAPI
1489  IN PVOID FsContext,
1494  IN PIRP NotifyIrp,
1497 {
1499  NotifyList,
1500  FsContext,
1502  WatchTree,
1503  IgnoreBuffer,
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  *--*/
1550 VOID
1551 NTAPI
1559  IN ULONG Action,
1561 {
1562  FsRtlNotifyFilterReportChange(NotifySync,
1563  NotifyList,
1566  StreamName,
1568  FilterMatch,
1569  Action,
1570  TargetContext,
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  *--*/
1588 VOID
1589 NTAPI
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  *--*/
1631 VOID
1632 NTAPI
1636  IN PUSHORT FileNamePartLength,
1638 {
1639  FsRtlNotifyFilterReportChange(NotifySync,
1640  NotifyList,
1642  FullTargetName->Length - *FileNamePartLength,
1643  NULL,
1644  NULL,
1645  FilterMatch,
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  *--*/
1666 VOID
1667 NTAPI
1669 {
1670  if (*NotifySync)
1671  {
1672  ExFreePoolWithTag(*NotifySync, 'SNSF');
1673  *NotifySync = NULL;
1674  }
1675 }
1676 
_Inout_ PLIST_ENTRY _In_ PVOID FsContext
Definition: fltkernel.h:2238
#define IN
Definition: typedefs.h:39
#define STATUS_DELETE_PENDING
Definition: ntstatus.h:322
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3767
_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:2238
DRIVER_CANCEL * PDRIVER_CANCEL
Definition: iotypes.h:2759
PVOID FsContext
Definition: fsrtl.h:78
#define WATCH_ROOT
Definition: fsrtl.h:59
#define ROUND_UP(n, align)
Definition: eventvwr.h:31
#define SL_PENDING_RETURNED
Definition: iotypes.h:3325
#define FILE_ACTION_RENAMED_OLD_NAME
_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:738
FORCEINLINE VOID FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
Definition: notify.c:22
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
ULONG ThisBufferLength
Definition: fsrtl.h:92
PSTRING FullDirectoryName
Definition: fsrtl.h:82
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
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
#define TRUE
Definition: types.h:120
uint16_t * PWSTR
Definition: typedefs.h:56
PVOID StreamID
Definition: fsrtl.h:79
char CHAR
Definition: xmlstorage.h:175
PVOID Buffer
Definition: fsrtl.h:90
VOID NTAPI FsRtlNotifyReportChange(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PSTRING FullTargetName, IN PUSHORT FileNamePartLength, IN ULONG FilterMatch)
Definition: notify.c:1633
LONG NTSTATUS
Definition: precomp.h:26
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 IoAcquireCancelSpinLock(OUT PKIRQL Irql)
Definition: util.c:56
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING NormalizedParentName
Definition: fsrtlfuncs.h:738
PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback
Definition: fsrtl.h:80
_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
unsigned short Length
Definition: sprintf.c:451
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN WatchTree
Definition: fltkernel.h:2238
ULONG ReferenceCount
Definition: fsrtl.h:95
PVOID AllocatedBuffer
Definition: fsrtl.h:89
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
BOOLEAN(NTAPI * PFILTER_REPORT_CHANGE)(_In_ PVOID NotifyContext, _In_ PVOID FilterContext)
Definition: fsrtltypes.h:297
#define InsertTailList(ListHead, Entry)
IoSetCancelRoutine(Irp, CancelRoutine)
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
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
_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:2238
VOID FASTCALL ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:86
ULONG DataLength
Definition: fsrtl.h:93
_SEH2_TRY
Definition: create.c:4226
_In_ PLIST_ENTRY _In_ PSTRING FullTargetName
Definition: fsrtlfuncs.h:738
uint32_t ULONG_PTR
Definition: typedefs.h:65
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
VOID NTAPI FsRtlNotifyCleanup(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:659
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:636
_In_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_opt_ PIRP NotifyIrp
Definition: fsrtlfuncs.h:722
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
struct _REAL_NOTIFY_SYNC * PREAL_NOTIFY_SYNC
void * Buffer
Definition: sprintf.c:453
#define L(x)
Definition: ntvdm.h:50
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
_In_ PIRP Irp
Definition: csq.h:116
BOOLEAN(NTAPI * PCHECK_FOR_TRAVERSE_ACCESS)(_In_ PVOID NotifyContext, _In_opt_ PVOID TargetContext, _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
Definition: fsrtltypes.h:291
VOID FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange, IN NTSTATUS Status)
Definition: notify.c:418
PSECURITY_SUBJECT_CONTEXT SubjectContext
Definition: fsrtl.h:81
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN IgnoreBuffer
Definition: fltkernel.h:2238
_In_opt_ PDRIVER_CANCEL CancelRoutine
Definition: iofuncs.h:2744
PNOTIFY_CHANGE FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:286
unsigned char BOOLEAN
LIST_ENTRY NotifyIrps
Definition: fsrtl.h:84
#define IoCompleteRequest
Definition: irp.c:1240
#define CLEANUP_IN_PROCESS
Definition: fsrtl.h:57
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1437
Definition: bufpool.h:45
void * PVOID
Definition: retypes.h:9
#define STATUS_NOTIFY_ENUM_DIR
Definition: ntstatus.h:91
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
FORCEINLINE VOID FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
Definition: notify.c:41
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR OutputBuffer
Definition: wdfiotarget.h:859
#define TAG_FS_NOTIFICATIONS
Definition: tag.h:65
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING StreamName
Definition: fsrtlfuncs.h:738
Status
Definition: gdiplustypes.h:24
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define WATCH_TREE
Definition: fsrtl.h:55
#define DELETE_IN_PROCESS
Definition: fsrtl.h:60
#define ASSERT(a)
Definition: mode.c:44
NTSYSAPI ULONG NTAPI RtlEqualMemory(CONST VOID *Source1, CONST VOID *Source2, ULONG Length)
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING _In_ ULONG FilterMatch
Definition: fsrtlfuncs.h:738
__wchar_t WCHAR
Definition: xmlstorage.h:180
PFILTER_REPORT_CHANGE FilterCallback
Definition: fsrtl.h:85
VOID FASTCALL ExAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:75
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define NOTIFY_LATER
Definition: fsrtl.h:58
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
#define STATUS_NOTIFY_CLEANUP
Definition: ntstatus.h:90
VOID FsRtlCheckNotifyForDelete(IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:259
PEPROCESS OwningProcess
Definition: fsrtl.h:96
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
ULONG BufferLength
Definition: fsrtl.h:91
VOID NTAPI FsRtlCancelNotify(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: notify.c:79
std::wstring STRING
Definition: fontsub.cpp:33
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define InterlockedDecrement
Definition: armddk.h:52
USHORT Flags
Definition: fsrtl.h:86
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
PREAL_NOTIFY_SYNC NotifySync
Definition: fsrtl.h:77
WCHAR TargetName[256]
Definition: arping.c:27
Definition: typedefs.h:119
VOID FsRtlNotifyCompleteIrp(IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange, IN ULONG DataLength, IN NTSTATUS Status, IN BOOLEAN SkipCompletion)
Definition: notify.c:314
VOID NTAPI IoReleaseCancelSpinLock(IN KIRQL Irql)
Definition: util.c:150
#define FsRtlNotifyGetLastPartOffset(FullLen, TargLen, Type, Chr)
Definition: notify.c:52
#define _SEH2_VOLATILE
Definition: pseh2_64.h:169
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING _In_ ULONG _In_ ULONG _In_opt_ PVOID TargetContext
Definition: fsrtlfuncs.h:738
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2793
_SEH2_END
Definition: create.c:4400
struct _NOTIFY_CHANGE * PNOTIFY_CHANGE
LIST_ENTRY NotifyList
Definition: fsrtl.h:83
#define IRP_BUFFERED_IO
#define InterlockedIncrement
Definition: armddk.h:53
unsigned short USHORT
Definition: pedump.c:61
_In_ WDFIOTARGET _In_ _Strict_type_match_ WDF_IO_TARGET_SENT_IO_ACTION Action
Definition: wdfiotarget.h:506
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT TargetNameOffset
Definition: fsrtlfuncs.h:738
#define FO_CLEANUP_COMPLETE
Definition: iotypes.h:1790
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
_Inout_ PLIST_ENTRY NotifyList
Definition: fltkernel.h:2238
signed char * PSTR
Definition: retypes.h:7
#define FORCEINLINE
Definition: wdftypes.h:67
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
_SEH2_FINALLY
Definition: create.c:4371
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _Inout_ PLARGE_INTEGER NumberOfBytes
Definition: iotypes.h:1035
#define NULL
Definition: types.h:112
BOOLEAN FsRtlNotifySetCancelRoutine(IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange OPTIONAL)
Definition: notify.c:448
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG CompletionFilter
Definition: fltkernel.h:2238
VOID NTAPI SeReleaseSubjectContext(_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
Releases both the primary and client tokens of a security subject context.
Definition: access.c:523
UCHAR CharacterSize
Definition: fsrtl.h:87
#define NOTIFY_IMMEDIATELY
Definition: fsrtl.h:56
_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:2238
#define IRP_DEALLOCATE_BUFFER
VOID NTAPI FsRtlNotifyInitializeSync(IN PNOTIFY_SYNC *NotifySync)
Definition: notify.c:1590
#define OUT
Definition: typedefs.h:40
unsigned int ULONG
Definition: retypes.h:1
#define MmGetSystemAddressForMdl(Mdl)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define ULONG_PTR
Definition: config.h:101
ULONG_PTR OwningThread
Definition: fsrtl.h:68
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
VOID NTAPI FsRtlNotifyUninitializeSync(IN PNOTIFY_SYNC *NotifySync)
Definition: notify.c:1668
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
#define POOL_RAISE_IF_ALLOCATION_FAILURE
#define STATUS_SUCCESS
Definition: shellext.h:65
#define _SEH2_LEAVE
Definition: filesup.c:20
#define DPRINT
Definition: sndvol32.h:71
#define KeGetCurrentThread
Definition: hal.h:55
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
ULONG CompletionFilter
Definition: fsrtl.h:88
IoMarkIrpPending(Irp)
ULONG OwnerCount
Definition: fsrtl.h:69
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
signed int * PLONG
Definition: retypes.h:5
#define CHAR(Char)
FAST_MUTEX FastMutex
Definition: fsrtl.h:67
unsigned short * PUSHORT
Definition: retypes.h:2
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING FullDirectoryName
Definition: fltkernel.h:2238
#define RtlOemStringToCountedUnicodeSize(STRING)
#define IRP_SYNCHRONOUS_PAGING_IO
#define PAGED_CODE()
ULONG LastEntry
Definition: fsrtl.h:94
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
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