]> git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/EnhancedFatDxe/FileName.c
Fix a typo when checking the 16-bit alignment of Unicode String.
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / FileName.c
1 /*++
2
3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12
13 Module Name:
14
15 FileName.c
16
17 Abstract:
18
19 Functions for manipulating file names
20
21 Revision History
22
23 --*/
24
25 #include "Fat.h"
26
27 BOOLEAN
28 FatCheckIs8Dot3Name (
29 IN CHAR16 *FileName,
30 OUT CHAR8 *File8Dot3Name
31 )
32 /*++
33
34 Routine Description:
35
36 This function checks whether the input FileName is a valid 8.3 short name.
37 If the input FileName is a valid 8.3, the output is the 8.3 short name;
38 otherwise, the output is the base tag of 8.3 short name.
39
40 Arguments:
41
42 FileName - The input unicode filename.
43 File8Dot3Name - The output ascii 8.3 short name or base tag of 8.3 short name.
44
45 Returns:
46
47 TRUE - The input unicode filename is a valid 8.3 short name.
48 FALSE - The input unicode filename is not a valid 8.3 short name.
49
50 --*/
51 {
52 BOOLEAN PossibleShortName;
53 CHAR16 *TempName;
54 CHAR16 *ExtendName;
55 CHAR16 *SeparateDot;
56 UINTN MainNameLen;
57 UINTN ExtendNameLen;
58
59 PossibleShortName = TRUE;
60 SeparateDot = NULL;
61 SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');
62 for (TempName = FileName; *TempName; TempName++) {
63 if (*TempName == L'.') {
64 SeparateDot = TempName;
65 }
66 }
67
68 if (SeparateDot == NULL) {
69 //
70 // Extended filename is not detected
71 //
72 MainNameLen = TempName - FileName;
73 ExtendName = TempName;
74 ExtendNameLen = 0;
75 } else {
76 //
77 // Extended filename is detected
78 //
79 MainNameLen = SeparateDot - FileName;
80 ExtendName = SeparateDot + 1;
81 ExtendNameLen = TempName - ExtendName;
82 }
83 //
84 // We scan the filename for the second time
85 // to check if there exists any extra blanks and dots
86 //
87 while (--TempName >= FileName) {
88 if ((*TempName == L'.' || *TempName == L' ') && (TempName != SeparateDot)) {
89 //
90 // There exist extra blanks and dots
91 //
92 PossibleShortName = FALSE;
93 }
94 }
95
96 if (MainNameLen == 0) {
97 PossibleShortName = FALSE;
98 }
99
100 if (MainNameLen > FAT_MAIN_NAME_LEN) {
101 PossibleShortName = FALSE;
102 MainNameLen = FAT_MAIN_NAME_LEN;
103 }
104
105 if (ExtendNameLen > FAT_EXTEND_NAME_LEN) {
106 PossibleShortName = FALSE;
107 ExtendNameLen = FAT_EXTEND_NAME_LEN;
108 }
109
110 if (FatStrToFat (FileName, MainNameLen, File8Dot3Name)) {
111 PossibleShortName = FALSE;
112 }
113
114 if (FatStrToFat (ExtendName, ExtendNameLen, File8Dot3Name + FAT_MAIN_NAME_LEN)) {
115 PossibleShortName = FALSE;
116 }
117
118 return PossibleShortName;
119 }
120
121 STATIC
122 UINTN
123 FatTrimAsciiTrailingBlanks (
124 IN CHAR8 *Name,
125 IN UINTN Len
126 )
127 /*++
128
129 Routine Description:
130
131 Trim the trailing blanks of fat name.
132
133 Arguments:
134
135 Name - The Char8 string needs to be trimed.
136 Len - The length of the fat name.
137
138 Returns:
139
140 The real length of the fat name after the trailing blanks are trimmed.
141
142 --*/
143 {
144 while (Len > 0 && Name[Len - 1] == ' ') {
145 Len--;
146 }
147
148 return Len;
149 }
150
151 VOID
152 FatNameToStr (
153 IN CHAR8 *FatName,
154 IN UINTN Len,
155 IN UINTN LowerCase,
156 OUT CHAR16 *Str
157 )
158 /*++
159
160 Routine Description:
161
162 Convert the ascii fat name to the unicode string and strip trailing spaces,
163 and if necessary, convert the unicode string to lower case.
164
165 Arguments:
166
167 FatName - The Char8 string needs to be converted.
168 Len - The length of the fat name.
169 LowerCase - Indicate whether to convert the string to lower case.
170 Str - The result of the convertion.
171
172 Returns:
173
174 None.
175
176 --*/
177 {
178 //
179 // First, trim the trailing blanks
180 //
181 Len = FatTrimAsciiTrailingBlanks (FatName, Len);
182 //
183 // Convert fat string to unicode string
184 //
185 FatFatToStr (Len, FatName, Str);
186
187 //
188 // If the name is to be lower cased, do it now
189 //
190 if (LowerCase != 0) {
191 FatStrLwr (Str);
192 }
193 }
194
195 VOID
196 FatCreate8Dot3Name (
197 IN FAT_OFILE *Parent,
198 IN FAT_DIRENT *DirEnt
199 )
200 /*++
201
202 Routine Description:
203
204 This function generates 8Dot3 name from user specified name for a newly created file.
205
206 Arguments:
207
208 Parent - The parent directory.
209 DirEnt - The directory entry whose 8Dot3Name needs to be generated.
210
211 Returns:
212
213 None.
214
215 --*/
216 {
217 CHAR8 *ShortName;
218 CHAR8 *ShortNameChar;
219 UINTN BaseTagLen;
220 UINTN Index;
221 UINTN Retry;
222 UINT8 Segment;
223 union {
224 UINT32 Crc;
225 struct HEX_DATA {
226 UINT8 Segment : HASH_VALUE_TAG_LEN;
227 } Hex[HASH_VALUE_TAG_LEN];
228 } HashValue;
229 //
230 // Make sure the whole directory has been loaded
231 //
232 ASSERT (Parent->ODir->EndOfDir);
233 ShortName = DirEnt->Entry.FileName;
234
235 //
236 // Trim trailing blanks of 8.3 name
237 //
238 BaseTagLen = FatTrimAsciiTrailingBlanks (ShortName, FAT_MAIN_NAME_LEN);
239 if (BaseTagLen > SPEC_BASE_TAG_LEN) {
240 BaseTagLen = SPEC_BASE_TAG_LEN;
241 }
242 //
243 // We first use the algorithm described by spec.
244 //
245 ShortNameChar = ShortName + BaseTagLen;
246 *ShortNameChar++ = '~';
247 *ShortNameChar = '1';
248 Retry = 0;
249 while (*FatShortNameHashSearch (Parent->ODir, ShortName) != NULL) {
250 *ShortNameChar = (CHAR8)(*ShortNameChar + 1);
251 if (++Retry == MAX_SPEC_RETRY) {
252 //
253 // We use new algorithm to generate 8.3 name
254 //
255 ASSERT (DirEnt->FileString != NULL);
256 gBS->CalculateCrc32 (DirEnt->FileString, StrSize (DirEnt->FileString), &HashValue.Crc);
257
258 if (BaseTagLen > HASH_BASE_TAG_LEN) {
259 BaseTagLen = HASH_BASE_TAG_LEN;
260 }
261
262 ShortNameChar = ShortName + BaseTagLen;
263 for (Index = 0; Index < HASH_VALUE_TAG_LEN; Index++) {
264 Segment = HashValue.Hex[Index].Segment;
265 if (Segment > 9) {
266 *ShortNameChar++ = (CHAR8)(Segment - 10 + 'A');
267 } else {
268 *ShortNameChar++ = (CHAR8)(Segment + '0');
269 }
270 }
271
272 *ShortNameChar++ = '~';
273 *ShortNameChar = '1';
274 }
275 }
276 }
277
278 STATIC
279 UINT8
280 FatCheckNameCase (
281 IN CHAR16 *Str,
282 IN UINT8 InCaseFlag
283 )
284 /*++
285
286 Routine Description:
287
288 Check the string is lower case or upper case
289 and it is used by fatname to dir entry count
290
291 Arguments:
292
293 Str - The string which needs to be checked.
294 InCaseFlag - The input case flag which is returned when the string is lower case.
295
296 Returns:
297
298 OutCaseFlag - The output case flag.
299
300 --*/
301 {
302 CHAR16 Buffer[FAT_MAIN_NAME_LEN + 1];
303 UINT8 OutCaseFlag;
304
305 ASSERT (StrSize (Str) <= sizeof (Buffer));
306 //
307 // Assume the case of input string is mixed
308 //
309 OutCaseFlag = FAT_CASE_MIXED;
310 //
311 // Lower case a copy of the string, if it matches the
312 // original then the string is lower case
313 //
314 StrCpy (Buffer, Str);
315 FatStrLwr (Buffer);
316 if (StrCmp (Str, Buffer) == 0) {
317 OutCaseFlag = InCaseFlag;
318 }
319 //
320 // Upper case a copy of the string, if it matches the
321 // original then the string is upper case
322 //
323 StrCpy (Buffer, Str);
324 FatStrUpr (Buffer);
325 if (StrCmp (Str, Buffer) == 0) {
326 OutCaseFlag = 0;
327 }
328
329 return OutCaseFlag;
330 }
331
332 VOID
333 FatSetCaseFlag (
334 IN FAT_DIRENT *DirEnt
335 )
336 /*++
337
338 Routine Description:
339
340 Set the caseflag value for the directory entry.
341
342 Arguments:
343
344 DirEnt - The logical directory entry whose caseflag value is to be set.
345
346 Returns:
347
348 None.
349
350 --*/
351 {
352 CHAR16 LfnBuffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1];
353 CHAR16 *TempCharPtr;
354 CHAR16 *ExtendName;
355 CHAR16 *FileNameCharPtr;
356 UINT8 CaseFlag;
357
358 ExtendName = NULL;
359 TempCharPtr = LfnBuffer;
360 FileNameCharPtr = DirEnt->FileString;
361 ASSERT (StrSize (DirEnt->FileString) <= sizeof (LfnBuffer));
362 while ((*TempCharPtr = *FileNameCharPtr) != 0) {
363 if (*TempCharPtr == L'.') {
364 ExtendName = TempCharPtr;
365 }
366
367 TempCharPtr++;
368 FileNameCharPtr++;
369 }
370
371 CaseFlag = 0;
372 if (ExtendName != NULL) {
373 *ExtendName = 0;
374 ExtendName++;
375 CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (ExtendName, FAT_CASE_EXT_LOWER));
376 }
377
378 CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (LfnBuffer, FAT_CASE_NAME_LOWER));
379 if ((CaseFlag & FAT_CASE_MIXED) == 0) {
380 //
381 // We just need one directory entry to store this file name entry
382 //
383 DirEnt->Entry.CaseFlag = CaseFlag;
384 } else {
385 //
386 // We need one extra directory entry to store the mixed case entry
387 //
388 DirEnt->Entry.CaseFlag = 0;
389 DirEnt->EntryCount++;
390 }
391 }
392
393 VOID
394 FatGetFileNameViaCaseFlag (
395 IN FAT_DIRENT *DirEnt,
396 OUT CHAR16 *FileString
397 )
398 /*++
399
400 Routine Description:
401
402 Convert the 8.3 ASCII fat name to cased Unicode string according to case flag.
403
404 Arguments:
405
406 DirEnt - The corresponding directory entry.
407 FileString - The output Unicode file name.
408
409 Returns:
410
411 None.
412
413 --*/
414 {
415 UINT8 CaseFlag;
416 CHAR8 *File8Dot3Name;
417 CHAR16 TempExt[1 + FAT_EXTEND_NAME_LEN + 1];
418 //
419 // Store file extension like ".txt"
420 //
421 CaseFlag = DirEnt->Entry.CaseFlag;
422 File8Dot3Name = DirEnt->Entry.FileName;
423
424 FatNameToStr (File8Dot3Name, FAT_MAIN_NAME_LEN, CaseFlag & FAT_CASE_NAME_LOWER, FileString);
425 FatNameToStr (File8Dot3Name + FAT_MAIN_NAME_LEN, FAT_EXTEND_NAME_LEN, CaseFlag & FAT_CASE_EXT_LOWER, &TempExt[1]);
426 if (TempExt[1] != 0) {
427 TempExt[0] = L'.';
428 StrCat (FileString, TempExt);
429 }
430 }
431
432 UINT8
433 FatCheckSum (
434 IN CHAR8 *ShortNameString
435 )
436 /*++
437
438 Routine Description:
439
440 Get the Check sum for a short name.
441
442 Arguments:
443
444 ShortNameString - The short name for a file.
445
446 Returns:
447
448 Sum - UINT8 checksum.
449
450 --*/
451 {
452 UINTN ShortNameLen;
453 UINT8 Sum;
454 Sum = 0;
455 for (ShortNameLen = FAT_NAME_LEN; ShortNameLen != 0; ShortNameLen--) {
456 Sum = (UINT8)(((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *ShortNameString++);
457 }
458
459 return Sum;
460 }
461
462 CHAR16 *
463 FatGetNextNameComponent (
464 IN CHAR16 *Path,
465 OUT CHAR16 *Name
466 )
467 /*++
468
469 Routine Description:
470
471 Takes Path as input, returns the next name component
472 in Name, and returns the position after Name (e.g., the
473 start of the next name component)
474
475 Arguments:
476
477 Path - The path of one file.
478 Name - The next name component in Path.
479
480 Returns:
481
482 The position after Name in the Path
483
484 --*/
485 {
486 while (*Path != 0 && *Path != PATH_NAME_SEPARATOR) {
487 *Name++ = *Path++;
488 }
489 *Name = 0;
490 //
491 // Get off of trailing path name separator
492 //
493 while (*Path == PATH_NAME_SEPARATOR) {
494 Path++;
495 }
496
497 return Path;
498 }
499
500 BOOLEAN
501 FatFileNameIsValid (
502 IN CHAR16 *InputFileName,
503 OUT CHAR16 *OutputFileName
504 )
505 /*++
506
507 Routine Description:
508
509 Check whether the IFileName is valid long file name. If the IFileName is a valid
510 long file name, then we trim the possible leading blanks and leading/trailing dots.
511 the trimmed filename is stored in OutputFileName
512
513 Arguments:
514
515 InputFileName - The input file name.
516 OutputFileName - The output file name.
517
518
519 Returns:
520
521 TRUE - The InputFileName is a valid long file name.
522 FALSE - The InputFileName is not a valid long file name.
523
524 --*/
525 {
526 CHAR16 *TempNamePointer;
527 CHAR16 TempChar;
528 //
529 // Trim Leading blanks
530 //
531 while (*InputFileName == L' ') {
532 InputFileName++;
533 }
534
535 TempNamePointer = OutputFileName;
536 while (*InputFileName != 0) {
537 *TempNamePointer++ = *InputFileName++;
538 }
539 //
540 // Trim Trailing blanks and dots
541 //
542 while (TempNamePointer > OutputFileName) {
543 TempChar = *(TempNamePointer - 1);
544 if (TempChar != L' ' && TempChar != L'.') {
545 break;
546 }
547
548 TempNamePointer--;
549 }
550
551 *TempNamePointer = 0;
552
553 //
554 // Per FAT Spec the file name should meet the following criteria:
555 // C1. Length (FileLongName) <= 255
556 // C2. Length (X:FileFullPath<NUL>) <= 260
557 // Here we check C1.
558 //
559 if (TempNamePointer - OutputFileName > EFI_FILE_STRING_LENGTH) {
560 return FALSE;
561 }
562 //
563 // See if there is any illegal characters within the name
564 //
565 do {
566 if (*OutputFileName < 0x20 ||
567 *OutputFileName == '\"' ||
568 *OutputFileName == '*' ||
569 *OutputFileName == '/' ||
570 *OutputFileName == ':' ||
571 *OutputFileName == '<' ||
572 *OutputFileName == '>' ||
573 *OutputFileName == '?' ||
574 *OutputFileName == '\\' ||
575 *OutputFileName == '|'
576 ) {
577 return FALSE;
578 }
579
580 OutputFileName++;
581 } while (*OutputFileName != 0);
582 return TRUE;
583 }