[NTOS:FSRTL] Rework FsRtlIsDbcsInExpression for correct parsing some expressions

* Fixes 1 test for kmtest:FsRtlExpression

svn path=/trunk/; revision=72839
This commit is contained in:
Dmitry Chapyshev 2016-09-28 19:01:10 +00:00
parent 7d865c5974
commit d507b7555e
2 changed files with 163 additions and 148 deletions

View file

@ -160,9 +160,14 @@ NTAPI
FsRtlIsDbcsInExpression(IN PANSI_STRING Expression, FsRtlIsDbcsInExpression(IN PANSI_STRING Expression,
IN PANSI_STRING Name) IN PANSI_STRING Name)
{ {
SHORT StarFound = -1, DosStarFound = -1; USHORT Offset, Position, BackTrackingPosition, OldBackTrackingPosition;
PUSHORT BackTracking = NULL, DosBackTracking = NULL; USHORT BackTrackingBuffer[16], OldBackTrackingBuffer[16] = {0};
USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars, LastDot; PUSHORT BackTrackingSwap, BackTracking = BackTrackingBuffer, OldBackTracking = OldBackTrackingBuffer;
USHORT ExpressionPosition, NamePosition = 0, MatchingChars = 1;
USHORT NameChar = 0, ExpressionChar;
BOOLEAN EndOfName = FALSE;
BOOLEAN Result;
BOOLEAN DontSkipDot;
PAGED_CODE(); PAGED_CODE();
ASSERT(Name->Length); ASSERT(Name->Length);
@ -232,170 +237,180 @@ FsRtlIsDbcsInExpression(IN PANSI_STRING Expression,
} }
} }
while (NamePosition < Name->Length && ExpressionPosition < Expression->Length) /* Name parsing loop */
for (; !EndOfName; MatchingChars = BackTrackingPosition)
{ {
/* Basic check to test if chars are equal */ /* Reset positions */
if ((Expression->Buffer[ExpressionPosition] == Name->Buffer[NamePosition])) OldBackTrackingPosition = BackTrackingPosition = 0;
{
NamePosition++;
ExpressionPosition++;
}
/* Check cases that eat one char */
else if (Expression->Buffer[ExpressionPosition] == '?')
{
NamePosition++;
ExpressionPosition++;
}
/* Test star */
else if (Expression->Buffer[ExpressionPosition] == '*')
{
/* Skip contigous stars */
while (ExpressionPosition + 1 < Expression->Length && Expression->Buffer[ExpressionPosition + 1] == '*')
{
ExpressionPosition++;
}
/* Save star position */ if (NamePosition >= Name->Length)
if (!BackTracking) {
{ EndOfName = TRUE;
BackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, if (OldBackTracking[MatchingChars - 1] == Expression->Length * 2)
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; break;
}
/* Allow null matching */
else if (Expression->Buffer[ExpressionPosition] != '?' &&
Expression->Buffer[ExpressionPosition] != Name->Buffer[NamePosition])
{
NamePosition++;
}
} }
/* Check DOS_STAR */ else
else if (Expression->Buffer[ExpressionPosition] == ANSI_DOS_STAR)
{ {
/* Skip contigous stars */ /* If lead byte present */
while (ExpressionPosition + 1 < Expression->Length && Expression->Buffer[ExpressionPosition + 1] == ANSI_DOS_STAR) if (FsRtlIsLeadDbcsCharacter(Name->Buffer[NamePosition]))
{ {
ExpressionPosition++; NameChar = Name->Buffer[NamePosition] +
} (0x100 * Name->Buffer[NamePosition + 1]);
NamePosition += sizeof(USHORT);
/* Look for last dot */
MatchingChars = 0;
LastDot = (USHORT)-1;
while (MatchingChars < Name->Length)
{
if (Name->Buffer[MatchingChars] == '.')
{
LastDot = MatchingChars;
if (LastDot > NamePosition)
break;
}
MatchingChars++;
}
/* If we don't have dots or we didn't find last yet
* start eating everything
*/
if (MatchingChars != Name->Length || LastDot == (USHORT)-1)
{
if (!DosBackTracking) DosBackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,
Expression->Length * sizeof(USHORT), 'nrSF');
DosBackTracking[++DosStarFound] = ExpressionPosition++;
/* Not the same char, start exploring */
if (Expression->Buffer[ExpressionPosition] != Name->Buffer[NamePosition])
NamePosition++;
} }
else else
{ {
/* Else, if we are at last dot, eat it - otherwise, null match */ NameChar = Name->Buffer[NamePosition];
if (Name->Buffer[NamePosition] == '.') NamePosition += sizeof(UCHAR);
NamePosition++;
ExpressionPosition++;
} }
} }
/* Check DOS_DOT */
else if (Expression->Buffer[ExpressionPosition] == ANSI_DOS_DOT)
{
/* We only match dots */
if (Name->Buffer[NamePosition] == '.')
{
NamePosition++;
}
/* Try to explore later on for null matching */
else if (ExpressionPosition + 1 < Expression->Length &&
Name->Buffer[NamePosition] == Expression->Buffer[ExpressionPosition + 1])
{
NamePosition++;
}
ExpressionPosition++;
}
/* Check DOS_QM */
else if (Expression->Buffer[ExpressionPosition] == ANSI_DOS_QM)
{
/* We match everything except dots */
if (Name->Buffer[NamePosition] != '.')
{
NamePosition++;
}
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 while (MatchingChars > OldBackTrackingPosition)
* and we can backtrack, then, backtrack */
if (ExpressionPosition == Expression->Length &&
NamePosition != Name->Length && StarFound >= 0)
{ {
ExpressionPosition = BackTracking[StarFound--]; ExpressionPosition = (OldBackTracking[OldBackTrackingPosition++] + 1) / 2;
}
} /* Expression parsing loop */
/* If we have nullable matching wc at the end of the string, eat them */ for (Offset = 0; ExpressionPosition < Expression->Length; )
if (ExpressionPosition != Expression->Length && NamePosition == Name->Length)
{
while (ExpressionPosition < Expression->Length)
{
if (Expression->Buffer[ExpressionPosition] != ANSI_DOS_DOT &&
Expression->Buffer[ExpressionPosition] != '*' &&
Expression->Buffer[ExpressionPosition] != ANSI_DOS_STAR)
{ {
ExpressionPosition += Offset;
if (ExpressionPosition == Expression->Length)
{
BackTracking[BackTrackingPosition++] = Expression->Length * 2;
break;
}
/* 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 + 1) * sizeof(USHORT) * 2,
'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 + 1) * sizeof(USHORT) * 2,
'nrSF');
/* Copy old buffer content */
RtlCopyMemory(OldBackTracking,
OldBackTrackingBuffer,
RTL_NUMBER_OF(OldBackTrackingBuffer) * sizeof(USHORT));
}
/* If lead byte present */
if (FsRtlIsLeadDbcsCharacter(Expression->Buffer[ExpressionPosition]))
{
ExpressionChar = Expression->Buffer[ExpressionPosition] +
(0x100 * Expression->Buffer[ExpressionPosition + 1]);
Offset = sizeof(USHORT);
}
else
{
ExpressionChar = Expression->Buffer[ExpressionPosition];
Offset = sizeof(UCHAR);
}
/* Basic check to test if chars are equal */
if (ExpressionChar == NameChar && !EndOfName)
{
BackTracking[BackTrackingPosition++] = (ExpressionPosition + Offset) * 2;
}
/* Check cases that eat one char */
else if (ExpressionChar == '?' && !EndOfName)
{
BackTracking[BackTrackingPosition++] = (ExpressionPosition + Offset) * 2;
}
/* Test star */
else if (ExpressionChar == '*')
{
BackTracking[BackTrackingPosition++] = ExpressionPosition * 2;
BackTracking[BackTrackingPosition++] = (ExpressionPosition * 2) + 1;
continue;
}
/* Check DOS_STAR */
else if (ExpressionChar == ANSI_DOS_STAR)
{
/* Look for last dot */
DontSkipDot = TRUE;
if (!EndOfName && NameChar == '.')
{
for (Position = NamePosition; Position < Name->Length; )
{
/* If lead byte not present */
if (!FsRtlIsLeadDbcsCharacter(Name->Buffer[Position]))
{
if (Name->Buffer[Position] == '.')
{
DontSkipDot = FALSE;
break;
}
Position += sizeof(UCHAR);
}
else
{
Position += sizeof(USHORT);
}
}
}
if (EndOfName || NameChar != '.' || !DontSkipDot)
BackTracking[BackTrackingPosition++] = ExpressionPosition * 2;
BackTracking[BackTrackingPosition++] = (ExpressionPosition * 2) + 1;
continue;
}
/* Check DOS_DOT */
else if (ExpressionChar == DOS_DOT)
{
if (EndOfName) continue;
if (NameChar == '.')
BackTracking[BackTrackingPosition++] = (ExpressionPosition + Offset) * 2;
}
/* Check DOS_QM */
else if (ExpressionChar == ANSI_DOS_QM)
{
if (EndOfName || NameChar == '.') continue;
BackTracking[BackTrackingPosition++] = (ExpressionPosition + Offset) * 2;
}
/* Leave from loop */
break; break;
} }
ExpressionPosition++;
for (Position = 0; MatchingChars > OldBackTrackingPosition && Position < BackTrackingPosition; Position++)
{
while (MatchingChars > OldBackTrackingPosition &&
BackTracking[Position] > OldBackTracking[OldBackTrackingPosition])
{
++OldBackTrackingPosition;
}
}
} }
/* Swap pointers */
BackTrackingSwap = BackTracking;
BackTracking = OldBackTracking;
OldBackTracking = BackTrackingSwap;
} }
if (BackTracking) /* Store result value */
{ Result = (OldBackTracking[MatchingChars - 1] == Expression->Length * 2);
/* Frees the memory if necessary */
if (BackTracking != BackTrackingBuffer && BackTracking != OldBackTrackingBuffer)
ExFreePoolWithTag(BackTracking, 'nrSF'); ExFreePoolWithTag(BackTracking, 'nrSF');
} if (OldBackTracking != BackTrackingBuffer && OldBackTracking != OldBackTrackingBuffer)
if (DosBackTracking) ExFreePoolWithTag(OldBackTracking, 'nrSF');
{
ExFreePoolWithTag(DosBackTracking, 'nrSF');
}
return (ExpressionPosition == Expression->Length && NamePosition == Name->Length); return Result;
} }
/*++ /*++

View file

@ -27,9 +27,9 @@ FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression,
USHORT BackTrackingBuffer[16], OldBackTrackingBuffer[16] = {0}; USHORT BackTrackingBuffer[16], OldBackTrackingBuffer[16] = {0};
PUSHORT BackTrackingSwap, BackTracking = BackTrackingBuffer, OldBackTracking = OldBackTrackingBuffer; PUSHORT BackTrackingSwap, BackTracking = BackTrackingBuffer, OldBackTracking = OldBackTrackingBuffer;
UNICODE_STRING IntExpression; UNICODE_STRING IntExpression;
USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars = 1; USHORT ExpressionPosition, NamePosition = 0, MatchingChars = 1;
BOOLEAN EndOfName = FALSE; BOOLEAN EndOfName = FALSE;
BOOLEAN Result = FALSE; BOOLEAN Result;
BOOLEAN DontSkipDot; BOOLEAN DontSkipDot;
WCHAR CompareChar; WCHAR CompareChar;
PAGED_CODE(); PAGED_CODE();