[NTOS:FSRTL] Rework FsRtlIsNameInExpressionPrivate for correct parsing some expressions
authorDmitry Chapyshev <dmitry@reactos.org>
Tue, 27 Sep 2016 23:00:20 +0000 (23:00 +0000)
committerDmitry Chapyshev <dmitry@reactos.org>
Tue, 27 Sep 2016 23:00:20 +0000 (23:00 +0000)
* Fixes 1 test for kmtest:FsRtlExpression and 15 tests for kernel32:file

svn path=/trunk/; revision=72835

reactos/ntoskrnl/fsrtl/name.c

index 90558e4..3830454 100644 (file)
@@ -23,13 +23,14 @@ FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression,
                                IN BOOLEAN IgnoreCase,
                                IN PWCHAR UpcaseTable OPTIONAL)
 {
-    SHORT StarFound = -1, DosStarFound = -1;
-    USHORT BackTrackingBuffer[5], DosBackTrackingBuffer[5];
-    PUSHORT BackTracking = BackTrackingBuffer, DosBackTracking = DosBackTrackingBuffer;
-    SHORT BackTrackingSize = RTL_NUMBER_OF(BackTrackingBuffer);
-    SHORT DosBackTrackingSize = RTL_NUMBER_OF(DosBackTrackingBuffer);
+    USHORT Offset, Position, BackTrackingPosition, OldBackTrackingPosition;
+    USHORT BackTrackingBuffer[16], OldBackTrackingBuffer[16] = {0};
+    PUSHORT BackTrackingSwap, BackTracking = BackTrackingBuffer, OldBackTracking = OldBackTrackingBuffer;
     UNICODE_STRING IntExpression;
-    USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars, LastDot;
+    USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars = 1;
+    BOOLEAN EndOfName = FALSE;
+    BOOLEAN Result = FALSE;
+    BOOLEAN DontSkipDot;
     WCHAR CompareChar;
     PAGED_CODE();
 
@@ -37,7 +38,7 @@ FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression,
     if (!Name->Length || !Expression->Length)
     {
         /* Return TRUE if both strings are empty, otherwise FALSE */
-        if (Name->Length == 0 && Expression->Length == 0)
+        if (!Name->Length && !Expression->Length)
             return TRUE;
         else
             return FALSE;
@@ -103,193 +104,144 @@ FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression,
         }
     }
 
-    while ((NamePosition < Name->Length / sizeof(WCHAR)) &&
-           (ExpressionPosition < Expression->Length / sizeof(WCHAR)))
+    /* Name parsing loop */
+    for (; !EndOfName; MatchingChars = BackTrackingPosition, NamePosition++)
     {
-        /* Basic check to test if chars are equal */
-        CompareChar = IgnoreCase ? UpcaseTable[Name->Buffer[NamePosition]] :
-                                   Name->Buffer[NamePosition];
-        if (Expression->Buffer[ExpressionPosition] == CompareChar)
-        {
-            NamePosition++;
-            ExpressionPosition++;
-        }
-        /* Check cases that eat one char */
-        else if (Expression->Buffer[ExpressionPosition] == L'?')
+        /* Reset positions */
+        OldBackTrackingPosition = BackTrackingPosition = 0;
+
+        if (NamePosition >= Name->Length / sizeof(WCHAR))
         {
-            NamePosition++;
-            ExpressionPosition++;
+            EndOfName = TRUE;
+            if (OldBackTracking[MatchingChars - 1] == Expression->Length * 2)
+                break;
         }
-        /* Test star */
-        else if (Expression->Buffer[ExpressionPosition] == L'*')
+
+        while (MatchingChars > OldBackTrackingPosition)
         {
-            /* Skip contigous stars */
-            while ((ExpressionPosition + 1 < (USHORT)(Expression->Length / sizeof(WCHAR))) &&
-                   (Expression->Buffer[ExpressionPosition + 1] == L'*'))
-            {
-                ExpressionPosition++;
-            }
+            ExpressionPosition = (OldBackTracking[OldBackTrackingPosition++] + 1) / 2;
 
-            /* Save star position */
-            StarFound++;
-            if (StarFound >= BackTrackingSize)
+            /* Expression parsing loop */
+            for (Offset = 0; ExpressionPosition < Expression->Length; Offset = sizeof(WCHAR))
             {
-                ASSERT(BackTracking == BackTrackingBuffer);
-
-                BackTrackingSize = Expression->Length / sizeof(WCHAR);
-                BackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,
-                                                     BackTrackingSize * sizeof(USHORT),
-                                                     'nrSF');
-                RtlCopyMemory(BackTracking, BackTrackingBuffer, sizeof(BackTrackingBuffer));
-
-            }
-            BackTracking[StarFound] = ExpressionPosition++;
+                ExpressionPosition += Offset;
 
-            /* If star is at the end, then eat all rest and leave */
-            if (ExpressionPosition == Expression->Length / sizeof(WCHAR))
-            {
-                NamePosition = Name->Length / sizeof(WCHAR);
-                break;
-            }
+                if (ExpressionPosition == Expression->Length)
+                {
+                    BackTracking[BackTrackingPosition++] = Expression->Length * 2;
+                    break;
+                }
 
-            /* Allow null matching */
-            if (Expression->Buffer[ExpressionPosition] != L'?' &&
-                     Expression->Buffer[ExpressionPosition] != Name->Buffer[NamePosition])
-            {
-                NamePosition++;
-            }
-        }
-        /* Check DOS_STAR */
-        else if (Expression->Buffer[ExpressionPosition] == DOS_STAR)
-        {
-            /* Skip contigous stars */
-            while ((ExpressionPosition + 1 < (USHORT)(Expression->Length / sizeof(WCHAR))) &&
-                   (Expression->Buffer[ExpressionPosition + 1] == DOS_STAR))
-            {
-                ExpressionPosition++;
-            }
+                /* If buffer too small */
+                if (BackTrackingPosition > RTL_NUMBER_OF(BackTrackingBuffer) - 1)
+                {
+                    /* Allocate memory for BackTracking */
+                    BackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,
+                                                         (Expression->Length + sizeof(WCHAR)) * sizeof(USHORT),
+                                                         'nrSF');
+                    /* Copy old buffer content */
+                    RtlCopyMemory(BackTracking,
+                                  BackTrackingBuffer,
+                                  RTL_NUMBER_OF(BackTrackingBuffer) * sizeof(USHORT));
+
+                    /* Allocate memory for OldBackTracking */
+                    OldBackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,
+                                                            (Expression->Length + sizeof(WCHAR)) * sizeof(USHORT),
+                                                            'nrSF');
+                    /* Copy old buffer content */
+                    RtlCopyMemory(OldBackTracking,
+                                  OldBackTrackingBuffer,
+                                  RTL_NUMBER_OF(OldBackTrackingBuffer) * sizeof(USHORT));
+                }
 
