FileName.c 12 KB

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