2 Functions for performing directory entry io.
4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
13 Get a directory entry from disk for the Ofile.
15 @param Parent - The parent of the OFile which need to update.
16 @param IoMode - Indicate whether to read directory entry or write directroy entry.
17 @param EntryPos - The position of the directory entry to be accessed.
18 @param Entry - The directory entry read or written.
20 @retval EFI_SUCCESS - Access the directory entry sucessfully.
21 @return other - An error occurred when reading the directory entry.
36 Position
= EntryPos
* sizeof (FAT_DIRECTORY_ENTRY
);
37 if (Position
>= Parent
->FileSize
) {
41 ASSERT (IoMode
== ReadData
);
42 ((FAT_DIRECTORY_ENTRY
*) Entry
)->FileName
[0] = EMPTY_ENTRY_MARK
;
43 ((FAT_DIRECTORY_ENTRY
*) Entry
)->Attributes
= 0;
47 BufferSize
= sizeof (FAT_DIRECTORY_ENTRY
);
48 return FatAccessOFile (Parent
, IoMode
, Position
, &BufferSize
, Entry
, NULL
);
53 Save the directory entry to disk.
55 @param OFile - The parent OFile which needs to update.
56 @param DirEnt - The directory entry to be saved.
58 @retval EFI_SUCCESS - Store the directory entry successfully.
59 @return other - An error occurred when writing the directory entry.
69 FAT_DIRECTORY_LFN LfnEntry
;
71 CHAR16
*LfnBufferPointer
;
72 CHAR16 LfnBuffer
[MAX_LFN_ENTRIES
* LFN_CHAR_TOTAL
+ 1];
76 EntryPos
= DirEnt
->EntryPos
;
77 EntryCount
= DirEnt
->EntryCount
;
79 // Write directory entry
81 Status
= FatAccessEntry (OFile
, WriteData
, EntryPos
, &DirEnt
->Entry
);
82 if (EFI_ERROR (Status
)) {
86 if (--EntryCount
> 0) {
88 // Write LFN directory entry
90 SetMem (LfnBuffer
, sizeof (CHAR16
) * LFN_CHAR_TOTAL
* EntryCount
, 0xff);
93 ARRAY_SIZE (LfnBuffer
),
96 if (EFI_ERROR (Status
)) {
100 LfnBufferPointer
= LfnBuffer
;
101 LfnEntry
.Attributes
= FAT_ATTRIBUTE_LFN
;
103 LfnEntry
.MustBeZero
= 0;
104 LfnEntry
.Checksum
= FatCheckSum (DirEnt
->Entry
.FileName
);
105 for (LfnOrdinal
= 1; LfnOrdinal
<= EntryCount
; LfnOrdinal
++) {
106 LfnEntry
.Ordinal
= LfnOrdinal
;
107 if (LfnOrdinal
== EntryCount
) {
108 LfnEntry
.Ordinal
|= FAT_LFN_LAST
;
111 CopyMem (LfnEntry
.Name1
, LfnBufferPointer
, sizeof (CHAR16
) * LFN_CHAR1_LEN
);
112 LfnBufferPointer
+= LFN_CHAR1_LEN
;
113 CopyMem (LfnEntry
.Name2
, LfnBufferPointer
, sizeof (CHAR16
) * LFN_CHAR2_LEN
);
114 LfnBufferPointer
+= LFN_CHAR2_LEN
;
115 CopyMem (LfnEntry
.Name3
, LfnBufferPointer
, sizeof (CHAR16
) * LFN_CHAR3_LEN
);
116 LfnBufferPointer
+= LFN_CHAR3_LEN
;
118 if (DirEnt
->Invalid
) {
119 LfnEntry
.Ordinal
= DELETE_ENTRY_MARK
;
122 Status
= FatAccessEntry (OFile
, WriteData
, EntryPos
, &LfnEntry
);
123 if (EFI_ERROR (Status
)) {
134 Determine whether the directory entry is "." or ".." entry.
136 @param DirEnt - The corresponding directory entry.
138 @retval TRUE - The directory entry is "." or ".." directory entry
139 @retval FALSE - The directory entry is not "." or ".." directory entry
144 IN FAT_DIRENT
*DirEnt
148 FileString
= DirEnt
->FileString
;
149 if (StrCmp (FileString
, L
".") == 0 || StrCmp (FileString
, L
"..") == 0) {
158 Set the OFile's cluster info in its directory entry.
160 @param OFile - The corresponding OFile.
165 FatSetDirEntCluster (
172 DirEnt
= OFile
->DirEnt
;
173 Cluster
= OFile
->FileCluster
;
174 DirEnt
->Entry
.FileClusterHigh
= (UINT16
) (Cluster
>> 16);
175 DirEnt
->Entry
.FileCluster
= (UINT16
) Cluster
;
180 Set the OFile's cluster and size info in its directory entry.
182 @param OFile - The corresponding OFile.
186 FatUpdateDirEntClusterSizeInfo (
190 ASSERT (OFile
->ODir
== NULL
);
191 OFile
->DirEnt
->Entry
.FileSize
= (UINT32
) OFile
->FileSize
;
192 FatSetDirEntCluster (OFile
);
197 Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
199 @param DirEnt1 - The destination directory entry.
200 @param DirEnt2 - The source directory entry.
205 IN FAT_DIRENT
*DirEnt1
,
206 IN FAT_DIRENT
*DirEnt2
211 Entry1
= (UINT8
*) &DirEnt1
->Entry
;
212 Entry2
= (UINT8
*) &DirEnt2
->Entry
;
214 Entry1
+ FAT_ENTRY_INFO_OFFSET
,
215 Entry2
+ FAT_ENTRY_INFO_OFFSET
,
216 sizeof (FAT_DIRECTORY_ENTRY
) - FAT_ENTRY_INFO_OFFSET
222 Get the LFN for the directory entry.
224 @param Parent - The parent directory.
225 @param DirEnt - The directory entry to get LFN.
230 FatLoadLongNameEntry (
231 IN FAT_OFILE
*Parent
,
232 IN FAT_DIRENT
*DirEnt
235 CHAR16 LfnBuffer
[MAX_LFN_ENTRIES
* LFN_CHAR_TOTAL
+ 1];
236 CHAR16
*LfnBufferPointer
;
237 CHAR8
*File8Dot3Name
;
241 FAT_DIRECTORY_LFN LfnEntry
;
244 EntryPos
= DirEnt
->EntryPos
;
245 File8Dot3Name
= DirEnt
->Entry
.FileName
;
246 LfnBufferPointer
= LfnBuffer
;
248 // Computes checksum for LFN
250 LfnChecksum
= FatCheckSum (File8Dot3Name
);
254 LfnBufferPointer
= LfnBuffer
;
259 Status
= FatAccessEntry (Parent
, ReadData
, EntryPos
, &LfnEntry
);
260 if (EFI_ERROR (Status
) ||
261 LfnEntry
.Attributes
!= FAT_ATTRIBUTE_LFN
||
262 LfnEntry
.MustBeZero
!= 0 ||
263 LfnEntry
.Checksum
!= LfnChecksum
||
264 (LfnEntry
.Ordinal
& (~FAT_LFN_LAST
)) != LfnOrdinal
||
265 LfnOrdinal
> MAX_LFN_ENTRIES
268 // The directory entry does not have a long file name or
269 // some error occurs when loading long file name for a directory entry,
270 // and then we load the long name from short name
272 LfnBufferPointer
= LfnBuffer
;
276 CopyMem (LfnBufferPointer
, LfnEntry
.Name1
, sizeof (CHAR16
) * LFN_CHAR1_LEN
);
277 LfnBufferPointer
+= LFN_CHAR1_LEN
;
278 CopyMem (LfnBufferPointer
, LfnEntry
.Name2
, sizeof (CHAR16
) * LFN_CHAR2_LEN
);
279 LfnBufferPointer
+= LFN_CHAR2_LEN
;
280 CopyMem (LfnBufferPointer
, LfnEntry
.Name3
, sizeof (CHAR16
) * LFN_CHAR3_LEN
);
281 LfnBufferPointer
+= LFN_CHAR3_LEN
;
283 } while ((LfnEntry
.Ordinal
& FAT_LFN_LAST
) == 0);
284 DirEnt
->EntryCount
= LfnOrdinal
;
286 // Terminate current Lfnbuffer
288 *LfnBufferPointer
= 0;
289 if (LfnBufferPointer
== LfnBuffer
) {
291 // Fail to get the long file name from long file name entry,
292 // get the file name from short name
294 FatGetFileNameViaCaseFlag (
297 ARRAY_SIZE (LfnBuffer
)
301 DirEnt
->FileString
= AllocateCopyPool (StrSize (LfnBuffer
), LfnBuffer
);
306 Add this directory entry node to the list of directory entries and hash table.
308 @param ODir - The parent OFile which needs to be updated.
309 @param DirEnt - The directory entry to be added.
316 IN FAT_DIRENT
*DirEnt
319 if (DirEnt
->Link
.BackLink
== NULL
) {
320 DirEnt
->Link
.BackLink
= &ODir
->ChildList
;
322 InsertTailList (DirEnt
->Link
.BackLink
, &DirEnt
->Link
);
323 FatInsertToHashTable (ODir
, DirEnt
);
328 Load from disk the next directory entry at current end of directory position.
330 @param OFile - The parent OFile.
331 @param PtrDirEnt - The directory entry that is loaded.
333 @retval EFI_SUCCESS - Load the directory entry successfully.
334 @retval EFI_OUT_OF_RESOURCES - Out of resource.
335 @return other - An error occurred when reading the directory entries.
342 OUT FAT_DIRENT
**PtrDirEnt
348 FAT_DIRECTORY_ENTRY Entry
;
352 // Make sure the parent's directory has been opened
354 ASSERT (ODir
!= NULL
);
356 // Assert we have not reached the end of directory
358 ASSERT (!ODir
->EndOfDir
);
363 // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
365 Status
= FatAccessEntry (OFile
, ReadData
, ODir
->CurrentEndPos
, &Entry
);
366 if (EFI_ERROR (Status
)) {
370 if (((UINT8
) Entry
.FileName
[0] != DELETE_ENTRY_MARK
) && (Entry
.Attributes
& FAT_ATTRIBUTE_VOLUME_ID
) == 0) {
372 // We get a valid directory entry, then handle it
377 ODir
->CurrentEndPos
++;
380 if (Entry
.FileName
[0] != EMPTY_ENTRY_MARK
) {
382 // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications
383 // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.
385 if (OFile
->Volume
->FatType
!= Fat32
) {
386 Entry
.FileClusterHigh
= 0;
390 // This is a valid directory entry
392 DirEnt
= AllocateZeroPool (sizeof (FAT_DIRENT
));
393 if (DirEnt
== NULL
) {
394 return EFI_OUT_OF_RESOURCES
;
397 DirEnt
->Signature
= FAT_DIRENT_SIGNATURE
;
399 // Remember the directory's entry position on disk
401 DirEnt
->EntryPos
= (UINT16
) ODir
->CurrentEndPos
;
402 CopyMem (&DirEnt
->Entry
, &Entry
, sizeof (FAT_DIRECTORY_ENTRY
));
403 FatLoadLongNameEntry (OFile
, DirEnt
);
404 if (DirEnt
->FileString
== NULL
) {
405 Status
= EFI_OUT_OF_RESOURCES
;
409 // Add this directory entry to directory
411 FatAddDirEnt (ODir
, DirEnt
);
413 // Point to next directory entry
415 ODir
->CurrentEndPos
++;
417 ODir
->EndOfDir
= TRUE
;
424 FatFreeDirEnt (DirEnt
);
430 Get the directory entry's info into Buffer.
432 @param Volume - FAT file system volume.
433 @param DirEnt - The corresponding directory entry.
434 @param BufferSize - Size of Buffer.
435 @param Buffer - Buffer containing file info.
437 @retval EFI_SUCCESS - Get the file info successfully.
438 @retval EFI_BUFFER_TOO_SMALL - The buffer is too small.
443 IN FAT_VOLUME
*Volume
,
444 IN FAT_DIRENT
*DirEnt
,
445 IN OUT UINTN
*BufferSize
,
455 FAT_DIRECTORY_ENTRY
*Entry
;
456 FAT_DATE_TIME FatLastAccess
;
458 ASSERT_VOLUME_LOCKED (Volume
);
460 Size
= SIZE_OF_EFI_FILE_INFO
;
461 NameSize
= StrSize (DirEnt
->FileString
);
462 ResultSize
= Size
+ NameSize
;
464 Status
= EFI_BUFFER_TOO_SMALL
;
465 if (*BufferSize
>= ResultSize
) {
466 Status
= EFI_SUCCESS
;
467 Entry
= &DirEnt
->Entry
;
469 Info
->Size
= ResultSize
;
470 if ((Entry
->Attributes
& FAT_ATTRIBUTE_DIRECTORY
) != 0) {
471 Cluster
= (Entry
->FileClusterHigh
<< 16) | Entry
->FileCluster
;
472 Info
->PhysicalSize
= FatPhysicalDirSize (Volume
, Cluster
);
473 Info
->FileSize
= Info
->PhysicalSize
;
475 Info
->FileSize
= Entry
->FileSize
;
476 Info
->PhysicalSize
= FatPhysicalFileSize (Volume
, Entry
->FileSize
);
479 ZeroMem (&FatLastAccess
.Time
, sizeof (FatLastAccess
.Time
));
480 CopyMem (&FatLastAccess
.Date
, &Entry
->FileLastAccess
, sizeof (FatLastAccess
.Date
));
481 FatFatTimeToEfiTime (&FatLastAccess
, &Info
->LastAccessTime
);
482 FatFatTimeToEfiTime (&Entry
->FileCreateTime
, &Info
->CreateTime
);
483 FatFatTimeToEfiTime (&Entry
->FileModificationTime
, &Info
->ModificationTime
);
484 Info
->Attribute
= Entry
->Attributes
& EFI_FILE_VALID_ATTR
;
485 CopyMem ((CHAR8
*) Buffer
+ Size
, DirEnt
->FileString
, NameSize
);
488 *BufferSize
= ResultSize
;
494 Search the directory for the directory entry whose filename is FileNameString.
496 @param OFile - The parent OFile whose directory is to be searched.
497 @param FileNameString - The filename to be searched.
498 @param PtrDirEnt - pointer to the directory entry if found.
500 @retval EFI_SUCCESS - Find the directory entry or not found.
501 @return other - An error occurred when reading the directory entries.
508 IN CHAR16
*FileNameString
,
509 OUT FAT_DIRENT
**PtrDirEnt
512 BOOLEAN PossibleShortName
;
513 CHAR8 File8Dot3Name
[FAT_NAME_LEN
];
519 ASSERT (ODir
!= NULL
);
521 // Check if the file name is a valid short name
523 PossibleShortName
= FatCheckIs8Dot3Name (FileNameString
, File8Dot3Name
);
525 // Search the hash table first
527 DirEnt
= *FatLongNameHashSearch (ODir
, FileNameString
);
528 if (DirEnt
== NULL
&& PossibleShortName
) {
529 DirEnt
= *FatShortNameHashSearch (ODir
, File8Dot3Name
);
531 if (DirEnt
== NULL
) {
533 // We fail to get the directory entry from hash table; we then
534 // search the rest directory
536 while (!ODir
->EndOfDir
) {
537 Status
= FatLoadNextDirEnt (OFile
, &DirEnt
);
538 if (EFI_ERROR (Status
)) {
542 if (DirEnt
!= NULL
) {
543 if (FatStriCmp (FileNameString
, DirEnt
->FileString
) == 0) {
547 if (PossibleShortName
&& CompareMem (File8Dot3Name
, DirEnt
->Entry
.FileName
, FAT_NAME_LEN
) == 0) {
560 Set the OFile's current directory cursor to the list head.
562 @param OFile - The directory OFile whose directory cursor is reset.
573 ASSERT (ODir
!= NULL
);
574 ODir
->CurrentCursor
= &(ODir
->ChildList
);
575 ODir
->CurrentPos
= 0;
580 Set the directory's cursor to the next and get the next directory entry.
582 @param OFile - The parent OFile.
583 @param PtrDirEnt - The next directory entry.
585 @retval EFI_SUCCESS - We get the next directory entry successfully.
586 @return other - An error occurred when get next directory entry.
592 OUT FAT_DIRENT
**PtrDirEnt
600 ASSERT (ODir
!= NULL
);
601 if (ODir
->CurrentCursor
->ForwardLink
== &ODir
->ChildList
) {
603 // End of directory, we will try one more time
605 if (!ODir
->EndOfDir
) {
607 // Read directory from disk
609 Status
= FatLoadNextDirEnt (OFile
, &DirEnt
);
610 if (EFI_ERROR (Status
)) {
616 if (ODir
->CurrentCursor
->ForwardLink
== &ODir
->ChildList
) {
618 // End of directory, return NULL
621 ODir
->CurrentPos
= ODir
->CurrentEndPos
;
623 ODir
->CurrentCursor
= ODir
->CurrentCursor
->ForwardLink
;
624 DirEnt
= DIRENT_FROM_LINK (ODir
->CurrentCursor
);
625 ODir
->CurrentPos
= DirEnt
->EntryPos
+ 1;
634 Set the directory entry count according to the filename.
636 @param OFile - The corresponding OFile.
637 @param DirEnt - The directory entry to be set.
644 IN FAT_DIRENT
*DirEnt
648 CHAR8
*File8Dot3Name
;
651 // Get new entry count and set the 8.3 name
653 DirEnt
->EntryCount
= 1;
654 FileString
= DirEnt
->FileString
;
655 File8Dot3Name
= DirEnt
->Entry
.FileName
;
656 SetMem (File8Dot3Name
, FAT_NAME_LEN
, ' ');
657 if (StrCmp (FileString
, L
".") == 0) {
661 File8Dot3Name
[0] = '.';
662 FatCloneDirEnt (DirEnt
, OFile
->DirEnt
);
663 } else if (StrCmp (FileString
, L
"..") == 0) {
667 File8Dot3Name
[0] = '.';
668 File8Dot3Name
[1] = '.';
669 FatCloneDirEnt (DirEnt
, OFile
->Parent
->DirEnt
);
674 if (FatCheckIs8Dot3Name (FileString
, File8Dot3Name
)) {
676 // This file name is a valid 8.3 file name, we need to further check its case flag
678 FatSetCaseFlag (DirEnt
);
681 // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
683 FatCreate8Dot3Name (OFile
, DirEnt
);
684 DirEnt
->EntryCount
= (UINT8
)(LFN_ENTRY_NUMBER (StrLen (FileString
)) + DirEnt
->EntryCount
);
691 Append a zero cluster to the current OFile.
693 @param OFile - The directory OFile which needs to be updated.
695 @retval EFI_SUCCESS - Append a zero cluster to the OFile successfully.
696 @return other - An error occurred when appending the zero cluster.
705 return FatExpandOFile (OFile
, OFile
->FileSize
+ OFile
->Volume
->ClusterSize
);
710 Search the Root OFile for the possible volume label.
712 @param Root - The Root OFile.
713 @param DirEnt - The returned directory entry of volume label.
715 @retval EFI_SUCCESS - The search process is completed successfully.
716 @return other - An error occurred when searching volume label.
723 OUT FAT_DIRENT
*DirEnt
728 FAT_DIRECTORY_ENTRY
*Entry
;
731 Entry
= &DirEnt
->Entry
;
732 DirEnt
->Invalid
= TRUE
;
734 Status
= FatAccessEntry (Root
, ReadData
, EntryPos
, Entry
);
735 if (EFI_ERROR (Status
)) {
739 if (((UINT8
) Entry
->FileName
[0] != DELETE_ENTRY_MARK
) && (((Entry
->Attributes
) & (~FAT_ATTRIBUTE_ARCHIVE
)) == FAT_ATTRIBUTE_VOLUME_ID
)) {
740 DirEnt
->EntryPos
= (UINT16
) EntryPos
;
741 DirEnt
->EntryCount
= 1;
742 DirEnt
->Invalid
= FALSE
;
747 } while (Entry
->FileName
[0] != EMPTY_ENTRY_MARK
);
753 Use First Fit Algorithm to insert directory entry.
754 Only this function will erase "E5" entries in a directory.
755 In view of safest recovery, this function will only be triggered
756 when maximum directory entry number has reached.
758 @param OFile - The corresponding OFile.
759 @param DirEnt - The directory entry to be inserted.
761 @retval EFI_SUCCESS - The directory entry has been successfully inserted.
762 @retval EFI_VOLUME_FULL - The directory can not hold more directory entries.
763 @return Others - Some error occurred when inserting new directory entries.
768 FatFirstFitInsertDirEnt (
770 IN FAT_DIRENT
*DirEnt
775 LIST_ENTRY
*CurrentEntry
;
776 FAT_DIRENT
*CurrentDirEnt
;
781 FAT_DIRENT LabelDirEnt
;
784 if (OFile
->Parent
== NULL
) {
785 Status
= FatSeekVolumeId (OFile
, &LabelDirEnt
);
786 if (EFI_ERROR (Status
)) {
790 if (!LabelDirEnt
.Invalid
) {
791 LabelPos
= LabelDirEnt
.EntryPos
;
795 EntryCount
= DirEnt
->EntryCount
;
796 NewEntryPos
= EntryCount
;
799 for (CurrentEntry
= ODir
->ChildList
.ForwardLink
;
800 CurrentEntry
!= &ODir
->ChildList
;
801 CurrentEntry
= CurrentEntry
->ForwardLink
803 CurrentDirEnt
= DIRENT_FROM_LINK (CurrentEntry
);
804 if (NewEntryPos
+ CurrentDirEnt
->EntryCount
<= CurrentDirEnt
->EntryPos
) {
805 if (LabelPos
> NewEntryPos
|| LabelPos
<= CurrentPos
) {
807 // first fit succeeded
813 CurrentPos
= CurrentDirEnt
->EntryPos
;
814 NewEntryPos
= CurrentPos
+ EntryCount
;
817 if (NewEntryPos
>= ODir
->CurrentEndPos
) {
818 return EFI_VOLUME_FULL
;
822 DirEnt
->EntryPos
= (UINT16
) NewEntryPos
;
823 DirEnt
->Link
.BackLink
= CurrentEntry
;
829 Find the new directory entry position for the directory entry.
831 @param OFile - The corresponding OFile.
832 @param DirEnt - The directory entry whose new position is to be set.
834 @retval EFI_SUCCESS - The new directory entry position is successfully found.
835 @retval EFI_VOLUME_FULL - The directory has reach its maximum capacity.
836 @return other - An error occurred when reading the directory entry.
843 IN FAT_DIRENT
*DirEnt
848 FAT_DIRENT
*TempDirEnt
;
852 ASSERT (ODir
!= NULL
);
854 // Make sure the whole directory has been loaded
856 while (!ODir
->EndOfDir
) {
857 Status
= FatLoadNextDirEnt (OFile
, &TempDirEnt
);
858 if (EFI_ERROR (Status
)) {
863 // We will append this entry to the end of directory
865 FatGetCurrentFatTime (&DirEnt
->Entry
.FileCreateTime
);
866 CopyMem (&DirEnt
->Entry
.FileModificationTime
, &DirEnt
->Entry
.FileCreateTime
, sizeof (FAT_DATE_TIME
));
867 CopyMem (&DirEnt
->Entry
.FileLastAccess
, &DirEnt
->Entry
.FileCreateTime
.Date
, sizeof (FAT_DATE
));
868 NewEndPos
= ODir
->CurrentEndPos
+ DirEnt
->EntryCount
;
869 if (NewEndPos
* sizeof (FAT_DIRECTORY_ENTRY
) > OFile
->FileSize
) {
870 if (NewEndPos
>= (OFile
->IsFixedRootDir
? OFile
->Volume
->RootEntries
: FAT_MAX_DIRENTRY_COUNT
)) {
872 // We try to use fist fit algorithm to insert this directory entry
874 return FatFirstFitInsertDirEnt (OFile
, DirEnt
);
877 // We should allocate a new cluster for this directory
879 Status
= FatExpandODir (OFile
);
880 if (EFI_ERROR (Status
)) {
885 // We append our directory entry at the end of directory file
887 ODir
->CurrentEndPos
= NewEndPos
;
888 DirEnt
->EntryPos
= (UINT16
) (ODir
->CurrentEndPos
- 1);
894 Get the directory entry for the volume.
896 @param Volume - FAT file system volume.
897 @param Name - The file name of the volume.
899 @retval EFI_SUCCESS - Update the volume with the directory entry sucessfully.
900 @return others - An error occurred when getting volume label.
905 IN FAT_VOLUME
*Volume
,
910 FAT_DIRENT LabelDirEnt
;
913 Status
= FatSeekVolumeId (Volume
->Root
, &LabelDirEnt
);
914 if (!EFI_ERROR (Status
)) {
915 if (!LabelDirEnt
.Invalid
) {
916 FatNameToStr (LabelDirEnt
.Entry
.FileName
, FAT_NAME_LEN
, FALSE
, Name
);
925 Set the relevant directory entry into disk for the volume.
927 @param Volume - FAT file system volume.
928 @param Name - The new file name of the volume.
930 @retval EFI_SUCCESS - Update the Volume sucessfully.
931 @retval EFI_UNSUPPORTED - The input label is not a valid volume label.
932 @return other - An error occurred when setting volume label.
937 IN FAT_VOLUME
*Volume
,
942 FAT_DIRENT LabelDirEnt
;
946 Status
= FatSeekVolumeId (Volume
->Root
, &LabelDirEnt
);
947 if (EFI_ERROR (Status
)) {
951 if (LabelDirEnt
.Invalid
) {
953 // If there is not the relevant directory entry, create a new one
955 ZeroMem (&LabelDirEnt
, sizeof (FAT_DIRENT
));
956 LabelDirEnt
.EntryCount
= 1;
957 Status
= FatNewEntryPos (Root
, &LabelDirEnt
);
958 if (EFI_ERROR (Status
)) {
962 LabelDirEnt
.Entry
.Attributes
= FAT_ATTRIBUTE_VOLUME_ID
;
965 SetMem (LabelDirEnt
.Entry
.FileName
, FAT_NAME_LEN
, ' ');
966 if (FatStrToFat (Name
, FAT_NAME_LEN
, LabelDirEnt
.Entry
.FileName
)) {
967 return EFI_UNSUPPORTED
;
970 FatGetCurrentFatTime (&LabelDirEnt
.Entry
.FileModificationTime
);
971 return FatStoreDirEnt (Root
, &LabelDirEnt
);
976 Create "." and ".." directory entries in the newly-created parent OFile.
978 @param OFile - The parent OFile.
980 @retval EFI_SUCCESS - The dot directory entries are successfully created.
981 @return other - An error occurred when creating the directory entry.
985 FatCreateDotDirEnts (
992 Status
= FatExpandODir (OFile
);
993 if (EFI_ERROR (Status
)) {
997 FatSetDirEntCluster (OFile
);
1001 Status
= FatCreateDirEnt (OFile
, L
".", FAT_ATTRIBUTE_DIRECTORY
, &DirEnt
);
1002 if (EFI_ERROR (Status
)) {
1008 Status
= FatCreateDirEnt (OFile
, L
"..", FAT_ATTRIBUTE_DIRECTORY
, &DirEnt
);
1014 Create a directory entry in the parent OFile.
1016 @param OFile - The parent OFile.
1017 @param FileName - The filename of the newly-created directory entry.
1018 @param Attributes - The attribute of the newly-created directory entry.
1019 @param PtrDirEnt - The pointer to the newly-created directory entry.
1021 @retval EFI_SUCCESS - The directory entry is successfully created.
1022 @retval EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry.
1023 @return other - An error occurred when creating the directory entry.
1028 IN FAT_OFILE
*OFile
,
1029 IN CHAR16
*FileName
,
1030 IN UINT8 Attributes
,
1031 OUT FAT_DIRENT
**PtrDirEnt
1038 ASSERT (OFile
!= NULL
);
1040 ASSERT (ODir
!= NULL
);
1041 DirEnt
= AllocateZeroPool (sizeof (FAT_DIRENT
));
1042 if (DirEnt
== NULL
) {
1043 return EFI_OUT_OF_RESOURCES
;
1046 DirEnt
->Signature
= FAT_DIRENT_SIGNATURE
;
1047 DirEnt
->FileString
= AllocateCopyPool (StrSize (FileName
), FileName
);
1048 if (DirEnt
->FileString
== NULL
) {
1049 Status
= EFI_OUT_OF_RESOURCES
;
1053 // Determine how many directory entries we need
1055 FatSetEntryCount (OFile
, DirEnt
);
1057 // Determine the file's directory entry position
1059 Status
= FatNewEntryPos (OFile
, DirEnt
);
1060 if (EFI_ERROR (Status
)) {
1064 FatAddDirEnt (ODir
, DirEnt
);
1065 DirEnt
->Entry
.Attributes
= Attributes
;
1066 *PtrDirEnt
= DirEnt
;
1067 DEBUG ((EFI_D_INFO
, "FSOpen: Created new directory entry '%S'\n", DirEnt
->FileString
));
1068 return FatStoreDirEnt (OFile
, DirEnt
);
1071 FatFreeDirEnt (DirEnt
);
1077 Remove this directory entry node from the list of directory entries and hash table.
1079 @param OFile - The parent OFile.
1080 @param DirEnt - The directory entry to be removed.
1082 @retval EFI_SUCCESS - The directory entry is successfully removed.
1083 @return other - An error occurred when removing the directory entry.
1088 IN FAT_OFILE
*OFile
,
1089 IN FAT_DIRENT
*DirEnt
1095 if (ODir
->CurrentCursor
== &DirEnt
->Link
) {
1097 // Move the directory cursor to its previous directory entry
1099 ODir
->CurrentCursor
= ODir
->CurrentCursor
->BackLink
;
1102 // Remove from directory entry list
1104 RemoveEntryList (&DirEnt
->Link
);
1106 // Remove from hash table
1108 FatDeleteFromHashTable (ODir
, DirEnt
);
1109 DirEnt
->Entry
.FileName
[0] = DELETE_ENTRY_MARK
;
1110 DirEnt
->Invalid
= TRUE
;
1111 return FatStoreDirEnt (OFile
, DirEnt
);
1116 Open the directory entry to get the OFile.
1118 @param Parent - The parent OFile.
1119 @param DirEnt - The directory entry to be opened.
1121 @retval EFI_SUCCESS - The directory entry is successfully opened.
1122 @retval EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile.
1123 @return other - An error occurred when opening the directory entry.
1128 IN FAT_OFILE
*Parent
,
1129 IN FAT_DIRENT
*DirEnt
1135 if (DirEnt
->OFile
== NULL
) {
1137 // Open the directory entry
1139 OFile
= AllocateZeroPool (sizeof (FAT_OFILE
));
1140 if (OFile
== NULL
) {
1141 return EFI_OUT_OF_RESOURCES
;
1144 OFile
->Signature
= FAT_OFILE_SIGNATURE
;
1145 InitializeListHead (&OFile
->Opens
);
1146 InitializeListHead (&OFile
->ChildHead
);
1147 OFile
->Parent
= Parent
;
1148 OFile
->DirEnt
= DirEnt
;
1149 if (Parent
!= NULL
) {
1151 // The newly created OFile is not root
1153 Volume
= Parent
->Volume
;
1154 OFile
->FullPathLen
= Parent
->FullPathLen
+ 1 + StrLen (DirEnt
->FileString
);
1155 OFile
->FileCluster
= ((DirEnt
->Entry
.FileClusterHigh
) << 16) | (DirEnt
->Entry
.FileCluster
);
1156 InsertTailList (&Parent
->ChildHead
, &OFile
->ChildLink
);
1159 // The newly created OFile is root
1161 Volume
= VOLUME_FROM_ROOT_DIRENT (DirEnt
);
1162 Volume
->Root
= OFile
;
1163 OFile
->FileCluster
= Volume
->RootCluster
;
1164 if (Volume
->FatType
!= Fat32
) {
1165 OFile
->IsFixedRootDir
= TRUE
;
1169 OFile
->FileCurrentCluster
= OFile
->FileCluster
;
1170 OFile
->Volume
= Volume
;
1171 InsertHeadList (&Volume
->CheckRef
, &OFile
->CheckLink
);
1173 OFile
->FileSize
= DirEnt
->Entry
.FileSize
;
1174 if ((DirEnt
->Entry
.Attributes
& FAT_ATTRIBUTE_DIRECTORY
) != 0) {
1175 if (OFile
->IsFixedRootDir
) {
1176 OFile
->FileSize
= Volume
->RootEntries
* sizeof (FAT_DIRECTORY_ENTRY
);
1178 OFile
->FileSize
= FatPhysicalDirSize (Volume
, OFile
->FileCluster
);
1181 FatRequestODir (OFile
);
1182 if (OFile
->ODir
== NULL
) {
1183 return EFI_OUT_OF_RESOURCES
;
1187 DirEnt
->OFile
= OFile
;
1195 Close the directory entry and free the OFile.
1197 @param DirEnt - The directory entry to be closed.
1202 IN FAT_DIRENT
*DirEnt
1208 OFile
= DirEnt
->OFile
;
1209 ASSERT (OFile
!= NULL
);
1210 Volume
= OFile
->Volume
;
1212 if (OFile
->ODir
!= NULL
) {
1213 FatDiscardODir (OFile
);
1216 if (OFile
->Parent
== NULL
) {
1217 Volume
->Root
= NULL
;
1219 RemoveEntryList (&OFile
->ChildLink
);
1223 DirEnt
->OFile
= NULL
;
1224 if (DirEnt
->Invalid
== TRUE
) {
1226 // Free directory entry itself
1228 FatFreeDirEnt (DirEnt
);
1234 Traverse filename and open all OFiles that can be opened.
1235 Update filename pointer to the component that can't be opened.
1236 If more than one name component remains, returns an error;
1237 otherwise, return the remaining name component so that the caller might choose to create it.
1239 @param PtrOFile - As input, the reference OFile; as output, the located OFile.
1240 @param FileName - The file name relevant to the OFile.
1241 @param Attributes - The attribute of the destination OFile.
1242 @param NewFileName - The remaining file name.
1244 @retval EFI_NOT_FOUND - The file name can't be opened and there is more than one
1245 components within the name left (this means the name can
1246 not be created either).
1247 @retval EFI_INVALID_PARAMETER - The parameter is not valid.
1248 @retval EFI_SUCCESS - Open the file successfully.
1249 @return other - An error occured when locating the OFile.
1254 IN OUT FAT_OFILE
**PtrOFile
,
1255 IN CHAR16
*FileName
,
1256 IN UINT8 Attributes
,
1257 OUT CHAR16
*NewFileName
1262 CHAR16 ComponentName
[EFI_PATH_STRING_LENGTH
];
1264 BOOLEAN DirIntended
;
1271 FileNameLen
= StrLen (FileName
);
1272 if (FileNameLen
== 0) {
1273 return EFI_INVALID_PARAMETER
;
1277 Volume
= OFile
->Volume
;
1279 DirIntended
= FALSE
;
1280 if (FileName
[FileNameLen
- 1] == PATH_NAME_SEPARATOR
) {
1284 // If name starts with path name separator, then move to root OFile
1286 if (*FileName
== PATH_NAME_SEPARATOR
) {
1287 OFile
= Volume
->Root
;
1292 // Per FAT Spec the file name should meet the following criteria:
1293 // C1. Length (FileLongName) <= 255
1294 // C2. Length (X:FileFullPath<NUL>) <= 260
1295 // Here we check C2 first.
1297 if (2 + OFile
->FullPathLen
+ 1 + FileNameLen
+ 1 > EFI_PATH_STRING_LENGTH
) {
1299 // Full path length can not surpass 256
1301 return EFI_INVALID_PARAMETER
;
1304 // Start at current location
1309 // Get the next component name
1312 Next
= FatGetNextNameComponent (FileName
, ComponentName
);
1315 // If end of the file name, we're done
1317 if (ComponentName
[0] == 0) {
1318 if (DirIntended
&& OFile
->ODir
== NULL
) {
1319 return EFI_NOT_FOUND
;
1326 // If "dot", then current
1328 if (StrCmp (ComponentName
, L
".") == 0) {
1332 // If "dot dot", then parent
1334 if (StrCmp (ComponentName
, L
"..") == 0) {
1335 if (OFile
->Parent
== NULL
) {
1336 return EFI_INVALID_PARAMETER
;
1338 OFile
= OFile
->Parent
;
1342 if (!FatFileNameIsValid (ComponentName
, NewFileName
)) {
1343 return EFI_INVALID_PARAMETER
;
1346 // We have a component name, try to open it
1348 if (OFile
->ODir
== NULL
) {
1350 // This file isn't a directory, can't open it
1352 return EFI_NOT_FOUND
;
1355 // Search the compName in the directory
1357 Status
= FatSearchODir (OFile
, NewFileName
, &DirEnt
);
1358 if (EFI_ERROR (Status
)) {
1362 if (DirEnt
== NULL
) {
1364 // component name is not found in the directory
1367 return EFI_NOT_FOUND
;
1370 if (DirIntended
&& (Attributes
& FAT_ATTRIBUTE_DIRECTORY
) == 0) {
1371 return EFI_INVALID_PARAMETER
;
1374 // It's the last component name - return with the open
1375 // path and the remaining name
1380 Status
= FatOpenDirEnt (OFile
, DirEnt
);
1381 if (EFI_ERROR (Status
)) {
1385 OFile
= DirEnt
->OFile
;