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 USHORT FirstPosition
, i
;
50 USHORT SkipFirstSlash
= 0;
53 /* Zero the strings before continuing */
54 RtlZeroMemory(FirstPart
, sizeof(ANSI_STRING
));
55 RtlZeroMemory(RemainingPart
, sizeof(ANSI_STRING
));
57 /* Just quit if the string is empty */
58 if (!Name
.Length
) return;
60 /* Find first backslash */
61 FirstPosition
= Name
.Length
;
62 for (i
= 0; i
< Name
.Length
; i
++)
64 /* First make sure the character it's not the Lead DBCS */
65 if (FsRtlIsLeadDbcsCharacter(Name
.Buffer
[i
]))
69 /* If we found one... */
70 else if (Name
.Buffer
[i
] == '\\')
72 /* If it begins string, just notice it and continue */
79 /* Else, save its position and break out of the loop */
86 /* Set up the first result string */
87 FirstPart
->Buffer
= Name
.Buffer
+ SkipFirstSlash
;
88 FirstPart
->Length
= (FirstPosition
- SkipFirstSlash
);
89 FirstPart
->MaximumLength
= FirstPart
->Length
;
91 /* And second one, if necessary */
92 if (FirstPosition
< (Name
.Length
))
94 RemainingPart
->Buffer
= Name
.Buffer
+ FirstPosition
+ 1;
95 RemainingPart
->Length
= Name
.Length
- (FirstPosition
+ 1);
96 RemainingPart
->MaximumLength
= RemainingPart
->Length
;
101 * @name FsRtlDoesDbcsContainWildCards
104 * Returns TRUE if the given DbcsName contains wildcards such as *, ?,
105 * ANSI_DOS_STAR, ANSI_DOS_DOT, and ANSI_DOS_QM
110 * @return TRUE if there are wildcards, FALSE otherwise
117 FsRtlDoesDbcsContainWildCards(IN PANSI_STRING Name
)
122 /* Check every character */
123 for (i
= 0; i
< Name
->Length
; i
++)
125 /* First make sure it's not the Lead DBCS */
126 if (FsRtlIsLeadDbcsCharacter(Name
->Buffer
[i
]))
130 else if (FsRtlIsAnsiCharacterWild(Name
->Buffer
[i
]))
132 /* Now return if it has a wildcard */
137 /* We didn't return above...so none found */
142 * @name FsRtlIsDbcsInExpression
145 * Check if the Name string is in the Expression string.
148 * The string in which we've to find Name. It can contains wildcards
151 * The string to find. It cannot contain wildcards.
153 * @return TRUE if Name is found in Expression, FALSE otherwise
160 FsRtlIsDbcsInExpression(IN PANSI_STRING Expression
,
161 IN PANSI_STRING Name
)
163 USHORT ExpressionPosition
= 0, NamePosition
= 0, MatchingChars
, StarFound
= MAXUSHORT
;
166 ASSERT(Name
->Length
);
167 ASSERT(Expression
->Length
);
168 ASSERT(!FsRtlDoesDbcsContainWildCards(Name
));
170 while (NamePosition
< Name
->Length
&& ExpressionPosition
< Expression
->Length
)
172 if ((Expression
->Buffer
[ExpressionPosition
] == Name
->Buffer
[NamePosition
]))
175 ExpressionPosition
++;
177 else if (StarFound
!= MAXUSHORT
&& (Expression
->Buffer
[StarFound
+ 1] == '*' ||
178 Expression
->Buffer
[StarFound
+ 1] == '?' || Expression
->Buffer
[StarFound
+ 1] == ANSI_DOS_DOT
))
180 ExpressionPosition
= StarFound
+ 1;
181 switch (Expression
->Buffer
[ExpressionPosition
])
184 StarFound
= MAXUSHORT
;
188 if (++ExpressionPosition
== Expression
->Length
)
190 NamePosition
= Name
->Length
;
194 MatchingChars
= NamePosition
;
195 while (NamePosition
< Name
->Length
&&
196 Name
->Buffer
[NamePosition
] != Expression
->Buffer
[ExpressionPosition
])
201 if (NamePosition
- MatchingChars
> 0)
203 StarFound
= MAXUSHORT
;
208 while (NamePosition
< Name
->Length
&& Name
->Buffer
[NamePosition
] != '.')
212 ExpressionPosition
++;
213 StarFound
= MAXUSHORT
;
217 /* Should never happen */
221 else if ((Expression
->Buffer
[ExpressionPosition
] == '?') || (Expression
->Buffer
[ExpressionPosition
] == ANSI_DOS_QM
) ||
222 (Expression
->Buffer
[ExpressionPosition
] == ANSI_DOS_DOT
&& Name
->Buffer
[NamePosition
] == '.'))
225 ExpressionPosition
++;
226 StarFound
= MAXUSHORT
;
228 else if (Expression
->Buffer
[ExpressionPosition
] == '*')
230 StarFound
= ExpressionPosition
++;
231 if (ExpressionPosition
== Expression
->Length
)
233 NamePosition
= Name
->Length
;
237 else if (Expression
->Buffer
[ExpressionPosition
] == ANSI_DOS_STAR
)
239 StarFound
= MAXUSHORT
;
240 MatchingChars
= NamePosition
;
241 while (MatchingChars
< Name
->Length
)
243 if (Name
->Buffer
[MatchingChars
] == '.')
245 NamePosition
= MatchingChars
;
249 ExpressionPosition
++;
251 else if (StarFound
!= MAXUSHORT
)
253 ExpressionPosition
= StarFound
+ 1;
254 while (NamePosition
< Name
->Length
&&
255 Name
->Buffer
[NamePosition
] != Expression
->Buffer
[ExpressionPosition
])
265 if (ExpressionPosition
+ 1 == Expression
->Length
&& NamePosition
== Name
->Length
&&
266 Expression
->Buffer
[ExpressionPosition
] == ANSI_DOS_DOT
)
268 ExpressionPosition
++;
271 return (ExpressionPosition
== Expression
->Length
&& NamePosition
== Name
->Length
);
275 * @name FsRtlIsFatDbcsLegal
278 * Returns TRUE if the given DbcsName is a valid FAT filename (in 8.3)
281 * The filename to check. It can also contains pathname.
283 * @param WildCardsPermissible
284 * If this is set to FALSE and if filename contains wildcard, the function
287 * @param PathNamePermissible
288 * If this is set to FALSE and if the filename comes with a pathname, the
291 * @param LeadingBackslashPermissible
292 * If this is set to FALSE and if the filename starts with a backslash, the
295 * @return TRUE if the DbcsName is legal, FALSE otherwise
302 FsRtlIsFatDbcsLegal(IN ANSI_STRING DbcsName
,
303 IN BOOLEAN WildCardsPermissible
,
304 IN BOOLEAN PathNamePermissible
,
305 IN BOOLEAN LeadingBackslashPermissible
)
307 ANSI_STRING FirstPart
, RemainingPart
, Name
;
312 /* Just quit if the string is empty */
313 if (!DbcsName
.Length
)
316 /* DbcsName wasn't supposed to be started with \ */
317 if (!LeadingBackslashPermissible
&& DbcsName
.Buffer
[0] == '\\')
319 /* DbcsName was allowed to be started with \, but now, remove it */
320 else if (LeadingBackslashPermissible
&& DbcsName
.Buffer
[0] == '\\')
322 DbcsName
.Buffer
= DbcsName
.Buffer
+ 1;
323 DbcsName
.Length
= DbcsName
.Length
- 1;
324 DbcsName
.MaximumLength
= DbcsName
.MaximumLength
- 1;
327 /* Extract first part of the DbcsName to work on */
328 FsRtlDissectDbcs(DbcsName
, &FirstPart
, &RemainingPart
);
329 while (FirstPart
.Length
> 0)
331 /* Reset dots count */
334 /* Accept special filename if wildcards are allowed */
335 if (WildCardsPermissible
&& (FirstPart
.Length
== 1 || FirstPart
.Length
== 2) && FirstPart
.Buffer
[0] == '.')
337 if (FirstPart
.Length
== 2)
339 if (FirstPart
.Buffer
[1] == '.')
350 /* Filename must be 8.3 filename */
351 if (FirstPart
.Length
< 3 || FirstPart
.Length
> 12)
354 /* Now, we will parse the filename to find everything bad in */
355 for (i
= 0; i
< FirstPart
.Length
; i
++)
357 /* First make sure the character it's not the Lead DBCS */
358 if (FsRtlIsLeadDbcsCharacter(FirstPart
.Buffer
[i
]))
360 if (i
== (FirstPart
.Length
) - 1)
364 /* Then check for bad characters */
365 else if (!FsRtlIsAnsiCharacterLegalFat(FirstPart
.Buffer
[i
], WildCardsPermissible
))
369 else if (FirstPart
.Buffer
[i
] == '.')
371 /* Filename can only contain one dot */
377 /* We mustn't have spaces before dot or at the end of the filename
378 * and no dot at the beginning of the filename */
379 if ((i
== (FirstPart
.Length
) - 1) || i
== 0)
383 if (FirstPart
.Buffer
[i
- 1] == ' ')
386 /* Filename must be 8.3 filename and not 3.8 filename */
387 if ((FirstPart
.Length
- 1) - i
> 3)
392 /* Filename mustn't finish with a space */
393 if (FirstPart
.Buffer
[FirstPart
.Length
- 1] == ' ')
397 /* Preparing next loop */
398 Name
.Buffer
= RemainingPart
.Buffer
;
399 Name
.Length
= RemainingPart
.Length
;
400 Name
.MaximumLength
= RemainingPart
.MaximumLength
;
402 /* Call once again our dissect function */
403 FsRtlDissectDbcs(Name
, &FirstPart
, &RemainingPart
);
405 /* We found a pathname, it wasn't allowed */
406 if (FirstPart
.Length
> 0 && !PathNamePermissible
)
413 * @name FsRtlIsHpfsDbcsLegal
416 * Returns TRUE if the given DbcsName is a valid HPFS filename
419 * The filename to check. It can also contains pathname.
421 * @param WildCardsPermissible
422 * If this is set to FALSE and if filename contains wildcard, the function
425 * @param PathNamePermissible
426 * If this is set to FALSE and if the filename comes with a pathname, the
429 * @param LeadingBackslashPermissible
430 * If this is set to FALSE and if the filename starts with a backslash, the
433 * @return TRUE if the DbcsName is legal, FALSE otherwise
440 FsRtlIsHpfsDbcsLegal(IN ANSI_STRING DbcsName
,
441 IN BOOLEAN WildCardsPermissible
,
442 IN BOOLEAN PathNamePermissible
,
443 IN BOOLEAN LeadingBackslashPermissible
)
445 ANSI_STRING FirstPart
, RemainingPart
, Name
;
449 /* Just quit if the string is empty */
450 if (!DbcsName
.Length
)
453 /* DbcsName wasn't supposed to be started with \ */
454 if (!LeadingBackslashPermissible
&& DbcsName
.Buffer
[0] == '\\')
456 /* DbcsName was allowed to be started with \, but now, remove it */
457 else if (LeadingBackslashPermissible
&& DbcsName
.Buffer
[0] == '\\')
459 DbcsName
.Buffer
= DbcsName
.Buffer
+ 1;
460 DbcsName
.Length
= DbcsName
.Length
- 1;
461 DbcsName
.MaximumLength
= DbcsName
.MaximumLength
- 1;
464 /* Extract first part of the DbcsName to work on */
465 FsRtlDissectDbcs(DbcsName
, &FirstPart
, &RemainingPart
);
466 while (FirstPart
.Length
> 0)
468 /* Accept special filename if wildcards are allowed */
469 if (WildCardsPermissible
&& (FirstPart
.Length
== 1 || FirstPart
.Length
== 2) && FirstPart
.Buffer
[0] == '.')
471 if (FirstPart
.Length
== 2)
473 if (FirstPart
.Buffer
[1] == '.')
484 /* Filename must be 255 bytes maximum */
485 if (FirstPart
.Length
> 255)
488 /* Now, we will parse the filename to find everything bad in */
489 for (i
= 0; i
< FirstPart
.Length
; i
++)
491 /* First make sure the character it's not the Lead DBCS */
492 if (FsRtlIsLeadDbcsCharacter(FirstPart
.Buffer
[i
]))
494 if (i
== (FirstPart
.Length
) - 1)
498 /* Then check for bad characters */
499 else if (!FsRtlIsAnsiCharacterLegalHpfs(FirstPart
.Buffer
[i
], WildCardsPermissible
))
505 /* Filename mustn't finish with a space or a dot */
506 if ((FirstPart
.Buffer
[FirstPart
.Length
- 1] == ' ') ||
507 (FirstPart
.Buffer
[FirstPart
.Length
- 1] == '.'))
511 /* Preparing next loop */
512 Name
.Buffer
= RemainingPart
.Buffer
;
513 Name
.Length
= RemainingPart
.Length
;
514 Name
.MaximumLength
= RemainingPart
.MaximumLength
;
516 /* Call once again our dissect function */
517 FsRtlDissectDbcs(Name
, &FirstPart
, &RemainingPart
);
519 /* We found a pathname, it wasn't allowed */
520 if (FirstPart
.Length
> 0 && !PathNamePermissible
)