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