[NTOSKNRL]
[reactos.git] / reactos / ntoskrnl / fsrtl / name.c
index 2693906..8ed32a3 100644 (file)
-/*\r
- * PROJECT:         ReactOS Kernel\r
- * LICENSE:         GPL - See COPYING in the top level directory\r
- * FILE:            ntoskrnl/fsrtl/name.c\r
- * PURPOSE:         Provides name parsing and other support routines for FSDs\r
- * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)\r
- *                  Filip Navara (navaraf@reactos.org)\r
- */\r
-\r
-/* INCLUDES ******************************************************************/\r
-\r
-#include <ntoskrnl.h>\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/* PUBLIC FUNCTIONS **********************************************************/\r
-\r
-/*++\r
- * @name FsRtlAreNamesEqual\r
- * @implemented\r
- *\r
- * FILLME\r
- *\r
- * @param Name1\r
- *        FILLME\r
- *\r
- * @param Name2\r
- *        FILLME\r
- *\r
- * @param IgnoreCase\r
- *        FILLME\r
- *\r
- * @param UpcaseTable\r
- *        FILLME\r
- *\r
- * @return None\r
- *\r
- * @remarks From Bo Branten's ntifs.h v25.\r
- *\r
- *--*/\r
-BOOLEAN\r
-NTAPI\r
-FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1,\r
-                   IN PCUNICODE_STRING Name2,\r
-                   IN BOOLEAN IgnoreCase,\r
-                   IN PCWCH UpcaseTable OPTIONAL)\r
-{\r
-    UNICODE_STRING UpcaseName1;\r
-    UNICODE_STRING UpcaseName2;\r
-    BOOLEAN StringsAreEqual, MemoryAllocated = FALSE;\r
-    ULONG i;\r
-    NTSTATUS Status;\r
-\r
-    /* Well, first check their size */\r
-    if (Name1->Length != Name2->Length) return FALSE;\r
-\r
-    /* Check if the caller didn't give an upcase table */\r
-    if ((IgnoreCase) && !(UpcaseTable))\r
-    {\r
-        /* Upcase the string ourselves */\r
-        Status = RtlUpcaseUnicodeString(&UpcaseName1, Name1, TRUE);\r
-        if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);\r
-\r
-        /* Upcase the second string too */\r
-        RtlUpcaseUnicodeString(&UpcaseName2, Name2, TRUE);\r
-        Name1 = &UpcaseName1;\r
-        Name2 = &UpcaseName2;\r
-\r
-        /* Make sure we go through the path below, but free the strings */\r
-        IgnoreCase = FALSE;\r
-        MemoryAllocated = TRUE;\r
-    }\r
-\r
-    /* Do a case-sensitive search */\r
-    if (!IgnoreCase)\r
-    {\r
-        /* Use a raw memory compare */\r
-        StringsAreEqual = RtlEqualMemory(Name1->Buffer,\r
-                                         Name2->Buffer,\r
-                                         Name1->Length);\r
-\r
-        /* Check if we allocated strings */\r
-        if (MemoryAllocated)\r
-        {\r
-            /* Free them */\r
-            RtlFreeUnicodeString(&UpcaseName1);\r
-            RtlFreeUnicodeString(&UpcaseName2);\r
-        }\r
-\r
-        /* Return the equality */\r
-        return StringsAreEqual;\r
-    }\r
-    else\r
-    {\r
-        /* Case in-sensitive search */\r
-        for (i = 0; i < Name1->Length / sizeof(WCHAR); i++)\r
-        {\r
-            /* Check if the character matches */\r
-            if (UpcaseTable[Name1->Buffer[i]] != UpcaseTable[Name2->Buffer[i]])\r
-            {\r
-                /* Non-match found! */\r
-                return FALSE;\r
-            }\r
-        }\r
-\r
-        /* We finished the loop so we are equal */\r
-        return TRUE;\r
-    }\r
-}\r
-\r
-/*++\r
- * @name FsRtlDissectName\r
- * @implemented\r
- *\r
- * Dissects a given path name into first and remaining part.\r
- *\r
- * @param Name\r
- *        Unicode string to dissect.\r
- *\r
- * @param FirstPart\r
- *        Pointer to user supplied UNICODE_STRING, that will later point\r
- *        to the first part of the original name.\r
- *\r
- * @param RemainingPart\r
- *        Pointer to user supplied UNICODE_STRING, that will later point\r
- *        to the remaining part of the original name.\r
- *\r
- * @return None\r
- *\r
- * @remarks Example:\r
- *          Name:           \test1\test2\test3\r
- *          FirstPart:      test1\r
- *          RemainingPart:  test2\test3\r
- *\r
- *--*/\r
-VOID\r
-NTAPI\r
-FsRtlDissectName(IN UNICODE_STRING Name,\r
-                 OUT PUNICODE_STRING FirstPart,\r
-                 OUT PUNICODE_STRING RemainingPart)\r
-{\r
-    ULONG FirstPosition, i;\r
-    ULONG SkipFirstSlash = 0;\r
-\r
-    /* Zero the strings before continuing */\r
-    RtlZeroMemory(FirstPart, sizeof(UNICODE_STRING));\r
-    RtlZeroMemory(RemainingPart, sizeof(UNICODE_STRING));\r
-\r
-    /* Just quit if the string is empty */\r
-    if (!Name.Length) return;\r
-\r
-    /* Find first backslash */\r
-    FirstPosition = Name.Length / sizeof(WCHAR) ;\r
-    for (i = 0; i < Name.Length / sizeof(WCHAR); i++)\r
-    {\r
-        /* If we found one... */\r
-        if (Name.Buffer[i] == L'\\')\r
-        {\r
-            /* If it begins string, just notice it and continue */\r
-            if (i == 0)\r
-            {\r
-                SkipFirstSlash = 1;\r
-            }\r
-            else\r
-            {\r
-                /* Else, save its position and break out of the loop */\r
-                FirstPosition = i;\r
-                break;\r
-            }\r
-        }\r
-    }\r
-\r
-    /* Set up the first result string */\r
-    FirstPart->Buffer = Name.Buffer + SkipFirstSlash;\r
-    FirstPart->Length = (FirstPosition - SkipFirstSlash) * sizeof(WCHAR);\r
-    FirstPart->MaximumLength = FirstPart->Length;\r
-\r
-    /* And second one, if necessary */\r
-    if (FirstPosition < (Name.Length / sizeof(WCHAR)))\r
-    {\r
-        RemainingPart->Buffer = Name.Buffer + FirstPosition + 1;\r
-        RemainingPart->Length = Name.Length - (FirstPosition + 1) * sizeof(WCHAR);\r
-        RemainingPart->MaximumLength = RemainingPart->Length;\r
-    }\r
-}\r
-\r
-/*++\r
- * @name FsRtlDoesNameContainWildCards\r
- * @implemented\r
- *\r
- * FILLME\r
- *\r
- * @param Name\r
- *        Pointer to a UNICODE_STRING containing Name to examine\r
- *\r
- * @return TRUE if Name contains wildcards, FALSE otherwise\r
- *\r
- * @remarks From Bo Branten's ntifs.h v12.\r
- *\r
- *--*/\r
-BOOLEAN\r
-NTAPI\r
-FsRtlDoesNameContainWildCards(IN PUNICODE_STRING Name)\r
-{\r
-    PWCHAR Ptr;\r
-\r
-    /* Loop through every character */\r
-    if (Name->Length)\r
-    {\r
-        Ptr = Name->Buffer + (Name->Length / sizeof(WCHAR)) - 1;\r
-        while ((Ptr >= Name->Buffer) && (*Ptr != L'\\'))\r
-        {\r
-            /* Check for Wildcard */\r
-            if (FsRtlIsUnicodeCharacterWild(*Ptr)) return TRUE;\r
-            Ptr--;\r
-        }\r
-    }\r
-\r
-    /* Nothing Found */\r
-    return FALSE;\r
-}\r
-\r
-/*++\r
- * @name FsRtlIsNameInExpression\r
- * @implemented\r
- *\r
- * FILLME\r
- *\r
- * @param DeviceObject\r
- *        FILLME\r
- *\r
- * @param Irp\r
- *        FILLME\r
- *\r
- * @return TRUE if Name is in Expression, FALSE otherwise\r
- *\r
- * @remarks From Bo Branten's ntifs.h v12. This function should be\r
- *          rewritten to avoid recursion and better wildcard handling\r
- *          should be implemented (see FsRtlDoesNameContainWildCards).\r
- *\r
- *--*/\r
-BOOLEAN\r
-NTAPI\r
-FsRtlIsNameInExpression(IN PUNICODE_STRING Expression,\r
-                        IN PUNICODE_STRING Name,\r
-                        IN BOOLEAN IgnoreCase,\r
-                        IN PWCHAR UpcaseTable OPTIONAL)\r
-{\r
-    USHORT ExpressionPosition, NamePosition;\r
-    UNICODE_STRING TempExpression, TempName;\r
-\r
-    ExpressionPosition = 0;\r
-    NamePosition = 0;\r
-    while (ExpressionPosition < (Expression->Length / sizeof(WCHAR)) &&\r
-        NamePosition < (Name->Length / sizeof(WCHAR)))\r
-    {\r
-        if (Expression->Buffer[ExpressionPosition] == L'*')\r
-        {\r
-            ExpressionPosition++;\r
-            if (ExpressionPosition == (Expression->Length / sizeof(WCHAR)))\r
-            {\r
-                return TRUE;\r
-            }\r
-            while (NamePosition < (Name->Length / sizeof(WCHAR)))\r
-            {\r
-                TempExpression.Length =\r
-                    TempExpression.MaximumLength =\r
-                    Expression->Length - (ExpressionPosition * sizeof(WCHAR));\r
-                TempExpression.Buffer = Expression->Buffer + ExpressionPosition;\r
-                TempName.Length =\r
-                    TempName.MaximumLength =\r
-                    Name->Length - (NamePosition * sizeof(WCHAR));\r
-                TempName.Buffer = Name->Buffer + NamePosition;\r
-                /* FIXME: Rewrite to get rid of recursion */\r
-                if (FsRtlIsNameInExpression(&TempExpression, &TempName,\r
-                    IgnoreCase, UpcaseTable))\r
-                {\r
-                    return TRUE;\r
-                }\r
-                NamePosition++;\r
-            }\r
-        }\r
-        else\r
-        {\r
-            /* FIXME: Take UpcaseTable into account! */\r
-            if (Expression->Buffer[ExpressionPosition] == L'?' ||\r
-                (IgnoreCase &&\r
-                RtlUpcaseUnicodeChar(Expression->Buffer[ExpressionPosition]) ==\r
-                RtlUpcaseUnicodeChar(Name->Buffer[NamePosition])) ||\r
-                (!IgnoreCase &&\r
-                Expression->Buffer[ExpressionPosition] ==\r
-                Name->Buffer[NamePosition]))\r
-            {\r
-                NamePosition++;\r
-                ExpressionPosition++;\r
-            }\r
-            else\r
-            {\r
-                return FALSE;\r
-            }\r
-        }\r
-    }\r
-\r
-    /* Handle matching of "f0_*.*" expression to "f0_000" file name. */\r
-    if (ExpressionPosition < (Expression->Length / sizeof(WCHAR)) &&\r
-        Expression->Buffer[ExpressionPosition] == L'.')\r
-    {\r
-        while (ExpressionPosition < (Expression->Length / sizeof(WCHAR)) &&\r
-            (Expression->Buffer[ExpressionPosition] == L'.' ||\r
-            Expression->Buffer[ExpressionPosition] == L'*' ||\r
-            Expression->Buffer[ExpressionPosition] == L'?'))\r
-        {\r
-            ExpressionPosition++;\r
-        }\r
-    }\r
-\r
-    if (ExpressionPosition == (Expression->Length / sizeof(WCHAR)) &&\r
-        NamePosition == (Name->Length / sizeof(WCHAR)))\r
-    {\r
-        return TRUE;\r
-    }\r
-\r
-    return FALSE;\r
-}\r
-\r
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            ntoskrnl/fsrtl/name.c
+ * PURPOSE:         Provides name parsing and other support routines for FSDs
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Filip Navara (navaraf@reactos.org)
+ *                  Pierre Schweitzer (pierre.schweitzer@reactos.org) 
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* PRIVATE FUNCTIONS *********************************************************/
+BOOLEAN
+NTAPI
+FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression,
+                               IN PUNICODE_STRING Name,
+                               IN BOOLEAN IgnoreCase,
+                               IN PWCHAR UpcaseTable OPTIONAL)
+{
+    USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars, StarFound = MAXUSHORT;
+    PAGED_CODE();
+
+    ASSERT(!IgnoreCase || UpcaseTable);
+
+    while (NamePosition < Name->Length / sizeof(WCHAR) && ExpressionPosition < Expression->Length / sizeof(WCHAR))
+    {
+        if ((Expression->Buffer[ExpressionPosition] == (IgnoreCase ? UpcaseTable[Name->Buffer[NamePosition]] : Name->Buffer[NamePosition])))
+        {
+            NamePosition++;
+            ExpressionPosition++;
+        }
+        else if (StarFound != MAXUSHORT && (Expression->Buffer[StarFound + 1] == L'*' ||
+                 Expression->Buffer[StarFound + 1] == L'?' || Expression->Buffer[StarFound + 1] == DOS_DOT))
+        {
+            ExpressionPosition = StarFound + 1;
+            switch (Expression->Buffer[ExpressionPosition])
+            {
+                case L'*':
+                    StarFound = MAXUSHORT;
+                    break;
+
+                case L'?':
+                    if (++ExpressionPosition == Expression->Length / sizeof(WCHAR))
+                    {
+                        NamePosition = Name->Length / sizeof(WCHAR);
+                        break;
+                    }
+
+                    MatchingChars = NamePosition;
+                    while (NamePosition < Name->Length / sizeof(WCHAR) &&
+                           (IgnoreCase ? UpcaseTable[Name->Buffer[NamePosition]] :
+                                         Name->Buffer[NamePosition]) != Expression->Buffer[ExpressionPosition])
+                    {
+                        NamePosition++;
+                    }
+
+                    if (NamePosition - MatchingChars > 0)
+                    {
+                        StarFound = MAXUSHORT;
+                    }
+                    break;
+
+                case DOS_DOT:
+                    while (NamePosition < Name->Length / sizeof(WCHAR) &&
+                           Name->Buffer[NamePosition] != L'.')
+                    {
+                        NamePosition++;
+                    }
+                    ExpressionPosition++;
+                    StarFound = MAXUSHORT;
+                    break;
+
+                default:
+                    /* Should never happen */
+                    ASSERT(FALSE);                   
+            }
+        }
+        else if (Expression->Buffer[ExpressionPosition] == L'?' || (Expression->Buffer[ExpressionPosition] == DOS_QM) ||
+                 (Expression->Buffer[ExpressionPosition] == DOS_DOT && Name->Buffer[NamePosition] == L'.'))
+        {
+            NamePosition++;
+            ExpressionPosition++;
+            StarFound = MAXUSHORT;
+        }
+        else if (Expression->Buffer[ExpressionPosition] == L'*')
+        {
+            StarFound = ExpressionPosition++;
+            if (ExpressionPosition == Expression->Length / sizeof(WCHAR))
+            {
+                NamePosition = Name->Length / sizeof(WCHAR);
+                break;
+            }
+        }
+        else if (Expression->Buffer[ExpressionPosition] == DOS_STAR)
+        {
+            StarFound = MAXUSHORT;
+            MatchingChars = NamePosition;
+            while (MatchingChars < Name->Length / sizeof(WCHAR))
+            {
+                if (Name->Buffer[MatchingChars] == L'.')
+                {
+                    NamePosition = MatchingChars;
+                }
+                MatchingChars++;
+            }
+            ExpressionPosition++;
+        }
+        else if (StarFound != MAXUSHORT)
+        {
+            ExpressionPosition = StarFound + 1;
+            while (NamePosition < Name->Length / sizeof(WCHAR) &&
+                   (IgnoreCase ? UpcaseTable[Name->Buffer[NamePosition]] :
+                    Name->Buffer[NamePosition]) != Expression->Buffer[ExpressionPosition])
+            {
+                NamePosition++;
+            }
+        }
+        else
+        {
+            break;
+        }
+    }
+    if (ExpressionPosition + 1 == Expression->Length / sizeof(WCHAR) && NamePosition == Name->Length / sizeof(WCHAR) &&
+        Expression->Buffer[ExpressionPosition] == DOS_DOT)
+    {
+        ExpressionPosition++;
+    }
+
+    return (ExpressionPosition == Expression->Length / sizeof(WCHAR) && NamePosition == Name->Length / sizeof(WCHAR));
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*++
+ * @name FsRtlAreNamesEqual
+ * @implemented
+ *
+ * Compare two strings to check if they match
+ *
+ * @param Name1
+ *        First unicode string to compare
+ *
+ * @param Name2
+ *        Second unicode string to compare
+ *
+ * @param IgnoreCase
+ *        If TRUE, Case will be ignored when comparing strings
+ *
+ * @param UpcaseTable
+ *        Table for upcase letters. If NULL is given, system one will be used
+ *
+ * @return TRUE if the strings are equal
+ *
+ * @remarks From Bo Branten's ntifs.h v25.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1,
+                   IN PCUNICODE_STRING Name2,
+                   IN BOOLEAN IgnoreCase,
+                   IN PCWCH UpcaseTable OPTIONAL)
+{
+    UNICODE_STRING UpcaseName1;
+    UNICODE_STRING UpcaseName2;
+    BOOLEAN StringsAreEqual, MemoryAllocated = FALSE;
+    USHORT i;
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Well, first check their size */
+    if (Name1->Length != Name2->Length) return FALSE;
+
+    /* Check if the caller didn't give an upcase table */
+    if ((IgnoreCase) && !(UpcaseTable))
+    {
+        /* Upcase the string ourselves */
+        Status = RtlUpcaseUnicodeString(&UpcaseName1, Name1, TRUE);
+        if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);
+
+        /* Upcase the second string too */
+        RtlUpcaseUnicodeString(&UpcaseName2, Name2, TRUE);
+        Name1 = &UpcaseName1;
+        Name2 = &UpcaseName2;
+
+        /* Make sure we go through the path below, but free the strings */
+        IgnoreCase = FALSE;
+        MemoryAllocated = TRUE;
+    }
+
+    /* Do a case-sensitive search */
+    if (!IgnoreCase)
+    {
+        /* Use a raw memory compare */
+        StringsAreEqual = RtlEqualMemory(Name1->Buffer,
+                                         Name2->Buffer,
+                                         Name1->Length);
+
+        /* Check if we allocated strings */
+        if (MemoryAllocated)
+        {
+            /* Free them */
+            RtlFreeUnicodeString(&UpcaseName1);
+            RtlFreeUnicodeString(&UpcaseName2);
+        }
+
+        /* Return the equality */
+        return StringsAreEqual;
+    }
+    else
+    {
+        /* Case in-sensitive search */
+        for (i = 0; i < Name1->Length / sizeof(WCHAR); i++)
+        {
+            /* Check if the character matches */
+            if (UpcaseTable[Name1->Buffer[i]] != UpcaseTable[Name2->Buffer[i]])
+            {
+                /* Non-match found! */
+                return FALSE;
+            }
+        }
+
+        /* We finished the loop so we are equal */
+        return TRUE;
+    }
+}
+
+/*++
+ * @name FsRtlDissectName
+ * @implemented
+ *
+ * Dissects a given path name into first and remaining part.
+ *
+ * @param Name
+ *        Unicode string to dissect.
+ *
+ * @param FirstPart
+ *        Pointer to user supplied UNICODE_STRING, that will later point
+ *        to the first part of the original name.
+ *
+ * @param RemainingPart
+ *        Pointer to user supplied UNICODE_STRING, that will later point
+ *        to the remaining part of the original name.
+ *
+ * @return None
+ *
+ * @remarks Example:
+ *          Name:           \test1\test2\test3
+ *          FirstPart:      test1
+ *          RemainingPart:  test2\test3
+ *
+ *--*/
+VOID
+NTAPI
+FsRtlDissectName(IN UNICODE_STRING Name,
+                 OUT PUNICODE_STRING FirstPart,
+                 OUT PUNICODE_STRING RemainingPart)
+{
+    USHORT FirstPosition, i;
+    USHORT SkipFirstSlash = 0;
+    PAGED_CODE();
+
+    /* Zero the strings before continuing */
+    RtlZeroMemory(FirstPart, sizeof(UNICODE_STRING));
+    RtlZeroMemory(RemainingPart, sizeof(UNICODE_STRING));
+
+    /* Just quit if the string is empty */
+    if (!Name.Length) return;
+
+    /* Find first backslash */
+    FirstPosition = Name.Length / sizeof(WCHAR) ;
+    for (i = 0; i < Name.Length / sizeof(WCHAR); i++)
+    {
+        /* If we found one... */
+        if (Name.Buffer[i] == L'\\')
+        {
+            /* If it begins string, just notice it and continue */
+            if (i == 0)
+            {
+                SkipFirstSlash = 1;
+            }
+            else
+            {
+                /* Else, save its position and break out of the loop */
+                FirstPosition = i;
+                break;
+            }
+        }
+    }
+
+    /* Set up the first result string */
+    FirstPart->Buffer = Name.Buffer + SkipFirstSlash;
+    FirstPart->Length = (FirstPosition - SkipFirstSlash) * sizeof(WCHAR);
+    FirstPart->MaximumLength = FirstPart->Length;
+
+    /* And second one, if necessary */
+    if (FirstPosition < (Name.Length / sizeof(WCHAR)))
+    {
+        RemainingPart->Buffer = Name.Buffer + FirstPosition + 1;
+        RemainingPart->Length = Name.Length - (FirstPosition + 1) * sizeof(WCHAR);
+        RemainingPart->MaximumLength = RemainingPart->Length;
+    }
+}
+
+/*++
+ * @name FsRtlDoesNameContainWildCards
+ * @implemented
+ *
+ * Checks if the given string contains WildCards
+ *
+ * @param Name
+ *        Pointer to a UNICODE_STRING containing Name to examine
+ *
+ * @return TRUE if Name contains wildcards, FALSE otherwise
+ *
+ * @remarks From Bo Branten's ntifs.h v12.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+FsRtlDoesNameContainWildCards(IN PUNICODE_STRING Name)
+{
+    PWCHAR Ptr;
+    PAGED_CODE();
+
+    /* Loop through every character */
+    if (Name->Length)
+    {
+        Ptr = Name->Buffer + (Name->Length / sizeof(WCHAR)) - 1;
+        while ((Ptr >= Name->Buffer) && (*Ptr != L'\\'))
+        {
+            /* Check for Wildcard */
+            if (FsRtlIsUnicodeCharacterWild(*Ptr)) return TRUE;
+            Ptr--;
+        }
+    }
+
+    /* Nothing Found */
+    return FALSE;
+}
+
+/*++
+ * @name FsRtlIsNameInExpression
+ * @implemented
+ *
+ * Check if the Name string is in the Expression string.
+ *
+ * @param Expression
+ *        The string in which we've to find Name. It can contain wildcards.
+ *        If IgnoreCase is set to TRUE, this string MUST BE uppercase. 
+ *
+ * @param Name
+ *        The string to find. It cannot contain wildcards
+ *
+ * @param IgnoreCase
+ *        If set to TRUE, case will be ignore with upcasing both strings
+ *
+ * @param UpcaseTable
+ *        If not NULL, and if IgnoreCase is set to TRUE, it will be used to
+ *        upcase the both strings 
+ *
+ * @return TRUE if Name is in Expression, FALSE otherwise
+ *
+ * @remarks From Bo Branten's ntifs.h v12. This function should be
+ *          rewritten to avoid recursion and better wildcard handling
+ *          should be implemented (see FsRtlDoesNameContainWildCards).
+ *
+ *--*/
+BOOLEAN
+NTAPI
+FsRtlIsNameInExpression(IN PUNICODE_STRING Expression,
+                        IN PUNICODE_STRING Name,
+                        IN BOOLEAN IgnoreCase,
+                        IN PWCHAR UpcaseTable OPTIONAL)
+{
+    BOOLEAN Result;
+    NTSTATUS Status;
+    UNICODE_STRING IntName;
+
+    if (IgnoreCase && !UpcaseTable)
+    {
+        Status = RtlUpcaseUnicodeString(&IntName, Name, TRUE);
+        if (Status != STATUS_SUCCESS)
+        {
+            ExRaiseStatus(Status);
+        }
+        Name = &IntName;
+        IgnoreCase = FALSE;
+    }
+    else
+    {
+        IntName.Buffer = NULL;
+    }
+
+    Result = FsRtlIsNameInExpressionPrivate(Expression, Name, IgnoreCase, UpcaseTable);
+
+    if (IntName.Buffer != NULL)
+    {
+        RtlFreeUnicodeString(&IntName);
+    }
+
+    return Result;
+}