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 * Aleksey Bragin (aleksey@reactos.org)
12 /* INCLUDES ******************************************************************/
18 /* PRIVATE FUNCTIONS *********************************************************/
21 FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression
,
22 IN PUNICODE_STRING Name
,
23 IN BOOLEAN IgnoreCase
,
24 IN PWCHAR UpcaseTable OPTIONAL
)
26 USHORT ExpressionPosition
= 0, NamePosition
= 0, MatchingChars
, StarFound
= MAXUSHORT
;
27 UNICODE_STRING IntExpression
;
30 /* Check if we were given strings at all */
31 if (!Name
->Length
|| !Expression
->Length
)
33 /* Return TRUE if both strings are empty, otherwise FALSE */
34 if (Name
->Length
== 0 && Expression
->Length
== 0)
40 /* Check for a shortcut: just one wildcard */
41 if (Expression
->Length
== sizeof(WCHAR
))
43 if (Expression
->Buffer
[0] == L
'*')
47 ASSERT(!IgnoreCase
|| UpcaseTable
);
49 /* Another shortcut, wildcard followed by some string */
50 if (Expression
->Buffer
[0] == L
'*')
52 /* Copy Expression to our local variable */
53 IntExpression
= *Expression
;
55 /* Skip the first char */
56 IntExpression
.Buffer
++;
57 IntExpression
.Length
-= sizeof(WCHAR
);
59 /* Continue only if the rest of the expression does NOT contain
61 if (!FsRtlDoesNameContainWildCards(&IntExpression
))
63 /* Check for a degenerate case */
64 if (Name
->Length
< (Expression
->Length
- sizeof(WCHAR
)))
67 /* Calculate position */
68 NamePosition
= (Name
->Length
- IntExpression
.Length
) / sizeof(WCHAR
);
73 /* We can just do a byte compare */
74 return RtlEqualMemory(IntExpression
.Buffer
,
75 Name
->Buffer
+ NamePosition
,
76 IntExpression
.Length
);
80 /* Not so easy, need to upcase and check char by char */
81 for (ExpressionPosition
= 0; ExpressionPosition
< (IntExpression
.Length
/ sizeof(WCHAR
)); ExpressionPosition
++)
83 /* Assert that expression is already upcased! */
84 ASSERT(IntExpression
.Buffer
[ExpressionPosition
] == UpcaseTable
[IntExpression
.Buffer
[ExpressionPosition
]]);
86 /* Now compare upcased name char with expression */
87 if (UpcaseTable
[Name
->Buffer
[NamePosition
+ ExpressionPosition
]] !=
88 IntExpression
.Buffer
[ExpressionPosition
])
100 while (NamePosition
< Name
->Length
/ sizeof(WCHAR
) && ExpressionPosition
< Expression
->Length
/ sizeof(WCHAR
))
102 if ((Expression
->Buffer
[ExpressionPosition
] == (IgnoreCase
? UpcaseTable
[Name
->Buffer
[NamePosition
]] : Name
->Buffer
[NamePosition
])))
105 ExpressionPosition
++;
107 else if (StarFound
!= MAXUSHORT
&& (Expression
->Buffer
[StarFound
+ 1] == L
'*' ||
108 Expression
->Buffer
[StarFound
+ 1] == L
'?' || Expression
->Buffer
[StarFound
+ 1] == DOS_DOT
))
110 ExpressionPosition
= StarFound
+ 1;
111 switch (Expression
->Buffer
[ExpressionPosition
])
114 StarFound
= MAXUSHORT
;
118 if (++ExpressionPosition
== Expression
->Length
/ sizeof(WCHAR
))
120 NamePosition
= Name
->Length
/ sizeof(WCHAR
);
124 MatchingChars
= NamePosition
;
125 while (NamePosition
< Name
->Length
/ sizeof(WCHAR
) &&
126 (IgnoreCase
? UpcaseTable
[Name
->Buffer
[NamePosition
]] :
127 Name
->Buffer
[NamePosition
]) != Expression
->Buffer
[ExpressionPosition
])
132 if (NamePosition
- MatchingChars
> 0)
134 StarFound
= MAXUSHORT
;
139 while (NamePosition
< Name
->Length
/ sizeof(WCHAR
) &&
140 Name
->Buffer
[NamePosition
] != L
'.')
144 ExpressionPosition
++;
145 StarFound
= MAXUSHORT
;
149 /* Should never happen */
153 else if (Expression
->Buffer
[ExpressionPosition
] == L
'?' || (Expression
->Buffer
[ExpressionPosition
] == DOS_QM
) ||
154 (Expression
->Buffer
[ExpressionPosition
] == DOS_DOT
&& Name
->Buffer
[NamePosition
] == L
'.'))
157 ExpressionPosition
++;
158 StarFound
= MAXUSHORT
;
160 else if (Expression
->Buffer
[ExpressionPosition
] == L
'*')
162 StarFound
= ExpressionPosition
++;
163 if (ExpressionPosition
== Expression
->Length
/ sizeof(WCHAR
))
165 NamePosition
= Name
->Length
/ sizeof(WCHAR
);
169 else if (Expression
->Buffer
[ExpressionPosition
] == DOS_STAR
)
171 StarFound
= MAXUSHORT
;
172 MatchingChars
= NamePosition
;
173 while (MatchingChars
< Name
->Length
/ sizeof(WCHAR
))
175 if (Name
->Buffer
[MatchingChars
] == L
'.')
177 NamePosition
= MatchingChars
;
181 ExpressionPosition
++;
183 else if (StarFound
!= MAXUSHORT
)
185 ExpressionPosition
= StarFound
+ 1;
186 while (NamePosition
< Name
->Length
/ sizeof(WCHAR
) &&
187 (IgnoreCase
? UpcaseTable
[Name
->Buffer
[NamePosition
]] :
188 Name
->Buffer
[NamePosition
]) != Expression
->Buffer
[ExpressionPosition
])
198 if (ExpressionPosition
+ 1 == Expression
->Length
/ sizeof(WCHAR
) && NamePosition
== Name
->Length
/ sizeof(WCHAR
) &&
199 Expression
->Buffer
[ExpressionPosition
] == DOS_DOT
)
201 ExpressionPosition
++;
204 return (ExpressionPosition
== Expression
->Length
/ sizeof(WCHAR
) && NamePosition
== Name
->Length
/ sizeof(WCHAR
));
207 /* PUBLIC FUNCTIONS **********************************************************/
210 * @name FsRtlAreNamesEqual
213 * Compare two strings to check if they match
216 * First unicode string to compare
219 * Second unicode string to compare
222 * If TRUE, Case will be ignored when comparing strings
225 * Table for upcase letters. If NULL is given, system one will be used
227 * @return TRUE if the strings are equal
229 * @remarks From Bo Branten's ntifs.h v25.
234 FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1
,
235 IN PCUNICODE_STRING Name2
,
236 IN BOOLEAN IgnoreCase
,
237 IN PCWCH UpcaseTable OPTIONAL
)
239 UNICODE_STRING UpcaseName1
;
240 UNICODE_STRING UpcaseName2
;
241 BOOLEAN StringsAreEqual
, MemoryAllocated
= FALSE
;
246 /* Well, first check their size */
247 if (Name1
->Length
!= Name2
->Length
) return FALSE
;
249 /* Check if the caller didn't give an upcase table */
250 if ((IgnoreCase
) && !(UpcaseTable
))
252 /* Upcase the string ourselves */
253 Status
= RtlUpcaseUnicodeString(&UpcaseName1
, Name1
, TRUE
);
254 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
256 /* Upcase the second string too */
257 RtlUpcaseUnicodeString(&UpcaseName2
, Name2
, TRUE
);
258 Name1
= &UpcaseName1
;
259 Name2
= &UpcaseName2
;
261 /* Make sure we go through the path below, but free the strings */
263 MemoryAllocated
= TRUE
;
266 /* Do a case-sensitive search */
269 /* Use a raw memory compare */
270 StringsAreEqual
= RtlEqualMemory(Name1
->Buffer
,
274 /* Check if we allocated strings */
278 RtlFreeUnicodeString(&UpcaseName1
);
279 RtlFreeUnicodeString(&UpcaseName2
);
282 /* Return the equality */
283 return StringsAreEqual
;
287 /* Case in-sensitive search */
288 for (i
= 0; i
< Name1
->Length
/ sizeof(WCHAR
); i
++)
290 /* Check if the character matches */
291 if (UpcaseTable
[Name1
->Buffer
[i
]] != UpcaseTable
[Name2
->Buffer
[i
]])
293 /* Non-match found! */
298 /* We finished the loop so we are equal */
304 * @name FsRtlDissectName
307 * Dissects a given path name into first and remaining part.
310 * Unicode string to dissect.
313 * Pointer to user supplied UNICODE_STRING, that will later point
314 * to the first part of the original name.
316 * @param RemainingPart
317 * Pointer to user supplied UNICODE_STRING, that will later point
318 * to the remaining part of the original name.
323 * Name: \test1\test2\test3
325 * RemainingPart: test2\test3
330 FsRtlDissectName(IN UNICODE_STRING Name
,
331 OUT PUNICODE_STRING FirstPart
,
332 OUT PUNICODE_STRING RemainingPart
)
334 USHORT FirstPosition
, i
;
335 USHORT SkipFirstSlash
= 0;
338 /* Zero the strings before continuing */
339 RtlZeroMemory(FirstPart
, sizeof(UNICODE_STRING
));
340 RtlZeroMemory(RemainingPart
, sizeof(UNICODE_STRING
));
342 /* Just quit if the string is empty */
343 if (!Name
.Length
) return;
345 /* Find first backslash */
346 FirstPosition
= Name
.Length
/ sizeof(WCHAR
) ;
347 for (i
= 0; i
< Name
.Length
/ sizeof(WCHAR
); i
++)
349 /* If we found one... */
350 if (Name
.Buffer
[i
] == L
'\\')
352 /* If it begins string, just notice it and continue */
359 /* Else, save its position and break out of the loop */
366 /* Set up the first result string */
367 FirstPart
->Buffer
= Name
.Buffer
+ SkipFirstSlash
;
368 FirstPart
->Length
= (FirstPosition
- SkipFirstSlash
) * sizeof(WCHAR
);
369 FirstPart
->MaximumLength
= FirstPart
->Length
;
371 /* And second one, if necessary */
372 if (FirstPosition
< (Name
.Length
/ sizeof(WCHAR
)))
374 RemainingPart
->Buffer
= Name
.Buffer
+ FirstPosition
+ 1;
375 RemainingPart
->Length
= Name
.Length
- (FirstPosition
+ 1) * sizeof(WCHAR
);
376 RemainingPart
->MaximumLength
= RemainingPart
->Length
;
381 * @name FsRtlDoesNameContainWildCards
384 * Checks if the given string contains WildCards
387 * Pointer to a UNICODE_STRING containing Name to examine
389 * @return TRUE if Name contains wildcards, FALSE otherwise
391 * @remarks From Bo Branten's ntifs.h v12.
396 FsRtlDoesNameContainWildCards(IN PUNICODE_STRING Name
)
401 /* Loop through every character */
404 Ptr
= Name
->Buffer
+ (Name
->Length
/ sizeof(WCHAR
)) - 1;
405 while ((Ptr
>= Name
->Buffer
) && (*Ptr
!= L
'\\'))
407 /* Check for Wildcard */
408 if (FsRtlIsUnicodeCharacterWild(*Ptr
)) return TRUE
;
418 * @name FsRtlIsNameInExpression
421 * Check if the Name string is in the Expression string.
424 * The string in which we've to find Name. It can contain wildcards.
425 * If IgnoreCase is set to TRUE, this string MUST BE uppercase.
428 * The string to find. It cannot contain wildcards
431 * If set to TRUE, case will be ignore with upcasing both strings
434 * If not NULL, and if IgnoreCase is set to TRUE, it will be used to
435 * upcase the both strings
437 * @return TRUE if Name is in Expression, FALSE otherwise
439 * @remarks From Bo Branten's ntifs.h v12. This function should be
440 * rewritten to avoid recursion and better wildcard handling
441 * should be implemented (see FsRtlDoesNameContainWildCards).
446 FsRtlIsNameInExpression(IN PUNICODE_STRING Expression
,
447 IN PUNICODE_STRING Name
,
448 IN BOOLEAN IgnoreCase
,
449 IN PWCHAR UpcaseTable OPTIONAL
)
453 UNICODE_STRING IntName
;
455 if (IgnoreCase
&& !UpcaseTable
)
457 Status
= RtlUpcaseUnicodeString(&IntName
, Name
, TRUE
);
458 if (!NT_SUCCESS(Status
))
460 ExRaiseStatus(Status
);
467 IntName
.Buffer
= NULL
;
470 Result
= FsRtlIsNameInExpressionPrivate(Expression
, Name
, IgnoreCase
, UpcaseTable
);
472 if (IntName
.Buffer
!= NULL
)
474 RtlFreeUnicodeString(&IntName
);