Fixes CodeQL alerts for CWE-457: https://cwe.mitre.org/data/definitions/457.html Cc: Dandan Bi <dandan.bi@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Erich McMillan <emcmillan@microsoft.com> Cc: Guomin Jiang <guomin.jiang@intel.com> Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Michael Kubacki <mikuback@linux.microsoft.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Zhichao Gao <zhichao.gao@intel.com> Co-authored-by: Erich McMillan <emcmillan@microsoft.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn> Reviewed-by: Oliver Smith-Denny <osd@smith-denny.com>
		
			
				
	
	
		
			1667 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1667 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| File explorer related functions.
 | |
| 
 | |
| Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "FileExplorer.h"
 | |
| 
 | |
| EFI_GUID  FileExplorerGuid = EFI_FILE_EXPLORE_FORMSET_GUID;
 | |
| 
 | |
| ///
 | |
| /// File system selection menu
 | |
| ///
 | |
| MENU_OPTION  mFsOptionMenu = {
 | |
|   MENU_OPTION_SIGNATURE,
 | |
|   { NULL },
 | |
|   0,
 | |
|   FALSE
 | |
| };
 | |
| 
 | |
| FILE_EXPLORER_CALLBACK_DATA  gFileExplorerPrivate = {
 | |
|   FILE_EXPLORER_CALLBACK_DATA_SIGNATURE,
 | |
|   NULL,
 | |
|   NULL,
 | |
|   {
 | |
|     LibExtractConfig,
 | |
|     LibRouteConfig,
 | |
|     LibCallback
 | |
|   },
 | |
|   NULL,
 | |
|   &mFsOptionMenu,
 | |
|   0
 | |
| };
 | |
| 
 | |
| HII_VENDOR_DEVICE_PATH  *gHiiVendorDevicePath;
 | |
| 
 | |
