DirectoryManage.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414
  1. /** @file
  2. Functions for performing directory entry io.
  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. Get a directory entry from disk for the Ofile.
  9. @param Parent - The parent of the OFile which need to update.
  10. @param IoMode - Indicate whether to read directory entry or write directory entry.
  11. @param EntryPos - The position of the directory entry to be accessed.
  12. @param Entry - The directory entry read or written.
  13. @retval EFI_SUCCESS - Access the directory entry successfully.
  14. @return other - An error occurred when reading the directory entry.
  15. **/
  16. STATIC
  17. EFI_STATUS
  18. FatAccessEntry (
  19. IN FAT_OFILE *Parent,
  20. IN IO_MODE IoMode,
  21. IN UINTN EntryPos,
  22. IN OUT VOID *Entry
  23. )
  24. {
  25. UINTN Position;
  26. UINTN BufferSize;
  27. Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY);
  28. if (Position >= Parent->FileSize) {
  29. //
  30. // End of directory
  31. //
  32. ASSERT (IoMode == ReadData);
  33. ((FAT_DIRECTORY_ENTRY *)Entry)->FileName[0] = EMPTY_ENTRY_MARK;
  34. ((FAT_DIRECTORY_ENTRY *)Entry)->Attributes = 0;
  35. return EFI_SUCCESS;
  36. }
  37. BufferSize = sizeof (FAT_DIRECTORY_ENTRY);
  38. return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry, NULL);
  39. }
  40. /**
  41. Save the directory entry to disk.
  42. @param OFile - The parent OFile which needs to update.
  43. @param DirEnt - The directory entry to be saved.
  44. @retval EFI_SUCCESS - Store the directory entry successfully.
  45. @return other - An error occurred when writing the directory entry.
  46. **/
  47. EFI_STATUS
  48. FatStoreDirEnt (
  49. IN FAT_OFILE *OFile,
  50. IN FAT_DIRENT *DirEnt
  51. )
  52. {
  53. EFI_STATUS Status;
  54. FAT_DIRECTORY_LFN LfnEntry;
  55. UINTN EntryPos;
  56. CHAR16 *LfnBufferPointer;
  57. CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
  58. UINT8 EntryCount;
  59. UINT8 LfnOrdinal;
  60. EntryPos = DirEnt->EntryPos;
  61. EntryCount = DirEnt->EntryCount;
  62. //
  63. // Write directory entry
  64. //
  65. Status = FatAccessEntry (OFile, WriteData, EntryPos, &DirEnt->Entry);
  66. if (EFI_ERROR (Status)) {
  67. return Status;
  68. }
  69. if (--EntryCount > 0) {
  70. //
  71. // Write LFN directory entry
  72. //
  73. SetMem (LfnBuffer, sizeof (CHAR16) * LFN_CHAR_TOTAL * EntryCount, 0xff);
  74. Status = StrCpyS (
  75. LfnBuffer,
  76. ARRAY_SIZE (LfnBuffer),
  77. DirEnt->FileString
  78. );
  79. if (EFI_ERROR (Status)) {
  80. return Status;
  81. }
  82. LfnBufferPointer = LfnBuffer;
  83. LfnEntry.Attributes = FAT_ATTRIBUTE_LFN;
  84. LfnEntry.Type = 0;
  85. LfnEntry.MustBeZero = 0;
  86. LfnEntry.Checksum = FatCheckSum (DirEnt->Entry.FileName);
  87. for (LfnOrdinal = 1; LfnOrdinal <= EntryCount; LfnOrdinal++) {
  88. LfnEntry.Ordinal = LfnOrdinal;
  89. if (LfnOrdinal == EntryCount) {
  90. LfnEntry.Ordinal |= FAT_LFN_LAST;
  91. }
  92. CopyMem (LfnEntry.Name1, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR1_LEN);
  93. LfnBufferPointer += LFN_CHAR1_LEN;
  94. CopyMem (LfnEntry.Name2, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR2_LEN);
  95. LfnBufferPointer += LFN_CHAR2_LEN;
  96. CopyMem (LfnEntry.Name3, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR3_LEN);
  97. LfnBufferPointer += LFN_CHAR3_LEN;
  98. EntryPos--;
  99. if (DirEnt->Invalid) {
  100. LfnEntry.Ordinal = DELETE_ENTRY_MARK;
  101. }
  102. Status = FatAccessEntry (OFile, WriteData, EntryPos, &LfnEntry);
  103. if (EFI_ERROR (Status)) {
  104. return Status;
  105. }
  106. }
  107. }
  108. return EFI_SUCCESS;
  109. }
  110. /**
  111. Determine whether the directory entry is "." or ".." entry.
  112. @param DirEnt - The corresponding directory entry.
  113. @retval TRUE - The directory entry is "." or ".." directory entry
  114. @retval FALSE - The directory entry is not "." or ".." directory entry
  115. **/
  116. BOOLEAN
  117. FatIsDotDirEnt (
  118. IN FAT_DIRENT *DirEnt
  119. )
  120. {
  121. CHAR16 *FileString;
  122. FileString = DirEnt->FileString;
  123. if ((StrCmp (FileString, L".") == 0) || (StrCmp (FileString, L"..") == 0)) {
  124. return TRUE;
  125. }
  126. return FALSE;
  127. }
  128. /**
  129. Set the OFile's cluster info in its directory entry.
  130. @param OFile - The corresponding OFile.
  131. **/
  132. STATIC
  133. VOID
  134. FatSetDirEntCluster (
  135. IN FAT_OFILE *OFile
  136. )
  137. {
  138. UINTN Cluster;
  139. FAT_DIRENT *DirEnt;
  140. DirEnt = OFile->DirEnt;
  141. Cluster = OFile->FileCluster;
  142. DirEnt->Entry.FileClusterHigh = (UINT16)(Cluster >> 16);
  143. DirEnt->Entry.FileCluster = (UINT16)Cluster;
  144. }
  145. /**
  146. Set the OFile's cluster and size info in its directory entry.
  147. @param OFile - The corresponding OFile.
  148. **/
  149. VOID
  150. FatUpdateDirEntClusterSizeInfo (
  151. IN FAT_OFILE *OFile
  152. )
  153. {
  154. ASSERT (OFile->ODir == NULL);
  155. OFile->DirEnt->Entry.FileSize = (UINT32)OFile->FileSize;
  156. FatSetDirEntCluster (OFile);
  157. }
  158. /**
  159. Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
  160. @param DirEnt1 - The destination directory entry.
  161. @param DirEnt2 - The source directory entry.
  162. **/
  163. VOID
  164. FatCloneDirEnt (
  165. IN FAT_DIRENT *DirEnt1,
  166. IN FAT_DIRENT *DirEnt2
  167. )
  168. {
  169. UINT8 *Entry1;
  170. UINT8 *Entry2;
  171. Entry1 = (UINT8 *)&DirEnt1->Entry;
  172. Entry2 = (UINT8 *)&DirEnt2->Entry;
  173. CopyMem (
  174. Entry1 + FAT_ENTRY_INFO_OFFSET,
  175. Entry2 + FAT_ENTRY_INFO_OFFSET,
  176. sizeof (FAT_DIRECTORY_ENTRY) - FAT_ENTRY_INFO_OFFSET
  177. );
  178. }
  179. /**
  180. Get the LFN for the directory entry.
  181. @param Parent - The parent directory.
  182. @param DirEnt - The directory entry to get LFN.
  183. **/
  184. STATIC
  185. VOID
  186. FatLoadLongNameEntry (
  187. IN FAT_OFILE *Parent,
  188. IN FAT_DIRENT *DirEnt
  189. )
  190. {
  191. CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
  192. CHAR16 *LfnBufferPointer;
  193. CHAR8 *File8Dot3Name;
  194. UINTN EntryPos;
  195. UINT8 LfnOrdinal;
  196. UINT8 LfnChecksum;
  197. FAT_DIRECTORY_LFN LfnEntry;
  198. EFI_STATUS Status;
  199. EntryPos = DirEnt->EntryPos;
  200. File8Dot3Name = DirEnt->Entry.FileName;
  201. LfnBufferPointer = LfnBuffer;
  202. //
  203. // Computes checksum for LFN
  204. //
  205. LfnChecksum = FatCheckSum (File8Dot3Name);
  206. LfnOrdinal = 1;
  207. do {
  208. if (EntryPos == 0) {
  209. LfnBufferPointer = LfnBuffer;
  210. break;
  211. }
  212. EntryPos--;
  213. Status = FatAccessEntry (Parent, ReadData, EntryPos, &LfnEntry);
  214. if (EFI_ERROR (Status) ||
  215. (LfnEntry.Attributes != FAT_ATTRIBUTE_LFN) ||
  216. (LfnEntry.MustBeZero != 0) ||
  217. (LfnEntry.Checksum != LfnChecksum) ||
  218. ((LfnEntry.Ordinal & (~FAT_LFN_LAST)) != LfnOrdinal) ||
  219. (LfnOrdinal > MAX_LFN_ENTRIES)
  220. )
  221. {
  222. //
  223. // The directory entry does not have a long file name or
  224. // some error occurs when loading long file name for a directory entry,
  225. // and then we load the long name from short name
  226. //
  227. LfnBufferPointer = LfnBuffer;
  228. break;
  229. }
  230. CopyMem (LfnBufferPointer, LfnEntry.Name1, sizeof (CHAR16) * LFN_CHAR1_LEN);
  231. LfnBufferPointer += LFN_CHAR1_LEN;
  232. CopyMem (LfnBufferPointer, LfnEntry.Name2, sizeof (CHAR16) * LFN_CHAR2_LEN);
  233. LfnBufferPointer += LFN_CHAR2_LEN;
  234. CopyMem (LfnBufferPointer, LfnEntry.Name3, sizeof (CHAR16) * LFN_CHAR3_LEN);
  235. LfnBufferPointer += LFN_CHAR3_LEN;
  236. LfnOrdinal++;
  237. } while ((LfnEntry.Ordinal & FAT_LFN_LAST) == 0);
  238. DirEnt->EntryCount = LfnOrdinal;
  239. //
  240. // Terminate current Lfnbuffer
  241. //
  242. *LfnBufferPointer = 0;
  243. if (LfnBufferPointer == LfnBuffer) {
  244. //
  245. // Fail to get the long file name from long file name entry,
  246. // get the file name from short name
  247. //
  248. FatGetFileNameViaCaseFlag (
  249. DirEnt,
  250. LfnBuffer,
  251. ARRAY_SIZE (LfnBuffer)
  252. );
  253. }
  254. DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer);
  255. }
  256. /**
  257. Add this directory entry node to the list of directory entries and hash table.
  258. @param ODir - The parent OFile which needs to be updated.
  259. @param DirEnt - The directory entry to be added.
  260. **/
  261. STATIC
  262. VOID
  263. FatAddDirEnt (
  264. IN FAT_ODIR *ODir,
  265. IN FAT_DIRENT *DirEnt
  266. )
  267. {
  268. if (DirEnt->Link.BackLink == NULL) {
  269. DirEnt->Link.BackLink = &ODir->ChildList;
  270. }
  271. InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link);
  272. FatInsertToHashTable (ODir, DirEnt);
  273. }
  274. /**
  275. Load from disk the next directory entry at current end of directory position.
  276. @param OFile - The parent OFile.
  277. @param PtrDirEnt - The directory entry that is loaded.
  278. @retval EFI_SUCCESS - Load the directory entry successfully.
  279. @retval EFI_OUT_OF_RESOURCES - Out of resource.
  280. @return other - An error occurred when reading the directory entries.
  281. **/
  282. STATIC
  283. EFI_STATUS
  284. FatLoadNextDirEnt (
  285. IN FAT_OFILE *OFile,
  286. OUT FAT_DIRENT **PtrDirEnt
  287. )
  288. {
  289. EFI_STATUS Status;
  290. FAT_DIRENT *DirEnt;
  291. FAT_ODIR *ODir;
  292. FAT_DIRECTORY_ENTRY Entry;
  293. ODir = OFile->ODir;
  294. //
  295. // Make sure the parent's directory has been opened
  296. //
  297. ASSERT (ODir != NULL);
  298. //
  299. // Assert we have not reached the end of directory
  300. //
  301. ASSERT (!ODir->EndOfDir);
  302. DirEnt = NULL;
  303. for ( ; ;) {
  304. //
  305. // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
  306. //
  307. Status = FatAccessEntry (OFile, ReadData, ODir->CurrentEndPos, &Entry);
  308. if (EFI_ERROR (Status)) {
  309. return Status;
  310. }
  311. if (((UINT8)Entry.FileName[0] != DELETE_ENTRY_MARK) && ((Entry.Attributes & FAT_ATTRIBUTE_VOLUME_ID) == 0)) {
  312. //
  313. // We get a valid directory entry, then handle it
  314. //
  315. break;
  316. }
  317. ODir->CurrentEndPos++;
  318. }
  319. if (Entry.FileName[0] != EMPTY_ENTRY_MARK) {
  320. //
  321. // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications
  322. // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.
  323. //
  324. if (OFile->Volume->FatType != Fat32) {
  325. Entry.FileClusterHigh = 0;
  326. }
  327. //
  328. // This is a valid directory entry
  329. //
  330. DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
  331. if (DirEnt == NULL) {
  332. return EFI_OUT_OF_RESOURCES;
  333. }
  334. DirEnt->Signature = FAT_DIRENT_SIGNATURE;
  335. //
  336. // Remember the directory's entry position on disk
  337. //
  338. DirEnt->EntryPos = (UINT16)ODir->CurrentEndPos;
  339. CopyMem (&DirEnt->Entry, &Entry, sizeof (FAT_DIRECTORY_ENTRY));
  340. FatLoadLongNameEntry (OFile, DirEnt);
  341. if (DirEnt->FileString == NULL) {
  342. Status = EFI_OUT_OF_RESOURCES;
  343. goto Done;
  344. }
  345. //
  346. // Add this directory entry to directory
  347. //
  348. FatAddDirEnt (ODir, DirEnt);
  349. //
  350. // Point to next directory entry
  351. //
  352. ODir->CurrentEndPos++;
  353. } else {
  354. ODir->EndOfDir = TRUE;
  355. }
  356. *PtrDirEnt = DirEnt;
  357. return EFI_SUCCESS;
  358. Done:
  359. FatFreeDirEnt (DirEnt);
  360. return Status;
  361. }
  362. /**
  363. Get the directory entry's info into Buffer.
  364. @param Volume - FAT file system volume.
  365. @param DirEnt - The corresponding directory entry.
  366. @param BufferSize - Size of Buffer.
  367. @param Buffer - Buffer containing file info.
  368. @retval EFI_SUCCESS - Get the file info successfully.
  369. @retval EFI_BUFFER_TOO_SMALL - The buffer is too small.
  370. **/
  371. EFI_STATUS
  372. FatGetDirEntInfo (
  373. IN FAT_VOLUME *Volume,
  374. IN FAT_DIRENT *DirEnt,
  375. IN OUT UINTN *BufferSize,
  376. OUT VOID *Buffer
  377. )
  378. {
  379. UINTN Size;
  380. UINTN NameSize;
  381. UINTN ResultSize;
  382. UINTN Cluster;
  383. EFI_STATUS Status;
  384. EFI_FILE_INFO *Info;
  385. FAT_DIRECTORY_ENTRY *Entry;
  386. FAT_DATE_TIME FatLastAccess;
  387. ASSERT_VOLUME_LOCKED (Volume);
  388. Size = SIZE_OF_EFI_FILE_INFO;
  389. NameSize = StrSize (DirEnt->FileString);
  390. ResultSize = Size + NameSize;
  391. Status = EFI_BUFFER_TOO_SMALL;
  392. if (*BufferSize >= ResultSize) {
  393. Status = EFI_SUCCESS;
  394. Entry = &DirEnt->Entry;
  395. Info = Buffer;
  396. Info->Size = ResultSize;
  397. if ((Entry->Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
  398. Cluster = (Entry->FileClusterHigh << 16) | Entry->FileCluster;
  399. Info->PhysicalSize = FatPhysicalDirSize (Volume, Cluster);
  400. Info->FileSize = Info->PhysicalSize;
  401. } else {
  402. Info->FileSize = Entry->FileSize;
  403. Info->PhysicalSize = FatPhysicalFileSize (Volume, Entry->FileSize);
  404. }
  405. ZeroMem (&FatLastAccess.Time, sizeof (FatLastAccess.Time));
  406. CopyMem (&FatLastAccess.Date, &Entry->FileLastAccess, sizeof (FatLastAccess.Date));
  407. FatFatTimeToEfiTime (&FatLastAccess, &Info->LastAccessTime);
  408. FatFatTimeToEfiTime (&Entry->FileCreateTime, &Info->CreateTime);
  409. FatFatTimeToEfiTime (&Entry->FileModificationTime, &Info->ModificationTime);
  410. Info->Attribute = Entry->Attributes & EFI_FILE_VALID_ATTR;
  411. CopyMem ((CHAR8 *)Buffer + Size, DirEnt->FileString, NameSize);
  412. }
  413. *BufferSize = ResultSize;
  414. return Status;
  415. }
  416. /**
  417. Search the directory for the directory entry whose filename is FileNameString.
  418. @param OFile - The parent OFile whose directory is to be searched.
  419. @param FileNameString - The filename to be searched.
  420. @param PtrDirEnt - pointer to the directory entry if found.
  421. @retval EFI_SUCCESS - Find the directory entry or not found.
  422. @return other - An error occurred when reading the directory entries.
  423. **/
  424. STATIC
  425. EFI_STATUS
  426. FatSearchODir (
  427. IN FAT_OFILE *OFile,
  428. IN CHAR16 *FileNameString,
  429. OUT FAT_DIRENT **PtrDirEnt
  430. )
  431. {
  432. BOOLEAN PossibleShortName;
  433. CHAR8 File8Dot3Name[FAT_NAME_LEN];
  434. FAT_ODIR *ODir;
  435. FAT_DIRENT *DirEnt;
  436. EFI_STATUS Status;
  437. ODir = OFile->ODir;
  438. ASSERT (ODir != NULL);
  439. //
  440. // Check if the file name is a valid short name
  441. //
  442. PossibleShortName = FatCheckIs8Dot3Name (FileNameString, File8Dot3Name);
  443. //
  444. // Search the hash table first
  445. //
  446. DirEnt = *FatLongNameHashSearch (ODir, FileNameString);
  447. if ((DirEnt == NULL) && PossibleShortName) {
  448. DirEnt = *FatShortNameHashSearch (ODir, File8Dot3Name);
  449. }
  450. if (DirEnt == NULL) {
  451. //
  452. // We fail to get the directory entry from hash table; we then
  453. // search the rest directory
  454. //
  455. while (!ODir->EndOfDir) {
  456. Status = FatLoadNextDirEnt (OFile, &DirEnt);
  457. if (EFI_ERROR (Status)) {
  458. return Status;
  459. }
  460. if (DirEnt != NULL) {
  461. if (FatStriCmp (FileNameString, DirEnt->FileString) == 0) {
  462. break;
  463. }
  464. if (PossibleShortName && (CompareMem (File8Dot3Name, DirEnt->Entry.FileName, FAT_NAME_LEN) == 0)) {
  465. break;
  466. }
  467. }
  468. }
  469. }
  470. *PtrDirEnt = DirEnt;
  471. return EFI_SUCCESS;
  472. }
  473. /**
  474. Set the OFile's current directory cursor to the list head.
  475. @param OFile - The directory OFile whose directory cursor is reset.
  476. **/
  477. VOID
  478. FatResetODirCursor (
  479. IN FAT_OFILE *OFile
  480. )
  481. {
  482. FAT_ODIR *ODir;
  483. ODir = OFile->ODir;
  484. ASSERT (ODir != NULL);
  485. ODir->CurrentCursor = &(ODir->ChildList);
  486. ODir->CurrentPos = 0;
  487. }
  488. /**
  489. Set the directory's cursor to the next and get the next directory entry.
  490. @param OFile - The parent OFile.
  491. @param PtrDirEnt - The next directory entry.
  492. @retval EFI_SUCCESS - We get the next directory entry successfully.
  493. @return other - An error occurred when get next directory entry.
  494. **/
  495. EFI_STATUS
  496. FatGetNextDirEnt (
  497. IN FAT_OFILE *OFile,
  498. OUT FAT_DIRENT **PtrDirEnt
  499. )
  500. {
  501. EFI_STATUS Status;
  502. FAT_DIRENT *DirEnt;
  503. FAT_ODIR *ODir;
  504. ODir = OFile->ODir;
  505. ASSERT (ODir != NULL);
  506. if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
  507. //
  508. // End of directory, we will try one more time
  509. //
  510. if (!ODir->EndOfDir) {
  511. //
  512. // Read directory from disk
  513. //
  514. Status = FatLoadNextDirEnt (OFile, &DirEnt);
  515. if (EFI_ERROR (Status)) {
  516. return Status;
  517. }
  518. }
  519. }
  520. if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
  521. //
  522. // End of directory, return NULL
  523. //
  524. DirEnt = NULL;
  525. ODir->CurrentPos = ODir->CurrentEndPos;
  526. } else {
  527. ODir->CurrentCursor = ODir->CurrentCursor->ForwardLink;
  528. DirEnt = DIRENT_FROM_LINK (ODir->CurrentCursor);
  529. ODir->CurrentPos = DirEnt->EntryPos + 1;
  530. }
  531. *PtrDirEnt = DirEnt;
  532. return EFI_SUCCESS;
  533. }
  534. /**
  535. Set the directory entry count according to the filename.
  536. @param OFile - The corresponding OFile.
  537. @param DirEnt - The directory entry to be set.
  538. **/
  539. STATIC
  540. VOID
  541. FatSetEntryCount (
  542. IN FAT_OFILE *OFile,
  543. IN FAT_DIRENT *DirEnt
  544. )
  545. {
  546. CHAR16 *FileString;
  547. CHAR8 *File8Dot3Name;
  548. //
  549. // Get new entry count and set the 8.3 name
  550. //
  551. DirEnt->EntryCount = 1;
  552. FileString = DirEnt->FileString;
  553. File8Dot3Name = DirEnt->Entry.FileName;
  554. SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');
  555. if (StrCmp (FileString, L".") == 0) {
  556. //
  557. // "." entry
  558. //
  559. File8Dot3Name[0] = '.';
  560. FatCloneDirEnt (DirEnt, OFile->DirEnt);
  561. } else if (StrCmp (FileString, L"..") == 0) {
  562. //
  563. // ".." entry
  564. //
  565. File8Dot3Name[0] = '.';
  566. File8Dot3Name[1] = '.';
  567. FatCloneDirEnt (DirEnt, OFile->Parent->DirEnt);
  568. } else {
  569. //
  570. // Normal name
  571. //
  572. if (FatCheckIs8Dot3Name (FileString, File8Dot3Name)) {
  573. //
  574. // This file name is a valid 8.3 file name, we need to further check its case flag
  575. //
  576. FatSetCaseFlag (DirEnt);
  577. } else {
  578. //
  579. // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
  580. //
  581. FatCreate8Dot3Name (OFile, DirEnt);
  582. DirEnt->EntryCount = (UINT8)(LFN_ENTRY_NUMBER (StrLen (FileString)) + DirEnt->EntryCount);
  583. }
  584. }
  585. }
  586. /**
  587. Append a zero cluster to the current OFile.
  588. @param OFile - The directory OFile which needs to be updated.
  589. @retval EFI_SUCCESS - Append a zero cluster to the OFile successfully.
  590. @return other - An error occurred when appending the zero cluster.
  591. **/
  592. STATIC
  593. EFI_STATUS
  594. FatExpandODir (
  595. IN FAT_OFILE *OFile
  596. )
  597. {
  598. return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);
  599. }
  600. /**
  601. Search the Root OFile for the possible volume label.
  602. @param Root - The Root OFile.
  603. @param DirEnt - The returned directory entry of volume label.
  604. @retval EFI_SUCCESS - The search process is completed successfully.
  605. @return other - An error occurred when searching volume label.
  606. **/
  607. STATIC
  608. EFI_STATUS
  609. FatSeekVolumeId (
  610. IN FAT_OFILE *Root,
  611. OUT FAT_DIRENT *DirEnt
  612. )
  613. {
  614. EFI_STATUS Status;
  615. UINTN EntryPos;
  616. FAT_DIRECTORY_ENTRY *Entry;
  617. EntryPos = 0;
  618. Entry = &DirEnt->Entry;
  619. DirEnt->Invalid = TRUE;
  620. do {
  621. Status = FatAccessEntry (Root, ReadData, EntryPos, Entry);
  622. if (EFI_ERROR (Status)) {
  623. return Status;
  624. }
  625. if (((UINT8)Entry->FileName[0] != DELETE_ENTRY_MARK) && (((Entry->Attributes) & (~FAT_ATTRIBUTE_ARCHIVE)) == FAT_ATTRIBUTE_VOLUME_ID)) {
  626. DirEnt->EntryPos = (UINT16)EntryPos;
  627. DirEnt->EntryCount = 1;
  628. DirEnt->Invalid = FALSE;
  629. break;
  630. }
  631. EntryPos++;
  632. } while (Entry->FileName[0] != EMPTY_ENTRY_MARK);
  633. return EFI_SUCCESS;
  634. }
  635. /**
  636. Use First Fit Algorithm to insert directory entry.
  637. Only this function will erase "E5" entries in a directory.
  638. In view of safest recovery, this function will only be triggered
  639. when maximum directory entry number has reached.
  640. @param OFile - The corresponding OFile.
  641. @param DirEnt - The directory entry to be inserted.
  642. @retval EFI_SUCCESS - The directory entry has been successfully inserted.
  643. @retval EFI_VOLUME_FULL - The directory can not hold more directory entries.
  644. @return Others - Some error occurred when inserting new directory entries.
  645. **/
  646. STATIC
  647. EFI_STATUS
  648. FatFirstFitInsertDirEnt (
  649. IN FAT_OFILE *OFile,
  650. IN FAT_DIRENT *DirEnt
  651. )
  652. {
  653. EFI_STATUS Status;
  654. FAT_ODIR *ODir;
  655. LIST_ENTRY *CurrentEntry;
  656. FAT_DIRENT *CurrentDirEnt;
  657. UINT32 CurrentPos;
  658. UINT32 LabelPos;
  659. UINT32 NewEntryPos;
  660. UINT16 EntryCount;
  661. FAT_DIRENT LabelDirEnt;
  662. LabelPos = 0;
  663. if (OFile->Parent == NULL) {
  664. Status = FatSeekVolumeId (OFile, &LabelDirEnt);
  665. if (EFI_ERROR (Status)) {
  666. return Status;
  667. }
  668. if (!LabelDirEnt.Invalid) {
  669. LabelPos = LabelDirEnt.EntryPos;
  670. }
  671. }
  672. EntryCount = DirEnt->EntryCount;
  673. NewEntryPos = EntryCount;
  674. CurrentPos = 0;
  675. ODir = OFile->ODir;
  676. for (CurrentEntry = ODir->ChildList.ForwardLink;
  677. CurrentEntry != &ODir->ChildList;
  678. CurrentEntry = CurrentEntry->ForwardLink
  679. )
  680. {
  681. CurrentDirEnt = DIRENT_FROM_LINK (CurrentEntry);
  682. if (NewEntryPos + CurrentDirEnt->EntryCount <= CurrentDirEnt->EntryPos) {
  683. if ((LabelPos > NewEntryPos) || (LabelPos <= CurrentPos)) {
  684. //
  685. // first fit succeeded
  686. //
  687. goto Done;
  688. }
  689. }
  690. CurrentPos = CurrentDirEnt->EntryPos;
  691. NewEntryPos = CurrentPos + EntryCount;
  692. }
  693. if (NewEntryPos >= ODir->CurrentEndPos) {
  694. return EFI_VOLUME_FULL;
  695. }
  696. Done:
  697. DirEnt->EntryPos = (UINT16)NewEntryPos;
  698. DirEnt->Link.BackLink = CurrentEntry;
  699. return EFI_SUCCESS;
  700. }
  701. /**
  702. Find the new directory entry position for the directory entry.
  703. @param OFile - The corresponding OFile.
  704. @param DirEnt - The directory entry whose new position is to be set.
  705. @retval EFI_SUCCESS - The new directory entry position is successfully found.
  706. @retval EFI_VOLUME_FULL - The directory has reach its maximum capacity.
  707. @return other - An error occurred when reading the directory entry.
  708. **/
  709. STATIC
  710. EFI_STATUS
  711. FatNewEntryPos (
  712. IN FAT_OFILE *OFile,
  713. IN FAT_DIRENT *DirEnt
  714. )
  715. {
  716. EFI_STATUS Status;
  717. FAT_ODIR *ODir;
  718. FAT_DIRENT *TempDirEnt;
  719. UINT32 NewEndPos;
  720. ODir = OFile->ODir;
  721. ASSERT (ODir != NULL);
  722. //
  723. // Make sure the whole directory has been loaded
  724. //
  725. while (!ODir->EndOfDir) {
  726. Status = FatLoadNextDirEnt (OFile, &TempDirEnt);
  727. if (EFI_ERROR (Status)) {
  728. return Status;
  729. }
  730. }
  731. //
  732. // We will append this entry to the end of directory
  733. //
  734. FatGetCurrentFatTime (&DirEnt->Entry.FileCreateTime);
  735. CopyMem (&DirEnt->Entry.FileModificationTime, &DirEnt->Entry.FileCreateTime, sizeof (FAT_DATE_TIME));
  736. CopyMem (&DirEnt->Entry.FileLastAccess, &DirEnt->Entry.FileCreateTime.Date, sizeof (FAT_DATE));
  737. NewEndPos = ODir->CurrentEndPos + DirEnt->EntryCount;
  738. if (NewEndPos * sizeof (FAT_DIRECTORY_ENTRY) > OFile->FileSize) {
  739. if (NewEndPos >= (OFile->IsFixedRootDir ? OFile->Volume->RootEntries : FAT_MAX_DIRENTRY_COUNT)) {
  740. //
  741. // We try to use fist fit algorithm to insert this directory entry
  742. //
  743. return FatFirstFitInsertDirEnt (OFile, DirEnt);
  744. }
  745. //
  746. // We should allocate a new cluster for this directory
  747. //
  748. Status = FatExpandODir (OFile);
  749. if (EFI_ERROR (Status)) {
  750. return Status;
  751. }
  752. }
  753. //
  754. // We append our directory entry at the end of directory file
  755. //
  756. ODir->CurrentEndPos = NewEndPos;
  757. DirEnt->EntryPos = (UINT16)(ODir->CurrentEndPos - 1);
  758. return EFI_SUCCESS;
  759. }
  760. /**
  761. Get the directory entry for the volume.
  762. @param Volume - FAT file system volume.
  763. @param Name - The file name of the volume.
  764. @retval EFI_SUCCESS - Update the volume with the directory entry successfully.
  765. @return others - An error occurred when getting volume label.
  766. **/
  767. EFI_STATUS
  768. FatGetVolumeEntry (
  769. IN FAT_VOLUME *Volume,
  770. IN CHAR16 *Name
  771. )
  772. {
  773. EFI_STATUS Status;
  774. FAT_DIRENT LabelDirEnt;
  775. *Name = 0;
  776. Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
  777. if (!EFI_ERROR (Status)) {
  778. if (!LabelDirEnt.Invalid) {
  779. FatNameToStr (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, FALSE, Name);
  780. }
  781. }
  782. return Status;
  783. }
  784. /**
  785. Set the relevant directory entry into disk for the volume.
  786. @param Volume - FAT file system volume.
  787. @param Name - The new file name of the volume.
  788. @retval EFI_SUCCESS - Update the Volume successfully.
  789. @retval EFI_UNSUPPORTED - The input label is not a valid volume label.
  790. @return other - An error occurred when setting volume label.
  791. **/
  792. EFI_STATUS
  793. FatSetVolumeEntry (
  794. IN FAT_VOLUME *Volume,
  795. IN CHAR16 *Name
  796. )
  797. {
  798. EFI_STATUS Status;
  799. FAT_DIRENT LabelDirEnt;
  800. FAT_OFILE *Root;
  801. Root = Volume->Root;
  802. Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
  803. if (EFI_ERROR (Status)) {
  804. return Status;
  805. }
  806. if (LabelDirEnt.Invalid) {
  807. //
  808. // If there is not the relevant directory entry, create a new one
  809. //
  810. ZeroMem (&LabelDirEnt, sizeof (FAT_DIRENT));
  811. LabelDirEnt.EntryCount = 1;
  812. Status = FatNewEntryPos (Root, &LabelDirEnt);
  813. if (EFI_ERROR (Status)) {
  814. return Status;
  815. }
  816. LabelDirEnt.Entry.Attributes = FAT_ATTRIBUTE_VOLUME_ID;
  817. }
  818. SetMem (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, ' ');
  819. if (FatStrToFat (Name, FAT_NAME_LEN, LabelDirEnt.Entry.FileName)) {
  820. return EFI_UNSUPPORTED;
  821. }
  822. FatGetCurrentFatTime (&LabelDirEnt.Entry.FileModificationTime);
  823. return FatStoreDirEnt (Root, &LabelDirEnt);
  824. }
  825. /**
  826. Create "." and ".." directory entries in the newly-created parent OFile.
  827. @param OFile - The parent OFile.
  828. @retval EFI_SUCCESS - The dot directory entries are successfully created.
  829. @return other - An error occurred when creating the directory entry.
  830. **/
  831. EFI_STATUS
  832. FatCreateDotDirEnts (
  833. IN FAT_OFILE *OFile
  834. )
  835. {
  836. EFI_STATUS Status;
  837. FAT_DIRENT *DirEnt;
  838. Status = FatExpandODir (OFile);
  839. if (EFI_ERROR (Status)) {
  840. return Status;
  841. }
  842. FatSetDirEntCluster (OFile);
  843. //
  844. // Create "."
  845. //
  846. Status = FatCreateDirEnt (OFile, L".", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
  847. if (EFI_ERROR (Status)) {
  848. return Status;
  849. }
  850. //
  851. // Create ".."
  852. //
  853. Status = FatCreateDirEnt (OFile, L"..", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
  854. return Status;
  855. }
  856. /**
  857. Create a directory entry in the parent OFile.
  858. @param OFile - The parent OFile.
  859. @param FileName - The filename of the newly-created directory entry.
  860. @param Attributes - The attribute of the newly-created directory entry.
  861. @param PtrDirEnt - The pointer to the newly-created directory entry.
  862. @retval EFI_SUCCESS - The directory entry is successfully created.
  863. @retval EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry.
  864. @return other - An error occurred when creating the directory entry.
  865. **/
  866. EFI_STATUS
  867. FatCreateDirEnt (
  868. IN FAT_OFILE *OFile,
  869. IN CHAR16 *FileName,
  870. IN UINT8 Attributes,
  871. OUT FAT_DIRENT **PtrDirEnt
  872. )
  873. {
  874. FAT_DIRENT *DirEnt;
  875. FAT_ODIR *ODir;
  876. EFI_STATUS Status;
  877. ASSERT (OFile != NULL);
  878. ODir = OFile->ODir;
  879. ASSERT (ODir != NULL);
  880. DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
  881. if (DirEnt == NULL) {
  882. return EFI_OUT_OF_RESOURCES;
  883. }
  884. DirEnt->Signature = FAT_DIRENT_SIGNATURE;
  885. DirEnt->FileString = AllocateCopyPool (StrSize (FileName), FileName);
  886. if (DirEnt->FileString == NULL) {
  887. Status = EFI_OUT_OF_RESOURCES;
  888. goto Done;
  889. }
  890. //
  891. // Determine how many directory entries we need
  892. //
  893. FatSetEntryCount (OFile, DirEnt);
  894. //
  895. // Determine the file's directory entry position
  896. //
  897. Status = FatNewEntryPos (OFile, DirEnt);
  898. if (EFI_ERROR (Status)) {
  899. goto Done;
  900. }
  901. FatAddDirEnt (ODir, DirEnt);
  902. DirEnt->Entry.Attributes = Attributes;
  903. *PtrDirEnt = DirEnt;
  904. DEBUG ((DEBUG_INFO, "FSOpen: Created new directory entry '%S'\n", DirEnt->FileString));
  905. return FatStoreDirEnt (OFile, DirEnt);
  906. Done:
  907. FatFreeDirEnt (DirEnt);
  908. return Status;
  909. }
  910. /**
  911. Remove this directory entry node from the list of directory entries and hash table.
  912. @param OFile - The parent OFile.
  913. @param DirEnt - The directory entry to be removed.
  914. @retval EFI_SUCCESS - The directory entry is successfully removed.
  915. @return other - An error occurred when removing the directory entry.
  916. **/
  917. EFI_STATUS
  918. FatRemoveDirEnt (
  919. IN FAT_OFILE *OFile,
  920. IN FAT_DIRENT *DirEnt
  921. )
  922. {
  923. FAT_ODIR *ODir;
  924. ODir = OFile->ODir;
  925. if (ODir->CurrentCursor == &DirEnt->Link) {
  926. //
  927. // Move the directory cursor to its previous directory entry
  928. //
  929. ODir->CurrentCursor = ODir->CurrentCursor->BackLink;
  930. }
  931. //
  932. // Remove from directory entry list
  933. //
  934. RemoveEntryList (&DirEnt->Link);
  935. //
  936. // Remove from hash table
  937. //
  938. FatDeleteFromHashTable (ODir, DirEnt);
  939. DirEnt->Entry.FileName[0] = DELETE_ENTRY_MARK;
  940. DirEnt->Invalid = TRUE;
  941. return FatStoreDirEnt (OFile, DirEnt);
  942. }
  943. /**
  944. Open the directory entry to get the OFile.
  945. @param Parent - The parent OFile.
  946. @param DirEnt - The directory entry to be opened.
  947. @retval EFI_SUCCESS - The directory entry is successfully opened.
  948. @retval EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile.
  949. @return other - An error occurred when opening the directory entry.
  950. **/
  951. EFI_STATUS
  952. FatOpenDirEnt (
  953. IN FAT_OFILE *Parent,
  954. IN FAT_DIRENT *DirEnt
  955. )
  956. {
  957. FAT_OFILE *OFile;
  958. FAT_VOLUME *Volume;
  959. if (DirEnt->OFile == NULL) {
  960. //
  961. // Open the directory entry
  962. //
  963. OFile = AllocateZeroPool (sizeof (FAT_OFILE));
  964. if (OFile == NULL) {
  965. return EFI_OUT_OF_RESOURCES;
  966. }
  967. OFile->Signature = FAT_OFILE_SIGNATURE;
  968. InitializeListHead (&OFile->Opens);
  969. InitializeListHead (&OFile->ChildHead);
  970. OFile->Parent = Parent;
  971. OFile->DirEnt = DirEnt;
  972. if (Parent != NULL) {
  973. //
  974. // The newly created OFile is not root
  975. //
  976. Volume = Parent->Volume;
  977. OFile->FullPathLen = Parent->FullPathLen + 1 + StrLen (DirEnt->FileString);
  978. OFile->FileCluster = ((DirEnt->Entry.FileClusterHigh) << 16) | (DirEnt->Entry.FileCluster);
  979. InsertTailList (&Parent->ChildHead, &OFile->ChildLink);
  980. } else {
  981. //
  982. // The newly created OFile is root
  983. //
  984. Volume = VOLUME_FROM_ROOT_DIRENT (DirEnt);
  985. Volume->Root = OFile;
  986. OFile->FileCluster = Volume->RootCluster;
  987. if (Volume->FatType != Fat32) {
  988. OFile->IsFixedRootDir = TRUE;
  989. }
  990. }
  991. OFile->FileCurrentCluster = OFile->FileCluster;
  992. OFile->Volume = Volume;
  993. InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);
  994. OFile->FileSize = DirEnt->Entry.FileSize;
  995. if ((DirEnt->Entry.Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
  996. if (OFile->IsFixedRootDir) {
  997. OFile->FileSize = Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY);
  998. } else {
  999. OFile->FileSize = FatPhysicalDirSize (Volume, OFile->FileCluster);
  1000. }
  1001. FatRequestODir (OFile);
  1002. if (OFile->ODir == NULL) {
  1003. return EFI_OUT_OF_RESOURCES;
  1004. }
  1005. }
  1006. DirEnt->OFile = OFile;
  1007. }
  1008. return EFI_SUCCESS;
  1009. }
  1010. /**
  1011. Close the directory entry and free the OFile.
  1012. @param DirEnt - The directory entry to be closed.
  1013. **/
  1014. VOID
  1015. FatCloseDirEnt (
  1016. IN FAT_DIRENT *DirEnt
  1017. )
  1018. {
  1019. FAT_OFILE *OFile;
  1020. FAT_VOLUME *Volume;
  1021. OFile = DirEnt->OFile;
  1022. ASSERT (OFile != NULL);
  1023. Volume = OFile->Volume;
  1024. if (OFile->ODir != NULL) {
  1025. FatDiscardODir (OFile);
  1026. }
  1027. if (OFile->Parent == NULL) {
  1028. Volume->Root = NULL;
  1029. } else {
  1030. RemoveEntryList (&OFile->ChildLink);
  1031. }
  1032. FreePool (OFile);
  1033. DirEnt->OFile = NULL;
  1034. if (DirEnt->Invalid == TRUE) {
  1035. //
  1036. // Free directory entry itself
  1037. //
  1038. FatFreeDirEnt (DirEnt);
  1039. }
  1040. }
  1041. /**
  1042. Traverse filename and open all OFiles that can be opened.
  1043. Update filename pointer to the component that can't be opened.
  1044. If more than one name component remains, returns an error;
  1045. otherwise, return the remaining name component so that the caller might choose to create it.
  1046. @param PtrOFile - As input, the reference OFile; as output, the located OFile.
  1047. @param FileName - The file name relevant to the OFile.
  1048. @param Attributes - The attribute of the destination OFile.
  1049. @param NewFileName - The remaining file name.
  1050. @retval EFI_NOT_FOUND - The file name can't be opened and there is more than one
  1051. components within the name left (this means the name can
  1052. not be created either).
  1053. @retval EFI_INVALID_PARAMETER - The parameter is not valid.
  1054. @retval EFI_SUCCESS - Open the file successfully.
  1055. @return other - An error occurred when locating the OFile.
  1056. **/
  1057. EFI_STATUS
  1058. FatLocateOFile (
  1059. IN OUT FAT_OFILE **PtrOFile,
  1060. IN CHAR16 *FileName,
  1061. IN UINT8 Attributes,
  1062. OUT CHAR16 *NewFileName
  1063. )
  1064. {
  1065. EFI_STATUS Status;
  1066. FAT_VOLUME *Volume;
  1067. CHAR16 ComponentName[EFI_PATH_STRING_LENGTH];
  1068. UINTN FileNameLen;
  1069. BOOLEAN DirIntended;
  1070. CHAR16 *Next;
  1071. FAT_OFILE *OFile;
  1072. FAT_DIRENT *DirEnt;
  1073. DirEnt = NULL;
  1074. FileNameLen = StrLen (FileName);
  1075. if (FileNameLen == 0) {
  1076. return EFI_INVALID_PARAMETER;
  1077. }
  1078. OFile = *PtrOFile;
  1079. Volume = OFile->Volume;
  1080. DirIntended = FALSE;
  1081. if (FileName[FileNameLen - 1] == PATH_NAME_SEPARATOR) {
  1082. DirIntended = TRUE;
  1083. }
  1084. //
  1085. // If name starts with path name separator, then move to root OFile
  1086. //
  1087. if (*FileName == PATH_NAME_SEPARATOR) {
  1088. OFile = Volume->Root;
  1089. FileName++;
  1090. FileNameLen--;
  1091. }
  1092. //
  1093. // Per FAT Spec the file name should meet the following criteria:
  1094. // C1. Length (FileLongName) <= 255
  1095. // C2. Length (X:FileFullPath<NUL>) <= 260
  1096. // Here we check C2 first.
  1097. //
  1098. if (2 + OFile->FullPathLen + 1 + FileNameLen + 1 > EFI_PATH_STRING_LENGTH) {
  1099. //
  1100. // Full path length can not surpass 256
  1101. //
  1102. return EFI_INVALID_PARAMETER;
  1103. }
  1104. //
  1105. // Start at current location
  1106. //
  1107. Next = FileName;
  1108. for ( ; ;) {
  1109. //
  1110. // Get the next component name
  1111. //
  1112. FileName = Next;
  1113. Next = FatGetNextNameComponent (FileName, ComponentName);
  1114. //
  1115. // If end of the file name, we're done
  1116. //
  1117. if (ComponentName[0] == 0) {
  1118. if (DirIntended && (OFile->ODir == NULL)) {
  1119. return EFI_NOT_FOUND;
  1120. }
  1121. NewFileName[0] = 0;
  1122. break;
  1123. }
  1124. //
  1125. // If "dot", then current
  1126. //
  1127. if (StrCmp (ComponentName, L".") == 0) {
  1128. continue;
  1129. }
  1130. //
  1131. // If "dot dot", then parent
  1132. //
  1133. if (StrCmp (ComponentName, L"..") == 0) {
  1134. if (OFile->Parent == NULL) {
  1135. return EFI_INVALID_PARAMETER;
  1136. }
  1137. OFile = OFile->Parent;
  1138. continue;
  1139. }
  1140. if (!FatFileNameIsValid (ComponentName, NewFileName)) {
  1141. return EFI_INVALID_PARAMETER;
  1142. }
  1143. //
  1144. // We have a component name, try to open it
  1145. //
  1146. if (OFile->ODir == NULL) {
  1147. //
  1148. // This file isn't a directory, can't open it
  1149. //
  1150. return EFI_NOT_FOUND;
  1151. }
  1152. //
  1153. // Search the compName in the directory
  1154. //
  1155. Status = FatSearchODir (OFile, NewFileName, &DirEnt);
  1156. if (EFI_ERROR (Status)) {
  1157. return Status;
  1158. }
  1159. if (DirEnt == NULL) {
  1160. //
  1161. // component name is not found in the directory
  1162. //
  1163. if (*Next != 0) {
  1164. return EFI_NOT_FOUND;
  1165. }
  1166. if (DirIntended && ((Attributes & FAT_ATTRIBUTE_DIRECTORY) == 0)) {
  1167. return EFI_INVALID_PARAMETER;
  1168. }
  1169. //
  1170. // It's the last component name - return with the open
  1171. // path and the remaining name
  1172. //
  1173. break;
  1174. }
  1175. Status = FatOpenDirEnt (OFile, DirEnt);
  1176. if (EFI_ERROR (Status)) {
  1177. return Status;
  1178. }
  1179. OFile = DirEnt->OFile;
  1180. }
  1181. *PtrOFile = OFile;
  1182. return EFI_SUCCESS;
  1183. }