-            /* Look for last dot */
-            MatchingChars = 0;
-            LastDot = (USHORT)-1;
-            while (MatchingChars < Name->Length / sizeof(WCHAR))
-            {
-                if (Name->Buffer[MatchingChars] == L'.')
+                /* Basic check to test if chars are equal */
+                CompareChar = IgnoreCase ? UpcaseTable[Name->Buffer[NamePosition]] :
+                                           Name->Buffer[NamePosition];
+                if (Expression->Buffer[ExpressionPosition / sizeof(WCHAR)] == CompareChar && !EndOfName)
+                {
+                    BackTracking[BackTrackingPosition++] = (ExpressionPosition + sizeof(WCHAR)) * 2;
+                }
+                /* Check cases that eat one char */
+                else if (Expression->Buffer[ExpressionPosition / sizeof(WCHAR)] == L'?' && !EndOfName)
+                {
+                    BackTracking[BackTrackingPosition++] = (ExpressionPosition + sizeof(WCHAR)) * 2;
+                }
+                /* Test star */
+                else if (Expression->Buffer[ExpressionPosition / sizeof(WCHAR)] == L'*')
                 {
-                    LastDot = MatchingChars;
-                    if (LastDot > NamePosition)
-                        break;
+                    BackTracking[BackTrackingPosition++] = ExpressionPosition * 2;
+                    BackTracking[BackTrackingPosition++] = (ExpressionPosition * 2) + 3;
+                    continue;
                 }
+                /* Check DOS_STAR */
+                else if (Expression->Buffer[ExpressionPosition / sizeof(WCHAR)] == DOS_STAR)
+                {
+                    /* Look for last dot */
+                    DontSkipDot = TRUE;
+                    if (!EndOfName && Name->Buffer[NamePosition] == '.')
+                    {
+                        for (Position = NamePosition - 1; Position < Name->Length; Position++)
+                        {
+                            if (Name->Buffer[Position] == L'.')
+                            {
+                                DontSkipDot = FALSE;
+                                break;
+                            }
+                        }
+                    }
 
-                MatchingChars++;
-            }
+                    if (EndOfName || Name->Buffer[NamePosition] != L'.' || !DontSkipDot)
+                        BackTracking[BackTrackingPosition++] = ExpressionPosition * 2;
 
-            /* If we don't have dots or we didn't find last yet
-             * start eating everything
-             */
-            if (MatchingChars != Name->Length || LastDot == (USHORT)-1)
-            {
-                DosStarFound++;
-                if (DosStarFound >= DosBackTrackingSize)
+                    BackTracking[BackTrackingPosition++] = (ExpressionPosition * 2) + 3;
+                    continue;
+                }
+                /* Check DOS_DOT */
+                else if (Expression->Buffer[ExpressionPosition / sizeof(WCHAR)] == DOS_DOT)
                 {
-                    ASSERT(DosBackTracking == DosBackTrackingBuffer);
+                    if (EndOfName) continue;
 
-                    DosBackTrackingSize = Expression->Length / sizeof(WCHAR);
-                    DosBackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,
-                                                            DosBackTrackingSize * sizeof(USHORT),
-                                                            'nrSF');
-                    RtlCopyMemory(DosBackTracking, DosBackTrackingBuffer, sizeof(DosBackTrackingBuffer));
+                    if (Name->Buffer[NamePosition] == L'.')
+                        BackTracking[BackTrackingPosition++] = (ExpressionPosition + sizeof(WCHAR)) * 2;
                 }