| HII_VENDOR_DEVICE_PATH  FeHiiVendorDevicePath = {
 | |
|   {
 | |
|     {
 | |
|       HARDWARE_DEVICE_PATH,
 | |
|       HW_VENDOR_DP,
 | |
|       {
 | |
|         (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
 | |
|         (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
 | |
|       }
 | |
|     },
 | |
|     //
 | |
|     // Will be replace with gEfiCallerIdGuid in code.
 | |
|     //
 | |
|     { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
 | |
|     }
 | |
|   },
 | |
|   {
 | |
|     END_DEVICE_PATH_TYPE,
 | |
|     END_ENTIRE_DEVICE_PATH_SUBTYPE,
 | |
|     {
 | |
|       (UINT8)(END_DEVICE_PATH_LENGTH),
 | |
|       (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| VOID                *mLibStartOpCodeHandle = NULL;
 | |
| VOID                *mLibEndOpCodeHandle   = NULL;
 | |
| EFI_IFR_GUID_LABEL  *mLibStartLabel        = NULL;
 | |
| EFI_IFR_GUID_LABEL  *mLibEndLabel          = NULL;
 | |
| UINT16              mQuestionIdUpdate;
 | |
| CHAR16              mNewFileName[MAX_FILE_NAME_LEN];
 | |
| CHAR16              mNewFolderName[MAX_FOLDER_NAME_LEN];
 | |
| UINTN               mNewFileQuestionId   = NEW_FILE_QUESTION_ID_BASE;
 | |
| UINTN               mNewFolderQuestionId = NEW_FOLDER_QUESTION_ID_BASE;
 | |
| 
 | |
| /**
 | |
|   Create a new file or folder in current directory.
 | |
| 
 | |
|   @param FileName              Point to the fileNmae or folder.
 | |
|   @param CreateFile            CreateFile== TRUE  means create a new file.
 | |
|                                CreateFile== FALSE means create a new Folder.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LibCreateNewFile (
 | |
|   IN CHAR16   *FileName,
 | |
|   IN BOOLEAN  CreateFile
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   This function allows a caller to extract the current configuration for one
 | |
|   or more named elements from the target driver.
 | |
| 
 | |
| 
 | |
|   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | |
|   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
 | |
|   @param Progress        On return, points to a character in the Request string.
 | |
|                          Points to the string's null terminator if request was successful.
 | |
|                          Points to the most recent '&' before the first failing name/value
 | |
|                          pair (or the beginning of the string if the failure is in the
 | |
|                          first name/value pair) if the request was not successful.
 | |
|   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
 | |
|                          has all values filled in for the names in the Request string.
 | |
|                          String to be allocated by the called function.
 | |
| 
 | |
|   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
 | |
|   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LibExtractConfig (
 | |
|   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
 | |
|   IN  CONST EFI_STRING                      Request,
 | |
|   OUT EFI_STRING                            *Progress,
 | |
|   OUT EFI_STRING                            *Results
 | |
|   )
 | |
| {
 | |
|   if ((Progress == NULL) || (Results == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *Progress = Request;
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function processes the results of changes in configuration.
 | |
| 
 | |
| 
 | |
|   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | |
|   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
 | |
|   @param Progress        A pointer to a string filled in with the offset of the most
 | |
|                          recent '&' before the first failing name/value pair (or the
 | |
|                          beginning of the string if the failure is in the first
 | |
|                          name/value pair) or the terminating NULL if all was successful.
 | |
| 
 | |
|   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
 | |
|   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LibRouteConfig (
 | |
|   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
 | |
|   IN  CONST EFI_STRING                      Configuration,
 | |
|   OUT EFI_STRING                            *Progress
 | |
|   )
 | |
| {
 | |
|   if ((Configuration == NULL) || (Progress == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *Progress = Configuration;
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function processes the results of changes in configuration.
 | |
|   When user select a interactive opcode, this callback will be triggered.
 | |
|   Based on the Question(QuestionId) that triggers the callback, the corresponding
 | |
|   actions is performed. It handles:
 | |
| 
 | |
|   1) Process the axtra action or exit file explorer when user select one file .
 | |
|   2) update of file content if a dir is selected.
 | |
| 
 | |
|   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | |
|   @param Action          Specifies the type of action taken by the browser.
 | |
|   @param QuestionId      A unique value which is sent to the original exporting driver
 | |
|                          so that it can identify the type of data to expect.
 | |
|   @param Type            The type of value for the question.
 | |
|   @param Value           A pointer to the data being sent to the original exporting driver.
 | |
|   @param ActionRequest   On return, points to the action requested by the callback function.
 | |
| 
 | |
|   @retval  EFI_SUCCESS           The callback successfully handled the action.
 | |
|   @retval  other error           Error occur when parse one directory.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LibCallback (
 | |
|   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
 | |
|   IN  EFI_BROWSER_ACTION                    Action,
 | |
|   IN  EFI_QUESTION_ID                       QuestionId,
 | |
|   IN  UINT8                                 Type,
 | |
|   IN  EFI_IFR_TYPE_VALUE                    *Value,
 | |
|   OUT EFI_BROWSER_ACTION_REQUEST            *ActionRequest
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   BOOLEAN     NeedExit;
 | |
|   CHAR16      *NewFileName;
 | |
|   CHAR16      *NewFolderName;
 | |
| 
 | |
|   NeedExit      = TRUE;
 | |
|   NewFileName   = NULL;
 | |
|   NewFolderName = NULL;
 | |
| 
 | |
|   if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
 | |
|     //
 | |
|     // Do nothing for other UEFI Action. Only do call back when data is changed.
 | |
|     //
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (Action == EFI_BROWSER_ACTION_CHANGED) {
 | |
|     if ((Value == NULL) || (ActionRequest == NULL)) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if (QuestionId == KEY_VALUE_CREATE_FILE_AND_EXIT) {
 | |
|       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
 | |
|       if (!IsZeroBuffer (mNewFileName, sizeof (mNewFileName))) {
 | |
|         Status = LibCreateNewFile (mNewFileName, TRUE);
 | |
|         ZeroMem (mNewFileName, sizeof (mNewFileName));
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (QuestionId == KEY_VALUE_NO_CREATE_FILE_AND_EXIT) {
 | |
|       ZeroMem (mNewFileName, sizeof (mNewFileName));
 | |
|       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
 | |
|     }
 | |
| 
 | |
|     if (QuestionId == KEY_VALUE_CREATE_FOLDER_AND_EXIT) {
 | |
|       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
 | |
|       if (!IsZeroBuffer (mNewFolderName, sizeof (mNewFolderName))) {
 | |
|         Status = LibCreateNewFile (mNewFolderName, FALSE);
 | |
|         ZeroMem (mNewFolderName, sizeof (mNewFolderName));
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (QuestionId == KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT) {
 | |
|       ZeroMem (mNewFolderName, sizeof (mNewFolderName));
 | |
|       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
 | |
|     }
 | |
| 
 | |
|     if (QuestionId == NEW_FILE_NAME_ID) {
 | |
|       NewFileName = HiiGetString (gFileExplorerPrivate.FeHiiHandle, Value->string, NULL);
 | |
|       if (NewFileName != NULL) {
 | |
|         StrCpyS (mNewFileName, MAX_FILE_NAME_LEN, NewFileName);
 | |
|         FreePool (NewFileName);
 | |
|         NewFileName = NULL;
 | |
|       } else {
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (QuestionId == NEW_FOLDER_NAME_ID) {
 | |
|       NewFolderName = HiiGetString (gFileExplorerPrivate.FeHiiHandle, Value->string, NULL);
 | |
|       if (NewFolderName != NULL) {
 | |
|         StrCpyS (mNewFolderName, MAX_FOLDER_NAME_LEN, NewFolderName);
 | |
|         FreePool (NewFolderName);
 | |
|         NewFolderName = NULL;
 | |
|       } else {
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (QuestionId >= FILE_OPTION_OFFSET) {
 | |
|       LibGetDevicePath (QuestionId);
 | |
| 
 | |
|       //
 | |
|       // Process the extra action.
 | |
|       //
 | |
|       if (gFileExplorerPrivate.ChooseHandler != NULL) {
 | |
|         NeedExit = gFileExplorerPrivate.ChooseHandler (gFileExplorerPrivate.RetDevicePath);
 | |
|       }
 | |
| 
 | |
|       if (NeedExit) {
 | |
|         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
 | |
|       }
 | |
|     }
 | |
|   } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
 | |
|     if (Value == NULL) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if (QuestionId >= FILE_OPTION_OFFSET) {
 | |
|       LibGetDevicePath (QuestionId);
 | |
|       Status = LibUpdateFileExplorer (QuestionId);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create a menu entry by given menu type.
 | |
| 
 | |
|   @retval NULL           If failed to create the menu.
 | |
|   @return the new menu entry.
 | |
| 
 | |
| **/
 | |
| MENU_ENTRY *
 | |
| LibCreateMenuEntry (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   MENU_ENTRY  *MenuEntry;
 | |
| 
 | |
|   //
 | |
|   // Create new menu entry
 | |
|   //
 | |
|   MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY));
 | |
|   if (MenuEntry == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT));
 | |
|   if (MenuEntry->VariableContext == NULL) {
 | |
|     FreePool (MenuEntry);
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   MenuEntry->Signature = MENU_ENTRY_SIGNATURE;
 | |
|   return MenuEntry;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the Menu Entry from the list in Menu Entry List.
 | |
| 
 | |
|   If MenuNumber is great or equal to the number of Menu
 | |
|   Entry in the list, then ASSERT.
 | |
| 
 | |
|   @param MenuOption      The Menu Entry List to read the menu entry.
 | |
|   @param MenuNumber      The index of Menu Entry.
 | |
| 
 | |
|   @return The Menu Entry.
 | |
| 
 | |
| **/
 | |
| MENU_ENTRY *
 | |
| LibGetMenuEntry (
 | |
|   MENU_OPTION  *MenuOption,
 | |
|   UINTN        MenuNumber
 | |
|   )
 | |
| {
 | |
|   MENU_ENTRY  *NewMenuEntry;
 | |
|   UINTN       Index;
 | |
|   LIST_ENTRY  *List;
 | |
| 
 | |
|   ASSERT (MenuNumber < MenuOption->MenuNumber);
 | |
| 
 | |
|   List = MenuOption->Head.ForwardLink;
 | |
|   for (Index = 0; Index < MenuNumber; Index++) {
 | |
|     List = List->ForwardLink;
 | |
|   }
 | |
| 
 | |
|   NewMenuEntry = CR (List, MENU_ENTRY, Link, MENU_ENTRY_SIGNATURE);
 | |
| 
 | |
|   return NewMenuEntry;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free up all resource allocated for a BM_MENU_ENTRY.
 | |
| 
 | |
|   @param MenuEntry   A pointer to BM_MENU_ENTRY.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| LibDestroyMenuEntry (
 | |
|   MENU_ENTRY  *MenuEntry
 | |
|   )
 | |
| {
 | |
|   FILE_CONTEXT  *FileContext;
 | |
| 
 | |
|   FileContext = (FILE_CONTEXT *)MenuEntry->VariableContext;
 | |
| 
 | |
|   if (!FileContext->IsRoot) {
 | |
|     if (FileContext->DevicePath != NULL) {
 | |
|       FreePool (FileContext->DevicePath);
 | |
|     }
 | |
|   } else {
 | |
|     if (FileContext->FileHandle != NULL) {
 | |
|       FileContext->FileHandle->Close (FileContext->FileHandle);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (FileContext->FileName != NULL) {
 | |
|     FreePool (FileContext->FileName);
 | |
|   }
 | |
| 
 | |
|   FreePool (FileContext);
 | |
| 
 | |
|   if (MenuEntry->DisplayString != NULL) {
 | |
|     FreePool (MenuEntry->DisplayString);
 | |
|   }
 | |
| 
 | |
|   if (MenuEntry->HelpString != NULL) {
 | |
|     FreePool (MenuEntry->HelpString);
 | |
|   }
 | |
| 
 | |
|   FreePool (MenuEntry);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free resources allocated in Allocate Rountine.
 | |
| 
 | |
|   @param FreeMenu        Menu to be freed
 | |
| **/
 | |
| VOID
 | |
| LibFreeMenu (
 | |
|   MENU_OPTION  *FreeMenu
 | |
|   )
 | |
| {
 | |
|   MENU_ENTRY  *MenuEntry;
 | |
| 
 | |
|   while (!IsListEmpty (&FreeMenu->Head)) {
 | |
|     MenuEntry = CR (
 | |
|                   FreeMenu->Head.ForwardLink,
 | |
|                   MENU_ENTRY,
 | |
|                   Link,
 | |
|                   MENU_ENTRY_SIGNATURE
 | |
|                   );
 | |
|     RemoveEntryList (&MenuEntry->Link);
 | |
|     LibDestroyMenuEntry (MenuEntry);
 | |
|   }
 | |
| 
 | |
|   FreeMenu->MenuNumber = 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Function opens and returns a file handle to the root directory of a volume.
 | |
| 
 | |
|   @param DeviceHandle    A handle for a device
 | |
| 
 | |
|   @return A valid file handle or NULL is returned
 | |
| 
 | |
| **/
 | |
| EFI_FILE_HANDLE
 | |
| LibOpenRoot (
 | |
|   IN EFI_HANDLE  DeviceHandle
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                       Status;
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Volume;
 | |
|   EFI_FILE_HANDLE                  File;
 | |
| 
 | |
|   File = NULL;
 | |
| 
 | |
|   //
 | |
|   // File the file system interface to the device
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   DeviceHandle,
 | |
|                   &gEfiSimpleFileSystemProtocolGuid,
 | |
|                   (VOID *)&Volume
 | |
|                   );
 | |
| 
 | |
|   //
 | |
|   // Open the root directory of the volume
 | |
|   //
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Status = Volume->OpenVolume (
 | |
|                        Volume,
 | |
|                        &File
 | |
|                        );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Done
 | |
|   //
 | |
|   return EFI_ERROR (Status) ? NULL : File;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function converts an input device structure to a Unicode string.
 | |
| 
 | |
|   @param DevPath                  A pointer to the device path structure.
 | |
| 
 | |
|   @return A new allocated Unicode string that represents the device path.
 | |
| 
 | |
| **/
 | |
| CHAR16 *
 | |
| LibDevicePathToStr (
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL  *DevPath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   CHAR16                            *ToText;
 | |
|   EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevPathToText;
 | |
| 
 | |
|   if (DevPath == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiDevicePathToTextProtocolGuid,
 | |
|                   NULL,
 | |
|                   (VOID **)&DevPathToText
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   ToText = DevPathToText->ConvertDevicePathToText (
 | |
|                             DevPath,
 | |
|                             FALSE,
 | |
|                             TRUE
 | |
|                             );
 | |
|   ASSERT (ToText != NULL);
 | |
| 
 | |
|   return ToText;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Duplicate a string.
 | |
| 
 | |
|   @param Src             The source.
 | |
| 
 | |
|   @return A new string which is duplicated copy of the source.
 | |
|   @retval NULL If there is not enough memory.
 | |
| 
 | |
| **/
 | |
| CHAR16 *
 | |
| LibStrDuplicate (
 | |
|   IN CHAR16  *Src
 | |
|   )
 | |
| {
 | |
|   CHAR16  *Dest;
 | |
|   UINTN   Size;
 | |
| 
 | |
|   Size = StrSize (Src);
 | |
|   Dest = AllocateZeroPool (Size);
 | |
|   ASSERT (Dest != NULL);
 | |
|   if (Dest != NULL) {
 | |
|     CopyMem (Dest, Src, Size);
 | |
|   }
 | |
| 
 | |
|   return Dest;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Function gets the file information from an open file descriptor, and stores it
 | |
|   in a buffer allocated from pool.
 | |
| 
 | |
|   @param FHand           File Handle.
 | |
|   @param InfoType        Info type need to get.
 | |
| 
 | |
|   @retval                A pointer to a buffer with file information or NULL is returned
 | |
| 
 | |
| **/
 | |
| VOID *
 | |
| LibFileInfo (
 | |
|   IN EFI_FILE_HANDLE  FHand,
 | |
|   IN EFI_GUID         *InfoType
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS     Status;
 | |
|   EFI_FILE_INFO  *Buffer;
 | |
|   UINTN          BufferSize;
 | |
| 
 | |
|   Buffer     = NULL;
 | |
|   BufferSize = 0;
 | |
| 
 | |
|   Status = FHand->GetInfo (
 | |
|                     FHand,
 | |
|                     InfoType,
 | |
|                     &BufferSize,
 | |
|                     Buffer
 | |
|                     );
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|     Buffer = AllocatePool (BufferSize);
 | |
|     ASSERT (Buffer != NULL);
 | |
|   }
 | |
| 
 | |
|   Status = FHand->GetInfo (
 | |
|                     FHand,
 | |
|                     InfoType,
 | |
|                     &BufferSize,
 | |
|                     Buffer
 | |
|                     );
 | |
| 
 | |
|   return Buffer;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Get file type base on the file name.
 | |
|   Just cut the file name, from the ".". eg ".efi"
 | |
| 
 | |
|   @param FileName  File need to be checked.
 | |
| 
 | |
|   @retval the file type string.
 | |
| 
 | |
| **/
 | |
| CHAR16 *
 | |
| LibGetTypeFromName (
 | |
|   IN CHAR16  *FileName
 | |
|   )
 | |
| {
 | |
|   UINTN  Index;
 | |
| 
 | |
|   Index = StrLen (FileName) - 1;
 | |
|   while ((FileName[Index] != L'.') && (Index != 0)) {
 | |
|     Index--;
 | |
|   }
 | |
| 
 | |
|   return Index == 0 ? NULL : &FileName[Index];
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Converts the unicode character of the string from uppercase to lowercase.
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param ConfigString  String to be converted
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| LibToLowerString (
 | |
|   IN CHAR16  *String
 | |
|   )
 | |
| {
 | |
|   CHAR16  *TmpStr;
 | |
| 
 | |
|   for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) {
 | |
|     if ((*TmpStr >= L'A') && (*TmpStr <= L'Z')) {
 | |
|       *TmpStr = (CHAR16)(*TmpStr - L'A' + L'a');
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Check whether current FileName point to a valid
 | |
|   Efi Image File.
 | |
| 
 | |
|   @param FileName  File need to be checked.
 | |
| 
 | |
|   @retval TRUE  Is Efi Image
 | |
|   @retval FALSE Not a valid Efi Image
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| LibIsSupportedFileType (
 | |
|   IN UINT16  *FileName
 | |
|   )
 | |
| {
 | |
|   CHAR16   *InputFileType;
 | |
|   CHAR16   *TmpStr;
 | |
|   BOOLEAN  IsSupported;
 | |
| 
 | |
|   if (gFileExplorerPrivate.FileType == NULL) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   InputFileType = LibGetTypeFromName (FileName);
 | |
|   //
 | |
|   // If the file not has *.* style, always return TRUE.
 | |
|   //
 | |
|   if (InputFileType == NULL) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType);
 | |
|   ASSERT (TmpStr != NULL);
 | |
|   LibToLowerString (TmpStr);
 | |
| 
 | |
|   IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE);
 | |
| 
 | |
|   FreePool (TmpStr);
 | |
|   return IsSupported;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Append file name to existing file name.
 | |
| 
 | |
|   @param Str1  The existing file name
 | |
|   @param Str2  The file name to be appended
 | |
| 
 | |
|   @return Allocate a new string to hold the appended result.
 | |
|           Caller is responsible to free the returned string.
 | |
| 
 | |
| **/
 | |
| CHAR16 *
 | |
| LibAppendFileName (
 | |
|   IN  CHAR16  *Str1,
 | |
|   IN  CHAR16  *Str2
 | |
|   )
 | |
| {
 | |
|   UINTN   Size1;
 | |
|   UINTN   Size2;
 | |
|   UINTN   MaxLen;
 | |
|   CHAR16  *Str;
 | |
|   CHAR16  *TmpStr;
 | |
|   CHAR16  *Ptr;
 | |
|   CHAR16  *LastSlash;
 | |
| 
 | |
|   Size1 = StrSize (Str1);
 | |
|   Size2 = StrSize (Str2);
 | |
| 
 | |
|   //
 | |
|   // Check overflow
 | |
|   //
 | |
|   if (((MAX_UINTN - Size1) < Size2) || ((MAX_UINTN - Size1 - Size2) < sizeof (CHAR16))) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16);
 | |
|   Str    = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
 | |
|   ASSERT (Str != NULL);
 | |
| 
 | |
|   TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
 | |
|   ASSERT (TmpStr != NULL);
 | |
| 
 | |
|   StrCpyS (Str, MaxLen, Str1);
 | |
|   if (!((*Str == '\\') && (*(Str + 1) == 0))) {
 | |
|     StrCatS (Str, MaxLen, L"\\");
 | |
|   }
 | |
| 
 | |
|   StrCatS (Str, MaxLen, Str2);
 | |
| 
 | |
|   Ptr       = Str;
 | |
|   LastSlash = Str;
 | |
|   while (*Ptr != 0) {
 | |
|     if ((*Ptr == '\\') && (*(Ptr + 1) == '.') && (*(Ptr + 2) == '.') && (*(Ptr + 3) == L'\\')) {
 | |
|       //
 | |
|       // Convert "\Name\..\" to "\"
 | |
|       // DO NOT convert the .. if it is at the end of the string. This will
 | |
|       // break the .. behavior in changing directories.
 | |
|       //
 | |
| 
 | |
|       //
 | |
|       // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
 | |
|       // that overlap.
 | |
|       //
 | |
|       StrCpyS (TmpStr, MaxLen, Ptr + 3);
 | |
|       StrCpyS (LastSlash, MaxLen - ((UINTN)LastSlash - (UINTN)Str) / sizeof (CHAR16), TmpStr);
 | |
|       Ptr = LastSlash;
 | |
|     } else if ((*Ptr == '\\') && (*(Ptr + 1) == '.') && (*(Ptr + 2) == '\\')) {
 | |
|       //
 | |
|       // Convert a "\.\" to a "\"
 | |
|       //
 | |
| 
 | |
|       //
 | |
|       // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
 | |
|       // that overlap.
 | |
|       //
 | |
|       StrCpyS (TmpStr, MaxLen, Ptr + 2);
 | |
|       StrCpyS (Ptr, MaxLen - ((UINTN)Ptr - (UINTN)Str) / sizeof (CHAR16), TmpStr);
 | |
|       Ptr = LastSlash;
 | |
|     } else if (*Ptr == '\\') {
 | |
|       LastSlash = Ptr;
 | |
|     }
 | |
| 
 | |
|     Ptr++;
 | |
|   }
 | |
| 
 | |
|   FreePool (TmpStr);
 | |
| 
 | |
|   return Str;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function build the FsOptionMenu list which records all
 | |
|   available file system in the system. They includes all instances
 | |
|   of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM.
 | |
| 
 | |
| 
 | |
|   @retval  EFI_SUCCESS             Success find the file system
 | |
|   @retval  EFI_OUT_OF_RESOURCES    Can not create menu entry
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LibFindFileSystem (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINTN                         NoSimpleFsHandles;
 | |
|   EFI_HANDLE                    *SimpleFsHandle;
 | |
|   UINT16                        *VolumeLabel;
 | |
|   UINTN                         Index;
 | |
|   EFI_STATUS                    Status;
 | |
|   MENU_ENTRY                    *MenuEntry;
 | |
|   FILE_CONTEXT                  *FileContext;
 | |
|   UINTN                         OptionNumber;
 | |
|   EFI_FILE_SYSTEM_VOLUME_LABEL  *Info;
 | |
| 
 | |
|   NoSimpleFsHandles = 0;
 | |
|   OptionNumber      = 0;
 | |
| 
 | |
|   //
 | |
|   // Locate Handles that support Simple File System protocol
 | |
|   //
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiSimpleFileSystemProtocolGuid,
 | |
|                   NULL,
 | |
|                   &NoSimpleFsHandles,
 | |
|                   &SimpleFsHandle
 | |
|                   );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Find all the instances of the File System prototocol
 | |
|     //
 | |
|     for (Index = 0; Index < NoSimpleFsHandles; Index++) {
 | |
|       //
 | |
|       // Allocate pool for this load option
 | |
|       //
 | |
|       MenuEntry = LibCreateMenuEntry ();
 | |
|       if (NULL == MenuEntry) {
 | |
|         FreePool (SimpleFsHandle);
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       FileContext               = (FILE_CONTEXT *)MenuEntry->VariableContext;
 | |
|       FileContext->DeviceHandle = SimpleFsHandle[Index];
 | |
|       FileContext->FileHandle   = LibOpenRoot (FileContext->DeviceHandle);
 | |
|       if (FileContext->FileHandle == NULL) {
 | |
|         LibDestroyMenuEntry (MenuEntry);
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       MenuEntry->HelpString   = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle));
 | |
|       FileContext->FileName   = LibStrDuplicate (L"\\");
 | |
|       FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName);
 | |
|       FileContext->IsDir      = TRUE;
 | |
|       FileContext->IsRoot     = TRUE;
 | |
| 
 | |
|       //
 | |
|       // Get current file system's Volume Label
 | |
|       //
 | |
|       Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *)LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid);
 | |
|       if (Info == NULL) {
 | |
|         VolumeLabel = L"NO FILE SYSTEM INFO";
 | |
|       } else {
 | |
|         VolumeLabel = Info->VolumeLabel;
 | |
|         if (*VolumeLabel == 0x0000) {
 | |
|           VolumeLabel = L"NO VOLUME LABEL";
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
 | |
|       ASSERT (MenuEntry->DisplayString != NULL);
 | |
|       UnicodeSPrint (
 | |
|         MenuEntry->DisplayString,
 | |
|         MAX_CHAR,
 | |
|         L"%s, [%s]",
 | |
|         VolumeLabel,
 | |
|         MenuEntry->HelpString
 | |
|         );
 | |
|       MenuEntry->DisplayStringToken = HiiSetString (
 | |
|                                         gFileExplorerPrivate.FeHiiHandle,
 | |
|                                         0,
 | |
|                                         MenuEntry->DisplayString,
 | |
|                                         NULL
 | |
|                                         );
 | |
| 
 | |
|       if (Info != NULL) {
 | |
|         FreePool (Info);
 | |
|       }
 | |
| 
 | |
|       OptionNumber++;
 | |
|       InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (NoSimpleFsHandles != 0) {
 | |
|     FreePool (SimpleFsHandle);
 | |
|   }
 | |
| 
 | |
|   gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find the file handle from the input menu info.
 | |
| 
 | |
|   @param  MenuEntry        Input Menu info.
 | |
|   @param  RetFileHandle    Return the file handle for the input device path.
 | |
| 
 | |
|   @retval EFI_SUCESS       Find the file handle success.
 | |
|   @retval Other            Find the file handle failure.
 | |
| **/
 | |
| EFI_STATUS
 | |
| LibGetFileHandleFromMenu (
 | |
|   IN  MENU_ENTRY       *MenuEntry,
 | |
|   OUT EFI_FILE_HANDLE  *RetFileHandle
 | |
|   )
 | |
| {
 | |
|   EFI_FILE_HANDLE  Dir;
 | |
|   EFI_FILE_HANDLE  NewDir;
 | |
|   FILE_CONTEXT     *FileContext;
 | |
|   EFI_STATUS       Status;
 | |
| 
 | |
|   FileContext = (FILE_CONTEXT *)MenuEntry->VariableContext;
 | |
|   Dir         = FileContext->FileHandle;
 | |
| 
 | |
|   //
 | |
|   // Open current directory to get files from it
 | |
|   //
 | |
|   Status = Dir->Open (
 | |
|                   Dir,
 | |
|                   &NewDir,
 | |
|                   FileContext->FileName,
 | |
|                   EFI_FILE_READ_ONLY,
 | |
|                   0
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (!FileContext->IsRoot) {
 | |
|     Dir->Close (Dir);
 | |
|   }
 | |
| 
 | |
|   *RetFileHandle = NewDir;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find the file handle from the input device path info.
 | |
| 
 | |
|   @param  RootDirectory    Device path info.
 | |
|   @param  RetFileHandle    Return the file handle for the input device path.
 | |
|   @param  ParentFileName   Parent file name.
 | |
|   @param  DeviceHandle     Driver handle for this partition.
 | |
| 
 | |
|   @retval EFI_SUCESS       Find the file handle success.
 | |
|   @retval Other            Find the file handle failure.
 | |
| **/
 | |
| EFI_STATUS
 | |
| LibGetFileHandleFromDevicePath (
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL  *RootDirectory,
 | |
|   OUT EFI_FILE_HANDLE           *RetFileHandle,
 | |
|   OUT UINT16                    **ParentFileName,
 | |
|   OUT EFI_HANDLE                *DeviceHandle
 | |
|   )
 | |
| {
 | |
|   EFI_DEVICE_PATH_PROTOCOL         *DevicePathNode;
 | |
|   EFI_DEVICE_PATH_PROTOCOL         *TempDevicePathNode;
 | |
|   EFI_STATUS                       Status;
 | |
|   EFI_HANDLE                       Handle;
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Volume;
 | |
|   EFI_FILE_HANDLE                  FileHandle;
 | |
|   EFI_FILE_HANDLE                  LastHandle;
 | |
|   CHAR16                           *TempPath;
 | |
| 
 | |
|   *ParentFileName = NULL;
 | |
| 
 | |
|   //
 | |
|   // Attempt to access the file via a file system interface
 | |
|   //
 | |
|   DevicePathNode = RootDirectory;
 | |
|   Status         = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Volume);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open the Volume to get the File System handle
 | |
|   //
 | |
|   Status = Volume->OpenVolume (Volume, &FileHandle);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   *DeviceHandle = Handle;
 | |
| 
 | |
|   if (IsDevicePathEnd (DevicePathNode)) {
 | |
|     *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\");
 | |
|     *RetFileHandle  = FileHandle;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Duplicate the device path to avoid the access to unaligned device path node.
 | |
|   // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
 | |
|   // nodes, It assures the fields in device path nodes are 2 byte aligned.
 | |
|   //
 | |
|   TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
 | |
|   if (TempDevicePathNode == NULL) {
 | |
|     //
 | |
|     // Setting Status to an EFI_ERROR value will cause the rest of
 | |
|     // the file system support below to be skipped.
 | |
|     //
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
 | |
|   // directory information and filename can be seperate. The goal is to inch
 | |
|   // our way down each device path node and close the previous node
 | |
|   //
 | |
|   DevicePathNode = TempDevicePathNode;
 | |
|   while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) {
 | |
|     if ((DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH) ||
 | |
|         (DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP))
 | |
|     {
 | |
|       Status = EFI_UNSUPPORTED;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     LastHandle = FileHandle;
 | |
|     FileHandle = NULL;
 | |
| 
 | |
|     Status = LastHandle->Open (
 | |
|                            LastHandle,
 | |
|                            &FileHandle,
 | |
|                            ((FILEPATH_DEVICE_PATH *)DevicePathNode)->PathName,
 | |
|                            EFI_FILE_MODE_READ,
 | |
|                            0
 | |
|                            );
 | |
|     if (*ParentFileName == NULL) {
 | |
|       *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *)DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *)DevicePathNode)->PathName);
 | |
|     } else {
 | |
|       TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *)DevicePathNode)->PathName);
 | |
|       if (TempPath == NULL) {
 | |
|         LastHandle->Close (LastHandle);
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       FreePool (*ParentFileName);
 | |
|       *ParentFileName = TempPath;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Close the previous node
 | |
|     //
 | |
|     LastHandle->Close (LastHandle);
 | |
| 
 | |
|     DevicePathNode = NextDevicePathNode (DevicePathNode);
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   *RetFileHandle = FileHandle;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
| Done:
 | |
|   if (TempDevicePathNode != NULL) {
 | |
|     FreePool (TempDevicePathNode);
 | |
|   }
 | |
| 
 | |
|   if ((FileHandle != NULL) && (EFI_ERROR (Status))) {
 | |
|     FileHandle->Close (FileHandle);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create a new file or folder in current directory.
 | |
| 
 | |
|   @param FileName              Point to the fileNmae or folder name.
 | |
|   @param CreateFile            CreateFile== TRUE  means create a new file.
 | |
|                                CreateFile== FALSE means create a new Folder.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LibCreateNewFile (
 | |
|   IN CHAR16   *FileName,
 | |
|   IN BOOLEAN  CreateFile
 | |
|   )
 | |
| {
 | |
|   EFI_FILE_HANDLE  FileHandle;
 | |
|   EFI_FILE_HANDLE  NewHandle;
 | |
|   EFI_HANDLE       DeviceHandle;
 | |
|   EFI_STATUS       Status;
 | |
|   CHAR16           *ParentName;
 | |
|   CHAR16           *FullFileName;
 | |
| 
 | |
|   NewHandle    = NULL;
 | |
|   FullFileName = NULL;
 | |
| 
 | |
|   if (EFI_ERROR (LibGetFileHandleFromDevicePath (gFileExplorerPrivate.RetDevicePath, &FileHandle, &ParentName, &DeviceHandle))) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   FullFileName = LibAppendFileName (ParentName, FileName);
 | |
|   if (FullFileName == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   if (CreateFile) {
 | |
|     Status = FileHandle->Open (
 | |
|                            FileHandle,
 | |
|                            &NewHandle,
 | |
|                            FullFileName,
 | |
|                            EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
 | |
|                            0
 | |
|                            );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       FileHandle->Close (FileHandle);
 | |
|       return Status;
 | |
|     }
 | |
|   } else {
 | |
|     Status = FileHandle->Open (
 | |
|                            FileHandle,
 | |
|                            &NewHandle,
 | |
|                            FullFileName,
 | |
|                            EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
 | |
|                            EFI_FILE_DIRECTORY
 | |
|                            );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       FileHandle->Close (FileHandle);
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FileHandle->Close (FileHandle);
 | |
| 
 | |
|   //
 | |
|   // Return the DevicePath of the new created file or folder.
 | |
|   //
 | |
|   gFileExplorerPrivate.RetDevicePath = FileDevicePath (DeviceHandle, FullFileName);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find files under current directory.
 | |
| 
 | |
|   All files and sub-directories in current directory
 | |
|   will be stored in DirectoryMenu for future use.
 | |
| 
 | |
|   @param FileHandle    Parent file handle.
 | |
|   @param FileName      Parent file name.
 | |
|   @param DeviceHandle  Driver handle for this partition.
 | |
| 
 | |
|   @retval EFI_SUCCESS         Get files from current dir successfully.
 | |
|   @return Other value if can't get files from current dir.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LibFindFiles (
 | |
|   IN EFI_FILE_HANDLE  FileHandle,
 | |
|   IN UINT16           *FileName,
 | |
|   IN EFI_HANDLE       DeviceHandle
 | |
|   )
 | |
| {
 | |
|   EFI_FILE_INFO  *DirInfo;
 | |
|   UINTN          BufferSize;
 | |
|   UINTN          DirBufferSize;
 | |
|   MENU_ENTRY     *NewMenuEntry;
 | |
|   FILE_CONTEXT   *NewFileContext;
 | |
|   UINTN          Pass;
 | |
|   EFI_STATUS     Status;
 | |
|   UINTN          OptionNumber;
 | |
| 
 | |
|   OptionNumber = 0;
 | |
| 
 | |
|   DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
 | |
|   DirInfo       = AllocateZeroPool (DirBufferSize);
 | |
|   if (DirInfo == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get all files in current directory
 | |
|   // Pass 1 to get Directories
 | |
|   // Pass 2 to get files that are EFI images
 | |
|   //
 | |
|   Status = EFI_SUCCESS;
 | |
|   for (Pass = 1; Pass <= 2; Pass++) {
 | |
|     FileHandle->SetPosition (FileHandle, 0);
 | |
|     for ( ; ;) {
 | |
|       BufferSize = DirBufferSize;
 | |
|       Status     = FileHandle->Read (FileHandle, &BufferSize, DirInfo);
 | |
|       if (EFI_ERROR (Status) || (BufferSize == 0)) {
 | |
|         Status = EFI_SUCCESS;
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       if ((((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0) && (Pass == 2)) ||
 | |
|           (((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) && (Pass == 1))
 | |
|           )
 | |
|       {
 | |
|         //
 | |
|         // Pass 1 is for Directories
 | |
|         // Pass 2 is for file names
 | |
|         //
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       if (!(((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0) || LibIsSupportedFileType (DirInfo->FileName))) {
 | |
|         //
 | |
|         // Slip file unless it is a directory entry or a .EFI file
 | |
|         //
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       NewMenuEntry = LibCreateMenuEntry ();
 | |
|       if (NULL == NewMenuEntry) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       NewFileContext               = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
 | |
|       NewFileContext->DeviceHandle = DeviceHandle;
 | |
|       NewFileContext->FileName     = LibAppendFileName (FileName, DirInfo->FileName);
 | |
|       if (NewFileContext->FileName == NULL) {
 | |
|         LibDestroyMenuEntry (NewMenuEntry);
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       NewFileContext->FileHandle = FileHandle;
 | |
|       NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName);
 | |
|       NewMenuEntry->HelpString   = NULL;
 | |
|       NewFileContext->IsDir      = (BOOLEAN)((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
 | |
| 
 | |
|       if (NewFileContext->IsDir) {
 | |
|         BufferSize                  = StrLen (DirInfo->FileName) * 2 + 6;
 | |
|         NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
 | |
|         UnicodeSPrint (
 | |
|           NewMenuEntry->DisplayString,
 | |
|           BufferSize,
 | |
|           L"<%s>",
 | |
|           DirInfo->FileName
 | |
|           );
 | |
|       } else {
 | |
|         NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName);
 | |
|       }
 | |
| 
 | |
|       NewMenuEntry->DisplayStringToken = HiiSetString (
 | |
|                                            gFileExplorerPrivate.FeHiiHandle,
 | |
|                                            0,
 | |
|                                            NewMenuEntry->DisplayString,
 | |
|                                            NULL
 | |
|                                            );
 | |
| 
 | |
|       NewFileContext->IsRoot = FALSE;
 | |
| 
 | |
|       OptionNumber++;
 | |
|       InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
 | |
| 
 | |
| Done:
 | |
| 
 | |
|   FreePool (DirInfo);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Refresh the global UpdateData structure.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| LibRefreshUpdateData (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Free current updated date
 | |
|   //
 | |
|   if (mLibStartOpCodeHandle != NULL) {
 | |
|     HiiFreeOpCodeHandle (mLibStartOpCodeHandle);
 | |
|   }
 | |
| 
 | |
|   if (mLibEndOpCodeHandle != NULL) {
 | |
|     HiiFreeOpCodeHandle (mLibEndOpCodeHandle);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create new OpCode Handle
 | |
|   //
 | |
|   mLibStartOpCodeHandle = HiiAllocateOpCodeHandle ();
 | |
|   mLibEndOpCodeHandle   = HiiAllocateOpCodeHandle ();
 | |
| 
 | |
|   //
 | |
|   // Create Hii Extend Label OpCode as the start opcode
 | |
|   //
 | |
|   mLibStartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
 | |
|                                            mLibStartOpCodeHandle,
 | |
|                                            &gEfiIfrTianoGuid,
 | |
|                                            NULL,
 | |
|                                            sizeof (EFI_IFR_GUID_LABEL)
 | |
|                                            );
 | |
|   mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
 | |
| 
 | |
|   mLibStartLabel->Number = FORM_FILE_EXPLORER_ID;
 | |
| 
 | |
|   //
 | |
|   // Create Hii Extend Label OpCode as the start opcode
 | |
|   //
 | |
|   mLibEndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
 | |
|                                          mLibEndOpCodeHandle,
 | |
|                                          &gEfiIfrTianoGuid,
 | |
|                                          NULL,
 | |
|                                          sizeof (EFI_IFR_GUID_LABEL)
 | |
|                                          );
 | |
|   mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
 | |
| 
 | |
|   mLibEndLabel->Number = LABEL_END;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Update the File Explore page.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| LibUpdateFileExplorePage (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINTN         Index;
 | |
|   MENU_ENTRY    *NewMenuEntry;
 | |
|   FILE_CONTEXT  *NewFileContext;
 | |
|   MENU_OPTION   *MenuOption;
 | |
|   BOOLEAN       CreateNewFile;
 | |
| 
 | |
|   NewMenuEntry   = NULL;
 | |
|   NewFileContext = NULL;
 | |
|   CreateNewFile  = FALSE;
 | |
| 
 | |
|   LibRefreshUpdateData ();
 | |
|   MenuOption = gFileExplorerPrivate.FsOptionMenu;
 | |
| 
 | |
|   mQuestionIdUpdate += QUESTION_ID_UPDATE_STEP;
 | |
| 
 | |
|   for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
 | |
|     NewMenuEntry   = LibGetMenuEntry (MenuOption, Index);
 | |
|     NewFileContext = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
 | |
| 
 | |
|     if (!NewFileContext->IsRoot && !CreateNewFile) {
 | |
|       HiiCreateGotoOpCode (
 | |
|         mLibStartOpCodeHandle,
 | |
|         FORM_ADD_NEW_FILE_ID,
 | |
|         STRING_TOKEN (STR_NEW_FILE),
 | |
|         STRING_TOKEN (STR_NEW_FILE_HELP),
 | |
|         EFI_IFR_FLAG_CALLBACK,
 | |
|         (UINT16)(mNewFileQuestionId++)
 | |
|         );
 | |
|       HiiCreateGotoOpCode (
 | |
|         mLibStartOpCodeHandle,
 | |
|         FORM_ADD_NEW_FOLDER_ID,
 | |
|         STRING_TOKEN (STR_NEW_FOLDER),
 | |
|         STRING_TOKEN (STR_NEW_FOLDER_HELP),
 | |
|         EFI_IFR_FLAG_CALLBACK,
 | |
|         (UINT16)(mNewFolderQuestionId++)
 | |
|         );
 | |
|       HiiCreateTextOpCode (
 | |
|         mLibStartOpCodeHandle,
 | |
|         STRING_TOKEN (STR_NULL_STRING),
 | |
|         STRING_TOKEN (STR_NULL_STRING),
 | |
|         0
 | |
|         );
 | |
|       CreateNewFile = TRUE;
 | |
|     }
 | |
| 
 | |
|     if (!NewFileContext->IsDir) {
 | |
|       //
 | |
|       // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
 | |
|       //
 | |
|       HiiCreateActionOpCode (
 | |
|         mLibStartOpCodeHandle,
 | |
|         (UINT16)(FILE_OPTION_OFFSET + Index + mQuestionIdUpdate),
 | |
|         NewMenuEntry->DisplayStringToken,
 | |
|         STRING_TOKEN (STR_NULL_STRING),
 | |
|         EFI_IFR_FLAG_CALLBACK,
 | |
|         0
 | |
|         );
 | |
|     } else {
 | |
|       //
 | |
|       // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
 | |
|       //
 | |
|       HiiCreateGotoOpCode (
 | |
|         mLibStartOpCodeHandle,
 | |
|         FORM_FILE_EXPLORER_ID,
 | |
|         NewMenuEntry->DisplayStringToken,
 | |
|         STRING_TOKEN (STR_NULL_STRING),
 | |
|         EFI_IFR_FLAG_CALLBACK,
 | |
|         (UINT16)(FILE_OPTION_OFFSET + Index + mQuestionIdUpdate)
 | |
|         );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   HiiUpdateForm (
 | |
|     gFileExplorerPrivate.FeHiiHandle,
 | |
|     &FileExplorerGuid,
 | |
|     FORM_FILE_EXPLORER_ID,
 | |
|     mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
 | |
|     mLibEndOpCodeHandle    // LABEL_END
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Update the file explower page with the refershed file system.
 | |
| 
 | |
|   @param KeyValue        Key value to identify the type of data to expect.
 | |
| 
 | |
|   @retval  EFI_SUCCESS   Update the file explorer form success.
 | |
|   @retval  other errors  Error occur when parse one directory.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LibUpdateFileExplorer (
 | |
|   IN UINT16  KeyValue
 | |
|   )
 | |
| {
 | |
|   UINT16           FileOptionMask;
 | |
|   MENU_ENTRY       *NewMenuEntry;
 | |
|   FILE_CONTEXT     *NewFileContext;
 | |
|   EFI_STATUS       Status;
 | |
|   EFI_FILE_HANDLE  FileHandle;
 | |
| 
 | |
|   Status         = EFI_SUCCESS;
 | |
|   FileOptionMask = (UINT16)(FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;
 | |
|   NewMenuEntry   = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
 | |
|   NewFileContext = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
 | |
| 
 | |
|   if (NewFileContext->IsDir) {
 | |
|     RemoveEntryList (&NewMenuEntry->Link);
 | |
|     LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
 | |
|     Status = LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle);
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         LibUpdateFileExplorePage ();
 | |
|       } else {
 | |
|         LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     LibDestroyMenuEntry (NewMenuEntry);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the device path info saved in the menu structure.
 | |
| 
 | |
|   @param KeyValue        Key value to identify the type of data to expect.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| LibGetDevicePath (
 | |
|   IN UINT16  KeyValue
 | |
|   )
 | |
| {
 | |
|   UINT16        FileOptionMask;
 | |
|   MENU_ENTRY    *NewMenuEntry;
 | |
|   FILE_CONTEXT  *NewFileContext;
 | |
| 
 | |
|   FileOptionMask = (UINT16)(FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;
 | |
| 
 | |
|   NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
 | |
| 
 | |
|   NewFileContext = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
 | |
| 
 | |
|   if (gFileExplorerPrivate.RetDevicePath != NULL) {
 | |
|     FreePool (gFileExplorerPrivate.RetDevicePath);
 | |
|   }
 | |
| 
 | |
|   gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Choose a file in the specified directory.
 | |
| 
 | |
|   If user input NULL for the RootDirectory, will choose file in the system.
 | |
| 
 | |
|   If user input *File != NULL, function will return the allocate device path
 | |
|   info for the choosed file, caller has to free the memory after use it.
 | |
| 
 | |
|   @param  RootDirectory    Pointer to the root directory.
 | |
|   @param  FileType         The file type need to choose.
 | |
|   @param  ChooseHandler    Function pointer to the extra task need to do
 | |
|                            after choose one file.
 | |
|   @param  File             Return the device path for the last time chosed file.
 | |
| 
 | |
|   @retval EFI_SUCESS             Choose file success.
 | |
|   @retval EFI_INVALID_PARAMETER  Both ChooseHandler and return device path are NULL
 | |
|                                  One of them must not NULL.
 | |
|   @retval Other errors           Choose file failed.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ChooseFile (
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL  *RootDirectory,
 | |
|   IN  CHAR16                    *FileType   OPTIONAL,
 | |
|   IN  CHOOSE_HANDLER            ChooseHandler   OPTIONAL,
 | |
|   OUT EFI_DEVICE_PATH_PROTOCOL  **File  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_FILE_HANDLE  FileHandle;
 | |
|   EFI_STATUS       Status;
 | |
|   UINT16           *FileName;
 | |
|   EFI_HANDLE       DeviceHandle;
 | |
| 
 | |
|   if ((ChooseHandler == NULL) && (File == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   mQuestionIdUpdate = 0;
 | |
|   FileName          = NULL;
 | |
| 
 | |
|   gFileExplorerPrivate.RetDevicePath = NULL;
 | |
|   gFileExplorerPrivate.ChooseHandler = ChooseHandler;
 | |
|   if (FileType != NULL) {
 | |
|     gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType);
 | |
|     ASSERT (gFileExplorerPrivate.FileType != NULL);
 | |
|     LibToLowerString (gFileExplorerPrivate.FileType);
 | |
|   } else {
 | |
|     gFileExplorerPrivate.FileType = NULL;
 | |
|   }
 | |
| 
 | |
|   if (RootDirectory == NULL) {
 | |
|     Status = LibFindFileSystem ();
 | |
|   } else {
 | |
|     Status = LibGetFileHandleFromDevicePath (RootDirectory, &FileHandle, &FileName, &DeviceHandle);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     Status = LibFindFiles (FileHandle, FileName, DeviceHandle);
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   LibUpdateFileExplorePage ();
 | |
| 
 | |
|   gFileExplorerPrivate.FormBrowser2->SendForm (
 | |
|                                        gFileExplorerPrivate.FormBrowser2,
 | |
|                                        &gFileExplorerPrivate.FeHiiHandle,
 | |
|                                        1,
 | |
|                                        &FileExplorerGuid,
 | |
|                                        0,
 | |
|                                        NULL,
 | |
|                                        NULL
 | |
|                                        );
 | |
| 
 | |
| Done:
 | |
|   if ((Status == EFI_SUCCESS) && (File != NULL)) {
 | |
|     *File = gFileExplorerPrivate.RetDevicePath;
 | |
|   } else if (gFileExplorerPrivate.RetDevicePath != NULL) {
 | |
|     FreePool (gFileExplorerPrivate.RetDevicePath);
 | |
|   }
 | |
| 
 | |
|   if (gFileExplorerPrivate.FileType != NULL) {
 | |
|     FreePool (gFileExplorerPrivate.FileType);
 | |
|   }
 | |
| 
 | |
|   LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
 | |
| 
 | |
|   if (FileName != NULL) {
 | |
|     FreePool (FileName);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Install Boot Manager Menu driver.
 | |
| 
 | |
|   @param ImageHandle     The image handle.
 | |
|   @param SystemTable     The system table.
 | |
| 
 | |
|   @retval  EFI_SUCEESS  Install File explorer library success.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| FileExplorerLibConstructor (
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH *)DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL *)&FeHiiVendorDevicePath);
 | |
|   ASSERT (gHiiVendorDevicePath != NULL);
 | |
|   CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid);
 | |
| 
 | |
|   //
 | |
|   // Install Device Path Protocol and Config Access protocol to driver handle
 | |
|   //
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &gFileExplorerPrivate.FeDriverHandle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   gHiiVendorDevicePath,
 | |
|                   &gEfiHiiConfigAccessProtocolGuid,
 | |
|                   &gFileExplorerPrivate.FeConfigAccess,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (Status == EFI_ALREADY_STARTED) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Post our File Explorer VFR binary to the HII database.
 | |
|   //
 | |
|   gFileExplorerPrivate.FeHiiHandle = HiiAddPackages (
 | |
|                                        &FileExplorerGuid,
 | |
|                                        gFileExplorerPrivate.FeDriverHandle,
 | |
|                                        FileExplorerVfrBin,
 | |
|                                        FileExplorerLibStrings,
 | |
|                                        NULL
 | |
|                                        );
 | |
|   ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL);
 | |
| 
 | |
|   //
 | |
|   // Locate Formbrowser2 protocol
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **)&gFileExplorerPrivate.FormBrowser2);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Unloads the application and its installed protocol.
 | |
| 
 | |
|   @param[in]  ImageHandle       Handle that identifies the image to be unloaded.
 | |
|   @param[in]  SystemTable       The system table.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The image has been unloaded.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| FileExplorerLibDestructor (
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   ASSERT (gHiiVendorDevicePath != NULL);
 | |
| 
 | |
|   if (gFileExplorerPrivate.FeDriverHandle != NULL) {
 | |
|     Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                     gFileExplorerPrivate.FeDriverHandle,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     gHiiVendorDevicePath,
 | |
|                     &gEfiHiiConfigAccessProtocolGuid,
 | |
|                     &gFileExplorerPrivate.FeConfigAccess,
 | |
|                     NULL
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle);
 | |
|     gFileExplorerPrivate.FeDriverHandle = NULL;
 | |
|   }
 | |
| 
 | |
|   FreePool (gHiiVendorDevicePath);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |