DirectoryManage.c 38 KB

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