3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Functions for performing directory entry io
39 Get a directory entry from disk for the Ofile.
43 Parent - The parent of the OFile which need to update.
44 IoMode - Indicate whether to read directory entry or write directroy entry.
45 EntryPos - The position of the directory entry to be accessed.
46 Entry - The directory entry read or written.
50 EFI_SUCCESS - Access the directory entry sucessfully.
51 other - An error occurred when reading the directory entry.
58 Position
= EntryPos
* sizeof (FAT_DIRECTORY_ENTRY
);
59 if (Position
>= Parent
->FileSize
) {
63 ASSERT (IoMode
== READ_DATA
);
64 ((FAT_DIRECTORY_ENTRY
*) Entry
)->FileName
[0] = EMPTY_ENTRY_MARK
;
65 ((FAT_DIRECTORY_ENTRY
*) Entry
)->Attributes
= 0;
69 BufferSize
= sizeof (FAT_DIRECTORY_ENTRY
);
70 return FatAccessOFile (Parent
, IoMode
, Position
, &BufferSize
, Entry
);
82 Save the directory entry to disk.
86 OFile - The parent OFile which needs to update.
87 DirEnt - The directory entry to be saved.
91 EFI_SUCCESS - Store the directory entry successfully.
92 other - An error occurred when writing the directory entry.
97 FAT_DIRECTORY_LFN LfnEntry
;
99 CHAR16
*LfnBufferPointer
;
100 CHAR16 LfnBuffer
[MAX_LFN_ENTRIES
* LFN_CHAR_TOTAL
+ 1];
104 EntryPos
= DirEnt
->EntryPos
;
105 EntryCount
= DirEnt
->EntryCount
;
107 // Write directory entry
109 Status
= FatAccessEntry (OFile
, WRITE_DATA
, EntryPos
, &DirEnt
->Entry
);
110 if (EFI_ERROR (Status
)) {
114 if (--EntryCount
> 0) {
116 // Write LFN directory entry
118 SetMem (LfnBuffer
, sizeof (CHAR16
) * LFN_CHAR_TOTAL
* EntryCount
, 0xff);
119 StrCpy (LfnBuffer
, DirEnt
->FileString
);
120 LfnBufferPointer
= LfnBuffer
;
121 LfnEntry
.Attributes
= FAT_ATTRIBUTE_LFN
;
123 LfnEntry
.MustBeZero
= 0;
124 LfnEntry
.Checksum
= FatCheckSum (DirEnt
->Entry
.FileName
);
125 for (LfnOrdinal
= 1; LfnOrdinal
<= EntryCount
; LfnOrdinal
++) {
126 LfnEntry
.Ordinal
= LfnOrdinal
;
127 if (LfnOrdinal
== EntryCount
) {
128 LfnEntry
.Ordinal
|= FAT_LFN_LAST
;
131 CopyMem (LfnEntry
.Name1
, LfnBufferPointer
, sizeof (CHAR16
) * LFN_CHAR1_LEN
);
132 LfnBufferPointer
+= LFN_CHAR1_LEN
;
133 CopyMem (LfnEntry
.Name2
, LfnBufferPointer
, sizeof (CHAR16
) * LFN_CHAR2_LEN
);
134 LfnBufferPointer
+= LFN_CHAR2_LEN
;
135 CopyMem (LfnEntry
.Name3
, LfnBufferPointer
, sizeof (CHAR16
) * LFN_CHAR3_LEN
);
136 LfnBufferPointer
+= LFN_CHAR3_LEN
;
138 if (DirEnt
->Invalid
) {
139 LfnEntry
.Ordinal
= DELETE_ENTRY_MARK
;
142 Status
= FatAccessEntry (OFile
, WRITE_DATA
, EntryPos
, &LfnEntry
);
143 if (EFI_ERROR (Status
)) {
154 IN FAT_DIRENT
*DirEnt
160 Determine whether the directory entry is "." or ".." entry.
164 DirEnt - The corresponding directory entry.
168 TRUE - The directory entry is "." or ".." directory entry
169 FALSE - The directory entry is not "." or ".." directory entry
174 FileString
= DirEnt
->FileString
;
175 if (StrCmp (FileString
, L
".") == 0 || StrCmp (FileString
, L
"..") == 0) {
184 FatSetDirEntCluster (
191 Set the OFile's cluster info in its directory entry.
195 OFile - The corresponding OFile.
206 DirEnt
= OFile
->DirEnt
;
207 Cluster
= OFile
->FileCluster
;
208 DirEnt
->Entry
.FileClusterHigh
= (UINT16
) (Cluster
>> 16);
209 DirEnt
->Entry
.FileCluster
= (UINT16
) Cluster
;
213 FatUpdateDirEntClusterSizeInfo (
220 Set the OFile's cluster and size info in its directory entry.
224 OFile - The corresponding OFile.
232 ASSERT (OFile
->ODir
== NULL
);
233 OFile
->DirEnt
->Entry
.FileSize
= (UINT32
) OFile
->FileSize
;
234 FatSetDirEntCluster (OFile
);
239 IN FAT_DIRENT
*DirEnt1
,
240 IN FAT_DIRENT
*DirEnt2
246 Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
250 DirEnt1 - The destination directory entry.
251 DirEnt2 - The source directory entry.
261 Entry1
= (UINT8
*) &DirEnt1
->Entry
;
262 Entry2
= (UINT8
*) &DirEnt2
->Entry
;
264 Entry1
+ FAT_ENTRY_INFO_OFFSET
,
265 Entry2
+ FAT_ENTRY_INFO_OFFSET
,
266 sizeof (FAT_DIRECTORY_ENTRY
) - FAT_ENTRY_INFO_OFFSET
272 FatLoadLongNameEntry (
273 IN FAT_OFILE
*Parent
,
274 IN FAT_DIRENT
*DirEnt
280 Get the LFN for the directory entry.
284 Parent - The parent directory.
285 DirEnt - The directory entry to get LFN.
293 CHAR16 LfnBuffer
[MAX_LFN_ENTRIES
* LFN_CHAR_TOTAL
+ 1];
294 CHAR16
*LfnBufferPointer
;
295 CHAR8
*File8Dot3Name
;
299 FAT_DIRECTORY_LFN LfnEntry
;
302 EntryPos
= DirEnt
->EntryPos
;
303 File8Dot3Name
= DirEnt
->Entry
.FileName
;
304 LfnBufferPointer
= LfnBuffer
;
306 // Computes checksum for LFN
308 LfnChecksum
= FatCheckSum (File8Dot3Name
);
312 LfnBufferPointer
= LfnBuffer
;
317 Status
= FatAccessEntry (Parent
, READ_DATA
, EntryPos
, &LfnEntry
);
318 if (EFI_ERROR (Status
) ||
319 LfnEntry
.Attributes
!= FAT_ATTRIBUTE_LFN
||
320 LfnEntry
.MustBeZero
!= 0 ||
321 LfnEntry
.Checksum
!= LfnChecksum
||
322 (LfnEntry
.Ordinal
& (~FAT_LFN_LAST
)) != LfnOrdinal
||
323 LfnOrdinal
> MAX_LFN_ENTRIES
326 // The directory entry does not have a long file name or
327 // some error occurs when loading long file name for a directory entry,
328 // and then we load the long name from short name
330 LfnBufferPointer
= LfnBuffer
;
334 CopyMem (LfnBufferPointer
, LfnEntry
.Name1
, sizeof (CHAR16
) * LFN_CHAR1_LEN
);
335 LfnBufferPointer
+= LFN_CHAR1_LEN
;
336 CopyMem (LfnBufferPointer
, LfnEntry
.Name2
, sizeof (CHAR16
) * LFN_CHAR2_LEN
);
337 LfnBufferPointer
+= LFN_CHAR2_LEN
;
338 CopyMem (LfnBufferPointer
, LfnEntry
.Name3
, sizeof (CHAR16
) * LFN_CHAR3_LEN
);
339 LfnBufferPointer
+= LFN_CHAR3_LEN
;
341 } while ((LfnEntry
.Ordinal
& FAT_LFN_LAST
) == 0);
342 DirEnt
->EntryCount
= LfnOrdinal
;
344 // Terminate current Lfnbuffer
346 *LfnBufferPointer
= 0;
347 if (LfnBufferPointer
== LfnBuffer
) {
349 // Fail to get the long file name from long file name entry,
350 // get the file name from short name
352 FatGetFileNameViaCaseFlag (DirEnt
, LfnBuffer
);
355 DirEnt
->FileString
= AllocateCopyPool (StrSize (LfnBuffer
), LfnBuffer
);
362 IN FAT_DIRENT
*DirEnt
368 Add this directory entry node to the list of directory entries and hash table.
372 ODir - The parent OFile which needs to be updated.
373 DirEnt - The directory entry to be added.
381 if (DirEnt
->Link
.BackLink
== NULL
) {
382 DirEnt
->Link
.BackLink
= &ODir
->ChildList
;
384 InsertTailList (DirEnt
->Link
.BackLink
, &DirEnt
->Link
);
385 FatInsertToHashTable (ODir
, DirEnt
);
392 OUT FAT_DIRENT
**PtrDirEnt
398 Load from disk the next directory entry at current end of directory position
402 OFile - The parent OFile.
403 PtrDirEnt - The directory entry that is loaded.
407 EFI_SUCCESS - Load the directory entry successfully.
408 EFI_OUT_OF_RESOURCES - Out of resource.
409 other - An error occurred when reading the directory entries.
416 FAT_DIRECTORY_ENTRY Entry
;
420 // Make sure the parent's directory has been opened
422 ASSERT (ODir
!= NULL
);
424 // Assert we have not reached the end of directory
426 ASSERT (!ODir
->EndOfDir
);
431 // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
433 Status
= FatAccessEntry (OFile
, READ_DATA
, ODir
->CurrentEndPos
, &Entry
);
434 if (EFI_ERROR (Status
)) {
438 if (((UINT8
) Entry
.FileName
[0] != DELETE_ENTRY_MARK
) && (Entry
.Attributes
& FAT_ATTRIBUTE_VOLUME_ID
) == 0) {
440 // We get a valid directory entry, then handle it
445 ODir
->CurrentEndPos
++;
448 if (Entry
.FileName
[0] != EMPTY_ENTRY_MARK
) {
450 // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications
451 // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.
453 if (OFile
->Volume
->FatType
!= FAT32
) {
454 Entry
.FileClusterHigh
= 0;
458 // This is a valid directory entry
460 DirEnt
= AllocateZeroPool (sizeof (FAT_DIRENT
));
461 if (DirEnt
== NULL
) {
462 return EFI_OUT_OF_RESOURCES
;
465 DirEnt
->Signature
= FAT_DIRENT_SIGNATURE
;
467 // Remember the directory's entry position on disk
469 DirEnt
->EntryPos
= (UINT16
) ODir
->CurrentEndPos
;
470 CopyMem (&DirEnt
->Entry
, &Entry
, sizeof (FAT_DIRECTORY_ENTRY
));
471 FatLoadLongNameEntry (OFile
, DirEnt
);
472 if (DirEnt
->FileString
== NULL
) {
473 Status
= EFI_OUT_OF_RESOURCES
;
477 // Add this directory entry to directory
479 FatAddDirEnt (ODir
, DirEnt
);
481 // Point to next directory entry
483 ODir
->CurrentEndPos
++;
485 ODir
->EndOfDir
= TRUE
;
492 FatFreeDirEnt (DirEnt
);
498 IN FAT_VOLUME
*Volume
,
499 IN FAT_DIRENT
*DirEnt
,
500 IN OUT UINTN
*BufferSize
,
507 Get the directory entry's info into Buffer.
511 Volume - FAT file system volume.
512 DirEnt - The corresponding directory entry.
513 BufferSize - Size of Buffer.
514 Buffer - Buffer containing file info.
518 EFI_SUCCESS - Get the file info successfully.
519 EFI_BUFFER_TOO_SMALL - The buffer is too small.
529 FAT_DIRECTORY_ENTRY
*Entry
;
530 FAT_DATE_TIME FatLastAccess
;
532 ASSERT_VOLUME_LOCKED (Volume
);
534 Size
= SIZE_OF_EFI_FILE_INFO
;
535 NameSize
= StrSize (DirEnt
->FileString
);
536 ResultSize
= Size
+ NameSize
;
538 Status
= EFI_BUFFER_TOO_SMALL
;
539 if (*BufferSize
>= ResultSize
) {
540 Status
= EFI_SUCCESS
;
541 Entry
= &DirEnt
->Entry
;
543 Info
->Size
= ResultSize
;
544 if ((Entry
->Attributes
& FAT_ATTRIBUTE_DIRECTORY
) != 0) {
545 Cluster
= (Entry
->FileClusterHigh
<< 16) | Entry
->FileCluster
;
546 Info
->PhysicalSize
= FatPhysicalDirSize (Volume
, Cluster
);
547 Info
->FileSize
= Info
->PhysicalSize
;
549 Info
->FileSize
= Entry
->FileSize
;
550 Info
->PhysicalSize
= FatPhysicalFileSize (Volume
, Entry
->FileSize
);
553 ZeroMem (&FatLastAccess
.Time
, sizeof (FatLastAccess
.Time
));
554 CopyMem (&FatLastAccess
.Date
, &Entry
->FileLastAccess
, sizeof (FatLastAccess
.Date
));
555 FatFatTimeToEfiTime (&FatLastAccess
, &Info
->LastAccessTime
);
556 FatFatTimeToEfiTime (&Entry
->FileCreateTime
, &Info
->CreateTime
);
557 FatFatTimeToEfiTime (&Entry
->FileModificationTime
, &Info
->ModificationTime
);
558 Info
->Attribute
= Entry
->Attributes
& EFI_FILE_VALID_ATTR
;
559 CopyMem ((CHAR8
*) Buffer
+ Size
, DirEnt
->FileString
, NameSize
);
562 *BufferSize
= ResultSize
;
570 IN CHAR16
*FileNameString
,
571 OUT FAT_DIRENT
**PtrDirEnt
577 Search the directory for the directory entry whose filename is FileNameString.
581 OFile - The parent OFile whose directory is to be searched.
582 FileNameString - The filename to be searched.
583 PtrDirEnt - pointer to the directory entry if found.
587 EFI_SUCCESS - Find the directory entry or not found.
588 other - An error occurred when reading the directory entries.
592 BOOLEAN PossibleShortName
;
593 CHAR8 File8Dot3Name
[FAT_NAME_LEN
];
599 ASSERT (ODir
!= NULL
);
601 // Check if the file name is a valid short name
603 PossibleShortName
= FatCheckIs8Dot3Name (FileNameString
, File8Dot3Name
);
605 // Search the hash table first
607 DirEnt
= *FatLongNameHashSearch (ODir
, FileNameString
);
608 if (DirEnt
== NULL
&& PossibleShortName
) {
609 DirEnt
= *FatShortNameHashSearch (ODir
, File8Dot3Name
);
611 if (DirEnt
== NULL
) {
613 // We fail to get the directory entry from hash table; we then
614 // search the rest directory
616 while (!ODir
->EndOfDir
) {
617 Status
= FatLoadNextDirEnt (OFile
, &DirEnt
);
618 if (EFI_ERROR (Status
)) {
622 if (DirEnt
!= NULL
) {
623 if (FatStriCmp (FileNameString
, DirEnt
->FileString
) == 0) {
627 if (PossibleShortName
&& CompareMem (File8Dot3Name
, DirEnt
->Entry
.FileName
, FAT_NAME_LEN
) == 0) {
646 Set the OFile's current directory cursor to the list head.
650 OFile - The directory OFile whose directory cursor is reset.
661 ASSERT (ODir
!= NULL
);
662 ODir
->CurrentCursor
= &(ODir
->ChildList
);
663 ODir
->CurrentPos
= 0;
669 OUT FAT_DIRENT
**PtrDirEnt
675 Set the directory’s cursor to the next and get the next directory entry.
679 OFile - The parent OFile.
680 PtrDirEnt - The next directory entry.
684 EFI_SUCCESS - We get the next directory entry successfully.
685 other - An error occurred when get next directory entry.
694 ASSERT (ODir
!= NULL
);
695 if (ODir
->CurrentCursor
->ForwardLink
== &ODir
->ChildList
) {
697 // End of directory, we will try one more time
699 if (!ODir
->EndOfDir
) {
701 // Read directory from disk
703 Status
= FatLoadNextDirEnt (OFile
, &DirEnt
);
704 if (EFI_ERROR (Status
)) {
710 if (ODir
->CurrentCursor
->ForwardLink
== &ODir
->ChildList
) {
712 // End of directory, return NULL
715 ODir
->CurrentPos
= ODir
->CurrentEndPos
;
717 ODir
->CurrentCursor
= ODir
->CurrentCursor
->ForwardLink
;
718 DirEnt
= DIRENT_FROM_LINK (ODir
->CurrentCursor
);
719 ODir
->CurrentPos
= DirEnt
->EntryPos
+ 1;
730 IN FAT_DIRENT
*DirEnt
736 Set the directory entry count according to the filename.
740 OFile - The corresponding OFile.
741 DirEnt - The directory entry to be set.
750 CHAR8
*File8Dot3Name
;
753 // Get new entry count and set the 8.3 name
755 DirEnt
->EntryCount
= 1;
756 FileString
= DirEnt
->FileString
;
757 File8Dot3Name
= DirEnt
->Entry
.FileName
;
758 SetMem (File8Dot3Name
, FAT_NAME_LEN
, ' ');
759 if (StrCmp (FileString
, L
".") == 0) {
763 File8Dot3Name
[0] = '.';
764 FatCloneDirEnt (DirEnt
, OFile
->DirEnt
);
765 } else if (StrCmp (FileString
, L
"..") == 0) {
769 File8Dot3Name
[0] = '.';
770 File8Dot3Name
[1] = '.';
771 FatCloneDirEnt (DirEnt
, OFile
->Parent
->DirEnt
);
776 if (FatCheckIs8Dot3Name (FileString
, File8Dot3Name
)) {
778 // This file name is a valid 8.3 file name, we need to further check its case flag
780 FatSetCaseFlag (DirEnt
);
783 // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
785 FatCreate8Dot3Name (OFile
, DirEnt
);
786 DirEnt
->EntryCount
= (UINT8
)(LFN_ENTRY_NUMBER (StrLen (FileString
)) + DirEnt
->EntryCount
);
800 Append a zero cluster to the current OFile.
804 OFile - The directory OFile which needs to be updated.
808 EFI_SUCCESS - Append a zero cluster to the OFile successfully.
809 other - An error occurred when appending the zero cluster.
813 return FatExpandOFile (OFile
, OFile
->FileSize
+ OFile
->Volume
->ClusterSize
);
820 OUT FAT_DIRENT
*DirEnt
826 Search the Root OFile for the possible volume label.
830 Root - The Root OFile.
831 DirEnt - The returned directory entry of volume label.
835 EFI_SUCCESS - The search process is completed successfully.
836 other - An error occurred when searching volume label.
842 FAT_DIRECTORY_ENTRY
*Entry
;
845 Entry
= &DirEnt
->Entry
;
846 DirEnt
->Invalid
= TRUE
;
848 Status
= FatAccessEntry (Root
, READ_DATA
, EntryPos
, Entry
);
849 if (EFI_ERROR (Status
)) {
853 if (((UINT8
) Entry
->FileName
[0] != DELETE_ENTRY_MARK
) && (((Entry
->Attributes
) & (~FAT_ATTRIBUTE_ARCHIVE
)) == FAT_ATTRIBUTE_VOLUME_ID
)) {
854 DirEnt
->EntryPos
= (UINT16
) EntryPos
;
855 DirEnt
->EntryCount
= 1;
856 DirEnt
->Invalid
= FALSE
;
861 } while (Entry
->FileName
[0] != EMPTY_ENTRY_MARK
);
867 FatFirstFitInsertDirEnt (
869 IN FAT_DIRENT
*DirEnt
875 Use First Fit Algorithm to insert directory entry.
876 Only this function will erase "E5" entries in a directory.
877 In view of safest recovery, this function will only be triggered
878 when maximum directory entry number has reached.
882 OFile - The corresponding OFile.
883 DirEnt - The directory entry to be inserted.
887 EFI_SUCCESS - The directory entry has been successfully inserted.
888 EFI_VOLUME_FULL - The directory can not hold more directory entries.
889 Others - Some error occurred when inserting new directory entries.
895 LIST_ENTRY
*CurrentEntry
;
896 FAT_DIRENT
*CurrentDirEnt
;
901 FAT_DIRENT LabelDirEnt
;
904 if (OFile
->Parent
== NULL
) {
905 Status
= FatSeekVolumeId (OFile
, &LabelDirEnt
);
906 if (EFI_ERROR (Status
)) {
910 if (!LabelDirEnt
.Invalid
) {
911 LabelPos
= LabelDirEnt
.EntryPos
;
915 EntryCount
= DirEnt
->EntryCount
;
916 NewEntryPos
= EntryCount
;
919 for (CurrentEntry
= ODir
->ChildList
.ForwardLink
;
920 CurrentEntry
!= &ODir
->ChildList
;
921 CurrentEntry
= CurrentEntry
->ForwardLink
923 CurrentDirEnt
= DIRENT_FROM_LINK (CurrentEntry
);
924 if (NewEntryPos
+ CurrentDirEnt
->EntryCount
<= CurrentDirEnt
->EntryPos
) {
925 if (LabelPos
> NewEntryPos
|| LabelPos
<= CurrentPos
) {
927 // first fit succeeded
933 CurrentPos
= CurrentDirEnt
->EntryPos
;
934 NewEntryPos
= CurrentPos
+ EntryCount
;
937 if (NewEntryPos
>= ODir
->CurrentEndPos
) {
938 return EFI_VOLUME_FULL
;
942 DirEnt
->EntryPos
= (UINT16
) NewEntryPos
;
943 DirEnt
->Link
.BackLink
= CurrentEntry
;
951 IN FAT_DIRENT
*DirEnt
957 Find the new directory entry position for the directory entry.
961 OFile - The corresponding OFile.
962 DirEnt - The directory entry whose new position is to be set.
966 EFI_SUCCESS - The new directory entry position is successfully found.
967 EFI_VOLUME_FULL - The directory has reach its maximum capacity.
968 other - An error occurred when reading the directory entry.
974 FAT_DIRENT
*TempDirEnt
;
978 ASSERT (ODir
!= NULL
);
980 // Make sure the whole directory has been loaded
982 while (!ODir
->EndOfDir
) {
983 Status
= FatLoadNextDirEnt (OFile
, &TempDirEnt
);
984 if (EFI_ERROR (Status
)) {
989 // We will append this entry to the end of directory
991 FatGetCurrentFatTime (&DirEnt
->Entry
.FileCreateTime
);
992 FatGetCurrentFatTime (&DirEnt
->Entry
.FileModificationTime
);
993 NewEndPos
= ODir
->CurrentEndPos
+ DirEnt
->EntryCount
;
994 if (NewEndPos
* sizeof (FAT_DIRECTORY_ENTRY
) > OFile
->FileSize
) {
995 if (NewEndPos
>= (OFile
->IsFixedRootDir
? OFile
->Volume
->RootEntries
: FAT_MAX_DIRENTRY_COUNT
)) {
997 // We try to use fist fit algorithm to insert this directory entry
999 return FatFirstFitInsertDirEnt (OFile
, DirEnt
);
1002 // We should allocate a new cluster for this directory
1004 Status
= FatExpandODir (OFile
);
1005 if (EFI_ERROR (Status
)) {
1010 // We append our directory entry at the end of directory file
1012 ODir
->CurrentEndPos
= NewEndPos
;
1013 DirEnt
->EntryPos
= (UINT16
) (ODir
->CurrentEndPos
- 1);
1019 IN FAT_VOLUME
*Volume
,
1024 Routine Description:
1026 Get the directory entry for the volume.
1030 Volume - FAT file system volume.
1031 Name - The file name of the volume.
1035 EFI_SUCCESS - Update the volume with the directory entry sucessfully.
1036 others - An error occurred when getting volume label.
1041 FAT_DIRENT LabelDirEnt
;
1044 Status
= FatSeekVolumeId (Volume
->Root
, &LabelDirEnt
);
1045 if (!EFI_ERROR (Status
)) {
1046 if (!LabelDirEnt
.Invalid
) {
1047 FatNameToStr (LabelDirEnt
.Entry
.FileName
, FAT_NAME_LEN
, FALSE
, Name
);
1056 IN FAT_VOLUME
*Volume
,
1061 Routine Description:
1063 Set the relevant directory entry into disk for the volume.
1067 Volume - FAT file system volume.
1068 Name - The new file name of the volume.
1072 EFI_SUCCESS - Update the Volume sucessfully.
1073 EFI_UNSUPPORTED - The input label is not a valid volume label.
1074 other - An error occurred when setting volume label.
1079 FAT_DIRENT LabelDirEnt
;
1082 Root
= Volume
->Root
;
1083 Status
= FatSeekVolumeId (Volume
->Root
, &LabelDirEnt
);
1084 if (EFI_ERROR (Status
)) {
1088 if (LabelDirEnt
.Invalid
) {
1090 // If there is not the relevant directory entry, create a new one
1092 ZeroMem (&LabelDirEnt
, sizeof (FAT_DIRENT
));
1093 LabelDirEnt
.EntryCount
= 1;
1094 Status
= FatNewEntryPos (Root
, &LabelDirEnt
);
1095 if (EFI_ERROR (Status
)) {
1099 LabelDirEnt
.Entry
.Attributes
= FAT_ATTRIBUTE_VOLUME_ID
;
1102 SetMem (LabelDirEnt
.Entry
.FileName
, FAT_NAME_LEN
, ' ');
1103 if (FatStrToFat (Name
, FAT_NAME_LEN
, LabelDirEnt
.Entry
.FileName
)) {
1104 return EFI_UNSUPPORTED
;
1107 FatGetCurrentFatTime (&LabelDirEnt
.Entry
.FileModificationTime
);
1108 return FatStoreDirEnt (Root
, &LabelDirEnt
);
1112 FatCreateDotDirEnts (
1117 Routine Description:
1119 Create "." and ".." directory entries in the newly-created parent OFile.
1123 OFile - The parent OFile.
1127 EFI_SUCCESS - The dot directory entries are successfully created.
1128 other - An error occurred when creating the directory entry.
1135 Status
= FatExpandODir (OFile
);
1136 if (EFI_ERROR (Status
)) {
1140 FatSetDirEntCluster (OFile
);
1144 Status
= FatCreateDirEnt (OFile
, L
".", FAT_ATTRIBUTE_DIRECTORY
, &DirEnt
);
1145 if (EFI_ERROR (Status
)) {
1151 Status
= FatCreateDirEnt (OFile
, L
"..", FAT_ATTRIBUTE_DIRECTORY
, &DirEnt
);
1157 IN FAT_OFILE
*OFile
,
1158 IN CHAR16
*FileName
,
1159 IN UINT8 Attributes
,
1160 OUT FAT_DIRENT
**PtrDirEnt
1164 Routine Description:
1166 Create a directory entry in the parent OFile.
1170 OFile - The parent OFile.
1171 FileName - The filename of the newly-created directory entry.
1172 Attributes - The attribute of the newly-created directory entry.
1173 PtrDirEnt - The pointer to the newly-created directory entry.
1177 EFI_SUCCESS - The directory entry is successfully created.
1178 EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry.
1179 other - An error occurred when creating the directory entry.
1188 ASSERT (ODir
!= NULL
);
1189 DirEnt
= AllocateZeroPool (sizeof (FAT_DIRENT
));
1190 if (DirEnt
== NULL
) {
1191 return EFI_OUT_OF_RESOURCES
;
1194 DirEnt
->Signature
= FAT_DIRENT_SIGNATURE
;
1195 DirEnt
->FileString
= AllocateCopyPool (StrSize (FileName
), FileName
);
1196 if (DirEnt
->FileString
== NULL
) {
1197 Status
= EFI_OUT_OF_RESOURCES
;
1201 // Determine how many directory entries we need
1203 FatSetEntryCount (OFile
, DirEnt
);
1205 // Determine the file's directory entry position
1207 Status
= FatNewEntryPos (OFile
, DirEnt
);
1208 if (EFI_ERROR (Status
)) {
1212 FatAddDirEnt (ODir
, DirEnt
);
1213 DirEnt
->Entry
.Attributes
= Attributes
;
1214 *PtrDirEnt
= DirEnt
;
1215 DEBUG ((EFI_D_INFO
, "FSOpen: Created new directory entry '%S'\n", DirEnt
->FileString
));
1216 return FatStoreDirEnt (OFile
, DirEnt
);
1219 FatFreeDirEnt (DirEnt
);
1225 IN FAT_OFILE
*OFile
,
1226 IN FAT_DIRENT
*DirEnt
1230 Routine Description:
1232 Remove this directory entry node from the list of directory entries and hash table.
1236 OFile - The parent OFile.
1237 DirEnt - The directory entry to be removed.
1241 EFI_SUCCESS - The directory entry is successfully removed.
1242 other - An error occurred when removing the directory entry.
1249 if (ODir
->CurrentCursor
== &DirEnt
->Link
) {
1251 // Move the directory cursor to its previous directory entry
1253 ODir
->CurrentCursor
= ODir
->CurrentCursor
->BackLink
;
1256 // Remove from directory entry list
1258 RemoveEntryList (&DirEnt
->Link
);
1260 // Remove from hash table
1262 FatDeleteFromHashTable (ODir
, DirEnt
);
1263 DirEnt
->Entry
.FileName
[0] = DELETE_ENTRY_MARK
;
1264 DirEnt
->Invalid
= TRUE
;
1265 return FatStoreDirEnt (OFile
, DirEnt
);
1270 IN FAT_OFILE
*Parent
,
1271 IN FAT_DIRENT
*DirEnt
1275 Routine Description:
1277 Open the directory entry to get the OFile.
1281 OFile - The parent OFile.
1282 DirEnt - The directory entry to be opened.
1286 EFI_SUCCESS - The directory entry is successfully opened.
1287 EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile.
1288 other - An error occurred when opening the directory entry.
1295 if (DirEnt
->OFile
== NULL
) {
1297 // Open the directory entry
1299 OFile
= AllocateZeroPool (sizeof (FAT_OFILE
));
1300 if (OFile
== NULL
) {
1301 return EFI_OUT_OF_RESOURCES
;
1304 OFile
->Signature
= FAT_OFILE_SIGNATURE
;
1305 InitializeListHead (&OFile
->Opens
);
1306 InitializeListHead (&OFile
->ChildHead
);
1307 OFile
->Parent
= Parent
;
1308 OFile
->DirEnt
= DirEnt
;
1309 if (Parent
!= NULL
) {
1311 // The newly created OFile is not root
1313 Volume
= Parent
->Volume
;
1314 OFile
->FullPathLen
= Parent
->FullPathLen
+ 1 + StrLen (DirEnt
->FileString
);
1315 OFile
->FileCluster
= ((DirEnt
->Entry
.FileClusterHigh
) << 16) | (DirEnt
->Entry
.FileCluster
);
1316 InsertTailList (&Parent
->ChildHead
, &OFile
->ChildLink
);
1319 // The newly created OFile is root
1321 Volume
= VOLUME_FROM_ROOT_DIRENT (DirEnt
);
1322 Volume
->Root
= OFile
;
1323 OFile
->FileCluster
= Volume
->RootCluster
;
1324 if (Volume
->FatType
!= FAT32
) {
1325 OFile
->IsFixedRootDir
= TRUE
;
1329 OFile
->FileCurrentCluster
= OFile
->FileCluster
;
1330 OFile
->Volume
= Volume
;
1331 InsertHeadList (&Volume
->CheckRef
, &OFile
->CheckLink
);
1333 OFile
->FileSize
= DirEnt
->Entry
.FileSize
;
1334 if ((DirEnt
->Entry
.Attributes
& FAT_ATTRIBUTE_DIRECTORY
) != 0) {
1335 if (OFile
->IsFixedRootDir
) {
1336 OFile
->FileSize
= Volume
->RootEntries
* sizeof (FAT_DIRECTORY_ENTRY
);
1338 OFile
->FileSize
= FatPhysicalDirSize (Volume
, OFile
->FileCluster
);
1341 FatRequestODir (OFile
);
1342 if (OFile
->ODir
== NULL
) {
1343 return EFI_OUT_OF_RESOURCES
;
1347 DirEnt
->OFile
= OFile
;
1355 IN FAT_DIRENT
*DirEnt
1359 Routine Description:
1361 Close the directory entry and free the OFile.
1365 DirEnt - The directory entry to be closed.
1369 EFI_SUCCESS - The directory entry is successfully opened.
1370 Other - An error occurred when opening the directory entry.
1377 OFile
= DirEnt
->OFile
;
1378 Volume
= OFile
->Volume
;
1379 ASSERT (OFile
!= NULL
);
1381 if (OFile
->ODir
!= NULL
) {
1382 FatDiscardODir (OFile
);
1385 if (OFile
->Parent
== NULL
) {
1386 Volume
->Root
= NULL
;
1388 RemoveEntryList (&OFile
->ChildLink
);
1392 DirEnt
->OFile
= NULL
;
1393 if (DirEnt
->Invalid
== TRUE
) {
1395 // Free directory entry itself
1397 FatFreeDirEnt (DirEnt
);
1403 IN OUT FAT_OFILE
**PtrOFile
,
1404 IN CHAR16
*FileName
,
1405 IN UINT8 Attributes
,
1406 OUT CHAR16
*NewFileName
1410 Routine Description:
1412 Traverse filename and open all OFiles that can be opened.
1413 Update filename pointer to the component that can't be opened.
1414 If more than one name component remains, returns an error;
1415 otherwise, return the remaining name component so that the caller might choose to create it.
1418 PtrOFile - As input, the reference OFile; as output, the located OFile.
1419 FileName - The file name relevant to the OFile.
1420 Attributes - The attribute of the destination OFile.
1421 NewFileName - The remaining file name.
1425 EFI_NOT_FOUND - The file name can't be opened and there is more than one
1426 components within the name left (this means the name can
1427 not be created either).
1428 EFI_INVALID_PARAMETER - The parameter is not valid.
1429 EFI_SUCCESS - Open the file successfully.
1430 other - An error occured when locating the OFile.
1436 CHAR16 ComponentName
[EFI_PATH_STRING_LENGTH
];
1438 BOOLEAN DirIntended
;
1443 FileNameLen
= StrLen (FileName
);
1444 if (FileNameLen
== 0) {
1445 return EFI_INVALID_PARAMETER
;
1449 Volume
= OFile
->Volume
;
1451 DirIntended
= FALSE
;
1452 if (FileName
[FileNameLen
- 1] == PATH_NAME_SEPARATOR
) {
1456 // If name starts with path name separator, then move to root OFile
1458 if (*FileName
== PATH_NAME_SEPARATOR
) {
1459 OFile
= Volume
->Root
;
1464 // Per FAT Spec the file name should meet the following criteria:
1465 // C1. Length (FileLongName) <= 255
1466 // C2. Length (X:FileFullPath<NUL>) <= 260
1467 // Here we check C2 first.
1469 if (2 + OFile
->FullPathLen
+ 1 + FileNameLen
+ 1 > EFI_PATH_STRING_LENGTH
) {
1471 // Full path length can not surpass 256
1473 return EFI_INVALID_PARAMETER
;
1476 // Start at current location
1481 // Get the next component name
1484 Next
= FatGetNextNameComponent (FileName
, ComponentName
);
1487 // If end of the file name, we're done
1489 if (ComponentName
[0] == 0) {
1490 if (DirIntended
&& OFile
->ODir
== NULL
) {
1491 return EFI_NOT_FOUND
;
1498 // If "dot", then current
1500 if (StrCmp (ComponentName
, L
".") == 0) {
1504 // If "dot dot", then parent
1506 if (StrCmp (ComponentName
, L
"..") == 0) {
1507 if (OFile
->Parent
== NULL
) {
1508 return EFI_INVALID_PARAMETER
;
1510 OFile
= OFile
->Parent
;
1514 if (!FatFileNameIsValid (ComponentName
, NewFileName
)) {
1515 return EFI_INVALID_PARAMETER
;
1518 // We have a component name, try to open it
1520 if (OFile
->ODir
== NULL
) {
1522 // This file isn't a directory, can't open it
1524 return EFI_NOT_FOUND
;
1527 // Search the compName in the directory
1529 Status
= FatSearchODir (OFile
, NewFileName
, &DirEnt
);
1530 if (EFI_ERROR (Status
)) {
1534 if (DirEnt
== NULL
) {
1536 // component name is not found in the directory
1539 return EFI_NOT_FOUND
;
1542 if (DirIntended
&& (Attributes
& FAT_ATTRIBUTE_DIRECTORY
) == 0) {
1543 return EFI_INVALID_PARAMETER
;
1546 // It's the last component name - return with the open
1547 // path and the remaining name
1552 Status
= FatOpenDirEnt (OFile
, DirEnt
);
1553 if (EFI_ERROR (Status
)) {
1557 OFile
= DirEnt
->OFile
;