]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - FatPkg/EnhancedFatDxe/FileName.c
UefiCpuPkg/PiSmmCpuDxeSmm: patch "gSmiStack" with PatchInstructionX86()
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / FileName.c
... / ...
CommitLineData
1/** @file\r
2 Functions for manipulating file names.\r
3\r
4Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials are licensed and made available\r
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
13**/\r
14\r
15#include "Fat.h"\r
16\r
17/**\r
18\r
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
22\r
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
25\r
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
28\r
29**/\r
30BOOLEAN\r
31FatCheckIs8Dot3Name (\r
32 IN CHAR16 *FileName,\r
33 OUT CHAR8 *File8Dot3Name\r
34 )\r
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
46 for (TempName = FileName; *TempName != '\0'; TempName++) {\r
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
105/**\r
106\r
107 Trim the trailing blanks of fat name.\r
108\r
109 @param Name - The Char8 string needs to be trimed.\r
110 @param Len - The length of the fat name.\r
111\r
112 The real length of the fat name after the trailing blanks are trimmed.\r
113\r
114**/\r
115STATIC\r
116UINTN\r
117FatTrimAsciiTrailingBlanks (\r
118 IN CHAR8 *Name,\r
119 IN UINTN Len\r
120 )\r
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
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
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
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
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
173VOID\r
174FatCreate8Dot3Name (\r
175 IN FAT_OFILE *Parent,\r
176 IN FAT_DIRENT *DirEnt\r
177 )\r
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
240/**\r
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
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
247\r
248 @retval OutCaseFlag - The output case flag.\r
249\r
250**/\r
251STATIC\r
252UINT8\r
253FatCheckNameCase (\r
254 IN CHAR16 *Str,\r
255 IN UINT8 InCaseFlag\r
256 )\r
257{\r
258 CHAR16 Buffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1];\r
259 UINT8 OutCaseFlag;\r
260\r
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
269 StrCpyS (Buffer, ARRAY_SIZE (Buffer), Str);\r
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
278 StrCpyS (Buffer, ARRAY_SIZE (Buffer), Str);\r
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
287/**\r
288\r
289 Set the caseflag value for the directory entry.\r
290\r
291 @param DirEnt - The logical directory entry whose caseflag value is to be set.\r
292\r
293**/\r
294VOID\r
295FatSetCaseFlag (\r
296 IN FAT_DIRENT *DirEnt\r
297 )\r
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
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
349VOID\r
350FatGetFileNameViaCaseFlag (\r
351 IN FAT_DIRENT *DirEnt,\r
352 IN OUT CHAR16 *FileString,\r
353 IN UINTN FileStringMax\r
354 )\r
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
369 StrCatS (FileString, FileStringMax, TempExt);\r
370 }\r
371}\r
372\r
373/**\r
374\r
375 Get the Check sum for a short name.\r
376\r
377 @param ShortNameString - The short name for a file.\r
378\r
379 @retval Sum - UINT8 checksum.\r
380\r
381**/\r
382UINT8\r
383FatCheckSum (\r
384 IN CHAR8 *ShortNameString\r
385 )\r
386{\r
387 UINTN ShortNameLen;\r
388 UINT8 Sum;\r
389 Sum = 0;\r
390 for (ShortNameLen = FAT_NAME_LEN; ShortNameLen != 0; ShortNameLen--) {\r
391 Sum = (UINT8)((((Sum & 1) != 0) ? 0x80 : 0) + (Sum >> 1) + *ShortNameString++);\r
392 }\r
393\r
394 return Sum;\r
395}\r
396\r
397/**\r
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
403 @param Path - The path of one file.\r
404 @param Name - The next name component in Path.\r
405\r
406 The position after Name in the Path\r
407\r
408**/\r
409CHAR16 *\r
410FatGetNextNameComponent (\r
411 IN CHAR16 *Path,\r
412 OUT CHAR16 *Name\r
413 )\r
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
429/**\r
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
435 @param InputFileName - The input file name.\r
436 @param OutputFileName - The output file name.\r
437\r
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
440\r
441**/\r
442BOOLEAN\r
443FatFileNameIsValid (\r
444 IN CHAR16 *InputFileName,\r
445 OUT CHAR16 *OutputFileName\r
446 )\r
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