Author: pschweitzer
Date: Sun Jul 11 21:31:14 2010
New Revision: 48002
URL:
http://svn.reactos.org/svn/reactos?rev=48002&view=rev
Log:
[NTOSKRNL]
Merging some stuff from pierre-fsd/arty-newcc branches:
- Implemented FsRtlDissectDbcs(), FsRtlIsDbcsInExpression(), FsRtlIsFatDbcsLegal(),
FsRtlIsHpfsDbcsLegal()
- Implemented FsRtlIsNameInExpressionPrivate()
- Rewritten FsRtlIsNameInExpression()
- Updated comments
About FsRtlIsNameInExpressionPrivate(), it comes with a fix there isn't in branch,
which avoids reading string more than its own length, and this helps getting rid of a
workaround later in code.
Modified:
trunk/reactos/ntoskrnl/fsrtl/dbcsname.c
trunk/reactos/ntoskrnl/fsrtl/name.c
Modified: trunk/reactos/ntoskrnl/fsrtl/dbcsname.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/dbcsname.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/fsrtl/dbcsname.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/fsrtl/dbcsname.c [iso-8859-1] Sun Jul 11 21:31:14 2010
@@ -4,6 +4,7 @@
* FILE: ntoskrnl/fsrtl/name.c
* PURPOSE: Provides DBCS parsing and other support routines for FSDs
* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
+ * Pierre Schweitzer (pierre.schweitzer(a)reactos.org)
*/
/* INCLUDES ******************************************************************/
@@ -45,19 +46,67 @@
OUT PANSI_STRING FirstPart,
OUT PANSI_STRING RemainingPart)
{
- KeBugCheck(FILE_SYSTEM);
+ ULONG FirstPosition, i;
+ ULONG SkipFirstSlash = 0;
+
+ /* Zero the strings before continuing */
+ RtlZeroMemory(FirstPart, sizeof(ANSI_STRING));
+ RtlZeroMemory(RemainingPart, sizeof(ANSI_STRING));
+
+ /* Just quit if the string is empty */
+ if (!Name.Length) return;
+
+ /* Find first backslash */
+ FirstPosition = Name.Length;
+ for (i = 0; i < Name.Length; i++)
+ {
+ /* First make sure the character it's not the Lead DBCS */
+ if (FsRtlIsLeadDbcsCharacter(Name.Buffer[i]))
+ {
+ i++;
+ }
+ /* If we found one... */
+ else if (Name.Buffer[i] == '\\')
+ {
+ /* 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);
+ FirstPart->MaximumLength = FirstPart->Length;
+
+ /* And second one, if necessary */
+ if (FirstPosition < (Name.Length))
+ {
+ RemainingPart->Buffer = Name.Buffer + FirstPosition + 1;
+ RemainingPart->Length = Name.Length - (FirstPosition + 1);
+ RemainingPart->MaximumLength = RemainingPart->Length;
+ }
}
/*++
* @name FsRtlDoesDbcsContainWildCards
* @implemented
*
- * FILLME
+ * Returns TRUE if the given DbcsName contains wildcards such as *, ?,
+ * ANSI_DOS_STAR, ANSI_DOS_DOT, and ANSI_DOS_QM
*
* @param Name
- * FILLME
- *
- * @return None
+ * The Name to check
+ *
+ * @return TRUE if there are wildcards, FALSE otherwise
*
* @remarks None
*
@@ -89,17 +138,17 @@
/*++
* @name FsRtlIsDbcsInExpression
- * @unimplemented
- *
- * FILLME
+ * @implemented
+ *
+ * Check if the Name string is in the Expression string.
*
* @param Expression
- * FILLME
+ * The string in which we've to find Name. It can contains wildcards
*
* @param Name
- * FILLME
- *
- * @return None
+ * The string to find. It cannot contain wildcards.
+ *
+ * @return TRUE if Name is found in Expression, FALSE otherwise
*
* @remarks None
*
@@ -109,27 +158,74 @@
FsRtlIsDbcsInExpression(IN PANSI_STRING Expression,
IN PANSI_STRING Name)
{
- KeBugCheck(FILE_SYSTEM);
+ ULONG ExpressionPosition, NamePosition, MatchingChars = 0;
+
+ ASSERT(!FsRtlDoesDbcsContainWildCards(Name));
+
+ /* One can't be null, both can be */
+ if (!Expression->Length || !Name->Length)
+ {
+ return !(Expression->Length ^ Name->Length);
+ }
+
+ for (ExpressionPosition = 0; ExpressionPosition < Expression->Length;
ExpressionPosition++)
+ {
+ if ((Expression->Buffer[ExpressionPosition] == Name->Buffer[MatchingChars])
||
+ (Expression->Buffer[ExpressionPosition] == '?') ||
+ (Expression->Buffer[ExpressionPosition] == ANSI_DOS_QM) ||
+ (Expression->Buffer[ExpressionPosition] == ANSI_DOS_DOT &&
+ (Name->Buffer[MatchingChars] == '.' ||
Name->Buffer[MatchingChars] == '0')))
+ {
+ MatchingChars++;
+ }
+ else if (Expression->Buffer[ExpressionPosition] == '*')
+ {
+ MatchingChars = Name->Length;
+ }
+ else if (Expression->Buffer[ExpressionPosition] == ANSI_DOS_STAR)
+ {
+ for (NamePosition = MatchingChars; NamePosition < Name->Length;
NamePosition++)
+ {
+ if (Name->Buffer[NamePosition] == '.')
+ {
+ MatchingChars = NamePosition;
+ break;
+ }
+ }
+ }
+ else
+ {
+ MatchingChars = 0;
+ }
+ if (MatchingChars == Name->Length)
+ {
+ return TRUE;
+ }
+ }
+
return FALSE;
}
/*++
* @name FsRtlIsFatDbcsLegal
- * @unimplemented
- *
- * FILLME
+ * @implemented
+ *
+ * Returns TRUE if the given DbcsName is a valid FAT filename (in 8.3)
*
* @param DbcsName
- * FILLME
+ * The filename to check. It can also contains pathname.
*
* @param WildCardsPermissible
- * FILLME
+ * If this is set to FALSE and if filename contains wildcard, the function
+ * will fail
*
* @param PathNamePermissible
- * FILLME
+ * If this is set to FALSE and if the filename comes with a pathname, the
+ * function will fail
*
* @param LeadingBackslashPermissible
- * FILLME
+ * If this is set to FALSE and if the filename starts with a backslash, the
+ * function will fail
*
* @return TRUE if the DbcsName is legal, FALSE otherwise
*
@@ -143,27 +239,130 @@
IN BOOLEAN PathNamePermissible,
IN BOOLEAN LeadingBackslashPermissible)
{
- KeBugCheck(FILE_SYSTEM);
- return FALSE;
+ ANSI_STRING FirstPart, RemainingPart, Name;
+ BOOLEAN LastDot;
+ ULONG i;
+
+ /* Just quit if the string is empty */
+ if (!DbcsName.Length)
+ return FALSE;
+
+ /* DbcsName wasn't supposed to be started with \ */
+ if (!LeadingBackslashPermissible && DbcsName.Buffer[0] == '\\')
+ return FALSE;
+ /* DbcsName was allowed to be started with \, but now, remove it */
+ else if (LeadingBackslashPermissible && DbcsName.Buffer[0] == '\\')
+ {
+ DbcsName.Buffer = DbcsName.Buffer + 1;
+ DbcsName.Length = DbcsName.Length - 1;
+ DbcsName.MaximumLength = DbcsName.MaximumLength - 1;
+ }
+
+ /* Extract first part of the DbcsName to work on */
+ FsRtlDissectDbcs(DbcsName, &FirstPart, &RemainingPart);
+ while (FirstPart.Length > 0)
+ {
+ /* Reset dots count */
+ LastDot = FALSE;
+
+ /* Accept special filename if wildcards are allowed */
+ if (WildCardsPermissible && (FirstPart.Length == 1 || FirstPart.Length ==
2) && FirstPart.Buffer[0] == '.')
+ {
+ if (FirstPart.Length == 2)
+ {
+ if (FirstPart.Buffer[1] == '.')
+ {
+ goto EndLoop;
+ }
+ }
+ else
+ {
+ goto EndLoop;
+ }
+ }
+
+ /* Filename must be 8.3 filename */
+ if (FirstPart.Length < 3 || FirstPart.Length > 12)
+ return FALSE;
+
+ /* 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 (!FsRtlIsAnsiCharacterLegalFat(FirstPart.Buffer[i],
WildCardsPermissible))
+ {
+ return FALSE;
+ }
+ else if (FirstPart.Buffer[i] == '.')
+ {
+ /* Filename can only contain one dot */
+ if (LastDot)
+ return FALSE;
+
+ LastDot = 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;
+
+ if (i > 0)
+ if (FirstPart.Buffer[i - 1] == ' ')
+ return FALSE;
+
+ /* Filename must be 8.3 filename and not 3.8 filename */
+ if ((FirstPart.Length - 1) - i > 3)
+ return FALSE;
+ }
+ }
+
+ /* Filename mustn't finish with a space */
+ if (FirstPart.Buffer[FirstPart.Length - 1] == ' ')
+ return FALSE;
+
+ EndLoop:
+ /* Preparing next loop */
+ Name.Buffer = RemainingPart.Buffer;
+ Name.Length = RemainingPart.Length;
+ Name.MaximumLength = RemainingPart.MaximumLength;
+
+ /* Call once again our dissect function */
+ FsRtlDissectDbcs(Name, &FirstPart, &RemainingPart);
+
+ /* We found a pathname, it wasn't allowed */
+ if (FirstPart.Length > 0 && !PathNamePermissible)
+ return FALSE;
+ }
+ return TRUE;
}
/*++
* @name FsRtlIsHpfsDbcsLegal
- * @unimplemented
- *
- * FILLME
+ * @implemented
+ *
+ * Returns TRUE if the given DbcsName is a valid HPFS filename
*
* @param DbcsName
- * FILLME
+ * The filename to check. It can also contains pathname.
*
* @param WildCardsPermissible
- * FILLME
+ * If this is set to FALSE and if filename contains wildcard, the function
+ * will fail
*
* @param PathNamePermissible
- * FILLME
+ * If this is set to FALSE and if the filename comes with a pathname, the
+ * function will fail
*
* @param LeadingBackslashPermissible
- * FILLME
+ * If this is set to FALSE and if the filename starts with a backslash, the
+ * function will fail
*
* @return TRUE if the DbcsName is legal, FALSE otherwise
*
@@ -177,6 +376,82 @@
IN BOOLEAN PathNamePermissible,
IN BOOLEAN LeadingBackslashPermissible)
{
- KeBugCheck(FILE_SYSTEM);
- return FALSE;
+ ANSI_STRING FirstPart, RemainingPart, Name;
+ ULONG i;
+
+ /* Just quit if the string is empty */
+ if (!DbcsName.Length)
+ return FALSE;
+
+ /* DbcsName wasn't supposed to be started with \ */
+ if (!LeadingBackslashPermissible && DbcsName.Buffer[0] == '\\')
+ return FALSE;
+ /* DbcsName was allowed to be started with \, but now, remove it */
+ else if (LeadingBackslashPermissible && DbcsName.Buffer[0] == '\\')
+ {
+ DbcsName.Buffer = DbcsName.Buffer + 1;
+ DbcsName.Length = DbcsName.Length - 1;
+ DbcsName.MaximumLength = DbcsName.MaximumLength - 1;
+ }
+
+ /* Extract first part of the DbcsName to work on */
+ FsRtlDissectDbcs(DbcsName, &FirstPart, &RemainingPart);
+ while (FirstPart.Length > 0)
+ {
+ /* Accept special filename if wildcards are allowed */
+ if (WildCardsPermissible && (FirstPart.Length == 1 || FirstPart.Length ==
2) && FirstPart.Buffer[0] == '.')
+ {
+ if (FirstPart.Length == 2)
+ {
+ if (FirstPart.Buffer[1] == '.')
+ {
+ goto EndLoop;
+ }
+ }
+ else
+ {
+ goto EndLoop;
+ }
+ }
+
+ /* Filename must be 255 bytes maximum */
+ if (FirstPart.Length > 255)
+ return FALSE;
+
+ /* 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))
+ {
+ 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;
+
+ /* Call once again our dissect function */
+ FsRtlDissectDbcs(Name, &FirstPart, &RemainingPart);
+
+ /* We found a pathname, it wasn't allowed */
+ if (FirstPart.Length > 0 && !PathNamePermissible)
+ return FALSE;
+ }
+ return TRUE;
}
Modified: trunk/reactos/ntoskrnl/fsrtl/name.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/name.c?rev=…
==============================================================================
--- trunk/reactos/ntoskrnl/fsrtl/name.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/fsrtl/name.c [iso-8859-1] Sun Jul 11 21:31:14 2010
@@ -5,6 +5,7 @@
* PURPOSE: Provides name parsing and other support routines for FSDs
* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
* Filip Navara (navaraf(a)reactos.org)
+ * Pierre Schweitzer (pierre.schweitzer(a)reactos.org)
*/
/* INCLUDES ******************************************************************/
@@ -13,27 +14,96 @@
#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)
+{
+ ULONG i = 0, j, k = 0;
+
+ ASSERT(!FsRtlDoesNameContainWildCards(Name));
+
+ while (i < Name->Length / sizeof(WCHAR) && k < Expression->Length
/ sizeof(WCHAR))
+ {
+ if ((Expression->Buffer[k] == (IgnoreCase ? UpcaseTable[Name->Buffer[i]] :
Name->Buffer[i])) ||
+ (Expression->Buffer[k] == L'?') || (Expression->Buffer[k] == DOS_QM) ||
+ (Expression->Buffer[k] == DOS_DOT && (Name->Buffer[i] == L'.' ||
Name->Buffer[i] == L'0')))
+ {
+ i++;
+ k++;
+ }
+ else if (Expression->Buffer[k] == L'*')
+ {
+ if (k < Expression->Length / sizeof(WCHAR))
+ {
+ if (Expression->Buffer[k+1] != L'*' && Expression->Buffer[k+1]
!= L'?' &&
+ Expression->Buffer[k+1] != DOS_DOT && Expression->Buffer[k+1]
!= DOS_QM &&
+ Expression->Buffer[k+1] != DOS_STAR)
+ {
+ while ((IgnoreCase ? UpcaseTable[Name->Buffer[i]] : Name->Buffer[i]) !=
Expression->Buffer[k+1] &&
+ i <= Name->Length / sizeof(WCHAR)) i++;
+ }
+ else
+ {
+ if (!(Expression->Buffer[k+1] != DOS_DOT && (Name->Buffer[i] ==
L'.' || Name->Buffer[i] == L'0')))
+ {
+ i++;
+ }
+ }
+ }
+ else
+ {
+ i = Name->Length / sizeof(WCHAR);
+ }
+ k++;
+ }
+ else if (Expression->Buffer[k] == DOS_STAR)
+ {
+ j = i;
+ while (j <= Name->Length / sizeof(WCHAR))
+ {
+ if (Name->Buffer[j] == L'.')
+ {
+ i = j;
+ }
+ j++;
+ }
+ k++;
+ }
+ else
+ {
+ i++;
+ k = 0;
+ }
+ }
+
+ return (k == Expression->Length / sizeof(WCHAR));
+}
+
/* PUBLIC FUNCTIONS **********************************************************/
/*++
* @name FsRtlAreNamesEqual
* @implemented
*
- * FILLME
+ * Compare two strings to check if they match
*
* @param Name1
- * FILLME
+ * First unicode string to compare
*
* @param Name2
- * FILLME
+ * Second unicode string to compare
*
* @param IgnoreCase
- * FILLME
+ * If TRUE, Case will be ignored when comparing strings
*
* @param UpcaseTable
- * FILLME
- *
- * @return None
+ * 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.
*
@@ -188,7 +258,7 @@
* @name FsRtlDoesNameContainWildCards
* @implemented
*
- * FILLME
+ * Checks if the given string contains WildCards
*
* @param Name
* Pointer to a UNICODE_STRING containing Name to examine
@@ -224,13 +294,21 @@
* @name FsRtlIsNameInExpression
* @implemented
*
- * FILLME
- *
- * @param DeviceObject
- * FILLME
- *
- * @param Irp
- * FILLME
+ * 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
*
@@ -246,80 +324,31 @@
IN BOOLEAN IgnoreCase,
IN PWCHAR UpcaseTable OPTIONAL)
{
- USHORT ExpressionPosition, NamePosition;
- UNICODE_STRING TempExpression, TempName;
-
- ExpressionPosition = 0;
- NamePosition = 0;
- while (ExpressionPosition < (Expression->Length / sizeof(WCHAR)) &&
- NamePosition < (Name->Length / sizeof(WCHAR)))
- {
- if (Expression->Buffer[ExpressionPosition] == L'*')
- {
- ExpressionPosition++;
- if (ExpressionPosition == (Expression->Length / sizeof(WCHAR)))
- {
- return TRUE;
- }
- while (NamePosition < (Name->Length / sizeof(WCHAR)))
- {
- TempExpression.Length =
- TempExpression.MaximumLength =
- Expression->Length - (ExpressionPosition * sizeof(WCHAR));
- TempExpression.Buffer = Expression->Buffer + ExpressionPosition;
- TempName.Length =
- TempName.MaximumLength =
- Name->Length - (NamePosition * sizeof(WCHAR));
- TempName.Buffer = Name->Buffer + NamePosition;
- /* FIXME: Rewrite to get rid of recursion */
- if (FsRtlIsNameInExpression(&TempExpression, &TempName,
- IgnoreCase, UpcaseTable))
- {
- return TRUE;
- }
- NamePosition++;
- }
- }
- else
- {
- /* FIXME: Take UpcaseTable into account! */
- if (Expression->Buffer[ExpressionPosition] == L'?' ||
- (IgnoreCase &&
- RtlUpcaseUnicodeChar(Expression->Buffer[ExpressionPosition]) ==
- RtlUpcaseUnicodeChar(Name->Buffer[NamePosition])) ||
- (!IgnoreCase &&
- Expression->Buffer[ExpressionPosition] ==
- Name->Buffer[NamePosition]))
- {
- NamePosition++;
- ExpressionPosition++;
- }
- else
- {
- return FALSE;
- }
- }
- }
-
- /* Handle matching of "f0_*.*" expression to "f0_000" file name.
*/
- if (ExpressionPosition < (Expression->Length / sizeof(WCHAR)) &&
- Expression->Buffer[ExpressionPosition] == L'.')
- {
- while (ExpressionPosition < (Expression->Length / sizeof(WCHAR))
&&
- (Expression->Buffer[ExpressionPosition] == L'.' ||
- Expression->Buffer[ExpressionPosition] == L'*' ||
- Expression->Buffer[ExpressionPosition] == L'?'))
- {
- ExpressionPosition++;
- }
- }
-
- if (ExpressionPosition == (Expression->Length / sizeof(WCHAR)) &&
- NamePosition == (Name->Length / sizeof(WCHAR)))
- {
- return TRUE;
- }
-
- return FALSE;
-}
-
+ 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;
+}