You need to clarify in the function header comment for ChooseFile API if the caller needs to free the returned DevicePath (File parameter).
Also, ChooseFile API may fail to de-allocate memory upon some failure conditions. Reviewed-by: Jaben Carsey <jaben.car...@intel.com> > -----Original Message----- > From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of Eric > Dong > Sent: Tuesday, October 27, 2015 7:35 PM > To: edk2-devel@lists.01.org > Cc: Gao, Liming <liming....@intel.com> > Subject: [edk2] [Patch] MdeModulePkg FileExplorerLib: Create file explorer > library. > > This library support select one file from the specified directory or from > system root directory. > > Cc: Liming Gao <liming....@intel.com> > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Eric Dong <eric.d...@intel.com> > --- > MdeModulePkg/Include/Library/FileExplorerLib.h | 57 + > .../Library/FileExplorerLib/FileExplorer.c | 1507 > ++++++++++++++++++++ > .../Library/FileExplorerLib/FileExplorer.h | 240 ++++ > .../Library/FileExplorerLib/FileExplorerLib.inf | 58 + > .../Library/FileExplorerLib/FileExplorerString.uni | Bin 0 -> 1852 bytes > .../Library/FileExplorerLib/FileExplorerVfr.vfr | 32 + > MdeModulePkg/Library/FileExplorerLib/FormGuid.h | 27 + > MdeModulePkg/MdeModulePkg.dec | 4 + > 8 files changed, 1925 insertions(+) > create mode 100644 MdeModulePkg/Include/Library/FileExplorerLib.h > create mode 100644 MdeModulePkg/Library/FileExplorerLib/FileExplorer.c > create mode 100644 MdeModulePkg/Library/FileExplorerLib/FileExplorer.h > create mode 100644 > MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf > create mode 100644 > MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni > create mode 100644 > MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr > create mode 100644 MdeModulePkg/Library/FileExplorerLib/FormGuid.h > > diff --git a/MdeModulePkg/Include/Library/FileExplorerLib.h > b/MdeModulePkg/Include/Library/FileExplorerLib.h > new file mode 100644 > index 0000000..7e0d5a2 > --- /dev/null > +++ b/MdeModulePkg/Include/Library/FileExplorerLib.h > @@ -0,0 +1,57 @@ > +/** @file > + > + This library class defines a set of interfaces for how to do file explorer. > + > +Copyright (c) 2007 - 2015, 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. > + > +**/ > + > +#ifndef __FILE_EXPLORER_LIB_H__ > +#define __FILE_EXPLORER_LIB_H__ > + > +/** > + Prototype for precessing the find file. > + > + @param[in] FilePath The device path of the find file. > + > + @retval TRUE Need exit file explorer after do the extra task. > + @retval FALSE Not need to exit file explorer after do the extra > task. > + > +**/ > +typedef > +BOOLEAN > +(EFIAPI *EXTRA_ACTION)( > + IN EFI_DEVICE_PATH_PROTOCOL *FilePath > + ); > + > +/** > + Choose a file in the specified directory. > + > + If user input NULL for the RootDirectory, will choose file in the system. > + > + @param RootDirectory Pointer to the root directory. > + @param FileType The file type need to choose. > + @param ExtraAction 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 the file success. > + @retval Other errors Choose the file failed. > +**/ > +EFI_STATUS > +EFIAPI > +ChooseFile ( > + IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, > + IN CHAR16 *FileType, > + IN EXTRA_ACTION ExtraAction, > + OUT EFI_DEVICE_PATH_PROTOCOL **File > + ); > + > +#endif > diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c > b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c > new file mode 100644 > index 0000000..c862a2d > --- /dev/null > +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c > @@ -0,0 +1,1507 @@ > +/** @file > + File explorer related functions. > + > + Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> > + This software and associated documentation (if any) is furnished > + under a license and may only be used or copied in accordance > + with the terms of the license. Except as permitted by such > + license, no part of this software or documentation may be > + reproduced, stored in a retrieval system, or transmitted in any > + form or by any means without the express written consent of > + Intel Corporation. > + > +**/ > + > +#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 > +}; > + > +FILE_EXPLORER_CALLBACK_DATA *gPrivatePtr; > + > +HII_VENDOR_DEVICE_PATH FeHiiVendorDevicePath = { > + { > + { > + HARDWARE_DEVICE_PATH, > + HW_VENDOR_DP, > + { > + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), > + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) > + } > + }, > + // > + // {91DB4238-B0C8-472e-BBFF-F3A6541010FF} > + // > + { 0x91db4238, 0xb0c8, 0x472e, { 0xbb, 0xff, 0xf3, 0xa6, 0x54, 0x10, 0x10, > 0xff } } > + }, > + { > + 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; > + } > + > + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; > + > + 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 (gPrivatePtr->ExtraAction != NULL) { > + NeedExit = gPrivatePtr->ExtraAction (gPrivatePtr->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; > + > + 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 (gPrivatePtr->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; > + CHAR16 *Str; > + CHAR16 *TmpStr; > + CHAR16 *Ptr; > + CHAR16 *LastSlash; > + > + Size1 = StrSize (Str1); > + Size2 = StrSize (Str2); > + Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); > + ASSERT (Str != NULL); > + > + TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); > + ASSERT (TmpStr != NULL); > + > + StrCat (Str, Str1); > + if (!((*Str == '\\') && (*(Str + 1) == 0))) { > + StrCat (Str, L"\\"); > + } > + > + StrCat (Str, 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 StrCpy in BaseLib does not handle copy of > two strings > + // that overlap. > + // > + StrCpy (TmpStr, Ptr + 3); > + StrCpy (LastSlash, TmpStr); > + Ptr = LastSlash; > + } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') { > + // > + // Convert a "\.\" to a "\" > + // > + > + // > + // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of > two strings > + // that overlap. > + // > + StrCpy (TmpStr, Ptr + 2); > + StrCpy (Ptr, 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 ( > + gPrivatePtr->FeHiiHandle, > + 0, > + MenuEntry->DisplayString, > + NULL > + ); > + FreePool (Info); > + > + OptionNumber++; > + InsertTailList (&gPrivatePtr->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 ( > + gPrivatePtr->FeHiiHandle, > + 0, > + MenuEntry->DisplayString, > + NULL > + ); > + > + OptionNumber++; > + InsertTailList (&gPrivatePtr->FsOptionMenu->Head, &MenuEntry->Link); > + } > + } > + > + if (NoLoadFileHandles != 0) { > + FreePool (LoadFileHandle); > + } > + > + gPrivatePtr->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 ( > + gPrivatePtr->FeHiiHandle, > + 0, > + NewMenuEntry->DisplayString, > + NULL > + ); > + > + NewFileContext->IsRoot = FALSE; > + > + OptionNumber++; > + InsertTailList (&gPrivatePtr->FsOptionMenu->Head, &NewMenuEntry- > >Link); > + } > + } > + > + gPrivatePtr->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 = gPrivatePtr->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 ( > + gPrivatePtr->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 (gPrivatePtr->FsOptionMenu, > FileOptionMask); > + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; > + > + if (NewFileContext->IsDir) { > + RemoveEntryList (&NewMenuEntry->Link); > + LibFreeMenu (gPrivatePtr->FsOptionMenu); > + LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle); > + Status = LibFindFiles (FileHandle, NewFileContext->FileName, > NewFileContext->DeviceHandle); > + if (!EFI_ERROR (Status)) { > + LibUpdateFileExplorePage (); > + } else { > + LibFreeMenu (gPrivatePtr->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 (gPrivatePtr->FsOptionMenu, > FileOptionMask); > + > + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; > + > + if (gPrivatePtr->RetDevicePath != NULL) { > + FreePool (gPrivatePtr->RetDevicePath); > + } > + gPrivatePtr->RetDevicePath = DuplicateDevicePath (NewFileContext- > >DevicePath); > +} > + > +/** > + Choose a file in the specified directory. > + > + If user input NULL for the RootDirectory, will choose file in the system. > + > + @param RootDirectory Pointer to the root directory. > + @param FileType The file type need to choose. > + @param ExtraAction 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 the file success. > + @retval Other errors Choose the file failed. > +**/ > +EFI_STATUS > +EFIAPI > +ChooseFile ( > + IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, > + IN CHAR16 *FileType, > + IN EXTRA_ACTION ExtraAction, > + OUT EFI_DEVICE_PATH_PROTOCOL **File > + ) > +{ > + EFI_FILE_HANDLE FileHandle; > + EFI_STATUS Status; > + UINT16 *FileName; > + EFI_HANDLE DeviceHandle; > + > + gPrivatePtr->ExtraAction = ExtraAction; > + gPrivatePtr->FileType = AllocateCopyPool (StrSize (FileType), FileType); > + LibToLowerString(gPrivatePtr->FileType); > + > + if (RootDirectory == NULL) { > + Status = LibFindFileSystem(); > + } else { > + Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, > &FileName, &DeviceHandle); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status = LibFindFiles (FileHandle, FileName, DeviceHandle); > + } > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + LibUpdateFileExplorePage(); > + > + gPrivatePtr->FormBrowser2->SendForm ( > + gPrivatePtr->FormBrowser2, > + &gPrivatePtr->FeHiiHandle, > + 1, > + &FileExplorerGuid, > + 0, > + NULL, > + NULL > + ); > + > + *File = gPrivatePtr->RetDevicePath; > + > + gPrivatePtr->RetDevicePath = NULL; > + FreePool (gPrivatePtr->FileType); > + LibFreeMenu (gPrivatePtr->FsOptionMenu); > + > + return EFI_SUCCESS; > +} > + > +/** > + > + 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; > + EFI_HANDLE DriverHandle; > + EFI_DEVICE_PATH_PROTOCOL *DevicePath; > + EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; > + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; > + > + DevicePath = DuplicateDevicePath > ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath); > + ASSERT (DevicePath != NULL); > + TmpDevicePath = DevicePath; > + > + Status = gBS->LocateDevicePath (&gEfiHiiConfigAccessProtocolGuid, > &TmpDevicePath, &DriverHandle); > + if (EFI_ERROR (Status)) { > + InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head); > + gFileExplorerPrivate.ReferenceCount++; > + > + // > + // Install Device Path Protocol and Config Access protocol to driver > handle > + // > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &gFileExplorerPrivate.FeDriverHandle, > + &gEfiDevicePathProtocolGuid, > + &FeHiiVendorDevicePath, > + &gEfiHiiConfigAccessProtocolGuid, > + &gFileExplorerPrivate.FeConfigAccess, > + NULL > + ); > + ASSERT_EFI_ERROR (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); > + > + gPrivatePtr = &gFileExplorerPrivate; > + } else { > + Status = gBS->HandleProtocol (DriverHandle, > &gEfiHiiConfigAccessProtocolGuid, &ConfigAccess); > + ASSERT_EFI_ERROR (Status); > + gPrivatePtr = FILE_EXPLORER_PRIVATE_FROM_THIS (ConfigAccess); > + gPrivatePtr->ReferenceCount++; > + } > + > + FreePool (DevicePath); > + 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; > + EFI_HANDLE DriverHandle; > + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; > + EFI_DEVICE_PATH_PROTOCOL *DevicePath; > + EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; > + > + DevicePath = DuplicateDevicePath > ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath); > + ASSERT (DevicePath != NULL); > + TmpDevicePath = DevicePath; > + > + Status = gBS->LocateDevicePath (&gEfiHiiConfigAccessProtocolGuid, > &TmpDevicePath, &DriverHandle); > + ASSERT_EFI_ERROR (Status); > + Status = gBS->HandleProtocol (DriverHandle, > &gEfiHiiConfigAccessProtocolGuid, &ConfigAccess); > + ASSERT_EFI_ERROR (Status); > + gPrivatePtr = FILE_EXPLORER_PRIVATE_FROM_THIS (ConfigAccess); > + > + if (gPrivatePtr->ReferenceCount == 1) { > + LibFreeMenu (gPrivatePtr->FsOptionMenu); > + > + Status = gBS->UninstallMultipleProtocolInterfaces ( > + gPrivatePtr->FeDriverHandle, > + &gEfiDevicePathProtocolGuid, > + &FeHiiVendorDevicePath, > + &gEfiHiiConfigAccessProtocolGuid, > + &gPrivatePtr->FeConfigAccess, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + HiiRemovePackages (gPrivatePtr->FeHiiHandle); > + } > + > + gPrivatePtr->ReferenceCount--; > + > + FreePool (DevicePath); > + > + return EFI_SUCCESS; > +} > + > diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h > b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h > new file mode 100644 > index 0000000..875fc77 > --- /dev/null > +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h > @@ -0,0 +1,240 @@ > +/** @file > + File explorer lib. > + > +Copyright (c) 2015, 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 > +which 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. > +**/ > + > +#ifndef _FILE_EXPLORER_H_ > +#define _FILE_EXPLORER_H_ > + > +#include <PiDxe.h> > +#include <Guid/FileSystemVolumeLabelInfo.h> > +#include <Guid/FileInfo.h> > +#include <Guid/MdeModuleHii.h> > + > +#include <Protocol/HiiConfigAccess.h> > +#include <Protocol/DevicePath.h> > +#include <Protocol/SimpleFileSystem.h> > +#include <Protocol/DevicePathToText.h> > +#include <Protocol/LoadFile.h> > +#include <Protocol/FormBrowser2.h> > + > +#include <Library/DebugLib.h> > +#include <Library/BaseMemoryLib.h> > +#include <Library/UefiBootServicesTableLib.h> > +#include <Library/MemoryAllocationLib.h> > +#include <Library/BaseLib.h> > +#include <Library/UefiLib.h> > +#include <Library/DevicePathLib.h> > +#include <Library/FileExplorerLib.h> > +#include <Library/HiiLib.h> > +#include <Library/PrintLib.h> > + > +#include "FormGuid.h" > + > +#define FILE_EXPLORER_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('f', > 'e', 'c', 'k') > + > + > +#pragma pack(1) > + > +/// > +/// HII specific Vendor Device Path definition. > +/// > +typedef struct { > + VENDOR_DEVICE_PATH VendorDevicePath; > + EFI_DEVICE_PATH_PROTOCOL End; > +} HII_VENDOR_DEVICE_PATH; > + > +typedef struct { > + EFI_HANDLE DeviceHandle; > + EFI_DEVICE_PATH_PROTOCOL *DevicePath; > + EFI_FILE_HANDLE FileHandle; > + UINT16 *FileName; > + > + BOOLEAN IsRoot; > + BOOLEAN IsDir; > +} FILE_CONTEXT; > + > +typedef struct { > + UINTN Signature; > + LIST_ENTRY Link; > + UINT16 *DisplayString; > + UINT16 *HelpString; > + EFI_STRING_ID DisplayStringToken; > + EFI_STRING_ID HelpStringToken; > + VOID *VariableContext; > +} MENU_ENTRY; > + > +typedef struct { > + UINTN Signature; > + LIST_ENTRY Head; > + UINTN MenuNumber; > + BOOLEAN Used; > +} MENU_OPTION; > + > +typedef struct { > + // > + // Shared callback data. > + // > + UINTN Signature; > + > + // > + // File explorer formset callback data. > + // > + EFI_HII_HANDLE FeHiiHandle; > + EFI_HANDLE FeDriverHandle; > + EFI_HII_CONFIG_ACCESS_PROTOCOL FeConfigAccess; > + EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2; > + MENU_OPTION *FsOptionMenu; > + UINTN ReferenceCount; > + CHAR16 *FileType; > + EXTRA_ACTION ExtraAction; > + EFI_DEVICE_PATH_PROTOCOL *RetDevicePath; > + > +} FILE_EXPLORER_CALLBACK_DATA; > + > +#define FILE_EXPLORER_PRIVATE_FROM_THIS(a) CR (a, > FILE_EXPLORER_CALLBACK_DATA, FeConfigAccess, > FILE_EXPLORER_CALLBACK_DATA_SIGNATURE) > + > +#pragma pack() > + > +extern UINT8 FileExplorerVfrBin[]; > + > +#define MENU_OPTION_SIGNATURE SIGNATURE_32 ('m', 'e', 'n', 'u') > +#define MENU_ENTRY_SIGNATURE SIGNATURE_32 ('e', 'n', 't', 'r') > + > +/// > +/// Define the maximum characters that will be accepted. > +/// > +#define MAX_CHAR 480 > +#define FILE_OPTION_OFFSET 0x8000 > +#define FILE_OPTION_MASK 0x7FFF > + > + > +/** > + 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) the addition of boot option. > + 2) the addition of driver option. > + 3) exit from file browser > + 4) update of file content if a dir is selected. > + 5) boot the file if a file is selected in "boot from file" > + > + > + @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 EFI_OUT_OF_RESOURCES Not enough storage is available to hold > the variable and its data. > + @retval EFI_DEVICE_ERROR The variable could not be saved. > + @retval EFI_UNSUPPORTED The specified Action is not supported by > the callback. > + > +**/ > +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 > + ); > + > + > +/** > + 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_SUCCESS The Results is filled with the requested > values. > + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the > results. > + @retval EFI_INVALID_PARAMETER Request is NULL, 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 > + ); > + > +/** > + 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_SUCCESS The Results is processed successfully. > + @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 > + ); > + > +/** > + 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 > + ); > + > + > +/** > + 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 > + ); > + > +#endif > diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf > b/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf > new file mode 100644 > index 0000000..bb4d813 > --- /dev/null > +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf > @@ -0,0 +1,58 @@ > +## @file > +# library defines a set of interfaces for how to do file explorer. > +# > +# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR> > +# This software and associated documentation (if any) is furnished > +# under a license and may only be used or copied in accordance > +# with the terms of the license. Except as permitted by such > +# license, no part of this software or documentation may be > +# reproduced, stored in a retrieval system, or transmitted in any > +# form or by any means without the express written consent of > +# Intel Corporation. > +# > +## > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = FileExplorerLib > + FILE_GUID = 4FC9C630-0F90-4053-8F13-264CBD22FC58 > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = FileExplorerLib|DXE_DRIVER > UEFI_APPLICATION > + CONSTRUCTOR = FileExplorerLibConstructor > + DESTRUCTOR = FileExplorerLibDestructor > + > +# > +# The following information is for reference only and not required by the > build tools. > +# > +# VALID_ARCHITECTURES = IA32 X64 IPF EBC > +# > + > +[Sources] > + FileExplorer.h > + FileExplorerVfr.vfr > + FileExplorerString.uni > + FileExplorer.c > + FormGuid.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + > +[LibraryClasses] > + DevicePathLib > + BaseLib > + MemoryAllocationLib > + UefiBootServicesTableLib > + BaseMemoryLib > + DebugLib > + > +[Guids] > + gEfiFileSystemVolumeLabelInfoIdGuid ## CONSUMES ## GUID > (Indicate the information type is volume) > + gEfiIfrTianoGuid ## CONSUMES ## GUID > (Extended IFR Guid > Opcode) > + > +[Protocols] > + gEfiSimpleFileSystemProtocolGuid ## PROTOCOL CONSUMES > + gEfiLoadFileProtocolGuid ## PROTOCOL CONSUMES > + gEfiHiiConfigAccessProtocolGuid ## PROTOCOL CONSUMES > + gEfiFormBrowser2ProtocolGuid ## PROTOCOL CONSUMES > diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni > b/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni > new file mode 100644 > index > 0000000000000000000000000000000000000000..4315a368b80f2b78afb2 > e4e0b93017b379068488 > GIT binary patch > literal 1852 > zcmc(g-EPxB5QXO&iFdG?n}TQy72E;hM- > 8e}prWb7U6dwq8YyusJ0awWd5gk#W|C%& > z5`?%x*4pdcnK@_9%-TQiPE6NhuFT$8ZeyF+&>q?YU(Z- > g=X$@gxmDN|HsWo7wY&<( > zoH1iovz{}nc)sH~V<)qZ)^oc#9tHEl`ph!BcE5@Huk5&imtwysPH8L09@(wOJS4^ > = > zVw~DjuIJ2-)^E@3g*{<@4vr8f%oU*`hVDH_729KW- > m)(X<rT4&Lxo?>sO%f}0hTYx > z=Zn2=aO}Wk>^av&&WXDux_mRwa^TMziy3Ukj;v_XPAdzWVk?$gPMIBInXe< > PJjcMu > zv9GY!+pV)oHCnKvib(k$L#j$;)g<LJWp~BC@}KzZ#`hO)CvH)_KF^XE!B<sQ+&-7~ > z2h5|2DTgKYbGT)G7pnBH$Woe0q3uqSpDJ-?- > <@%Zm$2khuKg8PvBdAjS=Xr12P?&I > z##9d!pel;0qNrOA`|1|i|EWG31*KbxuDX}t%wQ>QVk-_c$coxjGI}h|(~vIfc^B5? > zCi@|p$v4=@N_y9<rb=w8Qs9*`i4!=z_YcJsL6uj}MYN25jf%}+EPYfx)on;El#5P* > z>ab+KK~^WI3!<~sy`gK$;BU^J>^EccB|1q~URmq@t%W+`JVH}_b@Vk7%YsvX > &37rY > z1Nuk%>H(dP1NYtSmy^wrwK>o7Yp>P)0fKzPQ_NbtrC+=&>)_M1PhehfbwSq3I > V&HW > zQSjP*-*Q=iG=hCI198z1^6m)#y1ENF)gVRQmvfseFVMKl_- > dETKa=^H>(ODa<Ga5z > f+=ZN0E%c8+PkaGNDj27w`fpma=>z=>_c8hf(BBml > > literal 0 > HcmV?d00001 > > diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr > b/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr > new file mode 100644 > index 0000000..ee9755f > --- /dev/null > +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr > @@ -0,0 +1,32 @@ > +///** @file > +// > +// File Explorer Formset > +// > +// Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR> > +// This software and associated documentation (if any) is furnished > +// under a license and may only be used or copied in accordance > +// with the terms of the license. Except as permitted by such > +// license, no part of this software or documentation may be > +// reproduced, stored in a retrieval system, or transmitted in any > +// form or by any means without the express written consent of > +// Intel Corporation. > + > + > +//**/ > + > +#include "FormGuid.h" > + > +formset > + guid = EFI_FILE_EXPLORE_FORMSET_GUID, > + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE), > + help = STRING_TOKEN(STR_NULL_STRING), > + classguid = EFI_FILE_EXPLORE_FORMSET_GUID, > + > + form formid = FORM_FILE_EXPLORER_ID, > + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE); > + > + label FORM_FILE_EXPLORER_ID; > + label LABEL_END; > + endform; > + > +endformset; > \ No newline at end of file > diff --git a/MdeModulePkg/Library/FileExplorerLib/FormGuid.h > b/MdeModulePkg/Library/FileExplorerLib/FormGuid.h > new file mode 100644 > index 0000000..d842012 > --- /dev/null > +++ b/MdeModulePkg/Library/FileExplorerLib/FormGuid.h > @@ -0,0 +1,27 @@ > +/** @file > + Formset guids, form id and VarStore data structure for Boot Maintenance > Manager. > + > + Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> > + This software and associated documentation (if any) is furnished > + under a license and may only be used or copied in accordance > + with the terms of the license. Except as permitted by such > + license, no part of this software or documentation may be > + reproduced, stored in a retrieval system, or transmitted in any > + form or by any means without the express written consent of > + Intel Corporation. > + > +**/ > +#ifndef _FILE_EXPLORER_FORM_GUID_H_ > +#define _FILE_EXPLORER_FORM_GUID_H_ > + > + > +#define EFI_FILE_EXPLORE_FORMSET_GUID \ > + { \ > + 0x1f2d63e1, 0xfebd, 0x4dc7, {0x9c, 0xc5, 0xba, 0x2b, 0x1c, 0xef, 0x9c, > 0x5b} \ > + } > + > +#define FORM_FILE_EXPLORER_ID 0x1000 > +#define LABEL_END 0xffff > + > +#endif > + > diff --git a/MdeModulePkg/MdeModulePkg.dec > b/MdeModulePkg/MdeModulePkg.dec > index 3dfcd6a..d45e49a 100644 > --- a/MdeModulePkg/MdeModulePkg.dec > +++ b/MdeModulePkg/MdeModulePkg.dec > @@ -128,10 +128,14 @@ > VarCheckLib|Include/Library/VarCheckLib.h > > ## @libraryclass Provides services to get variable error flag and do > platform > variable cleanup. > # > PlatformVarCleanupLib|Include/Library/PlatformVarCleanupLib.h > + > + ## @libraryclass Provides services to get do the file explorer. > + # > + FileExplorerLib|Include/Library/FileExplorerLib.h > > [Guids] > ## MdeModule package token space guid > # Include/Guid/MdeModulePkgTokenSpace.h > gEfiMdeModulePkgTokenSpaceGuid = { 0xA1AFF049, 0xFDEB, 0x442a, { > 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC }} > -- > 1.9.5.msysgit.1 > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel