2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/name.c
5 * PURPOSE: Provides name parsing and other support routines for FSDs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
11 /* INCLUDES ******************************************************************/
17 /* PRIVATE FUNCTIONS *********************************************************/
20 FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression
,
21 IN PUNICODE_STRING Name
,
22 IN BOOLEAN IgnoreCase
,
23 IN PWCHAR UpcaseTable OPTIONAL
)
25 USHORT ExpressionPosition
= 0, NamePosition
= 0, MatchingChars
, StarFound
= MAXUSHORT
;
28 ASSERT(!IgnoreCase
|| UpcaseTable
);
30 while (NamePosition
< Name
->Length
/ sizeof(WCHAR
) && ExpressionPosition
< Expression
->Length
/ sizeof(WCHAR
))
32 if ((Expression
->Buffer
[ExpressionPosition
] == (IgnoreCase
? UpcaseTable
[Name
->Buffer
[NamePosition
]] : Name
->Buffer
[NamePosition
])))
37 else if (StarFound
!= MAXUSHORT
&& (Expression
->Buffer
[StarFound
+ 1] == L
'*' ||
38 Expression
->Buffer
[StarFound
+ 1] == L
'?' || Expression
->Buffer
[StarFound
+ 1] == DOS_DOT
))
40 ExpressionPosition
= StarFound
+ 1;
41 switch (Expression
->Buffer
[ExpressionPosition
])
44 StarFound
= MAXUSHORT
;
48 if (++ExpressionPosition
== Expression
->Length
/ sizeof(WCHAR
))
50 NamePosition
= Name
->Length
/ sizeof(WCHAR
);
54 MatchingChars
= NamePosition
;
55 while (NamePosition
< Name
->Length
/ sizeof(WCHAR
) &&
56 (IgnoreCase
? UpcaseTable
[Name
->Buffer
[NamePosition
]] :
57 Name
->Buffer
[NamePosition
]) != Expression
->Buffer
[ExpressionPosition
])
62 if (NamePosition
- MatchingChars
> 0)
64 StarFound
= MAXUSHORT
;
69 while (NamePosition
< Name
->Length
/ sizeof(WCHAR
) &&
70 Name
->Buffer
[NamePosition
] != L
'.')
75 StarFound
= MAXUSHORT
;
79 /* Should never happen */
83 else if (Expression
->Buffer
[ExpressionPosition
] == L
'?' || (Expression
->Buffer
[ExpressionPosition
] == DOS_QM
) ||
84 (Expression
->Buffer
[ExpressionPosition
] == DOS_DOT
&& Name
->Buffer
[NamePosition
] == L
'.'))
88 StarFound
= MAXUSHORT
;
90 else if (Expression
->Buffer
[ExpressionPosition
] == L
'*')
92 StarFound
= ExpressionPosition
++;
93 if (ExpressionPosition
== Expression
->Length
/ sizeof(WCHAR
))
95 NamePosition
= Name
->Length
/ sizeof(WCHAR
);
99 else if (Expression
->Buffer
[ExpressionPosition
] == DOS_STAR
)
101 StarFound
= MAXUSHORT
;
102 MatchingChars
= NamePosition
;
103 while (MatchingChars
< Name
->Length
/ sizeof(WCHAR
))
105 if (Name
->Buffer
[MatchingChars
] == L
'.')
107 NamePosition
= MatchingChars
;
111 ExpressionPosition
++;
113 else if (StarFound
!= MAXUSHORT
)
115 ExpressionPosition
= StarFound
+ 1;
116 while (NamePosition
< Name
->Length
/ sizeof(WCHAR
) &&
117 (IgnoreCase
? UpcaseTable
[Name
->Buffer
[NamePosition
]] :
118 Name
->Buffer
[NamePosition
]) != Expression
->Buffer
[ExpressionPosition
])
128 if (ExpressionPosition
+ 1 == Expression
->Length
/ sizeof(WCHAR
) && NamePosition
== Name
->Length
/ sizeof(WCHAR
) &&
129 Expression
->Buffer
[ExpressionPosition
] == DOS_DOT
)
131 ExpressionPosition
++;
134 return (ExpressionPosition
== Expression
->Length
/ sizeof(WCHAR
) && NamePosition
== Name
->Length
/ sizeof(WCHAR
));
137 /* PUBLIC FUNCTIONS **********************************************************/
140 * @name FsRtlAreNamesEqual
143 * Compare two strings to check if they match
146 * First unicode string to compare
149 * Second unicode string to compare
152 * If TRUE, Case will be ignored when comparing strings
155 * Table for upcase letters. If NULL is given, system one will be used
157 * @return TRUE if the strings are equal
159 * @remarks From Bo Branten's ntifs.h v25.
164 FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1
,
165 IN PCUNICODE_STRING Name2
,
166 IN BOOLEAN IgnoreCase
,
167 IN PCWCH UpcaseTable OPTIONAL
)
169 UNICODE_STRING UpcaseName1
;
170 UNICODE_STRING UpcaseName2
;
171 BOOLEAN StringsAreEqual
, MemoryAllocated
= FALSE
;
176 /* Well, first check their size */
177 if (Name1
->Length
!= Name2
->Length
) return FALSE
;
179 /* Check if the caller didn't give an upcase table */
180 if ((IgnoreCase
) && !(UpcaseTable
))
182 /* Upcase the string ourselves */
183 Status
= RtlUpcaseUnicodeString(&UpcaseName1
, Name1
, TRUE
);
184 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
186 /* Upcase the second string too */
187 RtlUpcaseUnicodeString(&UpcaseName2
, Name2
, TRUE
);
188 Name1
= &UpcaseName1
;
189 Name2
= &UpcaseName2
;
191 /* Make sure we go through the path below, but free the strings */
193 MemoryAllocated
= TRUE
;
196 /* Do a case-sensitive search */
199 /* Use a raw memory compare */
200 StringsAreEqual
= RtlEqualMemory(Name1
->Buffer
,
204 /* Check if we allocated strings */
208 RtlFreeUnicodeString(&UpcaseName1
);
209 RtlFreeUnicodeString(&UpcaseName2
);
212 /* Return the equality */
213 return StringsAreEqual
;
217 /* Case in-sensitive search */
218 for (i
= 0; i
< Name1
->Length
/ sizeof(WCHAR
); i
++)
220 /* Check if the character matches */
221 if (UpcaseTable
[Name1
->Buffer
[i
]] != UpcaseTable
[Name2
->Buffer
[i
]])
223 /* Non-match found! */
228 /* We finished the loop so we are equal */
234 * @name FsRtlDissectName
237 * Dissects a given path name into first and remaining part.
240 * Unicode string to dissect.
243 * Pointer to user supplied UNICODE_STRING, that will later point
244 * to the first part of the original name.
246 * @param RemainingPart
247 * Pointer to user supplied UNICODE_STRING, that will later point
248 * to the remaining part of the original name.
253 * Name: \test1\test2\test3
255 * RemainingPart: test2\test3
260 FsRtlDissectName(IN UNICODE_STRING Name
,
261 OUT PUNICODE_STRING FirstPart
,
262 OUT PUNICODE_STRING RemainingPart
)
264 USHORT FirstPosition
, i
;
265 USHORT SkipFirstSlash
= 0;
268 /* Zero the strings before continuing */
269 RtlZeroMemory(FirstPart
, sizeof(UNICODE_STRING
));
270 RtlZeroMemory(RemainingPart
, sizeof(UNICODE_STRING
));
272 /* Just quit if the string is empty */
273 if (!Name
.Length
) return;
275 /* Find first backslash */
276 FirstPosition
= Name
.Length
/ sizeof(WCHAR
) ;
277 for (i
= 0; i
< Name
.Length
/ sizeof(WCHAR
); i
++)
279 /* If we found one... */
280 if (Name
.Buffer
[i
] == L
'\\')
282 /* If it begins string, just notice it and continue */
289 /* Else, save its position and break out of the loop */
296 /* Set up the first result string */
297 FirstPart
->Buffer
= Name
.Buffer
+ SkipFirstSlash
;
298 FirstPart
->Length
= (FirstPosition
- SkipFirstSlash
) * sizeof(WCHAR
);
299 FirstPart
->MaximumLength
= FirstPart
->Length
;
301 /* And second one, if necessary */
302 if (FirstPosition
< (Name
.Length
/ sizeof(WCHAR
)))
304 RemainingPart
->Buffer
= Name
.Buffer
+ FirstPosition
+ 1;
305 RemainingPart
->Length
= Name
.Length
- (FirstPosition
+ 1) * sizeof(WCHAR
);
306 RemainingPart
->MaximumLength
= RemainingPart
->Length
;
311 * @name FsRtlDoesNameContainWildCards
314 * Checks if the given string contains WildCards
317 * Pointer to a UNICODE_STRING containing Name to examine
319 * @return TRUE if Name contains wildcards, FALSE otherwise
321 * @remarks From Bo Branten's ntifs.h v12.
326 FsRtlDoesNameContainWildCards(IN PUNICODE_STRING Name
)
331 /* Loop through every character */
334 Ptr
= Name
->Buffer
+ (Name
->Length
/ sizeof(WCHAR
)) - 1;
335 while ((Ptr
>= Name
->Buffer
) && (*Ptr
!= L
'\\'))
337 /* Check for Wildcard */
338 if (FsRtlIsUnicodeCharacterWild(*Ptr
)) return TRUE
;
348 * @name FsRtlIsNameInExpression
351 * Check if the Name string is in the Expression string.
354 * The string in which we've to find Name. It can contain wildcards.
355 * If IgnoreCase is set to TRUE, this string MUST BE uppercase.
358 * The string to find. It cannot contain wildcards
361 * If set to TRUE, case will be ignore with upcasing both strings
364 * If not NULL, and if IgnoreCase is set to TRUE, it will be used to
365 * upcase the both strings
367 * @return TRUE if Name is in Expression, FALSE otherwise
369 * @remarks From Bo Branten's ntifs.h v12. This function should be
370 * rewritten to avoid recursion and better wildcard handling
371 * should be implemented (see FsRtlDoesNameContainWildCards).
376 FsRtlIsNameInExpression(IN PUNICODE_STRING Expression
,
377 IN PUNICODE_STRING Name
,
378 IN BOOLEAN IgnoreCase
,
379 IN PWCHAR UpcaseTable OPTIONAL
)
383 UNICODE_STRING IntName
;
385 if (IgnoreCase
&& !UpcaseTable
)
387 Status
= RtlUpcaseUnicodeString(&IntName
, Name
, TRUE
);
388 if (Status
!= STATUS_SUCCESS
)
390 ExRaiseStatus(Status
);
397 IntName
.Buffer
= NULL
;
400 Result
= FsRtlIsNameInExpressionPrivate(Expression
, Name
, IgnoreCase
, UpcaseTable
);
402 if (IntName
.Buffer
!= NULL
)
404 RtlFreeUnicodeString(&IntName
);