1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414 |
- /** @file
- Functions for performing directory entry io.
- Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Fat.h"
- /**
- Get a directory entry from disk for the Ofile.
- @param Parent - The parent of the OFile which need to update.
- @param IoMode - Indicate whether to read directory entry or write directory entry.
- @param EntryPos - The position of the directory entry to be accessed.
- @param Entry - The directory entry read or written.
- @retval EFI_SUCCESS - Access the directory entry successfully.
- @return other - An error occurred when reading the directory entry.
- **/
- STATIC
- EFI_STATUS
- FatAccessEntry (
- IN FAT_OFILE *Parent,
- IN IO_MODE IoMode,
- IN UINTN EntryPos,
- IN OUT VOID *Entry
- )
- {
- UINTN Position;
- UINTN BufferSize;
- Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY);
- if (Position >= Parent->FileSize) {
- //
- // End of directory
- //
- ASSERT (IoMode == ReadData);
- ((FAT_DIRECTORY_ENTRY *)Entry)->FileName[0] = EMPTY_ENTRY_MARK;
- ((FAT_DIRECTORY_ENTRY *)Entry)->Attributes = 0;
- return EFI_SUCCESS;
- }
- BufferSize = sizeof (FAT_DIRECTORY_ENTRY);
- return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry, NULL);
- }
- /**
- Save the directory entry to disk.
- @param OFile - The parent OFile which needs to update.
- @param DirEnt - The directory entry to be saved.
- @retval EFI_SUCCESS - Store the directory entry successfully.
- @return other - An error occurred when writing the directory entry.
- **/
- EFI_STATUS
- FatStoreDirEnt (
- IN FAT_OFILE *OFile,
- IN FAT_DIRENT *DirEnt
- )
- {
- EFI_STATUS Status;
- FAT_DIRECTORY_LFN LfnEntry;
- UINTN EntryPos;
- CHAR16 *LfnBufferPointer;
- CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
- UINT8 EntryCount;
- UINT8 LfnOrdinal;
- EntryPos = DirEnt->EntryPos;
- EntryCount = DirEnt->EntryCount;
- //
- // Write directory entry
- //
- Status = FatAccessEntry (OFile, WriteData, EntryPos, &DirEnt->Entry);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (--EntryCount > 0) {
- //
- // Write LFN directory entry
- //
- SetMem (LfnBuffer, sizeof (CHAR16) * LFN_CHAR_TOTAL * EntryCount, 0xff);
- Status = StrCpyS (
- LfnBuffer,
- ARRAY_SIZE (LfnBuffer),
- DirEnt->FileString
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- LfnBufferPointer = LfnBuffer;
- LfnEntry.Attributes = FAT_ATTRIBUTE_LFN;
- LfnEntry.Type = 0;
- LfnEntry.MustBeZero = 0;
- LfnEntry.Checksum = FatCheckSum (DirEnt->Entry.FileName);
- for (LfnOrdinal = 1; LfnOrdinal <= EntryCount; LfnOrdinal++) {
- LfnEntry.Ordinal = LfnOrdinal;
- if (LfnOrdinal == EntryCount) {
- LfnEntry.Ordinal |= FAT_LFN_LAST;
- }
- CopyMem (LfnEntry.Name1, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR1_LEN);
- LfnBufferPointer += LFN_CHAR1_LEN;
- CopyMem (LfnEntry.Name2, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR2_LEN);
- LfnBufferPointer += LFN_CHAR2_LEN;
- CopyMem (LfnEntry.Name3, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR3_LEN);
- LfnBufferPointer += LFN_CHAR3_LEN;
- EntryPos--;
- if (DirEnt->Invalid) {
- LfnEntry.Ordinal = DELETE_ENTRY_MARK;
- }
- Status = FatAccessEntry (OFile, WriteData, EntryPos, &LfnEntry);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
- }
- return EFI_SUCCESS;
- }
- /**
- Determine whether the directory entry is "." or ".." entry.
- @param DirEnt - The corresponding directory entry.
- @retval TRUE - The directory entry is "." or ".." directory entry
- @retval FALSE - The directory entry is not "." or ".." directory entry
- **/
- BOOLEAN
- FatIsDotDirEnt (
- IN FAT_DIRENT *DirEnt
- )
- {
- CHAR16 *FileString;
- FileString = DirEnt->FileString;
- if ((StrCmp (FileString, L".") == 0) || (StrCmp (FileString, L"..") == 0)) {
- return TRUE;
- }
- return FALSE;
- }
- /**
- Set the OFile's cluster info in its directory entry.
- @param OFile - The corresponding OFile.
- **/
- STATIC
- VOID
- FatSetDirEntCluster (
- IN FAT_OFILE *OFile
- )
- {
- UINTN Cluster;
- FAT_DIRENT *DirEnt;
- DirEnt = OFile->DirEnt;
- Cluster = OFile->FileCluster;
- DirEnt->Entry.FileClusterHigh = (UINT16)(Cluster >> 16);
- DirEnt->Entry.FileCluster = (UINT16)Cluster;
- }
- /**
- Set the OFile's cluster and size info in its directory entry.
- @param OFile - The corresponding OFile.
- **/
- VOID
- FatUpdateDirEntClusterSizeInfo (
- IN FAT_OFILE *OFile
- )
- {
- ASSERT (OFile->ODir == NULL);
- OFile->DirEnt->Entry.FileSize = (UINT32)OFile->FileSize;
- FatSetDirEntCluster (OFile);
- }
- /**
- Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
- @param DirEnt1 - The destination directory entry.
- @param DirEnt2 - The source directory entry.
- **/
- VOID
- FatCloneDirEnt (
- IN FAT_DIRENT *DirEnt1,
- IN FAT_DIRENT *DirEnt2
- )
- {
- UINT8 *Entry1;
- UINT8 *Entry2;
- Entry1 = (UINT8 *)&DirEnt1->Entry;
- Entry2 = (UINT8 *)&DirEnt2->Entry;
- CopyMem (
- Entry1 + FAT_ENTRY_INFO_OFFSET,
- Entry2 + FAT_ENTRY_INFO_OFFSET,
- sizeof (FAT_DIRECTORY_ENTRY) - FAT_ENTRY_INFO_OFFSET
- );
- }
- /**
- Get the LFN for the directory entry.
- @param Parent - The parent directory.
- @param DirEnt - The directory entry to get LFN.
- **/
- STATIC
- VOID
- FatLoadLongNameEntry (
- IN FAT_OFILE *Parent,
- IN FAT_DIRENT *DirEnt
- )
- {
- CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
- CHAR16 *LfnBufferPointer;
- CHAR8 *File8Dot3Name;
- UINTN EntryPos;
- UINT8 LfnOrdinal;
- UINT8 LfnChecksum;
- FAT_DIRECTORY_LFN LfnEntry;
- EFI_STATUS Status;
- EntryPos = DirEnt->EntryPos;
- File8Dot3Name = DirEnt->Entry.FileName;
- LfnBufferPointer = LfnBuffer;
- //
- // Computes checksum for LFN
- //
- LfnChecksum = FatCheckSum (File8Dot3Name);
- LfnOrdinal = 1;
- do {
- if (EntryPos == 0) {
- LfnBufferPointer = LfnBuffer;
- break;
- }
- EntryPos--;
- Status = FatAccessEntry (Parent, ReadData, EntryPos, &LfnEntry);
- if (EFI_ERROR (Status) ||
- (LfnEntry.Attributes != FAT_ATTRIBUTE_LFN) ||
- (LfnEntry.MustBeZero != 0) ||
- (LfnEntry.Checksum != LfnChecksum) ||
- ((LfnEntry.Ordinal & (~FAT_LFN_LAST)) != LfnOrdinal) ||
- (LfnOrdinal > MAX_LFN_ENTRIES)
- )
- {
- //
- // The directory entry does not have a long file name or
- // some error occurs when loading long file name for a directory entry,
- // and then we load the long name from short name
- //
- LfnBufferPointer = LfnBuffer;
- break;
- }
- CopyMem (LfnBufferPointer, LfnEntry.Name1, sizeof (CHAR16) * LFN_CHAR1_LEN);
- LfnBufferPointer += LFN_CHAR1_LEN;
- CopyMem (LfnBufferPointer, LfnEntry.Name2, sizeof (CHAR16) * LFN_CHAR2_LEN);
- LfnBufferPointer += LFN_CHAR2_LEN;
- CopyMem (LfnBufferPointer, LfnEntry.Name3, sizeof (CHAR16) * LFN_CHAR3_LEN);
- LfnBufferPointer += LFN_CHAR3_LEN;
- LfnOrdinal++;
- } while ((LfnEntry.Ordinal & FAT_LFN_LAST) == 0);
- DirEnt->EntryCount = LfnOrdinal;
- //
- // Terminate current Lfnbuffer
- //
- *LfnBufferPointer = 0;
- if (LfnBufferPointer == LfnBuffer) {
- //
- // Fail to get the long file name from long file name entry,
- // get the file name from short name
- //
- FatGetFileNameViaCaseFlag (
- DirEnt,
- LfnBuffer,
- ARRAY_SIZE (LfnBuffer)
- );
- }
- DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer);
- }
- /**
- Add this directory entry node to the list of directory entries and hash table.
- @param ODir - The parent OFile which needs to be updated.
- @param DirEnt - The directory entry to be added.
- **/
- STATIC
- VOID
- FatAddDirEnt (
- IN FAT_ODIR *ODir,
- IN FAT_DIRENT *DirEnt
- )
- {
- if (DirEnt->Link.BackLink == NULL) {
- DirEnt->Link.BackLink = &ODir->ChildList;
- }
- InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link);
- FatInsertToHashTable (ODir, DirEnt);
- }
- /**
- Load from disk the next directory entry at current end of directory position.
- @param OFile - The parent OFile.
- @param PtrDirEnt - The directory entry that is loaded.
- @retval EFI_SUCCESS - Load the directory entry successfully.
- @retval EFI_OUT_OF_RESOURCES - Out of resource.
- @return other - An error occurred when reading the directory entries.
- **/
- STATIC
- EFI_STATUS
- FatLoadNextDirEnt (
- IN FAT_OFILE *OFile,
- OUT FAT_DIRENT **PtrDirEnt
- )
- {
- EFI_STATUS Status;
- FAT_DIRENT *DirEnt;
- FAT_ODIR *ODir;
- FAT_DIRECTORY_ENTRY Entry;
- ODir = OFile->ODir;
- //
- // Make sure the parent's directory has been opened
- //
- ASSERT (ODir != NULL);
- //
- // Assert we have not reached the end of directory
- //
- ASSERT (!ODir->EndOfDir);
- DirEnt = NULL;
- for ( ; ;) {
- //
- // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
- //
- Status = FatAccessEntry (OFile, ReadData, ODir->CurrentEndPos, &Entry);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (((UINT8)Entry.FileName[0] != DELETE_ENTRY_MARK) && ((Entry.Attributes & FAT_ATTRIBUTE_VOLUME_ID) == 0)) {
- //
- // We get a valid directory entry, then handle it
- //
- break;
- }
- ODir->CurrentEndPos++;
- }
- if (Entry.FileName[0] != EMPTY_ENTRY_MARK) {
- //
- // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications
- // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.
- //
- if (OFile->Volume->FatType != Fat32) {
- Entry.FileClusterHigh = 0;
- }
- //
- // This is a valid directory entry
- //
- DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
- if (DirEnt == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- DirEnt->Signature = FAT_DIRENT_SIGNATURE;
- //
- // Remember the directory's entry position on disk
- //
- DirEnt->EntryPos = (UINT16)ODir->CurrentEndPos;
- CopyMem (&DirEnt->Entry, &Entry, sizeof (FAT_DIRECTORY_ENTRY));
- FatLoadLongNameEntry (OFile, DirEnt);
- if (DirEnt->FileString == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- //
- // Add this directory entry to directory
- //
- FatAddDirEnt (ODir, DirEnt);
- //
- // Point to next directory entry
- //
- ODir->CurrentEndPos++;
- } else {
- ODir->EndOfDir = TRUE;
- }
- *PtrDirEnt = DirEnt;
- return EFI_SUCCESS;
- Done:
- FatFreeDirEnt (DirEnt);
- return Status;
- }
- /**
- Get the directory entry's info into Buffer.
- @param Volume - FAT file system volume.
- @param DirEnt - The corresponding directory entry.
- @param BufferSize - Size of Buffer.
- @param Buffer - Buffer containing file info.
- @retval EFI_SUCCESS - Get the file info successfully.
- @retval EFI_BUFFER_TOO_SMALL - The buffer is too small.
- **/
- EFI_STATUS
- FatGetDirEntInfo (
- IN FAT_VOLUME *Volume,
- IN FAT_DIRENT *DirEnt,
- IN OUT UINTN *BufferSize,
- OUT VOID *Buffer
- )
- {
- UINTN Size;
- UINTN NameSize;
- UINTN ResultSize;
- UINTN Cluster;
- EFI_STATUS Status;
- EFI_FILE_INFO *Info;
- FAT_DIRECTORY_ENTRY *Entry;
- FAT_DATE_TIME FatLastAccess;
- ASSERT_VOLUME_LOCKED (Volume);
- Size = SIZE_OF_EFI_FILE_INFO;
- NameSize = StrSize (DirEnt->FileString);
- ResultSize = Size + NameSize;
- Status = EFI_BUFFER_TOO_SMALL;
- if (*BufferSize >= ResultSize) {
- Status = EFI_SUCCESS;
- Entry = &DirEnt->Entry;
- Info = Buffer;
- Info->Size = ResultSize;
- if ((Entry->Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
- Cluster = (Entry->FileClusterHigh << 16) | Entry->FileCluster;
- Info->PhysicalSize = FatPhysicalDirSize (Volume, Cluster);
- Info->FileSize = Info->PhysicalSize;
- } else {
- Info->FileSize = Entry->FileSize;
- Info->PhysicalSize = FatPhysicalFileSize (Volume, Entry->FileSize);
- }
- ZeroMem (&FatLastAccess.Time, sizeof (FatLastAccess.Time));
- CopyMem (&FatLastAccess.Date, &Entry->FileLastAccess, sizeof (FatLastAccess.Date));
- FatFatTimeToEfiTime (&FatLastAccess, &Info->LastAccessTime);
- FatFatTimeToEfiTime (&Entry->FileCreateTime, &Info->CreateTime);
- FatFatTimeToEfiTime (&Entry->FileModificationTime, &Info->ModificationTime);
- Info->Attribute = Entry->Attributes & EFI_FILE_VALID_ATTR;
- CopyMem ((CHAR8 *)Buffer + Size, DirEnt->FileString, NameSize);
- }
- *BufferSize = ResultSize;
- return Status;
- }
- /**
- Search the directory for the directory entry whose filename is FileNameString.
- @param OFile - The parent OFile whose directory is to be searched.
- @param FileNameString - The filename to be searched.
- @param PtrDirEnt - pointer to the directory entry if found.
- @retval EFI_SUCCESS - Find the directory entry or not found.
- @return other - An error occurred when reading the directory entries.
- **/
- STATIC
- EFI_STATUS
- FatSearchODir (
- IN FAT_OFILE *OFile,
- IN CHAR16 *FileNameString,
- OUT FAT_DIRENT **PtrDirEnt
- )
- {
- BOOLEAN PossibleShortName;
- CHAR8 File8Dot3Name[FAT_NAME_LEN];
- FAT_ODIR *ODir;
- FAT_DIRENT *DirEnt;
- EFI_STATUS Status;
- ODir = OFile->ODir;
- ASSERT (ODir != NULL);
- //
- // Check if the file name is a valid short name
- //
- PossibleShortName = FatCheckIs8Dot3Name (FileNameString, File8Dot3Name);
- //
- // Search the hash table first
- //
- DirEnt = *FatLongNameHashSearch (ODir, FileNameString);
- if ((DirEnt == NULL) && PossibleShortName) {
- DirEnt = *FatShortNameHashSearch (ODir, File8Dot3Name);
- }
- if (DirEnt == NULL) {
- //
- // We fail to get the directory entry from hash table; we then
- // search the rest directory
- //
- while (!ODir->EndOfDir) {
- Status = FatLoadNextDirEnt (OFile, &DirEnt);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (DirEnt != NULL) {
- if (FatStriCmp (FileNameString, DirEnt->FileString) == 0) {
- break;
- }
- if (PossibleShortName && (CompareMem (File8Dot3Name, DirEnt->Entry.FileName, FAT_NAME_LEN) == 0)) {
- break;
- }
- }
- }
- }
- *PtrDirEnt = DirEnt;
- return EFI_SUCCESS;
- }
- /**
- Set the OFile's current directory cursor to the list head.
- @param OFile - The directory OFile whose directory cursor is reset.
- **/
- VOID
- FatResetODirCursor (
- IN FAT_OFILE *OFile
- )
- {
- FAT_ODIR *ODir;
- ODir = OFile->ODir;
- ASSERT (ODir != NULL);
- ODir->CurrentCursor = &(ODir->ChildList);
- ODir->CurrentPos = 0;
- }
- /**
- Set the directory's cursor to the next and get the next directory entry.
- @param OFile - The parent OFile.
- @param PtrDirEnt - The next directory entry.
- @retval EFI_SUCCESS - We get the next directory entry successfully.
- @return other - An error occurred when get next directory entry.
- **/
- EFI_STATUS
- FatGetNextDirEnt (
- IN FAT_OFILE *OFile,
- OUT FAT_DIRENT **PtrDirEnt
- )
- {
- EFI_STATUS Status;
- FAT_DIRENT *DirEnt;
- FAT_ODIR *ODir;
- ODir = OFile->ODir;
- ASSERT (ODir != NULL);
- if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
- //
- // End of directory, we will try one more time
- //
- if (!ODir->EndOfDir) {
- //
- // Read directory from disk
- //
- Status = FatLoadNextDirEnt (OFile, &DirEnt);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
- }
- if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
- //
- // End of directory, return NULL
- //
- DirEnt = NULL;
- ODir->CurrentPos = ODir->CurrentEndPos;
- } else {
- ODir->CurrentCursor = ODir->CurrentCursor->ForwardLink;
- DirEnt = DIRENT_FROM_LINK (ODir->CurrentCursor);
- ODir->CurrentPos = DirEnt->EntryPos + 1;
- }
- *PtrDirEnt = DirEnt;
- return EFI_SUCCESS;
- }
- /**
- Set the directory entry count according to the filename.
- @param OFile - The corresponding OFile.
- @param DirEnt - The directory entry to be set.
- **/
- STATIC
- VOID
- FatSetEntryCount (
- IN FAT_OFILE *OFile,
- IN FAT_DIRENT *DirEnt
- )
- {
- CHAR16 *FileString;
- CHAR8 *File8Dot3Name;
- //
- // Get new entry count and set the 8.3 name
- //
- DirEnt->EntryCount = 1;
- FileString = DirEnt->FileString;
- File8Dot3Name = DirEnt->Entry.FileName;
- SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');
- if (StrCmp (FileString, L".") == 0) {
- //
- // "." entry
- //
- File8Dot3Name[0] = '.';
- FatCloneDirEnt (DirEnt, OFile->DirEnt);
- } else if (StrCmp (FileString, L"..") == 0) {
- //
- // ".." entry
- //
- File8Dot3Name[0] = '.';
- File8Dot3Name[1] = '.';
- FatCloneDirEnt (DirEnt, OFile->Parent->DirEnt);
- } else {
- //
- // Normal name
- //
- if (FatCheckIs8Dot3Name (FileString, File8Dot3Name)) {
- //
- // This file name is a valid 8.3 file name, we need to further check its case flag
- //
- FatSetCaseFlag (DirEnt);
- } else {
- //
- // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
- //
- FatCreate8Dot3Name (OFile, DirEnt);
- DirEnt->EntryCount = (UINT8)(LFN_ENTRY_NUMBER (StrLen (FileString)) + DirEnt->EntryCount);
- }
- }
- }
- /**
- Append a zero cluster to the current OFile.
- @param OFile - The directory OFile which needs to be updated.
- @retval EFI_SUCCESS - Append a zero cluster to the OFile successfully.
- @return other - An error occurred when appending the zero cluster.
- **/
- STATIC
- EFI_STATUS
- FatExpandODir (
- IN FAT_OFILE *OFile
- )
- {
- return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);
- }
- /**
- Search the Root OFile for the possible volume label.
- @param Root - The Root OFile.
- @param DirEnt - The returned directory entry of volume label.
- @retval EFI_SUCCESS - The search process is completed successfully.
- @return other - An error occurred when searching volume label.
- **/
- STATIC
- EFI_STATUS
- FatSeekVolumeId (
- IN FAT_OFILE *Root,
- OUT FAT_DIRENT *DirEnt
- )
- {
- EFI_STATUS Status;
- UINTN EntryPos;
- FAT_DIRECTORY_ENTRY *Entry;
- EntryPos = 0;
- Entry = &DirEnt->Entry;
- DirEnt->Invalid = TRUE;
- do {
- Status = FatAccessEntry (Root, ReadData, EntryPos, Entry);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (((UINT8)Entry->FileName[0] != DELETE_ENTRY_MARK) && (((Entry->Attributes) & (~FAT_ATTRIBUTE_ARCHIVE)) == FAT_ATTRIBUTE_VOLUME_ID)) {
- DirEnt->EntryPos = (UINT16)EntryPos;
- DirEnt->EntryCount = 1;
- DirEnt->Invalid = FALSE;
- break;
- }
- EntryPos++;
- } while (Entry->FileName[0] != EMPTY_ENTRY_MARK);
- return EFI_SUCCESS;
- }
- /**
- Use First Fit Algorithm to insert directory entry.
- Only this function will erase "E5" entries in a directory.
- In view of safest recovery, this function will only be triggered
- when maximum directory entry number has reached.
- @param OFile - The corresponding OFile.
- @param DirEnt - The directory entry to be inserted.
- @retval EFI_SUCCESS - The directory entry has been successfully inserted.
- @retval EFI_VOLUME_FULL - The directory can not hold more directory entries.
- @return Others - Some error occurred when inserting new directory entries.
- **/
- STATIC
- EFI_STATUS
- FatFirstFitInsertDirEnt (
- IN FAT_OFILE *OFile,
- IN FAT_DIRENT *DirEnt
- )
- {
- EFI_STATUS Status;
- FAT_ODIR *ODir;
- LIST_ENTRY *CurrentEntry;
- FAT_DIRENT *CurrentDirEnt;
- UINT32 CurrentPos;
- UINT32 LabelPos;
- UINT32 NewEntryPos;
- UINT16 EntryCount;
- FAT_DIRENT LabelDirEnt;
- LabelPos = 0;
- if (OFile->Parent == NULL) {
- Status = FatSeekVolumeId (OFile, &LabelDirEnt);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (!LabelDirEnt.Invalid) {
- LabelPos = LabelDirEnt.EntryPos;
- }
- }
- EntryCount = DirEnt->EntryCount;
- NewEntryPos = EntryCount;
- CurrentPos = 0;
- ODir = OFile->ODir;
- for (CurrentEntry = ODir->ChildList.ForwardLink;
- CurrentEntry != &ODir->ChildList;
- CurrentEntry = CurrentEntry->ForwardLink
- )
- {
- CurrentDirEnt = DIRENT_FROM_LINK (CurrentEntry);
- if (NewEntryPos + CurrentDirEnt->EntryCount <= CurrentDirEnt->EntryPos) {
- if ((LabelPos > NewEntryPos) || (LabelPos <= CurrentPos)) {
- //
- // first fit succeeded
- //
- goto Done;
- }
- }
- CurrentPos = CurrentDirEnt->EntryPos;
- NewEntryPos = CurrentPos + EntryCount;
- }
- if (NewEntryPos >= ODir->CurrentEndPos) {
- return EFI_VOLUME_FULL;
- }
- Done:
- DirEnt->EntryPos = (UINT16)NewEntryPos;
- DirEnt->Link.BackLink = CurrentEntry;
- return EFI_SUCCESS;
- }
- /**
- Find the new directory entry position for the directory entry.
- @param OFile - The corresponding OFile.
- @param DirEnt - The directory entry whose new position is to be set.
- @retval EFI_SUCCESS - The new directory entry position is successfully found.
- @retval EFI_VOLUME_FULL - The directory has reach its maximum capacity.
- @return other - An error occurred when reading the directory entry.
- **/
- STATIC
- EFI_STATUS
- FatNewEntryPos (
- IN FAT_OFILE *OFile,
- IN FAT_DIRENT *DirEnt
- )
- {
- EFI_STATUS Status;
- FAT_ODIR *ODir;
- FAT_DIRENT *TempDirEnt;
- UINT32 NewEndPos;
- ODir = OFile->ODir;
- ASSERT (ODir != NULL);
- //
- // Make sure the whole directory has been loaded
- //
- while (!ODir->EndOfDir) {
- Status = FatLoadNextDirEnt (OFile, &TempDirEnt);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
- //
- // We will append this entry to the end of directory
- //
- FatGetCurrentFatTime (&DirEnt->Entry.FileCreateTime);
- CopyMem (&DirEnt->Entry.FileModificationTime, &DirEnt->Entry.FileCreateTime, sizeof (FAT_DATE_TIME));
- CopyMem (&DirEnt->Entry.FileLastAccess, &DirEnt->Entry.FileCreateTime.Date, sizeof (FAT_DATE));
- NewEndPos = ODir->CurrentEndPos + DirEnt->EntryCount;
- if (NewEndPos * sizeof (FAT_DIRECTORY_ENTRY) > OFile->FileSize) {
- if (NewEndPos >= (OFile->IsFixedRootDir ? OFile->Volume->RootEntries : FAT_MAX_DIRENTRY_COUNT)) {
- //
- // We try to use fist fit algorithm to insert this directory entry
- //
- return FatFirstFitInsertDirEnt (OFile, DirEnt);
- }
- //
- // We should allocate a new cluster for this directory
- //
- Status = FatExpandODir (OFile);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
- //
- // We append our directory entry at the end of directory file
- //
- ODir->CurrentEndPos = NewEndPos;
- DirEnt->EntryPos = (UINT16)(ODir->CurrentEndPos - 1);
- return EFI_SUCCESS;
- }
- /**
- Get the directory entry for the volume.
- @param Volume - FAT file system volume.
- @param Name - The file name of the volume.
- @retval EFI_SUCCESS - Update the volume with the directory entry successfully.
- @return others - An error occurred when getting volume label.
- **/
- EFI_STATUS
- FatGetVolumeEntry (
- IN FAT_VOLUME *Volume,
- IN CHAR16 *Name
- )
- {
- EFI_STATUS Status;
- FAT_DIRENT LabelDirEnt;
- *Name = 0;
- Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
- if (!EFI_ERROR (Status)) {
- if (!LabelDirEnt.Invalid) {
- FatNameToStr (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, FALSE, Name);
- }
- }
- return Status;
- }
- /**
- Set the relevant directory entry into disk for the volume.
- @param Volume - FAT file system volume.
- @param Name - The new file name of the volume.
- @retval EFI_SUCCESS - Update the Volume successfully.
- @retval EFI_UNSUPPORTED - The input label is not a valid volume label.
- @return other - An error occurred when setting volume label.
- **/
- EFI_STATUS
- FatSetVolumeEntry (
- IN FAT_VOLUME *Volume,
- IN CHAR16 *Name
- )
- {
- EFI_STATUS Status;
- FAT_DIRENT LabelDirEnt;
- FAT_OFILE *Root;
- Root = Volume->Root;
- Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (LabelDirEnt.Invalid) {
- //
- // If there is not the relevant directory entry, create a new one
- //
- ZeroMem (&LabelDirEnt, sizeof (FAT_DIRENT));
- LabelDirEnt.EntryCount = 1;
- Status = FatNewEntryPos (Root, &LabelDirEnt);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- LabelDirEnt.Entry.Attributes = FAT_ATTRIBUTE_VOLUME_ID;
- }
- SetMem (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, ' ');
- if (FatStrToFat (Name, FAT_NAME_LEN, LabelDirEnt.Entry.FileName)) {
- return EFI_UNSUPPORTED;
- }
- FatGetCurrentFatTime (&LabelDirEnt.Entry.FileModificationTime);
- return FatStoreDirEnt (Root, &LabelDirEnt);
- }
- /**
- Create "." and ".." directory entries in the newly-created parent OFile.
- @param OFile - The parent OFile.
- @retval EFI_SUCCESS - The dot directory entries are successfully created.
- @return other - An error occurred when creating the directory entry.
- **/
- EFI_STATUS
- FatCreateDotDirEnts (
- IN FAT_OFILE *OFile
- )
- {
- EFI_STATUS Status;
- FAT_DIRENT *DirEnt;
- Status = FatExpandODir (OFile);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- FatSetDirEntCluster (OFile);
- //
- // Create "."
- //
- Status = FatCreateDirEnt (OFile, L".", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Create ".."
- //
- Status = FatCreateDirEnt (OFile, L"..", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
- return Status;
- }
- /**
- Create a directory entry in the parent OFile.
- @param OFile - The parent OFile.
- @param FileName - The filename of the newly-created directory entry.
- @param Attributes - The attribute of the newly-created directory entry.
- @param PtrDirEnt - The pointer to the newly-created directory entry.
- @retval EFI_SUCCESS - The directory entry is successfully created.
- @retval EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry.
- @return other - An error occurred when creating the directory entry.
- **/
- EFI_STATUS
- FatCreateDirEnt (
- IN FAT_OFILE *OFile,
- IN CHAR16 *FileName,
- IN UINT8 Attributes,
- OUT FAT_DIRENT **PtrDirEnt
- )
- {
- FAT_DIRENT *DirEnt;
- FAT_ODIR *ODir;
- EFI_STATUS Status;
- ASSERT (OFile != NULL);
- ODir = OFile->ODir;
- ASSERT (ODir != NULL);
- DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
- if (DirEnt == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- DirEnt->Signature = FAT_DIRENT_SIGNATURE;
- DirEnt->FileString = AllocateCopyPool (StrSize (FileName), FileName);
- if (DirEnt->FileString == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- //
- // Determine how many directory entries we need
- //
- FatSetEntryCount (OFile, DirEnt);
- //
- // Determine the file's directory entry position
- //
- Status = FatNewEntryPos (OFile, DirEnt);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- FatAddDirEnt (ODir, DirEnt);
- DirEnt->Entry.Attributes = Attributes;
- *PtrDirEnt = DirEnt;
- DEBUG ((DEBUG_INFO, "FSOpen: Created new directory entry '%S'\n", DirEnt->FileString));
- return FatStoreDirEnt (OFile, DirEnt);
- Done:
- FatFreeDirEnt (DirEnt);
- return Status;
- }
- /**
- Remove this directory entry node from the list of directory entries and hash table.
- @param OFile - The parent OFile.
- @param DirEnt - The directory entry to be removed.
- @retval EFI_SUCCESS - The directory entry is successfully removed.
- @return other - An error occurred when removing the directory entry.
- **/
- EFI_STATUS
- FatRemoveDirEnt (
- IN FAT_OFILE *OFile,
- IN FAT_DIRENT *DirEnt
- )
- {
- FAT_ODIR *ODir;
- ODir = OFile->ODir;
- if (ODir->CurrentCursor == &DirEnt->Link) {
- //
- // Move the directory cursor to its previous directory entry
- //
- ODir->CurrentCursor = ODir->CurrentCursor->BackLink;
- }
- //
- // Remove from directory entry list
- //
- RemoveEntryList (&DirEnt->Link);
- //
- // Remove from hash table
- //
- FatDeleteFromHashTable (ODir, DirEnt);
- DirEnt->Entry.FileName[0] = DELETE_ENTRY_MARK;
- DirEnt->Invalid = TRUE;
- return FatStoreDirEnt (OFile, DirEnt);
- }
- /**
- Open the directory entry to get the OFile.
- @param Parent - The parent OFile.
- @param DirEnt - The directory entry to be opened.
- @retval EFI_SUCCESS - The directory entry is successfully opened.
- @retval EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile.
- @return other - An error occurred when opening the directory entry.
- **/
- EFI_STATUS
- FatOpenDirEnt (
- IN FAT_OFILE *Parent,
- IN FAT_DIRENT *DirEnt
- )
- {
- FAT_OFILE *OFile;
- FAT_VOLUME *Volume;
- if (DirEnt->OFile == NULL) {
- //
- // Open the directory entry
- //
- OFile = AllocateZeroPool (sizeof (FAT_OFILE));
- if (OFile == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- OFile->Signature = FAT_OFILE_SIGNATURE;
- InitializeListHead (&OFile->Opens);
- InitializeListHead (&OFile->ChildHead);
- OFile->Parent = Parent;
- OFile->DirEnt = DirEnt;
- if (Parent != NULL) {
- //
- // The newly created OFile is not root
- //
- Volume = Parent->Volume;
- OFile->FullPathLen = Parent->FullPathLen + 1 + StrLen (DirEnt->FileString);
- OFile->FileCluster = ((DirEnt->Entry.FileClusterHigh) << 16) | (DirEnt->Entry.FileCluster);
- InsertTailList (&Parent->ChildHead, &OFile->ChildLink);
- } else {
- //
- // The newly created OFile is root
- //
- Volume = VOLUME_FROM_ROOT_DIRENT (DirEnt);
- Volume->Root = OFile;
- OFile->FileCluster = Volume->RootCluster;
- if (Volume->FatType != Fat32) {
- OFile->IsFixedRootDir = TRUE;
- }
- }
- OFile->FileCurrentCluster = OFile->FileCluster;
- OFile->Volume = Volume;
- InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);
- OFile->FileSize = DirEnt->Entry.FileSize;
- if ((DirEnt->Entry.Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
- if (OFile->IsFixedRootDir) {
- OFile->FileSize = Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY);
- } else {
- OFile->FileSize = FatPhysicalDirSize (Volume, OFile->FileCluster);
- }
- FatRequestODir (OFile);
- if (OFile->ODir == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
- DirEnt->OFile = OFile;
- }
- return EFI_SUCCESS;
- }
- /**
- Close the directory entry and free the OFile.
- @param DirEnt - The directory entry to be closed.
- **/
- VOID
- FatCloseDirEnt (
- IN FAT_DIRENT *DirEnt
- )
- {
- FAT_OFILE *OFile;
- FAT_VOLUME *Volume;
- OFile = DirEnt->OFile;
- ASSERT (OFile != NULL);
- Volume = OFile->Volume;
- if (OFile->ODir != NULL) {
- FatDiscardODir (OFile);
- }
- if (OFile->Parent == NULL) {
- Volume->Root = NULL;
- } else {
- RemoveEntryList (&OFile->ChildLink);
- }
- FreePool (OFile);
- DirEnt->OFile = NULL;
- if (DirEnt->Invalid == TRUE) {
- //
- // Free directory entry itself
- //
- FatFreeDirEnt (DirEnt);
- }
- }
- /**
- Traverse filename and open all OFiles that can be opened.
- Update filename pointer to the component that can't be opened.
- If more than one name component remains, returns an error;
- otherwise, return the remaining name component so that the caller might choose to create it.
- @param PtrOFile - As input, the reference OFile; as output, the located OFile.
- @param FileName - The file name relevant to the OFile.
- @param Attributes - The attribute of the destination OFile.
- @param NewFileName - The remaining file name.
- @retval EFI_NOT_FOUND - The file name can't be opened and there is more than one
- components within the name left (this means the name can
- not be created either).
- @retval EFI_INVALID_PARAMETER - The parameter is not valid.
- @retval EFI_SUCCESS - Open the file successfully.
- @return other - An error occurred when locating the OFile.
- **/
- EFI_STATUS
- FatLocateOFile (
- IN OUT FAT_OFILE **PtrOFile,
- IN CHAR16 *FileName,
- IN UINT8 Attributes,
- OUT CHAR16 *NewFileName
- )
- {
- EFI_STATUS Status;
- FAT_VOLUME *Volume;
- CHAR16 ComponentName[EFI_PATH_STRING_LENGTH];
- UINTN FileNameLen;
- BOOLEAN DirIntended;
- CHAR16 *Next;
- FAT_OFILE *OFile;
- FAT_DIRENT *DirEnt;
- DirEnt = NULL;
- FileNameLen = StrLen (FileName);
- if (FileNameLen == 0) {
- return EFI_INVALID_PARAMETER;
- }
- OFile = *PtrOFile;
- Volume = OFile->Volume;
- DirIntended = FALSE;
- if (FileName[FileNameLen - 1] == PATH_NAME_SEPARATOR) {
- DirIntended = TRUE;
- }
- //
- // If name starts with path name separator, then move to root OFile
- //
- if (*FileName == PATH_NAME_SEPARATOR) {
- OFile = Volume->Root;
- FileName++;
- FileNameLen--;
- }
- //
- // Per FAT Spec the file name should meet the following criteria:
- // C1. Length (FileLongName) <= 255
- // C2. Length (X:FileFullPath<NUL>) <= 260
- // Here we check C2 first.
- //
- if (2 + OFile->FullPathLen + 1 + FileNameLen + 1 > EFI_PATH_STRING_LENGTH) {
- //
- // Full path length can not surpass 256
- //
- return EFI_INVALID_PARAMETER;
- }
- //
- // Start at current location
- //
- Next = FileName;
- for ( ; ;) {
- //
- // Get the next component name
- //
- FileName = Next;
- Next = FatGetNextNameComponent (FileName, ComponentName);
- //
- // If end of the file name, we're done
- //
- if (ComponentName[0] == 0) {
- if (DirIntended && (OFile->ODir == NULL)) {
- return EFI_NOT_FOUND;
- }
- NewFileName[0] = 0;
- break;
- }
- //
- // If "dot", then current
- //
- if (StrCmp (ComponentName, L".") == 0) {
- continue;
- }
- //
- // If "dot dot", then parent
- //
- if (StrCmp (ComponentName, L"..") == 0) {
- if (OFile->Parent == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- OFile = OFile->Parent;
- continue;
- }
- if (!FatFileNameIsValid (ComponentName, NewFileName)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // We have a component name, try to open it
- //
- if (OFile->ODir == NULL) {
- //
- // This file isn't a directory, can't open it
- //
- return EFI_NOT_FOUND;
- }
- //
- // Search the compName in the directory
- //
- Status = FatSearchODir (OFile, NewFileName, &DirEnt);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (DirEnt == NULL) {
- //
- // component name is not found in the directory
- //
- if (*Next != 0) {
- return EFI_NOT_FOUND;
- }
- if (DirIntended && ((Attributes & FAT_ATTRIBUTE_DIRECTORY) == 0)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // It's the last component name - return with the open
- // path and the remaining name
- //
- break;
- }
- Status = FatOpenDirEnt (OFile, DirEnt);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- OFile = DirEnt->OFile;
- }
- *PtrOFile = OFile;
- return EFI_SUCCESS;
- }
|