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