[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / fsrtl / name.c
1 /*
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)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* PRIVATE FUNCTIONS *********************************************************/
18 BOOLEAN
19 NTAPI
20 FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression,
21 IN PUNICODE_STRING Name,
22 IN BOOLEAN IgnoreCase,
23 IN PWCHAR UpcaseTable OPTIONAL)
24 {
25 USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars, StarFound = MAXUSHORT;
26 PAGED_CODE();
27
28 ASSERT(!IgnoreCase || UpcaseTable);
29
30 while (NamePosition < Name->Length / sizeof(WCHAR) && ExpressionPosition < Expression->Length / sizeof(WCHAR))
31 {
32 if ((Expression->Buffer[ExpressionPosition] == (IgnoreCase ? UpcaseTable[Name->Buffer[NamePosition]] : Name->Buffer[NamePosition])))
33 {
34 NamePosition++;
35 ExpressionPosition++;
36 }
37 else if (Expression->Buffer[ExpressionPosition] == L'?' || (Expression->Buffer[ExpressionPosition] == DOS_QM) ||
38 (Expression->Buffer[ExpressionPosition] == DOS_DOT && Name->Buffer[NamePosition] == L'.'))
39 {
40 NamePosition++;
41 ExpressionPosition++;
42 StarFound = MAXUSHORT;
43 }
44 else if (Expression->Buffer[ExpressionPosition] == L'*')
45 {
46 StarFound = ExpressionPosition++;
47 if (StarFound < (Expression->Length / sizeof(WCHAR) - 1))
48 {
49 while ((IgnoreCase ? UpcaseTable[Name->Buffer[NamePosition]] : Name->Buffer[NamePosition]) != Expression->Buffer[ExpressionPosition] &&
50 NamePosition < Name->Length / sizeof(WCHAR))
51 {
52 NamePosition++;
53 }
54 }
55 else
56 {
57 NamePosition = Name->Length / sizeof(WCHAR);
58 }
59 }
60 else if (Expression->Buffer[ExpressionPosition] == DOS_STAR)
61 {
62 StarFound = MAXUSHORT;
63 MatchingChars = NamePosition;
64 while (MatchingChars < Name->Length / sizeof(WCHAR))
65 {
66 if (Name->Buffer[MatchingChars] == L'.')
67 {
68 NamePosition = MatchingChars;
69 }
70 MatchingChars++;
71 }
72 ExpressionPosition++;
73 }
74 else if (StarFound != MAXUSHORT)
75 {
76 ExpressionPosition = StarFound + 1;
77 while ((IgnoreCase ? UpcaseTable[Name->Buffer[NamePosition]] : Name->Buffer[NamePosition]) != Expression->Buffer[ExpressionPosition] &&
78 NamePosition < Name->Length / sizeof(WCHAR))
79 {
80 NamePosition++;
81 }
82 }
83 else
84 {
85 NamePosition = Name->Length / sizeof(WCHAR);
86 }
87 }
88 if (ExpressionPosition + 1 == Expression->Length / sizeof(WCHAR) && NamePosition == Name->Length / sizeof(WCHAR) &&
89 Expression->Buffer[ExpressionPosition] == DOS_DOT)
90 {
91 ExpressionPosition++;
92 }
93
94 return (ExpressionPosition == Expression->Length / sizeof(WCHAR) && NamePosition == Name->Length / sizeof(WCHAR));
95 }
96
97 /* PUBLIC FUNCTIONS **********************************************************/
98
99 /*++
100 * @name FsRtlAreNamesEqual
101 * @implemented
102 *
103 * Compare two strings to check if they match
104 *
105 * @param Name1
106 * First unicode string to compare
107 *
108 * @param Name2
109 * Second unicode string to compare
110 *
111 * @param IgnoreCase
112 * If TRUE, Case will be ignored when comparing strings
113 *
114 * @param UpcaseTable
115 * Table for upcase letters. If NULL is given, system one will be used
116 *
117 * @return TRUE if the strings are equal
118 *
119 * @remarks From Bo Branten's ntifs.h v25.
120 *
121 *--*/
122 BOOLEAN
123 NTAPI
124 FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1,
125 IN PCUNICODE_STRING Name2,
126 IN BOOLEAN IgnoreCase,
127 IN PCWCH UpcaseTable OPTIONAL)
128 {
129 UNICODE_STRING UpcaseName1;
130 UNICODE_STRING UpcaseName2;
131 BOOLEAN StringsAreEqual, MemoryAllocated = FALSE;
132 ULONG i;
133 NTSTATUS Status;
134 PAGED_CODE();
135
136 /* Well, first check their size */
137 if (Name1->Length != Name2->Length) return FALSE;
138
139 /* Check if the caller didn't give an upcase table */
140 if ((IgnoreCase) && !(UpcaseTable))
141 {
142 /* Upcase the string ourselves */
143 Status = RtlUpcaseUnicodeString(&UpcaseName1, Name1, TRUE);
144 if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);
145
146 /* Upcase the second string too */
147 RtlUpcaseUnicodeString(&UpcaseName2, Name2, TRUE);
148 Name1 = &UpcaseName1;
149 Name2 = &UpcaseName2;
150
151 /* Make sure we go through the path below, but free the strings */
152 IgnoreCase = FALSE;
153 MemoryAllocated = TRUE;
154 }
155
156 /* Do a case-sensitive search */
157 if (!IgnoreCase)
158 {
159 /* Use a raw memory compare */
160 StringsAreEqual = RtlEqualMemory(Name1->Buffer,
161 Name2->Buffer,
162 Name1->Length);
163
164 /* Check if we allocated strings */
165 if (MemoryAllocated)
166 {
167 /* Free them */
168 RtlFreeUnicodeString(&UpcaseName1);
169 RtlFreeUnicodeString(&UpcaseName2);
170 }
171
172 /* Return the equality */
173 return StringsAreEqual;
174 }
175 else
176 {
177 /* Case in-sensitive search */
178 for (i = 0; i < Name1->Length / sizeof(WCHAR); i++)
179 {
180 /* Check if the character matches */
181 if (UpcaseTable[Name1->Buffer[i]] != UpcaseTable[Name2->Buffer[i]])
182 {
183 /* Non-match found! */
184 return FALSE;
185 }
186 }
187
188 /* We finished the loop so we are equal */
189 return TRUE;
190 }
191 }
192
193 /*++
194 * @name FsRtlDissectName
195 * @implemented
196 *
197 * Dissects a given path name into first and remaining part.
198 *
199 * @param Name
200 * Unicode string to dissect.
201 *
202 * @param FirstPart
203 * Pointer to user supplied UNICODE_STRING, that will later point
204 * to the first part of the original name.
205 *
206 * @param RemainingPart
207 * Pointer to user supplied UNICODE_STRING, that will later point
208 * to the remaining part of the original name.
209 *
210 * @return None
211 *
212 * @remarks Example:
213 * Name: \test1\test2\test3
214 * FirstPart: test1
215 * RemainingPart: test2\test3
216 *
217 *--*/
218 VOID
219 NTAPI
220 FsRtlDissectName(IN UNICODE_STRING Name,
221 OUT PUNICODE_STRING FirstPart,
222 OUT PUNICODE_STRING RemainingPart)
223 {
224 ULONG FirstPosition, i;
225 ULONG SkipFirstSlash = 0;
226 PAGED_CODE();
227
228 /* Zero the strings before continuing */
229 RtlZeroMemory(FirstPart, sizeof(UNICODE_STRING));
230 RtlZeroMemory(RemainingPart, sizeof(UNICODE_STRING));
231
232 /* Just quit if the string is empty */
233 if (!Name.Length) return;
234
235 /* Find first backslash */
236 FirstPosition = Name.Length / sizeof(WCHAR) ;
237 for (i = 0; i < Name.Length / sizeof(WCHAR); i++)
238 {
239 /* If we found one... */
240 if (Name.Buffer[i] == L'\\')
241 {
242 /* If it begins string, just notice it and continue */
243 if (i == 0)
244 {
245 SkipFirstSlash = 1;
246 }
247 else
248 {
249 /* Else, save its position and break out of the loop */
250 FirstPosition = i;
251 break;
252 }
253 }
254 }
255
256 /* Set up the first result string */
257 FirstPart->Buffer = Name.Buffer + SkipFirstSlash;
258 FirstPart->Length = (FirstPosition - SkipFirstSlash) * sizeof(WCHAR);
259 FirstPart->MaximumLength = FirstPart->Length;
260
261 /* And second one, if necessary */
262 if (FirstPosition < (Name.Length / sizeof(WCHAR)))
263 {
264 RemainingPart->Buffer = Name.Buffer + FirstPosition + 1;
265 RemainingPart->Length = Name.Length - (FirstPosition + 1) * sizeof(WCHAR);
266 RemainingPart->MaximumLength = RemainingPart->Length;
267 }
268 }
269
270 /*++
271 * @name FsRtlDoesNameContainWildCards
272 * @implemented
273 *
274 * Checks if the given string contains WildCards
275 *
276 * @param Name
277 * Pointer to a UNICODE_STRING containing Name to examine
278 *
279 * @return TRUE if Name contains wildcards, FALSE otherwise
280 *
281 * @remarks From Bo Branten's ntifs.h v12.
282 *
283 *--*/
284 BOOLEAN
285 NTAPI
286 FsRtlDoesNameContainWildCards(IN PUNICODE_STRING Name)
287 {
288 PWCHAR Ptr;
289 PAGED_CODE();
290
291 /* Loop through every character */
292 if (Name->Length)
293 {
294 Ptr = Name->Buffer + (Name->Length / sizeof(WCHAR)) - 1;
295 while ((Ptr >= Name->Buffer) && (*Ptr != L'\\'))
296 {
297 /* Check for Wildcard */
298 if (FsRtlIsUnicodeCharacterWild(*Ptr)) return TRUE;
299 Ptr--;
300 }
301 }
302
303 /* Nothing Found */
304 return FALSE;
305 }
306
307 /*++
308 * @name FsRtlIsNameInExpression
309 * @implemented
310 *
311 * Check if the Name string is in the Expression string.
312 *
313 * @param Expression
314 * The string in which we've to find Name. It can contain wildcards.
315 * If IgnoreCase is set to TRUE, this string MUST BE uppercase.
316 *
317 * @param Name
318 * The string to find. It cannot contain wildcards
319 *
320 * @param IgnoreCase
321 * If set to TRUE, case will be ignore with upcasing both strings
322 *
323 * @param UpcaseTable
324 * If not NULL, and if IgnoreCase is set to TRUE, it will be used to
325 * upcase the both strings
326 *
327 * @return TRUE if Name is in Expression, FALSE otherwise
328 *
329 * @remarks From Bo Branten's ntifs.h v12. This function should be
330 * rewritten to avoid recursion and better wildcard handling
331 * should be implemented (see FsRtlDoesNameContainWildCards).
332 *
333 *--*/
334 BOOLEAN
335 NTAPI
336 FsRtlIsNameInExpression(IN PUNICODE_STRING Expression,
337 IN PUNICODE_STRING Name,
338 IN BOOLEAN IgnoreCase,
339 IN PWCHAR UpcaseTable OPTIONAL)
340 {
341 BOOLEAN Result;
342 NTSTATUS Status;
343 UNICODE_STRING IntName;
344
345 if (IgnoreCase && !UpcaseTable)
346 {
347 Status = RtlUpcaseUnicodeString(&IntName, Name, TRUE);
348 if (Status != STATUS_SUCCESS)
349 {
350 ExRaiseStatus(Status);
351 }
352 Name = &IntName;
353 IgnoreCase = FALSE;
354 }
355 else
356 {
357 IntName.Buffer = NULL;
358 }
359
360 Result = FsRtlIsNameInExpressionPrivate(Expression, Name, IgnoreCase, UpcaseTable);
361
362 if (IntName.Buffer != NULL)
363 {
364 RtlFreeUnicodeString(&IntName);
365 }
366
367 return Result;
368 }