@@ -501,7 +501,180 @@ FsRtlNotifyFilterChangeDirectory(IN PNOTIFY_SYNC NotifySync,
501
501
IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL ,
502
502
IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL )
503
503
{
504
- KeBugCheck (FILE_SYSTEM );
504
+ ULONG SavedLength ;
505
+ PIO_STACK_LOCATION Stack ;
506
+ PNOTIFY_CHANGE NotifyChange ;
507
+ PREAL_NOTIFY_SYNC RealNotifySync ;
508
+
509
+ PAGED_CODE ();
510
+
511
+ DPRINT ("FsRtlNotifyFilterChangeDirectory(): %p, %p, %p, %wZ, %d, %d, %u, %p, %p, %p, %p\n" ,
512
+ NotifySync , NotifyList , FsContext , FullDirectoryName , WatchTree , IgnoreBuffer , CompletionFilter , NotifyIrp ,
513
+ TraverseCallback , SubjectContext , FilterCallback );
514
+
515
+ /* Get real structure hidden behind the opaque pointer */
516
+ RealNotifySync = (PREAL_NOTIFY_SYNC )NotifySync ;
517
+
518
+ /* Acquire the fast mutex */
519
+ FsRtlNotifyAcquireFastMutex (RealNotifySync );
520
+
521
+ _SEH2_TRY
522
+ {
523
+ /* If we have no IRP, FSD is performing a cleanup */
524
+ if (!NotifyIrp )
525
+ {
526
+ /* So, we delete */
527
+ FsRtlCheckNotifyForDelete (NotifyList , FsContext );
528
+ _SEH2_LEAVE ;
529
+ }
530
+
531
+ NotifyIrp -> IoStatus .Status = STATUS_SUCCESS ;
532
+ NotifyIrp -> IoStatus .Information = (ULONG_PTR )NULL ;
533
+
534
+ Stack = IoGetCurrentIrpStackLocation (NotifyIrp );
535
+ /* If FileObject's been cleaned up, just return */
536
+ if (Stack -> FileObject -> Flags & FO_CLEANUP_COMPLETE )
537
+ {
538
+ IoMarkIrpPending (NotifyIrp );
539
+ NotifyIrp -> IoStatus .Status = STATUS_NOTIFY_CLEANUP ;
540
+ IofCompleteRequest (NotifyIrp , EVENT_INCREMENT );
541
+ _SEH2_LEAVE ;
542
+ }
543
+
544
+ /* Try to find a matching notification has been already registered */
545
+ NotifyChange = FsRtlIsNotifyOnList (NotifyList , FsContext );
546
+ if (NotifyChange )
547
+ {
548
+ /* If it's been found, and is cleaned up, immediatly complete */
549
+ if (NotifyChange -> Flags & CLEANUP_IN_PROCESS )
550
+ {
551
+ IoMarkIrpPending (NotifyIrp );
552
+ NotifyIrp -> IoStatus .Status = STATUS_NOTIFY_CLEANUP ;
553
+ IofCompleteRequest (NotifyIrp , EVENT_INCREMENT );
554
+ }
555
+ /* Or if it's about to be deleted, complete */
556
+ else if (NotifyChange -> Flags & DELETE_IN_PROCESS )
557
+ {
558
+ IoMarkIrpPending (NotifyIrp );
559
+ NotifyIrp -> IoStatus .Status = STATUS_DELETE_PENDING ;
560
+ IofCompleteRequest (NotifyIrp , EVENT_INCREMENT );
561
+ }
562
+ /* Complete if there is directory enumeration and no buffer available any more */
563
+ if ((NotifyChange -> Flags & INVALIDATE_BUFFERS ) && (NotifyChange -> Flags & ENUMERATE_DIR ))
564
+ {
565
+ NotifyChange -> Flags &= ~INVALIDATE_BUFFERS ;
566
+ IoMarkIrpPending (NotifyIrp );
567
+ NotifyIrp -> IoStatus .Status = STATUS_NOTIFY_ENUM_DIR ;
568
+ IofCompleteRequest (NotifyIrp , EVENT_INCREMENT );
569
+ }
570
+ /* If no data yet, or directory enumeration, handle */
571
+ else if (NotifyChange -> DataLength == 0 || (NotifyChange -> Flags & ENUMERATE_DIR ))
572
+ {
573
+ goto HandleIRP ;
574
+ }
575
+ /* Else, just complete with we have */
576
+ else
577
+ {
578
+ SavedLength = NotifyChange -> DataLength ;
579
+ NotifyChange -> DataLength = 0 ;
580
+ FsRtlNotifyCompleteIrp (NotifyIrp , NotifyChange , SavedLength , STATUS_SUCCESS , FALSE);
581
+ }
582
+
583
+ _SEH2_LEAVE ;
584
+ }
585
+
586
+ /* Allocate new notification */
587
+ NotifyChange = ExAllocatePoolWithTag (PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE ,
588
+ sizeof (NOTIFY_CHANGE ), 'FSrN' );
589
+ RtlZeroMemory (NotifyChange , sizeof (NOTIFY_CHANGE ));
590
+
591
+ /* Set basic information */
592
+ NotifyChange -> NotifySync = NotifySync ;
593
+ NotifyChange -> FsContext = FsContext ;
594
+ NotifyChange -> StreamID = Stack -> FileObject -> FsContext ;
595
+ NotifyChange -> TraverseCallback = TraverseCallback ;
596
+ NotifyChange -> SubjectContext = SubjectContext ;
597
+ NotifyChange -> FullDirectoryName = FullDirectoryName ;
598
+ NotifyChange -> FilterCallback = FilterCallback ;
599
+ InitializeListHead (& (NotifyChange -> NotifyIrps ));
600
+
601
+ /* Keep trace of WatchTree */
602
+ if (WatchTree )
603
+ {
604
+ NotifyChange -> Flags |= WATCH_TREE ;
605
+ }
606
+
607
+ /* If string is empty, faulty to ANSI */
608
+ if (FullDirectoryName -> Length == 0 )
609
+ {
610
+ NotifyChange -> CharacterSize = sizeof (CHAR );
611
+ }
612
+ else
613
+ {
614
+ /* If it can't contain WCHAR, it's ANSI */
615
+ if (FullDirectoryName -> Length < sizeof (WCHAR ))
616
+ {
617
+ NotifyChange -> CharacterSize = sizeof (CHAR );
618
+ }
619
+ /* First char is \, so in unicode, right part is 0
620
+ * whereas in ANSI it contains next char
621
+ */
622
+ else if (((CHAR * )FullDirectoryName -> Buffer )[1 ] == 0 )
623
+ {
624
+ NotifyChange -> CharacterSize = sizeof (WCHAR );
625
+ }
626
+ else
627
+ {
628
+ NotifyChange -> CharacterSize = sizeof (CHAR );
629
+ }
630
+
631
+ /* Now, check is user is willing to watch root */
632
+ if (FullDirectoryName -> Length == NotifyChange -> CharacterSize )
633
+ {
634
+ NotifyChange -> Flags |= WATCH_ROOT ;
635
+ }
636
+ }
637
+
638
+ NotifyChange -> CompletionFilter = CompletionFilter ;
639
+
640
+ /* In case we have not to ignore buffer , keep its length */
641
+ if (!IgnoreBuffer )
642
+ {
643
+ NotifyChange -> BufferLength = Stack -> Parameters .NotifyDirectory .Length ;
644
+ }
645
+
646
+ NotifyChange -> OwningProcess = NotifyIrp -> Tail .Overlay .Thread -> ThreadsProcess ;
647
+
648
+ /* Insert the notification into the notification list */
649
+ InsertTailList (NotifyList , & (NotifyChange -> NotifyList ));
650
+
651
+ NotifyChange -> ReferenceCount = 1 ;
652
+
653
+ HandleIRP :
654
+ /* Associate the notification to the IRP */
655
+ NotifyIrp -> IoStatus .Information = (ULONG_PTR )NotifyChange ;
656
+ /* The IRP is pending */
657
+ IoMarkIrpPending (NotifyIrp );
658
+ /* Insert the IRP in the IRP list */
659
+ InsertTailList (& (NotifyChange -> NotifyIrps ), & (NotifyIrp -> Tail .Overlay .ListEntry ));
660
+ /* Increment reference count */
661
+ InterlockedIncrement ((PLONG )& (NotifyChange -> ReferenceCount ));
662
+ /* Set cancel routine to FsRtl one */
663
+ FsRtlNotifySetCancelRoutine (NotifyIrp , NULL );
664
+ }
665
+ _SEH2_FINALLY
666
+ {
667
+ /* Release fast mutex */
668
+ FsRtlNotifyReleaseFastMutex (RealNotifySync );
669
+
670
+ /* If the subject security context was captured and there's no notify */
671
+ if (SubjectContext && (!NotifyChange || FullDirectoryName ))
672
+ {
673
+ SeReleaseSubjectContext (SubjectContext );
674
+ ExFreePool (SubjectContext );
675
+ }
676
+ }
677
+ _SEH2_END ;
505
678
}
506
679
507
680
/*++
0 commit comments