ReactOS  0.4.14-dev-114-gc8cbd56
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;
85  PIO_STACK_LOCATION Stack;
86  PNOTIFY_CHANGE NotifyChange;
87  PREAL_NOTIFY_SYNC RealNotifySync;
89 
90  /* Get the NOTIFY_CHANGE struct and reset it */
91  NotifyChange = (PNOTIFY_CHANGE)Irp->IoStatus.Information;
92  Irp->IoStatus.Information = 0;
93  /* Reset the cancel routine */
95  /* And release lock */
96  IoReleaseCancelSpinLock(Irp->CancelIrql);
97  /* Get REAL_NOTIFY_SYNC struct */
98  RealNotifySync = NotifyChange->NotifySync;
99 
100  FsRtlNotifyAcquireFastMutex(RealNotifySync);
101 
102  _SEH2_TRY
103  {
104  /* Remove the IRP from the notifications list and mark it pending */
105  RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
107 
108  /* Now, the tricky part - let's find a buffer big enough to hold the return data */
109  if (NotifyChange->Buffer && NotifyChange->AllocatedBuffer == NULL &&
110  ((Irp->MdlAddress && MmGetSystemAddressForMdl(Irp->MdlAddress) == NotifyChange->Buffer) ||
111  NotifyChange->Buffer == Irp->AssociatedIrp.SystemBuffer))
112  {
113  /* Assume we didn't find any */
114  Buffer = NULL;
115  BufferLength = 0;
116 
117  /* If we don't have IRPs, check if current buffer is big enough */
118  if (IsListEmpty(&NotifyChange->NotifyIrps))
119  {
120  if (NotifyChange->BufferLength >= NotifyChange->DataLength)
121  {
122  BufferLength = NotifyChange->BufferLength;
123  }
124  }
125  else
126  {
127  /* Otherwise, try to look at next IRP available */
128  NotifyIrp = CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, IRP, Tail.Overlay.ListEntry);
130 
131  /* If its buffer is big enough, get it */
132  if (Stack->Parameters.NotifyDirectory.Length >= NotifyChange->BufferLength)
133  {
134  /* Is it MDL? */
135  if (NotifyIrp->AssociatedIrp.SystemBuffer == NULL)
136  {
137  if (NotifyIrp->MdlAddress != NULL)
138  {
140  }
141  }
142  else
143  {
144  Buffer = NotifyIrp->AssociatedIrp.MasterIrp;
145  }
146 
147  /* Backup our accepted buffer length */
148  BufferLength = Stack->Parameters.NotifyDirectory.Length;
149  if (BufferLength > NotifyChange->BufferLength)
150  {
151  BufferLength = NotifyChange->BufferLength;
152  }
153  }
154  }
155 
156  /* At that point, we *may* have a buffer */
157 
158  /* If it has null length, then note that we won't use it */
159  if (BufferLength == 0)
160  {
161  NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
162  }
163  else
164  {
165  /* If we have a buffer length, but no buffer then allocate one */
166  if (Buffer == NULL)
167  {
170  NotifyChange->AllocatedBuffer = Buffer;
171  }
172 
173  /* Copy data in that buffer */
174  RtlCopyMemory(Buffer, NotifyChange->Buffer, NotifyChange->DataLength);
175  NotifyChange->ThisBufferLength = BufferLength;
176  NotifyChange->Buffer = Buffer;
177  }
178 
179  /* If we have to notify immediately, ensure that any buffer is 0-ed out */
180  if (NotifyChange->Flags & NOTIFY_IMMEDIATELY)
181  {
182  NotifyChange->Buffer = 0;
183  NotifyChange->AllocatedBuffer = 0;
184  NotifyChange->LastEntry = 0;
185  NotifyChange->DataLength = 0;
186  NotifyChange->ThisBufferLength = 0;
187  }
188  }
189 
190  /* It's now time to complete - data are ready */
191 
192  /* Set appropriate status and complete */
193  Irp->IoStatus.Status = STATUS_CANCELLED;
195 
196  /* If that notification isn't referenced any longer, drop it */
197  if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount)))
198  {
199  /* If it had an allocated buffer, delete */
200  if (NotifyChange->AllocatedBuffer)
201  {
202  PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
204  }
205 
206  /* In case of full name, remember subject context for later deletion */
207  if (NotifyChange->FullDirectoryName)
208  {
209  SubjectContext = NotifyChange->SubjectContext;
210  }
211 
212  /* We mustn't have ANY change left anymore */
213  ASSERT(NotifyChange->NotifyList.Flink == NULL);
214  ExFreePoolWithTag(NotifyChange, 0);
215  }
216  }
218  {
219  FsRtlNotifyReleaseFastMutex(RealNotifySync);
220 
221  /* If the subject security context was captured, release and free it */
222  if (SubjectContext)
223  {
226  }
227  }
228  _SEH2_END;
229 }
230 
231 /*
232  * @implemented
233  */
234 VOID
237 {
238  PLIST_ENTRY NextEntry;
239  PNOTIFY_CHANGE NotifyChange;
240 
241  if (!IsListEmpty(NotifyList))
242  {
243  /* Browse the notifications list to find the matching entry */
244  for (NextEntry = NotifyList->Flink;
245  NextEntry != NotifyList;
246  NextEntry = NextEntry->Flink)
247  {
248  NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
249  /* If the current record matches with the given context, it's the good one */
250  if (NotifyChange->FsContext == FsContext && !IsListEmpty(&(NotifyChange->NotifyIrps)))
251  {
253  }
254  }
255  }
256 }
257 
258 /*
259  *@implemented
260  */
264 {
265  PLIST_ENTRY NextEntry;
266  PNOTIFY_CHANGE NotifyChange;
267 
268  if (!IsListEmpty(NotifyList))
269  {
270  /* Browse the notifications list to find the matching entry */
271  for (NextEntry = NotifyList->Flink;
272  NextEntry != NotifyList;
273  NextEntry = NextEntry->Flink)
274  {
275  NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
276  /* If the current record matches with the given context, it's the good one */
277  if (NotifyChange->FsContext == FsContext)
278  {
279  return NotifyChange;
280  }
281  }
282  }
283  return NULL;
284 }
285 
286 /*
287  * @implemented
288  */
289 VOID
291  IN PNOTIFY_CHANGE NotifyChange,
294  IN BOOLEAN SkipCompletion)
295 {
296  PVOID Buffer;
297  PIO_STACK_LOCATION Stack;
298 
299  PAGED_CODE();
300 
301  /* Check if we need to complete */
302  if (!FsRtlNotifySetCancelRoutine(Irp, NotifyChange) && SkipCompletion)
303  {
304  return;
305  }
306 
307  /* No succes => no data to return just complete */
308  if (Status != STATUS_SUCCESS)
309  {
310  goto Completion;
311  }
312 
313  /* Ensure there's something to return */
315  if (!DataLength || Stack->Parameters.NotifyDirectory.Length < DataLength)
316  {
318  goto Completion;
319  }
320 
321  /* Ensture there's a buffer where to find data */
322  if (!NotifyChange->AllocatedBuffer)
323  {
324  Irp->IoStatus.Information = DataLength;
325  NotifyChange->Buffer = NULL;
326  goto Completion;
327  }
328 
329  /* Now, browse all the way to return data
330  * and find the one that will work. We will
331  * return data whatever happens
332  */
333  if (Irp->AssociatedIrp.SystemBuffer)
334  {
335  Buffer = Irp->AssociatedIrp.SystemBuffer;
336  goto CopyAndComplete;
337  }
338 
339  if (Irp->MdlAddress)
340  {
341  Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
342  goto CopyAndComplete;
343  }
344 
345  if (!(Stack->Control & SL_PENDING_RETURNED))
346  {
347  Buffer = Irp->UserBuffer;
348  goto CopyAndComplete;
349  }
350 
352  Irp->AssociatedIrp.SystemBuffer = NotifyChange->AllocatedBuffer;
353  /* Nothing to copy */
354  goto ReleaseAndComplete;
355 
356 CopyAndComplete:
357  _SEH2_TRY
358  {
359  RtlCopyMemory(Buffer, NotifyChange->AllocatedBuffer, DataLength);
360  }
362  {
363  /* Do nothing */
364  }
365  _SEH2_END;
366 
367 ReleaseAndComplete:
368  PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
369 
370  /* Release buffer UNLESS it's used */
371  if (NotifyChange->AllocatedBuffer != Irp->AssociatedIrp.SystemBuffer &&
372  NotifyChange->AllocatedBuffer)
373  {
374  ExFreePoolWithTag(NotifyChange->AllocatedBuffer, 0);
375  }
376 
377  /* Prepare for return */
378  NotifyChange->AllocatedBuffer = 0;
379  NotifyChange->ThisBufferLength = 0;
380  Irp->IoStatus.Information = DataLength;
381  NotifyChange->Buffer = NULL;
382 
383  /* Finally complete */
384 Completion:
386  Irp->IoStatus.Status = Status;
388 }
389 
390 /*
391  * @implemented
392  */
393 VOID
396 {
397  PIRP Irp;
399  PLIST_ENTRY NextEntry;
400 
401  DataLength = NotifyChange->DataLength;
402 
403  NotifyChange->Flags &= (NOTIFY_IMMEDIATELY | WATCH_TREE);
404  NotifyChange->DataLength = 0;
405  NotifyChange->LastEntry = 0;
406 
407  while (!IsListEmpty(&(NotifyChange->NotifyIrps)))
408  {
409  /* We take the first entry */
410  NextEntry = RemoveHeadList(&(NotifyChange->NotifyIrps));
411  Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
412  /* We complete it */
413  FsRtlNotifyCompleteIrp(Irp, NotifyChange, DataLength, Status, TRUE);
414  /* If we're notifying success, just notify first one */
415  if (Status == STATUS_SUCCESS)
416  break;
417  }
418 }
419 
420 /*
421  * @implemented
422  */
423 BOOLEAN
425  IN PNOTIFY_CHANGE NotifyChange OPTIONAL)
426 {
428 
429  /* Acquire cancel lock */
430  IoAcquireCancelSpinLock(&Irp->CancelIrql);
431 
432  /* If NotifyChange was given */
433  if (NotifyChange)
434  {
435  /* First get cancel routine */
437  Irp->IoStatus.Information = 0;
438  /* Release cancel lock */
439  IoReleaseCancelSpinLock(Irp->CancelIrql);
440  /* If there was a cancel routine */
441  if (CancelRoutine)
442  {
443  /* Decrease reference count */
444  InterlockedDecrement((PLONG)&NotifyChange->ReferenceCount);
445  /* Notify that we removed cancel routine */
446  return TRUE;
447  }
448  }
449  else
450  {
451  /* If IRP is cancel, call FsRtl cancel routine */
452  if (Irp->Cancel)
453  {
455  }
456  else
457  {
458  /* Otherwise, define FsRtl cancel routine as IRP cancel routine */
460  /* Release lock */
461  IoReleaseCancelSpinLock(Irp->CancelIrql);
462  }
463  }
464 
465  /* Return that we didn't removed cancel routine */
466  return FALSE;
467 }
468 
469 /*
470  * @implemented
471  */
472 BOOLEAN
474  IN ULONG Action,
475  IN PSTRING ParentName,
478  IN BOOLEAN IsUnicode,
480 {
481  /* Unless there's an issue with buffers, there's no reason to fail */
482  BOOLEAN Succeed = TRUE;
483  ULONG AlreadyWritten = 0, ResultSize;
484 
485  PAGED_CODE();
486 
487  /* Update user buffer with the change that occured
488  * First copy parent name if any
489  * Then copy target name, there's always one
490  * And finally, copy stream name if any
491  * If these names aren't unicode, then convert first
492  */
493  _SEH2_TRY
494  {
495  OutputBuffer->NextEntryOffset = 0;
496  OutputBuffer->Action = Action;
498  if (IsUnicode)
499  {
500  if (ParentName->Length)
501  {
502  RtlCopyMemory(OutputBuffer->FileName, ParentName->Buffer, ParentName->Length);
503  OutputBuffer->FileName[ParentName->Length / sizeof(WCHAR)] = L'\\';
504  AlreadyWritten = ParentName->Length + sizeof(WCHAR);
505  }
506  RtlCopyMemory((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten),
507  TargetName->Buffer, TargetName->Length);
508  if (StreamName)
509  {
510  AlreadyWritten += TargetName->Length;
511  OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = L':';
512  RtlCopyMemory((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten + sizeof(WCHAR)),
513  StreamName->Buffer, StreamName->Length);
514  }
515  }
516  else
517  {
518  if (!ParentName->Length)
519  {
521  RtlCopyMemory(OutputBuffer->FileName, StreamName->Buffer, StreamName->Length);
522  }
523  else
524  {
525  RtlOemToUnicodeN(OutputBuffer->FileName, OutputBuffer->FileNameLength,
526  &ResultSize, ParentName->Buffer,
527  ParentName->Length);
528  OutputBuffer->FileName[ResultSize / sizeof(WCHAR)] = L'\\';
529  AlreadyWritten = ResultSize + sizeof(WCHAR);
530 
531  RtlOemToUnicodeN((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten),
532  OutputBuffer->FileNameLength, &ResultSize,
533  TargetName->Buffer, TargetName->Length);
534 
535  if (StreamName)
536  {
537  AlreadyWritten += ResultSize;
538  OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = L':';
539  RtlOemToUnicodeN((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten + sizeof(WCHAR)),
540  OutputBuffer->FileNameLength, &ResultSize,
541  StreamName->Buffer, StreamName->Length);
542  }
543  }
544  }
545  }
547  {
548  Succeed = FALSE;
549  }
550  _SEH2_END;
551 
552  return Succeed;
553 }
554 
555 /* PUBLIC FUNCTIONS **********************************************************/
556 
557 /*++
558  * @name FsRtlNotifyChangeDirectory
559  * @implemented
560  *
561  * Lets FSD know if changes occures in the specified directory.
562  * Directory will be reenumerated.
563  *
564  * @param NotifySync
565  * Synchronization object pointer
566  *
567  * @param FsContext
568  * Used to identify the notify structure
569  *
570  * @param FullDirectoryName
571  * String (A or W) containing the full directory name
572  *
573  * @param NotifyList
574  * Notify list pointer (to head)
575  *
576  * @param WatchTree
577  * True to notify changes in subdirectories too
578  *
579  * @param CompletionFilter
580  * Used to define types of changes to notify
581  *
582  * @param NotifyIrp
583  * IRP pointer to complete notify operation. It can be null
584  *
585  * @return None
586  *
587  * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
588  *
589  *--*/
590 VOID
591 NTAPI
598  IN PIRP NotifyIrp)
599 {
601  NotifyList,
602  FsContext,
604  WatchTree,
605  TRUE,
607  NotifyIrp,
608  NULL,
609  NULL,
610  NULL);
611 }
612 
613 /*++
614  * @name FsRtlNotifyCleanup
615  * @implemented
616  *
617  * Called by FSD when all handles to FileObject (identified by FsContext) are closed
618  *
619  * @param NotifySync
620  * Synchronization object pointer
621  *
622  * @param NotifyList
623  * Notify list pointer (to head)
624  *
625  * @param FsContext
626  * Used to identify the notify structure
627  *
628  * @return None
629  *
630  * @remarks None
631  *
632  *--*/
633 VOID
634 NTAPI
638 {
639  PNOTIFY_CHANGE NotifyChange;
640  PREAL_NOTIFY_SYNC RealNotifySync;
642 
643  /* Get real structure hidden behind the opaque pointer */
644  RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
645 
646  /* Acquire the fast mutex */
647  FsRtlNotifyAcquireFastMutex(RealNotifySync);
648 
649  _SEH2_TRY
650  {
651  /* Find if there's a matching notification with the FsContext */
652  NotifyChange = FsRtlIsNotifyOnList(NotifyList, FsContext);
653  if (NotifyChange)
654  {
655  /* Mark it as to know that cleanup is in process */
656  NotifyChange->Flags |= CLEANUP_IN_PROCESS;
657 
658  /* If there are pending IRPs, complete them using the STATUS_NOTIFY_CLEANUP status */
659  if (!IsListEmpty(&NotifyChange->NotifyIrps))
660  {
662  }
663 
664  /* Decrease reference number and if 0 is reached, it's time to do complete cleanup */
665  if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount)))
666  {
667  /* Remove it from the notifications list */
668  RemoveEntryList(&NotifyChange->NotifyList);
669 
670  /* In case there was an allocated buffer, free it */
671  if (NotifyChange->AllocatedBuffer)
672  {
673  PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
674  ExFreePool(NotifyChange->AllocatedBuffer);
675  }
676 
677  /* In case there the string was set, get the captured subject security context */
678  if (NotifyChange->FullDirectoryName)
679  {
680  SubjectContext = NotifyChange->SubjectContext;
681  }
682 
683  /* Finally, free the notification, as it's not needed anymore */
684  ExFreePoolWithTag(NotifyChange, 'FSrN');
685  }
686  }
687  }
689  {
690  /* Release fast mutex */
691  FsRtlNotifyReleaseFastMutex(RealNotifySync);
692 
693  /* If the subject security context was captured, release and free it */
694  if (SubjectContext)
695  {
698  }
699  }
700  _SEH2_END;
701 }
702 
703 /*++
704  * @name FsRtlNotifyFilterChangeDirectory
705  * @implemented
706  *
707  * FILLME
708  *
709  * @param NotifySync
710  * FILLME
711  *
712  * @param NotifyList
713  * FILLME
714  *
715  * @param FsContext
716  * FILLME
717  *
718  * @param FullDirectoryName
719  * FILLME
720  *
721  * @param WatchTree
722  * FILLME
723  *
724  * @param IgnoreBuffer
725  * FILLME
726  *
727  * @param CompletionFilter
728  * FILLME
729  *
730  * @param NotifyIrp
731  * FILLME
732  *
733  * @param TraverseCallback
734  * FILLME
735  *
736  * @param SubjectContext
737  * FILLME
738  *
739  * @param FilterCallback
740  * FILLME
741  *
742  * @return None
743  *
744  * @remarks None
745  *
746  *--*/
747 VOID
748 NTAPI
756  IN PIRP NotifyIrp,
760 {
761  ULONG SavedLength;
762  PIO_STACK_LOCATION Stack;
763  PNOTIFY_CHANGE NotifyChange = NULL;
764  PREAL_NOTIFY_SYNC RealNotifySync;
765 
766  PAGED_CODE();
767 
768  DPRINT("FsRtlNotifyFilterChangeDirectory(): %p, %p, %p, %wZ, %u, %u, %u, %p, %p, %p, %p\n",
771 
772  /* Get real structure hidden behind the opaque pointer */
773  RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
774 
775  /* Acquire the fast mutex */
776  FsRtlNotifyAcquireFastMutex(RealNotifySync);
777 
778  _SEH2_TRY
779  {
780  /* If we have no IRP, FSD is performing a cleanup */
781  if (!NotifyIrp)
782  {
783  /* So, we delete */
785  _SEH2_LEAVE;
786  }
787 
788  NotifyIrp->IoStatus.Status = STATUS_SUCCESS;
789  NotifyIrp->IoStatus.Information = (ULONG_PTR)NULL;
790 
792  /* If FileObject's been cleaned up, just return */
793  if (Stack->FileObject->Flags & FO_CLEANUP_COMPLETE)
794  {
796  NotifyIrp->IoStatus.Status = STATUS_NOTIFY_CLEANUP;
798  _SEH2_LEAVE;
799  }
800 
801  /* Try to find a matching notification has been already registered */
802  NotifyChange = FsRtlIsNotifyOnList(NotifyList, FsContext);
803  if (NotifyChange)
804  {
805  /* If it's been found, and is cleaned up, immediatly complete */
806  if (NotifyChange->Flags & CLEANUP_IN_PROCESS)
807  {
809  NotifyIrp->IoStatus.Status = STATUS_NOTIFY_CLEANUP;
811  }
812  /* Or if it's about to be deleted, complete */
813  else if (NotifyChange->Flags & DELETE_IN_PROCESS)
814  {
816  NotifyIrp->IoStatus.Status = STATUS_DELETE_PENDING;
818  }
819  /* Complete now if asked to (and not asked to notify later on) */
820  if ((NotifyChange->Flags & NOTIFY_IMMEDIATELY) && !(NotifyChange->Flags & NOTIFY_LATER))
821  {
822  NotifyChange->Flags &= ~NOTIFY_IMMEDIATELY;
824  NotifyIrp->IoStatus.Status = STATUS_NOTIFY_ENUM_DIR;
826  }
827  /* If no data yet, or asked to notify later on, handle */
828  else if (NotifyChange->DataLength == 0 || (NotifyChange->Flags & NOTIFY_LATER))
829  {
830  goto HandleIRP;
831  }
832  /* Else, just complete with we have */
833  else
834  {
835  SavedLength = NotifyChange->DataLength;
836  NotifyChange->DataLength = 0;
837  FsRtlNotifyCompleteIrp(NotifyIrp, NotifyChange, SavedLength, STATUS_SUCCESS, FALSE);
838  }
839 
840  _SEH2_LEAVE;
841  }
842 
843  /* Allocate new notification */
845  sizeof(NOTIFY_CHANGE), 'FSrN');
846  RtlZeroMemory(NotifyChange, sizeof(NOTIFY_CHANGE));
847 
848  /* Set basic information */
849  NotifyChange->NotifySync = NotifySync;
850  NotifyChange->FsContext = FsContext;
851  NotifyChange->StreamID = Stack->FileObject->FsContext;
852  NotifyChange->TraverseCallback = TraverseCallback;
853  NotifyChange->SubjectContext = SubjectContext;
854  NotifyChange->FullDirectoryName = FullDirectoryName;
855  NotifyChange->FilterCallback = FilterCallback;
856  InitializeListHead(&(NotifyChange->NotifyIrps));
857 
858  /* Keep trace of WatchTree */
859  if (WatchTree)
860  {
861  NotifyChange->Flags |= WATCH_TREE;
862  }
863 
864  /* If string is empty, faulty to ANSI */
865  if (FullDirectoryName->Length == 0)
866  {
867  NotifyChange->CharacterSize = sizeof(CHAR);
868  }
869  else
870  {
871  /* If it can't contain WCHAR, it's ANSI */
872  if (FullDirectoryName->Length < sizeof(WCHAR) || ((CHAR*)FullDirectoryName->Buffer)[1] != 0)
873  {
874  NotifyChange->CharacterSize = sizeof(CHAR);
875  }
876  else
877  {
878  NotifyChange->CharacterSize = sizeof(WCHAR);
879  }
880 
881  /* Now, check is user is willing to watch root */
882  if (FullDirectoryName->Length == NotifyChange->CharacterSize)
883  {
884  NotifyChange->Flags |= WATCH_ROOT;
885  }
886  }
887 
888  NotifyChange->CompletionFilter = CompletionFilter;
889 
890  /* In case we have not to ignore buffer , keep its length */
891  if (!IgnoreBuffer)
892  {
893  NotifyChange->BufferLength = Stack->Parameters.NotifyDirectory.Length;
894  }
895 
896  NotifyChange->OwningProcess = NotifyIrp->Tail.Overlay.Thread->ThreadsProcess;
897 
898  /* Insert the notification into the notification list */
899  InsertTailList(NotifyList, &(NotifyChange->NotifyList));
900 
901  NotifyChange->ReferenceCount = 1;
902 
903 HandleIRP:
904  /* Associate the notification to the IRP */
905  NotifyIrp->IoStatus.Information = (ULONG_PTR)NotifyChange;
906  /* The IRP is pending */
908  /* Insert the IRP in the IRP list */
909  InsertTailList(&(NotifyChange->NotifyIrps), &(NotifyIrp->Tail.Overlay.ListEntry));
910  /* Increment reference count */
911  InterlockedIncrement((PLONG)&(NotifyChange->ReferenceCount));
912  /* Set cancel routine to FsRtl one */
914  }
916  {
917  /* Release fast mutex */
918  FsRtlNotifyReleaseFastMutex(RealNotifySync);
919 
920  /* If the subject security context was captured and there's no notify */
921  if (SubjectContext && (!NotifyChange || NotifyChange->FullDirectoryName))
922  {
925  }
926  }
927  _SEH2_END;
928 }
929 
930 /*++
931  * @name FsRtlNotifyFilterReportChange
932  * @implemented
933  *
934  * FILLME
935  *
936  * @param NotifySync
937  * FILLME
938  *
939  * @param NotifyList
940  * FILLME
941  *
942  * @param FullTargetName
943  * FILLME
944  *
945  * @param TargetNameOffset
946  * FILLME
947  *
948  * @param StreamName
949  * FILLME
950  *
951  * @param NormalizedParentName
952  * FILLME
953  *
954  * @param FilterMatch
955  * FILLME
956  *
957  * @param Action
958  * FILLME
959  *
960  * @param TargetContext
961  * FILLME
962  *
963  * @param FilterContext
964  * FILLME
965  *
966  * @return None
967  *
968  * @remarks None
969  *
970  *--*/
971 VOID
972 NTAPI
980  IN ULONG Action,
983 {
984  PIRP Irp;
986  USHORT FullPosition;
987  PLIST_ENTRY NextEntry;
988  PIO_STACK_LOCATION Stack;
989  PNOTIFY_CHANGE NotifyChange;
990  PREAL_NOTIFY_SYNC RealNotifySync;
991  PFILE_NOTIFY_INFORMATION FileNotifyInfo;
992  BOOLEAN IsStream, IsParent, PoolQuotaCharged;
993  STRING TargetDirectory, TargetName, ParentName, IntNormalizedParentName;
994  ULONG NumberOfBytes, TargetNumberOfParts, FullNumberOfParts, LastPartOffset, ParentNameOffset, ParentNameLength;
995  ULONG DataLength, AlignedDataLength;
996 
997  TargetDirectory.Length = 0;
998  TargetDirectory.MaximumLength = 0;
999  TargetDirectory.Buffer = NULL;
1000  TargetName.Length = 0;
1001  TargetName.MaximumLength = 0;
1002  TargetName.Buffer = NULL;
1003  ParentName.Length = 0;
1004  ParentName.MaximumLength = 0;
1005  ParentName.Buffer = NULL;
1006  IsStream = FALSE;
1007 
1008  PAGED_CODE();
1009 
1010  DPRINT("FsRtlNotifyFilterReportChange(%p, %p, %p, %u, %p, %p, %p, %x, %x, %p, %p)\n",
1013 
1014  /* We need offset in name */
1016  {
1017  return;
1018  }
1019 
1020  /* Get real structure hidden behind the opaque pointer */
1021  RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
1022  /* Acquire lock - will be released in finally block */
1023  FsRtlNotifyAcquireFastMutex(RealNotifySync);
1024  _SEH2_TRY
1025  {
1026  /* Browse all the registered notifications we have */
1027  for (NextEntry = NotifyList->Flink; NextEntry != NotifyList;
1028  NextEntry = NextEntry->Flink)
1029  {
1030  /* Try to find an entry matching our change */
1031  NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
1032  if (FullTargetName != NULL)
1033  {
1034  ASSERT(NotifyChange->FullDirectoryName != NULL);
1035  if (!NotifyChange->FullDirectoryName->Length)
1036  {
1037  continue;
1038  }
1039 
1040  if (!(FilterMatch & NotifyChange->CompletionFilter))
1041  {
1042  continue;
1043  }
1044 
1045  /* If no normalized name provided, construct it from full target name */
1046  if (NormalizedParentName == NULL)
1047  {
1048  IntNormalizedParentName.Buffer = FullTargetName->Buffer;
1049  if (TargetNameOffset != NotifyChange->CharacterSize)
1050  {
1051  IntNormalizedParentName.MaximumLength =
1052  IntNormalizedParentName.Length = TargetNameOffset - NotifyChange->CharacterSize;
1053  }
1054  else
1055  {
1056  IntNormalizedParentName.MaximumLength =
1057  IntNormalizedParentName.Length = TargetNameOffset;
1058  }
1059  NormalizedParentName = &IntNormalizedParentName;
1060  }
1061 
1062  /* heh? Watched directory bigger than changed file? */
1063  if (NormalizedParentName->Length < NotifyChange->FullDirectoryName->Length)
1064  {
1065  continue;
1066  }
1067 
1068  /* Same len => parent */
1069  if (NormalizedParentName->Length == NotifyChange->FullDirectoryName->Length)
1070  {
1071  IsParent = TRUE;
1072  }
1073  /* If not, then, we have to be watching the tree, otherwise we don't have to report such changes */
1074  else if (!(NotifyChange->Flags & WATCH_TREE))
1075  {
1076  continue;
1077  }
1078  /* And finally, we've to check we're properly \-terminated */
1079  else
1080  {
1081  if (!(NotifyChange->Flags & WATCH_ROOT))
1082  {
1083  if (NotifyChange->CharacterSize == sizeof(CHAR))
1084  {
1085  if (((PSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length] != '\\')
1086  {
1087  continue;
1088  }
1089  }
1090  else
1091  {
1092  if (((PWSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length / sizeof (WCHAR)] != L'\\')
1093  {
1094  continue;
1095  }
1096  }
1097  }
1098 
1099  IsParent = FALSE;
1100  }
1101 
1102  /* If len matches, then check that both name are equal */
1103  if (!RtlEqualMemory(NormalizedParentName->Buffer, NotifyChange->FullDirectoryName->Buffer,
1104  NotifyChange->FullDirectoryName->Length))
1105  {
1106  continue;
1107  }
1108 
1109  /* Call traverse callback (only if we have to traverse ;-)) */
1110  if (!IsParent
1111  && NotifyChange->TraverseCallback != NULL
1112  && !NotifyChange->TraverseCallback(NotifyChange->FsContext,
1113  TargetContext,
1114  NotifyChange->SubjectContext))
1115  {
1116  continue;
1117  }
1118 
1119  /* And then, filter callback if provided */
1120  if (NotifyChange->FilterCallback != NULL
1121  && FilterContext != NULL
1122  && !NotifyChange->FilterCallback(NotifyChange->FsContext, FilterContext))
1123  {
1124  continue;
1125  }
1126  }
1127  /* We have a stream! */
1128  else
1129  {
1130  ASSERT(NotifyChange->FullDirectoryName == NULL);
1131  if (TargetContext != NotifyChange->SubjectContext)
1132  {
1133  continue;
1134  }
1135 
1136  ParentName.Buffer = NULL;
1137  ParentName.Length = 0;
1138  IsStream = TRUE;
1139  IsParent = FALSE;
1140  }
1141 
1142  /* If we don't have to notify immediately, prepare for output */
1143  if (!(NotifyChange->Flags & NOTIFY_IMMEDIATELY))
1144  {
1145  /* If we have something to output... */
1146  if (NotifyChange->BufferLength)
1147  {
1148  /* Get size of the output */
1149  NumberOfBytes = 0;
1150  Irp = NULL;
1151  if (!NotifyChange->ThisBufferLength)
1152  {
1153  if (IsListEmpty(&NotifyChange->NotifyIrps))
1154  {
1155  NumberOfBytes = NotifyChange->BufferLength;
1156  }
1157  else
1158  {
1159  Irp = CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, IRP, Tail.Overlay.ListEntry);
1161  NumberOfBytes = Stack->Parameters.NotifyDirectory.Length;
1162  }
1163  }
1164  else
1165  {
1166  NumberOfBytes = NotifyChange->ThisBufferLength;
1167  }
1168 
1169  /* If we're matching parent, we don't care about parent (redundant) */
1170  if (IsParent)
1171  {
1172  ParentName.Length = 0;
1173  }
1174  else
1175  {
1176  /* If we don't deal with streams, some more work is required */
1177  if (!IsStream)
1178  {
1179  if (NotifyChange->Flags & WATCH_ROOT ||
1180  (NormalizedParentName->Buffer != FullTargetName->Buffer))
1181  {
1182  /* Construct TargetDirectory if we don't have it yet */
1183  if (TargetDirectory.Buffer == NULL)
1184  {
1185  TargetDirectory.Buffer = FullTargetName->Buffer;
1186  TargetDirectory.Length = TargetNameOffset;
1187  if (TargetNameOffset != NotifyChange->CharacterSize)
1188  {
1189  TargetDirectory.Length = TargetNameOffset - NotifyChange->CharacterSize;
1190  }
1191  TargetDirectory.MaximumLength = TargetDirectory.Length;
1192  }
1193  /* Now, we start looking for matching parts (unless we watch root) */
1194  TargetNumberOfParts = 0;
1195  if (!(NotifyChange->Flags & WATCH_ROOT))
1196  {
1197  FullNumberOfParts = 1;
1198  if (NotifyChange->CharacterSize == sizeof(CHAR))
1199  {
1201  TargetDirectory.Length, PSTR, '\\');
1202  }
1203  else
1204  {
1206  TargetDirectory.Length / sizeof(WCHAR), PWSTR, L'\\');
1207  LastPartOffset *= NotifyChange->CharacterSize;
1208  }
1209  }
1210 
1211  /* Then, we can construct proper parent name */
1212  ParentNameOffset = NotifyChange->CharacterSize + LastPartOffset;
1213  ParentName.Buffer = &TargetDirectory.Buffer[ParentNameOffset];
1214  ParentNameLength = TargetDirectory.Length;
1215  }
1216  else
1217  {
1218  /* Construct parent name even for streams */
1219  ParentName.Buffer = &NormalizedParentName->Buffer[NotifyChange->FullDirectoryName->Length] + NotifyChange->CharacterSize;
1220  ParentNameLength = NormalizedParentName->Length - NotifyChange->FullDirectoryName->Length;
1221  ParentNameOffset = NotifyChange->CharacterSize;
1222  }
1223  ParentNameLength -= ParentNameOffset;
1224  ParentName.Length = ParentNameLength;
1225  ParentName.MaximumLength = ParentNameLength;
1226  }
1227  }
1228 
1229  /* Start to count amount of data to write, we've first the structure itself */
1231 
1232  /* If stream, we'll just append stream name */
1233  if (IsStream)
1234  {
1235  ASSERT(StreamName != NULL);
1236  DataLength += StreamName->Length;
1237  }
1238  else
1239  {
1240  /* If not parent, we've to append parent name */
1241  if (!IsParent)
1242  {
1243  if (NotifyChange->CharacterSize == sizeof(CHAR))
1244  {
1246  }
1247  else
1248  {
1249  DataLength += ParentName.Length;
1250  }
1251  DataLength += sizeof(WCHAR);
1252  }
1253 
1254  /* Look for target name & construct it, if required */
1255  if (TargetName.Buffer == NULL)
1256  {
1257  TargetName.Buffer = &FullTargetName->Buffer[TargetNameOffset];
1258  TargetName.Length =
1259  TargetName.MaximumLength = FullTargetName->Length - TargetNameOffset;
1260  }
1261 
1262  /* Then, we will append it as well */
1263  if (NotifyChange->CharacterSize == sizeof(CHAR))
1264  {
1266  }
1267  else
1268  {
1269  DataLength += TargetName.Length;
1270  }
1271 
1272  /* If we also had a stream name, then we can append it as well */
1273  if (StreamName != NULL)
1274  {
1275  if (NotifyChange->CharacterSize == sizeof(WCHAR))
1276  {
1277  DataLength += StreamName->Length + sizeof(WCHAR);
1278  }
1279  else
1280  {
1282  }
1283  }
1284  }
1285 
1286  /* Get the position where we can put our data (aligned!) */
1287  AlignedDataLength = ROUND_UP(NotifyChange->DataLength, sizeof(ULONG));
1288  /* If it's higher than buffer length, then, bail out without outputing */
1289  if (DataLength > NumberOfBytes || AlignedDataLength + DataLength > NumberOfBytes)
1290  {
1291  NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
1292  }
1293  else
1294  {
1295  OutputBuffer = NULL;
1296  FileNotifyInfo = NULL;
1297  /* If we already had a buffer, update last entry position */
1298  if (NotifyChange->Buffer != NULL)
1299  {
1300  FileNotifyInfo = (PVOID)((ULONG_PTR)NotifyChange->Buffer + NotifyChange->LastEntry);
1301  FileNotifyInfo->NextEntryOffset = AlignedDataLength - NotifyChange->LastEntry;
1302  NotifyChange->LastEntry = AlignedDataLength;
1303  /* And get our output buffer */
1304  OutputBuffer = (PVOID)((ULONG_PTR)NotifyChange->Buffer + AlignedDataLength);
1305  }
1306  /* If we hadn't buffer, try to find one */
1307  else if (Irp != NULL)
1308  {
1309  if (Irp->AssociatedIrp.SystemBuffer != NULL)
1310  {
1311  OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
1312  }
1313  else if (Irp->MdlAddress != NULL)
1314  {
1315  OutputBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1316  }
1317 
1318  NotifyChange->Buffer = OutputBuffer;
1319  NotifyChange->ThisBufferLength = NumberOfBytes;
1320  }
1321 
1322  /* If we couldn't find one, then allocate one */
1323  if (NotifyChange->Buffer == NULL)
1324  {
1325  PoolQuotaCharged = FALSE;
1326  _SEH2_TRY
1327  {
1329  PoolQuotaCharged = TRUE;
1332  NotifyChange->Buffer = OutputBuffer;
1333  NotifyChange->AllocatedBuffer = OutputBuffer;
1334  }
1335  /* If something went wrong during allocation, notify immediately instead of outputing */
1337  {
1338  if (PoolQuotaCharged)
1339  {
1341  }
1342  NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
1343  }
1344  _SEH2_END;
1345  }
1346 
1347  /* Finally, if we have a buffer, fill it in! */
1348  if (OutputBuffer != NULL)
1349  {
1351  Action, &ParentName, &TargetName,
1352  StreamName, NotifyChange->CharacterSize == sizeof(WCHAR),
1353  DataLength))
1354  {
1355  NotifyChange->DataLength = DataLength + AlignedDataLength;
1356  }
1357  /* If it failed, notify immediately */
1358  else
1359  {
1360  NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
1361  }
1362  }
1363  }
1364 
1365  /* If we have to notify right now (something went wrong?) */
1366  if (NotifyChange->Flags & NOTIFY_IMMEDIATELY)
1367  {
1368  /* Ensure that all our buffers are NULL */
1369  if (NotifyChange->Buffer != NULL)
1370  {
1371  if (NotifyChange->AllocatedBuffer != NULL)
1372  {
1373  PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
1375  }
1376 
1377  NotifyChange->Buffer = NULL;
1378  NotifyChange->AllocatedBuffer = NULL;
1379  NotifyChange->LastEntry = 0;
1380  NotifyChange->DataLength = 0;
1381  NotifyChange->ThisBufferLength = 0;
1382  }
1383  }
1384  }
1385  }
1386 
1387  /* If asking for old name in case of a rename, notify later on,
1388  * so that we can wait for new name.
1389  * http://msdn.microsoft.com/en-us/library/dn392331.aspx
1390  */
1392  {
1393  NotifyChange->Flags |= NOTIFY_LATER;
1394  }
1395  else
1396  {
1397  NotifyChange->Flags &= ~NOTIFY_LATER;
1398  if (!IsListEmpty(&NotifyChange->NotifyIrps))
1399  {
1401  }
1402  }
1403  }
1404  }
1406  {
1407  FsRtlNotifyReleaseFastMutex(RealNotifySync);
1408  }
1409  _SEH2_END;
1410 }
1411 
1412 /*++
1413  * @name FsRtlNotifyFullChangeDirectory
1414  * @implemented
1415  *
1416  * Lets FSD know if changes occures in the specified directory.
1417  *
1418  * @param NotifySync
1419  * Synchronization object pointer
1420  *
1421  * @param NotifyList
1422  * Notify list pointer (to head)
1423  *
1424  * @param FsContext
1425  * Used to identify the notify structure
1426  *
1427  * @param FullDirectoryName
1428  * String (A or W) containing the full directory name
1429  *
1430  * @param WatchTree
1431  * True to notify changes in subdirectories too
1432  *
1433  * @param IgnoreBuffer
1434  * True to reenumerate directory. It's ignored it NotifyIrp is null
1435  *
1436  * @param CompletionFilter
1437  * Used to define types of changes to notify
1438  *
1439  * @param NotifyIrp
1440  * IRP pointer to complete notify operation. It can be null
1441  *
1442  * @param TraverseCallback
1443  * Pointer to a callback function. It's called each time a change is
1444  * done in a subdirectory of the main directory. It's ignored it NotifyIrp
1445  * is null
1446  *
1447  * @param SubjectContext
1448  * Pointer to pass to SubjectContext member of TraverseCallback.
1449  * It's freed after use. It's ignored it NotifyIrp is null
1450  *
1451  * @return None
1452  *
1453  * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
1454  *
1455  *--*/
1456 VOID
1457 NTAPI
1460  IN PVOID FsContext,
1465  IN PIRP NotifyIrp,
1468 {
1470  NotifyList,
1471  FsContext,
1473  WatchTree,
1474  IgnoreBuffer,
1476  NotifyIrp,
1479  NULL);
1480 }
1481 
1482 /*++
1483  * @name FsRtlNotifyFullReportChange
1484  * @implemented
1485  *
1486  * Complets the pending notify IRPs.
1487  *
1488  * @param NotifySync
1489  * Synchronization object pointer
1490  *
1491  * @param NotifyList
1492  * Notify list pointer (to head)
1493  *
1494  * @param FullTargetName
1495  * String (A or W) containing the full directory name that changed
1496  *
1497  * @param TargetNameOffset
1498  * Offset, in FullTargetName, of the final component that is in the changed directory
1499  *
1500  * @param StreamName
1501  * String (A or W) containing a stream name
1502  *
1503  * @param NormalizedParentName
1504  * String (A or W) containing the full directory name that changed with long names
1505  *
1506  * @param FilterMatch
1507  * Flags that will be compared to the completion filter
1508  *
1509  * @param Action
1510  * Action code to store in user's buffer
1511  *
1512  * @param TargetContext
1513  * Pointer to a callback function. It's called each time a change is
1514  * done in a subdirectory of the main directory.
1515  *
1516  * @return None
1517  *
1518  * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
1519  *
1520  *--*/
1521 VOID
1522 NTAPI
1530  IN ULONG Action,
1532 {
1533  FsRtlNotifyFilterReportChange(NotifySync,
1534  NotifyList,
1537  StreamName,
1539  FilterMatch,
1540  Action,
1541  TargetContext,
1542  NULL);
1543 }
1544 
1545 /*++
1546  * @name FsRtlNotifyInitializeSync
1547  * @implemented
1548  *
1549  * Allocates the internal structure associated with notifications.
1550  *
1551  * @param NotifySync
1552  * Opaque pointer. It will receive the address of the allocated internal structure.
1553  *
1554  * @return None
1555  *
1556  * @remarks This function raise an exception in case of a failure.
1557  *
1558  *--*/
1559 VOID
1560 NTAPI
1562 {
1563  PREAL_NOTIFY_SYNC RealNotifySync;
1564 
1565  *NotifySync = NULL;
1566 
1568  sizeof(REAL_NOTIFY_SYNC), 'FSNS');
1569  ExInitializeFastMutex(&(RealNotifySync->FastMutex));
1570  RealNotifySync->OwningThread = 0;
1571  RealNotifySync->OwnerCount = 0;
1572 
1573  *NotifySync = RealNotifySync;
1574 }
1575 
1576 /*++
1577  * @name FsRtlNotifyReportChange
1578  * @implemented
1579  *
1580  * Complets the pending notify IRPs.
1581  *
1582  * @param NotifySync
1583  * Synchronization object pointer
1584  *
1585  * @param NotifyList
1586  * Notify list pointer (to head)
1587  *
1588  * @param FullTargetName
1589  * String (A or W) containing the full directory name that changed
1590  *
1591  * @param FileNamePartLength
1592  * Length of the final component that is in the changed directory
1593  *
1594  * @param FilterMatch
1595  * Flags that will be compared to the completion filter
1596  *
1597  * @return None
1598  *
1599  * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
1600  *
1601  *--*/
1602 VOID
1603 NTAPI
1607  IN PUSHORT FileNamePartLength,
1609 {
1610  FsRtlNotifyFilterReportChange(NotifySync,
1611  NotifyList,
1613  FullTargetName->Length - *FileNamePartLength,
1614  NULL,
1615  NULL,
1616  FilterMatch,
1617  0,
1618  NULL,
1619  NULL);
1620 }
1621 
1622 /*++
1623  * @name FsRtlNotifyUninitializeSync
1624  * @implemented
1625  *
1626  * Uninitialize a NOTIFY_SYNC object
1627  *
1628  * @param NotifySync
1629  * Address of a pointer to a PNOTIFY_SYNC object previously
1630  * initialized by FsRtlNotifyInitializeSync()
1631  *
1632  * @return None
1633  *
1634  * @remarks None
1635  *
1636  *--*/
1637 VOID
1638 NTAPI
1640 {
1641  if (*NotifySync)
1642  {
1643  ExFreePoolWithTag(*NotifySync, 'FSNS');
1644  *NotifySync = NULL;
1645  }
1646 }
1647 
_Inout_ PLIST_ENTRY _In_ PVOID FsContext
Definition: fltkernel.h:2239
#define IN
Definition: typedefs.h:38
#define STATUS_DELETE_PENDING
Definition: ntstatus.h:308
_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:2239
DRIVER_CANCEL * PDRIVER_CANCEL
Definition: iotypes.h:2405
VOID NTAPI SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
Definition: access.c:360
PVOID FsContext
Definition: fsrtl.h:78
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define WATCH_ROOT
Definition: fsrtl.h:59
#define ROUND_UP(n, align)
Definition: eventvwr.h:31
#define SL_PENDING_RETURNED
Definition: iotypes.h:2969
#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:1458
_In_ PIRP Irp
Definition: csq.h:116
uint16_t * PWSTR
Definition: typedefs.h:54
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:1604
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:973
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
unsigned short Length
Definition: sprintf.c:451
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN WatchTree
Definition: fltkernel.h:2239
NTSYSAPI NTSTATUS WINAPI RtlOemToUnicodeN(LPWSTR, DWORD, LPDWORD, LPCSTR, DWORD)
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:1523
BOOLEAN(NTAPI * PFILTER_REPORT_CHANGE)(_In_ PVOID NotifyContext, _In_ PVOID FilterContext)
Definition: fsrtltypes.h:297
IRP
Definition: iotypes.h:2463
#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:473
_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:2239
VOID FASTCALL ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:86
#define PAGED_CODE()
Definition: video.h:57
ULONG DataLength
Definition: fsrtl.h:93
_SEH2_TRY
Definition: create.c:4250
_In_ PLIST_ENTRY _In_ PSTRING FullTargetName
Definition: fsrtlfuncs.h:738
uint32_t ULONG_PTR
Definition: typedefs.h:63
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:635
_In_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_opt_ PIRP NotifyIrp
Definition: fsrtlfuncs.h:722
struct _REAL_NOTIFY_SYNC * PREAL_NOTIFY_SYNC
void * Buffer
Definition: sprintf.c:453
#define IO_DISK_INCREMENT
Definition: iotypes.h:568
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
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:394
VOID NTAPI PsChargePoolQuota(IN PEPROCESS Process, IN POOL_TYPE PoolType, IN SIZE_T Amount)
Definition: quota.c:175
_In_ ULONG BufferLength
Definition: usbdlib.h:225
PSECURITY_SUBJECT_CONTEXT SubjectContext
Definition: fsrtl.h:81
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN IgnoreBuffer
Definition: fltkernel.h:2239
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
_In_opt_ PDRIVER_CANCEL CancelRoutine
Definition: iofuncs.h:2696
PNOTIFY_CHANGE FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:262
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
LIST_ENTRY NotifyIrps
Definition: fsrtl.h:84
#define FORCEINLINE
Definition: ntbasedef.h:221
#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
void DPRINT(...)
Definition: polytest.cpp:61
Definition: bufpool.h:45
_Must_inspect_result_ __drv_aliasesMem _In_ PDEVICE_OBJECT _In_opt_ PVOID _In_ ULONG _Out_opt_ PVOID OutputBuffer
Definition: iofuncs.h:713
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
#define TAG_FS_NOTIFICATIONS
Definition: tag.h:53
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING StreamName
Definition: fsrtlfuncs.h:738
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
#define WATCH_TREE
Definition: fsrtl.h:55
#define DELETE_IN_PROCESS
Definition: fsrtl.h:60
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 NOTIFY_LATER
Definition: fsrtl.h:58
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING _In_ ULONG _In_ ULONG Action
Definition: fsrtlfuncs.h:738
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:235
PEPROCESS OwningProcess
Definition: fsrtl.h:96
ULONG BufferLength
Definition: fsrtl.h:91
VOID NTAPI FsRtlCancelNotify(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: notify.c:79
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
std::wstring STRING
Definition: fontsub.cpp:33
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static const WCHAR L[]
Definition: oid.c:1250
#define InterlockedDecrement
Definition: armddk.h:52
USHORT Flags
Definition: fsrtl.h:86
PREAL_NOTIFY_SYNC NotifySync
Definition: fsrtl.h:77
WCHAR TargetName[256]
Definition: arping.c:27
Definition: typedefs.h:117
VOID FsRtlNotifyCompleteIrp(IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange, IN ULONG DataLength, IN NTSTATUS Status, IN BOOLEAN SkipCompletion)
Definition: notify.c:290
VOID NTAPI IoReleaseCancelSpinLock(IN KIRQL Irql)
Definition: util.c:150
Status
Definition: gdiplustypes.h:24
#define FsRtlNotifyGetLastPartOffset(FullLen, TargLen, Type, Chr)
Definition: notify.c:52
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
_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:2745
PFILE_OBJECT FileObject
Definition: iotypes.h:2813
_SEH2_END
Definition: create.c:4424
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_ PLIST_ENTRY _In_ PSTRING _In_ USHORT TargetNameOffset
Definition: fsrtlfuncs.h:738
#define FO_CLEANUP_COMPLETE
Definition: iotypes.h:1747
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
_Inout_ PLIST_ENTRY NotifyList
Definition: fltkernel.h:2239
signed char * PSTR
Definition: retypes.h:7
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
_SEH2_FINALLY
Definition: create.c:4395
BOOLEAN FsRtlNotifySetCancelRoutine(IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange OPTIONAL)
Definition: notify.c:424
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG CompletionFilter
Definition: fltkernel.h:2239
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:2239
#define IRP_DEALLOCATE_BUFFER
VOID NTAPI FsRtlNotifyInitializeSync(IN PNOTIFY_SYNC *NotifySync)
Definition: notify.c:1561
#define OUT
Definition: typedefs.h:39
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _Inout_ PLARGE_INTEGER NumberOfBytes
Definition: iotypes.h:998
VOID NTAPI PsReturnProcessPagedPoolQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:267
unsigned int ULONG
Definition: retypes.h:1
#define MmGetSystemAddressForMdl(Mdl)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ULONG_PTR
Definition: config.h:101
ULONG_PTR OwningThread
Definition: fsrtl.h:68
VOID NTAPI FsRtlNotifyUninitializeSync(IN PNOTIFY_SYNC *NotifySync)
Definition: notify.c:1639
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define POOL_RAISE_IF_ALLOCATION_FAILURE
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define _SEH2_LEAVE
Definition: filesup.c:20
#define KeGetCurrentThread
Definition: hal.h:44
_Must_inspect_result_ _Out_writes_to_ DataLength PHIDP_DATA _Inout_ PULONG DataLength
Definition: hidpi.h:333
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2772
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
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:592
ULONG CompletionFilter
Definition: fsrtl.h:88
return STATUS_SUCCESS
Definition: btrfs.c:2966
IoMarkIrpPending(Irp)
ULONG OwnerCount
Definition: fsrtl.h:69
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:2239
#define RtlOemStringToCountedUnicodeSize(STRING)
#define IRP_SYNCHRONOUS_PAGING_IO
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:749