Home | History | Annotate | Download | only in EnhancedFatDxe
      1 /** @file
      2   Functions for performing directory entry io.
      3 
      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
      9 
     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.
     12 
     13 **/
     14 
     15 #include "Fat.h"
     16 
     17 /**
     18 
     19   Get a directory entry from disk for the Ofile.
     20 
     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.
     25 
     26   @retval EFI_SUCCESS           - Access the directory entry sucessfully.
     27   @return other                 - An error occurred when reading the directory entry.
     28 
     29 **/
     30 STATIC
     31 EFI_STATUS
     32 FatAccessEntry (
     33   IN     FAT_OFILE            *Parent,
     34   IN     IO_MODE              IoMode,
     35   IN     UINTN                EntryPos,
     36   IN OUT VOID                 *Entry
     37   )
     38 {
     39   UINTN Position;
     40   UINTN BufferSize;
     41 
     42   Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY);
     43   if (Position >= Parent->FileSize) {
     44     //
     45     // End of directory
     46     //
     47     ASSERT (IoMode == ReadData);
     48     ((FAT_DIRECTORY_ENTRY *) Entry)->FileName[0] = EMPTY_ENTRY_MARK;
     49     ((FAT_DIRECTORY_ENTRY *) Entry)->Attributes  = 0;
     50     return EFI_SUCCESS;
     51   }
     52 
     53   BufferSize = sizeof (FAT_DIRECTORY_ENTRY);
     54   return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry, NULL);
     55 }
     56 
     57 /**
     58 
     59   Save the directory entry to disk.
     60 
     61   @param  OFile                 - The parent OFile which needs to update.
     62   @param  DirEnt                - The directory entry to be saved.
     63 
     64   @retval EFI_SUCCESS           - Store the directory entry successfully.
     65   @return other                 - An error occurred when writing the directory entry.
     66 
     67 **/
     68 EFI_STATUS
     69 FatStoreDirEnt (
     70   IN FAT_OFILE            *OFile,
     71   IN FAT_DIRENT           *DirEnt
     72   )
     73 {
     74   EFI_STATUS        Status;
     75   FAT_DIRECTORY_LFN LfnEntry;
     76   UINTN             EntryPos;
     77   CHAR16            *LfnBufferPointer;
     78   CHAR16            LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
     79   UINT8             EntryCount;
     80   UINT8             LfnOrdinal;
     81 
     82   EntryPos   = DirEnt->EntryPos;
     83   EntryCount = DirEnt->EntryCount;
     84   //
     85   // Write directory entry
     86   //
     87   Status = FatAccessEntry (OFile, WriteData, EntryPos, &DirEnt->Entry);
     88   if (EFI_ERROR (Status)) {
     89     return Status;
     90   }
     91 
     92   if (--EntryCount > 0) {
     93     //
     94     // Write LFN directory entry
     95     //
     96     SetMem (LfnBuffer, sizeof (CHAR16) * LFN_CHAR_TOTAL * EntryCount, 0xff);
     97     Status = StrCpyS (
     98                LfnBuffer,
     99                ARRAY_SIZE (LfnBuffer),
    100                DirEnt->FileString
    101                );
    102     if (EFI_ERROR (Status)) {
    103       return Status;
    104     }
    105 
    106     LfnBufferPointer    = LfnBuffer;
    107     LfnEntry.Attributes = FAT_ATTRIBUTE_LFN;
    108     LfnEntry.Type       = 0;
    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;
    115       }
    116 
    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;
    123       EntryPos--;
    124       if (DirEnt->Invalid) {
    125         LfnEntry.Ordinal = DELETE_ENTRY_MARK;
    126       }
    127 
    128       Status = FatAccessEntry (OFile, WriteData, EntryPos, &LfnEntry);
    129       if (EFI_ERROR (Status)) {
    130         return Status;
    131       }
    132     }
    133   }
    134 
    135   return EFI_SUCCESS;
    136 }
    137 
    138 /**
    139 
    140   Determine whether the directory entry is "." or ".." entry.
    141 
    142   @param  DirEnt               - The corresponding directory entry.
    143 
    144   @retval TRUE                 - The directory entry is "." or ".." directory entry
    145   @retval FALSE                - The directory entry is not "." or ".." directory entry
    146 
    147 **/
    148 BOOLEAN
    149 FatIsDotDirEnt (
    150   IN FAT_DIRENT  *DirEnt
    151   )
    152 {
    153   CHAR16  *FileString;
    154   FileString = DirEnt->FileString;
    155   if (StrCmp (FileString, L".") == 0 || StrCmp (FileString, L"..") == 0) {
    156     return TRUE;
    157   }
    158 
    159   return FALSE;
    160 }
    161 
    162 /**
    163 
    164   Set the OFile's cluster info in its directory entry.
    165 
    166   @param  OFile                 - The corresponding OFile.
    167 
    168 **/
    169 STATIC
    170 VOID
    171 FatSetDirEntCluster (
    172   IN FAT_OFILE    *OFile
    173   )
    174 {
    175   UINTN       Cluster;
    176   FAT_DIRENT  *DirEnt;
    177 
    178   DirEnt                        = OFile->DirEnt;
    179   Cluster                       = OFile->FileCluster;
    180   DirEnt->Entry.FileClusterHigh = (UINT16) (Cluster >> 16);
    181   DirEnt->Entry.FileCluster     = (UINT16) Cluster;
    182 }
    183 
    184 /**
    185 
    186   Set the OFile's cluster and size info in its directory entry.
    187 
    188   @param  OFile                 - The corresponding OFile.
    189 
    190 **/
    191 VOID
    192 FatUpdateDirEntClusterSizeInfo (
    193   IN FAT_OFILE    *OFile
    194   )
    195 {
    196   ASSERT (OFile->ODir == NULL);
    197   OFile->DirEnt->Entry.FileSize = (UINT32) OFile->FileSize;
    198   FatSetDirEntCluster (OFile);
    199 }
    200 
    201 /**
    202 
    203   Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
    204 
    205   @param  DirEnt1               - The destination directory entry.
    206   @param  DirEnt2               - The source directory entry.
    207 
    208 **/
    209 VOID
    210 FatCloneDirEnt (
    211   IN  FAT_DIRENT          *DirEnt1,
    212   IN  FAT_DIRENT          *DirEnt2
    213   )
    214 {
    215   UINT8 *Entry1;
    216   UINT8 *Entry2;
    217   Entry1  = (UINT8 *) &DirEnt1->Entry;
    218   Entry2  = (UINT8 *) &DirEnt2->Entry;
    219   CopyMem (
    220     Entry1 + FAT_ENTRY_INFO_OFFSET,
    221     Entry2 + FAT_ENTRY_INFO_OFFSET,
    222     sizeof (FAT_DIRECTORY_ENTRY) - FAT_ENTRY_INFO_OFFSET
    223     );
    224 }
    225 
    226 /**
    227 
    228   Get the LFN for the directory entry.
    229 
    230   @param  Parent                - The parent directory.
    231   @param  DirEnt                - The directory entry to get LFN.
    232 
    233 **/
    234 STATIC
    235 VOID
    236 FatLoadLongNameEntry (
    237   IN FAT_OFILE           *Parent,
    238   IN FAT_DIRENT          *DirEnt
    239   )
    240 {
    241   CHAR16            LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
    242   CHAR16            *LfnBufferPointer;
    243   CHAR8             *File8Dot3Name;
    244   UINTN             EntryPos;
    245   UINT8             LfnOrdinal;
    246   UINT8             LfnChecksum;
    247   FAT_DIRECTORY_LFN LfnEntry;
    248   EFI_STATUS        Status;
    249 
    250   EntryPos          = DirEnt->EntryPos;
    251   File8Dot3Name     = DirEnt->Entry.FileName;
    252   LfnBufferPointer  = LfnBuffer;
    253   //
    254   // Computes checksum for LFN
    255   //
    256   LfnChecksum = FatCheckSum (File8Dot3Name);
    257   LfnOrdinal  = 1;
    258   do {
    259     if (EntryPos == 0) {
    260       LfnBufferPointer = LfnBuffer;
    261       break;
    262     }
    263 
    264     EntryPos--;
    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
    272         ) {
    273       //
    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
    277       //
    278       LfnBufferPointer = LfnBuffer;
    279       break;
    280     }
    281 
    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;
    288     LfnOrdinal++;
    289   } while ((LfnEntry.Ordinal & FAT_LFN_LAST) == 0);
    290   DirEnt->EntryCount = LfnOrdinal;
    291   //
    292   // Terminate current Lfnbuffer
    293   //
    294   *LfnBufferPointer = 0;
    295   if (LfnBufferPointer == LfnBuffer) {
    296     //
    297     // Fail to get the long file name from long file name entry,
    298     // get the file name from short name
    299     //
    300     FatGetFileNameViaCaseFlag (
    301       DirEnt,
    302       LfnBuffer,
    303       ARRAY_SIZE (LfnBuffer)
    304       );
    305   }
    306 
    307   DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer);
    308 }
    309 
    310 /**
    311 
    312   Add this directory entry node to the list of directory entries and hash table.
    313 
    314   @param  ODir                  - The parent OFile which needs to be updated.
    315   @param  DirEnt                - The directory entry to be added.
    316 
    317 **/
    318 STATIC
    319 VOID
    320 FatAddDirEnt (
    321   IN FAT_ODIR             *ODir,
    322   IN FAT_DIRENT           *DirEnt
    323   )
    324 {
    325   if (DirEnt->Link.BackLink == NULL) {
    326     DirEnt->Link.BackLink = &ODir->ChildList;
    327   }
    328   InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link);
    329   FatInsertToHashTable (ODir, DirEnt);
    330 }
    331 
    332 /**
    333 
    334   Load from disk the next directory entry at current end of directory position.
    335 
    336   @param  OFile                 - The parent OFile.
    337   @param  PtrDirEnt             - The directory entry that is loaded.
    338 
    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.
    342 
    343 **/
    344 STATIC
    345 EFI_STATUS
    346 FatLoadNextDirEnt (
    347   IN  FAT_OFILE           *OFile,
    348   OUT FAT_DIRENT          **PtrDirEnt
    349   )
    350 {
    351   EFI_STATUS          Status;
    352   FAT_DIRENT          *DirEnt;
    353   FAT_ODIR            *ODir;
    354   FAT_DIRECTORY_ENTRY Entry;
    355 
    356   ODir = OFile->ODir;
    357   //
    358   // Make sure the parent's directory has been opened
    359   //
    360   ASSERT (ODir != NULL);
    361   //
    362   // Assert we have not reached the end of directory
    363   //
    364   ASSERT (!ODir->EndOfDir);
    365   DirEnt = NULL;
    366 
    367   for (;;) {
    368     //
    369     // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
    370     //
    371     Status = FatAccessEntry (OFile, ReadData, ODir->CurrentEndPos, &Entry);
    372     if (EFI_ERROR (Status)) {
    373       return Status;
    374     }
    375 
    376     if (((UINT8) Entry.FileName[0] != DELETE_ENTRY_MARK) && (Entry.Attributes & FAT_ATTRIBUTE_VOLUME_ID) == 0) {
    377       //
    378       // We get a valid directory entry, then handle it
    379       //
    380       break;
    381     }
    382 
    383     ODir->CurrentEndPos++;
    384   }
    385 
    386   if (Entry.FileName[0] != EMPTY_ENTRY_MARK) {
    387     //
    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.
    390     //
    391     if (OFile->Volume->FatType != Fat32) {
    392       Entry.FileClusterHigh = 0;
    393     }
    394 
    395     //
    396     // This is a valid directory entry
    397     //
    398     DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
    399     if (DirEnt == NULL) {
    400       return EFI_OUT_OF_RESOURCES;
    401     }
    402 
    403     DirEnt->Signature = FAT_DIRENT_SIGNATURE;
    404     //
    405     // Remember the directory's entry position on disk
    406     //
    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;
    412       goto Done;
    413     }
    414     //
    415     // Add this directory entry to directory
    416     //
    417     FatAddDirEnt (ODir, DirEnt);
    418     //
    419     // Point to next directory entry
    420     //
    421     ODir->CurrentEndPos++;
    422   } else {
    423     ODir->EndOfDir = TRUE;
    424   }
    425 
    426   *PtrDirEnt = DirEnt;
    427   return EFI_SUCCESS;
    428 
    429 Done:
    430   FatFreeDirEnt (DirEnt);
    431   return Status;
    432 }
    433 
    434 /**
    435 
    436   Get the directory entry's info into Buffer.
    437 
    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.
    442 
    443   @retval EFI_SUCCESS           - Get the file info successfully.
    444   @retval EFI_BUFFER_TOO_SMALL  - The buffer is too small.
    445 
    446 **/
    447 EFI_STATUS
    448 FatGetDirEntInfo (
    449   IN     FAT_VOLUME         *Volume,
    450   IN     FAT_DIRENT         *DirEnt,
    451   IN OUT UINTN              *BufferSize,
    452      OUT VOID               *Buffer
    453   )
    454 {
    455   UINTN               Size;
    456   UINTN               NameSize;
    457   UINTN               ResultSize;
    458   UINTN               Cluster;
    459   EFI_STATUS          Status;
    460   EFI_FILE_INFO       *Info;
    461   FAT_DIRECTORY_ENTRY *Entry;
    462   FAT_DATE_TIME       FatLastAccess;
    463 
    464   ASSERT_VOLUME_LOCKED (Volume);
    465 
    466   Size        = SIZE_OF_EFI_FILE_INFO;
    467   NameSize    = StrSize (DirEnt->FileString);
    468   ResultSize  = Size + NameSize;
    469 
    470   Status      = EFI_BUFFER_TOO_SMALL;
    471   if (*BufferSize >= ResultSize) {
    472     Status      = EFI_SUCCESS;
    473     Entry       = &DirEnt->Entry;
    474     Info        = Buffer;
    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;
    480     } else {
    481       Info->FileSize      = Entry->FileSize;
    482       Info->PhysicalSize  = FatPhysicalFileSize (Volume, Entry->FileSize);
    483     }
    484 
    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);
    492   }
    493 
    494   *BufferSize = ResultSize;
    495   return Status;
    496 }
    497 
    498 /**
    499 
    500   Search the directory for the directory entry whose filename is FileNameString.
    501 
    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.
    505 
    506   @retval EFI_SUCCESS           - Find the directory entry or not found.
    507   @return other                 - An error occurred when reading the directory entries.
    508 
    509 **/
    510 STATIC
    511 EFI_STATUS
    512 FatSearchODir (
    513   IN  FAT_OFILE      *OFile,
    514   IN  CHAR16         *FileNameString,
    515   OUT FAT_DIRENT     **PtrDirEnt
    516   )
    517 {
    518   BOOLEAN     PossibleShortName;
    519   CHAR8       File8Dot3Name[FAT_NAME_LEN];
    520   FAT_ODIR    *ODir;
    521   FAT_DIRENT  *DirEnt;
    522   EFI_STATUS  Status;
    523 
    524   ODir = OFile->ODir;
    525   ASSERT (ODir != NULL);
    526   //
    527   // Check if the file name is a valid short name
    528   //
    529   PossibleShortName = FatCheckIs8Dot3Name (FileNameString, File8Dot3Name);
    530   //
    531   // Search the hash table first
    532   //
    533   DirEnt = *FatLongNameHashSearch (ODir, FileNameString);
    534   if (DirEnt == NULL && PossibleShortName) {
    535       DirEnt = *FatShortNameHashSearch (ODir, File8Dot3Name);
    536   }
    537   if (DirEnt == NULL) {
    538     //
    539     // We fail to get the directory entry from hash table; we then
    540     // search the rest directory
    541     //
    542     while (!ODir->EndOfDir) {
    543       Status = FatLoadNextDirEnt (OFile, &DirEnt);
    544       if (EFI_ERROR (Status)) {
    545         return Status;
    546       }
    547 
    548       if (DirEnt != NULL) {
    549         if (FatStriCmp (FileNameString, DirEnt->FileString) == 0) {
    550           break;
    551         }
    552 
    553         if (PossibleShortName && CompareMem (File8Dot3Name, DirEnt->Entry.FileName, FAT_NAME_LEN) == 0) {
    554           break;
    555         }
    556       }
    557     }
    558   }
    559 
    560   *PtrDirEnt = DirEnt;
    561   return EFI_SUCCESS;
    562 }
    563 
    564 /**
    565 
    566   Set the OFile's current directory cursor to the list head.
    567 
    568   @param OFile                 - The directory OFile whose directory cursor is reset.
    569 
    570 **/
    571 VOID
    572 FatResetODirCursor (
    573   IN FAT_OFILE    *OFile
    574   )
    575 {
    576   FAT_ODIR  *ODir;
    577 
    578   ODir = OFile->ODir;
    579   ASSERT (ODir != NULL);
    580   ODir->CurrentCursor = &(ODir->ChildList);
    581   ODir->CurrentPos    = 0;
    582 }
    583 
    584 /**
    585 
    586   Set the directory's cursor to the next and get the next directory entry.
    587 
    588   @param  OFile                 - The parent OFile.
    589   @param PtrDirEnt             - The next directory entry.
    590 
    591   @retval EFI_SUCCESS           - We get the next directory entry successfully.
    592   @return other                 - An error occurred when get next directory entry.
    593 
    594 **/
    595 EFI_STATUS
    596 FatGetNextDirEnt (
    597   IN  FAT_OFILE     *OFile,
    598   OUT FAT_DIRENT    **PtrDirEnt
    599   )
    600 {
    601   EFI_STATUS  Status;
    602   FAT_DIRENT  *DirEnt;
    603   FAT_ODIR    *ODir;
    604 
    605   ODir = OFile->ODir;
    606   ASSERT (ODir != NULL);
    607   if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
    608     //
    609     // End of directory, we will try one more time
    610     //
    611     if (!ODir->EndOfDir) {
    612       //
    613       // Read directory from disk
    614       //
    615       Status = FatLoadNextDirEnt (OFile, &DirEnt);
    616       if (EFI_ERROR (Status)) {
    617         return Status;
    618       }
    619     }
    620   }
    621 
    622   if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
    623     //
    624     // End of directory, return NULL
    625     //
    626     DirEnt              = NULL;
    627     ODir->CurrentPos    = ODir->CurrentEndPos;
    628   } else {
    629     ODir->CurrentCursor = ODir->CurrentCursor->ForwardLink;
    630     DirEnt              = DIRENT_FROM_LINK (ODir->CurrentCursor);
    631     ODir->CurrentPos    = DirEnt->EntryPos + 1;
    632   }
    633 
    634   *PtrDirEnt = DirEnt;
    635   return EFI_SUCCESS;
    636 }
    637 
    638 /**
    639 
    640   Set the directory entry count according to the filename.
    641 
    642   @param  OFile                 - The corresponding OFile.
    643   @param  DirEnt                - The directory entry to be set.
    644 
    645 **/
    646 STATIC
    647 VOID
    648 FatSetEntryCount (
    649   IN FAT_OFILE    *OFile,
    650   IN FAT_DIRENT   *DirEnt
    651   )
    652 {
    653   CHAR16  *FileString;
    654   CHAR8   *File8Dot3Name;
    655 
    656   //
    657   // Get new entry count and set the 8.3 name
    658   //
    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) {
    664     //
    665     // "." entry
    666     //
    667     File8Dot3Name[0] = '.';
    668     FatCloneDirEnt (DirEnt, OFile->DirEnt);
    669   } else if (StrCmp (FileString, L"..") == 0) {
    670     //
    671     // ".." entry
    672     //
    673     File8Dot3Name[0]  = '.';
    674     File8Dot3Name[1]  = '.';
    675     FatCloneDirEnt (DirEnt, OFile->Parent->DirEnt);
    676   } else {
    677     //
    678     // Normal name
    679     //
    680     if (FatCheckIs8Dot3Name (FileString, File8Dot3Name)) {
    681       //
    682       // This file name is a valid 8.3 file name, we need to further check its case flag
    683       //
    684       FatSetCaseFlag (DirEnt);
    685     } else {
    686       //
    687       // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
    688       //
    689       FatCreate8Dot3Name (OFile, DirEnt);
    690       DirEnt->EntryCount = (UINT8)(LFN_ENTRY_NUMBER (StrLen (FileString)) + DirEnt->EntryCount);
    691     }
    692   }
    693 }
    694 
    695 /**
    696 
    697   Append a zero cluster to the current OFile.
    698 
    699   @param  OFile        - The directory OFile which needs to be updated.
    700 
    701   @retval EFI_SUCCESS  - Append a zero cluster to the OFile successfully.
    702   @return other        - An error occurred when appending the zero cluster.
    703 
    704 **/
    705 STATIC
    706 EFI_STATUS
    707 FatExpandODir (
    708   IN FAT_OFILE  *OFile
    709   )
    710 {
    711   return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);
    712 }
    713 
    714 /**
    715 
    716   Search the Root OFile for the possible volume label.
    717 
    718   @param  Root                  - The Root OFile.
    719   @param  DirEnt                - The returned directory entry of volume label.
    720 
    721   @retval EFI_SUCCESS           - The search process is completed successfully.
    722   @return other                 - An error occurred when searching volume label.
    723 
    724 **/
    725 STATIC
    726 EFI_STATUS
    727 FatSeekVolumeId (
    728   IN  FAT_OFILE            *Root,
    729   OUT FAT_DIRENT           *DirEnt
    730   )
    731 {
    732   EFI_STATUS          Status;
    733   UINTN               EntryPos;
    734   FAT_DIRECTORY_ENTRY *Entry;
    735 
    736   EntryPos        = 0;
    737   Entry           = &DirEnt->Entry;
    738   DirEnt->Invalid = TRUE;
    739   do {
    740     Status = FatAccessEntry (Root, ReadData, EntryPos, Entry);
    741     if (EFI_ERROR (Status)) {
    742       return Status;
    743     }
    744 
    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;
    749       break;
    750     }
    751 
    752     EntryPos++;
    753   } while (Entry->FileName[0] != EMPTY_ENTRY_MARK);
    754   return EFI_SUCCESS;
    755 }
    756 
    757 /**
    758 
    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.
    763 
    764   @param  OFile                 - The corresponding OFile.
    765   @param  DirEnt                - The directory entry to be inserted.
    766 
    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.
    770 
    771 **/
    772 STATIC
    773 EFI_STATUS
    774 FatFirstFitInsertDirEnt (
    775   IN FAT_OFILE    *OFile,
    776   IN FAT_DIRENT   *DirEnt
    777   )
    778 {
    779   EFI_STATUS      Status;
    780   FAT_ODIR        *ODir;
    781   LIST_ENTRY      *CurrentEntry;
    782   FAT_DIRENT      *CurrentDirEnt;
    783   UINT32          CurrentPos;
    784   UINT32          LabelPos;
    785   UINT32          NewEntryPos;
    786   UINT16          EntryCount;
    787   FAT_DIRENT      LabelDirEnt;
    788 
    789   LabelPos = 0;
    790   if (OFile->Parent == NULL) {
    791     Status = FatSeekVolumeId (OFile, &LabelDirEnt);
    792     if (EFI_ERROR (Status)) {
    793       return Status;
    794     }
    795 
    796     if (!LabelDirEnt.Invalid) {
    797       LabelPos = LabelDirEnt.EntryPos;
    798     }
    799   }
    800 
    801   EntryCount  = DirEnt->EntryCount;
    802   NewEntryPos = EntryCount;
    803   CurrentPos  = 0;
    804   ODir        = OFile->ODir;
    805   for (CurrentEntry = ODir->ChildList.ForwardLink;
    806        CurrentEntry != &ODir->ChildList;
    807        CurrentEntry = CurrentEntry->ForwardLink
    808       ) {
    809     CurrentDirEnt = DIRENT_FROM_LINK (CurrentEntry);
    810     if (NewEntryPos + CurrentDirEnt->EntryCount <= CurrentDirEnt->EntryPos) {
    811       if (LabelPos > NewEntryPos || LabelPos <= CurrentPos) {
    812         //
    813         // first fit succeeded
    814         //
    815         goto Done;
    816       }
    817     }
    818 
    819     CurrentPos  = CurrentDirEnt->EntryPos;
    820     NewEntryPos = CurrentPos + EntryCount;
    821   }
    822 
    823   if (NewEntryPos >= ODir->CurrentEndPos) {
    824     return EFI_VOLUME_FULL;
    825   }
    826 
    827 Done:
    828   DirEnt->EntryPos   = (UINT16) NewEntryPos;
    829   DirEnt->Link.BackLink = CurrentEntry;
    830   return EFI_SUCCESS;
    831 }
    832 
    833 /**
    834 
    835   Find the new directory entry position for the directory entry.
    836 
    837   @param  OFile                 - The corresponding OFile.
    838   @param  DirEnt                - The directory entry whose new position is to be set.
    839 
    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.
    843 
    844 **/
    845 STATIC
    846 EFI_STATUS
    847 FatNewEntryPos (
    848   IN FAT_OFILE    *OFile,
    849   IN FAT_DIRENT   *DirEnt
    850   )
    851 {
    852   EFI_STATUS  Status;
    853   FAT_ODIR    *ODir;
    854   FAT_DIRENT  *TempDirEnt;
    855   UINT32      NewEndPos;
    856 
    857   ODir = OFile->ODir;
    858   ASSERT (ODir != NULL);
    859   //
    860   // Make sure the whole directory has been loaded
    861   //
    862   while (!ODir->EndOfDir) {
    863     Status = FatLoadNextDirEnt (OFile, &TempDirEnt);
    864     if (EFI_ERROR (Status)) {
    865       return Status;
    866     }
    867   }
    868   //
    869   // We will append this entry to the end of directory
    870   //
    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)) {
    877       //
    878       // We try to use fist fit algorithm to insert this directory entry
    879       //
    880       return FatFirstFitInsertDirEnt (OFile, DirEnt);
    881     }
    882     //
    883     // We should allocate a new cluster for this directory
    884     //
    885     Status = FatExpandODir (OFile);
    886     if (EFI_ERROR (Status)) {
    887       return Status;
    888     }
    889   }
    890   //
    891   // We append our directory entry at the end of directory file
    892   //
    893   ODir->CurrentEndPos = NewEndPos;
    894   DirEnt->EntryPos = (UINT16) (ODir->CurrentEndPos - 1);
    895   return EFI_SUCCESS;
    896 }
    897 
    898 /**
    899 
    900   Get the directory entry for the volume.
    901 
    902   @param  Volume                - FAT file system volume.
    903   @param  Name                  - The file name of the volume.
    904 
    905   @retval EFI_SUCCESS           - Update the volume with the directory entry sucessfully.
    906   @return others                - An error occurred when getting volume label.
    907 
    908 **/
    909 EFI_STATUS
    910 FatGetVolumeEntry (
    911   IN FAT_VOLUME           *Volume,
    912   IN CHAR16               *Name
    913   )
    914 {
    915   EFI_STATUS  Status;
    916   FAT_DIRENT  LabelDirEnt;
    917 
    918   *Name   = 0;
    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);
    923     }
    924   }
    925 
    926   return Status;
    927 }
    928 
    929 /**
    930 
    931   Set the relevant directory entry into disk for the volume.
    932 
    933   @param  Volume              - FAT file system volume.
    934   @param  Name                - The new file name of the volume.
    935 
    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.
    939 
    940 **/
    941 EFI_STATUS
    942 FatSetVolumeEntry (
    943   IN FAT_VOLUME           *Volume,
    944   IN CHAR16               *Name
    945   )
    946 {
    947   EFI_STATUS  Status;
    948   FAT_DIRENT  LabelDirEnt;
    949   FAT_OFILE   *Root;
    950 
    951   Root    = Volume->Root;
    952   Status  = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
    953   if (EFI_ERROR (Status)) {
    954     return Status;
    955   }
    956 
    957   if (LabelDirEnt.Invalid) {
    958     //
    959     // If there is not the relevant directory entry, create a new one
    960     //
    961     ZeroMem (&LabelDirEnt, sizeof (FAT_DIRENT));
    962     LabelDirEnt.EntryCount = 1;
    963     Status                 = FatNewEntryPos (Root, &LabelDirEnt);
    964     if (EFI_ERROR (Status)) {
    965       return Status;
    966     }
    967 
    968     LabelDirEnt.Entry.Attributes = FAT_ATTRIBUTE_VOLUME_ID;
    969   }
    970 
    971   SetMem (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, ' ');
    972   if (FatStrToFat (Name, FAT_NAME_LEN, LabelDirEnt.Entry.FileName)) {
    973     return EFI_UNSUPPORTED;
    974   }
    975 
    976   FatGetCurrentFatTime (&LabelDirEnt.Entry.FileModificationTime);
    977   return FatStoreDirEnt (Root, &LabelDirEnt);
    978 }
    979 
    980 /**
    981 
    982   Create "." and ".." directory entries in the newly-created parent OFile.
    983 
    984   @param  OFile                 - The parent OFile.
    985 
    986   @retval EFI_SUCCESS           - The dot directory entries are successfully created.
    987   @return other                 - An error occurred when creating the directory entry.
    988 
    989 **/
    990 EFI_STATUS
    991 FatCreateDotDirEnts (
    992   IN FAT_OFILE          *OFile
    993   )
    994 {
    995   EFI_STATUS  Status;
    996   FAT_DIRENT  *DirEnt;
    997 
    998   Status = FatExpandODir (OFile);
    999   if (EFI_ERROR (Status)) {
   1000     return Status;
   1001   }
   1002 
   1003   FatSetDirEntCluster (OFile);
   1004   //
   1005   // Create "."
   1006   //
   1007   Status = FatCreateDirEnt (OFile, L".", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
   1008   if (EFI_ERROR (Status)) {
   1009     return Status;
   1010   }
   1011   //
   1012   // Create ".."
   1013   //
   1014   Status = FatCreateDirEnt (OFile, L"..", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
   1015   return Status;
   1016 }
   1017 
   1018 /**
   1019 
   1020   Create a directory entry in the parent OFile.
   1021 
   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.
   1026 
   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.
   1030 
   1031 **/
   1032 EFI_STATUS
   1033 FatCreateDirEnt (
   1034   IN  FAT_OFILE         *OFile,
   1035   IN  CHAR16            *FileName,
   1036   IN  UINT8             Attributes,
   1037   OUT FAT_DIRENT        **PtrDirEnt
   1038   )
   1039 {
   1040   FAT_DIRENT  *DirEnt;
   1041   FAT_ODIR    *ODir;
   1042   EFI_STATUS  Status;
   1043 
   1044   ASSERT (OFile != NULL);
   1045   ODir = OFile->ODir;
   1046   ASSERT (ODir != NULL);
   1047   DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
   1048   if (DirEnt == NULL) {
   1049     return EFI_OUT_OF_RESOURCES;
   1050   }
   1051 
   1052   DirEnt->Signature   = FAT_DIRENT_SIGNATURE;
   1053   DirEnt->FileString  = AllocateCopyPool (StrSize (FileName), FileName);
   1054   if (DirEnt->FileString == NULL) {
   1055     Status = EFI_OUT_OF_RESOURCES;
   1056     goto Done;
   1057   }
   1058   //
   1059   // Determine how many directory entries we need
   1060   //
   1061   FatSetEntryCount (OFile, DirEnt);
   1062   //
   1063   // Determine the file's directory entry position
   1064   //
   1065   Status = FatNewEntryPos (OFile, DirEnt);
   1066   if (EFI_ERROR (Status)) {
   1067     goto Done;
   1068   }
   1069 
   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);
   1075 
   1076 Done:
   1077   FatFreeDirEnt (DirEnt);
   1078   return Status;
   1079 }
   1080 
   1081 /**
   1082 
   1083   Remove this directory entry node from the list of directory entries and hash table.
   1084 
   1085   @param  OFile                - The parent OFile.
   1086   @param  DirEnt               - The directory entry to be removed.
   1087 
   1088   @retval EFI_SUCCESS          - The directory entry is successfully removed.
   1089   @return other                - An error occurred when removing the directory entry.
   1090 
   1091 **/
   1092 EFI_STATUS
   1093 FatRemoveDirEnt (
   1094   IN FAT_OFILE    *OFile,
   1095   IN FAT_DIRENT   *DirEnt
   1096   )
   1097 {
   1098   FAT_ODIR  *ODir;
   1099 
   1100   ODir = OFile->ODir;
   1101   if (ODir->CurrentCursor == &DirEnt->Link) {
   1102     //
   1103     // Move the directory cursor to its previous directory entry
   1104     //
   1105     ODir->CurrentCursor = ODir->CurrentCursor->BackLink;
   1106   }
   1107   //
   1108   // Remove from directory entry list
   1109   //
   1110   RemoveEntryList (&DirEnt->Link);
   1111   //
   1112   // Remove from hash table
   1113   //
   1114   FatDeleteFromHashTable (ODir, DirEnt);
   1115   DirEnt->Entry.FileName[0] = DELETE_ENTRY_MARK;
   1116   DirEnt->Invalid           = TRUE;
   1117   return FatStoreDirEnt (OFile, DirEnt);
   1118 }
   1119 
   1120 /**
   1121 
   1122   Open the directory entry to get the OFile.
   1123 
   1124   @param  Parent                - The parent OFile.
   1125   @param  DirEnt                - The directory entry to be opened.
   1126 
   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.
   1130 
   1131 **/
   1132 EFI_STATUS
   1133 FatOpenDirEnt (
   1134   IN FAT_OFILE         *Parent,
   1135   IN FAT_DIRENT        *DirEnt
   1136   )
   1137 {
   1138   FAT_OFILE   *OFile;
   1139   FAT_VOLUME  *Volume;
   1140 
   1141   if (DirEnt->OFile == NULL) {
   1142     //
   1143     // Open the directory entry
   1144     //
   1145     OFile = AllocateZeroPool (sizeof (FAT_OFILE));
   1146     if (OFile == NULL) {
   1147       return EFI_OUT_OF_RESOURCES;
   1148     }
   1149 
   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) {
   1156       //
   1157       // The newly created OFile is not root
   1158       //
   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);
   1163     } else {
   1164       //
   1165       // The newly created OFile is root
   1166       //
   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;
   1172       }
   1173     }
   1174 
   1175     OFile->FileCurrentCluster  = OFile->FileCluster;
   1176     OFile->Volume              = Volume;
   1177     InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);
   1178 
   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);
   1183       } else {
   1184         OFile->FileSize = FatPhysicalDirSize (Volume, OFile->FileCluster);
   1185       }
   1186 
   1187       FatRequestODir (OFile);
   1188       if (OFile->ODir == NULL) {
   1189         return EFI_OUT_OF_RESOURCES;
   1190       }
   1191     }
   1192 
   1193     DirEnt->OFile = OFile;
   1194   }
   1195 
   1196   return EFI_SUCCESS;
   1197 }
   1198 
   1199 /**
   1200 
   1201   Close the directory entry and free the OFile.
   1202 
   1203   @param  DirEnt               - The directory entry to be closed.
   1204 
   1205 **/
   1206 VOID
   1207 FatCloseDirEnt (
   1208   IN FAT_DIRENT        *DirEnt
   1209   )
   1210 {
   1211   FAT_OFILE   *OFile;
   1212   FAT_VOLUME  *Volume;
   1213 
   1214   OFile   = DirEnt->OFile;
   1215   ASSERT (OFile != NULL);
   1216   Volume  = OFile->Volume;
   1217 
   1218   if (OFile->ODir != NULL) {
   1219     FatDiscardODir (OFile);
   1220   }
   1221 
   1222   if (OFile->Parent == NULL) {
   1223     Volume->Root = NULL;
   1224   } else {
   1225     RemoveEntryList (&OFile->ChildLink);
   1226   }
   1227 
   1228   FreePool (OFile);
   1229   DirEnt->OFile = NULL;
   1230   if (DirEnt->Invalid == TRUE) {
   1231     //
   1232     // Free directory entry itself
   1233     //
   1234     FatFreeDirEnt (DirEnt);
   1235   }
   1236 }
   1237 
   1238 /**
   1239 
   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.
   1244 
   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.
   1249 
   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.
   1256 
   1257 **/
   1258 EFI_STATUS
   1259 FatLocateOFile (
   1260   IN OUT FAT_OFILE        **PtrOFile,
   1261   IN     CHAR16           *FileName,
   1262   IN     UINT8            Attributes,
   1263      OUT CHAR16           *NewFileName
   1264   )
   1265 {
   1266   EFI_STATUS  Status;
   1267   FAT_VOLUME  *Volume;
   1268   CHAR16      ComponentName[EFI_PATH_STRING_LENGTH];
   1269   UINTN       FileNameLen;
   1270   BOOLEAN     DirIntended;
   1271   CHAR16      *Next;
   1272   FAT_OFILE   *OFile;
   1273   FAT_DIRENT  *DirEnt;
   1274 
   1275   DirEnt = NULL;
   1276 
   1277   FileNameLen = StrLen (FileName);
   1278   if (FileNameLen == 0) {
   1279     return EFI_INVALID_PARAMETER;
   1280   }
   1281 
   1282   OFile       = *PtrOFile;
   1283   Volume      = OFile->Volume;
   1284 
   1285   DirIntended = FALSE;
   1286   if (FileName[FileNameLen - 1] == PATH_NAME_SEPARATOR) {
   1287     DirIntended = TRUE;
   1288   }
   1289   //
   1290   // If name starts with path name separator, then move to root OFile
   1291   //
   1292   if (*FileName == PATH_NAME_SEPARATOR) {
   1293     OFile = Volume->Root;
   1294     FileName++;
   1295     FileNameLen--;
   1296   }
   1297   //
   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.
   1302   //
   1303   if (2 + OFile->FullPathLen + 1 + FileNameLen + 1 > EFI_PATH_STRING_LENGTH) {
   1304     //
   1305     // Full path length can not surpass 256
   1306     //
   1307     return EFI_INVALID_PARAMETER;
   1308   }
   1309   //
   1310   // Start at current location
   1311   //
   1312   Next = FileName;
   1313   for (;;) {
   1314     //
   1315     // Get the next component name
   1316     //
   1317     FileName = Next;
   1318     Next     = FatGetNextNameComponent (FileName, ComponentName);
   1319 
   1320     //
   1321     // If end of the file name, we're done
   1322     //
   1323     if (ComponentName[0] == 0) {
   1324       if (DirIntended && OFile->ODir == NULL) {
   1325         return EFI_NOT_FOUND;
   1326       }
   1327 
   1328       NewFileName[0] = 0;
   1329       break;
   1330     }
   1331     //
   1332     // If "dot", then current
   1333     //
   1334     if (StrCmp (ComponentName, L".") == 0) {
   1335       continue;
   1336     }
   1337     //
   1338     // If "dot dot", then parent
   1339     //
   1340     if (StrCmp (ComponentName, L"..") == 0) {
   1341       if (OFile->Parent == NULL) {
   1342         return EFI_INVALID_PARAMETER;
   1343       }
   1344       OFile = OFile->Parent;
   1345       continue;
   1346     }
   1347 
   1348     if (!FatFileNameIsValid (ComponentName, NewFileName)) {
   1349       return EFI_INVALID_PARAMETER;
   1350     }
   1351     //
   1352     // We have a component name, try to open it
   1353     //
   1354     if (OFile->ODir == NULL) {
   1355       //
   1356       // This file isn't a directory, can't open it
   1357       //
   1358       return EFI_NOT_FOUND;
   1359     }
   1360     //
   1361     // Search the compName in the directory
   1362     //
   1363     Status = FatSearchODir (OFile, NewFileName, &DirEnt);
   1364     if (EFI_ERROR (Status)) {
   1365       return Status;
   1366     }
   1367 
   1368     if (DirEnt == NULL) {
   1369       //
   1370       // component name is not found in the directory
   1371       //
   1372       if (*Next != 0) {
   1373         return EFI_NOT_FOUND;
   1374       }
   1375 
   1376       if (DirIntended && (Attributes & FAT_ATTRIBUTE_DIRECTORY) == 0) {
   1377         return EFI_INVALID_PARAMETER;
   1378       }
   1379       //
   1380       // It's the last component name - return with the open
   1381       // path and the remaining name
   1382       //
   1383       break;
   1384     }
   1385 
   1386     Status = FatOpenDirEnt (OFile, DirEnt);
   1387     if (EFI_ERROR (Status)) {
   1388       return Status;
   1389     }
   1390 
   1391     OFile = DirEnt->OFile;
   1392   }
   1393 
   1394   *PtrOFile = OFile;
   1395   return EFI_SUCCESS;
   1396 }
   1397 
   1398