| /** @file | |
| File explorer related functions. | |
| Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials are licensed and made available under | |
| the terms and conditions of the BSD License that accompanies this distribution. | |
| The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php. | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #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; | |
| /** | |
| 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; | |
| NeedExit = TRUE; | |
| 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 >= 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) { | |
| 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) { | |
| FreePool (FileContext->DevicePath); | |
| } else { | |
| if (FileContext->FileHandle != NULL) { | |
| FileContext->FileHandle->Close (FileContext->FileHandle); | |
| } | |
| } | |
| if (FileContext->FileName != NULL) { | |
| FreePool (FileContext->FileName); | |
| } | |
| FreePool (FileContext); | |
| 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); | |
| 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); | |
| 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 - Str), 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 - Str), 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; | |
| UINTN NoLoadFileHandles; | |
| EFI_HANDLE *SimpleFsHandle; | |
| EFI_HANDLE *LoadFileHandle; | |
| UINT16 *VolumeLabel; | |
| UINTN Index; | |
| EFI_STATUS Status; | |
| MENU_ENTRY *MenuEntry; | |
| FILE_CONTEXT *FileContext; | |
| UINTN OptionNumber; | |
| EFI_FILE_SYSTEM_VOLUME_LABEL *Info; | |
| NoSimpleFsHandles = 0; | |
| NoLoadFileHandles = 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 { | |
| if (Info->VolumeLabel == NULL) { | |
| VolumeLabel = L"NULL VOLUME LABEL"; | |
| } 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 | |
| ); | |
| FreePool (Info); | |
| OptionNumber++; | |
| InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link); | |
| } | |
| } | |
| if (NoSimpleFsHandles != 0) { | |
| FreePool (SimpleFsHandle); | |
| } | |
| // | |
| // Searching for handles that support Load File protocol | |
| // | |
| Status = gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| &gEfiLoadFileProtocolGuid, | |
| NULL, | |
| &NoLoadFileHandles, | |
| &LoadFileHandle | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| for (Index = 0; Index < NoLoadFileHandles; Index++) { | |
| MenuEntry = LibCreateMenuEntry (); | |
| if (NULL == MenuEntry) { | |
| FreePool (LoadFileHandle); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; | |
| FileContext->DeviceHandle = LoadFileHandle[Index]; | |
| FileContext->IsRoot = TRUE; | |
| FileContext->DevicePath = DevicePathFromHandle (FileContext->DeviceHandle); | |
| FileContext->FileName = LibDevicePathToStr (FileContext->DevicePath); | |
| MenuEntry->HelpString = LibDevicePathToStr (FileContext->DevicePath); | |
| MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); | |
| ASSERT (MenuEntry->DisplayString != NULL); | |
| UnicodeSPrint ( | |
| MenuEntry->DisplayString, | |
| MAX_CHAR, | |
| L"Load File [%s]", | |
| MenuEntry->HelpString | |
| ); | |
| MenuEntry->DisplayStringToken = HiiSetString ( | |
| gFileExplorerPrivate.FeHiiHandle, | |
| 0, | |
| MenuEntry->DisplayString, | |
| NULL | |
| ); | |
| OptionNumber++; | |
| InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link); | |
| } | |
| } | |
| if (NoLoadFileHandles != 0) { | |
| FreePool (LoadFileHandle); | |
| } | |
| 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; | |
| } | |
| // | |
| // 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); | |
| 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; | |
| } | |
| /** | |
| 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 | |
| // | |
| 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) { | |
| 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) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; | |
| NewFileContext->DeviceHandle = DeviceHandle; | |
| NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName); | |
| 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; | |
| FreePool (DirInfo); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| 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; | |
| NewMenuEntry = NULL; | |
| NewFileContext = NULL; | |
| LibRefreshUpdateData (); | |
| MenuOption = gFileExplorerPrivate.FsOptionMenu; | |
| for (Index = 0; Index < MenuOption->MenuNumber; Index++) { | |
| NewMenuEntry = LibGetMenuEntry (MenuOption, Index); | |
| NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; | |
| if (!NewFileContext->IsDir) { | |
| // | |
| // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile. | |
| // | |
| HiiCreateActionOpCode ( | |
| mLibStartOpCodeHandle, | |
| (UINT16) (FILE_OPTION_OFFSET + Index), | |
| 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) | |
| ); | |
| } | |
| } | |
| 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); | |
| NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask); | |
| NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; | |
| if (NewFileContext->IsDir) { | |
| RemoveEntryList (&NewMenuEntry->Link); | |
| LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); | |
| LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle); | |
| 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); | |
| 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; | |
| } | |
| FileName = NULL; | |
| gFileExplorerPrivate.RetDevicePath = NULL; | |
| gFileExplorerPrivate.ChooseHandler = ChooseHandler; | |
| if (FileType != NULL) { | |
| gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType); | |
| 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); | |
| } | |
| FreePool (gHiiVendorDevicePath); | |
| return EFI_SUCCESS; | |
| } | |