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