VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/FatPkg/EnhancedFatDxe/FileName.c@ 107064

Last change on this file since 107064 was 99404, checked in by vboxsync, 23 months ago

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette