Home | History | Annotate | Download | only in FileExplorerLib
      1 /** @file
      2 File explorer related functions.
      3 
      4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials are licensed and made available under
      6 the terms and conditions of the BSD License that accompanies this distribution.
      7 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 
     16 #include "FileExplorer.h"
     17 
     18 EFI_GUID FileExplorerGuid       = EFI_FILE_EXPLORE_FORMSET_GUID;
     19 
     20 ///
     21 /// File system selection menu
     22 ///
     23 MENU_OPTION      mFsOptionMenu = {
     24   MENU_OPTION_SIGNATURE,
     25   {NULL},
     26   0,
     27   FALSE
     28 };
     29 
     30 FILE_EXPLORER_CALLBACK_DATA  gFileExplorerPrivate = {
     31   FILE_EXPLORER_CALLBACK_DATA_SIGNATURE,
     32   NULL,
     33   NULL,
     34   {
     35     LibExtractConfig,
     36     LibRouteConfig,
     37     LibCallback
     38   },
     39   NULL,
     40   &mFsOptionMenu,
     41   0
     42 };
     43 
     44 HII_VENDOR_DEVICE_PATH  *gHiiVendorDevicePath;
     45 
     46 HII_VENDOR_DEVICE_PATH  FeHiiVendorDevicePath = {
     47   {
     48     {
     49       HARDWARE_DEVICE_PATH,
     50       HW_VENDOR_DP,
     51       {
     52         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
     53         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
     54       }
     55     },
     56     //
     57     // Will be replace with gEfiCallerIdGuid in code.
     58     //
     59     { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }
     60   },
     61   {
     62     END_DEVICE_PATH_TYPE,
     63     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     64     {
     65       (UINT8) (END_DEVICE_PATH_LENGTH),
     66       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
     67     }
     68   }
     69 };
     70 
     71 VOID                *mLibStartOpCodeHandle = NULL;
     72 VOID                *mLibEndOpCodeHandle = NULL;
     73 EFI_IFR_GUID_LABEL  *mLibStartLabel = NULL;
     74 EFI_IFR_GUID_LABEL  *mLibEndLabel = NULL;
     75 
     76 /**
     77   This function allows a caller to extract the current configuration for one
     78   or more named elements from the target driver.
     79 
     80 
     81   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
     82   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
     83   @param Progress        On return, points to a character in the Request string.
     84                          Points to the string's null terminator if request was successful.
     85                          Points to the most recent '&' before the first failing name/value
     86                          pair (or the beginning of the string if the failure is in the
     87                          first name/value pair) if the request was not successful.
     88   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
     89                          has all values filled in for the names in the Request string.
     90                          String to be allocated by the called function.
     91 
     92   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
     93   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
     94 
     95 **/
     96 EFI_STATUS
     97 EFIAPI
     98 LibExtractConfig (
     99   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    100   IN  CONST EFI_STRING                       Request,
    101   OUT EFI_STRING                             *Progress,
    102   OUT EFI_STRING                             *Results
    103   )
    104 {
    105   if (Progress == NULL || Results == NULL) {
    106     return EFI_INVALID_PARAMETER;
    107   }
    108 
    109   *Progress = Request;
    110   return EFI_NOT_FOUND;
    111 }
    112 
    113 /**
    114   This function processes the results of changes in configuration.
    115 
    116 
    117   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    118   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
    119   @param Progress        A pointer to a string filled in with the offset of the most
    120                          recent '&' before the first failing name/value pair (or the
    121                          beginning of the string if the failure is in the first
    122                          name/value pair) or the terminating NULL if all was successful.
    123 
    124   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
    125   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
    126 
    127 **/
    128 EFI_STATUS
    129 EFIAPI
    130 LibRouteConfig (
    131   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    132   IN  CONST EFI_STRING                       Configuration,
    133   OUT EFI_STRING                             *Progress
    134   )
    135 {
    136   if (Configuration == NULL || Progress == NULL) {
    137     return EFI_INVALID_PARAMETER;
    138   }
    139 
    140   *Progress = Configuration;
    141   return EFI_NOT_FOUND;
    142 }
    143 
    144 /**
    145   This function processes the results of changes in configuration.
    146   When user select a interactive opcode, this callback will be triggered.
    147   Based on the Question(QuestionId) that triggers the callback, the corresponding
    148   actions is performed. It handles:
    149 
    150   1) Process the axtra action or exit file explorer when user select one file .
    151   2) update of file content if a dir is selected.
    152 
    153   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    154   @param Action          Specifies the type of action taken by the browser.
    155   @param QuestionId      A unique value which is sent to the original exporting driver
    156                          so that it can identify the type of data to expect.
    157   @param Type            The type of value for the question.
    158   @param Value           A pointer to the data being sent to the original exporting driver.
    159   @param ActionRequest   On return, points to the action requested by the callback function.
    160 
    161   @retval  EFI_SUCCESS           The callback successfully handled the action.
    162   @retval  other error           Error occur when parse one directory.
    163 **/
    164 EFI_STATUS
    165 EFIAPI
    166 LibCallback (
    167   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    168   IN  EFI_BROWSER_ACTION                     Action,
    169   IN  EFI_QUESTION_ID                        QuestionId,
    170   IN  UINT8                                  Type,
    171   IN  EFI_IFR_TYPE_VALUE                     *Value,
    172   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
    173   )
    174 {
    175   EFI_STATUS    Status;
    176   BOOLEAN       NeedExit;
    177 
    178   NeedExit = TRUE;
    179 
    180   if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
    181     //
    182     // Do nothing for other UEFI Action. Only do call back when data is changed.
    183     //
    184     return EFI_UNSUPPORTED;
    185   }
    186 
    187   if (Action == EFI_BROWSER_ACTION_CHANGED) {
    188     if ((Value == NULL) || (ActionRequest == NULL)) {
    189       return EFI_INVALID_PARAMETER;
    190     }
    191 
    192     if (QuestionId >= FILE_OPTION_OFFSET) {
    193       LibGetDevicePath(QuestionId);
    194 
    195       //
    196       // Process the extra action.
    197       //
    198       if (gFileExplorerPrivate.ChooseHandler != NULL) {
    199         NeedExit = gFileExplorerPrivate.ChooseHandler (gFileExplorerPrivate.RetDevicePath);
    200       }
    201 
    202       if (NeedExit) {
    203         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
    204       }
    205     }
    206   } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
    207     if (Value == NULL) {
    208       return EFI_INVALID_PARAMETER;
    209     }
    210 
    211     if (QuestionId >= FILE_OPTION_OFFSET) {
    212       Status = LibUpdateFileExplorer (QuestionId);
    213       if (EFI_ERROR (Status)) {
    214         return Status;
    215       }
    216     }
    217   }
    218 
    219   return EFI_SUCCESS;
    220 }
    221 
    222 /**
    223   Create a menu entry by given menu type.
    224 
    225   @retval NULL           If failed to create the menu.
    226   @return the new menu entry.
    227 
    228 **/
    229 MENU_ENTRY *
    230 LibCreateMenuEntry (
    231   VOID
    232   )
    233 {
    234   MENU_ENTRY *MenuEntry;
    235 
    236   //
    237   // Create new menu entry
    238   //
    239   MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY));
    240   if (MenuEntry == NULL) {
    241     return NULL;
    242   }
    243 
    244   MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT));
    245   if (MenuEntry->VariableContext == NULL) {
    246     FreePool (MenuEntry);
    247     return NULL;
    248   }
    249 
    250   MenuEntry->Signature        = MENU_ENTRY_SIGNATURE;
    251   return MenuEntry;
    252 }
    253 
    254 
    255 /**
    256   Get the Menu Entry from the list in Menu Entry List.
    257 
    258   If MenuNumber is great or equal to the number of Menu
    259   Entry in the list, then ASSERT.
    260 
    261   @param MenuOption      The Menu Entry List to read the menu entry.
    262   @param MenuNumber      The index of Menu Entry.
    263 
    264   @return The Menu Entry.
    265 
    266 **/
    267 MENU_ENTRY *
    268 LibGetMenuEntry (
    269   MENU_OPTION         *MenuOption,
    270   UINTN               MenuNumber
    271   )
    272 {
    273   MENU_ENTRY      *NewMenuEntry;
    274   UINTN           Index;
    275   LIST_ENTRY      *List;
    276 
    277   ASSERT (MenuNumber < MenuOption->MenuNumber);
    278 
    279   List = MenuOption->Head.ForwardLink;
    280   for (Index = 0; Index < MenuNumber; Index++) {
    281     List = List->ForwardLink;
    282   }
    283 
    284   NewMenuEntry = CR (List, MENU_ENTRY, Link, MENU_ENTRY_SIGNATURE);
    285 
    286   return NewMenuEntry;
    287 }
    288 
    289 /**
    290   Free up all resource allocated for a BM_MENU_ENTRY.
    291 
    292   @param MenuEntry   A pointer to BM_MENU_ENTRY.
    293 
    294 **/
    295 VOID
    296 LibDestroyMenuEntry (
    297   MENU_ENTRY         *MenuEntry
    298   )
    299 {
    300   FILE_CONTEXT           *FileContext;
    301 
    302   FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
    303 
    304   if (!FileContext->IsRoot) {
    305     FreePool (FileContext->DevicePath);
    306   } else {
    307     if (FileContext->FileHandle != NULL) {
    308       FileContext->FileHandle->Close (FileContext->FileHandle);
    309     }
    310   }
    311 
    312   if (FileContext->FileName != NULL) {
    313     FreePool (FileContext->FileName);
    314   }
    315 
    316   FreePool (FileContext);
    317 
    318   FreePool (MenuEntry->DisplayString);
    319   if (MenuEntry->HelpString != NULL) {
    320     FreePool (MenuEntry->HelpString);
    321   }
    322 
    323   FreePool (MenuEntry);
    324 }
    325 
    326 
    327 /**
    328   Free resources allocated in Allocate Rountine.
    329 
    330   @param FreeMenu        Menu to be freed
    331 **/
    332 VOID
    333 LibFreeMenu (
    334   MENU_OPTION        *FreeMenu
    335   )
    336 {
    337   MENU_ENTRY *MenuEntry;
    338   while (!IsListEmpty (&FreeMenu->Head)) {
    339     MenuEntry = CR (
    340                   FreeMenu->Head.ForwardLink,
    341                   MENU_ENTRY,
    342                   Link,
    343                   MENU_ENTRY_SIGNATURE
    344                   );
    345     RemoveEntryList (&MenuEntry->Link);
    346     LibDestroyMenuEntry (MenuEntry);
    347   }
    348   FreeMenu->MenuNumber = 0;
    349 }
    350 
    351 /**
    352 
    353   Function opens and returns a file handle to the root directory of a volume.
    354 
    355   @param DeviceHandle    A handle for a device
    356 
    357   @return A valid file handle or NULL is returned
    358 
    359 **/
    360 EFI_FILE_HANDLE
    361 LibOpenRoot (
    362   IN EFI_HANDLE                   DeviceHandle
    363   )
    364 {
    365   EFI_STATUS                      Status;
    366   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
    367   EFI_FILE_HANDLE                 File;
    368 
    369   File = NULL;
    370 
    371   //
    372   // File the file system interface to the device
    373   //
    374   Status = gBS->HandleProtocol (
    375                   DeviceHandle,
    376                   &gEfiSimpleFileSystemProtocolGuid,
    377                   (VOID *) &Volume
    378                   );
    379 
    380   //
    381   // Open the root directory of the volume
    382   //
    383   if (!EFI_ERROR (Status)) {
    384     Status = Volume->OpenVolume (
    385                       Volume,
    386                       &File
    387                       );
    388   }
    389   //
    390   // Done
    391   //
    392   return EFI_ERROR (Status) ? NULL : File;
    393 }
    394 
    395 /**
    396   This function converts an input device structure to a Unicode string.
    397 
    398   @param DevPath                  A pointer to the device path structure.
    399 
    400   @return A new allocated Unicode string that represents the device path.
    401 
    402 **/
    403 CHAR16 *
    404 LibDevicePathToStr (
    405   IN EFI_DEVICE_PATH_PROTOCOL     *DevPath
    406   )
    407 {
    408   EFI_STATUS                       Status;
    409   CHAR16                           *ToText;
    410   EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
    411 
    412   if (DevPath == NULL) {
    413     return NULL;
    414   }
    415 
    416   Status = gBS->LocateProtocol (
    417                   &gEfiDevicePathToTextProtocolGuid,
    418                   NULL,
    419                   (VOID **) &DevPathToText
    420                   );
    421   ASSERT_EFI_ERROR (Status);
    422   ToText = DevPathToText->ConvertDevicePathToText (
    423                             DevPath,
    424                             FALSE,
    425                             TRUE
    426                             );
    427   ASSERT (ToText != NULL);
    428 
    429   return ToText;
    430 }
    431 
    432 /**
    433   Duplicate a string.
    434 
    435   @param Src             The source.
    436 
    437   @return A new string which is duplicated copy of the source.
    438   @retval NULL If there is not enough memory.
    439 
    440 **/
    441 CHAR16 *
    442 LibStrDuplicate (
    443   IN CHAR16   *Src
    444   )
    445 {
    446   CHAR16  *Dest;
    447   UINTN   Size;
    448 
    449   Size  = StrSize (Src);
    450   Dest  = AllocateZeroPool (Size);
    451   ASSERT (Dest != NULL);
    452   if (Dest != NULL) {
    453     CopyMem (Dest, Src, Size);
    454   }
    455 
    456   return Dest;
    457 }
    458 
    459 /**
    460 
    461   Function gets the file information from an open file descriptor, and stores it
    462   in a buffer allocated from pool.
    463 
    464   @param FHand           File Handle.
    465   @param InfoType        Info type need to get.
    466 
    467   @retval                A pointer to a buffer with file information or NULL is returned
    468 
    469 **/
    470 VOID *
    471 LibFileInfo (
    472   IN EFI_FILE_HANDLE      FHand,
    473   IN EFI_GUID             *InfoType
    474   )
    475 {
    476   EFI_STATUS    Status;
    477   EFI_FILE_INFO *Buffer;
    478   UINTN         BufferSize;
    479 
    480   Buffer      = NULL;
    481   BufferSize  = 0;
    482 
    483   Status = FHand->GetInfo (
    484                     FHand,
    485                     InfoType,
    486                     &BufferSize,
    487                     Buffer
    488                     );
    489   if (Status == EFI_BUFFER_TOO_SMALL) {
    490     Buffer = AllocatePool (BufferSize);
    491     ASSERT (Buffer != NULL);
    492   }
    493 
    494   Status = FHand->GetInfo (
    495                     FHand,
    496                     InfoType,
    497                     &BufferSize,
    498                     Buffer
    499                     );
    500 
    501   return Buffer;
    502 }
    503 
    504 /**
    505 
    506   Get file type base on the file name.
    507   Just cut the file name, from the ".". eg ".efi"
    508 
    509   @param FileName  File need to be checked.
    510 
    511   @retval the file type string.
    512 
    513 **/
    514 CHAR16*
    515 LibGetTypeFromName (
    516   IN CHAR16   *FileName
    517   )
    518 {
    519   UINTN    Index;
    520 
    521   Index = StrLen (FileName) - 1;
    522   while ((FileName[Index] != L'.') && (Index != 0)) {
    523     Index--;
    524   }
    525 
    526   return Index == 0 ? NULL : &FileName[Index];
    527 }
    528 
    529 /**
    530   Converts the unicode character of the string from uppercase to lowercase.
    531   This is a internal function.
    532 
    533   @param ConfigString  String to be converted
    534 
    535 **/
    536 VOID
    537 LibToLowerString (
    538   IN CHAR16  *String
    539   )
    540 {
    541   CHAR16      *TmpStr;
    542 
    543   for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) {
    544     if (*TmpStr >= L'A' && *TmpStr <= L'Z') {
    545       *TmpStr = (CHAR16) (*TmpStr - L'A' + L'a');
    546     }
    547   }
    548 }
    549 
    550 /**
    551 
    552   Check whether current FileName point to a valid
    553   Efi Image File.
    554 
    555   @param FileName  File need to be checked.
    556 
    557   @retval TRUE  Is Efi Image
    558   @retval FALSE Not a valid Efi Image
    559 
    560 **/
    561 BOOLEAN
    562 LibIsSupportedFileType (
    563   IN UINT16  *FileName
    564   )
    565 {
    566   CHAR16     *InputFileType;
    567   CHAR16     *TmpStr;
    568   BOOLEAN    IsSupported;
    569 
    570   if (gFileExplorerPrivate.FileType == NULL) {
    571     return TRUE;
    572   }
    573 
    574   InputFileType = LibGetTypeFromName (FileName);
    575   //
    576   // If the file not has *.* style, always return TRUE.
    577   //
    578   if (InputFileType == NULL) {
    579     return TRUE;
    580   }
    581 
    582   TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType);
    583   LibToLowerString(TmpStr);
    584 
    585   IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE);
    586 
    587   FreePool (TmpStr);
    588   return IsSupported;
    589 }
    590 
    591 /**
    592 
    593   Append file name to existing file name.
    594 
    595   @param Str1  The existing file name
    596   @param Str2  The file name to be appended
    597 
    598   @return Allocate a new string to hold the appended result.
    599           Caller is responsible to free the returned string.
    600 
    601 **/
    602 CHAR16 *
    603 LibAppendFileName (
    604   IN  CHAR16  *Str1,
    605   IN  CHAR16  *Str2
    606   )
    607 {
    608   UINTN   Size1;
    609   UINTN   Size2;
    610   UINTN   MaxLen;
    611   CHAR16  *Str;
    612   CHAR16  *TmpStr;
    613   CHAR16  *Ptr;
    614   CHAR16  *LastSlash;
    615 
    616   Size1 = StrSize (Str1);
    617   Size2 = StrSize (Str2);
    618   MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16);
    619   Str   = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
    620   ASSERT (Str != NULL);
    621 
    622   TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
    623   ASSERT (TmpStr != NULL);
    624 
    625   StrCpyS (Str, MaxLen, Str1);
    626   if (!((*Str == '\\') && (*(Str + 1) == 0))) {
    627     StrCatS (Str, MaxLen, L"\\");
    628   }
    629 
    630   StrCatS (Str, MaxLen, Str2);
    631 
    632   Ptr       = Str;
    633   LastSlash = Str;
    634   while (*Ptr != 0) {
    635     if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
    636       //
    637       // Convert "\Name\..\" to "\"
    638       // DO NOT convert the .. if it is at the end of the string. This will
    639       // break the .. behavior in changing directories.
    640       //
    641 
    642       //
    643       // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
    644       // that overlap.
    645       //
    646       StrCpyS (TmpStr, MaxLen, Ptr + 3);
    647       StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr);
    648       Ptr = LastSlash;
    649     } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
    650       //
    651       // Convert a "\.\" to a "\"
    652       //
    653 
    654       //
    655       // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
    656       // that overlap.
    657       //
    658       StrCpyS (TmpStr, MaxLen, Ptr + 2);
    659       StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr);
    660       Ptr = LastSlash;
    661     } else if (*Ptr == '\\') {
    662       LastSlash = Ptr;
    663     }
    664 
    665     Ptr++;
    666   }
    667 
    668   FreePool (TmpStr);
    669 
    670   return Str;
    671 }
    672 
    673 /**
    674   This function build the FsOptionMenu list which records all
    675   available file system in the system. They includes all instances
    676   of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM.
    677 
    678 
    679   @retval  EFI_SUCCESS             Success find the file system
    680   @retval  EFI_OUT_OF_RESOURCES    Can not create menu entry
    681 
    682 **/
    683 EFI_STATUS
    684 LibFindFileSystem (
    685   VOID
    686   )
    687 {
    688   UINTN                        NoSimpleFsHandles;
    689   UINTN                        NoLoadFileHandles;
    690   EFI_HANDLE                   *SimpleFsHandle;
    691   EFI_HANDLE                   *LoadFileHandle;
    692   UINT16                       *VolumeLabel;
    693   UINTN                        Index;
    694   EFI_STATUS                   Status;
    695   MENU_ENTRY                   *MenuEntry;
    696   FILE_CONTEXT                 *FileContext;
    697   UINTN                        OptionNumber;
    698   EFI_FILE_SYSTEM_VOLUME_LABEL *Info;
    699 
    700   NoSimpleFsHandles = 0;
    701   NoLoadFileHandles = 0;
    702   OptionNumber      = 0;
    703 
    704   //
    705   // Locate Handles that support Simple File System protocol
    706   //
    707   Status = gBS->LocateHandleBuffer (
    708                   ByProtocol,
    709                   &gEfiSimpleFileSystemProtocolGuid,
    710                   NULL,
    711                   &NoSimpleFsHandles,
    712                   &SimpleFsHandle
    713                   );
    714   if (!EFI_ERROR (Status)) {
    715     //
    716     // Find all the instances of the File System prototocol
    717     //
    718     for (Index = 0; Index < NoSimpleFsHandles; Index++) {
    719       //
    720       // Allocate pool for this load option
    721       //
    722       MenuEntry = LibCreateMenuEntry ();
    723       if (NULL == MenuEntry) {
    724         FreePool (SimpleFsHandle);
    725         return EFI_OUT_OF_RESOURCES;
    726       }
    727 
    728       FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
    729       FileContext->DeviceHandle = SimpleFsHandle[Index];
    730       FileContext->FileHandle = LibOpenRoot (FileContext->DeviceHandle);
    731       if (FileContext->FileHandle == NULL) {
    732         LibDestroyMenuEntry (MenuEntry);
    733         continue;
    734       }
    735 
    736       MenuEntry->HelpString = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle));
    737       FileContext->FileName = LibStrDuplicate (L"\\");
    738       FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName);
    739       FileContext->IsDir = TRUE;
    740       FileContext->IsRoot = TRUE;
    741 
    742       //
    743       // Get current file system's Volume Label
    744       //
    745       Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid);
    746       if (Info == NULL) {
    747         VolumeLabel = L"NO FILE SYSTEM INFO";
    748       } else {
    749         if (Info->VolumeLabel == NULL) {
    750           VolumeLabel = L"NULL VOLUME LABEL";
    751         } else {
    752           VolumeLabel = Info->VolumeLabel;
    753           if (*VolumeLabel == 0x0000) {
    754             VolumeLabel = L"NO VOLUME LABEL";
    755           }
    756         }
    757       }
    758       MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);
    759       ASSERT (MenuEntry->DisplayString != NULL);
    760       UnicodeSPrint (
    761         MenuEntry->DisplayString,
    762         MAX_CHAR,
    763         L"%s, [%s]",
    764         VolumeLabel,
    765         MenuEntry->HelpString
    766         );
    767   	  MenuEntry->DisplayStringToken = HiiSetString (
    768                                              gFileExplorerPrivate.FeHiiHandle,
    769                                              0,
    770                                              MenuEntry->DisplayString,
    771                                              NULL
    772                                              );
    773       FreePool (Info);
    774 
    775       OptionNumber++;
    776       InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
    777     }
    778   }
    779 
    780   if (NoSimpleFsHandles != 0) {
    781     FreePool (SimpleFsHandle);
    782   }
    783 
    784   //
    785   // Searching for handles that support Load File protocol
    786   //
    787   Status = gBS->LocateHandleBuffer (
    788                   ByProtocol,
    789                   &gEfiLoadFileProtocolGuid,
    790                   NULL,
    791                   &NoLoadFileHandles,
    792                   &LoadFileHandle
    793                   );
    794 
    795   if (!EFI_ERROR (Status)) {
    796     for (Index = 0; Index < NoLoadFileHandles; Index++) {
    797       MenuEntry = LibCreateMenuEntry ();
    798       if (NULL == MenuEntry) {
    799         FreePool (LoadFileHandle);
    800         return EFI_OUT_OF_RESOURCES;
    801       }
    802 
    803       FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
    804       FileContext->DeviceHandle = LoadFileHandle[Index];
    805       FileContext->IsRoot = TRUE;
    806 
    807       FileContext->DevicePath = DevicePathFromHandle (FileContext->DeviceHandle);
    808       FileContext->FileName = LibDevicePathToStr (FileContext->DevicePath);
    809 
    810       MenuEntry->HelpString = LibDevicePathToStr (FileContext->DevicePath);
    811       MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
    812       ASSERT (MenuEntry->DisplayString != NULL);
    813       UnicodeSPrint (
    814         MenuEntry->DisplayString,
    815         MAX_CHAR,
    816         L"Load File [%s]",
    817         MenuEntry->HelpString
    818         );
    819       MenuEntry->DisplayStringToken = HiiSetString (
    820                                            gFileExplorerPrivate.FeHiiHandle,
    821                                            0,
    822                                            MenuEntry->DisplayString,
    823                                            NULL
    824                                            );
    825 
    826       OptionNumber++;
    827       InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
    828     }
    829   }
    830 
    831   if (NoLoadFileHandles != 0) {
    832     FreePool (LoadFileHandle);
    833   }
    834 
    835   gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
    836 
    837   return EFI_SUCCESS;
    838 }
    839 
    840 /**
    841   Find the file handle from the input menu info.
    842 
    843   @param  MenuEntry        Input Menu info.
    844   @param  RetFileHandle    Return the file handle for the input device path.
    845 
    846   @retval EFI_SUCESS       Find the file handle success.
    847   @retval Other            Find the file handle failure.
    848 **/
    849 EFI_STATUS
    850 LibGetFileHandleFromMenu (
    851   IN  MENU_ENTRY                *MenuEntry,
    852   OUT EFI_FILE_HANDLE           *RetFileHandle
    853   )
    854 {
    855   EFI_FILE_HANDLE Dir;
    856   EFI_FILE_HANDLE NewDir;
    857   FILE_CONTEXT    *FileContext;
    858   EFI_STATUS      Status;
    859 
    860   FileContext   = (FILE_CONTEXT *) MenuEntry->VariableContext;
    861   Dir           = FileContext->FileHandle;
    862 
    863   //
    864   // Open current directory to get files from it
    865   //
    866   Status = Dir->Open (
    867                   Dir,
    868                   &NewDir,
    869                   FileContext->FileName,
    870                   EFI_FILE_READ_ONLY,
    871                   0
    872                   );
    873   if (EFI_ERROR (Status)) {
    874     return Status;
    875   }
    876 
    877   if (!FileContext->IsRoot) {
    878     Dir->Close (Dir);
    879   }
    880 
    881   *RetFileHandle = NewDir;
    882 
    883   return EFI_SUCCESS;
    884 }
    885 
    886 /**
    887   Find the file handle from the input device path info.
    888 
    889   @param  RootDirectory    Device path info.
    890   @param  RetFileHandle    Return the file handle for the input device path.
    891   @param  ParentFileName   Parent file name.
    892   @param  DeviceHandle     Driver handle for this partition.
    893 
    894   @retval EFI_SUCESS       Find the file handle success.
    895   @retval Other            Find the file handle failure.
    896 **/
    897 EFI_STATUS
    898 LibGetFileHandleFromDevicePath (
    899   IN  EFI_DEVICE_PATH_PROTOCOL  *RootDirectory,
    900   OUT EFI_FILE_HANDLE           *RetFileHandle,
    901   OUT UINT16                    **ParentFileName,
    902   OUT EFI_HANDLE                *DeviceHandle
    903   )
    904 {
    905   EFI_DEVICE_PATH_PROTOCOL          *DevicePathNode;
    906   EFI_DEVICE_PATH_PROTOCOL          *TempDevicePathNode;
    907   EFI_STATUS                        Status;
    908   EFI_HANDLE                        Handle;
    909   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Volume;
    910   EFI_FILE_HANDLE                   FileHandle;
    911   EFI_FILE_HANDLE                   LastHandle;
    912   CHAR16                            *TempPath;
    913 
    914   *ParentFileName = NULL;
    915 
    916   //
    917   // Attempt to access the file via a file system interface
    918   //
    919   DevicePathNode = RootDirectory;
    920   Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
    921   if (EFI_ERROR (Status)) {
    922     return Status;
    923   }
    924 
    925   Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);
    926   if (EFI_ERROR (Status)) {
    927     return Status;
    928   }
    929 
    930   //
    931   // Open the Volume to get the File System handle
    932   //
    933   Status = Volume->OpenVolume (Volume, &FileHandle);
    934   if (EFI_ERROR (Status)) {
    935     return Status;
    936   }
    937 
    938   *DeviceHandle = Handle;
    939 
    940   if (IsDevicePathEnd(DevicePathNode)) {
    941     *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\");
    942     *RetFileHandle = FileHandle;
    943     return EFI_SUCCESS;
    944   }
    945 
    946   //
    947   // Duplicate the device path to avoid the access to unaligned device path node.
    948   // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
    949   // nodes, It assures the fields in device path nodes are 2 byte aligned.
    950   //
    951   TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
    952   if (TempDevicePathNode == NULL) {
    953 
    954     //
    955     // Setting Status to an EFI_ERROR value will cause the rest of
    956     // the file system support below to be skipped.
    957     //
    958     Status = EFI_OUT_OF_RESOURCES;
    959   }
    960 
    961   //
    962   // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
    963   // directory information and filename can be seperate. The goal is to inch
    964   // our way down each device path node and close the previous node
    965   //
    966   DevicePathNode = TempDevicePathNode;
    967   while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) {
    968     if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||
    969         DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {
    970       Status = EFI_UNSUPPORTED;
    971       goto Done;
    972     }
    973 
    974     LastHandle = FileHandle;
    975     FileHandle = NULL;
    976 
    977     Status = LastHandle->Open (
    978                           LastHandle,
    979                           &FileHandle,
    980                           ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,
    981                           EFI_FILE_MODE_READ,
    982                           0
    983                           );
    984     if (*ParentFileName == NULL) {
    985       *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
    986     } else {
    987       TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
    988       FreePool (*ParentFileName);
    989       *ParentFileName = TempPath;
    990     }
    991 
    992     //
    993     // Close the previous node
    994     //
    995     LastHandle->Close (LastHandle);
    996 
    997     DevicePathNode = NextDevicePathNode (DevicePathNode);
    998   }
    999 
   1000   if (EFI_ERROR (Status)) {
   1001     goto Done;
   1002   }
   1003 
   1004   *RetFileHandle = FileHandle;
   1005 
   1006   Status = EFI_SUCCESS;
   1007 
   1008 Done:
   1009   if (TempDevicePathNode != NULL) {
   1010     FreePool (TempDevicePathNode);
   1011   }
   1012 
   1013   if ((FileHandle != NULL) && (EFI_ERROR (Status))) {
   1014     FileHandle->Close (FileHandle);
   1015   }
   1016 
   1017   return Status;
   1018 }
   1019 
   1020 /**
   1021   Find files under current directory.
   1022 
   1023   All files and sub-directories in current directory
   1024   will be stored in DirectoryMenu for future use.
   1025 
   1026   @param FileHandle    Parent file handle.
   1027   @param FileName      Parent file name.
   1028   @param DeviceHandle  Driver handle for this partition.
   1029 
   1030   @retval EFI_SUCCESS         Get files from current dir successfully.
   1031   @return Other value if can't get files from current dir.
   1032 
   1033 **/
   1034 EFI_STATUS
   1035 LibFindFiles (
   1036   IN EFI_FILE_HANDLE           FileHandle,
   1037   IN UINT16                    *FileName,
   1038   IN EFI_HANDLE                DeviceHandle
   1039   )
   1040 {
   1041   EFI_FILE_INFO   *DirInfo;
   1042   UINTN           BufferSize;
   1043   UINTN           DirBufferSize;
   1044   MENU_ENTRY      *NewMenuEntry;
   1045   FILE_CONTEXT    *NewFileContext;
   1046   UINTN           Pass;
   1047   EFI_STATUS      Status;
   1048   UINTN           OptionNumber;
   1049 
   1050   OptionNumber = 0;
   1051 
   1052   DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
   1053   DirInfo       = AllocateZeroPool (DirBufferSize);
   1054   if (DirInfo == NULL) {
   1055     return EFI_OUT_OF_RESOURCES;
   1056   }
   1057 
   1058   //
   1059   // Get all files in current directory
   1060   // Pass 1 to get Directories
   1061   // Pass 2 to get files that are EFI images
   1062   //
   1063   for (Pass = 1; Pass <= 2; Pass++) {
   1064     FileHandle->SetPosition (FileHandle, 0);
   1065     for (;;) {
   1066       BufferSize  = DirBufferSize;
   1067       Status      = FileHandle->Read (FileHandle, &BufferSize, DirInfo);
   1068       if (EFI_ERROR (Status) || BufferSize == 0) {
   1069         break;
   1070       }
   1071 
   1072       if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
   1073           ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
   1074           ) {
   1075         //
   1076         // Pass 1 is for Directories
   1077         // Pass 2 is for file names
   1078         //
   1079         continue;
   1080       }
   1081 
   1082       if (!((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 || LibIsSupportedFileType (DirInfo->FileName))) {
   1083         //
   1084         // Slip file unless it is a directory entry or a .EFI file
   1085         //
   1086         continue;
   1087       }
   1088 
   1089       NewMenuEntry = LibCreateMenuEntry ();
   1090       if (NULL == NewMenuEntry) {
   1091         return EFI_OUT_OF_RESOURCES;
   1092       }
   1093 
   1094       NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
   1095       NewFileContext->DeviceHandle = DeviceHandle;
   1096       NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName);
   1097       NewFileContext->FileHandle = FileHandle;
   1098       NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName);
   1099       NewMenuEntry->HelpString = NULL;
   1100       NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
   1101 
   1102       if (NewFileContext->IsDir) {
   1103         BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
   1104         NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
   1105         UnicodeSPrint (
   1106           NewMenuEntry->DisplayString,
   1107           BufferSize,
   1108           L"<%s>",
   1109           DirInfo->FileName
   1110           );
   1111       } else {
   1112         NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName);
   1113       }
   1114 
   1115       NewMenuEntry->DisplayStringToken = HiiSetString (
   1116                                            gFileExplorerPrivate.FeHiiHandle,
   1117                                            0,
   1118                                            NewMenuEntry->DisplayString,
   1119                                            NULL
   1120                                            );
   1121 
   1122       NewFileContext->IsRoot            = FALSE;
   1123 
   1124       OptionNumber++;
   1125       InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link);
   1126     }
   1127   }
   1128 
   1129   gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
   1130 
   1131   FreePool (DirInfo);
   1132 
   1133   return EFI_SUCCESS;
   1134 }
   1135 
   1136 /**
   1137   Refresh the global UpdateData structure.
   1138 
   1139 **/
   1140 VOID
   1141 LibRefreshUpdateData (
   1142   VOID
   1143   )
   1144 {
   1145   //
   1146   // Free current updated date
   1147   //
   1148   if (mLibStartOpCodeHandle != NULL) {
   1149     HiiFreeOpCodeHandle (mLibStartOpCodeHandle);
   1150   }
   1151   if (mLibEndOpCodeHandle != NULL) {
   1152     HiiFreeOpCodeHandle (mLibEndOpCodeHandle);
   1153   }
   1154 
   1155   //
   1156   // Create new OpCode Handle
   1157   //
   1158   mLibStartOpCodeHandle = HiiAllocateOpCodeHandle ();
   1159   mLibEndOpCodeHandle = HiiAllocateOpCodeHandle ();
   1160 
   1161   //
   1162   // Create Hii Extend Label OpCode as the start opcode
   1163   //
   1164   mLibStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
   1165                                          mLibStartOpCodeHandle,
   1166                                          &gEfiIfrTianoGuid,
   1167                                          NULL,
   1168                                          sizeof (EFI_IFR_GUID_LABEL)
   1169                                          );
   1170   mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
   1171 
   1172   mLibStartLabel->Number = FORM_FILE_EXPLORER_ID;
   1173 
   1174   //
   1175   // Create Hii Extend Label OpCode as the start opcode
   1176   //
   1177   mLibEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
   1178                                          mLibEndOpCodeHandle,
   1179                                          &gEfiIfrTianoGuid,
   1180                                          NULL,
   1181                                          sizeof (EFI_IFR_GUID_LABEL)
   1182                                          );
   1183   mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
   1184 
   1185   mLibEndLabel->Number = LABEL_END;
   1186 }
   1187 
   1188 /**
   1189 
   1190   Update the File Explore page.
   1191 
   1192 **/
   1193 VOID
   1194 LibUpdateFileExplorePage (
   1195   VOID
   1196   )
   1197 {
   1198   UINTN           Index;
   1199   MENU_ENTRY      *NewMenuEntry;
   1200   FILE_CONTEXT    *NewFileContext;
   1201   MENU_OPTION     *MenuOption;
   1202 
   1203   NewMenuEntry    = NULL;
   1204   NewFileContext  = NULL;
   1205 
   1206   LibRefreshUpdateData ();
   1207   MenuOption = gFileExplorerPrivate.FsOptionMenu;
   1208 
   1209   for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
   1210     NewMenuEntry    = LibGetMenuEntry (MenuOption, Index);
   1211     NewFileContext  = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
   1212 
   1213     if (!NewFileContext->IsDir) {
   1214       //
   1215       // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
   1216       //
   1217       HiiCreateActionOpCode (
   1218         mLibStartOpCodeHandle,
   1219         (UINT16) (FILE_OPTION_OFFSET + Index),
   1220         NewMenuEntry->DisplayStringToken,
   1221         STRING_TOKEN (STR_NULL_STRING),
   1222         EFI_IFR_FLAG_CALLBACK,
   1223         0
   1224         );
   1225     } else {
   1226       //
   1227       // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
   1228       //
   1229       HiiCreateGotoOpCode (
   1230         mLibStartOpCodeHandle,
   1231         FORM_FILE_EXPLORER_ID,
   1232         NewMenuEntry->DisplayStringToken,
   1233         STRING_TOKEN (STR_NULL_STRING),
   1234         EFI_IFR_FLAG_CALLBACK,
   1235         (UINT16) (FILE_OPTION_OFFSET + Index)
   1236         );
   1237     }
   1238   }
   1239 
   1240   HiiUpdateForm (
   1241     gFileExplorerPrivate.FeHiiHandle,
   1242     &FileExplorerGuid,
   1243     FORM_FILE_EXPLORER_ID,
   1244     mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
   1245     mLibEndOpCodeHandle    // LABEL_END
   1246     );
   1247 }
   1248 
   1249 /**
   1250   Update the file explower page with the refershed file system.
   1251 
   1252   @param KeyValue        Key value to identify the type of data to expect.
   1253 
   1254   @retval  EFI_SUCCESS   Update the file explorer form success.
   1255   @retval  other errors  Error occur when parse one directory.
   1256 
   1257 **/
   1258 EFI_STATUS
   1259 LibUpdateFileExplorer (
   1260   IN UINT16                       KeyValue
   1261   )
   1262 {
   1263   UINT16          FileOptionMask;
   1264   MENU_ENTRY      *NewMenuEntry;
   1265   FILE_CONTEXT    *NewFileContext;
   1266   EFI_STATUS      Status;
   1267   EFI_FILE_HANDLE FileHandle;
   1268 
   1269   Status = EFI_SUCCESS;
   1270   FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
   1271   NewMenuEntry   = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
   1272   NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
   1273 
   1274   if (NewFileContext->IsDir) {
   1275     RemoveEntryList (&NewMenuEntry->Link);
   1276     LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
   1277     LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle);
   1278     Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle);
   1279     if (!EFI_ERROR (Status)) {
   1280       LibUpdateFileExplorePage ();
   1281     } else {
   1282       LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
   1283     }
   1284     LibDestroyMenuEntry (NewMenuEntry);
   1285   }
   1286 
   1287   return Status;
   1288 }
   1289 
   1290 /**
   1291   Get the device path info saved in the menu structure.
   1292 
   1293   @param KeyValue        Key value to identify the type of data to expect.
   1294 
   1295 **/
   1296 VOID
   1297 LibGetDevicePath (
   1298   IN UINT16                       KeyValue
   1299   )
   1300 {
   1301   UINT16          FileOptionMask;
   1302   MENU_ENTRY      *NewMenuEntry;
   1303   FILE_CONTEXT    *NewFileContext;
   1304 
   1305   FileOptionMask    = (UINT16) (FILE_OPTION_MASK & KeyValue);
   1306 
   1307   NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
   1308 
   1309   NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
   1310 
   1311   if (gFileExplorerPrivate.RetDevicePath != NULL) {
   1312     FreePool (gFileExplorerPrivate.RetDevicePath);
   1313   }
   1314   gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath);
   1315 }
   1316 
   1317 /**
   1318   Choose a file in the specified directory.
   1319 
   1320   If user input NULL for the RootDirectory, will choose file in the system.
   1321 
   1322   If user input *File != NULL, function will return the allocate device path
   1323   info for the choosed file, caller has to free the memory after use it.
   1324 
   1325   @param  RootDirectory    Pointer to the root directory.
   1326   @param  FileType         The file type need to choose.
   1327   @param  ChooseHandler    Function pointer to the extra task need to do
   1328                            after choose one file.
   1329   @param  File             Return the device path for the last time chosed file.
   1330 
   1331   @retval EFI_SUCESS             Choose file success.
   1332   @retval EFI_INVALID_PARAMETER  Both ChooseHandler and return device path are NULL
   1333                                  One of them must not NULL.
   1334   @retval Other errors           Choose file failed.
   1335 **/
   1336 EFI_STATUS
   1337 EFIAPI
   1338 ChooseFile (
   1339   IN  EFI_DEVICE_PATH_PROTOCOL  *RootDirectory,
   1340   IN  CHAR16                    *FileType,  OPTIONAL
   1341   IN  CHOOSE_HANDLER            ChooseHandler,  OPTIONAL
   1342   OUT EFI_DEVICE_PATH_PROTOCOL  **File  OPTIONAL
   1343   )
   1344 {
   1345   EFI_FILE_HANDLE                   FileHandle;
   1346   EFI_STATUS                        Status;
   1347   UINT16                            *FileName;
   1348   EFI_HANDLE                        DeviceHandle;
   1349 
   1350   if ((ChooseHandler == NULL) && (File == NULL)) {
   1351     return EFI_INVALID_PARAMETER;
   1352   }
   1353 
   1354   FileName = NULL;
   1355 
   1356   gFileExplorerPrivate.RetDevicePath = NULL;
   1357   gFileExplorerPrivate.ChooseHandler = ChooseHandler;
   1358   if (FileType != NULL) {
   1359     gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType);
   1360     LibToLowerString(gFileExplorerPrivate.FileType);
   1361   } else {
   1362     gFileExplorerPrivate.FileType = NULL;
   1363   }
   1364 
   1365   if (RootDirectory == NULL) {
   1366     Status = LibFindFileSystem();
   1367   } else {
   1368     Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle);
   1369     if (EFI_ERROR (Status)) {
   1370       goto Done;
   1371     }
   1372 
   1373     Status = LibFindFiles (FileHandle, FileName, DeviceHandle);
   1374   }
   1375   if (EFI_ERROR (Status)) {
   1376     goto Done;
   1377   }
   1378 
   1379   LibUpdateFileExplorePage();
   1380 
   1381   gFileExplorerPrivate.FormBrowser2->SendForm (
   1382                          gFileExplorerPrivate.FormBrowser2,
   1383                          &gFileExplorerPrivate.FeHiiHandle,
   1384                          1,
   1385                          &FileExplorerGuid,
   1386                          0,
   1387                          NULL,
   1388                          NULL
   1389                          );
   1390 
   1391 Done:
   1392   if ((Status == EFI_SUCCESS) && (File != NULL)) {
   1393     *File  = gFileExplorerPrivate.RetDevicePath;
   1394   } else if (gFileExplorerPrivate.RetDevicePath != NULL) {
   1395     FreePool (gFileExplorerPrivate.RetDevicePath);
   1396   }
   1397 
   1398   if (gFileExplorerPrivate.FileType != NULL) {
   1399     FreePool (gFileExplorerPrivate.FileType);
   1400   }
   1401 
   1402   LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
   1403 
   1404   if (FileName != NULL) {
   1405     FreePool (FileName);
   1406   }
   1407 
   1408   return Status;
   1409 }
   1410 
   1411 /**
   1412 
   1413   Install Boot Manager Menu driver.
   1414 
   1415   @param ImageHandle     The image handle.
   1416   @param SystemTable     The system table.
   1417 
   1418   @retval  EFI_SUCEESS  Install File explorer library success.
   1419 
   1420 **/
   1421 EFI_STATUS
   1422 EFIAPI
   1423 FileExplorerLibConstructor (
   1424   IN EFI_HANDLE                            ImageHandle,
   1425   IN EFI_SYSTEM_TABLE                      *SystemTable
   1426   )
   1427 {
   1428   EFI_STATUS                     Status;
   1429 
   1430   gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath);
   1431   ASSERT (gHiiVendorDevicePath != NULL);
   1432   CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid);
   1433 
   1434   //
   1435   // Install Device Path Protocol and Config Access protocol to driver handle
   1436   //
   1437   Status = gBS->InstallMultipleProtocolInterfaces (
   1438                   &gFileExplorerPrivate.FeDriverHandle,
   1439                   &gEfiDevicePathProtocolGuid,
   1440                   gHiiVendorDevicePath,
   1441                   &gEfiHiiConfigAccessProtocolGuid,
   1442                   &gFileExplorerPrivate.FeConfigAccess,
   1443                   NULL
   1444                   );
   1445   if (Status == EFI_ALREADY_STARTED) {
   1446     return EFI_SUCCESS;
   1447   }
   1448   if (EFI_ERROR (Status)) {
   1449     return Status;
   1450   }
   1451 
   1452   //
   1453   // Post our File Explorer VFR binary to the HII database.
   1454   //
   1455   gFileExplorerPrivate.FeHiiHandle = HiiAddPackages (
   1456                                    &FileExplorerGuid,
   1457                                    gFileExplorerPrivate.FeDriverHandle,
   1458                                    FileExplorerVfrBin,
   1459                                    FileExplorerLibStrings,
   1460                                    NULL
   1461                                    );
   1462   ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL);
   1463 
   1464   //
   1465   // Locate Formbrowser2 protocol
   1466   //
   1467   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFileExplorerPrivate.FormBrowser2);
   1468   ASSERT_EFI_ERROR (Status);
   1469 
   1470   InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head);
   1471 
   1472   return EFI_SUCCESS;
   1473 }
   1474 
   1475 /**
   1476   Unloads the application and its installed protocol.
   1477 
   1478   @param[in]  ImageHandle       Handle that identifies the image to be unloaded.
   1479   @param[in]  SystemTable       The system table.
   1480 
   1481   @retval EFI_SUCCESS           The image has been unloaded.
   1482 **/
   1483 EFI_STATUS
   1484 EFIAPI
   1485 FileExplorerLibDestructor (
   1486   IN EFI_HANDLE                            ImageHandle,
   1487   IN EFI_SYSTEM_TABLE                      *SystemTable
   1488   )
   1489 {
   1490   EFI_STATUS    Status;
   1491 
   1492   ASSERT (gHiiVendorDevicePath != NULL);
   1493 
   1494   if (gFileExplorerPrivate.FeDriverHandle != NULL) {
   1495     Status = gBS->UninstallMultipleProtocolInterfaces (
   1496                     gFileExplorerPrivate.FeDriverHandle,
   1497                     &gEfiDevicePathProtocolGuid,
   1498                     gHiiVendorDevicePath,
   1499                     &gEfiHiiConfigAccessProtocolGuid,
   1500                     &gFileExplorerPrivate.FeConfigAccess,
   1501                     NULL
   1502                     );
   1503     ASSERT_EFI_ERROR (Status);
   1504 
   1505     HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle);
   1506   }
   1507 
   1508   FreePool (gHiiVendorDevicePath);
   1509 
   1510   return EFI_SUCCESS;
   1511 }
   1512 
   1513