-                DosBackTracking[DosStarFound] = ExpressionPosition++;
+                /* Check DOS_QM */
+                else if (Expression->Buffer[ExpressionPosition / sizeof(WCHAR)] == DOS_QM)
+                {
+                    if (EndOfName || Name->Buffer[NamePosition] == L'.') continue;
 
-                /* Not the same char, start exploring */
-                if (Expression->Buffer[ExpressionPosition] != Name->Buffer[NamePosition])
-                    NamePosition++;
-            }
-            else
-            {
-                /* Else, if we are at last dot, eat it - otherwise, null match */
-                if (Name->Buffer[NamePosition] == '.')
-                    NamePosition++;
+                    BackTracking[BackTrackingPosition++] = (ExpressionPosition + sizeof(WCHAR)) * 2;
+                }
 
-                 ExpressionPosition++;
-            }
-        }
-        /* Check DOS_DOT */
-        else if (Expression->Buffer[ExpressionPosition] == DOS_DOT)
-        {
-            /* We only match dots */
-            if (Name->Buffer[NamePosition] == L'.')
-            {
-                NamePosition++;
-            }
-            /* Try to explore later on for null matching */
-            else if ((ExpressionPosition + 1 < (USHORT)(Expression->Length / sizeof(WCHAR))) &&
-                     (Name->Buffer[NamePosition] == Expression->Buffer[ExpressionPosition + 1]))
-            {
-                NamePosition++;
-            }
-            ExpressionPosition++;
-        }
-        /* Check DOS_QM */
-        else if (Expression->Buffer[ExpressionPosition] == DOS_QM)
-        {
-            /* We match everything except dots */
-            if (Name->Buffer[NamePosition] != L'.')
-            {
-                NamePosition++;
+                /* Leave from loop */
+                break;
             }
-            ExpressionPosition++;
-        }
-        /* If nothing match, try to backtrack */
-        else if (StarFound >= 0)
-        {
-            ExpressionPosition = BackTracking[StarFound--];
-        }
-        else if (DosStarFound >= 0)
-        {
-            ExpressionPosition = DosBackTracking[DosStarFound--];
-        }
-        /* Otherwise, fail */
-        else
-        {
-            break;
-        }
 
-        /* Under certain circumstances, expression is over, but name isn't
-         * and we can backtrack, then, backtrack */
-        if (ExpressionPosition == Expression->Length / sizeof(WCHAR) &&
-            NamePosition != Name->Length / sizeof(WCHAR) &&
-            StarFound >= 0)
-        {
-            ExpressionPosition = BackTracking[StarFound--];
-        }
-    }
-    /* If we have nullable matching wc at the end of the string, eat them */
-    if (ExpressionPosition != Expression->Length / sizeof(WCHAR) && NamePosition == Name->Length / sizeof(WCHAR))
-    {
-        while (ExpressionPosition < Expression->Length / sizeof(WCHAR))
-        {
-            if (Expression->Buffer[ExpressionPosition] != DOS_DOT &&
-                Expression->Buffer[ExpressionPosition] != L'*' &&
-                Expression->Buffer[ExpressionPosition] != DOS_STAR)
+            for (Position = 0; MatchingChars > OldBackTrackingPosition && Position < BackTrackingPosition; Position++)
             {
-                break;
+                while (MatchingChars > OldBackTrackingPosition &&
+                       BackTracking[Position] > OldBackTracking[OldBackTrackingPosition])
+                {
+                    ++OldBackTrackingPosition;
+                }
             }
-            ExpressionPosition++;
         }
+
+        /* Swap pointers */
+        BackTrackingSwap = BackTracking;
+        BackTracking = OldBackTracking;
+        OldBackTracking = BackTrackingSwap;
     }
 
-    if (BackTracking != BackTrackingBuffer)
-    {
+    /* Store result value */
+    Result = (OldBackTracking[MatchingChars - 1] == (Expression->Length * 2));
+
+    /* Frees the memory if necessary */
+    if (BackTracking != BackTrackingBuffer && BackTracking != OldBackTrackingBuffer)
         ExFreePoolWithTag(BackTracking, 'nrSF');
-    }
-    if (DosBackTracking != DosBackTrackingBuffer)
-    {
-        ExFreePoolWithTag(DosBackTracking, 'nrSF');
-    }
+    if (OldBackTracking != BackTrackingBuffer && OldBackTracking != OldBackTrackingBuffer)
+        ExFreePoolWithTag(OldBackTracking, 'nrSF');
 
-    return (ExpressionPosition == Expression->Length / sizeof(WCHAR) && NamePosition == Name->Length / sizeof(WCHAR));
+    return Result;
 }
 
 /* PUBLIC FUNCTIONS **********************************************************/