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