/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/fsrtl/name.c
+ * FILE: ntoskrnl/fsrtl/dbcsname.c
* PURPOSE: Provides DBCS parsing and other support routines for FSDs
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Pierre Schweitzer (pierre.schweitzer@reactos.org)
FsRtlIsDbcsInExpression(IN PANSI_STRING Expression,
IN PANSI_STRING Name)
{
- SHORT StarFound = -1;
- PUSHORT BackTracking = NULL;
- USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars;
+ USHORT Offset, Position, BackTrackingPosition, OldBackTrackingPosition;
+ USHORT BackTrackingBuffer[16], OldBackTrackingBuffer[16] = {0};
+ 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();
ASSERT(Name->Length);
ASSERT(Expression->Length);
ASSERT(!FsRtlDoesDbcsContainWildCards(Name));
- while (NamePosition < Name->Length && ExpressionPosition < Expression->Length)
+ /* Check if we were given strings at all */
+ if (!Name->Length || !Expression->Length)
{
- /* Basic check to test if chars are equal */
- if ((Expression->Buffer[ExpressionPosition] == Name->Buffer[NamePosition]))
+ /* Return TRUE if both strings are empty, otherwise FALSE */
+ if (Name->Length == 0 && Expression->Length == 0)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ /* Check for a shortcut: just one wildcard */
+ if (Expression->Length == sizeof(CHAR))
+ {
+ if (Expression->Buffer[0] == '*')
+ return TRUE;
+ }
+
+ //ASSERT(FsRtlDoesDbcsContainWildCards(Expression));
+
+ /* Another shortcut, wildcard followed by some string */
+ if (Expression->Buffer[0] == '*')
+ {
+ /* Copy Expression to our local variable */
+ ANSI_STRING IntExpression = *Expression;
+
+ /* Skip the first char */
+ IntExpression.Buffer++;
+ IntExpression.Length -= sizeof(CHAR);
+
+ /* Continue only if the rest of the expression does NOT contain
+ any more wildcards */
+ if (!FsRtlDoesDbcsContainWildCards(&IntExpression))
{
- NamePosition++;
- ExpressionPosition++;
+ /* Check for a degenerate case */
+ if (Name->Length < (Expression->Length - sizeof(CHAR)))
+ return FALSE;
+
+ /* Calculate position */
+ NamePosition = (Name->Length - IntExpression.Length) / sizeof(CHAR);
+
+ /* Check whether we are breaking a two chars char (DBCS) */
+ if (NlsMbOemCodePageTag)
+ {
+ MatchingChars = 0;
+
+ while (MatchingChars < NamePosition)
+ {
+ /* Check if current char is DBCS lead char, if so, jump by two chars */
+ MatchingChars += FsRtlIsLeadDbcsCharacter(Name->Buffer[MatchingChars]) ? 2 : 1;
+ }
+
+ /* If so, deny */
+ if (MatchingChars > NamePosition)
+ return FALSE;
+ }
+
+ /* Compare */
+ return RtlEqualMemory(IntExpression.Buffer,
+ (Name->Buffer + NamePosition),
+ IntExpression.Length);
}
- /* 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] == '.'))
+ }
+
+ /* Name parsing loop */
+ for (; !EndOfName; MatchingChars = BackTrackingPosition)
+ {
+ /* Reset positions */
+ OldBackTrackingPosition = BackTrackingPosition = 0;
+
+ if (NamePosition >= Name->Length)
{
- NamePosition++;
- ExpressionPosition++;
+ EndOfName = TRUE;
+ if (OldBackTracking[MatchingChars - 1] == Expression->Length * 2)
+ break;
}
- /* Test star */
- else if (Expression->Buffer[ExpressionPosition] == '*')
+ else
{
- /* Skip contigous stars */
- while (ExpressionPosition + 1 < Expression->Length && Expression->Buffer[ExpressionPosition + 1] == '*')
+ /* If lead byte present */
+ if (FsRtlIsLeadDbcsCharacter(Name->Buffer[NamePosition]))
{
- ExpressionPosition++;
+ NameChar = Name->Buffer[NamePosition] +
+ (0x100 * Name->Buffer[NamePosition + 1]);
+ NamePosition += sizeof(USHORT);
}
-
- /* Save star position */
- if (!BackTracking)
+ else
{
- BackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,
- Expression->Length * sizeof(USHORT), 'nrSF');
+ NameChar = Name->Buffer[NamePosition];
+ NamePosition += sizeof(UCHAR);
}
- BackTracking[++StarFound] = ExpressionPosition++;
+ }
+
+ while (MatchingChars > OldBackTrackingPosition)
+ {
+ ExpressionPosition = (OldBackTracking[OldBackTrackingPosition++] + 1) / 2;
- /* If star is at the end, then eat all rest and leave */
- if (ExpressionPosition == Expression->Length)
+ /* Expression parsing loop */
+ for (Offset = 0; ExpressionPosition < Expression->Length; )
{
- NamePosition = Name->Length;
+ 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;
}
- else if (Expression->Buffer[ExpressionPosition] != '?')
- {
- NamePosition++;
- }
- }
- /* Check DOS_STAR */
- else if (Expression->Buffer[ExpressionPosition] == ANSI_DOS_STAR)
- {
- MatchingChars = NamePosition;
- while (MatchingChars < Name->Length)
+
+ for (Position = 0; MatchingChars > OldBackTrackingPosition && Position < BackTrackingPosition; Position++)
{
- if (Name->Buffer[MatchingChars] == '.')
+ while (MatchingChars > OldBackTrackingPosition &&
+ BackTracking[Position] > OldBackTracking[OldBackTrackingPosition])
{
- NamePosition = MatchingChars + 1;
+ ++OldBackTrackingPosition;
}
- MatchingChars++;
}
- ExpressionPosition++;
- }
- /* If nothing match, try to backtrack */
- else if (StarFound >= 0)
- {
- 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)
- {
- ExpressionPosition++;
+ /* 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');
- }
+ if (OldBackTracking != BackTrackingBuffer && OldBackTracking != OldBackTrackingBuffer)
+ ExFreePoolWithTag(OldBackTracking, 'nrSF');
- return (ExpressionPosition == Expression->Length && NamePosition == Name->Length);
+ return Result;
}
/*++
IN BOOLEAN PathNamePermissible,
IN BOOLEAN LeadingBackslashPermissible)
{
- ANSI_STRING FirstPart, RemainingPart, Name;
+ ANSI_STRING FirstPart, RemainingPart;
BOOLEAN LastDot;
USHORT i;
PAGED_CODE();
if (!DbcsName.Length)
return FALSE;
+ /* Accept special filename if wildcards are allowed */
+ if (WildCardsPermissible && (DbcsName.Length == 1 || DbcsName.Length == 2) && DbcsName.Buffer[0] == '.')
+ {
+ if (DbcsName.Length == 2)
+ {
+ if (DbcsName.Buffer[1] == '.')
+ return TRUE;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+
/* DbcsName wasn't supposed to be started with \ */
if (!LeadingBackslashPermissible && DbcsName.Buffer[0] == '\\')
return FALSE;
DbcsName.MaximumLength = DbcsName.MaximumLength - 1;
}
- /* Extract first part of the DbcsName to work on */
- FsRtlDissectDbcs(DbcsName, &FirstPart, &RemainingPart);
- while (FirstPart.Length > 0)
+ if (PathNamePermissible)
{
- /* Reset dots count */
- LastDot = FALSE;
+ /* We copy the buffer for FsRtlDissectDbcs call */
+ RemainingPart.Buffer = DbcsName.Buffer;
+ RemainingPart.Length = DbcsName.Length;
+ RemainingPart.MaximumLength = DbcsName.MaximumLength;
- /* Accept special filename if wildcards are allowed */
- if (WildCardsPermissible && (FirstPart.Length == 1 || FirstPart.Length == 2) && FirstPart.Buffer[0] == '.')
+ while (RemainingPart.Length > 0)
{
- if (FirstPart.Length == 2)
- {
- if (FirstPart.Buffer[1] == '.')
- {
- goto EndLoop;
- }
- }
- else
+ if (RemainingPart.Buffer[0] == '\\')
+ return FALSE;
+
+ /* Call once again our dissect function */
+ FsRtlDissectDbcs(RemainingPart, &FirstPart, &RemainingPart);
+
+ if (!FsRtlIsFatDbcsLegal(FirstPart,
+ WildCardsPermissible,
+ FALSE,
+ FALSE))
{
- goto EndLoop;
+ return FALSE;
}
}
- /* Filename must be 8.3 filename */
- if (FirstPart.Length < 3 || FirstPart.Length > 12)
- return FALSE;
+ return TRUE;
+ }
- /* Now, we will parse the filename to find everything bad in */
- for (i = 0; i < FirstPart.Length; i++)
+ if (WildCardsPermissible && FsRtlDoesDbcsContainWildCards(&DbcsName))
+ {
+ for (i = 0; i < DbcsName.Length; i++)
{
/* First make sure the character it's not the Lead DBCS */
- if (FsRtlIsLeadDbcsCharacter(FirstPart.Buffer[i]))
+ if (FsRtlIsLeadDbcsCharacter(DbcsName.Buffer[i]))
{
- if (i == (FirstPart.Length) - 1)
- return FALSE;
i++;
}
/* Then check for bad characters */
- else if (!FsRtlIsAnsiCharacterLegalFat(FirstPart.Buffer[i], WildCardsPermissible))
+ else if (!FsRtlIsAnsiCharacterLegalFat(DbcsName.Buffer[i], TRUE))
{
return FALSE;
}
- else if (FirstPart.Buffer[i] == '.')
- {
- /* Filename can only contain one dot */
- if (LastDot)
- return FALSE;
+ }
- LastDot = TRUE;
+ return TRUE;
+ }
- /* We mustn't have spaces before dot or at the end of the filename
- * and no dot at the beginning of the filename */
- if ((i == (FirstPart.Length) - 1) || i == 0)
- return FALSE;
+ /* Filename must be 8.3 filename */
+ if (DbcsName.Length > 12)
+ return FALSE;
- if (i > 0)
- if (FirstPart.Buffer[i - 1] == ' ')
- return FALSE;
+ /* Reset dots count */
+ LastDot = FALSE;
- /* Filename must be 8.3 filename and not 3.8 filename */
- if ((FirstPart.Length - 1) - i > 3)
- return FALSE;
- }
- }
+ for (i = 0; i < DbcsName.Length; i++)
+ {
+ /* First make sure the character it's not the Lead DBCS */
+ if (FsRtlIsLeadDbcsCharacter(DbcsName.Buffer[i]))
+ {
+ if (!LastDot && (i >= 7))
+ return FALSE;
- /* Filename mustn't finish with a space */
- if (FirstPart.Buffer[FirstPart.Length - 1] == ' ')
+ if (i == (DbcsName.Length - 1))
+ return FALSE;
+
+ i++;
+ continue;
+ }
+ /* Then check for bad characters */
+ else if (!FsRtlIsAnsiCharacterLegalFat(DbcsName.Buffer[i], WildCardsPermissible))
+ {
return FALSE;
+ }
+ else if (DbcsName.Buffer[i] == '.')
+ {
+ /* Filename can only contain one dot */
+ if (LastDot)
+ return FALSE;
+
+ LastDot = TRUE;
- EndLoop:
- /* Preparing next loop */
- Name.Buffer = RemainingPart.Buffer;
- Name.Length = RemainingPart.Length;
- Name.MaximumLength = RemainingPart.MaximumLength;
+ /* We mustn't have spaces before dot or at the end of the filename
+ * and no dot at the beginning of the filename */
+ if (i == (DbcsName.Length - 1) || i == 0)
+ return FALSE;
- /* Call once again our dissect function */
- FsRtlDissectDbcs(Name, &FirstPart, &RemainingPart);
+ /* Filename must be 8.3 filename and not 3.8 filename */
+ if ((DbcsName.Length - 1) - i > 3)
+ return FALSE;
- /* We found a pathname, it wasn't allowed */
- if (FirstPart.Length > 0 && !PathNamePermissible)
+ if ((i > 0) && DbcsName.Buffer[i - 1] == ' ')
+ return FALSE;
+ }
+ /* Filename mustn't finish with a space */
+ else if (DbcsName.Buffer[i] == ' ' && i == (DbcsName.Length - 1))
+ {
+ return FALSE;
+ }
+
+ if (!LastDot && (i >= 8))
return FALSE;
}
+
return TRUE;
}
IN BOOLEAN PathNamePermissible,
IN BOOLEAN LeadingBackslashPermissible)
{
- ANSI_STRING FirstPart, RemainingPart, Name;
+ ANSI_STRING FirstPart, RemainingPart;
USHORT i;
PAGED_CODE();
if (!DbcsName.Length)
return FALSE;
+ /* Accept special filename if wildcards are allowed */
+ if (WildCardsPermissible && (DbcsName.Length == 1 || DbcsName.Length == 2) && DbcsName.Buffer[0] == '.')
+ {
+ if (DbcsName.Length == 2)
+ {
+ if (DbcsName.Buffer[1] == '.')
+ return TRUE;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+
/* DbcsName wasn't supposed to be started with \ */
if (!LeadingBackslashPermissible && DbcsName.Buffer[0] == '\\')
return FALSE;
DbcsName.MaximumLength = DbcsName.MaximumLength - 1;
}
- /* Extract first part of the DbcsName to work on */
- FsRtlDissectDbcs(DbcsName, &FirstPart, &RemainingPart);
- while (FirstPart.Length > 0)
+ if (PathNamePermissible)
{
- /* Accept special filename if wildcards are allowed */
- if (WildCardsPermissible && (FirstPart.Length == 1 || FirstPart.Length == 2) && FirstPart.Buffer[0] == '.')
+ /* We copy the buffer for FsRtlDissectDbcs call */
+ RemainingPart.Buffer = DbcsName.Buffer;
+ RemainingPart.Length = DbcsName.Length;
+ RemainingPart.MaximumLength = DbcsName.MaximumLength;
+
+ while (RemainingPart.Length > 0)
{
- if (FirstPart.Length == 2)
- {
- if (FirstPart.Buffer[1] == '.')
- {
- goto EndLoop;
- }
- }
- else
- {
- goto EndLoop;
- }
- }
+ if (RemainingPart.Buffer[0] == '\\')
+ return FALSE;
- /* Filename must be 255 bytes maximum */
- if (FirstPart.Length > 255)
- return FALSE;
+ /* Call once again our dissect function */
+ FsRtlDissectDbcs(RemainingPart, &FirstPart, &RemainingPart);
- /* Now, we will parse the filename to find everything bad in */
- for (i = 0; i < FirstPart.Length; i++)
- {
- /* First make sure the character it's not the Lead DBCS */
- if (FsRtlIsLeadDbcsCharacter(FirstPart.Buffer[i]))
- {
- if (i == (FirstPart.Length) - 1)
- return FALSE;
- i++;
- }
- /* Then check for bad characters */
- else if (!FsRtlIsAnsiCharacterLegalHpfs(FirstPart.Buffer[i], WildCardsPermissible))
+ if (!FsRtlIsHpfsDbcsLegal(FirstPart,
+ WildCardsPermissible,
+ FALSE,
+ FALSE))
{
return FALSE;
}
}
- /* Filename mustn't finish with a space or a dot */
- if ((FirstPart.Buffer[FirstPart.Length - 1] == ' ') ||
- (FirstPart.Buffer[FirstPart.Length - 1] == '.'))
- return FALSE;
-
- EndLoop:
- /* Preparing next loop */
- Name.Buffer = RemainingPart.Buffer;
- Name.Length = RemainingPart.Length;
- Name.MaximumLength = RemainingPart.MaximumLength;
+ return TRUE;
+ }
- /* Call once again our dissect function */
- FsRtlDissectDbcs(Name, &FirstPart, &RemainingPart);
+ if (DbcsName.Length > 255)
+ return FALSE;
- /* We found a pathname, it wasn't allowed */
- if (FirstPart.Length > 0 && !PathNamePermissible)
+ for (i = 0; i < DbcsName.Length; i++)
+ {
+ /* First make sure the character it's not the Lead DBCS */
+ if (FsRtlIsLeadDbcsCharacter(DbcsName.Buffer[i]))
+ {
+ if (i == (DbcsName.Length - 1))
+ return FALSE;
+ i++;
+ }
+ /* Then check for bad characters */
+ else if (!FsRtlIsAnsiCharacterLegalHpfs(DbcsName.Buffer[i], WildCardsPermissible))
+ {
return FALSE;
+ }
+ /* Filename mustn't finish with a space or a dot */
+ else if ((DbcsName.Buffer[i] == ' ' || DbcsName.Buffer[i] == '.') && i == (DbcsName.Length - 1))
+ {
+ return FALSE;
+ }
}
+
return TRUE;
}