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