From f5465755dc1607c45ac2f2c9ca03dccb9e7903df Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Mon, 26 Sep 2011 05:58:13 +0000 Subject: [PATCH] [NTOSKRNL] Fix FsRtlIs*InExpression() by (finally) implementing backtracking. No regressions noticed regarding kmtest. Also commented code. svn path=/trunk/; revision=53859 --- reactos/ntoskrnl/fsrtl/dbcsname.c | 87 ++++++++++----------------- reactos/ntoskrnl/fsrtl/name.c | 97 +++++++++++++------------------ 2 files changed, 71 insertions(+), 113 deletions(-) diff --git a/reactos/ntoskrnl/fsrtl/dbcsname.c b/reactos/ntoskrnl/fsrtl/dbcsname.c index 2bf4af91b37..80e9d8e8264 100644 --- a/reactos/ntoskrnl/fsrtl/dbcsname.c +++ b/reactos/ntoskrnl/fsrtl/dbcsname.c @@ -160,7 +160,9 @@ NTAPI FsRtlIsDbcsInExpression(IN PANSI_STRING Expression, IN PANSI_STRING Name) { - USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars, StarFound = MAXUSHORT; + SHORT StarFound = -1; + PUSHORT BackTracking = NULL; + USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars; PAGED_CODE(); ASSERT(Name->Length); @@ -169,74 +171,44 @@ FsRtlIsDbcsInExpression(IN PANSI_STRING Expression, while (NamePosition < Name->Length && ExpressionPosition < Expression->Length) { + /* Basic check to test if chars are equal */ if ((Expression->Buffer[ExpressionPosition] == Name->Buffer[NamePosition])) { NamePosition++; ExpressionPosition++; } - else if (StarFound != MAXUSHORT && (Expression->Buffer[StarFound + 1] == '*' || - Expression->Buffer[StarFound + 1] == '?' || Expression->Buffer[StarFound + 1] == ANSI_DOS_DOT)) - { - ExpressionPosition = StarFound + 1; - switch (Expression->Buffer[ExpressionPosition]) - { - case '*': - StarFound = MAXUSHORT; - break; - - case '?': - if (++ExpressionPosition == Expression->Length) - { - NamePosition = Name->Length; - break; - } - - MatchingChars = NamePosition; - while (NamePosition < Name->Length && - Name->Buffer[NamePosition] != Expression->Buffer[ExpressionPosition]) - { - NamePosition++; - } - - if (NamePosition - MatchingChars > 0) - { - StarFound = MAXUSHORT; - } - break; - - case ANSI_DOS_DOT: - while (NamePosition < Name->Length && Name->Buffer[NamePosition] != '.') - { - NamePosition++; - } - ExpressionPosition++; - StarFound = MAXUSHORT; - break; - - default: - /* Should never happen */ - ASSERT(FALSE); - } - } + /* Check cases that eat one char */ else if ((Expression->Buffer[ExpressionPosition] == '?') || (Expression->Buffer[ExpressionPosition] == ANSI_DOS_QM) || (Expression->Buffer[ExpressionPosition] == ANSI_DOS_DOT && Name->Buffer[NamePosition] == '.')) { NamePosition++; ExpressionPosition++; - StarFound = MAXUSHORT; } + /* Test star */ else if (Expression->Buffer[ExpressionPosition] == '*') { - StarFound = ExpressionPosition++; + /* Save star position */ + if (!BackTracking) + { + BackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, + Expression->Length * sizeof(USHORT), 'nrSF'); + } + BackTracking[++StarFound] = ExpressionPosition++; + + /* If star is at the end, then eat all rest and leave */ if (ExpressionPosition == Expression->Length) { NamePosition = Name->Length; break; } + else if (Expression->Buffer[ExpressionPosition] != '?') + { + NamePosition++; + } } + /* Check DOS_STAR */ else if (Expression->Buffer[ExpressionPosition] == ANSI_DOS_STAR) { - StarFound = MAXUSHORT; MatchingChars = NamePosition; while (MatchingChars < Name->Length) { @@ -248,19 +220,24 @@ FsRtlIsDbcsInExpression(IN PANSI_STRING Expression, } ExpressionPosition++; } - else if (StarFound != MAXUSHORT) + /* If nothing match, try to backtrack */ + else if (StarFound >= 0) { - ExpressionPosition = StarFound + 1; - while (NamePosition < Name->Length && - Name->Buffer[NamePosition] != Expression->Buffer[ExpressionPosition]) - { - NamePosition++; - } + ExpressionPosition = BackTracking[StarFound--]; } + /* Otherwise, fail */ else { break; } + + /* Under certain circumstances, expression is over, but name isn't + * and we can backtrack, then, backtrack */ + if (ExpressionPosition == Expression->Length && + NamePosition != Name->Length && StarFound >= 0) + { + ExpressionPosition = BackTracking[StarFound--]; + } } if (ExpressionPosition + 1 == Expression->Length && NamePosition == Name->Length && Expression->Buffer[ExpressionPosition] == ANSI_DOS_DOT) diff --git a/reactos/ntoskrnl/fsrtl/name.c b/reactos/ntoskrnl/fsrtl/name.c index 4cd096038db..86acc261a72 100644 --- a/reactos/ntoskrnl/fsrtl/name.c +++ b/reactos/ntoskrnl/fsrtl/name.c @@ -23,8 +23,10 @@ FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression, IN BOOLEAN IgnoreCase, IN PWCHAR UpcaseTable OPTIONAL) { - USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars, StarFound = MAXUSHORT; + SHORT StarFound = -1; + PUSHORT BackTracking = NULL; UNICODE_STRING IntExpression; + USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars; PAGED_CODE(); /* Check if we were given strings at all */ @@ -99,76 +101,45 @@ FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression, while (NamePosition < Name->Length / sizeof(WCHAR) && ExpressionPosition < Expression->Length / sizeof(WCHAR)) { + /* Basic check to test if chars are equal */ 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); - } - } + /* Check cases that eat one char */ else if (Expression->Buffer[ExpressionPosition] == L'?' || (Expression->Buffer[ExpressionPosition] == DOS_QM) || (Expression->Buffer[ExpressionPosition] == DOS_DOT && Name->Buffer[NamePosition] == L'.')) { NamePosition++; ExpressionPosition++; - StarFound = MAXUSHORT; } + /* Test star */ else if (Expression->Buffer[ExpressionPosition] == L'*') { - StarFound = ExpressionPosition++; + /* Save star position */ + if (!BackTracking) + { + BackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, + (Expression->Length / sizeof(WCHAR)) * sizeof(USHORT), + 'nrSF'); + } + BackTracking[++StarFound] = ExpressionPosition++; + + /* If star is at the end, then eat all rest and leave */ if (ExpressionPosition == Expression->Length / sizeof(WCHAR)) { NamePosition = Name->Length / sizeof(WCHAR); break; } + else if (Expression->Buffer[ExpressionPosition] != L'?') + { + NamePosition++; + } } + /* Check DOS_STAR */ else if (Expression->Buffer[ExpressionPosition] == DOS_STAR) { - StarFound = MAXUSHORT; MatchingChars = NamePosition; while (MatchingChars < Name->Length / sizeof(WCHAR)) { @@ -180,20 +151,25 @@ FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression, } ExpressionPosition++; } - else if (StarFound != MAXUSHORT) + /* If nothing match, try to backtrack */ + else if (StarFound >= 0) { - ExpressionPosition = StarFound + 1; - while (NamePosition < Name->Length / sizeof(WCHAR) && - (IgnoreCase ? UpcaseTable[Name->Buffer[NamePosition]] : - Name->Buffer[NamePosition]) != Expression->Buffer[ExpressionPosition]) - { - NamePosition++; - } + ExpressionPosition = BackTracking[StarFound--]; } + /* 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 (ExpressionPosition + 1 == Expression->Length / sizeof(WCHAR) && NamePosition == Name->Length / sizeof(WCHAR) && Expression->Buffer[ExpressionPosition] == DOS_DOT) @@ -201,6 +177,11 @@ FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression, ExpressionPosition++; } + if (BackTracking) + { + ExFreePoolWithTag(BackTracking, 'nrSF'); + } + return (ExpressionPosition == Expression->Length / sizeof(WCHAR) && NamePosition == Name->Length / sizeof(WCHAR)); }