2 Functions for performing directory entry io.
4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Get a directory entry from disk for the Ofile.
21 @param Parent - The parent of the OFile which need to update.
22 @param IoMode - Indicate whether to read directory entry or write directroy entry.
23 @param EntryPos - The position of the directory entry to be accessed.
24 @param Entry - The directory entry read or written.
26 @retval EFI_SUCCESS - Access the directory entry sucessfully.
27 @return other - An error occurred when reading the directory entry.
42 Position
= EntryPos
* sizeof (FAT_DIRECTORY_ENTRY
);
43 if (Position
>= Parent
->FileSize
) {
47 ASSERT (IoMode
== ReadData
);
48 ((FAT_DIRECTORY_ENTRY
*) Entry
)->FileName
[0] = EMPTY_ENTRY_MARK
;
49 ((FAT_DIRECTORY_ENTRY
*) Entry
)->Attributes
= 0;
53 BufferSize
= sizeof (FAT_DIRECTORY_ENTRY
);
54 return FatAccessOFile (Parent
, IoMode
, Position
, &BufferSize
, Entry
, NULL
);
59 Save the directory entry to disk.
61 @param OFile - The parent OFile which needs to update.
62 @param DirEnt - The directory entry to be saved.
64 @retval EFI_SUCCESS - Store the directory entry successfully.
65 @return other - An error occurred when writing the directory entry.
75 FAT_DIRECTORY_LFN LfnEntry
;
77 CHAR16
*LfnBufferPointer
;
78 CHAR16 LfnBuffer
[MAX_LFN_ENTRIES
* LFN_CHAR_TOTAL
+ 1];
82 EntryPos
= DirEnt
->EntryPos
;
83 EntryCount
= DirEnt
->EntryCount
;
85 // Write directory entry
87 Status
= FatAccessEntry (OFile
, WriteData
, EntryPos
, &DirEnt
->Entry
);
88 if (EFI_ERROR (Status
)) {
92 if (--EntryCount
> 0) {
94 // Write LFN directory entry
96 SetMem (LfnBuffer
, sizeof (CHAR16
) * LFN_CHAR_TOTAL
* EntryCount
, 0xff);
99 ARRAY_SIZE (LfnBuffer
),
102 if (EFI_ERROR (Status
)) {
106 LfnBufferPointer
= LfnBuffer
;
107 LfnEntry
.Attributes
= FAT_ATTRIBUTE_LFN
;
109 LfnEntry
.MustBeZero
= 0;
110 LfnEntry
.Checksum
= FatCheckSum (DirEnt
->Entry
.FileName
);
111 for (LfnOrdinal
= 1; LfnOrdinal
<= EntryCount
; LfnOrdinal
++) {
112 LfnEntry
.Ordinal
= LfnOrdinal
;
113 if (LfnOrdinal
== EntryCount
) {
114 LfnEntry
.Ordinal
|= FAT_LFN_LAST
;
117 CopyMem (LfnEntry
.Name1
, LfnBufferPointer
, sizeof (CHAR16
) * LFN_CHAR1_LEN
);
118 LfnBufferPointer
+= LFN_CHAR1_LEN
;
119 CopyMem (LfnEntry
.Name2
, LfnBufferPointer
, sizeof (CHAR16
) * LFN_CHAR2_LEN
);
120 LfnBufferPointer
+= LFN_CHAR2_LEN
;
121 CopyMem (LfnEntry
.Name3
, LfnBufferPointer
, sizeof (CHAR16
) * LFN_CHAR3_LEN
);
122 LfnBufferPointer
+= LFN_CHAR3_LEN
;
124 if (DirEnt
->Invalid
) {
125 LfnEntry
.Ordinal
= DELETE_ENTRY_MARK
;
128 Status
= FatAccessEntry (OFile
, WriteData
, EntryPos
, &LfnEntry
);
129 if (EFI_ERROR (Status
)) {
140 Determine whether the directory entry is "." or ".." entry.
142 @param DirEnt - The corresponding directory entry.
144 @retval TRUE - The directory entry is "." or ".." directory entry
145 @retval FALSE - The directory entry is not "." or ".." directory entry
150 IN FAT_DIRENT
*DirEnt
154 FileString
= DirEnt
->FileString
;
155 if (StrCmp (FileString
, L
".") == 0 || StrCmp (FileString
, L
"..") == 0) {
164 Set the OFile's cluster info in its directory entry.
166 @param OFile - The corresponding OFile.
171 FatSetDirEntCluster (
178 DirEnt
= OFile
->DirEnt
;
179 Cluster
= OFile
->FileCluster
;
180 DirEnt
->Entry
.FileClusterHigh
= (UINT16
) (Cluster
>> 16);
181 DirEnt
->Entry
.FileCluster
= (UINT16
) Cluster
;
186 Set the OFile's cluster and size info in its directory entry.
188 @param OFile - The corresponding OFile.
192 FatUpdateDirEntClusterSizeInfo (
196 ASSERT (OFile
->ODir
== NULL
);
197 OFile
->DirEnt
->Entry
.FileSize
= (UINT32
) OFile
->FileSize
;
198 FatSetDirEntCluster (OFile
);
203 Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
205 @param DirEnt1 - The destination directory entry.
206 @param DirEnt2 - The source directory entry.
211 IN FAT_DIRENT
*DirEnt1
,
212 IN FAT_DIRENT
*DirEnt2
217 Entry1
= (UINT8
*) &DirEnt1
->Entry
;
218 Entry2
= (UINT8
*) &DirEnt2
->Entry
;
220 Entry1
+ FAT_ENTRY_INFO_OFFSET
,
221 Entry2
+ FAT_ENTRY_INFO_OFFSET
,
222 sizeof (FAT_DIRECTORY_ENTRY
) - FAT_ENTRY_INFO_OFFSET
228 Get the LFN for the directory entry.
230 @param Parent - The parent directory.
231 @param DirEnt - The directory entry to get LFN.
236 FatLoadLongNameEntry (
237 IN FAT_OFILE
*Parent
,
238 IN FAT_DIRENT
*DirEnt
241 CHAR16 LfnBuffer
[MAX_LFN_ENTRIES
* LFN_CHAR_TOTAL
+ 1];
242 CHAR16
*LfnBufferPointer
;
243 CHAR8
*File8Dot3Name
;
247 FAT_DIRECTORY_LFN LfnEntry
;
250 EntryPos
= DirEnt
->EntryPos
;
251 File8Dot3Name
= DirEnt
->Entry
.FileName
;
252 LfnBufferPointer
= LfnBuffer
;
254 // Computes checksum for LFN
256 LfnChecksum
= FatCheckSum (File8Dot3Name
);
260 LfnBufferPointer
= LfnBuffer
;
265 Status
= FatAccessEntry (Parent
, ReadData
, EntryPos
, &LfnEntry
);
266 if (EFI_ERROR (Status
) ||
267 LfnEntry
.Attributes
!= FAT_ATTRIBUTE_LFN
||
268 LfnEntry
.MustBeZero
!= 0 ||
269 LfnEntry
.Checksum
!= LfnChecksum
||
270 (LfnEntry
.Ordinal
& (~FAT_LFN_LAST
)) != LfnOrdinal
||
271 LfnOrdinal
> MAX_LFN_ENTRIES
274 // The directory entry does not have a long file name or
275 // some error occurs when loading long file name for a directory entry,
276 // and then we load the long name from short name
278 LfnBufferPointer
= LfnBuffer
;
282 CopyMem (LfnBufferPointer
, LfnEntry
.Name1
, sizeof (CHAR16
) * LFN_CHAR1_LEN
);
283 LfnBufferPointer
+= LFN_CHAR1_LEN
;
284 CopyMem (LfnBufferPointer
, LfnEntry
.Name2
, sizeof (CHAR16
) * LFN_CHAR2_LEN
);
285 LfnBufferPointer
+= LFN_CHAR2_LEN
;
286 CopyMem (LfnBufferPointer
, LfnEntry
.Name3
, sizeof (CHAR16
) * LFN_CHAR3_LEN
);
287 LfnBufferPointer
+= LFN_CHAR3_LEN
;
289 } while ((LfnEntry
.Ordinal
& FAT_LFN_LAST
) == 0);
290 DirEnt
->EntryCount
= LfnOrdinal
;
292 // Terminate current Lfnbuffer
294 *LfnBufferPointer
= 0;
295 if (LfnBufferPointer
== LfnBuffer
) {
297 // Fail to get the long file name from long file name entry,
298 // get the file name from short name
300 FatGetFileNameViaCaseFlag (
303 ARRAY_SIZE (LfnBuffer
)
307 DirEnt
->FileString
= AllocateCopyPool (StrSize (LfnBuffer
), LfnBuffer
);
312 Add this directory entry node to the list of directory entries and hash table.
314 @param ODir - The parent OFile which needs to be updated.
315 @param DirEnt - The directory entry to be added.
322 IN FAT_DIRENT
*DirEnt
325 if (DirEnt
->Link
.BackLink
== NULL
) {
326 DirEnt
->Link
.BackLink
= &ODir
->ChildList
;
328 InsertTailList (DirEnt
->Link
.BackLink
, &DirEnt
->Link
);
329 FatInsertToHashTable (ODir
, DirEnt
);
334 Load from disk the next directory entry at current end of directory position.
336 @param OFile - The parent OFile.
337 @param PtrDirEnt - The directory entry that is loaded.
339 @retval EFI_SUCCESS - Load the directory entry successfully.
340 @retval EFI_OUT_OF_RESOURCES - Out of resource.
341 @return other - An error occurred when reading the directory entries.
348 OUT FAT_DIRENT
**PtrDirEnt
354 FAT_DIRECTORY_ENTRY Entry
;
358 // Make sure the parent's directory has been opened
360 ASSERT (ODir
!= NULL
);
362 // Assert we have not reached the end of directory
364 ASSERT (!ODir
->EndOfDir
);
369 // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
371 Status
= FatAccessEntry (OFile
, ReadData
, ODir
->CurrentEndPos
, &Entry
);
372 if (EFI_ERROR (Status
)) {
376 if (((UINT8
) Entry
.FileName
[0] != DELETE_ENTRY_MARK
) && (Entry
.Attributes
& FAT_ATTRIBUTE_VOLUME_ID
) == 0) {
378 // We get a valid directory entry, then handle it
383 ODir
->CurrentEndPos
++;
386 if (Entry
.FileName
[0] != EMPTY_ENTRY_MARK
) {
388 // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications
389 // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.
391 if (OFile
->Volume
->FatType
!= Fat32
) {
392 Entry
.FileClusterHigh
= 0;
396 // This is a valid directory entry
398 DirEnt
= AllocateZeroPool (sizeof (FAT_DIRENT
));
399 if (DirEnt
== NULL
) {
400 return EFI_OUT_OF_RESOURCES
;
403 DirEnt
->Signature
= FAT_DIRENT_SIGNATURE
;
405 // Remember the directory's entry position on disk
407 DirEnt
->EntryPos
= (UINT16
) ODir
->CurrentEndPos
;
408 CopyMem (&DirEnt
->Entry
, &Entry
, sizeof (FAT_DIRECTORY_ENTRY
));
409 FatLoadLongNameEntry (OFile
, DirEnt
);
410 if (DirEnt
->FileString
== NULL
) {
411 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
);
537 if (DirEnt
== NULL
) {
539 // We fail to get the directory entry from hash table; we then
540 // search the rest directory
542 while (!ODir
->EndOfDir
) {
543 Status
= FatLoadNextDirEnt (OFile
, &DirEnt
);
544 if (EFI_ERROR (Status
)) {
548 if (DirEnt
!= NULL
) {
549 if (FatStriCmp (FileNameString
, DirEnt
->FileString
) == 0) {
553 if (PossibleShortName
&& CompareMem (File8Dot3Name
, DirEnt
->Entry
.FileName
, FAT_NAME_LEN
) == 0) {
566 Set the OFile's current directory cursor to the list head.
568 @param OFile - The directory OFile whose directory cursor is reset.
579 ASSERT (ODir
!= NULL
);
580 ODir
->CurrentCursor
= &(ODir
->ChildList
);
581 ODir
->CurrentPos
= 0;
586 Set the directory's cursor to the next and get the next directory entry.
588 @param OFile - The parent OFile.
589 @param PtrDirEnt - The next directory entry.
591 @retval EFI_SUCCESS - We get the next directory entry successfully.
592 @return other - An error occurred when get next directory entry.
598 OUT FAT_DIRENT
**PtrDirEnt
606 ASSERT (ODir
!= NULL
);
607 if (ODir
->CurrentCursor
->ForwardLink
== &ODir
->ChildList
) {
609 // End of directory, we will try one more time
611 if (!ODir
->EndOfDir
) {
613 // Read directory from disk
615 Status
= FatLoadNextDirEnt (OFile
, &DirEnt
);
616 if (EFI_ERROR (Status
)) {
622 if (ODir
->CurrentCursor
->ForwardLink
== &ODir
->ChildList
) {
624 // End of directory, return NULL
627 ODir
->CurrentPos
= ODir
->CurrentEndPos
;
629 ODir
->CurrentCursor
= ODir
->CurrentCursor
->ForwardLink
;
630 DirEnt
= DIRENT_FROM_LINK (ODir
->CurrentCursor
);
631 ODir
->CurrentPos
= DirEnt
->EntryPos
+ 1;
640 Set the directory entry count according to the filename.
642 @param OFile - The corresponding OFile.
643 @param DirEnt - The directory entry to be set.
650 IN FAT_DIRENT
*DirEnt
654 CHAR8
*File8Dot3Name
;
657 // Get new entry count and set the 8.3 name
659 DirEnt
->EntryCount
= 1;
660 FileString
= DirEnt
->FileString
;
661 File8Dot3Name
= DirEnt
->Entry
.FileName
;
662 SetMem (File8Dot3Name
, FAT_NAME_LEN
, ' ');
663 if (StrCmp (FileString
, L
".") == 0) {
667 File8Dot3Name
[0] = '.';
668 FatCloneDirEnt (DirEnt
, OFile
->DirEnt
);
669 } else if (StrCmp (FileString
, L
"..") == 0) {
673 File8Dot3Name
[0] = '.';
674 File8Dot3Name
[1] = '.';
675 FatCloneDirEnt (DirEnt
, OFile
->Parent
->DirEnt
);
680 if (FatCheckIs8Dot3Name (FileString
, File8Dot3Name
)) {
682 // This file name is a valid 8.3 file name, we need to further check its case flag
684 FatSetCaseFlag (DirEnt
);
687 // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
689 FatCreate8Dot3Name (OFile
, DirEnt
);
690 DirEnt
->EntryCount
= (UINT8
)(LFN_ENTRY_NUMBER (StrLen (FileString
)) + DirEnt
->EntryCount
);
697 Append a zero cluster to the current OFile.
699 @param OFile - The directory OFile which needs to be updated.
701 @retval EFI_SUCCESS - Append a zero cluster to the OFile successfully.
702 @return other - An error occurred when appending the zero cluster.
711 return FatExpandOFile (OFile
, OFile
->FileSize
+ OFile
->Volume
->ClusterSize
);
716 Search the Root OFile for the possible volume label.
718 @param Root - The Root OFile.
719 @param DirEnt - The returned directory entry of volume label.
721 @retval EFI_SUCCESS - The search process is completed successfully.
722 @return other - An error occurred when searching volume label.
729 OUT FAT_DIRENT
*DirEnt
734 FAT_DIRECTORY_ENTRY
*Entry
;
737 Entry
= &DirEnt
->Entry
;
738 DirEnt
->Invalid
= TRUE
;
740 Status
= FatAccessEntry (Root
, ReadData
, EntryPos
, Entry
);
741 if (EFI_ERROR (Status
)) {
745 if (((UINT8
) Entry
->FileName
[0] != DELETE_ENTRY_MARK
) && (((Entry
->Attributes
) & (~FAT_ATTRIBUTE_ARCHIVE
)) == FAT_ATTRIBUTE_VOLUME_ID
)) {
746 DirEnt
->EntryPos
= (UINT16
) EntryPos
;
747 DirEnt
->EntryCount
= 1;
748 DirEnt
->Invalid
= FALSE
;
753 } while (Entry
->FileName
[0] != EMPTY_ENTRY_MARK
);
759 Use First Fit Algorithm to insert directory entry.
760 Only this function will erase "E5" entries in a directory.
761 In view of safest recovery, this function will only be triggered
762 when maximum directory entry number has reached.
764 @param OFile - The corresponding OFile.
765 @param DirEnt - The directory entry to be inserted.
767 @retval EFI_SUCCESS - The directory entry has been successfully inserted.
768 @retval EFI_VOLUME_FULL - The directory can not hold more directory entries.
769 @return Others - Some error occurred when inserting new directory entries.
774 FatFirstFitInsertDirEnt (
776 IN FAT_DIRENT
*DirEnt
781 LIST_ENTRY
*CurrentEntry
;
782 FAT_DIRENT
*CurrentDirEnt
;
787 FAT_DIRENT LabelDirEnt
;
790 if (OFile
->Parent
== NULL
) {
791 Status
= FatSeekVolumeId (OFile
, &LabelDirEnt
);
792 if (EFI_ERROR (Status
)) {
796 if (!LabelDirEnt
.Invalid
) {
797 LabelPos
= LabelDirEnt
.EntryPos
;
801 EntryCount
= DirEnt
->EntryCount
;
802 NewEntryPos
= EntryCount
;
805 for (CurrentEntry
= ODir
->ChildList
.ForwardLink
;
806 CurrentEntry
!= &ODir
->ChildList
;
807 CurrentEntry
= CurrentEntry
->ForwardLink
809 CurrentDirEnt
= DIRENT_FROM_LINK (CurrentEntry
);
810 if (NewEntryPos
+ CurrentDirEnt
->EntryCount
<= CurrentDirEnt
->EntryPos
) {
811 if (LabelPos
> NewEntryPos
|| LabelPos
<= CurrentPos
) {
813 // first fit succeeded
819 CurrentPos
= CurrentDirEnt
->EntryPos
;
820 NewEntryPos
= CurrentPos
+ EntryCount
;
823 if (NewEntryPos
>= ODir
->CurrentEndPos
) {
824 return EFI_VOLUME_FULL
;
828 DirEnt
->EntryPos
= (UINT16
) NewEntryPos
;
829 DirEnt
->Link
.BackLink
= CurrentEntry
;
835 Find the new directory entry position for the directory entry.
837 @param OFile - The corresponding OFile.
838 @param DirEnt - The directory entry whose new position is to be set.
840 @retval EFI_SUCCESS - The new directory entry position is successfully found.
841 @retval EFI_VOLUME_FULL - The directory has reach its maximum capacity.
842 @return other - An error occurred when reading the directory entry.
849 IN FAT_DIRENT
*DirEnt
854 FAT_DIRENT
*TempDirEnt
;
858 ASSERT (ODir
!= NULL
);
860 // Make sure the whole directory has been loaded
862 while (!ODir
->EndOfDir
) {
863 Status
= FatLoadNextDirEnt (OFile
, &TempDirEnt
);
864 if (EFI_ERROR (Status
)) {
869 // We will append this entry to the end of directory
871 FatGetCurrentFatTime (&DirEnt
->Entry
.FileCreateTime
);
872 CopyMem (&DirEnt
->Entry
.FileModificationTime
, &DirEnt
->Entry
.FileCreateTime
, sizeof (FAT_DATE_TIME
));
873 CopyMem (&DirEnt
->Entry
.FileLastAccess
, &DirEnt
->Entry
.FileCreateTime
.Date
, sizeof (FAT_DATE
));
874 NewEndPos
= ODir
->CurrentEndPos
+ DirEnt
->EntryCount
;
875 if (NewEndPos
* sizeof (FAT_DIRECTORY_ENTRY
) > OFile
->FileSize
) {
876 if (NewEndPos
>= (OFile
->IsFixedRootDir
? OFile
->Volume
->RootEntries
: FAT_MAX_DIRENTRY_COUNT
)) {
878 // We try to use fist fit algorithm to insert this directory entry
880 return FatFirstFitInsertDirEnt (OFile
, DirEnt
);
883 // We should allocate a new cluster for this directory
885 Status
= FatExpandODir (OFile
);
886 if (EFI_ERROR (Status
)) {
891 // We append our directory entry at the end of directory file
893 ODir
->CurrentEndPos
= NewEndPos
;
894 DirEnt
->EntryPos
= (UINT16
) (ODir
->CurrentEndPos
- 1);
900 Get the directory entry for the volume.
902 @param Volume - FAT file system volume.
903 @param Name - The file name of the volume.
905 @retval EFI_SUCCESS - Update the volume with the directory entry sucessfully.
906 @return others - An error occurred when getting volume label.
911 IN FAT_VOLUME
*Volume
,
916 FAT_DIRENT LabelDirEnt
;
919 Status
= FatSeekVolumeId (Volume
->Root
, &LabelDirEnt
);
920 if (!EFI_ERROR (Status
)) {
921 if (!LabelDirEnt
.Invalid
) {
922 FatNameToStr (LabelDirEnt
.Entry
.FileName
, FAT_NAME_LEN
, FALSE
, Name
);
931 Set the relevant directory entry into disk for the volume.
933 @param Volume - FAT file system volume.
934 @param Name - The new file name of the volume.
936 @retval EFI_SUCCESS - Update the Volume sucessfully.
937 @retval EFI_UNSUPPORTED - The input label is not a valid volume label.
938 @return other - An error occurred when setting volume label.
943 IN FAT_VOLUME
*Volume
,
948 FAT_DIRENT LabelDirEnt
;
952 Status
= FatSeekVolumeId (Volume
->Root
, &LabelDirEnt
);
953 if (EFI_ERROR (Status
)) {
957 if (LabelDirEnt
.Invalid
) {
959 // If there is not the relevant directory entry, create a new one
961 ZeroMem (&LabelDirEnt
, sizeof (FAT_DIRENT
));
962 LabelDirEnt
.EntryCount
= 1;
963 Status
= FatNewEntryPos (Root
, &LabelDirEnt
);
964 if (EFI_ERROR (Status
)) {
968 LabelDirEnt
.Entry
.Attributes
= FAT_ATTRIBUTE_VOLUME_ID
;
971 SetMem (LabelDirEnt
.Entry
.FileName
, FAT_NAME_LEN
, ' ');
972 if (FatStrToFat (Name
, FAT_NAME_LEN
, LabelDirEnt
.Entry
.FileName
)) {
973 return EFI_UNSUPPORTED
;
976 FatGetCurrentFatTime (&LabelDirEnt
.Entry
.FileModificationTime
);
977 return FatStoreDirEnt (Root
, &LabelDirEnt
);
982 Create "." and ".." directory entries in the newly-created parent OFile.
984 @param OFile - The parent OFile.
986 @retval EFI_SUCCESS - The dot directory entries are successfully created.
987 @return other - An error occurred when creating the directory entry.
991 FatCreateDotDirEnts (
998 Status
= FatExpandODir (OFile
);
999 if (EFI_ERROR (Status
)) {
1003 FatSetDirEntCluster (OFile
);
1007 Status
= FatCreateDirEnt (OFile
, L
".", FAT_ATTRIBUTE_DIRECTORY
, &DirEnt
);
1008 if (EFI_ERROR (Status
)) {
1014 Status
= FatCreateDirEnt (OFile
, L
"..", FAT_ATTRIBUTE_DIRECTORY
, &DirEnt
);
1020 Create a directory entry in the parent OFile.
1022 @param OFile - The parent OFile.
1023 @param FileName - The filename of the newly-created directory entry.
1024 @param Attributes - The attribute of the newly-created directory entry.
1025 @param PtrDirEnt - The pointer to the newly-created directory entry.
1027 @retval EFI_SUCCESS - The directory entry is successfully created.
1028 @retval EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry.
1029 @return other - An error occurred when creating the directory entry.
1034 IN FAT_OFILE
*OFile
,
1035 IN CHAR16
*FileName
,
1036 IN UINT8 Attributes
,
1037 OUT FAT_DIRENT
**PtrDirEnt
1044 ASSERT (OFile
!= NULL
);
1046 ASSERT (ODir
!= NULL
);
1047 DirEnt
= AllocateZeroPool (sizeof (FAT_DIRENT
));
1048 if (DirEnt
== NULL
) {
1049 return EFI_OUT_OF_RESOURCES
;
1052 DirEnt
->Signature
= FAT_DIRENT_SIGNATURE
;
1053 DirEnt
->FileString
= AllocateCopyPool (StrSize (FileName
), FileName
);
1054 if (DirEnt
->FileString
== NULL
) {
1055 Status
= EFI_OUT_OF_RESOURCES
;
1059 // Determine how many directory entries we need
1061 FatSetEntryCount (OFile
, DirEnt
);
1063 // Determine the file's directory entry position
1065 Status
= FatNewEntryPos (OFile
, DirEnt
);
1066 if (EFI_ERROR (Status
)) {
1070 FatAddDirEnt (ODir
, DirEnt
);
1071 DirEnt
->Entry
.Attributes
= Attributes
;
1072 *PtrDirEnt
= DirEnt
;
1073 DEBUG ((EFI_D_INFO
, "FSOpen: Created new directory entry '%S'\n", DirEnt
->FileString
));
1074 return FatStoreDirEnt (OFile
, DirEnt
);
1077 FatFreeDirEnt (DirEnt
);
1083 Remove this directory entry node from the list of directory entries and hash table.
1085 @param OFile - The parent OFile.
1086 @param DirEnt - The directory entry to be removed.
1088 @retval EFI_SUCCESS - The directory entry is successfully removed.
1089 @return other - An error occurred when removing the directory entry.
1094 IN FAT_OFILE
*OFile
,
1095 IN FAT_DIRENT
*DirEnt
1101 if (ODir
->CurrentCursor
== &DirEnt
->Link
) {
1103 // Move the directory cursor to its previous directory entry
1105 ODir
->CurrentCursor
= ODir
->CurrentCursor
->BackLink
;
1108 // Remove from directory entry list
1110 RemoveEntryList (&DirEnt
->Link
);
1112 // Remove from hash table
1114 FatDeleteFromHashTable (ODir
, DirEnt
);
1115 DirEnt
->Entry
.FileName
[0] = DELETE_ENTRY_MARK
;
1116 DirEnt
->Invalid
= TRUE
;
1117 return FatStoreDirEnt (OFile
, DirEnt
);
1122 Open the directory entry to get the OFile.
1124 @param Parent - The parent OFile.
1125 @param DirEnt - The directory entry to be opened.
1127 @retval EFI_SUCCESS - The directory entry is successfully opened.
1128 @retval EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile.
1129 @return other - An error occurred when opening the directory entry.
1134 IN FAT_OFILE
*Parent
,
1135 IN FAT_DIRENT
*DirEnt
1141 if (DirEnt
->OFile
== NULL
) {
1143 // Open the directory entry
1145 OFile
= AllocateZeroPool (sizeof (FAT_OFILE
));
1146 if (OFile
== NULL
) {
1147 return EFI_OUT_OF_RESOURCES
;
1150 OFile
->Signature
= FAT_OFILE_SIGNATURE
;
1151 InitializeListHead (&OFile
->Opens
);
1152 InitializeListHead (&OFile
->ChildHead
);
1153 OFile
->Parent
= Parent
;
1154 OFile
->DirEnt
= DirEnt
;
1155 if (Parent
!= NULL
) {
1157 // The newly created OFile is not root
1159 Volume
= Parent
->Volume
;
1160 OFile
->FullPathLen
= Parent
->FullPathLen
+ 1 + StrLen (DirEnt
->FileString
);
1161 OFile
->FileCluster
= ((DirEnt
->Entry
.FileClusterHigh
) << 16) | (DirEnt
->Entry
.FileCluster
);
1162 InsertTailList (&Parent
->ChildHead
, &OFile
->ChildLink
);
1165 // The newly created OFile is root
1167 Volume
= VOLUME_FROM_ROOT_DIRENT (DirEnt
);
1168 Volume
->Root
= OFile
;
1169 OFile
->FileCluster
= Volume
->RootCluster
;
1170 if (Volume
->FatType
!= Fat32
) {
1171 OFile
->IsFixedRootDir
= TRUE
;
1175 OFile
->FileCurrentCluster
= OFile
->FileCluster
;
1176 OFile
->Volume
= Volume
;
1177 InsertHeadList (&Volume
->CheckRef
, &OFile
->CheckLink
);
1179 OFile
->FileSize
= DirEnt
->Entry
.FileSize
;
1180 if ((DirEnt
->Entry
.Attributes
& FAT_ATTRIBUTE_DIRECTORY
) != 0) {
1181 if (OFile
->IsFixedRootDir
) {
1182 OFile
->FileSize
= Volume
->RootEntries
* sizeof (FAT_DIRECTORY_ENTRY
);
1184 OFile
->FileSize
= FatPhysicalDirSize (Volume
, OFile
->FileCluster
);
1187 FatRequestODir (OFile
);
1188 if (OFile
->ODir
== NULL
) {
1189 return EFI_OUT_OF_RESOURCES
;
1193 DirEnt
->OFile
= OFile
;
1201 Close the directory entry and free the OFile.
1203 @param DirEnt - The directory entry to be closed.
1208 IN FAT_DIRENT
*DirEnt
1214 OFile
= DirEnt
->OFile
;
1215 ASSERT (OFile
!= NULL
);
1216 Volume
= OFile
->Volume
;
1218 if (OFile
->ODir
!= NULL
) {
1219 FatDiscardODir (OFile
);
1222 if (OFile
->Parent
== NULL
) {
1223 Volume
->Root
= NULL
;
1225 RemoveEntryList (&OFile
->ChildLink
);
1229 DirEnt
->OFile
= NULL
;
1230 if (DirEnt
->Invalid
== TRUE
) {
1232 // Free directory entry itself
1234 FatFreeDirEnt (DirEnt
);
1240 Traverse filename and open all OFiles that can be opened.
1241 Update filename pointer to the component that can't be opened.
1242 If more than one name component remains, returns an error;
1243 otherwise, return the remaining name component so that the caller might choose to create it.
1245 @param PtrOFile - As input, the reference OFile; as output, the located OFile.
1246 @param FileName - The file name relevant to the OFile.
1247 @param Attributes - The attribute of the destination OFile.
1248 @param NewFileName - The remaining file name.
1250 @retval EFI_NOT_FOUND - The file name can't be opened and there is more than one
1251 components within the name left (this means the name can
1252 not be created either).
1253 @retval EFI_INVALID_PARAMETER - The parameter is not valid.
1254 @retval EFI_SUCCESS - Open the file successfully.
1255 @return other - An error occured when locating the OFile.
1260 IN OUT FAT_OFILE
**PtrOFile
,
1261 IN CHAR16
*FileName
,
1262 IN UINT8 Attributes
,
1263 OUT CHAR16
*NewFileName
1268 CHAR16 ComponentName
[EFI_PATH_STRING_LENGTH
];
1270 BOOLEAN DirIntended
;
1277 FileNameLen
= StrLen (FileName
);
1278 if (FileNameLen
== 0) {
1279 return EFI_INVALID_PARAMETER
;
1283 Volume
= OFile
->Volume
;
1285 DirIntended
= FALSE
;
1286 if (FileName
[FileNameLen
- 1] == PATH_NAME_SEPARATOR
) {
1290 // If name starts with path name separator, then move to root OFile
1292 if (*FileName
== PATH_NAME_SEPARATOR
) {
1293 OFile
= Volume
->Root
;
1298 // Per FAT Spec the file name should meet the following criteria:
1299 // C1. Length (FileLongName) <= 255
1300 // C2. Length (X:FileFullPath<NUL>) <= 260
1301 // Here we check C2 first.
1303 if (2 + OFile
->FullPathLen
+ 1 + FileNameLen
+ 1 > EFI_PATH_STRING_LENGTH
) {
1305 // Full path length can not surpass 256
1307 return EFI_INVALID_PARAMETER
;
1310 // Start at current location
1315 // Get the next component name
1318 Next
= FatGetNextNameComponent (FileName
, ComponentName
);
1321 // If end of the file name, we're done
1323 if (ComponentName
[0] == 0) {
1324 if (DirIntended
&& OFile
->ODir
== NULL
) {
1325 return EFI_NOT_FOUND
;
1332 // If "dot", then current
1334 if (StrCmp (ComponentName
, L
".") == 0) {
1338 // If "dot dot", then parent
1340 if (StrCmp (ComponentName
, L
"..") == 0) {
1341 if (OFile
->Parent
== NULL
) {
1342 return EFI_INVALID_PARAMETER
;
1344 OFile
= OFile
->Parent
;
1348 if (!FatFileNameIsValid (ComponentName
, NewFileName
)) {
1349 return EFI_INVALID_PARAMETER
;
1352 // We have a component name, try to open it
1354 if (OFile
->ODir
== NULL
) {
1356 // This file isn't a directory, can't open it
1358 return EFI_NOT_FOUND
;
1361 // Search the compName in the directory
1363 Status
= FatSearchODir (OFile
, NewFileName
, &DirEnt
);
1364 if (EFI_ERROR (Status
)) {
1368 if (DirEnt
== NULL
) {
1370 // component name is not found in the directory
1373 return EFI_NOT_FOUND
;
1376 if (DirIntended
&& (Attributes
& FAT_ATTRIBUTE_DIRECTORY
) == 0) {
1377 return EFI_INVALID_PARAMETER
;
1380 // It's the last component name - return with the open
1381 // path and the remaining name
1386 Status
= FatOpenDirEnt (OFile
, DirEnt
);
1387 if (EFI_ERROR (Status
)) {
1391 OFile
= DirEnt
->OFile
;