\o/!

-----Message d'origine-----
De : ros-dev-boun...@reactos.org [mailto:ros-dev-boun...@reactos.org] De la 
part de Jérôme Gardou
Envoyé : vendredi 7 mars 2014 20:38
À : ros-dev@reactos.org
Objet : Re: [ros-dev] [ros-diffs] [pschweitzer] 62442: [NTOSKRNL] - Implement 
FsRtlNotifyFilterReportChange - Implement FsRtlNotifyUpdateBuffer - Implement 
FsRtlCancelNotify - Implement FsRtlNotifyGetLastPartOffset - Fix implementa...

Awesomeness, in its purest art.

Le 07.03.2014 20:33, pschweit...@svn.reactos.org a écrit :
> Author: pschweitzer
> Date: Fri Mar  7 19:33:38 2014
> New Revision: 62442
>
> URL: http://svn.reactos.org/svn/reactos?rev=62442&view=rev
> Log:
> [NTOSKRNL]
> - Implement FsRtlNotifyFilterReportChange
> - Implement FsRtlNotifyUpdateBuffer
> - Implement FsRtlCancelNotify
> - Implement FsRtlNotifyGetLastPartOffset
> - Fix implementation of FsRtlNotifyFilterChangeDirectory
>
> This finishes the implementation of file system notifications inside the 
> kernel.
> Data are properly returned to the caller on changes.
>
> CORE-2582
>
> Modified:
>      trunk/reactos/ntoskrnl/fsrtl/notify.c
>      trunk/reactos/ntoskrnl/include/internal/fsrtl.h
>
> Modified: trunk/reactos/ntoskrnl/fsrtl/notify.c
> URL: 
> http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/notify
> .c?rev=62442&r1=62441&r2=62442&view=diff
> ==============================================================================
> --- trunk/reactos/ntoskrnl/fsrtl/notify.c     [iso-8859-1] (original)
> +++ trunk/reactos/ntoskrnl/fsrtl/notify.c     [iso-8859-1] Fri Mar  7 
> 19:33:38 2014
> @@ -12,6 +12,55 @@
>   #define NDEBUG
>   #include <debug.h>
>   
> +/* INLINED FUNCTIONS 
> +*********************************************************/
> +
> +/*
> + * @implemented
> + */
> +FORCEINLINE
> +VOID
> +FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) {
> +    ULONG_PTR CurrentThread = (ULONG_PTR)KeGetCurrentThread();
> +
> +    /* Only acquire fast mutex if it's not already acquired by the current 
> thread */
> +    if (RealNotifySync->OwningThread != CurrentThread)
> +    {
> +        ExAcquireFastMutexUnsafe(&(RealNotifySync->FastMutex));
> +        RealNotifySync->OwningThread = CurrentThread;
> +    }
> +    /* Whatever the case, keep trace of the attempt to acquire fast mutex */
> +    RealNotifySync->OwnerCount++;
> +}
> +
> +/*
> + * @implemented
> + */
> +FORCEINLINE
> +VOID
> +FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) {
> +    RealNotifySync->OwnerCount--;
> +    /* Release the fast mutex only if no other instance needs it */
> +    if (!RealNotifySync->OwnerCount)
> +    {
> +        ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex));
> +        RealNotifySync->OwningThread = (ULONG_PTR)0;
> +    }
> +}
> +
> +#define FsRtlNotifyGetLastPartOffset(FullLen, TargLen, Type, Chr)            
>      \
> +    for (FullPosition = 0; FullPosition < FullLen; ++FullPosition)           
>      \
> +        if (((Type)NotifyChange->FullDirectoryName->Buffer)[FullPosition] == 
> Chr) \
> +            ++FullNumberOfParts;                                             
>      \
> +    for (LastPartOffset = 0; LastPartOffset < TargLen; ++LastPartOffset) {   
>      \
> +        if ( ((Type)TargetDirectory.Buffer)[LastPartOffset] == Chr) {        
>      \
> +            ++TargetNumberOfParts;                                           
>      \
> +        if (TargetNumberOfParts == FullNumberOfParts)                        
>      \
> +            break;                                                           
>      \
> +        }                                                                    
>      \
> +    }
> +
>   /* PRIVATE FUNCTIONS 
> *********************************************************/
>   
>   VOID
> @@ -22,13 +71,161 @@
>   FsRtlNotifySetCancelRoutine(IN PIRP Irp,
>                               IN PNOTIFY_CHANGE NotifyChange 
> OPTIONAL);
>   
> +/*
> + * @implemented
> + */
>   VOID
>   NTAPI
>   FsRtlCancelNotify(IN PDEVICE_OBJECT DeviceObject,
>                     IN PIRP Irp)
>   {
> +    PVOID Buffer;
> +    PIRP NotifyIrp;
> +    ULONG BufferLength;
> +    PIO_STACK_LOCATION Stack;
> +    PNOTIFY_CHANGE NotifyChange;
> +    PREAL_NOTIFY_SYNC RealNotifySync;
> +    PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL;
> +
> +    /* Get the NOTIFY_CHANGE struct and reset it */
> +    NotifyChange = (PNOTIFY_CHANGE)Irp->IoStatus.Information;
> +    Irp->IoStatus.Information = 0;
> +    /* Reset the cancel routine */
> +    IoSetCancelRoutine(Irp, NULL);
> +    /* And release lock */
>       IoReleaseCancelSpinLock(Irp->CancelIrql);
> -    UNIMPLEMENTED;
> +    /* Get REAL_NOTIFY_SYNC struct */
> +    RealNotifySync = NotifyChange->NotifySync;
> +
> +    FsRtlNotifyAcquireFastMutex(RealNotifySync);
> +
> +   _SEH2_TRY
> +   {
> +       /* Remove the IRP from the notifications list and mark it pending */
> +       RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
> +       IoMarkIrpPending(Irp);
> +
> +       /* Now, the tricky part - let's find a buffer big enough to hold the 
> return data */
> +       if (NotifyChange->Buffer && NotifyChange->AllocatedBuffer == NULL &&
> +           ((Irp->MdlAddress && MmGetSystemAddressForMdl(Irp->MdlAddress) == 
> NotifyChange->Buffer) ||
> +           NotifyChange->Buffer == Irp->AssociatedIrp.SystemBuffer))
> +       {
> +           /* Assume we didn't find any */
> +           Buffer = NULL;
> +           BufferLength = 0;
> +
> +           /* If we don't have IRPs, check if current buffer is big enough */
> +           if (IsListEmpty(&NotifyChange->NotifyIrps))
> +           {
> +               if (NotifyChange->BufferLength >= NotifyChange->DataLength)
> +               {
> +                   BufferLength = NotifyChange->BufferLength;
> +               }
> +           }
> +           else
> +           {
> +               /* Otherwise, try to look at next IRP available */
> +               NotifyIrp = CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, 
> IRP, Tail.Overlay.ListEntry);
> +               Stack = IoGetCurrentIrpStackLocation(NotifyIrp);
> +
> +               /* If its buffer is big enough, get it */
> +               if (Stack->Parameters.NotifyDirectory.Length >= 
> NotifyChange->BufferLength)
> +               {
> +                   /* Is it MDL? */
> +                   if (NotifyIrp->AssociatedIrp.SystemBuffer == NULL)
> +                   {
> +                       if (NotifyIrp->MdlAddress != NULL)
> +                       {
> +                           Buffer = 
> MmGetSystemAddressForMdl(NotifyIrp->MdlAddress);
> +                       }
> +                   }
> +                   else
> +                   {
> +                       Buffer = NotifyIrp->AssociatedIrp.MasterIrp;
> +                   }
> +
> +                   /* Backup our accepted buffer length */
> +                   BufferLength = Stack->Parameters.NotifyDirectory.Length;
> +                   if (BufferLength > NotifyChange->BufferLength)
> +                   {
> +                       BufferLength = NotifyChange->BufferLength;
> +                   }
> +               }
> +           }
> +
> +           /* At that point, we *may* have a buffer */
> +
> +           /* If it has null length, then note that we won't use it */
> +           if (BufferLength == 0)
> +           {
> +               NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
> +           }
> +           else
> +           {
> +               /* If we have a buffer length, but no buffer then allocate 
> one */
> +               if (Buffer == NULL)
> +               {
> +                   PsChargePoolQuota(NotifyChange->OwningProcess, PagedPool, 
> BufferLength);
> +                   Buffer = ExAllocatePoolWithTag(PagedPool | 
> POOL_RAISE_IF_ALLOCATION_FAILURE, BufferLength, 'NrSF');
> +                   NotifyChange->AllocatedBuffer = Buffer;
> +               }
> +
> +               /* Copy data in that buffer */
> +               RtlCopyMemory(Buffer, NotifyChange->Buffer, 
> NotifyChange->DataLength);
> +               NotifyChange->ThisBufferLength = BufferLength;
> +               NotifyChange->Buffer = Buffer;
> +           }
> +
> +           /* If we don't have valide buffer, ensure everything is 0-ed out 
> */
> +           if (NotifyChange->Flags & NOTIFY_IMMEDIATELY)
> +           {
> +               NotifyChange->Buffer = 0;
> +               NotifyChange->AllocatedBuffer = 0;
> +               NotifyChange->LastEntry = 0;
> +               NotifyChange->DataLength = 0;
> +               NotifyChange->ThisBufferLength = 0;
> +           }
> +       }
> +
> +       /* It's now time to complete - data are ready */
> +
> +       /* Set appropriate status and complete */
> +       Irp->IoStatus.Status = STATUS_CANCELLED;
> +       IofCompleteRequest(Irp, EVENT_INCREMENT);
> +
> +       /* If that notification isn't referenced any longer, drop it */
> +       if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount)))
> +       {
> +           /* If it had an allocated buffer, delete */
> +           if (NotifyChange->AllocatedBuffer)
> +           {
> +               PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, 
> NotifyChange->ThisBufferLength);
> +               ExFreePoolWithTag(NotifyChange->AllocatedBuffer, 'NrSF');
> +           }
> +
> +           /* In case of full name, remember subject context for later 
> deletion */
> +           if (NotifyChange->FullDirectoryName)
> +           {
> +               SubjectContext = NotifyChange->SubjectContext;
> +           }
> +
> +           /* We mustn't have ANY change left anymore */
> +           ASSERT(NotifyChange->NotifyList.Flink == NULL);
> +           ExFreePoolWithTag(NotifyChange, 0);
> +       }
> +    }
> +    _SEH2_FINALLY
> +    {
> +        FsRtlNotifyReleaseFastMutex(RealNotifySync);
> +
> +        /* If the subject security context was captured, release and free it 
> */
> +        if (SubjectContext)
> +        {
> +            SeReleaseSubjectContext(SubjectContext);
> +            ExFreePool(SubjectContext);
> +        }
> +    }
> +    _SEH2_END;
>   }
>   
>   /*
> @@ -58,6 +255,9 @@
>       }
>   }
>   
> +/*
> + *@implemented
> + */
>   PNOTIFY_CHANGE
>   FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList,
>                       IN PVOID FsContext) @@ -81,22 +281,6 @@
>           }
>       }
>       return NULL;
> -}
> -
> -FORCEINLINE
> -VOID
> -FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) -{
> -    ULONG_PTR CurrentThread = (ULONG_PTR)KeGetCurrentThread();
> -
> -    /* Only acquire fast mutex if it's not already acquired by the current 
> thread */
> -    if (RealNotifySync->OwningThread != CurrentThread)
> -    {
> -        ExAcquireFastMutexUnsafe(&(RealNotifySync->FastMutex));
> -        RealNotifySync->OwningThread = CurrentThread;
> -    }
> -    /* Whatever the case, keep trace of the attempt to acquire fast mutex */
> -    RealNotifySync->OwnerCount++;
>   }
>   
>   /*
> @@ -216,7 +400,7 @@
>   
>       DataLength = NotifyChange->DataLength;
>   
> -    NotifyChange->Flags &= (INVALIDATE_BUFFERS | WATCH_TREE);
> +    NotifyChange->Flags &= (NOTIFY_IMMEDIATELY | WATCH_TREE);
>       NotifyChange->DataLength = 0;
>       NotifyChange->LastEntry = 0;
>   
> @@ -233,19 +417,6 @@
>       }
>   }
>   
> -FORCEINLINE
> -VOID
> -FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) -{
> -    RealNotifySync->OwnerCount--;
> -    /* Release the fast mutex only if no other instance needs it */
> -    if (!RealNotifySync->OwnerCount)
> -    {
> -        ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex));
> -        RealNotifySync->OwningThread = (ULONG_PTR)0;
> -    }
> -}
> -
>   /*
>    * @implemented
>    */
> @@ -293,6 +464,91 @@
>   
>       /* Return that we didn't removed cancel routine */
>       return FALSE;
> +}
> +
> +/*
> + * @implemented
> + */
> +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) {
> +    /* Unless there's an issue with buffers, there's no reason to fail */
> +    BOOLEAN Succeed = TRUE;
> +    ULONG AlreadyWritten = 0, ResultSize;
> +
> +    PAGED_CODE();
> +
> +    /* Update user buffer with the change that occured
> +     * First copy parent name if any
> +     * Then copy target name, there's always one
> +     * And finally, copy stream name if any
> +     * If these names aren't unicode, then convert first
> +     */
> +    _SEH2_TRY
> +    {
> +        OutputBuffer->NextEntryOffset = 0;
> +        OutputBuffer->Action = Action;
> +        OutputBuffer->FileNameLength = DataLength - 
> sizeof(FILE_NOTIFY_INFORMATION);
> +        if (IsUnicode)
> +        {
> +            if (ParentName->Length)
> +            {
> +                RtlCopyMemory(OutputBuffer->FileName, ParentName->Buffer, 
> ParentName->Length);
> +                OutputBuffer->FileName[ParentName->Length / sizeof(WCHAR)] = 
> L'\\';
> +                AlreadyWritten = ParentName->Length + sizeof(WCHAR);
> +            }
> +            RtlCopyMemory(OutputBuffer->FileName + AlreadyWritten, 
> TargetName->Buffer, TargetName->Length);
> +            if (StreamName)
> +            {
> +                AlreadyWritten += TargetName->Length;
> +                OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = 
> L':';
> +                RtlCopyMemory(OutputBuffer->FileName + AlreadyWritten + 
> sizeof(WCHAR),
> +                              StreamName->Buffer, StreamName->Length);
> +            }
> +        }
> +        else
> +        {
> +            if (!ParentName->Length)
> +            {
> +                ASSERT(StreamName);
> +                RtlCopyMemory(OutputBuffer->FileName, StreamName->Buffer, 
> StreamName->Length);
> +            }
> +            else
> +            {
> +                RtlOemToUnicodeN(OutputBuffer->FileName, 
> OutputBuffer->FileNameLength,
> +                                 &ResultSize, ParentName->Buffer,
> +                                 ParentName->Length);
> +                OutputBuffer->FileName[ResultSize / sizeof(WCHAR)] = L'\\';
> +                AlreadyWritten = ResultSize + sizeof(WCHAR);
> +
> +                RtlOemToUnicodeN(OutputBuffer->FileName + AlreadyWritten,
> +                                 OutputBuffer->FileNameLength, &ResultSize,
> +                                 TargetName->Buffer, 
> + TargetName->Length);
> +
> +                if (StreamName)
> +                {
> +                    AlreadyWritten += ResultSize;
> +                    OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = 
> L':';
> +                    RtlOemToUnicodeN(OutputBuffer->FileName + AlreadyWritten 
> + sizeof(WCHAR),
> +                                     OutputBuffer->FileNameLength, 
> &ResultSize,
> +                                     StreamName->Buffer, StreamName->Length);
> +                }
> +            }
> +        }
> +    }
> +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
> +    {
> +        Succeed = FALSE;
> +    }
> +    _SEH2_END;
> +
> +    return Succeed;
>   }
>   
>   /* PUBLIC FUNCTIONS 
> **********************************************************/
> @@ -445,7 +701,7 @@
>   
>   /*++
>    * @name FsRtlNotifyFilterChangeDirectory
> - * @unimplemented
> + * @implemented
>    *
>    * FILLME
>    *
> @@ -559,16 +815,16 @@
>                   NotifyIrp->IoStatus.Status = STATUS_DELETE_PENDING;
>                   IoCompleteRequest(NotifyIrp, EVENT_INCREMENT);
>               }
> -            /* Complete if there is directory enumeration and no buffer 
> available any more */
> -            if ((NotifyChange->Flags & INVALIDATE_BUFFERS) && 
> (NotifyChange->Flags & ENUMERATE_DIR))
> -            {
> -                NotifyChange->Flags &= ~INVALIDATE_BUFFERS;
> +            /* Complete now if asked to (and not asked to notify later on) */
> +            if ((NotifyChange->Flags & NOTIFY_IMMEDIATELY) && 
> !(NotifyChange->Flags & NOTIFY_LATER))
> +            {
> +                NotifyChange->Flags &= ~NOTIFY_IMMEDIATELY;
>                   IoMarkIrpPending(NotifyIrp);
>                   NotifyIrp->IoStatus.Status = STATUS_NOTIFY_ENUM_DIR;
>                   IoCompleteRequest(NotifyIrp, EVENT_INCREMENT);
>               }
> -            /* If no data yet, or directory enumeration, handle */
> -            else if (NotifyChange->DataLength == 0 || (NotifyChange->Flags & 
> ENUMERATE_DIR))
> +            /* If no data yet, or asked to notify later on, handle */
> +            else if (NotifyChange->DataLength == 0 || 
> + (NotifyChange->Flags & NOTIFY_LATER))
>               {
>                   goto HandleIRP;
>               }
> @@ -612,20 +868,13 @@
>           else
>           {
>               /* If it can't contain WCHAR, it's ANSI */
> -            if (FullDirectoryName->Length < sizeof(WCHAR))
> +            if (FullDirectoryName->Length < sizeof(WCHAR) || 
> + ((CHAR*)FullDirectoryName->Buffer)[1] != 0)
>               {
>                   NotifyChange->CharacterSize = sizeof(CHAR);
>               }
> -            /* First char is \, so in unicode, right part is 0
> -             * whereas in ANSI it contains next char
> -             */
> -            else if (((CHAR*)FullDirectoryName->Buffer)[1] == 0)
> +            else
>               {
>                   NotifyChange->CharacterSize = sizeof(WCHAR);
> -            }
> -            else
> -            {
> -                NotifyChange->CharacterSize = sizeof(CHAR);
>               }
>   
>               /* Now, check is user is willing to watch root */ @@ 
> -668,7 +917,7 @@
>           FsRtlNotifyReleaseFastMutex(RealNotifySync);
>   
>           /* If the subject security context was captured and there's no 
> notify */
> -        if (SubjectContext && (!NotifyChange || FullDirectoryName))
> +        if (SubjectContext && (!NotifyChange || 
> + NotifyChange->FullDirectoryName))
>           {
>               SeReleaseSubjectContext(SubjectContext);
>               ExFreePool(SubjectContext); @@ -679,7 +928,7 @@
>   
>   /*++
>    * @name FsRtlNotifyFilterReportChange
> - * @unimplemented
> + * @implemented
>    *
>    * FILLME
>    *
> @@ -731,7 +980,437 @@
>                                 IN PVOID TargetContext,
>                                 IN PVOID FilterContext)
>   {
> -    KeBugCheck(FILE_SYSTEM);
> +    PIRP Irp;
> +    PVOID OutputBuffer;
> +    USHORT FullPosition;
> +    PLIST_ENTRY NextEntry;
> +    PIO_STACK_LOCATION Stack;
> +    PNOTIFY_CHANGE NotifyChange;
> +    PREAL_NOTIFY_SYNC RealNotifySync;
> +    PFILE_NOTIFY_INFORMATION FileNotifyInfo;
> +    BOOLEAN IsStream, IsParent, PoolQuotaCharged;
> +    STRING TargetDirectory, TargetName, ParentName, IntNormalizedParentName;
> +    ULONG NumberOfBytes, TargetNumberOfParts, FullNumberOfParts, 
> LastPartOffset, ParentNameOffset, ParentNameLength;
> +    ULONG DataLength, TargetNameLength, AlignedDataLength;
> +
> +    TargetDirectory.Length = 0;
> +    TargetDirectory.MaximumLength = 0;
> +    TargetDirectory.Buffer = NULL;
> +    TargetName.Length = 0;
> +    TargetName.MaximumLength = 0;
> +    TargetName.Buffer = NULL;
> +    ParentName.Length = 0;
> +    ParentName.MaximumLength = 0;
> +    ParentName.Buffer = NULL;
> +    IsStream = FALSE;
> +
> +    PAGED_CODE();
> +
> +    DPRINT("FsRtlNotifyFilterReportChange(%p, %p, %p, %u, %p, %p, %p, %x, 
> %x, %p, %p)\n",
> +           NotifySync, NotifyList, FullTargetName, TargetNameOffset, 
> StreamName, NormalizedParentName,
> +           FilterMatch, Action, TargetContext, FilterContext);
> +
> +    /* We need offset in name */
> +    if (!TargetNameOffset && FullTargetName)
> +    {
> +        return;
> +    }
> +
> +    /* Get real structure hidden behind the opaque pointer */
> +    RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
> +    /* Acquire lock - will be released in finally block */
> +    FsRtlNotifyAcquireFastMutex(RealNotifySync);
> +    _SEH2_TRY
> +    {
> +        /* Browse all the registered notifications we have */
> +        for (NextEntry = NotifyList->Flink; NextEntry != NotifyList;
> +             NextEntry = NextEntry->Flink)
> +        {
> +            /* Try to find an entry matching our change */
> +            NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, 
> NotifyList);
> +            if (FullTargetName != NULL)
> +            {
> +                ASSERT(NotifyChange->FullDirectoryName != NULL);
> +                if (!NotifyChange->FullDirectoryName->Length)
> +                {
> +                    continue;
> +                }
> +
> +                if (!(FilterMatch & NotifyChange->CompletionFilter))
> +                {
> +                    continue;
> +                }
> +
> +                /* If no normalized name provided, construct it from full 
> target name */
> +                if (NormalizedParentName == NULL)
> +                {
> +                    IntNormalizedParentName.Buffer = FullTargetName->Buffer;
> +                    if (TargetNameOffset != NotifyChange->CharacterSize)
> +                    {
> +                        IntNormalizedParentName.MaximumLength =
> +                        IntNormalizedParentName.Length = TargetNameOffset - 
> NotifyChange->CharacterSize;
> +                    }
> +                    else
> +                    {
> +                        IntNormalizedParentName.MaximumLength =
> +                        IntNormalizedParentName.Length = TargetNameOffset;
> +                    }
> +                    NormalizedParentName = &IntNormalizedParentName;
> +                }
> +
> +                /* heh? Watched directory bigger than changed file? */
> +                if (NormalizedParentName->Length < 
> NotifyChange->FullDirectoryName->Length)
> +                {
> +                    continue;
> +                }
> +
> +                /* Same len => parent */
> +                if (NormalizedParentName->Length == 
> NotifyChange->FullDirectoryName->Length)
> +                {
> +                    IsParent = TRUE;
> +                }
> +                /* If not, then, we have to be watching the tree, otherwise 
> we don't have to report such changes */
> +                else if (!(NotifyChange->Flags & WATCH_TREE))
> +                {
> +                    continue;
> +                }
> +                /* And finally, we've to check we're properly \-terminated */
> +                else
> +                {
> +                    if (!(NotifyChange->Flags & WATCH_ROOT))
> +                    {
> +                        if (NotifyChange->CharacterSize == sizeof(CHAR))
> +                        {
> +                            if 
> (((PSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length]
>  != '\\')
> +                            {
> +                                continue;
> +                            }
> +                        }
> +                        else
> +                        {
> +                            if 
> (((PWSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length
>  / sizeof (WCHAR)] != L'\\')
> +                            {
> +                                continue;
> +                            }
> +                        }
> +                    }
> +
> +                    IsParent = FALSE;
> +                }
> +
> +                /* If len matches, then check that both name are equal */
> +                if (!RtlEqualMemory(NormalizedParentName->Buffer, 
> NotifyChange->FullDirectoryName->Buffer,
> +                                    NotifyChange->FullDirectoryName->Length))
> +                {
> +                    continue;
> +                }
> +
> +                /* Call traverse callback (only if we have to traverse ;-)) 
> */
> +                if (!IsParent
> +                    && NotifyChange->TraverseCallback != NULL
> +                    && 
> !NotifyChange->TraverseCallback(NotifyChange->FsContext,
> +                                                       TargetContext,
> +                                                       
> NotifyChange->SubjectContext))
> +                {
> +                    continue;
> +                }
> +
> +                /* And then, filter callback if provided */
> +                if (NotifyChange->FilterCallback != NULL
> +                    && FilterContext != NULL
> +                    && 
> !NotifyChange->FilterCallback(NotifyChange->FsContext, FilterContext))
> +                {
> +                    continue;
> +                }
> +            }
> +            /* We have a stream! */
> +            else
> +            {
> +                ASSERT(NotifyChange->FullDirectoryName == NULL);
> +                if (TargetContext != NotifyChange->SubjectContext)
> +                {
> +                    continue;
> +                }
> +
> +                ParentName.Buffer = NULL;
> +                ParentName.Length = 0;
> +                IsStream = TRUE;
> +                IsParent = FALSE;
> +            }
> +
> +            /* If we don't have to notify immediately, prepare for output */
> +            if (!(NotifyChange->Flags & NOTIFY_IMMEDIATELY))
> +            {
> +                /* If we have something to output... */
> +                if (NotifyChange->BufferLength)
> +                {
> +                    /* Get size of the output */
> +                    NumberOfBytes = 0;
> +                    Irp = NULL;
> +                    if (!NotifyChange->ThisBufferLength)
> +                    {
> +                        if (IsListEmpty(&NotifyChange->NotifyIrps))
> +                        {
> +                            NumberOfBytes = NotifyChange->BufferLength;
> +                        }
> +                        else
> +                        {
> +                            Irp = 
> CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, IRP, 
> Tail.Overlay.ListEntry);
> +                            Stack = IoGetCurrentIrpStackLocation(Irp);
> +                            NumberOfBytes = 
> Stack->Parameters.NotifyDirectory.Length;
> +                        }
> +                    }
> +                    else
> +                    {
> +                        NumberOfBytes = NotifyChange->ThisBufferLength;
> +                    }
> +
> +                    /* If we're matching parent, we don't care about parent 
> (redundant) */
> +                    if (IsParent)
> +                    {
> +                        ParentName.Length = 0;
> +                    }
> +                    else
> +                    {
> +                        /* If we don't deal with streams, some more work is 
> required */
> +                        if (!IsStream)
> +                        {
> +                            if (NotifyChange->Flags & WATCH_ROOT ||
> +                                (NormalizedParentName->Buffer != 
> FullTargetName->Buffer))
> +                            {
> +                                /* Construct TargetDirectory if we don't 
> have it yet */
> +                                if (TargetDirectory.Buffer == NULL)
> +                                {
> +                                    TargetDirectory.Buffer = 
> FullTargetName->Buffer;
> +                                    TargetDirectory.Length = 
> TargetNameOffset;
> +                                    if (TargetNameOffset != 
> NotifyChange->CharacterSize)
> +                                    {
> +                                        TargetDirectory.Length = 
> TargetNameOffset - NotifyChange->CharacterSize;
> +                                    }
> +                                    TargetDirectory.MaximumLength = 
> TargetDirectory.Length;
> +                                }
> +                                /* Now, we start looking for matching parts 
> (unless we watch root) */
> +                                TargetNumberOfParts = 0;
> +                                if (!(NotifyChange->Flags & WATCH_ROOT))
> +                                {
> +                                    FullNumberOfParts = 1;
> +                                    if (NotifyChange->CharacterSize == 
> sizeof(CHAR))
> +                                    {
> +                                        
> FsRtlNotifyGetLastPartOffset(NotifyChange->FullDirectoryName->Length,
> +                                                                     
> TargetDirectory.Length, PSTR, '\\');
> +                                    }
> +                                    else
> +                                    {
> +                                        
> FsRtlNotifyGetLastPartOffset(NotifyChange->FullDirectoryName->Length / 
> sizeof(WCHAR),
> +                                                                     
> TargetDirectory.Length / sizeof(WCHAR), PWSTR, L'\\');
> +                                        LastPartOffset *= 
> NotifyChange->CharacterSize;
> +                                    }
> +                                }
> +
> +                                /* Then, we can construct proper parent name 
> */
> +                                ParentNameOffset = 
> NotifyChange->CharacterSize + LastPartOffset;
> +                                ParentName.Buffer = 
> &TargetDirectory.Buffer[ParentNameOffset];
> +                                ParentNameLength = TargetDirectory.Length;
> +                            }
> +                            else
> +                            {
> +                                /* Construct parent name even for streams */
> +                                ParentName.Buffer = 
> &NormalizedParentName->Buffer[NotifyChange->FullDirectoryName->Length] + 
> NotifyChange->CharacterSize;
> +                                ParentNameLength = 
> NormalizedParentName->Length - NotifyChange->FullDirectoryName->Length;
> +                                ParentNameOffset = 
> NotifyChange->CharacterSize;
> +                            }
> +                            ParentNameLength -= ParentNameOffset;
> +                            ParentName.Length = ParentNameLength;
> +                            ParentName.MaximumLength = ParentNameLength;
> +                        }
> +                    }
> +
> +                    /* Start to count amount of data to write, we've first 
> the structure itself */
> +                    DataLength = 
> + FIELD_OFFSET(FILE_NOTIFY_INFORMATION, FileName);
> +
> +                    /* If stream, we'll just append stream name */
> +                    if (IsStream)
> +                    {
> +                        ASSERT(StreamName != NULL);
> +                        DataLength += StreamName->Length;
> +                    }
> +                    else
> +                    {
> +                        /* If not parent, we've to append parent name */
> +                        if (!IsParent)
> +                        {
> +                            if (NotifyChange->CharacterSize == sizeof(CHAR))
> +                            {
> +                                DataLength += 
> RtlOemStringToCountedUnicodeSize(&ParentName);
> +                            }
> +                            else
> +                            {
> +                                DataLength += ParentName.Length;
> +                            }
> +                            DataLength += sizeof(WCHAR);
> +                        }
> +
> +                        /* Look for target name & construct it, if required 
> */
> +                        if (TargetName.Buffer)
> +                        {
> +                            TargetNameLength = TargetName.Length;
> +                        }
> +                        else
> +                        {
> +                            TargetName.Buffer = 
> &FullTargetName->Buffer[TargetNameOffset];
> +                            TargetNameLength = FullTargetName->Length - 
> TargetNameOffset;
> +                            TargetName.Length = TargetNameLength;
> +                            TargetName.MaximumLength = TargetNameLength;
> +                        }
> +
> +                        /* Then, we will append it as well */
> +                        if (NotifyChange->CharacterSize == sizeof(CHAR))
> +                        {
> +                            DataLength += 
> RtlOemStringToCountedUnicodeSize(&TargetName);
> +                        }
> +                        else
> +                        {
> +                            DataLength += TargetName.Length;
> +                        }
> +
> +                        /* If we also had a stream name, then we can append 
> it as well */
> +                        if (StreamName != NULL)
> +                        {
> +                            if (NotifyChange->CharacterSize == sizeof(WCHAR))
> +                            {
> +                                DataLength += StreamName->Length + 
> sizeof(WCHAR);
> +                            }
> +                            else
> +                            {
> +                                DataLength = DataLength + 
> RtlOemStringToCountedUnicodeSize(&TargetName) + sizeof(CHAR);
> +                            }
> +                        }
> +                    }
> +
> +                    /* Get the position where we can put our data (aligned!) 
> */
> +                    AlignedDataLength = ROUND_UP(NotifyChange->DataLength, 
> sizeof(ULONG));
> +                    /* If it's higher than buffer length, then, bail out 
> without outputing */
> +                    if (DataLength > NumberOfBytes || AlignedDataLength + 
> DataLength > NumberOfBytes)
> +                    {
> +                        NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
> +                    }
> +                    else
> +                    {
> +                        OutputBuffer = 0;
> +                        FileNotifyInfo = 0;
> +                        /* If we already had a buffer, update last entry 
> position */
> +                        if (NotifyChange->Buffer != NULL)
> +                        {
> +                            FileNotifyInfo = 
> (PVOID)((ULONG_PTR)NotifyChange->Buffer + NotifyChange->LastEntry);
> +                            FileNotifyInfo->NextEntryOffset = 
> AlignedDataLength - NotifyChange->LastEntry;
> +                            NotifyChange->LastEntry = AlignedDataLength;
> +                            /* And get our output buffer */
> +                            OutputBuffer = 
> (PVOID)((ULONG_PTR)NotifyChange->Buffer + AlignedDataLength);
> +                        }
> +                        /* If we hadn't buffer, try to find one */
> +                        else if (Irp != NULL)
> +                        {
> +                            if (Irp->AssociatedIrp.SystemBuffer != NULL)
> +                            {
> +                                OutputBuffer = 
> Irp->AssociatedIrp.SystemBuffer;
> +                            }
> +                            else if (Irp->MdlAddress != NULL)
> +                            {
> +                                OutputBuffer = 
> MmGetSystemAddressForMdl(Irp->MdlAddress);
> +                            }
> +
> +                            NotifyChange->Buffer = OutputBuffer;
> +                            NotifyChange->ThisBufferLength = NumberOfBytes;
> +                        }
> +
> +                        /* If we couldn't find one, then allocate one */
> +                        if (NotifyChange->Buffer == NULL)
> +                        {
> +                            PoolQuotaCharged = FALSE;
> +                            _SEH2_TRY
> +                            {
> +                                
> PsChargePoolQuota(NotifyChange->OwningProcess, PagedPool, NumberOfBytes);
> +                                PoolQuotaCharged = TRUE;
> +                                OutputBuffer = 
> ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,
> +                                                                     
> NumberOfBytes, 'NrSF');
> +                                NotifyChange->Buffer = OutputBuffer;
> +                                NotifyChange->AllocatedBuffer = OutputBuffer;
> +                            }
> +                            /* If something went wrong during allocation, 
> notify immediately instead of outputing */
> +                            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
> +                            {
> +                                if (PoolQuotaCharged)
> +                                {
> +                                    
> PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NumberOfBytes);
> +                                }
> +                                NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
> +                            }
> +                            _SEH2_END;
> +                        }
> +
> +                        /* Finally, if we have a buffer, fill it in! */
> +                        if (OutputBuffer != NULL)
> +                        {
> +                            if 
> (FsRtlNotifyUpdateBuffer((FILE_NOTIFY_INFORMATION *)OutputBuffer,
> +                                                         Action, 
> &ParentName, &TargetName,
> +                                                         StreamName, 
> NotifyChange->CharacterSize == sizeof(WCHAR),
> +                                                         DataLength))
> +                            {
> +                                NotifyChange->DataLength = DataLength + 
> AlignedDataLength;
> +                            }
> +                            /* If it failed, notify immediately */
> +                            else
> +                            {
> +                                NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
> +                            }
> +                        }
> +                    }
> +
> +                    /* If we have to notify right now (something went 
> wrong?) */
> +                    if (NotifyChange->Flags & NOTIFY_IMMEDIATELY)
> +                    {
> +                        /* Ensure that all our buffers are NULL */
> +                        if (NotifyChange->Buffer != NULL)
> +                        {
> +                            if (NotifyChange->AllocatedBuffer != NULL)
> +                            {
> +                                
> PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, 
> NotifyChange->ThisBufferLength);
> +                                
> ExFreePoolWithTag(NotifyChange->AllocatedBuffer, 'NrSF');
> +                            }
> +
> +                            NotifyChange->Buffer = NULL;
> +                            NotifyChange->AllocatedBuffer = NULL;
> +                            NotifyChange->LastEntry = 0;
> +                            NotifyChange->DataLength = 0;
> +                            NotifyChange->ThisBufferLength = 0;
> +                        }
> +                    }
> +                }
> +            }
> +
> +            /* If asking for old name in case of a rename, notify later on,
> +             * so that we can wait for new name.
> +             * http://msdn.microsoft.com/en-us/library/dn392331.aspx
> +             */
> +            if (Action == FILE_ACTION_RENAMED_OLD_NAME)
> +            {
> +                NotifyChange->Flags |= NOTIFY_LATER;
> +            }
> +            else
> +            {
> +                NotifyChange->Flags &= ~NOTIFY_LATER;
> +                if (!IsListEmpty(&NotifyChange->NotifyIrps))
> +                {
> +                    FsRtlNotifyCompleteIrpList(NotifyChange, STATUS_SUCCESS);
> +                }
> +            }
> +        }
> +    }
> +    _SEH2_FINALLY
> +    {
> +        FsRtlNotifyReleaseFastMutex(RealNotifySync);
> +    }
> +    _SEH2_END;
>   }
>   
>   /*++
>
> Modified: trunk/reactos/ntoskrnl/include/internal/fsrtl.h
> URL: 
> http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/inte
> rnal/fsrtl.h?rev=62442&r1=62441&r2=62442&view=diff
> ==============================================================================
> --- trunk/reactos/ntoskrnl/include/internal/fsrtl.h   [iso-8859-1] (original)
> +++ trunk/reactos/ntoskrnl/include/internal/fsrtl.h   [iso-8859-1] Fri Mar  7 
> 19:33:38 2014
> @@ -53,9 +53,9 @@
>   // Notifications flags
>   //
>   #define WATCH_TREE         0x01
> -#define INVALIDATE_BUFFERS 0x02
> +#define NOTIFY_IMMEDIATELY 0x02
>   #define CLEANUP_IN_PROCESS 0x04
> -#define ENUMERATE_DIR      0x08
> +#define NOTIFY_LATER       0x08
>   #define WATCH_ROOT         0x10
>   #define DELETE_IN_PROCESS  0x20
>   
>
>


_______________________________________________
Ros-dev mailing list
Ros-dev@reactos.org
http://www.reactos.org/mailman/listinfo/ros-dev

_______________________________________________
Ros-dev mailing list
Ros-dev@reactos.org
http://www.reactos.org/mailman/listinfo/ros-dev

Reply via email to