2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/name.c
5 * PURPOSE: Provides DBCS parsing and other support routines for FSDs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
10 /* INCLUDES ******************************************************************/
16 /* PUBLIC FUNCTIONS **********************************************************/
19 * @name FsRtlDissectDbcs
22 * Dissects a given path name into first and remaining part.
25 * ANSI string to dissect.
28 * Pointer to user supplied ANSI_STRING, that will later point
29 * to the first part of the original name.
31 * @param RemainingPart
32 * Pointer to user supplied ANSI_STRING, that will later point
33 * to the remaining part of the original name.
38 * Name: \test1\test2\test3
40 * RemainingPart: test2\test3
45 FsRtlDissectDbcs(IN ANSI_STRING Name
,
46 OUT PANSI_STRING FirstPart
,
47 OUT PANSI_STRING RemainingPart
)
49 ULONG FirstPosition
, i
;
50 ULONG SkipFirstSlash
= 0;
52 /* Zero the strings before continuing */
53 RtlZeroMemory(FirstPart
, sizeof(ANSI_STRING
));
54 RtlZeroMemory(RemainingPart
, sizeof(ANSI_STRING
));
56 /* Just quit if the string is empty */
57 if (!Name
.Length
) return;
59 /* Find first backslash */
60 FirstPosition
= Name
.Length
;
61 for (i
= 0; i
< Name
.Length
; i
++)
63 /* First make sure the character it's not the Lead DBCS */
64 if (FsRtlIsLeadDbcsCharacter(Name
.Buffer
[i
]))
68 /* If we found one... */
69 else if (Name
.Buffer
[i
] == '\\')
71 /* If it begins string, just notice it and continue */
78 /* Else, save its position and break out of the loop */
85 /* Set up the first result string */
86 FirstPart
->Buffer
= Name
.Buffer
+ SkipFirstSlash
;
87 FirstPart
->Length
= (FirstPosition
- SkipFirstSlash
);
88 FirstPart
->MaximumLength
= FirstPart
->Length
;
90 /* And second one, if necessary */
91 if (FirstPosition
< (Name
.Length
))
93 RemainingPart
->Buffer
= Name
.Buffer
+ FirstPosition
+ 1;
94 RemainingPart
->Length
= Name
.Length
- (FirstPosition
+ 1);
95 RemainingPart
->MaximumLength
= RemainingPart
->Length
;
100 * @name FsRtlDoesDbcsContainWildCards
103 * Returns TRUE if the given DbcsName contains wildcards such as *, ?,
104 * ANSI_DOS_STAR, ANSI_DOS_DOT, and ANSI_DOS_QM
109 * @return TRUE if there are wildcards, FALSE otherwise
116 FsRtlDoesDbcsContainWildCards(IN PANSI_STRING Name
)
120 /* Check every character */
121 for (i
= 0; i
< Name
->Length
; i
++)
123 /* First make sure it's not the Lead DBCS */
124 if (FsRtlIsLeadDbcsCharacter(Name
->Buffer
[i
]))
128 else if (FsRtlIsAnsiCharacterWild(Name
->Buffer
[i
]))
130 /* Now return if it has a wildcard */
135 /* We didn't return above...so none found */
140 * @name FsRtlIsDbcsInExpression
143 * Check if the Name string is in the Expression string.
146 * The string in which we've to find Name. It can contains wildcards
149 * The string to find. It cannot contain wildcards.
151 * @return TRUE if Name is found in Expression, FALSE otherwise
158 FsRtlIsDbcsInExpression(IN PANSI_STRING Expression
,
159 IN PANSI_STRING Name
)
161 ULONG ExpressionPosition
, NamePosition
, MatchingChars
= 0;
163 ASSERT(!FsRtlDoesDbcsContainWildCards(Name
));
165 /* One can't be null, both can be */
166 if (!Expression
->Length
|| !Name
->Length
)
168 return !(Expression
->Length
^ Name
->Length
);
171 for (ExpressionPosition
= 0; ExpressionPosition
< Expression
->Length
; ExpressionPosition
++)
173 if ((Expression
->Buffer
[ExpressionPosition
] == Name
->Buffer
[MatchingChars
]) ||
174 (Expression
->Buffer
[ExpressionPosition
] == '?') ||
175 (Expression
->Buffer
[ExpressionPosition
] == ANSI_DOS_QM
) ||
176 (Expression
->Buffer
[ExpressionPosition
] == ANSI_DOS_DOT
&&
177 (Name
->Buffer
[MatchingChars
] == '.' || Name
->Buffer
[MatchingChars
] == '0')))
181 else if (Expression
->Buffer
[ExpressionPosition
] == '*')
183 MatchingChars
= Name
->Length
;
185 else if (Expression
->Buffer
[ExpressionPosition
] == ANSI_DOS_STAR
)
187 for (NamePosition
= MatchingChars
; NamePosition
< Name
->Length
; NamePosition
++)
189 if (Name
->Buffer
[NamePosition
] == '.')
191 MatchingChars
= NamePosition
;
200 if (MatchingChars
== Name
->Length
)
210 * @name FsRtlIsFatDbcsLegal
213 * Returns TRUE if the given DbcsName is a valid FAT filename (in 8.3)
216 * The filename to check. It can also contains pathname.
218 * @param WildCardsPermissible
219 * If this is set to FALSE and if filename contains wildcard, the function
222 * @param PathNamePermissible
223 * If this is set to FALSE and if the filename comes with a pathname, the
226 * @param LeadingBackslashPermissible
227 * If this is set to FALSE and if the filename starts with a backslash, the
230 * @return TRUE if the DbcsName is legal, FALSE otherwise
237 FsRtlIsFatDbcsLegal(IN ANSI_STRING DbcsName
,
238 IN BOOLEAN WildCardsPermissible
,
239 IN BOOLEAN PathNamePermissible
,
240 IN BOOLEAN LeadingBackslashPermissible
)
242 ANSI_STRING FirstPart
, RemainingPart
, Name
;
246 /* Just quit if the string is empty */
247 if (!DbcsName
.Length
)
250 /* DbcsName wasn't supposed to be started with \ */
251 if (!LeadingBackslashPermissible
&& DbcsName
.Buffer
[0] == '\\')
253 /* DbcsName was allowed to be started with \, but now, remove it */
254 else if (LeadingBackslashPermissible
&& DbcsName
.Buffer
[0] == '\\')
256 DbcsName
.Buffer
= DbcsName
.Buffer
+ 1;
257 DbcsName
.Length
= DbcsName
.Length
- 1;
258 DbcsName
.MaximumLength
= DbcsName
.MaximumLength
- 1;
261 /* Extract first part of the DbcsName to work on */
262 FsRtlDissectDbcs(DbcsName
, &FirstPart
, &RemainingPart
);
263 while (FirstPart
.Length
> 0)
265 /* Reset dots count */
268 /* Accept special filename if wildcards are allowed */
269 if (WildCardsPermissible
&& (FirstPart
.Length
== 1 || FirstPart
.Length
== 2) && FirstPart
.Buffer
[0] == '.')
271 if (FirstPart
.Length
== 2)
273 if (FirstPart
.Buffer
[1] == '.')
284 /* Filename must be 8.3 filename */
285 if (FirstPart
.Length
< 3 || FirstPart
.Length
> 12)
288 /* Now, we will parse the filename to find everything bad in */
289 for (i
= 0; i
< FirstPart
.Length
; i
++)
291 /* First make sure the character it's not the Lead DBCS */
292 if (FsRtlIsLeadDbcsCharacter(FirstPart
.Buffer
[i
]))
294 if (i
== (FirstPart
.Length
) - 1)
298 /* Then check for bad characters */
299 else if (!FsRtlIsAnsiCharacterLegalFat(FirstPart
.Buffer
[i
], WildCardsPermissible
))
303 else if (FirstPart
.Buffer
[i
] == '.')
305 /* Filename can only contain one dot */
311 /* We mustn't have spaces before dot or at the end of the filename
312 * and no dot at the beginning of the filename */
313 if ((i
== (FirstPart
.Length
) - 1) || i
== 0)
317 if (FirstPart
.Buffer
[i
- 1] == ' ')
320 /* Filename must be 8.3 filename and not 3.8 filename */
321 if ((FirstPart
.Length
- 1) - i
> 3)
326 /* Filename mustn't finish with a space */
327 if (FirstPart
.Buffer
[FirstPart
.Length
- 1] == ' ')
331 /* Preparing next loop */
332 Name
.Buffer
= RemainingPart
.Buffer
;
333 Name
.Length
= RemainingPart
.Length
;
334 Name
.MaximumLength
= RemainingPart
.MaximumLength
;
336 /* Call once again our dissect function */
337 FsRtlDissectDbcs(Name
, &FirstPart
, &RemainingPart
);
339 /* We found a pathname, it wasn't allowed */
340 if (FirstPart
.Length
> 0 && !PathNamePermissible
)
347 * @name FsRtlIsHpfsDbcsLegal
350 * Returns TRUE if the given DbcsName is a valid HPFS filename
353 * The filename to check. It can also contains pathname.
355 * @param WildCardsPermissible
356 * If this is set to FALSE and if filename contains wildcard, the function
359 * @param PathNamePermissible
360 * If this is set to FALSE and if the filename comes with a pathname, the
363 * @param LeadingBackslashPermissible
364 * If this is set to FALSE and if the filename starts with a backslash, the
367 * @return TRUE if the DbcsName is legal, FALSE otherwise
374 FsRtlIsHpfsDbcsLegal(IN ANSI_STRING DbcsName
,
375 IN BOOLEAN WildCardsPermissible
,
376 IN BOOLEAN PathNamePermissible
,
377 IN BOOLEAN LeadingBackslashPermissible
)
379 ANSI_STRING FirstPart
, RemainingPart
, Name
;
382 /* Just quit if the string is empty */
383 if (!DbcsName
.Length
)
386 /* DbcsName wasn't supposed to be started with \ */
387 if (!LeadingBackslashPermissible
&& DbcsName
.Buffer
[0] == '\\')
389 /* DbcsName was allowed to be started with \, but now, remove it */
390 else if (LeadingBackslashPermissible
&& DbcsName
.Buffer
[0] == '\\')
392 DbcsName
.Buffer
= DbcsName
.Buffer
+ 1;
393 DbcsName
.Length
= DbcsName
.Length
- 1;
394 DbcsName
.MaximumLength
= DbcsName
.MaximumLength
- 1;
397 /* Extract first part of the DbcsName to work on */
398 FsRtlDissectDbcs(DbcsName
, &FirstPart
, &RemainingPart
);
399 while (FirstPart
.Length
> 0)
401 /* Accept special filename if wildcards are allowed */
402 if (WildCardsPermissible
&& (FirstPart
.Length
== 1 || FirstPart
.Length
== 2) && FirstPart
.Buffer
[0] == '.')
404 if (FirstPart
.Length
== 2)
406 if (FirstPart
.Buffer
[1] == '.')
417 /* Filename must be 255 bytes maximum */
418 if (FirstPart
.Length
> 255)
421 /* Now, we will parse the filename to find everything bad in */
422 for (i
= 0; i
< FirstPart
.Length
; i
++)
424 /* First make sure the character it's not the Lead DBCS */
425 if (FsRtlIsLeadDbcsCharacter(FirstPart
.Buffer
[i
]))
427 if (i
== (FirstPart
.Length
) - 1)
431 /* Then check for bad characters */
432 else if (!!FsRtlIsAnsiCharacterLegalHpfs(FirstPart
.Buffer
[i
], WildCardsPermissible
))
438 /* Filename mustn't finish with a space or a dot */
439 if ((FirstPart
.Buffer
[FirstPart
.Length
- 1] == ' ') ||
440 (FirstPart
.Buffer
[FirstPart
.Length
- 1] == '.'))
444 /* Preparing next loop */
445 Name
.Buffer
= RemainingPart
.Buffer
;
446 Name
.Length
= RemainingPart
.Length
;
447 Name
.MaximumLength
= RemainingPart
.MaximumLength
;
449 /* Call once again our dissect function */
450 FsRtlDissectDbcs(Name
, &FirstPart
, &RemainingPart
);
452 /* We found a pathname, it wasn't allowed */
453 if (FirstPart
.Length
> 0 && !PathNamePermissible
)