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 directory 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 successfully.
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
149 FileString
= DirEnt
->FileString
;
150 if ((StrCmp (FileString
, L
".") == 0) || (StrCmp (FileString
, L
"..") == 0)) {
159 Set the OFile's cluster info in its directory entry.
161 @param OFile - The corresponding OFile.
166 FatSetDirEntCluster (
173 DirEnt
= OFile
->DirEnt
;
174 Cluster
= OFile
->FileCluster
;
175 DirEnt
->Entry
.FileClusterHigh
= (UINT16
)(Cluster
>> 16);
176 DirEnt
->Entry
.FileCluster
= (UINT16
)Cluster
;
181 Set the OFile's cluster and size info in its directory entry.
183 @param OFile - The corresponding OFile.
187 FatUpdateDirEntClusterSizeInfo (
191 ASSERT (OFile
->ODir
== NULL
);
192 OFile
->DirEnt
->Entry
.FileSize
= (UINT32
)OFile
->FileSize
;
193 FatSetDirEntCluster (OFile
);
198 Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
200 @param DirEnt1 - The destination directory entry.
201 @param DirEnt2 - The source directory entry.
206 IN FAT_DIRENT
*DirEnt1
,
207 IN FAT_DIRENT
*DirEnt2
213 Entry1
= (UINT8
*)&DirEnt1
->Entry
;
214 Entry2
= (UINT8
*)&DirEnt2
->Entry
;
216 Entry1
+ FAT_ENTRY_INFO_OFFSET
,
217 Entry2
+ FAT_ENTRY_INFO_OFFSET
,
218 sizeof (FAT_DIRECTORY_ENTRY
) - FAT_ENTRY_INFO_OFFSET
224 Get the LFN for the directory entry.
226 @param Parent - The parent directory.
227 @param DirEnt - The directory entry to get LFN.
232 FatLoadLongNameEntry (
233 IN FAT_OFILE
*Parent
,
234 IN FAT_DIRENT
*DirEnt
237 CHAR16 LfnBuffer
[MAX_LFN_ENTRIES
* LFN_CHAR_TOTAL
+ 1];
238 CHAR16
*LfnBufferPointer
;
239 CHAR8
*File8Dot3Name
;
243 FAT_DIRECTORY_LFN LfnEntry
;
246 EntryPos
= DirEnt
->EntryPos
;
247 File8Dot3Name
= DirEnt
->Entry
.FileName
;
248 LfnBufferPointer
= LfnBuffer
;
250 // Computes checksum for LFN
252 LfnChecksum
= FatCheckSum (File8Dot3Name
);
256 LfnBufferPointer
= LfnBuffer
;
261 Status
= FatAccessEntry (Parent
, ReadData
, EntryPos
, &LfnEntry
);
262 if (EFI_ERROR (Status
) ||
263 (LfnEntry
.Attributes
!= FAT_ATTRIBUTE_LFN
) ||
264 (LfnEntry
.MustBeZero
!= 0) ||
265 (LfnEntry
.Checksum
!= LfnChecksum
) ||
266 ((LfnEntry
.Ordinal
& (~FAT_LFN_LAST
)) != LfnOrdinal
) ||
267 (LfnOrdinal
> MAX_LFN_ENTRIES
)
271 // The directory entry does not have a long file name or
272 // some error occurs when loading long file name for a directory entry,
273 // and then we load the long name from short name
275 LfnBufferPointer
= LfnBuffer
;
279 CopyMem (LfnBufferPointer
, LfnEntry
.Name1
, sizeof (CHAR16
) * LFN_CHAR1_LEN
);
280 LfnBufferPointer
+= LFN_CHAR1_LEN
;
281 CopyMem (LfnBufferPointer
, LfnEntry
.Name2
, sizeof (CHAR16
) * LFN_CHAR2_LEN
);
282 LfnBufferPointer
+= LFN_CHAR2_LEN
;
283 CopyMem (LfnBufferPointer
, LfnEntry
.Name3
, sizeof (CHAR16
) * LFN_CHAR3_LEN
);
284 LfnBufferPointer
+= LFN_CHAR3_LEN
;
286 } while ((LfnEntry
.Ordinal
& FAT_LFN_LAST
) == 0);
288 DirEnt
->EntryCount
= LfnOrdinal
;
290 // Terminate current Lfnbuffer
292 *LfnBufferPointer
= 0;
293 if (LfnBufferPointer
== LfnBuffer
) {
295 // Fail to get the long file name from long file name entry,
296 // get the file name from short name
298 FatGetFileNameViaCaseFlag (
301 ARRAY_SIZE (LfnBuffer
)
305 DirEnt
->FileString
= AllocateCopyPool (StrSize (LfnBuffer
), LfnBuffer
);
310 Add this directory entry node to the list of directory entries and hash table.
312 @param ODir - The parent OFile which needs to be updated.
313 @param DirEnt - The directory entry to be added.
320 IN FAT_DIRENT
*DirEnt
323 if (DirEnt
->Link
.BackLink
== NULL
) {
324 DirEnt
->Link
.BackLink
= &ODir
->ChildList
;
327 InsertTailList (DirEnt
->Link
.BackLink
, &DirEnt
->Link
);
328 FatInsertToHashTable (ODir
, DirEnt
);
333 Load from disk the next directory entry at current end of directory position.
335 @param OFile - The parent OFile.
336 @param PtrDirEnt - The directory entry that is loaded.
338 @retval EFI_SUCCESS - Load the directory entry successfully.
339 @retval EFI_OUT_OF_RESOURCES - Out of resource.
340 @return other - An error occurred when reading the directory entries.
347 OUT FAT_DIRENT
**PtrDirEnt
353 FAT_DIRECTORY_ENTRY Entry
;
357 // Make sure the parent's directory has been opened
359 ASSERT (ODir
!= NULL
);
361 // Assert we have not reached the end of directory
363 ASSERT (!ODir
->EndOfDir
);
368 // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
370 Status
= FatAccessEntry (OFile
, ReadData
, ODir
->CurrentEndPos
, &Entry
);
371 if (EFI_ERROR (Status
)) {
375 if (((UINT8
)Entry
.FileName
[0] != DELETE_ENTRY_MARK
) && ((Entry
.Attributes
& FAT_ATTRIBUTE_VOLUME_ID
) == 0)) {
377 // We get a valid directory entry, then handle it
382 ODir
->CurrentEndPos
++;
385 if (Entry
.FileName
[0] != EMPTY_ENTRY_MARK
) {
387 // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications
388 // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.
390 if (OFile
->Volume
->FatType
!= Fat32
) {
391 Entry
.FileClusterHigh
= 0;
395 // This is a valid directory entry
397 DirEnt
= AllocateZeroPool (sizeof (FAT_DIRENT
));
398 if (DirEnt
== NULL
) {
399 return EFI_OUT_OF_RESOURCES
;
402 DirEnt
->Signature
= FAT_DIRENT_SIGNATURE
;
404 // Remember the directory's entry position on disk
406 DirEnt
->EntryPos
= (UINT16
)ODir
->CurrentEndPos
;
407 CopyMem (&DirEnt
->Entry
, &Entry
, sizeof (FAT_DIRECTORY_ENTRY
));
408 FatLoadLongNameEntry (OFile
, DirEnt
);
409 if (DirEnt
->FileString
== NULL
) {
410 Status
= EFI_OUT_OF_RESOURCES
;
415 // Add this directory entry to directory
417 FatAddDirEnt (ODir
, DirEnt
);
419 // Point to next directory entry
421 ODir
->CurrentEndPos
++;
423 ODir
->EndOfDir
= TRUE
;
430 FatFreeDirEnt (DirEnt
);
436 Get the directory entry's info into Buffer.
438 @param Volume - FAT file system volume.
439 @param DirEnt - The corresponding directory entry.
440 @param BufferSize - Size of Buffer.
441 @param Buffer - Buffer containing file info.
443 @retval EFI_SUCCESS - Get the file info successfully.
444 @retval EFI_BUFFER_TOO_SMALL - The buffer is too small.
449 IN FAT_VOLUME
*Volume
,
450 IN FAT_DIRENT
*DirEnt
,
451 IN OUT UINTN
*BufferSize
,
461 FAT_DIRECTORY_ENTRY
*Entry
;
462 FAT_DATE_TIME FatLastAccess
;
464 ASSERT_VOLUME_LOCKED (Volume
);
466 Size
= SIZE_OF_EFI_FILE_INFO
;
467 NameSize
= StrSize (DirEnt
->FileString
);
468 ResultSize
= Size
+ NameSize
;
470 Status
= EFI_BUFFER_TOO_SMALL
;
471 if (*BufferSize
>= ResultSize
) {
472 Status
= EFI_SUCCESS
;
473 Entry
= &DirEnt
->Entry
;
475 Info
->Size
= ResultSize
;
476 if ((Entry
->Attributes
& FAT_ATTRIBUTE_DIRECTORY
) != 0) {
477 Cluster
= (Entry
->FileClusterHigh
<< 16) | Entry
->FileCluster
;
478 Info
->PhysicalSize
= FatPhysicalDirSize (Volume
, Cluster
);
479 Info
->FileSize
= Info
->PhysicalSize
;
481 Info
->FileSize
= Entry
->FileSize
;
482 Info
->PhysicalSize
= FatPhysicalFileSize (Volume
, Entry
->FileSize
);
485 ZeroMem (&FatLastAccess
.Time
, sizeof (FatLastAccess
.Time
));
486 CopyMem (&FatLastAccess
.Date
, &Entry
->FileLastAccess
, sizeof (FatLastAccess
.Date
));
487 FatFatTimeToEfiTime (&FatLastAccess
, &Info
->LastAccessTime
);
488 FatFatTimeToEfiTime (&Entry
->FileCreateTime
, &Info
->CreateTime
);
489 FatFatTimeToEfiTime (&Entry
->FileModificationTime
, &Info
->ModificationTime
);
490 Info
->Attribute
= Entry
->Attributes
& EFI_FILE_VALID_ATTR
;
491 CopyMem ((CHAR8
*)Buffer
+ Size
, DirEnt
->FileString
, NameSize
);
494 *BufferSize
= ResultSize
;
500 Search the directory for the directory entry whose filename is FileNameString.
502 @param OFile - The parent OFile whose directory is to be searched.
503 @param FileNameString - The filename to be searched.
504 @param PtrDirEnt - pointer to the directory entry if found.
506 @retval EFI_SUCCESS - Find the directory entry or not found.
507 @return other - An error occurred when reading the directory entries.
514 IN CHAR16
*FileNameString
,
515 OUT FAT_DIRENT
**PtrDirEnt
518 BOOLEAN PossibleShortName
;
519 CHAR8 File8Dot3Name
[FAT_NAME_LEN
];
525 ASSERT (ODir
!= NULL
);
527 // Check if the file name is a valid short name
529 PossibleShortName
= FatCheckIs8Dot3Name (FileNameString
, File8Dot3Name
);
531 // Search the hash table first
533 DirEnt
= *FatLongNameHashSearch (ODir
, FileNameString
);
534 if ((DirEnt
== NULL
) && PossibleShortName
) {
535 DirEnt
= *FatShortNameHashSearch (ODir
, File8Dot3Name
);
538 if (DirEnt
== NULL
) {
540 // We fail to get the directory entry from hash table; we then
541 // search the rest directory
543 while (!ODir
->EndOfDir
) {
544 Status
= FatLoadNextDirEnt (OFile
, &DirEnt
);
545 if (EFI_ERROR (Status
)) {
549 if (DirEnt
!= NULL
) {
550 if (FatStriCmp (FileNameString
, DirEnt
->FileString
) == 0) {
554 if (PossibleShortName
&& (CompareMem (File8Dot3Name
, DirEnt
->Entry
.FileName
, FAT_NAME_LEN
) == 0)) {
567 Set the OFile's current directory cursor to the list head.
569 @param OFile - The directory OFile whose directory cursor is reset.
580 ASSERT (ODir
!= NULL
);
581 ODir
->CurrentCursor
= &(ODir
->ChildList
);
582 ODir
->CurrentPos
= 0;
587 Set the directory's cursor to the next and get the next directory entry.
589 @param OFile - The parent OFile.
590 @param PtrDirEnt - The next directory entry.
592 @retval EFI_SUCCESS - We get the next directory entry successfully.
593 @return other - An error occurred when get next directory entry.
599 OUT FAT_DIRENT
**PtrDirEnt
607 ASSERT (ODir
!= NULL
);
608 if (ODir
->CurrentCursor
->ForwardLink
== &ODir
->ChildList
) {
610 // End of directory, we will try one more time
612 if (!ODir
->EndOfDir
) {
614 // Read directory from disk
616 Status
= FatLoadNextDirEnt (OFile
, &DirEnt
);
617 if (EFI_ERROR (Status
)) {
623 if (ODir
->CurrentCursor
->ForwardLink
== &ODir
->ChildList
) {
625 // End of directory, return NULL
628 ODir
->CurrentPos
= ODir
->CurrentEndPos
;
630 ODir
->CurrentCursor
= ODir
->CurrentCursor
->ForwardLink
;
631 DirEnt
= DIRENT_FROM_LINK (ODir
->CurrentCursor
);
632 ODir
->CurrentPos
= DirEnt
->EntryPos
+ 1;
641 Set the directory entry count according to the filename.
643 @param OFile - The corresponding OFile.
644 @param DirEnt - The directory entry to be set.
651 IN FAT_DIRENT
*DirEnt
655 CHAR8
*File8Dot3Name
;
658 // Get new entry count and set the 8.3 name
660 DirEnt
->EntryCount
= 1;
661 FileString
= DirEnt
->FileString
;
662 File8Dot3Name
= DirEnt
->Entry
.FileName
;
663 SetMem (File8Dot3Name
, FAT_NAME_LEN
, ' ');
664 if (StrCmp (FileString
, L
".") == 0) {
668 File8Dot3Name
[0] = '.';
669 FatCloneDirEnt (DirEnt
, OFile
->DirEnt
);
670 } else if (StrCmp (FileString
, L
"..") == 0) {
674 File8Dot3Name
[0] = '.';
675 File8Dot3Name
[1] = '.';
676 FatCloneDirEnt (DirEnt
, OFile
->Parent
->DirEnt
);
681 if (FatCheckIs8Dot3Name (FileString
, File8Dot3Name
)) {
683 // This file name is a valid 8.3 file name, we need to further check its case flag
685 FatSetCaseFlag (DirEnt
);
688 // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
690 FatCreate8Dot3Name (OFile
, DirEnt
);
691 DirEnt
->EntryCount
= (UINT8
)(LFN_ENTRY_NUMBER (StrLen (FileString
)) + DirEnt
->EntryCount
);
698 Append a zero cluster to the current OFile.
700 @param OFile - The directory OFile which needs to be updated.
702 @retval EFI_SUCCESS - Append a zero cluster to the OFile successfully.
703 @return other - An error occurred when appending the zero cluster.
712 return FatExpandOFile (OFile
, OFile
->FileSize
+ OFile
->Volume
->ClusterSize
);
717 Search the Root OFile for the possible volume label.
719 @param Root - The Root OFile.
720 @param DirEnt - The returned directory entry of volume label.
722 @retval EFI_SUCCESS - The search process is completed successfully.
723 @return other - An error occurred when searching volume label.
730 OUT FAT_DIRENT
*DirEnt
735 FAT_DIRECTORY_ENTRY
*Entry
;
738 Entry
= &DirEnt
->Entry
;
739 DirEnt
->Invalid
= TRUE
;
741 Status
= FatAccessEntry (Root
, ReadData
, EntryPos
, Entry
);
742 if (EFI_ERROR (Status
)) {
746 if (((UINT8
)Entry
->FileName
[0] != DELETE_ENTRY_MARK
) && (((Entry
->Attributes
) & (~FAT_ATTRIBUTE_ARCHIVE
)) == FAT_ATTRIBUTE_VOLUME_ID
)) {
747 DirEnt
->EntryPos
= (UINT16
)EntryPos
;
748 DirEnt
->EntryCount
= 1;
749 DirEnt
->Invalid
= FALSE
;
754 } while (Entry
->FileName
[0] != EMPTY_ENTRY_MARK
);
761 Use First Fit Algorithm to insert directory entry.
762 Only this function will erase "E5" entries in a directory.
763 In view of safest recovery, this function will only be triggered
764 when maximum directory entry number has reached.
766 @param OFile - The corresponding OFile.
767 @param DirEnt - The directory entry to be inserted.
769 @retval EFI_SUCCESS - The directory entry has been successfully inserted.
770 @retval EFI_VOLUME_FULL - The directory can not hold more directory entries.
771 @return Others - Some error occurred when inserting new directory entries.
776 FatFirstFitInsertDirEnt (
778 IN FAT_DIRENT
*DirEnt
783 LIST_ENTRY
*CurrentEntry
;
784 FAT_DIRENT
*CurrentDirEnt
;
789 FAT_DIRENT LabelDirEnt
;
792 if (OFile
->Parent
== NULL
) {
793 Status
= FatSeekVolumeId (OFile
, &LabelDirEnt
);
794 if (EFI_ERROR (Status
)) {
798 if (!LabelDirEnt
.Invalid
) {
799 LabelPos
= LabelDirEnt
.EntryPos
;
803 EntryCount
= DirEnt
->EntryCount
;
804 NewEntryPos
= EntryCount
;
807 for (CurrentEntry
= ODir
->ChildList
.ForwardLink
;
808 CurrentEntry
!= &ODir
->ChildList
;
809 CurrentEntry
= CurrentEntry
->ForwardLink
812 CurrentDirEnt
= DIRENT_FROM_LINK (CurrentEntry
);
813 if (NewEntryPos
+ CurrentDirEnt
->EntryCount
<= CurrentDirEnt
->EntryPos
) {
814 if ((LabelPos
> NewEntryPos
) || (LabelPos
<= CurrentPos
)) {
816 // first fit succeeded
822 CurrentPos
= CurrentDirEnt
->EntryPos
;
823 NewEntryPos
= CurrentPos
+ EntryCount
;
826 if (NewEntryPos
>= ODir
->CurrentEndPos
) {
827 return EFI_VOLUME_FULL
;
831 DirEnt
->EntryPos
= (UINT16
)NewEntryPos
;
832 DirEnt
->Link
.BackLink
= CurrentEntry
;
838 Find the new directory entry position for the directory entry.
840 @param OFile - The corresponding OFile.
841 @param DirEnt - The directory entry whose new position is to be set.
843 @retval EFI_SUCCESS - The new directory entry position is successfully found.
844 @retval EFI_VOLUME_FULL - The directory has reach its maximum capacity.
845 @return other - An error occurred when reading the directory entry.
852 IN FAT_DIRENT
*DirEnt
857 FAT_DIRENT
*TempDirEnt
;
861 ASSERT (ODir
!= NULL
);
863 // Make sure the whole directory has been loaded
865 while (!ODir
->EndOfDir
) {
866 Status
= FatLoadNextDirEnt (OFile
, &TempDirEnt
);
867 if (EFI_ERROR (Status
)) {
873 // We will append this entry to the end of directory
875 FatGetCurrentFatTime (&DirEnt
->Entry
.FileCreateTime
);
876 CopyMem (&DirEnt
->Entry
.FileModificationTime
, &DirEnt
->Entry
.FileCreateTime
, sizeof (FAT_DATE_TIME
));
877 CopyMem (&DirEnt
->Entry
.FileLastAccess
, &DirEnt
->Entry
.FileCreateTime
.Date
, sizeof (FAT_DATE
));
878 NewEndPos
= ODir
->CurrentEndPos
+ DirEnt
->EntryCount
;
879 if (NewEndPos
* sizeof (FAT_DIRECTORY_ENTRY
) > OFile
->FileSize
) {
880 if (NewEndPos
>= (OFile
->IsFixedRootDir
? OFile
->Volume
->RootEntries
: FAT_MAX_DIRENTRY_COUNT
)) {
882 // We try to use fist fit algorithm to insert this directory entry
884 return FatFirstFitInsertDirEnt (OFile
, DirEnt
);
888 // We should allocate a new cluster for this directory
890 Status
= FatExpandODir (OFile
);
891 if (EFI_ERROR (Status
)) {
897 // We append our directory entry at the end of directory file
899 ODir
->CurrentEndPos
= NewEndPos
;
900 DirEnt
->EntryPos
= (UINT16
)(ODir
->CurrentEndPos
- 1);
906 Get the directory entry for the volume.
908 @param Volume - FAT file system volume.
909 @param Name - The file name of the volume.
911 @retval EFI_SUCCESS - Update the volume with the directory entry successfully.
912 @return others - An error occurred when getting volume label.
917 IN FAT_VOLUME
*Volume
,
922 FAT_DIRENT LabelDirEnt
;
925 Status
= FatSeekVolumeId (Volume
->Root
, &LabelDirEnt
);
926 if (!EFI_ERROR (Status
)) {
927 if (!LabelDirEnt
.Invalid
) {
928 FatNameToStr (LabelDirEnt
.Entry
.FileName
, FAT_NAME_LEN
, FALSE
, Name
);
937 Set the relevant directory entry into disk for the volume.
939 @param Volume - FAT file system volume.
940 @param Name - The new file name of the volume.
942 @retval EFI_SUCCESS - Update the Volume successfully.
943 @retval EFI_UNSUPPORTED - The input label is not a valid volume label.
944 @return other - An error occurred when setting volume label.
949 IN FAT_VOLUME
*Volume
,
954 FAT_DIRENT LabelDirEnt
;
958 Status
= FatSeekVolumeId (Volume
->Root
, &LabelDirEnt
);
959 if (EFI_ERROR (Status
)) {
963 if (LabelDirEnt
.Invalid
) {
965 // If there is not the relevant directory entry, create a new one
967 ZeroMem (&LabelDirEnt
, sizeof (FAT_DIRENT
));
968 LabelDirEnt
.EntryCount
= 1;
969 Status
= FatNewEntryPos (Root
, &LabelDirEnt
);
970 if (EFI_ERROR (Status
)) {
974 LabelDirEnt
.Entry
.Attributes
= FAT_ATTRIBUTE_VOLUME_ID
;
977 SetMem (LabelDirEnt
.Entry
.FileName
, FAT_NAME_LEN
, ' ');
978 if (FatStrToFat (Name
, FAT_NAME_LEN
, LabelDirEnt
.Entry
.FileName
)) {
979 return EFI_UNSUPPORTED
;
982 FatGetCurrentFatTime (&LabelDirEnt
.Entry
.FileModificationTime
);
983 return FatStoreDirEnt (Root
, &LabelDirEnt
);
988 Create "." and ".." directory entries in the newly-created parent OFile.
990 @param OFile - The parent OFile.
992 @retval EFI_SUCCESS - The dot directory entries are successfully created.
993 @return other - An error occurred when creating the directory entry.
997 FatCreateDotDirEnts (
1004 Status
= FatExpandODir (OFile
);
1005 if (EFI_ERROR (Status
)) {
1009 FatSetDirEntCluster (OFile
);
1013 Status
= FatCreateDirEnt (OFile
, L
".", FAT_ATTRIBUTE_DIRECTORY
, &DirEnt
);
1014 if (EFI_ERROR (Status
)) {
1021 Status
= FatCreateDirEnt (OFile
, L
"..", FAT_ATTRIBUTE_DIRECTORY
, &DirEnt
);
1027 Create a directory entry in the parent OFile.
1029 @param OFile - The parent OFile.
1030 @param FileName - The filename of the newly-created directory entry.
1031 @param Attributes - The attribute of the newly-created directory entry.
1032 @param PtrDirEnt - The pointer to the newly-created directory entry.
1034 @retval EFI_SUCCESS - The directory entry is successfully created.
1035 @retval EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry.
1036 @return other - An error occurred when creating the directory entry.
1041 IN FAT_OFILE
*OFile
,
1042 IN CHAR16
*FileName
,
1043 IN UINT8 Attributes
,
1044 OUT FAT_DIRENT
**PtrDirEnt
1051 ASSERT (OFile
!= NULL
);
1053 ASSERT (ODir
!= NULL
);
1054 DirEnt
= AllocateZeroPool (sizeof (FAT_DIRENT
));
1055 if (DirEnt
== NULL
) {
1056 return EFI_OUT_OF_RESOURCES
;
1059 DirEnt
->Signature
= FAT_DIRENT_SIGNATURE
;
1060 DirEnt
->FileString
= AllocateCopyPool (StrSize (FileName
), FileName
);
1061 if (DirEnt
->FileString
== NULL
) {
1062 Status
= EFI_OUT_OF_RESOURCES
;
1067 // Determine how many directory entries we need
1069 FatSetEntryCount (OFile
, DirEnt
);
1071 // Determine the file's directory entry position
1073 Status
= FatNewEntryPos (OFile
, DirEnt
);
1074 if (EFI_ERROR (Status
)) {
1078 FatAddDirEnt (ODir
, DirEnt
);
1079 DirEnt
->Entry
.Attributes
= Attributes
;
1080 *PtrDirEnt
= DirEnt
;
1081 DEBUG ((DEBUG_INFO
, "FSOpen: Created new directory entry '%S'\n", DirEnt
->FileString
));
1082 return FatStoreDirEnt (OFile
, DirEnt
);
1085 FatFreeDirEnt (DirEnt
);
1091 Remove this directory entry node from the list of directory entries and hash table.
1093 @param OFile - The parent OFile.
1094 @param DirEnt - The directory entry to be removed.
1096 @retval EFI_SUCCESS - The directory entry is successfully removed.
1097 @return other - An error occurred when removing the directory entry.
1102 IN FAT_OFILE
*OFile
,
1103 IN FAT_DIRENT
*DirEnt
1109 if (ODir
->CurrentCursor
== &DirEnt
->Link
) {
1111 // Move the directory cursor to its previous directory entry
1113 ODir
->CurrentCursor
= ODir
->CurrentCursor
->BackLink
;
1117 // Remove from directory entry list
1119 RemoveEntryList (&DirEnt
->Link
);
1121 // Remove from hash table
1123 FatDeleteFromHashTable (ODir
, DirEnt
);
1124 DirEnt
->Entry
.FileName
[0] = DELETE_ENTRY_MARK
;
1125 DirEnt
->Invalid
= TRUE
;
1126 return FatStoreDirEnt (OFile
, DirEnt
);
1131 Open the directory entry to get the OFile.
1133 @param Parent - The parent OFile.
1134 @param DirEnt - The directory entry to be opened.
1136 @retval EFI_SUCCESS - The directory entry is successfully opened.
1137 @retval EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile.
1138 @return other - An error occurred when opening the directory entry.
1143 IN FAT_OFILE
*Parent
,
1144 IN FAT_DIRENT
*DirEnt
1150 if (DirEnt
->OFile
== NULL
) {
1152 // Open the directory entry
1154 OFile
= AllocateZeroPool (sizeof (FAT_OFILE
));
1155 if (OFile
== NULL
) {
1156 return EFI_OUT_OF_RESOURCES
;
1159 OFile
->Signature
= FAT_OFILE_SIGNATURE
;
1160 InitializeListHead (&OFile
->Opens
);
1161 InitializeListHead (&OFile
->ChildHead
);
1162 OFile
->Parent
= Parent
;
1163 OFile
->DirEnt
= DirEnt
;
1164 if (Parent
!= NULL
) {
1166 // The newly created OFile is not root
1168 Volume
= Parent
->Volume
;
1169 OFile
->FullPathLen
= Parent
->FullPathLen
+ 1 + StrLen (DirEnt
->FileString
);
1170 OFile
->FileCluster
= ((DirEnt
->Entry
.FileClusterHigh
) << 16) | (DirEnt
->Entry
.FileCluster
);
1171 InsertTailList (&Parent
->ChildHead
, &OFile
->ChildLink
);
1174 // The newly created OFile is root
1176 Volume
= VOLUME_FROM_ROOT_DIRENT (DirEnt
);
1177 Volume
->Root
= OFile
;
1178 OFile
->FileCluster
= Volume
->RootCluster
;
1179 if (Volume
->FatType
!= Fat32
) {
1180 OFile
->IsFixedRootDir
= TRUE
;
1184 OFile
->FileCurrentCluster
= OFile
->FileCluster
;
1185 OFile
->Volume
= Volume
;
1186 InsertHeadList (&Volume
->CheckRef
, &OFile
->CheckLink
);
1188 OFile
->FileSize
= DirEnt
->Entry
.FileSize
;
1189 if ((DirEnt
->Entry
.Attributes
& FAT_ATTRIBUTE_DIRECTORY
) != 0) {
1190 if (OFile
->IsFixedRootDir
) {
1191 OFile
->FileSize
= Volume
->RootEntries
* sizeof (FAT_DIRECTORY_ENTRY
);
1193 OFile
->FileSize
= FatPhysicalDirSize (Volume
, OFile
->FileCluster
);
1196 FatRequestODir (OFile
);
1197 if (OFile
->ODir
== NULL
) {
1198 return EFI_OUT_OF_RESOURCES
;
1202 DirEnt
->OFile
= OFile
;
1210 Close the directory entry and free the OFile.
1212 @param DirEnt - The directory entry to be closed.
1217 IN FAT_DIRENT
*DirEnt
1223 OFile
= DirEnt
->OFile
;
1224 ASSERT (OFile
!= NULL
);
1225 Volume
= OFile
->Volume
;
1227 if (OFile
->ODir
!= NULL
) {
1228 FatDiscardODir (OFile
);
1231 if (OFile
->Parent
== NULL
) {
1232 Volume
->Root
= NULL
;
1234 RemoveEntryList (&OFile
->ChildLink
);
1238 DirEnt
->OFile
= NULL
;
1239 if (DirEnt
->Invalid
== TRUE
) {
1241 // Free directory entry itself
1243 FatFreeDirEnt (DirEnt
);
1249 Traverse filename and open all OFiles that can be opened.
1250 Update filename pointer to the component that can't be opened.
1251 If more than one name component remains, returns an error;
1252 otherwise, return the remaining name component so that the caller might choose to create it.
1254 @param PtrOFile - As input, the reference OFile; as output, the located OFile.
1255 @param FileName - The file name relevant to the OFile.
1256 @param Attributes - The attribute of the destination OFile.
1257 @param NewFileName - The remaining file name.
1259 @retval EFI_NOT_FOUND - The file name can't be opened and there is more than one
1260 components within the name left (this means the name can
1261 not be created either).
1262 @retval EFI_INVALID_PARAMETER - The parameter is not valid.
1263 @retval EFI_SUCCESS - Open the file successfully.
1264 @return other - An error occurred when locating the OFile.
1269 IN OUT FAT_OFILE
**PtrOFile
,
1270 IN CHAR16
*FileName
,
1271 IN UINT8 Attributes
,
1272 OUT CHAR16
*NewFileName
1277 CHAR16 ComponentName
[EFI_PATH_STRING_LENGTH
];
1279 BOOLEAN DirIntended
;
1286 FileNameLen
= StrLen (FileName
);
1287 if (FileNameLen
== 0) {
1288 return EFI_INVALID_PARAMETER
;
1292 Volume
= OFile
->Volume
;
1294 DirIntended
= FALSE
;
1295 if (FileName
[FileNameLen
- 1] == PATH_NAME_SEPARATOR
) {
1300 // If name starts with path name separator, then move to root OFile
1302 if (*FileName
== PATH_NAME_SEPARATOR
) {
1303 OFile
= Volume
->Root
;
1309 // Per FAT Spec the file name should meet the following criteria:
1310 // C1. Length (FileLongName) <= 255
1311 // C2. Length (X:FileFullPath<NUL>) <= 260
1312 // Here we check C2 first.
1314 if (2 + OFile
->FullPathLen
+ 1 + FileNameLen
+ 1 > EFI_PATH_STRING_LENGTH
) {
1316 // Full path length can not surpass 256
1318 return EFI_INVALID_PARAMETER
;
1322 // Start at current location
1327 // Get the next component name
1330 Next
= FatGetNextNameComponent (FileName
, ComponentName
);
1333 // If end of the file name, we're done
1335 if (ComponentName
[0] == 0) {
1336 if (DirIntended
&& (OFile
->ODir
== NULL
)) {
1337 return EFI_NOT_FOUND
;
1345 // If "dot", then current
1347 if (StrCmp (ComponentName
, L
".") == 0) {
1352 // If "dot dot", then parent
1354 if (StrCmp (ComponentName
, L
"..") == 0) {
1355 if (OFile
->Parent
== NULL
) {
1356 return EFI_INVALID_PARAMETER
;
1359 OFile
= OFile
->Parent
;
1363 if (!FatFileNameIsValid (ComponentName
, NewFileName
)) {
1364 return EFI_INVALID_PARAMETER
;
1368 // We have a component name, try to open it
1370 if (OFile
->ODir
== NULL
) {
1372 // This file isn't a directory, can't open it
1374 return EFI_NOT_FOUND
;
1378 // Search the compName in the directory
1380 Status
= FatSearchODir (OFile
, NewFileName
, &DirEnt
);
1381 if (EFI_ERROR (Status
)) {
1385 if (DirEnt
== NULL
) {
1387 // component name is not found in the directory
1390 return EFI_NOT_FOUND
;
1393 if (DirIntended
&& ((Attributes
& FAT_ATTRIBUTE_DIRECTORY
) == 0)) {
1394 return EFI_INVALID_PARAMETER
;
1398 // It's the last component name - return with the open
1399 // path and the remaining name
1404 Status
= FatOpenDirEnt (OFile
, DirEnt
);
1405 if (EFI_ERROR (Status
)) {
1409 OFile
= DirEnt
->OFile
;