Skip to content

Commit 3f3e67e

Browse files
committed
[NTOSKRNL]
Implement FsRtlNotifyFilterChangeDirectory svn path=/trunk/; revision=55936
1 parent a764405 commit 3f3e67e

File tree

1 file changed

+174
-1
lines changed

1 file changed

+174
-1
lines changed

reactos/ntoskrnl/fsrtl/notify.c

Lines changed: 174 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,180 @@ FsRtlNotifyFilterChangeDirectory(IN PNOTIFY_SYNC NotifySync,
501501
IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL,
502502
IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL)
503503
{
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;
505678
}
506679

507680
/*++

0 commit comments

Comments
 (0)